ajo 0.1.34 → 0.1.35

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.js CHANGED
@@ -1,401 +1,363 @@
1
- import { Context, current } from './context.js'
2
- import { isVNode } from './jsx.js'
3
-
4
- const { isArray } = Array, { assign, hasOwn, keys } = Object
5
-
6
- const Key = Symbol.for('ajo.key')
7
- const Keyed = Symbol.for('ajo.keyed')
8
- const Memo = Symbol.for('ajo.memo')
9
- const Cache = Symbol.for('ajo.cache')
10
- const Generator = Symbol.for('ajo.generator')
11
- const Iterator = Symbol.for('ajo.iterator')
12
- const Render = Symbol.for('ajo.render')
13
- const Args = Symbol.for('ajo.args')
14
- const Controller = Symbol.for('ajo.controller')
15
-
16
- export const defaults = { tag: 'div' }
17
-
18
- export const stateful = (fn, is) => (is && (fn.is = is), fn)
19
-
20
- export const render = (h, el, child = el.firstChild, ref = null) => {
21
-
22
- walk(h, h => {
23
-
24
- const node = typeof h == 'string' ? text(h, child, ref) : element(h, el, child, ref)
25
-
26
- if (child == null) {
27
-
28
- before(el, node, ref)
29
-
30
- } else if (node == child) {
31
-
32
- child = node.nextSibling
33
-
34
- } else if (node == child.nextSibling) {
35
-
36
- if (child.contains(document.activeElement)) el.insertBefore(node, child)
37
-
38
- else el.insertBefore(child, ref)
39
-
40
- child = node.nextSibling
41
-
42
- } else {
43
-
44
- before(el, node, child)
45
- }
46
- })
47
-
48
- if (child && !ref && child == el.firstChild) {
49
-
50
- const gone = [...el.children]
51
-
52
- el[Keyed]?.clear()
53
-
54
- el.textContent = ''
55
-
56
- for (const node of gone) unref(node)
57
-
58
- } else while (child && child != ref) {
59
-
60
- const node = child.nextSibling
61
-
62
- el.removeChild(child)
63
-
64
- if (child.nodeType == 1) unref(child, el)
65
-
66
- child = node
67
- }
68
- }
69
-
70
- const walk = (h, fn) => {
71
-
72
- const type = typeof h
73
-
74
- if (h == null || type == 'boolean') return
75
-
76
- if (type == 'string') fn(h)
77
-
78
- else if (type == 'number' || type == 'bigint') fn(String(h))
79
-
80
- else if (isVNode(h)) typeof h.nodeName == 'function' ? run(h, fn) : fn(h)
81
-
82
- else if (Symbol.iterator in Object(h)) for (h of h) walk(h, fn)
83
-
84
- else fn(String(h))
85
- }
86
-
87
- const run = ({ nodeName, ...h }, fn) => {
88
-
89
- if (nodeName.constructor.name == 'GeneratorFunction') fn(runGenerator(nodeName, h))
90
-
91
- else walk(nodeName(h), fn)
92
- }
93
-
94
- const runGenerator = (fn, h) => {
95
-
96
- const attrs = { ...fn.attrs }, args = { ...fn.args }
97
-
98
- for (const key of keys(h)) {
99
-
100
- if (key.startsWith('attr:')) attrs[key.slice(5)] = h[key]
101
-
102
- else if (key == 'key' || key == 'skip' || key == 'memo' || key == 'ref' || key.startsWith('set:')) attrs[key] = h[key]
103
-
104
- else args[key] = h[key]
105
- }
106
-
107
- attrs.nodeName = fn.is ?? defaults.tag
108
-
109
- attrs[Generator] = fn
110
-
111
- attrs[Args] = args
112
-
113
- return attrs
114
- }
115
-
116
- const text = (h, node, ref) => {
117
-
118
- while (node && node != ref && node.nodeType != 3) node = node.nextSibling
119
-
120
- if (node == null || node == ref) node = document.createTextNode(h)
121
-
122
- else if (node.data != h) node.data = h
123
-
124
- return node
125
- }
126
-
127
- const element = (h, el, node, ref) => {
128
-
129
- const nodeName = h.nodeName, key = h.key, gen = h[Generator]
130
-
131
- if (node && key != null && ref == null) node = el[Keyed]?.get(key) ?? node
132
-
133
- while (node && node != ref) {
134
-
135
- const k = node[Key], g = node[Generator]
136
-
137
- if (node.localName == nodeName && (k == null || k == key) && (!g || g == gen)) break
138
-
139
- node = k != null ? null : node.nextElementSibling
140
- }
141
-
142
- if (node == null || node == ref) node = document.createElementNS(h.xmlns ?? el.namespaceURI, nodeName)
143
-
144
- if (key != null) (el[Keyed] ??= new Map()).set(node[Key] = key, node)
145
-
146
- if (!node[Cache] || h.memo == null || some(node[Memo], h.memo)) {
147
-
148
- attrs(node[Cache], h, node)
149
-
150
- if (!h.skip) {
151
-
152
- if (gen) next(gen, h[Args], node)
153
-
154
- else if (!node[Cache] && (typeof h.children == 'string' || typeof h.children == 'number')) node.textContent = h.children + ''
155
-
156
- else render(h.children, node)
157
- }
158
-
159
- node[Memo] = h.memo
160
-
161
- node[Cache] = h
162
- }
163
-
164
- return node
165
- }
166
-
167
- const special = key => key == 'nodeName' || key == 'children' || key == 'key' || key == 'skip' || key == 'memo'
168
-
169
- const attrs = (cache, h, node) => {
170
-
171
- if (!cache) for (let i = node.attributes.length; i--;) {
172
-
173
- const { name } = node.attributes[i]
174
-
175
- if (!hasOwn(h, name)) node.removeAttribute(name)
176
- }
177
-
178
- for (const key in h) if (hasOwn(h, key)) {
179
-
180
- const value = h[key]
181
-
182
- if (cache && cache[key] === value || special(key)) continue
183
-
184
- if (key == 'ref' && typeof value == 'function') value(node)
185
-
186
- else if (key.startsWith('set:')) node[key.slice(4)] = value
187
-
188
- else if (value == null || value === false) node.removeAttribute(key)
189
-
190
- else if (key == 'class' && typeof node.className == 'string') node.className = value === true ? '' : value
191
-
192
- else node.setAttribute(key, value === true ? '' : value)
193
- }
194
-
195
- if (cache) for (const key in cache) if (hasOwn(cache, key)) {
196
-
197
- if (hasOwn(h, key) || special(key)) continue
198
-
199
- if (key.startsWith('set:')) node[key.slice(4)] = undefined
200
-
201
- else node.removeAttribute(key)
202
- }
203
- }
204
-
205
- const some = (a, b) => {
206
-
207
- if (isArray(a) && isArray(b)) {
208
-
209
- if (a.length != b.length) return true
210
-
211
- for (let i = a.length; i--;) if (a[i] !== b[i]) return true
212
-
213
- return false
214
- }
215
-
216
- return a !== b
217
- }
218
-
219
- const each = (fn, node) => {
220
-
221
- let child = node.firstElementChild
222
-
223
- while (child)
224
-
225
- if (fn(child) && child.firstElementChild) child = child.firstElementChild
226
-
227
- else {
228
-
229
- while (child != node && !child.nextElementSibling) child = child.parentNode ?? node
230
-
231
- child = child != node && child.nextElementSibling
232
- }
233
- }
234
-
235
- const before = (el, node, child) => {
236
-
237
- if (node.isConnected && node.contains(document.activeElement)) {
238
-
239
- const ref = node.nextSibling
240
-
241
- while (child && child != node) {
242
-
243
- const next = child.nextSibling
244
-
245
- el.insertBefore(child, ref)
246
-
247
- child = next
248
- }
249
-
250
- } else el.insertBefore(node, child)
251
- }
252
-
253
- const unref = (root, parent) => {
254
-
255
- if (root[Memo] == unref) return
256
-
257
- root[Memo] = unref
258
-
259
- let node = root
260
-
261
- while (node.firstElementChild) node = node.firstElementChild
262
-
263
- while (true) {
264
-
265
- const { nextElementSibling, parentNode } = node
266
-
267
- if (node[Key] != null) (parentNode ?? parent)?.[Keyed]?.delete(node[Key])
268
-
269
- if (typeof node.return == 'function') node.return(false)
270
-
271
- if (typeof node[Cache]?.ref == 'function') node[Cache].ref(null)
272
-
273
- if (node == root) break
274
-
275
- node = nextElementSibling ?? parentNode ?? root
276
-
277
- if (nextElementSibling) while (node.firstElementChild) node = node.firstElementChild
278
- }
279
- }
280
-
281
- const next = (fn, args, el) => {
282
-
283
- if (!el[Generator]) {
284
-
285
- watch()
286
-
287
- assign(el, methods)[Context] = Object.create(current()?.[Context] ?? null)
288
-
289
- el[Generator] = fn
290
- }
291
-
292
- const prev = el[Args] ??= args
293
-
294
- for (const key of keys(prev)) if (!hasOwn(args, key)) delete prev[key]
295
-
296
- assign(prev, args)
297
-
298
- el[Render]()
299
- }
300
-
301
- let observer
302
-
303
- const watch = () => observer || (observer = new MutationObserver(records => {
304
-
305
- for (const record of records) for (const node of record.removedNodes) if (node.nodeType == 1 && !node.isConnected) unref(node, record.target)
306
-
307
- })).observe(document, { childList: true, subtree: true })
308
-
309
- const methods = {
310
-
311
- *[Symbol.iterator]() { while (true) yield this[Args] },
312
-
313
- [Render]() {
314
-
315
- const parent = current()
316
-
317
- current(this)
318
-
319
- try {
320
-
321
- if (!this[Iterator]) {
322
-
323
- this.signal = (this[Controller] = new AbortController()).signal
324
-
325
- this[Iterator] = this[Generator].call(this, this[Args])
326
- }
327
-
328
- const { value, done } = this[Iterator].next()
329
-
330
- render(value, this)
331
-
332
- if (done) this.return()
333
-
334
- } catch (e) {
335
-
336
- this.throw(e)
337
-
338
- } finally {
339
-
340
- current(parent)
341
- }
342
- },
343
-
344
- next(fn, result) {
345
-
346
- if (this[Iterator] === false || !this.isConnected) return result
347
-
348
- try {
349
-
350
- if (typeof fn == 'function') result = fn.call(this, this[Args])
351
-
352
- } catch (e) {
353
-
354
- return this.throw(e)
355
- }
356
-
357
- if (!current()?.contains(this)) this[Render]()
358
-
359
- return result
360
- },
361
-
362
- throw(value) {
363
-
364
- for (let el = this; el; el = el.parentNode) if (el[Iterator]?.throw) try {
365
-
366
- return render(el[Iterator].throw(value).value, el)
367
-
368
- } catch (e) {
369
-
370
- value = new Error(e?.message ?? e, { cause: value })
371
- }
372
-
373
- throw value
374
- },
375
-
376
- return(deep = true) {
377
-
378
- const iterator = this[Iterator]
379
-
380
- if (iterator === false) return
381
-
382
- this[Iterator] = false
383
-
384
- if (deep) each(el => typeof el.return == 'function' ? el.return() : true, this)
385
-
386
- try {
387
-
388
- iterator?.return()
389
-
390
- } catch (e) {
391
-
392
- this.throw(e)
393
-
394
- } finally {
395
-
396
- this[Iterator] = null
397
-
398
- this[Controller]?.abort()
399
- }
400
- }
401
- }
1
+ import { Context, current } from './context.js'
2
+ import { isVNode } from './jsx.js'
3
+
4
+ const { isArray } = Array, { assign, hasOwn, keys } = Object
5
+
6
+ const Key = Symbol.for('ajo.key')
7
+ const Keyed = Symbol.for('ajo.keyed')
8
+ const Memo = Symbol.for('ajo.memo')
9
+ const Cache = Symbol.for('ajo.cache')
10
+ const Generator = Symbol.for('ajo.generator')
11
+ const Iterator = Symbol.for('ajo.iterator')
12
+ const Render = Symbol.for('ajo.render')
13
+ const Args = Symbol.for('ajo.args')
14
+ const Controller = Symbol.for('ajo.controller')
15
+
16
+ export const defaults = { tag: 'div' }
17
+
18
+ export const stateful = (fn, is) => (is && (fn.is = is), fn)
19
+
20
+ export const render = (h, el, child = el.firstChild, ref = null) => {
21
+
22
+ walk(h, h => {
23
+
24
+ const node = typeof h == 'string' ? text(h, child, ref) : element(h, el, child, ref)
25
+
26
+ if (child == null) {
27
+
28
+ before(el, node, ref)
29
+
30
+ } else if (node == child) {
31
+
32
+ child = node.nextSibling
33
+
34
+ } else if (node == child.nextSibling) {
35
+
36
+ if (child.contains(document.activeElement)) el.insertBefore(node, child)
37
+
38
+ else el.insertBefore(child, ref)
39
+
40
+ child = node.nextSibling
41
+
42
+ } else {
43
+
44
+ before(el, node, child)
45
+ }
46
+ })
47
+
48
+ if (child && !ref && child == el.firstChild) {
49
+
50
+ const gone = [...el.children]
51
+
52
+ el[Keyed]?.clear()
53
+
54
+ el.textContent = ''
55
+
56
+ for (const node of gone) unref(node)
57
+
58
+ } else while (child && child != ref) {
59
+
60
+ const node = child.nextSibling
61
+
62
+ el.removeChild(child)
63
+
64
+ unref(child, el)
65
+
66
+ child = node
67
+ }
68
+ }
69
+
70
+ const walk = (h, fn) => {
71
+
72
+ if (h == null || typeof h == 'boolean') return
73
+
74
+ if (isVNode(h)) {
75
+
76
+ if (typeof h.nodeName != 'function') return fn(h)
77
+
78
+ const { nodeName, ...rest } = h
79
+
80
+ if (nodeName.prototype?.next) fn(runGenerator(nodeName, rest))
81
+
82
+ else walk(nodeName(rest), fn)
83
+
84
+ } else if (typeof h == 'object' && Symbol.iterator in h) for (h of h) walk(h, fn)
85
+
86
+ else fn(String(h))
87
+ }
88
+
89
+ const runGenerator = (fn, h) => {
90
+
91
+ const attrs = { ...fn.attrs }, args = { ...fn.args }
92
+
93
+ for (const key of keys(h)) {
94
+
95
+ if (key.startsWith('attr:')) attrs[key.slice(5)] = h[key]
96
+
97
+ else if (key == 'key' || key == 'skip' || key == 'memo' || key == 'ref' || key.startsWith('set:')) attrs[key] = h[key]
98
+
99
+ else args[key] = h[key]
100
+ }
101
+
102
+ attrs.nodeName = fn.is ?? defaults.tag
103
+
104
+ attrs[Generator] = fn
105
+
106
+ attrs[Args] = args
107
+
108
+ return attrs
109
+ }
110
+
111
+ const text = (h, node, ref) => {
112
+
113
+ while (node && node != ref && node.nodeType != 3) node = node.nextSibling
114
+
115
+ if (node == null || node == ref) node = document.createTextNode(h)
116
+
117
+ else if (node.data != h) node.data = h
118
+
119
+ return node
120
+ }
121
+
122
+ const element = (h, el, node, ref) => {
123
+
124
+ const nodeName = h.nodeName, key = h.key, gen = h[Generator]
125
+
126
+ if (node && key != null && ref == null) node = el[Keyed]?.get(key) ?? node
127
+
128
+ while (node && node != ref) {
129
+
130
+ const k = node[Key], g = node[Generator]
131
+
132
+ if (node.localName == nodeName && (k == null || k == key) && (!g || g == gen)) break
133
+
134
+ node = k != null ? null : node.nextElementSibling
135
+ }
136
+
137
+ if (node == null || node == ref) node = document.createElementNS(h.xmlns ?? el.namespaceURI, nodeName)
138
+
139
+ if (key != null) (el[Keyed] ??= new Map()).set(node[Key] = key, node)
140
+
141
+ if (!node[Cache] || h.memo == null || some(node[Memo], h.memo)) {
142
+
143
+ attrs(node[Cache], h, node)
144
+
145
+ if (!h.skip) {
146
+
147
+ if (gen) next(gen, h[Args], node)
148
+
149
+ else if (!node[Cache] && (typeof h.children == 'string' || typeof h.children == 'number')) node.textContent = h.children + ''
150
+
151
+ else render(h.children, node)
152
+ }
153
+
154
+ node[Memo] = h.memo
155
+
156
+ node[Cache] = h
157
+ }
158
+
159
+ return node
160
+ }
161
+
162
+ const special = key => key == 'nodeName' || key == 'children' || key == 'key' || key == 'skip' || key == 'memo'
163
+
164
+ const attrs = (cache, h, node) => {
165
+
166
+ for (const key of cache ? keys(cache) : node.getAttributeNames()) {
167
+
168
+ if (hasOwn(h, key) || special(key)) continue
169
+
170
+ if (key.startsWith('set:')) node[key.slice(4)] = undefined
171
+
172
+ else node.removeAttribute(key)
173
+ }
174
+
175
+ for (const key of keys(h)) {
176
+
177
+ const value = h[key]
178
+
179
+ if (cache && cache[key] === value || special(key)) continue
180
+
181
+ if (key == 'ref' && typeof value == 'function') value(node)
182
+
183
+ else if (key.startsWith('set:')) node[key.slice(4)] = value
184
+
185
+ else if (value == null || value === false) node.removeAttribute(key)
186
+
187
+ else if (key == 'class' && typeof node.className == 'string') node.className = value === true ? '' : value
188
+
189
+ else node.setAttribute(key, value === true ? '' : value)
190
+ }
191
+ }
192
+
193
+ const some = (a, b) =>
194
+
195
+ isArray(a) && isArray(b) ? a.length != b.length || a.some((v, i) => v !== b[i]) : a !== b
196
+
197
+ const each = (fn, node) => {
198
+
199
+ for (let child = node.firstElementChild; child; child = child.nextElementSibling) if (fn(child)) each(fn, child)
200
+ }
201
+
202
+ const before = (el, node, child) => {
203
+
204
+ if (node.isConnected && node.contains(document.activeElement)) {
205
+
206
+ const ref = node.nextSibling
207
+
208
+ while (child && child != node) {
209
+
210
+ const next = child.nextSibling
211
+
212
+ el.insertBefore(child, ref)
213
+
214
+ child = next
215
+ }
216
+
217
+ } else el.insertBefore(node, child)
218
+ }
219
+
220
+ const unref = (root, parent) => {
221
+
222
+ if (root[Memo] == unref) return
223
+
224
+ root[Memo] = unref
225
+
226
+ const clean = node => {
227
+
228
+ for (let child = node.firstElementChild, next; child; child = next) {
229
+
230
+ next = child.nextElementSibling
231
+
232
+ clean(child)
233
+ }
234
+
235
+ if (node[Key] != null) (node.parentNode ?? parent)?.[Keyed]?.delete(node[Key])
236
+
237
+ if (typeof node.return == 'function') node.return(false)
238
+
239
+ if (typeof node[Cache]?.ref == 'function') node[Cache].ref(null)
240
+ }
241
+
242
+ clean(root)
243
+ }
244
+
245
+ let observer
246
+
247
+ const next = (fn, args, el) => {
248
+
249
+ if (!el[Generator]) {
250
+
251
+ if (!observer) (observer = new MutationObserver(records => {
252
+
253
+ for (const record of records) for (const node of record.removedNodes) if (node.nodeType == 1 && !node.isConnected) unref(node, record.target)
254
+
255
+ })).observe(document, { childList: true, subtree: true })
256
+
257
+ assign(el, methods)[Context] = Object.create(current()?.[Context] ?? null)
258
+
259
+ el[Generator] = fn
260
+ }
261
+
262
+ const prev = el[Args] ??= args
263
+
264
+ for (const key of keys(prev)) if (!hasOwn(args, key)) delete prev[key]
265
+
266
+ assign(prev, args)
267
+
268
+ el[Render]()
269
+ }
270
+
271
+ const methods = {
272
+
273
+ *[Symbol.iterator]() { while (true) yield this[Args] },
274
+
275
+ [Render]() {
276
+
277
+ const parent = current()
278
+
279
+ current(this)
280
+
281
+ try {
282
+
283
+ if (!this[Iterator]) {
284
+
285
+ this.signal = (this[Controller] = new AbortController()).signal
286
+
287
+ this[Iterator] = this[Generator].call(this, this[Args])
288
+ }
289
+
290
+ const { value, done } = this[Iterator].next()
291
+
292
+ render(value, this)
293
+
294
+ if (done) this.return()
295
+
296
+ } catch (e) {
297
+
298
+ this.throw(e)
299
+
300
+ } finally {
301
+
302
+ current(parent)
303
+ }
304
+ },
305
+
306
+ next(fn, result) {
307
+
308
+ if (this[Iterator] === false || !this.isConnected) return result
309
+
310
+ try {
311
+
312
+ if (typeof fn == 'function') result = fn.call(this, this[Args])
313
+
314
+ } catch (e) {
315
+
316
+ return this.throw(e)
317
+ }
318
+
319
+ if (!current()?.contains(this)) this[Render]()
320
+
321
+ return result
322
+ },
323
+
324
+ throw(value) {
325
+
326
+ for (let el = this; el; el = el.parentNode) if (el[Iterator]?.throw) try {
327
+
328
+ return render(el[Iterator].throw(value).value, el)
329
+
330
+ } catch (e) {
331
+
332
+ value = new Error(e?.message ?? e, { cause: value })
333
+ }
334
+
335
+ throw value
336
+ },
337
+
338
+ return(deep = true) {
339
+
340
+ const iterator = this[Iterator]
341
+
342
+ if (iterator === false) return
343
+
344
+ this[Iterator] = false
345
+
346
+ if (deep) each(el => typeof el.return == 'function' ? el.return() : true, this)
347
+
348
+ try {
349
+
350
+ iterator?.return()
351
+
352
+ } catch (e) {
353
+
354
+ this.throw(e)
355
+
356
+ } finally {
357
+
358
+ this[Iterator] = null
359
+
360
+ this[Controller]?.abort()
361
+ }
362
+ }
363
+ }