UNPKG

@hitachivantara/uikit-react-lab

Version:

Contributed React components for the NEXT UI Kit.

176 lines (175 loc) 4.68 kB
import { jsx, jsxs } from "react/jsx-runtime"; import { useCallback, useMemo, useRef, useState, useEffect } from "react"; import { useDefaultProps, useControlled, useUniqueId, setId, HvTypography } from "@hitachivantara/uikit-react-core"; import { useClasses } from "./Blade.styles.js"; import { staticClasses } from "./Blade.styles.js"; const HvBlade = (props) => { const { id: idProp, className, classes: classesProp, expanded, defaultExpanded = false, label, labelVariant = "label", headingLevel, onChange, disabled = false, children, fullWidth, buttonProps, containerProps, ...others } = useDefaultProps("HvBlade", props); const { classes, cx } = useClasses(classesProp); const [isExpanded, setIsExpanded] = useControlled( expanded, Boolean(defaultExpanded) ); const handleAction = useCallback( (event) => { if (!disabled) { onChange?.(event, !isExpanded); setIsExpanded(!isExpanded); return true; } return false; }, [disabled, onChange, isExpanded, setIsExpanded] ); const handleClick = useCallback( (event) => { handleAction(event); event.preventDefault(); event.stopPropagation(); }, [handleAction] ); const handleKeyDown = useCallback( (event) => { let isEventHandled = false; const { key } = event; if (event.altKey || event.ctrlKey || event.metaKey || event.currentTarget !== event.target) { return; } switch (key) { case "Enter": case " ": isEventHandled = handleAction(event); break; default: return; } if (isEventHandled) { event.preventDefault(); event.stopPropagation(); } }, [handleAction] ); const id = useUniqueId(idProp); const bladeHeaderId = setId(id, "button"); const bladeContainerId = setId(id, "container"); const bladeHeader = useMemo(() => { const buttonLabel = typeof label === "function" ? label(isExpanded) : label; const bladeButton = /* @__PURE__ */ jsx( HvTypography, { id: bladeHeaderId, component: "div", role: "button", className: cx(classes.button, { [classes.textOnlyLabel]: typeof buttonLabel === "string", [classes.disabled]: disabled }), style: { flexShrink: headingLevel === void 0 ? 0 : void 0 }, disabled, tabIndex: 0, onKeyDown: handleKeyDown, onClick: handleClick, variant: labelVariant, "aria-expanded": isExpanded, "aria-controls": bladeContainerId, ...buttonProps, children: buttonLabel } ); return headingLevel === void 0 ? bladeButton : /* @__PURE__ */ jsx( HvTypography, { component: `h${headingLevel}`, variant: labelVariant, className: classes.heading, style: { flexShrink: 0 }, children: bladeButton } ); }, [ bladeContainerId, bladeHeaderId, buttonProps, classes.button, classes.disabled, classes.heading, classes.textOnlyLabel, cx, disabled, handleClick, handleKeyDown, headingLevel, isExpanded, label, labelVariant ]); const bladeRef = useRef(null); const [maxWidth, setMaxWidth] = useState(void 0); useEffect(() => { if (!bladeRef.current) return; const resizeObserver = new ResizeObserver((entries) => { setMaxWidth(entries[0].target.clientWidth); }); resizeObserver.observe( // using the blade's container as reference max-width is more stable bladeRef.current.parentElement ?? bladeRef.current ); return () => { resizeObserver.disconnect(); }; }, [isExpanded]); const { style: containerStyle, ...otherContainerProps } = containerProps || {}; return /* @__PURE__ */ jsxs( "div", { ref: bladeRef, id: idProp, className: cx(classes.root, className, { [classes.fullWidth]: fullWidth, [classes.expanded]: isExpanded }), ...others, children: [ bladeHeader, /* @__PURE__ */ jsx( "div", { id: bladeContainerId, role: "region", "aria-labelledby": bladeHeaderId, className: classes.container, hidden: !isExpanded, style: { ...containerStyle, maxWidth: isExpanded ? maxWidth : 0 }, ...otherContainerProps, children } ) ] } ); }; export { HvBlade, staticClasses as bladeClasses };