UNPKG

coveo-search-ui

Version:

Coveo JavaScript Search Framework

267 lines (226 loc) • 6.77 kB
import { Logger } from '../misc/Logger'; import { ComponentEvents } from '../ui/Base/Component'; import { KEYBOARD, KeyboardUtils } from '../utils/KeyboardUtils'; import { $$, Dom } from './Dom'; import 'styling/_AccessibleButton'; export enum ArrowDirection { UP, RIGHT, DOWN, LEFT } export class AccessibleButton { private element: Dom; private labelOrTitleRequired = true; private label: string; private title: string; private role: string; private clickAction: (e: Event) => void; private enterKeyboardAction: (e: Event) => void; private blurAction: (e: Event) => void; private mouseleaveAction: (e: Event) => void; private focusAction: (e: Event) => void; private mouseenterAction: (e: Event) => void; private arrowsAction: (direction: ArrowDirection, e: Event) => void; private logger: Logger; private eventOwner: ComponentEvents; public constructor() { this.logger = new Logger(this); } public withOwner(owner: ComponentEvents) { this.eventOwner = owner; return this; } public withElement(element: Dom | HTMLElement) { if (element instanceof HTMLElement) { this.element = $$(element); } else { this.element = element; } return this; } public withLabel(label: string) { this.label = label; return this; } public withoutLabelOrTitle() { this.labelOrTitleRequired = false; return this; } public withTitle(title: string) { this.title = title; return this; } public withSelectAction(action: (e: Event) => void) { this.clickAction = action; this.enterKeyboardAction = action; return this; } public withClickAction(clickAction: (e: Event) => void) { this.clickAction = clickAction; return this; } public withEnterKeyboardAction(enterAction: (e: Event) => void) { this.enterKeyboardAction = enterAction; return this; } public withFocusAndMouseEnterAction(action: (e: Event) => void) { this.focusAction = action; this.mouseenterAction = action; return this; } public withFocusAction(action: (e: Event) => void) { this.focusAction = action; return this; } public withMouseEnterAction(action: (e: Event) => void) { this.mouseenterAction = action; return this; } public withBlurAndMouseLeaveAction(action: (e: Event) => void) { this.mouseleaveAction = action; this.blurAction = action; return this; } public withMouseLeaveAction(action: (e: Event) => void) { this.mouseleaveAction = action; return this; } public withBlurAction(action: (e: Event) => void) { this.blurAction = action; return this; } public withArrowsAction(action: (direction: ArrowDirection, e: Event) => void) { this.arrowsAction = action; return this; } public withRole(role: string) { this.role = role; return this; } public build() { if (!this.element) { this.element = $$('div'); } this.ensureCorrectRole(); this.ensureCorrectLabelOrTitle(); this.ensureSelectAction(); this.ensureUnselectAction(); this.ensureMouseenterAndFocusAction(); this.ensureMouseleaveAndBlurAction(); this.ensureArrowsAction(); this.ensureDifferentiationBetweenKeyboardAndMouseFocus(); return this; } private ensureDifferentiationBetweenKeyboardAndMouseFocus() { const classWhenPressed = 'coveo-accessible-button-pressed'; $$(this.element).addClass('coveo-accessible-button'); $$(this.element).on('mouseup', () => $$(this.element).addClass(classWhenPressed)); $$(this.element).on('focus', () => { $$(this.element).removeClass(classWhenPressed); }); } private ensureCorrectRole() { if (!this.element.getAttribute('role')) { this.element.setAttribute('role', this.role || 'button'); } } private ensureCorrectLabelOrTitle() { if (!this.labelOrTitleRequired) { return; } if (!this.label && !this.title) { this.logger.error(`Missing a label or title to create an accessible button!`); return; } if (this.title) { this.element.setAttribute('title', this.title); return; } this.element.setAttribute('aria-label', this.label); } private ensureTabIndex() { this.element.setAttribute('tabindex', '0'); } private ensureSelectAction() { if (this.enterKeyboardAction) { this.ensureTabIndex(); this.bindEvent( 'keyup', KeyboardUtils.keypressAction(KEYBOARD.ENTER, (e: Event) => this.enterKeyboardAction(e)) ); this.bindEvent( 'keydown', KeyboardUtils.keypressAction(KEYBOARD.SPACEBAR, (e: Event) => { if (e.target instanceof HTMLInputElement) { return; } e.preventDefault(); }) ); this.bindEvent( 'keyup', KeyboardUtils.keypressAction(KEYBOARD.SPACEBAR, (e: Event) => { if (e.target instanceof HTMLInputElement) { return; } this.enterKeyboardAction(e); }) ); } if (this.clickAction) { this.bindEvent('click', this.clickAction); } } private ensureUnselectAction() { if (this.blurAction) { this.bindEvent('blur', this.blurAction); } if (this.mouseleaveAction) { this.bindEvent('mouseleave', this.mouseleaveAction); } } private ensureMouseenterAndFocusAction() { if (this.mouseenterAction) { this.bindEvent('mouseenter', this.mouseenterAction); } if (this.focusAction) { this.bindEvent('focus', this.focusAction); } } private ensureMouseleaveAndBlurAction() { if (this.mouseleaveAction) { this.bindEvent('mouseleave', this.mouseleaveAction); } if (this.blurAction) { this.bindEvent('blur', this.blurAction); } } private ensureArrowsAction() { if (this.arrowsAction) { this.bindEvent( 'keyup', KeyboardUtils.keypressAction(KEYBOARD.UP_ARROW, (e: Event) => this.arrowsAction(ArrowDirection.UP, e)) ); this.bindEvent( 'keyup', KeyboardUtils.keypressAction(KEYBOARD.RIGHT_ARROW, (e: Event) => this.arrowsAction(ArrowDirection.RIGHT, e)) ); this.bindEvent( 'keyup', KeyboardUtils.keypressAction(KEYBOARD.DOWN_ARROW, (e: Event) => this.arrowsAction(ArrowDirection.DOWN, e)) ); this.bindEvent( 'keyup', KeyboardUtils.keypressAction(KEYBOARD.LEFT_ARROW, (e: Event) => this.arrowsAction(ArrowDirection.LEFT, e)) ); } } private bindEvent(event: string, action: (...args: any[]) => void) { if (this.eventOwner) { this.eventOwner.on(this.element, event, action); } else { $$(this.element).on(event, action); } } }