@dloizides/game-input 1.5.1 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,45 +1,49 @@
1
- # Changelog
2
-
3
- All notable changes to `@dloizides/game-input` are documented here.
4
-
5
- ## 1.5.1
6
-
7
- - Pad back dispatches Escape at the focused element so a dialog host that handles Escape and stops propagation still closes (NAV-1).
8
-
9
- ## 1.5.0
10
-
11
- - `createMenuNav`: one menu focus engine for arrow keys (capture phase) and pad actions; top-most dialog owns focus, focus restored on close, sliders/selects step on Left/Right, text fields keep arrows until Escape/B, `data-nav-input` on <html> (NAV-1 "Every game menu works with arrow keys and controller").
12
- - `MENU_FOCUSABLE_SELECTOR`, `menuRoot`, `focusables`, `pickTarget` exported (pickTarget moved from Surge).
13
-
14
- ## 1.4.0
15
-
16
- GI-HAPTICS-1 "Haptics vibrate only after a user activation".
17
-
18
- - `createHaptics` no longer calls `navigator.vibrate` before a user gesture (Chrome blocks it and logs an
19
- intervention). Gate: `navigator.userActivation.hasBeenActive` where present, else a capture-phase latch on
20
- the first `pointerdown` / `keydown` / `touchstart` of `activationTarget` (new option, default `globalThis`).
21
- - The enable-confirmation tick follows the same gate. Disabled and unsupported stay silent no-ops.
22
- - New exports: `ActivationTarget` type, `USER_ACTIVATION_EVENTS`.
23
-
24
- ## 1.3.0
25
-
26
- Standard Gamepad action poller (first consumer: NextGame console-dashboard UI).
27
-
28
- - `stepPad(prev, next, repeat, now)` — pure per-frame reducer: face/shoulder buttons fire on the
29
- rising edge by W3C Standard POSITION; D-pad or left stick (0.5 dead-zone, dominant axis) fires
30
- once, repeats after 380 ms, then every 110 ms; release resets the repeat.
31
- - `createGamepadPoller({ getPads, requestFrame, cancelFrame, onAction })` — injectable rAF loop over
32
- the first connected pad; a disappearing pad resets state; `stop()` is safe from inside `onAction`.
33
- - `PAD_ACTIONS`, `STANDARD_BUTTON`, `IDLE_REPEAT` + types `PadAction`, `PadSnapshot`, `RepeatState`,
34
- `PadLike`, `GamepadPollerOptions`.
35
-
36
- ## 1.0.0
37
-
38
- Initial release — the haptics primitive of the C4 games shared kit.
39
-
40
- - `createHaptics(options)` — player-toggleable, always-safe Web Vibration API wrapper
41
- (localStorage-gated, structural/injectable `navigator` + `storage`, never throws into the game loop).
42
- - `HAPTIC_PATTERNS` — shared semantic vibration vocabulary (tap/select/lock/bump/navigate/success/error/loss/reveal).
43
- - Zero runtime dependencies; isomorphic; dual CJS/ESM; 100% test coverage.
44
-
45
- Extracted from Aurora's `src/input/haptics.ts`. First consumers: Aurora (re-export shim) and Morphe (new adoption).
1
+ # Changelog
2
+
3
+ All notable changes to `@dloizides/game-input` are documented here.
4
+
5
+ ## 1.6.0
6
+
7
+ - `MenuWalkHook` + `MENU_WALK_HOOK` + `installMenuWalkHook`: a canvas-menu game (Phaser, Babylon GUI) publishes `window.__menuWalk = { screen(), items(), focused() }` so `@dloizides/game-e2e` `expectHookMenuWalkable` can walk its menus by arrows and pad (NAV-1 "Every game menu works with arrow keys and controller", phase 4).
8
+
9
+ ## 1.5.1
10
+
11
+ - Pad back dispatches Escape at the focused element so a dialog host that handles Escape and stops propagation still closes (NAV-1).
12
+
13
+ ## 1.5.0
14
+
15
+ - `createMenuNav`: one menu focus engine for arrow keys (capture phase) and pad actions; top-most dialog owns focus, focus restored on close, sliders/selects step on Left/Right, text fields keep arrows until Escape/B, `data-nav-input` on <html> (NAV-1 "Every game menu works with arrow keys and controller").
16
+ - `MENU_FOCUSABLE_SELECTOR`, `menuRoot`, `focusables`, `pickTarget` exported (pickTarget moved from Surge).
17
+
18
+ ## 1.4.0
19
+
20
+ GI-HAPTICS-1 "Haptics vibrate only after a user activation".
21
+
22
+ - `createHaptics` no longer calls `navigator.vibrate` before a user gesture (Chrome blocks it and logs an
23
+ intervention). Gate: `navigator.userActivation.hasBeenActive` where present, else a capture-phase latch on
24
+ the first `pointerdown` / `keydown` / `touchstart` of `activationTarget` (new option, default `globalThis`).
25
+ - The enable-confirmation tick follows the same gate. Disabled and unsupported stay silent no-ops.
26
+ - New exports: `ActivationTarget` type, `USER_ACTIVATION_EVENTS`.
27
+
28
+ ## 1.3.0
29
+
30
+ Standard Gamepad action poller (first consumer: NextGame console-dashboard UI).
31
+
32
+ - `stepPad(prev, next, repeat, now)` — pure per-frame reducer: face/shoulder buttons fire on the
33
+ rising edge by W3C Standard POSITION; D-pad or left stick (0.5 dead-zone, dominant axis) fires
34
+ once, repeats after 380 ms, then every 110 ms; release resets the repeat.
35
+ - `createGamepadPoller({ getPads, requestFrame, cancelFrame, onAction })` — injectable rAF loop over
36
+ the first connected pad; a disappearing pad resets state; `stop()` is safe from inside `onAction`.
37
+ - `PAD_ACTIONS`, `STANDARD_BUTTON`, `IDLE_REPEAT` + types `PadAction`, `PadSnapshot`, `RepeatState`,
38
+ `PadLike`, `GamepadPollerOptions`.
39
+
40
+ ## 1.0.0
41
+
42
+ Initial release — the haptics primitive of the C4 games shared kit.
43
+
44
+ - `createHaptics(options)` — player-toggleable, always-safe Web Vibration API wrapper
45
+ (localStorage-gated, structural/injectable `navigator` + `storage`, never throws into the game loop).
46
+ - `HAPTIC_PATTERNS` — shared semantic vibration vocabulary (tap/select/lock/bump/navigate/success/error/loss/reveal).
47
+ - Zero runtime dependencies; isomorphic; dual CJS/ESM; 100% test coverage.
48
+
49
+ Extracted from Aurora's `src/input/haptics.ts`. First consumers: Aurora (re-export shim) and Morphe (new adoption).
package/README.md CHANGED
@@ -74,3 +74,18 @@ feel instead of re-picking magic durations:
74
74
  ## License
75
75
 
76
76
  MIT
77
+
78
+ ## Canvas menus: the walk hook (NAV-1)
79
+
80
+ A game whose menus are drawn on a canvas (no DOM buttons) publishes its menu state so the shared walker in
81
+ `@dloizides/game-e2e` (`expectHookMenuWalkable`) can prove every item is reachable by arrows and pad:
82
+
83
+ ```ts
84
+ import { installMenuWalkHook } from '@dloizides/game-input';
85
+
86
+ installMenuWalkHook({
87
+ screen: () => menu.screenId, // e.g. 'title', 'settings'
88
+ items: () => menu.items.map((i) => i.id),
89
+ focused: () => menu.focusedId ?? null,
90
+ });
91
+ ```
package/dist/index.d.mts CHANGED
@@ -109,6 +109,20 @@ declare function defaultInitialFocus(root: HTMLElement): HTMLElement | null;
109
109
  /** Top-most visible dialog (aria-modal preferred, last in DOM wins), else the visible base root, else null. */
110
110
  declare function menuRoot(baseRoot: () => HTMLElement | null): HTMLElement | null;
111
111
 
112
+ /** Global name a canvas-menu game publishes its {@link MenuWalkHook} under (`window.__menuWalk`). */
113
+ declare const MENU_WALK_HOOK = "__menuWalk";
114
+ /** Engine-native menu state a canvas game exposes so @dloizides/game-e2e can walk it (NAV-1). */
115
+ interface MenuWalkHook {
116
+ /** Stable id of the menu screen on top now (e.g. `title`, `settings`). */
117
+ screen(): string;
118
+ /** Ids of every selectable item on that screen, reachable or not. */
119
+ items(): string[];
120
+ /** Id of the item holding menu focus, or `null` when none has it. */
121
+ focused(): string | null;
122
+ }
123
+ /** Publishes `hook` as `target.__menuWalk` and returns a function that removes it again. */
124
+ declare function installMenuWalkHook(hook: MenuWalkHook, target?: object): () => void;
125
+
112
126
  interface Box {
113
127
  readonly x: number;
114
128
  readonly y: number;
@@ -208,4 +222,4 @@ type HapticIntent = 'tap' | 'select' | 'lock' | 'bump' | 'navigate' | 'success'
208
222
  */
209
223
  declare const HAPTIC_PATTERNS: Record<HapticIntent, VibrationPattern>;
210
224
 
211
- export { type ActivationTarget, DEFAULT_ENABLE_CONFIRMATION, DEFAULT_HAPTICS_STORAGE_KEY, DIALOG_SELECTOR, type GamepadPollerOptions, HAPTIC_PATTERNS, type HapticIntent, type Haptics, type HapticsOptions, type HapticsStorage, IDLE_REPEAT, MENU_DEFAULT_ATTR, MENU_FOCUSABLE_SELECTOR, type MenuNav, type MenuNavOptions, NAV_DIRS, NAV_INPUT, NAV_INPUT_ATTR, type Box as NavBox, type NavDir, type NavInput, PAD_ACTIONS, type PadAction, type PadLike, type PadSnapshot, type RepeatState, STANDARD_BUTTON, USER_ACTIVATION_EVENTS, type VibrationCapable, type VibrationPattern, createGamepadPoller, createHaptics, createMenuNav, defaultInitialFocus, focusables, isShown, menuRoot, navDir, pickTarget, stepPad };
225
+ export { type ActivationTarget, DEFAULT_ENABLE_CONFIRMATION, DEFAULT_HAPTICS_STORAGE_KEY, DIALOG_SELECTOR, type GamepadPollerOptions, HAPTIC_PATTERNS, type HapticIntent, type Haptics, type HapticsOptions, type HapticsStorage, IDLE_REPEAT, MENU_DEFAULT_ATTR, MENU_FOCUSABLE_SELECTOR, MENU_WALK_HOOK, type MenuNav, type MenuNavOptions, type MenuWalkHook, NAV_DIRS, NAV_INPUT, NAV_INPUT_ATTR, type Box as NavBox, type NavDir, type NavInput, PAD_ACTIONS, type PadAction, type PadLike, type PadSnapshot, type RepeatState, STANDARD_BUTTON, USER_ACTIVATION_EVENTS, type VibrationCapable, type VibrationPattern, createGamepadPoller, createHaptics, createMenuNav, defaultInitialFocus, focusables, installMenuWalkHook, isShown, menuRoot, navDir, pickTarget, stepPad };
package/dist/index.d.ts CHANGED
@@ -109,6 +109,20 @@ declare function defaultInitialFocus(root: HTMLElement): HTMLElement | null;
109
109
  /** Top-most visible dialog (aria-modal preferred, last in DOM wins), else the visible base root, else null. */
110
110
  declare function menuRoot(baseRoot: () => HTMLElement | null): HTMLElement | null;
111
111
 
112
+ /** Global name a canvas-menu game publishes its {@link MenuWalkHook} under (`window.__menuWalk`). */
113
+ declare const MENU_WALK_HOOK = "__menuWalk";
114
+ /** Engine-native menu state a canvas game exposes so @dloizides/game-e2e can walk it (NAV-1). */
115
+ interface MenuWalkHook {
116
+ /** Stable id of the menu screen on top now (e.g. `title`, `settings`). */
117
+ screen(): string;
118
+ /** Ids of every selectable item on that screen, reachable or not. */
119
+ items(): string[];
120
+ /** Id of the item holding menu focus, or `null` when none has it. */
121
+ focused(): string | null;
122
+ }
123
+ /** Publishes `hook` as `target.__menuWalk` and returns a function that removes it again. */
124
+ declare function installMenuWalkHook(hook: MenuWalkHook, target?: object): () => void;
125
+
112
126
  interface Box {
113
127
  readonly x: number;
114
128
  readonly y: number;
@@ -208,4 +222,4 @@ type HapticIntent = 'tap' | 'select' | 'lock' | 'bump' | 'navigate' | 'success'
208
222
  */
209
223
  declare const HAPTIC_PATTERNS: Record<HapticIntent, VibrationPattern>;
210
224
 
211
- export { type ActivationTarget, DEFAULT_ENABLE_CONFIRMATION, DEFAULT_HAPTICS_STORAGE_KEY, DIALOG_SELECTOR, type GamepadPollerOptions, HAPTIC_PATTERNS, type HapticIntent, type Haptics, type HapticsOptions, type HapticsStorage, IDLE_REPEAT, MENU_DEFAULT_ATTR, MENU_FOCUSABLE_SELECTOR, type MenuNav, type MenuNavOptions, NAV_DIRS, NAV_INPUT, NAV_INPUT_ATTR, type Box as NavBox, type NavDir, type NavInput, PAD_ACTIONS, type PadAction, type PadLike, type PadSnapshot, type RepeatState, STANDARD_BUTTON, USER_ACTIVATION_EVENTS, type VibrationCapable, type VibrationPattern, createGamepadPoller, createHaptics, createMenuNav, defaultInitialFocus, focusables, isShown, menuRoot, navDir, pickTarget, stepPad };
225
+ export { type ActivationTarget, DEFAULT_ENABLE_CONFIRMATION, DEFAULT_HAPTICS_STORAGE_KEY, DIALOG_SELECTOR, type GamepadPollerOptions, HAPTIC_PATTERNS, type HapticIntent, type Haptics, type HapticsOptions, type HapticsStorage, IDLE_REPEAT, MENU_DEFAULT_ATTR, MENU_FOCUSABLE_SELECTOR, MENU_WALK_HOOK, type MenuNav, type MenuNavOptions, type MenuWalkHook, NAV_DIRS, NAV_INPUT, NAV_INPUT_ATTR, type Box as NavBox, type NavDir, type NavInput, PAD_ACTIONS, type PadAction, type PadLike, type PadSnapshot, type RepeatState, STANDARD_BUTTON, USER_ACTIVATION_EVENTS, type VibrationCapable, type VibrationPattern, createGamepadPoller, createHaptics, createMenuNav, defaultInitialFocus, focusables, installMenuWalkHook, isShown, menuRoot, navDir, pickTarget, stepPad };
package/dist/index.js CHANGED
@@ -485,6 +485,18 @@ function createMenuNav(options) {
485
485
  };
486
486
  }
487
487
 
488
+ // src/menu/menuWalkHook.ts
489
+ var MENU_WALK_HOOK = "__menuWalk";
490
+ function installMenuWalkHook(hook, target = globalThis) {
491
+ const host = target;
492
+ host[MENU_WALK_HOOK] = hook;
493
+ return () => {
494
+ if (host[MENU_WALK_HOOK] === hook) {
495
+ delete host[MENU_WALK_HOOK];
496
+ }
497
+ };
498
+ }
499
+
488
500
  // src/constants.ts
489
501
  var DEFAULT_HAPTICS_STORAGE_KEY = "game.haptics";
490
502
  var DEFAULT_ENABLE_CONFIRMATION = 15;
@@ -602,6 +614,7 @@ exports.HAPTIC_PATTERNS = HAPTIC_PATTERNS;
602
614
  exports.IDLE_REPEAT = IDLE_REPEAT;
603
615
  exports.MENU_DEFAULT_ATTR = MENU_DEFAULT_ATTR;
604
616
  exports.MENU_FOCUSABLE_SELECTOR = MENU_FOCUSABLE_SELECTOR;
617
+ exports.MENU_WALK_HOOK = MENU_WALK_HOOK;
605
618
  exports.NAV_DIRS = NAV_DIRS;
606
619
  exports.NAV_INPUT = NAV_INPUT;
607
620
  exports.NAV_INPUT_ATTR = NAV_INPUT_ATTR;
@@ -613,6 +626,7 @@ exports.createHaptics = createHaptics;
613
626
  exports.createMenuNav = createMenuNav;
614
627
  exports.defaultInitialFocus = defaultInitialFocus;
615
628
  exports.focusables = focusables;
629
+ exports.installMenuWalkHook = installMenuWalkHook;
616
630
  exports.isShown = isShown;
617
631
  exports.menuRoot = menuRoot;
618
632
  exports.navDir = navDir;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/gamepad/padMap.ts","../src/gamepad/stepPad.ts","../src/gamepad/createGamepadPoller.ts","../src/menu/constants.ts","../src/menu/controlKind.ts","../src/menu/focusables.ts","../src/menu/menuRoot.ts","../src/menu/pickTarget.ts","../src/menu/stepControl.ts","../src/menu/navActions.ts","../src/menu/createMenuNav.ts","../src/constants.ts","../src/userActivation.ts","../src/haptics.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/** The semantic actions a Standard Gamepad produces, independent of the device's labels. */\nexport const PAD_ACTIONS = {\n up: 'up',\n down: 'down',\n left: 'left',\n right: 'right',\n confirm: 'confirm',\n back: 'back',\n mood: 'mood',\n view: 'view',\n pagePrev: 'pagePrev',\n pageNext: 'pageNext',\n} as const;\nexport type PadAction = (typeof PAD_ACTIONS)[keyof typeof PAD_ACTIONS];\n\n/** W3C Standard Gamepad button indices, named by POSITION (Nintendo swaps A/B labels). */\nexport const STANDARD_BUTTON = {\n south: 0,\n east: 1,\n west: 2,\n north: 3,\n leftShoulder: 4,\n rightShoulder: 5,\n dpadUp: 12,\n dpadDown: 13,\n dpadLeft: 14,\n dpadRight: 15,\n} as const;\n\n/** Edge-triggered buttons, in dispatch order. */\nexport const FACE_BUTTON_ACTIONS: ReadonlyArray<readonly [number, PadAction]> = [\n [STANDARD_BUTTON.south, PAD_ACTIONS.confirm],\n [STANDARD_BUTTON.east, PAD_ACTIONS.back],\n [STANDARD_BUTTON.west, PAD_ACTIONS.view],\n [STANDARD_BUTTON.north, PAD_ACTIONS.mood],\n [STANDARD_BUTTON.leftShoulder, PAD_ACTIONS.pagePrev],\n [STANDARD_BUTTON.rightShoulder, PAD_ACTIONS.pageNext],\n];\n\n/** Held (auto-repeating) buttons; the first pressed one wins. */\nexport const DPAD_ACTIONS: ReadonlyArray<readonly [number, PadAction]> = [\n [STANDARD_BUTTON.dpadUp, PAD_ACTIONS.up],\n [STANDARD_BUTTON.dpadDown, PAD_ACTIONS.down],\n [STANDARD_BUTTON.dpadLeft, PAD_ACTIONS.left],\n [STANDARD_BUTTON.dpadRight, PAD_ACTIONS.right],\n];\n\n/** Left-stick magnitude below which the stick counts as centred. */\nexport const STICK_DEAD_ZONE = 0.5;\n/** Delay before a held direction starts repeating (ms). */\nexport const REPEAT_DELAY_MS = 380;\n/** Interval between repeats once repeating (ms). */\nexport const REPEAT_INTERVAL_MS = 110;\n","import {\n DPAD_ACTIONS,\n FACE_BUTTON_ACTIONS,\n PAD_ACTIONS,\n REPEAT_DELAY_MS,\n REPEAT_INTERVAL_MS,\n STICK_DEAD_ZONE,\n type PadAction,\n} from './padMap';\n\n/** One frame of pad state: pressed flags by Standard button index, and raw axes. */\nexport interface PadSnapshot {\n buttons: readonly boolean[];\n axes: readonly number[];\n}\n\n/** Which direction is held, when it started, and when it last fired. */\nexport interface RepeatState {\n held: PadAction | null;\n since: number;\n lastFire: number;\n}\n\nexport const IDLE_REPEAT: RepeatState = { held: null, since: 0, lastFire: 0 };\n\nconst STICK_X = 0;\nconst STICK_Y = 1;\n\nfunction stickDirection(axes: readonly number[]): PadAction | null {\n const x = axes[STICK_X] ?? 0;\n const y = axes[STICK_Y] ?? 0;\n if (Math.max(Math.abs(x), Math.abs(y)) < STICK_DEAD_ZONE) {\n return null;\n }\n if (Math.abs(x) > Math.abs(y)) {\n return x > 0 ? PAD_ACTIONS.right : PAD_ACTIONS.left;\n }\n return y > 0 ? PAD_ACTIONS.down : PAD_ACTIONS.up;\n}\n\nfunction heldDirection(snapshot: PadSnapshot): PadAction | null {\n const dpad = DPAD_ACTIONS.find(([index]) => snapshot.buttons[index] === true);\n return dpad === undefined ? stickDirection(snapshot.axes) : dpad[1];\n}\n\n/** One poll frame → the actions to dispatch and the next repeat state. Pure. */\nexport function stepPad(\n prev: PadSnapshot | null,\n next: PadSnapshot,\n repeat: RepeatState,\n now: number,\n): { actions: PadAction[]; repeat: RepeatState } {\n const actions: PadAction[] = FACE_BUTTON_ACTIONS\n .filter(([index]) => next.buttons[index] === true && prev?.buttons[index] !== true)\n .map(([, action]) => action);\n const direction = heldDirection(next);\n if (direction === null) {\n return { actions, repeat: IDLE_REPEAT };\n }\n if (direction !== repeat.held) {\n return { actions: [...actions, direction], repeat: { held: direction, since: now, lastFire: now } };\n }\n const firstRepeat = repeat.lastFire === repeat.since;\n const wait = firstRepeat ? REPEAT_DELAY_MS : REPEAT_INTERVAL_MS;\n if (now - repeat.lastFire < wait) {\n return { actions, repeat };\n }\n return { actions: [...actions, direction], repeat: { ...repeat, lastFire: now } };\n}\n","import type { PadAction } from './padMap';\nimport { IDLE_REPEAT, stepPad, type PadSnapshot, type RepeatState } from './stepPad';\n\n/** The structural subset of the DOM `Gamepad` the poller reads. */\nexport interface PadLike {\n connected: boolean;\n buttons: ReadonlyArray<{ pressed: boolean }>;\n axes: readonly number[];\n}\n\nexport interface GamepadPollerOptions {\n /** Usually `() => navigator.getGamepads()`. */\n getPads: () => ReadonlyArray<PadLike | null>;\n /** Usually `requestAnimationFrame`. */\n requestFrame: (cb: (now: number) => void) => number;\n /** Usually `cancelAnimationFrame`. */\n cancelFrame: (id: number) => void;\n onAction: (action: PadAction) => void;\n}\n\n/**\n * rAF-driven poller over the first connected pad. Starts idle; call start().\n * Safe to stop() (or stop() then start()) from inside `onAction`.\n */\nexport function createGamepadPoller(opts: GamepadPollerOptions): { start: () => void; stop: () => void } {\n let prev: PadSnapshot | null = null;\n let repeat: RepeatState = IDLE_REPEAT;\n let running = false;\n let frame: number | null = null;\n\n const tick = (now: number): void => {\n frame = null;\n const pad = opts.getPads().find((p): p is PadLike => p !== null && p.connected);\n if (pad === undefined) {\n prev = null;\n repeat = IDLE_REPEAT;\n } else {\n const snapshot: PadSnapshot = { buttons: pad.buttons.map((b) => b.pressed), axes: pad.axes };\n const step = stepPad(prev, snapshot, repeat, now);\n prev = snapshot;\n repeat = step.repeat;\n step.actions.forEach((action) => opts.onAction(action));\n }\n if (running && frame === null) {\n frame = opts.requestFrame(tick);\n }\n };\n\n return {\n start: (): void => {\n if (running) {\n return;\n }\n running = true;\n if (frame === null) {\n frame = opts.requestFrame(tick);\n }\n },\n stop: (): void => {\n running = false;\n if (frame !== null) {\n opts.cancelFrame(frame);\n frame = null;\n }\n },\n };\n}\n","/** Every control a menu walker must be able to reach (shared with @dloizides/game-e2e). */\nexport const MENU_FOCUSABLE_SELECTOR = [\n 'button',\n 'a[href]',\n 'input',\n 'select',\n 'textarea',\n '[role=\"button\"]',\n '[role=\"tab\"]',\n '[role=\"option\"]',\n '[role=\"slider\"]',\n '[role=\"switch\"]',\n '[role=\"checkbox\"]',\n '[role=\"radio\"]',\n '[tabindex=\"0\"]',\n].join(', ');\n\nexport const NATIVE_FOCUSABLE_SELECTOR = 'button, input, select, textarea, a[href]';\nexport const DIALOG_SELECTOR = '[role=\"dialog\"]';\nexport const HIDDEN_ANCESTOR_SELECTOR = '[hidden], [inert], [aria-hidden=\"true\"]';\nexport const MENU_DEFAULT_ATTR = 'data-menu-default';\nexport const NAV_INPUT_ATTR = 'data-nav-input';\nexport const NAV_INPUT = { key: 'key', pad: 'pad' } as const;\nexport type NavInput = (typeof NAV_INPUT)[keyof typeof NAV_INPUT];\nexport const OBSERVED_ATTRIBUTES: readonly string[] = ['hidden', 'class', 'style', 'aria-hidden', 'aria-modal', 'inert', 'open'];\nexport const ESCAPE_KEY = 'Escape';\nexport const ENTER_KEY = 'Enter';\n","import { NATIVE_FOCUSABLE_SELECTOR } from './constants';\n\nexport const enum ControlKind {\n Button = 'button',\n Slider = 'slider',\n TextField = 'textField',\n Toggle = 'toggle',\n Select = 'select',\n}\n\nconst NON_TEXT_INPUTS: readonly string[] = ['button', 'submit', 'reset', 'color', 'file', 'image'];\nconst TOGGLE_ROLES: readonly string[] = ['checkbox', 'switch', 'radio'];\n\nfunction inputKind(el: HTMLInputElement): ControlKind {\n const type = el.type;\n if (type === 'range') {return ControlKind.Slider;}\n if (type === 'checkbox' || type === 'radio') {return ControlKind.Toggle;}\n return NON_TEXT_INPUTS.includes(type) ? ControlKind.Button : ControlKind.TextField;\n}\n\nexport function controlKind(el: Element): ControlKind {\n if (el instanceof HTMLInputElement) {return inputKind(el);}\n if (el instanceof HTMLTextAreaElement) {return ControlKind.TextField;}\n if (el instanceof HTMLSelectElement) {return ControlKind.Select;}\n const role = el.getAttribute('role') ?? '';\n if (role === 'slider') {return ControlKind.Slider;}\n return TOGGLE_ROLES.includes(role) ? ControlKind.Toggle : ControlKind.Button;\n}\n\nexport const isTextField = (el: Element): boolean => controlKind(el) === ControlKind.TextField;\n\nexport function isStepper(el: Element): boolean {\n const kind = controlKind(el);\n return kind === ControlKind.Slider || kind === ControlKind.Select;\n}\n\nexport function needsSyntheticClick(el: Element): boolean {\n const kind = controlKind(el);\n const clickable = kind === ControlKind.Button || kind === ControlKind.Toggle;\n return clickable && !el.matches(NATIVE_FOCUSABLE_SELECTOR);\n}\n","import { HIDDEN_ANCESTOR_SELECTOR, MENU_DEFAULT_ATTR, MENU_FOCUSABLE_SELECTOR } from './constants';\n\n/** True when the element has a layout box and no hidden, inert or aria-hidden ancestor. */\nexport function isShown(el: Element): boolean {\n return el.getClientRects().length > 0 && el.closest(HIDDEN_ANCESTOR_SELECTOR) === null;\n}\n\nconst isDisabled = (el: Element): boolean => (el as { disabled?: unknown }).disabled === true;\n\n/** The visible, enabled controls inside root, in DOM order. */\nexport function focusables(root: HTMLElement): HTMLElement[] {\n return Array.from(root.querySelectorAll<HTMLElement>(MENU_FOCUSABLE_SELECTOR)).filter((el) => isShown(el) && !isDisabled(el));\n}\n\n/** The [data-menu-default] control, else the first control, else null. */\nexport function defaultInitialFocus(root: HTMLElement): HTMLElement | null {\n const list = focusables(root);\n return list.find((el) => el.hasAttribute(MENU_DEFAULT_ATTR)) ?? list[0] ?? null;\n}\n","import { DIALOG_SELECTOR } from './constants';\nimport { isShown } from './focusables';\n\n/** Top-most visible dialog (aria-modal preferred, last in DOM wins), else the visible base root, else null. */\nexport function menuRoot(baseRoot: () => HTMLElement | null): HTMLElement | null {\n const dialogs = Array.from(document.querySelectorAll<HTMLElement>(DIALOG_SELECTOR)).filter(isShown);\n const modal = dialogs.filter((d) => d.getAttribute('aria-modal') === 'true');\n const top = (modal.length > 0 ? modal : dialogs).pop();\n if (top !== undefined) {return top;}\n const base = baseRoot();\n return base !== null && isShown(base) ? base : null;\n}\n","export interface Box { readonly x: number; readonly y: number; readonly w: number; readonly h: number }\n\nexport const NAV_DIRS = { up: 'arrowup', down: 'arrowdown', left: 'arrowleft', right: 'arrowright' } as const;\nexport type NavDir = (typeof NAV_DIRS)[keyof typeof NAV_DIRS];\n\nconst NAV_KEYS: readonly string[] = Object.values(NAV_DIRS);\nconst CROSS_WEIGHT = 2;\nconst SLACK = 1;\n\n/** The direction an arrow key names (case-insensitive), or null for any other key. */\nexport const navDir = (key: string): NavDir | null => (NAV_KEYS.includes(key.toLowerCase()) ? (key.toLowerCase() as NavDir) : null);\n\nconst centre = (b: Box): { cx: number; cy: number } => ({ cx: b.x + b.w / 2, cy: b.y + b.h / 2 });\n\nfunction cost(a: Box, b: Box, dir: NavDir): number | null {\n const p = centre(a);\n const q = centre(b);\n const dx = q.cx - p.cx;\n const dy = q.cy - p.cy;\n const vertical = dir === NAV_DIRS.up || dir === NAV_DIRS.down;\n const along = vertical ? (dir === NAV_DIRS.down ? dy : -dy) : dir === NAV_DIRS.right ? dx : -dx;\n if (along <= SLACK) {return null;}\n return along + CROSS_WEIGHT * Math.abs(vertical ? dx : dy);\n}\n\n/** Index of the nearest box from `from` in `dir`; wraps in list order when none lies that way; -1 for no boxes. */\nexport function pickTarget(boxes: readonly Box[], from: number, dir: NavDir): number {\n if (boxes.length === 0) {return -1;}\n if (from < 0 || from >= boxes.length) {return 0;}\n const origin = boxes[from] as Box;\n let best = -1;\n let bestCost = Infinity;\n boxes.forEach((b, i) => {\n const c = i === from ? null : cost(origin, b, dir);\n if (c !== null && c < bestCost) {\n best = i;\n bestCost = c;\n }\n });\n if (best >= 0) {return best;}\n const step = dir === NAV_DIRS.down || dir === NAV_DIRS.right ? 1 : -1;\n return (from + step + boxes.length) % boxes.length;\n}\n","const DEFAULT_MAX = 100;\n\nconst num = (raw: string | null, fallback: number): number => {\n const n = parseFloat(raw ?? '');\n return Number.isFinite(n) ? n : fallback;\n};\n\nfunction clampStep(value: number, delta: number, min: number, max: number, step: number): number {\n const decimals = (String(step).split('.')[1] ?? '').length;\n return Math.min(max, Math.max(min, Number((value + delta * step).toFixed(decimals))));\n}\n\nfunction apply(el: HTMLElement, current: number, next: number, write: (v: number) => void): void {\n if (next === current) {return;}\n write(next);\n el.dispatchEvent(new Event('input', { bubbles: true }));\n el.dispatchEvent(new Event('change', { bubbles: true }));\n}\n\n/** Steps a range, select or role=slider by one step in delta's direction, firing input + change when it moved. */\nexport function stepControl(el: HTMLElement, delta: 1 | -1): void {\n if (el instanceof HTMLInputElement) {\n const value = num(el.value, 0);\n const next = clampStep(value, delta, num(el.min, 0), num(el.max, DEFAULT_MAX), num(el.step, 1));\n apply(el, value, next, (v) => { el.value = String(v); });\n } else if (el instanceof HTMLSelectElement) {\n const next = Math.min(el.options.length - 1, Math.max(0, el.selectedIndex + delta));\n apply(el, el.selectedIndex, next, (v) => { el.selectedIndex = v; });\n } else {\n const value = num(el.getAttribute('aria-valuenow'), 0);\n const next = clampStep(value, delta, num(el.getAttribute('aria-valuemin'), 0), num(el.getAttribute('aria-valuemax'), DEFAULT_MAX), num(el.getAttribute('data-step'), 1));\n apply(el, value, next, (v) => el.setAttribute('aria-valuenow', String(v)));\n }\n}\n","import { NATIVE_FOCUSABLE_SELECTOR } from './constants';\nimport { isStepper } from './controlKind';\nimport { focusables } from './focusables';\nimport { type Box, NAV_DIRS, type NavDir, pickTarget } from './pickTarget';\nimport { stepControl } from './stepControl';\n\nexport type InitialFocus = (root: HTMLElement) => HTMLElement | null;\n\nconst boxOf = (el: Element): Box => {\n const r = el.getBoundingClientRect();\n return { x: r.left, y: r.top, w: r.width, h: r.height };\n};\n\n/** Focuses el (making a non-native control programmatically focusable) and scrolls it into view. */\nexport function focusControl(el: HTMLElement): void {\n if (!el.matches(NATIVE_FOCUSABLE_SELECTOR) && !el.hasAttribute('tabindex')) {el.setAttribute('tabindex', '-1');}\n el.focus({ preventScroll: true });\n if (typeof el.scrollIntoView === 'function') {el.scrollIntoView({ block: 'nearest' });}\n}\n\nexport function activeIn(root: HTMLElement): HTMLElement | null {\n const a = document.activeElement;\n return a instanceof HTMLElement && a !== root && root.contains(a) ? a : null;\n}\n\nexport function focusInitial(root: HTMLElement, initial: InitialFocus): boolean {\n const target = initial(root);\n if (target === null) {return false;}\n focusControl(target);\n return true;\n}\n\nfunction moveFocus(root: HTMLElement, active: HTMLElement | null, dir: NavDir, initial: InitialFocus): boolean {\n const list = focusables(root);\n const from = active === null ? -1 : list.indexOf(active);\n if (from < 0) {return focusInitial(root, initial);}\n focusControl(list[pickTarget(list.map(boxOf), from, dir)] as HTMLElement);\n return true;\n}\n\n/** Left/Right step a focused slider or select; every other case moves focus. True when it acted. */\nexport function direct(root: HTMLElement, active: HTMLElement | null, dir: NavDir, initial: InitialFocus): boolean {\n const horizontal = dir === NAV_DIRS.left || dir === NAV_DIRS.right;\n if (active !== null && horizontal && isStepper(active)) {\n stepControl(active, dir === NAV_DIRS.right ? 1 : -1);\n return true;\n }\n return moveFocus(root, active, dir, initial);\n}\n\n/** Leaves a text field for the control below it; blurs when it is the only control. */\nexport function leaveField(root: HTMLElement, field: HTMLElement): void {\n const list = focusables(root);\n const next = list[pickTarget(list.map(boxOf), list.indexOf(field), NAV_DIRS.down)];\n if (next === field || next === undefined) {\n field.blur();\n return;\n }\n focusControl(next);\n}\n","import { PAD_ACTIONS, type PadAction } from '../gamepad/padMap';\nimport { DIALOG_SELECTOR, ENTER_KEY, ESCAPE_KEY, NAV_INPUT, NAV_INPUT_ATTR, type NavInput, OBSERVED_ATTRIBUTES } from './constants';\nimport { isTextField, needsSyntheticClick } from './controlKind';\nimport { defaultInitialFocus, isShown } from './focusables';\nimport { menuRoot } from './menuRoot';\nimport { activeIn, direct, focusControl, focusInitial, leaveField } from './navActions';\nimport { NAV_DIRS, type NavDir, navDir } from './pickTarget';\n\nexport interface MenuNavOptions {\n /** The game's base menu root when no dialog is open; null = no menu (e.g. during play). */\n baseRoot: () => HTMLElement | null;\n /** True while input must not move focus (e.g. a remap capture). Default: never. */\n suspended?: () => boolean;\n /** Where focus goes when a root opens. Default: [data-menu-default], else the first control. */\n initialFocus?: (root: HTMLElement) => HTMLElement | null;\n}\n\nexport interface MenuNav {\n /** Feed one pad action from stepPad (the game keeps its own poller). */\n pad(action: PadAction): void;\n /** Re-evaluate the root and place focus (call after the game opens a screen). */\n refresh(): void;\n dispose(): void;\n}\n\ninterface OpenDialog { dialog: HTMLElement; restore: HTMLElement | null }\n\nconst PAD_DIRS: Partial<Record<PadAction, NavDir>> = { up: NAV_DIRS.up, down: NAV_DIRS.down, left: NAV_DIRS.left, right: NAV_DIRS.right };\n\nconst isOpen = (el: HTMLElement): boolean => el.isConnected && isShown(el);\nconst markInput = (kind: NavInput): void => document.documentElement.setAttribute(NAV_INPUT_ATTR, kind);\nconst clearInput = (): void => document.documentElement.removeAttribute(NAV_INPUT_ATTR);\nconst sendEscape = (): boolean => ([document.activeElement, window].find((t) => t !== null) as EventTarget).dispatchEvent(new KeyboardEvent('keydown', { key: ESCAPE_KEY, bubbles: true, cancelable: true }));\n\nfunction popClosed(stack: OpenDialog[]): HTMLElement | null {\n let restore: HTMLElement | null = null;\n while (stack.length > 0 && !isOpen((stack[stack.length - 1] as OpenDialog).dialog)) {restore = (stack.pop() as OpenDialog).restore;}\n return restore;\n}\n\nfunction canRestore(restore: HTMLElement | null, root: HTMLElement): restore is HTMLElement {\n return restore !== null && restore.isConnected && root.contains(restore) && isShown(restore);\n}\n\nfunction onKey(e: KeyboardEvent, root: HTMLElement, initial: (r: HTMLElement) => HTMLElement | null): void {\n const active = activeIn(root);\n const dir = navDir(e.key);\n if (e.key === ESCAPE_KEY) {\n if (active === null || !isTextField(active)) {return;}\n e.preventDefault();\n e.stopImmediatePropagation();\n leaveField(root, active);\n } else if (e.key === ENTER_KEY) {\n if (active === null || !needsSyntheticClick(active)) {return;}\n e.preventDefault();\n active.click();\n } else if (dir !== null) {\n markInput(NAV_INPUT.key);\n if (active !== null && isTextField(active)) {return;}\n if (direct(root, active, dir, initial)) {e.preventDefault();}\n }\n}\n\nfunction onPad(action: PadAction, root: HTMLElement | null, initial: (r: HTMLElement) => HTMLElement | null): void {\n const active = root === null ? null : activeIn(root);\n const dir = PAD_DIRS[action];\n if (action === PAD_ACTIONS.back) {\n if (root !== null && active !== null && isTextField(active)) {leaveField(root, active);}\n else {sendEscape();}\n } else if (root === null) {\n return;\n } else if (dir !== undefined) {\n direct(root, active, dir, initial);\n } else if (action === PAD_ACTIONS.confirm) {\n if (active === null) {focusInitial(root, initial);}\n else if (isTextField(active)) {focusControl(active);}\n else {active.click();}\n }\n}\n\n/** One focus engine for every game menu: arrow keys (capture phase), pad actions, dialogs on top, sliders and text fields. */\nexport function createMenuNav(options: MenuNavOptions): MenuNav {\n const suspended = options.suspended ?? ((): boolean => false);\n const initial = options.initialFocus ?? defaultInitialFocus;\n const stack: OpenDialog[] = [];\n let root = menuRoot(options.baseRoot);\n let lastInRoot: HTMLElement | null = null;\n\n const settle = (next: HTMLElement): void => {\n const restore = popClosed(stack);\n if (next.matches(DIALOG_SELECTOR) && !stack.some((s) => s.dialog === next)) {stack.push({ dialog: next, restore: lastInRoot });}\n if (activeIn(next) !== null) {return;}\n if (canRestore(restore, next)) {focusControl(restore);}\n else {focusInitial(next, initial);}\n };\n const refresh = (): HTMLElement | null => {\n const next = menuRoot(options.baseRoot);\n if (next === root) {return next;}\n root = next;\n if (next !== null) {settle(next);}\n return next;\n };\n const keydown = (e: KeyboardEvent): void => {\n if (e.altKey || e.ctrlKey || e.metaKey || suspended()) {return;}\n const r = refresh();\n if (r !== null) {onKey(e, r, initial);}\n };\n const focusin = (e: FocusEvent): void => {\n const t = e.target as HTMLElement;\n if (root !== null && root.contains(t) && t.closest(DIALOG_SELECTOR) === root.closest(DIALOG_SELECTOR)) {lastInRoot = t;}\n };\n const observer = new MutationObserver(() => { refresh(); });\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: [...OBSERVED_ATTRIBUTES] });\n window.addEventListener('keydown', keydown, true);\n window.addEventListener('pointerdown', clearInput, true);\n document.addEventListener('focusin', focusin, true);\n\n return {\n pad: (action: PadAction): void => {\n if (suspended()) {return;}\n markInput(NAV_INPUT.pad);\n onPad(action, refresh(), initial);\n },\n refresh: (): void => { refresh(); },\n dispose: (): void => {\n observer.disconnect();\n window.removeEventListener('keydown', keydown, true);\n window.removeEventListener('pointerdown', clearInput, true);\n document.removeEventListener('focusin', focusin, true);\n clearInput();\n },\n };\n}\n","import type { VibrationPattern } from './types';\r\n\r\n/** Default localStorage key for the haptics on/off preference. */\r\nexport const DEFAULT_HAPTICS_STORAGE_KEY = 'game.haptics';\r\n\r\n/** Default confirmation tick fired when haptics are turned ON (ms). */\r\nexport const DEFAULT_ENABLE_CONFIRMATION = 15;\r\n\r\n/** Stored value meaning \"disabled\". Any other value (or absent) means enabled. */\r\nexport const DISABLED_VALUE = '0';\r\n\r\n/** Stored value meaning \"enabled\". */\r\nexport const ENABLED_VALUE = '1';\r\n\r\n/** DOM events that count as a user activation before `navigator.userActivation` is available. */\r\nexport const USER_ACTIVATION_EVENTS = ['pointerdown', 'keydown', 'touchstart'] as const;\r\n\r\n/** The semantic intents games map their events onto. */\r\nexport type HapticIntent =\r\n | 'tap'\r\n | 'select'\r\n | 'lock'\r\n | 'bump'\r\n | 'navigate'\r\n | 'success'\r\n | 'error'\r\n | 'loss'\r\n | 'reveal';\r\n\r\n/**\r\n * A shared vocabulary of vibration patterns keyed by intent, so every game uses\r\n * the same tuned feel instead of re-picking magic durations. Pass any of these to\r\n * {@link Haptics.vibrate} (or supply your own pattern).\r\n */\r\nexport const HAPTIC_PATTERNS: Record<HapticIntent, VibrationPattern> = {\r\n /** Light tick for menu navigation / selection / undo / restart. */\r\n tap: 10,\r\n /** Light pulse when a tool/charm/item is picked up or selected. */\r\n select: 12,\r\n /** Short pulse when something locks into place. */\r\n lock: 18,\r\n /** Dull buzz when an action is blocked. */\r\n bump: 24,\r\n /** Quick pulse when stepping through a portal / page turn. */\r\n navigate: 16,\r\n /** Celebratory pattern when a level/chamber is cleared. */\r\n success: [0, 40, 50, 90],\r\n /** Sharp double crack for a fatal/destructive event. */\r\n error: [0, 14, 24, 14],\r\n /** Heavier buzz when the player loses / falls. */\r\n loss: [0, 40, 50, 40],\r\n /** Rising triple pulse the instant a puzzle resolves / an exit opens. */\r\n reveal: [0, 14, 20, 18, 26, 24],\r\n};\r\n","import { USER_ACTIVATION_EVENTS } from './constants';\nimport type { ActivationTarget, VibrationCapable } from './types';\n\nfunction resolveActivationTarget(explicit?: ActivationTarget): ActivationTarget | undefined {\n if (explicit) {return explicit;}\n const candidate = globalThis as Partial<ActivationTarget>;\n return typeof candidate.addEventListener === 'function' ? (candidate as ActivationTarget) : undefined;\n}\n\n/** Returns a probe that is true once the page has received a user gesture. */\nexport function createActivationProbe(\n navigator: VibrationCapable | undefined,\n explicitTarget?: ActivationTarget,\n): () => boolean {\n let latched = false;\n const target = typeof navigator?.vibrate === 'function' ? resolveActivationTarget(explicitTarget) : undefined;\n\n const onGesture = (): void => {\n latched = true;\n for (const type of USER_ACTIVATION_EVENTS) {target?.removeEventListener(type, onGesture, true);}\n };\n\n for (const type of USER_ACTIVATION_EVENTS) {target?.addEventListener(type, onGesture, true);}\n\n return (): boolean => latched || navigator?.userActivation?.hasBeenActive === true;\n}\n","import {\r\n DEFAULT_ENABLE_CONFIRMATION,\r\n DEFAULT_HAPTICS_STORAGE_KEY,\r\n DISABLED_VALUE,\r\n ENABLED_VALUE,\r\n} from './constants';\r\nimport type { Haptics, HapticsOptions, HapticsStorage, VibrationCapable, VibrationPattern } from './types';\r\nimport { createActivationProbe } from './userActivation';\r\n\r\nfunction resolveNavigator(explicit?: VibrationCapable): VibrationCapable | undefined {\r\n if (explicit) {\r\n return explicit;\r\n }\r\n return (globalThis as { navigator?: VibrationCapable }).navigator;\r\n}\r\n\r\nfunction resolveStorage(explicit?: HapticsStorage): HapticsStorage | undefined {\r\n if (explicit) {\r\n return explicit;\r\n }\r\n return (globalThis as { localStorage?: HapticsStorage }).localStorage;\r\n}\r\n\r\n/**\r\n * Create a player-toggleable, always-safe haptics controller: it never vibrates before a\r\n * user gesture, while disabled, or when the Vibration API is missing or blocked.\r\n */\r\nexport function createHaptics(options: HapticsOptions = {}): Haptics {\r\n const storageKey = options.storageKey ?? DEFAULT_HAPTICS_STORAGE_KEY;\r\n const confirmation =\r\n options.enableConfirmation === undefined ? DEFAULT_ENABLE_CONFIRMATION : options.enableConfirmation;\r\n const navigator = resolveNavigator(options.navigator);\r\n const storage = resolveStorage(options.storage);\r\n const hasUserActivation = createActivationProbe(navigator, options.activationTarget);\r\n\r\n const readPref = (): boolean => {\r\n try {\r\n return storage?.getItem(storageKey) !== DISABLED_VALUE;\r\n } catch {\r\n return true;\r\n }\r\n };\r\n\r\n let enabled = readPref();\r\n\r\n const vibrate = (pattern: VibrationPattern): void => {\r\n if (!enabled || !hasUserActivation()) {\r\n return;\r\n }\r\n try {\r\n navigator?.vibrate?.(pattern);\r\n } catch {\r\n return;\r\n }\r\n };\r\n\r\n const persist = (): void => {\r\n try {\r\n storage?.setItem(storageKey, enabled ? ENABLED_VALUE : DISABLED_VALUE);\r\n } catch {\r\n return;\r\n }\r\n };\r\n\r\n const setEnabled = (next: boolean): boolean => {\r\n enabled = next;\r\n persist();\r\n if (enabled && confirmation !== null) {\r\n vibrate(confirmation);\r\n }\r\n return enabled;\r\n };\r\n\r\n return {\r\n isEnabled: (): boolean => enabled,\r\n setEnabled,\r\n toggle: (): boolean => setEnabled(!enabled),\r\n vibrate,\r\n };\r\n}\r\n"]}
1
+ {"version":3,"sources":["../src/gamepad/padMap.ts","../src/gamepad/stepPad.ts","../src/gamepad/createGamepadPoller.ts","../src/menu/constants.ts","../src/menu/controlKind.ts","../src/menu/focusables.ts","../src/menu/menuRoot.ts","../src/menu/pickTarget.ts","../src/menu/stepControl.ts","../src/menu/navActions.ts","../src/menu/createMenuNav.ts","../src/menu/menuWalkHook.ts","../src/constants.ts","../src/userActivation.ts","../src/haptics.ts"],"names":[],"mappings":";;;AACO,IAAM,WAAA,GAAc;AAAA,EACzB,EAAA,EAAI,IAAA;AAAA,EACJ,IAAA,EAAM,MAAA;AAAA,EACN,IAAA,EAAM,MAAA;AAAA,EACN,KAAA,EAAO,OAAA;AAAA,EACP,OAAA,EAAS,SAAA;AAAA,EACT,IAAA,EAAM,MAAA;AAAA,EACN,IAAA,EAAM,MAAA;AAAA,EACN,IAAA,EAAM,MAAA;AAAA,EACN,QAAA,EAAU,UAAA;AAAA,EACV,QAAA,EAAU;AACZ;AAIO,IAAM,eAAA,GAAkB;AAAA,EAC7B,KAAA,EAAO,CAAA;AAAA,EACP,IAAA,EAAM,CAAA;AAAA,EACN,IAAA,EAAM,CAAA;AAAA,EACN,KAAA,EAAO,CAAA;AAAA,EACP,YAAA,EAAc,CAAA;AAAA,EACd,aAAA,EAAe,CAAA;AAAA,EACf,MAAA,EAAQ,EAAA;AAAA,EACR,QAAA,EAAU,EAAA;AAAA,EACV,QAAA,EAAU,EAAA;AAAA,EACV,SAAA,EAAW;AACb;AAGO,IAAM,mBAAA,GAAmE;AAAA,EAC9E,CAAC,eAAA,CAAgB,KAAA,EAAO,WAAA,CAAY,OAAO,CAAA;AAAA,EAC3C,CAAC,eAAA,CAAgB,IAAA,EAAM,WAAA,CAAY,IAAI,CAAA;AAAA,EACvC,CAAC,eAAA,CAAgB,IAAA,EAAM,WAAA,CAAY,IAAI,CAAA;AAAA,EACvC,CAAC,eAAA,CAAgB,KAAA,EAAO,WAAA,CAAY,IAAI,CAAA;AAAA,EACxC,CAAC,eAAA,CAAgB,YAAA,EAAc,WAAA,CAAY,QAAQ,CAAA;AAAA,EACnD,CAAC,eAAA,CAAgB,aAAA,EAAe,WAAA,CAAY,QAAQ;AACtD,CAAA;AAGO,IAAM,YAAA,GAA4D;AAAA,EACvE,CAAC,eAAA,CAAgB,MAAA,EAAQ,WAAA,CAAY,EAAE,CAAA;AAAA,EACvC,CAAC,eAAA,CAAgB,QAAA,EAAU,WAAA,CAAY,IAAI,CAAA;AAAA,EAC3C,CAAC,eAAA,CAAgB,QAAA,EAAU,WAAA,CAAY,IAAI,CAAA;AAAA,EAC3C,CAAC,eAAA,CAAgB,SAAA,EAAW,WAAA,CAAY,KAAK;AAC/C,CAAA;AAGO,IAAM,eAAA,GAAkB,GAAA;AAExB,IAAM,eAAA,GAAkB,GAAA;AAExB,IAAM,kBAAA,GAAqB,GAAA;;;AC7B3B,IAAM,cAA2B,EAAE,IAAA,EAAM,MAAM,KAAA,EAAO,CAAA,EAAG,UAAU,CAAA;AAE1E,IAAM,OAAA,GAAU,CAAA;AAChB,IAAM,OAAA,GAAU,CAAA;AAEhB,SAAS,eAAe,IAAA,EAA2C;AACjE,EAAA,MAAM,CAAA,GAAI,IAAA,CAAK,OAAO,CAAA,IAAK,CAAA;AAC3B,EAAA,MAAM,CAAA,GAAI,IAAA,CAAK,OAAO,CAAA,IAAK,CAAA;AAC3B,EAAA,IAAI,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,CAAC,CAAC,CAAA,GAAI,eAAA,EAAiB;AACxD,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,IAAI,KAAK,GAAA,CAAI,CAAC,IAAI,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,EAAG;AAC7B,IAAA,OAAO,CAAA,GAAI,CAAA,GAAI,WAAA,CAAY,KAAA,GAAQ,WAAA,CAAY,IAAA;AAAA,EACjD;AACA,EAAA,OAAO,CAAA,GAAI,CAAA,GAAI,WAAA,CAAY,IAAA,GAAO,WAAA,CAAY,EAAA;AAChD;AAEA,SAAS,cAAc,QAAA,EAAyC;AAC9D,EAAA,MAAM,IAAA,GAAO,YAAA,CAAa,IAAA,CAAK,CAAC,CAAC,KAAK,CAAA,KAAM,QAAA,CAAS,OAAA,CAAQ,KAAK,CAAA,KAAM,IAAI,CAAA;AAC5E,EAAA,OAAO,SAAS,MAAA,GAAY,cAAA,CAAe,SAAS,IAAI,CAAA,GAAI,KAAK,CAAC,CAAA;AACpE;AAGO,SAAS,OAAA,CACd,IAAA,EACA,IAAA,EACA,MAAA,EACA,GAAA,EAC+C;AAC/C,EAAA,MAAM,OAAA,GAAuB,mBAAA,CAC1B,MAAA,CAAO,CAAC,CAAC,KAAK,CAAA,KAAM,IAAA,CAAK,OAAA,CAAQ,KAAK,CAAA,KAAM,IAAA,IAAQ,MAAM,OAAA,CAAQ,KAAK,CAAA,KAAM,IAAI,CAAA,CACjF,GAAA,CAAI,CAAC,GAAG,MAAM,CAAA,KAAM,MAAM,CAAA;AAC7B,EAAA,MAAM,SAAA,GAAY,cAAc,IAAI,CAAA;AACpC,EAAA,IAAI,cAAc,IAAA,EAAM;AACtB,IAAA,OAAO,EAAE,OAAA,EAAS,MAAA,EAAQ,WAAA,EAAY;AAAA,EACxC;AACA,EAAA,IAAI,SAAA,KAAc,OAAO,IAAA,EAAM;AAC7B,IAAA,OAAO,EAAE,OAAA,EAAS,CAAC,GAAG,SAAS,SAAS,CAAA,EAAG,MAAA,EAAQ,EAAE,MAAM,SAAA,EAAW,KAAA,EAAO,GAAA,EAAK,QAAA,EAAU,KAAI,EAAE;AAAA,EACpG;AACA,EAAA,MAAM,WAAA,GAAc,MAAA,CAAO,QAAA,KAAa,MAAA,CAAO,KAAA;AAC/C,EAAA,MAAM,IAAA,GAAO,cAAc,eAAA,GAAkB,kBAAA;AAC7C,EAAA,IAAI,GAAA,GAAM,MAAA,CAAO,QAAA,GAAW,IAAA,EAAM;AAChC,IAAA,OAAO,EAAE,SAAS,MAAA,EAAO;AAAA,EAC3B;AACA,EAAA,OAAO,EAAE,OAAA,EAAS,CAAC,GAAG,OAAA,EAAS,SAAS,CAAA,EAAG,MAAA,EAAQ,EAAE,GAAG,MAAA,EAAQ,QAAA,EAAU,KAAI,EAAE;AAClF;;;AC5CO,SAAS,oBAAoB,IAAA,EAAqE;AACvG,EAAA,IAAI,IAAA,GAA2B,IAAA;AAC/B,EAAA,IAAI,MAAA,GAAsB,WAAA;AAC1B,EAAA,IAAI,OAAA,GAAU,KAAA;AACd,EAAA,IAAI,KAAA,GAAuB,IAAA;AAE3B,EAAA,MAAM,IAAA,GAAO,CAAC,GAAA,KAAsB;AAClC,IAAA,KAAA,GAAQ,IAAA;AACR,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,OAAA,EAAQ,CAAE,IAAA,CAAK,CAAC,CAAA,KAAoB,CAAA,KAAM,IAAA,IAAQ,CAAA,CAAE,SAAS,CAAA;AAC9E,IAAA,IAAI,QAAQ,MAAA,EAAW;AACrB,MAAA,IAAA,GAAO,IAAA;AACP,MAAA,MAAA,GAAS,WAAA;AAAA,IACX,CAAA,MAAO;AACL,MAAA,MAAM,QAAA,GAAwB,EAAE,OAAA,EAAS,GAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,CAAA,EAAG,IAAA,EAAM,IAAI,IAAA,EAAK;AAC3F,MAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,IAAA,EAAM,QAAA,EAAU,QAAQ,GAAG,CAAA;AAChD,MAAA,IAAA,GAAO,QAAA;AACP,MAAA,MAAA,GAAS,IAAA,CAAK,MAAA;AACd,MAAA,IAAA,CAAK,QAAQ,OAAA,CAAQ,CAAC,WAAW,IAAA,CAAK,QAAA,CAAS,MAAM,CAAC,CAAA;AAAA,IACxD;AACA,IAAA,IAAI,OAAA,IAAW,UAAU,IAAA,EAAM;AAC7B,MAAA,KAAA,GAAQ,IAAA,CAAK,aAAa,IAAI,CAAA;AAAA,IAChC;AAAA,EACF,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,OAAO,MAAY;AACjB,MAAA,IAAI,OAAA,EAAS;AACX,QAAA;AAAA,MACF;AACA,MAAA,OAAA,GAAU,IAAA;AACV,MAAA,IAAI,UAAU,IAAA,EAAM;AAClB,QAAA,KAAA,GAAQ,IAAA,CAAK,aAAa,IAAI,CAAA;AAAA,MAChC;AAAA,IACF,CAAA;AAAA,IACA,MAAM,MAAY;AAChB,MAAA,OAAA,GAAU,KAAA;AACV,MAAA,IAAI,UAAU,IAAA,EAAM;AAClB,QAAA,IAAA,CAAK,YAAY,KAAK,CAAA;AACtB,QAAA,KAAA,GAAQ,IAAA;AAAA,MACV;AAAA,IACF;AAAA,GACF;AACF;;;ACjEO,IAAM,uBAAA,GAA0B;AAAA,EACrC,QAAA;AAAA,EACA,SAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA;AAAA,EACA,UAAA;AAAA,EACA,iBAAA;AAAA,EACA,cAAA;AAAA,EACA,iBAAA;AAAA,EACA,iBAAA;AAAA,EACA,iBAAA;AAAA,EACA,mBAAA;AAAA,EACA,gBAAA;AAAA,EACA;AACF,CAAA,CAAE,KAAK,IAAI;AAEJ,IAAM,yBAAA,GAA4B,0CAAA;AAClC,IAAM,eAAA,GAAkB;AACxB,IAAM,wBAAA,GAA2B,yCAAA;AACjC,IAAM,iBAAA,GAAoB;AAC1B,IAAM,cAAA,GAAiB;AACvB,IAAM,SAAA,GAAY,EAAE,GAAA,EAAK,KAAA,EAAO,KAAK,KAAA;AAErC,IAAM,mBAAA,GAAyC,CAAC,QAAA,EAAU,OAAA,EAAS,SAAS,aAAA,EAAe,YAAA,EAAc,SAAS,MAAM,CAAA;AACxH,IAAM,UAAA,GAAa,QAAA;AACnB,IAAM,SAAA,GAAY,OAAA;;;AChBzB,IAAM,kBAAqC,CAAC,QAAA,EAAU,UAAU,OAAA,EAAS,OAAA,EAAS,QAAQ,OAAO,CAAA;AACjG,IAAM,YAAA,GAAkC,CAAC,UAAA,EAAY,QAAA,EAAU,OAAO,CAAA;AAEtE,SAAS,UAAU,EAAA,EAAmC;AACpD,EAAA,MAAM,OAAO,EAAA,CAAG,IAAA;AAChB,EAAA,IAAI,SAAS,OAAA,EAAS;AAAC,IAAA,OAAO,QAAA;AAAA,EAAmB;AACjD,EAAA,IAAI,IAAA,KAAS,UAAA,IAAc,IAAA,KAAS,OAAA,EAAS;AAAC,IAAA,OAAO,QAAA;AAAA,EAAmB;AACxE,EAAA,OAAO,eAAA,CAAgB,QAAA,CAAS,IAAI,CAAA,GAAI,QAAA,gBAAqB,WAAA;AAC/D;AAEO,SAAS,YAAY,EAAA,EAA0B;AACpD,EAAA,IAAI,cAAc,gBAAA,EAAkB;AAAC,IAAA,OAAO,UAAU,EAAE,CAAA;AAAA,EAAE;AAC1D,EAAA,IAAI,cAAc,mBAAA,EAAqB;AAAC,IAAA,OAAO,WAAA;AAAA,EAAsB;AACrE,EAAA,IAAI,cAAc,iBAAA,EAAmB;AAAC,IAAA,OAAO,QAAA;AAAA,EAAmB;AAChE,EAAA,MAAM,IAAA,GAAO,EAAA,CAAG,YAAA,CAAa,MAAM,CAAA,IAAK,EAAA;AACxC,EAAA,IAAI,SAAS,QAAA,EAAU;AAAC,IAAA,OAAO,QAAA;AAAA,EAAmB;AAClD,EAAA,OAAO,YAAA,CAAa,QAAA,CAAS,IAAI,CAAA,GAAI,QAAA,gBAAqB,QAAA;AAC5D;AAEO,IAAM,WAAA,GAAc,CAAC,EAAA,KAAyB,WAAA,CAAY,EAAE,CAAA,KAAM,WAAA;AAElE,SAAS,UAAU,EAAA,EAAsB;AAC9C,EAAA,MAAM,IAAA,GAAO,YAAY,EAAE,CAAA;AAC3B,EAAA,OAAO,IAAA,KAAS,yBAAsB,IAAA,KAAS,QAAA;AACjD;AAEO,SAAS,oBAAoB,EAAA,EAAsB;AACxD,EAAA,MAAM,IAAA,GAAO,YAAY,EAAE,CAAA;AAC3B,EAAA,MAAM,SAAA,GAAY,IAAA,KAAS,QAAA,iBAAsB,IAAA,KAAS,QAAA;AAC1D,EAAA,OAAO,SAAA,IAAa,CAAC,EAAA,CAAG,OAAA,CAAQ,yBAAyB,CAAA;AAC3D;;;ACrCO,SAAS,QAAQ,EAAA,EAAsB;AAC5C,EAAA,OAAO,EAAA,CAAG,gBAAe,CAAE,MAAA,GAAS,KAAK,EAAA,CAAG,OAAA,CAAQ,wBAAwB,CAAA,KAAM,IAAA;AACpF;AAEA,IAAM,UAAA,GAAa,CAAC,EAAA,KAA0B,EAAA,CAA8B,QAAA,KAAa,IAAA;AAGlF,SAAS,WAAW,IAAA,EAAkC;AAC3D,EAAA,OAAO,MAAM,IAAA,CAAK,IAAA,CAAK,gBAAA,CAA8B,uBAAuB,CAAC,CAAA,CAAE,MAAA,CAAO,CAAC,EAAA,KAAO,QAAQ,EAAE,CAAA,IAAK,CAAC,UAAA,CAAW,EAAE,CAAC,CAAA;AAC9H;AAGO,SAAS,oBAAoB,IAAA,EAAuC;AACzE,EAAA,MAAM,IAAA,GAAO,WAAW,IAAI,CAAA;AAC5B,EAAA,OAAO,IAAA,CAAK,IAAA,CAAK,CAAC,EAAA,KAAO,EAAA,CAAG,YAAA,CAAa,iBAAiB,CAAC,CAAA,IAAK,IAAA,CAAK,CAAC,CAAA,IAAK,IAAA;AAC7E;;;ACdO,SAAS,SAAS,QAAA,EAAwD;AAC/E,EAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,QAAA,CAAS,iBAA8B,eAAe,CAAC,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA;AAClG,EAAA,MAAM,KAAA,GAAQ,QAAQ,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,YAAA,CAAa,YAAY,CAAA,KAAM,MAAM,CAAA;AAC3E,EAAA,MAAM,OAAO,KAAA,CAAM,MAAA,GAAS,CAAA,GAAI,KAAA,GAAQ,SAAS,GAAA,EAAI;AACrD,EAAA,IAAI,QAAQ,MAAA,EAAW;AAAC,IAAA,OAAO,GAAA;AAAA,EAAI;AACnC,EAAA,MAAM,OAAO,QAAA,EAAS;AACtB,EAAA,OAAO,IAAA,KAAS,IAAA,IAAQ,OAAA,CAAQ,IAAI,IAAI,IAAA,GAAO,IAAA;AACjD;;;ACTO,IAAM,QAAA,GAAW,EAAE,EAAA,EAAI,SAAA,EAAW,MAAM,WAAA,EAAa,IAAA,EAAM,WAAA,EAAa,KAAA,EAAO,YAAA;AAGtF,IAAM,QAAA,GAA8B,MAAA,CAAO,MAAA,CAAO,QAAQ,CAAA;AAC1D,IAAM,YAAA,GAAe,CAAA;AACrB,IAAM,KAAA,GAAQ,CAAA;AAGP,IAAM,MAAA,GAAS,CAAC,GAAA,KAAgC,QAAA,CAAS,QAAA,CAAS,GAAA,CAAI,WAAA,EAAa,CAAA,GAAK,GAAA,CAAI,WAAA,EAAY,GAAe;AAE9H,IAAM,MAAA,GAAS,CAAC,CAAA,MAAwC,EAAE,IAAI,CAAA,CAAE,CAAA,GAAI,CAAA,CAAE,CAAA,GAAI,GAAG,EAAA,EAAI,CAAA,CAAE,CAAA,GAAI,CAAA,CAAE,IAAI,CAAA,EAAE,CAAA;AAE/F,SAAS,IAAA,CAAK,CAAA,EAAQ,CAAA,EAAQ,GAAA,EAA4B;AACxD,EAAA,MAAM,CAAA,GAAI,OAAO,CAAC,CAAA;AAClB,EAAA,MAAM,CAAA,GAAI,OAAO,CAAC,CAAA;AAClB,EAAA,MAAM,EAAA,GAAK,CAAA,CAAE,EAAA,GAAK,CAAA,CAAE,EAAA;AACpB,EAAA,MAAM,EAAA,GAAK,CAAA,CAAE,EAAA,GAAK,CAAA,CAAE,EAAA;AACpB,EAAA,MAAM,QAAA,GAAW,GAAA,KAAQ,QAAA,CAAS,EAAA,IAAM,QAAQ,QAAA,CAAS,IAAA;AACzD,EAAA,MAAM,KAAA,GAAQ,QAAA,GAAY,GAAA,KAAQ,QAAA,CAAS,IAAA,GAAO,EAAA,GAAK,CAAC,EAAA,GAAM,GAAA,KAAQ,QAAA,CAAS,KAAA,GAAQ,EAAA,GAAK,CAAC,EAAA;AAC7F,EAAA,IAAI,SAAS,KAAA,EAAO;AAAC,IAAA,OAAO,IAAA;AAAA,EAAK;AACjC,EAAA,OAAO,QAAQ,YAAA,GAAe,IAAA,CAAK,GAAA,CAAI,QAAA,GAAW,KAAK,EAAE,CAAA;AAC3D;AAGO,SAAS,UAAA,CAAW,KAAA,EAAuB,IAAA,EAAc,GAAA,EAAqB;AACnF,EAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AAAC,IAAA,OAAO,EAAA;AAAA,EAAG;AACnC,EAAA,IAAI,IAAA,GAAO,CAAA,IAAK,IAAA,IAAQ,KAAA,CAAM,MAAA,EAAQ;AAAC,IAAA,OAAO,CAAA;AAAA,EAAE;AAChD,EAAA,MAAM,MAAA,GAAS,MAAM,IAAI,CAAA;AACzB,EAAA,IAAI,IAAA,GAAO,EAAA;AACX,EAAA,IAAI,QAAA,GAAW,QAAA;AACf,EAAA,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA,EAAG,CAAA,KAAM;AACtB,IAAA,MAAM,IAAI,CAAA,KAAM,IAAA,GAAO,OAAO,IAAA,CAAK,MAAA,EAAQ,GAAG,GAAG,CAAA;AACjD,IAAA,IAAI,CAAA,KAAM,IAAA,IAAQ,CAAA,GAAI,QAAA,EAAU;AAC9B,MAAA,IAAA,GAAO,CAAA;AACP,MAAA,QAAA,GAAW,CAAA;AAAA,IACb;AAAA,EACF,CAAC,CAAA;AACD,EAAA,IAAI,QAAQ,CAAA,EAAG;AAAC,IAAA,OAAO,IAAA;AAAA,EAAK;AAC5B,EAAA,MAAM,OAAO,GAAA,KAAQ,QAAA,CAAS,QAAQ,GAAA,KAAQ,QAAA,CAAS,QAAQ,CAAA,GAAI,EAAA;AACnE,EAAA,OAAA,CAAQ,IAAA,GAAO,IAAA,GAAO,KAAA,CAAM,MAAA,IAAU,KAAA,CAAM,MAAA;AAC9C;;;AC1CA,IAAM,WAAA,GAAc,GAAA;AAEpB,IAAM,GAAA,GAAM,CAAC,GAAA,EAAoB,QAAA,KAA6B;AAC5D,EAAA,MAAM,CAAA,GAAI,UAAA,CAAW,GAAA,IAAO,EAAE,CAAA;AAC9B,EAAA,OAAO,MAAA,CAAO,QAAA,CAAS,CAAC,CAAA,GAAI,CAAA,GAAI,QAAA;AAClC,CAAA;AAEA,SAAS,SAAA,CAAU,KAAA,EAAe,KAAA,EAAe,GAAA,EAAa,KAAa,IAAA,EAAsB;AAC/F,EAAA,MAAM,QAAA,GAAA,CAAY,OAAO,IAAI,CAAA,CAAE,MAAM,GAAG,CAAA,CAAE,CAAC,CAAA,IAAK,EAAA,EAAI,MAAA;AACpD,EAAA,OAAO,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,IAAA,CAAK,IAAI,GAAA,EAAK,MAAA,CAAA,CAAQ,KAAA,GAAQ,KAAA,GAAQ,IAAA,EAAM,OAAA,CAAQ,QAAQ,CAAC,CAAC,CAAC,CAAA;AACtF;AAEA,SAAS,KAAA,CAAM,EAAA,EAAiB,OAAA,EAAiB,IAAA,EAAc,KAAA,EAAkC;AAC/F,EAAA,IAAI,SAAS,OAAA,EAAS;AAAC,IAAA;AAAA,EAAO;AAC9B,EAAA,KAAA,CAAM,IAAI,CAAA;AACV,EAAA,EAAA,CAAG,aAAA,CAAc,IAAI,KAAA,CAAM,OAAA,EAAS,EAAE,OAAA,EAAS,IAAA,EAAM,CAAC,CAAA;AACtD,EAAA,EAAA,CAAG,aAAA,CAAc,IAAI,KAAA,CAAM,QAAA,EAAU,EAAE,OAAA,EAAS,IAAA,EAAM,CAAC,CAAA;AACzD;AAGO,SAAS,WAAA,CAAY,IAAiB,KAAA,EAAqB;AAChE,EAAA,IAAI,cAAc,gBAAA,EAAkB;AAClC,IAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,EAAA,CAAG,KAAA,EAAO,CAAC,CAAA;AAC7B,IAAA,MAAM,OAAO,SAAA,CAAU,KAAA,EAAO,OAAO,GAAA,CAAI,EAAA,CAAG,KAAK,CAAC,CAAA,EAAG,GAAA,CAAI,EAAA,CAAG,KAAK,WAAW,CAAA,EAAG,IAAI,EAAA,CAAG,IAAA,EAAM,CAAC,CAAC,CAAA;AAC9F,IAAA,KAAA,CAAM,EAAA,EAAI,KAAA,EAAO,IAAA,EAAM,CAAC,CAAA,KAAM;AAAE,MAAA,EAAA,CAAG,KAAA,GAAQ,OAAO,CAAC,CAAA;AAAA,IAAG,CAAC,CAAA;AAAA,EACzD,CAAA,MAAA,IAAW,cAAc,iBAAA,EAAmB;AAC1C,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,EAAA,CAAG,OAAA,CAAQ,MAAA,GAAS,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,EAAA,CAAG,aAAA,GAAgB,KAAK,CAAC,CAAA;AAClF,IAAA,KAAA,CAAM,EAAA,EAAI,EAAA,CAAG,aAAA,EAAe,IAAA,EAAM,CAAC,CAAA,KAAM;AAAE,MAAA,EAAA,CAAG,aAAA,GAAgB,CAAA;AAAA,IAAG,CAAC,CAAA;AAAA,EACpE,CAAA,MAAO;AACL,IAAA,MAAM,QAAQ,GAAA,CAAI,EAAA,CAAG,YAAA,CAAa,eAAe,GAAG,CAAC,CAAA;AACrD,IAAA,MAAM,IAAA,GAAO,SAAA,CAAU,KAAA,EAAO,KAAA,EAAO,GAAA,CAAI,GAAG,YAAA,CAAa,eAAe,CAAA,EAAG,CAAC,CAAA,EAAG,GAAA,CAAI,GAAG,YAAA,CAAa,eAAe,CAAA,EAAG,WAAW,CAAA,EAAG,GAAA,CAAI,GAAG,YAAA,CAAa,WAAW,CAAA,EAAG,CAAC,CAAC,CAAA;AACvK,IAAA,KAAA,CAAM,EAAA,EAAI,KAAA,EAAO,IAAA,EAAM,CAAC,CAAA,KAAM,EAAA,CAAG,YAAA,CAAa,eAAA,EAAiB,MAAA,CAAO,CAAC,CAAC,CAAC,CAAA;AAAA,EAC3E;AACF;;;ACzBA,IAAM,KAAA,GAAQ,CAAC,EAAA,KAAqB;AAClC,EAAA,MAAM,CAAA,GAAI,GAAG,qBAAA,EAAsB;AACnC,EAAA,OAAO,EAAE,CAAA,EAAG,CAAA,CAAE,IAAA,EAAM,CAAA,EAAG,CAAA,CAAE,GAAA,EAAK,CAAA,EAAG,CAAA,CAAE,KAAA,EAAO,CAAA,EAAG,CAAA,CAAE,MAAA,EAAO;AACxD,CAAA;AAGO,SAAS,aAAa,EAAA,EAAuB;AAClD,EAAA,IAAI,CAAC,GAAG,OAAA,CAAQ,yBAAyB,KAAK,CAAC,EAAA,CAAG,YAAA,CAAa,UAAU,CAAA,EAAG;AAAC,IAAA,EAAA,CAAG,YAAA,CAAa,YAAY,IAAI,CAAA;AAAA,EAAE;AAC/G,EAAA,EAAA,CAAG,KAAA,CAAM,EAAE,aAAA,EAAe,IAAA,EAAM,CAAA;AAChC,EAAA,IAAI,OAAO,EAAA,CAAG,cAAA,KAAmB,UAAA,EAAY;AAAC,IAAA,EAAA,CAAG,cAAA,CAAe,EAAE,KAAA,EAAO,SAAA,EAAW,CAAA;AAAA,EAAE;AACxF;AAEO,SAAS,SAAS,IAAA,EAAuC;AAC9D,EAAA,MAAM,IAAI,QAAA,CAAS,aAAA;AACnB,EAAA,OAAO,CAAA,YAAa,eAAe,CAAA,KAAM,IAAA,IAAQ,KAAK,QAAA,CAAS,CAAC,IAAI,CAAA,GAAI,IAAA;AAC1E;AAEO,SAAS,YAAA,CAAa,MAAmB,OAAA,EAAgC;AAC9E,EAAA,MAAM,MAAA,GAAS,QAAQ,IAAI,CAAA;AAC3B,EAAA,IAAI,WAAW,IAAA,EAAM;AAAC,IAAA,OAAO,KAAA;AAAA,EAAM;AACnC,EAAA,YAAA,CAAa,MAAM,CAAA;AACnB,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,SAAA,CAAU,IAAA,EAAmB,MAAA,EAA4B,GAAA,EAAa,OAAA,EAAgC;AAC7G,EAAA,MAAM,IAAA,GAAO,WAAW,IAAI,CAAA;AAC5B,EAAA,MAAM,OAAO,MAAA,KAAW,IAAA,GAAO,EAAA,GAAK,IAAA,CAAK,QAAQ,MAAM,CAAA;AACvD,EAAA,IAAI,OAAO,CAAA,EAAG;AAAC,IAAA,OAAO,YAAA,CAAa,MAAM,OAAO,CAAA;AAAA,EAAE;AAClD,EAAA,YAAA,CAAa,IAAA,CAAK,WAAW,IAAA,CAAK,GAAA,CAAI,KAAK,CAAA,EAAG,IAAA,EAAM,GAAG,CAAC,CAAgB,CAAA;AACxE,EAAA,OAAO,IAAA;AACT;AAGO,SAAS,MAAA,CAAO,IAAA,EAAmB,MAAA,EAA4B,GAAA,EAAa,OAAA,EAAgC;AACjH,EAAA,MAAM,UAAA,GAAa,GAAA,KAAQ,QAAA,CAAS,IAAA,IAAQ,QAAQ,QAAA,CAAS,KAAA;AAC7D,EAAA,IAAI,MAAA,KAAW,IAAA,IAAQ,UAAA,IAAc,SAAA,CAAU,MAAM,CAAA,EAAG;AACtD,IAAA,WAAA,CAAY,MAAA,EAAQ,GAAA,KAAQ,QAAA,CAAS,KAAA,GAAQ,IAAI,EAAE,CAAA;AACnD,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,SAAA,CAAU,IAAA,EAAM,MAAA,EAAQ,GAAA,EAAK,OAAO,CAAA;AAC7C;AAGO,SAAS,UAAA,CAAW,MAAmB,KAAA,EAA0B;AACtE,EAAA,MAAM,IAAA,GAAO,WAAW,IAAI,CAAA;AAC5B,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,UAAA,CAAW,IAAA,CAAK,GAAA,CAAI,KAAK,CAAA,EAAG,IAAA,CAAK,OAAA,CAAQ,KAAK,CAAA,EAAG,QAAA,CAAS,IAAI,CAAC,CAAA;AACjF,EAAA,IAAI,IAAA,KAAS,KAAA,IAAS,IAAA,KAAS,MAAA,EAAW;AACxC,IAAA,KAAA,CAAM,IAAA,EAAK;AACX,IAAA;AAAA,EACF;AACA,EAAA,YAAA,CAAa,IAAI,CAAA;AACnB;;;AChCA,IAAM,QAAA,GAA+C,EAAE,EAAA,EAAI,QAAA,CAAS,EAAA,EAAI,IAAA,EAAM,QAAA,CAAS,IAAA,EAAM,IAAA,EAAM,QAAA,CAAS,IAAA,EAAM,KAAA,EAAO,SAAS,KAAA,EAAM;AAExI,IAAM,SAAS,CAAC,EAAA,KAA6B,EAAA,CAAG,WAAA,IAAe,QAAQ,EAAE,CAAA;AACzE,IAAM,YAAY,CAAC,IAAA,KAAyB,SAAS,eAAA,CAAgB,YAAA,CAAa,gBAAgB,IAAI,CAAA;AACtG,IAAM,UAAA,GAAa,MAAY,QAAA,CAAS,eAAA,CAAgB,gBAAgB,cAAc,CAAA;AACtF,IAAM,UAAA,GAAa,MAAgB,CAAC,QAAA,CAAS,aAAA,EAAe,MAAM,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,KAAM,IAAI,EAAkB,aAAA,CAAc,IAAI,aAAA,CAAc,SAAA,EAAW,EAAE,GAAA,EAAK,UAAA,EAAY,OAAA,EAAS,IAAA,EAAM,UAAA,EAAY,IAAA,EAAM,CAAC,CAAA;AAE5M,SAAS,UAAU,KAAA,EAAyC;AAC1D,EAAA,IAAI,OAAA,GAA8B,IAAA;AAClC,EAAA,OAAO,KAAA,CAAM,MAAA,GAAS,CAAA,IAAK,CAAC,MAAA,CAAQ,KAAA,CAAM,KAAA,CAAM,MAAA,GAAS,CAAC,CAAA,CAAiB,MAAM,CAAA,EAAG;AAAC,IAAA,OAAA,GAAW,KAAA,CAAM,KAAI,CAAiB,OAAA;AAAA,EAAQ;AACnI,EAAA,OAAO,OAAA;AACT;AAEA,SAAS,UAAA,CAAW,SAA6B,IAAA,EAA2C;AAC1F,EAAA,OAAO,OAAA,KAAY,QAAQ,OAAA,CAAQ,WAAA,IAAe,KAAK,QAAA,CAAS,OAAO,CAAA,IAAK,OAAA,CAAQ,OAAO,CAAA;AAC7F;AAEA,SAAS,KAAA,CAAM,CAAA,EAAkB,IAAA,EAAmB,OAAA,EAAuD;AACzG,EAAA,MAAM,MAAA,GAAS,SAAS,IAAI,CAAA;AAC5B,EAAA,MAAM,GAAA,GAAM,MAAA,CAAO,CAAA,CAAE,GAAG,CAAA;AACxB,EAAA,IAAI,CAAA,CAAE,QAAQ,UAAA,EAAY;AACxB,IAAA,IAAI,MAAA,KAAW,IAAA,IAAQ,CAAC,WAAA,CAAY,MAAM,CAAA,EAAG;AAAC,MAAA;AAAA,IAAO;AACrD,IAAA,CAAA,CAAE,cAAA,EAAe;AACjB,IAAA,CAAA,CAAE,wBAAA,EAAyB;AAC3B,IAAA,UAAA,CAAW,MAAM,MAAM,CAAA;AAAA,EACzB,CAAA,MAAA,IAAW,CAAA,CAAE,GAAA,KAAQ,SAAA,EAAW;AAC9B,IAAA,IAAI,MAAA,KAAW,IAAA,IAAQ,CAAC,mBAAA,CAAoB,MAAM,CAAA,EAAG;AAAC,MAAA;AAAA,IAAO;AAC7D,IAAA,CAAA,CAAE,cAAA,EAAe;AACjB,IAAA,MAAA,CAAO,KAAA,EAAM;AAAA,EACf,CAAA,MAAA,IAAW,QAAQ,IAAA,EAAM;AACvB,IAAA,SAAA,CAAU,UAAU,GAAG,CAAA;AACvB,IAAA,IAAI,MAAA,KAAW,IAAA,IAAQ,WAAA,CAAY,MAAM,CAAA,EAAG;AAAC,MAAA;AAAA,IAAO;AACpD,IAAA,IAAI,MAAA,CAAO,IAAA,EAAM,MAAA,EAAQ,GAAA,EAAK,OAAO,CAAA,EAAG;AAAC,MAAA,CAAA,CAAE,cAAA,EAAe;AAAA,IAAE;AAAA,EAC9D;AACF;AAEA,SAAS,KAAA,CAAM,MAAA,EAAmB,IAAA,EAA0B,OAAA,EAAuD;AACjH,EAAA,MAAM,MAAA,GAAS,IAAA,KAAS,IAAA,GAAO,IAAA,GAAO,SAAS,IAAI,CAAA;AACnD,EAAA,MAAM,GAAA,GAAM,SAAS,MAAM,CAAA;AAC3B,EAAA,IAAI,MAAA,KAAW,YAAY,IAAA,EAAM;AAC/B,IAAA,IAAI,SAAS,IAAA,IAAQ,MAAA,KAAW,IAAA,IAAQ,WAAA,CAAY,MAAM,CAAA,EAAG;AAAC,MAAA,UAAA,CAAW,MAAM,MAAM,CAAA;AAAA,IAAE,CAAA,MAClF;AAAC,MAAA,UAAA,EAAW;AAAA,IAAE;AAAA,EACrB,CAAA,MAAA,IAAW,SAAS,IAAA,EAAM;AACxB,IAAA;AAAA,EACF,CAAA,MAAA,IAAW,QAAQ,MAAA,EAAW;AAC5B,IAAA,MAAA,CAAO,IAAA,EAAM,MAAA,EAAQ,GAAA,EAAK,OAAO,CAAA;AAAA,EACnC,CAAA,MAAA,IAAW,MAAA,KAAW,WAAA,CAAY,OAAA,EAAS;AACzC,IAAA,IAAI,WAAW,IAAA,EAAM;AAAC,MAAA,YAAA,CAAa,MAAM,OAAO,CAAA;AAAA,IAAE,CAAA,MAAA,IACzC,WAAA,CAAY,MAAM,CAAA,EAAG;AAAC,MAAA,YAAA,CAAa,MAAM,CAAA;AAAA,IAAE,CAAA,MAC/C;AAAC,MAAA,MAAA,CAAO,KAAA,EAAM;AAAA,IAAE;AAAA,EACvB;AACF;AAGO,SAAS,cAAc,OAAA,EAAkC;AAC9D,EAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,SAAA,KAAc,MAAe,KAAA,CAAA;AACvD,EAAA,MAAM,OAAA,GAAU,QAAQ,YAAA,IAAgB,mBAAA;AACxC,EAAA,MAAM,QAAsB,EAAC;AAC7B,EAAA,IAAI,IAAA,GAAO,QAAA,CAAS,OAAA,CAAQ,QAAQ,CAAA;AACpC,EAAA,IAAI,UAAA,GAAiC,IAAA;AAErC,EAAA,MAAM,MAAA,GAAS,CAAC,IAAA,KAA4B;AAC1C,IAAA,MAAM,OAAA,GAAU,UAAU,KAAK,CAAA;AAC/B,IAAA,IAAI,IAAA,CAAK,OAAA,CAAQ,eAAe,CAAA,IAAK,CAAC,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,MAAA,KAAW,IAAI,CAAA,EAAG;AAAC,MAAA,KAAA,CAAM,KAAK,EAAE,MAAA,EAAQ,IAAA,EAAM,OAAA,EAAS,YAAY,CAAA;AAAA,IAAE;AAC/H,IAAA,IAAI,QAAA,CAAS,IAAI,CAAA,KAAM,IAAA,EAAM;AAAC,MAAA;AAAA,IAAO;AACrC,IAAA,IAAI,UAAA,CAAW,OAAA,EAAS,IAAI,CAAA,EAAG;AAAC,MAAA,YAAA,CAAa,OAAO,CAAA;AAAA,IAAE,CAAA,MACjD;AAAC,MAAA,YAAA,CAAa,MAAM,OAAO,CAAA;AAAA,IAAE;AAAA,EACpC,CAAA;AACA,EAAA,MAAM,UAAU,MAA0B;AACxC,IAAA,MAAM,IAAA,GAAO,QAAA,CAAS,OAAA,CAAQ,QAAQ,CAAA;AACtC,IAAA,IAAI,SAAS,IAAA,EAAM;AAAC,MAAA,OAAO,IAAA;AAAA,IAAK;AAChC,IAAA,IAAA,GAAO,IAAA;AACP,IAAA,IAAI,SAAS,IAAA,EAAM;AAAC,MAAA,MAAA,CAAO,IAAI,CAAA;AAAA,IAAE;AACjC,IAAA,OAAO,IAAA;AAAA,EACT,CAAA;AACA,EAAA,MAAM,OAAA,GAAU,CAAC,CAAA,KAA2B;AAC1C,IAAA,IAAI,EAAE,MAAA,IAAU,CAAA,CAAE,WAAW,CAAA,CAAE,OAAA,IAAW,WAAU,EAAG;AAAC,MAAA;AAAA,IAAO;AAC/D,IAAA,MAAM,IAAI,OAAA,EAAQ;AAClB,IAAA,IAAI,MAAM,IAAA,EAAM;AAAC,MAAA,KAAA,CAAM,CAAA,EAAG,GAAG,OAAO,CAAA;AAAA,IAAE;AAAA,EACxC,CAAA;AACA,EAAA,MAAM,OAAA,GAAU,CAAC,CAAA,KAAwB;AACvC,IAAA,MAAM,IAAI,CAAA,CAAE,MAAA;AACZ,IAAA,IAAI,IAAA,KAAS,IAAA,IAAQ,IAAA,CAAK,QAAA,CAAS,CAAC,CAAA,IAAK,CAAA,CAAE,OAAA,CAAQ,eAAe,CAAA,KAAM,IAAA,CAAK,OAAA,CAAQ,eAAe,CAAA,EAAG;AAAC,MAAA,UAAA,GAAa,CAAA;AAAA,IAAE;AAAA,EACzH,CAAA;AACA,EAAA,MAAM,QAAA,GAAW,IAAI,gBAAA,CAAiB,MAAM;AAAE,IAAA,OAAA,EAAQ;AAAA,EAAG,CAAC,CAAA;AAC1D,EAAA,QAAA,CAAS,OAAA,CAAQ,QAAA,CAAS,IAAA,EAAM,EAAE,WAAW,IAAA,EAAM,OAAA,EAAS,IAAA,EAAM,UAAA,EAAY,MAAM,eAAA,EAAiB,CAAC,GAAG,mBAAmB,GAAG,CAAA;AAC/H,EAAA,MAAA,CAAO,gBAAA,CAAiB,SAAA,EAAW,OAAA,EAAS,IAAI,CAAA;AAChD,EAAA,MAAA,CAAO,gBAAA,CAAiB,aAAA,EAAe,UAAA,EAAY,IAAI,CAAA;AACvD,EAAA,QAAA,CAAS,gBAAA,CAAiB,SAAA,EAAW,OAAA,EAAS,IAAI,CAAA;AAElD,EAAA,OAAO;AAAA,IACL,GAAA,EAAK,CAAC,MAAA,KAA4B;AAChC,MAAA,IAAI,WAAU,EAAG;AAAC,QAAA;AAAA,MAAO;AACzB,MAAA,SAAA,CAAU,UAAU,GAAG,CAAA;AACvB,MAAA,KAAA,CAAM,MAAA,EAAQ,OAAA,EAAQ,EAAG,OAAO,CAAA;AAAA,IAClC,CAAA;AAAA,IACA,SAAS,MAAY;AAAE,MAAA,OAAA,EAAQ;AAAA,IAAG,CAAA;AAAA,IAClC,SAAS,MAAY;AACnB,MAAA,QAAA,CAAS,UAAA,EAAW;AACpB,MAAA,MAAA,CAAO,mBAAA,CAAoB,SAAA,EAAW,OAAA,EAAS,IAAI,CAAA;AACnD,MAAA,MAAA,CAAO,mBAAA,CAAoB,aAAA,EAAe,UAAA,EAAY,IAAI,CAAA;AAC1D,MAAA,QAAA,CAAS,mBAAA,CAAoB,SAAA,EAAW,OAAA,EAAS,IAAI,CAAA;AACrD,MAAA,UAAA,EAAW;AAAA,IACb;AAAA,GACF;AACF;;;ACnIO,IAAM,cAAA,GAAiB;AAevB,SAAS,mBAAA,CAAoB,IAAA,EAAoB,MAAA,GAAiB,UAAA,EAAwB;AAC/F,EAAA,MAAM,IAAA,GAAO,MAAA;AACb,EAAA,IAAA,CAAK,cAAc,CAAA,GAAI,IAAA;AACvB,EAAA,OAAO,MAAM;AACX,IAAA,IAAI,IAAA,CAAK,cAAc,CAAA,KAAM,IAAA,EAAM;AAAC,MAAA,OAAO,KAAK,cAAc,CAAA;AAAA,IAAE;AAAA,EAClE,CAAA;AACF;;;ACnBO,IAAM,2BAAA,GAA8B;AAGpC,IAAM,2BAAA,GAA8B;AAGpC,IAAM,cAAA,GAAiB,GAAA;AAGvB,IAAM,aAAA,GAAgB,GAAA;AAGtB,IAAM,sBAAA,GAAyB,CAAC,aAAA,EAAe,SAAA,EAAW,YAAY;AAmBtE,IAAM,eAAA,GAA0D;AAAA;AAAA,EAErE,GAAA,EAAK,EAAA;AAAA;AAAA,EAEL,MAAA,EAAQ,EAAA;AAAA;AAAA,EAER,IAAA,EAAM,EAAA;AAAA;AAAA,EAEN,IAAA,EAAM,EAAA;AAAA;AAAA,EAEN,QAAA,EAAU,EAAA;AAAA;AAAA,EAEV,OAAA,EAAS,CAAC,CAAA,EAAG,EAAA,EAAI,IAAI,EAAE,CAAA;AAAA;AAAA,EAEvB,KAAA,EAAO,CAAC,CAAA,EAAG,EAAA,EAAI,IAAI,EAAE,CAAA;AAAA;AAAA,EAErB,IAAA,EAAM,CAAC,CAAA,EAAG,EAAA,EAAI,IAAI,EAAE,CAAA;AAAA;AAAA,EAEpB,QAAQ,CAAC,CAAA,EAAG,IAAI,EAAA,EAAI,EAAA,EAAI,IAAI,EAAE;AAChC;;;AClDA,SAAS,wBAAwB,QAAA,EAA2D;AAC1F,EAAA,IAAI,QAAA,EAAU;AAAC,IAAA,OAAO,QAAA;AAAA,EAAS;AAC/B,EAAA,MAAM,SAAA,GAAY,UAAA;AAClB,EAAA,OAAO,OAAO,SAAA,CAAU,gBAAA,KAAqB,UAAA,GAAc,SAAA,GAAiC,MAAA;AAC9F;AAGO,SAAS,qBAAA,CACd,WACA,cAAA,EACe;AACf,EAAA,IAAI,OAAA,GAAU,KAAA;AACd,EAAA,MAAM,SAAS,OAAO,SAAA,EAAW,YAAY,UAAA,GAAa,uBAAA,CAAwB,cAAc,CAAA,GAAI,MAAA;AAEpG,EAAA,MAAM,YAAY,MAAY;AAC5B,IAAA,OAAA,GAAU,IAAA;AACV,IAAA,KAAA,MAAW,QAAQ,sBAAA,EAAwB;AAAC,MAAA,MAAA,EAAQ,mBAAA,CAAoB,IAAA,EAAM,SAAA,EAAW,IAAI,CAAA;AAAA,IAAE;AAAA,EACjG,CAAA;AAEA,EAAA,KAAA,MAAW,QAAQ,sBAAA,EAAwB;AAAC,IAAA,MAAA,EAAQ,gBAAA,CAAiB,IAAA,EAAM,SAAA,EAAW,IAAI,CAAA;AAAA,EAAE;AAE5F,EAAA,OAAO,MAAe,OAAA,IAAW,SAAA,EAAW,cAAA,EAAgB,aAAA,KAAkB,IAAA;AAChF;;;AChBA,SAAS,iBAAiB,QAAA,EAA2D;AACnF,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,OAAO,QAAA;AAAA,EACT;AACA,EAAA,OAAQ,UAAA,CAAgD,SAAA;AAC1D;AAEA,SAAS,eAAe,QAAA,EAAuD;AAC7E,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,OAAO,QAAA;AAAA,EACT;AACA,EAAA,OAAQ,UAAA,CAAiD,YAAA;AAC3D;AAMO,SAAS,aAAA,CAAc,OAAA,GAA0B,EAAC,EAAY;AACnE,EAAA,MAAM,UAAA,GAAa,QAAQ,UAAA,IAAc,2BAAA;AACzC,EAAA,MAAM,YAAA,GACJ,OAAA,CAAQ,kBAAA,KAAuB,MAAA,GAAY,8BAA8B,OAAA,CAAQ,kBAAA;AACnF,EAAA,MAAM,SAAA,GAAY,gBAAA,CAAiB,OAAA,CAAQ,SAAS,CAAA;AACpD,EAAA,MAAM,OAAA,GAAU,cAAA,CAAe,OAAA,CAAQ,OAAO,CAAA;AAC9C,EAAA,MAAM,iBAAA,GAAoB,qBAAA,CAAsB,SAAA,EAAW,OAAA,CAAQ,gBAAgB,CAAA;AAEnF,EAAA,MAAM,WAAW,MAAe;AAC9B,IAAA,IAAI;AACF,MAAA,OAAO,OAAA,EAAS,OAAA,CAAQ,UAAU,CAAA,KAAM,cAAA;AAAA,IAC1C,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF,CAAA;AAEA,EAAA,IAAI,UAAU,QAAA,EAAS;AAEvB,EAAA,MAAM,OAAA,GAAU,CAAC,OAAA,KAAoC;AACnD,IAAA,IAAI,CAAC,OAAA,IAAW,CAAC,iBAAA,EAAkB,EAAG;AACpC,MAAA;AAAA,IACF;AACA,IAAA,IAAI;AACF,MAAA,SAAA,EAAW,UAAU,OAAO,CAAA;AAAA,IAC9B,CAAA,CAAA,MAAQ;AACN,MAAA;AAAA,IACF;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,UAAU,MAAY;AAC1B,IAAA,IAAI;AACF,MAAA,OAAA,EAAS,OAAA,CAAQ,UAAA,EAAY,OAAA,GAAU,aAAA,GAAgB,cAAc,CAAA;AAAA,IACvE,CAAA,CAAA,MAAQ;AACN,MAAA;AAAA,IACF;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,UAAA,GAAa,CAAC,IAAA,KAA2B;AAC7C,IAAA,OAAA,GAAU,IAAA;AACV,IAAA,OAAA,EAAQ;AACR,IAAA,IAAI,OAAA,IAAW,iBAAiB,IAAA,EAAM;AACpC,MAAA,OAAA,CAAQ,YAAY,CAAA;AAAA,IACtB;AACA,IAAA,OAAO,OAAA;AAAA,EACT,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,WAAW,MAAe,OAAA;AAAA,IAC1B,UAAA;AAAA,IACA,MAAA,EAAQ,MAAe,UAAA,CAAW,CAAC,OAAO,CAAA;AAAA,IAC1C;AAAA,GACF;AACF","file":"index.js","sourcesContent":["/** The semantic actions a Standard Gamepad produces, independent of the device's labels. */\nexport const PAD_ACTIONS = {\n up: 'up',\n down: 'down',\n left: 'left',\n right: 'right',\n confirm: 'confirm',\n back: 'back',\n mood: 'mood',\n view: 'view',\n pagePrev: 'pagePrev',\n pageNext: 'pageNext',\n} as const;\nexport type PadAction = (typeof PAD_ACTIONS)[keyof typeof PAD_ACTIONS];\n\n/** W3C Standard Gamepad button indices, named by POSITION (Nintendo swaps A/B labels). */\nexport const STANDARD_BUTTON = {\n south: 0,\n east: 1,\n west: 2,\n north: 3,\n leftShoulder: 4,\n rightShoulder: 5,\n dpadUp: 12,\n dpadDown: 13,\n dpadLeft: 14,\n dpadRight: 15,\n} as const;\n\n/** Edge-triggered buttons, in dispatch order. */\nexport const FACE_BUTTON_ACTIONS: ReadonlyArray<readonly [number, PadAction]> = [\n [STANDARD_BUTTON.south, PAD_ACTIONS.confirm],\n [STANDARD_BUTTON.east, PAD_ACTIONS.back],\n [STANDARD_BUTTON.west, PAD_ACTIONS.view],\n [STANDARD_BUTTON.north, PAD_ACTIONS.mood],\n [STANDARD_BUTTON.leftShoulder, PAD_ACTIONS.pagePrev],\n [STANDARD_BUTTON.rightShoulder, PAD_ACTIONS.pageNext],\n];\n\n/** Held (auto-repeating) buttons; the first pressed one wins. */\nexport const DPAD_ACTIONS: ReadonlyArray<readonly [number, PadAction]> = [\n [STANDARD_BUTTON.dpadUp, PAD_ACTIONS.up],\n [STANDARD_BUTTON.dpadDown, PAD_ACTIONS.down],\n [STANDARD_BUTTON.dpadLeft, PAD_ACTIONS.left],\n [STANDARD_BUTTON.dpadRight, PAD_ACTIONS.right],\n];\n\n/** Left-stick magnitude below which the stick counts as centred. */\nexport const STICK_DEAD_ZONE = 0.5;\n/** Delay before a held direction starts repeating (ms). */\nexport const REPEAT_DELAY_MS = 380;\n/** Interval between repeats once repeating (ms). */\nexport const REPEAT_INTERVAL_MS = 110;\n","import {\n DPAD_ACTIONS,\n FACE_BUTTON_ACTIONS,\n PAD_ACTIONS,\n REPEAT_DELAY_MS,\n REPEAT_INTERVAL_MS,\n STICK_DEAD_ZONE,\n type PadAction,\n} from './padMap';\n\n/** One frame of pad state: pressed flags by Standard button index, and raw axes. */\nexport interface PadSnapshot {\n buttons: readonly boolean[];\n axes: readonly number[];\n}\n\n/** Which direction is held, when it started, and when it last fired. */\nexport interface RepeatState {\n held: PadAction | null;\n since: number;\n lastFire: number;\n}\n\nexport const IDLE_REPEAT: RepeatState = { held: null, since: 0, lastFire: 0 };\n\nconst STICK_X = 0;\nconst STICK_Y = 1;\n\nfunction stickDirection(axes: readonly number[]): PadAction | null {\n const x = axes[STICK_X] ?? 0;\n const y = axes[STICK_Y] ?? 0;\n if (Math.max(Math.abs(x), Math.abs(y)) < STICK_DEAD_ZONE) {\n return null;\n }\n if (Math.abs(x) > Math.abs(y)) {\n return x > 0 ? PAD_ACTIONS.right : PAD_ACTIONS.left;\n }\n return y > 0 ? PAD_ACTIONS.down : PAD_ACTIONS.up;\n}\n\nfunction heldDirection(snapshot: PadSnapshot): PadAction | null {\n const dpad = DPAD_ACTIONS.find(([index]) => snapshot.buttons[index] === true);\n return dpad === undefined ? stickDirection(snapshot.axes) : dpad[1];\n}\n\n/** One poll frame → the actions to dispatch and the next repeat state. Pure. */\nexport function stepPad(\n prev: PadSnapshot | null,\n next: PadSnapshot,\n repeat: RepeatState,\n now: number,\n): { actions: PadAction[]; repeat: RepeatState } {\n const actions: PadAction[] = FACE_BUTTON_ACTIONS\n .filter(([index]) => next.buttons[index] === true && prev?.buttons[index] !== true)\n .map(([, action]) => action);\n const direction = heldDirection(next);\n if (direction === null) {\n return { actions, repeat: IDLE_REPEAT };\n }\n if (direction !== repeat.held) {\n return { actions: [...actions, direction], repeat: { held: direction, since: now, lastFire: now } };\n }\n const firstRepeat = repeat.lastFire === repeat.since;\n const wait = firstRepeat ? REPEAT_DELAY_MS : REPEAT_INTERVAL_MS;\n if (now - repeat.lastFire < wait) {\n return { actions, repeat };\n }\n return { actions: [...actions, direction], repeat: { ...repeat, lastFire: now } };\n}\n","import type { PadAction } from './padMap';\nimport { IDLE_REPEAT, stepPad, type PadSnapshot, type RepeatState } from './stepPad';\n\n/** The structural subset of the DOM `Gamepad` the poller reads. */\nexport interface PadLike {\n connected: boolean;\n buttons: ReadonlyArray<{ pressed: boolean }>;\n axes: readonly number[];\n}\n\nexport interface GamepadPollerOptions {\n /** Usually `() => navigator.getGamepads()`. */\n getPads: () => ReadonlyArray<PadLike | null>;\n /** Usually `requestAnimationFrame`. */\n requestFrame: (cb: (now: number) => void) => number;\n /** Usually `cancelAnimationFrame`. */\n cancelFrame: (id: number) => void;\n onAction: (action: PadAction) => void;\n}\n\n/**\n * rAF-driven poller over the first connected pad. Starts idle; call start().\n * Safe to stop() (or stop() then start()) from inside `onAction`.\n */\nexport function createGamepadPoller(opts: GamepadPollerOptions): { start: () => void; stop: () => void } {\n let prev: PadSnapshot | null = null;\n let repeat: RepeatState = IDLE_REPEAT;\n let running = false;\n let frame: number | null = null;\n\n const tick = (now: number): void => {\n frame = null;\n const pad = opts.getPads().find((p): p is PadLike => p !== null && p.connected);\n if (pad === undefined) {\n prev = null;\n repeat = IDLE_REPEAT;\n } else {\n const snapshot: PadSnapshot = { buttons: pad.buttons.map((b) => b.pressed), axes: pad.axes };\n const step = stepPad(prev, snapshot, repeat, now);\n prev = snapshot;\n repeat = step.repeat;\n step.actions.forEach((action) => opts.onAction(action));\n }\n if (running && frame === null) {\n frame = opts.requestFrame(tick);\n }\n };\n\n return {\n start: (): void => {\n if (running) {\n return;\n }\n running = true;\n if (frame === null) {\n frame = opts.requestFrame(tick);\n }\n },\n stop: (): void => {\n running = false;\n if (frame !== null) {\n opts.cancelFrame(frame);\n frame = null;\n }\n },\n };\n}\n","/** Every control a menu walker must be able to reach (shared with @dloizides/game-e2e). */\nexport const MENU_FOCUSABLE_SELECTOR = [\n 'button',\n 'a[href]',\n 'input',\n 'select',\n 'textarea',\n '[role=\"button\"]',\n '[role=\"tab\"]',\n '[role=\"option\"]',\n '[role=\"slider\"]',\n '[role=\"switch\"]',\n '[role=\"checkbox\"]',\n '[role=\"radio\"]',\n '[tabindex=\"0\"]',\n].join(', ');\n\nexport const NATIVE_FOCUSABLE_SELECTOR = 'button, input, select, textarea, a[href]';\nexport const DIALOG_SELECTOR = '[role=\"dialog\"]';\nexport const HIDDEN_ANCESTOR_SELECTOR = '[hidden], [inert], [aria-hidden=\"true\"]';\nexport const MENU_DEFAULT_ATTR = 'data-menu-default';\nexport const NAV_INPUT_ATTR = 'data-nav-input';\nexport const NAV_INPUT = { key: 'key', pad: 'pad' } as const;\nexport type NavInput = (typeof NAV_INPUT)[keyof typeof NAV_INPUT];\nexport const OBSERVED_ATTRIBUTES: readonly string[] = ['hidden', 'class', 'style', 'aria-hidden', 'aria-modal', 'inert', 'open'];\nexport const ESCAPE_KEY = 'Escape';\nexport const ENTER_KEY = 'Enter';\n","import { NATIVE_FOCUSABLE_SELECTOR } from './constants';\n\nexport const enum ControlKind {\n Button = 'button',\n Slider = 'slider',\n TextField = 'textField',\n Toggle = 'toggle',\n Select = 'select',\n}\n\nconst NON_TEXT_INPUTS: readonly string[] = ['button', 'submit', 'reset', 'color', 'file', 'image'];\nconst TOGGLE_ROLES: readonly string[] = ['checkbox', 'switch', 'radio'];\n\nfunction inputKind(el: HTMLInputElement): ControlKind {\n const type = el.type;\n if (type === 'range') {return ControlKind.Slider;}\n if (type === 'checkbox' || type === 'radio') {return ControlKind.Toggle;}\n return NON_TEXT_INPUTS.includes(type) ? ControlKind.Button : ControlKind.TextField;\n}\n\nexport function controlKind(el: Element): ControlKind {\n if (el instanceof HTMLInputElement) {return inputKind(el);}\n if (el instanceof HTMLTextAreaElement) {return ControlKind.TextField;}\n if (el instanceof HTMLSelectElement) {return ControlKind.Select;}\n const role = el.getAttribute('role') ?? '';\n if (role === 'slider') {return ControlKind.Slider;}\n return TOGGLE_ROLES.includes(role) ? ControlKind.Toggle : ControlKind.Button;\n}\n\nexport const isTextField = (el: Element): boolean => controlKind(el) === ControlKind.TextField;\n\nexport function isStepper(el: Element): boolean {\n const kind = controlKind(el);\n return kind === ControlKind.Slider || kind === ControlKind.Select;\n}\n\nexport function needsSyntheticClick(el: Element): boolean {\n const kind = controlKind(el);\n const clickable = kind === ControlKind.Button || kind === ControlKind.Toggle;\n return clickable && !el.matches(NATIVE_FOCUSABLE_SELECTOR);\n}\n","import { HIDDEN_ANCESTOR_SELECTOR, MENU_DEFAULT_ATTR, MENU_FOCUSABLE_SELECTOR } from './constants';\n\n/** True when the element has a layout box and no hidden, inert or aria-hidden ancestor. */\nexport function isShown(el: Element): boolean {\n return el.getClientRects().length > 0 && el.closest(HIDDEN_ANCESTOR_SELECTOR) === null;\n}\n\nconst isDisabled = (el: Element): boolean => (el as { disabled?: unknown }).disabled === true;\n\n/** The visible, enabled controls inside root, in DOM order. */\nexport function focusables(root: HTMLElement): HTMLElement[] {\n return Array.from(root.querySelectorAll<HTMLElement>(MENU_FOCUSABLE_SELECTOR)).filter((el) => isShown(el) && !isDisabled(el));\n}\n\n/** The [data-menu-default] control, else the first control, else null. */\nexport function defaultInitialFocus(root: HTMLElement): HTMLElement | null {\n const list = focusables(root);\n return list.find((el) => el.hasAttribute(MENU_DEFAULT_ATTR)) ?? list[0] ?? null;\n}\n","import { DIALOG_SELECTOR } from './constants';\nimport { isShown } from './focusables';\n\n/** Top-most visible dialog (aria-modal preferred, last in DOM wins), else the visible base root, else null. */\nexport function menuRoot(baseRoot: () => HTMLElement | null): HTMLElement | null {\n const dialogs = Array.from(document.querySelectorAll<HTMLElement>(DIALOG_SELECTOR)).filter(isShown);\n const modal = dialogs.filter((d) => d.getAttribute('aria-modal') === 'true');\n const top = (modal.length > 0 ? modal : dialogs).pop();\n if (top !== undefined) {return top;}\n const base = baseRoot();\n return base !== null && isShown(base) ? base : null;\n}\n","export interface Box { readonly x: number; readonly y: number; readonly w: number; readonly h: number }\n\nexport const NAV_DIRS = { up: 'arrowup', down: 'arrowdown', left: 'arrowleft', right: 'arrowright' } as const;\nexport type NavDir = (typeof NAV_DIRS)[keyof typeof NAV_DIRS];\n\nconst NAV_KEYS: readonly string[] = Object.values(NAV_DIRS);\nconst CROSS_WEIGHT = 2;\nconst SLACK = 1;\n\n/** The direction an arrow key names (case-insensitive), or null for any other key. */\nexport const navDir = (key: string): NavDir | null => (NAV_KEYS.includes(key.toLowerCase()) ? (key.toLowerCase() as NavDir) : null);\n\nconst centre = (b: Box): { cx: number; cy: number } => ({ cx: b.x + b.w / 2, cy: b.y + b.h / 2 });\n\nfunction cost(a: Box, b: Box, dir: NavDir): number | null {\n const p = centre(a);\n const q = centre(b);\n const dx = q.cx - p.cx;\n const dy = q.cy - p.cy;\n const vertical = dir === NAV_DIRS.up || dir === NAV_DIRS.down;\n const along = vertical ? (dir === NAV_DIRS.down ? dy : -dy) : dir === NAV_DIRS.right ? dx : -dx;\n if (along <= SLACK) {return null;}\n return along + CROSS_WEIGHT * Math.abs(vertical ? dx : dy);\n}\n\n/** Index of the nearest box from `from` in `dir`; wraps in list order when none lies that way; -1 for no boxes. */\nexport function pickTarget(boxes: readonly Box[], from: number, dir: NavDir): number {\n if (boxes.length === 0) {return -1;}\n if (from < 0 || from >= boxes.length) {return 0;}\n const origin = boxes[from] as Box;\n let best = -1;\n let bestCost = Infinity;\n boxes.forEach((b, i) => {\n const c = i === from ? null : cost(origin, b, dir);\n if (c !== null && c < bestCost) {\n best = i;\n bestCost = c;\n }\n });\n if (best >= 0) {return best;}\n const step = dir === NAV_DIRS.down || dir === NAV_DIRS.right ? 1 : -1;\n return (from + step + boxes.length) % boxes.length;\n}\n","const DEFAULT_MAX = 100;\n\nconst num = (raw: string | null, fallback: number): number => {\n const n = parseFloat(raw ?? '');\n return Number.isFinite(n) ? n : fallback;\n};\n\nfunction clampStep(value: number, delta: number, min: number, max: number, step: number): number {\n const decimals = (String(step).split('.')[1] ?? '').length;\n return Math.min(max, Math.max(min, Number((value + delta * step).toFixed(decimals))));\n}\n\nfunction apply(el: HTMLElement, current: number, next: number, write: (v: number) => void): void {\n if (next === current) {return;}\n write(next);\n el.dispatchEvent(new Event('input', { bubbles: true }));\n el.dispatchEvent(new Event('change', { bubbles: true }));\n}\n\n/** Steps a range, select or role=slider by one step in delta's direction, firing input + change when it moved. */\nexport function stepControl(el: HTMLElement, delta: 1 | -1): void {\n if (el instanceof HTMLInputElement) {\n const value = num(el.value, 0);\n const next = clampStep(value, delta, num(el.min, 0), num(el.max, DEFAULT_MAX), num(el.step, 1));\n apply(el, value, next, (v) => { el.value = String(v); });\n } else if (el instanceof HTMLSelectElement) {\n const next = Math.min(el.options.length - 1, Math.max(0, el.selectedIndex + delta));\n apply(el, el.selectedIndex, next, (v) => { el.selectedIndex = v; });\n } else {\n const value = num(el.getAttribute('aria-valuenow'), 0);\n const next = clampStep(value, delta, num(el.getAttribute('aria-valuemin'), 0), num(el.getAttribute('aria-valuemax'), DEFAULT_MAX), num(el.getAttribute('data-step'), 1));\n apply(el, value, next, (v) => el.setAttribute('aria-valuenow', String(v)));\n }\n}\n","import { NATIVE_FOCUSABLE_SELECTOR } from './constants';\nimport { isStepper } from './controlKind';\nimport { focusables } from './focusables';\nimport { type Box, NAV_DIRS, type NavDir, pickTarget } from './pickTarget';\nimport { stepControl } from './stepControl';\n\nexport type InitialFocus = (root: HTMLElement) => HTMLElement | null;\n\nconst boxOf = (el: Element): Box => {\n const r = el.getBoundingClientRect();\n return { x: r.left, y: r.top, w: r.width, h: r.height };\n};\n\n/** Focuses el (making a non-native control programmatically focusable) and scrolls it into view. */\nexport function focusControl(el: HTMLElement): void {\n if (!el.matches(NATIVE_FOCUSABLE_SELECTOR) && !el.hasAttribute('tabindex')) {el.setAttribute('tabindex', '-1');}\n el.focus({ preventScroll: true });\n if (typeof el.scrollIntoView === 'function') {el.scrollIntoView({ block: 'nearest' });}\n}\n\nexport function activeIn(root: HTMLElement): HTMLElement | null {\n const a = document.activeElement;\n return a instanceof HTMLElement && a !== root && root.contains(a) ? a : null;\n}\n\nexport function focusInitial(root: HTMLElement, initial: InitialFocus): boolean {\n const target = initial(root);\n if (target === null) {return false;}\n focusControl(target);\n return true;\n}\n\nfunction moveFocus(root: HTMLElement, active: HTMLElement | null, dir: NavDir, initial: InitialFocus): boolean {\n const list = focusables(root);\n const from = active === null ? -1 : list.indexOf(active);\n if (from < 0) {return focusInitial(root, initial);}\n focusControl(list[pickTarget(list.map(boxOf), from, dir)] as HTMLElement);\n return true;\n}\n\n/** Left/Right step a focused slider or select; every other case moves focus. True when it acted. */\nexport function direct(root: HTMLElement, active: HTMLElement | null, dir: NavDir, initial: InitialFocus): boolean {\n const horizontal = dir === NAV_DIRS.left || dir === NAV_DIRS.right;\n if (active !== null && horizontal && isStepper(active)) {\n stepControl(active, dir === NAV_DIRS.right ? 1 : -1);\n return true;\n }\n return moveFocus(root, active, dir, initial);\n}\n\n/** Leaves a text field for the control below it; blurs when it is the only control. */\nexport function leaveField(root: HTMLElement, field: HTMLElement): void {\n const list = focusables(root);\n const next = list[pickTarget(list.map(boxOf), list.indexOf(field), NAV_DIRS.down)];\n if (next === field || next === undefined) {\n field.blur();\n return;\n }\n focusControl(next);\n}\n","import { PAD_ACTIONS, type PadAction } from '../gamepad/padMap';\nimport { DIALOG_SELECTOR, ENTER_KEY, ESCAPE_KEY, NAV_INPUT, NAV_INPUT_ATTR, type NavInput, OBSERVED_ATTRIBUTES } from './constants';\nimport { isTextField, needsSyntheticClick } from './controlKind';\nimport { defaultInitialFocus, isShown } from './focusables';\nimport { menuRoot } from './menuRoot';\nimport { activeIn, direct, focusControl, focusInitial, leaveField } from './navActions';\nimport { NAV_DIRS, type NavDir, navDir } from './pickTarget';\n\nexport interface MenuNavOptions {\n /** The game's base menu root when no dialog is open; null = no menu (e.g. during play). */\n baseRoot: () => HTMLElement | null;\n /** True while input must not move focus (e.g. a remap capture). Default: never. */\n suspended?: () => boolean;\n /** Where focus goes when a root opens. Default: [data-menu-default], else the first control. */\n initialFocus?: (root: HTMLElement) => HTMLElement | null;\n}\n\nexport interface MenuNav {\n /** Feed one pad action from stepPad (the game keeps its own poller). */\n pad(action: PadAction): void;\n /** Re-evaluate the root and place focus (call after the game opens a screen). */\n refresh(): void;\n dispose(): void;\n}\n\ninterface OpenDialog { dialog: HTMLElement; restore: HTMLElement | null }\n\nconst PAD_DIRS: Partial<Record<PadAction, NavDir>> = { up: NAV_DIRS.up, down: NAV_DIRS.down, left: NAV_DIRS.left, right: NAV_DIRS.right };\n\nconst isOpen = (el: HTMLElement): boolean => el.isConnected && isShown(el);\nconst markInput = (kind: NavInput): void => document.documentElement.setAttribute(NAV_INPUT_ATTR, kind);\nconst clearInput = (): void => document.documentElement.removeAttribute(NAV_INPUT_ATTR);\nconst sendEscape = (): boolean => ([document.activeElement, window].find((t) => t !== null) as EventTarget).dispatchEvent(new KeyboardEvent('keydown', { key: ESCAPE_KEY, bubbles: true, cancelable: true }));\n\nfunction popClosed(stack: OpenDialog[]): HTMLElement | null {\n let restore: HTMLElement | null = null;\n while (stack.length > 0 && !isOpen((stack[stack.length - 1] as OpenDialog).dialog)) {restore = (stack.pop() as OpenDialog).restore;}\n return restore;\n}\n\nfunction canRestore(restore: HTMLElement | null, root: HTMLElement): restore is HTMLElement {\n return restore !== null && restore.isConnected && root.contains(restore) && isShown(restore);\n}\n\nfunction onKey(e: KeyboardEvent, root: HTMLElement, initial: (r: HTMLElement) => HTMLElement | null): void {\n const active = activeIn(root);\n const dir = navDir(e.key);\n if (e.key === ESCAPE_KEY) {\n if (active === null || !isTextField(active)) {return;}\n e.preventDefault();\n e.stopImmediatePropagation();\n leaveField(root, active);\n } else if (e.key === ENTER_KEY) {\n if (active === null || !needsSyntheticClick(active)) {return;}\n e.preventDefault();\n active.click();\n } else if (dir !== null) {\n markInput(NAV_INPUT.key);\n if (active !== null && isTextField(active)) {return;}\n if (direct(root, active, dir, initial)) {e.preventDefault();}\n }\n}\n\nfunction onPad(action: PadAction, root: HTMLElement | null, initial: (r: HTMLElement) => HTMLElement | null): void {\n const active = root === null ? null : activeIn(root);\n const dir = PAD_DIRS[action];\n if (action === PAD_ACTIONS.back) {\n if (root !== null && active !== null && isTextField(active)) {leaveField(root, active);}\n else {sendEscape();}\n } else if (root === null) {\n return;\n } else if (dir !== undefined) {\n direct(root, active, dir, initial);\n } else if (action === PAD_ACTIONS.confirm) {\n if (active === null) {focusInitial(root, initial);}\n else if (isTextField(active)) {focusControl(active);}\n else {active.click();}\n }\n}\n\n/** One focus engine for every game menu: arrow keys (capture phase), pad actions, dialogs on top, sliders and text fields. */\nexport function createMenuNav(options: MenuNavOptions): MenuNav {\n const suspended = options.suspended ?? ((): boolean => false);\n const initial = options.initialFocus ?? defaultInitialFocus;\n const stack: OpenDialog[] = [];\n let root = menuRoot(options.baseRoot);\n let lastInRoot: HTMLElement | null = null;\n\n const settle = (next: HTMLElement): void => {\n const restore = popClosed(stack);\n if (next.matches(DIALOG_SELECTOR) && !stack.some((s) => s.dialog === next)) {stack.push({ dialog: next, restore: lastInRoot });}\n if (activeIn(next) !== null) {return;}\n if (canRestore(restore, next)) {focusControl(restore);}\n else {focusInitial(next, initial);}\n };\n const refresh = (): HTMLElement | null => {\n const next = menuRoot(options.baseRoot);\n if (next === root) {return next;}\n root = next;\n if (next !== null) {settle(next);}\n return next;\n };\n const keydown = (e: KeyboardEvent): void => {\n if (e.altKey || e.ctrlKey || e.metaKey || suspended()) {return;}\n const r = refresh();\n if (r !== null) {onKey(e, r, initial);}\n };\n const focusin = (e: FocusEvent): void => {\n const t = e.target as HTMLElement;\n if (root !== null && root.contains(t) && t.closest(DIALOG_SELECTOR) === root.closest(DIALOG_SELECTOR)) {lastInRoot = t;}\n };\n const observer = new MutationObserver(() => { refresh(); });\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: [...OBSERVED_ATTRIBUTES] });\n window.addEventListener('keydown', keydown, true);\n window.addEventListener('pointerdown', clearInput, true);\n document.addEventListener('focusin', focusin, true);\n\n return {\n pad: (action: PadAction): void => {\n if (suspended()) {return;}\n markInput(NAV_INPUT.pad);\n onPad(action, refresh(), initial);\n },\n refresh: (): void => { refresh(); },\n dispose: (): void => {\n observer.disconnect();\n window.removeEventListener('keydown', keydown, true);\n window.removeEventListener('pointerdown', clearInput, true);\n document.removeEventListener('focusin', focusin, true);\n clearInput();\n },\n };\n}\n","/** Global name a canvas-menu game publishes its {@link MenuWalkHook} under (`window.__menuWalk`). */\nexport const MENU_WALK_HOOK = '__menuWalk';\n\n/** Engine-native menu state a canvas game exposes so @dloizides/game-e2e can walk it (NAV-1). */\nexport interface MenuWalkHook {\n /** Stable id of the menu screen on top now (e.g. `title`, `settings`). */\n screen(): string;\n /** Ids of every selectable item on that screen, reachable or not. */\n items(): string[];\n /** Id of the item holding menu focus, or `null` when none has it. */\n focused(): string | null;\n}\n\ntype HookHost = Record<string, unknown>;\n\n/** Publishes `hook` as `target.__menuWalk` and returns a function that removes it again. */\nexport function installMenuWalkHook(hook: MenuWalkHook, target: object = globalThis): () => void {\n const host = target as HookHost;\n host[MENU_WALK_HOOK] = hook;\n return () => {\n if (host[MENU_WALK_HOOK] === hook) {delete host[MENU_WALK_HOOK];}\n };\n}\n","import type { VibrationPattern } from './types';\r\n\r\n/** Default localStorage key for the haptics on/off preference. */\r\nexport const DEFAULT_HAPTICS_STORAGE_KEY = 'game.haptics';\r\n\r\n/** Default confirmation tick fired when haptics are turned ON (ms). */\r\nexport const DEFAULT_ENABLE_CONFIRMATION = 15;\r\n\r\n/** Stored value meaning \"disabled\". Any other value (or absent) means enabled. */\r\nexport const DISABLED_VALUE = '0';\r\n\r\n/** Stored value meaning \"enabled\". */\r\nexport const ENABLED_VALUE = '1';\r\n\r\n/** DOM events that count as a user activation before `navigator.userActivation` is available. */\r\nexport const USER_ACTIVATION_EVENTS = ['pointerdown', 'keydown', 'touchstart'] as const;\r\n\r\n/** The semantic intents games map their events onto. */\r\nexport type HapticIntent =\r\n | 'tap'\r\n | 'select'\r\n | 'lock'\r\n | 'bump'\r\n | 'navigate'\r\n | 'success'\r\n | 'error'\r\n | 'loss'\r\n | 'reveal';\r\n\r\n/**\r\n * A shared vocabulary of vibration patterns keyed by intent, so every game uses\r\n * the same tuned feel instead of re-picking magic durations. Pass any of these to\r\n * {@link Haptics.vibrate} (or supply your own pattern).\r\n */\r\nexport const HAPTIC_PATTERNS: Record<HapticIntent, VibrationPattern> = {\r\n /** Light tick for menu navigation / selection / undo / restart. */\r\n tap: 10,\r\n /** Light pulse when a tool/charm/item is picked up or selected. */\r\n select: 12,\r\n /** Short pulse when something locks into place. */\r\n lock: 18,\r\n /** Dull buzz when an action is blocked. */\r\n bump: 24,\r\n /** Quick pulse when stepping through a portal / page turn. */\r\n navigate: 16,\r\n /** Celebratory pattern when a level/chamber is cleared. */\r\n success: [0, 40, 50, 90],\r\n /** Sharp double crack for a fatal/destructive event. */\r\n error: [0, 14, 24, 14],\r\n /** Heavier buzz when the player loses / falls. */\r\n loss: [0, 40, 50, 40],\r\n /** Rising triple pulse the instant a puzzle resolves / an exit opens. */\r\n reveal: [0, 14, 20, 18, 26, 24],\r\n};\r\n","import { USER_ACTIVATION_EVENTS } from './constants';\nimport type { ActivationTarget, VibrationCapable } from './types';\n\nfunction resolveActivationTarget(explicit?: ActivationTarget): ActivationTarget | undefined {\n if (explicit) {return explicit;}\n const candidate = globalThis as Partial<ActivationTarget>;\n return typeof candidate.addEventListener === 'function' ? (candidate as ActivationTarget) : undefined;\n}\n\n/** Returns a probe that is true once the page has received a user gesture. */\nexport function createActivationProbe(\n navigator: VibrationCapable | undefined,\n explicitTarget?: ActivationTarget,\n): () => boolean {\n let latched = false;\n const target = typeof navigator?.vibrate === 'function' ? resolveActivationTarget(explicitTarget) : undefined;\n\n const onGesture = (): void => {\n latched = true;\n for (const type of USER_ACTIVATION_EVENTS) {target?.removeEventListener(type, onGesture, true);}\n };\n\n for (const type of USER_ACTIVATION_EVENTS) {target?.addEventListener(type, onGesture, true);}\n\n return (): boolean => latched || navigator?.userActivation?.hasBeenActive === true;\n}\n","import {\r\n DEFAULT_ENABLE_CONFIRMATION,\r\n DEFAULT_HAPTICS_STORAGE_KEY,\r\n DISABLED_VALUE,\r\n ENABLED_VALUE,\r\n} from './constants';\r\nimport type { Haptics, HapticsOptions, HapticsStorage, VibrationCapable, VibrationPattern } from './types';\r\nimport { createActivationProbe } from './userActivation';\r\n\r\nfunction resolveNavigator(explicit?: VibrationCapable): VibrationCapable | undefined {\r\n if (explicit) {\r\n return explicit;\r\n }\r\n return (globalThis as { navigator?: VibrationCapable }).navigator;\r\n}\r\n\r\nfunction resolveStorage(explicit?: HapticsStorage): HapticsStorage | undefined {\r\n if (explicit) {\r\n return explicit;\r\n }\r\n return (globalThis as { localStorage?: HapticsStorage }).localStorage;\r\n}\r\n\r\n/**\r\n * Create a player-toggleable, always-safe haptics controller: it never vibrates before a\r\n * user gesture, while disabled, or when the Vibration API is missing or blocked.\r\n */\r\nexport function createHaptics(options: HapticsOptions = {}): Haptics {\r\n const storageKey = options.storageKey ?? DEFAULT_HAPTICS_STORAGE_KEY;\r\n const confirmation =\r\n options.enableConfirmation === undefined ? DEFAULT_ENABLE_CONFIRMATION : options.enableConfirmation;\r\n const navigator = resolveNavigator(options.navigator);\r\n const storage = resolveStorage(options.storage);\r\n const hasUserActivation = createActivationProbe(navigator, options.activationTarget);\r\n\r\n const readPref = (): boolean => {\r\n try {\r\n return storage?.getItem(storageKey) !== DISABLED_VALUE;\r\n } catch {\r\n return true;\r\n }\r\n };\r\n\r\n let enabled = readPref();\r\n\r\n const vibrate = (pattern: VibrationPattern): void => {\r\n if (!enabled || !hasUserActivation()) {\r\n return;\r\n }\r\n try {\r\n navigator?.vibrate?.(pattern);\r\n } catch {\r\n return;\r\n }\r\n };\r\n\r\n const persist = (): void => {\r\n try {\r\n storage?.setItem(storageKey, enabled ? ENABLED_VALUE : DISABLED_VALUE);\r\n } catch {\r\n return;\r\n }\r\n };\r\n\r\n const setEnabled = (next: boolean): boolean => {\r\n enabled = next;\r\n persist();\r\n if (enabled && confirmation !== null) {\r\n vibrate(confirmation);\r\n }\r\n return enabled;\r\n };\r\n\r\n return {\r\n isEnabled: (): boolean => enabled,\r\n setEnabled,\r\n toggle: (): boolean => setEnabled(!enabled),\r\n vibrate,\r\n };\r\n}\r\n"]}
package/dist/index.mjs CHANGED
@@ -483,6 +483,18 @@ function createMenuNav(options) {
483
483
  };
484
484
  }
485
485
 
486
+ // src/menu/menuWalkHook.ts
487
+ var MENU_WALK_HOOK = "__menuWalk";
488
+ function installMenuWalkHook(hook, target = globalThis) {
489
+ const host = target;
490
+ host[MENU_WALK_HOOK] = hook;
491
+ return () => {
492
+ if (host[MENU_WALK_HOOK] === hook) {
493
+ delete host[MENU_WALK_HOOK];
494
+ }
495
+ };
496
+ }
497
+
486
498
  // src/constants.ts
487
499
  var DEFAULT_HAPTICS_STORAGE_KEY = "game.haptics";
488
500
  var DEFAULT_ENABLE_CONFIRMATION = 15;
@@ -593,6 +605,6 @@ function createHaptics(options = {}) {
593
605
  };
594
606
  }
595
607
 
596
- export { DEFAULT_ENABLE_CONFIRMATION, DEFAULT_HAPTICS_STORAGE_KEY, DIALOG_SELECTOR, HAPTIC_PATTERNS, IDLE_REPEAT, MENU_DEFAULT_ATTR, MENU_FOCUSABLE_SELECTOR, NAV_DIRS, NAV_INPUT, NAV_INPUT_ATTR, PAD_ACTIONS, STANDARD_BUTTON, USER_ACTIVATION_EVENTS, createGamepadPoller, createHaptics, createMenuNav, defaultInitialFocus, focusables, isShown, menuRoot, navDir, pickTarget, stepPad };
608
+ export { DEFAULT_ENABLE_CONFIRMATION, DEFAULT_HAPTICS_STORAGE_KEY, DIALOG_SELECTOR, HAPTIC_PATTERNS, IDLE_REPEAT, MENU_DEFAULT_ATTR, MENU_FOCUSABLE_SELECTOR, MENU_WALK_HOOK, NAV_DIRS, NAV_INPUT, NAV_INPUT_ATTR, PAD_ACTIONS, STANDARD_BUTTON, USER_ACTIVATION_EVENTS, createGamepadPoller, createHaptics, createMenuNav, defaultInitialFocus, focusables, installMenuWalkHook, isShown, menuRoot, navDir, pickTarget, stepPad };
597
609
  //# sourceMappingURL=index.mjs.map
598
610
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/gamepad/padMap.ts","../src/gamepad/stepPad.ts","../src/gamepad/createGamepadPoller.ts","../src/menu/constants.ts","../src/menu/controlKind.ts","../src/menu/focusables.ts","../src/menu/menuRoot.ts","../src/menu/pickTarget.ts","../src/menu/stepControl.ts","../src/menu/navActions.ts","../src/menu/createMenuNav.ts","../src/constants.ts","../src/userActivation.ts","../src/haptics.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/** The semantic actions a Standard Gamepad produces, independent of the device's labels. */\nexport const PAD_ACTIONS = {\n up: 'up',\n down: 'down',\n left: 'left',\n right: 'right',\n confirm: 'confirm',\n back: 'back',\n mood: 'mood',\n view: 'view',\n pagePrev: 'pagePrev',\n pageNext: 'pageNext',\n} as const;\nexport type PadAction = (typeof PAD_ACTIONS)[keyof typeof PAD_ACTIONS];\n\n/** W3C Standard Gamepad button indices, named by POSITION (Nintendo swaps A/B labels). */\nexport const STANDARD_BUTTON = {\n south: 0,\n east: 1,\n west: 2,\n north: 3,\n leftShoulder: 4,\n rightShoulder: 5,\n dpadUp: 12,\n dpadDown: 13,\n dpadLeft: 14,\n dpadRight: 15,\n} as const;\n\n/** Edge-triggered buttons, in dispatch order. */\nexport const FACE_BUTTON_ACTIONS: ReadonlyArray<readonly [number, PadAction]> = [\n [STANDARD_BUTTON.south, PAD_ACTIONS.confirm],\n [STANDARD_BUTTON.east, PAD_ACTIONS.back],\n [STANDARD_BUTTON.west, PAD_ACTIONS.view],\n [STANDARD_BUTTON.north, PAD_ACTIONS.mood],\n [STANDARD_BUTTON.leftShoulder, PAD_ACTIONS.pagePrev],\n [STANDARD_BUTTON.rightShoulder, PAD_ACTIONS.pageNext],\n];\n\n/** Held (auto-repeating) buttons; the first pressed one wins. */\nexport const DPAD_ACTIONS: ReadonlyArray<readonly [number, PadAction]> = [\n [STANDARD_BUTTON.dpadUp, PAD_ACTIONS.up],\n [STANDARD_BUTTON.dpadDown, PAD_ACTIONS.down],\n [STANDARD_BUTTON.dpadLeft, PAD_ACTIONS.left],\n [STANDARD_BUTTON.dpadRight, PAD_ACTIONS.right],\n];\n\n/** Left-stick magnitude below which the stick counts as centred. */\nexport const STICK_DEAD_ZONE = 0.5;\n/** Delay before a held direction starts repeating (ms). */\nexport const REPEAT_DELAY_MS = 380;\n/** Interval between repeats once repeating (ms). */\nexport const REPEAT_INTERVAL_MS = 110;\n","import {\n DPAD_ACTIONS,\n FACE_BUTTON_ACTIONS,\n PAD_ACTIONS,\n REPEAT_DELAY_MS,\n REPEAT_INTERVAL_MS,\n STICK_DEAD_ZONE,\n type PadAction,\n} from './padMap';\n\n/** One frame of pad state: pressed flags by Standard button index, and raw axes. */\nexport interface PadSnapshot {\n buttons: readonly boolean[];\n axes: readonly number[];\n}\n\n/** Which direction is held, when it started, and when it last fired. */\nexport interface RepeatState {\n held: PadAction | null;\n since: number;\n lastFire: number;\n}\n\nexport const IDLE_REPEAT: RepeatState = { held: null, since: 0, lastFire: 0 };\n\nconst STICK_X = 0;\nconst STICK_Y = 1;\n\nfunction stickDirection(axes: readonly number[]): PadAction | null {\n const x = axes[STICK_X] ?? 0;\n const y = axes[STICK_Y] ?? 0;\n if (Math.max(Math.abs(x), Math.abs(y)) < STICK_DEAD_ZONE) {\n return null;\n }\n if (Math.abs(x) > Math.abs(y)) {\n return x > 0 ? PAD_ACTIONS.right : PAD_ACTIONS.left;\n }\n return y > 0 ? PAD_ACTIONS.down : PAD_ACTIONS.up;\n}\n\nfunction heldDirection(snapshot: PadSnapshot): PadAction | null {\n const dpad = DPAD_ACTIONS.find(([index]) => snapshot.buttons[index] === true);\n return dpad === undefined ? stickDirection(snapshot.axes) : dpad[1];\n}\n\n/** One poll frame → the actions to dispatch and the next repeat state. Pure. */\nexport function stepPad(\n prev: PadSnapshot | null,\n next: PadSnapshot,\n repeat: RepeatState,\n now: number,\n): { actions: PadAction[]; repeat: RepeatState } {\n const actions: PadAction[] = FACE_BUTTON_ACTIONS\n .filter(([index]) => next.buttons[index] === true && prev?.buttons[index] !== true)\n .map(([, action]) => action);\n const direction = heldDirection(next);\n if (direction === null) {\n return { actions, repeat: IDLE_REPEAT };\n }\n if (direction !== repeat.held) {\n return { actions: [...actions, direction], repeat: { held: direction, since: now, lastFire: now } };\n }\n const firstRepeat = repeat.lastFire === repeat.since;\n const wait = firstRepeat ? REPEAT_DELAY_MS : REPEAT_INTERVAL_MS;\n if (now - repeat.lastFire < wait) {\n return { actions, repeat };\n }\n return { actions: [...actions, direction], repeat: { ...repeat, lastFire: now } };\n}\n","import type { PadAction } from './padMap';\nimport { IDLE_REPEAT, stepPad, type PadSnapshot, type RepeatState } from './stepPad';\n\n/** The structural subset of the DOM `Gamepad` the poller reads. */\nexport interface PadLike {\n connected: boolean;\n buttons: ReadonlyArray<{ pressed: boolean }>;\n axes: readonly number[];\n}\n\nexport interface GamepadPollerOptions {\n /** Usually `() => navigator.getGamepads()`. */\n getPads: () => ReadonlyArray<PadLike | null>;\n /** Usually `requestAnimationFrame`. */\n requestFrame: (cb: (now: number) => void) => number;\n /** Usually `cancelAnimationFrame`. */\n cancelFrame: (id: number) => void;\n onAction: (action: PadAction) => void;\n}\n\n/**\n * rAF-driven poller over the first connected pad. Starts idle; call start().\n * Safe to stop() (or stop() then start()) from inside `onAction`.\n */\nexport function createGamepadPoller(opts: GamepadPollerOptions): { start: () => void; stop: () => void } {\n let prev: PadSnapshot | null = null;\n let repeat: RepeatState = IDLE_REPEAT;\n let running = false;\n let frame: number | null = null;\n\n const tick = (now: number): void => {\n frame = null;\n const pad = opts.getPads().find((p): p is PadLike => p !== null && p.connected);\n if (pad === undefined) {\n prev = null;\n repeat = IDLE_REPEAT;\n } else {\n const snapshot: PadSnapshot = { buttons: pad.buttons.map((b) => b.pressed), axes: pad.axes };\n const step = stepPad(prev, snapshot, repeat, now);\n prev = snapshot;\n repeat = step.repeat;\n step.actions.forEach((action) => opts.onAction(action));\n }\n if (running && frame === null) {\n frame = opts.requestFrame(tick);\n }\n };\n\n return {\n start: (): void => {\n if (running) {\n return;\n }\n running = true;\n if (frame === null) {\n frame = opts.requestFrame(tick);\n }\n },\n stop: (): void => {\n running = false;\n if (frame !== null) {\n opts.cancelFrame(frame);\n frame = null;\n }\n },\n };\n}\n","/** Every control a menu walker must be able to reach (shared with @dloizides/game-e2e). */\nexport const MENU_FOCUSABLE_SELECTOR = [\n 'button',\n 'a[href]',\n 'input',\n 'select',\n 'textarea',\n '[role=\"button\"]',\n '[role=\"tab\"]',\n '[role=\"option\"]',\n '[role=\"slider\"]',\n '[role=\"switch\"]',\n '[role=\"checkbox\"]',\n '[role=\"radio\"]',\n '[tabindex=\"0\"]',\n].join(', ');\n\nexport const NATIVE_FOCUSABLE_SELECTOR = 'button, input, select, textarea, a[href]';\nexport const DIALOG_SELECTOR = '[role=\"dialog\"]';\nexport const HIDDEN_ANCESTOR_SELECTOR = '[hidden], [inert], [aria-hidden=\"true\"]';\nexport const MENU_DEFAULT_ATTR = 'data-menu-default';\nexport const NAV_INPUT_ATTR = 'data-nav-input';\nexport const NAV_INPUT = { key: 'key', pad: 'pad' } as const;\nexport type NavInput = (typeof NAV_INPUT)[keyof typeof NAV_INPUT];\nexport const OBSERVED_ATTRIBUTES: readonly string[] = ['hidden', 'class', 'style', 'aria-hidden', 'aria-modal', 'inert', 'open'];\nexport const ESCAPE_KEY = 'Escape';\nexport const ENTER_KEY = 'Enter';\n","import { NATIVE_FOCUSABLE_SELECTOR } from './constants';\n\nexport const enum ControlKind {\n Button = 'button',\n Slider = 'slider',\n TextField = 'textField',\n Toggle = 'toggle',\n Select = 'select',\n}\n\nconst NON_TEXT_INPUTS: readonly string[] = ['button', 'submit', 'reset', 'color', 'file', 'image'];\nconst TOGGLE_ROLES: readonly string[] = ['checkbox', 'switch', 'radio'];\n\nfunction inputKind(el: HTMLInputElement): ControlKind {\n const type = el.type;\n if (type === 'range') {return ControlKind.Slider;}\n if (type === 'checkbox' || type === 'radio') {return ControlKind.Toggle;}\n return NON_TEXT_INPUTS.includes(type) ? ControlKind.Button : ControlKind.TextField;\n}\n\nexport function controlKind(el: Element): ControlKind {\n if (el instanceof HTMLInputElement) {return inputKind(el);}\n if (el instanceof HTMLTextAreaElement) {return ControlKind.TextField;}\n if (el instanceof HTMLSelectElement) {return ControlKind.Select;}\n const role = el.getAttribute('role') ?? '';\n if (role === 'slider') {return ControlKind.Slider;}\n return TOGGLE_ROLES.includes(role) ? ControlKind.Toggle : ControlKind.Button;\n}\n\nexport const isTextField = (el: Element): boolean => controlKind(el) === ControlKind.TextField;\n\nexport function isStepper(el: Element): boolean {\n const kind = controlKind(el);\n return kind === ControlKind.Slider || kind === ControlKind.Select;\n}\n\nexport function needsSyntheticClick(el: Element): boolean {\n const kind = controlKind(el);\n const clickable = kind === ControlKind.Button || kind === ControlKind.Toggle;\n return clickable && !el.matches(NATIVE_FOCUSABLE_SELECTOR);\n}\n","import { HIDDEN_ANCESTOR_SELECTOR, MENU_DEFAULT_ATTR, MENU_FOCUSABLE_SELECTOR } from './constants';\n\n/** True when the element has a layout box and no hidden, inert or aria-hidden ancestor. */\nexport function isShown(el: Element): boolean {\n return el.getClientRects().length > 0 && el.closest(HIDDEN_ANCESTOR_SELECTOR) === null;\n}\n\nconst isDisabled = (el: Element): boolean => (el as { disabled?: unknown }).disabled === true;\n\n/** The visible, enabled controls inside root, in DOM order. */\nexport function focusables(root: HTMLElement): HTMLElement[] {\n return Array.from(root.querySelectorAll<HTMLElement>(MENU_FOCUSABLE_SELECTOR)).filter((el) => isShown(el) && !isDisabled(el));\n}\n\n/** The [data-menu-default] control, else the first control, else null. */\nexport function defaultInitialFocus(root: HTMLElement): HTMLElement | null {\n const list = focusables(root);\n return list.find((el) => el.hasAttribute(MENU_DEFAULT_ATTR)) ?? list[0] ?? null;\n}\n","import { DIALOG_SELECTOR } from './constants';\nimport { isShown } from './focusables';\n\n/** Top-most visible dialog (aria-modal preferred, last in DOM wins), else the visible base root, else null. */\nexport function menuRoot(baseRoot: () => HTMLElement | null): HTMLElement | null {\n const dialogs = Array.from(document.querySelectorAll<HTMLElement>(DIALOG_SELECTOR)).filter(isShown);\n const modal = dialogs.filter((d) => d.getAttribute('aria-modal') === 'true');\n const top = (modal.length > 0 ? modal : dialogs).pop();\n if (top !== undefined) {return top;}\n const base = baseRoot();\n return base !== null && isShown(base) ? base : null;\n}\n","export interface Box { readonly x: number; readonly y: number; readonly w: number; readonly h: number }\n\nexport const NAV_DIRS = { up: 'arrowup', down: 'arrowdown', left: 'arrowleft', right: 'arrowright' } as const;\nexport type NavDir = (typeof NAV_DIRS)[keyof typeof NAV_DIRS];\n\nconst NAV_KEYS: readonly string[] = Object.values(NAV_DIRS);\nconst CROSS_WEIGHT = 2;\nconst SLACK = 1;\n\n/** The direction an arrow key names (case-insensitive), or null for any other key. */\nexport const navDir = (key: string): NavDir | null => (NAV_KEYS.includes(key.toLowerCase()) ? (key.toLowerCase() as NavDir) : null);\n\nconst centre = (b: Box): { cx: number; cy: number } => ({ cx: b.x + b.w / 2, cy: b.y + b.h / 2 });\n\nfunction cost(a: Box, b: Box, dir: NavDir): number | null {\n const p = centre(a);\n const q = centre(b);\n const dx = q.cx - p.cx;\n const dy = q.cy - p.cy;\n const vertical = dir === NAV_DIRS.up || dir === NAV_DIRS.down;\n const along = vertical ? (dir === NAV_DIRS.down ? dy : -dy) : dir === NAV_DIRS.right ? dx : -dx;\n if (along <= SLACK) {return null;}\n return along + CROSS_WEIGHT * Math.abs(vertical ? dx : dy);\n}\n\n/** Index of the nearest box from `from` in `dir`; wraps in list order when none lies that way; -1 for no boxes. */\nexport function pickTarget(boxes: readonly Box[], from: number, dir: NavDir): number {\n if (boxes.length === 0) {return -1;}\n if (from < 0 || from >= boxes.length) {return 0;}\n const origin = boxes[from] as Box;\n let best = -1;\n let bestCost = Infinity;\n boxes.forEach((b, i) => {\n const c = i === from ? null : cost(origin, b, dir);\n if (c !== null && c < bestCost) {\n best = i;\n bestCost = c;\n }\n });\n if (best >= 0) {return best;}\n const step = dir === NAV_DIRS.down || dir === NAV_DIRS.right ? 1 : -1;\n return (from + step + boxes.length) % boxes.length;\n}\n","const DEFAULT_MAX = 100;\n\nconst num = (raw: string | null, fallback: number): number => {\n const n = parseFloat(raw ?? '');\n return Number.isFinite(n) ? n : fallback;\n};\n\nfunction clampStep(value: number, delta: number, min: number, max: number, step: number): number {\n const decimals = (String(step).split('.')[1] ?? '').length;\n return Math.min(max, Math.max(min, Number((value + delta * step).toFixed(decimals))));\n}\n\nfunction apply(el: HTMLElement, current: number, next: number, write: (v: number) => void): void {\n if (next === current) {return;}\n write(next);\n el.dispatchEvent(new Event('input', { bubbles: true }));\n el.dispatchEvent(new Event('change', { bubbles: true }));\n}\n\n/** Steps a range, select or role=slider by one step in delta's direction, firing input + change when it moved. */\nexport function stepControl(el: HTMLElement, delta: 1 | -1): void {\n if (el instanceof HTMLInputElement) {\n const value = num(el.value, 0);\n const next = clampStep(value, delta, num(el.min, 0), num(el.max, DEFAULT_MAX), num(el.step, 1));\n apply(el, value, next, (v) => { el.value = String(v); });\n } else if (el instanceof HTMLSelectElement) {\n const next = Math.min(el.options.length - 1, Math.max(0, el.selectedIndex + delta));\n apply(el, el.selectedIndex, next, (v) => { el.selectedIndex = v; });\n } else {\n const value = num(el.getAttribute('aria-valuenow'), 0);\n const next = clampStep(value, delta, num(el.getAttribute('aria-valuemin'), 0), num(el.getAttribute('aria-valuemax'), DEFAULT_MAX), num(el.getAttribute('data-step'), 1));\n apply(el, value, next, (v) => el.setAttribute('aria-valuenow', String(v)));\n }\n}\n","import { NATIVE_FOCUSABLE_SELECTOR } from './constants';\nimport { isStepper } from './controlKind';\nimport { focusables } from './focusables';\nimport { type Box, NAV_DIRS, type NavDir, pickTarget } from './pickTarget';\nimport { stepControl } from './stepControl';\n\nexport type InitialFocus = (root: HTMLElement) => HTMLElement | null;\n\nconst boxOf = (el: Element): Box => {\n const r = el.getBoundingClientRect();\n return { x: r.left, y: r.top, w: r.width, h: r.height };\n};\n\n/** Focuses el (making a non-native control programmatically focusable) and scrolls it into view. */\nexport function focusControl(el: HTMLElement): void {\n if (!el.matches(NATIVE_FOCUSABLE_SELECTOR) && !el.hasAttribute('tabindex')) {el.setAttribute('tabindex', '-1');}\n el.focus({ preventScroll: true });\n if (typeof el.scrollIntoView === 'function') {el.scrollIntoView({ block: 'nearest' });}\n}\n\nexport function activeIn(root: HTMLElement): HTMLElement | null {\n const a = document.activeElement;\n return a instanceof HTMLElement && a !== root && root.contains(a) ? a : null;\n}\n\nexport function focusInitial(root: HTMLElement, initial: InitialFocus): boolean {\n const target = initial(root);\n if (target === null) {return false;}\n focusControl(target);\n return true;\n}\n\nfunction moveFocus(root: HTMLElement, active: HTMLElement | null, dir: NavDir, initial: InitialFocus): boolean {\n const list = focusables(root);\n const from = active === null ? -1 : list.indexOf(active);\n if (from < 0) {return focusInitial(root, initial);}\n focusControl(list[pickTarget(list.map(boxOf), from, dir)] as HTMLElement);\n return true;\n}\n\n/** Left/Right step a focused slider or select; every other case moves focus. True when it acted. */\nexport function direct(root: HTMLElement, active: HTMLElement | null, dir: NavDir, initial: InitialFocus): boolean {\n const horizontal = dir === NAV_DIRS.left || dir === NAV_DIRS.right;\n if (active !== null && horizontal && isStepper(active)) {\n stepControl(active, dir === NAV_DIRS.right ? 1 : -1);\n return true;\n }\n return moveFocus(root, active, dir, initial);\n}\n\n/** Leaves a text field for the control below it; blurs when it is the only control. */\nexport function leaveField(root: HTMLElement, field: HTMLElement): void {\n const list = focusables(root);\n const next = list[pickTarget(list.map(boxOf), list.indexOf(field), NAV_DIRS.down)];\n if (next === field || next === undefined) {\n field.blur();\n return;\n }\n focusControl(next);\n}\n","import { PAD_ACTIONS, type PadAction } from '../gamepad/padMap';\nimport { DIALOG_SELECTOR, ENTER_KEY, ESCAPE_KEY, NAV_INPUT, NAV_INPUT_ATTR, type NavInput, OBSERVED_ATTRIBUTES } from './constants';\nimport { isTextField, needsSyntheticClick } from './controlKind';\nimport { defaultInitialFocus, isShown } from './focusables';\nimport { menuRoot } from './menuRoot';\nimport { activeIn, direct, focusControl, focusInitial, leaveField } from './navActions';\nimport { NAV_DIRS, type NavDir, navDir } from './pickTarget';\n\nexport interface MenuNavOptions {\n /** The game's base menu root when no dialog is open; null = no menu (e.g. during play). */\n baseRoot: () => HTMLElement | null;\n /** True while input must not move focus (e.g. a remap capture). Default: never. */\n suspended?: () => boolean;\n /** Where focus goes when a root opens. Default: [data-menu-default], else the first control. */\n initialFocus?: (root: HTMLElement) => HTMLElement | null;\n}\n\nexport interface MenuNav {\n /** Feed one pad action from stepPad (the game keeps its own poller). */\n pad(action: PadAction): void;\n /** Re-evaluate the root and place focus (call after the game opens a screen). */\n refresh(): void;\n dispose(): void;\n}\n\ninterface OpenDialog { dialog: HTMLElement; restore: HTMLElement | null }\n\nconst PAD_DIRS: Partial<Record<PadAction, NavDir>> = { up: NAV_DIRS.up, down: NAV_DIRS.down, left: NAV_DIRS.left, right: NAV_DIRS.right };\n\nconst isOpen = (el: HTMLElement): boolean => el.isConnected && isShown(el);\nconst markInput = (kind: NavInput): void => document.documentElement.setAttribute(NAV_INPUT_ATTR, kind);\nconst clearInput = (): void => document.documentElement.removeAttribute(NAV_INPUT_ATTR);\nconst sendEscape = (): boolean => ([document.activeElement, window].find((t) => t !== null) as EventTarget).dispatchEvent(new KeyboardEvent('keydown', { key: ESCAPE_KEY, bubbles: true, cancelable: true }));\n\nfunction popClosed(stack: OpenDialog[]): HTMLElement | null {\n let restore: HTMLElement | null = null;\n while (stack.length > 0 && !isOpen((stack[stack.length - 1] as OpenDialog).dialog)) {restore = (stack.pop() as OpenDialog).restore;}\n return restore;\n}\n\nfunction canRestore(restore: HTMLElement | null, root: HTMLElement): restore is HTMLElement {\n return restore !== null && restore.isConnected && root.contains(restore) && isShown(restore);\n}\n\nfunction onKey(e: KeyboardEvent, root: HTMLElement, initial: (r: HTMLElement) => HTMLElement | null): void {\n const active = activeIn(root);\n const dir = navDir(e.key);\n if (e.key === ESCAPE_KEY) {\n if (active === null || !isTextField(active)) {return;}\n e.preventDefault();\n e.stopImmediatePropagation();\n leaveField(root, active);\n } else if (e.key === ENTER_KEY) {\n if (active === null || !needsSyntheticClick(active)) {return;}\n e.preventDefault();\n active.click();\n } else if (dir !== null) {\n markInput(NAV_INPUT.key);\n if (active !== null && isTextField(active)) {return;}\n if (direct(root, active, dir, initial)) {e.preventDefault();}\n }\n}\n\nfunction onPad(action: PadAction, root: HTMLElement | null, initial: (r: HTMLElement) => HTMLElement | null): void {\n const active = root === null ? null : activeIn(root);\n const dir = PAD_DIRS[action];\n if (action === PAD_ACTIONS.back) {\n if (root !== null && active !== null && isTextField(active)) {leaveField(root, active);}\n else {sendEscape();}\n } else if (root === null) {\n return;\n } else if (dir !== undefined) {\n direct(root, active, dir, initial);\n } else if (action === PAD_ACTIONS.confirm) {\n if (active === null) {focusInitial(root, initial);}\n else if (isTextField(active)) {focusControl(active);}\n else {active.click();}\n }\n}\n\n/** One focus engine for every game menu: arrow keys (capture phase), pad actions, dialogs on top, sliders and text fields. */\nexport function createMenuNav(options: MenuNavOptions): MenuNav {\n const suspended = options.suspended ?? ((): boolean => false);\n const initial = options.initialFocus ?? defaultInitialFocus;\n const stack: OpenDialog[] = [];\n let root = menuRoot(options.baseRoot);\n let lastInRoot: HTMLElement | null = null;\n\n const settle = (next: HTMLElement): void => {\n const restore = popClosed(stack);\n if (next.matches(DIALOG_SELECTOR) && !stack.some((s) => s.dialog === next)) {stack.push({ dialog: next, restore: lastInRoot });}\n if (activeIn(next) !== null) {return;}\n if (canRestore(restore, next)) {focusControl(restore);}\n else {focusInitial(next, initial);}\n };\n const refresh = (): HTMLElement | null => {\n const next = menuRoot(options.baseRoot);\n if (next === root) {return next;}\n root = next;\n if (next !== null) {settle(next);}\n return next;\n };\n const keydown = (e: KeyboardEvent): void => {\n if (e.altKey || e.ctrlKey || e.metaKey || suspended()) {return;}\n const r = refresh();\n if (r !== null) {onKey(e, r, initial);}\n };\n const focusin = (e: FocusEvent): void => {\n const t = e.target as HTMLElement;\n if (root !== null && root.contains(t) && t.closest(DIALOG_SELECTOR) === root.closest(DIALOG_SELECTOR)) {lastInRoot = t;}\n };\n const observer = new MutationObserver(() => { refresh(); });\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: [...OBSERVED_ATTRIBUTES] });\n window.addEventListener('keydown', keydown, true);\n window.addEventListener('pointerdown', clearInput, true);\n document.addEventListener('focusin', focusin, true);\n\n return {\n pad: (action: PadAction): void => {\n if (suspended()) {return;}\n markInput(NAV_INPUT.pad);\n onPad(action, refresh(), initial);\n },\n refresh: (): void => { refresh(); },\n dispose: (): void => {\n observer.disconnect();\n window.removeEventListener('keydown', keydown, true);\n window.removeEventListener('pointerdown', clearInput, true);\n document.removeEventListener('focusin', focusin, true);\n clearInput();\n },\n };\n}\n","import type { VibrationPattern } from './types';\r\n\r\n/** Default localStorage key for the haptics on/off preference. */\r\nexport const DEFAULT_HAPTICS_STORAGE_KEY = 'game.haptics';\r\n\r\n/** Default confirmation tick fired when haptics are turned ON (ms). */\r\nexport const DEFAULT_ENABLE_CONFIRMATION = 15;\r\n\r\n/** Stored value meaning \"disabled\". Any other value (or absent) means enabled. */\r\nexport const DISABLED_VALUE = '0';\r\n\r\n/** Stored value meaning \"enabled\". */\r\nexport const ENABLED_VALUE = '1';\r\n\r\n/** DOM events that count as a user activation before `navigator.userActivation` is available. */\r\nexport const USER_ACTIVATION_EVENTS = ['pointerdown', 'keydown', 'touchstart'] as const;\r\n\r\n/** The semantic intents games map their events onto. */\r\nexport type HapticIntent =\r\n | 'tap'\r\n | 'select'\r\n | 'lock'\r\n | 'bump'\r\n | 'navigate'\r\n | 'success'\r\n | 'error'\r\n | 'loss'\r\n | 'reveal';\r\n\r\n/**\r\n * A shared vocabulary of vibration patterns keyed by intent, so every game uses\r\n * the same tuned feel instead of re-picking magic durations. Pass any of these to\r\n * {@link Haptics.vibrate} (or supply your own pattern).\r\n */\r\nexport const HAPTIC_PATTERNS: Record<HapticIntent, VibrationPattern> = {\r\n /** Light tick for menu navigation / selection / undo / restart. */\r\n tap: 10,\r\n /** Light pulse when a tool/charm/item is picked up or selected. */\r\n select: 12,\r\n /** Short pulse when something locks into place. */\r\n lock: 18,\r\n /** Dull buzz when an action is blocked. */\r\n bump: 24,\r\n /** Quick pulse when stepping through a portal / page turn. */\r\n navigate: 16,\r\n /** Celebratory pattern when a level/chamber is cleared. */\r\n success: [0, 40, 50, 90],\r\n /** Sharp double crack for a fatal/destructive event. */\r\n error: [0, 14, 24, 14],\r\n /** Heavier buzz when the player loses / falls. */\r\n loss: [0, 40, 50, 40],\r\n /** Rising triple pulse the instant a puzzle resolves / an exit opens. */\r\n reveal: [0, 14, 20, 18, 26, 24],\r\n};\r\n","import { USER_ACTIVATION_EVENTS } from './constants';\nimport type { ActivationTarget, VibrationCapable } from './types';\n\nfunction resolveActivationTarget(explicit?: ActivationTarget): ActivationTarget | undefined {\n if (explicit) {return explicit;}\n const candidate = globalThis as Partial<ActivationTarget>;\n return typeof candidate.addEventListener === 'function' ? (candidate as ActivationTarget) : undefined;\n}\n\n/** Returns a probe that is true once the page has received a user gesture. */\nexport function createActivationProbe(\n navigator: VibrationCapable | undefined,\n explicitTarget?: ActivationTarget,\n): () => boolean {\n let latched = false;\n const target = typeof navigator?.vibrate === 'function' ? resolveActivationTarget(explicitTarget) : undefined;\n\n const onGesture = (): void => {\n latched = true;\n for (const type of USER_ACTIVATION_EVENTS) {target?.removeEventListener(type, onGesture, true);}\n };\n\n for (const type of USER_ACTIVATION_EVENTS) {target?.addEventListener(type, onGesture, true);}\n\n return (): boolean => latched || navigator?.userActivation?.hasBeenActive === true;\n}\n","import {\r\n DEFAULT_ENABLE_CONFIRMATION,\r\n DEFAULT_HAPTICS_STORAGE_KEY,\r\n DISABLED_VALUE,\r\n ENABLED_VALUE,\r\n} from './constants';\r\nimport type { Haptics, HapticsOptions, HapticsStorage, VibrationCapable, VibrationPattern } from './types';\r\nimport { createActivationProbe } from './userActivation';\r\n\r\nfunction resolveNavigator(explicit?: VibrationCapable): VibrationCapable | undefined {\r\n if (explicit) {\r\n return explicit;\r\n }\r\n return (globalThis as { navigator?: VibrationCapable }).navigator;\r\n}\r\n\r\nfunction resolveStorage(explicit?: HapticsStorage): HapticsStorage | undefined {\r\n if (explicit) {\r\n return explicit;\r\n }\r\n return (globalThis as { localStorage?: HapticsStorage }).localStorage;\r\n}\r\n\r\n/**\r\n * Create a player-toggleable, always-safe haptics controller: it never vibrates before a\r\n * user gesture, while disabled, or when the Vibration API is missing or blocked.\r\n */\r\nexport function createHaptics(options: HapticsOptions = {}): Haptics {\r\n const storageKey = options.storageKey ?? DEFAULT_HAPTICS_STORAGE_KEY;\r\n const confirmation =\r\n options.enableConfirmation === undefined ? DEFAULT_ENABLE_CONFIRMATION : options.enableConfirmation;\r\n const navigator = resolveNavigator(options.navigator);\r\n const storage = resolveStorage(options.storage);\r\n const hasUserActivation = createActivationProbe(navigator, options.activationTarget);\r\n\r\n const readPref = (): boolean => {\r\n try {\r\n return storage?.getItem(storageKey) !== DISABLED_VALUE;\r\n } catch {\r\n return true;\r\n }\r\n };\r\n\r\n let enabled = readPref();\r\n\r\n const vibrate = (pattern: VibrationPattern): void => {\r\n if (!enabled || !hasUserActivation()) {\r\n return;\r\n }\r\n try {\r\n navigator?.vibrate?.(pattern);\r\n } catch {\r\n return;\r\n }\r\n };\r\n\r\n const persist = (): void => {\r\n try {\r\n storage?.setItem(storageKey, enabled ? ENABLED_VALUE : DISABLED_VALUE);\r\n } catch {\r\n return;\r\n }\r\n };\r\n\r\n const setEnabled = (next: boolean): boolean => {\r\n enabled = next;\r\n persist();\r\n if (enabled && confirmation !== null) {\r\n vibrate(confirmation);\r\n }\r\n return enabled;\r\n };\r\n\r\n return {\r\n isEnabled: (): boolean => enabled,\r\n setEnabled,\r\n toggle: (): boolean => setEnabled(!enabled),\r\n vibrate,\r\n };\r\n}\r\n"]}
1
+ {"version":3,"sources":["../src/gamepad/padMap.ts","../src/gamepad/stepPad.ts","../src/gamepad/createGamepadPoller.ts","../src/menu/constants.ts","../src/menu/controlKind.ts","../src/menu/focusables.ts","../src/menu/menuRoot.ts","../src/menu/pickTarget.ts","../src/menu/stepControl.ts","../src/menu/navActions.ts","../src/menu/createMenuNav.ts","../src/menu/menuWalkHook.ts","../src/constants.ts","../src/userActivation.ts","../src/haptics.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/** The semantic actions a Standard Gamepad produces, independent of the device's labels. */\nexport const PAD_ACTIONS = {\n up: 'up',\n down: 'down',\n left: 'left',\n right: 'right',\n confirm: 'confirm',\n back: 'back',\n mood: 'mood',\n view: 'view',\n pagePrev: 'pagePrev',\n pageNext: 'pageNext',\n} as const;\nexport type PadAction = (typeof PAD_ACTIONS)[keyof typeof PAD_ACTIONS];\n\n/** W3C Standard Gamepad button indices, named by POSITION (Nintendo swaps A/B labels). */\nexport const STANDARD_BUTTON = {\n south: 0,\n east: 1,\n west: 2,\n north: 3,\n leftShoulder: 4,\n rightShoulder: 5,\n dpadUp: 12,\n dpadDown: 13,\n dpadLeft: 14,\n dpadRight: 15,\n} as const;\n\n/** Edge-triggered buttons, in dispatch order. */\nexport const FACE_BUTTON_ACTIONS: ReadonlyArray<readonly [number, PadAction]> = [\n [STANDARD_BUTTON.south, PAD_ACTIONS.confirm],\n [STANDARD_BUTTON.east, PAD_ACTIONS.back],\n [STANDARD_BUTTON.west, PAD_ACTIONS.view],\n [STANDARD_BUTTON.north, PAD_ACTIONS.mood],\n [STANDARD_BUTTON.leftShoulder, PAD_ACTIONS.pagePrev],\n [STANDARD_BUTTON.rightShoulder, PAD_ACTIONS.pageNext],\n];\n\n/** Held (auto-repeating) buttons; the first pressed one wins. */\nexport const DPAD_ACTIONS: ReadonlyArray<readonly [number, PadAction]> = [\n [STANDARD_BUTTON.dpadUp, PAD_ACTIONS.up],\n [STANDARD_BUTTON.dpadDown, PAD_ACTIONS.down],\n [STANDARD_BUTTON.dpadLeft, PAD_ACTIONS.left],\n [STANDARD_BUTTON.dpadRight, PAD_ACTIONS.right],\n];\n\n/** Left-stick magnitude below which the stick counts as centred. */\nexport const STICK_DEAD_ZONE = 0.5;\n/** Delay before a held direction starts repeating (ms). */\nexport const REPEAT_DELAY_MS = 380;\n/** Interval between repeats once repeating (ms). */\nexport const REPEAT_INTERVAL_MS = 110;\n","import {\n DPAD_ACTIONS,\n FACE_BUTTON_ACTIONS,\n PAD_ACTIONS,\n REPEAT_DELAY_MS,\n REPEAT_INTERVAL_MS,\n STICK_DEAD_ZONE,\n type PadAction,\n} from './padMap';\n\n/** One frame of pad state: pressed flags by Standard button index, and raw axes. */\nexport interface PadSnapshot {\n buttons: readonly boolean[];\n axes: readonly number[];\n}\n\n/** Which direction is held, when it started, and when it last fired. */\nexport interface RepeatState {\n held: PadAction | null;\n since: number;\n lastFire: number;\n}\n\nexport const IDLE_REPEAT: RepeatState = { held: null, since: 0, lastFire: 0 };\n\nconst STICK_X = 0;\nconst STICK_Y = 1;\n\nfunction stickDirection(axes: readonly number[]): PadAction | null {\n const x = axes[STICK_X] ?? 0;\n const y = axes[STICK_Y] ?? 0;\n if (Math.max(Math.abs(x), Math.abs(y)) < STICK_DEAD_ZONE) {\n return null;\n }\n if (Math.abs(x) > Math.abs(y)) {\n return x > 0 ? PAD_ACTIONS.right : PAD_ACTIONS.left;\n }\n return y > 0 ? PAD_ACTIONS.down : PAD_ACTIONS.up;\n}\n\nfunction heldDirection(snapshot: PadSnapshot): PadAction | null {\n const dpad = DPAD_ACTIONS.find(([index]) => snapshot.buttons[index] === true);\n return dpad === undefined ? stickDirection(snapshot.axes) : dpad[1];\n}\n\n/** One poll frame → the actions to dispatch and the next repeat state. Pure. */\nexport function stepPad(\n prev: PadSnapshot | null,\n next: PadSnapshot,\n repeat: RepeatState,\n now: number,\n): { actions: PadAction[]; repeat: RepeatState } {\n const actions: PadAction[] = FACE_BUTTON_ACTIONS\n .filter(([index]) => next.buttons[index] === true && prev?.buttons[index] !== true)\n .map(([, action]) => action);\n const direction = heldDirection(next);\n if (direction === null) {\n return { actions, repeat: IDLE_REPEAT };\n }\n if (direction !== repeat.held) {\n return { actions: [...actions, direction], repeat: { held: direction, since: now, lastFire: now } };\n }\n const firstRepeat = repeat.lastFire === repeat.since;\n const wait = firstRepeat ? REPEAT_DELAY_MS : REPEAT_INTERVAL_MS;\n if (now - repeat.lastFire < wait) {\n return { actions, repeat };\n }\n return { actions: [...actions, direction], repeat: { ...repeat, lastFire: now } };\n}\n","import type { PadAction } from './padMap';\nimport { IDLE_REPEAT, stepPad, type PadSnapshot, type RepeatState } from './stepPad';\n\n/** The structural subset of the DOM `Gamepad` the poller reads. */\nexport interface PadLike {\n connected: boolean;\n buttons: ReadonlyArray<{ pressed: boolean }>;\n axes: readonly number[];\n}\n\nexport interface GamepadPollerOptions {\n /** Usually `() => navigator.getGamepads()`. */\n getPads: () => ReadonlyArray<PadLike | null>;\n /** Usually `requestAnimationFrame`. */\n requestFrame: (cb: (now: number) => void) => number;\n /** Usually `cancelAnimationFrame`. */\n cancelFrame: (id: number) => void;\n onAction: (action: PadAction) => void;\n}\n\n/**\n * rAF-driven poller over the first connected pad. Starts idle; call start().\n * Safe to stop() (or stop() then start()) from inside `onAction`.\n */\nexport function createGamepadPoller(opts: GamepadPollerOptions): { start: () => void; stop: () => void } {\n let prev: PadSnapshot | null = null;\n let repeat: RepeatState = IDLE_REPEAT;\n let running = false;\n let frame: number | null = null;\n\n const tick = (now: number): void => {\n frame = null;\n const pad = opts.getPads().find((p): p is PadLike => p !== null && p.connected);\n if (pad === undefined) {\n prev = null;\n repeat = IDLE_REPEAT;\n } else {\n const snapshot: PadSnapshot = { buttons: pad.buttons.map((b) => b.pressed), axes: pad.axes };\n const step = stepPad(prev, snapshot, repeat, now);\n prev = snapshot;\n repeat = step.repeat;\n step.actions.forEach((action) => opts.onAction(action));\n }\n if (running && frame === null) {\n frame = opts.requestFrame(tick);\n }\n };\n\n return {\n start: (): void => {\n if (running) {\n return;\n }\n running = true;\n if (frame === null) {\n frame = opts.requestFrame(tick);\n }\n },\n stop: (): void => {\n running = false;\n if (frame !== null) {\n opts.cancelFrame(frame);\n frame = null;\n }\n },\n };\n}\n","/** Every control a menu walker must be able to reach (shared with @dloizides/game-e2e). */\nexport const MENU_FOCUSABLE_SELECTOR = [\n 'button',\n 'a[href]',\n 'input',\n 'select',\n 'textarea',\n '[role=\"button\"]',\n '[role=\"tab\"]',\n '[role=\"option\"]',\n '[role=\"slider\"]',\n '[role=\"switch\"]',\n '[role=\"checkbox\"]',\n '[role=\"radio\"]',\n '[tabindex=\"0\"]',\n].join(', ');\n\nexport const NATIVE_FOCUSABLE_SELECTOR = 'button, input, select, textarea, a[href]';\nexport const DIALOG_SELECTOR = '[role=\"dialog\"]';\nexport const HIDDEN_ANCESTOR_SELECTOR = '[hidden], [inert], [aria-hidden=\"true\"]';\nexport const MENU_DEFAULT_ATTR = 'data-menu-default';\nexport const NAV_INPUT_ATTR = 'data-nav-input';\nexport const NAV_INPUT = { key: 'key', pad: 'pad' } as const;\nexport type NavInput = (typeof NAV_INPUT)[keyof typeof NAV_INPUT];\nexport const OBSERVED_ATTRIBUTES: readonly string[] = ['hidden', 'class', 'style', 'aria-hidden', 'aria-modal', 'inert', 'open'];\nexport const ESCAPE_KEY = 'Escape';\nexport const ENTER_KEY = 'Enter';\n","import { NATIVE_FOCUSABLE_SELECTOR } from './constants';\n\nexport const enum ControlKind {\n Button = 'button',\n Slider = 'slider',\n TextField = 'textField',\n Toggle = 'toggle',\n Select = 'select',\n}\n\nconst NON_TEXT_INPUTS: readonly string[] = ['button', 'submit', 'reset', 'color', 'file', 'image'];\nconst TOGGLE_ROLES: readonly string[] = ['checkbox', 'switch', 'radio'];\n\nfunction inputKind(el: HTMLInputElement): ControlKind {\n const type = el.type;\n if (type === 'range') {return ControlKind.Slider;}\n if (type === 'checkbox' || type === 'radio') {return ControlKind.Toggle;}\n return NON_TEXT_INPUTS.includes(type) ? ControlKind.Button : ControlKind.TextField;\n}\n\nexport function controlKind(el: Element): ControlKind {\n if (el instanceof HTMLInputElement) {return inputKind(el);}\n if (el instanceof HTMLTextAreaElement) {return ControlKind.TextField;}\n if (el instanceof HTMLSelectElement) {return ControlKind.Select;}\n const role = el.getAttribute('role') ?? '';\n if (role === 'slider') {return ControlKind.Slider;}\n return TOGGLE_ROLES.includes(role) ? ControlKind.Toggle : ControlKind.Button;\n}\n\nexport const isTextField = (el: Element): boolean => controlKind(el) === ControlKind.TextField;\n\nexport function isStepper(el: Element): boolean {\n const kind = controlKind(el);\n return kind === ControlKind.Slider || kind === ControlKind.Select;\n}\n\nexport function needsSyntheticClick(el: Element): boolean {\n const kind = controlKind(el);\n const clickable = kind === ControlKind.Button || kind === ControlKind.Toggle;\n return clickable && !el.matches(NATIVE_FOCUSABLE_SELECTOR);\n}\n","import { HIDDEN_ANCESTOR_SELECTOR, MENU_DEFAULT_ATTR, MENU_FOCUSABLE_SELECTOR } from './constants';\n\n/** True when the element has a layout box and no hidden, inert or aria-hidden ancestor. */\nexport function isShown(el: Element): boolean {\n return el.getClientRects().length > 0 && el.closest(HIDDEN_ANCESTOR_SELECTOR) === null;\n}\n\nconst isDisabled = (el: Element): boolean => (el as { disabled?: unknown }).disabled === true;\n\n/** The visible, enabled controls inside root, in DOM order. */\nexport function focusables(root: HTMLElement): HTMLElement[] {\n return Array.from(root.querySelectorAll<HTMLElement>(MENU_FOCUSABLE_SELECTOR)).filter((el) => isShown(el) && !isDisabled(el));\n}\n\n/** The [data-menu-default] control, else the first control, else null. */\nexport function defaultInitialFocus(root: HTMLElement): HTMLElement | null {\n const list = focusables(root);\n return list.find((el) => el.hasAttribute(MENU_DEFAULT_ATTR)) ?? list[0] ?? null;\n}\n","import { DIALOG_SELECTOR } from './constants';\nimport { isShown } from './focusables';\n\n/** Top-most visible dialog (aria-modal preferred, last in DOM wins), else the visible base root, else null. */\nexport function menuRoot(baseRoot: () => HTMLElement | null): HTMLElement | null {\n const dialogs = Array.from(document.querySelectorAll<HTMLElement>(DIALOG_SELECTOR)).filter(isShown);\n const modal = dialogs.filter((d) => d.getAttribute('aria-modal') === 'true');\n const top = (modal.length > 0 ? modal : dialogs).pop();\n if (top !== undefined) {return top;}\n const base = baseRoot();\n return base !== null && isShown(base) ? base : null;\n}\n","export interface Box { readonly x: number; readonly y: number; readonly w: number; readonly h: number }\n\nexport const NAV_DIRS = { up: 'arrowup', down: 'arrowdown', left: 'arrowleft', right: 'arrowright' } as const;\nexport type NavDir = (typeof NAV_DIRS)[keyof typeof NAV_DIRS];\n\nconst NAV_KEYS: readonly string[] = Object.values(NAV_DIRS);\nconst CROSS_WEIGHT = 2;\nconst SLACK = 1;\n\n/** The direction an arrow key names (case-insensitive), or null for any other key. */\nexport const navDir = (key: string): NavDir | null => (NAV_KEYS.includes(key.toLowerCase()) ? (key.toLowerCase() as NavDir) : null);\n\nconst centre = (b: Box): { cx: number; cy: number } => ({ cx: b.x + b.w / 2, cy: b.y + b.h / 2 });\n\nfunction cost(a: Box, b: Box, dir: NavDir): number | null {\n const p = centre(a);\n const q = centre(b);\n const dx = q.cx - p.cx;\n const dy = q.cy - p.cy;\n const vertical = dir === NAV_DIRS.up || dir === NAV_DIRS.down;\n const along = vertical ? (dir === NAV_DIRS.down ? dy : -dy) : dir === NAV_DIRS.right ? dx : -dx;\n if (along <= SLACK) {return null;}\n return along + CROSS_WEIGHT * Math.abs(vertical ? dx : dy);\n}\n\n/** Index of the nearest box from `from` in `dir`; wraps in list order when none lies that way; -1 for no boxes. */\nexport function pickTarget(boxes: readonly Box[], from: number, dir: NavDir): number {\n if (boxes.length === 0) {return -1;}\n if (from < 0 || from >= boxes.length) {return 0;}\n const origin = boxes[from] as Box;\n let best = -1;\n let bestCost = Infinity;\n boxes.forEach((b, i) => {\n const c = i === from ? null : cost(origin, b, dir);\n if (c !== null && c < bestCost) {\n best = i;\n bestCost = c;\n }\n });\n if (best >= 0) {return best;}\n const step = dir === NAV_DIRS.down || dir === NAV_DIRS.right ? 1 : -1;\n return (from + step + boxes.length) % boxes.length;\n}\n","const DEFAULT_MAX = 100;\n\nconst num = (raw: string | null, fallback: number): number => {\n const n = parseFloat(raw ?? '');\n return Number.isFinite(n) ? n : fallback;\n};\n\nfunction clampStep(value: number, delta: number, min: number, max: number, step: number): number {\n const decimals = (String(step).split('.')[1] ?? '').length;\n return Math.min(max, Math.max(min, Number((value + delta * step).toFixed(decimals))));\n}\n\nfunction apply(el: HTMLElement, current: number, next: number, write: (v: number) => void): void {\n if (next === current) {return;}\n write(next);\n el.dispatchEvent(new Event('input', { bubbles: true }));\n el.dispatchEvent(new Event('change', { bubbles: true }));\n}\n\n/** Steps a range, select or role=slider by one step in delta's direction, firing input + change when it moved. */\nexport function stepControl(el: HTMLElement, delta: 1 | -1): void {\n if (el instanceof HTMLInputElement) {\n const value = num(el.value, 0);\n const next = clampStep(value, delta, num(el.min, 0), num(el.max, DEFAULT_MAX), num(el.step, 1));\n apply(el, value, next, (v) => { el.value = String(v); });\n } else if (el instanceof HTMLSelectElement) {\n const next = Math.min(el.options.length - 1, Math.max(0, el.selectedIndex + delta));\n apply(el, el.selectedIndex, next, (v) => { el.selectedIndex = v; });\n } else {\n const value = num(el.getAttribute('aria-valuenow'), 0);\n const next = clampStep(value, delta, num(el.getAttribute('aria-valuemin'), 0), num(el.getAttribute('aria-valuemax'), DEFAULT_MAX), num(el.getAttribute('data-step'), 1));\n apply(el, value, next, (v) => el.setAttribute('aria-valuenow', String(v)));\n }\n}\n","import { NATIVE_FOCUSABLE_SELECTOR } from './constants';\nimport { isStepper } from './controlKind';\nimport { focusables } from './focusables';\nimport { type Box, NAV_DIRS, type NavDir, pickTarget } from './pickTarget';\nimport { stepControl } from './stepControl';\n\nexport type InitialFocus = (root: HTMLElement) => HTMLElement | null;\n\nconst boxOf = (el: Element): Box => {\n const r = el.getBoundingClientRect();\n return { x: r.left, y: r.top, w: r.width, h: r.height };\n};\n\n/** Focuses el (making a non-native control programmatically focusable) and scrolls it into view. */\nexport function focusControl(el: HTMLElement): void {\n if (!el.matches(NATIVE_FOCUSABLE_SELECTOR) && !el.hasAttribute('tabindex')) {el.setAttribute('tabindex', '-1');}\n el.focus({ preventScroll: true });\n if (typeof el.scrollIntoView === 'function') {el.scrollIntoView({ block: 'nearest' });}\n}\n\nexport function activeIn(root: HTMLElement): HTMLElement | null {\n const a = document.activeElement;\n return a instanceof HTMLElement && a !== root && root.contains(a) ? a : null;\n}\n\nexport function focusInitial(root: HTMLElement, initial: InitialFocus): boolean {\n const target = initial(root);\n if (target === null) {return false;}\n focusControl(target);\n return true;\n}\n\nfunction moveFocus(root: HTMLElement, active: HTMLElement | null, dir: NavDir, initial: InitialFocus): boolean {\n const list = focusables(root);\n const from = active === null ? -1 : list.indexOf(active);\n if (from < 0) {return focusInitial(root, initial);}\n focusControl(list[pickTarget(list.map(boxOf), from, dir)] as HTMLElement);\n return true;\n}\n\n/** Left/Right step a focused slider or select; every other case moves focus. True when it acted. */\nexport function direct(root: HTMLElement, active: HTMLElement | null, dir: NavDir, initial: InitialFocus): boolean {\n const horizontal = dir === NAV_DIRS.left || dir === NAV_DIRS.right;\n if (active !== null && horizontal && isStepper(active)) {\n stepControl(active, dir === NAV_DIRS.right ? 1 : -1);\n return true;\n }\n return moveFocus(root, active, dir, initial);\n}\n\n/** Leaves a text field for the control below it; blurs when it is the only control. */\nexport function leaveField(root: HTMLElement, field: HTMLElement): void {\n const list = focusables(root);\n const next = list[pickTarget(list.map(boxOf), list.indexOf(field), NAV_DIRS.down)];\n if (next === field || next === undefined) {\n field.blur();\n return;\n }\n focusControl(next);\n}\n","import { PAD_ACTIONS, type PadAction } from '../gamepad/padMap';\nimport { DIALOG_SELECTOR, ENTER_KEY, ESCAPE_KEY, NAV_INPUT, NAV_INPUT_ATTR, type NavInput, OBSERVED_ATTRIBUTES } from './constants';\nimport { isTextField, needsSyntheticClick } from './controlKind';\nimport { defaultInitialFocus, isShown } from './focusables';\nimport { menuRoot } from './menuRoot';\nimport { activeIn, direct, focusControl, focusInitial, leaveField } from './navActions';\nimport { NAV_DIRS, type NavDir, navDir } from './pickTarget';\n\nexport interface MenuNavOptions {\n /** The game's base menu root when no dialog is open; null = no menu (e.g. during play). */\n baseRoot: () => HTMLElement | null;\n /** True while input must not move focus (e.g. a remap capture). Default: never. */\n suspended?: () => boolean;\n /** Where focus goes when a root opens. Default: [data-menu-default], else the first control. */\n initialFocus?: (root: HTMLElement) => HTMLElement | null;\n}\n\nexport interface MenuNav {\n /** Feed one pad action from stepPad (the game keeps its own poller). */\n pad(action: PadAction): void;\n /** Re-evaluate the root and place focus (call after the game opens a screen). */\n refresh(): void;\n dispose(): void;\n}\n\ninterface OpenDialog { dialog: HTMLElement; restore: HTMLElement | null }\n\nconst PAD_DIRS: Partial<Record<PadAction, NavDir>> = { up: NAV_DIRS.up, down: NAV_DIRS.down, left: NAV_DIRS.left, right: NAV_DIRS.right };\n\nconst isOpen = (el: HTMLElement): boolean => el.isConnected && isShown(el);\nconst markInput = (kind: NavInput): void => document.documentElement.setAttribute(NAV_INPUT_ATTR, kind);\nconst clearInput = (): void => document.documentElement.removeAttribute(NAV_INPUT_ATTR);\nconst sendEscape = (): boolean => ([document.activeElement, window].find((t) => t !== null) as EventTarget).dispatchEvent(new KeyboardEvent('keydown', { key: ESCAPE_KEY, bubbles: true, cancelable: true }));\n\nfunction popClosed(stack: OpenDialog[]): HTMLElement | null {\n let restore: HTMLElement | null = null;\n while (stack.length > 0 && !isOpen((stack[stack.length - 1] as OpenDialog).dialog)) {restore = (stack.pop() as OpenDialog).restore;}\n return restore;\n}\n\nfunction canRestore(restore: HTMLElement | null, root: HTMLElement): restore is HTMLElement {\n return restore !== null && restore.isConnected && root.contains(restore) && isShown(restore);\n}\n\nfunction onKey(e: KeyboardEvent, root: HTMLElement, initial: (r: HTMLElement) => HTMLElement | null): void {\n const active = activeIn(root);\n const dir = navDir(e.key);\n if (e.key === ESCAPE_KEY) {\n if (active === null || !isTextField(active)) {return;}\n e.preventDefault();\n e.stopImmediatePropagation();\n leaveField(root, active);\n } else if (e.key === ENTER_KEY) {\n if (active === null || !needsSyntheticClick(active)) {return;}\n e.preventDefault();\n active.click();\n } else if (dir !== null) {\n markInput(NAV_INPUT.key);\n if (active !== null && isTextField(active)) {return;}\n if (direct(root, active, dir, initial)) {e.preventDefault();}\n }\n}\n\nfunction onPad(action: PadAction, root: HTMLElement | null, initial: (r: HTMLElement) => HTMLElement | null): void {\n const active = root === null ? null : activeIn(root);\n const dir = PAD_DIRS[action];\n if (action === PAD_ACTIONS.back) {\n if (root !== null && active !== null && isTextField(active)) {leaveField(root, active);}\n else {sendEscape();}\n } else if (root === null) {\n return;\n } else if (dir !== undefined) {\n direct(root, active, dir, initial);\n } else if (action === PAD_ACTIONS.confirm) {\n if (active === null) {focusInitial(root, initial);}\n else if (isTextField(active)) {focusControl(active);}\n else {active.click();}\n }\n}\n\n/** One focus engine for every game menu: arrow keys (capture phase), pad actions, dialogs on top, sliders and text fields. */\nexport function createMenuNav(options: MenuNavOptions): MenuNav {\n const suspended = options.suspended ?? ((): boolean => false);\n const initial = options.initialFocus ?? defaultInitialFocus;\n const stack: OpenDialog[] = [];\n let root = menuRoot(options.baseRoot);\n let lastInRoot: HTMLElement | null = null;\n\n const settle = (next: HTMLElement): void => {\n const restore = popClosed(stack);\n if (next.matches(DIALOG_SELECTOR) && !stack.some((s) => s.dialog === next)) {stack.push({ dialog: next, restore: lastInRoot });}\n if (activeIn(next) !== null) {return;}\n if (canRestore(restore, next)) {focusControl(restore);}\n else {focusInitial(next, initial);}\n };\n const refresh = (): HTMLElement | null => {\n const next = menuRoot(options.baseRoot);\n if (next === root) {return next;}\n root = next;\n if (next !== null) {settle(next);}\n return next;\n };\n const keydown = (e: KeyboardEvent): void => {\n if (e.altKey || e.ctrlKey || e.metaKey || suspended()) {return;}\n const r = refresh();\n if (r !== null) {onKey(e, r, initial);}\n };\n const focusin = (e: FocusEvent): void => {\n const t = e.target as HTMLElement;\n if (root !== null && root.contains(t) && t.closest(DIALOG_SELECTOR) === root.closest(DIALOG_SELECTOR)) {lastInRoot = t;}\n };\n const observer = new MutationObserver(() => { refresh(); });\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: [...OBSERVED_ATTRIBUTES] });\n window.addEventListener('keydown', keydown, true);\n window.addEventListener('pointerdown', clearInput, true);\n document.addEventListener('focusin', focusin, true);\n\n return {\n pad: (action: PadAction): void => {\n if (suspended()) {return;}\n markInput(NAV_INPUT.pad);\n onPad(action, refresh(), initial);\n },\n refresh: (): void => { refresh(); },\n dispose: (): void => {\n observer.disconnect();\n window.removeEventListener('keydown', keydown, true);\n window.removeEventListener('pointerdown', clearInput, true);\n document.removeEventListener('focusin', focusin, true);\n clearInput();\n },\n };\n}\n","/** Global name a canvas-menu game publishes its {@link MenuWalkHook} under (`window.__menuWalk`). */\nexport const MENU_WALK_HOOK = '__menuWalk';\n\n/** Engine-native menu state a canvas game exposes so @dloizides/game-e2e can walk it (NAV-1). */\nexport interface MenuWalkHook {\n /** Stable id of the menu screen on top now (e.g. `title`, `settings`). */\n screen(): string;\n /** Ids of every selectable item on that screen, reachable or not. */\n items(): string[];\n /** Id of the item holding menu focus, or `null` when none has it. */\n focused(): string | null;\n}\n\ntype HookHost = Record<string, unknown>;\n\n/** Publishes `hook` as `target.__menuWalk` and returns a function that removes it again. */\nexport function installMenuWalkHook(hook: MenuWalkHook, target: object = globalThis): () => void {\n const host = target as HookHost;\n host[MENU_WALK_HOOK] = hook;\n return () => {\n if (host[MENU_WALK_HOOK] === hook) {delete host[MENU_WALK_HOOK];}\n };\n}\n","import type { VibrationPattern } from './types';\r\n\r\n/** Default localStorage key for the haptics on/off preference. */\r\nexport const DEFAULT_HAPTICS_STORAGE_KEY = 'game.haptics';\r\n\r\n/** Default confirmation tick fired when haptics are turned ON (ms). */\r\nexport const DEFAULT_ENABLE_CONFIRMATION = 15;\r\n\r\n/** Stored value meaning \"disabled\". Any other value (or absent) means enabled. */\r\nexport const DISABLED_VALUE = '0';\r\n\r\n/** Stored value meaning \"enabled\". */\r\nexport const ENABLED_VALUE = '1';\r\n\r\n/** DOM events that count as a user activation before `navigator.userActivation` is available. */\r\nexport const USER_ACTIVATION_EVENTS = ['pointerdown', 'keydown', 'touchstart'] as const;\r\n\r\n/** The semantic intents games map their events onto. */\r\nexport type HapticIntent =\r\n | 'tap'\r\n | 'select'\r\n | 'lock'\r\n | 'bump'\r\n | 'navigate'\r\n | 'success'\r\n | 'error'\r\n | 'loss'\r\n | 'reveal';\r\n\r\n/**\r\n * A shared vocabulary of vibration patterns keyed by intent, so every game uses\r\n * the same tuned feel instead of re-picking magic durations. Pass any of these to\r\n * {@link Haptics.vibrate} (or supply your own pattern).\r\n */\r\nexport const HAPTIC_PATTERNS: Record<HapticIntent, VibrationPattern> = {\r\n /** Light tick for menu navigation / selection / undo / restart. */\r\n tap: 10,\r\n /** Light pulse when a tool/charm/item is picked up or selected. */\r\n select: 12,\r\n /** Short pulse when something locks into place. */\r\n lock: 18,\r\n /** Dull buzz when an action is blocked. */\r\n bump: 24,\r\n /** Quick pulse when stepping through a portal / page turn. */\r\n navigate: 16,\r\n /** Celebratory pattern when a level/chamber is cleared. */\r\n success: [0, 40, 50, 90],\r\n /** Sharp double crack for a fatal/destructive event. */\r\n error: [0, 14, 24, 14],\r\n /** Heavier buzz when the player loses / falls. */\r\n loss: [0, 40, 50, 40],\r\n /** Rising triple pulse the instant a puzzle resolves / an exit opens. */\r\n reveal: [0, 14, 20, 18, 26, 24],\r\n};\r\n","import { USER_ACTIVATION_EVENTS } from './constants';\nimport type { ActivationTarget, VibrationCapable } from './types';\n\nfunction resolveActivationTarget(explicit?: ActivationTarget): ActivationTarget | undefined {\n if (explicit) {return explicit;}\n const candidate = globalThis as Partial<ActivationTarget>;\n return typeof candidate.addEventListener === 'function' ? (candidate as ActivationTarget) : undefined;\n}\n\n/** Returns a probe that is true once the page has received a user gesture. */\nexport function createActivationProbe(\n navigator: VibrationCapable | undefined,\n explicitTarget?: ActivationTarget,\n): () => boolean {\n let latched = false;\n const target = typeof navigator?.vibrate === 'function' ? resolveActivationTarget(explicitTarget) : undefined;\n\n const onGesture = (): void => {\n latched = true;\n for (const type of USER_ACTIVATION_EVENTS) {target?.removeEventListener(type, onGesture, true);}\n };\n\n for (const type of USER_ACTIVATION_EVENTS) {target?.addEventListener(type, onGesture, true);}\n\n return (): boolean => latched || navigator?.userActivation?.hasBeenActive === true;\n}\n","import {\r\n DEFAULT_ENABLE_CONFIRMATION,\r\n DEFAULT_HAPTICS_STORAGE_KEY,\r\n DISABLED_VALUE,\r\n ENABLED_VALUE,\r\n} from './constants';\r\nimport type { Haptics, HapticsOptions, HapticsStorage, VibrationCapable, VibrationPattern } from './types';\r\nimport { createActivationProbe } from './userActivation';\r\n\r\nfunction resolveNavigator(explicit?: VibrationCapable): VibrationCapable | undefined {\r\n if (explicit) {\r\n return explicit;\r\n }\r\n return (globalThis as { navigator?: VibrationCapable }).navigator;\r\n}\r\n\r\nfunction resolveStorage(explicit?: HapticsStorage): HapticsStorage | undefined {\r\n if (explicit) {\r\n return explicit;\r\n }\r\n return (globalThis as { localStorage?: HapticsStorage }).localStorage;\r\n}\r\n\r\n/**\r\n * Create a player-toggleable, always-safe haptics controller: it never vibrates before a\r\n * user gesture, while disabled, or when the Vibration API is missing or blocked.\r\n */\r\nexport function createHaptics(options: HapticsOptions = {}): Haptics {\r\n const storageKey = options.storageKey ?? DEFAULT_HAPTICS_STORAGE_KEY;\r\n const confirmation =\r\n options.enableConfirmation === undefined ? DEFAULT_ENABLE_CONFIRMATION : options.enableConfirmation;\r\n const navigator = resolveNavigator(options.navigator);\r\n const storage = resolveStorage(options.storage);\r\n const hasUserActivation = createActivationProbe(navigator, options.activationTarget);\r\n\r\n const readPref = (): boolean => {\r\n try {\r\n return storage?.getItem(storageKey) !== DISABLED_VALUE;\r\n } catch {\r\n return true;\r\n }\r\n };\r\n\r\n let enabled = readPref();\r\n\r\n const vibrate = (pattern: VibrationPattern): void => {\r\n if (!enabled || !hasUserActivation()) {\r\n return;\r\n }\r\n try {\r\n navigator?.vibrate?.(pattern);\r\n } catch {\r\n return;\r\n }\r\n };\r\n\r\n const persist = (): void => {\r\n try {\r\n storage?.setItem(storageKey, enabled ? ENABLED_VALUE : DISABLED_VALUE);\r\n } catch {\r\n return;\r\n }\r\n };\r\n\r\n const setEnabled = (next: boolean): boolean => {\r\n enabled = next;\r\n persist();\r\n if (enabled && confirmation !== null) {\r\n vibrate(confirmation);\r\n }\r\n return enabled;\r\n };\r\n\r\n return {\r\n isEnabled: (): boolean => enabled,\r\n setEnabled,\r\n toggle: (): boolean => setEnabled(!enabled),\r\n vibrate,\r\n };\r\n}\r\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dloizides/game-input",
3
- "version": "1.5.1",
3
+ "version": "1.6.0",
4
4
  "description": "Framework-agnostic game input primitives. v1 ships safe, player-toggleable haptics (Vibration API wrapper, localStorage-gated, zero deps). Extracted from Aurora; consumed across EisaiPollis games.",
5
5
  "keywords": [
6
6
  "haptics",