Skip to content

Commit 64cd78a

Browse files
refactor(Page): Replace withStyles HOC by forwardRef implementation (#70)
1 parent fb67b47 commit 64cd78a

File tree

3 files changed

+96
-88
lines changed

3 files changed

+96
-88
lines changed

packages/main/__karma_snapshots__/Page.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,18 @@
33
#### `Basic Page`
44

55
```
6-
<div class="Page-pageContainer--- Page-pageWithHeader--- Page-pageWithFooter--- Page-backgroundStandard---"><header class="Page-pageHeader--- Page-baseBar---"><div data-bar-part="Root" class="Bar-bar---"><div data-bar-part="Left" class="Bar-left---"><ui5-button icon="navigation-left-arrow" design="Transparent" class></ui5-button></div><div data-bar-part="Center" class="Bar-center---"><div class="Bar-inner---"><ui5-title level="H5" class>Page Demo</ui5-title></div></div><div data-bar-part="Right" class="Bar-right---"></div></div></header><section class="Page-contentSection---">Page Content</section><footer class="Page-pageFooter--- Page-baseBar---"></footer></div>
6+
<div class="Page--pageContainer--- Page--pageWithHeader--- Page--pageWithFooter--- Page--backgroundStandard---"><header class="Page--pageHeader--- Page--baseBar---"><div data-bar-part="Root" class="Bar-bar---"><div data-bar-part="Left" class="Bar-left---"><ui5-button icon="navigation-left-arrow" design="Transparent" class></ui5-button></div><div data-bar-part="Center" class="Bar-center---"><div class="Bar-inner---"><ui5-title level="H5" class>Page Demo</ui5-title></div></div><div data-bar-part="Right" class="Bar-right---"></div></div></header><section class="Page--contentSection---">Page Content</section><footer class="Page--pageFooter--- Page--baseBar---"></footer></div>
77
```
88

99
#### `Basic Page w/o back button`
1010

1111
```
12-
<div class="Page-pageContainer--- Page-pageWithHeader--- Page-pageWithFooter--- Page-backgroundStandard---"><header class="Page-pageHeader--- Page-baseBar---"><div data-bar-part="Root" class="Bar-bar---"><div data-bar-part="Left" class="Bar-left---"></div><div data-bar-part="Center" class="Bar-center---"><div class="Bar-inner---"><ui5-title level="H5" class>Page Demo</ui5-title></div></div><div data-bar-part="Right" class="Bar-right---"></div></div></header><section class="Page-contentSection---">Page Content</section><footer class="Page-pageFooter--- Page-baseBar---"></footer></div>
12+
<div class="Page--pageContainer--- Page--pageWithHeader--- Page--pageWithFooter--- Page--backgroundStandard---"><header class="Page--pageHeader--- Page--baseBar---"><div data-bar-part="Root" class="Bar-bar---"><div data-bar-part="Left" class="Bar-left---"></div><div data-bar-part="Center" class="Bar-center---"><div class="Bar-inner---"><ui5-title level="H5" class>Page Demo</ui5-title></div></div><div data-bar-part="Right" class="Bar-right---"></div></div></header><section class="Page--contentSection---">Page Content</section><footer class="Page--pageFooter--- Page--baseBar---"></footer></div>
1313
```
1414

1515
#### `Without footer and Header`
1616

1717
```
18-
<section class="Page-contentSection---">Page Content</section>
18+
<section class="Page--contentSection---">Page Content</section>
1919
```
2020

packages/main/src/components/Page/demo.stories.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { boolean, select } from '@storybook/addon-knobs';
1+
import { boolean, select, text } from '@storybook/addon-knobs';
22
import { storiesOf } from '@storybook/react';
3+
import { action } from '@storybook/addon-actions';
34
import React from 'react';
45
import { Bar } from '../../lib/Bar';
56
import { Button } from '../../lib/Button';
@@ -10,12 +11,13 @@ import { PageBackgroundDesign } from '../../lib/PageBackgroundDesign';
1011
const renderPage = () => (
1112
<div style={{ height: '400px', width: '100%' }}>
1213
<Page
13-
title="Page Demo"
14+
title={text('title', 'Page Demo')}
1415
showFooter={boolean('showFooter', true)}
1516
showHeader={boolean('showHeader', true)}
1617
showBackButton={boolean('showBackButton', true)}
1718
backgroundDesign={select('backgroundDesign', PageBackgroundDesign, PageBackgroundDesign.Standard)}
1819
renderCustomFooter={() => <Bar renderContentRight={() => <Button>Button</Button>} />}
20+
onNavButtonPress={action('onNavButtonPress')}
1921
>
2022
<Label>Page Content</Label>
2123
</Page>
Lines changed: 89 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { Event, StyleClassHelper, withStyles } from '@ui5/webcomponents-react-base';
2-
import React, { Component, ReactElement, ReactNode } from 'react';
3-
import { ClassProps } from '../../interfaces/ClassProps';
1+
import { Event, StyleClassHelper } from '@ui5/webcomponents-react-base';
2+
import React, { forwardRef, ReactElement, ReactNode, Ref, useCallback, useMemo } from 'react';
3+
import { createUseStyles } from 'react-jss';
44
import { CommonProps } from '../../interfaces/CommonProps';
5+
import { JSSTheme } from '../../interfaces/JSSTheme';
56
import { Bar } from '../../lib/Bar';
67
import { Button } from '../../lib/Button';
78
import { ButtonDesign } from '../../lib/ButtonDesign';
@@ -23,89 +24,94 @@ export interface PagePropTypes extends CommonProps {
2324
children: ReactElement<any> | Array<ReactElement<any>> | ReactNode;
2425
}
2526

26-
interface PagePropsInternal extends PagePropTypes, ClassProps {}
27-
28-
@withStyles(styles)
29-
export class Page extends Component<PagePropTypes> {
30-
static defaultProps = {
31-
showHeader: true,
32-
showFooter: false,
33-
showBackButton: true,
34-
renderCustomHeader: null,
35-
renderCustomFooter: null,
36-
title: '',
37-
backgroundDesign: PageBackgroundDesign.Standard
38-
};
39-
40-
private handleNavBackButtonPress = (e) => {
41-
this.props.onNavButtonPress(Event.of(this, e.getOriginalEvent()));
42-
};
43-
44-
private renderBackButton = () => {
45-
return (
46-
<Button icon="navigation-left-arrow" design={ButtonDesign.Transparent} onClick={this.handleNavBackButtonPress} />
47-
);
48-
};
49-
50-
private renderTitle = () => <Title level={TitleLevel.H5}>{this.props.title}</Title>;
51-
52-
private renderHeader = () => {
53-
const { showBackButton } = this.props;
54-
return (
55-
<Bar
56-
renderContentLeft={showBackButton ? this.renderBackButton : () => null}
57-
renderContentMiddle={this.renderTitle}
58-
/>
59-
);
60-
};
61-
62-
render() {
63-
const {
64-
children,
65-
showFooter,
66-
showHeader,
67-
classes,
68-
className,
69-
style,
70-
renderCustomHeader,
71-
renderCustomFooter,
72-
backgroundDesign,
73-
tooltip,
74-
innerRef,
75-
slot
76-
} = this.props as PagePropsInternal;
77-
78-
const pageContainer = StyleClassHelper.of(classes.pageContainer);
79-
const headerClasses = StyleClassHelper.of(classes.pageHeader, classes.baseBar);
80-
const footerClasses = StyleClassHelper.of(classes.pageFooter, classes.baseBar);
81-
82-
if (showHeader) {
83-
pageContainer.put(classes.pageWithHeader);
84-
}
27+
const useStyles = createUseStyles<JSSTheme, keyof ReturnType<typeof styles>>(styles, {
28+
name: 'Page'
29+
});
30+
31+
const Page = forwardRef((props: PagePropTypes, ref: Ref<HTMLDivElement>) => {
32+
const {
33+
children,
34+
showFooter,
35+
showHeader,
36+
showBackButton,
37+
className,
38+
style,
39+
renderCustomHeader,
40+
renderCustomFooter,
41+
backgroundDesign,
42+
tooltip,
43+
slot,
44+
onNavButtonPress,
45+
title
46+
} = props;
47+
48+
const classes = useStyles();
8549

86-
if (showFooter) {
87-
pageContainer.put(classes.pageWithFooter);
50+
const handleNavBackButtonPress = useCallback(
51+
(e) => {
52+
if (typeof onNavButtonPress === 'function') {
53+
onNavButtonPress(Event.of(null, e.getOriginalEvent()));
54+
}
55+
},
56+
[onNavButtonPress]
57+
);
58+
59+
const renderBackButton = useCallback(() => {
60+
if (showBackButton) {
61+
return (
62+
<Button icon="navigation-left-arrow" design={ButtonDesign.Transparent} onClick={handleNavBackButtonPress} />
63+
);
8864
}
65+
return null;
66+
}, [showBackButton]);
67+
68+
const renderTitle = useCallback(() => <Title level={TitleLevel.H5}>{title}</Title>, [title]);
8969

90-
if (className) {
91-
pageContainer.put(className);
70+
const header = useMemo(() => {
71+
if (renderCustomHeader) {
72+
return renderCustomHeader();
9273
}
9374

94-
pageContainer.put(classes[`background${backgroundDesign}`]);
95-
96-
return (
97-
<div ref={innerRef} className={pageContainer.valueOf()} style={style} title={tooltip} slot={slot}>
98-
{showHeader && (
99-
<header className={headerClasses.valueOf()}>
100-
{renderCustomHeader && renderCustomHeader()}
101-
{!renderCustomHeader && this.renderHeader()}
102-
</header>
103-
)}
104-
<section className={classes.contentSection}>{children}</section>
105-
{showFooter && (
106-
<footer className={footerClasses.valueOf()}>{renderCustomFooter && renderCustomFooter()}</footer>
107-
)}
108-
</div>
109-
);
75+
return <Bar renderContentLeft={renderBackButton} renderContentMiddle={renderTitle} />;
76+
}, [renderCustomHeader, renderTitle, renderBackButton]);
77+
78+
const pageContainer = StyleClassHelper.of(classes.pageContainer);
79+
const headerClasses = StyleClassHelper.of(classes.pageHeader, classes.baseBar);
80+
const footerClasses = StyleClassHelper.of(classes.pageFooter, classes.baseBar);
81+
82+
if (showHeader) {
83+
pageContainer.put(classes.pageWithHeader);
11084
}
111-
}
85+
86+
if (showFooter) {
87+
pageContainer.put(classes.pageWithFooter);
88+
}
89+
90+
if (className) {
91+
pageContainer.put(className);
92+
}
93+
94+
pageContainer.put(classes[`background${backgroundDesign}`]);
95+
96+
return (
97+
<div ref={ref} className={pageContainer.valueOf()} style={style} title={tooltip} slot={slot}>
98+
{showHeader && <header className={headerClasses.valueOf()}>{header}</header>}
99+
<section className={classes.contentSection}>{children}</section>
100+
{showFooter && <footer className={footerClasses.valueOf()}>{renderCustomFooter && renderCustomFooter()}</footer>}
101+
</div>
102+
);
103+
});
104+
105+
Page.defaultProps = {
106+
showHeader: true,
107+
showFooter: false,
108+
showBackButton: true,
109+
renderCustomHeader: null,
110+
renderCustomFooter: null,
111+
title: '',
112+
backgroundDesign: PageBackgroundDesign.Standard
113+
};
114+
115+
Page.displayName = 'Page';
116+
117+
export { Page };

0 commit comments

Comments
 (0)