ajo 0.1.31 → 0.1.32

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,286 +1,309 @@
1
- import { Context, current } from 'ajo/context'
2
-
3
- const Key = Symbol.for('ajo.key')
4
- const Memo = Symbol.for('ajo.memo')
5
- const Ref = Symbol.for('ajo.ref')
6
- const Cache = Symbol.for('ajo.cache')
7
- const Generator = Symbol.for('ajo.generator')
8
- const Iterator = Symbol.for('ajo.iterator')
9
- const Render = Symbol.for('ajo.render')
10
- const Args = Symbol.for('ajo.args')
11
- const Controller = Symbol.for('ajo.controller')
12
-
13
- export const Fragment = props => props.children
14
-
15
- export const h = (type, props, ...children) => {
16
-
17
- (props ??= {}).nodeName = type
18
-
19
- if (!('children' in props) && children.length) props.children = children.length == 1 ? children[0] : children
20
-
21
- return props
22
- }
23
-
24
- export const render = (h, el, child = el.firstChild, ref = null) => {
25
-
26
- for (h of walk(h)) {
27
-
28
- const node = reconcile(h, el, child)
29
-
30
- if (child == null) {
31
-
32
- before(el, node, ref)
33
-
34
- } else if (node == child) {
35
-
36
- child = node.nextSibling
37
-
38
- } else if (node == child.nextSibling) {
39
-
40
- before(el, child, ref)
41
-
42
- child = node.nextSibling
43
-
44
- } else {
45
-
46
- before(el, node, child)
47
- }
48
- }
49
-
50
- while (child != ref) {
51
-
52
- const node = child.nextSibling
53
-
54
- if (child.nodeType == 1) unref(child)
55
-
56
- el.removeChild(child)
57
-
58
- child = node
59
- }
60
- }
61
-
62
- const walk = function* (h) {
63
-
64
- if (h == null) return
65
-
66
- const type = typeof h
67
-
68
- if (type == 'boolean') return
69
-
70
- if (type == 'string') yield h
71
-
72
- else if (type == 'number' || type == 'bigint') yield String(h)
73
-
74
- else if (Symbol.iterator in h) for (h of h) yield* walk(h)
75
-
76
- else if ('nodeName' in h) typeof h.nodeName == 'function' ? yield* run(h) : yield h
77
-
78
- else yield String(h)
79
- }
80
-
81
- const run = function* ({ nodeName, ...h }) {
82
-
83
- if (nodeName.constructor.name == 'GeneratorFunction') yield runGenerator(nodeName, h)
84
-
85
- else yield* walk(nodeName(h))
86
- }
87
-
88
- const runGenerator = (fn, h) => {
89
-
90
- const attrs = { ...fn.attrs }, args = { ...fn.args }
91
-
92
- for (const key in h) {
93
-
94
- if (key.startsWith('attr:')) attrs[key.slice(5)] = h[key]
95
-
96
- else if (key == 'key' || key == 'skip' || key == 'memo' || key == 'ref' || key.startsWith('set:')) attrs[key] = h[key]
97
-
98
- else args[key] = h[key]
99
- }
100
-
101
- return { ...attrs, nodeName: fn.is ?? 'div', [Generator]: fn, [Args]: args }
102
- }
103
-
104
- const reconcile = (h, el, node) => typeof h == 'string' ? text(h, node) : element(h, el, node)
105
-
106
- const text = (h, node) => {
107
-
108
- while (node && node.nodeType != 3) node = node.nextSibling
109
-
110
- node ? node.data != h && (node.data = h) : node = document.createTextNode(h)
111
-
112
- return node
113
- }
114
-
115
- const element = ({ nodeName, children, key, skip, memo, ref, [Generator]: gen, [Args]: args, ...h }, el, node) => {
116
-
117
- while (node && (
118
-
119
- (node.localName != nodeName) ||
120
-
121
- (node[Key] != null && node[Key] != key) ||
122
-
123
- (node[Generator] && node[Generator] != gen)
124
-
125
- )) node = node.nextSibling
126
-
127
- node ??= document.createElementNS(h.xmlns ?? el.namespaceURI, nodeName)
128
-
129
- if (key != null) node[Key] = key
130
-
131
- if (memo == null || some(node[Memo], node[Memo] = memo)) {
132
-
133
- attrs(node[Cache] ?? extract(node), node[Cache] = h, node)
134
-
135
- if (!skip) gen ? next(gen, args, node) : render(children, node)
136
-
137
- if (typeof ref == 'function') (node[Ref] = ref)(node)
138
- }
139
-
140
- return node
141
- }
142
-
143
- const attrs = (cache, h, node) => {
144
-
145
- for (const key in { ...cache, ...h }) {
146
-
147
- if (cache[key] === h[key]) continue
148
-
149
- if (key.startsWith('set:')) node[key.slice(4)] = h[key]
150
-
151
- else if (h[key] == null || h[key] === false) node.removeAttribute(key)
152
-
153
- else node.setAttribute(key, h[key] === true ? '' : h[key])
154
- }
155
- }
156
-
157
- const some = (a, b) => Array.isArray(a) && Array.isArray(b) ? a.some((v, i) => v !== b[i]) : a !== b
158
-
159
- const extract = el => Array.from(el.attributes).reduce((out, attr) => (out[attr.name] = attr.value, out), {})
160
-
161
- const before = (el, node, child) => {
162
-
163
- if (node.contains(document.activeElement)) {
164
-
165
- const ref = node.nextSibling
166
-
167
- while (child && child != node) {
168
-
169
- const next = child.nextSibling
170
-
171
- el.insertBefore(child, ref)
172
-
173
- child = next
174
- }
175
-
176
- } else el.insertBefore(node, child)
177
- }
178
-
179
- const unref = node => {
180
-
181
- for (const child of node.children) unref(child)
182
-
183
- if (typeof node.return == 'function') node.return()
184
-
185
- node[Ref]?.(null)
186
- }
187
-
188
- const next = (fn, args, el) => {
189
-
190
- el[Generator] ??= (attach(el), fn)
191
-
192
- Object.assign(el[Args] ??= {}, args)
193
-
194
- el[Render]()
195
- }
196
-
197
- const attach = el => {
198
-
199
- Object.assign(el, methods)
200
-
201
- el[Context] = Object.create(current()?.[Context] ?? null)
202
- }
203
-
204
- const methods = {
205
-
206
- [Render]() {
207
-
208
- const parent = current()
209
-
210
- current(this)
211
-
212
- try {
213
-
214
- if (!this[Iterator]) {
215
-
216
- this.signal = (this[Controller] = new AbortController()).signal
217
-
218
- this[Iterator] = this[Generator].call(this, this[Args])
219
- }
220
-
221
- const { value, done } = this[Iterator].next()
222
-
223
- render(value, this)
224
-
225
- this[Ref]?.(this)
226
-
227
- if (done) this.return()
228
-
229
- } catch (e) {
230
-
231
- this.throw(e)
232
-
233
- } finally {
234
-
235
- current(parent)
236
- }
237
- },
238
-
239
- next(fn, result) {
240
-
241
- try {
242
-
243
- if (typeof fn == 'function') result = fn.call(this, this[Args])
244
-
245
- } catch (e) {
246
-
247
- return this.throw(e)
248
- }
249
-
250
- if (!current()?.contains(this)) this[Render]()
251
-
252
- return result
253
- },
254
-
255
- throw(value) {
256
-
257
- for (let el = this; el; el = el.parentNode) if (el[Iterator]?.throw) try {
258
-
259
- return render(el[Iterator].throw(value).value, el)
260
-
261
- } catch (e) {
262
-
263
- value = new Error(e?.message ?? e, { cause: value })
264
- }
265
-
266
- throw value
267
- },
268
-
269
- return() {
270
-
271
- try {
272
-
273
- this[Iterator]?.return()
274
-
275
- } catch (e) {
276
-
277
- this.throw(e)
278
-
279
- } finally {
280
-
281
- this[Iterator] = null
282
-
283
- this[Controller]?.abort()
284
- }
285
- }
286
- }
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
+ }
package/jsx.js ADDED
@@ -0,0 +1,21 @@
1
+ export const Fragment = props => props.children
2
+
3
+ export const h = (type, props, ...children) => {
4
+
5
+ (props ??= {}).nodeName = type
6
+
7
+ if (!('children' in props) && children.length) props.children = children.length == 1 ? children[0] : children
8
+
9
+ return props
10
+ }
11
+
12
+ export function jsx(type, props, key) {
13
+
14
+ if (key != null) (props ??= {}).key = key
15
+
16
+ return h(type, props)
17
+ }
18
+
19
+ export const jsxs = jsx
20
+
21
+ export const jsxDEV = jsx
package/license CHANGED
@@ -1,15 +1,15 @@
1
- ISC License
2
-
3
- Copyright (c) 2022-2026, Cristian Falcone
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.
1
+ ISC License
2
+
3
+ Copyright (c) 2022-2026, Cristian Falcone
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.