diff --git a/babel.config.js b/babel.config.js
index 7b81d588a5e..0f948fcfecc 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -1,4 +1,4 @@
module.exports = {
presets: ['babel-preset-react-app'],
- plugins: ['@babel/plugin-proposal-nullish-coalescing-operator']
+ plugins: ['@babel/plugin-proposal-nullish-coalescing-operator', '@babel/plugin-proposal-optional-chaining']
};
diff --git a/package.json b/package.json
index 5ceeae99117..43b66a12490 100644
--- a/package.json
+++ b/package.json
@@ -15,6 +15,7 @@
"prettier:all": "prettier --write --config ./prettier.config.js \"packages/**/*.{ts,tsx}\""
},
"dependencies": {
+ "@babel/plugin-proposal-optional-chaining": "^7.7.5",
"@storybook/addon-actions": "5.3.0-beta.31",
"@storybook/addon-docs": "5.3.0-beta.31",
"@storybook/addon-info": "5.3.0-beta.31",
diff --git a/packages/main/src/components/ObjectPage/ObjectPage.jss.ts b/packages/main/src/components/ObjectPage/ObjectPage.jss.ts
index e3144db66ec..b6972168a55 100644
--- a/packages/main/src/components/ObjectPage/ObjectPage.jss.ts
+++ b/packages/main/src/components/ObjectPage/ObjectPage.jss.ts
@@ -1,5 +1,6 @@
import { JSSTheme } from '../../interfaces/JSSTheme';
import { ZIndex } from '../../enums/ZIndex';
+import { CSSProperties } from 'react';
const styles = ({ parameters }: JSSTheme) => ({
objectPage: {
@@ -129,6 +130,7 @@ const styles = ({ parameters }: JSSTheme) => ({
wordBreak: 'break-word',
verticalAlign: 'baseline',
paddingTop: '0.5rem',
+ paddingBottom: '0.5rem',
fontSize: '0.875rem',
color: parameters.sapUiContentLabelColor
},
@@ -148,7 +150,7 @@ const styles = ({ parameters }: JSSTheme) => ({
},
stickied: {},
headerContent: {
- paddingTop: '1.5rem',
+ //paddingTop: '1.5rem',
paddingBottom: '0.25rem',
transition: 'max-height 0.5s',
maxHeight: '500px',
@@ -160,7 +162,7 @@ const styles = ({ parameters }: JSSTheme) => ({
'& $headerContent': {
paddingTop: 0,
'& > *': {
- display: 'inline-block',
+ display: 'flex',
verticalAlign: 'top',
'&:not(:first-child)': {
marginRight: '2rem',
@@ -192,6 +194,10 @@ const styles = ({ parameters }: JSSTheme) => ({
lineHeight: '1.5rem'
}
},
+ headerCustomContentItem: {
+ marginLeft: '1rem'
+ },
+
headerImage: {
maxWidth: '5rem',
maxHeight: '5rem',
@@ -202,6 +208,28 @@ const styles = ({ parameters }: JSSTheme) => ({
image: {
width: '100%',
height: '100%'
+ },
+ keyInfos: {
+ '& > *': {
+ marginLeft: '1rem'
+ },
+ display: 'flex',
+ flexDirection: 'row'
+ },
+ flexBoxRow: {
+ display: 'flex',
+ flexDirection: 'row'
+ },
+ flexBoxColumn: {
+ display: 'flex',
+ flexDirection: 'column'
+ },
+ flexBoxCenter: {
+ display: 'flex',
+ alignItems: 'center'
+ },
+ avatar: {
+ marginRight: '1rem'
}
});
diff --git a/packages/main/src/components/ObjectPage/ObjectPage.test.tsx b/packages/main/src/components/ObjectPage/ObjectPage.test.tsx
index 906846c54d5..435372b3691 100644
--- a/packages/main/src/components/ObjectPage/ObjectPage.test.tsx
+++ b/packages/main/src/components/ObjectPage/ObjectPage.test.tsx
@@ -9,6 +9,9 @@ import { ObjectPageMode } from '@ui5/webcomponents-react/lib/ObjectPageMode';
import { ObjectPageSection } from '@ui5/webcomponents-react/lib/ObjectPageSection';
import { ObjectPageSubSection } from '@ui5/webcomponents-react/lib/ObjectPageSubSection';
import { Text } from '@ui5/webcomponents-react/lib/Text';
+import { Title } from '@ui5/webcomponents-react/lib/Title';
+import { Breadcrumbs } from '@ui5/webcomponents-react/lib/Breadcrumbs';
+import { TitleLevel } from '@ui5/webcomponents-react/lib/TitleLevel';
const renderHeaderContent = () => (
@@ -164,4 +167,39 @@ describe('ObjectPage', () => {
);
expect(wrapper.render()).toMatchSnapshot();
});
+
+ const renderKeyInfos = () => (
+ <>
+
+
Key Info 1
+ Value 1
+
+
+
Key Info 2
+ Value 2
+
+
+
Key Info 3
+ Value 3
+
+ >
+ );
+
+ const renderBreadcrumbs = () => (
+
+ Path1
+ Path2
+
+
+ );
+
+ test('Key Infos', () => {
+ const wrapper = mountThemedComponent(
+
+ Test
+ Test 2
+
+ );
+ expect(wrapper.render()).toMatchSnapshot();
+ });
});
diff --git a/packages/main/src/components/ObjectPage/__snapshots__/ObjectPage.test.tsx.snap b/packages/main/src/components/ObjectPage/__snapshots__/ObjectPage.test.tsx.snap
index 485e7af4b26..e2019f376bd 100644
--- a/packages/main/src/components/ObjectPage/__snapshots__/ObjectPage.test.tsx.snap
+++ b/packages/main/src/components/ObjectPage/__snapshots__/ObjectPage.test.tsx.snap
@@ -38,21 +38,32 @@ exports[`ObjectPage IconTabBar Mode 1`] = `
class="ObjectPage--titleBar-"
>
-
- Fiori Object Page Title
-
-
- Sub Title
-
+
+
+ Fiori Object Page Title
+
+
+ Sub Title
+
+
+
+
@@ -322,20 +333,50 @@ exports[`ObjectPage Just Some Sections 1`] = `
class="ObjectPage--titleBar-"
>
+
+
+
+`;
+
+exports[`ObjectPage Key Infos 1`] = `
+
+
+
+
+
+
+
+
@@ -402,6 +623,28 @@ exports[`ObjectPage Just Some Sections 1`] = `
+
+
-
-
-
-
+
@@ -652,20 +897,48 @@ exports[`ObjectPage Not crashing with 1 section - Default Mode 1`] = `
class="ObjectPage--titleBar-"
>
+
-
+
@@ -771,20 +1018,43 @@ exports[`ObjectPage Not crashing with 1 section - IconTabBar Mode 1`] = `
class="ObjectPage--titleBar-"
>
+
-
-
-
-
+
@@ -892,21 +1141,32 @@ exports[`ObjectPage Only Sections 1`] = `
class="ObjectPage--titleBar-"
>
-
- Fiori Object Page Title
-
-
- Sub Title
-
+
+
+ Fiori Object Page Title
+
+
+ Sub Title
+
+
+
+
@@ -1141,20 +1401,50 @@ exports[`ObjectPage Set selected section id 1`] = `
class="ObjectPage--titleBar-"
>
+
-
-
-
-
+
@@ -1269,21 +1531,32 @@ exports[`ObjectPage With Subsections 1`] = `
class="ObjectPage--titleBar-"
>
-
- Fiori Object Page Title
-
-
- Sub Title
-
+
+
+ Fiori Object Page Title
+
+
+ Sub Title
+
+
+
+
diff --git a/packages/main/src/components/ObjectPage/demo.stories.tsx b/packages/main/src/components/ObjectPage/demo.stories.tsx
index 470a52ffe07..90c8671d765 100644
--- a/packages/main/src/components/ObjectPage/demo.stories.tsx
+++ b/packages/main/src/components/ObjectPage/demo.stories.tsx
@@ -10,9 +10,13 @@ import { ObjectPageMode } from '@ui5/webcomponents-react/lib/ObjectPageMode';
import { ObjectPageSection } from '@ui5/webcomponents-react/lib/ObjectPageSection';
import { ObjectPageSubSection } from '@ui5/webcomponents-react/lib/ObjectPageSubSection';
import { Text } from '@ui5/webcomponents-react/lib/Text';
+import { FlexBox } from '@ui5/webcomponents-react/lib/FlexBox';
+import { Breadcrumbs } from '@ui5/webcomponents-react/lib/Breadcrumbs';
// @ts-ignore
import SampleImage from './DemoImage.png';
import notes from './ObjectPage.md';
+import { Title } from '@ui5/webcomponents-react/lib/Title';
+import { TitleLevel } from '@ui5/webcomponents-react/lib/TitleLevel';
const renderHeaderContent = () => (
<>
@@ -26,6 +30,32 @@ const renderHeaderContent = () => (
>
);
+
+const renderBreadcrumbs = () => (
+
+ Path1
+ Path2
+
+
+);
+
+const renderKeyInfos = () => (
+ <>
+
+
Key Info 1
+ Value 1
+
+
+
Key Info 2
+ Value 2
+
+
+
Key Info 3
+ Value 3
+
+ >
+);
+
export const renderDemo = () => {
return (
@@ -49,8 +79,10 @@ export const renderDemo = () => {
selectedSubSectionId={text('selectedSubSectionId', undefined)}
onSelectedSectionChanged={action('onSelectedSectionChanged')}
noHeader={boolean('noHeader', false)}
- alwaysShowContentHeader={boolean('alwaysShowContentHeader', true)}
+ alwaysShowContentHeader={boolean('alwaysShowContentHeader', false)}
showTitleInHeaderContent={boolean('showTitleInHeaderContent', true)}
+ renderBreadcrumbs={renderBreadcrumbs}
+ renderKeyInfos={renderKeyInfos}
style={{ height: '700px' }}
>
diff --git a/packages/main/src/components/ObjectPage/index.tsx b/packages/main/src/components/ObjectPage/index.tsx
index 87ffe8002a5..f3ea93b72a0 100644
--- a/packages/main/src/components/ObjectPage/index.tsx
+++ b/packages/main/src/components/ObjectPage/index.tsx
@@ -15,7 +15,8 @@ import React, {
useLayoutEffect,
useMemo,
useRef,
- useState
+ useState,
+ CSSProperties
} from 'react';
import { createUseStyles, useTheme } from 'react-jss';
import { CommonProps } from '../../interfaces/CommonProps';
@@ -51,6 +52,8 @@ export interface ObjectPagePropTypes extends CommonProps {
noHeader?: boolean;
showTitleInHeaderContent?: boolean;
scrollerRef?: RefObject;
+ renderBreadcrumbs?: () => JSX.Element;
+ renderKeyInfos?: () => JSX.Element;
}
const useStyles = createUseStyles>(styles, { name: 'ObjectPage' });
@@ -66,13 +69,15 @@ const findSectionIndexById = (sections, id) => {
return index;
};
+const positionRelativStyle: CSSProperties = { position: 'relative' };
+
const ObjectPage: FC = forwardRef((props: ObjectPagePropTypes, ref: RefObject) => {
const {
title,
image,
subTitle,
headerActions,
- renderHeaderContent,
+ renderHeaderContent: renderHeaderContentProp,
mode,
imageShapeCircle,
className,
@@ -86,14 +91,16 @@ const ObjectPage: FC = forwardRef((props: ObjectPagePropTyp
noHeader,
alwaysShowContentHeader,
showTitleInHeaderContent,
- scrollerRef
+ scrollerRef,
+ renderBreadcrumbs,
+ renderKeyInfos
} = props;
const [selectedSectionIndex, setSelectedSectionIndex] = useState(findSectionIndexById(children, selectedSectionId));
const [selectedSubSectionId, setSelectedSubSectionId] = useState(props.selectedSubSectionId);
const [expandHeaderActive, setExpandHeaderActive] = useState(false);
const [isMounted, setIsMounted] = useState(false);
- const [collapsedHeader, setCollapsedHeader] = useState(false);
+ const [collapsedHeader, setCollapsedHeader] = useState(renderHeaderContentProp === null);
const theme = useTheme();
const objectPage: RefObject = useConsolidatedRef(ref);
@@ -216,7 +223,7 @@ const ObjectPage: FC = forwardRef((props: ObjectPagePropTyp
}, [collapsedHeader, expandHeaderActive]);
const renderHideHeaderButton = () => {
- if (!showHideHeaderButton) return null;
+ if (!showHideHeaderButton || renderHeaderContentProp === null) return null;
const { contentDensity } = theme as JSSTheme;
@@ -237,8 +244,9 @@ const ObjectPage: FC = forwardRef((props: ObjectPagePropTyp
);
};
- const renderContentHeader = () => {
+ const renderHeader = () => {
let avatar = null;
+
if (image) {
if (typeof image === 'string') {
avatar = (
@@ -258,30 +266,39 @@ const ObjectPage: FC = forwardRef((props: ObjectPagePropTyp
}
if (showTitleInHeaderContent) {
- const headerContents = renderHeaderContent();
+ const headerContents = renderHeaderContentProp && renderHeaderContentProp();
let firstElement;
let contents = [];
- if (headerContents.type === React.Fragment) {
+ if (headerContents?.type === React.Fragment) {
[firstElement, ...contents] = React.Children.toArray(headerContents.props.children);
} else {
firstElement = headerContents;
}
-
return (
-
{avatar}
-
-
-
{title}
-
{subTitle}
- {firstElement}
+
+
{avatar}
+
+
{renderBreadcrumbs && renderBreadcrumbs()}
+
+
+
{title}
+ {subTitle}
+ {firstElement}
+
+
+ {contents.map((c, index) => (
+
+ {c}
+
+ ))}
+
+
{renderKeyInfos && renderKeyInfos()}
+
- {contents.map((c, index) => (
-
{c}
- ))}
{!expandHeaderActive && !alwaysShowContentHeader && renderHideHeaderButton()}
@@ -289,10 +306,11 @@ const ObjectPage: FC
= forwardRef((props: ObjectPagePropTyp
}
return (
-
+
{avatar}
- {renderHeaderContent && {renderHeaderContent()}}
+ {}
+ {renderHeaderContentProp && {renderHeaderContentProp()}}
{!expandHeaderActive && !alwaysShowContentHeader && renderHideHeaderButton()}
@@ -303,25 +321,29 @@ const ObjectPage: FC
= forwardRef((props: ObjectPagePropTyp
if (noHeader && !alwaysShowContentHeader) {
return renderAnchorBar();
}
-
return (
<>