fix(muyajs): split correct paragraph on Enter in multi-block list items (#4374) by Jocs · Pull Request #4376 · marktext/marktext · GitHub
Skip to content

fix(muyajs): split correct paragraph on Enter in multi-block list items (#4374) - #4376

Merged
Jocs merged 2 commits into
developfrom
fix/4374-enter-handler-loose-list
Jun 6, 2026
Merged

Jocs merged 2 commits into
developfrom
fix/4374-enter-handler-loose-list

Conversation

@Jocs

@Jocs Jocs commented Jun 6, 2026

Copy link
Copy Markdown
Member

Summary

Fixes #4374. Pressing Enter in a list item that holds multiple content blocks — e.g. a loose list with two paragraphs per item, a list with a nested sublist followed by a trailing paragraph, or a task item with a trailing paragraph — crashed the renderer with:

TypeError: Cannot set properties of undefined (setting 'nextSibling')
    at ContentState.chopBlockByCursor (packages/muyajs/lib/contentState/enterCtrl.js)
    at ContentState.enterHandler   (packages/muyajs/lib/contentState/enterCtrl.js)

Root cause

enterHandler walks block up from <p> to the parent <li> and then calls chopBlockByCursor(li.children[0], start.key, …) (or [1] for task lists), assuming the active line is li.children[0]. When the li contains [p, ul, p] / [p1, p2] / [input, p1, p2] and the caret is in any paragraph other than the first, findIndex returns -1 and children[-1].nextSibling = null throws.

Fix

packages/muyajs/lib/contentState/enterCtrl.js:

Reproduction (manual)

  1. Source mode → paste:
    - first paragraph
    
      second paragraph
    
  2. Switch back to WYSIWYG, place caret in second paragraph, press Enter → crash on the current develop, no crash with this PR.

Test plan

New regression spec packages/desktop/test/e2e/issue-4374.spec.ts covers:

  • Enter inside the second paragraph of a loose list item
  • Enter in the trailing paragraph of a task list item
  • Enter in a paragraph after a nested sublist inside a loose item
  • Enter mid-paragraph in the second paragraph of a loose list item
  • Enter at end of a single-paragraph list item still creates a new item (behavior-preservation sanity check)

Adjacent regression suites stayed green: issue-4346, issue-4328, issue-2800, paragraph-blocks (26/26 passed). pnpm run lint 0 errors, pnpm run typecheck clean.

🤖 Generated with Claude Code

…ms (#4374)

enterHandler walked up from <p> to the parent <li> and then called
chopBlockByCursor(li.children[0], start.key, ...) — assuming the active
line lives in li.children[0] (or [1] for task lists). For loose lists,
items with nested sublists, or task items with trailing paragraphs the
caret's span is not under children[0], so findIndex returned -1 and the
next statement crashed on `children[-1].nextSibling = null`.

Capture the active paragraph before the block→li promotion, look it up
in li.children, and migrate the blocks after it (sublist and/or trailing
paragraphs) into the new li so split semantics preserve order. Added a
defensive `index === -1` early return inside chopBlockByCursor.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 6, 2026 •

Copy link
Copy Markdown
Contributor

@github-actions

github-actions Bot commented Jun 6, 2026 •

Copy link
Copy Markdown
Contributor

Build artifacts for PR #4376:

Run: https://github.com/marktext/marktext/actions/runs/27060186503

Artifact Size Link
marktext-windows-arm64 249.6 MB Download
marktext-macos-x64 249.2 MB Download
marktext-linux 540.7 MB Download
marktext-windows-x64 250.9 MB Download
marktext-macos-arm64 238.9 MB Download

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 Muyajs renderer crash when pressing Enter inside list items that contain multiple content blocks (e.g., multiple paragraphs per <li>, nested sublists followed by trailing paragraphs, task items with trailing paragraphs). The change updates enterHandler to split the actual paragraph containing the caret and to preserve list-item continuation structure, and adds an e2e regression suite.

Changes:

  • Add a defensive guard in chopBlockByCursor to avoid crashing when the target key can’t be found.
  • Update list-item Enter handling to split the caret-owning paragraph within <li> and move trailing children into the newly created <li>.
  • Add Playwright e2e regression coverage for issue #4374 scenarios.

Reviewed changes

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

File Description
packages/muyajs/lib/contentState/enterCtrl.js Fix list-item Enter splitting to target the correct paragraph and preserve trailing children; add guard to prevent nextSibling crash.
packages/desktop/test/e2e/issue-4374.spec.ts Add e2e regression tests covering multi-block list-item Enter behavior and non-crash expectations.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +23 to +31
@@ -24,6 +24,11 @@ const enterCtrl = (ContentState) => {
const newBlock = this.createBlock('p')
const { children } = block
const index = children.findIndex((child) => child.key === key)
// Defensive guard for issue #4374: when the caller resolves the wrong
// owning paragraph (e.g. a list item with multiple paragraphs), `key`
// isn't in `children`. Return an empty continuation block instead of
// crashing on `children[-1].nextSibling = null`.
if (index === -1) return newBlock
Comment on lines +134 to +138
- chopBlockByCursor: return a well-formed empty paragraph via
  createBlockP('') in the index === -1 guard, so downstream code that
  assumes p.children[0] exists keeps the invariant.
- issue-4374 spec: assert one extra <li> is rendered after splitting a
  single-paragraph list item, so the sanity check catches functional
  regressions (not just crashes).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Jocs
Jocs merged commit 5694eed into develop Jun 6, 2026
11 checks passed
@Jocs
Jocs deleted the fix/4374-enter-handler-loose-list branch June 10, 2026 07:08
hisaboh pushed a commit to hisaboh/remarks that referenced this pull request Jun 11, 2026
…ms (marktext#4374) (marktext#4376)

* fix(muyajs): split correct paragraph on Enter in multi-block list items (marktext#4374)

enterHandler walked up from <p> to the parent <li> and then called
chopBlockByCursor(li.children[0], start.key, ...) — assuming the active
line lives in li.children[0] (or [1] for task lists). For loose lists,
items with nested sublists, or task items with trailing paragraphs the
caret's span is not under children[0], so findIndex returned -1 and the
next statement crashed on `children[-1].nextSibling = null`.

Capture the active paragraph before the block→li promotion, look it up
in li.children, and migrate the blocks after it (sublist and/or trailing
paragraphs) into the new li so split semantics preserve order. Added a
defensive `index === -1` early return inside chopBlockByCursor.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(muyajs): address Copilot review on marktext#4376

- chopBlockByCursor: return a well-formed empty paragraph via
  createBlockP('') in the index === -1 guard, so downstream code that
  assumes p.children[0] exists keeps the invariant.
- issue-4374 spec: assert one extra <li> is rendered after splitting a
  single-paragraph list item, so the sanity check catches functional
  regressions (not just crashes).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
(cherry picked from commit 5694eed)
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.

Unexpected error with message Cannot set properties of undefined (setting 'nextSibling')

2 participants