@carbon/react
Version:
React components for the Carbon Design System
505 lines (480 loc) • 18.4 kB
JavaScript
/**
* Copyright IBM Corp. 2016, 2023
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var _rollupPluginBabelHelpers = require('../../_virtual/_rollupPluginBabelHelpers.js');
var React = require('react');
var PropTypes = require('prop-types');
var cx = require('classnames');
var usePrefix = require('../../internal/usePrefix.js');
var layout = require('@carbon/layout');
var useMatchMedia = require('../../internal/useMatchMedia.js');
require('../Text/index.js');
var index = require('../MenuButton/index.js');
require('../Menu/Menu.js');
var MenuItem = require('../Menu/MenuItem.js');
var DefinitionTooltip = require('../Tooltip/DefinitionTooltip.js');
require('../Tooltip/Tooltip.js');
var AspectRatio = require('../AspectRatio/AspectRatio.js');
var utilities = require('@carbon/utilities');
var Tag = require('../Tag/Tag.js');
require('../Tag/DismissibleTag.js');
var OperationalTag = require('../Tag/OperationalTag.js');
require('../Tag/SelectableTag.js');
require('../Tag/Tag.Skeleton.js');
var useOverflowItems = require('../../internal/useOverflowItems.js');
var index$1 = require('../Popover/index.js');
var useId = require('../../internal/useId.js');
require('../Grid/FlexGrid.js');
var Grid = require('../Grid/Grid.js');
require('../Grid/Row.js');
var Column = require('../Grid/Column.js');
require('../Grid/ColumnHang.js');
require('../Grid/GridContext.js');
var Text = require('../Text/Text.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
var PropTypes__default = /*#__PURE__*/_interopDefaultLegacy(PropTypes);
var cx__default = /*#__PURE__*/_interopDefaultLegacy(cx);
/**
* ----------
* PageHeader
* ----------
*/
const PageHeader = /*#__PURE__*/React__default["default"].forwardRef(function PageHeader({
className,
children,
...other
}, ref) {
const prefix = usePrefix.usePrefix();
const classNames = cx__default["default"]({
[`${prefix}--page-header`]: true
}, className);
return /*#__PURE__*/React__default["default"].createElement("div", _rollupPluginBabelHelpers["extends"]({
className: classNames,
ref: ref
}, other), children);
});
PageHeader.displayName = 'PageHeader';
/**
* -----------------------
* PageHeaderBreadcrumbBar
* -----------------------
*/
const PageHeaderBreadcrumbBar = /*#__PURE__*/React__default["default"].forwardRef(function PageHeaderBreadcrumbBar({
border = true,
className,
children,
renderIcon: IconElement,
contentActions,
contentActionsFlush,
pageActions,
pageActionsFlush,
...other
}, ref) {
const prefix = usePrefix.usePrefix();
const classNames = cx__default["default"]({
[`${prefix}--page-header__breadcrumb-bar`]: true,
[`${prefix}--page-header__breadcrumb-bar-border`]: border,
[`${prefix}--page-header__breadcrumb__actions-flush`]: pageActionsFlush
}, className);
const contentActionsClasses = cx__default["default"]({
[`${prefix}--page-header__breadcrumb__content-actions`]: !contentActionsFlush
});
return /*#__PURE__*/React__default["default"].createElement("div", _rollupPluginBabelHelpers["extends"]({
className: classNames,
ref: ref
}, other), /*#__PURE__*/React__default["default"].createElement(Grid.Grid, null, /*#__PURE__*/React__default["default"].createElement(Column["default"], {
lg: 16,
md: 8,
sm: 4
}, /*#__PURE__*/React__default["default"].createElement("div", {
className: `${prefix}--page-header__breadcrumb-container`
}, /*#__PURE__*/React__default["default"].createElement("div", {
className: `${prefix}--page-header__breadcrumb-wrapper`
}, IconElement && /*#__PURE__*/React__default["default"].createElement("div", {
className: `${prefix}--page-header__breadcrumb__icon`
}, /*#__PURE__*/React__default["default"].createElement(IconElement, null)), children), /*#__PURE__*/React__default["default"].createElement("div", {
className: `${prefix}--page-header__breadcrumb__actions`
}, /*#__PURE__*/React__default["default"].createElement("div", {
className: contentActionsClasses
}, contentActions), pageActions)))));
});
PageHeaderBreadcrumbBar.displayName = 'PageHeaderBreadcrumbBar';
/**
* -----------------
* PageHeaderContent
* -----------------
*/
const PageHeaderContent = /*#__PURE__*/React__default["default"].forwardRef(function PageHeaderContent({
className,
children,
title,
renderIcon: IconElement,
contextualActions,
pageActions,
...other
}, ref) {
const prefix = usePrefix.usePrefix();
const classNames = cx__default["default"]({
[`${prefix}--page-header__content`]: true
}, className);
const titleRef = React.useRef(null);
const [isEllipsisApplied, setIsEllipsisApplied] = React.useState(false);
const isEllipsisActive = element => {
setIsEllipsisApplied(element.offsetHeight < element.scrollHeight);
return element.offsetHeight < element.scrollHeight;
};
React.useLayoutEffect(() => {
titleRef.current && isEllipsisActive(titleRef.current);
}, [title]);
return /*#__PURE__*/React__default["default"].createElement("div", _rollupPluginBabelHelpers["extends"]({
className: classNames,
ref: ref
}, other), /*#__PURE__*/React__default["default"].createElement(Grid.Grid, null, /*#__PURE__*/React__default["default"].createElement(Column["default"], {
lg: 16,
md: 8,
sm: 4
}, /*#__PURE__*/React__default["default"].createElement("div", {
className: `${prefix}--page-header__content__title-wrapper`
}, /*#__PURE__*/React__default["default"].createElement("div", {
className: `${prefix}--page-header__content__start`
}, /*#__PURE__*/React__default["default"].createElement("div", {
className: `${prefix}--page-header__content__title-container`
}, IconElement && /*#__PURE__*/React__default["default"].createElement("div", {
className: `${prefix}--page-header__content__icon`
}, /*#__PURE__*/React__default["default"].createElement(IconElement, null)), isEllipsisApplied ? /*#__PURE__*/React__default["default"].createElement(DefinitionTooltip.DefinitionTooltip, {
definition: title
}, /*#__PURE__*/React__default["default"].createElement(Text.Text, {
ref: titleRef,
as: "h4",
className: `${prefix}--page-header__content__title`
}, title)) : /*#__PURE__*/React__default["default"].createElement(Text.Text, {
ref: titleRef,
as: "h4",
className: `${prefix}--page-header__content__title`
}, title)), contextualActions && /*#__PURE__*/React__default["default"].createElement("div", {
className: `${prefix}--page-header__content__contextual-actions`
}, contextualActions)), pageActions), children)));
});
PageHeaderContent.displayName = 'PageHeaderContent';
PageHeaderContent.propTypes = {
/**
* Provide child elements to be rendered inside PageHeaderContent.
*/
children: PropTypes__default["default"].node,
/**
* Specify an optional className to be added to your PageHeaderContent
*/
className: PropTypes__default["default"].string,
/**
* Provide an optional icon to render in front of the PageHeaderContent's title.
*/
renderIcon: PropTypes__default["default"].oneOfType([PropTypes__default["default"].func, PropTypes__default["default"].object]),
/**
* The PageHeaderContent's title
*/
title: PropTypes__default["default"].string.isRequired,
/**
* The PageHeaderContent's subtitle
*/
subtitle: PropTypes__default["default"].string,
/**
* The PageHeaderContent's contextual actions
*/
contextualActions: PropTypes__default["default"].node,
/**
* The PageHeaderContent's page actions
*/
pageActions: PropTypes__default["default"].node
};
/**
* ----------------
* PageHeaderContentPageActions
* ----------------
*/
const PageHeaderContentPageActions = ({
className,
children,
menuButtonLabel = 'Actions',
actions,
...other
}) => {
const prefix = usePrefix.usePrefix();
const classNames = cx__default["default"]({
[`${prefix}--page-header__content__page-actions`]: true
}, className);
const containerRef = React.useRef(null);
const offsetRef = React.useRef(null);
const [menuButtonVisibility, setMenuButtonVisibility] = React.useState(false);
const [hiddenItems, setHiddenItems] = React.useState([]);
// need to set the grid columns width based on the menu button's width
// to avoid overlapping when resizing
React.useLayoutEffect(() => {
if (menuButtonVisibility && offsetRef.current) {
const width = offsetRef.current.offsetWidth;
document.documentElement.style.setProperty('--pageheader-title-grid-width', `${width}px`);
}
}, [menuButtonVisibility]);
React.useEffect(() => {
if (!containerRef.current || !Array.isArray(actions)) return;
utilities.createOverflowHandler({
container: containerRef.current,
// exclude the hidden menu button from children
maxVisibleItems: containerRef.current.children.length - 1,
onChange: (visible, hidden) => {
setHiddenItems(actions?.slice(visible.length));
if (hidden.length > 0) {
setMenuButtonVisibility(true);
}
}
});
}, []);
return /*#__PURE__*/React__default["default"].createElement("div", _rollupPluginBabelHelpers["extends"]({
className: classNames,
ref: containerRef
}, other), actions && /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, Array.isArray(actions) && /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, actions.map(action => /*#__PURE__*/React__default["default"].createElement("div", {
key: action.id
}, /*#__PURE__*/React__default["default"].cloneElement(action.body, {
...action.body.props,
onClick: action.onClick
}))), /*#__PURE__*/React__default["default"].createElement("span", {
"data-offset": true,
"data-hidden": true,
ref: offsetRef
}, /*#__PURE__*/React__default["default"].createElement(index.MenuButton, {
menuAlignment: "bottom-end",
label: menuButtonLabel,
size: "md"
}, [...hiddenItems].reverse().map(item => /*#__PURE__*/React__default["default"].createElement(MenuItem.MenuItem, _rollupPluginBabelHelpers["extends"]({
key: item.id,
onClick: item.onClick
}, item.menuItem))))))));
};
PageHeaderContentPageActions.displayName = 'PageHeaderContentPageActions';
PageHeaderContentPageActions.propTypes = {
/**
* Provide child elements to be rendered inside PageHeaderContentPageActions.
*/
children: PropTypes__default["default"].node,
/**
* Specify an optional className to be added to your PageHeaderContentPageActions
*/
className: PropTypes__default["default"].string,
/**
* The PageHeaderContent's collapsible Menu button label
*/
menuButtonLabel: PropTypes__default["default"].string,
/**
* The PageHeaderContent's page actions
*/
actions: PropTypes__default["default"].oneOfType([PropTypes__default["default"].node, PropTypes__default["default"].array])
};
/**
* ----------------
* PageHeaderContentText
* ----------------
*/
const PageHeaderContentText = ({
className,
children,
subtitle,
...other
}) => {
const prefix = usePrefix.usePrefix();
const classNames = cx__default["default"]({
[`${prefix}--page-header__content__body`]: true
}, className);
return /*#__PURE__*/React__default["default"].createElement("div", _rollupPluginBabelHelpers["extends"]({
className: classNames
}, other), subtitle && /*#__PURE__*/React__default["default"].createElement(Text.Text, {
as: "h3",
className: `${prefix}--page-header__content__subtitle`
}, subtitle), children);
};
PageHeaderContentText.displayName = 'PageHeaderContentText';
PageHeaderContentText.propTypes = {
/**
* Provide child elements to be rendered inside PageHeaderContentText.
*/
children: PropTypes__default["default"].node,
/**
* Specify an optional className to be added to your PageHeaderContentText
*/
className: PropTypes__default["default"].string,
/**
* The PageHeaderContent's subtitle
*/
subtitle: PropTypes__default["default"].string
};
/**
* ----------------
* PageHeaderHeroImage
* ----------------
*/
const PageHeaderHeroImage = ({
className,
children,
...other
}) => {
const prefix = usePrefix.usePrefix();
const classNames = cx__default["default"]({
[`${prefix}--page-header__hero-image`]: true
}, className);
const lgMediaQuery = `(min-width: ${layout.breakpoints.lg.width})`;
const isLg = useMatchMedia.useMatchMedia(lgMediaQuery);
return /*#__PURE__*/React__default["default"].createElement(AspectRatio["default"], _rollupPluginBabelHelpers["extends"]({
className: classNames
}, other, {
ratio: isLg ? '2x1' : '3x2'
}), children);
};
PageHeaderHeroImage.displayName = 'PageHeaderHeroImage';
PageHeaderHeroImage.propTypes = {
/**
* Provide child elements to be rendered inside PageHeaderHeroImage.
*/
children: PropTypes__default["default"].node,
/**
* Specify an optional className to be added to your PageHeaderHeroImage
*/
className: PropTypes__default["default"].string
};
/**
* ----------------
* PageHeaderTabBar
* ----------------
*/
const PageHeaderTabBar = /*#__PURE__*/React__default["default"].forwardRef(function PageHeaderTabBar({
className,
children,
tags = [],
...other
}, ref) {
const prefix = usePrefix.usePrefix();
const classNames = cx__default["default"]({
[`${prefix}--page-header__tab-bar`]: true
}, className);
// Early return if no tags are provided
if (!tags.length) {
return /*#__PURE__*/React__default["default"].createElement("div", _rollupPluginBabelHelpers["extends"]({
className: classNames,
ref: ref
}, other), /*#__PURE__*/React__default["default"].createElement(Grid.Grid, null, /*#__PURE__*/React__default["default"].createElement(Column["default"], {
lg: 16,
md: 8,
sm: 4
}, children)));
}
const [openPopover, setOpenPopover] = React.useState(false);
const tagSize = tags[0]?.size || 'md';
const instanceId = useId.useId('PageHeaderTabBar');
const tagsWithIds = React.useMemo(() => {
return tags.map((tag, index) => ({
...tag,
id: tag.id || `tag-${index}-${instanceId}`
}));
}, [tags]);
const tagsContainerRef = React.useRef(null);
const offsetRef = React.useRef(null);
// To close popover when window resizes
React.useEffect(() => {
const handleResize = () => {
// Close the popover when window resizes to prevent unwanted opens
setOpenPopover(false);
};
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
// overflow items hook
const {
visibleItems = [],
hiddenItems = [],
itemRefHandler = () => {}
} = useOverflowItems["default"](tagsWithIds, tagsContainerRef, offsetRef) || {
visibleItems: [],
hiddenItems: [],
itemRefHandler: () => {}
};
const handleOverflowClick = React.useCallback(event => {
event.stopPropagation();
setOpenPopover(prev => !prev);
}, []);
// Function to render tags
const renderTags = () => /*#__PURE__*/React__default["default"].createElement("div", {
className: `${prefix}--page-header__tags`,
ref: tagsContainerRef
}, visibleItems.map(tag => /*#__PURE__*/React__default["default"].createElement(Tag["default"], {
key: tag.id,
ref: node => itemRefHandler(tag.id, node),
type: tag.type,
size: tag.size,
className: `${prefix}--page-header__tag-item`
}, tag.text)), hiddenItems.length > 0 && /*#__PURE__*/React__default["default"].createElement(index$1.Popover, {
open: openPopover,
onRequestClose: () => setOpenPopover(false)
}, /*#__PURE__*/React__default["default"].createElement(OperationalTag["default"], {
onClick: handleOverflowClick,
"aria-expanded": openPopover,
text: `+${hiddenItems.length}`,
size: tagSize
}), /*#__PURE__*/React__default["default"].createElement(index$1.PopoverContent, {
className: "tag-popover-content"
}, /*#__PURE__*/React__default["default"].createElement("div", {
className: `${prefix}--page-header__tags-popover-list`
}, hiddenItems.map(tag => /*#__PURE__*/React__default["default"].createElement(Tag["default"], {
key: tag.id,
type: tag.type,
size: tag.size
}, tag.text))))));
return /*#__PURE__*/React__default["default"].createElement("div", _rollupPluginBabelHelpers["extends"]({
className: classNames,
ref: ref
}, other), /*#__PURE__*/React__default["default"].createElement(Grid.Grid, null, /*#__PURE__*/React__default["default"].createElement(Column["default"], {
lg: 16,
md: 8,
sm: 4
}, /*#__PURE__*/React__default["default"].createElement("div", {
className: `${prefix}--page-header__tab-bar--tablist`
}, 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';
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;