@atlaskit/editor-plugin-type-ahead 13.2.1 → 13.2.3
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 +14 -0
- package/dist/cjs/pm-plugins/commands/insert-type-ahead-item.js +96 -1
- package/dist/cjs/ui/ContentComponent.js +4 -0
- package/dist/cjs/ui/InputQuery.js +21 -14
- package/dist/cjs/ui/WrapperTypeAhead.js +23 -1
- package/dist/cjs/ui/hooks/use-load-items.js +6 -1
- package/dist/cjs/ui/registered-menu/PassThrough.js +10 -0
- package/dist/cjs/ui/registered-menu/RegisteredTypeAheadMenu.js +146 -0
- package/dist/cjs/ui/registered-menu/TypeAheadContext.js +8 -0
- package/dist/cjs/ui/registered-menu/TypeAheadItemRow.js +27 -0
- package/dist/cjs/ui/registered-menu/TypeAheadProvider.js +8 -0
- package/dist/cjs/ui/registered-menu/buildTypeAheadMenuModel.js +50 -0
- package/dist/cjs/ui/registered-menu/getTypeAheadItemId.js +9 -0
- package/dist/cjs/ui/registered-menu/quick-insert/TypeAheadQuickInsertItem.js +37 -0
- package/dist/cjs/ui/registered-menu/quick-insert/TypeAheadQuickInsertProvider.js +41 -0
- package/dist/cjs/ui/registered-menu/typeAheadMenuTypes.js +5 -0
- package/dist/cjs/ui/registered-menu/typeAheadSurfaces.js +26 -0
- package/dist/cjs/ui/registered-menu/useTypeAheadContext.js +15 -0
- package/dist/es2019/pm-plugins/commands/insert-type-ahead-item.js +97 -0
- package/dist/es2019/ui/ContentComponent.js +4 -0
- package/dist/es2019/ui/InputQuery.js +15 -8
- package/dist/es2019/ui/WrapperTypeAhead.js +23 -1
- package/dist/es2019/ui/hooks/use-load-items.js +6 -2
- package/dist/es2019/ui/registered-menu/PassThrough.js +3 -0
- package/dist/es2019/ui/registered-menu/RegisteredTypeAheadMenu.js +127 -0
- package/dist/es2019/ui/registered-menu/TypeAheadContext.js +2 -0
- package/dist/es2019/ui/registered-menu/TypeAheadItemRow.js +18 -0
- package/dist/es2019/ui/registered-menu/TypeAheadProvider.js +2 -0
- package/dist/es2019/ui/registered-menu/buildTypeAheadMenuModel.js +24 -0
- package/dist/es2019/ui/registered-menu/getTypeAheadItemId.js +1 -0
- package/dist/es2019/ui/registered-menu/quick-insert/TypeAheadQuickInsertItem.js +25 -0
- package/dist/es2019/ui/registered-menu/quick-insert/TypeAheadQuickInsertProvider.js +33 -0
- package/dist/es2019/ui/registered-menu/typeAheadMenuTypes.js +1 -0
- package/dist/es2019/ui/registered-menu/typeAheadSurfaces.js +20 -0
- package/dist/es2019/ui/registered-menu/useTypeAheadContext.js +9 -0
- package/dist/esm/pm-plugins/commands/insert-type-ahead-item.js +95 -0
- package/dist/esm/ui/ContentComponent.js +4 -0
- package/dist/esm/ui/InputQuery.js +21 -14
- package/dist/esm/ui/WrapperTypeAhead.js +23 -1
- package/dist/esm/ui/hooks/use-load-items.js +6 -1
- package/dist/esm/ui/registered-menu/PassThrough.js +4 -0
- package/dist/esm/ui/registered-menu/RegisteredTypeAheadMenu.js +137 -0
- package/dist/esm/ui/registered-menu/TypeAheadContext.js +2 -0
- package/dist/esm/ui/registered-menu/TypeAheadItemRow.js +19 -0
- package/dist/esm/ui/registered-menu/TypeAheadProvider.js +2 -0
- package/dist/esm/ui/registered-menu/buildTypeAheadMenuModel.js +44 -0
- package/dist/esm/ui/registered-menu/getTypeAheadItemId.js +3 -0
- package/dist/esm/ui/registered-menu/quick-insert/TypeAheadQuickInsertItem.js +28 -0
- package/dist/esm/ui/registered-menu/quick-insert/TypeAheadQuickInsertProvider.js +33 -0
- package/dist/esm/ui/registered-menu/typeAheadMenuTypes.js +1 -0
- package/dist/esm/ui/registered-menu/typeAheadSurfaces.js +20 -0
- package/dist/esm/ui/registered-menu/useTypeAheadContext.js +9 -0
- package/dist/types/pm-plugins/commands/insert-type-ahead-item.d.ts +7 -0
- package/dist/types/typeAheadPluginType.d.ts +3 -1
- package/dist/types/ui/InputQuery.d.ts +10 -2
- package/dist/types/ui/hooks/use-load-items.d.ts +1 -1
- package/dist/types/ui/registered-menu/PassThrough.d.ts +2 -0
- package/dist/types/ui/registered-menu/RegisteredTypeAheadMenu.d.ts +30 -0
- package/dist/types/ui/registered-menu/TypeAheadContext.d.ts +14 -0
- package/dist/types/ui/registered-menu/TypeAheadItemRow.d.ts +11 -0
- package/dist/types/ui/registered-menu/TypeAheadProvider.d.ts +3 -0
- package/dist/types/ui/registered-menu/buildTypeAheadMenuModel.d.ts +7 -0
- package/dist/types/ui/registered-menu/getTypeAheadItemId.d.ts +1 -0
- package/dist/types/ui/registered-menu/quick-insert/TypeAheadQuickInsertItem.d.ts +3 -0
- package/dist/types/ui/registered-menu/quick-insert/TypeAheadQuickInsertProvider.d.ts +2 -0
- package/dist/types/ui/registered-menu/typeAheadMenuTypes.d.ts +9 -0
- package/dist/types/ui/registered-menu/typeAheadSurfaces.d.ts +17 -0
- package/dist/types/ui/registered-menu/useTypeAheadContext.d.ts +2 -0
- package/package.json +8 -4
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _typeof = require("@babel/runtime/helpers/typeof");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.TypeAheadQuickInsertProvider = void 0;
|
|
8
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
9
|
+
var _provider = require("@atlaskit/editor-common/quick-insert/provider");
|
|
10
|
+
var _insertTypeAheadItem = require("../../../pm-plugins/commands/insert-type-ahead-item");
|
|
11
|
+
var _useTypeAheadContext2 = require("../useTypeAheadContext");
|
|
12
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
|
|
13
|
+
var TypeAheadQuickInsertProvider = exports.TypeAheadQuickInsertProvider = function TypeAheadQuickInsertProvider(_ref) {
|
|
14
|
+
var children = _ref.children;
|
|
15
|
+
var _useTypeAheadContext = (0, _useTypeAheadContext2.useTypeAheadContext)(),
|
|
16
|
+
editorView = _useTypeAheadContext.editorView,
|
|
17
|
+
inputMethod = _useTypeAheadContext.inputMethod,
|
|
18
|
+
onClose = _useTypeAheadContext.onClose,
|
|
19
|
+
query = _useTypeAheadContext.query,
|
|
20
|
+
triggerHandler = _useTypeAheadContext.triggerHandler;
|
|
21
|
+
var select = (0, _react.useCallback)(function (selectionHandler) {
|
|
22
|
+
onClose();
|
|
23
|
+
queueMicrotask(function () {
|
|
24
|
+
(0, _insertTypeAheadItem.performTypeAheadSelection)(editorView)({
|
|
25
|
+
handler: triggerHandler,
|
|
26
|
+
inputMethod: inputMethod,
|
|
27
|
+
query: query,
|
|
28
|
+
selectionHandler: selectionHandler
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
}, [editorView, inputMethod, onClose, query, triggerHandler]);
|
|
32
|
+
var contextValue = (0, _react.useMemo)(function () {
|
|
33
|
+
return {
|
|
34
|
+
editorView: editorView,
|
|
35
|
+
select: select
|
|
36
|
+
};
|
|
37
|
+
}, [editorView, select]);
|
|
38
|
+
return /*#__PURE__*/_react.default.createElement(_provider.QuickInsertProvider, {
|
|
39
|
+
value: contextValue
|
|
40
|
+
}, children);
|
|
41
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.getTypeAheadSurface = void 0;
|
|
7
|
+
var _analytics = require("@atlaskit/editor-common/analytics");
|
|
8
|
+
var _keys = require("@atlaskit/editor-common/quick-insert/keys");
|
|
9
|
+
var _typeAhead = require("@atlaskit/editor-common/type-ahead");
|
|
10
|
+
var _isExperimentEnabled = require("@atlaskit/platform-feature-experiments/is-experiment-enabled");
|
|
11
|
+
var _TypeAheadQuickInsertItem = require("./quick-insert/TypeAheadQuickInsertItem");
|
|
12
|
+
var _TypeAheadQuickInsertProvider = require("./quick-insert/TypeAheadQuickInsertProvider");
|
|
13
|
+
var quickInsertSurface = {
|
|
14
|
+
inputMethod: _analytics.INPUT_METHOD.QUICK_INSERT,
|
|
15
|
+
Item: _TypeAheadQuickInsertItem.TypeAheadQuickInsertItem,
|
|
16
|
+
listIdPrefix: 'quick-insert-menu',
|
|
17
|
+
listLabel: _typeAhead.typeAheadListMessages.quickInsertInputLabel,
|
|
18
|
+
Provider: _TypeAheadQuickInsertProvider.TypeAheadQuickInsertProvider,
|
|
19
|
+
root: _keys.MENU
|
|
20
|
+
};
|
|
21
|
+
var getTypeAheadSurface = exports.getTypeAheadSurface = function getTypeAheadSurface(id) {
|
|
22
|
+
if (id === _typeAhead.TypeAheadAvailableNodes.QUICK_INSERT && (0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_slash_command')) {
|
|
23
|
+
return quickInsertSurface;
|
|
24
|
+
}
|
|
25
|
+
return undefined;
|
|
26
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.useTypeAheadContext = void 0;
|
|
7
|
+
var _react = require("react");
|
|
8
|
+
var _TypeAheadContext = require("./TypeAheadContext");
|
|
9
|
+
var useTypeAheadContext = exports.useTypeAheadContext = function useTypeAheadContext() {
|
|
10
|
+
var value = (0, _react.useContext)(_TypeAheadContext.TypeAheadContext);
|
|
11
|
+
if (!value) {
|
|
12
|
+
throw new Error('useTypeAheadContext must be used within TypeAheadProvider');
|
|
13
|
+
}
|
|
14
|
+
return value;
|
|
15
|
+
};
|
|
@@ -201,4 +201,101 @@ export const insertTypeAheadItem = view => ({
|
|
|
201
201
|
closeHistory(tr);
|
|
202
202
|
view.dispatch(tr);
|
|
203
203
|
view.focus();
|
|
204
|
+
};
|
|
205
|
+
const executeTypeAheadSelection = view => ({
|
|
206
|
+
selectItem,
|
|
207
|
+
handler,
|
|
208
|
+
mode,
|
|
209
|
+
query,
|
|
210
|
+
sourceListItem
|
|
211
|
+
}) => {
|
|
212
|
+
const pluginState = getPluginState(view.state);
|
|
213
|
+
if (!pluginState) {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
const stats = (pluginState.stats || new StatsModifier()).serialize();
|
|
217
|
+
const meta = {
|
|
218
|
+
mode,
|
|
219
|
+
query,
|
|
220
|
+
stats,
|
|
221
|
+
sourceListItem
|
|
222
|
+
};
|
|
223
|
+
const {
|
|
224
|
+
tr
|
|
225
|
+
} = view.state;
|
|
226
|
+
const trigger = handler.trigger;
|
|
227
|
+
let text = `${trigger}${query}`;
|
|
228
|
+
if (mode === SelectItemMode.SPACE) {
|
|
229
|
+
text = text.trim().concat(' ');
|
|
230
|
+
}
|
|
231
|
+
const selectedIndex = -1;
|
|
232
|
+
const wasInsertedBySpace = mode === SelectItemMode.SPACE;
|
|
233
|
+
const {
|
|
234
|
+
selection: {
|
|
235
|
+
from: textStartPosition
|
|
236
|
+
}
|
|
237
|
+
} = tr;
|
|
238
|
+
const insertItem = newEditorState => {
|
|
239
|
+
const insertCallback = createInsertCallback({
|
|
240
|
+
editorState: newEditorState,
|
|
241
|
+
query,
|
|
242
|
+
mode,
|
|
243
|
+
handler,
|
|
244
|
+
wasInsertedBySpace,
|
|
245
|
+
selectedIndex,
|
|
246
|
+
textInserted: text,
|
|
247
|
+
textStartPosition
|
|
248
|
+
});
|
|
249
|
+
let wasInsertCallbackCalled = false;
|
|
250
|
+
const insertCallbackProxy = new Proxy(insertCallback, {
|
|
251
|
+
apply(target, _thisContext, argumentsList) {
|
|
252
|
+
wasInsertCallbackCalled = true;
|
|
253
|
+
return target(...argumentsList);
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
const nextTr = selectItem(newEditorState, insertCallbackProxy, meta);
|
|
257
|
+
if (!wasInsertCallbackCalled && nextTr) {
|
|
258
|
+
closeHistory(nextTr);
|
|
259
|
+
if (!nextTr.getMeta(pluginKey)) {
|
|
260
|
+
closeTypeAhead(nextTr);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return nextTr || false;
|
|
264
|
+
};
|
|
265
|
+
const position = {
|
|
266
|
+
start: tr.selection.from,
|
|
267
|
+
end: tr.selection.from + text.length
|
|
268
|
+
};
|
|
269
|
+
tr.setMeta(pluginKey, {
|
|
270
|
+
action: ACTIONS.INSERT_RAW_QUERY,
|
|
271
|
+
params: createDeleteRawTextCallback({
|
|
272
|
+
wasInsertedBySpace,
|
|
273
|
+
selectedIndex,
|
|
274
|
+
insertItem,
|
|
275
|
+
position,
|
|
276
|
+
query,
|
|
277
|
+
trigger
|
|
278
|
+
})
|
|
279
|
+
});
|
|
280
|
+
tr.insertText(text);
|
|
281
|
+
closeHistory(tr);
|
|
282
|
+
view.dispatch(tr);
|
|
283
|
+
view.focus();
|
|
284
|
+
};
|
|
285
|
+
export const performTypeAheadSelection = view => ({
|
|
286
|
+
inputMethod,
|
|
287
|
+
selectionHandler,
|
|
288
|
+
handler,
|
|
289
|
+
query
|
|
290
|
+
}) => {
|
|
291
|
+
executeTypeAheadSelection(view)({
|
|
292
|
+
handler,
|
|
293
|
+
mode: SelectItemMode.SELECTED,
|
|
294
|
+
query,
|
|
295
|
+
sourceListItem: [],
|
|
296
|
+
selectItem: (_state, insert) => selectionHandler({
|
|
297
|
+
insert,
|
|
298
|
+
source: inputMethod
|
|
299
|
+
})
|
|
300
|
+
});
|
|
204
301
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
|
|
3
|
+
import { getTypeAheadSurface } from './registered-menu/typeAheadSurfaces';
|
|
3
4
|
import { TypeAheadMenu } from './TypeAheadMenu';
|
|
4
5
|
export function ContentComponent({
|
|
5
6
|
api,
|
|
@@ -31,6 +32,9 @@ export function ContentComponent({
|
|
|
31
32
|
if (items === undefined || sections === undefined || decorationSet === undefined || errorInfo === undefined || decorationElement === undefined || query === undefined || selectedIndex === undefined) {
|
|
32
33
|
return null;
|
|
33
34
|
}
|
|
35
|
+
if (getTypeAheadSurface(triggerHandler === null || triggerHandler === void 0 ? void 0 : triggerHandler.id)) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
34
38
|
return /*#__PURE__*/React.createElement(TypeAheadMenu, {
|
|
35
39
|
editorView: editorView,
|
|
36
40
|
popupMountRef: popupMountRef
|
|
@@ -81,6 +81,7 @@ const getAriaLabel = (triggerPrefix, _intl) => {
|
|
|
81
81
|
}
|
|
82
82
|
};
|
|
83
83
|
export const InputQuery = /*#__PURE__*/React.memo(({
|
|
84
|
+
activeDescendantId,
|
|
84
85
|
triggerQueryPrefix,
|
|
85
86
|
cancel,
|
|
86
87
|
onQueryChange,
|
|
@@ -92,8 +93,13 @@ export const InputQuery = /*#__PURE__*/React.memo(({
|
|
|
92
93
|
onQueryFocus,
|
|
93
94
|
onUndoRedo,
|
|
94
95
|
editorView,
|
|
95
|
-
items
|
|
96
|
+
items,
|
|
97
|
+
listId,
|
|
98
|
+
optionCount,
|
|
99
|
+
shouldKeepOpenOnRegisteredMenu
|
|
96
100
|
}) => {
|
|
101
|
+
var _ref;
|
|
102
|
+
const resolvedOptionCount = (_ref = optionCount !== null && optionCount !== void 0 ? optionCount : items === null || items === void 0 ? void 0 : items.length) !== null && _ref !== void 0 ? _ref : 0;
|
|
97
103
|
const ref = useRef(document.createElement('span'));
|
|
98
104
|
const inputRef = useRef(null);
|
|
99
105
|
const [query, setQuery] = useState(null);
|
|
@@ -278,7 +284,7 @@ export const InputQuery = /*#__PURE__*/React.memo(({
|
|
|
278
284
|
// Given the user is changing the focus
|
|
279
285
|
// When the target is inside the TypeAhead Popup
|
|
280
286
|
// Then the popup should stay open
|
|
281
|
-
if (relatedTarget instanceof HTMLElement && relatedTarget.closest && relatedTarget.closest(`.${TYPE_AHEAD_POPUP_CONTENT_CLASS}`)) {
|
|
287
|
+
if (relatedTarget instanceof HTMLElement && relatedTarget.closest && (relatedTarget.closest(`.${TYPE_AHEAD_POPUP_CONTENT_CLASS}`) || shouldKeepOpenOnRegisteredMenu && relatedTarget.closest('[data-registered-type-ahead-menu]'))) {
|
|
282
288
|
return;
|
|
283
289
|
}
|
|
284
290
|
|
|
@@ -401,7 +407,7 @@ export const InputQuery = /*#__PURE__*/React.memo(({
|
|
|
401
407
|
element.removeEventListener('input', onInput);
|
|
402
408
|
}
|
|
403
409
|
};
|
|
404
|
-
}, [triggerQueryPrefix, cleanedInputContent, onQueryFocus, cancel, checkKeyEvent, editorView.state, isEditorControlsEnabled]);
|
|
410
|
+
}, [triggerQueryPrefix, cleanedInputContent, onQueryFocus, cancel, checkKeyEvent, editorView.state, isEditorControlsEnabled, shouldKeepOpenOnRegisteredMenu]);
|
|
405
411
|
useLayoutEffect(() => {
|
|
406
412
|
const hasReopenQuery = typeof reopenQuery === 'string' && reopenQuery.trim().length > 0;
|
|
407
413
|
if (ref.current && forceFocus) {
|
|
@@ -450,9 +456,10 @@ export const InputQuery = /*#__PURE__*/React.memo(({
|
|
|
450
456
|
tabIndex: -1,
|
|
451
457
|
onInput: isSearchPlaceholderEnabled ? onInput : undefined,
|
|
452
458
|
role: "combobox",
|
|
453
|
-
"aria-
|
|
459
|
+
"aria-activedescendant": activeDescendantId,
|
|
460
|
+
"aria-controls": listId !== null && listId !== void 0 ? listId : TYPE_AHEAD_DECORATION_ELEMENT_ID,
|
|
454
461
|
"aria-autocomplete": "list",
|
|
455
|
-
"aria-expanded":
|
|
462
|
+
"aria-expanded": resolvedOptionCount !== 0,
|
|
456
463
|
"aria-labelledby": assistiveHintID,
|
|
457
464
|
suppressContentEditableWarning: true,
|
|
458
465
|
"data-query-prefix": triggerQueryPrefix
|
|
@@ -470,10 +477,10 @@ export const InputQuery = /*#__PURE__*/React.memo(({
|
|
|
470
477
|
display: 'none'
|
|
471
478
|
}
|
|
472
479
|
}, intl.formatMessage(typeAheadListMessages.inputQueryAssistiveLabel)), jsx(AssistiveText, {
|
|
473
|
-
assistiveText:
|
|
474
|
-
itemsLength:
|
|
480
|
+
assistiveText: resolvedOptionCount === 0 ? intl.formatMessage(typeAheadListMessages.noSearchResultsLabel, {
|
|
481
|
+
itemsLength: resolvedOptionCount
|
|
475
482
|
}) : '',
|
|
476
|
-
isInFocus:
|
|
483
|
+
isInFocus: resolvedOptionCount === 0 || isInFocus,
|
|
477
484
|
id: TYPE_AHEAD_DECORATION_ELEMENT_ID
|
|
478
485
|
}));
|
|
479
486
|
});
|
|
@@ -13,6 +13,8 @@ import { useItemInsert } from './hooks/use-item-insert';
|
|
|
13
13
|
import { useLoadItems } from './hooks/use-load-items';
|
|
14
14
|
import { useOnForceSelect } from './hooks/use-on-force-select';
|
|
15
15
|
import { InputQuery } from './InputQuery';
|
|
16
|
+
import { RegisteredTypeAheadMenu } from './registered-menu/RegisteredTypeAheadMenu';
|
|
17
|
+
import { getTypeAheadSurface } from './registered-menu/typeAheadSurfaces';
|
|
16
18
|
export const WrapperTypeAhead = /*#__PURE__*/React.memo(({
|
|
17
19
|
triggerHandler,
|
|
18
20
|
editorView,
|
|
@@ -38,7 +40,8 @@ export const WrapperTypeAhead = /*#__PURE__*/React.memo(({
|
|
|
38
40
|
const [query, setQuery] = useState(reopenQuery || '');
|
|
39
41
|
const queryRef = useRef(query);
|
|
40
42
|
const editorViewRef = useRef(editorView);
|
|
41
|
-
const
|
|
43
|
+
const registeredSurface = getTypeAheadSurface(triggerHandler.id);
|
|
44
|
+
const items = useLoadItems(triggerHandler, editorView, query, showMoreOptionsButton, api, intl, !registeredSurface);
|
|
42
45
|
useEffect(() => {
|
|
43
46
|
if (!closed && fg('platform_editor_ease_of_use_metrics')) {
|
|
44
47
|
var _api$metrics;
|
|
@@ -141,6 +144,25 @@ export const WrapperTypeAhead = /*#__PURE__*/React.memo(({
|
|
|
141
144
|
if (!triggerHandler) {
|
|
142
145
|
return null;
|
|
143
146
|
}
|
|
147
|
+
if (registeredSurface) {
|
|
148
|
+
return /*#__PURE__*/React.createElement(RegisteredTypeAheadMenu, {
|
|
149
|
+
anchorElement: anchorElement,
|
|
150
|
+
api: api,
|
|
151
|
+
cancel: cancel,
|
|
152
|
+
editorView: editorView,
|
|
153
|
+
forceFocus: shouldFocusCursorInsideQuery,
|
|
154
|
+
onClose: closePopup,
|
|
155
|
+
onUndoRedo: onUndoRedo,
|
|
156
|
+
popupsBoundariesElement: popupsBoundariesElement,
|
|
157
|
+
popupsMountPoint: popupsMountPoint,
|
|
158
|
+
popupsScrollableElement: popupsScrollableElement,
|
|
159
|
+
query: query,
|
|
160
|
+
reopenQuery: reopenQuery,
|
|
161
|
+
setQuery: setQuery,
|
|
162
|
+
surface: registeredSurface,
|
|
163
|
+
triggerHandler: triggerHandler
|
|
164
|
+
});
|
|
165
|
+
}
|
|
144
166
|
return /*#__PURE__*/React.createElement(InputQuery, {
|
|
145
167
|
triggerQueryPrefix: triggerHandler === null || triggerHandler === void 0 ? void 0 : triggerHandler.trigger,
|
|
146
168
|
onQueryChange: setQuery,
|
|
@@ -6,13 +6,17 @@ import { updateListError } from '../../pm-plugins/commands/update-list-error';
|
|
|
6
6
|
import { updateListItem } from '../../pm-plugins/commands/update-list-items';
|
|
7
7
|
import { buildSectionedResult } from './build-sectioned-result';
|
|
8
8
|
const EMPTY_LIST_ITEM = [];
|
|
9
|
-
export const useLoadItems = (triggerHandler, editorView, query, showViewMore, api, intl) => {
|
|
9
|
+
export const useLoadItems = (triggerHandler, editorView, query, showViewMore, api, intl, enabled = true) => {
|
|
10
10
|
const [items, setItems] = useState(EMPTY_LIST_ITEM);
|
|
11
11
|
const componentIsMounted = useRef(true);
|
|
12
12
|
const editorViewRef = useRef(editorView);
|
|
13
13
|
const latestQueryRef = useRef(query);
|
|
14
14
|
latestQueryRef.current = query;
|
|
15
15
|
useEffect(() => {
|
|
16
|
+
if (!enabled) {
|
|
17
|
+
setItems(EMPTY_LIST_ITEM);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
16
20
|
const requestQuery = query;
|
|
17
21
|
const isStaleRequest = () => latestQueryRef.current !== requestQuery;
|
|
18
22
|
const options = {
|
|
@@ -119,7 +123,7 @@ export const useLoadItems = (triggerHandler, editorView, query, showViewMore, ap
|
|
|
119
123
|
// ignore because EditorView is mutable but we don't want to
|
|
120
124
|
// call loadItems when it changes, only when the query changes
|
|
121
125
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
122
|
-
}, [triggerHandler, query, intl]);
|
|
126
|
+
}, [triggerHandler, query, intl, enabled]);
|
|
123
127
|
useEffect(() => {
|
|
124
128
|
return () => {
|
|
125
129
|
componentIsMounted.current = false;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import React, { useCallback, useId, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
+
import { useIntl } from 'react-intl';
|
|
3
|
+
import { Popup } from '@atlaskit/editor-common/ui';
|
|
4
|
+
import { akEditorFloatingDialogZIndex } from '@atlaskit/editor-shared-styles/constants';
|
|
5
|
+
import { Box } from '@atlaskit/primitives/compiled';
|
|
6
|
+
import { InputQuery } from '../InputQuery';
|
|
7
|
+
import { buildTypeAheadMenuModel } from './buildTypeAheadMenuModel';
|
|
8
|
+
import { getTypeAheadItemId } from './getTypeAheadItemId';
|
|
9
|
+
import { PassThrough } from './PassThrough';
|
|
10
|
+
import { TypeAheadItemRow } from './TypeAheadItemRow';
|
|
11
|
+
import { TypeAheadProvider } from './TypeAheadProvider';
|
|
12
|
+
const POPUP_OFFSET = [0, 8];
|
|
13
|
+
export const RegisteredTypeAheadMenu = ({
|
|
14
|
+
anchorElement,
|
|
15
|
+
api,
|
|
16
|
+
cancel,
|
|
17
|
+
editorView,
|
|
18
|
+
forceFocus,
|
|
19
|
+
onClose,
|
|
20
|
+
onUndoRedo,
|
|
21
|
+
popupsBoundariesElement,
|
|
22
|
+
popupsMountPoint,
|
|
23
|
+
popupsScrollableElement,
|
|
24
|
+
query,
|
|
25
|
+
reopenQuery,
|
|
26
|
+
setQuery,
|
|
27
|
+
surface,
|
|
28
|
+
triggerHandler
|
|
29
|
+
}) => {
|
|
30
|
+
var _model$root$component, _model$root;
|
|
31
|
+
const intl = useIntl();
|
|
32
|
+
const generatedId = useId();
|
|
33
|
+
const listId = `${surface.listIdPrefix}-${generatedId}`;
|
|
34
|
+
const menuRef = useRef(null);
|
|
35
|
+
const [selectedItemIndex, setSelectedItemIndex] = useState(0);
|
|
36
|
+
const components = useMemo(() => {
|
|
37
|
+
var _api$uiControlRegistr, _api$uiControlRegistr2;
|
|
38
|
+
return (_api$uiControlRegistr = api === null || api === void 0 ? void 0 : (_api$uiControlRegistr2 = api.uiControlRegistry) === null || _api$uiControlRegistr2 === void 0 ? void 0 : _api$uiControlRegistr2.actions.getComponents(surface.root.key)) !== null && _api$uiControlRegistr !== void 0 ? _api$uiControlRegistr : [];
|
|
39
|
+
}, [api, surface.root.key]);
|
|
40
|
+
const model = useMemo(() => buildTypeAheadMenuModel(components, surface.root), [components, surface.root]);
|
|
41
|
+
const itemKeySignature = model.items.map(({
|
|
42
|
+
key
|
|
43
|
+
}) => key).join(',');
|
|
44
|
+
useLayoutEffect(() => {
|
|
45
|
+
setSelectedItemIndex(model.items.length > 0 ? 0 : -1);
|
|
46
|
+
}, [itemKeySignature, model.items.length, query]);
|
|
47
|
+
const selectActiveItem = useCallback(_mode => {
|
|
48
|
+
var _menuRef$current, _menuRef$current$owne;
|
|
49
|
+
if (selectedItemIndex < 0) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
(_menuRef$current = menuRef.current) === null || _menuRef$current === void 0 ? void 0 : (_menuRef$current$owne = _menuRef$current.ownerDocument.getElementById(getTypeAheadItemId(listId, selectedItemIndex))) === null || _menuRef$current$owne === void 0 ? void 0 : _menuRef$current$owne.click();
|
|
53
|
+
}, [listId, selectedItemIndex]);
|
|
54
|
+
const selectNextItem = useCallback(() => {
|
|
55
|
+
setSelectedItemIndex(currentIndex => {
|
|
56
|
+
if (model.items.length === 0) {
|
|
57
|
+
return -1;
|
|
58
|
+
}
|
|
59
|
+
return currentIndex < 0 || currentIndex === model.items.length - 1 ? 0 : currentIndex + 1;
|
|
60
|
+
});
|
|
61
|
+
}, [model.items.length]);
|
|
62
|
+
const selectPreviousItem = useCallback(() => {
|
|
63
|
+
setSelectedItemIndex(currentIndex => {
|
|
64
|
+
if (model.items.length === 0) {
|
|
65
|
+
return -1;
|
|
66
|
+
}
|
|
67
|
+
return currentIndex <= 0 ? model.items.length - 1 : currentIndex - 1;
|
|
68
|
+
});
|
|
69
|
+
}, [model.items.length]);
|
|
70
|
+
const typeAheadContextValue = useMemo(() => ({
|
|
71
|
+
api,
|
|
72
|
+
editorView,
|
|
73
|
+
inputMethod: surface.inputMethod,
|
|
74
|
+
onClose,
|
|
75
|
+
query,
|
|
76
|
+
triggerHandler
|
|
77
|
+
}), [api, editorView, onClose, query, surface.inputMethod, triggerHandler]);
|
|
78
|
+
const noOp = useCallback(() => {}, []);
|
|
79
|
+
const RootComponent = (_model$root$component = (_model$root = model.root) === null || _model$root === void 0 ? void 0 : _model$root.component) !== null && _model$root$component !== void 0 ? _model$root$component : PassThrough;
|
|
80
|
+
const SurfaceProvider = surface.Provider;
|
|
81
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(InputQuery, {
|
|
82
|
+
activeDescendantId: selectedItemIndex >= 0 ? getTypeAheadItemId(listId, selectedItemIndex) : undefined,
|
|
83
|
+
cancel: cancel,
|
|
84
|
+
editorView: editorView,
|
|
85
|
+
forceFocus: forceFocus,
|
|
86
|
+
listId: listId,
|
|
87
|
+
onItemSelect: selectActiveItem,
|
|
88
|
+
onQueryChange: setQuery,
|
|
89
|
+
onQueryFocus: noOp,
|
|
90
|
+
onUndoRedo: onUndoRedo,
|
|
91
|
+
optionCount: model.items.length,
|
|
92
|
+
reopenQuery: reopenQuery,
|
|
93
|
+
selectNextItem: selectNextItem,
|
|
94
|
+
selectPreviousItem: selectPreviousItem,
|
|
95
|
+
shouldKeepOpenOnRegisteredMenu: true,
|
|
96
|
+
triggerQueryPrefix: triggerHandler.trigger
|
|
97
|
+
}), /*#__PURE__*/React.createElement(Popup, {
|
|
98
|
+
ariaLabel: null,
|
|
99
|
+
boundariesElement: popupsBoundariesElement,
|
|
100
|
+
fitWidth: 320,
|
|
101
|
+
mountTo: popupsMountPoint,
|
|
102
|
+
offset: POPUP_OFFSET,
|
|
103
|
+
preventOverflow: true,
|
|
104
|
+
scrollableElement: popupsScrollableElement,
|
|
105
|
+
target: anchorElement,
|
|
106
|
+
zIndex: akEditorFloatingDialogZIndex
|
|
107
|
+
}, /*#__PURE__*/React.createElement(Box, {
|
|
108
|
+
ref: menuRef,
|
|
109
|
+
backgroundColor: "elevation.surface.overlay",
|
|
110
|
+
"data-registered-type-ahead-menu": "",
|
|
111
|
+
padding: "space.050"
|
|
112
|
+
}, /*#__PURE__*/React.createElement(TypeAheadProvider, {
|
|
113
|
+
value: typeAheadContextValue
|
|
114
|
+
}, /*#__PURE__*/React.createElement(SurfaceProvider, null, /*#__PURE__*/React.createElement(RootComponent, null, /*#__PURE__*/React.createElement(Box, {
|
|
115
|
+
"aria-label": intl.formatMessage(surface.listLabel),
|
|
116
|
+
id: listId,
|
|
117
|
+
role: "listbox"
|
|
118
|
+
}, model.items.map((registration, itemIndex) => /*#__PURE__*/React.createElement(TypeAheadItemRow, {
|
|
119
|
+
isSelected: selectedItemIndex === itemIndex,
|
|
120
|
+
itemIndex: itemIndex,
|
|
121
|
+
Item: surface.Item,
|
|
122
|
+
key: `${registration.type}:${registration.key}`,
|
|
123
|
+
listId: listId,
|
|
124
|
+
onItemHover: setSelectedItemIndex,
|
|
125
|
+
registration: registration
|
|
126
|
+
})))))))));
|
|
127
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React, { useCallback } from 'react';
|
|
2
|
+
import { getTypeAheadItemId } from './getTypeAheadItemId';
|
|
3
|
+
export const TypeAheadItemRow = ({
|
|
4
|
+
isSelected,
|
|
5
|
+
itemIndex,
|
|
6
|
+
Item,
|
|
7
|
+
listId,
|
|
8
|
+
onItemHover,
|
|
9
|
+
registration
|
|
10
|
+
}) => {
|
|
11
|
+
const onMouseMove = useCallback(() => onItemHover(itemIndex), [itemIndex, onItemHover]);
|
|
12
|
+
return /*#__PURE__*/React.createElement(Item, {
|
|
13
|
+
id: getTypeAheadItemId(listId, itemIndex),
|
|
14
|
+
isSelected: isSelected,
|
|
15
|
+
onMouseMove: onMouseMove,
|
|
16
|
+
registration: registration
|
|
17
|
+
});
|
|
18
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { resolveSurface, willComponentRender } from '@atlaskit/editor-ui-control-model/surface-renderer';
|
|
2
|
+
export const buildTypeAheadMenuModel = (components, rootComponent) => {
|
|
3
|
+
const {
|
|
4
|
+
root,
|
|
5
|
+
childrenMap,
|
|
6
|
+
topLevelChildren
|
|
7
|
+
} = resolveSurface(components, rootComponent);
|
|
8
|
+
const items = [];
|
|
9
|
+
for (const section of topLevelChildren !== null && topLevelChildren !== void 0 ? topLevelChildren : []) {
|
|
10
|
+
if (section.type !== 'menu-section' || !willComponentRender(section, childrenMap)) {
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
for (const child of (_childrenMap$get = childrenMap.get(section.key)) !== null && _childrenMap$get !== void 0 ? _childrenMap$get : []) {
|
|
14
|
+
var _childrenMap$get;
|
|
15
|
+
if (child.type === 'menu-item' && willComponentRender(child, childrenMap)) {
|
|
16
|
+
items.push(child);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
items,
|
|
22
|
+
root
|
|
23
|
+
};
|
|
24
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const getTypeAheadItemId = (listId, itemIndex) => `${listId}--${itemIndex}`;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
|
+
import { QuickInsertProvider } from '@atlaskit/editor-common/quick-insert/provider';
|
|
3
|
+
import { useQuickInsertContext } from '@atlaskit/editor-common/quick-insert/use-quick-insert-context';
|
|
4
|
+
import { PassThrough } from '../PassThrough';
|
|
5
|
+
export const TypeAheadQuickInsertItem = ({
|
|
6
|
+
id,
|
|
7
|
+
isSelected,
|
|
8
|
+
onMouseMove,
|
|
9
|
+
registration
|
|
10
|
+
}) => {
|
|
11
|
+
var _registration$compone;
|
|
12
|
+
const quickInsertContext = useQuickInsertContext();
|
|
13
|
+
const Component = (_registration$compone = registration.component) !== null && _registration$compone !== void 0 ? _registration$compone : PassThrough;
|
|
14
|
+
const contextValue = useMemo(() => ({
|
|
15
|
+
...quickInsertContext,
|
|
16
|
+
item: {
|
|
17
|
+
id,
|
|
18
|
+
isSelected,
|
|
19
|
+
onMouseMove
|
|
20
|
+
}
|
|
21
|
+
}), [id, isSelected, onMouseMove, quickInsertContext]);
|
|
22
|
+
return /*#__PURE__*/React.createElement(QuickInsertProvider, {
|
|
23
|
+
value: contextValue
|
|
24
|
+
}, /*#__PURE__*/React.createElement(Component, null, null));
|
|
25
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React, { useCallback, useMemo } from 'react';
|
|
2
|
+
import { QuickInsertProvider } from '@atlaskit/editor-common/quick-insert/provider';
|
|
3
|
+
import { performTypeAheadSelection } from '../../../pm-plugins/commands/insert-type-ahead-item';
|
|
4
|
+
import { useTypeAheadContext } from '../useTypeAheadContext';
|
|
5
|
+
export const TypeAheadQuickInsertProvider = ({
|
|
6
|
+
children
|
|
7
|
+
}) => {
|
|
8
|
+
const {
|
|
9
|
+
editorView,
|
|
10
|
+
inputMethod,
|
|
11
|
+
onClose,
|
|
12
|
+
query,
|
|
13
|
+
triggerHandler
|
|
14
|
+
} = useTypeAheadContext();
|
|
15
|
+
const select = useCallback(selectionHandler => {
|
|
16
|
+
onClose();
|
|
17
|
+
queueMicrotask(() => {
|
|
18
|
+
performTypeAheadSelection(editorView)({
|
|
19
|
+
handler: triggerHandler,
|
|
20
|
+
inputMethod,
|
|
21
|
+
query,
|
|
22
|
+
selectionHandler
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
}, [editorView, inputMethod, onClose, query, triggerHandler]);
|
|
26
|
+
const contextValue = useMemo(() => ({
|
|
27
|
+
editorView,
|
|
28
|
+
select
|
|
29
|
+
}), [editorView, select]);
|
|
30
|
+
return /*#__PURE__*/React.createElement(QuickInsertProvider, {
|
|
31
|
+
value: contextValue
|
|
32
|
+
}, children);
|
|
33
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { INPUT_METHOD } from '@atlaskit/editor-common/analytics';
|
|
2
|
+
import { MENU } from '@atlaskit/editor-common/quick-insert/keys';
|
|
3
|
+
import { TypeAheadAvailableNodes, typeAheadListMessages } from '@atlaskit/editor-common/type-ahead';
|
|
4
|
+
import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
|
|
5
|
+
import { TypeAheadQuickInsertItem } from './quick-insert/TypeAheadQuickInsertItem';
|
|
6
|
+
import { TypeAheadQuickInsertProvider } from './quick-insert/TypeAheadQuickInsertProvider';
|
|
7
|
+
const quickInsertSurface = {
|
|
8
|
+
inputMethod: INPUT_METHOD.QUICK_INSERT,
|
|
9
|
+
Item: TypeAheadQuickInsertItem,
|
|
10
|
+
listIdPrefix: 'quick-insert-menu',
|
|
11
|
+
listLabel: typeAheadListMessages.quickInsertInputLabel,
|
|
12
|
+
Provider: TypeAheadQuickInsertProvider,
|
|
13
|
+
root: MENU
|
|
14
|
+
};
|
|
15
|
+
export const getTypeAheadSurface = id => {
|
|
16
|
+
if (id === TypeAheadAvailableNodes.QUICK_INSERT && isExperimentEnabled('platform_editor_slash_command')) {
|
|
17
|
+
return quickInsertSurface;
|
|
18
|
+
}
|
|
19
|
+
return undefined;
|
|
20
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { useContext } from 'react';
|
|
2
|
+
import { TypeAheadContext } from './TypeAheadContext';
|
|
3
|
+
export const useTypeAheadContext = () => {
|
|
4
|
+
const value = useContext(TypeAheadContext);
|
|
5
|
+
if (!value) {
|
|
6
|
+
throw new Error('useTypeAheadContext must be used within TypeAheadProvider');
|
|
7
|
+
}
|
|
8
|
+
return value;
|
|
9
|
+
};
|