atom.io 0.6.8 → 0.7.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 (214) hide show
  1. package/README.md +21 -2
  2. package/dist/index.d.mts +42 -461
  3. package/dist/index.d.ts +42 -461
  4. package/dist/index.js +128 -1792
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +75 -1742
  7. package/dist/index.mjs.map +1 -1
  8. package/internal/dist/index.d.mts +342 -0
  9. package/internal/dist/index.d.ts +342 -0
  10. package/internal/dist/index.js +1873 -0
  11. package/internal/dist/index.js.map +1 -0
  12. package/internal/dist/index.mjs +1798 -0
  13. package/internal/dist/index.mjs.map +1 -0
  14. package/internal/package.json +15 -0
  15. package/internal/src/atom/create-atom.ts +75 -0
  16. package/internal/src/atom/delete-atom.ts +10 -0
  17. package/internal/src/atom/index.ts +3 -0
  18. package/{src/internal → internal/src/atom}/is-default.ts +4 -2
  19. package/internal/src/caching.ts +21 -0
  20. package/internal/src/families/create-atom-family.ts +59 -0
  21. package/internal/src/families/create-readonly-selector-family.ts +45 -0
  22. package/internal/src/families/create-selector-family.ts +67 -0
  23. package/internal/src/families/index.ts +3 -0
  24. package/internal/src/get-state-internal.ts +23 -0
  25. package/internal/src/index.ts +13 -0
  26. package/internal/src/mutable/create-mutable-atom-family.ts +25 -0
  27. package/internal/src/mutable/create-mutable-atom.ts +49 -0
  28. package/internal/src/mutable/get-json-token.ts +22 -0
  29. package/internal/src/mutable/get-update-token.ts +20 -0
  30. package/internal/src/mutable/index.ts +17 -0
  31. package/internal/src/mutable/is-atom-token-mutable.ts +7 -0
  32. package/internal/src/mutable/tracker-family.ts +61 -0
  33. package/internal/src/mutable/tracker.ts +164 -0
  34. package/internal/src/mutable/transceiver.ts +110 -0
  35. package/internal/src/operation.ts +68 -0
  36. package/{src/internal → internal/src}/selector/create-read-write-selector.ts +10 -13
  37. package/{src/internal → internal/src}/selector/create-readonly-selector.ts +9 -8
  38. package/internal/src/selector/create-selector.ts +65 -0
  39. package/{src/internal → internal/src}/selector/index.ts +1 -0
  40. package/internal/src/selector/lookup-selector-sources.ts +20 -0
  41. package/{src/internal → internal/src}/selector/register-selector.ts +13 -9
  42. package/{src/internal → internal/src}/selector/trace-selector-atoms.ts +4 -2
  43. package/{src/internal → internal/src}/selector/update-selector-atoms.ts +4 -3
  44. package/internal/src/set-state/become.ts +10 -0
  45. package/internal/src/set-state/copy-mutable-if-needed.ts +23 -0
  46. package/internal/src/set-state/copy-mutable-in-transaction.ts +59 -0
  47. package/internal/src/set-state/copy-mutable-into-new-store.ts +34 -0
  48. package/internal/src/set-state/emit-update.ts +23 -0
  49. package/internal/src/set-state/evict-downstream.ts +39 -0
  50. package/internal/src/set-state/index.ts +2 -0
  51. package/internal/src/set-state/set-atom-state.ts +38 -0
  52. package/internal/src/set-state/set-selector-state.ts +19 -0
  53. package/internal/src/set-state/set-state-internal.ts +18 -0
  54. package/internal/src/set-state/stow-update.ts +42 -0
  55. package/internal/src/store/deposit.ts +43 -0
  56. package/internal/src/store/index.ts +5 -0
  57. package/internal/src/store/lookup.ts +26 -0
  58. package/internal/src/store/store.ts +154 -0
  59. package/internal/src/store/withdraw-new-family-member.ts +53 -0
  60. package/internal/src/store/withdraw.ts +113 -0
  61. package/internal/src/subject.ts +21 -0
  62. package/internal/src/subscribe/index.ts +1 -0
  63. package/internal/src/subscribe/recall-state.ts +19 -0
  64. package/internal/src/subscribe/subscribe-to-root-atoms.ts +47 -0
  65. package/{src/internal → internal/src}/timeline/add-atom-to-timeline.ts +50 -29
  66. package/internal/src/timeline/index.ts +3 -0
  67. package/{src/internal → internal/src/timeline}/time-travel-internal.ts +6 -6
  68. package/{src/internal → internal/src/timeline}/timeline-internal.ts +20 -12
  69. package/{src/internal → internal/src}/transaction/abort-transaction.ts +1 -1
  70. package/{src/internal → internal/src}/transaction/apply-transaction.ts +25 -18
  71. package/{src/internal → internal/src}/transaction/build-transaction.ts +12 -6
  72. package/{src/internal → internal/src}/transaction/index.ts +3 -2
  73. package/{src/internal → internal/src}/transaction/redo-transaction.ts +4 -5
  74. package/{src/internal → internal/src/transaction}/transaction-internal.ts +16 -13
  75. package/{src/internal → internal/src}/transaction/undo-transaction.ts +4 -5
  76. package/introspection/dist/index.d.mts +12 -260
  77. package/introspection/dist/index.d.ts +12 -260
  78. package/introspection/dist/index.js +125 -140
  79. package/introspection/dist/index.js.map +1 -1
  80. package/introspection/dist/index.mjs +103 -116
  81. package/introspection/dist/index.mjs.map +1 -1
  82. package/{src/introspection → introspection/src}/attach-atom-index.ts +41 -30
  83. package/{src/introspection → introspection/src}/attach-introspection-states.ts +6 -10
  84. package/introspection/src/attach-selector-index.ts +90 -0
  85. package/{src/introspection → introspection/src}/attach-timeline-family.ts +16 -16
  86. package/introspection/src/attach-timeline-index.ts +38 -0
  87. package/introspection/src/attach-transaction-index.ts +40 -0
  88. package/{src/introspection → introspection/src}/attach-transaction-logs.ts +11 -8
  89. package/json/dist/index.d.mts +41 -2
  90. package/json/dist/index.d.ts +41 -2
  91. package/json/dist/index.js +88 -48
  92. package/json/dist/index.js.map +1 -1
  93. package/json/dist/index.mjs +76 -13
  94. package/json/dist/index.mjs.map +1 -1
  95. package/json/src/index.ts +5 -0
  96. package/json/src/select-json-family.ts +35 -0
  97. package/json/src/select-json.ts +22 -0
  98. package/package.json +105 -57
  99. package/react/dist/index.d.mts +9 -17
  100. package/react/dist/index.d.ts +9 -17
  101. package/react/dist/index.js +45 -77
  102. package/react/dist/index.js.map +1 -1
  103. package/react/dist/index.mjs +18 -34
  104. package/react/dist/index.mjs.map +1 -1
  105. package/react/src/store-context.tsx +12 -0
  106. package/react/src/store-hooks.ts +36 -0
  107. package/react-devtools/dist/index.css +1 -1
  108. package/react-devtools/dist/index.css.map +1 -1
  109. package/react-devtools/dist/index.d.mts +199 -230
  110. package/react-devtools/dist/index.d.ts +199 -230
  111. package/react-devtools/dist/index.js +610 -2466
  112. package/react-devtools/dist/index.js.map +1 -1
  113. package/react-devtools/dist/index.mjs +543 -2401
  114. package/react-devtools/dist/index.mjs.map +1 -1
  115. package/{src/react-devtools → react-devtools/src}/AtomIODevtools.tsx +5 -3
  116. package/{src/react-devtools → react-devtools/src}/Button.tsx +2 -3
  117. package/{src/react-devtools → react-devtools/src}/StateEditor.tsx +3 -2
  118. package/{src/react-devtools → react-devtools/src}/StateIndex.tsx +7 -4
  119. package/{src/react-devtools → react-devtools/src}/TimelineIndex.tsx +7 -11
  120. package/{src/react-devtools → react-devtools/src}/TransactionIndex.tsx +4 -4
  121. package/{src/react-devtools → react-devtools/src}/Updates.tsx +9 -4
  122. package/{src/react-devtools → react-devtools/src}/index.ts +5 -5
  123. package/realtime-react/dist/index.d.mts +9 -25
  124. package/realtime-react/dist/index.d.ts +9 -25
  125. package/realtime-react/dist/index.js +75 -193
  126. package/realtime-react/dist/index.js.map +1 -1
  127. package/realtime-react/dist/index.mjs +44 -148
  128. package/realtime-react/dist/index.mjs.map +1 -1
  129. package/realtime-react/src/index.ts +7 -0
  130. package/{src/realtime-react → realtime-react/src}/realtime-context.tsx +3 -4
  131. package/realtime-react/src/use-pull-family-member.ts +15 -0
  132. package/realtime-react/src/use-pull-mutable-family-member.ts +20 -0
  133. package/realtime-react/src/use-pull-mutable.ts +17 -0
  134. package/realtime-react/src/use-pull.ts +15 -0
  135. package/realtime-react/src/use-push.ts +19 -0
  136. package/realtime-react/src/use-server-action.ts +18 -0
  137. package/realtime-testing/dist/index.d.mts +49 -0
  138. package/realtime-testing/dist/index.d.ts +49 -0
  139. package/realtime-testing/dist/index.js +147 -0
  140. package/realtime-testing/dist/index.js.map +1 -0
  141. package/realtime-testing/dist/index.mjs +116 -0
  142. package/realtime-testing/dist/index.mjs.map +1 -0
  143. package/{src/realtime-testing → realtime-testing/src}/setup-realtime-test.tsx +10 -8
  144. package/src/atom.ts +64 -8
  145. package/src/index.ts +36 -29
  146. package/src/logger.ts +7 -7
  147. package/src/selector.ts +5 -5
  148. package/src/silo.ts +49 -43
  149. package/src/subscribe.ts +27 -22
  150. package/src/timeline.ts +9 -4
  151. package/src/transaction.ts +3 -4
  152. package/transceivers/set-rtx/dist/index.d.mts +39 -0
  153. package/transceivers/set-rtx/dist/index.d.ts +39 -0
  154. package/transceivers/set-rtx/dist/index.js +213 -0
  155. package/transceivers/set-rtx/dist/index.js.map +1 -0
  156. package/transceivers/set-rtx/dist/index.mjs +211 -0
  157. package/transceivers/set-rtx/dist/index.mjs.map +1 -0
  158. package/{realtime → transceivers/set-rtx}/package.json +1 -1
  159. package/transceivers/set-rtx/src/index.ts +1 -0
  160. package/transceivers/set-rtx/src/set-rtx.ts +242 -0
  161. package/realtime/dist/index.d.mts +0 -25
  162. package/realtime/dist/index.d.ts +0 -25
  163. package/realtime/dist/index.js +0 -190
  164. package/realtime/dist/index.js.map +0 -1
  165. package/realtime/dist/index.mjs +0 -151
  166. package/realtime/dist/index.mjs.map +0 -1
  167. package/src/internal/atom-internal.ts +0 -54
  168. package/src/internal/families-internal.ts +0 -144
  169. package/src/internal/get.ts +0 -129
  170. package/src/internal/index.ts +0 -15
  171. package/src/internal/operation.ts +0 -139
  172. package/src/internal/selector/lookup-selector-sources.ts +0 -16
  173. package/src/internal/selector-internal.ts +0 -58
  174. package/src/internal/set.ts +0 -99
  175. package/src/internal/store.ts +0 -151
  176. package/src/internal/subscribe-internal.ts +0 -88
  177. package/src/internal/timeline/index.ts +0 -1
  178. package/src/introspection/attach-selector-index.ts +0 -77
  179. package/src/introspection/attach-timeline-index.ts +0 -36
  180. package/src/introspection/attach-transaction-index.ts +0 -38
  181. package/src/json/index.ts +0 -1
  182. package/src/json/select-json.ts +0 -18
  183. package/src/react/store-context.tsx +0 -13
  184. package/src/react/store-hooks.ts +0 -47
  185. package/src/react-explorer/AtomIOExplorer.tsx +0 -218
  186. package/src/react-explorer/explorer-effects.ts +0 -20
  187. package/src/react-explorer/explorer-states.ts +0 -217
  188. package/src/react-explorer/index.ts +0 -23
  189. package/src/react-explorer/space-states.ts +0 -72
  190. package/src/react-explorer/view-states.ts +0 -41
  191. package/src/realtime/README.md +0 -33
  192. package/src/realtime/hook-composition/expose-family.ts +0 -101
  193. package/src/realtime/hook-composition/expose-single.ts +0 -38
  194. package/src/realtime/hook-composition/expose-timeline.ts +0 -60
  195. package/src/realtime/hook-composition/index.ts +0 -12
  196. package/src/realtime/hook-composition/receive-state.ts +0 -29
  197. package/src/realtime/hook-composition/receive-transaction.ts +0 -18
  198. package/src/realtime/index.ts +0 -1
  199. package/src/realtime-react/index.ts +0 -3
  200. package/src/realtime-react/realtime-hooks.ts +0 -39
  201. package/src/realtime-react/realtime-state.ts +0 -10
  202. package/src/realtime-react/use-pull-family-member.ts +0 -26
  203. package/src/realtime-react/use-pull-family.ts +0 -24
  204. package/src/realtime-react/use-pull.ts +0 -24
  205. package/src/realtime-react/use-push.ts +0 -27
  206. package/src/realtime-react/use-server-action.ts +0 -33
  207. package/src/tracker/index.ts +0 -3
  208. package/src/tracker/tracker.ts +0 -61
  209. package/src/web-effects/index.ts +0 -1
  210. package/src/web-effects/storage.ts +0 -30
  211. /package/{src/introspection → introspection/src}/index.ts +0 -0
  212. /package/{src/react → react/src}/index.ts +0 -0
  213. /package/{src/react-devtools → react-devtools/src}/devtools.scss +0 -0
  214. /package/{src/realtime-testing → realtime-testing/src}/index.ts +0 -0
@@ -1,218 +0,0 @@
1
- import type { StoreHooks } from "atom.io/react"
2
- import type { FC, ReactNode } from "react"
3
- import { useEffect } from "react"
4
- import { Link, MemoryRouter, useLocation } from "react-router-dom"
5
-
6
- import { RecoverableErrorBoundary } from "~/packages/hamr/src/react-error-boundary"
7
- import type { WC } from "~/packages/hamr/src/react-json-editor"
8
-
9
- import { attachExplorerState } from "./explorer-states"
10
- import { setState } from ".."
11
- import { runTransaction } from "../transaction"
12
-
13
- export type ExplorerOptions = {
14
- key: string
15
- Components?: {
16
- SpaceWrapper: WC
17
- CloseSpaceButton: FC<{ onClick: () => void }>
18
- }
19
- storeHooks: StoreHooks
20
- }
21
-
22
- const DEFAULT_COMPONENTS: ExplorerOptions[`Components`] = {
23
- SpaceWrapper: ({ children }) => <div>{children}</div>,
24
- CloseSpaceButton: ({ onClick }) => (
25
- <button type="button" onClick={onClick}>
26
- X
27
- </button>
28
- ),
29
- }
30
-
31
- export const composeExplorer = ({
32
- key,
33
- Components,
34
- storeHooks: { useO, useIO },
35
- }: ExplorerOptions): ReturnType<typeof attachExplorerState> & {
36
- Explorer: FC<{ children: ReactNode }>
37
- useSetTitle: (viewId: string) => void
38
- } => {
39
- const { SpaceWrapper, CloseSpaceButton } = {
40
- ...DEFAULT_COMPONENTS,
41
- ...Components,
42
- }
43
-
44
- const state = attachExplorerState(key)
45
-
46
- const {
47
- addSpace,
48
- addView,
49
- allViewsState,
50
- findSpaceFocusedViewState,
51
- findSpaceLayoutNode,
52
- findSpaceViewsState,
53
- findViewFocusedState,
54
- findViewState,
55
- removeSpace,
56
- removeView,
57
- spaceLayoutState,
58
- viewIndexState,
59
- } = state
60
-
61
- const View: FC<{
62
- children: ReactNode
63
- viewId: string
64
- }> = ({ children, viewId }) => {
65
- const location = useLocation()
66
- const viewState = findViewState(viewId)
67
- const [view, setView] = useIO(viewState)
68
- useEffect(() => {
69
- setView((view) => ({ ...view, location }))
70
- }, [location.key])
71
- return (
72
- <div className="view">
73
- <header>
74
- <h1>{view.title}</h1>
75
- <CloseSpaceButton onClick={() => runTransaction(removeView)(viewId)} />
76
- </header>
77
- <main>{children}</main>
78
- <footer>
79
- <nav>
80
- {location.pathname.split(`/`).map((pathPiece, idx, array) =>
81
- pathPiece === `` && idx === 1 ? null : (
82
- <Link
83
- to={array.slice(0, idx + 1).join(`/`)}
84
- key={`${pathPiece}_${viewId}`}
85
- >
86
- {idx === 0 ? `home` : pathPiece}/
87
- </Link>
88
- ),
89
- )}
90
- </nav>
91
- </footer>
92
- </div>
93
- )
94
- }
95
-
96
- const Tab: FC<{ viewId: string; spaceId: string }> = ({ viewId, spaceId }) => {
97
- const view = useO(findViewState(viewId))
98
- const [spaceFocusedView, setSpaceFocusedView] = useIO(
99
- findSpaceFocusedViewState(spaceId),
100
- )
101
- const handleClick = () => setSpaceFocusedView(viewId)
102
- return (
103
- <div
104
- className={`tab ${spaceFocusedView === viewId ? `focused` : ``}`}
105
- onClick={handleClick}
106
- onKeyUp={handleClick}
107
- >
108
- {view.title}
109
- </div>
110
- )
111
- }
112
-
113
- const TabBar: FC<{
114
- spaceId: string
115
- viewIds: string[]
116
- }> = ({ spaceId, viewIds }) => {
117
- return (
118
- <nav className="tab-bar">
119
- {viewIds.map((viewId) => (
120
- <Tab key={viewId} viewId={viewId} spaceId={spaceId} />
121
- ))}
122
- </nav>
123
- )
124
- }
125
-
126
- const Space: FC<{
127
- children: ReactNode
128
- focusedViewId: string
129
- spaceId: string
130
- viewIds: string[]
131
- }> = ({ children, focusedViewId, spaceId, viewIds }) => {
132
- const view = useO(findViewState(focusedViewId))
133
- return (
134
- <div className="space">
135
- <RecoverableErrorBoundary>
136
- <MemoryRouter
137
- initialEntries={view.location ? [view.location.pathname] : []}
138
- >
139
- <TabBar spaceId={spaceId} viewIds={viewIds} />
140
- <View viewId={focusedViewId}>{children}</View>
141
- </MemoryRouter>
142
- </RecoverableErrorBoundary>
143
- </div>
144
- )
145
- }
146
-
147
- const Spaces: FC<{ children: ReactNode; spaceId?: string }> = ({
148
- children,
149
- spaceId = `root`,
150
- }) => {
151
- const spaceLayout = useO(findSpaceLayoutNode(spaceId))
152
- const viewIds = useO(findSpaceViewsState(spaceId))
153
- const focusedViewId = useO(findSpaceFocusedViewState(spaceId))
154
- return (
155
- <div className="spaces">
156
- {spaceLayout.childSpaceIds.length === 0 ? (
157
- focusedViewId ? (
158
- <Space
159
- focusedViewId={focusedViewId}
160
- spaceId={spaceId}
161
- viewIds={viewIds}
162
- >
163
- {children}
164
- </Space>
165
- ) : (
166
- `no view`
167
- )
168
- ) : (
169
- spaceLayout.childSpaceIds.map((childSpaceId) => (
170
- <Spaces key={childSpaceId} spaceId={childSpaceId}>
171
- {children}
172
- </Spaces>
173
- ))
174
- )}
175
- <button
176
- type="button"
177
- onClick={() => runTransaction(addView)({ spaceId })}
178
- >
179
- + View
180
- </button>
181
- <button
182
- type="button"
183
- onClick={() => runTransaction(addSpace)({ parentId: spaceId })}
184
- >
185
- + Space
186
- </button>
187
- </div>
188
- )
189
- }
190
-
191
- const Explorer: FC<{ children: ReactNode }> = ({ children }) => {
192
- return <Spaces>{children}</Spaces>
193
- }
194
-
195
- const useSetTitle = (title: string): void => {
196
- let location: ReturnType<typeof useLocation>
197
- try {
198
- location = useLocation()
199
- } catch (thrown) {
200
- console.warn(
201
- `Failed to set title to "${title}"; useSetTitle must be called within the children of Explorer`,
202
- )
203
- return
204
- }
205
- const views = useO(allViewsState)
206
- const locationView = views.find(
207
- ([, view]) => view.location.key === location.key,
208
- )
209
- const viewId = locationView?.[0] ?? null
210
- useEffect(() => {
211
- if (viewId) {
212
- setState(findViewState(viewId), (v) => ({ ...v, title }))
213
- }
214
- }, [viewId])
215
- }
216
-
217
- return { Explorer, useSetTitle, ...state }
218
- }
@@ -1,20 +0,0 @@
1
- import { isArray } from "~/packages/anvl/src/array"
2
- import { parseJson, stringifyJson } from "~/packages/anvl/src/json"
3
-
4
- import { persistAtom } from "../web-effects"
5
-
6
- export const persistStringSetAtom = persistAtom<Set<string>>(localStorage)({
7
- stringify: (set) => stringifyJson([...set]),
8
- parse: (string) => {
9
- try {
10
- const json = parseJson(string)
11
- const array = isArray((v): v is string => typeof v === `string`)(json)
12
- ? json
13
- : []
14
- return new Set(array)
15
- } catch (thrown) {
16
- console.error(`Error parsing spaceIndexState from localStorage`)
17
- return new Set()
18
- }
19
- },
20
- })
@@ -1,217 +0,0 @@
1
- import { lastOf } from "~/packages/anvl/src/array"
2
- import { now } from "~/packages/anvl/src/id"
3
- import { Join } from "~/packages/anvl/src/join"
4
- import type { Entries } from "~/packages/anvl/src/object"
5
-
6
- import { addToIndex, removeFromIndex } from "."
7
- import {
8
- makeSpaceLayoutNodeFamily,
9
- makeSpaceFamily,
10
- makeSpaceIndex,
11
- makeSpaceLayoutState,
12
- } from "./space-states"
13
- import type { View } from "./view-states"
14
- import {
15
- makeViewFocusedFamily,
16
- makeViewFamily,
17
- makeViewIndex,
18
- } from "./view-states"
19
- import type {
20
- AtomFamily,
21
- AtomToken,
22
- ReadonlySelectorFamily,
23
- SelectorFamily,
24
- Write,
25
- } from ".."
26
- import { selectorFamily, selector, transaction, atom } from ".."
27
- import { persistAtom } from "../web-effects"
28
-
29
- export const makeViewsPerSpaceState = (
30
- key: string,
31
- ): AtomToken<Join<null, `viewId`, `spaceId`>> =>
32
- atom<Join<null, `viewId`, `spaceId`>>({
33
- key: `${key}:views_per_space`,
34
- default: new Join({ relationType: `1:n` }).from(`viewId`).to(`spaceId`),
35
- effects: [
36
- persistAtom<Join<null, `viewId`, `spaceId`>>(localStorage)({
37
- stringify: (index) => JSON.stringify(index.toJSON()),
38
- parse: (json) =>
39
- Join.fromJSON(JSON.parse(json), {
40
- from: `viewId`,
41
- to: `spaceId`,
42
- }),
43
- })(`${key}:views_per_space`),
44
- ],
45
- })
46
-
47
- export const makeSpaceViewsFamily = (
48
- key: string,
49
- viewsPerSpaceState: AtomToken<Join<null, `viewId`, `spaceId`>>,
50
- ): ReadonlySelectorFamily<string[], string> =>
51
- selectorFamily<string[], string>({
52
- key: `${key}:space_views`,
53
- get: (spaceId) => ({ get }) => {
54
- const join = get(viewsPerSpaceState)
55
- const viewIds = join.getRelatedIds(spaceId)
56
- return viewIds
57
- },
58
- })
59
-
60
- export const makeSpaceFocusedViewFamily = (
61
- key: string,
62
- findSpaceViewsState: ReadonlySelectorFamily<string[], string>,
63
- findViewFocusedState: AtomFamily<number, string>,
64
- ): SelectorFamily<string | null, string> =>
65
- selectorFamily<string | null, string>({
66
- key: `${key}:space_focused_view`,
67
- get: (spaceKey) => ({ get }) => {
68
- const views = get(findSpaceViewsState(spaceKey))
69
- const viewsLastFocused = views.map((viewKey): [string, number] => [
70
- viewKey,
71
- get(findViewFocusedState(viewKey)),
72
- ])
73
- const lastFocused = lastOf(viewsLastFocused.sort((a, b) => b[1] - a[1]))
74
- return lastFocused ? lastFocused[0] : null
75
- },
76
- set: (spaceKey) => ({ get, set }, viewKey) => {
77
- if (viewKey === null) {
78
- return
79
- }
80
- const views = get(findSpaceViewsState(spaceKey))
81
- if (views.includes(viewKey)) {
82
- set(findViewFocusedState(viewKey), Date.now())
83
- } else {
84
- console.warn(`View ${viewKey} not found in space ${spaceKey}`)
85
- }
86
- },
87
- })
88
-
89
- type AddViewOptions = { spaceId?: string; path?: string }
90
- type SplitSpaceOptions = { parentId?: string }
91
-
92
- // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
93
- export const attachExplorerState = (key: string) => {
94
- const findSpaceState = makeSpaceFamily(key)
95
- const findViewState = makeViewFamily(key)
96
- const findViewFocusedState = makeViewFocusedFamily(key)
97
- const spaceIndexState = makeSpaceIndex(key)
98
- const spaceLayoutState = makeSpaceLayoutState(key)
99
- const viewIndexState = makeViewIndex(key)
100
- const viewsPerSpaceState = makeViewsPerSpaceState(key)
101
-
102
- const findSpaceLayoutNode = makeSpaceLayoutNodeFamily(key, spaceLayoutState)
103
- const findSpaceViewsState = makeSpaceViewsFamily(key, viewsPerSpaceState)
104
- const findSpaceFocusedViewState = makeSpaceFocusedViewFamily(
105
- key,
106
- findSpaceViewsState,
107
- findViewFocusedState,
108
- )
109
-
110
- const allViewsState = selector<Entries<string, View>>({
111
- key: `${key}:all_views`,
112
- get: ({ get }) => {
113
- const viewIndex = get(viewIndexState)
114
- return [...viewIndex].map((id) => [id, get(findViewState(id))])
115
- },
116
- })
117
-
118
- const writeOperationAddSpace: Write<(options?: SplitSpaceOptions) => string> =
119
- (transactors, { parentId = `root` } = {}) => {
120
- const { set } = transactors
121
- const key = `s-${now()}`
122
- addToIndex(transactors, { indexAtom: spaceIndexState, id: key })
123
- set(spaceLayoutState, (current) =>
124
- current.set({ parent: `parent:${parentId}`, child: key }, { size: 1 }),
125
- )
126
- set(findSpaceState(key), 1)
127
- return key
128
- }
129
-
130
- const writeOperationRemoveSpace: Write<(id: string) => void> = (
131
- transactors,
132
- id,
133
- ) => {
134
- removeFromIndex(transactors, { indexAtom: spaceIndexState, id })
135
- transactors.set(findSpaceState(id), null)
136
- }
137
-
138
- const writeOperationAddView: Write<(options?: AddViewOptions) => void> = (
139
- transactors,
140
- { spaceId: maybeSpaceId, path } = {},
141
- ) => {
142
- const { get, set } = transactors
143
- const id = `v-${now()}`
144
-
145
- addToIndex(transactors, { indexAtom: viewIndexState, id })
146
- set(
147
- findViewState(id),
148
- (current): View => ({
149
- ...current,
150
- location: {
151
- ...current.location,
152
- pathname: path ?? `/`,
153
- },
154
- }),
155
- )
156
- const spaceId =
157
- maybeSpaceId ??
158
- lastOf([...get(spaceIndexState)]) ??
159
- writeOperationAddSpace(transactors)
160
- set(findViewFocusedState(id), Date.now())
161
-
162
- set(viewsPerSpaceState, (current) => current.set({ spaceId, viewId: id }))
163
- set(findViewFocusedState(id), Date.now())
164
- }
165
-
166
- const writeOperationRemoveView: Write<(viewId: string) => void> = (
167
- transactors,
168
- viewId,
169
- ) => {
170
- const { set } = transactors
171
- removeFromIndex(transactors, { indexAtom: viewIndexState, id: viewId })
172
- set(viewsPerSpaceState, (current) => current.remove({ viewId }))
173
- set(findViewState(viewId), null)
174
- }
175
-
176
- const addView = transaction<(options?: AddViewOptions) => void>({
177
- key: `${key}:add_view`,
178
- do: writeOperationAddView,
179
- })
180
-
181
- const removeView = transaction({
182
- key: `${key}:remove_view`,
183
- do: writeOperationRemoveView,
184
- })
185
-
186
- const addSpace = transaction({
187
- key: `${key}:add_space`,
188
- do: writeOperationAddSpace,
189
- })
190
-
191
- const removeSpace = transaction({
192
- key: `${key}:remove_space`,
193
- do: writeOperationRemoveSpace,
194
- })
195
-
196
- return {
197
- addSpace,
198
- addView,
199
- allViewsState,
200
- findSpaceLayoutNode,
201
- findSpaceFocusedViewState,
202
- findSpaceState,
203
- findSpaceViewsState,
204
- findViewState,
205
- findViewFocusedState,
206
- removeSpace,
207
- removeView,
208
- spaceIndexState,
209
- spaceLayoutState,
210
- viewIndexState,
211
- viewsPerSpaceState,
212
- writeOperationAddSpace,
213
- writeOperationAddView,
214
- writeOperationRemoveSpace,
215
- writeOperationRemoveView,
216
- }
217
- }
@@ -1,23 +0,0 @@
1
- import type { AtomToken, Write } from "atom.io"
2
-
3
- export * from "./AtomIOExplorer"
4
-
5
- export type AtomicIndexOptions = {
6
- indexAtom: AtomToken<Set<string>>
7
- id: string
8
- }
9
-
10
- export const addToIndex: Write<(options: AtomicIndexOptions) => void> = (
11
- { set },
12
- { indexAtom, id },
13
- ): void => set(indexAtom, (currentSet) => new Set(currentSet).add(id))
14
-
15
- export const removeFromIndex: Write<(options: AtomicIndexOptions) => void> = (
16
- { set },
17
- { indexAtom, id },
18
- ): void =>
19
- set(indexAtom, (currentSet) => {
20
- const newSet = new Set(currentSet)
21
- newSet.delete(id)
22
- return newSet
23
- })
@@ -1,72 +0,0 @@
1
- import { Join } from "~/packages/anvl/src/join"
2
- import { parseJson, stringifyJson } from "~/packages/anvl/src/json"
3
- import { hasExactProperties } from "~/packages/anvl/src/object"
4
-
5
- import { persistStringSetAtom } from "./explorer-effects"
6
- import type { AtomToken, ReadonlySelectorFamily } from ".."
7
- import { SelectorFamily, selectorFamily } from ".."
8
- import type { AtomFamily } from "../atom"
9
- import { atom, atomFamily } from "../atom"
10
- import { lazyLocalStorageEffect, persistAtom } from "../web-effects"
11
-
12
- export const makeSpaceIndex = (key: string): AtomToken<Set<string>> =>
13
- atom<Set<string>>({
14
- key: `${key}:space_index`,
15
- default: new Set([`root`]),
16
- effects: [persistStringSetAtom(`${key}:space_index`)],
17
- })
18
-
19
- export const makeSpaceLayoutState = (
20
- key: string,
21
- ): AtomToken<Join<{ size: number }, `parent`, `child`>> =>
22
- atom({
23
- key: `${key}:space_layout`,
24
- default: new Join<{ size: number }>({ relationType: `1:n` })
25
- .from(`parent`)
26
- .to(`child`),
27
- effects: [
28
- persistAtom<Join<{ size: number }, `parent`, `child`>>(localStorage)({
29
- stringify: (join) => stringifyJson(join.toJSON()),
30
- parse: (string) => {
31
- try {
32
- const json = parseJson(string)
33
- const join = Join.fromJSON(json, {
34
- isContent: hasExactProperties({
35
- size: (v): v is number => typeof v === `number`,
36
- }),
37
- from: `parent`,
38
- to: `child`,
39
- })
40
- return join
41
- } catch (thrown) {
42
- console.error(`Error parsing spaceLayoutState from localStorage`)
43
- return new Join({ relationType: `1:n` })
44
- }
45
- },
46
- })(`${key}:space_layout`),
47
- ],
48
- })
49
-
50
- export const makeSpaceLayoutNodeFamily = (
51
- key: string,
52
- spaceLayoutState: AtomToken<Join<{ size: number }, `parent`, `child`>>,
53
- ): ReadonlySelectorFamily<{ childSpaceIds: string[]; size: number }, string> =>
54
- selectorFamily<{ childSpaceIds: string[]; size: number }, string>({
55
- key: `${key}:explorer_space`,
56
- get: (me) => ({ get }) => {
57
- const join = get(spaceLayoutState)
58
- const myFollowers = join.getRelatedIds(`parent:${me}`)
59
- const myLeader = join.getRelatedId(me)
60
- const { size } = myLeader
61
- ? join.getContent(myLeader, me) ?? { size: NaN }
62
- : { size: NaN }
63
- return { childSpaceIds: myFollowers, size }
64
- },
65
- })
66
-
67
- export const makeSpaceFamily = (key: string): AtomFamily<number, string> =>
68
- atomFamily<number, string>({
69
- key: `${key}:space`,
70
- default: 1,
71
- effects: (subKey) => [lazyLocalStorageEffect(`${key}:${subKey}`)],
72
- })
@@ -1,41 +0,0 @@
1
- import type { Location } from "react-router-dom"
2
-
3
- import { persistStringSetAtom } from "./explorer-effects"
4
- import type { AtomToken } from ".."
5
- import type { AtomFamily } from "../atom"
6
- import { atom, atomFamily } from "../atom"
7
- import { lazyLocalStorageEffect } from "../web-effects"
8
-
9
- export type View = {
10
- title: string
11
- location: Omit<Location, `state`>
12
- }
13
-
14
- export const makeViewFamily = (key: string): AtomFamily<View, string> =>
15
- atomFamily<View, string>({
16
- key: `${key}:view`,
17
- default: {
18
- title: ``,
19
- location: {
20
- pathname: ``,
21
- search: ``,
22
- hash: ``,
23
- key: ``,
24
- },
25
- },
26
- effects: (subKey) => [lazyLocalStorageEffect(`${key}:${subKey}`)],
27
- })
28
-
29
- export const makeViewIndex = (key: string): AtomToken<Set<string>> =>
30
- atom<Set<string>>({
31
- key: `${key}:view_index`,
32
- default: new Set(),
33
- effects: [persistStringSetAtom(`${key}:view_index`)],
34
- })
35
-
36
- export const makeViewFocusedFamily = (key: string): AtomFamily<number, string> =>
37
- atomFamily<number, string>({
38
- key: `${key}:view_focused`,
39
- default: 0,
40
- effects: (subKey) => [lazyLocalStorageEffect(`${key}:${subKey}`)],
41
- })
@@ -1,33 +0,0 @@
1
- # CLIENT ACTS AND REPORTS
2
- - [x] input event fires
3
- - [x] event handler runs transaction
4
- - [x] client store updates optimistically
5
- - [ ] on success
6
- - [ ] client generates transactionId and optimistic TransactionUpdate
7
- - [ ] client pushes TransactionUpdate to TimelineData.history
8
- - [ ] client sets TransactionUpdate in optimisticTransactions map by transactionId
9
- - [ ] client emits TransactionRequest { key, params, transactionId }
10
-
11
- # SERVER VALIDATES, INTEGRATES, AND BROADCASTS
12
- ## use
13
- - [x] server receives TransactionRequest
14
- - `{ key, params, transactionId }`
15
- - [ ] verify `transactionId` is unique
16
- - [ ] server adds timestamp to `TransactionRequest`
17
- - `{ key, params, transactionId, timestamp }`
18
- - [ ] server runs transaction, computing `TransactionUpdate` in the process
19
- - [ ] emit `TransactionUpdate`
20
- - `{ key, params, transactionId, timestamp, atomUpdates, output }`
21
- - [ ] server adds `TransactionUpdate` to TimelineData.history
22
-
23
- # CLIENT BEHOLDS AND REACTS
24
- - [ ] client receives official TransactionUpdate
25
- - [ ] client retrieves its own TransactionUpdate from optimisticTransactions map
26
- - [ ] client compares official and optimistic TransactionUpdates
27
- - [ ] (stringify atomUpdates and compare strict)
28
- - [ ] if match, client removes TransactionUpdate from optimisticTransactions map
29
- - [ ] if mismatch
30
- - [ ] client undoes timeline until it finds its own TransactionUpdate
31
- - [ ] client replaces its own TransactionUpdate with official TransactionUpdate
32
- - [ ] client removes its own TransactionUpdate from optimisticTransactions map
33
- - [ ] client redoes timeline until it reaches the "HEAD"