UNPKG

@mantine/core

Version:

React components library focused on usability, accessibility and developer experience

155 lines (154 loc) 5.53 kB
"use client"; import { useCallback, useEffect, useRef, useState } from "react"; import { useDidUpdate, useIsomorphicEffect, useUncontrolled } from "@mantine/hooks"; import { arrow, autoUpdate, flip, hide, inline, limitShift, offset, shift, size, useFloating } from "@floating-ui/react"; //#region packages/@mantine/core/src/components/Popover/use-popover.ts function getDefaultMiddlewares(middlewares) { if (middlewares === void 0) return { shift: true, flip: true }; const result = { ...middlewares }; if (middlewares.shift === void 0) result.shift = true; if (middlewares.flip === void 0) result.flip = true; return result; } function getPopoverMiddlewares(options, getFloating, disableFlip, lockEnabled) { const middlewaresOptions = getDefaultMiddlewares(options.middlewares); const middlewares = [offset(options.offset), hide()]; if (middlewaresOptions.flip && !disableFlip) { const userFlip = typeof middlewaresOptions.flip === "boolean" ? {} : middlewaresOptions.flip; const flipOptions = lockEnabled ? { fallbackStrategy: "initialPlacement", ...userFlip } : userFlip; middlewares.push(flip(flipOptions)); } if (middlewaresOptions.shift) { const shiftOptions = typeof middlewaresOptions.shift === "boolean" ? {} : middlewaresOptions.shift; middlewares.push(shift((state) => { const isVerticalPlacement = state.placement.startsWith("top") || state.placement.startsWith("bottom"); return { limiter: limitShift(), padding: 5, ...options.width === "target" && isVerticalPlacement ? { mainAxis: false } : null, ...shiftOptions }; })); } if (middlewaresOptions.inline) middlewares.push(typeof middlewaresOptions.inline === "boolean" ? inline() : inline(middlewaresOptions.inline)); middlewares.push(arrow({ element: options.arrowRef, padding: options.arrowOffset })); if (middlewaresOptions.size || options.width === "target") middlewares.push(size({ ...typeof middlewaresOptions.size === "boolean" ? {} : middlewaresOptions.size, apply({ rects, availableWidth, availableHeight, ...rest }) { const styles = getFloating().refs.floating.current?.style ?? {}; if (middlewaresOptions.size) if (typeof middlewaresOptions.size === "object" && !!middlewaresOptions.size.apply) middlewaresOptions.size.apply({ rects, availableWidth, availableHeight, ...rest }); else Object.assign(styles, { maxWidth: `${availableWidth}px`, maxHeight: `${availableHeight}px` }); if (options.width === "target") Object.assign(styles, { width: `${rects.reference.width}px` }); } })); return middlewares; } function usePopover(options) { const [_opened, setOpened] = useUncontrolled({ value: options.opened, defaultValue: options.defaultOpened, finalValue: false, onChange: options.onChange }); const previouslyOpened = useRef(_opened); const [lockedPlacement, setLockedPlacement] = useState(null); const lockEnabled = options.preventPositionChangeWhenVisible !== false; const wasOpenedRef = useRef(_opened); if (_opened !== wasOpenedRef.current) { wasOpenedRef.current = _opened; if (_opened && lockedPlacement !== null) setLockedPlacement(null); } const resetLockedPlacement = useCallback(() => setLockedPlacement(null), []); const onClose = () => { if (_opened && !options.disabled) setOpened(false); }; const onToggle = () => { if (!options.disabled) setOpened(!_opened); }; const floating = useFloating({ open: _opened, strategy: options.strategy, placement: lockEnabled ? lockedPlacement ?? options.position : options.position, middleware: getPopoverMiddlewares(options, () => floating, lockEnabled && lockedPlacement !== null, lockEnabled), whileElementsMounted: !options.keepMounted ? autoUpdate : void 0 }); useEffect(() => { if (!options.keepMounted) return; const referenceElement = floating.refs.reference.current; const floatingElement = floating.refs.floating.current; if (_opened && referenceElement && floatingElement) return autoUpdate(referenceElement, floatingElement, floating.update); }, [ options.keepMounted, _opened, floating.update, floating.elements.reference, floating.elements.floating ]); const measuredAfterShowRef = useRef(false); useIsomorphicEffect(() => { if (!_opened) { measuredAfterShowRef.current = false; return; } if (!lockEnabled || lockedPlacement !== null) return; const flEl = floating.refs.floating.current; if (!flEl || flEl.offsetHeight === 0 || flEl.offsetWidth === 0) return; if (!measuredAfterShowRef.current) { measuredAfterShowRef.current = true; floating.update(); return; } if (floating.isPositioned) setLockedPlacement(floating.placement); }, [ lockEnabled, _opened, floating.isPositioned, floating.placement, lockedPlacement, floating.update ]); const previousPlacementRef = useRef(floating.placement); useIsomorphicEffect(() => { if (previousPlacementRef.current !== floating.placement) { previousPlacementRef.current = floating.placement; options.onPositionChange?.(floating.placement); } }, [floating.placement]); useDidUpdate(() => { if (_opened !== previouslyOpened.current) if (!_opened) options.onClose?.(); else options.onOpen?.(); previouslyOpened.current = _opened; }, [ _opened, options.onClose, options.onOpen ]); return { floating, controlled: typeof options.opened === "boolean", opened: _opened, onClose, onToggle, resetLockedPlacement }; } //#endregion export { usePopover }; //# sourceMappingURL=use-popover.mjs.map