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

Allow dragging between adjacent container blocks based on a threshold #56466

Merged
merged 9 commits into from
Dec 12, 2023

Conversation

andrewserong
Copy link
Contributor

@andrewserong andrewserong commented Nov 23, 2023

What?

Fixes #56463

This PR explores a potential fix for dragging between adjacent container blocks (specifically Group and Cover blocks) when dragging within their padding area.

The proposal here is to add a threshold area (within 30px) of the vertical and horizontal edges of the container block, where if a user drags in that area, we attempt to drop before or after the container block rather than within it.

Why?

If you have a template with adjacent Group or Cover blocks where there is no gap between those blocks, it is either very difficult or impossible to drag between them. This PR explores one potential solution to it, by adding a threshold area to allow dragging between these blocks (in the vertical and horizontal axes)

How?

  • If the block uses a dropZoneElement and the user is dragging toward the top or bottom of the block (i.e. within a 30px threshold) then treat the drag/drop as being intended for before or after the block instead of within it.
  • As above, but if the user is dragging within the left and right edges and the parent block is in a horizontal orientation (i.e. it is a Row block) then allow dragging before and after the block instead of within it.
  • Only enable the drag between behaviour if the block is big enough for it to be useable (currently 4 x the threshold, or 120px)
  • Add the dropZoneElement for the Group block so that its container element can be used to determine where to place the drop.

Note: the behaviour in this PR is most noticeable / mostly applies when a Group block has padding set. The Cover block already uses a padding area, so it's quite noticeable with the Cover block, too.

To-do

  • Ensure that dragging from a first child position to the above next block works (e.g. drag from first child of Cover to just previous to the Cover block)
  • Move the threshold to a constant
  • Update the drop indicator line
  • Fix issue when dragging a block that is already just before the target block (ensure that the logic that factors in the indexes of dragged blocks is reused)
  • Ensure the parent block allows drag to the position (i.e. what if the user shouldn't be allowed to break out of the current block in this context) Out of scope, as this is tracked in: [drag-and-drop] Visual cue for dropping element shown in another block's inner content even when dropping isn't possible #24174
  • Detect the orientation of the next block up — what should happen if the parent block is horizontally oriented, for example?

Testing Instructions

In a post or template (the TwentyTwentyFour template is good for testing this) attempt to drag and drop a block between two adjacent container blocks (in particular Cover and Group blocks). With this PR applied, you should be able to drag just within the padding area (or 30px of it) of the block to drag between the adjacent blocks. Note: it's expected that Group blocks without any padding should not receive this threshold, as the user will be dragging over a child of the Group block.

Test the above, but with Row as a parent block, and set the Row's block spacing to 0 so there are no gaps. If the children are Cover blocks or Group blocks with some padding, then the threshold behaviour in this PR should apply. That is, it should now be easier to drag between adjacent blocks. The logic should also work correctly in RTL languages.

See if this adversely affects drag or performance in any way compared to trunk.

Screenshots or screencast

Vertical

The following screengrab shows dragging between adjacent Cover and Group blocks, where dragging just toward the vertical edge allows for dragging between the blocks.

2023-11-28.16.46.27.mp4

Horizontal (LTR language)

2023-12-12.15.51.32.mp4

Horizontal (RTL language)

2023-12-12.16.10.16.mp4

@andrewserong andrewserong added [Type] Enhancement A suggestion for improvement. [Feature] Drag and Drop Drag and drop functionality when working with blocks labels Nov 23, 2023
@andrewserong andrewserong self-assigned this Nov 23, 2023
Copy link

github-actions bot commented Nov 23, 2023

Size Change: +292 B (0%)

Total Size: 1.71 MB

Filename Size Change
build/block-editor/index.min.js 246 kB +271 B (0%)
build/block-library/index.min.js 213 kB +21 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.29 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.29 kB
build/block-editor/content.css 4.28 kB
build/block-editor/default-editor-styles-rtl.css 403 B
build/block-editor/default-editor-styles.css 403 B
build/block-editor/style-rtl.css 15.2 kB
build/block-editor/style.css 15.2 kB
build/block-library/blocks/archives/editor-rtl.css 61 B
build/block-library/blocks/archives/editor.css 60 B
build/block-library/blocks/archives/style-rtl.css 90 B
build/block-library/blocks/archives/style.css 90 B
build/block-library/blocks/audio/editor-rtl.css 150 B
build/block-library/blocks/audio/editor.css 150 B
build/block-library/blocks/audio/style-rtl.css 122 B
build/block-library/blocks/audio/style.css 122 B
build/block-library/blocks/audio/theme-rtl.css 138 B
build/block-library/blocks/audio/theme.css 138 B
build/block-library/blocks/avatar/editor-rtl.css 116 B
build/block-library/blocks/avatar/editor.css 116 B
build/block-library/blocks/avatar/style-rtl.css 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 587 B
build/block-library/blocks/button/editor.css 587 B
build/block-library/blocks/button/style-rtl.css 633 B
build/block-library/blocks/button/style.css 632 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.27 kB
build/block-library/blocks/navigation/style.css 2.26 kB
build/block-library/blocks/navigation/view.min.js 1.04 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 335 B
build/block-library/blocks/pullquote/style.css 335 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 613 B
build/block-library/blocks/search/style.css 613 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 399 B
build/block-library/blocks/table/editor.css 399 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.4 kB
build/block-library/editor.css 12.4 kB
build/block-library/elements-rtl.css 54 B
build/block-library/elements.css 54 B
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.3 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 257 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.6 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.87 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.68 kB
build/edit-post/classic-rtl.css 571 B
build/edit-post/classic.css 571 B
build/edit-post/index.min.js 32.2 kB
build/edit-post/style-rtl.css 7.39 kB
build/edit-post/style.css 7.38 kB
build/edit-site/index.min.js 194 kB
build/edit-site/style-rtl.css 14.5 kB
build/edit-site/style.css 14.6 kB
build/edit-widgets/index.min.js 17.3 kB
build/edit-widgets/style-rtl.css 4.71 kB
build/edit-widgets/style.css 4.71 kB
build/editor/index.min.js 53.7 kB
build/editor/style-rtl.css 4.35 kB
build/editor/style.css 4.34 kB
build/element/index.min.js 4.87 kB
build/escape-html/index.min.js 548 B
build/format-library/index.min.js 7.76 kB
build/format-library/style-rtl.css 577 B
build/format-library/style.css 577 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.5 kB
build/interactivity/navigation.min.js 1.16 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/index.min.js 5.27 kB
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 1.85 kB
build/preferences/index.min.js 1.26 kB
build/primitives/index.min.js 994 B
build/priority-queue/index.min.js 1.52 kB
build/private-apis/index.min.js 994 B
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.5 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 1.98 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.18 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

@andrewserong
Copy link
Contributor Author

Update: still very hacky, but I've gotten the drop indicator line to now reflect the threshold so it feels a bit more stable now:

2023-11-24.15.42.44.mp4

Will continue hacking on the remaining to-do items next week!

@mtias mtias added the Needs Design Feedback Needs general design feedback. label Nov 24, 2023
@tellthemachines
Copy link
Contributor

Nice experiment!

From testing it feels like one has to linger a little too long on top of the border between the two adjacent containers in order to get the indicator to appear, especially when moving upwards.

draggydrop.mov

Also the visibility of the indicator could be a bit better; I think the problem is we're overlaying a line-shaped indicator on an existing line (the border between blocks) and it's really easy to miss. Not sure exactly how it could look otherwise. Perhaps there could be some animation on the draggable element when it hovers over a dropzone?

@andrewserong
Copy link
Contributor Author

Thanks for taking this for an early spin!

From testing it feels like one has to linger a little too long on top of the border between the two adjacent containers in order to get the indicator to appear, especially when moving upwards.

Oh, good point. Out of curiosity, were you dragging between two adjacent Cover blocks, or a Group block and a Cover block? From the screengrab, it looks like the bottom-most block might be a Group block, which doesn't yet use the dropZoneElement, so the top part of that block won't be receiving the logic in this PR. I'll have a go at adding it in here, too, as that might help with the problem. Essentially, for this PR to work well, both of the adjacent blocks will need to receive this threshold-based logic in order for it to feel smooth.

Perhaps there could be some animation on the draggable element when it hovers over a dropzone?

Definitely a lot we can explore with visual feedback as a user drags over or between dropzones to provide an immediate signal of a change, rather than having to wait for the animation to complete. It'll be a good one to play around with, but possibly for another PR?

@andrewserong
Copy link
Contributor Author

From testing it feels like one has to linger a little too long on top of the border between the two adjacent containers in order to get the indicator to appear, especially when moving upwards.

This might also be helped by adjusting the size of the threshold area, too 🤔

@tellthemachines
Copy link
Contributor

Out of curiosity, were you dragging between two adjacent Cover blocks, or a Group block and a Cover block?

It was a Cover and a Group! Sounds like that was the problem, the lag was definitely greater when moving up than down.

Definitely a lot we can explore with visual feedback as a user drags over or between dropzones to provide an immediate signal of a change, rather than having to wait for the animation to complete. It'll be a good one to play around with, but possibly for another PR?

Yeah that's probably out of scope for this PR; I think the pressing thing for now is to fix the inability to drop between containers!

@andrewserong andrewserong force-pushed the try/threshold-drag-between-blocks branch from b453c39 to 0bf25a4 Compare November 28, 2023 05:48
@andrewserong
Copy link
Contributor Author

It was a Cover and a Group! Sounds like that was the problem, the lag was definitely greater when moving up than down.

Update: yep, looks like that was the problem! Thanks again for testing, I've pushed an update to the Group block and that appears to have resolved it now, so it's a lot easier to get to that in-between position:

2023-11-28.16.46.27.mp4

There's still a bit of work to do in resolving some edge cases before this will be ready for review — things like checking that the parent block's orientation is vertical, otherwise it can get a little odd if a Cover block is the child of a Row block (maybe not terrible, but still odd):

2023-11-28.16.51.12.mp4

It'll also be interesting to see if the addition of the threshold interferes for anyone when the block they're working with intentionally doesn't have much in the way of padding within it, or if it's quite a small or short block 🤔

In any case, I'll continue working through those things, but very happy for feedback from anyone along the way!

@jasmussen
Copy link
Contributor

Just surfacing a little context from this other PR where we have a mockup for hovering on top of a block to surface dropzones before and after: #56186 (comment)

Notably, there's a mockup here that might benefit this particular PR (in addition to the conversation itself).

@andrewserong
Copy link
Contributor Author

Notably, #56186 (comment) that might benefit this particular PR (in addition to the conversation itself).

Oh, nice, thank you for the mockup! At this stage, I think this PR will likely be valuable to implement as a separate step prior to seeing if we can shift elements around to make space for the before and after positions. That is to say, if first we can improve increasing the area within which a valid drop target is made, the hopefully it'll be a little more straightforward in follow-ups to then explore how we present that valid drop target.

I have a bit more work to do on this PR before it'll be ready for review (I've been a bit more focused on list view displacement so far this week), but I'll ping for more feedback when this is ready for a proper look 🙂

Copy link

github-actions bot commented Dec 6, 2023

Flaky tests detected in b1e0fad.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/7177202242
📝 Reported issues:

@andrewserong andrewserong changed the title [WIP] Try: Allow dragging between blocks based on a threshold Allow dragging between adjacent container blocks based on a threshold Dec 7, 2023
@andrewserong andrewserong marked this pull request as ready for review December 7, 2023 04:05
@andrewserong
Copy link
Contributor Author

Update: I believe I've fixed all the edge cases I encountered during testing, so I think this should be ready for review and/or feedback now. It doesn't take care of dragging between all adjacent blocks, just container blocks with padding (i.e. Cover and Group), but the hope is that this should still make a difference to the ease of dragging while building or making adjustments to templates, since it's pretty common to have adjacent covers and groups.

@andrewserong
Copy link
Contributor Author

Hrm, looks like the can drag and drop to the end of a horizontal block list e2e test is failing, so I imagine I've broken something there. Will look into it!

@andrewserong
Copy link
Contributor Author

andrewserong commented Dec 7, 2023

Okay, I think I've fixed the test in ab292fd by adding a minimum height before this threshold behaviour can be used. I've set it to 120px or four times the height of the threshold area so that for shorter blocks (e.g. a row block) this threshold behaviour doesn't interfere with users' ability to drag between blocks within a row — we'll need to do some careful manual testing, especially with interacting with the row block before determining whether to land this PR.

Also if we're happy with the direction of this PR, it might be worth us seeing if we can add another e2e test to cover this change, too, if it isn't too difficult to reproduce the desired behaviour in an e2e.

@@ -20,6 +20,9 @@ import {
} from '../../utils/math';
import { store as blockEditorStore } from '../../store';

const THRESHOLD_DISTANCE = 30;
const MINIMUM_HEIGHT_FOR_THRESHOLD = 120;
Copy link
Member

@ramonjd ramonjd Dec 8, 2023

Choose a reason for hiding this comment

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

So, if a block is 120px high, its "inner" dropzone will be 60px high?

Is this an arbitrary min height or does it correspond to some average height for new blocks?

The computed height for a new, empty group block is 48px in my browser.

I guess it makes more sense to want to drop things inside an empty group block rather than around it 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I guess it makes more sense to want to drop things inside an empty group block rather than around it 😄

That was my thinking. These are just arbitrary numbers for now, but in practice, I figured you probably wouldn't want the threshold for the top/bottom positions being active unless there was at least the same amount of room on the inside of the block to allow for "real" internal dragging. So 120 seemed like a reasonable default to go with for now as it's 4 * the threshold distance. Happy to change any of these values, of course!

@ramonjd
Copy link
Member

ramonjd commented Dec 8, 2023

Just been testing in Chrome, FF and Safari in LTR and RTL locales.

Dragging and dropping between container elements is more intuitive in my experience. 🎉

Before

2023-12-08.14.41.15.mp4

After

2023-12-08.14.38.35.mp4

I removed padding on a few group blocks and dropping in between and inside works as I'd expect. It's a bit fiddly to often get things to land where you want, but it's also this way on trunk.

2023-12-08.14.46.35.mp4

Copy link
Contributor

@tellthemachines tellthemachines left a comment

Choose a reason for hiding this comment

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

This works really well in testing! There's a couple of things I'm having trouble wrapping my head around code-wise so mainly just left questions below 😅

rootBlockIndex = 0,
} = options;

if ( dropZoneElement && parentBlockOrientation !== 'horizontal' ) {
Copy link
Contributor

Choose a reason for hiding this comment

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

interesting that this doesn't seem to be a problem with blocks in horizontal containers even if they have zero space between them (in my testing the inserter always works)

Copy link
Contributor

Choose a reason for hiding this comment

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

Actually spoke too soon 😅 it can be a problem if trying to insert a block between two Stacks inside a Row.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, good point! We could always expand the logic here. Do you mind sharing a video if you get a chance? I'll continue working on this next week!

Copy link
Contributor

Choose a reason for hiding this comment

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

Here's a screengrab of trying to insert a Heading between two Stacks nested inside a Row. You can only really see the drop indicator when hovering at the end of the Row, and that takes a little doing:

drag-in-row.mov

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, yes, that is pretty challenging that one!

I suppose two potential options here:

  • Add in handling for the horizontal orientation here, too, and see if that resolves it (i.e. use threshold on the horizontal axis if the parent is horizontal), or:
  • Treat this PR as vertical only for now, and look at horizontal in a potential follow-up

I'm happy to go either way, but I'll have a play around with horizontal blocks next week and give it a little more thought 🙂

Copy link
Contributor

Choose a reason for hiding this comment

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

Either option sounds good! Anything we do here will be an improvement on the current state of things 😄

const onBlockDrop = useOnBlockDrop(
dropTarget.operation === 'before' || dropTarget.operation === 'after'
? parentBlockClientId
: targetRootClientId,
Copy link
Contributor

Choose a reason for hiding this comment

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

So this works, but I can't quite figure out how 😅 because at root level, targetRootClientId should be undefined. But I can drop a Paragraph between two Images at root level, with 0 block spacing, very smoothly!

Also I tried logging the operation here while dragging and it always switches to insert before the drop happens. I guess that's expected because it's actually an insertion?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So this works, but I can't quite figure out how 😅 because at root level, targetRootClientId should be undefined.

I think the comment for this hook is a bit misleading, unfortunately! At the root of the document, targetRootClientId will be undefined / an empty string, however for a container block at the root of the document that calls useBlockDropZone, it'll pass its clientId in as rootClientId here:

What this means, is that for a container block, by the time you're inside useBlockDropZone, targetRootClientId refers to the client id of the container block itself. So for our purposes, we need to pass in parentBlockClientId (the parent of the container's clientId) in order for it to work properly. In practice, for a Group block at the root of the document, targetRootClientId will be the client id of the Group block, and parentBlockClientId will be an empty string, as we're at the root of the document.

Hope that helps, I know it's quite a mouthful! If / when this PR looks ready to land, I'll see if I can write this up as a comment prior to this line so that it's clearer — and / or so that we can remember what we did here 😄


Also I tried logging the operation here while dragging and it always switches to insert before the drop happens.

Oh strange! I didn't notice that, but the drop should be happening with the previously returned onBlockDrop that had the last state with the "before" or "after" operation. When you perform a drop, I think it'll immediately clear out the dropTarget state back to its default which is insert, so in practice while logging we might be observing the returning to the previous state 🤔

I'm possibly either over thinking that part (or slightly confused about it), but in practice, before, after, and insert should all do the same thing, as the only operation that does anything differently in useOnBlockDrop is replace.

If it's causing any issues though, I can follow-up next week!

Copy link
Contributor

Choose a reason for hiding this comment

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

Oooh I see, thanks for explaining! Yes a comment would be great.

If it's causing any issues though, I can follow-up next week!

It's not causing any issues that I could notice, so should be fine to leave as-is!

@@ -124,6 +126,7 @@ function GroupEdit( { attributes, name, setAttributes, clientId } ) {
? blockProps
: { className: 'wp-block-group__inner-container' },
{
dropZoneElement: ref.current,
Copy link
Contributor

Choose a reason for hiding this comment

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

So in #56312 a similar change was made in Cover so that dragging over the empty area inside the block would make the inner drop zone show, and that caused the drop zone between blocks with no margins to be hidden. But this change is now necessary to make it possible for the in between drop zone to show between Groups?

My main question is how this may affect third party containers - will all containers now need a dropZoneElement ref passed to useInnerBlocksProps?

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 question!

My main question is how this may affect third party containers - will all containers now need a dropZoneElement ref passed to useInnerBlocksProps?

With this PR (and right now) I think they might need to if they want to allow the threshold dragging behaviour in this PR. It's a tricky one, because we can't really know exactly what a 3rd party block is doing with its UI and where its inner blocks will be placed in relation to anything else displayed within the block itself (a bit like how we have things like Media & Text, which is a non-standard kind of container block).

I think I'd lean slightly toward guarding the behaviour in this PR behind the dropZoneElement behaviour for now (and having it be manually passed to useInnerBlocksProps) while we're still fine-tuning how all the drag and drop behaviour works. Then, perhaps further down the track, we could look at making it all happen automatically within useInnerBlocksProps somehow? The tricky part in thinking about that, though, is that not all blocks might be using a ref attached to their outer wrapper, so it might be hard to make it all automatic. Still, worth thinking about!

Copy link
Contributor

Choose a reason for hiding this comment

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

we can't really know exactly what a 3rd party block is doing with its UI and where its inner blocks will be placed in relation to anything else

Yeah this is a good point. In testing with plain WP 6.4 I notice that it's also not possible to drop between two Columns blocks, but it is between Media & Text blocks. Those behaviours are unaltered in this PR so I guess that means regressions are unlikely?

I'm still not sure I quite grasp why the same thing that made dropping between blocks stop working for Cover in #56312 (passing the ref to useInnerBlocksProps) is making dropping between Group blocks work in this PR 😅

Copy link
Contributor Author

@andrewserong andrewserong Dec 8, 2023

Choose a reason for hiding this comment

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

I'm still not sure I quite grasp why the same thing that made dropping between blocks stop working for Cover in #56312 (passing the ref to useInnerBlocksProps) is making dropping between Group blocks work in this PR 😅

It's because we're doing it at the same time as the rest of this PR 😄
If we did a standalone PR that passed dropZoneElement to the Group block's useInnerBlocksProps then we'd expose the issue that we can't drag between two adjacent Group blocks, because the two blocks' dropZoneElements would be adjacent to each other, without any threshold for drag-between. But because this PR now enables a drag threshold within the dropZoneElement, the Group block gets to skip the intermediate step where we break the ability to drag between adjacent blocks.

Copy link
Contributor

Choose a reason for hiding this comment

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

It's already broken though - I guess the difference is that on trunk a drop indicator appears, apparently between the blocks, but in reality dropping over it just adds the dropped block to one of the Groups.

This happens in WP 6.4 with or without Gutenberg:

drop-between-groups.mov

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Gotcha! Yep, on trunk, I think you're right, it looks like it's just dropping within 👍

I must admit, I do find it hard to maintain a good mental model for how all this hooks together 😄

Thanks again for giving this a look!

Copy link
Contributor

Choose a reason for hiding this comment

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

I must admit, I do find it hard to maintain a good mental model for how all this hooks together

Same 😭

@andrewserong andrewserong force-pushed the try/threshold-drag-between-blocks branch from ab292fd to b1e0fad Compare December 12, 2023 05:12
@andrewserong
Copy link
Contributor Author

Update: I've added logic so that if the parent block is horizontal (i.e. it's a Row block) then we use the threshold on the left/right edges. Seems to be working pretty well!

2023-12-12.15.51.32.mp4

With that in place, I think this PR might be ready for a final review now 🤞

Copy link
Contributor

@tellthemachines tellthemachines left a comment

Choose a reason for hiding this comment

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

Re-tested and dropping between containers in both vertical and horizontal orientations is working really well now 🎉

Code also LGTM!

@andrewserong
Copy link
Contributor Author

Thanks for reviewing! I'm sure we'll have more to do to tweak the behaviour here, but I'll merge this in now so we can explore further tweaks in follow-ups.

(Also, if we run into any showstoppers in real world usage, it should be pretty straightforward to revert if need be)

@andrewserong andrewserong merged commit 4d61a94 into trunk Dec 12, 2023
52 checks passed
@andrewserong andrewserong deleted the try/threshold-drag-between-blocks branch December 12, 2023 21:54
@github-actions github-actions bot added this to the Gutenberg 17.3 milestone Dec 12, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Drag and Drop Drag and drop functionality when working with blocks Needs Design Feedback Needs general design feedback. [Type] Enhancement A suggestion for improvement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Improve dragging between adjacent blocks
5 participants