UNPKG

@grafana/ui

Version:
1 lines 8.09 kB
{"version":3,"file":"CollapsableSection.mjs","sources":["../../../../src/components/Collapse/CollapsableSection.tsx"],"sourcesContent":["import { css, cx } from '@emotion/css';\nimport { uniqueId } from 'lodash';\nimport { ReactNode, useRef, useState } from 'react';\nimport * as React from 'react';\n\nimport { GrafanaTheme2 } from '@grafana/data';\n\nimport { useStyles2 } from '../../themes/ThemeContext';\nimport { getFocusStyles } from '../../themes/mixins';\nimport { Icon } from '../Icon/Icon';\nimport { Spinner } from '../Spinner/Spinner';\n\nexport interface Props {\n label: ReactNode;\n isOpen: boolean;\n /** Callback for the toggle functionality */\n onToggle?: (isOpen: boolean) => void;\n children: ReactNode;\n className?: string;\n contentClassName?: string;\n loading?: boolean;\n labelId?: string;\n headerDataTestId?: string;\n contentDataTestId?: string;\n unmountContentWhenClosed?: boolean;\n}\n\n/**\n * A simple container for enabling collapsing/expanding of content.\n *\n * https://developers.grafana.com/ui/latest/index.html?path=/docs/layout-collapsablesection--docs\n */\nexport const CollapsableSection = ({\n label,\n isOpen,\n onToggle,\n className,\n contentClassName,\n children,\n labelId,\n loading = false,\n headerDataTestId,\n contentDataTestId,\n unmountContentWhenClosed = true,\n}: Props) => {\n const [internalOpenState, toggleInternalOpenState] = useState<boolean>(isOpen);\n const styles = useStyles2(collapsableSectionStyles);\n\n const isControlled = isOpen !== undefined && onToggle !== undefined;\n const isSectionOpen = isControlled ? isOpen : internalOpenState;\n\n const onClick = (e: React.MouseEvent) => {\n if (e.target instanceof HTMLElement && e.target.tagName === 'A') {\n return;\n }\n\n e.preventDefault();\n e.stopPropagation();\n\n onToggle?.(!isOpen);\n\n if (!isControlled) {\n toggleInternalOpenState(!internalOpenState);\n }\n };\n const { current: id } = useRef(uniqueId());\n\n const buttonLabelId = labelId ?? `collapse-label-${id}`;\n\n const content = (\n <div\n id={`collapse-content-${id}`}\n className={cx(styles.content, contentClassName, {\n [styles.contentHidden]: !unmountContentWhenClosed && !isSectionOpen,\n })}\n data-testid={contentDataTestId}\n >\n {children}\n </div>\n );\n\n return (\n <>\n {/* disabling the a11y rules here as the button handles keyboard interactions */}\n {/* this is just to provide a better experience for mouse users */}\n {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}\n <div onClick={onClick} className={cx(styles.header, className)}>\n <button\n type=\"button\"\n id={`collapse-button-${id}`}\n className={styles.button}\n onClick={onClick}\n aria-expanded={isSectionOpen && !loading}\n aria-controls={`collapse-content-${id}`}\n aria-labelledby={buttonLabelId}\n >\n {loading ? (\n <Spinner className={styles.spinner} />\n ) : (\n <Icon name={isSectionOpen ? 'angle-down' : 'angle-right'} className={styles.icon} />\n )}\n </button>\n <div className={styles.label} id={`collapse-label-${id}`} data-testid={headerDataTestId}>\n {label}\n </div>\n </div>\n {unmountContentWhenClosed ? isSectionOpen && content : content}\n </>\n );\n};\n\nconst collapsableSectionStyles = (theme: GrafanaTheme2) => ({\n header: css({\n display: 'flex',\n alignItems: 'center',\n cursor: 'pointer',\n boxSizing: 'border-box',\n position: 'relative',\n justifyContent: 'flex-start',\n fontSize: theme.typography.size.lg,\n padding: `${theme.spacing(0.5)} 0`,\n '&:focus-within': getFocusStyles(theme),\n }),\n button: css({\n all: 'unset',\n marginRight: theme.spacing(1),\n '&:focus-visible': {\n outline: 'none',\n outlineOffset: 'unset',\n [theme.transitions.handleMotion('no-preference', 'reduce')]: {\n transition: 'none',\n },\n boxShadow: 'none',\n },\n }),\n icon: css({\n color: theme.colors.text.secondary,\n }),\n content: css({\n padding: `${theme.spacing(2)} 0`,\n }),\n contentHidden: css({\n display: 'none',\n }),\n spinner: css({\n display: 'flex',\n alignItems: 'center',\n width: theme.spacing(2),\n }),\n label: css({\n display: 'flex',\n flex: '1 1 auto',\n fontWeight: theme.typography.fontWeightMedium,\n color: theme.colors.text.maxContrast,\n }),\n});\n"],"names":[],"mappings":"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"}