@workday/canvas-kit-react
Version:
The parent module that contains all Workday Canvas Kit React components
93 lines (92 loc) • 3.77 kB
JavaScript
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;
;