Refactored KeyValue toggle so columns with toggles align better below those without
Brian Vaughn committed
Apr 10, 2019 at 11:44 UTC
4f254c0a05cc6eba1aa8828736ef3617fc54017a
2 files changed
+51
-44
src/devtools/views/Components/KeyValue.css
+2
-1
@@ -5,6 +5,7 @@
5
.Name {
6
color: var(--color-dim);
7
flex: 0 0 auto;
8
+ user-select: none;
9
}
10
.EditableName {
11
color: var(--color-attribute-name);
@@ -27,7 +28,7 @@
28
font-style: italic;
29
}
30
30
-.Opener {
31
+.ExpandCollapseToggle {
32
display: inline-flex;
33
width: 1rem;
34
height: 1rem;
src/devtools/views/Components/KeyValue.js
+49
-43
@@ -1,6 +1,6 @@
1
// @flow
2
3
-import React, { useState } from 'react';
3
+import React, { useCallback, useState } from 'react';
4
import type { Element } from 'react';
5
import EditableValue from './EditableValue';
6
import Button from '../Button';
@@ -26,11 +26,7 @@ export default function KeyValue({
26
path = [],
27
value,
28
}: KeyValueProps) {
29
- const [open, setOpen] = useState(false);
30
-
31
- const handleToggle = () => {
32
- setOpen(prevOpen => !prevOpen);
33
- };
29
+ const [isOpen, setIsOpen] = useState<boolean>(true);
30
31
const dataType = typeof value;
32
const isSimpleType =
@@ -39,7 +35,9 @@ export default function KeyValue({
35
dataType === 'boolean' ||
36
value == null;
37
42
- const paddingLeft = `${depth * 0.75}rem`;
38
+ const style = {
39
+ paddingLeft: `${(depth - 1) * 0.75}rem`,
40
+ };
41
42
let children = null;
43
if (isSimpleType) {
@@ -58,7 +56,8 @@ export default function KeyValue({
56
typeof overrideValueFn === 'function' ? styles.EditableName : styles.Name;
57
58
children = (
61
- <div key="root" className={styles.Item} style={{ paddingLeft }}>
59
+ <div key="root" className={styles.Item} style={style}>
60
+ <div className={styles.ExpandCollapseToggle} />
61
<span className={nameClassName}>{name}</span>
62
{typeof overrideValueFn === 'function' ? (
63
<EditableValue
@@ -75,26 +74,17 @@ export default function KeyValue({
74
} else if (value.hasOwnProperty(meta.type)) {
75
// TODO Is this type even necessary? Can we just drop it?
76
children = (
78
- <div key="root" className={styles.Item} style={{ paddingLeft }}>
77
+ <div key="root" className={styles.Item} style={style}>
78
+ <div className={styles.ExpandCollapseToggle} />
79
<span className={styles.Name}>{name}</span>
80
<span className={styles.Value}>{getMetaValueLabel(value)}</span>
81
</div>
82
);
83
} else {
84
- const opener = (
85
- <Button
86
- className={styles.Opener}
87
- onClick={handleToggle}
88
- title={`${open ? 'Collapse' : 'Expand'} prop value`}
89
- >
90
- <ButtonIcon type={open ? 'expanded' : 'collapsed'} />
91
- </Button>
92
- );
93
-
84
if (Array.isArray(value)) {
95
- const showOpener = value.length > 0;
85
+ const hasChildren = value.length > 0;
86
97
- children = open
87
+ children = isOpen
88
? value.map((innerValue, index) => (
89
<KeyValue
90
key={index}
@@ -107,24 +97,20 @@ export default function KeyValue({
97
))
98
: [];
99
children.unshift(
110
- <div
111
- key={`${depth}-root`}
112
- className={styles.Item}
113
- style={{
114
- paddingLeft: showOpener
115
- ? `calc(${paddingLeft} - 1rem)`
116
- : paddingLeft,
117
- }}
118
- >
119
- {showOpener && opener}
100
+ <div key={`${depth}-root`} className={styles.Item} style={style}>
101
+ {hasChildren ? (
102
+ <ExpandCollapseToggle isOpen={isOpen} setIsOpen={setIsOpen} />
103
+ ) : (
104
+ <div className={styles.ExpandCollapseToggle} />
105
+ )}
106
<span className={styles.Name}>{name}</span>
107
<span>Array</span>
108
</div>
109
);
110
} else {
125
- const showOpener = Object.entries(value).length > 0;
111
+ const hasChildren = Object.entries(value).length > 0;
112
127
- children = open
113
+ children = isOpen
114
? Object.entries(value).map<Element<any>>(([name, value]) => (
115
<KeyValue
116
key={name}
@@ -137,16 +123,12 @@ export default function KeyValue({
123
))
124
: [];
125
children.unshift(
140
- <div
141
- key={`${depth}-root`}
142
- className={styles.Item}
143
- style={{
144
- paddingLeft: showOpener
145
- ? `calc(${paddingLeft} - 1rem)`
146
- : paddingLeft,
147
- }}
148
- >
149
- {showOpener && opener}
126
+ <div key={`${depth}-root`} className={styles.Item} style={style}>
127
+ {hasChildren ? (
128
+ <ExpandCollapseToggle isOpen={isOpen} setIsOpen={setIsOpen} />
129
+ ) : (
130
+ <div className={styles.ExpandCollapseToggle} />
131
+ )}
132
<span className={styles.Name}>{name}</span>
133
<span>Object</span>
134
</div>
@@ -156,3 +138,27 @@ export default function KeyValue({
138
139
return children;
140
}
141
+
142
+type ExpandCollapseToggleProps = {|
143
+ isOpen: boolean,
144
+ setIsOpen: Function,
145
+|};
146
+
147
+function ExpandCollapseToggle({
148
+ isOpen,
149
+ setIsOpen,
150
+}: ExpandCollapseToggleProps) {
151
+ const handleClick = useCallback(() => {
152
+ setIsOpen(prevIsOpen => !prevIsOpen);
153
+ }, [setIsOpen]);
154
+
155
+ return (
156
+ <Button
157
+ className={styles.ExpandCollapseToggle}
158
+ onClick={handleClick}
159
+ title={`${isOpen ? 'Collapse' : 'Expand'} prop value`}
160
+ >
161
+ <ButtonIcon type={isOpen ? 'expanded' : 'collapsed'} />
162
+ </Button>
163
+ );
164
+}