import { FlowBlock, Layout, Measure, Line } from '../../contracts/src/index.js'; import { Point, FragmentHit, PositionHit } from './position-hit.js'; export type { HeaderFooterType } from '../../contracts/src/index.js'; export { extractIdentifierFromConverter, getHeaderFooterType, defaultHeaderFooterIdentifier, resolveHeaderFooterForPage, buildMultiSectionIdentifier, defaultMultiSectionIdentifier, getHeaderFooterTypeForSection, getHeaderFooterIdForPage, resolveHeaderFooterForPageAndSection, } from './headerFooterUtils.js'; export type { HeaderFooterIdentifier, MultiSectionHeaderFooterIdentifier, SectionHeaderFooterIds, } from './headerFooterUtils.js'; export { layoutHeaderFooterWithCache, type HeaderFooterBatchResult, getBucketForPageNumber, getBucketRepresentative, } from './layoutHeaderFooter.js'; export type { HeaderFooterBatch, DigitBucket } from './layoutHeaderFooter.js'; export { findWordBoundaries, findParagraphBoundaries } from './text-boundaries.js'; export type { BoundaryRange } from './text-boundaries.js'; export { buildSectionAwareHeaderFooterLayoutKey, buildSectionContentWidth, buildEffectiveHeaderFooterRefsBySection, collectReferencedHeaderFooterRIds, buildSectionAwareHeaderFooterMeasurementGroups, } from './sectionAwareHeaderFooter.js'; export type { HeaderFooterSectionKind, HeaderFooterRefs, SectionAwareHeaderFooterMeasurementGroup, } from './sectionAwareHeaderFooter.js'; export { incrementalLayout, measureCache, normalizeMargin } from './incrementalLayout.js'; export type { HeaderFooterLayoutResult, IncrementalLayoutResult } from './incrementalLayout.js'; export { computeDisplayPageNumber } from '../../layout-engine/src/index.js'; export type { DisplayPageInfo, HeaderFooterConstraints } from '../../layout-engine/src/index.js'; export { remeasureParagraph } from './remeasure.js'; export { measureCharacterX } from './text-measurement.js'; export { sliceRunsForLine } from '../../contracts/src/index.js'; export { clickToPositionDom, findPageElement } from './dom-mapping.js'; export { isListItem, getWordLayoutConfig, calculateTextStartIndent, extractParagraphIndent } from './list-indent-utils.js'; export type { TextIndentCalculationParams } from './list-indent-utils.js'; export { LayoutVersionLogger } from './instrumentation.js'; export { FontMetricsCache } from './font-metrics-cache.js'; export type { FontMetrics, FontMetricsCacheConfig } from './font-metrics-cache.js'; export { ParagraphLineCache } from './paragraph-line-cache.js'; export type { LineInfo, ParagraphLines } from './paragraph-line-cache.js'; export { CursorRenderer } from './cursor-renderer.js'; export type { CursorRendererOptions, CursorRect } from './cursor-renderer.js'; export { LocalParagraphLayout } from './local-paragraph-layout.js'; export type { LocalLayoutResult, TextRun } from './local-paragraph-layout.js'; export { PmDomFallback } from './pm-dom-fallback.js'; export type { PageTransform, PmEditorView } from './pm-dom-fallback.js'; export { PageGeometryHelper } from './page-geometry-helper.js'; export type { PageGeometryConfig } from './page-geometry-helper.js'; export { DirtyTracker } from './dirty-tracker.js'; export type { DirtyRange } from './dirty-tracker.js'; export { DebouncedPassManager } from './debounced-passes.js'; export type { DebouncedPass } from './debounced-passes.js'; export { PmPositionValidator } from './pm-position-validator.js'; export type { ValidationResult, ValidationError } from './pm-position-validator.js'; export { ImeHandler } from './ime-handler.js'; export type { ImeState } from './ime-handler.js'; export { TableHandler } from './table-handler.js'; export type { TableLayoutState } from './table-handler.js'; export { TrackChangesHandler } from './track-changes-handler.js'; export type { TrackChangeSpan } from './track-changes-handler.js'; export { CacheWarmer } from './cache-warmer.js'; export type { WarmingConfig, ParagraphWarmInfo } from './cache-warmer.js'; export { PerformanceMetricsCollector, perfMetrics } from './performance-metrics.js'; export type { MetricSample, MetricSummary, TypingPerfMetrics, BudgetViolation } from './performance-metrics.js'; export { SafetyNet } from './safety-net.js'; export type { FallbackReason, SafetyConfig } from './safety-net.js'; export { FocusWatchdog } from './focus-watchdog.js'; export type { FocusWatchdogConfig } from './focus-watchdog.js'; export { hashParagraphBorder, hashParagraphBorders, hashParagraphAttrs, hashBorderSpec, hashTableBorderValue, hashTableBorders, hashCellBorders, hasStringProp, hasNumberProp, hasBooleanProp, getRunStringProp, getRunNumberProp, getRunBooleanProp, } from './paragraph-hash-utils.js'; export type { LayoutHit, LayoutHitDiagnostic, LayoutFragmentOpaqueRange, LayoutFragmentSubrange, LayoutRangeMapping, LayoutRect, PmOpaqueRange, } from './neutral-hit.js'; export { hitTestNeutral, mapRangeToFragmentsNeutral } from './neutral-hit.js'; export type { Point, PageHit, FragmentHit, PositionHit, TableHitResult, GeometryPageHint, ClickToPositionGeometryOptions, } from './position-hit.js'; export { isAtomicFragment, getAtomicPmRange, isRtlBlock, determineColumn, findLineIndexAtY, mapPointToPm, snapToNearestFragment, hitTestPage, hitTestFragment, hitTestAtomicFragment, hitTestTableFragment, findBlockIndexByFragmentId, calculatePageTopFallback, resolvePositionHitFromDomPosition, clickToPositionGeometry, } from './position-hit.js'; export type Rect = { x: number; y: number; width: number; height: number; pageIndex: number; }; /** * Compatibility wrapper — delegates to resolvePositionHitFromDomPosition and * clickToPositionGeometry from position-hit.ts. * * Production super-editor callers should use resolvePointerPositionHit (from * PositionHitResolver.ts) instead. This wrapper exists so that external * consumers and tests that import clickToPosition from @superdoc/layout-bridge * continue to work unchanged. */ export declare function clickToPosition(layout: Layout, blocks: FlowBlock[], measures: Measure[], containerPoint: Point, domContainer?: HTMLElement, clientX?: number, clientY?: number, geometryHelper?: import('./page-geometry-helper.js').PageGeometryHelper): PositionHit | null; /** * Given a PM range [from, to), return selection rectangles for highlighting. * * @param layout - The layout containing page and fragment data * @param blocks - Array of flow blocks * @param measures - Array of measurements corresponding to blocks * @param from - Start PM position * @param to - End PM position * @param geometryHelper - Optional PageGeometryHelper for accurate Y calculations (recommended) * @returns Array of selection rectangles in container space */ export declare function selectionToRects(layout: Layout, blocks: FlowBlock[], measures: Measure[], from: number, to: number, geometryHelper?: import('./page-geometry-helper.js').PageGeometryHelper): Rect[]; export declare function getFragmentAtPosition(layout: Layout, blocks: FlowBlock[], measures: Measure[], pos: number): FragmentHit | null; export declare function findLinesIntersectingRange(block: FlowBlock, measure: Measure, from: number, to: number): { line: Line; index: number; }[]; /** * Computes the ProseMirror position range for a line within a paragraph block. * * This function calculates the start and end PM positions by iterating through all runs * that contribute to the line, handling partial runs at line boundaries and accounting * for various run types (text, images, breaks, annotations). * * **Empty Run Handling (SD-1108 Fix):** * Unlike `pmPosToCharOffset` which skips empty runs during position-to-character mapping, * this function intentionally PRESERVES empty runs to support cursor positioning in * zero-width content like empty table cells. Empty runs carry PM position metadata that * enables click-to-position mapping even when there's no visible text. * * **Why the difference?** * - `computeLinePmRange`: Used for spatial operations (click mapping, selection highlighting) * where we need to know the PM range of ALL content, including zero-width positions. * - `pmPosToCharOffset`: Used for text measurement where only visible characters matter. * Empty runs contribute no pixels and should be skipped during character-based calculations. * * **Algorithm:** * 1. Filter out atomic runs (images, line breaks, field annotations) - they have no text length * 2. For each text run in the line: * a. If the run is empty (length 0), preserve its PM positions for cursor support * b. If the run has text, calculate PM positions based on character offsets * c. Handle partial runs (first/last in line) by adjusting offsets * 3. Return the accumulated PM range * * **Edge Cases Handled:** * - Empty runs (zero text length but valid PM positions) - PRESERVED for SD-1108 * - Atomic runs (images, breaks) - skipped, don't contribute to text range * - Runs with missing PM data - skipped with warning logged * - Runs with invalid PM positions (negative, Infinity, NaN) - logged as warnings * - Partial runs at line boundaries - offset calculations applied * * @param block - The flow block to compute PM range for (must be a paragraph block) * @param line - The line specification including run range (fromRun to toRun) and character offsets * @returns Object containing pmStart and pmEnd positions, or empty object if block is not a paragraph * * @example * ```typescript * // Normal text run * const range = computeLinePmRange(paragraphBlock, line); * // { pmStart: 10, pmEnd: 25 } * * // Empty table cell (SD-1108 fix) * const emptyRange = computeLinePmRange(emptyParagraphBlock, line); * // { pmStart: 15, pmEnd: 15 } - zero-width but valid for cursor positioning * ``` * * @see pmPosToCharOffset - Related function that skips empty runs during character offset calculation */ export declare function computeLinePmRange(block: FlowBlock, line: Line): { pmStart?: number; pmEnd?: number; }; /** * Convert a ProseMirror position to a character offset within a line. * * This function performs ratio-based interpolation to handle cases where the PM position * range doesn't match the text length (e.g., when a run has formatting marks or when * there are position gaps between runs due to wrapper nodes). * * Algorithm: * 1. Iterate through runs in the line * 2. For each run, calculate its PM range and character count * 3. If pmPos falls within the run's PM range: * - Use ratio interpolation: (pmPos - runStart) / runPmRange * runCharCount * - This handles cases where PM positions don't align 1:1 with characters * 4. Return the accumulated character offset * * Edge Cases: * - Position before line start: Returns 0 * - Position after line end: Returns total character count of the line * - Empty runs (images, breaks): Skipped, don't contribute to character count * - Runs with missing PM data: Skipped * - Zero-length PM range: Returns current accumulated offset without adding * * Performance: * - Time complexity: O(n) where n is the number of runs in the line * - Space complexity: O(1) * * @param block - The paragraph block containing the line * @param line - The line containing the position * @param pmPos - The ProseMirror position to convert * @returns Character offset from start of line (0-based), or 0 if position not found * * @example * ```typescript * // Run with PM range [10, 15] containing "Hello" (5 chars) * // pmPos = 12 should map to character offset 2 within the run * const offset = pmPosToCharOffset(block, line, 12); * // offset = 2 (ratio: (12-10)/(15-10) * 5 = 2/5 * 5 = 2) * ``` */ export declare function pmPosToCharOffset(block: FlowBlock, line: Line, pmPos: number): number; /** * Convert a ProseMirror position to a rendered character offset within a line. * * Unlike {@link pmPosToCharOffset}, this helper includes visual-only text runs * that do not carry PM positions. That matters for selection highlighting when * a line starts with rendered chrome such as a synthetic footnote number: * the marker consumes horizontal space in the painter, but it is not part of * the editable PM story. Using a PM-only offset would place the highlight too * far left by the marker's width. * * The returned offset is intended for visual X mapping, not for slicing PM text. */ export declare function pmPosToVisualCharOffset(block: FlowBlock, line: Line, pmPos: number): number; //# sourceMappingURL=index.d.ts.map