UNPKG

@grafana/ui

Version:
132 lines (129 loc) 5.12 kB
import { jsxs, jsx } from 'react/jsx-runtime'; import { css, cx } from '@emotion/css'; import { useDialog } from '@react-aria/dialog'; import { FocusScope } from '@react-aria/focus'; import { useOverlay } from '@react-aria/overlays'; import { forwardRef, Children, useState, useRef, createRef, useLayoutEffect } from 'react'; import { t } from '@grafana/i18n'; import { useTheme2 } from '../../themes/ThemeContext.mjs'; import { getPortalContainer } from '../Portal/Portal.mjs'; import { ToolbarButton } from './ToolbarButton.mjs'; "use strict"; const ToolbarButtonRow = forwardRef( ({ alignment = "left", className, children, ...rest }, ref) => { const childrenWithoutNull = Children.toArray(children).filter((child) => child != null); const [childVisibility, setChildVisibility] = useState(Array(childrenWithoutNull.length).fill(false)); const containerRef = useRef(null); const [showOverflowItems, setShowOverflowItems] = useState(false); const overflowRef = useRef(null); const overflowItemsRef = createRef(); const { overlayProps } = useOverlay( { onClose: () => setShowOverflowItems(false), isDismissable: true, isOpen: showOverflowItems, shouldCloseOnInteractOutside: (element) => { var _a; const portalContainer = getPortalContainer(); return !((_a = overflowRef.current) == null ? void 0 : _a.contains(element)) && !portalContainer.contains(element); } }, overflowItemsRef ); const { dialogProps } = useDialog({}, overflowItemsRef); const theme = useTheme2(); const overflowButtonOrder = alignment === "left" ? childVisibility.indexOf(false) - 1 : childVisibility.length; const styles = getStyles(theme, overflowButtonOrder, alignment); useLayoutEffect(() => { const intersectionObserver = new IntersectionObserver( (entries) => { entries.forEach((entry) => { if (entry.target instanceof HTMLElement && entry.target.parentNode) { const index = Array.prototype.indexOf.call(entry.target.parentNode.children, entry.target); setChildVisibility((prev) => { const newVisibility = [...prev]; newVisibility[index] = entry.isIntersecting; return newVisibility; }); } }); }, { threshold: 1, root: containerRef.current } ); if (containerRef.current) { Array.from(containerRef.current.children).forEach((item) => { if (item instanceof HTMLElement && item !== overflowRef.current) { intersectionObserver.observe(item); } }); } return () => intersectionObserver.disconnect(); }, [children]); return /* @__PURE__ */ jsxs("div", { ref: containerRef, className: cx(styles.container, className), ...rest, children: [ childrenWithoutNull.map((child, index) => /* @__PURE__ */ jsx( "div", { style: { order: index, visibility: childVisibility[index] ? "visible" : "hidden" }, className: styles.childWrapper, children: child }, index )), childVisibility.includes(false) && /* @__PURE__ */ jsxs("div", { ref: overflowRef, className: styles.overflowButton, children: [ /* @__PURE__ */ jsx( ToolbarButton, { variant: showOverflowItems ? "active" : "default", tooltip: t("grafana-ui.toolbar-button-row.show-more", "Show more items"), onClick: () => setShowOverflowItems(!showOverflowItems), icon: "ellipsis-v", iconOnly: true, narrow: true } ), showOverflowItems && /* @__PURE__ */ jsx(FocusScope, { contain: true, autoFocus: true, children: /* @__PURE__ */ jsx("div", { className: styles.overflowItems, ref: overflowItemsRef, ...overlayProps, ...dialogProps, children: childrenWithoutNull.map((child, index) => !childVisibility[index] && child) }) }) ] }) ] }); } ); ToolbarButtonRow.displayName = "ToolbarButtonRow"; const getStyles = (theme, overflowButtonOrder, alignment) => ({ overflowButton: css({ order: overflowButtonOrder }), overflowItems: css({ alignItems: "center", backgroundColor: theme.colors.background.primary, borderRadius: theme.shape.radius.default, boxShadow: theme.shadows.z2, display: "flex", flexWrap: "wrap", gap: theme.spacing(1), marginTop: theme.spacing(1), maxWidth: "80vw", padding: theme.spacing(0.5, 1), position: "absolute", right: 0, top: "100%", width: "max-content", zIndex: theme.zIndex.dropdown }), container: css({ alignItems: "center", display: "flex", gap: theme.spacing(1), justifyContent: alignment === "left" ? "flex-start" : "flex-end", minWidth: 0, position: "relative" }), childWrapper: css({ alignItems: "center", display: "flex", gap: theme.spacing(1) }) }); export { ToolbarButtonRow }; //# sourceMappingURL=ToolbarButtonRow.mjs.map