@base-ui/react
Version:
Base UI is a library of headless ('unstyled') React components and low-level hooks. You gain complete control over your app's CSS and accessibility features.
99 lines (97 loc) • 3.41 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "activeElement", {
enumerable: true,
get: function () {
return _shadowDom.activeElement;
}
});
Object.defineProperty(exports, "contains", {
enumerable: true,
get: function () {
return _shadowDom.contains;
}
});
exports.getFloatingFocusElement = getFloatingFocusElement;
Object.defineProperty(exports, "getTarget", {
enumerable: true,
get: function () {
return _shadowDom.getTarget;
}
});
exports.isEventTargetWithin = isEventTargetWithin;
exports.isInteractiveElement = isInteractiveElement;
exports.isRootElement = isRootElement;
exports.isTargetInsideEnabledTrigger = isTargetInsideEnabledTrigger;
exports.isTypeableCombobox = isTypeableCombobox;
exports.isTypeableElement = isTypeableElement;
exports.matchesFocusVisible = matchesFocusVisible;
var _dom = require("@floating-ui/utils/dom");
var _detectBrowser = require("@base-ui/utils/detectBrowser");
var _constants = require("./constants");
var _shadowDom = require("../../internals/shadowDom");
function isTargetInsideEnabledTrigger(target, triggerElements) {
if (!(0, _dom.isElement)(target)) {
return false;
}
const targetElement = target;
if (triggerElements.hasElement(targetElement)) {
return !targetElement.hasAttribute('data-trigger-disabled');
}
for (const [, trigger] of triggerElements.entries()) {
if ((0, _shadowDom.contains)(trigger, targetElement)) {
return !trigger.hasAttribute('data-trigger-disabled');
}
}
return false;
}
function isEventTargetWithin(event, node) {
if (node == null) {
return false;
}
if ('composedPath' in event) {
return event.composedPath().includes(node);
}
// TS thinks `event` is of type never as it assumes all browsers support composedPath, but browsers without shadow dom don't
const eventAgain = event;
return eventAgain.target != null && node.contains(eventAgain.target);
}
function isRootElement(element) {
return element.matches('html,body');
}
function isTypeableElement(element) {
return (0, _dom.isHTMLElement)(element) && element.matches(_constants.TYPEABLE_SELECTOR);
}
function isInteractiveElement(element) {
return element?.closest(`button,a[href],[role="button"],select,[tabindex]:not([tabindex="-1"]),${_constants.TYPEABLE_SELECTOR}`) != null;
}
function isTypeableCombobox(element) {
if (!element) {
return false;
}
return element.getAttribute('role') === 'combobox' && isTypeableElement(element);
}
function matchesFocusVisible(element) {
// We don't want to block focus from working with `visibleOnly`
// (JSDOM doesn't match `:focus-visible` when the element has `:focus`)
if (!element || _detectBrowser.isJSDOM) {
return true;
}
try {
return element.matches(':focus-visible');
} catch (_e) {
return true;
}
}
function getFloatingFocusElement(floatingElement) {
if (!floatingElement) {
return null;
}
// Try to find the element that has `{...getFloatingProps()}` spread on it.
// This indicates the floating element is acting as a positioning wrapper, and
// so focus should be managed on the child element with the event handlers and
// aria props.
return floatingElement.hasAttribute(_constants.FOCUSABLE_ATTRIBUTE) ? floatingElement : floatingElement.querySelector(`[${_constants.FOCUSABLE_ATTRIBUTE}]`) || floatingElement;
}