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

BlockSwitcher: Defer transform calculations until the Dropdown is open #57892

Merged

Conversation

ntsekouras
Copy link
Contributor

What?

This PR refactors the BlockSwitcher component so as to defer the expensive transform calculations. This should have some small improvements at least in some metrics like block select, type with top toolbar etc..

Why?

Currently when we render this component we calculate all the available transforms(either block or pattern) in order to decide whether to render a Dropdown menu or a simple disabled button. This is happening even if the user never clicks the button and also happens on every keystroke because we need the block information to determine the eligible transforms.

How?

With the refactor, there is a quite rare use case where a block might not have anything to show in the dropdown. In this case we show a message that there is no available transform and in core we can replicate I think only for List item block. I think that's an acceptable trade-off for the performance gain we have.

Additionally we still render a disabled button when a single block is selected with no styles that cannot be removed.

Notes

I refactored the tests too as most of them didn't seem to add much value.

Testing Instructions

  1. Everything regarding the component should work as before
  2. The only exception is that if a block has no available transforms or styles and can be removed it will display a message(see screenshot below). You can test this by inserting a List block and selecting a List item block.

Screenshots or screencast

Screenshot 2024-01-16 at 6 06 07 PM

@ntsekouras ntsekouras added the [Type] Performance Related to performance efforts label Jan 16, 2024
@ntsekouras ntsekouras self-assigned this Jan 16, 2024
Copy link

github-actions bot commented Jan 16, 2024

Size Change: +146 B (0%)

Total Size: 1.7 MB

Filename Size Change
build/block-editor/index.min.js 248 kB +83 B (0%)
build/block-editor/style-rtl.css 15.4 kB +20 B (0%)
build/block-editor/style.css 15.4 kB +18 B (0%)
build/patterns/index.min.js 5.43 kB +25 B (0%)
ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 964 B
build/annotations/index.min.js 2.71 kB
build/api-fetch/index.min.js 2.33 kB
build/autop/index.min.js 2.11 kB
build/blob/index.min.js 590 B
build/block-directory/index.min.js 7.25 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.31 kB
build/block-editor/content.css 4.31 kB
build/block-editor/default-editor-styles-rtl.css 403 B
build/block-editor/default-editor-styles.css 403 B
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 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 419 B
build/block-library/blocks/button/editor.css 417 B
build/block-library/blocks/button/style-rtl.css 632 B
build/block-library/blocks/button/style.css 631 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.7 kB
build/block-library/blocks/cover/style.css 1.69 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 138 B
build/block-library/blocks/embed/theme.css 138 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.min.js 322 B
build/block-library/blocks/footnotes/style-rtl.css 201 B
build/block-library/blocks/footnotes/style.css 199 B
build/block-library/blocks/form-input/editor-rtl.css 229 B
build/block-library/blocks/form-input/editor.css 228 B
build/block-library/blocks/form-input/style-rtl.css 343 B
build/block-library/blocks/form-input/style.css 343 B
build/block-library/blocks/form-submission-notification/editor-rtl.css 343 B
build/block-library/blocks/form-submission-notification/editor.css 342 B
build/block-library/blocks/form-submit-button/style-rtl.css 69 B
build/block-library/blocks/form-submit-button/style.css 69 B
build/block-library/blocks/form/view.min.js 452 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 957 B
build/block-library/blocks/gallery/editor.css 962 B
build/block-library/blocks/gallery/style-rtl.css 1.75 kB
build/block-library/blocks/gallery/style.css 1.75 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 189 B
build/block-library/blocks/heading/style.css 189 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 834 B
build/block-library/blocks/image/editor.css 833 B
build/block-library/blocks/image/style-rtl.css 1.61 kB
build/block-library/blocks/image/style.css 1.6 kB
build/block-library/blocks/image/theme-rtl.css 137 B
build/block-library/blocks/image/theme.css 137 B
build/block-library/blocks/image/view.min.js 2.02 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 671 B
build/block-library/blocks/navigation-link/editor.css 672 B
build/block-library/blocks/navigation-link/style-rtl.css 103 B
build/block-library/blocks/navigation-link/style.css 103 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.26 kB
build/block-library/blocks/navigation/editor.css 2.26 kB
build/block-library/blocks/navigation/style-rtl.css 2.25 kB
build/block-library/blocks/navigation/style.css 2.23 kB
build/block-library/blocks/navigation/view.min.js 1.1 kB
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 235 B
build/block-library/blocks/paragraph/editor.css 235 B
build/block-library/blocks/paragraph/style-rtl.css 335 B
build/block-library/blocks/paragraph/style.css 335 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 666 B
build/block-library/blocks/post-featured-image/editor.css 662 B
build/block-library/blocks/post-featured-image/style-rtl.css 345 B
build/block-library/blocks/post-featured-image/style.css 345 B
build/block-library/blocks/post-navigation-link/style-rtl.css 215 B
build/block-library/blocks/post-navigation-link/style.css 214 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 409 B
build/block-library/blocks/post-template/style.css 408 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 354 B
build/block-library/blocks/pullquote/style.css 354 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 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 486 B
build/block-library/blocks/query/editor.css 486 B
build/block-library/blocks/query/style-rtl.css 312 B
build/block-library/blocks/query/style.css 308 B
build/block-library/blocks/query/view.min.js 647 B
build/block-library/blocks/quote/style-rtl.css 237 B
build/block-library/blocks/quote/style.css 237 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 140 B
build/block-library/blocks/read-more/style.css 140 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 184 B
build/block-library/blocks/search/editor.css 184 B
build/block-library/blocks/search/style-rtl.css 602 B
build/block-library/blocks/search/style.css 602 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 475 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 760 B
build/block-library/blocks/site-logo/editor.css 760 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.49 kB
build/block-library/blocks/social-links/style.css 1.49 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 395 B
build/block-library/blocks/table/editor.css 395 B
build/block-library/blocks/table/style-rtl.css 646 B
build/block-library/blocks/table/style.css 645 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 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 191 B
build/block-library/blocks/video/style.css 191 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.11 kB
build/block-library/common.css 1.11 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.3 kB
build/block-library/editor.css 12.3 kB
build/block-library/elements-rtl.css 54 B
build/block-library/elements.css 54 B
build/block-library/index.min.js 215 kB
build/block-library/reset-rtl.css 472 B
build/block-library/reset.css 472 B
build/block-library/style-rtl.css 14.7 kB
build/block-library/style.css 14.7 kB
build/block-library/theme-rtl.css 700 B
build/block-library/theme.css 705 B
build/block-serialization-default-parser/index.min.js 1.13 kB
build/block-serialization-spec-parser/index.min.js 2.87 kB
build/blocks/index.min.js 51.6 kB
build/commands/index.min.js 15.5 kB
build/commands/style-rtl.css 947 B
build/commands/style.css 942 B
build/components/index.min.js 235 kB
build/components/style-rtl.css 12.1 kB
build/components/style.css 12.1 kB
build/compose/index.min.js 12.8 kB
build/core-commands/index.min.js 2.73 kB
build/core-data/index.min.js 72.7 kB
build/customize-widgets/index.min.js 12.1 kB
build/customize-widgets/style-rtl.css 1.36 kB
build/customize-widgets/style.css 1.36 kB
build/data-controls/index.min.js 651 B
build/data/index.min.js 8.96 kB
build/date/index.min.js 17.9 kB
build/deprecated/index.min.js 462 B
build/dom-ready/index.min.js 336 B
build/dom/index.min.js 4.69 kB
build/edit-post/classic-rtl.css 571 B
build/edit-post/classic.css 571 B
build/edit-post/index.min.js 24.9 kB
build/edit-post/style-rtl.css 5.68 kB
build/edit-post/style.css 5.68 kB
build/edit-site/index.min.js 195 kB
build/edit-site/style-rtl.css 15.1 kB
build/edit-site/style.css 15.1 kB
build/edit-widgets/index.min.js 17.4 kB
build/edit-widgets/style-rtl.css 4.44 kB
build/edit-widgets/style.css 4.43 kB
build/editor/index.min.js 61.7 kB
build/editor/style-rtl.css 5.48 kB
build/editor/style.css 5.48 kB
build/element/index.min.js 4.87 kB
build/escape-html/index.min.js 548 B
build/format-library/index.min.js 7.98 kB
build/format-library/style-rtl.css 500 B
build/format-library/style.css 500 B
build/hooks/index.min.js 1.57 kB
build/html-entities/index.min.js 454 B
build/i18n/index.min.js 3.61 kB
build/interactivity/file.min.js 442 B
build/interactivity/image.min.js 2.15 kB
build/interactivity/index.min.js 12.6 kB
build/interactivity/navigation.min.js 1.23 kB
build/interactivity/query.min.js 791 B
build/interactivity/search.min.js 610 B
build/is-shallow-equal/index.min.js 535 B
build/keyboard-shortcuts/index.min.js 1.76 kB
build/keycodes/index.min.js 1.49 kB
build/list-reusable-blocks/index.min.js 2.11 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.92 kB
build/modules/importmap-polyfill.min.js 12.2 kB
build/notices/index.min.js 964 B
build/nux/index.min.js 2.01 kB
build/nux/style-rtl.css 775 B
build/nux/style.css 771 B
build/patterns/style-rtl.css 564 B
build/patterns/style.css 564 B
build/plugins/index.min.js 1.81 kB
build/preferences-persistence/index.min.js 2.08 kB
build/preferences/index.min.js 2.52 kB
build/preferences/style-rtl.css 725 B
build/preferences/style.css 728 B
build/primitives/index.min.js 994 B
build/priority-queue/index.min.js 1.52 kB
build/private-apis/index.min.js 1.02 kB
build/react-i18n/index.min.js 631 B
build/react-refresh-entry/index.min.js 9.46 kB
build/react-refresh-runtime/index.min.js 6.78 kB
build/redux-routine/index.min.js 2.71 kB
build/reusable-blocks/index.min.js 2.74 kB
build/reusable-blocks/style-rtl.css 265 B
build/reusable-blocks/style.css 265 B
build/rich-text/index.min.js 10.4 kB
build/router/index.min.js 1.79 kB
build/server-side-render/index.min.js 1.96 kB
build/shortcode/index.min.js 1.4 kB
build/style-engine/index.min.js 2.06 kB
build/token-list/index.min.js 587 B
build/url/index.min.js 3.83 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 967 B
build/warning/index.min.js 259 B
build/widgets/index.min.js 7.22 kB
build/widgets/style-rtl.css 1.18 kB
build/widgets/style.css 1.18 kB
build/wordcount/index.min.js 1.03 kB

compressed-size-action

Copy link
Member

@Mamaduka Mamaduka left a comment

Choose a reason for hiding this comment

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

Love the improvement. Thank you, Nik.

I think another small improvement would be to stop passing around the blocks value. This will prevent re-rendering BlockSwitcher on every keystroke.

@ellatrix
Copy link
Member

Yes, it would be great if you could move the blocks selector too :)

@jasmussen
Copy link
Contributor

Makes sense, the performance win will outweigh virtually anything in this case.

Can we make it look like this?

No transforms
  • Same text indentation as menu items would have
  • $gray-700 text, set to $helptext-font-size

Note that the indentation from the left is due to the dropdown appearing from the button. I would love for us to find a way to nudge the inner padding of the block toolbar so that it can extend downwards, flush with the dark border of the block toolbar itself, like so:

not indented

That is not something for this PR, it's not even trivial, I'm simply noting it here that it's considered.

@ntsekouras
Copy link
Contributor Author

Yes, it would be great if you could move the blocks selector too :)

I can't move it down because we need to check the validity of blocks to decide if we can even render the component.

I think another small improvement would be to stop passing around the blocks value. This will prevent re-rendering BlockSwitcher on every keystroke.

I updated not to pass the blocks, but I don't believe this makes any difference since the BlockSwitcher component needs the blocks too and they will trigger a rerender on every keystroke. Do I miss something?

@@ -57,10 +57,7 @@ test.describe( 'Toolbar roving tabindex', () => {
// ensures list block toolbar uses roving tabindex
await editor.insertBlock( { name: 'core/list' } );
await page.keyboard.type( 'List' );
await ToolbarRovingTabindexUtils.testBlockToolbarKeyboardNavigation(
Copy link
Contributor Author

@ntsekouras ntsekouras Jan 17, 2024

Choose a reason for hiding this comment

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

It makes no sense to test list as a simple block since it has inner blocks for a while. The only reason this was passing is because List item has no transformation currently. testGroupKeyboardNavigation is handling tests for container blocks.

@ntsekouras ntsekouras force-pushed the refactor/block-switcher-to-defer-transform-calculations branch from e4ff6af to aab7c63 Compare January 17, 2024 09:03
@Mamaduka
Copy link
Member

Mamaduka commented Jan 17, 2024

This is what I had in mind.

Example

diff --git packages/block-editor/src/components/block-switcher/index.js packages/block-editor/src/components/block-switcher/index.js
index fd341f09596..4a6644d7866 100644
--- packages/block-editor/src/components/block-switcher/index.js
+++ packages/block-editor/src/components/block-switcher/index.js
@@ -163,59 +163,63 @@ function BlockSwitcherDropdownMenuContents( {
 
 export const BlockSwitcher = ( { clientIds } ) => {
 	const blockInformation = useBlockDisplayInformation( clientIds?.[ 0 ] );
-	const { canRemove, hasBlockStyles, icon, blocks, invalidBlocks } =
-		useSelect(
-			( select ) => {
-				const {
-					getBlockRootClientId,
-					getBlocksByClientId,
-					canRemoveBlocks,
-				} = select( blockEditorStore );
-				const { getBlockStyles, getBlockType } = select( blocksStore );
-				const _blocks = getBlocksByClientId( clientIds );
-				if (
-					! _blocks.length ||
-					_blocks.some( ( block ) => ! block )
-				) {
-					return { invalidBlocks: true };
-				}
-				const rootClientId = getBlockRootClientId( clientIds );
-				const [ { name: firstBlockName } ] = _blocks;
-				const _isSingleBlockSelected = _blocks.length === 1;
-				let _icon;
-				if ( _isSingleBlockSelected ) {
-					_icon = blockInformation?.icon; // Take into account active block variations.
-				} else {
-					const isSelectionOfSameType =
-						new Set( _blocks.map( ( { name } ) => name ) ).size ===
-						1;
-					// When selection consists of blocks of multiple types, display an
-					// appropriate icon to communicate the non-uniformity.
-					_icon = isSelectionOfSameType
-						? getBlockType( firstBlockName )?.icon
-						: copy;
-				}
-				return {
-					canRemove: canRemoveBlocks( clientIds, rootClientId ),
-					hasBlockStyles:
-						_isSingleBlockSelected &&
-						!! getBlockStyles( firstBlockName )?.length,
-					icon: _icon,
-					blocks: _blocks,
-				};
-			},
-			[ clientIds, blockInformation?.icon ]
-		);
+	const {
+		canRemove,
+		hasBlockStyles,
+		icon,
+		invalidBlocks,
+		isReusable,
+		isTemplate,
+	} = useSelect(
+		( select ) => {
+			const {
+				getBlockRootClientId,
+				getBlocksByClientId,
+				canRemoveBlocks,
+			} = select( blockEditorStore );
+			const { getBlockStyles, getBlockType } = select( blocksStore );
+			const _blocks = getBlocksByClientId( clientIds );
+			if ( ! _blocks.length || _blocks.some( ( block ) => ! block ) ) {
+				return { invalidBlocks: true };
+			}
+			const rootClientId = getBlockRootClientId( clientIds );
+			const [ { name: firstBlockName } ] = _blocks;
+			const _isSingleBlockSelected = _blocks.length === 1;
+			let _icon;
+			if ( _isSingleBlockSelected ) {
+				_icon = blockInformation?.icon; // Take into account active block variations.
+			} else {
+				const isSelectionOfSameType =
+					new Set( _blocks.map( ( { name } ) => name ) ).size === 1;
+				// When selection consists of blocks of multiple types, display an
+				// appropriate icon to communicate the non-uniformity.
+				_icon = isSelectionOfSameType
+					? getBlockType( firstBlockName )?.icon
+					: copy;
+			}
+			return {
+				canRemove: canRemoveBlocks( clientIds, rootClientId ),
+				hasBlockStyles:
+					_isSingleBlockSelected &&
+					!! getBlockStyles( firstBlockName )?.length,
+				icon: _icon,
+				isReusable:
+					_isSingleBlockSelected && isReusableBlock( _blocks[ 0 ] ),
+				isTemplate:
+					_isSingleBlockSelected && isTemplatePart( _blocks[ 0 ] ),
+			};
+		},
+		[ clientIds, blockInformation?.icon ]
+	);
 	const blockTitle = useBlockDisplayTitle( {
 		clientId: clientIds?.[ 0 ],
 		maximumLength: 35,
 	} );
+
 	if ( invalidBlocks ) {
 		return null;
 	}
-	const isSingleBlock = blocks.length === 1;
-	const isReusable = isSingleBlock && isReusableBlock( blocks[ 0 ] );
-	const isTemplate = isSingleBlock && isTemplatePart( blocks[ 0 ] );
+
 	const hideDropdown = ! hasBlockStyles && ! canRemove;
 	if ( hideDropdown ) {
 		return (
@@ -238,6 +242,8 @@ export const BlockSwitcher = ( { clientIds } ) => {
 			</ToolbarGroup>
 		);
 	}
+
+	const isSingleBlock = clientIds.length === 1;
 	const blockSwitcherLabel = isSingleBlock
 		? blockTitle
 		: __( 'Multiple blocks selected' );
@@ -248,9 +254,9 @@ export const BlockSwitcher = ( { clientIds } ) => {
 				_n(
 					'Change type of %d block',
 					'Change type of %d blocks',
-					blocks.length
+					clientIds.length
 				),
-				blocks.length
+				clientIds.length
 		  );
 	return (
 		<ToolbarGroup>

@ntsekouras
Copy link
Contributor Author

This is what I had in mind.

Okay, I got it now. I updated per your suggestion.

Copy link
Member

@Mamaduka Mamaduka 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, Nik.

The changes look great and test well for me. The feature also has a good e2e test coverage.

@afercia
Copy link
Contributor

afercia commented Jan 17, 2024

Please consider that as reported at #51445 this button should not get a HTML disabled attribute. Instead, it should get an aria-disabled attribute and be noop'ed to keep it focusable.

This button is also used to communicate the block type. In fac, its accessible name is the block type. By making the button not focusable, this information is not available to keyboard users and screen reader users.

Additionally:

  • Right now in this PR the butto gets both disabled and aria-disabled="true". That's not correct, it should only get one of the twos and htat should be aria-disabled="true".
  • WHen the button is aria-disabled="true", it should also visually look disabled. There is.a default styling for aria-disabled="true" buttons, not sure why it doesn't work in this case.
  • Please test also when the Show button text labels preference is enabled.
  • Also important: when a block is locked, I'm not sure users should be able to change the styles. I think the dropdown should not be available when a block is locked.

@Mamaduka
Copy link
Member

Mamaduka commented Jan 17, 2024

Sorry for the confusion, @afercia. I initially thought that the dropdown would always be displayed after this PR, which would have removed the need to disabling the button.

Your concerns are valid but not necessarily a blocker for this PR. Since it mainly contains performance improvement.

@ntsekouras
Copy link
Contributor Author

@afercia you're right about your suggestions, but since this is just a refactor for performance without updating the existing html, I think it's better to tackle this separately - tracked by your issue.

@ntsekouras ntsekouras merged commit 8c1b69c into trunk Jan 17, 2024
56 checks passed
@ntsekouras ntsekouras deleted the refactor/block-switcher-to-defer-transform-calculations branch January 17, 2024 12:26
@github-actions github-actions bot added this to the Gutenberg 17.6 milestone Jan 17, 2024
@Mamaduka
Copy link
Member

Btw refactoring the useBlockDisplayTitle hook would be a nice follow-up for this PR. Currently, it's the only reason the block switcher component re-renders. The optimization will benefit other components as well.

Previous attempts: #32118 and #40004.

@afercia
Copy link
Contributor

afercia commented Jan 18, 2024

@afercia you're right about your suggestions, but since this is just a refactor for performance without updating the existing html, I think it's better to tackle this separately - tracked by your issue.

Sure, no problem.

@Mamaduka
Copy link
Member

Btw, created a follow-up for useBlockDisplayTitle hook - #58250.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Type] Performance Related to performance efforts
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants