@octopusdeploy/design-system-components
Version:
The design systems component library.
67 lines (66 loc) • 3.64 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Accordion = Accordion;
const jsx_runtime_1 = require("react/jsx-runtime");
const css_1 = require("@emotion/css");
const design_system_icons_1 = require("@octopusdeploy/design-system-icons");
const design_system_tokens_1 = require("@octopusdeploy/design-system-tokens");
/**
* An accordion component built on the native `<details>` and `<summary>` elements.
*/
function Accordion({ summary, children, hasBorder = false }) {
const borderColor = hasBorder ? design_system_tokens_1.themeTokens.color.border.primary : "transparent";
return ((0, jsx_runtime_1.jsxs)("details", { className: styles.details, style: { borderTopColor: borderColor, borderBottomColor: borderColor }, children: [(0, jsx_runtime_1.jsxs)("summary", { className: styles.summary, children: [(0, jsx_runtime_1.jsx)("div", { className: styles.chevron, children: (0, jsx_runtime_1.jsx)(design_system_icons_1.ChevronRightIcon, { size: 20, color: design_system_tokens_1.themeTokens.color.button.icon.quiet }) }), summary] }), (0, jsx_runtime_1.jsx)("div", { className: styles.content, children: children })] }));
}
const styles = {
chevron: (0, css_1.css)({
display: "flex",
transition: "transform 150ms ease-in-out",
"details[open] > summary > &": {
transform: "rotate(90deg)",
},
}),
// Asymmetric borders collapse adjacent Accordions to one shared 1px line; transparent placeholders preserve layout when hasBorder toggles.
details: (0, css_1.css)({
borderBottom: "1px solid transparent",
"&:first-of-type": {
borderTop: "1px solid transparent",
},
// Opt into interpolating between numeric and keyword sizes so block-size: 0 → auto can transition. Inherited; older browsers snap.
interpolateSize: "allow-keywords",
"&::details-content": {
blockSize: 0,
opacity: 0,
overflow: "hidden",
// allow-discrete is needed because the browser toggles content-visibility on ::details-content; without it the height transition is interrupted.
transition: "content-visibility 200ms ease-in-out allow-discrete, block-size 200ms ease-in-out, opacity 100ms ease-in-out",
},
// The 100ms opacity delay applies only on opening — CSS transitions use the target state's declaration, so closing falls back to the base (no delay).
"&[open]::details-content": {
blockSize: "auto",
opacity: 1,
transition: "content-visibility 200ms ease-in-out allow-discrete, block-size 200ms ease-in-out, opacity 100ms ease-in-out 100ms",
},
}),
summary: (0, css_1.css)({
cursor: "pointer",
padding: `${design_system_tokens_1.space[8]} ${design_system_tokens_1.space[6]}`,
userSelect: "none",
font: design_system_tokens_1.text.body.bold.large,
display: "flex",
alignItems: "center",
gap: design_system_tokens_1.space[6],
listStyle: "none",
"&::-webkit-details-marker": { display: "none" },
"&:hover": {
backgroundColor: design_system_tokens_1.themeTokens.color.background.primary.hover,
},
"&:focus-visible": {
outline: `2px solid ${design_system_tokens_1.themeTokens.color.border.selected}`,
},
}),
content: (0, css_1.css)({
padding: `${design_system_tokens_1.space[8]} 0 ${design_system_tokens_1.space[16]} ${design_system_tokens_1.space[32]}`,
lineHeight: design_system_tokens_1.lineHeight.small,
}),
};