@viswa-test/test-citation 0.0.390 → 0.0.391
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/features/CognitiveCompare/CitationAnchor.js +1 -1
- package/dist/cjs/features/CognitiveCompare/CitationAnchor.js.map +1 -1
- package/dist/cjs/features/CognitiveCompare/CitationRenderer.js +1 -1
- package/dist/cjs/features/CognitiveCompare/CitationRenderer.js.map +1 -1
- package/dist/cjs/features/CognitiveCompare/CognitiveCompare.js +1 -1
- package/dist/cjs/features/CognitiveCompare/CognitiveCompare.js.map +1 -1
- package/dist/cjs/features/CognitiveCompare/CognitiveCompareConstants.js +1 -1
- package/dist/cjs/features/CognitiveCompare/CognitiveCompareConstants.js.map +1 -1
- package/dist/cjs/features/CognitiveCompare/CognitiveComparehelpers.js +1 -1
- package/dist/cjs/features/CognitiveCompare/CognitiveComparehelpers.js.map +1 -1
- package/dist/cjs/features/CognitiveCompare/CognitivePopup.js +1 -1
- package/dist/cjs/features/CognitiveCompare/CognitivePopup.js.map +1 -1
- package/dist/cjs/features/CognitiveCompare/CompareContext.js +1 -1
- package/dist/cjs/features/CognitiveCompare/CompareContext.js.map +1 -1
- package/dist/cjs/features/CognitiveCompare/Guidelines/components/GuidelinePanel.js +1 -1
- package/dist/cjs/features/CognitiveCompare/Guidelines/components/GuidelinePanel.js.map +1 -1
- package/dist/cjs/features/CognitiveCompare/Guidelines/components/WebGptPanel.js +1 -1
- package/dist/cjs/features/CognitiveCompare/Guidelines/components/WebGptPanel.js.map +1 -1
- package/dist/cjs/features/CognitiveCompare/Guidelines/utils/processGuidelinesMarkdown.js +1 -1
- package/dist/cjs/features/CognitiveCompare/Guidelines/utils/processGuidelinesMarkdown.js.map +1 -1
- package/dist/cjs/features/CognitiveCompare/components/LHSSectionRow.js +1 -1
- package/dist/cjs/features/CognitiveCompare/components/LHSSectionRow.js.map +1 -1
- package/dist/cjs/features/CognitiveCompare/components/RHSSectionRow.js +1 -1
- package/dist/cjs/features/CognitiveCompare/components/RHSSectionRow.js.map +1 -1
- package/dist/cjs/features/CognitiveCompare/components/SectionAccordion.js +1 -1
- package/dist/cjs/features/CognitiveCompare/components/SectionAccordion.js.map +1 -1
- package/dist/cjs/features/CognitiveCompare/components/SubSectionAccordion.js +1 -1
- package/dist/cjs/features/CognitiveCompare/components/SubSectionAccordion.js.map +1 -1
- package/dist/cjs/features/CognitiveCompare/components/SvgConnectors.js +1 -1
- package/dist/cjs/features/CognitiveCompare/components/SvgConnectors.js.map +1 -1
- package/dist/cjs/features/CognitiveCompare/hooks/memoizedMarkdown.js +1 -1
- package/dist/cjs/features/CognitiveCompare/hooks/memoizedMarkdown.js.map +1 -1
- package/dist/cjs/features/CognitiveCompare/hooks/useCompareData.js +1 -1
- package/dist/cjs/features/CognitiveCompare/hooks/useCompareData.js.map +1 -1
- package/dist/cjs/features/CognitiveCompare/hooks/useLinesCalculator.js +1 -1
- package/dist/cjs/features/CognitiveCompare/hooks/useLinesCalculator.js.map +1 -1
- package/dist/cjs/features/CognitiveCompare/hooks/useSideBySide.js +1 -1
- package/dist/cjs/features/CognitiveCompare/hooks/useSideBySide.js.map +1 -1
- package/dist/cjs/features/PdfViewer/PdfToolbar.js +1 -1
- package/dist/cjs/features/PdfViewer/PdfToolbar.js.map +1 -1
- package/dist/cjs/features/PdfViewer/PdfViewer.css.js +1 -1
- package/dist/cjs/features/PdfViewer/PdfViewer.js +1 -1
- package/dist/cjs/features/PdfViewer/PdfViewer.js.map +1 -1
- package/dist/cjs/features/PdfViewer/rotationManager.js +1 -1
- package/dist/cjs/features/PdfViewer/rotationManager.js.map +1 -1
- package/dist/cjs/features/PdfViewer/usePdfHighlight.js +1 -1
- package/dist/cjs/features/PdfViewer/usePdfHighlight.js.map +1 -1
- package/dist/cjs/features/PdfViewer/zoomStateManager.js +2 -0
- package/dist/cjs/features/PdfViewer/zoomStateManager.js.map +1 -0
- package/dist/cjs/features/SegmentReviewComponents/CognitiveScoreBadge.js +1 -1
- package/dist/cjs/features/SegmentReviewComponents/CognitiveScoreBadge.js.map +1 -1
- package/dist/cjs/features/SegmentReviewComponents/reviewStepAdapters.js +1 -1
- package/dist/cjs/features/SegmentReviewComponents/reviewStepAdapters.js.map +1 -1
- package/dist/features/CognitiveCompare/CitationAnchor.js +1 -1
- package/dist/features/CognitiveCompare/CitationAnchor.js.map +1 -1
- package/dist/features/CognitiveCompare/CitationRenderer.js +1 -1
- package/dist/features/CognitiveCompare/CitationRenderer.js.map +1 -1
- package/dist/features/CognitiveCompare/CognitiveCompare.js +1 -1
- package/dist/features/CognitiveCompare/CognitiveCompare.js.map +1 -1
- package/dist/features/CognitiveCompare/CognitiveCompareConstants.js +1 -1
- package/dist/features/CognitiveCompare/CognitiveCompareConstants.js.map +1 -1
- package/dist/features/CognitiveCompare/CognitiveComparehelpers.js +1 -1
- package/dist/features/CognitiveCompare/CognitiveComparehelpers.js.map +1 -1
- package/dist/features/CognitiveCompare/CognitivePopup.js +1 -1
- package/dist/features/CognitiveCompare/CognitivePopup.js.map +1 -1
- package/dist/features/CognitiveCompare/CompareContext.js +1 -1
- package/dist/features/CognitiveCompare/CompareContext.js.map +1 -1
- package/dist/features/CognitiveCompare/Guidelines/components/GuidelinePanel.js +1 -1
- package/dist/features/CognitiveCompare/Guidelines/components/GuidelinePanel.js.map +1 -1
- package/dist/features/CognitiveCompare/Guidelines/components/WebGptPanel.js +1 -1
- package/dist/features/CognitiveCompare/Guidelines/components/WebGptPanel.js.map +1 -1
- package/dist/features/CognitiveCompare/Guidelines/utils/processGuidelinesMarkdown.js +1 -1
- package/dist/features/CognitiveCompare/Guidelines/utils/processGuidelinesMarkdown.js.map +1 -1
- package/dist/features/CognitiveCompare/components/LHSSectionRow.js +1 -1
- package/dist/features/CognitiveCompare/components/LHSSectionRow.js.map +1 -1
- package/dist/features/CognitiveCompare/components/RHSSectionRow.js +1 -1
- package/dist/features/CognitiveCompare/components/RHSSectionRow.js.map +1 -1
- package/dist/features/CognitiveCompare/components/SectionAccordion.js +1 -1
- package/dist/features/CognitiveCompare/components/SectionAccordion.js.map +1 -1
- package/dist/features/CognitiveCompare/components/SubSectionAccordion.js +1 -1
- package/dist/features/CognitiveCompare/components/SubSectionAccordion.js.map +1 -1
- package/dist/features/CognitiveCompare/components/SvgConnectors.js +1 -1
- package/dist/features/CognitiveCompare/components/SvgConnectors.js.map +1 -1
- package/dist/features/CognitiveCompare/hooks/memoizedMarkdown.js +1 -1
- package/dist/features/CognitiveCompare/hooks/memoizedMarkdown.js.map +1 -1
- package/dist/features/CognitiveCompare/hooks/useCompareData.js +1 -1
- package/dist/features/CognitiveCompare/hooks/useCompareData.js.map +1 -1
- package/dist/features/CognitiveCompare/hooks/useLinesCalculator.js +1 -1
- package/dist/features/CognitiveCompare/hooks/useLinesCalculator.js.map +1 -1
- package/dist/features/CognitiveCompare/hooks/useSideBySide.js +1 -1
- package/dist/features/CognitiveCompare/hooks/useSideBySide.js.map +1 -1
- package/dist/features/PdfViewer/PdfToolbar.js +1 -1
- package/dist/features/PdfViewer/PdfToolbar.js.map +1 -1
- package/dist/features/PdfViewer/PdfViewer.css.js +1 -1
- package/dist/features/PdfViewer/PdfViewer.js +1 -1
- package/dist/features/PdfViewer/PdfViewer.js.map +1 -1
- package/dist/features/PdfViewer/rotationManager.js +1 -1
- package/dist/features/PdfViewer/rotationManager.js.map +1 -1
- package/dist/features/PdfViewer/usePdfHighlight.js +1 -1
- package/dist/features/PdfViewer/usePdfHighlight.js.map +1 -1
- package/dist/features/PdfViewer/zoomStateManager.js +2 -0
- package/dist/features/PdfViewer/zoomStateManager.js.map +1 -0
- package/dist/features/SegmentReviewComponents/CognitiveScoreBadge.js +1 -1
- package/dist/features/SegmentReviewComponents/CognitiveScoreBadge.js.map +1 -1
- package/dist/features/SegmentReviewComponents/reviewStepAdapters.js +1 -1
- package/dist/features/SegmentReviewComponents/reviewStepAdapters.js.map +1 -1
- package/dist/types/features/CognitiveCompare/CitationAnchor.d.ts +0 -2
- package/dist/types/features/CognitiveCompare/CitationAnchor.d.ts.map +1 -1
- package/dist/types/features/CognitiveCompare/CitationRenderer.d.ts +1 -8
- package/dist/types/features/CognitiveCompare/CitationRenderer.d.ts.map +1 -1
- package/dist/types/features/CognitiveCompare/CognitiveCompare.d.ts +1 -1
- package/dist/types/features/CognitiveCompare/CognitiveCompare.d.ts.map +1 -1
- package/dist/types/features/CognitiveCompare/CognitiveCompareConstants.d.ts +1 -1
- package/dist/types/features/CognitiveCompare/CognitiveCompareConstants.d.ts.map +1 -1
- package/dist/types/features/CognitiveCompare/CognitiveCompareTypes.d.ts +3 -12
- package/dist/types/features/CognitiveCompare/CognitiveCompareTypes.d.ts.map +1 -1
- package/dist/types/features/CognitiveCompare/CognitiveComparehelpers.d.ts +0 -12
- package/dist/types/features/CognitiveCompare/CognitiveComparehelpers.d.ts.map +1 -1
- package/dist/types/features/CognitiveCompare/CognitivePopup.d.ts.map +1 -1
- package/dist/types/features/CognitiveCompare/CompareContext.d.ts +2 -9
- package/dist/types/features/CognitiveCompare/CompareContext.d.ts.map +1 -1
- package/dist/types/features/CognitiveCompare/Guidelines/components/GuidelinePanel.d.ts.map +1 -1
- package/dist/types/features/CognitiveCompare/Guidelines/components/WebGptPanel.d.ts.map +1 -1
- package/dist/types/features/CognitiveCompare/Guidelines/utils/processGuidelinesMarkdown.d.ts +1 -14
- package/dist/types/features/CognitiveCompare/Guidelines/utils/processGuidelinesMarkdown.d.ts.map +1 -1
- package/dist/types/features/CognitiveCompare/components/LHSSectionRow.d.ts.map +1 -1
- package/dist/types/features/CognitiveCompare/components/RHSSectionRow.d.ts.map +1 -1
- package/dist/types/features/CognitiveCompare/components/SectionAccordion.d.ts.map +1 -1
- package/dist/types/features/CognitiveCompare/components/SubSectionAccordion.d.ts.map +1 -1
- package/dist/types/features/CognitiveCompare/components/SvgConnectors.d.ts +3 -2
- package/dist/types/features/CognitiveCompare/components/SvgConnectors.d.ts.map +1 -1
- package/dist/types/features/CognitiveCompare/hooks/memoizedMarkdown.d.ts +1 -2
- package/dist/types/features/CognitiveCompare/hooks/memoizedMarkdown.d.ts.map +1 -1
- package/dist/types/features/CognitiveCompare/hooks/useCompareData.d.ts +1 -1
- package/dist/types/features/CognitiveCompare/hooks/useCompareData.d.ts.map +1 -1
- package/dist/types/features/CognitiveCompare/hooks/useLinesCalculator.d.ts.map +1 -1
- package/dist/types/features/CognitiveCompare/hooks/useSideBySide.d.ts.map +1 -1
- package/dist/types/features/PdfViewer/PdfToolbar.d.ts.map +1 -1
- package/dist/types/features/PdfViewer/PdfViewer.d.ts.map +1 -1
- package/dist/types/features/PdfViewer/rotationManager.d.ts.map +1 -1
- package/dist/types/features/PdfViewer/usePdfHighlight.d.ts +1 -2
- package/dist/types/features/PdfViewer/usePdfHighlight.d.ts.map +1 -1
- package/dist/types/features/PdfViewer/zoomStateManager.d.ts +21 -0
- package/dist/types/features/PdfViewer/zoomStateManager.d.ts.map +1 -0
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePdfHighlight.js","sources":["../../../src/features/PdfViewer/usePdfHighlight.tsx"],"sourcesContent":["import { useMemo, useRef, useState } from \"react\";\nimport { searchPlugin } from \"@react-pdf-viewer/search\";\nimport { pageNavigationPlugin } from \"@react-pdf-viewer/page-navigation\";\nimport { zoomPlugin } from \"@react-pdf-viewer/zoom\";\nimport { HighlightArea } from \"./PdfViewer\";\nimport {\n highlightPlugin,\n RenderHighlightsProps,\n} from \"@react-pdf-viewer/highlight\";\n\nexport const PdfHighlightControls = (\n highlightText: string[],\n highlightPages: Record<number, number>,\n viewerRef: React.RefObject<HTMLDivElement | null>,\n highlightPageSet : Set<number>,\n useCoordinates : boolean,\n highlightCordinatePages : HighlightArea[],\n highlightColor = \"yellow\", \n activeHighlightColor = \"#F6D739\",\n) => {\n const [highlightIndex, setHighlightIndex] = useState(0);\n const hasJumpedRef = useRef(false);\n const [cursorIndex, setCursorIndex] = useState(0);\n const visibleHighlightsRef = useRef<HTMLElement[]>([]);\n\n // Text normalization helpers\n\n const normalizeWhitespace = (value: string): string =>\n value.replace(/[^\\S\\n]+/g, \" \").trim();\n\n const stripMarkdownEmphasis = (line: string): string =>\n line.replace(/(^|\\W)[*_]{1,3}([^*_]+)[*_]{1,3}(?=\\W|$)/g, \"$1$2\");\n\n const normalizeForMatch = (value: string): string =>\n (value || \"\")\n .toLowerCase()\n .replace(/\\u00ad/g, \"\")\n .replace(/[\"\"]/g, '\"')\n .replace(/['']/g, \"'\")\n .replace(/[\\u2013\\u2014]/g, \"-\")\n .replace(/-/g, \" \")\n .replace(/[^\\w\\s]/g, \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n\n const stripLeadingIndex = (line: string): string => {\n let trimmed = line.trim();\n trimmed = trimmed\n .replace(/[\\u200B-\\u200D\\uFEFF]/g, \"\")\n .replace(/[\\u00A0\\u2009\\u202F]/g, \" \");\n trimmed = trimmed.replace(/^[-•]\\s+/, \"\");\n const match = trimmed.match(\n /^((\\d+(?:\\.\\d+)*[.)]?)|[A-Za-z][.)]|\\([A-Za-z0-9]+\\)|(?:i|ii|iii|iv|v|vi|vii|viii|ix|x)[.)])\\s*/i\n );\n if (match) return trimmed.slice(match[0].length).trim();\n return trimmed;\n };\n\n const buildMatchVariants = (line: string): Set<string> => {\n const normalized = normalizeForMatch(line);\n const compact = normalized.replace(/\\s+/g, \"\");\n const variants = new Set<string>();\n if (normalized) variants.add(normalized);\n if (compact) variants.add(compact);\n return variants;\n };\n\n const buildSearchVariants = (line: string): string[] => {\n const base = normalizeWhitespace(\n line\n .replace(/[\\u00A0\\u2009\\u202F]/g, \" \")\n .replace(/\\u00ad/g, \"\")\n .replace(/[\"\"]/g, '\"')\n .replace(/['']/g, \"'\")\n );\n if (!base) return [];\n\n const dashNormalized = base.replace(/[\\u2013\\u2014]/g, \"-\");\n const dehyphenated = normalizeWhitespace(\n dashNormalized.replace(/(\\w)-\\s+(\\w)/g, \"$1$2\")\n );\n const hyphenToSpace = normalizeWhitespace(dashNormalized.replace(/-/g, \" \"));\n const hyphenRemoved = normalizeWhitespace(dashNormalized.replace(/-/g, \"\"));\n const punctuationStripped = normalizeWhitespace(base.replace(/[^\\w\\s]/g, \"\"));\n\n const variants = new Set<string>([\n base,\n dashNormalized,\n dehyphenated,\n hyphenToSpace,\n hyphenRemoved,\n punctuationStripped,\n ]);\n\n return Array.from(variants).filter(Boolean);\n };\n\n const decodeHtml = (str: string): string => {\n const textarea = document.createElement(\"textarea\");\n textarea.innerHTML = str;\n return textarea.value;\n };\n\n const getCleanedHighlightText = (text: string): string => {\n const cleanHighlight = text.replace(/\\\\([''])/g, \"$1\");\n const normalizedText = cleanHighlight.replace(/\\]\\s*\\n\\s*\\(/g, \"](\");\n return normalizedText\n .replace(/&[#\\w]+;/g, (match) => decodeHtml(match))\n .replace(/<br\\s*\\/?>/gi, \"\\n\")\n .replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, \"$1\")\n .replace(/`([^`]+)`/g, \"$1\");\n };\n\n const extractCleanLines = (text: string): string[] => {\n if (!text) return [];\n const cleaned = getCleanedHighlightText(text);\n\n return cleaned\n .split(/\\n+/)\n .map(stripLeadingIndex)\n .flatMap((line) => {\n const tableMatch = line.match(/^\\s*\\|(.+)\\|\\s*$/);\n if (tableMatch) {\n return tableMatch[1]\n .split(\"|\")\n .map((cell) => cell.trim())\n .filter(Boolean);\n }\n return [line];\n })\n .map((line) => normalizeWhitespace(stripMarkdownEmphasis(line)))\n .filter(Boolean);\n };\n\n const getMaxLineGap = (blocks: Array<{ lastTop: number }>): number => {\n if (blocks.length < 2) return 40;\n const diffs: number[] = [];\n for (let i = 1; i < blocks.length; i++) {\n const diff = Math.abs(blocks[i].lastTop - blocks[i - 1].lastTop);\n if (diff > 0) diffs.push(diff);\n }\n if (diffs.length === 0) return 40;\n diffs.sort((a, b) => a - b);\n const median = diffs[Math.floor(diffs.length / 2)];\n const scaled = Math.round(median * 2.25);\n return Math.min(60, Math.max(24, scaled));\n };\n\n type MergedHighlightArea = HighlightArea & {\n originalIndexes: number[];\n };\n\n // ─── Merge overlapping coordinate highlight areas on the same page ────────────\nconst mergeOverlappingAreas = (areas: HighlightArea[]): MergedHighlightArea[] => {\n if (areas.length === 0) return [];\n\n // Group by page\n const byPage = new Map<number, (HighlightArea & { originalIndex: number })[]>();\n areas.forEach((h, i) => {\n const pageKey = h.pageNumber != null ? h.pageNumber - 1 : h.pageIndex;\n if (!byPage.has(pageKey)) byPage.set(pageKey, []);\n byPage.get(pageKey)!.push({ ...h, originalIndex: i });\n });\n\n const merged: MergedHighlightArea[] = [];\n\n byPage.forEach((pageAreas) => {\n // Sort top-to-bottom, left-to-right\n const sorted = [...pageAreas].sort((a, b) =>\n a.top !== b.top ? a.top - b.top : a.left - b.left\n );\n\n const used = new Array(sorted.length).fill(false);\n\n for (let i = 0; i < sorted.length; i++) {\n if (used[i]) continue;\n\n let { left, top, width, height, pageIndex, pageNumber } = sorted[i];\n let right = left + width;\n let bottom = top + height;\n const originalIndexes = [sorted[i].originalIndex];\n used[i] = true;\n\n // Merge only true duplicate/heavily-overlapping rects. Nearby text lines\n // can be less than 1% apart vertically, so adjacency must stay separate.\n let changed = true;\n while (changed) {\n changed = false;\n for (let j = i + 1; j < sorted.length; j++) {\n if (used[j]) continue;\n const b = sorted[j];\n const bRight = b.left + b.width;\n const bBottom = b.top + b.height;\n\n const intersectionWidth = Math.max(\n 0,\n Math.min(right, bRight) - Math.max(left, b.left)\n );\n const intersectionHeight = Math.max(\n 0,\n Math.min(bottom, bBottom) - Math.max(top, b.top)\n );\n const intersectionArea = intersectionWidth * intersectionHeight;\n const currentArea = Math.max(width * height, 0.0001);\n const nextArea = Math.max(b.width * b.height, 0.0001);\n const smallerArea = Math.min(currentArea, nextArea);\n const overlapRatio = smallerArea > 0 ? intersectionArea / smallerArea : 0;\n\n const overlaps = overlapRatio >= 0.8;\n\n if (overlaps) {\n left = Math.min(left, b.left);\n top = Math.min(top, b.top);\n right = Math.max(right, bRight);\n bottom = Math.max(bottom, bBottom);\n width = right - left;\n height = bottom - top;\n originalIndexes.push(b.originalIndex);\n used[j] = true;\n changed = true;\n }\n }\n }\n\n merged.push({ pageIndex, pageNumber, left, top, width, height, originalIndexes });\n }\n });\n\n return merged;\n};\n\n const processPdfHighlightText = (text: string): string[] => {\n if (!text) return [];\n const cleaned = getCleanedHighlightText(text);\n return cleaned\n .split(/\\n{2,}/)\n .map((block) => extractCleanLines(block).join(\" \"))\n .map((line) => normalizeWhitespace(line))\n .filter(Boolean);\n };\n\n // ✅ Ordered valid keys (NO normalization to array)\n const orderedKeys = Object.keys(highlightPages)\n .map(Number)\n .sort((a, b) => a - b);\n\n\n /** Total navigable highlights. */\n const totalHighlights: number = useMemo(() => {\n if (useCoordinates) return highlightCordinatePages.length;\n if (!useCoordinates) return Object.values(highlightPages).filter((p) => p > 0).length;\n return 0;\n }, [highlightCordinatePages, highlightPages]);\n\n\n /** 1-based display position for a given cursor. */\n const getValidPosition = (cursor: number): number => {\n if (useCoordinates) return cursor + 1;\n if (!highlightPages) return 0;\n let count = 0;\n for (let i = 0; i <= cursor; i++) {\n if (highlightPages[orderedKeys[i]] > 0) count++;\n }\n return count;\n };\n\n const isSameLine = (a: DOMRect, b: DOMRect) =>\n Math.abs(a.top - b.top) < 5;\n\n const isHorizontallyClose = (a: DOMRect, b: DOMRect) =>\n Math.abs(a.right - b.left) < 20 || Math.abs(b.right - a.left) < 20;\n\n const isImmediateCluster = (\n curr:{\n el: HTMLElement;\n rect: DOMRect;\n text: string;\n },\n neighbor: {\n el: HTMLElement;\n rect: DOMRect;\n text: string;\n }) => {\n if (!neighbor) return false;\n\n return (\n isSameLine(curr.rect, neighbor.rect) &&\n isHorizontallyClose(curr.rect, neighbor.rect)\n );\n };\n\n\n const hideIsolatedShortHighlights = (pageHighlights: Element) => {\n const highlights = Array.from(\n pageHighlights.querySelectorAll(\".rpv-search__highlight\")\n ) as HTMLElement[];\n\n // ✅ Only process visible highlights — skip already-hidden ones\n const visibleItems = highlights\n .filter(el => el.style.display !== \"none\")\n .map(el => ({\n el,\n rect: el.getBoundingClientRect(),\n text: el.textContent?.trim() || \"\",\n }))\n .filter(item => item.rect.width > 0); // ✅ skip zero-rect (hidden/unmounted)\n\n visibleItems.forEach((item, i) => {\n const prev = visibleItems[i - 1];\n const next = visibleItems[i + 1];\n\n const width = item.rect.width;\n if (width > 100) return;\n const hasImmediateNeighbor =\n isImmediateCluster(item, prev) || isImmediateCluster(item, next);\n if (!hasImmediateNeighbor) item.el.style.display = \"none\";\n });\n };\n\n // ─── Core deduplication & matching ────────────────────────────────────────\n const deduplicateHighlights = (targetPage: number) => {\n if (!viewerRef.current) return;\n\n const pageHighlightsContainer = viewerRef.current.querySelector(\n `[data-testid=\"search__highlights-${targetPage}\"]`\n );\n if (!pageHighlightsContainer) return;\n\n const elements = Array.from(\n pageHighlightsContainer.querySelectorAll(\".rpv-search__highlight\")\n ) as HTMLElement[];\n\n if (elements.length === 0) return;\n\n const expectedSentenceVariants = filteredHighlightSentences.map(buildMatchVariants);\n const expectedLineVariants = filteredHighlightLineFragments.map(buildMatchVariants);\n if (expectedSentenceVariants.length === 0 && expectedLineVariants.length === 0) return;\n\n // Build DOM highlight items with coordinate fallback\n type HighlightItem = {\n el: HTMLElement;\n text: string;\n top: number;\n left: number;\n right: number;\n };\n\n type LogicalBlock = {\n title: string;\n elements: HTMLElement[];\n lastTop: number;\n lastRight: number;\n };\n\n const getCoords = (el: HTMLElement): { top: number; left: number; right: number } => {\n const rect = el.getBoundingClientRect();\n if (rect.height > 0 || rect.width > 0) {\n return { top: rect.top, left: rect.left, right: rect.right };\n }\n const top = el.offsetTop;\n const left = el.offsetLeft;\n const right = left + el.offsetWidth;\n return { top, left, right };\n };\n\n const items: HighlightItem[] = elements\n .map((el) => {\n const coords = getCoords(el);\n const rawText = (el.textContent || \"\").trim();\n const fallbackText = (el.getAttribute(\"title\") || \"\").trim();\n const text = rawText || fallbackText;\n return { el, text, ...coords };\n })\n .filter((item) => item.text.length > 0)\n .sort((a, b) => a.top - b.top || a.left - b.left);\n\n if (items.length === 0) return;\n\n // Group items into logical line-blocks\n const blocks: LogicalBlock[] = [];\n let currentBlock: LogicalBlock | null = null;\n let currentTextParts: string[] = [];\n const lineTolerance = 5;\n const wordGap = 28;\n\n const flushBlock = () => {\n if (!currentBlock) return;\n const joinedText = currentTextParts.join(\" \");\n currentBlock.title = normalizeForMatch(joinedText);\n if (currentBlock.title) blocks.push(currentBlock);\n currentBlock = null;\n currentTextParts = [];\n };\n\n items.forEach((item) => {\n if (!currentBlock) {\n currentBlock = {\n title: \"\",\n elements: [item.el],\n lastTop: item.top,\n lastRight: item.right,\n };\n currentTextParts = [item.text];\n return;\n }\n\n const sameLine = Math.abs(item.top - currentBlock.lastTop) <= lineTolerance;\n const closeToPrev = item.left <= currentBlock.lastRight + wordGap;\n\n if (sameLine && closeToPrev) {\n currentBlock.elements.push(item.el);\n currentBlock.lastTop = item.top;\n currentBlock.lastRight = Math.max(currentBlock.lastRight, item.right);\n currentTextParts.push(item.text);\n } else {\n flushBlock();\n currentBlock = {\n title: \"\",\n elements: [item.el],\n lastTop: item.top,\n lastRight: item.right,\n };\n currentTextParts = [item.text];\n }\n });\n flushBlock();\n\n if (blocks.length === 0) return;\n\n // Matching utilities\n\n // Returns true when blockTitle matches any of the expected variants.\n const matchesExpected = (blockTitle: string, variants: Set<string>): boolean => {\n if (!blockTitle) return false;\n if (variants.has(blockTitle)) return true;\n\n const compactTitle = blockTitle.replace(/\\s+/g, \"\");\n\n for (const variant of Array.from(variants)) {\n if (!variant) continue;\n const compactVariant = variant.replace(/\\s+/g, \"\");\n\n // Exact compact match\n if (compactVariant === compactTitle) return true;\n\n // Block is contained within the variant (fragmented DOM span)\n if (\n variant.length >= 8 &&\n blockTitle.length >= 5 &&\n variant.includes(blockTitle)\n )\n return true;\n if (\n compactVariant.length >= 8 &&\n compactTitle.length >= 5 &&\n compactVariant.includes(compactTitle)\n )\n return true;\n\n // Variant is contained within a larger block\n if (\n blockTitle.length >= 10 &&\n variant.length >= 8 &&\n blockTitle.includes(variant)\n )\n return true;\n if (\n compactTitle.length >= 10 &&\n compactVariant.length >= 8 &&\n compactTitle.includes(compactVariant)\n )\n return true;\n }\n return false;\n };\n\n let bestSequenceLen = 0;\n let blocksToKeep = new Set<number>();\n\n // Strategy A: Full-text sliding-window coverage\n\n const allExpectedNormalized = Array.from(\n new Set(\n [...filteredHighlightSentences, ...filteredHighlightLineFragments]\n .map(normalizeForMatch)\n .filter((s) => s.length >= 8)\n )\n ).sort((a, b) => b.length - a.length);\n\n const tryFullTextWindow = (expectedText: string): Set<number> | null => {\n if (!expectedText || expectedText.length < 8) return null;\n const expectedCompact = expectedText.replace(/\\s+/g, \"\");\n\n for (let start = 0; start < blocks.length; start++) {\n let combined = \"\";\n let combinedCompact = \"\";\n const collected = new Set<number>();\n\n for (\n let end = start;\n end < blocks.length && end < start + 20;\n end++\n ) {\n const piece = blocks[end].title;\n combined = combined ? `${combined} ${piece}` : piece;\n combinedCompact = combinedCompact\n ? `${combinedCompact}${piece.replace(/\\s+/g, \"\")}`\n : piece.replace(/\\s+/g, \"\");\n collected.add(end);\n\n if (\n combined.includes(expectedText) ||\n combinedCompact.includes(expectedCompact)\n ) {\n return collected;\n }\n\n if (\n combined.length >= 15 &&\n (expectedText.includes(combined) ||\n expectedCompact.includes(combinedCompact))\n ) {\n return collected;\n }\n\n if (combined.length > expectedText.length + 150) break;\n }\n }\n return null;\n };\n\n for (const expectedText of allExpectedNormalized) {\n const match = tryFullTextWindow(expectedText);\n if (match && match.size > 0) {\n match.forEach((idx) => blocksToKeep.add(idx));\n bestSequenceLen = blocksToKeep.size;\n }\n }\n\n // Strategy B: Per-sentence concatenated match\n\n const findConcatenatedMatch = (\n variantsList: Set<string>[]\n ): Set<number> | null => {\n if (variantsList.length === 0) return null;\n let bestMatch: { blocks: Set<number>; extra: number } | null = null;\n\n for (const variants of variantsList) {\n for (const variant of Array.from(variants)) {\n if (!variant || variant.length < 5) continue;\n const variantCompact = variant.replace(/\\s+/g, \"\");\n\n for (let start = 0; start < blocks.length; start++) {\n let combined = \"\";\n let combinedCompact = \"\";\n const collected = new Set<number>();\n\n for (\n let end = start;\n end < blocks.length && end < start + 15;\n end++\n ) {\n const piece = blocks[end].title;\n combined = combined ? `${combined} ${piece}` : piece;\n combinedCompact = combinedCompact\n ? `${combinedCompact}${piece.replace(/\\s+/g, \"\")}`\n : piece.replace(/\\s+/g, \"\");\n collected.add(end);\n\n if (\n combined.includes(variant) ||\n combinedCompact.includes(variantCompact)\n ) {\n const extra = Math.max(0, combined.length - variant.length);\n if (!bestMatch || extra < bestMatch.extra) {\n bestMatch = { blocks: new Set(collected), extra };\n }\n break;\n }\n\n if (combined.length > variant.length + 120) break;\n }\n }\n }\n }\n\n return bestMatch ? bestMatch.blocks : null;\n };\n\n if (bestSequenceLen === 0) {\n const concatenatedMatch = findConcatenatedMatch(expectedSentenceVariants);\n if (concatenatedMatch && concatenatedMatch.size > 0) {\n concatenatedMatch.forEach((idx) => blocksToKeep.add(idx));\n bestSequenceLen = blocksToKeep.size;\n }\n }\n\n // Strategy C: Line-by-line sequence matching\n\n const maxLineGap = getMaxLineGap(blocks);\n const expectedLineTexts = filteredHighlightLineFragments\n .map(normalizeForMatch)\n .filter((line) => line.length >= 8);\n const lineTokens = expectedLineTexts.map((line) =>\n line.split(/\\s+/).filter((word) => word.length >= 2)\n );\n\n if (bestSequenceLen === 0) {\n const sequenceCandidates = expectedLineVariants;\n\n for (\n let startBlockIdx = 0;\n startBlockIdx < blocks.length;\n startBlockIdx++\n ) {\n const blockTitle = blocks[startBlockIdx].title;\n\n for (let expStart = 0; expStart < sequenceCandidates.length; expStart++) {\n if (!matchesExpected(blockTitle, sequenceCandidates[expStart])) continue;\n\n let currentLen = 0;\n const currentKeptBlocks = new Set<number>();\n let expPtr = expStart;\n let lastMatchedBlockIdx = startBlockIdx - 1;\n\n for (let i = startBlockIdx; i < blocks.length && expPtr < sequenceCandidates.length; i++) {\n if (matchesExpected(blocks[i].title, sequenceCandidates[expPtr])) {\n if (lastMatchedBlockIdx >= 0) {\n const prevTop = blocks[lastMatchedBlockIdx].lastTop;\n const currentTop = blocks[i].lastTop;\n if (Math.abs(currentTop - prevTop) > maxLineGap) break;\n }\n\n currentLen++;\n currentKeptBlocks.add(i);\n lastMatchedBlockIdx = i;\n expPtr++;\n } else if (\n expPtr > 0 &&\n matchesExpected(blocks[i].title, sequenceCandidates[expPtr - 1])\n ) {\n const prevTop = blocks[lastMatchedBlockIdx].lastTop;\n const currentTop = blocks[i].lastTop;\n if (Math.abs(currentTop - prevTop) <= 3) {\n currentKeptBlocks.add(i);\n lastMatchedBlockIdx = i;\n }\n }\n\n if (i - lastMatchedBlockIdx > 6) break;\n }\n\n if (currentLen > bestSequenceLen) {\n bestSequenceLen = currentLen;\n blocksToKeep = currentKeptBlocks;\n }\n }\n }\n }\n\n // Strategy D: Fuzzy word-overlap fallback\n\n if (\n bestSequenceLen < Math.min(3, expectedLineTexts.length) &&\n expectedLineTexts.length > 0\n ) {\n const fuzzyBlocks = new Set<number>();\n\n blocks.forEach((block, index) => {\n const blockWords = block.title\n .split(/\\s+/)\n .filter((word) => word.length >= 2);\n\n if (blockWords.length < 2) return;\n const blockWordSet = new Set(blockWords);\n\n for (const expectedWords of lineTokens) {\n if (expectedWords.length < 2) continue;\n\n let common = 0;\n for (const word of expectedWords) {\n if (blockWordSet.has(word)) common++;\n }\n\n const ratio = common / expectedWords.length;\n if (common >= 3 || ratio >= 0.5) {\n fuzzyBlocks.add(index);\n break;\n }\n }\n });\n\n if (fuzzyBlocks.size > 0) {\n blocksToKeep = fuzzyBlocks;\n bestSequenceLen = Math.max(bestSequenceLen, fuzzyBlocks.size);\n }\n }\n\n // Strategy E: Normalized keyword exact-match fallback\n const normalizedSearchKeywords = new Set<string>();\n searchKeywords.forEach((keyword) => {\n const normalized = normalizeForMatch(keyword);\n if (!normalized) return;\n normalizedSearchKeywords.add(normalized);\n normalizedSearchKeywords.add(normalized.replace(/\\s+/g, \"\"));\n });\n\n if (bestSequenceLen === 0) {\n const fallbackBlocks = new Set<number>();\n blocks.forEach((block, index) => {\n const compactTitle = block.title.replace(/\\s+/g, \"\");\n if (\n normalizedSearchKeywords.has(block.title) ||\n normalizedSearchKeywords.has(compactTitle)\n ) {\n fallbackBlocks.add(index);\n return;\n }\n const keywordList = Array.from(normalizedSearchKeywords);\n for (let i = 0; i < keywordList.length; i++) {\n const kw = keywordList[i];\n if (kw.length >= 10 && kw.includes(block.title) && block.title.length >= 5) {\n fallbackBlocks.add(index);\n break;\n }\n }\n });\n\n if (fallbackBlocks.size === 0) return 0;\n blocksToKeep = fallbackBlocks;\n }\n\n // Reveal only verified blocks\n blocks.forEach((block, index) => {\n const isKept = blocksToKeep.has(index);\n block.elements.forEach((el) => {\n if (isKept) {\n // Reveal the verified sequence smoothly\n el.classList.add(\"verified-match\");\n el.style.display = \"\"; // Ensure it's in the document flow\n } else {\n // Hard-hide the noise so it doesn't block text selection\n el.style.display = \"none\";\n el.classList.remove(\"verified-match\");\n }\n });\n });\n\n // added console group for debugging - to be removed in final release\n // ─── After blocksToKeep is finalized, hide pixel-overlapping duplicates ──────\n // The search plugin sometimes renders multiple spans covering identical or\n // heavily-overlapping regions for the same keyword. We keep only the first\n // (largest) span in each overlapping cluster so opacity never compounds.\n\n const keptElements: HTMLElement[] = [];\n blocks.forEach((block, index) => {\n if (blocksToKeep.has(index)) {\n block.elements.forEach((el) => keptElements.push(el));\n }\n });\n\n // Build rects after a rAF so the browser has committed layout\n requestAnimationFrame(() => {\n type RectEntry = { el: HTMLElement; rect: DOMRect };\n const entries: RectEntry[] = keptElements\n .map((el) => ({ el, rect: el.getBoundingClientRect() }))\n .filter((e) => e.rect.width > 0 && e.rect.height > 0)\n // largest area first so we always keep the most-covering span\n .sort((a, b) => (b.rect.width * b.rect.height) - (a.rect.width * a.rect.height));\n\n const surviving: RectEntry[] = [];\n\n const overlapRatio = (a: DOMRect, b: DOMRect): number => {\n const ix = Math.max(0, Math.min(a.right, b.right) - Math.max(a.left, b.left));\n const iy = Math.max(0, Math.min(a.bottom, b.bottom) - Math.max(a.top, b.top));\n const intersection = ix * iy;\n const smaller = Math.min(a.width * a.height, b.width * b.height);\n return smaller > 0 ? intersection / smaller : 0;\n };\n\n entries.forEach(({ el, rect }) => {\n const isDuplicate = surviving.some(\n (s) => overlapRatio(s.rect, rect) > 0.5 // >50% of smaller rect is covered → duplicate\n );\n if (isDuplicate) {\n el.style.display = \"none\";\n el.classList.remove(\"verified-match\");\n } else {\n surviving.push({ el, rect });\n }\n });\n });\n console.groupCollapsed(`[debug: PDF ordered matching - Page ${targetPage}]`);\n console.log(\"input->\", highlightText);\n console.log(\"processed sentences->\", filteredHighlightSentences);\n console.log(\"processed lines->\", filteredHighlightLineFragments);\n console.log(\"Expected sentence count:\", expectedSentenceVariants.length);\n console.log(\"Expected line count:\", expectedLineVariants.length);\n console.log(\"Matched sequence length:\", bestSequenceLen);\n console.log(\"blocksToKeep\", blocksToKeep, \"size\", blocksToKeep.size);\n console.groupEnd();\n\n return blocksToKeep.size\n };\n\n\n const matchHighlightsInOrder = (\n processedHighlightText: string[],\n seenMap: Map<string, HTMLElement[]>\n ) => {\n const entries = Array.from(seenMap.entries());\n\n let pointer = 0;\n const result: any[] = [];\n\n const normalize = (str: string) =>\n str\n .toLowerCase()\n .replace(/[^\\w\\s]/g, \"\") // remove punctuation\n .replace(/\\s+/g, \" \") // normalize spaces\n .trim();\n\n for (let i = 0; i < processedHighlightText.length; i++) {\n const chunk = processedHighlightText[i];\n const normalizedChunk = normalize(chunk);\n\n while (pointer < entries.length) {\n const [key, value] = entries[pointer];\n const text = normalize(key.split(\"_#$_\")[0]);\n\n const nextChunk = processedHighlightText[i + 1];\n const nextEntry = entries[pointer + 1];\n\n const normalizedNextChunk = nextChunk ? normalize(nextChunk) : null;\n const nextText = nextEntry\n ? normalize(nextEntry[0].split(\"_#$_\")[0])\n : null;\n\n const isCurrentMatch = normalizedChunk === text;\n\n // ONLY apply lookahead if duplicate ahead\n const isDuplicateAhead =\n pointer + 1 < entries.length &&\n text === normalize(entries[pointer + 1][0].split(\"_#$_\")[0]);\n\n let isValid = isCurrentMatch;\n\n if (isCurrentMatch && isDuplicateAhead && normalizedNextChunk) {\n isValid = normalizedNextChunk === nextText;\n }\n\n if (isValid) {\n result.push({\n chunk,\n matchedKey: key,\n elements: value,\n });\n\n pointer++;\n break;\n }\n\n pointer++;\n }\n }\n\n return result;\n };\n\n\n // ✅ hide non-target pages\n // ✅ Accepts multiple target pages\n const hideNonTargetHighlights = (targetPages: Set<number>) => {\n if (!viewerRef.current) return;\n const allPageHighlights = viewerRef.current.querySelectorAll(\n \".rpv-search__highlights\"\n );\n\n allPageHighlights.forEach((pageHighlights) => {\n const testId = pageHighlights.getAttribute(\"data-testid\");\n const pageIndex = parseInt(\n // testId?.replace(\"search__highlights-\", \"\") || \"-1\"\n testId?.replace(/search__highlights-/g, \"\") || \"-1\"\n );\n const highlights = pageHighlights.querySelectorAll(\".rpv-search__highlight\");\n\n // ✅ Hide if page is NOT in the target set\n if (!targetPages.has(pageIndex)) {\n highlights.forEach((h) => {\n (h as HTMLElement).style.display = \"none\";\n });\n }\n // else if (highlights.length > 1) {\n // hideIsolatedShortHighlights(pageHighlights)\n // }\n });\n };\n\n // Pre-process input highlight text\n const processedHighlightSegments = highlightText\n .map((text) => processPdfHighlightText(text))\n .flat();\n\n const processedHighlightLineFragments = highlightText\n .map((text) => extractCleanLines(text))\n .flat();\n\n const minKeywordLength = processedHighlightSegments.some((line) => line.length >= 3)\n ? 3\n : 1;\n\n const filteredHighlightSentences = processedHighlightSegments.filter(\n (line) => line.length >= minKeywordLength\n );\n\n const filteredHighlightLineFragments = processedHighlightLineFragments.filter(\n (line) => line.length >= minKeywordLength\n );\n\n const isKeywordUseful = (line: string): boolean => {\n const words = line.split(/\\s+/).filter(Boolean);\n if (line.length < minKeywordLength) return false;\n if (words.length >= 3) return true;\n return line.length >= 12;\n };\n\n const buildWordWindows = (line: string, size = 6, step = 4): string[] => {\n const words = line.split(/\\s+/).filter(Boolean);\n if (words.length <= size) return [];\n const windows: string[] = [];\n for (let i = 0; i + size <= words.length; i += step) {\n windows.push(words.slice(i, i + size).join(\" \"));\n }\n if (words.length > size && (words.length - size) % step !== 0) {\n windows.push(words.slice(words.length - size).join(\" \"));\n }\n return windows;\n };\n\n const lineFragmentWindows = filteredHighlightLineFragments.flatMap((line) =>\n buildWordWindows(line)\n );\n\n const searchKeywords = Array.from(\n new Set(\n [\n ...filteredHighlightSentences,\n ...filteredHighlightLineFragments,\n ...lineFragmentWindows,\n ].flatMap(buildSearchVariants)\n )\n ).filter(isKeywordUseful);\n\n // Plugin instances\n const searchPluginInstance = searchPlugin({ keyword: searchKeywords });\n const pageNavigationPluginInstance = pageNavigationPlugin();\n const zoomPluginInstance = zoomPlugin();\n\n const { jumpToMatch } = searchPluginInstance;\n const { jumpToPage } = pageNavigationPluginInstance;\n const { zoomTo, ZoomInButton, ZoomOutButton, ZoomPopover } = zoomPluginInstance;\n\n // Pre-merge overlapping areas so stacked highlights don't compound opacity\nconst mergedCoordinateAreas = useMemo(\n () => mergeOverlappingAreas(highlightCordinatePages),\n [highlightCordinatePages]\n);\n\nconst highlightPluginInstance = highlightPlugin({\n renderHighlights: (props: RenderHighlightsProps) => (\n <>\n {mergedCoordinateAreas\n .filter((h) =>\n h.pageNumber != null\n ? h.pageNumber - 1 === props.pageIndex\n : h.pageIndex === props.pageIndex\n )\n .map((area) => {\n const isActive = area.originalIndexes.includes(cursorIndex);\n\n return (\n <div\n key={area.originalIndexes.join(\"-\")}\n style={{\n position: \"absolute\",\n left: `${area.left}%`,\n top: `${area.top + area.height * 0.08}%`,\n width: `${area.width}%`,\n height: `${area.height * 0.95}%`,\n background: isActive ? activeHighlightColor : highlightColor,\n opacity: isActive ? 0.7 : 0.4,\n transition: \"background 0.2s, opacity 0.2s\",\n border: isActive ? `1px solid ${\"red\"}` : `1px solid transparent`,\n }}\n />\n );\n })}\n </>\n ),\n});\n\n const tryJump = () => {\n if (hasJumpedRef.current) return;\n try {\n jumpToMatch(0);\n hasJumpedRef.current = true;\n const first = highlightCordinatePages[0]; // ✅ use highlightPages not hardcoded highlights\n if (first && useCoordinates) {\n scrollToCoord(first.pageIndex, first.top);\n }\n } catch {\n requestAnimationFrame(tryJump);\n }\n };\n\n\n const scrollToHighlightAfterNav = (targetPage: number, occurrence: number) => {\n if (!viewerRef.current) return;\n\n const container = viewerRef.current.querySelector(\".rpv-core__viewer\");\n if (!container) return;\n\n let lastScrollTop = -1;\n\n const doScrollToHighlight = () => {\n const scrollContainer = viewerRef.current?.querySelector(\n \".rpv-core__inner-pages\"\n ) as HTMLElement;\n if (!scrollContainer) return;\n\n // ✅ Wait for jumpToPage scroll to settle\n if (scrollContainer.scrollTop !== lastScrollTop) {\n lastScrollTop = scrollContainer.scrollTop;\n setTimeout(doScrollToHighlight, 100);\n return;\n }\n\n const pageElement = viewerRef.current?.querySelector(\n `[data-testid=\"core__page-layer-${targetPage}\"]`\n );\n if (!pageElement) return;\n\n // ✅ Get nth highlight on this page using occurrence\n const allHighlights = pageElement.querySelectorAll(\".rpv-search__highlight\");\n const target = allHighlights[occurrence] as HTMLElement;\n\n if (!target) return;\n\n const scrollContainerRect = scrollContainer.getBoundingClientRect();\n const highlightRect = target.getBoundingClientRect();\n\n const scrollTop =\n scrollContainer.scrollTop +\n (highlightRect.top - scrollContainerRect.top) -\n scrollContainer.clientHeight / 2 +\n highlightRect.height / 2;\n\n scrollContainer.scrollTo({ top: scrollTop, behavior: \"smooth\" });\n };\n\n setTimeout(doScrollToHighlight, 300);\n };\n\n // ─── Coordinate-mode: scroll by percentage position ───────────────────────\n\n const scrollToCoord = (pageIndex: number, top: number, height = 0) => {\n\n if (!viewerRef.current) return;\n let attempts = 0;\n const VIEWPORT_PADDING = 80;\n\n const doScroll = () => {\n if (++attempts > 60) return;\n\n const scrollContainer = viewerRef.current?.querySelector(\n \".rpv-core__inner-pages\"\n ) as HTMLElement | null;\n\n if (!scrollContainer) { setTimeout(doScroll, 100); return; }\n\n\n // const normalizedPageIndex = pageIndex - 1;\n\n const pageElement = viewerRef.current?.querySelector(\n `[data-testid=\"core__page-layer-${pageIndex}\"]`\n ) as HTMLElement | null;\n\n if (!pageElement) { setTimeout(doScroll, 100); return; }\n\n\n const pageRect = pageElement.getBoundingClientRect();\n\n if (pageRect.height === 0) { setTimeout(doScroll, 100); return; }\n\n const scrollContainerRect = scrollContainer.getBoundingClientRect();\n const highlightTopInPage = (top / 100) * pageRect.height;\n const highlightHeightInPage = (height / 100) * pageRect.height;\n const highlightTopAbsolute =\n pageRect.top - scrollContainerRect.top + highlightTopInPage;\n const highlightBottomAbsolute = highlightTopAbsolute + highlightHeightInPage;\n\n const isComfortablyVisible =\n highlightTopAbsolute >= VIEWPORT_PADDING &&\n highlightBottomAbsolute <= scrollContainer.clientHeight - VIEWPORT_PADDING;\n\n if (isComfortablyVisible) return;\n\n const scrollTop =\n highlightTopAbsolute < VIEWPORT_PADDING\n ? scrollContainer.scrollTop + highlightTopAbsolute - VIEWPORT_PADDING\n : scrollContainer.scrollTop +\n highlightBottomAbsolute -\n scrollContainer.clientHeight +\n VIEWPORT_PADDING;\n\n scrollContainer.scrollTo({\n top: scrollTop,\n behavior: \"smooth\",\n });\n };\n\n setTimeout(doScroll, 100);\n };\n\n\n// ✅ Map: page -> [cursorIndexes] for same-page occurrence tracking\nconst pageVisitMap = useMemo(() => {\n const map: Record<number, number[]> = {};\n orderedKeys.forEach((key, i) => {\n const page = highlightPages[key];\n if (page > 0) {\n if (!map[page]) map[page] = [];\n map[page].push(i);\n }\n });\n return map;\n}, [orderedKeys, highlightPages]);\n\n// ✅ Get which occurrence (0,1,2...) this cursorIndex is on its page\nconst getHighlightOccurrence = (cursorIdx: number): number => {\n const page = highlightPages[orderedKeys[cursorIdx]];\n const visits = pageVisitMap[page] || [];\n return visits.indexOf(cursorIdx);\n};\n\n\nconst scrollToCoordAfterNav = (pageIndex: number, top: number, height = 0) => {\n if (!viewerRef.current) return;\n const VIEWPORT_PADDING = 80;\n let lastScrollTop = -1;\n let attempts = 0;\n\n const waitForSettle = () => {\n if (++attempts > 60) return;\n\n const scrollContainer = viewerRef.current?.querySelector(\n \".rpv-core__inner-pages\"\n ) as HTMLElement | null;\n if (!scrollContainer) { setTimeout(waitForSettle, 100); return; }\n\n if (scrollContainer.scrollTop !== lastScrollTop) {\n lastScrollTop = scrollContainer.scrollTop;\n setTimeout(waitForSettle, 100);\n return;\n }\n\n const pageElement = viewerRef.current?.querySelector(\n `[data-testid=\"core__page-layer-${pageIndex}\"]`\n ) as HTMLElement | null;\n if (!pageElement) { setTimeout(waitForSettle, 100); return; }\n\n const pageRect = pageElement.getBoundingClientRect();\n if (pageRect.height === 0) { setTimeout(waitForSettle, 100); return; }\n\n const scrollContainerRect = scrollContainer.getBoundingClientRect();\n const highlightTopInPage = (top / 100) * pageRect.height;\n const highlightHeightInPage = (height / 100) * pageRect.height;\n const highlightTopAbsolute =\n pageRect.top - scrollContainerRect.top + highlightTopInPage;\n const highlightBottomAbsolute = highlightTopAbsolute + highlightHeightInPage;\n\n const isComfortablyVisible =\n highlightTopAbsolute >= VIEWPORT_PADDING &&\n highlightBottomAbsolute <= scrollContainer.clientHeight - VIEWPORT_PADDING;\n\n if (isComfortablyVisible) return;\n\n const scrollTop =\n highlightTopAbsolute < VIEWPORT_PADDING\n ? scrollContainer.scrollTop + highlightTopAbsolute - VIEWPORT_PADDING\n : scrollContainer.scrollTop +\n highlightBottomAbsolute -\n scrollContainer.clientHeight +\n VIEWPORT_PADDING;\n\n // ✅ instant — no second smooth animation\n scrollContainer.scrollTo({\n top: scrollTop,\n behavior: \"instant\" as ScrollBehavior,\n });\n };\n\n setTimeout(waitForSettle, 100);\n};\n\nconst goToNext = () => {\n if (useCoordinates && highlightCordinatePages) {\n for (let i = cursorIndex + 1; i < highlightCordinatePages.length; i++) {\n const h = highlightCordinatePages[i];\n const currentH = highlightCordinatePages[cursorIndex];\n setCursorIndex(i);\n\n if (h.pageIndex !== currentH.pageIndex) {\n jumpToPage(h.pageIndex);\n scrollToCoordAfterNav(h.pageIndex, h.top, h.height);\n } else {\n scrollToCoord(h.pageIndex, h.top, h.height);\n }\n return;\n }\n } else {\n const prev = cursorIndex;\n for (let i = prev + 1; i < orderedKeys.length; i++) {\n const key = orderedKeys[i];\n if (highlightPages[key] > 0) {\n const page = highlightPages[key] - 1;\n const occurrence = getHighlightOccurrence(i);\n setCursorIndex(i);\n jumpToPage(highlightPages[key] - 1);\n scrollToHighlightAfterNav(page, occurrence);\n setTimeout(() => { deduplicateHighlights(page); }, 500);\n if (Object.keys(highlightPages).length === 1) hideNonTargetHighlights(highlightPageSet);\n return;\n }\n }\n }\n};\n\nconst goToPrevious = () => {\n if (useCoordinates && highlightCordinatePages) {\n for (let i = cursorIndex - 1; i >= 0; i--) {\n const h = highlightCordinatePages[i];\n const currentH = highlightCordinatePages[cursorIndex];\n setCursorIndex(i);\n\n if (h.pageIndex !== currentH.pageIndex) {\n jumpToPage(h.pageIndex);\n scrollToCoordAfterNav(h.pageIndex, h.top, h.height);\n } else {\n scrollToCoord(h.pageIndex, h.top, h.height);\n }\n return;\n }\n } else {\n const prev = cursorIndex;\n for (let i = prev - 1; i >= 0; i--) {\n const key = orderedKeys[i];\n if (highlightPages[key] > 0) {\n const page = highlightPages[key] - 1;\n const occurrence = getHighlightOccurrence(i);\n setCursorIndex(i);\n jumpToPage(highlightPages[key] - 1);\n scrollToHighlightAfterNav(page, occurrence);\n setTimeout(() => { deduplicateHighlights(page); }, 500);\n if (Object.keys(highlightPages).length === 1) hideNonTargetHighlights(highlightPageSet);\n return;\n }\n }\n }\n};\n\n\n return {\n setHighlightIndex,\n highlightIndex,\n cursorIndex,\n setCursorIndex,\n orderedKeys,\n totalHighlights,\n getValidPosition,\n tryJump,\n jumpToPage,\n zoomTo,\n hideNonTargetHighlights,\n deduplicateHighlights,\n scrollToCoord,\n plugins: [\n useCoordinates ? highlightPluginInstance : searchPluginInstance,\n pageNavigationPluginInstance,\n zoomPluginInstance,\n ],\n controls: {\n ZoomInButton,\n ZoomOutButton,\n ZoomPopover,\n zoomTo,\n goToNext,\n goToPrevious,\n },\n };\n};"],"names":["PdfHighlightControls","highlightText","highlightPages","viewerRef","highlightPageSet","useCoordinates","highlightCordinatePages","highlightColor","activeHighlightColor","highlightIndex","setHighlightIndex","useState","hasJumpedRef","useRef","cursorIndex","setCursorIndex","normalizeWhitespace","value","replace","trim","normalizeForMatch","toLowerCase","stripLeadingIndex","line","trimmed","match","slice","length","buildMatchVariants","normalized","compact","variants","Set","add","getCleanedHighlightText","text","str","textarea","document","createElement","innerHTML","decodeHtml","extractCleanLines","split","map","flatMap","tableMatch","cell","filter","Boolean","stripMarkdownEmphasis","orderedKeys","Object","keys","Number","sort","a","b","totalHighlights","useMemo","values","p","deduplicateHighlights","targetPage","current","pageHighlightsContainer","querySelector","elements","Array","from","querySelectorAll","expectedSentenceVariants","filteredHighlightSentences","expectedLineVariants","filteredHighlightLineFragments","items","el","coords","rect","getBoundingClientRect","height","width","top","left","right","offsetTop","offsetLeft","offsetWidth","getCoords","rawText","textContent","fallbackText","getAttribute","item","blocks","currentBlock","currentTextParts","flushBlock","joinedText","join","title","push","forEach","lastTop","lastRight","sameLine","Math","abs","closeToPrev","max","matchesExpected","blockTitle","has","compactTitle","variant","compactVariant","includes","bestSequenceLen","blocksToKeep","allExpectedNormalized","s","tryFullTextWindow","expectedText","expectedCompact","start","combined","combinedCompact","collected","end","piece","size","idx","concatenatedMatch","variantsList","bestMatch","variantCompact","extra","findConcatenatedMatch","maxLineGap","diffs","i","diff","median","floor","scaled","round","min","getMaxLineGap","expectedLineTexts","lineTokens","word","sequenceCandidates","startBlockIdx","expStart","currentLen","currentKeptBlocks","expPtr","lastMatchedBlockIdx","prevTop","currentTop","fuzzyBlocks","block","index","blockWords","blockWordSet","expectedWords","common","ratio","normalizedSearchKeywords","searchKeywords","keyword","fallbackBlocks","keywordList","kw","isKept","classList","style","display","remove","keptElements","requestAnimationFrame","entries","e","surviving","some","intersection","bottom","smaller","overlapRatio","console","groupCollapsed","log","groupEnd","hideNonTargetHighlights","targetPages","pageHighlights","testId","pageIndex","parseInt","highlights","h","processedHighlightSegments","processPdfHighlightText","flat","processedHighlightLineFragments","minKeywordLength","lineFragmentWindows","step","words","windows","buildWordWindows","base","dashNormalized","dehyphenated","hyphenToSpace","hyphenRemoved","punctuationStripped","searchPluginInstance","searchPlugin","pageNavigationPluginInstance","pageNavigationPlugin","zoomPluginInstance","zoomPlugin","jumpToMatch","jumpToPage","zoomTo","ZoomInButton","ZoomOutButton","ZoomPopover","mergedCoordinateAreas","areas","byPage","Map","pageKey","pageNumber","set","get","originalIndex","merged","pageAreas","sorted","used","fill","originalIndexes","changed","j","bRight","bBottom","intersectionArea","currentArea","nextArea","smallerArea","mergeOverlappingAreas","highlightPluginInstance","highlightPlugin","renderHighlights","props","jsx","Fragment","children","area","isActive","position","background","opacity","transition","border","tryJump","first","scrollToCoord","scrollToHighlightAfterNav","occurrence","lastScrollTop","doScrollToHighlight","scrollContainer","scrollTop","setTimeout","pageElement","target","scrollContainerRect","highlightRect","clientHeight","scrollTo","behavior","attempts","doScroll","pageRect","highlightTopInPage","highlightHeightInPage","highlightTopAbsolute","highlightBottomAbsolute","pageVisitMap","key","page","getHighlightOccurrence","cursorIdx","indexOf","scrollToCoordAfterNav","waitForSettle","getValidPosition","cursor","count","plugins","controls","goToNext","currentH","goToPrevious"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"usePdfHighlight.js","sources":["../../../src/features/PdfViewer/usePdfHighlight.tsx"],"sourcesContent":["import { useMemo, useRef, useState } from \"react\";\nimport { searchPlugin } from \"@react-pdf-viewer/search\";\nimport { pageNavigationPlugin } from \"@react-pdf-viewer/page-navigation\";\nimport { zoomPlugin } from \"@react-pdf-viewer/zoom\";\nimport { HighlightArea } from \"./PdfViewer\";\nimport {\n highlightPlugin,\n RenderHighlightsProps,\n} from \"@react-pdf-viewer/highlight\";\n\nexport const PdfHighlightControls = (\n highlightText: string[],\n highlightPages: Record<number, number>,\n viewerRef: React.RefObject<HTMLDivElement | null>,\n highlightPageSet : Set<number>,\n useCoordinates : boolean,\n highlightCordinatePages : HighlightArea[],\n highlightColor = \"yellow\", \n activeHighlightColor = \"#F6D739\",\n) => {\n const [highlightIndex, setHighlightIndex] = useState(0);\n const hasJumpedRef = useRef(false);\n const [cursorIndex, setCursorIndex] = useState(0);\n const visibleHighlightsRef = useRef<HTMLElement[]>([]);\n\n // Text normalization helpers\n\n const normalizeWhitespace = (value: string): string =>\n value.replace(/[^\\S\\n]+/g, \" \").trim();\n\n const stripMarkdownEmphasis = (line: string): string =>\n line.replace(/(^|\\W)[*_]{1,3}([^*_]+)[*_]{1,3}(?=\\W|$)/g, \"$1$2\");\n\n const normalizeForMatch = (value: string): string =>\n (value || \"\")\n .toLowerCase()\n .replace(/\\u00ad/g, \"\")\n .replace(/[\"\"]/g, '\"')\n .replace(/['']/g, \"'\")\n .replace(/[\\u2013\\u2014]/g, \"-\")\n .replace(/-/g, \" \")\n .replace(/[^\\w\\s]/g, \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n\n const stripLeadingIndex = (line: string): string => {\n let trimmed = line.trim();\n trimmed = trimmed\n .replace(/[\\u200B-\\u200D\\uFEFF]/g, \"\")\n .replace(/[\\u00A0\\u2009\\u202F]/g, \" \");\n trimmed = trimmed.replace(/^[-•]\\s+/, \"\");\n const match = trimmed.match(\n /^((\\d+(?:\\.\\d+)*[.)]?)|[A-Za-z][.)]|\\([A-Za-z0-9]+\\)|(?:i|ii|iii|iv|v|vi|vii|viii|ix|x)[.)])\\s*/i\n );\n if (match) return trimmed.slice(match[0].length).trim();\n return trimmed;\n };\n\n const buildMatchVariants = (line: string): Set<string> => {\n const normalized = normalizeForMatch(line);\n const compact = normalized.replace(/\\s+/g, \"\");\n const variants = new Set<string>();\n if (normalized) variants.add(normalized);\n if (compact) variants.add(compact);\n return variants;\n };\n\n const buildSearchVariants = (line: string): string[] => {\n const base = normalizeWhitespace(\n line\n .replace(/[\\u00A0\\u2009\\u202F]/g, \" \")\n .replace(/\\u00ad/g, \"\")\n .replace(/[\"\"]/g, '\"')\n .replace(/['']/g, \"'\")\n );\n if (!base) return [];\n\n const dashNormalized = base.replace(/[\\u2013\\u2014]/g, \"-\");\n const dehyphenated = normalizeWhitespace(\n dashNormalized.replace(/(\\w)-\\s+(\\w)/g, \"$1$2\")\n );\n const hyphenToSpace = normalizeWhitespace(dashNormalized.replace(/-/g, \" \"));\n const hyphenRemoved = normalizeWhitespace(dashNormalized.replace(/-/g, \"\"));\n const punctuationStripped = normalizeWhitespace(base.replace(/[^\\w\\s]/g, \"\"));\n\n const variants = new Set<string>([\n base,\n dashNormalized,\n dehyphenated,\n hyphenToSpace,\n hyphenRemoved,\n punctuationStripped,\n ]);\n\n return Array.from(variants).filter(Boolean);\n };\n\n const decodeHtml = (str: string): string => {\n const textarea = document.createElement(\"textarea\");\n textarea.innerHTML = str;\n return textarea.value;\n };\n\n const getCleanedHighlightText = (text: string): string => {\n const cleanHighlight = text.replace(/\\\\([''])/g, \"$1\");\n const normalizedText = cleanHighlight.replace(/\\]\\s*\\n\\s*\\(/g, \"](\");\n return normalizedText\n .replace(/&[#\\w]+;/g, (match) => decodeHtml(match))\n .replace(/<br\\s*\\/?>/gi, \"\\n\")\n .replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, \"$1\")\n .replace(/`([^`]+)`/g, \"$1\");\n };\n\n const extractCleanLines = (text: string): string[] => {\n if (!text) return [];\n const cleaned = getCleanedHighlightText(text);\n\n return cleaned\n .split(/\\n+/)\n .map(stripLeadingIndex)\n .flatMap((line) => {\n const tableMatch = line.match(/^\\s*\\|(.+)\\|\\s*$/);\n if (tableMatch) {\n return tableMatch[1]\n .split(\"|\")\n .map((cell) => cell.trim())\n .filter(Boolean);\n }\n return [line];\n })\n .map((line) => normalizeWhitespace(stripMarkdownEmphasis(line)))\n .filter(Boolean);\n };\n\n const getMaxLineGap = (blocks: Array<{ lastTop: number }>): number => {\n if (blocks.length < 2) return 40;\n const diffs: number[] = [];\n for (let i = 1; i < blocks.length; i++) {\n const diff = Math.abs(blocks[i].lastTop - blocks[i - 1].lastTop);\n if (diff > 0) diffs.push(diff);\n }\n if (diffs.length === 0) return 40;\n diffs.sort((a, b) => a - b);\n const median = diffs[Math.floor(diffs.length / 2)];\n const scaled = Math.round(median * 2.25);\n return Math.min(60, Math.max(24, scaled));\n };\n\n type MergedHighlightArea = HighlightArea & {\n originalIndexes: number[];\n };\n\n // ─── Merge overlapping coordinate highlight areas on the same page ────────────\nconst mergeOverlappingAreas = (areas: HighlightArea[]): MergedHighlightArea[] => {\n if (areas.length === 0) return [];\n\n // Group by page\n const byPage = new Map<number, (HighlightArea & { originalIndex: number })[]>();\n areas.forEach((h, i) => {\n const pageKey = h.pageNumber != null ? h.pageNumber - 1 : h.pageIndex;\n if (!byPage.has(pageKey)) byPage.set(pageKey, []);\n byPage.get(pageKey)!.push({ ...h, originalIndex: i });\n });\n\n const merged: MergedHighlightArea[] = [];\n\n byPage.forEach((pageAreas) => {\n // Sort top-to-bottom, left-to-right\n const sorted = [...pageAreas].sort((a, b) =>\n a.top !== b.top ? a.top - b.top : a.left - b.left\n );\n\n const used = new Array(sorted.length).fill(false);\n\n for (let i = 0; i < sorted.length; i++) {\n if (used[i]) continue;\n\n let { left, top, width, height, pageIndex, pageNumber } = sorted[i];\n let right = left + width;\n let bottom = top + height;\n const originalIndexes = [sorted[i].originalIndex];\n used[i] = true;\n\n // Merge only true duplicate/heavily-overlapping rects. Nearby text lines\n // can be less than 1% apart vertically, so adjacency must stay separate.\n let changed = true;\n while (changed) {\n changed = false;\n for (let j = i + 1; j < sorted.length; j++) {\n if (used[j]) continue;\n const b = sorted[j];\n const bRight = b.left + b.width;\n const bBottom = b.top + b.height;\n\n const intersectionWidth = Math.max(\n 0,\n Math.min(right, bRight) - Math.max(left, b.left)\n );\n const intersectionHeight = Math.max(\n 0,\n Math.min(bottom, bBottom) - Math.max(top, b.top)\n );\n const intersectionArea = intersectionWidth * intersectionHeight;\n const currentArea = Math.max(width * height, 0.0001);\n const nextArea = Math.max(b.width * b.height, 0.0001);\n const smallerArea = Math.min(currentArea, nextArea);\n const overlapRatio = smallerArea > 0 ? intersectionArea / smallerArea : 0;\n\n const overlaps = overlapRatio >= 0.8;\n\n if (overlaps) {\n left = Math.min(left, b.left);\n top = Math.min(top, b.top);\n right = Math.max(right, bRight);\n bottom = Math.max(bottom, bBottom);\n width = right - left;\n height = bottom - top;\n originalIndexes.push(b.originalIndex);\n used[j] = true;\n changed = true;\n }\n }\n }\n\n merged.push({ pageIndex, pageNumber, left, top, width, height, originalIndexes });\n }\n });\n\n return merged;\n};\n\n const processPdfHighlightText = (text: string): string[] => {\n if (!text) return [];\n const cleaned = getCleanedHighlightText(text);\n return cleaned\n .split(/\\n{2,}/)\n .map((block) => extractCleanLines(block).join(\" \"))\n .map((line) => normalizeWhitespace(line))\n .filter(Boolean);\n };\n\n // ✅ Ordered valid keys (NO normalization to array)\n const orderedKeys = Object.keys(highlightPages)\n .map(Number)\n .sort((a, b) => a - b);\n\n\n /** Total navigable highlights. */\n const totalHighlights: number = useMemo(() => {\n if (useCoordinates) return highlightCordinatePages.length;\n if (!useCoordinates) return Object.values(highlightPages).filter((p) => p > 0).length;\n return 0;\n }, [highlightCordinatePages, highlightPages]);\n\n\n /** 1-based display position for a given cursor. */\n const getValidPosition = (cursor: number): number => {\n if (useCoordinates) return cursor + 1;\n if (!highlightPages) return 0;\n let count = 0;\n for (let i = 0; i <= cursor; i++) {\n if (highlightPages[orderedKeys[i]] > 0) count++;\n }\n return count;\n };\n\n const isSameLine = (a: DOMRect, b: DOMRect) =>\n Math.abs(a.top - b.top) < 5;\n\n const isHorizontallyClose = (a: DOMRect, b: DOMRect) =>\n Math.abs(a.right - b.left) < 20 || Math.abs(b.right - a.left) < 20;\n\n const isImmediateCluster = (\n curr:{\n el: HTMLElement;\n rect: DOMRect;\n text: string;\n },\n neighbor: {\n el: HTMLElement;\n rect: DOMRect;\n text: string;\n }) => {\n if (!neighbor) return false;\n\n return (\n isSameLine(curr.rect, neighbor.rect) &&\n isHorizontallyClose(curr.rect, neighbor.rect)\n );\n };\n\n\n const hideIsolatedShortHighlights = (pageHighlights: Element) => {\n const highlights = Array.from(\n pageHighlights.querySelectorAll(\".rpv-search__highlight\")\n ) as HTMLElement[];\n\n // ✅ Only process visible highlights — skip already-hidden ones\n const visibleItems = highlights\n .filter(el => el.style.display !== \"none\")\n .map(el => ({\n el,\n rect: el.getBoundingClientRect(),\n text: el.textContent?.trim() || \"\",\n }))\n .filter(item => item.rect.width > 0); // ✅ skip zero-rect (hidden/unmounted)\n\n visibleItems.forEach((item, i) => {\n const prev = visibleItems[i - 1];\n const next = visibleItems[i + 1];\n\n const width = item.rect.width;\n if (width > 100) return;\n const hasImmediateNeighbor =\n isImmediateCluster(item, prev) || isImmediateCluster(item, next);\n if (!hasImmediateNeighbor) item.el.style.display = \"none\";\n });\n };\n\n // ─── Core deduplication & matching ────────────────────────────────────────\n const deduplicateHighlights = (targetPage: number) => {\n if (!viewerRef.current) return;\n\n const pageHighlightsContainer = viewerRef.current.querySelector(\n `[data-testid=\"search__highlights-${targetPage}\"]`\n );\n if (!pageHighlightsContainer) return;\n\n const elements = Array.from(\n pageHighlightsContainer.querySelectorAll(\".rpv-search__highlight\")\n ) as HTMLElement[];\n\n if (elements.length === 0) return;\n\n const expectedSentenceVariants = filteredHighlightSentences.map(buildMatchVariants);\n const expectedLineVariants = filteredHighlightLineFragments.map(buildMatchVariants);\n if (expectedSentenceVariants.length === 0 && expectedLineVariants.length === 0) return;\n\n // Build DOM highlight items with coordinate fallback\n type HighlightItem = {\n el: HTMLElement;\n text: string;\n top: number;\n left: number;\n right: number;\n };\n\n type LogicalBlock = {\n title: string;\n elements: HTMLElement[];\n lastTop: number;\n lastRight: number;\n };\n\n const getCoords = (el: HTMLElement): { top: number; left: number; right: number } => {\n const rect = el.getBoundingClientRect();\n if (rect.height > 0 || rect.width > 0) {\n return { top: rect.top, left: rect.left, right: rect.right };\n }\n const top = el.offsetTop;\n const left = el.offsetLeft;\n const right = left + el.offsetWidth;\n return { top, left, right };\n };\n\n const items: HighlightItem[] = elements\n .map((el) => {\n const coords = getCoords(el);\n const rawText = (el.textContent || \"\").trim();\n const fallbackText = (el.getAttribute(\"title\") || \"\").trim();\n const text = rawText || fallbackText;\n return { el, text, ...coords };\n })\n .filter((item) => item.text.length > 0)\n .sort((a, b) => a.top - b.top || a.left - b.left);\n\n if (items.length === 0) return;\n\n // Group items into logical line-blocks\n const blocks: LogicalBlock[] = [];\n let currentBlock: LogicalBlock | null = null;\n let currentTextParts: string[] = [];\n const lineTolerance = 5;\n const wordGap = 28;\n\n const flushBlock = () => {\n if (!currentBlock) return;\n const joinedText = currentTextParts.join(\" \");\n currentBlock.title = normalizeForMatch(joinedText);\n if (currentBlock.title) blocks.push(currentBlock);\n currentBlock = null;\n currentTextParts = [];\n };\n\n items.forEach((item) => {\n if (!currentBlock) {\n currentBlock = {\n title: \"\",\n elements: [item.el],\n lastTop: item.top,\n lastRight: item.right,\n };\n currentTextParts = [item.text];\n return;\n }\n\n const sameLine = Math.abs(item.top - currentBlock.lastTop) <= lineTolerance;\n const closeToPrev = item.left <= currentBlock.lastRight + wordGap;\n\n if (sameLine && closeToPrev) {\n currentBlock.elements.push(item.el);\n currentBlock.lastTop = item.top;\n currentBlock.lastRight = Math.max(currentBlock.lastRight, item.right);\n currentTextParts.push(item.text);\n } else {\n flushBlock();\n currentBlock = {\n title: \"\",\n elements: [item.el],\n lastTop: item.top,\n lastRight: item.right,\n };\n currentTextParts = [item.text];\n }\n });\n flushBlock();\n\n if (blocks.length === 0) return;\n\n // Matching utilities\n\n // Returns true when blockTitle matches any of the expected variants.\n const matchesExpected = (blockTitle: string, variants: Set<string>): boolean => {\n if (!blockTitle) return false;\n if (variants.has(blockTitle)) return true;\n\n const compactTitle = blockTitle.replace(/\\s+/g, \"\");\n\n for (const variant of Array.from(variants)) {\n if (!variant) continue;\n const compactVariant = variant.replace(/\\s+/g, \"\");\n\n // Exact compact match\n if (compactVariant === compactTitle) return true;\n\n // Block is contained within the variant (fragmented DOM span)\n if (\n variant.length >= 8 &&\n blockTitle.length >= 5 &&\n variant.includes(blockTitle)\n )\n return true;\n if (\n compactVariant.length >= 8 &&\n compactTitle.length >= 5 &&\n compactVariant.includes(compactTitle)\n )\n return true;\n\n // Variant is contained within a larger block\n if (\n blockTitle.length >= 10 &&\n variant.length >= 8 &&\n blockTitle.includes(variant)\n )\n return true;\n if (\n compactTitle.length >= 10 &&\n compactVariant.length >= 8 &&\n compactTitle.includes(compactVariant)\n )\n return true;\n }\n return false;\n };\n\n let bestSequenceLen = 0;\n let blocksToKeep = new Set<number>();\n\n // Strategy A: Full-text sliding-window coverage\n\n const allExpectedNormalized = Array.from(\n new Set(\n [...filteredHighlightSentences, ...filteredHighlightLineFragments]\n .map(normalizeForMatch)\n .filter((s) => s.length >= 8)\n )\n ).sort((a, b) => b.length - a.length);\n\n const tryFullTextWindow = (expectedText: string): Set<number> | null => {\n if (!expectedText || expectedText.length < 8) return null;\n const expectedCompact = expectedText.replace(/\\s+/g, \"\");\n\n for (let start = 0; start < blocks.length; start++) {\n let combined = \"\";\n let combinedCompact = \"\";\n const collected = new Set<number>();\n\n for (\n let end = start;\n end < blocks.length && end < start + 20;\n end++\n ) {\n const piece = blocks[end].title;\n combined = combined ? `${combined} ${piece}` : piece;\n combinedCompact = combinedCompact\n ? `${combinedCompact}${piece.replace(/\\s+/g, \"\")}`\n : piece.replace(/\\s+/g, \"\");\n collected.add(end);\n\n if (\n combined.includes(expectedText) ||\n combinedCompact.includes(expectedCompact)\n ) {\n return collected;\n }\n\n if (\n combined.length >= 15 &&\n (expectedText.includes(combined) ||\n expectedCompact.includes(combinedCompact))\n ) {\n return collected;\n }\n\n if (combined.length > expectedText.length + 150) break;\n }\n }\n return null;\n };\n\n for (const expectedText of allExpectedNormalized) {\n const match = tryFullTextWindow(expectedText);\n if (match && match.size > 0) {\n match.forEach((idx) => blocksToKeep.add(idx));\n bestSequenceLen = blocksToKeep.size;\n }\n }\n\n // Strategy B: Per-sentence concatenated match\n\n const findConcatenatedMatch = (\n variantsList: Set<string>[]\n ): Set<number> | null => {\n if (variantsList.length === 0) return null;\n let bestMatch: { blocks: Set<number>; extra: number } | null = null;\n\n for (const variants of variantsList) {\n for (const variant of Array.from(variants)) {\n if (!variant || variant.length < 5) continue;\n const variantCompact = variant.replace(/\\s+/g, \"\");\n\n for (let start = 0; start < blocks.length; start++) {\n let combined = \"\";\n let combinedCompact = \"\";\n const collected = new Set<number>();\n\n for (\n let end = start;\n end < blocks.length && end < start + 15;\n end++\n ) {\n const piece = blocks[end].title;\n combined = combined ? `${combined} ${piece}` : piece;\n combinedCompact = combinedCompact\n ? `${combinedCompact}${piece.replace(/\\s+/g, \"\")}`\n : piece.replace(/\\s+/g, \"\");\n collected.add(end);\n\n if (\n combined.includes(variant) ||\n combinedCompact.includes(variantCompact)\n ) {\n const extra = Math.max(0, combined.length - variant.length);\n if (!bestMatch || extra < bestMatch.extra) {\n bestMatch = { blocks: new Set(collected), extra };\n }\n break;\n }\n\n if (combined.length > variant.length + 120) break;\n }\n }\n }\n }\n\n return bestMatch ? bestMatch.blocks : null;\n };\n\n if (bestSequenceLen === 0) {\n const concatenatedMatch = findConcatenatedMatch(expectedSentenceVariants);\n if (concatenatedMatch && concatenatedMatch.size > 0) {\n concatenatedMatch.forEach((idx) => blocksToKeep.add(idx));\n bestSequenceLen = blocksToKeep.size;\n }\n }\n\n // Strategy C: Line-by-line sequence matching\n\n const maxLineGap = getMaxLineGap(blocks);\n const expectedLineTexts = filteredHighlightLineFragments\n .map(normalizeForMatch)\n .filter((line) => line.length >= 8);\n const lineTokens = expectedLineTexts.map((line) =>\n line.split(/\\s+/).filter((word) => word.length >= 2)\n );\n\n if (bestSequenceLen === 0) {\n const sequenceCandidates = expectedLineVariants;\n\n for (\n let startBlockIdx = 0;\n startBlockIdx < blocks.length;\n startBlockIdx++\n ) {\n const blockTitle = blocks[startBlockIdx].title;\n\n for (let expStart = 0; expStart < sequenceCandidates.length; expStart++) {\n if (!matchesExpected(blockTitle, sequenceCandidates[expStart])) continue;\n\n let currentLen = 0;\n const currentKeptBlocks = new Set<number>();\n let expPtr = expStart;\n let lastMatchedBlockIdx = startBlockIdx - 1;\n\n for (let i = startBlockIdx; i < blocks.length && expPtr < sequenceCandidates.length; i++) {\n if (matchesExpected(blocks[i].title, sequenceCandidates[expPtr])) {\n if (lastMatchedBlockIdx >= 0) {\n const prevTop = blocks[lastMatchedBlockIdx].lastTop;\n const currentTop = blocks[i].lastTop;\n if (Math.abs(currentTop - prevTop) > maxLineGap) break;\n }\n\n currentLen++;\n currentKeptBlocks.add(i);\n lastMatchedBlockIdx = i;\n expPtr++;\n } else if (\n expPtr > 0 &&\n matchesExpected(blocks[i].title, sequenceCandidates[expPtr - 1])\n ) {\n const prevTop = blocks[lastMatchedBlockIdx].lastTop;\n const currentTop = blocks[i].lastTop;\n if (Math.abs(currentTop - prevTop) <= 3) {\n currentKeptBlocks.add(i);\n lastMatchedBlockIdx = i;\n }\n }\n\n if (i - lastMatchedBlockIdx > 6) break;\n }\n\n if (currentLen > bestSequenceLen) {\n bestSequenceLen = currentLen;\n blocksToKeep = currentKeptBlocks;\n }\n }\n }\n }\n\n // Strategy D: Fuzzy word-overlap fallback\n\n if (\n bestSequenceLen < Math.min(3, expectedLineTexts.length) &&\n expectedLineTexts.length > 0\n ) {\n const fuzzyBlocks = new Set<number>();\n\n blocks.forEach((block, index) => {\n const blockWords = block.title\n .split(/\\s+/)\n .filter((word) => word.length >= 2);\n\n if (blockWords.length < 2) return;\n const blockWordSet = new Set(blockWords);\n\n for (const expectedWords of lineTokens) {\n if (expectedWords.length < 2) continue;\n\n let common = 0;\n for (const word of expectedWords) {\n if (blockWordSet.has(word)) common++;\n }\n\n const ratio = common / expectedWords.length;\n if (common >= 3 || ratio >= 0.5) {\n fuzzyBlocks.add(index);\n break;\n }\n }\n });\n\n if (fuzzyBlocks.size > 0) {\n blocksToKeep = fuzzyBlocks;\n bestSequenceLen = Math.max(bestSequenceLen, fuzzyBlocks.size);\n }\n }\n\n // Strategy E: Normalized keyword exact-match fallback\n const normalizedSearchKeywords = new Set<string>();\n searchKeywords.forEach((keyword) => {\n const normalized = normalizeForMatch(keyword);\n if (!normalized) return;\n normalizedSearchKeywords.add(normalized);\n normalizedSearchKeywords.add(normalized.replace(/\\s+/g, \"\"));\n });\n\n if (bestSequenceLen === 0) {\n const fallbackBlocks = new Set<number>();\n blocks.forEach((block, index) => {\n const compactTitle = block.title.replace(/\\s+/g, \"\");\n if (\n normalizedSearchKeywords.has(block.title) ||\n normalizedSearchKeywords.has(compactTitle)\n ) {\n fallbackBlocks.add(index);\n return;\n }\n const keywordList = Array.from(normalizedSearchKeywords);\n for (let i = 0; i < keywordList.length; i++) {\n const kw = keywordList[i];\n if (kw.length >= 10 && kw.includes(block.title) && block.title.length >= 5) {\n fallbackBlocks.add(index);\n break;\n }\n }\n });\n\n if (fallbackBlocks.size === 0) return 0;\n blocksToKeep = fallbackBlocks;\n }\n\n // Reveal only verified blocks\n blocks.forEach((block, index) => {\n const isKept = blocksToKeep.has(index);\n block.elements.forEach((el) => {\n if (isKept) {\n // Reveal the verified sequence smoothly\n el.classList.add(\"verified-match\");\n el.style.display = \"\"; // Ensure it's in the document flow\n } else {\n // Hard-hide the noise so it doesn't block text selection\n el.style.display = \"none\";\n el.classList.remove(\"verified-match\");\n }\n });\n });\n\n // added console group for debugging - to be removed in final release\n // ─── After blocksToKeep is finalized, hide pixel-overlapping duplicates ──────\n // The search plugin sometimes renders multiple spans covering identical or\n // heavily-overlapping regions for the same keyword. We keep only the first\n // (largest) span in each overlapping cluster so opacity never compounds.\n\n const keptElements: HTMLElement[] = [];\n blocks.forEach((block, index) => {\n if (blocksToKeep.has(index)) {\n block.elements.forEach((el) => keptElements.push(el));\n }\n });\n\n // Build rects after a rAF so the browser has committed layout\n requestAnimationFrame(() => {\n type RectEntry = { el: HTMLElement; rect: DOMRect };\n const entries: RectEntry[] = keptElements\n .map((el) => ({ el, rect: el.getBoundingClientRect() }))\n .filter((e) => e.rect.width > 0 && e.rect.height > 0)\n // largest area first so we always keep the most-covering span\n .sort((a, b) => (b.rect.width * b.rect.height) - (a.rect.width * a.rect.height));\n\n const surviving: RectEntry[] = [];\n\n const overlapRatio = (a: DOMRect, b: DOMRect): number => {\n const ix = Math.max(0, Math.min(a.right, b.right) - Math.max(a.left, b.left));\n const iy = Math.max(0, Math.min(a.bottom, b.bottom) - Math.max(a.top, b.top));\n const intersection = ix * iy;\n const smaller = Math.min(a.width * a.height, b.width * b.height);\n return smaller > 0 ? intersection / smaller : 0;\n };\n\n entries.forEach(({ el, rect }) => {\n const isDuplicate = surviving.some(\n (s) => overlapRatio(s.rect, rect) > 0.5 // >50% of smaller rect is covered → duplicate\n );\n if (isDuplicate) {\n el.style.display = \"none\";\n el.classList.remove(\"verified-match\");\n } else {\n surviving.push({ el, rect });\n }\n });\n });\n console.groupCollapsed(`[debug: PDF ordered matching - Page ${targetPage}]`);\n console.log(\"input->\", highlightText);\n console.log(\"processed sentences->\", filteredHighlightSentences);\n console.log(\"processed lines->\", filteredHighlightLineFragments);\n console.log(\"Expected sentence count:\", expectedSentenceVariants.length);\n console.log(\"Expected line count:\", expectedLineVariants.length);\n console.log(\"Matched sequence length:\", bestSequenceLen);\n console.log(\"blocksToKeep\", blocksToKeep, \"size\", blocksToKeep.size);\n console.groupEnd();\n\n return blocksToKeep.size\n };\n\n\n const matchHighlightsInOrder = (\n processedHighlightText: string[],\n seenMap: Map<string, HTMLElement[]>\n ) => {\n const entries = Array.from(seenMap.entries());\n\n let pointer = 0;\n const result: any[] = [];\n\n const normalize = (str: string) =>\n str\n .toLowerCase()\n .replace(/[^\\w\\s]/g, \"\") // remove punctuation\n .replace(/\\s+/g, \" \") // normalize spaces\n .trim();\n\n for (let i = 0; i < processedHighlightText.length; i++) {\n const chunk = processedHighlightText[i];\n const normalizedChunk = normalize(chunk);\n\n while (pointer < entries.length) {\n const [key, value] = entries[pointer];\n const text = normalize(key.split(\"_#$_\")[0]);\n\n const nextChunk = processedHighlightText[i + 1];\n const nextEntry = entries[pointer + 1];\n\n const normalizedNextChunk = nextChunk ? normalize(nextChunk) : null;\n const nextText = nextEntry\n ? normalize(nextEntry[0].split(\"_#$_\")[0])\n : null;\n\n const isCurrentMatch = normalizedChunk === text;\n\n // ONLY apply lookahead if duplicate ahead\n const isDuplicateAhead =\n pointer + 1 < entries.length &&\n text === normalize(entries[pointer + 1][0].split(\"_#$_\")[0]);\n\n let isValid = isCurrentMatch;\n\n if (isCurrentMatch && isDuplicateAhead && normalizedNextChunk) {\n isValid = normalizedNextChunk === nextText;\n }\n\n if (isValid) {\n result.push({\n chunk,\n matchedKey: key,\n elements: value,\n });\n\n pointer++;\n break;\n }\n\n pointer++;\n }\n }\n\n return result;\n };\n\n\n // ✅ hide non-target pages\n // ✅ Accepts multiple target pages\n const hideNonTargetHighlights = (targetPages: Set<number>) => {\n if (!viewerRef.current) return;\n const allPageHighlights = viewerRef.current.querySelectorAll(\n \".rpv-search__highlights\"\n );\n\n allPageHighlights.forEach((pageHighlights) => {\n const testId = pageHighlights.getAttribute(\"data-testid\");\n const pageIndex = parseInt(\n // testId?.replace(\"search__highlights-\", \"\") || \"-1\"\n testId?.replace(/search__highlights-/g, \"\") || \"-1\"\n );\n const highlights = pageHighlights.querySelectorAll(\".rpv-search__highlight\");\n\n // ✅ Hide if page is NOT in the target set\n if (!targetPages.has(pageIndex)) {\n highlights.forEach((h) => {\n (h as HTMLElement).style.display = \"none\";\n });\n }\n // else if (highlights.length > 1) {\n // hideIsolatedShortHighlights(pageHighlights)\n // }\n });\n };\n\n // Pre-process input highlight text\n const processedHighlightSegments = highlightText\n .map((text) => processPdfHighlightText(text))\n .flat();\n\n const processedHighlightLineFragments = highlightText\n .map((text) => extractCleanLines(text))\n .flat();\n\n const minKeywordLength = processedHighlightSegments.some((line) => line.length >= 3)\n ? 3\n : 1;\n\n const filteredHighlightSentences = processedHighlightSegments.filter(\n (line) => line.length >= minKeywordLength\n );\n\n const filteredHighlightLineFragments = processedHighlightLineFragments.filter(\n (line) => line.length >= minKeywordLength\n );\n\n const isKeywordUseful = (line: string): boolean => {\n const words = line.split(/\\s+/).filter(Boolean);\n if (line.length < minKeywordLength) return false;\n if (words.length >= 3) return true;\n return line.length >= 12;\n };\n\n const buildWordWindows = (line: string, size = 6, step = 4): string[] => {\n const words = line.split(/\\s+/).filter(Boolean);\n if (words.length <= size) return [];\n const windows: string[] = [];\n for (let i = 0; i + size <= words.length; i += step) {\n windows.push(words.slice(i, i + size).join(\" \"));\n }\n if (words.length > size && (words.length - size) % step !== 0) {\n windows.push(words.slice(words.length - size).join(\" \"));\n }\n return windows;\n };\n\n const lineFragmentWindows = filteredHighlightLineFragments.flatMap((line) =>\n buildWordWindows(line)\n );\n\n const searchKeywords = Array.from(\n new Set(\n [\n ...filteredHighlightSentences,\n ...filteredHighlightLineFragments,\n ...lineFragmentWindows,\n ].flatMap(buildSearchVariants)\n )\n ).filter(isKeywordUseful);\n\n // Plugin instances\n const searchPluginInstance = searchPlugin({ keyword: searchKeywords });\n const pageNavigationPluginInstance = pageNavigationPlugin();\n const zoomPluginInstance = zoomPlugin();\n\n const { jumpToMatch } = searchPluginInstance;\n const { jumpToPage } = pageNavigationPluginInstance;\n const { zoomTo, CurrentScale, ZoomPopover } = zoomPluginInstance;\n\n // Pre-merge overlapping areas so stacked highlights don't compound opacity\nconst mergedCoordinateAreas = useMemo(\n () => mergeOverlappingAreas(highlightCordinatePages),\n [highlightCordinatePages]\n);\n\nconst highlightPluginInstance = highlightPlugin({\n renderHighlights: (props: RenderHighlightsProps) => (\n <>\n {mergedCoordinateAreas\n .filter((h) =>\n h.pageNumber != null\n ? h.pageNumber - 1 === props.pageIndex\n : h.pageIndex === props.pageIndex\n )\n .map((area) => {\n const isActive = area.originalIndexes.includes(cursorIndex);\n\n return (\n <div\n key={area.originalIndexes.join(\"-\")}\n style={{\n position: \"absolute\",\n left: `${area.left}%`,\n top: `${area.top + area.height * 0.08}%`,\n width: `${area.width}%`,\n height: `${area.height * 0.95}%`,\n background: isActive ? activeHighlightColor : highlightColor,\n opacity: isActive ? 0.7 : 0.4,\n transition: \"background 0.2s, opacity 0.2s\",\n border: isActive ? `1px solid ${\"red\"}` : `1px solid transparent`,\n }}\n />\n );\n })}\n </>\n ),\n});\n\n const tryJump = () => {\n if (hasJumpedRef.current) return;\n try {\n jumpToMatch(0);\n hasJumpedRef.current = true;\n const first = highlightCordinatePages[0]; // ✅ use highlightPages not hardcoded highlights\n if (first && useCoordinates) {\n scrollToCoord(first.pageIndex, first.top);\n }\n } catch {\n requestAnimationFrame(tryJump);\n }\n };\n\n\n const scrollToHighlightAfterNav = (targetPage: number, occurrence: number) => {\n if (!viewerRef.current) return;\n\n const container = viewerRef.current.querySelector(\".rpv-core__viewer\");\n if (!container) return;\n\n let lastScrollTop = -1;\n\n const doScrollToHighlight = () => {\n const scrollContainer = viewerRef.current?.querySelector(\n \".rpv-core__inner-pages\"\n ) as HTMLElement;\n if (!scrollContainer) return;\n\n // ✅ Wait for jumpToPage scroll to settle\n if (scrollContainer.scrollTop !== lastScrollTop) {\n lastScrollTop = scrollContainer.scrollTop;\n setTimeout(doScrollToHighlight, 100);\n return;\n }\n\n const pageElement = viewerRef.current?.querySelector(\n `[data-testid=\"core__page-layer-${targetPage}\"]`\n );\n if (!pageElement) return;\n\n // ✅ Get nth highlight on this page using occurrence\n const allHighlights = pageElement.querySelectorAll(\".rpv-search__highlight\");\n const target = allHighlights[occurrence] as HTMLElement;\n\n if (!target) return;\n\n const scrollContainerRect = scrollContainer.getBoundingClientRect();\n const highlightRect = target.getBoundingClientRect();\n\n const scrollTop =\n scrollContainer.scrollTop +\n (highlightRect.top - scrollContainerRect.top) -\n scrollContainer.clientHeight / 2 +\n highlightRect.height / 2;\n\n scrollContainer.scrollTo({ top: scrollTop, behavior: \"smooth\" });\n };\n\n setTimeout(doScrollToHighlight, 300);\n };\n\n // ─── Coordinate-mode: scroll by percentage position ───────────────────────\n\n const scrollToCoord = (pageIndex: number, top: number, height = 0) => {\n\n if (!viewerRef.current) return;\n let attempts = 0;\n const VIEWPORT_PADDING = 80;\n\n const doScroll = () => {\n if (++attempts > 60) return;\n\n const scrollContainer = viewerRef.current?.querySelector(\n \".rpv-core__inner-pages\"\n ) as HTMLElement | null;\n\n if (!scrollContainer) { setTimeout(doScroll, 100); return; }\n\n\n // const normalizedPageIndex = pageIndex - 1;\n\n const pageElement = viewerRef.current?.querySelector(\n `[data-testid=\"core__page-layer-${pageIndex}\"]`\n ) as HTMLElement | null;\n\n if (!pageElement) { setTimeout(doScroll, 100); return; }\n\n\n const pageRect = pageElement.getBoundingClientRect();\n\n if (pageRect.height === 0) { setTimeout(doScroll, 100); return; }\n\n const scrollContainerRect = scrollContainer.getBoundingClientRect();\n const highlightTopInPage = (top / 100) * pageRect.height;\n const highlightHeightInPage = (height / 100) * pageRect.height;\n const highlightTopAbsolute =\n pageRect.top - scrollContainerRect.top + highlightTopInPage;\n const highlightBottomAbsolute = highlightTopAbsolute + highlightHeightInPage;\n\n const isComfortablyVisible =\n highlightTopAbsolute >= VIEWPORT_PADDING &&\n highlightBottomAbsolute <= scrollContainer.clientHeight - VIEWPORT_PADDING;\n\n if (isComfortablyVisible) return;\n\n const scrollTop =\n highlightTopAbsolute < VIEWPORT_PADDING\n ? scrollContainer.scrollTop + highlightTopAbsolute - VIEWPORT_PADDING\n : scrollContainer.scrollTop +\n highlightBottomAbsolute -\n scrollContainer.clientHeight +\n VIEWPORT_PADDING;\n\n scrollContainer.scrollTo({\n top: scrollTop,\n behavior: \"smooth\",\n });\n };\n\n setTimeout(doScroll, 100);\n };\n\n\n// ✅ Map: page -> [cursorIndexes] for same-page occurrence tracking\nconst pageVisitMap = useMemo(() => {\n const map: Record<number, number[]> = {};\n orderedKeys.forEach((key, i) => {\n const page = highlightPages[key];\n if (page > 0) {\n if (!map[page]) map[page] = [];\n map[page].push(i);\n }\n });\n return map;\n}, [orderedKeys, highlightPages]);\n\n// ✅ Get which occurrence (0,1,2...) this cursorIndex is on its page\nconst getHighlightOccurrence = (cursorIdx: number): number => {\n const page = highlightPages[orderedKeys[cursorIdx]];\n const visits = pageVisitMap[page] || [];\n return visits.indexOf(cursorIdx);\n};\n\n\nconst scrollToCoordAfterNav = (pageIndex: number, top: number, height = 0) => {\n if (!viewerRef.current) return;\n const VIEWPORT_PADDING = 80;\n let lastScrollTop = -1;\n let attempts = 0;\n\n const waitForSettle = () => {\n if (++attempts > 60) return;\n\n const scrollContainer = viewerRef.current?.querySelector(\n \".rpv-core__inner-pages\"\n ) as HTMLElement | null;\n if (!scrollContainer) { setTimeout(waitForSettle, 100); return; }\n\n if (scrollContainer.scrollTop !== lastScrollTop) {\n lastScrollTop = scrollContainer.scrollTop;\n setTimeout(waitForSettle, 100);\n return;\n }\n\n const pageElement = viewerRef.current?.querySelector(\n `[data-testid=\"core__page-layer-${pageIndex}\"]`\n ) as HTMLElement | null;\n if (!pageElement) { setTimeout(waitForSettle, 100); return; }\n\n const pageRect = pageElement.getBoundingClientRect();\n if (pageRect.height === 0) { setTimeout(waitForSettle, 100); return; }\n\n const scrollContainerRect = scrollContainer.getBoundingClientRect();\n const highlightTopInPage = (top / 100) * pageRect.height;\n const highlightHeightInPage = (height / 100) * pageRect.height;\n const highlightTopAbsolute =\n pageRect.top - scrollContainerRect.top + highlightTopInPage;\n const highlightBottomAbsolute = highlightTopAbsolute + highlightHeightInPage;\n\n const isComfortablyVisible =\n highlightTopAbsolute >= VIEWPORT_PADDING &&\n highlightBottomAbsolute <= scrollContainer.clientHeight - VIEWPORT_PADDING;\n\n if (isComfortablyVisible) return;\n\n const scrollTop =\n highlightTopAbsolute < VIEWPORT_PADDING\n ? scrollContainer.scrollTop + highlightTopAbsolute - VIEWPORT_PADDING\n : scrollContainer.scrollTop +\n highlightBottomAbsolute -\n scrollContainer.clientHeight +\n VIEWPORT_PADDING;\n\n // ✅ instant — no second smooth animation\n scrollContainer.scrollTo({\n top: scrollTop,\n behavior: \"instant\" as ScrollBehavior,\n });\n };\n\n setTimeout(waitForSettle, 100);\n};\n\nconst goToNext = () => {\n if (useCoordinates && highlightCordinatePages) {\n for (let i = cursorIndex + 1; i < highlightCordinatePages.length; i++) {\n const h = highlightCordinatePages[i];\n const currentH = highlightCordinatePages[cursorIndex];\n setCursorIndex(i);\n\n if (h.pageIndex !== currentH.pageIndex) {\n jumpToPage(h.pageIndex);\n scrollToCoordAfterNav(h.pageIndex, h.top, h.height);\n } else {\n scrollToCoord(h.pageIndex, h.top, h.height);\n }\n return;\n }\n } else {\n const prev = cursorIndex;\n for (let i = prev + 1; i < orderedKeys.length; i++) {\n const key = orderedKeys[i];\n if (highlightPages[key] > 0) {\n const page = highlightPages[key] - 1;\n const occurrence = getHighlightOccurrence(i);\n setCursorIndex(i);\n jumpToPage(highlightPages[key] - 1);\n scrollToHighlightAfterNav(page, occurrence);\n setTimeout(() => { deduplicateHighlights(page); }, 500);\n if (Object.keys(highlightPages).length === 1) hideNonTargetHighlights(highlightPageSet);\n return;\n }\n }\n }\n};\n\nconst goToPrevious = () => {\n if (useCoordinates && highlightCordinatePages) {\n for (let i = cursorIndex - 1; i >= 0; i--) {\n const h = highlightCordinatePages[i];\n const currentH = highlightCordinatePages[cursorIndex];\n setCursorIndex(i);\n\n if (h.pageIndex !== currentH.pageIndex) {\n jumpToPage(h.pageIndex);\n scrollToCoordAfterNav(h.pageIndex, h.top, h.height);\n } else {\n scrollToCoord(h.pageIndex, h.top, h.height);\n }\n return;\n }\n } else {\n const prev = cursorIndex;\n for (let i = prev - 1; i >= 0; i--) {\n const key = orderedKeys[i];\n if (highlightPages[key] > 0) {\n const page = highlightPages[key] - 1;\n const occurrence = getHighlightOccurrence(i);\n setCursorIndex(i);\n jumpToPage(highlightPages[key] - 1);\n scrollToHighlightAfterNav(page, occurrence);\n setTimeout(() => { deduplicateHighlights(page); }, 500);\n if (Object.keys(highlightPages).length === 1) hideNonTargetHighlights(highlightPageSet);\n return;\n }\n }\n }\n};\n\n\n return {\n setHighlightIndex,\n highlightIndex,\n cursorIndex,\n setCursorIndex,\n orderedKeys,\n totalHighlights,\n getValidPosition,\n tryJump,\n jumpToPage,\n zoomTo,\n hideNonTargetHighlights,\n deduplicateHighlights,\n scrollToCoord,\n plugins: [\n useCoordinates ? highlightPluginInstance : searchPluginInstance,\n pageNavigationPluginInstance,\n zoomPluginInstance,\n ],\n controls: {\n CurrentScale,\n ZoomPopover,\n zoomTo,\n goToNext,\n goToPrevious,\n },\n };\n};"],"names":["PdfHighlightControls","highlightText","highlightPages","viewerRef","highlightPageSet","useCoordinates","highlightCordinatePages","highlightColor","activeHighlightColor","highlightIndex","setHighlightIndex","useState","hasJumpedRef","useRef","cursorIndex","setCursorIndex","normalizeWhitespace","value","replace","trim","normalizeForMatch","toLowerCase","stripLeadingIndex","line","trimmed","match","slice","length","buildMatchVariants","normalized","compact","variants","Set","add","getCleanedHighlightText","text","str","textarea","document","createElement","innerHTML","decodeHtml","extractCleanLines","split","map","flatMap","tableMatch","cell","filter","Boolean","stripMarkdownEmphasis","orderedKeys","Object","keys","Number","sort","a","b","totalHighlights","useMemo","values","p","deduplicateHighlights","targetPage","current","pageHighlightsContainer","querySelector","elements","Array","from","querySelectorAll","expectedSentenceVariants","filteredHighlightSentences","expectedLineVariants","filteredHighlightLineFragments","items","el","coords","rect","getBoundingClientRect","height","width","top","left","right","offsetTop","offsetLeft","offsetWidth","getCoords","rawText","textContent","fallbackText","getAttribute","item","blocks","currentBlock","currentTextParts","flushBlock","joinedText","join","title","push","forEach","lastTop","lastRight","sameLine","Math","abs","closeToPrev","max","matchesExpected","blockTitle","has","compactTitle","variant","compactVariant","includes","bestSequenceLen","blocksToKeep","allExpectedNormalized","s","tryFullTextWindow","expectedText","expectedCompact","start","combined","combinedCompact","collected","end","piece","size","idx","concatenatedMatch","variantsList","bestMatch","variantCompact","extra","findConcatenatedMatch","maxLineGap","diffs","i","diff","median","floor","scaled","round","min","getMaxLineGap","expectedLineTexts","lineTokens","word","sequenceCandidates","startBlockIdx","expStart","currentLen","currentKeptBlocks","expPtr","lastMatchedBlockIdx","prevTop","currentTop","fuzzyBlocks","block","index","blockWords","blockWordSet","expectedWords","common","ratio","normalizedSearchKeywords","searchKeywords","keyword","fallbackBlocks","keywordList","kw","isKept","classList","style","display","remove","keptElements","requestAnimationFrame","entries","e","surviving","some","intersection","bottom","smaller","overlapRatio","console","groupCollapsed","log","groupEnd","hideNonTargetHighlights","targetPages","pageHighlights","testId","pageIndex","parseInt","highlights","h","processedHighlightSegments","processPdfHighlightText","flat","processedHighlightLineFragments","minKeywordLength","lineFragmentWindows","step","words","windows","buildWordWindows","base","dashNormalized","dehyphenated","hyphenToSpace","hyphenRemoved","punctuationStripped","searchPluginInstance","searchPlugin","pageNavigationPluginInstance","pageNavigationPlugin","zoomPluginInstance","zoomPlugin","jumpToMatch","jumpToPage","zoomTo","CurrentScale","ZoomPopover","mergedCoordinateAreas","areas","byPage","Map","pageKey","pageNumber","set","get","originalIndex","merged","pageAreas","sorted","used","fill","originalIndexes","changed","j","bRight","bBottom","intersectionArea","currentArea","nextArea","smallerArea","mergeOverlappingAreas","highlightPluginInstance","highlightPlugin","renderHighlights","props","jsx","Fragment","children","area","isActive","position","background","opacity","transition","border","tryJump","first","scrollToCoord","scrollToHighlightAfterNav","occurrence","lastScrollTop","doScrollToHighlight","scrollContainer","scrollTop","setTimeout","pageElement","target","scrollContainerRect","highlightRect","clientHeight","scrollTo","behavior","attempts","doScroll","pageRect","highlightTopInPage","highlightHeightInPage","highlightTopAbsolute","highlightBottomAbsolute","pageVisitMap","key","page","getHighlightOccurrence","cursorIdx","indexOf","scrollToCoordAfterNav","waitForSettle","getValidPosition","cursor","count","plugins","controls","goToNext","currentH","goToPrevious"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
class t{constructor(){this.lastValidZoom=1,this.isRotating=!1,this.rotationTimeoutId=null,this.ROTATION_TRANSITION_DURATION=300,this.zoomStateListeners=new Set,this.frozenZoomDisplay=null,this.currentZoomLevel=1}getLastValidZoom(){return this.lastValidZoom}setLastValidZoom(t){Number.isFinite(t)&&t>0&&(this.lastValidZoom=t,this.currentZoomLevel=t,this.notifyZoomStateChange(t))}getDisplayZoom(){return this.isRotating&&null!==this.frozenZoomDisplay?this.frozenZoomDisplay:this.currentZoomLevel}beginRotation(){this.isRotating=!0,this.frozenZoomDisplay=this.currentZoomLevel,null!==this.rotationTimeoutId&&clearTimeout(this.rotationTimeoutId),this.rotationTimeoutId=setTimeout(()=>{this.endRotation()},this.ROTATION_TRANSITION_DURATION)}endRotation(){this.isRotating=!1,this.frozenZoomDisplay=null,null!==this.rotationTimeoutId&&(clearTimeout(this.rotationTimeoutId),this.rotationTimeoutId=null)}isInRotationTransition(){return this.isRotating}safeZoomEvaluation(t,o){try{const i=t(Number.isFinite(o)?o:this.lastValidZoom);return Number.isFinite(i)&&i>0?(this.setLastValidZoom(i),i):(console.warn(`[ZoomStateManager] Zoom calculation returned invalid value: ${i}. Recovering to last valid zoom: ${this.lastValidZoom}`),this.lastValidZoom)}catch(t){return console.error("[ZoomStateManager] Error during zoom evaluation:",t),this.lastValidZoom}}onZoomStateChange(t){return this.zoomStateListeners.add(t),()=>{this.zoomStateListeners.delete(t)}}notifyZoomStateChange(t){this.zoomStateListeners.forEach(o=>{try{o(t)}catch(t){console.error("[ZoomStateManager] Error in zoom state listener:",t)}})}reset(){this.lastValidZoom=1,this.currentZoomLevel=1,this.isRotating=!1,this.frozenZoomDisplay=null,null!==this.rotationTimeoutId&&(clearTimeout(this.rotationTimeoutId),this.rotationTimeoutId=null)}}const o=new t;export{t as ZoomStateManager,o as zoomStateManager};
|
|
2
|
+
//# sourceMappingURL=zoomStateManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zoomStateManager.js","sources":["../../../src/features/PdfViewer/zoomStateManager.ts"],"sourcesContent":["export class ZoomStateManager {\n private lastValidZoom: number = 1; // Default zoom level\n private isRotating: boolean = false;\n private rotationTimeoutId: ReturnType<typeof setTimeout> | null = null;\n private readonly ROTATION_TRANSITION_DURATION = 300; // Match CSS transition time\n private zoomStateListeners: Set<(zoom: number) => void> = new Set();\n private frozenZoomDisplay: number | null = null; // Caches zoom display value during rotation to prevent UI flicker\n private currentZoomLevel: number = 1; // Tracks actual current zoom level for display purposes\n\n getLastValidZoom(): number {\n return this.lastValidZoom;\n }\n\n setLastValidZoom(zoom: number): void {\n if (Number.isFinite(zoom) && zoom > 0) {\n this.lastValidZoom = zoom;\n this.currentZoomLevel = zoom;\n this.notifyZoomStateChange(zoom);\n }\n }\n\n getDisplayZoom(): number {\n if (this.isRotating && this.frozenZoomDisplay !== null) {\n return this.frozenZoomDisplay;\n }\n return this.currentZoomLevel;\n }\n\n beginRotation(): void {\n this.isRotating = true;\n this.frozenZoomDisplay = this.currentZoomLevel;\n\n if (this.rotationTimeoutId !== null) {\n clearTimeout(this.rotationTimeoutId);\n }\n this.rotationTimeoutId = setTimeout(() => {\n this.endRotation();\n }, this.ROTATION_TRANSITION_DURATION);\n }\n\n endRotation(): void {\n this.isRotating = false;\n this.frozenZoomDisplay = null;\n if (this.rotationTimeoutId !== null) {\n clearTimeout(this.rotationTimeoutId);\n this.rotationTimeoutId = null;\n }\n }\n\n isInRotationTransition(): boolean {\n return this.isRotating;\n }\n\n safeZoomEvaluation(\n zoomCallback: (current: number) => number,\n currentZoom: number\n ): number {\n try {\n const baseZoom = Number.isFinite(currentZoom) ? currentZoom : this.lastValidZoom;\n const newZoom = zoomCallback(baseZoom);\n\n if (Number.isFinite(newZoom) && newZoom > 0) {\n this.setLastValidZoom(newZoom);\n return newZoom;\n } else {\n console.warn(\n `[ZoomStateManager] Zoom calculation returned invalid value: ${newZoom}. ` +\n `Recovering to last valid zoom: ${this.lastValidZoom}`\n );\n return this.lastValidZoom;\n }\n } catch (error) {\n console.error(`[ZoomStateManager] Error during zoom evaluation:`, error);\n return this.lastValidZoom;\n }\n }\n\n onZoomStateChange(callback: (zoom: number) => void): () => void {\n this.zoomStateListeners.add(callback);\n return () => {\n this.zoomStateListeners.delete(callback);\n };\n }\n\n private notifyZoomStateChange(zoom: number): void {\n this.zoomStateListeners.forEach(listener => {\n try {\n listener(zoom);\n } catch (error) {\n console.error('[ZoomStateManager] Error in zoom state listener:', error);\n }\n });\n }\n\n reset(): void {\n this.lastValidZoom = 1;\n this.currentZoomLevel = 1;\n this.isRotating = false;\n this.frozenZoomDisplay = null;\n if (this.rotationTimeoutId !== null) {\n clearTimeout(this.rotationTimeoutId);\n this.rotationTimeoutId = null;\n }\n }\n}\n\nexport const zoomStateManager = new ZoomStateManager();\n\n"],"names":["ZoomStateManager","constructor","this","lastValidZoom","isRotating","rotationTimeoutId","ROTATION_TRANSITION_DURATION","zoomStateListeners","Set","frozenZoomDisplay","currentZoomLevel","getLastValidZoom","setLastValidZoom","zoom","Number","isFinite","notifyZoomStateChange","getDisplayZoom","beginRotation","clearTimeout","setTimeout","endRotation","isInRotationTransition","safeZoomEvaluation","zoomCallback","currentZoom","newZoom","console","warn","error","onZoomStateChange","callback","add","delete","forEach","listener","reset","zoomStateManager"],"mappings":"AAAO,MAAMA,EAAN,WAAAC,GACLC,KAAQC,cAAwB,EAChCD,KAAQE,YAAsB,EAC9BF,KAAQG,kBAA0D,KAClEH,KAAiBI,6BAA+B,IACxCJ,KAAAK,uBAAsDC,IAC9DN,KAAQO,kBAAmC,KAC3CP,KAAQQ,iBAA2B,CAAA,CAEnC,gBAAAC,GACE,OAAOT,KAAKC,aACd,CAEA,gBAAAS,CAAiBC,GACXC,OAAOC,SAASF,IAASA,EAAO,IAClCX,KAAKC,cAAgBU,EACrBX,KAAKQ,iBAAmBG,EACxBX,KAAKc,sBAAsBH,GAE/B,CAEA,cAAAI,GACE,OAAIf,KAAKE,YAAyC,OAA3BF,KAAKO,kBACnBP,KAAKO,kBAEPP,KAAKQ,gBACd,CAEA,aAAAQ,GACEhB,KAAKE,YAAa,EAClBF,KAAKO,kBAAoBP,KAAKQ,iBAEC,OAA3BR,KAAKG,mBACPc,aAAajB,KAAKG,mBAEfH,KAAAG,kBAAoBe,WAAW,KAClClB,KAAKmB,eACJnB,KAAKI,6BACV,CAEA,WAAAe,GACEnB,KAAKE,YAAa,EAClBF,KAAKO,kBAAoB,KACM,OAA3BP,KAAKG,oBACPc,aAAajB,KAAKG,mBAClBH,KAAKG,kBAAoB,KAE7B,CAEA,sBAAAiB,GACE,OAAOpB,KAAKE,UACd,CAEA,kBAAAmB,CACEC,EACAC,GAEI,IACF,MACMC,EAAUF,EADCV,OAAOC,SAASU,GAAeA,EAAcvB,KAAKC,eAGnE,OAAIW,OAAOC,SAASW,IAAYA,EAAU,GACxCxB,KAAKU,iBAAiBc,GACfA,IAECC,QAAAC,KACN,+DAA+DF,qCAC7BxB,KAAKC,iBAElCD,KAAKC,qBAEP0B,GAEP,OADQF,QAAAE,MAAM,mDAAoDA,GAC3D3B,KAAKC,aACd,CACF,CAEA,iBAAA2B,CAAkBC,GAEhB,OADK7B,KAAAK,mBAAmByB,IAAID,GACrB,KACA7B,KAAAK,mBAAmB0B,OAAOF,GAEnC,CAEQ,qBAAAf,CAAsBH,GACvBX,KAAAK,mBAAmB2B,QAAoBC,IACtC,IACFA,EAAStB,SACFgB,GACCF,QAAAE,MAAM,mDAAoDA,EACpE,GAEJ,CAEA,KAAAO,GACElC,KAAKC,cAAgB,EACrBD,KAAKQ,iBAAmB,EACxBR,KAAKE,YAAa,EAClBF,KAAKO,kBAAoB,KACM,OAA3BP,KAAKG,oBACPc,aAAajB,KAAKG,mBAClBH,KAAKG,kBAAoB,KAE7B,EAGW,MAAAgC,EAAmB,IAAIrC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{jsx as r}from"react/jsx-runtime";import o from"@mui/material/Box";import{getReviewScoreBand as e}from"./reviewScore.js";function t({score:t}){if(null==t||"string"==typeof t&&""===t.trim())return null;const
|
|
1
|
+
import{jsx as r}from"react/jsx-runtime";import o from"@mui/material/Box";import{getReviewScoreBand as e}from"./reviewScore.js";function t({score:t}){if(null==t||"string"==typeof t&&""===t.trim())return null;const n="number"==typeof t?`${t}%`:t;return e("number"==typeof t||"string"==typeof t?t:null),r(o,{component:"span",sx:{px:.625,py:0,border:"1.5px solid",borderColor:"#5925DC",borderRadius:10,color:"#5925DC",fontSize:11,lineHeight:1.25},children:n})}export{t as default};
|
|
2
2
|
//# sourceMappingURL=CognitiveScoreBadge.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CognitiveScoreBadge.js","sources":["../../../src/features/SegmentReviewComponents/CognitiveScoreBadge.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport Box from '@mui/material/Box';\nimport { getReviewScoreBand } from './reviewScore';\n\nexport interface CognitiveScoreBadgeProps {\n score?: ReactNode;\n}\n\n/** Displays numeric scores as percentages while preserving backend-formatted strings. */\nexport default function CognitiveScoreBadge({ score }: CognitiveScoreBadgeProps) {\n if (score == null || (typeof score === 'string' && score.trim() === '')) {\n return null;\n }\n\n const displayScore = typeof score === 'number' ? `${score}%` : score;\n const scoreBand = getReviewScoreBand(\n typeof score === 'number' || typeof score === 'string' ? score : null\n );\n const scoreColor = scoreBand === 'low'\n ? '#B91C1C'\n : scoreBand === 'medium'\n ? '#997800'\n : scoreBand === 'high'\n ? '#4F9E6C'\n : '#374151';\n\n return (\n <Box\n component=\"span\"\n sx={{\n px: 0.625,\n py: 0,\n border: '1.5px solid',\n borderColor:
|
|
1
|
+
{"version":3,"file":"CognitiveScoreBadge.js","sources":["../../../src/features/SegmentReviewComponents/CognitiveScoreBadge.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport Box from '@mui/material/Box';\nimport { getReviewScoreBand } from './reviewScore';\n\nexport interface CognitiveScoreBadgeProps {\n score?: ReactNode;\n}\n\n/** Displays numeric scores as percentages while preserving backend-formatted strings. */\nexport default function CognitiveScoreBadge({ score }: CognitiveScoreBadgeProps) {\n if (score == null || (typeof score === 'string' && score.trim() === '')) {\n return null;\n }\n\n const displayScore = typeof score === 'number' ? `${score}%` : score;\n const scoreBand = getReviewScoreBand(\n typeof score === 'number' || typeof score === 'string' ? score : null\n );\n const scoreColor = scoreBand === 'low'\n ? '#B91C1C'\n : scoreBand === 'medium'\n ? '#997800'\n : scoreBand === 'high'\n ? '#4F9E6C'\n : '#374151';\n\n return (\n <Box\n component=\"span\"\n sx={{\n px: 0.625,\n py: 0,\n border: '1.5px solid',\n borderColor: \"#5925DC\",\n borderRadius: 10,\n color: \"#5925DC\",\n fontSize: 11,\n lineHeight: 1.25,\n }}\n >\n {displayScore}\n </Box>\n );\n}\n"],"names":["CognitiveScoreBadge","score","trim","displayScore","getReviewScoreBand","jsx","Box","component","sx","px","py","border","borderColor","borderRadius","color","fontSize","lineHeight","children"],"mappings":"+HASwB,SAAAA,GAAoBC,MAAEA,IACxC,GAAS,MAATA,GAAmC,iBAAVA,GAAuC,KAAjBA,EAAMC,OAChD,OAAA,KAGT,MAAMC,EAAgC,iBAAVF,EAAqB,GAAGA,KAAWA,EAa7D,OAZgBG,EACC,iBAAVH,GAAuC,iBAAVA,EAAqBA,EAAQ,MAWjEI,EAACC,EAAA,CACCC,UAAU,OACVC,GAAI,CACFC,GAAI,KACJC,GAAI,EACJC,OAAQ,cACRC,YAAa,UACbC,aAAc,GACdC,MAAO,UACPC,SAAU,GACVC,WAAY,MAGbC,SAAAd,GAGP"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{isBoundaryReviewAction as e}from"./BoundaryCard.js";import{isLabelReviewAction as
|
|
1
|
+
import{isBoundaryReviewAction as e}from"./BoundaryCard.js";import{isLabelReviewAction as a}from"./LabelCheck.js";import{isPageCheckAction as i,PageCheckActionEnum as t}from"./PageCheck.js";const n=e=>"object"==typeof e&&null!==e?e:{},s=e=>"string"==typeof e?e:null,r=e=>"number"==typeof e&&Number.isFinite(e)?e:null,c=e=>Array.isArray(e)?e.filter(e=>"string"==typeof e):[],o=e=>{const a="string"==typeof e?e.trim().toLowerCase():"";return"table"===a||"drawing"===a?a:null},l=(e,a=0)=>e.stable_key||e.segment_id||`${e.start_page}-${e.end_page}-${a}`,d=e=>{const i=n(e);return{current_label:s(i.current_label),custom_label:s(i.custom_label),group_id:s(i.group_id),user_actions:c(i.user_actions).filter(a)}},u=e=>{const a=n(e),t=Array.isArray(a.type_choices)?a.type_choices.flatMap(e=>{const a=n(e),i=o(a.page_type),t=s(a.classification_id)?.trim();return i&&t?[{page_type:i,classification_id:t}]:[]}):[];return{page_type:o(a.page_type),page_num:r(a.page_num),classification_id:s(a.classification_id),type_choices:t.length>1?t:void 0,user_actions:c(a.user_actions).filter(i)}},_=e=>{const a=e.human_action?.verdict?.trim().toUpperCase();return a&&i(a)?a:null},p=a=>{const s=[],p=[],m=[];return a.forEach((a,g)=>{const f=l(a,g),h=a.review_steps??[];h.forEach((i,t)=>{const o=(e=>{const a=e.trim().toLowerCase();return"page_boundary"===a||"page boundary review"===a?"boundary":"label"===a||"label review"===a?"label":"page"===a?"page":null})(i.type);if("boundary"===o){const o=(a=>{const i=n(a);return{focus_page:r(i.focus_page),boundary_margin:r(i.boundary_margin),user_actions:c(i.user_actions).filter(e)}})(i.metadata);s.push({id:`${f}:boundary:${t}`,reviewStepIndex:t,segment:a,review_step:i,metadata:o})}"label"===o&&p.push({id:`${f}:label:${t}`,reviewStepIndex:t,segment:a,review_step:i,metadata:d(i.metadata)}),"page"===o&&m.push({id:`${f}:page:${t}`,reviewStepIndex:t,segment:a,review_step:i,metadata:u(i.metadata)})});let y=0;a.page_classifications?.forEach((e,n)=>{const s=e.page_num??null,r=e.questions??[],c=r.filter(e=>"table"===o(e.page_type)&&"string"==typeof e.id&&e.id.trim().length>0),l=r.filter(e=>"drawing"===o(e.page_type)&&"string"==typeof e.id&&e.id.trim().length>0);if(2===r.length&&1===c.length&&1===l.length){const i=c[0],n=l[0],r=((e,a,i,n)=>{const s=_(a),r=_(i),c=null!=s&&null!=r,o=[...s===t.YES?["table"]:[],...r===t.YES?["drawing"]:[]],l=1===o.length?o[0]:null,d="drawing"===o[0]?i:a;return{type:"page",confirmed:c,title:"Page Type Check",summary:e.summary?.trim()||void 0,format:"pdf",confidence:e.machine_classification?.confidence??a.machine_classification?.confidence??i.machine_classification?.confidence??null,decided_by:e.machine_classification?.decisioning_method??a.machine_classification?.decisioning_method??i.machine_classification?.decisioning_method??null,human_action_enum:null,reason:"Please check the type of this page.",reasons:e.reasons?.length?e.reasons:[...a.reasons??[],...i.reasons??[]],score:e.score??e.machine_classification?.score??a.score??a.machine_classification?.score??i.score??i.machine_classification?.score??null,review:c?{action:o.length>0?t.YES:t.NO,reviewed_by:d.human_action?.reviewed_by??"",reviewed_at:d.human_action?.reviewed_at??""}:null,metadata:{page_type:l,page_num:n,classification_id:null,type_choices:[{page_type:"table",classification_id:a.id},{page_type:"drawing",classification_id:i.id}],user_actions:["YES","NO"]}}})(e,i,n,s);return m.push({id:`${f}:page-classification-choice:${i.id}:${n.id}`,reviewStepIndex:h.length+y,segment:a,review_step:r,metadata:u(r.metadata)}),void(y+=1)}(r.length>0?r:e.severity?[e]:[]).forEach((t,r)=>{if(!o(t.page_type))return;const c=((e,a,t,n)=>{const s=o(e.page_type),r=e.human_action?.verdict?.trim().toUpperCase(),c=r&&i(r)?r:null,l="drawing"===s?"an engineering drawing":s?`a ${s}`:null;return{type:"page",confirmed:t,title:"Page Type Check",summary:n?.trim()||(c&&null!=a&&l?`Page ${a} was confirmed as ${"YES"===c?l:`not ${l}`}.`:void 0),format:"pdf",confidence:e.machine_classification?.confidence??null,decided_by:e.machine_classification?.decisioning_method??null,human_action_enum:null,reason:s?`We're not fully confident about the format of this page. Is this page a ${s}?`:null,reasons:e.reasons??[],score:e.score??e.machine_classification?.score??null,review:null==c?null:{action:c,reviewed_by:e.human_action?.reviewed_by??"",reviewed_at:e.human_action?.reviewed_at??""},metadata:{page_type:s,page_num:a,classification_id:e.id??null,user_actions:["YES","NO"]}}})(t,s,t.confirmed??e.confirmed??null,e.summary??null);m.push({id:`${f}:page-classification:${t.id??`${n}-${r}`}`,reviewStepIndex:h.length+y,segment:a,review_step:c,metadata:u(c.metadata)}),y+=1})})}),{boundaryReviews:s,labelReviews:p,pageReviews:m}};export{p as extractSegmentReviewData,l as getSegmentReviewKey};
|
|
2
2
|
//# sourceMappingURL=reviewStepAdapters.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reviewStepAdapters.js","sources":["../../../src/features/SegmentReviewComponents/reviewStepAdapters.ts"],"sourcesContent":["import type { BoundaryReviewAction, BoundaryReviewMetadata } from './BoundaryCard';\nimport { isBoundaryReviewAction } from './BoundaryCard';\nimport type { LabelReviewAction, LabelReviewMetadata } from './LabelCheck';\nimport { isLabelReviewAction } from './LabelCheck';\nimport type {\n PageCheckAction,\n PageCheckMetadata,\n PageCheckPageType,\n PageCheckTypeChoice,\n} from './PageCheck';\nimport { isPageCheckAction, PageCheckActionEnum } from './PageCheck';\n\nexport interface ReviewStepReview {\n action: BoundaryReviewAction | LabelReviewAction | PageCheckAction;\n reviewed_by: string;\n reviewed_at: string;\n}\n\nexport interface ReviewStepPerformedAction {\n action: string;\n performed_by: string;\n performed_at: string;\n human_revision: number;\n segment_version: number;\n change_summary: string | null;\n operation_id: string | null;\n}\n\nexport interface ReviewStepValueSnapshot {\n label?: string | null;\n type_id?: string | null;\n start_page?: number | null;\n end_page?: number | null;\n}\n\nexport interface ReviewStepHumanResolution {\n state: string;\n changed_by_human: boolean;\n changed_by: string | null;\n changed_at: string | null;\n human_revision: number;\n segment_version: number | null;\n action: string | null;\n change_summary: string | null;\n before: ReviewStepValueSnapshot | null;\n after: ReviewStepValueSnapshot | null;\n operation_id: string | null;\n}\n\nexport interface ReviewStepMetadata {\n focus_page?: number | null;\n boundary_margin?: number | null;\n current_label?: string | null;\n custom_label?: string | null;\n group_id?: string | null;\n page_type?: PageCheckPageType | null;\n page_num?: number | null;\n classification_id?: string | null;\n type_choices?: readonly PageCheckTypeChoice[];\n user_actions?: readonly string[];\n performed_actions?: readonly ReviewStepPerformedAction[];\n}\n\nexport interface ReviewStepSource {\n type: string;\n confirmed?: boolean | null;\n title?: string | null;\n question?: string | null;\n operation_id?: string | null;\n revert?: SegmentRevertInfo | null;\n format?: string | null;\n confidence?: string | null;\n summary?: string;\n decided_by?: string | null;\n human_action_enum?: string | null;\n llm_decision_awaited?: boolean | null;\n reason?: string | null;\n reasons?: readonly SegmentConfidenceReason[] | null;\n score?: string | number | null;\n gap?: string | null;\n details?: readonly string[];\n /** Object when reviewed; null while this individual check is pending. */\n review: ReviewStepReview | null;\n human_resolution?: ReviewStepHumanResolution | null;\n metadata?: ReviewStepMetadata | null;\n}\n\nexport interface SegmentConfidenceReason {\n text: string;\n type: string;\n}\n\nexport interface SegmentConfidence {\n level: string;\n summary: string;\n decided_by: string;\n awaiting_llm: boolean;\n classification_confidence: string | null;\n reasons: readonly SegmentConfidenceReason[];\n}\n\nexport interface SegmentReviewAction {\n focus_page: number | null;\n allowed_decisions: readonly string[];\n additional_decisions: Readonly<Record<string, readonly string[]>>\n}\n\nexport interface SegmentTimings {\n pages: number;\n total_ms: number;\n allocated: boolean;\n stage0_ms: number;\n stage1_ms: number;\n tables_ms: number;\n table_llm_ms: number;\n stage3_llm_ms: number;\n docai_tables_ms: number;\n}\n\nexport interface SegmentHumanActionLogEntry extends ReviewStepPerformedAction {\n step: string;\n before: ReviewStepValueSnapshot | null;\n after: ReviewStepValueSnapshot | null;\n}\n\nexport interface PageClassificationQuestionSource {\n id?: string | null;\n confirmed?: boolean | null;\n page_type?: string | null;\n severity?: string | null;\n score?: string | number | null;\n machine_classification?: {\n verdict?: string | null;\n confidence?: string | null;\n score?: string | number | null;\n decisioning_method?: string | null;\n } | null;\n human_action?: {\n verdict?: string | null;\n reviewed_by?: string | null;\n reviewed_at?: string | null;\n } | null;\n reasons?: readonly SegmentConfidenceReason[] | null;\n}\n\nexport interface PageClassificationSource extends PageClassificationQuestionSource {\n page_num?: number | null;\n page_image_url?: string | null;\n needs_type_choice?: boolean | null;\n ambiguity_reason?: string | null;\n summary?: string | null;\n questions?: readonly PageClassificationQuestionSource[];\n}\n\nexport interface SegmentRevertSnapshot {\n label?: string | null;\n title?: string | null;\n start_page: number;\n end_page: number;\n page_count?: number;\n segmentation_index?: number;\n stable_key: string;\n version?: number;\n type_id?: string | null;\n confidence?: string | null;\n status?: string | null;\n reviewed_by?: string | null;\n}\n\nexport interface SegmentRevertInfo {\n operation_id: string;\n type?: 'boundary' | 'label';\n decision: string;\n is_redo: boolean;\n performed_by: string;\n performed_at: string;\n revertable: boolean;\n blocked_reason?: string | null;\n summary?: string | null;\n state_hash?: string | null;\n current_segment_ids: readonly string[];\n previous_state: readonly SegmentRevertSnapshot[];\n}\n\nexport interface SegmentReviewSource {\n bundle_id?: string;\n run_id?: string;\n segmentation_index?: number;\n stable_key?: string;\n question?: string;\n segment_id?: string;\n version?: number;\n title: string;\n label?: string | null;\n category?: string | null;\n type_id?: string | null;\n start_page: number;\n end_page: number;\n page_count?: number;\n sensitivity?: string | null;\n status?: string;\n reviewed_by?: string | null;\n reviewed_at?: string | null;\n updated_at?: string | null;\n confidence?: SegmentConfidence | null;\n review_action?: SegmentReviewAction | null;\n ingest_mode?: string | null;\n segment_type?: string | null;\n special_tags?: readonly string[];\n table_pages?: readonly number[];\n tables_detected_count?: number;\n table_detection_confidence?: string | null;\n table_detection_confidence_reason?: string | null;\n drawing_pages?: readonly number[];\n drawings_detected_count?: number;\n drawing_detection_confidence?: string | null;\n drawing_detection_confidence_reason?: string | null;\n boundary_margin?: number | null;\n timings?: SegmentTimings | null;\n classification_method?: string | null;\n classification_confidence_reason?: string | null;\n matched_phrase?: string | null;\n runner_up_type_id?: string | null;\n runner_up_evidence?: string | null;\n segment_pdf_gs_url?: string | null;\n page_image_urls?: readonly string[];\n operation_id?: string | null;\n api_status?: string | null;\n revert?: SegmentRevertInfo | null;\n update_stage?: string | null;\n processing_updated_at?: string | null;\n provisional?: boolean;\n page_classifications?: readonly PageClassificationSource[];\n human_action_log?: readonly SegmentHumanActionLogEntry[];\n review_steps?: readonly ReviewStepSource[];\n segment_score?: string | number | null;\n}\n\nexport interface ExtractedBoundaryReview<TSegment extends SegmentReviewSource> {\n id: string;\n reviewStepIndex: number;\n segment: TSegment;\n review_step: ReviewStepSource;\n metadata: BoundaryReviewMetadata;\n human_resolution?: ReviewStepHumanResolution | null;\n}\n\nexport interface ExtractedLabelReview<TSegment extends SegmentReviewSource> {\n id: string;\n reviewStepIndex: number;\n segment: TSegment;\n review_step: ReviewStepSource;\n metadata: LabelReviewMetadata;\n}\n\nexport interface ExtractedPageReview<TSegment extends SegmentReviewSource> {\n id: string;\n reviewStepIndex: number;\n segment: TSegment;\n review_step: ReviewStepSource;\n metadata: PageCheckMetadata;\n}\n\nconst asRecord = (value: unknown): Record<string, unknown> =>\n typeof value === 'object' && value !== null\n ? value as Record<string, unknown>\n : {};\n\nconst asStringOrNull = (value: unknown): string | null =>\n typeof value === 'string' ? value : null;\n\nconst asNumberOrNull = (value: unknown): number | null =>\n typeof value === 'number' && Number.isFinite(value) ? value : null;\n\nconst asStringArray = (value: unknown): string[] =>\n Array.isArray(value)\n ? value.filter((item): item is string => typeof item === 'string')\n : [];\n\nconst asPageTypeOrNull = (value: unknown): PageCheckPageType | null => {\n const normalizedValue = typeof value === 'string'\n ? value.trim().toLowerCase()\n : '';\n\n return normalizedValue === 'table' || normalizedValue === 'drawing'\n ? normalizedValue\n : null;\n};\n\nexport const getSegmentReviewKey = (segment: SegmentReviewSource, index = 0) =>\n segment.stable_key ||\n segment.segment_id ||\n `${segment.start_page}-${segment.end_page}-${index}`;\n\nconst getReviewStepKind = (type: string): 'boundary' | 'label' | 'page' | null => {\n const normalizedType = type.trim().toLowerCase();\n\n if (normalizedType === 'page_boundary' || normalizedType === 'page boundary review') {\n return 'boundary';\n }\n\n if (normalizedType === 'label' || normalizedType === 'label review') {\n return 'label';\n }\n\n if (normalizedType === 'page') {\n return 'page';\n }\n\n return null;\n};\n\nconst getBoundaryMetadata = (value: unknown): BoundaryReviewMetadata => {\n const metadata = asRecord(value);\n return {\n focus_page: asNumberOrNull(metadata.focus_page),\n boundary_margin: asNumberOrNull(metadata.boundary_margin),\n user_actions: asStringArray(metadata.user_actions).filter(isBoundaryReviewAction),\n };\n};\n\nconst getLabelMetadata = (value: unknown): LabelReviewMetadata => {\n const metadata = asRecord(value);\n return {\n current_label: asStringOrNull(metadata.current_label),\n custom_label: asStringOrNull(metadata.custom_label),\n group_id: asStringOrNull(metadata.group_id),\n user_actions: asStringArray(metadata.user_actions).filter(isLabelReviewAction),\n };\n};\n\nconst getPageMetadata = (value: unknown): PageCheckMetadata => {\n const metadata = asRecord(value);\n const typeChoices = Array.isArray(metadata.type_choices)\n ? metadata.type_choices.flatMap<PageCheckTypeChoice>((value) => {\n const choice = asRecord(value);\n const pageType = asPageTypeOrNull(choice.page_type);\n const classificationId = asStringOrNull(choice.classification_id)?.trim();\n\n return pageType && classificationId\n ? [{ page_type: pageType, classification_id: classificationId }]\n : [];\n })\n : [];\n\n return {\n page_type: asPageTypeOrNull(metadata.page_type),\n page_num: asNumberOrNull(metadata.page_num),\n classification_id: asStringOrNull(metadata.classification_id),\n type_choices: typeChoices.length > 1 ? typeChoices : undefined,\n user_actions: asStringArray(metadata.user_actions).filter(isPageCheckAction),\n };\n};\n\nconst getQuestionAction = (question: PageClassificationQuestionSource) => {\n const action = question.human_action?.verdict?.trim().toUpperCase();\n return action && isPageCheckAction(action) ? action : null;\n};\n\nconst getCombinedPageTypeReviewStep = (\n classification: PageClassificationSource,\n tableQuestion: PageClassificationQuestionSource & { id: string },\n drawingQuestion: PageClassificationQuestionSource & { id: string },\n pageNum: number | null\n): ReviewStepSource => {\n const tableAction = getQuestionAction(tableQuestion);\n const drawingAction = getQuestionAction(drawingQuestion);\n const isResolved = tableAction != null && drawingAction != null;\n const selectedPageTypes: PageCheckPageType[] = [\n ...(tableAction === PageCheckActionEnum.YES ? ['table' as const] : []),\n ...(drawingAction === PageCheckActionEnum.YES ? ['drawing' as const] : []),\n ];\n const selectedPageType = selectedPageTypes.length === 1 ? selectedPageTypes[0] : null;\n const selectedQuestion = selectedPageTypes[0] === 'drawing'\n ? drawingQuestion\n : tableQuestion;\n\n return {\n type: 'page',\n confirmed: isResolved,\n title: 'Page Type Check',\n summary: classification.summary?.trim() || undefined,\n format: 'pdf',\n confidence: classification.machine_classification?.confidence ??\n tableQuestion.machine_classification?.confidence ??\n drawingQuestion.machine_classification?.confidence ??\n null,\n decided_by: classification.machine_classification?.decisioning_method ??\n tableQuestion.machine_classification?.decisioning_method ??\n drawingQuestion.machine_classification?.decisioning_method ??\n null,\n human_action_enum: null,\n reason: 'Please check the type of this page.',\n reasons: classification.reasons?.length\n ? classification.reasons\n : [...(tableQuestion.reasons ?? []), ...(drawingQuestion.reasons ?? [])],\n score: classification.score ??\n classification.machine_classification?.score ??\n tableQuestion.score ??\n tableQuestion.machine_classification?.score ??\n drawingQuestion.score ??\n drawingQuestion.machine_classification?.score ??\n null,\n review: !isResolved\n ? null\n : {\n action: selectedPageTypes.length > 0\n ? PageCheckActionEnum.YES\n : PageCheckActionEnum.NO,\n reviewed_by: selectedQuestion.human_action?.reviewed_by ?? '',\n reviewed_at: selectedQuestion.human_action?.reviewed_at ?? '',\n },\n metadata: {\n page_type: selectedPageType,\n page_num: pageNum,\n classification_id: null,\n type_choices: [\n { page_type: 'table', classification_id: tableQuestion.id },\n { page_type: 'drawing', classification_id: drawingQuestion.id },\n ],\n user_actions: ['YES', 'NO'],\n },\n };\n};\n\nconst getPageReviewStepFromClassification = (\n classification: PageClassificationQuestionSource,\n pageNum: number | null,\n confirmed: boolean | null,\n summary: string | null\n): ReviewStepSource => {\n const pageType = asPageTypeOrNull(classification.page_type);\n const humanVerdict = classification.human_action?.verdict?.trim().toUpperCase();\n const reviewAction = humanVerdict && isPageCheckAction(humanVerdict)\n ? humanVerdict\n : null;\n const reviewedPageType = pageType === 'drawing'\n ? 'an engineering drawing'\n : pageType\n ? `a ${pageType}`\n : null;\n const reviewSummary = summary?.trim() || (\n reviewAction && pageNum != null && reviewedPageType\n ? `Page ${pageNum} was confirmed as ${reviewAction === 'YES' ? reviewedPageType : `not ${reviewedPageType}`}.`\n : undefined\n );\n\n return {\n type: 'page',\n confirmed,\n title: 'Page Type Check',\n summary: reviewSummary,\n format: 'pdf',\n confidence: classification.machine_classification?.confidence ?? null,\n decided_by: classification.machine_classification?.decisioning_method ?? null,\n human_action_enum: null,\n reason: pageType\n ? `We're not fully confident about the type of this page. Is this page a ${pageType}?`\n : null,\n reasons: classification.reasons ?? [],\n score: classification.score ?? classification.machine_classification?.score ?? null,\n review: reviewAction == null\n ? null\n : {\n action: reviewAction,\n reviewed_by: classification.human_action?.reviewed_by ?? '',\n reviewed_at: classification.human_action?.reviewed_at ?? '',\n },\n metadata: {\n page_type: pageType,\n page_num: pageNum,\n classification_id: classification.id ?? null,\n user_actions: ['YES', 'NO'],\n },\n };\n};\n\n/** Converts backend-shaped segments into card-ready boundary, label, and page reviews. */\nexport const extractSegmentReviewData = <TSegment extends SegmentReviewSource>(\n segments: readonly TSegment[]\n) => {\n const boundaryReviews: ExtractedBoundaryReview<TSegment>[] = [];\n const labelReviews: ExtractedLabelReview<TSegment>[] = [];\n const pageReviews: ExtractedPageReview<TSegment>[] = [];\n\n segments.forEach((segment, segmentIndex) => {\n const segmentKey = getSegmentReviewKey(segment, segmentIndex);\n\n const reviewSteps = segment.review_steps ?? [];\n\n reviewSteps.forEach((step, stepIndex) => {\n const reviewStepKind = getReviewStepKind(step.type);\n\n if (reviewStepKind === 'boundary') {\n const metadata = getBoundaryMetadata(step.metadata);\n boundaryReviews.push({\n id: `${segmentKey}:boundary:${stepIndex}`,\n reviewStepIndex: stepIndex,\n segment,\n review_step: step,\n metadata,\n });\n }\n\n if (reviewStepKind === 'label') {\n labelReviews.push({\n id: `${segmentKey}:label:${stepIndex}`,\n reviewStepIndex: stepIndex,\n segment,\n review_step: step,\n metadata: getLabelMetadata(step.metadata),\n });\n }\n\n if (reviewStepKind === 'page') {\n pageReviews.push({\n id: `${segmentKey}:page:${stepIndex}`,\n reviewStepIndex: stepIndex,\n segment,\n review_step: step,\n metadata: getPageMetadata(step.metadata),\n });\n }\n });\n\n let pageReviewIndex = 0;\n segment.page_classifications?.forEach((classification, classificationIndex) => {\n const pageNum = classification.page_num ?? null;\n const questions = classification.questions ?? [];\n const tableQuestions = questions.filter(\n (question): question is PageClassificationQuestionSource & { id: string } =>\n asPageTypeOrNull(question.page_type) === 'table' &&\n typeof question.id === 'string' &&\n question.id.trim().length > 0\n );\n const drawingQuestions = questions.filter(\n (question): question is PageClassificationQuestionSource & { id: string } =>\n asPageTypeOrNull(question.page_type) === 'drawing' &&\n typeof question.id === 'string' &&\n question.id.trim().length > 0\n );\n const isCombinedTypeChoice = questions.length === 2 &&\n tableQuestions.length === 1 &&\n drawingQuestions.length === 1;\n\n if (isCombinedTypeChoice) {\n const tableQuestion = tableQuestions[0];\n const drawingQuestion = drawingQuestions[0];\n const reviewStep = getCombinedPageTypeReviewStep(\n classification,\n tableQuestion,\n drawingQuestion,\n pageNum\n );\n\n pageReviews.push({\n id: `${segmentKey}:page-classification-choice:${tableQuestion.id}:${drawingQuestion.id}`,\n reviewStepIndex: reviewSteps.length + pageReviewIndex,\n segment,\n review_step: reviewStep,\n metadata: getPageMetadata(reviewStep.metadata),\n });\n pageReviewIndex += 1;\n return;\n }\n\n const reviewSources = questions.length > 0\n ? questions\n : classification.severity\n ? [classification]\n : [];\n\n reviewSources.forEach((reviewSource, questionIndex) => {\n if (!asPageTypeOrNull(reviewSource.page_type)) return;\n\n const reviewStep = getPageReviewStepFromClassification(\n reviewSource,\n pageNum,\n reviewSource.confirmed ?? classification.confirmed ?? null,\n classification.summary ?? null\n );\n pageReviews.push({\n id: `${segmentKey}:page-classification:${reviewSource.id ?? `${classificationIndex}-${questionIndex}`}`,\n reviewStepIndex: reviewSteps.length + pageReviewIndex,\n segment,\n review_step: reviewStep,\n metadata: getPageMetadata(reviewStep.metadata),\n });\n pageReviewIndex += 1;\n });\n });\n });\n\n return { boundaryReviews, labelReviews, pageReviews };\n};\n"],"names":["asRecord","value","asStringOrNull","asNumberOrNull","Number","isFinite","asStringArray","Array","isArray","filter","item","asPageTypeOrNull","normalizedValue","trim","toLowerCase","getSegmentReviewKey","segment","index","stable_key","segment_id","start_page","end_page","getLabelMetadata","metadata","current_label","custom_label","group_id","user_actions","isLabelReviewAction","getPageMetadata","typeChoices","type_choices","flatMap","choice","pageType","page_type","classificationId","classification_id","page_num","length","isPageCheckAction","getQuestionAction","question","action","human_action","verdict","toUpperCase","extractSegmentReviewData","segments","boundaryReviews","labelReviews","pageReviews","forEach","segmentIndex","segmentKey","reviewSteps","review_steps","step","stepIndex","reviewStepKind","type","normalizedType","getReviewStepKind","focus_page","boundary_margin","isBoundaryReviewAction","getBoundaryMetadata","push","id","reviewStepIndex","review_step","pageReviewIndex","page_classifications","classification","classificationIndex","pageNum","questions","tableQuestions","drawingQuestions","tableQuestion","drawingQuestion","reviewStep","tableAction","drawingAction","isResolved","selectedPageTypes","PageCheckActionEnum","YES","selectedPageType","selectedQuestion","confirmed","title","summary","format","confidence","machine_classification","decided_by","decisioning_method","human_action_enum","reason","reasons","score","review","NO","reviewed_by","reviewed_at","getCombinedPageTypeReviewStep","severity","reviewSource","questionIndex","humanVerdict","reviewAction","reviewedPageType","getPageReviewStepFromClassification"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"reviewStepAdapters.js","sources":["../../../src/features/SegmentReviewComponents/reviewStepAdapters.ts"],"sourcesContent":["import type { BoundaryReviewAction, BoundaryReviewMetadata } from './BoundaryCard';\nimport { isBoundaryReviewAction } from './BoundaryCard';\nimport type { LabelReviewAction, LabelReviewMetadata } from './LabelCheck';\nimport { isLabelReviewAction } from './LabelCheck';\nimport type {\n PageCheckAction,\n PageCheckMetadata,\n PageCheckPageType,\n PageCheckTypeChoice,\n} from './PageCheck';\nimport { isPageCheckAction, PageCheckActionEnum } from './PageCheck';\n\nexport interface ReviewStepReview {\n action: BoundaryReviewAction | LabelReviewAction | PageCheckAction;\n reviewed_by: string;\n reviewed_at: string;\n}\n\nexport interface ReviewStepPerformedAction {\n action: string;\n performed_by: string;\n performed_at: string;\n human_revision: number;\n segment_version: number;\n change_summary: string | null;\n operation_id: string | null;\n}\n\nexport interface ReviewStepValueSnapshot {\n label?: string | null;\n type_id?: string | null;\n start_page?: number | null;\n end_page?: number | null;\n}\n\nexport interface ReviewStepHumanResolution {\n state: string;\n changed_by_human: boolean;\n changed_by: string | null;\n changed_at: string | null;\n human_revision: number;\n segment_version: number | null;\n action: string | null;\n change_summary: string | null;\n before: ReviewStepValueSnapshot | null;\n after: ReviewStepValueSnapshot | null;\n operation_id: string | null;\n}\n\nexport interface ReviewStepMetadata {\n focus_page?: number | null;\n boundary_margin?: number | null;\n current_label?: string | null;\n custom_label?: string | null;\n group_id?: string | null;\n page_type?: PageCheckPageType | null;\n page_num?: number | null;\n classification_id?: string | null;\n type_choices?: readonly PageCheckTypeChoice[];\n user_actions?: readonly string[];\n performed_actions?: readonly ReviewStepPerformedAction[];\n}\n\nexport interface ReviewStepSource {\n type: string;\n confirmed?: boolean | null;\n title?: string | null;\n question?: string | null;\n operation_id?: string | null;\n revert?: SegmentRevertInfo | null;\n format?: string | null;\n confidence?: string | null;\n summary?: string;\n decided_by?: string | null;\n human_action_enum?: string | null;\n llm_decision_awaited?: boolean | null;\n reason?: string | null;\n reasons?: readonly SegmentConfidenceReason[] | null;\n score?: string | number | null;\n gap?: string | null;\n details?: readonly string[];\n /** Object when reviewed; null while this individual check is pending. */\n review: ReviewStepReview | null;\n human_resolution?: ReviewStepHumanResolution | null;\n metadata?: ReviewStepMetadata | null;\n}\n\nexport interface SegmentConfidenceReason {\n text: string;\n type: string;\n}\n\nexport interface SegmentConfidence {\n level: string;\n summary: string;\n decided_by: string;\n awaiting_llm: boolean;\n classification_confidence: string | null;\n reasons: readonly SegmentConfidenceReason[];\n}\n\nexport interface SegmentReviewAction {\n focus_page: number | null;\n allowed_decisions: readonly string[];\n additional_decisions: Readonly<Record<string, readonly string[]>>\n}\n\nexport interface SegmentTimings {\n pages: number;\n total_ms: number;\n allocated: boolean;\n stage0_ms: number;\n stage1_ms: number;\n tables_ms: number;\n table_llm_ms: number;\n stage3_llm_ms: number;\n docai_tables_ms: number;\n}\n\nexport interface SegmentHumanActionLogEntry extends ReviewStepPerformedAction {\n step: string;\n before: ReviewStepValueSnapshot | null;\n after: ReviewStepValueSnapshot | null;\n}\n\nexport interface PageClassificationQuestionSource {\n id?: string | null;\n confirmed?: boolean | null;\n page_type?: string | null;\n severity?: string | null;\n score?: string | number | null;\n machine_classification?: {\n verdict?: string | null;\n confidence?: string | null;\n score?: string | number | null;\n decisioning_method?: string | null;\n } | null;\n human_action?: {\n verdict?: string | null;\n reviewed_by?: string | null;\n reviewed_at?: string | null;\n } | null;\n reasons?: readonly SegmentConfidenceReason[] | null;\n}\n\nexport interface PageClassificationSource extends PageClassificationQuestionSource {\n page_num?: number | null;\n page_image_url?: string | null;\n needs_type_choice?: boolean | null;\n ambiguity_reason?: string | null;\n summary?: string | null;\n questions?: readonly PageClassificationQuestionSource[];\n}\n\nexport interface SegmentRevertSnapshot {\n label?: string | null;\n title?: string | null;\n start_page: number;\n end_page: number;\n page_count?: number;\n segmentation_index?: number;\n stable_key: string;\n version?: number;\n type_id?: string | null;\n confidence?: string | null;\n status?: string | null;\n reviewed_by?: string | null;\n}\n\nexport interface SegmentRevertInfo {\n operation_id: string;\n type?: 'boundary' | 'label';\n decision: string;\n is_redo: boolean;\n performed_by: string;\n performed_at: string;\n revertable: boolean;\n blocked_reason?: string | null;\n summary?: string | null;\n state_hash?: string | null;\n current_segment_ids: readonly string[];\n previous_state: readonly SegmentRevertSnapshot[];\n}\n\nexport interface SegmentReviewSource {\n bundle_id?: string;\n run_id?: string;\n segmentation_index?: number;\n stable_key?: string;\n question?: string;\n segment_id?: string;\n version?: number;\n title: string;\n label?: string | null;\n category?: string | null;\n type_id?: string | null;\n start_page: number;\n end_page: number;\n page_count?: number;\n sensitivity?: string | null;\n status?: string;\n reviewed_by?: string | null;\n reviewed_at?: string | null;\n updated_at?: string | null;\n confidence?: SegmentConfidence | null;\n review_action?: SegmentReviewAction | null;\n ingest_mode?: string | null;\n segment_type?: string | null;\n special_tags?: readonly string[];\n table_pages?: readonly number[];\n tables_detected_count?: number;\n table_detection_confidence?: string | null;\n table_detection_confidence_reason?: string | null;\n drawing_pages?: readonly number[];\n drawings_detected_count?: number;\n drawing_detection_confidence?: string | null;\n drawing_detection_confidence_reason?: string | null;\n boundary_margin?: number | null;\n timings?: SegmentTimings | null;\n classification_method?: string | null;\n classification_confidence_reason?: string | null;\n matched_phrase?: string | null;\n runner_up_type_id?: string | null;\n runner_up_evidence?: string | null;\n segment_pdf_gs_url?: string | null;\n page_image_urls?: readonly string[];\n operation_id?: string | null;\n api_status?: string | null;\n revert?: SegmentRevertInfo | null;\n update_stage?: string | null;\n processing_updated_at?: string | null;\n provisional?: boolean;\n page_classifications?: readonly PageClassificationSource[];\n human_action_log?: readonly SegmentHumanActionLogEntry[];\n review_steps?: readonly ReviewStepSource[];\n segment_score?: string | number | null;\n}\n\nexport interface ExtractedBoundaryReview<TSegment extends SegmentReviewSource> {\n id: string;\n reviewStepIndex: number;\n segment: TSegment;\n review_step: ReviewStepSource;\n metadata: BoundaryReviewMetadata;\n human_resolution?: ReviewStepHumanResolution | null;\n}\n\nexport interface ExtractedLabelReview<TSegment extends SegmentReviewSource> {\n id: string;\n reviewStepIndex: number;\n segment: TSegment;\n review_step: ReviewStepSource;\n metadata: LabelReviewMetadata;\n}\n\nexport interface ExtractedPageReview<TSegment extends SegmentReviewSource> {\n id: string;\n reviewStepIndex: number;\n segment: TSegment;\n review_step: ReviewStepSource;\n metadata: PageCheckMetadata;\n}\n\nconst asRecord = (value: unknown): Record<string, unknown> =>\n typeof value === 'object' && value !== null\n ? value as Record<string, unknown>\n : {};\n\nconst asStringOrNull = (value: unknown): string | null =>\n typeof value === 'string' ? value : null;\n\nconst asNumberOrNull = (value: unknown): number | null =>\n typeof value === 'number' && Number.isFinite(value) ? value : null;\n\nconst asStringArray = (value: unknown): string[] =>\n Array.isArray(value)\n ? value.filter((item): item is string => typeof item === 'string')\n : [];\n\nconst asPageTypeOrNull = (value: unknown): PageCheckPageType | null => {\n const normalizedValue = typeof value === 'string'\n ? value.trim().toLowerCase()\n : '';\n\n return normalizedValue === 'table' || normalizedValue === 'drawing'\n ? normalizedValue\n : null;\n};\n\nexport const getSegmentReviewKey = (segment: SegmentReviewSource, index = 0) =>\n segment.stable_key ||\n segment.segment_id ||\n `${segment.start_page}-${segment.end_page}-${index}`;\n\nconst getReviewStepKind = (type: string): 'boundary' | 'label' | 'page' | null => {\n const normalizedType = type.trim().toLowerCase();\n\n if (normalizedType === 'page_boundary' || normalizedType === 'page boundary review') {\n return 'boundary';\n }\n\n if (normalizedType === 'label' || normalizedType === 'label review') {\n return 'label';\n }\n\n if (normalizedType === 'page') {\n return 'page';\n }\n\n return null;\n};\n\nconst getBoundaryMetadata = (value: unknown): BoundaryReviewMetadata => {\n const metadata = asRecord(value);\n return {\n focus_page: asNumberOrNull(metadata.focus_page),\n boundary_margin: asNumberOrNull(metadata.boundary_margin),\n user_actions: asStringArray(metadata.user_actions).filter(isBoundaryReviewAction),\n };\n};\n\nconst getLabelMetadata = (value: unknown): LabelReviewMetadata => {\n const metadata = asRecord(value);\n return {\n current_label: asStringOrNull(metadata.current_label),\n custom_label: asStringOrNull(metadata.custom_label),\n group_id: asStringOrNull(metadata.group_id),\n user_actions: asStringArray(metadata.user_actions).filter(isLabelReviewAction),\n };\n};\n\nconst getPageMetadata = (value: unknown): PageCheckMetadata => {\n const metadata = asRecord(value);\n const typeChoices = Array.isArray(metadata.type_choices)\n ? metadata.type_choices.flatMap<PageCheckTypeChoice>((value) => {\n const choice = asRecord(value);\n const pageType = asPageTypeOrNull(choice.page_type);\n const classificationId = asStringOrNull(choice.classification_id)?.trim();\n\n return pageType && classificationId\n ? [{ page_type: pageType, classification_id: classificationId }]\n : [];\n })\n : [];\n\n return {\n page_type: asPageTypeOrNull(metadata.page_type),\n page_num: asNumberOrNull(metadata.page_num),\n classification_id: asStringOrNull(metadata.classification_id),\n type_choices: typeChoices.length > 1 ? typeChoices : undefined,\n user_actions: asStringArray(metadata.user_actions).filter(isPageCheckAction),\n };\n};\n\nconst getQuestionAction = (question: PageClassificationQuestionSource) => {\n const action = question.human_action?.verdict?.trim().toUpperCase();\n return action && isPageCheckAction(action) ? action : null;\n};\n\nconst getCombinedPageTypeReviewStep = (\n classification: PageClassificationSource,\n tableQuestion: PageClassificationQuestionSource & { id: string },\n drawingQuestion: PageClassificationQuestionSource & { id: string },\n pageNum: number | null\n): ReviewStepSource => {\n const tableAction = getQuestionAction(tableQuestion);\n const drawingAction = getQuestionAction(drawingQuestion);\n const isResolved = tableAction != null && drawingAction != null;\n const selectedPageTypes: PageCheckPageType[] = [\n ...(tableAction === PageCheckActionEnum.YES ? ['table' as const] : []),\n ...(drawingAction === PageCheckActionEnum.YES ? ['drawing' as const] : []),\n ];\n const selectedPageType = selectedPageTypes.length === 1 ? selectedPageTypes[0] : null;\n const selectedQuestion = selectedPageTypes[0] === 'drawing'\n ? drawingQuestion\n : tableQuestion;\n\n return {\n type: 'page',\n confirmed: isResolved,\n title: 'Page Type Check',\n summary: classification.summary?.trim() || undefined,\n format: 'pdf',\n confidence: classification.machine_classification?.confidence ??\n tableQuestion.machine_classification?.confidence ??\n drawingQuestion.machine_classification?.confidence ??\n null,\n decided_by: classification.machine_classification?.decisioning_method ??\n tableQuestion.machine_classification?.decisioning_method ??\n drawingQuestion.machine_classification?.decisioning_method ??\n null,\n human_action_enum: null,\n reason: 'Please check the type of this page.',\n reasons: classification.reasons?.length\n ? classification.reasons\n : [...(tableQuestion.reasons ?? []), ...(drawingQuestion.reasons ?? [])],\n score: classification.score ??\n classification.machine_classification?.score ??\n tableQuestion.score ??\n tableQuestion.machine_classification?.score ??\n drawingQuestion.score ??\n drawingQuestion.machine_classification?.score ??\n null,\n review: !isResolved\n ? null\n : {\n action: selectedPageTypes.length > 0\n ? PageCheckActionEnum.YES\n : PageCheckActionEnum.NO,\n reviewed_by: selectedQuestion.human_action?.reviewed_by ?? '',\n reviewed_at: selectedQuestion.human_action?.reviewed_at ?? '',\n },\n metadata: {\n page_type: selectedPageType,\n page_num: pageNum,\n classification_id: null,\n type_choices: [\n { page_type: 'table', classification_id: tableQuestion.id },\n { page_type: 'drawing', classification_id: drawingQuestion.id },\n ],\n user_actions: ['YES', 'NO'],\n },\n };\n};\n\nconst getPageReviewStepFromClassification = (\n classification: PageClassificationQuestionSource,\n pageNum: number | null,\n confirmed: boolean | null,\n summary: string | null\n): ReviewStepSource => {\n const pageType = asPageTypeOrNull(classification.page_type);\n const humanVerdict = classification.human_action?.verdict?.trim().toUpperCase();\n const reviewAction = humanVerdict && isPageCheckAction(humanVerdict)\n ? humanVerdict\n : null;\n const reviewedPageType = pageType === 'drawing'\n ? 'an engineering drawing'\n : pageType\n ? `a ${pageType}`\n : null;\n const reviewSummary = summary?.trim() || (\n reviewAction && pageNum != null && reviewedPageType\n ? `Page ${pageNum} was confirmed as ${reviewAction === 'YES' ? reviewedPageType : `not ${reviewedPageType}`}.`\n : undefined\n );\n\n return {\n type: 'page',\n confirmed,\n title: 'Page Type Check',\n summary: reviewSummary,\n format: 'pdf',\n confidence: classification.machine_classification?.confidence ?? null,\n decided_by: classification.machine_classification?.decisioning_method ?? null,\n human_action_enum: null,\n reason: pageType\n ? `We're not fully confident about the format of this page. Is this page a ${pageType}?`\n : null,\n reasons: classification.reasons ?? [],\n score: classification.score ?? classification.machine_classification?.score ?? null,\n review: reviewAction == null\n ? null\n : {\n action: reviewAction,\n reviewed_by: classification.human_action?.reviewed_by ?? '',\n reviewed_at: classification.human_action?.reviewed_at ?? '',\n },\n metadata: {\n page_type: pageType,\n page_num: pageNum,\n classification_id: classification.id ?? null,\n user_actions: ['YES', 'NO'],\n },\n };\n};\n\n/** Converts backend-shaped segments into card-ready boundary, label, and page reviews. */\nexport const extractSegmentReviewData = <TSegment extends SegmentReviewSource>(\n segments: readonly TSegment[]\n) => {\n const boundaryReviews: ExtractedBoundaryReview<TSegment>[] = [];\n const labelReviews: ExtractedLabelReview<TSegment>[] = [];\n const pageReviews: ExtractedPageReview<TSegment>[] = [];\n\n segments.forEach((segment, segmentIndex) => {\n const segmentKey = getSegmentReviewKey(segment, segmentIndex);\n\n const reviewSteps = segment.review_steps ?? [];\n\n reviewSteps.forEach((step, stepIndex) => {\n const reviewStepKind = getReviewStepKind(step.type);\n\n if (reviewStepKind === 'boundary') {\n const metadata = getBoundaryMetadata(step.metadata);\n boundaryReviews.push({\n id: `${segmentKey}:boundary:${stepIndex}`,\n reviewStepIndex: stepIndex,\n segment,\n review_step: step,\n metadata,\n });\n }\n\n if (reviewStepKind === 'label') {\n labelReviews.push({\n id: `${segmentKey}:label:${stepIndex}`,\n reviewStepIndex: stepIndex,\n segment,\n review_step: step,\n metadata: getLabelMetadata(step.metadata),\n });\n }\n\n if (reviewStepKind === 'page') {\n pageReviews.push({\n id: `${segmentKey}:page:${stepIndex}`,\n reviewStepIndex: stepIndex,\n segment,\n review_step: step,\n metadata: getPageMetadata(step.metadata),\n });\n }\n });\n\n let pageReviewIndex = 0;\n segment.page_classifications?.forEach((classification, classificationIndex) => {\n const pageNum = classification.page_num ?? null;\n const questions = classification.questions ?? [];\n const tableQuestions = questions.filter(\n (question): question is PageClassificationQuestionSource & { id: string } =>\n asPageTypeOrNull(question.page_type) === 'table' &&\n typeof question.id === 'string' &&\n question.id.trim().length > 0\n );\n const drawingQuestions = questions.filter(\n (question): question is PageClassificationQuestionSource & { id: string } =>\n asPageTypeOrNull(question.page_type) === 'drawing' &&\n typeof question.id === 'string' &&\n question.id.trim().length > 0\n );\n const isCombinedTypeChoice = questions.length === 2 &&\n tableQuestions.length === 1 &&\n drawingQuestions.length === 1;\n\n if (isCombinedTypeChoice) {\n const tableQuestion = tableQuestions[0];\n const drawingQuestion = drawingQuestions[0];\n const reviewStep = getCombinedPageTypeReviewStep(\n classification,\n tableQuestion,\n drawingQuestion,\n pageNum\n );\n\n pageReviews.push({\n id: `${segmentKey}:page-classification-choice:${tableQuestion.id}:${drawingQuestion.id}`,\n reviewStepIndex: reviewSteps.length + pageReviewIndex,\n segment,\n review_step: reviewStep,\n metadata: getPageMetadata(reviewStep.metadata),\n });\n pageReviewIndex += 1;\n return;\n }\n\n const reviewSources = questions.length > 0\n ? questions\n : classification.severity\n ? [classification]\n : [];\n\n reviewSources.forEach((reviewSource, questionIndex) => {\n if (!asPageTypeOrNull(reviewSource.page_type)) return;\n\n const reviewStep = getPageReviewStepFromClassification(\n reviewSource,\n pageNum,\n reviewSource.confirmed ?? classification.confirmed ?? null,\n classification.summary ?? null\n );\n pageReviews.push({\n id: `${segmentKey}:page-classification:${reviewSource.id ?? `${classificationIndex}-${questionIndex}`}`,\n reviewStepIndex: reviewSteps.length + pageReviewIndex,\n segment,\n review_step: reviewStep,\n metadata: getPageMetadata(reviewStep.metadata),\n });\n pageReviewIndex += 1;\n });\n });\n });\n\n return { boundaryReviews, labelReviews, pageReviews };\n};\n"],"names":["asRecord","value","asStringOrNull","asNumberOrNull","Number","isFinite","asStringArray","Array","isArray","filter","item","asPageTypeOrNull","normalizedValue","trim","toLowerCase","getSegmentReviewKey","segment","index","stable_key","segment_id","start_page","end_page","getLabelMetadata","metadata","current_label","custom_label","group_id","user_actions","isLabelReviewAction","getPageMetadata","typeChoices","type_choices","flatMap","choice","pageType","page_type","classificationId","classification_id","page_num","length","isPageCheckAction","getQuestionAction","question","action","human_action","verdict","toUpperCase","extractSegmentReviewData","segments","boundaryReviews","labelReviews","pageReviews","forEach","segmentIndex","segmentKey","reviewSteps","review_steps","step","stepIndex","reviewStepKind","type","normalizedType","getReviewStepKind","focus_page","boundary_margin","isBoundaryReviewAction","getBoundaryMetadata","push","id","reviewStepIndex","review_step","pageReviewIndex","page_classifications","classification","classificationIndex","pageNum","questions","tableQuestions","drawingQuestions","tableQuestion","drawingQuestion","reviewStep","tableAction","drawingAction","isResolved","selectedPageTypes","PageCheckActionEnum","YES","selectedPageType","selectedQuestion","confirmed","title","summary","format","confidence","machine_classification","decided_by","decisioning_method","human_action_enum","reason","reasons","score","review","NO","reviewed_by","reviewed_at","getCombinedPageTypeReviewStep","severity","reviewSource","questionIndex","humanVerdict","reviewAction","reviewedPageType","getPageReviewStepFromClassification"],"mappings":"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"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import React, { CSSProperties } from "react";
|
|
2
|
-
import type { OnDemandCitationContext } from "./CognitiveCompareTypes";
|
|
3
2
|
interface CitationAnchorProps {
|
|
4
3
|
href: string;
|
|
5
4
|
children: any;
|
|
@@ -25,7 +24,6 @@ interface CitationAnchorProps {
|
|
|
25
24
|
defaultState?: boolean;
|
|
26
25
|
metaData?: any;
|
|
27
26
|
onFullscreenChange?: (isFullscreen: boolean) => void;
|
|
28
|
-
onDemandCitationContext?: OnDemandCitationContext;
|
|
29
27
|
}
|
|
30
28
|
declare const CitationAnchor: React.FC<CitationAnchorProps>;
|
|
31
29
|
export default CitationAnchor;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CitationAnchor.d.ts","sourceRoot":"","sources":["../../../../src/features/CognitiveCompare/CitationAnchor.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CitationAnchor.d.ts","sourceRoot":"","sources":["../../../../src/features/CognitiveCompare/CitationAnchor.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,EACV,aAAa,EAKhB,MAAM,OAAO,CAAC;AAcf,UAAU,mBAAmB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,GAAG,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACrC,oBAAoB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvC,WAAW,CAAC,EAAE;QACV,qBAAqB,CAAC,EAAE,aAAa,CAAC;QACtC,KAAK,CAAC,EAAE,aAAa,CAAC;QACtB,cAAc,CAAC,EAAE,aAAa,CAAC;QAC/B,iBAAiB,CAAC,EAAE,aAAa,CAAC;QAClC,UAAU,CAAC,EAAE,aAAa,CAAC;QAC3B,QAAQ,CAAC,EAAE,aAAa,CAAC;QACzB,SAAS,CAAC,EAAE,aAAa,CAAC;QAC1B,eAAe,CAAC,EAAE,aAAa,CAAC;QAChC,eAAe,CAAC,EAAE,aAAa,CAAC;QAChC,mBAAmB,CAAC,EAAE,aAAa,CAAC;QACpC,eAAe,CAAC,EAAE,aAAa,CAAC;QAChC,oBAAoB,CAAC,EAAE,aAAa,CAAC;QACrC,eAAe,CAAC,EAAE,aAAa,CAAC;KACnC,CAAC;IACF,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,GAAG,CAAC;IACf,kBAAkB,CAAC,EAAE,CAAC,YAAY,EAAE,OAAO,KAAK,IAAI,CAAC;CACxD;AAucD,QAAA,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAwNjD,CAAC;AAEF,eAAe,cAAc,CAAC"}
|