// packages/editor/src/components/collaborators-overlay/cursor-dom-utils.ts
var MAX_NODE_OFFSET_COUNT = 500;
var getCursorPosition = (absolutePositionIndex, blockElement, editorDocument, overlayRect) => {
  if (absolutePositionIndex === null || !blockElement) {
    return null;
  }
  return getOffsetPositionInBlock(
    blockElement,
    absolutePositionIndex,
    editorDocument,
    overlayRect
  ) ?? null;
};
var getOffsetPositionInBlock = (blockElement, charOffset, editorDocument, overlayRect) => {
  const { node, offset } = findInnerBlockOffset(
    blockElement,
    charOffset,
    editorDocument
  );
  const cursorRange = editorDocument.createRange();
  try {
    cursorRange.setStart(node, offset);
  } catch {
    return null;
  }
  cursorRange.collapse(true);
  const cursorRect = cursorRange.getBoundingClientRect();
  const blockRect = blockElement.getBoundingClientRect();
  let cursorX = 0;
  let cursorY = 0;
  if (cursorRect.x === 0 && cursorRect.y === 0 && cursorRect.width === 0 && cursorRect.height === 0) {
    cursorX = blockRect.left - overlayRect.left;
    cursorY = blockRect.top - overlayRect.top;
  } else {
    cursorX = cursorRect.left - overlayRect.left;
    cursorY = cursorRect.top - overlayRect.top;
  }
  let cursorHeight = cursorRect.height;
  if (cursorHeight === 0) {
    const view = editorDocument.defaultView ?? window;
    cursorHeight = parseInt(view.getComputedStyle(blockElement).lineHeight, 10) || blockRect.height;
  }
  return {
    x: cursorX,
    y: cursorY,
    height: cursorHeight
  };
};
var getSelectionRects = (blockElement, startOffset, endOffset, editorDocument, overlayRect) => {
  let normalizedStart = startOffset;
  let normalizedEnd = endOffset;
  if (normalizedStart > normalizedEnd) {
    [normalizedStart, normalizedEnd] = [normalizedEnd, normalizedStart];
  }
  const startPos = findInnerBlockOffset(
    blockElement,
    normalizedStart,
    editorDocument
  );
  const endPos = findInnerBlockOffset(
    blockElement,
    normalizedEnd,
    editorDocument
  );
  const range = editorDocument.createRange();
  try {
    range.setStart(startPos.node, startPos.offset);
    range.setEnd(endPos.node, endPos.offset);
  } catch {
    return null;
  }
  const clientRects = range.getClientRects();
  const rects = [];
  for (const rect of clientRects) {
    if (rect.width === 0 && rect.height === 0) {
      continue;
    }
    const x = rect.left - overlayRect.left;
    const y = rect.top - overlayRect.top;
    const isDuplicate = rects.some(
      (r) => r.x === x && r.y === y && r.width === rect.width && r.height === rect.height
    );
    if (isDuplicate) {
      continue;
    }
    rects.push({
      x,
      y,
      width: rect.width,
      height: rect.height
    });
  }
  return rects.length > 0 ? rects : null;
};
var getFullBlockSelectionRects = (blockElement, editorDocument, overlayRect) => {
  const range = editorDocument.createRange();
  range.selectNodeContents(blockElement);
  const clientRects = range.getClientRects();
  const rects = [];
  for (const rect of clientRects) {
    if (rect.width === 0 && rect.height === 0) {
      continue;
    }
    rects.push({
      x: rect.left - overlayRect.left,
      y: rect.top - overlayRect.top,
      width: rect.width,
      height: rect.height
    });
  }
  if (rects.length === 0) {
    const blockRect = blockElement.getBoundingClientRect();
    if (blockRect.width > 0 && blockRect.height > 0) {
      rects.push({
        x: blockRect.left - overlayRect.left,
        y: blockRect.top - overlayRect.top,
        width: blockRect.width,
        height: blockRect.height
      });
    }
  }
  return rects;
};
var getBlocksBetween = (startBlockId, endBlockId, editorDocument) => {
  const allBlocks = editorDocument.querySelectorAll("[data-block]");
  let startIndex = -1;
  let endIndex = -1;
  for (let i = 0; i < allBlocks.length; i++) {
    const blockId = allBlocks[i].getAttribute("data-block");
    if (blockId === startBlockId) {
      startIndex = i;
    }
    if (blockId === endBlockId) {
      endIndex = i;
    }
  }
  if (startIndex === -1 || endIndex === -1) {
    return [];
  }
  if (startIndex > endIndex) {
    [startIndex, endIndex] = [endIndex, startIndex];
  }
  const result = [];
  for (let i = startIndex + 1; i < endIndex; i++) {
    result.push(allBlocks[i]);
  }
  return result;
};
var findInnerBlockOffset = (blockElement, offset, editorDocument) => {
  const treeWalker = editorDocument.createTreeWalker(
    blockElement,
    NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT
    // eslint-disable-line no-bitwise
  );
  let currentOffset = 0;
  let lastTextNode = null;
  let node = null;
  let nodeCount = 1;
  while (node = treeWalker.nextNode()) {
    nodeCount++;
    if (nodeCount > MAX_NODE_OFFSET_COUNT) {
      if (lastTextNode) {
        return { node: lastTextNode, offset: 0 };
      }
      return { node: blockElement, offset: 0 };
    }
    const nodeLength = node.nodeValue?.length ?? 0;
    if (node.nodeType === Node.ELEMENT_NODE) {
      if (node.nodeName === "BR") {
        if (currentOffset + 1 >= offset) {
          const nodeAfterBr = treeWalker.nextNode();
          if (nodeAfterBr?.nodeType === Node.TEXT_NODE) {
            return { node: nodeAfterBr, offset: 0 };
          } else if (lastTextNode) {
            return {
              node: lastTextNode,
              offset: lastTextNode.nodeValue?.length ?? 0
            };
          }
          return { node: blockElement, offset: 0 };
        }
        currentOffset += 1;
        continue;
      } else {
        continue;
      }
    }
    if (nodeLength === 0) {
      continue;
    }
    if (currentOffset + nodeLength >= offset) {
      return { node, offset: offset - currentOffset };
    }
    currentOffset += nodeLength;
    if (node.nodeType === Node.TEXT_NODE) {
      lastTextNode = node;
    }
  }
  if (lastTextNode && lastTextNode.nodeValue?.length) {
    return { node: lastTextNode, offset: lastTextNode.nodeValue.length };
  }
  return { node: blockElement, offset: 0 };
};
var isNodeBefore = (a, b) => a.compareDocumentPosition(b) === Node.DOCUMENT_POSITION_FOLLOWING;
export {
  findInnerBlockOffset,
  getBlocksBetween,
  getCursorPosition,
  getFullBlockSelectionRects,
  getSelectionRects,
  isNodeBefore
};
//# sourceMappingURL=cursor-dom-utils.mjs.map
