@e-llm-studio/citation 0.0.253 → 0.0.254
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/ChatDrawer/ChatDrawer.js +1 -1
- package/dist/cjs/features/ChatDrawer/ChatDrawer.js.map +1 -1
- package/dist/cjs/features/IngestionStatus/IngestionStatusComponent.js +1 -1
- package/dist/cjs/features/IngestionStatus/IngestionStatusComponent.js.map +1 -1
- package/dist/cjs/features/IngestionStatus/useIngestionStatus.js +1 -1
- package/dist/cjs/features/IngestionStatus/useIngestionStatus.js.map +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/usePdfHighlight.js +1 -1
- package/dist/cjs/features/PdfViewer/usePdfHighlight.js.map +1 -1
- package/dist/cjs/features/SegmentReviewComponents/CognitiveIntegrity.js +1 -1
- package/dist/cjs/features/SegmentReviewComponents/CognitiveIntegrity.js.map +1 -1
- package/dist/cjs/features/SegmentReviewComponents/SaveAsLearningCard.js +1 -1
- package/dist/cjs/features/SegmentReviewComponents/SaveAsLearningCard.js.map +1 -1
- package/dist/cjs/features/SegmentReviewComponents/SegmentReviewPdfWrapper.js +1 -1
- package/dist/cjs/features/SegmentReviewComponents/SegmentReviewPdfWrapper.js.map +1 -1
- package/dist/features/ChatDrawer/ChatDrawer.js +1 -1
- package/dist/features/ChatDrawer/ChatDrawer.js.map +1 -1
- package/dist/features/IngestionStatus/IngestionStatusComponent.js +1 -1
- package/dist/features/IngestionStatus/IngestionStatusComponent.js.map +1 -1
- package/dist/features/IngestionStatus/useIngestionStatus.js +1 -1
- package/dist/features/IngestionStatus/useIngestionStatus.js.map +1 -1
- package/dist/features/PdfViewer/PdfViewer.js +1 -1
- package/dist/features/PdfViewer/PdfViewer.js.map +1 -1
- package/dist/features/PdfViewer/usePdfHighlight.js +1 -1
- package/dist/features/PdfViewer/usePdfHighlight.js.map +1 -1
- package/dist/features/SegmentReviewComponents/CognitiveIntegrity.js +1 -1
- package/dist/features/SegmentReviewComponents/CognitiveIntegrity.js.map +1 -1
- package/dist/features/SegmentReviewComponents/SaveAsLearningCard.js +1 -1
- package/dist/features/SegmentReviewComponents/SaveAsLearningCard.js.map +1 -1
- package/dist/features/SegmentReviewComponents/SegmentReviewPdfWrapper.js +1 -1
- package/dist/features/SegmentReviewComponents/SegmentReviewPdfWrapper.js.map +1 -1
- package/dist/types/features/ChatDrawer/ChatDrawer.d.ts.map +1 -1
- package/dist/types/features/IngestionStatus/IngestionStatusComponent.d.ts +1 -0
- package/dist/types/features/IngestionStatus/IngestionStatusComponent.d.ts.map +1 -1
- package/dist/types/features/IngestionStatus/useIngestionStatus.d.ts +1 -1
- package/dist/types/features/IngestionStatus/useIngestionStatus.d.ts.map +1 -1
- package/dist/types/features/PdfViewer/PdfViewer.d.ts.map +1 -1
- package/dist/types/features/PdfViewer/usePdfHighlight.d.ts +1 -0
- package/dist/types/features/PdfViewer/usePdfHighlight.d.ts.map +1 -1
- package/dist/types/features/SegmentReviewComponents/CognitiveIntegrity.d.ts +6 -1
- package/dist/types/features/SegmentReviewComponents/CognitiveIntegrity.d.ts.map +1 -1
- package/dist/types/features/SegmentReviewComponents/SaveAsLearningCard.d.ts +2 -1
- package/dist/types/features/SegmentReviewComponents/SaveAsLearningCard.d.ts.map +1 -1
- package/dist/types/features/SegmentReviewComponents/SegmentReviewPdfWrapper.d.ts +8 -1
- package/dist/types/features/SegmentReviewComponents/SegmentReviewPdfWrapper.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -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, 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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"}
|
|
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 const coordinateScrollSequenceRef = useRef(0);\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 // Cancel a pending cross-page adjustment when the user navigates again on\n // the current page.\n coordinateScrollSequenceRef.current += 1;\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 sequence = ++coordinateScrollSequenceRef.current;\n let lastScrollTop: number | null = null;\n let stableChecks = 0;\n let attempts = 0;\n\n const waitForSettle = () => {\n if (coordinateScrollSequenceRef.current !== sequence) return;\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 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 isTargetPageVisible =\n pageRect.bottom > scrollContainerRect.top &&\n pageRect.top < scrollContainerRect.bottom;\n\n if (lastScrollTop === scrollContainer.scrollTop) {\n stableChecks += 1;\n } else {\n lastScrollTop = scrollContainer.scrollTop;\n stableChecks = 0;\n }\n\n // jumpToPage updates the virtualized page list asynchronously. Waiting for\n // both visibility and a stable scroll position prevents its page scroll\n // from overwriting the boundary-box scroll below.\n if (!isTargetPageVisible || stableChecks < 2) {\n setTimeout(waitForSettle, 100);\n return;\n }\n\n const highlightTopInPage = (top / 100) * pageRect.height;\n const highlightHeightInPage = (height / 100) * pageRect.height;\n const highlightCenterInViewport =\n pageRect.top -\n scrollContainerRect.top +\n highlightTopInPage +\n highlightHeightInPage / 2;\n const scrollTop =\n scrollContainer.scrollTop +\n highlightCenterInViewport -\n scrollContainer.clientHeight / 2;\n\n scrollContainer.scrollTo({\n top: scrollTop,\n behavior: \"smooth\",\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 scrollToCoordAfterNav,\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};\n"],"names":["PdfHighlightControls","highlightText","highlightPages","viewerRef","highlightPageSet","useCoordinates","highlightCordinatePages","highlightColor","activeHighlightColor","highlightIndex","setHighlightIndex","useState","hasJumpedRef","useRef","cursorIndex","setCursorIndex","coordinateScrollSequenceRef","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","sequence","stableChecks","waitForSettle","isTargetPageVisible","highlightCenterInViewport","getValidPosition","cursor","count","plugins","controls","goToNext","currentH","goToPrevious"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{jsx as i,jsxs as e}from"react/jsx-runtime";import t from"@mui/icons-material/ChevronLeft";import n from"@mui/icons-material/Close";import o from"@mui/material/Box";import r from"@mui/material/Divider";import l from"@mui/material/IconButton";import a from"@mui/material/Paper";import
|
|
1
|
+
import{jsx as i,jsxs as e}from"react/jsx-runtime";import t from"@mui/icons-material/ChevronLeft";import n from"@mui/icons-material/Close";import o from"@mui/material/Box";import r from"@mui/material/Divider";import l from"@mui/material/IconButton";import a from"@mui/material/Paper";import s from"@mui/material/Stack";import m from"@mui/material/Typography";import h from"../CitationRenderer/MarkdownRenderer.js";import c from"./CognitiveIcon.js";import g from"./CognitiveScoreBadge.js";const p=(i,e)=>[i,...Array.isArray(e)?e:null==e?[]:[e]];function d({reasons:d,reason:x,gap:f,score:u,headerName:y="Cognitive Integrity",onBack:H,onClose:S,showCloseButton:b=!0,width:C=260,maxWidth:z=260,className:w,styles:v,renderReason:W}){const k=(d??[]).filter(i=>"evidence"===i.type.trim().toLowerCase()).map(i=>i.text.trim()).filter(Boolean),D=(d??[]).filter(i=>"gap"===i.type.trim().toLowerCase()).map(i=>i.text.trim()).filter(Boolean),B=x?.trim(),F=f?.trim();if(0===k.length&&B&&k.push(B),0===D.length&&F&&D.push(F),0===k.length&&0===D.length)return null;const I=(R=v?.markdown,{...R,containerWrapper:{...R?.containerWrapper,display:"block",height:"auto",minHeight:0,maxHeight:"fit-content",flex:"0 0 auto"},mainCard:{...R?.mainCard,height:"auto",minHeight:0,maxHeight:"none",flex:"0 0 auto",padding:0,border:"none",borderRadius:0,boxShadow:"none",backgroundColor:"transparent"},scrollArea:{height:"auto",minHeight:0,maxHeight:"none",overflowY:"visible",paddingRight:0,color:"#475569",fontSize:12,lineHeight:"20px",...R?.scrollArea},list:{margin:"0",padding:"0 0 0 18px",fontSize:"12px",lineHeight:"20px",...R?.list}});var R;const A={...I,scrollArea:{...I.scrollArea,fontSize:"inherit",lineHeight:"inherit"},summary:{...I.summary,display:"inline-flex",padding:0,fontSize:"inherit",lineHeight:"inherit"}},j=e=>{const t=W?.(e);return W&&"string"!=typeof t?t:i(h,{value:`<summary>${"string"==typeof t?t:e}</summary>`,styles:A})};return i(a,{className:w,elevation:4,sx:p({width:C,maxWidth:z,height:"fit-content",minHeight:0,alignSelf:"flex-start",flex:"0 0 auto",borderRadius:2,bgcolor:"background.paper",overflow:"hidden",boxSizing:"border-box","@media (max-width: 372px)":{width:"calc(100vw - 32px)"}},v?.root),children:e(s,{spacing:.75,sx:{p:1,height:"auto",minHeight:0,display:"flex",flexDirection:"column","& > *":{minHeight:0}},children:[e(s,{direction:"row",alignItems:"center",spacing:.75,sx:v?.header,children:[H&&i(l,{size:"small",onClick:H,"aria-label":"Return to review check",sx:{p:0,color:"#6941C6"},children:i(t,{sx:{fontSize:17}})}),i(c,{sx:{color:"#6941C6"}}),i(m,{sx:{flex:1,fontSize:12,fontWeight:500,alignItems:"center",display:"flex",lineHeight:1.25,textTransform:"capitalise"},children:y}),i(g,{score:u}),b&&i(l,{size:"small",onClick:S,disabled:!S,"aria-label":"Close cognitive integrity",sx:{p:0,"&.Mui-disabled":{color:"text.secondary"}},children:i(n,{sx:{fontSize:17}})})]}),i(r,{sx:{m:0}}),i(o,{sx:p({bgcolor:"#FFFFFF",px:1.5,py:1.25,height:"auto",minHeight:0,flex:"0 0 auto",display:"flex",flexDirection:"column"},v?.content),children:e(s,{spacing:1.5,sx:{display:"flex",flexDirection:"column",minHeight:0},children:[k.length>0&&e(o,{sx:{minHeight:0,display:"flex",flexDirection:"column"},children:[i(m,{sx:{mb:1,color:"#344054",fontSize:12,fontWeight:600,lineHeight:"20px",flexShrink:0},children:"Decision Making Factors"}),i(s,{spacing:.5,sx:{minHeight:0,display:"flex",flexDirection:"column"},children:k.map((t,n)=>e(s,{direction:"row",alignItems:"flex-start",spacing:.75,children:[e(m,{component:"span",sx:{flex:"0 0 auto",minWidth:14,color:"#475569",fontSize:12,fontWeight:400,lineHeight:"20px"},children:[n+1,"."]}),i(o,{sx:{flex:1,minWidth:0,color:"#475569",fontSize:12,fontWeight:400,lineHeight:"20px","& p":{m:0,color:"inherit",fontSize:"inherit",lineHeight:"inherit"}},children:j(t)})]},`evidence-${n}`))})]}),k.length>0&&D.length>0&&i(r,{sx:{my:"2px !important",borderColor:"#E4E7EC"}}),D.length>0&&e(o,{sx:{minHeight:0,display:"flex",flexDirection:"column"},children:[i(m,{sx:{mb:1,color:"#344054",fontSize:12,fontWeight:600,lineHeight:"20px",flexShrink:0},children:"Gaps in Decision"}),i(s,{spacing:.5,sx:{minHeight:0,display:"flex",flexDirection:"column"},children:D.map((t,n)=>e(s,{direction:"row",alignItems:"flex-start",spacing:.75,children:[e(m,{component:"span",sx:{flex:"0 0 auto",minWidth:14,color:"#475569",fontSize:12,fontWeight:400,lineHeight:"20px"},children:[n+1,"."]}),i(o,{sx:{flex:1,minWidth:0,color:"#475569",fontSize:12,fontWeight:400,lineHeight:"20px","& p":{m:0,color:"inherit",fontSize:"inherit",lineHeight:"inherit"}},children:j(t)})]},`gap-${n}`))})]})]})})]})})}export{d as default};
|
|
2
2
|
//# sourceMappingURL=CognitiveIntegrity.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CognitiveIntegrity.js","sources":["../../../src/features/SegmentReviewComponents/CognitiveIntegrity.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport ChevronLeftIcon from '@mui/icons-material/ChevronLeft';\nimport CloseIcon from '@mui/icons-material/Close';\nimport Box from '@mui/material/Box';\nimport Divider from '@mui/material/Divider';\nimport IconButton from '@mui/material/IconButton';\nimport Paper from '@mui/material/Paper';\nimport Stack from '@mui/material/Stack';\nimport Typography from '@mui/material/Typography';\nimport type { SxProps, Theme } from '@mui/material/styles';\nimport InfoAlert from '../../assests/icons/InfoAlert';\nimport MarkdownRenderer, {\n type MarkdownRendererStyles,\n} from '../CitationRenderer/MarkdownRenderer';\nimport CognitiveIcon from './CognitiveIcon';\nimport CognitiveScoreBadge from './CognitiveScoreBadge';\n\nconst mergeSx = (\n base: SxProps<Theme>,\n override?: SxProps<Theme>\n): SxProps<Theme> => [\n base,\n ...(Array.isArray(override) ? override : override == null ? [] : [override]),\n] as SxProps<Theme>;\n\nexport interface CognitiveIntegrityStyles {\n root?: SxProps<Theme>;\n header?: SxProps<Theme>;\n content?: SxProps<Theme>;\n section?: SxProps<Theme>;\n markdown?: MarkdownRendererStyles;\n}\n\nexport interface CognitiveIntegrityProps {\n reasons?: readonly CognitiveIntegrityReason[] | null;\n /** @deprecated Use `reasons` with `type: \"evidence\"` instead. */\n reason?: string | null;\n /** @deprecated Use `reasons` with `type: \"gap\"` instead. */\n gap?: string | null;\n score?: string | number | null;\n headerName?: ReactNode;\n onBack?: () => void;\n onClose?: () => void;\n showCloseButton?: boolean;\n width?: number | string;\n maxWidth?: number | string;\n className?: string;\n styles?: CognitiveIntegrityStyles;\n}\n\nexport interface CognitiveIntegrityReason {\n text: string;\n type: string;\n}\n\nconst getMarkdownStyles = (\n override?: MarkdownRendererStyles\n): MarkdownRendererStyles => ({\n ...override,\n containerWrapper: {\n ...override?.containerWrapper,\n display: 'block',\n height: 'auto',\n minHeight: 0,\n maxHeight: 'fit-content',\n flex: '0 0 auto',\n },\n mainCard: {\n ...override?.mainCard,\n height: 'auto',\n minHeight: 0,\n maxHeight: 'none',\n flex: '0 0 auto',\n padding: 0,\n border: 'none',\n borderRadius: 0,\n boxShadow: 'none',\n backgroundColor: 'transparent',\n },\n scrollArea: {\n height: 'auto',\n minHeight: 0,\n maxHeight: 'none',\n overflowY: 'visible',\n paddingRight: 0,\n color: '#475467',\n fontSize: 11.5,\n lineHeight: 1.3,\n ...override?.scrollArea,\n },\n list: {\n margin: '0',\n padding: '0 0 0 18px',\n fontSize: '11.5px',\n lineHeight: '1.3',\n ...override?.list,\n },\n});\n\n/** Compact popup content for displaying review reason and gap as Markdown. */\nexport default function CognitiveIntegrity({\n reasons,\n reason,\n gap,\n score: cognitiveScore,\n headerName = 'Cognitive Integrity',\n onBack,\n onClose,\n showCloseButton = true,\n width = 260,\n maxWidth = 260,\n className,\n styles,\n}: CognitiveIntegrityProps) {\n const evidence = (reasons ?? [])\n .filter((item) => item.type.trim().toLowerCase() === 'evidence')\n .map((item) => item.text.trim())\n .filter(Boolean);\n const gaps = (reasons ?? [])\n .filter((item) => item.type.trim().toLowerCase() === 'gap')\n .map((item) => item.text.trim())\n .filter(Boolean);\n\n const legacyReason = reason?.trim();\n const legacyGap = gap?.trim();\n if (evidence.length === 0 && legacyReason) evidence.push(legacyReason);\n if (gaps.length === 0 && legacyGap) gaps.push(legacyGap);\n\n if (evidence.length === 0 && gaps.length === 0) return null;\n\n const markdownStyles = getMarkdownStyles(styles?.markdown);\n const listItemMarkdownStyles: MarkdownRendererStyles = {\n ...markdownStyles,\n scrollArea: {\n ...markdownStyles.scrollArea,\n fontSize: 'inherit',\n lineHeight: 'inherit',\n },\n summary: {\n ...markdownStyles.summary,\n display: 'inline-flex',\n padding: 0,\n fontSize: 'inherit',\n lineHeight: 'inherit',\n },\n };\n const orderedListSx: SxProps<Theme> = {\n m: 0,\n pl: 2.25,\n listStyleType: 'decimal',\n listStylePosition: 'outside',\n fontSize: 11.5,\n lineHeight: 1.3,\n '& > li': {\n pl: 0.25,\n fontSize: 'inherit',\n lineHeight: 'inherit',\n },\n '& > li::marker': {\n fontSize: '1em',\n fontWeight: 'inherit',\n },\n };\n\n return (\n <Paper\n className={className}\n elevation={4}\n sx={mergeSx(\n {\n width,\n maxWidth,\n height: 'fit-content',\n minHeight: 0,\n alignSelf: 'flex-start',\n flex: '0 0 auto',\n // borderTop: '4px solid',\n // borderColor: '#7F56D9',\n borderRadius: 2,\n bgcolor: 'background.paper',\n overflow: 'hidden',\n boxSizing: 'border-box',\n '@media (max-width: 372px)': { width: 'calc(100vw - 32px)' },\n },\n styles?.root\n )}\n >\n <Stack spacing={0.75} sx={{ p: 1, height: 'auto', minHeight: 0, display: 'flex', flexDirection: 'column', '& > *': { minHeight: 0 } }}>\n <Stack direction=\"row\" alignItems=\"center\" spacing={0.75} sx={styles?.header}>\n {onBack && (\n <IconButton\n size=\"small\"\n onClick={onBack}\n aria-label=\"Return to review check\"\n sx={{ p: 0, color: '#6941C6' }}\n >\n <ChevronLeftIcon sx={{ fontSize: 17 }} />\n </IconButton>\n )}\n <CognitiveIcon sx={{ color: '#6941C6' }} />\n <Typography\n sx={{\n flex: 1,\n // color: '#6941C6',\n fontSize: 12,\n fontWeight: 500,\n alignItems: \"center\",\n display: 'flex',\n lineHeight: 1.25,\n textTransform: 'capitalise',\n }}\n >\n {headerName}\n </Typography>\n <CognitiveScoreBadge score={cognitiveScore} />\n {showCloseButton && (\n <IconButton\n size=\"small\"\n onClick={onClose}\n disabled={!onClose}\n aria-label=\"Close cognitive integrity\"\n sx={{ p: 0, '&.Mui-disabled': { color: 'text.secondary' } }}\n >\n <CloseIcon sx={{ fontSize: 17 }} />\n </IconButton>\n )}\n </Stack>\n\n <Divider sx={{ m: 0 }} />\n <Box\n sx={mergeSx(\n {\n bgcolor: '#F9FAFB',\n px: 1.5,\n py: 1.25,\n height: 'auto',\n minHeight: 0,\n flex: '0 0 auto',\n display: 'flex',\n flexDirection: 'column',\n },\n styles?.content\n )}\n >\n <Stack spacing={1.5} sx={{ display: 'flex', flexDirection: 'column', minHeight: 0 }}>\n {evidence.length > 0 && (\n <Box sx={{ minHeight: 0, display: 'flex', flexDirection: 'column' }}>\n <Typography\n sx={{\n mb: 1,\n color: '#344054',\n fontSize: 12,\n fontWeight: 600,\n lineHeight: 1.4,\n flexShrink: 0,\n }}\n >\n Decision Making Factors\n </Typography>\n\n <Stack spacing={0.75} sx={{ minHeight: 0, display: 'flex', flexDirection: 'column' }}>\n {evidence.map((item, index) => (\n <Stack\n key={`evidence-${index}`}\n direction=\"row\"\n alignItems=\"flex-start\"\n spacing={0.75}\n >\n <Typography\n component=\"span\"\n sx={{\n flex: '0 0 auto',\n minWidth: 14,\n color: '#475467',\n fontSize: 11.5,\n lineHeight: 1.65,\n }}\n >\n {index + 1}.\n </Typography>\n\n <Box\n sx={{\n flex: 1,\n minWidth: 0,\n color: '#667085',\n fontSize: 11.5,\n lineHeight: 1.65,\n\n '& p': {\n m: 0,\n color: 'inherit',\n fontSize: 'inherit',\n lineHeight: 'inherit',\n },\n }}\n >\n <MarkdownRenderer\n value={`<summary>${item}</summary>`}\n styles={listItemMarkdownStyles}\n />\n </Box>\n </Stack>\n ))}\n </Stack>\n </Box>\n )}\n\n {evidence.length > 0 && gaps.length > 0 && (\n <Divider\n sx={{\n my: '2px !important',\n borderColor: '#E4E7EC',\n }}\n />\n )}\n\n {gaps.length > 0 && (\n <Box sx={{ minHeight: 0, display: 'flex', flexDirection: 'column' }}>\n <Typography\n sx={{\n mb: 1,\n color: '#344054',\n fontSize: 12,\n fontWeight: 600,\n lineHeight: 1.4,\n flexShrink: 0,\n }}\n >\n Gaps in Decision\n </Typography>\n\n <Stack spacing={0.75} sx={{ minHeight: 0, display: 'flex', flexDirection: 'column' }}>\n {gaps.map((item, index) => (\n <Stack\n key={`gap-${index}`}\n direction=\"row\"\n alignItems=\"flex-start\"\n spacing={0.75}\n >\n <Typography\n component=\"span\"\n sx={{\n flex: '0 0 auto',\n minWidth: 14,\n color: '#475467',\n fontSize: 11.5,\n lineHeight: 1.65,\n }}\n >\n {index + 1}.\n </Typography>\n\n <Box\n sx={{\n flex: 1,\n minWidth: 0,\n color: '#667085',\n fontSize: 11.5,\n lineHeight: 1.65,\n\n '& p': {\n m: 0,\n color: 'inherit',\n fontSize: 'inherit',\n lineHeight: 'inherit',\n },\n }}\n >\n <MarkdownRenderer\n value={`<summary>${item}</summary>`}\n styles={listItemMarkdownStyles}\n />\n </Box>\n </Stack>\n ))}\n </Stack>\n </Box>\n )}\n </Stack>\n </Box>\n </Stack>\n </Paper>\n );\n}\n"],"names":["mergeSx","base","override","Array","isArray","CognitiveIntegrity","reasons","reason","gap","score","cognitiveScore","headerName","onBack","onClose","showCloseButton","width","maxWidth","className","styles","evidence","filter","item","type","trim","toLowerCase","map","text","Boolean","gaps","legacyReason","legacyGap","length","push","markdownStyles","markdown","containerWrapper","display","height","minHeight","maxHeight","flex","mainCard","padding","border","borderRadius","boxShadow","backgroundColor","scrollArea","overflowY","paddingRight","color","fontSize","lineHeight","list","margin","listItemMarkdownStyles","summary","jsx","Paper","elevation","sx","alignSelf","bgcolor","overflow","boxSizing","root","children","jsxs","Stack","spacing","p","flexDirection","direction","alignItems","header","IconButton","size","onClick","ChevronLeftIcon","CognitiveIcon","Typography","fontWeight","textTransform","CognitiveScoreBadge","disabled","CloseIcon","Divider","m","Box","px","py","content","mb","flexShrink","index","component","minWidth","MarkdownRenderer","value","my","borderColor"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CognitiveIntegrity.js","sources":["../../../src/features/SegmentReviewComponents/CognitiveIntegrity.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport ChevronLeftIcon from '@mui/icons-material/ChevronLeft';\nimport CloseIcon from '@mui/icons-material/Close';\nimport Box from '@mui/material/Box';\nimport Divider from '@mui/material/Divider';\nimport IconButton from '@mui/material/IconButton';\nimport Paper from '@mui/material/Paper';\nimport Stack from '@mui/material/Stack';\nimport Typography from '@mui/material/Typography';\nimport type { SxProps, Theme } from '@mui/material/styles';\nimport InfoAlert from '../../assests/icons/InfoAlert';\nimport MarkdownRenderer, {\n type MarkdownRendererStyles,\n} from '../CitationRenderer/MarkdownRenderer';\nimport CognitiveIcon from './CognitiveIcon';\nimport CognitiveScoreBadge from './CognitiveScoreBadge';\n\nconst mergeSx = (\n base: SxProps<Theme>,\n override?: SxProps<Theme>\n): SxProps<Theme> => [\n base,\n ...(Array.isArray(override) ? override : override == null ? [] : [override]),\n] as SxProps<Theme>;\n\nexport interface CognitiveIntegrityStyles {\n root?: SxProps<Theme>;\n header?: SxProps<Theme>;\n content?: SxProps<Theme>;\n section?: SxProps<Theme>;\n markdown?: MarkdownRendererStyles;\n}\n\nexport interface CognitiveIntegrityProps {\n reasons?: readonly CognitiveIntegrityReason[] | null;\n /** @deprecated Use `reasons` with `type: \"evidence\"` instead. */\n reason?: string | null;\n /** @deprecated Use `reasons` with `type: \"gap\"` instead. */\n gap?: string | null;\n score?: string | number | null;\n headerName?: ReactNode;\n onBack?: () => void;\n onClose?: () => void;\n showCloseButton?: boolean;\n width?: number | string;\n maxWidth?: number | string;\n className?: string;\n styles?: CognitiveIntegrityStyles;\n /**\n * Optional host renderer for reason text. Use this when reason strings contain\n * application-specific citation anchors that need interactive UI.\n */\n renderReason?: (text: string) => ReactNode;\n}\n\nexport interface CognitiveIntegrityReason {\n text: string;\n type: string;\n}\n\nconst getMarkdownStyles = (\n override?: MarkdownRendererStyles\n): MarkdownRendererStyles => ({\n ...override,\n containerWrapper: {\n ...override?.containerWrapper,\n display: 'block',\n height: 'auto',\n minHeight: 0,\n maxHeight: 'fit-content',\n flex: '0 0 auto',\n },\n mainCard: {\n ...override?.mainCard,\n height: 'auto',\n minHeight: 0,\n maxHeight: 'none',\n flex: '0 0 auto',\n padding: 0,\n border: 'none',\n borderRadius: 0,\n boxShadow: 'none',\n backgroundColor: 'transparent',\n },\n scrollArea: {\n height: 'auto',\n minHeight: 0,\n maxHeight: 'none',\n overflowY: 'visible',\n paddingRight: 0,\n color: '#475569',\n fontSize: 12,\n lineHeight: '20px',\n ...override?.scrollArea,\n },\n list: {\n margin: '0',\n padding: '0 0 0 18px',\n fontSize: '12px',\n lineHeight: '20px',\n ...override?.list,\n },\n});\n\n/** Compact popup content for displaying review reason and gap as Markdown. */\nexport default function CognitiveIntegrity({\n reasons,\n reason,\n gap,\n score: cognitiveScore,\n headerName = 'Cognitive Integrity',\n onBack,\n onClose,\n showCloseButton = true,\n width = 260,\n maxWidth = 260,\n className,\n styles,\n renderReason,\n}: CognitiveIntegrityProps) {\n const evidence = (reasons ?? [])\n .filter((item) => item.type.trim().toLowerCase() === 'evidence')\n .map((item) => item.text.trim())\n .filter(Boolean);\n const gaps = (reasons ?? [])\n .filter((item) => item.type.trim().toLowerCase() === 'gap')\n .map((item) => item.text.trim())\n .filter(Boolean);\n\n const legacyReason = reason?.trim();\n const legacyGap = gap?.trim();\n if (evidence.length === 0 && legacyReason) evidence.push(legacyReason);\n if (gaps.length === 0 && legacyGap) gaps.push(legacyGap);\n\n if (evidence.length === 0 && gaps.length === 0) return null;\n\n const markdownStyles = getMarkdownStyles(styles?.markdown);\n const listItemMarkdownStyles: MarkdownRendererStyles = {\n ...markdownStyles,\n scrollArea: {\n ...markdownStyles.scrollArea,\n fontSize: 'inherit',\n lineHeight: 'inherit',\n },\n summary: {\n ...markdownStyles.summary,\n display: 'inline-flex',\n padding: 0,\n fontSize: 'inherit',\n lineHeight: 'inherit',\n },\n };\n const renderReasonContent = (text: string) => {\n const rendered = renderReason?.(text);\n\n // Match the host panel's behavior: plain strings still receive Markdown\n // formatting, while recognized citation anchors return interactive nodes.\n if (!renderReason || typeof rendered === 'string') {\n return (\n <MarkdownRenderer\n value={`<summary>${typeof rendered === 'string' ? rendered : text}</summary>`}\n styles={listItemMarkdownStyles}\n />\n );\n }\n\n return rendered;\n };\n const orderedListSx: SxProps<Theme> = {\n m: 0,\n pl: 2.25,\n listStyleType: 'decimal',\n listStylePosition: 'outside',\n fontSize: 11.5,\n lineHeight: 1.3,\n '& > li': {\n pl: 0.25,\n fontSize: 'inherit',\n lineHeight: 'inherit',\n },\n '& > li::marker': {\n fontSize: '1em',\n fontWeight: 'inherit',\n },\n };\n\n return (\n <Paper\n className={className}\n elevation={4}\n sx={mergeSx(\n {\n width,\n maxWidth,\n height: 'fit-content',\n minHeight: 0,\n alignSelf: 'flex-start',\n flex: '0 0 auto',\n // borderTop: '4px solid',\n // borderColor: '#7F56D9',\n borderRadius: 2,\n bgcolor: 'background.paper',\n overflow: 'hidden',\n boxSizing: 'border-box',\n '@media (max-width: 372px)': { width: 'calc(100vw - 32px)' },\n },\n styles?.root\n )}\n >\n <Stack spacing={0.75} sx={{ p: 1, height: 'auto', minHeight: 0, display: 'flex', flexDirection: 'column', '& > *': { minHeight: 0 } }}>\n <Stack direction=\"row\" alignItems=\"center\" spacing={0.75} sx={styles?.header}>\n {onBack && (\n <IconButton\n size=\"small\"\n onClick={onBack}\n aria-label=\"Return to review check\"\n sx={{ p: 0, color: '#6941C6' }}\n >\n <ChevronLeftIcon sx={{ fontSize: 17 }} />\n </IconButton>\n )}\n <CognitiveIcon sx={{ color: '#6941C6' }} />\n <Typography\n sx={{\n flex: 1,\n // color: '#6941C6',\n fontSize: 12,\n fontWeight: 500,\n alignItems: \"center\",\n display: 'flex',\n lineHeight: 1.25,\n textTransform: 'capitalise',\n }}\n >\n {headerName}\n </Typography>\n <CognitiveScoreBadge score={cognitiveScore} />\n {showCloseButton && (\n <IconButton\n size=\"small\"\n onClick={onClose}\n disabled={!onClose}\n aria-label=\"Close cognitive integrity\"\n sx={{ p: 0, '&.Mui-disabled': { color: 'text.secondary' } }}\n >\n <CloseIcon sx={{ fontSize: 17 }} />\n </IconButton>\n )}\n </Stack>\n\n <Divider sx={{ m: 0 }} />\n <Box\n sx={mergeSx(\n {\n bgcolor: '#FFFFFF',\n px: 1.5,\n py: 1.25,\n height: 'auto',\n minHeight: 0,\n flex: '0 0 auto',\n display: 'flex',\n flexDirection: 'column',\n },\n styles?.content\n )}\n >\n <Stack spacing={1.5} sx={{ display: 'flex', flexDirection: 'column', minHeight: 0 }}>\n {evidence.length > 0 && (\n <Box sx={{ minHeight: 0, display: 'flex', flexDirection: 'column' }}>\n <Typography\n sx={{\n mb: 1,\n color: '#344054',\n fontSize: 12,\n fontWeight: 600,\n lineHeight: '20px',\n flexShrink: 0,\n }}\n >\n Decision Making Factors\n </Typography>\n\n <Stack spacing={0.5} sx={{ minHeight: 0, display: 'flex', flexDirection: 'column' }}>\n {evidence.map((item, index) => (\n <Stack\n key={`evidence-${index}`}\n direction=\"row\"\n alignItems=\"flex-start\"\n spacing={0.75}\n >\n <Typography\n component=\"span\"\n sx={{\n flex: '0 0 auto',\n minWidth: 14,\n color: '#475569',\n fontSize: 12,\n fontWeight: 400,\n lineHeight: '20px',\n }}\n >\n {index + 1}.\n </Typography>\n\n <Box\n sx={{\n flex: 1,\n minWidth: 0,\n color: '#475569',\n fontSize: 12,\n fontWeight: 400,\n lineHeight: '20px',\n\n '& p': {\n m: 0,\n color: 'inherit',\n fontSize: 'inherit',\n lineHeight: 'inherit',\n },\n }}\n >\n {renderReasonContent(item)}\n </Box>\n </Stack>\n ))}\n </Stack>\n </Box>\n )}\n\n {evidence.length > 0 && gaps.length > 0 && (\n <Divider\n sx={{\n my: '2px !important',\n borderColor: '#E4E7EC',\n }}\n />\n )}\n\n {gaps.length > 0 && (\n <Box sx={{ minHeight: 0, display: 'flex', flexDirection: 'column' }}>\n <Typography\n sx={{\n mb: 1,\n color: '#344054',\n fontSize: 12,\n fontWeight: 600,\n lineHeight: '20px',\n flexShrink: 0,\n }}\n >\n Gaps in Decision\n </Typography>\n\n <Stack spacing={0.5} sx={{ minHeight: 0, display: 'flex', flexDirection: 'column' }}>\n {gaps.map((item, index) => (\n <Stack\n key={`gap-${index}`}\n direction=\"row\"\n alignItems=\"flex-start\"\n spacing={0.75}\n >\n <Typography\n component=\"span\"\n sx={{\n flex: '0 0 auto',\n minWidth: 14,\n color: '#475569',\n fontSize: 12,\n fontWeight: 400,\n lineHeight: '20px',\n }}\n >\n {index + 1}.\n </Typography>\n\n <Box\n sx={{\n flex: 1,\n minWidth: 0,\n color: '#475569',\n fontSize: 12,\n fontWeight: 400,\n lineHeight: '20px',\n\n '& p': {\n m: 0,\n color: 'inherit',\n fontSize: 'inherit',\n lineHeight: 'inherit',\n },\n }}\n >\n {renderReasonContent(item)}\n </Box>\n </Stack>\n ))}\n </Stack>\n </Box>\n )}\n </Stack>\n </Box>\n </Stack>\n </Paper>\n );\n}\n"],"names":["mergeSx","base","override","Array","isArray","CognitiveIntegrity","reasons","reason","gap","score","cognitiveScore","headerName","onBack","onClose","showCloseButton","width","maxWidth","className","styles","renderReason","evidence","filter","item","type","trim","toLowerCase","map","text","Boolean","gaps","legacyReason","legacyGap","length","push","markdownStyles","markdown","containerWrapper","display","height","minHeight","maxHeight","flex","mainCard","padding","border","borderRadius","boxShadow","backgroundColor","scrollArea","overflowY","paddingRight","color","fontSize","lineHeight","list","margin","listItemMarkdownStyles","summary","renderReasonContent","rendered","jsx","MarkdownRenderer","value","Paper","elevation","sx","alignSelf","bgcolor","overflow","boxSizing","root","children","jsxs","Stack","spacing","p","flexDirection","direction","alignItems","header","IconButton","size","onClick","ChevronLeftIcon","CognitiveIcon","Typography","fontWeight","textTransform","CognitiveScoreBadge","disabled","CloseIcon","Divider","m","Box","px","py","content","mb","flexShrink","index","component","minWidth","my","borderColor"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{jsx as e,jsxs as a}from"react/jsx-runtime";import{useState as r}from"react";import
|
|
1
|
+
import{jsx as e,jsxs as a}from"react/jsx-runtime";import{useState as i,useEffect as r}from"react";import o from"@mui/material/Box";import t from"@mui/material/Button";import n from"@mui/material/CircularProgress";import s from"@mui/material/Tooltip";import{CheckCircle2 as l,Sparkles as c,Info as d}from"lucide-react";function m({onSave:m,onSaveComplete:g,onSaveError:f,disabled:u=!1,label:F="Save as learning",savingLabel:x="Saving your feedback…",tooltip:b="Use this decision to improve future automatic reviews.",isSaved:h=!1}){const[v,S]=i(!1),[k,y]=i(h);r(()=>{h&&y(!0)},[h]);return e(o,{sx:{mt:2},children:a(t,{variant:"contained",fullWidth:!0,disabled:v||u||k,onClick:()=>{(async()=>{if(!v&&!u){S(!0);try{const e=await m();e&&!1===e.success||(y(!0),g?.(e))}catch(e){console.error("Failed to save as learning:",e),f?.(e)}finally{S(!1)}}})()},sx:p,children:[a(o,{component:"span",sx:{display:"flex",alignItems:"center",gap:1},children:[v?e(n,{size:15,thickness:5,sx:{color:"#FFFFFF"}}):e(k?l:c,{size:16,strokeWidth:2.25}),e(o,{component:"span",children:v?x:k?"Learning saved":F})]}),e(s,{title:b,arrow:!0,children:e(o,{component:"span","aria-label":b,onClick:e=>e.stopPropagation(),sx:{display:"flex",alignItems:"center",flexShrink:0,opacity:.85},children:e(d,{size:16})})})]})})}const p={minHeight:40,display:"flex",alignItems:"center",justifyContent:"space-between",gap:1,px:2,borderRadius:2.5,background:"linear-gradient(135deg, #6366F1 0%, #4F46E5 100%)",color:"#FFFFFF",fontSize:13.5,fontWeight:600,letterSpacing:.1,textTransform:"none",boxShadow:"0 2px 8px rgba(79, 70, 229, 0.28)",transition:"box-shadow 0.2s ease, transform 0.15s ease, background 0.2s ease","&:hover":{background:"linear-gradient(135deg, #5457E8 0%, #4338CA 100%)",boxShadow:"0 4px 12px rgba(79, 70, 229, 0.36)"},"&:active":{transform:"scale(0.99)"},"&.Mui-disabled":{background:"linear-gradient(135deg, #A5A6F0 0%, #9092E8 100%)",color:"#FFFFFF",opacity:.75}};export{m as default};
|
|
2
2
|
//# sourceMappingURL=SaveAsLearningCard.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SaveAsLearningCard.js","sources":["../../../src/features/SegmentReviewComponents/SaveAsLearningCard.tsx"],"sourcesContent":["import { useState } from 'react';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport Tooltip from '@mui/material/Tooltip';\nimport { Sparkles, Info } from 'lucide-react';\n\nexport interface SaveAsLearningResult {\n success?: boolean;\n message?: string | null;\n}\n\nexport interface SaveAsLearningCardProps {\n onSave: () => void | SaveAsLearningResult | Promise<void | SaveAsLearningResult>;\n onSaveComplete?: (result: void | SaveAsLearningResult) => void;\n onSaveError?: (error: unknown) => void;\n disabled?: boolean;\n label?: string;\n savingLabel?: string;\n tooltip?: string;\n}\n\nexport default function SaveAsLearningCard({\n onSave,\n onSaveComplete,\n onSaveError,\n disabled = false,\n label = 'Save as learning',\n savingLabel = 'Saving your feedback…',\n tooltip = 'Use this decision to improve future automatic reviews.',\n}: SaveAsLearningCardProps) {\n const [isSaving, setIsSaving] = useState(false);\n const [isSaved, setIsSaved] = useState(
|
|
1
|
+
{"version":3,"file":"SaveAsLearningCard.js","sources":["../../../src/features/SegmentReviewComponents/SaveAsLearningCard.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport Tooltip from '@mui/material/Tooltip';\nimport { CheckCircle2, Sparkles, Info } from 'lucide-react';\n\nexport interface SaveAsLearningResult {\n success?: boolean;\n message?: string | null;\n}\n\nexport interface SaveAsLearningCardProps {\n onSave: () => void | SaveAsLearningResult | Promise<void | SaveAsLearningResult>;\n onSaveComplete?: (result: void | SaveAsLearningResult) => void;\n onSaveError?: (error: unknown) => void;\n disabled?: boolean;\n label?: string;\n savingLabel?: string;\n tooltip?: string;\n isSaved?: boolean;\n}\n\nexport default function SaveAsLearningCard({\n onSave,\n onSaveComplete,\n onSaveError,\n disabled = false,\n label = 'Save as learning',\n savingLabel = 'Saving your feedback…',\n tooltip = 'Use this decision to improve future automatic reviews.',\n isSaved: persistedIsSaved = false,\n}: SaveAsLearningCardProps) {\n const [isSaving, setIsSaving] = useState(false);\n const [isSaved, setIsSaved] = useState(persistedIsSaved);\n\n useEffect(() => {\n if (persistedIsSaved) setIsSaved(true);\n }, [persistedIsSaved]);\n\n\n const handleClick = async () => {\n if (isSaving || disabled) return;\n setIsSaving(true);\n try {\n const result = await onSave();\n // Hosts may return an explicit failure result instead of throwing.\n // Keep the card available in that case so the reviewer can retry.\n if (!result || result.success !== false) {\n setIsSaved(true);\n onSaveComplete?.(result);\n }\n } catch (error) {\n console.error('Failed to save as learning:', error);\n onSaveError?.(error);\n } finally {\n setIsSaving(false);\n }\n };\n\n return (\n <Box sx={{ mt: 2 }}>\n <Button\n variant=\"contained\"\n fullWidth\n disabled={isSaving || disabled || isSaved}\n onClick={() => { void handleClick(); }}\n sx={buttonSx}\n >\n <Box component=\"span\" sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>\n {isSaving ? (\n <CircularProgress size={15} thickness={5} sx={{ color: '#FFFFFF' }} />\n ) : isSaved ? (\n <CheckCircle2 size={16} strokeWidth={2.25} />\n ) : (\n <Sparkles size={16} strokeWidth={2.25} />\n )}\n <Box component=\"span\">{isSaving ? savingLabel : isSaved ? 'Learning saved' : label}</Box>\n </Box>\n\n <Tooltip title={tooltip} arrow>\n <Box\n component=\"span\"\n aria-label={tooltip}\n onClick={(e) => e.stopPropagation()}\n sx={{ display: 'flex', alignItems: 'center', flexShrink: 0, opacity: 0.85 }}\n >\n <Info size={16} />\n </Box>\n </Tooltip>\n </Button>\n </Box>\n );\n}\n\nconst buttonSx = {\n minHeight: 40,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 1,\n px: 2,\n borderRadius: 2.5,\n background: 'linear-gradient(135deg, #6366F1 0%, #4F46E5 100%)',\n color: '#FFFFFF',\n fontSize: 13.5,\n fontWeight: 600,\n letterSpacing: 0.1,\n textTransform: 'none',\n boxShadow: '0 2px 8px rgba(79, 70, 229, 0.28)',\n transition: 'box-shadow 0.2s ease, transform 0.15s ease, background 0.2s ease',\n '&:hover': {\n background: 'linear-gradient(135deg, #5457E8 0%, #4338CA 100%)',\n boxShadow: '0 4px 12px rgba(79, 70, 229, 0.36)',\n },\n '&:active': { transform: 'scale(0.99)' },\n '&.Mui-disabled': {\n background: 'linear-gradient(135deg, #A5A6F0 0%, #9092E8 100%)',\n color: '#FFFFFF',\n opacity: 0.75,\n },\n};"],"names":["SaveAsLearningCard","onSave","onSaveComplete","onSaveError","disabled","label","savingLabel","tooltip","isSaved","persistedIsSaved","isSaving","setIsSaving","useState","setIsSaved","useEffect","Box","sx","mt","children","jsxs","Button","variant","fullWidth","onClick","async","result","success","error","console","handleClick","buttonSx","component","display","alignItems","gap","jsx","CircularProgress","size","thickness","color","CheckCircle2","Sparkles","strokeWidth","Tooltip","title","arrow","e","stopPropagation","flexShrink","opacity","Info","minHeight","justifyContent","px","borderRadius","background","fontSize","fontWeight","letterSpacing","textTransform","boxShadow","transition","transform"],"mappings":"8TAuBA,SAAwBA,GAAmBC,OACzCA,EAAAC,eACAA,EAAAC,YACAA,EAAAC,SACAA,GAAW,EAAAC,MACXA,EAAQ,mBAAAC,YACRA,EAAc,wBAAAC,QACdA,EAAU,yDACVC,QAASC,GAAmB,IAE5B,MAAOC,EAAUC,GAAeC,GAAS,IAClCJ,EAASK,GAAcD,EAASH,GAEvCK,EAAU,KACJL,MAA6B,IAChC,CAACA,IAsBJ,SACGM,EAAI,CAAAC,GAAI,CAAEC,GAAI,GACbC,SAAAC,EAACC,EAAA,CACCC,QAAQ,YACRC,WAAS,EACTlB,SAAUM,GAAYN,GAAYI,EAClCe,QAAS,KAzBKC,WAClB,IAAId,IAAYN,EAAhB,CACAO,GAAY,GACR,IACI,MAAAc,QAAexB,IAGhBwB,IAA6B,IAAnBA,EAAOC,UACpBb,GAAW,GACXX,IAAiBuB,UAEZE,GACCC,QAAAD,MAAM,8BAA+BA,GAC7CxB,IAAcwB,EAAK,CACnB,QACAhB,GAAY,EACd,CAf0B,GAwBAkB,IACtBb,GAAIc,EAEJZ,SAAA,CAACC,EAAAJ,EAAA,CAAIgB,UAAU,OAAOf,GAAI,CAAEgB,QAAS,OAAQC,WAAY,SAAUC,IAAK,GACrEhB,SAAA,CACCR,EAAAyB,EAACC,EAAiB,CAAAC,KAAM,GAAIC,UAAW,EAAGtB,GAAI,CAAEuB,MAAO,aAEtDJ,EADC3B,EACDgC,EAEAC,EAFA,CAAaJ,KAAM,GAAIK,YAAa,OAIvCP,EAACpB,GAAIgB,UAAU,OAAQb,WAAWZ,EAAcE,EAAU,iBAAmBH,OAG9E8B,EAAAQ,EAAA,CAAQC,MAAOrC,EAASsC,OAAK,EAC5B3B,SAAAiB,EAACpB,EAAA,CACCgB,UAAU,OACV,aAAYxB,EACZgB,QAAUuB,GAAMA,EAAEC,kBAClB/B,GAAI,CAAEgB,QAAS,OAAQC,WAAY,SAAUe,WAAY,EAAGC,QAAS,KAErE/B,SAAAiB,EAACe,EAAK,CAAAb,KAAM,aAMxB,CAEA,MAAMP,EAAW,CACfqB,UAAW,GACXnB,QAAS,OACTC,WAAY,SACZmB,eAAgB,gBAChBlB,IAAK,EACLmB,GAAI,EACJC,aAAc,IACdC,WAAY,oDACZhB,MAAO,UACPiB,SAAU,KACVC,WAAY,IACZC,cAAe,GACfC,cAAe,OACfC,UAAW,oCACXC,WAAY,mEACZ,UAAW,CACTN,WAAY,oDACZK,UAAW,sCAEb,WAAY,CAAEE,UAAW,eACzB,iBAAkB,CAChBP,WAAY,oDACZhB,MAAO,UACPU,QAAS"}
|