From 7a8623a947ae2b5ed83d93b4b3342433559468d9 Mon Sep 17 00:00:00 2001 From: Tycho Bokdam Date: Wed, 6 Jan 2021 16:09:19 +0100 Subject: [PATCH 1/5] feat: You can also register React components directly --- src/abode.ts | 17 +++++++++++++---- src/index.ts | 1 + 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/abode.ts b/src/abode.ts index 6244f98..a915142 100644 --- a/src/abode.ts +++ b/src/abode.ts @@ -1,5 +1,5 @@ import { render } from 'react-dom'; -import { createElement } from 'react'; +import { createElement, FC } from 'react'; interface RegisteredComponents { [key: string]: Promise; @@ -18,11 +18,15 @@ interface PopulateOptions { callback?: Function; } +export type RegisterPromise = () => Promise +export type RegisterComponent = () => FC +export type RegisterFN = RegisterPromise | RegisterComponent + export let componentSelector = 'data-component'; export let components: RegisteredComponents = {}; export let unPopulatedElements: Element[] = []; -export const register = (name: string, fn: () => Promise) => { +export const register = (name: string, fn: RegisterFN) => { components[name] = retry(fn, 10, 20); }; @@ -53,6 +57,10 @@ export const setComponentSelector = (selector: string) => { componentSelector = selector; }; +export const getRegisteredComponents = () => { + return components +}; + export const getActiveComponents = () => { return Array.from( new Set(getAbodeElements().map(el => el.getAttribute(componentSelector))) @@ -120,8 +128,9 @@ export const renderAbode = async (el: Element) => { throw new Error(`no component registered for ${componentName}`); } - // @ts-ignore - render(createElement(module.default, props), el); + const element = module.default || module; + + render(createElement(element, props), el); }; export const trackPropChanges = (el: Element) => { diff --git a/src/index.ts b/src/index.ts index 3d6ea69..827064e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,5 +3,6 @@ export { setComponentSelector, register, getScriptProps, + getRegisteredComponents, getActiveComponents, } from './abode'; From 48b97cf59b72076766661676bcb67feb184060df Mon Sep 17 00:00:00 2001 From: Tycho Bokdam Date: Wed, 6 Jan 2021 16:15:33 +0100 Subject: [PATCH 2/5] test: Added tests --- package.json | 2 +- src/abode.ts | 8 ++++---- test/abode.test.tsx | 7 +++++++ 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 26835ac..5f507cf 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "0.1.7", + "version": "0.2.0", "license": "MIT", "repository": { "type": "git", diff --git a/src/abode.ts b/src/abode.ts index a915142..eb0bf5d 100644 --- a/src/abode.ts +++ b/src/abode.ts @@ -18,9 +18,9 @@ interface PopulateOptions { callback?: Function; } -export type RegisterPromise = () => Promise -export type RegisterComponent = () => FC -export type RegisterFN = RegisterPromise | RegisterComponent +export type RegisterPromise = () => Promise; +export type RegisterComponent = () => FC; +export type RegisterFN = RegisterPromise | RegisterComponent; export let componentSelector = 'data-component'; export let components: RegisteredComponents = {}; @@ -58,7 +58,7 @@ export const setComponentSelector = (selector: string) => { }; export const getRegisteredComponents = () => { - return components + return components; }; export const getActiveComponents = () => { diff --git a/test/abode.test.tsx b/test/abode.test.tsx index b2e3fad..08cc20b 100644 --- a/test/abode.test.tsx +++ b/test/abode.test.tsx @@ -106,6 +106,12 @@ describe('exported functions', () => { expect(typeof promise.then).toEqual('function'); const module = await promise; expect(Object.keys(module)).toEqual(['default']); + + register('TestComponent2', () => import('./TestComponent')); + expect(Object.keys(components)).toEqual(['TestComponent', 'TestComponent2']); + expect(Object.values(components).length).toEqual(2); + const component = Object.values(components)[1]; + expect(typeof component).toEqual('function'); }); it('populate', async () => { @@ -126,6 +132,7 @@ describe('exported functions', () => { ); }); + it.skip('getRegisteredComponents', () => {}); it.skip('getActiveComponents', () => {}); it.skip('setComponentSelector', () => {}); it.skip('register', () => {}); From b9284c1631818c9c0aa3e4654167b7747c57ddc5 Mon Sep 17 00:00:00 2001 From: Tycho Bokdam Date: Thu, 7 Jan 2021 07:56:34 +0100 Subject: [PATCH 3/5] test: Added tests --- package.json | 8 ++++---- test/abode.test.tsx | 37 ++++++++++++++++++++++++++++--------- yarn.lock | 30 ++++++++++++++---------------- 3 files changed, 46 insertions(+), 29 deletions(-) diff --git a/package.json b/package.json index 5f507cf..93c2fc0 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,10 @@ "name": "react-abode", "author": "Bram Kaashoek", "module": "dist/react-abode.esm.js", + "dependencies": { + "react": ">=16", + "react-dom": ">=16" + }, "devDependencies": { "@types/react": "^16.9.23", "@types/react-dom": "^16.9.5", @@ -44,10 +48,6 @@ "tslib": "^2.0.0", "typescript": "^3.9.7" }, - "peerDependencies": { - "react": ">=16", - "react-dom": ">=16" - }, "resolutions": { "serialize-javascript": "^3.1.0" } diff --git a/test/abode.test.tsx b/test/abode.test.tsx index 08cc20b..668b9f1 100644 --- a/test/abode.test.tsx +++ b/test/abode.test.tsx @@ -1,6 +1,7 @@ import { getCleanPropName, getAbodeElements, + getRegisteredComponents, unPopulatedElements, setUnpopulatedElements, getElementProps, @@ -12,6 +13,8 @@ import { populate, delay, } from '../src/abode'; +// @ts-ignore +import TestComponent from './TestComponent' import 'mutationobserver-shim'; global.MutationObserver = window.MutationObserver; @@ -102,37 +105,53 @@ describe('exported functions', () => { register('TestComponent', () => import('./TestComponent')); expect(Object.keys(components)).toEqual(['TestComponent']); expect(Object.values(components).length).toEqual(1); - const promise = Object.values(components)[0]; + let promise = Object.values(components)[0]; expect(typeof promise.then).toEqual('function'); - const module = await promise; + let module = await promise; + expect(typeof module).toEqual('object') expect(Object.keys(module)).toEqual(['default']); - register('TestComponent2', () => import('./TestComponent')); + register('TestComponent2', () => TestComponent); expect(Object.keys(components)).toEqual(['TestComponent', 'TestComponent2']); expect(Object.values(components).length).toEqual(2); - const component = Object.values(components)[1]; - expect(typeof component).toEqual('function'); + promise = Object.values(components)[1]; + expect(typeof promise.then).toEqual('function'); + module = await promise; + expect(typeof module).toEqual('function'); }); it('populate', async () => { const abodeElement = document.createElement('div'); abodeElement.setAttribute('data-component', 'TestComponent'); + const abodeSecondElement = document.createElement('div'); + abodeSecondElement.setAttribute('data-component', 'TestComponent2'); document.body.appendChild(abodeElement); + document.body.appendChild(abodeSecondElement); expect(document.body.innerHTML).toEqual( - `
` + `
` ); register('TestComponent', () => import('./TestComponent')); - populate(); + register('TestComponent2', () => TestComponent); + await populate(); await delay(20); expect(document.body.innerHTML).toEqual( - `
testing 1 2 3
` + `
testing 1 2 3
` + + `
testing 1 2 3
` ); }); - it.skip('getRegisteredComponents', () => {}); + it('getRegisteredComponents', () => { + register('TestComponent', () => import('./TestComponent')); + register('TestComponent2', () => TestComponent); + + const registeredComponents = getRegisteredComponents(); + + expect(Object.keys(registeredComponents).length).toEqual(2); + }); + it.skip('getActiveComponents', () => {}); it.skip('setComponentSelector', () => {}); it.skip('register', () => {}); diff --git a/yarn.lock b/yarn.lock index 9ddf2e7..fb36400 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4679,7 +4679,7 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.4" -prop-types@^15.6.2, prop-types@^15.7.2: +prop-types@^15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== @@ -4718,29 +4718,27 @@ randombytes@^2.1.0: dependencies: safe-buffer "^5.1.0" -react-dom@^16.13.1: - version "16.13.1" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.13.1.tgz#c1bd37331a0486c078ee54c4740720993b2e0e7f" - integrity sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag== +react-dom@>=16: + version "17.0.1" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.1.tgz#1de2560474ec9f0e334285662ede52dbc5426fc6" + integrity sha512-6eV150oJZ9U2t9svnsspTMrWNyHc6chX0KzDeAOXftRa8bNeOKTTfCJ7KorIwenkHd2xqVTBTCZd79yk/lx/Ug== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" - prop-types "^15.6.2" - scheduler "^0.19.1" + scheduler "^0.20.1" react-is@^16.8.1, react-is@^16.8.4: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== -react@^16.13.1: - version "16.13.1" - resolved "https://registry.yarnpkg.com/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e" - integrity sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w== +react@>=16: + version "17.0.1" + resolved "https://registry.yarnpkg.com/react/-/react-17.0.1.tgz#6e0600416bd57574e3f86d92edba3d9008726127" + integrity sha512-lG9c9UuMHdcAexXtigOZLX8exLWkW0Ku29qPRU8uhF2R9BN96dLCt0psvzPLlHc5OWkgymP3qwTRgbnw5BKx3w== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" - prop-types "^15.6.2" read-pkg-up@^2.0.0: version "2.0.0" @@ -5132,10 +5130,10 @@ sax@^1.2.4: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== -scheduler@^0.19.1: - version "0.19.1" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196" - integrity sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA== +scheduler@^0.20.1: + version "0.20.1" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.1.tgz#da0b907e24026b01181ecbc75efdc7f27b5a000c" + integrity sha512-LKTe+2xNJBNxu/QhHvDR14wUXHRQbVY5ZOYpOGWRzhydZUqrLb2JBvLPY7cAqFmqrWuDED0Mjk7013SZiOz6Bw== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" From d64a13706323a1e3966cfade41465752e0f3f3c6 Mon Sep 17 00:00:00 2001 From: Tycho Bokdam Date: Thu, 7 Jan 2021 07:57:50 +0100 Subject: [PATCH 4/5] refactor: Fix linting --- test/abode.test.tsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/test/abode.test.tsx b/test/abode.test.tsx index 668b9f1..9de1086 100644 --- a/test/abode.test.tsx +++ b/test/abode.test.tsx @@ -14,7 +14,7 @@ import { delay, } from '../src/abode'; // @ts-ignore -import TestComponent from './TestComponent' +import TestComponent from './TestComponent'; import 'mutationobserver-shim'; global.MutationObserver = window.MutationObserver; @@ -108,11 +108,14 @@ describe('exported functions', () => { let promise = Object.values(components)[0]; expect(typeof promise.then).toEqual('function'); let module = await promise; - expect(typeof module).toEqual('object') + expect(typeof module).toEqual('object'); expect(Object.keys(module)).toEqual(['default']); register('TestComponent2', () => TestComponent); - expect(Object.keys(components)).toEqual(['TestComponent', 'TestComponent2']); + expect(Object.keys(components)).toEqual([ + 'TestComponent', + 'TestComponent2', + ]); expect(Object.values(components).length).toEqual(2); promise = Object.values(components)[1]; expect(typeof promise.then).toEqual('function'); @@ -139,7 +142,7 @@ describe('exported functions', () => { expect(document.body.innerHTML).toEqual( `
testing 1 2 3
` + - `
testing 1 2 3
` + `
testing 1 2 3
` ); }); From e9350307a42703b0723864fe25d0bf66ecc8b697 Mon Sep 17 00:00:00 2001 From: Tycho Bokdam Date: Thu, 7 Jan 2021 10:24:48 +0100 Subject: [PATCH 5/5] docs(README): Added info about getRegisteredComponents and example for register --- README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 612495c..17e6321 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,13 @@ const Cart = (): JSX.Element => { // src/App.tsx import { populate, register } from 'react-abode'; -register('Cart', () => import('./modules/Cart/Cart')); // Each module must have the component you want to render as a default export +// Import can be used to reguster component +register('Cart', () => import('./modules/Cart/Cart')); + +// Component can also be used directly +import Cart from './modules/Cart/Cart' + +register('Cart', () => Cart); populate({ attributes: { classname: 'some-class-name' } }); ``` @@ -79,6 +85,10 @@ If you do not want to use `data-component` you can change the component selector You can use `getActiveComponents` to get a list of all Abode elements currently in your DOM. +#### getRegisteredComponents + +You can use `getRegisteredComponents` to get all registered components. + ### Populate parameters The `populate` function can be passed an object with options.