@atlaskit/editor-plugin-type-ahead 10.2.2 → 10.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/commands/package.json +17 -0
- package/dist/cjs/entry-points/commands.js +18 -0
- package/dist/cjs/pm-plugins/commands/open-typeahead-at-cursor.js +7 -2
- package/dist/cjs/pm-plugins/commands/update-list-items.js +3 -1
- package/dist/cjs/pm-plugins/main.js +54 -0
- package/dist/cjs/pm-plugins/reducer.js +7 -1
- package/dist/cjs/typeAheadPlugin.js +3 -1
- package/dist/cjs/ui/ContentComponent.js +10 -7
- package/dist/cjs/ui/TypeAheadList.js +126 -52
- package/dist/cjs/ui/TypeAheadMenu.js +3 -0
- package/dist/cjs/ui/TypeAheadPopup.js +3 -0
- package/dist/cjs/ui/WrapperTypeAhead.js +3 -1
- package/dist/cjs/ui/hooks/build-sectioned-result.js +131 -0
- package/dist/cjs/ui/hooks/use-load-items.js +12 -4
- package/dist/es2019/entry-points/commands.js +2 -0
- package/dist/es2019/pm-plugins/commands/open-typeahead-at-cursor.js +7 -2
- package/dist/es2019/pm-plugins/commands/update-list-items.js +3 -2
- package/dist/es2019/pm-plugins/main.js +54 -0
- package/dist/es2019/pm-plugins/reducer.js +6 -1
- package/dist/es2019/typeAheadPlugin.js +3 -1
- package/dist/es2019/ui/ContentComponent.js +10 -7
- package/dist/es2019/ui/TypeAheadList.js +85 -23
- package/dist/es2019/ui/TypeAheadMenu.js +2 -0
- package/dist/es2019/ui/TypeAheadPopup.js +2 -0
- package/dist/es2019/ui/WrapperTypeAhead.js +3 -1
- package/dist/es2019/ui/hooks/build-sectioned-result.js +83 -0
- package/dist/es2019/ui/hooks/use-load-items.js +13 -4
- package/dist/esm/entry-points/commands.js +2 -0
- package/dist/esm/pm-plugins/commands/open-typeahead-at-cursor.js +7 -2
- package/dist/esm/pm-plugins/commands/update-list-items.js +3 -1
- package/dist/esm/pm-plugins/main.js +54 -0
- package/dist/esm/pm-plugins/reducer.js +7 -1
- package/dist/esm/typeAheadPlugin.js +3 -1
- package/dist/esm/ui/ContentComponent.js +10 -7
- package/dist/esm/ui/TypeAheadList.js +126 -52
- package/dist/esm/ui/TypeAheadMenu.js +3 -0
- package/dist/esm/ui/TypeAheadPopup.js +3 -0
- package/dist/esm/ui/WrapperTypeAhead.js +3 -1
- package/dist/esm/ui/hooks/build-sectioned-result.js +124 -0
- package/dist/esm/ui/hooks/use-load-items.js +12 -4
- package/dist/types/entry-points/commands.d.ts +1 -0
- package/dist/types/pm-plugins/commands/update-list-items.d.ts +2 -1
- package/dist/types/types/index.d.ts +8 -0
- package/dist/types/ui/TypeAheadList.d.ts +3 -1
- package/dist/types/ui/TypeAheadPopup.d.ts +3 -2
- package/dist/types/ui/hooks/build-sectioned-result.d.ts +11 -0
- package/dist/types/ui/hooks/use-load-items.d.ts +2 -1
- package/dist/types-ts4.5/entry-points/commands.d.ts +1 -0
- package/dist/types-ts4.5/pm-plugins/commands/update-list-items.d.ts +2 -1
- package/dist/types-ts4.5/types/index.d.ts +8 -0
- package/dist/types-ts4.5/ui/TypeAheadList.d.ts +3 -1
- package/dist/types-ts4.5/ui/TypeAheadPopup.d.ts +3 -2
- package/dist/types-ts4.5/ui/hooks/build-sectioned-result.d.ts +11 -0
- package/dist/types-ts4.5/ui/hooks/use-load-items.d.ts +2 -1
- package/package.json +5 -5
|
@@ -70,6 +70,8 @@ var TypeAheadPopup = exports.TypeAheadPopup = /*#__PURE__*/_react.default.memo(f
|
|
|
70
70
|
popupsBoundariesElement = props.popupsBoundariesElement,
|
|
71
71
|
popupsScrollableElement = props.popupsScrollableElement,
|
|
72
72
|
items = props.items,
|
|
73
|
+
_props$sections = props.sections,
|
|
74
|
+
sections = _props$sections === void 0 ? [] : _props$sections,
|
|
73
75
|
emptyItem = props.emptyItem,
|
|
74
76
|
errorInfo = props.errorInfo,
|
|
75
77
|
selectedIndex = props.selectedIndex,
|
|
@@ -345,6 +347,7 @@ var TypeAheadPopup = exports.TypeAheadPopup = /*#__PURE__*/_react.default.memo(f
|
|
|
345
347
|
triggerHandler: triggerHandler
|
|
346
348
|
}), (0, _react2.jsx)(_TypeAheadList.TypeAheadList, {
|
|
347
349
|
items: items,
|
|
350
|
+
sections: sections,
|
|
348
351
|
emptyItem: emptyItem,
|
|
349
352
|
selectedIndex: selectedIndex
|
|
350
353
|
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
|
|
@@ -8,6 +8,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
8
8
|
exports.WrapperTypeAhead = void 0;
|
|
9
9
|
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
10
10
|
var _react = _interopRequireWildcard(require("react"));
|
|
11
|
+
var _reactIntl = require("react-intl");
|
|
11
12
|
var _analytics = require("@atlaskit/editor-common/analytics");
|
|
12
13
|
var _typeAhead = require("@atlaskit/editor-common/type-ahead");
|
|
13
14
|
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
@@ -40,6 +41,7 @@ var WrapperTypeAhead = exports.WrapperTypeAhead = /*#__PURE__*/_react.default.me
|
|
|
40
41
|
if ((0, _experiments.editorExperiment)('platform_editor_controls', 'variant1')) {
|
|
41
42
|
showMoreOptionsButton = !!(triggerHandler !== null && triggerHandler !== void 0 && triggerHandler.getMoreOptionsButtonConfig);
|
|
42
43
|
}
|
|
44
|
+
var intl = (0, _reactIntl.useIntl)();
|
|
43
45
|
var _useState = (0, _react.useState)(false),
|
|
44
46
|
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
|
|
45
47
|
closed = _useState2[0],
|
|
@@ -50,7 +52,7 @@ var WrapperTypeAhead = exports.WrapperTypeAhead = /*#__PURE__*/_react.default.me
|
|
|
50
52
|
setQuery = _useState4[1];
|
|
51
53
|
var queryRef = (0, _react.useRef)(query);
|
|
52
54
|
var editorViewRef = (0, _react.useRef)(editorView);
|
|
53
|
-
var items = (0, _useLoadItems.useLoadItems)(triggerHandler, editorView, query, showMoreOptionsButton, api);
|
|
55
|
+
var items = (0, _useLoadItems.useLoadItems)(triggerHandler, editorView, query, showMoreOptionsButton, api, intl);
|
|
54
56
|
(0, _react.useEffect)(function () {
|
|
55
57
|
if (!closed && (0, _platformFeatureFlags.fg)('platform_editor_ease_of_use_metrics')) {
|
|
56
58
|
var _api$metrics;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.buildSectionedResult = void 0;
|
|
8
|
+
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
9
|
+
var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
|
|
10
|
+
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
|
|
11
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
12
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
13
|
+
var buildSectionedResult = exports.buildSectionedResult = function buildSectionedResult(_ref) {
|
|
14
|
+
var _triggerHandler$getSe;
|
|
15
|
+
var items = _ref.items,
|
|
16
|
+
triggerHandler = _ref.triggerHandler,
|
|
17
|
+
intl = _ref.intl;
|
|
18
|
+
if (!(0, _experiments.editorExperiment)('platform_editor_agent_mentions', true) || !intl) {
|
|
19
|
+
return {
|
|
20
|
+
items: items,
|
|
21
|
+
sections: []
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
var sectionDefinitions = (_triggerHandler$getSe = triggerHandler.getSections) === null || _triggerHandler$getSe === void 0 ? void 0 : _triggerHandler$getSe.call(triggerHandler, {
|
|
25
|
+
intl: intl
|
|
26
|
+
});
|
|
27
|
+
if (!sectionDefinitions || sectionDefinitions.length === 0) {
|
|
28
|
+
return {
|
|
29
|
+
items: items,
|
|
30
|
+
sections: []
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Track which item indexes have been claimed by a section, or excluded (matched a section but
|
|
35
|
+
// cut by that section's limit). Items excluded by limit should not appear anywhere in the output.
|
|
36
|
+
var assignedToSection = new Set();
|
|
37
|
+
var excludedByLimit = new Set();
|
|
38
|
+
var groupedBySection = new Map();
|
|
39
|
+
var _iterator = _createForOfIteratorHelper(sectionDefinitions),
|
|
40
|
+
_step;
|
|
41
|
+
try {
|
|
42
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
43
|
+
var section = _step.value;
|
|
44
|
+
var matchingIndexes = [];
|
|
45
|
+
for (var _i = 0; _i < items.length; _i++) {
|
|
46
|
+
if (assignedToSection.has(_i) || excludedByLimit.has(_i)) {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (section.filter(items[_i])) {
|
|
50
|
+
matchingIndexes.push(_i);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
var acceptedIndexes = section.limit !== undefined ? matchingIndexes.slice(0, section.limit) : matchingIndexes;
|
|
54
|
+
var rejectedByLimit = matchingIndexes.slice(acceptedIndexes.length);
|
|
55
|
+
var _iterator3 = _createForOfIteratorHelper(acceptedIndexes),
|
|
56
|
+
_step3;
|
|
57
|
+
try {
|
|
58
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
59
|
+
var _i2 = _step3.value;
|
|
60
|
+
assignedToSection.add(_i2);
|
|
61
|
+
}
|
|
62
|
+
} catch (err) {
|
|
63
|
+
_iterator3.e(err);
|
|
64
|
+
} finally {
|
|
65
|
+
_iterator3.f();
|
|
66
|
+
}
|
|
67
|
+
var _iterator4 = _createForOfIteratorHelper(rejectedByLimit),
|
|
68
|
+
_step4;
|
|
69
|
+
try {
|
|
70
|
+
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
71
|
+
var _i3 = _step4.value;
|
|
72
|
+
excludedByLimit.add(_i3);
|
|
73
|
+
}
|
|
74
|
+
} catch (err) {
|
|
75
|
+
_iterator4.e(err);
|
|
76
|
+
} finally {
|
|
77
|
+
_iterator4.f();
|
|
78
|
+
}
|
|
79
|
+
if (acceptedIndexes.length === 0) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
groupedBySection.set(section.id, {
|
|
83
|
+
indexes: acceptedIndexes,
|
|
84
|
+
section: section
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
} catch (err) {
|
|
88
|
+
_iterator.e(err);
|
|
89
|
+
} finally {
|
|
90
|
+
_iterator.f();
|
|
91
|
+
}
|
|
92
|
+
var flattenedItems = [];
|
|
93
|
+
var sections = [];
|
|
94
|
+
var _iterator2 = _createForOfIteratorHelper(sectionDefinitions),
|
|
95
|
+
_step2;
|
|
96
|
+
try {
|
|
97
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
98
|
+
var _section = _step2.value;
|
|
99
|
+
var grouped = groupedBySection.get(_section.id);
|
|
100
|
+
if (!grouped) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
var startIndex = flattenedItems.length;
|
|
104
|
+
flattenedItems.push.apply(flattenedItems, (0, _toConsumableArray2.default)(grouped.indexes.map(function (i) {
|
|
105
|
+
return items[i];
|
|
106
|
+
})));
|
|
107
|
+
var endIndex = flattenedItems.length - 1;
|
|
108
|
+
sections.push({
|
|
109
|
+
endIndex: endIndex,
|
|
110
|
+
id: _section.id,
|
|
111
|
+
startIndex: startIndex,
|
|
112
|
+
title: _section.title
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Append items not claimed by any section and not excluded by a limit
|
|
117
|
+
} catch (err) {
|
|
118
|
+
_iterator2.e(err);
|
|
119
|
+
} finally {
|
|
120
|
+
_iterator2.f();
|
|
121
|
+
}
|
|
122
|
+
for (var i = 0; i < items.length; i++) {
|
|
123
|
+
if (!assignedToSection.has(i) && !excludedByLimit.has(i)) {
|
|
124
|
+
flattenedItems.push(items[i]);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return {
|
|
128
|
+
items: flattenedItems,
|
|
129
|
+
sections: sections
|
|
130
|
+
};
|
|
131
|
+
};
|
|
@@ -12,8 +12,9 @@ var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
|
|
|
12
12
|
var _clearListError = require("../../pm-plugins/commands/clear-list-error");
|
|
13
13
|
var _updateListError = require("../../pm-plugins/commands/update-list-error");
|
|
14
14
|
var _updateListItems = require("../../pm-plugins/commands/update-list-items");
|
|
15
|
+
var _buildSectionedResult2 = require("./build-sectioned-result");
|
|
15
16
|
var EMPTY_LIST_ITEM = [];
|
|
16
|
-
var useLoadItems = exports.useLoadItems = function useLoadItems(triggerHandler, editorView, query, showViewMore, api) {
|
|
17
|
+
var useLoadItems = exports.useLoadItems = function useLoadItems(triggerHandler, editorView, query, showViewMore, api, intl) {
|
|
17
18
|
var _useState = (0, _react.useState)(EMPTY_LIST_ITEM),
|
|
18
19
|
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
|
|
19
20
|
items = _useState2[0],
|
|
@@ -44,7 +45,14 @@ var useLoadItems = exports.useLoadItems = function useLoadItems(triggerHandler,
|
|
|
44
45
|
var emptyItem = result.length === 0 && (0, _expValEquals.expValEquals)('platform_editor_insert_menu_ai', 'isEnabled', true) ? (_triggerHandler$getEm = triggerHandler.getEmptyItem) === null || _triggerHandler$getEm === void 0 ? void 0 : _triggerHandler$getEm.call(triggerHandler, {
|
|
45
46
|
editorState: editorView.state
|
|
46
47
|
}) : undefined;
|
|
47
|
-
var
|
|
48
|
+
var rawList = result.length > 0 ? result : emptyItem ? [emptyItem] : EMPTY_LIST_ITEM;
|
|
49
|
+
var _buildSectionedResult = (0, _buildSectionedResult2.buildSectionedResult)({
|
|
50
|
+
items: rawList,
|
|
51
|
+
triggerHandler: triggerHandler,
|
|
52
|
+
intl: intl !== null && intl !== void 0 ? intl : null
|
|
53
|
+
}),
|
|
54
|
+
list = _buildSectionedResult.items,
|
|
55
|
+
sections = _buildSectionedResult.sections;
|
|
48
56
|
if (componentIsMounted.current) {
|
|
49
57
|
setItems(list);
|
|
50
58
|
}
|
|
@@ -54,7 +62,7 @@ var useLoadItems = exports.useLoadItems = function useLoadItems(triggerHandler,
|
|
|
54
62
|
title: 'View more'
|
|
55
63
|
};
|
|
56
64
|
queueMicrotask(function () {
|
|
57
|
-
(0, _updateListItems.updateListItem)(showViewMore ? list.concat(viewMoreItem) : list)(view.state, view.dispatch);
|
|
65
|
+
(0, _updateListItems.updateListItem)(showViewMore ? list.concat(viewMoreItem) : list, sections)(view.state, view.dispatch);
|
|
58
66
|
});
|
|
59
67
|
}).catch(function (e) {
|
|
60
68
|
if ((0, _experiments.editorExperiment)('platform_editor_offline_editing_web', true)) {
|
|
@@ -72,7 +80,7 @@ var useLoadItems = exports.useLoadItems = function useLoadItems(triggerHandler,
|
|
|
72
80
|
// ignore because EditorView is mutable but we don't want to
|
|
73
81
|
// call loadItems when it changes, only when the query changes
|
|
74
82
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
75
|
-
}, [triggerHandler, query]);
|
|
83
|
+
}, [triggerHandler, query, intl]);
|
|
76
84
|
(0, _react.useEffect)(function () {
|
|
77
85
|
return function () {
|
|
78
86
|
componentIsMounted.current = false;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { GapCursorSelection } from '@atlaskit/editor-common/selection';
|
|
2
2
|
import { NodeSelection, TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
3
|
+
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
3
4
|
import { ACTIONS } from '../actions';
|
|
4
5
|
import { pluginKey } from '../key';
|
|
5
6
|
export const openTypeAhead = props => tr => {
|
|
@@ -46,7 +47,7 @@ export const openTypeAheadAtCursor = ({
|
|
|
46
47
|
// delete 1 pos before wherever selection is now - that will delete the empty space
|
|
47
48
|
tr.delete(tr.selection.from - 1, tr.selection.from);
|
|
48
49
|
} else {
|
|
49
|
-
var _selection$$head, _selection$$head$
|
|
50
|
+
var _selection$$head$pare, _selection$$head$pare2, _selection$$head, _selection$$head$pare3;
|
|
50
51
|
if (selection instanceof NodeSelection) {
|
|
51
52
|
if (isInline) {
|
|
52
53
|
tr.deleteSelection();
|
|
@@ -75,7 +76,11 @@ export const openTypeAheadAtCursor = ({
|
|
|
75
76
|
// being inserted due to composition by checking if we have the trigger
|
|
76
77
|
// directly before the typeahead. This should not happen unless it has
|
|
77
78
|
// been eroneously added because we require whitespace/newline for typeahead.
|
|
78
|
-
|
|
79
|
+
// Check if the text ends with the trigger character (or any character matched
|
|
80
|
+
// by customRegex, to support wide-char variants like fullwidth slash /)
|
|
81
|
+
const triggerPattern = expValEquals('platform_editor_wide_slash_trigger', 'isEnabled', true) && triggerHandler.customRegex ? new RegExp(`(${triggerHandler.customRegex})$`, 'u') : null;
|
|
82
|
+
const endsWithTrigger = ((_selection$$head$pare = (_selection$$head$pare2 = selection.$head.parent.textContent).endsWith) === null || _selection$$head$pare === void 0 ? void 0 : _selection$$head$pare.call(_selection$$head$pare2, triggerHandler.trigger)) || triggerPattern && triggerPattern.test(selection.$head.parent.textContent);
|
|
83
|
+
if (cursorPos >= 2 && !!(selection !== null && selection !== void 0 && (_selection$$head = selection.$head) !== null && _selection$$head !== void 0 && (_selection$$head$pare3 = _selection$$head.parent) !== null && _selection$$head$pare3 !== void 0 && _selection$$head$pare3.textContent) && endsWithTrigger) {
|
|
79
84
|
tr.delete(cursorPos - 1, cursorPos);
|
|
80
85
|
}
|
|
81
86
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { ACTIONS } from '../actions';
|
|
2
2
|
import { pluginKey as typeAheadPluginKey } from '../key';
|
|
3
|
-
export const updateListItem = items => {
|
|
3
|
+
export const updateListItem = (items, sections = []) => {
|
|
4
4
|
return (state, dispatch) => {
|
|
5
5
|
const tr = state.tr;
|
|
6
6
|
tr.setMeta(typeAheadPluginKey, {
|
|
7
7
|
action: ACTIONS.UPDATE_LIST_ITEMS,
|
|
8
8
|
params: {
|
|
9
|
-
items
|
|
9
|
+
items,
|
|
10
|
+
sections
|
|
10
11
|
}
|
|
11
12
|
});
|
|
12
13
|
if (dispatch) {
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { InsertTypeAheadStep } from '@atlaskit/adf-schema/steps';
|
|
2
|
+
import { INPUT_METHOD } from '@atlaskit/editor-common/analytics';
|
|
2
3
|
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
3
4
|
import { closest } from '@atlaskit/editor-common/utils';
|
|
4
5
|
import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
|
|
5
6
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
7
|
+
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
6
8
|
import { ACTIONS } from './actions';
|
|
9
|
+
import { openTypeAheadAtCursor } from './commands/open-typeahead-at-cursor';
|
|
7
10
|
import { TYPE_AHEAD_DECORATION_DATA_ATTRIBUTE } from './constants';
|
|
8
11
|
import { factoryDecorations } from './decorations';
|
|
9
12
|
import { isInsertionTransaction } from './isInsertionTransaction';
|
|
@@ -43,6 +46,11 @@ export function createPlugin({
|
|
|
43
46
|
typeAheadHandlers,
|
|
44
47
|
popupMountRef
|
|
45
48
|
});
|
|
49
|
+
|
|
50
|
+
// Tracks a wide-char trigger handler detected during IME composition (e.g. /).
|
|
51
|
+
// Set by compositionupdate, cleared by compositionend. Used by handleKeyDown
|
|
52
|
+
// to intercept Enter that confirms the composition.
|
|
53
|
+
let pendingWideSlashHandler = null;
|
|
46
54
|
return new SafePlugin({
|
|
47
55
|
key: pluginKey,
|
|
48
56
|
state: {
|
|
@@ -53,6 +61,7 @@ export function createPlugin({
|
|
|
53
61
|
decorationSet: DecorationSet.empty,
|
|
54
62
|
decorationElement: null,
|
|
55
63
|
items: [],
|
|
64
|
+
sections: [],
|
|
56
65
|
errorInfo: null,
|
|
57
66
|
selectedIndex: -1,
|
|
58
67
|
stats: null,
|
|
@@ -94,8 +103,53 @@ export function createPlugin({
|
|
|
94
103
|
var _pluginKey$getState;
|
|
95
104
|
return (_pluginKey$getState = pluginKey.getState(state)) === null || _pluginKey$getState === void 0 ? void 0 : _pluginKey$getState.decorationSet;
|
|
96
105
|
},
|
|
106
|
+
handleKeyDown: (view, event) => {
|
|
107
|
+
// When composing a wide-char trigger (e.g. /), intercept the Enter key
|
|
108
|
+
// that confirms the composition so we can open the typeahead instead.
|
|
109
|
+
if (pendingWideSlashHandler && event.isComposing && (event.key === 'Enter' || event.keyCode === 13)) {
|
|
110
|
+
const handler = pendingWideSlashHandler;
|
|
111
|
+
pendingWideSlashHandler = null;
|
|
112
|
+
// Defer until ProseMirror has flushed the composed text into its state.
|
|
113
|
+
setTimeout(() => {
|
|
114
|
+
const command = openTypeAheadAtCursor({
|
|
115
|
+
triggerHandler: handler,
|
|
116
|
+
inputMethod: INPUT_METHOD.KEYBOARD
|
|
117
|
+
});
|
|
118
|
+
const tr = command({
|
|
119
|
+
tr: view.state.tr
|
|
120
|
+
});
|
|
121
|
+
if (tr) {
|
|
122
|
+
view.dispatch(tr);
|
|
123
|
+
}
|
|
124
|
+
}, 0);
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
return false;
|
|
128
|
+
},
|
|
97
129
|
handleDOMEvents: {
|
|
130
|
+
compositionupdate: (view, event) => {
|
|
131
|
+
// When the experiment is on, track whether the current composition
|
|
132
|
+
// exactly matches a wide-char trigger (e.g. / from Japanese keyboard).
|
|
133
|
+
// We can't open the typeahead yet because composition is still active,
|
|
134
|
+
// but we record the matching handler so the next keydown (Enter) can use it.
|
|
135
|
+
if (expValEquals('platform_editor_wide_slash_trigger', 'isEnabled', true)) {
|
|
136
|
+
var _event$data, _typeAheadHandlers$fi;
|
|
137
|
+
const pendingData = (_event$data = event.data) !== null && _event$data !== void 0 ? _event$data : '';
|
|
138
|
+
pendingWideSlashHandler = (_typeAheadHandlers$fi = typeAheadHandlers.find(handler => {
|
|
139
|
+
if (!handler.customRegex) {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
// Only match if the entire composition is a trigger character
|
|
143
|
+
const pattern = new RegExp(`^(${handler.customRegex})$`, 'u');
|
|
144
|
+
return pattern.test(pendingData);
|
|
145
|
+
})) !== null && _typeAheadHandlers$fi !== void 0 ? _typeAheadHandlers$fi : null;
|
|
146
|
+
}
|
|
147
|
+
return false;
|
|
148
|
+
},
|
|
98
149
|
compositionend: (view, event) => {
|
|
150
|
+
// Clear the pending handler when composition ends (cancelled or committed
|
|
151
|
+
// via a non-Enter key like Space, which we don't want to intercept).
|
|
152
|
+
pendingWideSlashHandler = null;
|
|
99
153
|
return false;
|
|
100
154
|
},
|
|
101
155
|
click: (view, event) => {
|
|
@@ -66,6 +66,7 @@ export const createReducer = ({
|
|
|
66
66
|
inputMethod,
|
|
67
67
|
selectedIndex: typeof selectedIndex === 'number' ? selectedIndex : -1,
|
|
68
68
|
items: [],
|
|
69
|
+
sections: [],
|
|
69
70
|
query: reopenQuery || '',
|
|
70
71
|
removePrefixTriggerOnCancel
|
|
71
72
|
};
|
|
@@ -85,6 +86,7 @@ export const createReducer = ({
|
|
|
85
86
|
stats: null,
|
|
86
87
|
triggerHandler: undefined,
|
|
87
88
|
items: [],
|
|
89
|
+
sections: [],
|
|
88
90
|
removePrefixTriggerOnCancel: undefined
|
|
89
91
|
};
|
|
90
92
|
};
|
|
@@ -140,11 +142,13 @@ export const createReducer = ({
|
|
|
140
142
|
...currentPluginState,
|
|
141
143
|
errorInfo,
|
|
142
144
|
items: [],
|
|
145
|
+
sections: [],
|
|
143
146
|
selectedIndex: -1
|
|
144
147
|
};
|
|
145
148
|
} else if (shouldUpdateListItems) {
|
|
146
149
|
const {
|
|
147
|
-
items
|
|
150
|
+
items,
|
|
151
|
+
sections = []
|
|
148
152
|
} = params;
|
|
149
153
|
const {
|
|
150
154
|
selectedIndex
|
|
@@ -152,6 +156,7 @@ export const createReducer = ({
|
|
|
152
156
|
return {
|
|
153
157
|
...currentPluginState,
|
|
154
158
|
items,
|
|
159
|
+
sections,
|
|
155
160
|
selectedIndex: Math.max(selectedIndex >= items.length ? items.length - 1 : selectedIndex, -1)
|
|
156
161
|
};
|
|
157
162
|
} else if (shouldUpdateSelectedIndex) {
|
|
@@ -208,7 +208,7 @@ export const typeAheadPlugin = ({
|
|
|
208
208
|
}];
|
|
209
209
|
},
|
|
210
210
|
getSharedState(editorState) {
|
|
211
|
-
var _state$decorationSet, _state$decorationElem, _state$items, _state$errorInfo, _state$selectedIndex;
|
|
211
|
+
var _state$decorationSet, _state$decorationElem, _state$items, _state$sections, _state$errorInfo, _state$selectedIndex;
|
|
212
212
|
if (!editorState) {
|
|
213
213
|
return {
|
|
214
214
|
query: '',
|
|
@@ -219,6 +219,7 @@ export const typeAheadPlugin = ({
|
|
|
219
219
|
decorationElement: null,
|
|
220
220
|
triggerHandler: undefined,
|
|
221
221
|
items: [],
|
|
222
|
+
sections: [],
|
|
222
223
|
errorInfo: null,
|
|
223
224
|
selectedIndex: 0
|
|
224
225
|
};
|
|
@@ -234,6 +235,7 @@ export const typeAheadPlugin = ({
|
|
|
234
235
|
decorationElement: (_state$decorationElem = state === null || state === void 0 ? void 0 : state.decorationElement) !== null && _state$decorationElem !== void 0 ? _state$decorationElem : null,
|
|
235
236
|
triggerHandler: state === null || state === void 0 ? void 0 : state.triggerHandler,
|
|
236
237
|
items: (_state$items = state === null || state === void 0 ? void 0 : state.items) !== null && _state$items !== void 0 ? _state$items : [],
|
|
238
|
+
sections: (_state$sections = state === null || state === void 0 ? void 0 : state.sections) !== null && _state$sections !== void 0 ? _state$sections : [],
|
|
237
239
|
errorInfo: (_state$errorInfo = state === null || state === void 0 ? void 0 : state.errorInfo) !== null && _state$errorInfo !== void 0 ? _state$errorInfo : null,
|
|
238
240
|
selectedIndex: (_state$selectedIndex = state === null || state === void 0 ? void 0 : state.selectedIndex) !== null && _state$selectedIndex !== void 0 ? _state$selectedIndex : 0
|
|
239
241
|
};
|
|
@@ -9,24 +9,26 @@ export function ContentComponent({
|
|
|
9
9
|
const {
|
|
10
10
|
triggerHandler,
|
|
11
11
|
items,
|
|
12
|
+
sections,
|
|
12
13
|
errorInfo,
|
|
13
14
|
decorationElement,
|
|
14
15
|
decorationSet,
|
|
15
16
|
query,
|
|
16
17
|
selectedIndex
|
|
17
18
|
} = useSharedPluginStateWithSelector(api, ['typeAhead'], states => {
|
|
18
|
-
var _states$typeAheadStat, _states$typeAheadStat2, _states$typeAheadStat3, _states$typeAheadStat4, _states$typeAheadStat5, _states$typeAheadStat6, _states$typeAheadStat7;
|
|
19
|
+
var _states$typeAheadStat, _states$typeAheadStat2, _states$typeAheadStat3, _states$typeAheadStat4, _states$typeAheadStat5, _states$typeAheadStat6, _states$typeAheadStat7, _states$typeAheadStat8;
|
|
19
20
|
return {
|
|
20
21
|
triggerHandler: (_states$typeAheadStat = states.typeAheadState) === null || _states$typeAheadStat === void 0 ? void 0 : _states$typeAheadStat.triggerHandler,
|
|
21
22
|
items: (_states$typeAheadStat2 = states.typeAheadState) === null || _states$typeAheadStat2 === void 0 ? void 0 : _states$typeAheadStat2.items,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
sections: (_states$typeAheadStat3 = states.typeAheadState) === null || _states$typeAheadStat3 === void 0 ? void 0 : _states$typeAheadStat3.sections,
|
|
24
|
+
errorInfo: (_states$typeAheadStat4 = states.typeAheadState) === null || _states$typeAheadStat4 === void 0 ? void 0 : _states$typeAheadStat4.errorInfo,
|
|
25
|
+
decorationElement: (_states$typeAheadStat5 = states.typeAheadState) === null || _states$typeAheadStat5 === void 0 ? void 0 : _states$typeAheadStat5.decorationElement,
|
|
26
|
+
decorationSet: (_states$typeAheadStat6 = states.typeAheadState) === null || _states$typeAheadStat6 === void 0 ? void 0 : _states$typeAheadStat6.decorationSet,
|
|
27
|
+
query: (_states$typeAheadStat7 = states.typeAheadState) === null || _states$typeAheadStat7 === void 0 ? void 0 : _states$typeAheadStat7.query,
|
|
28
|
+
selectedIndex: (_states$typeAheadStat8 = states.typeAheadState) === null || _states$typeAheadStat8 === void 0 ? void 0 : _states$typeAheadStat8.selectedIndex
|
|
27
29
|
};
|
|
28
30
|
});
|
|
29
|
-
if (items === undefined || decorationSet === undefined || errorInfo === undefined || decorationElement === undefined || query === undefined || selectedIndex === undefined) {
|
|
31
|
+
if (items === undefined || sections === undefined || decorationSet === undefined || errorInfo === undefined || decorationElement === undefined || query === undefined || selectedIndex === undefined) {
|
|
30
32
|
return null;
|
|
31
33
|
}
|
|
32
34
|
return /*#__PURE__*/React.createElement(TypeAheadMenu, {
|
|
@@ -37,6 +39,7 @@ export function ContentComponent({
|
|
|
37
39
|
typeAheadState: {
|
|
38
40
|
triggerHandler,
|
|
39
41
|
items,
|
|
42
|
+
sections,
|
|
40
43
|
errorInfo,
|
|
41
44
|
decorationElement,
|
|
42
45
|
decorationSet,
|