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}`);
}
}