@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.
147 lines (146 loc) • 5.38 kB
JavaScript
;
'use client';
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.PreviewCardRoot = PreviewCardRoot;
var React = _interopRequireWildcard(require("react"));
var ReactDOM = _interopRequireWildcard(require("react-dom"));
var _useControlled = require("@base-ui-components/utils/useControlled");
var _useStableCallback = require("@base-ui-components/utils/useStableCallback");
var _floatingUiReact = require("../../floating-ui-react");
var _PreviewCardContext = require("./PreviewCardContext");
var _constants = require("../utils/constants");
var _reasons = require("../../utils/reasons");
var _useFocusWithDelay = require("../../utils/interactions/useFocusWithDelay");
var _useOpenChangeComplete = require("../../utils/useOpenChangeComplete");
var _useTransitionStatus = require("../../utils/useTransitionStatus");
var _jsxRuntime = require("react/jsx-runtime");
/**
* Groups all parts of the preview card.
* Doesn’t render its own HTML element.
*
* Documentation: [Base UI Preview Card](https://base-ui.com/react/components/preview-card)
*/
function PreviewCardRoot(props) {
const {
open: externalOpen,
defaultOpen,
onOpenChange: onOpenChangeProp,
onOpenChangeComplete,
actionsRef
} = props;
const delayRef = React.useRef(_constants.OPEN_DELAY);
const closeDelayRef = React.useRef(_constants.CLOSE_DELAY);
const writeDelayRefs = (0, _useStableCallback.useStableCallback)(config => {
delayRef.current = config.delay ?? _constants.OPEN_DELAY;
closeDelayRef.current = config.closeDelay ?? _constants.CLOSE_DELAY;
});
const [triggerElement, setTriggerElement] = React.useState(null);
const [positionerElement, setPositionerElement] = React.useState(null);
const [instantTypeState, setInstantTypeState] = React.useState();
const popupRef = React.useRef(null);
const [open, setOpenUnwrapped] = (0, _useControlled.useControlled)({
controlled: externalOpen,
default: defaultOpen,
name: 'PreviewCard',
state: 'open'
});
const onOpenChange = (0, _useStableCallback.useStableCallback)(onOpenChangeProp);
const {
mounted,
setMounted,
transitionStatus
} = (0, _useTransitionStatus.useTransitionStatus)(open);
const handleUnmount = (0, _useStableCallback.useStableCallback)(() => {
setMounted(false);
onOpenChangeComplete?.(false);
});
(0, _useOpenChangeComplete.useOpenChangeComplete)({
enabled: !actionsRef,
open,
ref: popupRef,
onComplete() {
if (!open) {
handleUnmount();
}
}
});
React.useImperativeHandle(actionsRef, () => ({
unmount: handleUnmount
}), [handleUnmount]);
const setOpen = (0, _useStableCallback.useStableCallback)((nextOpen, eventDetails) => {
const isHover = eventDetails.reason === _reasons.REASONS.triggerHover;
const isFocusOpen = nextOpen && eventDetails.reason === _reasons.REASONS.triggerFocus;
const isDismissClose = !nextOpen && (eventDetails.reason === _reasons.REASONS.triggerPress || eventDetails.reason === _reasons.REASONS.escapeKey);
onOpenChange(nextOpen, eventDetails);
if (eventDetails.isCanceled) {
return;
}
function changeState() {
setOpenUnwrapped(nextOpen);
}
if (isHover) {
// If a hover reason is provided, we need to flush the state synchronously. This ensures
// `node.getAnimations()` knows about the new state.
ReactDOM.flushSync(changeState);
} else {
changeState();
}
if (isFocusOpen || isDismissClose) {
setInstantTypeState(isFocusOpen ? 'focus' : 'dismiss');
} else if (eventDetails.reason === _reasons.REASONS.triggerHover) {
setInstantTypeState(undefined);
}
});
const context = (0, _floatingUiReact.useFloatingRootContext)({
elements: {
reference: triggerElement,
floating: positionerElement
},
open,
onOpenChange: setOpen
});
const instantType = instantTypeState;
const getDelayValue = () => delayRef.current;
const getCloseDelayValue = () => closeDelayRef.current;
const hover = (0, _floatingUiReact.useHover)(context, {
mouseOnly: true,
move: false,
handleClose: (0, _floatingUiReact.safePolygon)(),
restMs: getDelayValue,
delay: () => ({
close: getCloseDelayValue()
})
});
const focus = (0, _useFocusWithDelay.useFocusWithDelay)(context, {
delay: getDelayValue
});
const dismiss = (0, _floatingUiReact.useDismiss)(context);
const {
getReferenceProps,
getFloatingProps
} = (0, _floatingUiReact.useInteractions)([hover, focus, dismiss]);
const contextValue = React.useMemo(() => ({
open,
setOpen,
mounted,
setMounted,
setTriggerElement,
positionerElement,
setPositionerElement,
popupRef,
triggerProps: getReferenceProps(),
popupProps: getFloatingProps(),
floatingRootContext: context,
instantType,
transitionStatus,
onOpenChangeComplete,
writeDelayRefs
}), [open, setOpen, mounted, setMounted, positionerElement, getReferenceProps, getFloatingProps, context, instantType, transitionStatus, onOpenChangeComplete, writeDelayRefs]);
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_PreviewCardContext.PreviewCardRootContext.Provider, {
value: contextValue,
children: props.children
});
}