sibujs 3.4.0 → 4.0.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.
Files changed (98) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +118 -15
  3. package/dist/browser.cjs +410 -101
  4. package/dist/browser.d.cts +50 -5
  5. package/dist/browser.d.ts +50 -5
  6. package/dist/browser.js +8 -6
  7. package/dist/build.cjs +777 -385
  8. package/dist/build.js +15 -15
  9. package/dist/cdn.global.js +11 -7
  10. package/dist/{chunk-JCO7AHNU.js → chunk-3EKJK5FZ.js} +73 -34
  11. package/dist/chunk-4MFZMLUU.js +147 -0
  12. package/dist/chunk-52XFPGSN.js +123 -0
  13. package/dist/chunk-5INI7D2L.js +194 -0
  14. package/dist/{chunk-OAVXAFAY.js → chunk-6LG2T7LO.js} +5 -5
  15. package/dist/{chunk-OOUQUCNN.js → chunk-ACBT6UZS.js} +57 -22
  16. package/dist/{chunk-F7HW2NI5.js → chunk-AW6HPJ3L.js} +1 -1
  17. package/dist/chunk-DHDZ7IVN.js +109 -0
  18. package/dist/{chunk-JNGGM2XE.js → chunk-DQVUBVNX.js} +16 -25
  19. package/dist/{chunk-AXFWGY32.js → chunk-DR7H6UGM.js} +232 -67
  20. package/dist/{chunk-WSGLJYFI.js → chunk-E62UADKL.js} +9 -3
  21. package/dist/{chunk-3Z2NGWQI.js → chunk-ES2GERY2.js} +1 -1
  22. package/dist/{chunk-S3V6ZXPI.js → chunk-EWEE7NBF.js} +115 -41
  23. package/dist/{chunk-3DVGCW7O.js → chunk-F64ZPCFE.js} +8 -8
  24. package/dist/{chunk-APFRCIRI.js → chunk-GCSGGA3Q.js} +295 -198
  25. package/dist/{chunk-EX77FXTT.js → chunk-HYCCIYNS.js} +228 -51
  26. package/dist/{chunk-ELXMRSVN.js → chunk-NF3LYCQH.js} +259 -124
  27. package/dist/chunk-O3QQ3XOL.js +61 -0
  28. package/dist/{chunk-BUKYCWHX.js → chunk-PBQEW5VW.js} +14 -10
  29. package/dist/{chunk-H5FI5WDP.js → chunk-RRIDJQ5C.js} +3 -3
  30. package/dist/{chunk-S3NFJO6L.js → chunk-TIRZCERI.js} +36 -5
  31. package/dist/{chunk-ODXVQ3CS.js → chunk-VFHIVEPF.js} +309 -188
  32. package/dist/chunk-VPP2FONR.js +142 -0
  33. package/dist/{chunk-KZBEVFXZ.js → chunk-W55YHPEP.js} +5 -3
  34. package/dist/{chunk-FKQG7FTY.js → chunk-WN6WDFCB.js} +4 -4
  35. package/dist/{chunk-CEBWDD63.js → chunk-WOOMUJFT.js} +228 -86
  36. package/dist/{chunk-ITWCTZYH.js → chunk-Z2CE42DB.js} +19 -25
  37. package/dist/{contracts-ey_Qh8ef.d.cts → contracts-Hg6ITAEF.d.cts} +6 -6
  38. package/dist/{contracts-ey_Qh8ef.d.ts → contracts-Hg6ITAEF.d.ts} +6 -6
  39. package/dist/{customElement-CPfIrbvg.d.ts → customElement-CKLoO63w.d.cts} +73 -11
  40. package/dist/{customElement-CPfIrbvg.d.cts → customElement-CKLoO63w.d.ts} +73 -11
  41. package/dist/data.cjs +483 -205
  42. package/dist/data.d.cts +139 -7
  43. package/dist/data.d.ts +139 -7
  44. package/dist/data.js +9 -9
  45. package/dist/devtools.cjs +222 -87
  46. package/dist/devtools.js +8 -8
  47. package/dist/dispose-4FZ6OFXR.js +19 -0
  48. package/dist/ecosystem.cjs +419 -175
  49. package/dist/ecosystem.js +11 -11
  50. package/dist/extras.cjs +1981 -765
  51. package/dist/extras.d.cts +7 -7
  52. package/dist/extras.d.ts +7 -7
  53. package/dist/extras.js +29 -26
  54. package/dist/index.cjs +784 -385
  55. package/dist/index.d.cts +299 -28
  56. package/dist/index.d.ts +299 -28
  57. package/dist/index.js +33 -18
  58. package/dist/motion.cjs +180 -50
  59. package/dist/motion.d.cts +26 -0
  60. package/dist/motion.d.ts +26 -0
  61. package/dist/motion.js +5 -5
  62. package/dist/patterns.cjs +437 -170
  63. package/dist/patterns.d.cts +60 -13
  64. package/dist/patterns.d.ts +60 -13
  65. package/dist/patterns.js +7 -7
  66. package/dist/performance.cjs +333 -148
  67. package/dist/performance.d.cts +55 -7
  68. package/dist/performance.d.ts +55 -7
  69. package/dist/performance.js +9 -9
  70. package/dist/plugins.cjs +1374 -576
  71. package/dist/plugins.d.cts +227 -9
  72. package/dist/plugins.d.ts +227 -9
  73. package/dist/plugins.js +613 -321
  74. package/dist/{ssr-D62yFwuw.d.cts → ssr-BiPRdZ6n.d.cts} +44 -15
  75. package/dist/{ssr-D62yFwuw.d.ts → ssr-BiPRdZ6n.d.ts} +44 -15
  76. package/dist/{ssr-2PPULEK2.js → ssr-JFP5535P.js} +5 -4
  77. package/dist/ssr.cjs +1104 -443
  78. package/dist/ssr.d.cts +230 -20
  79. package/dist/ssr.d.ts +230 -20
  80. package/dist/ssr.js +15 -12
  81. package/dist/{startup-0Qv6aosO.d.cts → startup-BMpaiMhP.d.cts} +1 -1
  82. package/dist/{startup-0Qv6aosO.d.ts → startup-BMpaiMhP.d.ts} +1 -1
  83. package/dist/testing.cjs +205 -63
  84. package/dist/testing.d.cts +1 -1
  85. package/dist/testing.d.ts +1 -1
  86. package/dist/testing.js +8 -10
  87. package/dist/ui.cjs +640 -199
  88. package/dist/ui.d.cts +2 -2
  89. package/dist/ui.d.ts +2 -2
  90. package/dist/ui.js +10 -10
  91. package/dist/widgets.cjs +207 -82
  92. package/dist/widgets.js +9 -9
  93. package/package.json +12 -7
  94. package/dist/chunk-5VGSK6D2.js +0 -80
  95. package/dist/chunk-COY6PUD2.js +0 -34
  96. package/dist/chunk-K35BAR4P.js +0 -96
  97. package/dist/chunk-L3GAGWCC.js +0 -111
  98. package/dist/chunk-RT3IYFN2.js +0 -38
package/dist/motion.cjs CHANGED
@@ -61,6 +61,94 @@ function devWarn(message) {
61
61
  }
62
62
  }
63
63
 
64
+ // src/core/errors.ts
65
+ var ERROR_STATE_KEY = /* @__PURE__ */ Symbol.for("sibujs.runtime-errors.v1");
66
+ function state() {
67
+ const g = globalThis;
68
+ const existing = g[ERROR_STATE_KEY];
69
+ if (existing) return existing;
70
+ const created = { handler: null, handlerDepth: 0 };
71
+ g[ERROR_STATE_KEY] = created;
72
+ return created;
73
+ }
74
+ function normalizeError(value) {
75
+ if (value instanceof Error) return value;
76
+ const message = typeof value === "string" ? value : `Non-Error value thrown: ${safeStringify(value)}`;
77
+ return new Error(message, { cause: value });
78
+ }
79
+ function safeStringify(value) {
80
+ if (typeof value === "symbol") return value.toString();
81
+ try {
82
+ return typeof value === "object" && value !== null ? JSON.stringify(value) : String(value);
83
+ } catch {
84
+ return Object.prototype.toString.call(value);
85
+ }
86
+ }
87
+ function describe(context) {
88
+ return context.name ? `${context.phase} "${context.name}"` : context.phase;
89
+ }
90
+ var REACTIVE_REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
91
+ function untrackedRun(fn) {
92
+ const api = globalThis[REACTIVE_REGISTRY_KEY];
93
+ return api?.untracked ? api.untracked(fn) : fn();
94
+ }
95
+ var PROPAGATE_EVENT = "sibu:error-propagate";
96
+ function claimedByBoundary(error, context) {
97
+ const raw = context.node;
98
+ if (!raw || typeof CustomEvent === "undefined") return false;
99
+ const target = resolveEventTarget(raw);
100
+ if (!target) return false;
101
+ try {
102
+ const event = new CustomEvent(PROPAGATE_EVENT, {
103
+ bubbles: true,
104
+ cancelable: true,
105
+ detail: { error, context }
106
+ });
107
+ return target.dispatchEvent(event) === false;
108
+ } catch {
109
+ return false;
110
+ }
111
+ }
112
+ function resolveEventTarget(node) {
113
+ const ELEMENT_NODE = 1;
114
+ let current = node;
115
+ while (current) {
116
+ if (current.nodeType === ELEMENT_NODE && typeof current.dispatchEvent === "function") {
117
+ return current;
118
+ }
119
+ current = current.parentNode;
120
+ }
121
+ const self = node;
122
+ return typeof self.dispatchEvent === "function" ? self : null;
123
+ }
124
+ function defaultReport(error, context) {
125
+ if (typeof console === "undefined") return;
126
+ console.error(`[SibuJS] Uncaught error during ${describe(context)}: ${error.message}`, error);
127
+ }
128
+ function reportError(error, context) {
129
+ const err = normalizeError(error);
130
+ untrackedRun(() => {
131
+ if (claimedByBoundary(err, context)) return;
132
+ const s = state();
133
+ const handler = s.handler;
134
+ if (handler && s.handlerDepth === 0) {
135
+ s.handlerDepth++;
136
+ try {
137
+ handler(error instanceof Error ? error : err, context);
138
+ return;
139
+ } catch (handlerError) {
140
+ if (typeof console !== "undefined") {
141
+ const detail = handlerError instanceof Error ? handlerError.message : String(handlerError);
142
+ console.error(`[SibuJS] runtime error handler itself threw: ${detail}`, handlerError);
143
+ }
144
+ } finally {
145
+ s.handlerDepth--;
146
+ }
147
+ }
148
+ defaultReport(err, context);
149
+ });
150
+ }
151
+
64
152
  // src/core/rendering/dispose.ts
65
153
  var elementDisposers = /* @__PURE__ */ new WeakMap();
66
154
  var _isDev2 = isDev();
@@ -164,7 +252,6 @@ function spring(element, keyframes, options = {}) {
164
252
  }
165
253
 
166
254
  // src/reactivity/track-core.ts
167
- var _isDev3 = isDev();
168
255
  var POOL_MAX = 4096;
169
256
  var nodePool = [];
170
257
  function createNode() {
@@ -172,6 +259,7 @@ function createNode() {
172
259
  sig: null,
173
260
  sub: null,
174
261
  epoch: 0,
262
+ depVersion: 0,
175
263
  sigPrev: null,
176
264
  sigNext: null,
177
265
  subPrev: null,
@@ -256,9 +344,28 @@ function safeInvoke(sub) {
256
344
  try {
257
345
  sub();
258
346
  } catch (err) {
259
- if (_isDev3) devWarn(`Subscriber threw during notification: ${err instanceof Error ? err.message : String(err)}`);
347
+ const s = sub;
348
+ reportError(err, { phase: s._errorPhase ?? "effect", name: s.__name, node: s._errorNode });
260
349
  }
261
350
  }
351
+ function depsChanged(sub) {
352
+ let node = sub.depsHead ?? null;
353
+ if (node === null) return true;
354
+ while (node !== null) {
355
+ const sig = node.sig;
356
+ if (sig === null) return true;
357
+ if (sig._d === true && sig._validate !== void 0) {
358
+ try {
359
+ sig._validate();
360
+ } catch {
361
+ return true;
362
+ }
363
+ }
364
+ if (node.depVersion !== sig.__v) return true;
365
+ node = node.subNext;
366
+ }
367
+ return false;
368
+ }
262
369
  var suspendDepth = 0;
263
370
  var trackingSuspended = false;
264
371
  function suspendTracking() {
@@ -339,7 +446,7 @@ function track(effectFn, subscriber) {
339
446
  const sub = subscriber;
340
447
  return sub._dispose ?? (sub._dispose = () => cleanup(subscriber));
341
448
  }
342
- function reactiveBinding(commit) {
449
+ function reactiveBinding(commit, ownerNode) {
343
450
  const run = () => {
344
451
  const s = subscriber;
345
452
  if (s._disposed || s._reentrant) return;
@@ -355,13 +462,17 @@ function reactiveBinding(commit) {
355
462
  subscriber.depsTail = null;
356
463
  subscriber._epoch = 0;
357
464
  subscriber._structDirty = false;
465
+ subscriber._hasComputedDep = false;
358
466
  subscriber._runEpoch = 0;
359
467
  subscriber._runs = 0;
360
468
  subscriber._reentrant = false;
361
469
  subscriber._disposed = false;
470
+ subscriber._errorPhase = "binding";
471
+ subscriber._errorNode = ownerNode;
362
472
  run();
363
473
  return subscriber._dispose ?? (subscriber._dispose = () => {
364
474
  subscriber._disposed = true;
475
+ subscriber._errorNode = void 0;
365
476
  cleanup(subscriber);
366
477
  });
367
478
  }
@@ -373,9 +484,12 @@ function recordDependency(signal2) {
373
484
  const active = sig.__activeNode ?? null;
374
485
  if (active !== null && active.sub === sub) {
375
486
  active.epoch = epoch;
487
+ active.depVersion = sig.__v ?? Number.NaN;
376
488
  return;
377
489
  }
490
+ if (sig._validate !== void 0) sub._hasComputedDep = true;
378
491
  const node = allocNode(signal2, sub, epoch);
492
+ node.depVersion = sig.__v ?? Number.NaN;
379
493
  node.prevActive = active;
380
494
  sig.__activeNode = node;
381
495
  linkSub(sub, node);
@@ -394,9 +508,10 @@ function cleanup(subscriber) {
394
508
  node = next;
395
509
  }
396
510
  }
397
- var maxSubscriberRepeats = 50;
511
+ var maxSubscriberRepeats = 1e3;
398
512
  var maxDrainIterations = 1e6;
399
513
  var drainEpoch = 0;
514
+ var quarantined = /* @__PURE__ */ new Set();
400
515
  function setMaxSubscriberRepeats(n) {
401
516
  const prev = maxSubscriberRepeats;
402
517
  if (Number.isFinite(n) && n > 0) maxSubscriberRepeats = Math.floor(n);
@@ -418,19 +533,21 @@ function tickRepeat(sub) {
418
533
  return s._runs > maxSubscriberRepeats;
419
534
  }
420
535
  function cycleError(sub) {
421
- if (typeof console !== "undefined") {
422
- const name = sub.__name ?? "<unnamed>";
423
- console.error(
424
- `[SibuJS] subscriber "${name}" fired more than ${maxSubscriberRepeats} times \u2014 likely a write-reads-self cycle between effects/signals. Breaking to prevent infinite loop.`
425
- );
426
- }
536
+ const name = sub.__name ?? "<unnamed>";
537
+ reportError(
538
+ new Error(
539
+ `subscriber "${name}" fired more than ${maxSubscriberRepeats} times \u2014 likely a write-reads-self cycle between effects/signals. This subscriber is quarantined for the rest of this update; other pending work still runs.`
540
+ ),
541
+ { phase: "scheduler", name }
542
+ );
427
543
  }
428
544
  function absoluteDrainError() {
429
- if (typeof console !== "undefined") {
430
- console.error(
431
- `[SibuJS] Notification drain exceeded ${maxDrainIterations} iterations \u2014 absolute safety net tripped. Breaking to prevent infinite loop.`
432
- );
433
- }
545
+ reportError(
546
+ new Error(
547
+ `Notification drain exceeded ${maxDrainIterations} iterations \u2014 absolute safety net tripped. Breaking to prevent infinite loop.`
548
+ ),
549
+ { phase: "scheduler" }
550
+ );
434
551
  }
435
552
  function drainQueue() {
436
553
  let i = 0;
@@ -440,11 +557,14 @@ function drainQueue() {
440
557
  break;
441
558
  }
442
559
  const sub = pendingQueue[i++];
560
+ pendingSet.delete(sub);
561
+ if (quarantined.size > 0 && quarantined.has(sub)) continue;
562
+ if (sub._hasComputedDep === true && !depsChanged(sub)) continue;
443
563
  if (tickRepeat(sub)) {
444
564
  cycleError(sub);
445
- break;
565
+ quarantined.add(sub);
566
+ continue;
446
567
  }
447
- pendingSet.delete(sub);
448
568
  safeInvoke(sub);
449
569
  }
450
570
  }
@@ -459,6 +579,7 @@ function drainNotificationQueue() {
459
579
  if (notifyDepth === 0) {
460
580
  pendingQueue.length = 0;
461
581
  pendingSet.clear();
582
+ if (quarantined.size > 0) quarantined.clear();
462
583
  }
463
584
  }
464
585
  }
@@ -552,6 +673,7 @@ function notifySubscribers(signal2) {
552
673
  if (notifyDepth === 0) {
553
674
  pendingQueue.length = 0;
554
675
  pendingSet.clear();
676
+ if (quarantined.size > 0) quarantined.clear();
555
677
  }
556
678
  }
557
679
  }
@@ -578,14 +700,14 @@ function forEachSubscriber(signal2, visit) {
578
700
  }
579
701
 
580
702
  // src/reactivity/track.ts
581
- var _isDev4 = isDev();
582
- var _runtimeVersion = true ? "3.4.0" : "dev";
703
+ var _isDev3 = isDev();
704
+ var _runtimeVersion = true ? "4.0.0" : "dev";
583
705
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
584
706
  function resolveReactiveApi() {
585
707
  const g = globalThis;
586
708
  const existing = g[REGISTRY_KEY];
587
709
  if (existing) {
588
- if (_isDev4 && !existing.__dupWarned) {
710
+ if (_isDev3 && !existing.__dupWarned) {
589
711
  existing.__dupWarned = true;
590
712
  devWarn(
591
713
  `Multiple instances of the reactive runtime detected on this page (active: ${existing.version}, duplicate: ${_runtimeVersion}). Reactivity still works \u2014 all copies share the first one \u2014 but de-duplicate sibujs in your bundler (e.g. Vite optimizeDeps.exclude: ['sibujs'] or resolve.dedupe: ['sibujs']).`
@@ -687,70 +809,72 @@ var isBatching = API2.isBatching;
687
809
 
688
810
  // src/core/signals/signal.ts
689
811
  var _g = globalThis;
690
- var _isDev5 = isDev();
812
+ var _isDev4 = isDev();
691
813
  function signal(initial, options) {
692
- const state = {
814
+ const state2 = {
693
815
  value: initial,
694
816
  __v: 0,
695
817
  __sc: 0,
696
818
  subsHead: null,
697
819
  subsTail: null,
698
820
  __activeNode: null,
699
- __name: void 0
821
+ __name: void 0,
822
+ _d: false,
823
+ _validate: void 0
700
824
  };
701
- const debugName = _isDev5 ? options?.name : void 0;
825
+ const debugName = _isDev4 ? options?.name : void 0;
702
826
  const equalsFn = options?.equals;
703
- if (debugName) state.__name = debugName;
827
+ if (debugName) state2.__name = debugName;
704
828
  function get() {
705
- recordDependency2(state);
706
- return state.value;
829
+ recordDependency2(state2);
830
+ return state2.value;
707
831
  }
708
- get.__signal = state;
832
+ get.__signal = state2;
709
833
  if (debugName) get.__name = debugName;
710
834
  let set;
711
835
  if (equalsFn) {
712
836
  set = (next) => {
713
- const prev = state.value;
837
+ const prev = state2.value;
714
838
  const newValue = typeof next === "function" ? next(prev) : next;
715
839
  if (equalsFn(prev, newValue)) return;
716
- state.value = newValue;
717
- state.__v++;
718
- if (_isDev5) {
840
+ state2.value = newValue;
841
+ state2.__v++;
842
+ if (_isDev4) {
719
843
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
720
- if (hook) hook.emit("signal:update", { signal: state, name: debugName, oldValue: prev, newValue });
844
+ if (hook) hook.emit("signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
721
845
  }
722
- if (!enqueueBatchedSignal(state)) {
723
- notifySubscribers2(state);
846
+ if (!enqueueBatchedSignal(state2)) {
847
+ notifySubscribers2(state2);
724
848
  }
725
849
  };
726
- } else if (_isDev5) {
850
+ } else if (_isDev4) {
727
851
  set = (next) => {
728
- const prev = state.value;
852
+ const prev = state2.value;
729
853
  const newValue = typeof next === "function" ? next(prev) : next;
730
854
  if (Object.is(newValue, prev)) return;
731
- state.value = newValue;
732
- state.__v++;
855
+ state2.value = newValue;
856
+ state2.__v++;
733
857
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
734
- if (hook) hook.emit("signal:update", { signal: state, name: debugName, oldValue: prev, newValue });
735
- if (!enqueueBatchedSignal(state)) {
736
- notifySubscribers2(state);
858
+ if (hook) hook.emit("signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
859
+ if (!enqueueBatchedSignal(state2)) {
860
+ notifySubscribers2(state2);
737
861
  }
738
862
  };
739
863
  } else {
740
864
  set = (next) => {
741
- const prev = state.value;
865
+ const prev = state2.value;
742
866
  const newValue = typeof next === "function" ? next(prev) : next;
743
867
  if (Object.is(newValue, prev)) return;
744
- state.value = newValue;
745
- state.__v++;
746
- if (!enqueueBatchedSignal(state)) {
747
- notifySubscribers2(state);
868
+ state2.value = newValue;
869
+ state2.__v++;
870
+ if (!enqueueBatchedSignal(state2)) {
871
+ notifySubscribers2(state2);
748
872
  }
749
873
  };
750
874
  }
751
- if (_isDev5) {
875
+ if (_isDev4) {
752
876
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
753
- if (hook) hook.emit("signal:create", { signal: state, name: debugName, getter: get, initial });
877
+ if (hook) hook.emit("signal:create", { signal: state2, name: debugName, getter: get, initial });
754
878
  }
755
879
  return [get, set];
756
880
  }
@@ -997,7 +1121,9 @@ function TransitionGroup(options) {
997
1121
  // src/ui/viewTransition.ts
998
1122
  function viewTransition(callback) {
999
1123
  const [isTransitioning, setIsTransitioning] = signal(false);
1124
+ let inflight = 0;
1000
1125
  async function start() {
1126
+ inflight++;
1001
1127
  setIsTransitioning(true);
1002
1128
  try {
1003
1129
  if (typeof document !== "undefined" && "startViewTransition" in document && typeof document.startViewTransition === "function") {
@@ -1007,7 +1133,11 @@ function viewTransition(callback) {
1007
1133
  await callback();
1008
1134
  }
1009
1135
  } finally {
1010
- setIsTransitioning(false);
1136
+ inflight--;
1137
+ if (inflight <= 0) {
1138
+ inflight = 0;
1139
+ setIsTransitioning(false);
1140
+ }
1011
1141
  }
1012
1142
  }
1013
1143
  return { start, isTransitioning };
package/dist/motion.d.cts CHANGED
@@ -128,6 +128,32 @@ declare function TransitionGroup(options: TransitionGroupOptions): {
128
128
  /**
129
129
  * viewTransition wraps the View Transitions API (document.startViewTransition).
130
130
  * Falls back to calling the callback directly when the API is unavailable.
131
+ *
132
+ * OVERLAP MODEL — aggregate in-flight state.
133
+ *
134
+ * `isTransitioning` used to be a plain boolean set true on entry and false in a
135
+ * `finally`, which makes it a claim owned by whichever run settled last rather
136
+ * than a description of the controller. Two overlapping starts raced over it:
137
+ *
138
+ * start A → pending
139
+ * start B → pending
140
+ * B finishes → isTransitioning() === false, while A is still running
141
+ *
142
+ * so the UI dropped its transition affordance — spinner, pointer-events guard,
143
+ * whatever it gates — in the middle of a transition that was still going.
144
+ *
145
+ * The flag now describes the aggregate: it becomes true when the first run
146
+ * starts, stays true while at least one run is in flight, and becomes false
147
+ * exactly when the final one settles, in any settlement order. A rejection is a
148
+ * settlement like any other, so one run failing does not clear the flag while
149
+ * another is still running — and every caller still receives its own resolution
150
+ * or rejection, unchanged.
151
+ *
152
+ * Native transitions are deliberately NOT serialized here. The browser's own
153
+ * API defines what happens when a second transition starts while one is active
154
+ * (it skips the older one), and queueing on top of that would delay callbacks
155
+ * the caller expects to have run. This wrapper reports state; it does not
156
+ * impose a scheduling policy the platform already has.
131
157
  */
132
158
  declare function viewTransition(callback: () => void | Promise<void>): {
133
159
  start: () => Promise<void>;
package/dist/motion.d.ts CHANGED
@@ -128,6 +128,32 @@ declare function TransitionGroup(options: TransitionGroupOptions): {
128
128
  /**
129
129
  * viewTransition wraps the View Transitions API (document.startViewTransition).
130
130
  * Falls back to calling the callback directly when the API is unavailable.
131
+ *
132
+ * OVERLAP MODEL — aggregate in-flight state.
133
+ *
134
+ * `isTransitioning` used to be a plain boolean set true on entry and false in a
135
+ * `finally`, which makes it a claim owned by whichever run settled last rather
136
+ * than a description of the controller. Two overlapping starts raced over it:
137
+ *
138
+ * start A → pending
139
+ * start B → pending
140
+ * B finishes → isTransitioning() === false, while A is still running
141
+ *
142
+ * so the UI dropped its transition affordance — spinner, pointer-events guard,
143
+ * whatever it gates — in the middle of a transition that was still going.
144
+ *
145
+ * The flag now describes the aggregate: it becomes true when the first run
146
+ * starts, stays true while at least one run is in flight, and becomes false
147
+ * exactly when the final one settles, in any settlement order. A rejection is a
148
+ * settlement like any other, so one run failing does not clear the flag while
149
+ * another is still running — and every caller still receives its own resolution
150
+ * or rejection, unchanged.
151
+ *
152
+ * Native transitions are deliberately NOT serialized here. The browser's own
153
+ * API defines what happens when a second transition starts while one is active
154
+ * (it skips the older one), and queueing on top of that would delay callbacks
155
+ * the caller expects to have run. This wrapper reports state; it does not
156
+ * impose a scheduling policy the platform already has.
131
157
  */
132
158
  declare function viewTransition(callback: () => void | Promise<void>): {
133
159
  start: () => Promise<void>;
package/dist/motion.js CHANGED
@@ -20,11 +20,11 @@ import {
20
20
  stagger,
21
21
  transition,
22
22
  viewTransition
23
- } from "./chunk-WSGLJYFI.js";
24
- import "./chunk-5VGSK6D2.js";
25
- import "./chunk-KZBEVFXZ.js";
26
- import "./chunk-OOUQUCNN.js";
27
- import "./chunk-COY6PUD2.js";
23
+ } from "./chunk-E62UADKL.js";
24
+ import "./chunk-DHDZ7IVN.js";
25
+ import "./chunk-W55YHPEP.js";
26
+ import "./chunk-ACBT6UZS.js";
27
+ import "./chunk-VPP2FONR.js";
28
28
  export {
29
29
  TransitionGroup,
30
30
  animate,