UNPKG

@base-ui/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.

110 lines (108 loc) 4.24 kB
'use client'; import * as React from 'react'; import { useStore } from '@base-ui/utils/store'; import { useIsoLayoutEffect } from '@base-ui/utils/useIsoLayoutEffect'; import { useStableCallback } from '@base-ui/utils/useStableCallback'; import { inertValue } from '@base-ui/utils/inertValue'; import { useComboboxFloatingContext, useComboboxRootContext, useComboboxDerivedItemsContext } from "../root/ComboboxRootContext.js"; import { ComboboxPositionerContext } from "./ComboboxPositionerContext.js"; import { useAnchorPositioning } from "../../utils/useAnchorPositioning.js"; import { useComboboxPortalContext } from "../portal/ComboboxPortalContext.js"; import { DROPDOWN_COLLISION_AVOIDANCE } from "../../internals/constants.js"; import { selectors } from "../store.js"; import { InternalBackdrop } from "../../utils/InternalBackdrop.js"; import { usePositioner } from "../../utils/usePositioner.js"; import { useAnchoredPopupScrollLock } from "../../utils/useAnchoredPopupScrollLock.js"; /** * Positions the popup against the trigger. * Renders a `<div>` element. * * Documentation: [Base UI Combobox](https://base-ui.com/react/components/combobox) */ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; export const ComboboxPositioner = /*#__PURE__*/React.forwardRef(function ComboboxPositioner(componentProps, forwardedRef) { const { render, className, anchor, positionMethod = 'absolute', side = 'bottom', align = 'center', sideOffset = 0, alignOffset = 0, collisionBoundary = 'clipping-ancestors', collisionPadding = 5, arrowPadding = 5, sticky = false, disableAnchorTracking = false, collisionAvoidance = DROPDOWN_COLLISION_AVOIDANCE, style: styleProp, ...elementProps } = componentProps; const store = useComboboxRootContext(); const { filteredItems } = useComboboxDerivedItemsContext(); const floatingRootContext = useComboboxFloatingContext(); const keepMounted = useComboboxPortalContext(); const modal = useStore(store, selectors.modal); const open = useStore(store, selectors.open); const mounted = useStore(store, selectors.mounted); const openMethod = useStore(store, selectors.openMethod); const positionerElement = useStore(store, selectors.positionerElement); const triggerElement = useStore(store, selectors.triggerElement); const inputElement = useStore(store, selectors.inputElement); const inputGroupElement = useStore(store, selectors.inputGroupElement); const inputInsidePopup = useStore(store, selectors.inputInsidePopup); const transitionStatus = useStore(store, selectors.transitionStatus); const empty = filteredItems.length === 0; const resolvedAnchor = anchor ?? (inputInsidePopup ? triggerElement : inputGroupElement ?? inputElement); const positioning = useAnchorPositioning({ anchor: resolvedAnchor, floatingRootContext, positionMethod, mounted, side, sideOffset, align, alignOffset, arrowPadding, collisionBoundary, collisionPadding, sticky, disableAnchorTracking, keepMounted, collisionAvoidance, lazyFlip: true }); useAnchoredPopupScrollLock(open && modal, openMethod === 'touch', positionerElement, triggerElement); const state = { open, side: positioning.side, align: positioning.align, anchorHidden: positioning.anchorHidden, empty }; useIsoLayoutEffect(() => { store.set('popupSide', positioning.side); }, [store, positioning.side]); const setPositionerElement = useStableCallback(element => { store.set('positionerElement', element); }); const element = usePositioner(componentProps, state, { styles: positioning.positionerStyles, transitionStatus, props: elementProps, refs: [forwardedRef, setPositionerElement], hidden: !mounted, inert: !open }); return /*#__PURE__*/_jsxs(ComboboxPositionerContext.Provider, { value: positioning, children: [mounted && modal && /*#__PURE__*/_jsx(InternalBackdrop, { inert: inertValue(!open), cutout: inputGroupElement ?? inputElement ?? triggerElement }), element] }); }); if (process.env.NODE_ENV !== "production") ComboboxPositioner.displayName = "ComboboxPositioner";