@solidjs/web 2.0.0-beta.25 → 2.0.0-beta.27
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/dist/dev.cjs +14 -9
- package/dist/dev.js +14 -10
- package/dist/server.cjs +41 -78
- package/dist/server.js +42 -80
- package/dist/web.cjs +14 -9
- package/dist/web.js +14 -10
- package/frames/dist/client.cjs +180 -224
- package/frames/dist/client.dev.cjs +1456 -0
- package/frames/dist/client.dev.js +1444 -0
- package/frames/dist/client.js +181 -225
- package/frames/dist/server.cjs +139 -123
- package/frames/dist/server.js +139 -123
- package/package.json +24 -4
- package/serialization/dist/serialization.cjs +6 -3
- package/serialization/dist/serialization.js +6 -3
- package/serialization/types/index.d.ts +7 -1
- package/serialization/types-cjs/index.d.cts +7 -1
- package/server-functions/dist/client.cjs +18 -5
- package/server-functions/dist/client.js +16 -6
- package/server-functions/dist/server.cjs +164 -8
- package/server-functions/dist/server.js +158 -9
- package/types/client.d.ts +3 -3
- package/types/frames/client.d.ts +1 -1
- package/types/frames/frame-client.d.ts +34 -28
- package/types/frames/serializer.d.ts +7 -1
- package/types/jsx.d.ts +1 -1
- package/types/response.d.ts +10 -0
- package/types/serializer.d.ts +7 -1
- package/types/server-functions/client.d.ts +3 -0
- package/types/server-functions/flash.d.ts +38 -0
- package/types/server-functions/server.d.ts +79 -4
- package/types/server-functions/shared.d.ts +35 -0
- package/types-cjs/client.d.cts +3 -3
- package/types-cjs/frames/client.d.cts +1 -1
- package/types-cjs/frames/frame-client.d.cts +34 -28
- package/types-cjs/frames/serializer.d.cts +7 -1
- package/types-cjs/jsx.d.cts +1 -1
- package/types-cjs/response.d.cts +10 -0
- package/types-cjs/serializer.d.cts +7 -1
- package/types-cjs/server-functions/client.d.cts +3 -0
- package/types-cjs/server-functions/flash.d.cts +38 -0
- package/types-cjs/server-functions/server.d.cts +79 -4
- package/types-cjs/server-functions/shared.d.cts +35 -0
package/frames/dist/client.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { getOwner, onCleanup, runWithOwner, sharedConfig, createOwner } from 'solid-js';
|
|
1
|
+
import { getOwner, onCleanup, createMemo, runWithOwner, createLoadingBoundary, sharedConfig, createOwner } from 'solid-js';
|
|
2
|
+
import { insert } from '@solidjs/web';
|
|
2
3
|
import { configureServerFunctionsClient } from '@solidjs/web/server-functions/client';
|
|
3
4
|
import { fromCrossJSON, Feature } from 'seroval';
|
|
4
5
|
import { AbortSignalPlugin, CustomEventPlugin, DOMExceptionPlugin, EventPlugin, FormDataPlugin, HeadersPlugin, ReadableStreamPlugin, RequestPlugin, ResponsePlugin, URLSearchParamsPlugin, URLPlugin } from 'seroval-plugins/web';
|
|
@@ -64,22 +65,6 @@ function chunkToRecords(chunk) {
|
|
|
64
65
|
args: chunk.args
|
|
65
66
|
}
|
|
66
67
|
};
|
|
67
|
-
case "template":
|
|
68
|
-
return {
|
|
69
|
-
[`tpl:${chunk.key}`]: {
|
|
70
|
-
kind: "template",
|
|
71
|
-
html: chunk.html,
|
|
72
|
-
fields: chunk.fields
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
case "block":
|
|
76
|
-
return {
|
|
77
|
-
[`seg:${chunk.key}`]: {
|
|
78
|
-
kind: "block",
|
|
79
|
-
template: `tpl:${chunk.template}`,
|
|
80
|
-
values: chunk.values
|
|
81
|
-
}
|
|
82
|
-
};
|
|
83
68
|
case "complete":
|
|
84
69
|
return {
|
|
85
70
|
":complete": true
|
|
@@ -127,7 +112,7 @@ function createFrameHost(options = {}) {
|
|
|
127
112
|
pending.delete(id);
|
|
128
113
|
const records = {};
|
|
129
114
|
let version;
|
|
130
|
-
for (const chunk of buffered) {
|
|
115
|
+
for (const chunk of buffered.chunks) {
|
|
131
116
|
if (chunk.type === "data") {
|
|
132
117
|
options.applyData && options.applyData(chunk);
|
|
133
118
|
continue;
|
|
@@ -159,12 +144,20 @@ function createFrameHost(options = {}) {
|
|
|
159
144
|
for (const frame of set) deliver(frame, chunk);
|
|
160
145
|
return;
|
|
161
146
|
}
|
|
162
|
-
const buffered = pending.get(chunk.id)
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
147
|
+
const buffered = pending.get(chunk.id);
|
|
148
|
+
if (!buffered) {
|
|
149
|
+
pending.set(chunk.id, {
|
|
150
|
+
version: chunk.version,
|
|
151
|
+
chunks: [chunk]
|
|
152
|
+
});
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
if (chunk.version < buffered.version) return;
|
|
156
|
+
if (chunk.version > buffered.version) {
|
|
157
|
+
buffered.version = chunk.version;
|
|
158
|
+
buffered.chunks.length = 0;
|
|
159
|
+
}
|
|
160
|
+
buffered.chunks.push(chunk);
|
|
168
161
|
},
|
|
169
162
|
get(id) {
|
|
170
163
|
const set = frames.get(id);
|
|
@@ -223,7 +216,7 @@ class FrameImpl {
|
|
|
223
216
|
if (options.host && options.id !== undefined) {
|
|
224
217
|
options.host.register(options.id, this);
|
|
225
218
|
}
|
|
226
|
-
if (options.adopt) this.#syncSlots();
|
|
219
|
+
if (options.adopt && this.#version === undefined) this.#syncSlots();
|
|
227
220
|
}
|
|
228
221
|
#parent() {
|
|
229
222
|
return this.#element ?? this.#start.parentNode;
|
|
@@ -273,7 +266,7 @@ class FrameImpl {
|
|
|
273
266
|
this.#revealed.clear();
|
|
274
267
|
this.#fallbackShown.clear();
|
|
275
268
|
for (const key of Object.keys(this.#store)) {
|
|
276
|
-
if (key.startsWith("seg:") || key
|
|
269
|
+
if (key.startsWith("seg:") || key === ":error") {
|
|
277
270
|
delete this.#store[key];
|
|
278
271
|
}
|
|
279
272
|
}
|
|
@@ -342,10 +335,14 @@ class FrameImpl {
|
|
|
342
335
|
if (record !== undefined) return record;
|
|
343
336
|
return this.#options.resolveSlotRecord?.(occurrence);
|
|
344
337
|
}
|
|
345
|
-
#
|
|
338
|
+
#removeSlotRecord(occurrence) {
|
|
339
|
+
const key = `slot:${occurrence}`;
|
|
340
|
+
if (key in this.#store) delete this.#store[key];else this.#options.removeSlotRecord?.(occurrence);
|
|
341
|
+
}
|
|
342
|
+
#syncSlots(root) {
|
|
346
343
|
if (!this.#slots && !this.#options.resolveSlot) return;
|
|
347
344
|
const found = new Map();
|
|
348
|
-
this.#collectSlots(found);
|
|
345
|
+
if (root) collectSlots(root, found);else this.#collectSlots(found);
|
|
349
346
|
for (const [occurrence, start] of found) {
|
|
350
347
|
const callback = this.#resolveSlot(propOf(occurrence));
|
|
351
348
|
if (!callback) continue;
|
|
@@ -358,11 +355,12 @@ class FrameImpl {
|
|
|
358
355
|
this.#runSlotCleanups(occurrence);
|
|
359
356
|
}
|
|
360
357
|
if (!this.#mountedSlots.has(occurrence)) {
|
|
358
|
+
if (this.#options.adopt) this.#discoverRegions(occurrence, start);
|
|
361
359
|
const nodes = this.#invokeSlot(occurrence, callback, record, start, this.#options.adopt);
|
|
362
360
|
if (nodes) this.#replaceRange(occurrence, start, nodes);
|
|
363
361
|
this.#slotNodes.set(occurrence, nodes);
|
|
364
362
|
this.#mountedSlots.add(occurrence);
|
|
365
|
-
this.#discoverRegions(occurrence, start);
|
|
363
|
+
if (!this.#options.adopt || nodes) this.#discoverRegions(occurrence, start);
|
|
366
364
|
this.#bindRegions(occurrence);
|
|
367
365
|
} else if (record !== this.#slotArgs.get(occurrence)) {
|
|
368
366
|
if (this.#refArgsUnchanged(occurrence, record)) {
|
|
@@ -375,8 +373,10 @@ class FrameImpl {
|
|
|
375
373
|
this.#bindRegions(occurrence);
|
|
376
374
|
}
|
|
377
375
|
}
|
|
378
|
-
|
|
379
|
-
|
|
376
|
+
if (!root) {
|
|
377
|
+
for (const occurrence of [...this.#mountedSlots]) {
|
|
378
|
+
if (!found.has(occurrence)) this.#unmountSlot(occurrence);
|
|
379
|
+
}
|
|
380
380
|
}
|
|
381
381
|
}
|
|
382
382
|
#invokeSlot(occurrence, callback, record, start, adopted) {
|
|
@@ -389,6 +389,13 @@ class FrameImpl {
|
|
|
389
389
|
existing: start ? rangeInterior(start, slotEnd(occurrence)) : []
|
|
390
390
|
};
|
|
391
391
|
const props = record && record.kind === "slot" ? this.#resolveArgs(occurrence, record.args) : {};
|
|
392
|
+
const regions = this.#slotRegions.get(occurrence);
|
|
393
|
+
if (regions) {
|
|
394
|
+
for (const entry of regions.values()) {
|
|
395
|
+
const argKey = entry.childId.slice(entry.childId.lastIndexOf(".") + 1);
|
|
396
|
+
if (!(argKey in props)) props[argKey] = entry.element;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
392
399
|
const content = callback(props, ctx);
|
|
393
400
|
this.#slotArgs.set(occurrence, record);
|
|
394
401
|
if (cleanups.length) this.#slotCleanups.set(occurrence, cleanups);
|
|
@@ -411,7 +418,7 @@ class FrameImpl {
|
|
|
411
418
|
this.#slotNodes.delete(key);
|
|
412
419
|
this.#slotArgs.delete(key);
|
|
413
420
|
this.#slotResolvedRefs.delete(key);
|
|
414
|
-
|
|
421
|
+
this.#removeSlotRecord(key);
|
|
415
422
|
this.#runSlotCleanups(key);
|
|
416
423
|
const regions = this.#slotRegions.get(key);
|
|
417
424
|
if (regions) {
|
|
@@ -445,29 +452,17 @@ class FrameImpl {
|
|
|
445
452
|
cache[key] = resolved;
|
|
446
453
|
props[key] = resolved;
|
|
447
454
|
} else if (isFrameRef(value)) {
|
|
448
|
-
const fragment = document.createDocumentFragment();
|
|
449
455
|
let entry = regions.get(value.$frame);
|
|
450
456
|
if (!entry) {
|
|
451
|
-
const
|
|
452
|
-
const end = document.createComment(`frame:${value.$frame}:end`);
|
|
457
|
+
const element = makeFrameElement(value.$frame);
|
|
453
458
|
entry = {
|
|
454
459
|
childId: value.$frame,
|
|
455
|
-
|
|
456
|
-
end,
|
|
460
|
+
element,
|
|
457
461
|
frame: undefined
|
|
458
462
|
};
|
|
459
463
|
regions.set(value.$frame, entry);
|
|
460
|
-
fragment.append(start, end);
|
|
461
|
-
} else {
|
|
462
|
-
let n = entry.start;
|
|
463
|
-
while (n) {
|
|
464
|
-
const next = n.nextSibling;
|
|
465
|
-
fragment.append(n);
|
|
466
|
-
if (n === entry.end) break;
|
|
467
|
-
n = next;
|
|
468
|
-
}
|
|
469
464
|
}
|
|
470
|
-
props[key] =
|
|
465
|
+
props[key] = entry.element;
|
|
471
466
|
} else {
|
|
472
467
|
props[key] = value;
|
|
473
468
|
}
|
|
@@ -481,49 +476,12 @@ class FrameImpl {
|
|
|
481
476
|
regions = new Map();
|
|
482
477
|
this.#slotRegions.set(slotKey, regions);
|
|
483
478
|
}
|
|
484
|
-
const doc = start.ownerDocument;
|
|
485
479
|
const endData = slotEnd(slotKey);
|
|
486
|
-
const comments = [];
|
|
487
480
|
let n = start.nextSibling;
|
|
488
481
|
while (n && !(n.nodeType === COMMENT_NODE && n.data === endData)) {
|
|
489
|
-
|
|
490
|
-
const walker = doc.createTreeWalker(n, 128 );
|
|
491
|
-
let c;
|
|
492
|
-
while (c = walker.nextNode()) comments.push(c);
|
|
493
|
-
}
|
|
482
|
+
collectRegionElements(n, regions);
|
|
494
483
|
n = n.nextSibling;
|
|
495
484
|
}
|
|
496
|
-
let depth = 0;
|
|
497
|
-
let openId = null;
|
|
498
|
-
let openStart = null;
|
|
499
|
-
for (const c of comments) {
|
|
500
|
-
const data = c.data;
|
|
501
|
-
if (!data.startsWith("frame:")) continue;
|
|
502
|
-
if (data.endsWith(":start")) {
|
|
503
|
-
const childId = data.slice(6, -6);
|
|
504
|
-
if (!childId) continue;
|
|
505
|
-
if (depth === 0) {
|
|
506
|
-
openId = childId;
|
|
507
|
-
openStart = c;
|
|
508
|
-
}
|
|
509
|
-
depth++;
|
|
510
|
-
} else if (data.endsWith(":end")) {
|
|
511
|
-
const childId = data.slice(6, -4);
|
|
512
|
-
if (!childId) continue;
|
|
513
|
-
if (depth > 0) {
|
|
514
|
-
depth--;
|
|
515
|
-
if (depth === 0 && childId === openId && !regions.has(openId)) {
|
|
516
|
-
regions.set(openId, {
|
|
517
|
-
childId: openId,
|
|
518
|
-
start: openStart,
|
|
519
|
-
end: c,
|
|
520
|
-
frame: undefined,
|
|
521
|
-
adopt: true
|
|
522
|
-
});
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
485
|
}
|
|
528
486
|
#refArgsUnchanged(occurrence, record) {
|
|
529
487
|
const old = this.#slotArgs.get(occurrence);
|
|
@@ -567,15 +525,16 @@ class FrameImpl {
|
|
|
567
525
|
const regions = this.#slotRegions.get(slotKey);
|
|
568
526
|
if (!regions) return;
|
|
569
527
|
for (const entry of regions.values()) {
|
|
570
|
-
if (!entry.frame
|
|
571
|
-
entry.frame = new FrameImpl(
|
|
528
|
+
if (!entry.frame) {
|
|
529
|
+
entry.frame = new FrameImpl(entry.element, null, null, {
|
|
572
530
|
id: entry.childId,
|
|
573
531
|
host: this.#options.host,
|
|
574
532
|
adopt: entry.adopt,
|
|
575
533
|
claimScope: this.#options.claimScope ?? this.#options.id,
|
|
576
534
|
ownerScope: this.#options.ownerScope,
|
|
577
535
|
resolveSlot: prop => this.#resolveSlot(prop),
|
|
578
|
-
resolveSlotRecord: occurrence => this.#resolveSlotRecord(occurrence)
|
|
536
|
+
resolveSlotRecord: occurrence => this.#resolveSlotRecord(occurrence),
|
|
537
|
+
removeSlotRecord: occurrence => this.#removeSlotRecord(occurrence)
|
|
579
538
|
});
|
|
580
539
|
}
|
|
581
540
|
}
|
|
@@ -590,12 +549,7 @@ class FrameImpl {
|
|
|
590
549
|
n = afterRange(n, id);
|
|
591
550
|
continue;
|
|
592
551
|
}
|
|
593
|
-
|
|
594
|
-
if (regionId !== null) {
|
|
595
|
-
n = afterFrameRegion(n, regionId);
|
|
596
|
-
continue;
|
|
597
|
-
}
|
|
598
|
-
if (n.nodeType === ELEMENT_NODE) collectSlots(n, found);
|
|
552
|
+
if (n.nodeType === ELEMENT_NODE && !isFrameElement(n)) collectSlots(n, found);
|
|
599
553
|
n = n.nextSibling;
|
|
600
554
|
}
|
|
601
555
|
}
|
|
@@ -617,6 +571,7 @@ class FrameImpl {
|
|
|
617
571
|
if (this.#disposed) return;
|
|
618
572
|
this.#disposed = true;
|
|
619
573
|
for (const key of [...this.#slotCleanups.keys()]) this.#runSlotCleanups(key);
|
|
574
|
+
for (const key of this.#mountedSlots) this.#removeSlotRecord(key);
|
|
620
575
|
for (const regions of this.#slotRegions.values()) {
|
|
621
576
|
for (const {
|
|
622
577
|
frame
|
|
@@ -662,13 +617,7 @@ class FrameImpl {
|
|
|
662
617
|
}
|
|
663
618
|
#segmentReady(name) {
|
|
664
619
|
const content = this.#store[`seg:${name}`];
|
|
665
|
-
if (!content) return false;
|
|
666
|
-
if (content.kind === "block") {
|
|
667
|
-
const template = this.#store[content.template];
|
|
668
|
-
if (!template || template.kind !== "template") return false;
|
|
669
|
-
} else if (content.kind !== "html") {
|
|
670
|
-
return false;
|
|
671
|
-
}
|
|
620
|
+
if (!content || content.kind !== "html") return false;
|
|
672
621
|
if (!this.#store[`seg:${name}:reveal`]) return false;
|
|
673
622
|
const assets = this.#store[`seg:${name}:assets`];
|
|
674
623
|
if (assets && assets.styles) {
|
|
@@ -695,6 +644,23 @@ class FrameImpl {
|
|
|
695
644
|
parent.removeChild(n);
|
|
696
645
|
n = next;
|
|
697
646
|
}
|
|
647
|
+
if (this.#options.reveal) {
|
|
648
|
+
const fallbackFrag = tpl.content.cloneNode(true);
|
|
649
|
+
this.#claimTree(fallbackFrag);
|
|
650
|
+
this.#options.reveal({
|
|
651
|
+
before: closing,
|
|
652
|
+
fallback: [...fallbackFrag.childNodes],
|
|
653
|
+
content: () => {
|
|
654
|
+
const materialized = this.#materialize(content);
|
|
655
|
+
this.#syncSlots(materialized);
|
|
656
|
+
this.#claimTree(materialized);
|
|
657
|
+
return materialized;
|
|
658
|
+
}
|
|
659
|
+
});
|
|
660
|
+
tpl.remove();
|
|
661
|
+
this.#revealed.add(name);
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
698
664
|
const materialized = this.#materialize(content);
|
|
699
665
|
this.#claimTree(materialized);
|
|
700
666
|
parent.insertBefore(materialized, closing);
|
|
@@ -713,70 +679,37 @@ class FrameImpl {
|
|
|
713
679
|
return true;
|
|
714
680
|
}
|
|
715
681
|
#materialize(record) {
|
|
716
|
-
|
|
717
|
-
if (record.kind === "block") {
|
|
718
|
-
const template = this.#store[record.template];
|
|
719
|
-
if (!template || template.kind !== "template") return parseFragment("");
|
|
720
|
-
return materializeBlock(template, record.values);
|
|
721
|
-
}
|
|
722
|
-
return parseFragment("");
|
|
682
|
+
return record.kind === "html" ? parseFragment(record.value) : parseFragment("");
|
|
723
683
|
}
|
|
724
684
|
}
|
|
725
|
-
function materializeBlock(template, values) {
|
|
726
|
-
const fragment = parseFragment(template.html);
|
|
727
|
-
for (let i = 0; i < template.fields.length; i++) {
|
|
728
|
-
const marker = `field:${template.fields[i]}`;
|
|
729
|
-
const value = values[i] == null ? "" : String(values[i]);
|
|
730
|
-
let hole = findComment(fragment, marker);
|
|
731
|
-
while (hole) {
|
|
732
|
-
hole.replaceWith(document.createTextNode(value));
|
|
733
|
-
hole = findComment(fragment, marker);
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
|
-
return fragment;
|
|
737
|
-
}
|
|
738
685
|
function createFrame(boundary, options) {
|
|
739
686
|
return new FrameImpl(boundary, null, null, options);
|
|
740
687
|
}
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
}
|
|
747
|
-
const FRAME = Symbol.for("dom-expressions.frame");
|
|
748
|
-
function createFrameInsertable(options) {
|
|
749
|
-
let frame = null;
|
|
750
|
-
let start = null;
|
|
751
|
-
let end = null;
|
|
688
|
+
const FRAME_TAG = "dx-frame";
|
|
689
|
+
const FRAME_ID_ATTR = "data-fid";
|
|
690
|
+
function createFrameElement(options) {
|
|
691
|
+
const el = makeFrameElement(options.id);
|
|
692
|
+
const frame = new FrameImpl(el, null, null, options);
|
|
752
693
|
return {
|
|
694
|
+
element: el,
|
|
753
695
|
get frame() {
|
|
754
696
|
return frame;
|
|
755
697
|
},
|
|
756
698
|
dispose() {
|
|
757
|
-
if (!frame) return;
|
|
758
699
|
frame.dispose();
|
|
759
|
-
|
|
760
|
-
const parent = start.parentNode;
|
|
761
|
-
if (!parent) return;
|
|
762
|
-
let n = start;
|
|
763
|
-
while (n) {
|
|
764
|
-
const next = n.nextSibling;
|
|
765
|
-
parent.removeChild(n);
|
|
766
|
-
if (n === end) break;
|
|
767
|
-
n = next;
|
|
768
|
-
}
|
|
769
|
-
},
|
|
770
|
-
[FRAME](parent, marker) {
|
|
771
|
-
if (frame) return;
|
|
772
|
-
start = document.createComment("frame:start");
|
|
773
|
-
end = document.createComment("frame:end");
|
|
774
|
-
parent.insertBefore(start, marker);
|
|
775
|
-
parent.insertBefore(end, marker);
|
|
776
|
-
frame = new FrameImpl(null, start, end, options);
|
|
700
|
+
el.remove();
|
|
777
701
|
}
|
|
778
702
|
};
|
|
779
703
|
}
|
|
704
|
+
function makeFrameElement(id) {
|
|
705
|
+
const el = document.createElement(FRAME_TAG);
|
|
706
|
+
el.style.display = "contents";
|
|
707
|
+
if (id !== undefined) el.setAttribute(FRAME_ID_ATTR, id);
|
|
708
|
+
return el;
|
|
709
|
+
}
|
|
710
|
+
function isFrameElement(node) {
|
|
711
|
+
return node.nodeType === ELEMENT_NODE && node.hasAttribute(FRAME_ID_ATTR);
|
|
712
|
+
}
|
|
780
713
|
function segmentName(key) {
|
|
781
714
|
const m = /^seg:([^:]+)$/.exec(key);
|
|
782
715
|
return m ? m[1] : null;
|
|
@@ -875,29 +808,25 @@ function collectSlots(root, out) {
|
|
|
875
808
|
n = afterRange(n, id);
|
|
876
809
|
continue;
|
|
877
810
|
}
|
|
878
|
-
|
|
879
|
-
if (regionId !== null) {
|
|
880
|
-
n = afterFrameRegion(n, regionId);
|
|
881
|
-
continue;
|
|
882
|
-
}
|
|
883
|
-
if (n.nodeType === ELEMENT_NODE) collectSlots(n, out);
|
|
811
|
+
if (n.nodeType === ELEMENT_NODE && !isFrameElement(n)) collectSlots(n, out);
|
|
884
812
|
n = n.nextSibling;
|
|
885
813
|
}
|
|
886
814
|
}
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
if (node
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
815
|
+
function collectRegionElements(node, regions) {
|
|
816
|
+
if (node.nodeType !== ELEMENT_NODE) return;
|
|
817
|
+
if (isFrameElement(node)) {
|
|
818
|
+
const childId = node.getAttribute(FRAME_ID_ATTR);
|
|
819
|
+
if (childId && !regions.has(childId)) {
|
|
820
|
+
regions.set(childId, {
|
|
821
|
+
childId,
|
|
822
|
+
element: node,
|
|
823
|
+
frame: undefined,
|
|
824
|
+
adopt: true
|
|
825
|
+
});
|
|
826
|
+
}
|
|
827
|
+
return;
|
|
899
828
|
}
|
|
900
|
-
|
|
829
|
+
for (let c = node.firstChild; c; c = c.nextSibling) collectRegionElements(c, regions);
|
|
901
830
|
}
|
|
902
831
|
function argsEquivalent(a, b) {
|
|
903
832
|
if (a === b) return true;
|
|
@@ -925,18 +854,6 @@ function rangeInterior(start, endData) {
|
|
|
925
854
|
}
|
|
926
855
|
return nodes;
|
|
927
856
|
}
|
|
928
|
-
function findComment(root, data) {
|
|
929
|
-
const children = root.childNodes;
|
|
930
|
-
for (let i = 0; i < children.length; i++) {
|
|
931
|
-
const node = children[i];
|
|
932
|
-
if (node.nodeType === COMMENT_NODE && node.data === data) return node;
|
|
933
|
-
if (node.nodeType === ELEMENT_NODE) {
|
|
934
|
-
const found = findComment(node, data);
|
|
935
|
-
if (found) return found;
|
|
936
|
-
}
|
|
937
|
-
}
|
|
938
|
-
return null;
|
|
939
|
-
}
|
|
940
857
|
function slotStartId(node) {
|
|
941
858
|
if (node.nodeType !== COMMENT_NODE) return null;
|
|
942
859
|
const m = SLOT_START.exec(node.data);
|
|
@@ -952,12 +869,18 @@ function compatible(a, b) {
|
|
|
952
869
|
if (a.nodeType === ELEMENT_NODE) return a.nodeName === b.nodeName;
|
|
953
870
|
return a.nodeType === TEXT_NODE || a.nodeType === COMMENT_NODE;
|
|
954
871
|
}
|
|
872
|
+
function preservesOpen(el) {
|
|
873
|
+
const t = el.tagName;
|
|
874
|
+
return t === "DETAILS" || t === "DIALOG";
|
|
875
|
+
}
|
|
955
876
|
function morphAttributes(oldEl, newEl, claim) {
|
|
956
877
|
let reclaim = false;
|
|
957
878
|
let changed = false;
|
|
879
|
+
const keepOpen = preservesOpen(oldEl);
|
|
958
880
|
const oldAttrs = oldEl.attributes;
|
|
959
881
|
for (let i = oldAttrs.length - 1; i >= 0; i--) {
|
|
960
882
|
const name = oldAttrs[i].name;
|
|
883
|
+
if (keepOpen && name === "open") continue;
|
|
961
884
|
if (!newEl.hasAttribute(name)) {
|
|
962
885
|
oldEl.removeAttribute(name);
|
|
963
886
|
changed = true;
|
|
@@ -967,6 +890,7 @@ function morphAttributes(oldEl, newEl, claim) {
|
|
|
967
890
|
const newAttrs = newEl.attributes;
|
|
968
891
|
for (let i = 0; i < newAttrs.length; i++) {
|
|
969
892
|
const attr = newAttrs[i];
|
|
893
|
+
if (keepOpen && attr.name === "open") continue;
|
|
970
894
|
if (oldEl.getAttribute(attr.name) !== attr.value) {
|
|
971
895
|
oldEl.setAttribute(attr.name, attr.value);
|
|
972
896
|
changed = true;
|
|
@@ -977,6 +901,7 @@ function morphAttributes(oldEl, newEl, claim) {
|
|
|
977
901
|
}
|
|
978
902
|
function morphNode(oldNode, newNode, claim) {
|
|
979
903
|
if (oldNode.nodeType === ELEMENT_NODE) {
|
|
904
|
+
if (oldNode.hasAttribute("data-preserve")) return;
|
|
980
905
|
morphAttributes(oldNode, newNode, claim);
|
|
981
906
|
reconcileChildren(oldNode, newNode, null, null, claim);
|
|
982
907
|
} else if (oldNode.data !== newNode.data) {
|
|
@@ -1161,15 +1086,15 @@ class ChunkReader {
|
|
|
1161
1086
|
}
|
|
1162
1087
|
}
|
|
1163
1088
|
async next() {
|
|
1164
|
-
|
|
1089
|
+
while (this.buffer.length < 12) {
|
|
1165
1090
|
if (this.done) {
|
|
1166
|
-
return {
|
|
1091
|
+
if (this.buffer.length === 0) return {
|
|
1167
1092
|
done: true,
|
|
1168
1093
|
value: undefined
|
|
1169
1094
|
};
|
|
1095
|
+
throw new Error("Malformed server function stream.");
|
|
1170
1096
|
}
|
|
1171
1097
|
await this.readChunk();
|
|
1172
|
-
return await this.next();
|
|
1173
1098
|
}
|
|
1174
1099
|
const head = new TextDecoder().decode(this.buffer.subarray(1, 11));
|
|
1175
1100
|
const bytes = Number.parseInt(head, 16);
|
|
@@ -1307,15 +1232,18 @@ function normalizeSlotContent(value) {
|
|
|
1307
1232
|
if (value == null || typeof value === "boolean") return document.createTextNode("");
|
|
1308
1233
|
return value instanceof Node ? value : document.createTextNode(String(value));
|
|
1309
1234
|
}
|
|
1235
|
+
function gatherClaims(el, registry) {
|
|
1236
|
+
if (el.hasAttribute("_hk")) registry.set(el.getAttribute("_hk"), el);
|
|
1237
|
+
if (el.hasAttribute(FRAME_ID_ATTR)) return;
|
|
1238
|
+
for (let c = el.firstElementChild; c; c = c.nextElementSibling) gatherClaims(c, registry);
|
|
1239
|
+
}
|
|
1310
1240
|
function claimRender(prefix, existing, render) {
|
|
1311
1241
|
const sc = sharedConfig;
|
|
1312
1242
|
if (!sc.getNextContextId) return render();
|
|
1313
1243
|
const registry = new Map();
|
|
1314
1244
|
for (const n of existing) {
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
if (el.hasAttribute("_hk")) registry.set(el.getAttribute("_hk"), el);
|
|
1318
|
-
el.querySelectorAll("*[_hk]").forEach(child => registry.set(child.getAttribute("_hk"), child));
|
|
1245
|
+
if (n.nodeType !== 1) continue;
|
|
1246
|
+
gatherClaims(n, registry);
|
|
1319
1247
|
}
|
|
1320
1248
|
if (!registry.size) return render();
|
|
1321
1249
|
const prevRegistry = sc.registry;
|
|
@@ -1357,50 +1285,80 @@ function slotsFor(props) {
|
|
|
1357
1285
|
}
|
|
1358
1286
|
});
|
|
1359
1287
|
}
|
|
1288
|
+
function revealSeam(owner) {
|
|
1289
|
+
return seam => runWithOwner(owner, () => insert(seam.before.parentNode, createLoadingBoundary(() => seam.content(), () => seam.fallback), seam.before));
|
|
1290
|
+
}
|
|
1360
1291
|
function boundaryComponent(host, id) {
|
|
1361
1292
|
return props => {
|
|
1362
1293
|
const owner = getOwner();
|
|
1363
|
-
const
|
|
1294
|
+
const {
|
|
1295
|
+
element,
|
|
1296
|
+
dispose
|
|
1297
|
+
} = createFrameElement({
|
|
1364
1298
|
host,
|
|
1365
1299
|
id,
|
|
1366
1300
|
slots: slotsFor(props),
|
|
1367
|
-
ownerScope: fn => runWithOwner(owner, fn)
|
|
1301
|
+
ownerScope: fn => runWithOwner(owner, fn),
|
|
1302
|
+
reveal: revealSeam(owner)
|
|
1368
1303
|
});
|
|
1369
|
-
onCleanup(
|
|
1370
|
-
return
|
|
1304
|
+
onCleanup(dispose);
|
|
1305
|
+
return element;
|
|
1371
1306
|
};
|
|
1372
1307
|
}
|
|
1373
1308
|
const claimedBoundaries = new Set();
|
|
1374
1309
|
let boundaryIndex = null;
|
|
1375
|
-
|
|
1310
|
+
const isBoundaryId = id => !id.includes(".");
|
|
1311
|
+
function indexBoundaries(root) {
|
|
1312
|
+
root.querySelectorAll(`[${FRAME_ID_ATTR}]`).forEach(el => {
|
|
1313
|
+
const key = el.getAttribute(FRAME_ID_ATTR);
|
|
1314
|
+
if (key && isBoundaryId(key) && !boundaryIndex.has(key)) boundaryIndex.set(key, el);
|
|
1315
|
+
});
|
|
1316
|
+
}
|
|
1317
|
+
function findBoundaryElement(id) {
|
|
1376
1318
|
if (!boundaryIndex) {
|
|
1377
1319
|
boundaryIndex = new Map();
|
|
1378
|
-
if (typeof document !== "undefined" && document.body)
|
|
1379
|
-
const walker = document.createTreeWalker(document.body, 128 );
|
|
1380
|
-
const opens = {};
|
|
1381
|
-
let c;
|
|
1382
|
-
while (c = walker.nextNode()) {
|
|
1383
|
-
const d = c.data;
|
|
1384
|
-
if (!d.startsWith("frame:")) continue;
|
|
1385
|
-
if (d.endsWith(":start")) {
|
|
1386
|
-
const key = d.slice(6, -6);
|
|
1387
|
-
if (key && !(key in opens)) opens[key] = c;
|
|
1388
|
-
} else if (d.endsWith(":end")) {
|
|
1389
|
-
const key = d.slice(6, -4);
|
|
1390
|
-
if (key && opens[key] && !boundaryIndex.has(key)) {
|
|
1391
|
-
boundaryIndex.set(key, [opens[key], c]);
|
|
1392
|
-
}
|
|
1393
|
-
}
|
|
1394
|
-
}
|
|
1395
|
-
}
|
|
1320
|
+
if (typeof document !== "undefined" && document.body) indexBoundaries(document.body);
|
|
1396
1321
|
}
|
|
1397
1322
|
return boundaryIndex.get(id);
|
|
1398
1323
|
}
|
|
1324
|
+
const boundaryWaiters = new Map();
|
|
1325
|
+
function documentStreaming() {
|
|
1326
|
+
const hy = globalThis._$HY;
|
|
1327
|
+
return !!hy && !hy.done;
|
|
1328
|
+
}
|
|
1329
|
+
function installRevealHook() {
|
|
1330
|
+
const hy = globalThis._$HY;
|
|
1331
|
+
if (!hy || hy.$sc) return;
|
|
1332
|
+
hy.$sc = true;
|
|
1333
|
+
const prev = hy.fe;
|
|
1334
|
+
hy.fe = (fragmentId, parent) => {
|
|
1335
|
+
if (prev) prev(fragmentId, parent);
|
|
1336
|
+
if (!boundaryIndex) return;
|
|
1337
|
+
const root = parent || (typeof document !== "undefined" ? document.body : null);
|
|
1338
|
+
if (!root) return;
|
|
1339
|
+
indexBoundaries(root);
|
|
1340
|
+
for (const [id, notify] of boundaryWaiters) {
|
|
1341
|
+
const el = boundaryIndex.get(id);
|
|
1342
|
+
if (!el) continue;
|
|
1343
|
+
boundaryWaiters.delete(id);
|
|
1344
|
+
notify(el);
|
|
1345
|
+
}
|
|
1346
|
+
};
|
|
1347
|
+
}
|
|
1399
1348
|
function documentBoundary(host, id, props) {
|
|
1400
|
-
const
|
|
1401
|
-
|
|
1349
|
+
const claimed = claimedBoundaries.has(id);
|
|
1350
|
+
const el = !claimed ? findBoundaryElement(id) : undefined;
|
|
1351
|
+
if (el) return adoptBoundary(host, id, el, props);
|
|
1352
|
+
if (!claimed && !boundaryWaiters.has(id) && documentStreaming()) {
|
|
1353
|
+
const owner = getOwner();
|
|
1354
|
+
const arrival = new Promise(resolve => boundaryWaiters.set(id, resolve));
|
|
1355
|
+
onCleanup(() => boundaryWaiters.delete(id));
|
|
1356
|
+
return createMemo(() => arrival.then(node => runWithOwner(owner, () => adoptBoundary(host, id, node, props))));
|
|
1357
|
+
}
|
|
1358
|
+
return boundaryComponent(host, id)(props);
|
|
1359
|
+
}
|
|
1360
|
+
function adoptBoundary(host, id, el, props) {
|
|
1402
1361
|
claimedBoundaries.add(id);
|
|
1403
|
-
const [start, end] = range;
|
|
1404
1362
|
const hy = globalThis._$HY;
|
|
1405
1363
|
if (hy && hy.r) {
|
|
1406
1364
|
const slotPrefix = `sc:slot:${id}:`;
|
|
@@ -1429,19 +1387,16 @@ function documentBoundary(host, id, props) {
|
|
|
1429
1387
|
}
|
|
1430
1388
|
}
|
|
1431
1389
|
const owner = getOwner();
|
|
1432
|
-
const frame =
|
|
1390
|
+
const frame = createFrame(el, {
|
|
1391
|
+
adopt: true,
|
|
1433
1392
|
host,
|
|
1434
1393
|
id,
|
|
1435
1394
|
slots: slotsFor(props),
|
|
1436
|
-
ownerScope: fn => runWithOwner(owner, fn)
|
|
1395
|
+
ownerScope: fn => runWithOwner(owner, fn),
|
|
1396
|
+
reveal: revealSeam(owner)
|
|
1437
1397
|
});
|
|
1438
1398
|
onCleanup(() => frame.dispose());
|
|
1439
|
-
|
|
1440
|
-
for (let n = start; n; n = n.nextSibling) {
|
|
1441
|
-
nodes.push(n);
|
|
1442
|
-
if (n === end) break;
|
|
1443
|
-
}
|
|
1444
|
-
return nodes;
|
|
1399
|
+
return el;
|
|
1445
1400
|
}
|
|
1446
1401
|
function installServerComponents(host = getFrameHost()) {
|
|
1447
1402
|
const g = globalThis;
|
|
@@ -1454,6 +1409,7 @@ function installServerComponents(host = getFrameHost()) {
|
|
|
1454
1409
|
};
|
|
1455
1410
|
}
|
|
1456
1411
|
g._$SC.impl = (id, props) => documentBoundary(host, id, props);
|
|
1412
|
+
installRevealHook();
|
|
1457
1413
|
configureServerFunctionsClient({
|
|
1458
1414
|
responseHandler: createServerComponentHandler({
|
|
1459
1415
|
host,
|
|
@@ -1464,11 +1420,11 @@ function installServerComponents(host = getFrameHost()) {
|
|
|
1464
1420
|
intercept: ({
|
|
1465
1421
|
id
|
|
1466
1422
|
}) => {
|
|
1467
|
-
if (claimedBoundaries.has(id) || !
|
|
1423
|
+
if (claimedBoundaries.has(id) || !findBoundaryElement(id)) return undefined;
|
|
1468
1424
|
return g._$SC.r(id);
|
|
1469
1425
|
}
|
|
1470
1426
|
})
|
|
1471
1427
|
});
|
|
1472
1428
|
}
|
|
1473
1429
|
|
|
1474
|
-
export { FRAME_APPLIED_EVENT, FRAME_STREAM_HEADER, applyFrameResponse, createFrame,
|
|
1430
|
+
export { FRAME_APPLIED_EVENT, FRAME_STREAM_HEADER, applyFrameResponse, createFrame, createFrameElement, createFrameHost, createJSONDataTable, createServerComponentHandler, getFrameHost, installServerComponents, isFrameStreamResponse };
|