@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.
52 lines (51 loc) • 2.1 kB
JavaScript
import { isElement } from '@floating-ui/utils/dom';
import { useId } from '@base-ui-components/utils/useId';
import { useRefWithInit } from '@base-ui-components/utils/useRefWithInit';
import { useIsoLayoutEffect } from '@base-ui-components/utils/useIsoLayoutEffect';
import { useFloatingParentNodeId } from "../components/FloatingTree.js";
import { FloatingRootStore } from "../components/FloatingRootStore.js";
import { PopupTriggerMap } from "../../utils/popups/index.js";
export function useFloatingRootContext(options) {
const {
open = false,
onOpenChange,
elements = {}
} = options;
const floatingId = useId();
const nested = useFloatingParentNodeId() != null;
if (process.env.NODE_ENV !== 'production') {
const optionDomReference = elements.reference;
if (optionDomReference && !isElement(optionDomReference)) {
console.error('Cannot pass a virtual element to the `elements.reference` option,', 'as it must be a real DOM element. Use `context.setPositionReference()`', 'instead.');
}
}
const store = useRefWithInit(() => new FloatingRootStore({
open,
onOpenChange,
referenceElement: elements.reference ?? null,
floatingElement: elements.floating ?? null,
triggerElements: elements.triggers ?? new PopupTriggerMap(),
floatingId,
nested,
noEmit: options.noEmit || false
})).current;
useIsoLayoutEffect(() => {
const valuesToSync = {
open,
floatingId
};
// Only sync elements that are defined to avoid overwriting existing ones
if (elements.reference !== undefined) {
valuesToSync.referenceElement = elements.reference;
valuesToSync.domReferenceElement = isElement(elements.reference) ? elements.reference : null;
}
if (elements.floating !== undefined) {
valuesToSync.floatingElement = elements.floating;
}
store.update(valuesToSync);
}, [open, floatingId, elements.reference, elements.floating, store]);
store.context.onOpenChange = onOpenChange;
store.context.nested = nested;
store.context.noEmit = options.noEmit || false;
return store;
}