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