UNPKG

@dialpad/dialtone

Version:

Dialpad's Dialtone design system monorepo

106 lines (105 loc) 4.26 kB
"use strict"; Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } }); const focusableAttrs = ':not(:disabled):not([aria-disabled="true"]):not([role="presentation"])'; const tabbableAttrs = `${focusableAttrs}:not([tabindex="-1"])`; const focusableElementsList = `button,[href],input,select,textarea,details,[tabindex]`; const Modal = { methods: { /** * get the first focusable element in your component, includes tabindex="-1". * @param {object} el - optional - ref of dom element to trap focus on. * will default to the root node of the vue component */ async getFirstFocusableElement(el) { await this.$nextTick(); const focusableElements = this._getFocusableElements(el, true); return this._getFirstFocusElement(focusableElements); }, /** * set focus to the first focusable element in your component, includes tabindex="-1". * @param {object} el - optional - ref of dom element to trap focus on. * will default to the root node of the vue component */ async focusFirstElement(el = this.$el) { const elToFocus = await this.getFirstFocusableElement(el); elToFocus == null ? void 0 : elToFocus.focus({ preventScroll: true }); }, async focusElementById(elementId) { var _a; await this.$nextTick(); const result = (_a = this.$el) == null ? void 0 : _a.querySelector(elementId); if (result) { result.focus(); return; } console.warn('Could not find the element specified in dt-modal prop "initialFocusElement". Defaulting to focusing the first element.'); await this.focusFirstElement(); }, /** * internal use only. * * @param focusableElements - list of focusable elements * @returns {*} - first DOM element that is focusable. * @private */ _getFirstFocusElement(focusableElements) { if (!focusableElements.length) { return; } let firstFocusEl = focusableElements[0]; if (firstFocusEl.matches('[type="radio"]:not(:checked)')) { firstFocusEl = focusableElements.find((el) => el.checked && el.name === firstFocusEl.name) || firstFocusEl; } return firstFocusEl; }, /** * internal use only. * * gets all the focusable elements within the component * and sets the first and last of those elements. * * @param {object} el - the root dom element to find focusable elements in. * @param {bool} includeNegativeTabIndex - will include tabindex="-1" in the list of focusable elements. */ _getFocusableElements(el = this.$el, includeNegativeTabIndex = false) { if (!el) return []; const focusableContent = [...el.querySelectorAll(focusableElementsList)]; return focusableContent.filter((fc) => { const style = window.getComputedStyle(fc); return style.getPropertyValue("display") !== "none" && style.getPropertyValue("visibility") !== "hidden" && fc.matches(includeNegativeTabIndex ? focusableAttrs : tabbableAttrs); }); }, /** * tabs to the next element contained within your component, does not include tabindex="-1". * @param {object} e - keypress event * @param {object} el - optional - ref of dom element to trap focus on. * will default to the root node of the vue component */ focusTrappedTabPress(e, el) { const isTabPressed = e.key === "Tab"; if (!isTabPressed) { return; } const focusableElements = this._getFocusableElements(el); if (!focusableElements.length) { e.preventDefault(); return; } const firstFocusableElement = this._getFirstFocusElement(focusableElements); const lastFocusableElement = focusableElements[focusableElements.length - 1]; if (e.shiftKey) { if (document.activeElement === firstFocusableElement) { lastFocusableElement.focus(); e.preventDefault(); } } else { if (document.activeElement === lastFocusableElement) { firstFocusableElement.focus(); e.preventDefault(); } } } } }; exports.default = Modal; //# sourceMappingURL=modal.cjs.map