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.

166 lines 5.49 kB
import { isElement } from '../util.js'; export const arrowLeft = 'ArrowLeft'; export const arrowRight = 'ArrowRight'; export const arrowUp = 'ArrowUp'; export const arrowDown = 'ArrowDown'; export const enterKey = 'Enter'; export const spaceBar = ' '; export const escapeKey = 'Escape'; export const homeKey = 'Home'; export const endKey = 'End'; export const pageUpKey = 'PageUp'; export const pageDownKey = 'PageDown'; export const tabKey = 'Tab'; export const altKey = 'Alt'; export const ctrlKey = 'Ctrl'; export const metaKey = 'Meta'; export const shiftKey = 'Shift'; const __modifiers = new Set([altKey, ctrlKey, metaKey, shiftKey].map((key) => key.toLowerCase())); const defaultOptions = { skip: ['input', 'textarea', 'select'], }; function normalizeKeys(keys) { return (Array.isArray(keys) ? keys : [keys]).map((key) => key.toLowerCase()); } function isModifier(key) { return __modifiers.has(key); } function isKeydown(event) { return event.type === 'keydown'; } function isKeyup(event) { return event.type === 'keyup'; } function isKeydownTrigger(triggers) { return triggers ? triggers.includes('keydown') || isKeydownRepeatTrigger(triggers) : false; } function isKeyupTrigger(triggers) { return triggers ? triggers.includes('keyup') : false; } function isKeydownRepeatTrigger(triggers) { return triggers ? triggers.includes('keydownRepeat') : false; } export function parseKeys(keys) { const parsed = normalizeKeys(keys); return { keys: parsed.filter((key) => !isModifier(key)), modifiers: parsed.filter((key) => isModifier(key)), }; } class KeyBindingController { get _element() { if (this._observedElement) { return this._observedElement; } return this._ref ? this._ref.value : this._host; } observeElement(element) { element.addEventListener('keydown', this); element.addEventListener('keyup', this); this._observedElement = element; return { unsubscribe: () => { this._observedElement?.removeEventListener('keydown', this); this._observedElement?.removeEventListener('keyup', this); this._observedElement = undefined; }, }; } constructor(host, options) { this.bindings = new Set(); this.pressedKeys = new Set(); this._host = host; this._ref = options?.ref; this._options = { ...defaultOptions, ...options }; host.addController(this); } eventModifiersMatch(binding, event) { if (binding.options?.preventDefault) { event.preventDefault(); } if (binding.options?.stopPropagation) { event.stopPropagation(); } } keysMatch(binding, event) { const modifiers = binding.modifiers ?? []; return (binding.keys.every((key) => this.pressedKeys.has(key)) && modifiers.every((mod) => !!event[`${mod}Key`])); } bindingMatches(binding, event) { const triggers = binding.options?.triggers ?? ['keydown']; if (!this.keysMatch(binding, event)) { return false; } if (isKeydown(event) && isKeydownTrigger(triggers)) { return true; } if (isKeyup(event) && isKeyupTrigger(triggers)) { return true; } return false; } handleEvent(event) { const key = event.key.toLowerCase(); const path = event.composedPath(); const skip = this._options?.skip; if (!this._element || !path.includes(this._element)) { return; } if (skip) { const shouldSkip = Array.isArray(skip) ? path.some((target) => isElement(target) && skip.some((selector) => target.matches(selector))) : skip.call(this._host, event.target, event); if (shouldSkip) { return; } } if (isModifier(key)) { this.pressedKeys.clear(); } if (isKeydown(event) && !isModifier(key)) { this.pressedKeys.add(key); } for (const binding of this.bindings) { if (this.bindingMatches(binding, event)) { this.eventModifiersMatch(binding, event); binding.handler.call(this._host, event); if (isKeydownRepeatTrigger(binding.options?.triggers)) { this.pressedKeys.delete(key); } } } if (isKeyup(event) && !isModifier(key)) { this.pressedKeys.delete(key); } } set(key, fn, options) { this.bindings.add({ ...parseKeys(key), handler: fn, options: { ...this._options?.bindingDefaults, ...options }, }); return this; } setActivateHandler(fn, options) { for (const key of [enterKey, spaceBar]) { this.set(key, fn, options); } return this; } hostConnected() { this._host.addEventListener('keyup', this); this._host.addEventListener('keydown', this); } hostDisconnected() { this._host.removeEventListener('keyup', this); this._host.removeEventListener('keydown', this); } } export function addKeybindings(element, options) { return new KeyBindingController(element, options); } //# sourceMappingURL=key-bindings.js.map