@atlaskit/editor-common 78.37.1 → 78.37.3
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/CHANGELOG.md +14 -0
- package/dist/cjs/element-browser/components/CategoryList.js +89 -8
- package/dist/cjs/element-browser/components/ElementList/ElementList.js +30 -4
- package/dist/cjs/element-browser/components/StatelessElementBrowser.js +77 -12
- package/dist/cjs/element-browser/hooks/use-select-and-focus-on-arrow-navigation.js +38 -4
- package/dist/cjs/monitoring/error.js +1 -1
- package/dist/cjs/ui/DropList/index.js +1 -1
- package/dist/es2019/element-browser/components/CategoryList.js +96 -12
- package/dist/es2019/element-browser/components/ElementList/ElementList.js +29 -3
- package/dist/es2019/element-browser/components/StatelessElementBrowser.js +78 -13
- package/dist/es2019/element-browser/hooks/use-select-and-focus-on-arrow-navigation.js +39 -5
- package/dist/es2019/monitoring/error.js +1 -1
- package/dist/es2019/ui/DropList/index.js +1 -1
- package/dist/esm/element-browser/components/CategoryList.js +89 -9
- package/dist/esm/element-browser/components/ElementList/ElementList.js +30 -4
- package/dist/esm/element-browser/components/StatelessElementBrowser.js +78 -13
- package/dist/esm/element-browser/hooks/use-select-and-focus-on-arrow-navigation.js +38 -4
- package/dist/esm/monitoring/error.js +1 -1
- package/dist/esm/ui/DropList/index.js +1 -1
- package/dist/types/element-browser/components/CategoryList.d.ts +5 -0
- package/dist/types/element-browser/components/ElementList/ElementList.d.ts +2 -0
- package/dist/types/element-browser/hooks/use-select-and-focus-on-arrow-navigation.d.ts +4 -1
- package/dist/types/types/annotation/index.d.ts +1 -1
- package/dist/types-ts4.5/element-browser/components/CategoryList.d.ts +5 -0
- package/dist/types-ts4.5/element-browser/components/ElementList/ElementList.d.ts +2 -0
- package/dist/types-ts4.5/element-browser/hooks/use-select-and-focus-on-arrow-navigation.d.ts +4 -1
- package/dist/types-ts4.5/types/annotation/index.d.ts +1 -1
- package/package.json +9 -6
|
@@ -1,26 +1,64 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/extends";
|
|
2
2
|
/** @jsx jsx */
|
|
3
|
-
|
|
4
3
|
import React, { Fragment, memo, useCallback } from 'react';
|
|
5
4
|
import { css, jsx } from '@emotion/react';
|
|
6
5
|
import { withAnalyticsContext } from '@atlaskit/analytics-next';
|
|
7
6
|
import Button from '@atlaskit/button/custom-theme-button';
|
|
7
|
+
import { getBooleanFF } from '@atlaskit/platform-feature-flags';
|
|
8
8
|
import { B400, B50, N800 } from '@atlaskit/theme/colors';
|
|
9
9
|
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, fireAnalyticsEvent } from '../../analytics';
|
|
10
10
|
import { DEVICE_BREAKPOINT_NUMBERS, GRID_SIZE } from '../constants';
|
|
11
11
|
import useFocus from '../hooks/use-focus';
|
|
12
|
+
const arrowsKeys = new Set(['ArrowUp', 'ArrowDown']);
|
|
12
13
|
function CategoryList({
|
|
13
14
|
categories = [],
|
|
14
15
|
...props
|
|
15
16
|
}) {
|
|
16
|
-
const [
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
17
|
+
const [focusedCategoryIndexState, setFocusedCategoryIndexState] = React.useState(null);
|
|
18
|
+
const {
|
|
19
|
+
focusedCategoryIndex: focusedCategoryIndexProp,
|
|
20
|
+
setFocusedCategoryIndex: setFocusedCategoryIndexProp,
|
|
21
|
+
onSelectCategory
|
|
22
|
+
} = props;
|
|
23
|
+
const focusedCategoryIndex = getBooleanFF('platform.editor.a11y-focus-order-for-element-browser-categories_ztiw1') ? focusedCategoryIndexProp : focusedCategoryIndexState;
|
|
24
|
+
const setFocusedCategoryIndex = getBooleanFF('platform.editor.a11y-focus-order-for-element-browser-categories_ztiw1') ? setFocusedCategoryIndexProp : setFocusedCategoryIndexState;
|
|
25
|
+
return jsx(Fragment, null, categories.map((category, index) => {
|
|
26
|
+
const categoriesLength = categories === null || categories === void 0 ? void 0 : categories.length;
|
|
27
|
+
let selectNextCategory;
|
|
28
|
+
let selectPreviousCategory;
|
|
29
|
+
if (getBooleanFF('platform.editor.a11y-focus-order-for-element-browser-categories_ztiw1') && categoriesLength > 1) {
|
|
30
|
+
selectNextCategory = () => {
|
|
31
|
+
if (index !== categoriesLength - 1) {
|
|
32
|
+
setFocusedCategoryIndex(index + 1);
|
|
33
|
+
onSelectCategory(categories[index + 1]);
|
|
34
|
+
} else {
|
|
35
|
+
setFocusedCategoryIndex(0);
|
|
36
|
+
onSelectCategory(categories[0]);
|
|
37
|
+
}
|
|
38
|
+
return;
|
|
39
|
+
};
|
|
40
|
+
selectPreviousCategory = () => {
|
|
41
|
+
if (index !== 0) {
|
|
42
|
+
setFocusedCategoryIndex(index - 1);
|
|
43
|
+
onSelectCategory(categories[index - 1]);
|
|
44
|
+
} else {
|
|
45
|
+
setFocusedCategoryIndex(categoriesLength - 1);
|
|
46
|
+
onSelectCategory(categories[categoriesLength - 1]);
|
|
47
|
+
}
|
|
48
|
+
return;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
return jsx(CategoryListItem, _extends({
|
|
52
|
+
key: category.title,
|
|
53
|
+
index: index,
|
|
54
|
+
category: category,
|
|
55
|
+
focus: focusedCategoryIndex === index
|
|
56
|
+
}, props, {
|
|
57
|
+
setFocusedCategoryIndex: setFocusedCategoryIndex,
|
|
58
|
+
selectPreviousCategory: selectPreviousCategory,
|
|
59
|
+
selectNextCategory: selectNextCategory
|
|
60
|
+
}));
|
|
61
|
+
}));
|
|
24
62
|
}
|
|
25
63
|
function CategoryListItem({
|
|
26
64
|
category,
|
|
@@ -29,11 +67,17 @@ function CategoryListItem({
|
|
|
29
67
|
index,
|
|
30
68
|
focus,
|
|
31
69
|
setFocusedCategoryIndex,
|
|
32
|
-
createAnalyticsEvent
|
|
70
|
+
createAnalyticsEvent,
|
|
71
|
+
setFocusedItemIndex,
|
|
72
|
+
setFocusOnSearch,
|
|
73
|
+
selectPreviousCategory,
|
|
74
|
+
selectNextCategory
|
|
33
75
|
}) {
|
|
34
76
|
const ref = useFocus(focus);
|
|
35
77
|
const onClick = useCallback(() => {
|
|
36
|
-
|
|
78
|
+
if (!getBooleanFF('platform.editor.a11y-focus-order-for-element-browser-categories_ztiw1')) {
|
|
79
|
+
onSelectCategory(category);
|
|
80
|
+
}
|
|
37
81
|
/**
|
|
38
82
|
* When user double clicks on same category, focus on first item.
|
|
39
83
|
*/
|
|
@@ -42,6 +86,9 @@ function CategoryListItem({
|
|
|
42
86
|
} else {
|
|
43
87
|
setFocusedCategoryIndex(index);
|
|
44
88
|
}
|
|
89
|
+
if (getBooleanFF('platform.editor.a11y-focus-order-for-element-browser-categories_ztiw1')) {
|
|
90
|
+
onSelectCategory(category);
|
|
91
|
+
}
|
|
45
92
|
fireAnalyticsEvent(createAnalyticsEvent)({
|
|
46
93
|
payload: {
|
|
47
94
|
action: ACTION.CLICKED,
|
|
@@ -76,6 +123,41 @@ function CategoryListItem({
|
|
|
76
123
|
...rest
|
|
77
124
|
};
|
|
78
125
|
}, [category.name, selectedCategory]);
|
|
126
|
+
const onTabPress = useCallback(e => {
|
|
127
|
+
const isShiftPressed = e.shiftKey;
|
|
128
|
+
if (!isShiftPressed) {
|
|
129
|
+
// set focus from focused category to first item in it
|
|
130
|
+
if (setFocusedItemIndex) {
|
|
131
|
+
setFocusedItemIndex(0);
|
|
132
|
+
e.preventDefault();
|
|
133
|
+
}
|
|
134
|
+
} else {
|
|
135
|
+
// jump from first category back to search
|
|
136
|
+
if (setFocusOnSearch) {
|
|
137
|
+
setFocusOnSearch();
|
|
138
|
+
e.preventDefault();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return;
|
|
142
|
+
}, [setFocusedItemIndex, setFocusOnSearch]);
|
|
143
|
+
const onArrowPress = useCallback(e => {
|
|
144
|
+
if (e.key === 'ArrowUp' && selectPreviousCategory) {
|
|
145
|
+
return selectPreviousCategory();
|
|
146
|
+
}
|
|
147
|
+
if (e.key === 'ArrowDown' && selectNextCategory) {
|
|
148
|
+
return selectNextCategory();
|
|
149
|
+
}
|
|
150
|
+
}, [selectPreviousCategory, selectNextCategory]);
|
|
151
|
+
const onKeyDown = useCallback(e => {
|
|
152
|
+
const isTabPressed = e.key === 'Tab';
|
|
153
|
+
const isArrowPressed = arrowsKeys.has(e.key);
|
|
154
|
+
if (isTabPressed) {
|
|
155
|
+
return onTabPress(e);
|
|
156
|
+
}
|
|
157
|
+
if (isArrowPressed) {
|
|
158
|
+
return onArrowPress(e);
|
|
159
|
+
}
|
|
160
|
+
}, [onTabPress, onArrowPress]);
|
|
79
161
|
return jsx("div", {
|
|
80
162
|
css: buttonWrapper,
|
|
81
163
|
role: "presentation"
|
|
@@ -84,13 +166,15 @@ function CategoryListItem({
|
|
|
84
166
|
isSelected: selectedCategory === category.name,
|
|
85
167
|
onClick: onClick,
|
|
86
168
|
onFocus: onFocus,
|
|
169
|
+
onKeyDown: getBooleanFF('platform.editor.a11y-focus-order-for-element-browser-categories_ztiw1') ? onKeyDown : undefined,
|
|
87
170
|
theme: getTheme,
|
|
88
171
|
role: "tab",
|
|
89
172
|
"aria-selected": selectedCategory === category.name ? 'true' : 'false',
|
|
90
173
|
"aria-controls": `browse-category-${category.name}-tab`,
|
|
91
174
|
id: `browse-category--${category.name}-button`,
|
|
92
175
|
ref: ref,
|
|
93
|
-
testId: "element-browser-category-item"
|
|
176
|
+
testId: "element-browser-category-item",
|
|
177
|
+
tabIndex: -1
|
|
94
178
|
}, category.title));
|
|
95
179
|
}
|
|
96
180
|
const buttonWrapper = css({
|
|
@@ -8,6 +8,7 @@ import { withAnalyticsContext } from '@atlaskit/analytics-next';
|
|
|
8
8
|
import { relativeFontSizeToBase16 } from '@atlaskit/editor-shared-styles';
|
|
9
9
|
import { shortcutStyle } from '@atlaskit/editor-shared-styles/shortcut';
|
|
10
10
|
import { ButtonItem } from '@atlaskit/menu';
|
|
11
|
+
import { getBooleanFF } from '@atlaskit/platform-feature-flags';
|
|
11
12
|
import { B100, N200 } from '@atlaskit/theme/colors';
|
|
12
13
|
import { borderRadius } from '@atlaskit/theme/constants';
|
|
13
14
|
import Tooltip from '@atlaskit/tooltip';
|
|
@@ -46,7 +47,10 @@ function ElementList({
|
|
|
46
47
|
createAnalyticsEvent,
|
|
47
48
|
emptyStateHandler,
|
|
48
49
|
selectedCategory,
|
|
50
|
+
selectedCategoryIndex,
|
|
49
51
|
searchTerm,
|
|
52
|
+
setFocusedCategoryIndex,
|
|
53
|
+
setFocusedItemIndex,
|
|
50
54
|
...props
|
|
51
55
|
}) {
|
|
52
56
|
const {
|
|
@@ -89,15 +93,37 @@ function ElementList({
|
|
|
89
93
|
style: style,
|
|
90
94
|
key: key,
|
|
91
95
|
className: "element-item-wrapper",
|
|
92
|
-
css: elementItemWrapper
|
|
96
|
+
css: elementItemWrapper,
|
|
97
|
+
onKeyDown: getBooleanFF('platform.editor.a11y-focus-order-for-element-browser-categories_ztiw1') ? e => {
|
|
98
|
+
if (e.key === 'Tab') {
|
|
99
|
+
if (e.shiftKey && index === 0) {
|
|
100
|
+
if (setFocusedCategoryIndex) {
|
|
101
|
+
if (!!selectedCategoryIndex) {
|
|
102
|
+
setFocusedCategoryIndex(selectedCategoryIndex);
|
|
103
|
+
} else {
|
|
104
|
+
setFocusedCategoryIndex(0);
|
|
105
|
+
}
|
|
106
|
+
e.preventDefault();
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// before focus jumps from elements list we need to rerender react-virtualized collection.
|
|
110
|
+
// Otherwise on the next render 'scrollToCell' will have same cached value
|
|
111
|
+
// and collection will not be scrolled to top.
|
|
112
|
+
// So Tab press on category will not work anymore due to invisible 1-t element.
|
|
113
|
+
else if (index === items.length - 2) {
|
|
114
|
+
setFocusedItemIndex(items.length - 1);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
} : undefined
|
|
93
118
|
}, jsx(MemoizedElementItem, _extends({
|
|
94
119
|
inlineMode: !fullMode,
|
|
95
120
|
index: index,
|
|
96
121
|
item: items[index],
|
|
97
122
|
selected: selectedItemIndex === index,
|
|
98
|
-
focus: focusedItemIndex === index
|
|
123
|
+
focus: focusedItemIndex === index,
|
|
124
|
+
setFocusedItemIndex: setFocusedItemIndex
|
|
99
125
|
}, props)));
|
|
100
|
-
}, [items, fullMode, selectedItemIndex, focusedItemIndex, props]);
|
|
126
|
+
}, [items, fullMode, selectedItemIndex, focusedItemIndex, selectedCategoryIndex, setFocusedCategoryIndex, setFocusedItemIndex, props]);
|
|
101
127
|
return jsx(Fragment, null, jsx(ContainerWidthMonitor, null), jsx("div", {
|
|
102
128
|
css: elementItemsWrapper,
|
|
103
129
|
"data-testid": "element-items",
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/extends";
|
|
2
2
|
/** @jsx jsx */
|
|
3
|
-
import React, { memo, useCallback, useEffect, useState } from 'react';
|
|
3
|
+
import React, { memo, useCallback, useEffect, useRef, useState } from 'react';
|
|
4
4
|
import { css, jsx } from '@emotion/react';
|
|
5
5
|
import { FormattedMessage } from 'react-intl-next';
|
|
6
6
|
import { withAnalyticsContext, withAnalyticsEvents } from '@atlaskit/analytics-next';
|
|
7
|
+
import { getBooleanFF } from '@atlaskit/platform-feature-flags';
|
|
7
8
|
import { ACTION, ACTION_SUBJECT, EVENT_TYPE, fireAnalyticsEvent } from '../../analytics';
|
|
8
9
|
import { DEVICE_BREAKPOINT_NUMBERS, GRID_SIZE, INLINE_SIDEBAR_HEIGHT, SIDEBAR_HEADING_WRAPPER_HEIGHT, SIDEBAR_WIDTH } from '../constants';
|
|
9
10
|
import useContainerWidth from '../hooks/use-container-width';
|
|
@@ -90,22 +91,47 @@ function StatelessElementBrowser(props) {
|
|
|
90
91
|
items,
|
|
91
92
|
onSelectItem,
|
|
92
93
|
onInsertItem,
|
|
93
|
-
viewMoreItem
|
|
94
|
+
viewMoreItem,
|
|
95
|
+
selectedCategory,
|
|
96
|
+
onSelectCategory,
|
|
97
|
+
searchTerm,
|
|
98
|
+
showCategories
|
|
94
99
|
} = props;
|
|
95
100
|
const {
|
|
96
101
|
containerWidth,
|
|
97
102
|
ContainerWidthMonitor
|
|
98
103
|
} = useContainerWidth();
|
|
104
|
+
const categoryBeenChosen = useRef(false);
|
|
99
105
|
const [columnCount, setColumnCount] = useState(1);
|
|
106
|
+
let selectedCategoryIndex;
|
|
107
|
+
let isFocusSearch;
|
|
108
|
+
if (getBooleanFF('platform.editor.a11y-focus-order-for-element-browser-categories_ztiw1')) {
|
|
109
|
+
var _props$categories;
|
|
110
|
+
selectedCategoryIndex = (_props$categories = props.categories) === null || _props$categories === void 0 ? void 0 : _props$categories.findIndex(category => {
|
|
111
|
+
return category.name === selectedCategory;
|
|
112
|
+
});
|
|
113
|
+
if (showCategories) {
|
|
114
|
+
const isEmptySearchTerm = !searchTerm || (searchTerm === null || searchTerm === void 0 ? void 0 : searchTerm.length) === 0;
|
|
115
|
+
if (!isEmptySearchTerm) {
|
|
116
|
+
// clear the flag if the search happens after a user has chosen the category
|
|
117
|
+
categoryBeenChosen.current = false;
|
|
118
|
+
}
|
|
119
|
+
// A11Y: if categories exists, on the initial render search element should receive focus.
|
|
120
|
+
// After user pick some category the category should stay focused.
|
|
121
|
+
isFocusSearch = !categoryBeenChosen.current || !isEmptySearchTerm;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
100
124
|
const {
|
|
101
125
|
selectedItemIndex,
|
|
102
126
|
focusedItemIndex,
|
|
103
127
|
setFocusedItemIndex,
|
|
128
|
+
setFocusedCategoryIndex,
|
|
129
|
+
focusedCategoryIndex,
|
|
104
130
|
focusOnSearch,
|
|
105
131
|
focusOnViewMore,
|
|
106
132
|
onKeyDown,
|
|
107
133
|
setFocusOnSearch
|
|
108
|
-
} = useSelectAndFocusOnArrowNavigation(items.length - 1, columnCount, !!viewMoreItem);
|
|
134
|
+
} = useSelectAndFocusOnArrowNavigation(items.length - 1, columnCount, !!viewMoreItem, isFocusSearch);
|
|
109
135
|
useEffect(() => {
|
|
110
136
|
fireAnalyticsEvent(props.createAnalyticsEvent)({
|
|
111
137
|
payload: {
|
|
@@ -135,15 +161,29 @@ function StatelessElementBrowser(props) {
|
|
|
135
161
|
* The actual enter key press is handled on individual items level.
|
|
136
162
|
*/
|
|
137
163
|
const selectedItem = selectedItemIndex !== undefined ? items[selectedItemIndex] : null;
|
|
138
|
-
const
|
|
139
|
-
if (
|
|
140
|
-
|
|
164
|
+
const onItemsEnterTabKeyPress = useCallback(e => {
|
|
165
|
+
if (getBooleanFF('platform.editor.a11y-focus-order-for-element-browser-categories_ztiw1')) {
|
|
166
|
+
if (e.key !== 'Enter' && (e.key !== 'Tab' || !showCategories)) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
} else {
|
|
170
|
+
if (e.key !== 'Enter') {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (getBooleanFF('platform.editor.a11y-focus-order-for-element-browser-categories_ztiw1')) {
|
|
175
|
+
if (showCategories && e.key === 'Tab' && selectedCategoryIndex !== undefined) {
|
|
176
|
+
// A11Y: Set focus on first category if tab pressed on search
|
|
177
|
+
setFocusedCategoryIndex(selectedCategoryIndex);
|
|
178
|
+
e.preventDefault();
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
141
181
|
}
|
|
142
182
|
if (onInsertItem && selectedItem != null) {
|
|
143
183
|
onInsertItem(selectedItem);
|
|
144
184
|
}
|
|
145
185
|
e.preventDefault();
|
|
146
|
-
}, [onInsertItem, selectedItem]);
|
|
186
|
+
}, [onInsertItem, selectedItem, setFocusedCategoryIndex, showCategories, selectedCategoryIndex]);
|
|
147
187
|
|
|
148
188
|
/**
|
|
149
189
|
* On arrow key selection and clicks the selectedItemIndex will change.
|
|
@@ -154,6 +194,10 @@ function StatelessElementBrowser(props) {
|
|
|
154
194
|
onSelectItem(selectedItem);
|
|
155
195
|
}
|
|
156
196
|
}, [onSelectItem, selectedItem]);
|
|
197
|
+
const onSelectCategoryCB = useCallback(category => {
|
|
198
|
+
onSelectCategory(category);
|
|
199
|
+
categoryBeenChosen.current = true;
|
|
200
|
+
}, [categoryBeenChosen, onSelectCategory]);
|
|
157
201
|
return jsx("div", {
|
|
158
202
|
css: wrapper,
|
|
159
203
|
"data-testid": "element-browser"
|
|
@@ -161,10 +205,12 @@ function StatelessElementBrowser(props) {
|
|
|
161
205
|
selectedItemIndex: selectedItemIndex,
|
|
162
206
|
focusedItemIndex: focusedItemIndex,
|
|
163
207
|
setFocusedItemIndex: setFocusedItemIndex,
|
|
208
|
+
focusedCategoryIndex: focusedCategoryIndex,
|
|
209
|
+
setFocusedCategoryIndex: setFocusedCategoryIndex,
|
|
164
210
|
focusOnSearch: focusOnSearch,
|
|
165
211
|
setColumnCount: setColumnCount,
|
|
166
212
|
setFocusOnSearch: setFocusOnSearch,
|
|
167
|
-
onKeyPress:
|
|
213
|
+
onKeyPress: onItemsEnterTabKeyPress,
|
|
168
214
|
onKeyDown: onKeyDown,
|
|
169
215
|
viewMoreItem: viewMoreItem,
|
|
170
216
|
focusOnViewMore: focusOnViewMore
|
|
@@ -175,8 +221,12 @@ function StatelessElementBrowser(props) {
|
|
|
175
221
|
focusOnSearch: focusOnSearch,
|
|
176
222
|
setColumnCount: setColumnCount,
|
|
177
223
|
setFocusOnSearch: setFocusOnSearch,
|
|
178
|
-
onKeyPress:
|
|
179
|
-
onKeyDown: onKeyDown
|
|
224
|
+
onKeyPress: onItemsEnterTabKeyPress,
|
|
225
|
+
onKeyDown: onKeyDown,
|
|
226
|
+
focusedCategoryIndex: focusedCategoryIndex,
|
|
227
|
+
setFocusedCategoryIndex: setFocusedCategoryIndex,
|
|
228
|
+
selectedCategoryIndex: selectedCategoryIndex,
|
|
229
|
+
onSelectCategory: getBooleanFF('platform.editor.a11y-focus-order-for-element-browser-categories_ztiw1') ? onSelectCategoryCB : onSelectCategory
|
|
180
230
|
})));
|
|
181
231
|
}
|
|
182
232
|
function MobileBrowser({
|
|
@@ -192,6 +242,8 @@ function MobileBrowser({
|
|
|
192
242
|
selectedItemIndex,
|
|
193
243
|
focusedItemIndex,
|
|
194
244
|
setFocusedItemIndex,
|
|
245
|
+
focusedCategoryIndex,
|
|
246
|
+
setFocusedCategoryIndex,
|
|
195
247
|
focusOnSearch,
|
|
196
248
|
focusOnViewMore,
|
|
197
249
|
setColumnCount,
|
|
@@ -224,7 +276,11 @@ function MobileBrowser({
|
|
|
224
276
|
}, jsx(CategoryList, {
|
|
225
277
|
categories: categories,
|
|
226
278
|
onSelectCategory: onSelectCategory,
|
|
227
|
-
selectedCategory: selectedCategory
|
|
279
|
+
selectedCategory: selectedCategory,
|
|
280
|
+
focusedCategoryIndex: focusedCategoryIndex,
|
|
281
|
+
setFocusedCategoryIndex: setFocusedCategoryIndex,
|
|
282
|
+
setFocusedItemIndex: setFocusedItemIndex,
|
|
283
|
+
setFocusOnSearch: setFocusOnSearch
|
|
228
284
|
}))), jsx("div", {
|
|
229
285
|
css: mobileMainContent
|
|
230
286
|
}, jsx(ElementList, {
|
|
@@ -257,6 +313,9 @@ function DesktopBrowser({
|
|
|
257
313
|
selectedItemIndex,
|
|
258
314
|
focusedItemIndex,
|
|
259
315
|
setFocusedItemIndex,
|
|
316
|
+
focusedCategoryIndex,
|
|
317
|
+
setFocusedCategoryIndex,
|
|
318
|
+
selectedCategoryIndex,
|
|
260
319
|
focusOnSearch,
|
|
261
320
|
setColumnCount,
|
|
262
321
|
setFocusOnSearch,
|
|
@@ -287,7 +346,11 @@ function DesktopBrowser({
|
|
|
287
346
|
categories: categories,
|
|
288
347
|
onSelectCategory: onSelectCategory,
|
|
289
348
|
selectedCategory: selectedCategory,
|
|
290
|
-
createAnalyticsEvent: createAnalyticsEvent
|
|
349
|
+
createAnalyticsEvent: createAnalyticsEvent,
|
|
350
|
+
focusedCategoryIndex: focusedCategoryIndex,
|
|
351
|
+
setFocusedCategoryIndex: setFocusedCategoryIndex,
|
|
352
|
+
setFocusedItemIndex: setFocusedItemIndex,
|
|
353
|
+
setFocusOnSearch: setFocusOnSearch
|
|
291
354
|
}))), jsx("div", {
|
|
292
355
|
css: mainContent,
|
|
293
356
|
onKeyDown: onKeyDown,
|
|
@@ -316,7 +379,9 @@ function DesktopBrowser({
|
|
|
316
379
|
createAnalyticsEvent: createAnalyticsEvent,
|
|
317
380
|
emptyStateHandler: emptyStateHandler,
|
|
318
381
|
selectedCategory: selectedCategory,
|
|
319
|
-
|
|
382
|
+
selectedCategoryIndex: selectedCategoryIndex,
|
|
383
|
+
searchTerm: searchTerm,
|
|
384
|
+
setFocusedCategoryIndex: showCategories ? setFocusedCategoryIndex : undefined
|
|
320
385
|
})));
|
|
321
386
|
}
|
|
322
387
|
const MemoizedElementBrowser = /*#__PURE__*/memo(withAnalyticsContext({
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useCallback, useEffect, useReducer, useRef } from 'react';
|
|
2
|
+
import { getBooleanFF } from '@atlaskit/platform-feature-flags';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* a custom hook that handles keyboard navigation for Arrow keys based on a
|
|
@@ -57,6 +58,7 @@ const reducer = (state, action) => {
|
|
|
57
58
|
return {
|
|
58
59
|
...state,
|
|
59
60
|
focusedItemIndex: undefined,
|
|
61
|
+
focusedCategoryIndex: undefined,
|
|
60
62
|
focusOnSearch: true,
|
|
61
63
|
focusOnViewMore: false
|
|
62
64
|
};
|
|
@@ -172,7 +174,7 @@ const getInitialState = (listSize, canFocusViewMore) => initialState => ({
|
|
|
172
174
|
listSize,
|
|
173
175
|
canFocusViewMore
|
|
174
176
|
});
|
|
175
|
-
function useSelectAndFocusOnArrowNavigation(listSize, step, canFocusViewMore) {
|
|
177
|
+
function useSelectAndFocusOnArrowNavigation(listSize, step, canFocusViewMore, isFocusSearch) {
|
|
176
178
|
const [state, dispatch] = useReducer(reducer, initialState, getInitialState(listSize, canFocusViewMore));
|
|
177
179
|
useEffect(() => {
|
|
178
180
|
dispatch({
|
|
@@ -186,25 +188,55 @@ function useSelectAndFocusOnArrowNavigation(listSize, step, canFocusViewMore) {
|
|
|
186
188
|
selectedItemIndex,
|
|
187
189
|
focusedItemIndex,
|
|
188
190
|
focusOnSearch,
|
|
189
|
-
focusOnViewMore
|
|
191
|
+
focusOnViewMore,
|
|
192
|
+
focusedCategoryIndex
|
|
190
193
|
} = state;
|
|
194
|
+
|
|
195
|
+
// calls if items size changed
|
|
191
196
|
const reset = useCallback(listSize => {
|
|
192
197
|
let payload = {
|
|
193
198
|
...initialState,
|
|
194
199
|
listSize
|
|
195
200
|
};
|
|
201
|
+
if (getBooleanFF('platform.editor.a11y-focus-order-for-element-browser-categories_ztiw1')) {
|
|
202
|
+
// A11Y: if categories exist ,on the initial render search element should receive focus.
|
|
203
|
+
// After user pick some category the category should stay focused.
|
|
204
|
+
payload = Object.assign(payload, {
|
|
205
|
+
focusOnSearch: isFocusSearch !== null && isFocusSearch !== void 0 ? isFocusSearch : initialState.focusOnSearch
|
|
206
|
+
});
|
|
207
|
+
}
|
|
196
208
|
dispatch({
|
|
197
209
|
type: ACTIONS.UPDATE_STATE,
|
|
198
210
|
payload
|
|
199
211
|
});
|
|
200
|
-
}, []);
|
|
212
|
+
}, [isFocusSearch]);
|
|
201
213
|
const removeFocusFromSearchAndSetOnItem = useCallback(index => {
|
|
202
|
-
|
|
214
|
+
let payload = {
|
|
203
215
|
focusedItemIndex: index,
|
|
204
216
|
selectedItemIndex: index,
|
|
205
217
|
focusOnSearch: false,
|
|
206
218
|
focusOnViewMore: false
|
|
207
219
|
};
|
|
220
|
+
if (getBooleanFF('platform.editor.a11y-focus-order-for-element-browser-categories_ztiw1')) {
|
|
221
|
+
payload = Object.assign(payload, {
|
|
222
|
+
focusedCategoryIndex: undefined
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
dispatch({
|
|
226
|
+
type: ACTIONS.UPDATE_STATE,
|
|
227
|
+
payload
|
|
228
|
+
});
|
|
229
|
+
}, [dispatch]);
|
|
230
|
+
const setFocusedCategoryIndex = useCallback(index => {
|
|
231
|
+
if (!getBooleanFF('platform.editor.a11y-focus-order-for-element-browser-categories_ztiw1')) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
const payload = {
|
|
235
|
+
focusOnSearch: false,
|
|
236
|
+
focusOnViewMore: false,
|
|
237
|
+
focusedCategoryIndex: index,
|
|
238
|
+
focusedItemIndex: undefined
|
|
239
|
+
};
|
|
208
240
|
dispatch({
|
|
209
241
|
type: ACTIONS.UPDATE_STATE,
|
|
210
242
|
payload
|
|
@@ -269,7 +301,9 @@ function useSelectAndFocusOnArrowNavigation(listSize, step, canFocusViewMore) {
|
|
|
269
301
|
focusOnViewMore,
|
|
270
302
|
setFocusOnSearch,
|
|
271
303
|
focusedItemIndex,
|
|
272
|
-
setFocusedItemIndex: removeFocusFromSearchAndSetOnItem
|
|
304
|
+
setFocusedItemIndex: removeFocusFromSearchAndSetOnItem,
|
|
305
|
+
focusedCategoryIndex,
|
|
306
|
+
setFocusedCategoryIndex: setFocusedCategoryIndex
|
|
273
307
|
};
|
|
274
308
|
}
|
|
275
309
|
export const ensureSafeIndex = (index, listSize) => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const SENTRY_DSN = 'https://0b10c8e02fb44d8796c047b102c9bee8@o55978.ingest.sentry.io/4505129224110080';
|
|
2
2
|
const packageName = 'editor-common'; // Sentry doesn't accept '/' in its releases https://docs.sentry.io/platforms/javascript/configuration/releases/
|
|
3
|
-
const packageVersion = "78.37.
|
|
3
|
+
const packageVersion = "78.37.3";
|
|
4
4
|
const sanitiseSentryEvents = (data, _hint) => {
|
|
5
5
|
// Remove URL as it has UGC
|
|
6
6
|
// TODO: Sanitise the URL instead of just removing it
|
|
@@ -7,7 +7,7 @@ import { createAndFireEvent, withAnalyticsContext, withAnalyticsEvents } from '@
|
|
|
7
7
|
import { N0, N50A, N60A, N900 } from '@atlaskit/theme/colors';
|
|
8
8
|
import Layer from '../Layer';
|
|
9
9
|
const packageName = "@atlaskit/editor-common";
|
|
10
|
-
const packageVersion = "78.37.
|
|
10
|
+
const packageVersion = "78.37.3";
|
|
11
11
|
const halfFocusRing = 1;
|
|
12
12
|
const dropOffset = '0, 8';
|
|
13
13
|
class DropList extends Component {
|
|
@@ -7,31 +7,65 @@ var _excluded = ["categories"],
|
|
|
7
7
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
8
8
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
9
9
|
/** @jsx jsx */
|
|
10
|
-
|
|
11
10
|
import React, { Fragment, memo, useCallback } from 'react';
|
|
12
11
|
import { css, jsx } from '@emotion/react';
|
|
13
12
|
import { withAnalyticsContext } from '@atlaskit/analytics-next';
|
|
14
13
|
import Button from '@atlaskit/button/custom-theme-button';
|
|
14
|
+
import { getBooleanFF } from '@atlaskit/platform-feature-flags';
|
|
15
15
|
import { B400, B50, N800 } from '@atlaskit/theme/colors';
|
|
16
16
|
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, fireAnalyticsEvent } from '../../analytics';
|
|
17
17
|
import { DEVICE_BREAKPOINT_NUMBERS, GRID_SIZE } from '../constants';
|
|
18
18
|
import useFocus from '../hooks/use-focus';
|
|
19
|
+
var arrowsKeys = new Set(['ArrowUp', 'ArrowDown']);
|
|
19
20
|
function CategoryList(_ref) {
|
|
20
21
|
var _ref$categories = _ref.categories,
|
|
21
22
|
categories = _ref$categories === void 0 ? [] : _ref$categories,
|
|
22
23
|
props = _objectWithoutProperties(_ref, _excluded);
|
|
23
24
|
var _React$useState = React.useState(null),
|
|
24
25
|
_React$useState2 = _slicedToArray(_React$useState, 2),
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
focusedCategoryIndexState = _React$useState2[0],
|
|
27
|
+
setFocusedCategoryIndexState = _React$useState2[1];
|
|
28
|
+
var focusedCategoryIndexProp = props.focusedCategoryIndex,
|
|
29
|
+
setFocusedCategoryIndexProp = props.setFocusedCategoryIndex,
|
|
30
|
+
onSelectCategory = props.onSelectCategory;
|
|
31
|
+
var focusedCategoryIndex = getBooleanFF('platform.editor.a11y-focus-order-for-element-browser-categories_ztiw1') ? focusedCategoryIndexProp : focusedCategoryIndexState;
|
|
32
|
+
var setFocusedCategoryIndex = getBooleanFF('platform.editor.a11y-focus-order-for-element-browser-categories_ztiw1') ? setFocusedCategoryIndexProp : setFocusedCategoryIndexState;
|
|
27
33
|
return jsx(Fragment, null, categories.map(function (category, index) {
|
|
34
|
+
var categoriesLength = categories === null || categories === void 0 ? void 0 : categories.length;
|
|
35
|
+
var selectNextCategory;
|
|
36
|
+
var selectPreviousCategory;
|
|
37
|
+
if (getBooleanFF('platform.editor.a11y-focus-order-for-element-browser-categories_ztiw1') && categoriesLength > 1) {
|
|
38
|
+
selectNextCategory = function selectNextCategory() {
|
|
39
|
+
if (index !== categoriesLength - 1) {
|
|
40
|
+
setFocusedCategoryIndex(index + 1);
|
|
41
|
+
onSelectCategory(categories[index + 1]);
|
|
42
|
+
} else {
|
|
43
|
+
setFocusedCategoryIndex(0);
|
|
44
|
+
onSelectCategory(categories[0]);
|
|
45
|
+
}
|
|
46
|
+
return;
|
|
47
|
+
};
|
|
48
|
+
selectPreviousCategory = function selectPreviousCategory() {
|
|
49
|
+
if (index !== 0) {
|
|
50
|
+
setFocusedCategoryIndex(index - 1);
|
|
51
|
+
onSelectCategory(categories[index - 1]);
|
|
52
|
+
} else {
|
|
53
|
+
setFocusedCategoryIndex(categoriesLength - 1);
|
|
54
|
+
onSelectCategory(categories[categoriesLength - 1]);
|
|
55
|
+
}
|
|
56
|
+
return;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
28
59
|
return jsx(CategoryListItem, _extends({
|
|
29
60
|
key: category.title,
|
|
30
61
|
index: index,
|
|
31
62
|
category: category,
|
|
32
|
-
focus: focusedCategoryIndex === index
|
|
33
|
-
|
|
34
|
-
|
|
63
|
+
focus: focusedCategoryIndex === index
|
|
64
|
+
}, props, {
|
|
65
|
+
setFocusedCategoryIndex: setFocusedCategoryIndex,
|
|
66
|
+
selectPreviousCategory: selectPreviousCategory,
|
|
67
|
+
selectNextCategory: selectNextCategory
|
|
68
|
+
}));
|
|
35
69
|
}));
|
|
36
70
|
}
|
|
37
71
|
function CategoryListItem(_ref2) {
|
|
@@ -41,10 +75,16 @@ function CategoryListItem(_ref2) {
|
|
|
41
75
|
index = _ref2.index,
|
|
42
76
|
focus = _ref2.focus,
|
|
43
77
|
setFocusedCategoryIndex = _ref2.setFocusedCategoryIndex,
|
|
44
|
-
createAnalyticsEvent = _ref2.createAnalyticsEvent
|
|
78
|
+
createAnalyticsEvent = _ref2.createAnalyticsEvent,
|
|
79
|
+
setFocusedItemIndex = _ref2.setFocusedItemIndex,
|
|
80
|
+
setFocusOnSearch = _ref2.setFocusOnSearch,
|
|
81
|
+
selectPreviousCategory = _ref2.selectPreviousCategory,
|
|
82
|
+
selectNextCategory = _ref2.selectNextCategory;
|
|
45
83
|
var ref = useFocus(focus);
|
|
46
84
|
var onClick = useCallback(function () {
|
|
47
|
-
|
|
85
|
+
if (!getBooleanFF('platform.editor.a11y-focus-order-for-element-browser-categories_ztiw1')) {
|
|
86
|
+
onSelectCategory(category);
|
|
87
|
+
}
|
|
48
88
|
/**
|
|
49
89
|
* When user double clicks on same category, focus on first item.
|
|
50
90
|
*/
|
|
@@ -53,6 +93,9 @@ function CategoryListItem(_ref2) {
|
|
|
53
93
|
} else {
|
|
54
94
|
setFocusedCategoryIndex(index);
|
|
55
95
|
}
|
|
96
|
+
if (getBooleanFF('platform.editor.a11y-focus-order-for-element-browser-categories_ztiw1')) {
|
|
97
|
+
onSelectCategory(category);
|
|
98
|
+
}
|
|
56
99
|
fireAnalyticsEvent(createAnalyticsEvent)({
|
|
57
100
|
payload: {
|
|
58
101
|
action: ACTION.CLICKED,
|
|
@@ -83,6 +126,41 @@ function CategoryListItem(_ref2) {
|
|
|
83
126
|
})
|
|
84
127
|
}, rest);
|
|
85
128
|
}, [category.name, selectedCategory]);
|
|
129
|
+
var onTabPress = useCallback(function (e) {
|
|
130
|
+
var isShiftPressed = e.shiftKey;
|
|
131
|
+
if (!isShiftPressed) {
|
|
132
|
+
// set focus from focused category to first item in it
|
|
133
|
+
if (setFocusedItemIndex) {
|
|
134
|
+
setFocusedItemIndex(0);
|
|
135
|
+
e.preventDefault();
|
|
136
|
+
}
|
|
137
|
+
} else {
|
|
138
|
+
// jump from first category back to search
|
|
139
|
+
if (setFocusOnSearch) {
|
|
140
|
+
setFocusOnSearch();
|
|
141
|
+
e.preventDefault();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return;
|
|
145
|
+
}, [setFocusedItemIndex, setFocusOnSearch]);
|
|
146
|
+
var onArrowPress = useCallback(function (e) {
|
|
147
|
+
if (e.key === 'ArrowUp' && selectPreviousCategory) {
|
|
148
|
+
return selectPreviousCategory();
|
|
149
|
+
}
|
|
150
|
+
if (e.key === 'ArrowDown' && selectNextCategory) {
|
|
151
|
+
return selectNextCategory();
|
|
152
|
+
}
|
|
153
|
+
}, [selectPreviousCategory, selectNextCategory]);
|
|
154
|
+
var onKeyDown = useCallback(function (e) {
|
|
155
|
+
var isTabPressed = e.key === 'Tab';
|
|
156
|
+
var isArrowPressed = arrowsKeys.has(e.key);
|
|
157
|
+
if (isTabPressed) {
|
|
158
|
+
return onTabPress(e);
|
|
159
|
+
}
|
|
160
|
+
if (isArrowPressed) {
|
|
161
|
+
return onArrowPress(e);
|
|
162
|
+
}
|
|
163
|
+
}, [onTabPress, onArrowPress]);
|
|
86
164
|
return jsx("div", {
|
|
87
165
|
css: buttonWrapper,
|
|
88
166
|
role: "presentation"
|
|
@@ -91,13 +169,15 @@ function CategoryListItem(_ref2) {
|
|
|
91
169
|
isSelected: selectedCategory === category.name,
|
|
92
170
|
onClick: onClick,
|
|
93
171
|
onFocus: onFocus,
|
|
172
|
+
onKeyDown: getBooleanFF('platform.editor.a11y-focus-order-for-element-browser-categories_ztiw1') ? onKeyDown : undefined,
|
|
94
173
|
theme: getTheme,
|
|
95
174
|
role: "tab",
|
|
96
175
|
"aria-selected": selectedCategory === category.name ? 'true' : 'false',
|
|
97
176
|
"aria-controls": "browse-category-".concat(category.name, "-tab"),
|
|
98
177
|
id: "browse-category--".concat(category.name, "-button"),
|
|
99
178
|
ref: ref,
|
|
100
|
-
testId: "element-browser-category-item"
|
|
179
|
+
testId: "element-browser-category-item",
|
|
180
|
+
tabIndex: -1
|
|
101
181
|
}, category.title));
|
|
102
182
|
}
|
|
103
183
|
var buttonWrapper = css(_defineProperty({
|