UNPKG

@spartacus/storefront

Version:

Spartacus Storefront is a package that you can include in your application, which allows you to add default storefront features.

75 lines 10.2 kB
import { Injectable } from '@angular/core'; import * as i0 from "@angular/core"; export class SelectFocusUtility { constructor() { /** * Query selectors used to query focusable child elements of the host element. * The selectors are supplemented with `:not([disabled])` and `:not([hidden])`. */ this.focusableSelectors = [ 'a[href]', 'button', '[tabindex]', 'input', 'select', 'textarea', ]; // like to leave out the following as we don't use it, and make this list exensible. // `[contentEditable=true]`, // very unlikely to suport as we're not a business tool // `iframe`, // we really don't like iframes... // `area[href]`, // very debatable! this.focusableSelectorSuffix = ':not([disabled]):not([hidden])'; } query(host, selector) { if (!selector || selector === '') { return []; } return Array.from(host.querySelectorAll(selector)); } findFirstFocusable(host, config = { autofocus: true }) { const selector = typeof (config === null || config === void 0 ? void 0 : config.autofocus) === 'string' ? config.autofocus : '[autofocus]'; // fallback to first focusable return (this.query(host, selector).find((el) => !this.isHidden(el)) || this.findFocusable(host).find((el) => Boolean(el))); } /** * returns all focusable child elements of the host element. The element selectors * are build from the `focusableSelectors`. * * @param host the `HTMLElement` used to query focusable elements * @param locked indicates whether inactive (`tabindex="-1"`) focusable elements should be returned * @param invisible indicates whether hidden focusable elements should be returned */ findFocusable(host, locked = false, invisible = false) { let suffix = this.focusableSelectorSuffix; if (!locked) { suffix += `:not([tabindex='-1'])`; } const selector = this.focusableSelectors .map((s) => (s += suffix)) .join(','); return this.query(host, selector).filter((el) => !invisible ? !this.isHidden(el) : Boolean(el)); } /** * Indicates whether the element is hidden by CSS. There are various CSS rules and * HTML structures which can lead to an hidden or invisible element. An `offsetParent` * of null indicates that the element or any of it's decendants is hidden (`display:none`). * * Oother techniques use the visibility (`visibility: hidden`), opacity (`opacity`) or * phyisical location on the element itself or any of it's anchestor elements. Those * technique require to work with the _computed styles_, which will cause a performance * downgrade. We don't do this in the standard implementaton. */ isHidden(el) { return el.offsetParent === null; } } SelectFocusUtility.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.0.5", ngImport: i0, type: SelectFocusUtility, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); SelectFocusUtility.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.0.5", ngImport: i0, type: SelectFocusUtility, providedIn: 'root' }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.0.5", ngImport: i0, type: SelectFocusUtility, decorators: [{ type: Injectable, args: [{ providedIn: 'root', }] }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VsZWN0LWZvY3VzLnV0aWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9zdG9yZWZyb250bGliL2xheW91dC9hMTF5L2tleWJvYXJkLWZvY3VzL3NlcnZpY2VzL3NlbGVjdC1mb2N1cy51dGlsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7O0FBTTNDLE1BQU0sT0FBTyxrQkFBa0I7SUFIL0I7UUFJRTs7O1dBR0c7UUFDTyx1QkFBa0IsR0FBYTtZQUN2QyxTQUFTO1lBQ1QsUUFBUTtZQUNSLFlBQVk7WUFDWixPQUFPO1lBQ1AsUUFBUTtZQUNSLFVBQVU7U0FDWCxDQUFDO1FBRUYsb0ZBQW9GO1FBQ3BGLHNGQUFzRjtRQUN0RixpREFBaUQ7UUFDakQscUNBQXFDO1FBRTNCLDRCQUF1QixHQUFHLGdDQUFnQyxDQUFDO0tBOER0RTtJQTVEQyxLQUFLLENBQUMsSUFBaUIsRUFBRSxRQUFnQjtRQUN2QyxJQUFJLENBQUMsUUFBUSxJQUFJLFFBQVEsS0FBSyxFQUFFLEVBQUU7WUFDaEMsT0FBTyxFQUFFLENBQUM7U0FDWDtRQUNELE9BQU8sS0FBSyxDQUFDLElBQUksQ0FDZixJQUFJLENBQUMsZ0JBQWdCLENBQUMsUUFBUSxDQUE0QixDQUMzRCxDQUFDO0lBQ0osQ0FBQztJQUVELGtCQUFrQixDQUNoQixJQUFpQixFQUNqQixTQUEwQixFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUU7UUFFN0MsTUFBTSxRQUFRLEdBQ1osT0FBTyxDQUFBLE1BQU0sYUFBTixNQUFNLHVCQUFOLE1BQU0sQ0FBRSxTQUFTLENBQUEsS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQztRQUMzRSw4QkFBOEI7UUFDOUIsT0FBTyxDQUNMLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQzNELElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FDbkQsQ0FBQztJQUNKLENBQUM7SUFFRDs7Ozs7OztPQU9HO0lBQ0gsYUFBYSxDQUNYLElBQWlCLEVBQ2pCLE1BQU0sR0FBRyxLQUFLLEVBQ2QsU0FBUyxHQUFHLEtBQUs7UUFFakIsSUFBSSxNQUFNLEdBQUcsSUFBSSxDQUFDLHVCQUF1QixDQUFDO1FBQzFDLElBQUksQ0FBQyxNQUFNLEVBQUU7WUFDWCxNQUFNLElBQUksdUJBQXVCLENBQUM7U0FDbkM7UUFDRCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsa0JBQWtCO2FBQ3JDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksTUFBTSxDQUFDLENBQUM7YUFDekIsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ2IsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxRQUFRLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUM5QyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLENBQzlDLENBQUM7SUFDSixDQUFDO0lBRUQ7Ozs7Ozs7OztPQVNHO0lBQ08sUUFBUSxDQUFDLEVBQWU7UUFDaEMsT0FBTyxFQUFFLENBQUMsWUFBWSxLQUFLLElBQUksQ0FBQztJQUNsQyxDQUFDOzsrR0FoRlUsa0JBQWtCO21IQUFsQixrQkFBa0IsY0FGakIsTUFBTTsyRkFFUCxrQkFBa0I7a0JBSDlCLFVBQVU7bUJBQUM7b0JBQ1YsVUFBVSxFQUFFLE1BQU07aUJBQ25CIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQXV0b0ZvY3VzQ29uZmlnIH0gZnJvbSAnLi4va2V5Ym9hcmQtZm9jdXMubW9kZWwnO1xuXG5ASW5qZWN0YWJsZSh7XG4gIHByb3ZpZGVkSW46ICdyb290Jyxcbn0pXG5leHBvcnQgY2xhc3MgU2VsZWN0Rm9jdXNVdGlsaXR5IHtcbiAgLyoqXG4gICAqIFF1ZXJ5IHNlbGVjdG9ycyB1c2VkIHRvIHF1ZXJ5IGZvY3VzYWJsZSBjaGlsZCBlbGVtZW50cyBvZiB0aGUgaG9zdCBlbGVtZW50LlxuICAgKiBUaGUgc2VsZWN0b3JzIGFyZSBzdXBwbGVtZW50ZWQgd2l0aCBgOm5vdChbZGlzYWJsZWRdKWAgYW5kIGA6bm90KFtoaWRkZW5dKWAuXG4gICAqL1xuICBwcm90ZWN0ZWQgZm9jdXNhYmxlU2VsZWN0b3JzOiBzdHJpbmdbXSA9IFtcbiAgICAnYVtocmVmXScsXG4gICAgJ2J1dHRvbicsXG4gICAgJ1t0YWJpbmRleF0nLFxuICAgICdpbnB1dCcsXG4gICAgJ3NlbGVjdCcsXG4gICAgJ3RleHRhcmVhJyxcbiAgXTtcblxuICAvLyBsaWtlIHRvIGxlYXZlIG91dCB0aGUgZm9sbG93aW5nIGFzIHdlIGRvbid0IHVzZSBpdCwgYW5kIG1ha2UgdGhpcyBsaXN0IGV4ZW5zaWJsZS5cbiAgLy8gICBgW2NvbnRlbnRFZGl0YWJsZT10cnVlXWAsIC8vIHZlcnkgdW5saWtlbHkgdG8gc3Vwb3J0IGFzIHdlJ3JlIG5vdCBhIGJ1c2luZXNzIHRvb2xcbiAgLy8gICBgaWZyYW1lYCwgLy8gd2UgcmVhbGx5IGRvbid0IGxpa2UgaWZyYW1lcy4uLlxuICAvLyAgIGBhcmVhW2hyZWZdYCwgLy8gdmVyeSBkZWJhdGFibGUhXG5cbiAgcHJvdGVjdGVkIGZvY3VzYWJsZVNlbGVjdG9yU3VmZml4ID0gJzpub3QoW2Rpc2FibGVkXSk6bm90KFtoaWRkZW5dKSc7XG5cbiAgcXVlcnkoaG9zdDogSFRNTEVsZW1lbnQsIHNlbGVjdG9yOiBzdHJpbmcpOiBIVE1MRWxlbWVudFtdIHtcbiAgICBpZiAoIXNlbGVjdG9yIHx8IHNlbGVjdG9yID09PSAnJykge1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cbiAgICByZXR1cm4gQXJyYXkuZnJvbShcbiAgICAgIGhvc3QucXVlcnlTZWxlY3RvckFsbChzZWxlY3RvcikgYXMgTm9kZUxpc3RPZjxIVE1MRWxlbWVudD5cbiAgICApO1xuICB9XG5cbiAgZmluZEZpcnN0Rm9jdXNhYmxlKFxuICAgIGhvc3Q6IEhUTUxFbGVtZW50LFxuICAgIGNvbmZpZzogQXV0b0ZvY3VzQ29uZmlnID0geyBhdXRvZm9jdXM6IHRydWUgfVxuICApOiBIVE1MRWxlbWVudCB7XG4gICAgY29uc3Qgc2VsZWN0b3IgPVxuICAgICAgdHlwZW9mIGNvbmZpZz8uYXV0b2ZvY3VzID09PSAnc3RyaW5nJyA/IGNvbmZpZy5hdXRvZm9jdXMgOiAnW2F1dG9mb2N1c10nO1xuICAgIC8vIGZhbGxiYWNrIHRvIGZpcnN0IGZvY3VzYWJsZVxuICAgIHJldHVybiAoXG4gICAgICB0aGlzLnF1ZXJ5KGhvc3QsIHNlbGVjdG9yKS5maW5kKChlbCkgPT4gIXRoaXMuaXNIaWRkZW4oZWwpKSB8fFxuICAgICAgdGhpcy5maW5kRm9jdXNhYmxlKGhvc3QpLmZpbmQoKGVsKSA9PiBCb29sZWFuKGVsKSlcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIHJldHVybnMgYWxsIGZvY3VzYWJsZSBjaGlsZCBlbGVtZW50cyBvZiB0aGUgaG9zdCBlbGVtZW50LiBUaGUgZWxlbWVudCBzZWxlY3RvcnNcbiAgICogYXJlIGJ1aWxkIGZyb20gdGhlIGBmb2N1c2FibGVTZWxlY3RvcnNgLlxuICAgKlxuICAgKiBAcGFyYW0gaG9zdCB0aGUgYEhUTUxFbGVtZW50YCB1c2VkIHRvIHF1ZXJ5IGZvY3VzYWJsZSBlbGVtZW50c1xuICAgKiBAcGFyYW0gbG9ja2VkIGluZGljYXRlcyB3aGV0aGVyIGluYWN0aXZlIChgdGFiaW5kZXg9XCItMVwiYCkgZm9jdXNhYmxlIGVsZW1lbnRzIHNob3VsZCBiZSByZXR1cm5lZFxuICAgKiBAcGFyYW0gaW52aXNpYmxlIGluZGljYXRlcyB3aGV0aGVyIGhpZGRlbiBmb2N1c2FibGUgZWxlbWVudHMgc2hvdWxkIGJlIHJldHVybmVkXG4gICAqL1xuICBmaW5kRm9jdXNhYmxlKFxuICAgIGhvc3Q6IEhUTUxFbGVtZW50LFxuICAgIGxvY2tlZCA9IGZhbHNlLFxuICAgIGludmlzaWJsZSA9IGZhbHNlXG4gICk6IEhUTUxFbGVtZW50W10ge1xuICAgIGxldCBzdWZmaXggPSB0aGlzLmZvY3VzYWJsZVNlbGVjdG9yU3VmZml4O1xuICAgIGlmICghbG9ja2VkKSB7XG4gICAgICBzdWZmaXggKz0gYDpub3QoW3RhYmluZGV4PSctMSddKWA7XG4gICAgfVxuICAgIGNvbnN0IHNlbGVjdG9yID0gdGhpcy5mb2N1c2FibGVTZWxlY3RvcnNcbiAgICAgIC5tYXAoKHMpID0+IChzICs9IHN1ZmZpeCkpXG4gICAgICAuam9pbignLCcpO1xuICAgIHJldHVybiB0aGlzLnF1ZXJ5KGhvc3QsIHNlbGVjdG9yKS5maWx0ZXIoKGVsKSA9PlxuICAgICAgIWludmlzaWJsZSA/ICF0aGlzLmlzSGlkZGVuKGVsKSA6IEJvb2xlYW4oZWwpXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbmRpY2F0ZXMgd2hldGhlciB0aGUgZWxlbWVudCBpcyBoaWRkZW4gYnkgQ1NTLiBUaGVyZSBhcmUgdmFyaW91cyBDU1MgcnVsZXMgYW5kXG4gICAqIEhUTUwgc3RydWN0dXJlcyB3aGljaCBjYW4gbGVhZCB0byBhbiBoaWRkZW4gb3IgaW52aXNpYmxlIGVsZW1lbnQuIEFuIGBvZmZzZXRQYXJlbnRgXG4gICAqIG9mIG51bGwgaW5kaWNhdGVzIHRoYXQgdGhlIGVsZW1lbnQgb3IgYW55IG9mIGl0J3MgZGVjZW5kYW50cyBpcyBoaWRkZW4gKGBkaXNwbGF5Om5vbmVgKS5cbiAgICpcbiAgICogT290aGVyIHRlY2huaXF1ZXMgdXNlIHRoZSB2aXNpYmlsaXR5IChgdmlzaWJpbGl0eTogaGlkZGVuYCksIG9wYWNpdHkgKGBvcGFjaXR5YCkgb3JcbiAgICogcGh5aXNpY2FsIGxvY2F0aW9uIG9uIHRoZSBlbGVtZW50IGl0c2VsZiBvciBhbnkgb2YgaXQncyBhbmNoZXN0b3IgZWxlbWVudHMuIFRob3NlXG4gICAqIHRlY2huaXF1ZSByZXF1aXJlIHRvIHdvcmsgd2l0aCB0aGUgX2NvbXB1dGVkIHN0eWxlc18sIHdoaWNoIHdpbGwgY2F1c2UgYSBwZXJmb3JtYW5jZVxuICAgKiBkb3duZ3JhZGUuIFdlIGRvbid0IGRvIHRoaXMgaW4gdGhlIHN0YW5kYXJkIGltcGxlbWVudGF0b24uXG4gICAqL1xuICBwcm90ZWN0ZWQgaXNIaWRkZW4oZWw6IEhUTUxFbGVtZW50KTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIGVsLm9mZnNldFBhcmVudCA9PT0gbnVsbDtcbiAgfVxufVxuIl19