Skip to content

Commit 271f04a

Browse files
authored
Merge pull request #4931 from udecode/codex/table-shift-arrow-eager-selection-2
2 parents 304b876 + 41ee45a commit 271f04a

13 files changed

Lines changed: 652 additions & 293 deletions

.changeset/funny-years-arrive.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@platejs/table": patch
3+
---
4+
5+
Fix `Shift+Arrow` table selection to switch cells without showing a transient native range
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Table Shift Arrow Eager Selection
2+
3+
## Goal
4+
5+
Remove the transient native text-range flash when `Shift+Arrow` expands from one table cell into another.
6+
7+
## Plan
8+
9+
- [completed] Add keydown-level regression coverage for eager single-cell `Shift+Arrow`.
10+
- [completed] Route single-cell `Shift+Arrow` through table-owned selection movement before native selection applies.
11+
- [completed] Remove `withApplyTable` repair behavior and delete `overrideSelectionFromCell`.
12+
- [completed] Update coverage and docs to reflect keydown-only ownership.
13+
- [completed] Run focused tests, package build, typecheck, lint.
14+
15+
## Findings
16+
17+
- Multi-cell `Shift+Arrow` already goes through `onKeyDownTable`.
18+
- Single-cell cross-cell expansion still waits for `set_selection` and `setTimeout`, which causes visible flash.
19+
- The quick fix is to take ownership in `onKeyDownTable` for the one-cell boundary-crossing case too.
20+
- `overrideSelectionFromCell` is now a redundant apply-time fallback unless a real non-keydown caller still depends on it.
21+
22+
## Progress
23+
24+
- Created plan for eager single-cell `Shift+Arrow` interception.
25+
- Added `onKeyDownTable` coverage for eager single-cell `Shift+Down` and `Shift+Right`.
26+
- Extracted the visual-line boundary check into a shared helper so plain arrows and shifted arrows use the same vertical edge rule.
27+
- Routed one-cell cross-cell `Shift+Arrow` through `onKeyDownTable` before native selection applies.
28+
- Removed the apply-time fallback and deleted `overrideSelectionFromCell` plus its dedicated tests.
29+
- Added a package changeset and a solution doc for the timing seam.
30+
- Follow-up refactor: extracted shared single-cell table movement context and adjacent-block checks used by both `moveLine` and `onKeyDownTable`.
31+
- Follow-up tests: added `Shift+Up`, `Shift+Left`, and multi-cell `Shift+Right` keydown coverage.
32+
33+
## Verification
34+
35+
- `bun test packages/table/src/react/onKeyDownTable.spec.tsx`
36+
- `bun test packages/table/src/react/onKeyDownTable.spec.tsx packages/table/src/lib/withApplyTable.spec.ts packages/table/src/lib/withTable.spec.tsx packages/table/src/lib/transforms/moveSelectionFromCell.spec.tsx`
37+
- `pnpm install`
38+
- `pnpm turbo build --filter=./packages/table`
39+
- `pnpm turbo typecheck --filter=./packages/table`
40+
- `pnpm lint:fix`
41+
- `bun test packages/table/src/react/onKeyDownTable.spec.tsx`
42+
- `bun test packages/table/src/lib/withTable.spec.tsx packages/table/src/lib/transforms/shouldMoveSelectionFromCell.spec.ts packages/table/src/lib/transforms/moveSelectionFromCell.spec.tsx packages/table/src/lib/withApplyTable.spec.ts`
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
---
2+
module: Table
3+
date: 2026-03-31
4+
problem_type: logic_error
5+
component: editor_transforms
6+
symptoms:
7+
- "Shift+Arrow from one table cell into another briefly showed a native text range before cell selection took over"
8+
- "Cross-cell Shift+Down and Shift+Right felt delayed even though the final cell selection was correct"
9+
root_cause: async_timing
10+
resolution_type: code_fix
11+
severity: medium
12+
tags:
13+
- table
14+
- selection
15+
- keyboard
16+
- shift-arrow
17+
- timing
18+
- keydown
19+
- slate
20+
---
21+
22+
# Table Shift+Arrow selection must own keydown before native selection
23+
24+
## Problem
25+
26+
Single-cell `Shift+Arrow` expansion across table cell boundaries produced the correct final cell selection, but only after a visible intermediate native range.
27+
28+
The flash was most obvious on `Shift+Down` and `Shift+Right`, where the browser first painted a normal text selection and table code repaired it one tick later.
29+
30+
## Root cause
31+
32+
Table selection only owned multi-cell `Shift+Arrow` at keydown time.
33+
34+
The one-cell case relied on apply-time repair after native selection had already moved once, which produced a visible intermediate text range.
35+
36+
## Fix
37+
38+
Take ownership of the one-cell boundary-crossing case in `onKeyDownTable` before native selection applies, and remove the apply-time repair path.
39+
40+
- Keep the existing eager multi-cell `Shift+Arrow` path.
41+
- Add a one-cell path that checks whether the moving focus edge is about to leave the current cell.
42+
- For `Shift+Up` and `Shift+Down`, reuse the same visual-line boundary logic as plain `moveLine`.
43+
- For `Shift+Left` and `Shift+Right`, only intercept when the focus is already at the cell start or end.
44+
- When the boundary test passes, call `moveSelectionFromCell(..., { fromOneCell: true })` immediately and prevent the native event.
45+
- Delete `overrideSelectionFromCell` and stop calling it from `withApplyTable`.
46+
47+
That moves the ownership seam fully to keydown-time interception.
48+
49+
## Verification
50+
51+
These checks passed:
52+
53+
```bash
54+
bun test packages/table/src/react/onKeyDownTable.spec.tsx packages/table/src/lib/withApplyTable.spec.ts packages/table/src/lib/withTable.spec.tsx packages/table/src/lib/transforms/moveSelectionFromCell.spec.tsx
55+
pnpm install
56+
pnpm turbo build --filter=./packages/table
57+
pnpm turbo typecheck --filter=./packages/table
58+
pnpm lint:fix
59+
```
60+
61+
The new coverage proves:
62+
63+
- `onKeyDownTable.spec.tsx` eagerly expands `Shift+Down` and `Shift+Right` from one cell into the adjacent cell
64+
- `onKeyDownTable.spec.tsx` keeps `Shift+Down` native while the focus can still move within the current multi-block cell
65+
66+
## Prevention
67+
68+
If a keyboard interaction should never show an intermediate native selection state, do not repair it later in `apply`.
69+
70+
Own it at the keydown seam instead of carrying a second repair path that can drift from the real behavior.
71+
72+
When plain-arrow and shifted-arrow movement share the same visual boundary rule, put that boundary check in one helper so the two seams cannot drift.
73+
74+
## Related Issues
75+
76+
- Related learning: [2026-03-29-table-arrow-navigation-must-own-moveline-and-visual-line-boundaries.md](/Users/hyeongjin/Workspace/plate/.claude/docs/solutions/logic-errors/2026-03-29-table-arrow-navigation-must-own-moveline-and-visual-line-boundaries.md)

packages/table/src/lib/transforms/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ export * from './insertTable';
99
export * from './insertTableColumn';
1010
export * from './insertTableRow';
1111
export * from './moveSelectionFromCell';
12-
export * from './overrideSelectionFromCell';
1312
export * from './setBorderSize';
1413
export * from './setCellBackground';
1514
export * from './setTableColSize';
1615
export * from './setTableMarginLeft';
1716
export * from './setTableRowSize';
17+
export * from './shouldMoveSelectionFromCell';

packages/table/src/lib/transforms/overrideSelectionFromCell.spec.tsx

Lines changed: 0 additions & 148 deletions
This file was deleted.

packages/table/src/lib/transforms/overrideSelectionFromCell.ts

Lines changed: 0 additions & 61 deletions
This file was deleted.

0 commit comments

Comments
 (0)