Skip to content

Commit

Permalink
build: introduce TypeScript to the project
Browse files Browse the repository at this point in the history
  • Loading branch information
kopach committed May 5, 2021
1 parent c61cc6f commit 36cdff4
Show file tree
Hide file tree
Showing 15 changed files with 2,018 additions and 3,343 deletions.
8 changes: 0 additions & 8 deletions .babelrc

This file was deleted.

1 change: 0 additions & 1 deletion .npmignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
src
.babelrc
webpack.config.js
assets
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,5 +159,5 @@ But for implementation purposed use it like a regular child component.
# TODO

- ~Live Demos~
- Maybe Typescript this?
- ~Maybe Typescript this?~
- Test cases
3 changes: 2 additions & 1 deletion dist/build.js

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions dist/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import React from 'react';
declare type Mode = 'open' | 'element';
export declare const registerAsWebComponent: (component: React.ElementType, customElementName: string, mode?: Mode) => void;
export {};
6 changes: 6 additions & 0 deletions dist/prop-bridge.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import React from 'react';
export declare const renderReact2Node: (RComponent: React.ElementType, initialProps: {}, targetDomNode: Element | DocumentFragment, onRender: (ref: React.RefObject<any>) => void) => void;
export declare const sendPropsToReact: (propBridgeRef: React.RefObject<any>, props: any) => void;
export declare const getPropsFromNode: (node: HTMLElement) => {
[key: string]: string | JSX.Element;
};
7 changes: 7 additions & 0 deletions dist/react-dom-child.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from 'react';
import 'child-replace-with-polyfill';
export declare class ReactDomChild extends React.Component {
ref: React.RefObject<HTMLDivElement>;
componentDidMount(): void;
render(): JSX.Element;
}
5,116 changes: 1,861 additions & 3,255 deletions package-lock.json

Large diffs are not rendered by default.

23 changes: 12 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"name": "react-webcomponentify",
"version": "1.2.2",
"description": "Build and export React Components as Web Components without any extra effort.",
"main": "dist/build.js",
"main": "dist/build",
"typings": "dist/index",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack -p"
Expand All @@ -26,18 +27,18 @@
},
"homepage": "https://github.com/master-atul/react-webcomponentify#readme",
"dependencies": {
"child-replace-with-polyfill": "^1.0.1",
"react-create-ref": "^1.0.1"
"child-replace-with-polyfill": "1.0.1",
"react-create-ref": "1.0.1"
},
"devDependencies": {
"@babel/core": "^7.2.2",
"@babel/plugin-proposal-class-properties": "^7.3.0",
"@babel/plugin-syntax-class-properties": "^7.2.0",
"@babel/plugin-transform-react-jsx": "^7.3.0",
"@babel/preset-env": "^7.3.1",
"babel-loader": "^8.0.5",
"webpack": "^4.29.0",
"webpack-cli": "^3.2.1"
"@types/react": "17.0.4",
"@types/react-dom": "17.0.3",
"react": "17.0.2",
"react-dom": "17.0.2",
"ts-loader": "8.2.0",
"typescript": "4.2.4",
"webpack": "4.29.0",
"webpack-cli": "3.2.1"
},
"peerDependencies": {
"react": "*",
Expand Down
57 changes: 39 additions & 18 deletions src/index.js → src/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
import React from 'react';
import {
renderReact2Node,
getPropsFromNode,
sendPropsToReact
} from "./prop-bridge";
sendPropsToReact,
} from './prop-bridge';

const getCustomElementFromReactComponent = (RComponent, mode) => {
type Mode = 'open' | 'element';

const getCustomElementFromReactComponent = (
RComponent: React.ElementType,
mode?: Mode
) => {
return class ReactAsCustomElement extends HTMLElement {
targetNode = null;
propBridgeRef = null;
targetNode: this | ShadowRoot = null;
propBridgeRef: any = null;
props = {};
observer = null;
observer: MutationObserver = null;

constructor() {
super();
Expand All @@ -28,27 +34,38 @@ const getCustomElementFromReactComponent = (RComponent, mode) => {
break;
}

renderReact2Node(RComponent, this.props, this.targetNode, this._onReactMount);
renderReact2Node(
RComponent,
this.props,
this.targetNode,
this._onReactMount
);
}

setProps = newProps => {
setProps = (newProps: {}) => {
this.props = { ...this.props, ...newProps };
sendPropsToReact(this.propBridgeRef, this.props);
};

_onReactMount = propBridgeRef => {
_onReactMount = (propBridgeRef: React.RefObject<any>) => {
this.propBridgeRef = propBridgeRef;
this.setProps(this.props);
};

_onMutation = mutationsList => {
const newProps = mutationsList.reduce((props, mutation) => {
if (mutation.type === "attributes") {
const propKey = mutation.attributeName;
props[propKey] = this.getAttribute(propKey);
}
return props;
}, {});
_onMutation = (mutationsList: any[]) => {
const newProps = mutationsList.reduce(
(
props: { [x: string]: string },
mutation: { type: string; attributeName: string }
) => {
if (mutation.type === 'attributes') {
const propKey = mutation.attributeName;
props[propKey] = this.getAttribute(propKey);
}
return props;
},
{}
);
this.setProps(newProps);
};
/*
Expand All @@ -73,7 +90,11 @@ const getCustomElementFromReactComponent = (RComponent, mode) => {
- "open" - open shadow DOM
- "element" - no shadow DOM
*/
export const registerAsWebComponent = (component, customElementName, mode) => {
export const registerAsWebComponent = (
component: React.ElementType,
customElementName: string,
mode?: Mode
) => {
const ReactCustomElement = getCustomElementFromReactComponent(
component,
mode
Expand Down
39 changes: 23 additions & 16 deletions src/prop-bridge.js → src/prop-bridge.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import ReactDOM from "react-dom";
import React from "react";
import { ReactDomChild } from "./react-dom-child";
import createRef from "react-create-ref";
import ReactDOM from 'react-dom';
import React from 'react';
import { ReactDomChild } from './react-dom-child';
import createRef from 'react-create-ref';

/*
PropBridge stores props passed to it via setProps in the state.
Expand All @@ -11,36 +11,43 @@ and then passing those as props to the react component.
*/

export const renderReact2Node = (
RComponent,
initialProps,
targetDomNode,
onRender
RComponent: React.ElementType,
initialProps: {},
targetDomNode: Element | DocumentFragment,
onRender: (ref: React.RefObject<any>) => void
) => {
class PropBridge extends React.PureComponent {
state = { ...initialProps };
setProps = props => this.setState(() => props);
setProps = (props: React.RefObject<PropBridge>) =>
this.setState(() => props);
render() {
return <RComponent {...this.props} {...this.state} />;
}
}
const propBridgeRef = createRef();
const propBridgeRef = createRef<PropBridge>();
ReactDOM.render(<PropBridge ref={propBridgeRef} />, targetDomNode, () =>
onRender(propBridgeRef)
);
};

export const sendPropsToReact = (propBridgeRef, props) => {
export const sendPropsToReact = (
propBridgeRef: React.RefObject<any>,
props: any
) => {
if (propBridgeRef && propBridgeRef.current) {
propBridgeRef.current.setProps(props);
}
};

export const getPropsFromNode = node => {
export const getPropsFromNode = (node: HTMLElement) => {
const attributeNames = node.getAttributeNames();
const mappedProps = attributeNames.reduce((props, name) => {
props[name] = node.getAttribute(name);
return props;
}, {});
const mappedProps = attributeNames.reduce(
(props: { [key: string]: string | JSX.Element }, name: string) => {
props[name] = node.getAttribute(name);
return props;
},
{}
);

const children = Array.from(node.children).map((e) => e.cloneNode(true));
mappedProps.children = <ReactDomChild>{children}</ReactDomChild>;
Expand Down
11 changes: 6 additions & 5 deletions src/react-dom-child.js → src/react-dom-child.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import React from "react";
import "child-replace-with-polyfill";
import createRef from "react-create-ref";
import React from 'react';
import 'child-replace-with-polyfill';
import createRef from 'react-create-ref';

/*
Wrapper class to wrap the raw html nodes in a
react component before passing it down to react as children
*/
export class ReactDomChild extends React.Component {
ref = createRef();
ref = createRef<HTMLDivElement>();
componentDidMount() {
const childNodes = this.props.children;
const childNodes: Node[] = this.props.children as Node[];
this.ref.current.replaceWith(...childNodes);
}
render() {
Expand Down
9 changes: 9 additions & 0 deletions src/types/react-create-ref.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
declare module 'react-create-ref' {
import React from 'react';

type ReactCreateRef<T> = typeof React.createRef extends Function
? React.RefObject<T>
: () => { current: null };

export default function createRef<T>(): ReactCreateRef<T>;
}
20 changes: 20 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"compilerOptions": {
"outDir": "./dist/",
"declaration": true,
"noImplicitAny": true,
"module": "es6",
"sourceMap": true,
"target": "es6",
"allowSyntheticDefaultImports": true,
"jsx": "react",
"typeRoots": [
"node_modules/@types",
"src/types"
],
"lib": [
"ES2017",
"DOM"
]
}
}
55 changes: 28 additions & 27 deletions webpack.config.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,40 @@
var path = require("path");
var path = require('path');

module.exports = {
entry: "./src/index.js",
mode: "development",
entry: './src/index.ts',
devtool: 'inline-source-map',
mode: 'development',
resolve: {
extensions: ['.ts', '.js', '.tsx'],
},
output: {
path: path.resolve(__dirname, "dist"),
filename: "build.js",
libraryTarget: "commonjs2"
path: path.resolve(__dirname, 'dist'),
filename: 'build.js',
libraryTarget: 'commonjs2',
},
devtool: "none",
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: "babel-loader"
}
}
]
test: /\.tsx?/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
externals: {
react: {
root: "React",
commonjs2: "react",
commonjs: "react",
amd: "react",
umd: "react"
root: 'React',
commonjs2: 'react',
commonjs: 'react',
amd: 'react',
umd: 'react',
},
'react-dom': {
root: 'ReactDOM',
commonjs2: 'react-dom',
commonjs: 'react-dom',
amd: 'react-dom',
umd: 'react-dom',
},
"react-dom": {
root: "ReactDOM",
commonjs2: "react-dom",
commonjs: "react-dom",
amd: "react-dom",
umd: "react-dom"
}
}
},
};

0 comments on commit 36cdff4

Please sign in to comment.