-
-
Notifications
You must be signed in to change notification settings - Fork 9.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
API: Add addon keyboard shortcuts & create shortcuts for addon-viewport #14658
Conversation
Amazing, thank you for taking this on! Quick feedback: it might bother Windows and Linux users that the addon takes over CTRL+V 😅 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 🎉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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).
@@ -221,6 +235,7 @@ export const useMenu = ( | |||
prev, | |||
next, | |||
collapse, | |||
...getAddonsShortcuts(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@apapadopoulou looks like this is where the shortcuts get added?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, thank you!
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.js
configuration 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
setAddonShortcut
method 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 anactionName
to avoid potential duplicates across different addons. It also feeds a globaladdonsShortcuts
object 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_ID
constant).shortcut
: an object of typeAddonShortcut
which describes the actual shortcut.This
shortcut
argument is explicitely typed (see theAddonShortcut
interface):label
: Label of the shortcut which will be displayed in Storybook's keyboard shortcuts setting page/the menu.defaultShortcut
: theKeyCollection
value 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
shortcutKeys
to build a list of all customizable shortcuts. ThisshortcutKeys
now 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 ashortcutLabels
const passed as a prop to theShortcutsScreen
component.I therefore needed a way to fetch the addon-specific shortcuts' labels/titles: this is why I've added both
getAddonsShortcuts
andgetAddonsShortcutLabels
methods to the shortcut API. They are used to pass addon-specific shortcuts' labels through anaddonsShortcutLabels
prop to theShortcutScreen
component. 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
getAddonsShortcutDefaults
to get default values for addon shortcuts, and agetDefaultShortcuts
which returns a merged object of both core and addon-specific shortcuts' default values to makerestoreAllDefaultShortcuts
andrestoreDefaultShortcut
work 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
showInMenu
property totrue
. It will also make use of thegetAddonsShortcuts
andgetAddonsShortcutLabels
methods from the updated shortcut API to display the right label.Adding
addon-viewport
shortcutsI've used the updated shortcut API to add three different shortcuts to the viewport addon:
shift + v
to set to the previous viewport.v
to set to the next viewport.ctrl + v
to 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 callinguseStorybookApi
anywhere else would raise an error. I eventually called it inside auseEffect
hook 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-viewport
to 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