@effect/atom-react 4.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023-present The Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,7 @@
1
+ # `@effect/atom-react`
2
+
3
+ React bindings for the Effect Atom modules.
4
+
5
+ ## Documentation
6
+
7
+ - **API Reference**: [View the full documentation](https://effect-ts.github.io/effect/docs/atom-react).
@@ -0,0 +1,80 @@
1
+ import * as Exit from "effect/Exit";
2
+ import type * as AsyncResult from "effect/unstable/reactivity/AsyncResult";
3
+ import * as Atom from "effect/unstable/reactivity/Atom";
4
+ import type * as AtomRef from "effect/unstable/reactivity/AtomRef";
5
+ /**
6
+ * @since 1.0.0
7
+ * @category hooks
8
+ */
9
+ export declare const useAtomInitialValues: (initialValues: Iterable<readonly [Atom.Atom<any>, any]>) => void;
10
+ /**
11
+ * @since 1.0.0
12
+ * @category hooks
13
+ */
14
+ export declare const useAtomValue: {
15
+ /**
16
+ * @since 1.0.0
17
+ * @category hooks
18
+ */
19
+ <A>(atom: Atom.Atom<A>): A;
20
+ /**
21
+ * @since 1.0.0
22
+ * @category hooks
23
+ */
24
+ <A, B>(atom: Atom.Atom<A>, f: (_: A) => B): B;
25
+ };
26
+ /**
27
+ * @since 1.0.0
28
+ * @category hooks
29
+ */
30
+ export declare const useAtomMount: <A>(atom: Atom.Atom<A>) => void;
31
+ /**
32
+ * @since 1.0.0
33
+ * @category hooks
34
+ */
35
+ export declare const useAtomSet: <R, W, Mode extends "value" | "promise" | "promiseExit" = never>(atom: Atom.Writable<R, W>, options?: {
36
+ readonly mode?: ([R] extends [AsyncResult.AsyncResult<any, any>] ? Mode : "value") | undefined;
37
+ }) => "promise" extends Mode ? ((value: W) => Promise<AsyncResult.AsyncResult.Success<R>>) : "promiseExit" extends Mode ? ((value: W) => Promise<Exit.Exit<AsyncResult.AsyncResult.Success<R>, AsyncResult.AsyncResult.Failure<R>>>) : ((value: W | ((value: R) => W)) => void);
38
+ /**
39
+ * @since 1.0.0
40
+ * @category hooks
41
+ */
42
+ export declare const useAtomRefresh: <A>(atom: Atom.Atom<A>) => () => void;
43
+ /**
44
+ * @since 1.0.0
45
+ * @category hooks
46
+ */
47
+ export declare const useAtom: <R, W, const Mode extends "value" | "promise" | "promiseExit" = never>(atom: Atom.Writable<R, W>, options?: {
48
+ readonly mode?: ([R] extends [AsyncResult.AsyncResult<any, any>] ? Mode : "value") | undefined;
49
+ }) => readonly [value: R, write: "promise" extends Mode ? ((value: W) => Promise<AsyncResult.AsyncResult.Success<R>>) : "promiseExit" extends Mode ? ((value: W) => Promise<Exit.Exit<AsyncResult.AsyncResult.Success<R>, AsyncResult.AsyncResult.Failure<R>>>) : ((value: W | ((value: R) => W)) => void)];
50
+ /**
51
+ * @since 1.0.0
52
+ * @category hooks
53
+ */
54
+ export declare const useAtomSuspense: <A, E, const IncludeFailure extends boolean = false>(atom: Atom.Atom<AsyncResult.AsyncResult<A, E>>, options?: {
55
+ readonly suspendOnWaiting?: boolean | undefined;
56
+ readonly includeFailure?: IncludeFailure | undefined;
57
+ }) => AsyncResult.Success<A, E> | (IncludeFailure extends true ? AsyncResult.Failure<A, E> : never);
58
+ /**
59
+ * @since 1.0.0
60
+ * @category hooks
61
+ */
62
+ export declare const useAtomSubscribe: <A>(atom: Atom.Atom<A>, f: (_: A) => void, options?: {
63
+ readonly immediate?: boolean;
64
+ }) => void;
65
+ /**
66
+ * @since 1.0.0
67
+ * @category hooks
68
+ */
69
+ export declare const useAtomRef: <A>(ref: AtomRef.ReadonlyRef<A>) => A;
70
+ /**
71
+ * @since 1.0.0
72
+ * @category hooks
73
+ */
74
+ export declare const useAtomRefProp: <A, K extends keyof A>(ref: AtomRef.AtomRef<A>, prop: K) => AtomRef.AtomRef<A[K]>;
75
+ /**
76
+ * @since 1.0.0
77
+ * @category hooks
78
+ */
79
+ export declare const useAtomRefPropValue: <A, K extends keyof A>(ref: AtomRef.AtomRef<A>, prop: K) => A[K];
80
+ //# sourceMappingURL=Hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Hooks.d.ts","sourceRoot":"","sources":["../src/Hooks.ts"],"names":[],"mappings":"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"}
package/dist/Hooks.js ADDED
@@ -0,0 +1,199 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ "use client";
5
+
6
+ import * as Cause from "effect/Cause";
7
+ import * as Effect from "effect/Effect";
8
+ import * as Exit from "effect/Exit";
9
+ import * as Atom from "effect/unstable/reactivity/Atom";
10
+ import * as AtomRegistry from "effect/unstable/reactivity/AtomRegistry";
11
+ import * as React from "react";
12
+ import { RegistryContext } from "./RegistryContext.js";
13
+ const storeRegistry = /*#__PURE__*/new WeakMap();
14
+ function makeStore(registry, atom) {
15
+ let stores = storeRegistry.get(registry);
16
+ if (stores === undefined) {
17
+ stores = new WeakMap();
18
+ storeRegistry.set(registry, stores);
19
+ }
20
+ const store = stores.get(atom);
21
+ if (store !== undefined) {
22
+ return store;
23
+ }
24
+ const newStore = {
25
+ subscribe(f) {
26
+ return registry.subscribe(atom, f);
27
+ },
28
+ snapshot() {
29
+ return registry.get(atom);
30
+ },
31
+ getServerSnapshot() {
32
+ return Atom.getServerValue(atom, registry);
33
+ }
34
+ };
35
+ stores.set(atom, newStore);
36
+ return newStore;
37
+ }
38
+ function useStore(registry, atom) {
39
+ const store = makeStore(registry, atom);
40
+ return React.useSyncExternalStore(store.subscribe, store.snapshot, store.getServerSnapshot);
41
+ }
42
+ const initialValuesSet = /*#__PURE__*/new WeakMap();
43
+ /**
44
+ * @since 1.0.0
45
+ * @category hooks
46
+ */
47
+ export const useAtomInitialValues = initialValues => {
48
+ const registry = React.useContext(RegistryContext);
49
+ let set = initialValuesSet.get(registry);
50
+ if (set === undefined) {
51
+ set = new WeakSet();
52
+ initialValuesSet.set(registry, set);
53
+ }
54
+ for (const [atom, value] of initialValues) {
55
+ if (!set.has(atom)) {
56
+ set.add(atom);
57
+ registry.ensureNode(atom).setValue(value);
58
+ }
59
+ }
60
+ };
61
+ /**
62
+ * @since 1.0.0
63
+ * @category hooks
64
+ */
65
+ export const useAtomValue = (atom, f) => {
66
+ const registry = React.useContext(RegistryContext);
67
+ if (f) {
68
+ const atomB = React.useMemo(() => Atom.map(atom, f), [atom, f]);
69
+ return useStore(registry, atomB);
70
+ }
71
+ return useStore(registry, atom);
72
+ };
73
+ function mountAtom(registry, atom) {
74
+ React.useEffect(() => registry.mount(atom), [atom, registry]);
75
+ }
76
+ function setAtom(registry, atom, options) {
77
+ if (options?.mode === "promise" || options?.mode === "promiseExit") {
78
+ return React.useCallback(value => {
79
+ registry.set(atom, value);
80
+ const promise = Effect.runPromiseExit(AtomRegistry.getResult(registry, atom, {
81
+ suspendOnWaiting: true
82
+ }));
83
+ return options.mode === "promise" ? promise.then(flattenExit) : promise;
84
+ }, [registry, atom, options.mode]);
85
+ }
86
+ return React.useCallback(value => {
87
+ registry.set(atom, typeof value === "function" ? value(registry.get(atom)) : value);
88
+ }, [registry, atom]);
89
+ }
90
+ const flattenExit = exit => {
91
+ if (Exit.isSuccess(exit)) return exit.value;
92
+ throw Cause.squash(exit.cause);
93
+ };
94
+ /**
95
+ * @since 1.0.0
96
+ * @category hooks
97
+ */
98
+ export const useAtomMount = atom => {
99
+ const registry = React.useContext(RegistryContext);
100
+ mountAtom(registry, atom);
101
+ };
102
+ /**
103
+ * @since 1.0.0
104
+ * @category hooks
105
+ */
106
+ export const useAtomSet = (atom, options) => {
107
+ const registry = React.useContext(RegistryContext);
108
+ mountAtom(registry, atom);
109
+ return setAtom(registry, atom, options);
110
+ };
111
+ /**
112
+ * @since 1.0.0
113
+ * @category hooks
114
+ */
115
+ export const useAtomRefresh = atom => {
116
+ const registry = React.useContext(RegistryContext);
117
+ mountAtom(registry, atom);
118
+ return React.useCallback(() => {
119
+ registry.refresh(atom);
120
+ }, [registry, atom]);
121
+ };
122
+ /**
123
+ * @since 1.0.0
124
+ * @category hooks
125
+ */
126
+ export const useAtom = (atom, options) => {
127
+ const registry = React.useContext(RegistryContext);
128
+ return [useStore(registry, atom), setAtom(registry, atom, options)];
129
+ };
130
+ const atomPromiseMap = {
131
+ suspendOnWaiting: /*#__PURE__*/new Map(),
132
+ default: /*#__PURE__*/new Map()
133
+ };
134
+ function atomToPromise(registry, atom, suspendOnWaiting) {
135
+ const map = suspendOnWaiting ? atomPromiseMap.suspendOnWaiting : atomPromiseMap.default;
136
+ let promise = map.get(atom);
137
+ if (promise !== undefined) {
138
+ return promise;
139
+ }
140
+ promise = new Promise(resolve => {
141
+ const dispose = registry.subscribe(atom, result => {
142
+ if (result._tag === "Initial" || suspendOnWaiting && result.waiting) {
143
+ return;
144
+ }
145
+ setTimeout(dispose, 1000);
146
+ resolve();
147
+ map.delete(atom);
148
+ });
149
+ });
150
+ map.set(atom, promise);
151
+ return promise;
152
+ }
153
+ function atomResultOrSuspend(registry, atom, suspendOnWaiting) {
154
+ const value = useStore(registry, atom);
155
+ if (value._tag === "Initial" || suspendOnWaiting && value.waiting) {
156
+ throw atomToPromise(registry, atom, suspendOnWaiting);
157
+ }
158
+ return value;
159
+ }
160
+ /**
161
+ * @since 1.0.0
162
+ * @category hooks
163
+ */
164
+ export const useAtomSuspense = (atom, options) => {
165
+ const registry = React.useContext(RegistryContext);
166
+ const result = atomResultOrSuspend(registry, atom, options?.suspendOnWaiting ?? false);
167
+ if (result._tag === "Failure" && !options?.includeFailure) {
168
+ throw Cause.squash(result.cause);
169
+ }
170
+ return result;
171
+ };
172
+ /**
173
+ * @since 1.0.0
174
+ * @category hooks
175
+ */
176
+ export const useAtomSubscribe = (atom, f, options) => {
177
+ const registry = React.useContext(RegistryContext);
178
+ React.useEffect(() => registry.subscribe(atom, f, options), [registry, atom, f, options?.immediate]);
179
+ };
180
+ /**
181
+ * @since 1.0.0
182
+ * @category hooks
183
+ */
184
+ export const useAtomRef = ref => {
185
+ const [, setValue] = React.useState(ref.value);
186
+ React.useEffect(() => ref.subscribe(setValue), [ref]);
187
+ return ref.value;
188
+ };
189
+ /**
190
+ * @since 1.0.0
191
+ * @category hooks
192
+ */
193
+ export const useAtomRefProp = (ref, prop) => React.useMemo(() => ref.prop(prop), [ref, prop]);
194
+ /**
195
+ * @since 1.0.0
196
+ * @category hooks
197
+ */
198
+ export const useAtomRefPropValue = (ref, prop) => useAtomRef(useAtomRefProp(ref, prop));
199
+ //# sourceMappingURL=Hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Hooks.js","names":["Cause","Effect","Exit","Atom","AtomRegistry","React","RegistryContext","storeRegistry","WeakMap","makeStore","registry","atom","stores","get","undefined","set","store","newStore","subscribe","f","snapshot","getServerSnapshot","getServerValue","useStore","useSyncExternalStore","initialValuesSet","useAtomInitialValues","initialValues","useContext","WeakSet","value","has","add","ensureNode","setValue","useAtomValue","atomB","useMemo","map","mountAtom","useEffect","mount","setAtom","options","mode","useCallback","promise","runPromiseExit","getResult","suspendOnWaiting","then","flattenExit","exit","isSuccess","squash","cause","useAtomMount","useAtomSet","useAtomRefresh","refresh","useAtom","atomPromiseMap","Map","default","atomToPromise","Promise","resolve","dispose","result","_tag","waiting","setTimeout","delete","atomResultOrSuspend","useAtomSuspense","includeFailure","useAtomSubscribe","immediate","useAtomRef","ref","useState","useAtomRefProp","prop","useAtomRefPropValue"],"sources":["../src/Hooks.ts"],"sourcesContent":[null],"mappings":"AAAA;;;AAGA,YAAY;;AAEZ,OAAO,KAAKA,KAAK,MAAM,cAAc;AACrC,OAAO,KAAKC,MAAM,MAAM,eAAe;AACvC,OAAO,KAAKC,IAAI,MAAM,aAAa;AAEnC,OAAO,KAAKC,IAAI,MAAM,iCAAiC;AAEvD,OAAO,KAAKC,YAAY,MAAM,yCAAyC;AACvE,OAAO,KAAKC,KAAK,MAAM,OAAO;AAC9B,SAASC,eAAe,QAAQ,sBAAsB;AAQtD,MAAMC,aAAa,gBAAG,IAAIC,OAAO,EAAsE;AAEvG,SAASC,SAASA,CAAIC,QAAmC,EAAEC,IAAkB;EAC3E,IAAIC,MAAM,GAAGL,aAAa,CAACM,GAAG,CAACH,QAAQ,CAAC;EACxC,IAAIE,MAAM,KAAKE,SAAS,EAAE;IACxBF,MAAM,GAAG,IAAIJ,OAAO,EAAE;IACtBD,aAAa,CAACQ,GAAG,CAACL,QAAQ,EAAEE,MAAM,CAAC;EACrC;EACA,MAAMI,KAAK,GAAGJ,MAAM,CAACC,GAAG,CAACF,IAAI,CAAC;EAC9B,IAAIK,KAAK,KAAKF,SAAS,EAAE;IACvB,OAAOE,KAAK;EACd;EACA,MAAMC,QAAQ,GAAiB;IAC7BC,SAASA,CAACC,CAAC;MACT,OAAOT,QAAQ,CAACQ,SAAS,CAACP,IAAI,EAAEQ,CAAC,CAAC;IACpC,CAAC;IACDC,QAAQA,CAAA;MACN,OAAOV,QAAQ,CAACG,GAAG,CAACF,IAAI,CAAC;IAC3B,CAAC;IACDU,iBAAiBA,CAAA;MACf,OAAOlB,IAAI,CAACmB,cAAc,CAACX,IAAI,EAAED,QAAQ,CAAC;IAC5C;GACD;EACDE,MAAM,CAACG,GAAG,CAACJ,IAAI,EAAEM,QAAQ,CAAC;EAC1B,OAAOA,QAAQ;AACjB;AAEA,SAASM,QAAQA,CAAIb,QAAmC,EAAEC,IAAkB;EAC1E,MAAMK,KAAK,GAAGP,SAAS,CAACC,QAAQ,EAAEC,IAAI,CAAC;EAEvC,OAAON,KAAK,CAACmB,oBAAoB,CAACR,KAAK,CAACE,SAAS,EAAEF,KAAK,CAACI,QAAQ,EAAEJ,KAAK,CAACK,iBAAiB,CAAC;AAC7F;AAEA,MAAMI,gBAAgB,gBAAG,IAAIjB,OAAO,EAAsD;AAE1F;;;;AAIA,OAAO,MAAMkB,oBAAoB,GAAIC,aAAuD,IAAU;EACpG,MAAMjB,QAAQ,GAAGL,KAAK,CAACuB,UAAU,CAACtB,eAAe,CAAC;EAClD,IAAIS,GAAG,GAAGU,gBAAgB,CAACZ,GAAG,CAACH,QAAQ,CAAC;EACxC,IAAIK,GAAG,KAAKD,SAAS,EAAE;IACrBC,GAAG,GAAG,IAAIc,OAAO,EAAE;IACnBJ,gBAAgB,CAACV,GAAG,CAACL,QAAQ,EAAEK,GAAG,CAAC;EACrC;EACA,KAAK,MAAM,CAACJ,IAAI,EAAEmB,KAAK,CAAC,IAAIH,aAAa,EAAE;IACzC,IAAI,CAACZ,GAAG,CAACgB,GAAG,CAACpB,IAAI,CAAC,EAAE;MAClBI,GAAG,CAACiB,GAAG,CAACrB,IAAI,CAAC;MACXD,QAAgB,CAACuB,UAAU,CAACtB,IAAI,CAAC,CAACuB,QAAQ,CAACJ,KAAK,CAAC;IACrD;EACF;AACF,CAAC;AAED;;;;AAIA,OAAO,MAAMK,YAAY,GAWrBA,CAAIxB,IAAkB,EAAEQ,CAAe,KAAO;EAChD,MAAMT,QAAQ,GAAGL,KAAK,CAACuB,UAAU,CAACtB,eAAe,CAAC;EAClD,IAAIa,CAAC,EAAE;IACL,MAAMiB,KAAK,GAAG/B,KAAK,CAACgC,OAAO,CAAC,MAAMlC,IAAI,CAACmC,GAAG,CAAC3B,IAAI,EAAEQ,CAAC,CAAC,EAAE,CAACR,IAAI,EAAEQ,CAAC,CAAC,CAAC;IAC/D,OAAOI,QAAQ,CAACb,QAAQ,EAAE0B,KAAK,CAAC;EAClC;EACA,OAAOb,QAAQ,CAACb,QAAQ,EAAEC,IAAI,CAAC;AACjC,CAAC;AAED,SAAS4B,SAASA,CAAI7B,QAAmC,EAAEC,IAAkB;EAC3EN,KAAK,CAACmC,SAAS,CAAC,MAAM9B,QAAQ,CAAC+B,KAAK,CAAC9B,IAAI,CAAC,EAAE,CAACA,IAAI,EAAED,QAAQ,CAAC,CAAC;AAC/D;AAEA,SAASgC,OAAOA,CACdhC,QAAmC,EACnCC,IAAyB,EACzBgC,OAEC;EASD,IAAIA,OAAO,EAAEC,IAAI,KAAK,SAAS,IAAID,OAAO,EAAEC,IAAI,KAAK,aAAa,EAAE;IAClE,OAAOvC,KAAK,CAACwC,WAAW,CAAEf,KAAQ,IAAI;MACpCpB,QAAQ,CAACK,GAAG,CAACJ,IAAI,EAAEmB,KAAK,CAAC;MACzB,MAAMgB,OAAO,GAAG7C,MAAM,CAAC8C,cAAc,CACnC3C,YAAY,CAAC4C,SAAS,CAACtC,QAAQ,EAAEC,IAAoD,EAAE;QACrFsC,gBAAgB,EAAE;OACnB,CAAC,CACH;MACD,OAAON,OAAQ,CAACC,IAAI,KAAK,SAAS,GAAGE,OAAO,CAACI,IAAI,CAACC,WAAW,CAAC,GAAGL,OAAO;IAC1E,CAAC,EAAE,CAACpC,QAAQ,EAAEC,IAAI,EAAEgC,OAAO,CAACC,IAAI,CAAC,CAAQ;EAC3C;EACA,OAAOvC,KAAK,CAACwC,WAAW,CAAEf,KAA4B,IAAI;IACxDpB,QAAQ,CAACK,GAAG,CAACJ,IAAI,EAAE,OAAOmB,KAAK,KAAK,UAAU,GAAIA,KAAa,CAACpB,QAAQ,CAACG,GAAG,CAACF,IAAI,CAAC,CAAC,GAAGmB,KAAK,CAAC;EAC9F,CAAC,EAAE,CAACpB,QAAQ,EAAEC,IAAI,CAAC,CAAQ;AAC7B;AAEA,MAAMwC,WAAW,GAAUC,IAAqB,IAAO;EACrD,IAAIlD,IAAI,CAACmD,SAAS,CAACD,IAAI,CAAC,EAAE,OAAOA,IAAI,CAACtB,KAAK;EAC3C,MAAM9B,KAAK,CAACsD,MAAM,CAACF,IAAI,CAACG,KAAK,CAAC;AAChC,CAAC;AAED;;;;AAIA,OAAO,MAAMC,YAAY,GAAO7C,IAAkB,IAAU;EAC1D,MAAMD,QAAQ,GAAGL,KAAK,CAACuB,UAAU,CAACtB,eAAe,CAAC;EAClDiC,SAAS,CAAC7B,QAAQ,EAAEC,IAAI,CAAC;AAC3B,CAAC;AAED;;;;AAIA,OAAO,MAAM8C,UAAU,GAAGA,CAKxB9C,IAAyB,EACzBgC,OAEC,KAO0C;EAE3C,MAAMjC,QAAQ,GAAGL,KAAK,CAACuB,UAAU,CAACtB,eAAe,CAAC;EAClDiC,SAAS,CAAC7B,QAAQ,EAAEC,IAAI,CAAC;EACzB,OAAO+B,OAAO,CAAChC,QAAQ,EAAEC,IAAI,EAAEgC,OAAO,CAAC;AACzC,CAAC;AAED;;;;AAIA,OAAO,MAAMe,cAAc,GAAO/C,IAAkB,IAAgB;EAClE,MAAMD,QAAQ,GAAGL,KAAK,CAACuB,UAAU,CAACtB,eAAe,CAAC;EAClDiC,SAAS,CAAC7B,QAAQ,EAAEC,IAAI,CAAC;EACzB,OAAON,KAAK,CAACwC,WAAW,CAAC,MAAK;IAC5BnC,QAAQ,CAACiD,OAAO,CAAChD,IAAI,CAAC;EACxB,CAAC,EAAE,CAACD,QAAQ,EAAEC,IAAI,CAAC,CAAC;AACtB,CAAC;AAED;;;;AAIA,OAAO,MAAMiD,OAAO,GAAGA,CACrBjD,IAAyB,EACzBgC,OAEC,KAUC;EACF,MAAMjC,QAAQ,GAAGL,KAAK,CAACuB,UAAU,CAACtB,eAAe,CAAC;EAClD,OAAO,CACLiB,QAAQ,CAACb,QAAQ,EAAEC,IAAI,CAAC,EACxB+B,OAAO,CAAChC,QAAQ,EAAEC,IAAI,EAAEgC,OAAO,CAAC,CACxB;AACZ,CAAC;AAED,MAAMkB,cAAc,GAAG;EACrBZ,gBAAgB,eAAE,IAAIa,GAAG,EAAiC;EAC1DC,OAAO,eAAE,IAAID,GAAG;CACjB;AAED,SAASE,aAAaA,CACpBtD,QAAmC,EACnCC,IAA8C,EAC9CsC,gBAAyB;EAEzB,MAAMX,GAAG,GAAGW,gBAAgB,GAAGY,cAAc,CAACZ,gBAAgB,GAAGY,cAAc,CAACE,OAAO;EACvF,IAAIjB,OAAO,GAAGR,GAAG,CAACzB,GAAG,CAACF,IAAI,CAAC;EAC3B,IAAImC,OAAO,KAAKhC,SAAS,EAAE;IACzB,OAAOgC,OAAO;EAChB;EACAA,OAAO,GAAG,IAAImB,OAAO,CAAQC,OAAO,IAAI;IACtC,MAAMC,OAAO,GAAGzD,QAAQ,CAACQ,SAAS,CAACP,IAAI,EAAGyD,MAAM,IAAI;MAClD,IAAIA,MAAM,CAACC,IAAI,KAAK,SAAS,IAAKpB,gBAAgB,IAAImB,MAAM,CAACE,OAAQ,EAAE;QACrE;MACF;MACAC,UAAU,CAACJ,OAAO,EAAE,IAAI,CAAC;MACzBD,OAAO,EAAE;MACT5B,GAAG,CAACkC,MAAM,CAAC7D,IAAI,CAAC;IAClB,CAAC,CAAC;EACJ,CAAC,CAAC;EACF2B,GAAG,CAACvB,GAAG,CAACJ,IAAI,EAAEmC,OAAO,CAAC;EACtB,OAAOA,OAAO;AAChB;AAEA,SAAS2B,mBAAmBA,CAC1B/D,QAAmC,EACnCC,IAA8C,EAC9CsC,gBAAyB;EAEzB,MAAMnB,KAAK,GAAGP,QAAQ,CAACb,QAAQ,EAAEC,IAAI,CAAC;EACtC,IAAImB,KAAK,CAACuC,IAAI,KAAK,SAAS,IAAKpB,gBAAgB,IAAInB,KAAK,CAACwC,OAAQ,EAAE;IACnE,MAAMN,aAAa,CAACtD,QAAQ,EAAEC,IAAI,EAAEsC,gBAAgB,CAAC;EACvD;EACA,OAAOnB,KAAK;AACd;AAEA;;;;AAIA,OAAO,MAAM4C,eAAe,GAAGA,CAC7B/D,IAA8C,EAC9CgC,OAGC,KACgG;EACjG,MAAMjC,QAAQ,GAAGL,KAAK,CAACuB,UAAU,CAACtB,eAAe,CAAC;EAClD,MAAM8D,MAAM,GAAGK,mBAAmB,CAAC/D,QAAQ,EAAEC,IAAI,EAAEgC,OAAO,EAAEM,gBAAgB,IAAI,KAAK,CAAC;EACtF,IAAImB,MAAM,CAACC,IAAI,KAAK,SAAS,IAAI,CAAC1B,OAAO,EAAEgC,cAAc,EAAE;IACzD,MAAM3E,KAAK,CAACsD,MAAM,CAACc,MAAM,CAACb,KAAK,CAAC;EAClC;EACA,OAAOa,MAAa;AACtB,CAAC;AAED;;;;AAIA,OAAO,MAAMQ,gBAAgB,GAAGA,CAC9BjE,IAAkB,EAClBQ,CAAiB,EACjBwB,OAA0C,KAClC;EACR,MAAMjC,QAAQ,GAAGL,KAAK,CAACuB,UAAU,CAACtB,eAAe,CAAC;EAClDD,KAAK,CAACmC,SAAS,CACb,MAAM9B,QAAQ,CAACQ,SAAS,CAACP,IAAI,EAAEQ,CAAC,EAAEwB,OAAO,CAAC,EAC1C,CAACjC,QAAQ,EAAEC,IAAI,EAAEQ,CAAC,EAAEwB,OAAO,EAAEkC,SAAS,CAAC,CACxC;AACH,CAAC;AAED;;;;AAIA,OAAO,MAAMC,UAAU,GAAOC,GAA2B,IAAO;EAC9D,MAAM,GAAG7C,QAAQ,CAAC,GAAG7B,KAAK,CAAC2E,QAAQ,CAACD,GAAG,CAACjD,KAAK,CAAC;EAC9CzB,KAAK,CAACmC,SAAS,CAAC,MAAMuC,GAAG,CAAC7D,SAAS,CAACgB,QAAQ,CAAC,EAAE,CAAC6C,GAAG,CAAC,CAAC;EACrD,OAAOA,GAAG,CAACjD,KAAK;AAClB,CAAC;AAED;;;;AAIA,OAAO,MAAMmD,cAAc,GAAGA,CAAuBF,GAAuB,EAAEG,IAAO,KACnF7E,KAAK,CAACgC,OAAO,CAAC,MAAM0C,GAAG,CAACG,IAAI,CAACA,IAAI,CAAC,EAAE,CAACH,GAAG,EAAEG,IAAI,CAAC,CAAC;AAElD;;;;AAIA,OAAO,MAAMC,mBAAmB,GAAGA,CAAuBJ,GAAuB,EAAEG,IAAO,KACxFJ,UAAU,CAACG,cAAc,CAACF,GAAG,EAAEG,IAAI,CAAC,CAAC","ignoreList":[]}
@@ -0,0 +1,25 @@
1
+ import type * as Atom from "effect/unstable/reactivity/Atom";
2
+ import * as AtomRegistry from "effect/unstable/reactivity/AtomRegistry";
3
+ import * as React from "react";
4
+ /**
5
+ * @since 1.0.0
6
+ * @category context
7
+ */
8
+ export declare function scheduleTask(f: () => void): () => void;
9
+ /**
10
+ * @since 1.0.0
11
+ * @category context
12
+ */
13
+ export declare const RegistryContext: React.Context<AtomRegistry.AtomRegistry>;
14
+ /**
15
+ * @since 1.0.0
16
+ * @category context
17
+ */
18
+ export declare const RegistryProvider: (options: {
19
+ readonly children?: React.ReactNode | undefined;
20
+ readonly initialValues?: Iterable<readonly [Atom.Atom<any>, any]> | undefined;
21
+ readonly scheduleTask?: ((f: () => void) => () => void) | undefined;
22
+ readonly timeoutResolution?: number | undefined;
23
+ readonly defaultIdleTTL?: number | undefined;
24
+ }) => React.FunctionComponentElement<React.ProviderProps<AtomRegistry.AtomRegistry>>;
25
+ //# sourceMappingURL=RegistryContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RegistryContext.d.ts","sourceRoot":"","sources":["../src/RegistryContext.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,IAAI,MAAM,iCAAiC,CAAA;AAC5D,OAAO,KAAK,YAAY,MAAM,yCAAyC,CAAA;AACvE,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAGtD;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,0CAGzB,CAAA;AAEH;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GAAI,SAAS;IACxC,QAAQ,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,GAAG,SAAS,CAAA;IAC/C,QAAQ,CAAC,aAAa,CAAC,EAAE,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,SAAS,CAAA;IAC7E,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAC,GAAG,SAAS,CAAA;IACnE,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC/C,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC7C,mFA2BA,CAAA"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ "use client";
5
+
6
+ import * as AtomRegistry from "effect/unstable/reactivity/AtomRegistry";
7
+ import * as React from "react";
8
+ import * as Scheduler from "scheduler";
9
+ /**
10
+ * @since 1.0.0
11
+ * @category context
12
+ */
13
+ export function scheduleTask(f) {
14
+ const node = Scheduler.unstable_scheduleCallback(Scheduler.unstable_LowPriority, f);
15
+ return () => Scheduler.unstable_cancelCallback(node);
16
+ }
17
+ /**
18
+ * @since 1.0.0
19
+ * @category context
20
+ */
21
+ export const RegistryContext = /*#__PURE__*/React.createContext(/*#__PURE__*/AtomRegistry.make({
22
+ scheduleTask,
23
+ defaultIdleTTL: 400
24
+ }));
25
+ /**
26
+ * @since 1.0.0
27
+ * @category context
28
+ */
29
+ export const RegistryProvider = options => {
30
+ const ref = React.useRef(null);
31
+ if (ref.current === null) {
32
+ ref.current = {
33
+ registry: AtomRegistry.make({
34
+ scheduleTask: options.scheduleTask ?? scheduleTask,
35
+ initialValues: options.initialValues,
36
+ timeoutResolution: options.timeoutResolution,
37
+ defaultIdleTTL: options.defaultIdleTTL
38
+ })
39
+ };
40
+ }
41
+ React.useEffect(() => {
42
+ if (ref.current?.timeout !== undefined) {
43
+ clearTimeout(ref.current.timeout);
44
+ }
45
+ return () => {
46
+ ref.current.timeout = setTimeout(() => {
47
+ ref.current?.registry.dispose();
48
+ ref.current = null;
49
+ }, 500);
50
+ };
51
+ }, [ref]);
52
+ return React.createElement(RegistryContext.Provider, {
53
+ value: ref.current.registry
54
+ }, options?.children);
55
+ };
56
+ //# sourceMappingURL=RegistryContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RegistryContext.js","names":["AtomRegistry","React","Scheduler","scheduleTask","f","node","unstable_scheduleCallback","unstable_LowPriority","unstable_cancelCallback","RegistryContext","createContext","make","defaultIdleTTL","RegistryProvider","options","ref","useRef","current","registry","initialValues","timeoutResolution","useEffect","timeout","undefined","clearTimeout","setTimeout","dispose","createElement","Provider","value","children"],"sources":["../src/RegistryContext.ts"],"sourcesContent":[null],"mappings":"AAAA;;;AAGA,YAAY;;AAGZ,OAAO,KAAKA,YAAY,MAAM,yCAAyC;AACvE,OAAO,KAAKC,KAAK,MAAM,OAAO;AAC9B,OAAO,KAAKC,SAAS,MAAM,WAAW;AAEtC;;;;AAIA,OAAM,SAAUC,YAAYA,CAACC,CAAa;EACxC,MAAMC,IAAI,GAAGH,SAAS,CAACI,yBAAyB,CAACJ,SAAS,CAACK,oBAAoB,EAAEH,CAAC,CAAC;EACnF,OAAO,MAAMF,SAAS,CAACM,uBAAuB,CAACH,IAAI,CAAC;AACtD;AAEA;;;;AAIA,OAAO,MAAMI,eAAe,gBAAGR,KAAK,CAACS,aAAa,cAA4BV,YAAY,CAACW,IAAI,CAAC;EAC9FR,YAAY;EACZS,cAAc,EAAE;CACjB,CAAC,CAAC;AAEH;;;;AAIA,OAAO,MAAMC,gBAAgB,GAAIC,OAMhC,IAAI;EACH,MAAMC,GAAG,GAAGd,KAAK,CAACe,MAAM,CAGrB,IAAI,CAAC;EACR,IAAID,GAAG,CAACE,OAAO,KAAK,IAAI,EAAE;IACxBF,GAAG,CAACE,OAAO,GAAG;MACZC,QAAQ,EAAElB,YAAY,CAACW,IAAI,CAAC;QAC1BR,YAAY,EAAEW,OAAO,CAACX,YAAY,IAAIA,YAAY;QAClDgB,aAAa,EAAEL,OAAO,CAACK,aAAa;QACpCC,iBAAiB,EAAEN,OAAO,CAACM,iBAAiB;QAC5CR,cAAc,EAAEE,OAAO,CAACF;OACzB;KACF;EACH;EACAX,KAAK,CAACoB,SAAS,CAAC,MAAK;IACnB,IAAIN,GAAG,CAACE,OAAO,EAAEK,OAAO,KAAKC,SAAS,EAAE;MACtCC,YAAY,CAACT,GAAG,CAACE,OAAO,CAACK,OAAO,CAAC;IACnC;IACA,OAAO,MAAK;MACVP,GAAG,CAACE,OAAQ,CAACK,OAAO,GAAGG,UAAU,CAAC,MAAK;QACrCV,GAAG,CAACE,OAAO,EAAEC,QAAQ,CAACQ,OAAO,EAAE;QAC/BX,GAAG,CAACE,OAAO,GAAG,IAAI;MACpB,CAAC,EAAE,GAAG,CAAQ;IAChB,CAAC;EACH,CAAC,EAAE,CAACF,GAAG,CAAC,CAAC;EACT,OAAOd,KAAK,CAAC0B,aAAa,CAAClB,eAAe,CAACmB,QAAQ,EAAE;IAAEC,KAAK,EAAEd,GAAG,CAACE,OAAO,CAACC;EAAQ,CAAE,EAAEJ,OAAO,EAAEgB,QAAQ,CAAC;AAC1G,CAAC","ignoreList":[]}
@@ -0,0 +1,85 @@
1
+ import type * as Atom from "effect/unstable/reactivity/Atom";
2
+ import * as React from "react";
3
+ /**
4
+ * @since 1.0.0
5
+ * @category Type IDs
6
+ *
7
+ * Type identifier for ScopedAtom.
8
+ */
9
+ export type TypeId = "~@effect/atom-react/ScopedAtom";
10
+ /**
11
+ * @since 1.0.0
12
+ * @category Type IDs
13
+ *
14
+ * Type identifier for ScopedAtom.
15
+ */
16
+ export declare const TypeId: TypeId;
17
+ /**
18
+ * @since 1.0.0
19
+ * @category models
20
+ *
21
+ * Scoped Atom interface with a provider-backed instance.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * import * as Atom from "effect/unstable/reactivity/Atom"
26
+ * import * as React from "react"
27
+ * import * as ScopedAtom from "@effect/atom-react/ScopedAtom"
28
+ * import { useAtomValue } from "@effect/atom-react"
29
+ *
30
+ * const Counter = ScopedAtom.make(() => Atom.make(0))
31
+ *
32
+ * function View() {
33
+ * const atom = Counter.use()
34
+ * const value = useAtomValue(atom)
35
+ * return React.createElement("div", null, value)
36
+ * }
37
+ *
38
+ * export function App() {
39
+ * return React.createElement(Counter.Provider, null, React.createElement(View))
40
+ * }
41
+ * ```
42
+ */
43
+ export interface ScopedAtom<A extends Atom.Atom<any>, Input = never> {
44
+ readonly [TypeId]: TypeId;
45
+ use(): A;
46
+ Provider: Input extends never ? React.FC<{
47
+ readonly children?: React.ReactNode | undefined;
48
+ }> : React.FC<{
49
+ readonly children?: React.ReactNode | undefined;
50
+ readonly value: Input;
51
+ }>;
52
+ Context: React.Context<A>;
53
+ }
54
+ /**
55
+ * @since 1.0.0
56
+ * @category constructors
57
+ *
58
+ * Creates a ScopedAtom from a factory function.
59
+ *
60
+ * @example
61
+ * ```ts
62
+ * import * as Atom from "effect/unstable/reactivity/Atom"
63
+ * import * as React from "react"
64
+ * import * as ScopedAtom from "@effect/atom-react/ScopedAtom"
65
+ * import { useAtomValue } from "@effect/atom-react"
66
+ *
67
+ * const User = ScopedAtom.make((name: string) => Atom.make(name))
68
+ *
69
+ * function UserName() {
70
+ * const atom = User.use()
71
+ * const value = useAtomValue(atom)
72
+ * return React.createElement("span", null, value)
73
+ * }
74
+ *
75
+ * export function App() {
76
+ * return React.createElement(
77
+ * User.Provider,
78
+ * { value: "Ada" },
79
+ * React.createElement(UserName)
80
+ * )
81
+ * }
82
+ * ```
83
+ */
84
+ export declare const make: <A extends Atom.Atom<any>, Input = never>(f: (() => A) | ((input: Input) => A)) => ScopedAtom<A, Input>;
85
+ //# sourceMappingURL=ScopedAtom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ScopedAtom.d.ts","sourceRoot":"","sources":["../src/ScopedAtom.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,IAAI,MAAM,iCAAiC,CAAA;AAC5D,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B;;;;;GAKG;AACH,MAAM,MAAM,MAAM,GAAG,gCAAgC,CAAA;AAErD;;;;;GAKG;AACH,eAAO,MAAM,MAAM,EAAE,MAAyC,CAAA;AAE9D;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,WAAW,UAAU,CAAC,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK;IACjE,QAAQ,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACzB,GAAG,IAAI,CAAC,CAAA;IACR,QAAQ,EAAE,KAAK,SAAS,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC;QAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,GAAG,SAAS,CAAA;KAAE,CAAC,GACzF,KAAK,CAAC,EAAE,CAAC;QAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,GAAG,SAAS,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;KAAE,CAAC,CAAA;IACxF,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;CAC1B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,IAAI,GAAI,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,EAC1D,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,CAAC,CAAC,KACnC,UAAU,CAAC,CAAC,EAAE,KAAK,CA6BrB,CAAA"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ "use client";
5
+
6
+ import * as React from "react";
7
+ /**
8
+ * @since 1.0.0
9
+ * @category Type IDs
10
+ *
11
+ * Type identifier for ScopedAtom.
12
+ */
13
+ export const TypeId = "~@effect/atom-react/ScopedAtom";
14
+ /**
15
+ * @since 1.0.0
16
+ * @category constructors
17
+ *
18
+ * Creates a ScopedAtom from a factory function.
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * import * as Atom from "effect/unstable/reactivity/Atom"
23
+ * import * as React from "react"
24
+ * import * as ScopedAtom from "@effect/atom-react/ScopedAtom"
25
+ * import { useAtomValue } from "@effect/atom-react"
26
+ *
27
+ * const User = ScopedAtom.make((name: string) => Atom.make(name))
28
+ *
29
+ * function UserName() {
30
+ * const atom = User.use()
31
+ * const value = useAtomValue(atom)
32
+ * return React.createElement("span", null, value)
33
+ * }
34
+ *
35
+ * export function App() {
36
+ * return React.createElement(
37
+ * User.Provider,
38
+ * { value: "Ada" },
39
+ * React.createElement(UserName)
40
+ * )
41
+ * }
42
+ * ```
43
+ */
44
+ export const make = f => {
45
+ const Context = React.createContext(undefined);
46
+ const use = () => {
47
+ const atom = React.useContext(Context);
48
+ if (atom === undefined) {
49
+ throw new Error("ScopedAtom used outside of its Provider");
50
+ }
51
+ return atom;
52
+ };
53
+ const Provider = props => {
54
+ const atom = React.useRef(null);
55
+ if (atom.current === null) {
56
+ if ("value" in props) {
57
+ atom.current = f(props.value);
58
+ } else {
59
+ atom.current = f();
60
+ }
61
+ }
62
+ return React.createElement(Context.Provider, {
63
+ value: atom.current
64
+ }, props.children);
65
+ };
66
+ return {
67
+ [TypeId]: TypeId,
68
+ use,
69
+ Provider: Provider,
70
+ Context
71
+ };
72
+ };
73
+ //# sourceMappingURL=ScopedAtom.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ScopedAtom.js","names":["React","TypeId","make","f","Context","createContext","undefined","use","atom","useContext","Error","Provider","props","useRef","current","value","createElement","children"],"sources":["../src/ScopedAtom.ts"],"sourcesContent":[null],"mappings":"AAAA;;;AAGA,YAAY;;AAGZ,OAAO,KAAKA,KAAK,MAAM,OAAO;AAU9B;;;;;;AAMA,OAAO,MAAMC,MAAM,GAAW,gCAAgC;AAoC9D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BA,OAAO,MAAMC,IAAI,GACfC,CAAoC,IACZ;EACxB,MAAMC,OAAO,GAAGJ,KAAK,CAACK,aAAa,CAAIC,SAAyB,CAAC;EAEjE,MAAMC,GAAG,GAAGA,CAAA,KAAQ;IAClB,MAAMC,IAAI,GAAGR,KAAK,CAACS,UAAU,CAACL,OAAO,CAAC;IACtC,IAAII,IAAI,KAAKF,SAAS,EAAE;MACtB,MAAM,IAAII,KAAK,CAAC,yCAAyC,CAAC;IAC5D;IACA,OAAOF,IAAI;EACb,CAAC;EAED,MAAMG,QAAQ,GAA2FC,KAAK,IAAI;IAChH,MAAMJ,IAAI,GAAGR,KAAK,CAACa,MAAM,CAAW,IAAI,CAAC;IACzC,IAAIL,IAAI,CAACM,OAAO,KAAK,IAAI,EAAE;MACzB,IAAI,OAAO,IAAIF,KAAK,EAAE;QACpBJ,IAAI,CAACM,OAAO,GAAIX,CAAyB,CAACS,KAAK,CAACG,KAAc,CAAC;MACjE,CAAC,MAAM;QACLP,IAAI,CAACM,OAAO,GAAIX,CAAa,EAAE;MACjC;IACF;IACA,OAAOH,KAAK,CAACgB,aAAa,CAACZ,OAAO,CAACO,QAAQ,EAAE;MAAEI,KAAK,EAAEP,IAAI,CAACM;IAAO,CAAE,EAAEF,KAAK,CAACK,QAAQ,CAAC;EACvF,CAAC;EAED,OAAO;IACL,CAAChB,MAAM,GAAGA,MAAM;IAChBM,GAAG;IACHI,QAAQ,EAAEA,QAAe;IACzBP;GACD;AACH,CAAC","ignoreList":[]}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ /**
5
+ * @since 1.0.0
6
+ */
7
+ export * from "./Hooks.ts";
8
+ /**
9
+ * @since 1.0.0
10
+ */
11
+ export * from "./RegistryContext.ts";
12
+ /**
13
+ * @since 1.0.0
14
+ */
15
+ export * from "./ScopedAtom.ts";
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,cAAc,YAAY,CAAA;AAE1B;;GAEG;AACH,cAAc,sBAAsB,CAAA;AAEpC;;GAEG;AACH,cAAc,iBAAiB,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ /**
5
+ * @since 1.0.0
6
+ */
7
+ export * from "./Hooks.js";
8
+ /**
9
+ * @since 1.0.0
10
+ */
11
+ export * from "./RegistryContext.js";
12
+ /**
13
+ * @since 1.0.0
14
+ */
15
+ export * from "./ScopedAtom.js";
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":[null],"mappings":"AAAA;;;AAIA;;;AAGA,cAAc,YAAY;AAE1B;;;AAGA,cAAc,sBAAsB;AAEpC;;;AAGA,cAAc,iBAAiB","ignoreList":[]}
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "@effect/atom-react",
3
+ "version": "4.0.0-beta.0",
4
+ "type": "module",
5
+ "license": "MIT",
6
+ "description": "React bindings for the Effect Atom modules",
7
+ "homepage": "https://effect.website",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/Effect-TS/effect-smol.git",
11
+ "directory": "packages/atom/react"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/Effect-TS/effect-smol/issues"
15
+ },
16
+ "tags": [
17
+ "typescript",
18
+ "react",
19
+ "database"
20
+ ],
21
+ "keywords": [
22
+ "typescript",
23
+ "react",
24
+ "database"
25
+ ],
26
+ "sideEffects": [],
27
+ "exports": {
28
+ "./package.json": "./package.json",
29
+ ".": "./dist/index.js",
30
+ "./*": "./dist/*.js",
31
+ "./internal/*": null,
32
+ "./*/index": null
33
+ },
34
+ "files": [
35
+ "src/**/*.ts",
36
+ "dist/**/*.js",
37
+ "dist/**/*.js.map",
38
+ "dist/**/*.d.ts",
39
+ "dist/**/*.d.ts.map"
40
+ ],
41
+ "publishConfig": {
42
+ "access": "public",
43
+ "provenance": true
44
+ },
45
+ "peerDependencies": {
46
+ "react": "^19.2.4",
47
+ "scheduler": "*",
48
+ "effect": "^4.0.0-beta.0"
49
+ },
50
+ "devDependencies": {
51
+ "@testing-library/dom": "^10.4.1",
52
+ "@testing-library/jest-dom": "^6.9.1",
53
+ "@testing-library/react": "^16.3.0",
54
+ "@types/react": "^19.2.2",
55
+ "@types/react-dom": "^19.2.2",
56
+ "@types/scheduler": "^0.26.0",
57
+ "jsdom": "^27.1.0",
58
+ "react": "19.2.3",
59
+ "react-dom": "19.2.3",
60
+ "react-error-boundary": "^6.0.0",
61
+ "scheduler": "^0.27.0",
62
+ "effect": "^4.0.0-beta.0"
63
+ },
64
+ "scripts": {
65
+ "build": "tsc -b tsconfig.json && pnpm babel",
66
+ "build:tsgo": "tsgo -b tsconfig.json && pnpm babel",
67
+ "babel": "babel dist --plugins annotate-pure-calls --out-dir dist --source-maps",
68
+ "check": "tsc -b tsconfig.json",
69
+ "test": "vitest",
70
+ "coverage": "vitest --coverage"
71
+ }
72
+ }
package/src/Hooks.ts ADDED
@@ -0,0 +1,310 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ "use client"
5
+
6
+ import * as Cause from "effect/Cause"
7
+ import * as Effect from "effect/Effect"
8
+ import * as Exit from "effect/Exit"
9
+ import type * as AsyncResult from "effect/unstable/reactivity/AsyncResult"
10
+ import * as Atom from "effect/unstable/reactivity/Atom"
11
+ import type * as AtomRef from "effect/unstable/reactivity/AtomRef"
12
+ import * as AtomRegistry from "effect/unstable/reactivity/AtomRegistry"
13
+ import * as React from "react"
14
+ import { RegistryContext } from "./RegistryContext.ts"
15
+
16
+ interface AtomStore<A> {
17
+ readonly subscribe: (f: () => void) => () => void
18
+ readonly snapshot: () => A
19
+ readonly getServerSnapshot: () => A
20
+ }
21
+
22
+ const storeRegistry = new WeakMap<AtomRegistry.AtomRegistry, WeakMap<Atom.Atom<any>, AtomStore<any>>>()
23
+
24
+ function makeStore<A>(registry: AtomRegistry.AtomRegistry, atom: Atom.Atom<A>): AtomStore<A> {
25
+ let stores = storeRegistry.get(registry)
26
+ if (stores === undefined) {
27
+ stores = new WeakMap()
28
+ storeRegistry.set(registry, stores)
29
+ }
30
+ const store = stores.get(atom)
31
+ if (store !== undefined) {
32
+ return store
33
+ }
34
+ const newStore: AtomStore<A> = {
35
+ subscribe(f) {
36
+ return registry.subscribe(atom, f)
37
+ },
38
+ snapshot() {
39
+ return registry.get(atom)
40
+ },
41
+ getServerSnapshot() {
42
+ return Atom.getServerValue(atom, registry)
43
+ }
44
+ }
45
+ stores.set(atom, newStore)
46
+ return newStore
47
+ }
48
+
49
+ function useStore<A>(registry: AtomRegistry.AtomRegistry, atom: Atom.Atom<A>): A {
50
+ const store = makeStore(registry, atom)
51
+
52
+ return React.useSyncExternalStore(store.subscribe, store.snapshot, store.getServerSnapshot)
53
+ }
54
+
55
+ const initialValuesSet = new WeakMap<AtomRegistry.AtomRegistry, WeakSet<Atom.Atom<any>>>()
56
+
57
+ /**
58
+ * @since 1.0.0
59
+ * @category hooks
60
+ */
61
+ export const useAtomInitialValues = (initialValues: Iterable<readonly [Atom.Atom<any>, any]>): void => {
62
+ const registry = React.useContext(RegistryContext)
63
+ let set = initialValuesSet.get(registry)
64
+ if (set === undefined) {
65
+ set = new WeakSet()
66
+ initialValuesSet.set(registry, set)
67
+ }
68
+ for (const [atom, value] of initialValues) {
69
+ if (!set.has(atom)) {
70
+ set.add(atom)
71
+ ;(registry as any).ensureNode(atom).setValue(value)
72
+ }
73
+ }
74
+ }
75
+
76
+ /**
77
+ * @since 1.0.0
78
+ * @category hooks
79
+ */
80
+ export const useAtomValue: {
81
+ /**
82
+ * @since 1.0.0
83
+ * @category hooks
84
+ */
85
+ <A>(atom: Atom.Atom<A>): A
86
+ /**
87
+ * @since 1.0.0
88
+ * @category hooks
89
+ */
90
+ <A, B>(atom: Atom.Atom<A>, f: (_: A) => B): B
91
+ } = <A>(atom: Atom.Atom<A>, f?: (_: A) => A): A => {
92
+ const registry = React.useContext(RegistryContext)
93
+ if (f) {
94
+ const atomB = React.useMemo(() => Atom.map(atom, f), [atom, f])
95
+ return useStore(registry, atomB)
96
+ }
97
+ return useStore(registry, atom)
98
+ }
99
+
100
+ function mountAtom<A>(registry: AtomRegistry.AtomRegistry, atom: Atom.Atom<A>): void {
101
+ React.useEffect(() => registry.mount(atom), [atom, registry])
102
+ }
103
+
104
+ function setAtom<R, W, Mode extends "value" | "promise" | "promiseExit" = never>(
105
+ registry: AtomRegistry.AtomRegistry,
106
+ atom: Atom.Writable<R, W>,
107
+ options?: {
108
+ readonly mode?: ([R] extends [AsyncResult.AsyncResult<any, any>] ? Mode : "value") | undefined
109
+ }
110
+ ): "promise" extends Mode ? (
111
+ (value: W) => Promise<AsyncResult.AsyncResult.Success<R>>
112
+ ) :
113
+ "promiseExit" extends Mode ? (
114
+ (value: W) => Promise<Exit.Exit<AsyncResult.AsyncResult.Success<R>, AsyncResult.AsyncResult.Failure<R>>>
115
+ ) :
116
+ ((value: W | ((value: R) => W)) => void)
117
+ {
118
+ if (options?.mode === "promise" || options?.mode === "promiseExit") {
119
+ return React.useCallback((value: W) => {
120
+ registry.set(atom, value)
121
+ const promise = Effect.runPromiseExit(
122
+ AtomRegistry.getResult(registry, atom as Atom.Atom<AsyncResult.AsyncResult<any, any>>, {
123
+ suspendOnWaiting: true
124
+ })
125
+ )
126
+ return options!.mode === "promise" ? promise.then(flattenExit) : promise
127
+ }, [registry, atom, options.mode]) as any
128
+ }
129
+ return React.useCallback((value: W | ((value: R) => W)) => {
130
+ registry.set(atom, typeof value === "function" ? (value as any)(registry.get(atom)) : value)
131
+ }, [registry, atom]) as any
132
+ }
133
+
134
+ const flattenExit = <A, E>(exit: Exit.Exit<A, E>): A => {
135
+ if (Exit.isSuccess(exit)) return exit.value
136
+ throw Cause.squash(exit.cause)
137
+ }
138
+
139
+ /**
140
+ * @since 1.0.0
141
+ * @category hooks
142
+ */
143
+ export const useAtomMount = <A>(atom: Atom.Atom<A>): void => {
144
+ const registry = React.useContext(RegistryContext)
145
+ mountAtom(registry, atom)
146
+ }
147
+
148
+ /**
149
+ * @since 1.0.0
150
+ * @category hooks
151
+ */
152
+ export const useAtomSet = <
153
+ R,
154
+ W,
155
+ Mode extends "value" | "promise" | "promiseExit" = never
156
+ >(
157
+ atom: Atom.Writable<R, W>,
158
+ options?: {
159
+ readonly mode?: ([R] extends [AsyncResult.AsyncResult<any, any>] ? Mode : "value") | undefined
160
+ }
161
+ ): "promise" extends Mode ? (
162
+ (value: W) => Promise<AsyncResult.AsyncResult.Success<R>>
163
+ ) :
164
+ "promiseExit" extends Mode ? (
165
+ (value: W) => Promise<Exit.Exit<AsyncResult.AsyncResult.Success<R>, AsyncResult.AsyncResult.Failure<R>>>
166
+ ) :
167
+ ((value: W | ((value: R) => W)) => void) =>
168
+ {
169
+ const registry = React.useContext(RegistryContext)
170
+ mountAtom(registry, atom)
171
+ return setAtom(registry, atom, options)
172
+ }
173
+
174
+ /**
175
+ * @since 1.0.0
176
+ * @category hooks
177
+ */
178
+ export const useAtomRefresh = <A>(atom: Atom.Atom<A>): () => void => {
179
+ const registry = React.useContext(RegistryContext)
180
+ mountAtom(registry, atom)
181
+ return React.useCallback(() => {
182
+ registry.refresh(atom)
183
+ }, [registry, atom])
184
+ }
185
+
186
+ /**
187
+ * @since 1.0.0
188
+ * @category hooks
189
+ */
190
+ export const useAtom = <R, W, const Mode extends "value" | "promise" | "promiseExit" = never>(
191
+ atom: Atom.Writable<R, W>,
192
+ options?: {
193
+ readonly mode?: ([R] extends [AsyncResult.AsyncResult<any, any>] ? Mode : "value") | undefined
194
+ }
195
+ ): readonly [
196
+ value: R,
197
+ write: "promise" extends Mode ? (
198
+ (value: W) => Promise<AsyncResult.AsyncResult.Success<R>>
199
+ ) :
200
+ "promiseExit" extends Mode ? (
201
+ (value: W) => Promise<Exit.Exit<AsyncResult.AsyncResult.Success<R>, AsyncResult.AsyncResult.Failure<R>>>
202
+ ) :
203
+ ((value: W | ((value: R) => W)) => void)
204
+ ] => {
205
+ const registry = React.useContext(RegistryContext)
206
+ return [
207
+ useStore(registry, atom),
208
+ setAtom(registry, atom, options)
209
+ ] as const
210
+ }
211
+
212
+ const atomPromiseMap = {
213
+ suspendOnWaiting: new Map<Atom.Atom<any>, Promise<void>>(),
214
+ default: new Map<Atom.Atom<any>, Promise<void>>()
215
+ }
216
+
217
+ function atomToPromise<A, E>(
218
+ registry: AtomRegistry.AtomRegistry,
219
+ atom: Atom.Atom<AsyncResult.AsyncResult<A, E>>,
220
+ suspendOnWaiting: boolean
221
+ ) {
222
+ const map = suspendOnWaiting ? atomPromiseMap.suspendOnWaiting : atomPromiseMap.default
223
+ let promise = map.get(atom)
224
+ if (promise !== undefined) {
225
+ return promise
226
+ }
227
+ promise = new Promise<void>((resolve) => {
228
+ const dispose = registry.subscribe(atom, (result) => {
229
+ if (result._tag === "Initial" || (suspendOnWaiting && result.waiting)) {
230
+ return
231
+ }
232
+ setTimeout(dispose, 1000)
233
+ resolve()
234
+ map.delete(atom)
235
+ })
236
+ })
237
+ map.set(atom, promise)
238
+ return promise
239
+ }
240
+
241
+ function atomResultOrSuspend<A, E>(
242
+ registry: AtomRegistry.AtomRegistry,
243
+ atom: Atom.Atom<AsyncResult.AsyncResult<A, E>>,
244
+ suspendOnWaiting: boolean
245
+ ) {
246
+ const value = useStore(registry, atom)
247
+ if (value._tag === "Initial" || (suspendOnWaiting && value.waiting)) {
248
+ throw atomToPromise(registry, atom, suspendOnWaiting)
249
+ }
250
+ return value
251
+ }
252
+
253
+ /**
254
+ * @since 1.0.0
255
+ * @category hooks
256
+ */
257
+ export const useAtomSuspense = <A, E, const IncludeFailure extends boolean = false>(
258
+ atom: Atom.Atom<AsyncResult.AsyncResult<A, E>>,
259
+ options?: {
260
+ readonly suspendOnWaiting?: boolean | undefined
261
+ readonly includeFailure?: IncludeFailure | undefined
262
+ }
263
+ ): AsyncResult.Success<A, E> | (IncludeFailure extends true ? AsyncResult.Failure<A, E> : never) => {
264
+ const registry = React.useContext(RegistryContext)
265
+ const result = atomResultOrSuspend(registry, atom, options?.suspendOnWaiting ?? false)
266
+ if (result._tag === "Failure" && !options?.includeFailure) {
267
+ throw Cause.squash(result.cause)
268
+ }
269
+ return result as any
270
+ }
271
+
272
+ /**
273
+ * @since 1.0.0
274
+ * @category hooks
275
+ */
276
+ export const useAtomSubscribe = <A>(
277
+ atom: Atom.Atom<A>,
278
+ f: (_: A) => void,
279
+ options?: { readonly immediate?: boolean }
280
+ ): void => {
281
+ const registry = React.useContext(RegistryContext)
282
+ React.useEffect(
283
+ () => registry.subscribe(atom, f, options),
284
+ [registry, atom, f, options?.immediate]
285
+ )
286
+ }
287
+
288
+ /**
289
+ * @since 1.0.0
290
+ * @category hooks
291
+ */
292
+ export const useAtomRef = <A>(ref: AtomRef.ReadonlyRef<A>): A => {
293
+ const [, setValue] = React.useState(ref.value)
294
+ React.useEffect(() => ref.subscribe(setValue), [ref])
295
+ return ref.value
296
+ }
297
+
298
+ /**
299
+ * @since 1.0.0
300
+ * @category hooks
301
+ */
302
+ export const useAtomRefProp = <A, K extends keyof A>(ref: AtomRef.AtomRef<A>, prop: K): AtomRef.AtomRef<A[K]> =>
303
+ React.useMemo(() => ref.prop(prop), [ref, prop])
304
+
305
+ /**
306
+ * @since 1.0.0
307
+ * @category hooks
308
+ */
309
+ export const useAtomRefPropValue = <A, K extends keyof A>(ref: AtomRef.AtomRef<A>, prop: K): A[K] =>
310
+ useAtomRef(useAtomRefProp(ref, prop))
@@ -0,0 +1,66 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ "use client"
5
+
6
+ import type * as Atom from "effect/unstable/reactivity/Atom"
7
+ import * as AtomRegistry from "effect/unstable/reactivity/AtomRegistry"
8
+ import * as React from "react"
9
+ import * as Scheduler from "scheduler"
10
+
11
+ /**
12
+ * @since 1.0.0
13
+ * @category context
14
+ */
15
+ export function scheduleTask(f: () => void): () => void {
16
+ const node = Scheduler.unstable_scheduleCallback(Scheduler.unstable_LowPriority, f)
17
+ return () => Scheduler.unstable_cancelCallback(node)
18
+ }
19
+
20
+ /**
21
+ * @since 1.0.0
22
+ * @category context
23
+ */
24
+ export const RegistryContext = React.createContext<AtomRegistry.AtomRegistry>(AtomRegistry.make({
25
+ scheduleTask,
26
+ defaultIdleTTL: 400
27
+ }))
28
+
29
+ /**
30
+ * @since 1.0.0
31
+ * @category context
32
+ */
33
+ export const RegistryProvider = (options: {
34
+ readonly children?: React.ReactNode | undefined
35
+ readonly initialValues?: Iterable<readonly [Atom.Atom<any>, any]> | undefined
36
+ readonly scheduleTask?: ((f: () => void) => () => void) | undefined
37
+ readonly timeoutResolution?: number | undefined
38
+ readonly defaultIdleTTL?: number | undefined
39
+ }) => {
40
+ const ref = React.useRef<{
41
+ readonly registry: AtomRegistry.AtomRegistry
42
+ timeout?: number | undefined
43
+ }>(null)
44
+ if (ref.current === null) {
45
+ ref.current = {
46
+ registry: AtomRegistry.make({
47
+ scheduleTask: options.scheduleTask ?? scheduleTask,
48
+ initialValues: options.initialValues,
49
+ timeoutResolution: options.timeoutResolution,
50
+ defaultIdleTTL: options.defaultIdleTTL
51
+ })
52
+ }
53
+ }
54
+ React.useEffect(() => {
55
+ if (ref.current?.timeout !== undefined) {
56
+ clearTimeout(ref.current.timeout)
57
+ }
58
+ return () => {
59
+ ref.current!.timeout = setTimeout(() => {
60
+ ref.current?.registry.dispose()
61
+ ref.current = null
62
+ }, 500) as any
63
+ }
64
+ }, [ref])
65
+ return React.createElement(RegistryContext.Provider, { value: ref.current.registry }, options?.children)
66
+ }
@@ -0,0 +1,120 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ "use client"
5
+
6
+ import type * as Atom from "effect/unstable/reactivity/Atom"
7
+ import * as React from "react"
8
+
9
+ /**
10
+ * @since 1.0.0
11
+ * @category Type IDs
12
+ *
13
+ * Type identifier for ScopedAtom.
14
+ */
15
+ export type TypeId = "~@effect/atom-react/ScopedAtom"
16
+
17
+ /**
18
+ * @since 1.0.0
19
+ * @category Type IDs
20
+ *
21
+ * Type identifier for ScopedAtom.
22
+ */
23
+ export const TypeId: TypeId = "~@effect/atom-react/ScopedAtom"
24
+
25
+ /**
26
+ * @since 1.0.0
27
+ * @category models
28
+ *
29
+ * Scoped Atom interface with a provider-backed instance.
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * import * as Atom from "effect/unstable/reactivity/Atom"
34
+ * import * as React from "react"
35
+ * import * as ScopedAtom from "@effect/atom-react/ScopedAtom"
36
+ * import { useAtomValue } from "@effect/atom-react"
37
+ *
38
+ * const Counter = ScopedAtom.make(() => Atom.make(0))
39
+ *
40
+ * function View() {
41
+ * const atom = Counter.use()
42
+ * const value = useAtomValue(atom)
43
+ * return React.createElement("div", null, value)
44
+ * }
45
+ *
46
+ * export function App() {
47
+ * return React.createElement(Counter.Provider, null, React.createElement(View))
48
+ * }
49
+ * ```
50
+ */
51
+ export interface ScopedAtom<A extends Atom.Atom<any>, Input = never> {
52
+ readonly [TypeId]: TypeId
53
+ use(): A
54
+ Provider: Input extends never ? React.FC<{ readonly children?: React.ReactNode | undefined }>
55
+ : React.FC<{ readonly children?: React.ReactNode | undefined; readonly value: Input }>
56
+ Context: React.Context<A>
57
+ }
58
+
59
+ /**
60
+ * @since 1.0.0
61
+ * @category constructors
62
+ *
63
+ * Creates a ScopedAtom from a factory function.
64
+ *
65
+ * @example
66
+ * ```ts
67
+ * import * as Atom from "effect/unstable/reactivity/Atom"
68
+ * import * as React from "react"
69
+ * import * as ScopedAtom from "@effect/atom-react/ScopedAtom"
70
+ * import { useAtomValue } from "@effect/atom-react"
71
+ *
72
+ * const User = ScopedAtom.make((name: string) => Atom.make(name))
73
+ *
74
+ * function UserName() {
75
+ * const atom = User.use()
76
+ * const value = useAtomValue(atom)
77
+ * return React.createElement("span", null, value)
78
+ * }
79
+ *
80
+ * export function App() {
81
+ * return React.createElement(
82
+ * User.Provider,
83
+ * { value: "Ada" },
84
+ * React.createElement(UserName)
85
+ * )
86
+ * }
87
+ * ```
88
+ */
89
+ export const make = <A extends Atom.Atom<any>, Input = never>(
90
+ f: (() => A) | ((input: Input) => A)
91
+ ): ScopedAtom<A, Input> => {
92
+ const Context = React.createContext<A>(undefined as unknown as A)
93
+
94
+ const use = (): A => {
95
+ const atom = React.useContext(Context)
96
+ if (atom === undefined) {
97
+ throw new Error("ScopedAtom used outside of its Provider")
98
+ }
99
+ return atom
100
+ }
101
+
102
+ const Provider: React.FC<{ readonly children?: React.ReactNode | undefined; readonly value?: Input }> = (props) => {
103
+ const atom = React.useRef<A | null>(null)
104
+ if (atom.current === null) {
105
+ if ("value" in props) {
106
+ atom.current = (f as (input: Input) => A)(props.value as Input)
107
+ } else {
108
+ atom.current = (f as () => A)()
109
+ }
110
+ }
111
+ return React.createElement(Context.Provider, { value: atom.current }, props.children)
112
+ }
113
+
114
+ return {
115
+ [TypeId]: TypeId,
116
+ use,
117
+ Provider: Provider as any,
118
+ Context
119
+ }
120
+ }
package/src/index.ts ADDED
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+
5
+ /**
6
+ * @since 1.0.0
7
+ */
8
+ export * from "./Hooks.ts"
9
+
10
+ /**
11
+ * @since 1.0.0
12
+ */
13
+ export * from "./RegistryContext.ts"
14
+
15
+ /**
16
+ * @since 1.0.0
17
+ */
18
+ export * from "./ScopedAtom.ts"