blob page keyboard navigation#46829
Conversation
Bundle size report 📦
Look at the Statoscope report for a full comparison between the commits d6810db and fa271fb or learn more. Open explanation
|
| if (event.key.length === 1) { | ||
| let currentId = getNextAccessible(data, id, expandedIds) | ||
| while (currentId !== id) { | ||
| if (currentId == null) { | ||
| currentId = data[0].children[0] | ||
| continue | ||
| } | ||
| if (data[currentId].name[0].toLowerCase() === event.key.toLowerCase()) { | ||
| dispatch({ | ||
| type: treeTypes.focus, | ||
| id: currentId, | ||
| lastInteractedWith: id, | ||
| }) | ||
| return | ||
| } | ||
| currentId = getNextAccessible(data, currentId, expandedIds) | ||
| } | ||
| } |
There was a problem hiding this comment.
a-z, A-Z keys handlers interfere with keyboard shortcuts introduced by this PR so we disable the former.
There was a problem hiding this comment.
Can we do this without patching the third-party library?
There was a problem hiding this comment.
Seems like there's no option for that though. Let's add a comment then and explain the change.
|
Converting back to the draft state to address implementation (https://github.com/sourcegraph/sourcegraph/pull/46829#discussion_r1124379369) and design (https://github.com/sourcegraph/sourcegraph/pull/46829#issuecomment-1453451232) issues. |
philipp-spiess
left a comment
There was a problem hiding this comment.
Couple of comments but it's all gated anyway so, sure. I’m sad that we have to let the a-zA-Z listeners in the treeview go for it though 😭
Adds shortcuts labels when the feature is enabled:
btw it looks like you forgot to commit the code for this? I don't see the change anywhere haha
| focusCodeEditor: { | ||
| title: 'Focus editor', | ||
| keybindings: [{ ordered: ['c'] }], | ||
| hideInHelp: true, |
There was a problem hiding this comment.
Why hide this in the help menu?
There was a problem hiding this comment.
Not to show them when the feature flag is disabled.
Though we can filter them out based on the feature flag value.
There was a problem hiding this comment.
Not to show them when the feature flag is disabled.
Ah, of course 😅
| }, | ||
| focusCodeEditor: { | ||
| title: 'Focus editor', | ||
| keybindings: [{ ordered: ['c'] }], |
There was a problem hiding this comment.
All other file handlers in this file have a modifier to go first, are we certain we want to break this pattern here? Hm.
There was a problem hiding this comment.
These shortcuts are from RFC 345.
I have a few doubts regarding it:
- both JetBrains and VSCode IDEs use shortcuts with modifiers (
Cmd+1andShift+Cmd+Erespectively) - I'll do an extra round of testing to ensure
c,f,sshortcuts to not hijack commonly used browser shortcuts (copy, interacting with panels, etc.)
There was a problem hiding this comment.
@taras-yemets What, for example, happens when you press c, f, or s while inside a text input?
Maybe we should discuss this with other folks as well? 🤔 summoning @sourcegraph/code-exploration-devs
There was a problem hiding this comment.
What, for example, happens when you press c, f, or s while inside a text input?
Nothing. Input behaves as usual.
It can be another argument favoring adding modifiers to focus files/symbols/code shortcuts so that we can switch from input to any of mentioned areas.
| )} | ||
|
|
||
| {enableBlobPageSwitchAreasShortcuts && | ||
| [focusFileTreeShortcut, focusSymbolsShortcut].map((shortcut, tabIndex) => |
There was a problem hiding this comment.
very minor nit feel free to ignore but I think it'd be easier to read this without combining it into an array and then mapping over it and instead rendering two components. 😅
| const [enableBlobPageSwitchAreasShortcuts] = useFeatureFlag('blob-page-switch-areas-shortcuts') | ||
| const focusFileTreeShortcut = useKeyboardShortcut('focusFileTree') | ||
| const focusSymbolsShortcut = useKeyboardShortcut('focusSymbols') | ||
| const [focusKey, setFocusKey] = useState('') |
There was a problem hiding this comment.
Hmmm I wonder if there are any issues here with reusing the same key across both components in combination with keeping the components mounted (so when we focus one, both are technically getting focused). Can you try to apply this line and see if it still works?
There was a problem hiding this comment.
Seems to work fine with <Tabs {...props} behavior="memoize" />
Screen.Recording.2023-03-03.at.15.21.59.mov
But you're right, focus() on the FocusableTree ref is called twice (once per tab). Looking into it 👀
There was a problem hiding this comment.
Addressed in https://github.com/sourcegraph/sourcegraph/pull/46829/commits/0f321dc0ab9498cd58d8dc4c18a86fe56de718c8.
Thanks for pointing this out!
| } | ||
|
|
||
| /** | ||
| * Renders {@link Tree} and focuses it when {@link focusKey} changes. |
There was a problem hiding this comment.
Are the @link like this even working? In JS, the Tree module is not global so i figured this is not really helpful anyway and will just render incorrectly, hence I've never bothered to use it. Happy to be proven wrong though :D
There was a problem hiding this comment.
It works for me in JetBrans IDE 🤷🏻
Screen.Recording.2023-03-03.at.14.48.08.mov
There was a problem hiding this comment.
Ah because it uses the Tree that is available within the current module I guess? 😱 And what about focusKey, no way it finds that?
There was a problem hiding this comment.
And what about focusKey, no way it finds that?
See sec 6 on the video. It takes it from the props interface.
There was a problem hiding this comment.
Awesome, thanks for showing.
| export function FocusableTree<N extends TreeNode>(props: FocusableTreeProps & TreeProps<N>): JSX.Element { | ||
| const { focusKey, ...rest } = props | ||
|
|
||
| const ref = useRef<HTMLUListElement>(null) |
There was a problem hiding this comment.
| const ref = useRef<HTMLUListElement>(null) | |
| const ref = useRef<TreeRef>(null) |
How did this not fail? 😱
There was a problem hiding this comment.
🤷🏻 maybe because HTMLUListElement matches TreeRef interface (has focus method)?
There was a problem hiding this comment.
I mean it has focus but it also has some properties that only DOM nodes have as well so this should really not work. Maybe the typescript workaround for generic refs doesn't work? :(
There was a problem hiding this comment.
There was a problem hiding this comment.
I’m still confused here. Does this mean useImperativeHandle merges the ref with the object you define? e.g. what happens if you do ref.current.innerHTML = 'foobar'? This would be valid on a UList but not on the TreeRef 😅
Also the error message is confusing because we don't want to assign HTMLUListElement ref into TreeRef but instead it should be assigned the other way around haha. Seems like this is a covariant/contravariant issue with your workaround because it looses the nuance that this is one over the other (I don't know exactly which term is the correct one here lol)
microsoft/TypeScript#30748 (comment)
Ah the sound type system strikes again 🙃
There was a problem hiding this comment.
what happens if you do ref.current.innerHTML = 'foobar'? This would be valid on a UList but not on the TreeRef
You're right! With TreeRef as a type we get an expected error

Seems like this is a covariant/contravariant issue with your workaround
Maybe 🤷🏻
Do you have ideas on how we can define safer types on the Tree component with generic type and forwardRef combo?
There was a problem hiding this comment.
Do you have ideas on how we can define safer types on the Tree component with generic type and forwardRef combo?
no, I did a quick google session but it's not as simple as in Flowtype to define a property as contravariant so I'd say we ignore it for now 😓
@philipp-spiess, exactly! https://github.com/sourcegraph/sourcegraph/pull/46829/commits/6e2dae2e9720f40ceb867086958d19453892d4d9 |
This reverts commit 6e2dae2.
Agree. Removing them for now. https://github.com/sourcegraph/sourcegraph/pull/46829/commits/fa4a6c44aecac509b9fa75cd8a5c055c4fd84774 |
|
Codenotify: Notifying subscribers in OWNERS files for diff fa271fb...d56b5b8.
|



Closes https://github.com/sourcegraph/sourcegraph/issues/46375
Adds keyboard shortcuts to switch between blob view, file, and symbol trees.
Available under
blob-page-switch-areas-shortcutsfeature flag.Screen.Recording.2023-03-02.at.18.47.40.mov
Adds shortcut labels to the code view and files/symbols tags. I asked for design help in this thread. I think it's not blocking as this feature is behind the feature flag and we can address the feedback as we get it.
Test plan
Tested manually (video attached).
App preview:
Check out the client app preview documentation to learn more.