{
  "version": 3,
  "sources": ["../../../src/components/collaborators-overlay/compute-selection.ts"],
  "sourcesContent": ["import { SelectionDirection, SelectionType } from '@wordpress/core-data';\nimport type { ResolvedSelection } from '@wordpress/core-data';\n\nimport {\n\tgetCursorPosition,\n\tgetSelectionRects,\n\tgetFullBlockSelectionRects,\n\tgetBlocksBetween,\n\tisNodeBefore,\n} from './cursor-dom-utils';\nimport type { CursorCoords, SelectionRect } from './cursor-dom-utils';\n\n/** Common parameters passed to cursor/selection computation helpers. */\ninterface OverlayContext {\n\teditorDocument: Document;\n\toverlayRect: DOMRect;\n}\n\n/** Selection rects and the resolved block element for a single-block selection. */\ninterface SingleBlockResult {\n\trects: SelectionRect[];\n\tblockElement: HTMLElement | null;\n}\n\n/** Selection rects and the resolved block elements for a multi-block selection. */\ninterface MultiBlockResult {\n\trects: SelectionRect[];\n\tfirstBlock: HTMLElement | null;\n\tlastBlock: HTMLElement | null;\n\tfirstBlockClientId: string | null;\n}\n\n/** Result of computing visual cursor/selection state for a single user. */\nexport interface SelectionVisual {\n\tcoords?: CursorCoords | null;\n\tselectionRects?: SelectionRect[];\n}\n\n/**\n * Compute cursor coords and optional selection rects for a single user's selection.\n *\n * @param selection      - The selection state from the awareness layer.\n * @param start          - Start position (block clientId + text index).\n * @param end            - End position (only for range selections).\n * @param overlayContext - Shared editor document / overlay references.\n * @return Cursor coordinates and optional selection rectangles.\n */\nexport function computeSelectionVisual(\n\tselection: any,\n\tstart: ResolvedSelection,\n\tend: ResolvedSelection | undefined,\n\toverlayContext: OverlayContext\n): SelectionVisual {\n\tif (\n\t\tselection.type === SelectionType.None ||\n\t\tselection.type === SelectionType.WholeBlock\n\t) {\n\t\treturn {};\n\t}\n\n\tif ( selection.type === SelectionType.Cursor ) {\n\t\treturn computeCursorOnly( start, overlayContext );\n\t}\n\n\t// SelectionInOneBlock or SelectionInMultipleBlocks.\n\tif ( ! end ) {\n\t\treturn {};\n\t}\n\treturn computeTextSelection( selection, start, end, overlayContext );\n}\n\n/**\n * Compute cursor coordinates for a simple cursor (no highlighted text).\n *\n * @param start          - Cursor position (block clientId + text index).\n * @param overlayContext - Shared editor document / overlay references.\n * @return Cursor coordinates.\n */\nfunction computeCursorOnly(\n\tstart: ResolvedSelection,\n\toverlayContext: OverlayContext\n): SelectionVisual {\n\tif ( ! start.localClientId ) {\n\t\treturn {};\n\t}\n\tconst blockElement =\n\t\toverlayContext.editorDocument.querySelector< HTMLElement >(\n\t\t\t`[data-block=\"${ start.localClientId }\"]`\n\t\t);\n\treturn {\n\t\tcoords: getCursorPosition(\n\t\t\tstart.richTextOffset,\n\t\t\tblockElement,\n\t\t\toverlayContext.editorDocument,\n\t\t\toverlayContext.overlayRect\n\t\t),\n\t};\n}\n\n/**\n * Compute cursor coordinates and selection highlight rects for a text selection\n * (single-block or multi-block).\n *\n * @param selection      - The selection state.\n * @param start          - Start position (block clientId + text index).\n * @param end            - End position (block clientId + text index).\n * @param overlayContext - Shared editor document / overlay references.\n * @return Cursor coordinates and optional selection rectangles.\n */\nfunction computeTextSelection(\n\tselection: any,\n\tstart: ResolvedSelection,\n\tend: ResolvedSelection,\n\toverlayContext: OverlayContext\n): SelectionVisual {\n\tif (\n\t\t! start.localClientId ||\n\t\t! end.localClientId ||\n\t\tstart.richTextOffset === null ||\n\t\tend.richTextOffset === null\n\t) {\n\t\treturn {};\n\t}\n\n\tconst isReverse =\n\t\tselection.selectionDirection === SelectionDirection.Backward;\n\tconst activeEnd = isReverse ? start : end;\n\n\tlet allRects: SelectionRect[];\n\tlet activeEndBlock: HTMLElement | null = null;\n\n\tif ( selection.type === SelectionType.SelectionInOneBlock ) {\n\t\tconst result = computeSingleBlockRects( start, end, overlayContext );\n\t\tallRects = result.rects;\n\t\t// Single block: start and end share the same block element.\n\t\tactiveEndBlock = result.blockElement;\n\t} else {\n\t\tconst result = computeMultiBlockRects( start, end, overlayContext );\n\t\tallRects = result.rects;\n\t\t// Pick the block element that matches the active end.\n\t\tactiveEndBlock =\n\t\t\tactiveEnd.localClientId === result.firstBlockClientId\n\t\t\t\t? result.firstBlock\n\t\t\t\t: result.lastBlock;\n\t}\n\n\tif ( allRects.length > 0 ) {\n\t\treturn {\n\t\t\tcoords: getCursorPosition(\n\t\t\t\tactiveEnd.richTextOffset,\n\t\t\t\tactiveEndBlock,\n\t\t\t\toverlayContext.editorDocument,\n\t\t\t\toverlayContext.overlayRect\n\t\t\t),\n\t\t\tselectionRects: allRects,\n\t\t};\n\t}\n\n\t// Fallback: cursor at start position only.\n\tconst startBlock =\n\t\toverlayContext.editorDocument.querySelector< HTMLElement >(\n\t\t\t`[data-block=\"${ start.localClientId }\"]`\n\t\t);\n\n\treturn {\n\t\tcoords: getCursorPosition(\n\t\t\tstart.richTextOffset,\n\t\t\tstartBlock,\n\t\t\toverlayContext.editorDocument,\n\t\t\toverlayContext.overlayRect\n\t\t),\n\t};\n}\n\n/**\n * Compute selection rects for a selection within a single block.\n *\n * @param start          - Start position (block clientId + text index).\n * @param end            - End position (block clientId + text index).\n * @param overlayContext - Shared editor document / overlay references.\n * @return Array of selection rectangles.\n */\nfunction computeSingleBlockRects(\n\tstart: ResolvedSelection,\n\tend: ResolvedSelection,\n\toverlayContext: OverlayContext\n): SingleBlockResult {\n\tconst blockElement =\n\t\toverlayContext.editorDocument.querySelector< HTMLElement >(\n\t\t\t`[data-block=\"${ start.localClientId }\"]`\n\t\t);\n\tif (\n\t\t! blockElement ||\n\t\tstart.richTextOffset === null ||\n\t\tend.richTextOffset === null\n\t) {\n\t\treturn { rects: [], blockElement: null };\n\t}\n\treturn {\n\t\trects:\n\t\t\tgetSelectionRects(\n\t\t\t\tblockElement,\n\t\t\t\tstart.richTextOffset,\n\t\t\t\tend.richTextOffset,\n\t\t\t\toverlayContext.editorDocument,\n\t\t\t\toverlayContext.overlayRect\n\t\t\t) ?? [],\n\t\tblockElement,\n\t};\n}\n\n/**\n * Compute selection rects for a selection spanning multiple blocks.\n *\n * Normalizes to document order \u2014 for backward selections the block editor\n * reports start after end.\n *\n * @param start          - Start position (block clientId + text index).\n * @param end            - End position (block clientId + text index).\n * @param overlayContext - Shared editor document / overlay references.\n * @return Array of selection rectangles.\n */\nfunction computeMultiBlockRects(\n\tstart: ResolvedSelection,\n\tend: ResolvedSelection,\n\toverlayContext: OverlayContext\n): MultiBlockResult {\n\tlet docFirst = start;\n\tlet docLast = end;\n\tlet firstBlock = overlayContext.editorDocument.querySelector< HTMLElement >(\n\t\t`[data-block=\"${ docFirst.localClientId }\"]`\n\t);\n\tlet lastBlock = overlayContext.editorDocument.querySelector< HTMLElement >(\n\t\t`[data-block=\"${ docLast.localClientId }\"]`\n\t);\n\n\t// Swap to document order if needed.\n\tif ( firstBlock && lastBlock && isNodeBefore( lastBlock, firstBlock ) ) {\n\t\tdocFirst = end;\n\t\tdocLast = start;\n\t\t[ firstBlock, lastBlock ] = [ lastBlock, firstBlock ];\n\t}\n\n\tif (\n\t\t! firstBlock ||\n\t\t! lastBlock ||\n\t\tdocFirst.richTextOffset === null ||\n\t\tdocLast.richTextOffset === null ||\n\t\t! docFirst.localClientId ||\n\t\t! docLast.localClientId\n\t) {\n\t\treturn {\n\t\t\trects: [],\n\t\t\tfirstBlock: null,\n\t\t\tlastBlock: null,\n\t\t\tfirstBlockClientId: null,\n\t\t};\n\t}\n\n\tconst allRects: SelectionRect[] = [];\n\n\t// First block: from start offset to end of block.\n\tconst startRects = getSelectionRects(\n\t\tfirstBlock,\n\t\tdocFirst.richTextOffset,\n\t\tNumber.MAX_SAFE_INTEGER,\n\t\toverlayContext.editorDocument,\n\t\toverlayContext.overlayRect\n\t);\n\tif ( startRects ) {\n\t\tallRects.push( ...startRects );\n\t}\n\n\t// Intermediate blocks: full content.\n\tconst intermediateBlocks = getBlocksBetween(\n\t\tdocFirst.localClientId,\n\t\tdocLast.localClientId,\n\t\toverlayContext.editorDocument\n\t);\n\tfor ( const intermediateBlock of intermediateBlocks ) {\n\t\tconst rects = getFullBlockSelectionRects(\n\t\t\tintermediateBlock,\n\t\t\toverlayContext.editorDocument,\n\t\t\toverlayContext.overlayRect\n\t\t);\n\t\tallRects.push( ...rects );\n\t}\n\n\t// Last block: from 0 to end offset.\n\tconst endRects = getSelectionRects(\n\t\tlastBlock,\n\t\t0,\n\t\tdocLast.richTextOffset,\n\t\toverlayContext.editorDocument,\n\t\toverlayContext.overlayRect\n\t);\n\tif ( endRects ) {\n\t\tallRects.push( ...endRects );\n\t}\n\n\treturn {\n\t\trects: allRects,\n\t\tfirstBlock,\n\t\tlastBlock,\n\t\tfirstBlockClientId: docFirst.localClientId,\n\t};\n}\n"],
  "mappings": "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",
  "names": []
}
