@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.
89 lines (86 loc) • 2.94 kB
JavaScript
import * as React from 'react';
import { useId } from '@base-ui-components/utils/useId';
import { useIsoLayoutEffect } from '@base-ui-components/utils/useIsoLayoutEffect';
import { useRefWithInit } from '@base-ui-components/utils/useRefWithInit';
import { FloatingTreeStore } from "./FloatingTreeStore.js";
import { jsx as _jsx } from "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";
export const useFloatingParentNodeId = () => React.useContext(FloatingNodeContext)?.id || null;
/**
* Returns the nearest floating tree context, if available.
*/
export const useFloatingTree = externalTree => {
const contextTree = React.useContext(FloatingTreeContext);
return externalTree ?? contextTree;
};
/**
* Registers a node into the `FloatingTree`, returning its id.
* @see https://floating-ui.com/docs/FloatingTree
*/
export function useFloatingNodeId(externalTree) {
const id = useId();
const tree = useFloatingTree(externalTree);
const parentId = useFloatingParentNodeId();
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
*/
export function FloatingNode(props) {
const {
children,
id
} = props;
const parentId = useFloatingParentNodeId();
return /*#__PURE__*/_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
*/
export function FloatingTree(props) {
const {
children,
externalTree
} = props;
const tree = useRefWithInit(() => externalTree ?? new FloatingTreeStore()).current;
return /*#__PURE__*/_jsx(FloatingTreeContext.Provider, {
value: tree,
children: children
});
}