creo 0.0.3-dev → 0.1.0
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/README.md +5 -1
- package/dist/functional/assert.d.ts +1 -0
- package/dist/functional/key.d.ts +2 -0
- package/dist/functional/maybe.d.ts +6 -0
- package/dist/functional/maybe_promise.d.ts +1 -0
- package/dist/functional/shallow_equal.d.ts +2 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +1373 -0
- package/dist/index.js.map +26 -0
- package/dist/internal/engine.d.ts +18 -0
- package/dist/internal/internal_view.d.ts +38 -0
- package/dist/internal/orchestrator.d.ts +16 -0
- package/dist/internal/wildcard.d.ts +1 -0
- package/dist/public/app.d.ts +19 -0
- package/dist/public/event_handle.d.ts +32 -0
- package/dist/public/primitive.d.ts +20 -0
- package/dist/public/primitives/primitives.d.ts +318 -0
- package/dist/public/state.d.ts +37 -0
- package/dist/public/store.d.ts +35 -0
- package/dist/public/view.d.ts +37 -0
- package/dist/render/canvas_render.d.ts +1 -0
- package/dist/render/html_render.d.ts +35 -0
- package/dist/render/json_render.d.ts +17 -0
- package/dist/render/render_interface.d.ts +7 -0
- package/dist/render/stream_render.d.ts +1 -0
- package/dist/render/string_render.d.ts +17 -0
- package/dist/structures/indexed_list.d.ts +46 -0
- package/dist/structures/list.d.ts +68 -0
- package/package.json +24 -7
- package/bun.lockb +0 -0
- package/index.html +0 -13
- package/src/main.ts +0 -13
- package/src/record/record.spec.ts +0 -146
- package/src/record/record.ts +0 -101
- package/src/style.css +0 -96
- package/src/tools/isRecordLike.spec.ts +0 -29
- package/src/tools/isRecordLike.ts +0 -3
- package/src/tools/optional.ts +0 -25
- package/src/ui/component.ts +0 -1
- package/src/ui/index.ts +0 -0
- package/src/ui/prop.ts +0 -13
- package/src/ui/state.ts +0 -0
- package/src/vite-env.d.ts +0 -1
- package/tsconfig.json +0 -23
package/dist/index.js
ADDED
|
@@ -0,0 +1,1373 @@
|
|
|
1
|
+
// src/structures/list.ts
|
|
2
|
+
var $next = Symbol("next");
|
|
3
|
+
var $prev = Symbol("prev");
|
|
4
|
+
var $owner = Symbol("owner");
|
|
5
|
+
|
|
6
|
+
class ListNode {
|
|
7
|
+
[$owner];
|
|
8
|
+
[$next];
|
|
9
|
+
[$prev];
|
|
10
|
+
v;
|
|
11
|
+
constructor(node, prev = null, next = null, list) {
|
|
12
|
+
this[$prev] = prev;
|
|
13
|
+
this[$next] = next;
|
|
14
|
+
this[$owner] = list;
|
|
15
|
+
this.v = node;
|
|
16
|
+
}
|
|
17
|
+
isFirst() {
|
|
18
|
+
return this[$prev] == null;
|
|
19
|
+
}
|
|
20
|
+
isLast() {
|
|
21
|
+
return this[$next] == null;
|
|
22
|
+
}
|
|
23
|
+
delete() {
|
|
24
|
+
this[$owner]?.delete(this);
|
|
25
|
+
}
|
|
26
|
+
clearFields() {
|
|
27
|
+
this[$next] = null;
|
|
28
|
+
this[$prev] = null;
|
|
29
|
+
this[$owner] = null;
|
|
30
|
+
}
|
|
31
|
+
insertNext(value) {
|
|
32
|
+
const owner = this[$owner];
|
|
33
|
+
if (!owner) {
|
|
34
|
+
throw new Error("The item is detached from DataContainer");
|
|
35
|
+
}
|
|
36
|
+
return owner.insertNext(this, value);
|
|
37
|
+
}
|
|
38
|
+
insertPrev(value) {
|
|
39
|
+
const owner = this[$owner];
|
|
40
|
+
if (!owner) {
|
|
41
|
+
throw new Error("The item is detached from DataContainer");
|
|
42
|
+
}
|
|
43
|
+
return owner.insertPrev(this, value);
|
|
44
|
+
}
|
|
45
|
+
getNext() {
|
|
46
|
+
return this[$next];
|
|
47
|
+
}
|
|
48
|
+
getPrev() {
|
|
49
|
+
return this[$prev];
|
|
50
|
+
}
|
|
51
|
+
getList() {
|
|
52
|
+
return this[$owner];
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
class InternalList {
|
|
57
|
+
#head;
|
|
58
|
+
#tail;
|
|
59
|
+
#size = 0;
|
|
60
|
+
#cursorNode;
|
|
61
|
+
#cursorIndex = -1;
|
|
62
|
+
#invalidateCursor() {
|
|
63
|
+
this.#cursorNode = null;
|
|
64
|
+
this.#cursorIndex = -1;
|
|
65
|
+
}
|
|
66
|
+
insertStart(value) {
|
|
67
|
+
const node = new ListNode(value, null, this.#head, this);
|
|
68
|
+
if (this.#head != null) {
|
|
69
|
+
this.#head[$prev] = node;
|
|
70
|
+
} else {
|
|
71
|
+
this.#tail = node;
|
|
72
|
+
}
|
|
73
|
+
this.#head = node;
|
|
74
|
+
this.#size++;
|
|
75
|
+
this.#invalidateCursor();
|
|
76
|
+
return this.#head;
|
|
77
|
+
}
|
|
78
|
+
delete(node) {
|
|
79
|
+
const n = node;
|
|
80
|
+
const prev = n[$prev];
|
|
81
|
+
const next = n[$next];
|
|
82
|
+
if (next) {
|
|
83
|
+
next[$prev] = prev;
|
|
84
|
+
}
|
|
85
|
+
if (prev) {
|
|
86
|
+
prev[$next] = next;
|
|
87
|
+
}
|
|
88
|
+
if (node === this.#head) {
|
|
89
|
+
this.#head = next;
|
|
90
|
+
}
|
|
91
|
+
if (node === this.#tail) {
|
|
92
|
+
this.#tail = prev;
|
|
93
|
+
}
|
|
94
|
+
n.clearFields();
|
|
95
|
+
this.#size--;
|
|
96
|
+
this.#invalidateCursor();
|
|
97
|
+
}
|
|
98
|
+
at(n) {
|
|
99
|
+
if (n < 0)
|
|
100
|
+
n = this.#size + n;
|
|
101
|
+
if (n < 0 || n >= this.#size)
|
|
102
|
+
return;
|
|
103
|
+
let current;
|
|
104
|
+
let pos;
|
|
105
|
+
const distFromHead = n;
|
|
106
|
+
const distFromTail = this.#size - 1 - n;
|
|
107
|
+
const distFromCursor = this.#cursorNode != null ? Math.abs(n - this.#cursorIndex) : Infinity;
|
|
108
|
+
if (distFromCursor <= distFromHead && distFromCursor <= distFromTail) {
|
|
109
|
+
current = this.#cursorNode;
|
|
110
|
+
pos = this.#cursorIndex;
|
|
111
|
+
} else if (distFromHead <= distFromTail) {
|
|
112
|
+
current = this.#head;
|
|
113
|
+
pos = 0;
|
|
114
|
+
} else {
|
|
115
|
+
current = this.#tail;
|
|
116
|
+
pos = this.#size - 1;
|
|
117
|
+
}
|
|
118
|
+
while (pos < n && current != null) {
|
|
119
|
+
current = current[$next];
|
|
120
|
+
pos++;
|
|
121
|
+
}
|
|
122
|
+
while (pos > n && current != null) {
|
|
123
|
+
current = current[$prev];
|
|
124
|
+
pos--;
|
|
125
|
+
}
|
|
126
|
+
if (current != null) {
|
|
127
|
+
this.#cursorNode = current;
|
|
128
|
+
this.#cursorIndex = pos;
|
|
129
|
+
}
|
|
130
|
+
return current;
|
|
131
|
+
}
|
|
132
|
+
get size() {
|
|
133
|
+
return this.#size;
|
|
134
|
+
}
|
|
135
|
+
clear() {
|
|
136
|
+
this.#head = null;
|
|
137
|
+
this.#tail = null;
|
|
138
|
+
this.#size = 0;
|
|
139
|
+
this.#invalidateCursor();
|
|
140
|
+
}
|
|
141
|
+
first() {
|
|
142
|
+
return this.#head;
|
|
143
|
+
}
|
|
144
|
+
last() {
|
|
145
|
+
return this.#tail;
|
|
146
|
+
}
|
|
147
|
+
insertEnd(value) {
|
|
148
|
+
const node = new ListNode(value, this.#tail, null, this);
|
|
149
|
+
if (this.#tail != null) {
|
|
150
|
+
this.#tail[$next] = node;
|
|
151
|
+
} else {
|
|
152
|
+
this.#head = node;
|
|
153
|
+
}
|
|
154
|
+
this.#tail = node;
|
|
155
|
+
this.#size++;
|
|
156
|
+
return this.#tail;
|
|
157
|
+
}
|
|
158
|
+
insertNext(ref, value) {
|
|
159
|
+
const r = ref;
|
|
160
|
+
if (r[$owner] != this) {
|
|
161
|
+
throw new TypeError("The reference node does not belong to the current list");
|
|
162
|
+
}
|
|
163
|
+
const node = new ListNode(value, r, r[$next], this);
|
|
164
|
+
if (r[$next]) {
|
|
165
|
+
r[$next][$prev] = node;
|
|
166
|
+
} else {
|
|
167
|
+
this.#tail = node;
|
|
168
|
+
}
|
|
169
|
+
r[$next] = node;
|
|
170
|
+
this.#size++;
|
|
171
|
+
this.#invalidateCursor();
|
|
172
|
+
return node;
|
|
173
|
+
}
|
|
174
|
+
insertPrev(ref, value) {
|
|
175
|
+
const r = ref;
|
|
176
|
+
if (r[$owner] != this) {
|
|
177
|
+
throw new TypeError("The reference node does not belong to the current list");
|
|
178
|
+
}
|
|
179
|
+
const node = new ListNode(value, r[$prev], r, this);
|
|
180
|
+
if (r[$prev]) {
|
|
181
|
+
r[$prev][$next] = node;
|
|
182
|
+
} else {
|
|
183
|
+
this.#head = node;
|
|
184
|
+
}
|
|
185
|
+
r[$prev] = node;
|
|
186
|
+
this.#size++;
|
|
187
|
+
this.#invalidateCursor();
|
|
188
|
+
return node;
|
|
189
|
+
}
|
|
190
|
+
*[Symbol.iterator]() {
|
|
191
|
+
let current = this.#head;
|
|
192
|
+
while (current) {
|
|
193
|
+
const next = current[$next];
|
|
194
|
+
yield current;
|
|
195
|
+
current = next;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// src/structures/indexed_list.ts
|
|
201
|
+
class IndexedList {
|
|
202
|
+
#list = new InternalList;
|
|
203
|
+
#map = new Map;
|
|
204
|
+
push(item) {
|
|
205
|
+
const existing = this.#map.get(item);
|
|
206
|
+
if (existing)
|
|
207
|
+
return existing;
|
|
208
|
+
const node = this.#list.insertEnd(item);
|
|
209
|
+
this.#map.set(item, node);
|
|
210
|
+
return node;
|
|
211
|
+
}
|
|
212
|
+
unshift(item) {
|
|
213
|
+
if (this.#map.has(item))
|
|
214
|
+
return;
|
|
215
|
+
const node = this.#list.insertStart(item);
|
|
216
|
+
this.#map.set(item, node);
|
|
217
|
+
}
|
|
218
|
+
insertAfter(ref, item) {
|
|
219
|
+
if (this.#map.has(item))
|
|
220
|
+
return;
|
|
221
|
+
const refNode = this.#map.get(ref);
|
|
222
|
+
if (!refNode) {
|
|
223
|
+
this.push(item);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const node = refNode.insertNext(item);
|
|
227
|
+
this.#map.set(item, node);
|
|
228
|
+
}
|
|
229
|
+
delete(item) {
|
|
230
|
+
const node = this.#map.get(item);
|
|
231
|
+
if (!node)
|
|
232
|
+
return;
|
|
233
|
+
this.#map.delete(item);
|
|
234
|
+
node.delete();
|
|
235
|
+
}
|
|
236
|
+
has(item) {
|
|
237
|
+
return this.#map.has(item);
|
|
238
|
+
}
|
|
239
|
+
get length() {
|
|
240
|
+
return this.#map.size;
|
|
241
|
+
}
|
|
242
|
+
first() {
|
|
243
|
+
return this.#list.first()?.v;
|
|
244
|
+
}
|
|
245
|
+
last() {
|
|
246
|
+
return this.#list.last()?.v;
|
|
247
|
+
}
|
|
248
|
+
getNode(item) {
|
|
249
|
+
return this.#map.get(item);
|
|
250
|
+
}
|
|
251
|
+
at(index) {
|
|
252
|
+
return this.#list.at(index)?.v;
|
|
253
|
+
}
|
|
254
|
+
upsert(pos, item) {
|
|
255
|
+
const existing = this.#list.at(pos);
|
|
256
|
+
if (!existing) {
|
|
257
|
+
return this.push(item);
|
|
258
|
+
}
|
|
259
|
+
this.#map.delete(existing.v);
|
|
260
|
+
existing.v = item;
|
|
261
|
+
this.#map.set(item, existing);
|
|
262
|
+
return existing;
|
|
263
|
+
}
|
|
264
|
+
swap(a, b) {
|
|
265
|
+
const nodeA = this.#map.get(a);
|
|
266
|
+
const nodeB = this.#map.get(b);
|
|
267
|
+
if (!nodeA || !nodeB)
|
|
268
|
+
return;
|
|
269
|
+
nodeA.v = b;
|
|
270
|
+
nodeB.v = a;
|
|
271
|
+
this.#map.set(a, nodeB);
|
|
272
|
+
this.#map.set(b, nodeA);
|
|
273
|
+
}
|
|
274
|
+
clear() {
|
|
275
|
+
this.#list.clear();
|
|
276
|
+
this.#map.clear();
|
|
277
|
+
}
|
|
278
|
+
*[Symbol.iterator]() {
|
|
279
|
+
for (const node of this.#list) {
|
|
280
|
+
yield node.v;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// src/internal/engine.ts
|
|
286
|
+
class Engine {
|
|
287
|
+
renderer;
|
|
288
|
+
dirty = new IndexedList;
|
|
289
|
+
#scheduler;
|
|
290
|
+
#renderScheduled = false;
|
|
291
|
+
#collector;
|
|
292
|
+
constructor(renderer, scheduler) {
|
|
293
|
+
this.renderer = renderer;
|
|
294
|
+
this.#scheduler = scheduler ?? "scheduler" in globalThis ? (cb) => window.scheduler.postTask(cb) : (cb) => queueMicrotask(cb);
|
|
295
|
+
}
|
|
296
|
+
disposeView(view) {
|
|
297
|
+
this.dirty.delete(view);
|
|
298
|
+
}
|
|
299
|
+
schedule() {
|
|
300
|
+
if (this.#renderScheduled) {
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
this.#renderScheduled = true;
|
|
304
|
+
this.#scheduler(() => {
|
|
305
|
+
this.#renderScheduled = false;
|
|
306
|
+
this.render();
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
markDirty(view) {
|
|
310
|
+
this.dirty.push(view);
|
|
311
|
+
this.schedule();
|
|
312
|
+
}
|
|
313
|
+
pendingView(view) {
|
|
314
|
+
this.#collector?.(view);
|
|
315
|
+
}
|
|
316
|
+
collect(slot) {
|
|
317
|
+
const list = [];
|
|
318
|
+
const prev = this.#collector;
|
|
319
|
+
this.#collector = list.push.bind(list);
|
|
320
|
+
slot();
|
|
321
|
+
this.#collector = prev;
|
|
322
|
+
return list;
|
|
323
|
+
}
|
|
324
|
+
#rendering = false;
|
|
325
|
+
render() {
|
|
326
|
+
if (this.#rendering)
|
|
327
|
+
return;
|
|
328
|
+
this.#rendering = true;
|
|
329
|
+
try {
|
|
330
|
+
const cbs = [];
|
|
331
|
+
while (this.dirty.length > 0) {
|
|
332
|
+
const view = this.dirty.first();
|
|
333
|
+
const isNew = view.renderRef == null;
|
|
334
|
+
if (!isNew)
|
|
335
|
+
view.onUpdateBefore();
|
|
336
|
+
this.renderer.render(view);
|
|
337
|
+
if (view.dirty) {
|
|
338
|
+
view.reconsile();
|
|
339
|
+
cbs.push(isNew ? view.onMount : view.onUpdateAfter);
|
|
340
|
+
view.dirty = false;
|
|
341
|
+
}
|
|
342
|
+
this.dirty.delete(view);
|
|
343
|
+
}
|
|
344
|
+
for (const cb of cbs) {
|
|
345
|
+
cb();
|
|
346
|
+
}
|
|
347
|
+
} finally {
|
|
348
|
+
this.#rendering = false;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// src/public/state.ts
|
|
354
|
+
class State {
|
|
355
|
+
#current;
|
|
356
|
+
#schedule;
|
|
357
|
+
constructor(initial, schedule) {
|
|
358
|
+
this.#current = initial;
|
|
359
|
+
this.#schedule = schedule;
|
|
360
|
+
}
|
|
361
|
+
get() {
|
|
362
|
+
return this.#current;
|
|
363
|
+
}
|
|
364
|
+
set(value) {
|
|
365
|
+
this.#current = value;
|
|
366
|
+
this.#schedule();
|
|
367
|
+
}
|
|
368
|
+
update(fn) {
|
|
369
|
+
const result = fn(this.#current);
|
|
370
|
+
if (result instanceof Promise) {
|
|
371
|
+
result.then((value) => {
|
|
372
|
+
this.#current = value;
|
|
373
|
+
this.#schedule();
|
|
374
|
+
});
|
|
375
|
+
} else {
|
|
376
|
+
this.#current = result;
|
|
377
|
+
this.#schedule();
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// src/public/store.ts
|
|
383
|
+
var $store = Symbol("store");
|
|
384
|
+
|
|
385
|
+
class Store {
|
|
386
|
+
[$store] = true;
|
|
387
|
+
#current;
|
|
388
|
+
#subscribers = new Set;
|
|
389
|
+
constructor(initial) {
|
|
390
|
+
this.#current = initial;
|
|
391
|
+
}
|
|
392
|
+
get() {
|
|
393
|
+
return this.#current;
|
|
394
|
+
}
|
|
395
|
+
set(value) {
|
|
396
|
+
this.#current = value;
|
|
397
|
+
this.#notify();
|
|
398
|
+
}
|
|
399
|
+
update(fn) {
|
|
400
|
+
const result = fn(this.#current);
|
|
401
|
+
if (result instanceof Promise) {
|
|
402
|
+
result.then((value) => {
|
|
403
|
+
this.#current = value;
|
|
404
|
+
this.#notify();
|
|
405
|
+
});
|
|
406
|
+
} else {
|
|
407
|
+
this.#current = result;
|
|
408
|
+
this.#notify();
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
subscribe(cb) {
|
|
412
|
+
this.#subscribers.add(cb);
|
|
413
|
+
return () => {
|
|
414
|
+
this.#subscribers.delete(cb);
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
#notify() {
|
|
418
|
+
for (const sub of this.#subscribers) {
|
|
419
|
+
sub();
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
function isStore(value) {
|
|
424
|
+
return value != null && typeof value === "object" && $store in value;
|
|
425
|
+
}
|
|
426
|
+
var store = {
|
|
427
|
+
new(initial) {
|
|
428
|
+
return new Store(initial);
|
|
429
|
+
}
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
// src/functional/shallow_equal.ts
|
|
433
|
+
function shallowEqual(a, b) {
|
|
434
|
+
if (a === b)
|
|
435
|
+
return true;
|
|
436
|
+
if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) {
|
|
437
|
+
return false;
|
|
438
|
+
}
|
|
439
|
+
const keysA = Object.keys(a);
|
|
440
|
+
if (keysA.length !== Object.keys(b).length)
|
|
441
|
+
return false;
|
|
442
|
+
for (let i = 0;i < keysA.length; i++) {
|
|
443
|
+
const key = keysA[i];
|
|
444
|
+
if (!Object.is(a[key], b[key])) {
|
|
445
|
+
return false;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
return true;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// src/internal/internal_view.ts
|
|
452
|
+
class View {
|
|
453
|
+
viewFn;
|
|
454
|
+
engine;
|
|
455
|
+
parent;
|
|
456
|
+
userKey;
|
|
457
|
+
renderRef;
|
|
458
|
+
props;
|
|
459
|
+
slotChildren;
|
|
460
|
+
body;
|
|
461
|
+
virtualDom;
|
|
462
|
+
keyToIndex;
|
|
463
|
+
dirty = true;
|
|
464
|
+
moved = false;
|
|
465
|
+
quickRerender = true;
|
|
466
|
+
#unsubscribe = [];
|
|
467
|
+
constructor(viewFn, initialProps, slot, engine, parent, userKey) {
|
|
468
|
+
this.viewFn = viewFn;
|
|
469
|
+
this.engine = engine;
|
|
470
|
+
this.parent = parent;
|
|
471
|
+
this.userKey = userKey;
|
|
472
|
+
this.props = initialProps;
|
|
473
|
+
this.body = viewFn({
|
|
474
|
+
props: () => this.props,
|
|
475
|
+
use: (storeOrInitial) => {
|
|
476
|
+
if (!isStore(storeOrInitial)) {
|
|
477
|
+
return new State(storeOrInitial, this.markDirty);
|
|
478
|
+
}
|
|
479
|
+
const s = storeOrInitial;
|
|
480
|
+
this.#unsubscribe.push(this.markDirty);
|
|
481
|
+
return s;
|
|
482
|
+
},
|
|
483
|
+
slot: () => {
|
|
484
|
+
if (!this.slotChildren) {
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
for (const child of this.slotChildren) {
|
|
488
|
+
this.engine.pendingView(child);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
});
|
|
492
|
+
this.slotChildren = slot && this.engine.collect(slot);
|
|
493
|
+
this.markDirty();
|
|
494
|
+
}
|
|
495
|
+
markDirty = () => {
|
|
496
|
+
this.dirty = true;
|
|
497
|
+
this.engine.markDirty(this);
|
|
498
|
+
};
|
|
499
|
+
markMove() {
|
|
500
|
+
this.moved = true;
|
|
501
|
+
this.engine.markDirty(this);
|
|
502
|
+
}
|
|
503
|
+
shouldUpdate(nextProps) {
|
|
504
|
+
if (this.body.shouldUpdate) {
|
|
505
|
+
return this.body.shouldUpdate(nextProps);
|
|
506
|
+
}
|
|
507
|
+
return !shallowEqual(this.props, nextProps);
|
|
508
|
+
}
|
|
509
|
+
onMount = () => {
|
|
510
|
+
this.quickRerender = false;
|
|
511
|
+
this.body.onMount?.();
|
|
512
|
+
};
|
|
513
|
+
onUpdateBefore() {
|
|
514
|
+
this.body.onUpdateBefore?.();
|
|
515
|
+
}
|
|
516
|
+
onUpdateAfter = () => {
|
|
517
|
+
this.quickRerender = false;
|
|
518
|
+
this.body.onUpdateBefore?.();
|
|
519
|
+
};
|
|
520
|
+
nextProps(nextProps, nextSlot) {
|
|
521
|
+
const prevChildren = this.slotChildren;
|
|
522
|
+
this.slotChildren = nextSlot && this.engine.collect(nextSlot);
|
|
523
|
+
if (this.shouldUpdate(nextProps) || hasNewChildren(prevChildren, this.slotChildren)) {
|
|
524
|
+
this.markDirty();
|
|
525
|
+
this.props = nextProps;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
reconsile() {
|
|
529
|
+
const children = this.engine.collect(this.body.render);
|
|
530
|
+
if (!this.virtualDom && children.length === 0)
|
|
531
|
+
return;
|
|
532
|
+
if (!this.virtualDom)
|
|
533
|
+
this.virtualDom = new IndexedList;
|
|
534
|
+
this.quickRerender = true;
|
|
535
|
+
const vdom = this.virtualDom;
|
|
536
|
+
for (let i = 0;i < children.length; i++) {
|
|
537
|
+
const pending = children[i];
|
|
538
|
+
const expectedNext = vdom.at(i);
|
|
539
|
+
if (pending.userKey == null) {
|
|
540
|
+
if (expectedNext?.viewFn === pending.viewFn) {
|
|
541
|
+
this.quickRerender = false;
|
|
542
|
+
expectedNext.nextProps(pending.props, pending.slot);
|
|
543
|
+
} else {
|
|
544
|
+
if (expectedNext) {
|
|
545
|
+
if (expectedNext.userKey)
|
|
546
|
+
this.keyToIndex?.delete(expectedNext.userKey);
|
|
547
|
+
expectedNext[Symbol.dispose]();
|
|
548
|
+
}
|
|
549
|
+
vdom.upsert(i, new View(pending.viewFn, pending.props, pending.slot, this.engine, this, null));
|
|
550
|
+
}
|
|
551
|
+
} else {
|
|
552
|
+
const matchedIndex = this.keyToIndex?.get(pending.userKey);
|
|
553
|
+
const matched = matchedIndex != null ? vdom.at(matchedIndex) : null;
|
|
554
|
+
if (matched && matched.viewFn === pending.viewFn) {
|
|
555
|
+
this.quickRerender = false;
|
|
556
|
+
matched.nextProps(pending.props, pending.slot);
|
|
557
|
+
if (expectedNext != null) {
|
|
558
|
+
if (matched !== expectedNext) {
|
|
559
|
+
matched.markMove();
|
|
560
|
+
expectedNext.markMove();
|
|
561
|
+
vdom.swap(matched, expectedNext);
|
|
562
|
+
if (this.keyToIndex) {
|
|
563
|
+
if (matched.userKey != null)
|
|
564
|
+
this.keyToIndex.set(matched.userKey, i);
|
|
565
|
+
if (expectedNext.userKey != null)
|
|
566
|
+
this.keyToIndex.set(expectedNext.userKey, matchedIndex);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
} else {
|
|
570
|
+
matched.markMove();
|
|
571
|
+
vdom.upsert(i, matched);
|
|
572
|
+
if (this.keyToIndex && matched.userKey != null) {
|
|
573
|
+
this.keyToIndex.set(matched.userKey, i);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
} else {
|
|
577
|
+
if (expectedNext) {
|
|
578
|
+
if (expectedNext.userKey)
|
|
579
|
+
this.keyToIndex?.delete(expectedNext.userKey);
|
|
580
|
+
expectedNext[Symbol.dispose]();
|
|
581
|
+
}
|
|
582
|
+
vdom.upsert(i, new View(pending.viewFn, pending.props, pending.slot, this.engine, this, pending.userKey));
|
|
583
|
+
if (!this.keyToIndex)
|
|
584
|
+
this.keyToIndex = new Map;
|
|
585
|
+
this.keyToIndex.set(pending.userKey, i);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
if (children.length < vdom.length) {
|
|
590
|
+
for (let i = vdom.length;i >= children.length; i--) {
|
|
591
|
+
const removed = vdom.at(i);
|
|
592
|
+
if (removed) {
|
|
593
|
+
if (removed.userKey)
|
|
594
|
+
this.keyToIndex?.delete(removed.userKey);
|
|
595
|
+
removed[Symbol.dispose]();
|
|
596
|
+
vdom.delete(removed);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
[Symbol.dispose]() {
|
|
602
|
+
if (this.virtualDom) {
|
|
603
|
+
for (const child of this.virtualDom) {
|
|
604
|
+
child[Symbol.dispose]();
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
this.engine.renderer.unmount(this);
|
|
608
|
+
this.engine.disposeView(this);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
function hasNewChildren(prev, next) {
|
|
612
|
+
const prevLen = prev?.length ?? 0;
|
|
613
|
+
const nextLen = next?.length ?? 0;
|
|
614
|
+
if (prevLen === 0 && nextLen === 0)
|
|
615
|
+
return false;
|
|
616
|
+
if (!prev || !next)
|
|
617
|
+
return true;
|
|
618
|
+
if (prev.length !== next.length)
|
|
619
|
+
return true;
|
|
620
|
+
for (let i = 0;i < next.length; i++) {
|
|
621
|
+
if (next[i].viewFn !== prev[i].viewFn)
|
|
622
|
+
return true;
|
|
623
|
+
if (next[i].userKey !== prev[i].userKey)
|
|
624
|
+
return true;
|
|
625
|
+
if (next[i].props !== prev[i].props)
|
|
626
|
+
return true;
|
|
627
|
+
}
|
|
628
|
+
return false;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// src/internal/orchestrator.ts
|
|
632
|
+
class Orchestrator {
|
|
633
|
+
#currentEngine;
|
|
634
|
+
setCurrentEngine(engine) {
|
|
635
|
+
this.#currentEngine = engine;
|
|
636
|
+
}
|
|
637
|
+
currentEngine() {
|
|
638
|
+
return this.#currentEngine;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
var orchestrator = new Orchestrator;
|
|
642
|
+
|
|
643
|
+
// src/public/app.ts
|
|
644
|
+
function createApp(slot, renderer, options) {
|
|
645
|
+
return {
|
|
646
|
+
mount(props) {
|
|
647
|
+
const engine = new Engine(renderer, options?.scheduler);
|
|
648
|
+
orchestrator.setCurrentEngine(engine);
|
|
649
|
+
new View(() => ({ render() {
|
|
650
|
+
slot();
|
|
651
|
+
} }), props ?? {}, null, engine, null, null);
|
|
652
|
+
engine.render();
|
|
653
|
+
return { engine };
|
|
654
|
+
}
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
// src/public/view.ts
|
|
658
|
+
function view(body) {
|
|
659
|
+
return (props, slot) => {
|
|
660
|
+
orchestrator.currentEngine().pendingView({
|
|
661
|
+
viewFn: body,
|
|
662
|
+
props,
|
|
663
|
+
slot,
|
|
664
|
+
userKey: maybeGetUserKey(props)
|
|
665
|
+
});
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
function maybeGetUserKey(params) {
|
|
669
|
+
if (params != null && typeof params === "object" && "key" in params && params.key != null && (typeof params.key === "string" || typeof params.key === "number")) {
|
|
670
|
+
return params.key;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
// src/public/primitive.ts
|
|
674
|
+
var $primitive = Symbol("primitive");
|
|
675
|
+
// src/public/primitives/primitives.ts
|
|
676
|
+
function html(tag) {
|
|
677
|
+
const fn = ({
|
|
678
|
+
slot
|
|
679
|
+
}) => ({
|
|
680
|
+
render() {
|
|
681
|
+
slot();
|
|
682
|
+
}
|
|
683
|
+
});
|
|
684
|
+
fn[$primitive] = tag;
|
|
685
|
+
return view(fn);
|
|
686
|
+
}
|
|
687
|
+
var text = html("text");
|
|
688
|
+
var div = html("div");
|
|
689
|
+
var span = html("span");
|
|
690
|
+
var section = html("section");
|
|
691
|
+
var article = html("article");
|
|
692
|
+
var aside = html("aside");
|
|
693
|
+
var nav = html("nav");
|
|
694
|
+
var header = html("header");
|
|
695
|
+
var footer = html("footer");
|
|
696
|
+
var main = html("main");
|
|
697
|
+
var p = html("p");
|
|
698
|
+
var h1 = html("h1");
|
|
699
|
+
var h2 = html("h2");
|
|
700
|
+
var h3 = html("h3");
|
|
701
|
+
var h4 = html("h4");
|
|
702
|
+
var h5 = html("h5");
|
|
703
|
+
var h6 = html("h6");
|
|
704
|
+
var pre = html("pre");
|
|
705
|
+
var code = html("code");
|
|
706
|
+
var em = html("em");
|
|
707
|
+
var strong = html("strong");
|
|
708
|
+
var small = html("small");
|
|
709
|
+
var br = html("br");
|
|
710
|
+
var hr = html("hr");
|
|
711
|
+
var a = html("a");
|
|
712
|
+
var blockquote = html("blockquote");
|
|
713
|
+
var label = html("label");
|
|
714
|
+
var ul = html("ul");
|
|
715
|
+
var ol = html("ol");
|
|
716
|
+
var li = html("li");
|
|
717
|
+
var table = html("table");
|
|
718
|
+
var thead = html("thead");
|
|
719
|
+
var tbody = html("tbody");
|
|
720
|
+
var tfoot = html("tfoot");
|
|
721
|
+
var tr = html("tr");
|
|
722
|
+
var th = html("th");
|
|
723
|
+
var td = html("td");
|
|
724
|
+
var form = html("form");
|
|
725
|
+
var button = html("button");
|
|
726
|
+
var input = html("input");
|
|
727
|
+
var textarea = html("textarea");
|
|
728
|
+
var select = html("select");
|
|
729
|
+
var option = html("option");
|
|
730
|
+
var fieldset = html("fieldset");
|
|
731
|
+
var legend = html("legend");
|
|
732
|
+
var img = html("img");
|
|
733
|
+
var video = html("video");
|
|
734
|
+
var audio = html("audio");
|
|
735
|
+
var canvas = html("canvas");
|
|
736
|
+
var source = html("source");
|
|
737
|
+
var details = html("details");
|
|
738
|
+
var summary = html("summary");
|
|
739
|
+
var dialog = html("dialog");
|
|
740
|
+
var menu = html("menu");
|
|
741
|
+
var iframe = html("iframe");
|
|
742
|
+
var embed = html("embed");
|
|
743
|
+
var object = html("object");
|
|
744
|
+
var picture = html("picture");
|
|
745
|
+
var portal = html("portal");
|
|
746
|
+
var svg = html("svg");
|
|
747
|
+
var script = html("script");
|
|
748
|
+
var noscript = html("noscript");
|
|
749
|
+
var template = html("template");
|
|
750
|
+
var slot = html("slot");
|
|
751
|
+
var address = html("address");
|
|
752
|
+
var hgroup = html("hgroup");
|
|
753
|
+
var search = html("search");
|
|
754
|
+
var abbr = html("abbr");
|
|
755
|
+
var b = html("b");
|
|
756
|
+
var bdi = html("bdi");
|
|
757
|
+
var bdo = html("bdo");
|
|
758
|
+
var cite = html("cite");
|
|
759
|
+
var data = html("data");
|
|
760
|
+
var dfn = html("dfn");
|
|
761
|
+
var i = html("i");
|
|
762
|
+
var kbd = html("kbd");
|
|
763
|
+
var mark = html("mark");
|
|
764
|
+
var q = html("q");
|
|
765
|
+
var rp = html("rp");
|
|
766
|
+
var rt = html("rt");
|
|
767
|
+
var ruby = html("ruby");
|
|
768
|
+
var s = html("s");
|
|
769
|
+
var samp = html("samp");
|
|
770
|
+
var sub = html("sub");
|
|
771
|
+
var sup = html("sup");
|
|
772
|
+
var time = html("time");
|
|
773
|
+
var u = html("u");
|
|
774
|
+
var varEl = html("var");
|
|
775
|
+
var wbr = html("wbr");
|
|
776
|
+
var del = html("del");
|
|
777
|
+
var ins = html("ins");
|
|
778
|
+
var caption = html("caption");
|
|
779
|
+
var colgroup = html("colgroup");
|
|
780
|
+
var col = html("col");
|
|
781
|
+
var datalist = html("datalist");
|
|
782
|
+
var optgroup = html("optgroup");
|
|
783
|
+
var output = html("output");
|
|
784
|
+
var progress = html("progress");
|
|
785
|
+
var meter = html("meter");
|
|
786
|
+
var figure = html("figure");
|
|
787
|
+
var figcaption = html("figcaption");
|
|
788
|
+
var dd = html("dd");
|
|
789
|
+
var dl = html("dl");
|
|
790
|
+
var dt = html("dt");
|
|
791
|
+
var track = html("track");
|
|
792
|
+
var map = html("map");
|
|
793
|
+
var area = html("area");
|
|
794
|
+
// src/render/html_render.ts
|
|
795
|
+
var DOM_EVENT = {
|
|
796
|
+
click: "click",
|
|
797
|
+
dblclick: "dblclick",
|
|
798
|
+
pointerDown: "pointerdown",
|
|
799
|
+
pointerUp: "pointerup",
|
|
800
|
+
pointerMove: "pointermove",
|
|
801
|
+
input: "input",
|
|
802
|
+
change: "change",
|
|
803
|
+
keyDown: "keydown",
|
|
804
|
+
keyUp: "keyup",
|
|
805
|
+
focus: "focus",
|
|
806
|
+
blur: "blur"
|
|
807
|
+
};
|
|
808
|
+
var SKIP_PROPS = new Set(["key"]);
|
|
809
|
+
var DOM_PROPERTIES = new Set([
|
|
810
|
+
"value",
|
|
811
|
+
"checked",
|
|
812
|
+
"selected",
|
|
813
|
+
"indeterminate"
|
|
814
|
+
]);
|
|
815
|
+
|
|
816
|
+
class HtmlRender {
|
|
817
|
+
container;
|
|
818
|
+
constructor(container) {
|
|
819
|
+
this.container = container;
|
|
820
|
+
}
|
|
821
|
+
render(view2) {
|
|
822
|
+
const ref = view2.renderRef;
|
|
823
|
+
if (!ref) {
|
|
824
|
+
const node = this.buildDom(view2);
|
|
825
|
+
const parent = view2.parent;
|
|
826
|
+
if (!parent) {
|
|
827
|
+
this.container.appendChild(node);
|
|
828
|
+
} else {
|
|
829
|
+
const parentNode = this.getParentDomNode(parent);
|
|
830
|
+
if (parentNode) {
|
|
831
|
+
parentNode.insertBefore(node, this.fastInsertionPoint(parent, view2));
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
const newRef = view2.renderRef;
|
|
835
|
+
if (newRef?.kind === "primitive" && newRef.element instanceof HTMLElement && view2.props?.autofocus) {
|
|
836
|
+
newRef.element.focus();
|
|
837
|
+
}
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
if (view2.moved) {
|
|
841
|
+
view2.moved = false;
|
|
842
|
+
if (view2.parent) {
|
|
843
|
+
const expectedStart = this.fastInsertionPoint(view2.parent, view2);
|
|
844
|
+
const firstDom = this.getFirstDomNode(view2);
|
|
845
|
+
if (firstDom && firstDom !== expectedStart) {
|
|
846
|
+
const parentNode = this.getParentDomNode(view2.parent);
|
|
847
|
+
if (parentNode) {
|
|
848
|
+
if (ref.kind === "primitive") {
|
|
849
|
+
parentNode.insertBefore(ref.element, expectedStart);
|
|
850
|
+
} else {
|
|
851
|
+
if (view2.virtualDom) {
|
|
852
|
+
for (const child of view2.virtualDom) {
|
|
853
|
+
this.moveDomNodes(child, parentNode, expectedStart);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
parentNode.insertBefore(ref.endComment, expectedStart);
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
if (ref.kind !== "primitive")
|
|
863
|
+
return;
|
|
864
|
+
if (ref.element instanceof Text) {
|
|
865
|
+
const nextText = String(view2.props);
|
|
866
|
+
if (ref.element.textContent !== nextText) {
|
|
867
|
+
ref.element.textContent = nextText;
|
|
868
|
+
}
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
const nextProps = view2.props;
|
|
872
|
+
if (!ref.prevProps) {
|
|
873
|
+
this.setAttributes(ref, ref.element, nextProps);
|
|
874
|
+
} else {
|
|
875
|
+
this.diffAttributes(ref, ref.element, ref.prevProps, nextProps);
|
|
876
|
+
}
|
|
877
|
+
ref.prevProps = { ...nextProps };
|
|
878
|
+
}
|
|
879
|
+
unmount(view2) {
|
|
880
|
+
this.removeDomNodes(view2);
|
|
881
|
+
view2.renderRef = undefined;
|
|
882
|
+
}
|
|
883
|
+
buildDom(view2) {
|
|
884
|
+
const tag = view2.viewFn[$primitive];
|
|
885
|
+
if (tag != null) {
|
|
886
|
+
if (tag === "text") {
|
|
887
|
+
const textNode = document.createTextNode(String(view2.props));
|
|
888
|
+
const ref2 = {
|
|
889
|
+
kind: "primitive",
|
|
890
|
+
element: textNode,
|
|
891
|
+
prevProps: null,
|
|
892
|
+
listeners: null
|
|
893
|
+
};
|
|
894
|
+
view2.renderRef = ref2;
|
|
895
|
+
return textNode;
|
|
896
|
+
}
|
|
897
|
+
const element = document.createElement(tag);
|
|
898
|
+
const props = view2.props;
|
|
899
|
+
const ref = {
|
|
900
|
+
kind: "primitive",
|
|
901
|
+
element,
|
|
902
|
+
prevProps: null,
|
|
903
|
+
listeners: null
|
|
904
|
+
};
|
|
905
|
+
view2.renderRef = ref;
|
|
906
|
+
this.setAttributes(ref, element, props);
|
|
907
|
+
return element;
|
|
908
|
+
}
|
|
909
|
+
const endComment = document.createComment("");
|
|
910
|
+
view2.renderRef = {
|
|
911
|
+
kind: "composite",
|
|
912
|
+
endComment
|
|
913
|
+
};
|
|
914
|
+
return endComment;
|
|
915
|
+
}
|
|
916
|
+
isEventProp(key, value) {
|
|
917
|
+
return key.length > 2 && key[0] === "o" && key[1] === "n" && key[2] >= "A" && key[2] <= "Z" && typeof value === "function";
|
|
918
|
+
}
|
|
919
|
+
eventPropToCreoName(prop) {
|
|
920
|
+
return prop[2].toLowerCase() + prop.slice(3);
|
|
921
|
+
}
|
|
922
|
+
setAttributes(ref, element, props) {
|
|
923
|
+
for (const key in props) {
|
|
924
|
+
const value = props[key];
|
|
925
|
+
if (SKIP_PROPS.has(key) || value == null)
|
|
926
|
+
continue;
|
|
927
|
+
if (this.isEventProp(key, value)) {
|
|
928
|
+
this.bindEvent(ref, element, key, value);
|
|
929
|
+
continue;
|
|
930
|
+
}
|
|
931
|
+
this.setAttribute(element, key, value);
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
diffAttributes(ref, element, prev, next) {
|
|
935
|
+
for (const key of Object.keys(prev)) {
|
|
936
|
+
if (SKIP_PROPS.has(key))
|
|
937
|
+
continue;
|
|
938
|
+
if (!(key in next) || next[key] == null) {
|
|
939
|
+
if (this.isEventProp(key, prev[key])) {
|
|
940
|
+
this.unbindEvent(ref, element, key);
|
|
941
|
+
} else {
|
|
942
|
+
this.removeAttribute(element, key);
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
for (const key in next) {
|
|
947
|
+
const value = next[key];
|
|
948
|
+
if (SKIP_PROPS.has(key) || value == null)
|
|
949
|
+
continue;
|
|
950
|
+
if (prev[key] === value)
|
|
951
|
+
continue;
|
|
952
|
+
if (this.isEventProp(key, value)) {
|
|
953
|
+
this.unbindEvent(ref, element, key);
|
|
954
|
+
this.bindEvent(ref, element, key, value);
|
|
955
|
+
} else {
|
|
956
|
+
this.setAttribute(element, key, value);
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
bindEvent(ref, element, prop, handler) {
|
|
961
|
+
const creoEvent = this.eventPropToCreoName(prop);
|
|
962
|
+
const domEvent = DOM_EVENT[creoEvent] ?? creoEvent.toLowerCase();
|
|
963
|
+
const wrapped = (e) => {
|
|
964
|
+
const data2 = this.mapEventData(creoEvent, e);
|
|
965
|
+
data2.stopPropagation = () => e.stopPropagation();
|
|
966
|
+
data2.preventDefault = () => e.preventDefault();
|
|
967
|
+
handler(data2);
|
|
968
|
+
};
|
|
969
|
+
if (!ref.listeners)
|
|
970
|
+
ref.listeners = new Map;
|
|
971
|
+
ref.listeners.set(prop, wrapped);
|
|
972
|
+
element.addEventListener(domEvent, wrapped);
|
|
973
|
+
}
|
|
974
|
+
unbindEvent(ref, element, prop) {
|
|
975
|
+
const wrapped = ref.listeners?.get(prop);
|
|
976
|
+
if (!wrapped)
|
|
977
|
+
return;
|
|
978
|
+
const creoEvent = this.eventPropToCreoName(prop);
|
|
979
|
+
const domEvent = DOM_EVENT[creoEvent] ?? creoEvent.toLowerCase();
|
|
980
|
+
element.removeEventListener(domEvent, wrapped);
|
|
981
|
+
ref.listeners.delete(prop);
|
|
982
|
+
}
|
|
983
|
+
mapEventData(creoEvent, e) {
|
|
984
|
+
if (creoEvent === "click" || creoEvent === "dblclick" || creoEvent.startsWith("pointer")) {
|
|
985
|
+
const pe = e;
|
|
986
|
+
return { x: pe.clientX, y: pe.clientY };
|
|
987
|
+
}
|
|
988
|
+
if (creoEvent === "input" || creoEvent === "change") {
|
|
989
|
+
return { value: e.target.value };
|
|
990
|
+
}
|
|
991
|
+
if (creoEvent.startsWith("key")) {
|
|
992
|
+
const ke = e;
|
|
993
|
+
return { key: ke.key, code: ke.code };
|
|
994
|
+
}
|
|
995
|
+
return {};
|
|
996
|
+
}
|
|
997
|
+
setAttribute(element, key, value) {
|
|
998
|
+
if (key === "class") {
|
|
999
|
+
element.className = String(value);
|
|
1000
|
+
} else if (key === "style") {
|
|
1001
|
+
element.style.cssText = String(value);
|
|
1002
|
+
} else if (DOM_PROPERTIES.has(key)) {
|
|
1003
|
+
element[key] = value;
|
|
1004
|
+
} else if (typeof value === "boolean") {
|
|
1005
|
+
if (value) {
|
|
1006
|
+
element.setAttribute(key, "");
|
|
1007
|
+
} else {
|
|
1008
|
+
element.removeAttribute(key);
|
|
1009
|
+
}
|
|
1010
|
+
} else {
|
|
1011
|
+
element.setAttribute(key, String(value));
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
removeAttribute(element, key) {
|
|
1015
|
+
if (key === "class") {
|
|
1016
|
+
element.className = "";
|
|
1017
|
+
} else if (key === "style") {
|
|
1018
|
+
element.style.cssText = "";
|
|
1019
|
+
} else if (DOM_PROPERTIES.has(key)) {
|
|
1020
|
+
element[key] = key === "value" ? "" : false;
|
|
1021
|
+
} else {
|
|
1022
|
+
element.removeAttribute(key);
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
fastInsertionPoint(parent, view2) {
|
|
1026
|
+
const vdom = parent.virtualDom;
|
|
1027
|
+
if (vdom && vdom.length > 0) {
|
|
1028
|
+
const node = vdom.getNode(view2);
|
|
1029
|
+
if (node) {
|
|
1030
|
+
if (node.isLast() || parent.quickRerender) {
|
|
1031
|
+
const ref2 = parent.renderRef;
|
|
1032
|
+
if (ref2?.kind === "composite") {
|
|
1033
|
+
return ref2.endComment;
|
|
1034
|
+
} else {
|
|
1035
|
+
return null;
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
const prev = node.getPrev();
|
|
1039
|
+
if (prev) {
|
|
1040
|
+
const prevRef = prev.v.renderRef;
|
|
1041
|
+
if (prevRef) {
|
|
1042
|
+
return (prevRef.kind === "composite" ? prevRef.endComment : prevRef.element).nextSibling;
|
|
1043
|
+
}
|
|
1044
|
+
let cur = prev.getPrev();
|
|
1045
|
+
while (cur) {
|
|
1046
|
+
const curRef = cur.v.renderRef;
|
|
1047
|
+
if (curRef) {
|
|
1048
|
+
return (curRef.kind === "composite" ? curRef.endComment : curRef.element).nextSibling;
|
|
1049
|
+
}
|
|
1050
|
+
cur = cur.getPrev();
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
const ref = parent.renderRef;
|
|
1056
|
+
if (!ref)
|
|
1057
|
+
return null;
|
|
1058
|
+
return ref.kind === "composite" ? ref.endComment : ref.element.firstChild;
|
|
1059
|
+
}
|
|
1060
|
+
getParentDomNode(parent) {
|
|
1061
|
+
const ref = parent.renderRef;
|
|
1062
|
+
if (!ref)
|
|
1063
|
+
return null;
|
|
1064
|
+
if (ref.kind === "primitive") {
|
|
1065
|
+
return ref.element;
|
|
1066
|
+
}
|
|
1067
|
+
return ref.endComment.parentNode;
|
|
1068
|
+
}
|
|
1069
|
+
moveDomNodes(view2, parentNode, insertBefore) {
|
|
1070
|
+
const ref = view2.renderRef;
|
|
1071
|
+
if (!ref)
|
|
1072
|
+
return;
|
|
1073
|
+
if (ref.kind === "primitive") {
|
|
1074
|
+
parentNode.insertBefore(ref.element, insertBefore);
|
|
1075
|
+
} else {
|
|
1076
|
+
if (view2.virtualDom) {
|
|
1077
|
+
for (const child of view2.virtualDom) {
|
|
1078
|
+
this.moveDomNodes(child, parentNode, insertBefore);
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
parentNode.insertBefore(ref.endComment, insertBefore);
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
getFirstDomNode(view2) {
|
|
1085
|
+
const ref = view2.renderRef;
|
|
1086
|
+
if (!ref)
|
|
1087
|
+
return null;
|
|
1088
|
+
if (ref.kind === "primitive")
|
|
1089
|
+
return ref.element;
|
|
1090
|
+
if (view2.virtualDom) {
|
|
1091
|
+
for (const child of view2.virtualDom) {
|
|
1092
|
+
const node = this.getFirstDomNode(child);
|
|
1093
|
+
if (node)
|
|
1094
|
+
return node;
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
return ref.endComment;
|
|
1098
|
+
}
|
|
1099
|
+
removeDomNodes(view2) {
|
|
1100
|
+
const ref = view2.renderRef;
|
|
1101
|
+
if (!ref)
|
|
1102
|
+
return;
|
|
1103
|
+
if (ref.kind === "primitive") {
|
|
1104
|
+
ref.element.parentNode?.removeChild(ref.element);
|
|
1105
|
+
return;
|
|
1106
|
+
}
|
|
1107
|
+
ref.endComment.parentNode?.removeChild(ref.endComment);
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
// src/render/json_render.ts
|
|
1111
|
+
class JsonRender {
|
|
1112
|
+
root;
|
|
1113
|
+
render(view2) {
|
|
1114
|
+
const existing = view2.renderRef;
|
|
1115
|
+
if (!existing) {
|
|
1116
|
+
const node = this.buildNode(view2);
|
|
1117
|
+
if (!view2.parent) {
|
|
1118
|
+
this.root = node;
|
|
1119
|
+
return;
|
|
1120
|
+
}
|
|
1121
|
+
const parentNode2 = view2.parent.renderRef;
|
|
1122
|
+
if (parentNode2) {
|
|
1123
|
+
parentNode2.children.push(node);
|
|
1124
|
+
}
|
|
1125
|
+
return;
|
|
1126
|
+
}
|
|
1127
|
+
const parentNode = view2.parent?.renderRef;
|
|
1128
|
+
if (parentNode) {
|
|
1129
|
+
const oldIdx = parentNode.children.indexOf(existing);
|
|
1130
|
+
if (oldIdx !== -1) {
|
|
1131
|
+
const nextSibling = this.getNextSibling(view2);
|
|
1132
|
+
const nextNode = nextSibling?.renderRef;
|
|
1133
|
+
const expectedIdx = nextNode ? parentNode.children.indexOf(nextNode) : parentNode.children.length;
|
|
1134
|
+
if (oldIdx !== expectedIdx && oldIdx !== expectedIdx - 1) {
|
|
1135
|
+
parentNode.children.splice(oldIdx, 1);
|
|
1136
|
+
const insertIdx = nextNode ? parentNode.children.indexOf(nextNode) : parentNode.children.length;
|
|
1137
|
+
parentNode.children.splice(insertIdx, 0, existing);
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
const tag = view2.viewFn[$primitive];
|
|
1142
|
+
existing.props = tag === "text" ? { content: view2.props } : { ...view2.props };
|
|
1143
|
+
}
|
|
1144
|
+
unmount(view2) {
|
|
1145
|
+
const childNode = view2.renderRef;
|
|
1146
|
+
const parentNode = view2.parent?.renderRef;
|
|
1147
|
+
if (parentNode && childNode) {
|
|
1148
|
+
const idx = parentNode.children.indexOf(childNode);
|
|
1149
|
+
if (idx !== -1)
|
|
1150
|
+
parentNode.children.splice(idx, 1);
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
getNextSibling(view2) {
|
|
1154
|
+
return view2.parent?.virtualDom?.getNode(view2)?.getNext()?.v;
|
|
1155
|
+
}
|
|
1156
|
+
buildNode(view2) {
|
|
1157
|
+
const tag = view2.viewFn[$primitive];
|
|
1158
|
+
const props = tag === "text" ? { content: view2.props } : { ...view2.props };
|
|
1159
|
+
const node = {
|
|
1160
|
+
type: tag ?? "composite",
|
|
1161
|
+
props,
|
|
1162
|
+
children: []
|
|
1163
|
+
};
|
|
1164
|
+
if (view2.userKey != null)
|
|
1165
|
+
node.key = view2.userKey;
|
|
1166
|
+
view2.renderRef = node;
|
|
1167
|
+
return node;
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
// src/render/string_render.ts
|
|
1171
|
+
var VOID_TAGS = new Set([
|
|
1172
|
+
"br",
|
|
1173
|
+
"hr",
|
|
1174
|
+
"img",
|
|
1175
|
+
"input",
|
|
1176
|
+
"source",
|
|
1177
|
+
"track",
|
|
1178
|
+
"embed",
|
|
1179
|
+
"area",
|
|
1180
|
+
"col",
|
|
1181
|
+
"wbr"
|
|
1182
|
+
]);
|
|
1183
|
+
|
|
1184
|
+
class StringRender {
|
|
1185
|
+
rootView;
|
|
1186
|
+
render(view2) {
|
|
1187
|
+
if (!view2.parent) {
|
|
1188
|
+
this.rootView = view2;
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
unmount(_view) {}
|
|
1192
|
+
renderToString() {
|
|
1193
|
+
if (!this.rootView)
|
|
1194
|
+
return "";
|
|
1195
|
+
return this.buildString(this.rootView);
|
|
1196
|
+
}
|
|
1197
|
+
buildString(view2) {
|
|
1198
|
+
const tag = view2.viewFn[$primitive];
|
|
1199
|
+
if (tag != null) {
|
|
1200
|
+
if (tag === "text") {
|
|
1201
|
+
return `${view2.props}`;
|
|
1202
|
+
}
|
|
1203
|
+
if (VOID_TAGS.has(tag)) {
|
|
1204
|
+
return this.buildVoidTag(tag, view2);
|
|
1205
|
+
}
|
|
1206
|
+
return `<${tag}>${this.buildChildren(view2)}</${tag}>`;
|
|
1207
|
+
}
|
|
1208
|
+
return this.buildChildren(view2);
|
|
1209
|
+
}
|
|
1210
|
+
buildVoidTag(tag, view2) {
|
|
1211
|
+
const props = view2.props;
|
|
1212
|
+
let attrs = "";
|
|
1213
|
+
if (props.src)
|
|
1214
|
+
attrs += ` src="${props.src}"`;
|
|
1215
|
+
if (props.alt)
|
|
1216
|
+
attrs += ` alt="${props.alt}"`;
|
|
1217
|
+
return `<${tag}${attrs} />`;
|
|
1218
|
+
}
|
|
1219
|
+
buildChildren(view2) {
|
|
1220
|
+
let result = "";
|
|
1221
|
+
if (view2.virtualDom) {
|
|
1222
|
+
for (const child of view2.virtualDom) {
|
|
1223
|
+
result += this.buildString(child);
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
return result;
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
// src/functional/maybe.ts
|
|
1230
|
+
function just(maybe, errorMessage) {
|
|
1231
|
+
if (maybe == null) {
|
|
1232
|
+
throw new TypeError(errorMessage ?? "Expected Just, received None as Maybe");
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
function withDefault(v, alternative) {
|
|
1236
|
+
if (v != null) {
|
|
1237
|
+
return v;
|
|
1238
|
+
}
|
|
1239
|
+
return alternative;
|
|
1240
|
+
}
|
|
1241
|
+
var _ = undefined;
|
|
1242
|
+
// src/functional/assert.ts
|
|
1243
|
+
function assertNever(x) {
|
|
1244
|
+
throw new Error(`Unhandled case: ${x}`);
|
|
1245
|
+
}
|
|
1246
|
+
export {
|
|
1247
|
+
withDefault,
|
|
1248
|
+
wbr,
|
|
1249
|
+
view,
|
|
1250
|
+
video,
|
|
1251
|
+
varEl,
|
|
1252
|
+
ul,
|
|
1253
|
+
u,
|
|
1254
|
+
track,
|
|
1255
|
+
tr,
|
|
1256
|
+
time,
|
|
1257
|
+
thead,
|
|
1258
|
+
th,
|
|
1259
|
+
tfoot,
|
|
1260
|
+
textarea,
|
|
1261
|
+
text,
|
|
1262
|
+
template,
|
|
1263
|
+
td,
|
|
1264
|
+
tbody,
|
|
1265
|
+
table,
|
|
1266
|
+
svg,
|
|
1267
|
+
sup,
|
|
1268
|
+
summary,
|
|
1269
|
+
sub,
|
|
1270
|
+
strong,
|
|
1271
|
+
store,
|
|
1272
|
+
span,
|
|
1273
|
+
source,
|
|
1274
|
+
small,
|
|
1275
|
+
slot,
|
|
1276
|
+
shallowEqual,
|
|
1277
|
+
select,
|
|
1278
|
+
section,
|
|
1279
|
+
search,
|
|
1280
|
+
script,
|
|
1281
|
+
samp,
|
|
1282
|
+
s,
|
|
1283
|
+
ruby,
|
|
1284
|
+
rt,
|
|
1285
|
+
rp,
|
|
1286
|
+
q,
|
|
1287
|
+
progress,
|
|
1288
|
+
pre,
|
|
1289
|
+
portal,
|
|
1290
|
+
picture,
|
|
1291
|
+
p,
|
|
1292
|
+
output,
|
|
1293
|
+
option,
|
|
1294
|
+
optgroup,
|
|
1295
|
+
ol,
|
|
1296
|
+
object,
|
|
1297
|
+
noscript,
|
|
1298
|
+
nav,
|
|
1299
|
+
meter,
|
|
1300
|
+
menu,
|
|
1301
|
+
mark,
|
|
1302
|
+
map,
|
|
1303
|
+
main,
|
|
1304
|
+
li,
|
|
1305
|
+
legend,
|
|
1306
|
+
label,
|
|
1307
|
+
kbd,
|
|
1308
|
+
just,
|
|
1309
|
+
isStore,
|
|
1310
|
+
ins,
|
|
1311
|
+
input,
|
|
1312
|
+
img,
|
|
1313
|
+
iframe,
|
|
1314
|
+
i,
|
|
1315
|
+
html,
|
|
1316
|
+
hr,
|
|
1317
|
+
hgroup,
|
|
1318
|
+
header,
|
|
1319
|
+
h6,
|
|
1320
|
+
h5,
|
|
1321
|
+
h4,
|
|
1322
|
+
h3,
|
|
1323
|
+
h2,
|
|
1324
|
+
h1,
|
|
1325
|
+
form,
|
|
1326
|
+
footer,
|
|
1327
|
+
figure,
|
|
1328
|
+
figcaption,
|
|
1329
|
+
fieldset,
|
|
1330
|
+
embed,
|
|
1331
|
+
em,
|
|
1332
|
+
dt,
|
|
1333
|
+
dl,
|
|
1334
|
+
div,
|
|
1335
|
+
dialog,
|
|
1336
|
+
dfn,
|
|
1337
|
+
details,
|
|
1338
|
+
del,
|
|
1339
|
+
dd,
|
|
1340
|
+
datalist,
|
|
1341
|
+
data,
|
|
1342
|
+
createApp,
|
|
1343
|
+
colgroup,
|
|
1344
|
+
col,
|
|
1345
|
+
code,
|
|
1346
|
+
cite,
|
|
1347
|
+
caption,
|
|
1348
|
+
canvas,
|
|
1349
|
+
button,
|
|
1350
|
+
br,
|
|
1351
|
+
blockquote,
|
|
1352
|
+
bdo,
|
|
1353
|
+
bdi,
|
|
1354
|
+
b,
|
|
1355
|
+
audio,
|
|
1356
|
+
assertNever,
|
|
1357
|
+
aside,
|
|
1358
|
+
article,
|
|
1359
|
+
area,
|
|
1360
|
+
address,
|
|
1361
|
+
abbr,
|
|
1362
|
+
a,
|
|
1363
|
+
_,
|
|
1364
|
+
StringRender,
|
|
1365
|
+
Store,
|
|
1366
|
+
State,
|
|
1367
|
+
JsonRender,
|
|
1368
|
+
HtmlRender,
|
|
1369
|
+
Engine,
|
|
1370
|
+
$primitive
|
|
1371
|
+
};
|
|
1372
|
+
|
|
1373
|
+
//# debugId=3A0F56854FC011F464756E2164756E21
|