signalium 3.0.2 → 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.
- package/CHANGELOG.md +39 -0
- package/dist/cjs/development/{component-shared-Cug2Y5YZ.js → component-shared-BjwFh5Jq.js} +2 -2
- package/dist/cjs/development/{component-shared-Cug2Y5YZ.js.map → component-shared-BjwFh5Jq.js.map} +1 -1
- package/dist/cjs/development/config-D6wyrhrW.js +58 -0
- package/dist/cjs/development/config-D6wyrhrW.js.map +1 -0
- package/dist/cjs/development/config.js +1 -1
- package/dist/cjs/development/{debug-C46WDxhL.js → debug-CbAX7VeM.js} +260 -43
- package/dist/cjs/development/debug-CbAX7VeM.js.map +1 -0
- package/dist/cjs/development/debug.js +3 -1
- package/dist/cjs/development/debug.js.map +1 -1
- package/dist/cjs/development/index.js +3 -2
- package/dist/cjs/development/index.js.map +1 -1
- package/dist/cjs/development/react/index.js +399 -52
- package/dist/cjs/development/react/index.js.map +1 -1
- package/dist/cjs/development/react/index.server.js +2 -2
- package/dist/cjs/development/react/index.server.js.map +1 -1
- package/dist/cjs/development/react/server.js +1 -1
- package/dist/cjs/development/{snapshot-CbZ6IH3B.js → snapshot-BTMVSd8Y.js} +4 -2
- package/dist/cjs/development/snapshot-BTMVSd8Y.js.map +1 -0
- package/dist/cjs/development/transform/index.js +5 -2
- package/dist/cjs/development/transform/index.js.map +1 -1
- package/dist/cjs/development/utils.js +34 -2
- package/dist/cjs/development/utils.js.map +1 -1
- package/dist/cjs/production/{component-shared-D0J85PUi.js → component-shared-CcxyLg4p.js} +2 -2
- package/dist/cjs/production/{component-shared-D0J85PUi.js.map → component-shared-CcxyLg4p.js.map} +1 -1
- package/dist/cjs/production/config-BHvmcsLQ.js +52 -0
- package/dist/cjs/production/config-BHvmcsLQ.js.map +1 -0
- package/dist/cjs/production/config.js +1 -1
- package/dist/cjs/production/{contexts-CM3QLfV8.js → contexts-waczQzHZ.js} +260 -43
- package/dist/cjs/production/contexts-waczQzHZ.js.map +1 -0
- package/dist/cjs/production/debug.js +3 -1
- package/dist/cjs/production/debug.js.map +1 -1
- package/dist/cjs/production/index.js +3 -2
- package/dist/cjs/production/index.js.map +1 -1
- package/dist/cjs/production/react/index.js +399 -52
- package/dist/cjs/production/react/index.js.map +1 -1
- package/dist/cjs/production/react/index.server.js +2 -2
- package/dist/cjs/production/react/index.server.js.map +1 -1
- package/dist/cjs/production/react/server.js +1 -1
- package/dist/cjs/production/{snapshot-DWwH7_9y.js → snapshot-7264bWj1.js} +4 -2
- package/dist/cjs/production/snapshot-7264bWj1.js.map +1 -0
- package/dist/cjs/production/transform/index.js +5 -2
- package/dist/cjs/production/transform/index.js.map +1 -1
- package/dist/cjs/production/utils.js +34 -2
- package/dist/cjs/production/utils.js.map +1 -1
- package/dist/esm/config.d.ts +1 -1
- package/dist/esm/config.d.ts.map +1 -1
- package/dist/esm/debug.d.ts +1 -0
- package/dist/esm/debug.d.ts.map +1 -1
- package/dist/esm/development/{component-shared-CLSmdnGU.js → component-shared-B3Q6mIzY.js} +2 -2
- package/dist/esm/development/{component-shared-CLSmdnGU.js.map → component-shared-B3Q6mIzY.js.map} +1 -1
- package/dist/esm/development/config-CQLKpPRj.js +59 -0
- package/dist/esm/development/config-CQLKpPRj.js.map +1 -0
- package/dist/esm/development/config.js +2 -2
- package/dist/esm/development/{debug-BTLbgTPK.js → debug-C3HD8WcT.js} +288 -71
- package/dist/esm/development/debug-C3HD8WcT.js.map +1 -0
- package/dist/esm/development/debug.js +12 -10
- package/dist/esm/development/index.js +18 -17
- package/dist/esm/development/react/index.js +400 -53
- package/dist/esm/development/react/index.js.map +1 -1
- package/dist/esm/development/react/index.server.js +2 -2
- package/dist/esm/development/react/index.server.js.map +1 -1
- package/dist/esm/development/react/server.js +1 -1
- package/dist/esm/development/{snapshot-CkndI4Hh.js → snapshot-CCKlBy-y.js} +7 -5
- package/dist/esm/development/snapshot-CCKlBy-y.js.map +1 -0
- package/dist/esm/development/transform/index.js +5 -2
- package/dist/esm/development/transform/index.js.map +1 -1
- package/dist/esm/development/utils.js +38 -6
- package/dist/esm/development/utils.js.map +1 -1
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/internals/async.d.ts.map +1 -1
- package/dist/esm/internals/config.d.ts +40 -0
- package/dist/esm/internals/config.d.ts.map +1 -1
- package/dist/esm/internals/lease.d.ts +30 -0
- package/dist/esm/internals/lease.d.ts.map +1 -0
- package/dist/esm/internals/reactive.d.ts +18 -1
- package/dist/esm/internals/reactive.d.ts.map +1 -1
- package/dist/esm/internals/scheduling.d.ts +2 -1
- package/dist/esm/internals/scheduling.d.ts.map +1 -1
- package/dist/esm/internals/utils/hash.d.ts +7 -0
- package/dist/esm/internals/utils/hash.d.ts.map +1 -1
- package/dist/esm/internals/utils/snapshot.d.ts +2 -0
- package/dist/esm/internals/utils/snapshot.d.ts.map +1 -1
- package/dist/esm/internals/watch.d.ts +3 -2
- package/dist/esm/internals/watch.d.ts.map +1 -1
- package/dist/esm/production/{component-shared-Dva0S5e3.js → component-shared-CycOXiis.js} +2 -2
- package/dist/esm/production/{component-shared-Dva0S5e3.js.map → component-shared-CycOXiis.js.map} +1 -1
- package/dist/esm/production/config-BhtwQYAN.js +53 -0
- package/dist/esm/production/config-BhtwQYAN.js.map +1 -0
- package/dist/esm/production/config.js +2 -2
- package/dist/esm/production/{contexts-FxCndlvf.js → contexts-ry5lvNSx.js} +291 -74
- package/dist/esm/production/contexts-ry5lvNSx.js.map +1 -0
- package/dist/esm/production/debug.js +3 -1
- package/dist/esm/production/index.js +19 -18
- package/dist/esm/production/react/index.js +400 -53
- package/dist/esm/production/react/index.js.map +1 -1
- package/dist/esm/production/react/index.server.js +2 -2
- package/dist/esm/production/react/index.server.js.map +1 -1
- package/dist/esm/production/react/server.js +1 -1
- package/dist/esm/production/{snapshot-CdCaJJ0L.js → snapshot-1d_HVP3L.js} +7 -5
- package/dist/esm/production/snapshot-1d_HVP3L.js.map +1 -0
- package/dist/esm/production/transform/index.js +5 -2
- package/dist/esm/production/transform/index.js.map +1 -1
- package/dist/esm/production/utils.js +39 -7
- package/dist/esm/production/utils.js.map +1 -1
- package/dist/esm/react/async-component.d.ts +10 -2
- package/dist/esm/react/async-component.d.ts.map +1 -1
- package/dist/esm/react/component-server.d.ts +6 -2
- package/dist/esm/react/component-server.d.ts.map +1 -1
- package/dist/esm/react/component.d.ts +5 -2
- package/dist/esm/react/component.d.ts.map +1 -1
- package/dist/esm/react/delivery.d.ts +107 -0
- package/dist/esm/react/delivery.d.ts.map +1 -0
- package/dist/esm/react/index.d.ts +3 -2
- package/dist/esm/react/index.d.ts.map +1 -1
- package/dist/esm/react/pause-signals-context.d.ts +16 -2
- package/dist/esm/react/pause-signals-context.d.ts.map +1 -1
- package/dist/esm/react/props-hash.d.ts +20 -0
- package/dist/esm/react/props-hash.d.ts.map +1 -0
- package/dist/esm/react/use-reactive.d.ts +6 -3
- package/dist/esm/react/use-reactive.d.ts.map +1 -1
- package/dist/esm/transform/async.d.ts.map +1 -1
- package/dist/esm/transform/callback.d.ts.map +1 -1
- package/dist/esm/transform/promise.d.ts.map +1 -1
- package/dist/esm/transform/use-reactive.d.ts.map +1 -1
- package/dist/esm/transform/utils.d.ts +1 -1
- package/dist/esm/transform/utils.d.ts.map +1 -1
- package/dist/esm/types.d.ts +20 -1
- package/dist/esm/types.d.ts.map +1 -1
- package/dist/esm/utils.d.ts +17 -1
- package/dist/esm/utils.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/cjs/development/config-B0MtLBgx.js +0 -21
- package/dist/cjs/development/config-B0MtLBgx.js.map +0 -1
- package/dist/cjs/development/debug-C46WDxhL.js.map +0 -1
- package/dist/cjs/development/snapshot-CbZ6IH3B.js.map +0 -1
- package/dist/cjs/production/config-B0MtLBgx.js +0 -21
- package/dist/cjs/production/config-B0MtLBgx.js.map +0 -1
- package/dist/cjs/production/contexts-CM3QLfV8.js.map +0 -1
- package/dist/cjs/production/snapshot-DWwH7_9y.js.map +0 -1
- package/dist/esm/development/config-CPQL7hX-.js +0 -22
- package/dist/esm/development/config-CPQL7hX-.js.map +0 -1
- package/dist/esm/development/debug-BTLbgTPK.js.map +0 -1
- package/dist/esm/development/snapshot-CkndI4Hh.js.map +0 -1
- package/dist/esm/production/config-CPQL7hX-.js +0 -22
- package/dist/esm/production/config-CPQL7hX-.js.map +0 -1
- package/dist/esm/production/contexts-FxCndlvf.js.map +0 -1
- package/dist/esm/production/snapshot-CdCaJJ0L.js.map +0 -1
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import * as React from "react";
|
|
3
|
-
import React__default, { createContext, useContext as useContext$1, useMemo, useRef, useEffect, useSyncExternalStore } from "react";
|
|
4
|
-
import { b as getCurrentConsumer, k as getGlobalScope, S as SignalScope, l as hashValue,
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
3
|
+
import React__default, { createContext, useContext as useContext$1, useMemo, useRef, useEffect, useSyncExternalStore, useReducer, useState, useLayoutEffect, useInsertionEffect } from "react";
|
|
4
|
+
import { b as getCurrentConsumer, k as getGlobalScope, S as SignalScope, l as hashValue, m as getObjectHash, n as hashObjectKeys, o as mixHash, p as finalizeHash, A as ARRAY_SEED, q as checkSignal, s as setCurrentConsumer, j as isReactivePromise, r as isPromise, t as isThennable, c as createReactiveSignal, u as runSignal, v as holdLeaseUntilSettled, w as holdSuspendedLease, x as releaseAbandonedAttempt, d as setRequestScopeGetter, y as signal } from "../debug-C3HD8WcT.js";
|
|
5
|
+
import { g as getReactDelivery, s as scheduleReactDelivery, r as runBatch } from "../config-CQLKpPRj.js";
|
|
6
|
+
import { i as isAsyncFunctionWithoutTransform, a as isGeneratorFunction, c as createServerAsyncComponentWrapper } from "../component-shared-B3Q6mIzY.js";
|
|
7
|
+
import { g as getReactiveFnAndDefinition, r as reactiveSignal, s as snapshot } from "../snapshot-CCKlBy-y.js";
|
|
7
8
|
const ScopeContext = createContext(void 0);
|
|
8
9
|
function useScope() {
|
|
9
10
|
return useContext$1(ScopeContext);
|
|
@@ -25,7 +26,14 @@ function ContextProvider({ children, contexts = [], inherit = true }) {
|
|
|
25
26
|
return jsx(ScopeContext.Provider, { value: scope, children });
|
|
26
27
|
}
|
|
27
28
|
class PauseSignalsManager {
|
|
28
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Readers per registered signal. Scope-cached signals can be shared across providers, so pausing
|
|
31
|
+
* counts readers on the signal instead of pausing it outright.
|
|
32
|
+
*/
|
|
33
|
+
signals = /* @__PURE__ */ new Map();
|
|
34
|
+
/** Unclaimed render leases taken under this provider (e.g. a suspended mount). Pruned lazily. */
|
|
35
|
+
leases = /* @__PURE__ */ new Set();
|
|
36
|
+
pruneLeasesAt = 64;
|
|
29
37
|
_paused;
|
|
30
38
|
constructor(initialPaused) {
|
|
31
39
|
this._paused = initialPaused;
|
|
@@ -33,22 +41,52 @@ class PauseSignalsManager {
|
|
|
33
41
|
get paused() {
|
|
34
42
|
return this._paused;
|
|
35
43
|
}
|
|
44
|
+
trackLease(signal2) {
|
|
45
|
+
const leases = this.leases;
|
|
46
|
+
leases.add(signal2);
|
|
47
|
+
if (leases.size >= this.pruneLeasesAt) {
|
|
48
|
+
for (const leased of leases) {
|
|
49
|
+
if (!leased._isLeased)
|
|
50
|
+
leases.delete(leased);
|
|
51
|
+
}
|
|
52
|
+
this.pruneLeasesAt = Math.max(64, leases.size * 2);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** Call before the reader subscribes, so a paused reader never takes the watch. */
|
|
36
56
|
register(signal2) {
|
|
37
|
-
this.signals.
|
|
57
|
+
this.signals.set(signal2, (this.signals.get(signal2) ?? 0) + 1);
|
|
58
|
+
this.leases.delete(signal2);
|
|
59
|
+
if (this._paused) {
|
|
60
|
+
signal2._addPausedReaders(1);
|
|
61
|
+
}
|
|
38
62
|
}
|
|
39
63
|
unregister(signal2) {
|
|
40
|
-
this.signals.
|
|
64
|
+
const count = this.signals.get(signal2);
|
|
65
|
+
if (count === void 0)
|
|
66
|
+
return;
|
|
67
|
+
if (count > 1) {
|
|
68
|
+
this.signals.set(signal2, count - 1);
|
|
69
|
+
} else {
|
|
70
|
+
this.signals.delete(signal2);
|
|
71
|
+
}
|
|
72
|
+
if (this._paused) {
|
|
73
|
+
signal2._addPausedReaders(-1, true);
|
|
74
|
+
}
|
|
41
75
|
}
|
|
42
76
|
setPaused(value) {
|
|
43
77
|
if (value === this._paused)
|
|
44
78
|
return;
|
|
45
79
|
this._paused = value;
|
|
46
|
-
for (const signal2 of this.signals) {
|
|
47
|
-
|
|
48
|
-
|
|
80
|
+
for (const [signal2, count] of this.signals) {
|
|
81
|
+
signal2._addPausedReaders(value ? count : -count);
|
|
82
|
+
}
|
|
83
|
+
for (const signal2 of this.leases) {
|
|
84
|
+
if (!signal2._isLeased) {
|
|
85
|
+
this.leases.delete(signal2);
|
|
86
|
+
} else if (value) {
|
|
87
|
+
signal2._pauseWatch();
|
|
49
88
|
} else {
|
|
50
|
-
|
|
51
|
-
schedulePull(signal2);
|
|
89
|
+
signal2._resumeWatch();
|
|
52
90
|
}
|
|
53
91
|
}
|
|
54
92
|
}
|
|
@@ -68,6 +106,299 @@ function PauseSignalsProvider({ value, children }) {
|
|
|
68
106
|
function usePauseSignalsManager() {
|
|
69
107
|
return useContext$1(PauseSignalsManagerContext);
|
|
70
108
|
}
|
|
109
|
+
function addRenderListener(signal2, manager) {
|
|
110
|
+
const subscribe = signal2.addListenerLazy(!manager?.paused);
|
|
111
|
+
if (manager !== null && signal2._isLeased) {
|
|
112
|
+
manager.trackLease(signal2);
|
|
113
|
+
}
|
|
114
|
+
return subscribe;
|
|
115
|
+
}
|
|
116
|
+
function usePausableStore(manager, signal2, subscribe, getSnapshot) {
|
|
117
|
+
useEffect(() => {
|
|
118
|
+
if (manager === null)
|
|
119
|
+
return;
|
|
120
|
+
manager.register(signal2);
|
|
121
|
+
return () => manager.unregister(signal2);
|
|
122
|
+
}, [manager, signal2]);
|
|
123
|
+
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
124
|
+
}
|
|
125
|
+
const { imul } = Math;
|
|
126
|
+
const { getPrototypeOf, keys: objectKeys } = Object;
|
|
127
|
+
const EMPTY_PROPS_HASH = hashValue({});
|
|
128
|
+
function hashPropValue(value, seen) {
|
|
129
|
+
if (typeof value === "object" && value !== null) {
|
|
130
|
+
const proto = getPrototypeOf(value);
|
|
131
|
+
if (proto === Object.prototype) {
|
|
132
|
+
const keys = objectKeys(value);
|
|
133
|
+
if (keys.includes("$$typeof") && typeof value.$$typeof === "symbol") {
|
|
134
|
+
return getObjectHash(value);
|
|
135
|
+
}
|
|
136
|
+
seen.push(value);
|
|
137
|
+
const h = hashObjectKeys(value, keys, seen);
|
|
138
|
+
seen.pop();
|
|
139
|
+
return h;
|
|
140
|
+
}
|
|
141
|
+
if (proto === Array.prototype) {
|
|
142
|
+
if (seen.includes(value))
|
|
143
|
+
return 0;
|
|
144
|
+
seen.push(value);
|
|
145
|
+
const array = value;
|
|
146
|
+
let h = ARRAY_SEED;
|
|
147
|
+
for (let i = 0; i < array.length; i++) {
|
|
148
|
+
h = mixHash(h, hashPropValue(array[i], seen));
|
|
149
|
+
}
|
|
150
|
+
seen.pop();
|
|
151
|
+
return finalizeHash(h, array.length);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return hashValue(value, seen);
|
|
155
|
+
}
|
|
156
|
+
function hashProps(props) {
|
|
157
|
+
const keyMultiplier = 2654435769;
|
|
158
|
+
const seen = [];
|
|
159
|
+
let sum = EMPTY_PROPS_HASH;
|
|
160
|
+
for (const key of objectKeys(props)) {
|
|
161
|
+
sum += imul(hashValue(key), keyMultiplier) ^ hashPropValue(props[key], seen);
|
|
162
|
+
}
|
|
163
|
+
return sum >>> 0;
|
|
164
|
+
}
|
|
165
|
+
function shallowIdentical(prev, next) {
|
|
166
|
+
let count = 0;
|
|
167
|
+
for (const key in next) {
|
|
168
|
+
if (!Object.is(prev[key], next[key]) || !(key in prev))
|
|
169
|
+
return false;
|
|
170
|
+
count++;
|
|
171
|
+
}
|
|
172
|
+
for (const _key in prev) {
|
|
173
|
+
count--;
|
|
174
|
+
}
|
|
175
|
+
return count === 0;
|
|
176
|
+
}
|
|
177
|
+
class PropsHashCache {
|
|
178
|
+
props;
|
|
179
|
+
hash;
|
|
180
|
+
constructor(props, hash) {
|
|
181
|
+
this.props = props;
|
|
182
|
+
this.hash = hash;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function usePropsHash(props) {
|
|
186
|
+
const ref = useRef(null);
|
|
187
|
+
const cache = ref.current;
|
|
188
|
+
if (cache !== null) {
|
|
189
|
+
if (cache.props === props || shallowIdentical(cache.props, props)) {
|
|
190
|
+
return cache.hash;
|
|
191
|
+
}
|
|
192
|
+
const hash2 = hashProps(props);
|
|
193
|
+
cache.props = props;
|
|
194
|
+
cache.hash = hash2;
|
|
195
|
+
return hash2;
|
|
196
|
+
}
|
|
197
|
+
const hash = hashProps(props);
|
|
198
|
+
ref.current = new PropsHashCache(props, hash);
|
|
199
|
+
return hash;
|
|
200
|
+
}
|
|
201
|
+
function useDeliveryMode(override) {
|
|
202
|
+
const ref = useRef(void 0);
|
|
203
|
+
return ref.current ??= override ?? getReactDelivery();
|
|
204
|
+
}
|
|
205
|
+
const useCommitEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
|
|
206
|
+
const increment = (n) => n + 1;
|
|
207
|
+
class StateDelivery {
|
|
208
|
+
signal;
|
|
209
|
+
committed;
|
|
210
|
+
forceUpdate;
|
|
211
|
+
/** In the pending-delivery queue. */
|
|
212
|
+
queued = false;
|
|
213
|
+
/** A `setState` was delivered and its render has not committed yet. */
|
|
214
|
+
awaitingCommit = false;
|
|
215
|
+
/** Visible: between the subscription layout effect's setup and cleanup. Only visible readers get deliveries. */
|
|
216
|
+
mounted = false;
|
|
217
|
+
/**
|
|
218
|
+
* Set by every render, cleared by its commit. Still set when Suspense hides the reader, it means
|
|
219
|
+
* the reader's own render suspended, so it stays live: a change may no longer need what it
|
|
220
|
+
* suspended on.
|
|
221
|
+
*/
|
|
222
|
+
rendering = false;
|
|
223
|
+
/** The subscription layout effect has run before: its next run is a reveal, not a first mount. */
|
|
224
|
+
connected = false;
|
|
225
|
+
/**
|
|
226
|
+
* A commit included the reader without connecting it: it was committed hidden (prerendered in a
|
|
227
|
+
* hidden `<Activity>`, or mounted into a Suspense-hidden tree), so its first connect is a reveal.
|
|
228
|
+
*/
|
|
229
|
+
committedHidden = false;
|
|
230
|
+
/** The subscription currently held, the subscribe function it was made with, and its signal and pause manager. */
|
|
231
|
+
subscribedWith = null;
|
|
232
|
+
subscribedSignal = null;
|
|
233
|
+
pauseManager = null;
|
|
234
|
+
unsubscribe = null;
|
|
235
|
+
listener;
|
|
236
|
+
constructor(signal2, version, forceUpdate) {
|
|
237
|
+
this.signal = signal2;
|
|
238
|
+
this.committed = version;
|
|
239
|
+
this.forceUpdate = forceUpdate;
|
|
240
|
+
this.listener = () => this.check();
|
|
241
|
+
}
|
|
242
|
+
check() {
|
|
243
|
+
if (this.queued || this.awaitingCommit || !this.mounted)
|
|
244
|
+
return;
|
|
245
|
+
if (this.signal.updatedCount !== this.committed) {
|
|
246
|
+
enqueueDelivery(this);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Brings the signal up to date the way a read would, and reports whether it moved past the
|
|
251
|
+
* committed version. A signal nobody watched (the reader was hidden, or its render lease expired
|
|
252
|
+
* before the commit) is not recomputed when its dependencies change, so its `updatedCount` alone
|
|
253
|
+
* can be stale.
|
|
254
|
+
*/
|
|
255
|
+
pull() {
|
|
256
|
+
try {
|
|
257
|
+
checkSignal(this.signal);
|
|
258
|
+
} catch {
|
|
259
|
+
return 2;
|
|
260
|
+
}
|
|
261
|
+
return this.signal.updatedCount !== this.committed ? 1 : 0;
|
|
262
|
+
}
|
|
263
|
+
subscribe(subscribe, manager) {
|
|
264
|
+
if (this.subscribedWith === subscribe && this.pauseManager === manager)
|
|
265
|
+
return;
|
|
266
|
+
this.release();
|
|
267
|
+
manager?.register(this.signal);
|
|
268
|
+
this.subscribedSignal = this.signal;
|
|
269
|
+
this.pauseManager = manager;
|
|
270
|
+
this.unsubscribe = subscribe(this.listener);
|
|
271
|
+
this.subscribedWith = subscribe;
|
|
272
|
+
}
|
|
273
|
+
release() {
|
|
274
|
+
if (this.unsubscribe === null)
|
|
275
|
+
return;
|
|
276
|
+
this.unsubscribe();
|
|
277
|
+
this.pauseManager?.unregister(this.subscribedSignal);
|
|
278
|
+
this.unsubscribe = null;
|
|
279
|
+
this.subscribedWith = null;
|
|
280
|
+
this.subscribedSignal = null;
|
|
281
|
+
this.pauseManager = null;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
let PENDING_DELIVERIES = [];
|
|
285
|
+
let deliveryScheduled = false;
|
|
286
|
+
function enqueueDelivery(delivery) {
|
|
287
|
+
delivery.queued = true;
|
|
288
|
+
PENDING_DELIVERIES.push(delivery);
|
|
289
|
+
if (!deliveryScheduled) {
|
|
290
|
+
deliveryScheduled = true;
|
|
291
|
+
scheduleReactDelivery(flushDeliveries);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
function flushDeliveries() {
|
|
295
|
+
deliveryScheduled = false;
|
|
296
|
+
const deliveries = PENDING_DELIVERIES;
|
|
297
|
+
PENDING_DELIVERIES = [];
|
|
298
|
+
runBatch(() => {
|
|
299
|
+
for (const delivery of deliveries) {
|
|
300
|
+
delivery.queued = false;
|
|
301
|
+
if (delivery.mounted && delivery.signal.updatedCount !== delivery.committed) {
|
|
302
|
+
delivery.awaitingCommit = true;
|
|
303
|
+
delivery.forceUpdate();
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
function useStateDeliveryState(signal2) {
|
|
309
|
+
const [, forceUpdate] = useReducer(increment, 0);
|
|
310
|
+
const [delivery] = useState(() => new StateDelivery(signal2, signal2.updatedCount, forceUpdate));
|
|
311
|
+
delivery.rendering = true;
|
|
312
|
+
return delivery;
|
|
313
|
+
}
|
|
314
|
+
function useStateDelivery(delivery, signal2, subscribe, version, manager) {
|
|
315
|
+
useCommitEffect(() => {
|
|
316
|
+
delivery.signal = signal2;
|
|
317
|
+
delivery.committed = version;
|
|
318
|
+
delivery.awaitingCommit = false;
|
|
319
|
+
delivery.rendering = false;
|
|
320
|
+
delivery.check();
|
|
321
|
+
});
|
|
322
|
+
useInsertionEffect(() => {
|
|
323
|
+
if (delivery.connected)
|
|
324
|
+
return;
|
|
325
|
+
queueMicrotask(() => {
|
|
326
|
+
if (!delivery.connected)
|
|
327
|
+
delivery.committedHidden = true;
|
|
328
|
+
});
|
|
329
|
+
}, [delivery]);
|
|
330
|
+
useCommitEffect(() => {
|
|
331
|
+
const revealing = delivery.connected || delivery.committedHidden;
|
|
332
|
+
delivery.connected = true;
|
|
333
|
+
delivery.committedHidden = false;
|
|
334
|
+
delivery.mounted = true;
|
|
335
|
+
delivery.subscribe(subscribe, manager);
|
|
336
|
+
const pulled = delivery.pull();
|
|
337
|
+
if (pulled === 2 || pulled === 1 && revealing) {
|
|
338
|
+
delivery.awaitingCommit = true;
|
|
339
|
+
delivery.forceUpdate();
|
|
340
|
+
} else if (pulled === 1) {
|
|
341
|
+
delivery.check();
|
|
342
|
+
}
|
|
343
|
+
return () => {
|
|
344
|
+
if (delivery.rendering) {
|
|
345
|
+
delivery.awaitingCommit = false;
|
|
346
|
+
} else {
|
|
347
|
+
delivery.mounted = false;
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
}, [subscribe, manager]);
|
|
351
|
+
useEffect(() => () => delivery.release(), [delivery]);
|
|
352
|
+
}
|
|
353
|
+
const elementPropsByInnerProps = /* @__PURE__ */ new WeakMap();
|
|
354
|
+
const suspendedAttemptsByElement = /* @__PURE__ */ new WeakMap();
|
|
355
|
+
function createComponentElement(Inner, props) {
|
|
356
|
+
const element = React__default.createElement(Inner, props);
|
|
357
|
+
elementPropsByInnerProps.set(element.props, props);
|
|
358
|
+
return element;
|
|
359
|
+
}
|
|
360
|
+
function isReactSuspenseException(error) {
|
|
361
|
+
if (!(error instanceof Error))
|
|
362
|
+
return false;
|
|
363
|
+
const { message } = error;
|
|
364
|
+
return message.startsWith("Suspense Exception") || /^Minified React error #(460|542)\b/.test(message);
|
|
365
|
+
}
|
|
366
|
+
function readComponentSignal(signal2, props) {
|
|
367
|
+
const element = elementPropsByInnerProps.get(props);
|
|
368
|
+
let attempts = element === void 0 ? void 0 : suspendedAttemptsByElement.get(element);
|
|
369
|
+
try {
|
|
370
|
+
runSignal(signal2);
|
|
371
|
+
const value = signal2.value;
|
|
372
|
+
attempts?.delete(signal2);
|
|
373
|
+
return value;
|
|
374
|
+
} catch (error) {
|
|
375
|
+
let pinned = true;
|
|
376
|
+
if (error !== null && typeof error === "object" && isThennable(error)) {
|
|
377
|
+
holdLeaseUntilSettled(signal2, error);
|
|
378
|
+
} else if (isReactSuspenseException(error)) {
|
|
379
|
+
holdSuspendedLease(signal2);
|
|
380
|
+
} else {
|
|
381
|
+
pinned = false;
|
|
382
|
+
}
|
|
383
|
+
if (pinned && element !== void 0 && signal2._isLeased) {
|
|
384
|
+
if (attempts === void 0) {
|
|
385
|
+
attempts = /* @__PURE__ */ new Set();
|
|
386
|
+
suspendedAttemptsByElement.set(element, attempts);
|
|
387
|
+
}
|
|
388
|
+
attempts.add(signal2);
|
|
389
|
+
}
|
|
390
|
+
throw error;
|
|
391
|
+
} finally {
|
|
392
|
+
if (attempts !== void 0) {
|
|
393
|
+
for (const attempt of attempts) {
|
|
394
|
+
if (attempt !== signal2) {
|
|
395
|
+
releaseAbandonedAttempt(attempt);
|
|
396
|
+
attempts.delete(attempt);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
71
402
|
const thenableOutcome = /* @__PURE__ */ new WeakMap();
|
|
72
403
|
function adoptYieldedThenable(thenable) {
|
|
73
404
|
const expanded = thenable;
|
|
@@ -134,10 +465,12 @@ function runSyncReplayAsyncComponent(fn, props, ownerSignal) {
|
|
|
134
465
|
setCurrentConsumer(prevConsumer);
|
|
135
466
|
}
|
|
136
467
|
}
|
|
137
|
-
function createAsyncComponentWrapper(fn) {
|
|
468
|
+
function createAsyncComponentWrapper(fn, options) {
|
|
469
|
+
const deliveryOverride = options?.delivery;
|
|
138
470
|
const Inner = (props) => {
|
|
139
471
|
const scope = useScope();
|
|
140
472
|
const manager = usePauseSignalsManager();
|
|
473
|
+
const delivery = useDeliveryMode(deliveryOverride);
|
|
141
474
|
const fnSignalRef = useRef(void 0);
|
|
142
475
|
const propsRef = useRef(props);
|
|
143
476
|
propsRef.current = props;
|
|
@@ -153,18 +486,20 @@ function createAsyncComponentWrapper(fn) {
|
|
|
153
486
|
owned._isLazy = true;
|
|
154
487
|
fnSignalRef.current = sig = owned;
|
|
155
488
|
}
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
489
|
+
const subscribe = addRenderListener(sig, manager);
|
|
490
|
+
const stateDelivery = delivery === "state" ? useStateDeliveryState(sig) : null;
|
|
491
|
+
const value = readComponentSignal(sig, props);
|
|
492
|
+
if (stateDelivery !== null) {
|
|
493
|
+
useStateDelivery(stateDelivery, sig, subscribe, sig.updatedCount, manager);
|
|
494
|
+
} else {
|
|
495
|
+
const getSnapshot = () => sig.updatedCount;
|
|
496
|
+
usePausableStore(manager, sig, subscribe, getSnapshot);
|
|
497
|
+
}
|
|
498
|
+
return value;
|
|
164
499
|
};
|
|
165
500
|
const Outer = (props) => {
|
|
166
|
-
const hash =
|
|
167
|
-
return useMemo(() =>
|
|
501
|
+
const hash = usePropsHash(props);
|
|
502
|
+
return useMemo(() => createComponentElement(Inner, props), [hash]);
|
|
168
503
|
};
|
|
169
504
|
Object.defineProperty(Outer, SIGNALIUM_ASYNC_COMPONENT, { value: true, enumerable: false });
|
|
170
505
|
return Outer;
|
|
@@ -180,7 +515,7 @@ function ensureSsrScope() {
|
|
|
180
515
|
setRequestScopeGetter(() => getScope());
|
|
181
516
|
}
|
|
182
517
|
}
|
|
183
|
-
function component(fn) {
|
|
518
|
+
function component(fn, options) {
|
|
184
519
|
ensureSsrScope();
|
|
185
520
|
if (isAsyncFunctionWithoutTransform(fn)) {
|
|
186
521
|
throw new Error("signalium: `component(async (props) => { await ... })` requires the Signalium Babel preset (async transform).");
|
|
@@ -189,12 +524,14 @@ function component(fn) {
|
|
|
189
524
|
if (typeof window === "undefined") {
|
|
190
525
|
return createServerAsyncComponentWrapper(fn);
|
|
191
526
|
}
|
|
192
|
-
return createAsyncComponentWrapper(fn);
|
|
527
|
+
return createAsyncComponentWrapper(fn, options);
|
|
193
528
|
}
|
|
194
529
|
const syncFn = fn;
|
|
530
|
+
const deliveryOverride = options?.delivery;
|
|
195
531
|
const Component = (props) => {
|
|
196
532
|
const scope = useScope();
|
|
197
533
|
const manager = usePauseSignalsManager();
|
|
534
|
+
const delivery = useDeliveryMode(deliveryOverride);
|
|
198
535
|
const fnSignalRef = useRef(void 0);
|
|
199
536
|
const propsRef = useRef(props);
|
|
200
537
|
propsRef.current = props;
|
|
@@ -209,18 +546,20 @@ function component(fn) {
|
|
|
209
546
|
created._isLazy = true;
|
|
210
547
|
fnSignalRef.current = signal2 = created;
|
|
211
548
|
}
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
549
|
+
const subscribe = addRenderListener(signal2, manager);
|
|
550
|
+
const stateDelivery = delivery === "state" ? useStateDeliveryState(signal2) : null;
|
|
551
|
+
const value = readComponentSignal(signal2, props);
|
|
552
|
+
if (stateDelivery !== null) {
|
|
553
|
+
useStateDelivery(stateDelivery, signal2, subscribe, signal2.updatedCount, manager);
|
|
554
|
+
} else {
|
|
555
|
+
const getSnapshot = () => signal2.updatedCount;
|
|
556
|
+
usePausableStore(manager, signal2, subscribe, getSnapshot);
|
|
557
|
+
}
|
|
558
|
+
return value;
|
|
220
559
|
};
|
|
221
560
|
return (props) => {
|
|
222
|
-
const hash =
|
|
223
|
-
return useMemo(() =>
|
|
561
|
+
const hash = usePropsHash(props);
|
|
562
|
+
return useMemo(() => createComponentElement(Component, props), [hash]);
|
|
224
563
|
};
|
|
225
564
|
}
|
|
226
565
|
function useSignal(value, opts) {
|
|
@@ -230,30 +569,34 @@ function useSignal(value, opts) {
|
|
|
230
569
|
}
|
|
231
570
|
return ref.current;
|
|
232
571
|
}
|
|
233
|
-
function useSignalWithSuspension(signal2) {
|
|
572
|
+
function useSignalWithSuspension(signal2, options) {
|
|
234
573
|
const manager = usePauseSignalsManager();
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
574
|
+
const delivery = useDeliveryMode(options?.delivery);
|
|
575
|
+
const subscribe = addRenderListener(signal2, manager);
|
|
576
|
+
if (delivery === "state") {
|
|
577
|
+
const stateDelivery = useStateDeliveryState(signal2);
|
|
578
|
+
const value = signal2.value;
|
|
579
|
+
useStateDelivery(stateDelivery, signal2, subscribe, signal2.updatedCount, manager);
|
|
580
|
+
return value;
|
|
581
|
+
}
|
|
582
|
+
const getSnapshot = () => signal2.value;
|
|
583
|
+
return usePausableStore(manager, signal2, subscribe, getSnapshot);
|
|
241
584
|
}
|
|
242
|
-
function useReactiveShallow(fn) {
|
|
585
|
+
function useReactiveShallow(fn, options) {
|
|
243
586
|
if (getCurrentConsumer()) {
|
|
244
587
|
throw new Error("signalium: `useReactiveShallow` cannot be called inside a reactive function. Call your reactive function directly instead — it already participates in the signal graph.");
|
|
245
588
|
}
|
|
246
589
|
const [, def] = getReactiveFnAndDefinition(fn);
|
|
247
590
|
const scope = useScope() ?? getGlobalScope();
|
|
248
591
|
const signal2 = scope.get(def, []);
|
|
249
|
-
return useSignalWithSuspension(signal2);
|
|
592
|
+
return useSignalWithSuspension(signal2, options);
|
|
250
593
|
}
|
|
251
|
-
function useReactive(fn) {
|
|
594
|
+
function useReactive(fn, options) {
|
|
252
595
|
if (getCurrentConsumer()) {
|
|
253
596
|
throw new Error("signalium: `useReactive` cannot be called inside a reactive function. Call your reactive function directly instead — it already participates in the signal graph.");
|
|
254
597
|
}
|
|
255
598
|
const manager = usePauseSignalsManager();
|
|
256
|
-
const
|
|
599
|
+
const delivery = useDeliveryMode(options?.delivery);
|
|
257
600
|
const scope = useScope() ?? getGlobalScope();
|
|
258
601
|
const innerSignalRef = useRef(void 0);
|
|
259
602
|
const cloneSignalRef = useRef(void 0);
|
|
@@ -270,17 +613,21 @@ function useReactive(fn) {
|
|
|
270
613
|
});
|
|
271
614
|
}
|
|
272
615
|
const cloneSignal = cloneSignalRef.current;
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
616
|
+
const subscribe = addRenderListener(cloneSignal, manager);
|
|
617
|
+
if (delivery === "state") {
|
|
618
|
+
const stateDelivery = useStateDeliveryState(cloneSignal);
|
|
619
|
+
const value = cloneSignal.value;
|
|
620
|
+
useStateDelivery(stateDelivery, cloneSignal, subscribe, cloneSignal.updatedCount, manager);
|
|
621
|
+
return value;
|
|
622
|
+
}
|
|
623
|
+
const getSnapshot = () => cloneSignal.value;
|
|
624
|
+
return usePausableStore(manager, cloneSignal, subscribe, getSnapshot);
|
|
278
625
|
}
|
|
279
|
-
function useReactiveDeep(fn) {
|
|
626
|
+
function useReactiveDeep(fn, options) {
|
|
280
627
|
{
|
|
281
628
|
warnUseReactiveDeepOnce();
|
|
282
629
|
}
|
|
283
|
-
return useReactive(fn);
|
|
630
|
+
return useReactive(fn, options);
|
|
284
631
|
}
|
|
285
632
|
let _useReactiveDeepWarned = false;
|
|
286
633
|
function warnUseReactiveDeepOnce() {
|