Repository navigation
fix(muyajs): split correct paragraph on Enter in multi-block list items (#4374) - #4376
Conversation
…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>
|
Build artifacts for PR #4376: Run: https://github.com/marktext/marktext/actions/runs/27060186503
|
There was a problem hiding this comment.
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
chopBlockByCursorto 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.
| @@ -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 | |||
- 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>
…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)

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:
Root cause
enterHandlerwalksblockup from<p>to the parent<li>and then callschopBlockByCursor(li.children[0], start.key, …)(or[1]for task lists), assuming the active line isli.children[0]. When thelicontains[p, ul, p]/[p1, p2]/[input, p1, p2]and the caret is in any paragraph other than the first,findIndexreturns-1andchildren[-1].nextSibling = nullthrows.Fix
packages/muyajs/lib/contentState/enterCtrl.js:activeParagraphBlockbefore the<p> → <li>promotion so we still know which paragraph owns the caret.type === 'li'switch branch, find that paragraph's index insideli.childrenand split it (replaces the hard-codedchildren[0]/children[1]lookup). Fall back to the historical index when not found so single-paragraph items behave exactly as before.liso split semantics preserve continuation order.if (index === -1) return newBlockinsidechopBlockByCursor— same null-guard style as Unexpected error with message Cannot destructure property 'bulletMarkerOrDelimiter' of 'block2.children[0]' as it is undefined. #4346 /<pre>test</pre>in typewriter mode breaks input #2800.Reproduction (manual)
second paragraph, press Enter → crash on the currentdevelop, no crash with this PR.Test plan
New regression spec
packages/desktop/test/e2e/issue-4374.spec.tscovers:Adjacent regression suites stayed green:
issue-4346,issue-4328,issue-2800,paragraph-blocks(26/26 passed).pnpm run lint0 errors,pnpm run typecheckclean.🤖 Generated with Claude Code