@coreui/react-pro
Version:
UI Components Library for React.js
134 lines (130 loc) • 4.9 kB
JavaScript
;
var React = require('react');
/**
* Gets all focusable child elements within a container.
* Uses a comprehensive selector to find elements that can receive focus.
* @param element - The container element to search within
* @returns Array of focusable HTML elements
*/
const focusableChildren = (element) => {
const focusableSelectors = [
'a[href]',
'button:not([disabled])',
'input:not([disabled])',
'textarea:not([disabled])',
'select:not([disabled])',
'details',
'[tabindex]:not([tabindex="-1"])',
'[contenteditable="true"]',
].join(',');
const elements = [...element.querySelectorAll(focusableSelectors)];
return elements.filter((el) => !isDisabled(el) && isVisible(el));
};
/**
* Extracts the ref from a React element, handling version differences between React 18 and 19+.
*
* In React 18 and earlier, refs are stored directly on the element object.
* In React 19+, refs are stored in the element's props object due to changes in React's internals.
* This function automatically detects the React version and uses the appropriate access pattern.
* @param child - The React element to extract the ref from
* @returns The ref attached to the element, or undefined if no ref is present
*/
const getChildRef = (child) => {
var _a, _b, _c;
const major = Number((_c = (_b = (_a = React.version) === null || _a === void 0 ? void 0 : _a.split) === null || _b === void 0 ? void 0 : _b.call(_a, '.')[0]) !== null && _c !== void 0 ? _c : 18);
// React 18 stores ref directly on the element
if (major <= 18 && 'ref' in child && child.ref !== undefined) {
return child.ref;
}
// React 19 stores ref in props
if (child.props && typeof child.props === 'object' && 'ref' in child.props) {
return child.props.ref;
}
return undefined;
};
/**
* Checks if an element is disabled.
* Considers various ways an element can be disabled including CSS classes and attributes.
* @param element - The HTML element to check
* @returns True if the element is disabled, false otherwise
*/
const isDisabled = (element) => {
if (!element || element.nodeType !== Node.ELEMENT_NODE) {
return true;
}
if (element.classList.contains('disabled')) {
return true;
}
if ('disabled' in element && typeof element.disabled === 'boolean') {
return element.disabled;
}
return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false';
};
/**
* Type guard to check if an object is an Element.
* Handles edge cases including jQuery objects.
* @param object - The object to check
* @returns True if the object is an Element, false otherwise
*/
const isElement = (object) => {
if (!object || typeof object !== 'object') {
return false;
}
return 'nodeType' in object && typeof object.nodeType === 'number';
};
/**
* Checks if an element is visible in the DOM.
* Considers client rects and computed visibility styles, handling edge cases like details elements.
* @param element - The HTML element to check for visibility
* @returns True if the element is visible, false otherwise
*/
const isVisible = (element) => {
if (!isElement(element) || element.getClientRects().length === 0) {
return false;
}
const elementIsVisible = getComputedStyle(element).getPropertyValue('visibility') === 'visible';
// Handle `details` element as its content may falsely appear visible when it is closed
const closedDetails = element.closest('details:not([open])');
if (!closedDetails) {
return elementIsVisible;
}
if (closedDetails !== element) {
const summary = element.closest('summary');
// Check if summary is a direct child of the closed details
if ((summary === null || summary === void 0 ? void 0 : summary.parentNode) !== closedDetails) {
return false;
}
}
return elementIsVisible;
};
/**
* Merges multiple React refs into a single ref callback.
* Handles both function refs and ref objects, gracefully ignoring failures.
* @param refs - Array of React refs to merge
* @returns A ref callback that applies to all provided refs
*/
const mergeRefs = (...refs) => (node) => {
refs.forEach((ref) => {
if (!ref)
return;
if (typeof ref === 'function') {
ref(node);
}
else {
try {
;
ref.current = node;
}
catch (_a) {
// Ignore assignment failures for read-only refs
}
}
});
};
exports.focusableChildren = focusableChildren;
exports.getChildRef = getChildRef;
exports.isDisabled = isDisabled;
exports.isElement = isElement;
exports.isVisible = isVisible;
exports.mergeRefs = mergeRefs;
//# sourceMappingURL=utils.js.map