atom.io 0.33.9 → 0.33.11

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.
@@ -1,4 +1,4 @@
1
- import type { WritableToken } from "atom.io"
1
+ import type { ReadableToken } from "atom.io"
2
2
 
3
3
  import type { Store } from "./store"
4
4
  import { isChildStore } from "./transaction/is-root-store"
@@ -12,12 +12,12 @@ export type OperationProgress =
12
12
  done: Set<string>
13
13
  prev: Map<string, any>
14
14
  time: number
15
- token: WritableToken<any>
15
+ token: ReadableToken<any>
16
16
  }
17
17
 
18
18
  export const openOperation = (
19
19
  store: Store,
20
- token: WritableToken<any>,
20
+ token: ReadableToken<any>,
21
21
  ): number | undefined => {
22
22
  if (store.operation.open) {
23
23
  const rejectionTime = performance.now()
@@ -1,10 +1,10 @@
1
- import type { Atom } from ".."
1
+ import type { Atom, Selector } from ".."
2
2
  import { evictCachedValue } from "../caching"
3
3
  import { newest } from "../lineage"
4
4
  import { isDone, markDone } from "../operation"
5
5
  import type { Store } from "../store"
6
6
 
7
- export const evictDownStream = <T>(store: Store, atom: Atom<T>): void => {
7
+ export function evictDownStream(store: Store, atom: Atom<any>): void {
8
8
  const target = newest(store)
9
9
  const downstreamKeys = target.selectorAtoms.getRelatedKeys(atom.key)
10
10
  target.logger.info(
@@ -34,3 +34,22 @@ export const evictDownStream = <T>(store: Store, atom: Atom<T>): void => {
34
34
  }
35
35
  }
36
36
  }
37
+
38
+ export function evictDownStreamFromSelector(
39
+ store: Store,
40
+ selector: Selector<any>,
41
+ ): void {
42
+ const target = newest(store)
43
+ const relationEntries = target.selectorGraph
44
+ .getRelationEntries({
45
+ upstreamSelectorKey: selector.key,
46
+ })
47
+ .filter(([_, { source }]) => source === selector.key)
48
+ for (const [downstreamSelectorKey] of relationEntries) {
49
+ if (isDone(target, downstreamSelectorKey)) {
50
+ continue
51
+ }
52
+ evictCachedValue(downstreamSelectorKey, target)
53
+ markDone(target, downstreamSelectorKey)
54
+ }
55
+ }
@@ -1,18 +1,29 @@
1
1
  main[data-css="atom_io_devtools"] {
2
2
  --fg-color: #ccc;
3
3
  --fg-light: #aaa;
4
+ --fg-soft: #777;
4
5
  --fg-faint: #555;
6
+ --fg-hint: #333;
7
+ --fg-max: #fff;
5
8
  --bg-color: #111;
6
9
  --bg-accent: #00f;
10
+ --bg-max: #000;
7
11
  --bg-tint1: #222;
12
+ --bg-tint2: #333;
8
13
  --fg-border: 1px solid var(--fg-color);
14
+ --fg-border-soft: 1px solid var(--fg-soft);
9
15
  @media (prefers-color-scheme: light) {
10
16
  --fg-color: #444;
11
17
  --fg-light: #777;
18
+ --fg-soft: #888;
12
19
  --fg-faint: #999;
20
+ --fg-hint: #ccc;
21
+ --fg-max: #000;
13
22
  --bg-color: #ddd;
14
23
  --bg-accent: #0ff;
24
+ --bg-max: #fff;
15
25
  --bg-tint1: #e3e3e3;
26
+ --bg-tint2: #f3f3f3;
16
27
  }
17
28
  & {
18
29
  pointer-events: all;
@@ -42,14 +53,20 @@ main[data-css="atom_io_devtools"] {
42
53
  display: flex;
43
54
  justify-content: space-between;
44
55
  h1 {
45
- margin: 0;
56
+ margin: 2px 4px;
46
57
  font-size: 24px;
47
58
  font-family: charter, serif;
48
59
  }
49
60
  nav {
61
+ position: relative;
50
62
  display: flex;
51
63
  flex-flow: row nowrap;
64
+ margin-top: 4px;
65
+ overflow-x: scroll;
66
+ overflow-y: visible;
67
+ height: 24px;
52
68
  button {
69
+ height: 24px;
53
70
  cursor: pointer;
54
71
  background: none;
55
72
  border: none;
@@ -58,10 +75,9 @@ main[data-css="atom_io_devtools"] {
58
75
  z-index: 1000;
59
76
  &:disabled {
60
77
  cursor: default;
61
- background-color: var(--bg-tint1);
62
- color: var(--fg-color);
78
+ background-color: var(--fg-color);
79
+ color: var(--bg-color);
63
80
  border: var(--fg-border);
64
- border-bottom: none;
65
81
  }
66
82
  }
67
83
  }
@@ -69,6 +85,10 @@ main[data-css="atom_io_devtools"] {
69
85
  > main {
70
86
  background: var(--bg-tint1);
71
87
  }
88
+ > main::before {
89
+ background-color: black;
90
+ height: 10px;
91
+ }
72
92
  main {
73
93
  overflow-y: scroll;
74
94
  flex-grow: 1;
@@ -86,7 +106,7 @@ main[data-css="atom_io_devtools"] {
86
106
  }
87
107
  .node > .node {
88
108
  margin: 0px 2px 2px 18px;
89
- border-left: var(--fg-border);
109
+ border-left: var(--fg-border-soft);
90
110
  &:last-of-type {
91
111
  margin-bottom: 6px;
92
112
  }
@@ -107,6 +127,8 @@ main[data-css="atom_io_devtools"] {
107
127
  z-index: 999;
108
128
  top: 0;
109
129
  height: 22px;
130
+ background: var(--bg-tint2);
131
+ border-bottom: var(--fg-border-soft);
110
132
  button.carat {
111
133
  cursor: pointer;
112
134
  background: none;
@@ -118,7 +140,10 @@ main[data-css="atom_io_devtools"] {
118
140
  }
119
141
  &:disabled {
120
142
  cursor: default;
121
- color: var(--fg-faint);
143
+ }
144
+ &:focus-within {
145
+ outline: 2px solid var(--fg-max);
146
+ background: var(--bg-max);
122
147
  }
123
148
  }
124
149
  > main {
@@ -126,6 +151,7 @@ main[data-css="atom_io_devtools"] {
126
151
  flex-flow: row;
127
152
  cursor: help;
128
153
  align-items: center;
154
+ flex-shrink: 0;
129
155
  * {
130
156
  height: 100%;
131
157
  display: flex;
@@ -150,21 +176,24 @@ main[data-css="atom_io_devtools"] {
150
176
  > .json_editor,
151
177
  > .json_viewer {
152
178
  display: flex;
179
+ flex-shrink: 1;
180
+ z-index: -1;
181
+ overflow-x: scroll;
153
182
  align-items: center;
154
- border-left: 1px solid var(--fg-light);
155
- background-color: var(--bg-tint1);
156
- * {
183
+ border-left: var(--fg-border-soft);
184
+ white-space: pre;
185
+ background: var(--bg-tint2);
186
+ &:focus-within {
187
+ background-color: var(--bg-max);
188
+ outline: 2px solid var(--fg-max);
189
+ }
190
+ &.nu * {
157
191
  display: flex;
158
192
  height: 100%;
159
193
  }
160
194
  > span {
161
195
  padding: 0px 5px;
162
- border-left: var(--fg-color);
163
196
  z-index: 0;
164
- &:focus-within {
165
- outline: 4px solid var(--fg-color);
166
- background: var(--bg-accent);
167
- }
168
197
  }
169
198
  input {
170
199
  outline: none;
@@ -288,12 +317,34 @@ main[data-css="atom_io_devtools"] {
288
317
  border: none;
289
318
  }
290
319
  }
320
+ input,
321
+ button,
322
+ select {
323
+ &:focus-within {
324
+ outline: 2px solid var(--fg-max);
325
+ background: var(--bg-max);
326
+ }
327
+ }
328
+ button:disabled {
329
+ cursor: default;
330
+ > span.json_editor_icon {
331
+ color: var(--fg-hint);
332
+ }
333
+ &:hover {
334
+ background: none;
335
+ }
336
+ }
337
+ input::selection {
338
+ background: var(--bg-accent);
339
+ }
340
+
291
341
  button {
292
342
  background: none;
293
343
  color: #777;
294
344
  border: none;
295
345
  font-family: theia, monospace;
296
346
  font-size: 14px;
347
+ height: 21px;
297
348
  margin: none;
298
349
  padding: 4px;
299
350
  padding-bottom: 6px;
@@ -323,7 +374,10 @@ main[data-css="atom_io_devtools"] {
323
374
  background-color: #f055;
324
375
  }
325
376
  .json_editor_key {
326
- padding-right: 10px;
377
+ padding-right: 0px;
378
+ &::after {
379
+ content: ":";
380
+ }
327
381
  input {
328
382
  color: #999;
329
383
  @media (prefers-color-scheme: light) {
@@ -331,16 +385,37 @@ main[data-css="atom_io_devtools"] {
331
385
  }
332
386
  }
333
387
  }
334
- .json_editor_object {
335
- border-left: 2px solid #333;
336
- padding-left: 20px;
337
- @media (prefers-color-scheme: light) {
338
- border-color: #ccc;
339
- }
340
- .json_editor_properties {
341
- > * {
342
- border-bottom: var(--fg-border);
388
+ .json_editor_object,
389
+ .json_editor_array {
390
+ border-left: var(--fg-border-soft);
391
+ padding-left: 12px;
392
+ margin-left: 8px;
393
+ .json_editor_properties,
394
+ .json_editor_elements {
395
+ .json_editor_property,
396
+ .json_editor_element {
397
+ border-bottom: var(--fg-border-soft);
343
398
  margin-bottom: 2px;
399
+ min-height: 23px;
400
+ > span {
401
+ input {
402
+ min-width: 10px;
403
+ }
404
+ > * {
405
+ border: var(--fg-border-soft);
406
+ }
407
+ }
408
+ }
409
+ &.readonly {
410
+ .json_editor_property,
411
+ .json_editor_element {
412
+ &:last-of-type {
413
+ border-bottom: none;
414
+ }
415
+ > span > * {
416
+ border: 1px solid transparent;
417
+ }
418
+ }
344
419
  }
345
420
  }
346
421
  }
@@ -1,9 +1,13 @@
1
- import type { Json } from "atom.io/json"
1
+ import { type Json, JSON_DEFAULTS } from "atom.io/json"
2
2
  import type { ReactElement } from "react"
3
3
 
4
4
  import type { JsonEditorProps_INTERNAL } from "../json-editor-internal"
5
5
  import { JsonEditor_INTERNAL } from "../json-editor-internal"
6
6
  import { makeElementSetters } from "./utilities/array-elements"
7
+ import {
8
+ makePropertyRecasters,
9
+ makePropertyRemovers,
10
+ } from "./utilities/object-properties"
7
11
 
8
12
  export const ArrayEditor = ({
9
13
  path = [],
@@ -14,25 +18,49 @@ export const ArrayEditor = ({
14
18
  Components,
15
19
  testid,
16
20
  }: JsonEditorProps_INTERNAL<Json.Tree.Array>): ReactElement => {
21
+ const disabled = isReadonly(path)
22
+
17
23
  const setElement = makeElementSetters(data, set)
24
+ const removeElement = makePropertyRemovers(data, set)
25
+ const recastElement = makePropertyRecasters(data, set)
26
+
18
27
  return (
19
- <>
20
- {data.map((element, index) => {
21
- const newPath = [...path, index]
22
- return (
23
- <JsonEditor_INTERNAL
24
- key={newPath.join(``)}
25
- path={newPath}
26
- isReadonly={isReadonly}
27
- isHidden={isHidden}
28
- data={element}
29
- set={setElement[index]}
30
- Components={Components}
31
- className="json_editor_element"
32
- testid={`${testid}-element-${index}`}
33
- />
34
- )
35
- })}
36
- </>
28
+ <Components.ArrayWrapper>
29
+ <div className={`json_editor_elements${disabled ? ` readonly` : ``}`}>
30
+ {data.map((element, index) => {
31
+ const newPath = [...path, index]
32
+ return (
33
+ <JsonEditor_INTERNAL
34
+ key={newPath.join(``)}
35
+ path={newPath}
36
+ name={`${index}`}
37
+ isReadonly={isReadonly}
38
+ isHidden={isHidden}
39
+ data={element}
40
+ set={setElement[index]}
41
+ remove={removeElement[index]}
42
+ recast={recastElement[index]}
43
+ className="json_editor_element"
44
+ Components={Components}
45
+ testid={`${testid}-element-${index}`}
46
+ />
47
+ )
48
+ })}
49
+ </div>
50
+ {disabled ? null : (
51
+ <Components.Button
52
+ testid={`${testid}-add-element`}
53
+ disabled={disabled}
54
+ onClick={() => {
55
+ set((current) => {
56
+ const newData = [...current, JSON_DEFAULTS.string]
57
+ return newData
58
+ })
59
+ }}
60
+ >
61
+ +
62
+ </Components.Button>
63
+ )}
64
+ </Components.ArrayWrapper>
37
65
  )
38
66
  }
@@ -72,48 +72,36 @@ export const ObjectEditor = <T extends Json.Tree.Object>({
72
72
  const makePropertyAdder = makePropertyCreationInterface(data, set)
73
73
 
74
74
  return (
75
- <>
76
- <Components.Button
77
- testid={`${testid}-sort-properties`}
78
- onClick={() => {
79
- sortProperties()
80
- }}
81
- disabled={disabled}
82
- >
83
- Sort
84
- </Components.Button>
85
- <Components.ObjectWrapper>
86
- <div className="json_editor_properties">
87
- {Object.keys(data).map((key) => {
88
- const originalKey = stableKeyMap.current[key]
89
- const newPath = [...path, key]
90
- const originalPath = [...path, originalKey]
75
+ <Components.ObjectWrapper>
76
+ <div className={`json_editor_properties${disabled ? ` readonly` : ``}`}>
77
+ {Object.keys(data).map((key) => {
78
+ const originalKey = stableKeyMap.current[key]
79
+ const newPath = [...path, key]
80
+ const originalPath = [...path, originalKey]
91
81
 
92
- return (
93
- <JsonEditor_INTERNAL
94
- key={originalPath.join(`.`)}
95
- path={newPath}
96
- name={key}
97
- isReadonly={isReadonly}
98
- isHidden={isHidden}
99
- data={data[key as keyof T]}
100
- set={setProperty[key as keyof T]}
101
- rename={renameProperty[key as keyof T]}
102
- remove={removeProperty[key as keyof T]}
103
- recast={recastProperty[key as keyof T]}
104
- className="json_editor_property"
105
- Components={Components}
106
- testid={`${testid}-property-${key}`}
107
- />
108
- )
109
- })}
110
- </div>
111
- {disabled ? (
112
- <Components.Button disabled testid={`${testid}-add-property`}>
113
- +
114
- </Components.Button>
115
- ) : (
82
+ return (
83
+ <JsonEditor_INTERNAL
84
+ key={originalPath.join(`.`)}
85
+ path={newPath}
86
+ name={key}
87
+ isReadonly={isReadonly}
88
+ isHidden={isHidden}
89
+ data={data[key as keyof T]}
90
+ set={setProperty[key as keyof T]}
91
+ rename={renameProperty[key as keyof T]}
92
+ remove={removeProperty[key as keyof T]}
93
+ recast={recastProperty[key as keyof T]}
94
+ className="json_editor_property"
95
+ Components={Components}
96
+ testid={`${testid}-property-${key}`}
97
+ />
98
+ )
99
+ })}
100
+ </div>
101
+ {disabled ? null : (
102
+ <>
116
103
  <Components.Button
104
+ disabled={disabled}
117
105
  testid={`${testid}-add-property`}
118
106
  onClick={() => {
119
107
  makePropertyAdder(`new_property`, `string`)()
@@ -121,8 +109,17 @@ export const ObjectEditor = <T extends Json.Tree.Object>({
121
109
  >
122
110
  +
123
111
  </Components.Button>
124
- )}
125
- </Components.ObjectWrapper>
126
- </>
112
+ <Components.Button
113
+ testid={`${testid}-sort-properties`}
114
+ onClick={() => {
115
+ sortProperties()
116
+ }}
117
+ disabled={disabled}
118
+ >
119
+ Sort
120
+ </Components.Button>
121
+ </>
122
+ )}
123
+ </Components.ObjectWrapper>
127
124
  )
128
125
  }
@@ -4,6 +4,8 @@ import { NumberInput, TextInput } from "../../elastic-input"
4
4
  import type { JsonEditorProps_INTERNAL } from "../json-editor-internal"
5
5
 
6
6
  export const BooleanEditor = ({
7
+ path = [],
8
+ isReadonly = () => false,
7
9
  data,
8
10
  set,
9
11
  Components,
@@ -11,6 +13,7 @@ export const BooleanEditor = ({
11
13
  }: JsonEditorProps_INTERNAL<boolean>): ReactElement => (
12
14
  <Components.BooleanWrapper>
13
15
  <input
16
+ disabled={isReadonly(path)}
14
17
  data-testid={`${testid}-boolean-input`}
15
18
  type="checkbox"
16
19
  checked={data}
@@ -38,6 +41,7 @@ export const NumberEditor = ({
38
41
  }: JsonEditorProps_INTERNAL<number>): ReactElement => (
39
42
  <Components.NumberWrapper>
40
43
  <NumberInput
44
+ disabled={isReadonly(path)}
41
45
  testid={`${testid}-number-input`}
42
46
  value={data}
43
47
  set={
@@ -63,6 +67,7 @@ export const StringEditor = ({
63
67
  return (
64
68
  <Components.StringWrapper>
65
69
  <TextInput
70
+ readOnly={isReadonly(path)}
66
71
  testid={`${testid}-string-input`}
67
72
  value={data}
68
73
  set={isReadonly(path) ? undefined : set}
@@ -45,7 +45,9 @@ export const makePropertyRenamers = <T extends Json.Tree.Object>(
45
45
  ]),
46
46
  )
47
47
 
48
- export const makePropertyRemovers = <T extends Json.Tree.Object>(
48
+ export const makePropertyRemovers = <
49
+ T extends Json.Tree.Array | Json.Tree.Object,
50
+ >(
49
51
  data: T,
50
52
  set: SetterOrUpdater<T>,
51
53
  ): { [K in keyof T]: () => void } =>
@@ -54,14 +56,24 @@ export const makePropertyRemovers = <T extends Json.Tree.Object>(
54
56
  key,
55
57
  () => {
56
58
  set(() => {
57
- const { [key]: _, ...rest } = data
58
- return rest as T
59
+ let next: T
60
+ if (Array.isArray(data)) {
61
+ const copy = [...data]
62
+ copy.splice(key as number, 1)
63
+ next = copy as unknown as T
64
+ } else {
65
+ const { [key]: _, ...rest } = data
66
+ next = rest as T
67
+ }
68
+ return next
59
69
  })
60
70
  },
61
71
  ]),
62
72
  )
63
73
 
64
- export const makePropertyRecasters = <T extends Json.Tree.Object>(
74
+ export const makePropertyRecasters = <
75
+ T extends Json.Tree.Array | Json.Tree.Object,
76
+ >(
65
77
  data: T,
66
78
  set: SetterOrUpdater<T>,
67
79
  ): { [K in keyof T]: (newType: JsonTypeName) => void } =>
@@ -69,10 +81,20 @@ export const makePropertyRecasters = <T extends Json.Tree.Object>(
69
81
  toEntries(data).map(([key, value]) => [
70
82
  key,
71
83
  (newType: JsonTypeName) => {
72
- set(() => ({
73
- ...data,
74
- [key]: castToJson(value)[newType],
75
- }))
84
+ set(() => {
85
+ let next: T
86
+ if (Array.isArray(data)) {
87
+ const copy = [...data]
88
+ copy[key as number] = castToJson(value)[newType]
89
+ next = copy as unknown as T
90
+ } else {
91
+ next = {
92
+ ...data,
93
+ [key]: castToJson(value)[newType],
94
+ }
95
+ }
96
+ return next
97
+ })
76
98
  },
77
99
  ]),
78
100
  )
@@ -1,16 +1,3 @@
1
- import type { JsonTypes } from "atom.io/json"
2
- import type { FC } from "react"
3
-
4
- import { ArrayEditor } from "./editors-by-type/array-editor"
5
- import { ObjectEditor } from "./editors-by-type/object-editor"
6
- import {
7
- BooleanEditor,
8
- NullEditor,
9
- NumberEditor,
10
- StringEditor,
11
- } from "./editors-by-type/primitive-editors"
12
- import type { JsonEditorProps_INTERNAL } from "./json-editor-internal"
13
-
14
1
  export * from "./default-components"
15
2
  export * from "./developer-interface"
16
3
  export * from "./editors-by-type/utilities/cast-to-json"
@@ -18,15 +5,3 @@ export * from "./editors-by-type/utilities/cast-to-json"
18
5
  export type SetterOrUpdater<T> = <New extends T>(
19
6
  next: New | ((old: T) => New),
20
7
  ) => void
21
-
22
- export const SubEditors: Record<
23
- keyof JsonTypes,
24
- FC<JsonEditorProps_INTERNAL<any>>
25
- > = {
26
- array: ArrayEditor,
27
- boolean: BooleanEditor,
28
- null: NullEditor,
29
- number: NumberEditor,
30
- object: ObjectEditor,
31
- string: StringEditor,
32
- }
@@ -61,20 +61,15 @@ export const JsonEditor_INTERNAL = <T,>({
61
61
  testid={testid}
62
62
  >
63
63
  {remove ? (
64
- disabled ? (
65
- <Components.Button disabled testid={`${testid}-delete`}>
66
- <Components.DeleteIcon />
67
- </Components.Button>
68
- ) : (
69
- <Components.Button
70
- testid={`${testid}-delete`}
71
- onClick={() => {
72
- remove()
73
- }}
74
- >
75
- <Components.DeleteIcon />
76
- </Components.Button>
77
- )
64
+ <Components.Button
65
+ disabled={disabled}
66
+ onClick={() => {
67
+ remove()
68
+ }}
69
+ testid={`${testid}-delete`}
70
+ >
71
+ <Components.DeleteIcon />
72
+ </Components.Button>
78
73
  ) : null}
79
74
  {HeaderDisplay && <HeaderDisplay data={data} />}
80
75
  {rename && (