Skip to content

Commit 105b2da

Browse files
authored
feat(ObjectPage): refactor component to support ui5wc v2 (#6089)
BREAKING CHANGE: `headerContent` has been renamed to `headerArea` and now only accepts the `ObjectPageHeader` component. BREAKING CHANGE: `headerTitle` has been renamed to `titleArea` and now only accepts the `ObjectPageTitle` component. BREAKING CHANGE: `footer` has been renamed to `footerArea`. BREAKING CHANGE: `onToggleHeaderContent` has been renamed to `onToggleHeaderArea` BREAKING CHANGE: `onPinnedStateChange` has been renamed to `onPinButtonToggle` BREAKING CHANGE: __ObjectPageTitle__: `actions` has been renamed to `actionsBar`. Instead of single actions, the `Toolbar` component should now be passed. BREAKING CHANGE: __ObjectPageTitle__: `navigationActions` has been renamed to `navigationBar`. Instead of single actions, the `Toolbar` component should now be passed. BREAKING CHANGE: __ObjectPageTitle__: `actionsToolbarProps`: Since it's now recommended passing the `Toolbar` component directly, this prop is redundant. BREAKING CHANGE: __ObjectPageTitle__: `navigationActionsToolbarProps`: Since it's now recommended passing the `Toolbar` component directly, this prop is redundant.
1 parent 44c90da commit 105b2da

File tree

16 files changed

+607
-439
lines changed

16 files changed

+607
-439
lines changed

docs/MigrationGuide.mdx

Lines changed: 66 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -627,33 +627,88 @@ The regular methods are now general purpose, so they can be used both inside the
627627
### ObjectPage
628628

629629
The newly introduced `DynamicPage` web component comes with its own `DynamicPageHeader` and `DynamicPageTitle` components, which are unfortunately incompatible with our `ObjectPage` implementation.
630-
Please use the following components instead:
630+
Please use the `ObjectPageHeader` or `ObjectPageTitle` component instead.
631631

632-
- `headerContent` now only accepts the `ObjectPageHeader` component.
633-
- `headerTitle` now only accepts the `ObjectPageTitle` component.
632+
**Removed Props:**
633+
634+
- `showHideHeaderButton`: Hiding the expand/collapse button is not supported by design anymore.
635+
- `showTitleInHeaderContent`: Showing the `headerTitle` as part of the `headerContent` is [not supported by design anymore](https://experience.sap.com/fiori-design-web/object-page/#dynamic-page-header-mandatory).
636+
637+
**Refactored Props:**
638+
639+
- `headerContent` has been renamed to `headerArea` and now only accepts the `ObjectPageHeader` component.
640+
- `headerTitle` has been renamed to `titleArea` and now only accepts the `ObjectPageTitle` component.
641+
- `headerContentPinnable` has been renamed to `hidePinButton` and the logic has been inverted. The pin button is now shown by default.
634642

635643
**Renamed Props:**
636644

637645
- `a11yConfig` has been renamed to `accessibilityAttributes`
638646
- `a11yConfig.dynamicPageAnchorBar` has been renamed to `accessibilityAttributes.objectPageAnchorBar`
639647
- `alwaysShowContentHeader` has been renamed to `headerPinned`
640-
- `headerContentPinnable` has been renamed to `hidePinButton` and the logic has been inverted. The pin button is now shown by default.
641-
642-
**Removed Props:**
643-
644-
- `showHideHeaderButton`: Hiding the expand/collapse button is not supported by design anymore.
645-
- `showTitleInHeaderContent`: Showing the `headerTitle` as part of the `headerContent` is [not supported by design anymore](https://experience.sap.com/fiori-design-web/object-page/#dynamic-page-header-mandatory).
648+
- `footer` has been renamed to `footerArea`
649+
- `onToggleHeaderContent` has been renamed to `onToggleHeaderArea`
650+
- `onPinnedStateChange` has been renamed to `onPinButtonToggle`
646651

647652
Also, the namings of internal `data-component-name` attributes have been adjusted accordingly. E.g. `data-component-name="DynamicPageTitleSubHeader"` has been renamed to `data-component-name="ObjectPageTitleSubHeader"`
648653

649-
### ObjectPageTitle
654+
### ObjectPageTitle (f.k.a. DynamicPageTitle)
650655

651-
_The `ObjectPageTitle` component is the renamed implementation of the old (React only) `DynamicPageTitle` component._
656+
_The `ObjectPageTitle` component is the renamed implementation of the old (React only) `DynamicPageTitle` component. Now, it should only be used in the `ObjectPage`._
652657

653658
**Removed Props:**
654659

660+
- `actionsToolbarProps`: Since it's now recommended passing the `Toolbar` component directly, this prop is redundant.
661+
- `navigationActionsToolbarProps`: Since it's now recommended passing the `Toolbar` component directly, this prop is redundant.
655662
- `showSubHeaderRight`: Displaying the subheader in the same line as the header is not supported by design anymore.
656663

664+
**Refactored Props:**
665+
666+
- `actions` has been renamed to `actionsBar`. Instead of single actions, the `Toolbar` component should now be passed.
667+
- `navigationActions` has been renamed to `navigationBar`. Instead of single actions, the `Toolbar` component should now be passed. The `ObjectPageTitle` still offers support for the legacy `Toolbar`.
668+
669+
_The `ObjectPageTitle` still offers support for the legacy `Toolbar`. You can find out more about this [here](?path=/docs/layouts-floorplans-objectpage--docs#legacy-toolbar-support)._
670+
671+
```jsx
672+
// v1
673+
<DynamicPageTitle
674+
showSubHeaderRight
675+
actionsToolbarProps={{ style: { background: 'red' } }}
676+
navigationActionsToolbarProps={{ style: { background: 'red' } }}
677+
actions={
678+
<>
679+
<Button>Action 1</Button>
680+
<Button>Action 2</Button>
681+
</>
682+
}
683+
navigationActions={
684+
<>
685+
<Button>Navigation-Action 1</Button>
686+
<Button>Navigation-Action 2</Button>
687+
</>
688+
}
689+
/>
690+
691+
// v2
692+
<ObjectPageTitle
693+
// `showSubHeaderRight` has been removed without replacement
694+
695+
// You can now pass all toolbar props directly to the toolbar,
696+
// making `actionsToolbarProps` and `navigationActionsToolbarProps` redundant
697+
actionsBar={
698+
<Toolbar design="Transparent" style={{ background: 'red' }}>
699+
<ToolbarButton text="Action 1" />
700+
<ToolbarButton text="Action 2" />
701+
</Toolbar>
702+
}
703+
navigationBar={
704+
<Toolbar design="Transparent" style={{ background: 'red' }}>
705+
<ToolbarButton text="Navigation-Action 1" />
706+
<ToolbarButton text="Navigation-Action 2" />
707+
</Toolbar>
708+
}
709+
/>
710+
```
711+
657712
### ObjectPageSection
658713

659714
The prop `titleText` is now required and the default value `true` has been removed for the `titleTextUppercase` prop to comply with the updated Fiori design guidelines.

packages/base/src/utils/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ export const enrichEventWithDetails = <
2323
event: Event,
2424
payload: Detail
2525
): EnrichedEventType<Event, Detail> => {
26+
if (!event) {
27+
return event;
28+
}
2629
// todo: once we drop React 16 support, remove this
2730
// the helper accepts both SyntheticEvents and browser events
2831
const syntheticEventCast = event as unknown as SyntheticEvent;

packages/cli/src/scripts/codemod/transforms/v2/codemodConfig.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,10 +319,16 @@
319319
"changedProps": {
320320
"a11yConfig": "accessibilityAttributes",
321321
"alwaysShowContentHeader": "headerPinned",
322-
"headerContentPinnable": "hidePinButton"
322+
"headerContentPinnable": "hidePinButton",
323+
"footer": "footerArea",
324+
"onToggleHeaderContent": "onToggleHeaderArea",
325+
"onPinnedStateChange": "onPinButtonToggle"
323326
},
324327
"removedProps": ["showHideHeaderButton", "showTitleInHeaderContent"]
325328
},
329+
"ObjectPageTitle": {
330+
"removedProps": ["showSubHeaderRight"]
331+
},
326332
"ObjectStatus": {
327333
"changedProps": {
328334
"active": "interactive"

packages/cli/src/scripts/codemod/transforms/v2/main.cts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,72 @@ export default function transform(file: FileInfo, api: API, options?: Options):
347347
headerContentPinnable.remove();
348348
isDirty = true;
349349
}
350+
351+
const headerContent = j(el).find(j.JSXAttribute, { name: { name: 'headerContent' } });
352+
if (headerContent.size() > 0) {
353+
const attr = headerContent.get();
354+
if (attr.value.value && attr.value.value.type === 'JSXExpressionContainer') {
355+
headerContent.forEach((el) => {
356+
const dynamicPageHeader = j(el).find(j.JSXElement, {
357+
openingElement: { name: { name: 'DynamicPageHeader' } }
358+
});
359+
360+
// remove DynamicPageHeader import only if no DynamicPage is there
361+
if (!componentIsImportedFromWebComponentsReact(j, root, 'DynamicPage')) {
362+
const imports = root.find(j.ImportDeclaration);
363+
const dphImport = imports.find(j.ImportSpecifier, { local: { name: 'DynamicPageHeader' } });
364+
dphImport.remove();
365+
}
366+
addWebComponentsReactImport(j, root, 'ObjectPageHeader');
367+
368+
// replace JSX tag (component)
369+
dynamicPageHeader.forEach((innerEl) => {
370+
const updatedTagName = j.jsxIdentifier('ObjectPageHeader');
371+
innerEl.node.openingElement.name = updatedTagName;
372+
if (innerEl.node.closingElement) {
373+
innerEl.node.closingElement.name = updatedTagName;
374+
}
375+
});
376+
377+
// replace prop name
378+
headerContent.find(j.JSXIdentifier, { name: 'headerContent' }).replaceWith(j.jsxIdentifier('headerArea'));
379+
});
380+
isDirty = true;
381+
}
382+
}
383+
384+
const headerTitle = j(el).find(j.JSXAttribute, { name: { name: 'headerTitle' } });
385+
if (headerTitle.size() > 0) {
386+
const attr = headerTitle.get();
387+
if (attr.value.value && attr.value.value.type === 'JSXExpressionContainer') {
388+
headerTitle.forEach((el) => {
389+
const dynamicPageTitle = j(el).find(j.JSXElement, {
390+
openingElement: { name: { name: 'DynamicPageTitle' } }
391+
});
392+
393+
// remove DynamicPageTitle import only if no DynamicPage is there
394+
dynamicPageTitle.forEach((innerEl) => {
395+
if (!componentIsImportedFromWebComponentsReact(j, root, 'DynamicPage')) {
396+
const imports = root.find(j.ImportDeclaration);
397+
const dptImport = imports.find(j.ImportSpecifier, { local: { name: 'DynamicPageTitle' } });
398+
dptImport.remove();
399+
}
400+
addWebComponentsReactImport(j, root, 'ObjectPageTitle');
401+
402+
// replace JSX tag (component)
403+
const updatedTagName = j.jsxIdentifier('ObjectPageTitle');
404+
innerEl.node.openingElement.name = updatedTagName;
405+
if (innerEl.node.closingElement) {
406+
innerEl.node.closingElement.name = updatedTagName;
407+
}
408+
});
409+
410+
// replace prop name
411+
headerTitle.find(j.JSXIdentifier, { name: 'headerTitle' }).replaceWith(j.jsxIdentifier('titleArea'));
412+
});
413+
isDirty = true;
414+
}
415+
}
350416
});
351417
}
352418

packages/compat/src/components/Toolbar/index.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ const Toolbar = forwardRef<HTMLDivElement, ToolbarPropTypes>((props, ref) => {
164164
...rest
165165
} = props;
166166

167+
const inObjectPage = props['data-in-object-page-title'];
168+
167169
useStylesheet(styleData, Toolbar.displayName);
168170
const [componentRef, outerContainer] = useSyncRef<HTMLDivElement>(ref);
169171
const controlMetaData = useRef([]);
@@ -317,6 +319,9 @@ const Toolbar = forwardRef<HTMLDivElement, ToolbarPropTypes>((props, ref) => {
317319
}, [calculateVisibleItems]);
318320

319321
const handleToolbarClick = (e) => {
322+
if (inObjectPage && typeof onClick === 'function') {
323+
onClick(e);
324+
}
320325
if (active && typeof onClick === 'function') {
321326
const isSpaceEnterDown = e.type === 'keydown' && (e.code === 'Enter' || e.code === 'Space');
322327
if (isSpaceEnterDown && e.target !== e.currentTarget) {
@@ -379,6 +384,7 @@ const Toolbar = forwardRef<HTMLDivElement, ToolbarPropTypes>((props, ref) => {
379384
tabIndex={active ? 0 : undefined}
380385
role={active ? 'button' : undefined}
381386
data-sap-ui-fastnavgroup="true"
387+
data-component-name="Toolbar"
382388
{...rest}
383389
>
384390
<div className={classNames.toolbar} data-component-name="ToolbarContent" ref={contentRef}>
@@ -420,4 +426,6 @@ const Toolbar = forwardRef<HTMLDivElement, ToolbarPropTypes>((props, ref) => {
420426
});
421427

422428
Toolbar.displayName = 'Toolbar';
429+
//@ts-expect-error: private identifier
430+
Toolbar._displayName = 'UI5WCRToolbar';
423431
export { Toolbar };

0 commit comments

Comments
 (0)