@mantine/core
Version:
React components library focused on usability, accessibility and developer experience
110 lines (109 loc) • 4.19 kB
JavaScript
"use client";
import { useMantineEnv } from "../../core/MantineProvider/Mantine.context.mjs";
import { useEffect, useRef } 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, env) {
const middlewaresOptions = getDefaultMiddlewares(options.middlewares);
const middlewares = [offset(options.offset), hide()];
if (options.dropdownVisible && env !== "test" && options.preventPositionChangeWhenVisible) middlewaresOptions.flip = false;
if (middlewaresOptions.flip) middlewares.push(typeof middlewaresOptions.flip === "boolean" ? flip() : flip(middlewaresOptions.flip));
if (middlewaresOptions.shift) middlewares.push(shift(typeof middlewaresOptions.shift === "boolean" ? {
limiter: limitShift(),
padding: 5
} : {
limiter: limitShift(),
padding: 5,
...middlewaresOptions.shift
}));
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 env = useMantineEnv();
const [_opened, setOpened] = useUncontrolled({
value: options.opened,
defaultValue: options.defaultOpened,
finalValue: false,
onChange: options.onChange
});
const previouslyOpened = useRef(_opened);
const onClose = () => {
if (_opened && !options.disabled) setOpened(false);
};
const onToggle = () => {
if (!options.disabled) setOpened(!_opened);
};
const floating = useFloating({
strategy: options.strategy,
placement: options.preventPositionChangeWhenVisible ? options.positionRef.current : options.position,
middleware: getPopoverMiddlewares(options, () => floating, env),
whileElementsMounted: !options.keepMounted ? autoUpdate : void 0
});
useEffect(() => {
if (!floating.refs.reference.current || !floating.refs.floating.current) return;
if (_opened) return autoUpdate(floating.refs.reference.current, floating.refs.floating.current, floating.update);
}, [_opened, floating.update]);
useDidUpdate(() => {
options.onPositionChange?.(floating.placement);
options.positionRef.current = floating.placement;
}, [floating.placement, options.preventPositionChangeWhenVisible]);
useDidUpdate(() => {
if (_opened !== previouslyOpened.current) if (!_opened) options.onClose?.();
else options.onOpen?.();
previouslyOpened.current = _opened;
}, [
_opened,
options.onClose,
options.onOpen
]);
useIsomorphicEffect(() => {
let timeout = -1;
if (_opened) timeout = window.setTimeout(() => options.setDropdownVisible(true), 4);
return () => {
window.clearTimeout(timeout);
};
}, [_opened, options.position]);
return {
floating,
controlled: typeof options.opened === "boolean",
opened: _opened,
onClose,
onToggle
};
}
//#endregion
export { usePopover };
//# sourceMappingURL=use-popover.mjs.map