UNPKG

@atlaskit/editor-plugin-tasks-and-decisions

Version:

Tasks and decisions plugin for @atlaskit/editor-core

173 lines (165 loc) 7.69 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.wrapSelectionInTaskList = exports.liftSelection = exports.joinAtCut = void 0; var _commands = require("@atlaskit/editor-common/commands"); var _lists = require("@atlaskit/editor-common/lists"); var _transforms = require("@atlaskit/editor-common/transforms"); var _transform = require("@atlaskit/editor-prosemirror/transform"); var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals"); var _helpers = require("./helpers"); var _utils = require("./utils"); var _paste = require("./utils/paste"); var liftSelection = exports.liftSelection = function liftSelection(state, dispatch) { var normalizedSelection = (0, _utils.normalizeTaskItemsSelection)(state.selection); var $from = normalizedSelection.$from, $to = normalizedSelection.$to; var tr = (0, _helpers.liftBlock)(state.tr, $from, $to); if (dispatch && tr) { dispatch(tr); } return !!tr; }; /** * Wraps the current selection in a task list, respecting a maximum indentation depth of 6 levels. * * - Normalizes the selection to ensure it covers complete task items. * - Determines the maximum depth of task list nesting within the selection. * - If the selection is already nested at or beyond the maximum depth, the command does nothing. * - Calculates the block range to wrap, handling both regular and block task items. * - Wraps the block in a task list to increase indentation or create a new task list if necessary. * * @param state - The current editor state. * @param dispatch - The dispatch function to apply the transaction. * @returns `true` if the command was handled (even if no changes were made), otherwise `false`. * @example * ```typescript * autoJoin(wrapSelectionInTaskList, ['taskList']))(state, dispatch); * ``` */ var wrapSelectionInTaskList = exports.wrapSelectionInTaskList = function wrapSelectionInTaskList(state, dispatch) { var _normalizeTaskItemsSe = (0, _utils.normalizeTaskItemsSelection)(state.selection), $from = _normalizeTaskItemsSe.$from, $to = _normalizeTaskItemsSe.$to; // limit ui indentation to 6 levels var _state$schema$nodes = state.schema.nodes, taskList = _state$schema$nodes.taskList, taskItem = _state$schema$nodes.taskItem, blockTaskItem = _state$schema$nodes.blockTaskItem; var maxDepth = (0, _helpers.subtreeHeight)($from, $to, [taskList, taskItem]); if (blockTaskItem) { var resultOfFindBlockTaskItem = (0, _utils.findBlockTaskItem)($from); if (resultOfFindBlockTaskItem) { var hasParagraph = resultOfFindBlockTaskItem.hasParagraph; // If the selection is inside a nested node inside the blockTaskItem // Remove the difference in depth between the selection and the blockTaskItemNode if (hasParagraph) { maxDepth = (0, _helpers.subtreeHeight)($from, $to, [taskList, blockTaskItem]) - 1; } else { maxDepth = (0, _helpers.subtreeHeight)($from, $to, [taskList, blockTaskItem]); } } } if (maxDepth >= 6) { return true; } var blockRange = (0, _helpers.getBlockRange)({ $from: $from, $to: $to }); if (!blockRange) { return true; } var wrapping = (0, _transform.findWrapping)(blockRange, state.schema.nodes.taskList); if (!wrapping) { return true; } if (dispatch) { dispatch(state.tr.wrap(blockRange, wrapping).scrollIntoView()); } return true; }; /** * Tries to move the paragraph content near the given position into the taskItem or decisionItem * before it. * * Looks backwards from the given position to find the "cut point" between the last taskItem and the * following paragraph. Then tries to move the content from that paragraph into the taskItem. * * @param $pos Position at the end of, or anywhere in paragraph following, the last taskItem * @see {joinToPreviousListItem} */ var joinAtCut = exports.joinAtCut = function joinAtCut($pos) { return function (state, dispatch) { var $cut = (0, _commands.findCutBefore)($pos); var blockTaskItem = state.schema.nodes.blockTaskItem; var fontSize = state.schema.marks.fontSize; if (!$cut) { return false; } var paragraph = $cut.doc.type.schema.nodes.paragraph; // find the boundary between the taskList and paragraph if ($cut.nodeBefore && (0, _helpers.isActionOrDecisionList)($cut.nodeBefore) && $cut.nodeAfter && $cut.nodeAfter.type === paragraph) { // we'll find the boundary of a taskList // so resolve -1 to find the inside end of the last taskItem var $lastNode = $cut.doc.resolve($cut.pos - 1); // might have deeply nested taskList, keep trying to find it while (!(0, _helpers.isActionOrDecisionItem)($lastNode.parent)) { $lastNode = state.doc.resolve($lastNode.pos - 1); } // grab the structure between the taskItem and the paragraph // note: structure = true in ReplaceAroundStep var slice = state.tr.doc.slice($lastNode.pos, $cut.pos); var from = $lastNode.pos; var to = $cut.pos + $cut.nodeAfter.nodeSize; var gapFrom = $cut.pos + 1; var gapTo = $cut.pos + $cut.nodeAfter.nodeSize - 1; var insert = 0; if (blockTaskItem) { if ($lastNode.parent.type === blockTaskItem) { var childOfLastNode = state.doc.resolve($lastNode.pos - 1); if (childOfLastNode.parent.type === paragraph) { // Recalculate the slice to include the full blockTaskItem structure slice = state.tr.doc.slice(childOfLastNode.pos, $cut.pos); // Need to move one pos in to get to the text node of the paragraph from = $lastNode.pos - 1; } else { // If the blockTaskItem last node is not a paragraph // Expand the gap to include the paragraph being merged gapFrom = $cut.pos; // To get the actual paragraph node gapTo = $cut.pos + $cut.nodeAfter.nodeSize - 1; } } } // collapse the range between end of last taskItem and after the paragraph // with the gap being the paragraph's content (i.e. take that content) // // we pass the structure we found earlier to join the p and taskItem nodes // // see https://prosemirror.net/docs/ref/#transform.ReplaceStep.constructor // see https://prosemirror.net/docs/ref/#transform.ReplaceAroundStep.constructor var tr = state.tr.step(new _transform.ReplaceAroundStep(from, to, gapFrom, gapTo, slice, insert, true)); if (fontSize && (0, _expValEquals.expValEquals)('platform_editor_small_font_size', 'isEnabled', true)) { var targetTaskListSmallTextAttrs = (0, _lists.getFirstParagraphBlockMarkAttrs)($cut.nodeBefore, fontSize); var followingListPos = $cut.pos + $cut.nodeAfter.nodeSize; var followingListNode = state.doc.resolve(followingListPos).nodeAfter; if (followingListNode && (0, _transforms.isTaskList)(followingListNode.type)) { var normalizedListNode = (0, _paste.normalizeNodeForTaskTextSize)(followingListNode, state.schema, targetTaskListSmallTextAttrs)[0]; if (normalizedListNode && normalizedListNode !== followingListNode) { var mappedFollowingListPos = tr.mapping.map(followingListPos); var currentFollowingListNode = tr.doc.nodeAt(mappedFollowingListPos); if (currentFollowingListNode) { tr = tr.replaceWith(mappedFollowingListPos, mappedFollowingListPos + currentFollowingListNode.nodeSize, normalizedListNode); } } } } if (dispatch) { dispatch(tr); } return true; } return false; }; };