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

List View: allow expanding and collapsing of nested blocks #32117

Merged
merged 16 commits into from
Jun 15, 2021

Conversation

gwwar
Copy link
Contributor

@gwwar gwwar commented May 21, 2021

Part of #26141 to add the ability to expand and collapse parts of list view.

Updates in this PR include click support for expand/collapse and left and right keyboard events, as noted in https://www.w3.org/TR/wai-aria-practices/examples/treegrid/treegrid-1.html. A left keypress on a expanded item should collapse it, and a second keypress should navigate to its parent. Similarly a right keypress on a collapsed item should expand it.

I plan on splitting up work for List View expand/collapse in two parts:

  • This PR will focus on basic UI + click/keyboard events.
  • A follow up PR will add animations for slide in and out for the tree grid rows. Work here is somewhat non-trivial due to the nature of the markup (nested items aren't children but siblings) and no native support for transitions on auto dimensions. We'll need JS to animate this. Ideally react spring should be updated before we add another animation here. See Block Editor: update react-spring to 9.2.4 #30979

Due to related interest, I also wrote up a quick issue around if Tree Grid still makes sense for this component #32294

expandcollapse.mp4

Requested Feedback 👀

The main thing that sticks out is state management and keyboard/focus handling. Right now keyboard handling is implemented at the Tree Grid level, which makes triggering callbacks at the branch level very difficult. I couldn't think of a good way of preserving nested collapsed state without resorting to a heavier data solution like a data store, or something a bit hacky like the click() call I made. Let me know if folks had thoughts around that. I think I have this mostly sorted with useReducer, but I can also make a data store here if folks would prefer that instead.

Testing Instructions

  • Navigate to the Post or Site Editor, and click to display the list view.
  • Verify that clicking on the chevron toggles display of nested items
  • Hidden items should not be rendered in the DOM
  • Toggle state of child items should be preserved.
  • Other list views like in the Navigation block should still work/make sense
nav.mp4

@gwwar gwwar requested a review from ellatrix as a code owner May 21, 2021 22:05
@gwwar gwwar self-assigned this May 21, 2021
@gwwar gwwar marked this pull request as draft May 21, 2021 22:05
@github-actions
Copy link

github-actions bot commented May 21, 2021

Size Change: +1.46 kB (0%)

Total Size: 1.04 MB

Filename Size Change
build/block-editor/index.min.js 119 kB +489 B (0%)
build/block-editor/style-rtl.css 13.5 kB +119 B (+1%)
build/block-editor/style.css 13.5 kB +119 B (+1%)
build/block-library/index.min.js 144 kB +152 B (0%)
build/components/index.min.js 180 kB +234 B (0%)
build/compose/index.min.js 10.2 kB +5 B (0%)
build/data/index.min.js 7.22 kB +2 B (0%)
build/edit-post/index.min.js 58.6 kB +140 B (0%)
build/edit-post/style-rtl.css 6.98 kB +52 B (+1%)
build/edit-post/style.css 6.96 kB +54 B (+1%)
build/edit-site/index.min.js 25.9 kB -5 B (0%)
build/edit-widgets/index.min.js 15.8 kB +99 B (+1%)
ℹ️ View Unchanged
Filename Size Change
build/a11y/index.min.js 1.12 kB 0 B
build/annotations/index.min.js 2.93 kB 0 B
build/api-fetch/index.min.js 2.42 kB 0 B
build/autop/index.min.js 2.28 kB 0 B
build/blob/index.min.js 672 B 0 B
build/block-directory/index.min.js 6.62 kB 0 B
build/block-directory/style-rtl.css 989 B 0 B
build/block-directory/style.css 990 B 0 B
build/block-library/blocks/archives/editor-rtl.css 61 B 0 B
build/block-library/blocks/archives/editor.css 60 B 0 B
build/block-library/blocks/archives/style-rtl.css 65 B 0 B
build/block-library/blocks/archives/style.css 65 B 0 B
build/block-library/blocks/audio/editor-rtl.css 58 B 0 B
build/block-library/blocks/audio/editor.css 58 B 0 B
build/block-library/blocks/audio/style-rtl.css 112 B 0 B
build/block-library/blocks/audio/style.css 112 B 0 B
build/block-library/blocks/audio/theme-rtl.css 125 B 0 B
build/block-library/blocks/audio/theme.css 125 B 0 B
build/block-library/blocks/block/editor-rtl.css 161 B 0 B
build/block-library/blocks/block/editor.css 161 B 0 B
build/block-library/blocks/button/editor-rtl.css 475 B 0 B
build/block-library/blocks/button/editor.css 474 B 0 B
build/block-library/blocks/button/style-rtl.css 603 B 0 B
build/block-library/blocks/button/style.css 602 B 0 B
build/block-library/blocks/buttons/editor-rtl.css 315 B 0 B
build/block-library/blocks/buttons/editor.css 315 B 0 B
build/block-library/blocks/buttons/style-rtl.css 375 B 0 B
build/block-library/blocks/buttons/style.css 375 B 0 B
build/block-library/blocks/calendar/style-rtl.css 208 B 0 B
build/block-library/blocks/calendar/style.css 208 B 0 B
build/block-library/blocks/categories/editor-rtl.css 84 B 0 B
build/block-library/blocks/categories/editor.css 83 B 0 B
build/block-library/blocks/categories/style-rtl.css 79 B 0 B
build/block-library/blocks/categories/style.css 79 B 0 B
build/block-library/blocks/code/style-rtl.css 90 B 0 B
build/block-library/blocks/code/style.css 90 B 0 B
build/block-library/blocks/code/theme-rtl.css 131 B 0 B
build/block-library/blocks/code/theme.css 131 B 0 B
build/block-library/blocks/columns/editor-rtl.css 190 B 0 B
build/block-library/blocks/columns/editor.css 190 B 0 B
build/block-library/blocks/columns/style-rtl.css 422 B 0 B
build/block-library/blocks/columns/style.css 422 B 0 B
build/block-library/blocks/cover/editor-rtl.css 644 B 0 B
build/block-library/blocks/cover/editor.css 646 B 0 B
build/block-library/blocks/cover/style-rtl.css 1.22 kB 0 B
build/block-library/blocks/cover/style.css 1.23 kB 0 B
build/block-library/blocks/embed/editor-rtl.css 486 B 0 B
build/block-library/blocks/embed/editor.css 486 B 0 B
build/block-library/blocks/embed/style-rtl.css 401 B 0 B
build/block-library/blocks/embed/style.css 400 B 0 B
build/block-library/blocks/embed/theme-rtl.css 124 B 0 B
build/block-library/blocks/embed/theme.css 124 B 0 B
build/block-library/blocks/file/editor-rtl.css 301 B 0 B
build/block-library/blocks/file/editor.css 300 B 0 B
build/block-library/blocks/file/frontend.min.js 773 B 0 B
build/block-library/blocks/file/style-rtl.css 255 B 0 B
build/block-library/blocks/file/style.css 255 B 0 B
build/block-library/blocks/freeform/editor-rtl.css 2.44 kB 0 B
build/block-library/blocks/freeform/editor.css 2.44 kB 0 B
build/block-library/blocks/gallery/editor-rtl.css 704 B 0 B
build/block-library/blocks/gallery/editor.css 705 B 0 B
build/block-library/blocks/gallery/style-rtl.css 1.06 kB 0 B
build/block-library/blocks/gallery/style.css 1.06 kB 0 B
build/block-library/blocks/gallery/theme-rtl.css 122 B 0 B
build/block-library/blocks/gallery/theme.css 122 B 0 B
build/block-library/blocks/group/editor-rtl.css 160 B 0 B
build/block-library/blocks/group/editor.css 160 B 0 B
build/block-library/blocks/group/style-rtl.css 57 B 0 B
build/block-library/blocks/group/style.css 57 B 0 B
build/block-library/blocks/group/theme-rtl.css 93 B 0 B
build/block-library/blocks/group/theme.css 93 B 0 B
build/block-library/blocks/heading/editor-rtl.css 152 B 0 B
build/block-library/blocks/heading/editor.css 152 B 0 B
build/block-library/blocks/heading/style-rtl.css 76 B 0 B
build/block-library/blocks/heading/style.css 76 B 0 B
build/block-library/blocks/home-link/style-rtl.css 259 B 0 B
build/block-library/blocks/home-link/style.css 259 B 0 B
build/block-library/blocks/html/editor-rtl.css 281 B 0 B
build/block-library/blocks/html/editor.css 281 B 0 B
build/block-library/blocks/image/editor-rtl.css 729 B 0 B
build/block-library/blocks/image/editor.css 727 B 0 B
build/block-library/blocks/image/style-rtl.css 481 B 0 B
build/block-library/blocks/image/style.css 485 B 0 B
build/block-library/blocks/image/theme-rtl.css 124 B 0 B
build/block-library/blocks/image/theme.css 124 B 0 B
build/block-library/blocks/latest-comments/style-rtl.css 281 B 0 B
build/block-library/blocks/latest-comments/style.css 282 B 0 B
build/block-library/blocks/latest-posts/editor-rtl.css 137 B 0 B
build/block-library/blocks/latest-posts/editor.css 137 B 0 B
build/block-library/blocks/latest-posts/style-rtl.css 529 B 0 B
build/block-library/blocks/latest-posts/style.css 529 B 0 B
build/block-library/blocks/list/style-rtl.css 63 B 0 B
build/block-library/blocks/list/style.css 63 B 0 B
build/block-library/blocks/media-text/editor-rtl.css 176 B 0 B
build/block-library/blocks/media-text/editor.css 176 B 0 B
build/block-library/blocks/media-text/style-rtl.css 492 B 0 B
build/block-library/blocks/media-text/style.css 489 B 0 B
build/block-library/blocks/more/editor-rtl.css 434 B 0 B
build/block-library/blocks/more/editor.css 434 B 0 B
build/block-library/blocks/navigation-link/editor-rtl.css 633 B 0 B
build/block-library/blocks/navigation-link/editor.css 634 B 0 B
build/block-library/blocks/navigation-link/style-rtl.css 94 B 0 B
build/block-library/blocks/navigation-link/style.css 94 B 0 B
build/block-library/blocks/navigation/editor-rtl.css 1.55 kB 0 B
build/block-library/blocks/navigation/editor.css 1.55 kB 0 B
build/block-library/blocks/navigation/frontend.min.js 2.86 kB 0 B
build/block-library/blocks/navigation/style-rtl.css 1.63 kB 0 B
build/block-library/blocks/navigation/style.css 1.63 kB 0 B
build/block-library/blocks/nextpage/editor-rtl.css 395 B 0 B
build/block-library/blocks/nextpage/editor.css 395 B 0 B
build/block-library/blocks/page-list/editor-rtl.css 310 B 0 B
build/block-library/blocks/page-list/editor.css 311 B 0 B
build/block-library/blocks/page-list/style-rtl.css 240 B 0 B
build/block-library/blocks/page-list/style.css 240 B 0 B
build/block-library/blocks/paragraph/editor-rtl.css 157 B 0 B
build/block-library/blocks/paragraph/editor.css 157 B 0 B
build/block-library/blocks/paragraph/style-rtl.css 247 B 0 B
build/block-library/blocks/paragraph/style.css 248 B 0 B
build/block-library/blocks/post-author/editor-rtl.css 209 B 0 B
build/block-library/blocks/post-author/editor.css 209 B 0 B
build/block-library/blocks/post-author/style-rtl.css 183 B 0 B
build/block-library/blocks/post-author/style.css 184 B 0 B
build/block-library/blocks/post-comments-form/style-rtl.css 140 B 0 B
build/block-library/blocks/post-comments-form/style.css 140 B 0 B
build/block-library/blocks/post-comments/style-rtl.css 360 B 0 B
build/block-library/blocks/post-comments/style.css 359 B 0 B
build/block-library/blocks/post-content/editor-rtl.css 139 B 0 B
build/block-library/blocks/post-content/editor.css 139 B 0 B
build/block-library/blocks/post-excerpt/editor-rtl.css 73 B 0 B
build/block-library/blocks/post-excerpt/editor.css 73 B 0 B
build/block-library/blocks/post-excerpt/style-rtl.css 69 B 0 B
build/block-library/blocks/post-excerpt/style.css 69 B 0 B
build/block-library/blocks/post-featured-image/editor-rtl.css 338 B 0 B
build/block-library/blocks/post-featured-image/editor.css 338 B 0 B
build/block-library/blocks/post-featured-image/style-rtl.css 141 B 0 B
build/block-library/blocks/post-featured-image/style.css 141 B 0 B
build/block-library/blocks/post-template/editor-rtl.css 100 B 0 B
build/block-library/blocks/post-template/editor.css 99 B 0 B
build/block-library/blocks/post-template/style-rtl.css 379 B 0 B
build/block-library/blocks/post-template/style.css 380 B 0 B
build/block-library/blocks/post-title/style-rtl.css 60 B 0 B
build/block-library/blocks/post-title/style.css 60 B 0 B
build/block-library/blocks/preformatted/style-rtl.css 103 B 0 B
build/block-library/blocks/preformatted/style.css 103 B 0 B
build/block-library/blocks/pullquote/editor-rtl.css 183 B 0 B
build/block-library/blocks/pullquote/editor.css 183 B 0 B
build/block-library/blocks/pullquote/style-rtl.css 318 B 0 B
build/block-library/blocks/pullquote/style.css 318 B 0 B
build/block-library/blocks/pullquote/theme-rtl.css 169 B 0 B
build/block-library/blocks/pullquote/theme.css 169 B 0 B
build/block-library/blocks/query-pagination-numbers/editor-rtl.css 122 B 0 B
build/block-library/blocks/query-pagination-numbers/editor.css 121 B 0 B
build/block-library/blocks/query-pagination/editor-rtl.css 270 B 0 B
build/block-library/blocks/query-pagination/editor.css 262 B 0 B
build/block-library/blocks/query-pagination/style-rtl.css 168 B 0 B
build/block-library/blocks/query-pagination/style.css 168 B 0 B
build/block-library/blocks/query-title/editor-rtl.css 86 B 0 B
build/block-library/blocks/query-title/editor.css 86 B 0 B
build/block-library/blocks/query/editor-rtl.css 131 B 0 B
build/block-library/blocks/query/editor.css 132 B 0 B
build/block-library/blocks/quote/style-rtl.css 169 B 0 B
build/block-library/blocks/quote/style.css 169 B 0 B
build/block-library/blocks/quote/theme-rtl.css 221 B 0 B
build/block-library/blocks/quote/theme.css 221 B 0 B
build/block-library/blocks/rss/editor-rtl.css 201 B 0 B
build/block-library/blocks/rss/editor.css 202 B 0 B
build/block-library/blocks/rss/style-rtl.css 290 B 0 B
build/block-library/blocks/rss/style.css 290 B 0 B
build/block-library/blocks/search/editor-rtl.css 211 B 0 B
build/block-library/blocks/search/editor.css 211 B 0 B
build/block-library/blocks/search/style-rtl.css 359 B 0 B
build/block-library/blocks/search/style.css 362 B 0 B
build/block-library/blocks/search/theme-rtl.css 64 B 0 B
build/block-library/blocks/search/theme.css 64 B 0 B
build/block-library/blocks/separator/editor-rtl.css 99 B 0 B
build/block-library/blocks/separator/editor.css 99 B 0 B
build/block-library/blocks/separator/style-rtl.css 251 B 0 B
build/block-library/blocks/separator/style.css 251 B 0 B
build/block-library/blocks/separator/theme-rtl.css 172 B 0 B
build/block-library/blocks/separator/theme.css 172 B 0 B
build/block-library/blocks/shortcode/editor-rtl.css 512 B 0 B
build/block-library/blocks/shortcode/editor.css 512 B 0 B
build/block-library/blocks/site-logo/editor-rtl.css 440 B 0 B
build/block-library/blocks/site-logo/editor.css 441 B 0 B
build/block-library/blocks/site-logo/style-rtl.css 154 B 0 B
build/block-library/blocks/site-logo/style.css 154 B 0 B
build/block-library/blocks/social-link/editor-rtl.css 164 B 0 B
build/block-library/blocks/social-link/editor.css 165 B 0 B
build/block-library/blocks/social-links/editor-rtl.css 800 B 0 B
build/block-library/blocks/social-links/editor.css 799 B 0 B
build/block-library/blocks/social-links/style-rtl.css 1.34 kB 0 B
build/block-library/blocks/social-links/style.css 1.34 kB 0 B
build/block-library/blocks/spacer/editor-rtl.css 308 B 0 B
build/block-library/blocks/spacer/editor.css 308 B 0 B
build/block-library/blocks/spacer/style-rtl.css 48 B 0 B
build/block-library/blocks/spacer/style.css 48 B 0 B
build/block-library/blocks/table/editor-rtl.css 478 B 0 B
build/block-library/blocks/table/editor.css 478 B 0 B
build/block-library/blocks/table/style-rtl.css 480 B 0 B
build/block-library/blocks/table/style.css 480 B 0 B
build/block-library/blocks/table/theme-rtl.css 188 B 0 B
build/block-library/blocks/table/theme.css 188 B 0 B
build/block-library/blocks/tag-cloud/editor-rtl.css 118 B 0 B
build/block-library/blocks/tag-cloud/editor.css 118 B 0 B
build/block-library/blocks/tag-cloud/style-rtl.css 94 B 0 B
build/block-library/blocks/tag-cloud/style.css 94 B 0 B
build/block-library/blocks/template-part/editor-rtl.css 551 B 0 B
build/block-library/blocks/template-part/editor.css 550 B 0 B
build/block-library/blocks/template-part/theme-rtl.css 101 B 0 B
build/block-library/blocks/template-part/theme.css 101 B 0 B
build/block-library/blocks/term-description/editor-rtl.css 90 B 0 B
build/block-library/blocks/term-description/editor.css 90 B 0 B
build/block-library/blocks/text-columns/editor-rtl.css 95 B 0 B
build/block-library/blocks/text-columns/editor.css 95 B 0 B
build/block-library/blocks/text-columns/style-rtl.css 166 B 0 B
build/block-library/blocks/text-columns/style.css 166 B 0 B
build/block-library/blocks/verse/style-rtl.css 87 B 0 B
build/block-library/blocks/verse/style.css 87 B 0 B
build/block-library/blocks/video/editor-rtl.css 569 B 0 B
build/block-library/blocks/video/editor.css 570 B 0 B
build/block-library/blocks/video/style-rtl.css 173 B 0 B
build/block-library/blocks/video/style.css 173 B 0 B
build/block-library/blocks/video/theme-rtl.css 124 B 0 B
build/block-library/blocks/video/theme.css 124 B 0 B
build/block-library/common-rtl.css 1.26 kB 0 B
build/block-library/common.css 1.26 kB 0 B
build/block-library/editor-rtl.css 9.68 kB 0 B
build/block-library/editor.css 9.67 kB 0 B
build/block-library/reset-rtl.css 506 B 0 B
build/block-library/reset.css 507 B 0 B
build/block-library/style-rtl.css 10.2 kB 0 B
build/block-library/style.css 10.2 kB 0 B
build/block-library/theme-rtl.css 692 B 0 B
build/block-library/theme.css 693 B 0 B
build/block-serialization-default-parser/index.min.js 1.3 kB 0 B
build/block-serialization-spec-parser/index.min.js 3.06 kB 0 B
build/blocks/index.min.js 47.2 kB 0 B
build/components/style-rtl.css 16.2 kB 0 B
build/components/style.css 16.1 kB 0 B
build/core-data/index.min.js 12.1 kB 0 B
build/customize-widgets/index.min.js 9.98 kB 0 B
build/customize-widgets/style-rtl.css 1.45 kB 0 B
build/customize-widgets/style.css 1.44 kB 0 B
build/data-controls/index.min.js 828 B 0 B
build/date/index.min.js 31.8 kB 0 B
build/deprecated/index.min.js 738 B 0 B
build/dom-ready/index.min.js 576 B 0 B
build/dom/index.min.js 4.62 kB 0 B
build/edit-navigation/index.min.js 14 kB 0 B
build/edit-navigation/style-rtl.css 3.08 kB 0 B
build/edit-navigation/style.css 3.08 kB 0 B
build/edit-post/classic-rtl.css 454 B 0 B
build/edit-post/classic.css 454 B 0 B
build/edit-site/style-rtl.css 4.75 kB 0 B
build/edit-site/style.css 4.75 kB 0 B
build/edit-widgets/style-rtl.css 3.45 kB 0 B
build/edit-widgets/style.css 3.45 kB 0 B
build/editor/index.min.js 38.3 kB 0 B
build/editor/style-rtl.css 3.91 kB 0 B
build/editor/style.css 3.9 kB 0 B
build/element/index.min.js 3.44 kB 0 B
build/escape-html/index.min.js 739 B 0 B
build/format-library/index.min.js 5.68 kB 0 B
build/format-library/style-rtl.css 637 B 0 B
build/format-library/style.css 639 B 0 B
build/hooks/index.min.js 1.76 kB 0 B
build/html-entities/index.min.js 628 B 0 B
build/i18n/index.min.js 3.73 kB 0 B
build/is-shallow-equal/index.min.js 709 B 0 B
build/keyboard-shortcuts/index.min.js 1.74 kB 0 B
build/keycodes/index.min.js 1.43 kB 0 B
build/list-reusable-blocks/index.min.js 2.07 kB 0 B
build/list-reusable-blocks/style-rtl.css 629 B 0 B
build/list-reusable-blocks/style.css 628 B 0 B
build/media-utils/index.min.js 3.08 kB 0 B
build/notices/index.min.js 1.07 kB 0 B
build/nux/index.min.js 2.31 kB 0 B
build/nux/style-rtl.css 718 B 0 B
build/nux/style.css 716 B 0 B
build/plugins/index.min.js 1.99 kB 0 B
build/primitives/index.min.js 1.03 kB 0 B
build/priority-queue/index.min.js 791 B 0 B
build/react-i18n/index.min.js 924 B 0 B
build/redux-routine/index.min.js 2.82 kB 0 B
build/reusable-blocks/index.min.js 2.56 kB 0 B
build/reusable-blocks/style-rtl.css 225 B 0 B
build/reusable-blocks/style.css 225 B 0 B
build/rich-text/index.min.js 10.6 kB 0 B
build/server-side-render/index.min.js 1.63 kB 0 B
build/shortcode/index.min.js 1.68 kB 0 B
build/token-list/index.min.js 847 B 0 B
build/url/index.min.js 1.95 kB 0 B
build/viewport/index.min.js 1.28 kB 0 B
build/warning/index.min.js 1.13 kB 0 B
build/widgets/index.min.js 6.32 kB 0 B
build/widgets/style-rtl.css 693 B 0 B
build/widgets/style.css 693 B 0 B
build/wordcount/index.min.js 1.24 kB 0 B

compressed-size-action

@jasmussen
Copy link
Contributor

Took this for a quick spin, even if it's still a work in progress. This is what I see:

list view

Already now, this is an amazing improvement, it's incredibly better. I have a few design metrics that I'll help push so the various buttons are just right. This one also shows an ellipsis menu:

Screenshot 2021-05-26 at 09 22 14

Even just in this state, it surfaces some interesting questions that I'm happy to chat through. For example: if you select a deeply nested block in the canvas, which is inside a collapsed group, does it uncollapse the group? And also, should the groups that you collapse stay collapsed even if you close and reopen the list view? Should every top level item start collapsed? All excellent questions that I imagine we can tune across a few PRs and not something we have to get right in this one. All to say, amazing work.

@gwwar
Copy link
Contributor Author

gwwar commented May 26, 2021

Thanks for adding images @jasmussen, I ran out of time last week ✨

Even just in this state, it surfaces some interesting questions that I'm happy to chat through.

💯 I wanted to chat through this too!

One thing that was much more jarring is that the primary action selects the block. This is not much of an issue with a mouse, but with a keyboard this means that focus is lost on the side panel, and a second enter creates a new paragraph, rather than toggling primary action.

For example: if you select a deeply nested block in the canvas, which is inside a collapsed group, does it uncollapse the group? And also, should the groups that you collapse stay collapsed even if you close and reopen the list view?

There's a demo in treegrid on behavior https://www.w3.org/TR/wai-aria-practices/examples/treegrid/treegrid-1.html, where the first click selects, and the second click expands. I'm not sure I like the feel of the tristate toggle myself, but we could do something similar.

demo.mp4

Another thing that's different with the current implementation is that we're using a single td cell, and we need to be able to select nested items. This means that we need to reserve the primary action enter for selecting the block rather than expand/collapsing the item. Reserving Left and right keyboard events to expand and toggle feels okay.

And also, should the groups that you collapse stay collapsed even if you close and reopen the list view?

I would expect it to retain remain collapsed, but also provide an expand all button/open all folders to the selected node. It's actually cheaper to not keep track of non-visible toggle state, so it's pretty simple to implement if we feel otherwise. We could also let other folks weigh in and modify this in follow up PRs.

Should every top level item start collapsed?

It'd be much more performant for pages with lots of nested items to do this, but the tradeoff is more overhead for what is this/what do I do? I do think we'd want to hold off on trying this until we have implemented an open all nested items button, or open all items to our selected node target button.

All excellent questions that I imagine we can tune across a few PRs and not something we have to get right in this one. All to say, amazing work.

To not let this get too out of scope, I'll aim to add the necessary missing keyboard events and try merging with behavior as is, unless folks spot anything that we should have for the first pass.

@gwwar
Copy link
Contributor Author

gwwar commented May 26, 2021

Looking at some of the keyboard handling, it probably makes more sense to try and put the expand/collapse state + handling in the treegrid component, I'll give that a try next.

@jasmussen
Copy link
Contributor

One thing that was much more jarring is that the primary action selects the block. This is not much of an issue with a mouse, but with a keyboard this means that focus is lost on the side panel, and a second enter creates a new paragraph, rather than toggling primary action.

Just to be sure, this is describing existing trunk behavior also, correct? It isn't specific to the addition of the expand/collapse chevron? Also CC: @Copons @jameskoster for some of the conversations around the list view. There may be prior art in the inserter, where if you tab to select a block and press Enter, it inserts it but doesn't move focus there. Whereas tab and press ⌘ + Enter, it inserts it and moves focus there. If I recall the conversation correctly, that is a known pattern for screen readers and interaction shortcuts.

Reserving Left and right keyboard events to expand and toggle feels okay.

👍 👍

We could also let other folks weigh in and modify this in follow up PRs.

Definitely good to keep this PR as small as possible, I only got excited about all the potential followups! And yes, I do think it'd be nice that a group you intentionally collapsed stays collapsed across your entire session, despite opening and closing the list view.

@jameskoster
Copy link
Contributor

One thing that was much more jarring is that the primary action selects the block. This is not much of an issue with a mouse, but with a keyboard this means that focus is lost on the side panel, and a second enter creates a new paragraph, rather than toggling primary action.

I'm pretty sure this is the issue @Copons has surfaced a number of times: there's no streamlined way for one to move focus back to list view after selecting a block. The 'workaround' is that you need to close + reopen it which is one step more than it should be. One solution might be separate keyboard shortcuts for opening/closing rather than a single toggle, but that's probably something to explore separately.

@jasmussen
Copy link
Contributor

By the way, let me know when you're ready for me to push some polish here to the paddings (just little things) ✨

@gwwar
Copy link
Contributor Author

gwwar commented May 27, 2021

By the way, let me know when you're ready for me to push some polish here to the paddings (just little things) ✨

@jasmussen I'll give you a ping when I'm ready, I'm still sorting out the best place to handle state 👍

@gwwar
Copy link
Contributor Author

gwwar commented May 27, 2021

I added a quick work around for the keyboard support. @jasmussen feel free to add commits to the branch. 👍

@gwwar gwwar marked this pull request as ready for review May 27, 2021 22:25
@gwwar gwwar requested review from Copons and talldan May 27, 2021 22:26
* WordPress dependencies
*/
import { chevronRight, Icon } from '@wordpress/icons';
export default function BlockNavigationExpander( { onClick } ) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ideally in the future we don't need a component like this, and can instead use CSS rules to point at an SVG image.

@jasmussen
Copy link
Contributor

I pushed a little polish:

Screenshot 2021-05-28 at 09 52 05

This is based on the metrics in #32294 (comment), and involved creating a new "chevron-small" icon. I believe these utility icons are useful, just like we have a close and close small icon, for specific contexts like these.

@@ -121,8 +121,8 @@

.block-editor-block-icon {
align-self: flex-start;
margin-right: ( $grid-unit-05 * 2.5 ); // 10px is off the 4px grid, but required for visual alignment between block name and subsequent nested icon
Copy link
Contributor

Choose a reason for hiding this comment

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

CC: @jameskoster, the icon was scaled down to 20px, so it didn't show true pixels. I shifted the metrics around a bit, but would appreciate you taking a look when you have a chance, thank you.

Copy link
Contributor

Choose a reason for hiding this comment

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

Screenshot 2021-05-28 at 10 41 48

Looks good to me.

@jameskoster
Copy link
Contributor

One small issue I spotted: If you select and collapse a parent, it would be nice if the bottom border radii matched the top. Here's how it looks currently:

Screenshot 2021-05-28 at 10 42 45


@jasmussen I appreciate the smaller chevron, but am wondering if it could be even smaller? I'm still feeling some tension between the block icon and the chevron. Here's a slightly downsized version (keeping the same overall footprint):

Screenshot 2021-05-28 at 10 55 56

And an even more downsized version (1px stroke):

Screenshot 2021-05-28 at 10 55 26

What do you think?

@jameskoster jameskoster added Figma Component Issues that require updates to Figma components for designers Needs Figma Update Needs an update to Figma for design purposes labels May 28, 2021
@jasmussen
Copy link
Contributor

I'd be on board with a smaller one, but I'd keep it 1.5px so as to not introduce new visual ingredients, which it'd feel like at 1px.

@jameskoster
Copy link
Contributor

jameskoster commented May 28, 2021

It's a shame, the 1px feels better to me in practise, but I understand the reluctance to add more ingredients :D

I pushed a smaller version of the 1.5px chevron to try. It's a little larger (filesize) because I outlined the stroke.

@jameskoster
Copy link
Contributor

@jameskoster jameskoster removed Figma Component Issues that require updates to Figma components for designers Needs Figma Update Needs an update to Figma for design purposes labels May 28, 2021
@jasmussen
Copy link
Contributor

Nice one, thanks Jay!

@gwwar gwwar force-pushed the try/collapsible-list-view branch from 14d82c8 to c36de9e Compare June 11, 2021 16:13
@chrisvanpatten
Copy link
Contributor

This looks really slick! Hope to see it ship!

// Left:
// If a row is focused, and it is expanded, collapses the current row.
if ( activeRow?.ariaExpanded === 'true' ) {
onCollapseRow( activeRow?.dataset?.block );
Copy link
Contributor

@talldan talldan Jun 14, 2021

Choose a reason for hiding this comment

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

This and the similar line below couples the generic treegrid implementation to only work with elements that have a data-block attribute (blocks). I think it should ideally work for any kind of tree regardless of the content.

I'm not too precious about it (the whole thing could end up being deleted given the other discussions about moving away from tree grid in #32294 .)

But if there's a quick fix it would be good. Maybe pass the element back to the List View code or something, and that code can instead be responsible for accessing the dataset.block on the element.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think that's pretty fair. I've updated this in 90dd73f to pass back the row element instead

return (
// Keyboard events are handled by TreeGrid see: components/src/tree-grid/index.js
// eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions
<span
Copy link
Contributor

@talldan talldan Jun 14, 2021

Choose a reason for hiding this comment

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

The implementation as a pseudo-element in the w3 example was really surprising to me.

I guess that makes it completely hidden from the accessibility tree, in which case the span could have aria-hidden="true" specified to replicate that.

It might be worth adding some comments to the component explaining why this is implemented like it is—I imagine many devs with good intentions might be tempted to change it to a Button which wouldn't be good given it's already rendered in a Button.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good call, I've updated this in f4b5a5f

For folks 👀 we can see the pseudo element in https://www.w3.org/TR/wai-aria-practices/examples/treegrid/treegrid-1.html

Screen Shot 2021-06-14 at 9 25 57 AM

@@ -17,6 +23,16 @@ import useBlockNavigationDropZone from './use-block-navigation-drop-zone';
import { store as blockEditorStore } from '../../store';

const noop = () => {};
const expanded = ( state, action ) => {
Copy link
Contributor

@talldan talldan Jun 14, 2021

Choose a reason for hiding this comment

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

Yeah, agreed, it's probably not a big issue. I doubt this will ever become a huge amount of data.

I have ideas but I think it's an effort vs. reward question more than anything:

  • BlockNavigation could receive stable block client ids from a selector (e.g. from getBlockOrder), and reconcile it against the expanded state in an effect.
  • It could be possible to move the state to the treegrid component entirely. Could each TreeGridRow manage its own state? I think it'd then have to render its own expander component, but that seems potentially ok. I might be missing some complications.

}
// If a row is focused, and it is expanded, focuses the first cell in the row.
getRowFocusables( activeRow )?.[ 0 ]?.focus();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Looks like that's how a tree view works:
https://www.w3.org/TR/wai-aria-practices/#keyboard-interaction-22

So it might be determined by how #32294 is progressed. I'm not sure how that can be moved forwards, but probably worth coming to a decision soon.

Copy link
Contributor

@talldan talldan left a comment

Choose a reason for hiding this comment

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

Looks and works great. Comments are all pretty minor.

@gwwar
Copy link
Contributor Author

gwwar commented Jun 14, 2021

It could be possible to move the state to the treegrid component entirely. Could each TreeGridRow manage its own state? I think it'd then have to render its own expander component, but that seems potentially ok. I might be missing some complications.

Right we could try to simplify state by making this a boolean value on a child component versus a map in List View. Two things that stopped me from going with that approach were:

Ideally, we do not render children in the DOM if it's collapsed. The List View mirrors the full document state in some use cases, which is a performance sensitive area.

dom.mp4

Persistence of toggle stage (Eg if we collapse child items, and then toggle a parent, do we retain state of those toggled child elements, or does it default to all toggled open?).

retainstate.mp4

@gwwar
Copy link
Contributor Author

gwwar commented Jun 14, 2021

I think this should be good to go after another round of 👀 cc @Copons @talldan. Thanks for everyone's feedback so far!

@talldan talldan added [Feature] List View Menu item in the top toolbar to select blocks from a list of links. [Type] Feature New feature to highlight in changelogs. labels Jun 15, 2021
Copy link
Contributor

@talldan talldan left a comment

Choose a reason for hiding this comment

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

Fantastic addition, great work @gwwar.

For a follow-up, I did notice that when closing and reopening list view, the expanded/collapsed state isn't retained, I guess a side-effect of the component no longer being rendered and the component state being lost.

@gwwar
Copy link
Contributor Author

gwwar commented Jun 15, 2021

Thanks for taking another look @talldan!

For a follow-up, I did notice that when closing and reopening list view, the expanded/collapsed state isn't retained, I guess a side-effect of the component no longer being rendered and the component state being lost.

To support that we can move component state into a data store. Shouldn't be too bad to do, but we'll need to make sure that other list view instances are not sharing state.

@gwwar gwwar merged commit dbba260 into trunk Jun 15, 2021
@gwwar gwwar deleted the try/collapsible-list-view branch June 15, 2021 15:59
@shaunandrews
Copy link
Contributor

🥳

@talldan talldan added this to the Gutenberg 10.9 milestone Jun 16, 2021
@talldan
Copy link
Contributor

talldan commented Jun 17, 2021

To support that we can move component state into a data store. Shouldn't be too bad to do, but we'll need to make sure that other list view instances are not sharing state.

Another thing I wondered is whether this state should be part of the block editor store. Looking through that store, most of the actions/selectors relate directly to an actual block or block list, while this is a view on a block list, so it does feel slightly different to the main purpose of that store. 🤔

@mtias
Copy link
Member

mtias commented Jun 23, 2021

Awesome to see this, great work everyone! Really happy with all the iterations and refinements on this elements, it's becoming more and more useful and powerful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] List View Menu item in the top toolbar to select blocks from a list of links. [Type] Feature New feature to highlight in changelogs.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants