fix^(live-preview^)^: place caret at click point inside table cells#142
Open
zhenyu666-debug wants to merge 5 commits into
Open
fix^(live-preview^)^: place caret at click point inside table cells#142zhenyu666-debug wants to merge 5 commits into
zhenyu666-debug wants to merge 5 commits into
Conversation
|
Cursor Agent seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account. You have signed the CLA already but the status is still pending? Let us recheck it. |
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.
PR: fix(live-preview): place caret at click point inside table cells
PR title (Conventional Commits):
Scope
live-preview=packages/core/src/live-preview-table.ts.Summary / 摘要
Clicking inside a table cell now lands the caret at the clicked character
boundary instead of snapping to the cell origin or to the styled
wrapper's mapped start offset (e.g.
<strong>重点菜单</strong>).点击表格单元格任意位置,光标会落在被点击的字符边界,而不是被强制
吸到单元格起点或样式包裹元素(如
<strong>)的内嵌文本起点。Motivation / 背景与动机
A user clicking in the middle of a Chinese cell rendered with inline
markup (
**重点菜单**,[*重点菜单*](url),`Ctrl+Z`) saw thecaret jump to either the very start of the cell or to the start offset
of the inner wrapped Text node — never to the actual character boundary
they clicked on. Three independent paths contributed to the wrong caret
position:
rawSourceOffsetFromPointcollapsed every left-half click on a styledcell to the mapped start of the inner Text (e.g. raw offset 2 for
**重点菜单**) because sub-rect fallback only handled non-TextoffsetNodes, and the sub-rect path was applied unconditionally.
placeRawSourceCaretbailed out as soon astd.firstChildwas anElement instead of a Text — every styled cell silently dropped the
caret.
The Enter-into-edit-mode closure ran twice (once from the click
handler, once from the focus listener) and the second call's
td.textContent = srctore down the range that the first call hadjust placed.
Issue: addresses the user-reported "点 cell 中间光标跳到最前" symptom
Roadmap (docs/ROADMAP.md): live-preview stability / cell interaction
OpenSpec change: n/a (bug fix, no new capability)
Changes / 变更内容
packages/core:rawSourceOffsetFromPoint: gate sub-rect hit-testing behindapiTextHit— when the browser API already returns a Text node wetrust caretPos directly (more accurate for CJK / monospace), and
only fall back to sub-rect when the API returns a wrapper Element
(
<strong>,<em>,<del>,<a>,<code>).rawSourceOffsetFromCaret: walk up the parent chain to find thenearest registered source range, instead of only looking at the
container's own child slots. The first-iteration hit is unchanged
for the common Text case; the fallback covers the rare wrapper case.
placeRawSourceCaret: use a TreeWalker to find the first descendantText instead of
td.firstChild, so styled cells get a concreteanchor and the caret lands at the requested raw offset.
EditableTableWidget.enterEditModeclosure: idempotent guard — ifthe cell already holds the raw source as a single Text node we skip
the destructive
textContentswap that was destroying the just-placed range.
packages/plugin-*: no changesapps/electron-demo: no changes (manual testing was done in aseparate scratch branch, not included in this PR)
openspec/: no changesTesting / 测试
pnpm testpasses / 全绿vitest run packages/core/test/live-preview.test.ts→ 70/70pnpm build) / 受影响包构建通过tsc --noEmit -p packages/core/tsconfig.json→ 0 errorsThe existing suite already covers the click → caret path
indirectly; the fix is observable in the demo (see "Manual UI
check" below). Adding two pinpoint unit assertions for
placeRawSourceCaretwith a styled cell is tracked separately asa follow-up; intentionally out of scope for this minimal-change
PR.
- Click middle of plain text cell → caret at clicked character ✓
- Click inside
**重点菜单**→ caret at clicked character ✓- Click inside
[重点菜单](url)→ caret at clicked character ✓- Click inside
`Ctrl+Z`→ caret at clicked character ✓- IME / drag-select / search highlight (covered by prior PRs)
unchanged.
Compliance / 合规自检
primarily generated by AI. AI assistance was used to draft the
ancestor-walk refactor of
rawSourceOffsetFromCaretand todraft the comment block explaining why sub-rect hit-testing is
gated behind
apiTextHit. The bug reproductions and the manualverification were done by the human contributor.
AI-assisted notes / AI 使用说明:
- ancestor walk in
rawSourceOffsetFromCaret— AI-draftedrefactor of the original children-walk fallback
-
[Fix-A]comment inrawSourceOffsetFromPoint— AI-draftedexplanation of why we trust the API over sub-rect for Text nodes
none
.env/ personal vault data committedChecklist / 自检清单
changed; all four edits are inside
live-preview-table.tsandkeep the existing widget behaviour observable from outside
live-preview-table.ts→ walked through the 12 TableWidget rules in CLAUDE.md:
1. source round-trip — unchanged, no edits to markdown parsing
2-7. (cell focus / editing / IME / selection) — IME path
unaffected; selection path was re-confirmed via the manual
checklist above
8. read-only mode toggle — unaffected
9. multi-cell selection across the table — unaffected (only
single-cell click path changed)
10. undo/redo — unaffected
11. copy/paste — unaffected
12. fixture parity with prosemirror-tables — unaffected
(bug fix, no new capability)
widget caret placement is core scope
Screenshots / Recordings · 截图或录屏 (UI changes)
Before: clicking mid-cell snaps caret to cell origin or styled-wrapper
start.
After: caret lands at the clicked character boundary in plain text,
strong,em,link, and inline-code cells alike.Manual probe data captured during development:
(See scratch branch
fix/table-search-highlightwhich carried thediagnostics harness; not part of this PR.)