Skip to content

Commit

Permalink
refactor(withWebComponent): new static wrapper & web components as pe…
Browse files Browse the repository at this point in the history
…er dependency (#412)

BREAKING CHANGE: the dependencies `@ui5/webcomponents`, `@ui5/webcomponents-fiori` and `@ui5/webcomponents-icons` are now  `peerDependencies` and have to be installed next to `@ui5/webcomponents-react`
  • Loading branch information
MarcusNotheis authored Apr 8, 2020
1 parent 4665db7 commit dca9b9a
Show file tree
Hide file tree
Showing 68 changed files with 1,075 additions and 445 deletions.
17 changes: 10 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,15 @@
"@storybook/cli": "5.3.18",
"@storybook/react": "5.3.18",
"@storybook/theming": "5.3.18",
"@ui5/webcomponents": "1.0.0-rc.6",
"@ui5/webcomponents-fiori": "1.0.0-rc.6",
"@ui5/webcomponents-icons": "1.0.0-rc.6",
"react-docgen-typescript-loader": "3.7.2"
},
"devDependencies": {
"@babel/core": "^7.8.7",
"@babel/core": "^7.9.0",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.0",
"@babel/plugin-proposal-optional-chaining": "^7.8.0",
"@babel/plugin-proposal-optional-chaining": "^7.9.0",
"@rollup/plugin-json": "^4.0.2",
"@rollup/plugin-node-resolve": "^7.1.1",
"@rollup/plugin-replace": "^2.3.1",
Expand All @@ -44,8 +47,8 @@
"@typescript-eslint/parser": "^2.19.0",
"@webcomponents/webcomponentsjs": "^2.4.2",
"babel-code-frame": "^6.26.0",
"babel-loader": "^8.0.5",
"babel-preset-react-app": "^9.1.1",
"babel-loader": "^8.1.0",
"babel-preset-react-app": "^9.1.2",
"chalk": "^3.0.0",
"cli-table": "^0.3.1",
"dedent": "^0.7.0",
Expand All @@ -59,7 +62,7 @@
"eslint-plugin-react": "^7.18.3",
"filesize": "^6.0.1",
"glob": "^7.1.6",
"google-closure-compiler": "^20200204.0.0",
"google-closure-compiler": "^20200315.0.0",
"gzip-size": "^5.1.0",
"husky": "^4.2.1",
"identity-obj-proxy": "^3.0.0",
Expand All @@ -71,7 +74,7 @@
"lerna": "^3.20.2",
"lint-staged": "^9.5.0",
"minimist": "^1.2.0",
"mkdirp": "^1.0.3",
"mkdirp": "^1.0.4",
"ncp": "^2.0.0",
"npm-run-all": "^4.1.5",
"prettier": "^1.19.1",
Expand All @@ -81,7 +84,7 @@
"rimraf": "^3.0.1",
"rollup": "^2.3.1",
"rollup-plugin-babel": "^4.3.2",
"rollup-plugin-prettier": "^0.6.0",
"rollup-plugin-prettier": "^0.7.0",
"rollup-plugin-strip-banner": "^2.0.0",
"shelljs": "^0.8.3",
"sinon": "^8.1.1",
Expand Down
8 changes: 5 additions & 3 deletions packages/main/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,15 @@
"license": "Apache-2.0",
"sideEffects": [
"@ui5/webcomponents-icons/dist/icons/*",
"@ui5/webcomponents/dist/*",
"@ui5/webcomponents-fiori/dist/*",
"*/ThemingSupport.js"
],
"scripts": {
"clean": "rimraf cjs components enums interfaces internal lib webComponents index.esm.js index.d.ts",
"postbuild": "rollup -c rollup.config.js"
},
"dependencies": {
"@ui5/webcomponents": "1.0.0-rc.6",
"@ui5/webcomponents-fiori": "1.0.0-rc.6",
"@ui5/webcomponents-icons": "1.0.0-rc.6",
"@ui5/webcomponents-react-base": "^0.9.0-rc.9",
"lodash.debounce": "^4.0.8",
"react-content-loader": "^5.0.2",
Expand All @@ -32,6 +31,9 @@
"react-window": "^1.8.5"
},
"peerDependencies": {
"@ui5/webcomponents": "1.0.0-rc.6",
"@ui5/webcomponents-fiori": "1.0.0-rc.6",
"@ui5/webcomponents-icons": "1.0.0-rc.6",
"react": "^16.8.0",
"react-dom": "^16.8.0"
},
Expand Down
96 changes: 89 additions & 7 deletions packages/main/scripts/create-web-components-wrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,64 @@ COMPONENTS_WITHOUT_DEMOS.add('ComboBoxItem');
COMPONENTS_WITHOUT_DEMOS.add('MultiComboBoxItem');
COMPONENTS_WITHOUT_DEMOS.add('SuggestionItem');

const TagNames = new Map();
TagNames.set('Avatar', 'ui5-avatar');
TagNames.set('Badge', 'ui5-badge');
TagNames.set('BusyIndicator', 'ui5-busyindicator');
TagNames.set('Button', 'ui5-button');
TagNames.set('Calendar', 'ui5-calendar');
TagNames.set('Card', 'ui5-card');
TagNames.set('Carousel', 'ui5-carousel');
TagNames.set('CheckBox', 'ui5-checkbox');
TagNames.set('ComboBox', 'ui5-combobox');
TagNames.set('ComboBoxItem', 'ui5-cb-item');
TagNames.set('CustomListItem', 'ui5-li-custom');
TagNames.set('DatePicker', 'ui5-datepicker');
TagNames.set('Dialog', 'ui5-dialog');
TagNames.set('FileUploader', 'ui5-file-uploader');
TagNames.set('GroupHeaderListItem', 'ui5-li-groupheader');
TagNames.set('Icon', 'ui5-icon');
TagNames.set('Input', 'ui5-input');
TagNames.set('Label', 'ui5-label');
TagNames.set('Link', 'ui5-link');
TagNames.set('List', 'ui5-list');
TagNames.set('MessageStrip', 'ui5-messagestrip');
TagNames.set('MultiComboBox', 'ui5-multi-combobox');
TagNames.set('MultiComboBoxItem', 'ui5-mcb-item');
TagNames.set('Option', 'ui5-option');
TagNames.set('Panel', 'ui5-panel');
TagNames.set('Popover', 'ui5-popover');
TagNames.set('ProductSwitch', 'ui5-product-switch');
TagNames.set('ProductSwitchItem', 'ui5-product-switch-item');
TagNames.set('RadioButton', 'ui5-radiobutton');
TagNames.set('ResponsivePopover', 'ui5-responsive-popover');
TagNames.set('SegmentedButton', 'ui5-segmentedbutton');
TagNames.set('Select', 'ui5-select');
TagNames.set('ShellBar', 'ui5-shellbar');
TagNames.set('ShellBarItem', 'ui5-shellbar-item');
TagNames.set('StandardListItem', 'ui5-li');
TagNames.set('SuggestionItem', 'ui5-suggestion-item');
TagNames.set('Switch', 'ui5-switch');
TagNames.set('Tab', 'ui5-tab');
TagNames.set('TabContainer', 'ui5-tabcontainer');
TagNames.set('Table', 'ui5-table');
TagNames.set('TableCell', 'ui5-table-cell');
TagNames.set('TableColumn', 'ui5-table-column');
TagNames.set('TableRow', 'ui5-table-row');
TagNames.set('TabSeparator', 'ui5-tab-separator');
TagNames.set('TextArea', 'ui5-textarea');
TagNames.set('Timeline', 'ui5-timeline');
TagNames.set('TimelineItem', 'ui5-timeline-item');
TagNames.set('TimePicker', 'ui5-timepicker');
TagNames.set('Title', 'ui5-title');
TagNames.set('Toast', 'ui5-toast');
TagNames.set('ToggleButton', 'ui5-togglebutton');

const componentsFromFioriPackage = new Set(fioriWebComponentsSpec.symbols.map((componentSpec) => componentSpec.module));

const capitalizeFirstLetter = (s) => s.charAt(0).toUpperCase() + s.slice(1);
const filterNonPublicAttributes = (prop) =>
prop.visibility === 'public' && prop.readonly !== 'true' && prop.static !== true;

const getTypeScriptTypeForProperty = (property) => {
switch (property.type) {
Expand Down Expand Up @@ -259,11 +314,20 @@ const getEventParameters = (parameters) => {
};
};

const createWebComponentWrapper = (name, types, importStatements, defaultProps) => {
const createWebComponentWrapper = (
name,
types,
importStatements,
defaultProps,
regularProps,
booleanProps,
slotProps,
eventProps
) => {
return prettier.format(
`
import { withWebComponent } from '@ui5/webcomponents-react/lib/withWebComponent';
import UI5${name} from '@ui5/webcomponents${componentsFromFioriPackage.has(name) ? '-fiori' : ''}/dist/${name}';
import '@ui5/webcomponents${componentsFromFioriPackage.has(name) ? '-fiori' : ''}/dist/${name}';
import React, { FC } from 'react';
import { WithWebComponentPropTypes } from '../../internal/withWebComponent';
${importStatements.join('\n')}
Expand All @@ -277,7 +341,16 @@ const createWebComponentWrapper = (name, types, importStatements, defaultProps)
* <br />
* <a href="https://sap.github.io/ui5-webcomponents/playground/components/${name}" target="_blank">UI5 Web Components Playground</a>
*/
const ${name}: FC<${name}PropTypes> = withWebComponent<${name}PropTypes>(UI5${name});
const ${name}: FC<${name}PropTypes> = withWebComponent<${name}PropTypes>(
'${TagNames.get(name)}',
[${regularProps.map((v) => `'${v}'`).join(', ')}],
[${booleanProps.map((v) => `'${v}'`).join(', ')}],
[${slotProps
.filter((name) => name !== 'children')
.map((v) => `'${v}'`)
.join(', ')}],
[${eventProps.map((v) => `'${v}'`).join(', ')}]
);
${name}.displayName = '${name}';
Expand Down Expand Up @@ -525,17 +598,26 @@ resolvedWebComponents.forEach((componentSpec) => {
componentSpec.module,
propTypes,
uniqueAdditionalImports,
defaultProps
defaultProps,
(componentSpec.properties || [])
.filter(filterNonPublicAttributes)
.filter(({ type }) => type !== 'boolean' && type !== 'Boolean')
.map(({ name }) => name),
(componentSpec.properties || [])
.filter(filterNonPublicAttributes)
.filter(({ type }) => type === 'boolean' || type === 'Boolean')
.map(({ name }) => name),
(componentSpec.slots || []).filter(filterNonPublicAttributes).map(({ name }) => name),
(componentSpec.events || []).filter(filterNonPublicAttributes).map(({ name }) => name)
);

// check if folder exists and create it if necessary
const webComponentFolderPath = path.join(WEB_COMPONENTS_ROOT_DIR, componentSpec.module);
if (!fs.existsSync(webComponentFolderPath)) {
fs.mkdirSync(webComponentFolderPath);
}
if (!fs.existsSync(path.join(webComponentFolderPath, 'index.tsx'))) {
fs.writeFileSync(path.join(webComponentFolderPath, 'index.tsx'), webComponentWrapper);
}

fs.writeFileSync(path.join(webComponentFolderPath, 'index.tsx'), webComponentWrapper);

// create test
if (!fs.existsSync(path.join(webComponentFolderPath, `${componentSpec.module}.test.tsx`))) {
Expand Down
3 changes: 0 additions & 3 deletions packages/main/src/interfaces/DynamicObjectList.ts

This file was deleted.

5 changes: 0 additions & 5 deletions packages/main/src/interfaces/Ui5Property.ts

This file was deleted.

14 changes: 0 additions & 14 deletions packages/main/src/interfaces/Ui5WebComponentMetadata.ts

This file was deleted.

5 changes: 2 additions & 3 deletions packages/main/src/internal/WithWebComponent.test.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { mount } from 'enzyme';
import { Button } from '@ui5/webcomponents-react/lib/Button';
import React, { cloneElement, FC } from 'react';
import { mount } from 'enzyme';
import React from 'react';
import { spy } from 'sinon';
import { withWebComponent } from './withWebComponent';

describe('withWebComponent', () => {
test('Unmount Event Handlers correctly after prop update', () => {
Expand Down
Loading

0 comments on commit dca9b9a

Please sign in to comment.