@atlaskit/editor-plugin-list 0.2.0 → 1.1.0

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 (181) hide show
  1. package/.eslintrc.js +14 -0
  2. package/CHANGELOG.md +16 -0
  3. package/README.md +1 -1
  4. package/dist/cjs/actions/conversions.js +153 -0
  5. package/dist/cjs/actions/indent-list-items-selected.js +125 -0
  6. package/dist/cjs/actions/indent-list.js +49 -0
  7. package/dist/cjs/actions/join-list-items-forward.js +59 -0
  8. package/dist/cjs/actions/join-list-items-scenarios/index.js +40 -0
  9. package/dist/cjs/actions/join-list-items-scenarios/join-list-item-with-paragraph.js +88 -0
  10. package/dist/cjs/actions/join-list-items-scenarios/join-list-item-with-parent-nested-list.js +85 -0
  11. package/dist/cjs/actions/join-list-items-scenarios/join-nested-list-with-parent-list-item.js +79 -0
  12. package/dist/cjs/actions/join-list-items-scenarios/join-paragraph-with-list.js +45 -0
  13. package/dist/cjs/actions/join-list-items-scenarios/join-sibling-list-items.js +56 -0
  14. package/dist/cjs/actions/merge-lists.js +27 -0
  15. package/dist/cjs/actions/outdent-list-items-selected.js +289 -0
  16. package/dist/cjs/actions/wrap-and-join-lists.js +100 -0
  17. package/dist/cjs/commands/indent-list.js +69 -0
  18. package/dist/cjs/commands/index.js +349 -0
  19. package/dist/cjs/commands/isFirstChildOfParent.js +12 -0
  20. package/dist/cjs/commands/join-list-item-forward.js +61 -0
  21. package/dist/cjs/commands/listBackspace.js +284 -0
  22. package/dist/cjs/commands/outdent-list.js +69 -0
  23. package/dist/cjs/index.js +8 -1
  24. package/dist/cjs/messages.js +37 -0
  25. package/dist/cjs/plugin.js +137 -0
  26. package/dist/cjs/pm-plugins/input-rules/create-list-input-rule.js +63 -0
  27. package/dist/cjs/pm-plugins/input-rules/index.js +38 -0
  28. package/dist/cjs/pm-plugins/input-rules/wrapping-join-rule.js +60 -0
  29. package/dist/cjs/pm-plugins/keymap.js +27 -0
  30. package/dist/cjs/pm-plugins/main.js +166 -0
  31. package/dist/cjs/transforms.js +99 -0
  32. package/dist/cjs/types.js +4 -1
  33. package/dist/cjs/utils/analytics.js +22 -0
  34. package/dist/cjs/utils/find.js +68 -0
  35. package/dist/cjs/utils/indentation.js +22 -0
  36. package/dist/cjs/utils/mark.js +40 -0
  37. package/dist/cjs/utils/node.js +16 -0
  38. package/dist/cjs/utils/selection.js +95 -0
  39. package/dist/es2019/actions/conversions.js +160 -0
  40. package/dist/es2019/actions/indent-list-items-selected.js +124 -0
  41. package/dist/es2019/actions/indent-list.js +44 -0
  42. package/dist/es2019/actions/join-list-items-forward.js +54 -0
  43. package/dist/es2019/actions/join-list-items-scenarios/index.js +5 -0
  44. package/dist/es2019/actions/join-list-items-scenarios/join-list-item-with-paragraph.js +74 -0
  45. package/dist/es2019/actions/join-list-items-scenarios/join-list-item-with-parent-nested-list.js +77 -0
  46. package/dist/es2019/actions/join-list-items-scenarios/join-nested-list-with-parent-list-item.js +71 -0
  47. package/dist/es2019/actions/join-list-items-scenarios/join-paragraph-with-list.js +37 -0
  48. package/dist/es2019/actions/join-list-items-scenarios/join-sibling-list-items.js +48 -0
  49. package/dist/es2019/actions/merge-lists.js +24 -0
  50. package/dist/es2019/actions/outdent-list-items-selected.js +293 -0
  51. package/dist/es2019/actions/wrap-and-join-lists.js +93 -0
  52. package/dist/es2019/commands/indent-list.js +61 -0
  53. package/dist/es2019/commands/index.js +322 -0
  54. package/dist/es2019/commands/isFirstChildOfParent.js +7 -0
  55. package/dist/es2019/commands/join-list-item-forward.js +53 -0
  56. package/dist/es2019/commands/listBackspace.js +276 -0
  57. package/dist/es2019/commands/outdent-list.js +60 -0
  58. package/dist/es2019/index.js +1 -1
  59. package/dist/es2019/messages.js +29 -0
  60. package/dist/es2019/plugin.js +123 -0
  61. package/dist/es2019/pm-plugins/input-rules/create-list-input-rule.js +56 -0
  62. package/dist/es2019/pm-plugins/input-rules/index.js +35 -0
  63. package/dist/es2019/pm-plugins/input-rules/wrapping-join-rule.js +55 -0
  64. package/dist/es2019/pm-plugins/keymap.js +19 -0
  65. package/dist/es2019/pm-plugins/main.js +156 -0
  66. package/dist/es2019/transforms.js +101 -0
  67. package/dist/es2019/types.js +1 -1
  68. package/dist/es2019/utils/analytics.js +12 -0
  69. package/dist/es2019/utils/find.js +61 -0
  70. package/dist/es2019/utils/indentation.js +15 -0
  71. package/dist/es2019/utils/mark.js +30 -0
  72. package/dist/es2019/utils/node.js +12 -0
  73. package/dist/es2019/utils/selection.js +96 -0
  74. package/dist/esm/actions/conversions.js +147 -0
  75. package/dist/esm/actions/indent-list-items-selected.js +117 -0
  76. package/dist/esm/actions/indent-list.js +43 -0
  77. package/dist/esm/actions/join-list-items-forward.js +52 -0
  78. package/dist/esm/actions/join-list-items-scenarios/index.js +5 -0
  79. package/dist/esm/actions/join-list-items-scenarios/join-list-item-with-paragraph.js +81 -0
  80. package/dist/esm/actions/join-list-items-scenarios/join-list-item-with-parent-nested-list.js +78 -0
  81. package/dist/esm/actions/join-list-items-scenarios/join-nested-list-with-parent-list-item.js +72 -0
  82. package/dist/esm/actions/join-list-items-scenarios/join-paragraph-with-list.js +38 -0
  83. package/dist/esm/actions/join-list-items-scenarios/join-sibling-list-items.js +49 -0
  84. package/dist/esm/actions/merge-lists.js +21 -0
  85. package/dist/esm/actions/outdent-list-items-selected.js +281 -0
  86. package/dist/esm/actions/wrap-and-join-lists.js +94 -0
  87. package/dist/esm/commands/indent-list.js +61 -0
  88. package/dist/esm/commands/index.js +323 -0
  89. package/dist/esm/commands/isFirstChildOfParent.js +5 -0
  90. package/dist/esm/commands/join-list-item-forward.js +53 -0
  91. package/dist/esm/commands/listBackspace.js +275 -0
  92. package/dist/esm/commands/outdent-list.js +61 -0
  93. package/dist/esm/index.js +1 -1
  94. package/dist/esm/messages.js +29 -0
  95. package/dist/esm/plugin.js +130 -0
  96. package/dist/esm/pm-plugins/input-rules/create-list-input-rule.js +57 -0
  97. package/dist/esm/pm-plugins/input-rules/index.js +32 -0
  98. package/dist/esm/pm-plugins/input-rules/wrapping-join-rule.js +54 -0
  99. package/dist/esm/pm-plugins/keymap.js +19 -0
  100. package/dist/esm/pm-plugins/main.js +156 -0
  101. package/dist/esm/transforms.js +91 -0
  102. package/dist/esm/types.js +1 -1
  103. package/dist/esm/utils/analytics.js +12 -0
  104. package/dist/esm/utils/find.js +59 -0
  105. package/dist/esm/utils/indentation.js +15 -0
  106. package/dist/esm/utils/mark.js +33 -0
  107. package/dist/esm/utils/node.js +10 -0
  108. package/dist/esm/utils/selection.js +81 -0
  109. package/dist/types/actions/conversions.d.ts +6 -0
  110. package/dist/types/actions/indent-list-items-selected.d.ts +2 -0
  111. package/dist/types/actions/indent-list.d.ts +2 -0
  112. package/dist/types/actions/join-list-items-forward.d.ts +13 -0
  113. package/dist/types/actions/join-list-items-scenarios/index.d.ts +5 -0
  114. package/dist/types/actions/join-list-items-scenarios/join-list-item-with-paragraph.d.ts +9 -0
  115. package/dist/types/actions/join-list-items-scenarios/join-list-item-with-parent-nested-list.d.ts +9 -0
  116. package/dist/types/actions/join-list-items-scenarios/join-nested-list-with-parent-list-item.d.ts +9 -0
  117. package/dist/types/actions/join-list-items-scenarios/join-paragraph-with-list.d.ts +9 -0
  118. package/dist/types/actions/join-list-items-scenarios/join-sibling-list-items.d.ts +9 -0
  119. package/dist/types/actions/merge-lists.d.ts +7 -0
  120. package/dist/types/actions/outdent-list-items-selected.d.ts +3 -0
  121. package/dist/types/actions/wrap-and-join-lists.d.ts +17 -0
  122. package/dist/types/commands/indent-list.d.ts +6 -0
  123. package/dist/types/commands/index.d.ts +15 -0
  124. package/dist/types/commands/isFirstChildOfParent.d.ts +2 -0
  125. package/dist/types/commands/join-list-item-forward.d.ts +3 -0
  126. package/dist/types/commands/listBackspace.d.ts +10 -0
  127. package/dist/types/commands/outdent-list.d.ts +6 -0
  128. package/dist/types/index.d.ts +2 -1
  129. package/dist/types/messages.d.ts +27 -0
  130. package/dist/types/plugin.d.ts +2 -0
  131. package/dist/types/pm-plugins/input-rules/create-list-input-rule.d.ts +11 -0
  132. package/dist/types/pm-plugins/input-rules/index.d.ts +5 -0
  133. package/dist/types/pm-plugins/input-rules/wrapping-join-rule.d.ts +13 -0
  134. package/dist/types/pm-plugins/keymap.d.ts +5 -0
  135. package/dist/types/pm-plugins/main.d.ts +11 -0
  136. package/dist/types/transforms.d.ts +4 -0
  137. package/dist/types/types.d.ts +13 -13
  138. package/dist/types/utils/analytics.d.ts +5 -0
  139. package/dist/types/utils/find.d.ts +10 -0
  140. package/dist/types/utils/indentation.d.ts +2 -0
  141. package/dist/types/utils/mark.d.ts +8 -0
  142. package/dist/types/utils/node.d.ts +2 -0
  143. package/dist/types/utils/selection.d.ts +14 -0
  144. package/dist/types-ts4.5/actions/conversions.d.ts +6 -0
  145. package/dist/types-ts4.5/actions/indent-list-items-selected.d.ts +2 -0
  146. package/dist/types-ts4.5/actions/indent-list.d.ts +2 -0
  147. package/dist/types-ts4.5/actions/join-list-items-forward.d.ts +16 -0
  148. package/dist/types-ts4.5/actions/join-list-items-scenarios/index.d.ts +5 -0
  149. package/dist/types-ts4.5/actions/join-list-items-scenarios/join-list-item-with-paragraph.d.ts +9 -0
  150. package/dist/types-ts4.5/actions/join-list-items-scenarios/join-list-item-with-parent-nested-list.d.ts +9 -0
  151. package/dist/types-ts4.5/actions/join-list-items-scenarios/join-nested-list-with-parent-list-item.d.ts +9 -0
  152. package/dist/types-ts4.5/actions/join-list-items-scenarios/join-paragraph-with-list.d.ts +9 -0
  153. package/dist/types-ts4.5/actions/join-list-items-scenarios/join-sibling-list-items.d.ts +9 -0
  154. package/dist/types-ts4.5/actions/merge-lists.d.ts +7 -0
  155. package/dist/types-ts4.5/actions/outdent-list-items-selected.d.ts +3 -0
  156. package/dist/types-ts4.5/actions/wrap-and-join-lists.d.ts +17 -0
  157. package/dist/types-ts4.5/commands/indent-list.d.ts +6 -0
  158. package/dist/types-ts4.5/commands/index.d.ts +15 -0
  159. package/dist/types-ts4.5/commands/isFirstChildOfParent.d.ts +2 -0
  160. package/dist/types-ts4.5/commands/join-list-item-forward.d.ts +3 -0
  161. package/dist/types-ts4.5/commands/listBackspace.d.ts +13 -0
  162. package/dist/types-ts4.5/commands/outdent-list.d.ts +6 -0
  163. package/dist/types-ts4.5/index.d.ts +2 -1
  164. package/dist/types-ts4.5/messages.d.ts +27 -0
  165. package/dist/types-ts4.5/plugin.d.ts +2 -0
  166. package/dist/types-ts4.5/pm-plugins/input-rules/create-list-input-rule.d.ts +11 -0
  167. package/dist/types-ts4.5/pm-plugins/input-rules/index.d.ts +5 -0
  168. package/dist/types-ts4.5/pm-plugins/input-rules/wrapping-join-rule.d.ts +13 -0
  169. package/dist/types-ts4.5/pm-plugins/keymap.d.ts +5 -0
  170. package/dist/types-ts4.5/pm-plugins/main.d.ts +11 -0
  171. package/dist/types-ts4.5/transforms.d.ts +4 -0
  172. package/dist/types-ts4.5/types.d.ts +13 -13
  173. package/dist/types-ts4.5/utils/analytics.d.ts +5 -0
  174. package/dist/types-ts4.5/utils/find.d.ts +10 -0
  175. package/dist/types-ts4.5/utils/indentation.d.ts +2 -0
  176. package/dist/types-ts4.5/utils/mark.d.ts +8 -0
  177. package/dist/types-ts4.5/utils/node.d.ts +2 -0
  178. package/dist/types-ts4.5/utils/selection.d.ts +14 -0
  179. package/package.json +8 -5
  180. package/report.api.md +17 -18
  181. package/tmp/api-report-tmp.d.ts +15 -11
@@ -0,0 +1,48 @@
1
+ import { insertContentDeleteRange } from '@atlaskit/editor-common/utils';
2
+ //Case for two adjacent list items of the same indentation
3
+ export const joinSiblingListItems = ({
4
+ tr,
5
+ $next,
6
+ $head
7
+ }) => {
8
+ /* CASE 2
9
+ * Initial Structure:
10
+ *
11
+ * List A {
12
+ * ListItem B {
13
+ * ...Children C
14
+ * Paragraph D { text1 |$head||textInsertPos| } //Cant have children since that would be Case 4
15
+ * |childrenGInsertPos| }
16
+ * ListItem E { |$next|
17
+ * Paragraph F { text2 }
18
+ * ...Children G
19
+ * }
20
+ * }
21
+ *
22
+ * Converts to:
23
+ *
24
+ * List A {
25
+ * ListItem B {
26
+ * ...Children C
27
+ * Paragraph C { text1text2 }
28
+ * ...Children G
29
+ * }
30
+ * }
31
+ *
32
+ */
33
+
34
+ const listItemE = $next.parent;
35
+ const paragraphF = $next.nodeAfter; //ListItem must have at least one child
36
+ if (!paragraphF) {
37
+ return false;
38
+ }
39
+ const beforeListItemE = $next.before();
40
+ const afterListItemE = $next.after();
41
+ const endListItemB = $head.end(-1);
42
+ const textInsertPos = $head.pos;
43
+ const childrenGInsertPos = endListItemB;
44
+ const textContent = paragraphF.content;
45
+ const childrenGContent = listItemE.content.cut(paragraphF.nodeSize);
46
+ insertContentDeleteRange(tr, tr => tr.doc.resolve(textInsertPos), [[textContent, textInsertPos], [childrenGContent, childrenGInsertPos]], [[beforeListItemE, afterListItemE]]);
47
+ return true;
48
+ };
@@ -0,0 +1,24 @@
1
+ import { isListNode } from '@atlaskit/editor-common/utils';
2
+ export function mergeNextListAtPosition({
3
+ tr,
4
+ listPosition
5
+ }) {
6
+ const listNodeAtPosition = tr.doc.nodeAt(listPosition);
7
+ if (!isListNode(listNodeAtPosition)) {
8
+ return;
9
+ }
10
+ const listPositionResolved = tr.doc.resolve(listPosition + listNodeAtPosition.nodeSize);
11
+ const {
12
+ pos,
13
+ nodeAfter,
14
+ nodeBefore
15
+ } = listPositionResolved;
16
+ if (!isListNode(nodeBefore) || !isListNode(nodeAfter)) {
17
+ return;
18
+ }
19
+ if ((nodeAfter === null || nodeAfter === void 0 ? void 0 : nodeAfter.type.name) !== (nodeBefore === null || nodeBefore === void 0 ? void 0 : nodeBefore.type.name)) {
20
+ const previousListPosition = pos - nodeBefore.nodeSize;
21
+ tr.setNodeMarkup(previousListPosition, nodeAfter.type);
22
+ }
23
+ tr.join(pos);
24
+ }
@@ -0,0 +1,293 @@
1
+ import { OUTDENT_SCENARIOS } from '@atlaskit/editor-common/analytics';
2
+ import { JoinDirection, joinSiblingLists, normalizeListItemsSelection } from '@atlaskit/editor-common/lists';
3
+ import { GapCursorSelection } from '@atlaskit/editor-common/selection';
4
+ import { getOrderFromOrderedListNode, isListItemNode, isListNode } from '@atlaskit/editor-common/utils';
5
+ import { Fragment, NodeRange, Slice } from '@atlaskit/editor-prosemirror/model';
6
+ import { NodeSelection, Selection, TextSelection } from '@atlaskit/editor-prosemirror/state';
7
+ import { liftTarget, ReplaceAroundStep, ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
8
+ import { getRestartListsAttributes, storeRestartListsAttributes } from '../utils/analytics';
9
+ import { findFirstParentListItemNode, findRootParentListNode } from '../utils/find';
10
+ import { createListNodeRange } from '../utils/selection';
11
+ export const outdentListItemsSelected = (tr, featureFlags) => {
12
+ const originalSelection = tr.selection;
13
+ const normalizedSelection = normalizeListItemsSelection({
14
+ selection: tr.selection,
15
+ doc: tr.doc
16
+ });
17
+ const rootList = findRootParentListNode(normalizedSelection.$from);
18
+ if (!rootList) {
19
+ return;
20
+ }
21
+ const commonList = normalizedSelection.$from.blockRange(rootList, isListNode);
22
+ if (!commonList) {
23
+ return;
24
+ }
25
+ let hasNormalizedToPositionLiftedOut = false;
26
+ let hasNormalizedFromPositionLiftedOut = false;
27
+ const {
28
+ from: oldFrom,
29
+ to: oldTo
30
+ } = normalizedSelection;
31
+ const nodeRanges = splitRangeSelection(normalizedSelection);
32
+ nodeRanges.forEach(range => {
33
+ const $from = tr.doc.resolve(tr.mapping.map(range.from));
34
+ const $to = tr.doc.resolve(tr.mapping.map(range.to));
35
+ const mappedRange = $from.blockRange($to, isListNode);
36
+ if (!mappedRange) {
37
+ return;
38
+ }
39
+ if (isListItemNode($from.node(mappedRange.depth - 1))) {
40
+ outdentRangeToParentList({
41
+ tr,
42
+ range: mappedRange
43
+ });
44
+ } else {
45
+ extractListItemsRangeFromList({
46
+ tr,
47
+ range: mappedRange,
48
+ featureFlags
49
+ });
50
+ hasNormalizedToPositionLiftedOut = hasNormalizedToPositionLiftedOut || oldTo >= range.from && oldTo < range.to;
51
+ hasNormalizedFromPositionLiftedOut = hasNormalizedFromPositionLiftedOut || oldFrom >= range.from && oldFrom < range.to;
52
+ }
53
+ });
54
+ const hasCommonListMoved = commonList.start !== tr.mapping.map(commonList.start);
55
+ const nextSelection = calculateNewSelection({
56
+ originalSelection,
57
+ normalizedSelection,
58
+ tr,
59
+ hasCommonListMoved,
60
+ hasNormalizedToPositionLiftedOut,
61
+ hasNormalizedFromPositionLiftedOut
62
+ });
63
+ tr.setSelection(nextSelection);
64
+ joinSiblingLists({
65
+ tr,
66
+ direction: JoinDirection.RIGHT
67
+ });
68
+ };
69
+ const calculateNewSelection = ({
70
+ tr,
71
+ originalSelection,
72
+ normalizedSelection,
73
+ hasCommonListMoved,
74
+ hasNormalizedToPositionLiftedOut,
75
+ hasNormalizedFromPositionLiftedOut
76
+ }) => {
77
+ const {
78
+ $from,
79
+ $to
80
+ } = normalizedSelection;
81
+ const isCursorSelection = normalizedSelection.empty;
82
+ let from = tr.mapping.map($from.pos);
83
+ let to = tr.mapping.map($to.pos);
84
+ const LIST_STRUCTURE_CHANGED_OFFSET = 2;
85
+ const isToFromSameListItem = $from.sameParent($to);
86
+ if (hasNormalizedFromPositionLiftedOut) {
87
+ const fromMapped = isToFromSameListItem ? $from.pos : from;
88
+ from = hasNormalizedFromPositionLiftedOut ? $from.pos : fromMapped;
89
+ from = hasCommonListMoved ? from - LIST_STRUCTURE_CHANGED_OFFSET : from;
90
+ from = Math.max(from, 0);
91
+ }
92
+ if (hasNormalizedToPositionLiftedOut) {
93
+ const toMapped = isToFromSameListItem ? $to.pos : to;
94
+ to = hasNormalizedToPositionLiftedOut ? $to.pos : toMapped;
95
+ to = hasCommonListMoved ? to - LIST_STRUCTURE_CHANGED_OFFSET : to;
96
+ to = Math.min(to, tr.doc.nodeSize - 2);
97
+ }
98
+ if (normalizedSelection instanceof GapCursorSelection) {
99
+ const nextSelectionFrom = tr.doc.resolve(from);
100
+ return new GapCursorSelection(nextSelectionFrom, normalizedSelection.side);
101
+ }
102
+ if (originalSelection instanceof NodeSelection) {
103
+ return NodeSelection.create(tr.doc, from);
104
+ }
105
+ if (isCursorSelection) {
106
+ return TextSelection.between(tr.doc.resolve(to), tr.doc.resolve(to), -1);
107
+ }
108
+ return TextSelection.between(tr.doc.resolve(from), tr.doc.resolve(to), -1);
109
+ };
110
+ const splitRangeSelection = selection => {
111
+ const commonListRange = createListNodeRange({
112
+ selection
113
+ });
114
+ if (!commonListRange) {
115
+ return [];
116
+ }
117
+ const {
118
+ $from,
119
+ $to
120
+ } = selection;
121
+ if ($from.pos === $to.pos && $from.sameParent($to)) {
122
+ return [{
123
+ from: commonListRange.start,
124
+ to: commonListRange.end,
125
+ depth: commonListRange.depth
126
+ }];
127
+ }
128
+ const lastListItem = findPreviousListItemSibling($from);
129
+ if (!lastListItem) {
130
+ return [];
131
+ }
132
+ const nodeRanges = [];
133
+ const {
134
+ doc
135
+ } = $from;
136
+ let previousListItem = findPreviousListItemSibling($to);
137
+ while (previousListItem && previousListItem.pos >= lastListItem.pos && previousListItem.pos >= commonListRange.start) {
138
+ const node = doc.nodeAt(previousListItem.pos);
139
+ if (!node || !isListItemNode(node)) {
140
+ return [];
141
+ }
142
+ let offset = 0;
143
+ if (node && node.lastChild && isListNode(node.lastChild)) {
144
+ offset = node.lastChild.nodeSize;
145
+ }
146
+ const start = previousListItem.pos + 1;
147
+ nodeRanges.push({
148
+ from: start,
149
+ to: doc.resolve(start).end() - offset,
150
+ depth: previousListItem.depth
151
+ });
152
+ previousListItem = findPreviousListItemSibling(previousListItem);
153
+ }
154
+ return nodeRanges;
155
+ };
156
+ const outdentRangeToParentList = ({
157
+ tr,
158
+ range
159
+ }) => {
160
+ const end = range.end;
161
+ const endOfList = range.$to.end(range.depth);
162
+ const {
163
+ listItem
164
+ } = tr.doc.type.schema.nodes;
165
+ if (end < endOfList) {
166
+ const slice = new Slice(Fragment.from(listItem.create(null, range.parent.copy())), 1, 0);
167
+ const step = new ReplaceAroundStep(end - 1, endOfList, end, endOfList, slice, 1, true);
168
+ tr.step(step);
169
+ range = new NodeRange(tr.doc.resolve(range.$from.pos), tr.doc.resolve(endOfList), range.depth);
170
+ }
171
+ const target = liftTarget(range);
172
+ if (target) {
173
+ tr.lift(range, target);
174
+ }
175
+ };
176
+ const extractListItemsRangeFromList = ({
177
+ tr,
178
+ range,
179
+ featureFlags
180
+ }) => {
181
+ const list = range.parent;
182
+ const $start = tr.doc.resolve(range.start);
183
+ const listStart = $start.start(range.depth);
184
+ const listEnd = $start.end(range.depth);
185
+ const isAtTop = listStart === range.start;
186
+ const isAtBottom = listEnd === range.end;
187
+ const isTheEntireList = isAtTop && isAtBottom;
188
+ let listItemContent = isAtTop ? Fragment.empty : Fragment.from(list.copy(Fragment.empty));
189
+ for (let i = range.startIndex; i < range.endIndex; i++) {
190
+ listItemContent = listItemContent.append(list.child(i).content);
191
+ }
192
+ if (isAtTop) {
193
+ for (let i = 0; i < listItemContent.childCount; i++) {
194
+ const child = listItemContent.child(i);
195
+ if (child && isListNode(child) && child.type !== list.type) {
196
+ const newNestedList = list.type.create(null, child.content);
197
+ listItemContent = listItemContent.replaceChild(i, newNestedList);
198
+ }
199
+ }
200
+ }
201
+ let nextList = list.copy(Fragment.empty);
202
+ let nextListStartNumber;
203
+ if (featureFlags !== null && featureFlags !== void 0 && featureFlags.restartNumberedLists) {
204
+ // if splitting a numbered list, keep the splitted item
205
+ // counter as the start of the next (second half) list (instead
206
+ // of reverting back to 1 as a starting number)
207
+ const order = getOrderFromOrderedListNode(list);
208
+ if (list.type.name === 'orderedList') {
209
+ nextListStartNumber = range.endIndex - 1 + order;
210
+ // @ts-ignore - [unblock prosemirror bump] assigning to readonly attrs
211
+ nextList.attrs = {
212
+ ...nextList.attrs,
213
+ order: nextListStartNumber
214
+ };
215
+ const {
216
+ splitListStartNumber
217
+ } = getRestartListsAttributes(tr);
218
+ if (typeof splitListStartNumber !== 'number') {
219
+ storeRestartListsAttributes(tr, {
220
+ splitListStartNumber: nextListStartNumber
221
+ });
222
+ }
223
+ }
224
+ }
225
+ const nextListFragment = listItemContent.append(Fragment.from(nextList));
226
+ if (featureFlags !== null && featureFlags !== void 0 && featureFlags.restartNumberedLists) {
227
+ // if the split list with nextListStartNumber is below another list
228
+ // with order (e.g due to multi-level indent items being lifted), track the
229
+ // list above's order instead, as it will be the split list's order after sibling joins
230
+ nextListFragment.forEach((node, _offset, index) => {
231
+ var _node$attrs;
232
+ if (node.type.name === 'orderedList' && ((_node$attrs = node.attrs) === null || _node$attrs === void 0 ? void 0 : _node$attrs.order) === nextListStartNumber) {
233
+ var _prev$attrs;
234
+ const prev = nextListFragment.child(index - 1);
235
+ if ((prev === null || prev === void 0 ? void 0 : (_prev$attrs = prev.attrs) === null || _prev$attrs === void 0 ? void 0 : _prev$attrs.order) >= 0) {
236
+ var _prev$attrs2;
237
+ storeRestartListsAttributes(tr, {
238
+ splitListStartNumber: prev === null || prev === void 0 ? void 0 : (_prev$attrs2 = prev.attrs) === null || _prev$attrs2 === void 0 ? void 0 : _prev$attrs2.order
239
+ });
240
+ }
241
+ }
242
+ });
243
+ }
244
+ if (isTheEntireList) {
245
+ const slice = new Slice(listItemContent, 0, 0);
246
+ const step = new ReplaceStep($start.pos - 1, range.end + 1, slice, false);
247
+ if (featureFlags !== null && featureFlags !== void 0 && featureFlags.restartNumberedLists) {
248
+ storeRestartListsAttributes(tr, {
249
+ outdentScenario: undefined
250
+ });
251
+ }
252
+ tr.step(step);
253
+ } else if (isAtTop) {
254
+ const slice = new Slice(nextListFragment, 0, 1);
255
+ const step = new ReplaceStep($start.pos - 1, range.end, slice, false);
256
+ tr.step(step);
257
+ } else if (isAtBottom) {
258
+ const slice = new Slice(listItemContent, 1, 0);
259
+ const step = new ReplaceStep($start.pos, listEnd + 1, slice, false);
260
+ tr.step(step);
261
+ } else {
262
+ if (featureFlags !== null && featureFlags !== void 0 && featureFlags.restartNumberedLists) {
263
+ storeRestartListsAttributes(tr, {
264
+ outdentScenario: OUTDENT_SCENARIOS.SPLIT_LIST
265
+ });
266
+ }
267
+ const slice = new Slice(nextListFragment, 1, 1);
268
+ const step = new ReplaceAroundStep($start.pos, listEnd, range.end, listEnd, slice, slice.size, false);
269
+ tr.step(step);
270
+ }
271
+ };
272
+ const findPreviousListItemSibling = $pos => {
273
+ const doc = $pos.doc;
274
+ const isPositionListItem = isListNode($pos.node());
275
+ let listItemPosition = $pos;
276
+ if (!isPositionListItem) {
277
+ const listItem = findFirstParentListItemNode($pos);
278
+ if (!listItem) {
279
+ return null;
280
+ }
281
+ return doc.resolve(listItem.pos);
282
+ }
283
+ const resolved = doc.resolve(listItemPosition.pos);
284
+ const foundPosition = Selection.findFrom(resolved, -1);
285
+ if (!foundPosition) {
286
+ return null;
287
+ }
288
+ const parentListItemNode = findFirstParentListItemNode(foundPosition.$from);
289
+ if (!parentListItemNode) {
290
+ return null;
291
+ }
292
+ return doc.resolve(parentListItemNode.pos);
293
+ };
@@ -0,0 +1,93 @@
1
+ import { GapCursorSelection } from '@atlaskit/editor-common/selection';
2
+ import { autoJoinTr } from '@atlaskit/editor-common/utils';
3
+ import { Fragment, NodeRange, Slice } from '@atlaskit/editor-prosemirror/model';
4
+ import { canSplit, findWrapping, ReplaceAroundStep } from '@atlaskit/editor-prosemirror/transform';
5
+ import { isWrappingPossible } from '../utils/selection';
6
+
7
+ /**
8
+ * Wraps the selection in a list with the given type. If this results in
9
+ * two adjacent lists of the same type, those will be joined together.
10
+ */
11
+ export function wrapInListAndJoin(nodeType, tr) {
12
+ wrapInList(nodeType)(tr);
13
+ autoJoinTr(tr, (before, after) => before.type === after.type && before.type === nodeType);
14
+ }
15
+
16
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
+
18
+ /**
19
+ * Wraps the selection in a list with the given type and attributes.
20
+ *
21
+ * Adapted from https://github.com/ProseMirror/prosemirror-schema-list/blob/master/src/schema-list.js#L64-L89
22
+ */
23
+ export function wrapInList(listType, attrs) {
24
+ return function (tr) {
25
+ const {
26
+ $from,
27
+ $to
28
+ } = tr.selection;
29
+ let range;
30
+ if (tr.selection instanceof GapCursorSelection && $from.nodeAfter && isWrappingPossible(listType, tr.selection)) {
31
+ const nodeSize = $from.nodeAfter.nodeSize || 1;
32
+ range = $from.blockRange($from.doc.resolve($from.pos + nodeSize));
33
+ } else {
34
+ range = $from.blockRange($to);
35
+ }
36
+ let doJoin = false;
37
+ let outerRange = range;
38
+ if (!range) {
39
+ return false;
40
+ }
41
+ // This is at the top of an existing list item
42
+ if (range.depth >= 2 &&
43
+ // @ts-ignore - missing type for compatibleContent
44
+ $from.node(range.depth - 1).type.compatibleContent(listType) && range.startIndex === 0) {
45
+ // Don't do anything if this is the top of the list
46
+ if ($from.index(range.depth - 1) === 0) {
47
+ return false;
48
+ }
49
+ let $insert = tr.doc.resolve(range.start - 2);
50
+ outerRange = new NodeRange($insert, $insert, range.depth);
51
+ if (range.endIndex < range.parent.childCount) {
52
+ range = new NodeRange($from, tr.doc.resolve($to.end(range.depth)), range.depth);
53
+ }
54
+ doJoin = true;
55
+ }
56
+ let wrap = findWrapping(outerRange, listType, attrs, range);
57
+ if (!wrap) {
58
+ return false;
59
+ }
60
+ tr = doWrapInList(tr, range, wrap, doJoin, listType);
61
+ return true;
62
+ };
63
+ }
64
+
65
+ /**
66
+ * Internal function used by wrapInList
67
+ *
68
+ * Adapted from https://github.com/ProseMirror/prosemirror-schema-list/blob/master/src/schema-list.js#L91-L112
69
+ */
70
+ function doWrapInList(tr, range, wrappers, joinBefore, listType) {
71
+ let content = Fragment.empty;
72
+ for (let i = wrappers.length - 1; i >= 0; i--) {
73
+ content = Fragment.from(wrappers[i].type.create(wrappers[i].attrs, content));
74
+ }
75
+ tr.step(new ReplaceAroundStep(range.start - (joinBefore ? 2 : 0), range.end, range.start, range.end, new Slice(content, 0, 0), wrappers.length, true));
76
+ let found = 0;
77
+ for (let i = 0; i < wrappers.length; i++) {
78
+ if (wrappers[i].type === listType) {
79
+ found = i + 1;
80
+ }
81
+ }
82
+ const splitDepth = wrappers.length - found;
83
+ let splitPos = range.start + wrappers.length - (joinBefore ? 2 : 0);
84
+ const parent = range.parent;
85
+ for (let i = range.startIndex, e = range.endIndex, first = true; i < e; i++, first = false) {
86
+ if (!first && canSplit(tr.doc, splitPos, splitDepth)) {
87
+ tr.split(splitPos, splitDepth);
88
+ splitPos += 2 * splitDepth;
89
+ }
90
+ splitPos += parent.child(i).nodeSize;
91
+ }
92
+ return tr;
93
+ }
@@ -0,0 +1,61 @@
1
+ import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics';
2
+ import { getCommonListAnalyticsAttributes, getListItemAttributes, hasValidListIndentationLevel } from '@atlaskit/editor-common/lists';
3
+ import { PassiveTransaction } from '@atlaskit/editor-common/preset';
4
+ import { isBulletList } from '@atlaskit/editor-common/utils';
5
+ import { closeHistory } from '@atlaskit/editor-prosemirror/history';
6
+ import { indentListItemsSelected as indentListAction } from '../actions/indent-list-items-selected';
7
+ import { MAX_NESTED_LIST_INDENTATION } from '../types';
8
+ import { findFirstParentListNode } from '../utils/find';
9
+ import { isInsideListItem, isInsideTableCell } from '../utils/selection';
10
+ export const indentList = editorAnalyticsAPI => (inputMethod = INPUT_METHOD.KEYBOARD) => {
11
+ return function ({
12
+ tr
13
+ }) {
14
+ const {
15
+ selection: {
16
+ $from
17
+ }
18
+ } = tr;
19
+
20
+ // don't indent if selection is not inside a list
21
+ if (!isInsideListItem(tr)) {
22
+ return null;
23
+ }
24
+
25
+ // Save the history, so it could undo/revert to the same state before the indent, see https://product-fabric.atlassian.net/browse/ED-14753
26
+ closeHistory(tr);
27
+ const firstListItemSelectedAttributes = getListItemAttributes($from);
28
+ const parentListNode = findFirstParentListNode($from);
29
+ if (!parentListNode || firstListItemSelectedAttributes && firstListItemSelectedAttributes.indentLevel === 0 && firstListItemSelectedAttributes.itemIndex === 0) {
30
+ if (isInsideTableCell(tr)) {
31
+ // dont consume tab, as table-keymap should move cursor to next cell
32
+ return null;
33
+ } else {
34
+ // Even though this is a non-operation, we don't want to send this event to the browser. Because if we return false, the browser will move the focus to another place
35
+ return new PassiveTransaction();
36
+ }
37
+ }
38
+ const currentListNode = parentListNode.node;
39
+ const actionSubjectId = isBulletList(currentListNode) ? ACTION_SUBJECT_ID.FORMAT_LIST_BULLET : ACTION_SUBJECT_ID.FORMAT_LIST_NUMBER;
40
+ indentListAction(tr);
41
+ const maximimunNestedLevelReached = !hasValidListIndentationLevel({
42
+ tr,
43
+ maxIndentation: MAX_NESTED_LIST_INDENTATION
44
+ });
45
+ if (maximimunNestedLevelReached || !tr.docChanged) {
46
+ // Even though this is a non-operation, we don't want to send this event to the browser. Because if we return false, the browser will move the focus to another place
47
+ return new PassiveTransaction();
48
+ }
49
+ editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 ? void 0 : editorAnalyticsAPI.attachAnalyticsEvent({
50
+ action: ACTION.INDENTED,
51
+ actionSubject: ACTION_SUBJECT.LIST,
52
+ actionSubjectId,
53
+ eventType: EVENT_TYPE.TRACK,
54
+ attributes: {
55
+ ...getCommonListAnalyticsAttributes(tr),
56
+ inputMethod
57
+ }
58
+ })(tr);
59
+ return tr;
60
+ };
61
+ };