ajo 0.0.14 → 0.0.17
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/index.cjs +124 -107
- package/index.js +172 -140
- package/index.min.js +1 -1
- package/license +15 -0
- package/package.json +13 -3
- package/readme.md +37 -10
package/index.cjs
CHANGED
|
@@ -17,6 +17,7 @@ var __copyProps = (to, from2, except, desc) => {
|
|
|
17
17
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
18
|
var ajo_exports = {};
|
|
19
19
|
__export(ajo_exports, {
|
|
20
|
+
For: () => For,
|
|
20
21
|
Fragment: () => Fragment,
|
|
21
22
|
cleanup: () => cleanup,
|
|
22
23
|
clx: () => clx,
|
|
@@ -32,140 +33,156 @@ __export(ajo_exports, {
|
|
|
32
33
|
stx: () => stx
|
|
33
34
|
});
|
|
34
35
|
module.exports = __toCommonJS(ajo_exports);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}, component = (setup) => ({ is, key, host, ref, ...props }) => h(is ?? setup.is ?? "div", {
|
|
39
|
-
key,
|
|
40
|
-
...setup.host,
|
|
41
|
-
...host,
|
|
36
|
+
var import_element_notifier = require("element-notifier");
|
|
37
|
+
const Fragment = ({ children }) => children, For = ({ is, each, by, children, ref: ref2, ...props }) => h(is ?? "div", {
|
|
38
|
+
...props,
|
|
42
39
|
skip: true,
|
|
43
|
-
ref: (
|
|
44
|
-
}), render = (h2, host) => {
|
|
45
|
-
let child = host.firstChild, node
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
40
|
+
ref: (host, root) => iterate(host, root, each, by, children, ref2)
|
|
41
|
+
}), h = (nodeName, props, ...children) => ({ children: children.length == 0 ? null : children.length == 1 ? children[0] : children, ...props, nodeName }), render = (h2, host, to, root = host) => {
|
|
42
|
+
let child = host.firstChild, node;
|
|
43
|
+
root == host && (root.$mo ??= (0, import_element_notifier.notify)((host2, connected) => connected || root.contains(host2) || dispose(host2), root));
|
|
44
|
+
for (h2 of normalize(h2)) {
|
|
45
|
+
if (h2 instanceof Node)
|
|
46
|
+
node = h2;
|
|
47
|
+
else if (typeof h2 == "string") {
|
|
48
|
+
for (node = child; node != to; node = node.nextSibling)
|
|
49
49
|
if (node.nodeType == 3)
|
|
50
50
|
break;
|
|
51
|
-
node ? node
|
|
52
|
-
} else if (h2 instanceof Node) {
|
|
53
|
-
node = h2;
|
|
51
|
+
node == to ? node = document.createTextNode(h2) : node.data != h2 && (node.data = h2);
|
|
54
52
|
} else {
|
|
55
|
-
const {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
!(skip || block != null && every(deps.get(node), deps.set(node, block))) && render(children, node);
|
|
66
|
-
isFn(ref) && ref(node);
|
|
53
|
+
const { nodeName, block, skip, children, ref: ref2, ...props } = h2;
|
|
54
|
+
for (node = child; node != to; node = node.nextSibling)
|
|
55
|
+
if (node.localName == nodeName)
|
|
56
|
+
break;
|
|
57
|
+
node == to && (node = document.createElement(nodeName));
|
|
58
|
+
if (block == null || some(node.$deps, node.$deps = block)) {
|
|
59
|
+
update(props, node);
|
|
60
|
+
skip || render(children, node, null, root);
|
|
61
|
+
isFunction(ref2) && ref2(node, root);
|
|
62
|
+
}
|
|
67
63
|
}
|
|
68
|
-
node
|
|
64
|
+
node == child ? child = child.nextSibling : before(host, node, child);
|
|
69
65
|
}
|
|
70
|
-
while (child) {
|
|
66
|
+
while (child != to) {
|
|
71
67
|
const next = child.nextSibling;
|
|
72
|
-
host.removeChild(child)
|
|
68
|
+
host.removeChild(child);
|
|
73
69
|
child = next;
|
|
74
70
|
}
|
|
75
|
-
},
|
|
71
|
+
}, component = (setup) => ({ is, props, ref: ref2, ...params }) => h(is ?? setup.is ?? "div", {
|
|
72
|
+
...setup.props,
|
|
73
|
+
...props,
|
|
74
|
+
skip: true,
|
|
75
|
+
ref: (host, root) => run(host, root, setup, params, ref2)
|
|
76
|
+
}), refresh = (host) => {
|
|
76
77
|
try {
|
|
77
|
-
|
|
78
|
-
throwTypeError("Setup", setup, fn);
|
|
79
|
-
props = props ? memo.set(host, { ...setup?.props, ...props }) : memo.get(host) ?? {};
|
|
80
|
-
render((renders.get(host) ?? renders.set(host, setup(props, host)))(props, host), host);
|
|
78
|
+
render((host.$render ??= host.$setup(host))(host.$params), host, null, host.$root);
|
|
81
79
|
} catch (error) {
|
|
82
80
|
propagate(host, error);
|
|
83
81
|
}
|
|
84
|
-
}, provide = (host, key, value) => (provisions
|
|
85
|
-
let
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
return map.get(key);
|
|
89
|
-
host = host.parentNode;
|
|
90
|
-
}
|
|
82
|
+
}, provide = (host, key, value) => (host.$provisions ??= /* @__PURE__ */ new Map()).set(key, value), consume = (host, key, fallback) => {
|
|
83
|
+
for (let map2; host; host = host.parentNode)
|
|
84
|
+
if ((map2 = host.$provisions) && map2.has(key))
|
|
85
|
+
return map2.get(key);
|
|
91
86
|
return fallback;
|
|
92
|
-
}, intercept = (host, interceptor) => {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}, propagate = (host, error) => {
|
|
97
|
-
for (let interceptor; host; host = host.parentNode)
|
|
98
|
-
if (interceptor = interceptors.get(host))
|
|
99
|
-
return render(interceptor(error), host);
|
|
87
|
+
}, intercept = (host, fn) => isFunction(fn) && (host.$interceptor = fn), propagate = (host, error) => {
|
|
88
|
+
for (let fn; host; host = host.parentNode)
|
|
89
|
+
if (isFunction(fn = host.$interceptor))
|
|
90
|
+
return render(fn(error));
|
|
100
91
|
throw error;
|
|
101
|
-
}, cleanup = (host,
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
const instance = /* @__PURE__ */ new WeakMap(), { set } = instance;
|
|
108
|
-
instance.set = (key, value) => (set.call(instance, key, value), value);
|
|
109
|
-
return instance;
|
|
110
|
-
}, throwTypeError = (name, value, expected) => {
|
|
111
|
-
throw new TypeError(`Expected ${name} to be of type ${expected}, got ${typeof value} instead`);
|
|
112
|
-
}, every = (a, b) => a === b || isArray(a) && isArray(b) && a.length == b.length && a.every((v, i) => v === b[i]), apply = (o, { name, value }) => (o[name] = value, o), reduce = (list) => from(list).reduce(apply, {}), isFn = (v) => typeof v == fn, { keys, entries } = Object, { isArray, from } = Array, fn = "function", search = /([a-z0-9])([A-Z])/g, replace = "$1-$2", keyed = wm(), deps = wm(), memo = wm(), renders = wm(), provisions = wm(), interceptors = wm(), cleaners = wm(), cache = wm(), normalize = function* (h2, host) {
|
|
113
|
-
let type, buffer = "";
|
|
114
|
-
for (h2 of isFn(h2?.[Symbol.iterator]) ? h2 : [h2]) {
|
|
115
|
-
if (h2 == null || (type = typeof h2) == "boolean")
|
|
116
|
-
continue;
|
|
117
|
-
if (type == "string" || type == "number") {
|
|
118
|
-
buffer += h2;
|
|
119
|
-
continue;
|
|
120
|
-
}
|
|
121
|
-
if ("nodeName" in Object(h2)) {
|
|
122
|
-
if (isFn(h2.nodeName)) {
|
|
123
|
-
yield* normalize(h2.nodeName(h2, host), host);
|
|
124
|
-
continue;
|
|
125
|
-
}
|
|
126
|
-
if (buffer) {
|
|
127
|
-
yield buffer;
|
|
128
|
-
buffer = "";
|
|
129
|
-
}
|
|
130
|
-
yield h2;
|
|
92
|
+
}, cleanup = (host, fn) => isFunction(fn) && (host.$cleanups ??= /* @__PURE__ */ new Set()).add(fn), clx = (o) => keys(o).filter((k) => o[k]).join(" ") || null, stx = (o) => entries(o).map((t) => t.join(":")).join(";") || null, keb = (o) => keys(o).reduce((r, k) => (r[k.replace(search, replace).toLowerCase()] = o[k], r), {});
|
|
93
|
+
const { isArray, from } = Array, { keys, entries } = Object, isFunction = (v) => typeof v == "function", noop = () => {
|
|
94
|
+
}, ref = (v) => (...args) => args.length ? v = args[0] : v, map = (list) => list.reduce(set, /* @__PURE__ */ new Map()), set = (m, v, i) => (m.set(v, i), m), some = (a, b) => isArray(a) && isArray(b) ? a.some((v, i) => v !== b[i]) : a !== b, reduce = (v) => from(v).reduce(assign, {}), assign = (v, { name, value }) => (v[name] = value, v), proxy = { firstChild: null, insertBefore: (node) => proxy.firstChild ??= node }, search = /([a-z0-9])([A-Z])/g, replace = "$1-$2", normalize = function* (h2, buffer = ref(""), root = true) {
|
|
95
|
+
let text;
|
|
96
|
+
for (h2 of isArray(h2) ? h2 : [h2]) {
|
|
97
|
+
if (h2 == null || typeof h2 == "boolean")
|
|
131
98
|
continue;
|
|
132
|
-
|
|
133
|
-
|
|
99
|
+
if (typeof h2.nodeName == "string")
|
|
100
|
+
(text = buffer()) && (buffer(""), yield text), yield h2;
|
|
101
|
+
else if (isFunction(h2.nodeName))
|
|
102
|
+
yield* normalize(h2.nodeName(h2), buffer, false);
|
|
103
|
+
else
|
|
104
|
+
isArray(h2) ? yield* normalize(h2, buffer, false) : buffer(buffer() + h2);
|
|
134
105
|
}
|
|
135
|
-
|
|
136
|
-
yield buffer;
|
|
106
|
+
root && (text = buffer()) && (yield text);
|
|
137
107
|
}, update = (props, host) => {
|
|
138
|
-
const prev =
|
|
108
|
+
const prev = host.$props ?? (host.hasAttributes() ? reduce(host.attributes) : {});
|
|
139
109
|
for (const name in { ...prev, ...props }) {
|
|
140
110
|
let value = props[name];
|
|
141
|
-
if (value
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
value = "";
|
|
149
|
-
else if (value == null || value === false) {
|
|
150
|
-
host.removeAttribute(name);
|
|
151
|
-
continue;
|
|
152
|
-
}
|
|
153
|
-
host.setAttribute(name, value);
|
|
111
|
+
if (value !== prev[name])
|
|
112
|
+
if (name.startsWith("set:"))
|
|
113
|
+
host[name.slice(4)] = value;
|
|
114
|
+
else if (value == null || value === false)
|
|
115
|
+
host.removeAttribute(name);
|
|
116
|
+
else
|
|
117
|
+
host.setAttribute(name, value === true ? "" : value);
|
|
154
118
|
}
|
|
155
|
-
|
|
156
|
-
}, before = (host,
|
|
119
|
+
host.$props = props;
|
|
120
|
+
}, before = (host, node, child) => {
|
|
157
121
|
if (node.contains?.(document.activeElement)) {
|
|
158
|
-
const
|
|
122
|
+
const ref2 = node.nextSibling;
|
|
159
123
|
while (child && child !== node) {
|
|
160
124
|
const next = child.nextSibling;
|
|
161
|
-
host.insertBefore(child,
|
|
125
|
+
host.insertBefore(child, ref2);
|
|
162
126
|
child = next;
|
|
163
127
|
}
|
|
164
128
|
} else
|
|
165
129
|
host.insertBefore(node, child);
|
|
130
|
+
}, iterate = (host, root, each, by, fn, ref2) => {
|
|
131
|
+
each = isArray(each) ? each : [];
|
|
132
|
+
by = isFunction(by) ? by : (v) => v;
|
|
133
|
+
fn = isFunction(fn) ? fn : noop;
|
|
134
|
+
const map2 = host.$for ??= /* @__PURE__ */ new Map(), del = (node) => map2.delete(node.$key), clr = each !== host.$each, len = (host.$each = each).length, a = from(host.childNodes), b = new Array(len);
|
|
135
|
+
clr && map2.clear();
|
|
136
|
+
for (let last, index = 0; index < len; index++) {
|
|
137
|
+
const item = each[index], key = by(item, index);
|
|
138
|
+
proxy.firstChild = (clr ? a[index] : map2.get(key)) ?? last?.cloneNode(true);
|
|
139
|
+
render(fn(item), proxy, proxy.firstChild?.nextSibling, root);
|
|
140
|
+
last = proxy.firstChild;
|
|
141
|
+
proxy.firstChild = null;
|
|
142
|
+
map2.set(last.$key = key, b[index] = last);
|
|
143
|
+
}
|
|
144
|
+
arrange(host, a, b, del);
|
|
145
|
+
isFunction(ref2) && ref2(host, root);
|
|
146
|
+
}, arrange = (host, a, b, dispose2 = noop) => {
|
|
147
|
+
const aLen = a.length, bLen = b.length;
|
|
148
|
+
let aIndex = 0, bIndex = 0, aValue, bValue, aMap, bMap, i;
|
|
149
|
+
while (aIndex !== aLen || bIndex !== bLen) {
|
|
150
|
+
aValue = a[aIndex];
|
|
151
|
+
bValue = b[bIndex];
|
|
152
|
+
if (aValue === null)
|
|
153
|
+
aIndex++;
|
|
154
|
+
else if (bLen <= bIndex)
|
|
155
|
+
aIndex++, dispose2(host.removeChild(aValue));
|
|
156
|
+
else if (aLen <= aIndex)
|
|
157
|
+
bIndex++, host.appendChild(bValue);
|
|
158
|
+
else if (aValue === bValue)
|
|
159
|
+
aIndex++, bIndex++;
|
|
160
|
+
else {
|
|
161
|
+
aMap ??= map(a);
|
|
162
|
+
bMap ??= map(b);
|
|
163
|
+
if (bMap.get(aValue) == null)
|
|
164
|
+
aIndex++, dispose2(host.removeChild(aValue));
|
|
165
|
+
else {
|
|
166
|
+
host.insertBefore(bValue, aValue), bIndex++;
|
|
167
|
+
if ((i = aMap.get(bValue)) != null) {
|
|
168
|
+
if (i > aIndex + 1)
|
|
169
|
+
aIndex++;
|
|
170
|
+
a[i] = null;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}, run = (host, root, setup, params, ref2) => {
|
|
176
|
+
host.$root = root;
|
|
177
|
+
host.$setup ??= isFunction(setup) ? setup : noop;
|
|
178
|
+
host.$params = { ...setup.params, ...params };
|
|
179
|
+
refresh(host);
|
|
180
|
+
isFunction(ref2) && ref2(host, root);
|
|
166
181
|
}, dispose = (host) => {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
182
|
+
const { $cleanups } = host;
|
|
183
|
+
if ($cleanups) {
|
|
184
|
+
for (let fn of $cleanups)
|
|
185
|
+
fn(host);
|
|
186
|
+
$cleanups.clear();
|
|
187
|
+
}
|
|
171
188
|
};
|
package/index.js
CHANGED
|
@@ -1,198 +1,230 @@
|
|
|
1
|
-
|
|
2
|
-
Fragment = ({ children }) => children,
|
|
1
|
+
import { notify } from 'element-notifier'
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
return { children, ...props, nodeName }
|
|
7
|
-
},
|
|
3
|
+
export const
|
|
4
|
+
Fragment = ({ children }) => children,
|
|
8
5
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
For = ({ is, each, by, children, ref, ...props }) => h(is ?? 'div', {
|
|
7
|
+
...props, skip: true, ref: (host, root) => iterate(host, root, each, by, children, ref)
|
|
8
|
+
}),
|
|
12
9
|
|
|
13
|
-
|
|
10
|
+
h = (nodeName, props, ...children) => ({ children: children.length == 0 ? null : children.length == 1 ? children[0] : children, ...props, nodeName }),
|
|
14
11
|
|
|
15
|
-
|
|
12
|
+
render = (h, host, to, root = host) => {
|
|
16
13
|
|
|
17
|
-
|
|
14
|
+
let child = host.firstChild, node
|
|
18
15
|
|
|
19
|
-
|
|
16
|
+
root == host && (root.$mo ??= notify((host, connected) => connected || root.contains(host) || dispose(host), root))
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
node ? node.data !== h && (node.data = h) : node = document.createTextNode(h)
|
|
18
|
+
for (h of normalize(h)) {
|
|
23
19
|
|
|
24
|
-
|
|
20
|
+
if (h instanceof Node) node = h
|
|
25
21
|
|
|
26
|
-
|
|
22
|
+
else if (typeof h == 'string') {
|
|
27
23
|
|
|
28
|
-
|
|
24
|
+
for (node = child; node != to; node = node.nextSibling) if (node.nodeType == 3) break
|
|
25
|
+
node == to ? node = document.createTextNode(h) : node.data != h && (node.data = h)
|
|
29
26
|
|
|
30
|
-
|
|
27
|
+
} else {
|
|
31
28
|
|
|
32
|
-
|
|
33
|
-
else for (node = child; node; node = node.nextSibling) if (node.localName == nodeName) break
|
|
29
|
+
const { nodeName, block, skip, children, ref, ...props } = h
|
|
34
30
|
|
|
35
|
-
|
|
31
|
+
for (node = child; node != to; node = node.nextSibling) if (node.localName == nodeName) break
|
|
32
|
+
node == to && (node = document.createElement(nodeName))
|
|
36
33
|
|
|
37
|
-
|
|
34
|
+
if (block == null || some(node.$deps, node.$deps = block)) {
|
|
35
|
+
update(props, node)
|
|
36
|
+
skip || render(children, node, null, root)
|
|
37
|
+
isFunction(ref) && ref(node, root)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
38
40
|
|
|
39
|
-
|
|
41
|
+
node == child ? child = child.nextSibling : before(host, node, child)
|
|
42
|
+
}
|
|
40
43
|
|
|
41
|
-
|
|
44
|
+
while (child != to) {
|
|
45
|
+
const next = child.nextSibling
|
|
46
|
+
host.removeChild(child)
|
|
47
|
+
child = next
|
|
48
|
+
}
|
|
49
|
+
},
|
|
42
50
|
|
|
43
|
-
|
|
44
|
-
|
|
51
|
+
component = setup => ({ is, props, ref, ...params }) => h(is ?? setup.is ?? 'div', {
|
|
52
|
+
...setup.props, ...props, skip: true, ref: (host, root) => run(host, root, setup, params, ref)
|
|
53
|
+
}),
|
|
45
54
|
|
|
46
|
-
|
|
47
|
-
|
|
55
|
+
refresh = host => {
|
|
56
|
+
try {
|
|
57
|
+
render((host.$render ??= host.$setup(host))(host.$params), host, null, host.$root)
|
|
58
|
+
} catch (error) {
|
|
59
|
+
propagate(host, error)
|
|
60
|
+
}
|
|
61
|
+
},
|
|
48
62
|
|
|
49
|
-
|
|
50
|
-
const next = child.nextSibling
|
|
51
|
-
host.removeChild(child).nodeType == 1 && dispose(child)
|
|
52
|
-
child = next
|
|
53
|
-
}
|
|
54
|
-
},
|
|
63
|
+
provide = (host, key, value) => (host.$provisions ??= new Map).set(key, value),
|
|
55
64
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
render((renders.get(host) ?? renders.set(host, setup(props, host)))(props, host), host)
|
|
61
|
-
} catch (error) {
|
|
62
|
-
propagate(host, error)
|
|
63
|
-
}
|
|
64
|
-
},
|
|
65
|
+
consume = (host, key, fallback) => {
|
|
66
|
+
for (let map; host; host = host.parentNode) if ((map = host.$provisions) && map.has(key)) return map.get(key)
|
|
67
|
+
return fallback
|
|
68
|
+
},
|
|
65
69
|
|
|
66
|
-
|
|
70
|
+
intercept = (host, fn) => isFunction(fn) && (host.$interceptor = fn),
|
|
67
71
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
host = host.parentNode
|
|
73
|
-
}
|
|
74
|
-
return fallback
|
|
75
|
-
},
|
|
72
|
+
propagate = (host, error) => {
|
|
73
|
+
for (let fn; host; host = host.parentNode) if (isFunction(fn = host.$interceptor)) return render(fn(error))
|
|
74
|
+
throw error
|
|
75
|
+
},
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
if (!isFn(interceptor)) throwTypeError('Interceptor', interceptor, fn)
|
|
79
|
-
interceptors.set(host, interceptor)
|
|
80
|
-
},
|
|
77
|
+
cleanup = (host, fn) => isFunction(fn) && (host.$cleanups ??= new Set).add(fn),
|
|
81
78
|
|
|
82
|
-
|
|
83
|
-
for (let interceptor; host; host = host.parentNode)
|
|
84
|
-
if (interceptor = interceptors.get(host)) return render(interceptor(error), host)
|
|
85
|
-
throw error
|
|
86
|
-
},
|
|
79
|
+
clx = o => keys(o).filter(k => o[k]).join(' ') || null,
|
|
87
80
|
|
|
88
|
-
|
|
89
|
-
if (!isFn(cleaner)) throwTypeError('Cleaner', cleaner, fn);
|
|
90
|
-
(cleaners.get(host) ?? cleaners.set(host, new Set)).add(cleaner)
|
|
91
|
-
},
|
|
81
|
+
stx = o => entries(o).map(t => t.join(':')).join(';') || null,
|
|
92
82
|
|
|
93
|
-
|
|
94
|
-
stx = o => entries(o).map(t => t.join(':')).join(';') || null,
|
|
95
|
-
keb = o => keys(o).reduce((r, k) => ((r[k.replace(search, replace).toLowerCase()] = o[k]), r), {})
|
|
83
|
+
keb = o => keys(o).reduce((r, k) => ((r[k.replace(search, replace).toLowerCase()] = o[k]), r), {})
|
|
96
84
|
|
|
97
85
|
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
86
|
+
{ isArray, from } = Array, { keys, entries } = Object, isFunction = v => typeof v == 'function',
|
|
87
|
+
|
|
88
|
+
noop = () => { }, ref = v => (...args) => args.length ? v = args[0] : v,
|
|
89
|
+
|
|
90
|
+
map = list => list.reduce(set, new Map), set = (m, v, i) => (m.set(v, i), m),
|
|
91
|
+
|
|
92
|
+
some = (a, b) => (isArray(a) && isArray(b)) ? a.some((v, i) => v !== b[i]) : a !== b,
|
|
93
|
+
|
|
94
|
+
reduce = v => from(v).reduce(assign, {}), assign = (v, { name, value }) => ((v[name] = value), v),
|
|
95
|
+
|
|
96
|
+
proxy = { firstChild: null, insertBefore: node => proxy.firstChild ??= node },
|
|
97
|
+
|
|
98
|
+
search = /([a-z0-9])([A-Z])/g, replace = '$1-$2',
|
|
99
|
+
|
|
100
|
+
normalize = function* (h, buffer = ref(''), root = true) {
|
|
101
|
+
|
|
102
|
+
let text
|
|
103
|
+
|
|
104
|
+
for (h of isArray(h) ? h : [h]) {
|
|
105
|
+
if (h == null || typeof h == 'boolean') continue
|
|
106
|
+
if (typeof h.nodeName == 'string') ((text = buffer()) && (buffer(''), yield text)), yield h
|
|
107
|
+
else if (isFunction(h.nodeName)) yield* normalize(h.nodeName(h), buffer, false)
|
|
108
|
+
else isArray(h) ? yield* normalize(h, buffer, false) : buffer(buffer() + h)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
root && (text = buffer()) && (yield text)
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
update = (props, host) => {
|
|
115
|
+
|
|
116
|
+
const prev = host.$props ?? (host.hasAttributes() ? reduce(host.attributes) : {})
|
|
117
|
+
|
|
118
|
+
for (const name in { ...prev, ...props }) {
|
|
119
|
+
|
|
120
|
+
let value = props[name]
|
|
121
|
+
|
|
122
|
+
if (value !== prev[name])
|
|
123
|
+
if (name.startsWith('set:')) host[name.slice(4)] = value
|
|
124
|
+
else if (value == null || value === false) host.removeAttribute(name)
|
|
125
|
+
else host.setAttribute(name, value === true ? '' : value)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
host.$props = props
|
|
129
|
+
},
|
|
103
130
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
},
|
|
131
|
+
before = (host, node, child) => {
|
|
132
|
+
if (node.contains?.(document.activeElement)) {
|
|
107
133
|
|
|
108
|
-
|
|
109
|
-
apply = (o, { name, value }) => ((o[name] = value), o),
|
|
110
|
-
reduce = list => from(list).reduce(apply, {}),
|
|
111
|
-
isFn = v => typeof v == fn,
|
|
134
|
+
const ref = node.nextSibling
|
|
112
135
|
|
|
113
|
-
|
|
136
|
+
while (child && child !== node) {
|
|
137
|
+
const next = child.nextSibling
|
|
138
|
+
host.insertBefore(child, ref)
|
|
139
|
+
child = next
|
|
140
|
+
}
|
|
114
141
|
|
|
115
|
-
|
|
142
|
+
} else host.insertBefore(node, child)
|
|
143
|
+
},
|
|
116
144
|
|
|
117
|
-
|
|
145
|
+
iterate = (host, root, each, by, fn, ref) => {
|
|
118
146
|
|
|
119
|
-
|
|
147
|
+
each = isArray(each) ? each : []
|
|
148
|
+
by = isFunction(by) ? by : v => v
|
|
149
|
+
fn = isFunction(fn) ? fn : noop
|
|
120
150
|
|
|
121
|
-
|
|
151
|
+
const
|
|
152
|
+
map = host.$for ??= new Map,
|
|
153
|
+
del = node => map.delete(node.$key),
|
|
154
|
+
clr = each !== host.$each,
|
|
155
|
+
len = (host.$each = each).length,
|
|
156
|
+
a = from(host.childNodes),
|
|
157
|
+
b = new Array(len)
|
|
122
158
|
|
|
123
|
-
|
|
159
|
+
clr && map.clear()
|
|
124
160
|
|
|
125
|
-
|
|
161
|
+
for (let last, index = 0; index < len; index++) {
|
|
126
162
|
|
|
127
|
-
|
|
128
|
-
buffer += h
|
|
129
|
-
continue
|
|
130
|
-
}
|
|
163
|
+
const item = each[index], key = by(item, index)
|
|
131
164
|
|
|
132
|
-
|
|
165
|
+
proxy.firstChild = (clr ? a[index] : map.get(key)) ?? last?.cloneNode(true)
|
|
166
|
+
render(fn(item), proxy, proxy.firstChild?.nextSibling, root)
|
|
133
167
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
continue
|
|
137
|
-
}
|
|
168
|
+
last = proxy.firstChild
|
|
169
|
+
proxy.firstChild = null
|
|
138
170
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
buffer = ''
|
|
142
|
-
}
|
|
171
|
+
map.set(last.$key = key, b[index] = last)
|
|
172
|
+
}
|
|
143
173
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
174
|
+
arrange(host, a, b, del)
|
|
175
|
+
isFunction(ref) && ref(host, root)
|
|
176
|
+
},
|
|
147
177
|
|
|
148
|
-
|
|
149
|
-
}
|
|
178
|
+
arrange = (host, a, b, dispose = noop) => {
|
|
150
179
|
|
|
151
|
-
|
|
152
|
-
},
|
|
180
|
+
const aLen = a.length, bLen = b.length
|
|
153
181
|
|
|
154
|
-
|
|
182
|
+
let aIndex = 0, bIndex = 0, aValue, bValue, aMap, bMap, i
|
|
155
183
|
|
|
156
|
-
|
|
184
|
+
while (aIndex !== aLen || bIndex !== bLen) {
|
|
157
185
|
|
|
158
|
-
|
|
186
|
+
aValue = a[aIndex]
|
|
187
|
+
bValue = b[bIndex]
|
|
159
188
|
|
|
160
|
-
|
|
189
|
+
if (aValue === null) aIndex++
|
|
190
|
+
else if (bLen <= bIndex) aIndex++, dispose(host.removeChild(aValue))
|
|
191
|
+
else if (aLen <= aIndex) bIndex++, host.appendChild(bValue)
|
|
192
|
+
else if (aValue === bValue) aIndex++, bIndex++
|
|
193
|
+
else {
|
|
161
194
|
|
|
162
|
-
|
|
195
|
+
aMap ??= map(a)
|
|
196
|
+
bMap ??= map(b)
|
|
163
197
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
continue
|
|
167
|
-
}
|
|
198
|
+
if (bMap.get(aValue) == null) aIndex++, dispose(host.removeChild(aValue))
|
|
199
|
+
else {
|
|
168
200
|
|
|
169
|
-
|
|
170
|
-
else if (value == null || value === false) {
|
|
171
|
-
host.removeAttribute(name)
|
|
172
|
-
continue
|
|
173
|
-
}
|
|
201
|
+
host.insertBefore(bValue, aValue), bIndex++
|
|
174
202
|
|
|
175
|
-
|
|
176
|
-
|
|
203
|
+
if ((i = aMap.get(bValue)) != null) {
|
|
204
|
+
if (i > aIndex + 1) aIndex++
|
|
205
|
+
a[i] = null
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
},
|
|
177
211
|
|
|
178
|
-
|
|
179
|
-
},
|
|
212
|
+
run = (host, root, setup, params, ref) => {
|
|
180
213
|
|
|
181
|
-
|
|
182
|
-
|
|
214
|
+
host.$root = root
|
|
215
|
+
host.$setup ??= isFunction(setup) ? setup : noop
|
|
216
|
+
host.$params = { ...setup.params, ...params }
|
|
183
217
|
|
|
184
|
-
|
|
218
|
+
refresh(host)
|
|
219
|
+
isFunction(ref) && ref(host, root)
|
|
220
|
+
},
|
|
185
221
|
|
|
186
|
-
|
|
187
|
-
const next = child.nextSibling
|
|
188
|
-
host.insertBefore(child, ref)
|
|
189
|
-
child = next
|
|
190
|
-
}
|
|
222
|
+
dispose = host => {
|
|
191
223
|
|
|
192
|
-
|
|
193
|
-
},
|
|
224
|
+
const { $cleanups } = host
|
|
194
225
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
226
|
+
if ($cleanups) {
|
|
227
|
+
for (let fn of $cleanups) fn(host)
|
|
228
|
+
$cleanups.clear()
|
|
229
|
+
}
|
|
230
|
+
}
|
package/index.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var ajo=(()=>{var
|
|
1
|
+
var ajo=(()=>{var y=Object.defineProperty;var F=Object.getOwnPropertyDescriptor;var L=Object.getOwnPropertyNames;var z=Object.prototype.hasOwnProperty;var E=(e,n)=>{for(var i in n)y(e,i,{get:n[i],enumerable:!0})},I=(e,n,i,l)=>{if(n&&typeof n=="object"||typeof n=="function")for(let r of L(n))!z.call(e,r)&&r!==i&&y(e,r,{get:()=>n[r],enumerable:!(l=F(n,r))||l.enumerable});return e};var T=e=>I(y({},"__esModule",{value:!0}),e);var ae={};E(ae,{For:()=>O,Fragment:()=>V,cleanup:()=>G,clx:()=>H,component:()=>W,consume:()=>q,h:()=>N,intercept:()=>D,keb:()=>K,propagate:()=>M,provide:()=>Z,refresh:()=>A,render:()=>x,stx:()=>J});var S=require("element-notifier");const V=({children:e})=>e,O=({is:e,each:n,by:i,children:l,ref:r,...t})=>N(e??"div",{...t,skip:!0,ref:(a,f)=>ie(a,f,n,i,l,r)}),N=(e,n,...i)=>({children:i.length==0?null:i.length==1?i[0]:i,...n,nodeName:e}),x=(e,n,i,l=n)=>{let r=n.firstChild,t;l==n&&(l.$mo??=(0,S.notify)((a,f)=>f||l.contains(a)||te(a),l));for(e of C(e)){if(e instanceof Node)t=e;else if(typeof e=="string"){for(t=r;t!=i&&t.nodeType!=3;t=t.nextSibling);t==i?t=document.createTextNode(e):t.data!=e&&(t.data=e)}else{const{nodeName:a,block:f,skip:p,children:d,ref:o,...u}=e;for(t=r;t!=i&&t.localName!=a;t=t.nextSibling);t==i&&(t=document.createElement(a)),(f==null||U(t.$deps,t.$deps=f))&&(ee(u,t),p||x(d,t,null,l),c(o)&&o(t,l))}t==r?r=r.nextSibling:ne(n,t,r)}for(;r!=i;){const a=r.nextSibling;n.removeChild(r),r=a}},W=e=>({is:n,props:i,ref:l,...r})=>N(n??e.is??"div",{...e.props,...i,skip:!0,ref:(t,a)=>re(t,a,e,r,l)}),A=e=>{try{x((e.$render??=e.$setup(e))(e.$params),e,null,e.$root)}catch(n){M(e,n)}},Z=(e,n,i)=>(e.$provisions??=new Map).set(n,i),q=(e,n,i)=>{for(let l;e;e=e.parentNode)if((l=e.$provisions)&&l.has(n))return l.get(n);return i},D=(e,n)=>c(n)&&(e.$interceptor=n),M=(e,n)=>{for(let i;e;e=e.parentNode)if(c(i=e.$interceptor))return x(i(n));throw n},G=(e,n)=>c(n)&&(e.$cleanups??=new Set).add(n),H=e=>B(e).filter(n=>e[n]).join(" ")||null,J=e=>P(e).map(n=>n.join(":")).join(";")||null,K=e=>B(e).reduce((n,i)=>(n[i.replace(_,h).toLowerCase()]=e[i],n),{}),{isArray:g,from:j}=Array,{keys:B,entries:P}=Object,c=e=>typeof e=="function",b=()=>{},Q=e=>(...n)=>n.length?e=n[0]:e,k=e=>e.reduce(R,new Map),R=(e,n,i)=>(e.set(n,i),e),U=(e,n)=>g(e)&&g(n)?e.some((i,l)=>i!==n[l]):e!==n,X=e=>j(e).reduce(Y,{}),Y=(e,{name:n,value:i})=>(e[n]=i,e),$={firstChild:null,insertBefore:e=>$.firstChild??=e},_=/([a-z0-9])([A-Z])/g,h="$1-$2",C=function*(e,n=Q(""),i=!0){let l;for(e of g(e)?e:[e])e==null||typeof e=="boolean"||(typeof e.nodeName=="string"?((l=n())&&(n(""),yield l),yield e):c(e.nodeName)?yield*C(e.nodeName(e),n,!1):g(e)?yield*C(e,n,!1):n(n()+e));i&&(l=n())&&(yield l)},ee=(e,n)=>{const i=n.$props??(n.hasAttributes()?X(n.attributes):{});for(const l in{...i,...e}){let r=e[l];r!==i[l]&&(l.startsWith("set:")?n[l.slice(4)]=r:r==null||r===!1?n.removeAttribute(l):n.setAttribute(l,r===!0?"":r))}n.$props=e},ne=(e,n,i)=>{if(n.contains?.(document.activeElement)){const l=n.nextSibling;for(;i&&i!==n;){const r=i.nextSibling;e.insertBefore(i,l),i=r}}else e.insertBefore(n,i)},ie=(e,n,i,l,r,t)=>{i=g(i)?i:[],l=c(l)?l:s=>s,r=c(r)?r:b;const a=e.$for??=new Map,f=s=>a.delete(s.$key),p=i!==e.$each,d=(e.$each=i).length,o=j(e.childNodes),u=new Array(d);p&&a.clear();for(let s,m=0;m<d;m++){const v=i[m],w=l(v,m);$.firstChild=(p?o[m]:a.get(w))??s?.cloneNode(!0),x(r(v),$,$.firstChild?.nextSibling,n),s=$.firstChild,$.firstChild=null,a.set(s.$key=w,u[m]=s)}le(e,o,u,f),c(t)&&t(e,n)},le=(e,n,i,l=b)=>{const r=n.length,t=i.length;let a=0,f=0,p,d,o,u,s;for(;a!==r||f!==t;)p=n[a],d=i[f],p===null?a++:t<=f?(a++,l(e.removeChild(p))):r<=a?(f++,e.appendChild(d)):p===d?(a++,f++):(o??=k(n),u??=k(i),u.get(p)==null?(a++,l(e.removeChild(p))):(e.insertBefore(d,p),f++,(s=o.get(d))!=null&&(s>a+1&&a++,n[s]=null)))},re=(e,n,i,l,r)=>{e.$root=n,e.$setup??=c(i)?i:b,e.$params={...i.params,...l},A(e),c(r)&&r(e,n)},te=e=>{const{$cleanups:n}=e;if(n){for(let i of n)i(e);n.clear()}};return T(ae);})();
|
package/license
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022, Cristian Falcone, @cristianfalcone
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
10
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
11
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
12
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
13
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
|
14
|
+
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
15
|
+
PERFORMANCE OF THIS SOFTWARE.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ajo",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.17",
|
|
4
4
|
"description": "ajo is a JavaScript view library for building user interfaces",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "index.js",
|
|
@@ -17,6 +17,13 @@
|
|
|
17
17
|
"index.js",
|
|
18
18
|
"index.min.js"
|
|
19
19
|
],
|
|
20
|
+
"keywords": [
|
|
21
|
+
"ui",
|
|
22
|
+
"frontend",
|
|
23
|
+
"web",
|
|
24
|
+
"dom",
|
|
25
|
+
"jsx"
|
|
26
|
+
],
|
|
20
27
|
"scripts": {
|
|
21
28
|
"build": "npm run build:require && npm run build:browser",
|
|
22
29
|
"build:require": "esbuild --format=cjs --out-extension:.js=.cjs --outdir=. index.js",
|
|
@@ -30,8 +37,11 @@
|
|
|
30
37
|
"bugs": "https://github.com/cristianfalcone/ajo/issues",
|
|
31
38
|
"homepage": "https://github.com/cristianfalcone/ajo#readme",
|
|
32
39
|
"devDependencies": {
|
|
33
|
-
"backdom": "^0.0.
|
|
34
|
-
"esbuild": "^0.
|
|
40
|
+
"backdom": "^0.0.6",
|
|
41
|
+
"esbuild": "^0.15.6",
|
|
35
42
|
"uvu": "^0.5.6"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"element-notifier": "^1.1.2"
|
|
36
46
|
}
|
|
37
47
|
}
|
package/readme.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# ajo
|
|
2
2
|
ajo is a JavaScript view library for building user interfaces
|
|
3
3
|
|
|
4
|
-
##
|
|
4
|
+
## install
|
|
5
5
|
|
|
6
6
|
```sh
|
|
7
7
|
npm install ajo
|
|
8
8
|
```
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## render JSX to a DOM element
|
|
11
11
|
|
|
12
12
|
```jsx
|
|
13
13
|
/** @jsx h */
|
|
@@ -18,7 +18,7 @@ document.body.innerHTML = '<div>Hello World</div>'
|
|
|
18
18
|
render(<div>Goodbye World</div>, document.body)
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
##
|
|
21
|
+
## stateless component
|
|
22
22
|
|
|
23
23
|
```jsx
|
|
24
24
|
/** @jsx h */
|
|
@@ -29,26 +29,53 @@ const Greet = ({ name }) => <div>Hello {name}</div>
|
|
|
29
29
|
render(<Greet name="World" />, document.body)
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
##
|
|
32
|
+
## stateful component
|
|
33
33
|
|
|
34
34
|
```jsx
|
|
35
35
|
/** @jsx h */
|
|
36
36
|
import { h, component, refresh, render } from 'ajo'
|
|
37
37
|
|
|
38
|
-
const Counter = component(
|
|
39
|
-
|
|
40
|
-
let count =
|
|
41
|
-
|
|
38
|
+
const Counter = component(host => {
|
|
39
|
+
|
|
40
|
+
let count = 0
|
|
41
|
+
|
|
42
42
|
const increment = () => {
|
|
43
43
|
count++
|
|
44
44
|
refresh(host)
|
|
45
45
|
}
|
|
46
|
-
|
|
46
|
+
|
|
47
47
|
return () =>
|
|
48
48
|
<button set:onclick={increment}>
|
|
49
49
|
Current: {count}
|
|
50
50
|
</button>
|
|
51
51
|
})
|
|
52
52
|
|
|
53
|
-
render(<Counter
|
|
53
|
+
render(<Counter />, document.body)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## rendering lists
|
|
57
|
+
|
|
58
|
+
```jsx
|
|
59
|
+
/** @jsx h */
|
|
60
|
+
import { h, render, component, For } from 'ajo'
|
|
61
|
+
|
|
62
|
+
const products = [
|
|
63
|
+
{ title: 'Cabbage', isFruit: false, id: 1 },
|
|
64
|
+
{ title: 'Garlic', isFruit: false, id: 2 },
|
|
65
|
+
{ title: 'Apple', isFruit: true, id: 3 },
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
const ShoppingList = component(() => {
|
|
69
|
+
const listItem = product =>
|
|
70
|
+
<li style={stx({ color: product.isFruit ? 'magenta' : 'darkgreen' })}>
|
|
71
|
+
{product.title}
|
|
72
|
+
</li>
|
|
73
|
+
|
|
74
|
+
return ({ products }) => <For each={products} is="ul">{listItem}</For>
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
render(<ShoppingList producst={products} />, document.body)
|
|
54
78
|
```
|
|
79
|
+
|
|
80
|
+
## acknowledgments
|
|
81
|
+
ajo takes heavy inspiration from [Incremental DOM](https://github.com/google/incremental-dom) and [Crank.js](https://github.com/bikeshaving/crank)
|