mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
fix(core): allow undefined hotkey options (#1242)
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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']);
|
||||
|
||||
@@ -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 });
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
+2
-2
@@ -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 {}
|
||||
@@ -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 });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
|
||||
@@ -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<Core extends MediaButtonComponent> 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();
|
||||
|
||||
Reference in New Issue
Block a user