@atlaskit/editor-plugin-tasks-and-decisions 0.2.15 → 0.3.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @atlaskit/editor-plugin-tasks-and-decisions
2
2
 
3
+ ## 0.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#68790](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/68790) [`c6d8affc52d1`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/c6d8affc52d1) - Support maybeAdd plugins in usePreset. Add typing support for universal preset.
8
+
9
+ Now when using the editor API with the universal preset
10
+
11
+ ### Patch Changes
12
+
13
+ - [#69144](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/69144) [`10e7328aea8c`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/10e7328aea8c) - [ux] ED-21844 Add fix for enter keybind behaviour for nested actions inside list and relevant testcases
14
+ - Updated dependencies
15
+
16
+ ## 0.2.16
17
+
18
+ ### Patch Changes
19
+
20
+ - Updated dependencies
21
+
3
22
  ## 0.2.15
4
23
 
5
24
  ### Patch Changes
@@ -3,6 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ exports.findFirstParentListNode = findFirstParentListNode;
6
7
  exports.focusCheckboxAndUpdateSelection = focusCheckboxAndUpdateSelection;
7
8
  exports.getAllTaskItemsDataInRootTaskList = getAllTaskItemsDataInRootTaskList;
8
9
  exports.getCurrentIndentLevel = exports.getBlockRange = void 0;
@@ -296,4 +297,25 @@ function removeCheckboxFocus(view) {
296
297
  dispatch(tr.setMeta(_pluginKey.stateKey, {
297
298
  action: _types.ACTIONS.FOCUS_BY_LOCALID
298
299
  }));
300
+ }
301
+ function findFirstParentListNode($pos) {
302
+ var currentNode = $pos.doc.nodeAt($pos.pos);
303
+ var listNodePosition = null;
304
+ if ((0, _utils.isListNode)(currentNode)) {
305
+ listNodePosition = $pos.pos;
306
+ } else {
307
+ var result = (0, _utils2.findParentNodeClosestToPos)($pos, _utils.isListNode);
308
+ listNodePosition = result && result.pos;
309
+ }
310
+ if (listNodePosition == null) {
311
+ return null;
312
+ }
313
+ var node = $pos.doc.nodeAt(listNodePosition);
314
+ if (!node) {
315
+ return null;
316
+ }
317
+ return {
318
+ node: node,
319
+ pos: listNodePosition
320
+ };
299
321
  }
@@ -222,7 +222,38 @@ var unindentTaskOrUnwrapTaskDecisionFollowing = function unindentTaskOrUnwrapTas
222
222
  return false;
223
223
  };
224
224
  var deleteForwards = (0, _commands.autoJoin)((0, _commands.chainCommands)((0, _utils.deleteEmptyParagraphAndMoveBlockUp)(_helpers.isActionOrDecisionList), joinTaskDecisionFollowing, unindentTaskOrUnwrapTaskDecisionFollowing), ['taskList', 'decisionList']);
225
+ var deleteExtraListItem = function deleteExtraListItem(tr, $from) {
226
+ /*
227
+ After we replace actionItem with empty list item if there's the anomaly of extra empty list item
228
+ the cursor moves inside the first taskItem of splitted taskList
229
+ so the extra list item present above the list item containing taskList & cursor
230
+ */
231
+
232
+ var $currentFrom = tr.selection.$from;
233
+ var listItemContainingActionList = tr.doc.resolve($currentFrom.start($currentFrom.depth - 2));
234
+ var emptyListItem = tr.doc.resolve(listItemContainingActionList.before() - 1);
235
+ tr.delete(emptyListItem.start(), listItemContainingActionList.pos);
236
+ };
237
+ var processNestedActionItem = function processNestedActionItem(tr, $from, previousListItemPos) {
238
+ var parentListNode = (0, _helpers.findFirstParentListNode)($from);
239
+ var previousChildCountOfList = parentListNode === null || parentListNode === void 0 ? void 0 : parentListNode.node.childCount;
240
+ var currentParentListNode = (0, _helpers.findFirstParentListNode)(tr.doc.resolve(tr.mapping.map($from.pos)));
241
+ var currentChildCountOfList = currentParentListNode === null || currentParentListNode === void 0 ? void 0 : currentParentListNode.node.childCount;
242
+
243
+ /*
244
+ While replacing range with empty list item an extra list item gets created in some of the scenarios
245
+ After splitting only one extra listItem should be created else an extra listItem is created
246
+ */
247
+ if (previousChildCountOfList && currentChildCountOfList && previousChildCountOfList + 1 !== currentChildCountOfList) {
248
+ deleteExtraListItem(tr, $from);
249
+ }
250
+
251
+ // Set custom selection for nested action inside lists using previosuly calculated previousListItem position
252
+ var stableResolvedPos = tr.doc.resolve(previousListItemPos);
253
+ tr.setSelection(_state.TextSelection.create(tr.doc, stableResolvedPos.after() + 2));
254
+ };
225
255
  var splitListItemWith = function splitListItemWith(tr, content, $from, setSelection) {
256
+ var _frag$firstChild;
226
257
  var origDoc = tr.doc;
227
258
 
228
259
  // split just before the current item
@@ -230,7 +261,13 @@ var splitListItemWith = function splitListItemWith(tr, content, $from, setSelect
230
261
  var container = $from.node($from.depth - 2);
231
262
  var posInList = $from.index($from.depth - 1);
232
263
  var shouldSplit = !(!(0, _helpers.isActionOrDecisionList)(container) && posInList === 0);
233
- if (shouldSplit) {
264
+ var frag = _model.Fragment.from(content);
265
+ var isNestedActionInsideLists = frag.childCount === 1 && ((_frag$firstChild = frag.firstChild) === null || _frag$firstChild === void 0 ? void 0 : _frag$firstChild.type.name) === 'listItem';
266
+
267
+ /* We don't split the list item if it's nested inside lists
268
+ to have consistent behaviour and their resolution.
269
+ */
270
+ if (shouldSplit && !isNestedActionInsideLists) {
234
271
  // this only splits a node to delete it, so we probably don't need a random uuid
235
272
  // but generate one anyway for correctness
236
273
  tr = tr.split($from.pos, 1, [{
@@ -240,19 +277,25 @@ var splitListItemWith = function splitListItemWith(tr, content, $from, setSelect
240
277
  }
241
278
  }]);
242
279
  }
280
+ /*
281
+ In case of nested action inside lists we explicitly set the cursor
282
+ We need to insert it relatively to previous doc structure
283
+ So we calculate the position of previous list item and save that position
284
+ (The cursor can be placed easily next to list item)
285
+ */
286
+ var previousListItemPos = isNestedActionInsideLists ? $from.start($from.depth - 2) : 0;
287
+
243
288
  // and delete the action at the current pos
244
289
  // we can do this because we know either first new child will be taskItem or nothing at all
245
- var frag = _model.Fragment.from(content);
290
+
246
291
  tr = tr.replace(tr.mapping.map($from.start() - 2), tr.mapping.map($from.end() + 2), frag.size ? new _model.Slice(frag, 0, 0) : _model.Slice.empty);
247
292
 
248
293
  // put cursor inside paragraph
249
- if (setSelection) {
294
+ if (setSelection && !isNestedActionInsideLists) {
250
295
  tr = tr.setSelection(new _state.TextSelection(tr.doc.resolve($from.pos + 1 - (shouldSplit ? 0 : 2))));
251
296
  }
252
-
253
297
  // lift list up if the node after the initial one was a taskList
254
298
  // which means it would have empty placeholder content if we just immediately delete it
255
- //
256
299
  // if it's a taskItem then it can stand alone, so it's fine
257
300
  var $oldAfter = origDoc.resolve($from.after());
258
301
 
@@ -273,14 +316,26 @@ var splitListItemWith = function splitListItemWith(tr, content, $from, setSelect
273
316
  tr = tr.deleteRange(pos - 3, pos - 1);
274
317
  }
275
318
  }
319
+ if (isNestedActionInsideLists) {
320
+ processNestedActionItem(tr, $from, previousListItemPos);
321
+ }
276
322
  return tr;
277
323
  };
324
+ var creatParentListItemFragement = function creatParentListItemFragement(state) {
325
+ return state.schema.nodes.listItem.create({}, state.schema.nodes.paragraph.create());
326
+ };
278
327
  var splitListItem = function splitListItem(state, dispatch) {
279
328
  var tr = state.tr,
280
329
  $from = state.selection.$from;
281
330
  var paragraph = state.schema.nodes.paragraph;
331
+ var listItem = state.schema.nodes.listItem;
282
332
  if (actionDecisionFollowsOrNothing($from)) {
283
333
  if (dispatch) {
334
+ if ((0, _utils2.hasParentNodeOfType)(listItem)(tr.selection)) {
335
+ // if we're inside a list item, then we pass in a fragment containing a new list item not a paragraph
336
+ dispatch(splitListItemWith(tr, creatParentListItemFragement(state), $from, true));
337
+ return true;
338
+ }
284
339
  dispatch(splitListItemWith(tr, paragraph.createChecked(), $from, true));
285
340
  }
286
341
  return true;
@@ -1,4 +1,4 @@
1
- import { findFarthestParentNode } from '@atlaskit/editor-common/utils';
1
+ import { findFarthestParentNode, isListNode } from '@atlaskit/editor-common/utils';
2
2
  import { TextSelection } from '@atlaskit/editor-prosemirror/state';
3
3
  import { liftTarget } from '@atlaskit/editor-prosemirror/transform';
4
4
  import { findParentNodeClosestToPos, hasParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
@@ -313,4 +313,25 @@ export function removeCheckboxFocus(view) {
313
313
  dispatch(tr.setMeta(stateKey, {
314
314
  action: ACTIONS.FOCUS_BY_LOCALID
315
315
  }));
316
+ }
317
+ export function findFirstParentListNode($pos) {
318
+ const currentNode = $pos.doc.nodeAt($pos.pos);
319
+ let listNodePosition = null;
320
+ if (isListNode(currentNode)) {
321
+ listNodePosition = $pos.pos;
322
+ } else {
323
+ const result = findParentNodeClosestToPos($pos, isListNode);
324
+ listNodePosition = result && result.pos;
325
+ }
326
+ if (listNodePosition == null) {
327
+ return null;
328
+ }
329
+ const node = $pos.doc.nodeAt(listNodePosition);
330
+ if (!node) {
331
+ return null;
332
+ }
333
+ return {
334
+ node,
335
+ pos: listNodePosition
336
+ };
316
337
  }
@@ -8,11 +8,11 @@ import { autoJoin, chainCommands } from '@atlaskit/editor-prosemirror/commands';
8
8
  import { keymap } from '@atlaskit/editor-prosemirror/keymap';
9
9
  import { Fragment, Slice } from '@atlaskit/editor-prosemirror/model';
10
10
  import { TextSelection } from '@atlaskit/editor-prosemirror/state';
11
- import { findParentNodeOfType, findParentNodeOfTypeClosestToPos } from '@atlaskit/editor-prosemirror/utils';
11
+ import { findParentNodeOfType, findParentNodeOfTypeClosestToPos, hasParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
12
12
  import { insertTaskDecisionWithAnalytics } from '../commands';
13
13
  import { normalizeTaskItemsSelection } from '../utils';
14
14
  import { joinAtCut, liftSelection, wrapSelectionInTaskList } from './commands';
15
- import { getBlockRange, getCurrentIndentLevel, getTaskItemIndex, isActionOrDecisionItem, isActionOrDecisionList, isEmptyTaskDecision, isInsideDecision, isInsideTask, isInsideTaskOrDecisionItem, isTable, liftBlock, walkOut } from './helpers';
15
+ import { findFirstParentListNode, getBlockRange, getCurrentIndentLevel, getTaskItemIndex, isActionOrDecisionItem, isActionOrDecisionList, isEmptyTaskDecision, isInsideDecision, isInsideTask, isInsideTaskOrDecisionItem, isTable, liftBlock, walkOut } from './helpers';
16
16
  const indentationAnalytics = (curIndentLevel, direction, inputMethod) => ({
17
17
  action: ACTION.FORMATTED,
18
18
  actionSubject: ACTION_SUBJECT.TEXT,
@@ -197,7 +197,38 @@ const unindentTaskOrUnwrapTaskDecisionFollowing = (state, dispatch) => {
197
197
  return false;
198
198
  };
199
199
  const deleteForwards = autoJoin(chainCommands(deleteEmptyParagraphAndMoveBlockUp(isActionOrDecisionList), joinTaskDecisionFollowing, unindentTaskOrUnwrapTaskDecisionFollowing), ['taskList', 'decisionList']);
200
+ const deleteExtraListItem = (tr, $from) => {
201
+ /*
202
+ After we replace actionItem with empty list item if there's the anomaly of extra empty list item
203
+ the cursor moves inside the first taskItem of splitted taskList
204
+ so the extra list item present above the list item containing taskList & cursor
205
+ */
206
+
207
+ const $currentFrom = tr.selection.$from;
208
+ const listItemContainingActionList = tr.doc.resolve($currentFrom.start($currentFrom.depth - 2));
209
+ const emptyListItem = tr.doc.resolve(listItemContainingActionList.before() - 1);
210
+ tr.delete(emptyListItem.start(), listItemContainingActionList.pos);
211
+ };
212
+ const processNestedActionItem = (tr, $from, previousListItemPos) => {
213
+ const parentListNode = findFirstParentListNode($from);
214
+ const previousChildCountOfList = parentListNode === null || parentListNode === void 0 ? void 0 : parentListNode.node.childCount;
215
+ const currentParentListNode = findFirstParentListNode(tr.doc.resolve(tr.mapping.map($from.pos)));
216
+ const currentChildCountOfList = currentParentListNode === null || currentParentListNode === void 0 ? void 0 : currentParentListNode.node.childCount;
217
+
218
+ /*
219
+ While replacing range with empty list item an extra list item gets created in some of the scenarios
220
+ After splitting only one extra listItem should be created else an extra listItem is created
221
+ */
222
+ if (previousChildCountOfList && currentChildCountOfList && previousChildCountOfList + 1 !== currentChildCountOfList) {
223
+ deleteExtraListItem(tr, $from);
224
+ }
225
+
226
+ // Set custom selection for nested action inside lists using previosuly calculated previousListItem position
227
+ const stableResolvedPos = tr.doc.resolve(previousListItemPos);
228
+ tr.setSelection(TextSelection.create(tr.doc, stableResolvedPos.after() + 2));
229
+ };
200
230
  const splitListItemWith = (tr, content, $from, setSelection) => {
231
+ var _frag$firstChild;
201
232
  const origDoc = tr.doc;
202
233
 
203
234
  // split just before the current item
@@ -205,7 +236,13 @@ const splitListItemWith = (tr, content, $from, setSelection) => {
205
236
  const container = $from.node($from.depth - 2);
206
237
  const posInList = $from.index($from.depth - 1);
207
238
  const shouldSplit = !(!isActionOrDecisionList(container) && posInList === 0);
208
- if (shouldSplit) {
239
+ const frag = Fragment.from(content);
240
+ const isNestedActionInsideLists = frag.childCount === 1 && ((_frag$firstChild = frag.firstChild) === null || _frag$firstChild === void 0 ? void 0 : _frag$firstChild.type.name) === 'listItem';
241
+
242
+ /* We don't split the list item if it's nested inside lists
243
+ to have consistent behaviour and their resolution.
244
+ */
245
+ if (shouldSplit && !isNestedActionInsideLists) {
209
246
  // this only splits a node to delete it, so we probably don't need a random uuid
210
247
  // but generate one anyway for correctness
211
248
  tr = tr.split($from.pos, 1, [{
@@ -215,19 +252,25 @@ const splitListItemWith = (tr, content, $from, setSelection) => {
215
252
  }
216
253
  }]);
217
254
  }
255
+ /*
256
+ In case of nested action inside lists we explicitly set the cursor
257
+ We need to insert it relatively to previous doc structure
258
+ So we calculate the position of previous list item and save that position
259
+ (The cursor can be placed easily next to list item)
260
+ */
261
+ const previousListItemPos = isNestedActionInsideLists ? $from.start($from.depth - 2) : 0;
262
+
218
263
  // and delete the action at the current pos
219
264
  // we can do this because we know either first new child will be taskItem or nothing at all
220
- const frag = Fragment.from(content);
265
+
221
266
  tr = tr.replace(tr.mapping.map($from.start() - 2), tr.mapping.map($from.end() + 2), frag.size ? new Slice(frag, 0, 0) : Slice.empty);
222
267
 
223
268
  // put cursor inside paragraph
224
- if (setSelection) {
269
+ if (setSelection && !isNestedActionInsideLists) {
225
270
  tr = tr.setSelection(new TextSelection(tr.doc.resolve($from.pos + 1 - (shouldSplit ? 0 : 2))));
226
271
  }
227
-
228
272
  // lift list up if the node after the initial one was a taskList
229
273
  // which means it would have empty placeholder content if we just immediately delete it
230
- //
231
274
  // if it's a taskItem then it can stand alone, so it's fine
232
275
  const $oldAfter = origDoc.resolve($from.after());
233
276
 
@@ -248,8 +291,14 @@ const splitListItemWith = (tr, content, $from, setSelection) => {
248
291
  tr = tr.deleteRange(pos - 3, pos - 1);
249
292
  }
250
293
  }
294
+ if (isNestedActionInsideLists) {
295
+ processNestedActionItem(tr, $from, previousListItemPos);
296
+ }
251
297
  return tr;
252
298
  };
299
+ const creatParentListItemFragement = state => {
300
+ return state.schema.nodes.listItem.create({}, state.schema.nodes.paragraph.create());
301
+ };
253
302
  const splitListItem = (state, dispatch) => {
254
303
  let {
255
304
  tr,
@@ -264,8 +313,16 @@ const splitListItem = (state, dispatch) => {
264
313
  }
265
314
  }
266
315
  } = state;
316
+ const {
317
+ listItem
318
+ } = state.schema.nodes;
267
319
  if (actionDecisionFollowsOrNothing($from)) {
268
320
  if (dispatch) {
321
+ if (hasParentNodeOfType(listItem)(tr.selection)) {
322
+ // if we're inside a list item, then we pass in a fragment containing a new list item not a paragraph
323
+ dispatch(splitListItemWith(tr, creatParentListItemFragement(state), $from, true));
324
+ return true;
325
+ }
269
326
  dispatch(splitListItemWith(tr, paragraph.createChecked(), $from, true));
270
327
  }
271
328
  return true;
@@ -1,4 +1,4 @@
1
- import { findFarthestParentNode } from '@atlaskit/editor-common/utils';
1
+ import { findFarthestParentNode, isListNode } from '@atlaskit/editor-common/utils';
2
2
  import { TextSelection } from '@atlaskit/editor-prosemirror/state';
3
3
  import { liftTarget } from '@atlaskit/editor-prosemirror/transform';
4
4
  import { findParentNodeClosestToPos, hasParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
@@ -282,4 +282,25 @@ export function removeCheckboxFocus(view) {
282
282
  dispatch(tr.setMeta(stateKey, {
283
283
  action: ACTIONS.FOCUS_BY_LOCALID
284
284
  }));
285
+ }
286
+ export function findFirstParentListNode($pos) {
287
+ var currentNode = $pos.doc.nodeAt($pos.pos);
288
+ var listNodePosition = null;
289
+ if (isListNode(currentNode)) {
290
+ listNodePosition = $pos.pos;
291
+ } else {
292
+ var result = findParentNodeClosestToPos($pos, isListNode);
293
+ listNodePosition = result && result.pos;
294
+ }
295
+ if (listNodePosition == null) {
296
+ return null;
297
+ }
298
+ var node = $pos.doc.nodeAt(listNodePosition);
299
+ if (!node) {
300
+ return null;
301
+ }
302
+ return {
303
+ node: node,
304
+ pos: listNodePosition
305
+ };
285
306
  }
@@ -11,11 +11,11 @@ import { autoJoin, chainCommands } from '@atlaskit/editor-prosemirror/commands';
11
11
  import { keymap } from '@atlaskit/editor-prosemirror/keymap';
12
12
  import { Fragment, Slice } from '@atlaskit/editor-prosemirror/model';
13
13
  import { TextSelection } from '@atlaskit/editor-prosemirror/state';
14
- import { findParentNodeOfType, findParentNodeOfTypeClosestToPos } from '@atlaskit/editor-prosemirror/utils';
14
+ import { findParentNodeOfType, findParentNodeOfTypeClosestToPos, hasParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
15
15
  import { insertTaskDecisionWithAnalytics } from '../commands';
16
16
  import { normalizeTaskItemsSelection } from '../utils';
17
17
  import { joinAtCut, liftSelection, wrapSelectionInTaskList } from './commands';
18
- import { getBlockRange, getCurrentIndentLevel, getTaskItemIndex, isActionOrDecisionItem, isActionOrDecisionList, isEmptyTaskDecision, isInsideDecision, isInsideTask, isInsideTaskOrDecisionItem, isTable, liftBlock, walkOut } from './helpers';
18
+ import { findFirstParentListNode, getBlockRange, getCurrentIndentLevel, getTaskItemIndex, isActionOrDecisionItem, isActionOrDecisionList, isEmptyTaskDecision, isInsideDecision, isInsideTask, isInsideTaskOrDecisionItem, isTable, liftBlock, walkOut } from './helpers';
19
19
  var indentationAnalytics = function indentationAnalytics(curIndentLevel, direction, inputMethod) {
20
20
  return {
21
21
  action: ACTION.FORMATTED,
@@ -214,7 +214,38 @@ var unindentTaskOrUnwrapTaskDecisionFollowing = function unindentTaskOrUnwrapTas
214
214
  return false;
215
215
  };
216
216
  var deleteForwards = autoJoin(chainCommands(deleteEmptyParagraphAndMoveBlockUp(isActionOrDecisionList), joinTaskDecisionFollowing, unindentTaskOrUnwrapTaskDecisionFollowing), ['taskList', 'decisionList']);
217
+ var deleteExtraListItem = function deleteExtraListItem(tr, $from) {
218
+ /*
219
+ After we replace actionItem with empty list item if there's the anomaly of extra empty list item
220
+ the cursor moves inside the first taskItem of splitted taskList
221
+ so the extra list item present above the list item containing taskList & cursor
222
+ */
223
+
224
+ var $currentFrom = tr.selection.$from;
225
+ var listItemContainingActionList = tr.doc.resolve($currentFrom.start($currentFrom.depth - 2));
226
+ var emptyListItem = tr.doc.resolve(listItemContainingActionList.before() - 1);
227
+ tr.delete(emptyListItem.start(), listItemContainingActionList.pos);
228
+ };
229
+ var processNestedActionItem = function processNestedActionItem(tr, $from, previousListItemPos) {
230
+ var parentListNode = findFirstParentListNode($from);
231
+ var previousChildCountOfList = parentListNode === null || parentListNode === void 0 ? void 0 : parentListNode.node.childCount;
232
+ var currentParentListNode = findFirstParentListNode(tr.doc.resolve(tr.mapping.map($from.pos)));
233
+ var currentChildCountOfList = currentParentListNode === null || currentParentListNode === void 0 ? void 0 : currentParentListNode.node.childCount;
234
+
235
+ /*
236
+ While replacing range with empty list item an extra list item gets created in some of the scenarios
237
+ After splitting only one extra listItem should be created else an extra listItem is created
238
+ */
239
+ if (previousChildCountOfList && currentChildCountOfList && previousChildCountOfList + 1 !== currentChildCountOfList) {
240
+ deleteExtraListItem(tr, $from);
241
+ }
242
+
243
+ // Set custom selection for nested action inside lists using previosuly calculated previousListItem position
244
+ var stableResolvedPos = tr.doc.resolve(previousListItemPos);
245
+ tr.setSelection(TextSelection.create(tr.doc, stableResolvedPos.after() + 2));
246
+ };
217
247
  var splitListItemWith = function splitListItemWith(tr, content, $from, setSelection) {
248
+ var _frag$firstChild;
218
249
  var origDoc = tr.doc;
219
250
 
220
251
  // split just before the current item
@@ -222,7 +253,13 @@ var splitListItemWith = function splitListItemWith(tr, content, $from, setSelect
222
253
  var container = $from.node($from.depth - 2);
223
254
  var posInList = $from.index($from.depth - 1);
224
255
  var shouldSplit = !(!isActionOrDecisionList(container) && posInList === 0);
225
- if (shouldSplit) {
256
+ var frag = Fragment.from(content);
257
+ var isNestedActionInsideLists = frag.childCount === 1 && ((_frag$firstChild = frag.firstChild) === null || _frag$firstChild === void 0 ? void 0 : _frag$firstChild.type.name) === 'listItem';
258
+
259
+ /* We don't split the list item if it's nested inside lists
260
+ to have consistent behaviour and their resolution.
261
+ */
262
+ if (shouldSplit && !isNestedActionInsideLists) {
226
263
  // this only splits a node to delete it, so we probably don't need a random uuid
227
264
  // but generate one anyway for correctness
228
265
  tr = tr.split($from.pos, 1, [{
@@ -232,19 +269,25 @@ var splitListItemWith = function splitListItemWith(tr, content, $from, setSelect
232
269
  }
233
270
  }]);
234
271
  }
272
+ /*
273
+ In case of nested action inside lists we explicitly set the cursor
274
+ We need to insert it relatively to previous doc structure
275
+ So we calculate the position of previous list item and save that position
276
+ (The cursor can be placed easily next to list item)
277
+ */
278
+ var previousListItemPos = isNestedActionInsideLists ? $from.start($from.depth - 2) : 0;
279
+
235
280
  // and delete the action at the current pos
236
281
  // we can do this because we know either first new child will be taskItem or nothing at all
237
- var frag = Fragment.from(content);
282
+
238
283
  tr = tr.replace(tr.mapping.map($from.start() - 2), tr.mapping.map($from.end() + 2), frag.size ? new Slice(frag, 0, 0) : Slice.empty);
239
284
 
240
285
  // put cursor inside paragraph
241
- if (setSelection) {
286
+ if (setSelection && !isNestedActionInsideLists) {
242
287
  tr = tr.setSelection(new TextSelection(tr.doc.resolve($from.pos + 1 - (shouldSplit ? 0 : 2))));
243
288
  }
244
-
245
289
  // lift list up if the node after the initial one was a taskList
246
290
  // which means it would have empty placeholder content if we just immediately delete it
247
- //
248
291
  // if it's a taskItem then it can stand alone, so it's fine
249
292
  var $oldAfter = origDoc.resolve($from.after());
250
293
 
@@ -265,14 +308,26 @@ var splitListItemWith = function splitListItemWith(tr, content, $from, setSelect
265
308
  tr = tr.deleteRange(pos - 3, pos - 1);
266
309
  }
267
310
  }
311
+ if (isNestedActionInsideLists) {
312
+ processNestedActionItem(tr, $from, previousListItemPos);
313
+ }
268
314
  return tr;
269
315
  };
316
+ var creatParentListItemFragement = function creatParentListItemFragement(state) {
317
+ return state.schema.nodes.listItem.create({}, state.schema.nodes.paragraph.create());
318
+ };
270
319
  var splitListItem = function splitListItem(state, dispatch) {
271
320
  var tr = state.tr,
272
321
  $from = state.selection.$from;
273
322
  var paragraph = state.schema.nodes.paragraph;
323
+ var listItem = state.schema.nodes.listItem;
274
324
  if (actionDecisionFollowsOrNothing($from)) {
275
325
  if (dispatch) {
326
+ if (hasParentNodeOfType(listItem)(tr.selection)) {
327
+ // if we're inside a list item, then we pass in a fragment containing a new list item not a paragraph
328
+ dispatch(splitListItemWith(tr, creatParentListItemFragement(state), $from, true));
329
+ return true;
330
+ }
276
331
  dispatch(splitListItemWith(tr, paragraph.createChecked(), $from, true));
277
332
  }
278
333
  return true;
@@ -1,2 +1,2 @@
1
1
  export { tasksAndDecisionsPlugin } from './plugin';
2
- export type { TasksAndDecisionsPlugin } from './types';
2
+ export type { TasksAndDecisionsPlugin, TaskDecisionPluginOptions, TaskAndDecisionsSharedState, TaskDecisionListType, AddItemTransactionCreator, } from './types';
@@ -74,3 +74,7 @@ export declare function getTaskItemDataToFocus(view: EditorView, direction: 'nex
74
74
  } | undefined;
75
75
  export declare function focusCheckboxAndUpdateSelection(view: EditorView, taskItemData: TaskItemData): void;
76
76
  export declare function removeCheckboxFocus(view: EditorView): void;
77
+ export declare function findFirstParentListNode($pos: ResolvedPos): {
78
+ pos: number;
79
+ node: Node;
80
+ } | null;
@@ -1,2 +1,2 @@
1
1
  export { tasksAndDecisionsPlugin } from './plugin';
2
- export type { TasksAndDecisionsPlugin } from './types';
2
+ export type { TasksAndDecisionsPlugin, TaskDecisionPluginOptions, TaskAndDecisionsSharedState, TaskDecisionListType, AddItemTransactionCreator, } from './types';
@@ -74,3 +74,7 @@ export declare function getTaskItemDataToFocus(view: EditorView, direction: 'nex
74
74
  } | undefined;
75
75
  export declare function focusCheckboxAndUpdateSelection(view: EditorView, taskItemData: TaskItemData): void;
76
76
  export declare function removeCheckboxFocus(view: EditorView): void;
77
+ export declare function findFirstParentListNode($pos: ResolvedPos): {
78
+ pos: number;
79
+ node: Node;
80
+ } | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-tasks-and-decisions",
3
- "version": "0.2.15",
3
+ "version": "0.3.0",
4
4
  "description": "Tasks and decisions plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -36,7 +36,7 @@
36
36
  "@atlaskit/adf-schema": "^35.3.0",
37
37
  "@atlaskit/analytics-namespaced-context": "^6.9.0",
38
38
  "@atlaskit/analytics-next": "^9.1.0",
39
- "@atlaskit/editor-common": "^76.41.0",
39
+ "@atlaskit/editor-common": "^77.1.0",
40
40
  "@atlaskit/editor-plugin-analytics": "^0.4.0",
41
41
  "@atlaskit/editor-plugin-type-ahead": "^0.9.0",
42
42
  "@atlaskit/editor-prosemirror": "1.1.0",