Skip to content

Commit 506dc1d

Browse files
refactor(ThemeProvider): Functional component (#89)
1 parent 598a97e commit 506dc1d

File tree

7 files changed

+164
-104
lines changed

7 files changed

+164
-104
lines changed

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,16 @@ You could import all components also from `@ui5/webcomponents-react` directly, b
101101

102102
### Browser Support
103103
`@ui5/webcomponents-react` is supporting all modern major browsers. There is no support for Internet Explorer 11 built in.<br />
104-
If you want your application to run in IE11, you will have to polyfill some features by importing:
104+
If you want your application to run in IE11, you will have to polyfill some features by importing these polyfills as **first** imports in your `src/index.js`:
105105
```js
106+
import 'react-app-polyfill/ie11';
107+
import '@ui5/webcomponents-base/src/features/browsersupport/IE11';
106108
import '@ui5/webcomponents-react-base/polyfill/IE11';
109+
import '@webcomponents/webcomponentsjs/webcomponents-bundle';
110+
```
111+
You can install `react-app-polyfill` and `@webcomponents/webcomponentsjs` with the following command:
112+
```bash
113+
npm install react-app-polyfill @webcomponents/webcomponentsjs --save
107114
```
108115

109116
For Browser Support and the configuration of the UI5 Web Components, please take a look at the

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"@types/react-dom": "^16.8.4",
3737
"@types/sinon": "^7.0.12",
3838
"@types/storybook__react": "^4.0.1",
39+
"@webcomponents/webcomponentsjs": "^2.2.10",
3940
"babel-code-frame": "^6.26.0",
4041
"babel-loader": "^8.0.5",
4142
"babel-preset-react-app": "^9.0.0",
@@ -91,6 +92,7 @@
9192
"puppeteer": "^1.15.0",
9293
"qs": "^6.7.0",
9394
"react": "^16.8.6",
95+
"react-app-polyfill": "^1.0.2",
9496
"react-docgen-typescript-loader": "^3.1.0",
9597
"react-dom": "^16.8.6",
9698
"react-highlight.js": "^1.0.7",

packages/docs/.storybook/config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import 'react-app-polyfill/ie11';
2+
import '@ui5/webcomponents-base/src/features/browsersupport/IE11';
3+
import '@webcomponents/webcomponentsjs/webcomponents-bundle';
14
import React from 'react';
25
import { ContentDensity } from '@ui5/webcomponents-react/lib/ContentDensity';
36
import { ThemeProvider } from '@ui5/webcomponents-react/lib/ThemeProvider';

packages/docs/.storybook/webpack.config.js

Lines changed: 45 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,17 @@ require('dotenv').config({
55
path: path.join(PATHS.root, '.env')
66
});
77

8+
process.env.NODE_ENV = 'development';
9+
process.env.BABEL_ENV = 'development';
10+
811
module.exports = ({ config }) => {
912
const tsLoader = {
1013
test: /\.tsx?$/,
1114
use: [
1215
{
1316
loader: require.resolve('babel-loader'),
1417
options: {
15-
presets: [require.resolve('babel-preset-react-app')]
18+
presets: [[require.resolve('babel-preset-react-app'), { flow: false, typescript: true }]]
1619
}
1720
}
1821
]
@@ -30,37 +33,48 @@ SKIP_DOC_GENERATION=true
3033
tsLoader.use.push({ loader: require.resolve('react-docgen-typescript-loader') });
3134
}
3235

33-
return {
34-
...config,
35-
module: {
36-
...config.module,
37-
rules: [
38-
...config.module.rules,
39-
tsLoader,
40-
{
41-
test: [/cldr\/.*\.json$/, /i18n\/.*\.json$/],
42-
loader: 'file-loader',
43-
options: {
44-
name: 'static/media/[name].[hash:8].[ext]'
45-
},
46-
type: 'javascript/auto'
47-
},
48-
{
49-
test: /\.properties$/,
50-
use: 'file-loader'
51-
}
52-
]
53-
},
54-
resolve: {
55-
...config.resolve,
56-
extensions: [...config.resolve.extensions, '.ts', '.tsx', '.jsx'],
57-
alias: {
58-
...config.resolve.alias,
59-
'@shared': path.join(PATHS.root, 'shared'),
60-
'@ui5/webcomponents-react/lib': path.join(PATHS.root, 'packages', 'main', 'src', 'lib'),
61-
'@ui5/webcomponents-react-charts/lib': path.join(PATHS.root, 'packages', 'charts', 'src', 'lib'),
62-
'@ui5/webcomponents-react-base': path.join(PATHS.root, 'packages', 'base', 'src', 'index.ts')
36+
config.module.rules.push(
37+
tsLoader,
38+
{
39+
test: /\.(js|mjs)$/,
40+
exclude: /@babel(?:\/|\\{1,2})runtime/,
41+
loader: require.resolve('babel-loader'),
42+
options: {
43+
babelrc: false,
44+
configFile: false,
45+
compact: false,
46+
presets: [[require.resolve('babel-preset-react-app/dependencies'), { helpers: true }]],
47+
cacheDirectory: true,
48+
cacheCompression: false,
49+
50+
// If an error happens in a package, it's possible to be
51+
// because it was compiled. Thus, we don't want the browser
52+
// debugger to show the original code. Instead, the code
53+
// being evaluated would be much more helpful.
54+
sourceMaps: false
6355
}
56+
},
57+
{
58+
test: /\.properties$/,
59+
use: 'file-loader'
6460
}
61+
);
62+
63+
config.module.rules = [
64+
{
65+
oneOf: config.module.rules
66+
}
67+
];
68+
69+
config.resolve.extensions.push('.ts', '.tsx');
70+
config.resolve.alias = {
71+
...config.resolve.alias,
72+
'@shared': path.join(PATHS.root, 'shared'),
73+
'@ui5/webcomponents-react/lib': path.join(PATHS.root, 'packages', 'main', 'src', 'lib'),
74+
'@ui5/webcomponents-react-charts/lib': path.join(PATHS.root, 'packages', 'charts', 'src', 'lib'),
75+
'@ui5/webcomponents-react-base/lib': path.join(PATHS.root, 'packages', 'base', 'src', 'lib'),
76+
'@ui5/webcomponents-react-base/polyfill': path.join(PATHS.root, 'packages', 'base', 'npm', 'polyfill')
6577
};
78+
79+
return config;
6680
};
Lines changed: 52 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import boot from '@ui5/webcomponents-base/src/boot';
22
import { getCompactSize, getTheme } from '@ui5/webcomponents-base/src/Configuration';
33
import { injectThemeProperties } from '@ui5/webcomponents-base/src/theming/StyleInjection';
4-
import { createGenerateClassName, sap_fiori_3 } from '@ui5/webcomponents-react-base';
5-
import fiori3ThemeProperties from '@ui5/webcomponents/dist/themes/sap_fiori_3/parameters-bundle.css.json';
6-
import React, { Fragment, PureComponent, ReactNode } from 'react';
4+
import { createGenerateClassName, sap_fiori_3, Device } from '@ui5/webcomponents-react-base';
5+
import fiori3Theme from '@ui5/webcomponents/dist/generated/themes/sap_fiori_3/parameters-bundle.css.js';
6+
import React, { FC, Fragment, ReactNode, useEffect, useMemo } from 'react';
77
import { JssProvider, ThemeProvider as ReactJssThemeProvider } from 'react-jss';
88
import { ContentDensity } from '../../lib/ContentDensity';
99
import { MessageToast } from '../../lib/MessageToast';
@@ -16,47 +16,57 @@ export interface ThemeProviderProps {
1616

1717
const generateClassName = createGenerateClassName();
1818

19-
export class ThemeProvider extends PureComponent<ThemeProviderProps> {
20-
static defaultProps = {
21-
withToastContainer: false
22-
};
23-
24-
constructor(props) {
25-
super(props);
26-
boot().then((_) => {
27-
let existingThemingProperties = document.querySelector('head style[data-ui5-webcomponents-theme-properties]');
28-
if (!existingThemingProperties || !existingThemingProperties.innerHTML) {
29-
injectThemeProperties(fiori3ThemeProperties._);
19+
const ThemeProvider: FC<ThemeProviderProps> = (props) => {
20+
const theme = getTheme();
21+
useEffect(() => {
22+
boot().then(async () => {
23+
// TODO will rename to 'data-ui5-theme-properties' after next UI5 Web Components Release
24+
const styleElement = document.head.querySelector('style[data-ui5-webcomponents-theme-properties]');
25+
// only inject parameters for sap_fiori_3 and if they haven't been injected before
26+
if (theme === Themes.sap_fiori_3 && !styleElement.textContent) {
27+
injectThemeProperties(fiori3Theme);
28+
const CSSVarsPonyfill = window['CSSVarsPonyfill'];
29+
if (Device.browser.msie && CSSVarsPonyfill) {
30+
setTimeout(() => {
31+
CSSVarsPonyfill.resetCssVars();
32+
CSSVarsPonyfill.cssVars();
33+
}, 0);
34+
}
3035
}
3136
});
32-
}
37+
}, [theme]);
38+
const { withToastContainer, children } = props;
3339

34-
private static getTheme = (theme: Themes) => {
40+
const isCompactSize = getCompactSize();
41+
42+
const parameters = useMemo(() => {
3543
if (theme === Themes.sap_fiori_3) return sap_fiori_3;
3644
return null;
37-
};
38-
39-
private static getContentDensity = (compactSize: boolean) => {
40-
return compactSize ? ContentDensity.Compact : ContentDensity.Cozy;
41-
};
42-
43-
render() {
44-
const { withToastContainer } = this.props;
45-
return (
46-
<JssProvider generateId={generateClassName}>
47-
<ReactJssThemeProvider
48-
theme={{
49-
theme: getTheme(),
50-
contentDensity: ThemeProvider.getContentDensity(getCompactSize()),
51-
parameters: ThemeProvider.getTheme(getTheme())
52-
}}
53-
>
54-
<Fragment>
55-
{this.props.children}
56-
{withToastContainer && <MessageToast />}
57-
</Fragment>
58-
</ReactJssThemeProvider>
59-
</JssProvider>
60-
);
61-
}
62-
}
45+
}, [theme]);
46+
47+
const themeContext = useMemo(() => {
48+
return {
49+
theme,
50+
contentDensity: isCompactSize ? ContentDensity.Compact : ContentDensity.Cozy,
51+
parameters
52+
};
53+
}, [theme, isCompactSize, parameters]);
54+
55+
return (
56+
<JssProvider generateId={generateClassName}>
57+
<ReactJssThemeProvider theme={themeContext}>
58+
<Fragment>
59+
{children}
60+
{withToastContainer && <MessageToast />}
61+
</Fragment>
62+
</ReactJssThemeProvider>
63+
</JssProvider>
64+
);
65+
};
66+
67+
ThemeProvider.displayName = 'ThemeProvider';
68+
ThemeProvider.defaultProps = {
69+
withToastContainer: false
70+
};
71+
72+
export { ThemeProvider };

scripts/rollup/results.json

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,29 @@
44
"filename": "charts.development.js",
55
"bundleType": "NODE_ES_DEV",
66
"packageName": "charts",
7-
"size": 39708,
8-
"gzip": 7661
7+
"size": 39752,
8+
"gzip": 7671
99
},
1010
{
1111
"filename": "charts.production.min.js",
1212
"bundleType": "NODE_ES_PROD",
1313
"packageName": "charts",
14-
"size": 39604,
15-
"gzip": 7639
14+
"size": 39648,
15+
"gzip": 7649
1616
},
1717
{
1818
"filename": "charts.development.js",
1919
"bundleType": "NODE_DEV",
2020
"packageName": "charts",
21-
"size": 40469,
22-
"gzip": 7702
21+
"size": 40513,
22+
"gzip": 7711
2323
},
2424
{
2525
"filename": "charts.production.min.js",
2626
"bundleType": "NODE_PROD",
2727
"packageName": "charts",
28-
"size": 20060,
29-
"gzip": 6117
28+
"size": 20079,
29+
"gzip": 6122
3030
},
3131
{
3232
"filename": "base.development.js",
@@ -60,29 +60,29 @@
6060
"filename": "main.development.js",
6161
"bundleType": "NODE_ES_DEV",
6262
"packageName": "main",
63-
"size": 180706,
64-
"gzip": 33215
63+
"size": 184672,
64+
"gzip": 34502
6565
},
6666
{
6767
"filename": "main.production.min.js",
6868
"bundleType": "NODE_ES_PROD",
6969
"packageName": "main",
70-
"size": 180706,
71-
"gzip": 33215
70+
"size": 184672,
71+
"gzip": 34502
7272
},
7373
{
7474
"filename": "main.development.js",
7575
"bundleType": "NODE_DEV",
7676
"packageName": "main",
77-
"size": 186313,
78-
"gzip": 33339
77+
"size": 190406,
78+
"gzip": 34658
7979
},
8080
{
8181
"filename": "main.production.min.js",
8282
"bundleType": "NODE_PROD",
8383
"packageName": "main",
84-
"size": 95013,
85-
"gzip": 25174
84+
"size": 97719,
85+
"gzip": 26216
8686
}
8787
]
8888
}

0 commit comments

Comments
 (0)