atom.io 0.28.1 → 0.29.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.
- package/dist/{chunk-6WL4RQMQ.js → chunk-XPYU2HY2.js} +22 -57
- package/eslint-plugin/dist/index.js +0 -1
- package/eslint-plugin/src/walk.ts +0 -1
- package/internal/dist/index.d.ts +4 -4
- package/internal/dist/index.js +1 -1
- package/internal/src/atom/dispose-atom.ts +0 -11
- package/internal/src/ingest-updates/ingest-creation-disposal.ts +16 -25
- package/internal/src/operation.ts +7 -7
- package/internal/src/selector/create-writable-selector.ts +1 -1
- package/internal/src/selector/dispose-selector.ts +0 -13
- package/internal/src/set-state/become.ts +1 -3
- package/internal/src/set-state/evict-downstream.ts +2 -2
- package/internal/src/set-state/set-atom.ts +1 -1
- package/internal/src/set-state/set-into-store.ts +1 -1
- package/internal/src/set-state/stow-update.ts +2 -2
- package/internal/src/store/store.ts +1 -1
- package/introspection/dist/index.d.ts +15 -6
- package/introspection/dist/index.js +620 -1
- package/introspection/src/attach-atom-index.ts +5 -6
- package/introspection/src/attach-introspection-states.ts +5 -6
- package/introspection/src/attach-selector-index.ts +6 -7
- package/introspection/src/attach-timeline-family.ts +3 -4
- package/introspection/src/attach-timeline-index.ts +4 -8
- package/introspection/src/attach-transaction-index.ts +4 -8
- package/introspection/src/attach-transaction-logs.ts +4 -8
- package/introspection/src/attach-type-selectors.ts +13 -6
- package/introspection/src/differ.ts +1 -1
- package/introspection/src/index.ts +1 -0
- package/introspection/src/refinery.ts +9 -7
- package/introspection/src/sprawl.ts +42 -0
- package/json/dist/index.d.ts +12 -1
- package/json/dist/index.js +111 -2
- package/json/src/index.ts +29 -0
- package/package.json +12 -12
- package/react-devtools/dist/index.d.ts +159 -2
- package/react-devtools/dist/index.js +260 -663
- package/react-devtools/src/AtomIODevtools.tsx +24 -13
- package/react-devtools/src/StateEditor.tsx +5 -47
- package/react-devtools/src/StateIndex.tsx +15 -9
- package/react-devtools/src/TimelineIndex.tsx +9 -6
- package/react-devtools/src/TransactionIndex.tsx +9 -11
- package/react-devtools/src/elastic-input/ElasticInput.tsx +86 -0
- package/react-devtools/src/elastic-input/NumberInput.tsx +199 -0
- package/react-devtools/src/elastic-input/TextInput.tsx +47 -0
- package/react-devtools/src/elastic-input/index.ts +3 -0
- package/react-devtools/src/error-boundary/DefaultFallback.tsx +49 -0
- package/react-devtools/src/error-boundary/ReactErrorBoundary.tsx +56 -0
- package/react-devtools/src/error-boundary/index.ts +2 -0
- package/react-devtools/src/index.ts +3 -0
- package/react-devtools/src/json-editor/assets/Untitled-1.ai +1436 -2
- package/react-devtools/src/json-editor/assets/data-vis.ai +1548 -1
- package/react-devtools/src/json-editor/comp/json-editor-sketches.ai +1451 -3
- package/react-devtools/src/json-editor/default-components.tsx +101 -0
- package/react-devtools/src/json-editor/developer-interface.tsx +81 -0
- package/react-devtools/src/json-editor/editors-by-type/array-editor.tsx +38 -0
- package/react-devtools/src/json-editor/editors-by-type/non-json.tsx +23 -0
- package/react-devtools/src/json-editor/editors-by-type/object-editor.tsx +128 -0
- package/react-devtools/src/json-editor/editors-by-type/primitive-editors.tsx +73 -0
- package/react-devtools/src/json-editor/editors-by-type/utilities/array-elements.ts +16 -0
- package/react-devtools/src/json-editor/editors-by-type/utilities/cast-json.ts +57 -0
- package/react-devtools/src/json-editor/editors-by-type/utilities/cast-to-json.ts +156 -0
- package/react-devtools/src/json-editor/editors-by-type/utilities/object-properties.ts +106 -0
- package/react-devtools/src/json-editor/index.ts +32 -0
- package/react-devtools/src/json-editor/json-editor-internal.tsx +128 -0
- package/react-devtools/src/json-editor/todo.md +7 -0
- package/react-devtools/src/store.ts +70 -46
- package/dist/chunk-D52JNVER.js +0 -721
- package/dist/chunk-YQ46F5O2.js +0 -95
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { become } from "atom.io/internal"
|
|
2
|
+
import type { Json, JsonTypeName } from "atom.io/json"
|
|
3
|
+
import { fromEntries, JSON_DEFAULTS, toEntries } from "atom.io/json"
|
|
4
|
+
import type { MutableRefObject } from "react"
|
|
5
|
+
|
|
6
|
+
import type { SetterOrUpdater } from "../.."
|
|
7
|
+
import { castToJson } from "./cast-to-json"
|
|
8
|
+
|
|
9
|
+
export const makePropertySetters = <T extends Json.Tree.Object>(
|
|
10
|
+
data: T,
|
|
11
|
+
set: SetterOrUpdater<T>,
|
|
12
|
+
): { [K in keyof T]: SetterOrUpdater<T[K]> } =>
|
|
13
|
+
fromEntries(
|
|
14
|
+
toEntries(data).map(([key, value]) => [
|
|
15
|
+
key,
|
|
16
|
+
(newValue) => {
|
|
17
|
+
set({ ...data, [key]: become(newValue)(value) })
|
|
18
|
+
},
|
|
19
|
+
]),
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
export const makePropertyRenamers = <T extends Json.Tree.Object>(
|
|
23
|
+
data: T,
|
|
24
|
+
set: SetterOrUpdater<T>,
|
|
25
|
+
stableKeyMapRef: MutableRefObject<{ [Key in keyof T]: keyof T }>,
|
|
26
|
+
): { [K in keyof T]: (newKey: string) => void } =>
|
|
27
|
+
fromEntries(
|
|
28
|
+
toEntries(data).map(([key, value]) => [
|
|
29
|
+
key,
|
|
30
|
+
(newKey: string) => {
|
|
31
|
+
if (!Object.hasOwn(data, newKey)) {
|
|
32
|
+
set(() => {
|
|
33
|
+
const entries = Object.entries(data)
|
|
34
|
+
const index = entries.findIndex(([k]) => k === key)
|
|
35
|
+
entries[index] = [newKey, value]
|
|
36
|
+
const stableKeyMap = stableKeyMapRef.current
|
|
37
|
+
stableKeyMapRef.current = {
|
|
38
|
+
...stableKeyMap,
|
|
39
|
+
[newKey]: stableKeyMap[key],
|
|
40
|
+
}
|
|
41
|
+
return Object.fromEntries(entries) as T
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
]),
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
export const makePropertyRemovers = <T extends Json.Tree.Object>(
|
|
49
|
+
data: T,
|
|
50
|
+
set: SetterOrUpdater<T>,
|
|
51
|
+
): { [K in keyof T]: () => void } =>
|
|
52
|
+
fromEntries(
|
|
53
|
+
toEntries(data).map(([key]) => [
|
|
54
|
+
key,
|
|
55
|
+
() => {
|
|
56
|
+
set(() => {
|
|
57
|
+
const { [key]: _, ...rest } = data
|
|
58
|
+
return rest as T
|
|
59
|
+
})
|
|
60
|
+
},
|
|
61
|
+
]),
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
export const makePropertyRecasters = <T extends Json.Tree.Object>(
|
|
65
|
+
data: T,
|
|
66
|
+
set: SetterOrUpdater<T>,
|
|
67
|
+
): { [K in keyof T]: (newType: JsonTypeName) => void } =>
|
|
68
|
+
fromEntries(
|
|
69
|
+
toEntries(data).map(([key, value]) => [
|
|
70
|
+
key,
|
|
71
|
+
(newType: JsonTypeName) => {
|
|
72
|
+
set(() => ({
|
|
73
|
+
...data,
|
|
74
|
+
[key]: castToJson(value)[newType],
|
|
75
|
+
}))
|
|
76
|
+
},
|
|
77
|
+
]),
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
export const makePropertyCreationInterface =
|
|
81
|
+
<T extends Json.Tree.Object>(
|
|
82
|
+
data: T,
|
|
83
|
+
set: SetterOrUpdater<T>,
|
|
84
|
+
): ((
|
|
85
|
+
key: string,
|
|
86
|
+
type: JsonTypeName,
|
|
87
|
+
) => (value?: Json.Serializable) => void) =>
|
|
88
|
+
(key, type) =>
|
|
89
|
+
(value) => {
|
|
90
|
+
set({ ...data, [key]: value ?? JSON_DEFAULTS[type] })
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export const makePropertySorter =
|
|
94
|
+
<T extends Json.Tree.Object>(
|
|
95
|
+
data: T,
|
|
96
|
+
set: SetterOrUpdater<T>,
|
|
97
|
+
sortFn?: (a: string, b: string) => number,
|
|
98
|
+
): (() => void) =>
|
|
99
|
+
() => {
|
|
100
|
+
const sortedKeys = Object.keys(data).sort(sortFn)
|
|
101
|
+
const sortedObj = {} as Record<string, unknown>
|
|
102
|
+
for (const key of sortedKeys) {
|
|
103
|
+
sortedObj[key] = data[key]
|
|
104
|
+
}
|
|
105
|
+
set(sortedObj as T)
|
|
106
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
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
|
+
export * from "./default-components"
|
|
15
|
+
export * from "./developer-interface"
|
|
16
|
+
export * from "./editors-by-type/utilities/cast-to-json"
|
|
17
|
+
|
|
18
|
+
export type SetterOrUpdater<T> = <New extends T>(
|
|
19
|
+
next: New | ((old: T) => New),
|
|
20
|
+
) => 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
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { jsonRefinery } from "atom.io/introspection"
|
|
2
|
+
import type { JsonTypes } from "atom.io/json"
|
|
3
|
+
import { isJson } from "atom.io/json"
|
|
4
|
+
import type { CSSProperties, FC, ReactElement } from "react"
|
|
5
|
+
|
|
6
|
+
import { ElasticInput } from "../elastic-input"
|
|
7
|
+
import type { SetterOrUpdater } from "."
|
|
8
|
+
import { SubEditors } from "."
|
|
9
|
+
import type { JsonEditorComponents } from "./default-components"
|
|
10
|
+
import { NonJsonEditor } from "./editors-by-type/non-json"
|
|
11
|
+
|
|
12
|
+
export type JsonEditorProps_INTERNAL<T> = {
|
|
13
|
+
data: T
|
|
14
|
+
set: SetterOrUpdater<T>
|
|
15
|
+
name?: string | undefined
|
|
16
|
+
rename?: ((newKey: string) => void) | undefined
|
|
17
|
+
remove?: (() => void) | undefined
|
|
18
|
+
recast?: (newType: keyof JsonTypes) => void
|
|
19
|
+
path?: ReadonlyArray<number | string>
|
|
20
|
+
isReadonly?: (path: ReadonlyArray<number | string>) => boolean
|
|
21
|
+
isHidden?: (path: ReadonlyArray<number | string>) => boolean
|
|
22
|
+
className?: string | undefined
|
|
23
|
+
style?: CSSProperties | undefined
|
|
24
|
+
Header?: FC<{ data: T }> | undefined
|
|
25
|
+
Components: JsonEditorComponents
|
|
26
|
+
testid?: string | undefined
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const JsonEditor_INTERNAL = <T,>({
|
|
30
|
+
data,
|
|
31
|
+
set,
|
|
32
|
+
name,
|
|
33
|
+
rename,
|
|
34
|
+
remove,
|
|
35
|
+
recast,
|
|
36
|
+
path = [],
|
|
37
|
+
isReadonly = () => false,
|
|
38
|
+
isHidden = () => false,
|
|
39
|
+
className,
|
|
40
|
+
style,
|
|
41
|
+
Header: HeaderDisplay,
|
|
42
|
+
Components,
|
|
43
|
+
testid,
|
|
44
|
+
}: JsonEditorProps_INTERNAL<T>): ReactElement | null => {
|
|
45
|
+
const dataIsJson = isJson(data)
|
|
46
|
+
const refined = jsonRefinery.refine<unknown>(data) ?? {
|
|
47
|
+
type: `non-json`,
|
|
48
|
+
data,
|
|
49
|
+
}
|
|
50
|
+
const SubEditor = dataIsJson ? SubEditors[refined.type] : NonJsonEditor
|
|
51
|
+
|
|
52
|
+
const disabled = isReadonly(path)
|
|
53
|
+
|
|
54
|
+
return isHidden(path) ? null : (
|
|
55
|
+
<Components.ErrorBoundary>
|
|
56
|
+
<Components.EditorWrapper
|
|
57
|
+
className={className}
|
|
58
|
+
style={style}
|
|
59
|
+
testid={testid}
|
|
60
|
+
>
|
|
61
|
+
{remove ? (
|
|
62
|
+
disabled ? (
|
|
63
|
+
<Components.Button disabled testid={`${testid}-delete`}>
|
|
64
|
+
<Components.DeleteIcon />
|
|
65
|
+
</Components.Button>
|
|
66
|
+
) : (
|
|
67
|
+
<Components.Button
|
|
68
|
+
testid={`${testid}-delete`}
|
|
69
|
+
onClick={() => {
|
|
70
|
+
remove()
|
|
71
|
+
}}
|
|
72
|
+
>
|
|
73
|
+
<Components.DeleteIcon />
|
|
74
|
+
</Components.Button>
|
|
75
|
+
)
|
|
76
|
+
) : null}
|
|
77
|
+
{HeaderDisplay && <HeaderDisplay data={data} />}
|
|
78
|
+
{rename && (
|
|
79
|
+
<Components.KeyWrapper>
|
|
80
|
+
<ElasticInput
|
|
81
|
+
value={name}
|
|
82
|
+
onChange={
|
|
83
|
+
disabled
|
|
84
|
+
? undefined
|
|
85
|
+
: (e) => {
|
|
86
|
+
rename(e.target.value)
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
disabled={disabled}
|
|
90
|
+
data-testid={`${testid}-rename`}
|
|
91
|
+
/>
|
|
92
|
+
</Components.KeyWrapper>
|
|
93
|
+
)}
|
|
94
|
+
<SubEditor
|
|
95
|
+
data={refined.data}
|
|
96
|
+
set={set}
|
|
97
|
+
remove={remove}
|
|
98
|
+
rename={rename}
|
|
99
|
+
path={path}
|
|
100
|
+
isReadonly={isReadonly}
|
|
101
|
+
isHidden={isHidden}
|
|
102
|
+
Components={Components}
|
|
103
|
+
testid={testid}
|
|
104
|
+
/>
|
|
105
|
+
{recast && dataIsJson ? (
|
|
106
|
+
<select
|
|
107
|
+
onChange={
|
|
108
|
+
disabled
|
|
109
|
+
? undefined
|
|
110
|
+
: (e) => {
|
|
111
|
+
recast(e.target.value as keyof JsonTypes)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
value={refined.type}
|
|
115
|
+
disabled={disabled}
|
|
116
|
+
data-testid={`${testid}-recast`}
|
|
117
|
+
>
|
|
118
|
+
{Object.keys(SubEditors).map((type) => (
|
|
119
|
+
<option key={type} value={type}>
|
|
120
|
+
{type}
|
|
121
|
+
</option>
|
|
122
|
+
))}
|
|
123
|
+
</select>
|
|
124
|
+
) : null}
|
|
125
|
+
</Components.EditorWrapper>
|
|
126
|
+
</Components.ErrorBoundary>
|
|
127
|
+
)
|
|
128
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
|
|
2
|
+
- [x] add an ErrorBoundary to the Components prop
|
|
3
|
+
- [x] wrap each JsonEditor_INTERNAL in an ErrorBoundary
|
|
4
|
+
- [ ] add display of miscast properties with button to fix
|
|
5
|
+
- [ ] fixing a miscast generates a template from the schema
|
|
6
|
+
- [ ] sort official properties as listed in schema
|
|
7
|
+
- [ ] add extra line break in JSON before unofficial properties
|
|
@@ -1,51 +1,75 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { RegularAtomFamilyToken, RegularAtomToken } from "atom.io"
|
|
2
|
+
import {
|
|
3
|
+
createAtomFamily,
|
|
4
|
+
createStandaloneAtom,
|
|
5
|
+
IMPLICIT,
|
|
6
|
+
type Store,
|
|
7
|
+
} from "atom.io/internal"
|
|
8
|
+
import type { IntrospectionStates } from "atom.io/introspection"
|
|
2
9
|
import { attachIntrospectionStates } from "atom.io/introspection"
|
|
3
10
|
import { persistSync } from "atom.io/web"
|
|
4
|
-
|
|
5
|
-
export const {
|
|
6
|
-
atomIndex,
|
|
7
|
-
selectorIndex,
|
|
8
|
-
transactionIndex,
|
|
9
|
-
transactionLogSelectors,
|
|
10
|
-
timelineIndex,
|
|
11
|
-
timelineSelectors,
|
|
12
|
-
typeSelectors,
|
|
13
|
-
} = attachIntrospectionStates()
|
|
14
|
-
|
|
15
|
-
export const devtoolsAreOpenState = atom<boolean>({
|
|
16
|
-
key: `👁🗨 Devtools Are Open`,
|
|
17
|
-
default: true,
|
|
18
|
-
effects:
|
|
19
|
-
typeof window === `undefined`
|
|
20
|
-
? []
|
|
21
|
-
: [persistSync(window.localStorage, JSON, `👁🗨 Devtools Are Open`)],
|
|
22
|
-
})
|
|
11
|
+
import { createContext } from "react"
|
|
23
12
|
|
|
24
13
|
type DevtoolsView = `atoms` | `selectors` | `timelines` | `transactions`
|
|
25
14
|
|
|
26
|
-
export
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
15
|
+
export type DevtoolsStates = {
|
|
16
|
+
devtoolsAreOpenState: RegularAtomToken<boolean>
|
|
17
|
+
devtoolsViewSelectionState: RegularAtomToken<DevtoolsView>
|
|
18
|
+
devtoolsViewOptionsState: RegularAtomToken<DevtoolsView[]>
|
|
19
|
+
viewIsOpenAtoms: RegularAtomFamilyToken<boolean, string>
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function attachDevtoolsStates(
|
|
23
|
+
store: Store,
|
|
24
|
+
): DevtoolsStates & IntrospectionStates & { store: Store } {
|
|
25
|
+
const introspectionStates = attachIntrospectionStates(store)
|
|
26
|
+
|
|
27
|
+
const devtoolsAreOpenState = createStandaloneAtom<boolean>(store, {
|
|
28
|
+
key: `🔍 Devtools Are Open`,
|
|
29
|
+
default: true,
|
|
30
|
+
effects:
|
|
31
|
+
typeof window === `undefined`
|
|
32
|
+
? []
|
|
33
|
+
: [persistSync(window.localStorage, JSON, `🔍 Devtools Are Open`)],
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
const devtoolsViewSelectionState = createStandaloneAtom<DevtoolsView>(store, {
|
|
37
|
+
key: `🔍 Devtools View Selection`,
|
|
38
|
+
default: `atoms`,
|
|
39
|
+
effects:
|
|
40
|
+
typeof window === `undefined`
|
|
41
|
+
? []
|
|
42
|
+
: [persistSync(window.localStorage, JSON, `🔍 Devtools View`)],
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
const devtoolsViewOptionsState = createStandaloneAtom<DevtoolsView[]>(store, {
|
|
46
|
+
key: `🔍 Devtools View Options`,
|
|
47
|
+
default: [`atoms`, `selectors`, `transactions`, `timelines`],
|
|
48
|
+
effects:
|
|
49
|
+
typeof window === `undefined`
|
|
50
|
+
? []
|
|
51
|
+
: [persistSync(window.localStorage, JSON, `🔍 Devtools View Options`)],
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
const viewIsOpenAtoms = createAtomFamily<boolean, string>(store, {
|
|
55
|
+
key: `🔍 Devtools View Is Open`,
|
|
56
|
+
default: false,
|
|
57
|
+
effects: (key) =>
|
|
58
|
+
typeof window === `undefined`
|
|
59
|
+
? []
|
|
60
|
+
: [persistSync(window.localStorage, JSON, key + `:view-is-open`)],
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
...introspectionStates,
|
|
65
|
+
devtoolsAreOpenState,
|
|
66
|
+
devtoolsViewSelectionState,
|
|
67
|
+
devtoolsViewOptionsState,
|
|
68
|
+
viewIsOpenAtoms,
|
|
69
|
+
store,
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export const DevtoolsContext = createContext<
|
|
74
|
+
DevtoolsStates & IntrospectionStates & { store: Store }
|
|
75
|
+
>(attachDevtoolsStates(IMPLICIT.STORE))
|