@grafana/ui
Version:
Grafana Components Library
123 lines (118 loc) • 3.84 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var jsxRuntime = require('react/jsx-runtime');
var css = require('@emotion/css');
var React = require('react');
var ThemeContext = require('../../themes/ThemeContext.cjs');
var mixins = require('../../themes/mixins.cjs');
var Icon = require('../Icon/Icon.cjs');
var Spinner = require('../Spinner/Spinner.cjs');
"use strict";
const CollapsableSection = ({
label,
isOpen,
onToggle,
className,
contentClassName,
children,
labelId,
loading = false,
headerDataTestId,
contentDataTestId,
unmountContentWhenClosed = true
}) => {
const [internalOpenState, toggleInternalOpenState] = React.useState(isOpen);
const styles = ThemeContext.useStyles2(collapsableSectionStyles);
const isControlled = isOpen !== void 0 && onToggle !== void 0;
const isSectionOpen = isControlled ? isOpen : internalOpenState;
const onClick = (e) => {
if (e.target instanceof HTMLElement && e.target.tagName === "A") {
return;
}
e.preventDefault();
e.stopPropagation();
onToggle == null ? void 0 : onToggle(!isOpen);
if (!isControlled) {
toggleInternalOpenState(!internalOpenState);
}
};
const id = React.useId();
const buttonLabelId = labelId != null ? labelId : `collapse-label-${id}`;
const content = /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
id: `collapse-content-${id}`,
className: css.cx(styles.content, contentClassName, {
[styles.contentHidden]: !unmountContentWhenClosed && !isSectionOpen
}),
"data-testid": contentDataTestId,
children
}
);
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
/* @__PURE__ */ jsxRuntime.jsxs("div", { onClick, className: css.cx(styles.header, className), children: [
/* @__PURE__ */ jsxRuntime.jsx(
"button",
{
type: "button",
id: `collapse-button-${id}`,
className: styles.button,
onClick,
"aria-expanded": isSectionOpen && !loading,
"aria-controls": `collapse-content-${id}`,
"aria-labelledby": buttonLabelId,
children: loading ? /* @__PURE__ */ jsxRuntime.jsx(Spinner.Spinner, { className: styles.spinner }) : /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { name: isSectionOpen ? "angle-down" : "angle-right", className: styles.icon })
}
),
/* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.label, id: `collapse-label-${id}`, "data-testid": headerDataTestId, children: label })
] }),
unmountContentWhenClosed ? isSectionOpen && content : content
] });
};
const collapsableSectionStyles = (theme) => ({
header: css.css({
display: "flex",
alignItems: "center",
cursor: "pointer",
boxSizing: "border-box",
position: "relative",
justifyContent: "flex-start",
fontSize: theme.typography.size.lg,
padding: `${theme.spacing(0.5)} 0`,
"&:focus-within": mixins.getFocusStyles(theme)
}),
button: css.css({
all: "unset",
marginRight: theme.spacing(1),
"&:focus-visible": {
outline: "none",
outlineOffset: "unset",
[theme.transitions.handleMotion("no-preference", "reduce")]: {
transition: "none"
},
boxShadow: "none"
}
}),
icon: css.css({
color: theme.colors.text.secondary
}),
content: css.css({
padding: `${theme.spacing(2)} 0`
}),
contentHidden: css.css({
display: "none"
}),
spinner: css.css({
display: "flex",
alignItems: "center",
width: theme.spacing(2)
}),
label: css.css({
display: "flex",
flex: "1 1 auto",
fontWeight: theme.typography.fontWeightMedium,
color: theme.colors.text.maxContrast
})
});
exports.CollapsableSection = CollapsableSection;
//# sourceMappingURL=CollapsableSection.cjs.map