docs/plans/2026-05-25-slate-v2-editable-void-keyboard-click-navigation.md
Objective: Add focused Playwright coverage for click plus keyboard navigation in the editable-void example's same-runtime child root, reproduce the boundary bug, fix the example/schema ownership, and close only when focused browser, package/site, lint, and review gates pass.
Goal plan: docs/plans/2026-05-25-slate-v2-editable-void-keyboard-click-navigation.md
Template: docs/plans/templates/task.md
Applied packs:
Task source:
Completion threshold:
node .agents/rules/autogoal/scripts/check-complete.mjs docs/plans/2026-05-25-slate-v2-editable-void-keyboard-click-navigation.md
passes.Verification surface:
.tmp/slate-v2 Playwright editable-voids route..tmp/slate-v2 site typecheck..tmp/slate-v2 Slate React focused contract tests..tmp/slate-v2 lint..tmp/slate-v2 autoreview local diff.Constraints:
Boundaries:
.tmp/slate-v2 editable-voids example, Playwright test,
and only the runtime code needed if tests prove runtime ownership is wrong.site/examples/ts/editable-voids.tsx through
playwright/integration/examples/editable-voids.test.ts.Blocked condition:
Task state:
Current verdict:
contentRoot, so the navigation bridge ignored it. The example now opts the
editable-void body into contentRoot: { slot: 'body' }, while native
controls remain wrapped in contentEditable={false}.Work Checklist:
.tmp/slate-v2.Completion Gates:
| Gate | Applies | Evidence |
|---|---|---|
| Bug reproduced before fix | yes | New boundary Playwright row failed before the fix: child-root selection stayed null after ArrowRight from the previous sibling into the mixed editable void. |
| Targeted behavior verification | yes | Focused new-row rerun passed: PLAYWRIGHT_RETRIES=0 bun run playwright playwright/integration/examples/editable-voids.test.ts --project=chromium -g "child-root (arrow navigation usable after clicks|boundaries with keyboard)", 2 passed. |
| Full browser route proof | yes | PLAYWRIGHT_RETRIES=0 bun run playwright playwright/integration/examples/editable-voids.test.ts --project=chromium, 19 passed with fresh Next build. |
| TypeScript / typed config | yes | bun typecheck:site passed. |
| Focused package tests | yes | bun --filter ./packages/slate-react test:vitest -- content-root-navigation-contract selection-controller-contract keyboard-input-strategy-contract, 32 passed. |
| Lint | yes | bun lint passed after Biome formatting. |
| Package behavior / public API changed | no | N/A: this slice changed example schema usage and Playwright tests only; no package exports or published API changed. |
| Autoreview | yes | /Users/zbeyens/git/plate-2/.agents/skills/autoreview/scripts/autoreview --mode local passed with no accepted/actionable findings. |
| PR / tracker sync | no | N/A: user did not ask for PR/tracker work. |
| Goal plan complete | yes | Final checker must pass before goal close. |
Phase / pass table:
| Phase | Status | Evidence | Next |
|---|---|---|---|
| Intake and source read | complete | User request identified missing keyboard/click navigation coverage in editable-void example. Existing tests/source read for child-root click, editor-only content-root navigation, and example schema. | implementation |
| Repro test | complete | Added mixed editable-void boundary Playwright row; focused run failed before the fix because child-root selection stayed null after outer ArrowRight. | fix |
| Implementation | complete | Added contentRoot: { slot: 'body' } to the example's editable-void schema entry and kept native controls noneditable. | verification |
| Verification | complete | Focused rows, full route, typecheck, lint, focused unit tests, and autoreview passed. | closeout |
| Closeout | complete | Final evidence and reboot state recorded; checker rerun pending. | final response |
Implementation notes:
keeps same-runtime child-root arrow navigation usable after clicks.moves across editable void child-root boundaries with keyboard.ArrowRight from the paragraph before the mixed
editable void did not enter the void child root.{
type: 'editable-void',
contentRoot: { slot: 'body' },
void: 'editable-island',
}
Design:
editable-island roots into navigation would
make native-control islands behave like document flow without an explicit
contract.contentRoot; the bug was the example failing to declare the slot.Final handoff contract:
Timeline:
contentRoot: { slot: 'body' } to the editable-void
example spec.Open risks:
Verification evidence:
.tmp/slate-v2 focused Playwright row
moves across editable void child-root boundaries with keyboard failed before
the fix with expected child-root selection [0,0] offset 0 but received
null..tmp/slate-v2
PLAYWRIGHT_RETRIES=0 bun run playwright playwright/integration/examples/editable-voids.test.ts --project=chromium -g "child-root (arrow navigation usable after clicks|boundaries with keyboard)"
passed, 2 tests..tmp/slate-v2
PLAYWRIGHT_RETRIES=0 bun run playwright playwright/integration/examples/editable-voids.test.ts --project=chromium
passed, 19 tests..tmp/slate-v2 bun typecheck:site passed..tmp/slate-v2
bun --filter ./packages/slate-react test:vitest -- content-root-navigation-contract selection-controller-contract keyboard-input-strategy-contract
passed, 32 tests..tmp/slate-v2 bun lint passed..tmp/slate-v2
/Users/zbeyens/git/plate-2/.agents/skills/autoreview/scripts/autoreview --mode local
passed with no accepted/actionable findings.Reboot status:
| Question | Answer |
|---|---|
| Where am I? | Closeout complete. |
| Where am I going? | Final response after checker and goal close. |
| What is the goal? | Add Playwright keyboard/click navigation coverage for editable-void child roots, fix reproduced bugs, and verify. |
| What have I learned? | Basic arrowing inside an already focused child root worked; boundary navigation into the mixed editable void failed because the example child root was not declared as a content root. |
| What have I done? | Added two Playwright rows, declared editable-void body as contentRoot, verified browser/site/unit/lint/review gates. |