@atlaskit/editor-common 74.57.0 → 74.58.1
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 +13 -0
- package/dist/cjs/element-browser/ElementBrowser.js +152 -0
- package/dist/cjs/element-browser/ViewMore.js +39 -0
- package/dist/cjs/element-browser/components/CategoryList.js +115 -0
- package/dist/cjs/element-browser/components/ElementBrowserLoader.js +36 -0
- package/dist/cjs/element-browser/components/ElementList/ElementList.js +256 -0
- package/dist/cjs/element-browser/components/ElementList/EmptyState.js +47 -0
- package/dist/cjs/element-browser/components/ElementList/NotFoundIllustration.js +70 -0
- package/dist/cjs/element-browser/components/ElementList/cellSizeAndPositionGetter.js +42 -0
- package/dist/cjs/element-browser/components/ElementList/utils.js +54 -0
- package/dist/cjs/element-browser/components/ElementSearch.js +88 -0
- package/dist/cjs/element-browser/components/StatelessElementBrowser.js +269 -0
- package/dist/cjs/element-browser/constants.js +41 -0
- package/dist/cjs/element-browser/hooks/use-container-width.js +70 -0
- package/dist/cjs/element-browser/hooks/use-focus.js +51 -0
- package/dist/cjs/element-browser/hooks/use-select-and-focus-on-arrow-navigation.js +286 -0
- package/dist/cjs/element-browser/index.js +20 -0
- package/dist/cjs/element-browser/types.js +12 -0
- package/dist/cjs/monitoring/error.js +1 -1
- package/dist/cjs/ui/DropList/index.js +1 -1
- package/dist/cjs/utils/performance/measure-render.js +4 -3
- package/dist/cjs/utils/performance/measure-tti.js +9 -3
- package/dist/cjs/utils/validator.js +7 -0
- package/dist/es2019/element-browser/ElementBrowser.js +117 -0
- package/dist/es2019/element-browser/ViewMore.js +40 -0
- package/dist/es2019/element-browser/components/CategoryList.js +106 -0
- package/dist/es2019/element-browser/components/ElementBrowserLoader.js +21 -0
- package/dist/es2019/element-browser/components/ElementList/ElementList.js +320 -0
- package/dist/es2019/element-browser/components/ElementList/EmptyState.js +58 -0
- package/dist/es2019/element-browser/components/ElementList/NotFoundIllustration.js +65 -0
- package/dist/es2019/element-browser/components/ElementList/cellSizeAndPositionGetter.js +39 -0
- package/dist/es2019/element-browser/components/ElementList/utils.js +50 -0
- package/dist/es2019/element-browser/components/ElementSearch.js +117 -0
- package/dist/es2019/element-browser/components/StatelessElementBrowser.js +339 -0
- package/dist/es2019/element-browser/constants.js +23 -0
- package/dist/es2019/element-browser/hooks/use-container-width.js +59 -0
- package/dist/es2019/element-browser/hooks/use-focus.js +48 -0
- package/dist/es2019/element-browser/hooks/use-select-and-focus-on-arrow-navigation.js +284 -0
- package/dist/es2019/element-browser/index.js +2 -0
- package/dist/es2019/element-browser/types.js +5 -0
- package/dist/es2019/monitoring/error.js +1 -1
- package/dist/es2019/ui/DropList/index.js +1 -1
- package/dist/es2019/utils/performance/measure-render.js +2 -3
- package/dist/es2019/utils/performance/measure-tti.js +9 -3
- package/dist/es2019/utils/validator.js +7 -0
- package/dist/esm/element-browser/ElementBrowser.js +142 -0
- package/dist/esm/element-browser/ViewMore.js +31 -0
- package/dist/esm/element-browser/components/CategoryList.js +105 -0
- package/dist/esm/element-browser/components/ElementBrowserLoader.js +23 -0
- package/dist/esm/element-browser/components/ElementList/ElementList.js +241 -0
- package/dist/esm/element-browser/components/ElementList/EmptyState.js +40 -0
- package/dist/esm/element-browser/components/ElementList/NotFoundIllustration.js +63 -0
- package/dist/esm/element-browser/components/ElementList/cellSizeAndPositionGetter.js +37 -0
- package/dist/esm/element-browser/components/ElementList/utils.js +46 -0
- package/dist/esm/element-browser/components/ElementSearch.js +77 -0
- package/dist/esm/element-browser/components/StatelessElementBrowser.js +258 -0
- package/dist/esm/element-browser/constants.js +23 -0
- package/dist/esm/element-browser/hooks/use-container-width.js +61 -0
- package/dist/esm/element-browser/hooks/use-focus.js +46 -0
- package/dist/esm/element-browser/hooks/use-select-and-focus-on-arrow-navigation.js +278 -0
- package/dist/esm/element-browser/index.js +2 -0
- package/dist/esm/element-browser/types.js +5 -0
- package/dist/esm/monitoring/error.js +1 -1
- package/dist/esm/ui/DropList/index.js +1 -1
- package/dist/esm/utils/performance/measure-render.js +2 -3
- package/dist/esm/utils/performance/measure-tti.js +9 -3
- package/dist/esm/utils/validator.js +7 -0
- package/dist/types/analytics/types/general-events.d.ts +2 -1
- package/dist/types/element-browser/ElementBrowser.d.ts +37 -0
- package/dist/types/element-browser/ViewMore.d.ts +6 -0
- package/dist/types/element-browser/components/CategoryList.d.ts +10 -0
- package/dist/types/element-browser/components/ElementBrowserLoader.d.ts +6 -0
- package/dist/types/element-browser/components/ElementList/ElementList.d.ts +33 -0
- package/dist/types/element-browser/components/ElementList/EmptyState.d.ts +6 -0
- package/dist/types/element-browser/components/ElementList/NotFoundIllustration.d.ts +2 -0
- package/dist/types/element-browser/components/ElementList/cellSizeAndPositionGetter.d.ts +7 -0
- package/dist/types/element-browser/components/ElementList/utils.d.ts +12 -0
- package/dist/types/element-browser/components/ElementSearch.d.ts +18 -0
- package/dist/types/element-browser/components/StatelessElementBrowser.d.ts +23 -0
- package/dist/types/element-browser/constants.d.ts +19 -0
- package/dist/types/element-browser/hooks/use-container-width.d.ts +33 -0
- package/dist/types/element-browser/hooks/use-focus.d.ts +35 -0
- package/dist/types/element-browser/hooks/use-select-and-focus-on-arrow-navigation.d.ts +72 -0
- package/dist/types/element-browser/index.d.ts +2 -0
- package/dist/types/element-browser/types.d.ts +12 -0
- package/dist/types/types/quick-insert.d.ts +1 -0
- package/dist/types/utils/performance/measure-render.d.ts +6 -4
- package/dist/types/utils/performance/measure-tti.d.ts +1 -1
- package/dist/types-ts4.5/analytics/types/general-events.d.ts +2 -1
- package/dist/types-ts4.5/element-browser/ElementBrowser.d.ts +37 -0
- package/dist/types-ts4.5/element-browser/ViewMore.d.ts +6 -0
- package/dist/types-ts4.5/element-browser/components/CategoryList.d.ts +10 -0
- package/dist/types-ts4.5/element-browser/components/ElementBrowserLoader.d.ts +6 -0
- package/dist/types-ts4.5/element-browser/components/ElementList/ElementList.d.ts +33 -0
- package/dist/types-ts4.5/element-browser/components/ElementList/EmptyState.d.ts +6 -0
- package/dist/types-ts4.5/element-browser/components/ElementList/NotFoundIllustration.d.ts +2 -0
- package/dist/types-ts4.5/element-browser/components/ElementList/cellSizeAndPositionGetter.d.ts +7 -0
- package/dist/types-ts4.5/element-browser/components/ElementList/utils.d.ts +12 -0
- package/dist/types-ts4.5/element-browser/components/ElementSearch.d.ts +18 -0
- package/dist/types-ts4.5/element-browser/components/StatelessElementBrowser.d.ts +23 -0
- package/dist/types-ts4.5/element-browser/constants.d.ts +19 -0
- package/dist/types-ts4.5/element-browser/hooks/use-container-width.d.ts +33 -0
- package/dist/types-ts4.5/element-browser/hooks/use-focus.d.ts +35 -0
- package/dist/types-ts4.5/element-browser/hooks/use-select-and-focus-on-arrow-navigation.d.ts +72 -0
- package/dist/types-ts4.5/element-browser/index.d.ts +2 -0
- package/dist/types-ts4.5/element-browser/types.d.ts +12 -0
- package/dist/types-ts4.5/types/quick-insert.d.ts +1 -0
- package/dist/types-ts4.5/utils/performance/measure-render.d.ts +6 -4
- package/dist/types-ts4.5/utils/performance/measure-tti.d.ts +1 -1
- package/element-browser/package.json +15 -0
- package/package.json +6 -2
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { useCallback, useEffect, useReducer, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* a custom hook that handles keyboard navigation for Arrow keys based on a
|
|
5
|
+
* given listSize, and a step (for up and down arrows).
|
|
6
|
+
*
|
|
7
|
+
* @param {number} listSize
|
|
8
|
+
* @param {number} upDownStep
|
|
9
|
+
*
|
|
10
|
+
* Example usage:
|
|
11
|
+
* const list = ['Confluence','Jira','Atlaskit'];
|
|
12
|
+
* const {
|
|
13
|
+
* selectedItemIndex,
|
|
14
|
+
* focusedItemIndex,
|
|
15
|
+
* focusOnSearch,
|
|
16
|
+
* focusOnViewMore,
|
|
17
|
+
* setFocusedItemIndex,
|
|
18
|
+
* onKeyDown
|
|
19
|
+
* } = useSelectAndFocusOnArrowNavigation(list.length - 1, 1);
|
|
20
|
+
*
|
|
21
|
+
* return (
|
|
22
|
+
* <div onKeyDown={onKeyDown}>
|
|
23
|
+
* <SearchBar onClick={() => setFocusedItemIndex(undefined)} focus={focusOnSearch} />
|
|
24
|
+
* {list.map((item, index) => (
|
|
25
|
+
* <ListItem
|
|
26
|
+
* title={item}
|
|
27
|
+
* style={{ ..., color: selected ? 'selectedStateColor' : defaultColor }}
|
|
28
|
+
* onClick={() => {
|
|
29
|
+
* setFocusedItemIndex(index);
|
|
30
|
+
* }
|
|
31
|
+
* />
|
|
32
|
+
* )}
|
|
33
|
+
* </div>
|
|
34
|
+
* );
|
|
35
|
+
*
|
|
36
|
+
* const SearchBar = ({ focus }) => {
|
|
37
|
+
* const ref = useRefToFocusOrScroll(focus);
|
|
38
|
+
* return <input ref={ref} />
|
|
39
|
+
* }
|
|
40
|
+
*
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
export let ACTIONS = /*#__PURE__*/function (ACTIONS) {
|
|
44
|
+
ACTIONS["FOCUS_SEARCH"] = "focusOnSearch";
|
|
45
|
+
ACTIONS["UPDATE_STATE"] = "updateState";
|
|
46
|
+
ACTIONS["MOVE"] = "move";
|
|
47
|
+
return ACTIONS;
|
|
48
|
+
}({});
|
|
49
|
+
const reducer = (state, action) => {
|
|
50
|
+
switch (action.type) {
|
|
51
|
+
case ACTIONS.UPDATE_STATE:
|
|
52
|
+
return {
|
|
53
|
+
...state,
|
|
54
|
+
...action.payload
|
|
55
|
+
};
|
|
56
|
+
case ACTIONS.FOCUS_SEARCH:
|
|
57
|
+
return {
|
|
58
|
+
...state,
|
|
59
|
+
focusedItemIndex: undefined,
|
|
60
|
+
focusOnSearch: true,
|
|
61
|
+
focusOnViewMore: false
|
|
62
|
+
};
|
|
63
|
+
case ACTIONS.MOVE:
|
|
64
|
+
return moveReducer(state, action);
|
|
65
|
+
}
|
|
66
|
+
return state;
|
|
67
|
+
};
|
|
68
|
+
const moveReducer = (state, action) => {
|
|
69
|
+
const {
|
|
70
|
+
listSize,
|
|
71
|
+
canFocusViewMore
|
|
72
|
+
} = state;
|
|
73
|
+
if (state.focusOnSearch) {
|
|
74
|
+
// up arrow
|
|
75
|
+
if (action.payload.positions && action.payload.positions <= -1) {
|
|
76
|
+
return {
|
|
77
|
+
...state,
|
|
78
|
+
focusOnSearch: false,
|
|
79
|
+
focusOnViewMore: !!canFocusViewMore,
|
|
80
|
+
focusedItemIndex: canFocusViewMore ? undefined : listSize,
|
|
81
|
+
selectedItemIndex: canFocusViewMore ? undefined : listSize
|
|
82
|
+
};
|
|
83
|
+
} else {
|
|
84
|
+
return {
|
|
85
|
+
...state,
|
|
86
|
+
focusOnSearch: false,
|
|
87
|
+
focusOnViewMore: false,
|
|
88
|
+
focusedItemIndex: 0,
|
|
89
|
+
selectedItemIndex: 0
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (state.focusOnViewMore) {
|
|
94
|
+
// down arrow
|
|
95
|
+
if (action.payload.positions === 1) {
|
|
96
|
+
return {
|
|
97
|
+
...state,
|
|
98
|
+
focusOnSearch: true,
|
|
99
|
+
focusOnViewMore: false,
|
|
100
|
+
focusedItemIndex: undefined,
|
|
101
|
+
// if search is focused then select first item.
|
|
102
|
+
selectedItemIndex: 0
|
|
103
|
+
};
|
|
104
|
+
} else {
|
|
105
|
+
return {
|
|
106
|
+
...state,
|
|
107
|
+
focusOnSearch: false,
|
|
108
|
+
focusOnViewMore: false,
|
|
109
|
+
focusedItemIndex: listSize,
|
|
110
|
+
selectedItemIndex: listSize
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const newIndex = state.selectedItemIndex ? state.selectedItemIndex + action.payload.positions : action.payload.positions;
|
|
115
|
+
const safeIndex = ensureSafeIndex(newIndex, state.listSize);
|
|
116
|
+
// down arrow key is pressed or right arrow key is pressed.
|
|
117
|
+
if (state.focusedItemIndex !== undefined && action.payload.positions && action.payload.positions >= 1) {
|
|
118
|
+
// when multi column element browser is open and we are in last
|
|
119
|
+
// row then newIndex will be greater than listSize when
|
|
120
|
+
// down arrow key is pressed.
|
|
121
|
+
// Or when last item is focused and down or right arrow key is pressed.
|
|
122
|
+
const isLastItemFocused = newIndex > listSize;
|
|
123
|
+
const focusOnSearch = isLastItemFocused && !canFocusViewMore;
|
|
124
|
+
const focusOnViewMore = isLastItemFocused && !!canFocusViewMore;
|
|
125
|
+
// if search is focused, then select first item.
|
|
126
|
+
// otherwise if view more is focused then select item should be undefined.
|
|
127
|
+
const selectedItemIndex = focusOnSearch ? 0 : focusOnViewMore ? undefined : safeIndex;
|
|
128
|
+
return {
|
|
129
|
+
...state,
|
|
130
|
+
focusOnSearch,
|
|
131
|
+
focusOnViewMore,
|
|
132
|
+
selectedItemIndex,
|
|
133
|
+
focusedItemIndex: isLastItemFocused ? undefined : safeIndex
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// up arrow key is pressed or left arrow key is pressed.
|
|
138
|
+
if (state.focusedItemIndex !== undefined && action.payload.positions && action.payload.positions <= -1) {
|
|
139
|
+
// if arrow up key is pressed when focus is in first row,
|
|
140
|
+
// or, arrow left key is pressed when first item is focused,
|
|
141
|
+
// then newIndex will become less than zero.
|
|
142
|
+
// In this case, focus search, and, kept previously selected item.
|
|
143
|
+
const isFirstRowFocused = newIndex < 0;
|
|
144
|
+
// if focus goes to search then kept last selected item in first row.
|
|
145
|
+
const selectedItemIndex = isFirstRowFocused ? state.selectedItemIndex : safeIndex;
|
|
146
|
+
return {
|
|
147
|
+
...state,
|
|
148
|
+
// focus search if first item is focused on up or left arrow key
|
|
149
|
+
focusOnSearch: isFirstRowFocused,
|
|
150
|
+
focusOnViewMore: false,
|
|
151
|
+
focusedItemIndex: isFirstRowFocused ? undefined : safeIndex,
|
|
152
|
+
selectedItemIndex
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
return {
|
|
156
|
+
...state,
|
|
157
|
+
focusOnSearch: false,
|
|
158
|
+
focusOnViewMore: false,
|
|
159
|
+
selectedItemIndex: safeIndex,
|
|
160
|
+
focusedItemIndex: safeIndex
|
|
161
|
+
};
|
|
162
|
+
};
|
|
163
|
+
const initialState = {
|
|
164
|
+
focusOnSearch: true,
|
|
165
|
+
focusOnViewMore: false,
|
|
166
|
+
selectedItemIndex: 0,
|
|
167
|
+
focusedItemIndex: undefined,
|
|
168
|
+
listSize: 0
|
|
169
|
+
};
|
|
170
|
+
const getInitialState = (listSize, canFocusViewMore) => initialState => ({
|
|
171
|
+
...initialState,
|
|
172
|
+
listSize,
|
|
173
|
+
canFocusViewMore
|
|
174
|
+
});
|
|
175
|
+
function useSelectAndFocusOnArrowNavigation(listSize, step, canFocusViewMore) {
|
|
176
|
+
const [state, dispatch] = useReducer(reducer, initialState, getInitialState(listSize, canFocusViewMore));
|
|
177
|
+
useEffect(() => {
|
|
178
|
+
dispatch({
|
|
179
|
+
type: ACTIONS.UPDATE_STATE,
|
|
180
|
+
payload: {
|
|
181
|
+
canFocusViewMore
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
}, [canFocusViewMore]);
|
|
185
|
+
const {
|
|
186
|
+
selectedItemIndex,
|
|
187
|
+
focusedItemIndex,
|
|
188
|
+
focusOnSearch,
|
|
189
|
+
focusOnViewMore
|
|
190
|
+
} = state;
|
|
191
|
+
const reset = useCallback(listSize => {
|
|
192
|
+
let payload = {
|
|
193
|
+
...initialState,
|
|
194
|
+
listSize
|
|
195
|
+
};
|
|
196
|
+
dispatch({
|
|
197
|
+
type: ACTIONS.UPDATE_STATE,
|
|
198
|
+
payload
|
|
199
|
+
});
|
|
200
|
+
}, []);
|
|
201
|
+
const removeFocusFromSearchAndSetOnItem = useCallback(index => {
|
|
202
|
+
const payload = {
|
|
203
|
+
focusedItemIndex: index,
|
|
204
|
+
selectedItemIndex: index,
|
|
205
|
+
focusOnSearch: false,
|
|
206
|
+
focusOnViewMore: false
|
|
207
|
+
};
|
|
208
|
+
dispatch({
|
|
209
|
+
type: ACTIONS.UPDATE_STATE,
|
|
210
|
+
payload
|
|
211
|
+
});
|
|
212
|
+
}, [dispatch]);
|
|
213
|
+
const setFocusOnSearch = useCallback(() => {
|
|
214
|
+
dispatch({
|
|
215
|
+
type: ACTIONS.FOCUS_SEARCH,
|
|
216
|
+
payload: {}
|
|
217
|
+
});
|
|
218
|
+
}, [dispatch]);
|
|
219
|
+
const isMoving = useRef(false);
|
|
220
|
+
const move = useCallback((e, positions, actualStep) => {
|
|
221
|
+
e.preventDefault();
|
|
222
|
+
e.stopPropagation();
|
|
223
|
+
|
|
224
|
+
// avoid firing 2 moves at the same time when holding an arrow down as this can freeze the screen
|
|
225
|
+
if (!isMoving.current) {
|
|
226
|
+
isMoving.current = true;
|
|
227
|
+
requestAnimationFrame(() => {
|
|
228
|
+
isMoving.current = false;
|
|
229
|
+
dispatch({
|
|
230
|
+
type: ACTIONS.MOVE,
|
|
231
|
+
payload: {
|
|
232
|
+
positions,
|
|
233
|
+
step: actualStep
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
}, []);
|
|
239
|
+
const onKeyDown = useCallback(e => {
|
|
240
|
+
const avoidKeysWhileSearching = ['/',
|
|
241
|
+
// While already focused on search bar, let users type in.
|
|
242
|
+
'ArrowRight', 'ArrowLeft'];
|
|
243
|
+
if (focusOnSearch && avoidKeysWhileSearching.includes(e.key)) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
switch (e.key) {
|
|
247
|
+
case '/':
|
|
248
|
+
e.preventDefault();
|
|
249
|
+
e.stopPropagation();
|
|
250
|
+
return setFocusOnSearch();
|
|
251
|
+
case 'ArrowRight':
|
|
252
|
+
return move(e, +1);
|
|
253
|
+
case 'ArrowLeft':
|
|
254
|
+
return move(e, -1);
|
|
255
|
+
case 'ArrowDown':
|
|
256
|
+
return move(e, +step);
|
|
257
|
+
case 'ArrowUp':
|
|
258
|
+
return move(e, -step, step);
|
|
259
|
+
}
|
|
260
|
+
}, [focusOnSearch, setFocusOnSearch, move, step]);
|
|
261
|
+
useEffect(() => {
|
|
262
|
+
// To reset selection when user filters
|
|
263
|
+
reset(listSize);
|
|
264
|
+
}, [listSize, reset]);
|
|
265
|
+
return {
|
|
266
|
+
selectedItemIndex,
|
|
267
|
+
onKeyDown,
|
|
268
|
+
focusOnSearch,
|
|
269
|
+
focusOnViewMore,
|
|
270
|
+
setFocusOnSearch,
|
|
271
|
+
focusedItemIndex,
|
|
272
|
+
setFocusedItemIndex: removeFocusFromSearchAndSetOnItem
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
export const ensureSafeIndex = (index, listSize) => {
|
|
276
|
+
if (index < 0) {
|
|
277
|
+
return 0;
|
|
278
|
+
}
|
|
279
|
+
if (index > listSize) {
|
|
280
|
+
return listSize;
|
|
281
|
+
}
|
|
282
|
+
return index;
|
|
283
|
+
};
|
|
284
|
+
export default useSelectAndFocusOnArrowNavigation;
|
|
@@ -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 = "74.
|
|
3
|
+
const packageVersion = "74.58.1";
|
|
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
|
|
@@ -9,7 +9,7 @@ import { themed } from '@atlaskit/theme/components';
|
|
|
9
9
|
import { borderRadius } from '@atlaskit/theme/constants';
|
|
10
10
|
import Layer from '../Layer';
|
|
11
11
|
const packageName = "@atlaskit/editor-common";
|
|
12
|
-
const packageVersion = "74.
|
|
12
|
+
const packageVersion = "74.58.1";
|
|
13
13
|
const halfFocusRing = 1;
|
|
14
14
|
const dropOffset = '0, 8';
|
|
15
15
|
class DropList extends Component {
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { isPerformanceAPIAvailable } from './is-performance-api-available';
|
|
2
|
-
|
|
3
2
|
/**
|
|
4
3
|
* Monitors if a pages enters a visibility state which will lead to
|
|
5
4
|
* distorted duration measurements (where the measurement uses the
|
|
6
5
|
* requestAnimationFrame api).
|
|
7
6
|
*/
|
|
8
|
-
export
|
|
7
|
+
export const getDistortedDurationMonitor = () => {
|
|
9
8
|
if (typeof document === 'undefined') {
|
|
10
9
|
return {
|
|
11
10
|
distortedDuration: false,
|
|
@@ -37,7 +36,7 @@ export function getDistortedDurationMonitor() {
|
|
|
37
36
|
document.removeEventListener('visibilitychange', handleVisibilityChange);
|
|
38
37
|
}
|
|
39
38
|
};
|
|
40
|
-
}
|
|
39
|
+
};
|
|
41
40
|
|
|
42
41
|
/**
|
|
43
42
|
* Measures time it takes to render a frame including -> style, paint, layout and composition.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SEVERITY } from '../analytics';
|
|
2
2
|
import { isPerformanceObserverLongTaskAvailable } from './is-performance-api-available';
|
|
3
|
+
import { getDistortedDurationMonitor } from './measure-render';
|
|
3
4
|
export function measureTTI(onMeasureComplete, idleThreshold = 1000, cancelAfter = 60,
|
|
4
5
|
// Dependency Injection for easier testing
|
|
5
6
|
PerfObserver) {
|
|
@@ -7,6 +8,8 @@ PerfObserver) {
|
|
|
7
8
|
return;
|
|
8
9
|
}
|
|
9
10
|
const start = performance.now();
|
|
11
|
+
// Keeping track of users moving away from the tab, which distorts the TTI measurement
|
|
12
|
+
const distortedDurationMonitor = getDistortedDurationMonitor();
|
|
10
13
|
let prevLongTask;
|
|
11
14
|
let lastLongTask = {
|
|
12
15
|
startTime: start,
|
|
@@ -37,13 +40,16 @@ PerfObserver) {
|
|
|
37
40
|
const canceled = elapsedTimeMs > cancelAfterMs;
|
|
38
41
|
if (!prevLongTask) {
|
|
39
42
|
observer.disconnect();
|
|
40
|
-
|
|
43
|
+
distortedDurationMonitor.cleanup();
|
|
44
|
+
return onMeasureComplete(prevEnd, 0, false, distortedDurationMonitor.distortedDuration);
|
|
41
45
|
} else if (lastLongTask.startTime - prevEnd >= idleThreshold) {
|
|
42
46
|
observer.disconnect();
|
|
43
|
-
|
|
47
|
+
distortedDurationMonitor.cleanup();
|
|
48
|
+
return onMeasureComplete(prevEnd, prevEnd - start, canceled, distortedDurationMonitor.distortedDuration);
|
|
44
49
|
} else if (now - lastEnd >= idleThreshold || canceled) {
|
|
45
50
|
observer.disconnect();
|
|
46
|
-
|
|
51
|
+
distortedDurationMonitor.cleanup();
|
|
52
|
+
return onMeasureComplete(lastEnd, lastEnd - start, canceled, distortedDurationMonitor.distortedDuration);
|
|
47
53
|
}
|
|
48
54
|
return setTimeout(checkIdle, idleThreshold);
|
|
49
55
|
};
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
|
2
|
+
import _createClass from "@babel/runtime/helpers/createClass";
|
|
3
|
+
import _assertThisInitialized from "@babel/runtime/helpers/assertThisInitialized";
|
|
4
|
+
import _inherits from "@babel/runtime/helpers/inherits";
|
|
5
|
+
import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
|
|
6
|
+
import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
|
|
7
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
8
|
+
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
|
|
9
|
+
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
|
|
10
|
+
import React, { PureComponent } from 'react';
|
|
11
|
+
import StatelessElementBrowser from './components/StatelessElementBrowser';
|
|
12
|
+
var ElementBrowser = /*#__PURE__*/function (_PureComponent) {
|
|
13
|
+
_inherits(ElementBrowser, _PureComponent);
|
|
14
|
+
var _super = _createSuper(ElementBrowser);
|
|
15
|
+
function ElementBrowser() {
|
|
16
|
+
var _this;
|
|
17
|
+
_classCallCheck(this, ElementBrowser);
|
|
18
|
+
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
19
|
+
args[_key] = arguments[_key];
|
|
20
|
+
}
|
|
21
|
+
_this = _super.call.apply(_super, [this].concat(args));
|
|
22
|
+
_defineProperty(_assertThisInitialized(_this), "state", {
|
|
23
|
+
categories: [],
|
|
24
|
+
items: [],
|
|
25
|
+
searchTerm: '',
|
|
26
|
+
selectedCategory: _this.props.defaultCategory
|
|
27
|
+
});
|
|
28
|
+
_defineProperty(_assertThisInitialized(_this), "getCategories", function () {
|
|
29
|
+
var items = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _this.fetchItems();
|
|
30
|
+
return (
|
|
31
|
+
// NOTE: we fetch all items to determine available categories.
|
|
32
|
+
_this.filterCategories(items, _this.props.categories)
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
_defineProperty(_assertThisInitialized(_this), "filterCategories", function (items) {
|
|
36
|
+
var categories = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
|
37
|
+
var showCategories = _this.props.showCategories;
|
|
38
|
+
if (!showCategories) {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
return categories.filter(function (category) {
|
|
42
|
+
return category.name === 'all' || items.some(function (item) {
|
|
43
|
+
return (item.categories || []).includes(category.name);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
_defineProperty(_assertThisInitialized(_this), "fetchItems", function (query, category) {
|
|
48
|
+
return _this.props.getItems(query, category);
|
|
49
|
+
});
|
|
50
|
+
_defineProperty(_assertThisInitialized(_this), "handleSearch", function (searchTerm) {
|
|
51
|
+
var defaultCategory = _this.props.defaultCategory;
|
|
52
|
+
_this.setState({
|
|
53
|
+
searchTerm: searchTerm,
|
|
54
|
+
selectedCategory: defaultCategory
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
_defineProperty(_assertThisInitialized(_this), "handleCategorySelection", function (clickedCategory) {
|
|
58
|
+
var stateCategoryValue = _this.state.selectedCategory;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Reset selection if clicked on the same category twice.
|
|
62
|
+
*/
|
|
63
|
+
if (stateCategoryValue === clickedCategory.name) {
|
|
64
|
+
return _this.setState({
|
|
65
|
+
selectedCategory: _this.props.defaultCategory
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
_this.setState({
|
|
69
|
+
selectedCategory: clickedCategory.name,
|
|
70
|
+
searchTerm: ''
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
return _this;
|
|
74
|
+
}
|
|
75
|
+
_createClass(ElementBrowser, [{
|
|
76
|
+
key: "componentDidMount",
|
|
77
|
+
value: function componentDidMount() {
|
|
78
|
+
var items = this.fetchItems();
|
|
79
|
+
this.setState({
|
|
80
|
+
items: items,
|
|
81
|
+
categories: this.getCategories(items)
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}, {
|
|
85
|
+
key: "componentDidUpdate",
|
|
86
|
+
value: function componentDidUpdate(prevProps, prevState) {
|
|
87
|
+
var _this$state = this.state,
|
|
88
|
+
searchTerm = _this$state.searchTerm,
|
|
89
|
+
selectedCategory = _this$state.selectedCategory;
|
|
90
|
+
|
|
91
|
+
// Update both items and categories when there's a new getItems
|
|
92
|
+
if (this.props.getItems !== prevProps.getItems) {
|
|
93
|
+
this.setState({
|
|
94
|
+
categories: this.getCategories(),
|
|
95
|
+
items: this.fetchItems(searchTerm, selectedCategory)
|
|
96
|
+
});
|
|
97
|
+
} else if (searchTerm !== prevState.searchTerm || selectedCategory !== prevState.selectedCategory) {
|
|
98
|
+
this.setState({
|
|
99
|
+
items: this.fetchItems(searchTerm, selectedCategory)
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}, {
|
|
104
|
+
key: "render",
|
|
105
|
+
value: function render() {
|
|
106
|
+
var _this$props = this.props,
|
|
107
|
+
onInsertItem = _this$props.onInsertItem,
|
|
108
|
+
onSelectItem = _this$props.onSelectItem,
|
|
109
|
+
showSearch = _this$props.showSearch,
|
|
110
|
+
showCategories = _this$props.showCategories,
|
|
111
|
+
mode = _this$props.mode,
|
|
112
|
+
emptyStateHandler = _this$props.emptyStateHandler,
|
|
113
|
+
viewMoreItem = _this$props.viewMoreItem;
|
|
114
|
+
var _this$state2 = this.state,
|
|
115
|
+
categories = _this$state2.categories,
|
|
116
|
+
searchTerm = _this$state2.searchTerm,
|
|
117
|
+
selectedCategory = _this$state2.selectedCategory,
|
|
118
|
+
items = _this$state2.items;
|
|
119
|
+
return /*#__PURE__*/React.createElement(StatelessElementBrowser, {
|
|
120
|
+
items: items,
|
|
121
|
+
categories: categories,
|
|
122
|
+
onSearch: this.handleSearch,
|
|
123
|
+
onSelectCategory: this.handleCategorySelection,
|
|
124
|
+
onSelectItem: onSelectItem,
|
|
125
|
+
onInsertItem: onInsertItem,
|
|
126
|
+
selectedCategory: selectedCategory,
|
|
127
|
+
showSearch: showSearch,
|
|
128
|
+
showCategories: showCategories,
|
|
129
|
+
mode: mode,
|
|
130
|
+
searchTerm: searchTerm,
|
|
131
|
+
emptyStateHandler: emptyStateHandler,
|
|
132
|
+
viewMoreItem: viewMoreItem
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}]);
|
|
136
|
+
return ElementBrowser;
|
|
137
|
+
}(PureComponent);
|
|
138
|
+
_defineProperty(ElementBrowser, "defaultProps", {
|
|
139
|
+
defaultCategory: 'all',
|
|
140
|
+
onInsertItem: function onInsertItem() {}
|
|
141
|
+
});
|
|
142
|
+
export { ElementBrowser as default };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import _taggedTemplateLiteral from "@babel/runtime/helpers/taggedTemplateLiteral";
|
|
2
|
+
var _templateObject, _templateObject2;
|
|
3
|
+
/** @jsx jsx */
|
|
4
|
+
import { useEffect, useRef } from 'react';
|
|
5
|
+
import { css, jsx } from '@emotion/react';
|
|
6
|
+
import { ButtonItem, Section } from '@atlaskit/menu';
|
|
7
|
+
var itemBefore = css(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n width: 40px;\n height: 40px;\n box-sizing: border-box;\n display: flex;\n justify-content: center;\n align-items: center;\n margin-right: ", ";\n"])), "var(--ds-space-050, 4px)");
|
|
8
|
+
export var ViewMore = function ViewMore(_ref) {
|
|
9
|
+
var item = _ref.item,
|
|
10
|
+
focus = _ref.focus;
|
|
11
|
+
var ref = useRef(null);
|
|
12
|
+
useEffect(function () {
|
|
13
|
+
if (ref.current && focus) {
|
|
14
|
+
ref.current.focus();
|
|
15
|
+
}
|
|
16
|
+
}, [focus]);
|
|
17
|
+
return jsx(Section, {
|
|
18
|
+
hasSeparator: true
|
|
19
|
+
}, jsx(ButtonItem, {
|
|
20
|
+
onClick: item.action,
|
|
21
|
+
iconBefore: jsx("div", {
|
|
22
|
+
css: itemBefore
|
|
23
|
+
}, item.icon()),
|
|
24
|
+
"aria-describedby": item.title,
|
|
25
|
+
"data-testid": "view-more-elements-item"
|
|
26
|
+
// @ts-ignore Overriding Menu styles is not supported
|
|
27
|
+
,
|
|
28
|
+
css: css(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["\n padding: 0px ", ";\n "])), "var(--ds-space-150, 12px)"),
|
|
29
|
+
ref: ref
|
|
30
|
+
}, item.title));
|
|
31
|
+
};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import _taggedTemplateLiteral from "@babel/runtime/helpers/taggedTemplateLiteral";
|
|
2
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
3
|
+
import _extends from "@babel/runtime/helpers/extends";
|
|
4
|
+
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
5
|
+
import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
|
|
6
|
+
var _templateObject;
|
|
7
|
+
var _excluded = ["categories"],
|
|
8
|
+
_excluded2 = ["buttonStyles"];
|
|
9
|
+
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; }
|
|
10
|
+
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; }
|
|
11
|
+
/** @jsx jsx */
|
|
12
|
+
|
|
13
|
+
import React, { Fragment, memo, useCallback } from 'react';
|
|
14
|
+
import { css, jsx } from '@emotion/react';
|
|
15
|
+
import { withAnalyticsContext } from '@atlaskit/analytics-next';
|
|
16
|
+
import Button from '@atlaskit/button/custom-theme-button';
|
|
17
|
+
import { B400, B50, N800 } from '@atlaskit/theme/colors';
|
|
18
|
+
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, fireAnalyticsEvent } from '../../analytics';
|
|
19
|
+
import { DEVICE_BREAKPOINT_NUMBERS, GRID_SIZE } from '../constants';
|
|
20
|
+
import useFocus from '../hooks/use-focus';
|
|
21
|
+
function CategoryList(_ref) {
|
|
22
|
+
var _ref$categories = _ref.categories,
|
|
23
|
+
categories = _ref$categories === void 0 ? [] : _ref$categories,
|
|
24
|
+
props = _objectWithoutProperties(_ref, _excluded);
|
|
25
|
+
var _React$useState = React.useState(null),
|
|
26
|
+
_React$useState2 = _slicedToArray(_React$useState, 2),
|
|
27
|
+
focusedCategoryIndex = _React$useState2[0],
|
|
28
|
+
setFocusedCategoryIndex = _React$useState2[1];
|
|
29
|
+
return jsx(Fragment, null, categories.map(function (category, index) {
|
|
30
|
+
return jsx(CategoryListItem, _extends({
|
|
31
|
+
key: category.title,
|
|
32
|
+
index: index,
|
|
33
|
+
category: category,
|
|
34
|
+
focus: focusedCategoryIndex === index,
|
|
35
|
+
setFocusedCategoryIndex: setFocusedCategoryIndex
|
|
36
|
+
}, props));
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
function CategoryListItem(_ref2) {
|
|
40
|
+
var category = _ref2.category,
|
|
41
|
+
onSelectCategory = _ref2.onSelectCategory,
|
|
42
|
+
selectedCategory = _ref2.selectedCategory,
|
|
43
|
+
index = _ref2.index,
|
|
44
|
+
focus = _ref2.focus,
|
|
45
|
+
setFocusedCategoryIndex = _ref2.setFocusedCategoryIndex,
|
|
46
|
+
createAnalyticsEvent = _ref2.createAnalyticsEvent;
|
|
47
|
+
var ref = useFocus(focus);
|
|
48
|
+
var onClick = useCallback(function () {
|
|
49
|
+
onSelectCategory(category);
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* When user double clicks on same category, focus on first item.
|
|
53
|
+
*/
|
|
54
|
+
if (selectedCategory === category.name) {
|
|
55
|
+
setFocusedCategoryIndex(0);
|
|
56
|
+
} else {
|
|
57
|
+
setFocusedCategoryIndex(index);
|
|
58
|
+
}
|
|
59
|
+
fireAnalyticsEvent(createAnalyticsEvent)({
|
|
60
|
+
payload: {
|
|
61
|
+
action: ACTION.CLICKED,
|
|
62
|
+
actionSubject: ACTION_SUBJECT.BUTTON,
|
|
63
|
+
actionSubjectId: ACTION_SUBJECT_ID.BUTTON_CATEGORY,
|
|
64
|
+
eventType: EVENT_TYPE.TRACK
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}, [onSelectCategory, category, index, selectedCategory, setFocusedCategoryIndex, createAnalyticsEvent]);
|
|
68
|
+
var onFocus = useCallback(function () {
|
|
69
|
+
if (!focus) {
|
|
70
|
+
setFocusedCategoryIndex(index);
|
|
71
|
+
}
|
|
72
|
+
}, [focus, index, setFocusedCategoryIndex]);
|
|
73
|
+
var getTheme = useCallback(function (currentTheme, themeProps) {
|
|
74
|
+
var _currentTheme = currentTheme(themeProps),
|
|
75
|
+
buttonStyles = _currentTheme.buttonStyles,
|
|
76
|
+
rest = _objectWithoutProperties(_currentTheme, _excluded2);
|
|
77
|
+
return _objectSpread({
|
|
78
|
+
buttonStyles: _objectSpread(_objectSpread({}, buttonStyles), {}, {
|
|
79
|
+
textAlign: 'start',
|
|
80
|
+
marginLeft: "var(--ds-space-025, 2px)",
|
|
81
|
+
height: '100%',
|
|
82
|
+
width: '100%',
|
|
83
|
+
color: category.name !== selectedCategory ? "var(--ds-text, ".concat(N800, ")") : "var(--ds-text-selected, ".concat(B400, ")")
|
|
84
|
+
}, category.name === selectedCategory && {
|
|
85
|
+
background: "var(--ds-background-selected, ".concat(B50, ")")
|
|
86
|
+
})
|
|
87
|
+
}, rest);
|
|
88
|
+
}, [category.name, selectedCategory]);
|
|
89
|
+
return jsx("div", {
|
|
90
|
+
css: buttonWrapper
|
|
91
|
+
}, jsx(Button, {
|
|
92
|
+
appearance: "subtle",
|
|
93
|
+
isSelected: selectedCategory === category.name,
|
|
94
|
+
onClick: onClick,
|
|
95
|
+
onFocus: onFocus,
|
|
96
|
+
theme: getTheme,
|
|
97
|
+
ref: ref,
|
|
98
|
+
testId: "element-browser-category-item"
|
|
99
|
+
}, category.title));
|
|
100
|
+
}
|
|
101
|
+
var buttonWrapper = css(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n height: ", "px;\n margin: ", " ", "\n ", " 0;\n\n @media (min-width: ", "px) {\n :not(:last-child) {\n margin-bottom: 0;\n }\n }\n"])), GRID_SIZE * 4, "var(--ds-space-050, 4px)", "var(--ds-space-050, 4px)", "var(--ds-space-050, 4px)", DEVICE_BREAKPOINT_NUMBERS.medium);
|
|
102
|
+
var MemoizedCategoryListWithAnalytics = /*#__PURE__*/memo(withAnalyticsContext({
|
|
103
|
+
component: 'CategoryList'
|
|
104
|
+
})(CategoryList));
|
|
105
|
+
export default MemoizedCategoryListWithAnalytics;
|