Repository navigation
[lexical-react][lexical-playground] Feature: Draggable individual list items - #9705
Draft
playlikeboy wants to merge 1 commit into
Draft
playlikeboy wants to merge 1 commit into
playlikeboy wants to merge 1 commit into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…t items The drag handle of DraggableBlockPlugin_EXPERIMENTAL now targets the block under the pointer at any depth instead of only top-level blocks, so a list item (in a nested list too) gets its own handle. Descent stops at shadow roots (tables, layout containers, collapsibles), which stay one draggable unit, and the margin band of a list still drags the whole list. Drop targeting is aware of the dragged node: a list item can land between the items of any list (any type, any depth) or outside a list, where it is wrapped in a copy of the list it came from so its type is kept; a block that is not a list item dragged over a list targets the enclosing list, so the drop line only appears where the drop will happen. The drop line starts at the target's left edge to show the nesting depth. Browser-mode tests cover handle targeting, reordering in flat and nested lists, moves between lists, moves out of a list and the escalation of a paragraph to the whole list; the playground e2e spec covers the same flows through the real handle. Closes meta#7630 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
AI review status for this pull request.
|
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
DraggableBlockPlugin_EXPERIMENTALonly ever targets top-level blocks, so hovering a list shows one handle for the whole<ul>/<ol>and individual items cannot be reordered by drag (#7630). Two earlier attempts (#7640, #8178) stalled; the review feedback on them was that nested lists should be reorderable at any depth, that the drop line should only appear where the dragged node can actually land, and that there is no API surface to preserve, so the targeting code may change as needed.This PR changes the targeting in two places:
$getNestedBlockElementdescends into the child block that contains the pointer, repeatedly, so a list item at any depth gets its own handle. Descent stops at shadow roots (tables, layout containers, collapsibles), which stay one draggable unit as before, and at blocks with only inline content. If no child block is under the pointer (the margin band of a list), the block itself is the target, so a whole list can still be dragged from its edge.$resolveDropTargetstarts at the hovered block and walks up to the nearest ancestor that can take the dragged node as a sibling ($canDropAsSibling): anything under the root; a node that requires a parent (a list item) only beside nodes whose parent has the same type as its own, so items move between lists of any type and depth; any other block never beside such nodes. A paragraph dragged over a list item therefore targets the enclosing list and the drop line is drawn above or below the list, not between its items. On drop, a list item that lands outside a list is wrapped in$copyNode(parent), so a numbered item stays numbered (theListItemNodetransform alone would make it a bullet). The drop line starts at the target's left edge so the nesting depth of the target is visible.The rules are expressed with
isParentRequired()/isShadowRoot()/isInline()rather than list node classes, so the plugin does not depend on@lexical/list. Playground containers that are shadow roots (collapsible, layout) are deliberately not descended into in this PR; a predicate prop could opt them in later (this answers the suggestion in #8178 to generalize, without touching table or layout structure here). Horizontal drag-to-indent and multi-block drag are out of scope.Closes #7630
Changeset
.changeset/draggable-block-nested-items.md(@lexical/react: patch,[feature], with aVerify:paragraph).Test plan
Commands run locally (Node 22.22.0, pnpm 11.24.0, Chromium via Playwright):
pnpm run tscandpnpm run tsc-test: clean.pnpm run lintandpnpm run prettier: clean.pnpm run check-changesets: passed.npx vitest --project unit --no-watch packages/lexical-react/src/__tests__/unit/LexicalDraggableBlockPlugin.test.tsx: 2 passed (existing tests).npx vitest --project browser --no-watch packages/lexical-react/src/__tests__/browser/LexicalDraggableBlockPlugin.test.tsx: 7 passed (new; needs a real layout engine, jsdom reports zero rects).pnpm run start+E2E_BROWSER=chromium npx playwright test --project=chromium packages/lexical-playground/__tests__/e2e/DraggableBlock.spec.mjs: 9 passed (5 existing, 4 new). Firefox and WebKit were not run here (the existing drag tests in this spec are already skipped on Firefox).Before
Hovering any list item shows the handle for the whole list; the only drag unit is the
<ul>/<ol>.After
New browser-mode tests (
packages/lexical-react/src/__tests__/browser/LexicalDraggableBlockPlugin.test.tsx):New e2e tests in
packages/lexical-playground/__tests__/e2e/DraggableBlock.spec.mjs, driven through the real handle in the playground:🤖 Generated with Claude Code