API: Add addon keyboard shortcuts & create shortcuts for addon-viewport#14658
API: Add addon keyboard shortcuts & create shortcuts for addon-viewport#14658shilman merged 5 commits intostorybookjs:nextfrom Dschungelabenteuer:fix-issue-14401
Conversation
|
Amazing, thank you for taking this on! Quick feedback: it might bother Windows and Linux users that the addon takes over CTRL+V 😅 |
shilman
left a comment
There was a problem hiding this comment.
This is so awesome @Dschungelabenteuer, tremendous work! 💯
Before merging, I'd like to get a review from @ndelangen on the code, which LGTM, and from @jonniebigodes @winkerVSbecks on the addons API documentation.
|
Thank you for your feedbacks, really appreciated! @kaelig I have to admit I told myself this would not be much of a problem since shortcuts do not apply when focus is set on inputs, Any suggestions? |
addons/viewport/src/shortcuts.ts
Outdated
| import { ADDON_ID } from './constants'; | ||
| import { MINIMAL_VIEWPORTS } from './defaults'; | ||
|
|
||
| const viewportsKeys = Object.keys(MINIMAL_VIEWPORTS); |
There was a problem hiding this comment.
When a custom list of viewports is set, will it be registered? (It's a dynamic list, and can completely change between two stories)
There was a problem hiding this comment.
Oh good catch, I had not thought of that at all! Thank you for pointing that out, I'll be fixing it as soon as possible! Edit: custom viewports are now correctly registered 🎉
kaelig
left a comment
There was a problem hiding this comment.
I have a few questions, this is looking great. I haven't tested it yet.
|
LGTM |
|
@shilman on the docs side of things it's good to me as well! @Dschungelabenteuer wow, this is so cool, thank you very much for the time and effort you put into this! Can't wait to see this one merged and have the functionality generally available for all Storybook users. Stay safe |
|
Should I update the |
|
@Dschungelabenteuer yes please! 🙏 we can't merge until the tests pass. Let me know if you need any help with that. |
|
First: awesome work! really cool @Dschungelabenteuer @kaelig If we're talking about shortcuts. Then when users want to change, they can change it for everyone (in This is not a required change for this PR, but something I think we could do, if we're touching the code anyway. The |
|
@Dschungelabenteuer this looks mergeable to me. Do you want to change "ctl-v" or should I merge as is? |
@shilman It would have worked fine, but I changed it to alt + v to avoid any confusion with our holy ctrl + v 😅 @ndelangen I guess this could be a nice thing! I could try some things out in another branch later, and if I eventually come up with something interesting I could refere this pull request and maybe create another pull request? (I am really sorry for closing and re-opening the PR, I misclicked...) |
|
👏 |
|
|
||
| await api.setAddonShortcut(ADDON_ID, { | ||
| label: 'Reset viewport', | ||
| defaultShortcut: ['alt', 'V'], |
There was a problem hiding this comment.
I'm very sorry for that, Kaelig 😞 Is this alt + v combination a macOS's built-in shortcut?
There was a problem hiding this comment.
Yes, the option key is very commonly used in macOS to provide alternative characters or alternative key functionality (which is a feature I love and I miss a lot when I use Windows).
| prev, | ||
| next, | ||
| collapse, | ||
| ...getAddonsShortcuts(), |
There was a problem hiding this comment.
@apapadopoulou looks like this is where the shortcuts get added?

Issue: #14401
What I did
This is my very first time going deeper into Storybook's source code and architecture. I'm therefore not confident about all this but I really wanted to give it a try to learn and improve. My french fellow @kaelig* wanted a way to cycle through viewports using keyboard shortcuts, which is a great idea to save some time and efforts while visually testing components.
Defining this kind of addon-specific shortcuts should be the addon's responsibility: we obviously don't want to make them available if the relevant addon is not actually used and specified into Storybook's
main.jsconfiguration file. Unfortunately, I could not find any way to create addon-specific shortcuts. At the moment, it looks like Storybook does not offer addon developers such a feature, which could be really interesting way beyondaddon-viewport.This is why I've tried to go a bit further than the original issue's feature request by extending the shortcut API so that addon developers can provide their own shortcuts.
Extending the shortcut API
Storybook provides a shortcut API which exposes methods to get, set and reset shortcuts. This API is pretty narrow/restricted since it relies on some hard-coded and core-related values (e.g. go fullscreen, show/hide addons, etc.)
setAddonShortcut(addon, shortcut)First, I've added a
setAddonShortcutmethod which can be used to set addon-specific shortcuts. When called, it creates (or overwrites) a shortcut key whose name is a simple concatenation of the actual addon id and anactionNameto avoid potential duplicates across different addons. It also feeds a globaladdonsShortcutsobject which will be consumed later on to actually execute the relevant action and get the shortcut's description and default value.This method requires two arguments :
addon: a string which should correspond to the relevant addon's id (often set as aADDON_IDconstant).shortcut: an object of typeAddonShortcutwhich describes the actual shortcut.This
shortcutargument is explicitely typed (see theAddonShortcutinterface):label: Label of the shortcut which will be displayed in Storybook's keyboard shortcuts setting page/the menu.defaultShortcut: theKeyCollectionvalue which defines the expected keyboard shortcut key to apply the relevant action.actionName: the action name which should be unique within a single addon.showInMenu: a boolean which determines whether the shortcut should be displayed inside Storybook's menu. (optional and defaults tofalse).action: the actual action that should be triggered when pressing the shortcut key.Display and customize the addon shortcuts
At this point, the addon shortcuts should be working correctly if correctly set from any addon. However, Storybook:
Customize addon shortcuts
The Keyboard shortcuts page browses
shortcutKeysto build a list of all customizable shortcuts. ThisshortcutKeysnow includes our addon-specific shortcuts, which is pretty useful for the users to customize both core and addon-specific shortcuts . However, until now, every single shortcut had its label hard-coded through ashortcutLabelsconst passed as a prop to theShortcutsScreencomponent.I therefore needed a way to fetch the addon-specific shortcuts' labels/titles: this is why I've added both
getAddonsShortcutsandgetAddonsShortcutLabelsmethods to the shortcut API. They are used to pass addon-specific shortcuts' labels through anaddonsShortcutLabelsprop to theShortcutScreencomponent. This component will now try to display a shortcut's hard-coded label and if it does not exist, will try to display an addon-specific shortcut label.Customization and persistence are automatically handled by the existing shortcut API.
Reset shortcuts to their default values.
Similarly, core shortcuts' default values are hard-coded. I had to add
getAddonsShortcutDefaultsto get default values for addon shortcuts, and agetDefaultShortcutswhich returns a merged object of both core and addon-specific shortcuts' default values to makerestoreAllDefaultShortcutsandrestoreDefaultShortcutwork properly in both cases.Display shortcuts into Storybook's menu
I also made it possible to display addon-specific shortcuts into the Storybook's menu. When adding an addon-specific shortcut, you just have to set the
showInMenuproperty totrue. It will also make use of thegetAddonsShortcutsandgetAddonsShortcutLabelsmethods from the updated shortcut API to display the right label.Adding
addon-viewportshortcutsI've used the updated shortcut API to add three different shortcuts to the viewport addon:
shift + vto set to the previous viewport.vto set to the next viewport.ctrl + vto reset the viewport (not referenced in the original issue).These shortcuts are registered one at a time from an async function (
registerShortcuts). To be honest, I did not really know the best way to call this function: I just assumed it had to be called within the Functional Component since callinguseStorybookApianywhere else would raise an error. I eventually called it inside auseEffecthook without an empty dep array to avoid useless calls. Unfortunately, it still gets called twice instead of just once and I'm not sure why.Pitfalls and notes
addon-viewportto list the different shortcuts (previous viewport, next viewport, clear viewport).How to test
(*) I'm still waiting for that design tokens roundtable transcript kaelig, ne m'oublie pas please ! 😛
Edit 24/04/2021 : I remove the WIP status: I need some feedback which is not likely to happen from a draft state. Please do not hesitate pointing out anythig I could have done wrong and help me improve, <3