@carbon/react
Version:
React components for the Carbon Design System
112 lines (110 loc) • 3.85 kB
JavaScript
/**
* Copyright IBM Corp. 2016, 2026
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
import { usePrefix } from "../../internal/usePrefix.js";
import { AccordionContext } from "./AccordionProvider.js";
import { Text } from "../Text/Text.js";
import { Escape } from "../../internal/keyboard/keys.js";
import { match } from "../../internal/keyboard/match.js";
import { useId } from "../../internal/useId.js";
import { deprecate } from "../../prop-types/deprecate.js";
import classNames from "classnames";
import React, { useContext, useEffect, useRef, useState } from "react";
import PropTypes from "prop-types";
import { jsx, jsxs } from "react/jsx-runtime";
import { ChevronRight } from "@carbon/icons-react";
//#region src/components/Accordion/AccordionItem.tsx
/**
* Copyright IBM Corp. 2016, 2026
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
const defaultRenderToggle = (props) => /* @__PURE__ */ jsx("button", {
type: "button",
...props
});
function AccordionItem({ children, className: customClassName = "", open = false, onHeadingClick, renderExpando = defaultRenderToggle, renderToggle, title = "title", disabled: controlledDisabled, handleAnimationEnd, "aria-label": ariaLabel, ...rest }) {
const [isOpen, setIsOpen] = useState(open);
const prevOpenRef = useRef(open);
const accordionState = useContext(AccordionContext);
const disabled = typeof controlledDisabled === "boolean" ? controlledDisabled : accordionState.disabled;
const id = useId("accordion-item");
const prefix = usePrefix();
const className = classNames({
[`${prefix}--accordion__item`]: true,
[`${prefix}--accordion__item--active`]: isOpen && !disabled,
[`${prefix}--accordion__item--disabled`]: disabled,
[customClassName]: !!customClassName
});
const Toggle = renderToggle || renderExpando;
const content = React.useCallback((node) => {
if (!node) return;
if (isOpen) node.style.maxBlockSize = "";
}, [isOpen]);
useEffect(() => {
if (open !== prevOpenRef.current) {
setIsOpen(open);
prevOpenRef.current = open;
}
}, [open]);
function onClick(event) {
const nextValue = !isOpen;
setIsOpen(nextValue);
if (onHeadingClick) onHeadingClick({
isOpen: nextValue,
event
});
}
function onKeyDown(event) {
if (isOpen && match(event, Escape)) setIsOpen(false);
}
function onAnimationEnd(event) {
if (handleAnimationEnd) handleAnimationEnd(event);
}
return /* @__PURE__ */ jsxs("li", {
className,
...rest,
children: [/* @__PURE__ */ jsxs(Toggle, {
disabled,
"aria-controls": id,
"aria-expanded": isOpen,
"aria-label": ariaLabel,
className: `${prefix}--accordion__heading`,
onClick,
onKeyDown,
type: "button",
children: [/* @__PURE__ */ jsx(ChevronRight, { className: `${prefix}--accordion__arrow` }), /* @__PURE__ */ jsx(Text, {
as: "div",
className: `${prefix}--accordion__title`,
children: title
})]
}), /* @__PURE__ */ jsx("div", {
ref: content,
className: `${prefix}--accordion__wrapper`,
onTransitionEnd: onAnimationEnd,
children: /* @__PURE__ */ jsx("div", {
id,
className: `${prefix}--accordion__content`,
children
})
})]
});
}
AccordionItem.propTypes = {
children: PropTypes.node,
className: PropTypes.string,
disabled: PropTypes.bool,
"aria-label": PropTypes.string,
onClick: PropTypes.func,
onHeadingClick: PropTypes.func,
open: PropTypes.bool,
renderExpando: deprecate(PropTypes.func, "The `renderExpando` prop has been deprecated and will be removed in the next major release of Carbon. Use the `renderToggle` prop instead."),
renderToggle: PropTypes.func,
title: PropTypes.node
};
//#endregion
export { AccordionItem as default };