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

Fix multiple tooltips showing on NavigableToolbars #49644

Merged
merged 28 commits into from
Apr 19, 2023

Conversation

jeryj
Copy link
Contributor

@jeryj jeryj commented Apr 6, 2023

The 'core/block-editor/focus-toolbar' shortcut (alt + F10) selects the active navigable toolbar's first tabbable item, but when there are multiple navigable toolbars, it places focus on all of the active navigable toolbar components. This results in an odd state of two tooltips being open. This commit scaffolds the ability to disable the keyboard shortcut from applying.

Editor screen with Toggle block inserter and Paragraph tooltips open and focus on both buttons

TODO: Figure out how to identify if multiple NavigableToolbars are present, or at least tell the document toolbar not to show if the block toolbar is present.

What?

Only apply the shortcut to one NavigableToolbar component.

Why?

Each NavigableToolbar gets an alt + F10 (or fn + option + F10 on mac keyboards) shortcut added to it. When there are multiple NavigableToolbars components on the page, they all try to focus the first tabbable element within it, displaying multiple popovers at once.

How?

Add useKeyboardShortcut prop to NavigableToolbar and useToolbarFocus components so the document HeaderToolbar can disable itself from using the shortcut if the block toolbar is also showing.

If there are no selected blocks OR we're not in edit mode, then we'll allow the keyboard shortcut for the header toolbar to be active. There may be other conditions I'm missing to identify if a focusable block toolbar is showing.

The shortcut says Navigate to the nearest toolbar which means to me, "Move to the toolbar closest to my current focus in the DOM," but the implementation here is, "Move to the most specific toolbar." As in, if there is a block toolbar open, move to it. If there is only one toolbar open, move to it.

Testing Instructions

These are all documented in the e2e tests. To see them all running, add:

test.use( {
	launchOptions: {
		slowMo: 500,
	},
} );

to the top of test/e2e/specs/editor/various/shortcut-focus-toolbar.spec.js (like, line 5) and then run these tests with npm run test:e2e:playwright -- shortcut-focus-toolbar --headed

Testing Instructions for Keyboard

Block toolbar open

  • Move focus into a block to display the block toolbar.
  • Press alt + F10 (or fn + option + F10 on mac keyboards)
  • Focus should be applied to the block toolbar

No selected blocks

  • Hide the block toolbar by moving focus to the editor page title (or anywhere else)
  • Press alt + F10 (or fn + option + F10 on mac keyboards)
  • Focus should be in the document toolbar

In Select Mode

  • In the top document toolbar, change to Select mode
  • Place focus on a block
  • Press alt + F10 (or fn + option + F10 on mac keyboards)
  • Focus should be in the document toolbar

Basically, try to break it using all of the different view modes (Top Toolbar on/off, Spotlight mode, etc) and with an empty default blocks selected, a block selected, multiple blocks selected, etc. Anytime a block toolbar is showing, it should receive focus with the alt + F10 shortcut, and anytime it's not showing, focus should be in the top toolbar.

Screenshots or screencast

Broken state:
https://user-images.githubusercontent.com/967608/230490886-5849ba0e-1910-47b0-b522-750b2f99e70c.mov

@jeryj jeryj self-assigned this Apr 6, 2023
@jeryj jeryj changed the title Add useKeyboardShortcut prop to NavigableToolbar and useToolbarFocus Fix multiple tooltips showing on NavigableToolbars Apr 6, 2023
@github-actions
Copy link

github-actions bot commented Apr 6, 2023

Size Change: -2.76 kB (0%)

Total Size: 1.36 MB

Filename Size Change
build/block-editor/index.min.js 200 kB -2.92 kB (-1%)
build/edit-post/index.min.js 35.2 kB +155 B (0%)
ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 993 B
build/annotations/index.min.js 2.78 kB
build/api-fetch/index.min.js 2.27 kB
build/autop/index.min.js 2.15 kB
build/blob/index.min.js 483 B
build/block-directory/index.min.js 7.2 kB
build/block-directory/style-rtl.css 1.04 kB
build/block-directory/style.css 1.04 kB
build/block-editor/content-rtl.css 4.17 kB
build/block-editor/content.css 4.17 kB
build/block-editor/default-editor-styles-rtl.css 403 B
build/block-editor/default-editor-styles.css 403 B
build/block-editor/style-rtl.css 15.1 kB
build/block-editor/style.css 15.1 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 138 B
build/block-library/blocks/audio/theme.css 138 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 91 B
build/block-library/blocks/avatar/style.css 91 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 587 B
build/block-library/blocks/button/editor.css 587 B
build/block-library/blocks/button/style-rtl.css 628 B
build/block-library/blocks/button/style.css 627 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 409 B
build/block-library/blocks/columns/style.css 409 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 649 B
build/block-library/blocks/cover/editor.css 651 B
build/block-library/blocks/cover/style-rtl.css 1.61 kB
build/block-library/blocks/cover/style.css 1.6 kB
build/block-library/blocks/details-summary/editor-rtl.css 65 B
build/block-library/blocks/details-summary/editor.css 65 B
build/block-library/blocks/details-summary/style-rtl.css 61 B
build/block-library/blocks/details-summary/style.css 61 B
build/block-library/blocks/details/style-rtl.css 54 B
build/block-library/blocks/details/style.css 54 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 138 B
build/block-library/blocks/embed/theme.css 138 B
build/block-library/blocks/file/editor-rtl.css 300 B
build/block-library/blocks/file/editor.css 300 B
build/block-library/blocks/file/style-rtl.css 269 B
build/block-library/blocks/file/style.css 270 B
build/block-library/blocks/file/view.min.js 353 B
build/block-library/blocks/freeform/editor-rtl.css 2.44 kB
build/block-library/blocks/freeform/editor.css 2.44 kB
build/block-library/blocks/gallery/editor-rtl.css 984 B
build/block-library/blocks/gallery/editor.css 988 B
build/block-library/blocks/gallery/style-rtl.css 1.55 kB
build/block-library/blocks/gallery/style.css 1.55 kB
build/block-library/blocks/gallery/theme-rtl.css 122 B
build/block-library/blocks/gallery/theme.css 122 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 340 B
build/block-library/blocks/html/editor.css 341 B
build/block-library/blocks/image/editor-rtl.css 830 B
build/block-library/blocks/image/editor.css 829 B
build/block-library/blocks/image/style-rtl.css 652 B
build/block-library/blocks/image/style.css 652 B
build/block-library/blocks/image/theme-rtl.css 137 B
build/block-library/blocks/image/theme.css 137 B
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 507 B
build/block-library/blocks/media-text/style.css 505 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 716 B
build/block-library/blocks/navigation-link/editor.css 715 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 299 B
build/block-library/blocks/navigation-submenu/editor.css 299 B
build/block-library/blocks/navigation/editor-rtl.css 2.13 kB
build/block-library/blocks/navigation/editor.css 2.14 kB
build/block-library/blocks/navigation/style-rtl.css 2.22 kB
build/block-library/blocks/navigation/style.css 2.21 kB
build/block-library/blocks/navigation/view-modal.min.js 2.81 kB
build/block-library/blocks/navigation/view.min.js 447 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 501 B
build/block-library/blocks/post-comments-form/style.css 501 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 322 B
build/block-library/blocks/post-featured-image/style.css 322 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 281 B
build/block-library/blocks/post-template/style.css 281 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 103 B
build/block-library/blocks/preformatted/style.css 103 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 167 B
build/block-library/blocks/pullquote/theme.css 167 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 288 B
build/block-library/blocks/query-pagination/style.css 284 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 463 B
build/block-library/blocks/query/editor.css 463 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 165 B
build/block-library/blocks/search/editor.css 165 B
build/block-library/blocks/search/style-rtl.css 408 B
build/block-library/blocks/search/style.css 406 B
build/block-library/blocks/search/theme-rtl.css 114 B
build/block-library/blocks/search/theme.css 114 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 329 B
build/block-library/blocks/shortcode/editor.css 329 B
build/block-library/blocks/site-logo/editor-rtl.css 489 B
build/block-library/blocks/site-logo/editor.css 489 B
build/block-library/blocks/site-logo/style-rtl.css 203 B
build/block-library/blocks/site-logo/style.css 203 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 674 B
build/block-library/blocks/social-links/editor.css 673 B
build/block-library/blocks/social-links/style-rtl.css 1.4 kB
build/block-library/blocks/social-links/style.css 1.39 kB
build/block-library/blocks/spacer/editor-rtl.css 359 B
build/block-library/blocks/spacer/editor.css 359 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 433 B
build/block-library/blocks/table/editor.css 433 B
build/block-library/blocks/table/style-rtl.css 651 B
build/block-library/blocks/table/style.css 650 B
build/block-library/blocks/table/theme-rtl.css 157 B
build/block-library/blocks/table/theme.css 157 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 404 B
build/block-library/blocks/template-part/editor.css 404 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/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 179 B
build/block-library/blocks/video/style.css 179 B
build/block-library/blocks/video/theme-rtl.css 139 B
build/block-library/blocks/video/theme.css 139 B
build/block-library/classic-rtl.css 179 B
build/block-library/classic.css 179 B
build/block-library/common-rtl.css 1.12 kB
build/block-library/common.css 1.12 kB
build/block-library/editor-elements-rtl.css 75 B
build/block-library/editor-elements.css 75 B
build/block-library/editor-rtl.css 11.6 kB
build/block-library/editor.css 11.6 kB
build/block-library/elements-rtl.css 54 B
build/block-library/elements.css 54 B
build/block-library/index.min.js 204 kB
build/block-library/reset-rtl.css 478 B
build/block-library/reset.css 478 B
build/block-library/style-rtl.css 12.8 kB
build/block-library/style.css 12.8 kB
build/block-library/theme-rtl.css 698 B
build/block-library/theme.css 703 B
build/block-serialization-default-parser/index.min.js 1.13 kB
build/block-serialization-spec-parser/index.min.js 2.83 kB
build/blocks/index.min.js 51.1 kB
build/commands/index.min.js 14.8 kB
build/commands/style-rtl.css 789 B
build/commands/style.css 786 B
build/components/index.min.js 208 kB
build/components/style-rtl.css 11.7 kB
build/components/style.css 11.7 kB
build/compose/index.min.js 12.4 kB
build/core-data/index.min.js 16.3 kB
build/customize-widgets/index.min.js 12.2 kB
build/customize-widgets/style-rtl.css 1.41 kB
build/customize-widgets/style.css 1.41 kB
build/data-controls/index.min.js 718 B
build/data/index.min.js 8.68 kB
build/date/index.min.js 40.4 kB
build/deprecated/index.min.js 518 B
build/dom-ready/index.min.js 336 B
build/dom/index.min.js 4.76 kB
build/edit-post/classic-rtl.css 571 B
build/edit-post/classic.css 571 B
build/edit-post/style-rtl.css 7.63 kB
build/edit-post/style.css 7.63 kB
build/edit-site/index.min.js 64.5 kB
build/edit-site/style-rtl.css 10.1 kB
build/edit-site/style.css 10.1 kB
build/edit-widgets/index.min.js 17.3 kB
build/edit-widgets/style-rtl.css 4.56 kB
build/edit-widgets/style.css 4.56 kB
build/editor/index.min.js 45.9 kB
build/editor/style-rtl.css 3.49 kB
build/editor/style.css 3.48 kB
build/element/index.min.js 4.95 kB
build/escape-html/index.min.js 548 B
build/format-library/index.min.js 7.26 kB
build/format-library/style-rtl.css 557 B
build/format-library/style.css 556 B
build/hooks/index.min.js 1.66 kB
build/html-entities/index.min.js 454 B
build/i18n/index.min.js 3.79 kB
build/is-shallow-equal/index.min.js 535 B
build/keyboard-shortcuts/index.min.js 1.79 kB
build/keycodes/index.min.js 1.94 kB
build/list-reusable-blocks/index.min.js 2.14 kB
build/list-reusable-blocks/style-rtl.css 865 B
build/list-reusable-blocks/style.css 865 B
build/media-utils/index.min.js 2.99 kB
build/notices/index.min.js 977 B
build/plugins/index.min.js 1.94 kB
build/preferences-persistence/index.min.js 2.23 kB
build/preferences/index.min.js 1.35 kB
build/primitives/index.min.js 960 B
build/priority-queue/index.min.js 1.52 kB
build/private-apis/index.min.js 942 B
build/react-i18n/index.min.js 702 B
build/react-refresh-entry/index.min.js 8.44 kB
build/react-refresh-runtime/index.min.js 7.31 kB
build/redux-routine/index.min.js 2.75 kB
build/reusable-blocks/index.min.js 2.26 kB
build/reusable-blocks/style-rtl.css 265 B
build/reusable-blocks/style.css 265 B
build/rich-text/index.min.js 11.1 kB
build/server-side-render/index.min.js 2.09 kB
build/shortcode/index.min.js 1.52 kB
build/style-engine/index.min.js 1.55 kB
build/token-list/index.min.js 650 B
build/url/index.min.js 3.74 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 1.09 kB
build/warning/index.min.js 280 B
build/widgets/index.min.js 7.3 kB
build/widgets/style-rtl.css 1.18 kB
build/widgets/style.css 1.18 kB
build/wordcount/index.min.js 1.06 kB

compressed-size-action

@github-actions
Copy link

github-actions bot commented Apr 6, 2023

Flaky tests detected in 3ccbc8e.
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/4700797082
📝 Reported issues:

@draganescu
Copy link
Contributor

I like this solution:

  • it preserves the intended behavior
  • it implements a solution to a bug that comes from the limitations of our system (finding the actually "closest" toolbar)
  • the opt out behaviour is easy to embrance as in the example you implemented, based on situational constraints

Let's move forward with this solution, 👏🏻

Comment on lines 6 to 27
const documentToolbarButton = ( page ) => {
return page.getByRole( 'button', {
name: 'Toggle block inserter',
exact: true,
} );
};

const documentToolbarTooltip = ( page ) => {
return page.locator( 'text=Toggle block inserter' );
};

const blockToolbarButton = ( page ) => {
return page.getByRole( 'button', { name: 'Paragraph', exact: true } );
};

const useSelectMode = async ( page ) => {
await page.keyboard.press( 'Escape' );
};

const moveToToolbarShortcut = async ( pageUtils ) => {
await pageUtils.pressKeys( 'alt+F10' );
};
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Even though these are mostly one-liners, I found they made the test cases below much easier to read. They behave as comments when named like this.

Copy link
Member

Choose a reason for hiding this comment

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

It's recommended to place these inside a POM-style util. You can see some prior examples in other tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, nice! Thanks for the tip!

Comment on lines 39 to 55
// Test: Focus the top level toolbar from title
await moveToToolbarShortcut( pageUtils );
await expect( documentToolbarButton( page ) ).toBeFocused();

// Test: Focus document toolbar from empty block
await editor.insertBlock( { name: 'core/paragraph' } );
await moveToToolbarShortcut( pageUtils );
await expect( documentToolbarButton( page ) ).toBeFocused();

// Test: Focus block toolbar from block content when block toolbar isn't visible
await editor.insertBlock( { name: 'core/paragraph' } );
await page.keyboard.type(
"Focus to block toolbar when block toolbar isn't visible"
);
await moveToToolbarShortcut( pageUtils );
await expect( blockToolbarButton( page ) ).toBeFocused();
await expect( documentToolbarTooltip( page ) ).not.toBeVisible();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Initially these were separate tests. I combined the tests into groups based into view and mode instead. This cuts the test execution time down by about half, (18s for running all the tests vs 9s for the current setup). This is recommended by Playwright Best Practices of "write fewer tests but longer tests": https://playwright.dev/docs/best-practices#write-fewer-tests-but-longer-tests. I think the time saved per commit is worth having more assertions per test.

Copy link
Member

Choose a reason for hiding this comment

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

Nice improvement! 💯

* @param this
* @param isFixed Boolean value true/false for on/off.
*/
export async function toggleFixedToolbar( this: Editor, isFixed: boolean ) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is taken from https://github.com/WordPress/gutenberg/blob/trunk/packages/e2e-tests/specs/editor/various/links.test.js#L275-L284. If the plan is to move the older e2e tests into playwright, then this will be useful.

Copy link
Member

Choose a reason for hiding this comment

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

Maybe we should rename it to setIsFixedToolbar because toggle seems a bit weird with the isFixed parameter 🤔 .

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, that's much better to read.

@jeryj jeryj marked this pull request as ready for review April 11, 2023 21:14
@@ -147,6 +154,7 @@ function useToolbarFocus(
function NavigableToolbar( {
children,
focusOnMount,
useKeyboardFocusShortcut = true,
Copy link
Member

Choose a reason for hiding this comment

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

Could we rename this to shouldUseKeyboardFocusShortcut as seen below? use* variable often suggests a hook in React and that might cause some confusion. shouuld* also has the benefit of suggesting the variable to be a boolean too.

Copy link
Contributor

@ajlende ajlende left a comment

Choose a reason for hiding this comment

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

[RESOLVED]

I found a case where I still see both tooltips.

  1. esc to enter navigation mode
  2. return to enter edit mode
  3. alt + F10 shows both tooltips
double-focus.mov

* @param this
* @param setIsFixedToolbar Boolean value true/false for on/off.
*/
export async function toggleFixedToolbar(
Copy link
Member

Choose a reason for hiding this comment

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

Oh oops, I mean the util name, not the parameter name. isFixed is actually a more readable parameter name too.

@ajlende
Copy link
Contributor

ajlende commented Apr 13, 2023

There may be other conditions I'm missing to identify if a focusable block toolbar is showing.

If we want these conditions to be the same, would it be better to make a hook that controls both of them based on the application state? Basically match this?

const shouldShowContextualToolbar =
editorMode === 'edit' &&
! hasFixedToolbar &&
isLargeViewport &&
! isMultiSelecting &&
! showEmptyBlockSideInserter &&
! isTyping &&
! isBlockInterfaceHidden;
const canFocusHiddenToolbar =
editorMode === 'edit' &&
! shouldShowContextualToolbar &&
! hasFixedToolbar &&
! isDistractionFree &&
! isEmptyDefaultBlock;

@jeryj
Copy link
Contributor Author

jeryj commented Apr 14, 2023

If we want these conditions to be the same, would it be better to make a hook that controls both of them based on the application state?

Done!

@@ -880,6 +880,18 @@ _Returns_

- `any`: Returns the value defined for the setting.

### useShouldContextualToolbarShow
Copy link
Member

Choose a reason for hiding this comment

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

Question: Do we want to publicize this API just now? As soon as we make it public we have to make it backward-compatible. Maybe we can keep it internal for now?

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree with @kevin940726 - this looks useful only for internal use for now.

Copy link
Contributor

Choose a reason for hiding this comment

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

oh I saw later why this is exported, so we can use it in the post editor later. Do we really need this useShouldContextualToolbarShow refactoring?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do we want to publicize this API just now?

Erring on the side of caution sounds good. What does making it internal look like? Adding experimental or unstable in front of the name?

Copy link
Member

Choose a reason for hiding this comment

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

At the time I left this review, it was only used in the same package. If it's also used in other packages and it's useful then I don't mind publicizing it 😅 .

Copy link
Member

Choose a reason for hiding this comment

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

I guess there's a fine line between whether it should be implemented as a @wordpress/data selector or a hook. I don't mind either but would rather keep it consistent. It's just one small thing to consider before we publicizing it :).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@kevin940726 - I believe we tried to do use selector first, but we were blocked due to the useViewportMatch. @ajlende can confirm/deny this statement 😅

Copy link
Contributor

@ajlende ajlende Apr 19, 2023

Choose a reason for hiding this comment

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

Yeah, the useViewportMatch is the problem with making it a selector. We could, in the future, do the same thing as useViewportMatch and update the store when the media query changes. So it's a good idea to make it private.

Copy link
Contributor

@draganescu draganescu left a comment

Choose a reason for hiding this comment

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

Looks great 👏🏻 Not sure about the refactoring and also I think we need to implement the idea in the site editor and the widgets editor too?

@@ -880,6 +880,18 @@ _Returns_

- `any`: Returns the value defined for the setting.

### useShouldContextualToolbarShow
Copy link
Contributor

Choose a reason for hiding this comment

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

oh I saw later why this is exported, so we can use it in the post editor later. Do we really need this useShouldContextualToolbarShow refactoring?

useShouldContextualToolbarShow( selectedBlockId );
// If there's a block toolbar to be focused, disable the focus shortcut for the document toolbar.
// There's a fixed block toolbar when the fixed toolbar option is enabled or when the browser width is less than the large viewport.
const blockToolbarCanBeFocused =
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a similar thing going on in edit-site too? What is the advantage of using useShouldContextualToolbarShow here instead of leaving all the conditions inlined where they were and just looking at ( ( hasFixedToolbar || ! isLargeViewport ) && selectedBlockId ) here?

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 was a lot of conditions in the block toolbar and @ajlende pointed out that we might be missing some conditions. For example, my conditions didn't account for smaller viewports. The way to be sure we weren't sending focus to the top toolbar was to use all the same conditions as we are for the block toolbar. That's why we decided to consolidate them.

All that said, I don't have a strong preference. I do like this hook though. It can be very useful for knowing if the block toolbar should be showing or if it will be focusable from a keyboard shortcut anywhere else in Gutenberg.

Copy link
Contributor

Choose a reason for hiding this comment

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

Having the hook means that we know it will be the same in both places which is what we want. From previous experience, if you don't do things this way in gutenberg, someone is going to update the condition in one place and miss the other place.

The 'core/block-editor/focus-toolbar' shortcut (alt + F10) selects the active navigable toolbar's fi
rst tabbable item, but when there are multiple navigable toolbars, it places focus on all of the act
ive navigable toolbar components. This results in an odd state of two tooltips being open. This comm
it scaffolds the ability to disable the keyboard shortcut from applying.
I couldn't find a reliable way of determining if there is a block toolbar showing, so I approximated it by checking if there are no selected blocks or we're not in 'edit' mode. If one of those conditions applies, then a focusable block toolbar won't be present (there may other instances I'm missing though), and we can enable the shortcut for the header toolbar.
I hope I'm missing a reliable isBlockToolbarShowing() instead of doingn all these checks, but I didn't see a function like that. Maybe it's worth adding?
…dDefaultBlock

We don't care if it's an unmodified default block or not in the condition to use the shortcut for the top level toolbar, we need to know if there's a chance the toolbar is showing or not. This simplifies the logic so anytime a block with a toolbar is selected, we set maybeBlockToolbarShowing to true, then check the extra condition of a fixed toolbar with ANY block selected.
jeryj added 12 commits April 19, 2023 10:18
There were 12 tests and each time had to go through all of the test set-up. I combined the tests into groups based into view and mode for four total tests. This cuts the test time down by about half, (18s for the previous 12 tests vs 9s for these 4 tests). This is recommended by Playwright Best Practices of "write fewer tests but longer tests": https://playwright.dev/docs/best-practices#write-fewer-tests-but-longer-tests. I think the time saved per commit is worth having more assertions per test.
…seShouldContextualToolbarShow hook

In order to decide if the block toolbar or document toolbar should be focused from the alt+F10 shortcut, we need to do duplicate the same code in both toolbar wrappers. This moves them into a shared hook to keep things consistent.
@draganescu draganescu dismissed their stale review April 19, 2023 15:48

I understand the reasons for the refactoring but also recommend we make the hook a private API.

@jeryj jeryj force-pushed the fix/multiple-tooltips-on-navigable-toolbar branch from 9ad643a to 3eef424 Compare April 19, 2023 16:10
Copy link
Contributor

@scruffian scruffian left a comment

Choose a reason for hiding this comment

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

LGTM

@scruffian scruffian enabled auto-merge (squash) April 19, 2023 16:15
@scruffian scruffian merged commit 6446ff7 into trunk Apr 19, 2023
@scruffian scruffian deleted the fix/multiple-tooltips-on-navigable-toolbar branch April 19, 2023 16:45
@github-actions github-actions bot added this to the Gutenberg 15.7 milestone Apr 19, 2023
@scruffian
Copy link
Contributor

We should create issues for the follow ups here.

Comment on lines +80 to +83
test.beforeEach( async ( { editor } ) => {
// Ensure the fixed toolbar option is on
await editor.setIsFixedToolbar( true );
} );
Copy link
Member

Choose a reason for hiding this comment

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

@jeryj, the block editor settings are persisted across the tests, and this setting occasionally might leak to other tests. We should probably add cleanup test.afterEach and restore the toolbar setting.

I noticed while debugging #49733.

Screenshot from the test failure

test-failed-1

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nice catch! Put in a fix here: #51600

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Type] Bug An existing feature does not function as intended [Type] Build Tooling Issues or PRs related to build tooling
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants