@atlaskit/editor-plugin-list 0.2.0 → 1.0.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 +10 -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 +291 -0
  16. package/dist/cjs/actions/wrap-and-join-lists.js +100 -0
  17. package/dist/cjs/commands/indent-list.js +71 -0
  18. package/dist/cjs/commands/index.js +350 -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 +70 -0
  23. package/dist/cjs/index.js +8 -1
  24. package/dist/cjs/messages.js +37 -0
  25. package/dist/cjs/plugin.js +133 -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 +295 -0
  51. package/dist/es2019/actions/wrap-and-join-lists.js +93 -0
  52. package/dist/es2019/commands/indent-list.js +62 -0
  53. package/dist/es2019/commands/index.js +326 -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 +121 -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 +283 -0
  86. package/dist/esm/actions/wrap-and-join-lists.js +94 -0
  87. package/dist/esm/commands/indent-list.js +63 -0
  88. package/dist/esm/commands/index.js +324 -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 +62 -0
  93. package/dist/esm/index.js +1 -1
  94. package/dist/esm/messages.js +29 -0
  95. package/dist/esm/plugin.js +126 -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 +16 -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 +4 -6
  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 +16 -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 +4 -6
  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 +6 -2
  181. package/tmp/api-report-tmp.d.ts +4 -1
@@ -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,295 @@
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, state, 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
+ state,
49
+ featureFlags
50
+ });
51
+ hasNormalizedToPositionLiftedOut = hasNormalizedToPositionLiftedOut || oldTo >= range.from && oldTo < range.to;
52
+ hasNormalizedFromPositionLiftedOut = hasNormalizedFromPositionLiftedOut || oldFrom >= range.from && oldFrom < range.to;
53
+ }
54
+ });
55
+ const hasCommonListMoved = commonList.start !== tr.mapping.map(commonList.start);
56
+ const nextSelection = calculateNewSelection({
57
+ originalSelection,
58
+ normalizedSelection,
59
+ tr,
60
+ hasCommonListMoved,
61
+ hasNormalizedToPositionLiftedOut,
62
+ hasNormalizedFromPositionLiftedOut
63
+ });
64
+ tr.setSelection(nextSelection);
65
+ joinSiblingLists({
66
+ tr,
67
+ direction: JoinDirection.RIGHT
68
+ });
69
+ };
70
+ const calculateNewSelection = ({
71
+ tr,
72
+ originalSelection,
73
+ normalizedSelection,
74
+ hasCommonListMoved,
75
+ hasNormalizedToPositionLiftedOut,
76
+ hasNormalizedFromPositionLiftedOut
77
+ }) => {
78
+ const {
79
+ $from,
80
+ $to
81
+ } = normalizedSelection;
82
+ const isCursorSelection = normalizedSelection.empty;
83
+ let from = tr.mapping.map($from.pos);
84
+ let to = tr.mapping.map($to.pos);
85
+ const LIST_STRUCTURE_CHANGED_OFFSET = 2;
86
+ const isToFromSameListItem = $from.sameParent($to);
87
+ if (hasNormalizedFromPositionLiftedOut) {
88
+ const fromMapped = isToFromSameListItem ? $from.pos : from;
89
+ from = hasNormalizedFromPositionLiftedOut ? $from.pos : fromMapped;
90
+ from = hasCommonListMoved ? from - LIST_STRUCTURE_CHANGED_OFFSET : from;
91
+ from = Math.max(from, 0);
92
+ }
93
+ if (hasNormalizedToPositionLiftedOut) {
94
+ const toMapped = isToFromSameListItem ? $to.pos : to;
95
+ to = hasNormalizedToPositionLiftedOut ? $to.pos : toMapped;
96
+ to = hasCommonListMoved ? to - LIST_STRUCTURE_CHANGED_OFFSET : to;
97
+ to = Math.min(to, tr.doc.nodeSize - 2);
98
+ }
99
+ if (normalizedSelection instanceof GapCursorSelection) {
100
+ const nextSelectionFrom = tr.doc.resolve(from);
101
+ return new GapCursorSelection(nextSelectionFrom, normalizedSelection.side);
102
+ }
103
+ if (originalSelection instanceof NodeSelection) {
104
+ return NodeSelection.create(tr.doc, from);
105
+ }
106
+ if (isCursorSelection) {
107
+ return TextSelection.between(tr.doc.resolve(to), tr.doc.resolve(to), -1);
108
+ }
109
+ return TextSelection.between(tr.doc.resolve(from), tr.doc.resolve(to), -1);
110
+ };
111
+ const splitRangeSelection = selection => {
112
+ const commonListRange = createListNodeRange({
113
+ selection
114
+ });
115
+ if (!commonListRange) {
116
+ return [];
117
+ }
118
+ const {
119
+ $from,
120
+ $to
121
+ } = selection;
122
+ if ($from.pos === $to.pos && $from.sameParent($to)) {
123
+ return [{
124
+ from: commonListRange.start,
125
+ to: commonListRange.end,
126
+ depth: commonListRange.depth
127
+ }];
128
+ }
129
+ const lastListItem = findPreviousListItemSibling($from);
130
+ if (!lastListItem) {
131
+ return [];
132
+ }
133
+ const nodeRanges = [];
134
+ const {
135
+ doc
136
+ } = $from;
137
+ let previousListItem = findPreviousListItemSibling($to);
138
+ while (previousListItem && previousListItem.pos >= lastListItem.pos && previousListItem.pos >= commonListRange.start) {
139
+ const node = doc.nodeAt(previousListItem.pos);
140
+ if (!node || !isListItemNode(node)) {
141
+ return [];
142
+ }
143
+ let offset = 0;
144
+ if (node && node.lastChild && isListNode(node.lastChild)) {
145
+ offset = node.lastChild.nodeSize;
146
+ }
147
+ const start = previousListItem.pos + 1;
148
+ nodeRanges.push({
149
+ from: start,
150
+ to: doc.resolve(start).end() - offset,
151
+ depth: previousListItem.depth
152
+ });
153
+ previousListItem = findPreviousListItemSibling(previousListItem);
154
+ }
155
+ return nodeRanges;
156
+ };
157
+ const outdentRangeToParentList = ({
158
+ tr,
159
+ range
160
+ }) => {
161
+ const end = range.end;
162
+ const endOfList = range.$to.end(range.depth);
163
+ const {
164
+ listItem
165
+ } = tr.doc.type.schema.nodes;
166
+ if (end < endOfList) {
167
+ const slice = new Slice(Fragment.from(listItem.create(null, range.parent.copy())), 1, 0);
168
+ const step = new ReplaceAroundStep(end - 1, endOfList, end, endOfList, slice, 1, true);
169
+ tr.step(step);
170
+ range = new NodeRange(tr.doc.resolve(range.$from.pos), tr.doc.resolve(endOfList), range.depth);
171
+ }
172
+ const target = liftTarget(range);
173
+ if (target) {
174
+ tr.lift(range, target);
175
+ }
176
+ };
177
+ const extractListItemsRangeFromList = ({
178
+ tr,
179
+ range,
180
+ state,
181
+ featureFlags
182
+ }) => {
183
+ const list = range.parent;
184
+ const $start = tr.doc.resolve(range.start);
185
+ const listStart = $start.start(range.depth);
186
+ const listEnd = $start.end(range.depth);
187
+ const isAtTop = listStart === range.start;
188
+ const isAtBottom = listEnd === range.end;
189
+ const isTheEntireList = isAtTop && isAtBottom;
190
+ let listItemContent = isAtTop ? Fragment.empty : Fragment.from(list.copy(Fragment.empty));
191
+ for (let i = range.startIndex; i < range.endIndex; i++) {
192
+ listItemContent = listItemContent.append(list.child(i).content);
193
+ }
194
+ if (isAtTop) {
195
+ for (let i = 0; i < listItemContent.childCount; i++) {
196
+ const child = listItemContent.child(i);
197
+ if (child && isListNode(child) && child.type !== list.type) {
198
+ const newNestedList = list.type.create(null, child.content);
199
+ listItemContent = listItemContent.replaceChild(i, newNestedList);
200
+ }
201
+ }
202
+ }
203
+ let nextList = list.copy(Fragment.empty);
204
+ let nextListStartNumber;
205
+ if (featureFlags !== null && featureFlags !== void 0 && featureFlags.restartNumberedLists) {
206
+ // if splitting a numbered list, keep the splitted item
207
+ // counter as the start of the next (second half) list (instead
208
+ // of reverting back to 1 as a starting number)
209
+ const order = getOrderFromOrderedListNode(list);
210
+ if (list.type.name === 'orderedList') {
211
+ nextListStartNumber = range.endIndex - 1 + order;
212
+ // @ts-ignore - [unblock prosemirror bump] assigning to readonly attrs
213
+ nextList.attrs = {
214
+ ...nextList.attrs,
215
+ order: nextListStartNumber
216
+ };
217
+ const {
218
+ splitListStartNumber
219
+ } = getRestartListsAttributes(tr);
220
+ if (typeof splitListStartNumber !== 'number') {
221
+ storeRestartListsAttributes(tr, {
222
+ splitListStartNumber: nextListStartNumber
223
+ });
224
+ }
225
+ }
226
+ }
227
+ const nextListFragment = listItemContent.append(Fragment.from(nextList));
228
+ if (featureFlags !== null && featureFlags !== void 0 && featureFlags.restartNumberedLists) {
229
+ // if the split list with nextListStartNumber is below another list
230
+ // with order (e.g due to multi-level indent items being lifted), track the
231
+ // list above's order instead, as it will be the split list's order after sibling joins
232
+ nextListFragment.forEach((node, _offset, index) => {
233
+ var _node$attrs;
234
+ if (node.type.name === 'orderedList' && ((_node$attrs = node.attrs) === null || _node$attrs === void 0 ? void 0 : _node$attrs.order) === nextListStartNumber) {
235
+ var _prev$attrs;
236
+ const prev = nextListFragment.child(index - 1);
237
+ if ((prev === null || prev === void 0 ? void 0 : (_prev$attrs = prev.attrs) === null || _prev$attrs === void 0 ? void 0 : _prev$attrs.order) >= 0) {
238
+ var _prev$attrs2;
239
+ storeRestartListsAttributes(tr, {
240
+ splitListStartNumber: prev === null || prev === void 0 ? void 0 : (_prev$attrs2 = prev.attrs) === null || _prev$attrs2 === void 0 ? void 0 : _prev$attrs2.order
241
+ });
242
+ }
243
+ }
244
+ });
245
+ }
246
+ if (isTheEntireList) {
247
+ const slice = new Slice(listItemContent, 0, 0);
248
+ const step = new ReplaceStep($start.pos - 1, range.end + 1, slice, false);
249
+ if (featureFlags !== null && featureFlags !== void 0 && featureFlags.restartNumberedLists) {
250
+ storeRestartListsAttributes(tr, {
251
+ outdentScenario: undefined
252
+ });
253
+ }
254
+ tr.step(step);
255
+ } else if (isAtTop) {
256
+ const slice = new Slice(nextListFragment, 0, 1);
257
+ const step = new ReplaceStep($start.pos - 1, range.end, slice, false);
258
+ tr.step(step);
259
+ } else if (isAtBottom) {
260
+ const slice = new Slice(listItemContent, 1, 0);
261
+ const step = new ReplaceStep($start.pos, listEnd + 1, slice, false);
262
+ tr.step(step);
263
+ } else {
264
+ if (featureFlags !== null && featureFlags !== void 0 && featureFlags.restartNumberedLists) {
265
+ storeRestartListsAttributes(tr, {
266
+ outdentScenario: OUTDENT_SCENARIOS.SPLIT_LIST
267
+ });
268
+ }
269
+ const slice = new Slice(nextListFragment, 1, 1);
270
+ const step = new ReplaceAroundStep($start.pos, listEnd, range.end, listEnd, slice, slice.size, false);
271
+ tr.step(step);
272
+ }
273
+ };
274
+ const findPreviousListItemSibling = $pos => {
275
+ const doc = $pos.doc;
276
+ const isPositionListItem = isListNode($pos.node());
277
+ let listItemPosition = $pos;
278
+ if (!isPositionListItem) {
279
+ const listItem = findFirstParentListItemNode($pos);
280
+ if (!listItem) {
281
+ return null;
282
+ }
283
+ return doc.resolve(listItem.pos);
284
+ }
285
+ const resolved = doc.resolve(listItemPosition.pos);
286
+ const foundPosition = Selection.findFrom(resolved, -1);
287
+ if (!foundPosition) {
288
+ return null;
289
+ }
290
+ const parentListItemNode = findFirstParentListItemNode(foundPosition.$from);
291
+ if (!parentListItemNode) {
292
+ return null;
293
+ }
294
+ return doc.resolve(parentListItemNode.pos);
295
+ };
@@ -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,62 @@
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 { isBulletList } from '@atlaskit/editor-common/utils';
4
+ import { closeHistory } from '@atlaskit/editor-prosemirror/history';
5
+ import { indentListItemsSelected as indentListAction } from '../actions/indent-list-items-selected';
6
+ import { MAX_NESTED_LIST_INDENTATION } from '../types';
7
+ import { findFirstParentListNode } from '../utils/find';
8
+ import { isInsideListItem, isInsideTableCell } from '../utils/selection';
9
+ export const indentList = editorAnalyticsAPI => (inputMethod = INPUT_METHOD.KEYBOARD) => {
10
+ return function (state, dispatch) {
11
+ const {
12
+ tr,
13
+ selection: {
14
+ $from
15
+ }
16
+ } = state;
17
+
18
+ // don't indent if selection is not inside a list
19
+ if (!isInsideListItem(state)) {
20
+ return false;
21
+ }
22
+
23
+ // Save the history, so it could undo/revert to the same state before the indent, see https://product-fabric.atlassian.net/browse/ED-14753
24
+ closeHistory(tr);
25
+ const firstListItemSelectedAttributes = getListItemAttributes($from);
26
+ const parentListNode = findFirstParentListNode($from);
27
+ if (!parentListNode || firstListItemSelectedAttributes && firstListItemSelectedAttributes.indentLevel === 0 && firstListItemSelectedAttributes.itemIndex === 0) {
28
+ if (isInsideTableCell(state)) {
29
+ // dont consume tab, as table-keymap should move cursor to next cell
30
+ return false;
31
+ } else {
32
+ // 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
33
+ return true;
34
+ }
35
+ }
36
+ const currentListNode = parentListNode.node;
37
+ const actionSubjectId = isBulletList(currentListNode) ? ACTION_SUBJECT_ID.FORMAT_LIST_BULLET : ACTION_SUBJECT_ID.FORMAT_LIST_NUMBER;
38
+ indentListAction(tr);
39
+ const maximimunNestedLevelReached = !hasValidListIndentationLevel({
40
+ tr,
41
+ maxIndentation: MAX_NESTED_LIST_INDENTATION
42
+ });
43
+ if (maximimunNestedLevelReached || !tr.docChanged) {
44
+ // 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
45
+ return true;
46
+ }
47
+ editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 ? void 0 : editorAnalyticsAPI.attachAnalyticsEvent({
48
+ action: ACTION.INDENTED,
49
+ actionSubject: ACTION_SUBJECT.LIST,
50
+ actionSubjectId,
51
+ eventType: EVENT_TYPE.TRACK,
52
+ attributes: {
53
+ ...getCommonListAnalyticsAttributes(state),
54
+ inputMethod
55
+ }
56
+ })(tr);
57
+ if (dispatch) {
58
+ dispatch(tr);
59
+ }
60
+ return true;
61
+ };
62
+ };