UNPKG

igniteui-webcomponents

Version:

Ignite UI for Web Components is a complete library of UI components, giving you the ability to build modern web applications using encapsulation and the concept of reusable components in a dependency-free approach.

241 lines (240 loc) 10.1 kB
import type { ReactiveController, ReactiveControllerHost } from 'lit'; import type { Ref } from 'lit/directives/ref.js'; export declare const arrowLeft: "ArrowLeft"; export declare const arrowRight: "ArrowRight"; export declare const arrowUp: "ArrowUp"; export declare const arrowDown: "ArrowDown"; export declare const enterKey: "Enter"; export declare const spaceBar: " "; export declare const escapeKey: "Escape"; export declare const homeKey: "Home"; export declare const endKey: "End"; export declare const pageUpKey: "PageUp"; export declare const pageDownKey: "PageDown"; export declare const tabKey: "Tab"; export declare const altKey: "Alt"; export declare const ctrlKey: "Control"; export declare const metaKey: "Meta"; export declare const shiftKey: "Shift"; type KeyBindingHandler = (event: KeyboardEvent) => void; type KeyBindingObserverCleanup = { unsubscribe: () => void; }; /** * Whether the current event should be ignored by the controller. * * @param node - The event target * @param event - The event object * * When `true` is returned, the current event is ignored. */ type KeyBindingSkipCallback = (node: Element, event: KeyboardEvent) => boolean; /** * The event type which will trigger the bound handler. */ type KeyBindingTrigger = 'keydown' | 'keyup'; /** * Configuration object for the controller. * @ignore */ interface KeyBindingControllerOptions { /** * By default, the controller listens for keypress events in the context of the host element. * If you pass a `ref`, you can limit the observation to a certain DOM part of the host scope. */ ref?: Ref; /** * Option to ignore key press events. * * If passed an array of CSS selectors, it will ignore key presses originating from elements in the event composed path * that match one of the selectors. * Otherwise you can pass a {@link KeyBindingSkipCallback} function. * * Defaults to `['input', 'textarea', 'select']`. * * @example * ```ts * { * // Skip events originating from elements with `readonly` attribute * skip: ['[readonly]'] * } * ... * { * // Same as above but with a callback * skip: (node: Element) => node.hasAttribute('readonly') * } * ``` */ skip?: string[] | KeyBindingSkipCallback; /** * A set of KeyBindingOptions configuration which is applied to every handler * that is added to the controller. * * Any additional KeyBindingOptions values passed when `set` is called * will be merged with `bindingDefaults`. */ bindingDefaults?: KeyBindingOptions; } /** * Configuration object for customizing the behavior of * the registered handler. */ interface KeyBindingOptions { /** * The event type(s) on which the handler will be invoked. * * Defaults to `keydown` if not set. */ triggers?: KeyBindingTrigger[]; /** * Whether the handler should fire on auto-repeated keydown events (i.e. when a key is held down). * * Defaults to `false`. */ repeat?: boolean; /** * Whether to call `preventDefault` on the target event before the handler is invoked. */ preventDefault?: boolean; /** * Whether to call `stopPropagation` on the target event before the handler is invoked. */ stopPropagation?: boolean; } /** * Maps internal modifier names to their corresponding `KeyboardEvent` boolean property names. * Needed because `ctrlKey` in the DOM is the property for the `'control'` modifier (not `'controlKey'`). */ export declare const MODIFIER_EVENT_KEYS: Record<string, string>; /** * A controller for managing key bindings on a host element. It allows you to register handlers for specific key combinations, * with support for modifier keys and event options such as `preventDefault` and `stopPropagation`. * * The controller listens for keyboard events on the host element (or an optionally specified element) and invokes the appropriate handlers * when the registered key combinations are detected. * */ declare class KeyBindingController implements ReactiveController { private static readonly _defaultOptions; private readonly _host; private readonly _ref?; private readonly _abortHandle; private readonly _bindings; private readonly _allowedKeys; private readonly _pressedKeys; private readonly _options; private readonly _skipSelector; private _observedElement?; private get _element(); constructor(host: ReactiveControllerHost & Element, options?: KeyBindingControllerOptions); /** * Applies the event modifiers specified in the binding options to the provided keyboard event. * If `preventDefault` is set, it calls `event.preventDefault()`. * If `stopPropagation` is set, it calls `event.stopPropagation()`. */ private _applyEventModifiers; /** * Determines whether the provided keyboard event matches the specified key binding, * taking into account the event type and the binding's trigger options. */ private _bindingMatches; /** * Determines whether the provided event should be ignored based on the controller's configuration and the event's context. * The method checks if the event's key is among the allowed keys, if the event originated from within the controller's scope, * and if it matches any of the skip conditions defined in the controller's options. */ private _shouldSkip; /** @internal */ hostConnected(): void; /** @internal */ hostDisconnected(): void; /** * Handles the global blur event to clear the internal state of pressed keys. * * This is necessary to prevent "stuck" keys when the user switches to another application * or tab while holding down a key. */ private _handleGlobalBlur; /** * Handles keyboard events on the observed element. * * It checks if the event should be skipped based on the controller's configuration, * and if not, it determines if there is a registered handler for the combination of pressed keys and active modifiers. * * If a matching handler is found, it applies the specified event modifiers and invokes the handler. * It also manages the internal state of currently pressed keys to accurately detect key combinations. * */ private _handleKeyEvent; /** @internal */ handleEvent(event: KeyboardEvent | FocusEvent): void; /** * Registers a key binding with the specified key(s), handler function, and optional configuration. * * The `key` parameter can be a single key or an array of keys, and can include modifier keys (e.g., 'ctrl+s', ['shift', 'a']). * The `handler` is a function that will be called when the specified key combination is detected. * The `bindingOptions` allow you to customize the behavior of the binding, such as which event types trigger the handler, * whether it should fire on auto-repeated keydown events, and whether to call `preventDefault` or `stopPropagation`. * * The method returns the controller instance to allow for method chaining. */ set(key: string | string[], handler: KeyBindingHandler, bindingOptions?: KeyBindingOptions): this; /** * Registers the provided handler function to be called when either the Enter key or Space bar is pressed. * * This is a common pattern for activating buttons or interactive elements, and this method provides a convenient way to set up such bindings. * * The method accepts optional `KeyBindingOptions` which are applied to both the Enter key and Space bar bindings. * It returns the controller instance to allow for method chaining. * */ setActivateHandler(handler: KeyBindingHandler, options?: KeyBindingOptions): this; /** * Sets the controller to listen for keyboard events on an arbitrary `element` in the page context. * All the configuration and event handlers are applied as well. * * Returns an object with an `unsubscribe` function which should be called when the observing of keyboard * events on the `element` should cease. */ observeElement(element: Element): KeyBindingObserverCleanup; } /** * Parses the provided key(s) and separates them into modifiers and regular keys. * * Modifiers are keys like Alt, Ctrl, Meta and Shift which modify the behavior of other keys when pressed in combination. * Regular keys are all other keys which trigger the bound handler when pressed. * * The returned `keys` and `modifiers` are normalized to lowercase for consistency. * * @internal * * @param inputKeys - The key or keys to parse, provided as a string or an array of strings. * @returns An object containing the separated `keys` and `modifiers`. */ export declare function parseKeys(inputKeys: string | string[]): { keys: string[]; modifiers: string[]; }; /** * Controller factory function which creates a {@link KeyBindingController} instance and attaches it to the provided host. * * @param element - The host element to which the controller will be attached. * @param options - Optional configuration for the controller. * @returns The created {@link KeyBindingController} instance. * * @example * ```ts * class MyComponent extends LitElement { * private _keyBindings = addKeybindings(this, { * skip: ['input', 'textarea'], // Optional: Skip key events originating from these elements * bindingDefaults: { preventDefault: true }, // Optional: Default options for all bindings * }); * * constructor() { * super(); * this._keyBindings.set('ctrl+s', this._handleSave); // Register a key binding * } * ``` */ export declare function addKeybindings(element: ReactiveControllerHost & Element, options?: KeyBindingControllerOptions): KeyBindingController; export type { KeyBindingController, KeyBindingControllerOptions, KeyBindingHandler, KeyBindingObserverCleanup, KeyBindingOptions, KeyBindingSkipCallback, KeyBindingTrigger, };