@effect-rx/rx-react 0.38.0 → 0.38.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Hooks/package.json +6 -0
- package/ReactHydration/package.json +6 -0
- package/RegistryContext/package.json +6 -0
- package/dist/cjs/Hooks.js +254 -0
- package/dist/cjs/Hooks.js.map +1 -0
- package/dist/cjs/ReactHydration.js +50 -0
- package/dist/cjs/ReactHydration.js.map +1 -0
- package/dist/cjs/RegistryContext.js +73 -0
- package/dist/cjs/RegistryContext.js.map +1 -0
- package/dist/cjs/index.js +40 -293
- package/dist/cjs/index.js.map +1 -1
- package/dist/dts/Hooks.d.ts +79 -0
- package/dist/dts/Hooks.d.ts.map +1 -0
- package/dist/dts/ReactHydration.d.ts +11 -0
- package/dist/dts/ReactHydration.d.ts.map +1 -0
- package/dist/dts/RegistryContext.d.ts +25 -0
- package/dist/dts/RegistryContext.d.ts.map +1 -0
- package/dist/dts/index.d.ts +12 -98
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/esm/Hooks.js +215 -0
- package/dist/esm/Hooks.js.map +1 -0
- package/dist/esm/ReactHydration.js +23 -0
- package/dist/esm/ReactHydration.js.map +1 -0
- package/dist/esm/RegistryContext.js +45 -0
- package/dist/esm/RegistryContext.js.map +1 -0
- package/dist/esm/index.js +12 -243
- package/dist/esm/index.js.map +1 -1
- package/package.json +30 -2
- package/src/Hooks.ts +285 -0
- package/src/ReactHydration.ts +22 -0
- package/src/RegistryContext.ts +54 -0
- package/src/index.ts +12 -319
package/src/index.ts
CHANGED
|
@@ -2,351 +2,44 @@
|
|
|
2
2
|
* @since 1.0.0
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import * as Registry from "@effect-rx/rx/Registry"
|
|
6
|
-
import * as Result from "@effect-rx/rx/Result"
|
|
7
|
-
import * as Rx from "@effect-rx/rx/Rx"
|
|
8
|
-
import type * as RxRef from "@effect-rx/rx/RxRef"
|
|
9
|
-
import * as Cause from "effect/Cause"
|
|
10
|
-
import type * as Exit from "effect/Exit"
|
|
11
|
-
import { globalValue } from "effect/GlobalValue"
|
|
12
|
-
import * as React from "react"
|
|
13
|
-
import * as Scheduler from "scheduler"
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @since 1.0.0
|
|
17
|
-
* @category modules
|
|
18
|
-
*/
|
|
19
|
-
export * as Registry from "@effect-rx/rx/Registry"
|
|
20
5
|
/**
|
|
21
6
|
* @since 1.0.0
|
|
22
|
-
* @category
|
|
23
|
-
*/
|
|
24
|
-
export * as Result from "@effect-rx/rx/Result"
|
|
25
|
-
/**
|
|
26
|
-
* @since 1.0.0
|
|
27
|
-
* @category modules
|
|
7
|
+
* @category re-exports
|
|
28
8
|
*/
|
|
29
9
|
export * as Rx from "@effect-rx/rx/Rx"
|
|
30
|
-
/**
|
|
31
|
-
* @since 1.0.0
|
|
32
|
-
* @category modules
|
|
33
|
-
*/
|
|
34
|
-
export * as RxRef from "@effect-rx/rx/RxRef"
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* @since 1.0.0
|
|
38
|
-
* @category context
|
|
39
|
-
*/
|
|
40
|
-
export function scheduleTask(f: () => void): void {
|
|
41
|
-
Scheduler.unstable_scheduleCallback(Scheduler.unstable_LowPriority, f)
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* @since 1.0.0
|
|
46
|
-
* @category context
|
|
47
|
-
*/
|
|
48
|
-
export const RegistryContext = React.createContext<Registry.Registry>(Registry.make({
|
|
49
|
-
scheduleTask,
|
|
50
|
-
defaultIdleTTL: 400
|
|
51
|
-
}))
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* @since 1.0.0
|
|
55
|
-
* @category context
|
|
56
|
-
*/
|
|
57
|
-
export const RegistryProvider = (options: {
|
|
58
|
-
readonly children?: React.ReactNode | undefined
|
|
59
|
-
readonly initialValues?: Iterable<readonly [Rx.Rx<any>, any]> | undefined
|
|
60
|
-
readonly scheduleTask?: ((f: () => void) => void) | undefined
|
|
61
|
-
readonly timeoutResolution?: number | undefined
|
|
62
|
-
readonly defaultIdleTTL?: number | undefined
|
|
63
|
-
}) => {
|
|
64
|
-
const registry = React.useMemo(() =>
|
|
65
|
-
Registry.make({
|
|
66
|
-
scheduleTask,
|
|
67
|
-
defaultIdleTTL: 400,
|
|
68
|
-
...options
|
|
69
|
-
}), [])
|
|
70
|
-
React.useEffect(() => () => {
|
|
71
|
-
registry.dispose()
|
|
72
|
-
}, [registry])
|
|
73
|
-
return React.createElement(RegistryContext.Provider, {
|
|
74
|
-
value: Registry.make({
|
|
75
|
-
scheduleTask,
|
|
76
|
-
defaultIdleTTL: 400,
|
|
77
|
-
...options
|
|
78
|
-
})
|
|
79
|
-
}, options?.children)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
interface RxStore<A> {
|
|
83
|
-
readonly subscribe: (f: () => void) => () => void
|
|
84
|
-
readonly snapshot: () => A
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const storeRegistry = globalValue(
|
|
88
|
-
"@effect-rx/rx-react/storeRegistry",
|
|
89
|
-
() => new WeakMap<Registry.Registry, WeakMap<Rx.Rx<any>, RxStore<any>>>()
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
function makeStore<A>(registry: Registry.Registry, rx: Rx.Rx<A>): RxStore<A> {
|
|
93
|
-
let stores = storeRegistry.get(registry)
|
|
94
|
-
if (stores === undefined) {
|
|
95
|
-
stores = new WeakMap()
|
|
96
|
-
storeRegistry.set(registry, stores)
|
|
97
|
-
}
|
|
98
|
-
const store = stores.get(rx)
|
|
99
|
-
if (store !== undefined) {
|
|
100
|
-
return store
|
|
101
|
-
}
|
|
102
|
-
const newStore: RxStore<A> = {
|
|
103
|
-
subscribe(f) {
|
|
104
|
-
return registry.subscribe(rx, f)
|
|
105
|
-
},
|
|
106
|
-
snapshot() {
|
|
107
|
-
return registry.get(rx)
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
stores.set(rx, newStore)
|
|
111
|
-
return newStore
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function useStore<A>(registry: Registry.Registry, rx: Rx.Rx<A>): A {
|
|
115
|
-
const store = makeStore(registry, rx)
|
|
116
|
-
return React.useSyncExternalStore(store.subscribe, store.snapshot, store.snapshot)
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
const initialValuesSet = globalValue(
|
|
120
|
-
"@effect-rx/rx-react/initialValuesSet",
|
|
121
|
-
() => new WeakMap<Registry.Registry, WeakSet<Rx.Rx<any>>>()
|
|
122
|
-
)
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* @since 1.0.0
|
|
126
|
-
* @category hooks
|
|
127
|
-
*/
|
|
128
|
-
export const useRxInitialValues = (initialValues: Iterable<readonly [Rx.Rx<any>, any]>): void => {
|
|
129
|
-
const registry = React.useContext(RegistryContext)
|
|
130
|
-
let set = initialValuesSet.get(registry)
|
|
131
|
-
if (set === undefined) {
|
|
132
|
-
set = new WeakSet()
|
|
133
|
-
initialValuesSet.set(registry, set)
|
|
134
|
-
}
|
|
135
|
-
for (const [rx, value] of initialValues) {
|
|
136
|
-
if (!set.has(rx)) {
|
|
137
|
-
set.add(rx)
|
|
138
|
-
;(registry as any).ensureNode(rx).setValue(value)
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* @since 1.0.0
|
|
145
|
-
* @category hooks
|
|
146
|
-
*/
|
|
147
|
-
export const useRxValue: {
|
|
148
|
-
<A>(rx: Rx.Rx<A>): A
|
|
149
|
-
<A, B>(rx: Rx.Rx<A>, f: (_: A) => B): B
|
|
150
|
-
} = <A>(rx: Rx.Rx<A>, f?: (_: A) => A): A => {
|
|
151
|
-
const registry = React.useContext(RegistryContext)
|
|
152
|
-
if (f) {
|
|
153
|
-
const rxB = React.useMemo(() => Rx.map(rx, f), [rx, f])
|
|
154
|
-
return useStore(registry, rxB)
|
|
155
|
-
}
|
|
156
|
-
return useStore(registry, rx)
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
function mountRx<A>(registry: Registry.Registry, rx: Rx.Rx<A>): void {
|
|
160
|
-
React.useEffect(() => registry.mount(rx), [rx, registry])
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function setRx<R, W>(registry: Registry.Registry, rx: Rx.Writable<R, W>): (_: W | ((_: R) => W)) => void {
|
|
164
|
-
return React.useCallback((value) => {
|
|
165
|
-
if (typeof value === "function") {
|
|
166
|
-
registry.set(rx, (value as any)(registry.get(rx)))
|
|
167
|
-
return
|
|
168
|
-
} else {
|
|
169
|
-
registry.set(rx, value)
|
|
170
|
-
}
|
|
171
|
-
}, [registry, rx])
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* @since 1.0.0
|
|
176
|
-
* @category hooks
|
|
177
|
-
*/
|
|
178
|
-
export const useRxMount = <A>(rx: Rx.Rx<A>): void => {
|
|
179
|
-
const registry = React.useContext(RegistryContext)
|
|
180
|
-
mountRx(registry, rx)
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* @since 1.0.0
|
|
185
|
-
* @category hooks
|
|
186
|
-
*/
|
|
187
|
-
export const useRxSet = <R, W>(rx: Rx.Writable<R, W>): (_: W | ((_: R) => W)) => void => {
|
|
188
|
-
const registry = React.useContext(RegistryContext)
|
|
189
|
-
mountRx(registry, rx)
|
|
190
|
-
return setRx(registry, rx)
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* @since 1.0.0
|
|
195
|
-
* @category hooks
|
|
196
|
-
*/
|
|
197
|
-
export const useRxSetPromise = <E, A, W>(
|
|
198
|
-
rx: Rx.Writable<Result.Result<A, E>, W>
|
|
199
|
-
): (_: W) => Promise<Exit.Exit<A, E>> => {
|
|
200
|
-
const registry = React.useContext(RegistryContext)
|
|
201
|
-
const resolves = React.useMemo(() => new Set<(result: Exit.Exit<A, E>) => void>(), [])
|
|
202
|
-
React.useEffect(() =>
|
|
203
|
-
registry.subscribe(rx, (result) => {
|
|
204
|
-
if (result.waiting || result._tag === "Initial") return
|
|
205
|
-
const fns = Array.from(resolves)
|
|
206
|
-
resolves.clear()
|
|
207
|
-
const exit = Result.toExit(result)
|
|
208
|
-
fns.forEach((resolve) => resolve(exit as any))
|
|
209
|
-
}, { immediate: true }), [registry, rx, resolves])
|
|
210
|
-
return React.useCallback((value) =>
|
|
211
|
-
new Promise((resolve) => {
|
|
212
|
-
resolves.add(resolve)
|
|
213
|
-
registry.set(rx, value)
|
|
214
|
-
}), [registry, rx, resolves])
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* @since 1.0.0
|
|
219
|
-
* @category hooks
|
|
220
|
-
*/
|
|
221
|
-
export const useRxRefresh = <A>(rx: Rx.Rx<A> & Rx.Refreshable): () => void => {
|
|
222
|
-
const registry = React.useContext(RegistryContext)
|
|
223
|
-
mountRx(registry, rx)
|
|
224
|
-
return React.useCallback(() => {
|
|
225
|
-
registry.refresh(rx)
|
|
226
|
-
}, [registry, rx])
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* @since 1.0.0
|
|
231
|
-
* @category hooks
|
|
232
|
-
*/
|
|
233
|
-
export const useRx = <R, W>(
|
|
234
|
-
rx: Rx.Writable<R, W>
|
|
235
|
-
): readonly [value: R, setOrUpdate: (_: W | ((_: R) => W)) => void] => {
|
|
236
|
-
const registry = React.useContext(RegistryContext)
|
|
237
|
-
return [
|
|
238
|
-
useStore(registry, rx),
|
|
239
|
-
setRx(registry, rx)
|
|
240
|
-
] as const
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
const rxPromiseMap = globalValue(
|
|
244
|
-
"@effect-rx/rx-react/rxPromiseMap",
|
|
245
|
-
() => ({
|
|
246
|
-
suspendOnWaiting: new Map<Rx.Rx<any>, Promise<void>>(),
|
|
247
|
-
default: new Map<Rx.Rx<any>, Promise<void>>()
|
|
248
|
-
})
|
|
249
|
-
)
|
|
250
|
-
|
|
251
|
-
function rxToPromise<A, E>(
|
|
252
|
-
registry: Registry.Registry,
|
|
253
|
-
rx: Rx.Rx<Result.Result<A, E>>,
|
|
254
|
-
suspendOnWaiting: boolean
|
|
255
|
-
) {
|
|
256
|
-
const map = suspendOnWaiting ? rxPromiseMap.suspendOnWaiting : rxPromiseMap.default
|
|
257
|
-
let promise = map.get(rx)
|
|
258
|
-
if (promise !== undefined) {
|
|
259
|
-
return promise
|
|
260
|
-
}
|
|
261
|
-
promise = new Promise<void>((resolve) => {
|
|
262
|
-
const dispose = registry.subscribe(rx, (result) => {
|
|
263
|
-
if (result._tag === "Initial" || (suspendOnWaiting && result.waiting)) {
|
|
264
|
-
return
|
|
265
|
-
}
|
|
266
|
-
setTimeout(dispose, 1000)
|
|
267
|
-
resolve()
|
|
268
|
-
map.delete(rx)
|
|
269
|
-
})
|
|
270
|
-
})
|
|
271
|
-
map.set(rx, promise)
|
|
272
|
-
return promise
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
function rxResultOrSuspend<A, E>(
|
|
276
|
-
registry: Registry.Registry,
|
|
277
|
-
rx: Rx.Rx<Result.Result<A, E>>,
|
|
278
|
-
suspendOnWaiting: boolean
|
|
279
|
-
) {
|
|
280
|
-
const value = useStore(registry, rx)
|
|
281
|
-
if (value._tag === "Initial" || (suspendOnWaiting && value.waiting)) {
|
|
282
|
-
throw rxToPromise(registry, rx, suspendOnWaiting)
|
|
283
|
-
}
|
|
284
|
-
return value
|
|
285
|
-
}
|
|
286
10
|
|
|
287
11
|
/**
|
|
288
12
|
* @since 1.0.0
|
|
289
|
-
* @category
|
|
13
|
+
* @category re-exports
|
|
290
14
|
*/
|
|
291
|
-
export
|
|
292
|
-
rx: Rx.Rx<Result.Result<A, E>>,
|
|
293
|
-
options?: { readonly suspendOnWaiting?: boolean }
|
|
294
|
-
): Result.Success<A, E> | Result.Failure<A, E> => {
|
|
295
|
-
const registry = React.useContext(RegistryContext)
|
|
296
|
-
return rxResultOrSuspend(registry, rx, options?.suspendOnWaiting ?? false)
|
|
297
|
-
}
|
|
15
|
+
export * as Registry from "@effect-rx/rx/Registry"
|
|
298
16
|
|
|
299
17
|
/**
|
|
300
18
|
* @since 1.0.0
|
|
301
|
-
* @category
|
|
19
|
+
* @category re-exports
|
|
302
20
|
*/
|
|
303
|
-
export
|
|
304
|
-
rx: Rx.Rx<Result.Result<A, E>>,
|
|
305
|
-
options?: { readonly suspendOnWaiting?: boolean }
|
|
306
|
-
): Result.Success<A, E> => {
|
|
307
|
-
const result = useRxSuspense(rx, options)
|
|
308
|
-
if (result._tag === "Failure") {
|
|
309
|
-
throw Cause.squash(result.cause)
|
|
310
|
-
}
|
|
311
|
-
return result
|
|
312
|
-
}
|
|
21
|
+
export * as Result from "@effect-rx/rx/Registry"
|
|
313
22
|
|
|
314
23
|
/**
|
|
315
24
|
* @since 1.0.0
|
|
316
|
-
* @category
|
|
25
|
+
* @category re-exports
|
|
317
26
|
*/
|
|
318
|
-
export
|
|
319
|
-
rx: Rx.Rx<A>,
|
|
320
|
-
f: (_: A) => void,
|
|
321
|
-
options?: { readonly immediate?: boolean }
|
|
322
|
-
): void => {
|
|
323
|
-
const registry = React.useContext(RegistryContext)
|
|
324
|
-
React.useEffect(
|
|
325
|
-
() => registry.subscribe(rx, f, options),
|
|
326
|
-
[registry, rx, f, options?.immediate]
|
|
327
|
-
)
|
|
328
|
-
}
|
|
27
|
+
export * as Hydration from "@effect-rx/rx/Hydration"
|
|
329
28
|
|
|
330
29
|
/**
|
|
331
30
|
* @since 1.0.0
|
|
332
|
-
* @category
|
|
31
|
+
* @category re-exports
|
|
333
32
|
*/
|
|
334
|
-
export
|
|
335
|
-
const [, setValue] = React.useState(ref.value)
|
|
336
|
-
React.useEffect(() => ref.subscribe(setValue), [ref])
|
|
337
|
-
return ref.value
|
|
338
|
-
}
|
|
33
|
+
export * as RxRef from "@effect-rx/rx/RxRef"
|
|
339
34
|
|
|
340
35
|
/**
|
|
341
36
|
* @since 1.0.0
|
|
342
37
|
* @category hooks
|
|
343
38
|
*/
|
|
344
|
-
export
|
|
345
|
-
React.useMemo(() => ref.prop(prop), [ref, prop])
|
|
39
|
+
export * from "./Hooks.js"
|
|
346
40
|
|
|
347
41
|
/**
|
|
348
42
|
* @since 1.0.0
|
|
349
|
-
* @category
|
|
43
|
+
* @category context
|
|
350
44
|
*/
|
|
351
|
-
export
|
|
352
|
-
useRxRef(useRxRefProp(ref, prop))
|
|
45
|
+
export * from "./RegistryContext.js"
|