@atlaskit/editor-plugin-quick-insert 29.0.4 → 30.0.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.
Files changed (87) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/cjs/quickInsertPlugin.js +10 -5
  3. package/dist/cjs/ui/QuickInsertRecommendedSlot.js +11 -8
  4. package/dist/cjs/ui/RegistryElementBrowser/RegistryElementBrowser.js +31 -7
  5. package/dist/cjs/ui/RegistryElementBrowser/RegistryElementBrowserSearchResults.js +13 -7
  6. package/dist/cjs/ui/RegistryElementBrowser/model.js +14 -15
  7. package/dist/cjs/ui/getQuickInsertComponents.js +28 -16
  8. package/dist/cjs/ui/getRecommendedComponents.js +2 -2
  9. package/dist/cjs/ui/registered-menu/QuickInsertEmptyState.compiled.css +11 -0
  10. package/dist/cjs/ui/registered-menu/QuickInsertEmptyState.js +61 -0
  11. package/dist/cjs/ui/registered-menu/QuickInsertMenuRoot.js +220 -0
  12. package/dist/cjs/ui/registered-menu/QuickInsertMenuSection.js +23 -0
  13. package/dist/cjs/ui/registered-menu/QuickInsertSearchResultsSection.js +19 -0
  14. package/dist/cjs/ui/registered-menu/RegisteredQuickInsertMenuItem.js +42 -0
  15. package/dist/cjs/ui/registered-menu/ToolbarQuickInsertMenu.compiled.css +11 -0
  16. package/dist/cjs/ui/registered-menu/ToolbarQuickInsertMenu.js +128 -0
  17. package/dist/cjs/ui/registered-menu/TypeAheadQuickInsertMenu.compiled.css +3 -0
  18. package/dist/cjs/ui/registered-menu/TypeAheadQuickInsertMenu.js +90 -0
  19. package/dist/cjs/ui/registered-menu/assets/no-results.js +36 -0
  20. package/dist/cjs/ui/registered-menu/get-quick-insert-menu-model.js +237 -0
  21. package/dist/cjs/ui/registered-menu/getQuickInsertMenuItemId.js +9 -0
  22. package/dist/cjs/ui/registered-menu/selectQuickInsertCategoryItems.js +27 -0
  23. package/dist/cjs/ui/registered-menu/useQuickInsertSearchAnalytics.js +100 -0
  24. package/dist/es2019/quickInsertPlugin.js +10 -5
  25. package/dist/es2019/ui/QuickInsertRecommendedSlot.js +10 -5
  26. package/dist/es2019/ui/RegistryElementBrowser/RegistryElementBrowser.js +19 -2
  27. package/dist/es2019/ui/RegistryElementBrowser/RegistryElementBrowserSearchResults.js +12 -7
  28. package/dist/es2019/ui/RegistryElementBrowser/model.js +12 -13
  29. package/dist/es2019/ui/getQuickInsertComponents.js +24 -10
  30. package/dist/es2019/ui/getRecommendedComponents.js +2 -2
  31. package/dist/es2019/ui/registered-menu/QuickInsertEmptyState.compiled.css +11 -0
  32. package/dist/es2019/ui/registered-menu/QuickInsertEmptyState.js +47 -0
  33. package/dist/es2019/ui/registered-menu/QuickInsertMenuRoot.js +191 -0
  34. package/dist/es2019/ui/registered-menu/QuickInsertMenuSection.js +15 -0
  35. package/dist/es2019/ui/registered-menu/QuickInsertSearchResultsSection.js +14 -0
  36. package/dist/es2019/ui/registered-menu/RegisteredQuickInsertMenuItem.js +34 -0
  37. package/dist/es2019/ui/registered-menu/ToolbarQuickInsertMenu.compiled.css +11 -0
  38. package/dist/es2019/ui/registered-menu/ToolbarQuickInsertMenu.js +116 -0
  39. package/dist/es2019/ui/registered-menu/TypeAheadQuickInsertMenu.compiled.css +3 -0
  40. package/dist/es2019/ui/registered-menu/TypeAheadQuickInsertMenu.js +78 -0
  41. package/dist/es2019/ui/registered-menu/assets/no-results.js +30 -0
  42. package/dist/es2019/ui/registered-menu/get-quick-insert-menu-model.js +177 -0
  43. package/dist/es2019/ui/registered-menu/getQuickInsertMenuItemId.js +1 -0
  44. package/dist/es2019/ui/registered-menu/selectQuickInsertCategoryItems.js +19 -0
  45. package/dist/es2019/ui/registered-menu/useQuickInsertSearchAnalytics.js +91 -0
  46. package/dist/esm/quickInsertPlugin.js +10 -5
  47. package/dist/esm/ui/QuickInsertRecommendedSlot.js +11 -8
  48. package/dist/esm/ui/RegistryElementBrowser/RegistryElementBrowser.js +30 -6
  49. package/dist/esm/ui/RegistryElementBrowser/RegistryElementBrowserSearchResults.js +12 -7
  50. package/dist/esm/ui/RegistryElementBrowser/model.js +14 -15
  51. package/dist/esm/ui/getQuickInsertComponents.js +27 -15
  52. package/dist/esm/ui/getRecommendedComponents.js +2 -2
  53. package/dist/esm/ui/registered-menu/QuickInsertEmptyState.compiled.css +11 -0
  54. package/dist/esm/ui/registered-menu/QuickInsertEmptyState.js +50 -0
  55. package/dist/esm/ui/registered-menu/QuickInsertMenuRoot.js +211 -0
  56. package/dist/esm/ui/registered-menu/QuickInsertMenuSection.js +16 -0
  57. package/dist/esm/ui/registered-menu/QuickInsertSearchResultsSection.js +12 -0
  58. package/dist/esm/ui/registered-menu/RegisteredQuickInsertMenuItem.js +34 -0
  59. package/dist/esm/ui/registered-menu/ToolbarQuickInsertMenu.compiled.css +11 -0
  60. package/dist/esm/ui/registered-menu/ToolbarQuickInsertMenu.js +120 -0
  61. package/dist/esm/ui/registered-menu/TypeAheadQuickInsertMenu.compiled.css +3 -0
  62. package/dist/esm/ui/registered-menu/TypeAheadQuickInsertMenu.js +82 -0
  63. package/dist/esm/ui/registered-menu/assets/no-results.js +29 -0
  64. package/dist/esm/ui/registered-menu/get-quick-insert-menu-model.js +230 -0
  65. package/dist/esm/ui/registered-menu/getQuickInsertMenuItemId.js +3 -0
  66. package/dist/esm/ui/registered-menu/selectQuickInsertCategoryItems.js +21 -0
  67. package/dist/esm/ui/registered-menu/useQuickInsertSearchAnalytics.js +93 -0
  68. package/dist/types/quickInsertPluginType.d.ts +1 -1
  69. package/dist/types/ui/QuickInsertRecommendedSlot.d.ts +3 -3
  70. package/dist/types/ui/RegistryElementBrowser/RegistryElementBrowserSearchResults.d.ts +5 -2
  71. package/dist/types/ui/RegistryElementBrowser/model.d.ts +3 -2
  72. package/dist/types/ui/getQuickInsertComponents.d.ts +8 -2
  73. package/dist/types/ui/registered-menu/QuickInsertEmptyState.d.ts +7 -0
  74. package/dist/types/ui/registered-menu/QuickInsertMenuRoot.d.ts +11 -0
  75. package/dist/types/ui/registered-menu/QuickInsertMenuSection.d.ts +4 -0
  76. package/dist/types/ui/registered-menu/QuickInsertSearchResultsSection.d.ts +2 -0
  77. package/dist/types/ui/registered-menu/RegisteredQuickInsertMenuItem.d.ts +3 -0
  78. package/dist/types/ui/registered-menu/ToolbarQuickInsertMenu.d.ts +28 -0
  79. package/dist/types/ui/registered-menu/TypeAheadQuickInsertMenu.d.ts +27 -0
  80. package/dist/types/ui/registered-menu/assets/no-results.d.ts +7 -0
  81. package/dist/types/ui/registered-menu/get-quick-insert-menu-model.d.ts +19 -0
  82. package/dist/types/ui/registered-menu/getQuickInsertMenuItemId.d.ts +1 -0
  83. package/dist/types/ui/registered-menu/selectQuickInsertCategoryItems.d.ts +7 -0
  84. package/dist/types/ui/registered-menu/useQuickInsertSearchAnalytics.d.ts +12 -0
  85. package/package.json +14 -11
  86. package/registered-menu/model/package.json +10 -0
  87. package/registered-menu/search-analytics/package.json +10 -0
@@ -0,0 +1,177 @@
1
+ import { ASK_ROVO_MENU_ITEM, MENU, SEARCH_RESULTS_SECTION } from '@atlaskit/editor-common/quick-insert/keys';
2
+ import { applyRegisteredItemRanks } from '@atlaskit/editor-common/registered-menu/item-rank';
3
+ import { isMenuFooterSectionKey } from '@atlaskit/editor-common/type-ahead-is-menu-footer-section-key';
4
+ import { isSectionOverflowItemKey } from '@atlaskit/editor-common/type-ahead-is-section-overflow-item-key';
5
+ import { getComponentIdentity, resolveSurface, willComponentRender } from '@atlaskit/editor-ui-control-model/surface-renderer';
6
+ import { QuickInsertSearchResultsSection } from './QuickInsertSearchResultsSection';
7
+ const SEARCH_TOP_MATCH_LIMIT = 5;
8
+ const SEARCH_RESULTS_HEADING = {
9
+ key: SEARCH_RESULTS_SECTION.key,
10
+ type: SEARCH_RESULTS_SECTION.type,
11
+ component: QuickInsertSearchResultsSection,
12
+ parents: [{
13
+ key: MENU.key,
14
+ type: MENU.type,
15
+ rank: 0
16
+ }]
17
+ };
18
+ const getParentRank = (component, parentKey) => {
19
+ var _component$parents$fi, _component$parents, _component$parents$fi2;
20
+ 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;
21
+ };
22
+ const compareMatchedItems = (a, b) => a.sectionRank - b.sectionRank || a.score - b.score || a.itemRank - b.itemRank || a.sourceIndex - b.sourceIndex || a.identity.localeCompare(b.identity);
23
+ const compareSearchResults = (a, b) => a.score - b.score || a.sectionRank - b.sectionRank || a.itemRank - b.itemRank || a.sourceIndex - b.sourceIndex || a.identity.localeCompare(b.identity);
24
+ const getSearchResults = matches => {
25
+ const topMatches = Array.from(matches).sort(compareSearchResults).slice(0, SEARCH_TOP_MATCH_LIMIT);
26
+ const topMatchIdentities = new Set(topMatches.map(({
27
+ identity
28
+ }) => identity));
29
+ const tailMatches = matches.filter(({
30
+ identity
31
+ }) => !topMatchIdentities.has(identity));
32
+ return [...topMatches, ...tailMatches].map(({
33
+ item
34
+ }) => item);
35
+ };
36
+ const getRenderedMenuItems = (section, childrenMap, surfaceContext) => {
37
+ var _childrenMap$get;
38
+ return ((_childrenMap$get = childrenMap.get(getComponentIdentity(section))) !== null && _childrenMap$get !== void 0 ? _childrenMap$get : []).filter(child => child.type === 'menu-item' && willComponentRender(child, childrenMap, surfaceContext));
39
+ };
40
+ const buildBrowseSections = ({
41
+ childrenMap,
42
+ contentSections,
43
+ selectCategoryItems,
44
+ surfaceContext
45
+ }) => {
46
+ const sections = [];
47
+ for (const section of contentSections) {
48
+ const children = getRenderedMenuItems(section, childrenMap, surfaceContext);
49
+ const overflowItems = children.filter(child => isSectionOverflowItemKey(child.key));
50
+ const viewMoreItem = overflowItems[overflowItems.length - 1];
51
+ const items = children.filter(child => !isSectionOverflowItemKey(child.key));
52
+ if (items.length === 0) {
53
+ continue;
54
+ }
55
+ const selectedItems = viewMoreItem !== undefined && selectCategoryItems !== undefined ? selectCategoryItems(items) : items;
56
+ if (selectedItems.length < items.length && viewMoreItem !== undefined) {
57
+ sections.push([section, ...selectedItems, viewMoreItem]);
58
+ } else {
59
+ sections.push([section, ...selectedItems]);
60
+ }
61
+ }
62
+ return {
63
+ fallbackItems: [],
64
+ sections
65
+ };
66
+ };
67
+ const buildSearchSections = ({
68
+ childrenMap,
69
+ components,
70
+ contentSections,
71
+ formatMessage,
72
+ query,
73
+ root,
74
+ surfaceContext
75
+ }) => {
76
+ const matches = new Map();
77
+ const sourceIndexByComponent = new Map(components.map((component, index) => [component, index]));
78
+ for (const section of contentSections) {
79
+ for (const item of getRenderedMenuItems(section, childrenMap, surfaceContext)) {
80
+ var _item$match, _match$score, _sourceIndexByCompone;
81
+ if (isSectionOverflowItemKey(item.key)) {
82
+ continue;
83
+ }
84
+ const match = (_item$match = item.match) === null || _item$match === void 0 ? void 0 : _item$match.call(item, {
85
+ formatMessage,
86
+ query
87
+ });
88
+ if (item.match && match === null) {
89
+ continue;
90
+ }
91
+ const candidate = {
92
+ identity: `${item.type}:${item.key}`,
93
+ item,
94
+ itemRank: getParentRank(item, section.key),
95
+ 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)),
96
+ sourceIndex: (_sourceIndexByCompone = sourceIndexByComponent.get(item)) !== null && _sourceIndexByCompone !== void 0 ? _sourceIndexByCompone : Number.MAX_SAFE_INTEGER,
97
+ sectionRank: getParentRank(section, root.key)
98
+ };
99
+ const existing = matches.get(candidate.identity);
100
+ if (!existing || compareMatchedItems(candidate, existing) < 0) {
101
+ matches.set(candidate.identity, candidate);
102
+ }
103
+ }
104
+ }
105
+ const uniqueMatches = Array.from(matches.values()).sort(compareMatchedItems);
106
+ const searchResults = getSearchResults(uniqueMatches);
107
+ if (searchResults.length > 0) {
108
+ return {
109
+ fallbackItems: [],
110
+ sections: [[SEARCH_RESULTS_HEADING, ...searchResults]]
111
+ };
112
+ }
113
+ const fallbackItem = contentSections.flatMap(section => {
114
+ var _childrenMap$get2;
115
+ return (_childrenMap$get2 = childrenMap.get(getComponentIdentity(section))) !== null && _childrenMap$get2 !== void 0 ? _childrenMap$get2 : [];
116
+ }).find(component => component.type === ASK_ROVO_MENU_ITEM.type && component.key === ASK_ROVO_MENU_ITEM.key && willComponentRender(component, childrenMap, surfaceContext));
117
+ return {
118
+ fallbackItems: fallbackItem ? [fallbackItem] : [],
119
+ sections: []
120
+ };
121
+ };
122
+
123
+ /**
124
+ * Builds the registered quick-insert menu model. An empty query browses every
125
+ * category; a non-empty query returns ranked matches. The footer is shared by both.
126
+ */
127
+ export const getQuickInsertMenuModel = ({
128
+ components,
129
+ formatMessage,
130
+ getItemRank,
131
+ query,
132
+ rootComponent,
133
+ selectCategoryItems,
134
+ surfaceContext
135
+ }) => {
136
+ const rankedComponents = applyRegisteredItemRanks(components, getItemRank);
137
+ const {
138
+ childrenMap,
139
+ root,
140
+ topLevelChildren = []
141
+ } = resolveSurface(rankedComponents, rootComponent);
142
+ if (!root || !willComponentRender(root, childrenMap, surfaceContext)) {
143
+ return {
144
+ fallbackItems: [],
145
+ footer: undefined,
146
+ root: undefined,
147
+ sections: []
148
+ };
149
+ }
150
+ const renderedSections = topLevelChildren.filter(section => section.type === 'menu-section' && willComponentRender(section, childrenMap, surfaceContext));
151
+ const footerSection = renderedSections.find(({
152
+ key
153
+ }) => isMenuFooterSectionKey(key));
154
+ const contentSections = renderedSections.filter(({
155
+ key
156
+ }) => !isMenuFooterSectionKey(key));
157
+ const content = query === '' ? buildBrowseSections({
158
+ childrenMap,
159
+ contentSections,
160
+ selectCategoryItems,
161
+ surfaceContext
162
+ }) : buildSearchSections({
163
+ childrenMap,
164
+ components: rankedComponents,
165
+ contentSections,
166
+ formatMessage,
167
+ query,
168
+ root,
169
+ surfaceContext
170
+ });
171
+ const footer = footerSection ? getRenderedMenuItems(footerSection, childrenMap, surfaceContext)[0] : undefined;
172
+ return {
173
+ ...content,
174
+ footer,
175
+ root
176
+ };
177
+ };
@@ -0,0 +1 @@
1
+ export const getQuickInsertMenuItemId = (listId, itemIndex) => `${listId}-${itemIndex}`;
@@ -0,0 +1,19 @@
1
+ import { quickInsertProviderMenuItemKey } from '@atlaskit/editor-common/quick-insert/get-provider-menu-item-key';
2
+ const DEFAULT_ITEM_LIMIT = 30;
3
+ const ECOSYSTEM_ITEM_LIMIT = 10;
4
+ const isEcosystemQuickInsertItem = item => quickInsertProviderMenuItemKey.isEcosystem(item.key);
5
+
6
+ /**
7
+ * Keeps the initial native and ecosystem results while ensuring ecosystem registrations
8
+ * remain discoverable beyond the default category item limit.
9
+ */
10
+ export const selectQuickInsertCategoryItems = items => {
11
+ let ecosystemItemCount = 0;
12
+ return items.filter((item, index) => {
13
+ const isEcosystemItem = isEcosystemQuickInsertItem(item);
14
+ if (isEcosystemItem) {
15
+ ecosystemItemCount++;
16
+ }
17
+ return index < DEFAULT_ITEM_LIMIT || isEcosystemItem && ecosystemItemCount <= ECOSYSTEM_ITEM_LIMIT;
18
+ });
19
+ };
@@ -0,0 +1,91 @@
1
+ import { useCallback, useEffect, useRef } from 'react';
2
+ import { ACTION, ACTION_SUBJECT, EVENT_TYPE } from '@atlaskit/editor-common/analytics/types/enums';
3
+ const SEARCH_DEBOUNCE_MS = 1000;
4
+ export const useQuickInsertSearchAnalytics = ({
5
+ query,
6
+ resultCount,
7
+ surface,
8
+ category,
9
+ isOpen = true,
10
+ fireAnalyticsEvent
11
+ }) => {
12
+ const latestOptions = useRef({
13
+ query,
14
+ resultCount,
15
+ surface,
16
+ category,
17
+ fireAnalyticsEvent
18
+ });
19
+ latestOptions.current = {
20
+ query,
21
+ resultCount,
22
+ surface,
23
+ category,
24
+ fireAnalyticsEvent
25
+ };
26
+ const pendingSearch = useRef(null);
27
+ const effectVersion = useRef(0);
28
+ const flush = useCallback(() => {
29
+ const pending = pendingSearch.current;
30
+ if (!pending) {
31
+ return;
32
+ }
33
+ clearTimeout(pending.timer);
34
+ pendingSearch.current = null;
35
+ const current = latestOptions.current;
36
+ if (current.query.trim() !== pending.query || !current.fireAnalyticsEvent) {
37
+ return;
38
+ }
39
+ const attributes = {
40
+ ...(current.surface === 'element-browser' && current.category !== undefined ? {
41
+ category: current.category
42
+ } : {}),
43
+ isEmpty: current.resultCount === 0,
44
+ queryLength: current.query.trim().length,
45
+ resultCount: current.resultCount,
46
+ surface: current.surface
47
+ };
48
+ const payload = {
49
+ action: ACTION.SEARCHED,
50
+ actionSubject: ACTION_SUBJECT.QUICK_INSERT,
51
+ eventType: EVENT_TYPE.TRACK,
52
+ attributes
53
+ };
54
+ current.fireAnalyticsEvent(payload);
55
+ }, []);
56
+ useEffect(() => {
57
+ const currentVersion = ++effectVersion.current;
58
+ if (!isOpen) {
59
+ flush();
60
+ return;
61
+ }
62
+ const trimmedQuery = query.trim();
63
+ if (!trimmedQuery) {
64
+ if (pendingSearch.current) {
65
+ clearTimeout(pendingSearch.current.timer);
66
+ pendingSearch.current = null;
67
+ }
68
+ return;
69
+ }
70
+ if (pendingSearch.current) {
71
+ clearTimeout(pendingSearch.current.timer);
72
+ }
73
+ const timer = setTimeout(flush, SEARCH_DEBOUNCE_MS);
74
+ pendingSearch.current = {
75
+ query: trimmedQuery,
76
+ timer
77
+ };
78
+ return () => {
79
+ if (pendingSearch.current) {
80
+ clearTimeout(pendingSearch.current.timer);
81
+ }
82
+ Promise.resolve().then(() => {
83
+ // oxlint-disable-next-line react-hooks/exhaustive-deps -- The live effect version distinguishes dependency cleanup from a real unmount.
84
+ if (effectVersion.current === currentVersion) {
85
+ flush();
86
+ }
87
+ });
88
+ };
89
+ }, [query, surface, category, isOpen, flush]);
90
+ return flush;
91
+ };
@@ -8,6 +8,7 @@ import React from 'react';
8
8
  import { useIntl } from 'react-intl';
9
9
  import { isSSR } from '@atlaskit/editor-common/is-ssr';
10
10
  import { toolbarInsertBlockMessages as messages } from '@atlaskit/editor-common/messages/insert-block';
11
+ import { MENU } from '@atlaskit/editor-common/quick-insert/keys';
11
12
  import { createQuickInsertRankResolver } from '@atlaskit/editor-common/quick-insert/quick-insert-rank';
12
13
  import { memoProcessQuickInsertItems } from '@atlaskit/editor-common/quick-insert/utils';
13
14
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
@@ -37,6 +38,7 @@ export var quickInsertPlugin = function quickInsertPlugin(_ref) {
37
38
  var getItemRank = createQuickInsertRankResolver(options === null || options === void 0 ? void 0 : options.getItemRank);
38
39
  var typeAhead = {
39
40
  id: TypeAheadAvailableNodes.QUICK_INSERT,
41
+ registeredMenuKey: isExperimentEnabled('platform_editor_slash_command') ? MENU.key : undefined,
40
42
  getRegisteredItemRank: getItemRank,
41
43
  trigger: '/',
42
44
  // Support fullwidth slash (U+FF0F) used by Japanese/CJK keyboards (e.g. typing / on a Japanese keyboard layout)
@@ -78,12 +80,15 @@ export var quickInsertPlugin = function quickInsertPlugin(_ref) {
78
80
  } : undefined
79
81
  };
80
82
  if (isExperimentEnabled('platform_editor_slash_command')) {
81
- var _api$uiControlRegistr;
83
+ var _api$uiControlRegistr, _api$analytics;
82
84
  api === null || api === void 0 || (_api$uiControlRegistr = api.uiControlRegistry) === null || _api$uiControlRegistr === void 0 || _api$uiControlRegistr.actions.register(getQuickInsertComponents({
83
85
  api: api,
84
- includeElementBrowserItems: (options === null || options === void 0 ? void 0 : options.enableElementBrowser) === true,
86
+ getItemRank: getItemRank,
85
87
  isRecommendedItem: options === null || options === void 0 ? void 0 : options.isRecommendedItem,
86
- maxRecommendedItems: options === null || options === void 0 ? void 0 : options.maxRecommendedItems
88
+ maxRecommendedItems: options === null || options === void 0 ? void 0 : options.maxRecommendedItems,
89
+ emptyStateHandler: options === null || options === void 0 ? void 0 : options.emptyStateHandler,
90
+ fireAnalyticsEvent: api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions.fireAnalyticsEvent,
91
+ includeElementBrowserItems: (options === null || options === void 0 ? void 0 : options.enableElementBrowser) === true
87
92
  }));
88
93
  }
89
94
  if (isExperimentEnabled('platform_editor_block_control_migration') && (options === null || options === void 0 ? void 0 : options.blockControlButtonEnabled) !== false) {
@@ -142,8 +147,8 @@ export var quickInsertPlugin = function quickInsertPlugin(_ref) {
142
147
  return getQuickInsertOpenExperiencePlugin({
143
148
  refs: refs,
144
149
  dispatchAnalyticsEvent: function dispatchAnalyticsEvent(payload) {
145
- var _api$analytics;
146
- return api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || (_api$analytics = _api$analytics.actions) === null || _api$analytics === void 0 ? void 0 : _api$analytics.fireAnalyticsEvent(payload);
150
+ var _api$analytics2;
151
+ return api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 || (_api$analytics2 = _api$analytics2.actions) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.fireAnalyticsEvent(payload);
147
152
  }
148
153
  });
149
154
  }
@@ -1,13 +1,16 @@
1
- import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
2
- var _excluded = ["index", "getSnapshot"];
3
1
  import React from 'react';
4
2
  import { useQuickInsertContext } from '@atlaskit/editor-common/quick-insert/use-quick-insert-context';
5
3
  export var QuickInsertRecommendedSlot = function QuickInsertRecommendedSlot(_ref) {
6
- var index = _ref.index,
7
- getSnapshot = _ref.getSnapshot,
8
- props = _objectWithoutProperties(_ref, _excluded);
4
+ var children = _ref.children,
5
+ parents = _ref.parents,
6
+ surfaceContext = _ref.surfaceContext,
7
+ index = _ref.index,
8
+ getSnapshot = _ref.getSnapshot;
9
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;
10
+ menuSurfaceContext = _useQuickInsertContex.surfaceContext;
11
+ var item = getSnapshot(menuSurfaceContext)[index];
12
+ return item !== null && item !== void 0 && item.component ? /*#__PURE__*/React.createElement(item.component, {
13
+ parents: parents,
14
+ surfaceContext: surfaceContext
15
+ }, children) : null;
13
16
  };
@@ -11,7 +11,7 @@ import IconButton from '@atlaskit/button/icon/button';
11
11
  // eslint-disable-next-line @atlaskit/platform/no-barrel-entry-imports
12
12
  import { messages } from '@atlaskit/editor-common/quick-insert';
13
13
  import { MENU, RECOMMENDED_SECTION } from '@atlaskit/editor-common/quick-insert/keys';
14
- import { useQuickInsertSearchAnalytics } from '@atlaskit/editor-common/quick-insert/use-search-analytics';
14
+ import { createRegisteredMenuSurfaceContext } from '@atlaskit/editor-common/registered-menu/surface-context';
15
15
  import { getMenuFooterSectionKey } from '@atlaskit/editor-common/type-ahead-get-menu-footer-section-key';
16
16
  import { getSectionOverflowItemKey } from '@atlaskit/editor-common/type-ahead-get-section-overflow-item-key';
17
17
  import Heading from '@atlaskit/heading/heading';
@@ -24,6 +24,7 @@ import ModalTitle from '@atlaskit/modal-dialog/modal-title';
24
24
  import ModalTransition from '@atlaskit/modal-dialog/modal-transition';
25
25
  import { fg } from '@atlaskit/platform-feature-flags/fg';
26
26
  import Textfield from '@atlaskit/textfield/text-field';
27
+ import { useQuickInsertSearchAnalytics } from '../registered-menu/useQuickInsertSearchAnalytics';
27
28
  import { createRegistryElementBrowserModel, getInitialRegistryElementBrowserSection, getRegistryElementBrowserItems } from './model';
28
29
  import { RegistryElementBrowserCategories } from './RegistryElementBrowserCategories';
29
30
  import { RegistryElementBrowserFooter } from './RegistryElementBrowserFooter';
@@ -63,13 +64,34 @@ export var RegistryElementBrowser = function RegistryElementBrowser(_ref) {
63
64
  onSelect = _ref.onSelect;
64
65
  var _useIntl = useIntl(),
65
66
  formatMessage = _useIntl.formatMessage;
66
- var _useState = useState({
67
+ var _useState = useState(function () {
68
+ return {
69
+ isOpen: isOpen,
70
+ menuOpenId: Symbol('element-browser')
71
+ };
72
+ }),
73
+ _useState2 = _slicedToArray(_useState, 2),
74
+ session = _useState2[0],
75
+ setSession = _useState2[1];
76
+ if (session.isOpen !== isOpen) {
77
+ setSession({
78
+ isOpen: isOpen,
79
+ menuOpenId: isOpen ? Symbol('element-browser') : session.menuOpenId
80
+ });
81
+ }
82
+ var surfaceContext = useMemo(function () {
83
+ return createRegisteredMenuSurfaceContext({
84
+ menuOpenId: session.menuOpenId,
85
+ surface: 'element-browser'
86
+ });
87
+ }, [session.menuOpenId]);
88
+ var _useState3 = useState({
67
89
  query: '',
68
90
  section: defaultSection
69
91
  }),
70
- _useState2 = _slicedToArray(_useState, 2),
71
- browserState = _useState2[0],
72
- setBrowserState = _useState2[1];
92
+ _useState4 = _slicedToArray(_useState3, 2),
93
+ browserState = _useState4[0],
94
+ setBrowserState = _useState4[1];
73
95
  var query = browserState.query,
74
96
  section = browserState.section,
75
97
  selectedRegistration = browserState.selectedRegistration;
@@ -77,6 +99,7 @@ export var RegistryElementBrowser = function RegistryElementBrowser(_ref) {
77
99
  var browserModel = useMemo(function () {
78
100
  var model = createRegistryElementBrowserModel(components, {
79
101
  footerKey: getMenuFooterSectionKey(MENU.key),
102
+ surfaceContext: surfaceContext,
80
103
  overflowKeys: new Set(components.filter(function (component) {
81
104
  return component.type === 'menu-section';
82
105
  }).map(function (component) {
@@ -99,7 +122,7 @@ export var RegistryElementBrowser = function RegistryElementBrowser(_ref) {
99
122
  section: effectiveSection
100
123
  })
101
124
  };
102
- }, [components, formatMessage, query, section]);
125
+ }, [components, formatMessage, query, section, surfaceContext]);
103
126
  var model = browserModel.model,
104
127
  effectiveSection = browserModel.effectiveSection,
105
128
  items = browserModel.items;
@@ -353,6 +376,7 @@ export var RegistryElementBrowser = function RegistryElementBrowser(_ref) {
353
376
  fallbackItems: model.fallbackItems,
354
377
  query: query,
355
378
  resultsId: resultsId,
379
+ surfaceContext: surfaceContext,
356
380
  section: effectiveSection,
357
381
  selectedKey: selectedKey,
358
382
  onKeyDown: onKeyDown,
@@ -3,9 +3,8 @@ import "./RegistryElementBrowserSearchResults.compiled.css";
3
3
  import { ax, ix } from "@compiled/react/runtime";
4
4
  import React, { useMemo } from 'react';
5
5
  import { useIntl } from 'react-intl';
6
- import { QuickInsertEmptyState } from '@atlaskit/editor-common/quick-insert/empty-state';
7
6
  import { QuickInsertProvider } from '@atlaskit/editor-common/quick-insert/provider';
8
-
7
+ import { QuickInsertEmptyState } from '../registered-menu/QuickInsertEmptyState';
9
8
  // oxlint-disable-next-line eslint/no-redeclare
10
9
 
11
10
  var resultsGridStyles = null;
@@ -18,7 +17,8 @@ var RegistryElementBrowserItem = function RegistryElementBrowserItem(_ref) {
18
17
  isOffline = _ref.isOffline,
19
18
  isSelected = _ref.isSelected,
20
19
  item = _ref.item,
21
- onSelect = _ref.onSelect;
20
+ onSelect = _ref.onSelect,
21
+ surfaceContext = _ref.surfaceContext;
22
22
  var _item$registration = item.registration,
23
23
  Component = _item$registration.component,
24
24
  key = _item$registration.key;
@@ -34,15 +34,18 @@ var RegistryElementBrowserItem = function RegistryElementBrowserItem(_ref) {
34
34
  select: function select(handler) {
35
35
  return onSelect(key, handler);
36
36
  },
37
- surface: 'element-browser'
37
+ surfaceContext: surfaceContext
38
38
  };
39
- }, [editorView, isOffline, isSelected, item.description, key, onSelect]);
39
+ }, [editorView, isOffline, isSelected, item.description, key, onSelect, surfaceContext]);
40
40
  if (!Component) {
41
41
  return null;
42
42
  }
43
43
  return /*#__PURE__*/React.createElement(QuickInsertProvider, {
44
44
  value: contextValue
45
- }, /*#__PURE__*/React.createElement(Component, undefined, null));
45
+ }, /*#__PURE__*/React.createElement(Component, {
46
+ parents: item.registration.parents,
47
+ surfaceContext: surfaceContext
48
+ }, null));
46
49
  };
47
50
  export var RegistryElementBrowserSearchResults = function RegistryElementBrowserSearchResults(_ref2) {
48
51
  var editorView = _ref2.editorView,
@@ -56,6 +59,7 @@ export var RegistryElementBrowserSearchResults = function RegistryElementBrowser
56
59
  resultsId = _ref2.resultsId,
57
60
  section = _ref2.section,
58
61
  selectedKey = _ref2.selectedKey,
62
+ surfaceContext = _ref2.surfaceContext,
59
63
  onKeyDown = _ref2.onKeyDown,
60
64
  onSelect = _ref2.onSelect;
61
65
  var _useIntl = useIntl(),
@@ -96,7 +100,8 @@ export var RegistryElementBrowserSearchResults = function RegistryElementBrowser
96
100
  isSelected: selectedKey === item.registration.key,
97
101
  item: item,
98
102
  key: item.registration.key,
99
- onSelect: onSelect
103
+ onSelect: onSelect,
104
+ surfaceContext: surfaceContext
100
105
  });
101
106
  })), shouldRenderEmptyState && !hasFallbackItems && query.trim().length > 0 && /*#__PURE__*/React.createElement(QuickInsertEmptyState, {
102
107
  mode: "full"
@@ -14,16 +14,14 @@ var compareRanks = function compareRanks(left, right) {
14
14
  }
15
15
  return 0;
16
16
  };
17
- var isVisible = function isVisible(registration) {
18
- var _registration$isHidde;
19
- return ((_registration$isHidde = registration.isHidden) === null || _registration$isHidde === void 0 ? void 0 : _registration$isHidde.call(registration)) !== true;
20
- };
21
- var getChildren = function getChildren(components, parentKey) {
17
+ var getChildren = function getChildren(components, parentKey, surfaceContext) {
22
18
  return components.filter(function (component) {
23
- var _component$parents;
24
- return isVisible(component) && ((_component$parents = component.parents) === null || _component$parents === void 0 ? void 0 : _component$parents.some(function (parent) {
19
+ var _component$parents, _component$isHidden;
20
+ return ((_component$parents = component.parents) === null || _component$parents === void 0 ? void 0 : _component$parents.some(function (parent) {
25
21
  return parent.key === parentKey;
26
- }));
22
+ })) && ((_component$isHidden = component.isHidden) === null || _component$isHidden === void 0 ? void 0 : _component$isHidden.call(component, {
23
+ surfaceContext: surfaceContext
24
+ })) !== true;
27
25
  });
28
26
  };
29
27
  var getParentRank = function getParentRank(registration, parentKey) {
@@ -32,8 +30,8 @@ var getParentRank = function getParentRank(registration, parentKey) {
32
30
  return parent.key === parentKey;
33
31
  })) === null || _registration$parents2 === void 0 ? void 0 : _registration$parents2.rank) !== null && _registration$parents !== void 0 ? _registration$parents : Number.MAX_SAFE_INTEGER;
34
32
  };
35
- var _getDescendantItems = function getDescendantItems(components, parentKey, ancestorRanks, sectionKey) {
36
- return getChildren(components, parentKey).flatMap(function (component) {
33
+ var _getDescendantItems = function getDescendantItems(components, parentKey, ancestorRanks, sectionKey, surfaceContext) {
34
+ return getChildren(components, parentKey, surfaceContext).flatMap(function (component) {
37
35
  var ranks = [].concat(_toConsumableArray(ancestorRanks), [getParentRank(component, parentKey)]);
38
36
  if (component.type === 'menu-item') {
39
37
  return component.component ? [{
@@ -42,7 +40,7 @@ var _getDescendantItems = function getDescendantItems(components, parentKey, anc
42
40
  sectionKeys: [sectionKey]
43
41
  }] : [];
44
42
  }
45
- return _getDescendantItems(components, component.key, ranks, sectionKey);
43
+ return _getDescendantItems(components, component.key, ranks, sectionKey, surfaceContext);
46
44
  });
47
45
  };
48
46
 
@@ -54,12 +52,13 @@ export var createRegistryElementBrowserModel = function createRegistryElementBro
54
52
  var footerKey = _ref.footerKey,
55
53
  overflowKeys = _ref.overflowKeys,
56
54
  recommendedSectionKey = _ref.recommendedSectionKey,
57
- rootKey = _ref.rootKey;
55
+ rootKey = _ref.rootKey,
56
+ surfaceContext = _ref.surfaceContext;
58
57
  var excludedKeys = new Set([footerKey, recommendedSectionKey].concat(_toConsumableArray(overflowKeys)));
59
58
  var visibleComponents = components.filter(function (component) {
60
- return isVisible(component) && !excludedKeys.has(component.key);
59
+ return !excludedKeys.has(component.key);
61
60
  });
62
- var sections = getChildren(visibleComponents, rootKey).filter(function (component) {
61
+ var sections = getChildren(visibleComponents, rootKey, surfaceContext).filter(function (component) {
63
62
  return component.type === 'menu-section';
64
63
  }).map(function (section) {
65
64
  return {
@@ -71,7 +70,7 @@ export var createRegistryElementBrowserModel = function createRegistryElementBro
71
70
  });
72
71
  var itemByKey = new Map();
73
72
  sections.forEach(function (section) {
74
- _getDescendantItems(visibleComponents, section.key, [section.rank], section.key).forEach(function (item) {
73
+ _getDescendantItems(visibleComponents, section.key, [section.rank], section.key, surfaceContext).forEach(function (item) {
75
74
  var existing = itemByKey.get(item.registration.key);
76
75
  if (!existing) {
77
76
  itemByKey.set(item.registration.key, item);
@@ -1,12 +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; }
5
2
  import React from 'react';
6
3
  import { useIntl } from 'react-intl';
7
4
  import { BLOCK_TEMPLATES_SECTION, CREATE_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';
8
- import { QuickInsertMenuRoot } from '@atlaskit/editor-common/quick-insert/menu-root';
9
- import { QuickInsertMenuSection } from '@atlaskit/editor-common/quick-insert/menu-section';
10
5
  import { messages } from '@atlaskit/editor-common/quick-insert/messages';
11
6
  import { CATEGORY_VIEW_MORE_RANK, QUICK_INSERT_MENU_RANK } from '@atlaskit/editor-common/quick-insert/rank';
12
7
  import { getMenuFooterSectionKey } from '@atlaskit/editor-common/type-ahead-get-menu-footer-section-key';
@@ -15,6 +10,8 @@ import { createRecommendedSnapshotCache, MAX_RECOMMENDED_ITEMS, RECOMMENDED_SLOT
15
10
  import { QuickInsertMenuFooterItem } from './QuickInsertMenuFooterItem';
16
11
  import { QuickInsertRecommendedSlot } from './QuickInsertRecommendedSlot';
17
12
  import { QuickInsertSectionOverflowMenuItem } from './QuickInsertSectionOverflowMenuItem';
13
+ import QuickInsertMenuRoot from './registered-menu/QuickInsertMenuRoot';
14
+ import { QuickInsertMenuSection } from './registered-menu/QuickInsertMenuSection';
18
15
  var categories = [{
19
16
  message: messages.categoryRecommended,
20
17
  section: RECOMMENDED_SECTION
@@ -61,7 +58,10 @@ export var getQuickInsertComponents = function getQuickInsertComponents(_ref2) {
61
58
  var api = _ref2.api,
62
59
  includeElementBrowserItems = _ref2.includeElementBrowserItems,
63
60
  isRecommendedItem = _ref2.isRecommendedItem,
64
- maxRecommendedItems = _ref2.maxRecommendedItems;
61
+ maxRecommendedItems = _ref2.maxRecommendedItems,
62
+ getItemRank = _ref2.getItemRank,
63
+ emptyStateHandler = _ref2.emptyStateHandler,
64
+ fireAnalyticsEvent = _ref2.fireAnalyticsEvent;
65
65
  var recommendedSnapshot = createRecommendedSnapshotCache({
66
66
  api: api,
67
67
  isRecommendedItem: isRecommendedItem,
@@ -86,21 +86,33 @@ export var getQuickInsertComponents = function getQuickInsertComponents(_ref2) {
86
86
  surfaceContext = _ref3.surfaceContext;
87
87
  return !recommendedSnapshot.getSnapshot(surfaceContext)[index];
88
88
  },
89
- component: function component(props) {
90
- return /*#__PURE__*/React.createElement(QuickInsertRecommendedSlot, _objectSpread(_objectSpread({}, props), {}, {
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,
91
96
  index: index,
92
97
  getSnapshot: recommendedSnapshot.getSnapshot
93
- }));
98
+ }, children);
94
99
  }
95
100
  };
96
101
  });
97
102
  return [{
98
103
  key: MENU.key,
99
104
  type: MENU.type,
100
- component: QuickInsertMenuRoot
101
- }].concat(recommendedSlots, _toConsumableArray(categories.flatMap(function (_ref4) {
102
- var message = _ref4.message,
103
- section = _ref4.section;
105
+ component: function component(_ref5) {
106
+ var children = _ref5.children;
107
+ return /*#__PURE__*/React.createElement(QuickInsertMenuRoot, {
108
+ getItemRank: getItemRank,
109
+ emptyStateHandler: emptyStateHandler,
110
+ fireAnalyticsEvent: fireAnalyticsEvent
111
+ }, children);
112
+ }
113
+ }].concat(recommendedSlots, _toConsumableArray(categories.flatMap(function (_ref6) {
114
+ var message = _ref6.message,
115
+ section = _ref6.section;
104
116
  return [{
105
117
  key: section.key,
106
118
  type: section.type,
@@ -111,8 +123,8 @@ export var getQuickInsertComponents = function getQuickInsertComponents(_ref2) {
111
123
  }],
112
124
  component: createSectionComponent(message),
113
125
  isHidden: section.key === RECOMMENDED_SECTION.key ? function () {
114
- var _ref5 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
115
- surfaceContext = _ref5.surfaceContext;
126
+ var _ref7 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
127
+ surfaceContext = _ref7.surfaceContext;
116
128
  return recommendedSnapshot.getSnapshot(surfaceContext).length === 0;
117
129
  } : undefined
118
130
  }].concat(_toConsumableArray(includeElementBrowserItems && section.key !== RECOMMENDED_SECTION.key ? [{