@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) • 1.89 kB
JavaScript
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 { isElement } from '@floating-ui/utils/dom';
import { useFloatingParentNodeId } from "../components/FloatingTree.js";
import { FloatingRootStore } from "../components/FloatingRootStore.js";
/**
* Initializes a FloatingRootStore that is kept in sync with the provided PopupStore.
* The new instance is created only once and updated on every render.
*/
export function useSyncedFloatingRootContext(options) {
const {
popupStore,
noEmit = false,
treatPopupAsFloatingElement = false,
onOpenChange
} = options;
const floatingId = useId();
const nested = useFloatingParentNodeId() != null;
const open = popupStore.useState('open');
const referenceElement = popupStore.useState('activeTriggerElement');
const floatingElement = popupStore.useState(treatPopupAsFloatingElement ? 'popupElement' : 'positionerElement');
const triggerElements = popupStore.context.triggerElements;
const store = useRefWithInit(() => new FloatingRootStore({
open,
referenceElement,
floatingElement,
triggerElements,
onOpenChange,
floatingId,
nested,
noEmit
})).current;
useIsoLayoutEffect(() => {
const valuesToSync = {
open,
floatingId,
referenceElement,
floatingElement
};
if (isElement(referenceElement)) {
valuesToSync.domReferenceElement = referenceElement;
}
store.update(valuesToSync);
}, [open, floatingId, referenceElement, floatingElement, store]);
// TODO: When `setOpen` is a part of the PopupStore API, we don't need to sync it.
store.context.onOpenChange = onOpenChange;
store.context.nested = nested;
store.context.noEmit = noEmit;
return store;
}