@effect/atom-react 4.0.0-beta.4 → 4.0.0-beta.5

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.
@@ -0,0 +1,16 @@
1
+ import * as Hydration from "effect/unstable/reactivity/Hydration";
2
+ import * as React from "react";
3
+ /**
4
+ * @since 1.0.0
5
+ * @category components
6
+ */
7
+ export interface HydrationBoundaryProps {
8
+ state?: Iterable<Hydration.DehydratedAtom>;
9
+ children?: React.ReactNode;
10
+ }
11
+ /**
12
+ * @since 1.0.0
13
+ * @category components
14
+ */
15
+ export declare const HydrationBoundary: React.FC<HydrationBoundaryProps>;
16
+ //# sourceMappingURL=ReactHydration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReactHydration.d.ts","sourceRoot":"","sources":["../src/ReactHydration.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,SAAS,MAAM,sCAAsC,CAAA;AACjE,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC,KAAK,CAAC,EAAE,QAAQ,CAAC,SAAS,CAAC,cAAc,CAAC,CAAA;IAC1C,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC3B;AAED;;;GAGG;AACH,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC,sBAAsB,CA6D9D,CAAA"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ "use client";
5
+
6
+ import * as Hydration from "effect/unstable/reactivity/Hydration";
7
+ import * as React from "react";
8
+ import { RegistryContext } from "./RegistryContext.js";
9
+ /**
10
+ * @since 1.0.0
11
+ * @category components
12
+ */
13
+ export const HydrationBoundary = ({
14
+ children,
15
+ state
16
+ }) => {
17
+ const registry = React.useContext(RegistryContext);
18
+ // This useMemo is for performance reasons only, everything inside it must
19
+ // be safe to run in every render and code here should be read as "in render".
20
+ //
21
+ // This code needs to happen during the render phase, because after initial
22
+ // SSR, hydration needs to happen _before_ children render. Also, if hydrating
23
+ // during a transition, we want to hydrate as much as is safe in render so
24
+ // we can prerender as much as possible.
25
+ //
26
+ // For any Atom values that already exist in the registry, we want to hold back on
27
+ // hydrating until _after_ the render phase. The reason for this is that during
28
+ // transitions, we don't want the existing Atom values and subscribers to update to
29
+ // the new data on the current page, only _after_ the transition is committed.
30
+ // If the transition is aborted, we will have hydrated any _new_ Atom values, but
31
+ // we throw away the fresh data for any existing ones to avoid unexpectedly
32
+ // updating the UI.
33
+ const hydrationQueue = React.useMemo(() => {
34
+ if (state) {
35
+ const dehydratedAtoms = Array.from(state);
36
+ const nodes = registry.getNodes();
37
+ const newDehydratedAtoms = [];
38
+ const existingDehydratedAtoms = [];
39
+ for (const dehydratedAtom of dehydratedAtoms) {
40
+ const existingNode = nodes.get(dehydratedAtom.key);
41
+ if (!existingNode) {
42
+ // This is a new Atom value, safe to hydrate immediately
43
+ newDehydratedAtoms.push(dehydratedAtom);
44
+ } else {
45
+ // This Atom value already exists, queue it for later hydration
46
+ existingDehydratedAtoms.push(dehydratedAtom);
47
+ }
48
+ }
49
+ if (newDehydratedAtoms.length > 0) {
50
+ // It's actually fine to call this with state that already exists
51
+ // in the registry, or is older. hydrate() is idempotent.
52
+ Hydration.hydrate(registry, newDehydratedAtoms);
53
+ }
54
+ if (existingDehydratedAtoms.length > 0) {
55
+ return existingDehydratedAtoms;
56
+ }
57
+ }
58
+ return undefined;
59
+ }, [registry, state]);
60
+ React.useEffect(() => {
61
+ if (hydrationQueue) {
62
+ Hydration.hydrate(registry, hydrationQueue);
63
+ }
64
+ }, [registry, hydrationQueue]);
65
+ return React.createElement(React.Fragment, {}, children);
66
+ };
67
+ //# sourceMappingURL=ReactHydration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReactHydration.js","names":["Hydration","React","RegistryContext","HydrationBoundary","children","state","registry","useContext","hydrationQueue","useMemo","dehydratedAtoms","Array","from","nodes","getNodes","newDehydratedAtoms","existingDehydratedAtoms","dehydratedAtom","existingNode","get","key","push","length","hydrate","undefined","useEffect","createElement","Fragment"],"sources":["../src/ReactHydration.ts"],"sourcesContent":[null],"mappings":"AAAA;;;AAGA,YAAY;;AACZ,OAAO,KAAKA,SAAS,MAAM,sCAAsC;AACjE,OAAO,KAAKC,KAAK,MAAM,OAAO;AAC9B,SAASC,eAAe,QAAQ,sBAAsB;AAWtD;;;;AAIA,OAAO,MAAMC,iBAAiB,GAAqCA,CAAC;EAClEC,QAAQ;EACRC;AAAK,CACN,KAAI;EACH,MAAMC,QAAQ,GAAGL,KAAK,CAACM,UAAU,CAACL,eAAe,CAAC;EAElD;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,MAAMM,cAAc,GAAqDP,KAAK,CAACQ,OAAO,CAAC,MAAK;IAC1F,IAAIJ,KAAK,EAAE;MACT,MAAMK,eAAe,GAAGC,KAAK,CAACC,IAAI,CAACP,KAAK,CAAyC;MACjF,MAAMQ,KAAK,GAAGP,QAAQ,CAACQ,QAAQ,EAAE;MAEjC,MAAMC,kBAAkB,GAAyC,EAAE;MACnE,MAAMC,uBAAuB,GAAyC,EAAE;MAExE,KAAK,MAAMC,cAAc,IAAIP,eAAe,EAAE;QAC5C,MAAMQ,YAAY,GAAGL,KAAK,CAACM,GAAG,CAACF,cAAc,CAACG,GAAG,CAAC;QAElD,IAAI,CAACF,YAAY,EAAE;UACjB;UACAH,kBAAkB,CAACM,IAAI,CAACJ,cAAc,CAAC;QACzC,CAAC,MAAM;UACL;UACAD,uBAAuB,CAACK,IAAI,CAACJ,cAAc,CAAC;QAC9C;MACF;MAEA,IAAIF,kBAAkB,CAACO,MAAM,GAAG,CAAC,EAAE;QACjC;QACA;QACAtB,SAAS,CAACuB,OAAO,CAACjB,QAAQ,EAAES,kBAAkB,CAAC;MACjD;MAEA,IAAIC,uBAAuB,CAACM,MAAM,GAAG,CAAC,EAAE;QACtC,OAAON,uBAAuB;MAChC;IACF;IACA,OAAOQ,SAAS;EAClB,CAAC,EAAE,CAAClB,QAAQ,EAAED,KAAK,CAAC,CAAC;EAErBJ,KAAK,CAACwB,SAAS,CAAC,MAAK;IACnB,IAAIjB,cAAc,EAAE;MAClBR,SAAS,CAACuB,OAAO,CAACjB,QAAQ,EAAEE,cAAc,CAAC;IAC7C;EACF,CAAC,EAAE,CAACF,QAAQ,EAAEE,cAAc,CAAC,CAAC;EAE9B,OAAOP,KAAK,CAACyB,aAAa,CAACzB,KAAK,CAAC0B,QAAQ,EAAE,EAAE,EAAEvB,QAAQ,CAAC;AAC1D,CAAC","ignoreList":[]}
package/dist/index.d.ts CHANGED
@@ -9,6 +9,10 @@ export * from "./Hooks.ts";
9
9
  * @since 1.0.0
10
10
  */
11
11
  export * from "./RegistryContext.ts";
12
+ /**
13
+ * @since 1.0.0
14
+ */
15
+ export * from "./ReactHydration.ts";
12
16
  /**
13
17
  * @since 1.0.0
14
18
  */
@@ -1 +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"}
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,qBAAqB,CAAA;AAEnC;;GAEG;AACH,cAAc,iBAAiB,CAAA"}
package/dist/index.js CHANGED
@@ -9,6 +9,10 @@ export * from "./Hooks.js";
9
9
  * @since 1.0.0
10
10
  */
11
11
  export * from "./RegistryContext.js";
12
+ /**
13
+ * @since 1.0.0
14
+ */
15
+ export * from "./ReactHydration.js";
12
16
  /**
13
17
  * @since 1.0.0
14
18
  */
package/dist/index.js.map CHANGED
@@ -1 +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":[]}
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,qBAAqB;AAEnC;;;AAGA,cAAc,iBAAiB","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect/atom-react",
3
- "version": "4.0.0-beta.4",
3
+ "version": "4.0.0-beta.5",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "React bindings for the Effect Atom modules",
@@ -45,7 +45,7 @@
45
45
  "peerDependencies": {
46
46
  "react": "^19.2.4",
47
47
  "scheduler": "*",
48
- "effect": "^4.0.0-beta.4"
48
+ "effect": "^4.0.0-beta.5"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@testing-library/dom": "^10.4.1",
@@ -59,7 +59,7 @@
59
59
  "react-dom": "19.2.3",
60
60
  "react-error-boundary": "^6.0.0",
61
61
  "scheduler": "^0.27.0",
62
- "effect": "^4.0.0-beta.4"
62
+ "effect": "^4.0.0-beta.5"
63
63
  },
64
64
  "scripts": {
65
65
  "build": "tsc -b tsconfig.json && pnpm babel",
@@ -0,0 +1,83 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ "use client"
5
+ import * as Hydration from "effect/unstable/reactivity/Hydration"
6
+ import * as React from "react"
7
+ import { RegistryContext } from "./RegistryContext.ts"
8
+
9
+ /**
10
+ * @since 1.0.0
11
+ * @category components
12
+ */
13
+ export interface HydrationBoundaryProps {
14
+ state?: Iterable<Hydration.DehydratedAtom>
15
+ children?: React.ReactNode
16
+ }
17
+
18
+ /**
19
+ * @since 1.0.0
20
+ * @category components
21
+ */
22
+ export const HydrationBoundary: React.FC<HydrationBoundaryProps> = ({
23
+ children,
24
+ state
25
+ }) => {
26
+ const registry = React.useContext(RegistryContext)
27
+
28
+ // This useMemo is for performance reasons only, everything inside it must
29
+ // be safe to run in every render and code here should be read as "in render".
30
+ //
31
+ // This code needs to happen during the render phase, because after initial
32
+ // SSR, hydration needs to happen _before_ children render. Also, if hydrating
33
+ // during a transition, we want to hydrate as much as is safe in render so
34
+ // we can prerender as much as possible.
35
+ //
36
+ // For any Atom values that already exist in the registry, we want to hold back on
37
+ // hydrating until _after_ the render phase. The reason for this is that during
38
+ // transitions, we don't want the existing Atom values and subscribers to update to
39
+ // the new data on the current page, only _after_ the transition is committed.
40
+ // If the transition is aborted, we will have hydrated any _new_ Atom values, but
41
+ // we throw away the fresh data for any existing ones to avoid unexpectedly
42
+ // updating the UI.
43
+ const hydrationQueue: Array<Hydration.DehydratedAtomValue> | undefined = React.useMemo(() => {
44
+ if (state) {
45
+ const dehydratedAtoms = Array.from(state) as Array<Hydration.DehydratedAtomValue>
46
+ const nodes = registry.getNodes()
47
+
48
+ const newDehydratedAtoms: Array<Hydration.DehydratedAtomValue> = []
49
+ const existingDehydratedAtoms: Array<Hydration.DehydratedAtomValue> = []
50
+
51
+ for (const dehydratedAtom of dehydratedAtoms) {
52
+ const existingNode = nodes.get(dehydratedAtom.key)
53
+
54
+ if (!existingNode) {
55
+ // This is a new Atom value, safe to hydrate immediately
56
+ newDehydratedAtoms.push(dehydratedAtom)
57
+ } else {
58
+ // This Atom value already exists, queue it for later hydration
59
+ existingDehydratedAtoms.push(dehydratedAtom)
60
+ }
61
+ }
62
+
63
+ if (newDehydratedAtoms.length > 0) {
64
+ // It's actually fine to call this with state that already exists
65
+ // in the registry, or is older. hydrate() is idempotent.
66
+ Hydration.hydrate(registry, newDehydratedAtoms)
67
+ }
68
+
69
+ if (existingDehydratedAtoms.length > 0) {
70
+ return existingDehydratedAtoms
71
+ }
72
+ }
73
+ return undefined
74
+ }, [registry, state])
75
+
76
+ React.useEffect(() => {
77
+ if (hydrationQueue) {
78
+ Hydration.hydrate(registry, hydrationQueue)
79
+ }
80
+ }, [registry, hydrationQueue])
81
+
82
+ return React.createElement(React.Fragment, {}, children)
83
+ }
package/src/index.ts CHANGED
@@ -12,6 +12,11 @@ export * from "./Hooks.ts"
12
12
  */
13
13
  export * from "./RegistryContext.ts"
14
14
 
15
+ /**
16
+ * @since 1.0.0
17
+ */
18
+ export * from "./ReactHydration.ts"
19
+
15
20
  /**
16
21
  * @since 1.0.0
17
22
  */