Skip to content

Commit 08982ba

Browse files
vberschMarcusNotheis
authored andcommitted
refactor(withWebComponent): replace innerComponentRef with ref for Web Components (#44)
BREAKING CHANGE Replaced `innerComponentRef` with `ref` to support React `RefObject`
1 parent 4d3c529 commit 08982ba

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+2981
-3669
lines changed

packages/base/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"core-js": "^3.1.4",
1717
"deepmerge": "^3.2.0",
1818
"hoist-non-react-statics": "^3.3.0",
19-
"react-jss": "^8.6.1",
19+
"react-jss": "10.0.0-alpha.21",
2020
"tslib": "^1.9.3"
2121
}
2222
}

packages/base/src/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ import KeyCodes from './KeyCodes';
1515
import { LOG_LEVEL, Logger } from './Logger';
1616
import Optional from './Optional';
1717
import StyleClassHelper from './StyleClassHelper';
18-
1918
import { deprecationNotice, pushElementBackInScreen } from './Util';
19+
import { createGenerateClassName } from './withStyles/createGenerateClassName';
2020

2121
export {
2222
StyleClassHelper,
@@ -35,5 +35,6 @@ export {
3535
HSLColor,
3636
sap_fiori_3,
3737
bootstrap,
38-
withStyles
38+
withStyles,
39+
createGenerateClassName
3940
};
Lines changed: 23 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,34 @@
1-
import deepMerge from 'deepmerge';
21
import hoistNonReactStatics from 'hoist-non-react-statics';
3-
import React, { ComponentType, Ref } from 'react';
4-
import injectSheet from 'react-jss';
5-
import { createGenerateClassName } from './createGenerateClassName';
6-
7-
const generateClassName = createGenerateClassName();
8-
9-
const getStyle = (style) => (...args) => (typeof style === 'function' ? style(...args) : style);
10-
11-
const mergeStyles = (styles, ...newStyles) => {
12-
return (...args) =>
13-
deepMerge.all([getStyle(styles)(...args), ...newStyles.map((newStyle) => getStyle(newStyle)(...args))]);
14-
};
2+
import React, { ComponentType, ForwardRefExoticComponent, RefAttributes, RefObject } from 'react';
3+
// @ts-ignore
4+
import { createUseStyles, useTheme } from 'react-jss';
155

166
const getDisplayName = (Component) => Component.displayName || Component.name || 'Component';
177
const wrapComponentName = (componentName) => `WithStyles(${componentName})`;
188

19-
export interface WithStylesPropTypes {
20-
innerComponentRef: Ref<any>;
9+
export interface WithStylesComponent<T = {}> extends ForwardRefExoticComponent<RefAttributes<T>> {
10+
InnerComponent?: ComponentType<any>;
2111
}
2212

23-
export const withStyles = (styles) => (Component: ComponentType<any>) => {
24-
class WithStyles extends React.Component<WithStylesPropTypes> {
25-
static defaultProps = Component.defaultProps;
26-
static InnerComponent = Component;
27-
static displayName = wrapComponentName(getDisplayName(Component));
28-
static withCustomStyles = (...newStyles) => {
29-
return withStyles(mergeStyles(styles, ...newStyles))(Component);
30-
};
13+
export function withStyles<T>(styles): any {
14+
return (Component: ComponentType<T>) => {
15+
const displayName = wrapComponentName(getDisplayName(Component));
3116

32-
state = {
33-
error: false
34-
};
17+
const useStyles = createUseStyles(styles, {
18+
name: displayName
19+
});
3520

36-
componentDidUpdate(prevProps) {
37-
if (prevProps !== this.props) {
38-
// retry rendering of Component
39-
this.setState({ error: false });
40-
}
41-
}
21+
const WithStyles: WithStylesComponent<T> = React.forwardRef((props: T, ref: RefObject<any>) => {
22+
const classes = useStyles(props);
23+
const theme = useTheme();
4224

43-
componentDidCatch(error, info) {
44-
// Logger.error(error.message, Component.displayName || WithStyles.displayName);
45-
this.setState({ error: true });
46-
}
25+
return <Component {...props} ref={ref} classes={classes} theme={theme} />;
26+
});
4727

48-
render() {
49-
const { innerComponentRef, ...rest } = this.props;
50-
const { error } = this.state;
51-
52-
// props containing theme, classes generated by react-jss as well as
53-
// user defined props
54-
if (!error) {
55-
return <Component ref={innerComponentRef} {...rest} />;
56-
} else {
57-
return null;
58-
}
59-
}
60-
}
61-
62-
hoistNonReactStatics(WithStyles, Component);
63-
return injectSheet(styles, {
64-
generateClassName
65-
})(WithStyles);
66-
};
28+
WithStyles.defaultProps = Component.defaultProps;
29+
WithStyles.displayName = displayName;
30+
WithStyles.InnerComponent = Component;
31+
hoistNonReactStatics(WithStyles, Component);
32+
return WithStyles;
33+
};
34+
}
Lines changed: 3 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
import React, { cloneElement, Component } from 'react';
1+
import React, { Component } from 'react';
22
import { withStyles } from './index';
33
import { mountThemedComponent } from '@shared/tests/utils';
44
import sinon from 'sinon';
55

6-
const testAttribute = 'TEST';
7-
86
class UnitTestDemo extends Component<any> {
9-
static testAttribute = testAttribute;
107
render() {
118
const { classes } = this.props;
129
if (!classes) {
@@ -16,71 +13,17 @@ class UnitTestDemo extends Component<any> {
1613
}
1714
}
1815

19-
const UnitTestDemoSfc = (props) => {
20-
const { classes } = props;
21-
if (!classes) {
22-
throw 'No classes passed down';
23-
}
24-
return <div />;
25-
};
26-
27-
// @ts-ignore
28-
UnitTestDemoSfc.testAttribute = testAttribute;
29-
30-
const FaultyComponent = withStyles(() => ({}))((props) => {
31-
if (props.fail) {
32-
throw 'Oooops';
33-
}
34-
35-
return <div>All fine!</div>;
36-
});
37-
3816
const styles = () => ({
3917
testClass: {
4018
color: 'green'
4119
}
4220
});
4321

4422
describe('withStyles', () => {
45-
test('Extend Class Component with Styles and check statics', () => {
46-
const DemoWithStyles = withStyles(styles)(UnitTestDemo);
47-
expect(DemoWithStyles.testAttribute).toBe(testAttribute);
48-
expect(DemoWithStyles.InnerComponent).toBe(UnitTestDemo);
49-
50-
const ExtendedDemo = DemoWithStyles.withCustomStyles({ testClass: { color: 'black' } });
51-
expect(ExtendedDemo.testAttribute).toBe(testAttribute);
52-
expect(ExtendedDemo.InnerComponent).toBe(UnitTestDemo);
53-
});
54-
55-
test('render styled component without crashing', () => {
56-
const DemoWithStyles = withStyles(styles)(UnitTestDemo);
57-
mountThemedComponent(<DemoWithStyles />);
58-
const ExtendedDemo = DemoWithStyles.withCustomStyles({ testClass: { color: 'black' } });
59-
mountThemedComponent(<ExtendedDemo />);
60-
});
61-
62-
test('innerComponentRef', () => {
23+
test('component ref', () => {
6324
const callback = sinon.spy();
6425
const DemoWithStyles = withStyles(styles)(UnitTestDemo);
65-
mountThemedComponent(<DemoWithStyles innerComponentRef={callback} />);
26+
mountThemedComponent(<DemoWithStyles ref={callback} />);
6627
expect(callback.callCount).toBe(1);
6728
});
68-
69-
test('test with SFC', () => {
70-
const DemoWithStyles = withStyles(styles)(UnitTestDemoSfc);
71-
mountThemedComponent(<DemoWithStyles />);
72-
expect(DemoWithStyles.testAttribute).toBe(testAttribute);
73-
const ExtendedDemo = DemoWithStyles.withCustomStyles({ testClass: { color: 'black' } });
74-
mountThemedComponent(<ExtendedDemo />);
75-
expect(ExtendedDemo.testAttribute).toBe(testAttribute);
76-
});
77-
78-
test('Error Boundary', () => {
79-
const wrapper = mountThemedComponent(<FaultyComponent fail />);
80-
expect((wrapper.find('WithStyles(Component)').instance().state as any).error).toBe(true);
81-
wrapper.setProps({
82-
children: cloneElement(wrapper.props().children, { fail: false })
83-
});
84-
expect((wrapper.find('WithStyles(Component)').instance().state as any).error).toBe(false);
85-
});
8629
});

packages/main/__karma_snapshots__/ActionSheet.md

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,26 @@
44

55
```
66
<ThemeProvider withToastContainer={false}>
7-
<ThemeProvider jss={{...}} theme={{...}}>
8-
<Jss(WithStyles(ActionSheet)) openBy={{...}} placement="Bottom">
9-
<WithStyles(ActionSheet) openBy={{...}} placement="Bottom" classes={{...}}>
10-
<ActionSheet openBy={{...}} placement="Bottom" classes={{...}}>
11-
<Popover noHeader={true} innerComponentRef={[Function]} openBy={{...}} placementType="Bottom" style={[undefined]} data-ui5-slot={[undefined]} initialFocus={{...}} headerText="" horizontalAlign="Center" verticalAlign="Center">
7+
<JssProvider generateId={[Function]} id={{...}}>
8+
<ThemeProvider theme={{...}}>
9+
<WithStyles(ActionSheet) openBy={{...}} placement="Bottom">
10+
<ActionSheet openBy={{...}} placement="Bottom" classes={{...}} theme={{...}}>
11+
<Popover noHeader={true} openBy={{...}} placementType="Bottom" style={[undefined]} data-ui5-slot={[undefined]} initialFocus={{...}} headerText="" horizontalAlign="Center" verticalAlign="Center">
1212
<div style={{...}} onClick={[Function]}>
1313
<Button design="Default">
14-
<WithWebComponent theme={{...}} design="Default">
15-
<ui5-button design="Default" class="" />
16-
</WithWebComponent>
14+
<ui5-button design="Default" class="" />
1715
</Button>
1816
</div>
19-
<WithTheme(WithWebComponent) noHeader={true} innerComponentRef={[Function]} placementType="Bottom" style={[undefined]} data-ui5-slot={[undefined]} initialFocus={{...}} headerText="" horizontalAlign="Center" verticalAlign="Center">
20-
<WithWebComponent theme={{...}} noHeader={true} innerComponentRef={[Function]} placementType="Bottom" style={[undefined]} data-ui5-slot={[undefined]} initialFocus={{...}} headerText="" horizontalAlign="Center" verticalAlign="Center">
21-
<ui5-popover no-header={true} inner-component-ref={[Function]} placement-type="Bottom" style={[undefined]} data-ui5-slot={[undefined]} initial-focus={{...}} header-text="" horizontal-align="Center" vertical-align="Center" class="">
22-
<ul className="ActionSheet-actionSheet---" />
23-
</ui5-popover>
24-
</WithWebComponent>
25-
</WithTheme(WithWebComponent)>
17+
<WithWebComponent(Popover) noHeader={true} placementType="Bottom" style={[undefined]} data-ui5-slot={[undefined]} initialFocus={{...}} headerText="" horizontalAlign="Center" verticalAlign="Center">
18+
<ui5-popover no-header={true} placement-type="Bottom" style={[undefined]} data-ui5-slot={[undefined]} initial-focus={{...}} header-text="" horizontal-align="Center" vertical-align="Center" class="">
19+
<ul className="ActionSheet-actionSheet---" />
20+
</ui5-popover>
21+
</WithWebComponent(Popover)>
2622
</Popover>
2723
</ActionSheet>
2824
</WithStyles(ActionSheet)>
29-
</Jss(WithStyles(ActionSheet))>
30-
</ThemeProvider>
25+
</ThemeProvider>
26+
</JssProvider>
3127
</ThemeProvider>
3228
```
3329

0 commit comments

Comments
 (0)