UNPKG

@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
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; }