atom.io 0.13.0 → 0.14.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.
Files changed (64) hide show
  1. package/dist/index.cjs +9 -74
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +4 -4
  4. package/dist/index.d.ts +4 -4
  5. package/dist/index.js +11 -74
  6. package/dist/index.js.map +1 -1
  7. package/dist/metafile-cjs.json +1 -1
  8. package/dist/metafile-esm.json +1 -1
  9. package/internal/dist/index.cjs +802 -730
  10. package/internal/dist/index.cjs.map +1 -1
  11. package/internal/dist/index.d.cts +9 -2
  12. package/internal/dist/index.d.ts +9 -2
  13. package/internal/dist/index.js +800 -731
  14. package/internal/dist/index.js.map +1 -1
  15. package/internal/dist/metafile-cjs.json +1 -1
  16. package/internal/dist/metafile-esm.json +1 -1
  17. package/internal/src/atom/create-atom.ts +3 -2
  18. package/internal/src/mutable/create-mutable-atom.ts +3 -2
  19. package/internal/src/mutable/tracker.ts +6 -4
  20. package/internal/src/selector/register-selector.ts +1 -1
  21. package/internal/src/selector/update-selector-atoms.ts +3 -3
  22. package/internal/src/subscribe/index.ts +3 -0
  23. package/internal/src/subscribe/recall-state.ts +0 -6
  24. package/internal/src/subscribe/subscribe-to-state.ts +47 -0
  25. package/internal/src/subscribe/subscribe-to-timeline.ts +28 -0
  26. package/internal/src/subscribe/subscribe-to-transaction.ts +33 -0
  27. package/package.json +8 -8
  28. package/react/dist/index.cjs +39 -1
  29. package/react/dist/index.cjs.map +1 -1
  30. package/react/dist/index.d.cts +9 -2
  31. package/react/dist/index.d.ts +9 -2
  32. package/react/dist/index.js +41 -4
  33. package/react/dist/index.js.map +1 -1
  34. package/react/dist/metafile-cjs.json +1 -1
  35. package/react/dist/metafile-esm.json +1 -1
  36. package/react/src/store-hooks.ts +52 -3
  37. package/react-devtools/dist/index.cjs.map +1 -1
  38. package/react-devtools/dist/index.js.map +1 -1
  39. package/react-devtools/dist/metafile-cjs.json +1 -1
  40. package/react-devtools/dist/metafile-esm.json +1 -1
  41. package/realtime-client/dist/index.cjs +8 -7
  42. package/realtime-client/dist/index.cjs.map +1 -1
  43. package/realtime-client/dist/index.d.cts +3 -2
  44. package/realtime-client/dist/index.d.ts +3 -2
  45. package/realtime-client/dist/index.js +3 -2
  46. package/realtime-client/dist/index.js.map +1 -1
  47. package/realtime-client/dist/metafile-cjs.json +1 -1
  48. package/realtime-client/dist/metafile-esm.json +1 -1
  49. package/realtime-client/src/use-push.ts +4 -4
  50. package/realtime-client/src/use-server-action.ts +4 -4
  51. package/realtime-server/dist/index.cjs +46 -25
  52. package/realtime-server/dist/index.cjs.map +1 -1
  53. package/realtime-server/dist/index.d.cts +5 -5
  54. package/realtime-server/dist/index.d.ts +5 -5
  55. package/realtime-server/dist/index.js +38 -17
  56. package/realtime-server/dist/index.js.map +1 -1
  57. package/realtime-server/dist/metafile-cjs.json +1 -1
  58. package/realtime-server/dist/metafile-esm.json +1 -1
  59. package/realtime-server/src/hook-composition/expose-family.ts +7 -3
  60. package/realtime-server/src/hook-composition/expose-mutable-family.ts +13 -5
  61. package/realtime-server/src/hook-composition/expose-mutable.ts +11 -3
  62. package/realtime-server/src/hook-composition/expose-single.ts +6 -2
  63. package/realtime-server/src/hook-composition/receive-transaction.ts +14 -5
  64. package/src/subscribe.ts +37 -91
@@ -0,0 +1,47 @@
1
+ import type { ReadonlySelectorToken, StateToken, UpdateHandler } from "atom.io"
2
+ import type { Store } from "atom.io/internal"
3
+ import { subscribeToRootAtoms, withdraw } from "atom.io/internal"
4
+
5
+ export function subscribeToState<T>(
6
+ token: ReadonlySelectorToken<T> | StateToken<T>,
7
+ handleUpdate: UpdateHandler<T>,
8
+ key: string,
9
+ store: Store,
10
+ ): () => void {
11
+ const state = withdraw<T>(token, store)
12
+ if (state === undefined) {
13
+ throw new Error(
14
+ `State "${token.key}" not found in this store. Did you forget to initialize with the "atom" or "selector" function?`,
15
+ )
16
+ }
17
+ const unsubFunction = state.subject.subscribe(key, handleUpdate)
18
+ store.logger.info(`👀`, state.type, state.key, `Adding subscription "${key}"`)
19
+ const dependencyUnsubFunctions =
20
+ state.type !== `atom` ? subscribeToRootAtoms(state, store) : null
21
+
22
+ const unsubscribe =
23
+ dependencyUnsubFunctions === null
24
+ ? () => {
25
+ store.logger.info(
26
+ `🙈`,
27
+ state.type,
28
+ state.key,
29
+ `Removing subscription "${key}"`,
30
+ )
31
+ unsubFunction()
32
+ }
33
+ : () => {
34
+ store.logger.info(
35
+ `🙈`,
36
+ state.type,
37
+ state.key,
38
+ `Removing subscription "${key}"`,
39
+ )
40
+ unsubFunction()
41
+ for (const unsubFromDependency of dependencyUnsubFunctions) {
42
+ unsubFromDependency()
43
+ }
44
+ }
45
+
46
+ return unsubscribe
47
+ }
@@ -0,0 +1,28 @@
1
+ import type { TimelineToken, TimelineUpdate } from "atom.io"
2
+ import type { Store } from "atom.io/internal"
3
+ import { withdraw } from "atom.io/internal"
4
+
5
+ export const subscribeToTimeline = (
6
+ token: TimelineToken,
7
+ handleUpdate: (update: TimelineUpdate | `redo` | `undo`) => void,
8
+ key: string,
9
+ store: Store,
10
+ ): (() => void) => {
11
+ const tl = withdraw(token, store)
12
+ if (tl === undefined) {
13
+ throw new Error(
14
+ `Cannot subscribe to timeline "${token.key}": timeline not found in store "${store.config.name}".`,
15
+ )
16
+ }
17
+ store.logger.info(`👀`, `timeline`, token.key, `Adding subscription "${key}"`)
18
+ const unsubscribe = tl.subject.subscribe(key, handleUpdate)
19
+ return () => {
20
+ store.logger.info(
21
+ `🙈`,
22
+ `timeline`,
23
+ token.key,
24
+ `Removing subscription "${key}" from timeline`,
25
+ )
26
+ unsubscribe()
27
+ }
28
+ }
@@ -0,0 +1,33 @@
1
+ import type { TransactionToken, TransactionUpdateHandler, ƒn } from "atom.io"
2
+ import type { Store } from "atom.io/internal"
3
+ import { withdraw } from "atom.io/internal"
4
+
5
+ export const subscribeToTransaction = <ƒ extends ƒn>(
6
+ token: TransactionToken<ƒ>,
7
+ handleUpdate: TransactionUpdateHandler<ƒ>,
8
+ key: string,
9
+ store: Store,
10
+ ): (() => void) => {
11
+ const tx = withdraw(token, store)
12
+ if (tx === undefined) {
13
+ throw new Error(
14
+ `Cannot subscribe to transaction "${token.key}": transaction not found in store "${store.config.name}".`,
15
+ )
16
+ }
17
+ store.logger.info(
18
+ `👀`,
19
+ `transaction`,
20
+ token.key,
21
+ `Adding subscription "${key}"`,
22
+ )
23
+ const unsubscribe = tx.subject.subscribe(key, handleUpdate)
24
+ return () => {
25
+ store.logger.info(
26
+ `🙈`,
27
+ `transaction`,
28
+ token.key,
29
+ `Removing subscription "${key}"`,
30
+ )
31
+ unsubscribe()
32
+ }
33
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "atom.io",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "description": "Composable and testable reactive data library.",
5
5
  "homepage": "https://atom.io.fyi",
6
6
  "sideEffects": false,
@@ -54,17 +54,17 @@
54
54
  "@types/npmlog": "7.0.0",
55
55
  "@types/react": "18.2.42",
56
56
  "@types/tmp": "0.2.6",
57
- "@vitest/coverage-v8": "1.0.1",
57
+ "@vitest/coverage-v8": "1.0.2",
58
58
  "concurrently": "8.2.2",
59
59
  "drizzle-kit": "0.20.6",
60
60
  "drizzle-orm": "0.29.1",
61
61
  "eslint": "8.55.0",
62
- "framer-motion": "10.16.14",
62
+ "framer-motion": "10.16.16",
63
63
  "happy-dom": "12.10.3",
64
64
  "http-proxy": "1.18.1",
65
65
  "npmlog": "7.0.1",
66
66
  "postgres": "3.4.3",
67
- "preact": "10.19.2",
67
+ "preact": "10.19.3",
68
68
  "react": "18.2.0",
69
69
  "react-dom": "18.2.0",
70
70
  "react-router-dom": "6.20.1",
@@ -72,10 +72,10 @@
72
72
  "socket.io-client": "4.7.2",
73
73
  "tmp": "0.2.1",
74
74
  "tsup": "8.0.1",
75
- "typescript": "5.3.2",
76
- "vite": "5.0.6",
77
- "vite-tsconfig-paths": "4.2.1",
78
- "vitest": "1.0.1"
75
+ "typescript": "5.3.3",
76
+ "vite": "5.0.7",
77
+ "vite-tsconfig-paths": "4.2.2",
78
+ "vitest": "1.0.2"
79
79
  },
80
80
  "main": "dist/index.js",
81
81
  "types": "dist/index.d.ts",
@@ -40,7 +40,7 @@ function useO(token) {
40
40
  const store = React2__namespace.useContext(StoreContext);
41
41
  const id = React2__namespace.useId();
42
42
  return React2__namespace.useSyncExternalStore(
43
- (dispatch) => atom_io.subscribe(token, dispatch, `use-o:${id}`, store),
43
+ (dispatch) => internal.subscribeToState(token, dispatch, `use-o:${id}`, store),
44
44
  () => atom_io.getState(token, store),
45
45
  () => atom_io.getState(token, store)
46
46
  );
@@ -49,11 +49,49 @@ function useJSON(token) {
49
49
  const jsonToken = internal.getJsonToken(token);
50
50
  return useO(jsonToken);
51
51
  }
52
+ function useTL(token) {
53
+ const store = React2__namespace.useContext(StoreContext);
54
+ const id = React2__namespace.useId();
55
+ const timeline = internal.withdraw(token, store);
56
+ if (timeline === void 0) {
57
+ store.logger.error(
58
+ `\u274C`,
59
+ `timeline`,
60
+ token.key,
61
+ `Failed to use timeline because it does not exist`
62
+ );
63
+ return {
64
+ at: NaN,
65
+ length: NaN,
66
+ undo: () => {
67
+ },
68
+ redo: () => {
69
+ }
70
+ };
71
+ }
72
+ const meta = React2__namespace.useRef({
73
+ at: timeline.at,
74
+ length: timeline.history.length,
75
+ undo: () => atom_io.undo(token),
76
+ redo: () => atom_io.redo(token)
77
+ });
78
+ const retrieve = React2__namespace.useCallback(() => {
79
+ meta.current.at = timeline.at;
80
+ meta.current.length = timeline.history.length;
81
+ return meta.current;
82
+ }, [meta]);
83
+ return React2__namespace.useSyncExternalStore(
84
+ (dispatch) => internal.subscribeToTimeline(token, dispatch, `use-tl:${id}`, store),
85
+ retrieve,
86
+ retrieve
87
+ );
88
+ }
52
89
 
53
90
  exports.StoreContext = StoreContext;
54
91
  exports.StoreProvider = StoreProvider;
55
92
  exports.useI = useI;
56
93
  exports.useJSON = useJSON;
57
94
  exports.useO = useO;
95
+ exports.useTL = useTL;
58
96
  //# sourceMappingURL=out.js.map
59
97
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/store-context.tsx","../src/store-hooks.ts"],"names":["React"],"mappings":";AACA,SAAS,gBAAgB;AACzB,YAAY,WAAW;AAQtB;AANM,IAAM,eAAqB,oBAAqB,SAAS,KAAK;AAE9D,IAAM,gBAGR,CAAC,EAAE,UAAU,QAAQ,SAAS,MAAM,MACxC,oBAAC,aAAa,UAAb,EAAsB,OAAO,OAAQ,UAAS;;;ACVhD,YAAYA,YAAW;AAEvB,SAAS,UAAU,UAAU,iBAAiB;AAO9C,SAAS,oBAAoB;AAItB,SAAS,KACf,OACyD;AACzD,QAAM,QAAc,kBAAW,YAAY;AAC3C,QAAM,SAEI,cAAO,IAAI;AACrB,MAAI,OAAO,YAAY,MAAM;AAC5B,WAAO,UAAU,CAAC,SAAS,SAAS,OAAO,MAAM,KAAK;AAAA,EACvD;AACA,SAAO,OAAO;AACf;AAEO,SAAS,KAAQ,OAAoD;AAC3E,QAAM,QAAc,kBAAW,YAAY;AAC3C,QAAM,KAAW,aAAM;AACvB,SAAa;AAAA,IACZ,CAAC,aAAa,UAAU,OAAO,UAAU,SAAS,EAAE,IAAI,KAAK;AAAA,IAC7D,MAAM,SAAS,OAAO,KAAK;AAAA,IAC3B,MAAM,SAAS,OAAO,KAAK;AAAA,EAC5B;AACD;AAEO,SAAS,QACf,OACe;AACf,QAAM,YAAY,aAAa,KAAK;AACpC,SAAO,KAAK,SAAS;AACtB","sourcesContent":["import type { Store } from \"atom.io/internal\"\nimport { IMPLICIT } from \"atom.io/internal\"\nimport * as React from \"react\"\n\nexport const StoreContext = React.createContext<Store>(IMPLICIT.STORE)\n\nexport const StoreProvider: React.FC<{\n\tchildren: React.ReactNode\n\tstore?: Store\n}> = ({ children, store = IMPLICIT.STORE }) => (\n\t<StoreContext.Provider value={store}>{children}</StoreContext.Provider>\n)\n","import * as React from \"react\"\n\nimport { getState, setState, subscribe } from \"atom.io\"\nimport type {\n\tMutableAtomToken,\n\tReadonlySelectorToken,\n\tStateToken,\n} from \"atom.io\"\n\nimport { getJsonToken } from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\nimport { StoreContext } from \"./store-context\"\n\nexport function useI<T>(\n\ttoken: StateToken<T>,\n): <New extends T>(next: New | ((old: T) => New)) => void {\n\tconst store = React.useContext(StoreContext)\n\tconst setter: React.MutableRefObject<\n\t\t(<New extends T>(next: New | ((old: T) => New)) => void) | null\n\t> = React.useRef(null)\n\tif (setter.current === null) {\n\t\tsetter.current = (next) => setState(token, next, store)\n\t}\n\treturn setter.current\n}\n\nexport function useO<T>(token: ReadonlySelectorToken<T> | StateToken<T>): T {\n\tconst store = React.useContext(StoreContext)\n\tconst id = React.useId()\n\treturn React.useSyncExternalStore<T>(\n\t\t(dispatch) => subscribe(token, dispatch, `use-o:${id}`, store),\n\t\t() => getState(token, store),\n\t\t() => getState(token, store),\n\t)\n}\n\nexport function useJSON<Serializable extends Json.Serializable>(\n\ttoken: MutableAtomToken<any, Serializable>,\n): Serializable {\n\tconst jsonToken = getJsonToken(token)\n\treturn useO(jsonToken)\n}\n"]}
1
+ {"version":3,"sources":["../src/store-context.tsx","../src/store-hooks.ts"],"names":["React"],"mappings":";AACA,SAAS,gBAAgB;AACzB,YAAY,WAAW;AAQtB;AANM,IAAM,eAAqB,oBAAqB,SAAS,KAAK;AAE9D,IAAM,gBAGR,CAAC,EAAE,UAAU,QAAQ,SAAS,MAAM,MACxC,oBAAC,aAAa,UAAb,EAAsB,OAAO,OAAQ,UAAS;;;ACVhD,YAAYA,YAAW;AAEvB,SAAS,UAAU,MAAM,UAAU,YAAY;AAQ/C;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AAIA,SAAS,KACf,OACyD;AACzD,QAAM,QAAc,kBAAW,YAAY;AAC3C,QAAM,SAEI,cAAO,IAAI;AACrB,MAAI,OAAO,YAAY,MAAM;AAC5B,WAAO,UAAU,CAAC,SAAS,SAAS,OAAO,MAAM,KAAK;AAAA,EACvD;AACA,SAAO,OAAO;AACf;AAEO,SAAS,KAAQ,OAAoD;AAC3E,QAAM,QAAc,kBAAW,YAAY;AAC3C,QAAM,KAAW,aAAM;AACvB,SAAa;AAAA,IACZ,CAAC,aAAa,iBAAiB,OAAO,UAAU,SAAS,EAAE,IAAI,KAAK;AAAA,IACpE,MAAM,SAAS,OAAO,KAAK;AAAA,IAC3B,MAAM,SAAS,OAAO,KAAK;AAAA,EAC5B;AACD;AAEO,SAAS,QACf,OACe;AACf,QAAM,YAAY,aAAa,KAAK;AACpC,SAAO,KAAK,SAAS;AACtB;AASO,SAAS,MAAM,OAAoC;AACzD,QAAM,QAAc,kBAAW,YAAY;AAC3C,QAAM,KAAW,aAAM;AACvB,QAAM,WAAW,SAAS,OAAO,KAAK;AACtC,MAAI,aAAa,QAAW;AAC3B,UAAM,OAAO;AAAA,MACZ;AAAA,MACA;AAAA,MACA,MAAM;AAAA,MACN;AAAA,IACD;AACA,WAAO;AAAA,MACN,IAAI;AAAA,MACJ,QAAQ;AAAA,MACR,MAAM,MAAM;AAAA,MAAC;AAAA,MACb,MAAM,MAAM;AAAA,MAAC;AAAA,IACd;AAAA,EACD;AACA,QAAM,OAAa,cAAqB;AAAA,IACvC,IAAI,SAAS;AAAA,IACb,QAAQ,SAAS,QAAQ;AAAA,IACzB,MAAM,MAAM,KAAK,KAAK;AAAA,IACtB,MAAM,MAAM,KAAK,KAAK;AAAA,EACvB,CAAC;AACD,QAAM,WAAiB,mBAAY,MAAM;AACxC,SAAK,QAAQ,KAAK,SAAS;AAC3B,SAAK,QAAQ,SAAS,SAAS,QAAQ;AACvC,WAAO,KAAK;AAAA,EACb,GAAG,CAAC,IAAI,CAAC;AACT,SAAa;AAAA,IACZ,CAAC,aAAa,oBAAoB,OAAO,UAAU,UAAU,EAAE,IAAI,KAAK;AAAA,IACxE;AAAA,IACA;AAAA,EACD;AACD","sourcesContent":["import type { Store } from \"atom.io/internal\"\nimport { IMPLICIT } from \"atom.io/internal\"\nimport * as React from \"react\"\n\nexport const StoreContext = React.createContext<Store>(IMPLICIT.STORE)\n\nexport const StoreProvider: React.FC<{\n\tchildren: React.ReactNode\n\tstore?: Store\n}> = ({ children, store = IMPLICIT.STORE }) => (\n\t<StoreContext.Provider value={store}>{children}</StoreContext.Provider>\n)\n","import * as React from \"react\"\n\nimport { getState, redo, setState, undo } from \"atom.io\"\nimport type {\n\tMutableAtomToken,\n\tReadonlySelectorToken,\n\tStateToken,\n\tTimelineToken,\n} from \"atom.io\"\n\nimport {\n\tgetJsonToken,\n\tsubscribeToState,\n\tsubscribeToTimeline,\n\twithdraw,\n} from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\nimport { StoreContext } from \"./store-context\"\n\nexport function useI<T>(\n\ttoken: StateToken<T>,\n): <New extends T>(next: New | ((old: T) => New)) => void {\n\tconst store = React.useContext(StoreContext)\n\tconst setter: React.MutableRefObject<\n\t\t(<New extends T>(next: New | ((old: T) => New)) => void) | null\n\t> = React.useRef(null)\n\tif (setter.current === null) {\n\t\tsetter.current = (next) => setState(token, next, store)\n\t}\n\treturn setter.current\n}\n\nexport function useO<T>(token: ReadonlySelectorToken<T> | StateToken<T>): T {\n\tconst store = React.useContext(StoreContext)\n\tconst id = React.useId()\n\treturn React.useSyncExternalStore<T>(\n\t\t(dispatch) => subscribeToState(token, dispatch, `use-o:${id}`, store),\n\t\t() => getState(token, store),\n\t\t() => getState(token, store),\n\t)\n}\n\nexport function useJSON<Serializable extends Json.Serializable>(\n\ttoken: MutableAtomToken<any, Serializable>,\n): Serializable {\n\tconst jsonToken = getJsonToken(token)\n\treturn useO(jsonToken)\n}\n\nexport type TimelineMeta = {\n\tat: number\n\tlength: number\n\tundo: () => void\n\tredo: () => void\n}\n\nexport function useTL(token: TimelineToken): TimelineMeta {\n\tconst store = React.useContext(StoreContext)\n\tconst id = React.useId()\n\tconst timeline = withdraw(token, store)\n\tif (timeline === undefined) {\n\t\tstore.logger.error(\n\t\t\t`❌`,\n\t\t\t`timeline`,\n\t\t\ttoken.key,\n\t\t\t`Failed to use timeline because it does not exist`,\n\t\t)\n\t\treturn {\n\t\t\tat: NaN,\n\t\t\tlength: NaN,\n\t\t\tundo: () => {},\n\t\t\tredo: () => {},\n\t\t}\n\t}\n\tconst meta = React.useRef<TimelineMeta>({\n\t\tat: timeline.at,\n\t\tlength: timeline.history.length,\n\t\tundo: () => undo(token),\n\t\tredo: () => redo(token),\n\t})\n\tconst retrieve = React.useCallback(() => {\n\t\tmeta.current.at = timeline.at\n\t\tmeta.current.length = timeline.history.length\n\t\treturn meta.current\n\t}, [meta])\n\treturn React.useSyncExternalStore<TimelineMeta>(\n\t\t(dispatch) => subscribeToTimeline(token, dispatch, `use-tl:${id}`, store),\n\t\tretrieve,\n\t\tretrieve,\n\t)\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import { Store } from 'atom.io/internal';
2
2
  import * as React from 'react';
3
- import { StateToken, ReadonlySelectorToken, MutableAtomToken } from 'atom.io';
3
+ import { StateToken, ReadonlySelectorToken, MutableAtomToken, TimelineToken } from 'atom.io';
4
4
  import { Json } from 'atom.io/json';
5
5
 
6
6
  declare const StoreContext: React.Context<Store>;
@@ -12,5 +12,12 @@ declare const StoreProvider: React.FC<{
12
12
  declare function useI<T>(token: StateToken<T>): <New extends T>(next: New | ((old: T) => New)) => void;
13
13
  declare function useO<T>(token: ReadonlySelectorToken<T> | StateToken<T>): T;
14
14
  declare function useJSON<Serializable extends Json.Serializable>(token: MutableAtomToken<any, Serializable>): Serializable;
15
+ type TimelineMeta = {
16
+ at: number;
17
+ length: number;
18
+ undo: () => void;
19
+ redo: () => void;
20
+ };
21
+ declare function useTL(token: TimelineToken): TimelineMeta;
15
22
 
16
- export { StoreContext, StoreProvider, useI, useJSON, useO };
23
+ export { StoreContext, StoreProvider, type TimelineMeta, useI, useJSON, useO, useTL };
@@ -1,6 +1,6 @@
1
1
  import { Store } from 'atom.io/internal';
2
2
  import * as React from 'react';
3
- import { StateToken, ReadonlySelectorToken, MutableAtomToken } from 'atom.io';
3
+ import { StateToken, ReadonlySelectorToken, MutableAtomToken, TimelineToken } from 'atom.io';
4
4
  import { Json } from 'atom.io/json';
5
5
 
6
6
  declare const StoreContext: React.Context<Store>;
@@ -12,5 +12,12 @@ declare const StoreProvider: React.FC<{
12
12
  declare function useI<T>(token: StateToken<T>): <New extends T>(next: New | ((old: T) => New)) => void;
13
13
  declare function useO<T>(token: ReadonlySelectorToken<T> | StateToken<T>): T;
14
14
  declare function useJSON<Serializable extends Json.Serializable>(token: MutableAtomToken<any, Serializable>): Serializable;
15
+ type TimelineMeta = {
16
+ at: number;
17
+ length: number;
18
+ undo: () => void;
19
+ redo: () => void;
20
+ };
21
+ declare function useTL(token: TimelineToken): TimelineMeta;
15
22
 
16
- export { StoreContext, StoreProvider, useI, useJSON, useO };
23
+ export { StoreContext, StoreProvider, type TimelineMeta, useI, useJSON, useO, useTL };
@@ -1,7 +1,7 @@
1
- import { IMPLICIT, getJsonToken } from 'atom.io/internal';
1
+ import { IMPLICIT, subscribeToState, getJsonToken, withdraw, subscribeToTimeline } from 'atom.io/internal';
2
2
  import * as React2 from 'react';
3
3
  import { jsx } from 'react/jsx-runtime';
4
- import { setState, subscribe, getState } from 'atom.io';
4
+ import { setState, getState, undo, redo } from 'atom.io';
5
5
 
6
6
  // src/store-context.tsx
7
7
  var StoreContext = React2.createContext(IMPLICIT.STORE);
@@ -18,7 +18,7 @@ function useO(token) {
18
18
  const store = React2.useContext(StoreContext);
19
19
  const id = React2.useId();
20
20
  return React2.useSyncExternalStore(
21
- (dispatch) => subscribe(token, dispatch, `use-o:${id}`, store),
21
+ (dispatch) => subscribeToState(token, dispatch, `use-o:${id}`, store),
22
22
  () => getState(token, store),
23
23
  () => getState(token, store)
24
24
  );
@@ -27,7 +27,44 @@ function useJSON(token) {
27
27
  const jsonToken = getJsonToken(token);
28
28
  return useO(jsonToken);
29
29
  }
30
+ function useTL(token) {
31
+ const store = React2.useContext(StoreContext);
32
+ const id = React2.useId();
33
+ const timeline = withdraw(token, store);
34
+ if (timeline === void 0) {
35
+ store.logger.error(
36
+ `\u274C`,
37
+ `timeline`,
38
+ token.key,
39
+ `Failed to use timeline because it does not exist`
40
+ );
41
+ return {
42
+ at: NaN,
43
+ length: NaN,
44
+ undo: () => {
45
+ },
46
+ redo: () => {
47
+ }
48
+ };
49
+ }
50
+ const meta = React2.useRef({
51
+ at: timeline.at,
52
+ length: timeline.history.length,
53
+ undo: () => undo(token),
54
+ redo: () => redo(token)
55
+ });
56
+ const retrieve = React2.useCallback(() => {
57
+ meta.current.at = timeline.at;
58
+ meta.current.length = timeline.history.length;
59
+ return meta.current;
60
+ }, [meta]);
61
+ return React2.useSyncExternalStore(
62
+ (dispatch) => subscribeToTimeline(token, dispatch, `use-tl:${id}`, store),
63
+ retrieve,
64
+ retrieve
65
+ );
66
+ }
30
67
 
31
- export { StoreContext, StoreProvider, useI, useJSON, useO };
68
+ export { StoreContext, StoreProvider, useI, useJSON, useO, useTL };
32
69
  //# sourceMappingURL=out.js.map
33
70
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/store-context.tsx","../src/store-hooks.ts"],"names":["React"],"mappings":";AACA,SAAS,gBAAgB;AACzB,YAAY,WAAW;AAQtB;AANM,IAAM,eAAqB,oBAAqB,SAAS,KAAK;AAE9D,IAAM,gBAGR,CAAC,EAAE,UAAU,QAAQ,SAAS,MAAM,MACxC,oBAAC,aAAa,UAAb,EAAsB,OAAO,OAAQ,UAAS;;;ACVhD,YAAYA,YAAW;AAEvB,SAAS,UAAU,UAAU,iBAAiB;AAO9C,SAAS,oBAAoB;AAItB,SAAS,KACf,OACyD;AACzD,QAAM,QAAc,kBAAW,YAAY;AAC3C,QAAM,SAEI,cAAO,IAAI;AACrB,MAAI,OAAO,YAAY,MAAM;AAC5B,WAAO,UAAU,CAAC,SAAS,SAAS,OAAO,MAAM,KAAK;AAAA,EACvD;AACA,SAAO,OAAO;AACf;AAEO,SAAS,KAAQ,OAAoD;AAC3E,QAAM,QAAc,kBAAW,YAAY;AAC3C,QAAM,KAAW,aAAM;AACvB,SAAa;AAAA,IACZ,CAAC,aAAa,UAAU,OAAO,UAAU,SAAS,EAAE,IAAI,KAAK;AAAA,IAC7D,MAAM,SAAS,OAAO,KAAK;AAAA,IAC3B,MAAM,SAAS,OAAO,KAAK;AAAA,EAC5B;AACD;AAEO,SAAS,QACf,OACe;AACf,QAAM,YAAY,aAAa,KAAK;AACpC,SAAO,KAAK,SAAS;AACtB","sourcesContent":["import type { Store } from \"atom.io/internal\"\nimport { IMPLICIT } from \"atom.io/internal\"\nimport * as React from \"react\"\n\nexport const StoreContext = React.createContext<Store>(IMPLICIT.STORE)\n\nexport const StoreProvider: React.FC<{\n\tchildren: React.ReactNode\n\tstore?: Store\n}> = ({ children, store = IMPLICIT.STORE }) => (\n\t<StoreContext.Provider value={store}>{children}</StoreContext.Provider>\n)\n","import * as React from \"react\"\n\nimport { getState, setState, subscribe } from \"atom.io\"\nimport type {\n\tMutableAtomToken,\n\tReadonlySelectorToken,\n\tStateToken,\n} from \"atom.io\"\n\nimport { getJsonToken } from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\nimport { StoreContext } from \"./store-context\"\n\nexport function useI<T>(\n\ttoken: StateToken<T>,\n): <New extends T>(next: New | ((old: T) => New)) => void {\n\tconst store = React.useContext(StoreContext)\n\tconst setter: React.MutableRefObject<\n\t\t(<New extends T>(next: New | ((old: T) => New)) => void) | null\n\t> = React.useRef(null)\n\tif (setter.current === null) {\n\t\tsetter.current = (next) => setState(token, next, store)\n\t}\n\treturn setter.current\n}\n\nexport function useO<T>(token: ReadonlySelectorToken<T> | StateToken<T>): T {\n\tconst store = React.useContext(StoreContext)\n\tconst id = React.useId()\n\treturn React.useSyncExternalStore<T>(\n\t\t(dispatch) => subscribe(token, dispatch, `use-o:${id}`, store),\n\t\t() => getState(token, store),\n\t\t() => getState(token, store),\n\t)\n}\n\nexport function useJSON<Serializable extends Json.Serializable>(\n\ttoken: MutableAtomToken<any, Serializable>,\n): Serializable {\n\tconst jsonToken = getJsonToken(token)\n\treturn useO(jsonToken)\n}\n"]}
1
+ {"version":3,"sources":["../src/store-context.tsx","../src/store-hooks.ts"],"names":["React"],"mappings":";AACA,SAAS,gBAAgB;AACzB,YAAY,WAAW;AAQtB;AANM,IAAM,eAAqB,oBAAqB,SAAS,KAAK;AAE9D,IAAM,gBAGR,CAAC,EAAE,UAAU,QAAQ,SAAS,MAAM,MACxC,oBAAC,aAAa,UAAb,EAAsB,OAAO,OAAQ,UAAS;;;ACVhD,YAAYA,YAAW;AAEvB,SAAS,UAAU,MAAM,UAAU,YAAY;AAQ/C;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AAIA,SAAS,KACf,OACyD;AACzD,QAAM,QAAc,kBAAW,YAAY;AAC3C,QAAM,SAEI,cAAO,IAAI;AACrB,MAAI,OAAO,YAAY,MAAM;AAC5B,WAAO,UAAU,CAAC,SAAS,SAAS,OAAO,MAAM,KAAK;AAAA,EACvD;AACA,SAAO,OAAO;AACf;AAEO,SAAS,KAAQ,OAAoD;AAC3E,QAAM,QAAc,kBAAW,YAAY;AAC3C,QAAM,KAAW,aAAM;AACvB,SAAa;AAAA,IACZ,CAAC,aAAa,iBAAiB,OAAO,UAAU,SAAS,EAAE,IAAI,KAAK;AAAA,IACpE,MAAM,SAAS,OAAO,KAAK;AAAA,IAC3B,MAAM,SAAS,OAAO,KAAK;AAAA,EAC5B;AACD;AAEO,SAAS,QACf,OACe;AACf,QAAM,YAAY,aAAa,KAAK;AACpC,SAAO,KAAK,SAAS;AACtB;AASO,SAAS,MAAM,OAAoC;AACzD,QAAM,QAAc,kBAAW,YAAY;AAC3C,QAAM,KAAW,aAAM;AACvB,QAAM,WAAW,SAAS,OAAO,KAAK;AACtC,MAAI,aAAa,QAAW;AAC3B,UAAM,OAAO;AAAA,MACZ;AAAA,MACA;AAAA,MACA,MAAM;AAAA,MACN;AAAA,IACD;AACA,WAAO;AAAA,MACN,IAAI;AAAA,MACJ,QAAQ;AAAA,MACR,MAAM,MAAM;AAAA,MAAC;AAAA,MACb,MAAM,MAAM;AAAA,MAAC;AAAA,IACd;AAAA,EACD;AACA,QAAM,OAAa,cAAqB;AAAA,IACvC,IAAI,SAAS;AAAA,IACb,QAAQ,SAAS,QAAQ;AAAA,IACzB,MAAM,MAAM,KAAK,KAAK;AAAA,IACtB,MAAM,MAAM,KAAK,KAAK;AAAA,EACvB,CAAC;AACD,QAAM,WAAiB,mBAAY,MAAM;AACxC,SAAK,QAAQ,KAAK,SAAS;AAC3B,SAAK,QAAQ,SAAS,SAAS,QAAQ;AACvC,WAAO,KAAK;AAAA,EACb,GAAG,CAAC,IAAI,CAAC;AACT,SAAa;AAAA,IACZ,CAAC,aAAa,oBAAoB,OAAO,UAAU,UAAU,EAAE,IAAI,KAAK;AAAA,IACxE;AAAA,IACA;AAAA,EACD;AACD","sourcesContent":["import type { Store } from \"atom.io/internal\"\nimport { IMPLICIT } from \"atom.io/internal\"\nimport * as React from \"react\"\n\nexport const StoreContext = React.createContext<Store>(IMPLICIT.STORE)\n\nexport const StoreProvider: React.FC<{\n\tchildren: React.ReactNode\n\tstore?: Store\n}> = ({ children, store = IMPLICIT.STORE }) => (\n\t<StoreContext.Provider value={store}>{children}</StoreContext.Provider>\n)\n","import * as React from \"react\"\n\nimport { getState, redo, setState, undo } from \"atom.io\"\nimport type {\n\tMutableAtomToken,\n\tReadonlySelectorToken,\n\tStateToken,\n\tTimelineToken,\n} from \"atom.io\"\n\nimport {\n\tgetJsonToken,\n\tsubscribeToState,\n\tsubscribeToTimeline,\n\twithdraw,\n} from \"atom.io/internal\"\nimport type { Json } from \"atom.io/json\"\nimport { StoreContext } from \"./store-context\"\n\nexport function useI<T>(\n\ttoken: StateToken<T>,\n): <New extends T>(next: New | ((old: T) => New)) => void {\n\tconst store = React.useContext(StoreContext)\n\tconst setter: React.MutableRefObject<\n\t\t(<New extends T>(next: New | ((old: T) => New)) => void) | null\n\t> = React.useRef(null)\n\tif (setter.current === null) {\n\t\tsetter.current = (next) => setState(token, next, store)\n\t}\n\treturn setter.current\n}\n\nexport function useO<T>(token: ReadonlySelectorToken<T> | StateToken<T>): T {\n\tconst store = React.useContext(StoreContext)\n\tconst id = React.useId()\n\treturn React.useSyncExternalStore<T>(\n\t\t(dispatch) => subscribeToState(token, dispatch, `use-o:${id}`, store),\n\t\t() => getState(token, store),\n\t\t() => getState(token, store),\n\t)\n}\n\nexport function useJSON<Serializable extends Json.Serializable>(\n\ttoken: MutableAtomToken<any, Serializable>,\n): Serializable {\n\tconst jsonToken = getJsonToken(token)\n\treturn useO(jsonToken)\n}\n\nexport type TimelineMeta = {\n\tat: number\n\tlength: number\n\tundo: () => void\n\tredo: () => void\n}\n\nexport function useTL(token: TimelineToken): TimelineMeta {\n\tconst store = React.useContext(StoreContext)\n\tconst id = React.useId()\n\tconst timeline = withdraw(token, store)\n\tif (timeline === undefined) {\n\t\tstore.logger.error(\n\t\t\t`❌`,\n\t\t\t`timeline`,\n\t\t\ttoken.key,\n\t\t\t`Failed to use timeline because it does not exist`,\n\t\t)\n\t\treturn {\n\t\t\tat: NaN,\n\t\t\tlength: NaN,\n\t\t\tundo: () => {},\n\t\t\tredo: () => {},\n\t\t}\n\t}\n\tconst meta = React.useRef<TimelineMeta>({\n\t\tat: timeline.at,\n\t\tlength: timeline.history.length,\n\t\tundo: () => undo(token),\n\t\tredo: () => redo(token),\n\t})\n\tconst retrieve = React.useCallback(() => {\n\t\tmeta.current.at = timeline.at\n\t\tmeta.current.length = timeline.history.length\n\t\treturn meta.current\n\t}, [meta])\n\treturn React.useSyncExternalStore<TimelineMeta>(\n\t\t(dispatch) => subscribeToTimeline(token, dispatch, `use-tl:${id}`, store),\n\t\tretrieve,\n\t\tretrieve,\n\t)\n}\n"]}
@@ -1 +1 @@
1
- {"inputs":{"src/store-context.tsx":{"bytes":399,"imports":[{"path":"atom.io/internal","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react/jsx-runtime","kind":"import-statement","external":true}],"format":"esm"},"src/store-hooks.ts":{"bytes":1233,"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"atom.io","kind":"import-statement","external":true},{"path":"atom.io/internal","kind":"import-statement","external":true},{"path":"src/store-context.tsx","kind":"import-statement","original":"./store-context"}],"format":"esm"},"src/index.ts":{"bytes":62,"imports":[{"path":"src/store-context.tsx","kind":"import-statement","original":"./store-context"},{"path":"src/store-hooks.ts","kind":"import-statement","original":"./store-hooks"}],"format":"esm"}},"outputs":{"dist/index.cjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":2582},"dist/index.cjs":{"imports":[{"path":"atom.io/internal","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react/jsx-runtime","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"atom.io","kind":"import-statement","external":true},{"path":"atom.io/internal","kind":"import-statement","external":true}],"exports":["StoreContext","StoreProvider","useI","useJSON","useO"],"entryPoint":"src/index.ts","inputs":{"src/store-context.tsx":{"bytesInOutput":308},"src/index.ts":{"bytesInOutput":0},"src/store-hooks.ts":{"bytesInOutput":750}},"bytes":1177}}}
1
+ {"inputs":{"src/store-context.tsx":{"bytes":399,"imports":[{"path":"atom.io/internal","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react/jsx-runtime","kind":"import-statement","external":true}],"format":"esm"},"src/store-hooks.ts":{"bytes":2285,"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"atom.io","kind":"import-statement","external":true},{"path":"atom.io/internal","kind":"import-statement","external":true},{"path":"src/store-context.tsx","kind":"import-statement","original":"./store-context"}],"format":"esm"},"src/index.ts":{"bytes":62,"imports":[{"path":"src/store-context.tsx","kind":"import-statement","original":"./store-context"},{"path":"src/store-hooks.ts","kind":"import-statement","original":"./store-hooks"}],"format":"esm"}},"outputs":{"dist/index.cjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":4490},"dist/index.cjs":{"imports":[{"path":"atom.io/internal","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react/jsx-runtime","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"atom.io","kind":"import-statement","external":true},{"path":"atom.io/internal","kind":"import-statement","external":true}],"exports":["StoreContext","StoreProvider","useI","useJSON","useO","useTL"],"entryPoint":"src/index.ts","inputs":{"src/store-context.tsx":{"bytesInOutput":308},"src/index.ts":{"bytesInOutput":0},"src/store-hooks.ts":{"bytesInOutput":1717}},"bytes":2153}}}
@@ -1 +1 @@
1
- {"inputs":{"src/store-context.tsx":{"bytes":399,"imports":[{"path":"atom.io/internal","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react/jsx-runtime","kind":"import-statement","external":true}],"format":"esm"},"src/store-hooks.ts":{"bytes":1233,"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"atom.io","kind":"import-statement","external":true},{"path":"atom.io/internal","kind":"import-statement","external":true},{"path":"src/store-context.tsx","kind":"import-statement","original":"./store-context"}],"format":"esm"},"src/index.ts":{"bytes":62,"imports":[{"path":"src/store-context.tsx","kind":"import-statement","original":"./store-context"},{"path":"src/store-hooks.ts","kind":"import-statement","original":"./store-hooks"}],"format":"esm"}},"outputs":{"dist/index.js.map":{"imports":[],"exports":[],"inputs":{},"bytes":2582},"dist/index.js":{"imports":[{"path":"atom.io/internal","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react/jsx-runtime","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"atom.io","kind":"import-statement","external":true},{"path":"atom.io/internal","kind":"import-statement","external":true}],"exports":["StoreContext","StoreProvider","useI","useJSON","useO"],"entryPoint":"src/index.ts","inputs":{"src/store-context.tsx":{"bytesInOutput":308},"src/index.ts":{"bytesInOutput":0},"src/store-hooks.ts":{"bytesInOutput":750}},"bytes":1177}}}
1
+ {"inputs":{"src/store-context.tsx":{"bytes":399,"imports":[{"path":"atom.io/internal","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react/jsx-runtime","kind":"import-statement","external":true}],"format":"esm"},"src/store-hooks.ts":{"bytes":2285,"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"atom.io","kind":"import-statement","external":true},{"path":"atom.io/internal","kind":"import-statement","external":true},{"path":"src/store-context.tsx","kind":"import-statement","original":"./store-context"}],"format":"esm"},"src/index.ts":{"bytes":62,"imports":[{"path":"src/store-context.tsx","kind":"import-statement","original":"./store-context"},{"path":"src/store-hooks.ts","kind":"import-statement","original":"./store-hooks"}],"format":"esm"}},"outputs":{"dist/index.js.map":{"imports":[],"exports":[],"inputs":{},"bytes":4490},"dist/index.js":{"imports":[{"path":"atom.io/internal","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react/jsx-runtime","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"atom.io","kind":"import-statement","external":true},{"path":"atom.io/internal","kind":"import-statement","external":true}],"exports":["StoreContext","StoreProvider","useI","useJSON","useO","useTL"],"entryPoint":"src/index.ts","inputs":{"src/store-context.tsx":{"bytesInOutput":308},"src/index.ts":{"bytesInOutput":0},"src/store-hooks.ts":{"bytesInOutput":1717}},"bytes":2153}}}
@@ -1,13 +1,19 @@
1
1
  import * as React from "react"
2
2
 
3
- import { getState, setState, subscribe } from "atom.io"
3
+ import { getState, redo, setState, undo } from "atom.io"
4
4
  import type {
5
5
  MutableAtomToken,
6
6
  ReadonlySelectorToken,
7
7
  StateToken,
8
+ TimelineToken,
8
9
  } from "atom.io"
9
10
 
10
- import { getJsonToken } from "atom.io/internal"
11
+ import {
12
+ getJsonToken,
13
+ subscribeToState,
14
+ subscribeToTimeline,
15
+ withdraw,
16
+ } from "atom.io/internal"
11
17
  import type { Json } from "atom.io/json"
12
18
  import { StoreContext } from "./store-context"
13
19
 
@@ -28,7 +34,7 @@ export function useO<T>(token: ReadonlySelectorToken<T> | StateToken<T>): T {
28
34
  const store = React.useContext(StoreContext)
29
35
  const id = React.useId()
30
36
  return React.useSyncExternalStore<T>(
31
- (dispatch) => subscribe(token, dispatch, `use-o:${id}`, store),
37
+ (dispatch) => subscribeToState(token, dispatch, `use-o:${id}`, store),
32
38
  () => getState(token, store),
33
39
  () => getState(token, store),
34
40
  )
@@ -40,3 +46,46 @@ export function useJSON<Serializable extends Json.Serializable>(
40
46
  const jsonToken = getJsonToken(token)
41
47
  return useO(jsonToken)
42
48
  }
49
+
50
+ export type TimelineMeta = {
51
+ at: number
52
+ length: number
53
+ undo: () => void
54
+ redo: () => void
55
+ }
56
+
57
+ export function useTL(token: TimelineToken): TimelineMeta {
58
+ const store = React.useContext(StoreContext)
59
+ const id = React.useId()
60
+ const timeline = withdraw(token, store)
61
+ if (timeline === undefined) {
62
+ store.logger.error(
63
+ `❌`,
64
+ `timeline`,
65
+ token.key,
66
+ `Failed to use timeline because it does not exist`,
67
+ )
68
+ return {
69
+ at: NaN,
70
+ length: NaN,
71
+ undo: () => {},
72
+ redo: () => {},
73
+ }
74
+ }
75
+ const meta = React.useRef<TimelineMeta>({
76
+ at: timeline.at,
77
+ length: timeline.history.length,
78
+ undo: () => undo(token),
79
+ redo: () => redo(token),
80
+ })
81
+ const retrieve = React.useCallback(() => {
82
+ meta.current.at = timeline.at
83
+ meta.current.length = timeline.history.length
84
+ return meta.current
85
+ }, [meta])
86
+ return React.useSyncExternalStore<TimelineMeta>(
87
+ (dispatch) => subscribeToTimeline(token, dispatch, `use-tl:${id}`, store),
88
+ retrieve,
89
+ retrieve,
90
+ )
91
+ }