UNPKG

@octopusdeploy/design-system-components

Version:
120 lines (119 loc) 6.48 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FormSection = FormSection; 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"); const react_1 = require("react"); const markerLabels = { optional: "(optional)", required: "(required)", prefilled: "(pre-filled)", }; /** * Groups related form fields under a distinctive legend bar. * @remarks Rollout currently paused — do not use in new code until further notice. */ function FormSection(props) { const contentId = (0, react_1.useId)(); const isInteractive = props.isInteractive === true; const isOpen = !isInteractive || props.isOpen; return ((0, jsx_runtime_1.jsxs)("fieldset", { className: styles.root, children: [props.isInteractive ? ((0, jsx_runtime_1.jsx)("legend", { className: styles.interactiveWrapper, children: (0, jsx_runtime_1.jsxs)("button", { type: "button", className: styles.interactiveButton, "aria-expanded": props.isOpen, "aria-controls": contentId, onClick: () => props.onToggle(!props.isOpen), children: [(0, jsx_runtime_1.jsxs)("span", { className: styles.interactiveLeftGroup, children: [(0, jsx_runtime_1.jsxs)("span", { className: styles.titleAndMarker, children: [(0, jsx_runtime_1.jsx)("span", { children: props.title }), props.marker && (0, jsx_runtime_1.jsx)("span", { children: markerLabels[props.marker] })] }), props.badge] }), (0, jsx_runtime_1.jsx)("span", { className: (0, css_1.cx)(styles.chevron, { [styles.chevronOpen]: props.isOpen }), children: (0, jsx_runtime_1.jsx)(design_system_icons_1.ChevronRightIcon, { size: 20, color: design_system_tokens_1.themeTokens.color.button.icon.quiet }) })] }) })) : ((0, jsx_runtime_1.jsxs)("legend", { className: styles.static, children: [(0, jsx_runtime_1.jsxs)("span", { className: styles.titleAndMarker, children: [(0, jsx_runtime_1.jsx)("span", { children: props.title }), props.marker && (0, jsx_runtime_1.jsx)("span", { children: markerLabels[props.marker] })] }), props.badge] })), (0, jsx_runtime_1.jsx)("div", { id: contentId, className: (0, css_1.cx)(styles.content, { [styles.contentClosed]: !isOpen }), inert: isOpen ? undefined : "", children: props.children })] })); } const styles = { root: (0, css_1.css)({ display: "flex", flexDirection: "column", padding: 0, border: 0, margin: 0, minWidth: 0, interpolateSize: "allow-keywords", // Divider between stacked sections. :last-of-type (rather than :last-child) keeps the // rule scoped to sibling fieldsets - the only element FormSection renders - so a // trailing non-fieldset sibling doesn't give the final section a stray border. If the // divider ever needs to react to other sibling elements, don't broaden this selector; // push the logic up into an explicit parent component so FormSection keeps to its own // boundary. "&:not(:last-of-type)": { borderBottom: `${design_system_tokens_1.borderWidth[1]} solid ${design_system_tokens_1.themeTokens.color.border.primary}`, }, }), static: (0, css_1.css)({ display: "flex", alignItems: "center", gap: design_system_tokens_1.space[4], padding: `${design_system_tokens_1.space[12]} ${design_system_tokens_1.space[16]}`, backgroundColor: design_system_tokens_1.themeTokens.color.formLegend.background.rest, font: design_system_tokens_1.text.body.bold.large, color: design_system_tokens_1.themeTokens.color.text.primary, width: "100%", boxSizing: "border-box", }), interactiveWrapper: (0, css_1.css)({ padding: 0, width: "100%", }), interactiveButton: (0, css_1.css)({ display: "flex", alignItems: "center", justifyContent: "space-between", gap: design_system_tokens_1.space[8], width: "100%", padding: `${design_system_tokens_1.space[8]} ${design_system_tokens_1.space[8]} ${design_system_tokens_1.space[8]} ${design_system_tokens_1.space[16]}`, textAlign: "left", font: design_system_tokens_1.text.body.bold.large, color: design_system_tokens_1.themeTokens.color.text.primary, backgroundColor: design_system_tokens_1.themeTokens.color.formLegend.background.rest, transition: "background-color 150ms ease-in-out", border: "none", cursor: "pointer", "&:hover": { backgroundColor: design_system_tokens_1.themeTokens.color.formLegend.background.hover, }, "&:focus-visible": { outline: `2px solid ${design_system_tokens_1.themeTokens.color.border.selected}`, outlineOffset: "-2px", }, }), interactiveLeftGroup: (0, css_1.css)({ display: "flex", alignItems: "center", gap: design_system_tokens_1.space[4], }), chevron: (0, css_1.css)({ display: "flex", padding: `${design_system_tokens_1.space[6]} ${design_system_tokens_1.space[6]} ${design_system_tokens_1.space[6]} ${design_system_tokens_1.space[0]}`, svg: { transition: "transform 150ms ease-in-out", }, }), chevronOpen: (0, css_1.css)({ svg: { transform: "rotate(90deg)", }, }), titleAndMarker: (0, css_1.css)({ display: "flex", alignItems: "center", gap: design_system_tokens_1.space[2], }), content: (0, css_1.css)({ boxSizing: "border-box", width: "100%", padding: `${design_system_tokens_1.space[16]} ${design_system_tokens_1.space[16]} ${design_system_tokens_1.space[24]} ${design_system_tokens_1.space[16]} `, blockSize: "auto", opacity: 1, overflow: "hidden", transition: "block-size 200ms ease-in-out, padding-block 200ms ease-in-out, opacity 100ms ease-in-out 100ms", }), contentClosed: (0, css_1.css)({ blockSize: 0, // box-sizing: border-box can't shrink the box below its block padding, so zero it // too - otherwise a closed section keeps 40px of empty space below the legend. paddingBlock: 0, opacity: 0, transition: "block-size 200ms ease-in-out, padding-block 200ms ease-in-out, opacity 100ms ease-in-out", }), };