UNPKG

@workday/canvas-kit-react

Version:

The parent module that contains all Workday Canvas Kit React components

93 lines (92 loc) 3.77 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getLastFocusableElement = exports.getFirstFocusableElement = exports.isFocusable = exports.isKeyboardFocusable = exports.isMouseFocusable = void 0; const isBaseFocusable = (element) => { if (element.hasAttribute('disabled')) { return false; } const nodeName = element.nodeName.toLowerCase(); const validInput = nodeName === 'input' && element.getAttribute('type') !== 'hidden'; const validAnchor = nodeName === 'a' && element.hasAttribute('href'); const validAudioVideo = ['audio', 'video'].includes(nodeName) && element.hasAttribute('controls'); const validImgObject = ['img', 'object'].includes(nodeName) && element.hasAttribute('usemap'); const validNativelyFocusable = [ 'button', 'details', 'embed', 'iframe', 'select', 'textarea', ].includes(nodeName); const hasTabIndex = element.getAttribute('tabindex') === '0'; return (validInput || validAnchor || validAudioVideo || validImgObject || validNativelyFocusable || hasTabIndex); }; /** * Is an element focusable? This function performs various tests to see if the element in question * can receive focus via a pointer. Should skip disabled elements as they are not focusable. */ exports.isMouseFocusable = isBaseFocusable; /** * Is an element focusable? This function performs various tests to see if the element in question * can receive focus via the keyboard. Should skip disabled elements as they are not focusable. */ const isKeyboardFocusable = (element) => { return isBaseFocusable(element) && element.getAttribute('tabindex') !== '-1'; }; exports.isKeyboardFocusable = isKeyboardFocusable; /** * @deprecated Use `isMouseFocusable` for mouse events and `isKeyboardFocusable` for keyboard * events. `isFocusable` is an alias to `isKeyboardFocusable` */ exports.isFocusable = exports.isKeyboardFocusable; /** * Get the first focusable element in a container. * * Returns an array of elements if the first focusable element is a radio group */ const getFirstFocusableElement = (container) => { const elements = container.querySelectorAll('*'); for (let i = 0; i < elements.length; i++) { const element = elements.item(i); if (element && (0, exports.isKeyboardFocusable)(element)) { if (isRadioInput(element)) { const radioGroup = getRadioGroup(container, element); return radioGroup.length > 1 ? Array.from(radioGroup) : element; } return element; } } return null; }; exports.getFirstFocusableElement = getFirstFocusableElement; const isRadioInput = (element) => { return element.nodeName.toLowerCase() === 'input' && element.getAttribute('type') === 'radio'; }; const getRadioGroup = (container, element) => { return container.querySelectorAll(`input[type="radio"][name="${element.getAttribute('name')}"]`); }; /** * Get the last focusable element in a container. * * Returns an array of elements if the last focusable element is a radio group */ const getLastFocusableElement = (container) => { const elements = container.querySelectorAll('*'); for (let i = elements.length - 1; i >= 0; i--) { const element = elements.item(i); if (element && (0, exports.isKeyboardFocusable)(element)) { if (isRadioInput(element)) { const radioGroup = getRadioGroup(container, element); return radioGroup.length > 1 ? Array.from(radioGroup) : element; } return element; } } return null; }; exports.getLastFocusableElement = getLastFocusableElement;