@atlaskit/editor-plugin-tasks-and-decisions 8.4.9 → 9.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @atlaskit/editor-plugin-tasks-and-decisions
2
2
 
3
+ ## 9.0.0
4
+
5
+ ### Patch Changes
6
+
7
+ - [`133f7636e3a6c`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/133f7636e3a6c) -
8
+ [ux] EDITOR-1750 Refactoring and improving delete key behaviours for block task item
9
+ - Updated dependencies
10
+
11
+ ## 8.5.0
12
+
13
+ ### Minor Changes
14
+
15
+ - [`687c1b8fa7801`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/687c1b8fa7801) -
16
+ EDITOR-1566 bump adf-schema + update validator
17
+
18
+ ### Patch Changes
19
+
20
+ - Updated dependencies
21
+
3
22
  ## 8.4.9
4
23
 
5
24
  ### Patch Changes
@@ -225,6 +225,7 @@ var backspaceFrom = function backspaceFrom(editorAnalyticsAPI) {
225
225
  var _slice;
226
226
  try {
227
227
  _slice = _taskContent.size ? paragraph.createChecked(undefined, _taskContent) : paragraph.createChecked();
228
+
228
229
  // might be end of document after
229
230
  var _tr2 = splitListItemWith(state.tr, _slice, $from, true);
230
231
  dispatch(_tr2);
@@ -260,40 +261,131 @@ var unindentTaskOrUnwrapTaskDecisionFollowing = function unindentTaskOrUnwrapTas
260
261
  taskList = _state$schema$nodes4.taskList,
261
262
  doc = _state$schema$nodes4.doc,
262
263
  paragraph = _state$schema$nodes4.paragraph,
264
+ blockTaskItem = _state$schema$nodes4.blockTaskItem,
265
+ taskItem = _state$schema$nodes4.taskItem,
263
266
  tr = state.tr;
267
+ if ((0, _platformFeatureFlags.fg)('platform_editor_blocktaskitem_patch_3')) {
268
+ var _$next$node, _$from$node, _$next$node2, _$from$node2, _$next$node3;
269
+ // only run if cursor is at the end of the node
270
+ if (!(0, _utils.isEmptySelectionAtEnd)(state) || !dispatch) {
271
+ return false;
272
+ }
264
273
 
265
- // only run if cursor is at the end of the node
266
- if (!(0, _utils.isEmptySelectionAtEnd)(state) || !dispatch) {
267
- return false;
268
- }
274
+ // look for the node after this current one
275
+ var $next = (0, _helpers.walkOut)($from);
269
276
 
270
- // look for the node after this current one
271
- var $next = (0, _helpers.walkOut)($from);
277
+ // this is a top-level node it wont have $next.before()
278
+ if (!$next.parent || $next.parent.type === doc) {
279
+ return false;
280
+ }
272
281
 
273
- // this is a top-level node it wont have $next.before()
274
- if (!$next.parent || $next.parent.type === doc) {
275
- return false;
276
- }
282
+ // get resolved position of parent
283
+ var $parentPos = $from.doc.resolve($from.start($from.depth - 1));
284
+ var currentNode = $from.node();
285
+ var parentNode = $parentPos.node();
277
286
 
278
- // if nested, just unindent
279
- if ($next.node($next.depth - 2).type === taskList ||
280
- // this is for the case when we are on a non-nested item and next one is nested
281
- $next.node($next.depth - 1).type === taskList && $next.parent.type === taskList) {
282
- (0, _helpers.liftBlock)(tr, $next, $next);
283
- dispatch(tr);
284
- return true;
285
- }
287
+ // if current position isn't an action or decision item, return false
288
+ if (!(0, _helpers.isActionOrDecisionItem)(currentNode) && !(0, _helpers.isActionOrDecisionItem)(parentNode)) {
289
+ return false;
290
+ }
291
+ var resultOfCurrentFindBlockTaskItem = (0, _utils3.findBlockTaskItem)($next);
292
+ var isCurrentEmptyBlockTaskItem = false;
293
+ if (resultOfCurrentFindBlockTaskItem) {
294
+ var _blockTaskItemNode$fi;
295
+ var blockTaskItemNode = resultOfCurrentFindBlockTaskItem.blockTaskItemNode;
296
+ isCurrentEmptyBlockTaskItem = blockTaskItem && blockTaskItemNode && blockTaskItemNode.childCount === 1 && ((_blockTaskItemNode$fi = blockTaskItemNode.firstChild) === null || _blockTaskItemNode$fi === void 0 ? void 0 : _blockTaskItemNode$fi.type) === paragraph && blockTaskItemNode.firstChild.childCount === 0;
297
+ }
298
+ var isEmptyActionOrDecisionItem = currentNode && (0, _helpers.isActionOrDecisionItem)(currentNode) && currentNode.childCount === 0;
299
+
300
+ // If empty item, use default handler
301
+ if (isEmptyActionOrDecisionItem || isCurrentEmptyBlockTaskItem) {
302
+ return false;
303
+ }
286
304
 
287
- // if next node is of same type, remove the node wrapping and create paragraph
288
- if (!(0, _helpers.isTable)($next.nodeAfter) && (0, _helpers.isActionOrDecisionItem)($from.parent) && actionDecisionFollowsOrNothing($from) &&
289
- // only forward delete if the node is same type
290
- $next.node().type.name === $from.node().type.name) {
291
- var taskContent = state.doc.slice($next.start(), $next.end()).content;
305
+ // Check if next node is a blockTaskItem paragraph
306
+ var resultOfNextFindBlockTaskItem = (0, _utils3.findBlockTaskItem)($next);
307
+ var isNextInBlockTaskItemParagraph = resultOfNextFindBlockTaskItem && (resultOfNextFindBlockTaskItem === null || resultOfNextFindBlockTaskItem === void 0 ? void 0 : resultOfNextFindBlockTaskItem.hasParagraph);
292
308
 
293
- // might be end of document after
294
- var slice = taskContent.size ? paragraph.createChecked(undefined, taskContent) : [];
295
- dispatch(splitListItemWith(tr, slice, $next, false));
296
- return true;
309
+ // if nested, just unindent
310
+ if ($next.node($next.depth - 2).type === taskList ||
311
+ // this is for the case when we are on a non-nested item and next one is nested
312
+ $next.node($next.depth - 1).type === taskList && $next.parent.type === taskList) {
313
+ (0, _helpers.liftBlock)(tr, $next, $next);
314
+ dispatch(tr);
315
+ return true;
316
+ }
317
+ var isNextCompatibleWithBlockTaskItem = blockTaskItem && (($next === null || $next === void 0 || (_$next$node = $next.node()) === null || _$next$node === void 0 ? void 0 : _$next$node.type) === taskItem && ($from === null || $from === void 0 || (_$from$node = $from.node()) === null || _$from$node === void 0 ? void 0 : _$from$node.type) === blockTaskItem || ($next === null || $next === void 0 || (_$next$node2 = $next.node()) === null || _$next$node2 === void 0 ? void 0 : _$next$node2.type) === blockTaskItem && ($from === null || $from === void 0 || (_$from$node2 = $from.node()) === null || _$from$node2 === void 0 ? void 0 : _$from$node2.type) === taskItem || [taskItem, blockTaskItem].includes($next === null || $next === void 0 || (_$next$node3 = $next.node()) === null || _$next$node3 === void 0 ? void 0 : _$next$node3.type) && resultOfCurrentFindBlockTaskItem && resultOfCurrentFindBlockTaskItem.blockTaskItemNode);
318
+
319
+ // if next node is of same type or compatible type, remove the node wrapping and create paragraph
320
+ if (!(0, _helpers.isTable)($next.nodeAfter) && (0, _helpers.isActionOrDecisionItem)($from.parent) || resultOfCurrentFindBlockTaskItem && resultOfCurrentFindBlockTaskItem.blockTaskItemNode && actionDecisionFollowsOrNothing($from) && (
321
+ // only forward delete if the node is same type or compatible
322
+ $next.node().type.name === $from.node().type.name || isNextCompatibleWithBlockTaskItem)) {
323
+ if (dispatch) {
324
+ // If next node is in a blockTaskItem paragraph, we need to get the content of the whole blockTaskItem
325
+ // So we reduce the depth by 1 to get to the blockTaskItem node content
326
+ var taskContent = isNextInBlockTaskItemParagraph ? state.doc.slice($next.start($next.depth - 1), $next.end($next.depth - 1)).content : state.doc.slice($next.start(), $next.end()).content;
327
+ var slice;
328
+ try {
329
+ slice = taskContent.size ? paragraph.createChecked(undefined, taskContent) : paragraph.createChecked();
330
+
331
+ // might be end of document after
332
+ var _tr4 = splitListItemWith(state.tr, slice, $next, false);
333
+ dispatch(_tr4);
334
+ return true;
335
+ } catch (error) {
336
+ // If there's an error creating a paragraph, check if we are in a blockTaskItem
337
+ // Block task item's can have non-text content that cannot be wrapped in a paragraph
338
+ // So if the selection is in a blockTaskItem, just pass the content as is
339
+ if (resultOfNextFindBlockTaskItem && resultOfNextFindBlockTaskItem.blockTaskItemNode) {
340
+ var _$next$node$firstChil;
341
+ // Create an array from the fragment to pass into splitListItemWith, as the `content` property is readonly
342
+ slice = Array.from(taskContent.content);
343
+ var $splitPos = $next;
344
+ if ((_$next$node$firstChil = $next.node().firstChild) !== null && _$next$node$firstChil !== void 0 && _$next$node$firstChil.isTextblock) {
345
+ // set $next to the resolved position of inside the textblock
346
+ $splitPos = $next.doc.resolve($next.pos + 1);
347
+ }
348
+ var _tr5 = splitListItemWith(state.tr, slice, $splitPos, false);
349
+ dispatch(_tr5);
350
+ return true;
351
+ }
352
+ }
353
+ }
354
+ }
355
+ } else {
356
+ // only run if cursor is at the end of the node
357
+ if (!(0, _utils.isEmptySelectionAtEnd)(state) || !dispatch) {
358
+ return false;
359
+ }
360
+
361
+ // look for the node after this current one
362
+ var _$next = (0, _helpers.walkOut)($from);
363
+
364
+ // this is a top-level node it wont have $next.before()
365
+ if (!_$next.parent || _$next.parent.type === doc) {
366
+ return false;
367
+ }
368
+
369
+ // if nested, just unindent
370
+ if (_$next.node(_$next.depth - 2).type === taskList ||
371
+ // this is for the case when we are on a non-nested item and next one is nested
372
+ _$next.node(_$next.depth - 1).type === taskList && _$next.parent.type === taskList) {
373
+ (0, _helpers.liftBlock)(tr, _$next, _$next);
374
+ dispatch(tr);
375
+ return true;
376
+ }
377
+
378
+ // if next node is of same type, remove the node wrapping and create paragraph
379
+ if (!(0, _helpers.isTable)(_$next.nodeAfter) && (0, _helpers.isActionOrDecisionItem)($from.parent) && actionDecisionFollowsOrNothing($from) &&
380
+ // only forward delete if the node is same type
381
+ _$next.node().type.name === $from.node().type.name) {
382
+ var _taskContent2 = state.doc.slice(_$next.start(), _$next.end()).content;
383
+
384
+ // might be end of document after
385
+ var _slice2 = _taskContent2.size ? paragraph.createChecked(undefined, _taskContent2) : [];
386
+ dispatch(splitListItemWith(tr, _slice2, _$next, false));
387
+ return true;
388
+ }
297
389
  }
298
390
  return false;
299
391
  };
@@ -341,11 +433,13 @@ var splitListItemWith = function splitListItemWith(tr, content, $from, setSelect
341
433
  var deleteBlockModifier = 0;
342
434
  var shouldSplitBlockTaskItem = true;
343
435
  var isGapCursorSelection = false;
436
+ var hasBlockTaskItem = false;
344
437
  if (blockTaskItem) {
345
438
  var result = (0, _utils3.findBlockTaskItem)($from);
346
439
  if (result) {
347
440
  var blockTaskItemNode = result.blockTaskItemNode,
348
441
  hasParagraph = result.hasParagraph;
442
+ hasBlockTaskItem = (0, _platformFeatureFlags.fg)('platform_editor_blocktaskitem_patch_3') && !!blockTaskItemNode;
349
443
  if (blockTaskItemNode) {
350
444
  var _$oldAfter$nodeAfter, _$posPreviousSibling$;
351
445
  // If the case there is a paragraph in the block task item we need to
@@ -391,7 +485,9 @@ var splitListItemWith = function splitListItemWith(tr, content, $from, setSelect
391
485
  if (shouldSplit && !isNestedActionInsideLists) {
392
486
  // this only splits a node to delete it, so we probably don't need a random uuid
393
487
  // but generate one anyway for correctness
394
- tr = tr.split($from.pos, 1, [{
488
+ tr = tr.split($from.pos,
489
+ // eslint-disable-next-line @atlaskit/platform/no-preconditioning
490
+ (0, _platformFeatureFlags.fg)('platform_editor_blocktaskitem_patch_3') && hasBlockTaskItem ? 0 : 1, [{
395
491
  type: $from.parent.type,
396
492
  attrs: {
397
493
  localId: _adfSchema.uuid.generate()
@@ -201,6 +201,7 @@ const backspaceFrom = editorAnalyticsAPI => $from => (state, dispatch) => {
201
201
  let slice;
202
202
  try {
203
203
  slice = taskContent.size ? paragraph.createChecked(undefined, taskContent) : paragraph.createChecked();
204
+
204
205
  // might be end of document after
205
206
  const tr = splitListItemWith(state.tr, slice, $from, true);
206
207
  dispatch(tr);
@@ -231,44 +232,137 @@ const unindentTaskOrUnwrapTaskDecisionFollowing = (state, dispatch) => {
231
232
  nodes: {
232
233
  taskList,
233
234
  doc,
234
- paragraph
235
+ paragraph,
236
+ blockTaskItem,
237
+ taskItem
235
238
  }
236
239
  },
237
240
  tr
238
241
  } = state;
242
+ if (fg('platform_editor_blocktaskitem_patch_3')) {
243
+ var _$next$node, _$from$node, _$next$node2, _$from$node2, _$next$node3;
244
+ // only run if cursor is at the end of the node
245
+ if (!isEmptySelectionAtEnd(state) || !dispatch) {
246
+ return false;
247
+ }
239
248
 
240
- // only run if cursor is at the end of the node
241
- if (!isEmptySelectionAtEnd(state) || !dispatch) {
242
- return false;
243
- }
249
+ // look for the node after this current one
250
+ const $next = walkOut($from);
244
251
 
245
- // look for the node after this current one
246
- const $next = walkOut($from);
252
+ // this is a top-level node it wont have $next.before()
253
+ if (!$next.parent || $next.parent.type === doc) {
254
+ return false;
255
+ }
247
256
 
248
- // this is a top-level node it wont have $next.before()
249
- if (!$next.parent || $next.parent.type === doc) {
250
- return false;
251
- }
257
+ // get resolved position of parent
258
+ const $parentPos = $from.doc.resolve($from.start($from.depth - 1));
259
+ const currentNode = $from.node();
260
+ const parentNode = $parentPos.node();
252
261
 
253
- // if nested, just unindent
254
- if ($next.node($next.depth - 2).type === taskList ||
255
- // this is for the case when we are on a non-nested item and next one is nested
256
- $next.node($next.depth - 1).type === taskList && $next.parent.type === taskList) {
257
- liftBlock(tr, $next, $next);
258
- dispatch(tr);
259
- return true;
260
- }
262
+ // if current position isn't an action or decision item, return false
263
+ if (!isActionOrDecisionItem(currentNode) && !isActionOrDecisionItem(parentNode)) {
264
+ return false;
265
+ }
266
+ const resultOfCurrentFindBlockTaskItem = findBlockTaskItem($next);
267
+ let isCurrentEmptyBlockTaskItem = false;
268
+ if (resultOfCurrentFindBlockTaskItem) {
269
+ var _blockTaskItemNode$fi;
270
+ const {
271
+ blockTaskItemNode
272
+ } = resultOfCurrentFindBlockTaskItem;
273
+ isCurrentEmptyBlockTaskItem = blockTaskItem && blockTaskItemNode && blockTaskItemNode.childCount === 1 && ((_blockTaskItemNode$fi = blockTaskItemNode.firstChild) === null || _blockTaskItemNode$fi === void 0 ? void 0 : _blockTaskItemNode$fi.type) === paragraph && blockTaskItemNode.firstChild.childCount === 0;
274
+ }
275
+ const isEmptyActionOrDecisionItem = currentNode && isActionOrDecisionItem(currentNode) && currentNode.childCount === 0;
261
276
 
262
- // if next node is of same type, remove the node wrapping and create paragraph
263
- if (!isTable($next.nodeAfter) && isActionOrDecisionItem($from.parent) && actionDecisionFollowsOrNothing($from) &&
264
- // only forward delete if the node is same type
265
- $next.node().type.name === $from.node().type.name) {
266
- const taskContent = state.doc.slice($next.start(), $next.end()).content;
277
+ // If empty item, use default handler
278
+ if (isEmptyActionOrDecisionItem || isCurrentEmptyBlockTaskItem) {
279
+ return false;
280
+ }
267
281
 
268
- // might be end of document after
269
- const slice = taskContent.size ? paragraph.createChecked(undefined, taskContent) : [];
270
- dispatch(splitListItemWith(tr, slice, $next, false));
271
- return true;
282
+ // Check if next node is a blockTaskItem paragraph
283
+ const resultOfNextFindBlockTaskItem = findBlockTaskItem($next);
284
+ const isNextInBlockTaskItemParagraph = resultOfNextFindBlockTaskItem && (resultOfNextFindBlockTaskItem === null || resultOfNextFindBlockTaskItem === void 0 ? void 0 : resultOfNextFindBlockTaskItem.hasParagraph);
285
+
286
+ // if nested, just unindent
287
+ if ($next.node($next.depth - 2).type === taskList ||
288
+ // this is for the case when we are on a non-nested item and next one is nested
289
+ $next.node($next.depth - 1).type === taskList && $next.parent.type === taskList) {
290
+ liftBlock(tr, $next, $next);
291
+ dispatch(tr);
292
+ return true;
293
+ }
294
+ const isNextCompatibleWithBlockTaskItem = blockTaskItem && (($next === null || $next === void 0 ? void 0 : (_$next$node = $next.node()) === null || _$next$node === void 0 ? void 0 : _$next$node.type) === taskItem && ($from === null || $from === void 0 ? void 0 : (_$from$node = $from.node()) === null || _$from$node === void 0 ? void 0 : _$from$node.type) === blockTaskItem || ($next === null || $next === void 0 ? void 0 : (_$next$node2 = $next.node()) === null || _$next$node2 === void 0 ? void 0 : _$next$node2.type) === blockTaskItem && ($from === null || $from === void 0 ? void 0 : (_$from$node2 = $from.node()) === null || _$from$node2 === void 0 ? void 0 : _$from$node2.type) === taskItem || [taskItem, blockTaskItem].includes($next === null || $next === void 0 ? void 0 : (_$next$node3 = $next.node()) === null || _$next$node3 === void 0 ? void 0 : _$next$node3.type) && resultOfCurrentFindBlockTaskItem && resultOfCurrentFindBlockTaskItem.blockTaskItemNode);
295
+
296
+ // if next node is of same type or compatible type, remove the node wrapping and create paragraph
297
+ if (!isTable($next.nodeAfter) && isActionOrDecisionItem($from.parent) || resultOfCurrentFindBlockTaskItem && resultOfCurrentFindBlockTaskItem.blockTaskItemNode && actionDecisionFollowsOrNothing($from) && (
298
+ // only forward delete if the node is same type or compatible
299
+ $next.node().type.name === $from.node().type.name || isNextCompatibleWithBlockTaskItem)) {
300
+ if (dispatch) {
301
+ // If next node is in a blockTaskItem paragraph, we need to get the content of the whole blockTaskItem
302
+ // So we reduce the depth by 1 to get to the blockTaskItem node content
303
+ const taskContent = isNextInBlockTaskItemParagraph ? state.doc.slice($next.start($next.depth - 1), $next.end($next.depth - 1)).content : state.doc.slice($next.start(), $next.end()).content;
304
+ let slice;
305
+ try {
306
+ slice = taskContent.size ? paragraph.createChecked(undefined, taskContent) : paragraph.createChecked();
307
+
308
+ // might be end of document after
309
+ const tr = splitListItemWith(state.tr, slice, $next, false);
310
+ dispatch(tr);
311
+ return true;
312
+ } catch (error) {
313
+ // If there's an error creating a paragraph, check if we are in a blockTaskItem
314
+ // Block task item's can have non-text content that cannot be wrapped in a paragraph
315
+ // So if the selection is in a blockTaskItem, just pass the content as is
316
+ if (resultOfNextFindBlockTaskItem && resultOfNextFindBlockTaskItem.blockTaskItemNode) {
317
+ var _$next$node$firstChil;
318
+ // Create an array from the fragment to pass into splitListItemWith, as the `content` property is readonly
319
+ slice = Array.from(taskContent.content);
320
+ let $splitPos = $next;
321
+ if ((_$next$node$firstChil = $next.node().firstChild) !== null && _$next$node$firstChil !== void 0 && _$next$node$firstChil.isTextblock) {
322
+ // set $next to the resolved position of inside the textblock
323
+ $splitPos = $next.doc.resolve($next.pos + 1);
324
+ }
325
+ const tr = splitListItemWith(state.tr, slice, $splitPos, false);
326
+ dispatch(tr);
327
+ return true;
328
+ }
329
+ }
330
+ }
331
+ }
332
+ } else {
333
+ // only run if cursor is at the end of the node
334
+ if (!isEmptySelectionAtEnd(state) || !dispatch) {
335
+ return false;
336
+ }
337
+
338
+ // look for the node after this current one
339
+ const $next = walkOut($from);
340
+
341
+ // this is a top-level node it wont have $next.before()
342
+ if (!$next.parent || $next.parent.type === doc) {
343
+ return false;
344
+ }
345
+
346
+ // if nested, just unindent
347
+ if ($next.node($next.depth - 2).type === taskList ||
348
+ // this is for the case when we are on a non-nested item and next one is nested
349
+ $next.node($next.depth - 1).type === taskList && $next.parent.type === taskList) {
350
+ liftBlock(tr, $next, $next);
351
+ dispatch(tr);
352
+ return true;
353
+ }
354
+
355
+ // if next node is of same type, remove the node wrapping and create paragraph
356
+ if (!isTable($next.nodeAfter) && isActionOrDecisionItem($from.parent) && actionDecisionFollowsOrNothing($from) &&
357
+ // only forward delete if the node is same type
358
+ $next.node().type.name === $from.node().type.name) {
359
+ const taskContent = state.doc.slice($next.start(), $next.end()).content;
360
+
361
+ // might be end of document after
362
+ const slice = taskContent.size ? paragraph.createChecked(undefined, taskContent) : [];
363
+ dispatch(splitListItemWith(tr, slice, $next, false));
364
+ return true;
365
+ }
272
366
  }
273
367
  return false;
274
368
  };
@@ -317,6 +411,7 @@ const splitListItemWith = (tr, content, $from, setSelection) => {
317
411
  let deleteBlockModifier = 0;
318
412
  let shouldSplitBlockTaskItem = true;
319
413
  let isGapCursorSelection = false;
414
+ let hasBlockTaskItem = false;
320
415
  if (blockTaskItem) {
321
416
  const result = findBlockTaskItem($from);
322
417
  if (result) {
@@ -324,6 +419,7 @@ const splitListItemWith = (tr, content, $from, setSelection) => {
324
419
  blockTaskItemNode,
325
420
  hasParagraph
326
421
  } = result;
422
+ hasBlockTaskItem = fg('platform_editor_blocktaskitem_patch_3') && !!blockTaskItemNode;
327
423
  if (blockTaskItemNode) {
328
424
  var _$oldAfter$nodeAfter, _$posPreviousSibling$;
329
425
  // If the case there is a paragraph in the block task item we need to
@@ -369,7 +465,9 @@ const splitListItemWith = (tr, content, $from, setSelection) => {
369
465
  if (shouldSplit && !isNestedActionInsideLists) {
370
466
  // this only splits a node to delete it, so we probably don't need a random uuid
371
467
  // but generate one anyway for correctness
372
- tr = tr.split($from.pos, 1, [{
468
+ tr = tr.split($from.pos,
469
+ // eslint-disable-next-line @atlaskit/platform/no-preconditioning
470
+ fg('platform_editor_blocktaskitem_patch_3') && hasBlockTaskItem ? 0 : 1, [{
373
471
  type: $from.parent.type,
374
472
  attrs: {
375
473
  localId: uuid.generate()
@@ -217,6 +217,7 @@ var backspaceFrom = function backspaceFrom(editorAnalyticsAPI) {
217
217
  var _slice;
218
218
  try {
219
219
  _slice = _taskContent.size ? paragraph.createChecked(undefined, _taskContent) : paragraph.createChecked();
220
+
220
221
  // might be end of document after
221
222
  var _tr2 = splitListItemWith(state.tr, _slice, $from, true);
222
223
  dispatch(_tr2);
@@ -252,40 +253,131 @@ var unindentTaskOrUnwrapTaskDecisionFollowing = function unindentTaskOrUnwrapTas
252
253
  taskList = _state$schema$nodes4.taskList,
253
254
  doc = _state$schema$nodes4.doc,
254
255
  paragraph = _state$schema$nodes4.paragraph,
256
+ blockTaskItem = _state$schema$nodes4.blockTaskItem,
257
+ taskItem = _state$schema$nodes4.taskItem,
255
258
  tr = state.tr;
259
+ if (fg('platform_editor_blocktaskitem_patch_3')) {
260
+ var _$next$node, _$from$node, _$next$node2, _$from$node2, _$next$node3;
261
+ // only run if cursor is at the end of the node
262
+ if (!isEmptySelectionAtEnd(state) || !dispatch) {
263
+ return false;
264
+ }
256
265
 
257
- // only run if cursor is at the end of the node
258
- if (!isEmptySelectionAtEnd(state) || !dispatch) {
259
- return false;
260
- }
266
+ // look for the node after this current one
267
+ var $next = walkOut($from);
261
268
 
262
- // look for the node after this current one
263
- var $next = walkOut($from);
269
+ // this is a top-level node it wont have $next.before()
270
+ if (!$next.parent || $next.parent.type === doc) {
271
+ return false;
272
+ }
264
273
 
265
- // this is a top-level node it wont have $next.before()
266
- if (!$next.parent || $next.parent.type === doc) {
267
- return false;
268
- }
274
+ // get resolved position of parent
275
+ var $parentPos = $from.doc.resolve($from.start($from.depth - 1));
276
+ var currentNode = $from.node();
277
+ var parentNode = $parentPos.node();
269
278
 
270
- // if nested, just unindent
271
- if ($next.node($next.depth - 2).type === taskList ||
272
- // this is for the case when we are on a non-nested item and next one is nested
273
- $next.node($next.depth - 1).type === taskList && $next.parent.type === taskList) {
274
- liftBlock(tr, $next, $next);
275
- dispatch(tr);
276
- return true;
277
- }
279
+ // if current position isn't an action or decision item, return false
280
+ if (!isActionOrDecisionItem(currentNode) && !isActionOrDecisionItem(parentNode)) {
281
+ return false;
282
+ }
283
+ var resultOfCurrentFindBlockTaskItem = findBlockTaskItem($next);
284
+ var isCurrentEmptyBlockTaskItem = false;
285
+ if (resultOfCurrentFindBlockTaskItem) {
286
+ var _blockTaskItemNode$fi;
287
+ var blockTaskItemNode = resultOfCurrentFindBlockTaskItem.blockTaskItemNode;
288
+ isCurrentEmptyBlockTaskItem = blockTaskItem && blockTaskItemNode && blockTaskItemNode.childCount === 1 && ((_blockTaskItemNode$fi = blockTaskItemNode.firstChild) === null || _blockTaskItemNode$fi === void 0 ? void 0 : _blockTaskItemNode$fi.type) === paragraph && blockTaskItemNode.firstChild.childCount === 0;
289
+ }
290
+ var isEmptyActionOrDecisionItem = currentNode && isActionOrDecisionItem(currentNode) && currentNode.childCount === 0;
291
+
292
+ // If empty item, use default handler
293
+ if (isEmptyActionOrDecisionItem || isCurrentEmptyBlockTaskItem) {
294
+ return false;
295
+ }
278
296
 
279
- // if next node is of same type, remove the node wrapping and create paragraph
280
- if (!isTable($next.nodeAfter) && isActionOrDecisionItem($from.parent) && actionDecisionFollowsOrNothing($from) &&
281
- // only forward delete if the node is same type
282
- $next.node().type.name === $from.node().type.name) {
283
- var taskContent = state.doc.slice($next.start(), $next.end()).content;
297
+ // Check if next node is a blockTaskItem paragraph
298
+ var resultOfNextFindBlockTaskItem = findBlockTaskItem($next);
299
+ var isNextInBlockTaskItemParagraph = resultOfNextFindBlockTaskItem && (resultOfNextFindBlockTaskItem === null || resultOfNextFindBlockTaskItem === void 0 ? void 0 : resultOfNextFindBlockTaskItem.hasParagraph);
284
300
 
285
- // might be end of document after
286
- var slice = taskContent.size ? paragraph.createChecked(undefined, taskContent) : [];
287
- dispatch(splitListItemWith(tr, slice, $next, false));
288
- return true;
301
+ // if nested, just unindent
302
+ if ($next.node($next.depth - 2).type === taskList ||
303
+ // this is for the case when we are on a non-nested item and next one is nested
304
+ $next.node($next.depth - 1).type === taskList && $next.parent.type === taskList) {
305
+ liftBlock(tr, $next, $next);
306
+ dispatch(tr);
307
+ return true;
308
+ }
309
+ var isNextCompatibleWithBlockTaskItem = blockTaskItem && (($next === null || $next === void 0 || (_$next$node = $next.node()) === null || _$next$node === void 0 ? void 0 : _$next$node.type) === taskItem && ($from === null || $from === void 0 || (_$from$node = $from.node()) === null || _$from$node === void 0 ? void 0 : _$from$node.type) === blockTaskItem || ($next === null || $next === void 0 || (_$next$node2 = $next.node()) === null || _$next$node2 === void 0 ? void 0 : _$next$node2.type) === blockTaskItem && ($from === null || $from === void 0 || (_$from$node2 = $from.node()) === null || _$from$node2 === void 0 ? void 0 : _$from$node2.type) === taskItem || [taskItem, blockTaskItem].includes($next === null || $next === void 0 || (_$next$node3 = $next.node()) === null || _$next$node3 === void 0 ? void 0 : _$next$node3.type) && resultOfCurrentFindBlockTaskItem && resultOfCurrentFindBlockTaskItem.blockTaskItemNode);
310
+
311
+ // if next node is of same type or compatible type, remove the node wrapping and create paragraph
312
+ if (!isTable($next.nodeAfter) && isActionOrDecisionItem($from.parent) || resultOfCurrentFindBlockTaskItem && resultOfCurrentFindBlockTaskItem.blockTaskItemNode && actionDecisionFollowsOrNothing($from) && (
313
+ // only forward delete if the node is same type or compatible
314
+ $next.node().type.name === $from.node().type.name || isNextCompatibleWithBlockTaskItem)) {
315
+ if (dispatch) {
316
+ // If next node is in a blockTaskItem paragraph, we need to get the content of the whole blockTaskItem
317
+ // So we reduce the depth by 1 to get to the blockTaskItem node content
318
+ var taskContent = isNextInBlockTaskItemParagraph ? state.doc.slice($next.start($next.depth - 1), $next.end($next.depth - 1)).content : state.doc.slice($next.start(), $next.end()).content;
319
+ var slice;
320
+ try {
321
+ slice = taskContent.size ? paragraph.createChecked(undefined, taskContent) : paragraph.createChecked();
322
+
323
+ // might be end of document after
324
+ var _tr4 = splitListItemWith(state.tr, slice, $next, false);
325
+ dispatch(_tr4);
326
+ return true;
327
+ } catch (error) {
328
+ // If there's an error creating a paragraph, check if we are in a blockTaskItem
329
+ // Block task item's can have non-text content that cannot be wrapped in a paragraph
330
+ // So if the selection is in a blockTaskItem, just pass the content as is
331
+ if (resultOfNextFindBlockTaskItem && resultOfNextFindBlockTaskItem.blockTaskItemNode) {
332
+ var _$next$node$firstChil;
333
+ // Create an array from the fragment to pass into splitListItemWith, as the `content` property is readonly
334
+ slice = Array.from(taskContent.content);
335
+ var $splitPos = $next;
336
+ if ((_$next$node$firstChil = $next.node().firstChild) !== null && _$next$node$firstChil !== void 0 && _$next$node$firstChil.isTextblock) {
337
+ // set $next to the resolved position of inside the textblock
338
+ $splitPos = $next.doc.resolve($next.pos + 1);
339
+ }
340
+ var _tr5 = splitListItemWith(state.tr, slice, $splitPos, false);
341
+ dispatch(_tr5);
342
+ return true;
343
+ }
344
+ }
345
+ }
346
+ }
347
+ } else {
348
+ // only run if cursor is at the end of the node
349
+ if (!isEmptySelectionAtEnd(state) || !dispatch) {
350
+ return false;
351
+ }
352
+
353
+ // look for the node after this current one
354
+ var _$next = walkOut($from);
355
+
356
+ // this is a top-level node it wont have $next.before()
357
+ if (!_$next.parent || _$next.parent.type === doc) {
358
+ return false;
359
+ }
360
+
361
+ // if nested, just unindent
362
+ if (_$next.node(_$next.depth - 2).type === taskList ||
363
+ // this is for the case when we are on a non-nested item and next one is nested
364
+ _$next.node(_$next.depth - 1).type === taskList && _$next.parent.type === taskList) {
365
+ liftBlock(tr, _$next, _$next);
366
+ dispatch(tr);
367
+ return true;
368
+ }
369
+
370
+ // if next node is of same type, remove the node wrapping and create paragraph
371
+ if (!isTable(_$next.nodeAfter) && isActionOrDecisionItem($from.parent) && actionDecisionFollowsOrNothing($from) &&
372
+ // only forward delete if the node is same type
373
+ _$next.node().type.name === $from.node().type.name) {
374
+ var _taskContent2 = state.doc.slice(_$next.start(), _$next.end()).content;
375
+
376
+ // might be end of document after
377
+ var _slice2 = _taskContent2.size ? paragraph.createChecked(undefined, _taskContent2) : [];
378
+ dispatch(splitListItemWith(tr, _slice2, _$next, false));
379
+ return true;
380
+ }
289
381
  }
290
382
  return false;
291
383
  };
@@ -333,11 +425,13 @@ var splitListItemWith = function splitListItemWith(tr, content, $from, setSelect
333
425
  var deleteBlockModifier = 0;
334
426
  var shouldSplitBlockTaskItem = true;
335
427
  var isGapCursorSelection = false;
428
+ var hasBlockTaskItem = false;
336
429
  if (blockTaskItem) {
337
430
  var result = findBlockTaskItem($from);
338
431
  if (result) {
339
432
  var blockTaskItemNode = result.blockTaskItemNode,
340
433
  hasParagraph = result.hasParagraph;
434
+ hasBlockTaskItem = fg('platform_editor_blocktaskitem_patch_3') && !!blockTaskItemNode;
341
435
  if (blockTaskItemNode) {
342
436
  var _$oldAfter$nodeAfter, _$posPreviousSibling$;
343
437
  // If the case there is a paragraph in the block task item we need to
@@ -383,7 +477,9 @@ var splitListItemWith = function splitListItemWith(tr, content, $from, setSelect
383
477
  if (shouldSplit && !isNestedActionInsideLists) {
384
478
  // this only splits a node to delete it, so we probably don't need a random uuid
385
479
  // but generate one anyway for correctness
386
- tr = tr.split($from.pos, 1, [{
480
+ tr = tr.split($from.pos,
481
+ // eslint-disable-next-line @atlaskit/platform/no-preconditioning
482
+ fg('platform_editor_blocktaskitem_patch_3') && hasBlockTaskItem ? 0 : 1, [{
387
483
  type: $from.parent.type,
388
484
  attrs: {
389
485
  localId: uuid.generate()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-tasks-and-decisions",
3
- "version": "8.4.9",
3
+ "version": "9.0.0",
4
4
  "description": "Tasks and decisions plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -29,34 +29,34 @@
29
29
  ],
30
30
  "atlaskit:src": "src/index.ts",
31
31
  "dependencies": {
32
- "@atlaskit/adf-schema": "^51.1.2",
33
- "@atlaskit/analytics-namespaced-context": "^7.0.0",
32
+ "@atlaskit/adf-schema": "^51.2.0",
33
+ "@atlaskit/analytics-namespaced-context": "^7.1.0",
34
34
  "@atlaskit/analytics-next": "^11.1.0",
35
35
  "@atlaskit/css": "^0.14.0",
36
- "@atlaskit/editor-plugin-analytics": "^5.2.0",
37
- "@atlaskit/editor-plugin-block-menu": "^3.2.0",
38
- "@atlaskit/editor-plugin-context-identifier": "^5.0.0",
39
- "@atlaskit/editor-plugin-editor-viewmode": "^7.0.0",
40
- "@atlaskit/editor-plugin-selection": "^5.0.0",
41
- "@atlaskit/editor-plugin-type-ahead": "^5.2.0",
36
+ "@atlaskit/editor-plugin-analytics": "^6.0.0",
37
+ "@atlaskit/editor-plugin-block-menu": "^4.0.0",
38
+ "@atlaskit/editor-plugin-context-identifier": "^6.0.0",
39
+ "@atlaskit/editor-plugin-editor-viewmode": "^8.0.0",
40
+ "@atlaskit/editor-plugin-selection": "^6.0.0",
41
+ "@atlaskit/editor-plugin-type-ahead": "^6.0.0",
42
42
  "@atlaskit/editor-prosemirror": "7.0.0",
43
43
  "@atlaskit/editor-shared-styles": "^3.6.0",
44
44
  "@atlaskit/editor-toolbar": "^0.9.0",
45
45
  "@atlaskit/heading": "^5.2.0",
46
- "@atlaskit/icon": "^28.2.0",
46
+ "@atlaskit/icon": "^28.3.0",
47
47
  "@atlaskit/platform-feature-flags": "^1.1.0",
48
48
  "@atlaskit/popup": "^4.4.0",
49
49
  "@atlaskit/primitives": "^14.15.0",
50
50
  "@atlaskit/prosemirror-input-rules": "^3.4.0",
51
51
  "@atlaskit/task-decision": "^19.2.0",
52
- "@atlaskit/tmp-editor-statsig": "^12.28.0",
52
+ "@atlaskit/tmp-editor-statsig": "^12.31.0",
53
53
  "@atlaskit/tokens": "^6.3.0",
54
54
  "@babel/runtime": "^7.0.0",
55
55
  "@compiled/react": "^0.18.3",
56
56
  "bind-event-listener": "^3.0.0"
57
57
  },
58
58
  "peerDependencies": {
59
- "@atlaskit/editor-common": "^109.11.0",
59
+ "@atlaskit/editor-common": "^110.0.0",
60
60
  "react": "^18.2.0",
61
61
  "react-dom": "^18.2.0",
62
62
  "react-intl-next": "npm:react-intl@^5.18.1"
@@ -65,7 +65,7 @@
65
65
  "@af/integration-testing": "workspace:^",
66
66
  "@af/visual-regression": "workspace:^",
67
67
  "@atlaskit/ssr": "workspace:^",
68
- "@atlaskit/util-data-test": "^18.2.0",
68
+ "@atlaskit/util-data-test": "^18.3.0",
69
69
  "@testing-library/react": "^13.4.0",
70
70
  "wait-for-expect": "^1.2.0"
71
71
  },
@@ -113,6 +113,9 @@
113
113
  },
114
114
  "platform_editor_block_menu_format_rank_revised": {
115
115
  "type": "boolean"
116
+ },
117
+ "platform_editor_blocktaskitem_patch_3": {
118
+ "type": "boolean"
116
119
  }
117
120
  }
118
121
  }