@pumped-fn/lite-react 1.1.0 → 1.1.1
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 +7 -0
- package/README.md +20 -10
- package/dist/index.cjs +90 -50
- package/dist/index.d.cts +4 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +4 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +90 -50
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# @pumped-fn/lite-react
|
|
2
2
|
|
|
3
|
+
## 1.1.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 8ed17e7: - Fix watch and invalidation edge cases in `@pumped-fn/lite` by aligning `select()` with `Object.is`, snapshotting select listeners during notification, making watch option typing match the runtime contract, and surfacing invalidation-chain failures from `flush()` instead of leaking them as background rejections.
|
|
8
|
+
- Fix `@pumped-fn/lite-react` hook refresh behavior by keeping stale values visible during re-resolution, recomputing `useSelect` snapshots when selector or equality semantics change, tracking pending promises per controller, and suppressing non-Suspense `unhandledRejection` leaks on failed refreshes.
|
|
9
|
+
|
|
3
10
|
## 1.1.0
|
|
4
11
|
|
|
5
12
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @pumped-fn/lite-react
|
|
2
2
|
|
|
3
|
-
React bindings for `@pumped-fn/lite` with Suspense and
|
|
3
|
+
React bindings for `@pumped-fn/lite` with Suspense, ErrorBoundary integration, and stale-while-revalidate refreshes.
|
|
4
4
|
|
|
5
5
|
**Zero dependencies** · **<2KB bundle** · **React 18+**
|
|
6
6
|
|
|
@@ -20,12 +20,14 @@ sequenceDiagram
|
|
|
20
20
|
alt resolved
|
|
21
21
|
Controller-->>useAtom: value
|
|
22
22
|
useAtom->>Controller: subscribe to changes
|
|
23
|
-
else resolving
|
|
23
|
+
else resolving with stale value
|
|
24
|
+
Controller-->>useAtom: stale value
|
|
25
|
+
else resolving without value
|
|
24
26
|
useAtom-->>App: throw Promise (Suspense)
|
|
25
27
|
else failed
|
|
26
28
|
useAtom-->>App: throw Error (ErrorBoundary)
|
|
27
29
|
else idle
|
|
28
|
-
useAtom-->>App: throw
|
|
30
|
+
useAtom-->>App: throw Promise (Suspense)
|
|
29
31
|
end
|
|
30
32
|
```
|
|
31
33
|
|
|
@@ -37,19 +39,21 @@ flowchart TD
|
|
|
37
39
|
Hook --> State{ctrl.state?}
|
|
38
40
|
|
|
39
41
|
State -->|idle| AutoResolve[Auto-resolve + Throw Promise]
|
|
40
|
-
State -->|resolving|
|
|
42
|
+
State -->|resolving + stale value| Stale[Return stale value]
|
|
43
|
+
State -->|resolving + no value| Promise[Throw cached Promise]
|
|
41
44
|
State -->|resolved| Value[Return value]
|
|
42
45
|
State -->|failed| Stored[Throw stored error]
|
|
43
46
|
|
|
44
47
|
AutoResolve --> Suspense[Suspense catches]
|
|
45
48
|
Promise --> Suspense
|
|
49
|
+
Stale --> Render[Keep current UI]
|
|
46
50
|
Stored --> ErrorBoundary[ErrorBoundary catches]
|
|
47
51
|
```
|
|
48
52
|
|
|
49
53
|
| State | Hook Behavior |
|
|
50
54
|
|-------|---------------|
|
|
51
55
|
| `idle` | Auto-resolves and suspends — Suspense shows fallback |
|
|
52
|
-
| `resolving` |
|
|
56
|
+
| `resolving` | Returns stale value if available, otherwise throws cached promise |
|
|
53
57
|
| `resolved` | Returns value, subscribes to changes |
|
|
54
58
|
| `failed` | Throws stored error — ErrorBoundary catches |
|
|
55
59
|
|
|
@@ -99,6 +103,8 @@ const ctrl = useController(configAtom, { resolve: true })
|
|
|
99
103
|
ctrl.get() // safe - Suspense guarantees resolved state
|
|
100
104
|
```
|
|
101
105
|
|
|
106
|
+
While a controller is re-resolving, `{ resolve: true }` keeps suspending until the controller settles.
|
|
107
|
+
|
|
102
108
|
### useAtom
|
|
103
109
|
|
|
104
110
|
Subscribe to atom value with Suspense integration.
|
|
@@ -125,6 +131,7 @@ For manual loading/error state handling without Suspense:
|
|
|
125
131
|
function UserProfile() {
|
|
126
132
|
const { data, loading, error, controller } = useAtom(userAtom, { suspense: false })
|
|
127
133
|
|
|
134
|
+
if (loading && data) return <div>Refreshing {data.name}...</div>
|
|
128
135
|
if (loading) return <div>Loading...</div>
|
|
129
136
|
if (error) return <div>Error: {error.message}</div>
|
|
130
137
|
if (!data) return <div>Not loaded</div>
|
|
@@ -150,6 +157,8 @@ const { data, loading, error } = useAtom(userAtom, { suspense: false, resolve: t
|
|
|
150
157
|
| `{ suspense: false }` | Returns state object, no auto-resolve |
|
|
151
158
|
| `{ suspense: false, resolve: true }` | Returns state object, auto-resolves on mount |
|
|
152
159
|
|
|
160
|
+
While `loading` is `true`, `data` may still contain the last resolved value during a refresh.
|
|
161
|
+
|
|
153
162
|
### useSelect
|
|
154
163
|
|
|
155
164
|
Fine-grained selection — only re-renders when selected value changes.
|
|
@@ -161,7 +170,7 @@ const count = useSelect(todosAtom, todos => todos.length, (a, b) => a === b)
|
|
|
161
170
|
|
|
162
171
|
## Invalidation
|
|
163
172
|
|
|
164
|
-
When an atom is invalidated,
|
|
173
|
+
When an atom is invalidated, `useAtom` and `useSelect` keep rendering the last value while re-resolving:
|
|
165
174
|
|
|
166
175
|
```mermaid
|
|
167
176
|
sequenceDiagram
|
|
@@ -174,14 +183,16 @@ sequenceDiagram
|
|
|
174
183
|
|
|
175
184
|
Note over Controller: ctrl.invalidate()
|
|
176
185
|
Controller->>Controller: state = resolving
|
|
177
|
-
useAtom-->>Component:
|
|
178
|
-
Note over Component:
|
|
186
|
+
useAtom-->>Component: stale value
|
|
187
|
+
Note over Component: current UI stays visible
|
|
179
188
|
|
|
180
189
|
Controller->>Controller: factory runs
|
|
181
190
|
Controller->>Controller: state = resolved
|
|
182
191
|
useAtom->>Component: re-render (new value)
|
|
183
192
|
```
|
|
184
193
|
|
|
194
|
+
`useController(atom, { resolve: true })` is different: it suspends until the controller settles again.
|
|
195
|
+
|
|
185
196
|
## Testing
|
|
186
197
|
|
|
187
198
|
Use presets for test isolation:
|
|
@@ -204,10 +215,9 @@ render(
|
|
|
204
215
|
|
|
205
216
|
## SSR
|
|
206
217
|
|
|
207
|
-
SSR-compatible
|
|
218
|
+
SSR-compatible when request-scoped atoms are resolved before rendering:
|
|
208
219
|
|
|
209
220
|
- No side effects on import
|
|
210
|
-
- Uses `useSyncExternalStore` with server snapshot
|
|
211
221
|
- Scope passed as prop (no global state)
|
|
212
222
|
|
|
213
223
|
```tsx
|
package/dist/index.cjs
CHANGED
|
@@ -27,12 +27,28 @@ function ScopeProvider({ scope, children }) {
|
|
|
27
27
|
//#endregion
|
|
28
28
|
//#region src/hooks.ts
|
|
29
29
|
const pendingPromises = /* @__PURE__ */ new WeakMap();
|
|
30
|
-
function getOrCreatePendingPromise(
|
|
31
|
-
let pending = pendingPromises.get(
|
|
30
|
+
function getOrCreatePendingPromise(ctrl) {
|
|
31
|
+
let pending = pendingPromises.get(ctrl);
|
|
32
32
|
if (!pending) {
|
|
33
|
-
pending =
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
if (ctrl.state === "resolving") pending = new Promise((resolve, reject) => {
|
|
34
|
+
const unsub = ctrl.on("*", () => {
|
|
35
|
+
if (ctrl.state === "resolved") {
|
|
36
|
+
unsub();
|
|
37
|
+
resolve(ctrl.get());
|
|
38
|
+
} else if (ctrl.state === "failed") {
|
|
39
|
+
unsub();
|
|
40
|
+
try {
|
|
41
|
+
ctrl.get();
|
|
42
|
+
} catch (e) {
|
|
43
|
+
reject(e);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
else pending = ctrl.resolve();
|
|
49
|
+
pendingPromises.set(ctrl, pending);
|
|
50
|
+
pending.catch(() => {});
|
|
51
|
+
pending.then(() => pendingPromises.delete(ctrl), () => pendingPromises.delete(ctrl));
|
|
36
52
|
}
|
|
37
53
|
return pending;
|
|
38
54
|
}
|
|
@@ -44,8 +60,10 @@ function getOrCreatePendingPromise(atom$1, ctrl) {
|
|
|
44
60
|
*
|
|
45
61
|
* @example
|
|
46
62
|
* ```tsx
|
|
47
|
-
*
|
|
48
|
-
*
|
|
63
|
+
* function MyComponent() {
|
|
64
|
+
* const scope = useScope()
|
|
65
|
+
* const handleClick = () => scope.resolve(myAtom)
|
|
66
|
+
* }
|
|
49
67
|
* ```
|
|
50
68
|
*/
|
|
51
69
|
function useScope() {
|
|
@@ -57,62 +75,76 @@ function useController(atom$1, options) {
|
|
|
57
75
|
const scope = useScope();
|
|
58
76
|
const ctrl = (0, react.useMemo)(() => scope.controller(atom$1), [scope, atom$1]);
|
|
59
77
|
if (options?.resolve) {
|
|
60
|
-
if (ctrl.state === "idle" || ctrl.state === "resolving") throw getOrCreatePendingPromise(
|
|
78
|
+
if (ctrl.state === "idle" || ctrl.state === "resolving") throw getOrCreatePendingPromise(ctrl);
|
|
61
79
|
if (ctrl.state === "failed") throw ctrl.get();
|
|
62
80
|
}
|
|
63
81
|
return ctrl;
|
|
64
82
|
}
|
|
65
83
|
function useAtom(atom$1, options) {
|
|
66
84
|
const ctrl = useController(atom$1);
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
const autoResolve = options?.resolve !== false;
|
|
71
|
-
const getSnapshot = (0, react.useCallback)(() => {
|
|
72
|
-
if (ctrl.state === "idle") {
|
|
73
|
-
if (autoResolve) throw getOrCreatePendingPromise(atomRef.current, ctrl);
|
|
74
|
-
throw new Error("Atom is not resolved. Set resolve: true or resolve the atom before rendering.");
|
|
75
|
-
}
|
|
76
|
-
if (ctrl.state === "resolving") throw getOrCreatePendingPromise(atomRef.current, ctrl);
|
|
77
|
-
if (ctrl.state === "failed") throw ctrl.get();
|
|
78
|
-
return ctrl.get();
|
|
79
|
-
}, [ctrl, autoResolve]);
|
|
80
|
-
return (0, react.useSyncExternalStore)((0, react.useCallback)((onStoreChange) => ctrl.on("resolved", onStoreChange), [ctrl]), getSnapshot, getSnapshot);
|
|
81
|
-
}
|
|
82
|
-
function useAtomState(atom$1, ctrl, autoResolve) {
|
|
85
|
+
const ctrlState = ctrl.state;
|
|
86
|
+
const isSuspense = options?.suspense !== false;
|
|
87
|
+
const autoResolve = isSuspense ? options?.resolve !== false : !!options?.resolve;
|
|
83
88
|
const stateCache = (0, react.useRef)(null);
|
|
84
89
|
(0, react.useEffect)(() => {
|
|
85
|
-
if (
|
|
90
|
+
if (!isSuspense && (ctrlState === "resolving" || autoResolve && ctrlState === "idle")) getOrCreatePendingPromise(ctrl).catch(() => {});
|
|
86
91
|
}, [
|
|
87
|
-
atom$1,
|
|
88
92
|
ctrl,
|
|
89
|
-
|
|
93
|
+
ctrlState,
|
|
94
|
+
autoResolve,
|
|
95
|
+
isSuspense
|
|
90
96
|
]);
|
|
91
97
|
const getSnapshot = (0, react.useCallback)(() => {
|
|
98
|
+
if (isSuspense) {
|
|
99
|
+
if (ctrl.state === "idle") {
|
|
100
|
+
if (autoResolve) throw getOrCreatePendingPromise(ctrl);
|
|
101
|
+
throw new Error("Atom is not resolved. Set resolve: true or resolve the atom before rendering.");
|
|
102
|
+
}
|
|
103
|
+
if (ctrl.state === "failed") throw ctrl.get();
|
|
104
|
+
try {
|
|
105
|
+
return ctrl.get();
|
|
106
|
+
} catch {
|
|
107
|
+
throw getOrCreatePendingPromise(ctrl);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
92
110
|
let data;
|
|
93
111
|
let error;
|
|
94
|
-
if (ctrl.state === "resolved"
|
|
112
|
+
if (ctrl.state === "resolved" || ctrl.state === "resolving") try {
|
|
113
|
+
data = ctrl.get();
|
|
114
|
+
} catch {}
|
|
95
115
|
else if (ctrl.state === "failed") try {
|
|
96
116
|
ctrl.get();
|
|
97
117
|
} catch (e) {
|
|
98
118
|
error = e instanceof Error ? e : new Error(String(e));
|
|
99
119
|
}
|
|
100
|
-
|
|
120
|
+
const loading = ctrl.state === "resolving" || autoResolve && ctrl.state === "idle";
|
|
121
|
+
if (stateCache.current && stateCache.current.ctrl === ctrl && stateCache.current.ctrlState === ctrl.state && stateCache.current.data === data && stateCache.current.error === error && stateCache.current.loading === loading) return stateCache.current.result;
|
|
101
122
|
const result = {
|
|
102
123
|
data,
|
|
103
|
-
loading
|
|
124
|
+
loading,
|
|
104
125
|
error,
|
|
105
126
|
controller: ctrl
|
|
106
127
|
};
|
|
107
128
|
stateCache.current = {
|
|
129
|
+
ctrl,
|
|
108
130
|
ctrlState: ctrl.state,
|
|
109
131
|
data,
|
|
110
132
|
error,
|
|
133
|
+
loading,
|
|
111
134
|
result
|
|
112
135
|
};
|
|
113
136
|
return result;
|
|
114
|
-
}, [
|
|
115
|
-
|
|
137
|
+
}, [
|
|
138
|
+
ctrl,
|
|
139
|
+
autoResolve,
|
|
140
|
+
isSuspense
|
|
141
|
+
]);
|
|
142
|
+
return (0, react.useSyncExternalStore)((0, react.useCallback)((onStoreChange) => {
|
|
143
|
+
return ctrl.on("*", () => {
|
|
144
|
+
if (!isSuspense && ctrl.state === "resolving") getOrCreatePendingPromise(ctrl).catch(() => {});
|
|
145
|
+
onStoreChange();
|
|
146
|
+
});
|
|
147
|
+
}, [ctrl, isSuspense]), getSnapshot, getSnapshot);
|
|
116
148
|
}
|
|
117
149
|
/**
|
|
118
150
|
* Select a derived value from an atom with fine-grained reactivity.
|
|
@@ -129,33 +161,41 @@ function useAtomState(atom$1, ctrl, autoResolve) {
|
|
|
129
161
|
* ```
|
|
130
162
|
*/
|
|
131
163
|
function useSelect(atom$1, selector, eq) {
|
|
132
|
-
const scope = useScope();
|
|
133
164
|
const ctrl = useController(atom$1);
|
|
134
|
-
const atomRef = (0, react.useRef)(atom$1);
|
|
135
|
-
atomRef.current = atom$1;
|
|
136
165
|
const selectorRef = (0, react.useRef)(selector);
|
|
137
166
|
const eqRef = (0, react.useRef)(eq);
|
|
138
167
|
selectorRef.current = selector;
|
|
139
168
|
eqRef.current = eq;
|
|
140
|
-
const
|
|
141
|
-
const getOrCreateHandle = (0, react.useCallback)(() => {
|
|
142
|
-
if (!handleRef.current || handleRef.current.scope !== scope || handleRef.current.atom !== atom$1) handleRef.current = {
|
|
143
|
-
scope,
|
|
144
|
-
atom: atom$1,
|
|
145
|
-
handle: scope.select(atom$1, selectorRef.current, { eq: eqRef.current })
|
|
146
|
-
};
|
|
147
|
-
return handleRef.current.handle;
|
|
148
|
-
}, [scope, atom$1]);
|
|
169
|
+
const selectionCache = (0, react.useRef)(null);
|
|
149
170
|
const getSnapshot = (0, react.useCallback)(() => {
|
|
150
171
|
const state = ctrl.state;
|
|
151
|
-
if (state === "idle"
|
|
172
|
+
if (state === "idle") throw getOrCreatePendingPromise(ctrl);
|
|
152
173
|
if (state === "failed") throw ctrl.get();
|
|
153
|
-
|
|
154
|
-
|
|
174
|
+
let value;
|
|
175
|
+
try {
|
|
176
|
+
value = ctrl.get();
|
|
177
|
+
} catch {
|
|
178
|
+
throw getOrCreatePendingPromise(ctrl);
|
|
179
|
+
}
|
|
180
|
+
const nextSelector = selectorRef.current;
|
|
181
|
+
const nextEq = eqRef.current;
|
|
182
|
+
const current = selectionCache.current;
|
|
183
|
+
if (current && current.ctrl === ctrl && current.ctrlState === state && Object.is(current.source, value) && current.selector === nextSelector && current.eq === nextEq) return current.value;
|
|
184
|
+
const nextValue = nextSelector(value);
|
|
185
|
+
const selectedValue = current && current.ctrl === ctrl && current.selector === nextSelector && (nextEq ?? Object.is)(current.value, nextValue) ? current.value : nextValue;
|
|
186
|
+
selectionCache.current = {
|
|
187
|
+
ctrl,
|
|
188
|
+
ctrlState: state,
|
|
189
|
+
source: value,
|
|
190
|
+
selector: nextSelector,
|
|
191
|
+
eq: nextEq,
|
|
192
|
+
value: selectedValue
|
|
193
|
+
};
|
|
194
|
+
return selectedValue;
|
|
195
|
+
}, [ctrl]);
|
|
155
196
|
return (0, react.useSyncExternalStore)((0, react.useCallback)((onStoreChange) => {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}, [ctrl, getOrCreateHandle]), getSnapshot, getSnapshot);
|
|
197
|
+
return ctrl.on("*", onStoreChange);
|
|
198
|
+
}, [ctrl]), getSnapshot, getSnapshot);
|
|
159
199
|
}
|
|
160
200
|
|
|
161
201
|
//#endregion
|
package/dist/index.d.cts
CHANGED
|
@@ -56,8 +56,10 @@ interface UseControllerOptions {
|
|
|
56
56
|
*
|
|
57
57
|
* @example
|
|
58
58
|
* ```tsx
|
|
59
|
-
*
|
|
60
|
-
*
|
|
59
|
+
* function MyComponent() {
|
|
60
|
+
* const scope = useScope()
|
|
61
|
+
* const handleClick = () => scope.resolve(myAtom)
|
|
62
|
+
* }
|
|
61
63
|
* ```
|
|
62
64
|
*/
|
|
63
65
|
declare function useScope(): Lite$1.Scope;
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/context.tsx","../src/hooks.ts"],"sourcesContent":[],"mappings":";;;;;;;;;cAMM,cAAY,MAAA,CAAA,QAAA,MAAA,CAAA;AALyB,UAOjC,kBAAA,CAFiD;EAEjD,KAAA,EACD,MAAA,CAAK,KADJ;EAeD,QAAA,EAbG,SAaU;;;;;;;;;ACtBqB;AAGX;AAMF;AAMqC,iBDO1D,aAAA,CCLa;EAAA,KAAA;EAAA;AAAA,CAAA,EDKsB,kBCLtB,CAAA,EDKwC,kBAAA,CAAA,GAAA,CAAA,OCLxC;;;UAdZ,sBAAA;;;;;ADHiC,UCSjC,oBAAA,CDJQ;EAER,QAAA,EAAA,KAAA;EAeD;EAAgB,OAAA,CAAA,EAAA,OAAA;;KCPpB,cAAA,GAAiB,sBDOsB,GCPG,oBDOH;UCLlC,YDKoD,CAAA,CAAA,CAAA,CAAA;EAAA,IAAA,ECJtD,CDIsD,GAAA,SAAA;;SCFrD;cACK,MAAA,CAAK,WAAW;AArBa;AAGX,UAqBtB,oBAAA,CAfoB;EAMzB,OAAA,CAAA,EAAA,OAAc;AAAgD;;;;;;AAMtC;AAGC;
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/context.tsx","../src/hooks.ts"],"sourcesContent":[],"mappings":";;;;;;;;;cAMM,cAAY,MAAA,CAAA,QAAA,MAAA,CAAA;AALyB,UAOjC,kBAAA,CAFiD;EAEjD,KAAA,EACD,MAAA,CAAK,KADJ;EAeD,QAAA,EAbG,SAaU;;;;;;;;;ACtBqB;AAGX;AAMF;AAMqC,iBDO1D,aAAA,CCLa;EAAA,KAAA;EAAA;AAAA,CAAA,EDKsB,kBCLtB,CAAA,EDKwC,kBAAA,CAAA,GAAA,CAAA,OCLxC;;;UAdZ,sBAAA;;;;;ADHiC,UCSjC,oBAAA,CDJQ;EAER,QAAA,EAAA,KAAA;EAeD;EAAgB,OAAA,CAAA,EAAA,OAAA;;KCPpB,cAAA,GAAiB,sBDOsB,GCPG,oBDOH;UCLlC,YDKoD,CAAA,CAAA,CAAA,CAAA;EAAA,IAAA,ECJtD,CDIsD,GAAA,SAAA;;SCFrD;cACK,MAAA,CAAK,WAAW;AArBa;AAGX,UAqBtB,oBAAA,CAfoB;EAMzB,OAAA,CAAA,EAAA,OAAc;AAAgD;;;;;;AAMtC;AAGC;AAgDC;;;;;;AAiB+B;iBAjBrD,QAAA,CAAA,CAkBiC,EAlBrB,MAAA,CAAK,KAkBgB;;;;;;AAAmD;;;;iBADpF,aA2BiC,CAAA,CAAA,CAAA,CAAA,IAAA,EA3BV,MAAA,CAAK,IA2BK,CA3BA,CA2BA,CAAA,CAAA,EA3BK,MAAA,CAAK,UA2BV,CA3BqB,CA2BrB,CAAA;AAAA,iBA1BjC,aA2BO,CAAA,CAAA,CAAA,CAAA,IAAA,EA3BgB,MAAA,CAAK,IA2BrB,CA3B0B,CA2B1B,CAAA,EAAA,OAAA,EA3BuC,oBA2BvC,CAAA,EA3B8D,MAAA,CAAK,UA2BnE,CA3B8E,CA2B9E,CAAA;;;;;;AAA2D;;;;iBADlE,OAE4E,CAAA,CAAA,CAAA,CAAA,IAAA,EAF3D,MAAA,CAAK,IAEsD,CAFjD,CAEiD,CAAA,CAAA,EAF5C,CAE4C;iBAD5E,OAC+D,CAAA,CAAA,CAAA,CAAA,IAAA,EAD9C,MAAA,CAAK,IACyC,CADpC,CACoC,CAAA,EAAA,OAAA,EADvB,sBACuB,CAAA,EADE,CACF;iBAA/D,OAA2E,CAAA,CAAA,CAAA,CAAA,IAAA,EAA1D,MAAA,CAAK,IAAqD,CAAhD,CAAgD,CAAA,EAAA,OAAA,EAAnC,oBAAmC,CAAA,EAAZ,YAAY,CAAC,CAAD,CAAA;AAAA;;;;;;;;;;;;;;iBA0G3E,sBACD,MAAA,CAAK,KAAK,sBACE,MAAM,YACf,MAAM,gBACd"}
|
package/dist/index.d.mts
CHANGED
|
@@ -56,8 +56,10 @@ interface UseControllerOptions {
|
|
|
56
56
|
*
|
|
57
57
|
* @example
|
|
58
58
|
* ```tsx
|
|
59
|
-
*
|
|
60
|
-
*
|
|
59
|
+
* function MyComponent() {
|
|
60
|
+
* const scope = useScope()
|
|
61
|
+
* const handleClick = () => scope.resolve(myAtom)
|
|
62
|
+
* }
|
|
61
63
|
* ```
|
|
62
64
|
*/
|
|
63
65
|
declare function useScope(): Lite$1.Scope;
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/context.tsx","../src/hooks.ts"],"sourcesContent":[],"mappings":";;;;;;;;;cAMM,cAAY,MAAA,CAAA,QAAA,MAAA,CAAA;AALyB,UAOjC,kBAAA,CAFiD;EAEjD,KAAA,EACD,MAAA,CAAK,KADJ;EAeD,QAAA,EAbG,SAaU;;;;;;;;;ACtBqB;AAGX;AAMF;AAMqC,iBDO1D,aAAA,CCLa;EAAA,KAAA;EAAA;AAAA,CAAA,EDKsB,kBCLtB,CAAA,EDKwC,kBAAA,CAAA,GAAA,CAAA,OCLxC;;;UAdZ,sBAAA;;;;;ADHiC,UCSjC,oBAAA,CDJQ;EAER,QAAA,EAAA,KAAA;EAeD;EAAgB,OAAA,CAAA,EAAA,OAAA;;KCPpB,cAAA,GAAiB,sBDOsB,GCPG,oBDOH;UCLlC,YDKoD,CAAA,CAAA,CAAA,CAAA;EAAA,IAAA,ECJtD,CDIsD,GAAA,SAAA;;SCFrD;cACK,MAAA,CAAK,WAAW;AArBa;AAGX,UAqBtB,oBAAA,CAfoB;EAMzB,OAAA,CAAA,EAAA,OAAc;AAAgD;;;;;;AAMtC;AAGC;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/context.tsx","../src/hooks.ts"],"sourcesContent":[],"mappings":";;;;;;;;;cAMM,cAAY,MAAA,CAAA,QAAA,MAAA,CAAA;AALyB,UAOjC,kBAAA,CAFiD;EAEjD,KAAA,EACD,MAAA,CAAK,KADJ;EAeD,QAAA,EAbG,SAaU;;;;;;;;;ACtBqB;AAGX;AAMF;AAMqC,iBDO1D,aAAA,CCLa;EAAA,KAAA;EAAA;AAAA,CAAA,EDKsB,kBCLtB,CAAA,EDKwC,kBAAA,CAAA,GAAA,CAAA,OCLxC;;;UAdZ,sBAAA;;;;;ADHiC,UCSjC,oBAAA,CDJQ;EAER,QAAA,EAAA,KAAA;EAeD;EAAgB,OAAA,CAAA,EAAA,OAAA;;KCPpB,cAAA,GAAiB,sBDOsB,GCPG,oBDOH;UCLlC,YDKoD,CAAA,CAAA,CAAA,CAAA;EAAA,IAAA,ECJtD,CDIsD,GAAA,SAAA;;SCFrD;cACK,MAAA,CAAK,WAAW;AArBa;AAGX,UAqBtB,oBAAA,CAfoB;EAMzB,OAAA,CAAA,EAAA,OAAc;AAAgD;;;;;;AAMtC;AAGC;AAgDC;;;;;;AAiB+B;iBAjBrD,QAAA,CAAA,CAkBiC,EAlBrB,MAAA,CAAK,KAkBgB;;;;;;AAAmD;;;;iBADpF,aA2BiC,CAAA,CAAA,CAAA,CAAA,IAAA,EA3BV,MAAA,CAAK,IA2BK,CA3BA,CA2BA,CAAA,CAAA,EA3BK,MAAA,CAAK,UA2BV,CA3BqB,CA2BrB,CAAA;AAAA,iBA1BjC,aA2BO,CAAA,CAAA,CAAA,CAAA,IAAA,EA3BgB,MAAA,CAAK,IA2BrB,CA3B0B,CA2B1B,CAAA,EAAA,OAAA,EA3BuC,oBA2BvC,CAAA,EA3B8D,MAAA,CAAK,UA2BnE,CA3B8E,CA2B9E,CAAA;;;;;;AAA2D;;;;iBADlE,OAE4E,CAAA,CAAA,CAAA,CAAA,IAAA,EAF3D,MAAA,CAAK,IAEsD,CAFjD,CAEiD,CAAA,CAAA,EAF5C,CAE4C;iBAD5E,OAC+D,CAAA,CAAA,CAAA,CAAA,IAAA,EAD9C,MAAA,CAAK,IACyC,CADpC,CACoC,CAAA,EAAA,OAAA,EADvB,sBACuB,CAAA,EADE,CACF;iBAA/D,OAA2E,CAAA,CAAA,CAAA,CAAA,IAAA,EAA1D,MAAA,CAAK,IAAqD,CAAhD,CAAgD,CAAA,EAAA,OAAA,EAAnC,oBAAmC,CAAA,EAAZ,YAAY,CAAC,CAAD,CAAA;AAAA;;;;;;;;;;;;;;iBA0G3E,sBACD,MAAA,CAAK,KAAK,sBACE,MAAM,YACf,MAAM,gBACd"}
|
package/dist/index.mjs
CHANGED
|
@@ -27,12 +27,28 @@ function ScopeProvider({ scope, children }) {
|
|
|
27
27
|
//#endregion
|
|
28
28
|
//#region src/hooks.ts
|
|
29
29
|
const pendingPromises = /* @__PURE__ */ new WeakMap();
|
|
30
|
-
function getOrCreatePendingPromise(
|
|
31
|
-
let pending = pendingPromises.get(
|
|
30
|
+
function getOrCreatePendingPromise(ctrl) {
|
|
31
|
+
let pending = pendingPromises.get(ctrl);
|
|
32
32
|
if (!pending) {
|
|
33
|
-
pending =
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
if (ctrl.state === "resolving") pending = new Promise((resolve, reject) => {
|
|
34
|
+
const unsub = ctrl.on("*", () => {
|
|
35
|
+
if (ctrl.state === "resolved") {
|
|
36
|
+
unsub();
|
|
37
|
+
resolve(ctrl.get());
|
|
38
|
+
} else if (ctrl.state === "failed") {
|
|
39
|
+
unsub();
|
|
40
|
+
try {
|
|
41
|
+
ctrl.get();
|
|
42
|
+
} catch (e) {
|
|
43
|
+
reject(e);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
else pending = ctrl.resolve();
|
|
49
|
+
pendingPromises.set(ctrl, pending);
|
|
50
|
+
pending.catch(() => {});
|
|
51
|
+
pending.then(() => pendingPromises.delete(ctrl), () => pendingPromises.delete(ctrl));
|
|
36
52
|
}
|
|
37
53
|
return pending;
|
|
38
54
|
}
|
|
@@ -44,8 +60,10 @@ function getOrCreatePendingPromise(atom$1, ctrl) {
|
|
|
44
60
|
*
|
|
45
61
|
* @example
|
|
46
62
|
* ```tsx
|
|
47
|
-
*
|
|
48
|
-
*
|
|
63
|
+
* function MyComponent() {
|
|
64
|
+
* const scope = useScope()
|
|
65
|
+
* const handleClick = () => scope.resolve(myAtom)
|
|
66
|
+
* }
|
|
49
67
|
* ```
|
|
50
68
|
*/
|
|
51
69
|
function useScope() {
|
|
@@ -57,62 +75,76 @@ function useController(atom$1, options) {
|
|
|
57
75
|
const scope = useScope();
|
|
58
76
|
const ctrl = useMemo(() => scope.controller(atom$1), [scope, atom$1]);
|
|
59
77
|
if (options?.resolve) {
|
|
60
|
-
if (ctrl.state === "idle" || ctrl.state === "resolving") throw getOrCreatePendingPromise(
|
|
78
|
+
if (ctrl.state === "idle" || ctrl.state === "resolving") throw getOrCreatePendingPromise(ctrl);
|
|
61
79
|
if (ctrl.state === "failed") throw ctrl.get();
|
|
62
80
|
}
|
|
63
81
|
return ctrl;
|
|
64
82
|
}
|
|
65
83
|
function useAtom(atom$1, options) {
|
|
66
84
|
const ctrl = useController(atom$1);
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
const autoResolve = options?.resolve !== false;
|
|
71
|
-
const getSnapshot = useCallback(() => {
|
|
72
|
-
if (ctrl.state === "idle") {
|
|
73
|
-
if (autoResolve) throw getOrCreatePendingPromise(atomRef.current, ctrl);
|
|
74
|
-
throw new Error("Atom is not resolved. Set resolve: true or resolve the atom before rendering.");
|
|
75
|
-
}
|
|
76
|
-
if (ctrl.state === "resolving") throw getOrCreatePendingPromise(atomRef.current, ctrl);
|
|
77
|
-
if (ctrl.state === "failed") throw ctrl.get();
|
|
78
|
-
return ctrl.get();
|
|
79
|
-
}, [ctrl, autoResolve]);
|
|
80
|
-
return useSyncExternalStore(useCallback((onStoreChange) => ctrl.on("resolved", onStoreChange), [ctrl]), getSnapshot, getSnapshot);
|
|
81
|
-
}
|
|
82
|
-
function useAtomState(atom$1, ctrl, autoResolve) {
|
|
85
|
+
const ctrlState = ctrl.state;
|
|
86
|
+
const isSuspense = options?.suspense !== false;
|
|
87
|
+
const autoResolve = isSuspense ? options?.resolve !== false : !!options?.resolve;
|
|
83
88
|
const stateCache = useRef(null);
|
|
84
89
|
useEffect(() => {
|
|
85
|
-
if (
|
|
90
|
+
if (!isSuspense && (ctrlState === "resolving" || autoResolve && ctrlState === "idle")) getOrCreatePendingPromise(ctrl).catch(() => {});
|
|
86
91
|
}, [
|
|
87
|
-
atom$1,
|
|
88
92
|
ctrl,
|
|
89
|
-
|
|
93
|
+
ctrlState,
|
|
94
|
+
autoResolve,
|
|
95
|
+
isSuspense
|
|
90
96
|
]);
|
|
91
97
|
const getSnapshot = useCallback(() => {
|
|
98
|
+
if (isSuspense) {
|
|
99
|
+
if (ctrl.state === "idle") {
|
|
100
|
+
if (autoResolve) throw getOrCreatePendingPromise(ctrl);
|
|
101
|
+
throw new Error("Atom is not resolved. Set resolve: true or resolve the atom before rendering.");
|
|
102
|
+
}
|
|
103
|
+
if (ctrl.state === "failed") throw ctrl.get();
|
|
104
|
+
try {
|
|
105
|
+
return ctrl.get();
|
|
106
|
+
} catch {
|
|
107
|
+
throw getOrCreatePendingPromise(ctrl);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
92
110
|
let data;
|
|
93
111
|
let error;
|
|
94
|
-
if (ctrl.state === "resolved"
|
|
112
|
+
if (ctrl.state === "resolved" || ctrl.state === "resolving") try {
|
|
113
|
+
data = ctrl.get();
|
|
114
|
+
} catch {}
|
|
95
115
|
else if (ctrl.state === "failed") try {
|
|
96
116
|
ctrl.get();
|
|
97
117
|
} catch (e) {
|
|
98
118
|
error = e instanceof Error ? e : new Error(String(e));
|
|
99
119
|
}
|
|
100
|
-
|
|
120
|
+
const loading = ctrl.state === "resolving" || autoResolve && ctrl.state === "idle";
|
|
121
|
+
if (stateCache.current && stateCache.current.ctrl === ctrl && stateCache.current.ctrlState === ctrl.state && stateCache.current.data === data && stateCache.current.error === error && stateCache.current.loading === loading) return stateCache.current.result;
|
|
101
122
|
const result = {
|
|
102
123
|
data,
|
|
103
|
-
loading
|
|
124
|
+
loading,
|
|
104
125
|
error,
|
|
105
126
|
controller: ctrl
|
|
106
127
|
};
|
|
107
128
|
stateCache.current = {
|
|
129
|
+
ctrl,
|
|
108
130
|
ctrlState: ctrl.state,
|
|
109
131
|
data,
|
|
110
132
|
error,
|
|
133
|
+
loading,
|
|
111
134
|
result
|
|
112
135
|
};
|
|
113
136
|
return result;
|
|
114
|
-
}, [
|
|
115
|
-
|
|
137
|
+
}, [
|
|
138
|
+
ctrl,
|
|
139
|
+
autoResolve,
|
|
140
|
+
isSuspense
|
|
141
|
+
]);
|
|
142
|
+
return useSyncExternalStore(useCallback((onStoreChange) => {
|
|
143
|
+
return ctrl.on("*", () => {
|
|
144
|
+
if (!isSuspense && ctrl.state === "resolving") getOrCreatePendingPromise(ctrl).catch(() => {});
|
|
145
|
+
onStoreChange();
|
|
146
|
+
});
|
|
147
|
+
}, [ctrl, isSuspense]), getSnapshot, getSnapshot);
|
|
116
148
|
}
|
|
117
149
|
/**
|
|
118
150
|
* Select a derived value from an atom with fine-grained reactivity.
|
|
@@ -129,33 +161,41 @@ function useAtomState(atom$1, ctrl, autoResolve) {
|
|
|
129
161
|
* ```
|
|
130
162
|
*/
|
|
131
163
|
function useSelect(atom$1, selector, eq) {
|
|
132
|
-
const scope = useScope();
|
|
133
164
|
const ctrl = useController(atom$1);
|
|
134
|
-
const atomRef = useRef(atom$1);
|
|
135
|
-
atomRef.current = atom$1;
|
|
136
165
|
const selectorRef = useRef(selector);
|
|
137
166
|
const eqRef = useRef(eq);
|
|
138
167
|
selectorRef.current = selector;
|
|
139
168
|
eqRef.current = eq;
|
|
140
|
-
const
|
|
141
|
-
const getOrCreateHandle = useCallback(() => {
|
|
142
|
-
if (!handleRef.current || handleRef.current.scope !== scope || handleRef.current.atom !== atom$1) handleRef.current = {
|
|
143
|
-
scope,
|
|
144
|
-
atom: atom$1,
|
|
145
|
-
handle: scope.select(atom$1, selectorRef.current, { eq: eqRef.current })
|
|
146
|
-
};
|
|
147
|
-
return handleRef.current.handle;
|
|
148
|
-
}, [scope, atom$1]);
|
|
169
|
+
const selectionCache = useRef(null);
|
|
149
170
|
const getSnapshot = useCallback(() => {
|
|
150
171
|
const state = ctrl.state;
|
|
151
|
-
if (state === "idle"
|
|
172
|
+
if (state === "idle") throw getOrCreatePendingPromise(ctrl);
|
|
152
173
|
if (state === "failed") throw ctrl.get();
|
|
153
|
-
|
|
154
|
-
|
|
174
|
+
let value;
|
|
175
|
+
try {
|
|
176
|
+
value = ctrl.get();
|
|
177
|
+
} catch {
|
|
178
|
+
throw getOrCreatePendingPromise(ctrl);
|
|
179
|
+
}
|
|
180
|
+
const nextSelector = selectorRef.current;
|
|
181
|
+
const nextEq = eqRef.current;
|
|
182
|
+
const current = selectionCache.current;
|
|
183
|
+
if (current && current.ctrl === ctrl && current.ctrlState === state && Object.is(current.source, value) && current.selector === nextSelector && current.eq === nextEq) return current.value;
|
|
184
|
+
const nextValue = nextSelector(value);
|
|
185
|
+
const selectedValue = current && current.ctrl === ctrl && current.selector === nextSelector && (nextEq ?? Object.is)(current.value, nextValue) ? current.value : nextValue;
|
|
186
|
+
selectionCache.current = {
|
|
187
|
+
ctrl,
|
|
188
|
+
ctrlState: state,
|
|
189
|
+
source: value,
|
|
190
|
+
selector: nextSelector,
|
|
191
|
+
eq: nextEq,
|
|
192
|
+
value: selectedValue
|
|
193
|
+
};
|
|
194
|
+
return selectedValue;
|
|
195
|
+
}, [ctrl]);
|
|
155
196
|
return useSyncExternalStore(useCallback((onStoreChange) => {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}, [ctrl, getOrCreateHandle]), getSnapshot, getSnapshot);
|
|
197
|
+
return ctrl.on("*", onStoreChange);
|
|
198
|
+
}, [ctrl]), getSnapshot, getSnapshot);
|
|
159
199
|
}
|
|
160
200
|
|
|
161
201
|
//#endregion
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["atom","data: T | undefined","error: Error | undefined","result: UseAtomState<T>"],"sources":["../src/context.tsx","../src/hooks.ts"],"sourcesContent":["import { createContext, type ReactNode } from 'react'\nimport { type Lite } from '@pumped-fn/lite'\n\n/**\n * React context for Lite.Scope.\n */\nconst ScopeContext = createContext<Lite.Scope | null>(null)\n\ninterface ScopeProviderProps {\n scope: Lite.Scope\n children: ReactNode\n}\n\n/**\n * Provider component for Lite.Scope.\n *\n * @example\n * ```tsx\n * <ScopeProvider scope={scope}>\n * <App />\n * </ScopeProvider>\n * ```\n */\nfunction ScopeProvider({ scope, children }: ScopeProviderProps) {\n return (\n <ScopeContext.Provider value={scope}>\n {children}\n </ScopeContext.Provider>\n )\n}\n\nexport { ScopeContext, ScopeProvider }\nexport type { ScopeProviderProps }\n","import { useCallback, useContext, useEffect, useMemo, useRef, useSyncExternalStore } from 'react'\nimport { type Lite } from '@pumped-fn/lite'\nimport { ScopeContext } from './context'\n\ninterface UseAtomSuspenseOptions {\n suspense?: true\n /** @default true */\n resolve?: boolean\n}\n\ninterface UseAtomManualOptions {\n suspense: false\n /** @default false */\n resolve?: boolean\n}\n\ntype UseAtomOptions = UseAtomSuspenseOptions | UseAtomManualOptions\n\ninterface UseAtomState<T> {\n data: T | undefined\n loading: boolean\n error: Error | undefined\n controller: Lite.Controller<T>\n}\n\ninterface UseControllerOptions {\n resolve?: boolean\n}\n\nconst pendingPromises = new WeakMap<Lite.Atom<unknown>, Promise<unknown>>()\n\nfunction getOrCreatePendingPromise<T>(atom: Lite.Atom<T>, ctrl: Lite.Controller<T>): Promise<T> {\n let pending = pendingPromises.get(atom) as Promise<T> | undefined\n if (!pending) {\n pending = ctrl.resolve()\n pendingPromises.set(atom, pending)\n pending.finally(() => pendingPromises.delete(atom))\n }\n return pending\n}\n\n/**\n * Access the current Lite.Scope from context.\n *\n * @returns The current Lite.Scope instance from context\n * @throws When called outside of a ScopeProvider\n *\n * @example\n * ```tsx\n * const scope = useScope()\n * await scope.resolve(myAtom)\n * ```\n */\nfunction useScope(): Lite.Scope {\n const scope = useContext(ScopeContext)\n if (!scope) {\n throw new Error(\"useScope must be used within a ScopeProvider\")\n }\n return scope\n}\n\n/**\n * Get a memoized controller for an atom.\n *\n * @example\n * ```tsx\n * const ctrl = useController(counterAtom)\n * ctrl.set(ctrl.get() + 1)\n * ```\n */\nfunction useController<T>(atom: Lite.Atom<T>): Lite.Controller<T>\nfunction useController<T>(atom: Lite.Atom<T>, options: UseControllerOptions): Lite.Controller<T>\nfunction useController<T>(atom: Lite.Atom<T>, options?: UseControllerOptions): Lite.Controller<T> {\n const scope = useScope()\n const ctrl = useMemo(() => scope.controller(atom), [scope, atom])\n\n if (options?.resolve) {\n if (ctrl.state === 'idle' || ctrl.state === 'resolving') {\n throw getOrCreatePendingPromise(atom, ctrl)\n }\n if (ctrl.state === 'failed') {\n throw ctrl.get()\n }\n }\n\n return ctrl\n}\n\n/**\n * Subscribe to atom value with Suspense/ErrorBoundary integration.\n *\n * @example\n * ```tsx\n * const user = useAtom(userAtom)\n * const { data, loading, error } = useAtom(userAtom, { suspense: false })\n * ```\n */\nfunction useAtom<T>(atom: Lite.Atom<T>): T\nfunction useAtom<T>(atom: Lite.Atom<T>, options: UseAtomSuspenseOptions): T\nfunction useAtom<T>(atom: Lite.Atom<T>, options: UseAtomManualOptions): UseAtomState<T>\nfunction useAtom<T>(atom: Lite.Atom<T>, options?: UseAtomOptions): T | UseAtomState<T> {\n const ctrl = useController(atom)\n const atomRef = useRef(atom)\n atomRef.current = atom\n\n if (options?.suspense === false) {\n return useAtomState(atom, ctrl, options.resolve ?? false)\n }\n\n const autoResolve = options?.resolve !== false\n\n const getSnapshot = useCallback((): T => {\n if (ctrl.state === 'idle') {\n if (autoResolve) {\n throw getOrCreatePendingPromise(atomRef.current, ctrl)\n }\n throw new Error('Atom is not resolved. Set resolve: true or resolve the atom before rendering.')\n }\n if (ctrl.state === 'resolving') {\n throw getOrCreatePendingPromise(atomRef.current, ctrl)\n }\n if (ctrl.state === 'failed') {\n throw ctrl.get()\n }\n return ctrl.get()\n }, [ctrl, autoResolve])\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => ctrl.on('resolved', onStoreChange),\n [ctrl]\n )\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n}\n\nfunction useAtomState<T>(\n atom: Lite.Atom<T>,\n ctrl: Lite.Controller<T>,\n autoResolve: boolean\n): UseAtomState<T> {\n const stateCache = useRef<{\n ctrlState: Lite.Controller<T>['state']\n data: T | undefined\n error: Error | undefined\n result: UseAtomState<T>\n } | null>(null)\n\n useEffect(() => {\n if (autoResolve && (ctrl.state === 'idle' || ctrl.state === 'resolving')) {\n getOrCreatePendingPromise(atom, ctrl)\n }\n }, [atom, ctrl, autoResolve])\n\n const getSnapshot = useCallback((): UseAtomState<T> => {\n let data: T | undefined\n let error: Error | undefined\n\n if (ctrl.state === 'resolved') {\n data = ctrl.get()\n } else if (ctrl.state === 'failed') {\n try {\n ctrl.get()\n } catch (e) {\n error = e instanceof Error ? e : new Error(String(e))\n }\n }\n\n if (\n stateCache.current &&\n stateCache.current.ctrlState === ctrl.state &&\n stateCache.current.data === data &&\n stateCache.current.error === error\n ) {\n return stateCache.current.result\n }\n\n const result: UseAtomState<T> = {\n data,\n loading: ctrl.state === 'resolving',\n error,\n controller: ctrl,\n }\n\n stateCache.current = { ctrlState: ctrl.state, data, error, result }\n return result\n }, [ctrl])\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => ctrl.on('*', onStoreChange),\n [ctrl]\n )\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n}\n\n/**\n * Select a derived value from an atom with fine-grained reactivity.\n * Only re-renders when the selected value changes per equality function.\n *\n * @param atom - The atom to select from\n * @param selector - Function to extract a derived value\n * @param eq - Optional equality function\n * @returns The selected value\n *\n * @example\n * ```tsx\n * const name = useSelect(userAtom, user => user.name)\n * ```\n */\nfunction useSelect<T, S>(\n atom: Lite.Atom<T>,\n selector: (value: T) => S,\n eq?: (a: S, b: S) => boolean\n): S {\n const scope = useScope()\n const ctrl = useController(atom)\n\n const atomRef = useRef(atom)\n atomRef.current = atom\n\n const selectorRef = useRef(selector)\n const eqRef = useRef(eq)\n selectorRef.current = selector\n eqRef.current = eq\n\n const handleRef = useRef<{\n scope: Lite.Scope\n atom: Lite.Atom<T>\n handle: Lite.SelectHandle<S>\n } | null>(null)\n\n const getOrCreateHandle = useCallback(() => {\n if (\n !handleRef.current ||\n handleRef.current.scope !== scope ||\n handleRef.current.atom !== atom\n ) {\n const handle = scope.select(atom, selectorRef.current, { eq: eqRef.current })\n handleRef.current = { scope, atom, handle }\n }\n return handleRef.current.handle\n }, [scope, atom])\n\n const getSnapshot = useCallback((): S => {\n const state = ctrl.state\n if (state === 'idle' || state === 'resolving') {\n throw getOrCreatePendingPromise(atomRef.current, ctrl)\n }\n if (state === 'failed') {\n throw ctrl.get()\n }\n return getOrCreateHandle().get()\n }, [ctrl, getOrCreateHandle])\n\n const subscribe = useCallback((onStoreChange: () => void) => {\n if (ctrl.state !== 'resolved') {\n return () => {}\n }\n return getOrCreateHandle().subscribe(onStoreChange)\n }, [ctrl, getOrCreateHandle])\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n}\n\nexport { useScope, useController, useAtom, useSelect }\nexport type { UseAtomSuspenseOptions, UseAtomManualOptions, UseAtomOptions, UseAtomState, UseControllerOptions }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["atom","data: T | undefined","error: Error | undefined","result: UseAtomState<T>","value: T"],"sources":["../src/context.tsx","../src/hooks.ts"],"sourcesContent":["import { createContext, type ReactNode } from 'react'\nimport { type Lite } from '@pumped-fn/lite'\n\n/**\n * React context for Lite.Scope.\n */\nconst ScopeContext = createContext<Lite.Scope | null>(null)\n\ninterface ScopeProviderProps {\n scope: Lite.Scope\n children: ReactNode\n}\n\n/**\n * Provider component for Lite.Scope.\n *\n * @example\n * ```tsx\n * <ScopeProvider scope={scope}>\n * <App />\n * </ScopeProvider>\n * ```\n */\nfunction ScopeProvider({ scope, children }: ScopeProviderProps) {\n return (\n <ScopeContext.Provider value={scope}>\n {children}\n </ScopeContext.Provider>\n )\n}\n\nexport { ScopeContext, ScopeProvider }\nexport type { ScopeProviderProps }\n","import { useCallback, useContext, useEffect, useMemo, useRef, useSyncExternalStore } from 'react'\nimport { type Lite } from '@pumped-fn/lite'\nimport { ScopeContext } from './context'\n\ninterface UseAtomSuspenseOptions {\n suspense?: true\n /** @default true */\n resolve?: boolean\n}\n\ninterface UseAtomManualOptions {\n suspense: false\n /** @default false */\n resolve?: boolean\n}\n\ntype UseAtomOptions = UseAtomSuspenseOptions | UseAtomManualOptions\n\ninterface UseAtomState<T> {\n data: T | undefined\n loading: boolean\n error: Error | undefined\n controller: Lite.Controller<T>\n}\n\ninterface UseControllerOptions {\n resolve?: boolean\n}\n\nconst pendingPromises = new WeakMap<Lite.Controller<unknown>, Promise<unknown>>()\n\nfunction getOrCreatePendingPromise<T>(ctrl: Lite.Controller<T>): Promise<T> {\n let pending = pendingPromises.get(ctrl) as Promise<T> | undefined\n if (!pending) {\n if (ctrl.state === 'resolving') {\n pending = new Promise<T>((resolve, reject) => {\n const unsub = ctrl.on('*', () => {\n if (ctrl.state === 'resolved') {\n unsub()\n resolve(ctrl.get())\n } else if (ctrl.state === 'failed') {\n unsub()\n try { ctrl.get() } catch (e) { reject(e) }\n }\n })\n })\n } else {\n pending = ctrl.resolve()\n }\n pendingPromises.set(ctrl, pending)\n void pending.catch(() => {})\n pending.then(\n () => pendingPromises.delete(ctrl),\n () => pendingPromises.delete(ctrl)\n )\n }\n return pending\n}\n\n/**\n * Access the current Lite.Scope from context.\n *\n * @returns The current Lite.Scope instance from context\n * @throws When called outside of a ScopeProvider\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const scope = useScope()\n * const handleClick = () => scope.resolve(myAtom)\n * }\n * ```\n */\nfunction useScope(): Lite.Scope {\n const scope = useContext(ScopeContext)\n if (!scope) {\n throw new Error(\"useScope must be used within a ScopeProvider\")\n }\n return scope\n}\n\n/**\n * Get a memoized controller for an atom.\n *\n * @example\n * ```tsx\n * const ctrl = useController(counterAtom)\n * ctrl.set(ctrl.get() + 1)\n * ```\n */\nfunction useController<T>(atom: Lite.Atom<T>): Lite.Controller<T>\nfunction useController<T>(atom: Lite.Atom<T>, options: UseControllerOptions): Lite.Controller<T>\nfunction useController<T>(atom: Lite.Atom<T>, options?: UseControllerOptions): Lite.Controller<T> {\n const scope = useScope()\n const ctrl = useMemo(() => scope.controller(atom), [scope, atom])\n\n if (options?.resolve) {\n if (ctrl.state === 'idle' || ctrl.state === 'resolving') {\n throw getOrCreatePendingPromise(ctrl)\n }\n if (ctrl.state === 'failed') {\n throw ctrl.get()\n }\n }\n\n return ctrl\n}\n\n/**\n * Subscribe to atom value with Suspense/ErrorBoundary integration.\n *\n * @example\n * ```tsx\n * const user = useAtom(userAtom)\n * const { data, loading, error } = useAtom(userAtom, { suspense: false })\n * ```\n */\nfunction useAtom<T>(atom: Lite.Atom<T>): T\nfunction useAtom<T>(atom: Lite.Atom<T>, options: UseAtomSuspenseOptions): T\nfunction useAtom<T>(atom: Lite.Atom<T>, options: UseAtomManualOptions): UseAtomState<T>\nfunction useAtom<T>(atom: Lite.Atom<T>, options?: UseAtomOptions): T | UseAtomState<T> {\n const ctrl = useController(atom)\n const ctrlState = ctrl.state\n\n const isSuspense = options?.suspense !== false\n const autoResolve = isSuspense ? options?.resolve !== false : !!options?.resolve\n\n const stateCache = useRef<{\n ctrl: Lite.Controller<T>\n ctrlState: Lite.Controller<T>['state']\n data: T | undefined\n error: Error | undefined\n loading: boolean\n result: UseAtomState<T>\n } | null>(null)\n\n useEffect(() => {\n if (!isSuspense && (ctrlState === 'resolving' || (autoResolve && ctrlState === 'idle'))) {\n void getOrCreatePendingPromise(ctrl).catch(() => {})\n }\n }, [ctrl, ctrlState, autoResolve, isSuspense])\n\n const getSnapshot = useCallback((): T | UseAtomState<T> => {\n if (isSuspense) {\n if (ctrl.state === 'idle') {\n if (autoResolve) {\n throw getOrCreatePendingPromise(ctrl)\n }\n throw new Error('Atom is not resolved. Set resolve: true or resolve the atom before rendering.')\n }\n if (ctrl.state === 'failed') {\n throw ctrl.get()\n }\n try {\n return ctrl.get()\n } catch {\n throw getOrCreatePendingPromise(ctrl)\n }\n }\n\n let data: T | undefined\n let error: Error | undefined\n\n if (ctrl.state === 'resolved' || ctrl.state === 'resolving') {\n try {\n data = ctrl.get()\n } catch {}\n } else if (ctrl.state === 'failed') {\n try {\n ctrl.get()\n } catch (e) {\n error = e instanceof Error ? e : new Error(String(e))\n }\n }\n\n const loading = ctrl.state === 'resolving' || (autoResolve && ctrl.state === 'idle')\n\n if (\n stateCache.current &&\n stateCache.current.ctrl === ctrl &&\n stateCache.current.ctrlState === ctrl.state &&\n stateCache.current.data === data &&\n stateCache.current.error === error &&\n stateCache.current.loading === loading\n ) {\n return stateCache.current.result\n }\n\n const result: UseAtomState<T> = {\n data,\n loading,\n error,\n controller: ctrl,\n }\n\n stateCache.current = { ctrl, ctrlState: ctrl.state, data, error, loading, result }\n return result\n }, [ctrl, autoResolve, isSuspense])\n\n const subscribe = useCallback((onStoreChange: () => void) => {\n return ctrl.on('*', () => {\n if (!isSuspense && ctrl.state === 'resolving') {\n void getOrCreatePendingPromise(ctrl).catch(() => {})\n }\n onStoreChange()\n })\n }, [ctrl, isSuspense])\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n}\n\n/**\n * Select a derived value from an atom with fine-grained reactivity.\n * Only re-renders when the selected value changes per equality function.\n *\n * @param atom - The atom to select from\n * @param selector - Function to extract a derived value\n * @param eq - Optional equality function\n * @returns The selected value\n *\n * @example\n * ```tsx\n * const name = useSelect(userAtom, user => user.name)\n * ```\n */\nfunction useSelect<T, S>(\n atom: Lite.Atom<T>,\n selector: (value: T) => S,\n eq?: (a: S, b: S) => boolean\n): S {\n const ctrl = useController(atom)\n\n const selectorRef = useRef(selector)\n const eqRef = useRef(eq)\n selectorRef.current = selector\n eqRef.current = eq\n\n const selectionCache = useRef<{\n ctrl: Lite.Controller<T>\n ctrlState: Lite.Controller<T>['state']\n source: T\n selector: (value: T) => S\n eq: ((a: S, b: S) => boolean) | undefined\n value: S\n } | null>(null)\n\n const getSnapshot = useCallback((): S => {\n const state = ctrl.state\n if (state === 'idle') {\n throw getOrCreatePendingPromise(ctrl)\n }\n if (state === 'failed') {\n throw ctrl.get()\n }\n let value: T\n try {\n value = ctrl.get()\n } catch {\n throw getOrCreatePendingPromise(ctrl)\n }\n\n const nextSelector = selectorRef.current\n const nextEq = eqRef.current\n const current = selectionCache.current\n if (\n current &&\n current.ctrl === ctrl &&\n current.ctrlState === state &&\n Object.is(current.source, value) &&\n current.selector === nextSelector &&\n current.eq === nextEq\n ) {\n return current.value\n }\n\n const nextValue = nextSelector(value)\n const selectedValue = current &&\n current.ctrl === ctrl &&\n current.selector === nextSelector &&\n (nextEq ?? Object.is)(current.value, nextValue)\n ? current.value\n : nextValue\n\n selectionCache.current = {\n ctrl,\n ctrlState: state,\n source: value,\n selector: nextSelector,\n eq: nextEq,\n value: selectedValue,\n }\n\n return selectedValue\n }, [ctrl])\n\n const subscribe = useCallback((onStoreChange: () => void) => {\n return ctrl.on('*', onStoreChange)\n }, [ctrl])\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n}\n\nexport { useScope, useController, useAtom, useSelect }\nexport type { UseAtomSuspenseOptions, UseAtomManualOptions, UseAtomOptions, UseAtomState, UseControllerOptions }\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pumped-fn/lite-react",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "React integration for @pumped-fn/lite",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -31,13 +31,14 @@
|
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@testing-library/jest-dom": "^6.9.1",
|
|
33
33
|
"@testing-library/react": "^16.3.0",
|
|
34
|
+
"@types/node": "^20.19.22",
|
|
34
35
|
"@types/react": "^18.3.27",
|
|
35
36
|
"jsdom": "^27.3.0",
|
|
36
37
|
"react": "^18.3.1",
|
|
37
38
|
"tsdown": "^0.17.2",
|
|
38
39
|
"typescript": "^5.9.3",
|
|
39
|
-
"vitest": "^4.0.
|
|
40
|
-
"@pumped-fn/lite": "1.
|
|
40
|
+
"vitest": "^4.0.18",
|
|
41
|
+
"@pumped-fn/lite": "2.1.2"
|
|
41
42
|
},
|
|
42
43
|
"engines": {
|
|
43
44
|
"node": ">=18"
|