You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
How it works - plugins can register keyboard shortcuts which Docusaurus will attach as a global event listener and show a list of all supported shortcuts on the website when the user types ?, like Reddit:
Of course it'll be up to the plugins to define their own logic for responding to events. Docusaurus can provide the keyboard event listening mechanism and call plugin code when a specific key combination occurs.
Reacted by James and Eric Andrechek
Reacted by Silver Zachara, James and Eric Andrechek
Initially tagged for MLH, also @taylorallen0913 told me he was interested to work on this.
I don't have a strong opinion on how this should be implemented. Maybe we could discuss about an exhaustive list of shortcuts we'd like to support initially, and see from there if we are able to design this feature?
Some thoughts:
The shortcuts should run client-side
If we had a core plugin api like "addShortcut" in contentLoaded lifecycle, it's likely to be limited because we'd have to handle shortcuts in a declarative way (ie the shortcuts should be serialized to json and only then be wired on the frontend)
plugins don't often do this often, but they are able to ship frontend code as well (see ideal image plugin, which provides an image component). I think could use a declarative way to use shortcuts, maybe using a JSX-based shortcut lib.
Use the Context API and wrap our client to register a global event listener
Write our own useKeyboardShortcut hook that handles registering shortcuts and customizing them
Create our own data structure to store our keyboard shortcuts
Map all of our keybind names, shortcuts, etc. to a menu
Optional functionalities:
Custom user keyboard shortcuts from list of actions
Shortcut rebindability
I plan to implement all of this inside a new docusaurus-keyboard-shortcuts monorepo.
This is my general idea for the keybind data structure, and obviously it will be stored in memory in either the hook or context. Also the way I have it set up currently is that you have to register the hook on a file-by-file basis so you can control when the keyboard shortcuts are active.
I am also doing some testing of my implementation here. I wrote it in my own repo because I am not completely familiar with the codebase yet, and I should be able to just transfer everything over when I get it to reasonably functioning state.
If anyone has any ideas please let me know so I can improve this.
I was thinking if @docusaurus/plugins-content-docs want to add a keyboard shortcut to move to the next page in the sidebar how it be handled by @taylorallen0913 implementation.
I was thinking if @docusaurus/plugins-content-docs want to add a keyboard shortcut to move to the next page in the sidebar how it be handled by @taylorallen0913 implementation.
I think the way we should implement should be as general as possible— making the system scalable, so that down the line, as we add more plugins, the keyboard shortcut functionalities are not limited. The way I see this being possible is allowing the plugin to provide a function/callback for what they want the keyboard shortcut to accomplish. In theory, it would allow almost anything to executed with a keyboard shortcut as long as the task is programmatically possible (which I assume should not limit anything).
This is an example on how a plugin would register their desired shortcut, most likely just consuming a reducer on mount:
Do you agree on the approach i’m taking? What do you think could be improved?
The ts-eslint website uses a client module to register a global key listener. It's a konami code easter egg. (For those who don't know what konami code is: try typing ↑↑↓↓←→←→BA on the website)
I think it's a good model to follow for plugins. There's no need to populate the core with more lifecycle APIs. Each plugin can add a set of hotkeys and register them to a global file (we should do the same for the linkification logic: instead of routing the logic to the core, prefer plugins writing to a global data register), and the theme will pick up that generated file and render it as a hotkey map popup.
I think the purpose of putting this in core is so that in the case of overlapping/conflicting shortcuts, we can throw errors or inform users. Letting Docusaurus core manage keyboard shortcuts will also allow shortcuts to be contextual, e.g. when focus is in a component, Ctrl + K does something different from search. This can also be done entirely in userland, but just a bit more work for users.
I think the purpose of putting this in core is so that in the case of overlapping/conflicting shortcuts, we can throw errors or inform users.
I was about to that "this can be done by writing to @generated/hotkeys.json during contentLoaded as well" but I realized that there's no guaranteed execution order :( Indeed we would at least need a new lifecycle that runs in series, allowing each plugin to write to a global data register in a deterministic order. This would be useful for file path -> URL mapping as well.
allow shortcuts to be contextual
Isn't that ultimately on the theme though? Ideally the core doesn't know much about what's happening inside the Layout comp?
This can also be done entirely in userland, but just a bit more work for users.
We would definitely want a more imperative API to register hotkeys, maybe in the form of a utility function in the plugin. Not sure if site builders would want addition hotkeys / hotkey configuration🤔 I imagine as soon as we release this there would be requests like "let me use WASD instead of ↑↓←→ for navigation"
Direct writing to a file seems like a bad idea. In addition to race conditions it's also an implicit API surface, more complex to implement for users.
I also agree that shortcuts can be contextual, and shortcuts can be namespaced by plugin.
Not directly related but I'd also like to have a core hook that tells a page by which plugin/id it was created (each page is always created by a plugin, maybe not minor edge cases like the 404?) => that can allow custom login on a per-instance basis in swizzled components.
Random thought: what are the advantages for plugins to expose shortcuts as a Node.js API?
Handling of shortcuts has to be implemented in the themes anyway to wire a key to a concrete action implementation.
Maybe the Node.js API should only expose options to customize the shortcut keys, and that's all we need?
What kind of shortcut would benefit from new lifecycle APIs?
Activity
slorber commentedon Jul 1, 2020
Initially tagged for MLH, also @taylorallen0913 told me he was interested to work on this.
I don't have a strong opinion on how this should be implemented. Maybe we could discuss about an exhaustive list of shortcuts we'd like to support initially, and see from there if we are able to design this feature?
Some thoughts:
taylorallen0913 commentedon Jul 1, 2020
Heres my ideas on how we can implement this:
Core functionalities:
useKeyboardShortcuthook that handles registering shortcuts and customizing themOptional functionalities:
I plan to implement all of this inside a new
docusaurus-keyboard-shortcutsmonorepo.This is my general idea for the keybind data structure, and obviously it will be stored in memory in either the hook or context. Also the way I have it set up currently is that you have to register the hook on a file-by-file basis so you can control when the keyboard shortcuts are active.
I am also doing some testing of my implementation here. I wrote it in my own repo because I am not completely familiar with the codebase yet, and I should be able to just transfer everything over when I get it to reasonably functioning state.
If anyone has any ideas please let me know so I can improve this.
anshulrgoyal commentedon Jul 2, 2020
I was thinking if
@docusaurus/plugins-content-docswant to add a keyboard shortcut to move to the next page in the sidebar how it be handled by @taylorallen0913 implementation.taylorallen0913 commentedon Jul 2, 2020
I think the way we should implement should be as general as possible— making the system scalable, so that down the line, as we add more plugins, the keyboard shortcut functionalities are not limited. The way I see this being possible is allowing the plugin to provide a function/callback for what they want the keyboard shortcut to accomplish. In theory, it would allow almost anything to executed with a keyboard shortcut as long as the task is programmatically possible (which I assume should not limit anything).
This is an example on how a plugin would register their desired shortcut, most likely just consuming a reducer on mount:
Do you agree on the approach i’m taking? What do you think could be improved?
slorber commentedon Oct 1, 2020
As we have new MLH interns coming soon, was thinking about this issue.
To me, it's not totally clear if shortcuts should be provided by a plugin, by a theme, or both.
This feature is not very easy to design.
Josh-Cena commentedon Nov 20, 2021
The ts-eslint website uses a client module to register a global key listener. It's a konami code easter egg. (For those who don't know what konami code is: try typing
↑↑↓↓←→←→BAon the website)I think it's a good model to follow for plugins. There's no need to populate the core with more lifecycle APIs. Each plugin can add a set of hotkeys and register them to a global file (we should do the same for the linkification logic: instead of routing the logic to the core, prefer plugins writing to a global data register), and the theme will pick up that generated file and render it as a hotkey map popup.
yangshun commentedon Nov 20, 2021
I think the purpose of putting this in core is so that in the case of overlapping/conflicting shortcuts, we can throw errors or inform users. Letting Docusaurus core manage keyboard shortcuts will also allow shortcuts to be contextual, e.g. when focus is in a component, Ctrl + K does something different from search. This can also be done entirely in userland, but just a bit more work for users.
Josh-Cena commentedon Nov 20, 2021
I was about to that "this can be done by writing to
@generated/hotkeys.jsonduringcontentLoadedas well" but I realized that there's no guaranteed execution order :( Indeed we would at least need a new lifecycle that runs in series, allowing each plugin to write to a global data register in a deterministic order. This would be useful for file path -> URL mapping as well.Isn't that ultimately on the theme though? Ideally the core doesn't know much about what's happening inside the
Layoutcomp?We would definitely want a more imperative API to register hotkeys, maybe in the form of a utility function in the plugin. Not sure if site builders would want addition hotkeys / hotkey configuration🤔 I imagine as soon as we release this there would be requests like "let me use WASD instead of ↑↓←→ for navigation"
slorber commentedon Dec 8, 2021
Direct writing to a file seems like a bad idea. In addition to race conditions it's also an implicit API surface, more complex to implement for users.
I also agree that shortcuts can be contextual, and shortcuts can be namespaced by plugin.
Not directly related but I'd also like to have a core hook that tells a page by which plugin/id it was created (each page is always created by a plugin, maybe not minor edge cases like the 404?) => that can allow custom login on a per-instance basis in swizzled components.
Random thought: what are the advantages for plugins to expose shortcuts as a Node.js API?
Handling of shortcuts has to be implemented in the themes anyway to wire a key to a concrete action implementation.
Maybe the Node.js API should only expose options to customize the shortcut keys, and that's all we need?
What kind of shortcut would benefit from new lifecycle APIs?