@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,258 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/extends";
|
|
2
|
+
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
3
|
+
import _taggedTemplateLiteral from "@babel/runtime/helpers/taggedTemplateLiteral";
|
|
4
|
+
var _templateObject, _templateObject2, _templateObject3, _templateObject4, _templateObject5, _templateObject6, _templateObject7, _templateObject8, _templateObject9, _templateObject10, _templateObject11, _templateObject12, _templateObject13, _templateObject14, _templateObject15;
|
|
5
|
+
/** @jsx jsx */
|
|
6
|
+
import React, { memo, useCallback, useEffect, useState } from 'react';
|
|
7
|
+
import { css, jsx } from '@emotion/react';
|
|
8
|
+
import { FormattedMessage } from 'react-intl-next';
|
|
9
|
+
import { withAnalyticsContext, withAnalyticsEvents } from '@atlaskit/analytics-next';
|
|
10
|
+
import { ACTION, ACTION_SUBJECT, EVENT_TYPE, fireAnalyticsEvent } from '../../analytics';
|
|
11
|
+
import { DEVICE_BREAKPOINT_NUMBERS, GRID_SIZE, INLINE_SIDEBAR_HEIGHT, SIDEBAR_HEADING_PADDING_LEFT, SIDEBAR_HEADING_WRAPPER_HEIGHT, SIDEBAR_WIDTH } from '../constants';
|
|
12
|
+
import useContainerWidth from '../hooks/use-container-width';
|
|
13
|
+
import useSelectAndFocusOnArrowNavigation from '../hooks/use-select-and-focus-on-arrow-navigation';
|
|
14
|
+
import { ViewMore } from '../ViewMore';
|
|
15
|
+
import CategoryList from './CategoryList';
|
|
16
|
+
import ElementList from './ElementList/ElementList';
|
|
17
|
+
import ElementSearch from './ElementSearch';
|
|
18
|
+
var wrapper = css(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n width: 100%;\n max-height: inherit;\n overflow: hidden;\n"])));
|
|
19
|
+
var baseBrowserContainerStyles = css(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["\n display: flex;\n height: 100%;\n /** Needed for Safari to work with current css.\n * 100% heights wont work and\n * will default to auto if one of the containers doesn't have a specified height in pixels.\n * Setting the min-height to fill available fits safari's needs and the above 100% height works on the rest of the browsers.\n */\n\n /* TODO: fix in develop: https://atlassian.slack.com/archives/CFG3PSQ9E/p1647395052443259?thread_ts=1647394572.556029&cid=CFG3PSQ9E */\n\n /* stylelint-disable-next-line */\n min-height: -webkit-fill-available;\n"])));
|
|
20
|
+
var mobileElementBrowserContainer = css(_templateObject3 || (_templateObject3 = _taggedTemplateLiteral(["\n ", ";\n flex-direction: column;\n"])), baseBrowserContainerStyles);
|
|
21
|
+
var elementBrowserContainer = css(_templateObject4 || (_templateObject4 = _taggedTemplateLiteral(["\n ", ";\n flex-direction: row;\n"])), baseBrowserContainerStyles);
|
|
22
|
+
var baseSidebarStyles = css(_templateObject5 || (_templateObject5 = _taggedTemplateLiteral(["\n display: flex;\n flex-direction: column;\n\n overflow-x: auto;\n overflow-y: hidden;\n"])));
|
|
23
|
+
var mobileSideBar = css(_templateObject6 || (_templateObject6 = _taggedTemplateLiteral(["\n ", ";\n flex: 0 0 ", ";\n padding: ", " ", " 0\n ", ";\n"])), baseSidebarStyles, INLINE_SIDEBAR_HEIGHT, "var(--ds-space-150, 12px)", "var(--ds-space-150, 12px)", "var(--ds-space-150, 12px)");
|
|
24
|
+
var mobileSideBarShowCategories = css(_templateObject7 || (_templateObject7 = _taggedTemplateLiteral(["\n flex: 0 0 auto;\n"])));
|
|
25
|
+
var sideBar = css(_templateObject8 || (_templateObject8 = _taggedTemplateLiteral(["\n ", ";\n flex: 0 0 'auto';\n"])), baseSidebarStyles);
|
|
26
|
+
var sideBarShowCategories = css(_templateObject9 || (_templateObject9 = _taggedTemplateLiteral(["\n ", ";\n flex: 0 0 ", ";\n"])), baseSidebarStyles, SIDEBAR_WIDTH);
|
|
27
|
+
var sidebarHeading = css(_templateObject10 || (_templateObject10 = _taggedTemplateLiteral(["\n flex: 0 0 ", ";\n display: inline-flex;\n align-items: center;\n padding-left: ", ";\n font-weight: 700;\n"])), SIDEBAR_HEADING_WRAPPER_HEIGHT, SIDEBAR_HEADING_PADDING_LEFT);
|
|
28
|
+
var mobileMainContent = css(_templateObject11 || (_templateObject11 = _taggedTemplateLiteral(["\n flex: 1 1 auto;\n\n display: flex;\n flex-direction: column;\n\n overflow-y: auto;\n height: 100%;\n"])));
|
|
29
|
+
var mainContent = css(_templateObject12 || (_templateObject12 = _taggedTemplateLiteral(["\n ", "\n margin-left: ", "px;\n // Needed for safari\n height: auto;\n"])), mobileMainContent, GRID_SIZE * 2);
|
|
30
|
+
var searchContainer = css(_templateObject13 || (_templateObject13 = _taggedTemplateLiteral(["\n padding-bottom: ", "px;\n"])), GRID_SIZE * 2);
|
|
31
|
+
var mobileCategoryListWrapper = css(_templateObject14 || (_templateObject14 = _taggedTemplateLiteral(["\n display: flex;\n overflow-x: auto;\n\n padding: ", "px 0 ", "px 0;\n min-height: ", "px;\n\n overflow: -moz-scrollbars-none;\n ::-webkit-scrollbar {\n display: none;\n }\n scrollbar-width: none;\n -ms-overflow-style: none;\n"])), GRID_SIZE, GRID_SIZE * 2, GRID_SIZE * 4);
|
|
32
|
+
var categoryListWrapper = css(_templateObject15 || (_templateObject15 = _taggedTemplateLiteral(["\n ", "\n padding: 0;\n margin-top: ", "px;\n flex-direction: column;\n"])), mobileCategoryListWrapper, GRID_SIZE * 3);
|
|
33
|
+
function StatelessElementBrowser(props) {
|
|
34
|
+
var items = props.items,
|
|
35
|
+
onSelectItem = props.onSelectItem,
|
|
36
|
+
onInsertItem = props.onInsertItem,
|
|
37
|
+
viewMoreItem = props.viewMoreItem;
|
|
38
|
+
var _useContainerWidth = useContainerWidth(),
|
|
39
|
+
containerWidth = _useContainerWidth.containerWidth,
|
|
40
|
+
ContainerWidthMonitor = _useContainerWidth.ContainerWidthMonitor;
|
|
41
|
+
var _useState = useState(1),
|
|
42
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
43
|
+
columnCount = _useState2[0],
|
|
44
|
+
setColumnCount = _useState2[1];
|
|
45
|
+
var _useSelectAndFocusOnA = useSelectAndFocusOnArrowNavigation(items.length - 1, columnCount, !!viewMoreItem),
|
|
46
|
+
selectedItemIndex = _useSelectAndFocusOnA.selectedItemIndex,
|
|
47
|
+
focusedItemIndex = _useSelectAndFocusOnA.focusedItemIndex,
|
|
48
|
+
setFocusedItemIndex = _useSelectAndFocusOnA.setFocusedItemIndex,
|
|
49
|
+
focusOnSearch = _useSelectAndFocusOnA.focusOnSearch,
|
|
50
|
+
focusOnViewMore = _useSelectAndFocusOnA.focusOnViewMore,
|
|
51
|
+
onKeyDown = _useSelectAndFocusOnA.onKeyDown,
|
|
52
|
+
setFocusOnSearch = _useSelectAndFocusOnA.setFocusOnSearch;
|
|
53
|
+
useEffect(function () {
|
|
54
|
+
fireAnalyticsEvent(props.createAnalyticsEvent)({
|
|
55
|
+
payload: {
|
|
56
|
+
action: ACTION.OPENED,
|
|
57
|
+
actionSubject: ACTION_SUBJECT.ELEMENT_BROWSER,
|
|
58
|
+
eventType: EVENT_TYPE.UI,
|
|
59
|
+
attributes: {
|
|
60
|
+
mode: props.mode
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
return function () {
|
|
65
|
+
fireAnalyticsEvent(props.createAnalyticsEvent)({
|
|
66
|
+
payload: {
|
|
67
|
+
action: ACTION.CLOSED,
|
|
68
|
+
actionSubject: ACTION_SUBJECT.ELEMENT_BROWSER,
|
|
69
|
+
eventType: EVENT_TYPE.UI,
|
|
70
|
+
attributes: {
|
|
71
|
+
mode: props.mode
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
}, [props.createAnalyticsEvent, props.mode]);
|
|
77
|
+
|
|
78
|
+
/* Only for hitting enter to select item when focused on search bar,
|
|
79
|
+
* The actual enter key press is handled on individual items level.
|
|
80
|
+
*/
|
|
81
|
+
var selectedItem = selectedItemIndex !== undefined ? items[selectedItemIndex] : null;
|
|
82
|
+
var onItemsEnterKeyPress = useCallback(function (e) {
|
|
83
|
+
if (e.key !== 'Enter') {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (onInsertItem && selectedItem != null) {
|
|
87
|
+
onInsertItem(selectedItem);
|
|
88
|
+
}
|
|
89
|
+
e.preventDefault();
|
|
90
|
+
}, [onInsertItem, selectedItem]);
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* On arrow key selection and clicks the selectedItemIndex will change.
|
|
94
|
+
* Making sure to update parent component.
|
|
95
|
+
*/
|
|
96
|
+
useEffect(function () {
|
|
97
|
+
if (onSelectItem && selectedItem != null) {
|
|
98
|
+
onSelectItem(selectedItem);
|
|
99
|
+
}
|
|
100
|
+
}, [onSelectItem, selectedItem]);
|
|
101
|
+
return jsx("div", {
|
|
102
|
+
css: wrapper,
|
|
103
|
+
"data-testid": "element-browser"
|
|
104
|
+
}, jsx(ContainerWidthMonitor, null), containerWidth < DEVICE_BREAKPOINT_NUMBERS.medium ? jsx(MobileBrowser, _extends({}, props, {
|
|
105
|
+
selectedItemIndex: selectedItemIndex,
|
|
106
|
+
focusedItemIndex: focusedItemIndex,
|
|
107
|
+
setFocusedItemIndex: setFocusedItemIndex,
|
|
108
|
+
focusOnSearch: focusOnSearch,
|
|
109
|
+
setColumnCount: setColumnCount,
|
|
110
|
+
setFocusOnSearch: setFocusOnSearch,
|
|
111
|
+
onKeyPress: onItemsEnterKeyPress,
|
|
112
|
+
onKeyDown: onKeyDown,
|
|
113
|
+
viewMoreItem: viewMoreItem,
|
|
114
|
+
focusOnViewMore: focusOnViewMore
|
|
115
|
+
})) : jsx(DesktopBrowser, _extends({}, props, {
|
|
116
|
+
selectedItemIndex: selectedItemIndex,
|
|
117
|
+
focusedItemIndex: focusedItemIndex,
|
|
118
|
+
setFocusedItemIndex: setFocusedItemIndex,
|
|
119
|
+
focusOnSearch: focusOnSearch,
|
|
120
|
+
setColumnCount: setColumnCount,
|
|
121
|
+
setFocusOnSearch: setFocusOnSearch,
|
|
122
|
+
onKeyPress: onItemsEnterKeyPress,
|
|
123
|
+
onKeyDown: onKeyDown
|
|
124
|
+
})));
|
|
125
|
+
}
|
|
126
|
+
function MobileBrowser(_ref) {
|
|
127
|
+
var showCategories = _ref.showCategories,
|
|
128
|
+
showSearch = _ref.showSearch,
|
|
129
|
+
onSearch = _ref.onSearch,
|
|
130
|
+
mode = _ref.mode,
|
|
131
|
+
categories = _ref.categories,
|
|
132
|
+
onSelectCategory = _ref.onSelectCategory,
|
|
133
|
+
items = _ref.items,
|
|
134
|
+
onInsertItem = _ref.onInsertItem,
|
|
135
|
+
selectedCategory = _ref.selectedCategory,
|
|
136
|
+
selectedItemIndex = _ref.selectedItemIndex,
|
|
137
|
+
focusedItemIndex = _ref.focusedItemIndex,
|
|
138
|
+
setFocusedItemIndex = _ref.setFocusedItemIndex,
|
|
139
|
+
focusOnSearch = _ref.focusOnSearch,
|
|
140
|
+
focusOnViewMore = _ref.focusOnViewMore,
|
|
141
|
+
setColumnCount = _ref.setColumnCount,
|
|
142
|
+
setFocusOnSearch = _ref.setFocusOnSearch,
|
|
143
|
+
onKeyPress = _ref.onKeyPress,
|
|
144
|
+
onKeyDown = _ref.onKeyDown,
|
|
145
|
+
searchTerm = _ref.searchTerm,
|
|
146
|
+
createAnalyticsEvent = _ref.createAnalyticsEvent,
|
|
147
|
+
emptyStateHandler = _ref.emptyStateHandler,
|
|
148
|
+
viewMoreItem = _ref.viewMoreItem;
|
|
149
|
+
return jsx("div", {
|
|
150
|
+
css: mobileElementBrowserContainer,
|
|
151
|
+
onKeyDown: onKeyDown,
|
|
152
|
+
"data-testid": "mobile__element-browser"
|
|
153
|
+
}, jsx("div", {
|
|
154
|
+
css: showCategories ? [mobileSideBar, mobileSideBarShowCategories] : mobileSideBar
|
|
155
|
+
}, showSearch && jsx(ElementSearch, {
|
|
156
|
+
onSearch: onSearch,
|
|
157
|
+
onKeyDown: onKeyPress,
|
|
158
|
+
mode: mode,
|
|
159
|
+
focus: focusOnSearch,
|
|
160
|
+
onClick: setFocusOnSearch,
|
|
161
|
+
searchTerm: searchTerm
|
|
162
|
+
}), showCategories && jsx("nav", {
|
|
163
|
+
css: mobileCategoryListWrapper,
|
|
164
|
+
tabIndex: -1
|
|
165
|
+
}, jsx(CategoryList, {
|
|
166
|
+
categories: categories,
|
|
167
|
+
onSelectCategory: onSelectCategory,
|
|
168
|
+
selectedCategory: selectedCategory
|
|
169
|
+
}))), jsx("div", {
|
|
170
|
+
css: mobileMainContent
|
|
171
|
+
}, jsx(ElementList, {
|
|
172
|
+
items: items,
|
|
173
|
+
mode: mode,
|
|
174
|
+
onInsertItem: onInsertItem,
|
|
175
|
+
selectedItemIndex: selectedItemIndex,
|
|
176
|
+
focusedItemIndex: focusedItemIndex,
|
|
177
|
+
setFocusedItemIndex: setFocusedItemIndex,
|
|
178
|
+
setColumnCount: setColumnCount,
|
|
179
|
+
createAnalyticsEvent: createAnalyticsEvent,
|
|
180
|
+
emptyStateHandler: emptyStateHandler,
|
|
181
|
+
selectedCategory: selectedCategory,
|
|
182
|
+
searchTerm: searchTerm
|
|
183
|
+
})), viewMoreItem && jsx(ViewMore, {
|
|
184
|
+
item: viewMoreItem,
|
|
185
|
+
focus: focusOnViewMore
|
|
186
|
+
}));
|
|
187
|
+
}
|
|
188
|
+
function DesktopBrowser(_ref2) {
|
|
189
|
+
var showCategories = _ref2.showCategories,
|
|
190
|
+
showSearch = _ref2.showSearch,
|
|
191
|
+
onSearch = _ref2.onSearch,
|
|
192
|
+
mode = _ref2.mode,
|
|
193
|
+
categories = _ref2.categories,
|
|
194
|
+
onSelectCategory = _ref2.onSelectCategory,
|
|
195
|
+
items = _ref2.items,
|
|
196
|
+
onInsertItem = _ref2.onInsertItem,
|
|
197
|
+
selectedCategory = _ref2.selectedCategory,
|
|
198
|
+
selectedItemIndex = _ref2.selectedItemIndex,
|
|
199
|
+
focusedItemIndex = _ref2.focusedItemIndex,
|
|
200
|
+
setFocusedItemIndex = _ref2.setFocusedItemIndex,
|
|
201
|
+
focusOnSearch = _ref2.focusOnSearch,
|
|
202
|
+
setColumnCount = _ref2.setColumnCount,
|
|
203
|
+
setFocusOnSearch = _ref2.setFocusOnSearch,
|
|
204
|
+
onKeyPress = _ref2.onKeyPress,
|
|
205
|
+
onKeyDown = _ref2.onKeyDown,
|
|
206
|
+
searchTerm = _ref2.searchTerm,
|
|
207
|
+
createAnalyticsEvent = _ref2.createAnalyticsEvent,
|
|
208
|
+
emptyStateHandler = _ref2.emptyStateHandler;
|
|
209
|
+
return jsx("div", {
|
|
210
|
+
css: elementBrowserContainer,
|
|
211
|
+
"data-testid": "desktop__element-browser"
|
|
212
|
+
}, showCategories && jsx("div", {
|
|
213
|
+
css: showCategories ? sideBarShowCategories : sideBar
|
|
214
|
+
}, jsx("h2", {
|
|
215
|
+
css: sidebarHeading,
|
|
216
|
+
"data-testid": "sidebar-heading"
|
|
217
|
+
}, jsx(FormattedMessage, {
|
|
218
|
+
id: "fabric.editor.elementbrowser.sidebar.heading",
|
|
219
|
+
defaultMessage: "Browse",
|
|
220
|
+
description: "Sidebar heading"
|
|
221
|
+
})), jsx("nav", {
|
|
222
|
+
css: categoryListWrapper
|
|
223
|
+
}, jsx(CategoryList, {
|
|
224
|
+
categories: categories,
|
|
225
|
+
onSelectCategory: onSelectCategory,
|
|
226
|
+
selectedCategory: selectedCategory,
|
|
227
|
+
createAnalyticsEvent: createAnalyticsEvent
|
|
228
|
+
}))), jsx("div", {
|
|
229
|
+
css: mainContent,
|
|
230
|
+
onKeyDown: onKeyDown,
|
|
231
|
+
"data-testid": "main-content"
|
|
232
|
+
}, showSearch && jsx("div", {
|
|
233
|
+
css: searchContainer
|
|
234
|
+
}, jsx(ElementSearch, {
|
|
235
|
+
onSearch: onSearch,
|
|
236
|
+
onKeyDown: onKeyPress,
|
|
237
|
+
mode: mode,
|
|
238
|
+
focus: focusOnSearch,
|
|
239
|
+
onClick: setFocusOnSearch,
|
|
240
|
+
searchTerm: searchTerm
|
|
241
|
+
})), jsx(ElementList, {
|
|
242
|
+
items: items,
|
|
243
|
+
mode: mode,
|
|
244
|
+
onInsertItem: onInsertItem,
|
|
245
|
+
selectedItemIndex: selectedItemIndex,
|
|
246
|
+
focusedItemIndex: focusedItemIndex,
|
|
247
|
+
setFocusedItemIndex: setFocusedItemIndex,
|
|
248
|
+
setColumnCount: setColumnCount,
|
|
249
|
+
createAnalyticsEvent: createAnalyticsEvent,
|
|
250
|
+
emptyStateHandler: emptyStateHandler,
|
|
251
|
+
selectedCategory: selectedCategory,
|
|
252
|
+
searchTerm: searchTerm
|
|
253
|
+
})));
|
|
254
|
+
}
|
|
255
|
+
var MemoizedElementBrowser = /*#__PURE__*/memo(withAnalyticsContext({
|
|
256
|
+
source: 'ElementBrowser'
|
|
257
|
+
})(withAnalyticsEvents()(StatelessElementBrowser)));
|
|
258
|
+
export default MemoizedElementBrowser;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// eslint-disable-next-line @atlaskit/design-system/no-deprecated-imports
|
|
2
|
+
import { gridSize } from '@atlaskit/theme/constants';
|
|
3
|
+
// TODO: Migrate away from gridSize
|
|
4
|
+
// Recommendation: Replace gridSize with 8
|
|
5
|
+
export var GRID_SIZE = gridSize();
|
|
6
|
+
export var DEVICE_BREAKPOINT_NUMBERS = {
|
|
7
|
+
small: GRID_SIZE * 40,
|
|
8
|
+
medium: GRID_SIZE * 75,
|
|
9
|
+
large: GRID_SIZE * 128
|
|
10
|
+
};
|
|
11
|
+
export var FLEX_ITEMS_CONTAINER_BREAKPOINT_NUMBERS = {
|
|
12
|
+
small: GRID_SIZE * 50,
|
|
13
|
+
medium: DEVICE_BREAKPOINT_NUMBERS.medium,
|
|
14
|
+
large: DEVICE_BREAKPOINT_NUMBERS.large
|
|
15
|
+
};
|
|
16
|
+
export var SIDEBAR_WIDTH = "".concat(GRID_SIZE * 25, "px");
|
|
17
|
+
export var SIDEBAR_HEADING_WRAPPER_HEIGHT = "".concat(GRID_SIZE * 6, "px");
|
|
18
|
+
export var SIDEBAR_HEADING_PADDING_LEFT = '12px';
|
|
19
|
+
export var INLINE_SIDEBAR_HEIGHT = '54px';
|
|
20
|
+
export var SEARCH_ITEM_HEIGHT_WIDTH = '20px';
|
|
21
|
+
export var SCROLLBAR_WIDTH = 15;
|
|
22
|
+
export var ELEMENT_LIST_PADDING = 2;
|
|
23
|
+
export var ELEMENT_ITEM_HEIGHT = 75;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
2
|
+
import _taggedTemplateLiteral from "@babel/runtime/helpers/taggedTemplateLiteral";
|
|
3
|
+
var _templateObject;
|
|
4
|
+
/** @jsx jsx */
|
|
5
|
+
import React, { memo, useEffect, useRef, useState } from 'react';
|
|
6
|
+
import { css, jsx } from '@emotion/react';
|
|
7
|
+
import { WidthObserver } from '@atlaskit/width-detector';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
*
|
|
11
|
+
* Problem:
|
|
12
|
+
* While using WidthObserver, there's no initial width.
|
|
13
|
+
* That may cause problems, but not limited to, something like a lag between
|
|
14
|
+
* renders for conditionally rendered components.
|
|
15
|
+
*
|
|
16
|
+
* solution:
|
|
17
|
+
* useContainerWidth() hook
|
|
18
|
+
* it pre-measures the width of a parent container on initial mount
|
|
19
|
+
* and gives you back the containerWidth.
|
|
20
|
+
*
|
|
21
|
+
*
|
|
22
|
+
* Example hook usage:
|
|
23
|
+
*
|
|
24
|
+
* const { containerWidth, ContainerWidthMonitor } = useContainerWidth();
|
|
25
|
+
*
|
|
26
|
+
* return (
|
|
27
|
+
* <>
|
|
28
|
+
* <ContainerWidthMonitor />
|
|
29
|
+
* {containerWidth < 600 ? <MobileComponent /> : <DesktopComponent />}
|
|
30
|
+
* </>
|
|
31
|
+
* );
|
|
32
|
+
*
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
var widthObserverWrapper = css(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n position: relative;\n"])));
|
|
36
|
+
export default function useContainerWidth() {
|
|
37
|
+
var _useState = useState(0),
|
|
38
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
39
|
+
containerWidth = _useState2[0],
|
|
40
|
+
setContainerWidth = _useState2[1];
|
|
41
|
+
var ref = useRef(null);
|
|
42
|
+
useEffect(function () {
|
|
43
|
+
var current = ref.current;
|
|
44
|
+
if (ref && current) {
|
|
45
|
+
setContainerWidth(current.getBoundingClientRect().width);
|
|
46
|
+
}
|
|
47
|
+
}, [ref]);
|
|
48
|
+
var ContainerWidthMonitor = /*#__PURE__*/memo(function () {
|
|
49
|
+
return jsx("div", {
|
|
50
|
+
css: widthObserverWrapper,
|
|
51
|
+
ref: ref,
|
|
52
|
+
tabIndex: -1
|
|
53
|
+
}, jsx(WidthObserver, {
|
|
54
|
+
setWidth: setContainerWidth
|
|
55
|
+
}));
|
|
56
|
+
});
|
|
57
|
+
return {
|
|
58
|
+
containerWidth: containerWidth,
|
|
59
|
+
ContainerWidthMonitor: ContainerWidthMonitor
|
|
60
|
+
};
|
|
61
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { useLayoutEffect, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A custom hook that handles focus on a DOM element.
|
|
5
|
+
* Takes in a boolean value and calls element.focus
|
|
6
|
+
*
|
|
7
|
+
* @param {boolean} focus
|
|
8
|
+
*
|
|
9
|
+
* Example usage:
|
|
10
|
+
*******************************************************************************
|
|
11
|
+
* const SearchBar = ({ focus }) => {
|
|
12
|
+
* const ref = useFocus(focus);
|
|
13
|
+
* return <input ref={ref} />
|
|
14
|
+
* }
|
|
15
|
+
*******************************************************************************
|
|
16
|
+
* const ItemList = ({ items, focus }) => (
|
|
17
|
+
* <ul>
|
|
18
|
+
* {items.map((item, index) => (
|
|
19
|
+
* <Item key={item.uuid} item={item} focus={focus} />
|
|
20
|
+
* ))}
|
|
21
|
+
* </ul>
|
|
22
|
+
* );
|
|
23
|
+
*
|
|
24
|
+
* const Item = ({ item, focus }) => {
|
|
25
|
+
* const ref = useFocus(focus);
|
|
26
|
+
* return (
|
|
27
|
+
* <li ref={ref}>
|
|
28
|
+
* {item.name}
|
|
29
|
+
* </li>
|
|
30
|
+
* )
|
|
31
|
+
* }
|
|
32
|
+
*******************************************************************************
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
export default function useFocus(focus) {
|
|
36
|
+
var ref = useRef(null);
|
|
37
|
+
useLayoutEffect(function () {
|
|
38
|
+
var current = ref.current;
|
|
39
|
+
if (focus && current && document.activeElement !== current) {
|
|
40
|
+
current.focus({
|
|
41
|
+
preventScroll: true
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}, [focus]);
|
|
45
|
+
return ref;
|
|
46
|
+
}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
2
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
3
|
+
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; }
|
|
4
|
+
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; }
|
|
5
|
+
import { useCallback, useEffect, useReducer, useRef } from 'react';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* a custom hook that handles keyboard navigation for Arrow keys based on a
|
|
9
|
+
* given listSize, and a step (for up and down arrows).
|
|
10
|
+
*
|
|
11
|
+
* @param {number} listSize
|
|
12
|
+
* @param {number} upDownStep
|
|
13
|
+
*
|
|
14
|
+
* Example usage:
|
|
15
|
+
* const list = ['Confluence','Jira','Atlaskit'];
|
|
16
|
+
* const {
|
|
17
|
+
* selectedItemIndex,
|
|
18
|
+
* focusedItemIndex,
|
|
19
|
+
* focusOnSearch,
|
|
20
|
+
* focusOnViewMore,
|
|
21
|
+
* setFocusedItemIndex,
|
|
22
|
+
* onKeyDown
|
|
23
|
+
* } = useSelectAndFocusOnArrowNavigation(list.length - 1, 1);
|
|
24
|
+
*
|
|
25
|
+
* return (
|
|
26
|
+
* <div onKeyDown={onKeyDown}>
|
|
27
|
+
* <SearchBar onClick={() => setFocusedItemIndex(undefined)} focus={focusOnSearch} />
|
|
28
|
+
* {list.map((item, index) => (
|
|
29
|
+
* <ListItem
|
|
30
|
+
* title={item}
|
|
31
|
+
* style={{ ..., color: selected ? 'selectedStateColor' : defaultColor }}
|
|
32
|
+
* onClick={() => {
|
|
33
|
+
* setFocusedItemIndex(index);
|
|
34
|
+
* }
|
|
35
|
+
* />
|
|
36
|
+
* )}
|
|
37
|
+
* </div>
|
|
38
|
+
* );
|
|
39
|
+
*
|
|
40
|
+
* const SearchBar = ({ focus }) => {
|
|
41
|
+
* const ref = useRefToFocusOrScroll(focus);
|
|
42
|
+
* return <input ref={ref} />
|
|
43
|
+
* }
|
|
44
|
+
*
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
export var ACTIONS = /*#__PURE__*/function (ACTIONS) {
|
|
48
|
+
ACTIONS["FOCUS_SEARCH"] = "focusOnSearch";
|
|
49
|
+
ACTIONS["UPDATE_STATE"] = "updateState";
|
|
50
|
+
ACTIONS["MOVE"] = "move";
|
|
51
|
+
return ACTIONS;
|
|
52
|
+
}({});
|
|
53
|
+
var reducer = function reducer(state, action) {
|
|
54
|
+
switch (action.type) {
|
|
55
|
+
case ACTIONS.UPDATE_STATE:
|
|
56
|
+
return _objectSpread(_objectSpread({}, state), action.payload);
|
|
57
|
+
case ACTIONS.FOCUS_SEARCH:
|
|
58
|
+
return _objectSpread(_objectSpread({}, 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
|
+
var moveReducer = function moveReducer(state, action) {
|
|
69
|
+
var listSize = state.listSize,
|
|
70
|
+
canFocusViewMore = state.canFocusViewMore;
|
|
71
|
+
if (state.focusOnSearch) {
|
|
72
|
+
// up arrow
|
|
73
|
+
if (action.payload.positions && action.payload.positions <= -1) {
|
|
74
|
+
return _objectSpread(_objectSpread({}, state), {}, {
|
|
75
|
+
focusOnSearch: false,
|
|
76
|
+
focusOnViewMore: !!canFocusViewMore,
|
|
77
|
+
focusedItemIndex: canFocusViewMore ? undefined : listSize,
|
|
78
|
+
selectedItemIndex: canFocusViewMore ? undefined : listSize
|
|
79
|
+
});
|
|
80
|
+
} else {
|
|
81
|
+
return _objectSpread(_objectSpread({}, state), {}, {
|
|
82
|
+
focusOnSearch: false,
|
|
83
|
+
focusOnViewMore: false,
|
|
84
|
+
focusedItemIndex: 0,
|
|
85
|
+
selectedItemIndex: 0
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (state.focusOnViewMore) {
|
|
90
|
+
// down arrow
|
|
91
|
+
if (action.payload.positions === 1) {
|
|
92
|
+
return _objectSpread(_objectSpread({}, state), {}, {
|
|
93
|
+
focusOnSearch: true,
|
|
94
|
+
focusOnViewMore: false,
|
|
95
|
+
focusedItemIndex: undefined,
|
|
96
|
+
// if search is focused then select first item.
|
|
97
|
+
selectedItemIndex: 0
|
|
98
|
+
});
|
|
99
|
+
} else {
|
|
100
|
+
return _objectSpread(_objectSpread({}, state), {}, {
|
|
101
|
+
focusOnSearch: false,
|
|
102
|
+
focusOnViewMore: false,
|
|
103
|
+
focusedItemIndex: listSize,
|
|
104
|
+
selectedItemIndex: listSize
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
var newIndex = state.selectedItemIndex ? state.selectedItemIndex + action.payload.positions : action.payload.positions;
|
|
109
|
+
var safeIndex = ensureSafeIndex(newIndex, state.listSize);
|
|
110
|
+
// down arrow key is pressed or right arrow key is pressed.
|
|
111
|
+
if (state.focusedItemIndex !== undefined && action.payload.positions && action.payload.positions >= 1) {
|
|
112
|
+
// when multi column element browser is open and we are in last
|
|
113
|
+
// row then newIndex will be greater than listSize when
|
|
114
|
+
// down arrow key is pressed.
|
|
115
|
+
// Or when last item is focused and down or right arrow key is pressed.
|
|
116
|
+
var isLastItemFocused = newIndex > listSize;
|
|
117
|
+
var focusOnSearch = isLastItemFocused && !canFocusViewMore;
|
|
118
|
+
var focusOnViewMore = isLastItemFocused && !!canFocusViewMore;
|
|
119
|
+
// if search is focused, then select first item.
|
|
120
|
+
// otherwise if view more is focused then select item should be undefined.
|
|
121
|
+
var selectedItemIndex = focusOnSearch ? 0 : focusOnViewMore ? undefined : safeIndex;
|
|
122
|
+
return _objectSpread(_objectSpread({}, state), {}, {
|
|
123
|
+
focusOnSearch: focusOnSearch,
|
|
124
|
+
focusOnViewMore: focusOnViewMore,
|
|
125
|
+
selectedItemIndex: selectedItemIndex,
|
|
126
|
+
focusedItemIndex: isLastItemFocused ? undefined : safeIndex
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// up arrow key is pressed or left arrow key is pressed.
|
|
131
|
+
if (state.focusedItemIndex !== undefined && action.payload.positions && action.payload.positions <= -1) {
|
|
132
|
+
// if arrow up key is pressed when focus is in first row,
|
|
133
|
+
// or, arrow left key is pressed when first item is focused,
|
|
134
|
+
// then newIndex will become less than zero.
|
|
135
|
+
// In this case, focus search, and, kept previously selected item.
|
|
136
|
+
var isFirstRowFocused = newIndex < 0;
|
|
137
|
+
// if focus goes to search then kept last selected item in first row.
|
|
138
|
+
var _selectedItemIndex = isFirstRowFocused ? state.selectedItemIndex : safeIndex;
|
|
139
|
+
return _objectSpread(_objectSpread({}, state), {}, {
|
|
140
|
+
// focus search if first item is focused on up or left arrow key
|
|
141
|
+
focusOnSearch: isFirstRowFocused,
|
|
142
|
+
focusOnViewMore: false,
|
|
143
|
+
focusedItemIndex: isFirstRowFocused ? undefined : safeIndex,
|
|
144
|
+
selectedItemIndex: _selectedItemIndex
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
return _objectSpread(_objectSpread({}, state), {}, {
|
|
148
|
+
focusOnSearch: false,
|
|
149
|
+
focusOnViewMore: false,
|
|
150
|
+
selectedItemIndex: safeIndex,
|
|
151
|
+
focusedItemIndex: safeIndex
|
|
152
|
+
});
|
|
153
|
+
};
|
|
154
|
+
var initialState = {
|
|
155
|
+
focusOnSearch: true,
|
|
156
|
+
focusOnViewMore: false,
|
|
157
|
+
selectedItemIndex: 0,
|
|
158
|
+
focusedItemIndex: undefined,
|
|
159
|
+
listSize: 0
|
|
160
|
+
};
|
|
161
|
+
var getInitialState = function getInitialState(listSize, canFocusViewMore) {
|
|
162
|
+
return function (initialState) {
|
|
163
|
+
return _objectSpread(_objectSpread({}, initialState), {}, {
|
|
164
|
+
listSize: listSize,
|
|
165
|
+
canFocusViewMore: canFocusViewMore
|
|
166
|
+
});
|
|
167
|
+
};
|
|
168
|
+
};
|
|
169
|
+
function useSelectAndFocusOnArrowNavigation(listSize, step, canFocusViewMore) {
|
|
170
|
+
var _useReducer = useReducer(reducer, initialState, getInitialState(listSize, canFocusViewMore)),
|
|
171
|
+
_useReducer2 = _slicedToArray(_useReducer, 2),
|
|
172
|
+
state = _useReducer2[0],
|
|
173
|
+
dispatch = _useReducer2[1];
|
|
174
|
+
useEffect(function () {
|
|
175
|
+
dispatch({
|
|
176
|
+
type: ACTIONS.UPDATE_STATE,
|
|
177
|
+
payload: {
|
|
178
|
+
canFocusViewMore: canFocusViewMore
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
}, [canFocusViewMore]);
|
|
182
|
+
var selectedItemIndex = state.selectedItemIndex,
|
|
183
|
+
focusedItemIndex = state.focusedItemIndex,
|
|
184
|
+
focusOnSearch = state.focusOnSearch,
|
|
185
|
+
focusOnViewMore = state.focusOnViewMore;
|
|
186
|
+
var reset = useCallback(function (listSize) {
|
|
187
|
+
var payload = _objectSpread(_objectSpread({}, initialState), {}, {
|
|
188
|
+
listSize: listSize
|
|
189
|
+
});
|
|
190
|
+
dispatch({
|
|
191
|
+
type: ACTIONS.UPDATE_STATE,
|
|
192
|
+
payload: payload
|
|
193
|
+
});
|
|
194
|
+
}, []);
|
|
195
|
+
var removeFocusFromSearchAndSetOnItem = useCallback(function (index) {
|
|
196
|
+
var payload = {
|
|
197
|
+
focusedItemIndex: index,
|
|
198
|
+
selectedItemIndex: index,
|
|
199
|
+
focusOnSearch: false,
|
|
200
|
+
focusOnViewMore: false
|
|
201
|
+
};
|
|
202
|
+
dispatch({
|
|
203
|
+
type: ACTIONS.UPDATE_STATE,
|
|
204
|
+
payload: payload
|
|
205
|
+
});
|
|
206
|
+
}, [dispatch]);
|
|
207
|
+
var setFocusOnSearch = useCallback(function () {
|
|
208
|
+
dispatch({
|
|
209
|
+
type: ACTIONS.FOCUS_SEARCH,
|
|
210
|
+
payload: {}
|
|
211
|
+
});
|
|
212
|
+
}, [dispatch]);
|
|
213
|
+
var isMoving = useRef(false);
|
|
214
|
+
var move = useCallback(function (e, positions, actualStep) {
|
|
215
|
+
e.preventDefault();
|
|
216
|
+
e.stopPropagation();
|
|
217
|
+
|
|
218
|
+
// avoid firing 2 moves at the same time when holding an arrow down as this can freeze the screen
|
|
219
|
+
if (!isMoving.current) {
|
|
220
|
+
isMoving.current = true;
|
|
221
|
+
requestAnimationFrame(function () {
|
|
222
|
+
isMoving.current = false;
|
|
223
|
+
dispatch({
|
|
224
|
+
type: ACTIONS.MOVE,
|
|
225
|
+
payload: {
|
|
226
|
+
positions: positions,
|
|
227
|
+
step: actualStep
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}, []);
|
|
233
|
+
var onKeyDown = useCallback(function (e) {
|
|
234
|
+
var avoidKeysWhileSearching = ['/',
|
|
235
|
+
// While already focused on search bar, let users type in.
|
|
236
|
+
'ArrowRight', 'ArrowLeft'];
|
|
237
|
+
if (focusOnSearch && avoidKeysWhileSearching.includes(e.key)) {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
switch (e.key) {
|
|
241
|
+
case '/':
|
|
242
|
+
e.preventDefault();
|
|
243
|
+
e.stopPropagation();
|
|
244
|
+
return setFocusOnSearch();
|
|
245
|
+
case 'ArrowRight':
|
|
246
|
+
return move(e, +1);
|
|
247
|
+
case 'ArrowLeft':
|
|
248
|
+
return move(e, -1);
|
|
249
|
+
case 'ArrowDown':
|
|
250
|
+
return move(e, +step);
|
|
251
|
+
case 'ArrowUp':
|
|
252
|
+
return move(e, -step, step);
|
|
253
|
+
}
|
|
254
|
+
}, [focusOnSearch, setFocusOnSearch, move, step]);
|
|
255
|
+
useEffect(function () {
|
|
256
|
+
// To reset selection when user filters
|
|
257
|
+
reset(listSize);
|
|
258
|
+
}, [listSize, reset]);
|
|
259
|
+
return {
|
|
260
|
+
selectedItemIndex: selectedItemIndex,
|
|
261
|
+
onKeyDown: onKeyDown,
|
|
262
|
+
focusOnSearch: focusOnSearch,
|
|
263
|
+
focusOnViewMore: focusOnViewMore,
|
|
264
|
+
setFocusOnSearch: setFocusOnSearch,
|
|
265
|
+
focusedItemIndex: focusedItemIndex,
|
|
266
|
+
setFocusedItemIndex: removeFocusFromSearchAndSetOnItem
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
export var ensureSafeIndex = function ensureSafeIndex(index, listSize) {
|
|
270
|
+
if (index < 0) {
|
|
271
|
+
return 0;
|
|
272
|
+
}
|
|
273
|
+
if (index > listSize) {
|
|
274
|
+
return listSize;
|
|
275
|
+
}
|
|
276
|
+
return index;
|
|
277
|
+
};
|
|
278
|
+
export default useSelectAndFocusOnArrowNavigation;
|