Skip to content

Commit 8a53747

Browse files
committed
Added React Wrapper Output Target
1 parent ac56cc4 commit 8a53747

20 files changed

+791
-39
lines changed

.eslintrc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@
99
"rules": {
1010
"@stencil-community/strict-boolean-conditions": "off",
1111
"react/jsx-no-bind": "off"
12-
}
12+
},
13+
"ignorePatterns": ["*.config.ts", "react-library/*"]
1314
}

package-lock.json

Lines changed: 29 additions & 25 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "data-view-web-component",
3-
"version": "0.0.10",
3+
"version": "0.0.11",
44
"description": "Generic Web Component used to display various hierarchical data in a card format",
55
"main": "dist/index.cjs.js",
66
"module": "dist/index.js",
@@ -35,6 +35,7 @@
3535
},
3636
"devDependencies": {
3737
"@stencil-community/eslint-plugin": "^0.7.2",
38+
"@stencil/react-output-target": "^0.5.3",
3839
"@storybook/addon-essentials": "^7.6.7",
3940
"@storybook/addon-links": "^7.6.7",
4041
"@storybook/addon-mdx-gfm": "^7.6.7",
@@ -43,6 +44,7 @@
4344
"@storybook/web-components-vite": "^7.6.7",
4445
"@types/jest": "^29.5.6",
4546
"@types/node": "^16.18.11",
47+
"@types/react": "^18.3.1",
4648
"@typescript-eslint/eslint-plugin": "^6",
4749
"@typescript-eslint/parser": "^6",
4850
"eslint": "^8.57.0",
@@ -51,8 +53,8 @@
5153
"jest-cli": "^29.7.0",
5254
"lit": "^3.0.2",
5355
"puppeteer": "21.1.1",
54-
"react": "^18.2.0",
55-
"react-dom": "^18.2.0",
56+
"react": "^18.3.1",
57+
"react-dom": "^18.3.1",
5658
"storybook": "^7.6.7",
5759
"typescript": "^5.4.5"
5860
},
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/* eslint-disable */
2+
/* tslint:disable */
3+
/* auto-generated react proxies */
4+
import { createReactComponent } from './react-component-lib';
5+
6+
import type { JSX } from 'data-view-web-component';
7+
8+
import { defineCustomElements } from 'data-view-web-component/loader';
9+
10+
defineCustomElements();
11+
export const DataCard = /*@__PURE__*/createReactComponent<JSX.DataCard, HTMLDataCardElement>('data-card');
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import React, { createElement } from 'react';
2+
3+
import { attachProps, camelToDashCase, createForwardRef, dashToPascalCase, isCoveredByReact, mergeRefs } from './utils';
4+
5+
export interface HTMLStencilElement extends HTMLElement {
6+
componentOnReady(): Promise<this>;
7+
}
8+
9+
interface StencilReactInternalProps<ElementType> extends React.HTMLAttributes<ElementType> {
10+
forwardedRef: React.RefObject<ElementType>;
11+
ref?: React.Ref<any>;
12+
}
13+
14+
export const createReactComponent = <
15+
PropType,
16+
ElementType extends HTMLStencilElement,
17+
ContextStateType = {},
18+
ExpandedPropsTypes = {}
19+
>(
20+
tagName: string,
21+
ReactComponentContext?: React.Context<ContextStateType>,
22+
manipulatePropsFunction?: (
23+
originalProps: StencilReactInternalProps<ElementType>,
24+
propsToPass: any
25+
) => ExpandedPropsTypes,
26+
defineCustomElement?: () => void
27+
) => {
28+
if (defineCustomElement !== undefined) {
29+
defineCustomElement();
30+
}
31+
32+
const displayName = dashToPascalCase(tagName);
33+
const ReactComponent = class extends React.Component<StencilReactInternalProps<ElementType>> {
34+
componentEl!: ElementType;
35+
36+
setComponentElRef = (element: ElementType) => {
37+
this.componentEl = element;
38+
};
39+
40+
constructor(props: StencilReactInternalProps<ElementType>) {
41+
super(props);
42+
}
43+
44+
componentDidMount() {
45+
this.componentDidUpdate(this.props);
46+
}
47+
48+
componentDidUpdate(prevProps: StencilReactInternalProps<ElementType>) {
49+
attachProps(this.componentEl, this.props, prevProps);
50+
}
51+
52+
render() {
53+
const { children, forwardedRef, style, className, ref, ...cProps } = this.props;
54+
55+
let propsToPass = Object.keys(cProps).reduce((acc: any, name) => {
56+
const value = (cProps as any)[name];
57+
58+
if (name.indexOf('on') === 0 && name[2] === name[2].toUpperCase()) {
59+
const eventName = name.substring(2).toLowerCase();
60+
if (typeof document !== 'undefined' && isCoveredByReact(eventName)) {
61+
acc[name] = value;
62+
}
63+
} else {
64+
// we should only render strings, booleans, and numbers as attrs in html.
65+
// objects, functions, arrays etc get synced via properties on mount.
66+
const type = typeof value;
67+
68+
if (type === 'string' || type === 'boolean' || type === 'number') {
69+
acc[camelToDashCase(name)] = value;
70+
}
71+
}
72+
return acc;
73+
}, {} as ExpandedPropsTypes);
74+
75+
if (manipulatePropsFunction) {
76+
propsToPass = manipulatePropsFunction(this.props, propsToPass);
77+
}
78+
79+
const newProps: Omit<StencilReactInternalProps<ElementType>, 'forwardedRef'> = {
80+
...propsToPass,
81+
ref: mergeRefs(forwardedRef, this.setComponentElRef),
82+
style,
83+
};
84+
85+
/**
86+
* We use createElement here instead of
87+
* React.createElement to work around a
88+
* bug in Vite (https://github.com/vitejs/vite/issues/6104).
89+
* React.createElement causes all elements to be rendered
90+
* as <tagname> instead of the actual Web Component.
91+
*/
92+
return createElement(tagName, newProps, children);
93+
}
94+
95+
static get displayName() {
96+
return displayName;
97+
}
98+
};
99+
100+
// If context was passed to createReactComponent then conditionally add it to the Component Class
101+
if (ReactComponentContext) {
102+
ReactComponent.contextType = ReactComponentContext;
103+
}
104+
105+
return createForwardRef<PropType, ElementType>(ReactComponent, displayName);
106+
};

0 commit comments

Comments
 (0)