Skip to content

Commit

Permalink
feat: Support template children
Browse files Browse the repository at this point in the history
  • Loading branch information
aki77 committed Sep 30, 2021
1 parent 61085f2 commit bd8e741
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 33 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ You can then use this element in an HTML file:
<my-component-with-children>
<div class="alert">Hello, world!</div>
</my-component-with-children>

<!-- OR -->
<my-component-with-children>
<template>
<div class="alert">Hello, world!</div>
</template>
</my-component-with-children>
```

## Limitation
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@sonicgarden/rewrap",
"version": "0.1.0",
"version": "0.2.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"author": "aki77",
Expand Down
64 changes: 32 additions & 32 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react'
import ReactDOM from 'react-dom'

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type Component = React.FunctionComponent<any> | React.ComponentClass<any>

const fragmentToReactElement = (fragment: DocumentFragment) => {
Expand All @@ -15,30 +16,37 @@ const getChildren = (el: HTMLElement) => {

const fragment = document.createDocumentFragment()
while (el.childNodes.length > 0) {
fragment.append(el.childNodes[0])
if (el.childNodes[0].nodeName !== 'TEMPLATE') {
fragment.append(el.childNodes[0])
continue
}
const div = document.createElement('div')
div.innerHTML = (el.childNodes[0] as HTMLTemplateElement).innerHTML
fragment.append(div)
el.childNodes[0].remove()
}
return fragmentToReactElement(fragment)
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const getProps = (element: HTMLElement): any => {
const json = element.dataset.props
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if (!json) return {} as any

return JSON.parse(json)
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const render = (root: HTMLElement, component: Component, props: any) => {
const elem = React.createElement(component, props)
ReactDOM.render(elem, root)
}

const defineRewrapComponent = (
name: string,
connectedCallback: (this:HTMLElement) => void
): void => {
const defineRewrapComponent = (name: string, connectedCallback: (el: HTMLElement) => void): void => {
class RewrapElement extends HTMLElement {
connectedCallback() {
connectedCallback.call(this)
connectedCallback(this)
}

disconnectedCallback() {
Expand All @@ -49,40 +57,32 @@ const defineRewrapComponent = (
window.customElements.define(name, RewrapElement)
}

export const rewrap = (
name: string,
component: Component,
hasChildren = false
): void => {
defineRewrapComponent(name, function() {
const props = getProps(this)
export const rewrap = (name: string, component: Component, hasChildren = false): void => {
defineRewrapComponent(name, (el) => {
const props = getProps(el)

if (!hasChildren) {
return render(this, component, props)
}
if (!hasChildren) {
return render(el, component, props)
}

// NOTE: Wait for children to render
window.setTimeout(() => {
render(this, component, {
...props,
children: getChildren(this),
})
}, 0)
// NOTE: Wait for children to render
window.setTimeout(() => {
render(el, component, {
...props,
children: getChildren(el),
})
}, 0)
})
}

export const asyncRewrap = (
name: string,
component: () => Promise<Component>,
hasChildren = false
): void => {
defineRewrapComponent(name, async function() {
const props = getProps(this)
export const asyncRewrap = (name: string, component: () => Promise<Component>, hasChildren = false): void => {
defineRewrapComponent(name, async (el) => {
const props = getProps(el)
const resolvedComponent = await component()

render(this, resolvedComponent, {
render(el, resolvedComponent, {
...props,
...(hasChildren ? { children: getChildren(this) } : {})
...(hasChildren ? { children: getChildren(el) } : {}),
})
})
}

0 comments on commit bd8e741

Please sign in to comment.