ajo 0.1.14 → 0.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/html.cjs +1 -1
- package/dist/html.js +36 -43
- package/dist/index.cjs +1 -1
- package/dist/index.js +61 -96
- package/license +1 -1
- package/package.json +9 -6
- package/readme.md +50 -72
- package/types.ts +75 -61
package/dist/html.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const{assign:
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const{assign:$,entries:f,hasOwn:p}=Object,{isArray:u}=Array,a=e=>[...d(e)].join(""),d=function*(e){for(e of c(e))if(typeof e=="string")yield m(e);else{const{nodeName:t,skip:r,children:l=""}=e;let n="";for(const[i,o]of f(e))g.has(i)||i.startsWith("set:")||o==null||o===!1||(n+=o===!0?`${n} ${i}`:`${n} ${i}="${m(String(o))}"`);v.has(t)?yield`<${t}${n}>`:r?yield`<${t}${n}></${t}>`:typeof l=="string"?yield`<${t}${n}>${l}</${t}>`:(yield`<${t}${n}>`,yield*d(l),yield`</${t}>`)}},c=function*(e,t={value:""},r=!0){for(e of u(e)?e:[e])if(!(e==null||typeof e=="boolean"))if(p(e,"nodeName")){const{value:l}=t,{nodeName:n}=e;if(l&&(yield l,t.value=""),typeof n=="function")if(delete e.nodeName,n.constructor.name==="GeneratorFunction"){const i={},o=$({},n.attrs);for(const s in e){const y=e[s];s.startsWith("attr:")?o[s.slice(5)]=y:i[s]=y}o.nodeName=n.is??"div",o.children=k(n,i),yield o}else delete e.nodeName,yield*c(n(e),t,!1);else yield e}else u(e)?yield*c(e,t,!1):t.value+=e;r&&t.value&&(yield t.value)},v=new Set("area,base,br,col,command,embed,hr,img,input,keygen,link,meta,param,source,track,wbr".split(",")),g=new Set("nodeName,key,skip,memo,ref,children".split(",")),m=e=>e.replace(/[&<>"']/g,t=>`&#${t.charCodeAt(0)};`),k=(e,t)=>{let r,l;try{const n=e.call(r={$args:t,*[Symbol.iterator](){for(;;)yield t},$next(){l=a(n.next().value)},$throw(i){l=a(n.throw(i).value)},$return(){n.return()}},t);r.$next()}catch(n){r.$throw(n)}finally{r.$return()}return l};exports.html=d;exports.render=a;
|
package/dist/html.js
CHANGED
|
@@ -1,64 +1,57 @@
|
|
|
1
|
-
const { assign:
|
|
2
|
-
for (e of
|
|
3
|
-
if (typeof e == "string")
|
|
4
|
-
yield u(e);
|
|
1
|
+
const { assign: f, entries: m, hasOwn: p } = Object, { isArray: d } = Array, y = (e) => [...$(e)].join(""), $ = function* (e) {
|
|
2
|
+
for (e of a(e))
|
|
3
|
+
if (typeof e == "string") yield u(e);
|
|
5
4
|
else {
|
|
6
|
-
const { nodeName: t, skip:
|
|
5
|
+
const { nodeName: t, skip: r, children: l = "" } = e;
|
|
7
6
|
let n = "";
|
|
8
|
-
for (const [
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
for (const [i, o] of m(e))
|
|
8
|
+
k.has(i) || i.startsWith("set:") || o == null || o === !1 || (n += o === !0 ? `${n} ${i}` : `${n} ${i}="${u(String(o))}"`);
|
|
9
|
+
v.has(t) ? yield `<${t}${n}>` : r ? yield `<${t}${n}></${t}>` : typeof l == "string" ? yield `<${t}${n}>${l}</${t}>` : (yield `<${t}${n}>`, yield* $(l), yield `</${t}>`);
|
|
11
10
|
}
|
|
12
|
-
},
|
|
13
|
-
for (e of
|
|
11
|
+
}, a = function* (e, t = { value: "" }, r = !0) {
|
|
12
|
+
for (e of d(e) ? e : [e])
|
|
14
13
|
if (!(e == null || typeof e == "boolean"))
|
|
15
|
-
if (
|
|
16
|
-
const { value:
|
|
17
|
-
if (
|
|
14
|
+
if (p(e, "nodeName")) {
|
|
15
|
+
const { value: l } = t, { nodeName: n } = e;
|
|
16
|
+
if (l && (yield l, t.value = ""), typeof n == "function")
|
|
18
17
|
if (delete e.nodeName, n.constructor.name === "GeneratorFunction") {
|
|
19
|
-
const
|
|
20
|
-
for (const
|
|
21
|
-
const
|
|
22
|
-
|
|
18
|
+
const i = {}, o = f({}, n.attrs);
|
|
19
|
+
for (const s in e) {
|
|
20
|
+
const c = e[s];
|
|
21
|
+
s.startsWith("attr:") ? o[s.slice(5)] = c : i[s] = c;
|
|
23
22
|
}
|
|
24
|
-
|
|
25
|
-
} else
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
o && t.value && (yield t.value);
|
|
32
|
-
}, k = new Set("area,base,br,col,command,embed,hr,img,input,keygen,link,meta,param,source,track,wbr".split(",")), w = new Set("nodeName,key,skip,memo,ref,children".split(",")), u = (e) => e.replace(/[&<>"']/g, (t) => `&#${t.charCodeAt(0)};`), v = (e, t) => {
|
|
33
|
-
let o, i;
|
|
23
|
+
o.nodeName = n.is ?? "div", o.children = w(n, i), yield o;
|
|
24
|
+
} else delete e.nodeName, yield* a(n(e), t, !1);
|
|
25
|
+
else yield e;
|
|
26
|
+
} else d(e) ? yield* a(e, t, !1) : t.value += e;
|
|
27
|
+
r && t.value && (yield t.value);
|
|
28
|
+
}, v = new Set("area,base,br,col,command,embed,hr,img,input,keygen,link,meta,param,source,track,wbr".split(",")), k = new Set("nodeName,key,skip,memo,ref,children".split(",")), u = (e) => e.replace(/[&<>"']/g, (t) => `&#${t.charCodeAt(0)};`), w = (e, t) => {
|
|
29
|
+
let r, l;
|
|
34
30
|
try {
|
|
35
|
-
const n = e.call(
|
|
31
|
+
const n = e.call(r = {
|
|
36
32
|
$args: t,
|
|
37
33
|
*[Symbol.iterator]() {
|
|
38
|
-
for (; ; )
|
|
39
|
-
yield t;
|
|
34
|
+
for (; ; ) yield t;
|
|
40
35
|
},
|
|
41
|
-
|
|
36
|
+
$next() {
|
|
37
|
+
l = y(n.next().value);
|
|
42
38
|
},
|
|
43
|
-
|
|
44
|
-
|
|
39
|
+
$throw(i) {
|
|
40
|
+
l = y(n.throw(i).value);
|
|
45
41
|
},
|
|
46
|
-
|
|
47
|
-
i = f(n.throw(l).value);
|
|
48
|
-
},
|
|
49
|
-
return() {
|
|
42
|
+
$return() {
|
|
50
43
|
n.return();
|
|
51
44
|
}
|
|
52
45
|
}, t);
|
|
53
|
-
|
|
46
|
+
r.$next();
|
|
54
47
|
} catch (n) {
|
|
55
|
-
|
|
48
|
+
r.$throw(n);
|
|
56
49
|
} finally {
|
|
57
|
-
|
|
50
|
+
r.$return();
|
|
58
51
|
}
|
|
59
|
-
return
|
|
52
|
+
return l;
|
|
60
53
|
};
|
|
61
54
|
export {
|
|
62
|
-
|
|
63
|
-
|
|
55
|
+
$ as html,
|
|
56
|
+
y as render
|
|
64
57
|
};
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const N=({children:e})=>e,k=function(e,t){const{length:n}=arguments;return(t??(t={})).nodeName=e,"children"in t||n<3||(t.children=n===3?arguments[2]:S.call(arguments,2)),t},m=(e,t)=>{let n=t.firstChild;for(e of g(e)){let i=n;if(typeof e=="string"){for(;i&&i.nodeType!=3;)i=i.nextSibling;i?i.data!=e&&(i.data=e):i=document.createTextNode(e)}else{const{nodeName:o,key:a,skip:r,memo:s,ref:l,children:x}=e;for(;i&&!(i.localName===o&&(i.$key??(i.$key=a))==a);)i=i.nextSibling;if(i??(i=d(document.createElementNS(e.xmlns??o==="svg"?O:t.namespaceURI,o),{$key:a})),s==null||T(i.$memo,i.$memo=s)){const{$props:u}=i,$={};for(const c of w(d({},u,e))){if(A.has(c))continue;const f=$[c]=e[c];f!==(u==null?void 0:u[c])&&(c.startsWith("set:")?i[c.slice(4)]=f:f==null||f===!1?i.removeAttribute(c):i.setAttribute(c,f===!0?"":f))}i.$props=$,r||m(x,i),typeof l=="function"&&(i.$ref=l)(i)}}i===n?n=n.nextSibling:P(t,i,n)}for(;n;){const i=n.nextSibling;n.nodeType===1&&h(n),t.removeChild(n),n=i}},{isArray:y,prototype:{slice:S}}=Array,{keys:w,assign:d,hasOwn:b,setPrototypeOf:p,getPrototypeOf:v}=Object,O="http://www.w3.org/2000/svg",A=new Set("nodeName,key,skip,memo,ref,children".split(",")),T=(e,t)=>y(e)&&y(t)?e.some((n,i)=>n!==t[i]):e!==t,g=function*(e,t={value:""},n=!0){for(e of y(e)?e:[e])if(!(e==null||typeof e=="boolean"))if(b(e,"nodeName")){const{value:i}=t,{nodeName:o}=e;if(i&&(yield i,t.value=""),typeof o=="function")if(delete e.nodeName,o.constructor.name==="GeneratorFunction"){const a={},r=d({},o.attrs);for(const s of w(e)){const l=e[s];s.startsWith("attr:")?r[s.slice(5)]=l:s==="key"||s==="memo"?r[s]=l:a[s]=l}r.nodeName=o.is??"div",r.skip=!0,r.ref=C.bind(null,o,a),yield r}else yield*g(o(e),t,!1);else yield e}else y(e)?yield*g(e,t,!1):t.value+=e;n&&t.value&&(yield t.value)},C=(e,t,n)=>{n&&(n.$gen??(n.$gen=(new j(n),e)),n.$ref=F.bind(null,n),d(n.$args??(n.$args={}),t),n.$next())},F=(e,t)=>t??e.$return(),P=(e,t,n)=>{if(t.contains(document.activeElement)){const i=t.nextSibling;for(;n&&n!=t;){const o=n.nextSibling;e.insertBefore(n,i),n=o}}else e.insertBefore(t,n)},h=e=>{for(const n of e.children)h(n);const{$ref:t}=e;typeof t=="function"&&t(null)};class j{constructor(t){p(t,p(v(this),v(t)))}$next(){try{m((this.$it??(this.$it=this.$gen.call(this,this.$args))).next().value,this),typeof this.$ref=="function"&&this.$ref(this)}catch(t){this.$throw(t)}}$throw(t){var n;for(let i=this;i;i=i.parentNode)if(typeof((n=i.$it)==null?void 0:n.throw)=="function")try{return m(i.$it.throw(t).value,i)}catch{}throw t}$return(){var t;try{(t=this.$it)==null||t.return()}catch(n){this.$throw(n)}finally{this.$it=null}}}exports.Fragment=N;exports.h=k;exports.render=m;
|
package/dist/index.js
CHANGED
|
@@ -1,131 +1,96 @@
|
|
|
1
|
-
const
|
|
2
|
-
const { length:
|
|
3
|
-
return (t ?? (t =
|
|
1
|
+
const E = ({ children: e }) => e, F = function(e, t) {
|
|
2
|
+
const { length: n } = arguments;
|
|
3
|
+
return (t ?? (t = {})).nodeName = e, "children" in t || n < 3 || (t.children = n === 3 ? arguments[2] : N.call(arguments, 2)), t;
|
|
4
4
|
}, d = (e, t) => {
|
|
5
|
-
let
|
|
6
|
-
for (e of
|
|
7
|
-
let
|
|
5
|
+
let n = t.firstChild;
|
|
6
|
+
for (e of $(e)) {
|
|
7
|
+
let i = n;
|
|
8
8
|
if (typeof e == "string") {
|
|
9
|
-
for (;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
for (const c of w(g({}, y, e))) {
|
|
21
|
-
if (q.has(c))
|
|
22
|
-
continue;
|
|
23
|
-
const f = $[c] = e[c];
|
|
24
|
-
f !== (y == null ? void 0 : y[c]) && (c.startsWith("set:") ? n[c.slice(4)] = f : f == null || f === !1 ? n.removeAttribute(c) : n.setAttribute(c, f === !0 ? "" : f));
|
|
9
|
+
for (; i && i.nodeType != 3; ) i = i.nextSibling;
|
|
10
|
+
i ? i.data != e && (i.data = e) : i = document.createTextNode(e);
|
|
11
|
+
} else {
|
|
12
|
+
const { nodeName: o, key: a, skip: r, memo: s, ref: l, children: h } = e;
|
|
13
|
+
for (; i && !(i.localName === o && (i.$key ?? (i.$key = a)) == a); ) i = i.nextSibling;
|
|
14
|
+
if (i ?? (i = y(document.createElementNS(e.xmlns ?? o === "svg" ? S : t.namespaceURI, o), { $key: a })), s == null || A(i.$memo, i.$memo = s)) {
|
|
15
|
+
const { $props: u } = i, g = {};
|
|
16
|
+
for (const c of w(y({}, u, e))) {
|
|
17
|
+
if (b.has(c)) continue;
|
|
18
|
+
const f = g[c] = e[c];
|
|
19
|
+
f !== (u == null ? void 0 : u[c]) && (c.startsWith("set:") ? i[c.slice(4)] = f : f == null || f === !1 ? i.removeAttribute(c) : i.setAttribute(c, f === !0 ? "" : f));
|
|
25
20
|
}
|
|
26
|
-
|
|
21
|
+
i.$props = g, r || d(h, i), typeof l == "function" && (i.$ref = l)(i);
|
|
27
22
|
}
|
|
28
23
|
}
|
|
29
|
-
|
|
24
|
+
i === n ? n = n.nextSibling : T(t, i, n);
|
|
30
25
|
}
|
|
31
|
-
for (;
|
|
32
|
-
const
|
|
33
|
-
|
|
26
|
+
for (; n; ) {
|
|
27
|
+
const i = n.nextSibling;
|
|
28
|
+
n.nodeType === 1 && x(n), t.removeChild(n), n = i;
|
|
34
29
|
}
|
|
35
|
-
}, { isArray:
|
|
36
|
-
for (e of
|
|
30
|
+
}, { isArray: m, prototype: { slice: N } } = Array, { keys: w, assign: y, hasOwn: k, setPrototypeOf: p, getPrototypeOf: v } = Object, S = "http://www.w3.org/2000/svg", b = new Set("nodeName,key,skip,memo,ref,children".split(",")), A = (e, t) => m(e) && m(t) ? e.some((n, i) => n !== t[i]) : e !== t, $ = function* (e, t = { value: "" }, n = !0) {
|
|
31
|
+
for (e of m(e) ? e : [e])
|
|
37
32
|
if (!(e == null || typeof e == "boolean"))
|
|
38
|
-
if (
|
|
39
|
-
const { value:
|
|
40
|
-
if (
|
|
33
|
+
if (k(e, "nodeName")) {
|
|
34
|
+
const { value: i } = t, { nodeName: o } = e;
|
|
35
|
+
if (i && (yield i, t.value = ""), typeof o == "function")
|
|
41
36
|
if (delete e.nodeName, o.constructor.name === "GeneratorFunction") {
|
|
42
|
-
const
|
|
37
|
+
const a = {}, r = y({}, o.attrs);
|
|
43
38
|
for (const s of w(e)) {
|
|
44
|
-
const
|
|
45
|
-
s.startsWith("attr:")
|
|
39
|
+
const l = e[s];
|
|
40
|
+
s.startsWith("attr:") ? r[s.slice(5)] = l : s === "key" || s === "memo" ? r[s] = l : a[s] = l;
|
|
46
41
|
}
|
|
47
|
-
r.nodeName = o.is ?? "div", r.skip = !0, r.ref =
|
|
48
|
-
} else
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}, T = (e, t, i) => {
|
|
56
|
-
i && (i.$gen ?? (i.$gen = (new I(i), e)), i.$ref = B.bind(null, i), i.$args = t, i.next());
|
|
57
|
-
}, B = (e, t) => t ?? e.return(), E = (e, t, i) => {
|
|
42
|
+
r.nodeName = o.is ?? "div", r.skip = !0, r.ref = O.bind(null, o, a), yield r;
|
|
43
|
+
} else yield* $(o(e), t, !1);
|
|
44
|
+
else yield e;
|
|
45
|
+
} else m(e) ? yield* $(e, t, !1) : t.value += e;
|
|
46
|
+
n && t.value && (yield t.value);
|
|
47
|
+
}, O = (e, t, n) => {
|
|
48
|
+
n && (n.$gen ?? (n.$gen = (new B(n), e)), n.$ref = C.bind(null, n), y(n.$args ?? (n.$args = {}), t), n.$next());
|
|
49
|
+
}, C = (e, t) => t ?? e.$return(), T = (e, t, n) => {
|
|
58
50
|
if (t.contains(document.activeElement)) {
|
|
59
|
-
const
|
|
60
|
-
for (;
|
|
61
|
-
const o =
|
|
62
|
-
e.insertBefore(
|
|
51
|
+
const i = t.nextSibling;
|
|
52
|
+
for (; n && n != t; ) {
|
|
53
|
+
const o = n.nextSibling;
|
|
54
|
+
e.insertBefore(n, i), n = o;
|
|
63
55
|
}
|
|
64
|
-
} else
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
for (const i of e.children)
|
|
68
|
-
k(i);
|
|
56
|
+
} else e.insertBefore(t, n);
|
|
57
|
+
}, x = (e) => {
|
|
58
|
+
for (const n of e.children) x(n);
|
|
69
59
|
const { $ref: t } = e;
|
|
70
60
|
typeof t == "function" && t(null);
|
|
71
|
-
for (const i of w(e))
|
|
72
|
-
e[i] = null;
|
|
73
61
|
};
|
|
74
|
-
class
|
|
62
|
+
class B {
|
|
75
63
|
constructor(t) {
|
|
76
|
-
|
|
64
|
+
p(t, p(v(this), v(t)));
|
|
77
65
|
}
|
|
78
|
-
|
|
79
|
-
for (; ; )
|
|
80
|
-
yield this.$args ?? {};
|
|
81
|
-
}
|
|
82
|
-
refresh() {
|
|
83
|
-
P(this);
|
|
84
|
-
}
|
|
85
|
-
next() {
|
|
66
|
+
$next() {
|
|
86
67
|
try {
|
|
87
|
-
d((this.$it ?? (this.$it = this.$gen.call(this, this.$args
|
|
68
|
+
d((this.$it ?? (this.$it = this.$gen.call(this, this.$args))).next().value, this), typeof this.$ref == "function" && this.$ref(this);
|
|
88
69
|
} catch (t) {
|
|
89
|
-
this
|
|
70
|
+
this.$throw(t);
|
|
90
71
|
}
|
|
91
72
|
}
|
|
92
|
-
throw(t) {
|
|
93
|
-
var
|
|
94
|
-
for (let
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
} catch {
|
|
99
|
-
}
|
|
73
|
+
$throw(t) {
|
|
74
|
+
var n;
|
|
75
|
+
for (let i = this; i; i = i.parentNode) if (typeof ((n = i.$it) == null ? void 0 : n.throw) == "function") try {
|
|
76
|
+
return d(i.$it.throw(t).value, i);
|
|
77
|
+
} catch {
|
|
78
|
+
}
|
|
100
79
|
throw t;
|
|
101
80
|
}
|
|
102
|
-
return() {
|
|
81
|
+
$return() {
|
|
103
82
|
var t;
|
|
104
83
|
try {
|
|
105
84
|
(t = this.$it) == null || t.return();
|
|
106
|
-
} catch (
|
|
107
|
-
this
|
|
85
|
+
} catch (n) {
|
|
86
|
+
this.$throw(n);
|
|
108
87
|
} finally {
|
|
109
88
|
this.$it = null;
|
|
110
89
|
}
|
|
111
90
|
}
|
|
112
91
|
}
|
|
113
|
-
let l, S;
|
|
114
|
-
const P = (e) => {
|
|
115
|
-
(l ?? (l = /* @__PURE__ */ new Set())).has(e) && l.delete(e);
|
|
116
|
-
for (const t of l) {
|
|
117
|
-
if (t.contains(e))
|
|
118
|
-
return;
|
|
119
|
-
e.contains(t) && l.delete(t);
|
|
120
|
-
}
|
|
121
|
-
l.add(e), S ?? (S = requestAnimationFrame(W));
|
|
122
|
-
}, W = () => {
|
|
123
|
-
for (const e of l)
|
|
124
|
-
e.isConnected && e.next();
|
|
125
|
-
l.clear(), S = null;
|
|
126
|
-
};
|
|
127
92
|
export {
|
|
128
|
-
|
|
129
|
-
|
|
93
|
+
E as Fragment,
|
|
94
|
+
F as h,
|
|
130
95
|
d as render
|
|
131
96
|
};
|
package/license
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ajo",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
4
4
|
"description": "ajo is a JavaScript view library for building user interfaces",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -9,11 +9,13 @@
|
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
11
|
"import": "./dist/index.js",
|
|
12
|
-
"require": "./dist/index.cjs"
|
|
12
|
+
"require": "./dist/index.cjs",
|
|
13
|
+
"types": "./types.ts"
|
|
13
14
|
},
|
|
14
15
|
"./html": {
|
|
15
16
|
"import": "./dist/html.js",
|
|
16
|
-
"require": "./dist/html.
|
|
17
|
+
"require": "./dist/html.cjs",
|
|
18
|
+
"types": "./types.ts"
|
|
17
19
|
}
|
|
18
20
|
},
|
|
19
21
|
"files": [
|
|
@@ -21,9 +23,10 @@
|
|
|
21
23
|
"types.ts"
|
|
22
24
|
],
|
|
23
25
|
"devDependencies": {
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
26
|
+
"@types/node": "^20.14.10",
|
|
27
|
+
"jsdom": "24.1.0",
|
|
28
|
+
"vite": "5.3.3",
|
|
29
|
+
"vitest": "2.0.1"
|
|
27
30
|
},
|
|
28
31
|
"keywords": [
|
|
29
32
|
"ui",
|
package/readme.md
CHANGED
|
@@ -68,7 +68,7 @@ function* Counter() {
|
|
|
68
68
|
|
|
69
69
|
const handleClick = () => {
|
|
70
70
|
count++
|
|
71
|
-
this
|
|
71
|
+
this.$next()
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
while (true) yield (
|
|
@@ -254,7 +254,7 @@ Stateful components in Ajo are defined using generator functions. These componen
|
|
|
254
254
|
The following example demonstrates key features of stateful components in Ajo:
|
|
255
255
|
|
|
256
256
|
```jsx
|
|
257
|
-
function* ChatComponent(
|
|
257
|
+
function* ChatComponent(props) {
|
|
258
258
|
|
|
259
259
|
// Define mutable state variables.
|
|
260
260
|
let message = '', connected = false
|
|
@@ -264,36 +264,33 @@ function* ChatComponent({ user = 'Anonymous', room }) { // Receive arguments ini
|
|
|
264
264
|
|
|
265
265
|
message = event.target.value
|
|
266
266
|
|
|
267
|
-
|
|
268
|
-
this.next()
|
|
267
|
+
this.$next()
|
|
269
268
|
}
|
|
270
269
|
|
|
271
270
|
const send = () => {
|
|
272
271
|
|
|
273
272
|
if (message) {
|
|
274
273
|
|
|
275
|
-
|
|
276
|
-
connection.send(JSON.stringify({ user: this.$args.user, message }))
|
|
274
|
+
connection.send(JSON.stringify({ user: props.user ?? 'Anonymous', message }))
|
|
277
275
|
|
|
278
276
|
message = ''
|
|
279
277
|
|
|
280
|
-
|
|
281
|
-
this.refresh()
|
|
278
|
+
this.$next()
|
|
282
279
|
}
|
|
283
280
|
}
|
|
284
281
|
|
|
285
282
|
const handleConnectionOpen = () => {
|
|
286
283
|
connected = true
|
|
287
|
-
this
|
|
284
|
+
this.$next()
|
|
288
285
|
}
|
|
289
286
|
|
|
290
287
|
const handleConnectionError = error => {
|
|
291
288
|
// Throw error to be caught by the component itself or a parent component.
|
|
292
|
-
this
|
|
289
|
+
this.$throw(new Error('Connection error: ' + error.message))
|
|
293
290
|
}
|
|
294
291
|
|
|
295
292
|
// Setup resources.
|
|
296
|
-
const server = `ws://chat.com/${room}`
|
|
293
|
+
const server = `ws://chat.com/${props.room}`
|
|
297
294
|
const connection = new WebSocket(server)
|
|
298
295
|
|
|
299
296
|
connection.onopen = handleConnectionOpen
|
|
@@ -304,12 +301,12 @@ function* ChatComponent({ user = 'Anonymous', room }) { // Receive arguments ini
|
|
|
304
301
|
|
|
305
302
|
try { // Optional try/finally block for cleanup logic.
|
|
306
303
|
|
|
307
|
-
|
|
304
|
+
while (true) {
|
|
308
305
|
|
|
309
306
|
try { // Optional try/catch block for error handling.
|
|
310
307
|
|
|
311
308
|
// Compute derived values.
|
|
312
|
-
const status = connected ? `You are connected as ${user}.` : "Connecting to chat..."
|
|
309
|
+
const status = connected ? `You are connected as ${props.user ?? 'Anonymous'}.` : "Connecting to chat..."
|
|
313
310
|
|
|
314
311
|
// Render the component UI.
|
|
315
312
|
yield (
|
|
@@ -401,7 +398,7 @@ function* ParentComponent() {
|
|
|
401
398
|
/>
|
|
402
399
|
}
|
|
403
400
|
|
|
404
|
-
function* ChildComponent({ data
|
|
401
|
+
function* ChildComponent(props) { // props is an object containing data and onEvent
|
|
405
402
|
// ...
|
|
406
403
|
}
|
|
407
404
|
```
|
|
@@ -417,95 +414,76 @@ In the context of Server-Side Rendering (SSR), this features allows Ajo to grace
|
|
|
417
414
|
|
|
418
415
|
Stateful components in Ajo are equipped with several methods that allow for advanced control over component behavior, error handling, and rendering processes. These methods are called lifecycle methods and are invoked at different stages of the component's lifecycle.
|
|
419
416
|
|
|
420
|
-
### `this
|
|
417
|
+
### `this.$next()`
|
|
421
418
|
|
|
422
|
-
The `
|
|
419
|
+
The `$next` method is used within stateful components in Ajo to advance the component's generator function to its next yield point. This method is crucial for rendering the next state of the component.
|
|
423
420
|
|
|
424
421
|
#### Purpose:
|
|
425
422
|
|
|
426
|
-
- **
|
|
427
|
-
- **Single Render:** If called multiple times before the browser paints, `this.refresh()` schedules only one render, ensuring that the component is rendered only once.
|
|
423
|
+
- **Synchronous Rendering:** `this.$next()` is used to render the next state of the component. It advances the generator function to the next yield, reflecting any changes in state or props right away.
|
|
428
424
|
|
|
429
425
|
#### Usage:
|
|
430
426
|
|
|
431
|
-
- **
|
|
432
|
-
- **In Event Handlers and Async Operations:** Useful in event handlers or after asynchronous operations where you need to update the UI in response to changes.
|
|
427
|
+
- **In Response to State Changes:** Typically, `this.$next()` is called in scenarios where the component's state has changed and an update to the DOM is required.
|
|
433
428
|
|
|
434
429
|
#### Example:
|
|
435
430
|
|
|
436
431
|
```jsx
|
|
437
|
-
function*
|
|
432
|
+
function* Counter() {
|
|
438
433
|
|
|
439
|
-
let
|
|
434
|
+
let count = 0
|
|
440
435
|
|
|
441
|
-
const
|
|
436
|
+
const increment = () => {
|
|
442
437
|
|
|
443
|
-
|
|
438
|
+
count++
|
|
444
439
|
|
|
445
|
-
|
|
446
|
-
this.refresh()
|
|
440
|
+
this.$next()
|
|
447
441
|
}
|
|
448
442
|
|
|
449
443
|
while (true) {
|
|
450
|
-
yield
|
|
451
|
-
<div>
|
|
452
|
-
<button set:onclick={fetchData}>Fetch Data</button>
|
|
453
|
-
{data && <DisplayData data={data} />}
|
|
454
|
-
</div>
|
|
455
|
-
)
|
|
444
|
+
yield <button set:onclick={increment}>{count}</button>
|
|
456
445
|
}
|
|
457
446
|
}
|
|
458
447
|
```
|
|
459
|
-
> In this example, `
|
|
460
|
-
|
|
461
|
-
### `this.next()`
|
|
462
|
-
> **Note:** `this.next()` is called asynchronously when calling `this.refresh()`.
|
|
463
|
-
|
|
464
|
-
The `next` method is used within stateful components in Ajo to manually advance the component's generator function to its next yield point. This method is crucial for synchronously rendering the next state of the component.
|
|
465
|
-
|
|
466
|
-
#### Purpose:
|
|
467
|
-
|
|
468
|
-
- **Synchronous Rendering:** `this.next()` is used to immediately render the next state of the component. It advances the generator function to the next yield, reflecting any changes in state or props right away.
|
|
469
|
-
|
|
470
|
-
#### Usage:
|
|
471
|
-
|
|
472
|
-
- **In Response to State Changes:** Typically, `this.next()` is called in scenarios where the component's state has changed and an immediate update to the DOM is required.
|
|
473
|
-
- **For Controlled Updates:** It allows for more controlled and predictable updates, as it bypasses the asynchronous rendering cycle from `this.refresh()`.
|
|
474
|
-
|
|
475
|
-
#### Example:
|
|
448
|
+
> In this example, `Counter` uses `this.$next()` in its `increment` function to render the updated count whenever the button is clicked.
|
|
476
449
|
|
|
477
450
|
```jsx
|
|
478
|
-
function*
|
|
451
|
+
function* DataFetcher() {
|
|
479
452
|
|
|
480
|
-
let
|
|
453
|
+
let data = null
|
|
481
454
|
|
|
482
|
-
const
|
|
455
|
+
const fetchData = async () => {
|
|
483
456
|
|
|
484
|
-
|
|
457
|
+
data = await fetchSomeData()
|
|
485
458
|
|
|
486
|
-
//
|
|
487
|
-
this
|
|
459
|
+
// Queue a re-render to update the component with the fetched data:
|
|
460
|
+
this.$next()
|
|
488
461
|
}
|
|
489
462
|
|
|
490
463
|
while (true) {
|
|
491
|
-
yield
|
|
464
|
+
yield (
|
|
465
|
+
<div>
|
|
466
|
+
<button set:onclick={fetchData}>Fetch Data</button>
|
|
467
|
+
{data && <DisplayData data={data} />}
|
|
468
|
+
</div>
|
|
469
|
+
)
|
|
492
470
|
}
|
|
493
471
|
}
|
|
494
472
|
```
|
|
495
|
-
> In this example, `
|
|
473
|
+
> In this example, `DataFetcher` uses `this.$next()` to update its display after data is fetched.
|
|
496
474
|
|
|
497
|
-
### `this
|
|
498
|
-
> **Note:** `this
|
|
475
|
+
### `this.$throw()`
|
|
476
|
+
> **Note:** `this.$throw()` is automatically called when an error is thrown from a component's generator function.
|
|
499
477
|
|
|
500
|
-
The
|
|
478
|
+
The `$throw` method in Ajo stateful components is designed for error propagation within the component hierarchy. It allows developers to throw errors from a child component to be caught and handled by itself or a parent component, facilitating a structured approach to error management.
|
|
501
479
|
|
|
502
480
|
#### Purpose:
|
|
503
481
|
|
|
504
|
-
- **Error Propagation:** `this
|
|
482
|
+
- **Error Propagation:** `this.$throw()` is used to send errors from the current component up to its parents component, akin to creating an error boundary.
|
|
505
483
|
|
|
506
484
|
#### Usage:
|
|
507
485
|
|
|
508
|
-
- **Handling Uncaught Exceptions:** Typically used within event handlers or asynchronous operations where errors might occur. Instead of handling these errors locally within the component, `this
|
|
486
|
+
- **Handling Uncaught Exceptions:** Typically used within event handlers or asynchronous operations where errors might occur. Instead of handling these errors locally within the component, `this.$throw()` sends them to the parent component for a more centralized handling approach.
|
|
509
487
|
- **Creating Error Boundaries:** Useful in scenarios where a parent component is designed to handle errors from its child components, maintaining separation of concerns and cleaner code.
|
|
510
488
|
|
|
511
489
|
#### Example:
|
|
@@ -522,7 +500,7 @@ function* ChildComponent() {
|
|
|
522
500
|
} catch (err) {
|
|
523
501
|
|
|
524
502
|
// Propagate error to parent component
|
|
525
|
-
this
|
|
503
|
+
this.$throw(err)
|
|
526
504
|
}
|
|
527
505
|
}
|
|
528
506
|
|
|
@@ -541,16 +519,16 @@ function* ParentComponent() {
|
|
|
541
519
|
}
|
|
542
520
|
}
|
|
543
521
|
```
|
|
544
|
-
> In this example, `ChildComponent` uses `this
|
|
522
|
+
> In this example, `ChildComponent` uses `this.$throw()` within an event handler to propagate errors upwards to its parent component, `ParentComponent`. The parent component then catches the error and renders it to the DOM.
|
|
545
523
|
|
|
546
|
-
### `this
|
|
547
|
-
> **Note:** `this
|
|
524
|
+
### `this.$return()`
|
|
525
|
+
> **Note:** `this.$return()` is automatically called when a stateful component is unmounted.
|
|
548
526
|
|
|
549
|
-
The
|
|
527
|
+
The `$return` method in Ajo is used to reset and restart the generator function of a stateful component. It effectively ends the current execution of the component's generator function, and optionally re-execute it from scratch allowing for a complete reset of the component's state and behavior.
|
|
550
528
|
|
|
551
529
|
#### Purpose:
|
|
552
530
|
|
|
553
|
-
- **Component Reset:** `this
|
|
531
|
+
- **Component Reset:** `this.$return()` is used to restart a component's generator function from the beginning, resetting its internal state and re-initializing it as needed.
|
|
554
532
|
|
|
555
533
|
#### Usage:
|
|
556
534
|
|
|
@@ -571,16 +549,16 @@ function* MultiStepForm({ initialData }) {
|
|
|
571
549
|
currentStep++
|
|
572
550
|
|
|
573
551
|
// Re-render with the next step
|
|
574
|
-
this
|
|
552
|
+
this.$next()
|
|
575
553
|
}
|
|
576
554
|
|
|
577
555
|
const handleRestart = () => {
|
|
578
556
|
|
|
579
557
|
// Reset the generator function
|
|
580
|
-
this
|
|
558
|
+
this.$return()
|
|
581
559
|
|
|
582
560
|
// Re-render the component in its initial state
|
|
583
|
-
this
|
|
561
|
+
this.$next()
|
|
584
562
|
}
|
|
585
563
|
|
|
586
564
|
while (true) {
|
|
@@ -608,7 +586,7 @@ function* MultiStepForm({ initialData }) {
|
|
|
608
586
|
}
|
|
609
587
|
}
|
|
610
588
|
```
|
|
611
|
-
> In `handleRestart`, `this
|
|
589
|
+
> In `handleRestart`, `this.$return()` is first called to reset the generator function. This effectively ends the current execution of the component's generator function and prepares it to start from the beginning. Immediately after, `this.$next()` is called to trigger a re-render of the component. This ensures that after the state is reset, the component's UI is also updated to reflect its initial state.
|
|
612
590
|
|
|
613
591
|
## Server-Side Rendering (SSR)
|
|
614
592
|
|
package/types.ts
CHANGED
|
@@ -1,69 +1,83 @@
|
|
|
1
|
-
declare
|
|
2
|
-
|
|
3
|
-
interface VNode<TTag = Tag> extends Partial<AjoProps<ElementType<TTag>>> {
|
|
4
|
-
nodeName: TTag,
|
|
5
|
-
[key: string]: unknown,
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
type Child = null | undefined | boolean | bigint | number | string | symbol | Node | VNode | Iterable<Child>
|
|
9
|
-
|
|
10
|
-
type Tag = keyof (HTMLElementTagNameMap & SVGElementTagNameMap)
|
|
11
|
-
|
|
12
|
-
type ElementType<TTag> =
|
|
13
|
-
TTag extends keyof HTMLElementTagNameMap
|
|
14
|
-
? HTMLElementTagNameMap[TTag]
|
|
15
|
-
: TTag extends keyof SVGElementTagNameMap
|
|
16
|
-
? SVGElementTagNameMap[TTag]
|
|
17
|
-
: HTMLElement
|
|
18
|
-
|
|
19
|
-
type AjoProps<TElement> = {
|
|
20
|
-
key: unknown,
|
|
21
|
-
skip: boolean,
|
|
22
|
-
memo: unknown,
|
|
23
|
-
ref: (el: TElement | null) => void,
|
|
24
|
-
children: Child,
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
type SetProps<TTag> = {
|
|
28
|
-
[K in keyof ElementType<TTag> as `set:${Exclude<K, symbol>}`]: ElementType<TTag>[K]
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
type AttrProps<T> = {
|
|
32
|
-
[K in keyof T as `attr:${Exclude<K, symbol>}`]: T[K]
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
type Context<TArgs> = {
|
|
36
|
-
$args: TArgs
|
|
37
|
-
next: () => void
|
|
38
|
-
throw: (error?: unknown) => void
|
|
39
|
-
return: () => void
|
|
40
|
-
refresh: () => void
|
|
41
|
-
[Symbol.iterator]: () => Generator<TArgs, void, TArgs>
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
type Function<TArgs = {}> = (args: TArgs) => Child
|
|
45
|
-
|
|
46
|
-
type Component<TArgs = {}, TTag extends Tag = 'div'> = {
|
|
47
|
-
(this: ElementType<TTag> & Context<TArgs>, args: TArgs): Generator<Child, void, Child>
|
|
48
|
-
} & (TTag extends 'div' ? { is?: TTag } : { is: TTag })
|
|
49
|
-
}
|
|
1
|
+
declare module 'ajo' {
|
|
50
2
|
|
|
51
|
-
|
|
3
|
+
type Tag = keyof (HTMLElementTagNameMap & SVGElementTagNameMap)
|
|
4
|
+
|
|
5
|
+
type Type = Tag | Function | Component
|
|
6
|
+
|
|
7
|
+
type Props = Record<string, unknown>
|
|
8
|
+
|
|
9
|
+
type AjoNode<TTag extends Type> = { nodeName: TTag } & TagProps<TTag>
|
|
10
|
+
|
|
11
|
+
type Children = any
|
|
12
|
+
|
|
13
|
+
type ElementType<TTag = Tag> = TTag extends keyof HTMLElementTagNameMap
|
|
14
|
+
? HTMLElementTagNameMap[TTag]
|
|
15
|
+
: TTag extends keyof SVGElementTagNameMap
|
|
16
|
+
? SVGElementTagNameMap[TTag]
|
|
17
|
+
: never
|
|
18
|
+
|
|
19
|
+
type AjoProps<TElement> = {
|
|
20
|
+
key: unknown
|
|
21
|
+
skip: boolean
|
|
22
|
+
memo: unknown
|
|
23
|
+
ref: (el: TElement | null) => void
|
|
24
|
+
} & ElementChildrenAttribute
|
|
25
|
+
|
|
26
|
+
type SetProps<TTag = Tag> = {
|
|
27
|
+
[K in keyof ElementType<TTag> as `set:${Exclude<K, symbol>}`]: ElementType<TTag>[K]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type AttrProps<TAttribute = Props> = {
|
|
31
|
+
[K in keyof TAttribute as `attr:${Exclude<K, symbol>}`]: TAttribute[K]
|
|
32
|
+
}
|
|
52
33
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
34
|
+
type Context<TArguments = Props> = {
|
|
35
|
+
$args: TArguments
|
|
36
|
+
$next: () => void
|
|
37
|
+
$throw: (value?: unknown) => void
|
|
38
|
+
$return: () => void
|
|
39
|
+
[Symbol.iterator]: () => Iterator<TArguments, unknown, unknown>
|
|
40
|
+
}
|
|
56
41
|
|
|
57
|
-
|
|
42
|
+
type Function<TArguments = Props> = (args: TArguments) => Children
|
|
43
|
+
|
|
44
|
+
type Component<TArguments = Props, TTag extends Tag = 'div'> = {
|
|
45
|
+
(this: ElementType<TTag> & Context<TArguments>, args: TArguments): Iterator<Children, unknown, unknown>
|
|
46
|
+
} & (TTag extends 'div' ? { is?: TTag } : { is: TTag })
|
|
47
|
+
|
|
48
|
+
type Ref<TComponent> = TComponent extends Component<infer TArguments, infer TTag>
|
|
49
|
+
? Component<TArguments & { ref: (el: ThisParameterType<Ref<TComponent>> | null) => void }, TTag>
|
|
50
|
+
: never
|
|
51
|
+
|
|
52
|
+
type IntrinsicElements = {
|
|
53
|
+
[TTag in Tag]: Partial<SetProps<TTag> & AjoProps<ElementType<TTag>>> & Props
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
type IntrinsicAttributes = Partial<Omit<AjoProps<ElementType<Tag>>, 'skip' | 'ref'>> & AttrProps
|
|
57
|
+
|
|
58
|
+
type ElementChildrenAttribute = { children: Children }
|
|
59
|
+
|
|
60
|
+
type TagProps<TTag extends Type> = TTag extends Tag
|
|
61
|
+
? IntrinsicElements[TTag] & IntrinsicAttributes
|
|
62
|
+
: TTag extends Function<infer TArguments>
|
|
63
|
+
? TArguments
|
|
64
|
+
: TTag extends Component<infer TArguments>
|
|
65
|
+
? TArguments
|
|
66
|
+
: never
|
|
67
|
+
|
|
68
|
+
function Fragment({ children }: ElementChildrenAttribute): typeof children
|
|
69
|
+
function h<TTag extends Tag>(tag: TTag, props?: TagProps<TTag> | null, ...children: Array<unknown>): AjoNode<TTag>
|
|
70
|
+
function render(h: Children, el: Element): void
|
|
58
71
|
}
|
|
59
72
|
|
|
60
|
-
declare namespace
|
|
61
|
-
|
|
62
|
-
|
|
73
|
+
declare namespace JSX {
|
|
74
|
+
type ElementChildrenAttribute = import('ajo').ElementChildrenAttribute
|
|
75
|
+
type IntrinsicElements = import('ajo').IntrinsicElements
|
|
76
|
+
type IntrinsicAttributes = import('ajo').IntrinsicAttributes
|
|
63
77
|
}
|
|
64
78
|
|
|
65
|
-
declare
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
79
|
+
declare namespace React {
|
|
80
|
+
const createElement: typeof import('ajo').h
|
|
81
|
+
const Fragment: typeof import('ajo').Fragment
|
|
82
|
+
type ReactNode = import('ajo').Children
|
|
69
83
|
}
|