@ui5/webcomponents-react
Version:
React Wrapper for UI5 Web Components and additional components
674 lines (667 loc) • 28 kB
JavaScript
'use client';
import AvatarSize from '@ui5/webcomponents/dist/types/AvatarSize.js';
import { debounce, enrichEventWithDetails, ThemingParameters, useStylesheet, useSyncRef } from '@ui5/webcomponents-react-base';
import { clsx } from 'clsx';
import { cloneElement, forwardRef, isValidElement, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { ObjectPageMode } from '../../enums/index.js';
import { addCustomCSSWithScoping } from '../../internal/addCustomCSSWithScoping.js';
import { safeGetChildrenArray } from '../../internal/safeGetChildrenArray.js';
import { useObserveHeights } from '../../internal/useObserveHeights.js';
import { Tab, TabContainer } from '../../webComponents/index.js';
import { ObjectPageAnchorBar } from '../ObjectPageAnchorBar/index.js';
import { CollapsedAvatar } from './CollapsedAvatar.js';
import { classNames, styleData } from './ObjectPage.module.css.js';
import { extractSectionIdFromHtmlId, getSectionById } from './ObjectPageUtils.js';
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
addCustomCSSWithScoping('ui5-tabcontainer',
// todo: the additional text span adds 3px to the container - needs to be investigated why
`
:host([data-component-name="ObjectPageTabContainer"]) [id$="additionalText"] {
display: none;
}
`);
const ObjectPageCssVariables = {
headerDisplay: '--_ui5wcr_ObjectPage_header_display',
titleFontSize: '--_ui5wcr_ObjectPage_title_fontsize'
};
const TAB_CONTAINER_HEADER_HEIGHT = 48;
/**
* A component that allows apps to easily display information related to a business object.
*
* The `ObjectPage` is composed of a header (title and content) and block content wrapped in sections and subsections that structure the information.
*/
const ObjectPage = /*#__PURE__*/forwardRef((props, ref) => {
const {
titleArea,
image,
footerArea,
mode = ObjectPageMode.Default,
imageShapeCircle,
className,
style,
slot,
children,
selectedSectionId,
headerPinned: headerPinnedProp,
headerArea,
hidePinButton,
preserveHeaderStateOnClick,
accessibilityAttributes,
placeholder,
onSelectedSectionChange,
onToggleHeaderArea,
onPinButtonToggle,
onBeforeNavigate,
...rest
} = props;
useStylesheet(styleData, ObjectPage.displayName);
const firstSectionId = safeGetChildrenArray(children)[0]?.props?.id;
const [internalSelectedSectionId, setInternalSelectedSectionId] = useState(selectedSectionId ?? firstSectionId);
const [selectedSubSectionId, setSelectedSubSectionId] = useState(props.selectedSubSectionId);
const [headerPinned, setHeaderPinned] = useState(headerPinnedProp);
const isProgrammaticallyScrolled = useRef(false);
const prevSelectedSectionId = useRef(undefined);
const [componentRef, objectPageRef] = useSyncRef(ref);
const topHeaderRef = useRef(null);
const scrollEvent = useRef(undefined);
const prevTopHeaderHeight = useRef(0);
// @ts-expect-error: useSyncRef will create a ref if not present
const [componentRefHeaderContent, headerContentRef] = useSyncRef(headerArea?.ref);
const anchorBarRef = useRef(null);
const objectPageContentRef = useRef(null);
const selectionScrollTimeout = useRef(null);
const [isAfterScroll, setIsAfterScroll] = useState(false);
const isToggledRef = useRef(false);
const [headerCollapsedInternal, setHeaderCollapsedInternal] = useState(undefined);
const [scrolledHeaderExpanded, setScrolledHeaderExpanded] = useState(false);
const scrollTimeout = useRef(0);
const [sectionSpacer, setSectionSpacer] = useState(0);
const [currentTabModeSection, setCurrentTabModeSection] = useState(null);
const sections = mode === ObjectPageMode.IconTabBar ? currentTabModeSection : children;
useEffect(() => {
const currentSection = mode === ObjectPageMode.IconTabBar ? getSectionById(children, internalSelectedSectionId) : null;
setCurrentTabModeSection(currentSection);
}, [mode, children, internalSelectedSectionId]);
const prevInternalSelectedSectionId = useRef(internalSelectedSectionId);
const fireOnSelectedChangedEvent = (targetEvent, index, id, section) => {
if (typeof onSelectedSectionChange === 'function' && prevInternalSelectedSectionId.current !== id) {
onSelectedSectionChange(enrichEventWithDetails(targetEvent, {
selectedSectionIndex: parseInt(index, 10),
selectedSectionId: id,
section
}));
prevInternalSelectedSectionId.current = id;
}
};
const debouncedOnSectionChange = useRef(debounce(fireOnSelectedChangedEvent, 500)).current;
useEffect(() => {
return () => {
debouncedOnSectionChange.cancel();
clearTimeout(selectionScrollTimeout.current);
};
}, []);
// observe heights of header parts
const {
topHeaderHeight,
headerContentHeight,
anchorBarHeight,
totalHeaderHeight,
headerCollapsed
} = useObserveHeights(objectPageRef, topHeaderRef, headerContentRef, anchorBarRef, [headerCollapsedInternal, setHeaderCollapsedInternal], {
noHeader: !titleArea && !headerArea,
fixedHeader: headerPinned,
scrollTimeout
});
useEffect(() => {
if (typeof onToggleHeaderArea === 'function' && isToggledRef.current) {
onToggleHeaderArea(headerCollapsed !== true);
}
}, [headerCollapsed]);
useEffect(() => {
const objectPageNode = objectPageRef.current;
if (objectPageNode) {
Object.assign(objectPageNode, {
toggleHeaderArea(snapped) {
if (typeof snapped === 'boolean') {
onToggleHeaderContentVisibility({
detail: {
visible: !snapped
}
});
} else {
onToggleHeaderContentVisibility({
detail: {
visible: !!headerCollapsed
}
});
}
}
});
}
}, [headerCollapsed]);
const avatar = useMemo(() => {
if (!image) {
return null;
}
if (typeof image === 'string') {
return /*#__PURE__*/_jsx("span", {
className: classNames.headerImage,
style: {
borderRadius: imageShapeCircle ? '50%' : 0,
overflow: 'hidden'
},
children: /*#__PURE__*/_jsx("img", {
src: image,
className: classNames.image,
alt: "Company Logo"
})
});
} else {
return /*#__PURE__*/cloneElement(image, {
size: AvatarSize.L,
className: clsx(classNames.headerImage, image.props?.className)
});
}
}, [image, classNames.headerImage, classNames.image, imageShapeCircle]);
const scrollToSectionById = (id, isSubSection = false) => {
const section = objectPageRef.current?.querySelector(`#${isSubSection ? 'ObjectPageSubSection' : 'ObjectPageSection'}-${CSS.escape(id)}`);
scrollTimeout.current = performance.now() + 500;
if (section) {
const safeTopHeaderHeight = topHeaderHeight || prevTopHeaderHeight.current;
section.style.scrollMarginBlockStart = safeTopHeaderHeight + anchorBarHeight + TAB_CONTAINER_HEADER_HEIGHT + (headerPinned ? headerContentHeight : 0) + 'px';
section.focus();
section.scrollIntoView({
behavior: 'smooth'
});
section.style.scrollMarginBlockStart = '0px';
}
};
const scrollToSection = sectionId => {
if (!sectionId) {
return;
}
if (firstSectionId === sectionId) {
objectPageRef.current?.scrollTo({
top: 0,
behavior: 'smooth'
});
} else {
scrollToSectionById(sectionId);
}
isProgrammaticallyScrolled.current = false;
};
const programmaticallySetSection = () => {
const currentId = selectedSectionId ?? firstSectionId;
if (currentId !== prevSelectedSectionId.current) {
debouncedOnSectionChange.cancel();
isProgrammaticallyScrolled.current = true;
setInternalSelectedSectionId(currentId);
prevSelectedSectionId.current = currentId;
const sectionNodes = objectPageRef.current?.querySelectorAll('section[data-component-name="ObjectPageSection"]');
const currentIndex = safeGetChildrenArray(children).findIndex(objectPageSection => {
return /*#__PURE__*/isValidElement(objectPageSection) && objectPageSection.props?.id === currentId;
});
fireOnSelectedChangedEvent({}, currentIndex, currentId, sectionNodes[0]);
}
};
// change selected section when prop is changed (external change)
const [timeStamp, setTimeStamp] = useState(0);
const requestAnimationFrameRef = useRef(undefined);
useEffect(() => {
if (selectedSectionId) {
if (mode === ObjectPageMode.Default) {
// wait for DOM draw, otherwise initial scroll won't work as intended
if (timeStamp < 750 && timeStamp !== undefined) {
requestAnimationFrameRef.current = requestAnimationFrame(internalTimestamp => {
setTimeStamp(internalTimestamp);
});
} else {
setTimeStamp(undefined);
programmaticallySetSection();
}
} else {
programmaticallySetSection();
}
}
return () => {
cancelAnimationFrame(requestAnimationFrameRef.current);
};
}, [timeStamp, selectedSectionId, firstSectionId, debouncedOnSectionChange]);
// section was selected by clicking on the tab bar buttons
const handleOnSectionSelected = (targetEvent, newSelectionSectionId, index, section) => {
isProgrammaticallyScrolled.current = true;
debouncedOnSectionChange.cancel();
setInternalSelectedSectionId(prevSelectedSection => {
if (prevSelectedSection === newSelectionSectionId) {
scrollToSection(newSelectionSectionId);
}
return newSelectionSectionId;
});
scrollEvent.current = targetEvent;
fireOnSelectedChangedEvent(targetEvent, index, newSelectionSectionId, section);
};
// do internal scrolling
useEffect(() => {
if (mode === ObjectPageMode.Default && isProgrammaticallyScrolled.current === true && !selectedSubSectionId) {
scrollToSection(internalSelectedSectionId);
}
}, [internalSelectedSectionId, mode, isProgrammaticallyScrolled, scrollToSection, selectedSubSectionId]);
// Scrolling for Sub Section Selection
useEffect(() => {
if (selectedSubSectionId && isProgrammaticallyScrolled.current === true && sectionSpacer) {
scrollToSectionById(selectedSubSectionId, true);
isProgrammaticallyScrolled.current = false;
}
}, [selectedSubSectionId, isProgrammaticallyScrolled.current, sectionSpacer]);
useEffect(() => {
if (headerPinnedProp !== undefined) {
setHeaderPinned(headerPinnedProp);
}
if (headerPinnedProp) {
onToggleHeaderContentVisibility({
detail: {
visible: true
}
});
}
}, [headerPinnedProp]);
const prevHeaderPinned = useRef(headerPinned);
useEffect(() => {
if (prevHeaderPinned.current && !headerPinned && objectPageRef.current.scrollTop > topHeaderHeight) {
onToggleHeaderContentVisibility({
detail: {
visible: false
}
});
prevHeaderPinned.current = false;
}
if (!prevHeaderPinned.current && headerPinned) {
prevHeaderPinned.current = true;
}
}, [headerPinned, topHeaderHeight]);
useEffect(() => {
setSelectedSubSectionId(props.selectedSubSectionId);
if (props.selectedSubSectionId) {
isProgrammaticallyScrolled.current = true;
if (mode === ObjectPageMode.IconTabBar) {
let sectionId;
safeGetChildrenArray(children).forEach(section => {
if ( /*#__PURE__*/isValidElement(section) && section.props && section.props.children) {
safeGetChildrenArray(section.props.children).forEach(subSection => {
if ( /*#__PURE__*/isValidElement(subSection) && subSection.props && subSection.props.id === props.selectedSubSectionId) {
sectionId = section.props?.id;
}
});
}
});
if (sectionId) {
setInternalSelectedSectionId(sectionId);
}
}
}
}, [props.selectedSubSectionId, children, mode]);
const tabContainerContainerRef = useRef(null);
useEffect(() => {
const objectPage = objectPageRef.current;
const sectionNodes = objectPage.querySelectorAll('[id^="ObjectPageSection"]');
const lastSectionNode = sectionNodes[sectionNodes.length - 1];
const tabContainerContainer = tabContainerContainerRef.current;
const observer = new ResizeObserver(([sectionElement]) => {
const subSections = lastSectionNode.querySelectorAll('[id^="ObjectPageSubSection"]');
const lastSubSection = subSections[subSections.length - 1];
const lastSubSectionOrSection = lastSubSection ?? sectionElement.target;
if (currentTabModeSection && !lastSubSection || sectionNodes.length === 1 && !lastSubSection) {
setSectionSpacer(0);
} else if (!!tabContainerContainer) {
setSectionSpacer(objectPage.getBoundingClientRect().bottom - tabContainerContainer.getBoundingClientRect().bottom - lastSubSectionOrSection.getBoundingClientRect().height - TAB_CONTAINER_HEADER_HEIGHT);
}
});
if (objectPage && lastSectionNode) {
observer.observe(lastSectionNode, {
box: 'border-box'
});
}
return () => {
observer.disconnect();
};
}, [headerCollapsed, topHeaderHeight, headerContentHeight, currentTabModeSection, children]);
const onToggleHeaderContentVisibility = useCallback(e => {
isToggledRef.current = true;
scrollTimeout.current = performance.now() + 500;
if (!e.detail.visible) {
setHeaderCollapsedInternal(true);
objectPageRef.current?.classList.add(classNames.headerCollapsed);
} else {
setHeaderCollapsedInternal(false);
setScrolledHeaderExpanded(true);
objectPageRef.current?.classList.remove(classNames.headerCollapsed);
}
}, []);
const handleOnSubSectionSelected = useCallback(e => {
isProgrammaticallyScrolled.current = true;
if (mode === ObjectPageMode.IconTabBar) {
const sectionId = e.detail.sectionId;
setInternalSelectedSectionId(sectionId);
const sectionNodes = objectPageRef.current?.querySelectorAll('section[data-component-name="ObjectPageSection"]');
const currentIndex = safeGetChildrenArray(children).findIndex(objectPageSection => {
return /*#__PURE__*/isValidElement(objectPageSection) && objectPageSection.props?.id === sectionId;
});
debouncedOnSectionChange(e, currentIndex, sectionId, sectionNodes[currentIndex]);
}
const subSectionId = e.detail.subSectionId;
scrollTimeout.current = performance.now() + 200;
setSelectedSubSectionId(subSectionId);
}, [mode, setInternalSelectedSectionId, setSelectedSubSectionId, isProgrammaticallyScrolled, children]);
const objectPageClasses = clsx(classNames.objectPage, className, mode === ObjectPageMode.IconTabBar && classNames.iconTabBarMode);
const {
onScroll: _0,
selectedSubSectionId: _1,
...propsWithoutOmitted
} = rest;
useEffect(() => {
const sectionNodes = objectPageRef.current?.querySelectorAll('section[data-component-name="ObjectPageSection"]');
const objectPageHeight = objectPageRef.current?.clientHeight ?? 1000;
const marginBottom = objectPageHeight - totalHeaderHeight - /*TabContainer*/TAB_CONTAINER_HEADER_HEIGHT;
const rootMargin = `-${totalHeaderHeight}px 0px -${marginBottom < 0 ? 0 : marginBottom}px 0px`;
const observer = new IntersectionObserver(([section]) => {
if (section.isIntersecting && isProgrammaticallyScrolled.current === false) {
if (objectPageRef.current.getBoundingClientRect().top + totalHeaderHeight + TAB_CONTAINER_HEADER_HEIGHT <= section.target.getBoundingClientRect().bottom) {
const currentId = extractSectionIdFromHtmlId(section.target.id);
setInternalSelectedSectionId(currentId);
const currentIndex = safeGetChildrenArray(children).findIndex(objectPageSection => {
return /*#__PURE__*/isValidElement(objectPageSection) && objectPageSection.props?.id === currentId;
});
debouncedOnSectionChange(scrollEvent.current, currentIndex, currentId, section.target);
}
}
}, {
root: objectPageRef.current,
rootMargin,
threshold: [0]
});
sectionNodes.forEach(el => {
observer.observe(el);
});
return () => {
observer.disconnect();
};
}, [children, totalHeaderHeight, setInternalSelectedSectionId, isProgrammaticallyScrolled]);
// Fallback when scrolling faster than the IntersectionObserver can observe (in most cases faster than 60fps)
useEffect(() => {
const sectionNodes = objectPageRef.current?.querySelectorAll('section[data-component-name="ObjectPageSection"]');
if (isAfterScroll) {
let currentSection = sectionNodes[sectionNodes.length - 1];
let currentIndex;
for (let i = 0; i <= sectionNodes.length - 1; i++) {
const sectionNode = sectionNodes[i];
if (objectPageRef.current.getBoundingClientRect().top + totalHeaderHeight + TAB_CONTAINER_HEADER_HEIGHT <= sectionNode.getBoundingClientRect().bottom) {
currentSection = sectionNode;
currentIndex = i;
break;
}
}
const currentSectionId = extractSectionIdFromHtmlId(currentSection?.id);
if (currentSectionId !== internalSelectedSectionId) {
setInternalSelectedSectionId(currentSectionId);
debouncedOnSectionChange(scrollEvent.current, currentIndex ?? sectionNodes.length - 1, currentSectionId, currentSection);
}
setIsAfterScroll(false);
}
}, [isAfterScroll]);
const onTitleClick = e => {
e.stopPropagation();
if (!preserveHeaderStateOnClick) {
onToggleHeaderContentVisibility(enrichEventWithDetails(e, {
visible: headerCollapsed
}));
}
};
const snappedHeaderInObjPage = titleArea && titleArea.props.snappedContent && headerCollapsed === true && !!image;
const isInitial = useRef(true);
useEffect(() => {
if (!isInitial.current) {
scrollTimeout.current = performance.now() + 200;
} else {
isInitial.current = false;
}
}, [snappedHeaderInObjPage]);
const renderHeaderContentSection = () => {
if (headerArea?.props) {
return /*#__PURE__*/cloneElement(headerArea, {
...headerArea.props,
topHeaderHeight,
style: headerCollapsed === true ? {
position: 'absolute',
visibility: 'hidden',
flexShrink: 0
} : {
...headerArea.props.style,
flexShrink: 0
},
headerPinned: headerPinned || scrolledHeaderExpanded,
//@ts-expect-error: todo remove me when forwardref has been replaced
ref: componentRefHeaderContent,
children: /*#__PURE__*/_jsxs("div", {
className: classNames.headerContainer,
"data-component-name": "ObjectPageHeaderContainer",
children: [avatar, headerArea.props.children && /*#__PURE__*/_jsx("div", {
"data-component-name": "ObjectPageHeaderContent",
children: headerArea.props.children
})]
})
});
}
};
const onTabItemSelect = event => {
if (typeof onBeforeNavigate === 'function') {
const selectedTabDataset = event.detail.tab.dataset;
const sectionIndex = parseInt(selectedTabDataset.index, 10);
const sectionId = selectedTabDataset.parentId ?? selectedTabDataset.sectionId;
const subSectionId = selectedTabDataset.hasOwnProperty('isSubTab') ? selectedTabDataset.sectionId : undefined;
onBeforeNavigate(enrichEventWithDetails(event, {
sectionIndex,
sectionId,
subSectionId
}));
if (event.defaultPrevented) {
return;
}
}
event.preventDefault();
const {
sectionId,
index,
isSubTab,
parentId
} = event.detail.tab.dataset;
if (isSubTab !== undefined) {
handleOnSubSectionSelected(enrichEventWithDetails(event, {
sectionId: parentId,
subSectionId: sectionId
}));
} else {
const section = safeGetChildrenArray(children).find(el => {
return el.props.id == sectionId;
});
handleOnSectionSelected(event, section?.props?.id, index, section);
}
};
const prevScrollTop = useRef(undefined);
const onObjectPageScroll = useCallback(e => {
if (!isToggledRef.current) {
isToggledRef.current = true;
}
if (scrollTimeout.current >= performance.now()) {
return;
}
scrollEvent.current = e;
if (typeof props.onScroll === 'function') {
props.onScroll(e);
}
if (selectedSubSectionId) {
setSelectedSubSectionId(undefined);
}
if (selectionScrollTimeout.current) {
clearTimeout(selectionScrollTimeout.current);
}
selectionScrollTimeout.current = setTimeout(() => {
setIsAfterScroll(true);
}, 100);
if (!headerPinned || e.target.scrollTop === 0) {
objectPageRef.current?.classList.remove(classNames.headerCollapsed);
}
if (scrolledHeaderExpanded && e.target.scrollTop !== prevScrollTop.current) {
if (e.target.scrollHeight - e.target.scrollTop === e.target.clientHeight) {
return;
}
prevScrollTop.current = e.target.scrollTop;
if (!headerPinned) {
setHeaderCollapsedInternal(true);
}
setScrolledHeaderExpanded(false);
}
}, [topHeaderHeight, headerPinned, props.onScroll, scrolledHeaderExpanded, selectedSubSectionId]);
const onHoverToggleButton = useCallback(e => {
if (e?.type === 'mouseover') {
topHeaderRef.current?.classList.add(classNames.headerHoverStyles);
} else {
topHeaderRef.current?.classList.remove(classNames.headerHoverStyles);
}
}, [classNames.headerHoverStyles]);
const objectPageStyles = {
...style
};
if (headerCollapsed === true && headerArea) {
objectPageStyles[ObjectPageCssVariables.titleFontSize] = ThemingParameters.sapObjectHeader_Title_SnappedFontSize;
}
return /*#__PURE__*/_jsxs("div", {
"data-component-name": "ObjectPage",
slot: slot,
className: objectPageClasses,
style: objectPageStyles,
ref: componentRef,
onScroll: onObjectPageScroll,
...propsWithoutOmitted,
children: [/*#__PURE__*/_jsxs("header", {
onMouseOver: onHoverToggleButton,
onMouseLeave: onHoverToggleButton,
"data-component-name": "ObjectPageTopHeader",
ref: topHeaderRef,
role: accessibilityAttributes?.objectPageTopHeader?.role,
"data-not-clickable": !!preserveHeaderStateOnClick,
"aria-roledescription": accessibilityAttributes?.objectPageTopHeader?.ariaRoledescription ?? 'Object Page header',
className: classNames.header,
style: {
gridAutoColumns: `min-content ${titleArea && image && headerCollapsed === true ? `calc(100% - 3rem - 1rem)` : '100%'}`
},
children: [/*#__PURE__*/_jsx("span", {
className: classNames.clickArea,
onClick: onTitleClick,
"data-component-name": "ObjectPageTitleAreaClickElement"
}), titleArea && image && headerCollapsed === true && /*#__PURE__*/_jsx(CollapsedAvatar, {
image: image,
imageShapeCircle: imageShapeCircle
}), titleArea && /*#__PURE__*/cloneElement(titleArea, {
className: clsx(titleArea?.props?.className),
onToggleHeaderContentVisibility: onTitleClick,
'data-not-clickable': !!preserveHeaderStateOnClick,
'data-header-content-visible': headerArea && headerCollapsed !== true,
'data-is-snapped-rendered-outside': snappedHeaderInObjPage
}), snappedHeaderInObjPage && /*#__PURE__*/_jsx("div", {
className: classNames.snappedContent,
"data-component-name": "ATwithImageSnappedContentContainer",
children: titleArea.props.snappedContent
})]
}), renderHeaderContentSection(), headerArea && titleArea && /*#__PURE__*/_jsx("div", {
"data-component-name": "ObjectPageAnchorBar",
ref: anchorBarRef,
className: classNames.anchorBar,
style: {
top: scrolledHeaderExpanded || headerPinned ? `${topHeaderHeight + (headerCollapsed === true ? 0 : headerContentHeight)}px` : `${topHeaderHeight + 5}px`
},
children: /*#__PURE__*/_jsx(ObjectPageAnchorBar, {
headerContentVisible: headerArea && headerCollapsed !== true,
hidePinButton: !!hidePinButton,
headerPinned: headerPinned,
accessibilityAttributes: accessibilityAttributes,
onToggleHeaderContentVisibility: onToggleHeaderContentVisibility,
setHeaderPinned: setHeaderPinned,
onHoverToggleButton: onHoverToggleButton,
onPinButtonToggle: onPinButtonToggle
})
}), !placeholder && /*#__PURE__*/_jsx("div", {
ref: tabContainerContainerRef,
className: classNames.tabContainer,
"data-component-name": "ObjectPageTabContainer",
style: {
top: headerPinned || scrolledHeaderExpanded ? `${topHeaderHeight + (headerCollapsed === true ? 0 : headerContentHeight)}px` : `${topHeaderHeight}px`
},
children: /*#__PURE__*/_jsx(TabContainer, {
collapsed: true,
onTabSelect: onTabItemSelect,
"data-component-name": "ObjectPageTabContainer",
className: classNames.tabContainerComponent,
children: safeGetChildrenArray(children).map((section, index) => {
if (! /*#__PURE__*/isValidElement(section) || !section.props) return null;
const subTabs = safeGetChildrenArray(section.props.children).filter(subSection =>
// @ts-expect-error: if the `ObjectPageSubSection` component is passed as children, the `displayName` is available. Otherwise, the default children should be rendered w/o additional logic.
/*#__PURE__*/isValidElement(subSection) && subSection?.type?.displayName === 'ObjectPageSubSection');
return /*#__PURE__*/_jsx(Tab, {
"data-index": index,
"data-section-id": section.props.id,
text: section.props.titleText,
selected: internalSelectedSectionId === section.props?.id || undefined,
items: subTabs.map(item => {
if (! /*#__PURE__*/isValidElement(item)) {
return null;
}
return /*#__PURE__*/_jsx(Tab, {
"data-parent-id": section.props.id,
"data-is-sub-tab": true,
"data-section-id": item.props.id,
text: item.props.titleText,
selected: item.props.id === selectedSubSectionId || undefined,
"data-index": index,
children: /*#__PURE__*/_jsx("span", {
style: {
display: 'none'
}
})
}, item.props.id);
}),
children: /*#__PURE__*/_jsx("span", {
style: {
display: 'none'
}
})
}, `Anchor-${section.props?.id}`);
})
})
}), /*#__PURE__*/_jsxs("div", {
"data-component-name": "ObjectPageContent",
className: classNames.content,
ref: objectPageContentRef,
children: [/*#__PURE__*/_jsx("div", {
style: {
height: headerCollapsed ? `${headerContentHeight}px` : 0
},
"aria-hidden": true
}), placeholder ? placeholder : sections, /*#__PURE__*/_jsx("div", {
style: {
height: `${sectionSpacer}px`
},
"aria-hidden": true
})]
}), footerArea && mode === ObjectPageMode.IconTabBar && !sectionSpacer && /*#__PURE__*/_jsx("div", {
className: classNames.footerSpacer,
"data-component-name": "ObjectPageFooterSpacer",
"aria-hidden": true
}), footerArea && /*#__PURE__*/_jsx("footer", {
className: classNames.footer,
"data-component-name": "ObjectPageFooter",
children: footerArea
})]
});
});
ObjectPage.displayName = 'ObjectPage';
export { ObjectPage };