@atlaskit/editor-plugin-block-menu 5.2.11 → 5.2.13

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 (67) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/cjs/editor-commands/transform-node-utils/transform.js +2 -1
  3. package/dist/cjs/editor-commands/transform-node-utils/utils.js +1 -53
  4. package/dist/cjs/editor-commands/transformNode.js +4 -4
  5. package/dist/cjs/ui/block-menu-renderer/BlockMenuComponent.js +37 -0
  6. package/dist/cjs/ui/block-menu-renderer/BlockMenuComponents.js +29 -0
  7. package/dist/cjs/ui/block-menu-renderer/BlockMenuRenderer.js +33 -0
  8. package/dist/cjs/ui/block-menu-renderer/fallbacks.js +32 -0
  9. package/dist/cjs/ui/block-menu-renderer/types.js +5 -0
  10. package/dist/cjs/ui/block-menu-renderer/utils.js +127 -0
  11. package/dist/cjs/ui/block-menu.js +7 -20
  12. package/dist/cjs/ui/copy-link.js +7 -11
  13. package/dist/cjs/ui/hooks/useSuggestedItems.js +11 -4
  14. package/dist/cjs/ui/utils/copyLink.js +4 -4
  15. package/dist/cjs/ui/utils/suggested-items-rank.js +1 -1
  16. package/dist/es2019/editor-commands/transform-node-utils/transform.js +2 -1
  17. package/dist/es2019/editor-commands/transform-node-utils/utils.js +0 -54
  18. package/dist/es2019/editor-commands/transformNode.js +2 -2
  19. package/dist/es2019/ui/block-menu-renderer/BlockMenuComponent.js +31 -0
  20. package/dist/es2019/ui/block-menu-renderer/BlockMenuComponents.js +21 -0
  21. package/dist/es2019/ui/block-menu-renderer/BlockMenuRenderer.js +24 -0
  22. package/dist/es2019/ui/block-menu-renderer/fallbacks.js +21 -0
  23. package/dist/es2019/ui/block-menu-renderer/types.js +1 -0
  24. package/dist/es2019/ui/block-menu-renderer/utils.js +93 -0
  25. package/dist/es2019/ui/block-menu.js +6 -13
  26. package/dist/es2019/ui/copy-link.js +7 -11
  27. package/dist/es2019/ui/hooks/useSuggestedItems.js +10 -5
  28. package/dist/es2019/ui/utils/copyLink.js +3 -4
  29. package/dist/es2019/ui/utils/suggested-items-rank.js +0 -5
  30. package/dist/esm/editor-commands/transform-node-utils/transform.js +2 -1
  31. package/dist/esm/editor-commands/transform-node-utils/utils.js +0 -52
  32. package/dist/esm/editor-commands/transformNode.js +2 -2
  33. package/dist/esm/ui/block-menu-renderer/BlockMenuComponent.js +30 -0
  34. package/dist/esm/ui/block-menu-renderer/BlockMenuComponents.js +22 -0
  35. package/dist/esm/ui/block-menu-renderer/BlockMenuRenderer.js +25 -0
  36. package/dist/esm/ui/block-menu-renderer/fallbacks.js +25 -0
  37. package/dist/esm/ui/block-menu-renderer/types.js +1 -0
  38. package/dist/esm/ui/block-menu-renderer/utils.js +121 -0
  39. package/dist/esm/ui/block-menu.js +6 -19
  40. package/dist/esm/ui/copy-link.js +7 -11
  41. package/dist/esm/ui/hooks/useSuggestedItems.js +12 -5
  42. package/dist/esm/ui/utils/copyLink.js +4 -4
  43. package/dist/esm/ui/utils/suggested-items-rank.js +1 -1
  44. package/dist/types/blockMenuPluginType.d.ts +3 -2
  45. package/dist/types/editor-commands/transform-node-utils/utils.d.ts +1 -17
  46. package/dist/types/ui/block-menu-renderer/BlockMenuComponent.d.ts +11 -0
  47. package/dist/types/ui/block-menu-renderer/BlockMenuComponents.d.ts +12 -0
  48. package/dist/types/ui/block-menu-renderer/BlockMenuRenderer.d.ts +12 -0
  49. package/dist/types/ui/block-menu-renderer/fallbacks.d.ts +2 -0
  50. package/dist/types/ui/block-menu-renderer/types.d.ts +27 -0
  51. package/dist/types/ui/block-menu-renderer/utils.d.ts +37 -0
  52. package/dist/types/ui/utils/copyLink.d.ts +1 -3
  53. package/dist/types-ts4.5/blockMenuPluginType.d.ts +3 -2
  54. package/dist/types-ts4.5/editor-commands/transform-node-utils/utils.d.ts +1 -17
  55. package/dist/types-ts4.5/ui/block-menu-renderer/BlockMenuComponent.d.ts +11 -0
  56. package/dist/types-ts4.5/ui/block-menu-renderer/BlockMenuComponents.d.ts +12 -0
  57. package/dist/types-ts4.5/ui/block-menu-renderer/BlockMenuRenderer.d.ts +12 -0
  58. package/dist/types-ts4.5/ui/block-menu-renderer/fallbacks.d.ts +2 -0
  59. package/dist/types-ts4.5/ui/block-menu-renderer/types.d.ts +27 -0
  60. package/dist/types-ts4.5/ui/block-menu-renderer/utils.d.ts +37 -0
  61. package/dist/types-ts4.5/ui/utils/copyLink.d.ts +1 -3
  62. package/package.json +1 -1
  63. package/dist/cjs/ui/block-menu-renderer.js +0 -104
  64. package/dist/es2019/ui/block-menu-renderer.js +0 -83
  65. package/dist/esm/ui/block-menu-renderer.js +0 -95
  66. package/dist/types/ui/block-menu-renderer.d.ts +0 -18
  67. package/dist/types-ts4.5/ui/block-menu-renderer.d.ts +0 -18
@@ -1,8 +1,6 @@
1
- import { expandToBlockRange } from '@atlaskit/editor-common/selection';
2
1
  import { NodeSelection, TextSelection } from '@atlaskit/editor-prosemirror/state';
3
2
  import { findParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
4
3
  import { CellSelection } from '@atlaskit/editor-tables';
5
- import { findTable, isTableSelected } from '@atlaskit/editor-tables/utils';
6
4
  export const getSelectedNode = selection => {
7
5
  if (selection instanceof NodeSelection) {
8
6
  return {
@@ -52,58 +50,6 @@ export const getTargetNodeTypeNameInContext = (nodeTypeName, isNested) => {
52
50
  }
53
51
  return nodeTypeName;
54
52
  };
55
-
56
- /**
57
- * Use common expandToBlockRange function to get the correct range for the selection
58
- * For example, if selection starts in a listItem, go find the bullet list or ordered list, their $from
59
- * @param selection
60
- * @param schema
61
- * @returns
62
- */
63
- export const expandSelectionToBlockRange = (selection, schema) => {
64
- const {
65
- nodes
66
- } = schema;
67
- const nodesNeedToExpandRange = [nodes.bulletList, nodes.orderedList, nodes.taskList, nodes.listItem, nodes.taskItem];
68
-
69
- // when adding nodes.tableRow, tableHeader, tableCell in nodesNeedToExpandRang,
70
- // expandToBlockRange does not return expected table start position, sometimes even freeze editor
71
- // so handle table in the below logic
72
- if (isTableSelected(selection)) {
73
- const table = findTable(selection);
74
- if (table) {
75
- const $from = selection.$from.doc.resolve(table.pos);
76
- const $to = selection.$from.doc.resolve(table.pos + table.node.nodeSize - 1);
77
- return {
78
- $from,
79
- $to,
80
- range: $from.blockRange($to)
81
- };
82
- }
83
- }
84
-
85
- // when selecting a file, selection is on media
86
- // need to find media group and return its pos
87
- if (selection instanceof NodeSelection) {
88
- if (selection.node.type === nodes.media) {
89
- const mediaGroup = findParentNodeOfType(nodes.mediaGroup)(selection);
90
- if (mediaGroup) {
91
- const $from = selection.$from.doc.resolve(mediaGroup.pos);
92
- const $to = selection.$from.doc.resolve(mediaGroup.pos + mediaGroup.node.nodeSize);
93
- return {
94
- $from,
95
- $to
96
- };
97
- }
98
- }
99
- }
100
- return expandToBlockRange(selection.$from, selection.$to, node => {
101
- if (nodesNeedToExpandRange.includes(node.type)) {
102
- return false;
103
- }
104
- return true;
105
- });
106
- };
107
53
  export const isListType = (node, schema) => {
108
54
  const lists = [schema.nodes.taskList, schema.nodes.bulletList, schema.nodes.orderedList];
109
55
  return lists.some(list => list === node.type);
@@ -1,8 +1,8 @@
1
+ import { expandSelectionToBlockRange } from '@atlaskit/editor-common/selection';
1
2
  import { Fragment } from '@atlaskit/editor-prosemirror/model';
2
3
  import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
3
4
  import { isNestedNode } from '../ui/utils/isNestedNode';
4
5
  import { getOutputNodes } from './transform-node-utils/transform';
5
- import { expandSelectionToBlockRange } from './transform-node-utils/utils';
6
6
  import { isListNode } from './transforms/utils';
7
7
  export const transformNode = api =>
8
8
  // eslint-disable-next-line no-unused-vars
@@ -22,7 +22,7 @@ export const transformNode = api =>
22
22
  const {
23
23
  $from,
24
24
  $to
25
- } = expandSelectionToBlockRange(preservedSelection, schema);
25
+ } = expandSelectionToBlockRange(preservedSelection);
26
26
  const isNested = isNestedNode(preservedSelection, '');
27
27
  const selectedParent = $from.parent;
28
28
  let fragment = Fragment.empty;
@@ -0,0 +1,31 @@
1
+ import React from 'react';
2
+ import { BlockMenuComponents } from './BlockMenuComponents';
3
+ import { getChildrenMapKey, willComponentRender } from './utils';
4
+ /**
5
+ * Renders the given registered component based on its type
6
+ */
7
+ export const BlockMenuComponent = ({
8
+ registeredComponent,
9
+ childrenMap,
10
+ fallbacks
11
+ }) => {
12
+ if (registeredComponent.type === 'block-menu-item') {
13
+ const ItemComponent = registeredComponent.component || fallbacks['block-menu-item'];
14
+ return /*#__PURE__*/React.createElement(ItemComponent, {
15
+ key: registeredComponent.key
16
+ });
17
+ }
18
+ if (!willComponentRender(registeredComponent, childrenMap)) {
19
+ return null;
20
+ }
21
+ const ParentComponent = registeredComponent.component || fallbacks[registeredComponent.type];
22
+ const childrenMapKey = getChildrenMapKey(registeredComponent.key, registeredComponent.type);
23
+ const registeredComponents = childrenMap.get(childrenMapKey);
24
+ return /*#__PURE__*/React.createElement(ParentComponent, {
25
+ key: registeredComponent.key
26
+ }, /*#__PURE__*/React.createElement(BlockMenuComponents, {
27
+ registeredComponents: registeredComponents,
28
+ childrenMap: childrenMap,
29
+ fallbacks: fallbacks
30
+ }));
31
+ };
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ import { BlockMenuComponent } from './BlockMenuComponent';
3
+ /**
4
+ * Renders the given registered components
5
+ * Returns null if no components are rendered
6
+ */
7
+ export const BlockMenuComponents = ({
8
+ registeredComponents,
9
+ childrenMap,
10
+ fallbacks
11
+ }) => {
12
+ if (!(registeredComponents !== null && registeredComponents !== void 0 && registeredComponents.length)) {
13
+ return null;
14
+ }
15
+ return /*#__PURE__*/React.createElement(React.Fragment, null, registeredComponents.map(registeredComponent => /*#__PURE__*/React.createElement(BlockMenuComponent, {
16
+ key: registeredComponent.key,
17
+ registeredComponent: registeredComponent,
18
+ childrenMap: childrenMap,
19
+ fallbacks: fallbacks
20
+ })));
21
+ };
@@ -0,0 +1,24 @@
1
+ import React, { useMemo } from 'react';
2
+ import { BlockMenuComponents } from './BlockMenuComponents';
3
+ import { BLOCK_MENU_FALLBACKS } from './fallbacks';
4
+ import { buildChildrenMap, getSortedTopLevelSections } from './utils';
5
+ /**
6
+ * BlockMenuRenderer orchestrates the rendering of the entire block menu hierarchy
7
+ */
8
+ export const BlockMenuRenderer = ({
9
+ allRegisteredComponents,
10
+ fallbacks = BLOCK_MENU_FALLBACKS
11
+ }) => {
12
+ const {
13
+ childrenMap,
14
+ topLevelSections
15
+ } = useMemo(() => ({
16
+ childrenMap: buildChildrenMap(allRegisteredComponents),
17
+ topLevelSections: getSortedTopLevelSections(allRegisteredComponents)
18
+ }), [allRegisteredComponents]);
19
+ return /*#__PURE__*/React.createElement(BlockMenuComponents, {
20
+ registeredComponents: topLevelSections,
21
+ childrenMap: childrenMap,
22
+ fallbacks: fallbacks
23
+ });
24
+ };
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ import { ToolbarDropdownItem, ToolbarDropdownItemSection, ToolbarNestedDropdownMenu } from '@atlaskit/editor-toolbar';
3
+ import ChevronRightIcon from '@atlaskit/icon/core/chevron-right';
4
+ export const BLOCK_MENU_FALLBACKS = {
5
+ 'block-menu-nested': ({
6
+ children
7
+ }) => /*#__PURE__*/React.createElement(ToolbarNestedDropdownMenu, {
8
+ elemBefore: undefined,
9
+ elemAfter: /*#__PURE__*/React.createElement(ChevronRightIcon, {
10
+ label: ""
11
+ }),
12
+ text: "Nested Menu",
13
+ enableMaxHeight: true,
14
+ shouldFitContainer: true
15
+ }, children),
16
+ 'block-menu-section': ({
17
+ children
18
+ }) => /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, null, children),
19
+ // eslint-disable-next-line @atlassian/i18n/no-literal-string-in-jsx
20
+ 'block-menu-item': () => /*#__PURE__*/React.createElement(ToolbarDropdownItem, null, "Block Menu Item")
21
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Type guard to check if a component has a parent
3
+ *
4
+ * @param component The block menu component to check
5
+ * @returns True if the component has a parent, false otherwise
6
+ */
7
+ const hasParent = component => {
8
+ return 'parent' in component && !!component.parent;
9
+ };
10
+
11
+ /**
12
+ * Type guard to identify top-level sections (sections without a parent)
13
+ *
14
+ * @param component The block menu component to check
15
+ * @returns True if the component is a top-level section, false otherwise
16
+ */
17
+ const isTopLevelSection = component => {
18
+ return component.type === 'block-menu-section' && !hasParent(component);
19
+ };
20
+
21
+ /**
22
+ * Gets all top-level sections (those without a parent) sorted by rank
23
+ *
24
+ * @param components All registered block menu components
25
+ * @returns Sorted array of top-level sections
26
+ */
27
+ export const getSortedTopLevelSections = components => {
28
+ return components.filter(isTopLevelSection).sort((a, b) => (a.rank || 0) - (b.rank || 0));
29
+ };
30
+
31
+ /**
32
+ * Generates a unique key from a key and type
33
+ * Used to lookup children in the childrenMap
34
+ *
35
+ * @param key The component's key
36
+ * @param type The component's type
37
+ * @returns A unique string key combining type and key
38
+ */
39
+ export const getChildrenMapKey = (key, type) => {
40
+ return `${type}:${key}`;
41
+ };
42
+
43
+ /**
44
+ * Builds a map of parent keys to their sorted children
45
+ * This enables efficient hierarchical rendering of the menu structure
46
+ *
47
+ * @param components All registered block menu components
48
+ * @returns Map where keys are parent identifiers and values are sorted child components
49
+ */
50
+ export const buildChildrenMap = components => {
51
+ const childrenMap = new Map();
52
+ for (const component of components) {
53
+ // Only components with parents can be children
54
+ if ('parent' in component && !!component.parent) {
55
+ const childrenMapKey = getChildrenMapKey(component.parent.key, component.parent.type);
56
+ const existing = childrenMap.get(childrenMapKey) || [];
57
+ existing.push(component);
58
+ childrenMap.set(childrenMapKey, existing);
59
+ }
60
+ }
61
+
62
+ // Sort children by their rank within their parent
63
+ for (const [, children] of childrenMap.entries()) {
64
+ children.sort((a, b) => {
65
+ const rankA = hasParent(a) ? a.parent.rank || 0 : 0;
66
+ const rankB = hasParent(b) ? b.parent.rank || 0 : 0;
67
+ return rankA - rankB;
68
+ });
69
+ }
70
+ return childrenMap;
71
+ };
72
+
73
+ /**
74
+ * Determines whether a component will render based on its type and children
75
+ *
76
+ * Rules:
77
+ * - An item will not render if has a component that returns null
78
+ * - A nested menu will render if it has at least one registered child component
79
+ * - A section will render if it has at least one registered child component that will render
80
+ *
81
+ * NOTE: This requires invoking each item's component function to check for null return
82
+ */
83
+ export const willComponentRender = (registeredComponent, childrenMap) => {
84
+ if (registeredComponent.type === 'block-menu-item') {
85
+ return registeredComponent.component ? registeredComponent.component() !== null : true;
86
+ }
87
+ const childrenMapKey = getChildrenMapKey(registeredComponent.key, registeredComponent.type);
88
+ const registeredComponents = childrenMap.get(childrenMapKey) || [];
89
+ if (registeredComponent.type === 'block-menu-nested') {
90
+ return registeredComponents.length > 0;
91
+ }
92
+ return registeredComponents.some(childComponent => willComponentRender(childComponent, childrenMap));
93
+ };
@@ -10,15 +10,15 @@ import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks'
10
10
  import { deleteSelectedRange } from '@atlaskit/editor-common/selection';
11
11
  import { DRAG_HANDLE_SELECTOR, DRAG_HANDLE_WIDTH } from '@atlaskit/editor-common/styles';
12
12
  import { Popup } from '@atlaskit/editor-common/ui';
13
+ import { ArrowKeyNavigationProvider, ArrowKeyNavigationType } from '@atlaskit/editor-common/ui-menu';
13
14
  import { OutsideClickTargetRefContext, withReactEditorViewOuterListeners } from '@atlaskit/editor-common/ui-react';
14
15
  import { akEditorFloatingOverlapPanelZIndex } from '@atlaskit/editor-shared-styles';
15
- import { ToolbarDropdownItem, ToolbarDropdownItemSection, ToolbarNestedDropdownMenu } from '@atlaskit/editor-toolbar';
16
16
  import { fg } from '@atlaskit/platform-feature-flags';
17
17
  import { conditionalHooksFactory } from '@atlaskit/platform-feature-flags-react';
18
18
  import { Box } from '@atlaskit/primitives/compiled';
19
19
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
20
20
  import { useBlockMenu } from './block-menu-provider';
21
- import { BlockMenuRenderer } from './block-menu-renderer';
21
+ import { BlockMenuRenderer } from './block-menu-renderer/BlockMenuRenderer';
22
22
  const styles = {
23
23
  base: "_2rko12b0 _bfhk1bhr _16qs130s",
24
24
  emptyMenuSectionStyles: "_1cc0glyw _1k2yglyw"
@@ -111,18 +111,11 @@ const BlockMenuContent = ({
111
111
  testId: "editor-block-menu",
112
112
  ref: ref,
113
113
  xcss: cx(styles.base, editorExperiment('platform_synced_block', true) && styles.emptyMenuSectionStyles)
114
+ }, /*#__PURE__*/React.createElement(ArrowKeyNavigationProvider, {
115
+ type: ArrowKeyNavigationType.MENU
114
116
  }, /*#__PURE__*/React.createElement(BlockMenuRenderer, {
115
- components: blockMenuComponents || [],
116
- fallbacks: {
117
- nestedMenu: () => /*#__PURE__*/React.createElement(ToolbarNestedDropdownMenu, {
118
- elemBefore: undefined,
119
- elemAfter: undefined
120
- }, /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, null, /*#__PURE__*/React.createElement(ToolbarDropdownItem, null, "Block Menu Item"))),
121
- section: () => /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, null, /*#__PURE__*/React.createElement(ToolbarDropdownItem, null, "Block Menu Item")),
122
- // eslint-disable-next-line @atlassian/i18n/no-literal-string-in-jsx
123
- item: () => /*#__PURE__*/React.createElement(ToolbarDropdownItem, null, "Block Menu Item")
124
- }
125
- }));
117
+ allRegisteredComponents: blockMenuComponents || []
118
+ })));
126
119
  };
127
120
  const BlockMenu = ({
128
121
  editorView,
@@ -29,23 +29,20 @@ const CopyLinkDropdownItemContent = ({
29
29
  const {
30
30
  preservedSelection,
31
31
  defaultSelection,
32
- menuTriggerBy,
33
- schema
34
- } = useSharedPluginStateWithSelector(api, ['blockControls', 'selection', 'core'], ({
32
+ menuTriggerBy
33
+ } = useSharedPluginStateWithSelector(api, ['blockControls', 'selection'], ({
35
34
  blockControlsState,
36
- selectionState,
37
- coreState
35
+ selectionState
38
36
  }) => {
39
37
  return {
40
38
  menuTriggerBy: blockControlsState === null || blockControlsState === void 0 ? void 0 : blockControlsState.menuTriggerBy,
41
39
  preservedSelection: blockControlsState === null || blockControlsState === void 0 ? void 0 : blockControlsState.preservedSelection,
42
- defaultSelection: selectionState === null || selectionState === void 0 ? void 0 : selectionState.selection,
43
- schema: coreState === null || coreState === void 0 ? void 0 : coreState.schema
40
+ defaultSelection: selectionState === null || selectionState === void 0 ? void 0 : selectionState.selection
44
41
  };
45
42
  });
46
43
  const selection = preservedSelection || defaultSelection;
47
44
  const handleClick = useCallback(() => {
48
- if (!selection || !schema) {
45
+ if (!selection) {
49
46
  return;
50
47
  }
51
48
  api === null || api === void 0 ? void 0 : api.core.actions.execute(({
@@ -72,8 +69,7 @@ const CopyLinkDropdownItemContent = ({
72
69
  copyLink({
73
70
  getLinkPath,
74
71
  blockLinkHashPrefix,
75
- selection,
76
- schema
72
+ selection
77
73
  }).then(success => {
78
74
  if (success) {
79
75
  api === null || api === void 0 ? void 0 : api.core.actions.execute(({
@@ -86,7 +82,7 @@ const CopyLinkDropdownItemContent = ({
86
82
  });
87
83
  }
88
84
  });
89
- }, [api, blockLinkHashPrefix, getLinkPath, onDropdownOpenChanged, schema, selection]);
85
+ }, [api, blockLinkHashPrefix, getLinkPath, onDropdownOpenChanged, selection]);
90
86
 
91
87
  // Hide copy link when `platform_editor_adf_with_localid` feature flag is off or when the node is nested or on empty line
92
88
  if (!fg('platform_editor_adf_with_localid') || !!menuTriggerBy && isNestedNode(selection, menuTriggerBy) || selection !== null && selection !== void 0 && selection.empty) {
@@ -1,6 +1,7 @@
1
1
  import { useMemo } from 'react';
2
2
  import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
3
- import { getBlockNodesInRange, expandSelectionToBlockRange } from '../../editor-commands/transform-node-utils/utils';
3
+ import { expandSelectionToBlockRange } from '@atlaskit/editor-common/selection';
4
+ import { getBlockNodesInRange } from '../../editor-commands/transform-node-utils/utils';
4
5
  import { getSortedSuggestedItems } from '../utils/suggested-items-rank';
5
6
  export const useSuggestedItems = api => {
6
7
  var _api$blockMenu;
@@ -28,16 +29,20 @@ export const useSuggestedItems = api => {
28
29
  }
29
30
  const {
30
31
  range
31
- } = expandSelectionToBlockRange(currentSelection, currentSelection.$from.doc.type.schema);
32
+ } = expandSelectionToBlockRange(currentSelection);
32
33
  if (!range) {
33
34
  return [];
34
35
  }
35
36
  const blockNodes = getBlockNodesInRange(range);
36
- const singleNode = blockNodes.length === 1 ? blockNodes[0] : undefined;
37
- if (!singleNode) {
37
+ if (blockNodes.length === 0) {
38
38
  return [];
39
39
  }
40
- const nodeTypeName = singleNode.type.name;
40
+ const firstNodeType = blockNodes[0].type.name;
41
+ const allSameType = blockNodes.every(node => node.type.name === firstNodeType);
42
+ if (!allSameType) {
43
+ return [];
44
+ }
45
+ const nodeTypeName = firstNodeType;
41
46
  const sortedKeys = getSortedSuggestedItems(nodeTypeName);
42
47
  return sortedKeys.map(key => menuItemsMap.get(key)).filter(item => item !== undefined);
43
48
  }, [menuItemsMap, preservedSelection, selection]);
@@ -1,14 +1,13 @@
1
1
  import { createBlockLinkHashValue, DEFAULT_BLOCK_LINK_HASH_PREFIX } from '@atlaskit/editor-common/block-menu';
2
2
  import { copyToClipboard } from '@atlaskit/editor-common/clipboard';
3
3
  import { logException } from '@atlaskit/editor-common/monitoring';
4
- import { expandSelectionToBlockRange } from '../../editor-commands/transform-node-utils/utils';
4
+ import { expandSelectionToBlockRange } from '@atlaskit/editor-common/selection';
5
5
  export const copyLink = async ({
6
6
  getLinkPath,
7
7
  blockLinkHashPrefix = DEFAULT_BLOCK_LINK_HASH_PREFIX,
8
- selection,
9
- schema
8
+ selection
10
9
  }) => {
11
- const blockRange = expandSelectionToBlockRange(selection, schema);
10
+ const blockRange = expandSelectionToBlockRange(selection);
12
11
  if (!blockRange) {
13
12
  return false;
14
13
  }
@@ -99,11 +99,6 @@ export const TRANSFORM_SUGGESTED_ITEMS_RANK = {
99
99
  [TRANSFORM_STRUCTURE_EXPAND_MENU_ITEM.key]: 100,
100
100
  [TRANSFORM_STRUCTURE_PANEL_MENU_ITEM.key]: 200,
101
101
  [TRANSFORM_STRUCTURE_LAYOUT_MENU_ITEM.key]: 300
102
- },
103
- [BLOCK_MENU_NODE_TYPES.BODIED_EXTENSION]: {
104
- [TRANSFORM_STRUCTURE_EXPAND_MENU_ITEM.key]: 100,
105
- [TRANSFORM_STRUCTURE_PANEL_MENU_ITEM.key]: 200,
106
- [TRANSFORM_STRUCTURE_LAYOUT_MENU_ITEM.key]: 300
107
102
  }
108
103
  };
109
104
  export const getSuggestedItemsForNodeType = nodeType => {
@@ -128,7 +128,8 @@ var TRANSFORM_STEPS_OVERRIDE = {
128
128
  decisionList: {
129
129
  bulletList: [decisionListToListStep],
130
130
  orderedList: [decisionListToListStep],
131
- taskList: [decisionListToListStep]
131
+ taskList: [decisionListToListStep],
132
+ layoutSection: [wrapIntoLayoutStep]
132
133
  }
133
134
  };
134
135
  var getTransformStepsForNodeTypes = function getTransformStepsForNodeTypes(selectedNodeTypeName, targetNodeTypeName) {
@@ -1,8 +1,6 @@
1
- import { expandToBlockRange } from '@atlaskit/editor-common/selection';
2
1
  import { NodeSelection, TextSelection } from '@atlaskit/editor-prosemirror/state';
3
2
  import { findParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
4
3
  import { CellSelection } from '@atlaskit/editor-tables';
5
- import { findTable, isTableSelected } from '@atlaskit/editor-tables/utils';
6
4
  export var getSelectedNode = function getSelectedNode(selection) {
7
5
  if (selection instanceof NodeSelection) {
8
6
  return {
@@ -51,56 +49,6 @@ export var getTargetNodeTypeNameInContext = function getTargetNodeTypeNameInCont
51
49
  }
52
50
  return nodeTypeName;
53
51
  };
54
-
55
- /**
56
- * Use common expandToBlockRange function to get the correct range for the selection
57
- * For example, if selection starts in a listItem, go find the bullet list or ordered list, their $from
58
- * @param selection
59
- * @param schema
60
- * @returns
61
- */
62
- export var expandSelectionToBlockRange = function expandSelectionToBlockRange(selection, schema) {
63
- var nodes = schema.nodes;
64
- var nodesNeedToExpandRange = [nodes.bulletList, nodes.orderedList, nodes.taskList, nodes.listItem, nodes.taskItem];
65
-
66
- // when adding nodes.tableRow, tableHeader, tableCell in nodesNeedToExpandRang,
67
- // expandToBlockRange does not return expected table start position, sometimes even freeze editor
68
- // so handle table in the below logic
69
- if (isTableSelected(selection)) {
70
- var table = findTable(selection);
71
- if (table) {
72
- var $from = selection.$from.doc.resolve(table.pos);
73
- var $to = selection.$from.doc.resolve(table.pos + table.node.nodeSize - 1);
74
- return {
75
- $from: $from,
76
- $to: $to,
77
- range: $from.blockRange($to)
78
- };
79
- }
80
- }
81
-
82
- // when selecting a file, selection is on media
83
- // need to find media group and return its pos
84
- if (selection instanceof NodeSelection) {
85
- if (selection.node.type === nodes.media) {
86
- var mediaGroup = findParentNodeOfType(nodes.mediaGroup)(selection);
87
- if (mediaGroup) {
88
- var _$from = selection.$from.doc.resolve(mediaGroup.pos);
89
- var _$to = selection.$from.doc.resolve(mediaGroup.pos + mediaGroup.node.nodeSize);
90
- return {
91
- $from: _$from,
92
- $to: _$to
93
- };
94
- }
95
- }
96
- }
97
- return expandToBlockRange(selection.$from, selection.$to, function (node) {
98
- if (nodesNeedToExpandRange.includes(node.type)) {
99
- return false;
100
- }
101
- return true;
102
- });
103
- };
104
52
  export var isListType = function isListType(node, schema) {
105
53
  var lists = [schema.nodes.taskList, schema.nodes.bulletList, schema.nodes.orderedList];
106
54
  return lists.some(function (list) {
@@ -1,8 +1,8 @@
1
+ import { expandSelectionToBlockRange } from '@atlaskit/editor-common/selection';
1
2
  import { Fragment } from '@atlaskit/editor-prosemirror/model';
2
3
  import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
3
4
  import { isNestedNode } from '../ui/utils/isNestedNode';
4
5
  import { getOutputNodes } from './transform-node-utils/transform';
5
- import { expandSelectionToBlockRange } from './transform-node-utils/utils';
6
6
  import { isListNode } from './transforms/utils';
7
7
  export var transformNode = function transformNode(api) {
8
8
  return (
@@ -17,7 +17,7 @@ export var transformNode = function transformNode(api) {
17
17
  }
18
18
  var schema = tr.doc.type.schema;
19
19
  var nodes = schema.nodes;
20
- var _expandSelectionToBlo = expandSelectionToBlockRange(preservedSelection, schema),
20
+ var _expandSelectionToBlo = expandSelectionToBlockRange(preservedSelection),
21
21
  $from = _expandSelectionToBlo.$from,
22
22
  $to = _expandSelectionToBlo.$to;
23
23
  var isNested = isNestedNode(preservedSelection, '');
@@ -0,0 +1,30 @@
1
+ import React from 'react';
2
+ import { BlockMenuComponents } from './BlockMenuComponents';
3
+ import { getChildrenMapKey, willComponentRender } from './utils';
4
+ /**
5
+ * Renders the given registered component based on its type
6
+ */
7
+ export var BlockMenuComponent = function BlockMenuComponent(_ref) {
8
+ var registeredComponent = _ref.registeredComponent,
9
+ childrenMap = _ref.childrenMap,
10
+ fallbacks = _ref.fallbacks;
11
+ if (registeredComponent.type === 'block-menu-item') {
12
+ var ItemComponent = registeredComponent.component || fallbacks['block-menu-item'];
13
+ return /*#__PURE__*/React.createElement(ItemComponent, {
14
+ key: registeredComponent.key
15
+ });
16
+ }
17
+ if (!willComponentRender(registeredComponent, childrenMap)) {
18
+ return null;
19
+ }
20
+ var ParentComponent = registeredComponent.component || fallbacks[registeredComponent.type];
21
+ var childrenMapKey = getChildrenMapKey(registeredComponent.key, registeredComponent.type);
22
+ var registeredComponents = childrenMap.get(childrenMapKey);
23
+ return /*#__PURE__*/React.createElement(ParentComponent, {
24
+ key: registeredComponent.key
25
+ }, /*#__PURE__*/React.createElement(BlockMenuComponents, {
26
+ registeredComponents: registeredComponents,
27
+ childrenMap: childrenMap,
28
+ fallbacks: fallbacks
29
+ }));
30
+ };
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+ import { BlockMenuComponent } from './BlockMenuComponent';
3
+ /**
4
+ * Renders the given registered components
5
+ * Returns null if no components are rendered
6
+ */
7
+ export var BlockMenuComponents = function BlockMenuComponents(_ref) {
8
+ var registeredComponents = _ref.registeredComponents,
9
+ childrenMap = _ref.childrenMap,
10
+ fallbacks = _ref.fallbacks;
11
+ if (!(registeredComponents !== null && registeredComponents !== void 0 && registeredComponents.length)) {
12
+ return null;
13
+ }
14
+ return /*#__PURE__*/React.createElement(React.Fragment, null, registeredComponents.map(function (registeredComponent) {
15
+ return /*#__PURE__*/React.createElement(BlockMenuComponent, {
16
+ key: registeredComponent.key,
17
+ registeredComponent: registeredComponent,
18
+ childrenMap: childrenMap,
19
+ fallbacks: fallbacks
20
+ });
21
+ }));
22
+ };
@@ -0,0 +1,25 @@
1
+ import React, { useMemo } from 'react';
2
+ import { BlockMenuComponents } from './BlockMenuComponents';
3
+ import { BLOCK_MENU_FALLBACKS } from './fallbacks';
4
+ import { buildChildrenMap, getSortedTopLevelSections } from './utils';
5
+ /**
6
+ * BlockMenuRenderer orchestrates the rendering of the entire block menu hierarchy
7
+ */
8
+ export var BlockMenuRenderer = function BlockMenuRenderer(_ref) {
9
+ var allRegisteredComponents = _ref.allRegisteredComponents,
10
+ _ref$fallbacks = _ref.fallbacks,
11
+ fallbacks = _ref$fallbacks === void 0 ? BLOCK_MENU_FALLBACKS : _ref$fallbacks;
12
+ var _useMemo = useMemo(function () {
13
+ return {
14
+ childrenMap: buildChildrenMap(allRegisteredComponents),
15
+ topLevelSections: getSortedTopLevelSections(allRegisteredComponents)
16
+ };
17
+ }, [allRegisteredComponents]),
18
+ childrenMap = _useMemo.childrenMap,
19
+ topLevelSections = _useMemo.topLevelSections;
20
+ return /*#__PURE__*/React.createElement(BlockMenuComponents, {
21
+ registeredComponents: topLevelSections,
22
+ childrenMap: childrenMap,
23
+ fallbacks: fallbacks
24
+ });
25
+ };
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ import { ToolbarDropdownItem, ToolbarDropdownItemSection, ToolbarNestedDropdownMenu } from '@atlaskit/editor-toolbar';
3
+ import ChevronRightIcon from '@atlaskit/icon/core/chevron-right';
4
+ export var BLOCK_MENU_FALLBACKS = {
5
+ 'block-menu-nested': function blockMenuNested(_ref) {
6
+ var children = _ref.children;
7
+ return /*#__PURE__*/React.createElement(ToolbarNestedDropdownMenu, {
8
+ elemBefore: undefined,
9
+ elemAfter: /*#__PURE__*/React.createElement(ChevronRightIcon, {
10
+ label: ""
11
+ }),
12
+ text: "Nested Menu",
13
+ enableMaxHeight: true,
14
+ shouldFitContainer: true
15
+ }, children);
16
+ },
17
+ 'block-menu-section': function blockMenuSection(_ref2) {
18
+ var children = _ref2.children;
19
+ return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, null, children);
20
+ },
21
+ // eslint-disable-next-line @atlassian/i18n/no-literal-string-in-jsx
22
+ 'block-menu-item': function blockMenuItem() {
23
+ return /*#__PURE__*/React.createElement(ToolbarDropdownItem, null, "Block Menu Item");
24
+ }
25
+ };
@@ -0,0 +1 @@
1
+ export {};