UNPKG

@carbon/react

Version:

React components for the Carbon Design System

345 lines (343 loc) 15.2 kB
/** * Copyright IBM Corp. 2016, 2026 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ const require_runtime = require("../../_virtual/_rolldown/runtime.js"); const require_usePrefix = require("../../internal/usePrefix.js"); const require_Text = require("../Text/Text.js"); const require_useIsomorphicEffect = require("../../internal/useIsomorphicEffect.js"); const require_useId = require("../../internal/useId.js"); const require_AspectRatio = require("../AspectRatio/AspectRatio.js"); const require_index = require("../Popover/index.js"); const require_DefinitionTooltip = require("../Tooltip/DefinitionTooltip.js"); const require_MenuItem = require("../Menu/MenuItem.js"); const require_Grid = require("../Grid/Grid.js"); const require_Column = require("../Grid/Column.js"); const require_index$1 = require("../MenuButton/index.js"); const require_useMatchMedia = require("../../internal/useMatchMedia.js"); const require_Tag = require("../Tag/Tag.js"); const require_OperationalTag = require("../Tag/OperationalTag.js"); const require_useOverflowItems = require("../../internal/useOverflowItems.js"); let classnames = require("classnames"); classnames = require_runtime.__toESM(classnames); let react = require("react"); react = require_runtime.__toESM(react); let prop_types = require("prop-types"); prop_types = require_runtime.__toESM(prop_types); let react_jsx_runtime = require("react/jsx-runtime"); let _carbon_utilities = require("@carbon/utilities"); let _carbon_layout = require("@carbon/layout"); //#region src/components/PageHeader/PageHeader.tsx /** * Copyright IBM Corp. 2025, 2026 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ const PageHeader = react.default.forwardRef(({ className, children, ...other }, ref) => { return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: (0, classnames.default)({ [`${require_usePrefix.usePrefix()}--page-header`]: true }, className), ref, ...other, children }); }); PageHeader.displayName = "PageHeader"; const PageHeaderBreadcrumbBar = react.default.forwardRef(({ border = true, className, children, renderIcon: IconElement, contentActions, contentActionsFlush, pageActions, pageActionsFlush, ...other }, ref) => { const prefix = require_usePrefix.usePrefix(); const classNames = (0, classnames.default)({ [`${prefix}--page-header__breadcrumb-bar`]: true, [`${prefix}--page-header__breadcrumb-bar-border`]: border, [`${prefix}--page-header__breadcrumb__actions-flush`]: pageActionsFlush }, className); const contentActionsClasses = (0, classnames.default)({ [`${prefix}--page-header__breadcrumb__content-actions`]: !contentActionsFlush }); return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: classNames, ref, ...other, children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Grid.GridAsGridComponent, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Column.default, { lg: 16, md: 8, sm: 4, children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { className: `${prefix}--page-header__breadcrumb-container`, children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { className: `${prefix}--page-header__breadcrumb-wrapper`, children: [IconElement && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: `${prefix}--page-header__breadcrumb__icon`, children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconElement, {}) }), children] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { className: `${prefix}--page-header__breadcrumb__actions`, children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: contentActionsClasses, children: contentActions }), pageActions] })] }) }) }) }); }); PageHeaderBreadcrumbBar.displayName = "PageHeaderBreadcrumbBar"; const PageHeaderContent = react.default.forwardRef(({ className, children, title, renderIcon: IconElement, contextualActions, pageActions, ...other }, ref) => { const prefix = require_usePrefix.usePrefix(); const classNames = (0, classnames.default)({ [`${prefix}--page-header__content`]: true }, className); const titleRef = (0, react.useRef)(null); const [isEllipsisApplied, setIsEllipsisApplied] = (0, react.useState)(false); const isEllipsisActive = (element) => { setIsEllipsisApplied(element.offsetHeight < element.scrollHeight); return element.offsetHeight < element.scrollHeight; }; require_useIsomorphicEffect.default(() => { if (titleRef.current) isEllipsisActive(titleRef.current); }, [title]); return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: classNames, ref, ...other, children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Grid.GridAsGridComponent, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_Column.default, { lg: 16, md: 8, sm: 4, children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { className: `${prefix}--page-header__content__title-wrapper`, children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { className: `${prefix}--page-header__content__start`, children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { className: `${prefix}--page-header__content__title-container`, children: [IconElement && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: `${prefix}--page-header__content__icon`, children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconElement, {}) }), isEllipsisApplied ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_DefinitionTooltip.DefinitionTooltip, { definition: title, children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Text.Text, { ref: titleRef, as: "h4", className: `${prefix}--page-header__content__title`, children: title }) }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Text.Text, { ref: titleRef, as: "h4", className: `${prefix}--page-header__content__title`, children: title })] }), contextualActions && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: `${prefix}--page-header__content__contextual-actions`, children: contextualActions })] }), pageActions] }), children] }) }) }); }); PageHeaderContent.displayName = "PageHeaderContent"; PageHeaderContent.propTypes = { children: prop_types.default.node, className: prop_types.default.string, renderIcon: prop_types.default.oneOfType([prop_types.default.func, prop_types.default.object]), title: prop_types.default.string.isRequired, subtitle: prop_types.default.string, contextualActions: prop_types.default.node, pageActions: prop_types.default.node }; const PageHeaderContentPageActions = ({ className, children, menuButtonLabel = "Actions", actions, ...other }) => { const classNames = (0, classnames.default)({ [`${require_usePrefix.usePrefix()}--page-header__content__page-actions`]: true }, className); const containerRef = (0, react.useRef)(null); const offsetRef = (0, react.useRef)(null); const [menuButtonVisibility, setMenuButtonVisibility] = (0, react.useState)(false); const [hiddenItems, setHiddenItems] = (0, react.useState)([]); require_useIsomorphicEffect.default(() => { if (menuButtonVisibility && offsetRef.current) { const width = offsetRef.current.offsetWidth; document.documentElement.style.setProperty("--pageheader-title-grid-width", `${width}px`); } }, [menuButtonVisibility]); (0, react.useEffect)(() => { if (!containerRef.current || !Array.isArray(actions)) return; (0, _carbon_utilities.createOverflowHandler)({ container: containerRef.current, maxVisibleItems: containerRef.current.children.length - 1, onChange: (visible, hidden) => { setHiddenItems(actions?.slice(visible.length)); if (hidden.length > 0) setMenuButtonVisibility(true); } }); }, []); return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: classNames, ref: containerRef, ...other, children: actions && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: Array.isArray(actions) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [actions.map((action) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: react.default.cloneElement(action.body, { ...action.body.props, onClick: action.onClick }) }, action.id)), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { "data-offset": true, "data-hidden": true, ref: offsetRef, children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_index$1.MenuButton, { menuAlignment: "bottom-end", label: menuButtonLabel, size: "md", children: [...hiddenItems].reverse().map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_MenuItem.MenuItem, { onClick: item.onClick, ...item.menuItem }, item.id)) }) })] }) }) }); }; PageHeaderContentPageActions.displayName = "PageHeaderContentPageActions"; PageHeaderContentPageActions.propTypes = { children: prop_types.default.node, className: prop_types.default.string, menuButtonLabel: prop_types.default.string, actions: prop_types.default.oneOfType([prop_types.default.node, prop_types.default.array]) }; const PageHeaderContentText = ({ className, children, subtitle, ...other }) => { const prefix = require_usePrefix.usePrefix(); return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { className: (0, classnames.default)({ [`${prefix}--page-header__content__body`]: true }, className), ...other, children: [subtitle && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Text.Text, { as: "h3", className: `${prefix}--page-header__content__subtitle`, children: subtitle }), children] }); }; PageHeaderContentText.displayName = "PageHeaderContentText"; PageHeaderContentText.propTypes = { children: prop_types.default.node, className: prop_types.default.string, subtitle: prop_types.default.string }; const PageHeaderHeroImage = ({ className, children, ...other }) => { const classNames = (0, classnames.default)({ [`${require_usePrefix.usePrefix()}--page-header__hero-image`]: true }, className); const isLg = require_useMatchMedia.useMatchMedia(`(min-width: ${_carbon_layout.breakpoints.lg.width})`); return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_AspectRatio.default, { className: classNames, ...other, ratio: isLg ? "2x1" : "3x2", children }); }; PageHeaderHeroImage.displayName = "PageHeaderHeroImage"; PageHeaderHeroImage.propTypes = { children: prop_types.default.node, className: prop_types.default.string }; const PageHeaderTabBar = react.default.forwardRef(({ className, children, tags = [], ...other }, ref) => { const prefix = require_usePrefix.usePrefix(); const classNames = (0, classnames.default)({ [`${prefix}--page-header__tab-bar`]: true }, className); const [openPopover, setOpenPopover] = (0, react.useState)(false); const tagSize = tags[0]?.size || "md"; const instanceId = require_useId.useId("PageHeaderTabBar"); const tagsWithIds = (0, react.useMemo)(() => { return tags.map((tag, index) => ({ ...tag, id: tag.id || `tag-${index}-${instanceId}` })); }, [instanceId, tags]); const tagsContainerRef = (0, react.useRef)(null); const offsetRef = (0, react.useRef)(null); (0, react.useEffect)(() => { const handleResize = () => { setOpenPopover(false); }; window.addEventListener("resize", handleResize); return () => { window.removeEventListener("resize", handleResize); }; }, []); const { visibleItems = [], hiddenItems = [], itemRefHandler = () => {} } = require_useOverflowItems.default(tagsWithIds, tagsContainerRef, offsetRef) || { visibleItems: [], hiddenItems: [], itemRefHandler: () => {} }; const handleOverflowClick = (0, react.useCallback)((event) => { event.stopPropagation(); setOpenPopover((prev) => !prev); }, []); const renderTags = () => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { className: `${prefix}--page-header__tags`, ref: tagsContainerRef, children: [visibleItems.map((tag) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Tag.default, { ref: (node) => itemRefHandler(tag.id, node), type: tag.type, size: tag.size, className: `${prefix}--page-header__tag-item`, children: tag.text }, tag.id)), hiddenItems.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_index.Popover, { open: openPopover, onRequestClose: () => setOpenPopover(false), children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_OperationalTag.default, { onClick: handleOverflowClick, "aria-expanded": openPopover, text: `+${hiddenItems.length}`, size: tagSize }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_index.PopoverContent, { className: "tag-popover-content", children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: `${prefix}--page-header__tags-popover-list`, children: hiddenItems.map((tag) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Tag.default, { type: tag.type, size: tag.size, children: tag.text }, tag.id)) }) })] })] }); return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: classNames, ref, ...other, children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Grid.GridAsGridComponent, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Column.default, { lg: 16, md: 8, sm: 4, children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { className: `${prefix}--page-header__tab-bar--tablist`, children: [children, tags.length > 0 && renderTags()] }) }) }) }); }); PageHeaderTabBar.displayName = "PageHeaderTabBar"; /** * ------- * Exports * ------- */ const Root = PageHeader; Root.displayName = "PageHeader.Root"; const BreadcrumbBar = PageHeaderBreadcrumbBar; BreadcrumbBar.displayName = "PageHeaderBreadcrumbBar"; const Content = PageHeaderContent; Content.displayName = "PageHeaderContent"; const ContentPageActions = PageHeaderContentPageActions; ContentPageActions.displayName = "PageHeaderContentPageActions"; const ContentText = PageHeaderContentText; ContentText.displayName = "PageHeaderContentText"; const HeroImage = PageHeaderHeroImage; HeroImage.displayName = "PageHeaderHeroImage"; const TabBar = PageHeaderTabBar; TabBar.displayName = "PageHeaderTabBar"; //#endregion exports.BreadcrumbBar = BreadcrumbBar; exports.Content = Content; exports.ContentPageActions = ContentPageActions; exports.ContentText = ContentText; exports.HeroImage = HeroImage; exports.PageHeader = PageHeader; exports.PageHeaderBreadcrumbBar = PageHeaderBreadcrumbBar; exports.PageHeaderContent = PageHeaderContent; exports.PageHeaderContentPageActions = PageHeaderContentPageActions; exports.PageHeaderContentText = PageHeaderContentText; exports.PageHeaderHeroImage = PageHeaderHeroImage; exports.PageHeaderTabBar = PageHeaderTabBar; exports.Root = Root; exports.TabBar = TabBar;