atom.io 0.6.7 → 0.6.9
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.
- package/dist/index.d.mts +241 -263
- package/dist/index.d.ts +241 -263
- package/dist/index.js +28 -1911
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5 -1871
- package/dist/index.mjs.map +1 -1
- package/introspection/dist/index.d.mts +121 -176
- package/introspection/dist/index.d.ts +121 -176
- package/introspection/dist/index.js +6 -346
- package/introspection/dist/index.js.map +1 -1
- package/introspection/dist/index.mjs +5 -324
- package/introspection/dist/index.mjs.map +1 -1
- package/json/dist/index.d.mts +37 -8
- package/json/dist/index.d.ts +37 -8
- package/json/dist/index.js +31 -48
- package/json/dist/index.js.map +1 -1
- package/json/dist/index.mjs +6 -14
- package/json/dist/index.mjs.map +1 -1
- package/package.json +30 -14
- package/react/dist/index.js +34 -83
- package/react/dist/index.js.map +1 -1
- package/react/dist/index.mjs +7 -43
- package/react/dist/index.mjs.map +1 -1
- package/react-devtools/dist/index.css +1 -42
- package/react-devtools/dist/index.css.map +1 -1
- package/react-devtools/dist/index.d.mts +128 -193
- package/react-devtools/dist/index.d.ts +128 -193
- package/react-devtools/dist/index.js +56 -4154
- package/react-devtools/dist/index.js.map +1 -1
- package/react-devtools/dist/index.mjs +19 -4117
- package/react-devtools/dist/index.mjs.map +1 -1
- package/realtime/dist/index.d.mts +7 -11
- package/realtime/dist/index.d.ts +7 -11
- package/realtime/dist/index.js +26 -185
- package/realtime/dist/index.js.map +1 -1
- package/realtime/dist/index.mjs +4 -149
- package/realtime/dist/index.mjs.map +1 -1
- package/realtime-react/dist/index.d.mts +12 -16
- package/realtime-react/dist/index.d.ts +12 -16
- package/realtime-react/dist/index.js +41 -214
- package/realtime-react/dist/index.js.map +1 -1
- package/realtime-react/dist/index.mjs +9 -169
- package/realtime-react/dist/index.mjs.map +1 -1
- package/src/atom.ts +7 -6
- package/src/index.ts +12 -9
- package/src/logger.ts +5 -5
- package/src/selector.ts +16 -14
- package/src/silo.ts +36 -39
- package/src/subscribe.ts +25 -20
- package/src/timeline.ts +9 -4
- package/src/transaction.ts +3 -4
- package/src/internal/atom-internal.ts +0 -54
- package/src/internal/families-internal.ts +0 -141
- package/src/internal/get.ts +0 -129
- package/src/internal/index.ts +0 -15
- package/src/internal/is-default.ts +0 -35
- package/src/internal/operation.ts +0 -139
- package/src/internal/selector/create-read-write-selector.ts +0 -66
- package/src/internal/selector/create-readonly-selector.ts +0 -46
- package/src/internal/selector/index.ts +0 -4
- package/src/internal/selector/lookup-selector-sources.ts +0 -16
- package/src/internal/selector/register-selector.ts +0 -57
- package/src/internal/selector/trace-selector-atoms.ts +0 -43
- package/src/internal/selector/update-selector-atoms.ts +0 -33
- package/src/internal/selector-internal.ts +0 -58
- package/src/internal/set.ts +0 -99
- package/src/internal/store.ts +0 -151
- package/src/internal/subject.ts +0 -24
- package/src/internal/subscribe-internal.ts +0 -88
- package/src/internal/time-travel-internal.ts +0 -91
- package/src/internal/timeline/add-atom-to-timeline.ts +0 -168
- package/src/internal/timeline/index.ts +0 -1
- package/src/internal/timeline-internal.ts +0 -107
- package/src/internal/transaction/abort-transaction.ts +0 -12
- package/src/internal/transaction/apply-transaction.ts +0 -57
- package/src/internal/transaction/build-transaction.ts +0 -33
- package/src/internal/transaction/index.ts +0 -25
- package/src/internal/transaction/redo-transaction.ts +0 -23
- package/src/internal/transaction/undo-transaction.ts +0 -23
- package/src/internal/transaction-internal.ts +0 -61
- package/src/introspection/attach-atom-index.ts +0 -73
- package/src/introspection/attach-introspection-states.ts +0 -42
- package/src/introspection/attach-selector-index.ts +0 -77
- package/src/introspection/attach-timeline-family.ts +0 -59
- package/src/introspection/attach-timeline-index.ts +0 -36
- package/src/introspection/attach-transaction-index.ts +0 -38
- package/src/introspection/attach-transaction-logs.ts +0 -40
- package/src/introspection/index.ts +0 -20
- package/src/json/index.ts +0 -1
- package/src/json/select-json.ts +0 -18
- package/src/react/index.ts +0 -2
- package/src/react/store-context.tsx +0 -13
- package/src/react/store-hooks.ts +0 -47
- package/src/react-devtools/AtomIODevtools.tsx +0 -107
- package/src/react-devtools/Button.tsx +0 -24
- package/src/react-devtools/StateEditor.tsx +0 -70
- package/src/react-devtools/StateIndex.tsx +0 -153
- package/src/react-devtools/TimelineIndex.tsx +0 -92
- package/src/react-devtools/TransactionIndex.tsx +0 -70
- package/src/react-devtools/Updates.tsx +0 -145
- package/src/react-devtools/devtools.scss +0 -311
- package/src/react-devtools/index.ts +0 -72
- package/src/react-explorer/AtomIOExplorer.tsx +0 -218
- package/src/react-explorer/explorer-effects.ts +0 -20
- package/src/react-explorer/explorer-states.ts +0 -217
- package/src/react-explorer/index.ts +0 -23
- package/src/react-explorer/space-states.ts +0 -72
- package/src/react-explorer/view-states.ts +0 -41
- package/src/realtime/README.md +0 -33
- package/src/realtime/hook-composition/expose-family.ts +0 -101
- package/src/realtime/hook-composition/expose-single.ts +0 -38
- package/src/realtime/hook-composition/expose-timeline.ts +0 -60
- package/src/realtime/hook-composition/index.ts +0 -12
- package/src/realtime/hook-composition/receive-state.ts +0 -29
- package/src/realtime/hook-composition/receive-transaction.ts +0 -18
- package/src/realtime/index.ts +0 -1
- package/src/realtime-react/index.ts +0 -3
- package/src/realtime-react/realtime-context.tsx +0 -30
- package/src/realtime-react/realtime-hooks.ts +0 -39
- package/src/realtime-react/realtime-state.ts +0 -10
- package/src/realtime-react/use-pull-family-member.ts +0 -26
- package/src/realtime-react/use-pull-family.ts +0 -24
- package/src/realtime-react/use-pull.ts +0 -22
- package/src/realtime-react/use-push.ts +0 -25
- package/src/realtime-react/use-server-action.ts +0 -33
- package/src/realtime-testing/index.ts +0 -1
- package/src/realtime-testing/setup-realtime-test.tsx +0 -159
- package/src/web-effects/index.ts +0 -1
- package/src/web-effects/storage.ts +0 -30
|
@@ -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
|
-
})
|
package/src/realtime/README.md
DELETED
|
@@ -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"
|