@solidjs/web 2.0.0-beta.15 → 2.0.0-beta.17

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/web.cjs CHANGED
@@ -60,9 +60,9 @@ const syncOptions = {
60
60
  sync: true
61
61
  };
62
62
  const effect = (fn, effectFn, options) => solidJs.createRenderEffect(fn, effectFn, options ? {
63
- transparent: true,
64
63
  sync: true,
65
- ...options
64
+ ...options,
65
+ transparent: !options.scope
66
66
  } : transparentOptions);
67
67
  const memo = fn => solidJs.createMemo(() => fn(), syncOptions);
68
68
 
@@ -330,20 +330,41 @@ function addEvent(node, name, handler, delegate) {
330
330
  }
331
331
  function style(node, value, prev) {
332
332
  if (!value) {
333
- if (prev) setAttribute(node, "style");
333
+ if (prev || node._$styles) {
334
+ setAttribute(node, "style");
335
+ node._$styles = undefined;
336
+ }
334
337
  return;
335
338
  }
336
339
  const nodeStyle = node.style;
337
- if (typeof value === "string") return nodeStyle.cssText = value;
338
- typeof prev === "string" && (nodeStyle.cssText = prev = undefined);
339
- prev || (prev = {});
340
+ if (typeof value === "string") {
341
+ node._$styles = undefined;
342
+ return nodeStyle.cssText = value;
343
+ }
344
+ if (typeof prev === "string") {
345
+ nodeStyle.cssText = "";
346
+ prev = undefined;
347
+ }
348
+ let applied = node._$styles;
349
+ if (!applied) {
350
+ applied = node._$styles = prev ? {
351
+ ...prev
352
+ } : {};
353
+ }
340
354
  let v, s;
355
+ for (s in applied) {
356
+ if (value[s] == null) {
357
+ nodeStyle.removeProperty(s);
358
+ delete applied[s];
359
+ }
360
+ }
341
361
  for (s in value) {
342
362
  v = value[s];
343
- if (v !== prev[s]) nodeStyle.setProperty(s, v);
344
- delete prev[s];
363
+ if (v != null && v !== applied[s]) {
364
+ nodeStyle.setProperty(s, v);
365
+ applied[s] = v;
366
+ }
345
367
  }
346
- for (s in prev) value[s] == null && nodeStyle.removeProperty(s);
347
368
  }
348
369
  function setStyleProperty(node, name, value) {
349
370
  value != null ? node.style.setProperty(name, value) : node.style.removeProperty(name);
@@ -382,19 +403,28 @@ function ref(fn, element) {
382
403
  const resolved = solidJs.untrack(fn);
383
404
  solidJs.runWithOwner(null, () => applyRef(resolved, element));
384
405
  }
406
+ function scope(fn) {
407
+ fn.$s = true;
408
+ return fn;
409
+ }
410
+ const SCOPE_OPTIONS = {
411
+ scope: true
412
+ };
413
+ function stripTextSeparators(nodes) {
414
+ let j = 0;
415
+ for (let i = 0; i < nodes.length; i++) {
416
+ if (nodes[i].nodeType === 8 && nodes[i].nodeValue === "!$") nodes[i].remove();else nodes[j++] = nodes[i];
417
+ }
418
+ nodes.length = j;
419
+ return nodes;
420
+ }
385
421
  function insert(parent, accessor, marker, initial, options) {
386
422
  const multi = marker !== undefined;
387
423
  const host = options && options.host;
388
424
  if (multi && !initial) initial = [];
389
425
  if (isHydrating(parent)) {
390
426
  if (!multi && initial === undefined && parent) initial = [...parent.childNodes];
391
- if (Array.isArray(initial)) {
392
- let j = 0;
393
- for (let i = 0; i < initial.length; i++) {
394
- if (initial[i].nodeType === 8 && initial[i].nodeValue === "!$") initial[i].remove();else initial[j++] = initial[i];
395
- }
396
- initial.length = j;
397
- }
427
+ if (Array.isArray(initial)) stripTextSeparators(initial);
398
428
  }
399
429
  if (typeof accessor !== "function") {
400
430
  accessor = normalize(accessor, initial, multi, true);
@@ -410,10 +440,34 @@ function insert(parent, accessor, marker, initial, options) {
410
440
  initial = [placeholder];
411
441
  }
412
442
  let current = initial;
443
+ function reclaimSwappedRegion() {
444
+ if (!solidJs.sharedConfig.hydrating || !current || !parent.isConnected) return;
445
+ const first = Array.isArray(current) ? current[0] : current;
446
+ if (!first || !first.nodeType || first.isConnected) return;
447
+ let nodes;
448
+ if (marker) {
449
+ nodes = [];
450
+ let node = marker.previousSibling,
451
+ depth = 0;
452
+ while (node) {
453
+ if (node.nodeType === 8) {
454
+ const v = node.nodeValue;
455
+ if (v === "/") depth++;else if (v === "$") {
456
+ if (depth === 0) break;
457
+ depth--;
458
+ }
459
+ }
460
+ nodes.unshift(node);
461
+ node = node.previousSibling;
462
+ }
463
+ } else nodes = [...parent.childNodes];
464
+ current = stripTextSeparators(nodes);
465
+ }
413
466
  effect(prev => {
467
+ reclaimSwappedRegion();
414
468
  const value = normalize(accessor(), current, multi, true);
415
469
  if (typeof value !== "function") return value;
416
- effect(() => normalize(value, current, multi), inner => {
470
+ effect(() => (reclaimSwappedRegion(), normalize(value, current, multi)), inner => {
417
471
  insertExpression(parent, inner, current, marker);
418
472
  current = inner;
419
473
  host && tagHost(current, host);
@@ -427,7 +481,11 @@ function insert(parent, accessor, marker, initial, options) {
427
481
  insertExpression(parent, value, current, marker);
428
482
  current = value;
429
483
  host && tagHost(current, host);
430
- }, options);
484
+ },
485
+ accessor.$s ? options ? {
486
+ ...options,
487
+ scope: true
488
+ } : SCOPE_OPTIONS : options);
431
489
  }
432
490
  function assign(node, props, skipChildren, prevProps = {}, skipRef = false) {
433
491
  const nodeName = node.nodeName;
@@ -446,19 +504,117 @@ function assign(node, props, skipChildren, prevProps = {}, skipRef = false) {
446
504
  prevProps[prop] = assignProp(node, prop, props[prop], prevProps[prop], skipRef, nodeName);
447
505
  }
448
506
  }
507
+ const ASSET_REMOVAL_GRACE = 100;
508
+ const assetRegistry = new Map();
509
+ function assetEntryKey(descriptor) {
510
+ if (descriptor.policy === "exclusive") return "x|" + descriptor.key;
511
+ return descriptor.type === "inline-style" ? "i|" + descriptor.id : descriptor.type + "|" + descriptor.href;
512
+ }
513
+ function findAssetElement(selector, attr, value) {
514
+ const nodes = document.querySelectorAll(selector);
515
+ for (let i = 0; i < nodes.length; i++) {
516
+ if (nodes[i].getAttribute(attr) === value) return nodes[i];
517
+ }
518
+ return null;
519
+ }
520
+ function mountAssetElement(descriptor) {
521
+ let el;
522
+ if (descriptor.type === "inline-style") {
523
+ el = findAssetElement("style[data-asset]", "data-asset", descriptor.id);
524
+ if (!el) {
525
+ el = document.createElement("style");
526
+ el.setAttribute("data-asset", descriptor.id);
527
+ el.textContent = descriptor.content || "";
528
+ }
529
+ } else {
530
+ const rel = descriptor.type === "module" ? "modulepreload" : "stylesheet";
531
+ el = findAssetElement(`link[rel="${rel}"]`, "href", descriptor.href);
532
+ if (!el) {
533
+ el = document.createElement("link");
534
+ el.rel = rel;
535
+ el.href = descriptor.href;
536
+ }
537
+ }
538
+ if (descriptor.attrs) {
539
+ for (const name in descriptor.attrs) el.setAttribute(name, descriptor.attrs[name]);
540
+ }
541
+ if (!el.isConnected) document.head.appendChild(el);
542
+ return el;
543
+ }
544
+ function acquireAsset(descriptor) {
545
+ const key = assetEntryKey(descriptor);
546
+ let entry = assetRegistry.get(key);
547
+ if (descriptor.policy === "exclusive") {
548
+ if (!entry) {
549
+ entry = {
550
+ original: descriptor.get(),
551
+ set: descriptor.set,
552
+ writers: []
553
+ };
554
+ assetRegistry.set(key, entry);
555
+ }
556
+ const writer = {
557
+ value: descriptor.value
558
+ };
559
+ entry.writers.push(writer);
560
+ entry.set(writer.value);
561
+ let released = false;
562
+ return () => {
563
+ if (released) return;
564
+ released = true;
565
+ const index = entry.writers.indexOf(writer);
566
+ const wasTop = index === entry.writers.length - 1;
567
+ entry.writers.splice(index, 1);
568
+ if (!wasTop) return;
569
+ if (entry.writers.length) {
570
+ entry.set(entry.writers[entry.writers.length - 1].value);
571
+ } else {
572
+ entry.set(entry.original);
573
+ assetRegistry.delete(key);
574
+ }
575
+ };
576
+ }
577
+ if (!entry) {
578
+ entry = {
579
+ count: 0,
580
+ element: null,
581
+ timer: null
582
+ };
583
+ assetRegistry.set(key, entry);
584
+ }
585
+ if (entry.timer) {
586
+ clearTimeout(entry.timer);
587
+ entry.timer = null;
588
+ }
589
+ entry.count++;
590
+ if (!entry.element || !entry.element.isConnected) entry.element = mountAssetElement(descriptor);
591
+ let released = false;
592
+ return () => {
593
+ if (released) return;
594
+ released = true;
595
+ if (--entry.count > 0) return;
596
+ entry.timer = setTimeout(() => {
597
+ assetRegistry.delete(key);
598
+ entry.element && entry.element.remove();
599
+ }, ASSET_REMOVAL_GRACE);
600
+ };
601
+ }
449
602
  function loadModuleAssets(mapping) {
450
603
  const hy = globalThis._$HY;
451
604
  if (!hy) return;
452
605
  const pending = [];
453
- for (const moduleUrl in mapping) {
454
- if (hy.modules[moduleUrl]) continue;
455
- const entryUrl = mapping[moduleUrl];
456
- if (!hy.loading[moduleUrl]) {
457
- hy.loading[moduleUrl] = import(entryUrl).then(mod => {
458
- hy.modules[moduleUrl] = mod;
606
+ for (const key in mapping) {
607
+ if (hy.modules[key]) continue;
608
+ const entryUrl = mapping[key];
609
+ if (!hy.loading[key]) {
610
+ hy.loading[key] = import(entryUrl).then(mod => {
611
+ hy.modules[key] = mod;
612
+ }, err => {
613
+ delete hy.loading[key];
614
+ throw err;
459
615
  });
460
616
  }
461
- pending.push(hy.loading[moduleUrl]);
617
+ pending.push(hy.loading[key]);
462
618
  }
463
619
  return pending.length ? Promise.all(pending).then(() => {}) : undefined;
464
620
  }
@@ -503,8 +659,11 @@ function hydrate$1(code, element, options = {}) {
503
659
  } finally {
504
660
  solidJs.sharedConfig.hydrating = false;
505
661
  }
506
- }, () => {
662
+ }, err => {
663
+ console.error("Hydration module preload failed, falling back to client render:", err);
507
664
  solidJs.sharedConfig.hydrating = false;
665
+ solidJs.sharedConfig.registry = undefined;
666
+ disposer = render$1(code, element, [...element.childNodes], options);
508
667
  });
509
668
  return () => disposer && disposer();
510
669
  }
@@ -574,17 +733,32 @@ function runHydrationEvents() {
574
733
  const [el, e] = events[0];
575
734
  if (!completed.has(el)) return;
576
735
  events.shift();
577
- let match;
736
+ let matchContainer, matchState, matchDistance, matches;
578
737
  for (const [container, state] of delegatedContainers) {
579
738
  if (!state.handlers.has(e.type)) continue;
580
739
  const entry = findOwner(e.target, state);
581
- if (entry && (!match || entry.distance < match.distance)) match = {
582
- container,
583
- state,
584
- distance: entry.distance
585
- };
740
+ if (!entry) continue;
741
+ if (matchContainer) {
742
+ if (!matches) matches = [{
743
+ container: matchContainer,
744
+ state: matchState,
745
+ distance: matchDistance
746
+ }];
747
+ matches.push({
748
+ container,
749
+ state,
750
+ distance: entry.distance
751
+ });
752
+ } else {
753
+ matchContainer = container;
754
+ matchState = state;
755
+ matchDistance = entry.distance;
756
+ }
586
757
  }
587
- if (match) eventHandler(e, match.container, match.state);
758
+ if (matches) {
759
+ matches.sort((a, b) => a.distance - b.distance);
760
+ for (let i = 0; i < matches.length; i++) eventHandler(e, matches[i].container, matches[i].state);
761
+ } else if (matchContainer) eventHandler(e, matchContainer, matchState);
588
762
  }
589
763
  if (solidJs.sharedConfig.done) {
590
764
  solidJs.sharedConfig.events = _$HY.events = null;
@@ -655,11 +829,16 @@ function eventHandler(e, container, state) {
655
829
  if (solidJs.sharedConfig.registry && solidJs.sharedConfig.events) {
656
830
  if (solidJs.sharedConfig.events.find(([el, ev]) => ev === e)) return;
657
831
  }
658
- if (e[$$EVENT_OWNER]) return;
832
+ const prev = e[$$EVENT_OWNER];
833
+ let resumeNode;
834
+ if (prev) {
835
+ if (prev === true || prev === container || !container.contains(prev)) return;
836
+ resumeNode = prev;
837
+ }
659
838
  const owner = state && (state.owners.size === 1 && state.owners.has(container) ? container : findOwner(e.target, state)?.owner);
660
839
  if (state && !owner) return;
661
840
  e[$$EVENT_OWNER] = owner || true;
662
- let node = e.target;
841
+ let node = resumeNode || e.target;
663
842
  const key = `$$${e.type}`;
664
843
  const oriTarget = e.target;
665
844
  const boundary = owner || container || e.currentTarget;
@@ -689,7 +868,10 @@ function eventHandler(e, container, state) {
689
868
  return node || boundary || document;
690
869
  }
691
870
  });
692
- if (e.composedPath) {
871
+ if (resumeNode) {
872
+ if (resumeNode === e.target) node = resumeNode._$host || resumeNode.parentNode || resumeNode.host;
873
+ if (node && node !== boundary) walkUpTree();
874
+ } else if (e.composedPath) {
693
875
  const path = e.composedPath();
694
876
  if (path.length) {
695
877
  retarget(path[0]);
@@ -719,7 +901,13 @@ function insertExpression(parent, value, current, marker) {
719
901
  const tc = typeof current;
720
902
  if (tc === "string" || tc === "number") {
721
903
  parent.firstChild.data = value;
722
- } else parent.textContent = value;
904
+ } else {
905
+ const owned = ownedChildCount(current);
906
+ if (owned === -1 || owned === parent.childNodes.length) parent.textContent = value;else {
907
+ removeOwnedChildren(parent, current);
908
+ parent.insertBefore(document.createTextNode(value), parent.firstChild);
909
+ }
910
+ }
723
911
  } else if (value === undefined) {
724
912
  cleanChildren(parent, current, marker);
725
913
  } else if (value.nodeType) {
@@ -742,7 +930,7 @@ function insertExpression(parent, value, current, marker) {
742
930
  appendNodes(parent, value, marker);
743
931
  } else reconcileArrays(parent, current, value, marker);
744
932
  } else {
745
- current && cleanChildren(parent);
933
+ current && cleanChildren(parent, current);
746
934
  appendNodes(parent, value);
747
935
  }
748
936
  } else ;
@@ -782,8 +970,31 @@ function appendNodes(parent, array, marker = null) {
782
970
  if (marker) n[$$SLOT] = marker;
783
971
  }
784
972
  }
973
+ function ownedChildCount(current) {
974
+ if (Array.isArray(current)) return current.length;
975
+ if (current == null) return -1;
976
+ if (current === "") return 0;
977
+ return 1;
978
+ }
979
+ function removeOwnedChildren(parent, current) {
980
+ if (Array.isArray(current)) {
981
+ for (let i = 0; i < current.length; i++) {
982
+ const el = current[i];
983
+ if (el.parentNode === parent) el.remove();
984
+ }
985
+ } else if (current.nodeType) {
986
+ if (current.parentNode === parent) current.remove();
987
+ } else {
988
+ const first = parent.firstChild;
989
+ if (first && first.nodeType === 3) first.remove();
990
+ }
991
+ }
785
992
  function cleanChildren(parent, current, marker, replacement) {
786
- if (marker === undefined) return parent.textContent = "";
993
+ if (marker === undefined) {
994
+ const owned = ownedChildCount(current);
995
+ if (owned === -1 || owned === parent.childNodes.length) return parent.textContent = "";
996
+ return removeOwnedChildren(parent, current);
997
+ }
787
998
  if (current.length) {
788
999
  let inserted = false;
789
1000
  for (let i = current.length - 1; i >= 0; i--) {
@@ -872,9 +1083,10 @@ function Portal(props) {
872
1083
  return () => {
873
1084
  dispose();
874
1085
  let c = startMarker;
875
- while (c && c !== endMarker) {
1086
+ while (c) {
876
1087
  const n = c.nextSibling;
877
1088
  m.removeChild(c);
1089
+ if (c === endMarker) break;
878
1090
  c = n;
879
1091
  }
880
1092
  };
@@ -984,6 +1196,7 @@ exports.RawTextElements = RawTextElements;
984
1196
  exports.RequestContext = RequestContext;
985
1197
  exports.SVGElements = SVGElements;
986
1198
  exports.VoidElements = VoidElements;
1199
+ exports.acquireAsset = acquireAsset;
987
1200
  exports.addEvent = addEvent;
988
1201
  exports.applyRef = applyRef;
989
1202
  exports.assign = assign;
@@ -1018,6 +1231,7 @@ exports.renderToString = renderToString;
1018
1231
  exports.renderToStringAsync = renderToStringAsync;
1019
1232
  exports.resolveSSRNode = resolveSSRNode;
1020
1233
  exports.runHydrationEvents = runHydrationEvents;
1234
+ exports.scope = scope;
1021
1235
  exports.setAttribute = setAttribute;
1022
1236
  exports.setAttributeNS = setAttributeNS;
1023
1237
  exports.setProperty = setProperty;