what-core 0.6.0 → 0.6.2

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/render.js CHANGED
@@ -285,40 +285,47 @@ function scheduleMicrotask() {
285
285
  });
286
286
  }
287
287
  }
288
+ var isFlushing = false;
288
289
  function flush() {
289
- let iterations = 0;
290
- while (pendingEffects.length > 0 && iterations < 25) {
291
- const batch2 = pendingEffects;
292
- pendingEffects = [];
293
- if (batch2.length > 1 && pendingNeedSort) {
294
- batch2.sort((a, b) => a._level - b._level);
295
- }
296
- pendingNeedSort = false;
297
- for (let i = 0; i < batch2.length; i++) {
298
- const e = batch2[i];
299
- e._pending = false;
300
- if (!e.disposed && !e._onNotify) {
301
- const prevDepsLen = e.deps.length;
302
- _runEffect(e);
303
- if (!e._computed && e.deps.length !== prevDepsLen) {
304
- _updateLevel(e);
290
+ if (isFlushing) return;
291
+ isFlushing = true;
292
+ try {
293
+ let iterations = 0;
294
+ while (pendingEffects.length > 0 && iterations < 25) {
295
+ const batch2 = pendingEffects;
296
+ pendingEffects = [];
297
+ if (batch2.length > 1 && pendingNeedSort) {
298
+ batch2.sort((a, b) => a._level - b._level);
299
+ }
300
+ pendingNeedSort = false;
301
+ for (let i = 0; i < batch2.length; i++) {
302
+ const e = batch2[i];
303
+ e._pending = false;
304
+ if (!e.disposed && !e._onNotify) {
305
+ const prevDepsLen = e.deps.length;
306
+ _runEffect(e);
307
+ if (!e._computed && e.deps.length !== prevDepsLen) {
308
+ _updateLevel(e);
309
+ }
305
310
  }
306
311
  }
312
+ iterations++;
307
313
  }
308
- iterations++;
309
- }
310
- if (iterations >= 25) {
311
- if (__DEV__) {
312
- const remaining = pendingEffects.slice(0, 3);
313
- const effectNames = remaining.map((e) => e.fn?.name || e.fn?.toString().slice(0, 60) || "(anonymous)");
314
- console.warn(
315
- `[what] Possible infinite effect loop detected (25 iterations). Likely cause: an effect writes to a signal it also reads, creating a cycle. Use untrack() to read signals without subscribing. Looping effects: ${effectNames.join(", ")}`
316
- );
317
- } else {
318
- console.warn("[what] Possible infinite effect loop detected");
314
+ if (iterations >= 25) {
315
+ for (let i = 0; i < pendingEffects.length; i++) pendingEffects[i]._pending = false;
316
+ pendingEffects.length = 0;
317
+ if (__DEV__) {
318
+ const remaining = pendingEffects.slice(0, 3);
319
+ const effectNames = remaining.map((e) => e.fn?.name || e.fn?.toString().slice(0, 60) || "(anonymous)");
320
+ console.warn(
321
+ `[what] Possible infinite effect loop detected (25 iterations). Likely cause: an effect writes to a signal it also reads, creating a cycle. Use untrack() to read signals without subscribing. Looping effects: ${effectNames.join(", ")}`
322
+ );
323
+ } else {
324
+ console.warn("[what] Possible infinite effect loop detected");
325
+ }
319
326
  }
320
- for (let i = 0; i < pendingEffects.length; i++) pendingEffects[i]._pending = false;
321
- pendingEffects.length = 0;
327
+ } finally {
328
+ isFlushing = false;
322
329
  }
323
330
  }
324
331
  function untrack(fn) {
@@ -718,8 +725,8 @@ function createComponent(vnode, parent, isSvg) {
718
725
  function createErrorBoundary(vnode, parent) {
719
726
  const { errorState, handleError, fallback, reset } = vnode.props;
720
727
  const children = vnode.children;
721
- const wrapper = document.createElement("span");
722
- wrapper.style.display = "contents";
728
+ const startComment = document.createComment("eb:start");
729
+ const endComment = document.createComment("eb:end");
723
730
  const boundaryCtx = {
724
731
  hooks: [],
725
732
  hookIndex: 0,
@@ -728,15 +735,24 @@ function createErrorBoundary(vnode, parent) {
728
735
  mounted: false,
729
736
  disposed: false,
730
737
  _parentCtx: componentStack[componentStack.length - 1] || null,
731
- _errorBoundary: handleError
738
+ _errorBoundary: handleError,
739
+ _startComment: startComment,
740
+ _endComment: endComment
732
741
  };
733
- wrapper._componentCtx = boundaryCtx;
742
+ _commentCtxMap.set(startComment, boundaryCtx);
743
+ const container = document.createDocumentFragment();
744
+ container._componentCtx = boundaryCtx;
745
+ container.appendChild(startComment);
746
+ container.appendChild(endComment);
734
747
  const dispose = effect(() => {
735
748
  const error = errorState();
736
749
  componentStack.push(boundaryCtx);
737
- while (wrapper.firstChild) {
738
- disposeTree(wrapper.firstChild);
739
- wrapper.removeChild(wrapper.firstChild);
750
+ if (startComment.parentNode) {
751
+ while (startComment.nextSibling && startComment.nextSibling !== endComment) {
752
+ const old = startComment.nextSibling;
753
+ disposeTree(old);
754
+ old.parentNode.removeChild(old);
755
+ }
740
756
  }
741
757
  let vnodes;
742
758
  if (error) {
@@ -746,19 +762,25 @@ function createErrorBoundary(vnode, parent) {
746
762
  }
747
763
  vnodes = Array.isArray(vnodes) ? vnodes : [vnodes];
748
764
  for (const v of vnodes) {
749
- const node = createDOM(v, wrapper);
750
- if (node) wrapper.appendChild(node);
765
+ const node = createDOM(v, parent);
766
+ if (node) {
767
+ if (endComment.parentNode) {
768
+ endComment.parentNode.insertBefore(node, endComment);
769
+ } else {
770
+ container.insertBefore(node, endComment);
771
+ }
772
+ }
751
773
  }
752
774
  componentStack.pop();
753
775
  });
754
776
  boundaryCtx.effects.push(dispose);
755
- return wrapper;
777
+ return container;
756
778
  }
757
779
  function createSuspenseBoundary(vnode, parent) {
758
780
  const { boundary, fallback, loading } = vnode.props;
759
781
  const children = vnode.children;
760
- const wrapper = document.createElement("span");
761
- wrapper.style.display = "contents";
782
+ const startComment = document.createComment("sb:start");
783
+ const endComment = document.createComment("sb:end");
762
784
  const boundaryCtx = {
763
785
  hooks: [],
764
786
  hookIndex: 0,
@@ -766,26 +788,41 @@ function createSuspenseBoundary(vnode, parent) {
766
788
  cleanups: [],
767
789
  mounted: false,
768
790
  disposed: false,
769
- _parentCtx: componentStack[componentStack.length - 1] || null
791
+ _parentCtx: componentStack[componentStack.length - 1] || null,
792
+ _startComment: startComment,
793
+ _endComment: endComment
770
794
  };
771
- wrapper._componentCtx = boundaryCtx;
795
+ _commentCtxMap.set(startComment, boundaryCtx);
796
+ const container = document.createDocumentFragment();
797
+ container._componentCtx = boundaryCtx;
798
+ container.appendChild(startComment);
799
+ container.appendChild(endComment);
772
800
  const dispose = effect(() => {
773
801
  const isLoading = loading();
774
802
  const vnodes = isLoading ? [fallback] : children;
775
803
  const normalized = Array.isArray(vnodes) ? vnodes : [vnodes];
776
804
  componentStack.push(boundaryCtx);
777
- while (wrapper.firstChild) {
778
- disposeTree(wrapper.firstChild);
779
- wrapper.removeChild(wrapper.firstChild);
805
+ if (startComment.parentNode) {
806
+ while (startComment.nextSibling && startComment.nextSibling !== endComment) {
807
+ const old = startComment.nextSibling;
808
+ disposeTree(old);
809
+ old.parentNode.removeChild(old);
810
+ }
780
811
  }
781
812
  for (const v of normalized) {
782
- const node = createDOM(v, wrapper);
783
- if (node) wrapper.appendChild(node);
813
+ const node = createDOM(v, parent);
814
+ if (node) {
815
+ if (endComment.parentNode) {
816
+ endComment.parentNode.insertBefore(node, endComment);
817
+ } else {
818
+ container.insertBefore(node, endComment);
819
+ }
820
+ }
784
821
  }
785
822
  componentStack.pop();
786
823
  });
787
824
  boundaryCtx.effects.push(dispose);
788
- return wrapper;
825
+ return container;
789
826
  }
790
827
  function createPortalDOM(vnode, parent) {
791
828
  const { container } = vnode.props;
@@ -1135,6 +1172,12 @@ function sameNodeArray(a, b) {
1135
1172
  return true;
1136
1173
  }
1137
1174
  function reconcileInsert(parent, value, current, marker) {
1175
+ if (!parent || typeof parent.insertBefore !== "function") {
1176
+ if (__DEV__) {
1177
+ console.warn("[what] reconcileInsert called with invalid parent:", parent);
1178
+ }
1179
+ return current;
1180
+ }
1138
1181
  const targetMarker = marker || null;
1139
1182
  if (value == null || typeof value === "boolean") {
1140
1183
  const oldNodes2 = asNodeArray(current);
@@ -1648,6 +1691,12 @@ function spread(el, props) {
1648
1691
  }
1649
1692
  }
1650
1693
  function setProp2(el, key, value) {
1694
+ if (key === "ref") {
1695
+ if (typeof value === "function") value(el);
1696
+ else if (value && typeof value === "object") value.current = el;
1697
+ return;
1698
+ }
1699
+ if (key === "key") return;
1651
1700
  if (URL_ATTRS.has(key) || URL_ATTRS.has(key.toLowerCase())) {
1652
1701
  if (!isSafeUrl(value)) {
1653
1702
  if (typeof console !== "undefined") {