atom.io 0.33.11 → 0.33.12
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/react/index.js +2 -43
- package/dist/react/index.js.map +1 -1
- package/dist/react-devtools/index.css +86 -30
- package/dist/react-devtools/index.css.map +1 -1
- package/dist/react-devtools/index.d.ts +3 -0
- package/dist/react-devtools/index.d.ts.map +1 -1
- package/dist/react-devtools/index.js +174 -93
- package/dist/react-devtools/index.js.map +1 -1
- package/dist/use-o-BrXc7Qro.js +47 -0
- package/dist/use-o-BrXc7Qro.js.map +1 -0
- package/package.json +1 -1
- package/src/react-devtools/Button.tsx +1 -1
- package/src/react-devtools/devtools.css +86 -30
- package/src/react-devtools/json-editor/default-components.tsx +4 -1
- package/src/react-devtools/json-editor/editors-by-type/array-editor.tsx +80 -23
- package/src/react-devtools/json-editor/editors-by-type/object-editor.tsx +94 -16
- package/src/react-devtools/json-editor/json-editor-internal.tsx +105 -55
|
@@ -12,6 +12,7 @@ main[data-css="atom_io_devtools"] {
|
|
|
12
12
|
--bg-tint2: #333;
|
|
13
13
|
--fg-border: 1px solid var(--fg-color);
|
|
14
14
|
--fg-border-soft: 1px solid var(--fg-soft);
|
|
15
|
+
--fg-border-hint: 1px solid var(--fg-hint);
|
|
15
16
|
@media (prefers-color-scheme: light) {
|
|
16
17
|
--fg-color: #444;
|
|
17
18
|
--fg-light: #777;
|
|
@@ -120,7 +121,7 @@ main[data-css="atom_io_devtools"] {
|
|
|
120
121
|
&.transaction_update {
|
|
121
122
|
padding: 0;
|
|
122
123
|
}
|
|
123
|
-
header {
|
|
124
|
+
> header {
|
|
124
125
|
display: flex;
|
|
125
126
|
flex-flow: row;
|
|
126
127
|
position: sticky;
|
|
@@ -129,23 +130,6 @@ main[data-css="atom_io_devtools"] {
|
|
|
129
130
|
height: 22px;
|
|
130
131
|
background: var(--bg-tint2);
|
|
131
132
|
border-bottom: var(--fg-border-soft);
|
|
132
|
-
button.carat {
|
|
133
|
-
cursor: pointer;
|
|
134
|
-
background: none;
|
|
135
|
-
border: none;
|
|
136
|
-
width: 20px;
|
|
137
|
-
color: var(--fg-light);
|
|
138
|
-
&.open {
|
|
139
|
-
transform: rotate(90deg);
|
|
140
|
-
}
|
|
141
|
-
&:disabled {
|
|
142
|
-
cursor: default;
|
|
143
|
-
}
|
|
144
|
-
&:focus-within {
|
|
145
|
-
outline: 2px solid var(--fg-max);
|
|
146
|
-
background: var(--bg-max);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
133
|
> main {
|
|
150
134
|
display: flex;
|
|
151
135
|
flex-flow: row;
|
|
@@ -172,6 +156,9 @@ main[data-css="atom_io_devtools"] {
|
|
|
172
156
|
}
|
|
173
157
|
> .json_viewer {
|
|
174
158
|
color: var(--fg-light);
|
|
159
|
+
font-size: 14px;
|
|
160
|
+
flex-shrink: 1;
|
|
161
|
+
overflow-x: scroll;
|
|
175
162
|
}
|
|
176
163
|
> .json_editor,
|
|
177
164
|
> .json_viewer {
|
|
@@ -186,6 +173,9 @@ main[data-css="atom_io_devtools"] {
|
|
|
186
173
|
&:focus-within {
|
|
187
174
|
background-color: var(--bg-max);
|
|
188
175
|
outline: 2px solid var(--fg-max);
|
|
176
|
+
* {
|
|
177
|
+
color: var(--fg-max);
|
|
178
|
+
}
|
|
189
179
|
}
|
|
190
180
|
&.nu * {
|
|
191
181
|
display: flex;
|
|
@@ -310,6 +300,41 @@ main[data-css="atom_io_devtools"] {
|
|
|
310
300
|
}
|
|
311
301
|
|
|
312
302
|
.json_editor {
|
|
303
|
+
display: flex;
|
|
304
|
+
flex-flow: column;
|
|
305
|
+
align-items: flex-start;
|
|
306
|
+
> header {
|
|
307
|
+
display: flex;
|
|
308
|
+
flex-flow: row;
|
|
309
|
+
width: 100%;
|
|
310
|
+
position: relative;
|
|
311
|
+
align-items: baseline;
|
|
312
|
+
overflow: hidden;
|
|
313
|
+
white-space: nowrap;
|
|
314
|
+
> .json_viewer {
|
|
315
|
+
flex-shrink: 1;
|
|
316
|
+
overflow-x: scroll;
|
|
317
|
+
height: 21px;
|
|
318
|
+
font-size: 14px;
|
|
319
|
+
display: flex;
|
|
320
|
+
align-items: center;
|
|
321
|
+
margin-left: 6px;
|
|
322
|
+
color: var(--fg-light);
|
|
323
|
+
}
|
|
324
|
+
> button {
|
|
325
|
+
padding: 0;
|
|
326
|
+
&.carat {
|
|
327
|
+
line-height: 0.5em;
|
|
328
|
+
font-size: 14px;
|
|
329
|
+
align-self: flex-start;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
> .json_editor_array,
|
|
334
|
+
> .json_editor_object {
|
|
335
|
+
width: 100%;
|
|
336
|
+
flex-grow: 1;
|
|
337
|
+
}
|
|
313
338
|
input {
|
|
314
339
|
font-family: theia, monospace;
|
|
315
340
|
background: none;
|
|
@@ -323,6 +348,7 @@ main[data-css="atom_io_devtools"] {
|
|
|
323
348
|
&:focus-within {
|
|
324
349
|
outline: 2px solid var(--fg-max);
|
|
325
350
|
background: var(--bg-max);
|
|
351
|
+
color: var(--fg-max);
|
|
326
352
|
}
|
|
327
353
|
}
|
|
328
354
|
button:disabled {
|
|
@@ -345,6 +371,7 @@ main[data-css="atom_io_devtools"] {
|
|
|
345
371
|
font-family: theia, monospace;
|
|
346
372
|
font-size: 14px;
|
|
347
373
|
height: 21px;
|
|
374
|
+
min-width: 21px;
|
|
348
375
|
margin: none;
|
|
349
376
|
padding: 4px;
|
|
350
377
|
padding-bottom: 6px;
|
|
@@ -379,30 +406,33 @@ main[data-css="atom_io_devtools"] {
|
|
|
379
406
|
content: ":";
|
|
380
407
|
}
|
|
381
408
|
input {
|
|
382
|
-
color:
|
|
383
|
-
@media (prefers-color-scheme: light) {
|
|
384
|
-
color: #777;
|
|
385
|
-
}
|
|
409
|
+
color: var(--fg-color);
|
|
386
410
|
}
|
|
387
411
|
}
|
|
388
412
|
.json_editor_object,
|
|
389
413
|
.json_editor_array {
|
|
390
414
|
border-left: var(--fg-border-soft);
|
|
391
|
-
padding-left:
|
|
392
|
-
margin-left:
|
|
415
|
+
padding-left: 10px;
|
|
416
|
+
margin-left: 10px;
|
|
417
|
+
width: calc(100% - 21px);
|
|
393
418
|
.json_editor_properties,
|
|
394
419
|
.json_editor_elements {
|
|
395
420
|
.json_editor_property,
|
|
396
421
|
.json_editor_element {
|
|
422
|
+
display: flex;
|
|
397
423
|
border-bottom: var(--fg-border-soft);
|
|
398
424
|
margin-bottom: 2px;
|
|
399
425
|
min-height: 23px;
|
|
400
|
-
>
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
426
|
+
> header {
|
|
427
|
+
width: 100%;
|
|
428
|
+
|
|
429
|
+
> span {
|
|
430
|
+
input {
|
|
431
|
+
min-width: 10px;
|
|
432
|
+
}
|
|
433
|
+
> * {
|
|
434
|
+
border: var(--fg-border-hint);
|
|
435
|
+
}
|
|
406
436
|
}
|
|
407
437
|
}
|
|
408
438
|
}
|
|
@@ -420,4 +450,30 @@ main[data-css="atom_io_devtools"] {
|
|
|
420
450
|
}
|
|
421
451
|
}
|
|
422
452
|
}
|
|
453
|
+
|
|
454
|
+
.json_editor_icon {
|
|
455
|
+
color: var(--fg-soft);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
button.carat {
|
|
459
|
+
border: none;
|
|
460
|
+
cursor: pointer;
|
|
461
|
+
background: none;
|
|
462
|
+
&:focus-within {
|
|
463
|
+
outline: none;
|
|
464
|
+
background: none;
|
|
465
|
+
}
|
|
466
|
+
> .json_editor_icon {
|
|
467
|
+
line-height: 4px;
|
|
468
|
+
}
|
|
469
|
+
&.open {
|
|
470
|
+
transform: rotate(90deg);
|
|
471
|
+
}
|
|
472
|
+
&:disabled {
|
|
473
|
+
> .json_editor_icon {
|
|
474
|
+
cursor: default;
|
|
475
|
+
color: var(--fg-hint);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
423
479
|
}
|
|
@@ -18,6 +18,7 @@ export type JsonEditorComponents = {
|
|
|
18
18
|
disabled?: boolean
|
|
19
19
|
}>
|
|
20
20
|
DeleteIcon: FC
|
|
21
|
+
AddIcon: FC
|
|
21
22
|
|
|
22
23
|
EditorWrapper: WC<{
|
|
23
24
|
style?: CSSProperties | undefined
|
|
@@ -86,8 +87,10 @@ export const DEFAULT_JSON_EDITOR_COMPONENTS: JsonEditorComponents = {
|
|
|
86
87
|
<span className="json_editor_null" data-testid={testid} />
|
|
87
88
|
),
|
|
88
89
|
DeleteIcon: () => (
|
|
89
|
-
<span className="json_editor_icon json_editor_delete"
|
|
90
|
+
<span className="json_editor_icon json_editor_delete">×</span>
|
|
90
91
|
),
|
|
92
|
+
// big plus
|
|
93
|
+
AddIcon: () => <span className="json_editor_icon json_editor_add">+</span>,
|
|
91
94
|
MissingPropertyWrapper: ({ children, testid }) => (
|
|
92
95
|
<span className="json_editor_missing_property" data-testid={testid}>
|
|
93
96
|
{children}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import type { RegularAtomToken } from "atom.io"
|
|
2
|
+
import { findInStore } from "atom.io/internal"
|
|
3
|
+
import type { Json, JsonTypes } from "atom.io/json"
|
|
4
|
+
import { JSON_DEFAULTS } from "atom.io/json"
|
|
5
|
+
import { useI, useO } from "atom.io/react"
|
|
6
|
+
import { DevtoolsContext } from "atom.io/react-devtools/store"
|
|
7
|
+
import { type ReactElement, useContext } from "react"
|
|
3
8
|
|
|
9
|
+
import type { JsonEditorComponents, SetterOrUpdater } from ".."
|
|
4
10
|
import type { JsonEditorProps_INTERNAL } from "../json-editor-internal"
|
|
5
11
|
import { JsonEditor_INTERNAL } from "../json-editor-internal"
|
|
6
12
|
import { makeElementSetters } from "./utilities/array-elements"
|
|
@@ -9,6 +15,53 @@ import {
|
|
|
9
15
|
makePropertyRemovers,
|
|
10
16
|
} from "./utilities/object-properties"
|
|
11
17
|
|
|
18
|
+
type ArrayElementProps = {
|
|
19
|
+
path: ReadonlyArray<number | string>
|
|
20
|
+
isReadonly: (path: ReadonlyArray<number | string>) => boolean
|
|
21
|
+
isHidden: (path: ReadonlyArray<number | string>) => boolean
|
|
22
|
+
data: unknown
|
|
23
|
+
set: SetterOrUpdater<Json.Tree.Array>
|
|
24
|
+
remove: (() => void) | undefined
|
|
25
|
+
recast: (newType: keyof JsonTypes) => void
|
|
26
|
+
Components: JsonEditorComponents
|
|
27
|
+
testid?: string | undefined
|
|
28
|
+
viewIsOpenAtom: RegularAtomToken<boolean, string>
|
|
29
|
+
}
|
|
30
|
+
const ArrayElement = ({
|
|
31
|
+
path,
|
|
32
|
+
isReadonly,
|
|
33
|
+
isHidden,
|
|
34
|
+
data,
|
|
35
|
+
set,
|
|
36
|
+
remove,
|
|
37
|
+
recast,
|
|
38
|
+
Components,
|
|
39
|
+
testid,
|
|
40
|
+
viewIsOpenAtom,
|
|
41
|
+
}: ArrayElementProps): ReactElement => {
|
|
42
|
+
const index = path[path.length - 1]
|
|
43
|
+
const viewIsOpen = useO(viewIsOpenAtom)
|
|
44
|
+
const setViewIsOpen = useI(viewIsOpenAtom)
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<JsonEditor_INTERNAL
|
|
48
|
+
path={path}
|
|
49
|
+
name={`${index}`}
|
|
50
|
+
isReadonly={isReadonly}
|
|
51
|
+
isHidden={isHidden}
|
|
52
|
+
data={data}
|
|
53
|
+
set={set}
|
|
54
|
+
remove={remove}
|
|
55
|
+
recast={recast}
|
|
56
|
+
className="json_editor_element"
|
|
57
|
+
Components={Components}
|
|
58
|
+
isOpen={viewIsOpen}
|
|
59
|
+
setIsOpen={setViewIsOpen}
|
|
60
|
+
testid={`${testid}-element-${index}`}
|
|
61
|
+
/>
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
|
|
12
65
|
export const ArrayEditor = ({
|
|
13
66
|
path = [],
|
|
14
67
|
isReadonly = () => false,
|
|
@@ -18,6 +71,7 @@ export const ArrayEditor = ({
|
|
|
18
71
|
Components,
|
|
19
72
|
testid,
|
|
20
73
|
}: JsonEditorProps_INTERNAL<Json.Tree.Array>): ReactElement => {
|
|
74
|
+
const { viewIsOpenAtoms, store } = useContext(DevtoolsContext)
|
|
21
75
|
const disabled = isReadonly(path)
|
|
22
76
|
|
|
23
77
|
const setElement = makeElementSetters(data, set)
|
|
@@ -28,39 +82,42 @@ export const ArrayEditor = ({
|
|
|
28
82
|
<Components.ArrayWrapper>
|
|
29
83
|
<div className={`json_editor_elements${disabled ? ` readonly` : ``}`}>
|
|
30
84
|
{data.map((element, index) => {
|
|
31
|
-
const
|
|
85
|
+
const elementPath = [...path, index]
|
|
86
|
+
const pathKey = elementPath.join(`,`)
|
|
87
|
+
const viewIsOpenAtom = findInStore(
|
|
88
|
+
store,
|
|
89
|
+
viewIsOpenAtoms,
|
|
90
|
+
`${testid}__${pathKey}`,
|
|
91
|
+
)
|
|
32
92
|
return (
|
|
33
|
-
<
|
|
34
|
-
key={
|
|
35
|
-
path={
|
|
36
|
-
name={`${index}`}
|
|
93
|
+
<ArrayElement
|
|
94
|
+
key={pathKey}
|
|
95
|
+
path={elementPath}
|
|
37
96
|
isReadonly={isReadonly}
|
|
38
97
|
isHidden={isHidden}
|
|
39
98
|
data={element}
|
|
40
99
|
set={setElement[index]}
|
|
41
100
|
remove={removeElement[index]}
|
|
42
101
|
recast={recastElement[index]}
|
|
43
|
-
className="json_editor_element"
|
|
44
102
|
Components={Components}
|
|
45
|
-
testid={
|
|
103
|
+
testid={testid}
|
|
104
|
+
viewIsOpenAtom={viewIsOpenAtom}
|
|
46
105
|
/>
|
|
47
106
|
)
|
|
48
107
|
})}
|
|
49
108
|
</div>
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
</Components.Button>
|
|
63
|
-
)}
|
|
109
|
+
<Components.Button
|
|
110
|
+
testid={`${testid}-add-element`}
|
|
111
|
+
disabled={disabled}
|
|
112
|
+
onClick={() => {
|
|
113
|
+
set((current) => {
|
|
114
|
+
const newData = [...current, JSON_DEFAULTS.string]
|
|
115
|
+
return newData
|
|
116
|
+
})
|
|
117
|
+
}}
|
|
118
|
+
>
|
|
119
|
+
<Components.AddIcon />
|
|
120
|
+
</Components.Button>
|
|
64
121
|
</Components.ArrayWrapper>
|
|
65
122
|
)
|
|
66
123
|
}
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { RegularAtomToken } from "atom.io"
|
|
2
|
+
import { findInStore } from "atom.io/internal"
|
|
3
|
+
import type { Json, JsonTypes } from "atom.io/json"
|
|
4
|
+
import { useI } from "atom.io/react/use-i"
|
|
5
|
+
import { useO } from "atom.io/react/use-o"
|
|
6
|
+
import { DevtoolsContext } from "atom.io/react-devtools/store"
|
|
2
7
|
import type { FC, ReactElement } from "react"
|
|
3
|
-
import { useRef } from "react"
|
|
8
|
+
import { useContext, useRef } from "react"
|
|
4
9
|
|
|
5
10
|
import { ElasticInput } from "../../elastic-input"
|
|
11
|
+
import type { SetterOrUpdater } from ".."
|
|
6
12
|
import type { JsonEditorComponents } from "../default-components"
|
|
7
13
|
import type { JsonEditorProps_INTERNAL } from "../json-editor-internal"
|
|
8
14
|
import { JsonEditor_INTERNAL } from "../json-editor-internal"
|
|
@@ -43,6 +49,56 @@ export const PropertyAdder: FC<PropertyAdderProps> = ({
|
|
|
43
49
|
</Components.MissingPropertyWrapper>
|
|
44
50
|
)
|
|
45
51
|
|
|
52
|
+
type ObjectPropertyProps = {
|
|
53
|
+
path: ReadonlyArray<number | string>
|
|
54
|
+
isReadonly: (path: ReadonlyArray<number | string>) => boolean
|
|
55
|
+
isHidden: (path: ReadonlyArray<number | string>) => boolean
|
|
56
|
+
data: unknown
|
|
57
|
+
set: SetterOrUpdater<Json.Tree.Object>
|
|
58
|
+
rename: (newKey: string) => void
|
|
59
|
+
remove: (() => void) | undefined
|
|
60
|
+
recast: (newType: keyof JsonTypes) => void
|
|
61
|
+
Components: JsonEditorComponents
|
|
62
|
+
testid?: string | undefined
|
|
63
|
+
viewIsOpenAtom: RegularAtomToken<boolean, string>
|
|
64
|
+
}
|
|
65
|
+
const ObjectProperty = ({
|
|
66
|
+
path,
|
|
67
|
+
isReadonly,
|
|
68
|
+
isHidden,
|
|
69
|
+
data,
|
|
70
|
+
set,
|
|
71
|
+
rename,
|
|
72
|
+
remove,
|
|
73
|
+
recast,
|
|
74
|
+
Components,
|
|
75
|
+
testid,
|
|
76
|
+
viewIsOpenAtom,
|
|
77
|
+
}: ObjectPropertyProps): ReactElement => {
|
|
78
|
+
const key = path[path.length - 1]
|
|
79
|
+
const viewIsOpen = useO(viewIsOpenAtom)
|
|
80
|
+
const setViewIsOpen = useI(viewIsOpenAtom)
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<JsonEditor_INTERNAL
|
|
84
|
+
path={path}
|
|
85
|
+
name={`${key}`}
|
|
86
|
+
isReadonly={isReadonly}
|
|
87
|
+
isHidden={isHidden}
|
|
88
|
+
data={data}
|
|
89
|
+
set={set}
|
|
90
|
+
rename={rename}
|
|
91
|
+
remove={remove}
|
|
92
|
+
recast={recast}
|
|
93
|
+
className="json_editor_property"
|
|
94
|
+
Components={Components}
|
|
95
|
+
isOpen={viewIsOpen}
|
|
96
|
+
setIsOpen={setViewIsOpen}
|
|
97
|
+
testid={`${testid}-property-${key}`}
|
|
98
|
+
/>
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
46
102
|
export const ObjectEditor = <T extends Json.Tree.Object>({
|
|
47
103
|
path = [],
|
|
48
104
|
isReadonly = () => false,
|
|
@@ -52,6 +108,8 @@ export const ObjectEditor = <T extends Json.Tree.Object>({
|
|
|
52
108
|
Components,
|
|
53
109
|
testid,
|
|
54
110
|
}: JsonEditorProps_INTERNAL<T>): ReactElement => {
|
|
111
|
+
const { viewIsOpenAtoms, store } = useContext(DevtoolsContext)
|
|
112
|
+
|
|
55
113
|
const disabled = isReadonly(path)
|
|
56
114
|
|
|
57
115
|
const stableKeyMap = useRef<Record<keyof T, keyof T>>(
|
|
@@ -76,24 +134,44 @@ export const ObjectEditor = <T extends Json.Tree.Object>({
|
|
|
76
134
|
<div className={`json_editor_properties${disabled ? ` readonly` : ``}`}>
|
|
77
135
|
{Object.keys(data).map((key) => {
|
|
78
136
|
const originalKey = stableKeyMap.current[key]
|
|
79
|
-
const
|
|
80
|
-
const
|
|
137
|
+
const propertyPath = [...path, key]
|
|
138
|
+
const originalPropertyPath = [...path, originalKey]
|
|
139
|
+
const stablePathKey = originalPropertyPath.join(`.`)
|
|
140
|
+
const viewIsOpenAtom = findInStore(
|
|
141
|
+
store,
|
|
142
|
+
viewIsOpenAtoms,
|
|
143
|
+
`${testid}__${stablePathKey}`,
|
|
144
|
+
)
|
|
81
145
|
|
|
82
146
|
return (
|
|
83
|
-
<JsonEditor_INTERNAL
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
147
|
+
// <JsonEditor_INTERNAL
|
|
148
|
+
// key={originalPath.join(`.`)}
|
|
149
|
+
// path={newPath}
|
|
150
|
+
// name={key}
|
|
151
|
+
// isReadonly={isReadonly}
|
|
152
|
+
// isHidden={isHidden}
|
|
153
|
+
// data={data[key as keyof T]}
|
|
154
|
+
// set={setProperty[key as keyof T]}
|
|
155
|
+
// rename={renameProperty[key as keyof T]}
|
|
156
|
+
// remove={removeProperty[key as keyof T]}
|
|
157
|
+
// recast={recastProperty[key as keyof T]}
|
|
158
|
+
// className="json_editor_property"
|
|
159
|
+
// Components={Components}
|
|
160
|
+
// testid={`${testid}-property-${key}`}
|
|
161
|
+
// />
|
|
162
|
+
<ObjectProperty
|
|
163
|
+
key={stablePathKey}
|
|
164
|
+
path={propertyPath}
|
|
87
165
|
isReadonly={isReadonly}
|
|
88
166
|
isHidden={isHidden}
|
|
89
|
-
data={data[key
|
|
90
|
-
set={setProperty[key
|
|
91
|
-
rename={renameProperty[key
|
|
92
|
-
remove={removeProperty[key
|
|
93
|
-
recast={recastProperty[key
|
|
94
|
-
className="json_editor_property"
|
|
167
|
+
data={data[key]}
|
|
168
|
+
set={setProperty[key]}
|
|
169
|
+
rename={renameProperty[key]}
|
|
170
|
+
remove={removeProperty[key]}
|
|
171
|
+
recast={recastProperty[key]}
|
|
95
172
|
Components={Components}
|
|
96
|
-
testid={
|
|
173
|
+
testid={testid}
|
|
174
|
+
viewIsOpenAtom={viewIsOpenAtom}
|
|
97
175
|
/>
|
|
98
176
|
)
|
|
99
177
|
})}
|
|
@@ -107,7 +185,7 @@ export const ObjectEditor = <T extends Json.Tree.Object>({
|
|
|
107
185
|
makePropertyAdder(`new_property`, `string`)()
|
|
108
186
|
}}
|
|
109
187
|
>
|
|
110
|
-
|
|
188
|
+
<Components.AddIcon />
|
|
111
189
|
</Components.Button>
|
|
112
190
|
<Components.Button
|
|
113
191
|
testid={`${testid}-sort-properties`}
|
|
@@ -3,6 +3,7 @@ import type { JsonTypes } from "atom.io/json"
|
|
|
3
3
|
import { isJson } from "atom.io/json"
|
|
4
4
|
import type { CSSProperties, FC, ReactElement } from "react"
|
|
5
5
|
|
|
6
|
+
import { button } from "../Button"
|
|
6
7
|
import { ElasticInput } from "../elastic-input"
|
|
7
8
|
import type { SetterOrUpdater } from "."
|
|
8
9
|
import { SubEditors } from "."
|
|
@@ -23,6 +24,8 @@ export type JsonEditorProps_INTERNAL<T> = {
|
|
|
23
24
|
style?: CSSProperties | undefined
|
|
24
25
|
Header?: FC<{ data: T }> | undefined
|
|
25
26
|
Components: JsonEditorComponents
|
|
27
|
+
isOpen?: boolean
|
|
28
|
+
setIsOpen?: (newValue: boolean) => void
|
|
26
29
|
testid?: string | undefined
|
|
27
30
|
}
|
|
28
31
|
|
|
@@ -38,8 +41,9 @@ export const JsonEditor_INTERNAL = <T,>({
|
|
|
38
41
|
isHidden = () => false,
|
|
39
42
|
className,
|
|
40
43
|
style,
|
|
41
|
-
Header: HeaderDisplay,
|
|
42
44
|
Components,
|
|
45
|
+
isOpen,
|
|
46
|
+
setIsOpen,
|
|
43
47
|
testid,
|
|
44
48
|
}: JsonEditorProps_INTERNAL<T>): ReactElement | null => {
|
|
45
49
|
const dataIsJson = isJson(data)
|
|
@@ -53,6 +57,8 @@ export const JsonEditor_INTERNAL = <T,>({
|
|
|
53
57
|
|
|
54
58
|
const disabled = isReadonly(path)
|
|
55
59
|
|
|
60
|
+
const dataIsTree = refined.type === `array` || refined.type === `object`
|
|
61
|
+
|
|
56
62
|
return isHidden(path) ? null : (
|
|
57
63
|
<Components.ErrorBoundary>
|
|
58
64
|
<Components.EditorWrapper
|
|
@@ -60,64 +66,108 @@ export const JsonEditor_INTERNAL = <T,>({
|
|
|
60
66
|
style={style}
|
|
61
67
|
testid={testid}
|
|
62
68
|
>
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
onClick={() => {
|
|
67
|
-
remove()
|
|
68
|
-
}}
|
|
69
|
-
testid={`${testid}-delete`}
|
|
70
|
-
>
|
|
71
|
-
<Components.DeleteIcon />
|
|
72
|
-
</Components.Button>
|
|
73
|
-
) : null}
|
|
74
|
-
{HeaderDisplay && <HeaderDisplay data={data} />}
|
|
75
|
-
{rename && (
|
|
76
|
-
<Components.KeyWrapper>
|
|
77
|
-
<ElasticInput
|
|
78
|
-
value={name}
|
|
79
|
-
onChange={
|
|
80
|
-
disabled
|
|
81
|
-
? undefined
|
|
82
|
-
: (e) => {
|
|
83
|
-
rename(e.target.value)
|
|
84
|
-
}
|
|
85
|
-
}
|
|
69
|
+
<header>
|
|
70
|
+
{remove ? (
|
|
71
|
+
<Components.Button
|
|
86
72
|
disabled={disabled}
|
|
87
|
-
|
|
73
|
+
onClick={() => {
|
|
74
|
+
remove()
|
|
75
|
+
}}
|
|
76
|
+
testid={`${testid}-delete`}
|
|
77
|
+
>
|
|
78
|
+
<Components.DeleteIcon />
|
|
79
|
+
</Components.Button>
|
|
80
|
+
) : null}
|
|
81
|
+
{dataIsTree && isOpen !== undefined && setIsOpen ? (
|
|
82
|
+
<button.OpenClose
|
|
83
|
+
isOpen={isOpen}
|
|
84
|
+
testid={`${testid}-open-close`}
|
|
85
|
+
setIsOpen={setIsOpen}
|
|
88
86
|
/>
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
: (e) => {
|
|
87
|
+
) : null}
|
|
88
|
+
{rename && (
|
|
89
|
+
<Components.KeyWrapper>
|
|
90
|
+
<ElasticInput
|
|
91
|
+
value={name}
|
|
92
|
+
onChange={(e) => {
|
|
93
|
+
rename(e.target.value)
|
|
94
|
+
}}
|
|
95
|
+
disabled={disabled}
|
|
96
|
+
data-testid={`${testid}-rename`}
|
|
97
|
+
/>
|
|
98
|
+
</Components.KeyWrapper>
|
|
99
|
+
)}
|
|
100
|
+
{dataIsTree ? (
|
|
101
|
+
<>
|
|
102
|
+
{recast ? (
|
|
103
|
+
<select
|
|
104
|
+
onChange={(e) => {
|
|
108
105
|
recast(e.target.value as keyof JsonTypes)
|
|
106
|
+
}}
|
|
107
|
+
value={refined.type}
|
|
108
|
+
disabled={disabled}
|
|
109
|
+
data-testid={`${testid}-recast`}
|
|
110
|
+
>
|
|
111
|
+
{Object.keys(SubEditors).map((type) => (
|
|
112
|
+
<option key={type} value={type}>
|
|
113
|
+
{type}
|
|
114
|
+
</option>
|
|
115
|
+
))}
|
|
116
|
+
</select>
|
|
117
|
+
) : null}
|
|
118
|
+
{isOpen !== undefined && setIsOpen ? (
|
|
119
|
+
<span className="json_viewer">{JSON.stringify(data)}</span>
|
|
120
|
+
) : null}
|
|
121
|
+
</>
|
|
122
|
+
) : (
|
|
123
|
+
<>
|
|
124
|
+
<SubEditor
|
|
125
|
+
data={refined.data as never}
|
|
126
|
+
set={set}
|
|
127
|
+
remove={remove}
|
|
128
|
+
rename={rename}
|
|
129
|
+
path={path}
|
|
130
|
+
isReadonly={isReadonly}
|
|
131
|
+
isHidden={isHidden}
|
|
132
|
+
Components={Components}
|
|
133
|
+
testid={testid}
|
|
134
|
+
/>
|
|
135
|
+
{recast && dataIsJson ? (
|
|
136
|
+
<select
|
|
137
|
+
onChange={
|
|
138
|
+
disabled
|
|
139
|
+
? undefined
|
|
140
|
+
: (e) => {
|
|
141
|
+
recast(e.target.value as keyof JsonTypes)
|
|
142
|
+
}
|
|
109
143
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
144
|
+
value={refined.type}
|
|
145
|
+
disabled={disabled}
|
|
146
|
+
data-testid={`${testid}-recast`}
|
|
147
|
+
>
|
|
148
|
+
{Object.keys(SubEditors).map((type) => (
|
|
149
|
+
<option key={type} value={type}>
|
|
150
|
+
{type}
|
|
151
|
+
</option>
|
|
152
|
+
))}
|
|
153
|
+
</select>
|
|
154
|
+
) : null}
|
|
155
|
+
</>
|
|
156
|
+
)}
|
|
157
|
+
</header>
|
|
158
|
+
|
|
159
|
+
{dataIsTree && isOpen !== false ? (
|
|
160
|
+
<SubEditor
|
|
161
|
+
data={refined.data as never}
|
|
162
|
+
set={set}
|
|
163
|
+
remove={remove}
|
|
164
|
+
rename={rename}
|
|
165
|
+
path={path}
|
|
166
|
+
isReadonly={isReadonly}
|
|
167
|
+
isHidden={isHidden}
|
|
168
|
+
Components={Components}
|
|
169
|
+
testid={testid}
|
|
170
|
+
/>
|
|
121
171
|
) : null}
|
|
122
172
|
</Components.EditorWrapper>
|
|
123
173
|
</Components.ErrorBoundary>
|