Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(Page): Replace withStyles HOC by forwardRef implementation #70

Merged
merged 7 commits into from
Aug 2, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/main/__karma_snapshots__/CheckBox.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

```
<ThemeProvider withToastContainer={false}>
<JssProvider generateId={[Function]} id={{...}}>
<JssProvider generateId={[Function]}>
<ThemeProvider theme={{...}}>
<CheckBox valueState="None">
<ui5-checkbox value-state="None" class="" />
Expand Down
6 changes: 3 additions & 3 deletions packages/main/__karma_snapshots__/Page.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@
#### `Basic Page`

```
<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>
<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>
```

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

```
<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>
<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>
```

#### `Without footer and Header`

```
<section class="Page-contentSection---">Page Content</section>
<section class="Page--contentSection---">Page Content</section>
```

6 changes: 4 additions & 2 deletions packages/main/src/components/Page/demo.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { boolean, select } from '@storybook/addon-knobs';
import { boolean, select, text } from '@storybook/addon-knobs';
import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions';
import React from 'react';
import { Bar } from '../../lib/Bar';
import { Button } from '../../lib/Button';
Expand All @@ -10,12 +11,13 @@ import { PageBackgroundDesign } from '../../lib/PageBackgroundDesign';
const renderPage = () => (
<div style={{ height: '400px', width: '100%' }}>
<Page
title="Page Demo"
title={text('title', 'Page Demo')}
showFooter={boolean('showFooter', true)}
showHeader={boolean('showHeader', true)}
showBackButton={boolean('showBackButton', true)}
backgroundDesign={select('backgroundDesign', PageBackgroundDesign, PageBackgroundDesign.Standard)}
renderCustomFooter={() => <Bar renderContentRight={() => <Button>Button</Button>} />}
onNavButtonPress={action('onNavButtonPress')}
>
<Label>Page Content</Label>
</Page>
Expand Down
188 changes: 100 additions & 88 deletions packages/main/src/components/Page/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Event, StyleClassHelper, withStyles } from '@ui5/webcomponents-react-base';
import React, { Component, ReactElement, ReactNode } from 'react';
import { ClassProps } from '../../interfaces/ClassProps';
import { Event, StyleClassHelper } from '@ui5/webcomponents-react-base';
import React, { forwardRef, ReactElement, ReactNode, Ref, useCallback, useMemo } from 'react';
import { createUseStyles } from 'react-jss';
import { CommonProps } from '../../interfaces/CommonProps';
import { Bar } from '../../lib/Bar';
import { Button } from '../../lib/Button';
Expand All @@ -23,89 +23,101 @@ export interface PagePropTypes extends CommonProps {
children: ReactElement<any> | Array<ReactElement<any>> | ReactNode;
}

interface PagePropsInternal extends PagePropTypes, ClassProps {}

@withStyles(styles)
export class Page extends Component<PagePropTypes> {
static defaultProps = {
showHeader: true,
showFooter: false,
showBackButton: true,
renderCustomHeader: null,
renderCustomFooter: null,
title: '',
backgroundDesign: PageBackgroundDesign.Standard
};

private handleNavBackButtonPress = (e) => {
this.props.onNavButtonPress(Event.of(this, e.getOriginalEvent()));
};

private renderBackButton = () => {
return (
<Button icon="navigation-left-arrow" design={ButtonDesign.Transparent} onClick={this.handleNavBackButtonPress} />
);
};

private renderTitle = () => <Title level={TitleLevel.H5}>{this.props.title}</Title>;

private renderHeader = () => {
const { showBackButton } = this.props;
return (
<Bar
renderContentLeft={showBackButton ? this.renderBackButton : () => null}
renderContentMiddle={this.renderTitle}
/>
);
};

render() {
const {
children,
showFooter,
showHeader,
classes,
className,
style,
renderCustomHeader,
renderCustomFooter,
backgroundDesign,
tooltip,
innerRef,
slot
} = this.props as PagePropsInternal;

const pageContainer = StyleClassHelper.of(classes.pageContainer);
const headerClasses = StyleClassHelper.of(classes.pageHeader, classes.baseBar);
const footerClasses = StyleClassHelper.of(classes.pageFooter, classes.baseBar);

if (showHeader) {
pageContainer.put(classes.pageWithHeader);
}

if (showFooter) {
pageContainer.put(classes.pageWithFooter);
}

if (className) {
pageContainer.put(className);
}

pageContainer.put(classes[`background${backgroundDesign}`]);

return (
<div ref={innerRef} className={pageContainer.valueOf()} style={style} title={tooltip} slot={slot}>
{showHeader && (
<header className={headerClasses.valueOf()}>
{renderCustomHeader && renderCustomHeader()}
{!renderCustomHeader && this.renderHeader()}
</header>
)}
<section className={classes.contentSection}>{children}</section>
{showFooter && (
<footer className={footerClasses.valueOf()}>{renderCustomFooter && renderCustomFooter()}</footer>
)}
</div>
);
const useStyles = createUseStyles<string>(styles, {
name: 'Page'
});

const Page = forwardRef((props: PagePropTypes, ref: Ref<HTMLDivElement>) => {
const {
children,
showFooter,
showHeader,
showBackButton,
className,
style,
renderCustomHeader,
renderCustomFooter,
backgroundDesign,
tooltip,
slot,
onNavButtonPress,
title
} = props;

const classes = useStyles();

const handleNavBackButtonPress = useCallback(
(e) => {
if (typeof onNavButtonPress === 'function') {
onNavButtonPress(Event.of(null, e.getOriginalEvent()));
}
},
[onNavButtonPress]
);

const renderBackButton = useMemo(
MarcusNotheis marked this conversation as resolved.
Show resolved Hide resolved
() => () => {
if (showBackButton) {
return (
<Button icon="navigation-left-arrow" design={ButtonDesign.Transparent} onClick={handleNavBackButtonPress} />
);
}
return null;
},
[showBackButton]
);

const renderTitle = useMemo(() => () => <Title level={TitleLevel.H5}>{title}</Title>, [title]);
MarcusNotheis marked this conversation as resolved.
Show resolved Hide resolved

const renderHeader = useMemo(
MarcusNotheis marked this conversation as resolved.
Show resolved Hide resolved
() => () => {
return <Bar renderContentLeft={renderBackButton} renderContentMiddle={renderTitle} />;
},
[renderTitle, renderBackButton]
);

const pageContainer = StyleClassHelper.of(classes.pageContainer);
const headerClasses = StyleClassHelper.of(classes.pageHeader, classes.baseBar);
const footerClasses = StyleClassHelper.of(classes.pageFooter, classes.baseBar);

if (showHeader) {
pageContainer.put(classes.pageWithHeader);
}
}

if (showFooter) {
pageContainer.put(classes.pageWithFooter);
}

if (className) {
pageContainer.put(className);
}

pageContainer.put(classes[`background${backgroundDesign}`]);

return (
<div ref={ref} className={pageContainer.valueOf()} style={style} title={tooltip} slot={slot}>
{showHeader && (
<header className={headerClasses.valueOf()}>
{renderCustomHeader && renderCustomHeader()}
{!renderCustomHeader && renderHeader()}
</header>
)}
<section className={classes.contentSection}>{children}</section>
{showFooter && <footer className={footerClasses.valueOf()}>{renderCustomFooter && renderCustomFooter()}</footer>}
</div>
);
});

Page.defaultProps = {
showHeader: true,
showFooter: false,
showBackButton: true,
renderCustomHeader: null,
renderCustomFooter: null,
title: '',
backgroundDesign: PageBackgroundDesign.Standard
};

Page.displayName = 'Page';

export { Page };