@atlaskit/editor-plugin-type-ahead 2.1.0 → 2.1.2
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 +18 -0
- package/dist/cjs/ui/TypeAheadList.js +32 -14
- package/dist/cjs/ui/TypeAheadListItem.js +2 -2
- package/dist/cjs/ui/TypeAheadPopup.js +24 -17
- package/dist/cjs/ui/ViewMore.js +49 -7
- package/dist/cjs/ui/WrapperTypeAhead.js +5 -1
- package/dist/cjs/ui/hooks/use-load-items.js +5 -2
- package/dist/cjs/ui/modern/TypeAheadPopup.js +22 -13
- package/dist/es2019/ui/TypeAheadList.js +32 -14
- package/dist/es2019/ui/TypeAheadListItem.js +2 -2
- package/dist/es2019/ui/TypeAheadPopup.js +24 -17
- package/dist/es2019/ui/ViewMore.js +45 -1
- package/dist/es2019/ui/WrapperTypeAhead.js +6 -2
- package/dist/es2019/ui/hooks/use-load-items.js +5 -2
- package/dist/es2019/ui/modern/TypeAheadPopup.js +22 -13
- package/dist/esm/ui/TypeAheadList.js +32 -14
- package/dist/esm/ui/TypeAheadListItem.js +2 -2
- package/dist/esm/ui/TypeAheadPopup.js +24 -17
- package/dist/esm/ui/ViewMore.js +43 -1
- package/dist/esm/ui/WrapperTypeAhead.js +6 -2
- package/dist/esm/ui/hooks/use-load-items.js +5 -2
- package/dist/esm/ui/modern/TypeAheadPopup.js +22 -13
- package/dist/types/ui/TypeAheadList.d.ts +2 -0
- package/dist/types/ui/ViewMore.d.ts +3 -6
- package/dist/types/ui/hooks/use-load-items.d.ts +1 -1
- package/dist/types-ts4.5/ui/TypeAheadList.d.ts +2 -0
- package/dist/types-ts4.5/ui/ViewMore.d.ts +3 -6
- package/dist/types-ts4.5/ui/hooks/use-load-items.d.ts +1 -1
- package/package.json +3 -3
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* @jsxRuntime classic
|
|
3
3
|
* @jsx jsx
|
|
4
4
|
*/
|
|
5
|
+
import { useEffect, useRef } from 'react';
|
|
6
|
+
|
|
5
7
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
|
|
6
8
|
import { css, jsx } from '@emotion/react';
|
|
7
9
|
import { useIntl } from 'react-intl-next';
|
|
@@ -13,19 +15,61 @@ const buttonStyles = css({
|
|
|
13
15
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors -- Ignored via go/DSP-18766
|
|
14
16
|
'& > button:hover': {
|
|
15
17
|
backgroundColor: `var(--ds-background-neutral-subtle-hovered, ${N30})`
|
|
18
|
+
},
|
|
19
|
+
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors -- Ignored via go/DSP-18766
|
|
20
|
+
'& > button:focus': {
|
|
21
|
+
backgroundColor: `var(--ds-background-neutral-subtle-hovered, ${N30})`,
|
|
22
|
+
outline: 'none'
|
|
16
23
|
}
|
|
17
24
|
});
|
|
18
25
|
export const ViewMore = ({
|
|
19
|
-
onClick
|
|
26
|
+
onClick,
|
|
27
|
+
isFocused
|
|
20
28
|
}) => {
|
|
21
29
|
const {
|
|
22
30
|
formatMessage
|
|
23
31
|
} = useIntl();
|
|
32
|
+
const ref = useRef(null);
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
if (isFocused && ref.current) {
|
|
35
|
+
ref.current.focus();
|
|
36
|
+
}
|
|
37
|
+
}, [isFocused]);
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
if (!ref.current) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const {
|
|
43
|
+
current: element
|
|
44
|
+
} = ref;
|
|
45
|
+
const handleEnter = e => {
|
|
46
|
+
if (e.key === 'Enter') {
|
|
47
|
+
onClick();
|
|
48
|
+
// Prevent keydown listener in TypeaheadList from handling Enter pressed
|
|
49
|
+
e.stopPropagation();
|
|
50
|
+
} else if (e.key === 'Tab') {
|
|
51
|
+
// TypeaheadList will try to insert selected item on Tab press
|
|
52
|
+
// hence stop propagation to prevent that and treat this as noop
|
|
53
|
+
e.stopPropagation();
|
|
54
|
+
e.preventDefault();
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// Ignored via go/ees005
|
|
59
|
+
// eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
|
|
60
|
+
element === null || element === void 0 ? void 0 : element.addEventListener('keydown', handleEnter);
|
|
61
|
+
return () => {
|
|
62
|
+
// Ignored via go/ees005
|
|
63
|
+
// eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
|
|
64
|
+
element === null || element === void 0 ? void 0 : element.removeEventListener('keydown', handleEnter);
|
|
65
|
+
};
|
|
66
|
+
});
|
|
24
67
|
return jsx(Section, {
|
|
25
68
|
hasSeparator: true
|
|
26
69
|
}, jsx("span", {
|
|
27
70
|
css: buttonStyles
|
|
28
71
|
}, jsx(ButtonItem, {
|
|
72
|
+
ref: ref,
|
|
29
73
|
onClick: onClick,
|
|
30
74
|
iconBefore: jsx(ShowMoreHorizontalIcon, {
|
|
31
75
|
label: ""
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
-
import { SelectItemMode } from '@atlaskit/editor-common/type-ahead';
|
|
2
|
+
import { SelectItemMode, TypeAheadAvailableNodes } from '@atlaskit/editor-common/type-ahead';
|
|
3
|
+
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
|
|
3
4
|
import { updateQuery } from '../pm-plugins/commands/update-query';
|
|
4
5
|
import { itemIsDisabled } from '../pm-plugins/item-is-disabled';
|
|
5
6
|
import { getPluginState, moveSelectedIndex, skipForwardToSafeItem } from '../pm-plugins/utils';
|
|
@@ -21,11 +22,14 @@ export const WrapperTypeAhead = /*#__PURE__*/React.memo(({
|
|
|
21
22
|
onUndoRedo,
|
|
22
23
|
api
|
|
23
24
|
}) => {
|
|
25
|
+
// @ts-ignore
|
|
26
|
+
const openElementBrowserModal = triggerHandler === null || triggerHandler === void 0 ? void 0 : triggerHandler.openElementBrowserModal;
|
|
27
|
+
const showViewMore = (triggerHandler === null || triggerHandler === void 0 ? void 0 : triggerHandler.id) === TypeAheadAvailableNodes.QUICK_INSERT && !!openElementBrowserModal && editorExperiment('platform_editor_controls', 'variant1');
|
|
24
28
|
const [closed, setClosed] = useState(false);
|
|
25
29
|
const [query, setQuery] = useState(reopenQuery || '');
|
|
26
30
|
const queryRef = useRef(query);
|
|
27
31
|
const editorViewRef = useRef(editorView);
|
|
28
|
-
const items = useLoadItems(triggerHandler, editorView, query);
|
|
32
|
+
const items = useLoadItems(triggerHandler, editorView, query, showViewMore);
|
|
29
33
|
useLayoutEffect(() => {
|
|
30
34
|
queryRef.current = query;
|
|
31
35
|
}, [query]);
|
|
@@ -3,7 +3,7 @@ import { fg } from '@atlaskit/platform-feature-flags';
|
|
|
3
3
|
import { updateListError } from '../../pm-plugins/commands/update-list-error';
|
|
4
4
|
import { updateListItem } from '../../pm-plugins/commands/update-list-items';
|
|
5
5
|
const EMPTY_LIST_ITEM = [];
|
|
6
|
-
export const useLoadItems = (triggerHandler, editorView, query) => {
|
|
6
|
+
export const useLoadItems = (triggerHandler, editorView, query, showViewMore) => {
|
|
7
7
|
const [items, setItems] = useState(EMPTY_LIST_ITEM);
|
|
8
8
|
const componentIsMounted = useRef(true);
|
|
9
9
|
const editorViewRef = useRef(editorView);
|
|
@@ -25,8 +25,11 @@ export const useLoadItems = (triggerHandler, editorView, query) => {
|
|
|
25
25
|
if (componentIsMounted.current) {
|
|
26
26
|
setItems(list);
|
|
27
27
|
}
|
|
28
|
+
const viewMoreItem = {
|
|
29
|
+
title: 'View more'
|
|
30
|
+
};
|
|
28
31
|
queueMicrotask(() => {
|
|
29
|
-
updateListItem(list)(view.state, view.dispatch);
|
|
32
|
+
updateListItem(showViewMore ? list.concat(viewMoreItem) : list)(view.state, view.dispatch);
|
|
30
33
|
});
|
|
31
34
|
}).catch(e => {
|
|
32
35
|
if (fg('platform_editor_offline_editing_ga')) {
|
|
@@ -199,22 +199,31 @@ export const TypeAheadPopup = /*#__PURE__*/React.memo(props => {
|
|
|
199
199
|
var _window$getSelection2;
|
|
200
200
|
// Check if new focus point is inside the current editor. If it is not we
|
|
201
201
|
// want to close the typeahead popup regardless of text selection state
|
|
202
|
-
const
|
|
202
|
+
const currentFocus = (_window$getSelection2 = window.getSelection()) === null || _window$getSelection2 === void 0 ? void 0 : _window$getSelection2.focusNode; // the focusNode is either TextNode, ElementNode
|
|
203
|
+
// if currentFocus is not HTMLElement, take its parent node as focusNode
|
|
204
|
+
const focusNode = currentFocus instanceof HTMLElement ? currentFocus : currentFocus === null || currentFocus === void 0 ? void 0 : currentFocus.parentNode;
|
|
203
205
|
if (focusNode instanceof HTMLElement) {
|
|
204
206
|
const innerEditor = focusNode.closest('.extension-editable-area');
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
if (
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
207
|
+
if (innerEditor) {
|
|
208
|
+
// When there is no related target, we default to not closing the popup
|
|
209
|
+
let newFocusInsideCurrentEditor = !relatedTarget;
|
|
210
|
+
if (relatedTarget instanceof HTMLElement) {
|
|
211
|
+
if (innerEditor) {
|
|
212
|
+
// check if the new focus is inside inner editor, keep popup opens
|
|
213
|
+
newFocusInsideCurrentEditor = innerEditor.contains(relatedTarget);
|
|
214
|
+
} else {
|
|
215
|
+
// if the new focus contains current focus node, the popup won't close
|
|
216
|
+
newFocusInsideCurrentEditor = relatedTarget.contains(focusNode);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (!isTextSelected && newFocusInsideCurrentEditor) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
} else {
|
|
223
|
+
// if the current focus in outer editor, keep the existing behaviour, do not close the pop up if text is not selected
|
|
224
|
+
if (!isTextSelected) {
|
|
225
|
+
return;
|
|
214
226
|
}
|
|
215
|
-
}
|
|
216
|
-
if (!isTextSelected && newFocusInsideCurrentEditor) {
|
|
217
|
-
return;
|
|
218
227
|
}
|
|
219
228
|
}
|
|
220
229
|
} else {
|
|
@@ -20,6 +20,7 @@ import { TYPE_AHEAD_DECORATION_ELEMENT_ID } from '../pm-plugins/constants';
|
|
|
20
20
|
import { getTypeAheadListAriaLabels, moveSelectedIndex } from '../pm-plugins/utils';
|
|
21
21
|
import { AssistiveText } from './AssistiveText';
|
|
22
22
|
import { TypeAheadListItem } from './TypeAheadListItem';
|
|
23
|
+
import { ViewMore } from './ViewMore';
|
|
23
24
|
var LIST_ITEM_ESTIMATED_HEIGHT = 64;
|
|
24
25
|
var LIST_WIDTH = 320;
|
|
25
26
|
var list = css({
|
|
@@ -53,7 +54,8 @@ var TypeAheadListComponent = /*#__PURE__*/React.memo(function (_ref2) {
|
|
|
53
54
|
triggerHandler = _ref2.triggerHandler,
|
|
54
55
|
moreElementsInQuickInsertViewEnabled = _ref2.moreElementsInQuickInsertViewEnabled,
|
|
55
56
|
api = _ref2.api,
|
|
56
|
-
showViewMore = _ref2.showViewMore
|
|
57
|
+
showViewMore = _ref2.showViewMore,
|
|
58
|
+
onViewMoreClick = _ref2.onViewMoreClick;
|
|
57
59
|
var listRef = useRef();
|
|
58
60
|
var listContainerRef = useRef(null);
|
|
59
61
|
var lastVisibleIndexes = useRef({
|
|
@@ -62,7 +64,10 @@ var TypeAheadListComponent = /*#__PURE__*/React.memo(function (_ref2) {
|
|
|
62
64
|
startIndex: 0,
|
|
63
65
|
stopIndex: 0
|
|
64
66
|
});
|
|
65
|
-
|
|
67
|
+
|
|
68
|
+
// Exclude view more item from the count
|
|
69
|
+
var itemsLength = showViewMore ? items.length - 1 : items.length;
|
|
70
|
+
var estimatedHeight = itemsLength * LIST_ITEM_ESTIMATED_HEIGHT;
|
|
66
71
|
var _useState = useState(Math.min(estimatedHeight, fitHeight)),
|
|
67
72
|
_useState2 = _slicedToArray(_useState, 2),
|
|
68
73
|
height = _useState2[0],
|
|
@@ -128,7 +133,10 @@ var TypeAheadListComponent = /*#__PURE__*/React.memo(function (_ref2) {
|
|
|
128
133
|
// to calculate each height. THen, we can schedule a new frame when this one finishs.
|
|
129
134
|
requestAnimationFrame(function () {
|
|
130
135
|
requestAnimationFrame(function () {
|
|
131
|
-
var
|
|
136
|
+
var isViewMoreSelected = showViewMore && selectedIndex === itemsLength;
|
|
137
|
+
var isSelectedItemVisible = selectedIndex >= lastVisibleStartIndex && selectedIndex <= lastVisibleStopIndex ||
|
|
138
|
+
// view more is always visible, hence no scrolling
|
|
139
|
+
isViewMoreSelected;
|
|
132
140
|
|
|
133
141
|
//Should scroll to the list item only when the selectedIndex >= 0 and item is not visible
|
|
134
142
|
if (!isSelectedItemVisible && selectedIndex !== -1) {
|
|
@@ -138,7 +146,7 @@ var TypeAheadListComponent = /*#__PURE__*/React.memo(function (_ref2) {
|
|
|
138
146
|
}
|
|
139
147
|
});
|
|
140
148
|
});
|
|
141
|
-
}, [selectedIndex, lastVisibleStartIndex, lastVisibleStopIndex]);
|
|
149
|
+
}, [selectedIndex, lastVisibleStartIndex, lastVisibleStopIndex, itemsLength, showViewMore]);
|
|
142
150
|
var _onMouseMove = function onMouseMove(event, index) {
|
|
143
151
|
event.preventDefault();
|
|
144
152
|
event.stopPropagation();
|
|
@@ -151,7 +159,10 @@ var TypeAheadListComponent = /*#__PURE__*/React.memo(function (_ref2) {
|
|
|
151
159
|
if (!listRef.current) {
|
|
152
160
|
return;
|
|
153
161
|
}
|
|
154
|
-
var
|
|
162
|
+
var isViewMoreSelected = showViewMore && selectedIndex === itemsLength;
|
|
163
|
+
var isSelectedItemVisible = selectedIndex >= lastVisibleStartIndex && selectedIndex <= lastVisibleStopIndex ||
|
|
164
|
+
// view more is always visible, hence no scrolling
|
|
165
|
+
isViewMoreSelected;
|
|
155
166
|
|
|
156
167
|
//Should scroll to the list item only when the selectedIndex >= 0 and item is not visible
|
|
157
168
|
if (!isSelectedItemVisible && selectedIndex !== -1) {
|
|
@@ -159,7 +170,7 @@ var TypeAheadListComponent = /*#__PURE__*/React.memo(function (_ref2) {
|
|
|
159
170
|
} else if (selectedIndex === -1) {
|
|
160
171
|
listRef.current.scrollToRow(0);
|
|
161
172
|
}
|
|
162
|
-
}, [selectedIndex, lastVisibleStartIndex, lastVisibleStopIndex]);
|
|
173
|
+
}, [selectedIndex, lastVisibleStartIndex, lastVisibleStopIndex, itemsLength, showViewMore]);
|
|
163
174
|
useLayoutEffect(function () {
|
|
164
175
|
setCache(new CellMeasurerCache({
|
|
165
176
|
fixedWidth: true,
|
|
@@ -177,13 +188,15 @@ var TypeAheadListComponent = /*#__PURE__*/React.memo(function (_ref2) {
|
|
|
177
188
|
});
|
|
178
189
|
}, [items]);
|
|
179
190
|
useLayoutEffect(function () {
|
|
180
|
-
|
|
191
|
+
// Exclude view more item from the count
|
|
192
|
+
var itemsToRender = showViewMore ? items.slice(0, -1) : items;
|
|
193
|
+
var height = Math.min(itemsToRender.reduce(function (prevValue, currentValue, index) {
|
|
181
194
|
return prevValue + cache.rowHeight({
|
|
182
195
|
index: index
|
|
183
196
|
});
|
|
184
197
|
}, 0), fitHeight);
|
|
185
198
|
setHeight(height);
|
|
186
|
-
}, [items, cache, fitHeight]);
|
|
199
|
+
}, [items, cache, fitHeight, showViewMore]);
|
|
187
200
|
useLayoutEffect(function () {
|
|
188
201
|
if (!listContainerRef.current) {
|
|
189
202
|
return;
|
|
@@ -236,7 +249,7 @@ var TypeAheadListComponent = /*#__PURE__*/React.memo(function (_ref2) {
|
|
|
236
249
|
// eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
|
|
237
250
|
element === null || element === void 0 || element.removeEventListener('keydown', handleKeyDown);
|
|
238
251
|
};
|
|
239
|
-
}, [editorView.state, focusTargetElement, selectNextItem, selectPreviousItem, selectedIndex, onItemClick,
|
|
252
|
+
}, [editorView.state, focusTargetElement, selectNextItem, selectPreviousItem, selectedIndex, onItemClick, itemsLength]);
|
|
240
253
|
var firstOnlineSupportedRow = useMemo(function () {
|
|
241
254
|
return items.findIndex(function (item) {
|
|
242
255
|
return item.isDisabledOffline !== true;
|
|
@@ -266,7 +279,7 @@ var TypeAheadListComponent = /*#__PURE__*/React.memo(function (_ref2) {
|
|
|
266
279
|
key: items[index].title,
|
|
267
280
|
item: currentItem,
|
|
268
281
|
firstOnlineSupportedIndex: firstOnlineSupportedRow,
|
|
269
|
-
itemsLength:
|
|
282
|
+
itemsLength: itemsLength,
|
|
270
283
|
itemIndex: index,
|
|
271
284
|
selectedIndex: selectedIndex,
|
|
272
285
|
onItemClick: actions.onItemClick,
|
|
@@ -296,8 +309,10 @@ var TypeAheadListComponent = /*#__PURE__*/React.memo(function (_ref2) {
|
|
|
296
309
|
})));
|
|
297
310
|
var ListContent = jsx(List, {
|
|
298
311
|
rowRenderer: renderRow,
|
|
299
|
-
ref: listRef
|
|
300
|
-
|
|
312
|
+
ref: listRef
|
|
313
|
+
// Skip rendering the view more button in the list
|
|
314
|
+
,
|
|
315
|
+
rowCount: itemsLength,
|
|
301
316
|
rowHeight: cache.rowHeight,
|
|
302
317
|
onRowsRendered: onItemsRendered,
|
|
303
318
|
width: LIST_WIDTH,
|
|
@@ -331,8 +346,11 @@ var TypeAheadListComponent = /*#__PURE__*/React.memo(function (_ref2) {
|
|
|
331
346
|
}, jsx("div", {
|
|
332
347
|
id: menuGroupId,
|
|
333
348
|
ref: listContainerRef
|
|
334
|
-
}, !showViewMore ||
|
|
335
|
-
|
|
349
|
+
}, !showViewMore || itemsLength ? ListContent : EmptyResultView, showViewMore && onViewMoreClick && jsx(ViewMore, {
|
|
350
|
+
onClick: onViewMoreClick,
|
|
351
|
+
isFocused: selectedIndex === itemsLength
|
|
352
|
+
}), jsx(TypeaheadAssistiveTextPureComponent, {
|
|
353
|
+
numberOfResults: itemsLength.toString()
|
|
336
354
|
})));
|
|
337
355
|
});
|
|
338
356
|
export var TypeAheadList = injectIntl(TypeAheadListComponent);
|
|
@@ -62,7 +62,7 @@ var itemTitle = css({
|
|
|
62
62
|
lineHeight: '1.4'
|
|
63
63
|
});
|
|
64
64
|
var itemTitleOverride = css({
|
|
65
|
-
font: "var(--ds-font-body, normal 400 14px/20px ui-sans-serif, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Ubuntu,
|
|
65
|
+
font: "var(--ds-font-body, normal 400 14px/20px ui-sans-serif, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Ubuntu, \"Helvetica Neue\", sans-serif)"
|
|
66
66
|
});
|
|
67
67
|
var itemDescription = css({
|
|
68
68
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values, @atlaskit/design-system/use-tokens-typography
|
|
@@ -71,7 +71,7 @@ var itemDescription = css({
|
|
|
71
71
|
marginTop: "var(--ds-space-050, 4px)".concat(";")
|
|
72
72
|
});
|
|
73
73
|
var itemDescriptionOverride = css({
|
|
74
|
-
font: "var(--ds-font-body-small, normal 400 11px/16px ui-sans-serif, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Ubuntu,
|
|
74
|
+
font: "var(--ds-font-body-small, normal 400 11px/16px ui-sans-serif, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Ubuntu, \"Helvetica Neue\", sans-serif)",
|
|
75
75
|
marginTop: 0
|
|
76
76
|
});
|
|
77
77
|
|
|
@@ -18,7 +18,6 @@ import { N0, N50A, N60A } from '@atlaskit/theme/colors';
|
|
|
18
18
|
import { CloseSelectionOptions, TYPE_AHEAD_DECORATION_DATA_ATTRIBUTE, TYPE_AHEAD_POPUP_CONTENT_CLASS } from '../pm-plugins/constants';
|
|
19
19
|
import { TypeAheadErrorFallback } from './TypeAheadErrorFallback';
|
|
20
20
|
import { TypeAheadList } from './TypeAheadList';
|
|
21
|
-
import { ViewMore } from './ViewMore';
|
|
22
21
|
var DEFAULT_TYPEAHEAD_MENU_HEIGHT = 380;
|
|
23
22
|
var VIEWMORE_BUTTON_HEIGHT = 53;
|
|
24
23
|
var DEFAULT_TYPEAHEAD_MENU_HEIGHT_NEW = 480;
|
|
@@ -209,22 +208,31 @@ export var TypeAheadPopup = /*#__PURE__*/React.memo(function (props) {
|
|
|
209
208
|
var _window$getSelection2;
|
|
210
209
|
// Check if new focus point is inside the current editor. If it is not we
|
|
211
210
|
// want to close the typeahead popup regardless of text selection state
|
|
212
|
-
var
|
|
211
|
+
var currentFocus = (_window$getSelection2 = window.getSelection()) === null || _window$getSelection2 === void 0 ? void 0 : _window$getSelection2.focusNode; // the focusNode is either TextNode, ElementNode
|
|
212
|
+
// if currentFocus is not HTMLElement, take its parent node as focusNode
|
|
213
|
+
var focusNode = currentFocus instanceof HTMLElement ? currentFocus : currentFocus === null || currentFocus === void 0 ? void 0 : currentFocus.parentNode;
|
|
213
214
|
if (focusNode instanceof HTMLElement) {
|
|
214
215
|
var innerEditor = focusNode.closest('.extension-editable-area');
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
if (
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
216
|
+
if (innerEditor) {
|
|
217
|
+
// When there is no related target, we default to not closing the popup
|
|
218
|
+
var newFocusInsideCurrentEditor = !relatedTarget;
|
|
219
|
+
if (relatedTarget instanceof HTMLElement) {
|
|
220
|
+
if (innerEditor) {
|
|
221
|
+
// check if the new focus is inside inner editor, keep popup opens
|
|
222
|
+
newFocusInsideCurrentEditor = innerEditor.contains(relatedTarget);
|
|
223
|
+
} else {
|
|
224
|
+
// if the new focus contains current focus node, the popup won't close
|
|
225
|
+
newFocusInsideCurrentEditor = relatedTarget.contains(focusNode);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
if (!isTextSelected && newFocusInsideCurrentEditor) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
} else {
|
|
232
|
+
// if the current focus in outer editor, keep the existing behaviour, do not close the pop up if text is not selected
|
|
233
|
+
if (!isTextSelected) {
|
|
234
|
+
return;
|
|
224
235
|
}
|
|
225
|
-
}
|
|
226
|
-
if (!isTextSelected && newFocusInsideCurrentEditor) {
|
|
227
|
-
return;
|
|
228
236
|
}
|
|
229
237
|
}
|
|
230
238
|
} else {
|
|
@@ -317,9 +325,8 @@ export var TypeAheadPopup = /*#__PURE__*/React.memo(function (props) {
|
|
|
317
325
|
triggerHandler: triggerHandler,
|
|
318
326
|
moreElementsInQuickInsertViewEnabled: moreElementsInQuickInsertViewEnabled,
|
|
319
327
|
api: api,
|
|
320
|
-
showViewMore: showViewMore
|
|
321
|
-
|
|
322
|
-
onClick: onViewMoreClick
|
|
328
|
+
showViewMore: showViewMore,
|
|
329
|
+
onViewMoreClick: onViewMoreClick
|
|
323
330
|
}))));
|
|
324
331
|
});
|
|
325
332
|
TypeAheadPopup.displayName = 'TypeAheadPopup';
|
package/dist/esm/ui/ViewMore.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* @jsxRuntime classic
|
|
3
3
|
* @jsx jsx
|
|
4
4
|
*/
|
|
5
|
+
import { useEffect, useRef } from 'react';
|
|
6
|
+
|
|
5
7
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
|
|
6
8
|
import { css, jsx } from '@emotion/react';
|
|
7
9
|
import { useIntl } from 'react-intl-next';
|
|
@@ -13,17 +15,57 @@ var buttonStyles = css({
|
|
|
13
15
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors -- Ignored via go/DSP-18766
|
|
14
16
|
'& > button:hover': {
|
|
15
17
|
backgroundColor: "var(--ds-background-neutral-subtle-hovered, ".concat(N30, ")")
|
|
18
|
+
},
|
|
19
|
+
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors -- Ignored via go/DSP-18766
|
|
20
|
+
'& > button:focus': {
|
|
21
|
+
backgroundColor: "var(--ds-background-neutral-subtle-hovered, ".concat(N30, ")"),
|
|
22
|
+
outline: 'none'
|
|
16
23
|
}
|
|
17
24
|
});
|
|
18
25
|
export var ViewMore = function ViewMore(_ref) {
|
|
19
|
-
var onClick = _ref.onClick
|
|
26
|
+
var onClick = _ref.onClick,
|
|
27
|
+
isFocused = _ref.isFocused;
|
|
20
28
|
var _useIntl = useIntl(),
|
|
21
29
|
formatMessage = _useIntl.formatMessage;
|
|
30
|
+
var ref = useRef(null);
|
|
31
|
+
useEffect(function () {
|
|
32
|
+
if (isFocused && ref.current) {
|
|
33
|
+
ref.current.focus();
|
|
34
|
+
}
|
|
35
|
+
}, [isFocused]);
|
|
36
|
+
useEffect(function () {
|
|
37
|
+
if (!ref.current) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
var element = ref.current;
|
|
41
|
+
var handleEnter = function handleEnter(e) {
|
|
42
|
+
if (e.key === 'Enter') {
|
|
43
|
+
onClick();
|
|
44
|
+
// Prevent keydown listener in TypeaheadList from handling Enter pressed
|
|
45
|
+
e.stopPropagation();
|
|
46
|
+
} else if (e.key === 'Tab') {
|
|
47
|
+
// TypeaheadList will try to insert selected item on Tab press
|
|
48
|
+
// hence stop propagation to prevent that and treat this as noop
|
|
49
|
+
e.stopPropagation();
|
|
50
|
+
e.preventDefault();
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// Ignored via go/ees005
|
|
55
|
+
// eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
|
|
56
|
+
element === null || element === void 0 || element.addEventListener('keydown', handleEnter);
|
|
57
|
+
return function () {
|
|
58
|
+
// Ignored via go/ees005
|
|
59
|
+
// eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
|
|
60
|
+
element === null || element === void 0 || element.removeEventListener('keydown', handleEnter);
|
|
61
|
+
};
|
|
62
|
+
});
|
|
22
63
|
return jsx(Section, {
|
|
23
64
|
hasSeparator: true
|
|
24
65
|
}, jsx("span", {
|
|
25
66
|
css: buttonStyles
|
|
26
67
|
}, jsx(ButtonItem, {
|
|
68
|
+
ref: ref,
|
|
27
69
|
onClick: onClick,
|
|
28
70
|
iconBefore: jsx(ShowMoreHorizontalIcon, {
|
|
29
71
|
label: ""
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
2
2
|
import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
3
|
-
import { SelectItemMode } from '@atlaskit/editor-common/type-ahead';
|
|
3
|
+
import { SelectItemMode, TypeAheadAvailableNodes } from '@atlaskit/editor-common/type-ahead';
|
|
4
|
+
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
|
|
4
5
|
import { updateQuery } from '../pm-plugins/commands/update-query';
|
|
5
6
|
import { itemIsDisabled as _itemIsDisabled } from '../pm-plugins/item-is-disabled';
|
|
6
7
|
import { getPluginState, moveSelectedIndex, skipForwardToSafeItem } from '../pm-plugins/utils';
|
|
@@ -21,6 +22,9 @@ export var WrapperTypeAhead = /*#__PURE__*/React.memo(function (_ref) {
|
|
|
21
22
|
reopenQuery = _ref.reopenQuery,
|
|
22
23
|
onUndoRedo = _ref.onUndoRedo,
|
|
23
24
|
api = _ref.api;
|
|
25
|
+
// @ts-ignore
|
|
26
|
+
var openElementBrowserModal = triggerHandler === null || triggerHandler === void 0 ? void 0 : triggerHandler.openElementBrowserModal;
|
|
27
|
+
var showViewMore = (triggerHandler === null || triggerHandler === void 0 ? void 0 : triggerHandler.id) === TypeAheadAvailableNodes.QUICK_INSERT && !!openElementBrowserModal && editorExperiment('platform_editor_controls', 'variant1');
|
|
24
28
|
var _useState = useState(false),
|
|
25
29
|
_useState2 = _slicedToArray(_useState, 2),
|
|
26
30
|
closed = _useState2[0],
|
|
@@ -31,7 +35,7 @@ export var WrapperTypeAhead = /*#__PURE__*/React.memo(function (_ref) {
|
|
|
31
35
|
setQuery = _useState4[1];
|
|
32
36
|
var queryRef = useRef(query);
|
|
33
37
|
var editorViewRef = useRef(editorView);
|
|
34
|
-
var items = useLoadItems(triggerHandler, editorView, query);
|
|
38
|
+
var items = useLoadItems(triggerHandler, editorView, query, showViewMore);
|
|
35
39
|
useLayoutEffect(function () {
|
|
36
40
|
queryRef.current = query;
|
|
37
41
|
}, [query]);
|
|
@@ -4,7 +4,7 @@ import { fg } from '@atlaskit/platform-feature-flags';
|
|
|
4
4
|
import { updateListError } from '../../pm-plugins/commands/update-list-error';
|
|
5
5
|
import { updateListItem } from '../../pm-plugins/commands/update-list-items';
|
|
6
6
|
var EMPTY_LIST_ITEM = [];
|
|
7
|
-
export var useLoadItems = function useLoadItems(triggerHandler, editorView, query) {
|
|
7
|
+
export var useLoadItems = function useLoadItems(triggerHandler, editorView, query, showViewMore) {
|
|
8
8
|
var _useState = useState(EMPTY_LIST_ITEM),
|
|
9
9
|
_useState2 = _slicedToArray(_useState, 2),
|
|
10
10
|
items = _useState2[0],
|
|
@@ -27,8 +27,11 @@ export var useLoadItems = function useLoadItems(triggerHandler, editorView, quer
|
|
|
27
27
|
if (componentIsMounted.current) {
|
|
28
28
|
setItems(list);
|
|
29
29
|
}
|
|
30
|
+
var viewMoreItem = {
|
|
31
|
+
title: 'View more'
|
|
32
|
+
};
|
|
30
33
|
queueMicrotask(function () {
|
|
31
|
-
updateListItem(list)(view.state, view.dispatch);
|
|
34
|
+
updateListItem(showViewMore ? list.concat(viewMoreItem) : list)(view.state, view.dispatch);
|
|
32
35
|
});
|
|
33
36
|
}).catch(function (e) {
|
|
34
37
|
if (fg('platform_editor_offline_editing_ga')) {
|
|
@@ -198,22 +198,31 @@ export var TypeAheadPopup = /*#__PURE__*/React.memo(function (props) {
|
|
|
198
198
|
var _window$getSelection2;
|
|
199
199
|
// Check if new focus point is inside the current editor. If it is not we
|
|
200
200
|
// want to close the typeahead popup regardless of text selection state
|
|
201
|
-
var
|
|
201
|
+
var currentFocus = (_window$getSelection2 = window.getSelection()) === null || _window$getSelection2 === void 0 ? void 0 : _window$getSelection2.focusNode; // the focusNode is either TextNode, ElementNode
|
|
202
|
+
// if currentFocus is not HTMLElement, take its parent node as focusNode
|
|
203
|
+
var focusNode = currentFocus instanceof HTMLElement ? currentFocus : currentFocus === null || currentFocus === void 0 ? void 0 : currentFocus.parentNode;
|
|
202
204
|
if (focusNode instanceof HTMLElement) {
|
|
203
205
|
var innerEditor = focusNode.closest('.extension-editable-area');
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
if (
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
206
|
+
if (innerEditor) {
|
|
207
|
+
// When there is no related target, we default to not closing the popup
|
|
208
|
+
var newFocusInsideCurrentEditor = !relatedTarget;
|
|
209
|
+
if (relatedTarget instanceof HTMLElement) {
|
|
210
|
+
if (innerEditor) {
|
|
211
|
+
// check if the new focus is inside inner editor, keep popup opens
|
|
212
|
+
newFocusInsideCurrentEditor = innerEditor.contains(relatedTarget);
|
|
213
|
+
} else {
|
|
214
|
+
// if the new focus contains current focus node, the popup won't close
|
|
215
|
+
newFocusInsideCurrentEditor = relatedTarget.contains(focusNode);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
if (!isTextSelected && newFocusInsideCurrentEditor) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
} else {
|
|
222
|
+
// if the current focus in outer editor, keep the existing behaviour, do not close the pop up if text is not selected
|
|
223
|
+
if (!isTextSelected) {
|
|
224
|
+
return;
|
|
213
225
|
}
|
|
214
|
-
}
|
|
215
|
-
if (!isTextSelected && newFocusInsideCurrentEditor) {
|
|
216
|
-
return;
|
|
217
226
|
}
|
|
218
227
|
}
|
|
219
228
|
} else {
|
|
@@ -20,6 +20,7 @@ export declare const TypeAheadList: React.FC<import("react-intl-next").WithIntlP
|
|
|
20
20
|
moreElementsInQuickInsertViewEnabled?: boolean | undefined;
|
|
21
21
|
api: ExtractInjectionAPI<TypeAheadPlugin> | undefined;
|
|
22
22
|
showViewMore?: boolean | undefined;
|
|
23
|
+
onViewMoreClick?: (() => void) | undefined;
|
|
23
24
|
} & WrappedComponentProps>> & {
|
|
24
25
|
WrappedComponent: React.ComponentType<{
|
|
25
26
|
items: Array<TypeAheadItem>;
|
|
@@ -32,5 +33,6 @@ export declare const TypeAheadList: React.FC<import("react-intl-next").WithIntlP
|
|
|
32
33
|
moreElementsInQuickInsertViewEnabled?: boolean | undefined;
|
|
33
34
|
api: ExtractInjectionAPI<TypeAheadPlugin> | undefined;
|
|
34
35
|
showViewMore?: boolean | undefined;
|
|
36
|
+
onViewMoreClick?: (() => void) | undefined;
|
|
35
37
|
} & WrappedComponentProps>;
|
|
36
38
|
};
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @jsxRuntime classic
|
|
3
|
-
* @jsx jsx
|
|
4
|
-
*/
|
|
5
1
|
import { jsx } from '@emotion/react';
|
|
6
|
-
export declare const ViewMore: ({ onClick, }: {
|
|
7
|
-
onClick: (
|
|
2
|
+
export declare const ViewMore: ({ onClick, isFocused }: {
|
|
3
|
+
onClick: () => void;
|
|
4
|
+
isFocused: boolean;
|
|
8
5
|
}) => jsx.JSX.Element;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { TypeAheadHandler, TypeAheadItem } from '@atlaskit/editor-common/types';
|
|
2
2
|
import type { EditorView } from '@atlaskit/editor-prosemirror/view';
|
|
3
|
-
export declare const useLoadItems: (triggerHandler: TypeAheadHandler, editorView: EditorView, query: string) => Array<TypeAheadItem>;
|
|
3
|
+
export declare const useLoadItems: (triggerHandler: TypeAheadHandler, editorView: EditorView, query: string, showViewMore?: boolean) => Array<TypeAheadItem>;
|
|
@@ -20,6 +20,7 @@ export declare const TypeAheadList: React.FC<import("react-intl-next").WithIntlP
|
|
|
20
20
|
moreElementsInQuickInsertViewEnabled?: boolean | undefined;
|
|
21
21
|
api: ExtractInjectionAPI<TypeAheadPlugin> | undefined;
|
|
22
22
|
showViewMore?: boolean | undefined;
|
|
23
|
+
onViewMoreClick?: (() => void) | undefined;
|
|
23
24
|
} & WrappedComponentProps>> & {
|
|
24
25
|
WrappedComponent: React.ComponentType<{
|
|
25
26
|
items: Array<TypeAheadItem>;
|
|
@@ -32,5 +33,6 @@ export declare const TypeAheadList: React.FC<import("react-intl-next").WithIntlP
|
|
|
32
33
|
moreElementsInQuickInsertViewEnabled?: boolean | undefined;
|
|
33
34
|
api: ExtractInjectionAPI<TypeAheadPlugin> | undefined;
|
|
34
35
|
showViewMore?: boolean | undefined;
|
|
36
|
+
onViewMoreClick?: (() => void) | undefined;
|
|
35
37
|
} & WrappedComponentProps>;
|
|
36
38
|
};
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @jsxRuntime classic
|
|
3
|
-
* @jsx jsx
|
|
4
|
-
*/
|
|
5
1
|
import { jsx } from '@emotion/react';
|
|
6
|
-
export declare const ViewMore: ({ onClick, }: {
|
|
7
|
-
onClick: (
|
|
2
|
+
export declare const ViewMore: ({ onClick, isFocused }: {
|
|
3
|
+
onClick: () => void;
|
|
4
|
+
isFocused: boolean;
|
|
8
5
|
}) => jsx.JSX.Element;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { TypeAheadHandler, TypeAheadItem } from '@atlaskit/editor-common/types';
|
|
2
2
|
import type { EditorView } from '@atlaskit/editor-prosemirror/view';
|
|
3
|
-
export declare const useLoadItems: (triggerHandler: TypeAheadHandler, editorView: EditorView, query: string) => Array<TypeAheadItem>;
|
|
3
|
+
export declare const useLoadItems: (triggerHandler: TypeAheadHandler, editorView: EditorView, query: string, showViewMore?: boolean) => Array<TypeAheadItem>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-type-ahead",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.2",
|
|
4
4
|
"description": "Type-ahead plugin for @atlaskit/editor-core",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@atlaskit/adf-schema": "^47.6.0",
|
|
37
|
-
"@atlaskit/editor-common": "^
|
|
37
|
+
"@atlaskit/editor-common": "^101.1.0",
|
|
38
38
|
"@atlaskit/editor-element-browser": "^0.1.0",
|
|
39
39
|
"@atlaskit/editor-plugin-analytics": "^2.1.0",
|
|
40
40
|
"@atlaskit/editor-plugin-connectivity": "^2.0.0",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"@atlaskit/platform-feature-flags": "^1.1.0",
|
|
48
48
|
"@atlaskit/primitives": "^14.1.0",
|
|
49
49
|
"@atlaskit/prosemirror-input-rules": "^3.3.0",
|
|
50
|
-
"@atlaskit/theme": "^
|
|
50
|
+
"@atlaskit/theme": "^18.0.0",
|
|
51
51
|
"@atlaskit/tmp-editor-statsig": "^3.4.0",
|
|
52
52
|
"@atlaskit/tokens": "^4.3.0",
|
|
53
53
|
"@babel/runtime": "^7.0.0",
|