@atlaskit/editor-plugin-block-menu 1.0.3 → 1.0.5

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 (35) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/cjs/editor-commands/formatNode.js +1 -1
  3. package/dist/cjs/editor-commands/transforms/layout-transforms.js +30 -0
  4. package/dist/cjs/editor-commands/transforms/list/transformBetweenListTypes.js +65 -63
  5. package/dist/cjs/editor-commands/transforms/list-transforms.js +97 -30
  6. package/dist/cjs/editor-commands/transforms/transformNodeToTargetType.js +4 -0
  7. package/dist/cjs/editor-commands/transforms/utils.js +23 -2
  8. package/dist/cjs/ui/block-menu-components.js +2 -1
  9. package/dist/es2019/editor-commands/formatNode.js +1 -1
  10. package/dist/es2019/editor-commands/transforms/layout-transforms.js +25 -0
  11. package/dist/es2019/editor-commands/transforms/list/transformBetweenListTypes.js +67 -62
  12. package/dist/es2019/editor-commands/transforms/list-transforms.js +97 -27
  13. package/dist/es2019/editor-commands/transforms/transformNodeToTargetType.js +5 -1
  14. package/dist/es2019/editor-commands/transforms/utils.js +22 -1
  15. package/dist/es2019/ui/block-menu-components.js +2 -1
  16. package/dist/esm/editor-commands/formatNode.js +1 -1
  17. package/dist/esm/editor-commands/transforms/layout-transforms.js +24 -0
  18. package/dist/esm/editor-commands/transforms/list/transformBetweenListTypes.js +66 -63
  19. package/dist/esm/editor-commands/transforms/list-transforms.js +92 -26
  20. package/dist/esm/editor-commands/transforms/transformNodeToTargetType.js +5 -1
  21. package/dist/esm/editor-commands/transforms/utils.js +22 -1
  22. package/dist/esm/ui/block-menu-components.js +2 -1
  23. package/dist/types/editor-commands/transforms/layout-transforms.d.ts +2 -0
  24. package/dist/types/editor-commands/transforms/list/transformBetweenListTypes.d.ts +3 -7
  25. package/dist/types/editor-commands/transforms/list-transforms.d.ts +5 -1
  26. package/dist/types/editor-commands/transforms/transformNodeToTargetType.d.ts +1 -1
  27. package/dist/types/editor-commands/transforms/types.d.ts +2 -2
  28. package/dist/types/editor-commands/transforms/utils.d.ts +5 -0
  29. package/dist/types-ts4.5/editor-commands/transforms/layout-transforms.d.ts +2 -0
  30. package/dist/types-ts4.5/editor-commands/transforms/list/transformBetweenListTypes.d.ts +3 -7
  31. package/dist/types-ts4.5/editor-commands/transforms/list-transforms.d.ts +5 -1
  32. package/dist/types-ts4.5/editor-commands/transforms/transformNodeToTargetType.d.ts +1 -1
  33. package/dist/types-ts4.5/editor-commands/transforms/types.d.ts +2 -2
  34. package/dist/types-ts4.5/editor-commands/transforms/utils.d.ts +5 -0
  35. package/package.json +6 -6
@@ -1,3 +1,5 @@
1
+ import { getSupportedListTypesSet, isBulletOrOrderedList, isTaskList } from '../utils';
2
+
1
3
  /**
2
4
  * Convert a block node to inline content suitable for task items
3
5
  */
@@ -6,89 +8,92 @@ const convertBlockToInlineContent = (node, schema) => {
6
8
  paragraph
7
9
  } = schema.nodes;
8
10
  if (node.type === paragraph) {
9
- // Extract inline content from paragraphs
10
11
  return [...node.content.content];
11
- } else if (node.isBlock) {
12
- // For other block content types eg. codeBlock, extract their text content and create text nodes
12
+ }
13
+ if (node.isBlock) {
13
14
  const textContent = node.textContent;
14
- if (textContent) {
15
- const textNode = schema.text(textContent);
16
- return [textNode];
17
- }
18
- } else {
19
- // Already inline content, add directly
20
- return [node];
15
+ return textContent ? [schema.text(textContent)] : [];
21
16
  }
22
- return [];
17
+ return [node];
23
18
  };
24
19
 
25
20
  /**
26
- * Transform list structure
21
+ * Transform list structure between different list types
27
22
  */
28
- export const transformListStructure = (tr, listNode, targetNodeType, nodes) => {
23
+ export const transformListStructure = context => {
24
+ const {
25
+ tr,
26
+ sourceNode,
27
+ sourcePos,
28
+ targetNodeType
29
+ } = context;
30
+ const nodes = tr.doc.type.schema.nodes;
29
31
  try {
32
+ const listNode = {
33
+ node: sourceNode,
34
+ pos: sourcePos
35
+ };
30
36
  const {
31
37
  node: sourceList,
32
38
  pos: listPos
33
39
  } = listNode;
34
40
  const {
35
- bulletList,
36
- orderedList,
37
41
  taskList,
38
42
  listItem,
39
43
  taskItem,
40
44
  paragraph
41
45
  } = nodes;
42
- const isSourceBulletOrOrdered = sourceList.type === bulletList || sourceList.type === orderedList;
43
- const isTargetTask = targetNodeType === taskList;
44
- const isSourceTask = sourceList.type === taskList;
45
- const newListItems = [];
46
- const listStart = listPos;
47
- const listEnd = listPos + sourceList.nodeSize;
48
-
49
- // Use nodesBetween to efficiently traverse the list structure
50
- tr.doc.nodesBetween(listStart, listEnd, (node, pos, parent) => {
51
- // Only process direct children of the list (depth 1)
52
- if (parent !== sourceList) {
53
- return true; // Continue traversal
54
- }
55
- if (isSourceBulletOrOrdered && isTargetTask) {
56
- // Converting from bullet/ordered list to task list
57
- // Extract inline content from all children within listItem
58
- if (node.type === listItem) {
59
- const inlineContent = [];
60
- // Extract inline content from all child nodes
61
- node.forEach(child => {
62
- inlineContent.push(...convertBlockToInlineContent(child, tr.doc.type.schema));
63
- });
64
- if (inlineContent.length > 0) {
65
- const newItem = taskItem.create(null, inlineContent);
66
- newListItems.push(newItem);
46
+ const isSourceBulletOrOrdered = isBulletOrOrderedList(sourceList.type);
47
+ const isTargetTask = isTaskList(targetNodeType);
48
+ const isSourceTask = isTaskList(sourceList.type);
49
+ const isTargetBulletOrOrdered = isBulletOrOrderedList(targetNodeType);
50
+ const supportedListTypes = getSupportedListTypesSet(nodes);
51
+ const transformListRecursively = listNode => {
52
+ const transformedItems = [];
53
+ listNode.forEach(child => {
54
+ if (isSourceBulletOrOrdered && isTargetTask) {
55
+ // Convert bullet/ordered => task
56
+ if (child.type === listItem) {
57
+ const inlineContent = [];
58
+ const nestedTaskLists = [];
59
+ child.forEach(grandChild => {
60
+ if (supportedListTypes.has(grandChild.type) && grandChild.type !== taskList) {
61
+ nestedTaskLists.push(transformListRecursively(grandChild));
62
+ } else {
63
+ inlineContent.push(...convertBlockToInlineContent(grandChild, tr.doc.type.schema));
64
+ }
65
+ });
66
+ if (inlineContent.length > 0) {
67
+ transformedItems.push(taskItem.create(null, inlineContent));
68
+ }
69
+ transformedItems.push(...nestedTaskLists);
67
70
  }
68
- }
69
- } else if (isSourceTask && !isTargetTask) {
70
- // Converting from task list to bullet/ordered list
71
- // Structure: taskItem > inline content -> listItem > paragraph > inline content
72
- if (node.type === taskItem) {
73
- const inlineContent = [...node.content.content];
74
- if (inlineContent.length > 0) {
75
- const paragraphNode = paragraph.create(null, inlineContent);
76
- const newListItem = listItem.create(null, paragraphNode);
77
- newListItems.push(newListItem);
71
+ } else if (isSourceTask && isTargetBulletOrOrdered) {
72
+ // Convert task => bullet/ordered
73
+ if (child.type === taskItem) {
74
+ const inlineContent = [...child.content.content];
75
+ if (inlineContent.length > 0) {
76
+ const paragraphNode = paragraph.create(null, inlineContent);
77
+ transformedItems.push(listItem.create(null, [paragraphNode]));
78
+ }
79
+ } else if (child.type === taskList) {
80
+ const transformedNestedList = transformListRecursively(child);
81
+ const lastItem = transformedItems[transformedItems.length - 1];
82
+ if ((lastItem === null || lastItem === void 0 ? void 0 : lastItem.type) === listItem) {
83
+ // Attach nested list to previous item
84
+ const updatedContent = [...lastItem.content.content, transformedNestedList];
85
+ transformedItems[transformedItems.length - 1] = listItem.create(lastItem.attrs, updatedContent);
86
+ } else {
87
+ // No previous item, flatten nested items
88
+ transformedItems.push(...transformedNestedList.content.content);
89
+ }
78
90
  }
79
91
  }
80
- }
81
- return false; // Don't traverse into children of list items
82
- });
83
- if (newListItems.length === 0) {
84
- return tr;
85
- }
86
-
87
- // Create new list with transformed items
88
- const newList = targetNodeType.create(null, newListItems);
89
-
90
- // Replace the entire list
91
- tr.replaceWith(listStart, listEnd, newList);
92
+ });
93
+ return targetNodeType.create(null, transformedItems);
94
+ };
95
+ const newList = transformListRecursively(sourceList);
96
+ tr.replaceWith(listPos, listPos + sourceList.nodeSize, newList);
92
97
  return tr;
93
98
  } catch {
94
99
  return tr;
@@ -1,10 +1,10 @@
1
+ import { Fragment } from '@atlaskit/editor-prosemirror/model';
1
2
  import { findWrapping } from '@atlaskit/editor-prosemirror/transform';
2
- import { findParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
3
3
  import { transformListStructure } from './list/transformBetweenListTypes';
4
4
  import { transformOrderedUnorderedListToBlockNodes } from './list/transformOrderedUnorderedListToBlockNodes';
5
5
  import { transformTaskListToBlockNodes } from './list/transformTaskListToBlockNodes';
6
6
  import { transformToTaskList } from './list/transformToTaskList';
7
- import { isBlockNodeType, isContainerNodeType, isListNodeType } from './utils';
7
+ import { getSupportedListTypesSet, isBulletOrOrderedList, isBlockNodeType, isContainerNodeType, isListNodeType, isTaskList } from './utils';
8
8
 
9
9
  /**
10
10
  * Transform selection to list type
@@ -27,7 +27,7 @@ export const transformBlockToList = context => {
27
27
  const {
28
28
  nodes
29
29
  } = tr.doc.type.schema;
30
- const isTargetTask = targetNodeType === nodes.taskList;
30
+ const isTargetTask = isTaskList(targetNodeType);
31
31
 
32
32
  // Handle task lists differently due to their structure
33
33
  if (isTargetTask) {
@@ -65,6 +65,65 @@ export const transformListToBlockNodes = context => {
65
65
  }
66
66
  };
67
67
 
68
+ /**
69
+ * Wraps bulletList, orderedList or taskList in node of container type
70
+ */
71
+ export const transformListToContainer = context => {
72
+ const {
73
+ tr,
74
+ sourceNode,
75
+ sourcePos,
76
+ targetNodeType,
77
+ targetAttrs
78
+ } = context;
79
+ if (sourcePos === null) {
80
+ return null;
81
+ }
82
+ const {
83
+ schema
84
+ } = tr.doc.type;
85
+ const {
86
+ blockquote,
87
+ taskList,
88
+ taskItem,
89
+ paragraph
90
+ } = schema.nodes;
91
+
92
+ // Special case: Task list -> Blockquote
93
+ // Flattens the task list before wrapping by blockquote
94
+ if (sourceNode.type === taskList && targetNodeType === blockquote) {
95
+ const extractParagraphsFromTaskList = node => {
96
+ const paragraphs = [];
97
+ node.forEach(child => {
98
+ if (child.type === taskItem) {
99
+ if (child.content.size > 0) {
100
+ const paragraphNode = paragraph.createChecked({}, child.content.content);
101
+ paragraphs.push(paragraphNode);
102
+ }
103
+ } else if (child.type === taskList) {
104
+ paragraphs.push(...extractParagraphsFromTaskList(child));
105
+ }
106
+ });
107
+ return paragraphs;
108
+ };
109
+ const liftedParagraphs = extractParagraphsFromTaskList(sourceNode);
110
+ const containerNode = targetNodeType.createAndFill(targetAttrs, Fragment.from(liftedParagraphs));
111
+ if (!containerNode) {
112
+ return null;
113
+ }
114
+ tr.replaceWith(sourcePos, sourcePos + sourceNode.nodeSize, containerNode);
115
+ return tr;
116
+ }
117
+
118
+ // Default case
119
+ const containerNode = targetNodeType.createAndFill(targetAttrs, [sourceNode]);
120
+ if (!containerNode) {
121
+ return null;
122
+ }
123
+ tr.replaceWith(sourcePos, sourcePos + sourceNode.nodeSize, containerNode);
124
+ return tr;
125
+ };
126
+
68
127
  /**
69
128
  * Transform list nodes
70
129
  */
@@ -80,8 +139,8 @@ export const transformListNode = context => {
80
139
 
81
140
  // Transform list to container type
82
141
  if (isContainerNodeType(targetNodeType)) {
83
- // Lift list items out of the list and convert to container type
84
- return null;
142
+ // Wrap list items into container type, where possible
143
+ return transformListToContainer(context);
85
144
  }
86
145
 
87
146
  // Transform between list types
@@ -102,41 +161,52 @@ export const liftListToBlockType = () => {
102
161
  /**
103
162
  * Transform between different list types
104
163
  */
105
- export const transformBetweenListTypes = ({
106
- tr,
107
- targetNodeType
108
- }) => {
164
+ export const transformBetweenListTypes = context => {
109
165
  const {
110
- selection
111
- } = tr;
166
+ tr,
167
+ sourceNode,
168
+ sourcePos,
169
+ targetNodeType
170
+ } = context;
112
171
  const {
113
172
  nodes
114
173
  } = tr.doc.type.schema;
115
-
116
- // Find the list node - support bullet lists, ordered lists, and task lists
117
- const supportedListTypes = [nodes.bulletList, nodes.orderedList, nodes.taskList].filter(Boolean); // Filter out undefined nodes in case some schemas don't have all types
118
-
119
- const listNode = findParentNodeOfType(supportedListTypes)(selection);
120
- if (!listNode) {
121
- return null;
122
- }
123
- const sourceListType = listNode.node.type;
124
- const isSourceBulletOrOrdered = sourceListType === nodes.bulletList || sourceListType === nodes.orderedList;
125
- const isTargetTask = targetNodeType === nodes.taskList;
126
- const isSourceTask = sourceListType === nodes.taskList;
127
- const isTargetBulletOrOrdered = targetNodeType === nodes.bulletList || targetNodeType === nodes.orderedList;
174
+ const sourceListType = sourceNode.type;
175
+ const isSourceBulletOrOrdered = isBulletOrOrderedList(sourceListType);
176
+ const isTargetTask = isTaskList(targetNodeType);
177
+ const isSourceTask = isTaskList(sourceListType);
178
+ const isTargetBulletOrOrdered = isBulletOrOrderedList(targetNodeType);
128
179
 
129
180
  // Check if we need structure transformation
130
181
  const needsStructureTransform = isSourceBulletOrOrdered && isTargetTask || isSourceTask && isTargetBulletOrOrdered;
131
182
  try {
132
183
  if (!needsStructureTransform) {
133
184
  // Simple type change for same structure lists (bullet <-> ordered)
134
- tr.setNodeMarkup(listNode.pos, targetNodeType);
185
+ // Apply to the main list
186
+ tr.setNodeMarkup(sourcePos, targetNodeType);
187
+
188
+ // Apply to nested lists
189
+ const listStart = sourcePos;
190
+ const listEnd = sourcePos + sourceNode.nodeSize;
191
+ const supportedListTypesSet = getSupportedListTypesSet(nodes);
192
+ tr.doc.nodesBetween(listStart, listEnd, (node, pos, parent) => {
193
+ // Only process nested lists (not the root list we already handled)
194
+ if (supportedListTypesSet.has(node.type) && pos !== sourcePos) {
195
+ const isNestedList = parent && (supportedListTypesSet.has(parent.type) || parent.type === nodes.listItem);
196
+ if (isNestedList) {
197
+ const shouldTransformNode = node.type === sourceListType || isBulletOrOrderedList(node.type) && isTargetBulletOrOrdered;
198
+ if (shouldTransformNode) {
199
+ tr.setNodeMarkup(pos, targetNodeType);
200
+ }
201
+ }
202
+ }
203
+ return true; // Continue traversing
204
+ });
205
+ return tr;
135
206
  } else {
136
- tr = transformListStructure(tr, listNode, targetNodeType, nodes);
207
+ return transformListStructure(context);
137
208
  }
138
209
  } catch {
139
210
  return null;
140
211
  }
141
- return tr;
142
212
  };
@@ -1,7 +1,8 @@
1
1
  import { transformBlockNode } from './block-transforms';
2
2
  import { transformContainerNode } from './container-transforms';
3
+ import { convertToLayout } from './layout-transforms';
3
4
  import { transformListNode } from './list-transforms';
4
- import { getTargetNodeInfo, isBlockNode, isListNode, isContainerNode } from './utils';
5
+ import { getTargetNodeInfo, isBlockNode, isListNode, isContainerNode, isLayoutNodeType } from './utils';
5
6
  export function transformNodeToTargetType(tr, sourceNode, sourcePos, targetType) {
6
7
  const {
7
8
  nodes
@@ -41,6 +42,9 @@ export function transformNodeToTargetType(tr, sourceNode, sourcePos, targetType)
41
42
 
42
43
  // Route to appropriate transformation strategy based on source node type
43
44
  try {
45
+ if (isLayoutNodeType(targetNodeType)) {
46
+ return convertToLayout(transformationContext);
47
+ }
44
48
  if (isBlockNode(sourceNode)) {
45
49
  return transformBlockNode(transformationContext);
46
50
  }
@@ -77,6 +77,10 @@ export const getTargetNodeInfo = (targetType, nodes) => {
77
77
  return {
78
78
  nodeType: nodes.taskList
79
79
  };
80
+ case 'layoutSection':
81
+ return {
82
+ nodeType: nodes.layoutSection
83
+ };
80
84
  default:
81
85
  return null;
82
86
  }
@@ -87,7 +91,7 @@ export const isBlockNode = node => {
87
91
  return ['paragraph', 'heading', 'codeBlock'].includes(node.type.name);
88
92
  };
89
93
  export const isListNode = node => {
90
- return ['bulletList', 'orderedList', 'taskList', 'listItem'].includes(node.type.name);
94
+ return ['bulletList', 'orderedList', 'taskList'].includes(node.type.name);
91
95
  };
92
96
  export const isContainerNode = node => {
93
97
  return ['panel', 'expand', 'blockquote'].includes(node.type.name);
@@ -100,4 +104,21 @@ export const isListNodeType = nodeType => {
100
104
  };
101
105
  export const isContainerNodeType = nodeType => {
102
106
  return ['panel', 'expand', 'blockquote'].includes(nodeType.name);
107
+ };
108
+
109
+ // List type utilities
110
+ export const isBulletOrOrderedList = nodeType => {
111
+ return nodeType.name === 'bulletList' || nodeType.name === 'orderedList';
112
+ };
113
+ export const isTaskList = nodeType => {
114
+ return nodeType.name === 'taskList';
115
+ };
116
+ export const getSupportedListTypes = nodes => {
117
+ return [nodes.bulletList, nodes.orderedList, nodes.taskList].filter(Boolean);
118
+ };
119
+ export const getSupportedListTypesSet = nodes => {
120
+ return new Set(getSupportedListTypes(nodes));
121
+ };
122
+ export const isLayoutNodeType = nodeType => {
123
+ return nodeType.name === 'layoutSection';
103
124
  };
@@ -54,7 +54,8 @@ const getFormatMenuComponents = () => {
54
54
  }),
55
55
  elemAfter: /*#__PURE__*/React.createElement(ChevronRightIcon, {
56
56
  label: 'example nested menu'
57
- })
57
+ }),
58
+ enableMaxHeight: true
58
59
  }, children);
59
60
  }
60
61
  }, {
@@ -12,7 +12,7 @@ export var formatNode = function formatNode(targetType) {
12
12
 
13
13
  // Find the node to format from the current selection
14
14
  var nodeToFormat;
15
- var nodePos = null;
15
+ var nodePos = selection.from;
16
16
 
17
17
  // Try to find the current node from selection
18
18
  var selectedNode = findSelectedNodeOfType([nodes.paragraph, nodes.heading, nodes.blockquote, nodes.panel, nodes.expand, nodes.codeBlock, nodes.bulletList, nodes.orderedList, nodes.taskList, nodes.layoutSection])(selection);
@@ -0,0 +1,24 @@
1
+ import { DEFAULT_TWO_COLUMN_LAYOUT_COLUMN_WIDTH } from '@atlaskit/editor-common/styles';
2
+ import { Fragment } from '@atlaskit/editor-prosemirror/model';
3
+ export var convertToLayout = function convertToLayout(context) {
4
+ var tr = context.tr,
5
+ sourceNode = context.sourceNode,
6
+ sourcePos = context.sourcePos;
7
+ var _ref = tr.doc.type.schema.nodes || {},
8
+ layoutSection = _ref.layoutSection,
9
+ layoutColumn = _ref.layoutColumn,
10
+ paragraph = _ref.paragraph;
11
+ var content = sourceNode.mark(sourceNode.marks.filter(function (mark) {
12
+ return mark.type.name !== 'breakout';
13
+ }));
14
+ var layoutContent = Fragment.fromArray([layoutColumn.createChecked({
15
+ width: DEFAULT_TWO_COLUMN_LAYOUT_COLUMN_WIDTH
16
+ }, content), layoutColumn.create({
17
+ width: DEFAULT_TWO_COLUMN_LAYOUT_COLUMN_WIDTH
18
+ }, paragraph.createAndFill())]);
19
+ var layoutSectionNode = layoutSection.createChecked(undefined, layoutContent);
20
+
21
+ // Replace the original node with the new layout node
22
+ tr.replaceRangeWith(sourcePos || 0, (sourcePos || 0) + sourceNode.nodeSize, layoutSectionNode);
23
+ return tr;
24
+ };
@@ -1,89 +1,92 @@
1
1
  import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
+ import { getSupportedListTypesSet, isBulletOrOrderedList, isTaskList } from '../utils';
3
+
2
4
  /**
3
5
  * Convert a block node to inline content suitable for task items
4
6
  */
5
7
  var convertBlockToInlineContent = function convertBlockToInlineContent(node, schema) {
6
8
  var paragraph = schema.nodes.paragraph;
7
9
  if (node.type === paragraph) {
8
- // Extract inline content from paragraphs
9
10
  return _toConsumableArray(node.content.content);
10
- } else if (node.isBlock) {
11
- // For other block content types eg. codeBlock, extract their text content and create text nodes
11
+ }
12
+ if (node.isBlock) {
12
13
  var textContent = node.textContent;
13
- if (textContent) {
14
- var textNode = schema.text(textContent);
15
- return [textNode];
16
- }
17
- } else {
18
- // Already inline content, add directly
19
- return [node];
14
+ return textContent ? [schema.text(textContent)] : [];
20
15
  }
21
- return [];
16
+ return [node];
22
17
  };
23
18
 
24
19
  /**
25
- * Transform list structure
20
+ * Transform list structure between different list types
26
21
  */
27
- export var transformListStructure = function transformListStructure(tr, listNode, targetNodeType, nodes) {
22
+ export var transformListStructure = function transformListStructure(context) {
23
+ var tr = context.tr,
24
+ sourceNode = context.sourceNode,
25
+ sourcePos = context.sourcePos,
26
+ targetNodeType = context.targetNodeType;
27
+ var nodes = tr.doc.type.schema.nodes;
28
28
  try {
29
+ var listNode = {
30
+ node: sourceNode,
31
+ pos: sourcePos
32
+ };
29
33
  var sourceList = listNode.node,
30
34
  listPos = listNode.pos;
31
- var bulletList = nodes.bulletList,
32
- orderedList = nodes.orderedList,
33
- taskList = nodes.taskList,
35
+ var taskList = nodes.taskList,
34
36
  listItem = nodes.listItem,
35
37
  taskItem = nodes.taskItem,
36
38
  paragraph = nodes.paragraph;
37
- var isSourceBulletOrOrdered = sourceList.type === bulletList || sourceList.type === orderedList;
38
- var isTargetTask = targetNodeType === taskList;
39
- var isSourceTask = sourceList.type === taskList;
40
- var newListItems = [];
41
- var listStart = listPos;
42
- var listEnd = listPos + sourceList.nodeSize;
43
-
44
- // Use nodesBetween to efficiently traverse the list structure
45
- tr.doc.nodesBetween(listStart, listEnd, function (node, pos, parent) {
46
- // Only process direct children of the list (depth 1)
47
- if (parent !== sourceList) {
48
- return true; // Continue traversal
49
- }
50
- if (isSourceBulletOrOrdered && isTargetTask) {
51
- // Converting from bullet/ordered list to task list
52
- // Extract inline content from all children within listItem
53
- if (node.type === listItem) {
54
- var inlineContent = [];
55
- // Extract inline content from all child nodes
56
- node.forEach(function (child) {
57
- inlineContent.push.apply(inlineContent, _toConsumableArray(convertBlockToInlineContent(child, tr.doc.type.schema)));
58
- });
59
- if (inlineContent.length > 0) {
60
- var newItem = taskItem.create(null, inlineContent);
61
- newListItems.push(newItem);
39
+ var isSourceBulletOrOrdered = isBulletOrOrderedList(sourceList.type);
40
+ var isTargetTask = isTaskList(targetNodeType);
41
+ var isSourceTask = isTaskList(sourceList.type);
42
+ var isTargetBulletOrOrdered = isBulletOrOrderedList(targetNodeType);
43
+ var supportedListTypes = getSupportedListTypesSet(nodes);
44
+ var _transformListRecursively = function transformListRecursively(listNode) {
45
+ var transformedItems = [];
46
+ listNode.forEach(function (child) {
47
+ if (isSourceBulletOrOrdered && isTargetTask) {
48
+ // Convert bullet/ordered => task
49
+ if (child.type === listItem) {
50
+ var inlineContent = [];
51
+ var nestedTaskLists = [];
52
+ child.forEach(function (grandChild) {
53
+ if (supportedListTypes.has(grandChild.type) && grandChild.type !== taskList) {
54
+ nestedTaskLists.push(_transformListRecursively(grandChild));
55
+ } else {
56
+ inlineContent.push.apply(inlineContent, _toConsumableArray(convertBlockToInlineContent(grandChild, tr.doc.type.schema)));
57
+ }
58
+ });
59
+ if (inlineContent.length > 0) {
60
+ transformedItems.push(taskItem.create(null, inlineContent));
61
+ }
62
+ transformedItems.push.apply(transformedItems, nestedTaskLists);
62
63
  }
63
- }
64
- } else if (isSourceTask && !isTargetTask) {
65
- // Converting from task list to bullet/ordered list
66
- // Structure: taskItem > inline content -> listItem > paragraph > inline content
67
- if (node.type === taskItem) {
68
- var _inlineContent = _toConsumableArray(node.content.content);
69
- if (_inlineContent.length > 0) {
70
- var paragraphNode = paragraph.create(null, _inlineContent);
71
- var newListItem = listItem.create(null, paragraphNode);
72
- newListItems.push(newListItem);
64
+ } else if (isSourceTask && isTargetBulletOrOrdered) {
65
+ // Convert task => bullet/ordered
66
+ if (child.type === taskItem) {
67
+ var _inlineContent = _toConsumableArray(child.content.content);
68
+ if (_inlineContent.length > 0) {
69
+ var paragraphNode = paragraph.create(null, _inlineContent);
70
+ transformedItems.push(listItem.create(null, [paragraphNode]));
71
+ }
72
+ } else if (child.type === taskList) {
73
+ var transformedNestedList = _transformListRecursively(child);
74
+ var lastItem = transformedItems[transformedItems.length - 1];
75
+ if ((lastItem === null || lastItem === void 0 ? void 0 : lastItem.type) === listItem) {
76
+ // Attach nested list to previous item
77
+ var updatedContent = [].concat(_toConsumableArray(lastItem.content.content), [transformedNestedList]);
78
+ transformedItems[transformedItems.length - 1] = listItem.create(lastItem.attrs, updatedContent);
79
+ } else {
80
+ // No previous item, flatten nested items
81
+ transformedItems.push.apply(transformedItems, _toConsumableArray(transformedNestedList.content.content));
82
+ }
73
83
  }
74
84
  }
75
- }
76
- return false; // Don't traverse into children of list items
77
- });
78
- if (newListItems.length === 0) {
79
- return tr;
80
- }
81
-
82
- // Create new list with transformed items
83
- var newList = targetNodeType.create(null, newListItems);
84
-
85
- // Replace the entire list
86
- tr.replaceWith(listStart, listEnd, newList);
85
+ });
86
+ return targetNodeType.create(null, transformedItems);
87
+ };
88
+ var newList = _transformListRecursively(sourceList);
89
+ tr.replaceWith(listPos, listPos + sourceList.nodeSize, newList);
87
90
  return tr;
88
91
  } catch (_unused) {
89
92
  return tr;