@atlaskit/editor-plugin-block-menu 1.0.11 → 1.0.13

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 (39) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/cjs/editor-commands/transforms/block-transforms.js +1 -1
  3. package/dist/cjs/editor-commands/transforms/container-transforms.js +8 -25
  4. package/dist/cjs/editor-commands/transforms/inline-node-transforms.js +9 -7
  5. package/dist/cjs/editor-commands/transforms/layout/utils.js +289 -0
  6. package/dist/cjs/editor-commands/transforms/layout-transforms.js +40 -2
  7. package/dist/cjs/editor-commands/transforms/list/transformBetweenListTypes.js +92 -50
  8. package/dist/cjs/editor-commands/transforms/list-transforms.js +7 -0
  9. package/dist/cjs/editor-commands/transforms/transformNodeToTargetType.js +3 -0
  10. package/dist/cjs/editor-commands/transforms/utils.js +40 -1
  11. package/dist/es2019/editor-commands/transforms/block-transforms.js +2 -2
  12. package/dist/es2019/editor-commands/transforms/container-transforms.js +8 -23
  13. package/dist/es2019/editor-commands/transforms/inline-node-transforms.js +8 -6
  14. package/dist/es2019/editor-commands/transforms/layout/utils.js +272 -0
  15. package/dist/es2019/editor-commands/transforms/layout-transforms.js +40 -1
  16. package/dist/es2019/editor-commands/transforms/list/transformBetweenListTypes.js +94 -51
  17. package/dist/es2019/editor-commands/transforms/list-transforms.js +7 -0
  18. package/dist/es2019/editor-commands/transforms/transformNodeToTargetType.js +5 -2
  19. package/dist/es2019/editor-commands/transforms/utils.js +39 -0
  20. package/dist/esm/editor-commands/transforms/block-transforms.js +2 -2
  21. package/dist/esm/editor-commands/transforms/container-transforms.js +8 -25
  22. package/dist/esm/editor-commands/transforms/inline-node-transforms.js +8 -6
  23. package/dist/esm/editor-commands/transforms/layout/utils.js +282 -0
  24. package/dist/esm/editor-commands/transforms/layout-transforms.js +38 -1
  25. package/dist/esm/editor-commands/transforms/list/transformBetweenListTypes.js +92 -49
  26. package/dist/esm/editor-commands/transforms/list-transforms.js +7 -0
  27. package/dist/esm/editor-commands/transforms/transformNodeToTargetType.js +5 -2
  28. package/dist/esm/editor-commands/transforms/utils.js +39 -0
  29. package/dist/types/editor-commands/transforms/inline-node-transforms.d.ts +3 -3
  30. package/dist/types/editor-commands/transforms/layout/utils.d.ts +5 -0
  31. package/dist/types/editor-commands/transforms/layout-transforms.d.ts +1 -0
  32. package/dist/types/editor-commands/transforms/list/transformBetweenListTypes.d.ts +13 -0
  33. package/dist/types/editor-commands/transforms/utils.d.ts +13 -0
  34. package/dist/types-ts4.5/editor-commands/transforms/inline-node-transforms.d.ts +3 -3
  35. package/dist/types-ts4.5/editor-commands/transforms/layout/utils.d.ts +5 -0
  36. package/dist/types-ts4.5/editor-commands/transforms/layout-transforms.d.ts +1 -0
  37. package/dist/types-ts4.5/editor-commands/transforms/list/transformBetweenListTypes.d.ts +13 -0
  38. package/dist/types-ts4.5/editor-commands/transforms/utils.d.ts +13 -0
  39. package/package.json +2 -2
@@ -52,6 +52,9 @@ function transformNodeToTargetType(tr, sourceNode, sourcePos, targetType) {
52
52
  if (sourceNode.type.name === 'codeBlock' && (0, _utils.isListNodeType)(targetNodeType)) {
53
53
  return (0, _containerTransforms.unwrapAndConvertToList)(transformationContext);
54
54
  }
55
+ if ((0, _utils.isLayoutNode)(sourceNode)) {
56
+ return (0, _layoutTransforms.transformLayoutNode)(transformationContext);
57
+ }
55
58
  if ((0, _utils.isBlockNode)(sourceNode)) {
56
59
  return (0, _blockTransforms.transformBlockNode)(transformationContext);
57
60
  }
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.isTaskList = exports.isListNodeType = exports.isListNode = exports.isLayoutNodeType = exports.isContainerNodeType = exports.isContainerNode = exports.isBulletOrOrderedList = exports.isBlockNodeType = exports.isBlockNodeForExtraction = exports.isBlockNode = exports.getTargetNodeInfo = exports.getSupportedListTypesSet = exports.getSupportedListTypes = exports.getContentSupportChecker = exports.convertNodeToInlineContent = void 0;
6
+ exports.isTaskList = exports.isListNodeType = exports.isListNode = exports.isLayoutNodeType = exports.isLayoutNode = exports.isHeadingOrParagraphNode = exports.isContainerNodeType = exports.isContainerNode = exports.isBulletOrOrderedList = exports.isBlockNodeType = exports.isBlockNodeForExtraction = exports.isBlockNode = exports.getTargetNodeInfo = exports.getSupportedListTypesSet = exports.getSupportedListTypes = exports.getContentSupportChecker = exports.filterMarksForTargetNodeType = exports.convertNodeToInlineContent = exports.convertCodeBlockContentToParagraphs = void 0;
7
7
  var _model = require("@atlaskit/editor-prosemirror/model");
8
8
  var getTargetNodeInfo = exports.getTargetNodeInfo = function getTargetNodeInfo(targetType, nodes) {
9
9
  switch (targetType) {
@@ -97,6 +97,9 @@ var getTargetNodeInfo = exports.getTargetNodeInfo = function getTargetNodeInfo(t
97
97
  var isBlockNode = exports.isBlockNode = function isBlockNode(node) {
98
98
  return ['paragraph', 'heading', 'codeBlock'].includes(node.type.name);
99
99
  };
100
+ var isHeadingOrParagraphNode = exports.isHeadingOrParagraphNode = function isHeadingOrParagraphNode(node) {
101
+ return ['paragraph', 'heading'].includes(node.type.name);
102
+ };
100
103
  var isListNode = exports.isListNode = function isListNode(node) {
101
104
  return ['bulletList', 'orderedList', 'taskList'].includes(node.type.name);
102
105
  };
@@ -129,6 +132,9 @@ var getSupportedListTypesSet = exports.getSupportedListTypesSet = function getSu
129
132
  var isLayoutNodeType = exports.isLayoutNodeType = function isLayoutNodeType(nodeType) {
130
133
  return nodeType.name === 'layoutSection';
131
134
  };
135
+ var isLayoutNode = exports.isLayoutNode = function isLayoutNode(node) {
136
+ return node.type.name === 'layoutSection';
137
+ };
132
138
 
133
139
  /**
134
140
  * Check if a node should be extracted as a standalone block node
@@ -174,4 +180,37 @@ var convertNodeToInlineContent = exports.convertNodeToInlineContent = function c
174
180
  return [schema.text(node.textContent)];
175
181
  }
176
182
  return inlineNodes;
183
+ };
184
+
185
+ /**
186
+ * Filter marks from content based on the target node type
187
+ * @param content The content fragment to filter
188
+ * @param targetNodeType The target node type to check against
189
+ * @returns A new fragment with marks filtered for the target node type
190
+ */
191
+ var filterMarksForTargetNodeType = exports.filterMarksForTargetNodeType = function filterMarksForTargetNodeType(content, targetNodeType) {
192
+ var withValidMarks = [];
193
+ content.forEach(function (node) {
194
+ if (node.marks.length > 0) {
195
+ var allowedMarks = targetNodeType.allowedMarks(node.marks);
196
+ var updatedNode = node.mark(allowedMarks);
197
+ withValidMarks.push(updatedNode);
198
+ } else {
199
+ withValidMarks.push(node);
200
+ }
201
+ });
202
+ return _model.Fragment.from(withValidMarks);
203
+ };
204
+
205
+ /** * Convert content from a code block node into multiple paragraph nodes
206
+ */
207
+ var convertCodeBlockContentToParagraphs = exports.convertCodeBlockContentToParagraphs = function convertCodeBlockContentToParagraphs(codeBlockNode, schema) {
208
+ var paragraphNodes = [];
209
+ var codeText = codeBlockNode.textContent;
210
+ var lines = codeText.split('\n');
211
+ lines.forEach(function (line) {
212
+ var paragraphNode = schema.nodes.paragraph.create(null, line ? schema.text(line) : null);
213
+ paragraphNodes.push(paragraphNode);
214
+ });
215
+ return paragraphNodes;
177
216
  };
@@ -1,5 +1,5 @@
1
1
  import { transformToContainer, unwrapAndConvertToBlockType } from './container-transforms';
2
- import { getInlineNodeTextContent } from './inline-node-transforms';
2
+ import { getInlineNodeTextNode } from './inline-node-transforms';
3
3
  import { transformBlockToList } from './list-transforms';
4
4
  import { isListNodeType, isContainerNodeType, isBlockNodeType } from './utils';
5
5
 
@@ -44,7 +44,7 @@ const transformToBlockNode = context => {
44
44
  } = selection;
45
45
  const schema = doc.type.schema;
46
46
  if (targetNodeType === schema.nodes.codeBlock) {
47
- const textContent = getInlineNodeTextContent(selection.content().content, tr);
47
+ const textContent = getInlineNodeTextNode(selection.content().content, schema);
48
48
  const node = schema.nodes.codeBlock.createChecked(undefined, textContent);
49
49
  return tr.replaceRangeWith(selection.from, selection.to, node);
50
50
  }
@@ -1,5 +1,5 @@
1
1
  import { Fragment, Slice } from '@atlaskit/editor-prosemirror/model';
2
- import { isBlockNodeType, isListNodeType, isContainerNodeType, isBlockNodeForExtraction, convertNodeToInlineContent, getContentSupportChecker } from './utils';
2
+ import { isBlockNodeType, isListNodeType, isContainerNodeType, isBlockNodeForExtraction, convertNodeToInlineContent, getContentSupportChecker, convertCodeBlockContentToParagraphs, filterMarksForTargetNodeType } from './utils';
3
3
  const convertInvalidNodeToValidNodeType = (sourceContent, sourceNodeType, validNodeType, withMarks) => {
4
4
  const validTransformedContent = [];
5
5
  // Headings are not valid inside headings so convert heading nodes to paragraphs
@@ -12,19 +12,6 @@ const convertInvalidNodeToValidNodeType = (sourceContent, sourceNodeType, validN
12
12
  });
13
13
  return Fragment.from(validTransformedContent);
14
14
  };
15
- const filterMarksForTargetNodeType = (content, targetNodeType) => {
16
- const withValidMarks = [];
17
- content.forEach(node => {
18
- if (node.marks.length > 0) {
19
- const allowedMarks = targetNodeType.allowedMarks(node.marks);
20
- const updatedNode = node.mark(allowedMarks);
21
- withValidMarks.push(updatedNode);
22
- } else {
23
- withValidMarks.push(node);
24
- }
25
- });
26
- return Fragment.from(withValidMarks);
27
- };
28
15
 
29
16
  /**
30
17
  * Transform selection to container type
@@ -40,7 +27,8 @@ export const transformToContainer = ({
40
27
  const content = selection.content().content;
41
28
  let transformedContent = content;
42
29
  if (sourceNode.type === schema.nodes.codeBlock) {
43
- transformedContent = convertInvalidNodeToValidNodeType(transformedContent, schema.nodes.codeBlock, schema.nodes.paragraph);
30
+ const paragraphNodes = convertCodeBlockContentToParagraphs(sourceNode, schema);
31
+ transformedContent = Fragment.fromArray(paragraphNodes);
44
32
  }
45
33
  if (targetNodeType === schema.nodes.blockquote) {
46
34
  transformedContent = convertInvalidNodeToValidNodeType(transformedContent, schema.nodes.heading, schema.nodes.paragraph, true);
@@ -157,10 +145,7 @@ export const unwrapAndConvertToBlockType = context => {
157
145
 
158
146
  // if the container is a code block, convert text content to multiple paragraphs
159
147
  if (sourceNode.type === codeBlock) {
160
- const codeText = sourceNode.textContent;
161
- const lines = codeText.split('\n');
162
- const paragraphNodes = lines.map(line => paragraph.create(null, line ? schema.text(line) : null));
163
- sourceChildren = paragraphNodes;
148
+ sourceChildren = convertCodeBlockContentToParagraphs(sourceNode, schema);
164
149
  }
165
150
 
166
151
  // if target node is a paragraph, just do unwrap
@@ -399,15 +384,15 @@ const splitContentAroundUnsupportedBlocks = (sourceNode, isContentSupported, tar
399
384
  if (isContentSupported(childNode)) {
400
385
  // Supported content - add to current container
401
386
  currentContainerContent.push(childNode);
402
- } else if (isBlockNodeForExtraction(childNode)) {
403
- // Unsupported block node - flush current container, add block, continue
404
- flushCurrentContainer();
405
- splits.push(childNode);
406
387
  } else if (childNode.type.name === targetNodeType.name) {
407
388
  // Same type of container merge contents
408
389
  childNode.content.forEach(child => {
409
390
  currentContainerContent.push(child);
410
391
  });
392
+ } else if (childNode.isBlock) {
393
+ // Unsupported block node - flush current container, add block, continue
394
+ flushCurrentContainer();
395
+ splits.push(childNode);
411
396
  } else {
412
397
  // Unsupported inline content - convert to paragraph and add to container
413
398
  const inlineContent = convertNodeToInlineContent(childNode, schema);
@@ -1,8 +1,7 @@
1
- export const getInlineNodeTextContent = (sourceContent, tr) => {
1
+ export const getInlineNodeTextContent = sourceContent => {
2
2
  let validTransformedContent = '';
3
- const schema = tr.doc.type.schema;
4
- if (sourceContent.content.length > 1) {
5
- return;
3
+ if (sourceContent.content.length < 1) {
4
+ return '';
6
5
  }
7
6
  // Headings are not valid inside headings so convert heading nodes to paragraphs
8
7
  sourceContent.forEach(node => {
@@ -14,8 +13,11 @@ export const getInlineNodeTextContent = (sourceContent, tr) => {
14
13
  validTransformedContent += `${inlineNode.textContent}`;
15
14
  }
16
15
  });
17
- validTransformedContent;
18
16
  }
19
17
  });
20
- return schema.text(validTransformedContent);
18
+ return validTransformedContent;
19
+ };
20
+ export const getInlineNodeTextNode = (sourceContent, schema) => {
21
+ const text = getInlineNodeTextContent(sourceContent);
22
+ return schema.text(text);
21
23
  };
@@ -0,0 +1,272 @@
1
+ import { Fragment } from '@atlaskit/editor-prosemirror/model';
2
+ import { findChildrenByType } from '@atlaskit/editor-prosemirror/utils';
3
+ import { getInlineNodeTextContent } from '../inline-node-transforms';
4
+ import { transformListRecursively } from '../list/transformBetweenListTypes';
5
+ import { getContentSupportChecker, getSupportedListTypesSet, isBlockNode, isBlockNodeForExtraction, isBlockNodeType, isBulletOrOrderedList, isContainerNode, isContainerNodeType, isHeadingOrParagraphNode, isListNode, isListNodeType, isTaskList } from '../utils';
6
+ export const unwrapLayoutNodesToTextNodes = (context, finalTargetNodeType) => {
7
+ const {
8
+ tr,
9
+ sourceNode,
10
+ targetNodeType,
11
+ targetAttrs
12
+ } = context;
13
+ const schema = tr.doc.type.schema || {};
14
+ const isValid = getContentSupportChecker(finalTargetNodeType);
15
+ const createTextNode = node => {
16
+ const isTextNode = node.type.name === 'text';
17
+ if (isValid(node) && !isTextNode) {
18
+ return node;
19
+ }
20
+ return targetNodeType.createChecked(targetAttrs, isTextNode ? node : node.content, node.marks);
21
+ };
22
+ if (isBlockNode(sourceNode)) {
23
+ // code block acts like a container, we need to unwrap it
24
+ if (sourceNode.type === schema.nodes.codeBlock) {
25
+ const textNodes = sourceNode.textContent.split('\n').map(line => targetNodeType.createChecked(undefined, line ? schema.text(line) : null));
26
+ return textNodes;
27
+ }
28
+ return [createTextNode(sourceNode)];
29
+ }
30
+ if (isContainerNode(sourceNode)) {
31
+ var _sourceNode$attrs;
32
+ const containerNodes = [];
33
+ if (sourceNode.type.name === 'expand' && (_sourceNode$attrs = sourceNode.attrs) !== null && _sourceNode$attrs !== void 0 && _sourceNode$attrs.title) {
34
+ containerNodes.push(createTextNode(schema.text(sourceNode.attrs.title)));
35
+ }
36
+ sourceNode.content.forEach(childNode => {
37
+ if (isHeadingOrParagraphNode(childNode)) {
38
+ containerNodes.push(createTextNode(childNode));
39
+ return;
40
+ }
41
+ containerNodes.push(childNode);
42
+ });
43
+ return containerNodes;
44
+ }
45
+ if (isListNode(sourceNode)) {
46
+ if (isBlockNodeType(finalTargetNodeType)) {
47
+ if (sourceNode.type.name === 'taskList') {
48
+ const taskItemsResult = findChildrenByType(sourceNode, schema.nodes.taskItem);
49
+ const taskItems = taskItemsResult.map(item => item.node);
50
+ const taskItemFragments = taskItems.map(taskItem => taskItem.content);
51
+ return taskItemFragments.map(fragment => targetNodeType.createChecked(targetAttrs, fragment.content));
52
+ } else {
53
+ const paragraphs = findChildrenByType(sourceNode, schema.nodes.paragraph);
54
+ const paragraphNodes = paragraphs.map(paragraph => paragraph.node);
55
+ if (targetNodeType === schema.nodes.heading) {
56
+ return paragraphNodes.map(paragraphNode => targetNodeType.createChecked(targetAttrs, paragraphNode.content));
57
+ }
58
+ return paragraphNodes;
59
+ }
60
+ }
61
+ return [sourceNode];
62
+ }
63
+ return [sourceNode];
64
+ };
65
+ const transformToBlockNode = (nodes, targetNodeType, schema) => {
66
+ if (targetNodeType === schema.nodes.codeBlock) {
67
+ const newNodes = [];
68
+ nodes.forEach(node => {
69
+ if (node.isTextblock) {
70
+ const inlineTextContent = node.type === schema.nodes.codeBlock ? node.textContent : getInlineNodeTextContent(Fragment.from(node));
71
+
72
+ // For first node, add directly
73
+ if (newNodes.length === 0) {
74
+ newNodes.push({
75
+ canBeTransformed: true,
76
+ content: [inlineTextContent]
77
+ });
78
+ } else {
79
+ // Check if last node can also be transformed, if yes then append content
80
+ const lastItem = newNodes[newNodes.length - 1];
81
+ if (lastItem.canBeTransformed) {
82
+ newNodes[newNodes.length - 1] = {
83
+ content: [...lastItem.content, inlineTextContent],
84
+ canBeTransformed: true
85
+ };
86
+ } else {
87
+ newNodes.push({
88
+ content: [inlineTextContent],
89
+ canBeTransformed: true
90
+ });
91
+ }
92
+ }
93
+ } else {
94
+ // If not text block, then cannot be transformed
95
+ newNodes.push({
96
+ canBeTransformed: false,
97
+ content: node
98
+ });
99
+ }
100
+ });
101
+ return newNodes.map(({
102
+ canBeTransformed,
103
+ content
104
+ }) => {
105
+ if (canBeTransformed) {
106
+ const text = content.join('\n');
107
+ if (text === '') {
108
+ return undefined;
109
+ }
110
+ return targetNodeType.createChecked(null, schema.text(text));
111
+ } else {
112
+ return content;
113
+ }
114
+ }).filter(Boolean);
115
+ }
116
+ return nodes;
117
+ };
118
+ const transformToContainerNode = (nodes, targetNodeType) => {
119
+ const newNodes = [];
120
+ const isNodeValid = getContentSupportChecker(targetNodeType);
121
+ nodes.forEach(node => {
122
+ // If the node is not supported then we append as is
123
+ if (isBlockNodeForExtraction(node)) {
124
+ newNodes.push({
125
+ node: node,
126
+ canBeTransformed: false
127
+ });
128
+ } else {
129
+ // Remove alignment marks as container nodes don't support them
130
+ const nodeWithValidAttrs = node.mark(node.marks.filter(mark => mark.type.name !== 'alignment'));
131
+ const isSameNodeType = node.type === targetNodeType;
132
+
133
+ // If the node is not valid and not the same type, we cannot transform it
134
+ if (!isNodeValid(nodeWithValidAttrs) && !isSameNodeType) {
135
+ newNodes.push({
136
+ node: node,
137
+ canBeTransformed: false
138
+ });
139
+ return;
140
+ }
141
+ const nodes = isSameNodeType ? node.content.content : [nodeWithValidAttrs];
142
+ if (newNodes.length === 0) {
143
+ newNodes.push({
144
+ node: nodes,
145
+ canBeTransformed: true
146
+ });
147
+ } else {
148
+ const lastItem = newNodes[newNodes.length - 1];
149
+ if (lastItem.canBeTransformed) {
150
+ newNodes[newNodes.length - 1] = {
151
+ node: [...lastItem.node, ...nodes],
152
+ canBeTransformed: true
153
+ };
154
+ } else {
155
+ newNodes.push({
156
+ node: nodes,
157
+ canBeTransformed: true
158
+ });
159
+ }
160
+ }
161
+ }
162
+ });
163
+ return newNodes.map(({
164
+ node,
165
+ canBeTransformed
166
+ }) => {
167
+ if (canBeTransformed) {
168
+ return targetNodeType.createChecked(null, Fragment.fromArray(node));
169
+ } else {
170
+ return node;
171
+ }
172
+ });
173
+ };
174
+ export const transformToListNode = (nodes, targetNodeType, schema) => {
175
+ const isTargetTask = isTaskList(targetNodeType);
176
+ const listItems = [];
177
+ const listItemType = isTargetTask ? schema.nodes.taskItem : schema.nodes.listItem;
178
+ const isValid = getContentSupportChecker(listItemType);
179
+ nodes.forEach(node => {
180
+ // Append unsupported nodes as is
181
+ if (isBlockNodeForExtraction(node)) {
182
+ listItems.push({
183
+ canBeTransformed: false,
184
+ node
185
+ });
186
+ } else {
187
+ let newListItems;
188
+
189
+ // If the node is a list, we may need to transform it
190
+ if (isListNode(node)) {
191
+ const isSourceBulletOrOrdered = isBulletOrOrderedList(node.type);
192
+ const isTargetTask = isTaskList(targetNodeType);
193
+ const isSourceTask = isTaskList(node.type);
194
+ const isTargetBulletOrOrdered = isBulletOrOrderedList(targetNodeType);
195
+ const supportedListTypes = getSupportedListTypesSet(schema.nodes);
196
+ if (node.type === targetNodeType) {
197
+ // For the same list type, we can keep the structure
198
+ newListItems = node.content.content;
199
+ } else {
200
+ const newList = transformListRecursively({
201
+ isSourceBulletOrOrdered,
202
+ isSourceTask,
203
+ isTargetBulletOrOrdered,
204
+ isTargetTask,
205
+ listNode: node,
206
+ schema,
207
+ supportedListTypes,
208
+ targetNodeType
209
+ });
210
+ newListItems = [...newList.content.content];
211
+ }
212
+ } else if (isHeadingOrParagraphNode(node) || isValid(node)) {
213
+ if (isTargetTask) {
214
+ const inlineContent = [...node.content.content];
215
+ if (inlineContent.length > 0) {
216
+ newListItems = [listItemType.create(null, inlineContent)];
217
+ }
218
+ } else {
219
+ newListItems = [listItemType.create(null, node)];
220
+ }
221
+ } else if (!isValid(node)) {
222
+ listItems.push({
223
+ canBeTransformed: false,
224
+ node
225
+ });
226
+ }
227
+ if (newListItems) {
228
+ if (listItems.length === 0) {
229
+ listItems.push({
230
+ canBeTransformed: true,
231
+ node: newListItems
232
+ });
233
+ } else {
234
+ const lastItem = listItems[listItems.length - 1];
235
+ if (lastItem.canBeTransformed) {
236
+ listItems[listItems.length - 1] = {
237
+ node: [...lastItem.node, ...newListItems],
238
+ canBeTransformed: true
239
+ };
240
+ } else {
241
+ listItems.push({
242
+ node: newListItems,
243
+ canBeTransformed: true
244
+ });
245
+ }
246
+ }
247
+ }
248
+ }
249
+ });
250
+ return listItems.map(({
251
+ node,
252
+ canBeTransformed
253
+ }) => {
254
+ if (canBeTransformed) {
255
+ return targetNodeType.createChecked(null, Fragment.fromArray(node));
256
+ } else {
257
+ return node;
258
+ }
259
+ });
260
+ };
261
+ export const convertUnwrappedLayoutContent = (nodes, targetNodeType, schema) => {
262
+ if (isBlockNodeType(targetNodeType)) {
263
+ return transformToBlockNode(nodes, targetNodeType, schema);
264
+ }
265
+ if (isContainerNodeType(targetNodeType)) {
266
+ return transformToContainerNode(nodes, targetNodeType);
267
+ }
268
+ if (isListNodeType(targetNodeType)) {
269
+ return transformToListNode(nodes, targetNodeType, schema);
270
+ }
271
+ return [];
272
+ };
@@ -1,5 +1,6 @@
1
1
  import { DEFAULT_TWO_COLUMN_LAYOUT_COLUMN_WIDTH } from '@atlaskit/editor-common/styles';
2
2
  import { Fragment } from '@atlaskit/editor-prosemirror/model';
3
+ import { convertUnwrappedLayoutContent, unwrapLayoutNodesToTextNodes } from './layout/utils';
3
4
  export const convertToLayout = context => {
4
5
  const {
5
6
  tr,
@@ -20,6 +21,44 @@ export const convertToLayout = context => {
20
21
  const layoutSectionNode = layoutSection.createChecked(undefined, layoutContent);
21
22
 
22
23
  // Replace the original node with the new layout node
23
- tr.replaceRangeWith(sourcePos || 0, (sourcePos || 0) + sourceNode.nodeSize, layoutSectionNode);
24
+ tr.replaceRangeWith(sourcePos, sourcePos + sourceNode.nodeSize, layoutSectionNode);
24
25
  return tr;
26
+ };
27
+ export const transformLayoutNode = context => {
28
+ const {
29
+ tr,
30
+ sourceNode,
31
+ targetNodeType,
32
+ sourcePos,
33
+ targetAttrs
34
+ } = context;
35
+ const schema = tr.doc.type.schema || {};
36
+ const {
37
+ layoutSection,
38
+ layoutColumn,
39
+ paragraph,
40
+ heading
41
+ } = schema.nodes || {};
42
+ const layoutColumnNodes = [];
43
+ const targetTextNodeType = targetNodeType === heading ? heading : paragraph;
44
+ sourceNode.children.forEach(child => {
45
+ if (child.type === layoutColumn) {
46
+ const unwrappedContent = [];
47
+ child.content.forEach(node => {
48
+ // Unwrap all nodes and convert to text nodes
49
+ const context = {
50
+ tr,
51
+ sourceNode: node,
52
+ targetNodeType: targetTextNodeType,
53
+ sourcePos: 0,
54
+ targetAttrs
55
+ };
56
+ const newContent = unwrapLayoutNodesToTextNodes(context, targetNodeType);
57
+ unwrappedContent.push(...newContent);
58
+ });
59
+ const newColumnContent = convertUnwrappedLayoutContent(unwrappedContent, targetNodeType, schema);
60
+ layoutColumnNodes.push(layoutColumn.createChecked(child.attrs, Fragment.fromArray(newColumnContent), child.marks));
61
+ }
62
+ });
63
+ return tr.replaceRangeWith(sourcePos, sourcePos + sourceNode.nodeSize, layoutSection.createChecked(sourceNode.attrs, Fragment.fromArray(layoutColumnNodes), sourceNode.marks));
25
64
  };
@@ -16,6 +16,88 @@ const convertBlockToInlineContent = (node, schema) => {
16
16
  }
17
17
  return [node];
18
18
  };
19
+ export const transformListRecursively = props => {
20
+ const transformedItems = [];
21
+ const {
22
+ listNode,
23
+ isSourceBulletOrOrdered,
24
+ isTargetBulletOrOrdered,
25
+ isSourceTask,
26
+ isTargetTask,
27
+ supportedListTypes,
28
+ schema,
29
+ targetNodeType
30
+ } = props;
31
+ const {
32
+ taskList,
33
+ listItem,
34
+ taskItem,
35
+ paragraph
36
+ } = schema.nodes;
37
+ listNode.forEach(child => {
38
+ if (isSourceBulletOrOrdered && isTargetTask) {
39
+ // Convert bullet/ordered => task
40
+ if (child.type === listItem) {
41
+ const inlineContent = [];
42
+ const nestedTaskLists = [];
43
+ child.forEach(grandChild => {
44
+ if (supportedListTypes.has(grandChild.type) && grandChild.type !== taskList) {
45
+ nestedTaskLists.push(transformListRecursively({
46
+ ...props,
47
+ listNode: grandChild
48
+ }));
49
+ } else {
50
+ inlineContent.push(...convertBlockToInlineContent(grandChild, schema));
51
+ }
52
+ });
53
+ if (inlineContent.length > 0) {
54
+ transformedItems.push(taskItem.create(null, inlineContent));
55
+ }
56
+ transformedItems.push(...nestedTaskLists);
57
+ }
58
+ } else if (isSourceTask && isTargetBulletOrOrdered) {
59
+ // Convert task => bullet/ordered
60
+ if (child.type === taskItem) {
61
+ const inlineContent = [...child.content.content];
62
+ if (inlineContent.length > 0) {
63
+ const paragraphNode = paragraph.create(null, inlineContent);
64
+ transformedItems.push(listItem.create(null, [paragraphNode]));
65
+ }
66
+ } else if (child.type === taskList) {
67
+ const transformedNestedList = transformListRecursively({
68
+ ...props,
69
+ listNode: child
70
+ });
71
+ const lastItem = transformedItems[transformedItems.length - 1];
72
+ if ((lastItem === null || lastItem === void 0 ? void 0 : lastItem.type) === listItem) {
73
+ // Attach nested list to previous item
74
+ const updatedContent = [...lastItem.content.content, transformedNestedList];
75
+ transformedItems[transformedItems.length - 1] = listItem.create(lastItem.attrs, updatedContent);
76
+ } else {
77
+ // No previous item, flatten nested items
78
+ transformedItems.push(...transformedNestedList.content.content);
79
+ }
80
+ }
81
+ } else if (isSourceBulletOrOrdered && isTargetBulletOrOrdered) {
82
+ if (child.type === listItem) {
83
+ const convertedNestedLists = [];
84
+ child.forEach(grandChild => {
85
+ if (supportedListTypes.has(grandChild.type) && grandChild.type !== targetNodeType) {
86
+ const convertedNode = transformListRecursively({
87
+ ...props,
88
+ listNode: grandChild
89
+ });
90
+ convertedNestedLists.push(convertedNode);
91
+ } else {
92
+ convertedNestedLists.push(grandChild);
93
+ }
94
+ });
95
+ transformedItems.push(listItem.create(null, convertedNestedLists));
96
+ }
97
+ }
98
+ });
99
+ return targetNodeType.create(null, transformedItems);
100
+ };
19
101
 
20
102
  /**
21
103
  * Transform list structure between different list types
@@ -37,62 +119,23 @@ export const transformListStructure = context => {
37
119
  node: sourceList,
38
120
  pos: listPos
39
121
  } = listNode;
40
- const {
41
- taskList,
42
- listItem,
43
- taskItem,
44
- paragraph
45
- } = nodes;
122
+ // const { taskList, listItem, taskItem, paragraph } = nodes;
123
+
46
124
  const isSourceBulletOrOrdered = isBulletOrOrderedList(sourceList.type);
47
125
  const isTargetTask = isTaskList(targetNodeType);
48
126
  const isSourceTask = isTaskList(sourceList.type);
49
127
  const isTargetBulletOrOrdered = isBulletOrOrderedList(targetNodeType);
50
128
  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);
70
- }
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
- }
90
- }
91
- }
92
- });
93
- return targetNodeType.create(null, transformedItems);
94
- };
95
- const newList = transformListRecursively(sourceList);
129
+ const newList = transformListRecursively({
130
+ isSourceBulletOrOrdered,
131
+ isSourceTask,
132
+ isTargetBulletOrOrdered,
133
+ isTargetTask,
134
+ listNode: sourceList,
135
+ schema: tr.doc.type.schema,
136
+ supportedListTypes,
137
+ targetNodeType
138
+ });
96
139
  tr.replaceWith(listPos, listPos + sourceList.nodeSize, newList);
97
140
  return tr;
98
141
  } catch {