@base-ui/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.
122 lines (121 loc) • 3.91 kB
JavaScript
'use client';
import * as React from 'react';
import { useIsoLayoutEffect } from '@base-ui/utils/useIsoLayoutEffect';
import { warn } from '@base-ui/utils/warn';
import { resolveStyle } from "../../utils/resolveStyle.js";
import { useCollapsibleRootContext } from "../../collapsible/root/CollapsibleRootContext.js";
import { useCollapsiblePanel } from "../../collapsible/panel/useCollapsiblePanel.js";
import { useAccordionRootContext } from "../root/AccordionRootContext.js";
import { useAccordionItemContext } from "../item/AccordionItemContext.js";
import { accordionStateAttributesMapping } from "../item/stateAttributesMapping.js";
import { AccordionPanelCssVars } from "./AccordionPanelCssVars.js";
import { useRenderElement } from "../../internals/useRenderElement.js";
/**
* A collapsible panel with the accordion item contents.
* Renders a `<div>` element.
*
* Documentation: [Base UI Accordion](https://base-ui.com/react/components/accordion)
*/
export const AccordionPanel = /*#__PURE__*/React.forwardRef(function AccordionPanel(componentProps, forwardedRef) {
const {
className,
hiddenUntilFound: hiddenUntilFoundProp,
keepMounted: keepMountedProp,
id: idProp,
render,
style,
...elementProps
} = componentProps;
const {
hiddenUntilFound: contextHiddenUntilFound,
keepMounted: contextKeepMounted
} = useAccordionRootContext();
const {
mounted,
onOpenChange,
open,
panelId,
setMounted,
setOpen,
setPanelIdState,
transitionStatus
} = useCollapsibleRootContext();
const hiddenUntilFound = hiddenUntilFoundProp ?? contextHiddenUntilFound;
const keepMounted = keepMountedProp ?? contextKeepMounted;
if (process.env.NODE_ENV !== 'production') {
// eslint-disable-next-line react-hooks/rules-of-hooks
useIsoLayoutEffect(() => {
if (keepMountedProp === false && hiddenUntilFound) {
warn('The `keepMounted={false}` prop on an `Accordion.Panel` is ignored when `hiddenUntilFound` is enabled on the panel or root, since the panel must remain mounted while closed.');
}
}, [hiddenUntilFound, keepMountedProp]);
}
useIsoLayoutEffect(() => {
if (idProp) {
setPanelIdState(idProp);
return () => {
setPanelIdState(undefined);
};
}
return undefined;
}, [idProp, setPanelIdState]);
const {
height,
props,
ref,
shouldPreventOpenAnimation,
shouldRender,
transitionStatus: panelTransitionStatus,
width
} = useCollapsiblePanel({
externalRef: forwardedRef,
hiddenUntilFound,
id: idProp ?? panelId,
keepMounted,
mounted,
onOpenChange,
open,
setMounted,
setOpen,
transitionStatus
});
const {
state,
triggerId
} = useAccordionItemContext();
const panelState = {
...state,
transitionStatus: panelTransitionStatus
};
const resolvedStyle = resolveStyle(style, panelState);
const element = useRenderElement('div', {
...componentProps,
style: undefined
}, {
state: panelState,
ref,
props: [props, {
'aria-labelledby': triggerId,
role: 'region',
style: {
[AccordionPanelCssVars.accordionPanelHeight]: height === undefined ? 'auto' : `${height}px`,
[AccordionPanelCssVars.accordionPanelWidth]: width === undefined ? 'auto' : `${width}px`
}
}, elementProps, resolvedStyle ? {
style: resolvedStyle
} : undefined,
// Resolve the public `style` prop so temporary `animationName: 'none'`
// can still win after user's inline styles have been merged.
shouldPreventOpenAnimation ? {
style: {
animationName: 'none'
}
} : undefined],
stateAttributesMapping: accordionStateAttributesMapping
});
if (!shouldRender) {
return null;
}
return element;
});
if (process.env.NODE_ENV !== "production") AccordionPanel.displayName = "AccordionPanel";