@atlaskit/editor-plugin-type-ahead 15.0.4 → 15.1.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 +33 -0
- package/dist/cjs/ui/registered-menu/RegisteredTypeAheadMenu.js +6 -2
- package/dist/cjs/ui/registered-menu/getMatchingComponents.js +112 -0
- package/dist/cjs/ui/registered-menu/quick-insert/TypeAheadQuickInsertItem.js +1 -0
- package/dist/cjs/ui/registered-menu/quick-insert/TypeAheadQuickInsertProvider.js +12 -1
- package/dist/es2019/ui/registered-menu/RegisteredTypeAheadMenu.js +6 -1
- package/dist/es2019/ui/registered-menu/getMatchingComponents.js +72 -0
- package/dist/es2019/ui/registered-menu/quick-insert/TypeAheadQuickInsertItem.js +1 -0
- package/dist/es2019/ui/registered-menu/quick-insert/TypeAheadQuickInsertProvider.js +12 -1
- package/dist/esm/ui/registered-menu/RegisteredTypeAheadMenu.js +6 -2
- package/dist/esm/ui/registered-menu/getMatchingComponents.js +106 -0
- package/dist/esm/ui/registered-menu/quick-insert/TypeAheadQuickInsertItem.js +1 -0
- package/dist/esm/ui/registered-menu/quick-insert/TypeAheadQuickInsertProvider.js +12 -1
- package/dist/types/ui/registered-menu/getMatchingComponents.d.ts +9 -0
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-type-ahead
|
|
2
2
|
|
|
3
|
+
## 15.1.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`3a4c286fdb8c1`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/3a4c286fdb8c1) -
|
|
8
|
+
Add registry-backed Quick Insert search matching under the existing
|
|
9
|
+
`platform_editor_slash_command` experiment. Make native, provider, and extension registered Quick
|
|
10
|
+
Insert items searchable.
|
|
11
|
+
- Updated dependencies
|
|
12
|
+
|
|
13
|
+
## 15.1.0
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- [`c0cf420333ef1`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/c0cf420333ef1) -
|
|
18
|
+
Add public registration APIs for provider-backed Quick Insert components.
|
|
19
|
+
|
|
20
|
+
Providers can expose registered items directly:
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
const getComponents = async () => [
|
|
24
|
+
{
|
|
25
|
+
key: 'insert-table',
|
|
26
|
+
component: TableItem,
|
|
27
|
+
parents: [{ type: 'menu-section', key: 'quick-insert', rank: 1 }],
|
|
28
|
+
},
|
|
29
|
+
];
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Patch Changes
|
|
33
|
+
|
|
34
|
+
- Updated dependencies
|
|
35
|
+
|
|
3
36
|
## 15.0.4
|
|
4
37
|
|
|
5
38
|
### Patch Changes
|
|
@@ -11,12 +11,14 @@ require("./RegisteredTypeAheadMenu.compiled.css");
|
|
|
11
11
|
var _runtime = require("@compiled/react/runtime");
|
|
12
12
|
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
13
13
|
var _react = _interopRequireWildcard(require("react"));
|
|
14
|
+
var _reactIntl = require("react-intl");
|
|
14
15
|
var _typeAheadIsSectionOverflowItemKey = require("@atlaskit/editor-common/type-ahead-is-section-overflow-item-key");
|
|
15
16
|
var _ui = require("@atlaskit/editor-common/ui");
|
|
16
17
|
var _constants = require("@atlaskit/editor-shared-styles/constants");
|
|
17
18
|
var _compiled = require("@atlaskit/primitives/compiled");
|
|
18
19
|
var _InputQuery = require("../InputQuery");
|
|
19
20
|
var _buildTypeAheadMenuModel = require("./buildTypeAheadMenuModel");
|
|
21
|
+
var _getMatchingComponents = require("./getMatchingComponents");
|
|
20
22
|
var _getTypeAheadGlobalViewMoreId = require("./getTypeAheadGlobalViewMoreId");
|
|
21
23
|
var _getTypeAheadItemId = require("./getTypeAheadItemId");
|
|
22
24
|
var _TypeAheadMenuRenderer = require("./TypeAheadMenuRenderer");
|
|
@@ -46,6 +48,8 @@ var RegisteredTypeAheadMenu = exports.RegisteredTypeAheadMenu = function Registe
|
|
|
46
48
|
setQuery = _ref.setQuery,
|
|
47
49
|
surface = _ref.surface,
|
|
48
50
|
triggerHandler = _ref.triggerHandler;
|
|
51
|
+
var _useIntl = (0, _reactIntl.useIntl)(),
|
|
52
|
+
formatMessage = _useIntl.formatMessage;
|
|
49
53
|
var generatedId = (0, _react.useId)();
|
|
50
54
|
var listId = "".concat(surface.listIdPrefix, "-").concat(generatedId);
|
|
51
55
|
var menuRef = (0, _react.useRef)(null);
|
|
@@ -64,8 +68,8 @@ var RegisteredTypeAheadMenu = exports.RegisteredTypeAheadMenu = function Registe
|
|
|
64
68
|
});
|
|
65
69
|
}, [components]);
|
|
66
70
|
var menuModel = (0, _react.useMemo)(function () {
|
|
67
|
-
return (0, _buildTypeAheadMenuModel.buildTypeAheadMenuModel)(components, surface.root, hasSectionOverflowItems ? SECTION_OVERFLOW_LIMIT : undefined);
|
|
68
|
-
}, [components, hasSectionOverflowItems, surface.root]);
|
|
71
|
+
return query === '' ? (0, _buildTypeAheadMenuModel.buildTypeAheadMenuModel)(components, surface.root, hasSectionOverflowItems ? SECTION_OVERFLOW_LIMIT : undefined) : (0, _getMatchingComponents.getMatchingComponents)(components, surface.root, query, formatMessage);
|
|
72
|
+
}, [components, formatMessage, hasSectionOverflowItems, query, surface.root]);
|
|
69
73
|
var rows = (0, _react.useMemo)(function () {
|
|
70
74
|
return menuModel.sections.flat();
|
|
71
75
|
}, [menuModel.sections]);
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.getMatchingComponents = void 0;
|
|
7
|
+
var _typeAheadIsMenuFooterSectionKey = require("@atlaskit/editor-common/type-ahead-is-menu-footer-section-key");
|
|
8
|
+
var _typeAheadIsSectionOverflowItemKey = require("@atlaskit/editor-common/type-ahead-is-section-overflow-item-key");
|
|
9
|
+
var _surfaceRenderer = require("@atlaskit/editor-ui-control-model/surface-renderer");
|
|
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 getRank = function getRank(component, parentKey) {
|
|
14
|
+
var _component$parents$fi, _component$parents;
|
|
15
|
+
return (_component$parents$fi = (_component$parents = component.parents) === null || _component$parents === void 0 || (_component$parents = _component$parents.find(function (parent) {
|
|
16
|
+
return parent.key === parentKey;
|
|
17
|
+
})) === null || _component$parents === void 0 ? void 0 : _component$parents.rank) !== null && _component$parents$fi !== void 0 ? _component$parents$fi : Number.MAX_SAFE_INTEGER;
|
|
18
|
+
};
|
|
19
|
+
var compareMatchedItems = function compareMatchedItems(a, b) {
|
|
20
|
+
return a.score - b.score || a.sectionRank - b.sectionRank || a.itemRank - b.itemRank || a.identity.localeCompare(b.identity);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Resolves registered menu items for a non-empty query. This intentionally has
|
|
25
|
+
* no empty-query path so browse behavior remains owned by buildTypeAheadMenuModel.
|
|
26
|
+
*/
|
|
27
|
+
var getMatchingComponents = exports.getMatchingComponents = function getMatchingComponents(components, rootComponent, query, formatMessage) {
|
|
28
|
+
var _resolveSurface = (0, _surfaceRenderer.resolveSurface)(components, rootComponent),
|
|
29
|
+
childrenMap = _resolveSurface.childrenMap,
|
|
30
|
+
root = _resolveSurface.root,
|
|
31
|
+
topLevelChildren = _resolveSurface.topLevelChildren;
|
|
32
|
+
if (!root || !topLevelChildren) {
|
|
33
|
+
return {
|
|
34
|
+
footer: undefined,
|
|
35
|
+
root: root,
|
|
36
|
+
sections: []
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
var matches = new Map();
|
|
40
|
+
var _iterator = _createForOfIteratorHelper(topLevelChildren),
|
|
41
|
+
_step;
|
|
42
|
+
try {
|
|
43
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
44
|
+
var _childrenMap$get;
|
|
45
|
+
var section = _step.value;
|
|
46
|
+
if (section.type !== 'menu-section' || (0, _typeAheadIsMenuFooterSectionKey.isMenuFooterSectionKey)(section.key) || !(0, _surfaceRenderer.willComponentRender)(section, childrenMap)) {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
var _iterator3 = _createForOfIteratorHelper((_childrenMap$get = childrenMap.get(section.key)) !== null && _childrenMap$get !== void 0 ? _childrenMap$get : []),
|
|
50
|
+
_step3;
|
|
51
|
+
try {
|
|
52
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
53
|
+
var _item$match, _match$score;
|
|
54
|
+
var item = _step3.value;
|
|
55
|
+
if (item.type !== 'menu-item' || (0, _typeAheadIsSectionOverflowItemKey.isSectionOverflowItemKey)(item.key) || !(0, _surfaceRenderer.willComponentRender)(item, childrenMap)) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
var match = (_item$match = item.match) === null || _item$match === void 0 ? void 0 : _item$match.call(item, {
|
|
59
|
+
formatMessage: formatMessage,
|
|
60
|
+
query: query
|
|
61
|
+
});
|
|
62
|
+
if (item.match && match === null) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
var candidate = {
|
|
66
|
+
identity: "".concat(item.type, ":").concat(item.key),
|
|
67
|
+
item: item,
|
|
68
|
+
itemRank: getRank(item, section.key),
|
|
69
|
+
score: Math.min(1, Math.max(0, (_match$score = match === null || match === void 0 ? void 0 : match.score) !== null && _match$score !== void 0 ? _match$score : 0)),
|
|
70
|
+
section: section,
|
|
71
|
+
sectionRank: getRank(section, root.key)
|
|
72
|
+
};
|
|
73
|
+
var existing = matches.get(candidate.identity);
|
|
74
|
+
if (!existing || compareMatchedItems(candidate, existing) < 0) {
|
|
75
|
+
matches.set(candidate.identity, candidate);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
} catch (err) {
|
|
79
|
+
_iterator3.e(err);
|
|
80
|
+
} finally {
|
|
81
|
+
_iterator3.f();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
} catch (err) {
|
|
85
|
+
_iterator.e(err);
|
|
86
|
+
} finally {
|
|
87
|
+
_iterator.f();
|
|
88
|
+
}
|
|
89
|
+
var sectionsByKey = new Map();
|
|
90
|
+
var _iterator2 = _createForOfIteratorHelper(Array.from(matches.values()).sort(compareMatchedItems)),
|
|
91
|
+
_step2;
|
|
92
|
+
try {
|
|
93
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
94
|
+
var _match = _step2.value;
|
|
95
|
+
var _existing = sectionsByKey.get(_match.section.key);
|
|
96
|
+
if (_existing) {
|
|
97
|
+
_existing.push(_match.item);
|
|
98
|
+
} else {
|
|
99
|
+
sectionsByKey.set(_match.section.key, [_match.section, _match.item]);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
} catch (err) {
|
|
103
|
+
_iterator2.e(err);
|
|
104
|
+
} finally {
|
|
105
|
+
_iterator2.f();
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
footer: undefined,
|
|
109
|
+
root: root,
|
|
110
|
+
sections: Array.from(sectionsByKey.values())
|
|
111
|
+
};
|
|
112
|
+
};
|
|
@@ -20,6 +20,7 @@ var TypeAheadQuickInsertItem = exports.TypeAheadQuickInsertItem = function TypeA
|
|
|
20
20
|
var contextValue = (0, _react.useMemo)(function () {
|
|
21
21
|
return {
|
|
22
22
|
editorView: quickInsertContext.editorView,
|
|
23
|
+
isOffline: quickInsertContext.isOffline,
|
|
23
24
|
item: {
|
|
24
25
|
id: id,
|
|
25
26
|
isSelected: isSelected
|
|
@@ -6,6 +6,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
});
|
|
7
7
|
exports.TypeAheadQuickInsertProvider = void 0;
|
|
8
8
|
var _react = _interopRequireWildcard(require("react"));
|
|
9
|
+
var _isOfflineMode = require("@atlaskit/editor-common/connectivity/isOfflineMode");
|
|
10
|
+
var _hooks = require("@atlaskit/editor-common/hooks");
|
|
9
11
|
var _provider = require("@atlaskit/editor-common/quick-insert/provider");
|
|
10
12
|
var _insertTypeAheadItem = require("../../../pm-plugins/commands/insert-type-ahead-item");
|
|
11
13
|
var _useTypeAheadContext2 = require("../useTypeAheadContext");
|
|
@@ -13,11 +15,19 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
|
|
|
13
15
|
var TypeAheadQuickInsertProvider = exports.TypeAheadQuickInsertProvider = function TypeAheadQuickInsertProvider(_ref) {
|
|
14
16
|
var children = _ref.children;
|
|
15
17
|
var _useTypeAheadContext = (0, _useTypeAheadContext2.useTypeAheadContext)(),
|
|
18
|
+
api = _useTypeAheadContext.api,
|
|
16
19
|
editorView = _useTypeAheadContext.editorView,
|
|
17
20
|
inputMethod = _useTypeAheadContext.inputMethod,
|
|
18
21
|
onClose = _useTypeAheadContext.onClose,
|
|
19
22
|
query = _useTypeAheadContext.query,
|
|
20
23
|
triggerHandler = _useTypeAheadContext.triggerHandler;
|
|
24
|
+
var _useSharedPluginState = (0, _hooks.useSharedPluginStateWithSelector)(api, ['connectivity'], function (_ref2) {
|
|
25
|
+
var connectivityState = _ref2.connectivityState;
|
|
26
|
+
return {
|
|
27
|
+
isOffline: (0, _isOfflineMode.isOfflineMode)(connectivityState === null || connectivityState === void 0 ? void 0 : connectivityState.mode)
|
|
28
|
+
};
|
|
29
|
+
}),
|
|
30
|
+
isOffline = _useSharedPluginState.isOffline;
|
|
21
31
|
var select = (0, _react.useCallback)(function (selectionHandler) {
|
|
22
32
|
onClose();
|
|
23
33
|
queueMicrotask(function () {
|
|
@@ -32,9 +42,10 @@ var TypeAheadQuickInsertProvider = exports.TypeAheadQuickInsertProvider = functi
|
|
|
32
42
|
var contextValue = (0, _react.useMemo)(function () {
|
|
33
43
|
return {
|
|
34
44
|
editorView: editorView,
|
|
45
|
+
isOffline: isOffline,
|
|
35
46
|
select: select
|
|
36
47
|
};
|
|
37
|
-
}, [editorView, select]);
|
|
48
|
+
}, [editorView, isOffline, select]);
|
|
38
49
|
return /*#__PURE__*/_react.default.createElement(_provider.QuickInsertProvider, {
|
|
39
50
|
value: contextValue
|
|
40
51
|
}, children);
|
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
import "./RegisteredTypeAheadMenu.compiled.css";
|
|
3
3
|
import { ax, ix } from "@compiled/react/runtime";
|
|
4
4
|
import React, { useCallback, useId, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
5
|
+
import { useIntl } from 'react-intl';
|
|
5
6
|
import { isSectionOverflowItemKey } from '@atlaskit/editor-common/type-ahead-is-section-overflow-item-key';
|
|
6
7
|
import { Popup } from '@atlaskit/editor-common/ui';
|
|
7
8
|
import { akEditorFloatingDialogZIndex } from '@atlaskit/editor-shared-styles/constants';
|
|
8
9
|
import { Box } from '@atlaskit/primitives/compiled';
|
|
9
10
|
import { InputQuery } from '../InputQuery';
|
|
10
11
|
import { buildTypeAheadMenuModel } from './buildTypeAheadMenuModel';
|
|
12
|
+
import { getMatchingComponents } from './getMatchingComponents';
|
|
11
13
|
import { getTypeAheadGlobalViewMoreId } from './getTypeAheadGlobalViewMoreId';
|
|
12
14
|
import { getTypeAheadItemId } from './getTypeAheadItemId';
|
|
13
15
|
import { TypeAheadMenuRenderer } from './TypeAheadMenuRenderer';
|
|
@@ -36,6 +38,9 @@ export const RegisteredTypeAheadMenu = ({
|
|
|
36
38
|
surface,
|
|
37
39
|
triggerHandler
|
|
38
40
|
}) => {
|
|
41
|
+
const {
|
|
42
|
+
formatMessage
|
|
43
|
+
} = useIntl();
|
|
39
44
|
const generatedId = useId();
|
|
40
45
|
const listId = `${surface.listIdPrefix}-${generatedId}`;
|
|
41
46
|
const menuRef = useRef(null);
|
|
@@ -47,7 +52,7 @@ export const RegisteredTypeAheadMenu = ({
|
|
|
47
52
|
const hasSectionOverflowItems = useMemo(() => components.some(({
|
|
48
53
|
key
|
|
49
54
|
}) => isSectionOverflowItemKey(key)), [components]);
|
|
50
|
-
const menuModel = useMemo(() => buildTypeAheadMenuModel(components, surface.root, hasSectionOverflowItems ? SECTION_OVERFLOW_LIMIT : undefined), [components, hasSectionOverflowItems, surface.root]);
|
|
55
|
+
const menuModel = useMemo(() => query === '' ? buildTypeAheadMenuModel(components, surface.root, hasSectionOverflowItems ? SECTION_OVERFLOW_LIMIT : undefined) : getMatchingComponents(components, surface.root, query, formatMessage), [components, formatMessage, hasSectionOverflowItems, query, surface.root]);
|
|
51
56
|
const rows = useMemo(() => menuModel.sections.flat(), [menuModel.sections]);
|
|
52
57
|
const selectableRowIndexes = useMemo(() => rows.flatMap((registration, rowIndex) => registration.type === 'menu-item' ? [rowIndex] : []), [rows]);
|
|
53
58
|
const selectableRowKeys = selectableRowIndexes.map(index => {
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { isMenuFooterSectionKey } from '@atlaskit/editor-common/type-ahead-is-menu-footer-section-key';
|
|
2
|
+
import { isSectionOverflowItemKey } from '@atlaskit/editor-common/type-ahead-is-section-overflow-item-key';
|
|
3
|
+
import { resolveSurface, willComponentRender } from '@atlaskit/editor-ui-control-model/surface-renderer';
|
|
4
|
+
const getRank = (component, parentKey) => {
|
|
5
|
+
var _component$parents$fi, _component$parents, _component$parents$fi2;
|
|
6
|
+
return (_component$parents$fi = (_component$parents = component.parents) === null || _component$parents === void 0 ? void 0 : (_component$parents$fi2 = _component$parents.find(parent => parent.key === parentKey)) === null || _component$parents$fi2 === void 0 ? void 0 : _component$parents$fi2.rank) !== null && _component$parents$fi !== void 0 ? _component$parents$fi : Number.MAX_SAFE_INTEGER;
|
|
7
|
+
};
|
|
8
|
+
const compareMatchedItems = (a, b) => a.score - b.score || a.sectionRank - b.sectionRank || a.itemRank - b.itemRank || a.identity.localeCompare(b.identity);
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Resolves registered menu items for a non-empty query. This intentionally has
|
|
12
|
+
* no empty-query path so browse behavior remains owned by buildTypeAheadMenuModel.
|
|
13
|
+
*/
|
|
14
|
+
export const getMatchingComponents = (components, rootComponent, query, formatMessage) => {
|
|
15
|
+
const {
|
|
16
|
+
childrenMap,
|
|
17
|
+
root,
|
|
18
|
+
topLevelChildren
|
|
19
|
+
} = resolveSurface(components, rootComponent);
|
|
20
|
+
if (!root || !topLevelChildren) {
|
|
21
|
+
return {
|
|
22
|
+
footer: undefined,
|
|
23
|
+
root,
|
|
24
|
+
sections: []
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
const matches = new Map();
|
|
28
|
+
for (const section of topLevelChildren) {
|
|
29
|
+
if (section.type !== 'menu-section' || isMenuFooterSectionKey(section.key) || !willComponentRender(section, childrenMap)) {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
for (const item of (_childrenMap$get = childrenMap.get(section.key)) !== null && _childrenMap$get !== void 0 ? _childrenMap$get : []) {
|
|
33
|
+
var _childrenMap$get, _item$match, _match$score;
|
|
34
|
+
if (item.type !== 'menu-item' || isSectionOverflowItemKey(item.key) || !willComponentRender(item, childrenMap)) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
const match = (_item$match = item.match) === null || _item$match === void 0 ? void 0 : _item$match.call(item, {
|
|
38
|
+
formatMessage,
|
|
39
|
+
query
|
|
40
|
+
});
|
|
41
|
+
if (item.match && match === null) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
const candidate = {
|
|
45
|
+
identity: `${item.type}:${item.key}`,
|
|
46
|
+
item,
|
|
47
|
+
itemRank: getRank(item, section.key),
|
|
48
|
+
score: Math.min(1, Math.max(0, (_match$score = match === null || match === void 0 ? void 0 : match.score) !== null && _match$score !== void 0 ? _match$score : 0)),
|
|
49
|
+
section,
|
|
50
|
+
sectionRank: getRank(section, root.key)
|
|
51
|
+
};
|
|
52
|
+
const existing = matches.get(candidate.identity);
|
|
53
|
+
if (!existing || compareMatchedItems(candidate, existing) < 0) {
|
|
54
|
+
matches.set(candidate.identity, candidate);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const sectionsByKey = new Map();
|
|
59
|
+
for (const match of Array.from(matches.values()).sort(compareMatchedItems)) {
|
|
60
|
+
const existing = sectionsByKey.get(match.section.key);
|
|
61
|
+
if (existing) {
|
|
62
|
+
existing.push(match.item);
|
|
63
|
+
} else {
|
|
64
|
+
sectionsByKey.set(match.section.key, [match.section, match.item]);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
footer: undefined,
|
|
69
|
+
root,
|
|
70
|
+
sections: Array.from(sectionsByKey.values())
|
|
71
|
+
};
|
|
72
|
+
};
|
|
@@ -12,6 +12,7 @@ export const TypeAheadQuickInsertItem = ({
|
|
|
12
12
|
const Component = (_registration$compone = registration.component) !== null && _registration$compone !== void 0 ? _registration$compone : PassThrough;
|
|
13
13
|
const contextValue = useMemo(() => ({
|
|
14
14
|
editorView: quickInsertContext.editorView,
|
|
15
|
+
isOffline: quickInsertContext.isOffline,
|
|
15
16
|
item: {
|
|
16
17
|
id,
|
|
17
18
|
isSelected
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import React, { useCallback, useMemo } from 'react';
|
|
2
|
+
import { isOfflineMode } from '@atlaskit/editor-common/connectivity/isOfflineMode';
|
|
3
|
+
import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
|
|
2
4
|
import { QuickInsertProvider } from '@atlaskit/editor-common/quick-insert/provider';
|
|
3
5
|
import { performTypeAheadSelection } from '../../../pm-plugins/commands/insert-type-ahead-item';
|
|
4
6
|
import { useTypeAheadContext } from '../useTypeAheadContext';
|
|
@@ -6,12 +8,20 @@ export const TypeAheadQuickInsertProvider = ({
|
|
|
6
8
|
children
|
|
7
9
|
}) => {
|
|
8
10
|
const {
|
|
11
|
+
api,
|
|
9
12
|
editorView,
|
|
10
13
|
inputMethod,
|
|
11
14
|
onClose,
|
|
12
15
|
query,
|
|
13
16
|
triggerHandler
|
|
14
17
|
} = useTypeAheadContext();
|
|
18
|
+
const {
|
|
19
|
+
isOffline
|
|
20
|
+
} = useSharedPluginStateWithSelector(api, ['connectivity'], ({
|
|
21
|
+
connectivityState
|
|
22
|
+
}) => ({
|
|
23
|
+
isOffline: isOfflineMode(connectivityState === null || connectivityState === void 0 ? void 0 : connectivityState.mode)
|
|
24
|
+
}));
|
|
15
25
|
const select = useCallback(selectionHandler => {
|
|
16
26
|
onClose();
|
|
17
27
|
queueMicrotask(() => {
|
|
@@ -25,8 +35,9 @@ export const TypeAheadQuickInsertProvider = ({
|
|
|
25
35
|
}, [editorView, inputMethod, onClose, query, triggerHandler]);
|
|
26
36
|
const contextValue = useMemo(() => ({
|
|
27
37
|
editorView,
|
|
38
|
+
isOffline,
|
|
28
39
|
select
|
|
29
|
-
}), [editorView, select]);
|
|
40
|
+
}), [editorView, isOffline, select]);
|
|
30
41
|
return /*#__PURE__*/React.createElement(QuickInsertProvider, {
|
|
31
42
|
value: contextValue
|
|
32
43
|
}, children);
|
|
@@ -3,12 +3,14 @@ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
|
3
3
|
import "./RegisteredTypeAheadMenu.compiled.css";
|
|
4
4
|
import { ax, ix } from "@compiled/react/runtime";
|
|
5
5
|
import React, { useCallback, useId, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
6
|
+
import { useIntl } from 'react-intl';
|
|
6
7
|
import { isSectionOverflowItemKey } from '@atlaskit/editor-common/type-ahead-is-section-overflow-item-key';
|
|
7
8
|
import { Popup } from '@atlaskit/editor-common/ui';
|
|
8
9
|
import { akEditorFloatingDialogZIndex } from '@atlaskit/editor-shared-styles/constants';
|
|
9
10
|
import { Box } from '@atlaskit/primitives/compiled';
|
|
10
11
|
import { InputQuery } from '../InputQuery';
|
|
11
12
|
import { buildTypeAheadMenuModel } from './buildTypeAheadMenuModel';
|
|
13
|
+
import { getMatchingComponents } from './getMatchingComponents';
|
|
12
14
|
import { getTypeAheadGlobalViewMoreId } from './getTypeAheadGlobalViewMoreId';
|
|
13
15
|
import { getTypeAheadItemId } from './getTypeAheadItemId';
|
|
14
16
|
import { TypeAheadMenuRenderer } from './TypeAheadMenuRenderer';
|
|
@@ -37,6 +39,8 @@ export var RegisteredTypeAheadMenu = function RegisteredTypeAheadMenu(_ref) {
|
|
|
37
39
|
setQuery = _ref.setQuery,
|
|
38
40
|
surface = _ref.surface,
|
|
39
41
|
triggerHandler = _ref.triggerHandler;
|
|
42
|
+
var _useIntl = useIntl(),
|
|
43
|
+
formatMessage = _useIntl.formatMessage;
|
|
40
44
|
var generatedId = useId();
|
|
41
45
|
var listId = "".concat(surface.listIdPrefix, "-").concat(generatedId);
|
|
42
46
|
var menuRef = useRef(null);
|
|
@@ -55,8 +59,8 @@ export var RegisteredTypeAheadMenu = function RegisteredTypeAheadMenu(_ref) {
|
|
|
55
59
|
});
|
|
56
60
|
}, [components]);
|
|
57
61
|
var menuModel = useMemo(function () {
|
|
58
|
-
return buildTypeAheadMenuModel(components, surface.root, hasSectionOverflowItems ? SECTION_OVERFLOW_LIMIT : undefined);
|
|
59
|
-
}, [components, hasSectionOverflowItems, surface.root]);
|
|
62
|
+
return query === '' ? buildTypeAheadMenuModel(components, surface.root, hasSectionOverflowItems ? SECTION_OVERFLOW_LIMIT : undefined) : getMatchingComponents(components, surface.root, query, formatMessage);
|
|
63
|
+
}, [components, formatMessage, hasSectionOverflowItems, query, surface.root]);
|
|
60
64
|
var rows = useMemo(function () {
|
|
61
65
|
return menuModel.sections.flat();
|
|
62
66
|
}, [menuModel.sections]);
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
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; } } }; }
|
|
2
|
+
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; } }
|
|
3
|
+
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; }
|
|
4
|
+
import { isMenuFooterSectionKey } from '@atlaskit/editor-common/type-ahead-is-menu-footer-section-key';
|
|
5
|
+
import { isSectionOverflowItemKey } from '@atlaskit/editor-common/type-ahead-is-section-overflow-item-key';
|
|
6
|
+
import { resolveSurface, willComponentRender } from '@atlaskit/editor-ui-control-model/surface-renderer';
|
|
7
|
+
var getRank = function getRank(component, parentKey) {
|
|
8
|
+
var _component$parents$fi, _component$parents;
|
|
9
|
+
return (_component$parents$fi = (_component$parents = component.parents) === null || _component$parents === void 0 || (_component$parents = _component$parents.find(function (parent) {
|
|
10
|
+
return parent.key === parentKey;
|
|
11
|
+
})) === null || _component$parents === void 0 ? void 0 : _component$parents.rank) !== null && _component$parents$fi !== void 0 ? _component$parents$fi : Number.MAX_SAFE_INTEGER;
|
|
12
|
+
};
|
|
13
|
+
var compareMatchedItems = function compareMatchedItems(a, b) {
|
|
14
|
+
return a.score - b.score || a.sectionRank - b.sectionRank || a.itemRank - b.itemRank || a.identity.localeCompare(b.identity);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Resolves registered menu items for a non-empty query. This intentionally has
|
|
19
|
+
* no empty-query path so browse behavior remains owned by buildTypeAheadMenuModel.
|
|
20
|
+
*/
|
|
21
|
+
export var getMatchingComponents = function getMatchingComponents(components, rootComponent, query, formatMessage) {
|
|
22
|
+
var _resolveSurface = resolveSurface(components, rootComponent),
|
|
23
|
+
childrenMap = _resolveSurface.childrenMap,
|
|
24
|
+
root = _resolveSurface.root,
|
|
25
|
+
topLevelChildren = _resolveSurface.topLevelChildren;
|
|
26
|
+
if (!root || !topLevelChildren) {
|
|
27
|
+
return {
|
|
28
|
+
footer: undefined,
|
|
29
|
+
root: root,
|
|
30
|
+
sections: []
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
var matches = new Map();
|
|
34
|
+
var _iterator = _createForOfIteratorHelper(topLevelChildren),
|
|
35
|
+
_step;
|
|
36
|
+
try {
|
|
37
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
38
|
+
var _childrenMap$get;
|
|
39
|
+
var section = _step.value;
|
|
40
|
+
if (section.type !== 'menu-section' || isMenuFooterSectionKey(section.key) || !willComponentRender(section, childrenMap)) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
var _iterator3 = _createForOfIteratorHelper((_childrenMap$get = childrenMap.get(section.key)) !== null && _childrenMap$get !== void 0 ? _childrenMap$get : []),
|
|
44
|
+
_step3;
|
|
45
|
+
try {
|
|
46
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
47
|
+
var _item$match, _match$score;
|
|
48
|
+
var item = _step3.value;
|
|
49
|
+
if (item.type !== 'menu-item' || isSectionOverflowItemKey(item.key) || !willComponentRender(item, childrenMap)) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
var match = (_item$match = item.match) === null || _item$match === void 0 ? void 0 : _item$match.call(item, {
|
|
53
|
+
formatMessage: formatMessage,
|
|
54
|
+
query: query
|
|
55
|
+
});
|
|
56
|
+
if (item.match && match === null) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
var candidate = {
|
|
60
|
+
identity: "".concat(item.type, ":").concat(item.key),
|
|
61
|
+
item: item,
|
|
62
|
+
itemRank: getRank(item, section.key),
|
|
63
|
+
score: Math.min(1, Math.max(0, (_match$score = match === null || match === void 0 ? void 0 : match.score) !== null && _match$score !== void 0 ? _match$score : 0)),
|
|
64
|
+
section: section,
|
|
65
|
+
sectionRank: getRank(section, root.key)
|
|
66
|
+
};
|
|
67
|
+
var existing = matches.get(candidate.identity);
|
|
68
|
+
if (!existing || compareMatchedItems(candidate, existing) < 0) {
|
|
69
|
+
matches.set(candidate.identity, candidate);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
} catch (err) {
|
|
73
|
+
_iterator3.e(err);
|
|
74
|
+
} finally {
|
|
75
|
+
_iterator3.f();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
} catch (err) {
|
|
79
|
+
_iterator.e(err);
|
|
80
|
+
} finally {
|
|
81
|
+
_iterator.f();
|
|
82
|
+
}
|
|
83
|
+
var sectionsByKey = new Map();
|
|
84
|
+
var _iterator2 = _createForOfIteratorHelper(Array.from(matches.values()).sort(compareMatchedItems)),
|
|
85
|
+
_step2;
|
|
86
|
+
try {
|
|
87
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
88
|
+
var _match = _step2.value;
|
|
89
|
+
var _existing = sectionsByKey.get(_match.section.key);
|
|
90
|
+
if (_existing) {
|
|
91
|
+
_existing.push(_match.item);
|
|
92
|
+
} else {
|
|
93
|
+
sectionsByKey.set(_match.section.key, [_match.section, _match.item]);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
} catch (err) {
|
|
97
|
+
_iterator2.e(err);
|
|
98
|
+
} finally {
|
|
99
|
+
_iterator2.f();
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
footer: undefined,
|
|
103
|
+
root: root,
|
|
104
|
+
sections: Array.from(sectionsByKey.values())
|
|
105
|
+
};
|
|
106
|
+
};
|
|
@@ -12,6 +12,7 @@ export var TypeAheadQuickInsertItem = function TypeAheadQuickInsertItem(_ref) {
|
|
|
12
12
|
var contextValue = useMemo(function () {
|
|
13
13
|
return {
|
|
14
14
|
editorView: quickInsertContext.editorView,
|
|
15
|
+
isOffline: quickInsertContext.isOffline,
|
|
15
16
|
item: {
|
|
16
17
|
id: id,
|
|
17
18
|
isSelected: isSelected
|
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
import React, { useCallback, useMemo } from 'react';
|
|
2
|
+
import { isOfflineMode } from '@atlaskit/editor-common/connectivity/isOfflineMode';
|
|
3
|
+
import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
|
|
2
4
|
import { QuickInsertProvider } from '@atlaskit/editor-common/quick-insert/provider';
|
|
3
5
|
import { performTypeAheadSelection } from '../../../pm-plugins/commands/insert-type-ahead-item';
|
|
4
6
|
import { useTypeAheadContext } from '../useTypeAheadContext';
|
|
5
7
|
export var TypeAheadQuickInsertProvider = function TypeAheadQuickInsertProvider(_ref) {
|
|
6
8
|
var children = _ref.children;
|
|
7
9
|
var _useTypeAheadContext = useTypeAheadContext(),
|
|
10
|
+
api = _useTypeAheadContext.api,
|
|
8
11
|
editorView = _useTypeAheadContext.editorView,
|
|
9
12
|
inputMethod = _useTypeAheadContext.inputMethod,
|
|
10
13
|
onClose = _useTypeAheadContext.onClose,
|
|
11
14
|
query = _useTypeAheadContext.query,
|
|
12
15
|
triggerHandler = _useTypeAheadContext.triggerHandler;
|
|
16
|
+
var _useSharedPluginState = useSharedPluginStateWithSelector(api, ['connectivity'], function (_ref2) {
|
|
17
|
+
var connectivityState = _ref2.connectivityState;
|
|
18
|
+
return {
|
|
19
|
+
isOffline: isOfflineMode(connectivityState === null || connectivityState === void 0 ? void 0 : connectivityState.mode)
|
|
20
|
+
};
|
|
21
|
+
}),
|
|
22
|
+
isOffline = _useSharedPluginState.isOffline;
|
|
13
23
|
var select = useCallback(function (selectionHandler) {
|
|
14
24
|
onClose();
|
|
15
25
|
queueMicrotask(function () {
|
|
@@ -24,9 +34,10 @@ export var TypeAheadQuickInsertProvider = function TypeAheadQuickInsertProvider(
|
|
|
24
34
|
var contextValue = useMemo(function () {
|
|
25
35
|
return {
|
|
26
36
|
editorView: editorView,
|
|
37
|
+
isOffline: isOffline,
|
|
27
38
|
select: select
|
|
28
39
|
};
|
|
29
|
-
}, [editorView, select]);
|
|
40
|
+
}, [editorView, isOffline, select]);
|
|
30
41
|
return /*#__PURE__*/React.createElement(QuickInsertProvider, {
|
|
31
42
|
value: contextValue
|
|
32
43
|
}, children);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { IntlShape } from 'react-intl';
|
|
2
|
+
import type { SurfaceIdentifier } from '@atlaskit/editor-ui-control-model/surface-renderer/types';
|
|
3
|
+
import type { RegisterComponent } from '@atlaskit/editor-ui-control-model/types';
|
|
4
|
+
import type { TypeAheadMenuModel } from './buildTypeAheadMenuModel';
|
|
5
|
+
/**
|
|
6
|
+
* Resolves registered menu items for a non-empty query. This intentionally has
|
|
7
|
+
* no empty-query path so browse behavior remains owned by buildTypeAheadMenuModel.
|
|
8
|
+
*/
|
|
9
|
+
export declare const getMatchingComponents: (components: RegisterComponent[], rootComponent: SurfaceIdentifier, query: string, formatMessage: IntlShape['formatMessage']) => TypeAheadMenuModel;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-type-ahead",
|
|
3
|
-
"version": "15.
|
|
3
|
+
"version": "15.1.1",
|
|
4
4
|
"description": "Type-ahead plugin for @atlaskit/editor-core",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -27,10 +27,10 @@
|
|
|
27
27
|
"@atlaskit/editor-plugin-connectivity": "^14.0.0",
|
|
28
28
|
"@atlaskit/editor-plugin-context-panel": "^16.0.0",
|
|
29
29
|
"@atlaskit/editor-plugin-metrics": "^15.0.0",
|
|
30
|
-
"@atlaskit/editor-plugin-ui-control-registry": "^8.
|
|
30
|
+
"@atlaskit/editor-plugin-ui-control-registry": "^8.1.0",
|
|
31
31
|
"@atlaskit/editor-prosemirror": "^8.0.0",
|
|
32
32
|
"@atlaskit/editor-shared-styles": "^4.0.0",
|
|
33
|
-
"@atlaskit/editor-ui-control-model": "^2.
|
|
33
|
+
"@atlaskit/editor-ui-control-model": "^2.6.0",
|
|
34
34
|
"@atlaskit/feature-gate-js-client": "^6.0.0",
|
|
35
35
|
"@atlaskit/heading": "^7.0.0",
|
|
36
36
|
"@atlaskit/icon": "^37.3.0",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"w3c-keyname": "^2.1.8"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
|
-
"@atlaskit/editor-common": "^118.
|
|
56
|
+
"@atlaskit/editor-common": "^118.10.0",
|
|
57
57
|
"react": "^18.2.0 || ^19.2.0",
|
|
58
58
|
"react-dom": "^18.2.0 || ^19.2.0",
|
|
59
59
|
"react-intl": "^5.25.1 || ^6.0.0 || ^7.0.0"
|