@atlaskit/editor-plugin-block-menu 0.0.20 → 1.0.1

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 (38) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/cjs/editor-commands/formatNode.js +6 -3
  3. package/dist/cjs/editor-commands/transforms/block-transforms.js +22 -10
  4. package/dist/cjs/editor-commands/transforms/container-transforms.js +40 -7
  5. package/dist/cjs/editor-commands/transforms/inline-node-transforms.js +27 -0
  6. package/dist/cjs/editor-commands/transforms/list/transformBetweenListTypes.js +102 -0
  7. package/dist/cjs/editor-commands/transforms/list-transforms.js +51 -19
  8. package/dist/cjs/editor-commands/transforms/utils.js +1 -1
  9. package/dist/cjs/ui/block-menu-components.js +1 -2
  10. package/dist/es2019/editor-commands/formatNode.js +6 -3
  11. package/dist/es2019/editor-commands/transforms/block-transforms.js +29 -15
  12. package/dist/es2019/editor-commands/transforms/container-transforms.js +35 -2
  13. package/dist/es2019/editor-commands/transforms/inline-node-transforms.js +21 -0
  14. package/dist/es2019/editor-commands/transforms/list/transformBetweenListTypes.js +98 -0
  15. package/dist/es2019/editor-commands/transforms/list-transforms.js +49 -15
  16. package/dist/es2019/editor-commands/transforms/utils.js +1 -1
  17. package/dist/es2019/ui/block-menu-components.js +1 -2
  18. package/dist/esm/editor-commands/formatNode.js +6 -3
  19. package/dist/esm/editor-commands/transforms/block-transforms.js +23 -11
  20. package/dist/esm/editor-commands/transforms/container-transforms.js +39 -7
  21. package/dist/esm/editor-commands/transforms/inline-node-transforms.js +21 -0
  22. package/dist/esm/editor-commands/transforms/list/transformBetweenListTypes.js +95 -0
  23. package/dist/esm/editor-commands/transforms/list-transforms.js +50 -18
  24. package/dist/esm/editor-commands/transforms/utils.js +1 -1
  25. package/dist/esm/ui/block-menu-components.js +1 -2
  26. package/dist/types/editor-commands/transforms/container-transforms.d.ts +2 -2
  27. package/dist/types/editor-commands/transforms/inline-node-transforms.d.ts +3 -0
  28. package/dist/types/editor-commands/transforms/list/transformBetweenListTypes.d.ts +9 -0
  29. package/dist/types/editor-commands/transforms/list-transforms.d.ts +1 -6
  30. package/dist/types/editor-commands/transforms/types.d.ts +3 -3
  31. package/dist/types/editor-commands/transforms/utils.d.ts +1 -1
  32. package/dist/types-ts4.5/editor-commands/transforms/container-transforms.d.ts +2 -2
  33. package/dist/types-ts4.5/editor-commands/transforms/inline-node-transforms.d.ts +3 -0
  34. package/dist/types-ts4.5/editor-commands/transforms/list/transformBetweenListTypes.d.ts +9 -0
  35. package/dist/types-ts4.5/editor-commands/transforms/list-transforms.d.ts +1 -6
  36. package/dist/types-ts4.5/editor-commands/transforms/types.d.ts +3 -3
  37. package/dist/types-ts4.5/editor-commands/transforms/utils.d.ts +1 -1
  38. package/package.json +7 -12
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @atlaskit/editor-plugin-block-menu
2
2
 
3
+ ## 1.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [`ecae39119dc4b`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/ecae39119dc4b) -
8
+ [ux] ED-28558 Wrap block nodes inside container nodes
9
+ - Updated dependencies
10
+
11
+ ## 1.0.0
12
+
13
+ ### Patch Changes
14
+
15
+ - [`e882e86092666`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/e882e86092666) -
16
+ [ux] Register expand, layout and code block itmes in block menu. Update panel item.
17
+ - Updated dependencies
18
+
3
19
  ## 0.0.20
4
20
 
5
21
  ### Patch Changes
@@ -27,19 +27,22 @@ var formatNode = exports.formatNode = function formatNode(targetType) {
27
27
  nodePos = selectedNode.pos;
28
28
  } else {
29
29
  // Try to find parent node (including list parents)
30
- var parentNode = (0, _utils.findParentNodeOfType)([nodes.blockquote, nodes.panel, nodes.expand, nodes.codeBlock, nodes.listItem, nodes.layoutSection])(selection);
30
+ var parentNode = (0, _utils.findParentNodeOfType)([nodes.blockquote, nodes.panel, nodes.expand, nodes.codeBlock, nodes.listItem, nodes.taskItem, nodes.layoutSection])(selection);
31
31
  if (parentNode) {
32
32
  nodeToFormat = parentNode.node;
33
33
  nodePos = parentNode.pos;
34
-
34
+ var paragraphOrHeadingNode = (0, _utils.findParentNodeOfType)([nodes.paragraph, nodes.heading])(selection);
35
35
  // Special case: if we found a listItem, check if we need the parent list instead
36
- if (parentNode.node.type === nodes.listItem) {
36
+ if (parentNode.node.type === nodes.listItem || parentNode.node.type === nodes.taskItem) {
37
37
  var listParent = (0, _utils.findParentNodeOfType)([nodes.bulletList, nodes.orderedList, nodes.taskList])(selection);
38
38
  if (listParent) {
39
39
  // For list transformations, we want the list parent, not the listItem
40
40
  nodeToFormat = listParent.node;
41
41
  nodePos = listParent.pos;
42
42
  }
43
+ } else if (paragraphOrHeadingNode) {
44
+ nodeToFormat = paragraphOrHeadingNode.node;
45
+ nodePos = paragraphOrHeadingNode.pos;
43
46
  }
44
47
  }
45
48
  }
@@ -5,33 +5,45 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.transformBlockNode = void 0;
7
7
  var _containerTransforms = require("./container-transforms");
8
+ var _inlineNodeTransforms = require("./inline-node-transforms");
8
9
  var _listTransforms = require("./list-transforms");
9
10
  var _utils = require("./utils");
10
11
  /**
11
12
  * Transform block nodes (paragraph, heading, codeblock)
12
13
  */
13
14
  var transformBlockNode = exports.transformBlockNode = function transformBlockNode(context) {
14
- var tr = context.tr,
15
- targetNodeType = context.targetNodeType,
16
- targetAttrs = context.targetAttrs;
17
- var selection = tr.selection;
18
- var $from = selection.$from,
19
- $to = selection.$to;
15
+ var targetNodeType = context.targetNodeType;
20
16
 
21
17
  // Handle transformation to list types
22
18
  if ((0, _utils.isListNodeType)(targetNodeType)) {
23
- return (0, _listTransforms.transformToList)(context);
19
+ return (0, _listTransforms.transformBlockToList)(context);
24
20
  }
25
21
 
26
22
  // Handle transformation to container types (panel, expand, blockquote)
27
23
  if ((0, _utils.isContainerNodeType)(targetNodeType)) {
28
- return (0, _containerTransforms.transformToContainer)();
24
+ return (0, _containerTransforms.transformToContainer)(context);
29
25
  }
30
26
 
31
27
  // Handle block type transformation (paragraph, heading, codeblock)
32
28
  if ((0, _utils.isBlockNodeType)(targetNodeType)) {
33
- tr.setBlockType($from.pos, $to.pos, targetNodeType, targetAttrs);
34
- return tr;
29
+ return transformToBlockNode(context);
35
30
  }
36
31
  return null;
32
+ };
33
+ var transformToBlockNode = function transformToBlockNode(context) {
34
+ var tr = context.tr,
35
+ targetNodeType = context.targetNodeType,
36
+ targetAttrs = context.targetAttrs;
37
+ var selection = tr.selection,
38
+ doc = tr.doc;
39
+ var $from = selection.$from,
40
+ $to = selection.$to;
41
+ var schema = doc.type.schema;
42
+ if (targetNodeType === schema.nodes.codeBlock) {
43
+ var textContent = (0, _inlineNodeTransforms.getInlineNodeTextContent)(selection.content().content, tr);
44
+ var node = schema.nodes.codeBlock.createChecked(undefined, textContent);
45
+ return tr.replaceRangeWith(selection.from, selection.to, node);
46
+ }
47
+ tr.setBlockType($from.pos, $to.pos, targetNodeType, targetAttrs);
48
+ return tr;
37
49
  };
@@ -4,22 +4,55 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.unwrapAndConvertToList = exports.unwrapAndConvertToBlockType = exports.transformToContainer = exports.transformContainerNode = void 0;
7
+ var _model = require("@atlaskit/editor-prosemirror/model");
7
8
  var _utils = require("./utils");
9
+ var convertInvalidNodeToValidNodeType = function convertInvalidNodeToValidNodeType(sourceContent, sourceNodeType, validNodeType, withMarks) {
10
+ var validTransformedContent = [];
11
+ // Headings are not valid inside headings so convert heading nodes to paragraphs
12
+ sourceContent.forEach(function (node) {
13
+ if (sourceNodeType === node.type) {
14
+ validTransformedContent.push(validNodeType.createChecked(node.attrs, node.content, withMarks ? node.marks : undefined));
15
+ } else {
16
+ validTransformedContent.push(node);
17
+ }
18
+ });
19
+ return _model.Fragment.from(validTransformedContent);
20
+ };
21
+
8
22
  /**
9
23
  * Transform selection to container type
10
24
  */
11
- var transformToContainer = exports.transformToContainer = function transformToContainer() {
12
- return null;
25
+ var transformToContainer = exports.transformToContainer = function transformToContainer(_ref) {
26
+ var tr = _ref.tr,
27
+ sourceNode = _ref.sourceNode,
28
+ targetNodeType = _ref.targetNodeType,
29
+ targetAttrs = _ref.targetAttrs;
30
+ var selection = tr.selection;
31
+ var schema = tr.doc.type.schema;
32
+ var content = selection.content().content;
33
+ var transformedContent = content;
34
+ if (sourceNode.type === schema.nodes.codeBlock) {
35
+ transformedContent = convertInvalidNodeToValidNodeType(transformedContent, schema.nodes.codeBlock, schema.nodes.paragraph);
36
+ }
37
+ if (targetNodeType === schema.nodes.blockquote) {
38
+ transformedContent = convertInvalidNodeToValidNodeType(transformedContent, schema.nodes.heading, schema.nodes.paragraph, true);
39
+ }
40
+ var newNode = targetNodeType.createAndFill(targetAttrs, transformedContent);
41
+ if (!newNode) {
42
+ return null;
43
+ }
44
+ tr.replaceRangeWith(selection.from, selection.to, newNode);
45
+ return tr;
13
46
  };
14
47
 
15
48
  /**
16
49
  * Transform container nodes (panel, expand, blockquote)
17
50
  */
18
- var transformContainerNode = exports.transformContainerNode = function transformContainerNode(_ref) {
19
- var tr = _ref.tr,
20
- sourcePos = _ref.sourcePos,
21
- targetNodeType = _ref.targetNodeType,
22
- targetAttrs = _ref.targetAttrs;
51
+ var transformContainerNode = exports.transformContainerNode = function transformContainerNode(_ref2) {
52
+ var tr = _ref2.tr,
53
+ sourcePos = _ref2.sourcePos,
54
+ targetNodeType = _ref2.targetNodeType,
55
+ targetAttrs = _ref2.targetAttrs;
23
56
  if (sourcePos === null) {
24
57
  return null;
25
58
  }
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getInlineNodeTextContent = void 0;
7
+ var getInlineNodeTextContent = exports.getInlineNodeTextContent = function getInlineNodeTextContent(sourceContent, tr) {
8
+ var validTransformedContent = '';
9
+ var schema = tr.doc.type.schema;
10
+ if (sourceContent.content.length > 1) {
11
+ return;
12
+ }
13
+ // Headings are not valid inside headings so convert heading nodes to paragraphs
14
+ sourceContent.forEach(function (node) {
15
+ if (['paragraph', 'heading'].includes(node.type.name)) {
16
+ node.content.forEach(function (inlineNode) {
17
+ if (inlineNode.type.name === 'status') {
18
+ validTransformedContent += inlineNode.attrs.text;
19
+ } else {
20
+ validTransformedContent += "".concat(inlineNode.textContent);
21
+ }
22
+ });
23
+ validTransformedContent;
24
+ }
25
+ });
26
+ return schema.text(validTransformedContent);
27
+ };
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.transformListStructure = void 0;
8
+ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
+ /**
10
+ * Extract all inline content from a node
11
+ */
12
+ var extractInlineContent = function extractInlineContent(node) {
13
+ var inlineContent = [];
14
+ for (var i = 0; i < node.childCount; i++) {
15
+ inlineContent.push(node.child(i));
16
+ }
17
+ return inlineContent;
18
+ };
19
+
20
+ /**
21
+ * Transform list structure
22
+ */
23
+ var transformListStructure = exports.transformListStructure = function transformListStructure(tr, listNode, targetNodeType, nodes) {
24
+ try {
25
+ var sourceList = listNode.node,
26
+ listPos = listNode.pos;
27
+ var bulletList = nodes.bulletList,
28
+ orderedList = nodes.orderedList,
29
+ taskList = nodes.taskList,
30
+ listItem = nodes.listItem,
31
+ taskItem = nodes.taskItem,
32
+ paragraph = nodes.paragraph;
33
+ var isSourceBulletOrOrdered = sourceList.type === bulletList || sourceList.type === orderedList;
34
+ var isTargetTask = targetNodeType === taskList;
35
+ var isSourceTask = sourceList.type === taskList;
36
+ var newListItems = [];
37
+ var listStart = listPos;
38
+ var listEnd = listPos + sourceList.nodeSize;
39
+
40
+ // Use nodesBetween to efficiently traverse the list structure
41
+ tr.doc.nodesBetween(listStart, listEnd, function (node, pos, parent) {
42
+ // Only process direct children of the list (depth 1)
43
+ if (parent !== sourceList) {
44
+ return true; // Continue traversal
45
+ }
46
+ if (isSourceBulletOrOrdered && isTargetTask) {
47
+ // Converting from bullet/ordered list to task list
48
+ // Extract inline content from all children within listItem
49
+ if (node.type === listItem) {
50
+ var inlineContent = [];
51
+
52
+ // Extract all inline content from all child nodes
53
+ for (var i = 0; i < node.childCount; i++) {
54
+ var child = node.child(i);
55
+ if (child.type === paragraph) {
56
+ // Extract inline content from paragraphs
57
+ inlineContent.push.apply(inlineContent, (0, _toConsumableArray2.default)(extractInlineContent(child)));
58
+ } else if (child.isBlock) {
59
+ // For other block content types eg. codeBlock, extract their text content and create text nodes
60
+ var textContent = child.textContent;
61
+ if (textContent) {
62
+ var textNode = tr.doc.type.schema.text(textContent);
63
+ inlineContent.push(textNode);
64
+ }
65
+ } else {
66
+ // Already inline content, add directly
67
+ inlineContent.push(child);
68
+ }
69
+ }
70
+ if (inlineContent.length > 0) {
71
+ var newItem = taskItem.create(null, inlineContent);
72
+ newListItems.push(newItem);
73
+ }
74
+ }
75
+ } else if (isSourceTask && !isTargetTask) {
76
+ // Converting from task list to bullet/ordered list
77
+ // Structure: taskItem > inline content -> listItem > paragraph > inline content
78
+ if (node.type === taskItem) {
79
+ var _inlineContent = extractInlineContent(node);
80
+ if (_inlineContent.length > 0) {
81
+ var paragraphNode = paragraph.create(null, _inlineContent);
82
+ var newListItem = listItem.create(null, paragraphNode);
83
+ newListItems.push(newListItem);
84
+ }
85
+ }
86
+ }
87
+ return false; // Don't traverse into children of list items
88
+ });
89
+ if (newListItems.length === 0) {
90
+ return tr;
91
+ }
92
+
93
+ // Create new list with transformed items
94
+ var newList = targetNodeType.create(null, newListItems);
95
+
96
+ // Replace the entire list
97
+ tr.replaceWith(listStart, listEnd, newList);
98
+ return tr;
99
+ } catch (_unused) {
100
+ return tr;
101
+ }
102
+ };
@@ -3,18 +3,18 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.transformToList = exports.transformListNode = exports.transformBetweenListTypes = exports.liftListToBlockType = void 0;
6
+ exports.transformListNode = exports.transformBlockToList = exports.transformBetweenListTypes = exports.liftListToBlockType = void 0;
7
7
  var _transform = require("@atlaskit/editor-prosemirror/transform");
8
8
  var _utils = require("@atlaskit/editor-prosemirror/utils");
9
+ var _transformBetweenListTypes = require("./list/transformBetweenListTypes");
9
10
  var _utils2 = require("./utils");
10
11
  /**
11
12
  * Transform selection to list type
12
13
  */
13
- var transformToList = exports.transformToList = function transformToList(_ref) {
14
- var tr = _ref.tr,
15
- targetNodeType = _ref.targetNodeType,
16
- targetAttrs = _ref.targetAttrs;
17
- // Wrap selection in list of target type
14
+ var transformBlockToList = exports.transformBlockToList = function transformBlockToList(context) {
15
+ var tr = context.tr,
16
+ targetNodeType = context.targetNodeType,
17
+ targetAttrs = context.targetAttrs;
18
18
  var _tr$selection = tr.selection,
19
19
  $from = _tr$selection.$from,
20
20
  $to = _tr$selection.$to;
@@ -22,13 +22,30 @@ var transformToList = exports.transformToList = function transformToList(_ref) {
22
22
  if (!range) {
23
23
  return null;
24
24
  }
25
+ var nodes = tr.doc.type.schema.nodes;
26
+ var isTargetTask = targetNodeType === nodes.taskList;
27
+
28
+ // Handle task lists differently due to their structure
29
+ // TODO: ED-29152 - Implement task list transformation
30
+ if (isTargetTask) {
31
+ return null;
32
+ }
33
+
34
+ // For headings, convert to paragraph first since headings cannot be direct children of list items
35
+ var sourceNode = tr.doc.nodeAt(range.start);
36
+ if (sourceNode && sourceNode.type.name.startsWith('heading')) {
37
+ tr.setBlockType(range.start, range.end, nodes.paragraph);
38
+ }
39
+
40
+ // Get the current range (updated if we converted from heading)
41
+ var currentRange = tr.selection.$from.blockRange(tr.selection.$to) || range;
25
42
 
26
- // Find if we can wrap the selection in the target list type
27
- var wrapping = (0, _transform.findWrapping)(range, targetNodeType, targetAttrs);
43
+ // Wrap in the target list type
44
+ var wrapping = (0, _transform.findWrapping)(currentRange, targetNodeType, targetAttrs);
28
45
  if (!wrapping) {
29
46
  return null;
30
47
  }
31
- tr.wrap(range, wrapping);
48
+ tr.wrap(currentRange, wrapping);
32
49
  return tr;
33
50
  };
34
51
 
@@ -67,22 +84,37 @@ var liftListToBlockType = exports.liftListToBlockType = function liftListToBlock
67
84
  /**
68
85
  * Transform between different list types
69
86
  */
70
- var transformBetweenListTypes = exports.transformBetweenListTypes = function transformBetweenListTypes(_ref2) {
71
- var tr = _ref2.tr,
72
- targetNodeType = _ref2.targetNodeType;
73
- var selection = tr.selection;
87
+ var transformBetweenListTypes = exports.transformBetweenListTypes = function transformBetweenListTypes(_ref) {
88
+ var tr = _ref.tr,
89
+ targetNodeType = _ref.targetNodeType;
90
+ var _tr = tr,
91
+ selection = _tr.selection;
74
92
  var nodes = tr.doc.type.schema.nodes;
75
93
 
76
- // Find the list node
77
- var listNode = (0, _utils.findParentNodeOfType)([nodes.bulletList, nodes.orderedList, nodes.taskList])(selection);
94
+ // Find the list node - support bullet lists, ordered lists, and task lists
95
+ var supportedListTypes = [nodes.bulletList, nodes.orderedList, nodes.taskList].filter(Boolean); // Filter out undefined nodes in case some schemas don't have all types
96
+
97
+ var listNode = (0, _utils.findParentNodeOfType)(supportedListTypes)(selection);
78
98
  if (!listNode) {
79
99
  return null;
80
100
  }
101
+ var sourceListType = listNode.node.type;
102
+ var isSourceBulletOrOrdered = sourceListType === nodes.bulletList || sourceListType === nodes.orderedList;
103
+ var isTargetTask = targetNodeType === nodes.taskList;
104
+ var isSourceTask = sourceListType === nodes.taskList;
105
+ var isTargetBulletOrOrdered = targetNodeType === nodes.bulletList || targetNodeType === nodes.orderedList;
106
+
107
+ // Check if we need structure transformation
108
+ var needsStructureTransform = isSourceBulletOrOrdered && isTargetTask || isSourceTask && isTargetBulletOrOrdered;
81
109
  try {
82
- // Change the list type while preserving content
83
- tr.setNodeMarkup(listNode.pos, targetNodeType);
84
- return tr;
85
- } catch (e) {
110
+ if (!needsStructureTransform) {
111
+ // Simple type change for same structure lists (bullet <-> ordered)
112
+ tr.setNodeMarkup(listNode.pos, targetNodeType);
113
+ } else {
114
+ tr = (0, _transformBetweenListTypes.transformListStructure)(tr, listNode, targetNodeType, nodes);
115
+ }
116
+ } catch (_unused) {
86
117
  return null;
87
118
  }
119
+ return tr;
88
120
  };
@@ -67,7 +67,7 @@ var getTargetNodeInfo = exports.getTargetNodeInfo = function getTargetNodeInfo(t
67
67
  panelType: 'info'
68
68
  }
69
69
  };
70
- case 'codeblock':
70
+ case 'codeBlock':
71
71
  return {
72
72
  nodeType: nodes.codeBlock
73
73
  };
@@ -11,7 +11,6 @@ var _blockMenu = require("@atlaskit/editor-common/block-menu");
11
11
  var _editorToolbar = require("@atlaskit/editor-toolbar");
12
12
  var _changes = _interopRequireDefault(require("@atlaskit/icon/core/changes"));
13
13
  var _chevronRight = _interopRequireDefault(require("@atlaskit/icon/core/chevron-right"));
14
- var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
15
14
  var _copyBlock = _interopRequireDefault(require("./copy-block"));
16
15
  var _copyLink = require("./copy-link");
17
16
  var _deleteButton = require("./delete-button");
@@ -98,7 +97,7 @@ var getFormatMenuComponents = function getFormatMenuComponents() {
98
97
  var getBlockMenuComponents = exports.getBlockMenuComponents = function getBlockMenuComponents(_ref4) {
99
98
  var api = _ref4.api,
100
99
  config = _ref4.config;
101
- return [].concat((0, _toConsumableArray2.default)((0, _platformFeatureFlags.fg)('platform_editor_block_menu_format') ? getFormatMenuComponents() : []), [{
100
+ return [].concat((0, _toConsumableArray2.default)(getFormatMenuComponents()), [{
102
101
  type: 'block-menu-section',
103
102
  key: _blockMenu.COPY_MENU_SECTION.key,
104
103
  rank: _blockMenu.BLOCK_MENU_SECTION_RANK[_blockMenu.COPY_MENU_SECTION.key],
@@ -26,19 +26,22 @@ export const formatNode = targetType => {
26
26
  nodePos = selectedNode.pos;
27
27
  } else {
28
28
  // Try to find parent node (including list parents)
29
- const parentNode = findParentNodeOfType([nodes.blockquote, nodes.panel, nodes.expand, nodes.codeBlock, nodes.listItem, nodes.layoutSection])(selection);
29
+ const parentNode = findParentNodeOfType([nodes.blockquote, nodes.panel, nodes.expand, nodes.codeBlock, nodes.listItem, nodes.taskItem, nodes.layoutSection])(selection);
30
30
  if (parentNode) {
31
31
  nodeToFormat = parentNode.node;
32
32
  nodePos = parentNode.pos;
33
-
33
+ const paragraphOrHeadingNode = findParentNodeOfType([nodes.paragraph, nodes.heading])(selection);
34
34
  // Special case: if we found a listItem, check if we need the parent list instead
35
- if (parentNode.node.type === nodes.listItem) {
35
+ if (parentNode.node.type === nodes.listItem || parentNode.node.type === nodes.taskItem) {
36
36
  const listParent = findParentNodeOfType([nodes.bulletList, nodes.orderedList, nodes.taskList])(selection);
37
37
  if (listParent) {
38
38
  // For list transformations, we want the list parent, not the listItem
39
39
  nodeToFormat = listParent.node;
40
40
  nodePos = listParent.pos;
41
41
  }
42
+ } else if (paragraphOrHeadingNode) {
43
+ nodeToFormat = paragraphOrHeadingNode.node;
44
+ nodePos = paragraphOrHeadingNode.pos;
42
45
  }
43
46
  }
44
47
  }
@@ -1,5 +1,6 @@
1
1
  import { transformToContainer } from './container-transforms';
2
- import { transformToList } from './list-transforms';
2
+ import { getInlineNodeTextContent } from './inline-node-transforms';
3
+ import { transformBlockToList } from './list-transforms';
3
4
  import { isListNodeType, isContainerNodeType, isBlockNodeType } from './utils';
4
5
 
5
6
  /**
@@ -7,32 +8,45 @@ import { isListNodeType, isContainerNodeType, isBlockNodeType } from './utils';
7
8
  */
8
9
  export const transformBlockNode = context => {
9
10
  const {
10
- tr,
11
- targetNodeType,
12
- targetAttrs
11
+ targetNodeType
13
12
  } = context;
14
- const {
15
- selection
16
- } = tr;
17
- const {
18
- $from,
19
- $to
20
- } = selection;
21
13
 
22
14
  // Handle transformation to list types
23
15
  if (isListNodeType(targetNodeType)) {
24
- return transformToList(context);
16
+ return transformBlockToList(context);
25
17
  }
26
18
 
27
19
  // Handle transformation to container types (panel, expand, blockquote)
28
20
  if (isContainerNodeType(targetNodeType)) {
29
- return transformToContainer();
21
+ return transformToContainer(context);
30
22
  }
31
23
 
32
24
  // Handle block type transformation (paragraph, heading, codeblock)
33
25
  if (isBlockNodeType(targetNodeType)) {
34
- tr.setBlockType($from.pos, $to.pos, targetNodeType, targetAttrs);
35
- return tr;
26
+ return transformToBlockNode(context);
36
27
  }
37
28
  return null;
29
+ };
30
+ const transformToBlockNode = context => {
31
+ const {
32
+ tr,
33
+ targetNodeType,
34
+ targetAttrs
35
+ } = context;
36
+ const {
37
+ selection,
38
+ doc
39
+ } = tr;
40
+ const {
41
+ $from,
42
+ $to
43
+ } = selection;
44
+ const schema = doc.type.schema;
45
+ if (targetNodeType === schema.nodes.codeBlock) {
46
+ const textContent = getInlineNodeTextContent(selection.content().content, tr);
47
+ const node = schema.nodes.codeBlock.createChecked(undefined, textContent);
48
+ return tr.replaceRangeWith(selection.from, selection.to, node);
49
+ }
50
+ tr.setBlockType($from.pos, $to.pos, targetNodeType, targetAttrs);
51
+ return tr;
38
52
  };
@@ -1,10 +1,43 @@
1
+ import { Fragment } from '@atlaskit/editor-prosemirror/model';
1
2
  import { isBlockNodeType, isListNodeType, isContainerNodeType } from './utils';
3
+ const convertInvalidNodeToValidNodeType = (sourceContent, sourceNodeType, validNodeType, withMarks) => {
4
+ const validTransformedContent = [];
5
+ // Headings are not valid inside headings so convert heading nodes to paragraphs
6
+ sourceContent.forEach(node => {
7
+ if (sourceNodeType === node.type) {
8
+ validTransformedContent.push(validNodeType.createChecked(node.attrs, node.content, withMarks ? node.marks : undefined));
9
+ } else {
10
+ validTransformedContent.push(node);
11
+ }
12
+ });
13
+ return Fragment.from(validTransformedContent);
14
+ };
2
15
 
3
16
  /**
4
17
  * Transform selection to container type
5
18
  */
6
- export const transformToContainer = () => {
7
- return null;
19
+ export const transformToContainer = ({
20
+ tr,
21
+ sourceNode,
22
+ targetNodeType,
23
+ targetAttrs
24
+ }) => {
25
+ const selection = tr.selection;
26
+ const schema = tr.doc.type.schema;
27
+ const content = selection.content().content;
28
+ let transformedContent = content;
29
+ if (sourceNode.type === schema.nodes.codeBlock) {
30
+ transformedContent = convertInvalidNodeToValidNodeType(transformedContent, schema.nodes.codeBlock, schema.nodes.paragraph);
31
+ }
32
+ if (targetNodeType === schema.nodes.blockquote) {
33
+ transformedContent = convertInvalidNodeToValidNodeType(transformedContent, schema.nodes.heading, schema.nodes.paragraph, true);
34
+ }
35
+ const newNode = targetNodeType.createAndFill(targetAttrs, transformedContent);
36
+ if (!newNode) {
37
+ return null;
38
+ }
39
+ tr.replaceRangeWith(selection.from, selection.to, newNode);
40
+ return tr;
8
41
  };
9
42
 
10
43
  /**
@@ -0,0 +1,21 @@
1
+ export const getInlineNodeTextContent = (sourceContent, tr) => {
2
+ let validTransformedContent = '';
3
+ const schema = tr.doc.type.schema;
4
+ if (sourceContent.content.length > 1) {
5
+ return;
6
+ }
7
+ // Headings are not valid inside headings so convert heading nodes to paragraphs
8
+ sourceContent.forEach(node => {
9
+ if (['paragraph', 'heading'].includes(node.type.name)) {
10
+ node.content.forEach(inlineNode => {
11
+ if (inlineNode.type.name === 'status') {
12
+ validTransformedContent += inlineNode.attrs.text;
13
+ } else {
14
+ validTransformedContent += `${inlineNode.textContent}`;
15
+ }
16
+ });
17
+ validTransformedContent;
18
+ }
19
+ });
20
+ return schema.text(validTransformedContent);
21
+ };