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

Multi-selection: allow partial block selection #38892

Merged
merged 67 commits into from
Mar 28, 2022

Conversation

ellatrix
Copy link
Member

@ellatrix ellatrix commented Feb 17, 2022

Description

Fixes #27481.
See also #3629.

These changes allow the user to select multiple blocks without selecting the blocks as a whole. This is done by allowing native selection across block boundaries, detecting the selection start and end in the appropriate rich text instances, and handling actions for this selection.

This PR implements Enter, Backspace, Delete (forward merge) and any input (typing) over the selection.

You can select partially by mouse (drag), shift + click, and also the keyboard (shift + arrow).

It works in all browsers including Firefox.

cross-block-selection

We use the merge function on the block type to handle merges and detect if two blocks are mergeable. If two blocks are not mergeable, we fall back to the current behaviour, which is to select the blocks entirely.

Testing Instructions

Screenshots

Types of changes

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • I've tested my changes with keyboard and screen readers.
  • My code has proper inline documentation.
  • I've included developer documentation if appropriate.
  • I've updated all React Native files affected by any refactorings/renamings in this PR (please manually search all *.native.js files for terms that need renaming or removal).
  • I've updated related schemas if appropriate.

@ellatrix ellatrix added [Type] Enhancement A suggestion for improvement. [Feature] Writing Flow Block selection, navigation, splitting, merging, deletion... [Feature] Block Multi Selection The ability to select and manipulate multiple blocks labels Feb 17, 2022
@github-actions
Copy link

github-actions bot commented Feb 17, 2022

Size Change: +1.5 kB (0%)

Total Size: 1.21 MB

Filename Size Change
build/block-editor/index.min.js 148 kB +1.16 kB (+1%)
build/block-editor/style-rtl.css 15.4 kB +20 B (0%)
build/block-editor/style.css 15.4 kB +20 B (0%)
build/block-library/index.min.js 171 kB +35 B (0%)
build/blocks/index.min.js 46.8 kB -1 B (0%)
build/components/index.min.js 223 kB +74 B (0%)
build/customize-widgets/index.min.js 11 kB +48 B (0%)
build/data/index.min.js 8.61 kB +57 B (+1%)
build/dom/index.min.js 4.58 kB +44 B (+1%)
build/edit-post/index.min.js 29.6 kB +14 B (0%)
build/edit-site/index.min.js 45.2 kB +18 B (0%)
build/editor/index.min.js 38.4 kB -74 B (0%)
build/rich-text/index.min.js 11.2 kB +94 B (+1%)
ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 993 B
build/admin-manifest/index.min.js 1.24 kB
build/annotations/index.min.js 2.77 kB
build/api-fetch/index.min.js 2.27 kB
build/autop/index.min.js 2.15 kB
build/blob/index.min.js 487 B
build/block-directory/index.min.js 6.49 kB
build/block-directory/style-rtl.css 1.01 kB
build/block-directory/style.css 1.01 kB
build/block-editor/default-editor-styles-rtl.css 378 B
build/block-editor/default-editor-styles.css 378 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 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 111 B
build/block-library/blocks/audio/style.css 111 B
build/block-library/blocks/audio/theme-rtl.css 125 B
build/block-library/blocks/audio/theme.css 125 B
build/block-library/blocks/avatar/editor-rtl.css 59 B
build/block-library/blocks/avatar/editor.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 445 B
build/block-library/blocks/button/editor.css 445 B
build/block-library/blocks/button/style-rtl.css 560 B
build/block-library/blocks/button/style.css 560 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-template/style-rtl.css 127 B
build/block-library/blocks/comment-template/style.css 127 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-query-loop/editor-rtl.css 95 B
build/block-library/blocks/comments-query-loop/editor.css 95 B
build/block-library/blocks/cover/editor-rtl.css 546 B
build/block-library/blocks/cover/editor.css 547 B
build/block-library/blocks/cover/style-rtl.css 1.56 kB
build/block-library/blocks/cover/style.css 1.56 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 417 B
build/block-library/blocks/embed/style.css 417 B
build/block-library/blocks/embed/theme-rtl.css 124 B
build/block-library/blocks/embed/theme.css 124 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 255 B
build/block-library/blocks/file/style.css 255 B
build/block-library/blocks/file/view.min.js 353 B
build/block-library/blocks/freeform/editor-rtl.css 2.44 kB
build/block-library/blocks/freeform/editor.css 2.44 kB
build/block-library/blocks/gallery/editor-rtl.css 961 B
build/block-library/blocks/gallery/editor.css 964 B
build/block-library/blocks/gallery/style-rtl.css 1.51 kB
build/block-library/blocks/gallery/style.css 1.51 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 159 B
build/block-library/blocks/group/editor.css 159 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 114 B
build/block-library/blocks/heading/style.css 114 B
build/block-library/blocks/html/editor-rtl.css 332 B
build/block-library/blocks/html/editor.css 333 B
build/block-library/blocks/image/editor-rtl.css 731 B
build/block-library/blocks/image/editor.css 730 B
build/block-library/blocks/image/style-rtl.css 529 B
build/block-library/blocks/image/style.css 535 B
build/block-library/blocks/image/theme-rtl.css 124 B
build/block-library/blocks/image/theme.css 124 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 199 B
build/block-library/blocks/latest-posts/editor.css 198 B
build/block-library/blocks/latest-posts/style-rtl.css 447 B
build/block-library/blocks/latest-posts/style.css 446 B
build/block-library/blocks/list/style-rtl.css 94 B
build/block-library/blocks/list/style.css 94 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 708 B
build/block-library/blocks/navigation-link/editor.css 706 B
build/block-library/blocks/navigation-link/style-rtl.css 94 B
build/block-library/blocks/navigation-link/style.css 94 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-submenu/view.min.js 375 B
build/block-library/blocks/navigation/editor-rtl.css 2.03 kB
build/block-library/blocks/navigation/editor.css 2.04 kB
build/block-library/blocks/navigation/style-rtl.css 1.89 kB
build/block-library/blocks/navigation/style.css 1.88 kB
build/block-library/blocks/navigation/view.min.js 2.85 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 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 157 B
build/block-library/blocks/paragraph/editor.css 157 B
build/block-library/blocks/paragraph/style-rtl.css 273 B
build/block-library/blocks/paragraph/style.css 273 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/style-rtl.css 446 B
build/block-library/blocks/post-comments-form/style.css 446 B
build/block-library/blocks/post-comments/style-rtl.css 521 B
build/block-library/blocks/post-comments/style.css 521 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 721 B
build/block-library/blocks/post-featured-image/editor.css 721 B
build/block-library/blocks/post-featured-image/style-rtl.css 153 B
build/block-library/blocks/post-featured-image/style.css 153 B
build/block-library/blocks/post-template/editor-rtl.css 99 B
build/block-library/blocks/post-template/editor.css 98 B
build/block-library/blocks/post-template/style-rtl.css 323 B
build/block-library/blocks/post-template/style.css 323 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 80 B
build/block-library/blocks/post-title/style.css 80 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 198 B
build/block-library/blocks/pullquote/editor.css 198 B
build/block-library/blocks/pullquote/style-rtl.css 370 B
build/block-library/blocks/pullquote/style.css 370 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 234 B
build/block-library/blocks/query-pagination/style.css 231 B
build/block-library/blocks/query/editor-rtl.css 131 B
build/block-library/blocks/query/editor.css 132 B
build/block-library/blocks/quote/style-rtl.css 201 B
build/block-library/blocks/quote/style.css 201 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 397 B
build/block-library/blocks/search/style.css 398 B
build/block-library/blocks/search/theme-rtl.css 64 B
build/block-library/blocks/search/theme.css 64 B
build/block-library/blocks/separator/editor-rtl.css 140 B
build/block-library/blocks/separator/editor.css 140 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 474 B
build/block-library/blocks/shortcode/editor.css 474 B
build/block-library/blocks/site-logo/editor-rtl.css 759 B
build/block-library/blocks/site-logo/editor.css 759 B
build/block-library/blocks/site-logo/style-rtl.css 181 B
build/block-library/blocks/site-logo/style.css 181 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 177 B
build/block-library/blocks/social-link/editor.css 177 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.37 kB
build/block-library/blocks/social-links/style.css 1.36 kB
build/block-library/blocks/spacer/editor-rtl.css 332 B
build/block-library/blocks/spacer/editor.css 332 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 471 B
build/block-library/blocks/table/editor.css 472 B
build/block-library/blocks/table/style-rtl.css 481 B
build/block-library/blocks/table/style.css 481 B
build/block-library/blocks/table/theme-rtl.css 188 B
build/block-library/blocks/table/theme.css 188 B
build/block-library/blocks/tag-cloud/style-rtl.css 226 B
build/block-library/blocks/tag-cloud/style.css 227 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 571 B
build/block-library/blocks/video/editor.css 572 B
build/block-library/blocks/video/style-rtl.css 173 B
build/block-library/blocks/video/style.css 173 B
build/block-library/blocks/video/theme-rtl.css 124 B
build/block-library/blocks/video/theme.css 124 B
build/block-library/common-rtl.css 934 B
build/block-library/common.css 932 B
build/block-library/editor-rtl.css 10 kB
build/block-library/editor.css 10 kB
build/block-library/reset-rtl.css 474 B
build/block-library/reset.css 474 B
build/block-library/style-rtl.css 11.2 kB
build/block-library/style.css 11.2 kB
build/block-library/theme-rtl.css 689 B
build/block-library/theme.css 694 B
build/block-serialization-default-parser/index.min.js 1.12 kB
build/block-serialization-spec-parser/index.min.js 2.83 kB
build/components/style-rtl.css 14.9 kB
build/components/style.css 14.9 kB
build/compose/index.min.js 11.2 kB
build/core-data/index.min.js 14.3 kB
build/customize-widgets/style-rtl.css 1.39 kB
build/customize-widgets/style.css 1.39 kB
build/data-controls/index.min.js 663 B
build/date/index.min.js 32 kB
build/deprecated/index.min.js 518 B
build/dom-ready/index.min.js 336 B
build/edit-navigation/index.min.js 15.8 kB
build/edit-navigation/style-rtl.css 4.04 kB
build/edit-navigation/style.css 4.05 kB
build/edit-post/classic-rtl.css 546 B
build/edit-post/classic.css 547 B
build/edit-post/style-rtl.css 7.07 kB
build/edit-post/style.css 7.07 kB
build/edit-site/style-rtl.css 7.6 kB
build/edit-site/style.css 7.58 kB
build/edit-widgets/index.min.js 16.3 kB
build/edit-widgets/style-rtl.css 4.4 kB
build/edit-widgets/style.css 4.39 kB
build/editor/style-rtl.css 3.71 kB
build/editor/style.css 3.71 kB
build/element/index.min.js 4.29 kB
build/escape-html/index.min.js 548 B
build/format-library/index.min.js 6.62 kB
build/format-library/style-rtl.css 571 B
build/format-library/style.css 571 B
build/hooks/index.min.js 1.66 kB
build/html-entities/index.min.js 454 B
build/i18n/index.min.js 3.79 kB
build/is-shallow-equal/index.min.js 535 B
build/keyboard-shortcuts/index.min.js 1.83 kB
build/keycodes/index.min.js 1.41 kB
build/list-reusable-blocks/index.min.js 1.75 kB
build/list-reusable-blocks/style-rtl.css 838 B
build/list-reusable-blocks/style.css 838 B
build/media-utils/index.min.js 2.94 kB
build/notices/index.min.js 957 B
build/nux/index.min.js 2.12 kB
build/nux/style-rtl.css 751 B
build/nux/style.css 749 B
build/plugins/index.min.js 1.98 kB
build/preferences/index.min.js 1.2 kB
build/primitives/index.min.js 949 B
build/priority-queue/index.min.js 611 B
build/react-i18n/index.min.js 704 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.69 kB
build/reusable-blocks/index.min.js 2.24 kB
build/reusable-blocks/style-rtl.css 256 B
build/reusable-blocks/style.css 256 B
build/server-side-render/index.min.js 1.61 kB
build/shortcode/index.min.js 1.52 kB
build/token-list/index.min.js 668 B
build/url/index.min.js 1.99 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 280 B
build/widgets/index.min.js 7.21 kB
build/widgets/style-rtl.css 1.16 kB
build/widgets/style.css 1.16 kB
build/wordcount/index.min.js 1.07 kB

compressed-size-action

@mcsf
Copy link
Contributor

mcsf commented Feb 21, 2022

🎉

Let us know when you'd like some testing and reviewing done. For now this was really cool to try out, but I can also consistently crash the editor if I delete a span of text across two blocks (using Enter) and then use the editor's undo action.

@ellatrix
Copy link
Member Author

For now this was really cool to try out, but I can also consistently crash the editor if I delete a span of text across two blocks (using Enter) and then use the editor's undo action.

That's because Enter is not implemented yet. Only Backspace and (forward) Delete is implemented right now. For now I disabled all native behaviour, which was causing the errors.

@ellatrix
Copy link
Member Author

Almost all e2e tests should be passing now. What remains to be done is polishing up the code and reusing more of the existing merge function (merge the mergeBlocks code paths into a single one).

As part of that, or after that, we can look into adding Enter handling. This can be either:

  • Merging the blocks first, then split
  • Reusing parts of the merge (delete all selected content), then insert a paragraph between the two blocks instead of merging them.

event.preventDefault();
removeBlocks( clientIds );

if ( clientIds.length < 2 ) {
Copy link
Member

Choose a reason for hiding this comment

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

Some of these cases could use a comment to describe the situation we are addressing

@mtias
Copy link
Member

mtias commented Feb 24, 2022

Excellent to see this! I'm glad it's able to build incrementally on the foundation we have. Ensuring mergeBlocks is doing its job well as a basis makes sense.

Outside of the mechanics, I think we need to revisit the multiselect outline to only show when you are performing a block level operation (moving multiple blocks, transforming, etc) similar to how we highlight the outline on hover / focus of the blocktype area on single blocks. It might need some design tweaks as well.

One last comment: I think it might be worth (as a follow up) to consider whether it makes sense to allow pressing shift while selecting across blocks to force full block selection instead of partial. Curious what you think about that or if it'd even be necessary given block level tools would still apply block level even with partial selections (inspector controls, etc).

@ellatrix
Copy link
Member Author

One last comment: I think it might be worth (as a follow up) to consider whether it makes sense to allow pressing shift while selecting across blocks to force full block selection instead of partial. Curious what you think about that or if it'd even be necessary given block level tools would still apply block level even with partial selections (inspector controls, etc).

Yes I'm definitely going to work on enabling this for keyboard as well. So far focus has been on getting tests to pass :D

@ellatrix
Copy link
Member Author

ellatrix commented Feb 25, 2022

Yes I'm definitely going to work on enabling this for keyboard as well.

Added selection by keyboard.

To do: add Enter handling and more e2e tests. Also split the deleteSelection code into more parts because it's quite verbose.

Copy link
Member

@dmsnell dmsnell left a comment

Choose a reason for hiding this comment

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

No telling how far-reaching and positive this change will be. I'm only starting to digest the changes and hope to provide some more-useful feedback, but as a first pass I'm just trying to understand more than review. Thanks for attacking this problem.

const selectionAnchor = select.getSelectionStart();
const selectionFocus = select.getSelectionEnd();

if ( selectionAnchor.clientId === selectionFocus.clientId ) return;
Copy link
Member

Choose a reason for hiding this comment

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

should we not wrap these in {}s to avoid making it easy to recreate some infamous bugs due to the missing brackets?

// oops!
if (  )
	someNewThing();
	return;

Copy link
Member Author

Choose a reason for hiding this comment

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

Prettier will decrease indentation, so imho it's clear when you add lines. If we don't like this style, we should probably add the relevant rule to the linter.

Copy link
Member

Choose a reason for hiding this comment

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

just raising it because I thought the practice was long abandoned because of its risk. I hadn't seen it in Gutenberg before and it seems riskier still to rely on the auto-formatter to avoid code patterns that invite bugs. carry on 🙇‍♂️

(by the way, it would seem fine to add this to the linter if other people are also leery of single-line if blocks)

Copy link
Member Author

Choose a reason for hiding this comment

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

Right, I'm fine with avoiding it. Maybe we should add it to the linter though, so it's "official".

packages/block-editor/src/store/actions.js Show resolved Hide resolved
packages/block-editor/src/store/actions.js Outdated Show resolved Hide resolved
* @param {string} attributeKey The selected block attribute key.
* @param {number} startOffset The start offset.
* @param {number} endOffset The end offset.
* @param {string|Object} clientId The selected block client ID.
Copy link
Member

Choose a reason for hiding this comment

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

should we update the description here, or better, use a different attribute name for clientId if we aren't actually passing a clientId? I'm guessing we're looking at passing an actual block instead of a clientId, but I would be surprised if I had to do this: block = action.clientId;

Copy link
Member Author

Choose a reason for hiding this comment

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

Right, I just haven't stared fixing all the doc blocks yet.

Copy link
Contributor

Choose a reason for hiding this comment

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

➕ to update the docs and possibly the param name here. Also can we rename the passed object's property from start to selectionStart to map the name in state?

Copy link
Contributor

@youknowriad youknowriad left a comment

Choose a reason for hiding this comment

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

This is a great start, people will love to have this. I didn't dive into the code but I wanted to try it a bit.

Things I noticed so far:

  • It seems the selection works well for paragraph blocks only
  • When I tried, list, quote blocks, selecting across two blocks does some weird things: The selection changes when I release the mouse.
  • After using the feature (Enter after cross paragraph selection), I think the second paragraph block end up in a weird state. I'm not able to use "Enter" on that paragraph anymore, sometimes cross-selection doesn't work anymore.
  • In Firefox, multi-selection doesn't seem to work.
  • I have some blocks that can fail (JS errors) when I try merge or undo after a cross-selection removal or "Enter" (I'm not sure yet about the exact step but here's what I see on the console.

Screen Shot 2022-02-26 at 7 59 55 AM

@mtias
Copy link
Member

mtias commented Feb 26, 2022

@ellatrix sorry :) to clarify my comment regarding shift, I meant combining shift with pointer based selection (so you drag between blocks while holding shift) to force pure multi-selection. Though I don't think it'd be necessary if we always have block selection happening anyways.

@ellatrix
Copy link
Member Author

@youknowriad

It seems the selection works well for paragraph blocks only
When I tried, list, quote blocks, selecting across two blocks does some weird things: The selection changes when I release the mouse.

If works for me. Did you pull the most recent changes? Both list and quote blocks have merging functions and I checked that this works correctly. For some blocks that don't have merging functions we will select the entire blocks at mouse up, which is what we do for all blocks currently. That is to communicate to the user that the blocks are selected as a whole (not partially).

After using the feature (Enter after cross paragraph selection), I think the second paragraph block end up in a weird state. I'm not able to use "Enter" on that paragraph anymore, sometimes cross-selection doesn't work anymore.

I'm still able to press Enter in both the newly created empty paragraph (sitting in the middle) and the third paragraph. Not sure if we're at the same commit 😅

In Firefox, multi-selection doesn't seem to work.

Confirmed. I will investigate this.

I have some blocks that can fail (JS errors) when I try merge or undo after a cross-selection removal or "Enter" (I'm not sure yet about the exact step but here's what I see on the console.

This also indicates to me that you're maybe at an earlier state of this PR? I used to get error messages, but I no longer get them.

@youknowriad
Copy link
Contributor

@ellatrix I think the last Firefox fix broke the behavior in Safari and Chrome. Also, in Firefox, I noticed that I'm not able to start a selection from the currently selected block.

@ellatrix ellatrix force-pushed the try/partial-multi-selection branch 3 times, most recently from a790836 to f875847 Compare March 11, 2022 16:03
@dmsnell
Copy link
Member

dmsnell commented Mar 11, 2022

In case anyone's interested, I had a hard time assessing the clipboard contents (as usual when dealing with the clipboard) while testing with this. I made a simple clipboard viewer to reveal all the MIME types and previews of the items in the paste events.

@ellatrix ellatrix force-pushed the try/partial-multi-selection branch from f875847 to 90240a5 Compare March 15, 2022 08:22
@ellatrix ellatrix marked this pull request as ready for review March 15, 2022 08:22
@youknowriad
Copy link
Contributor

This is still working good but I'm noticing a couple more issues:

  • I can't select a text inside a quote
  • shift + selection behaves weird (testing on Safari): I shift select multiple blocks starting from a paragraph. Sometimes if I try to delete, selection jumps happen but nothing is deleted, sometimes it just stop multi-selecting... It depends I guess on what blocks I'm selecting (sometimes I include buttons, quote in the selections)

@ellatrix
Copy link
Member Author

@youknowriad I tested both of your points in different browsers and it works fine. Can select text in Safari, Firefox and Chrome. Shift+Arrow seems to work well in Safari.

keyboard-selection-safari

@youknowriad
Copy link
Contributor

I just tested again and I also can't reproduce. I don't know if I was on the wrong commit or if it something that starts happening after some interactions.

Anyway, found another smaller thing where sometimes I have to hit "backspace" twice to delete a simple selection (inside a quote).

Screen.Recording.2022-03-28.at.9.22.52.AM.mov

@ellatrix
Copy link
Member Author

Anyway, found another smaller thing where sometimes I have to hit "backspace" twice to delete a simple selection (inside a quote).

Yes, seeing that also. Can't delete selection in list as well. So many behaviours we don't have tests for 🙈

@ellatrix
Copy link
Member Author

Anyway, found another smaller thing where sometimes I have to hit "backspace" twice to delete a simple selection (inside a quote).

I fixed it, just waiting for the tests to run on the last commit to push.

@ellatrix ellatrix merged commit 721e3c4 into trunk Mar 28, 2022
@ellatrix ellatrix deleted the try/partial-multi-selection branch March 28, 2022 09:47
@github-actions github-actions bot added this to the Gutenberg 13.0 milestone Mar 28, 2022
@mtias
Copy link
Member

mtias commented Mar 28, 2022

Outstanding work here, thanks for persevering @ellatrix :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Block Multi Selection The ability to select and manipulate multiple blocks [Feature] Writing Flow Block selection, navigation, splitting, merging, deletion... [Type] Enhancement A suggestion for improvement.
Projects
No open projects
Archived in project
Development

Successfully merging this pull request may close these issues.

Block Selection: Partial block multiselection
9 participants