@atlaskit/editor-plugin-block-menu 5.2.16 → 5.2.18

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 (45) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/cjs/blockMenuPlugin.js +2 -2
  3. package/dist/cjs/editor-commands/transform-node-utils/flattenStep.js +18 -8
  4. package/dist/cjs/editor-commands/transform-node-utils/steps/applyTargetTextTypeStep.js +50 -0
  5. package/dist/cjs/editor-commands/transform-node-utils/steps/flattenListStep.js +12 -2
  6. package/dist/cjs/editor-commands/transform-node-utils/steps/unwrapListStep.js +10 -2
  7. package/dist/cjs/editor-commands/transform-node-utils/transform.js +20 -5
  8. package/dist/cjs/editor-commands/transformNode.js +5 -3
  9. package/dist/cjs/editor-commands/transforms/utils.js +3 -1
  10. package/dist/cjs/ui/block-menu.js +38 -33
  11. package/dist/es2019/blockMenuPlugin.js +2 -2
  12. package/dist/es2019/editor-commands/transform-node-utils/flattenStep.js +16 -6
  13. package/dist/es2019/editor-commands/transform-node-utils/steps/applyTargetTextTypeStep.js +46 -0
  14. package/dist/es2019/editor-commands/transform-node-utils/steps/flattenListStep.js +12 -2
  15. package/dist/es2019/editor-commands/transform-node-utils/steps/unwrapListStep.js +10 -2
  16. package/dist/es2019/editor-commands/transform-node-utils/transform.js +20 -5
  17. package/dist/es2019/editor-commands/transformNode.js +5 -3
  18. package/dist/es2019/editor-commands/transforms/utils.js +3 -1
  19. package/dist/es2019/ui/block-menu.js +38 -33
  20. package/dist/esm/blockMenuPlugin.js +2 -2
  21. package/dist/esm/editor-commands/transform-node-utils/flattenStep.js +18 -8
  22. package/dist/esm/editor-commands/transform-node-utils/steps/applyTargetTextTypeStep.js +44 -0
  23. package/dist/esm/editor-commands/transform-node-utils/steps/flattenListStep.js +12 -2
  24. package/dist/esm/editor-commands/transform-node-utils/steps/unwrapListStep.js +10 -2
  25. package/dist/esm/editor-commands/transform-node-utils/transform.js +20 -5
  26. package/dist/esm/editor-commands/transformNode.js +5 -3
  27. package/dist/esm/editor-commands/transforms/utils.js +3 -1
  28. package/dist/esm/ui/block-menu.js +38 -33
  29. package/dist/types/blockMenuPluginType.d.ts +2 -2
  30. package/dist/types/editor-commands/transform-node-utils/steps/applyTargetTextTypeStep.d.ts +20 -0
  31. package/dist/types/editor-commands/transform-node-utils/steps/unwrapListStep.d.ts +3 -0
  32. package/dist/types/editor-commands/transform-node-utils/transform.d.ts +2 -1
  33. package/dist/types/editor-commands/transform-node-utils/types.d.ts +1 -0
  34. package/dist/types/editor-commands/transformNode.d.ts +2 -2
  35. package/dist/types/editor-commands/transforms/types.d.ts +2 -1
  36. package/dist/types/index.d.ts +1 -0
  37. package/dist/types-ts4.5/blockMenuPluginType.d.ts +2 -2
  38. package/dist/types-ts4.5/editor-commands/transform-node-utils/steps/applyTargetTextTypeStep.d.ts +20 -0
  39. package/dist/types-ts4.5/editor-commands/transform-node-utils/steps/unwrapListStep.d.ts +3 -0
  40. package/dist/types-ts4.5/editor-commands/transform-node-utils/transform.d.ts +2 -1
  41. package/dist/types-ts4.5/editor-commands/transform-node-utils/types.d.ts +1 -0
  42. package/dist/types-ts4.5/editor-commands/transformNode.d.ts +2 -2
  43. package/dist/types-ts4.5/editor-commands/transforms/types.d.ts +2 -1
  44. package/dist/types-ts4.5/index.d.ts +1 -0
  45. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @atlaskit/editor-plugin-block-menu
2
2
 
3
+ ## 5.2.18
4
+
5
+ ### Patch Changes
6
+
7
+ - [`bfb0acc5f3d72`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/bfb0acc5f3d72) -
8
+ [ux] Update list flattening steps to handle decision lists as well
9
+ - [`a528ea956ce65`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/a528ea956ce65) -
10
+ [ux] EDITOR-3956 fix sync block resize handle padding and alignment
11
+ - Updated dependencies
12
+
13
+ ## 5.2.17
14
+
15
+ ### Patch Changes
16
+
17
+ - [`1da3868c8f709`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/1da3868c8f709) -
18
+ EDITOR-3916 Fix block menu alternating on drag handle click
19
+ - [`722f272e8b78f`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/722f272e8b78f) -
20
+ Editor-2778: Smartlink card and embed transform
21
+ - Updated dependencies
22
+
3
23
  ## 5.2.16
4
24
 
5
25
  ### Patch Changes
@@ -42,8 +42,8 @@ var blockMenuPlugin = exports.blockMenuPlugin = function blockMenuPlugin(_ref) {
42
42
  formatNode: function formatNode(targetType, analyticsAttrs) {
43
43
  return (0, _formatNode2.formatNode)(api)(targetType, analyticsAttrs);
44
44
  },
45
- transformNode: function transformNode(targetType, analyticsAttrs) {
46
- return (0, _transformNode2.transformNode)(api)(targetType, analyticsAttrs);
45
+ transformNode: function transformNode(targetType, metadata) {
46
+ return (0, _transformNode2.transformNode)(api)(targetType, metadata);
47
47
  }
48
48
  },
49
49
  getSharedState: function getSharedState(editorState) {
@@ -7,15 +7,25 @@ exports.flattenStep = void 0;
7
7
  var flattenStep = exports.flattenStep = function flattenStep(nodes, context) {
8
8
  var schema = context.schema,
9
9
  targetNodeTypeName = context.targetNodeTypeName;
10
+ var targetNodeType = schema.nodes[targetNodeTypeName];
11
+ if (!targetNodeType) {
12
+ return nodes;
13
+ }
10
14
 
11
15
  // TODO: EDITOR-2920 - Implement flattening logic.
12
- // This is a simplified preliminary approach. We might want to use prosemirror-markdown functions.
13
- var codeBlockContent = nodes.map(function (node) {
14
- return node.content.textBetween(0, node.content.size, '\n');
15
- }).join('\n');
16
- var outputNode = schema.nodes[targetNodeTypeName].createAndFill({}, schema.text(codeBlockContent));
17
- if (!outputNode) {
18
- return nodes;
16
+ var isTargetCodeBlock = targetNodeTypeName === 'codeBlock';
17
+ if (isTargetCodeBlock) {
18
+ // This strips explicitly text nodes
19
+ var codeBlockContent = nodes.map(function (node) {
20
+ return node.content.textBetween(0, node.content.size, '\n');
21
+ }).join('\n');
22
+ return [schema.nodes.codeBlock.create({}, schema.text(codeBlockContent))];
19
23
  }
20
- return [outputNode];
24
+ return nodes.map(function (node) {
25
+ var isValidWithin = targetNodeType.validContent(node.content);
26
+ if (!isValidWithin) {
27
+ return node;
28
+ }
29
+ return schema.nodes.paragraph.create({}, node.content);
30
+ });
21
31
  };
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.applyTargetTextTypeStep = void 0;
7
+ /**
8
+ * Applies target text type conversion. If the target type is a heading, converts textblock nodes
9
+ * (paragraphs, headings) to heading nodes with the specified level. Otherwise, leaves nodes unchanged.
10
+ * Non-textblock nodes are always left unchanged.
11
+ *
12
+ * @example
13
+ * Input:
14
+ * - paragraph "Heading 1"
15
+ * - paragraph "Heading 2"
16
+ *
17
+ * Output (with target: heading, level: 2):
18
+ * - heading (level: 2) "Heading 1"
19
+ * - heading (level: 2) "Heading 2"
20
+ *
21
+ * @param nodes
22
+ * @param context
23
+ * @returns
24
+ */
25
+ var applyTargetTextTypeStep = exports.applyTargetTextTypeStep = function applyTargetTextTypeStep(nodes, context) {
26
+ var schema = context.schema,
27
+ targetNodeTypeName = context.targetNodeTypeName,
28
+ targetAttrs = context.targetAttrs;
29
+ if (targetNodeTypeName !== 'heading') {
30
+ return nodes;
31
+ }
32
+ var headingType = schema.nodes.heading;
33
+ if (!headingType) {
34
+ return nodes;
35
+ }
36
+
37
+ // Default to level 1 if no level is specified
38
+ // The level should ideally come from targetAttrs, but if not available, use default
39
+ var headingLevel = typeof (targetAttrs === null || targetAttrs === void 0 ? void 0 : targetAttrs.level) === 'number' ? targetAttrs.level : 1;
40
+ return nodes.map(function (node) {
41
+ if (node.isTextblock) {
42
+ // Convert textblock nodes (paragraphs, headings) to heading with specified level
43
+ return headingType.create({
44
+ level: headingLevel
45
+ }, node.content);
46
+ }
47
+ // Non-textblock nodes are left unchanged
48
+ return node;
49
+ });
50
+ };
@@ -9,7 +9,7 @@ var _nodeChecks = require("../nodeChecks");
9
9
  var extractNestedLists = function extractNestedLists(node, schema) {
10
10
  var items = [];
11
11
  var paragraph = schema.nodes.paragraph;
12
- var itemTypes = [schema.nodes.listItem, schema.nodes.taskItem];
12
+ var itemTypes = [schema.nodes.listItem, schema.nodes.taskItem, schema.nodes.decisionItem];
13
13
  var _extract = function extract(currentNode) {
14
14
  currentNode.forEach(function (child) {
15
15
  if (itemTypes.some(function (type) {
@@ -17,11 +17,21 @@ var extractNestedLists = function extractNestedLists(node, schema) {
17
17
  })) {
18
18
  var contentWithoutNestedLists = [];
19
19
  var nestedLists = [];
20
+
21
+ // Check if this item type expects inline content (taskItem, decisionItem)
22
+ // vs block content (listItem) based on the schema definition
23
+ var isInlineItem = child.type.inlineContent;
20
24
  child.forEach(function (grandChild) {
21
25
  if ((0, _nodeChecks.isListWithIndentation)(grandChild.type.name, schema)) {
22
26
  nestedLists.push(grandChild);
23
27
  } else if (grandChild.isText) {
24
- contentWithoutNestedLists.push(paragraph.createAndFill({}, grandChild));
28
+ // For taskItem/decisionItem, keep text as-is (they support inline content)
29
+ // For listItem, wrap text in paragraph (they require block content)
30
+ if (isInlineItem) {
31
+ contentWithoutNestedLists.push(grandChild);
32
+ } else {
33
+ contentWithoutNestedLists.push(paragraph.createAndFill({}, grandChild));
34
+ }
25
35
  } else {
26
36
  contentWithoutNestedLists.push(grandChild);
27
37
  }
@@ -10,6 +10,9 @@ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers
10
10
  * Given an array of nodes, processes each list removing all parent list nodes and
11
11
  * just returning their child contents.
12
12
  *
13
+ * For lists with block content (bulletList, orderedList), it extracts the block nodes directly.
14
+ * For lists with inline content (taskList, decisionList), it wraps the content in paragraphs.
15
+ *
13
16
  * @example
14
17
  * Input:
15
18
  * - bulletList
@@ -27,14 +30,19 @@ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers
27
30
  * @returns
28
31
  */
29
32
  var unwrapListStep = exports.unwrapListStep = function unwrapListStep(nodes, context) {
30
- var listTypes = [context.schema.nodes.bulletList, context.schema.nodes.orderedList, context.schema.nodes.taskList];
33
+ var listTypes = [context.schema.nodes.bulletList, context.schema.nodes.orderedList, context.schema.nodes.taskList, context.schema.nodes.decisionList];
31
34
  return nodes.flatMap(function (node) {
32
35
  if (listTypes.some(function (type) {
33
36
  return node.type === type;
34
37
  })) {
35
38
  var listItems = [];
36
39
  node.forEach(function (listItem) {
37
- listItems.push.apply(listItems, (0, _toConsumableArray2.default)(listItem.children));
40
+ // if isTaskItem or isDecisionItem, convert to paragraph
41
+ if (listItem.type.name === 'taskItem' || listItem.type.name === 'decisionItem') {
42
+ listItems.push(context.schema.nodes.paragraph.create({}, listItem.content));
43
+ } else {
44
+ listItems.push.apply(listItems, (0, _toConsumableArray2.default)(listItem.children));
45
+ }
38
46
  });
39
47
  return listItems;
40
48
  }
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.getOutputNodes = void 0;
7
7
  var _utils = require("../transform-node-utils/utils");
8
8
  var _flattenStep = require("./flattenStep");
9
+ var _applyTargetTextTypeStep = require("./steps/applyTargetTextTypeStep");
9
10
  var _decisionListToListStep = require("./steps/decisionListToListStep");
10
11
  var _flattenListStep = require("./steps/flattenListStep");
11
12
  var _listToDecisionListStep = require("./steps/listToDecisionListStep");
@@ -34,19 +35,19 @@ var TRANSFORM_STEPS = {
34
35
  atomic: undefined,
35
36
  container: [_unwrapStep.unwrapStep, _wrapStep.wrapStep],
36
37
  list: undefined,
37
- text: [_unwrapStep.unwrapStep]
38
+ text: [_unwrapStep.unwrapStep, _applyTargetTextTypeStep.applyTargetTextTypeStep]
38
39
  },
39
40
  list: {
40
41
  atomic: undefined,
41
42
  container: [_wrapStep.wrapStep],
42
43
  list: [_listToListStep.listToListStep],
43
- text: [_flattenListStep.flattenListStep, _unwrapListStep.unwrapListStep]
44
+ text: [_flattenListStep.flattenListStep, _unwrapListStep.unwrapListStep, _applyTargetTextTypeStep.applyTargetTextTypeStep]
44
45
  },
45
46
  text: {
46
47
  atomic: undefined,
47
48
  container: [_wrapStep.wrapStep],
48
49
  list: [_wrapIntoListStep.wrapIntoListStep],
49
- text: [_stubStep.stubStep]
50
+ text: [_flattenStep.flattenStep, _applyTargetTextTypeStep.applyTargetTextTypeStep]
50
51
  }
51
52
  };
52
53
 
@@ -129,6 +130,18 @@ var TRANSFORM_STEPS_OVERRIDE = {
129
130
  orderedList: [_decisionListToListStep.decisionListToListStep],
130
131
  taskList: [_decisionListToListStep.decisionListToListStep],
131
132
  layoutSection: [_wrapIntoLayoutStep.wrapIntoLayoutStep]
133
+ },
134
+ blockCard: {
135
+ layoutSection: [_wrapIntoLayoutStep.wrapIntoLayoutStep]
136
+ },
137
+ embedCard: {
138
+ layoutSection: [_wrapIntoLayoutStep.wrapIntoLayoutStep]
139
+ },
140
+ extension: {
141
+ layoutSection: [_wrapIntoLayoutStep.wrapIntoLayoutStep]
142
+ },
143
+ bodiedExtension: {
144
+ layoutSection: [_wrapIntoLayoutStep.wrapIntoLayoutStep]
132
145
  }
133
146
  };
134
147
  var getTransformStepsForNodeTypes = function getTransformStepsForNodeTypes(selectedNodeTypeName, targetNodeTypeName) {
@@ -143,7 +156,8 @@ var getOutputNodes = exports.getOutputNodes = function getOutputNodes(_ref) {
143
156
  var sourceNode = _ref.sourceNode,
144
157
  targetNodeType = _ref.targetNodeType,
145
158
  schema = _ref.schema,
146
- isNested = _ref.isNested;
159
+ isNested = _ref.isNested,
160
+ targetAttrs = _ref.targetAttrs;
147
161
  var nodesToReplace = [sourceNode];
148
162
  var selectedNodeTypeName = (0, _types.toNodeTypeValue)(sourceNode.type.name);
149
163
  var initialTargetNodeTypeName = (0, _types.toNodeTypeValue)(targetNodeType.name);
@@ -156,7 +170,8 @@ var getOutputNodes = exports.getOutputNodes = function getOutputNodes(_ref) {
156
170
  var context = {
157
171
  fromNode: sourceNode,
158
172
  targetNodeTypeName: targetNodeTypeName,
159
- schema: schema
173
+ schema: schema,
174
+ targetAttrs: targetAttrs
160
175
  };
161
176
  if (!steps || steps.length === 0) {
162
177
  return;
@@ -13,7 +13,7 @@ var _utils = require("./transforms/utils");
13
13
  var transformNode = exports.transformNode = function transformNode(api) {
14
14
  return (
15
15
  // eslint-disable-next-line no-unused-vars
16
- function (targetType, analyticsAttrs) {
16
+ function (targetType, metadata) {
17
17
  return function (_ref) {
18
18
  var _api$blockControls;
19
19
  var tr = _ref.tr;
@@ -26,8 +26,9 @@ var transformNode = exports.transformNode = function transformNode(api) {
26
26
  var _expandSelectionToBlo = (0, _selection.expandSelectionToBlockRange)(preservedSelection),
27
27
  $from = _expandSelectionToBlo.$from,
28
28
  $to = _expandSelectionToBlo.$to;
29
- var isNested = (0, _isNestedNode.isNestedNode)(preservedSelection, '');
30
29
  var selectedParent = $from.parent;
30
+ var isParentLayout = selectedParent.type === nodes.layoutColumn;
31
+ var isNestedExceptLayout = (0, _isNestedNode.isNestedNode)(preservedSelection, '') && !isParentLayout;
31
32
  var fragment = _model.Fragment.empty;
32
33
  var isList = (0, _utils.isListNode)(selectedParent);
33
34
  var slice = tr.doc.slice(isList ? $from.pos - 1 : $from.pos, isList ? $to.pos + 1 : $to.pos);
@@ -36,7 +37,8 @@ var transformNode = exports.transformNode = function transformNode(api) {
36
37
  sourceNode: node,
37
38
  targetNodeType: targetType,
38
39
  schema: tr.doc.type.schema,
39
- isNested: isNested
40
+ isNested: isNestedExceptLayout,
41
+ targetAttrs: metadata === null || metadata === void 0 ? void 0 : metadata.targetAttrs
40
42
  });
41
43
  if (outputNode) {
42
44
  fragment = fragment.append(_model.Fragment.fromArray(outputNode));
@@ -6,7 +6,9 @@ Object.defineProperty(exports, "__esModule", {
6
6
  });
7
7
  exports.isListNodeType = exports.isListNode = exports.isLayoutNodeType = exports.isLayoutNode = exports.isHeadingOrParagraphNode = exports.isContainerNodeType = exports.isContainerNode = exports.isBlockNodeType = exports.isBlockNodeForExtraction = exports.isBlockNode = exports.getTargetNodeInfo = exports.getMarksWithBreakout = exports.getConversionType = exports.getContentSupportChecker = exports.filterMarksForTargetNodeType = exports.convertNodeToInlineContent = exports.convertCodeBlockContentToParagraphs = void 0;
8
8
  var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
+ var _utils = require("@atlaskit/editor-common/utils");
9
10
  var _model = require("@atlaskit/editor-prosemirror/model");
11
+ var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
10
12
  var getTargetNodeInfo = exports.getTargetNodeInfo = function getTargetNodeInfo(targetType, nodes) {
11
13
  switch (targetType) {
12
14
  case 'heading1':
@@ -206,7 +208,7 @@ var convertCodeBlockContentToParagraphs = exports.convertCodeBlockContentToParag
206
208
  return paragraphNodes;
207
209
  };
208
210
  var isBreakoutMarkSupported = function isBreakoutMarkSupported(nodeType) {
209
- return ['codeBlock', 'expand', 'layoutSection'].includes(nodeType.name);
211
+ return (0, _experiments.editorExperiment)('platform_synced_block', true) ? _utils.breakoutResizableNodes.includes(nodeType.name) : ['codeBlock', 'expand', 'layoutSection'].includes(nodeType.name);
210
212
  };
211
213
  var getMarksWithBreakout = exports.getMarksWithBreakout = function getMarksWithBreakout(sourceNode, targetNodeType) {
212
214
  var allowedMarks = targetNodeType.allowedMarks(sourceNode.marks);
@@ -127,7 +127,7 @@ var BlockMenuContent = function BlockMenuContent(_ref3) {
127
127
  })));
128
128
  };
129
129
  var BlockMenu = function BlockMenu(_ref4) {
130
- var _editorView$dom, _ref5;
130
+ var _editorView$dom, _ref5, _api$analytics3;
131
131
  var editorView = _ref4.editorView,
132
132
  api = _ref4.api,
133
133
  mountTo = _ref4.mountTo,
@@ -202,6 +202,13 @@ var BlockMenu = function BlockMenu(_ref4) {
202
202
  return tr;
203
203
  });
204
204
  };
205
+ var handleClickOutside = function handleClickOutside(e) {
206
+ // check if the clicked element was another drag handle, if so don't close the menu
207
+ if (e.target instanceof HTMLElement && e.target.closest(_styles.DRAG_HANDLE_SELECTOR)) {
208
+ return;
209
+ }
210
+ closeMenu();
211
+ };
205
212
  var closeMenu = function closeMenu() {
206
213
  api === null || api === void 0 || api.core.actions.execute(function (_ref7) {
207
214
  var _api$blockControls3, _api$userIntent3;
@@ -227,39 +234,37 @@ var BlockMenu = function BlockMenu(_ref4) {
227
234
  popupRef.current = el;
228
235
  }
229
236
  };
230
- if (targetHandleRef instanceof HTMLElement) {
231
- var _api$analytics3;
232
- return /*#__PURE__*/_react.default.createElement(_errorBoundary.ErrorBoundary, {
233
- component: _analytics.ACTION_SUBJECT.BLOCK_MENU,
234
- dispatchAnalyticsEvent: api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : _api$analytics3.actions.fireAnalyticsEvent,
235
- fallbackComponent: null
236
- }, /*#__PURE__*/_react.default.createElement(PopupWithListeners, {
237
- alignX: 'right',
238
- alignY: 'start',
239
- handleClickOutside: closeMenu,
240
- handleEscapeKeydown: closeMenu,
241
- handleBackspaceDeleteKeydown: handleBackspaceDeleteKeydown,
242
- mountTo: mountTo,
243
- boundariesElement: boundariesElement,
244
- scrollableElement: scrollableElement,
245
- target: targetHandleRef,
246
- zIndex: _editorSharedStyles.akEditorFloatingOverlapPanelZIndex,
247
- fitWidth: DEFAULT_MENU_WIDTH,
248
- fitHeight: menuHeight,
249
- preventOverflow: true,
250
- stick: true,
251
- offset: [_styles.DRAG_HANDLE_WIDTH + DRAG_HANDLE_OFFSET_PADDING, targetHandleHeightOffset],
252
- focusTrap: openedViaKeyboard ?
253
- // Only enable focus trap when opened via keyboard to make sure the focus is on the first focusable menu item
254
- {
255
- initialFocus: undefined
256
- } : undefined
257
- }, /*#__PURE__*/_react.default.createElement(BlockMenuContent, {
258
- api: api,
259
- setRef: setRef
260
- })));
261
- } else {
237
+ if (!(targetHandleRef instanceof HTMLElement)) {
262
238
  return null;
263
239
  }
240
+ return /*#__PURE__*/_react.default.createElement(_errorBoundary.ErrorBoundary, {
241
+ component: _analytics.ACTION_SUBJECT.BLOCK_MENU,
242
+ dispatchAnalyticsEvent: api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : _api$analytics3.actions.fireAnalyticsEvent,
243
+ fallbackComponent: null
244
+ }, /*#__PURE__*/_react.default.createElement(PopupWithListeners, {
245
+ alignX: 'right',
246
+ alignY: 'start',
247
+ handleClickOutside: handleClickOutside,
248
+ handleEscapeKeydown: closeMenu,
249
+ handleBackspaceDeleteKeydown: handleBackspaceDeleteKeydown,
250
+ mountTo: mountTo,
251
+ boundariesElement: boundariesElement,
252
+ scrollableElement: scrollableElement,
253
+ target: targetHandleRef,
254
+ zIndex: _editorSharedStyles.akEditorFloatingOverlapPanelZIndex,
255
+ fitWidth: DEFAULT_MENU_WIDTH,
256
+ fitHeight: menuHeight,
257
+ preventOverflow: true,
258
+ stick: true,
259
+ offset: [_styles.DRAG_HANDLE_WIDTH + DRAG_HANDLE_OFFSET_PADDING, targetHandleHeightOffset],
260
+ focusTrap: openedViaKeyboard ?
261
+ // Only enable focus trap when opened via keyboard to make sure the focus is on the first focusable menu item
262
+ {
263
+ initialFocus: undefined
264
+ } : undefined
265
+ }, /*#__PURE__*/_react.default.createElement(BlockMenuContent, {
266
+ api: api,
267
+ setRef: setRef
268
+ })));
264
269
  };
265
270
  var _default = exports.default = (0, _reactIntlNext.injectIntl)(BlockMenu);
@@ -36,8 +36,8 @@ export const blockMenuPlugin = ({
36
36
  formatNode: (targetType, analyticsAttrs) => {
37
37
  return formatNode(api)(targetType, analyticsAttrs);
38
38
  },
39
- transformNode: (targetType, analyticsAttrs) => {
40
- return transformNode(api)(targetType, analyticsAttrs);
39
+ transformNode: (targetType, metadata) => {
40
+ return transformNode(api)(targetType, metadata);
41
41
  }
42
42
  },
43
43
  getSharedState(editorState) {
@@ -3,13 +3,23 @@ export const flattenStep = (nodes, context) => {
3
3
  schema,
4
4
  targetNodeTypeName
5
5
  } = context;
6
+ const targetNodeType = schema.nodes[targetNodeTypeName];
7
+ if (!targetNodeType) {
8
+ return nodes;
9
+ }
6
10
 
7
11
  // TODO: EDITOR-2920 - Implement flattening logic.
8
- // This is a simplified preliminary approach. We might want to use prosemirror-markdown functions.
9
- const codeBlockContent = nodes.map(node => node.content.textBetween(0, node.content.size, '\n')).join('\n');
10
- const outputNode = schema.nodes[targetNodeTypeName].createAndFill({}, schema.text(codeBlockContent));
11
- if (!outputNode) {
12
- return nodes;
12
+ const isTargetCodeBlock = targetNodeTypeName === 'codeBlock';
13
+ if (isTargetCodeBlock) {
14
+ // This strips explicitly text nodes
15
+ const codeBlockContent = nodes.map(node => node.content.textBetween(0, node.content.size, '\n')).join('\n');
16
+ return [schema.nodes.codeBlock.create({}, schema.text(codeBlockContent))];
13
17
  }
14
- return [outputNode];
18
+ return nodes.map(node => {
19
+ const isValidWithin = targetNodeType.validContent(node.content);
20
+ if (!isValidWithin) {
21
+ return node;
22
+ }
23
+ return schema.nodes.paragraph.create({}, node.content);
24
+ });
15
25
  };
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Applies target text type conversion. If the target type is a heading, converts textblock nodes
3
+ * (paragraphs, headings) to heading nodes with the specified level. Otherwise, leaves nodes unchanged.
4
+ * Non-textblock nodes are always left unchanged.
5
+ *
6
+ * @example
7
+ * Input:
8
+ * - paragraph "Heading 1"
9
+ * - paragraph "Heading 2"
10
+ *
11
+ * Output (with target: heading, level: 2):
12
+ * - heading (level: 2) "Heading 1"
13
+ * - heading (level: 2) "Heading 2"
14
+ *
15
+ * @param nodes
16
+ * @param context
17
+ * @returns
18
+ */
19
+ export const applyTargetTextTypeStep = (nodes, context) => {
20
+ const {
21
+ schema,
22
+ targetNodeTypeName,
23
+ targetAttrs
24
+ } = context;
25
+ if (targetNodeTypeName !== 'heading') {
26
+ return nodes;
27
+ }
28
+ const headingType = schema.nodes.heading;
29
+ if (!headingType) {
30
+ return nodes;
31
+ }
32
+
33
+ // Default to level 1 if no level is specified
34
+ // The level should ideally come from targetAttrs, but if not available, use default
35
+ const headingLevel = typeof (targetAttrs === null || targetAttrs === void 0 ? void 0 : targetAttrs.level) === 'number' ? targetAttrs.level : 1;
36
+ return nodes.map(node => {
37
+ if (node.isTextblock) {
38
+ // Convert textblock nodes (paragraphs, headings) to heading with specified level
39
+ return headingType.create({
40
+ level: headingLevel
41
+ }, node.content);
42
+ }
43
+ // Non-textblock nodes are left unchanged
44
+ return node;
45
+ });
46
+ };
@@ -3,17 +3,27 @@ import { isListWithIndentation } from '../nodeChecks';
3
3
  const extractNestedLists = (node, schema) => {
4
4
  const items = [];
5
5
  const paragraph = schema.nodes.paragraph;
6
- const itemTypes = [schema.nodes.listItem, schema.nodes.taskItem];
6
+ const itemTypes = [schema.nodes.listItem, schema.nodes.taskItem, schema.nodes.decisionItem];
7
7
  const extract = currentNode => {
8
8
  currentNode.forEach(child => {
9
9
  if (itemTypes.some(type => child.type === type)) {
10
10
  const contentWithoutNestedLists = [];
11
11
  const nestedLists = [];
12
+
13
+ // Check if this item type expects inline content (taskItem, decisionItem)
14
+ // vs block content (listItem) based on the schema definition
15
+ const isInlineItem = child.type.inlineContent;
12
16
  child.forEach(grandChild => {
13
17
  if (isListWithIndentation(grandChild.type.name, schema)) {
14
18
  nestedLists.push(grandChild);
15
19
  } else if (grandChild.isText) {
16
- contentWithoutNestedLists.push(paragraph.createAndFill({}, grandChild));
20
+ // For taskItem/decisionItem, keep text as-is (they support inline content)
21
+ // For listItem, wrap text in paragraph (they require block content)
22
+ if (isInlineItem) {
23
+ contentWithoutNestedLists.push(grandChild);
24
+ } else {
25
+ contentWithoutNestedLists.push(paragraph.createAndFill({}, grandChild));
26
+ }
17
27
  } else {
18
28
  contentWithoutNestedLists.push(grandChild);
19
29
  }
@@ -2,6 +2,9 @@
2
2
  * Given an array of nodes, processes each list removing all parent list nodes and
3
3
  * just returning their child contents.
4
4
  *
5
+ * For lists with block content (bulletList, orderedList), it extracts the block nodes directly.
6
+ * For lists with inline content (taskList, decisionList), it wraps the content in paragraphs.
7
+ *
5
8
  * @example
6
9
  * Input:
7
10
  * - bulletList
@@ -19,12 +22,17 @@
19
22
  * @returns
20
23
  */
21
24
  export const unwrapListStep = (nodes, context) => {
22
- const listTypes = [context.schema.nodes.bulletList, context.schema.nodes.orderedList, context.schema.nodes.taskList];
25
+ const listTypes = [context.schema.nodes.bulletList, context.schema.nodes.orderedList, context.schema.nodes.taskList, context.schema.nodes.decisionList];
23
26
  return nodes.flatMap(node => {
24
27
  if (listTypes.some(type => node.type === type)) {
25
28
  const listItems = [];
26
29
  node.forEach(listItem => {
27
- listItems.push(...listItem.children);
30
+ // if isTaskItem or isDecisionItem, convert to paragraph
31
+ if (listItem.type.name === 'taskItem' || listItem.type.name === 'decisionItem') {
32
+ listItems.push(context.schema.nodes.paragraph.create({}, listItem.content));
33
+ } else {
34
+ listItems.push(...listItem.children);
35
+ }
28
36
  });
29
37
  return listItems;
30
38
  }
@@ -1,5 +1,6 @@
1
1
  import { getTargetNodeTypeNameInContext } from '../transform-node-utils/utils';
2
2
  import { flattenStep } from './flattenStep';
3
+ import { applyTargetTextTypeStep } from './steps/applyTargetTextTypeStep';
3
4
  import { decisionListToListStep } from './steps/decisionListToListStep';
4
5
  import { flattenListStep } from './steps/flattenListStep';
5
6
  import { listToDecisionListStep } from './steps/listToDecisionListStep';
@@ -29,19 +30,19 @@ const TRANSFORM_STEPS = {
29
30
  atomic: undefined,
30
31
  container: [unwrapStep, wrapStep],
31
32
  list: undefined,
32
- text: [unwrapStep]
33
+ text: [unwrapStep, applyTargetTextTypeStep]
33
34
  },
34
35
  list: {
35
36
  atomic: undefined,
36
37
  container: [wrapStep],
37
38
  list: [listToListStep],
38
- text: [flattenListStep, unwrapListStep]
39
+ text: [flattenListStep, unwrapListStep, applyTargetTextTypeStep]
39
40
  },
40
41
  text: {
41
42
  atomic: undefined,
42
43
  container: [wrapStep],
43
44
  list: [wrapIntoListStep],
44
- text: [stubStep]
45
+ text: [flattenStep, applyTargetTextTypeStep]
45
46
  }
46
47
  };
47
48
 
@@ -124,6 +125,18 @@ const TRANSFORM_STEPS_OVERRIDE = {
124
125
  orderedList: [decisionListToListStep],
125
126
  taskList: [decisionListToListStep],
126
127
  layoutSection: [wrapIntoLayoutStep]
128
+ },
129
+ blockCard: {
130
+ layoutSection: [wrapIntoLayoutStep]
131
+ },
132
+ embedCard: {
133
+ layoutSection: [wrapIntoLayoutStep]
134
+ },
135
+ extension: {
136
+ layoutSection: [wrapIntoLayoutStep]
137
+ },
138
+ bodiedExtension: {
139
+ layoutSection: [wrapIntoLayoutStep]
127
140
  }
128
141
  };
129
142
  const getTransformStepsForNodeTypes = (selectedNodeTypeName, targetNodeTypeName) => {
@@ -138,7 +151,8 @@ export const getOutputNodes = ({
138
151
  sourceNode,
139
152
  targetNodeType,
140
153
  schema,
141
- isNested
154
+ isNested,
155
+ targetAttrs
142
156
  }) => {
143
157
  const nodesToReplace = [sourceNode];
144
158
  const selectedNodeTypeName = toNodeTypeValue(sourceNode.type.name);
@@ -152,7 +166,8 @@ export const getOutputNodes = ({
152
166
  const context = {
153
167
  fromNode: sourceNode,
154
168
  targetNodeTypeName,
155
- schema
169
+ schema,
170
+ targetAttrs
156
171
  };
157
172
  if (!steps || steps.length === 0) {
158
173
  return;
@@ -6,7 +6,7 @@ import { getOutputNodes } from './transform-node-utils/transform';
6
6
  import { isListNode } from './transforms/utils';
7
7
  export const transformNode = api =>
8
8
  // eslint-disable-next-line no-unused-vars
9
- (targetType, analyticsAttrs) => {
9
+ (targetType, metadata) => {
10
10
  return ({
11
11
  tr
12
12
  }) => {
@@ -23,8 +23,9 @@ export const transformNode = api =>
23
23
  $from,
24
24
  $to
25
25
  } = expandSelectionToBlockRange(preservedSelection);
26
- const isNested = isNestedNode(preservedSelection, '');
27
26
  const selectedParent = $from.parent;
27
+ const isParentLayout = selectedParent.type === nodes.layoutColumn;
28
+ const isNestedExceptLayout = isNestedNode(preservedSelection, '') && !isParentLayout;
28
29
  let fragment = Fragment.empty;
29
30
  const isList = isListNode(selectedParent);
30
31
  const slice = tr.doc.slice(isList ? $from.pos - 1 : $from.pos, isList ? $to.pos + 1 : $to.pos);
@@ -33,7 +34,8 @@ export const transformNode = api =>
33
34
  sourceNode: node,
34
35
  targetNodeType: targetType,
35
36
  schema: tr.doc.type.schema,
36
- isNested
37
+ isNested: isNestedExceptLayout,
38
+ targetAttrs: metadata === null || metadata === void 0 ? void 0 : metadata.targetAttrs
37
39
  });
38
40
  if (outputNode) {
39
41
  fragment = fragment.append(Fragment.fromArray(outputNode));