Skip to content

fix(core): preserve text selection when toggling off list with AllSelection#7718

Open
togswr wants to merge 3 commits intoueberdosis:mainfrom
togswr:fix/toggle-list-allselection-selection-collapse
Open

fix(core): preserve text selection when toggling off list with AllSelection#7718
togswr wants to merge 3 commits intoueberdosis:mainfrom
togswr:fix/toggle-list-allselection-selection-collapse

Conversation

@togswr
Copy link
Copy Markdown

@togswr togswr commented Apr 7, 2026

Changes Overview

Fix a regression introduced in #7683 where toggling off a list with AllSelection (Ctrl/Cmd+A) causes the text selection to collapse. After the list is lifted, the selection becomes empty (from === to), causing the user to lose their selection and BubbleMenu to disappear.

Implementation Approach

createInnerSelectionForWholeDocList() used structural boundary positions (from = 1, to = list.nodeSize - 1) to create a TextSelection. These positions sit outside inline content, so after liftListItem removes the list/item wrappers, TextSelection.map() falls back to Selection.near() and collapses the selection.

Replace TextSelection.create() with TextSelection.between(), which resolves non-text positions to the nearest valid cursor positions. This ensures the selection maps correctly through the lift operation and remains non-empty afterward.

Position trace (single list item containing "abc"):

Before lift:                    After lift:
pos 0: <ol>                     pos 0: <p>
pos 1: ├─ <li>   <-- from=1     pos 1: │ a
pos 2: │  ├─ <p>                pos 2: │ b
pos 3: │  │  a                  pos 3: │ c
pos 4: │  │  b                  pos 4: </p>
pos 5: │  │  c
pos 6: │  ├─ </p>
pos 7: ├─ </li>  <-- to=7
pos 8: </ol>

With TextSelection.create: from=1 → 0, to=7 → 4 — both at doc level, selection collapses.
With TextSelection.between: from=3 → 1, to=6 → 4 — both inside paragraph, selection preserved.

Testing Done

Added 3 regression tests verifying that text selection is preserved after toggling off a list with AllSelection:

  • Single-item ordered list
  • Single-item bullet list
  • Multi-item ordered list

Each test asserts exact from and to positions after the toggle operation.

Verification Steps

  1. Open the official example: https://tiptap.dev/docs/editor/extensions/nodes/bullet-list
  2. Clear editor content and type some text
  3. Select all with Ctrl/Cmd+A
  4. Click Bullet List to apply a list
  5. Click the same button again to toggle the list off
  6. Verify that the text selection is preserved (not collapsed to a cursor)

Checklist

  • I have created a changeset for this PR if necessary.
  • My changes do not break the library.
  • I have added tests where applicable.
  • I have followed the project guidelines.
  • I have fixed any lint issues.

Related Issues

Regression from #7683 (fix for #7562)

togswr added 2 commits April 7, 2026 19:05
…election

Verify that text selection is preserved (not collapsed) after toggling
off a list when the entire document is selected via Ctrl+A.

Covers:
- single-item ordered list
- single-item bullet list
- multi-item ordered list
…ection

`createInnerSelectionForWholeDocList()` (introduced in ueberdosis#7683) used
structural boundary positions (from=1, to=list.nodeSize-1) to create
a TextSelection. These positions sit outside inline content, so after
`liftListItem` removes list/item wrappers, `TextSelection.map()` falls
back to `Selection.near()` and collapses the selection.

Replace `TextSelection.create()` with `TextSelection.between()`, which
resolves non-text positions to the nearest valid cursor positions. This
ensures the selection maps correctly through the lift operation and
remains non-empty afterward.

Regression from ueberdosis#7683 (fix for ueberdosis#7562).
Copilot AI review requested due to automatic review settings April 7, 2026 10:15
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 7, 2026

🦋 Changeset detected

Latest commit: a74a05c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 72 packages
Name Type
@tiptap/core Patch
@tiptap/extension-audio Patch
@tiptap/extension-blockquote Patch
@tiptap/extension-bold Patch
@tiptap/extension-bubble-menu Patch
@tiptap/extension-code-block-lowlight Patch
@tiptap/extension-code-block Patch
@tiptap/extension-code Patch
@tiptap/extension-collaboration-caret Patch
@tiptap/extension-collaboration Patch
@tiptap/extension-details Patch
@tiptap/extension-document Patch
@tiptap/extension-drag-handle Patch
@tiptap/extension-emoji Patch
@tiptap/extension-file-handler Patch
@tiptap/extension-floating-menu Patch
@tiptap/extension-hard-break Patch
@tiptap/extension-heading Patch
@tiptap/extension-highlight Patch
@tiptap/extension-horizontal-rule Patch
@tiptap/extension-image Patch
@tiptap/extension-invisible-characters Patch
@tiptap/extension-italic Patch
@tiptap/extension-link Patch
@tiptap/extension-list Patch
@tiptap/extension-mathematics Patch
@tiptap/extension-mention Patch
@tiptap/extension-node-range Patch
@tiptap/extension-paragraph Patch
@tiptap/extension-strike Patch
@tiptap/extension-subscript Patch
@tiptap/extension-superscript Patch
@tiptap/extension-table-of-contents Patch
@tiptap/extension-table Patch
@tiptap/extension-text-align Patch
@tiptap/extension-text-style Patch
@tiptap/extension-text Patch
@tiptap/extension-twitch Patch
@tiptap/extension-typography Patch
@tiptap/extension-underline Patch
@tiptap/extension-unique-id Patch
@tiptap/extension-youtube Patch
@tiptap/extensions Patch
@tiptap/html Patch
@tiptap/markdown Patch
@tiptap/react Patch
@tiptap/starter-kit Patch
@tiptap/static-renderer Patch
@tiptap/suggestion Patch
@tiptap/vue-2 Patch
@tiptap/vue-3 Patch
@tiptap/extension-drag-handle-react Patch
@tiptap/extension-drag-handle-vue-2 Patch
@tiptap/extension-drag-handle-vue-3 Patch
@tiptap/extension-bullet-list Patch
@tiptap/extension-ordered-list Patch
@tiptap/extension-list-item Patch
@tiptap/extension-list-keymap Patch
@tiptap/extension-task-item Patch
@tiptap/extension-task-list Patch
@tiptap/extension-table-cell Patch
@tiptap/extension-table-header Patch
@tiptap/extension-table-row Patch
@tiptap/extension-color Patch
@tiptap/extension-font-family Patch
@tiptap/extension-character-count Patch
@tiptap/extension-dropcursor Patch
@tiptap/extension-focus Patch
@tiptap/extension-gapcursor Patch
@tiptap/extension-history Patch
@tiptap/extension-placeholder Patch
@tiptap/pm Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@netlify
Copy link
Copy Markdown

netlify bot commented Apr 7, 2026

Deploy Preview for tiptap-embed ready!

Name Link
🔨 Latest commit a74a05c
🔍 Latest deploy log https://app.netlify.com/projects/tiptap-embed/deploys/69d4dc40931eb7000797f00b
😎 Deploy Preview https://deploy-preview-7718--tiptap-embed.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes a regression in @tiptap/core list toggling where turning off a top-level list while the selection is an AllSelection (Ctrl/Cmd+A) caused the selection to collapse after lifting, which in turn makes UI like BubbleMenu disappear.

Changes:

  • Update the internal “normalize AllSelection into the list” helper to use TextSelection.between(...) so boundary positions resolve into valid inline positions and survive mapping through liftListItem.
  • Add regression tests for ordered/bullet lists (single-item and multi-item) verifying selection preservation after toggling off with AllSelection.
  • Add a changeset for a @tiptap/core patch release.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
packages/core/src/commands/toggleList.ts Adjusts the AllSelection normalization selection creation to avoid collapsing after lift/mapping.
packages/extension-list/__tests__/taskItem.spec.ts Adds regression coverage for selection preservation when toggling off lists with AllSelection.
.changeset/fix-togglelist-allselection-selection.md Declares a patch changeset for the user-facing selection preservation fix.

Add explicit assertions that selectAll() produces an AllSelection
(from === 0, to === doc.content.size) before the toggle operation,
matching the pattern used in existing tests.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants