@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/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 modules
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 hooks
13
+ * @category re-exports
290
14
  */
291
- export const useRxSuspense = <A, E>(
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 hooks
19
+ * @category re-exports
302
20
  */
303
- export const useRxSuspenseSuccess = <A, E>(
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 hooks
25
+ * @category re-exports
317
26
  */
318
- export const useRxSubscribe = <A>(
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 hooks
31
+ * @category re-exports
333
32
  */
334
- export const useRxRef = <A>(ref: RxRef.ReadonlyRef<A>): A => {
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 const useRxRefProp = <A, K extends keyof A>(ref: RxRef.RxRef<A>, prop: K): RxRef.RxRef<A[K]> =>
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 hooks
43
+ * @category context
350
44
  */
351
- export const useRxRefPropValue = <A, K extends keyof A>(ref: RxRef.RxRef<A>, prop: K): A[K] =>
352
- useRxRef(useRxRefProp(ref, prop))
45
+ export * from "./RegistryContext.js"