From 953ba35260413ffa0c124e7d86b3071fd4e885d7 Mon Sep 17 00:00:00 2001 From: Jorge Acosta <61467132+JLAcostaEC@users.noreply.github.com> Date: Mon, 22 Jun 2026 11:00:56 -0400 Subject: [PATCH] feat: replace root `manageEscape` and `manageHomeEnd` with a single `manageSpecialKeys` option. --- .changeset/stale-swans-take.md | 12 +++++++++++ README.md | 13 ++++++------ src/enums.ts | 8 ++++++++ src/navigation.ts | 25 ++++++++++++++--------- src/parser.ts | 27 ++++++++++++++++++++++--- src/tests/fixtures/context.ts | 7 +++---- src/tests/grid.test.ts | 2 +- src/tests/parser.test.ts | 37 ++++++++++++++++++++++++++++++---- src/types.ts | 12 ++++++++--- 9 files changed, 113 insertions(+), 30 deletions(-) create mode 100644 .changeset/stale-swans-take.md diff --git a/.changeset/stale-swans-take.md b/.changeset/stale-swans-take.md new file mode 100644 index 0000000..20d4728 --- /dev/null +++ b/.changeset/stale-swans-take.md @@ -0,0 +1,12 @@ +--- +"tabspot": minor +--- + +feat: replace root `manageEscape` and `manageHomeEnd` with a single `manageSpecialKeys` option. + +`manageSpecialKeys` accepts either a boolean (`true` handles all special keys) or a per-key object toggling `Escape`, `Home`, `End`, `PageUp`, and `PageDown` individually. Keys use the exact `KeyboardEvent.key` strings; omitted keys default to off. + +Migration: +- `{ manageEscape: true }` → `{ manageSpecialKeys: { Escape: true } }` +- `{ manageHomeEnd: true }` → `{ manageSpecialKeys: { Home: true, End: true, PageUp: true, PageDown: true } }` +- both true → `{ manageSpecialKeys: true }` \ No newline at end of file diff --git a/README.md b/README.md index 8055912..d55c5d7 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ const nav = document.querySelector("#main-nav")!; setTabspotAttributes({ element: nav, config: { - root: { manageEscape: true, manageHomeEnd: true }, + root: { manageSpecialKeys: true }, mover: { axis: "vertical", cyclic: true }, }, }); @@ -60,7 +60,7 @@ For SSR use `getTabspotAttributes`, it returns the attributes to be rendered on import { getTabspotAttributes } from "tabspot"; const attrs = getTabspotAttributes({ - root: { manageEscape: true, manageHomeEnd: true }, + root: { manageSpecialKeys: true }, mover: { axis: "vertical", cyclic: true }, }); @@ -88,8 +88,9 @@ Every element configured with Tabspot carries a single `data-tabspot` attribute ```ts interface TabspotNodeOptions { root?: { - manageEscape?: boolean; - manageHomeEnd?: boolean; // Home/End/PageUp/PageDown/Ctrl+Home/Ctrl+End + // true = handle all; or toggle each key. Esc exits; the rest jump. + manageSpecialKeys?: boolean | Partial>; + // RootSpecialKey = "Escape" | "Home" | "End" | "PageUp" | "PageDown" rtl?: "auto" | "ltr" | "rtl"; debug?: "basic" | "full"; }; @@ -131,7 +132,7 @@ type Activation = ### Levels and transitions - **Mover**: its children stay at the parent's level. A linear Mover carries the axis + cyclic behavior for in-axis moves. -- **Grouper** opens a new level (`level + 1`). Enter via `grouper.enterDirection` from a sibling, or any cross-axis arrow when the grouper is implicit. Exit via `grouper.exitDirection` (gated by first/last + `enterExitOnLast`) or `Escape` (if `manageEscape`). +- **Grouper** opens a new level (`level + 1`). Enter via `grouper.enterDirection` from a sibling, or any cross-axis arrow when the grouper is implicit. Exit via `grouper.exitDirection` (gated by first/last + `enterExitOnLast`) or `Escape` (if `manageSpecialKeys.Escape`). - A focusable that declares its own `mover` synthesizes an `implicit grouper` underneath. ## Grid movers (`layout: "grid"`) @@ -151,7 +152,7 @@ A grid mover navigates its items as a 2-D matrix: **both** axes move. Rows are d - **`flow: "contained"`** (default) — `ArrowLeft|Right` move within the current row; `ArrowUp|Down` within the column. Clamps at every edge. - **`flow: "linear"`** — vertical is identical, but `ArrowLeft|Right` traverse the whole row-major sequence (end of a row continues into the next), clamping only at the global first/last cell. - `cyclic: true` wraps within the row/column (or around the whole sequence for `flow: "linear"`). -- **Keys** (with `manageHomeEnd`): `Home`/`End` → start/end of the current row; `Ctrl+Home`/`Ctrl+End` → first/last cell of the grid; `PageUp`/`PageDown` → ±`pageSize` rows (default 5). +- **Keys** (gated per-key by `manageSpecialKeys`): `Home`/`End` → start/end of the current row; `Ctrl+Home`/`Ctrl+End` → first/last cell of the grid; `PageUp`/`PageDown` → ±`pageSize` rows (default 5). - Row strategies handle markup `parent`-grouping can't: `{by:"selector",row:"tr"}` for `