ajo 0.1.32 → 0.1.33

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