@samitouri / QOS-React / commits / d1a5346c48

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;