From d2fbc5943c9909ad49efb67cb7d0d0a319146900 Mon Sep 17 00:00:00 2001 From: Kevin Bulteel Date: Wed, 10 Jan 2024 18:31:54 +0100 Subject: [PATCH] fix: nested component property forwarding --- .../ui/example/nested-component/a.html | 5 +- .../@hec.js/ui/example/nested-component/a.js | 4 +- .../@hec.js/ui/example/nested-component/b.js | 4 +- .../ui/example/nested-component/c.html | 1 + .../@hec.js/ui/example/nested-component/c.js | 8 ++++ .../ui/example/nested-component/index.html | 1 + packages/@hec.js/ui/lib/src/component.js | 18 ++++--- .../@hec.js/ui/lib/src/plugins/data-for.js | 1 - packages/@hec.js/ui/lib/src/props.js | 47 ++++++++++++++++++- packages/@hec.js/ui/lib/src/template.js | 12 ++--- 10 files changed, 77 insertions(+), 24 deletions(-) create mode 100644 packages/@hec.js/ui/example/nested-component/c.html create mode 100644 packages/@hec.js/ui/example/nested-component/c.js diff --git a/packages/@hec.js/ui/example/nested-component/a.html b/packages/@hec.js/ui/example/nested-component/a.html index 4324b10..f381854 100644 --- a/packages/@hec.js/ui/example/nested-component/a.html +++ b/packages/@hec.js/ui/example/nested-component/a.html @@ -1,2 +1,5 @@
{{ text }}
- \ No newline at end of file + + + + \ No newline at end of file diff --git a/packages/@hec.js/ui/example/nested-component/a.js b/packages/@hec.js/ui/example/nested-component/a.js index 0ffa727..4cf9cde 100644 --- a/packages/@hec.js/ui/example/nested-component/a.js +++ b/packages/@hec.js/ui/example/nested-component/a.js @@ -1,6 +1,8 @@ import { component, templateByName } from '../../lib/index.js'; component('c-a', { text: 'Hi' }, (props) => { + + const list = Array.from({ length: 2 }, () => ({ text: props.text })); - return templateByName('./a.html', props); + return templateByName('./a.html', { list, text: props.text }); }); \ No newline at end of file diff --git a/packages/@hec.js/ui/example/nested-component/b.js b/packages/@hec.js/ui/example/nested-component/b.js index fbb7101..47922ae 100644 --- a/packages/@hec.js/ui/example/nested-component/b.js +++ b/packages/@hec.js/ui/example/nested-component/b.js @@ -2,5 +2,7 @@ import { component, templateByName } from '../../lib/index.js'; component('c-b', { text: '' }, (props) => { - return templateByName('./b.html', props); + return templateByName('./b.html', { + text: () => props.text() + }); }); \ No newline at end of file diff --git a/packages/@hec.js/ui/example/nested-component/c.html b/packages/@hec.js/ui/example/nested-component/c.html new file mode 100644 index 0000000..59883e9 --- /dev/null +++ b/packages/@hec.js/ui/example/nested-component/c.html @@ -0,0 +1 @@ +
Hi nested object named: {{ text }}
\ No newline at end of file diff --git a/packages/@hec.js/ui/example/nested-component/c.js b/packages/@hec.js/ui/example/nested-component/c.js new file mode 100644 index 0000000..40a349c --- /dev/null +++ b/packages/@hec.js/ui/example/nested-component/c.js @@ -0,0 +1,8 @@ +import { component, templateByName } from '../../lib/index.js'; + +component('c-c', { person: { text: '' } }, (props) => { + + return templateByName('./c.html', { + text: () => props.person().text + }); +}); \ No newline at end of file diff --git a/packages/@hec.js/ui/example/nested-component/index.html b/packages/@hec.js/ui/example/nested-component/index.html index 8c123d2..eb588a0 100644 --- a/packages/@hec.js/ui/example/nested-component/index.html +++ b/packages/@hec.js/ui/example/nested-component/index.html @@ -6,6 +6,7 @@ hec.js :: Component + diff --git a/packages/@hec.js/ui/lib/src/component.js b/packages/@hec.js/ui/lib/src/component.js index 17a4cf2..fa69910 100644 --- a/packages/@hec.js/ui/lib/src/component.js +++ b/packages/@hec.js/ui/lib/src/component.js @@ -1,5 +1,5 @@ import { notifyVisible } from "./notify/visible.js"; -import { f, nodeProps, prop, propsOf } from "./props.js"; +import { deletePropsOf, f, prop, propsOf, setPropsOf } from "./props.js"; import { isSignal, signal } from "./signal.js"; /** @@ -72,11 +72,9 @@ export function component(name, props, fn) { /** @param { Node } node */ const append = (node) => { - const exProps = nodeProps.get(this); - - nodeProps.set( - this, Object.assign(propsOf(node), (typeof exProps === 'object' ? exProps : null) ?? {}) - ); + console.log(this.localName); + + setPropsOf(this, propsOf(node)); this.dispatchEvent(new CustomEvent('::loaded', { bubbles: true })); @@ -84,7 +82,7 @@ export function component(name, props, fn) { this.#aborts['::attributes'] = new AbortController(); - for (const k in this.#signals) { + for (const k in props) { if (!this.hasAttribute(k)) { this.setAttribute(k, props[k].toString()); @@ -102,7 +100,7 @@ export function component(name, props, fn) { } disconnectedCallback() { - nodeProps.delete(this); + deletePropsOf(this); for (const k in this.#aborts) { this.#aborts[k].abort(); @@ -138,8 +136,8 @@ export function component(name, props, fn) { if (value.startsWith('@parent.')) { // @ts-ignore const parent = this.parentNode.host || this.parentNode, - parentProps = propsOf(parent), - parentProp = prop(parentProps, value.slice(8)); + key = value.slice(8), + parentProp = prop(propsOf(parent), key) ?? prop(propsOf(this), key); if (isSignal(parentProp)) { this.#aborts[p]?.abort(); diff --git a/packages/@hec.js/ui/lib/src/plugins/data-for.js b/packages/@hec.js/ui/lib/src/plugins/data-for.js index 55a73c2..102afe4 100644 --- a/packages/@hec.js/ui/lib/src/plugins/data-for.js +++ b/packages/@hec.js/ui/lib/src/plugins/data-for.js @@ -49,7 +49,6 @@ export const dataForPlugin = { }); done.add(c); - n.after(templateByNode(c, p)); n = n.nextSibling; } diff --git a/packages/@hec.js/ui/lib/src/props.js b/packages/@hec.js/ui/lib/src/props.js index 80887fe..8c7f75c 100644 --- a/packages/@hec.js/ui/lib/src/props.js +++ b/packages/@hec.js/ui/lib/src/props.js @@ -4,10 +4,22 @@ import { isSignal, signal } from "./signal.js"; * @template T * @type { WeakMap } */ -export const nodeProps = new WeakMap(); +const nodeProps = new WeakMap(); /** @param { Node } node */ export const propsOf = (node) => nodeProps.get(node); +export const deletePropsOf = (node) => nodeProps.delete(node); + +export const setPropsOf = (node, props) => { + const existing = propsOf(node); + + if (existing && typeof existing === 'object' ) { + nodeProps.set(node, Object.assign(existing, props)); + } else { + nodeProps.set(node, props); + } + +} /** * @param { any | function(): any} v @@ -63,10 +75,41 @@ export function prop(props, key) { } else if (typeof props === 'function') { props = f(props); - } else { + } else if (typeof props[p] !== 'undefined') { props = props[p]; + } else { + return null; } } return props; +} + +/** + * @param { {[key: string]: any} } props + * @param { string } key + * @returns { boolean } + */ +export function hasProp(props, key) { + const chain = key.split('.'); + + if (!key) { + return false; + } + + for (const p of chain) { + + if (['loading', 'error'].includes(p) && props?.loading && props?.error) { + return props[p]; + } else if (typeof props === 'function') { + props = f(props); + } else if (typeof props[p] !== 'undefined') { + props = props[p]; + } else { + return false; + } + + } + + return true; } \ No newline at end of file diff --git a/packages/@hec.js/ui/lib/src/template.js b/packages/@hec.js/ui/lib/src/template.js index 8903ee5..8954ea4 100644 --- a/packages/@hec.js/ui/lib/src/template.js +++ b/packages/@hec.js/ui/lib/src/template.js @@ -2,7 +2,7 @@ import { expression } from './expression.js'; import { pipes } from './pipes.js'; import { plugins } from './plugins.js'; import { isSignal } from './signal.js'; -import { f, nodeProps, prop } from './props.js'; +import { f, setPropsOf, prop, hasProp } from './props.js'; /** @type {{ [key: string]: Promise }} */ const templatesLoading = {} @@ -63,10 +63,6 @@ export function templateByString(template, props = {}) { */ export function templateByNode(template, props = {}) { - if (nodeProps.has(template)) { - return; - } - /** * @param { string } text * @param { function(string): void } update @@ -142,12 +138,12 @@ export function templateByNode(template, props = {}) { let stopFlag = false; if (node.nodeName == '#document-fragment') { - nodeProps.set(node, props); + setPropsOf(node, props); } if (node instanceof HTMLElement) { - nodeProps.set(node, props); + setPropsOf(node, props); for (const plugin of plugins) { if (node.matches(plugin.select)) { @@ -170,7 +166,7 @@ export function templateByNode(template, props = {}) { node.setAttribute(attributeName, text.trim().replace(/ +/, ' ')) }); - } else if (node.localName.includes('-') && props[attribute]) { + } else if (node.localName.includes('-') && hasProp(props, attribute)) { node.setAttribute(attributeName, `@parent.${attribute}`); } }