@atlaskit/editor-common 74.57.0 → 74.58.0

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.
Files changed (108) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/cjs/element-browser/ElementBrowser.js +152 -0
  3. package/dist/cjs/element-browser/ViewMore.js +39 -0
  4. package/dist/cjs/element-browser/components/CategoryList.js +115 -0
  5. package/dist/cjs/element-browser/components/ElementBrowserLoader.js +36 -0
  6. package/dist/cjs/element-browser/components/ElementList/ElementList.js +256 -0
  7. package/dist/cjs/element-browser/components/ElementList/EmptyState.js +47 -0
  8. package/dist/cjs/element-browser/components/ElementList/NotFoundIllustration.js +70 -0
  9. package/dist/cjs/element-browser/components/ElementList/cellSizeAndPositionGetter.js +42 -0
  10. package/dist/cjs/element-browser/components/ElementList/utils.js +54 -0
  11. package/dist/cjs/element-browser/components/ElementSearch.js +88 -0
  12. package/dist/cjs/element-browser/components/StatelessElementBrowser.js +269 -0
  13. package/dist/cjs/element-browser/constants.js +41 -0
  14. package/dist/cjs/element-browser/hooks/use-container-width.js +70 -0
  15. package/dist/cjs/element-browser/hooks/use-focus.js +51 -0
  16. package/dist/cjs/element-browser/hooks/use-select-and-focus-on-arrow-navigation.js +286 -0
  17. package/dist/cjs/element-browser/index.js +20 -0
  18. package/dist/cjs/element-browser/types.js +12 -0
  19. package/dist/cjs/monitoring/error.js +1 -1
  20. package/dist/cjs/ui/DropList/index.js +1 -1
  21. package/dist/cjs/utils/performance/measure-render.js +4 -3
  22. package/dist/cjs/utils/performance/measure-tti.js +9 -3
  23. package/dist/es2019/element-browser/ElementBrowser.js +117 -0
  24. package/dist/es2019/element-browser/ViewMore.js +40 -0
  25. package/dist/es2019/element-browser/components/CategoryList.js +106 -0
  26. package/dist/es2019/element-browser/components/ElementBrowserLoader.js +21 -0
  27. package/dist/es2019/element-browser/components/ElementList/ElementList.js +320 -0
  28. package/dist/es2019/element-browser/components/ElementList/EmptyState.js +58 -0
  29. package/dist/es2019/element-browser/components/ElementList/NotFoundIllustration.js +65 -0
  30. package/dist/es2019/element-browser/components/ElementList/cellSizeAndPositionGetter.js +39 -0
  31. package/dist/es2019/element-browser/components/ElementList/utils.js +50 -0
  32. package/dist/es2019/element-browser/components/ElementSearch.js +117 -0
  33. package/dist/es2019/element-browser/components/StatelessElementBrowser.js +339 -0
  34. package/dist/es2019/element-browser/constants.js +23 -0
  35. package/dist/es2019/element-browser/hooks/use-container-width.js +59 -0
  36. package/dist/es2019/element-browser/hooks/use-focus.js +48 -0
  37. package/dist/es2019/element-browser/hooks/use-select-and-focus-on-arrow-navigation.js +284 -0
  38. package/dist/es2019/element-browser/index.js +2 -0
  39. package/dist/es2019/element-browser/types.js +5 -0
  40. package/dist/es2019/monitoring/error.js +1 -1
  41. package/dist/es2019/ui/DropList/index.js +1 -1
  42. package/dist/es2019/utils/performance/measure-render.js +2 -3
  43. package/dist/es2019/utils/performance/measure-tti.js +9 -3
  44. package/dist/esm/element-browser/ElementBrowser.js +142 -0
  45. package/dist/esm/element-browser/ViewMore.js +31 -0
  46. package/dist/esm/element-browser/components/CategoryList.js +105 -0
  47. package/dist/esm/element-browser/components/ElementBrowserLoader.js +23 -0
  48. package/dist/esm/element-browser/components/ElementList/ElementList.js +241 -0
  49. package/dist/esm/element-browser/components/ElementList/EmptyState.js +40 -0
  50. package/dist/esm/element-browser/components/ElementList/NotFoundIllustration.js +63 -0
  51. package/dist/esm/element-browser/components/ElementList/cellSizeAndPositionGetter.js +37 -0
  52. package/dist/esm/element-browser/components/ElementList/utils.js +46 -0
  53. package/dist/esm/element-browser/components/ElementSearch.js +77 -0
  54. package/dist/esm/element-browser/components/StatelessElementBrowser.js +258 -0
  55. package/dist/esm/element-browser/constants.js +23 -0
  56. package/dist/esm/element-browser/hooks/use-container-width.js +61 -0
  57. package/dist/esm/element-browser/hooks/use-focus.js +46 -0
  58. package/dist/esm/element-browser/hooks/use-select-and-focus-on-arrow-navigation.js +278 -0
  59. package/dist/esm/element-browser/index.js +2 -0
  60. package/dist/esm/element-browser/types.js +5 -0
  61. package/dist/esm/monitoring/error.js +1 -1
  62. package/dist/esm/ui/DropList/index.js +1 -1
  63. package/dist/esm/utils/performance/measure-render.js +2 -3
  64. package/dist/esm/utils/performance/measure-tti.js +9 -3
  65. package/dist/types/analytics/types/general-events.d.ts +2 -1
  66. package/dist/types/element-browser/ElementBrowser.d.ts +37 -0
  67. package/dist/types/element-browser/ViewMore.d.ts +6 -0
  68. package/dist/types/element-browser/components/CategoryList.d.ts +10 -0
  69. package/dist/types/element-browser/components/ElementBrowserLoader.d.ts +6 -0
  70. package/dist/types/element-browser/components/ElementList/ElementList.d.ts +33 -0
  71. package/dist/types/element-browser/components/ElementList/EmptyState.d.ts +6 -0
  72. package/dist/types/element-browser/components/ElementList/NotFoundIllustration.d.ts +2 -0
  73. package/dist/types/element-browser/components/ElementList/cellSizeAndPositionGetter.d.ts +7 -0
  74. package/dist/types/element-browser/components/ElementList/utils.d.ts +12 -0
  75. package/dist/types/element-browser/components/ElementSearch.d.ts +18 -0
  76. package/dist/types/element-browser/components/StatelessElementBrowser.d.ts +23 -0
  77. package/dist/types/element-browser/constants.d.ts +19 -0
  78. package/dist/types/element-browser/hooks/use-container-width.d.ts +33 -0
  79. package/dist/types/element-browser/hooks/use-focus.d.ts +35 -0
  80. package/dist/types/element-browser/hooks/use-select-and-focus-on-arrow-navigation.d.ts +72 -0
  81. package/dist/types/element-browser/index.d.ts +2 -0
  82. package/dist/types/element-browser/types.d.ts +12 -0
  83. package/dist/types/types/quick-insert.d.ts +1 -0
  84. package/dist/types/utils/performance/measure-render.d.ts +6 -4
  85. package/dist/types/utils/performance/measure-tti.d.ts +1 -1
  86. package/dist/types-ts4.5/analytics/types/general-events.d.ts +2 -1
  87. package/dist/types-ts4.5/element-browser/ElementBrowser.d.ts +37 -0
  88. package/dist/types-ts4.5/element-browser/ViewMore.d.ts +6 -0
  89. package/dist/types-ts4.5/element-browser/components/CategoryList.d.ts +10 -0
  90. package/dist/types-ts4.5/element-browser/components/ElementBrowserLoader.d.ts +6 -0
  91. package/dist/types-ts4.5/element-browser/components/ElementList/ElementList.d.ts +33 -0
  92. package/dist/types-ts4.5/element-browser/components/ElementList/EmptyState.d.ts +6 -0
  93. package/dist/types-ts4.5/element-browser/components/ElementList/NotFoundIllustration.d.ts +2 -0
  94. package/dist/types-ts4.5/element-browser/components/ElementList/cellSizeAndPositionGetter.d.ts +7 -0
  95. package/dist/types-ts4.5/element-browser/components/ElementList/utils.d.ts +12 -0
  96. package/dist/types-ts4.5/element-browser/components/ElementSearch.d.ts +18 -0
  97. package/dist/types-ts4.5/element-browser/components/StatelessElementBrowser.d.ts +23 -0
  98. package/dist/types-ts4.5/element-browser/constants.d.ts +19 -0
  99. package/dist/types-ts4.5/element-browser/hooks/use-container-width.d.ts +33 -0
  100. package/dist/types-ts4.5/element-browser/hooks/use-focus.d.ts +35 -0
  101. package/dist/types-ts4.5/element-browser/hooks/use-select-and-focus-on-arrow-navigation.d.ts +72 -0
  102. package/dist/types-ts4.5/element-browser/index.d.ts +2 -0
  103. package/dist/types-ts4.5/element-browser/types.d.ts +12 -0
  104. package/dist/types-ts4.5/types/quick-insert.d.ts +1 -0
  105. package/dist/types-ts4.5/utils/performance/measure-render.d.ts +6 -4
  106. package/dist/types-ts4.5/utils/performance/measure-tti.d.ts +1 -1
  107. package/element-browser/package.json +15 -0
  108. package/package.json +6 -2
@@ -0,0 +1,50 @@
1
+ import { ELEMENT_LIST_PADDING, FLEX_ITEMS_CONTAINER_BREAKPOINT_NUMBERS, SCROLLBAR_WIDTH } from '../../constants';
2
+ export function getColumnCount(clientWidth) {
3
+ const {
4
+ small,
5
+ medium,
6
+ large
7
+ } = FLEX_ITEMS_CONTAINER_BREAKPOINT_NUMBERS;
8
+ switch (true) {
9
+ case clientWidth < small:
10
+ return 1;
11
+ case clientWidth >= small && clientWidth < medium:
12
+ return Math.floor(clientWidth / 200);
13
+ case clientWidth >= large:
14
+ return Math.floor(clientWidth / 248);
15
+ default:
16
+ return Math.floor(clientWidth / 220);
17
+ }
18
+ }
19
+ export function generateVirtualizedContainerDatum(containerWidth, options) {
20
+ const {
21
+ scrollbarWidth
22
+ } = options;
23
+ const columnCount = getColumnCount(containerWidth);
24
+ const availableWidth = containerWidth - (scrollbarWidth + ELEMENT_LIST_PADDING);
25
+ return {
26
+ availableWidth,
27
+ columnCount
28
+ };
29
+ }
30
+ let CALCULATED_SCROLLBAR_WIDTH;
31
+ export function getScrollbarWidth() {
32
+ if (!CALCULATED_SCROLLBAR_WIDTH) {
33
+ var _container$parentNode;
34
+ const container = document.createElement('div');
35
+ container.style.visibility = 'hidden';
36
+ container.style.overflow = 'scroll';
37
+ document.body.appendChild(container);
38
+ const innerContainer = document.createElement('div');
39
+ container.appendChild(innerContainer);
40
+ const scrollbarWidth = container.offsetWidth - innerContainer.offsetWidth;
41
+ (_container$parentNode = container.parentNode) === null || _container$parentNode === void 0 ? void 0 : _container$parentNode.removeChild(container);
42
+ if (scrollbarWidth) {
43
+ CALCULATED_SCROLLBAR_WIDTH = scrollbarWidth;
44
+ return scrollbarWidth;
45
+ }
46
+ return SCROLLBAR_WIDTH;
47
+ } else {
48
+ return CALCULATED_SCROLLBAR_WIDTH;
49
+ }
50
+ }
@@ -0,0 +1,117 @@
1
+ /** @jsx jsx */
2
+ import React, { memo } from 'react';
3
+ import { css, jsx } from '@emotion/react';
4
+ import { injectIntl } from 'react-intl-next';
5
+ import { withAnalyticsContext } from '@atlaskit/analytics-next';
6
+ import { relativeFontSizeToBase16 } from '@atlaskit/editor-shared-styles';
7
+ import { shortcutStyle } from '@atlaskit/editor-shared-styles/shortcut';
8
+ import SearchIcon from '@atlaskit/icon/glyph/search';
9
+ import Textfield from '@atlaskit/textfield';
10
+ import { N200 } from '@atlaskit/theme/colors';
11
+ import { GRID_SIZE, SEARCH_ITEM_HEIGHT_WIDTH } from '../constants';
12
+ import useFocus from '../hooks/use-focus';
13
+ import { Modes } from '../types';
14
+ function ElementSearch({
15
+ onSearch,
16
+ mode,
17
+ intl: {
18
+ formatMessage
19
+ },
20
+ focus,
21
+ onClick,
22
+ onKeyDown,
23
+ searchTerm
24
+ }) {
25
+ const ref = useFocus(focus);
26
+ const onChange = ({
27
+ target: {
28
+ value
29
+ }
30
+ }) => {
31
+ onSearch(value);
32
+ };
33
+ const onFocus = e => {};
34
+ const onBlur = e => {};
35
+ return jsx("div", {
36
+ css: [wrapper, mode === Modes.inline && wrapperInline]
37
+ }, jsx(Textfield, {
38
+ ref: ref,
39
+ onChange: onChange,
40
+ onClick: onClick,
41
+ onFocus: onFocus,
42
+ onKeyDown: onKeyDown,
43
+ onBlur: onBlur,
44
+ elemBeforeInput: jsx("div", {
45
+ css: elementBeforeInput,
46
+ "data-testid": "element_search__element_before_input"
47
+ }, jsx(SearchIcon, {
48
+ size: "medium",
49
+ label: "Advanced search",
50
+ primaryColor: "inherit"
51
+ })),
52
+ elemAfterInput: jsx("div", {
53
+ css: elementAfterInput,
54
+ "data-testid": "element_search__element_after_input"
55
+ }, jsx("div", {
56
+ css: styledShortcut
57
+ }, "\u23CE ", formatMessage(elementAfterInputMessage))),
58
+ placeholder: formatMessage(placeHolderMessage),
59
+ "aria-label": "search",
60
+ value: searchTerm
61
+ }));
62
+ }
63
+ const elementAfterInputMessage = {
64
+ id: 'fabric.editor.elementbrowser.searchbar.elementAfterInput',
65
+ defaultMessage: 'Enter',
66
+ description: 'Enter to insert'
67
+ };
68
+ const placeHolderMessage = {
69
+ id: 'fabric.editor.elementbrowser.searchbar.placeholder',
70
+ defaultMessage: 'Search',
71
+ description: 'Search field placeholder'
72
+ };
73
+ const styledShortcut = css`
74
+ ${shortcutStyle}
75
+ padding: ${GRID_SIZE / 2}px ${GRID_SIZE}px;
76
+ width: ${GRID_SIZE * 6}px;
77
+ `;
78
+ const wrapper = css`
79
+ & > [data-ds--text-field--container] {
80
+ height: ${GRID_SIZE * 6}px;
81
+ border-radius: ${GRID_SIZE}px;
82
+ flex: 1 1 100%;
83
+ overflow: visible;
84
+ & > [data-ds--text-field--input] {
85
+ margin-bottom: 3px;
86
+ font-size: ${relativeFontSizeToBase16(14)};
87
+ padding: ${GRID_SIZE}px ${"var(--ds-space-075, 6px)"} ${GRID_SIZE}px 0;
88
+ }
89
+ }
90
+ `;
91
+ const wrapperInline = css`
92
+ & > [data-ds--text-field--container] {
93
+ height: ${GRID_SIZE * 5}px;
94
+ flex: none;
95
+ overflow: revert;
96
+ }
97
+ `;
98
+ const elementBeforeInput = css`
99
+ margin: 1px ${"var(--ds-space-075, 6px)"} 0 ${"var(--ds-space-100, 8px)"};
100
+ color: ${`var(--ds-icon, ${N200})`};
101
+
102
+ // Custom SearchIcon style
103
+ span,
104
+ svg {
105
+ height: 20px;
106
+ width: 20px;
107
+ }
108
+ `;
109
+ const elementAfterInput = css`
110
+ margin: 0 ${"var(--ds-space-100, 8px)"};
111
+ height: ${SEARCH_ITEM_HEIGHT_WIDTH};
112
+ text-align: center;
113
+ `;
114
+ const MemoizedElementSearchWithAnalytics = /*#__PURE__*/memo(withAnalyticsContext({
115
+ component: 'Searchbar'
116
+ })(injectIntl(ElementSearch)));
117
+ export default MemoizedElementSearchWithAnalytics;
@@ -0,0 +1,339 @@
1
+ import _extends from "@babel/runtime/helpers/extends";
2
+ /** @jsx jsx */
3
+ import React, { memo, useCallback, useEffect, useState } from 'react';
4
+ import { css, jsx } from '@emotion/react';
5
+ import { FormattedMessage } from 'react-intl-next';
6
+ import { withAnalyticsContext, withAnalyticsEvents } from '@atlaskit/analytics-next';
7
+ import { ACTION, ACTION_SUBJECT, EVENT_TYPE, fireAnalyticsEvent } from '../../analytics';
8
+ import { DEVICE_BREAKPOINT_NUMBERS, GRID_SIZE, INLINE_SIDEBAR_HEIGHT, SIDEBAR_HEADING_PADDING_LEFT, SIDEBAR_HEADING_WRAPPER_HEIGHT, SIDEBAR_WIDTH } from '../constants';
9
+ import useContainerWidth from '../hooks/use-container-width';
10
+ import useSelectAndFocusOnArrowNavigation from '../hooks/use-select-and-focus-on-arrow-navigation';
11
+ import { ViewMore } from '../ViewMore';
12
+ import CategoryList from './CategoryList';
13
+ import ElementList from './ElementList/ElementList';
14
+ import ElementSearch from './ElementSearch';
15
+ const wrapper = css`
16
+ width: 100%;
17
+ max-height: inherit;
18
+ overflow: hidden;
19
+ `;
20
+ const baseBrowserContainerStyles = css`
21
+ display: flex;
22
+ height: 100%;
23
+ /** Needed for Safari to work with current css.
24
+ * 100% heights wont work and
25
+ * will default to auto if one of the containers doesn't have a specified height in pixels.
26
+ * Setting the min-height to fill available fits safari's needs and the above 100% height works on the rest of the browsers.
27
+ */
28
+
29
+ /* TODO: fix in develop: https://atlassian.slack.com/archives/CFG3PSQ9E/p1647395052443259?thread_ts=1647394572.556029&cid=CFG3PSQ9E */
30
+
31
+ /* stylelint-disable-next-line */
32
+ min-height: -webkit-fill-available;
33
+ `;
34
+ const mobileElementBrowserContainer = css`
35
+ ${baseBrowserContainerStyles};
36
+ flex-direction: column;
37
+ `;
38
+ const elementBrowserContainer = css`
39
+ ${baseBrowserContainerStyles};
40
+ flex-direction: row;
41
+ `;
42
+ const baseSidebarStyles = css`
43
+ display: flex;
44
+ flex-direction: column;
45
+
46
+ overflow-x: auto;
47
+ overflow-y: hidden;
48
+ `;
49
+ const mobileSideBar = css`
50
+ ${baseSidebarStyles};
51
+ flex: 0 0 ${INLINE_SIDEBAR_HEIGHT};
52
+ padding: ${"var(--ds-space-150, 12px)"} ${"var(--ds-space-150, 12px)"} 0
53
+ ${"var(--ds-space-150, 12px)"};
54
+ `;
55
+ const mobileSideBarShowCategories = css`
56
+ flex: 0 0 auto;
57
+ `;
58
+ const sideBar = css`
59
+ ${baseSidebarStyles};
60
+ flex: 0 0 'auto';
61
+ `;
62
+ const sideBarShowCategories = css`
63
+ ${baseSidebarStyles};
64
+ flex: 0 0 ${SIDEBAR_WIDTH};
65
+ `;
66
+ const sidebarHeading = css`
67
+ flex: 0 0 ${SIDEBAR_HEADING_WRAPPER_HEIGHT};
68
+ display: inline-flex;
69
+ align-items: center;
70
+ padding-left: ${SIDEBAR_HEADING_PADDING_LEFT};
71
+ font-weight: 700;
72
+ `;
73
+ const mobileMainContent = css`
74
+ flex: 1 1 auto;
75
+
76
+ display: flex;
77
+ flex-direction: column;
78
+
79
+ overflow-y: auto;
80
+ height: 100%;
81
+ `;
82
+ const mainContent = css`
83
+ ${mobileMainContent}
84
+ margin-left: ${GRID_SIZE * 2}px;
85
+ // Needed for safari
86
+ height: auto;
87
+ `;
88
+ const searchContainer = css`
89
+ padding-bottom: ${GRID_SIZE * 2}px;
90
+ `;
91
+ const mobileCategoryListWrapper = css`
92
+ display: flex;
93
+ overflow-x: auto;
94
+
95
+ padding: ${GRID_SIZE}px 0 ${GRID_SIZE * 2}px 0;
96
+ min-height: ${GRID_SIZE * 4}px;
97
+
98
+ overflow: -moz-scrollbars-none;
99
+ ::-webkit-scrollbar {
100
+ display: none;
101
+ }
102
+ scrollbar-width: none;
103
+ -ms-overflow-style: none;
104
+ `;
105
+ const categoryListWrapper = css`
106
+ ${mobileCategoryListWrapper}
107
+ padding: 0;
108
+ margin-top: ${GRID_SIZE * 3}px;
109
+ flex-direction: column;
110
+ `;
111
+ function StatelessElementBrowser(props) {
112
+ const {
113
+ items,
114
+ onSelectItem,
115
+ onInsertItem,
116
+ viewMoreItem
117
+ } = props;
118
+ const {
119
+ containerWidth,
120
+ ContainerWidthMonitor
121
+ } = useContainerWidth();
122
+ const [columnCount, setColumnCount] = useState(1);
123
+ const {
124
+ selectedItemIndex,
125
+ focusedItemIndex,
126
+ setFocusedItemIndex,
127
+ focusOnSearch,
128
+ focusOnViewMore,
129
+ onKeyDown,
130
+ setFocusOnSearch
131
+ } = useSelectAndFocusOnArrowNavigation(items.length - 1, columnCount, !!viewMoreItem);
132
+ useEffect(() => {
133
+ fireAnalyticsEvent(props.createAnalyticsEvent)({
134
+ payload: {
135
+ action: ACTION.OPENED,
136
+ actionSubject: ACTION_SUBJECT.ELEMENT_BROWSER,
137
+ eventType: EVENT_TYPE.UI,
138
+ attributes: {
139
+ mode: props.mode
140
+ }
141
+ }
142
+ });
143
+ return () => {
144
+ fireAnalyticsEvent(props.createAnalyticsEvent)({
145
+ payload: {
146
+ action: ACTION.CLOSED,
147
+ actionSubject: ACTION_SUBJECT.ELEMENT_BROWSER,
148
+ eventType: EVENT_TYPE.UI,
149
+ attributes: {
150
+ mode: props.mode
151
+ }
152
+ }
153
+ });
154
+ };
155
+ }, [props.createAnalyticsEvent, props.mode]);
156
+
157
+ /* Only for hitting enter to select item when focused on search bar,
158
+ * The actual enter key press is handled on individual items level.
159
+ */
160
+ const selectedItem = selectedItemIndex !== undefined ? items[selectedItemIndex] : null;
161
+ const onItemsEnterKeyPress = useCallback(e => {
162
+ if (e.key !== 'Enter') {
163
+ return;
164
+ }
165
+ if (onInsertItem && selectedItem != null) {
166
+ onInsertItem(selectedItem);
167
+ }
168
+ e.preventDefault();
169
+ }, [onInsertItem, selectedItem]);
170
+
171
+ /**
172
+ * On arrow key selection and clicks the selectedItemIndex will change.
173
+ * Making sure to update parent component.
174
+ */
175
+ useEffect(() => {
176
+ if (onSelectItem && selectedItem != null) {
177
+ onSelectItem(selectedItem);
178
+ }
179
+ }, [onSelectItem, selectedItem]);
180
+ return jsx("div", {
181
+ css: wrapper,
182
+ "data-testid": "element-browser"
183
+ }, jsx(ContainerWidthMonitor, null), containerWidth < DEVICE_BREAKPOINT_NUMBERS.medium ? jsx(MobileBrowser, _extends({}, props, {
184
+ selectedItemIndex: selectedItemIndex,
185
+ focusedItemIndex: focusedItemIndex,
186
+ setFocusedItemIndex: setFocusedItemIndex,
187
+ focusOnSearch: focusOnSearch,
188
+ setColumnCount: setColumnCount,
189
+ setFocusOnSearch: setFocusOnSearch,
190
+ onKeyPress: onItemsEnterKeyPress,
191
+ onKeyDown: onKeyDown,
192
+ viewMoreItem: viewMoreItem,
193
+ focusOnViewMore: focusOnViewMore
194
+ })) : jsx(DesktopBrowser, _extends({}, props, {
195
+ selectedItemIndex: selectedItemIndex,
196
+ focusedItemIndex: focusedItemIndex,
197
+ setFocusedItemIndex: setFocusedItemIndex,
198
+ focusOnSearch: focusOnSearch,
199
+ setColumnCount: setColumnCount,
200
+ setFocusOnSearch: setFocusOnSearch,
201
+ onKeyPress: onItemsEnterKeyPress,
202
+ onKeyDown: onKeyDown
203
+ })));
204
+ }
205
+ function MobileBrowser({
206
+ showCategories,
207
+ showSearch,
208
+ onSearch,
209
+ mode,
210
+ categories,
211
+ onSelectCategory,
212
+ items,
213
+ onInsertItem,
214
+ selectedCategory,
215
+ selectedItemIndex,
216
+ focusedItemIndex,
217
+ setFocusedItemIndex,
218
+ focusOnSearch,
219
+ focusOnViewMore,
220
+ setColumnCount,
221
+ setFocusOnSearch,
222
+ onKeyPress,
223
+ onKeyDown,
224
+ searchTerm,
225
+ createAnalyticsEvent,
226
+ emptyStateHandler,
227
+ viewMoreItem
228
+ }) {
229
+ return jsx("div", {
230
+ css: mobileElementBrowserContainer,
231
+ onKeyDown: onKeyDown,
232
+ "data-testid": "mobile__element-browser"
233
+ }, jsx("div", {
234
+ css: showCategories ? [mobileSideBar, mobileSideBarShowCategories] : mobileSideBar
235
+ }, showSearch && jsx(ElementSearch, {
236
+ onSearch: onSearch,
237
+ onKeyDown: onKeyPress,
238
+ mode: mode,
239
+ focus: focusOnSearch,
240
+ onClick: setFocusOnSearch,
241
+ searchTerm: searchTerm
242
+ }), showCategories && jsx("nav", {
243
+ css: mobileCategoryListWrapper,
244
+ tabIndex: -1
245
+ }, jsx(CategoryList, {
246
+ categories: categories,
247
+ onSelectCategory: onSelectCategory,
248
+ selectedCategory: selectedCategory
249
+ }))), jsx("div", {
250
+ css: mobileMainContent
251
+ }, jsx(ElementList, {
252
+ items: items,
253
+ mode: mode,
254
+ onInsertItem: onInsertItem,
255
+ selectedItemIndex: selectedItemIndex,
256
+ focusedItemIndex: focusedItemIndex,
257
+ setFocusedItemIndex: setFocusedItemIndex,
258
+ setColumnCount: setColumnCount,
259
+ createAnalyticsEvent: createAnalyticsEvent,
260
+ emptyStateHandler: emptyStateHandler,
261
+ selectedCategory: selectedCategory,
262
+ searchTerm: searchTerm
263
+ })), viewMoreItem && jsx(ViewMore, {
264
+ item: viewMoreItem,
265
+ focus: focusOnViewMore
266
+ }));
267
+ }
268
+ function DesktopBrowser({
269
+ showCategories,
270
+ showSearch,
271
+ onSearch,
272
+ mode,
273
+ categories,
274
+ onSelectCategory,
275
+ items,
276
+ onInsertItem,
277
+ selectedCategory,
278
+ selectedItemIndex,
279
+ focusedItemIndex,
280
+ setFocusedItemIndex,
281
+ focusOnSearch,
282
+ setColumnCount,
283
+ setFocusOnSearch,
284
+ onKeyPress,
285
+ onKeyDown,
286
+ searchTerm,
287
+ createAnalyticsEvent,
288
+ emptyStateHandler
289
+ }) {
290
+ return jsx("div", {
291
+ css: elementBrowserContainer,
292
+ "data-testid": "desktop__element-browser"
293
+ }, showCategories && jsx("div", {
294
+ css: showCategories ? sideBarShowCategories : sideBar
295
+ }, jsx("h2", {
296
+ css: sidebarHeading,
297
+ "data-testid": "sidebar-heading"
298
+ }, jsx(FormattedMessage, {
299
+ id: "fabric.editor.elementbrowser.sidebar.heading",
300
+ defaultMessage: "Browse",
301
+ description: "Sidebar heading"
302
+ })), jsx("nav", {
303
+ css: categoryListWrapper
304
+ }, jsx(CategoryList, {
305
+ categories: categories,
306
+ onSelectCategory: onSelectCategory,
307
+ selectedCategory: selectedCategory,
308
+ createAnalyticsEvent: createAnalyticsEvent
309
+ }))), jsx("div", {
310
+ css: mainContent,
311
+ onKeyDown: onKeyDown,
312
+ "data-testid": "main-content"
313
+ }, showSearch && jsx("div", {
314
+ css: searchContainer
315
+ }, jsx(ElementSearch, {
316
+ onSearch: onSearch,
317
+ onKeyDown: onKeyPress,
318
+ mode: mode,
319
+ focus: focusOnSearch,
320
+ onClick: setFocusOnSearch,
321
+ searchTerm: searchTerm
322
+ })), jsx(ElementList, {
323
+ items: items,
324
+ mode: mode,
325
+ onInsertItem: onInsertItem,
326
+ selectedItemIndex: selectedItemIndex,
327
+ focusedItemIndex: focusedItemIndex,
328
+ setFocusedItemIndex: setFocusedItemIndex,
329
+ setColumnCount: setColumnCount,
330
+ createAnalyticsEvent: createAnalyticsEvent,
331
+ emptyStateHandler: emptyStateHandler,
332
+ selectedCategory: selectedCategory,
333
+ searchTerm: searchTerm
334
+ })));
335
+ }
336
+ const MemoizedElementBrowser = /*#__PURE__*/memo(withAnalyticsContext({
337
+ source: 'ElementBrowser'
338
+ })(withAnalyticsEvents()(StatelessElementBrowser)));
339
+ 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 const GRID_SIZE = gridSize();
6
+ export const DEVICE_BREAKPOINT_NUMBERS = {
7
+ small: GRID_SIZE * 40,
8
+ medium: GRID_SIZE * 75,
9
+ large: GRID_SIZE * 128
10
+ };
11
+ export const 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 const SIDEBAR_WIDTH = `${GRID_SIZE * 25}px`;
17
+ export const SIDEBAR_HEADING_WRAPPER_HEIGHT = `${GRID_SIZE * 6}px`;
18
+ export const SIDEBAR_HEADING_PADDING_LEFT = '12px';
19
+ export const INLINE_SIDEBAR_HEIGHT = '54px';
20
+ export const SEARCH_ITEM_HEIGHT_WIDTH = '20px';
21
+ export const SCROLLBAR_WIDTH = 15;
22
+ export const ELEMENT_LIST_PADDING = 2;
23
+ export const ELEMENT_ITEM_HEIGHT = 75;
@@ -0,0 +1,59 @@
1
+ /** @jsx jsx */
2
+ import React, { memo, useEffect, useRef, useState } from 'react';
3
+ import { css, jsx } from '@emotion/react';
4
+ import { WidthObserver } from '@atlaskit/width-detector';
5
+
6
+ /**
7
+ *
8
+ * Problem:
9
+ * While using WidthObserver, there's no initial width.
10
+ * That may cause problems, but not limited to, something like a lag between
11
+ * renders for conditionally rendered components.
12
+ *
13
+ * solution:
14
+ * useContainerWidth() hook
15
+ * it pre-measures the width of a parent container on initial mount
16
+ * and gives you back the containerWidth.
17
+ *
18
+ *
19
+ * Example hook usage:
20
+ *
21
+ * const { containerWidth, ContainerWidthMonitor } = useContainerWidth();
22
+ *
23
+ * return (
24
+ * <>
25
+ * <ContainerWidthMonitor />
26
+ * {containerWidth < 600 ? <MobileComponent /> : <DesktopComponent />}
27
+ * </>
28
+ * );
29
+ *
30
+ */
31
+
32
+ const widthObserverWrapper = css`
33
+ position: relative;
34
+ `;
35
+ export default function useContainerWidth() {
36
+ const [containerWidth, setContainerWidth] = useState(0);
37
+ const ref = useRef(null);
38
+ useEffect(() => {
39
+ const {
40
+ current
41
+ } = ref;
42
+ if (ref && current) {
43
+ setContainerWidth(current.getBoundingClientRect().width);
44
+ }
45
+ }, [ref]);
46
+ const ContainerWidthMonitor = /*#__PURE__*/memo(() => {
47
+ return jsx("div", {
48
+ css: widthObserverWrapper,
49
+ ref: ref,
50
+ tabIndex: -1
51
+ }, jsx(WidthObserver, {
52
+ setWidth: setContainerWidth
53
+ }));
54
+ });
55
+ return {
56
+ containerWidth,
57
+ ContainerWidthMonitor
58
+ };
59
+ }
@@ -0,0 +1,48 @@
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
+ const ref = useRef(null);
37
+ useLayoutEffect(() => {
38
+ const {
39
+ current
40
+ } = ref;
41
+ if (focus && current && document.activeElement !== current) {
42
+ current.focus({
43
+ preventScroll: true
44
+ });
45
+ }
46
+ }, [focus]);
47
+ return ref;
48
+ }