@pumped-fn/lite-react 1.0.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 +20 -0
- package/README.md +61 -10
- package/dist/index.cjs +121 -63
- package/dist/index.d.cts +30 -14
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +30 -14
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +122 -64
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
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
|
+
|
|
10
|
+
## 1.1.0
|
|
11
|
+
|
|
12
|
+
### Minor Changes
|
|
13
|
+
|
|
14
|
+
- 1624845: feat(lite-react): add non-Suspense mode and resolve options for useAtom/useController
|
|
15
|
+
|
|
16
|
+
- Add `{ suspense: false }` option to `useAtom` returning `UseAtomState<T>` with `data`, `loading`, `error`, `controller`
|
|
17
|
+
- Add `{ resolve: boolean }` option to control auto-resolution behavior
|
|
18
|
+
- Suspense mode: `resolve` defaults to `true` (auto-resolves idle atoms)
|
|
19
|
+
- Non-Suspense mode: `resolve` defaults to `false` (no auto-resolve)
|
|
20
|
+
- Add `{ resolve: true }` option to `useController` for Suspense integration
|
|
21
|
+
- Export new types: `UseAtomSuspenseOptions`, `UseAtomManualOptions`, `UseAtomOptions`, `UseAtomState`, `UseControllerOptions`
|
|
22
|
+
|
|
3
23
|
## 1.0.0
|
|
4
24
|
|
|
5
25
|
### Major 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
|
|
|
@@ -91,6 +95,16 @@ ctrl.update(n => n + 1)
|
|
|
91
95
|
ctrl.invalidate()
|
|
92
96
|
```
|
|
93
97
|
|
|
98
|
+
With `{ resolve: true }` option, triggers Suspense if atom not resolved:
|
|
99
|
+
|
|
100
|
+
```tsx
|
|
101
|
+
// Suspense ensures controller is resolved before render
|
|
102
|
+
const ctrl = useController(configAtom, { resolve: true })
|
|
103
|
+
ctrl.get() // safe - Suspense guarantees resolved state
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
While a controller is re-resolving, `{ resolve: true }` keeps suspending until the controller settles.
|
|
107
|
+
|
|
94
108
|
### useAtom
|
|
95
109
|
|
|
96
110
|
Subscribe to atom value with Suspense integration.
|
|
@@ -109,6 +123,42 @@ function UserProfile() {
|
|
|
109
123
|
</ErrorBoundary>
|
|
110
124
|
```
|
|
111
125
|
|
|
126
|
+
#### Non-Suspense Mode
|
|
127
|
+
|
|
128
|
+
For manual loading/error state handling without Suspense:
|
|
129
|
+
|
|
130
|
+
```tsx
|
|
131
|
+
function UserProfile() {
|
|
132
|
+
const { data, loading, error, controller } = useAtom(userAtom, { suspense: false })
|
|
133
|
+
|
|
134
|
+
if (loading && data) return <div>Refreshing {data.name}...</div>
|
|
135
|
+
if (loading) return <div>Loading...</div>
|
|
136
|
+
if (error) return <div>Error: {error.message}</div>
|
|
137
|
+
if (!data) return <div>Not loaded</div>
|
|
138
|
+
|
|
139
|
+
return (
|
|
140
|
+
<div>
|
|
141
|
+
<h1>{data.name}</h1>
|
|
142
|
+
<button onClick={() => controller.invalidate()}>Refresh</button>
|
|
143
|
+
</div>
|
|
144
|
+
)
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
With `{ resolve: true }`, auto-resolves on mount:
|
|
149
|
+
|
|
150
|
+
```tsx
|
|
151
|
+
// Starts resolution automatically when component mounts
|
|
152
|
+
const { data, loading, error } = useAtom(userAtom, { suspense: false, resolve: true })
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
| Option | Effect |
|
|
156
|
+
|--------|--------|
|
|
157
|
+
| `{ suspense: false }` | Returns state object, no auto-resolve |
|
|
158
|
+
| `{ suspense: false, resolve: true }` | Returns state object, auto-resolves on mount |
|
|
159
|
+
|
|
160
|
+
While `loading` is `true`, `data` may still contain the last resolved value during a refresh.
|
|
161
|
+
|
|
112
162
|
### useSelect
|
|
113
163
|
|
|
114
164
|
Fine-grained selection — only re-renders when selected value changes.
|
|
@@ -120,7 +170,7 @@ const count = useSelect(todosAtom, todos => todos.length, (a, b) => a === b)
|
|
|
120
170
|
|
|
121
171
|
## Invalidation
|
|
122
172
|
|
|
123
|
-
When an atom is invalidated,
|
|
173
|
+
When an atom is invalidated, `useAtom` and `useSelect` keep rendering the last value while re-resolving:
|
|
124
174
|
|
|
125
175
|
```mermaid
|
|
126
176
|
sequenceDiagram
|
|
@@ -133,14 +183,16 @@ sequenceDiagram
|
|
|
133
183
|
|
|
134
184
|
Note over Controller: ctrl.invalidate()
|
|
135
185
|
Controller->>Controller: state = resolving
|
|
136
|
-
useAtom-->>Component:
|
|
137
|
-
Note over Component:
|
|
186
|
+
useAtom-->>Component: stale value
|
|
187
|
+
Note over Component: current UI stays visible
|
|
138
188
|
|
|
139
189
|
Controller->>Controller: factory runs
|
|
140
190
|
Controller->>Controller: state = resolved
|
|
141
191
|
useAtom->>Component: re-render (new value)
|
|
142
192
|
```
|
|
143
193
|
|
|
194
|
+
`useController(atom, { resolve: true })` is different: it suspends until the controller settles again.
|
|
195
|
+
|
|
144
196
|
## Testing
|
|
145
197
|
|
|
146
198
|
Use presets for test isolation:
|
|
@@ -163,10 +215,9 @@ render(
|
|
|
163
215
|
|
|
164
216
|
## SSR
|
|
165
217
|
|
|
166
|
-
SSR-compatible
|
|
218
|
+
SSR-compatible when request-scoped atoms are resolved before rendering:
|
|
167
219
|
|
|
168
220
|
- No side effects on import
|
|
169
|
-
- Uses `useSyncExternalStore` with server snapshot
|
|
170
221
|
- Scope passed as prop (no global state)
|
|
171
222
|
|
|
172
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() {
|
|
@@ -53,48 +71,80 @@ function useScope() {
|
|
|
53
71
|
if (!scope) throw new Error("useScope must be used within a ScopeProvider");
|
|
54
72
|
return scope;
|
|
55
73
|
}
|
|
56
|
-
|
|
57
|
-
* Get a memoized controller for an atom.
|
|
58
|
-
*
|
|
59
|
-
* @param atom - The atom to create a controller for
|
|
60
|
-
* @returns A memoized Lite.Controller instance
|
|
61
|
-
*
|
|
62
|
-
* @example
|
|
63
|
-
* ```tsx
|
|
64
|
-
* const ctrl = useController(counterAtom)
|
|
65
|
-
* ctrl.set(ctrl.get() + 1)
|
|
66
|
-
* ```
|
|
67
|
-
*/
|
|
68
|
-
function useController(atom$1) {
|
|
74
|
+
function useController(atom$1, options) {
|
|
69
75
|
const scope = useScope();
|
|
70
|
-
|
|
76
|
+
const ctrl = (0, react.useMemo)(() => scope.controller(atom$1), [scope, atom$1]);
|
|
77
|
+
if (options?.resolve) {
|
|
78
|
+
if (ctrl.state === "idle" || ctrl.state === "resolving") throw getOrCreatePendingPromise(ctrl);
|
|
79
|
+
if (ctrl.state === "failed") throw ctrl.get();
|
|
80
|
+
}
|
|
81
|
+
return ctrl;
|
|
71
82
|
}
|
|
72
|
-
|
|
73
|
-
* Subscribe to atom value with Suspense/ErrorBoundary integration.
|
|
74
|
-
* Auto-resolves atoms lazily and throws cached Promise for Suspense.
|
|
75
|
-
*
|
|
76
|
-
* @param atom - The atom to read
|
|
77
|
-
* @returns The current value of the atom
|
|
78
|
-
*
|
|
79
|
-
* @example
|
|
80
|
-
* ```tsx
|
|
81
|
-
* function UserProfile() {
|
|
82
|
-
* const user = useAtom(userAtom)
|
|
83
|
-
* return <div>{user.name}</div>
|
|
84
|
-
* }
|
|
85
|
-
* ```
|
|
86
|
-
*/
|
|
87
|
-
function useAtom(atom$1) {
|
|
83
|
+
function useAtom(atom$1, options) {
|
|
88
84
|
const ctrl = useController(atom$1);
|
|
89
|
-
const
|
|
90
|
-
|
|
85
|
+
const ctrlState = ctrl.state;
|
|
86
|
+
const isSuspense = options?.suspense !== false;
|
|
87
|
+
const autoResolve = isSuspense ? options?.resolve !== false : !!options?.resolve;
|
|
88
|
+
const stateCache = (0, react.useRef)(null);
|
|
89
|
+
(0, react.useEffect)(() => {
|
|
90
|
+
if (!isSuspense && (ctrlState === "resolving" || autoResolve && ctrlState === "idle")) getOrCreatePendingPromise(ctrl).catch(() => {});
|
|
91
|
+
}, [
|
|
92
|
+
ctrl,
|
|
93
|
+
ctrlState,
|
|
94
|
+
autoResolve,
|
|
95
|
+
isSuspense
|
|
96
|
+
]);
|
|
91
97
|
const getSnapshot = (0, react.useCallback)(() => {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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
|
+
}
|
|
110
|
+
let data;
|
|
111
|
+
let error;
|
|
112
|
+
if (ctrl.state === "resolved" || ctrl.state === "resolving") try {
|
|
113
|
+
data = ctrl.get();
|
|
114
|
+
} catch {}
|
|
115
|
+
else if (ctrl.state === "failed") try {
|
|
116
|
+
ctrl.get();
|
|
117
|
+
} catch (e) {
|
|
118
|
+
error = e instanceof Error ? e : new Error(String(e));
|
|
119
|
+
}
|
|
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;
|
|
122
|
+
const result = {
|
|
123
|
+
data,
|
|
124
|
+
loading,
|
|
125
|
+
error,
|
|
126
|
+
controller: ctrl
|
|
127
|
+
};
|
|
128
|
+
stateCache.current = {
|
|
129
|
+
ctrl,
|
|
130
|
+
ctrlState: ctrl.state,
|
|
131
|
+
data,
|
|
132
|
+
error,
|
|
133
|
+
loading,
|
|
134
|
+
result
|
|
135
|
+
};
|
|
136
|
+
return result;
|
|
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);
|
|
98
148
|
}
|
|
99
149
|
/**
|
|
100
150
|
* Select a derived value from an atom with fine-grained reactivity.
|
|
@@ -111,33 +161,41 @@ function useAtom(atom$1) {
|
|
|
111
161
|
* ```
|
|
112
162
|
*/
|
|
113
163
|
function useSelect(atom$1, selector, eq) {
|
|
114
|
-
const scope = useScope();
|
|
115
164
|
const ctrl = useController(atom$1);
|
|
116
|
-
const atomRef = (0, react.useRef)(atom$1);
|
|
117
|
-
atomRef.current = atom$1;
|
|
118
165
|
const selectorRef = (0, react.useRef)(selector);
|
|
119
166
|
const eqRef = (0, react.useRef)(eq);
|
|
120
167
|
selectorRef.current = selector;
|
|
121
168
|
eqRef.current = eq;
|
|
122
|
-
const
|
|
123
|
-
const getOrCreateHandle = (0, react.useCallback)(() => {
|
|
124
|
-
if (!handleRef.current || handleRef.current.scope !== scope || handleRef.current.atom !== atom$1) handleRef.current = {
|
|
125
|
-
scope,
|
|
126
|
-
atom: atom$1,
|
|
127
|
-
handle: scope.select(atom$1, selectorRef.current, { eq: eqRef.current })
|
|
128
|
-
};
|
|
129
|
-
return handleRef.current.handle;
|
|
130
|
-
}, [scope, atom$1]);
|
|
169
|
+
const selectionCache = (0, react.useRef)(null);
|
|
131
170
|
const getSnapshot = (0, react.useCallback)(() => {
|
|
132
171
|
const state = ctrl.state;
|
|
133
|
-
if (state === "idle"
|
|
172
|
+
if (state === "idle") throw getOrCreatePendingPromise(ctrl);
|
|
134
173
|
if (state === "failed") throw ctrl.get();
|
|
135
|
-
|
|
136
|
-
|
|
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]);
|
|
137
196
|
return (0, react.useSyncExternalStore)((0, react.useCallback)((onStoreChange) => {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}, [ctrl, getOrCreateHandle]), getSnapshot, getSnapshot);
|
|
197
|
+
return ctrl.on("*", onStoreChange);
|
|
198
|
+
}, [ctrl]), getSnapshot, getSnapshot);
|
|
141
199
|
}
|
|
142
200
|
|
|
143
201
|
//#endregion
|
package/dist/index.d.cts
CHANGED
|
@@ -28,6 +28,26 @@ declare function ScopeProvider({
|
|
|
28
28
|
}: ScopeProviderProps): react_jsx_runtime0.JSX.Element;
|
|
29
29
|
//#endregion
|
|
30
30
|
//#region src/hooks.d.ts
|
|
31
|
+
interface UseAtomSuspenseOptions {
|
|
32
|
+
suspense?: true;
|
|
33
|
+
/** @default true */
|
|
34
|
+
resolve?: boolean;
|
|
35
|
+
}
|
|
36
|
+
interface UseAtomManualOptions {
|
|
37
|
+
suspense: false;
|
|
38
|
+
/** @default false */
|
|
39
|
+
resolve?: boolean;
|
|
40
|
+
}
|
|
41
|
+
type UseAtomOptions = UseAtomSuspenseOptions | UseAtomManualOptions;
|
|
42
|
+
interface UseAtomState<T> {
|
|
43
|
+
data: T | undefined;
|
|
44
|
+
loading: boolean;
|
|
45
|
+
error: Error | undefined;
|
|
46
|
+
controller: Lite$1.Controller<T>;
|
|
47
|
+
}
|
|
48
|
+
interface UseControllerOptions {
|
|
49
|
+
resolve?: boolean;
|
|
50
|
+
}
|
|
31
51
|
/**
|
|
32
52
|
* Access the current Lite.Scope from context.
|
|
33
53
|
*
|
|
@@ -36,17 +56,16 @@ declare function ScopeProvider({
|
|
|
36
56
|
*
|
|
37
57
|
* @example
|
|
38
58
|
* ```tsx
|
|
39
|
-
*
|
|
40
|
-
*
|
|
59
|
+
* function MyComponent() {
|
|
60
|
+
* const scope = useScope()
|
|
61
|
+
* const handleClick = () => scope.resolve(myAtom)
|
|
62
|
+
* }
|
|
41
63
|
* ```
|
|
42
64
|
*/
|
|
43
65
|
declare function useScope(): Lite$1.Scope;
|
|
44
66
|
/**
|
|
45
67
|
* Get a memoized controller for an atom.
|
|
46
68
|
*
|
|
47
|
-
* @param atom - The atom to create a controller for
|
|
48
|
-
* @returns A memoized Lite.Controller instance
|
|
49
|
-
*
|
|
50
69
|
* @example
|
|
51
70
|
* ```tsx
|
|
52
71
|
* const ctrl = useController(counterAtom)
|
|
@@ -54,22 +73,19 @@ declare function useScope(): Lite$1.Scope;
|
|
|
54
73
|
* ```
|
|
55
74
|
*/
|
|
56
75
|
declare function useController<T>(atom: Lite$1.Atom<T>): Lite$1.Controller<T>;
|
|
76
|
+
declare function useController<T>(atom: Lite$1.Atom<T>, options: UseControllerOptions): Lite$1.Controller<T>;
|
|
57
77
|
/**
|
|
58
78
|
* Subscribe to atom value with Suspense/ErrorBoundary integration.
|
|
59
|
-
* Auto-resolves atoms lazily and throws cached Promise for Suspense.
|
|
60
|
-
*
|
|
61
|
-
* @param atom - The atom to read
|
|
62
|
-
* @returns The current value of the atom
|
|
63
79
|
*
|
|
64
80
|
* @example
|
|
65
81
|
* ```tsx
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* return <div>{user.name}</div>
|
|
69
|
-
* }
|
|
82
|
+
* const user = useAtom(userAtom)
|
|
83
|
+
* const { data, loading, error } = useAtom(userAtom, { suspense: false })
|
|
70
84
|
* ```
|
|
71
85
|
*/
|
|
72
86
|
declare function useAtom<T>(atom: Lite$1.Atom<T>): T;
|
|
87
|
+
declare function useAtom<T>(atom: Lite$1.Atom<T>, options: UseAtomSuspenseOptions): T;
|
|
88
|
+
declare function useAtom<T>(atom: Lite$1.Atom<T>, options: UseAtomManualOptions): UseAtomState<T>;
|
|
73
89
|
/**
|
|
74
90
|
* Select a derived value from an atom with fine-grained reactivity.
|
|
75
91
|
* Only re-renders when the selected value changes per equality function.
|
|
@@ -86,5 +102,5 @@ declare function useAtom<T>(atom: Lite$1.Atom<T>): T;
|
|
|
86
102
|
*/
|
|
87
103
|
declare function useSelect<T, S>(atom: Lite$1.Atom<T>, selector: (value: T) => S, eq?: (a: S, b: S) => boolean): S;
|
|
88
104
|
//#endregion
|
|
89
|
-
export { type Lite, ScopeContext, ScopeProvider, type ScopeProviderProps, atom, createScope, flow, preset, useAtom, useController, useScope, useSelect };
|
|
105
|
+
export { type Lite, ScopeContext, ScopeProvider, type ScopeProviderProps, type UseAtomManualOptions, type UseAtomOptions, type UseAtomState, type UseAtomSuspenseOptions, type UseControllerOptions, atom, createScope, flow, preset, useAtom, useController, useScope, useSelect };
|
|
90
106
|
//# sourceMappingURL=index.d.cts.map
|
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;
|
|
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
|
@@ -28,6 +28,26 @@ declare function ScopeProvider({
|
|
|
28
28
|
}: ScopeProviderProps): react_jsx_runtime0.JSX.Element;
|
|
29
29
|
//#endregion
|
|
30
30
|
//#region src/hooks.d.ts
|
|
31
|
+
interface UseAtomSuspenseOptions {
|
|
32
|
+
suspense?: true;
|
|
33
|
+
/** @default true */
|
|
34
|
+
resolve?: boolean;
|
|
35
|
+
}
|
|
36
|
+
interface UseAtomManualOptions {
|
|
37
|
+
suspense: false;
|
|
38
|
+
/** @default false */
|
|
39
|
+
resolve?: boolean;
|
|
40
|
+
}
|
|
41
|
+
type UseAtomOptions = UseAtomSuspenseOptions | UseAtomManualOptions;
|
|
42
|
+
interface UseAtomState<T> {
|
|
43
|
+
data: T | undefined;
|
|
44
|
+
loading: boolean;
|
|
45
|
+
error: Error | undefined;
|
|
46
|
+
controller: Lite$1.Controller<T>;
|
|
47
|
+
}
|
|
48
|
+
interface UseControllerOptions {
|
|
49
|
+
resolve?: boolean;
|
|
50
|
+
}
|
|
31
51
|
/**
|
|
32
52
|
* Access the current Lite.Scope from context.
|
|
33
53
|
*
|
|
@@ -36,17 +56,16 @@ declare function ScopeProvider({
|
|
|
36
56
|
*
|
|
37
57
|
* @example
|
|
38
58
|
* ```tsx
|
|
39
|
-
*
|
|
40
|
-
*
|
|
59
|
+
* function MyComponent() {
|
|
60
|
+
* const scope = useScope()
|
|
61
|
+
* const handleClick = () => scope.resolve(myAtom)
|
|
62
|
+
* }
|
|
41
63
|
* ```
|
|
42
64
|
*/
|
|
43
65
|
declare function useScope(): Lite$1.Scope;
|
|
44
66
|
/**
|
|
45
67
|
* Get a memoized controller for an atom.
|
|
46
68
|
*
|
|
47
|
-
* @param atom - The atom to create a controller for
|
|
48
|
-
* @returns A memoized Lite.Controller instance
|
|
49
|
-
*
|
|
50
69
|
* @example
|
|
51
70
|
* ```tsx
|
|
52
71
|
* const ctrl = useController(counterAtom)
|
|
@@ -54,22 +73,19 @@ declare function useScope(): Lite$1.Scope;
|
|
|
54
73
|
* ```
|
|
55
74
|
*/
|
|
56
75
|
declare function useController<T>(atom: Lite$1.Atom<T>): Lite$1.Controller<T>;
|
|
76
|
+
declare function useController<T>(atom: Lite$1.Atom<T>, options: UseControllerOptions): Lite$1.Controller<T>;
|
|
57
77
|
/**
|
|
58
78
|
* Subscribe to atom value with Suspense/ErrorBoundary integration.
|
|
59
|
-
* Auto-resolves atoms lazily and throws cached Promise for Suspense.
|
|
60
|
-
*
|
|
61
|
-
* @param atom - The atom to read
|
|
62
|
-
* @returns The current value of the atom
|
|
63
79
|
*
|
|
64
80
|
* @example
|
|
65
81
|
* ```tsx
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* return <div>{user.name}</div>
|
|
69
|
-
* }
|
|
82
|
+
* const user = useAtom(userAtom)
|
|
83
|
+
* const { data, loading, error } = useAtom(userAtom, { suspense: false })
|
|
70
84
|
* ```
|
|
71
85
|
*/
|
|
72
86
|
declare function useAtom<T>(atom: Lite$1.Atom<T>): T;
|
|
87
|
+
declare function useAtom<T>(atom: Lite$1.Atom<T>, options: UseAtomSuspenseOptions): T;
|
|
88
|
+
declare function useAtom<T>(atom: Lite$1.Atom<T>, options: UseAtomManualOptions): UseAtomState<T>;
|
|
73
89
|
/**
|
|
74
90
|
* Select a derived value from an atom with fine-grained reactivity.
|
|
75
91
|
* Only re-renders when the selected value changes per equality function.
|
|
@@ -86,5 +102,5 @@ declare function useAtom<T>(atom: Lite$1.Atom<T>): T;
|
|
|
86
102
|
*/
|
|
87
103
|
declare function useSelect<T, S>(atom: Lite$1.Atom<T>, selector: (value: T) => S, eq?: (a: S, b: S) => boolean): S;
|
|
88
104
|
//#endregion
|
|
89
|
-
export { type Lite, ScopeContext, ScopeProvider, type ScopeProviderProps, atom, createScope, flow, preset, useAtom, useController, useScope, useSelect };
|
|
105
|
+
export { type Lite, ScopeContext, ScopeProvider, type ScopeProviderProps, type UseAtomManualOptions, type UseAtomOptions, type UseAtomState, type UseAtomSuspenseOptions, type UseControllerOptions, atom, createScope, flow, preset, useAtom, useController, useScope, useSelect };
|
|
90
106
|
//# sourceMappingURL=index.d.mts.map
|
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;
|
|
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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { atom, createScope, flow, preset } from "@pumped-fn/lite";
|
|
2
|
-
import { createContext, useCallback, useContext, useMemo, useRef, useSyncExternalStore } from "react";
|
|
2
|
+
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useSyncExternalStore } from "react";
|
|
3
3
|
import { jsx } from "react/jsx-runtime";
|
|
4
4
|
|
|
5
5
|
//#region src/context.tsx
|
|
@@ -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() {
|
|
@@ -53,48 +71,80 @@ function useScope() {
|
|
|
53
71
|
if (!scope) throw new Error("useScope must be used within a ScopeProvider");
|
|
54
72
|
return scope;
|
|
55
73
|
}
|
|
56
|
-
|
|
57
|
-
* Get a memoized controller for an atom.
|
|
58
|
-
*
|
|
59
|
-
* @param atom - The atom to create a controller for
|
|
60
|
-
* @returns A memoized Lite.Controller instance
|
|
61
|
-
*
|
|
62
|
-
* @example
|
|
63
|
-
* ```tsx
|
|
64
|
-
* const ctrl = useController(counterAtom)
|
|
65
|
-
* ctrl.set(ctrl.get() + 1)
|
|
66
|
-
* ```
|
|
67
|
-
*/
|
|
68
|
-
function useController(atom$1) {
|
|
74
|
+
function useController(atom$1, options) {
|
|
69
75
|
const scope = useScope();
|
|
70
|
-
|
|
76
|
+
const ctrl = useMemo(() => scope.controller(atom$1), [scope, atom$1]);
|
|
77
|
+
if (options?.resolve) {
|
|
78
|
+
if (ctrl.state === "idle" || ctrl.state === "resolving") throw getOrCreatePendingPromise(ctrl);
|
|
79
|
+
if (ctrl.state === "failed") throw ctrl.get();
|
|
80
|
+
}
|
|
81
|
+
return ctrl;
|
|
71
82
|
}
|
|
72
|
-
|
|
73
|
-
* Subscribe to atom value with Suspense/ErrorBoundary integration.
|
|
74
|
-
* Auto-resolves atoms lazily and throws cached Promise for Suspense.
|
|
75
|
-
*
|
|
76
|
-
* @param atom - The atom to read
|
|
77
|
-
* @returns The current value of the atom
|
|
78
|
-
*
|
|
79
|
-
* @example
|
|
80
|
-
* ```tsx
|
|
81
|
-
* function UserProfile() {
|
|
82
|
-
* const user = useAtom(userAtom)
|
|
83
|
-
* return <div>{user.name}</div>
|
|
84
|
-
* }
|
|
85
|
-
* ```
|
|
86
|
-
*/
|
|
87
|
-
function useAtom(atom$1) {
|
|
83
|
+
function useAtom(atom$1, options) {
|
|
88
84
|
const ctrl = useController(atom$1);
|
|
89
|
-
const
|
|
90
|
-
|
|
85
|
+
const ctrlState = ctrl.state;
|
|
86
|
+
const isSuspense = options?.suspense !== false;
|
|
87
|
+
const autoResolve = isSuspense ? options?.resolve !== false : !!options?.resolve;
|
|
88
|
+
const stateCache = useRef(null);
|
|
89
|
+
useEffect(() => {
|
|
90
|
+
if (!isSuspense && (ctrlState === "resolving" || autoResolve && ctrlState === "idle")) getOrCreatePendingPromise(ctrl).catch(() => {});
|
|
91
|
+
}, [
|
|
92
|
+
ctrl,
|
|
93
|
+
ctrlState,
|
|
94
|
+
autoResolve,
|
|
95
|
+
isSuspense
|
|
96
|
+
]);
|
|
91
97
|
const getSnapshot = useCallback(() => {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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
|
+
}
|
|
110
|
+
let data;
|
|
111
|
+
let error;
|
|
112
|
+
if (ctrl.state === "resolved" || ctrl.state === "resolving") try {
|
|
113
|
+
data = ctrl.get();
|
|
114
|
+
} catch {}
|
|
115
|
+
else if (ctrl.state === "failed") try {
|
|
116
|
+
ctrl.get();
|
|
117
|
+
} catch (e) {
|
|
118
|
+
error = e instanceof Error ? e : new Error(String(e));
|
|
119
|
+
}
|
|
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;
|
|
122
|
+
const result = {
|
|
123
|
+
data,
|
|
124
|
+
loading,
|
|
125
|
+
error,
|
|
126
|
+
controller: ctrl
|
|
127
|
+
};
|
|
128
|
+
stateCache.current = {
|
|
129
|
+
ctrl,
|
|
130
|
+
ctrlState: ctrl.state,
|
|
131
|
+
data,
|
|
132
|
+
error,
|
|
133
|
+
loading,
|
|
134
|
+
result
|
|
135
|
+
};
|
|
136
|
+
return result;
|
|
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);
|
|
98
148
|
}
|
|
99
149
|
/**
|
|
100
150
|
* Select a derived value from an atom with fine-grained reactivity.
|
|
@@ -111,33 +161,41 @@ function useAtom(atom$1) {
|
|
|
111
161
|
* ```
|
|
112
162
|
*/
|
|
113
163
|
function useSelect(atom$1, selector, eq) {
|
|
114
|
-
const scope = useScope();
|
|
115
164
|
const ctrl = useController(atom$1);
|
|
116
|
-
const atomRef = useRef(atom$1);
|
|
117
|
-
atomRef.current = atom$1;
|
|
118
165
|
const selectorRef = useRef(selector);
|
|
119
166
|
const eqRef = useRef(eq);
|
|
120
167
|
selectorRef.current = selector;
|
|
121
168
|
eqRef.current = eq;
|
|
122
|
-
const
|
|
123
|
-
const getOrCreateHandle = useCallback(() => {
|
|
124
|
-
if (!handleRef.current || handleRef.current.scope !== scope || handleRef.current.atom !== atom$1) handleRef.current = {
|
|
125
|
-
scope,
|
|
126
|
-
atom: atom$1,
|
|
127
|
-
handle: scope.select(atom$1, selectorRef.current, { eq: eqRef.current })
|
|
128
|
-
};
|
|
129
|
-
return handleRef.current.handle;
|
|
130
|
-
}, [scope, atom$1]);
|
|
169
|
+
const selectionCache = useRef(null);
|
|
131
170
|
const getSnapshot = useCallback(() => {
|
|
132
171
|
const state = ctrl.state;
|
|
133
|
-
if (state === "idle"
|
|
172
|
+
if (state === "idle") throw getOrCreatePendingPromise(ctrl);
|
|
134
173
|
if (state === "failed") throw ctrl.get();
|
|
135
|
-
|
|
136
|
-
|
|
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]);
|
|
137
196
|
return useSyncExternalStore(useCallback((onStoreChange) => {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}, [ctrl, getOrCreateHandle]), getSnapshot, getSnapshot);
|
|
197
|
+
return ctrl.on("*", onStoreChange);
|
|
198
|
+
}, [ctrl]), getSnapshot, getSnapshot);
|
|
141
199
|
}
|
|
142
200
|
|
|
143
201
|
//#endregion
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["atom"],"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, useMemo, useRef, useSyncExternalStore } from 'react'\nimport { type Lite } from '@pumped-fn/lite'\nimport { ScopeContext } from './context'\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 * @param atom - The atom to create a controller for\n * @returns A memoized Lite.Controller instance\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> {\n const scope = useScope()\n return useMemo(() => scope.controller(atom), [scope, atom])\n}\n\n/**\n * Subscribe to atom value with Suspense/ErrorBoundary integration.\n * Auto-resolves atoms lazily and throws cached Promise for Suspense.\n *\n * @param atom - The atom to read\n * @returns The current value of the atom\n *\n * @example\n * ```tsx\n * function UserProfile() {\n * const user = useAtom(userAtom)\n * return <div>{user.name}</div>\n * }\n * ```\n */\nfunction useAtom<T>(atom: Lite.Atom<T>): T {\n const ctrl = useController(atom)\n const atomRef = useRef(atom)\n atomRef.current = atom\n\n const getSnapshot = useCallback((): T => {\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 ctrl.get()\n }, [ctrl])\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => ctrl.on('resolved', 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 }\n"],"mappings":";;;;;;;;AAMA,MAAM,eAAe,cAAiC,KAAK;;;;;;;;;;;AAiB3D,SAAS,cAAc,EAAE,OAAO,YAAgC;AAC9D,QACE,oBAAC,aAAa;EAAS,OAAO;EAC3B;GACqB;;;;;ACvB5B,MAAM,kCAAkB,IAAI,SAA+C;AAE3E,SAAS,0BAA6B,QAAoB,MAAsC;CAC9F,IAAI,UAAU,gBAAgB,IAAIA,OAAK;AACvC,KAAI,CAAC,SAAS;AACZ,YAAU,KAAK,SAAS;AACxB,kBAAgB,IAAIA,QAAM,QAAQ;AAClC,UAAQ,cAAc,gBAAgB,OAAOA,OAAK,CAAC;;AAErD,QAAO;;;;;;;;;;;;;;AAeT,SAAS,WAAuB;CAC9B,MAAM,QAAQ,WAAW,aAAa;AACtC,KAAI,CAAC,MACH,OAAM,IAAI,MAAM,+CAA+C;AAEjE,QAAO;;;;;;;;;;;;;;AAeT,SAAS,cAAiB,QAAwC;CAChE,MAAM,QAAQ,UAAU;AACxB,QAAO,cAAc,MAAM,WAAWA,OAAK,EAAE,CAAC,OAAOA,OAAK,CAAC;;;;;;;;;;;;;;;;;AAkB7D,SAAS,QAAW,QAAuB;CACzC,MAAM,OAAO,cAAcA,OAAK;CAChC,MAAM,UAAU,OAAOA,OAAK;AAC5B,SAAQ,UAAUA;CAElB,MAAM,cAAc,kBAAqB;EACvC,MAAM,QAAQ,KAAK;AACnB,MAAI,UAAU,UAAU,UAAU,YAChC,OAAM,0BAA0B,QAAQ,SAAS,KAAK;AAExD,MAAI,UAAU,SACZ,OAAM,KAAK,KAAK;AAElB,SAAO,KAAK,KAAK;IAChB,CAAC,KAAK,CAAC;AAOV,QAAO,qBALW,aACf,kBAA8B,KAAK,GAAG,YAAY,cAAc,EACjE,CAAC,KAAK,CACP,EAEsC,aAAa,YAAY;;;;;;;;;;;;;;;;AAiBlE,SAAS,UACP,QACA,UACA,IACG;CACH,MAAM,QAAQ,UAAU;CACxB,MAAM,OAAO,cAAcA,OAAK;CAEhC,MAAM,UAAU,OAAOA,OAAK;AAC5B,SAAQ,UAAUA;CAElB,MAAM,cAAc,OAAO,SAAS;CACpC,MAAM,QAAQ,OAAO,GAAG;AACxB,aAAY,UAAU;AACtB,OAAM,UAAU;CAEhB,MAAM,YAAY,OAIR,KAAK;CAEf,MAAM,oBAAoB,kBAAkB;AAC1C,MACE,CAAC,UAAU,WACX,UAAU,QAAQ,UAAU,SAC5B,UAAU,QAAQ,SAASA,OAG3B,WAAU,UAAU;GAAE;GAAO;GAAM,QADpB,MAAM,OAAOA,QAAM,YAAY,SAAS,EAAE,IAAI,MAAM,SAAS,CAAC;GAClC;AAE7C,SAAO,UAAU,QAAQ;IACxB,CAAC,OAAOA,OAAK,CAAC;CAEjB,MAAM,cAAc,kBAAqB;EACvC,MAAM,QAAQ,KAAK;AACnB,MAAI,UAAU,UAAU,UAAU,YAChC,OAAM,0BAA0B,QAAQ,SAAS,KAAK;AAExD,MAAI,UAAU,SACZ,OAAM,KAAK,KAAK;AAElB,SAAO,mBAAmB,CAAC,KAAK;IAC/B,CAAC,MAAM,kBAAkB,CAAC;AAS7B,QAAO,qBAPW,aAAa,kBAA8B;AAC3D,MAAI,KAAK,UAAU,WACjB,cAAa;AAEf,SAAO,mBAAmB,CAAC,UAAU,cAAc;IAClD,CAAC,MAAM,kBAAkB,CAAC,EAEU,aAAa,YAAY"}
|
|
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.
|
|
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/
|
|
35
|
-
"
|
|
34
|
+
"@types/node": "^20.19.22",
|
|
35
|
+
"@types/react": "^18.3.27",
|
|
36
|
+
"jsdom": "^27.3.0",
|
|
36
37
|
"react": "^18.3.1",
|
|
37
|
-
"tsdown": "^0.
|
|
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"
|