diff --git a/.pnpm-store/v10/projects/f8319dbbd94c7aa820b9caf9498e7396 b/.pnpm-store/v10/projects/f8319dbbd94c7aa820b9caf9498e7396 new file mode 120000 index 0000000..a8a4f8c --- /dev/null +++ b/.pnpm-store/v10/projects/f8319dbbd94c7aa820b9caf9498e7396 @@ -0,0 +1 @@ +../../.. \ No newline at end of file diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index a73d70c..be96969 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -30,9 +30,13 @@ Run from the repo root: | `pnpm lint` | Checks formatting across the workspace with Prettier. | | `pnpm format` | Rewrites files to Prettier style. | | `pnpm build` | Builds every package. | +| `pnpm bench` | Times `keyRove` in headless Chrome. | | `pnpm typecheck` | Type-checks every package. | | `pnpm preview` | Serves the built docs site. | +The benchmark's method and recorded results are in +[packages/keyrove/bench](packages/keyrove/bench/README.md). + Any script can be aimed at one package with a filter: ```sh @@ -71,6 +75,25 @@ The served markdown is not the file verbatim: frontmatter is site plumbing, so it is replaced by the `title` as an H1 and the `description` as a blockquote, leaving a document that stands on its own when fetched in isolation. +### Documentation search + +The header search button and `Cmd+K` / `Ctrl+K` open a native dialog. MiniSearch +and `search-index.json` load on first use. The index contains docs page leads +and individual sections, with heading IDs allocated by the same parser as the +rendered pages; landing and `noindex` pages are excluded. Titles and headings +rank above body matches, with prefix matching and typo tolerance enabled. + +The results are a keyrove group: the site navigating with its own library. +Each result is a link, `initRovingTabindex` gives the list one tab stop after +every render, `keyRove` moves focus between the links and `followFocus` keeps +the stop in step. keyrove leaves a text field its caret keys, so the box +focuses an end of the list itself to hand focus over, and a character typed on +a result sends focus back to the box. + +The Vite plugin generates the index in development and production. Markdown +edits invalidate the development cache and reload the page, including search. +Run the search indexing tests with `pnpm --filter @mixedrays/keyrove/docs test`. + ### Live demos A content file embeds a demo with `
`. The markup diff --git a/README.md b/README.md index 8592c5b..6ee3038 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,8 @@ [![minzipped size](https://img.shields.io/bundlejs/size/%40mixedrays%2Fkeyrove?color=4f46e5&label=minzipped%20size)](https://bundlejs.com/?q=%40mixedrays%2Fkeyrove) [![license](https://img.shields.io/npm/l/@mixedrays/keyrove?color=4f46e5)](https://github.com/mixedrays/keyrove/blob/main/LICENSE) -Framework-agnostic keyboard navigation for lists, grids and trees, driven by -`data-*` attributes or a plain options object. Any key can move focus — arrows -are only the default — and native Tab navigation keeps working. +Keyboard navigation for lists, grids and trees. Configure it with data +attributes or JavaScript options, in any framework. ## Getting started @@ -31,9 +30,8 @@ import { keyRove } from '@mixedrays/keyrove'; document.querySelector('#menu').addEventListener('keydown', (e) => keyRove(e)); ``` -Where the markup is not yours to change — a component library's menu, a CMS's -output — every attribute has an option of the same name, so the same list can -be described in the call instead: +Use an `items` option when you cannot add attributes to the markup. This +selects the same list items without `data-keyrove-item`; keep their tabindex: ```ts document @@ -41,10 +39,13 @@ document .addEventListener('keydown', (e) => keyRove(e, { items: 'li' })); ``` -`keyRove` takes anything shaped like a keydown event, so React, Vue and Svelte -synthetic events work without an adapter. The -[installation guide](https://keyrove.pages.dev/docs/installation) shows the -wiring in each framework. +Options override attributes one setting at a time, with +[scope and replacement differences](https://keyrove.pages.dev/docs/attributes-and-options#configuration-differences). + +`keyRove` accepts native keyboard events and compatible framework events, +including React synthetic events. The +[installation guide](https://keyrove.pages.dev/docs/installation) shows setup +for vanilla JavaScript, React, Vue and Svelte. ## Documentation diff --git a/package.json b/package.json index 1668cf5..ce22f42 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "lint": "prettier --check .", "format": "prettier --write .", "build": "pnpm -r build", + "bench": "pnpm --filter @mixedrays/keyrove bench", "typecheck": "pnpm -r typecheck", "preview": "pnpm --filter @mixedrays/keyrove/docs preview", "release": "pnpm --filter @mixedrays/keyrove release" diff --git a/packages/docs/build/icons.ts b/packages/docs/build/icons.ts index 8d1fd88..7e694c7 100644 --- a/packages/docs/build/icons.ts +++ b/packages/docs/build/icons.ts @@ -7,7 +7,9 @@ import { LayoutGrid, Menu, Moon, + Search, Sun, + X, type IconNode, } from 'lucide'; @@ -55,6 +57,8 @@ const fromLucide = (node: IconNode): IconDef => ({ }); const ICONS = { + search: fromLucide(Search), + close: fromLucide(X), menu: fromLucide(Menu), book: fromLucide(BookOpen), keyboard: fromLucide(Keyboard), diff --git a/packages/docs/build/layout.ts b/packages/docs/build/layout.ts index d8bcefb..9e7ff36 100644 --- a/packages/docs/build/layout.ts +++ b/packages/docs/build/layout.ts @@ -83,7 +83,14 @@ const renderHeader = (resolveHref: HrefResolver, page: Page) => { ${link(resolveHref('/'), `${icon('keyboard', 'size-6')}keyrove`, 'wordmark')}
-