import * as react from 'react'; import { ReactNode } from 'react'; /** * D-pad focus navigation for the Meta Ray-Ban Display. * * The Display has no touch and no pointer. The Neural Band wristband * is the only input — its swipes/clicks reach the Web App as arrow * keys + Enter. So navigation is: move a focus ring between elements * with the arrows, activate with Enter. * * Convention: give any interactive element the `focusable` class. * `useDpad()` (call once near the app root) does the rest — spatial * navigation picks the nearest `focusable` in the pressed direction. * * Locally, your keyboard's arrow keys simulate the wristband. */ type Dir = "up" | "down" | "left" | "right"; type RectLike = { left: number; top: number; width: number; height: number; }; /** * Score a candidate's position relative to the current rect in a * direction. Returns null if the candidate is not in `dir` at all, * otherwise a positive number where lower wins. Pure — no DOM. The * extraction makes the spatial-focus algorithm directly unit-testable. */ declare function scoreRect(current: RectLike, candidate: RectLike, dir: Dir): number | null; /** * The current D-pad candidates, in DOM order — honors the innermost * and skips disabled/invisible elements. Exposed so navigation * containers can implement focus memory (record the focused index on push, * restore it on pop). */ declare function getFocusables(): HTMLElement[]; /** * Move focus to the screen's preferred element: the first focusable carrying * `data-autofocus`, else the first focusable in DOM order. Exposed so a * screen that swaps its content under a single `useDpad()` (no remount) can * re-seed focus when its focusable set changes — `useDpad` itself only seeds * once on mount. Uses the same `SELECTOR`, so it skips disabled elements. */ declare function seedFocus(): void; /** * — contain the D-pad ring to a subtree while mounted (modal * surfaces: Confirm, PermissionPrompt, sheets). On mount it seeds focus * inside; arrows and Enter only see focusables within the innermost mounted * scope; on unmount focus returns to the element that had it before the * scope opened (or reseeds if that element is gone). Renders a * `display: contents` wrapper, so it never affects layout. */ declare function FocusScope({ children, restoreFocus, }: { children: ReactNode; /** Return focus to the previously focused element on unmount. */ restoreFocus?: boolean; }): react.JSX.Element; /** * Wire the D-pad to focus navigation. Call once, near the app root. * Returns `{ seedFocus }` for screens that need to re-seed focus after * swapping content within the same mount. */ declare function useDpad(): { seedFocus: () => void; }; /** * Read the D-pad cursor in React. Returns the `data-key` of the currently * focused `.focusable` element (or null), and re-renders as the cursor moves. * * The cursor is real DOM focus, so this is the SINGLE source of truth. Use it * to render decorations keyed off the focused item — a preview, a label, the * legal-move dots for the focused board square — WITHOUT inventing a second * "selected index" state that can drift out of sync with focus and paint a * competing highlight. There is exactly one cursor (the focused element); this * just lets you render against it. * * Give each focusable a stable `data-key`: * `