@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.
118 lines (117 loc) • 4.26 kB
JavaScript
;
'use client';
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.useCollapsibleRoot = useCollapsibleRoot;
var React = _interopRequireWildcard(require("react"));
var _useControlled = require("@base-ui-components/utils/useControlled");
var _useIsoLayoutEffect = require("@base-ui-components/utils/useIsoLayoutEffect");
var _useStableCallback = require("@base-ui-components/utils/useStableCallback");
var _useBaseUiId = require("../../utils/useBaseUiId");
var _createBaseUIEventDetails = require("../../utils/createBaseUIEventDetails");
var _reasons = require("../../utils/reasons");
var _useAnimationsFinished = require("../../utils/useAnimationsFinished");
var _useTransitionStatus = require("../../utils/useTransitionStatus");
function useCollapsibleRoot(parameters) {
const {
open: openParam,
defaultOpen,
onOpenChange,
disabled
} = parameters;
const isControlled = openParam !== undefined;
const [open, setOpen] = (0, _useControlled.useControlled)({
controlled: openParam,
default: defaultOpen,
name: 'Collapsible',
state: 'open'
});
const {
mounted,
setMounted,
transitionStatus
} = (0, _useTransitionStatus.useTransitionStatus)(open, true, true);
const [visible, setVisible] = React.useState(open);
const [{
height,
width
}, setDimensions] = React.useState({
height: undefined,
width: undefined
});
const defaultPanelId = (0, _useBaseUiId.useBaseUiId)();
const [panelIdState, setPanelIdState] = React.useState();
const panelId = panelIdState ?? defaultPanelId;
const [hiddenUntilFound, setHiddenUntilFound] = React.useState(false);
const [keepMounted, setKeepMounted] = React.useState(false);
const abortControllerRef = React.useRef(null);
const animationTypeRef = React.useRef(null);
const transitionDimensionRef = React.useRef(null);
const panelRef = React.useRef(null);
const runOnceAnimationsFinish = (0, _useAnimationsFinished.useAnimationsFinished)(panelRef, false);
const handleTrigger = (0, _useStableCallback.useStableCallback)(event => {
const nextOpen = !open;
const eventDetails = (0, _createBaseUIEventDetails.createChangeEventDetails)(_reasons.REASONS.triggerPress, event.nativeEvent);
onOpenChange(nextOpen, eventDetails);
if (eventDetails.isCanceled) {
return;
}
const panel = panelRef.current;
if (animationTypeRef.current === 'css-animation' && panel != null) {
panel.style.removeProperty('animation-name');
}
if (!hiddenUntilFound && !keepMounted) {
if (animationTypeRef.current != null && animationTypeRef.current !== 'css-animation') {
if (!mounted && nextOpen) {
setMounted(true);
}
}
if (animationTypeRef.current === 'css-animation') {
if (!visible && nextOpen) {
setVisible(true);
}
if (!mounted && nextOpen) {
setMounted(true);
}
}
}
setOpen(nextOpen);
if (animationTypeRef.current === 'none' && mounted && !nextOpen) {
setMounted(false);
}
});
(0, _useIsoLayoutEffect.useIsoLayoutEffect)(() => {
/**
* Unmount immediately when closing in controlled mode and keepMounted={false}
* and no CSS animations or transitions are applied
*/
if (isControlled && animationTypeRef.current === 'none' && !keepMounted && !open) {
setMounted(false);
}
}, [isControlled, keepMounted, open, openParam, setMounted]);
return React.useMemo(() => ({
abortControllerRef,
animationTypeRef,
disabled,
handleTrigger,
height,
mounted,
open,
panelId,
panelRef,
runOnceAnimationsFinish,
setDimensions,
setHiddenUntilFound,
setKeepMounted,
setMounted,
setOpen,
setPanelIdState,
setVisible,
transitionDimensionRef,
transitionStatus,
visible,
width
}), [abortControllerRef, animationTypeRef, disabled, handleTrigger, height, mounted, open, panelId, panelRef, runOnceAnimationsFinish, setDimensions, setHiddenUntilFound, setKeepMounted, setMounted, setOpen, setVisible, transitionDimensionRef, transitionStatus, visible, width]);
}