@atlaskit/editor-plugin-quick-insert 15.0.10 → 15.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @atlaskit/editor-plugin-quick-insert
2
2
 
3
+ ## 15.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`edcef04b6350e`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/edcef04b6350e) -
8
+ Add the Quick Insert recommendation resolver API and typed surface context support for the gated
9
+ `platform_editor_slash_command` Recommended menu. TypeAhead uses immutable surface context for
10
+ visibility and React context for registered Quick Insert rendering, while Quick Insert keeps one
11
+ recommendation snapshot per menu open. Fix Quick Insert declaration generation.
12
+
13
+ ### Patch Changes
14
+
15
+ - Updated dependencies
16
+
3
17
  ## 15.0.10
4
18
 
5
19
  ### Patch Changes
@@ -99,7 +99,8 @@ var quickInsertPlugin = exports.quickInsertPlugin = function quickInsertPlugin(_
99
99
  var _api$uiControlRegistr;
100
100
  api === null || api === void 0 || (_api$uiControlRegistr = api.uiControlRegistry) === null || _api$uiControlRegistr === void 0 || _api$uiControlRegistr.actions.register((0, _getQuickInsertComponents.getQuickInsertComponents)({
101
101
  api: api,
102
- includeElementBrowserItems: (options === null || options === void 0 ? void 0 : options.enableElementBrowser) === true
102
+ includeElementBrowserItems: (options === null || options === void 0 ? void 0 : options.enableElementBrowser) === true,
103
+ isRecommendedItem: options === null || options === void 0 ? void 0 : options.isRecommendedItem
103
104
  }));
104
105
  }
105
106
  var openElementBrowser = function openElementBrowser(options) {
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.QuickInsertRecommendedSlot = void 0;
8
+ var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
9
+ var _react = _interopRequireDefault(require("react"));
10
+ var _useQuickInsertContext = require("@atlaskit/editor-common/quick-insert/use-quick-insert-context");
11
+ var _excluded = ["index", "getSnapshot"];
12
+ var QuickInsertRecommendedSlot = exports.QuickInsertRecommendedSlot = function QuickInsertRecommendedSlot(_ref) {
13
+ var index = _ref.index,
14
+ getSnapshot = _ref.getSnapshot,
15
+ props = (0, _objectWithoutProperties2.default)(_ref, _excluded);
16
+ var _useQuickInsertContex = (0, _useQuickInsertContext.useQuickInsertContext)(),
17
+ surfaceContext = _useQuickInsertContex.surfaceContext;
18
+ var item = getSnapshot(surfaceContext)[index];
19
+ return item !== null && item !== void 0 && item.component ? /*#__PURE__*/_react.default.createElement(item.component, props) : null;
20
+ };
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  });
7
7
  exports.getQuickInsertComponents = void 0;
8
8
  var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
10
  var _react = _interopRequireDefault(require("react"));
10
11
  var _reactIntl = require("react-intl");
11
12
  var _keys = require("@atlaskit/editor-common/quick-insert/keys");
@@ -16,7 +17,11 @@ var _rank = require("@atlaskit/editor-common/quick-insert/rank");
16
17
  var _typeAheadGetMenuFooterSectionKey = require("@atlaskit/editor-common/type-ahead-get-menu-footer-section-key");
17
18
  var _typeAheadGetSectionOverflowItemKey = require("@atlaskit/editor-common/type-ahead-get-section-overflow-item-key");
18
19
  var _QuickInsertMenuFooterItem = require("./QuickInsertMenuFooterItem");
20
+ var _QuickInsertRecommendedSlot = require("./QuickInsertRecommendedSlot");
19
21
  var _QuickInsertSectionOverflowMenuItem = require("./QuickInsertSectionOverflowMenuItem");
22
+ var _getRecommendedComponents = require("./getRecommendedComponents");
23
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
24
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
20
25
  var categories = [{
21
26
  message: _messages.messages.categoryRecommended,
22
27
  section: _keys.RECOMMENDED_SECTION
@@ -58,14 +63,46 @@ var createSectionComponent = function createSectionComponent(message) {
58
63
  };
59
64
  var getQuickInsertComponents = exports.getQuickInsertComponents = function getQuickInsertComponents(_ref2) {
60
65
  var api = _ref2.api,
61
- includeElementBrowserItems = _ref2.includeElementBrowserItems;
66
+ includeElementBrowserItems = _ref2.includeElementBrowserItems,
67
+ isRecommendedItem = _ref2.isRecommendedItem;
68
+ var recommendedSnapshot = (0, _getRecommendedComponents.createRecommendedSnapshotCache)({
69
+ api: api,
70
+ isRecommendedItem: isRecommendedItem
71
+ });
72
+ var recommendedSlots = Array.from({
73
+ length: _getRecommendedComponents.MAX_RECOMMENDED_ITEMS
74
+ }, function (_, index) {
75
+ return {
76
+ key: "".concat(_getRecommendedComponents.RECOMMENDED_SLOT_KEY_PREFIX).concat(index),
77
+ type: 'menu-item',
78
+ parents: [{
79
+ key: _keys.RECOMMENDED_SECTION.key,
80
+ type: _keys.RECOMMENDED_SECTION.type,
81
+ rank: index
82
+ }],
83
+ match: function match() {
84
+ return null;
85
+ },
86
+ isHidden: function isHidden() {
87
+ var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
88
+ surfaceContext = _ref3.surfaceContext;
89
+ return !recommendedSnapshot.getSnapshot(surfaceContext)[index];
90
+ },
91
+ component: function component(props) {
92
+ return /*#__PURE__*/_react.default.createElement(_QuickInsertRecommendedSlot.QuickInsertRecommendedSlot, _objectSpread(_objectSpread({}, props), {}, {
93
+ index: index,
94
+ getSnapshot: recommendedSnapshot.getSnapshot
95
+ }));
96
+ }
97
+ };
98
+ });
62
99
  return [{
63
100
  key: _keys.MENU.key,
64
101
  type: _keys.MENU.type,
65
102
  component: _menuRoot.QuickInsertMenuRoot
66
- }].concat((0, _toConsumableArray2.default)(categories.flatMap(function (_ref3) {
67
- var message = _ref3.message,
68
- section = _ref3.section;
103
+ }].concat(recommendedSlots, (0, _toConsumableArray2.default)(categories.flatMap(function (_ref4) {
104
+ var message = _ref4.message,
105
+ section = _ref4.section;
69
106
  return [{
70
107
  key: section.key,
71
108
  type: section.type,
@@ -74,8 +111,13 @@ var getQuickInsertComponents = exports.getQuickInsertComponents = function getQu
74
111
  type: _keys.MENU.type,
75
112
  rank: _rank.QUICK_INSERT_MENU_RANK[section.key]
76
113
  }],
77
- component: createSectionComponent(message)
78
- }].concat((0, _toConsumableArray2.default)(includeElementBrowserItems ? [{
114
+ component: createSectionComponent(message),
115
+ isHidden: section.key === _keys.RECOMMENDED_SECTION.key ? function () {
116
+ var _ref5 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
117
+ surfaceContext = _ref5.surfaceContext;
118
+ return recommendedSnapshot.getSnapshot(surfaceContext).length === 0;
119
+ } : undefined
120
+ }].concat((0, _toConsumableArray2.default)(includeElementBrowserItems && section.key !== _keys.RECOMMENDED_SECTION.key ? [{
79
121
  key: (0, _typeAheadGetSectionOverflowItemKey.getSectionOverflowItemKey)(section.key),
80
122
  type: 'menu-item',
81
123
  parents: [{
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.isRecommendedSlotKey = exports.getRecommendedComponents = exports.createRecommendedSnapshotCache = exports.RECOMMENDED_SLOT_KEY_PREFIX = exports.MAX_RECOMMENDED_ITEMS = void 0;
7
+ var _keys = require("@atlaskit/editor-common/quick-insert/keys");
8
+ var _typeAheadIsMenuFooterSectionKey = require("@atlaskit/editor-common/type-ahead-is-menu-footer-section-key");
9
+ var _typeAheadIsSectionOverflowItemKey = require("@atlaskit/editor-common/type-ahead-is-section-overflow-item-key");
10
+ var _isRecommendedItem = require("@atlaskit/editor-common/quick-insert/is-recommended-item");
11
+ var _monitoring = require("@atlaskit/editor-common/monitoring");
12
+ var _typeAheadSurfaceContext = require("@atlaskit/editor-common/type-ahead-surface-context");
13
+ var MAX_RECOMMENDED_ITEMS = exports.MAX_RECOMMENDED_ITEMS = 5;
14
+ var RECOMMENDED_SLOT_KEY_PREFIX = exports.RECOMMENDED_SLOT_KEY_PREFIX = 'quick-insert-recommended-slot-';
15
+ var isRecommendedSlotKey = exports.isRecommendedSlotKey = function isRecommendedSlotKey(key) {
16
+ return key.startsWith(RECOMMENDED_SLOT_KEY_PREFIX);
17
+ };
18
+ var isRecommendationCandidate = function isRecommendationCandidate(component) {
19
+ return component.type === 'menu-item' && !isRecommendedSlotKey(component.key) && !(0, _typeAheadIsSectionOverflowItemKey.isSectionOverflowItemKey)(component.key) && !component.parents.some(function (parent) {
20
+ return (0, _typeAheadIsMenuFooterSectionKey.isMenuFooterSectionKey)(parent.key);
21
+ });
22
+ };
23
+ var getRecommendedComponents = exports.getRecommendedComponents = function getRecommendedComponents(_ref) {
24
+ var components = _ref.components,
25
+ context = _ref.context,
26
+ _ref$isRecommendedIte = _ref.isRecommendedItem,
27
+ isRecommendedItem = _ref$isRecommendedIte === void 0 ? _isRecommendedItem.defaultIsRecommendedItem : _ref$isRecommendedIte;
28
+ return components.filter(isRecommendationCandidate).flatMap(function (component, index) {
29
+ var _component$isHidden;
30
+ var result = isRecommendedItem({
31
+ itemKey: component.key
32
+ });
33
+ if (result === null) {
34
+ return [];
35
+ }
36
+ if (Number.isNaN(result)) {
37
+ void (0, _monitoring.logException)(new Error('Invalid Quick Insert recommended item rank'), {
38
+ location: 'editor-plugin-quick-insert/getRecommendedComponents'
39
+ });
40
+ return [];
41
+ }
42
+ if ((_component$isHidden = component.isHidden) !== null && _component$isHidden !== void 0 && _component$isHidden.call(component, {
43
+ surfaceContext: context
44
+ })) {
45
+ return [];
46
+ }
47
+ return [{
48
+ component: component,
49
+ index: index,
50
+ rank: result
51
+ }];
52
+ }).sort(function (first, second) {
53
+ return first.rank === second.rank ? first.index - second.index : first.rank - second.rank;
54
+ }).slice(0, MAX_RECOMMENDED_ITEMS).map(function (_ref2) {
55
+ var component = _ref2.component;
56
+ return component;
57
+ });
58
+ };
59
+
60
+ /** Keeps only the current menu-open recommendation snapshot. */
61
+
62
+ var createRecommendedSnapshotCache = exports.createRecommendedSnapshotCache = function createRecommendedSnapshotCache(_ref3) {
63
+ var api = _ref3.api,
64
+ isRecommendedItem = _ref3.isRecommendedItem;
65
+ var snapshot;
66
+ var getSnapshot = function getSnapshot(surfaceContext) {
67
+ var _surfaceContext$get, _snapshot;
68
+ var menuOpenId = surfaceContext === null || surfaceContext === void 0 || (_surfaceContext$get = surfaceContext.get(_typeAheadSurfaceContext.TYPE_AHEAD_SURFACE_CONTEXT)) === null || _surfaceContext$get === void 0 ? void 0 : _surfaceContext$get.menuOpenId;
69
+ if (!surfaceContext || !menuOpenId) {
70
+ return [];
71
+ }
72
+ if (((_snapshot = snapshot) === null || _snapshot === void 0 ? void 0 : _snapshot.id) !== menuOpenId) {
73
+ var _api$uiControlRegistr, _api$uiControlRegistr2;
74
+ snapshot = {
75
+ id: menuOpenId,
76
+ items: getRecommendedComponents({
77
+ components: (_api$uiControlRegistr = api === null || api === void 0 || (_api$uiControlRegistr2 = api.uiControlRegistry) === null || _api$uiControlRegistr2 === void 0 ? void 0 : _api$uiControlRegistr2.actions.getComponents(_keys.MENU.key)) !== null && _api$uiControlRegistr !== void 0 ? _api$uiControlRegistr : [],
78
+ context: surfaceContext,
79
+ isRecommendedItem: isRecommendedItem
80
+ })
81
+ };
82
+ }
83
+ return snapshot.items;
84
+ };
85
+ return {
86
+ getSnapshot: getSnapshot
87
+ };
88
+ };
@@ -90,7 +90,8 @@ export const quickInsertPlugin = ({
90
90
  var _api$uiControlRegistr;
91
91
  api === null || api === void 0 ? void 0 : (_api$uiControlRegistr = api.uiControlRegistry) === null || _api$uiControlRegistr === void 0 ? void 0 : _api$uiControlRegistr.actions.register(getQuickInsertComponents({
92
92
  api,
93
- includeElementBrowserItems: (options === null || options === void 0 ? void 0 : options.enableElementBrowser) === true
93
+ includeElementBrowserItems: (options === null || options === void 0 ? void 0 : options.enableElementBrowser) === true,
94
+ isRecommendedItem: options === null || options === void 0 ? void 0 : options.isRecommendedItem
94
95
  }));
95
96
  }
96
97
  const openElementBrowser = options => ({
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import { useQuickInsertContext } from '@atlaskit/editor-common/quick-insert/use-quick-insert-context';
3
+ export const QuickInsertRecommendedSlot = ({
4
+ index,
5
+ getSnapshot,
6
+ ...props
7
+ }) => {
8
+ const {
9
+ surfaceContext
10
+ } = useQuickInsertContext();
11
+ const item = getSnapshot(surfaceContext)[index];
12
+ return item !== null && item !== void 0 && item.component ? /*#__PURE__*/React.createElement(item.component, props) : null;
13
+ };
@@ -8,7 +8,9 @@ import { CATEGORY_VIEW_MORE_RANK, QUICK_INSERT_MENU_RANK } from '@atlaskit/edito
8
8
  import { getMenuFooterSectionKey } from '@atlaskit/editor-common/type-ahead-get-menu-footer-section-key';
9
9
  import { getSectionOverflowItemKey } from '@atlaskit/editor-common/type-ahead-get-section-overflow-item-key';
10
10
  import { QuickInsertMenuFooterItem } from './QuickInsertMenuFooterItem';
11
+ import { QuickInsertRecommendedSlot } from './QuickInsertRecommendedSlot';
11
12
  import { QuickInsertSectionOverflowMenuItem } from './QuickInsertSectionOverflowMenuItem';
13
+ import { createRecommendedSnapshotCache, MAX_RECOMMENDED_ITEMS, RECOMMENDED_SLOT_KEY_PREFIX } from './getRecommendedComponents';
12
14
  const categories = [{
13
15
  message: messages.categoryRecommended,
14
16
  section: RECOMMENDED_SECTION
@@ -52,52 +54,82 @@ const createSectionComponent = message => {
52
54
  };
53
55
  export const getQuickInsertComponents = ({
54
56
  api,
55
- includeElementBrowserItems
56
- }) => [{
57
- key: MENU.key,
58
- type: MENU.type,
59
- component: QuickInsertMenuRoot
60
- }, ...categories.flatMap(({
61
- message,
62
- section
63
- }) => [{
64
- key: section.key,
65
- type: section.type,
66
- parents: [{
57
+ includeElementBrowserItems,
58
+ isRecommendedItem
59
+ }) => {
60
+ const recommendedSnapshot = createRecommendedSnapshotCache({
61
+ api,
62
+ isRecommendedItem
63
+ });
64
+ const recommendedSlots = Array.from({
65
+ length: MAX_RECOMMENDED_ITEMS
66
+ }, (_, index) => ({
67
+ key: `${RECOMMENDED_SLOT_KEY_PREFIX}${index}`,
68
+ type: 'menu-item',
69
+ parents: [{
70
+ key: RECOMMENDED_SECTION.key,
71
+ type: RECOMMENDED_SECTION.type,
72
+ rank: index
73
+ }],
74
+ match: () => null,
75
+ isHidden: ({
76
+ surfaceContext
77
+ } = {}) => !recommendedSnapshot.getSnapshot(surfaceContext)[index],
78
+ component: props => /*#__PURE__*/React.createElement(QuickInsertRecommendedSlot, {
79
+ ...props,
80
+ index,
81
+ getSnapshot: recommendedSnapshot.getSnapshot
82
+ })
83
+ }));
84
+ return [{
67
85
  key: MENU.key,
68
86
  type: MENU.type,
69
- rank: QUICK_INSERT_MENU_RANK[section.key]
70
- }],
71
- component: createSectionComponent(message)
72
- }, ...(includeElementBrowserItems ? [{
73
- key: getSectionOverflowItemKey(section.key),
74
- type: 'menu-item',
75
- parents: [{
87
+ component: QuickInsertMenuRoot
88
+ }, ...recommendedSlots, ...categories.flatMap(({
89
+ message,
90
+ section
91
+ }) => [{
76
92
  key: section.key,
77
93
  type: section.type,
78
- rank: CATEGORY_VIEW_MORE_RANK
79
- }],
80
- component: () => /*#__PURE__*/React.createElement(QuickInsertSectionOverflowMenuItem, {
81
- api,
82
- category: section.key
83
- })
84
- }] : [])]), ...(includeElementBrowserItems ? [{
85
- key: getMenuFooterSectionKey(MENU.key),
86
- type: 'menu-section',
87
- parents: [{
88
- key: MENU.key,
89
- type: MENU.type,
90
- rank: Number.MAX_SAFE_INTEGER
91
- }]
92
- }, {
93
- key: VIEW_ALL_ELEMENTS_MENU_ITEM.key,
94
- type: VIEW_ALL_ELEMENTS_MENU_ITEM.type,
95
- parents: [{
94
+ parents: [{
95
+ key: MENU.key,
96
+ type: MENU.type,
97
+ rank: QUICK_INSERT_MENU_RANK[section.key]
98
+ }],
99
+ component: createSectionComponent(message),
100
+ isHidden: section.key === RECOMMENDED_SECTION.key ? ({
101
+ surfaceContext
102
+ } = {}) => recommendedSnapshot.getSnapshot(surfaceContext).length === 0 : undefined
103
+ }, ...(includeElementBrowserItems && section.key !== RECOMMENDED_SECTION.key ? [{
104
+ key: getSectionOverflowItemKey(section.key),
105
+ type: 'menu-item',
106
+ parents: [{
107
+ key: section.key,
108
+ type: section.type,
109
+ rank: CATEGORY_VIEW_MORE_RANK
110
+ }],
111
+ component: () => /*#__PURE__*/React.createElement(QuickInsertSectionOverflowMenuItem, {
112
+ api,
113
+ category: section.key
114
+ })
115
+ }] : [])]), ...(includeElementBrowserItems ? [{
96
116
  key: getMenuFooterSectionKey(MENU.key),
97
117
  type: 'menu-section',
98
- rank: 100
99
- }],
100
- component: () => /*#__PURE__*/React.createElement(QuickInsertMenuFooterItem, {
101
- api
102
- })
103
- }] : [])];
118
+ parents: [{
119
+ key: MENU.key,
120
+ type: MENU.type,
121
+ rank: Number.MAX_SAFE_INTEGER
122
+ }]
123
+ }, {
124
+ key: VIEW_ALL_ELEMENTS_MENU_ITEM.key,
125
+ type: VIEW_ALL_ELEMENTS_MENU_ITEM.type,
126
+ parents: [{
127
+ key: getMenuFooterSectionKey(MENU.key),
128
+ type: 'menu-section',
129
+ rank: 100
130
+ }],
131
+ component: () => /*#__PURE__*/React.createElement(QuickInsertMenuFooterItem, {
132
+ api
133
+ })
134
+ }] : [])];
135
+ };
@@ -0,0 +1,74 @@
1
+ import { MENU } from '@atlaskit/editor-common/quick-insert/keys';
2
+ import { isMenuFooterSectionKey } from '@atlaskit/editor-common/type-ahead-is-menu-footer-section-key';
3
+ import { isSectionOverflowItemKey } from '@atlaskit/editor-common/type-ahead-is-section-overflow-item-key';
4
+ import { defaultIsRecommendedItem } from '@atlaskit/editor-common/quick-insert/is-recommended-item';
5
+ import { logException } from '@atlaskit/editor-common/monitoring';
6
+ import { TYPE_AHEAD_SURFACE_CONTEXT } from '@atlaskit/editor-common/type-ahead-surface-context';
7
+ export const MAX_RECOMMENDED_ITEMS = 5;
8
+ export const RECOMMENDED_SLOT_KEY_PREFIX = 'quick-insert-recommended-slot-';
9
+ export const isRecommendedSlotKey = key => key.startsWith(RECOMMENDED_SLOT_KEY_PREFIX);
10
+ const isRecommendationCandidate = component => component.type === 'menu-item' && !isRecommendedSlotKey(component.key) && !isSectionOverflowItemKey(component.key) && !component.parents.some(parent => isMenuFooterSectionKey(parent.key));
11
+ export const getRecommendedComponents = ({
12
+ components,
13
+ context,
14
+ isRecommendedItem = defaultIsRecommendedItem
15
+ }) => {
16
+ return components.filter(isRecommendationCandidate).flatMap((component, index) => {
17
+ var _component$isHidden;
18
+ const result = isRecommendedItem({
19
+ itemKey: component.key
20
+ });
21
+ if (result === null) {
22
+ return [];
23
+ }
24
+ if (Number.isNaN(result)) {
25
+ void logException(new Error('Invalid Quick Insert recommended item rank'), {
26
+ location: 'editor-plugin-quick-insert/getRecommendedComponents'
27
+ });
28
+ return [];
29
+ }
30
+ if ((_component$isHidden = component.isHidden) !== null && _component$isHidden !== void 0 && _component$isHidden.call(component, {
31
+ surfaceContext: context
32
+ })) {
33
+ return [];
34
+ }
35
+ return [{
36
+ component,
37
+ index,
38
+ rank: result
39
+ }];
40
+ }).sort((first, second) => first.rank === second.rank ? first.index - second.index : first.rank - second.rank).slice(0, MAX_RECOMMENDED_ITEMS).map(({
41
+ component
42
+ }) => component);
43
+ };
44
+
45
+ /** Keeps only the current menu-open recommendation snapshot. */
46
+
47
+ export const createRecommendedSnapshotCache = ({
48
+ api,
49
+ isRecommendedItem
50
+ }) => {
51
+ let snapshot;
52
+ const getSnapshot = surfaceContext => {
53
+ var _surfaceContext$get, _snapshot;
54
+ const menuOpenId = surfaceContext === null || surfaceContext === void 0 ? void 0 : (_surfaceContext$get = surfaceContext.get(TYPE_AHEAD_SURFACE_CONTEXT)) === null || _surfaceContext$get === void 0 ? void 0 : _surfaceContext$get.menuOpenId;
55
+ if (!surfaceContext || !menuOpenId) {
56
+ return [];
57
+ }
58
+ if (((_snapshot = snapshot) === null || _snapshot === void 0 ? void 0 : _snapshot.id) !== menuOpenId) {
59
+ var _api$uiControlRegistr, _api$uiControlRegistr2;
60
+ snapshot = {
61
+ id: menuOpenId,
62
+ items: getRecommendedComponents({
63
+ components: (_api$uiControlRegistr = api === null || api === void 0 ? void 0 : (_api$uiControlRegistr2 = api.uiControlRegistry) === null || _api$uiControlRegistr2 === void 0 ? void 0 : _api$uiControlRegistr2.actions.getComponents(MENU.key)) !== null && _api$uiControlRegistr !== void 0 ? _api$uiControlRegistr : [],
64
+ context: surfaceContext,
65
+ isRecommendedItem
66
+ })
67
+ };
68
+ }
69
+ return snapshot.items;
70
+ };
71
+ return {
72
+ getSnapshot
73
+ };
74
+ };
@@ -92,7 +92,8 @@ export var quickInsertPlugin = function quickInsertPlugin(_ref) {
92
92
  var _api$uiControlRegistr;
93
93
  api === null || api === void 0 || (_api$uiControlRegistr = api.uiControlRegistry) === null || _api$uiControlRegistr === void 0 || _api$uiControlRegistr.actions.register(getQuickInsertComponents({
94
94
  api: api,
95
- includeElementBrowserItems: (options === null || options === void 0 ? void 0 : options.enableElementBrowser) === true
95
+ includeElementBrowserItems: (options === null || options === void 0 ? void 0 : options.enableElementBrowser) === true,
96
+ isRecommendedItem: options === null || options === void 0 ? void 0 : options.isRecommendedItem
96
97
  }));
97
98
  }
98
99
  var openElementBrowser = function openElementBrowser(options) {
@@ -0,0 +1,13 @@
1
+ import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
2
+ var _excluded = ["index", "getSnapshot"];
3
+ import React from 'react';
4
+ import { useQuickInsertContext } from '@atlaskit/editor-common/quick-insert/use-quick-insert-context';
5
+ export var QuickInsertRecommendedSlot = function QuickInsertRecommendedSlot(_ref) {
6
+ var index = _ref.index,
7
+ getSnapshot = _ref.getSnapshot,
8
+ props = _objectWithoutProperties(_ref, _excluded);
9
+ var _useQuickInsertContex = useQuickInsertContext(),
10
+ surfaceContext = _useQuickInsertContex.surfaceContext;
11
+ var item = getSnapshot(surfaceContext)[index];
12
+ return item !== null && item !== void 0 && item.component ? /*#__PURE__*/React.createElement(item.component, props) : null;
13
+ };
@@ -1,4 +1,7 @@
1
1
  import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
3
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
4
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
2
5
  import React from 'react';
3
6
  import { useIntl } from 'react-intl';
4
7
  import { BLOCK_TEMPLATES_SECTION, DATA_AND_CHARTS_SECTION, EMBED_SECTION, MEDIA_SECTION, MENU, OTHER_SECTION, RECOMMENDED_SECTION, ROVO_SECTION, STRUCTURE_SECTION, TEXT_FORMATTING_SECTION, VIEW_ALL_ELEMENTS_MENU_ITEM } from '@atlaskit/editor-common/quick-insert/keys';
@@ -9,7 +12,9 @@ import { CATEGORY_VIEW_MORE_RANK, QUICK_INSERT_MENU_RANK } from '@atlaskit/edito
9
12
  import { getMenuFooterSectionKey } from '@atlaskit/editor-common/type-ahead-get-menu-footer-section-key';
10
13
  import { getSectionOverflowItemKey } from '@atlaskit/editor-common/type-ahead-get-section-overflow-item-key';
11
14
  import { QuickInsertMenuFooterItem } from './QuickInsertMenuFooterItem';
15
+ import { QuickInsertRecommendedSlot } from './QuickInsertRecommendedSlot';
12
16
  import { QuickInsertSectionOverflowMenuItem } from './QuickInsertSectionOverflowMenuItem';
17
+ import { createRecommendedSnapshotCache, MAX_RECOMMENDED_ITEMS, RECOMMENDED_SLOT_KEY_PREFIX } from './getRecommendedComponents';
13
18
  var categories = [{
14
19
  message: messages.categoryRecommended,
15
20
  section: RECOMMENDED_SECTION
@@ -51,14 +56,46 @@ var createSectionComponent = function createSectionComponent(message) {
51
56
  };
52
57
  export var getQuickInsertComponents = function getQuickInsertComponents(_ref2) {
53
58
  var api = _ref2.api,
54
- includeElementBrowserItems = _ref2.includeElementBrowserItems;
59
+ includeElementBrowserItems = _ref2.includeElementBrowserItems,
60
+ isRecommendedItem = _ref2.isRecommendedItem;
61
+ var recommendedSnapshot = createRecommendedSnapshotCache({
62
+ api: api,
63
+ isRecommendedItem: isRecommendedItem
64
+ });
65
+ var recommendedSlots = Array.from({
66
+ length: MAX_RECOMMENDED_ITEMS
67
+ }, function (_, index) {
68
+ return {
69
+ key: "".concat(RECOMMENDED_SLOT_KEY_PREFIX).concat(index),
70
+ type: 'menu-item',
71
+ parents: [{
72
+ key: RECOMMENDED_SECTION.key,
73
+ type: RECOMMENDED_SECTION.type,
74
+ rank: index
75
+ }],
76
+ match: function match() {
77
+ return null;
78
+ },
79
+ isHidden: function isHidden() {
80
+ var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
81
+ surfaceContext = _ref3.surfaceContext;
82
+ return !recommendedSnapshot.getSnapshot(surfaceContext)[index];
83
+ },
84
+ component: function component(props) {
85
+ return /*#__PURE__*/React.createElement(QuickInsertRecommendedSlot, _objectSpread(_objectSpread({}, props), {}, {
86
+ index: index,
87
+ getSnapshot: recommendedSnapshot.getSnapshot
88
+ }));
89
+ }
90
+ };
91
+ });
55
92
  return [{
56
93
  key: MENU.key,
57
94
  type: MENU.type,
58
95
  component: QuickInsertMenuRoot
59
- }].concat(_toConsumableArray(categories.flatMap(function (_ref3) {
60
- var message = _ref3.message,
61
- section = _ref3.section;
96
+ }].concat(recommendedSlots, _toConsumableArray(categories.flatMap(function (_ref4) {
97
+ var message = _ref4.message,
98
+ section = _ref4.section;
62
99
  return [{
63
100
  key: section.key,
64
101
  type: section.type,
@@ -67,8 +104,13 @@ export var getQuickInsertComponents = function getQuickInsertComponents(_ref2) {
67
104
  type: MENU.type,
68
105
  rank: QUICK_INSERT_MENU_RANK[section.key]
69
106
  }],
70
- component: createSectionComponent(message)
71
- }].concat(_toConsumableArray(includeElementBrowserItems ? [{
107
+ component: createSectionComponent(message),
108
+ isHidden: section.key === RECOMMENDED_SECTION.key ? function () {
109
+ var _ref5 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
110
+ surfaceContext = _ref5.surfaceContext;
111
+ return recommendedSnapshot.getSnapshot(surfaceContext).length === 0;
112
+ } : undefined
113
+ }].concat(_toConsumableArray(includeElementBrowserItems && section.key !== RECOMMENDED_SECTION.key ? [{
72
114
  key: getSectionOverflowItemKey(section.key),
73
115
  type: 'menu-item',
74
116
  parents: [{
@@ -0,0 +1,82 @@
1
+ import { MENU } from '@atlaskit/editor-common/quick-insert/keys';
2
+ import { isMenuFooterSectionKey } from '@atlaskit/editor-common/type-ahead-is-menu-footer-section-key';
3
+ import { isSectionOverflowItemKey } from '@atlaskit/editor-common/type-ahead-is-section-overflow-item-key';
4
+ import { defaultIsRecommendedItem } from '@atlaskit/editor-common/quick-insert/is-recommended-item';
5
+ import { logException } from '@atlaskit/editor-common/monitoring';
6
+ import { TYPE_AHEAD_SURFACE_CONTEXT } from '@atlaskit/editor-common/type-ahead-surface-context';
7
+ export var MAX_RECOMMENDED_ITEMS = 5;
8
+ export var RECOMMENDED_SLOT_KEY_PREFIX = 'quick-insert-recommended-slot-';
9
+ export var isRecommendedSlotKey = function isRecommendedSlotKey(key) {
10
+ return key.startsWith(RECOMMENDED_SLOT_KEY_PREFIX);
11
+ };
12
+ var isRecommendationCandidate = function isRecommendationCandidate(component) {
13
+ return component.type === 'menu-item' && !isRecommendedSlotKey(component.key) && !isSectionOverflowItemKey(component.key) && !component.parents.some(function (parent) {
14
+ return isMenuFooterSectionKey(parent.key);
15
+ });
16
+ };
17
+ export var getRecommendedComponents = function getRecommendedComponents(_ref) {
18
+ var components = _ref.components,
19
+ context = _ref.context,
20
+ _ref$isRecommendedIte = _ref.isRecommendedItem,
21
+ isRecommendedItem = _ref$isRecommendedIte === void 0 ? defaultIsRecommendedItem : _ref$isRecommendedIte;
22
+ return components.filter(isRecommendationCandidate).flatMap(function (component, index) {
23
+ var _component$isHidden;
24
+ var result = isRecommendedItem({
25
+ itemKey: component.key
26
+ });
27
+ if (result === null) {
28
+ return [];
29
+ }
30
+ if (Number.isNaN(result)) {
31
+ void logException(new Error('Invalid Quick Insert recommended item rank'), {
32
+ location: 'editor-plugin-quick-insert/getRecommendedComponents'
33
+ });
34
+ return [];
35
+ }
36
+ if ((_component$isHidden = component.isHidden) !== null && _component$isHidden !== void 0 && _component$isHidden.call(component, {
37
+ surfaceContext: context
38
+ })) {
39
+ return [];
40
+ }
41
+ return [{
42
+ component: component,
43
+ index: index,
44
+ rank: result
45
+ }];
46
+ }).sort(function (first, second) {
47
+ return first.rank === second.rank ? first.index - second.index : first.rank - second.rank;
48
+ }).slice(0, MAX_RECOMMENDED_ITEMS).map(function (_ref2) {
49
+ var component = _ref2.component;
50
+ return component;
51
+ });
52
+ };
53
+
54
+ /** Keeps only the current menu-open recommendation snapshot. */
55
+
56
+ export var createRecommendedSnapshotCache = function createRecommendedSnapshotCache(_ref3) {
57
+ var api = _ref3.api,
58
+ isRecommendedItem = _ref3.isRecommendedItem;
59
+ var snapshot;
60
+ var getSnapshot = function getSnapshot(surfaceContext) {
61
+ var _surfaceContext$get, _snapshot;
62
+ var menuOpenId = surfaceContext === null || surfaceContext === void 0 || (_surfaceContext$get = surfaceContext.get(TYPE_AHEAD_SURFACE_CONTEXT)) === null || _surfaceContext$get === void 0 ? void 0 : _surfaceContext$get.menuOpenId;
63
+ if (!surfaceContext || !menuOpenId) {
64
+ return [];
65
+ }
66
+ if (((_snapshot = snapshot) === null || _snapshot === void 0 ? void 0 : _snapshot.id) !== menuOpenId) {
67
+ var _api$uiControlRegistr, _api$uiControlRegistr2;
68
+ snapshot = {
69
+ id: menuOpenId,
70
+ items: getRecommendedComponents({
71
+ components: (_api$uiControlRegistr = api === null || api === void 0 || (_api$uiControlRegistr2 = api.uiControlRegistry) === null || _api$uiControlRegistr2 === void 0 ? void 0 : _api$uiControlRegistr2.actions.getComponents(MENU.key)) !== null && _api$uiControlRegistr !== void 0 ? _api$uiControlRegistr : [],
72
+ context: surfaceContext,
73
+ isRecommendedItem: isRecommendedItem
74
+ })
75
+ };
76
+ }
77
+ return snapshot.items;
78
+ };
79
+ return {
80
+ getSnapshot: getSnapshot
81
+ };
82
+ };
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import type { RegisterMenuItem, SurfaceContext } from '@atlaskit/editor-ui-control-model/types';
3
+ type Props = Record<string, unknown> & {
4
+ getSnapshot: (surfaceContext?: SurfaceContext) => RegisterMenuItem[];
5
+ index: number;
6
+ };
7
+ export declare const QuickInsertRecommendedSlot: ({ index, getSnapshot, ...props }: Props) => React.ReactNode;
8
+ export {};
@@ -1,9 +1,11 @@
1
1
  import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
2
2
  import type { RegisterComponent } from '@atlaskit/editor-ui-control-model/types';
3
+ import type { IsRecommendedItem } from '@atlaskit/editor-common/quick-insert/is-recommended-item';
3
4
  import type { QuickInsertPlugin } from '../quickInsertPluginType';
4
5
  type Params = {
5
6
  api: ExtractInjectionAPI<QuickInsertPlugin> | undefined;
6
7
  includeElementBrowserItems: boolean;
8
+ isRecommendedItem?: IsRecommendedItem;
7
9
  };
8
- export declare const getQuickInsertComponents: ({ api, includeElementBrowserItems, }: Params) => RegisterComponent[];
10
+ export declare const getQuickInsertComponents: ({ api, includeElementBrowserItems, isRecommendedItem, }: Params) => RegisterComponent[];
9
11
  export {};
@@ -0,0 +1,21 @@
1
+ import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
2
+ import { type IsRecommendedItem } from '@atlaskit/editor-common/quick-insert/is-recommended-item';
3
+ import type { RegisterComponent, RegisterMenuItem, SurfaceContext } from '@atlaskit/editor-ui-control-model/types';
4
+ import type { QuickInsertPlugin } from '../quickInsertPluginType';
5
+ export declare const MAX_RECOMMENDED_ITEMS = 5;
6
+ export declare const RECOMMENDED_SLOT_KEY_PREFIX = "quick-insert-recommended-slot-";
7
+ export declare const isRecommendedSlotKey: (key: string) => boolean;
8
+ export declare const getRecommendedComponents: ({ components, context, isRecommendedItem, }: {
9
+ components: RegisterComponent[];
10
+ context: SurfaceContext;
11
+ isRecommendedItem?: IsRecommendedItem;
12
+ }) => RegisterMenuItem[];
13
+ /** Keeps only the current menu-open recommendation snapshot. */
14
+ type RecommendedSnapshotCache = {
15
+ getSnapshot: (surfaceContext?: SurfaceContext) => RegisterMenuItem[];
16
+ };
17
+ export declare const createRecommendedSnapshotCache: ({ api, isRecommendedItem, }: {
18
+ api: ExtractInjectionAPI<QuickInsertPlugin> | undefined;
19
+ isRecommendedItem?: IsRecommendedItem;
20
+ }) => RecommendedSnapshotCache;
21
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-quick-insert",
3
- "version": "15.0.10",
3
+ "version": "15.1.0",
4
4
  "description": "Quick insert plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -28,7 +28,7 @@
28
28
  "@atlaskit/editor-plugin-type-ahead": "^16.1.0",
29
29
  "@atlaskit/editor-plugin-ui-control-registry": "^9.0.0",
30
30
  "@atlaskit/editor-prosemirror": "^8.0.0",
31
- "@atlaskit/editor-ui-control-model": "^2.7.0",
31
+ "@atlaskit/editor-ui-control-model": "^2.8.0",
32
32
  "@atlaskit/icon": "^37.5.0",
33
33
  "@atlaskit/modal-dialog": "^16.5.0",
34
34
  "@atlaskit/platform-feature-experiments": "^0.3.0",
@@ -39,7 +39,7 @@
39
39
  "@emotion/react": "^11.7.1"
40
40
  },
41
41
  "peerDependencies": {
42
- "@atlaskit/editor-common": "^119.13.0",
42
+ "@atlaskit/editor-common": "^119.14.0",
43
43
  "react": "^18.2.0 || ^19.2.0",
44
44
  "react-dom": "^18.2.0 || ^19.2.0",
45
45
  "react-intl": "^5.25.1 || ^6.0.0 || ^7.0.0"