@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.
72 lines (71 loc) • 1.93 kB
JavaScript
'use client';
import * as React from 'react';
import { mergeReactProps } from '../../utils/mergeReactProps.js';
import { useAnchorPositioning } from '../../utils/useAnchorPositioning.js';
import { useMenuRootContext } from '../root/MenuRootContext.js';
export function useMenuPositioner(params) {
const {
keepMounted,
mounted,
menuEvents,
nodeId,
parentNodeId,
setOpen
} = params;
const {
open
} = useMenuRootContext();
const {
positionerStyles,
arrowStyles,
anchorHidden,
arrowRef,
arrowUncentered,
renderedSide,
renderedAlign,
positionerContext: floatingContext
} = useAnchorPositioning(params);
const getPositionerProps = React.useCallback((externalProps = {}) => {
const hiddenStyles = {};
if (keepMounted && !open) {
hiddenStyles.pointerEvents = 'none';
}
return mergeReactProps(externalProps, {
role: 'presentation',
hidden: !mounted,
style: {
...positionerStyles,
...hiddenStyles
}
});
}, [keepMounted, open, positionerStyles, mounted]);
React.useEffect(() => {
function onMenuOpened(event) {
if (event.nodeId !== nodeId && event.parentNodeId === parentNodeId) {
setOpen(false);
}
}
menuEvents.on('opened', onMenuOpened);
return () => {
menuEvents.off('opened', onMenuOpened);
};
}, [menuEvents, nodeId, parentNodeId, setOpen]);
React.useEffect(() => {
if (open) {
menuEvents.emit('opened', {
nodeId,
parentNodeId
});
}
}, [menuEvents, open, nodeId, parentNodeId]);
return React.useMemo(() => ({
getPositionerProps,
arrowRef,
arrowUncentered,
arrowStyles,
side: renderedSide,
align: renderedAlign,
floatingContext,
anchorHidden
}), [getPositionerProps, arrowRef, arrowUncentered, arrowStyles, renderedSide, renderedAlign, floatingContext, anchorHidden]);
}