diff --git a/packages/core/src/dom/hotkey/actions.ts b/packages/core/src/dom/hotkey/actions.ts index f9092e79..1b612c72 100644 --- a/packages/core/src/dom/hotkey/actions.ts +++ b/packages/core/src/dom/hotkey/actions.ts @@ -25,7 +25,7 @@ export type HotkeyActionName = export interface HotkeyActionContext { store: AnyPlayerStore; - value?: number; + value?: number | undefined; /** The matched key character (used by `seekToPercent` to derive digit). */ key: string; } diff --git a/packages/core/src/dom/hotkey/coordinator.ts b/packages/core/src/dom/hotkey/coordinator.ts index 781893b0..943dc241 100644 --- a/packages/core/src/dom/hotkey/coordinator.ts +++ b/packages/core/src/dom/hotkey/coordinator.ts @@ -142,7 +142,7 @@ export class HotkeyCoordinator { const { options, parsed } = binding; if (options.disabled) continue; - if (event.repeat && options.allowRepeat === false) continue; + if (event.repeat && options.repeatable === false) continue; // Only consider bindings matching the event's target scope. const isDocBinding = options.target === 'document'; diff --git a/packages/core/src/dom/hotkey/hotkey.ts b/packages/core/src/dom/hotkey/hotkey.ts index c33dfe68..61c3990e 100644 --- a/packages/core/src/dom/hotkey/hotkey.ts +++ b/packages/core/src/dom/hotkey/hotkey.ts @@ -16,12 +16,12 @@ export interface HotkeyOptions { keys: string; onActivate: (event: KeyboardEvent, key: string) => void; /** Where to listen — `'player'` (container) or `'document'`. */ - target?: 'player' | 'document'; + target?: 'player' | 'document' | undefined; /** Whether `event.repeat` should fire the callback. */ - allowRepeat?: boolean; - disabled?: boolean; + repeatable?: boolean | undefined; + disabled?: boolean | undefined; /** Action name for the ARIA registry. */ - action?: string; + action?: string | undefined; } const MODIFIER_KEYS = new Set(['shift', 'ctrl', 'alt', 'meta']); diff --git a/packages/core/src/dom/hotkey/tests/coordinator.test.ts b/packages/core/src/dom/hotkey/tests/coordinator.test.ts index 24a7b621..25cfa2e2 100644 --- a/packages/core/src/dom/hotkey/tests/coordinator.test.ts +++ b/packages/core/src/dom/hotkey/tests/coordinator.test.ts @@ -200,20 +200,20 @@ describe('HotkeyCoordinator', () => { }); describe('repeat handling', () => { - it('ignores repeat events when allowRepeat is false', () => { + it('ignores repeat events when repeat is false', () => { const c = setup(); const onActivate = vi.fn(); - c.add({ keys: 'k', onActivate, allowRepeat: false }); + c.add({ keys: 'k', onActivate, repeatable: false }); keydown(container, 'k', { repeat: true }); expect(onActivate).not.toHaveBeenCalled(); }); - it('fires repeat events when allowRepeat is true', () => { + it('fires repeat events when repeatable is true', () => { const c = setup(); const onActivate = vi.fn(); - c.add({ keys: 'k', onActivate, allowRepeat: true }); + c.add({ keys: 'k', onActivate, repeatable: true }); keydown(container, 'k', { repeat: true }); diff --git a/packages/html/src/index.ts b/packages/html/src/index.ts index cf96f4e5..e49fec8b 100644 --- a/packages/html/src/index.ts +++ b/packages/html/src/index.ts @@ -27,8 +27,8 @@ export { ControlsElement } from './ui/controls/controls-element'; export { ControlsGroupElement } from './ui/controls/controls-group-element'; export { ErrorDialogElement } from './ui/error-dialog/error-dialog-element'; export { FullscreenButtonElement } from './ui/fullscreen-button/fullscreen-button-element'; +export { AriaKeyShortcutsController } from './ui/hotkey/aria-key-shortcuts-controller'; export { HotkeyElement } from './ui/hotkey/hotkey-element'; -export { HotkeyRegistryController } from './ui/hotkey/hotkey-registry-controller'; export { MediaButtonElement } from './ui/media-button-element'; // Primitives export * from './ui/media-element'; diff --git a/packages/html/src/ui/hotkey/hotkey-registry-controller.ts b/packages/html/src/ui/hotkey/aria-key-shortcuts-controller.ts similarity index 85% rename from packages/html/src/ui/hotkey/hotkey-registry-controller.ts rename to packages/html/src/ui/hotkey/aria-key-shortcuts-controller.ts index c93fe859..e78a8a32 100644 --- a/packages/html/src/ui/hotkey/hotkey-registry-controller.ts +++ b/packages/html/src/ui/hotkey/aria-key-shortcuts-controller.ts @@ -7,7 +7,7 @@ import { containerContext } from '../../player/context'; import type { PlayerControllerHost } from '../../player/player-controller'; /** Provides `aria-keyshortcuts` for a given hotkey action name. */ -export class HotkeyRegistryController implements ReactiveController { +export class AriaKeyShortcutsController implements ReactiveController { #action: string; #container: ContainerContextConsumer; @@ -20,7 +20,7 @@ export class HotkeyRegistryController implements ReactiveController { get value(): string | undefined { const container = this.#container.value?.container; if (!container) return undefined; - return findHotkeyCoordinator(container as HTMLElement)?.getAriaKeys(this.#action); + return findHotkeyCoordinator(container)?.getAriaKeys(this.#action); } hostConnected(): void {} diff --git a/packages/html/src/ui/hotkey/hotkey-element.ts b/packages/html/src/ui/hotkey/hotkey-element.ts index 5633032d..68c03fa6 100644 --- a/packages/html/src/ui/hotkey/hotkey-element.ts +++ b/packages/html/src/ui/hotkey/hotkey-element.ts @@ -58,14 +58,14 @@ export class HotkeyElement extends MediaElement { const { value, action } = this; - this.#cleanup = createHotkey(container as HTMLElement, { + this.#cleanup = createHotkey(container, { keys: this.keys, action, target: this.target, disabled: this.disabled, - allowRepeat: !isHotkeyToggleAction(action), + repeatable: !isHotkeyToggleAction(action), onActivate: (_event, key) => { - resolver({ store, key, ...(value !== undefined && { value }) }); + resolver({ store, key, value }); }, }); } diff --git a/packages/html/src/ui/hotkey/tests/hotkey-element.test.ts b/packages/html/src/ui/hotkey/tests/hotkey-element.test.ts index 93f84c7e..c0073bbf 100644 --- a/packages/html/src/ui/hotkey/tests/hotkey-element.test.ts +++ b/packages/html/src/ui/hotkey/tests/hotkey-element.test.ts @@ -1,7 +1,6 @@ import { afterEach, describe, expect, it } from 'vitest'; - +import { AriaKeyShortcutsController } from '../aria-key-shortcuts-controller'; import { HotkeyElement } from '../hotkey-element'; -import { HotkeyRegistryController } from '../hotkey-registry-controller'; let tagCounter = 0; @@ -42,12 +41,12 @@ describe('HotkeyElement', () => { }); }); -describe('HotkeyRegistryController', () => { +describe('AriaKeyShortcutsController', () => { it('returns undefined when no coordinator exists', () => { const el = createElement(HotkeyElement); document.body.appendChild(el); - const controller = new HotkeyRegistryController(el, 'togglePaused'); + const controller = new AriaKeyShortcutsController(el, 'togglePaused'); expect(controller.value).toBeUndefined(); }); diff --git a/packages/html/src/ui/media-button-element.ts b/packages/html/src/ui/media-button-element.ts index aa1501dd..e23de36b 100644 --- a/packages/html/src/ui/media-button-element.ts +++ b/packages/html/src/ui/media-button-element.ts @@ -10,7 +10,7 @@ import type { PropertyDeclarationMap, PropertyValues } from '@videojs/element'; import type { State } from '@videojs/store'; import type { PlayerController } from '../player/player-controller'; -import { HotkeyRegistryController } from './hotkey/hotkey-registry-controller'; +import { AriaKeyShortcutsController } from './hotkey/aria-key-shortcuts-controller'; import { MediaElement } from './media-element'; /** Abstract base for HTML custom elements that render a media-control button. */ @@ -37,13 +37,13 @@ export abstract class MediaButtonElement exte } #disconnect: AbortController | null = null; - #hotkeyRegistry: HotkeyRegistryController | null = null; + #hotkeyRegistry: AriaKeyShortcutsController | null = null; override connectedCallback(): void { super.connectedCallback(); if (this.hotkeyAction && !this.#hotkeyRegistry) { - this.#hotkeyRegistry = new HotkeyRegistryController(this, this.hotkeyAction); + this.#hotkeyRegistry = new AriaKeyShortcutsController(this, this.hotkeyAction); } this.#disconnect = new AbortController();