@base-ui-components/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.
109 lines (105 loc) • 3.73 kB
JavaScript
;
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.FloatingNode = FloatingNode;
exports.FloatingTree = FloatingTree;
exports.useFloatingNodeId = useFloatingNodeId;
exports.useFloatingTree = exports.useFloatingParentNodeId = void 0;
var React = _interopRequireWildcard(require("react"));
var _useId = require("@base-ui-components/utils/useId");
var _useIsoLayoutEffect = require("@base-ui-components/utils/useIsoLayoutEffect");
var _createEventEmitter = require("../utils/createEventEmitter");
var _jsxRuntime = require("react/jsx-runtime");
const FloatingNodeContext = /*#__PURE__*/React.createContext(null);
if (process.env.NODE_ENV !== "production") FloatingNodeContext.displayName = "FloatingNodeContext";
const FloatingTreeContext = /*#__PURE__*/React.createContext(null);
/**
* Returns the parent node id for nested floating elements, if available.
* Returns `null` for top-level floating elements.
*/
if (process.env.NODE_ENV !== "production") FloatingTreeContext.displayName = "FloatingTreeContext";
const useFloatingParentNodeId = () => React.useContext(FloatingNodeContext)?.id || null;
/**
* Returns the nearest floating tree context, if available.
*/
exports.useFloatingParentNodeId = useFloatingParentNodeId;
const useFloatingTree = () => React.useContext(FloatingTreeContext);
/**
* Registers a node into the `FloatingTree`, returning its id.
* @see https://floating-ui.com/docs/FloatingTree
*/
exports.useFloatingTree = useFloatingTree;
function useFloatingNodeId(customParentId) {
const id = (0, _useId.useId)();
const tree = useFloatingTree();
const reactParentId = useFloatingParentNodeId();
const parentId = customParentId || reactParentId;
(0, _useIsoLayoutEffect.useIsoLayoutEffect)(() => {
if (!id) {
return undefined;
}
const node = {
id,
parentId
};
tree?.addNode(node);
return () => {
tree?.removeNode(node);
};
}, [tree, id, parentId]);
return id;
}
/**
* Provides parent node context for nested floating elements.
* @see https://floating-ui.com/docs/FloatingTree
* @internal
*/
function FloatingNode(props) {
const {
children,
id
} = props;
const parentId = useFloatingParentNodeId();
return /*#__PURE__*/(0, _jsxRuntime.jsx)(FloatingNodeContext.Provider, {
value: React.useMemo(() => ({
id,
parentId
}), [id, parentId]),
children: children
});
}
/**
* Provides context for nested floating elements when they are not children of
* each other on the DOM.
* This is not necessary in all cases, except when there must be explicit communication between parent and child floating elements. It is necessary for:
* - The `bubbles` option in the `useDismiss()` Hook
* - Nested virtual list navigation
* - Nested floating elements that each open on hover
* - Custom communication between parent and child floating elements
* @see https://floating-ui.com/docs/FloatingTree
* @internal
*/
function FloatingTree(props) {
const {
children
} = props;
const nodesRef = React.useRef([]);
const addNode = React.useCallback(node => {
nodesRef.current = [...nodesRef.current, node];
}, []);
const removeNode = React.useCallback(node => {
nodesRef.current = nodesRef.current.filter(n => n !== node);
}, []);
const [events] = React.useState(() => (0, _createEventEmitter.createEventEmitter)());
return /*#__PURE__*/(0, _jsxRuntime.jsx)(FloatingTreeContext.Provider, {
value: React.useMemo(() => ({
nodesRef,
addNode,
removeNode,
events
}), [addNode, removeNode, events]),
children: children
});
}