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 navigation select menu focus loss #42956

Closed
wants to merge 1 commit into from

Conversation

talldan
Copy link
Contributor

@talldan talldan commented Aug 4, 2022

What?

Fixes #38169

After #42916, it's now possible to fix this issue properly. The previous temporary fix in #40390 had the trade-off that it wasn't possible to keep the dropdown menu open when switching menus, but with this fix that's now possible.

How?

This a much bigger change than I anticipated, but it's good that it resulted in more code removed than added.

I had to remove:

Testing Instructions

  1. Open the site editor
  2. Select a nav block and try switching between nav menus

Screenshots or screencast

Before

Kapture.2022-08-03.at.17.41.12.mp4

After

Kapture.2022-08-03.at.17.36.43.mp4

@github-actions
Copy link

github-actions bot commented Aug 4, 2022

Size Change: -127 B (0%)

Total Size: 1.24 MB

Filename Size Change
build/block-library/index.min.js 186 kB -127 B (0%)
ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 982 B
build/annotations/index.min.js 2.76 kB
build/api-fetch/index.min.js 2.26 kB
build/autop/index.min.js 2.14 kB
build/blob/index.min.js 475 B
build/block-directory/index.min.js 7.06 kB
build/block-directory/style-rtl.css 990 B
build/block-directory/style.css 991 B
build/block-editor/default-editor-styles-rtl.css 378 B
build/block-editor/default-editor-styles.css 378 B
build/block-editor/index.min.js 159 kB
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 65 B
build/block-library/blocks/archives/style.css 65 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 110 B
build/block-library/blocks/audio/theme.css 110 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 59 B
build/block-library/blocks/avatar/style.css 59 B
build/block-library/blocks/block/editor-rtl.css 161 B
build/block-library/blocks/block/editor.css 161 B
build/block-library/blocks/button/editor-rtl.css 441 B
build/block-library/blocks/button/editor.css 441 B
build/block-library/blocks/button/style-rtl.css 539 B
build/block-library/blocks/button/style.css 539 B
build/block-library/blocks/buttons/editor-rtl.css 292 B
build/block-library/blocks/buttons/editor.css 292 B
build/block-library/blocks/buttons/style-rtl.css 275 B
build/block-library/blocks/buttons/style.css 275 B
build/block-library/blocks/calendar/style-rtl.css 207 B
build/block-library/blocks/calendar/style.css 207 B
build/block-library/blocks/categories/editor-rtl.css 84 B
build/block-library/blocks/categories/editor.css 83 B
build/block-library/blocks/categories/style-rtl.css 79 B
build/block-library/blocks/categories/style.css 79 B
build/block-library/blocks/code/style-rtl.css 103 B
build/block-library/blocks/code/style.css 103 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 406 B
build/block-library/blocks/columns/style.css 406 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 187 B
build/block-library/blocks/comment-template/style.css 185 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 834 B
build/block-library/blocks/comments/editor.css 832 B
build/block-library/blocks/comments/style-rtl.css 632 B
build/block-library/blocks/comments/style.css 630 B
build/block-library/blocks/cover/editor-rtl.css 615 B
build/block-library/blocks/cover/editor.css 616 B
build/block-library/blocks/cover/style-rtl.css 1.55 kB
build/block-library/blocks/cover/style.css 1.55 kB
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 110 B
build/block-library/blocks/embed/theme.css 110 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 253 B
build/block-library/blocks/file/style.css 254 B
build/block-library/blocks/file/view.min.js 346 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 948 B
build/block-library/blocks/gallery/editor.css 950 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 412 B
build/block-library/blocks/group/editor.css 412 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 327 B
build/block-library/blocks/html/editor.css 329 B
build/block-library/blocks/image/editor-rtl.css 876 B
build/block-library/blocks/image/editor.css 873 B
build/block-library/blocks/image/style-rtl.css 627 B
build/block-library/blocks/image/style.css 630 B
build/block-library/blocks/image/theme-rtl.css 110 B
build/block-library/blocks/image/theme.css 110 B
build/block-library/blocks/latest-comments/style-rtl.css 284 B
build/block-library/blocks/latest-comments/style.css 284 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 463 B
build/block-library/blocks/latest-posts/style.css 462 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 493 B
build/block-library/blocks/media-text/style.css 490 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 705 B
build/block-library/blocks/navigation-link/editor.css 703 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-submenu/view.min.js 423 B
build/block-library/blocks/navigation/editor-rtl.css 2.05 kB
build/block-library/blocks/navigation/editor.css 2.06 kB
build/block-library/blocks/navigation/style-rtl.css 1.98 kB
build/block-library/blocks/navigation/style.css 1.97 kB
build/block-library/blocks/navigation/view-modal.min.js 2.78 kB
build/block-library/blocks/navigation/view.min.js 443 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 363 B
build/block-library/blocks/page-list/editor.css 363 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 260 B
build/block-library/blocks/paragraph/style.css 260 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 493 B
build/block-library/blocks/post-comments-form/style.css 493 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 73 B
build/block-library/blocks/post-excerpt/editor.css 73 B
build/block-library/blocks/post-excerpt/style-rtl.css 69 B
build/block-library/blocks/post-excerpt/style.css 69 B
build/block-library/blocks/post-featured-image/editor-rtl.css 507 B
build/block-library/blocks/post-featured-image/editor.css 505 B
build/block-library/blocks/post-featured-image/style-rtl.css 166 B
build/block-library/blocks/post-featured-image/style.css 166 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 282 B
build/block-library/blocks/post-template/style.css 282 B
build/block-library/blocks/post-terms/style-rtl.css 73 B
build/block-library/blocks/post-terms/style.css 73 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 326 B
build/block-library/blocks/pullquote/style.css 325 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 282 B
build/block-library/blocks/query-pagination/style.css 278 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 439 B
build/block-library/blocks/query/editor.css 439 B
build/block-library/blocks/quote/style-rtl.css 213 B
build/block-library/blocks/quote/style.css 213 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 202 B
build/block-library/blocks/rss/editor.css 204 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 396 B
build/block-library/blocks/search/style.css 393 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 233 B
build/block-library/blocks/separator/style.css 233 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 464 B
build/block-library/blocks/shortcode/editor.css 464 B
build/block-library/blocks/site-logo/editor-rtl.css 455 B
build/block-library/blocks/site-logo/editor.css 455 B
build/block-library/blocks/site-logo/style-rtl.css 192 B
build/block-library/blocks/site-logo/style.css 192 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 84 B
build/block-library/blocks/site-title/editor.css 84 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.39 kB
build/block-library/blocks/social-links/style.css 1.38 kB
build/block-library/blocks/spacer/editor-rtl.css 322 B
build/block-library/blocks/spacer/editor.css 322 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 494 B
build/block-library/blocks/table/editor.css 494 B
build/block-library/blocks/table/style-rtl.css 611 B
build/block-library/blocks/table/style.css 609 B
build/block-library/blocks/table/theme-rtl.css 175 B
build/block-library/blocks/table/theme.css 175 B
build/block-library/blocks/tag-cloud/style-rtl.css 239 B
build/block-library/blocks/tag-cloud/style.css 239 B
build/block-library/blocks/template-part/editor-rtl.css 235 B
build/block-library/blocks/template-part/editor.css 235 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 87 B
build/block-library/blocks/verse/style.css 87 B
build/block-library/blocks/video/editor-rtl.css 561 B
build/block-library/blocks/video/editor.css 563 B
build/block-library/blocks/video/style-rtl.css 174 B
build/block-library/blocks/video/style.css 174 B
build/block-library/blocks/video/theme-rtl.css 110 B
build/block-library/blocks/video/theme.css 110 B
build/block-library/common-rtl.css 1.01 kB
build/block-library/common.css 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 11 kB
build/block-library/editor.css 11 kB
build/block-library/elements-rtl.css 54 B
build/block-library/elements.css 54 B
build/block-library/reset-rtl.css 478 B
build/block-library/reset.css 478 B
build/block-library/style-rtl.css 11.9 kB
build/block-library/style.css 11.9 kB
build/block-library/theme-rtl.css 695 B
build/block-library/theme.css 700 B
build/block-serialization-default-parser/index.min.js 1.11 kB
build/block-serialization-spec-parser/index.min.js 2.83 kB
build/blocks/index.min.js 49.5 kB
build/components/index.min.js 198 kB
build/components/style-rtl.css 11.6 kB
build/components/style.css 11.6 kB
build/compose/index.min.js 12 kB
build/core-data/index.min.js 15.4 kB
build/customize-widgets/index.min.js 11.3 kB
build/customize-widgets/style-rtl.css 1.4 kB
build/customize-widgets/style.css 1.4 kB
build/data-controls/index.min.js 653 B
build/data/index.min.js 8.03 kB
build/date/index.min.js 32 kB
build/deprecated/index.min.js 507 B
build/dom-ready/index.min.js 324 B
build/dom/index.min.js 4.69 kB
build/edit-navigation/index.min.js 16 kB
build/edit-navigation/style-rtl.css 4 kB
build/edit-navigation/style.css 4.01 kB
build/edit-post/classic-rtl.css 546 B
build/edit-post/classic.css 547 B
build/edit-post/index.min.js 30.5 kB
build/edit-post/style-rtl.css 6.94 kB
build/edit-post/style.css 6.94 kB
build/edit-site/index.min.js 57.4 kB
build/edit-site/style-rtl.css 8.22 kB
build/edit-site/style.css 8.2 kB
build/edit-widgets/index.min.js 16.5 kB
build/edit-widgets/style-rtl.css 4.35 kB
build/edit-widgets/style.css 4.35 kB
build/editor/index.min.js 41.5 kB
build/editor/style-rtl.css 3.66 kB
build/editor/style.css 3.65 kB
build/element/index.min.js 4.68 kB
build/escape-html/index.min.js 537 B
build/format-library/index.min.js 6.75 kB
build/format-library/style-rtl.css 571 B
build/format-library/style.css 571 B
build/hooks/index.min.js 1.64 kB
build/html-entities/index.min.js 448 B
build/i18n/index.min.js 3.77 kB
build/is-shallow-equal/index.min.js 527 B
build/keyboard-shortcuts/index.min.js 1.78 kB
build/keycodes/index.min.js 1.81 kB
build/list-reusable-blocks/index.min.js 1.74 kB
build/list-reusable-blocks/style-rtl.css 835 B
build/list-reusable-blocks/style.css 835 B
build/media-utils/index.min.js 2.93 kB
build/notices/index.min.js 953 B
build/nux/index.min.js 2.05 kB
build/nux/style-rtl.css 732 B
build/nux/style.css 728 B
build/plugins/index.min.js 1.94 kB
build/preferences-persistence/index.min.js 2.22 kB
build/preferences/index.min.js 1.3 kB
build/primitives/index.min.js 933 B
build/priority-queue/index.min.js 612 B
build/react-i18n/index.min.js 696 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.74 kB
build/reusable-blocks/index.min.js 2.21 kB
build/reusable-blocks/style-rtl.css 256 B
build/reusable-blocks/style.css 256 B
build/rich-text/index.min.js 11.2 kB
build/server-side-render/index.min.js 1.61 kB
build/shortcode/index.min.js 1.53 kB
build/token-list/index.min.js 644 B
build/url/index.min.js 3.61 kB
build/vendors/react-dom.min.js 38.5 kB
build/vendors/react.min.js 4.34 kB
build/viewport/index.min.js 1.08 kB
build/warning/index.min.js 268 B
build/widgets/index.min.js 7.19 kB
build/widgets/style-rtl.css 1.16 kB
build/widgets/style.css 1.16 kB
build/wordcount/index.min.js 1.06 kB

compressed-size-action

@@ -225,13 +224,10 @@ function Navigation( {

const navRef = useRef();

const isDraftNavigationMenu = navigationMenu?.status === 'draft';
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 seems to be unused. Previously, 'unsaved inner blocks' when saved were created as drafts, but that was accidentally removed months ago by some refactoring and no-one really complained, so I'll remove this as well. 😄

Copy link
Contributor

Choose a reason for hiding this comment

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

Although I think @draganescu might need it back very shortly 😄

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, I was exploring the idea of saving menus as drafts initially indifferent of how they're created so the user does the "final call" action when clicking save. The idea is to avoid fiddling with live site menus by mistake.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Worth noting that there's still some code that changes the status to publish when saving wp_navigation entities in an editor:

const PUBLISH_ON_SAVE_ENTITIES = [
{
kind: 'postType',
name: 'wp_navigation',
},
];

if (
PUBLISH_ON_SAVE_ENTITIES.some(
( typeToPublish ) =>
typeToPublish.kind === kind &&
typeToPublish.name === name
)
) {
editEntityRecord( kind, name, key, { status: 'publish' } );
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@draganescu Let me know what you'd like me to do. I can make a separate PR that removes all of the draft handling, which you can revert when you need it back. Or I can put isDraftNavigationMenu back in this PR

Copy link
Contributor

Choose a reason for hiding this comment

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

I think you should proceed as things are no need for any separate PR. We'll see how trunk looks when we start changing the publish behavior 🙏🏻

Comment on lines 424 to 441
const handleSelectNavigation = useCallback(
( navPostOrClassicMenu ) => {
if ( ! navPostOrClassicMenu ) {
return;
}

const isClassicMenu =
navPostOrClassicMenu.hasOwnProperty( 'auto_add' );

if ( isClassicMenu ) {
convert( navPostOrClassicMenu.id, navPostOrClassicMenu.name );
} else {
handleUpdateMenu( navPostOrClassicMenu.id );
}
setShouldFocusNavigationSelector( true );
},
[ convert, handleUpdateMenu ]
);
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've removed this in favour of having separate onSelectNavigationMenu and onSelectClassicMenu props for NavigationMenuSelector. It seems simpler than checking the auto_add property.

Copy link
Contributor

Choose a reason for hiding this comment

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

There was definitely a reason I did it this way. I clearly failed to document that in the code so I can't remember what it was now.

I might have been that the menu selector component was used in another context and having a single handler helped to avoid overcomplicating the interface. I found

Comment on lines 645 to 653
const navigationMenu = await convertClassicMenu(
classicMenu.id,
classicMenu.name
);
setRef( navigationMenu.id );
Copy link
Contributor Author

@talldan talldan Aug 4, 2022

Choose a reason for hiding this comment

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

I decided to switch to having convertClassicMenu return the resulting menu, rather than using the value from the hook. That means there's now no need to update it in a useEffect.

Copy link
Contributor

Choose a reason for hiding this comment

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

I seem to remember the reason the hook works the way it does is to avoid waiting on async stuff in UI onSelect or onClick handlers.

Previously you will recall that the UI used to "hang" when the user took certain actions.

Due to exposing the status of the ongoing async operation this may no longer be such a concern. That said I'd like to ensure we've checked that we're not reintroducing old problems.

Copy link
Contributor

Choose a reason for hiding this comment

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

That said I tested in the UI and I didn't notice anything hanging which is good.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

An async function won't cause the UI to hang. I think the problem before was that there was no loading indicator.

@@ -704,20 +659,24 @@ function Navigation( {
<EntityProvider kind="postType" type="wp_navigation" id={ ref }>
<RecursionProvider uniqueId={ recursionId }>
<BlockControls>
{ ! isDraftNavigationMenu && isEntityAvailable && (
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 don't think these conditions do anything important, because there are already early returns in the component for missing entities or unselected menus.

Comment on lines 46 to 63
const handleSelect = useCallback(
( _onClose ) => ( selectedId ) => {
_onClose();
onSelect(
navigationMenus?.find( ( post ) => post.id === selectedId )
);
},
[ navigationMenus ]
);

const handleSelectClassic = useCallback(
( _onClose, menu ) => () => {
_onClose();
onSelect( menu );
},
[]
);

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 don't think these need to be memoized, so I removed that. It turns out that the navigationMenus?.find( ( post ) => post.id === selectedId ) isn't needed as the onSelect callback only uses the id of the menu.

The new onSelectNavigationMenu prop can be passed directly to MenuItemsChoice

Copy link
Contributor

Choose a reason for hiding this comment

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

Nice tidying although are these related to the purpose of the PR? I only ask because we're in the middle of a lot of refactoring on the block right now and we're really trying to keep our PRs as small as possible.

menu
) }
onClick={ () => {
onClose();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Decided to keep onClose here, as converting a classic menu has a saving/loading period, and keeping the menu open while that was happening felt weird.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes this is exactly that I want to avoid. We need to have the UI immediate "respond" and then make sure we have the necessary data available to the wider block to convey the progress of the async action. As you know I did a lot of refactoring in the 6.0 cycle to allow for this but these little touches help. Thank you!

setStatus( CLASSIC_MENU_CONVERSION_PENDING );
setError( null );

return await convertClassicMenuToBlockMenu( menuId, menuName )
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Now we return the value and allow the caller to handle it rather than use setValue. This feels simpler to me.

I think the same could be done for errors and status too, but I've tried to keep refactoring to a minimum.

Copy link
Contributor

Choose a reason for hiding this comment

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

You and I did refactor this specifically to ensure the loading states and errors were available to the wider block and not localised to the caller.

Copy link
Contributor Author

@talldan talldan Aug 4, 2022

Choose a reason for hiding this comment

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

It doesn't look like I had a lot of input into those PRs. My comment is referenced on that earlier PR, so maybe it's that - #38824 (review).

My suggestion there was to make it an async function called convertClassicToBlockMenu instead of a hook, and it looks like it went the other way. That's absolutely fine, it's just a difference of opinion.

I can go into more detail about why I feel that it shouldn't be a hook. I think the problem with relying on a hook is that creating a menu is a one time operation, but a hook generally returns values that are long lived (over multiple renders).

So I might create a menu once by calling the convert function:

const [ value, convert ] = useConvertClassicToBlockMenu( // ... );

// ...

onSelectClassicMenu={ ( classicMenu ) => {
    convert( classicMenu );
} }

But because of the way hooks work, value continues to be set to the value of the menu for a long time after it is actually useful. Not only that, but it has to be handled in a useEffect hook separately from the code that called it.

If more work is done in the event handler, then that value can be garbage collected and it has the net result of reducing the complexity of the main Edit function.

Copy link
Contributor

@getdave getdave left a comment

Choose a reason for hiding this comment

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

Thank you for this PR. It seems to work as expected although I wasn't 100% sure from the PR test instructions how to test for the focus loss.

I noticed that when you select a Nav menu the dropdown remains open whereas when you select a classic menu the dropdown closes.

Screen.Capture.on.2022-08-04.at.08-58-12.mp4

A wider concern for me is that the scope of changes in this PR is pretty large. A number of contributors are working on the block right now and we've agreed that smaller discreet PRs are the key to avoiding problematic rebases. I notice that some of the changes seem to be beyond the scope of the PR and might be better as individual PRs to allow contributors to better assess them in isolation and also to handle the merge conflicts more easily. I appreciate it's an overhead but would you be open to breaking this up a little bit?

One of my major concerns is that with all these changes we don't regress the work that you and I did to improve the communication of loading states to the user and also avoiding reintroducing excess duplication in to the block. I've left comments which reference previous PRs from the 6.0 (or even 5.9?) cycle to help us assess whether that might be happening here. Again it would be easier if these changes were broken out for individual assessment.

Thanks again for the PR 🙇‍♂️

Comment on lines 645 to 653
const navigationMenu = await convertClassicMenu(
classicMenu.id,
classicMenu.name
);
setRef( navigationMenu.id );
Copy link
Contributor

Choose a reason for hiding this comment

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

I seem to remember the reason the hook works the way it does is to avoid waiting on async stuff in UI onSelect or onClick handlers.

Previously you will recall that the UI used to "hang" when the user took certain actions.

Due to exposing the status of the ongoing async operation this may no longer be such a concern. That said I'd like to ensure we've checked that we're not reintroducing old problems.

Comment on lines 645 to 653
const navigationMenu = await convertClassicMenu(
classicMenu.id,
classicMenu.name
);
setRef( navigationMenu.id );
Copy link
Contributor

Choose a reason for hiding this comment

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

That said I tested in the UI and I didn't notice anything hanging which is good.

@@ -225,13 +224,10 @@ function Navigation( {

const navRef = useRef();

const isDraftNavigationMenu = navigationMenu?.status === 'draft';
Copy link
Contributor

Choose a reason for hiding this comment

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

Although I think @draganescu might need it back very shortly 😄

Comment on lines 46 to 63
const handleSelect = useCallback(
( _onClose ) => ( selectedId ) => {
_onClose();
onSelect(
navigationMenus?.find( ( post ) => post.id === selectedId )
);
},
[ navigationMenus ]
);

const handleSelectClassic = useCallback(
( _onClose, menu ) => () => {
_onClose();
onSelect( menu );
},
[]
);

Copy link
Contributor

Choose a reason for hiding this comment

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

Nice tidying although are these related to the purpose of the PR? I only ask because we're in the middle of a lot of refactoring on the block right now and we're really trying to keep our PRs as small as possible.

menu
) }
onClick={ () => {
onClose();
Copy link
Contributor

Choose a reason for hiding this comment

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

Yes this is exactly that I want to avoid. We need to have the UI immediate "respond" and then make sure we have the necessary data available to the wider block to convey the progress of the async action. As you know I did a lot of refactoring in the 6.0 cycle to allow for this but these little touches help. Thank you!

setStatus( CLASSIC_MENU_CONVERSION_PENDING );
setError( null );

return await convertClassicMenuToBlockMenu( menuId, menuName )
Copy link
Contributor

Choose a reason for hiding this comment

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

You and I did refactor this specifically to ensure the loading states and errors were available to the wider block and not localised to the caller.

Comment on lines 424 to 441
const handleSelectNavigation = useCallback(
( navPostOrClassicMenu ) => {
if ( ! navPostOrClassicMenu ) {
return;
}

const isClassicMenu =
navPostOrClassicMenu.hasOwnProperty( 'auto_add' );

if ( isClassicMenu ) {
convert( navPostOrClassicMenu.id, navPostOrClassicMenu.name );
} else {
handleUpdateMenu( navPostOrClassicMenu.id );
}
setShouldFocusNavigationSelector( true );
},
[ convert, handleUpdateMenu ]
);
Copy link
Contributor

Choose a reason for hiding this comment

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

There was definitely a reason I did it this way. I clearly failed to document that in the code so I can't remember what it was now.

I might have been that the menu selector component was used in another context and having a single handler helped to avoid overcomplicating the interface. I found

@scruffian
Copy link
Contributor

+1 to what @getdave said. We're making some changes in: #42735 and #42182. If we can keep the scope of each change small it will make these merges a lot easier.

@talldan
Copy link
Contributor Author

talldan commented Aug 4, 2022

As mentioned in the PR it ended up being bigger than expected. I think all the changes are necessary, though in some cases there are multiple ways to solve the problem. I went with what I thought best.

I'll see if I can break some out into a refactor PR first. 👍

@getdave
Copy link
Contributor

getdave commented Aug 4, 2022

As mentioned in the PR it ended up being bigger than expected.

I noted this. Understood. It's a tricky balance.

@alexstine
Copy link
Contributor

@talldan Let me know when this is ready for review. I am mostly AFK ATM, but I will check when I can.

@talldan
Copy link
Contributor Author

talldan commented Aug 8, 2022

@alexstine Thanks. It should be ready for testing, but the code is liable to change until I've merged a few separate PRs.

@getdave @scruffian First pure refactor PR in #43057.

@talldan
Copy link
Contributor Author

talldan commented Aug 9, 2022

Second refactor PR - #43081

@alexstine
Copy link
Contributor

Accessibility seems to be much improved. There are still options and functionality that cause focus loss, but selecting menus is no longer one of them.

Thanks.

@alexstine alexstine added the [Focus] Accessibility (a11y) Changes that impact accessibility and need corresponding review (e.g. markup changes). label Aug 11, 2022
@alexstine alexstine removed their request for review August 11, 2022 04:55
@talldan talldan force-pushed the fix/navigation-select-menu-focus-loss branch from 6e90091 to 59e8a5d Compare August 15, 2022 09:02
Remove navigation selector ref

Update e2e test

Switch back to useCallback

Fix test
@talldan talldan force-pushed the fix/navigation-select-menu-focus-loss branch from 59e8a5d to 56462ff Compare August 23, 2022 04:28
@talldan
Copy link
Contributor Author

talldan commented Aug 23, 2022

There were some conflicts, so I've rebased this and solved them.

#42735 has since been merged, and that introduced more places where NavigationMenuSelector is shown, so I need to test if those new places have issues retaining focused.

Also, that PR was pretty huge, I don't really get why I had to divide this PR up into smaller parts. 🤷

@getdave
Copy link
Contributor

getdave commented Aug 23, 2022

Also, that PR was pretty huge, I don't really get why I had to divide this PR up into smaller parts. 🤷

I believe the reason that PR was shipped en masse was because we had to land all the functionality at once otherwise the experience would have become inconsistent.

That said, I appreciate it might seem inconsistent and frustrating. I've been away on AFK for 2 weeks so I've been out of the loop so I'm not well placed to provide any further insight.

All I can say Dan is that we appreciate your efforts and diligence.

draganescu added a commit that referenced this pull request Aug 29, 2022
…rding to #42956

Switching between menus keeps the menu open and focused on the current selection.
Importing classic menus or creating new ones focuses the current navigation block.

Co-authored-by: Daniel Richards <677833+talldan@users.noreply.github.com>
draganescu added a commit that referenced this pull request Aug 30, 2022
…rding to #42956

Switching between menus keeps the menu open and focused on the current selection.
Importing classic menus or creating new ones focuses the current navigation block.

Co-authored-by: Daniel Richards <677833+talldan@users.noreply.github.com>
draganescu added a commit that referenced this pull request Sep 2, 2022
…rding to #42956

Switching between menus keeps the menu open and focused on the current selection.
Importing classic menus or creating new ones focuses the current navigation block.

Co-authored-by: Daniel Richards <677833+talldan@users.noreply.github.com>
draganescu added a commit that referenced this pull request Sep 5, 2022
* adds a list view with the navigation block inner blocks to the block's inspector

* adds a first toolpanel item

* stub toolpanel item

* moves the menu selector block controls to the inspector

* fixes label update bug

* labels navigation menu selector if no menus or deleted menu, fixes label when importing classic menu

* adds the chevron

* only show no menus label if no block menus exist, disregard classic menus

* adds check for permissions on the manage menus link; removes rogue showManageActions

* Implements handling focus persistence in the Navigation Selector according to #42956
Switching between menus keeps the menu open and focused on the current selection.
Importing classic menus or creating new ones focuses the current navigation block.

Co-authored-by: Daniel Richards <677833+talldan@users.noreply.github.com>

* It looks like `hasManagePermissions` is not cached between API calls so we refresh this quite often when switching between menus. For a more consistent UI experience we disabe the menu management link untill `hasManagePermissions` is refreshed.

Another option would be to cache this at a component level. But, this could be more accurate?

* Closes the dropdown when importing or creating new menu as in #43529
Fixes slow connection UX by disabling and enabling the selector and the manage menus link depending on data status.

Co-authored-by: Dave Smith <444434+getdave@users.noreply.github.com>

* Larger commit, adds:

- The label of the currently selected menu updates if menu is renamed from advanced
- Uses a visually hidden label to explain this is a menu switcher
- Defaults to a button if there are no block menus and no classic menus
- Renames "Loading options ..." to "Loading ..."

Co-authored-by: Javier Arce <4933+javierarce@users.noreply.github.com>
Co-authored-by: Alex Stine <13755480+alexstine@users.noreply.github.com>

* move styles to editor.scss as they are only needed for the editor

* use flex rather than absolute positioning

* alphabetize CSS properties

* Incorporates review feedback:

- replaces disabled with isBusy for toggle working state
- refactores some conditionals for better readability
- adds consistency to the toggle label

Co-authored-by: Daniel Richards <677833+talldan@users.noreply.github.com>
Co-authored-by: Dave Smith <444434+getdave@users.noreply.github.com>
Co-authored-by: Javier Arce <4933+javierarce@users.noreply.github.com>
Co-authored-by: Paal Joachim Romdahl <5323259+paaljoachim@users.noreply.github.com>

Co-authored-by: Daniel Richards <677833+talldan@users.noreply.github.com>
Co-authored-by: Dave Smith <444434+getdave@users.noreply.github.com>
Co-authored-by: Javier Arce <4933+javierarce@users.noreply.github.com>
Co-authored-by: Alex Stine <13755480+alexstine@users.noreply.github.com>
Co-authored-by: Ben Dwyer <ben@scruffian.com>
Co-authored-by: Paal Joachim Romdahl <5323259+paaljoachim@users.noreply.github.com>
@talldan
Copy link
Contributor Author

talldan commented Sep 6, 2022

Closing as this is now outdated and the UI has changed.

@talldan talldan closed this Sep 6, 2022
@talldan talldan deleted the fix/navigation-select-menu-focus-loss branch September 6, 2022 02:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Block] Navigation Affects the Navigation Block [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.

Focus is lost after selecting option from "Select Menu" dropdown
5 participants