@atlaskit/editor-plugin-block-menu 5.1.6 → 5.1.8

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 (41) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/cjs/editor-commands/transform-node-utils/flattenListStep.js +9 -32
  3. package/dist/cjs/editor-commands/transform-node-utils/transform.js +5 -4
  4. package/dist/cjs/editor-commands/transform-node-utils/unwrapListStep.js +16 -1
  5. package/dist/cjs/editor-commands/transform-node-utils/utils.js +30 -1
  6. package/dist/cjs/editor-commands/transform-node-utils/wrapMixedContentStep.js +141 -0
  7. package/dist/cjs/editor-commands/transformNode.js +6 -6
  8. package/dist/cjs/ui/block-menu-components.js +29 -24
  9. package/dist/cjs/ui/suggested-items-renderer.js +62 -0
  10. package/dist/cjs/ui/utils/suggested-items-rank.js +66 -0
  11. package/dist/es2019/editor-commands/transform-node-utils/flattenListStep.js +9 -32
  12. package/dist/es2019/editor-commands/transform-node-utils/transform.js +5 -4
  13. package/dist/es2019/editor-commands/transform-node-utils/unwrapListStep.js +16 -1
  14. package/dist/es2019/editor-commands/transform-node-utils/utils.js +29 -1
  15. package/dist/es2019/editor-commands/transform-node-utils/wrapMixedContentStep.js +135 -0
  16. package/dist/es2019/editor-commands/transformNode.js +2 -2
  17. package/dist/es2019/ui/block-menu-components.js +12 -9
  18. package/dist/es2019/ui/suggested-items-renderer.js +48 -0
  19. package/dist/es2019/ui/utils/suggested-items-rank.js +130 -0
  20. package/dist/esm/editor-commands/transform-node-utils/flattenListStep.js +9 -32
  21. package/dist/esm/editor-commands/transform-node-utils/transform.js +5 -4
  22. package/dist/esm/editor-commands/transform-node-utils/unwrapListStep.js +16 -1
  23. package/dist/esm/editor-commands/transform-node-utils/utils.js +30 -1
  24. package/dist/esm/editor-commands/transform-node-utils/wrapMixedContentStep.js +135 -0
  25. package/dist/esm/editor-commands/transformNode.js +4 -4
  26. package/dist/esm/ui/block-menu-components.js +30 -25
  27. package/dist/esm/ui/suggested-items-renderer.js +54 -0
  28. package/dist/esm/ui/utils/suggested-items-rank.js +60 -0
  29. package/dist/types/editor-commands/transform-node-utils/flattenListStep.d.ts +0 -18
  30. package/dist/types/editor-commands/transform-node-utils/unwrapListStep.d.ts +16 -1
  31. package/dist/types/editor-commands/transform-node-utils/utils.d.ts +12 -0
  32. package/dist/types/editor-commands/transform-node-utils/wrapMixedContentStep.d.ts +20 -0
  33. package/dist/types/ui/suggested-items-renderer.d.ts +8 -0
  34. package/dist/types/ui/utils/suggested-items-rank.d.ts +45 -0
  35. package/dist/types-ts4.5/editor-commands/transform-node-utils/flattenListStep.d.ts +0 -18
  36. package/dist/types-ts4.5/editor-commands/transform-node-utils/unwrapListStep.d.ts +16 -1
  37. package/dist/types-ts4.5/editor-commands/transform-node-utils/utils.d.ts +12 -0
  38. package/dist/types-ts4.5/editor-commands/transform-node-utils/wrapMixedContentStep.d.ts +20 -0
  39. package/dist/types-ts4.5/ui/suggested-items-renderer.d.ts +8 -0
  40. package/dist/types-ts4.5/ui/utils/suggested-items-rank.d.ts +45 -0
  41. package/package.json +4 -4
@@ -1,5 +1,6 @@
1
+ import { expandToBlockRange } from '@atlaskit/editor-common/selection';
1
2
  import { NodeSelection, TextSelection } from '@atlaskit/editor-prosemirror/state';
2
- import { findParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
3
+ import { findParentNodeOfType, hasParentNode } from '@atlaskit/editor-prosemirror/utils';
3
4
  import { CellSelection } from '@atlaskit/editor-tables';
4
5
  export var getSelectedNode = function getSelectedNode(selection) {
5
6
  if (selection instanceof NodeSelection) {
@@ -48,4 +49,32 @@ export var getTargetNodeTypeNameInContext = function getTargetNodeTypeNameInCont
48
49
  return 'nestedExpand';
49
50
  }
50
51
  return nodeTypeName;
52
+ };
53
+
54
+ /**
55
+ * Use common expandToBlockRange function, but account for edge cases with lists.
56
+ *
57
+ * @param selection
58
+ * @param schema
59
+ * @returns
60
+ */
61
+ export var expandSelectionToBlockRange = function expandSelectionToBlockRange(selection, schema) {
62
+ var isListInSelection = hasParentNode(function (node) {
63
+ return node.type === schema.nodes.bulletList || node.type === schema.nodes.orderedList;
64
+ })(selection);
65
+ var _expandToBlockRange = expandToBlockRange(selection.$from, selection.$to, function (node) {
66
+ if (!isListInSelection) {
67
+ return true;
68
+ }
69
+ if (node.type === schema.nodes.bulletList || node.type === schema.nodes.orderedList) {
70
+ return true;
71
+ }
72
+ return false;
73
+ }),
74
+ $from = _expandToBlockRange.$from,
75
+ $to = _expandToBlockRange.$to;
76
+ return {
77
+ $from: $from,
78
+ $to: $to
79
+ };
51
80
  };
@@ -0,0 +1,135 @@
1
+ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
+ import { Fragment } from '@atlaskit/editor-prosemirror/model';
3
+ import { NODE_CATEGORY_BY_TYPE } from './types';
4
+ import { unwrapStep } from './unwrapStep';
5
+
6
+ /**
7
+ * Determines if a node can be flattened (unwrapped and its contents merged).
8
+ *
9
+ * According to the text transformations list, flattenable nodes are:
10
+ * - Bulleted list, Numbered list, Task list
11
+ * - Text nodes (heading, paragraph)
12
+ *
13
+ * Containers (panels, expands, layouts, blockquotes) and atomic nodes (tables, media, macros) break out.
14
+ */
15
+ var canFlatten = function canFlatten(node) {
16
+ var category = NODE_CATEGORY_BY_TYPE[node.type.name];
17
+ // Text and list nodes can be flattened (converted to simpler forms)
18
+ return category === 'text' || category === 'list';
19
+ };
20
+
21
+ /**
22
+ * Flattens a node by extracting its contents using the appropriate unwrap step.
23
+ * This is only called for text and list nodes that can be converted to simpler forms.
24
+ * Uses unwrapStep to extract children from list containers.
25
+ */
26
+ var flattenNode = function flattenNode(node, context) {
27
+ return unwrapStep([node], context);
28
+ };
29
+
30
+ /**
31
+ * Determines if a node can be wrapped in the target container type.
32
+ * Uses the schema's validContent to check if the target container can hold this node.
33
+ *
34
+ * Note: What can be wrapped depends on the target container type - for example:
35
+ * - Tables and media CAN go inside expand nodes
36
+ * - Tables CANNOT go inside panels or blockquotes
37
+ */
38
+ var canWrapInTarget = function canWrapInTarget(node, targetNodeType, targetNodeTypeName) {
39
+ // Same-type containers should break out as separate containers
40
+ if (node.type.name === targetNodeTypeName) {
41
+ return false;
42
+ }
43
+
44
+ // Use the schema to determine if this node can be contained in the target
45
+ try {
46
+ return targetNodeType.validContent(Fragment.from(node));
47
+ } catch (_unused) {
48
+ return false;
49
+ }
50
+ };
51
+
52
+ /**
53
+ * Converts a nestedExpand to a regular expand node.
54
+ * NestedExpands can only exist inside expands, so when breaking out they must be converted.
55
+ */
56
+ var convertNestedExpandToExpand = function convertNestedExpandToExpand(node, schema) {
57
+ var _node$attrs;
58
+ var expandType = schema.nodes.expand;
59
+ if (!expandType) {
60
+ return null;
61
+ }
62
+ return expandType.createAndFill({
63
+ title: ((_node$attrs = node.attrs) === null || _node$attrs === void 0 ? void 0 : _node$attrs.title) || ''
64
+ }, node.content);
65
+ };
66
+
67
+ /**
68
+ * A wrap step that handles mixed content according to the Compatibility Matrix:
69
+ * - Wraps consecutive compatible nodes into the target container
70
+ * - Same-type containers break out as separate containers (preserved as-is)
71
+ * - NestedExpands break out as regular expands (converted since nestedExpand can't exist outside expand)
72
+ * - Container structures that can't be nested in target break out (not flattened)
73
+ * - Text/list nodes that can't be wrapped are flattened and merged into the container
74
+ * - Atomic nodes (tables, media, macros) break out
75
+ *
76
+ * What can be wrapped depends on the target container's schema:
77
+ * - expand → panel: tables break out, nestedExpands convert to expands and break out
78
+ * - expand → blockquote: tables/media break out, nestedExpands convert to expands and break out
79
+ * - expand → expand: tables/media stay inside (expands can contain them)
80
+ *
81
+ * Example: expand(p('a'), table(), p('b')) → panel: [panel(p('a')), table(), panel(p('b'))]
82
+ * Example: expand(p('a'), panel(p('x')), p('b')) → panel: [panel(p('a')), panel(p('x')), panel(p('b'))]
83
+ * Example: expand(p('a'), nestedExpand({title: 'inner'})(p('x')), p('b')) → panel: [panel(p('a')), expand({title: 'inner'})(p('x')), panel(p('b'))]
84
+ */
85
+ export var wrapMixedContentStep = function wrapMixedContentStep(nodes, context) {
86
+ var schema = context.schema,
87
+ targetNodeTypeName = context.targetNodeTypeName;
88
+ var targetNodeType = schema.nodes[targetNodeTypeName];
89
+ if (!targetNodeType) {
90
+ return nodes;
91
+ }
92
+ var result = [];
93
+ var currentContainerContent = [];
94
+ var flushCurrentContainer = function flushCurrentContainer() {
95
+ if (currentContainerContent.length > 0) {
96
+ var containerNode = targetNodeType.createAndFill({}, Fragment.fromArray(currentContainerContent));
97
+ if (containerNode) {
98
+ result.push(containerNode);
99
+ }
100
+ currentContainerContent = [];
101
+ }
102
+ };
103
+ nodes.forEach(function (node) {
104
+ if (canWrapInTarget(node, targetNodeType, targetNodeTypeName)) {
105
+ // Node can be wrapped - add to current container content
106
+ currentContainerContent.push(node);
107
+ } else if (node.type.name === targetNodeTypeName) {
108
+ // Same-type container - breaks out as a separate container (preserved as-is)
109
+ // This handles: "If there's a panel in the expand, it breaks out into a separate panel"
110
+ flushCurrentContainer();
111
+ result.push(node);
112
+ } else if (node.type.name === 'nestedExpand') {
113
+ // NestedExpand can't be wrapped and can't exist outside an expand
114
+ // Convert to regular expand and break out
115
+ flushCurrentContainer();
116
+ var expandNode = convertNestedExpandToExpand(node, schema);
117
+ if (expandNode) {
118
+ result.push(expandNode);
119
+ }
120
+ } else if (canFlatten(node)) {
121
+ var _currentContainerCont;
122
+ // Node cannot be wrapped but CAN be flattened - flatten and add to container
123
+ var flattenedNodes = flattenNode(node, context);
124
+ (_currentContainerCont = currentContainerContent).push.apply(_currentContainerCont, _toConsumableArray(flattenedNodes));
125
+ } else {
126
+ // Node cannot be wrapped AND cannot be flattened (containers, tables, media, macros) - break out
127
+ flushCurrentContainer();
128
+ result.push(node);
129
+ }
130
+ });
131
+
132
+ // Flush any remaining content into a container
133
+ flushCurrentContainer();
134
+ return result.length > 0 ? result : nodes;
135
+ };
@@ -1,7 +1,7 @@
1
- import { expandToBlockRange } from '@atlaskit/editor-common/selection';
2
1
  import { Fragment } from '@atlaskit/editor-prosemirror/model';
3
2
  import { isNestedNode } from '../ui/utils/isNestedNode';
4
3
  import { getOutputNodes } from './transform-node-utils/transform';
4
+ import { expandSelectionToBlockRange } from './transform-node-utils/utils';
5
5
  import { isListNode } from './transforms/utils';
6
6
  export var transformNode = function transformNode(api) {
7
7
  return (
@@ -14,9 +14,9 @@ export var transformNode = function transformNode(api) {
14
14
  if (!preservedSelection) {
15
15
  return tr;
16
16
  }
17
- var _expandToBlockRange = expandToBlockRange(preservedSelection.$from, preservedSelection.$to),
18
- $from = _expandToBlockRange.$from,
19
- $to = _expandToBlockRange.$to;
17
+ var _expandSelectionToBlo = expandSelectionToBlockRange(preservedSelection, tr.doc.type.schema),
18
+ $from = _expandSelectionToBlo.$from,
19
+ $to = _expandSelectionToBlo.$to;
20
20
  var isNested = isNestedNode(preservedSelection, '');
21
21
  var selectedParent = $from.parent;
22
22
  var fragment = Fragment.empty;
@@ -1,6 +1,6 @@
1
1
  import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
2
  import React from 'react';
3
- import { BLOCK_ACTIONS_COPY_LINK_TO_BLOCK_MENU_ITEM, BLOCK_ACTIONS_MENU_SECTION, BLOCK_ACTIONS_MENU_SECTION_RANK, DELETE_MENU_SECTION, DELETE_MENU_SECTION_RANK, DELETE_MENU_ITEM, POSITION_MENU_SECTION, POSITION_MENU_SECTION_RANK, POSITION_MOVE_DOWN_MENU_ITEM, POSITION_MOVE_UP_MENU_ITEM, TRANSFORM_MENU_ITEM, TRANSFORM_MENU_ITEM_RANK, TRANSFORM_MENU_SECTION, TRANSFORM_MENU_SECTION_RANK, TRANSFORM_CREATE_MENU_SECTION, TRANSFORM_SUGGESTED_MENU_SECTION, TRANSFORM_STRUCTURE_MENU_SECTION, TRANSFORM_HEADINGS_MENU_SECTION, MAIN_BLOCK_MENU_SECTION_RANK } from '@atlaskit/editor-common/block-menu';
3
+ import { BLOCK_ACTIONS_COPY_LINK_TO_BLOCK_MENU_ITEM, BLOCK_ACTIONS_MENU_SECTION, BLOCK_ACTIONS_MENU_SECTION_RANK, DELETE_MENU_SECTION, DELETE_MENU_SECTION_RANK, DELETE_MENU_ITEM, POSITION_MENU_SECTION, POSITION_MENU_SECTION_RANK, POSITION_MOVE_DOWN_MENU_ITEM, POSITION_MOVE_UP_MENU_ITEM, TRANSFORM_MENU_ITEM, TRANSFORM_MENU_ITEM_RANK, TRANSFORM_MENU_SECTION, TRANSFORM_MENU_SECTION_RANK, TRANSFORM_CREATE_MENU_SECTION, TRANSFORM_SUGGESTED_MENU_SECTION, TRANSFORM_STRUCTURE_MENU_SECTION, TRANSFORM_HEADINGS_MENU_SECTION, MAIN_BLOCK_MENU_SECTION_RANK, TRANSFORM_SUGGESTED_MENU_SECTION_RANK, TRANSFORM_SUGGESTED_MENU_ITEM } from '@atlaskit/editor-common/block-menu';
4
4
  import { ToolbarDropdownItemSection } from '@atlaskit/editor-toolbar';
5
5
  import { CopyLinkDropdownItem } from './copy-link';
6
6
  import { CopySection } from './copy-section';
@@ -10,6 +10,7 @@ import { FormatMenuComponent } from './format-menu-nested';
10
10
  import { FormatMenuSection } from './format-menu-section';
11
11
  import { MoveDownDropdownItem } from './move-down';
12
12
  import { MoveUpDropdownItem } from './move-up';
13
+ import { SuggestedItemsRenderer } from './suggested-items-renderer';
13
14
  var getMoveUpMoveDownMenuComponents = function getMoveUpMoveDownMenuComponents(api) {
14
15
  return [{
15
16
  type: 'block-menu-item',
@@ -66,13 +67,17 @@ var getTurnIntoMenuComponents = function getTurnIntoMenuComponents(api) {
66
67
  rank: TRANSFORM_MENU_ITEM_RANK[TRANSFORM_SUGGESTED_MENU_SECTION.key]
67
68
  },
68
69
  component: function component() {
69
- var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
70
- children: null
71
- },
72
- children = _ref2.children;
73
- return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, {
74
- title: "Suggested"
75
- }, children);
70
+ return /*#__PURE__*/React.createElement(SuggestedItemsRenderer, {
71
+ api: api
72
+ });
73
+ }
74
+ }, {
75
+ type: 'block-menu-item',
76
+ key: TRANSFORM_SUGGESTED_MENU_ITEM.key,
77
+ parent: {
78
+ type: 'block-menu-section',
79
+ key: TRANSFORM_SUGGESTED_MENU_SECTION.key,
80
+ rank: TRANSFORM_SUGGESTED_MENU_SECTION_RANK[TRANSFORM_SUGGESTED_MENU_ITEM.key]
76
81
  }
77
82
  }, {
78
83
  type: 'block-menu-section',
@@ -83,10 +88,10 @@ var getTurnIntoMenuComponents = function getTurnIntoMenuComponents(api) {
83
88
  rank: TRANSFORM_MENU_ITEM_RANK[TRANSFORM_CREATE_MENU_SECTION.key]
84
89
  },
85
90
  component: function component() {
86
- var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
91
+ var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
87
92
  children: null
88
93
  },
89
- children = _ref3.children;
94
+ children = _ref2.children;
90
95
  return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, {
91
96
  title: "Create"
92
97
  }, children);
@@ -100,10 +105,10 @@ var getTurnIntoMenuComponents = function getTurnIntoMenuComponents(api) {
100
105
  rank: TRANSFORM_MENU_ITEM_RANK[TRANSFORM_STRUCTURE_MENU_SECTION.key]
101
106
  },
102
107
  component: function component() {
103
- var _ref4 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
108
+ var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
104
109
  children: null
105
110
  },
106
- children = _ref4.children;
111
+ children = _ref3.children;
107
112
  return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, {
108
113
  title: "Structure"
109
114
  }, children);
@@ -117,10 +122,10 @@ var getTurnIntoMenuComponents = function getTurnIntoMenuComponents(api) {
117
122
  rank: TRANSFORM_MENU_ITEM_RANK[TRANSFORM_HEADINGS_MENU_SECTION.key]
118
123
  },
119
124
  component: function component() {
120
- var _ref5 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
125
+ var _ref4 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
121
126
  children: null
122
127
  },
123
- children = _ref5.children;
128
+ children = _ref4.children;
124
129
  return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, {
125
130
  title: "Headings",
126
131
  hasSeparator: true
@@ -130,23 +135,23 @@ var getTurnIntoMenuComponents = function getTurnIntoMenuComponents(api) {
130
135
  type: 'block-menu-section',
131
136
  key: TRANSFORM_MENU_SECTION.key,
132
137
  rank: MAIN_BLOCK_MENU_SECTION_RANK[TRANSFORM_MENU_SECTION.key],
133
- component: function component(_ref6) {
134
- var children = _ref6.children;
138
+ component: function component(_ref5) {
139
+ var children = _ref5.children;
135
140
  return /*#__PURE__*/React.createElement(FormatMenuSection, {
136
141
  api: api
137
142
  }, children);
138
143
  }
139
144
  }];
140
145
  };
141
- export var getBlockMenuComponents = function getBlockMenuComponents(_ref7) {
142
- var api = _ref7.api,
143
- config = _ref7.config;
146
+ export var getBlockMenuComponents = function getBlockMenuComponents(_ref6) {
147
+ var api = _ref6.api,
148
+ config = _ref6.config;
144
149
  return [].concat(_toConsumableArray(getTurnIntoMenuComponents(api)), [{
145
150
  type: 'block-menu-section',
146
151
  key: BLOCK_ACTIONS_MENU_SECTION.key,
147
152
  rank: MAIN_BLOCK_MENU_SECTION_RANK[BLOCK_ACTIONS_MENU_SECTION.key],
148
- component: function component(_ref8) {
149
- var children = _ref8.children;
153
+ component: function component(_ref7) {
154
+ var children = _ref7.children;
150
155
  return /*#__PURE__*/React.createElement(CopySection, {
151
156
  api: api
152
157
  }, children);
@@ -169,8 +174,8 @@ export var getBlockMenuComponents = function getBlockMenuComponents(_ref7) {
169
174
  type: 'block-menu-section',
170
175
  key: POSITION_MENU_SECTION.key,
171
176
  rank: MAIN_BLOCK_MENU_SECTION_RANK[POSITION_MENU_SECTION.key],
172
- component: function component(_ref9) {
173
- var children = _ref9.children;
177
+ component: function component(_ref8) {
178
+ var children = _ref8.children;
174
179
  return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, {
175
180
  hasSeparator: true
176
181
  }, children);
@@ -179,8 +184,8 @@ export var getBlockMenuComponents = function getBlockMenuComponents(_ref7) {
179
184
  type: 'block-menu-section',
180
185
  key: DELETE_MENU_SECTION.key,
181
186
  rank: MAIN_BLOCK_MENU_SECTION_RANK[DELETE_MENU_SECTION.key],
182
- component: function component(_ref0) {
183
- var children = _ref0.children;
187
+ component: function component(_ref9) {
188
+ var children = _ref9.children;
184
189
  return /*#__PURE__*/React.createElement(DeleteSection, {
185
190
  api: api
186
191
  }, children);
@@ -0,0 +1,54 @@
1
+ import React, { useMemo } from 'react';
2
+ import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
3
+ import { ToolbarDropdownItemSection } from '@atlaskit/editor-toolbar';
4
+ import { getSelectedNode } from '../editor-commands/transform-node-utils/utils';
5
+ import { getSortedSuggestedItems } from './utils/suggested-items-rank';
6
+ export var SuggestedItemsRenderer = /*#__PURE__*/React.memo(function (_ref) {
7
+ var _api$blockMenu;
8
+ var api = _ref.api;
9
+ var _useSharedPluginState = useSharedPluginStateWithSelector(api, ['blockControls'], function (states) {
10
+ var _states$blockControls;
11
+ return {
12
+ preservedSelection: (_states$blockControls = states.blockControlsState) === null || _states$blockControls === void 0 ? void 0 : _states$blockControls.preservedSelection
13
+ };
14
+ }),
15
+ preservedSelection = _useSharedPluginState.preservedSelection;
16
+ var blockMenuComponents = api === null || api === void 0 || (_api$blockMenu = api.blockMenu) === null || _api$blockMenu === void 0 ? void 0 : _api$blockMenu.actions.getBlockMenuComponents();
17
+ var menuItemsMap = useMemo(function () {
18
+ if (!blockMenuComponents) {
19
+ return new Map();
20
+ }
21
+ return new Map(blockMenuComponents.filter(function (c) {
22
+ return c.type === 'block-menu-item';
23
+ }).map(function (item) {
24
+ return [item.key, item];
25
+ }));
26
+ }, [blockMenuComponents]);
27
+ var suggestedItems = useMemo(function () {
28
+ if (!preservedSelection || menuItemsMap.size === 0) {
29
+ return [];
30
+ }
31
+ var selectedNode = getSelectedNode(preservedSelection);
32
+ if (!selectedNode) {
33
+ return [];
34
+ }
35
+ var nodeTypeName = selectedNode.node.type.name;
36
+ var sortedKeys = getSortedSuggestedItems(nodeTypeName);
37
+ return sortedKeys.map(function (key) {
38
+ return menuItemsMap.get(key);
39
+ }).filter(function (item) {
40
+ return item !== undefined;
41
+ });
42
+ }, [menuItemsMap, preservedSelection]);
43
+ if (suggestedItems.length === 0) {
44
+ return null;
45
+ }
46
+ return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, {
47
+ title: "Suggested"
48
+ }, suggestedItems.map(function (item) {
49
+ var ItemComponent = item.component;
50
+ return ItemComponent ? /*#__PURE__*/React.createElement(ItemComponent, {
51
+ key: item.key
52
+ }) : null;
53
+ }));
54
+ });
@@ -0,0 +1,60 @@
1
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
3
+ var _TRANSFORM_SUGGESTED_;
4
+ /**
5
+ * Suggested transformations mapping for each block type.
6
+ * Based on the Block Menu Compatibility Matrix:
7
+ * https://hello.atlassian.net/wiki/spaces/egcuc/pages/5868774224/Block+Menu+Compatibility+Matrix#Suggested-for-each-block-type
8
+ *
9
+ * This mapping defines which transform items should appear in the TRANSFORM_SUGGESTED_MENU_SECTION
10
+ * for each block type, ranked by priority (lower rank = higher priority).
11
+ *
12
+ * Structure:
13
+ * {
14
+ * [sourceNodeType]: {
15
+ * [targetMenuItemKey]: rank
16
+ * }
17
+ * }
18
+ */
19
+
20
+ import { TRANSFORM_STRUCTURE_PANEL_MENU_ITEM, TRANSFORM_STRUCTURE_EXPAND_MENU_ITEM, TRANSFORM_STRUCTURE_LAYOUT_MENU_ITEM, TRANSFORM_STRUCTURE_QUOTE_MENU_ITEM, TRANSFORM_STRUCTURE_CODE_BLOCK_MENU_ITEM, TRANSFORM_STRUCTURE_BULLETED_LIST_MENU_ITEM, TRANSFORM_STRUCTURE_NUMBERED_LIST_MENU_ITEM, TRANSFORM_STRUCTURE_TASK_LIST_MENU_ITEM, TRANSFORM_HEADINGS_H2_MENU_ITEM, TRANSFORM_HEADINGS_H3_MENU_ITEM, TRANSFORM_STRUCTURE_PARAGRAPH_MENU_ITEM } from '@atlaskit/editor-common/block-menu';
21
+ export var BLOCK_MENU_NODE_TYPES = {
22
+ PARAGRAPH: 'paragraph',
23
+ EXPAND: 'expand',
24
+ BLOCKQUOTE: 'blockquote',
25
+ LAYOUT_SECTION: 'layoutSection',
26
+ PANEL: 'panel',
27
+ CODE_BLOCK: 'codeBlock',
28
+ DECISION: 'decisionList',
29
+ BULLET_LIST: 'bulletList',
30
+ ORDERED_LIST: 'orderedList',
31
+ HEADING: 'heading',
32
+ TASK_LIST: 'taskList',
33
+ MEDIA_SINGLE: 'mediaSingle',
34
+ EXTENSION: 'extension',
35
+ BODIED_EXTENSION: 'bodiedExtension',
36
+ BLOCK_CARD: 'blockCard',
37
+ EMBED_CARD: 'embedCard',
38
+ TABLE: 'table'
39
+ };
40
+ export var TRANSFORM_SUGGESTED_ITEMS_RANK = (_TRANSFORM_SUGGESTED_ = {}, _defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_TRANSFORM_SUGGESTED_, BLOCK_MENU_NODE_TYPES.PARAGRAPH, _defineProperty(_defineProperty(_defineProperty({}, TRANSFORM_STRUCTURE_PANEL_MENU_ITEM.key, 100), TRANSFORM_HEADINGS_H2_MENU_ITEM.key, 200), TRANSFORM_HEADINGS_H3_MENU_ITEM.key, 300)), BLOCK_MENU_NODE_TYPES.EXPAND, _defineProperty(_defineProperty(_defineProperty({}, TRANSFORM_STRUCTURE_PANEL_MENU_ITEM.key, 100), TRANSFORM_STRUCTURE_LAYOUT_MENU_ITEM.key, 200), TRANSFORM_STRUCTURE_PARAGRAPH_MENU_ITEM.key, 300)), BLOCK_MENU_NODE_TYPES.BLOCKQUOTE, _defineProperty(_defineProperty(_defineProperty({}, TRANSFORM_STRUCTURE_PANEL_MENU_ITEM.key, 100), TRANSFORM_STRUCTURE_PARAGRAPH_MENU_ITEM.key, 200), TRANSFORM_STRUCTURE_LAYOUT_MENU_ITEM.key, 300)), BLOCK_MENU_NODE_TYPES.LAYOUT_SECTION, _defineProperty(_defineProperty(_defineProperty({}, TRANSFORM_STRUCTURE_PANEL_MENU_ITEM.key, 100), TRANSFORM_STRUCTURE_EXPAND_MENU_ITEM.key, 200), TRANSFORM_HEADINGS_H2_MENU_ITEM.key, 300)), BLOCK_MENU_NODE_TYPES.PANEL, _defineProperty(_defineProperty(_defineProperty({}, TRANSFORM_STRUCTURE_PARAGRAPH_MENU_ITEM.key, 100), TRANSFORM_STRUCTURE_QUOTE_MENU_ITEM.key, 200), TRANSFORM_STRUCTURE_CODE_BLOCK_MENU_ITEM.key, 300)), BLOCK_MENU_NODE_TYPES.CODE_BLOCK, _defineProperty(_defineProperty(_defineProperty({}, TRANSFORM_STRUCTURE_EXPAND_MENU_ITEM.key, 100), TRANSFORM_STRUCTURE_LAYOUT_MENU_ITEM.key, 200), TRANSFORM_STRUCTURE_PANEL_MENU_ITEM.key, 300)), BLOCK_MENU_NODE_TYPES.DECISION, _defineProperty(_defineProperty(_defineProperty({}, TRANSFORM_STRUCTURE_PANEL_MENU_ITEM.key, 100), TRANSFORM_STRUCTURE_PARAGRAPH_MENU_ITEM.key, 200), TRANSFORM_STRUCTURE_TASK_LIST_MENU_ITEM.key, 300)), BLOCK_MENU_NODE_TYPES.BULLET_LIST, _defineProperty(_defineProperty(_defineProperty({}, TRANSFORM_STRUCTURE_NUMBERED_LIST_MENU_ITEM.key, 100), TRANSFORM_STRUCTURE_QUOTE_MENU_ITEM.key, 200), TRANSFORM_STRUCTURE_PARAGRAPH_MENU_ITEM.key, 300)), BLOCK_MENU_NODE_TYPES.ORDERED_LIST, _defineProperty(_defineProperty(_defineProperty({}, TRANSFORM_STRUCTURE_BULLETED_LIST_MENU_ITEM.key, 100), TRANSFORM_STRUCTURE_TASK_LIST_MENU_ITEM.key, 200), TRANSFORM_STRUCTURE_PARAGRAPH_MENU_ITEM.key, 300)), BLOCK_MENU_NODE_TYPES.HEADING, _defineProperty(_defineProperty(_defineProperty({}, TRANSFORM_STRUCTURE_PARAGRAPH_MENU_ITEM.key, 100), TRANSFORM_HEADINGS_H2_MENU_ITEM.key, 200), TRANSFORM_STRUCTURE_PANEL_MENU_ITEM.key, 300)), _defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_TRANSFORM_SUGGESTED_, BLOCK_MENU_NODE_TYPES.TASK_LIST, _defineProperty(_defineProperty(_defineProperty({}, TRANSFORM_STRUCTURE_PARAGRAPH_MENU_ITEM.key, 100), TRANSFORM_STRUCTURE_NUMBERED_LIST_MENU_ITEM.key, 200), TRANSFORM_STRUCTURE_CODE_BLOCK_MENU_ITEM.key, 300)), BLOCK_MENU_NODE_TYPES.MEDIA_SINGLE, _defineProperty(_defineProperty(_defineProperty({}, TRANSFORM_STRUCTURE_PANEL_MENU_ITEM.key, 100), TRANSFORM_STRUCTURE_LAYOUT_MENU_ITEM.key, 200), TRANSFORM_STRUCTURE_PARAGRAPH_MENU_ITEM.key, 300)), BLOCK_MENU_NODE_TYPES.EXTENSION, _defineProperty(_defineProperty(_defineProperty({}, TRANSFORM_STRUCTURE_PANEL_MENU_ITEM.key, 100), TRANSFORM_STRUCTURE_PARAGRAPH_MENU_ITEM.key, 200), TRANSFORM_STRUCTURE_EXPAND_MENU_ITEM.key, 300)), BLOCK_MENU_NODE_TYPES.BODIED_EXTENSION, _defineProperty(_defineProperty(_defineProperty({}, TRANSFORM_STRUCTURE_PANEL_MENU_ITEM.key, 100), TRANSFORM_STRUCTURE_PARAGRAPH_MENU_ITEM.key, 200), TRANSFORM_STRUCTURE_EXPAND_MENU_ITEM.key, 300)), BLOCK_MENU_NODE_TYPES.BLOCK_CARD, _defineProperty(_defineProperty({}, TRANSFORM_STRUCTURE_PANEL_MENU_ITEM.key, 100), TRANSFORM_STRUCTURE_PARAGRAPH_MENU_ITEM.key, 200)), BLOCK_MENU_NODE_TYPES.EMBED_CARD, _defineProperty(_defineProperty({}, TRANSFORM_STRUCTURE_PANEL_MENU_ITEM.key, 100), TRANSFORM_STRUCTURE_PARAGRAPH_MENU_ITEM.key, 200)), BLOCK_MENU_NODE_TYPES.TABLE, _defineProperty(_defineProperty({}, TRANSFORM_STRUCTURE_EXPAND_MENU_ITEM.key, 100), TRANSFORM_STRUCTURE_LAYOUT_MENU_ITEM.key, 200)));
41
+ export var getSuggestedItemsForNodeType = function getSuggestedItemsForNodeType(nodeType) {
42
+ return TRANSFORM_SUGGESTED_ITEMS_RANK[nodeType];
43
+ };
44
+ export var getSortedSuggestedItems = function getSortedSuggestedItems(nodeType) {
45
+ var suggestions = getSuggestedItemsForNodeType(nodeType);
46
+ if (!suggestions) {
47
+ return [];
48
+ }
49
+ return Object.entries(suggestions).sort(function (_ref, _ref2) {
50
+ var _ref3 = _slicedToArray(_ref, 2),
51
+ rankA = _ref3[1];
52
+ var _ref4 = _slicedToArray(_ref2, 2),
53
+ rankB = _ref4[1];
54
+ return rankA - rankB;
55
+ }).map(function (_ref5) {
56
+ var _ref6 = _slicedToArray(_ref5, 1),
57
+ key = _ref6[0];
58
+ return key;
59
+ });
60
+ };
@@ -4,24 +4,6 @@ import type { TransformStep } from './types';
4
4
  * to it's first ancestor list, maintaining document order.
5
5
  *
6
6
  * @example
7
- * Input:
8
- * - bulletList
9
- * - listItem "A"
10
- * - listItem "B"
11
- * - bulletList
12
- * - listItem "C"
13
- * - listItem "D"
14
- * - listItem "E"
15
- *
16
- * Output:
17
- * - bulletList
18
- * - listItem "A"
19
- * - listItem "B"
20
- * - listItem "C"
21
- * - listItem "D"
22
- * - listItem "E"
23
- *
24
- * @example
25
7
  * Input (deeply nested):
26
8
  * - bulletList
27
9
  * - listItem "1"
@@ -1,7 +1,22 @@
1
1
  import type { TransformStep } from './types';
2
2
  /**
3
- * Given an array of nodes, returns an array with the flattened children of any list nodes.
3
+ * Given an array of nodes, processes each list removing all parent list nodes and
4
+ * just returning their child contents.
5
+ *
6
+ * @example
7
+ * Input:
8
+ * - bulletList
9
+ * - listItem "1"
10
+ * - paragraph "1"
11
+ * - listItem "2"
12
+ * - paragraph "2"
13
+ *
14
+ * Output:
15
+ * - paragraph "1"
16
+ * - paragraph "2"
17
+ *
4
18
  * @param nodes
19
+ * @param context
5
20
  * @returns
6
21
  */
7
22
  export declare const unwrapListStep: TransformStep;
@@ -1,5 +1,17 @@
1
+ import type { Schema } from '@atlaskit/editor-prosemirror/model';
1
2
  import type { Selection } from '@atlaskit/editor-prosemirror/state';
2
3
  import { type ContentNodeWithPos } from '@atlaskit/editor-prosemirror/utils';
3
4
  import type { NodeTypeName } from './types';
4
5
  export declare const getSelectedNode: (selection: Selection) => ContentNodeWithPos | undefined;
5
6
  export declare const getTargetNodeTypeNameInContext: (nodeTypeName: NodeTypeName | null, isNested?: boolean) => NodeTypeName | null;
7
+ /**
8
+ * Use common expandToBlockRange function, but account for edge cases with lists.
9
+ *
10
+ * @param selection
11
+ * @param schema
12
+ * @returns
13
+ */
14
+ export declare const expandSelectionToBlockRange: (selection: Selection, schema: Schema) => {
15
+ $from: import("prosemirror-model").ResolvedPos;
16
+ $to: import("prosemirror-model").ResolvedPos;
17
+ };
@@ -0,0 +1,20 @@
1
+ import type { TransformStep } from './types';
2
+ /**
3
+ * A wrap step that handles mixed content according to the Compatibility Matrix:
4
+ * - Wraps consecutive compatible nodes into the target container
5
+ * - Same-type containers break out as separate containers (preserved as-is)
6
+ * - NestedExpands break out as regular expands (converted since nestedExpand can't exist outside expand)
7
+ * - Container structures that can't be nested in target break out (not flattened)
8
+ * - Text/list nodes that can't be wrapped are flattened and merged into the container
9
+ * - Atomic nodes (tables, media, macros) break out
10
+ *
11
+ * What can be wrapped depends on the target container's schema:
12
+ * - expand → panel: tables break out, nestedExpands convert to expands and break out
13
+ * - expand → blockquote: tables/media break out, nestedExpands convert to expands and break out
14
+ * - expand → expand: tables/media stay inside (expands can contain them)
15
+ *
16
+ * Example: expand(p('a'), table(), p('b')) → panel: [panel(p('a')), table(), panel(p('b'))]
17
+ * Example: expand(p('a'), panel(p('x')), p('b')) → panel: [panel(p('a')), panel(p('x')), panel(p('b'))]
18
+ * Example: expand(p('a'), nestedExpand({title: 'inner'})(p('x')), p('b')) → panel: [panel(p('a')), expand({title: 'inner'})(p('x')), panel(p('b'))]
19
+ */
20
+ export declare const wrapMixedContentStep: TransformStep;
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
3
+ import type { BlockMenuPlugin } from '../blockMenuPluginType';
4
+ type SuggestedItemsRendererProps = {
5
+ api: ExtractInjectionAPI<BlockMenuPlugin> | undefined;
6
+ };
7
+ export declare const SuggestedItemsRenderer: React.NamedExoticComponent<SuggestedItemsRendererProps>;
8
+ export {};
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Suggested transformations mapping for each block type.
3
+ * Based on the Block Menu Compatibility Matrix:
4
+ * https://hello.atlassian.net/wiki/spaces/egcuc/pages/5868774224/Block+Menu+Compatibility+Matrix#Suggested-for-each-block-type
5
+ *
6
+ * This mapping defines which transform items should appear in the TRANSFORM_SUGGESTED_MENU_SECTION
7
+ * for each block type, ranked by priority (lower rank = higher priority).
8
+ *
9
+ * Structure:
10
+ * {
11
+ * [sourceNodeType]: {
12
+ * [targetMenuItemKey]: rank
13
+ * }
14
+ * }
15
+ */
16
+ export declare const BLOCK_MENU_NODE_TYPES: {
17
+ readonly PARAGRAPH: "paragraph";
18
+ readonly EXPAND: "expand";
19
+ readonly BLOCKQUOTE: "blockquote";
20
+ readonly LAYOUT_SECTION: "layoutSection";
21
+ readonly PANEL: "panel";
22
+ readonly CODE_BLOCK: "codeBlock";
23
+ readonly DECISION: "decisionList";
24
+ readonly BULLET_LIST: "bulletList";
25
+ readonly ORDERED_LIST: "orderedList";
26
+ readonly HEADING: "heading";
27
+ readonly TASK_LIST: "taskList";
28
+ readonly MEDIA_SINGLE: "mediaSingle";
29
+ readonly EXTENSION: "extension";
30
+ readonly BODIED_EXTENSION: "bodiedExtension";
31
+ readonly BLOCK_CARD: "blockCard";
32
+ readonly EMBED_CARD: "embedCard";
33
+ readonly TABLE: "table";
34
+ };
35
+ export type BlockMenuNodeType = (typeof BLOCK_MENU_NODE_TYPES)[keyof typeof BLOCK_MENU_NODE_TYPES];
36
+ export type SuggestedItemsRankMap = {
37
+ [nodeType: string]: {
38
+ [menuItemKey: string]: number;
39
+ };
40
+ };
41
+ export declare const TRANSFORM_SUGGESTED_ITEMS_RANK: SuggestedItemsRankMap;
42
+ export declare const getSuggestedItemsForNodeType: (nodeType: string) => {
43
+ [menuItemKey: string]: number;
44
+ } | undefined;
45
+ export declare const getSortedSuggestedItems: (nodeType: string) => string[];
@@ -4,24 +4,6 @@ import type { TransformStep } from './types';
4
4
  * to it's first ancestor list, maintaining document order.
5
5
  *
6
6
  * @example
7
- * Input:
8
- * - bulletList
9
- * - listItem "A"
10
- * - listItem "B"
11
- * - bulletList
12
- * - listItem "C"
13
- * - listItem "D"
14
- * - listItem "E"
15
- *
16
- * Output:
17
- * - bulletList
18
- * - listItem "A"
19
- * - listItem "B"
20
- * - listItem "C"
21
- * - listItem "D"
22
- * - listItem "E"
23
- *
24
- * @example
25
7
  * Input (deeply nested):
26
8
  * - bulletList
27
9
  * - listItem "1"
@@ -1,7 +1,22 @@
1
1
  import type { TransformStep } from './types';
2
2
  /**
3
- * Given an array of nodes, returns an array with the flattened children of any list nodes.
3
+ * Given an array of nodes, processes each list removing all parent list nodes and
4
+ * just returning their child contents.
5
+ *
6
+ * @example
7
+ * Input:
8
+ * - bulletList
9
+ * - listItem "1"
10
+ * - paragraph "1"
11
+ * - listItem "2"
12
+ * - paragraph "2"
13
+ *
14
+ * Output:
15
+ * - paragraph "1"
16
+ * - paragraph "2"
17
+ *
4
18
  * @param nodes
19
+ * @param context
5
20
  * @returns
6
21
  */
7
22
  export declare const unwrapListStep: TransformStep;