@ui5/webcomponents-react
Version:
React Wrapper for UI5 Web Components and additional components
185 lines (184 loc) • 8.03 kB
JavaScript
'use client';
import { debounce, Device, useStylesheet, useSyncRef } from '@ui5/webcomponents-react-base';
import { clsx } from 'clsx';
import { cloneElement, forwardRef, isValidElement, useEffect, useMemo, useRef, useState } from 'react';
import { FlexBoxAlignItems } from '../../enums/FlexBoxAlignItems.js';
import { FlexBoxDirection } from '../../enums/FlexBoxDirection.js';
import { FlexBoxJustifyContent } from '../../enums/FlexBoxJustifyContent.js';
import { stopPropagation } from '../../internal/stopPropagation.js';
import { FlexBox } from '../FlexBox/index.js';
import { classNames, styleData } from './ObjectPageTitle.module.css.js';
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
/**
* The `ObjectPageTitle` component is used to serve as title of the `ObjectPage`.
* It can contain Breadcrumbs, Title, Subtitle, Content, KPIs and Actions.
*
* __Note:__ When used inside a custom component, it's essential to pass through all props, as otherwise the component won't function as intended!
*/
const ObjectPageTitle = /*#__PURE__*/forwardRef((props, ref) => {
const {
actionsBar,
breadcrumbs,
children,
header,
subHeader,
navigationBar,
className,
onToggleHeaderContentVisibility,
expandedContent,
snappedContent,
snappedHeader,
snappedSubHeader,
_snappedAvatar,
...rest
} = props;
useStylesheet(styleData, ObjectPageTitle.displayName);
const [componentRef, dynamicPageTitleRef] = useSyncRef(ref);
const [showNavigationInTopArea, setShowNavigationInTopArea] = useState(undefined);
const isMounted = useRef(false);
const [isPhone, setIsPhone] = useState(false);
const containerClasses = clsx(classNames.container, isPhone && classNames.phone, className);
const toolbarContainerRef = useRef(null);
const _header = !props?.['data-header-content-visible'] && snappedHeader ? snappedHeader : header;
const _subHeader = !props?.['data-header-content-visible'] && snappedSubHeader ? snappedSubHeader : subHeader;
useEffect(() => {
isMounted.current = true;
return () => {
isMounted.current = false;
};
}, [isMounted]);
const onHeaderClick = e => {
if (typeof onToggleHeaderContentVisibility === 'function') {
onToggleHeaderContentVisibility(e);
}
};
useEffect(() => {
const debouncedObserverFn = debounce(([titleContainer]) => {
// Firefox implements `borderBoxSize` as a single content rect, rather than an array
const borderBoxSize = Array.isArray(titleContainer.borderBoxSize) ? titleContainer.borderBoxSize[0] : titleContainer.borderBoxSize;
// Safari doesn't implement `borderBoxSize`
const titleContainerWidth = borderBoxSize?.inlineSize ?? titleContainer.target.getBoundingClientRect().width;
setIsPhone(Device.getCurrentRange(titleContainerWidth)?.name === 'Phone');
if (titleContainerWidth < 1280 && !showNavigationInTopArea === true && isMounted.current) {
setShowNavigationInTopArea(true);
} else if (titleContainerWidth >= 1280 && !showNavigationInTopArea === false && isMounted.current) {
setShowNavigationInTopArea(false);
}
}, 150);
const observer = new ResizeObserver(debouncedObserverFn);
if (dynamicPageTitleRef.current) {
observer.observe(dynamicPageTitleRef.current);
}
return () => {
debouncedObserverFn.cancel();
observer.disconnect();
};
}, [dynamicPageTitleRef, showNavigationInTopArea, isMounted]);
const wcrNavToolbar = useMemo(() => {
//@ts-expect-error: private identifier
if (/*#__PURE__*/isValidElement(navigationBar) && navigationBar?.type?._displayName === 'UI5WCRToolbar') {
return /*#__PURE__*/cloneElement(navigationBar, {
numberOfAlwaysVisibleItems: Infinity
});
}
return null;
}, [navigationBar]);
useEffect(() => {
const toolbarContainer = toolbarContainerRef.current;
const updateNavigationToolbar = container => {
if (container.children.length >= 2) {
const lastChild = container.lastElementChild;
if (lastChild && lastChild.matches('[ui5-toolbar]')) {
Array.from(lastChild.children).forEach(item => {
item.setAttribute('overflow-priority', 'NeverOverflow');
});
}
}
};
const observer = new MutationObserver(([toolbarContainerMutation]) => {
if (toolbarContainerMutation.type === 'childList') {
updateNavigationToolbar(toolbarContainerMutation.target);
}
});
const config = {
childList: true,
subtree: true
};
if (toolbarContainer) {
updateNavigationToolbar(toolbarContainer);
observer.observe(toolbarContainer, config);
}
return () => {
observer.disconnect();
};
}, []);
return /*#__PURE__*/_jsxs(FlexBox, {
className: containerClasses,
ref: componentRef,
"data-component-name": "ObjectPageTitle",
direction: FlexBoxDirection.Column,
justifyContent: FlexBoxJustifyContent.SpaceBetween,
...rest,
children: [/*#__PURE__*/_jsx("span", {
className: classNames.clickArea,
onClick: onHeaderClick,
"data-component-name": "ObjectPageTitleClickElement"
}), (breadcrumbs || navigationBar && showNavigationInTopArea) && /*#__PURE__*/_jsxs(FlexBox, {
justifyContent: FlexBoxJustifyContent.SpaceBetween,
"data-component-name": "ObjectPageTitleBreadcrumbs",
children: [breadcrumbs && /*#__PURE__*/_jsx("div", {
className: classNames.breadcrumbs,
onClick: stopPropagation,
children: breadcrumbs
}), showNavigationInTopArea && navigationBar && /*#__PURE__*/_jsx("div", {
className: classNames.toolbar,
children: navigationBar
})]
}), /*#__PURE__*/_jsxs(FlexBox, {
alignItems: FlexBoxAlignItems.End,
children: [/*#__PURE__*/_jsx("div", {
className: classNames.snappedAvatarContainer,
children: _snappedAvatar
}), /*#__PURE__*/_jsx(FlexBox, {
direction: FlexBoxDirection.Column,
className: classNames.contentContainer,
children: /*#__PURE__*/_jsxs(FlexBox, {
alignItems: FlexBoxAlignItems.Center,
className: classNames.middleSection,
"data-component-name": "ObjectPageTitleMiddleSection",
children: [/*#__PURE__*/_jsxs(FlexBox, {
direction: FlexBoxDirection.Column,
className: classNames.titleAndSubHeader,
children: [/*#__PURE__*/_jsxs(FlexBox, {
className: classNames.titleMainSection,
onClick: onHeaderClick,
children: [_header && /*#__PURE__*/_jsx("div", {
className: classNames.title,
"data-component-name": "ObjectPageTitleHeader",
children: _header
}), children && /*#__PURE__*/_jsx("div", {
className: classNames.content,
"data-component-name": "ObjectPageTitleContent",
children: children
})]
}), _subHeader && /*#__PURE__*/_jsx("div", {
className: clsx(classNames.subTitle, classNames.subTitleBottom),
"data-component-name": "ObjectPageTitleSubHeader",
children: _subHeader
})]
}), (actionsBar || !showNavigationInTopArea && navigationBar) && /*#__PURE__*/_jsxs("div", {
className: classNames.toolbar,
ref: toolbarContainerRef,
children: [actionsBar, !showNavigationInTopArea && actionsBar && navigationBar && /*#__PURE__*/_jsx("div", {
className: classNames.actionsSeparator,
"data-component-name": "ObjectPageTitleActionsSeparator",
"aria-hidden": "true"
}), !showNavigationInTopArea && (wcrNavToolbar ? wcrNavToolbar : navigationBar)]
})]
})
})]
}), props?.['data-header-content-visible'] ? expandedContent : snappedContent]
});
});
ObjectPageTitle.displayName = 'ObjectPageTitle';
export { ObjectPageTitle };