@atlaskit/editor-plugin-type-ahead 0.5.0 → 0.7.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.
- package/.eslintrc.js +11 -0
- package/CHANGELOG.md +12 -0
- package/dist/cjs/api.js +215 -0
- package/dist/cjs/commands/insert-type-ahead-item.js +205 -0
- package/dist/cjs/commands/update-list-items.js +23 -0
- package/dist/cjs/commands/update-query.js +27 -0
- package/dist/cjs/commands/update-selected-index.js +27 -0
- package/dist/cjs/constants.js +15 -0
- package/dist/cjs/index.js +8 -1
- package/dist/cjs/insert-utils.js +107 -0
- package/dist/cjs/messages.js +79 -0
- package/dist/cjs/plugin.js +382 -0
- package/dist/cjs/pm-plugins/actions.js +16 -0
- package/dist/cjs/pm-plugins/decorations.js +148 -0
- package/dist/cjs/pm-plugins/input-rules.js +36 -0
- package/dist/cjs/pm-plugins/insert-item-plugin.js +22 -0
- package/dist/cjs/pm-plugins/key.js +8 -0
- package/dist/cjs/pm-plugins/main.js +110 -0
- package/dist/cjs/pm-plugins/reducer.js +158 -0
- package/dist/cjs/pm-plugins/utils.js +18 -0
- package/dist/cjs/stats-modifier.js +42 -0
- package/dist/cjs/transforms/close-type-ahead.js +13 -0
- package/dist/cjs/transforms/open-typeahead-at-cursor.js +75 -0
- package/dist/cjs/transforms/set-selection-before-query.js +18 -0
- package/dist/cjs/ui/AssistiveText.js +120 -0
- package/dist/cjs/ui/InputQuery.js +400 -0
- package/dist/cjs/ui/TypeAheadList.js +285 -0
- package/dist/cjs/ui/TypeAheadListItem.js +181 -0
- package/dist/cjs/ui/TypeAheadPopup.js +230 -0
- package/dist/cjs/ui/WrapperTypeAhead.js +127 -0
- package/dist/cjs/ui/hooks/use-item-insert.js +109 -0
- package/dist/cjs/ui/hooks/use-load-items.js +50 -0
- package/dist/cjs/ui/hooks/use-on-force-select.js +41 -0
- package/dist/cjs/utils.js +130 -0
- package/dist/es2019/api.js +205 -0
- package/dist/es2019/commands/insert-type-ahead-item.js +204 -0
- package/dist/es2019/commands/update-list-items.js +17 -0
- package/dist/es2019/commands/update-query.js +21 -0
- package/dist/es2019/commands/update-selected-index.js +21 -0
- package/dist/es2019/constants.js +9 -0
- package/dist/es2019/index.js +1 -1
- package/dist/es2019/insert-utils.js +106 -0
- package/dist/es2019/messages.js +73 -0
- package/dist/es2019/plugin.js +381 -0
- package/dist/es2019/pm-plugins/actions.js +10 -0
- package/dist/es2019/pm-plugins/decorations.js +148 -0
- package/dist/es2019/pm-plugins/input-rules.js +29 -0
- package/dist/es2019/pm-plugins/insert-item-plugin.js +16 -0
- package/dist/es2019/pm-plugins/key.js +2 -0
- package/dist/es2019/pm-plugins/main.js +106 -0
- package/dist/es2019/pm-plugins/reducer.js +160 -0
- package/dist/es2019/pm-plugins/utils.js +12 -0
- package/dist/es2019/stats-modifier.js +33 -0
- package/dist/es2019/transforms/close-type-ahead.js +7 -0
- package/dist/es2019/transforms/open-typeahead-at-cursor.js +71 -0
- package/dist/es2019/transforms/set-selection-before-query.js +10 -0
- package/dist/es2019/ui/AssistiveText.js +88 -0
- package/dist/es2019/ui/InputQuery.js +393 -0
- package/dist/es2019/ui/TypeAheadList.js +273 -0
- package/dist/es2019/ui/TypeAheadListItem.js +216 -0
- package/dist/es2019/ui/TypeAheadPopup.js +233 -0
- package/dist/es2019/ui/WrapperTypeAhead.js +109 -0
- package/dist/es2019/ui/hooks/use-item-insert.js +112 -0
- package/dist/es2019/ui/hooks/use-load-items.js +41 -0
- package/dist/es2019/ui/hooks/use-on-force-select.js +38 -0
- package/dist/es2019/utils.js +126 -0
- package/dist/esm/api.js +209 -0
- package/dist/esm/commands/insert-type-ahead-item.js +198 -0
- package/dist/esm/commands/update-list-items.js +17 -0
- package/dist/esm/commands/update-query.js +21 -0
- package/dist/esm/commands/update-selected-index.js +21 -0
- package/dist/esm/constants.js +9 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/insert-utils.js +101 -0
- package/dist/esm/messages.js +73 -0
- package/dist/esm/plugin.js +374 -0
- package/dist/esm/pm-plugins/actions.js +10 -0
- package/dist/esm/pm-plugins/decorations.js +141 -0
- package/dist/esm/pm-plugins/input-rules.js +29 -0
- package/dist/esm/pm-plugins/insert-item-plugin.js +16 -0
- package/dist/esm/pm-plugins/key.js +2 -0
- package/dist/esm/pm-plugins/main.js +104 -0
- package/dist/esm/pm-plugins/reducer.js +151 -0
- package/dist/esm/pm-plugins/utils.js +12 -0
- package/dist/esm/stats-modifier.js +35 -0
- package/dist/esm/transforms/close-type-ahead.js +7 -0
- package/dist/esm/transforms/open-typeahead-at-cursor.js +69 -0
- package/dist/esm/transforms/set-selection-before-query.js +12 -0
- package/dist/esm/ui/AssistiveText.js +115 -0
- package/dist/esm/ui/InputQuery.js +390 -0
- package/dist/esm/ui/TypeAheadList.js +276 -0
- package/dist/esm/ui/TypeAheadListItem.js +171 -0
- package/dist/esm/ui/TypeAheadPopup.js +220 -0
- package/dist/esm/ui/WrapperTypeAhead.js +117 -0
- package/dist/esm/ui/hooks/use-item-insert.js +103 -0
- package/dist/esm/ui/hooks/use-load-items.js +43 -0
- package/dist/esm/ui/hooks/use-on-force-select.js +35 -0
- package/dist/esm/utils.js +124 -0
- package/dist/types/api.d.ts +61 -0
- package/dist/types/commands/insert-type-ahead-item.d.ts +12 -0
- package/dist/types/commands/update-list-items.d.ts +3 -0
- package/dist/types/commands/update-query.d.ts +2 -0
- package/dist/types/commands/update-selected-index.d.ts +2 -0
- package/dist/types/constants.d.ts +8 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/insert-utils.d.ts +18 -0
- package/dist/types/messages.d.ts +72 -0
- package/dist/types/plugin.d.ts +10 -0
- package/dist/types/pm-plugins/actions.d.ts +9 -0
- package/dist/types/pm-plugins/decorations.d.ts +14 -0
- package/dist/types/pm-plugins/input-rules.d.ts +6 -0
- package/dist/types/pm-plugins/insert-item-plugin.d.ts +2 -0
- package/dist/types/pm-plugins/key.d.ts +3 -0
- package/dist/types/pm-plugins/main.d.ts +14 -0
- package/dist/types/pm-plugins/reducer.d.ts +10 -0
- package/dist/types/pm-plugins/utils.d.ts +4 -0
- package/dist/types/stats-modifier.d.ts +20 -0
- package/dist/types/transforms/close-type-ahead.d.ts +2 -0
- package/dist/types/transforms/open-typeahead-at-cursor.d.ts +11 -0
- package/dist/types/transforms/set-selection-before-query.d.ts +2 -0
- package/dist/types/types.d.ts +64 -3
- package/dist/types/ui/AssistiveText.d.ts +33 -0
- package/dist/types/ui/InputQuery.d.ts +26 -0
- package/dist/types/ui/TypeAheadList.d.ts +25 -0
- package/dist/types/ui/TypeAheadListItem.d.ts +18 -0
- package/dist/types/ui/TypeAheadPopup.d.ts +29 -0
- package/dist/types/ui/WrapperTypeAhead.d.ts +20 -0
- package/dist/types/ui/hooks/use-item-insert.d.ts +3 -0
- package/dist/types/ui/hooks/use-load-items.d.ts +3 -0
- package/dist/types/ui/hooks/use-on-force-select.d.ts +11 -0
- package/dist/types/utils.d.ts +27 -0
- package/dist/types-ts4.5/api.d.ts +61 -0
- package/dist/types-ts4.5/commands/insert-type-ahead-item.d.ts +12 -0
- package/dist/types-ts4.5/commands/update-list-items.d.ts +3 -0
- package/dist/types-ts4.5/commands/update-query.d.ts +2 -0
- package/dist/types-ts4.5/commands/update-selected-index.d.ts +2 -0
- package/dist/types-ts4.5/constants.d.ts +8 -0
- package/dist/types-ts4.5/index.d.ts +2 -1
- package/dist/types-ts4.5/insert-utils.d.ts +18 -0
- package/dist/types-ts4.5/messages.d.ts +72 -0
- package/dist/types-ts4.5/plugin.d.ts +10 -0
- package/dist/types-ts4.5/pm-plugins/actions.d.ts +9 -0
- package/dist/types-ts4.5/pm-plugins/decorations.d.ts +14 -0
- package/dist/types-ts4.5/pm-plugins/input-rules.d.ts +6 -0
- package/dist/types-ts4.5/pm-plugins/insert-item-plugin.d.ts +2 -0
- package/dist/types-ts4.5/pm-plugins/key.d.ts +3 -0
- package/dist/types-ts4.5/pm-plugins/main.d.ts +14 -0
- package/dist/types-ts4.5/pm-plugins/reducer.d.ts +10 -0
- package/dist/types-ts4.5/pm-plugins/utils.d.ts +4 -0
- package/dist/types-ts4.5/stats-modifier.d.ts +20 -0
- package/dist/types-ts4.5/transforms/close-type-ahead.d.ts +2 -0
- package/dist/types-ts4.5/transforms/open-typeahead-at-cursor.d.ts +11 -0
- package/dist/types-ts4.5/transforms/set-selection-before-query.d.ts +2 -0
- package/dist/types-ts4.5/types.d.ts +64 -3
- package/dist/types-ts4.5/ui/AssistiveText.d.ts +33 -0
- package/dist/types-ts4.5/ui/InputQuery.d.ts +26 -0
- package/dist/types-ts4.5/ui/TypeAheadList.d.ts +25 -0
- package/dist/types-ts4.5/ui/TypeAheadListItem.d.ts +18 -0
- package/dist/types-ts4.5/ui/TypeAheadPopup.d.ts +29 -0
- package/dist/types-ts4.5/ui/WrapperTypeAhead.d.ts +20 -0
- package/dist/types-ts4.5/ui/hooks/use-item-insert.d.ts +7 -0
- package/dist/types-ts4.5/ui/hooks/use-load-items.d.ts +3 -0
- package/dist/types-ts4.5/ui/hooks/use-on-force-select.d.ts +11 -0
- package/dist/types-ts4.5/utils.d.ts +27 -0
- package/package.json +21 -28
- package/report.api.md +32 -1
- package/tmp/api-report-tmp.d.ts +29 -0
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
/** @jsx jsx */
|
|
2
|
+
import React, { Fragment, useCallback, useLayoutEffect, useRef, useState } from 'react';
|
|
3
|
+
import { css, jsx } from '@emotion/react';
|
|
4
|
+
import { useIntl } from 'react-intl-next';
|
|
5
|
+
import { keyName as keyNameNormalized } from 'w3c-keyname';
|
|
6
|
+
import { SelectItemMode } from '@atlaskit/editor-common/type-ahead';
|
|
7
|
+
import { browser } from '@atlaskit/editor-common/utils';
|
|
8
|
+
import { blockNodesVerticalMargin } from '@atlaskit/editor-shared-styles';
|
|
9
|
+
import { CloseSelectionOptions, TYPE_AHEAD_POPUP_CONTENT_CLASS } from '../constants';
|
|
10
|
+
import { TYPE_AHEAD_DECORATION_ELEMENT_ID } from '../constants';
|
|
11
|
+
import { typeAheadListMessages } from '../messages';
|
|
12
|
+
import { getPluginState } from '../utils';
|
|
13
|
+
import { AssistiveText } from './AssistiveText';
|
|
14
|
+
const querySpanStyles = css({
|
|
15
|
+
outline: 'none',
|
|
16
|
+
'& input': {
|
|
17
|
+
width: '5px',
|
|
18
|
+
border: 'none',
|
|
19
|
+
background: 'transparent',
|
|
20
|
+
padding: 0,
|
|
21
|
+
margin: 0,
|
|
22
|
+
// ED-17022 Fixes firefox caret position
|
|
23
|
+
fontSize: '1em',
|
|
24
|
+
height: blockNodesVerticalMargin,
|
|
25
|
+
caretColor: "var(--ds-text-accent-blue, #0052CC)"
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
const isNavigationKey = event => {
|
|
29
|
+
return ['Enter', 'Tab', 'ArrowDown', 'ArrowUp'].includes(event.key);
|
|
30
|
+
};
|
|
31
|
+
const isUndoRedoShortcut = event => {
|
|
32
|
+
const key = keyNameNormalized(event);
|
|
33
|
+
if (event.ctrlKey && key === 'y') {
|
|
34
|
+
return 'historyRedo';
|
|
35
|
+
}
|
|
36
|
+
if ((event.ctrlKey || event.metaKey) && event.shiftKey && key === 'Z') {
|
|
37
|
+
return 'historyRedo';
|
|
38
|
+
}
|
|
39
|
+
if ((event.ctrlKey || event.metaKey) && key === 'z') {
|
|
40
|
+
return 'historyUndo';
|
|
41
|
+
}
|
|
42
|
+
return false;
|
|
43
|
+
};
|
|
44
|
+
const getAriaLabel = (triggerPrefix, intl) => {
|
|
45
|
+
switch (triggerPrefix) {
|
|
46
|
+
case '@':
|
|
47
|
+
return typeAheadListMessages.mentionInputLabel;
|
|
48
|
+
case '/':
|
|
49
|
+
return typeAheadListMessages.quickInsertInputLabel;
|
|
50
|
+
case ':':
|
|
51
|
+
return typeAheadListMessages.emojiInputLabel;
|
|
52
|
+
default:
|
|
53
|
+
return typeAheadListMessages.quickInsertInputLabel;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
export const InputQuery = /*#__PURE__*/React.memo(({
|
|
57
|
+
triggerQueryPrefix,
|
|
58
|
+
cancel,
|
|
59
|
+
onQueryChange,
|
|
60
|
+
onItemSelect,
|
|
61
|
+
selectNextItem,
|
|
62
|
+
selectPreviousItem,
|
|
63
|
+
forceFocus,
|
|
64
|
+
reopenQuery,
|
|
65
|
+
onQueryFocus,
|
|
66
|
+
onUndoRedo,
|
|
67
|
+
editorView,
|
|
68
|
+
items
|
|
69
|
+
}) => {
|
|
70
|
+
const ref = useRef(document.createElement('span'));
|
|
71
|
+
const inputRef = useRef(null);
|
|
72
|
+
const [query, setQuery] = useState(null);
|
|
73
|
+
const cleanedInputContent = useCallback(() => {
|
|
74
|
+
var _ref$current;
|
|
75
|
+
const raw = ((_ref$current = ref.current) === null || _ref$current === void 0 ? void 0 : _ref$current.textContent) || '';
|
|
76
|
+
return raw;
|
|
77
|
+
}, []);
|
|
78
|
+
const onKeyUp = useCallback(event => {
|
|
79
|
+
const text = cleanedInputContent();
|
|
80
|
+
onQueryChange(text);
|
|
81
|
+
}, [onQueryChange, cleanedInputContent]);
|
|
82
|
+
const [isInFocus, setInFocus] = useState(false);
|
|
83
|
+
const checkKeyEvent = useCallback(event => {
|
|
84
|
+
var _ref$current2;
|
|
85
|
+
const key = keyNameNormalized(event);
|
|
86
|
+
const sel = document.getSelection();
|
|
87
|
+
const raw = ((_ref$current2 = ref.current) === null || _ref$current2 === void 0 ? void 0 : _ref$current2.textContent) || '';
|
|
88
|
+
const text = cleanedInputContent();
|
|
89
|
+
let stopDefault = false;
|
|
90
|
+
const {
|
|
91
|
+
selectedIndex
|
|
92
|
+
} = getPluginState(editorView.state) || {};
|
|
93
|
+
setInFocus(true);
|
|
94
|
+
switch (key) {
|
|
95
|
+
case ' ':
|
|
96
|
+
// space key
|
|
97
|
+
if (text.length === 0) {
|
|
98
|
+
cancel({
|
|
99
|
+
forceFocusOnEditor: true,
|
|
100
|
+
text: ' ',
|
|
101
|
+
addPrefixTrigger: true,
|
|
102
|
+
setSelectionAt: CloseSelectionOptions.AFTER_TEXT_INSERTED
|
|
103
|
+
});
|
|
104
|
+
stopDefault = true;
|
|
105
|
+
}
|
|
106
|
+
break;
|
|
107
|
+
case 'Escape':
|
|
108
|
+
case 'PageUp':
|
|
109
|
+
case 'PageDown':
|
|
110
|
+
case 'Home':
|
|
111
|
+
cancel({
|
|
112
|
+
text,
|
|
113
|
+
forceFocusOnEditor: true,
|
|
114
|
+
addPrefixTrigger: true,
|
|
115
|
+
setSelectionAt: CloseSelectionOptions.AFTER_TEXT_INSERTED
|
|
116
|
+
});
|
|
117
|
+
stopDefault = true;
|
|
118
|
+
break;
|
|
119
|
+
case 'Backspace':
|
|
120
|
+
if (raw.length === 0 || (sel === null || sel === void 0 ? void 0 : sel.anchorOffset) === 0) {
|
|
121
|
+
event.stopPropagation();
|
|
122
|
+
event.preventDefault();
|
|
123
|
+
cancel({
|
|
124
|
+
forceFocusOnEditor: true,
|
|
125
|
+
text,
|
|
126
|
+
addPrefixTrigger: false,
|
|
127
|
+
setSelectionAt: CloseSelectionOptions.BEFORE_TEXT_INSERTED
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
break;
|
|
131
|
+
case 'Enter':
|
|
132
|
+
// ED-14758 - Under the W3C specification, any keycode sent under IME would return a keycode 229
|
|
133
|
+
// event.isComposing can't be used alone as this also included a virtual keyboard under a keyboardless device, therefore, it seems the best practice would be intercepting the event as below.
|
|
134
|
+
// Some suggested the other workaround maybe listen on`keypress` instead of `keydown`
|
|
135
|
+
if (!event.isComposing && event.which !== 229 && event.keyCode !== 229) {
|
|
136
|
+
if (selectedIndex === -1) {
|
|
137
|
+
/**
|
|
138
|
+
* TODO DTR-1401: (also see ED-17200) There are two options
|
|
139
|
+
* here, either
|
|
140
|
+
* - set the index directly to 1 in WrapperTypeAhead.tsx's
|
|
141
|
+
* `insertSelectedItem` at the cost of breaking some of the a11y
|
|
142
|
+
* focus changes,
|
|
143
|
+
* - or do this jank at the cost of some small analytics noise.
|
|
144
|
+
*
|
|
145
|
+
* The focus behaviour still needs cleanup
|
|
146
|
+
*/
|
|
147
|
+
selectPreviousItem();
|
|
148
|
+
selectNextItem();
|
|
149
|
+
}
|
|
150
|
+
onItemSelect(event.shiftKey ? SelectItemMode.SHIFT_ENTER : SelectItemMode.ENTER);
|
|
151
|
+
}
|
|
152
|
+
break;
|
|
153
|
+
case 'Tab':
|
|
154
|
+
if (selectedIndex === -1) {
|
|
155
|
+
/**
|
|
156
|
+
* TODO DTR-1401: (also see ED-17200) There are two options
|
|
157
|
+
* here, either
|
|
158
|
+
* - set the index directly to 1 in WrapperTypeAhead.tsx's
|
|
159
|
+
* `insertSelectedItem` at the cost of breaking some of the a11y
|
|
160
|
+
* focus changes,
|
|
161
|
+
* - or do this jank at the cost of some small analytics noise.
|
|
162
|
+
*
|
|
163
|
+
*/
|
|
164
|
+
selectPreviousItem();
|
|
165
|
+
selectNextItem();
|
|
166
|
+
}
|
|
167
|
+
// TODO DTR-1401: why is this calling select item when hitting tab? fix this in DTR-1401
|
|
168
|
+
onItemSelect(SelectItemMode.TAB);
|
|
169
|
+
break;
|
|
170
|
+
case 'ArrowDown':
|
|
171
|
+
selectNextItem();
|
|
172
|
+
break;
|
|
173
|
+
case 'ArrowUp':
|
|
174
|
+
selectPreviousItem();
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
const undoRedoType = isUndoRedoShortcut(event);
|
|
178
|
+
if (onUndoRedo && undoRedoType && onUndoRedo(undoRedoType)) {
|
|
179
|
+
stopDefault = true;
|
|
180
|
+
}
|
|
181
|
+
if (isNavigationKey(event) || stopDefault) {
|
|
182
|
+
event.stopPropagation();
|
|
183
|
+
event.preventDefault();
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
}, [onUndoRedo, onItemSelect, selectNextItem, selectPreviousItem, cancel, cleanedInputContent, editorView.state]);
|
|
187
|
+
const onClick = useCallback(event => {
|
|
188
|
+
var _inputRef$current;
|
|
189
|
+
event.stopPropagation();
|
|
190
|
+
event.preventDefault();
|
|
191
|
+
onQueryFocus();
|
|
192
|
+
(_inputRef$current = inputRef.current) === null || _inputRef$current === void 0 ? void 0 : _inputRef$current.focus();
|
|
193
|
+
return false;
|
|
194
|
+
}, [onQueryFocus]);
|
|
195
|
+
useLayoutEffect(() => {
|
|
196
|
+
if (!ref.current) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
const {
|
|
200
|
+
current: element
|
|
201
|
+
} = ref;
|
|
202
|
+
const onFocusIn = event => {
|
|
203
|
+
onQueryFocus();
|
|
204
|
+
};
|
|
205
|
+
const keyDown = event => {
|
|
206
|
+
const key = keyNameNormalized(event);
|
|
207
|
+
if (['ArrowLeft', 'ArrowRight'].includes(key) && document.getSelection && document.getSelection()) {
|
|
208
|
+
var _ref$current3;
|
|
209
|
+
const q = ((_ref$current3 = ref.current) === null || _ref$current3 === void 0 ? void 0 : _ref$current3.textContent) || '';
|
|
210
|
+
const sel = document.getSelection();
|
|
211
|
+
const isMovingRight = sel && 'ArrowRight' === key && sel.anchorOffset === q.length;
|
|
212
|
+
const isMovingLeft = sel && 'ArrowLeft' === key && (sel.anchorOffset === 0 || event.metaKey);
|
|
213
|
+
if (!isMovingRight && !isMovingLeft) {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
cancel({
|
|
217
|
+
forceFocusOnEditor: true,
|
|
218
|
+
addPrefixTrigger: true,
|
|
219
|
+
text: cleanedInputContent(),
|
|
220
|
+
setSelectionAt: isMovingRight ? CloseSelectionOptions.AFTER_TEXT_INSERTED : CloseSelectionOptions.BEFORE_TEXT_INSERTED
|
|
221
|
+
});
|
|
222
|
+
event.preventDefault();
|
|
223
|
+
event.stopPropagation();
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
checkKeyEvent(event);
|
|
227
|
+
};
|
|
228
|
+
const onFocusOut = event => {
|
|
229
|
+
var _window$getSelection;
|
|
230
|
+
const {
|
|
231
|
+
relatedTarget
|
|
232
|
+
} = event;
|
|
233
|
+
|
|
234
|
+
// Given the user is changing the focus
|
|
235
|
+
// When the target is inside the TypeAhead Popup
|
|
236
|
+
// Then the popup should stay open
|
|
237
|
+
if (relatedTarget instanceof HTMLElement && relatedTarget.closest && relatedTarget.closest(`.${TYPE_AHEAD_POPUP_CONTENT_CLASS}`)) {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// See ED-14909: Chrome may emit focusout events where an input
|
|
242
|
+
// device was not directly responsible. (This rears in react v17+ consumers
|
|
243
|
+
// where react-managed node removal now appears to propagate focusout events to
|
|
244
|
+
// our event listener). As this path is strictly for click or other typeahead
|
|
245
|
+
// dismissals that don't involve typeahead item selection, we carve out an
|
|
246
|
+
// exception for Chrome-specific events where an input device was not the initiator.
|
|
247
|
+
if (browser.chrome && !(((_window$getSelection = window.getSelection()) === null || _window$getSelection === void 0 ? void 0 : _window$getSelection.type) === 'Range') && !('sourceCapabilities' in event && event.sourceCapabilities)) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
cancel({
|
|
251
|
+
addPrefixTrigger: true,
|
|
252
|
+
text: cleanedInputContent(),
|
|
253
|
+
setSelectionAt: CloseSelectionOptions.BEFORE_TEXT_INSERTED,
|
|
254
|
+
forceFocusOnEditor: false
|
|
255
|
+
});
|
|
256
|
+
};
|
|
257
|
+
const close = () => {
|
|
258
|
+
cancel({
|
|
259
|
+
addPrefixTrigger: false,
|
|
260
|
+
text: '',
|
|
261
|
+
forceFocusOnEditor: true,
|
|
262
|
+
setSelectionAt: CloseSelectionOptions.BEFORE_TEXT_INSERTED
|
|
263
|
+
});
|
|
264
|
+
};
|
|
265
|
+
const beforeinput = e => {
|
|
266
|
+
var _target$textContent;
|
|
267
|
+
setInFocus(false);
|
|
268
|
+
const {
|
|
269
|
+
target
|
|
270
|
+
} = e;
|
|
271
|
+
if (e.isComposing || !(target instanceof HTMLElement)) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
if (e.inputType === 'historyUndo' && ((_target$textContent = target.textContent) === null || _target$textContent === void 0 ? void 0 : _target$textContent.length) === 0) {
|
|
275
|
+
e.preventDefault();
|
|
276
|
+
e.stopPropagation();
|
|
277
|
+
close();
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
if (e.data != null && inputRef.current === null) {
|
|
281
|
+
setQuery('');
|
|
282
|
+
|
|
283
|
+
// We need to change the content on Safari
|
|
284
|
+
// and set the cursor at the right place
|
|
285
|
+
if (browser.safari) {
|
|
286
|
+
e.preventDefault();
|
|
287
|
+
const dataElement = document.createTextNode(e.data);
|
|
288
|
+
element.appendChild(dataElement);
|
|
289
|
+
const sel = window.getSelection();
|
|
290
|
+
const range = document.createRange();
|
|
291
|
+
range.setStart(dataElement, dataElement.length);
|
|
292
|
+
range.collapse(true);
|
|
293
|
+
sel === null || sel === void 0 ? void 0 : sel.removeAllRanges();
|
|
294
|
+
sel === null || sel === void 0 ? void 0 : sel.addRange(range);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
let onInput = null;
|
|
299
|
+
if (browser.safari) {
|
|
300
|
+
// On Safari, for reasons beyond my understanding,
|
|
301
|
+
// The undo behavior is totally different from other browsers
|
|
302
|
+
// That why we need to have an specific branch only for Safari.
|
|
303
|
+
const onInput = e => {
|
|
304
|
+
var _target$textContent2;
|
|
305
|
+
const {
|
|
306
|
+
target
|
|
307
|
+
} = e;
|
|
308
|
+
if (e.isComposing || !(target instanceof HTMLElement)) {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
if (e.inputType === 'historyUndo' && ((_target$textContent2 = target.textContent) === null || _target$textContent2 === void 0 ? void 0 : _target$textContent2.length) === 1) {
|
|
312
|
+
e.preventDefault();
|
|
313
|
+
e.stopPropagation();
|
|
314
|
+
close();
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
element.addEventListener('input', onInput);
|
|
319
|
+
}
|
|
320
|
+
element.addEventListener('focusout', onFocusOut);
|
|
321
|
+
element.addEventListener('focusin', onFocusIn);
|
|
322
|
+
element.addEventListener('keydown', keyDown);
|
|
323
|
+
element.addEventListener('beforeinput', beforeinput);
|
|
324
|
+
return () => {
|
|
325
|
+
element.removeEventListener('focusout', onFocusOut);
|
|
326
|
+
element.removeEventListener('focusin', onFocusIn);
|
|
327
|
+
element.removeEventListener('keydown', keyDown);
|
|
328
|
+
element.removeEventListener('beforeinput', beforeinput);
|
|
329
|
+
if (browser.safari) {
|
|
330
|
+
element.removeEventListener('input', onInput);
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
}, [triggerQueryPrefix, cleanedInputContent, onQueryFocus, cancel, checkKeyEvent, editorView.state]);
|
|
334
|
+
useLayoutEffect(() => {
|
|
335
|
+
const hasReopenQuery = typeof reopenQuery === 'string' && reopenQuery.trim().length > 0;
|
|
336
|
+
if (ref.current && forceFocus) {
|
|
337
|
+
setQuery(hasReopenQuery ? reopenQuery : null);
|
|
338
|
+
requestAnimationFrame(() => {
|
|
339
|
+
if (!(ref !== null && ref !== void 0 && ref.current)) {
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
const sel = window.getSelection();
|
|
343
|
+
if (sel && hasReopenQuery && ref.current.lastChild instanceof Text) {
|
|
344
|
+
const lastChild = ref.current.lastChild;
|
|
345
|
+
const range = document.createRange();
|
|
346
|
+
range.setStart(ref.current.lastChild, lastChild.length);
|
|
347
|
+
range.collapse(true);
|
|
348
|
+
sel.removeAllRanges();
|
|
349
|
+
sel.addRange(range);
|
|
350
|
+
}
|
|
351
|
+
ref.current.focus();
|
|
352
|
+
setInFocus(true);
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
}, [forceFocus, reopenQuery]);
|
|
356
|
+
const assistiveHintID = TYPE_AHEAD_DECORATION_ELEMENT_ID + '__assistiveHint';
|
|
357
|
+
const intl = useIntl();
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
When we migrated to emotion from styled component, we started getting this error.
|
|
361
|
+
jsx-a11y/interactive-supports-focus
|
|
362
|
+
Task added in https://product-fabric.atlassian.net/wiki/spaces/E/pages/3182068181/Potential+improvements#Moderate-changes.
|
|
363
|
+
*/
|
|
364
|
+
return jsx(Fragment, null, triggerQueryPrefix, jsx("span", {
|
|
365
|
+
css: querySpanStyles,
|
|
366
|
+
contentEditable: true,
|
|
367
|
+
ref: ref,
|
|
368
|
+
onKeyUp: onKeyUp,
|
|
369
|
+
onClick: onClick,
|
|
370
|
+
role: "combobox",
|
|
371
|
+
"aria-controls": TYPE_AHEAD_DECORATION_ELEMENT_ID,
|
|
372
|
+
"aria-autocomplete": "list",
|
|
373
|
+
"aria-expanded": items.length !== 0,
|
|
374
|
+
"aria-labelledby": assistiveHintID,
|
|
375
|
+
suppressContentEditableWarning: true,
|
|
376
|
+
"data-query-prefix": triggerQueryPrefix
|
|
377
|
+
}, query === null ? jsx("input", {
|
|
378
|
+
ref: inputRef,
|
|
379
|
+
type: "text"
|
|
380
|
+
}) : query), jsx("span", {
|
|
381
|
+
id: assistiveHintID,
|
|
382
|
+
style: {
|
|
383
|
+
display: 'none'
|
|
384
|
+
}
|
|
385
|
+
}, intl.formatMessage(getAriaLabel(triggerQueryPrefix, intl)), ",", intl.formatMessage(typeAheadListMessages.inputQueryAssistiveLabel)), jsx(AssistiveText, {
|
|
386
|
+
assistiveText: items.length === 0 ? intl.formatMessage(typeAheadListMessages.noSearchResultsLabel, {
|
|
387
|
+
itemsLength: items.length
|
|
388
|
+
}) : '',
|
|
389
|
+
isInFocus: items.length === 0 || isInFocus,
|
|
390
|
+
id: TYPE_AHEAD_DECORATION_ELEMENT_ID
|
|
391
|
+
}));
|
|
392
|
+
});
|
|
393
|
+
InputQuery.displayName = 'InputQuery';
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/** @jsx jsx */
|
|
2
|
+
|
|
3
|
+
import React, { useCallback, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
4
|
+
import { css, jsx } from '@emotion/react';
|
|
5
|
+
import { injectIntl, useIntl } from 'react-intl-next';
|
|
6
|
+
import { CellMeasurer, CellMeasurerCache } from 'react-virtualized/dist/commonjs/CellMeasurer';
|
|
7
|
+
import { List } from 'react-virtualized/dist/commonjs/List';
|
|
8
|
+
import { SelectItemMode } from '@atlaskit/editor-common/type-ahead';
|
|
9
|
+
import { MenuGroup } from '@atlaskit/menu';
|
|
10
|
+
import { updateSelectedIndex } from '../commands/update-selected-index';
|
|
11
|
+
import { TYPE_AHEAD_DECORATION_ELEMENT_ID } from '../constants';
|
|
12
|
+
import { typeAheadListMessages } from '../messages';
|
|
13
|
+
import { getTypeAheadListAriaLabels, moveSelectedIndex } from '../utils';
|
|
14
|
+
import { AssistiveText } from './AssistiveText';
|
|
15
|
+
import { ICON_HEIGHT, ITEM_PADDING, TypeAheadListItem } from './TypeAheadListItem';
|
|
16
|
+
const LIST_ITEM_ESTIMATED_HEIGHT = ICON_HEIGHT + ITEM_PADDING * 2;
|
|
17
|
+
const LIST_WIDTH = 320;
|
|
18
|
+
const TypeaheadAssistiveTextPureComponent = /*#__PURE__*/React.memo(({
|
|
19
|
+
numberOfResults
|
|
20
|
+
}) => {
|
|
21
|
+
const intl = useIntl();
|
|
22
|
+
return jsx(AssistiveText, {
|
|
23
|
+
assistiveText: intl.formatMessage(typeAheadListMessages.searchResultsLabel, {
|
|
24
|
+
itemsLength: numberOfResults
|
|
25
|
+
})
|
|
26
|
+
// when the popup is open its always in focus
|
|
27
|
+
,
|
|
28
|
+
isInFocus: true,
|
|
29
|
+
id: TYPE_AHEAD_DECORATION_ELEMENT_ID + '__popup'
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
const TypeAheadListComponent = /*#__PURE__*/React.memo(({
|
|
33
|
+
items,
|
|
34
|
+
selectedIndex,
|
|
35
|
+
editorView,
|
|
36
|
+
onItemClick,
|
|
37
|
+
intl,
|
|
38
|
+
fitHeight,
|
|
39
|
+
decorationElement,
|
|
40
|
+
triggerHandler
|
|
41
|
+
}) => {
|
|
42
|
+
var _decorationElement$qu2;
|
|
43
|
+
const listRef = useRef();
|
|
44
|
+
const listContainerRef = useRef(null);
|
|
45
|
+
const lastVisibleIndexes = useRef({
|
|
46
|
+
overscanStartIndex: 0,
|
|
47
|
+
overscanStopIndex: 0,
|
|
48
|
+
startIndex: 0,
|
|
49
|
+
stopIndex: 0
|
|
50
|
+
});
|
|
51
|
+
const estimatedHeight = items.length * LIST_ITEM_ESTIMATED_HEIGHT;
|
|
52
|
+
const [height, setHeight] = useState(Math.min(estimatedHeight, fitHeight));
|
|
53
|
+
const [cache, setCache] = useState(new CellMeasurerCache({
|
|
54
|
+
fixedWidth: true,
|
|
55
|
+
defaultHeight: LIST_ITEM_ESTIMATED_HEIGHT
|
|
56
|
+
}));
|
|
57
|
+
const onItemsRendered = useCallback(props => {
|
|
58
|
+
lastVisibleIndexes.current = props;
|
|
59
|
+
}, []);
|
|
60
|
+
const actions = useMemo(() => ({
|
|
61
|
+
onItemClick
|
|
62
|
+
}), [onItemClick]);
|
|
63
|
+
const isNavigationKey = event => {
|
|
64
|
+
return ['ArrowDown', 'ArrowUp', 'Tab', 'Enter'].includes(event.key);
|
|
65
|
+
};
|
|
66
|
+
const focusTargetElement = useCallback(() => {
|
|
67
|
+
var _decorationElement$qu;
|
|
68
|
+
//To reset the selected index
|
|
69
|
+
updateSelectedIndex(-1)(editorView.state, editorView.dispatch);
|
|
70
|
+
listRef.current.scrollToRow(0);
|
|
71
|
+
decorationElement === null || decorationElement === void 0 ? void 0 : (_decorationElement$qu = decorationElement.querySelector(`[role='combobox']`)) === null || _decorationElement$qu === void 0 ? void 0 : _decorationElement$qu.focus();
|
|
72
|
+
}, [editorView, listRef, decorationElement]);
|
|
73
|
+
const selectNextItem = useMemo(() => moveSelectedIndex({
|
|
74
|
+
editorView,
|
|
75
|
+
direction: 'next'
|
|
76
|
+
}), [editorView]);
|
|
77
|
+
const selectPreviousItem = useMemo(() => moveSelectedIndex({
|
|
78
|
+
editorView,
|
|
79
|
+
direction: 'previous'
|
|
80
|
+
}), [editorView]);
|
|
81
|
+
const lastVisibleStartIndex = lastVisibleIndexes.current.startIndex;
|
|
82
|
+
const lastVisibleStopIndex = lastVisibleIndexes.current.stopIndex;
|
|
83
|
+
const onScroll = useCallback(({
|
|
84
|
+
scrollUpdateWasRequested
|
|
85
|
+
}) => {
|
|
86
|
+
if (!scrollUpdateWasRequested) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// In case the user scroll to a non-visible item like press ArrowUp from the first index
|
|
91
|
+
// We will force the scroll calling the scrollToItem in the useEffect hook
|
|
92
|
+
// When the scroll happens and we render the elements,
|
|
93
|
+
// we still need calculate the items height and re-draw the List.
|
|
94
|
+
// It is possible the item selected became invisible again (because the items height changed)
|
|
95
|
+
// So, we need to wait for height to be calculated. Then we need to check
|
|
96
|
+
// if the selected item is visible or not. If it isn't visible we call the scrollToItem again.
|
|
97
|
+
//
|
|
98
|
+
// We can't do this check in the first frame because that frame is being used by the resetScreenThrottled
|
|
99
|
+
// to calculate each height. THen, we can schedule a new frame when this one finishs.
|
|
100
|
+
requestAnimationFrame(() => {
|
|
101
|
+
requestAnimationFrame(() => {
|
|
102
|
+
const isSelectedItemVisible = selectedIndex >= lastVisibleStartIndex && selectedIndex <= lastVisibleStopIndex;
|
|
103
|
+
|
|
104
|
+
//Should scroll to the list item only when the selectedIndex >= 0 and item is not visible
|
|
105
|
+
if (!isSelectedItemVisible && selectedIndex !== -1) {
|
|
106
|
+
listRef.current.scrollToRow(selectedIndex);
|
|
107
|
+
} else if (selectedIndex === -1) {
|
|
108
|
+
listRef.current.scrollToRow(0);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
}, [selectedIndex, lastVisibleStartIndex, lastVisibleStopIndex]);
|
|
113
|
+
const onMouseMove = (event, index) => {
|
|
114
|
+
event.preventDefault();
|
|
115
|
+
event.stopPropagation();
|
|
116
|
+
if (selectedIndex === index) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
updateSelectedIndex(index)(editorView.state, editorView.dispatch);
|
|
120
|
+
};
|
|
121
|
+
useLayoutEffect(() => {
|
|
122
|
+
if (!listRef.current) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const isSelectedItemVisible = selectedIndex >= lastVisibleStartIndex && selectedIndex <= lastVisibleStopIndex;
|
|
126
|
+
|
|
127
|
+
//Should scroll to the list item only when the selectedIndex >= 0 and item is not visible
|
|
128
|
+
if (!isSelectedItemVisible && selectedIndex !== -1) {
|
|
129
|
+
listRef.current.scrollToRow(selectedIndex);
|
|
130
|
+
} else if (selectedIndex === -1) {
|
|
131
|
+
listRef.current.scrollToRow(0);
|
|
132
|
+
}
|
|
133
|
+
}, [selectedIndex, lastVisibleStartIndex, lastVisibleStopIndex]);
|
|
134
|
+
useLayoutEffect(() => {
|
|
135
|
+
setCache(new CellMeasurerCache({
|
|
136
|
+
fixedWidth: true,
|
|
137
|
+
defaultHeight: LIST_ITEM_ESTIMATED_HEIGHT
|
|
138
|
+
}));
|
|
139
|
+
// When query is updated, sometimes the scroll position of the menu is not at the top
|
|
140
|
+
// Scrolling back to top for consistency
|
|
141
|
+
requestAnimationFrame(() => {
|
|
142
|
+
var _listContainerRef$cur;
|
|
143
|
+
if ((_listContainerRef$cur = listContainerRef.current) !== null && _listContainerRef$cur !== void 0 && _listContainerRef$cur.firstChild) {
|
|
144
|
+
listContainerRef.current.firstChild.scrollTo(0, 0);
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
}, [items]);
|
|
148
|
+
useLayoutEffect(() => {
|
|
149
|
+
const height = Math.min(items.reduce((prevValue, currentValue, index) => {
|
|
150
|
+
return prevValue + cache.rowHeight({
|
|
151
|
+
index: index
|
|
152
|
+
});
|
|
153
|
+
}, 0), fitHeight);
|
|
154
|
+
setHeight(height);
|
|
155
|
+
}, [items, cache, fitHeight]);
|
|
156
|
+
useLayoutEffect(() => {
|
|
157
|
+
if (!listContainerRef.current) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
const {
|
|
161
|
+
current: element
|
|
162
|
+
} = listContainerRef;
|
|
163
|
+
/**
|
|
164
|
+
* To handle the key events on the list
|
|
165
|
+
* @param event
|
|
166
|
+
*/
|
|
167
|
+
const handleKeyDown = event => {
|
|
168
|
+
if (isNavigationKey(event)) {
|
|
169
|
+
switch (event.key) {
|
|
170
|
+
case 'ArrowDown':
|
|
171
|
+
selectNextItem();
|
|
172
|
+
event.preventDefault();
|
|
173
|
+
event.stopPropagation();
|
|
174
|
+
break;
|
|
175
|
+
case 'ArrowUp':
|
|
176
|
+
selectPreviousItem();
|
|
177
|
+
event.preventDefault();
|
|
178
|
+
event.stopPropagation();
|
|
179
|
+
break;
|
|
180
|
+
|
|
181
|
+
// TODO DTR-1401: why is this calling item click when hitting tab? fix this in DTR-1401
|
|
182
|
+
case 'Tab':
|
|
183
|
+
//Tab key quick inserts the selected item.
|
|
184
|
+
onItemClick(SelectItemMode.TAB, selectedIndex);
|
|
185
|
+
event.preventDefault();
|
|
186
|
+
break;
|
|
187
|
+
case 'Enter':
|
|
188
|
+
//Enter key quick inserts the selected item.
|
|
189
|
+
if (!event.isComposing || event.which !== 229 && event.keyCode !== 229) {
|
|
190
|
+
onItemClick(event.shiftKey ? SelectItemMode.SHIFT_ENTER : SelectItemMode.ENTER, selectedIndex);
|
|
191
|
+
event.preventDefault();
|
|
192
|
+
}
|
|
193
|
+
break;
|
|
194
|
+
default:
|
|
195
|
+
event.preventDefault();
|
|
196
|
+
}
|
|
197
|
+
} else {
|
|
198
|
+
//All the remaining keys sets focus on the typeahead query(inputQuery.tsx))
|
|
199
|
+
focusTargetElement();
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
element === null || element === void 0 ? void 0 : element.addEventListener('keydown', handleKeyDown);
|
|
203
|
+
return () => {
|
|
204
|
+
element === null || element === void 0 ? void 0 : element.removeEventListener('keydown', handleKeyDown);
|
|
205
|
+
};
|
|
206
|
+
}, [editorView.state, focusTargetElement, selectNextItem, selectPreviousItem, selectedIndex, onItemClick, items.length]);
|
|
207
|
+
const renderRow = ({
|
|
208
|
+
index,
|
|
209
|
+
key,
|
|
210
|
+
style,
|
|
211
|
+
parent
|
|
212
|
+
}) => {
|
|
213
|
+
const currentItem = items[index];
|
|
214
|
+
return jsx(CellMeasurer, {
|
|
215
|
+
key: key,
|
|
216
|
+
cache: cache,
|
|
217
|
+
parent: parent,
|
|
218
|
+
columnIndex: 0,
|
|
219
|
+
rowIndex: index
|
|
220
|
+
}, jsx("div", {
|
|
221
|
+
style: style,
|
|
222
|
+
"data-index": index
|
|
223
|
+
}, jsx("div", {
|
|
224
|
+
"data-testid": `list-item-height-observed-${index}`,
|
|
225
|
+
onMouseMove: e => onMouseMove(e, index)
|
|
226
|
+
}, jsx(TypeAheadListItem, {
|
|
227
|
+
key: items[index].title,
|
|
228
|
+
item: currentItem,
|
|
229
|
+
itemsLength: items.length,
|
|
230
|
+
itemIndex: index,
|
|
231
|
+
selectedIndex: selectedIndex,
|
|
232
|
+
onItemClick: actions.onItemClick,
|
|
233
|
+
ariaLabel: getTypeAheadListAriaLabels(triggerHandler === null || triggerHandler === void 0 ? void 0 : triggerHandler.trigger, intl, currentItem).listItemAriaLabel
|
|
234
|
+
}))));
|
|
235
|
+
};
|
|
236
|
+
const popupAriaLabel = getTypeAheadListAriaLabels(triggerHandler === null || triggerHandler === void 0 ? void 0 : triggerHandler.trigger, intl).popupAriaLabel;
|
|
237
|
+
if (!Array.isArray(items)) {
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
const menuGroupId = ((_decorationElement$qu2 = decorationElement.querySelector(`[role='combobox']`)) === null || _decorationElement$qu2 === void 0 ? void 0 : _decorationElement$qu2.getAttribute('aria-controls')) || TYPE_AHEAD_DECORATION_ELEMENT_ID;
|
|
241
|
+
return jsx(MenuGroup, {
|
|
242
|
+
"aria-label": popupAriaLabel,
|
|
243
|
+
"aria-relevant": "additions removals"
|
|
244
|
+
}, jsx("div", {
|
|
245
|
+
id: menuGroupId,
|
|
246
|
+
ref: listContainerRef
|
|
247
|
+
}, jsx(List, {
|
|
248
|
+
rowRenderer: renderRow,
|
|
249
|
+
ref: listRef,
|
|
250
|
+
rowCount: items.length,
|
|
251
|
+
rowHeight: cache.rowHeight,
|
|
252
|
+
onRowsRendered: onItemsRendered,
|
|
253
|
+
width: LIST_WIDTH,
|
|
254
|
+
onScroll: onScroll,
|
|
255
|
+
height: height,
|
|
256
|
+
overscanRowCount: 3,
|
|
257
|
+
containerRole: "presentation",
|
|
258
|
+
role: "listbox",
|
|
259
|
+
css: css`
|
|
260
|
+
button {
|
|
261
|
+
padding: ${"var(--ds-space-150, 12px)"}
|
|
262
|
+
${"var(--ds-space-150, 12px)"} 11px;
|
|
263
|
+
span:last-child span:last-child {
|
|
264
|
+
white-space: normal;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
`
|
|
268
|
+
}), jsx(TypeaheadAssistiveTextPureComponent, {
|
|
269
|
+
numberOfResults: items.length.toString()
|
|
270
|
+
})));
|
|
271
|
+
});
|
|
272
|
+
export const TypeAheadList = injectIntl(TypeAheadListComponent);
|
|
273
|
+
TypeAheadList.displayName = 'TypeAheadList';
|