UNPKG

@limetech/lime-elements

Version:
92 lines (91 loc) 3.45 kB
const eventHandlers = new WeakMap(); class EnterClickable { constructor(element) { this.element = element; this.isActive = false; this.hasJustReleasedEnter = true; this.handleKeyDown = (event) => { if (event.key === 'Enter' && !this.isActive && !event.repeat) { this.isActive = true; } }; this.handleKeyUp = (event) => { if (event.key === 'Enter' && this.isActive) { this.isActive = false; this.hasJustReleasedEnter = true; } }; this.handleBlur = () => { this.isActive = false; this.hasJustReleasedEnter = true; }; this.handleClick = (event) => { if (!this.isActive) { return; } if (this.hasJustReleasedEnter) { this.hasJustReleasedEnter = false; return; } event.stopImmediatePropagation(); }; this.callbacks = { keydownHandler: this.handleKeyDown.bind(this), keyupHandler: this.handleKeyUp.bind(this), blurHandler: this.handleBlur.bind(this), clickHandler: this.handleClick.bind(this), }; } enable() { this.element.addEventListener('keydown', this.callbacks.keydownHandler); this.element.addEventListener('keyup', this.callbacks.keyupHandler); this.element.addEventListener('blur', this.callbacks.blurHandler); this.element.addEventListener('click', this.callbacks.clickHandler, true); } disable() { this.element.removeEventListener('keydown', this.callbacks.keydownHandler); this.element.removeEventListener('keyup', this.callbacks.keyupHandler); this.element.removeEventListener('blur', this.callbacks.blurHandler); this.element.removeEventListener('click', this.callbacks.clickHandler, true); } } /** * Overrides the default browser behavior for clickable elements. * When focused and pressing down Enter, avoids calling onClick repeatedly. * * **Accessibility Context:** * Per WCAG 2.1 guidelines, keyboard users must be able to activate buttons and * clickable elements using both Enter and Space keys. Browsers natively support * both keys on button elements, allowing keyboard-only users full access to * interactive controls. * * **Why only Enter, not Space?** * - Enter key: Fires click events repeatedly while held down (browser bug/quirk) * - Space key: Fires click only once on keyup (correct behavior) * * This utility only fixes the problematic Enter key behavior. Space key * works correctly by default and doesn't need intervention. * * @param element - The clickable element */ export function makeEnterClickable(element) { if (!eventHandlers.has(element)) { const enterClickable = new EnterClickable(element); enterClickable.enable(); eventHandlers.set(element, enterClickable); } } /** * Removes the keyboard-enter click override behavior from an element. * Call this during teardown (e.g. `disconnectedCallback`) to avoid leaking * event listeners. * * @param element - The clickable element */ export function removeEnterClickable(element) { const enterClickable = eventHandlers.get(element); if (enterClickable) { enterClickable.disable(); eventHandlers.delete(element); } }