atom.io 0.40.4 → 0.40.6

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.
@@ -23,17 +23,19 @@ declare function useLoadable<T, E>(token: ReadableToken<Loadable<T>, any, E>): `
23
23
  loading: boolean;
24
24
  value: E | T;
25
25
  };
26
- declare function useLoadable<T, K extends Canonical, E>(token: ReadableFamilyToken<Loadable<T>, K, E>, key: K): `LOADING` | {
26
+ declare function useLoadable<T, K extends Canonical, Key extends K, E>(token: ReadableFamilyToken<Loadable<T>, K, E>, key: Key): `LOADING` | {
27
27
  loading: boolean;
28
28
  value: E | T;
29
29
  };
30
30
  declare function useLoadable<T, F extends T, E>(token: ReadableToken<Loadable<T>, any, E>, fallback: F): {
31
31
  loading: boolean;
32
32
  value: T;
33
+ error?: E;
33
34
  };
34
- declare function useLoadable<T, K extends Canonical, F extends T, E>(token: ReadableFamilyToken<Loadable<T>, K, E>, key: K, fallback: F): {
35
+ declare function useLoadable<T, K extends Canonical, F extends T, Key extends K, E>(token: ReadableFamilyToken<Loadable<T>, K, E>, key: Key, fallback: F): {
35
36
  loading: boolean;
36
- value: E | T;
37
+ value: T;
38
+ error?: E;
37
39
  };
38
40
  //#endregion
39
41
  //#region src/react/use-o.d.ts
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":["StoreContext: React.Context<RootStore>","StoreProvider: React.FC<{\n\tchildren: React.ReactNode\n\tstore?: RootStore\n}>"],"sources":["../../src/react/store-context.tsx","../../src/react/use-i.ts","../../src/react/use-json.ts","../../src/react/use-loadable.ts","../../src/react/use-o.ts","../../src/react/use-tl.ts"],"sourcesContent":[],"mappings":";;;;;;cAIaA,cAAc,OAAA,CAAM,QAAQ;cAI5BC,eAAe,OAAA,CAAM;YACvB,OAAA,CAAM;UACR;AANT,CAAA,CAAA;;;iBCIgB,eACR,cAAc,4BACN,SAAS,aAAa,MAAM;iBAE5B,kBAAkB,WDRlC,YCQyD,CDR5CD,CAA4B,CAAA,KAAA,ECSjC,mBDTiC,CCSb,CDTa,ECSV,CDTU,EAAA,GAAA,CAAA,EAAA,GAAA,ECUnC,GDVmC,CAAA,EAAA,CAAA,YCWzB,CDXyB,CAAA,CAAA,IAAA,ECWhB,GDXgB,GAAA,CAAA,CAAA,GAAA,ECWH,CDXG,EAAA,GCWG,GDXH,CAAA,EAAA,GAAA,IAAA;;;iBEKzB,kBAAkB,mCAC1B,iBAAiB,KACtB,OAAO;iBAEM,kBACL,4BFVX,UEWW,SFX8B,CAAA,CAAA,KAAA,EEYhC,sBFZgC,CEYT,CFZS,EEYN,CFZM,CAAA,EAAA,GAAA,EEYG,CFZH,CAAA,EEYO,MFZP,CEYc,CFZd,CAAA;;;iBGEzB,iBHFhB,CAAA,KAAaA,EGGL,aHHiC,CGGnB,QHHmB,CGGV,CHHU,CAAA,EAAA,GAAA,EGGD,CHHC,CAAA,CAAA,EAAA,SAAA,GAAA;EAAA,OAAA,EAAA,OAAA;SGIC,CHJD,GGIK,CHJL;;iBGMzB,YHFhB,CAAA,YGEyC,mBHAhC,EGCD,mBHDC,CGCmB,QHDnB,CGC4B,CHD5B,CAAA,EGCgC,CHDhC,EGCmC,CHDnC,CAAA,EAAA,GAAA,EGEH,CHFG,CAAA,EAAA,SAAA,GAAA;SAFmB,EAAA,OAAM;SGKQ,IAAI;;iBAE9B,eFPhB,UEOyC,CFPzB,EAAA,CAAA,OACM,EEOd,aFPc,CEOA,QFPA,CEOS,CFPT,CAAA,EAAA,GAAA,EEOkB,CFPlB,CAAA,EAAA,QAAA,EEQX,CFRW,CAAA,EAAA;SAAd,EAAA,OAAA;SESsB,CFRd;;AAAsB,iBEUtB,WFVsB,cEUG,WFRzC,UEQ8D,CFR9C,EAAA,CAAA,OAAkB,EES1B,mBFT0B,CESN,QFTM,CESG,CFTH,CAAA,EESO,CFTP,EESU,CFTV,CAAA,EAAA,GAAA,EEU5B,CFV4B,EAAA,QAAA,EEWvB,CFXuB,CAAA,EAAA;SAAuB,EAAA,OAAA;SEY3B,CFXF,GEWM,CFXN;;;;iBGLZ,kBAAkB,cAAc,QAAQ,KAAK,IAAI;AJJpDA,iBIMG,IJNyB,CAAA,CAAA,YIMP,SJNO,cIMgB,CJN9B,IAI3B,CAAA,KAAaC,EIGL,mBJHKA,CIGe,CJHfA,EIGkB,CJHlBA,EIGqB,CJHrBA,CAAAA,EAAAA,GAAAA,EIIP,GJJOA,CAAAA,EIKV,CJLUA,GIKN,CJLMA;;;KKDD,YAAA;;;;;ALHZ,CAAA;AAAyC,iBKUzB,KAAA,CLVyB,KAAA,EKUZ,aLVY,CAAA,GAAA,CAAA,CAAA,EKUS,YLVT"}
1
+ {"version":3,"file":"index.d.ts","names":["StoreContext: React.Context<RootStore>","StoreProvider: React.FC<{\n\tchildren: React.ReactNode\n\tstore?: RootStore\n}>"],"sources":["../../src/react/store-context.tsx","../../src/react/use-i.ts","../../src/react/use-json.ts","../../src/react/use-loadable.ts","../../src/react/use-o.ts","../../src/react/use-tl.ts"],"sourcesContent":[],"mappings":";;;;;;cAIaA,cAAc,OAAA,CAAM,QAAQ;cAI5BC,eAAe,OAAA,CAAM;YACvB,OAAA,CAAM;UACR;AANT,CAAA,CAAA;;;iBCIgB,eACR,cAAc,4BACN,SAAS,aAAa,MAAM;iBAE5B,kBAAkB,WDRlC,YCQyD,CDR5CD,CAA4B,CAAA,KAAA,ECSjC,mBDTiC,CCSb,CDTa,ECSV,CDTU,EAAA,GAAA,CAAA,EAAA,GAAA,ECUnC,GDVmC,CAAA,EAAA,CAAA,YCWzB,CDXyB,CAAA,CAAA,IAAA,ECWhB,GDXgB,GAAA,CAAA,CAAA,GAAA,ECWH,CDXG,EAAA,GCWG,GDXH,CAAA,EAAA,GAAA,IAAA;;;iBEKzB,kBAAkB,mCAC1B,iBAAiB,KACtB,OAAO;iBAEM,kBACL,4BFVX,UEWW,SFX8B,CAAA,CAAA,KAAA,EEYhC,sBFZgC,CEYT,CFZS,EEYN,CFZM,CAAA,EAAA,GAAA,EEYG,CFZH,CAAA,EEYO,MFZP,CEYc,CFZd,CAAA;;;iBGGzB,iBHHhB,CAAA,KAAaA,EGIL,aHJiC,CGInB,QHJmB,CGIV,CHJU,CAAA,EAAA,GAAA,EGID,CHJC,CAAA,CAAA,EAAA,SAAA,GAAA;EAAA,OAAA,EAAA,OAAA;SGKC,CHLD,GGKK,CHLL;;iBGOzB,YHHhB,CAAA,YGGyC,uBAAuB,CHFrD,UADiB,EGIpB,mBHJ0B,CGIN,QHJM,CGIG,CHJH,CAAA,EGIO,CHJP,EGIU,CHJV,CAAA,EAAA,GAAA,EGK5B,GHL4B,CAAA,EAAA,SAAA,GAAA;;SGMQ,IAAI;;iBAE9B,YFRhB,CAAA,EAAgB,UEQyB,CFRzB,UACR,EEQA,aFRA,CEQc,QFRd,CEQuB,CFRvB,CAAA,EAAA,GAAA,EEQgC,CFRhC,CAAA,EAAA,QAAA,EESG,CFTH,CAAA,EAAA;SACQ,EAAA,OAAA;SESc,CFTL;QAAa,EESG,CFTH;;iBEWtB,YFThB,CAAA,EAAgB,UEWL,SFXK,YEYL,CFZuB,cEarB,CFb4C,UAC1B,EEevB,mBFfuB,CEeH,QFfG,CEeM,CFfN,CAAA,EEeU,CFfV,EEea,CFfb,CAAA,EAAA,GAAA,EEgBzB,GFhByB,EAAA,QAAA,EEiBpB,CFjBoB,CAAA,EAAA;SAAvB,EAAA,OAAA;SEkBsB,CFjBxB;QACU,EEgByB,CFhBzB;;;;iBGPA,kBAAkB,cAAc,QAAQ,KAAK,IAAI;AJJpDA,iBIMG,IJNyB,CAAA,CAAA,YIMP,SJNO,cIMgB,CJN9B,IAI3B,CAAA,KAAaC,EIGL,mBJHKA,CIGe,CJHfA,EIGkB,CJHlBA,EIGqB,CJHrBA,CAAAA,EAAAA,GAAAA,EIIP,GJJOA,CAAAA,EIKV,CJLUA,GIKN,CJLMA;;;KKDD,YAAA;;;;;ALHZ,CAAA;AAAyC,iBKUzB,KAAA,CLVyB,KAAA,EKUZ,aLVY,CAAA,GAAA,CAAA,CAAA,EKUS,YLVT"}
@@ -3,7 +3,7 @@ import { redo, undo } from "atom.io";
3
3
  import * as React$1 from "react";
4
4
  import React from "react";
5
5
  import { jsx } from "react/jsx-runtime";
6
- import { useO as useO$1 } from "atom.io/react";
6
+ import { StoreContext as StoreContext$1, useO as useO$1 } from "atom.io/react";
7
7
 
8
8
  //#region src/react/store-context.tsx
9
9
  const StoreContext = React$1.createContext(IMPLICIT.STORE);
@@ -57,6 +57,8 @@ function useJSON(token, key) {
57
57
  //#endregion
58
58
  //#region src/react/use-loadable.ts
59
59
  function useLoadable(...params) {
60
+ const store = React.useContext(StoreContext$1);
61
+ let value;
60
62
  let state;
61
63
  let fallback;
62
64
  const [token] = params;
@@ -68,7 +70,8 @@ function useLoadable(...params) {
68
70
  case `readonly_pure_selector`:
69
71
  case `writable_held_selector`:
70
72
  case `writable_pure_selector`:
71
- state = useO$1(token);
73
+ value = useO$1(token);
74
+ state = withdraw(store, token);
72
75
  fallback = params[1];
73
76
  break;
74
77
  case `atom_family`:
@@ -78,31 +81,49 @@ function useLoadable(...params) {
78
81
  case `writable_held_selector_family`:
79
82
  case `writable_pure_selector_family`:
80
83
  key = params[1];
81
- state = useO$1(token, key);
84
+ value = useO$1(token, key);
85
+ state = withdraw(store, findInStore(store, token, key));
82
86
  fallback = params[2];
83
87
  }
88
+ const isErr = `catch` in state && state.catch.some((E) => value instanceof E);
84
89
  const wrapperRef = React.useRef({
85
90
  loading: false,
86
91
  value: null
87
92
  });
88
- const lastLoadedRef = React.useRef(fallback ?? (state instanceof Promise ? `LOADING` : state));
93
+ const lastLoadedRef = React.useRef(fallback ?? (value instanceof Promise ? `LOADING` : value));
89
94
  const { current: lastLoaded } = lastLoadedRef;
90
95
  let { current: wrapper } = wrapperRef;
91
- if (state instanceof Promise) {
96
+ const wasErr = `catch` in state && state.catch.some((E) => lastLoaded instanceof E);
97
+ if (value instanceof Promise) {
92
98
  if (lastLoaded === `LOADING`) return `LOADING`;
93
- wrapper = wrapperRef.current = {
99
+ if (wasErr && fallback) wrapper = wrapperRef.current = {
100
+ loading: true,
101
+ value: fallback,
102
+ error: lastLoaded
103
+ };
104
+ else wrapper = wrapperRef.current = {
94
105
  loading: true,
95
106
  value: lastLoaded
96
107
  };
97
108
  } else {
98
- lastLoadedRef.current = state;
99
- if (wrapper.loading === true) wrapper = wrapperRef.current = {
109
+ lastLoadedRef.current = value;
110
+ if (wrapper.loading === true) if (isErr && fallback) wrapper = wrapperRef.current = {
100
111
  loading: false,
101
- value: state
112
+ value: fallback,
113
+ error: value
102
114
  };
103
- else {
115
+ else wrapper = wrapperRef.current = {
116
+ loading: false,
117
+ value
118
+ };
119
+ else if (isErr && fallback) {
120
+ wrapper.loading = false;
121
+ wrapper.value = fallback;
122
+ wrapper.error = value;
123
+ } else {
104
124
  wrapper.loading = false;
105
- wrapper.value = state;
125
+ wrapper.value = value;
126
+ delete wrapper.error;
106
127
  }
107
128
  }
108
129
  return wrapper;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["StoreContext: React.Context<RootStore>","React","StoreProvider: React.FC<{\n\tchildren: React.ReactNode\n\tstore?: RootStore\n}>","token: ReadableToken<any, any, any>","React","setter: React.RefObject<\n\t\t(<New extends T>(next: New | ((old: T) => New)) => void) | null\n\t>","React","React","stateToken: MutableAtomToken<any>","state: unknown","fallback: unknown","key: Canonical","useO","React"],"sources":["../../src/react/store-context.tsx","../../src/react/parse-state-overloads.ts","../../src/react/use-i.ts","../../src/react/use-o.ts","../../src/react/use-json.ts","../../src/react/use-loadable.ts","../../src/react/use-tl.ts"],"sourcesContent":["import type { RootStore } from \"atom.io/internal\"\nimport { IMPLICIT } from \"atom.io/internal\"\nimport * as React from \"react\"\n\nexport const StoreContext: React.Context<RootStore> = React.createContext(\n\tIMPLICIT.STORE,\n)\n\nexport const StoreProvider: React.FC<{\n\tchildren: React.ReactNode\n\tstore?: RootStore\n}> = ({ children, store = IMPLICIT.STORE }) => (\n\t<StoreContext.Provider value={store}>{children}</StoreContext.Provider>\n)\n","import type {\n\tReadableFamilyToken,\n\tReadableToken,\n\tWritableFamilyToken,\n\tWritableToken,\n} from \"atom.io\"\nimport type { Store } from \"atom.io/internal\"\nimport { findInStore } from \"atom.io/internal\"\nimport type { Canonical } from \"atom.io/json\"\n\nexport function parseStateOverloads<T, K extends Canonical, Key extends K, E>(\n\tstore: Store,\n\t...rest: [WritableFamilyToken<T, K, E>, Key] | [WritableToken<T, any, E>]\n): WritableToken<T, K, E>\n\nexport function parseStateOverloads<T, K extends Canonical, Key extends K, E>(\n\tstore: Store,\n\t...rest: [ReadableFamilyToken<T, K, E>, Key] | [ReadableToken<T, any, E>]\n): ReadableToken<T, K, E>\n\nexport function parseStateOverloads<T, K extends Canonical, Key extends K, E>(\n\tstore: Store,\n\t...rest: [ReadableFamilyToken<T, K, E>, Key] | [ReadableToken<T, any, E>]\n): ReadableToken<T, K, E> {\n\tlet token: ReadableToken<any, any, any>\n\tif (rest.length === 2) {\n\t\tconst family = rest[0]\n\t\tconst key = rest[1]\n\n\t\ttoken = findInStore(store, family, key)\n\t} else {\n\t\ttoken = rest[0]\n\t}\n\treturn token\n}\n","import type { WritableFamilyToken, WritableToken } from \"atom.io\"\nimport { setIntoStore } from \"atom.io/internal\"\nimport type { Canonical } from \"atom.io/json\"\nimport * as React from \"react\"\n\nimport { parseStateOverloads } from \"./parse-state-overloads\"\nimport { StoreContext } from \"./store-context\"\n\nexport function useI<T>(\n\ttoken: WritableToken<T, any, any>,\n): <New extends T>(next: New | ((old: T) => New)) => void\n\nexport function useI<T, K extends Canonical, Key extends K>(\n\ttoken: WritableFamilyToken<T, K, any>,\n\tkey: Key,\n): <New extends T>(next: New | ((old: T) => New)) => void\n\nexport function useI<T, K extends Canonical, Key extends K>(\n\t...params: [WritableFamilyToken<T, K, any>, Key] | [WritableToken<T, any, any>]\n): <New extends T>(next: New | ((old: T) => New)) => void {\n\tconst store = React.useContext(StoreContext)\n\tconst token = parseStateOverloads(store, ...params)\n\tconst setter: React.RefObject<\n\t\t(<New extends T>(next: New | ((old: T) => New)) => void) | null\n\t> = React.useRef(null)\n\tsetter.current ??= (next) => {\n\t\tsetIntoStore(store, token, next)\n\t}\n\treturn setter.current\n}\n","import type { ReadableFamilyToken, ReadableToken } from \"atom.io\"\nimport { getFromStore, subscribeToState } from \"atom.io/internal\"\nimport type { Canonical } from \"atom.io/json\"\nimport * as React from \"react\"\n\nimport { parseStateOverloads } from \"./parse-state-overloads\"\nimport { StoreContext } from \"./store-context\"\n\nexport function useO<T, E>(token: ReadableToken<T, any, E>): E | T\n\nexport function useO<T, K extends Canonical, Key extends K, E>(\n\ttoken: ReadableFamilyToken<T, K, E>,\n\tkey: Key,\n): E | T\n\nexport function useO<T, K extends Canonical, Key extends K, E>(\n\t...params: [ReadableFamilyToken<T, K, E>, Key] | [ReadableToken<T, any, E>]\n): E | T {\n\tconst store = React.useContext(StoreContext)\n\tconst token = parseStateOverloads(store, ...params)\n\tconst id = React.useId()\n\treturn React.useSyncExternalStore<E | T>(\n\t\t(dispatch) => subscribeToState(store, token, `use-o:${id}`, dispatch),\n\t\t() => getFromStore(store, token),\n\t\t() => getFromStore(store, token),\n\t)\n}\n","import type { MutableAtomFamilyToken, MutableAtomToken } from \"atom.io\"\nimport type { AsJSON, Transceiver } from \"atom.io/internal\"\nimport { findInStore, getJsonToken } from \"atom.io/internal\"\nimport type { Canonical, Json } from \"atom.io/json\"\nimport * as React from \"react\"\n\nimport { StoreContext } from \"./store-context\"\nimport { useO } from \"./use-o\"\n\nexport function useJSON<T extends Transceiver<any, any, any>>(\n\ttoken: MutableAtomToken<T>,\n): AsJSON<T>\n\nexport function useJSON<\n\tT extends Transceiver<any, any, any>,\n\tK extends Canonical,\n>(token: MutableAtomFamilyToken<T, K>, key: K): AsJSON<T>\n\nexport function useJSON(\n\ttoken: MutableAtomFamilyToken<any, any> | MutableAtomToken<any>,\n\tkey?: Canonical,\n): Json.Serializable {\n\tconst store = React.useContext(StoreContext)\n\tconst stateToken: MutableAtomToken<any> =\n\t\ttoken.type === `mutable_atom_family` ? findInStore(store, token, key) : token\n\tconst jsonToken = getJsonToken(store, stateToken)\n\treturn useO(jsonToken)\n}\n","/** biome-ignore-all lint/correctness/useHookAtTopLevel: params are used in an invariant way */\nimport type { Loadable, ReadableFamilyToken, ReadableToken } from \"atom.io\"\nimport type { Canonical } from \"atom.io/json\"\nimport { useO } from \"atom.io/react\"\nimport React from \"react\"\n\nexport function useLoadable<T, E>(\n\ttoken: ReadableToken<Loadable<T>, any, E>,\n): `LOADING` | { loading: boolean; value: E | T }\n\nexport function useLoadable<T, K extends Canonical, E>(\n\ttoken: ReadableFamilyToken<Loadable<T>, K, E>,\n\tkey: K,\n): `LOADING` | { loading: boolean; value: E | T }\n\nexport function useLoadable<T, F extends T, E>(\n\ttoken: ReadableToken<Loadable<T>, any, E>,\n\tfallback: F,\n): { loading: boolean; value: T }\n\nexport function useLoadable<T, K extends Canonical, F extends T, E>(\n\ttoken: ReadableFamilyToken<Loadable<T>, K, E>,\n\tkey: K,\n\tfallback: F,\n): { loading: boolean; value: E | T }\n\nexport function useLoadable(\n\t...params:\n\t\t| readonly [ReadableFamilyToken<any, Canonical, any>, Canonical, unknown]\n\t\t| readonly [ReadableFamilyToken<any, Canonical, any>, Canonical]\n\t\t| readonly [ReadableToken<any, any, any>, unknown]\n\t\t| readonly [ReadableToken<any, any, any>]\n): `LOADING` | { loading: boolean; value: unknown } {\n\tlet state: unknown\n\tlet fallback: unknown\n\n\tconst [token] = params\n\tlet key: Canonical\n\tswitch (token.type) {\n\t\tcase `atom`:\n\t\tcase `mutable_atom`:\n\t\tcase `readonly_held_selector`:\n\t\tcase `readonly_pure_selector`:\n\t\tcase `writable_held_selector`:\n\t\tcase `writable_pure_selector`:\n\t\t\tstate = useO(token)\n\t\t\tfallback = params[1]\n\t\t\tbreak\n\t\tcase `atom_family`:\n\t\tcase `mutable_atom_family`:\n\t\tcase `readonly_held_selector_family`:\n\t\tcase `readonly_pure_selector_family`:\n\t\tcase `writable_held_selector_family`:\n\t\tcase `writable_pure_selector_family`:\n\t\t\tkey = params[1] as Canonical\n\t\t\tstate = useO(token, key)\n\t\t\tfallback = params[2]\n\t}\n\n\tconst wrapperRef = React.useRef({ loading: false, value: null as unknown })\n\tconst lastLoadedRef = React.useRef(\n\t\tfallback ?? (state instanceof Promise ? `LOADING` : state),\n\t)\n\n\tconst { current: lastLoaded } = lastLoadedRef\n\tlet { current: wrapper } = wrapperRef\n\n\tif (state instanceof Promise) {\n\t\tif (lastLoaded === `LOADING`) {\n\t\t\treturn `LOADING`\n\t\t}\n\t\twrapper = wrapperRef.current = { loading: true, value: lastLoaded }\n\t} else {\n\t\tlastLoadedRef.current = state\n\t\tif (wrapper.loading === true) {\n\t\t\twrapper = wrapperRef.current = { loading: false, value: state }\n\t\t} else {\n\t\t\twrapper.loading = false\n\t\t\twrapper.value = state\n\t\t}\n\t}\n\n\treturn wrapper\n}\n","import type { TimelineToken } from \"atom.io\"\nimport { redo, undo } from \"atom.io\"\nimport { subscribeToTimeline, withdraw } from \"atom.io/internal\"\nimport * as React from \"react\"\n\nimport { StoreContext } from \"./store-context\"\n\nexport type TimelineMeta = {\n\tat: number\n\tlength: number\n\tundo: () => void\n\tredo: () => void\n}\n\nexport function useTL(token: TimelineToken<any>): TimelineMeta {\n\tconst store = React.useContext(StoreContext)\n\tconst id = React.useId()\n\tconst timeline = withdraw(store, token)\n\tconst tokenRef = React.useRef(token)\n\tconst rebuildMeta = () => {\n\t\treturn {\n\t\t\tat: timeline.at,\n\t\t\tlength: timeline.history.length,\n\t\t\tundo: () => {\n\t\t\t\tundo(token)\n\t\t\t},\n\t\t\tredo: () => {\n\t\t\t\tredo(token)\n\t\t\t},\n\t\t}\n\t}\n\tconst meta = React.useRef<TimelineMeta>(rebuildMeta())\n\tconst retrieve = () => {\n\t\tif (\n\t\t\tmeta.current.at !== timeline?.at ||\n\t\t\tmeta.current.length !== timeline?.history.length ||\n\t\t\ttokenRef.current !== token\n\t\t) {\n\t\t\ttokenRef.current = token\n\t\t\tmeta.current = rebuildMeta()\n\t\t}\n\t\treturn meta.current\n\t}\n\treturn React.useSyncExternalStore<TimelineMeta>(\n\t\t(dispatch) => subscribeToTimeline(store, token, `use-tl:${id}`, dispatch),\n\t\tretrieve,\n\t\tretrieve,\n\t)\n}\n"],"mappings":";;;;;;;;AAIA,MAAaA,eAAyCC,QAAM,cAC3D,SAAS;AAGV,MAAaC,iBAGP,EAAE,UAAU,QAAQ,SAAS,YAClC,oBAAC,aAAa;CAAS,OAAO;CAAQ;;;;;ACQvC,SAAgB,oBACf,OACA,GAAG,MACsB;CACzB,IAAIC;AACJ,KAAI,KAAK,WAAW,GAAG;EACtB,MAAM,SAAS,KAAK;EACpB,MAAM,MAAM,KAAK;AAEjB,UAAQ,YAAY,OAAO,QAAQ;OAEnC,SAAQ,KAAK;AAEd,QAAO;;;;;AChBR,SAAgB,KACf,GAAG,QACsD;CACzD,MAAM,QAAQC,QAAM,WAAW;CAC/B,MAAM,QAAQ,oBAAoB,OAAO,GAAG;CAC5C,MAAMC,SAEFD,QAAM,OAAO;AACjB,QAAO,aAAa,SAAS;AAC5B,eAAa,OAAO,OAAO;;AAE5B,QAAO,OAAO;;;;;ACbf,SAAgB,KACf,GAAG,QACK;CACR,MAAM,QAAQE,QAAM,WAAW;CAC/B,MAAM,QAAQ,oBAAoB,OAAO,GAAG;CAC5C,MAAM,KAAKA,QAAM;AACjB,QAAOA,QAAM,sBACX,aAAa,iBAAiB,OAAO,OAAO,SAAS,MAAM,iBACtD,aAAa,OAAO,cACpB,aAAa,OAAO;;;;;ACN5B,SAAgB,QACf,OACA,KACoB;CACpB,MAAM,QAAQC,QAAM,WAAW;CAC/B,MAAMC,aACL,MAAM,SAAS,wBAAwB,YAAY,OAAO,OAAO,OAAO;CACzE,MAAM,YAAY,aAAa,OAAO;AACtC,QAAO,KAAK;;;;;ACAb,SAAgB,YACf,GAAG,QAKgD;CACnD,IAAIC;CACJ,IAAIC;CAEJ,MAAM,CAAC,SAAS;CAChB,IAAIC;AACJ,SAAQ,MAAM,MAAd;EACC,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;AACJ,WAAQC,OAAK;AACb,cAAW,OAAO;AAClB;EACD,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;AACJ,SAAM,OAAO;AACb,WAAQA,OAAK,OAAO;AACpB,cAAW,OAAO;;CAGpB,MAAM,aAAa,MAAM,OAAO;EAAE,SAAS;EAAO,OAAO;;CACzD,MAAM,gBAAgB,MAAM,OAC3B,aAAa,iBAAiB,UAAU,YAAY;CAGrD,MAAM,EAAE,SAAS,eAAe;CAChC,IAAI,EAAE,SAAS,YAAY;AAE3B,KAAI,iBAAiB,SAAS;AAC7B,MAAI,eAAe,UAClB,QAAO;AAER,YAAU,WAAW,UAAU;GAAE,SAAS;GAAM,OAAO;;QACjD;AACN,gBAAc,UAAU;AACxB,MAAI,QAAQ,YAAY,KACvB,WAAU,WAAW,UAAU;GAAE,SAAS;GAAO,OAAO;;OAClD;AACN,WAAQ,UAAU;AAClB,WAAQ,QAAQ;;;AAIlB,QAAO;;;;;ACpER,SAAgB,MAAM,OAAyC;CAC9D,MAAM,QAAQC,QAAM,WAAW;CAC/B,MAAM,KAAKA,QAAM;CACjB,MAAM,WAAW,SAAS,OAAO;CACjC,MAAM,WAAWA,QAAM,OAAO;CAC9B,MAAM,oBAAoB;AACzB,SAAO;GACN,IAAI,SAAS;GACb,QAAQ,SAAS,QAAQ;GACzB,YAAY;AACX,SAAK;;GAEN,YAAY;AACX,SAAK;;;;CAIR,MAAM,OAAOA,QAAM,OAAqB;CACxC,MAAM,iBAAiB;AACtB,MACC,KAAK,QAAQ,OAAO,UAAU,MAC9B,KAAK,QAAQ,WAAW,UAAU,QAAQ,UAC1C,SAAS,YAAY,OACpB;AACD,YAAS,UAAU;AACnB,QAAK,UAAU;;AAEhB,SAAO,KAAK;;AAEb,QAAOA,QAAM,sBACX,aAAa,oBAAoB,OAAO,OAAO,UAAU,MAAM,WAChE,UACA"}
1
+ {"version":3,"file":"index.js","names":["StoreContext: React.Context<RootStore>","React","StoreProvider: React.FC<{\n\tchildren: React.ReactNode\n\tstore?: RootStore\n}>","token: ReadableToken<any, any, any>","React","setter: React.RefObject<\n\t\t(<New extends T>(next: New | ((old: T) => New)) => void) | null\n\t>","React","React","stateToken: MutableAtomToken<any>","StoreContext","value: unknown","state: ReadableState<any, any>","fallback: unknown","key: Canonical","useO","React"],"sources":["../../src/react/store-context.tsx","../../src/react/parse-state-overloads.ts","../../src/react/use-i.ts","../../src/react/use-o.ts","../../src/react/use-json.ts","../../src/react/use-loadable.ts","../../src/react/use-tl.ts"],"sourcesContent":["import type { RootStore } from \"atom.io/internal\"\nimport { IMPLICIT } from \"atom.io/internal\"\nimport * as React from \"react\"\n\nexport const StoreContext: React.Context<RootStore> = React.createContext(\n\tIMPLICIT.STORE,\n)\n\nexport const StoreProvider: React.FC<{\n\tchildren: React.ReactNode\n\tstore?: RootStore\n}> = ({ children, store = IMPLICIT.STORE }) => (\n\t<StoreContext.Provider value={store}>{children}</StoreContext.Provider>\n)\n","import type {\n\tReadableFamilyToken,\n\tReadableToken,\n\tWritableFamilyToken,\n\tWritableToken,\n} from \"atom.io\"\nimport type { Store } from \"atom.io/internal\"\nimport { findInStore } from \"atom.io/internal\"\nimport type { Canonical } from \"atom.io/json\"\n\nexport function parseStateOverloads<T, K extends Canonical, Key extends K, E>(\n\tstore: Store,\n\t...rest: [WritableFamilyToken<T, K, E>, Key] | [WritableToken<T, any, E>]\n): WritableToken<T, K, E>\n\nexport function parseStateOverloads<T, K extends Canonical, Key extends K, E>(\n\tstore: Store,\n\t...rest: [ReadableFamilyToken<T, K, E>, Key] | [ReadableToken<T, any, E>]\n): ReadableToken<T, K, E>\n\nexport function parseStateOverloads<T, K extends Canonical, Key extends K, E>(\n\tstore: Store,\n\t...rest: [ReadableFamilyToken<T, K, E>, Key] | [ReadableToken<T, any, E>]\n): ReadableToken<T, K, E> {\n\tlet token: ReadableToken<any, any, any>\n\tif (rest.length === 2) {\n\t\tconst family = rest[0]\n\t\tconst key = rest[1]\n\n\t\ttoken = findInStore(store, family, key)\n\t} else {\n\t\ttoken = rest[0]\n\t}\n\treturn token\n}\n","import type { WritableFamilyToken, WritableToken } from \"atom.io\"\nimport { setIntoStore } from \"atom.io/internal\"\nimport type { Canonical } from \"atom.io/json\"\nimport * as React from \"react\"\n\nimport { parseStateOverloads } from \"./parse-state-overloads\"\nimport { StoreContext } from \"./store-context\"\n\nexport function useI<T>(\n\ttoken: WritableToken<T, any, any>,\n): <New extends T>(next: New | ((old: T) => New)) => void\n\nexport function useI<T, K extends Canonical, Key extends K>(\n\ttoken: WritableFamilyToken<T, K, any>,\n\tkey: Key,\n): <New extends T>(next: New | ((old: T) => New)) => void\n\nexport function useI<T, K extends Canonical, Key extends K>(\n\t...params: [WritableFamilyToken<T, K, any>, Key] | [WritableToken<T, any, any>]\n): <New extends T>(next: New | ((old: T) => New)) => void {\n\tconst store = React.useContext(StoreContext)\n\tconst token = parseStateOverloads(store, ...params)\n\tconst setter: React.RefObject<\n\t\t(<New extends T>(next: New | ((old: T) => New)) => void) | null\n\t> = React.useRef(null)\n\tsetter.current ??= (next) => {\n\t\tsetIntoStore(store, token, next)\n\t}\n\treturn setter.current\n}\n","import type { ReadableFamilyToken, ReadableToken } from \"atom.io\"\nimport { getFromStore, subscribeToState } from \"atom.io/internal\"\nimport type { Canonical } from \"atom.io/json\"\nimport * as React from \"react\"\n\nimport { parseStateOverloads } from \"./parse-state-overloads\"\nimport { StoreContext } from \"./store-context\"\n\nexport function useO<T, E>(token: ReadableToken<T, any, E>): E | T\n\nexport function useO<T, K extends Canonical, Key extends K, E>(\n\ttoken: ReadableFamilyToken<T, K, E>,\n\tkey: Key,\n): E | T\n\nexport function useO<T, K extends Canonical, Key extends K, E>(\n\t...params: [ReadableFamilyToken<T, K, E>, Key] | [ReadableToken<T, any, E>]\n): E | T {\n\tconst store = React.useContext(StoreContext)\n\tconst token = parseStateOverloads(store, ...params)\n\tconst id = React.useId()\n\treturn React.useSyncExternalStore<E | T>(\n\t\t(dispatch) => subscribeToState(store, token, `use-o:${id}`, dispatch),\n\t\t() => getFromStore(store, token),\n\t\t() => getFromStore(store, token),\n\t)\n}\n","import type { MutableAtomFamilyToken, MutableAtomToken } from \"atom.io\"\nimport type { AsJSON, Transceiver } from \"atom.io/internal\"\nimport { findInStore, getJsonToken } from \"atom.io/internal\"\nimport type { Canonical, Json } from \"atom.io/json\"\nimport * as React from \"react\"\n\nimport { StoreContext } from \"./store-context\"\nimport { useO } from \"./use-o\"\n\nexport function useJSON<T extends Transceiver<any, any, any>>(\n\ttoken: MutableAtomToken<T>,\n): AsJSON<T>\n\nexport function useJSON<\n\tT extends Transceiver<any, any, any>,\n\tK extends Canonical,\n>(token: MutableAtomFamilyToken<T, K>, key: K): AsJSON<T>\n\nexport function useJSON(\n\ttoken: MutableAtomFamilyToken<any, any> | MutableAtomToken<any>,\n\tkey?: Canonical,\n): Json.Serializable {\n\tconst store = React.useContext(StoreContext)\n\tconst stateToken: MutableAtomToken<any> =\n\t\ttoken.type === `mutable_atom_family` ? findInStore(store, token, key) : token\n\tconst jsonToken = getJsonToken(store, stateToken)\n\treturn useO(jsonToken)\n}\n","/** biome-ignore-all lint/correctness/useHookAtTopLevel: params are used in an invariant way */\nimport type { Loadable, ReadableFamilyToken, ReadableToken } from \"atom.io\"\nimport { findInStore, type ReadableState, withdraw } from \"atom.io/internal\"\nimport type { Canonical } from \"atom.io/json\"\nimport { StoreContext, useO } from \"atom.io/react\"\nimport React from \"react\"\n\nexport function useLoadable<T, E>(\n\ttoken: ReadableToken<Loadable<T>, any, E>,\n): `LOADING` | { loading: boolean; value: E | T }\n\nexport function useLoadable<T, K extends Canonical, Key extends K, E>(\n\ttoken: ReadableFamilyToken<Loadable<T>, K, E>,\n\tkey: Key,\n): `LOADING` | { loading: boolean; value: E | T }\n\nexport function useLoadable<T, F extends T, E>(\n\ttoken: ReadableToken<Loadable<T>, any, E>,\n\tfallback: F,\n): { loading: boolean; value: T; error?: E }\n\nexport function useLoadable<\n\tT,\n\tK extends Canonical,\n\tF extends T,\n\tKey extends K,\n\tE,\n>(\n\ttoken: ReadableFamilyToken<Loadable<T>, K, E>,\n\tkey: Key,\n\tfallback: F,\n): { loading: boolean; value: T; error?: E }\n\nexport function useLoadable(\n\t...params:\n\t\t| readonly [ReadableFamilyToken<any, Canonical, any>, Canonical, unknown]\n\t\t| readonly [ReadableFamilyToken<any, Canonical, any>, Canonical]\n\t\t| readonly [ReadableToken<any, any, any>, unknown]\n\t\t| readonly [ReadableToken<any, any, any>]\n): `LOADING` | { loading: boolean; value: unknown; error?: unknown } {\n\tconst store = React.useContext(StoreContext)\n\n\tlet value: unknown\n\tlet state: ReadableState<any, any>\n\tlet fallback: unknown\n\n\tconst [token] = params\n\tlet key: Canonical\n\tswitch (token.type) {\n\t\tcase `atom`:\n\t\tcase `mutable_atom`:\n\t\tcase `readonly_held_selector`:\n\t\tcase `readonly_pure_selector`:\n\t\tcase `writable_held_selector`:\n\t\tcase `writable_pure_selector`:\n\t\t\tvalue = useO(token)\n\t\t\tstate = withdraw(store, token)\n\t\t\tfallback = params[1]\n\t\t\tbreak\n\t\tcase `atom_family`:\n\t\tcase `mutable_atom_family`:\n\t\tcase `readonly_held_selector_family`:\n\t\tcase `readonly_pure_selector_family`:\n\t\tcase `writable_held_selector_family`:\n\t\tcase `writable_pure_selector_family`:\n\t\t\tkey = params[1] as Canonical\n\t\t\tvalue = useO(token, key)\n\t\t\tstate = withdraw(store, findInStore(store, token, key))\n\t\t\tfallback = params[2]\n\t}\n\n\tconst isErr = `catch` in state && state.catch.some((E) => value instanceof E)\n\n\tconst wrapperRef = React.useRef<{\n\t\tloading: boolean\n\t\tvalue: unknown\n\t\terror?: unknown\n\t}>({ loading: false, value: null as unknown })\n\tconst lastLoadedRef = React.useRef(\n\t\tfallback ?? (value instanceof Promise ? `LOADING` : value),\n\t)\n\n\tconst { current: lastLoaded } = lastLoadedRef\n\tlet { current: wrapper } = wrapperRef\n\n\tconst wasErr =\n\t\t`catch` in state && state.catch.some((E) => lastLoaded instanceof E)\n\n\tif (value instanceof Promise) {\n\t\tif (lastLoaded === `LOADING`) {\n\t\t\treturn `LOADING`\n\t\t}\n\t\tif (wasErr && fallback) {\n\t\t\twrapper = wrapperRef.current = {\n\t\t\t\tloading: true,\n\t\t\t\tvalue: fallback,\n\t\t\t\terror: lastLoaded,\n\t\t\t}\n\t\t} else {\n\t\t\twrapper = wrapperRef.current = { loading: true, value: lastLoaded }\n\t\t}\n\t} else {\n\t\tlastLoadedRef.current = value\n\t\tif (wrapper.loading === true) {\n\t\t\tif (isErr && fallback) {\n\t\t\t\twrapper = wrapperRef.current = {\n\t\t\t\t\tloading: false,\n\t\t\t\t\tvalue: fallback,\n\t\t\t\t\terror: value,\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twrapper = wrapperRef.current = { loading: false, value: value }\n\t\t\t}\n\t\t} else {\n\t\t\tif (isErr && fallback) {\n\t\t\t\twrapper.loading = false\n\t\t\t\twrapper.value = fallback\n\t\t\t\twrapper.error = value\n\t\t\t} else {\n\t\t\t\twrapper.loading = false\n\t\t\t\twrapper.value = value\n\t\t\t\tdelete wrapper.error\n\t\t\t}\n\t\t}\n\t}\n\n\treturn wrapper\n}\n","import type { TimelineToken } from \"atom.io\"\nimport { redo, undo } from \"atom.io\"\nimport { subscribeToTimeline, withdraw } from \"atom.io/internal\"\nimport * as React from \"react\"\n\nimport { StoreContext } from \"./store-context\"\n\nexport type TimelineMeta = {\n\tat: number\n\tlength: number\n\tundo: () => void\n\tredo: () => void\n}\n\nexport function useTL(token: TimelineToken<any>): TimelineMeta {\n\tconst store = React.useContext(StoreContext)\n\tconst id = React.useId()\n\tconst timeline = withdraw(store, token)\n\tconst tokenRef = React.useRef(token)\n\tconst rebuildMeta = () => {\n\t\treturn {\n\t\t\tat: timeline.at,\n\t\t\tlength: timeline.history.length,\n\t\t\tundo: () => {\n\t\t\t\tundo(token)\n\t\t\t},\n\t\t\tredo: () => {\n\t\t\t\tredo(token)\n\t\t\t},\n\t\t}\n\t}\n\tconst meta = React.useRef<TimelineMeta>(rebuildMeta())\n\tconst retrieve = () => {\n\t\tif (\n\t\t\tmeta.current.at !== timeline?.at ||\n\t\t\tmeta.current.length !== timeline?.history.length ||\n\t\t\ttokenRef.current !== token\n\t\t) {\n\t\t\ttokenRef.current = token\n\t\t\tmeta.current = rebuildMeta()\n\t\t}\n\t\treturn meta.current\n\t}\n\treturn React.useSyncExternalStore<TimelineMeta>(\n\t\t(dispatch) => subscribeToTimeline(store, token, `use-tl:${id}`, dispatch),\n\t\tretrieve,\n\t\tretrieve,\n\t)\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "atom.io",
3
- "version": "0.40.4",
3
+ "version": "0.40.6",
4
4
  "description": "Composable and testable reactive data library.",
5
5
  "homepage": "https://atom.io.fyi",
6
6
  "sideEffects": false,
@@ -2,7 +2,7 @@ import type { ViewOf } from "atom.io"
2
2
 
3
3
  import type { ReadableState } from ".."
4
4
  import { readFromCache, writeToCache } from "../caching"
5
- import { isFn } from "../is-fn"
5
+ import { safeCompute } from "../safe-compute"
6
6
  import type { Store } from "../store"
7
7
 
8
8
  export function readOrComputeValue<T, E>(
@@ -30,83 +30,10 @@ export function readOrComputeValue<T, E>(
30
30
  case `writable_held_selector`:
31
31
  target.logger.info(`🧮`, state.type, key, `computing value`)
32
32
  return state.getFrom(target)
33
+ case `writable_pure_selector`:
33
34
  case `readonly_pure_selector`:
34
- case `writable_pure_selector`: {
35
- let val: E | T
36
- target.logger.info(`🧮`, state.type, key, `computing value`)
37
- try {
38
- val = state.getFrom(target)
39
- if (val instanceof Promise) {
40
- return (val as Promise<E & T>).catch((thrown) => {
41
- target.logger.error(`💥`, state.type, key, `rejected:`, thrown)
42
- if (state.catch) {
43
- for (const Class of state.catch) {
44
- if (thrown instanceof Class) {
45
- return thrown
46
- }
47
- }
48
- }
49
- throw thrown
50
- }) as E | T
51
- }
52
- } catch (e) {
53
- target.logger.error(`💥`, state.type, key, `rejected:`, e)
54
- if (state.catch) {
55
- for (const Class of state.catch) {
56
- if (e instanceof Class) {
57
- return writeToCache(target, state, e)
58
- }
59
- }
60
- }
61
- throw e
62
- }
63
- const cachedValue = writeToCache(target, state, val)
64
- return cachedValue
65
- }
66
- case `atom`: {
67
- let def: E | T
68
- if (isFn(state.default)) {
69
- try {
70
- def = state.default()
71
- if (def instanceof Promise) {
72
- def = (def as Promise<T> & T).catch<E | T>((thrown) => {
73
- target.logger.error(`💥`, state.type, key, `rejected:`, thrown)
74
- if (state.catch) {
75
- for (const Class of state.catch) {
76
- if (thrown instanceof Class) {
77
- return thrown
78
- }
79
- }
80
- }
81
- throw thrown
82
- }) as E | T
83
- }
84
- } catch (e) {
85
- target.logger.error(`💥`, state.type, key, `rejected:`, e)
86
- if (state.catch) {
87
- for (const Class of state.catch) {
88
- if (e instanceof Class) {
89
- def = writeToCache(target, state, e)
90
- target.logger.info(
91
- `✨`,
92
- state.type,
93
- key,
94
- `computed default`,
95
- def,
96
- )
97
- return def
98
- }
99
- }
100
- }
101
- throw e
102
- }
103
- } else {
104
- def = state.default
105
- target.logger.info(`✨`, state.type, key, `using static default`, def)
106
- }
107
- const cachedValue = writeToCache(target, state, def)
108
- return cachedValue
109
- }
35
+ case `atom`:
36
+ return safeCompute(target, state)
110
37
  case `mutable_atom`: {
111
38
  const instance = new state.class()
112
39
  target.logger.info(`✨`, state.type, key, `created new instance`, instance)
@@ -0,0 +1,90 @@
1
+ import type { PureSelector, RegularAtom } from "."
2
+ import { writeToCache } from "./caching"
3
+ import { isFn } from "./is-fn"
4
+ import type { Store } from "./store"
5
+
6
+ export function safeCompute<T, E>(
7
+ target: Store,
8
+ state: PureSelector<T, E> | RegularAtom<T, E>,
9
+ ): E | T {
10
+ const { type, key, catch: canCatch } = state
11
+ switch (type) {
12
+ case `readonly_pure_selector`:
13
+ case `writable_pure_selector`: {
14
+ let val: E | T
15
+ target.logger.info(`🧮`, type, key, `computing value`)
16
+ try {
17
+ val = state.getFrom(target)
18
+ if (val instanceof Promise) {
19
+ return (val as Promise<E & T>).catch((thrown) => {
20
+ target.logger.error(`💥`, type, key, `rejected:`, thrown)
21
+ if (canCatch) {
22
+ for (const Class of canCatch) {
23
+ if (thrown instanceof Class) {
24
+ return thrown
25
+ }
26
+ }
27
+ }
28
+ throw thrown
29
+ }) as E | T
30
+ }
31
+ } catch (e) {
32
+ target.logger.error(`💥`, type, key, `rejected:`, e)
33
+ if (canCatch) {
34
+ for (const Class of canCatch) {
35
+ if (e instanceof Class) {
36
+ return writeToCache(target, state, e)
37
+ }
38
+ }
39
+ }
40
+ throw e
41
+ }
42
+ const cachedValue = writeToCache(target, state, val)
43
+ return cachedValue
44
+ }
45
+ case `atom`: {
46
+ let def: E | T
47
+ if (isFn(state.default)) {
48
+ try {
49
+ def = state.default()
50
+ if (def instanceof Promise) {
51
+ def = (def as Promise<T> & T).catch<E | T>((thrown) => {
52
+ target.logger.error(`💥`, type, key, `rejected:`, thrown)
53
+ if (canCatch) {
54
+ for (const Class of canCatch) {
55
+ if (thrown instanceof Class) {
56
+ return thrown
57
+ }
58
+ }
59
+ }
60
+ throw thrown
61
+ }) as E | T
62
+ }
63
+ } catch (e) {
64
+ target.logger.error(`💥`, type, key, `rejected:`, e)
65
+ if (canCatch) {
66
+ for (const Class of canCatch) {
67
+ if (e instanceof Class) {
68
+ def = writeToCache(target, state, e)
69
+ target.logger.info(
70
+ `✨`,
71
+ state.type,
72
+ key,
73
+ `computed default`,
74
+ def,
75
+ )
76
+ return def
77
+ }
78
+ }
79
+ }
80
+ throw e
81
+ }
82
+ } else {
83
+ def = state.default
84
+ target.logger.info(`✨`, state.type, key, `using static default`, def)
85
+ }
86
+ const cachedValue = writeToCache(target, state, def)
87
+ return cachedValue
88
+ }
89
+ }
90
+ }
@@ -1,6 +1,7 @@
1
1
  import type { Atom, OpenOperation, Store, WritableState } from ".."
2
2
  import { traceRootSelectorAtoms } from ".."
3
3
  import { isFn } from "../is-fn"
4
+ import { safeCompute } from "../safe-compute"
4
5
  import { dispatchOrDeferStateUpdate } from "./dispatch-state-update"
5
6
  import type { ProtoUpdate } from "./operate-on-store"
6
7
  import { setAtom } from "./set-atom"
@@ -13,8 +14,9 @@ function resetAtom<T, E>(
13
14
  case `mutable_atom`:
14
15
  return setAtom(target, atom, new atom.class())
15
16
  case `atom`: {
16
- let def = atom.default
17
- if (isFn(def)) def = def()
17
+ let def: E | T
18
+ if (isFn(atom.default)) def = safeCompute(target, atom)
19
+ else def = atom.default
18
20
  return setAtom(target, atom, def)
19
21
  }
20
22
  }
@@ -30,16 +32,26 @@ export function resetAtomOrSelector<T, E>(
30
32
  case `mutable_atom`:
31
33
  protoUpdate = resetAtom(target, state)
32
34
  break
33
- case `writable_pure_selector`:
34
35
  case `writable_held_selector`:
35
36
  {
36
- const oldValue = state.getFrom(target)
37
37
  const atoms = traceRootSelectorAtoms(target, state.key)
38
38
  for (const atom of atoms.values()) {
39
39
  const rootProtoUpdate = resetAtom(target, atom)
40
40
  dispatchOrDeferStateUpdate(target, state, rootProtoUpdate, false)
41
41
  }
42
- const newValue = state.getFrom(target)
42
+ const value = state.getFrom(target)
43
+ protoUpdate = { oldValue: value, newValue: value }
44
+ }
45
+ break
46
+ case `writable_pure_selector`:
47
+ {
48
+ const oldValue = safeCompute(target, state)
49
+ const atoms = traceRootSelectorAtoms(target, state.key)
50
+ for (const atom of atoms.values()) {
51
+ const rootProtoUpdate = resetAtom(target, atom)
52
+ dispatchOrDeferStateUpdate(target, state, rootProtoUpdate, false)
53
+ }
54
+ const newValue = safeCompute(target, state)
43
55
  protoUpdate = { oldValue, newValue }
44
56
  }
45
57
  break
@@ -1,28 +1,35 @@
1
1
  /** biome-ignore-all lint/correctness/useHookAtTopLevel: params are used in an invariant way */
2
2
  import type { Loadable, ReadableFamilyToken, ReadableToken } from "atom.io"
3
+ import { findInStore, type ReadableState, withdraw } from "atom.io/internal"
3
4
  import type { Canonical } from "atom.io/json"
4
- import { useO } from "atom.io/react"
5
+ import { StoreContext, useO } from "atom.io/react"
5
6
  import React from "react"
6
7
 
7
8
  export function useLoadable<T, E>(
8
9
  token: ReadableToken<Loadable<T>, any, E>,
9
10
  ): `LOADING` | { loading: boolean; value: E | T }
10
11
 
11
- export function useLoadable<T, K extends Canonical, E>(
12
+ export function useLoadable<T, K extends Canonical, Key extends K, E>(
12
13
  token: ReadableFamilyToken<Loadable<T>, K, E>,
13
- key: K,
14
+ key: Key,
14
15
  ): `LOADING` | { loading: boolean; value: E | T }
15
16
 
16
17
  export function useLoadable<T, F extends T, E>(
17
18
  token: ReadableToken<Loadable<T>, any, E>,
18
19
  fallback: F,
19
- ): { loading: boolean; value: T }
20
+ ): { loading: boolean; value: T; error?: E }
20
21
 
21
- export function useLoadable<T, K extends Canonical, F extends T, E>(
22
+ export function useLoadable<
23
+ T,
24
+ K extends Canonical,
25
+ F extends T,
26
+ Key extends K,
27
+ E,
28
+ >(
22
29
  token: ReadableFamilyToken<Loadable<T>, K, E>,
23
- key: K,
30
+ key: Key,
24
31
  fallback: F,
25
- ): { loading: boolean; value: E | T }
32
+ ): { loading: boolean; value: T; error?: E }
26
33
 
27
34
  export function useLoadable(
28
35
  ...params:
@@ -30,8 +37,11 @@ export function useLoadable(
30
37
  | readonly [ReadableFamilyToken<any, Canonical, any>, Canonical]
31
38
  | readonly [ReadableToken<any, any, any>, unknown]
32
39
  | readonly [ReadableToken<any, any, any>]
33
- ): `LOADING` | { loading: boolean; value: unknown } {
34
- let state: unknown
40
+ ): `LOADING` | { loading: boolean; value: unknown; error?: unknown } {
41
+ const store = React.useContext(StoreContext)
42
+
43
+ let value: unknown
44
+ let state: ReadableState<any, any>
35
45
  let fallback: unknown
36
46
 
37
47
  const [token] = params
@@ -43,7 +53,8 @@ export function useLoadable(
43
53
  case `readonly_pure_selector`:
44
54
  case `writable_held_selector`:
45
55
  case `writable_pure_selector`:
46
- state = useO(token)
56
+ value = useO(token)
57
+ state = withdraw(store, token)
47
58
  fallback = params[1]
48
59
  break
49
60
  case `atom_family`:
@@ -53,30 +64,63 @@ export function useLoadable(
53
64
  case `writable_held_selector_family`:
54
65
  case `writable_pure_selector_family`:
55
66
  key = params[1] as Canonical
56
- state = useO(token, key)
67
+ value = useO(token, key)
68
+ state = withdraw(store, findInStore(store, token, key))
57
69
  fallback = params[2]
58
70
  }
59
71
 
60
- const wrapperRef = React.useRef({ loading: false, value: null as unknown })
72
+ const isErr = `catch` in state && state.catch.some((E) => value instanceof E)
73
+
74
+ const wrapperRef = React.useRef<{
75
+ loading: boolean
76
+ value: unknown
77
+ error?: unknown
78
+ }>({ loading: false, value: null as unknown })
61
79
  const lastLoadedRef = React.useRef(
62
- fallback ?? (state instanceof Promise ? `LOADING` : state),
80
+ fallback ?? (value instanceof Promise ? `LOADING` : value),
63
81
  )
64
82
 
65
83
  const { current: lastLoaded } = lastLoadedRef
66
84
  let { current: wrapper } = wrapperRef
67
85
 
68
- if (state instanceof Promise) {
86
+ const wasErr =
87
+ `catch` in state && state.catch.some((E) => lastLoaded instanceof E)
88
+
89
+ if (value instanceof Promise) {
69
90
  if (lastLoaded === `LOADING`) {
70
91
  return `LOADING`
71
92
  }
72
- wrapper = wrapperRef.current = { loading: true, value: lastLoaded }
93
+ if (wasErr && fallback) {
94
+ wrapper = wrapperRef.current = {
95
+ loading: true,
96
+ value: fallback,
97
+ error: lastLoaded,
98
+ }
99
+ } else {
100
+ wrapper = wrapperRef.current = { loading: true, value: lastLoaded }
101
+ }
73
102
  } else {
74
- lastLoadedRef.current = state
103
+ lastLoadedRef.current = value
75
104
  if (wrapper.loading === true) {
76
- wrapper = wrapperRef.current = { loading: false, value: state }
105
+ if (isErr && fallback) {
106
+ wrapper = wrapperRef.current = {
107
+ loading: false,
108
+ value: fallback,
109
+ error: value,
110
+ }
111
+ } else {
112
+ wrapper = wrapperRef.current = { loading: false, value: value }
113
+ }
77
114
  } else {
78
- wrapper.loading = false
79
- wrapper.value = state
115
+ if (isErr && fallback) {
116
+ wrapper.loading = false
117
+ wrapper.value = fallback
118
+ wrapper.error = value
119
+ } else {
120
+ wrapper.loading = false
121
+ wrapper.value = value
122
+ delete wrapper.error
123
+ }
80
124
  }
81
125
  }
82
126