@atlaskit/editor-plugin-quick-insert 30.0.2 → 30.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/cjs/quickInsertPlugin.js +6 -2
  3. package/dist/cjs/ui/getQuickInsertComponents.js +8 -53
  4. package/dist/cjs/ui/getRecommendedComponents.js +19 -38
  5. package/dist/cjs/ui/registered-menu/QuickInsertMenuRoot.js +4 -2
  6. package/dist/cjs/ui/registered-menu/RegisteredQuickInsertMenuItem.js +5 -3
  7. package/dist/cjs/ui/registered-menu/get-quick-insert-menu-model.js +175 -88
  8. package/dist/es2019/quickInsertPlugin.js +6 -2
  9. package/dist/es2019/ui/getQuickInsertComponents.js +6 -43
  10. package/dist/es2019/ui/getRecommendedComponents.js +17 -37
  11. package/dist/es2019/ui/registered-menu/QuickInsertMenuRoot.js +4 -2
  12. package/dist/es2019/ui/registered-menu/RegisteredQuickInsertMenuItem.js +5 -3
  13. package/dist/es2019/ui/registered-menu/get-quick-insert-menu-model.js +128 -55
  14. package/dist/esm/quickInsertPlugin.js +6 -2
  15. package/dist/esm/ui/getQuickInsertComponents.js +8 -53
  16. package/dist/esm/ui/getRecommendedComponents.js +18 -37
  17. package/dist/esm/ui/registered-menu/QuickInsertMenuRoot.js +4 -2
  18. package/dist/esm/ui/registered-menu/RegisteredQuickInsertMenuItem.js +5 -3
  19. package/dist/esm/ui/registered-menu/get-quick-insert-menu-model.js +176 -89
  20. package/dist/types/ui/getQuickInsertComponents.d.ts +3 -4
  21. package/dist/types/ui/getRecommendedComponents.d.ts +8 -13
  22. package/dist/types/ui/registered-menu/QuickInsertMenuRoot.d.ts +3 -1
  23. package/dist/types/ui/registered-menu/get-quick-insert-menu-model.d.ts +12 -2
  24. package/package.json +2 -2
  25. package/dist/cjs/ui/QuickInsertRecommendedSlot.js +0 -23
  26. package/dist/es2019/ui/QuickInsertRecommendedSlot.js +0 -18
  27. package/dist/esm/ui/QuickInsertRecommendedSlot.js +0 -16
  28. package/dist/types/ui/QuickInsertRecommendedSlot.d.ts +0 -8
@@ -17,6 +17,7 @@ import { pluginKey } from './pm-plugins/plugin-key';
17
17
  import { getBlockControlQuickInsertComponents } from './ui/block-control-quick-insert';
18
18
  import { getLegacyCompatibleComponents } from './ui/getLegacyCompatibleComponents';
19
19
  import { getQuickInsertComponents } from './ui/getQuickInsertComponents';
20
+ import { createRecommendedItemsResolver } from './ui/getRecommendedComponents';
20
21
  import ModalElementBrowser from './ui/ModalElementBrowser';
21
22
  import { RegistryElementBrowserContainer } from './ui/RegistryElementBrowser';
22
23
  import { getQuickInsertSuggestions, withLayoutQuickInsertPrioritySorting } from './ui/search';
@@ -31,6 +32,10 @@ export const quickInsertPlugin = ({
31
32
  };
32
33
  const typeAheadPrioritySortingFn = withLayoutQuickInsertPrioritySorting(options === null || options === void 0 ? void 0 : options.prioritySortingFn);
33
34
  const getItemRank = createQuickInsertRankResolver(options === null || options === void 0 ? void 0 : options.getItemRank);
35
+ const getRecommendedItems = createRecommendedItemsResolver({
36
+ isRecommendedItem: options === null || options === void 0 ? void 0 : options.isRecommendedItem,
37
+ maxRecommendedItems: options === null || options === void 0 ? void 0 : options.maxRecommendedItems
38
+ });
34
39
  const typeAhead = {
35
40
  id: TypeAheadAvailableNodes.QUICK_INSERT,
36
41
  registeredMenuKey: isExperimentEnabled('platform_editor_slash_command') ? MENU.key : undefined,
@@ -79,8 +84,7 @@ export const quickInsertPlugin = ({
79
84
  api === null || api === void 0 ? void 0 : (_api$uiControlRegistr = api.uiControlRegistry) === null || _api$uiControlRegistr === void 0 ? void 0 : _api$uiControlRegistr.actions.register(getQuickInsertComponents({
80
85
  api,
81
86
  getItemRank,
82
- isRecommendedItem: options === null || options === void 0 ? void 0 : options.isRecommendedItem,
83
- maxRecommendedItems: options === null || options === void 0 ? void 0 : options.maxRecommendedItems,
87
+ getRecommendedItems,
84
88
  emptyStateHandler: options === null || options === void 0 ? void 0 : options.emptyStateHandler,
85
89
  fireAnalyticsEvent: api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions.fireAnalyticsEvent,
86
90
  includeElementBrowserItems: (options === null || options === void 0 ? void 0 : options.enableElementBrowser) === true
@@ -5,9 +5,7 @@ import { messages } from '@atlaskit/editor-common/quick-insert/messages';
5
5
  import { CATEGORY_VIEW_MORE_RANK, QUICK_INSERT_MENU_RANK } from '@atlaskit/editor-common/quick-insert/rank';
6
6
  import { getMenuFooterSectionKey } from '@atlaskit/editor-common/type-ahead-get-menu-footer-section-key';
7
7
  import { getSectionOverflowItemKey } from '@atlaskit/editor-common/type-ahead-get-section-overflow-item-key';
8
- import { createRecommendedSnapshotCache, MAX_RECOMMENDED_ITEMS, RECOMMENDED_SLOT_KEY_PREFIX } from './getRecommendedComponents';
9
8
  import { QuickInsertMenuFooterItem } from './QuickInsertMenuFooterItem';
10
- import { QuickInsertRecommendedSlot } from './QuickInsertRecommendedSlot';
11
9
  import { QuickInsertSectionOverflowMenuItem } from './QuickInsertSectionOverflowMenuItem';
12
10
  import QuickInsertMenuRoot from './registered-menu/QuickInsertMenuRoot';
13
11
  import { QuickInsertMenuSection } from './registered-menu/QuickInsertMenuSection';
@@ -58,53 +56,21 @@ const createSectionComponent = message => {
58
56
  export const getQuickInsertComponents = ({
59
57
  api,
60
58
  includeElementBrowserItems,
61
- isRecommendedItem,
62
- maxRecommendedItems,
63
59
  getItemRank,
60
+ getRecommendedItems,
64
61
  emptyStateHandler,
65
62
  fireAnalyticsEvent
66
63
  }) => {
67
- const recommendedSnapshot = createRecommendedSnapshotCache({
68
- api,
69
- isRecommendedItem,
70
- maxRecommendedItems
71
- });
72
- const recommendedSlots = Array.from({
73
- length: MAX_RECOMMENDED_ITEMS
74
- }, (_, index) => ({
75
- key: `${RECOMMENDED_SLOT_KEY_PREFIX}${index}`,
76
- type: 'menu-item',
77
- parents: [{
78
- key: RECOMMENDED_SECTION.key,
79
- type: RECOMMENDED_SECTION.type,
80
- rank: index
81
- }],
82
- match: () => null,
83
- isHidden: ({
84
- surfaceContext
85
- } = {}) => !recommendedSnapshot.getSnapshot(surfaceContext)[index],
86
- component: ({
87
- children,
88
- parents,
89
- surfaceContext
90
- }) => /*#__PURE__*/React.createElement(QuickInsertRecommendedSlot, {
91
- parents: parents,
92
- surfaceContext: surfaceContext,
93
- index: index,
94
- getSnapshot: recommendedSnapshot.getSnapshot
95
- }, children)
96
- }));
97
64
  return [{
98
65
  key: MENU.key,
99
66
  type: MENU.type,
100
- component: ({
101
- children
102
- }) => /*#__PURE__*/React.createElement(QuickInsertMenuRoot, {
67
+ component: () => /*#__PURE__*/React.createElement(QuickInsertMenuRoot, {
103
68
  getItemRank: getItemRank,
69
+ getRecommendedItems: getRecommendedItems,
104
70
  emptyStateHandler: emptyStateHandler,
105
71
  fireAnalyticsEvent: fireAnalyticsEvent
106
- }, children)
107
- }, ...recommendedSlots, ...categories.flatMap(({
72
+ })
73
+ }, ...categories.flatMap(({
108
74
  message,
109
75
  section
110
76
  }) => [{
@@ -115,10 +81,7 @@ export const getQuickInsertComponents = ({
115
81
  type: MENU.type,
116
82
  rank: QUICK_INSERT_MENU_RANK[section.key]
117
83
  }],
118
- component: createSectionComponent(message),
119
- isHidden: section.key === RECOMMENDED_SECTION.key ? ({
120
- surfaceContext
121
- } = {}) => recommendedSnapshot.getSnapshot(surfaceContext).length === 0 : undefined
84
+ component: createSectionComponent(message)
122
85
  }, ...(includeElementBrowserItems && section.key !== RECOMMENDED_SECTION.key ? [{
123
86
  key: getSectionOverflowItemKey(section.key),
124
87
  type: 'menu-item',
@@ -1,22 +1,18 @@
1
1
  import { logException } from '@atlaskit/editor-common/monitoring/error';
2
2
  import { quickInsertProviderMenuItemKey } from '@atlaskit/editor-common/quick-insert/get-provider-menu-item-key';
3
3
  import { defaultIsRecommendedItem } from '@atlaskit/editor-common/quick-insert/is-recommended-item';
4
- import { MENU } from '@atlaskit/editor-common/quick-insert/keys';
5
- import { REGISTERED_MENU_SURFACE_CONTEXT } from '@atlaskit/editor-common/registered-menu/surface-context';
6
4
  import { isMenuFooterSectionKey } from '@atlaskit/editor-common/type-ahead-is-menu-footer-section-key';
7
5
  import { isSectionOverflowItemKey } from '@atlaskit/editor-common/type-ahead-is-section-overflow-item-key';
8
6
  export const MAX_RECOMMENDED_ITEMS = 5;
9
- export const RECOMMENDED_SLOT_KEY_PREFIX = 'quick-insert-recommended-slot-';
10
- export const isRecommendedSlotKey = key => key.startsWith(RECOMMENDED_SLOT_KEY_PREFIX);
11
- const isRecommendationCandidate = component => component.type === 'menu-item' && !isRecommendedSlotKey(component.key) && !isSectionOverflowItemKey(component.key) && !component.parents.some(parent => isMenuFooterSectionKey(parent.key));
7
+ const isRecommendationCandidate = component => component.type === 'menu-item' && !isSectionOverflowItemKey(component.key) && !component.parents.some(parent => isMenuFooterSectionKey(parent.key));
12
8
 
13
- /** Normalises a consumer-supplied limit to the number of available recommended slots. */
9
+ /** Normalises a consumer-supplied limit to the supported number of recommended items. */
14
10
  export const resolveMaxRecommendedItems = maxRecommendedItems => {
15
11
  if (maxRecommendedItems === undefined || !Number.isFinite(maxRecommendedItems)) {
16
12
  return MAX_RECOMMENDED_ITEMS;
17
13
  }
18
14
  if (maxRecommendedItems > MAX_RECOMMENDED_ITEMS) {
19
- void logException(new Error('Quick Insert maxRecommendedItems exceeds the available slots'), {
15
+ void logException(new Error('Quick Insert maxRecommendedItems exceeds the supported maximum'), {
20
16
  location: 'editor-plugin-quick-insert/getRecommendedComponents'
21
17
  });
22
18
  }
@@ -58,35 +54,19 @@ export const getRecommendedComponents = ({
58
54
  }) => component);
59
55
  };
60
56
 
61
- /** Keeps only the current menu-open recommendation snapshot. */
62
-
63
- export const createRecommendedSnapshotCache = ({
64
- api,
57
+ /**
58
+ * Resolves the Recommended section for a browse-mode menu. Callers memoise per components array,
59
+ * so the resolver itself keeps no state.
60
+ */
61
+ export const createRecommendedItemsResolver = ({
65
62
  isRecommendedItem,
66
63
  maxRecommendedItems
67
- }) => {
68
- let snapshot;
69
- const getSnapshot = surfaceContext => {
70
- var _surfaceContext$get, _snapshot;
71
- const menuOpenId = surfaceContext === null || surfaceContext === void 0 ? void 0 : (_surfaceContext$get = surfaceContext.get(REGISTERED_MENU_SURFACE_CONTEXT)) === null || _surfaceContext$get === void 0 ? void 0 : _surfaceContext$get.menuOpenId;
72
- if (!surfaceContext || !menuOpenId) {
73
- return [];
74
- }
75
- if (((_snapshot = snapshot) === null || _snapshot === void 0 ? void 0 : _snapshot.id) !== menuOpenId) {
76
- var _api$uiControlRegistr, _api$uiControlRegistr2;
77
- snapshot = {
78
- id: menuOpenId,
79
- items: getRecommendedComponents({
80
- 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 : [],
81
- context: surfaceContext,
82
- isRecommendedItem,
83
- maxRecommendedItems
84
- })
85
- };
86
- }
87
- return snapshot.items;
88
- };
89
- return {
90
- getSnapshot
91
- };
92
- };
64
+ }) => ({
65
+ components,
66
+ surfaceContext
67
+ }) => surfaceContext ? getRecommendedComponents({
68
+ components,
69
+ context: surfaceContext,
70
+ isRecommendedItem,
71
+ maxRecommendedItems
72
+ }) : [];
@@ -21,7 +21,8 @@ const isImeEnter = event => event.isComposing || event.keyCode === 229;
21
21
  const QuickInsertMenuRoot = ({
22
22
  emptyStateHandler,
23
23
  fireAnalyticsEvent,
24
- getItemRank
24
+ getItemRank,
25
+ getRecommendedItems
25
26
  }) => {
26
27
  var _surfaceContext$get, _registeredMenu$maxHe;
27
28
  const registeredMenu = useRegisteredMenuContext();
@@ -46,13 +47,14 @@ const QuickInsertMenuRoot = ({
46
47
  components,
47
48
  formatMessage,
48
49
  getItemRank: runtimeItemRank !== null && runtimeItemRank !== void 0 ? runtimeItemRank : getItemRank,
50
+ getRecommendedItems,
49
51
  query,
50
52
  rootComponent,
51
53
  selectCategoryItems: components.some(({
52
54
  key
53
55
  }) => isSectionOverflowItemKey(key)) ? selectQuickInsertCategoryItems : undefined,
54
56
  surfaceContext
55
- }), [components, formatMessage, getItemRank, query, rootComponent, runtimeItemRank, surfaceContext]);
57
+ }), [components, formatMessage, getItemRank, getRecommendedItems, query, rootComponent, runtimeItemRank, surfaceContext]);
56
58
  const resultCount = useMemo(() => model.sections.reduce((count, [, ...items]) => count + items.filter(({
57
59
  key
58
60
  }) => !isSectionOverflowItemKey(key)).length, 0), [model.sections]);
@@ -7,7 +7,6 @@ export const RegisteredQuickInsertMenuItem = ({
7
7
  isActive,
8
8
  registration
9
9
  }) => {
10
- var _registration$compone;
11
10
  const {
12
11
  editorView,
13
12
  isOffline,
@@ -27,8 +26,11 @@ export const RegisteredQuickInsertMenuItem = ({
27
26
  select,
28
27
  surfaceContext
29
28
  }), [editorView, isOffline, popupsMountPoint, select, surfaceContext, isActive, id, isSelected]);
30
- const Component = (_registration$compone = registration.component) !== null && _registration$compone !== void 0 ? _registration$compone : React.Fragment;
29
+ const Component = registration.component;
31
30
  return /*#__PURE__*/React.createElement(QuickInsertProvider, {
32
31
  value: value
33
- }, /*#__PURE__*/React.createElement(Component, null, null));
32
+ }, Component ? /*#__PURE__*/React.createElement(Component, {
33
+ parents: registration.parents,
34
+ surfaceContext: surfaceContext
35
+ }, null) : null);
34
36
  };
@@ -1,4 +1,4 @@
1
- import { ASK_ROVO_MENU_ITEM, MENU, SEARCH_RESULTS_SECTION } from '@atlaskit/editor-common/quick-insert/keys';
1
+ import { ASK_ROVO_MENU_ITEM, MENU, RECOMMENDED_SECTION, SEARCH_RESULTS_SECTION } from '@atlaskit/editor-common/quick-insert/keys';
2
2
  import { applyRegisteredItemRanks } from '@atlaskit/editor-common/registered-menu/item-rank';
3
3
  import { isMenuFooterSectionKey } from '@atlaskit/editor-common/type-ahead-is-menu-footer-section-key';
4
4
  import { isSectionOverflowItemKey } from '@atlaskit/editor-common/type-ahead-is-section-overflow-item-key';
@@ -30,38 +30,81 @@ const getSearchResults = matches => {
30
30
  const topMatchIdentities = new Set(topMatches.map(({
31
31
  identity
32
32
  }) => identity));
33
- const tailMatches = matches.filter(({
33
+ return [...topMatches, ...matches.filter(({
34
34
  identity
35
- }) => !topMatchIdentities.has(identity));
36
- return [...topMatches, ...tailMatches].map(({
37
- item
38
- }) => item);
35
+ }) => !topMatchIdentities.has(identity))];
39
36
  };
40
- const getRenderedMenuItems = (section, childrenMap, surfaceContext) => {
41
- var _childrenMap$get;
42
- return ((_childrenMap$get = childrenMap.get(getComponentIdentity(section))) !== null && _childrenMap$get !== void 0 ? _childrenMap$get : []).filter(child => child.type === 'menu-item' && willComponentRender(child, childrenMap, surfaceContext));
37
+
38
+ /** Recommended uses resolved items rather than registered children. */
39
+ const readMenuSections = ({
40
+ childrenMap,
41
+ recommendedItems = [],
42
+ sections,
43
+ surfaceContext
44
+ }) => {
45
+ const renderedSections = [];
46
+ for (const section of sections) {
47
+ var _section$isHidden, _section$isHidden2, _childrenMap$get;
48
+ if (section.type !== 'menu-section') {
49
+ continue;
50
+ }
51
+ if (surfaceContext ? (_section$isHidden = section.isHidden) === null || _section$isHidden === void 0 ? void 0 : _section$isHidden.call(section, {
52
+ surfaceContext
53
+ }) : (_section$isHidden2 = section.isHidden) === null || _section$isHidden2 === void 0 ? void 0 : _section$isHidden2.call(section)) {
54
+ continue;
55
+ }
56
+ if (section.key === RECOMMENDED_SECTION.key) {
57
+ renderedSections.push({
58
+ section,
59
+ items: recommendedItems
60
+ });
61
+ continue;
62
+ }
63
+ const children = (_childrenMap$get = childrenMap.get(getComponentIdentity(section))) !== null && _childrenMap$get !== void 0 ? _childrenMap$get : [];
64
+ const items = [];
65
+ let viewMoreItem;
66
+ for (const child of children) {
67
+ if (child.type !== 'menu-item' || !willComponentRender(child, childrenMap, surfaceContext)) {
68
+ continue;
69
+ }
70
+ if (isSectionOverflowItemKey(child.key)) {
71
+ viewMoreItem ??= child;
72
+ } else {
73
+ items.push(child);
74
+ }
75
+ }
76
+ // Empty registrations are visible leaves; containers need a visible child.
77
+ if (children.length === 0 || items.length > 0 || viewMoreItem) {
78
+ renderedSections.push({
79
+ section,
80
+ items,
81
+ viewMoreItem
82
+ });
83
+ }
84
+ }
85
+ return renderedSections;
86
+ };
87
+ const getOwnerSectionKey = (item, isRecommendedItem) => {
88
+ var _item$parents$;
89
+ return isRecommendedItem(item) ? RECOMMENDED_SECTION.key : (_item$parents$ = item.parents[0]) === null || _item$parents$ === void 0 ? void 0 : _item$parents$.key;
43
90
  };
44
91
  const buildBrowseSections = ({
45
- childrenMap,
46
92
  contentSections,
47
- selectCategoryItems,
48
- surfaceContext
93
+ isRecommendedItem,
94
+ selectCategoryItems
49
95
  }) => {
50
96
  const sections = [];
51
- for (const section of contentSections) {
52
- const children = getRenderedMenuItems(section, childrenMap, surfaceContext);
53
- const overflowItems = children.filter(child => isSectionOverflowItemKey(child.key));
54
- const viewMoreItem = overflowItems[overflowItems.length - 1];
55
- const items = children.filter(child => !isSectionOverflowItemKey(child.key));
56
- if (items.length === 0) {
97
+ for (const {
98
+ items,
99
+ section,
100
+ viewMoreItem
101
+ } of contentSections) {
102
+ const ownedItems = items.filter(item => getOwnerSectionKey(item, isRecommendedItem) === section.key);
103
+ if (ownedItems.length === 0) {
57
104
  continue;
58
105
  }
59
- const selectedItems = viewMoreItem !== undefined && selectCategoryItems !== undefined ? selectCategoryItems(items) : items;
60
- if (selectedItems.length < items.length && viewMoreItem !== undefined) {
61
- sections.push([section, ...selectedItems, viewMoreItem]);
62
- } else {
63
- sections.push([section, ...selectedItems]);
64
- }
106
+ const selectedItems = viewMoreItem && selectCategoryItems ? selectCategoryItems(ownedItems) : ownedItems;
107
+ sections.push([section, ...selectedItems, ...(viewMoreItem && selectedItems.length < ownedItems.length ? [viewMoreItem] : [])]);
65
108
  }
66
109
  return {
67
110
  fallbackItems: [],
@@ -69,38 +112,42 @@ const buildBrowseSections = ({
69
112
  };
70
113
  };
71
114
  const buildSearchSections = ({
72
- childrenMap,
73
115
  components,
74
116
  contentSections,
75
117
  formatMessage,
118
+ isRecommendedItem,
76
119
  query,
77
- root,
78
- surfaceContext
120
+ root
79
121
  }) => {
80
- const matches = new Map();
81
122
  const sourceIndexByComponent = new Map(components.map((component, index) => [component, index]));
82
- for (const section of contentSections) {
83
- for (const item of getRenderedMenuItems(section, childrenMap, surfaceContext)) {
123
+ const matches = new Map();
124
+ let fallbackItem;
125
+ for (const {
126
+ items,
127
+ section
128
+ } of contentSections) {
129
+ const sectionRank = getParentRank(section, root.key);
130
+ for (const item of items) {
84
131
  var _item$match, _match$score, _sourceIndexByCompone;
85
- if (isSectionOverflowItemKey(item.key)) {
86
- continue;
132
+ if (item.key === ASK_ROVO_MENU_ITEM.key) {
133
+ fallbackItem ??= item;
87
134
  }
88
135
  const match = (_item$match = item.match) === null || _item$match === void 0 ? void 0 : _item$match.call(item, {
89
136
  formatMessage,
90
137
  itemKey: item.key,
91
138
  query
92
139
  });
93
- if (item.match && match === null) {
140
+ if (item.match && match === null || getOwnerSectionKey(item, isRecommendedItem) !== section.key) {
94
141
  continue;
95
142
  }
96
143
  const candidate = {
97
- identity: `${item.type}:${item.key}`,
144
+ identity: getComponentIdentity(item),
98
145
  item,
99
146
  itemRank: getParentRank(item, section.key),
100
147
  priorityGroup: (match === null || match === void 0 ? void 0 : match.priorityGroup) !== undefined && Number.isFinite(match.priorityGroup) ? match.priorityGroup : undefined,
101
148
  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)),
102
- sourceIndex: (_sourceIndexByCompone = sourceIndexByComponent.get(item)) !== null && _sourceIndexByCompone !== void 0 ? _sourceIndexByCompone : Number.MAX_SAFE_INTEGER,
103
- sectionRank: getParentRank(section, root.key)
149
+ sectionRank,
150
+ sourceIndex: (_sourceIndexByCompone = sourceIndexByComponent.get(item)) !== null && _sourceIndexByCompone !== void 0 ? _sourceIndexByCompone : Number.MAX_SAFE_INTEGER
104
151
  };
105
152
  const existing = matches.get(candidate.identity);
106
153
  if (!existing || compareMatchedItems(candidate, existing) < 0) {
@@ -117,23 +164,26 @@ const buildSearchSections = ({
117
164
  }) => priorityGroup === undefined);
118
165
  const orderedSearchResults = [...prioritizedMatches.sort(comparePrioritizedSearchResults).map(({
119
166
  item
120
- }) => item), ...getSearchResults(unprioritizedMatches)];
167
+ }) => item), ...getSearchResults(unprioritizedMatches).map(({
168
+ item
169
+ }) => item)];
121
170
  if (orderedSearchResults.length > 0) {
122
171
  return {
123
172
  fallbackItems: [],
124
173
  sections: [[SEARCH_RESULTS_HEADING, ...orderedSearchResults]]
125
174
  };
126
175
  }
127
- const fallbackItem = contentSections.flatMap(section => {
128
- var _childrenMap$get2;
129
- return (_childrenMap$get2 = childrenMap.get(getComponentIdentity(section))) !== null && _childrenMap$get2 !== void 0 ? _childrenMap$get2 : [];
130
- }).find(component => component.type === ASK_ROVO_MENU_ITEM.type && component.key === ASK_ROVO_MENU_ITEM.key && willComponentRender(component, childrenMap, surfaceContext));
131
176
  return {
132
177
  fallbackItems: fallbackItem ? [fallbackItem] : [],
133
178
  sections: []
134
179
  };
135
180
  };
136
181
 
182
+ /**
183
+ * Resolves the Recommended items for a browse. Receives the unranked components so a resolver
184
+ * can look recommendations up by their registered keys.
185
+ */
186
+
137
187
  /**
138
188
  * Builds the registered quick-insert menu model. An empty query browses every
139
189
  * category; a non-empty query returns ranked matches. The footer is shared by both.
@@ -142,18 +192,40 @@ export const getQuickInsertMenuModel = ({
142
192
  components,
143
193
  formatMessage,
144
194
  getItemRank,
195
+ getRecommendedItems,
145
196
  query,
146
197
  rootComponent,
147
198
  selectCategoryItems,
148
199
  surfaceContext
149
200
  }) => {
201
+ var _root$isHidden, _root$isHidden2, _contentSections$find;
150
202
  const rankedComponents = applyRegisteredItemRanks(components, getItemRank);
151
203
  const {
152
204
  childrenMap,
153
205
  root,
154
206
  topLevelChildren = []
155
207
  } = resolveSurface(rankedComponents, rootComponent);
156
- if (!root || !willComponentRender(root, childrenMap, surfaceContext)) {
208
+ if (!root || (surfaceContext ? (_root$isHidden = root.isHidden) === null || _root$isHidden === void 0 ? void 0 : _root$isHidden.call(root, {
209
+ surfaceContext
210
+ }) : (_root$isHidden2 = root.isHidden) === null || _root$isHidden2 === void 0 ? void 0 : _root$isHidden2.call(root))) {
211
+ return {
212
+ fallbackItems: [],
213
+ footer: undefined,
214
+ root: undefined,
215
+ sections: []
216
+ };
217
+ }
218
+ const isBrowse = query === '';
219
+ const renderedSections = readMenuSections({
220
+ sections: topLevelChildren,
221
+ childrenMap,
222
+ surfaceContext,
223
+ recommendedItems: isBrowse ? getRecommendedItems === null || getRecommendedItems === void 0 ? void 0 : getRecommendedItems({
224
+ components,
225
+ surfaceContext
226
+ }) : undefined
227
+ });
228
+ if (topLevelChildren.length > 0 && renderedSections.length === 0) {
157
229
  return {
158
230
  fallbackItems: [],
159
231
  footer: undefined,
@@ -161,28 +233,29 @@ export const getQuickInsertMenuModel = ({
161
233
  sections: []
162
234
  };
163
235
  }
164
- const renderedSections = topLevelChildren.filter(section => section.type === 'menu-section' && willComponentRender(section, childrenMap, surfaceContext));
165
236
  const footerSection = renderedSections.find(({
166
- key
167
- }) => isMenuFooterSectionKey(key));
237
+ section
238
+ }) => isMenuFooterSectionKey(section.key));
168
239
  const contentSections = renderedSections.filter(({
169
- key
170
- }) => !isMenuFooterSectionKey(key));
171
- const content = query === '' ? buildBrowseSections({
172
- childrenMap,
240
+ section
241
+ }) => !isMenuFooterSectionKey(section.key) && (isBrowse || section.key !== RECOMMENDED_SECTION.key));
242
+ const recommendedIdentities = new Set((_contentSections$find = contentSections.find(({
243
+ section
244
+ }) => section.key === RECOMMENDED_SECTION.key)) === null || _contentSections$find === void 0 ? void 0 : _contentSections$find.items.map(getComponentIdentity));
245
+ const isRecommendedItem = item => recommendedIdentities.has(getComponentIdentity(item));
246
+ const content = isBrowse ? buildBrowseSections({
173
247
  contentSections,
174
- selectCategoryItems,
175
- surfaceContext
248
+ isRecommendedItem,
249
+ selectCategoryItems
176
250
  }) : buildSearchSections({
177
- childrenMap,
178
251
  components: rankedComponents,
179
252
  contentSections,
180
253
  formatMessage,
254
+ isRecommendedItem,
181
255
  query,
182
- root,
183
- surfaceContext
256
+ root
184
257
  });
185
- const footer = footerSection ? getRenderedMenuItems(footerSection, childrenMap, surfaceContext)[0] : undefined;
258
+ const footer = footerSection === null || footerSection === void 0 ? void 0 : footerSection.items[0];
186
259
  return {
187
260
  ...content,
188
261
  footer,
@@ -23,6 +23,7 @@ import { pluginKey } from './pm-plugins/plugin-key';
23
23
  import { getBlockControlQuickInsertComponents } from './ui/block-control-quick-insert';
24
24
  import { getLegacyCompatibleComponents } from './ui/getLegacyCompatibleComponents';
25
25
  import { getQuickInsertComponents } from './ui/getQuickInsertComponents';
26
+ import { createRecommendedItemsResolver } from './ui/getRecommendedComponents';
26
27
  import ModalElementBrowser from './ui/ModalElementBrowser';
27
28
  import { RegistryElementBrowserContainer } from './ui/RegistryElementBrowser';
28
29
  import { getQuickInsertSuggestions, withLayoutQuickInsertPrioritySorting } from './ui/search';
@@ -36,6 +37,10 @@ export var quickInsertPlugin = function quickInsertPlugin(_ref) {
36
37
  };
37
38
  var typeAheadPrioritySortingFn = withLayoutQuickInsertPrioritySorting(options === null || options === void 0 ? void 0 : options.prioritySortingFn);
38
39
  var getItemRank = createQuickInsertRankResolver(options === null || options === void 0 ? void 0 : options.getItemRank);
40
+ var getRecommendedItems = createRecommendedItemsResolver({
41
+ isRecommendedItem: options === null || options === void 0 ? void 0 : options.isRecommendedItem,
42
+ maxRecommendedItems: options === null || options === void 0 ? void 0 : options.maxRecommendedItems
43
+ });
39
44
  var typeAhead = {
40
45
  id: TypeAheadAvailableNodes.QUICK_INSERT,
41
46
  registeredMenuKey: isExperimentEnabled('platform_editor_slash_command') ? MENU.key : undefined,
@@ -84,8 +89,7 @@ export var quickInsertPlugin = function quickInsertPlugin(_ref) {
84
89
  api === null || api === void 0 || (_api$uiControlRegistr = api.uiControlRegistry) === null || _api$uiControlRegistr === void 0 || _api$uiControlRegistr.actions.register(getQuickInsertComponents({
85
90
  api: api,
86
91
  getItemRank: getItemRank,
87
- isRecommendedItem: options === null || options === void 0 ? void 0 : options.isRecommendedItem,
88
- maxRecommendedItems: options === null || options === void 0 ? void 0 : options.maxRecommendedItems,
92
+ getRecommendedItems: getRecommendedItems,
89
93
  emptyStateHandler: options === null || options === void 0 ? void 0 : options.emptyStateHandler,
90
94
  fireAnalyticsEvent: api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions.fireAnalyticsEvent,
91
95
  includeElementBrowserItems: (options === null || options === void 0 ? void 0 : options.enableElementBrowser) === true
@@ -6,9 +6,7 @@ import { messages } from '@atlaskit/editor-common/quick-insert/messages';
6
6
  import { CATEGORY_VIEW_MORE_RANK, QUICK_INSERT_MENU_RANK } from '@atlaskit/editor-common/quick-insert/rank';
7
7
  import { getMenuFooterSectionKey } from '@atlaskit/editor-common/type-ahead-get-menu-footer-section-key';
8
8
  import { getSectionOverflowItemKey } from '@atlaskit/editor-common/type-ahead-get-section-overflow-item-key';
9
- import { createRecommendedSnapshotCache, MAX_RECOMMENDED_ITEMS, RECOMMENDED_SLOT_KEY_PREFIX } from './getRecommendedComponents';
10
9
  import { QuickInsertMenuFooterItem } from './QuickInsertMenuFooterItem';
11
- import { QuickInsertRecommendedSlot } from './QuickInsertRecommendedSlot';
12
10
  import { QuickInsertSectionOverflowMenuItem } from './QuickInsertSectionOverflowMenuItem';
13
11
  import QuickInsertMenuRoot from './registered-menu/QuickInsertMenuRoot';
14
12
  import { QuickInsertMenuSection } from './registered-menu/QuickInsertMenuSection';
@@ -57,62 +55,24 @@ var createSectionComponent = function createSectionComponent(message) {
57
55
  export var getQuickInsertComponents = function getQuickInsertComponents(_ref2) {
58
56
  var api = _ref2.api,
59
57
  includeElementBrowserItems = _ref2.includeElementBrowserItems,
60
- isRecommendedItem = _ref2.isRecommendedItem,
61
- maxRecommendedItems = _ref2.maxRecommendedItems,
62
58
  getItemRank = _ref2.getItemRank,
59
+ getRecommendedItems = _ref2.getRecommendedItems,
63
60
  emptyStateHandler = _ref2.emptyStateHandler,
64
61
  fireAnalyticsEvent = _ref2.fireAnalyticsEvent;
65
- var recommendedSnapshot = createRecommendedSnapshotCache({
66
- api: api,
67
- isRecommendedItem: isRecommendedItem,
68
- maxRecommendedItems: maxRecommendedItems
69
- });
70
- var recommendedSlots = Array.from({
71
- length: MAX_RECOMMENDED_ITEMS
72
- }, function (_, index) {
73
- return {
74
- key: "".concat(RECOMMENDED_SLOT_KEY_PREFIX).concat(index),
75
- type: 'menu-item',
76
- parents: [{
77
- key: RECOMMENDED_SECTION.key,
78
- type: RECOMMENDED_SECTION.type,
79
- rank: index
80
- }],
81
- match: function match() {
82
- return null;
83
- },
84
- isHidden: function isHidden() {
85
- var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
86
- surfaceContext = _ref3.surfaceContext;
87
- return !recommendedSnapshot.getSnapshot(surfaceContext)[index];
88
- },
89
- component: function component(_ref4) {
90
- var children = _ref4.children,
91
- parents = _ref4.parents,
92
- surfaceContext = _ref4.surfaceContext;
93
- return /*#__PURE__*/React.createElement(QuickInsertRecommendedSlot, {
94
- parents: parents,
95
- surfaceContext: surfaceContext,
96
- index: index,
97
- getSnapshot: recommendedSnapshot.getSnapshot
98
- }, children);
99
- }
100
- };
101
- });
102
62
  return [{
103
63
  key: MENU.key,
104
64
  type: MENU.type,
105
- component: function component(_ref5) {
106
- var children = _ref5.children;
65
+ component: function component() {
107
66
  return /*#__PURE__*/React.createElement(QuickInsertMenuRoot, {
108
67
  getItemRank: getItemRank,
68
+ getRecommendedItems: getRecommendedItems,
109
69
  emptyStateHandler: emptyStateHandler,
110
70
  fireAnalyticsEvent: fireAnalyticsEvent
111
- }, children);
71
+ });
112
72
  }
113
- }].concat(recommendedSlots, _toConsumableArray(categories.flatMap(function (_ref6) {
114
- var message = _ref6.message,
115
- section = _ref6.section;
73
+ }].concat(_toConsumableArray(categories.flatMap(function (_ref3) {
74
+ var message = _ref3.message,
75
+ section = _ref3.section;
116
76
  return [{
117
77
  key: section.key,
118
78
  type: section.type,
@@ -121,12 +81,7 @@ export var getQuickInsertComponents = function getQuickInsertComponents(_ref2) {
121
81
  type: MENU.type,
122
82
  rank: QUICK_INSERT_MENU_RANK[section.key]
123
83
  }],
124
- component: createSectionComponent(message),
125
- isHidden: section.key === RECOMMENDED_SECTION.key ? function () {
126
- var _ref7 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
127
- surfaceContext = _ref7.surfaceContext;
128
- return recommendedSnapshot.getSnapshot(surfaceContext).length === 0;
129
- } : undefined
84
+ component: createSectionComponent(message)
130
85
  }].concat(_toConsumableArray(includeElementBrowserItems && section.key !== RECOMMENDED_SECTION.key ? [{
131
86
  key: getSectionOverflowItemKey(section.key),
132
87
  type: 'menu-item',