@atlaskit/editor-plugin-block-menu 1.0.2 → 1.0.4

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 (37) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/cjs/editor-commands/formatNode.js +2 -2
  3. package/dist/cjs/editor-commands/transforms/container-transforms.js +60 -4
  4. package/dist/cjs/editor-commands/transforms/list/transformBetweenListTypes.js +69 -71
  5. package/dist/cjs/editor-commands/transforms/list/transformToTaskList.js +44 -0
  6. package/dist/cjs/editor-commands/transforms/list-transforms.js +40 -30
  7. package/dist/cjs/editor-commands/transforms/utils.js +16 -2
  8. package/dist/cjs/ui/block-menu-components.js +2 -1
  9. package/dist/es2019/editor-commands/formatNode.js +2 -2
  10. package/dist/es2019/editor-commands/transforms/container-transforms.js +64 -4
  11. package/dist/es2019/editor-commands/transforms/list/transformBetweenListTypes.js +73 -70
  12. package/dist/es2019/editor-commands/transforms/list/transformToTaskList.js +38 -0
  13. package/dist/es2019/editor-commands/transforms/list-transforms.js +38 -28
  14. package/dist/es2019/editor-commands/transforms/utils.js +15 -1
  15. package/dist/es2019/ui/block-menu-components.js +2 -1
  16. package/dist/esm/editor-commands/formatNode.js +2 -2
  17. package/dist/esm/editor-commands/transforms/container-transforms.js +60 -4
  18. package/dist/esm/editor-commands/transforms/list/transformBetweenListTypes.js +70 -71
  19. package/dist/esm/editor-commands/transforms/list/transformToTaskList.js +37 -0
  20. package/dist/esm/editor-commands/transforms/list-transforms.js +37 -27
  21. package/dist/esm/editor-commands/transforms/utils.js +15 -1
  22. package/dist/esm/ui/block-menu-components.js +2 -1
  23. package/dist/types/editor-commands/transforms/container-transforms.d.ts +1 -1
  24. package/dist/types/editor-commands/transforms/list/transformBetweenListTypes.d.ts +3 -7
  25. package/dist/types/editor-commands/transforms/list/transformToTaskList.d.ts +10 -0
  26. package/dist/types/editor-commands/transforms/list-transforms.d.ts +1 -1
  27. package/dist/types/editor-commands/transforms/transformNodeToTargetType.d.ts +1 -1
  28. package/dist/types/editor-commands/transforms/types.d.ts +1 -1
  29. package/dist/types/editor-commands/transforms/utils.d.ts +4 -0
  30. package/dist/types-ts4.5/editor-commands/transforms/container-transforms.d.ts +1 -1
  31. package/dist/types-ts4.5/editor-commands/transforms/list/transformBetweenListTypes.d.ts +3 -7
  32. package/dist/types-ts4.5/editor-commands/transforms/list/transformToTaskList.d.ts +10 -0
  33. package/dist/types-ts4.5/editor-commands/transforms/list-transforms.d.ts +1 -1
  34. package/dist/types-ts4.5/editor-commands/transforms/transformNodeToTargetType.d.ts +1 -1
  35. package/dist/types-ts4.5/editor-commands/transforms/types.d.ts +1 -1
  36. package/dist/types-ts4.5/editor-commands/transforms/utils.d.ts +4 -0
  37. package/package.json +6 -6
@@ -1,96 +1,99 @@
1
+ import { getSupportedListTypesSet, isBulletOrOrderedList, isTaskList } from '../utils';
2
+
1
3
  /**
2
- * Extract all inline content from a node
4
+ * Convert a block node to inline content suitable for task items
3
5
  */
4
- const extractInlineContent = node => {
5
- const inlineContent = [];
6
- for (let i = 0; i < node.childCount; i++) {
7
- inlineContent.push(node.child(i));
6
+ const convertBlockToInlineContent = (node, schema) => {
7
+ const {
8
+ paragraph
9
+ } = schema.nodes;
10
+ if (node.type === paragraph) {
11
+ return [...node.content.content];
12
+ }
13
+ if (node.isBlock) {
14
+ const textContent = node.textContent;
15
+ return textContent ? [schema.text(textContent)] : [];
8
16
  }
9
- return inlineContent;
17
+ return [node];
10
18
  };
11
19
 
12
20
  /**
13
- * Transform list structure
21
+ * Transform list structure between different list types
14
22
  */
15
- 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;
16
31
  try {
32
+ const listNode = {
33
+ node: sourceNode,
34
+ pos: sourcePos
35
+ };
17
36
  const {
18
37
  node: sourceList,
19
38
  pos: listPos
20
39
  } = listNode;
21
40
  const {
22
- bulletList,
23
- orderedList,
24
41
  taskList,
25
42
  listItem,
26
43
  taskItem,
27
44
  paragraph
28
45
  } = nodes;
29
- const isSourceBulletOrOrdered = sourceList.type === bulletList || sourceList.type === orderedList;
30
- const isTargetTask = targetNodeType === taskList;
31
- const isSourceTask = sourceList.type === taskList;
32
- const newListItems = [];
33
- const listStart = listPos;
34
- const listEnd = listPos + sourceList.nodeSize;
35
-
36
- // Use nodesBetween to efficiently traverse the list structure
37
- tr.doc.nodesBetween(listStart, listEnd, (node, pos, parent) => {
38
- // Only process direct children of the list (depth 1)
39
- if (parent !== sourceList) {
40
- return true; // Continue traversal
41
- }
42
- if (isSourceBulletOrOrdered && isTargetTask) {
43
- // Converting from bullet/ordered list to task list
44
- // Extract inline content from all children within listItem
45
- if (node.type === listItem) {
46
- const inlineContent = [];
47
-
48
- // Extract all inline content from all child nodes
49
- for (let i = 0; i < node.childCount; i++) {
50
- const child = node.child(i);
51
- if (child.type === paragraph) {
52
- // Extract inline content from paragraphs
53
- inlineContent.push(...extractInlineContent(child));
54
- } else if (child.isBlock) {
55
- // For other block content types eg. codeBlock, extract their text content and create text nodes
56
- const textContent = child.textContent;
57
- if (textContent) {
58
- const textNode = tr.doc.type.schema.text(textContent);
59
- inlineContent.push(textNode);
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));
60
64
  }
61
- } else {
62
- // Already inline content, add directly
63
- inlineContent.push(child);
65
+ });
66
+ if (inlineContent.length > 0) {
67
+ transformedItems.push(taskItem.create(null, inlineContent));
64
68
  }
69
+ transformedItems.push(...nestedTaskLists);
65
70
  }
66
- if (inlineContent.length > 0) {
67
- const newItem = taskItem.create(null, inlineContent);
68
- newListItems.push(newItem);
69
- }
70
- }
71
- } else if (isSourceTask && !isTargetTask) {
72
- // Converting from task list to bullet/ordered list
73
- // Structure: taskItem > inline content -> listItem > paragraph > inline content
74
- if (node.type === taskItem) {
75
- const inlineContent = extractInlineContent(node);
76
- if (inlineContent.length > 0) {
77
- const paragraphNode = paragraph.create(null, inlineContent);
78
- const newListItem = listItem.create(null, paragraphNode);
79
- 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
+ }
80
90
  }
81
91
  }
82
- }
83
- return false; // Don't traverse into children of list items
84
- });
85
- if (newListItems.length === 0) {
86
- return tr;
87
- }
88
-
89
- // Create new list with transformed items
90
- const newList = targetNodeType.create(null, newListItems);
91
-
92
- // Replace the entire list
93
- 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);
94
97
  return tr;
95
98
  } catch {
96
99
  return tr;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Transform selection to task list
3
+ * Handles the special structure where taskItem contains text directly (no paragraph wrapper)
4
+ */
5
+ export const transformToTaskList = (tr, range, targetNodeType, targetAttrs, nodes) => {
6
+ try {
7
+ const {
8
+ taskItem
9
+ } = nodes;
10
+ const listItems = [];
11
+
12
+ // Process each block in the range
13
+ tr.doc.nodesBetween(range.start, range.end, node => {
14
+ if (node.isBlock) {
15
+ // For block nodes like paragraphs, directly use their inline content
16
+ const inlineContent = [...node.content.content];
17
+ if (inlineContent.length > 0) {
18
+ // Create task item with inline content directly
19
+ const listItem = taskItem.create(targetAttrs, inlineContent);
20
+ listItems.push(listItem);
21
+ }
22
+ }
23
+ return false; // Don't traverse into children
24
+ });
25
+ if (listItems.length === 0) {
26
+ return null;
27
+ }
28
+
29
+ // Create the new task list
30
+ const newList = targetNodeType.create(targetAttrs, listItems);
31
+
32
+ // Replace the range with the new list
33
+ tr.replaceWith(range.start, range.end, newList);
34
+ return tr;
35
+ } catch {
36
+ return null;
37
+ }
38
+ };
@@ -1,9 +1,9 @@
1
1
  import { findWrapping } from '@atlaskit/editor-prosemirror/transform';
2
- import { findParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
3
2
  import { transformListStructure } from './list/transformBetweenListTypes';
4
3
  import { transformOrderedUnorderedListToBlockNodes } from './list/transformOrderedUnorderedListToBlockNodes';
5
4
  import { transformTaskListToBlockNodes } from './list/transformTaskListToBlockNodes';
6
- import { isBlockNodeType, isContainerNodeType, isListNodeType } from './utils';
5
+ import { transformToTaskList } from './list/transformToTaskList';
6
+ import { getSupportedListTypesSet, isBulletOrOrderedList, isBlockNodeType, isContainerNodeType, isListNodeType, isTaskList } from './utils';
7
7
 
8
8
  /**
9
9
  * Transform selection to list type
@@ -11,6 +11,7 @@ import { isBlockNodeType, isContainerNodeType, isListNodeType } from './utils';
11
11
  export const transformBlockToList = context => {
12
12
  const {
13
13
  tr,
14
+ sourceNode,
14
15
  targetNodeType,
15
16
  targetAttrs
16
17
  } = context;
@@ -25,16 +26,14 @@ export const transformBlockToList = context => {
25
26
  const {
26
27
  nodes
27
28
  } = tr.doc.type.schema;
28
- const isTargetTask = targetNodeType === nodes.taskList;
29
+ const isTargetTask = isTaskList(targetNodeType);
29
30
 
30
31
  // Handle task lists differently due to their structure
31
- // TODO: ED-29152 - Implement task list transformation
32
32
  if (isTargetTask) {
33
- return null;
33
+ return transformToTaskList(tr, range, targetNodeType, targetAttrs, nodes);
34
34
  }
35
35
 
36
36
  // For headings, convert to paragraph first since headings cannot be direct children of list items
37
- const sourceNode = tr.doc.nodeAt(range.start);
38
37
  if (sourceNode && sourceNode.type.name.startsWith('heading')) {
39
38
  tr.setBlockType(range.start, range.end, nodes.paragraph);
40
39
  }
@@ -102,41 +101,52 @@ export const liftListToBlockType = () => {
102
101
  /**
103
102
  * Transform between different list types
104
103
  */
105
- export const transformBetweenListTypes = ({
106
- tr,
107
- targetNodeType
108
- }) => {
104
+ export const transformBetweenListTypes = context => {
109
105
  const {
110
- selection
111
- } = tr;
106
+ tr,
107
+ sourceNode,
108
+ sourcePos,
109
+ targetNodeType
110
+ } = context;
112
111
  const {
113
112
  nodes
114
113
  } = 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;
114
+ const sourceListType = sourceNode.type;
115
+ const isSourceBulletOrOrdered = isBulletOrOrderedList(sourceListType);
116
+ const isTargetTask = isTaskList(targetNodeType);
117
+ const isSourceTask = isTaskList(sourceListType);
118
+ const isTargetBulletOrOrdered = isBulletOrOrderedList(targetNodeType);
128
119
 
129
120
  // Check if we need structure transformation
130
121
  const needsStructureTransform = isSourceBulletOrOrdered && isTargetTask || isSourceTask && isTargetBulletOrOrdered;
131
122
  try {
132
123
  if (!needsStructureTransform) {
133
124
  // Simple type change for same structure lists (bullet <-> ordered)
134
- tr.setNodeMarkup(listNode.pos, targetNodeType);
125
+ // Apply to the main list
126
+ tr.setNodeMarkup(sourcePos, targetNodeType);
127
+
128
+ // Apply to nested lists
129
+ const listStart = sourcePos;
130
+ const listEnd = sourcePos + sourceNode.nodeSize;
131
+ const supportedListTypesSet = getSupportedListTypesSet(nodes);
132
+ tr.doc.nodesBetween(listStart, listEnd, (node, pos, parent) => {
133
+ // Only process nested lists (not the root list we already handled)
134
+ if (supportedListTypesSet.has(node.type) && pos !== sourcePos) {
135
+ const isNestedList = parent && (supportedListTypesSet.has(parent.type) || parent.type === nodes.listItem);
136
+ if (isNestedList) {
137
+ const shouldTransformNode = node.type === sourceListType || isBulletOrOrderedList(node.type) && isTargetBulletOrOrdered;
138
+ if (shouldTransformNode) {
139
+ tr.setNodeMarkup(pos, targetNodeType);
140
+ }
141
+ }
142
+ }
143
+ return true; // Continue traversing
144
+ });
145
+ return tr;
135
146
  } else {
136
- tr = transformListStructure(tr, listNode, targetNodeType, nodes);
147
+ return transformListStructure(context);
137
148
  }
138
149
  } catch {
139
150
  return null;
140
151
  }
141
- return tr;
142
152
  };
@@ -87,7 +87,7 @@ export const isBlockNode = node => {
87
87
  return ['paragraph', 'heading', 'codeBlock'].includes(node.type.name);
88
88
  };
89
89
  export const isListNode = node => {
90
- return ['bulletList', 'orderedList', 'taskList', 'listItem'].includes(node.type.name);
90
+ return ['bulletList', 'orderedList', 'taskList'].includes(node.type.name);
91
91
  };
92
92
  export const isContainerNode = node => {
93
93
  return ['panel', 'expand', 'blockquote'].includes(node.type.name);
@@ -100,4 +100,18 @@ export const isListNodeType = nodeType => {
100
100
  };
101
101
  export const isContainerNodeType = nodeType => {
102
102
  return ['panel', 'expand', 'blockquote'].includes(nodeType.name);
103
+ };
104
+
105
+ // List type utilities
106
+ export const isBulletOrOrderedList = nodeType => {
107
+ return nodeType.name === 'bulletList' || nodeType.name === 'orderedList';
108
+ };
109
+ export const isTaskList = nodeType => {
110
+ return nodeType.name === 'taskList';
111
+ };
112
+ export const getSupportedListTypes = nodes => {
113
+ return [nodes.bulletList, nodes.orderedList, nodes.taskList].filter(Boolean);
114
+ };
115
+ export const getSupportedListTypesSet = nodes => {
116
+ return new Set(getSupportedListTypes(nodes));
103
117
  };
@@ -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);
@@ -34,7 +34,7 @@ export var formatNode = function formatNode(targetType) {
34
34
  nodeToFormat = listParent.node;
35
35
  nodePos = listParent.pos;
36
36
  }
37
- } else if (paragraphOrHeadingNode) {
37
+ } else if (parentNode.node.type !== nodes.blockquote && paragraphOrHeadingNode) {
38
38
  nodeToFormat = paragraphOrHeadingNode.node;
39
39
  nodePos = paragraphOrHeadingNode.pos;
40
40
  }
@@ -44,6 +44,7 @@ export var transformToContainer = function transformToContainer(_ref) {
44
44
  */
45
45
  export var transformContainerNode = function transformContainerNode(_ref2) {
46
46
  var tr = _ref2.tr,
47
+ sourceNode = _ref2.sourceNode,
47
48
  sourcePos = _ref2.sourcePos,
48
49
  targetNodeType = _ref2.targetNodeType,
49
50
  targetAttrs = _ref2.targetAttrs;
@@ -58,7 +59,13 @@ export var transformContainerNode = function transformContainerNode(_ref2) {
58
59
 
59
60
  // Transform container to list type
60
61
  if (isListNodeType(targetNodeType)) {
61
- return unwrapAndConvertToList();
62
+ return unwrapAndConvertToList({
63
+ tr: tr,
64
+ sourceNode: sourceNode,
65
+ sourcePos: sourcePos,
66
+ targetNodeType: targetNodeType,
67
+ targetAttrs: targetAttrs
68
+ });
62
69
  }
63
70
 
64
71
  // Transform between container types
@@ -80,7 +87,56 @@ export var unwrapAndConvertToBlockType = function unwrapAndConvertToBlockType()
80
87
  /**
81
88
  * Unwrap container node and convert content to list
82
89
  */
83
- export var unwrapAndConvertToList = function unwrapAndConvertToList() {
84
- // Convert to list directly
85
- return null;
90
+ export var unwrapAndConvertToList = function unwrapAndConvertToList(_ref3) {
91
+ var tr = _ref3.tr,
92
+ sourceNode = _ref3.sourceNode,
93
+ sourcePos = _ref3.sourcePos,
94
+ targetNodeType = _ref3.targetNodeType,
95
+ targetAttrs = _ref3.targetAttrs;
96
+ if (sourcePos === null) {
97
+ return tr;
98
+ }
99
+ var schema = tr.doc.type.schema;
100
+ var _schema$nodes = schema.nodes,
101
+ listItem = _schema$nodes.listItem,
102
+ paragraph = _schema$nodes.paragraph,
103
+ taskList = _schema$nodes.taskList,
104
+ taskItem = _schema$nodes.taskItem;
105
+ var isTargetTaskList = targetNodeType === taskList;
106
+ var createListItemFromInline = function createListItemFromInline(inlineFrag) {
107
+ return isTargetTaskList ? taskItem.create(null, inlineFrag) : listItem.create(null, paragraph.create(null, inlineFrag));
108
+ };
109
+ var getInlineContent = function getInlineContent(textblock) {
110
+ var inlineContent = [];
111
+ textblock.forEach(function (inline) {
112
+ inlineContent.push(inline);
113
+ });
114
+ return inlineContent;
115
+ };
116
+ var items = [];
117
+
118
+ // Expand's title should become the first item of the list
119
+ if (sourceNode.type.name === 'expand') {
120
+ var _sourceNode$attrs;
121
+ var title = (_sourceNode$attrs = sourceNode.attrs) === null || _sourceNode$attrs === void 0 ? void 0 : _sourceNode$attrs.title;
122
+ if (title) {
123
+ var titleContent = schema.text(title);
124
+ items.push(isTargetTaskList ? taskItem.create(null, titleContent) : listItem.create(null, paragraph.create(null, titleContent)));
125
+ }
126
+ }
127
+ for (var i = 0; i < sourceNode.childCount; i++) {
128
+ var node = sourceNode.child(i);
129
+
130
+ // Abort early if unsupported content (e.g. table) encounted inside of the container
131
+ if (!node.isTextblock) {
132
+ return tr;
133
+ }
134
+ var inline = Fragment.from(getInlineContent(node));
135
+ items.push(createListItemFromInline(inline));
136
+ }
137
+ if (!items.length) {
138
+ return tr;
139
+ }
140
+ var list = targetNodeType.create(targetAttrs || null, Fragment.from(items));
141
+ return tr.replaceWith(sourcePos, sourcePos + sourceNode.nodeSize, list);
86
142
  };
@@ -1,93 +1,92 @@
1
1
  import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
+ import { getSupportedListTypesSet, isBulletOrOrderedList, isTaskList } from '../utils';
3
+
2
4
  /**
3
- * Extract all inline content from a node
5
+ * Convert a block node to inline content suitable for task items
4
6
  */
5
- var extractInlineContent = function extractInlineContent(node) {
6
- var inlineContent = [];
7
- for (var i = 0; i < node.childCount; i++) {
8
- inlineContent.push(node.child(i));
7
+ var convertBlockToInlineContent = function convertBlockToInlineContent(node, schema) {
8
+ var paragraph = schema.nodes.paragraph;
9
+ if (node.type === paragraph) {
10
+ return _toConsumableArray(node.content.content);
11
+ }
12
+ if (node.isBlock) {
13
+ var textContent = node.textContent;
14
+ return textContent ? [schema.text(textContent)] : [];
9
15
  }
10
- return inlineContent;
16
+ return [node];
11
17
  };
12
18
 
13
19
  /**
14
- * Transform list structure
20
+ * Transform list structure between different list types
15
21
  */
16
- 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;
17
28
  try {
29
+ var listNode = {
30
+ node: sourceNode,
31
+ pos: sourcePos
32
+ };
18
33
  var sourceList = listNode.node,
19
34
  listPos = listNode.pos;
20
- var bulletList = nodes.bulletList,
21
- orderedList = nodes.orderedList,
22
- taskList = nodes.taskList,
35
+ var taskList = nodes.taskList,
23
36
  listItem = nodes.listItem,
24
37
  taskItem = nodes.taskItem,
25
38
  paragraph = nodes.paragraph;
26
- var isSourceBulletOrOrdered = sourceList.type === bulletList || sourceList.type === orderedList;
27
- var isTargetTask = targetNodeType === taskList;
28
- var isSourceTask = sourceList.type === taskList;
29
- var newListItems = [];
30
- var listStart = listPos;
31
- var listEnd = listPos + sourceList.nodeSize;
32
-
33
- // Use nodesBetween to efficiently traverse the list structure
34
- tr.doc.nodesBetween(listStart, listEnd, function (node, pos, parent) {
35
- // Only process direct children of the list (depth 1)
36
- if (parent !== sourceList) {
37
- return true; // Continue traversal
38
- }
39
- if (isSourceBulletOrOrdered && isTargetTask) {
40
- // Converting from bullet/ordered list to task list
41
- // Extract inline content from all children within listItem
42
- if (node.type === listItem) {
43
- var inlineContent = [];
44
-
45
- // Extract all inline content from all child nodes
46
- for (var i = 0; i < node.childCount; i++) {
47
- var child = node.child(i);
48
- if (child.type === paragraph) {
49
- // Extract inline content from paragraphs
50
- inlineContent.push.apply(inlineContent, _toConsumableArray(extractInlineContent(child)));
51
- } else if (child.isBlock) {
52
- // For other block content types eg. codeBlock, extract their text content and create text nodes
53
- var textContent = child.textContent;
54
- if (textContent) {
55
- var textNode = tr.doc.type.schema.text(textContent);
56
- inlineContent.push(textNode);
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
57
  }
58
- } else {
59
- // Already inline content, add directly
60
- inlineContent.push(child);
58
+ });
59
+ if (inlineContent.length > 0) {
60
+ transformedItems.push(taskItem.create(null, inlineContent));
61
61
  }
62
+ transformedItems.push.apply(transformedItems, nestedTaskLists);
62
63
  }
63
- if (inlineContent.length > 0) {
64
- var newItem = taskItem.create(null, inlineContent);
65
- newListItems.push(newItem);
66
- }
67
- }
68
- } else if (isSourceTask && !isTargetTask) {
69
- // Converting from task list to bullet/ordered list
70
- // Structure: taskItem > inline content -> listItem > paragraph > inline content
71
- if (node.type === taskItem) {
72
- var _inlineContent = extractInlineContent(node);
73
- if (_inlineContent.length > 0) {
74
- var paragraphNode = paragraph.create(null, _inlineContent);
75
- var newListItem = listItem.create(null, paragraphNode);
76
- 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
+ }
77
83
  }
78
84
  }
79
- }
80
- return false; // Don't traverse into children of list items
81
- });
82
- if (newListItems.length === 0) {
83
- return tr;
84
- }
85
-
86
- // Create new list with transformed items
87
- var newList = targetNodeType.create(null, newListItems);
88
-
89
- // Replace the entire list
90
- 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);
91
90
  return tr;
92
91
  } catch (_unused) {
93
92
  return tr;