Skip to content
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

Add a new keyboard shortcut package #19100

Merged
merged 26 commits into from Dec 23, 2019
Merged

Conversation

youknowriad
Copy link
Contributor

@youknowriad youknowriad commented Dec 12, 2019

There's a few ideas in this PR:

  • Create a new package that handles the keyboard shortcuts in a data store:
    • Ultimately this allows us to implement a UI to change the keyboard combination per user.
    • Potentially, this also allows third-party shortcuts and shortcut categories.
  • Create a useShortcut hook as a replacement to the KeyboardShorcuts package but there's no need to pass the actual combination since it's retrieved from the store.
  • Refactors the BlockEditorKeyboardShortcuts component to use this new package. (Ultimately, all shortcuts should rely on this package).
  • While refactoring BlockEditorKeyboardShortcuts, I moved some logic we had in components into data actions (DuplicateBlocks, InsertBefore, InsertAfter actions) and also handle the checks in the action itself. Removing selectors calls from components into one of actions can have potential performance boost and also allow easy logic sharing. Related here, I think the BlockActions component should be deprecated and removed in favor of selectors and actions.

Once all the keyboard shortcuts refactored to use this package, the whole modal could be generated without any hard-coded code.

@youknowriad youknowriad added [Focus] Accessibility (a11y) Changes that impact accessibility and need corresponding review (e.g. markup changes). [a11y] Keyboard & Focus labels Dec 12, 2019
@youknowriad youknowriad self-assigned this Dec 12, 2019
@youknowriad youknowriad requested review from aduth, afercia and a team December 12, 2019 12:24
@gziolo
Copy link
Member

It's a huge PR and I won't have time to review but I applaud the efforts. Great idea 💯

Copy link
Contributor

@MarcoZehe MarcoZehe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found some misspellings of the word "shortcut" throughout the files and suggested corrections so they don't look weird.

packages/keyboard-shortcuts/package.json Outdated Show resolved Hide resolved
packages/keyboard-shortcuts/package.json Outdated Show resolved Hide resolved
packages/keyboard-shortcuts/src/hooks/use-shortcut.js Outdated Show resolved Hide resolved
packages/keyboard-shortcuts/src/hooks/use-shortcut.js Outdated Show resolved Hide resolved
packages/keyboard-shortcuts/src/hooks/use-shortcut.js Outdated Show resolved Hide resolved
packages/keyboard-shortcuts/src/hooks/use-shortcut.js Outdated Show resolved Hide resolved
packages/keyboard-shortcuts/src/store/selectors.js Outdated Show resolved Hide resolved
@youknowriad youknowriad force-pushed the add/keyboard-shortcuts-package branch 2 times, most recently from d810e97 to 6708224 Compare December 17, 2019 16:35
@youknowriad
Copy link
Contributor Author

I updated the Modal accordingly.

packages/keyboard-shortcuts/src/store/selectors.js Outdated Show resolved Hide resolved
packages/keyboard-shortcuts/src/store/actions.js Outdated Show resolved Hide resolved
packages/keyboard-shortcuts/src/store/actions.js Outdated Show resolved Hide resolved
packages/keyboard-shortcuts/src/hooks/use-shortcut.js Outdated Show resolved Hide resolved
packages/keyboard-shortcuts/src/hooks/use-shortcut.js Outdated Show resolved Hide resolved

shortcutKeys.forEach( ( shortcut ) => {
const keys = shortcut.split( '+' );
const modifiers = new Set( keys.filter( ( value ) => value.length > 1 ) );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the single-character modifier we're filtering here? Comment or externalized/named function could help clarify.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't tell. This is ported from KeyboardShortcuts.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like it determines whether a key is a modifier by the length of the string. E.g. if I add a pass a shortcut Shift+Cmd+M, it'll determine that the modifiers are Shift and Cmd because they're not a single character.

That does seem a little bit unusual. Might be safer to check against an array of known modifiers.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like it determines whether a key is a modifier by the length of the string. E.g. if I add a pass a shortcut Shift+Cmd+M, it'll determine that the modifiers are Shift and Cmd because they're not a single character.

That sounds about right.

Might be safer to check against an array of known modifiers.

I'd have been content if the original implementation had simply added an inline comment, to save ourselves the struggle in trying to decipher its meaning 😅

Copy link
Contributor

@talldan talldan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like the direction this is taking. 👍

I spotted a couple of bugs to be fixed - shortcuts not working and the unregister action has the wrong type.

packages/block-editor/src/store/actions.js Outdated Show resolved Hide resolved
packages/block-editor/src/store/actions.js Outdated Show resolved Hide resolved
packages/keyboard-shortcuts/src/store/actions.js Outdated Show resolved Hide resolved
packages/keyboard-shortcuts/src/store/actions.js Outdated Show resolved Hide resolved
// Registering the shortcuts
const { registerShortcut } = useDispatch( 'core/keyboard-shortcuts' );
useEffect( () => {
registerShortcut(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In terms of displaying a list of shortcuts in the help modal, it seems great that this can be done dynamically using the values from the store, and it might be good to move towards this more.

The main issue I see with shortcuts being registered in this way is that it could result in a situation where a component with shortcuts hasn't yet been rendered, meaning the shortcut isn't registered and so the description won't appear in the help modal.

I wondered if an api more like registerBlock in the blocks api might be preferable to get around that issue and then have these registered outside of the component scope.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think registration belongs to the initialization of a package. In this case, the block-editor package does both at the same time but I agree that we should be careful about that.

I do think it should always be tied to a component though and registerBlock is the wrong approach here (can't change now) to avoid globals. See #8981 for the problems of the globals approach.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be wrong, but I think a similar issue exists today with the KeyboardShortcuts component anyway. If I remember correctly that's why there was a separate BlockActions component in the first place—the shortcuts have to be rendered in a different part of the render tree. So it might be a moot point, if the component isn't rendered the shortcuts won't work.

There's one case where this is still a little problematic, which is if you load the editor in Code Editor mode and then open the help modal, Code Editor elminates a huge part of the render tree, including the shortcut registration. Most of the Block shortcuts are then not visible. 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's one case where this is still a little problematic, which is if you load the editor in Code Editor mode and then open the help modal, Code Editor elminates a huge part of the render tree, including the shortcut registration. Most of the Block shortcuts are then not visible.

That's a good point, I'll fix.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I split the registration and the handling into two components.

Copy link
Contributor

@talldan talldan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@youknowriad I took if for a one last spin and it's all working well. Code looks good to me too. 🎉

Only thing that might be nice is tests for those new selectors and reducers, but the bulk of the code looks great and I'm about to go away until 2020. 😄

youknowriad and others added 2 commits December 20, 2019 14:08
Co-Authored-By: Daniel Richards <daniel.richards@automattic.com>
keyCombination: '/',
description: __( 'Change the block type after adding a new paragraph.' ),
/* translators: The forward-slash character. e.g. '/'. */
ariaLabel: __( 'Forward-slash' ),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be an option in the shortcut registration? I see there's a few more usages of this in globalShortcuts as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potentially yes, we'll probably find a few other options once we refactor all existing shortcuts.

packages/keyboard-shortcuts/src/store/actions.js Outdated Show resolved Hide resolved
packages/keyboard-shortcuts/src/store/actions.js Outdated Show resolved Hide resolved
packages/keyboard-shortcuts/src/store/selectors.js Outdated Show resolved Hide resolved

shortcutKeys.forEach( ( shortcut ) => {
const keys = shortcut.split( '+' );
const modifiers = new Set( keys.filter( ( value ) => value.length > 1 ) );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like it determines whether a key is a modifier by the length of the string. E.g. if I add a pass a shortcut Shift+Cmd+M, it'll determine that the modifiers are Shift and Cmd because they're not a single character.

That sounds about right.

Might be safer to check against an array of known modifiers.

I'd have been content if the original implementation had simply added an inline comment, to save ourselves the struggle in trying to decipher its meaning 😅

youknowriad and others added 6 commits December 20, 2019 16:55
Co-Authored-By: Andrew Duthie <andrew@andrewduthie.com>
Co-Authored-By: Andrew Duthie <andrew@andrewduthie.com>
Co-Authored-By: Andrew Duthie <andrew@andrewduthie.com>
@youknowriad youknowriad merged commit fba1069 into master Dec 23, 2019
@youknowriad youknowriad deleted the add/keyboard-shortcuts-package branch December 23, 2019 08:26
@youknowriad youknowriad added the Needs Dev Note Requires a developer note for a major WordPress release cycle label Dec 23, 2019
@youknowriad youknowriad added this to the Gutenberg 7.2 milestone Jan 6, 2020
@jorgefilipecosta jorgefilipecosta mentioned this pull request Feb 12, 2020
23 tasks
@afercia
Copy link
Contributor

afercia commented Feb 19, 2020

Thanks for this change. Read also the dev-note post and looking forward to the next steps to offer "a centralized UI to modify the keyboard shortcuts per user" so that #3218 gets addressed 🎉

A couple quick questions /Cc @youknowriad

1
What happens when two or more plugins register the same shortcut? I do realize they're registered under different "namespaces" but in the browser they will conflict. E.g. a potential keyboard shortcut Cmd + Alt + F + O + O added by plugin X will conflict with Cmd + Alt + F + O + O added by plugin Y. Not sure what would actually happen in the browser. One of the twos might not work or both might be triggered simultaneously, which doesn't seem ideal. Does the package handle potential conflicts?

2
Regarding:

Registered shortcuts can also be unregistered (and potentially replaced) by third-party plugins

Does this mean plugin X can unregister a keyboard shortcut added by plugin Y? If so, that doesn't sound ideal as it actually allows plugins to disrupt other plugins functionalities.

@youknowriad
Copy link
Contributor Author

1-

I believe right now, both callbacks are triggered but we can enhance the package to do some conflicts detection.

2-

Yes, that's what it means but that's the case for blocks, for style variations, for any filter. Basically any WordPress API. So I'm not sure that's really a concern.

@@ -0,0 +1,32 @@
# Keycodes
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this was meant to be "Keyboard Shortcuts"? 😃 (Guessing it may have been missed for revision in a copy paste)

Related: https://github.com/WordPress/gutenberg/blob/master/packages/keycodes/README.md

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy/paste? me? never

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 8c6916c

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The commit doesn't seem right though :) copy/paste issue?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The commit doesn't seem right though :) copy/paste issue?

🤦‍♂ ac818ae

@youknowriad youknowriad removed the Needs Dev Note Requires a developer note for a major WordPress release cycle label Apr 8, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Focus] Accessibility (a11y) Changes that impact accessibility and need corresponding review (e.g. markup changes).
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants