{"version":3,"file":"wrap-selection-in-thread-mark-node.cjs","sources":["../../src/comments/wrap-selection-in-thread-mark-node.ts"],"sourcesContent":["/**\n * MIT License\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n * \n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n * \n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nimport type { LexicalNode, RangeSelection } from \"lexical\";\nimport { $isElementNode, $isTextNode } from \"lexical\";\n\nimport type { ThreadMarkNode } from \"./thread-mark-node\";\nimport { $createThreadMarkNode, $isThreadMarkNode } from \"./thread-mark-node\";\n\nexport default function $wrapSelectionInThreadMarkNode(\n  selection: RangeSelection,\n  isBackward: boolean,\n  id: string,\n  createNode?: (ids: Array<string>) => ThreadMarkNode\n): void {\n  const nodes = selection.getNodes();\n  const anchorOffset = selection.anchor.offset;\n  const focusOffset = selection.focus.offset;\n  const nodesLength = nodes.length;\n  const startOffset = isBackward ? focusOffset : anchorOffset;\n  const endOffset = isBackward ? anchorOffset : focusOffset;\n  let currentNodeParent;\n  let lastCreatedMarkNode;\n\n  // We only want wrap adjacent text nodes, line break nodes\n  // and inline element nodes. For decorator nodes and block\n  // element nodes, we step out of their boundary and start\n  // again after, if there are more nodes.\n  for (let i = 0; i < nodesLength; i++) {\n    const node = nodes[i];\n    if (\n      $isElementNode(lastCreatedMarkNode) &&\n      lastCreatedMarkNode.isParentOf(node)\n    ) {\n      // If the current node is a child of the last created mark node, there is nothing to do here\n      continue;\n    }\n    const isFirstNode = i === 0;\n    const isLastNode = i === nodesLength - 1;\n    let targetNode: LexicalNode | null = null;\n\n    if ($isTextNode(node)) {\n      // Case 1: The node is a text node and we can split it\n      const textContentSize = node.getTextContentSize();\n      const startTextOffset = isFirstNode ? startOffset : 0;\n      const endTextOffset = isLastNode ? endOffset : textContentSize;\n      if (startTextOffset === 0 && endTextOffset === 0) {\n        continue;\n      }\n      const splitNodes = node.splitText(startTextOffset, endTextOffset);\n      targetNode =\n        splitNodes.length > 1 &&\n        (splitNodes.length === 3 ||\n          (isFirstNode && !isLastNode) ||\n          endTextOffset === textContentSize)\n          ? splitNodes[1]\n          : splitNodes[0];\n    } else if ($isThreadMarkNode(node)) {\n      // Case 2: the node is a mark node and we can ignore it as a target,\n      // moving on to its children. Note that when we make a mark inside\n      // another mark, it may utlimately be unnested by a call to\n      // `registerNestedElementResolver<MarkNode>` somewhere else in the\n      // codebase.\n\n      continue;\n    } else if ($isElementNode(node) && node.isInline()) {\n      // Case 3: inline element nodes can be added in their entirety to the new\n      // mark\n      targetNode = node;\n    }\n\n    if (targetNode !== null) {\n      // Now that we have a target node for wrapping with a mark, we can run\n      // through special cases.\n      if (targetNode && targetNode.is(currentNodeParent)) {\n        // The current node is a child of the target node to be wrapped, there\n        // is nothing to do here.\n        continue;\n      }\n      const parentNode = targetNode.getParent();\n      if (parentNode === null || !parentNode.is(currentNodeParent)) {\n        // If the parent node is not the current node's parent node, we can\n        // clear the last created mark node.\n        lastCreatedMarkNode = undefined;\n      }\n\n      currentNodeParent = parentNode;\n\n      if (lastCreatedMarkNode === undefined) {\n        // If we don't have a created mark node, we can make one\n        const createMarkNode = createNode || $createThreadMarkNode;\n        lastCreatedMarkNode = createMarkNode([id]);\n        targetNode.insertBefore(lastCreatedMarkNode);\n      }\n\n      // Add the target node to be wrapped in the latest created mark node\n      lastCreatedMarkNode.append(targetNode);\n    } else {\n      // If we don't have a target node to wrap we can clear our state and\n      // continue on with the next node\n      currentNodeParent = undefined;\n      lastCreatedMarkNode = undefined;\n    }\n  }\n  // Make selection collapsed at the end\n  if ($isElementNode(lastCreatedMarkNode)) {\n    if (isBackward) {\n      lastCreatedMarkNode.selectStart();\n    } else {\n      lastCreatedMarkNode.selectEnd();\n    }\n  }\n}\n"],"names":["$isElementNode","$isTextNode","$isThreadMarkNode","$createThreadMarkNode"],"mappings":"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"}