atom.io 0.6.9 → 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 (169) hide show
  1. package/README.md +21 -2
  2. package/dist/index.d.mts +34 -421
  3. package/dist/index.d.ts +34 -421
  4. package/dist/index.js +248 -23
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +209 -4
  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/internal/src/atom/is-default.ts +37 -0
  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/internal/src/selector/create-read-write-selector.ts +65 -0
  37. package/internal/src/selector/create-readonly-selector.ts +49 -0
  38. package/internal/src/selector/create-selector.ts +65 -0
  39. package/internal/src/selector/index.ts +5 -0
  40. package/internal/src/selector/lookup-selector-sources.ts +20 -0
  41. package/internal/src/selector/register-selector.ts +61 -0
  42. package/internal/src/selector/trace-selector-atoms.ts +45 -0
  43. package/internal/src/selector/update-selector-atoms.ts +34 -0
  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/internal/src/timeline/add-atom-to-timeline.ts +189 -0
  66. package/internal/src/timeline/index.ts +3 -0
  67. package/internal/src/timeline/time-travel-internal.ts +91 -0
  68. package/internal/src/timeline/timeline-internal.ts +115 -0
  69. package/internal/src/transaction/abort-transaction.ts +12 -0
  70. package/internal/src/transaction/apply-transaction.ts +64 -0
  71. package/internal/src/transaction/build-transaction.ts +39 -0
  72. package/internal/src/transaction/index.ts +26 -0
  73. package/internal/src/transaction/redo-transaction.ts +22 -0
  74. package/internal/src/transaction/transaction-internal.ts +64 -0
  75. package/internal/src/transaction/undo-transaction.ts +22 -0
  76. package/introspection/dist/index.d.mts +3 -197
  77. package/introspection/dist/index.d.ts +3 -197
  78. package/introspection/dist/index.js +329 -4
  79. package/introspection/dist/index.js.map +1 -1
  80. package/introspection/dist/index.mjs +310 -4
  81. package/introspection/dist/index.mjs.map +1 -1
  82. package/introspection/src/attach-atom-index.ts +84 -0
  83. package/introspection/src/attach-introspection-states.ts +38 -0
  84. package/introspection/src/attach-selector-index.ts +90 -0
  85. package/introspection/src/attach-timeline-family.ts +59 -0
  86. package/introspection/src/attach-timeline-index.ts +38 -0
  87. package/introspection/src/attach-transaction-index.ts +40 -0
  88. package/introspection/src/attach-transaction-logs.ts +43 -0
  89. package/introspection/src/index.ts +20 -0
  90. package/json/dist/index.d.mts +10 -2
  91. package/json/dist/index.d.ts +10 -2
  92. package/json/dist/index.js +83 -26
  93. package/json/dist/index.js.map +1 -1
  94. package/json/dist/index.mjs +74 -3
  95. package/json/dist/index.mjs.map +1 -1
  96. package/json/src/index.ts +5 -0
  97. package/json/src/select-json-family.ts +35 -0
  98. package/json/src/select-json.ts +22 -0
  99. package/package.json +103 -63
  100. package/react/dist/index.d.mts +9 -17
  101. package/react/dist/index.d.ts +9 -17
  102. package/react/dist/index.js +44 -27
  103. package/react/dist/index.js.map +1 -1
  104. package/react/dist/index.mjs +24 -4
  105. package/react/dist/index.mjs.map +1 -1
  106. package/react/src/index.ts +2 -0
  107. package/react/src/store-context.tsx +12 -0
  108. package/react/src/store-hooks.ts +36 -0
  109. package/react-devtools/dist/index.css +50 -1
  110. package/react-devtools/dist/index.css.map +1 -1
  111. package/react-devtools/dist/index.d.mts +104 -71
  112. package/react-devtools/dist/index.d.ts +104 -71
  113. package/react-devtools/dist/index.js +2806 -44
  114. package/react-devtools/dist/index.js.map +1 -1
  115. package/react-devtools/dist/index.mjs +2775 -10
  116. package/react-devtools/dist/index.mjs.map +1 -1
  117. package/react-devtools/src/AtomIODevtools.tsx +109 -0
  118. package/react-devtools/src/Button.tsx +23 -0
  119. package/react-devtools/src/StateEditor.tsx +75 -0
  120. package/react-devtools/src/StateIndex.tsx +159 -0
  121. package/react-devtools/src/TimelineIndex.tsx +88 -0
  122. package/react-devtools/src/TransactionIndex.tsx +70 -0
  123. package/react-devtools/src/Updates.tsx +150 -0
  124. package/react-devtools/src/devtools.scss +310 -0
  125. package/react-devtools/src/index.ts +72 -0
  126. package/realtime-react/dist/index.d.mts +8 -22
  127. package/realtime-react/dist/index.d.ts +8 -22
  128. package/realtime-react/dist/index.js +87 -32
  129. package/realtime-react/dist/index.js.map +1 -1
  130. package/realtime-react/dist/index.mjs +62 -6
  131. package/realtime-react/dist/index.mjs.map +1 -1
  132. package/realtime-react/src/index.ts +7 -0
  133. package/realtime-react/src/realtime-context.tsx +29 -0
  134. package/realtime-react/src/use-pull-family-member.ts +15 -0
  135. package/realtime-react/src/use-pull-mutable-family-member.ts +20 -0
  136. package/realtime-react/src/use-pull-mutable.ts +17 -0
  137. package/realtime-react/src/use-pull.ts +15 -0
  138. package/realtime-react/src/use-push.ts +19 -0
  139. package/realtime-react/src/use-server-action.ts +18 -0
  140. package/realtime-testing/dist/index.d.mts +49 -0
  141. package/realtime-testing/dist/index.d.ts +49 -0
  142. package/realtime-testing/dist/index.js +147 -0
  143. package/realtime-testing/dist/index.js.map +1 -0
  144. package/realtime-testing/dist/index.mjs +116 -0
  145. package/realtime-testing/dist/index.mjs.map +1 -0
  146. package/realtime-testing/src/index.ts +1 -0
  147. package/realtime-testing/src/setup-realtime-test.tsx +161 -0
  148. package/src/atom.ts +64 -9
  149. package/src/index.ts +36 -32
  150. package/src/logger.ts +3 -3
  151. package/src/selector.ts +3 -3
  152. package/src/silo.ts +29 -20
  153. package/src/subscribe.ts +3 -3
  154. package/src/timeline.ts +2 -2
  155. package/transceivers/set-rtx/dist/index.d.mts +39 -0
  156. package/transceivers/set-rtx/dist/index.d.ts +39 -0
  157. package/transceivers/set-rtx/dist/index.js +213 -0
  158. package/transceivers/set-rtx/dist/index.js.map +1 -0
  159. package/transceivers/set-rtx/dist/index.mjs +211 -0
  160. package/transceivers/set-rtx/dist/index.mjs.map +1 -0
  161. package/{realtime → transceivers/set-rtx}/package.json +1 -1
  162. package/transceivers/set-rtx/src/index.ts +1 -0
  163. package/transceivers/set-rtx/src/set-rtx.ts +242 -0
  164. package/realtime/dist/index.d.mts +0 -23
  165. package/realtime/dist/index.d.ts +0 -23
  166. package/realtime/dist/index.js +0 -32
  167. package/realtime/dist/index.js.map +0 -1
  168. package/realtime/dist/index.mjs +0 -7
  169. package/realtime/dist/index.mjs.map +0 -1
@@ -0,0 +1,109 @@
1
+ import { useI, useO } from "atom.io/react"
2
+ import { LayoutGroup, motion, spring } from "framer-motion"
3
+ import { useRef } from "react"
4
+
5
+ import {
6
+ atomIndex,
7
+ devtoolsAreOpenState,
8
+ devtoolsViewOptionsState,
9
+ devtoolsViewSelectionState,
10
+ selectorIndex,
11
+ } from "."
12
+ import { StateIndex } from "./StateIndex"
13
+ import { TimelineIndex } from "./TimelineIndex"
14
+ import { TransactionIndex } from "./TransactionIndex"
15
+
16
+ import "./devtools.scss"
17
+
18
+ export const AtomIODevtools = (): JSX.Element => {
19
+ const constraintsRef = useRef(null)
20
+
21
+ const setDevtoolsAreOpen = useI(devtoolsAreOpenState)
22
+ const devtoolsAreOpen = useO(devtoolsAreOpenState)
23
+ const setDevtoolsView = useI(devtoolsViewSelectionState)
24
+ const devtoolsView = useO(devtoolsViewSelectionState)
25
+ const devtoolsViewOptions = useO(devtoolsViewOptionsState)
26
+
27
+ const mouseHasMoved = useRef(false)
28
+
29
+ return (
30
+ <>
31
+ <motion.span
32
+ ref={constraintsRef}
33
+ className="atom_io_devtools_zone"
34
+ style={{
35
+ position: `fixed`,
36
+ top: 0,
37
+ left: 0,
38
+ right: 0,
39
+ bottom: 0,
40
+ pointerEvents: `none`,
41
+ }}
42
+ />
43
+ <motion.main
44
+ drag
45
+ dragConstraints={constraintsRef}
46
+ className="atom_io_devtools"
47
+ transition={spring}
48
+ style={
49
+ devtoolsAreOpen
50
+ ? {}
51
+ : {
52
+ backgroundColor: `#0000`,
53
+ borderColor: `#0000`,
54
+ maxHeight: 28,
55
+ maxWidth: 33,
56
+ }
57
+ }
58
+ >
59
+ {devtoolsAreOpen ? (
60
+ <>
61
+ <motion.header>
62
+ <h1>atom.io</h1>
63
+ <nav>
64
+ {devtoolsViewOptions.map((viewOption) => (
65
+ <button
66
+ key={viewOption}
67
+ type="button"
68
+ className={viewOption === devtoolsView ? `active` : ``}
69
+ onClick={() => setDevtoolsView(viewOption)}
70
+ disabled={viewOption === devtoolsView}
71
+ >
72
+ {viewOption}
73
+ </button>
74
+ ))}
75
+ </nav>
76
+ </motion.header>
77
+ <motion.main>
78
+ <LayoutGroup>
79
+ {devtoolsView === `atoms` ? (
80
+ <StateIndex tokenIndex={atomIndex} />
81
+ ) : devtoolsView === `selectors` ? (
82
+ <StateIndex tokenIndex={selectorIndex} />
83
+ ) : devtoolsView === `transactions` ? (
84
+ <TransactionIndex />
85
+ ) : devtoolsView === `timelines` ? (
86
+ <TimelineIndex />
87
+ ) : null}
88
+ </LayoutGroup>
89
+ </motion.main>
90
+ </>
91
+ ) : null}
92
+ <footer>
93
+ <button
94
+ type="button"
95
+ onMouseDown={() => (mouseHasMoved.current = false)}
96
+ onMouseMove={() => (mouseHasMoved.current = true)}
97
+ onMouseUp={() => {
98
+ if (!mouseHasMoved.current) {
99
+ setDevtoolsAreOpen((open) => !open)
100
+ }
101
+ }}
102
+ >
103
+ 👁‍🗨
104
+ </button>
105
+ </footer>
106
+ </motion.main>
107
+ </>
108
+ )
109
+ }
@@ -0,0 +1,23 @@
1
+ import type { Modify } from "atom.io/internal"
2
+ import type { FC } from "react"
3
+
4
+ export const OpenClose: FC<{
5
+ isOpen: boolean
6
+ setIsOpen: (next: Modify<boolean> | boolean) => void
7
+ disabled?: boolean
8
+ }> = ({ isOpen, setIsOpen, disabled }) => {
9
+ return (
10
+ <button
11
+ type="button"
12
+ className={`carat ${isOpen ? `open` : `closed`}`}
13
+ onClick={() => setIsOpen((isOpen) => !isOpen)}
14
+ disabled={disabled}
15
+ >
16
+
17
+ </button>
18
+ )
19
+ }
20
+
21
+ export const button = {
22
+ OpenClose,
23
+ }
@@ -0,0 +1,75 @@
1
+ import type { ReadonlySelectorToken, StateToken } from "atom.io"
2
+ import { useI, useO } from "atom.io/react"
3
+ import type { FC } from "react"
4
+
5
+ import { fallback } from "~/packages/anvl/src/function"
6
+ import { Join } from "~/packages/anvl/src/join"
7
+ import { isJson } from "~/packages/anvl/src/refinement/refine-json"
8
+ import { RelationEditor } from "~/packages/hamr/src/react-data-designer"
9
+ import { ElasticInput } from "~/packages/hamr/src/react-elastic-input"
10
+ import { JsonEditor } from "~/packages/hamr/src/react-json-editor"
11
+
12
+ export const StateEditor: FC<{
13
+ token: StateToken<unknown>
14
+ }> = ({ token }) => {
15
+ const set = useI(token)
16
+ const data = useO(token)
17
+ return isJson(data) ? (
18
+ <JsonEditor data={data} set={set} schema={true} />
19
+ ) : data instanceof Join ? (
20
+ <RelationEditor data={data} set={set} />
21
+ ) : (
22
+ <div className="json_editor">
23
+ <ElasticInput
24
+ value={
25
+ data instanceof Set
26
+ ? `Set { ${JSON.stringify([...data]).slice(1, -1)} }`
27
+ : data instanceof Map
28
+ ? `Map ` + JSON.stringify([...data])
29
+ : Object.getPrototypeOf(data).constructor.name +
30
+ ` ` +
31
+ fallback(() => JSON.stringify(data), `?`)
32
+ }
33
+ disabled={true}
34
+ />
35
+ </div>
36
+ )
37
+ }
38
+
39
+ export const ReadonlySelectorViewer: FC<{
40
+ token: ReadonlySelectorToken<unknown>
41
+ }> = ({ token }) => {
42
+ const data = useO(token)
43
+ return isJson(data) ? (
44
+ <JsonEditor
45
+ data={data}
46
+ set={() => null}
47
+ schema={true}
48
+ isReadonly={() => true}
49
+ />
50
+ ) : (
51
+ <div className="json_editor">
52
+ <ElasticInput
53
+ value={
54
+ data instanceof Set
55
+ ? `Set ` + JSON.stringify([...data])
56
+ : data instanceof Map
57
+ ? `Map ` + JSON.stringify([...data])
58
+ : Object.getPrototypeOf(data).constructor.name +
59
+ ` ` +
60
+ JSON.stringify(data)
61
+ }
62
+ disabled={true}
63
+ />
64
+ </div>
65
+ )
66
+ }
67
+
68
+ export const StoreEditor: FC<{
69
+ token: ReadonlySelectorToken<unknown> | StateToken<unknown>
70
+ }> = ({ token }) => {
71
+ if (token.type === `readonly_selector`) {
72
+ return <ReadonlySelectorViewer token={token} />
73
+ }
74
+ return <StateEditor token={token} />
75
+ }
@@ -0,0 +1,159 @@
1
+ import type { AtomToken, ReadonlySelectorToken, SelectorToken } from "atom.io"
2
+ import { getState, selectorFamily } from "atom.io"
3
+ import type { FamilyNode, StateTokenIndex } from "atom.io/introspection"
4
+ import { useI, useO } from "atom.io/react"
5
+ import type { FC } from "react"
6
+
7
+ import {
8
+ isJson,
9
+ refineJsonType,
10
+ } from "~/packages/anvl/src/refinement/refine-json"
11
+
12
+ import { findViewIsOpenState, primitiveRefinery } from "."
13
+ import { button } from "./Button"
14
+ import { StoreEditor } from "./StateEditor"
15
+
16
+ const findStateTypeState = selectorFamily<string, { key: string }>({
17
+ key: `👁‍🗨 State Type`,
18
+ get: (token) => ({ get }) => {
19
+ let state: unknown
20
+ try {
21
+ state = get(token as any)
22
+ } catch (error) {
23
+ return `error`
24
+ }
25
+ if (state === undefined) return `undefined`
26
+ if (isJson(state)) return refineJsonType(state).type
27
+ return Object.getPrototypeOf(state).constructor.name
28
+ },
29
+ })
30
+
31
+ export const StateIndexLeafNode: FC<{
32
+ node:
33
+ | AtomToken<unknown>
34
+ | ReadonlySelectorToken<unknown>
35
+ | SelectorToken<unknown>
36
+ isOpenState: AtomToken<boolean>
37
+ typeState: ReadonlySelectorToken<string>
38
+ }> = ({ node, isOpenState, typeState }) => {
39
+ const setIsOpen = useI(isOpenState)
40
+ const isOpen = useO(isOpenState)
41
+
42
+ const state = useO(node)
43
+ const stateType = useO(typeState)
44
+
45
+ const isPrimitive = Boolean(primitiveRefinery.refine(state))
46
+
47
+ return (
48
+ <>
49
+ <header>
50
+ <button.OpenClose
51
+ isOpen={isOpen && !isPrimitive}
52
+ setIsOpen={setIsOpen}
53
+ disabled={isPrimitive}
54
+ />
55
+ <label
56
+ onClick={() => console.log(node, getState(node))}
57
+ onKeyUp={() => console.log(node, getState(node))}
58
+ >
59
+ <h2>{node.family?.subKey ?? node.key}</h2>
60
+ <span className="type detail">({stateType})</span>
61
+ </label>
62
+ {isPrimitive ? <StoreEditor token={node} /> : null}
63
+ </header>
64
+ {isOpen && !isPrimitive ? (
65
+ <main>
66
+ <StoreEditor token={node} />
67
+ </main>
68
+ ) : null}
69
+ </>
70
+ )
71
+ }
72
+ export const StateIndexTreeNode: FC<{
73
+ node: FamilyNode<
74
+ AtomToken<unknown> | ReadonlySelectorToken<unknown> | SelectorToken<unknown>
75
+ >
76
+ isOpenState: AtomToken<boolean>
77
+ }> = ({ node, isOpenState }) => {
78
+ const setIsOpen = useI(isOpenState)
79
+ const isOpen = useO(isOpenState)
80
+ Object.entries(node.familyMembers).forEach(([key, childNode]) => {
81
+ findViewIsOpenState(key)
82
+ findStateTypeState(childNode)
83
+ })
84
+ return (
85
+ <>
86
+ <header>
87
+ <button.OpenClose isOpen={isOpen} setIsOpen={setIsOpen} />
88
+ <label>
89
+ <h2>{node.key}</h2>
90
+ <span className="type detail"> (family)</span>
91
+ </label>
92
+ </header>
93
+ {isOpen
94
+ ? Object.entries(node.familyMembers).map(([key, childNode]) => (
95
+ <StateIndexNode
96
+ key={key}
97
+ node={childNode}
98
+ isOpenState={findViewIsOpenState(childNode.key)}
99
+ typeState={findStateTypeState(childNode)}
100
+ />
101
+ ))
102
+ : null}
103
+ </>
104
+ )
105
+ }
106
+
107
+ export const StateIndexNode: FC<{
108
+ node: StateTokenIndex<
109
+ AtomToken<unknown> | ReadonlySelectorToken<unknown> | SelectorToken<unknown>
110
+ >[string]
111
+ isOpenState: AtomToken<boolean>
112
+ typeState: ReadonlySelectorToken<string>
113
+ }> = ({ node, isOpenState, typeState }) => {
114
+ if (node.key.startsWith(`👁‍🗨`)) {
115
+ return null
116
+ }
117
+ return (
118
+ <section className="node state">
119
+ {`type` in node ? (
120
+ <StateIndexLeafNode
121
+ node={node}
122
+ isOpenState={isOpenState}
123
+ typeState={typeState}
124
+ />
125
+ ) : (
126
+ <StateIndexTreeNode node={node} isOpenState={isOpenState} />
127
+ )}
128
+ </section>
129
+ )
130
+ }
131
+
132
+ export const StateIndex: FC<{
133
+ tokenIndex: ReadonlySelectorToken<
134
+ StateTokenIndex<
135
+ | AtomToken<unknown>
136
+ | ReadonlySelectorToken<unknown>
137
+ | SelectorToken<unknown>
138
+ >
139
+ >
140
+ }> = ({ tokenIndex }) => {
141
+ const tokenIds = useO(tokenIndex)
142
+ return (
143
+ <article className="index state_index">
144
+ {Object.entries(tokenIds)
145
+ .filter(([key]) => !key.startsWith(`👁‍🗨`))
146
+ .sort()
147
+ .map(([key, node]) => {
148
+ return (
149
+ <StateIndexNode
150
+ key={key}
151
+ node={node}
152
+ isOpenState={findViewIsOpenState(node.key)}
153
+ typeState={findStateTypeState(node)}
154
+ />
155
+ )
156
+ })}
157
+ </article>
158
+ )
159
+ }
@@ -0,0 +1,88 @@
1
+ import type { AtomToken, ReadonlySelectorToken, TimelineToken } from "atom.io"
2
+ import { redo, undo } from "atom.io"
3
+ import type { Timeline } from "atom.io/internal"
4
+ import { useI, useO } from "atom.io/react"
5
+ import { type FC, Fragment } from "react"
6
+
7
+ import { findTimelineState, findViewIsOpenState, timelineIndex } from "."
8
+ import { button } from "./Button"
9
+ import { article } from "./Updates"
10
+
11
+ export const YouAreHere: FC = () => {
12
+ return <span className="you_are_here">you are here</span>
13
+ }
14
+
15
+ export const TimelineLog: FC<{
16
+ token: TimelineToken
17
+ isOpenState: AtomToken<boolean>
18
+ timelineState: ReadonlySelectorToken<Timeline>
19
+ }> = ({ token, isOpenState, timelineState }) => {
20
+ const timeline = useO(timelineState)
21
+ const isOpen = useO(isOpenState)
22
+ const setIsOpen = useI(isOpenState)
23
+
24
+ return (
25
+ <section className="node timeline_log">
26
+ <header>
27
+ <button.OpenClose isOpen={isOpen} setIsOpen={setIsOpen} />
28
+ <label>
29
+ <h2>{token.key}</h2>
30
+ <span className="detail length">
31
+ ({timeline.at}/{timeline.history.length})
32
+ </span>
33
+ <span className="gap" />
34
+ <nav>
35
+ <button
36
+ type="button"
37
+ onClick={() => undo(token)}
38
+ disabled={timeline.at === 0}
39
+ >
40
+ undo
41
+ </button>
42
+ <button
43
+ type="button"
44
+ onClick={() => redo(token)}
45
+ disabled={timeline.at === timeline.history.length}
46
+ >
47
+ redo
48
+ </button>
49
+ </nav>
50
+ </label>
51
+ </header>
52
+ {isOpen ? (
53
+ <main>
54
+ {timeline.history.map((update, index) => (
55
+ <Fragment key={update.key + index + timeline.at}>
56
+ {index === timeline.at ? <YouAreHere /> : null}
57
+ <article.TimelineUpdate timelineUpdate={update} />
58
+ {index === timeline.history.length - 1 &&
59
+ timeline.at === timeline.history.length ? (
60
+ <YouAreHere />
61
+ ) : null}
62
+ </Fragment>
63
+ ))}
64
+ </main>
65
+ ) : null}
66
+ </section>
67
+ )
68
+ }
69
+
70
+ export const TimelineIndex: FC = () => {
71
+ const tokenIds = useO(timelineIndex)
72
+ return (
73
+ <article className="index timeline_index">
74
+ {tokenIds
75
+ .filter((token) => !token.key.startsWith(`👁‍🗨`))
76
+ .map((token) => {
77
+ return (
78
+ <TimelineLog
79
+ key={token.key}
80
+ token={token}
81
+ isOpenState={findViewIsOpenState(token.key)}
82
+ timelineState={findTimelineState(token.key)}
83
+ />
84
+ )
85
+ })}
86
+ </article>
87
+ )
88
+ }
@@ -0,0 +1,70 @@
1
+ import type {
2
+ AtomToken,
3
+ ReadonlySelectorToken,
4
+ TransactionToken,
5
+ TransactionUpdate,
6
+ ƒn,
7
+ } from "atom.io"
8
+ import { useI, useO } from "atom.io/react"
9
+ import type { FC } from "react"
10
+
11
+ import {
12
+ findTransactionLogState,
13
+ findViewIsOpenState,
14
+ transactionIndex,
15
+ } from "."
16
+ import { button } from "./Button"
17
+ import { article } from "./Updates"
18
+
19
+ export const TransactionLog: FC<{
20
+ token: TransactionToken<ƒn>
21
+ isOpenState: AtomToken<boolean>
22
+ logState: ReadonlySelectorToken<TransactionUpdate<ƒn>[]>
23
+ }> = ({ token, isOpenState, logState }) => {
24
+ const log = useO(logState)
25
+ const isOpen = useO(isOpenState)
26
+ const setIsOpen = useI(isOpenState)
27
+
28
+ return (
29
+ <section className="node transaction_log">
30
+ <header>
31
+ <button.OpenClose isOpen={isOpen} setIsOpen={setIsOpen} />
32
+ <label>
33
+ <h2>{token.key}</h2>
34
+ <span className="detail length">({log.length})</span>
35
+ </label>
36
+ </header>
37
+ {isOpen ? (
38
+ <main>
39
+ {log.map((update, index) => (
40
+ <article.TransactionUpdate
41
+ key={update.key + index}
42
+ serialNumber={index}
43
+ transactionUpdate={update}
44
+ />
45
+ ))}
46
+ </main>
47
+ ) : null}
48
+ </section>
49
+ )
50
+ }
51
+
52
+ export const TransactionIndex: FC = () => {
53
+ const tokenIds = useO(transactionIndex)
54
+ return (
55
+ <article className="index transaction_index">
56
+ {tokenIds
57
+ .filter((token) => !token.key.startsWith(`👁‍🗨`))
58
+ .map((token) => {
59
+ return (
60
+ <TransactionLog
61
+ key={token.key}
62
+ token={token}
63
+ isOpenState={findViewIsOpenState(token.key)}
64
+ logState={findTransactionLogState(token.key)}
65
+ />
66
+ )
67
+ })}
68
+ </article>
69
+ )
70
+ }
@@ -0,0 +1,150 @@
1
+ import type {
2
+ KeyedStateUpdate,
3
+ TimelineUpdate,
4
+ TransactionUpdate,
5
+ ƒn,
6
+ } from "atom.io"
7
+ import * as React from "react"
8
+
9
+ import { discoverType } from "~/packages/anvl/src/refinement/refinery"
10
+
11
+ import { prettyJson } from "."
12
+
13
+ const AtomUpdateFC: React.FC<{
14
+ serialNumber: number
15
+ atomUpdate: KeyedStateUpdate<unknown>
16
+ }> = ({ atomUpdate }) => {
17
+ return (
18
+ <article
19
+ key={atomUpdate.key}
20
+ className="node atom_update"
21
+ onClick={() => console.log(atomUpdate)}
22
+ onKeyUp={() => console.log(atomUpdate)}
23
+ >
24
+ <span className="detail">{atomUpdate.key}: </span>
25
+ <span>
26
+ <span className="summary">
27
+ {prettyJson.diff(atomUpdate.oldValue, atomUpdate.newValue).summary}
28
+ </span>
29
+ </span>
30
+ </article>
31
+ )
32
+ }
33
+
34
+ const TransactionUpdateFC: React.FC<{
35
+ serialNumber: number
36
+ transactionUpdate: TransactionUpdate<ƒn>
37
+ }> = ({ serialNumber, transactionUpdate }) => {
38
+ return (
39
+ <article className="node transaction_update">
40
+ <header>
41
+ <h4>{serialNumber}</h4>
42
+ </header>
43
+ <main>
44
+ <section className="transaction_params">
45
+ <span className="detail">params: </span>
46
+ {transactionUpdate.params.map((param, index) => {
47
+ return (
48
+ <article
49
+ key={`param` + index}
50
+ className="node transaction_param"
51
+ onClick={() => console.log(transactionUpdate)}
52
+ onKeyUp={() => console.log(transactionUpdate)}
53
+ >
54
+ <span className="detail">{discoverType(param)}: </span>
55
+ <span className="summary">
56
+ {typeof param === `object` &&
57
+ param !== null &&
58
+ `type` in param &&
59
+ `target` in param ? (
60
+ <>{JSON.stringify(param.type)}</>
61
+ ) : (
62
+ <>{JSON.stringify(param)}</>
63
+ )}
64
+ </span>
65
+ </article>
66
+ )
67
+ })}
68
+ </section>
69
+ <section className="node transaction_output">
70
+ <span className="detail">output: </span>
71
+ <span className="detail">
72
+ {discoverType(transactionUpdate.output)}
73
+ </span>
74
+ {transactionUpdate.output ? (
75
+ <span className="summary">
76
+ : {JSON.stringify(transactionUpdate.output)}
77
+ </span>
78
+ ) : null}
79
+ </section>
80
+ <section className="transaction_impact">
81
+ <span className="detail">impact: </span>
82
+ {transactionUpdate.atomUpdates
83
+ .filter((token) => !token.key.startsWith(`👁‍🗨`))
84
+ .map((atomUpdate, index) => {
85
+ return (
86
+ <article.AtomUpdate
87
+ key={`${transactionUpdate.key}:${index}:${atomUpdate.key}`}
88
+ serialNumber={index}
89
+ atomUpdate={atomUpdate}
90
+ />
91
+ )
92
+ })}
93
+ </section>
94
+ </main>
95
+ </article>
96
+ )
97
+ }
98
+
99
+ export const TimelineUpdateFC: React.FC<{
100
+ timelineUpdate: TimelineUpdate
101
+ }> = ({ timelineUpdate }) => {
102
+ return (
103
+ <article className="node timeline_update">
104
+ <header>
105
+ <h4>
106
+ {timelineUpdate.timestamp}: {timelineUpdate.type} ({timelineUpdate.key}
107
+ )
108
+ </h4>
109
+ </header>
110
+ <main>
111
+ {timelineUpdate.type === `transaction_update` ? (
112
+ timelineUpdate.atomUpdates
113
+ .filter((token) => !token.key.startsWith(`👁‍🗨`))
114
+ .map((atomUpdate, index) => {
115
+ return (
116
+ <article.AtomUpdate
117
+ key={`${timelineUpdate.key}:${index}:${atomUpdate.key}`}
118
+ serialNumber={index}
119
+ atomUpdate={atomUpdate}
120
+ />
121
+ )
122
+ })
123
+ ) : timelineUpdate.type === `selector_update` ? (
124
+ timelineUpdate.atomUpdates
125
+ .filter((token) => !token.key.startsWith(`👁‍🗨`))
126
+ .map((atomUpdate, index) => {
127
+ return (
128
+ <article.AtomUpdate
129
+ key={`${timelineUpdate.key}:${index}:${atomUpdate.key}`}
130
+ serialNumber={index}
131
+ atomUpdate={atomUpdate}
132
+ />
133
+ )
134
+ })
135
+ ) : timelineUpdate.type === `atom_update` ? (
136
+ <article.AtomUpdate
137
+ serialNumber={timelineUpdate.timestamp}
138
+ atomUpdate={timelineUpdate}
139
+ />
140
+ ) : null}
141
+ </main>
142
+ </article>
143
+ )
144
+ }
145
+
146
+ export const article = {
147
+ AtomUpdate: AtomUpdateFC,
148
+ TransactionUpdate: TransactionUpdateFC,
149
+ TimelineUpdate: TimelineUpdateFC,
150
+ }