Improved keyboard UX and focus UI for Tree and OwnersStack
Brian Vaughn committed
Apr 5, 2019 at 08:08 UTC
d1a5346c48323a8ed02c081ac97f8c60c4fb30a7
5 files changed
+52
-13
src/devtools/views/Components/OwnersStack.css
+9
@@ -14,6 +14,8 @@
14
font-size: var(--font-size-monospace-normal);
15
white-space: nowrap;
16
border-radius: 0.125rem;
17
+ border: none;
18
+ background: none;
19
}
20
21
.Component {
@@ -23,11 +25,18 @@
25
.Component:hover {
26
background-color: var(--color-hover-background);
27
}
28
+.Component:focus {
29
+ outline: none;
30
+ background-color: var(--color-hover-background);
31
+}
32
33
.FocusedComponent {
34
background-color: var(--color-selected-background);
35
color: var(--color-selected-foreground);
36
}
37
+.FocusedComponent:focus {
38
+ outline: none;
39
+}
40
41
.VRule {
42
height: 20px;
src/devtools/views/Components/OwnersStack.js
+6
-8
@@ -42,22 +42,20 @@ function ElementView({ id, index }: Props) {
42
const store = useContext(StoreContext);
43
const { displayName } = ((store.getElementByID(id): any): Element);
44
45
- const isCurrentlyFocusedOwner = ownerStackIndex === index;
45
+ const isSelected = ownerStackIndex === index;
46
47
const handleClick = useCallback(() => {
48
- if (!isCurrentlyFocusedOwner) {
48
+ if (!isSelected) {
49
selectOwner(id);
50
}
51
- }, [id, isCurrentlyFocusedOwner, selectOwner]);
51
+ }, [id, isSelected, selectOwner]);
52
53
return (
54
- <span
55
- className={
56
- isCurrentlyFocusedOwner ? styles.FocusedComponent : styles.Component
57
- }
54
+ <button
55
+ className={isSelected ? styles.FocusedComponent : styles.Component}
56
onClick={handleClick}
57
>
58
{displayName}
61
- </span>
59
+ </button>
60
);
61
}
src/devtools/views/Components/Tree.css
+8
-1
@@ -18,11 +18,18 @@
18
width: 100%;
19
overflow: auto;
20
flex: 1 0 auto;
21
- padding: 0.25rem;
21
}
22
23
.List {
24
font-family: var(--font-family-monospace);
25
font-size: var(--font-size-monospace-normal);
26
line-height: var(--line-height-data);
27
+ border: 0.25rem solid transparent;
28
+}
29
+.List:focus-within {
30
+ border-color: var(--color-button-background-focus);
31
+}
32
+
33
+.InnerElementType:focus {
34
+ outline: none;
35
}
src/devtools/views/Components/Tree.js
+22
-1
@@ -1,6 +1,7 @@
1
// @flow
2
3
import React, {
4
+ useCallback,
5
useContext,
6
useEffect,
7
useMemo,
@@ -132,8 +133,10 @@ export default function Tree(props: Props) {
133
function InnerElementType({ style, ...rest }) {
134
const {
135
numElements,
136
+ selectedElementID,
137
selectedElementIndex,
138
selectElementAtIndex,
139
+ selectOwner,
140
} = useContext(TreeContext);
141
142
const handleFocus = () => {
@@ -142,20 +145,38 @@ function InnerElementType({ style, ...rest }) {
145
}
146
};
147
148
+ const handleKeyPress = useCallback(
149
+ event => {
150
+ switch (event.key) {
151
+ case 'Enter':
152
+ case ' ':
153
+ if (selectedElementID !== null) {
154
+ selectOwner(selectedElementID);
155
+ }
156
+ break;
157
+ default:
158
+ break;
159
+ }
160
+ },
161
+ [selectedElementID, selectOwner]
162
+ );
163
+
164
// This style override enables the background color to fill the full visible width,
165
// when combined with the CSS tweaks in Element.
166
// A lot of options were considered; this seemed the one that requires the least code.
167
// See https://github.com/bvaughn/react-devtools-experimental/issues/9
168
return (
169
<div
151
- tabIndex={0}
170
+ className={styles.InnerElementType}
171
onFocus={handleFocus}
172
+ onKeyPress={handleKeyPress}
173
style={{
174
...style,
175
display: 'inline-block',
176
minWidth: '100%',
177
width: undefined,
178
}}
179
+ tabIndex={0}
180
{...rest}
181
/>
182
);
src/devtools/views/Components/TreeContext.js
+7
-3
@@ -134,9 +134,11 @@ function reduceTreeState(store: Store, state: State, action: Action): State {
134
break;
135
case 'SELECT_NEXT_ELEMENT_IN_TREE':
136
if (
137
- selectedElementIndex !== null &&
138
- selectedElementIndex + 1 < numElements
137
+ selectedElementIndex === null ||
138
+ selectedElementIndex + 1 >= numElements
139
) {
140
+ selectedElementIndex = 0;
141
+ } else {
142
selectedElementIndex++;
143
}
144
break;
@@ -152,7 +154,9 @@ function reduceTreeState(store: Store, state: State, action: Action): State {
154
}
155
break;
156
case 'SELECT_PREVIOUS_ELEMENT_IN_TREE':
155
- if (selectedElementIndex !== null && selectedElementIndex > 0) {
157
+ if (selectedElementIndex === null || selectedElementIndex === 0) {
158
+ selectedElementIndex = numElements - 1;
159
+ } else {
160
selectedElementIndex--;
161
}
162
break;