UNPKG

@octopusdeploy/design-system-components

Version:
75 lines (74 loc) 4.08 kB
"use strict"; 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, noPadding = false, hasTopBorder = false, hasBottomBorder = false }) { if (hasBorder) { hasTopBorder = true; hasBottomBorder = true; } const topBorderColour = hasTopBorder ? design_system_tokens_1.themeTokens.color.border.primary : "transparent"; const bottomBorderColour = hasBottomBorder ? design_system_tokens_1.themeTokens.color.border.primary : "transparent"; return ((0, jsx_runtime_1.jsxs)("details", { className: styles.details, style: { borderTopColor: topBorderColour, borderBottomColor: bottomBorderColour }, 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: noPadding ? styles.contentNoPadding : 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, }), contentNoPadding: (0, css_1.css)({ lineHeight: design_system_tokens_1.lineHeight.small, }), };