-
Notifications
You must be signed in to change notification settings - Fork 118
fix: table gap clicks selecting wrong paragraph and jumping scroll (SD-2356) #2707
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -189,6 +189,14 @@ export function clickToPositionDom(domContainer: HTMLElement, clientX: number, c | |
| return resolveLineAtX(hitChainLine, clientX); | ||
| } | ||
|
|
||
| if (fragmentEl.classList.contains(CLASS.tableFragment)) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. when a table splits across pages, the container here can hold lines from all pages of that table. so tested with both customer docs, the jump still happens. could you scope this to only lines within the current page fragment? |
||
| const scopedContainer = findScopedLineContainer(hitChain, fragmentEl); | ||
| if (scopedContainer) { | ||
| log('Resolving table click from scoped line container'); | ||
| return resolveLineInContainer(scopedContainer, clientX, clientY); | ||
| } | ||
| } | ||
|
|
||
| // For table fragments without a direct line hit, defer to geometry | ||
| // (hitTestTableFragment resolves the correct cell by column). | ||
| if (fragmentEl.classList.contains(CLASS.tableFragment)) { | ||
|
|
@@ -278,6 +286,18 @@ function resolveFragment(fragmentEl: HTMLElement, viewX: number, viewY: number): | |
| return resolveLineAtX(lineEl, viewX); | ||
| } | ||
|
|
||
| function resolveLineInContainer(containerEl: HTMLElement, viewX: number, viewY: number): number | null { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this function is the same as |
||
| const lineEls = Array.from(containerEl.querySelectorAll(`.${CLASS.line}`)) as HTMLElement[]; | ||
| if (lineEls.length === 0) { | ||
| return null; | ||
| } | ||
|
|
||
| const lineEl = findLineAtY(lineEls, viewY); | ||
| if (!lineEl) return null; | ||
|
|
||
| return resolveLineAtX(lineEl, viewX); | ||
| } | ||
|
|
||
| /** | ||
| * Given a known line element, resolves the PM position at the given X | ||
| * coordinate. | ||
|
|
@@ -364,12 +384,21 @@ function resolvePositionInLine( | |
| function findLineAtY(lineEls: HTMLElement[], viewY: number): HTMLElement | null { | ||
| if (lineEls.length === 0) return null; | ||
|
|
||
| let nearest: HTMLElement = lineEls[0]; | ||
| let minDistance = Infinity; | ||
|
|
||
| for (const lineEl of lineEls) { | ||
| const r = lineEl.getBoundingClientRect(); | ||
| if (viewY >= r.top && viewY <= r.bottom) return lineEl; | ||
|
|
||
| const distance = viewY < r.top ? r.top - viewY : Math.max(0, viewY - r.bottom); | ||
| if (distance < minDistance) { | ||
| minDistance = distance; | ||
| nearest = lineEl; | ||
| } | ||
| } | ||
|
|
||
| return lineEls[lineEls.length - 1]; | ||
| return nearest; | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -397,6 +426,19 @@ function findSpanAtX(spanEls: HTMLElement[], viewX: number): HTMLElement | null | |
| return nearest; | ||
| } | ||
|
|
||
| function findScopedLineContainer(hitChain: Element[], fragmentEl: HTMLElement): HTMLElement | null { | ||
| for (const el of hitChain) { | ||
| if (!(el instanceof HTMLElement)) continue; | ||
| if (el === fragmentEl) break; | ||
| if (!fragmentEl.contains(el)) continue; | ||
| if (el.querySelector(`.${CLASS.line}`)) { | ||
| return el; | ||
| } | ||
| } | ||
|
|
||
| return null; | ||
| } | ||
|
|
||
| // --------------------------------------------------------------------------- | ||
| // Character-level position resolution | ||
| // --------------------------------------------------------------------------- | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this path never fires during manual testing — the table extends into the margin area, so margin clicks get resolved as table hits instead of reaching here.