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

Make the shortcut provider optional #53942

Closed
wants to merge 11 commits into from

Conversation

youknowriad
Copy link
Contributor

Partially reverts #34539
Related #53874

What and why?

Gutenberg can be used as a platform/framework to build block editors. Mainly thanks to the @wordpress/block-editor package. That said, the experience today is not as straightforward as it can be. There can be a lot of small gotchas and hacks you need to do in order to achieve the desired result. One of these small things is the need to manually render ShortcutProvider component, this PR bundles this behavior within the BlockEditorProvider component, that way custom block editors don't have to render this extra component.

The original PR says that it only impacts "focus loss" behavior but that is not true, if you navigate in the browser between different pages in WP-Admin, focus is moved to the "body" when you enter new pages and some keyboard shortcuts are expected to work in that context directly without the need to focus any part of the UI. For instance the global command palette shortcut. This means that the current PR also fixes a bug.

Testing Instructions

1- Check that the different keyboard shortcuts still work as intended. I'm honestly not 100% confident about the impact here but I believe it's a good improvement.

@youknowriad youknowriad force-pushed the update/make-shortcuts-provider-optional branch from 28fd16a to a7151ed Compare August 25, 2023 11:21
@github-actions
Copy link

github-actions bot commented Aug 25, 2023

Size Change: +163 B (0%)

Total Size: 1.51 MB

Filename Size Change
build/block-editor/index.min.js 213 kB +51 B (0%)
build/components/index.min.js 245 kB +18 B (0%)
build/customize-widgets/index.min.js 12 kB -8 B (0%)
build/edit-post/index.min.js 35.4 kB -8 B (0%)
build/edit-site/index.min.js 91 kB -18 B (0%)
build/edit-widgets/index.min.js 16.9 kB -13 B (0%)
build/keyboard-shortcuts/index.min.js 1.78 kB +141 B (+9%) 🔍
ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 955 B
build/annotations/index.min.js 2.69 kB
build/api-fetch/index.min.js 2.28 kB
build/autop/index.min.js 2.1 kB
build/blob/index.min.js 451 B
build/block-directory/index.min.js 7.01 kB
build/block-directory/style-rtl.css 1.02 kB
build/block-directory/style.css 1.02 kB
build/block-editor/content-rtl.css 4.25 kB
build/block-editor/content.css 4.24 kB
build/block-editor/default-editor-styles-rtl.css 381 B
build/block-editor/default-editor-styles.css 381 B
build/block-editor/style-rtl.css 15 kB
build/block-editor/style.css 15 kB
build/block-library/blocks/archives/editor-rtl.css 61 B
build/block-library/blocks/archives/editor.css 60 B
build/block-library/blocks/archives/style-rtl.css 90 B
build/block-library/blocks/archives/style.css 90 B
build/block-library/blocks/audio/editor-rtl.css 150 B
build/block-library/blocks/audio/editor.css 150 B
build/block-library/blocks/audio/style-rtl.css 122 B
build/block-library/blocks/audio/style.css 122 B
build/block-library/blocks/audio/theme-rtl.css 126 B
build/block-library/blocks/audio/theme.css 126 B
build/block-library/blocks/avatar/editor-rtl.css 116 B
build/block-library/blocks/avatar/editor.css 116 B
build/block-library/blocks/avatar/style-rtl.css 104 B
build/block-library/blocks/avatar/style.css 104 B
build/block-library/blocks/block/editor-rtl.css 305 B
build/block-library/blocks/block/editor.css 305 B
build/block-library/blocks/button/editor-rtl.css 584 B
build/block-library/blocks/button/editor.css 582 B
build/block-library/blocks/button/style-rtl.css 629 B
build/block-library/blocks/button/style.css 628 B
build/block-library/blocks/buttons/editor-rtl.css 337 B
build/block-library/blocks/buttons/editor.css 337 B
build/block-library/blocks/buttons/style-rtl.css 332 B
build/block-library/blocks/buttons/style.css 332 B
build/block-library/blocks/calendar/style-rtl.css 239 B
build/block-library/blocks/calendar/style.css 239 B
build/block-library/blocks/categories/editor-rtl.css 113 B
build/block-library/blocks/categories/editor.css 112 B
build/block-library/blocks/categories/style-rtl.css 124 B
build/block-library/blocks/categories/style.css 124 B
build/block-library/blocks/code/editor-rtl.css 53 B
build/block-library/blocks/code/editor.css 53 B
build/block-library/blocks/code/style-rtl.css 121 B
build/block-library/blocks/code/style.css 121 B
build/block-library/blocks/code/theme-rtl.css 124 B
build/block-library/blocks/code/theme.css 124 B
build/block-library/blocks/columns/editor-rtl.css 108 B
build/block-library/blocks/columns/editor.css 108 B
build/block-library/blocks/columns/style-rtl.css 421 B
build/block-library/blocks/columns/style.css 421 B
build/block-library/blocks/comment-author-avatar/editor-rtl.css 125 B
build/block-library/blocks/comment-author-avatar/editor.css 125 B
build/block-library/blocks/comment-content/style-rtl.css 92 B
build/block-library/blocks/comment-content/style.css 92 B
build/block-library/blocks/comment-template/style-rtl.css 199 B
build/block-library/blocks/comment-template/style.css 198 B
build/block-library/blocks/comments-pagination-numbers/editor-rtl.css 123 B
build/block-library/blocks/comments-pagination-numbers/editor.css 121 B
build/block-library/blocks/comments-pagination/editor-rtl.css 222 B
build/block-library/blocks/comments-pagination/editor.css 209 B
build/block-library/blocks/comments-pagination/style-rtl.css 235 B
build/block-library/blocks/comments-pagination/style.css 231 B
build/block-library/blocks/comments-title/editor-rtl.css 75 B
build/block-library/blocks/comments-title/editor.css 75 B
build/block-library/blocks/comments/editor-rtl.css 840 B
build/block-library/blocks/comments/editor.css 839 B
build/block-library/blocks/comments/style-rtl.css 637 B
build/block-library/blocks/comments/style.css 636 B
build/block-library/blocks/cover/editor-rtl.css 647 B
build/block-library/blocks/cover/editor.css 650 B
build/block-library/blocks/cover/style-rtl.css 1.63 kB
build/block-library/blocks/cover/style.css 1.62 kB
build/block-library/blocks/details/editor-rtl.css 65 B
build/block-library/blocks/details/editor.css 65 B
build/block-library/blocks/details/style-rtl.css 98 B
build/block-library/blocks/details/style.css 98 B
build/block-library/blocks/embed/editor-rtl.css 293 B
build/block-library/blocks/embed/editor.css 293 B
build/block-library/blocks/embed/style-rtl.css 410 B
build/block-library/blocks/embed/style.css 410 B
build/block-library/blocks/embed/theme-rtl.css 126 B
build/block-library/blocks/embed/theme.css 126 B
build/block-library/blocks/file/editor-rtl.css 316 B
build/block-library/blocks/file/editor.css 316 B
build/block-library/blocks/file/style-rtl.css 280 B
build/block-library/blocks/file/style.css 281 B
build/block-library/blocks/file/view-interactivity.min.js 317 B
build/block-library/blocks/file/view.min.js 375 B
build/block-library/blocks/footnotes/style-rtl.css 201 B
build/block-library/blocks/footnotes/style.css 199 B
build/block-library/blocks/freeform/editor-rtl.css 2.61 kB
build/block-library/blocks/freeform/editor.css 2.61 kB
build/block-library/blocks/gallery/editor-rtl.css 947 B
build/block-library/blocks/gallery/editor.css 952 B
build/block-library/blocks/gallery/style-rtl.css 1.53 kB
build/block-library/blocks/gallery/style.css 1.53 kB
build/block-library/blocks/gallery/theme-rtl.css 108 B
build/block-library/blocks/gallery/theme.css 108 B
build/block-library/blocks/group/editor-rtl.css 654 B
build/block-library/blocks/group/editor.css 654 B
build/block-library/blocks/group/style-rtl.css 57 B
build/block-library/blocks/group/style.css 57 B
build/block-library/blocks/group/theme-rtl.css 78 B
build/block-library/blocks/group/theme.css 78 B
build/block-library/blocks/heading/style-rtl.css 76 B
build/block-library/blocks/heading/style.css 76 B
build/block-library/blocks/html/editor-rtl.css 336 B
build/block-library/blocks/html/editor.css 337 B
build/block-library/blocks/image/editor-rtl.css 834 B
build/block-library/blocks/image/editor.css 833 B
build/block-library/blocks/image/style-rtl.css 1.42 kB
build/block-library/blocks/image/style.css 1.41 kB
build/block-library/blocks/image/theme-rtl.css 126 B
build/block-library/blocks/image/theme.css 126 B
build/block-library/blocks/image/view-interactivity.min.js 1.83 kB
build/block-library/blocks/latest-comments/style-rtl.css 357 B
build/block-library/blocks/latest-comments/style.css 357 B
build/block-library/blocks/latest-posts/editor-rtl.css 213 B
build/block-library/blocks/latest-posts/editor.css 212 B
build/block-library/blocks/latest-posts/style-rtl.css 478 B
build/block-library/blocks/latest-posts/style.css 478 B
build/block-library/blocks/list/style-rtl.css 88 B
build/block-library/blocks/list/style.css 88 B
build/block-library/blocks/media-text/editor-rtl.css 266 B
build/block-library/blocks/media-text/editor.css 263 B
build/block-library/blocks/media-text/style-rtl.css 505 B
build/block-library/blocks/media-text/style.css 503 B
build/block-library/blocks/more/editor-rtl.css 431 B
build/block-library/blocks/more/editor.css 431 B
build/block-library/blocks/navigation-link/editor-rtl.css 712 B
build/block-library/blocks/navigation-link/editor.css 711 B
build/block-library/blocks/navigation-link/style-rtl.css 115 B
build/block-library/blocks/navigation-link/style.css 115 B
build/block-library/blocks/navigation-submenu/editor-rtl.css 296 B
build/block-library/blocks/navigation-submenu/editor.css 295 B
build/block-library/blocks/navigation/editor-rtl.css 2.26 kB
build/block-library/blocks/navigation/editor.css 2.26 kB
build/block-library/blocks/navigation/style-rtl.css 2.23 kB
build/block-library/blocks/navigation/style.css 2.22 kB
build/block-library/blocks/navigation/view-interactivity.min.js 988 B
build/block-library/blocks/navigation/view-modal.min.js 2.85 kB
build/block-library/blocks/navigation/view.min.js 469 B
build/block-library/blocks/nextpage/editor-rtl.css 395 B
build/block-library/blocks/nextpage/editor.css 395 B
build/block-library/blocks/page-list/editor-rtl.css 401 B
build/block-library/blocks/page-list/editor.css 401 B
build/block-library/blocks/page-list/style-rtl.css 175 B
build/block-library/blocks/page-list/style.css 175 B
build/block-library/blocks/paragraph/editor-rtl.css 174 B
build/block-library/blocks/paragraph/editor.css 174 B
build/block-library/blocks/paragraph/style-rtl.css 279 B
build/block-library/blocks/paragraph/style.css 281 B
build/block-library/blocks/post-author/style-rtl.css 175 B
build/block-library/blocks/post-author/style.css 176 B
build/block-library/blocks/post-comments-form/editor-rtl.css 96 B
build/block-library/blocks/post-comments-form/editor.css 96 B
build/block-library/blocks/post-comments-form/style-rtl.css 508 B
build/block-library/blocks/post-comments-form/style.css 508 B
build/block-library/blocks/post-date/style-rtl.css 61 B
build/block-library/blocks/post-date/style.css 61 B
build/block-library/blocks/post-excerpt/editor-rtl.css 71 B
build/block-library/blocks/post-excerpt/editor.css 71 B
build/block-library/blocks/post-excerpt/style-rtl.css 141 B
build/block-library/blocks/post-excerpt/style.css 141 B
build/block-library/blocks/post-featured-image/editor-rtl.css 588 B
build/block-library/blocks/post-featured-image/editor.css 586 B
build/block-library/blocks/post-featured-image/style-rtl.css 319 B
build/block-library/blocks/post-featured-image/style.css 319 B
build/block-library/blocks/post-navigation-link/style-rtl.css 153 B
build/block-library/blocks/post-navigation-link/style.css 153 B
build/block-library/blocks/post-template/editor-rtl.css 99 B
build/block-library/blocks/post-template/editor.css 98 B
build/block-library/blocks/post-template/style-rtl.css 314 B
build/block-library/blocks/post-template/style.css 314 B
build/block-library/blocks/post-terms/style-rtl.css 96 B
build/block-library/blocks/post-terms/style.css 96 B
build/block-library/blocks/post-time-to-read/style-rtl.css 69 B
build/block-library/blocks/post-time-to-read/style.css 69 B
build/block-library/blocks/post-title/style-rtl.css 100 B
build/block-library/blocks/post-title/style.css 100 B
build/block-library/blocks/preformatted/style-rtl.css 125 B
build/block-library/blocks/preformatted/style.css 125 B
build/block-library/blocks/pullquote/editor-rtl.css 135 B
build/block-library/blocks/pullquote/editor.css 135 B
build/block-library/blocks/pullquote/style-rtl.css 335 B
build/block-library/blocks/pullquote/style.css 335 B
build/block-library/blocks/pullquote/theme-rtl.css 168 B
build/block-library/blocks/pullquote/theme.css 168 B
build/block-library/blocks/query-pagination-numbers/editor-rtl.css 122 B
build/block-library/blocks/query-pagination-numbers/editor.css 121 B
build/block-library/blocks/query-pagination/editor-rtl.css 221 B
build/block-library/blocks/query-pagination/editor.css 211 B
build/block-library/blocks/query-pagination/style-rtl.css 302 B
build/block-library/blocks/query-pagination/style.css 299 B
build/block-library/blocks/query-title/style-rtl.css 63 B
build/block-library/blocks/query-title/style.css 63 B
build/block-library/blocks/query/editor-rtl.css 450 B
build/block-library/blocks/query/editor.css 449 B
build/block-library/blocks/query/style-rtl.css 370 B
build/block-library/blocks/query/style.css 368 B
build/block-library/blocks/query/view.min.js 559 B
build/block-library/blocks/quote/style-rtl.css 222 B
build/block-library/blocks/quote/style.css 222 B
build/block-library/blocks/quote/theme-rtl.css 223 B
build/block-library/blocks/quote/theme.css 226 B
build/block-library/blocks/read-more/style-rtl.css 132 B
build/block-library/blocks/read-more/style.css 132 B
build/block-library/blocks/rss/editor-rtl.css 149 B
build/block-library/blocks/rss/editor.css 149 B
build/block-library/blocks/rss/style-rtl.css 289 B
build/block-library/blocks/rss/style.css 288 B
build/block-library/blocks/search/editor-rtl.css 178 B
build/block-library/blocks/search/editor.css 178 B
build/block-library/blocks/search/style-rtl.css 607 B
build/block-library/blocks/search/style.css 607 B
build/block-library/blocks/search/theme-rtl.css 114 B
build/block-library/blocks/search/theme.css 114 B
build/block-library/blocks/search/view.min.js 631 B
build/block-library/blocks/separator/editor-rtl.css 146 B
build/block-library/blocks/separator/editor.css 146 B
build/block-library/blocks/separator/style-rtl.css 234 B
build/block-library/blocks/separator/style.css 234 B
build/block-library/blocks/separator/theme-rtl.css 194 B
build/block-library/blocks/separator/theme.css 194 B
build/block-library/blocks/shortcode/editor-rtl.css 323 B
build/block-library/blocks/shortcode/editor.css 323 B
build/block-library/blocks/site-logo/editor-rtl.css 754 B
build/block-library/blocks/site-logo/editor.css 754 B
build/block-library/blocks/site-logo/style-rtl.css 204 B
build/block-library/blocks/site-logo/style.css 204 B
build/block-library/blocks/site-tagline/editor-rtl.css 86 B
build/block-library/blocks/site-tagline/editor.css 86 B
build/block-library/blocks/site-title/editor-rtl.css 116 B
build/block-library/blocks/site-title/editor.css 116 B
build/block-library/blocks/site-title/style-rtl.css 57 B
build/block-library/blocks/site-title/style.css 57 B
build/block-library/blocks/social-link/editor-rtl.css 184 B
build/block-library/blocks/social-link/editor.css 184 B
build/block-library/blocks/social-links/editor-rtl.css 682 B
build/block-library/blocks/social-links/editor.css 681 B
build/block-library/blocks/social-links/style-rtl.css 1.44 kB
build/block-library/blocks/social-links/style.css 1.43 kB
build/block-library/blocks/spacer/editor-rtl.css 348 B
build/block-library/blocks/spacer/editor.css 348 B
build/block-library/blocks/spacer/style-rtl.css 48 B
build/block-library/blocks/spacer/style.css 48 B
build/block-library/blocks/table/editor-rtl.css 432 B
build/block-library/blocks/table/editor.css 432 B
build/block-library/blocks/table/style-rtl.css 639 B
build/block-library/blocks/table/style.css 639 B
build/block-library/blocks/table/theme-rtl.css 146 B
build/block-library/blocks/table/theme.css 146 B
build/block-library/blocks/tag-cloud/style-rtl.css 251 B
build/block-library/blocks/tag-cloud/style.css 253 B
build/block-library/blocks/template-part/editor-rtl.css 403 B
build/block-library/blocks/template-part/editor.css 403 B
build/block-library/blocks/template-part/theme-rtl.css 101 B
build/block-library/blocks/template-part/theme.css 101 B
build/block-library/blocks/term-description/style-rtl.css 111 B
build/block-library/blocks/term-description/style.css 111 B
build/block-library/blocks/text-columns/editor-rtl.css 95 B
build/block-library/blocks/text-columns/editor.css 95 B
build/block-library/blocks/text-columns/style-rtl.css 166 B
build/block-library/blocks/text-columns/style.css 166 B
build/block-library/blocks/verse/style-rtl.css 99 B
build/block-library/blocks/verse/style.css 99 B
build/block-library/blocks/video/editor-rtl.css 552 B
build/block-library/blocks/video/editor.css 555 B
build/block-library/blocks/video/style-rtl.css 185 B
build/block-library/blocks/video/style.css 185 B
build/block-library/blocks/video/theme-rtl.css 126 B
build/block-library/blocks/video/theme.css 126 B
build/block-library/classic-rtl.css 179 B
build/block-library/classic.css 179 B
build/block-library/common-rtl.css 1.1 kB
build/block-library/common.css 1.1 kB
build/block-library/editor-elements-rtl.css 75 B
build/block-library/editor-elements.css 75 B
build/block-library/editor-rtl.css 12.1 kB
build/block-library/editor.css 12.1 kB
build/block-library/elements-rtl.css 54 B
build/block-library/elements.css 54 B
build/block-library/index.min.js 203 kB
build/block-library/reset-rtl.css 478 B
build/block-library/reset.css 478 B
build/block-library/style-rtl.css 13.8 kB
build/block-library/style.css 13.8 kB
build/block-library/theme-rtl.css 688 B
build/block-library/theme.css 693 B
build/block-serialization-default-parser/index.min.js 1.12 kB
build/block-serialization-spec-parser/index.min.js 2.87 kB
build/blocks/index.min.js 51.4 kB
build/commands/index.min.js 15.5 kB
build/commands/style-rtl.css 932 B
build/commands/style.css 929 B
build/components/style-rtl.css 11.8 kB
build/components/style.css 11.8 kB
build/compose/index.min.js 12.1 kB
build/core-commands/index.min.js 2.72 kB
build/core-data/index.min.js 16.8 kB
build/customize-widgets/style-rtl.css 1.46 kB
build/customize-widgets/style.css 1.45 kB
build/data-controls/index.min.js 640 B
build/data/index.min.js 8.38 kB
build/date/index.min.js 17.8 kB
build/deprecated/index.min.js 451 B
build/dom-ready/index.min.js 324 B
build/dom/index.min.js 4.64 kB
build/edit-post/classic-rtl.css 544 B
build/edit-post/classic.css 545 B
build/edit-post/style-rtl.css 7.62 kB
build/edit-post/style.css 7.62 kB
build/edit-site/style-rtl.css 13.2 kB
build/edit-site/style.css 13.2 kB
build/edit-widgets/style-rtl.css 4.52 kB
build/edit-widgets/style.css 4.52 kB
build/editor/index.min.js 45.5 kB
build/editor/style-rtl.css 3.53 kB
build/editor/style.css 3.52 kB
build/element/index.min.js 4.82 kB
build/escape-html/index.min.js 537 B
build/format-library/index.min.js 7.59 kB
build/format-library/style-rtl.css 554 B
build/format-library/style.css 553 B
build/hooks/index.min.js 1.55 kB
build/html-entities/index.min.js 448 B
build/i18n/index.min.js 3.58 kB
build/interactivity/index.min.js 11.2 kB
build/is-shallow-equal/index.min.js 527 B
build/keycodes/index.min.js 1.87 kB
build/list-reusable-blocks/index.min.js 2.2 kB
build/list-reusable-blocks/style-rtl.css 836 B
build/list-reusable-blocks/style.css 836 B
build/media-utils/index.min.js 2.9 kB
build/notices/index.min.js 948 B
build/nux/index.min.js 1.99 kB
build/nux/style-rtl.css 735 B
build/nux/style.css 732 B
build/patterns/index.min.js 2.71 kB
build/patterns/style-rtl.css 240 B
build/patterns/style.css 240 B
build/plugins/index.min.js 1.79 kB
build/preferences-persistence/index.min.js 1.84 kB
build/preferences/index.min.js 1.24 kB
build/primitives/index.min.js 943 B
build/priority-queue/index.min.js 1.52 kB
build/private-apis/index.min.js 958 B
build/react-i18n/index.min.js 615 B
build/react-refresh-entry/index.min.js 9.47 kB
build/react-refresh-runtime/index.min.js 7.31 kB
build/redux-routine/index.min.js 2.7 kB
build/reusable-blocks/index.min.js 2.7 kB
build/reusable-blocks/style-rtl.css 243 B
build/reusable-blocks/style.css 243 B
build/rich-text/index.min.js 11 kB
build/router/index.min.js 1.78 kB
build/server-side-render/index.min.js 1.94 kB
build/shortcode/index.min.js 1.39 kB
build/style-engine/index.min.js 1.85 kB
build/sync/index.min.js 53.8 kB
build/token-list/index.min.js 582 B
build/url/index.min.js 3.73 kB
build/vendors/inert-polyfill.min.js 2.48 kB
build/vendors/react-dom.min.js 41.8 kB
build/vendors/react.min.js 4.02 kB
build/viewport/index.min.js 958 B
build/warning/index.min.js 249 B
build/widgets/index.min.js 7.16 kB
build/widgets/style-rtl.css 1.15 kB
build/widgets/style.css 1.16 kB
build/wordcount/index.min.js 1.02 kB

compressed-size-action

@@ -35,16 +34,14 @@ export default function App() {
}

return (
<ShortcutProvider style={ { height: '100%' } }>
Copy link
Member

Choose a reason for hiding this comment

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

It seems like this code was relying on ShortcutProvider having a div. Not sure if we should not add a div, but if things work I guess we can keep this change.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah I think this height was there to ensure the editor was full height and the removal of the height is probably going to have the same effect. Of course checking that the site editor is still full height.

Copy link
Member

@jorgefilipecosta jorgefilipecosta left a comment

Choose a reason for hiding this comment

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

These end to end test failure may be relevant:

  • [chromium] › editor/various/shortcut-focus-toolbar.spec.js:17:2 › Focus toolbar shortcut (alt + F10) › Focuses correct toolbar in default view options in edit mode
    Error: expect(received).toBeFocused()
  • [chromium] › editor/blocks/heading.spec.js:183:2 › Heading › should change heading level with keyboard shortcuts

Copy link
Member

@jorgefilipecosta jorgefilipecosta left a comment

Choose a reason for hiding this comment

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

The change seems good but I'm able to reproduce the end to end test failures with manual testing.
On Mac option + f10 (may need to press fn) on trunk focus the toolbar in this branch it does not. On Mac in trunk control + option + (1,2,3,4,5,6) changes heading in this branch, it does not.

@youknowriad
Copy link
Contributor Author

So it's actually the iframe that is preventing the events from propagating to the parent event handler. In trunk, there's the same problem for real DOM events but React does some trickery to bubble these as react events (when using onKeyDown props...). I wonder if we should just find a way to bubble these in the iframe instead of forcing a provider.

@youknowriad
Copy link
Contributor Author

It turns out that we were already bubbling some event types through the iframe, I've added the keydown events to the list, let's see if it fixes the tests. At least it fixed the focusToolbar in my tests.

@github-actions
Copy link

github-actions bot commented Aug 28, 2023

Flaky tests detected in 687c653.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/6013649089
📝 Reported issues:

Copy link
Member

@jsnajdr jsnajdr left a comment

Choose a reason for hiding this comment

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

The useShortcut function will need to updated, too, because the method on the context object is no longer delete, but remove.

There are two additional nice-to-have improvements on useShortcut:

  • set the callbackRef.current value in useEffect rather than during render. That's the canonical recommended approach to do this typical task.
  • the isDisabled prop should default to false. Then the isDisabled value inside the function doesn't alternate between undefined and false, possibly rerunning the effect even though it doesn't need to.

packages/keyboard-shortcuts/src/context.js Outdated Show resolved Hide resolved
packages/keyboard-shortcuts/src/context.js Outdated Show resolved Hide resolved
packages/keyboard-shortcuts/src/hooks/use-shortcut.js Outdated Show resolved Hide resolved
};
}, [ name, isDisabled ] );
}, [ name, isDisabled, shortcuts ] );
Copy link
Member

Choose a reason for hiding this comment

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

It good that shortcuts ended up being a dependency. If the context value changes, then all shortcuts will be removed from the old registry and added to the new one, automatically.

@youknowriad youknowriad enabled auto-merge (squash) August 29, 2023 14:27
@youknowriad
Copy link
Contributor Author

I've noticed that a lot e2e test failures were because events were triggering twice now (it started happening when I added the bubbling of keydown events from the iframe to the parent component) and I've fixed most of these by just adding stopPropagation call on the event handler.

So I'm wondering:

  • Why are we catching the event twice, it's almost like the KeyboardShortcutContext is registered twice even though I'm not using ShortcutProvider at all so in theory, we should only have the "global listener".

  • Maybe the iframe bubbling code has a bug that forwards the event twice?

Any idea @jsnajdr @ellatrix

@jsnajdr
Copy link
Member

jsnajdr commented Aug 30, 2023

I'll try to debug this. I suspect that it has something to do with how React attaches DOM listeners. When there is a React element with a React event listener:

<div onKeydown={ handleKeydown } />

then the real DOM listener is not attached on the div, but on the React root element, and React uses event.target to figure out that it should call the handleKeydown function.

That affects the order in which handlers are called during the capture and bubbling phases.

@jsnajdr
Copy link
Member

jsnajdr commented Aug 30, 2023

Some findings. The e2e failure occurs when a custom completer is active, it looks like this:

Screenshot 2023-08-30 at 12 46 46

Now, when I press Escape, the completer popover disappears, and the paragraph element now loses focus. Before this PR, the document.activeElement was the p element all the time, now the focus goes to the body element after Escape. Further typing doesn't go into the paragraph block, but the e2e test expects that it goes.

This is caused by the newly introduced bubbling of the keydown events. When I disable the frameElement.dispatchEvent call, the bug disappears.

And it has nothing to do with the global keydown listener for shortcuts. If I disable the listener, the bug is still there.

I'll continue searching for the code that causes the focus loss.

@@ -71,44 +71,51 @@ export default function BlockTools( {
const clientIds = getSelectedBlockClientIds();
if ( clientIds.length ) {
event.preventDefault();
event.stopPropagation();
Copy link
Member

@ellatrix ellatrix Aug 30, 2023

Choose a reason for hiding this comment

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

Why are we stopping propagation? This is usually a sign that something is wrong. You're preventing components up the tree from listening to this event.

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'm explaining this here, #53942 (comment) I think we have a bug in the event bubbling code that make the event handler trigger twice for some reason unless the event propagation is stopped. I don't understand why yet.

@@ -70,7 +70,7 @@ function bubbleEvents( doc ) {
}
}

const eventTypes = [ 'dragover', 'mousemove' ];
const eventTypes = [ 'dragover', 'mousemove', 'keydown' ];
Copy link
Member

Choose a reason for hiding this comment

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

We should definitely not add more event names to this list. Ideally we should removing this bubbling entirely.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If we're totally against this, the alternative would be to add a ShortcutProvider to the Iframe component to catch the keyboard shortcuts events. The problem though is that right now ShortcutProvider also serves as a registry for event handlers useShortcut calls, so we need to have two kind of providers:

  • One that keeps track of active event handlers.
  • One that only catches event and try to match them with active event handlers.

@jsnajdr
Copy link
Member

jsnajdr commented Aug 30, 2023

I'll continue searching for the code that causes the focus loss.

So, the offending focus call is on this line:

__unstableContentRef?.current.focus();

It's handler for the "Clear selection" keyboard shortcut that's registered, on the Esc key, here:

registerShortcut( {
name: 'core/block-editor/unselect',
category: 'selection',
description: __( 'Clear selection.' ),
keyCombination: {
character: 'escape',
},
} );

Now when we started forwarding the keydown event to the iframe's parent, the event is caught by the BlockTools component, which is the iframe's parent.

@ellatrix
Copy link
Member

I don't understand form the code what exactly ShortcutProvider is being replaced with. In any case, we need a div so that the shortcuts are scoped to that div (shortcuts shouldn't be global). So either we need to move this into BlockEditorProvider or BlockTools . BlockTools (it already has a div that has an onKeyDown listener for other shortcuts) could work too because InspectorControls actually contains a slot from within the block, so shortcuts should continue to work in there.

@youknowriad
Copy link
Contributor Author

I don't understand form the code what exactly ShortcutProvider is being replaced with. In any case, we need a div so that the shortcuts are scoped to that div (shortcuts shouldn't be global).

I disagree with this take, some shortcuts don't need a div, like command palette. Maybe some block editor shortcuts need a div but right now in trunk that div is a random div containing the whole page and not something scoped to the block editor.

@youknowriad
Copy link
Contributor Author

youknowriad commented Aug 30, 2023

@jsnajdr interesting find.

The question is: in "trunk" that event handler "core/block-editor/unselect" is also supposed to be triggered when you hit "Escape" (it's just caught differently using a global React listener and not DOM listener). So I'd say that probably there's some code that "prevents bubbling" or "prevents default" already in place but that code only run when the auto-complete is open.

So IMO, the problem is still the same as I said above: the event is kind of triggered twice, one of them is canceled/preventDefault/preventPropagation by the autocomplete but then the autocomplete closes and the second event is not cancelled causing the selection clear.

@youknowriad
Copy link
Contributor Author

youknowriad commented Aug 30, 2023

Ok after a discussion with @ellatrix we figured that iframe event bubbling results in "two React event handlers" being triggered because of React's internal behavior and the new event the bubbling causes.

and BlockTools is relying on its own react event handler and does not use the "Shortcuts" package default one (which is a DOM one), so it creates the double events issue.

This kind of forces to rethink this PR a bit. My current plan is the following:

  • Replace iframe event bubbling with a ShortcutEventProvider that catches all events and forward them to the registered handlers.
  • Find a way to keep the global event handler on body.
  • Potentially find a way to keep the scoped event handlers (the event handler of BlockTools is scoped), maybe by passing a "ref" as a scope argument to useShortcut call.

@ellatrix
Copy link
Member

Thanks @youknowriad!

@youknowriad
Copy link
Contributor Author

Pushed a commit to implement the proposed solution (kept the iframe bubbling temporarily). I'm not entirely satisfied for a few reasons:

  • I don't like passing "ref objects" as arguments to hooks because these are dependent on component lifecycle for instance if the element unmounts, the ref is no longer valid.
  • I noticed that several of our block editor shortcuts (removal, inserter after, insert before, duplicate) are actually duplicated in the code base between two or more places. I suspect that it's because we have scoping in place, these shortcuts would have worked if they were not scope. Maybe there's another way to handle these shortcuts or share their implementation. The existing BlockActions component was meant to share this kind of logic but it's failing entirely. (probably out of scope of this PR though).
  • I like that this PR basically allows us to "remove" the __unstableUseShortcutEventMatch API.

@youknowriad youknowriad force-pushed the update/make-shortcuts-provider-optional branch from 717376a to 5c6c3ed Compare August 31, 2023 03:25
@youknowriad
Copy link
Contributor Author

youknowriad commented Aug 31, 2023

@ellatrix After thinking a bit here. I actually didn't feel great with the new "scope" API especially because of the weird refs passed around that it forces us to do. (Explained a bit better above)

So I decided to give the initial approach of this PR a second chance: iframe event bubbling but keeping the scoping you had in place in BlockTools and similar using "local" event handlers.

I managed to actually fix the problem we had with iframe event bubbling creating two react synthetic events, it's actually as simple as "prevent propagation" within the bubbling function.

The solution is here #54080

I've kept it on a separate PR/branch for us to compare but I'm personally more confident about #54080. it's less changes and keeps a very similar logic to trunk, only change is to switch the default event handler to an event handler on the body of the outer document.

@youknowriad
Copy link
Contributor Author

Closing this one in favor of #54080

@youknowriad youknowriad closed this Sep 4, 2023
auto-merge was automatically disabled September 4, 2023 09:51

Pull request was closed

@youknowriad youknowriad deleted the update/make-shortcuts-provider-optional branch September 4, 2023 09:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Type] Enhancement A suggestion for improvement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants