@mantine/hooks
Version:
A collection of 50+ hooks for state and UI management
101 lines (100 loc) • 3.31 kB
JavaScript
"use client";
const require_use_did_update = require("../use-did-update/use-did-update.cjs");
const require_use_merged_ref = require("../use-merged-ref/use-merged-ref.cjs");
let react = require("react");
let react_dom = require("react-dom");
//#region packages/@mantine/hooks/src/use-collapse/use-collapse.ts
function getAutoHeightDuration(height) {
if (!height || typeof height === "string") return 0;
const constant = height / 36;
return Math.round((4 + 15 * constant ** .25 + constant / 5) * 10);
}
function getElementHeight(elementRef) {
return elementRef.current ? elementRef.current.scrollHeight : "auto";
}
function useCollapse({ transitionDuration, transitionTimingFunction = "ease", onTransitionEnd, onTransitionStart, expanded, keepMounted }) {
const collapsedStyles = {
height: 0,
overflow: "hidden",
...keepMounted ? {} : { display: "none" }
};
const onTransitionStartEvent = (0, react.useEffectEvent)(() => onTransitionStart?.());
const elementRef = (0, react.useRef)(null);
const [styles, setStylesRaw] = (0, react.useState)(expanded ? {} : collapsedStyles);
const [state, setState] = (0, react.useState)(expanded ? "entered" : "exited");
const setStyles = (newStyles) => {
(0, react_dom.flushSync)(() => setStylesRaw(newStyles));
};
const mergeStyles = (newStyles) => {
setStyles((oldStyles) => ({
...oldStyles,
...newStyles
}));
};
const getTransitionStyles = (height) => {
const duration = transitionDuration || getAutoHeightDuration(height);
return { transition: `height ${duration}ms ${transitionTimingFunction}, opacity ${duration}ms ${transitionTimingFunction}` };
};
require_use_did_update.useDidUpdate(() => {
if (transitionDuration !== 0) onTransitionStartEvent();
if (expanded) window.requestAnimationFrame(() => {
(0, react_dom.flushSync)(() => setState("entering"));
mergeStyles({
willChange: "height",
display: "block",
overflow: "hidden"
});
window.requestAnimationFrame(() => {
const height = getElementHeight(elementRef);
mergeStyles({
...getTransitionStyles(height),
height
});
});
});
else window.requestAnimationFrame(() => {
(0, react_dom.flushSync)(() => setState("exiting"));
const height = getElementHeight(elementRef);
mergeStyles({
...getTransitionStyles(height),
willChange: "height",
height
});
window.requestAnimationFrame(() => mergeStyles({
height: 0,
overflow: "hidden"
}));
});
}, [expanded]);
const handleTransitionEnd = (event) => {
if (event.target !== elementRef.current || event.propertyName !== "height") return;
if (expanded) {
const height = getElementHeight(elementRef);
if (height === styles.height) setStyles({});
else mergeStyles({ height });
setState("entered");
onTransitionEnd?.();
} else if (styles.height === 0) {
setStyles(collapsedStyles);
setState("exited");
onTransitionEnd?.();
}
};
return {
state,
getCollapseProps: (input) => ({
"aria-hidden": !expanded,
inert: !expanded,
ref: require_use_merged_ref.mergeRefs(elementRef, input?.ref),
onTransitionEnd: handleTransitionEnd,
style: {
boxSizing: "border-box",
...input?.style,
...styles
}
})
};
}
//#endregion
exports.useCollapse = useCollapse;
//# sourceMappingURL=use-collapse.cjs.map