Skip to content

Commit fb922c9

Browse files
committed
add ScopedAtom module to atom-react
closes #322
1 parent c7bc459 commit fb922c9

5 files changed

Lines changed: 168 additions & 0 deletions

File tree

.changeset/plain-pianos-poke.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@effect-atom/atom-react": patch
3+
---
4+
5+
add ScopedAtom module to atom-react

docs/atom-react/ScopedAtom.ts.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
---
2+
title: ScopedAtom.ts
3+
nav_order: 5
4+
parent: "@effect-atom/atom-react"
5+
---
6+
7+
## ScopedAtom overview
8+
9+
Added in v1.0.0
10+
11+
---
12+
13+
<h2 class="text-delta">Table of contents</h2>
14+
15+
- [Type IDs](#type-ids)
16+
- [TypeId](#typeid)
17+
- [TypeId (type alias)](#typeid-type-alias)
18+
- [constructors](#constructors)
19+
- [make](#make)
20+
- [models](#models)
21+
- [ScopedAtom (interface)](#scopedatom-interface)
22+
23+
---
24+
25+
# Type IDs
26+
27+
## TypeId
28+
29+
**Signature**
30+
31+
```ts
32+
export declare const TypeId: "~@effect-atom/atom-react/ScopedAtom"
33+
```
34+
35+
Added in v1.0.0
36+
37+
## TypeId (type alias)
38+
39+
**Signature**
40+
41+
```ts
42+
export type TypeId = "~@effect-atom/atom-react/ScopedAtom"
43+
```
44+
45+
Added in v1.0.0
46+
47+
# constructors
48+
49+
## make
50+
51+
**Signature**
52+
53+
```ts
54+
export declare const make: <A extends Atom.Atom<any>, Input = never>(
55+
f: (() => A) | ((input: Input) => A)
56+
) => ScopedAtom<A, Input>
57+
```
58+
59+
Added in v1.0.0
60+
61+
# models
62+
63+
## ScopedAtom (interface)
64+
65+
**Signature**
66+
67+
```ts
68+
export interface ScopedAtom<A extends Atom.Atom<any>, Input = never> {
69+
readonly [TypeId]: TypeId
70+
use(): A
71+
Provider: Input extends never
72+
? React.FC<{ readonly children?: React.ReactNode | undefined }>
73+
: React.FC<{ readonly children?: React.ReactNode | undefined; readonly value: Input }>
74+
Context: React.Context<A>
75+
}
76+
```
77+
78+
Added in v1.0.0

docs/atom-react/index.ts.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Added in v1.0.0
1919
- [hooks](#hooks)
2020
- [From "./Hooks.js"](#from-hooksjs)
2121
- [re-exports](#re-exports)
22+
- [From "./ScopedAtom.js"](#from-scopedatomjs)
2223
- [From "@effect-atom/atom/AtomHttpApi"](#from-effect-atomatomatomhttpapi)
2324
- [From "@effect-atom/atom/AtomRef"](#from-effect-atomatomatomref)
2425
- [From "@effect-atom/atom/AtomRpc"](#from-effect-atomatomatomrpc)
@@ -72,6 +73,18 @@ Added in v1.0.0
7273

7374
# re-exports
7475

76+
## From "./ScopedAtom.js"
77+
78+
Re-exports all named exports from the "./ScopedAtom.js" module as `ScopedAtom`.
79+
80+
**Signature**
81+
82+
```ts
83+
export * as ScopedAtom from "./ScopedAtom.js"
84+
```
85+
86+
Added in v1.0.0
87+
7588
## From "@effect-atom/atom/AtomHttpApi"
7689

7790
Re-exports all named exports from the "@effect-atom/atom/AtomHttpApi" module as `AtomHttpApi`.
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/**
2+
* @since 1.0.0
3+
*/
4+
"use client"
5+
import type * as Atom from "@effect-atom/atom/Atom"
6+
import * as React from "react"
7+
8+
/**
9+
* @since 1.0.0
10+
* @category Type IDs
11+
*/
12+
export type TypeId = "~@effect-atom/atom-react/ScopedAtom"
13+
14+
/**
15+
* @since 1.0.0
16+
* @category Type IDs
17+
*/
18+
export const TypeId: TypeId = "~@effect-atom/atom-react/ScopedAtom"
19+
20+
/**
21+
* @since 1.0.0
22+
* @category models
23+
*/
24+
export interface ScopedAtom<A extends Atom.Atom<any>, Input = never> {
25+
readonly [TypeId]: TypeId
26+
use(): A
27+
Provider: Input extends never ? React.FC<{ readonly children?: React.ReactNode | undefined }>
28+
: React.FC<{ readonly children?: React.ReactNode | undefined; readonly value: Input }>
29+
Context: React.Context<A>
30+
}
31+
32+
/**
33+
* @since 1.0.0
34+
* @category constructors
35+
*/
36+
export const make = <A extends Atom.Atom<any>, Input = never>(
37+
f: (() => A) | ((input: Input) => A)
38+
): ScopedAtom<A, Input> => {
39+
const Context = React.createContext<A>(undefined as unknown as A)
40+
41+
const use = (): A => {
42+
const atom = React.useContext(Context)
43+
if (atom === undefined) {
44+
throw new Error("ScopedAtom used outside of its Provider")
45+
}
46+
return atom
47+
}
48+
49+
const Provider: React.FC<{ readonly children?: React.ReactNode | undefined; readonly value: Input }> = ({
50+
children,
51+
value
52+
}) => {
53+
const atom = React.useRef<A | null>(null)
54+
if (atom.current === null) {
55+
atom.current = f(value)
56+
}
57+
return React.createElement(Context.Provider, { value: atom.current }, children)
58+
}
59+
60+
return {
61+
[TypeId]: TypeId,
62+
use,
63+
Provider: Provider as any,
64+
Context
65+
}
66+
}

packages/atom-react/src/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ export * as AtomRpc from "@effect-atom/atom/AtomRpc"
4444
*/
4545
export * as Hydration from "@effect-atom/atom/Hydration"
4646

47+
/**
48+
* @since 1.0.0
49+
* @category re-exports
50+
*/
51+
export * as ScopedAtom from "./ScopedAtom.js"
52+
4753
/**
4854
* @since 1.0.0
4955
* @category hooks

0 commit comments

Comments
 (0)