@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,2 +1,2 @@
|
|
|
1
|
-
import{jsxs as e,jsx as t}from"react/jsx-runtime";import{useState as o,useRef as n,useEffect as
|
|
1
|
+
import{jsxs as e,jsx as t}from"react/jsx-runtime";import{useState as o,useRef as n,useEffect as i}from"react";import{ChevronDown as r}from"lucide-react";const d=({children:d,uploadListTopContent:l,defaultHeight:s=300,minHeight:a=150,maxHeight:u,isExpanded:p=!1,onToggle:c,onHeightChange:h,styles:m={},drawerSummaryComponent:f,totalCountsBadge:g,headerComponent:x})=>{const[v,w]=o(!1),[b,y]=o(s),C=n(0),E=n(s),z=n(null),H=n(0),L=()=>"string"==typeof u?parseFloat(u)/100*(window.visualViewport?.height??window.innerHeight):u??.4*window.innerHeight;i(()=>{const e=()=>{const e=Math.max(a,Math.min(L(),b));e!==b&&(y(e),h?.(e))};window.addEventListener("resize",e),window.visualViewport?.addEventListener("resize",e);const t="undefined"!=typeof ResizeObserver?new ResizeObserver(e):null;return t?.observe(document.documentElement),()=>{window.removeEventListener("resize",e),window.visualViewport?.removeEventListener("resize",e),t?.disconnect()}},[b,u,a,h]),i(()=>{!p&&z.current&&(H.current=z.current.getBoundingClientRect().height)},[p]);return i(()=>{if(!v)return;const e=e=>{e.preventDefault();const t=e.clientY-C.current,o=Math.max(a,Math.min(L(),E.current+t));y(o),h?.(o)},t=()=>{w(!1),document.body.style.userSelect=""};return document.addEventListener("mousemove",e),document.addEventListener("mouseup",t),()=>{document.removeEventListener("mousemove",e),document.removeEventListener("mouseup",t)}},[v,u,a,h]),e("div",{ref:z,style:{position:"relative",width:"100%",minHeight:p?H.current:"auto"},children:[e("div",{style:{position:p?"absolute":"relative",zIndex:p?10:"auto",left:0,right:0,top:0,display:"flex",flexDirection:"column",backgroundColor:"#fff",borderRadius:20,border:"1px solid #BDB4FE",boxShadow:"0 4px 8px -2px rgba(16, 24, 40, 0.05), 0 2px 4px -2px rgba(16, 24, 40, 0.06)",height:p?`${b}px`:"auto",minHeight:p?`${a}px`:"auto",maxHeight:p?`${b}px`:"auto",overflow:"hidden",width:"100%",...m.container},children:[e("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",width:"100%",marginBottom:12,flexShrink:0,padding:"12px 20px 0 20px",gap:"16px",...m.header},children:[t("span",{style:{display:"inline-block",flex:1,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",fontSize:16,fontWeight:500,lineHeight:"24px",color:"#101828",fontFamily:"Inter, sans-serif",...m.title},children:x||(l?.trim()?l:"Data uploaded for your context")}),g]}),f,p&&t("div",{style:{flex:1,overflowY:"auto",overflowX:"hidden",minHeight:0,padding:"0 20px",paddingBottom:"36px",...m.body},children:d}),p&&t("div",{onMouseDown:e=>{e.preventDefault(),w(!0),C.current=e.clientY,E.current=b,document.body.style.userSelect="none"},style:{position:"absolute",bottom:0,left:0,right:0,backgroundColor:m.body?.backgroundColor??"#fff",display:"flex",justifyContent:"center",alignItems:"center",padding:"8px 20px",cursor:"ns-resize",userSelect:"none",flexShrink:0},children:t("div",{style:{width:48,height:4,borderRadius:4,background:v?m.dragPillActiveColor??"#a78bfa":"#d1d5db",...m.dragPill}})})]}),t("div",{style:{position:p?"absolute":"relative",top:p?`${b}px`:"auto",width:"100%",display:"flex",justifyContent:"center",height:18,zIndex:p?10:"auto"},children:t("button",{onClick:c,"aria-label":p?"Collapse":"Expand",style:{position:"absolute",width:"52px",height:"18px",borderBottomLeftRadius:"10px",borderBottomRightRadius:"10px",border:"1px solid rgb(189, 180, 254)",borderTop:"none",backgroundColor:"#fff",display:"flex",alignItems:"center",justifyContent:"center",cursor:"pointer",padding:0,...m.notch},children:t(r,{size:14,color:m.notchArrowColor??"#6d28d9",style:{transform:p?"rotate(180deg)":"rotate(0deg)",transition:"transform 0.2s ease"}})})})]})};export{d as default};
|
|
2
2
|
//# sourceMappingURL=ChatDrawer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatDrawer.js","sources":["../../../src/features/ChatDrawer/ChatDrawer.tsx"],"sourcesContent":["import React, { useState, useRef, useEffect } from 'react';\nimport { ChevronDown } from 'lucide-react';\nimport { ChatDrawerProps } from './types/ChatDrawer.types';\n\nconst ChatDrawer: React.FC<ChatDrawerProps> = ({\n children,\n uploadListTopContent,\n defaultHeight = 300,\n minHeight = 150,\n maxHeight,\n isExpanded = false,\n onToggle,\n onHeightChange,\n styles = {},\n drawerSummaryComponent,\n totalCountsBadge, \n headerComponent\n}) => {\n const [isDragging, setIsDragging] = useState(false);\n const [height, setHeight] = useState<number>(defaultHeight);\n\n const startYRef = useRef<number>(0);\n const startHeightRef = useRef<number>(defaultHeight);\n const wrapperRef = useRef<HTMLDivElement>(null);\n const collapsedHeightRef = useRef<number>(0);\n\n const resolvedMaxHeight =\n typeof maxHeight === 'string'\n ? (parseFloat(maxHeight) / 100) * window.innerHeight\n : maxHeight ?? window.innerHeight * 0.4;\n\n useEffect(() => {\n if (!isExpanded && wrapperRef.current) {\n collapsedHeightRef.current = wrapperRef.current.getBoundingClientRect().height;\n }\n }, [isExpanded]);\n\n const handleDragStart = (e: React.MouseEvent) => {\n e.preventDefault();\n setIsDragging(true);\n startYRef.current = e.clientY;\n startHeightRef.current = height;\n document.body.style.userSelect = 'none';\n };\n\n useEffect(() => {\n if (!isDragging) return;\n\n const onMove = (e: MouseEvent) => {\n e.preventDefault();\n const deltaY = e.clientY - startYRef.current;\n const newHeight = Math.max(\n minHeight,\n Math.min(resolvedMaxHeight, startHeightRef.current + deltaY)\n );\n setHeight(newHeight);\n onHeightChange?.(newHeight);\n };\n\n const onUp = () => {\n setIsDragging(false);\n document.body.style.userSelect = '';\n };\n\n document.addEventListener('mousemove', onMove);\n document.addEventListener('mouseup', onUp);\n return () => {\n document.removeEventListener('mousemove', onMove);\n document.removeEventListener('mouseup', onUp);\n };\n }, [isDragging]);\n\n return (\n <div\n ref={wrapperRef}\n style={{\n position: 'relative',\n width: '100%',\n minHeight: isExpanded ? collapsedHeightRef.current : 'auto',\n }}\n >\n {/* Main drawer container */}\n <div\n style={{\n position: isExpanded ? 'absolute' : 'relative',\n zIndex: isExpanded ? 10 : 'auto',\n left: 0,\n right: 0,\n top: 0,\n display: 'flex',\n flexDirection: 'column',\n backgroundColor: '#fff',\n borderRadius: 20,\n border: '1px solid #BDB4FE',\n boxShadow: '0 4px 8px -2px rgba(16, 24, 40, 0.05), 0 2px 4px -2px rgba(16, 24, 40, 0.06)',\n height: isExpanded ? `${height}px` : 'auto',\n minHeight: isExpanded ? `${minHeight}px` : 'auto',\n maxHeight: isExpanded ? `${height}px` : 'auto',\n overflow: 'hidden',\n width: '100%',\n ...styles.container,\n }}\n >\n {/* Header */}\n <div style={{ \n display: 'flex', \n alignItems: 'center', \n justifyContent: 'space-between', \n width: '100%', \n marginBottom: 12, \n flexShrink: 0, \n padding: '12px 20px 0 20px', \n gap: '16px',\n ...styles.header \n }}>\n <span\n style={{\n display: 'inline-block',\n flex: 1, \n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n fontSize: 16,\n fontWeight: 500,\n lineHeight: '24px',\n color: '#101828',\n fontFamily: 'Inter, sans-serif',\n ...styles.title,\n }}\n >\n {headerComponent ? headerComponent : (uploadListTopContent?.trim() ? uploadListTopContent : 'Data uploaded for your context')}\n </span>\n \n {totalCountsBadge}\n </div>\n {/* Summary of drawer */}\n {drawerSummaryComponent}\n\n {/* Body */}\n {isExpanded && (\n <div style={{ \n flex: 1, \n overflowY: 'auto', \n overflowX: 'hidden', \n minHeight: 0, \n padding: '0 20px', \n paddingBottom: '36px', // ADDED: Prevents content from hiding behind the floating drag handle\n ...styles.body \n }}>\n {children}\n </div>\n )}\n\n {/* Drag handle */}\n {isExpanded && (\n <div\n onMouseDown={handleDragStart}\n style={{ \n position: 'absolute', // Pin it to the bottom of the container\n bottom: 0, \n left: 0, \n right: 0,\n backgroundColor: styles.body?.backgroundColor ?? '#fff', // Use themed background\n display: 'flex', \n justifyContent: 'center', \n alignItems: 'center', \n padding: '8px 20px', \n cursor: 'ns-resize', \n userSelect: 'none', \n flexShrink: 0,\n }}\n >\n <div style={{ width: 48, height: 4, borderRadius: 4, background: isDragging ? (styles.dragPillActiveColor ?? '#a78bfa') : '#d1d5db', ...styles.dragPill }} />\n </div>\n )}\n </div>\n\n {/* Notch */}\n <div\n style={{\n position: isExpanded ? 'absolute' : 'relative',\n top: isExpanded ? `${height}px` : 'auto',\n width: '100%',\n display: 'flex',\n justifyContent: 'center',\n height: 18,\n zIndex: isExpanded ? 10 : 'auto',\n }}\n >\n <button\n onClick={onToggle}\n aria-label={isExpanded ? 'Collapse' : 'Expand'}\n style={{\n position: 'absolute',\n width: '52px',\n height: '18px',\n borderBottomLeftRadius: '10px',\n borderBottomRightRadius: '10px',\n border: '1px solid rgb(189, 180, 254)',\n borderTop: 'none',\n backgroundColor: '#fff',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n cursor: 'pointer',\n padding: 0,\n ...styles.notch,\n }}\n >\n <ChevronDown\n size={14}\n color={styles.notchArrowColor ?? \"#6d28d9\"}\n style={{\n transform: isExpanded ? 'rotate(180deg)' : 'rotate(0deg)',\n transition: 'transform 0.2s ease',\n }}\n />\n </button>\n </div>\n </div>\n );\n};\n\nexport default ChatDrawer;"],"names":["ChatDrawer","children","uploadListTopContent","defaultHeight","minHeight","maxHeight","isExpanded","onToggle","onHeightChange","styles","drawerSummaryComponent","totalCountsBadge","headerComponent","isDragging","setIsDragging","useState","height","setHeight","startYRef","useRef","startHeightRef","wrapperRef","collapsedHeightRef","resolvedMaxHeight","parseFloat","window","innerHeight","useEffect","current","getBoundingClientRect","onMove","e","preventDefault","deltaY","clientY","newHeight","Math","max","min","onUp","document","body","style","userSelect","addEventListener","removeEventListener","jsxs","ref","position","width","zIndex","left","right","top","display","flexDirection","backgroundColor","borderRadius","border","boxShadow","overflow","container","alignItems","justifyContent","marginBottom","flexShrink","padding","gap","header","jsx","flex","textOverflow","whiteSpace","fontSize","fontWeight","lineHeight","color","fontFamily","title","trim","overflowY","overflowX","paddingBottom","onMouseDown","bottom","cursor","background","dragPillActiveColor","dragPill","onClick","borderBottomLeftRadius","borderBottomRightRadius","borderTop","notch","ChevronDown","size","notchArrowColor","transform","transition"],"mappings":"yJAIA,MAAMA,EAAwC,EAC5CC,WACAC,uBACAC,gBAAgB,IAChBC,YAAY,IACZC,YACAC,cAAa,EACbC,WACAC,iBACAC,SAAS,CAAC,EACVC,yBACAC,mBACAC,sBAEA,MAAOC,EAAYC,GAAiBC,GAAS,IACtCC,EAAQC,GAAaF,EAAiBZ,GAEvCe,EAAYC,EAAe,GAC3BC,EAAiBD,EAAehB,GAChCkB,EAAaF,EAAuB,MACpCG,EAAqBH,EAAe,GAEpCI,EACiB,iBAAdlB,EACFmB,WAAWnB,GAAa,IAAOoB,OAAOC,YACvCrB,GAAkC,GAArBoB,OAAOC,YAE1BC,EAAU,MACHrB,GAAce,EAAWO,UAC5BN,EAAmBM,QAAUP,EAAWO,QAAQC,wBAAwBb,SAEzE,CAACV,IAsCF,OA5BFqB,EAAU,KACR,IAAKd,EAAY,OAEX,MAAAiB,EAAUC,IACdA,EAAEC,iBACI,MAAAC,EAASF,EAAEG,QAAUhB,EAAUU,QAC/BO,EAAYC,KAAKC,IACrBjC,EACAgC,KAAKE,IAAIf,EAAmBH,EAAeQ,QAAUK,IAEvDhB,EAAUkB,GACV3B,IAAiB2B,IAGbI,EAAO,KACXzB,GAAc,GACL0B,SAAAC,KAAKC,MAAMC,WAAa,IAKnC,OAFSH,SAAAI,iBAAiB,YAAad,GAC9BU,SAAAI,iBAAiB,UAAWL,GAC9B,KACIC,SAAAK,oBAAoB,YAAaf,GACjCU,SAAAK,oBAAoB,UAAWN,KAEzC,CAAC1B,IAGFiC,EAAC,MAAA,CACCC,IAAK1B,EACLqB,MAAO,CACLM,SAAU,WACVC,MAAO,OACP7C,UAAWE,EAAagB,EAAmBM,QAAU,QAIvD3B,SAAA,CAAA6C,EAAC,MAAA,CACCJ,MAAO,CACLM,SAAU1C,EAAa,WAAa,WACpC4C,OAAQ5C,EAAa,GAAK,OAC1B6C,KAAM,EACNC,MAAO,EACPC,IAAK,EACLC,QAAS,OACTC,cAAe,SACfC,gBAAiB,OACjBC,aAAc,GACdC,OAAQ,oBACRC,UAAW,+EACX3C,OAAQV,EAAa,GAAGU,MAAa,OACrCZ,UAAWE,EAAa,GAAGF,MAAgB,OAC3CC,UAAWC,EAAa,GAAGU,MAAa,OACxC4C,SAAU,SACVX,MAAO,UACJxC,EAAOoD,WAIZ5D,SAAA,CAAA6C,EAAC,OAAIJ,MAAO,CACVY,QAAS,OACTQ,WAAY,SACZC,eAAgB,gBAChBd,MAAO,OACPe,aAAc,GACdC,WAAY,EACZC,QAAS,mBACTC,IAAK,UACF1D,EAAO2D,QAEVnE,SAAA,CAAAoE,EAAC,OAAA,CACC3B,MAAO,CACLY,QAAS,eACTgB,KAAM,EACNV,SAAU,SACVW,aAAc,WACdC,WAAY,SACZC,SAAU,GACVC,WAAY,IACZC,WAAY,OACZC,MAAO,UACPC,WAAY,uBACTpE,EAAOqE,OAGX7E,SAAkBW,IAAmBV,GAAsB6E,OAAS7E,EAAuB,oCAG3FS,KAGJD,EAGAJ,GACE+D,EAAA,MAAA,CAAI3B,MAAO,CACV4B,KAAM,EACNU,UAAW,OACXC,UAAW,SACX7E,UAAW,EACX8D,QAAS,SACTgB,cAAe,UACZzE,EAAOgC,MAETxC,aAKJK,GACC+D,EAAC,MAAA,CACCc,YAvHepD,IACvBA,EAAEC,iBACFlB,GAAc,GACdI,EAAUU,QAAUG,EAAEG,QACtBd,EAAeQ,QAAUZ,EAChBwB,SAAAC,KAAKC,MAAMC,WAAa,QAmHzBD,MAAO,CACLM,SAAU,WACVoC,OAAQ,EACRjC,KAAM,EACNC,MAAO,EACNI,gBAAiB/C,EAAOgC,MAAMe,iBAAmB,OAClDF,QAAS,OACTS,eAAgB,SAChBD,WAAY,SACZI,QAAS,WACTmB,OAAQ,YACR1C,WAAY,OACZsB,WAAY,GAGdhE,WAAC,MAAI,CAAAyC,MAAO,CAAEO,MAAO,GAAIjC,OAAQ,EAAGyC,aAAc,EAAG6B,WAAYzE,EAAcJ,EAAO8E,qBAAuB,UAAa,aAAc9E,EAAO+E,iBAMrJnB,EAAC,MAAA,CACC3B,MAAO,CACLM,SAAU1C,EAAa,WAAa,WACpC+C,IAAK/C,EAAa,GAAGU,MAAa,OAClCiC,MAAO,OACPK,QAAS,OACTS,eAAgB,SAChB/C,OAAQ,GACRkC,OAAQ5C,EAAa,GAAK,QAG5BL,SAAAoE,EAAC,SAAA,CACCoB,QAASlF,EACT,aAAYD,EAAa,WAAa,SACtCoC,MAAO,CACLM,SAAU,WACVC,MAAO,OACPjC,OAAQ,OACR0E,uBAAwB,OACxBC,wBAAyB,OACzBjC,OAAQ,+BACRkC,UAAW,OACXpC,gBAAiB,OACjBF,QAAS,OACTQ,WAAY,SACZC,eAAgB,SAChBsB,OAAQ,UACRnB,QAAS,KACNzD,EAAOoF,OAGZ5F,SAAAoE,EAACyB,EAAA,CACCC,KAAM,GACNnB,MAAOnE,EAAOuF,iBAAmB,UACjCtD,MAAO,CACLuD,UAAW3F,EAAa,iBAAmB,eAC3C4F,WAAY"}
|
|
1
|
+
{"version":3,"file":"ChatDrawer.js","sources":["../../../src/features/ChatDrawer/ChatDrawer.tsx"],"sourcesContent":["import React, { useState, useRef, useEffect } from 'react';\nimport { ChevronDown } from 'lucide-react';\nimport { ChatDrawerProps } from './types/ChatDrawer.types';\n\nconst ChatDrawer: React.FC<ChatDrawerProps> = ({\n children,\n uploadListTopContent,\n defaultHeight = 300,\n minHeight = 150,\n maxHeight,\n isExpanded = false,\n onToggle,\n onHeightChange,\n styles = {},\n drawerSummaryComponent,\n totalCountsBadge, \n headerComponent\n}) => {\n const [isDragging, setIsDragging] = useState(false);\n const [height, setHeight] = useState<number>(defaultHeight);\n\n const startYRef = useRef<number>(0);\n const startHeightRef = useRef<number>(defaultHeight);\n const wrapperRef = useRef<HTMLDivElement>(null);\n const collapsedHeightRef = useRef<number>(0);\n\n const getResolvedMaxHeight = () =>\n typeof maxHeight === 'string'\n ? (parseFloat(maxHeight) / 100) * (window.visualViewport?.height ?? window.innerHeight)\n : maxHeight ?? window.innerHeight * 0.4;\n\n useEffect(() => {\n const clampHeightToViewport = () => {\n const nextHeight = Math.max(minHeight, Math.min(getResolvedMaxHeight(), height));\n\n if (nextHeight !== height) {\n setHeight(nextHeight);\n onHeightChange?.(nextHeight);\n }\n };\n\n window.addEventListener('resize', clampHeightToViewport);\n window.visualViewport?.addEventListener('resize', clampHeightToViewport);\n\n const resizeObserver = typeof ResizeObserver !== 'undefined'\n ? new ResizeObserver(clampHeightToViewport)\n : null;\n resizeObserver?.observe(document.documentElement);\n\n return () => {\n window.removeEventListener('resize', clampHeightToViewport);\n window.visualViewport?.removeEventListener('resize', clampHeightToViewport);\n resizeObserver?.disconnect();\n };\n }, [height, maxHeight, minHeight, onHeightChange]);\n\n useEffect(() => {\n if (!isExpanded && wrapperRef.current) {\n collapsedHeightRef.current = wrapperRef.current.getBoundingClientRect().height;\n }\n }, [isExpanded]);\n\n const handleDragStart = (e: React.MouseEvent) => {\n e.preventDefault();\n setIsDragging(true);\n startYRef.current = e.clientY;\n startHeightRef.current = height;\n document.body.style.userSelect = 'none';\n };\n\n useEffect(() => {\n if (!isDragging) return;\n\n const onMove = (e: MouseEvent) => {\n e.preventDefault();\n const deltaY = e.clientY - startYRef.current;\n const newHeight = Math.max(\n minHeight,\n Math.min(getResolvedMaxHeight(), startHeightRef.current + deltaY)\n );\n setHeight(newHeight);\n onHeightChange?.(newHeight);\n };\n\n const onUp = () => {\n setIsDragging(false);\n document.body.style.userSelect = '';\n };\n\n document.addEventListener('mousemove', onMove);\n document.addEventListener('mouseup', onUp);\n return () => {\n document.removeEventListener('mousemove', onMove);\n document.removeEventListener('mouseup', onUp);\n };\n }, [isDragging, maxHeight, minHeight, onHeightChange]);\n\n return (\n <div\n ref={wrapperRef}\n style={{\n position: 'relative',\n width: '100%',\n minHeight: isExpanded ? collapsedHeightRef.current : 'auto',\n }}\n >\n {/* Main drawer container */}\n <div\n style={{\n position: isExpanded ? 'absolute' : 'relative',\n zIndex: isExpanded ? 10 : 'auto',\n left: 0,\n right: 0,\n top: 0,\n display: 'flex',\n flexDirection: 'column',\n backgroundColor: '#fff',\n borderRadius: 20,\n border: '1px solid #BDB4FE',\n boxShadow: '0 4px 8px -2px rgba(16, 24, 40, 0.05), 0 2px 4px -2px rgba(16, 24, 40, 0.06)',\n height: isExpanded ? `${height}px` : 'auto',\n minHeight: isExpanded ? `${minHeight}px` : 'auto',\n maxHeight: isExpanded ? `${height}px` : 'auto',\n overflow: 'hidden',\n width: '100%',\n ...styles.container,\n }}\n >\n {/* Header */}\n <div style={{ \n display: 'flex', \n alignItems: 'center', \n justifyContent: 'space-between', \n width: '100%', \n marginBottom: 12, \n flexShrink: 0, \n padding: '12px 20px 0 20px', \n gap: '16px',\n ...styles.header \n }}>\n <span\n style={{\n display: 'inline-block',\n flex: 1, \n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n fontSize: 16,\n fontWeight: 500,\n lineHeight: '24px',\n color: '#101828',\n fontFamily: 'Inter, sans-serif',\n ...styles.title,\n }}\n >\n {headerComponent ? headerComponent : (uploadListTopContent?.trim() ? uploadListTopContent : 'Data uploaded for your context')}\n </span>\n \n {totalCountsBadge}\n </div>\n {/* Summary of drawer */}\n {drawerSummaryComponent}\n\n {/* Body */}\n {isExpanded && (\n <div style={{ \n flex: 1, \n overflowY: 'auto', \n overflowX: 'hidden', \n minHeight: 0, \n padding: '0 20px', \n paddingBottom: '36px', // ADDED: Prevents content from hiding behind the floating drag handle\n ...styles.body \n }}>\n {children}\n </div>\n )}\n\n {/* Drag handle */}\n {isExpanded && (\n <div\n onMouseDown={handleDragStart}\n style={{ \n position: 'absolute', // Pin it to the bottom of the container\n bottom: 0, \n left: 0, \n right: 0,\n backgroundColor: styles.body?.backgroundColor ?? '#fff', // Use themed background\n display: 'flex', \n justifyContent: 'center', \n alignItems: 'center', \n padding: '8px 20px', \n cursor: 'ns-resize', \n userSelect: 'none', \n flexShrink: 0,\n }}\n >\n <div style={{ width: 48, height: 4, borderRadius: 4, background: isDragging ? (styles.dragPillActiveColor ?? '#a78bfa') : '#d1d5db', ...styles.dragPill }} />\n </div>\n )}\n </div>\n\n {/* Notch */}\n <div\n style={{\n position: isExpanded ? 'absolute' : 'relative',\n top: isExpanded ? `${height}px` : 'auto',\n width: '100%',\n display: 'flex',\n justifyContent: 'center',\n height: 18,\n zIndex: isExpanded ? 10 : 'auto',\n }}\n >\n <button\n onClick={onToggle}\n aria-label={isExpanded ? 'Collapse' : 'Expand'}\n style={{\n position: 'absolute',\n width: '52px',\n height: '18px',\n borderBottomLeftRadius: '10px',\n borderBottomRightRadius: '10px',\n border: '1px solid rgb(189, 180, 254)',\n borderTop: 'none',\n backgroundColor: '#fff',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n cursor: 'pointer',\n padding: 0,\n ...styles.notch,\n }}\n >\n <ChevronDown\n size={14}\n color={styles.notchArrowColor ?? \"#6d28d9\"}\n style={{\n transform: isExpanded ? 'rotate(180deg)' : 'rotate(0deg)',\n transition: 'transform 0.2s ease',\n }}\n />\n </button>\n </div>\n </div>\n );\n};\n\nexport default ChatDrawer;"],"names":["ChatDrawer","children","uploadListTopContent","defaultHeight","minHeight","maxHeight","isExpanded","onToggle","onHeightChange","styles","drawerSummaryComponent","totalCountsBadge","headerComponent","isDragging","setIsDragging","useState","height","setHeight","startYRef","useRef","startHeightRef","wrapperRef","collapsedHeightRef","getResolvedMaxHeight","parseFloat","window","visualViewport","innerHeight","useEffect","clampHeightToViewport","nextHeight","Math","max","min","addEventListener","resizeObserver","ResizeObserver","observe","document","documentElement","removeEventListener","disconnect","current","getBoundingClientRect","onMove","e","preventDefault","deltaY","clientY","newHeight","onUp","body","style","userSelect","jsxs","ref","position","width","zIndex","left","right","top","display","flexDirection","backgroundColor","borderRadius","border","boxShadow","overflow","container","alignItems","justifyContent","marginBottom","flexShrink","padding","gap","header","jsx","flex","textOverflow","whiteSpace","fontSize","fontWeight","lineHeight","color","fontFamily","title","trim","overflowY","overflowX","paddingBottom","onMouseDown","bottom","cursor","background","dragPillActiveColor","dragPill","onClick","borderBottomLeftRadius","borderBottomRightRadius","borderTop","notch","ChevronDown","size","notchArrowColor","transform","transition"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{jsx as e,jsxs as n,Fragment as s}from"react/jsx-runtime";import r from"./ingestion.module.css.js";import{useIngestionWebSocket as t}from"./useIngestionStatus.js";import{ExternalLink as o}from"lucide-react";const i={ingested:{label:"Ingested",className:r.ingested},failed:{label:"Ingestion Failed",className:r.failed},in_progress:{label:"Ingesting...",className:r.inProgress},pending:{label:"Pending",className:r.pending}};const a=({status:t,label:a,percentage:l,customConfig:c,redirectionLink:u})=>{if(c)return e("span",{className:r.chip,style:{border:`1px solid ${c.borderColor}`,background:c.background,color:c.color},children:a??c.label});if("custom"===t)return null;const d=i[t];if(!d)return null;const g="in_progress"===t&&void 0!==l;return n("span",{className:`${r.chip} ${d.className}`,style:{display:"inline-flex",alignItems:"center",gap:6},children:[g?n(s,{children:[a??"Ingesting",e("span",{className:r.dot}),`${l}%`]}):a??d.label,u&&e(o,{size:14,style:{cursor:"pointer",flexShrink:0},onClick:e=>{e.stopPropagation(),window.open(u,"_blank","noopener,noreferrer")}})]})},l=new Set(["DONE","COMPLETED","FAILED"]),c=({ingestionId:n,status:s,wsBaseUrl:r,showPercentage:o=!0,statusMap:i,customStatusConfigs:c,redirectionLink:u})=>{console.log("Component:",u);const
|
|
1
|
+
import{jsx as e,jsxs as n,Fragment as s}from"react/jsx-runtime";import r from"./ingestion.module.css.js";import{useIngestionWebSocket as t}from"./useIngestionStatus.js";import{ExternalLink as o}from"lucide-react";const i={ingested:{label:"Ingested",className:r.ingested},failed:{label:"Ingestion Failed",className:r.failed},in_progress:{label:"Ingesting...",className:r.inProgress},pending:{label:"Pending",className:r.pending}};const a=({status:t,label:a,percentage:l,customConfig:c,redirectionLink:u})=>{if(c)return e("span",{className:r.chip,style:{border:`1px solid ${c.borderColor}`,background:c.background,color:c.color},children:a??c.label});if("custom"===t)return null;const d=i[t];if(!d)return null;const g="in_progress"===t&&void 0!==l;return n("span",{className:`${r.chip} ${d.className}`,style:{display:"inline-flex",alignItems:"center",gap:6},children:[g?n(s,{children:[a??"Ingesting",e("span",{className:r.dot}),`${l}%`]}):a??d.label,u&&e(o,{size:14,style:{cursor:"pointer",flexShrink:0},onClick:e=>{e.stopPropagation(),window.open(u,"_blank","noopener,noreferrer")}})]})},l=new Set(["DONE","COMPLETED","FAILED"]),c=({ingestionId:n,status:s,wsBaseUrl:r,showPercentage:o=!0,statusMap:i,customStatusConfigs:c,redirectionLink:u,authToken:d})=>{console.log("Component:",u);const g=!!s&&l.has(s.toUpperCase()),{data:p}=t(!g&&n?n:null,r,d),m=g?s:p?.ingestionStatus??s??"",f=m?function(e,n){if(!e)return"custom";if(n){if(void 0!==n[e])return n[e];const s=e.toUpperCase();if(void 0!==n[s])return n[s]}return"custom"}(m,i):"pending",b=c?c[f]??c[m]??c[m.toUpperCase()]:void 0,h=(()=>{if(!g&&o)return void 0!==p?.currentProgress?Math.max(5,p.currentProgress):"in_progress"===f?5:void 0})();return e(a,{status:f,percentage:h,customConfig:b,redirectionLink:u})};export{a as IngestionStatusChip,c as IngestionStatusComponent};
|
|
2
2
|
//# sourceMappingURL=IngestionStatusComponent.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IngestionStatusComponent.js","sources":["../../../src/features/IngestionStatus/IngestionStatusComponent.tsx"],"sourcesContent":["import React from \"react\";\nimport styles from \"./ingestion.module.css\";\nimport { useIngestionWebSocket } from \"./useIngestionStatus\";\nimport { ExternalLink } from \"lucide-react\";\n\n\nconst STATUS_CONFIG: Record<\n Exclude<string, \"custom\">,\n { label: string; className: string }\n> = {\n ingested: { label: \"Ingested\", className: styles.ingested },\n failed: { label: \"Ingestion Failed\", className: styles.failed },\n in_progress: { label: \"Ingesting...\", className: styles.inProgress },\n pending: { label: \"Pending\", className: styles.pending },\n};\n\nexport interface CustomChipConfig {\n label: string;\n borderColor: string;\n background: string;\n color: string;\n dotColor?: string;\n}\n\nfunction mapStatus(rawStatus: string, statusMap?: Record<string, string>): string {\n if (!rawStatus) return \"custom\";\n if (statusMap) {\n if (statusMap[rawStatus] !== undefined) return statusMap[rawStatus];\n const upper = rawStatus.toUpperCase();\n if (statusMap[upper] !== undefined) return statusMap[upper];\n }\n return \"custom\";\n}\n\ninterface IngestionStatusChipProps {\n status: string;\n label?: string;\n percentage?: number;\n customConfig?: CustomChipConfig;\n redirectionLink?: string;\n\n}\n\nexport const IngestionStatusChip: React.FC<IngestionStatusChipProps> = ({\n status,\n label,\n percentage,\n customConfig,\n redirectionLink,\n}) => {\n if (customConfig) {\n return (\n <span\n className={styles.chip}\n style={{\n border: `1px solid ${customConfig.borderColor}`,\n background: customConfig.background,\n color: customConfig.color,\n }}\n >\n {label ?? customConfig.label}\n </span>\n );\n }\n\n if (status === \"custom\") return null;\n\n const config = STATUS_CONFIG[status];\n if (!config) return null;\n const showPercentage = status === \"in_progress\" && percentage !== undefined;\n\n return (\n <span className={`${styles.chip} ${config.className}`}\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 6,\n }}>\n {showPercentage ? (\n <>\n {label ?? \"Ingesting\"}\n <span className={styles.dot} />\n {`${percentage}%`}\n </>\n ) : (\n label ?? config.label\n )}\n \n {redirectionLink && (\n <ExternalLink\n size={14}\n style={{ cursor: \"pointer\", flexShrink: 0 }}\n onClick={(e) => {\n e.stopPropagation();\n window.open(redirectionLink, \"_blank\", \"noopener,noreferrer\");\n }}\n />\n )}\n </span>\n );\n};\n\nconst TERMINAL_STATUSES = new Set([\"DONE\", \"COMPLETED\", \"FAILED\"]);\n\n\ninterface IngestionStatusComponentProps {\n ingestionId?: string;\n status?: string;\n wsBaseUrl?: string;\n showPercentage?: boolean;\n statusMap?: Record<string, string>;\n customStatusConfigs?: Record<string, CustomChipConfig>;\n redirectionLink?: string;\n\n}\n\nexport const IngestionStatusComponent: React.FC<IngestionStatusComponentProps> = ({\n ingestionId,\n status,\n wsBaseUrl,\n showPercentage = true,\n statusMap,\n customStatusConfigs,\n redirectionLink\n}) => {\n console.log(\"Component:\", redirectionLink);\n\n const isTerminal = status ? TERMINAL_STATUSES.has(status.toUpperCase()) : false;\n\n const { data } = useIngestionWebSocket(\n !isTerminal && ingestionId ? ingestionId : null,\n wsBaseUrl\n );\n\n const rawForMapping: string = isTerminal\n ? status!\n : data?.ingestionStatus ?? status ?? \"\";\n\n const resolvedStatus: string = rawForMapping\n ? mapStatus(rawForMapping, statusMap)\n : \"pending\";\n\n const customConfig: CustomChipConfig | undefined = customStatusConfigs\n ? customStatusConfigs[resolvedStatus] ??\n customStatusConfigs[rawForMapping] ??\n customStatusConfigs[rawForMapping.toUpperCase()]\n : undefined;\n\n const percentage = (() => {\n if (isTerminal || !showPercentage) return undefined;\n if (data?.currentProgress !== undefined) return Math.max(5, data.currentProgress);\n if (resolvedStatus === \"in_progress\") return 5;\n return undefined;\n })();\n\n return <IngestionStatusChip status={resolvedStatus} percentage={percentage} customConfig={customConfig} redirectionLink={redirectionLink}\n />;\n};\n\n"],"names":["STATUS_CONFIG","ingested","label","className","styles","failed","in_progress","inProgress","pending","IngestionStatusChip","status","percentage","customConfig","redirectionLink","jsx","chip","style","border","borderColor","background","color","children","config","showPercentage","jsxs","display","alignItems","gap","Fragment","dot","ExternalLink","size","cursor","flexShrink","onClick","e","stopPropagation","window","open","TERMINAL_STATUSES","Set","IngestionStatusComponent","ingestionId","wsBaseUrl","statusMap","customStatusConfigs","console","log","isTerminal","has","toUpperCase","data","useIngestionWebSocket","rawForMapping","ingestionStatus","resolvedStatus","rawStatus","upper","mapStatus","currentProgress","Math","max"],"mappings":"qNAMA,MAAMA,EAGF,CACFC,SAAU,CAAEC,MAAO,WAAYC,UAAWC,EAAOH,UACjDI,OAAQ,CAAEH,MAAO,mBAAoBC,UAAWC,EAAOC,QACvDC,YAAa,CAAEJ,MAAO,eAAgBC,UAAWC,EAAOG,YACxDC,QAAS,CAAEN,MAAO,UAAWC,UAAWC,EAAOI,UA8B1C,MAAMC,EAA0D,EACrEC,SACAR,QACAS,aACAC,eACAC,sBAEA,GAAID,EAEA,OAAAE,EAAC,OAAA,CACCX,UAAWC,EAAOW,KAClBC,MAAO,CACLC,OAAQ,aAAaL,EAAaM,cAClCC,WAAYP,EAAaO,WACzBC,MAAOR,EAAaQ,OAGrBC,YAAST,EAAaV,QAKzB,GAAW,WAAXQ,EAA4B,OAAA,KAE1B,MAAAY,EAAStB,EAAcU,GACzB,IAACY,EAAe,OAAA,KACd,MAAAC,EAA4B,gBAAXb,QAA2C,IAAfC,EAGjD,OAAAa,EAAC,OAAA,CAAKrB,UAAW,GAAGC,EAAOW,QAAQO,EAAOnB,YAC1Ca,MAAO,CACLS,QAAS,cACTC,WAAY,SACZC,IAAK,GAEJN,SAAA,CAAAE,EAEIC,EAAAI,EAAA,CAAAP,SAAA,CAASnB,GAAA,YACTY,EAAA,OAAA,CAAKX,UAAWC,EAAOyB,MACvB,GAAGlB,QAGNT,GAASoB,EAAOpB,MAGjBW,GACDC,EAACgB,EAAA,CACCC,KAAM,GACNf,MAAO,CAAEgB,OAAQ,UAAWC,WAAY,GACxCC,QAAUC,IACRA,EAAEC,kBACKC,OAAAC,KAAKzB,EAAiB,SAAU,8BAQ3C0B,EAAwB,IAAAC,IAAI,CAAC,OAAQ,YAAa,
|
|
1
|
+
{"version":3,"file":"IngestionStatusComponent.js","sources":["../../../src/features/IngestionStatus/IngestionStatusComponent.tsx"],"sourcesContent":["import React from \"react\";\nimport styles from \"./ingestion.module.css\";\nimport { useIngestionWebSocket } from \"./useIngestionStatus\";\nimport { ExternalLink } from \"lucide-react\";\n\n\nconst STATUS_CONFIG: Record<\n Exclude<string, \"custom\">,\n { label: string; className: string }\n> = {\n ingested: { label: \"Ingested\", className: styles.ingested },\n failed: { label: \"Ingestion Failed\", className: styles.failed },\n in_progress: { label: \"Ingesting...\", className: styles.inProgress },\n pending: { label: \"Pending\", className: styles.pending },\n};\n\nexport interface CustomChipConfig {\n label: string;\n borderColor: string;\n background: string;\n color: string;\n dotColor?: string;\n}\n\nfunction mapStatus(rawStatus: string, statusMap?: Record<string, string>): string {\n if (!rawStatus) return \"custom\";\n if (statusMap) {\n if (statusMap[rawStatus] !== undefined) return statusMap[rawStatus];\n const upper = rawStatus.toUpperCase();\n if (statusMap[upper] !== undefined) return statusMap[upper];\n }\n return \"custom\";\n}\n\ninterface IngestionStatusChipProps {\n status: string;\n label?: string;\n percentage?: number;\n customConfig?: CustomChipConfig;\n redirectionLink?: string;\n\n}\n\nexport const IngestionStatusChip: React.FC<IngestionStatusChipProps> = ({\n status,\n label,\n percentage,\n customConfig,\n redirectionLink,\n}) => {\n if (customConfig) {\n return (\n <span\n className={styles.chip}\n style={{\n border: `1px solid ${customConfig.borderColor}`,\n background: customConfig.background,\n color: customConfig.color,\n }}\n >\n {label ?? customConfig.label}\n </span>\n );\n }\n\n if (status === \"custom\") return null;\n\n const config = STATUS_CONFIG[status];\n if (!config) return null;\n const showPercentage = status === \"in_progress\" && percentage !== undefined;\n\n return (\n <span className={`${styles.chip} ${config.className}`}\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 6,\n }}>\n {showPercentage ? (\n <>\n {label ?? \"Ingesting\"}\n <span className={styles.dot} />\n {`${percentage}%`}\n </>\n ) : (\n label ?? config.label\n )}\n \n {redirectionLink && (\n <ExternalLink\n size={14}\n style={{ cursor: \"pointer\", flexShrink: 0 }}\n onClick={(e) => {\n e.stopPropagation();\n window.open(redirectionLink, \"_blank\", \"noopener,noreferrer\");\n }}\n />\n )}\n </span>\n );\n};\n\nconst TERMINAL_STATUSES = new Set([\"DONE\", \"COMPLETED\", \"FAILED\"]);\n\n\ninterface IngestionStatusComponentProps {\n ingestionId?: string;\n status?: string;\n wsBaseUrl?: string;\n showPercentage?: boolean;\n statusMap?: Record<string, string>;\n customStatusConfigs?: Record<string, CustomChipConfig>;\n redirectionLink?: string;\n authToken?: string;\n\n}\n\nexport const IngestionStatusComponent: React.FC<IngestionStatusComponentProps> = ({\n ingestionId,\n status,\n wsBaseUrl,\n showPercentage = true,\n statusMap,\n customStatusConfigs,\n redirectionLink,\n authToken\n}) => {\n console.log(\"Component:\", redirectionLink);\n\n const isTerminal = status ? TERMINAL_STATUSES.has(status.toUpperCase()) : false;\n\n const { data } = useIngestionWebSocket(\n !isTerminal && ingestionId ? ingestionId : null,\n wsBaseUrl,\n authToken\n );\n\n const rawForMapping: string = isTerminal\n ? status!\n : data?.ingestionStatus ?? status ?? \"\";\n\n const resolvedStatus: string = rawForMapping\n ? mapStatus(rawForMapping, statusMap)\n : \"pending\";\n\n const customConfig: CustomChipConfig | undefined = customStatusConfigs\n ? customStatusConfigs[resolvedStatus] ??\n customStatusConfigs[rawForMapping] ??\n customStatusConfigs[rawForMapping.toUpperCase()]\n : undefined;\n\n const percentage = (() => {\n if (isTerminal || !showPercentage) return undefined;\n if (data?.currentProgress !== undefined) return Math.max(5, data.currentProgress);\n if (resolvedStatus === \"in_progress\") return 5;\n return undefined;\n })();\n\n return <IngestionStatusChip status={resolvedStatus} percentage={percentage} customConfig={customConfig} redirectionLink={redirectionLink}\n />;\n};\n\n"],"names":["STATUS_CONFIG","ingested","label","className","styles","failed","in_progress","inProgress","pending","IngestionStatusChip","status","percentage","customConfig","redirectionLink","jsx","chip","style","border","borderColor","background","color","children","config","showPercentage","jsxs","display","alignItems","gap","Fragment","dot","ExternalLink","size","cursor","flexShrink","onClick","e","stopPropagation","window","open","TERMINAL_STATUSES","Set","IngestionStatusComponent","ingestionId","wsBaseUrl","statusMap","customStatusConfigs","authToken","console","log","isTerminal","has","toUpperCase","data","useIngestionWebSocket","rawForMapping","ingestionStatus","resolvedStatus","rawStatus","upper","mapStatus","currentProgress","Math","max"],"mappings":"qNAMA,MAAMA,EAGF,CACFC,SAAU,CAAEC,MAAO,WAAYC,UAAWC,EAAOH,UACjDI,OAAQ,CAAEH,MAAO,mBAAoBC,UAAWC,EAAOC,QACvDC,YAAa,CAAEJ,MAAO,eAAgBC,UAAWC,EAAOG,YACxDC,QAAS,CAAEN,MAAO,UAAWC,UAAWC,EAAOI,UA8B1C,MAAMC,EAA0D,EACrEC,SACAR,QACAS,aACAC,eACAC,sBAEA,GAAID,EAEA,OAAAE,EAAC,OAAA,CACCX,UAAWC,EAAOW,KAClBC,MAAO,CACLC,OAAQ,aAAaL,EAAaM,cAClCC,WAAYP,EAAaO,WACzBC,MAAOR,EAAaQ,OAGrBC,YAAST,EAAaV,QAKzB,GAAW,WAAXQ,EAA4B,OAAA,KAE1B,MAAAY,EAAStB,EAAcU,GACzB,IAACY,EAAe,OAAA,KACd,MAAAC,EAA4B,gBAAXb,QAA2C,IAAfC,EAGjD,OAAAa,EAAC,OAAA,CAAKrB,UAAW,GAAGC,EAAOW,QAAQO,EAAOnB,YAC1Ca,MAAO,CACLS,QAAS,cACTC,WAAY,SACZC,IAAK,GAEJN,SAAA,CAAAE,EAEIC,EAAAI,EAAA,CAAAP,SAAA,CAASnB,GAAA,YACTY,EAAA,OAAA,CAAKX,UAAWC,EAAOyB,MACvB,GAAGlB,QAGNT,GAASoB,EAAOpB,MAGjBW,GACDC,EAACgB,EAAA,CACCC,KAAM,GACNf,MAAO,CAAEgB,OAAQ,UAAWC,WAAY,GACxCC,QAAUC,IACRA,EAAEC,kBACKC,OAAAC,KAAKzB,EAAiB,SAAU,8BAQ3C0B,EAAwB,IAAAC,IAAI,CAAC,OAAQ,YAAa,WAe3CC,EAAoE,EAC/EC,cACAhC,SACAiC,YACApB,kBAAiB,EACjBqB,YACAC,sBACAhC,kBACAiC,gBAEUC,QAAAC,IAAI,aAAcnC,GAE5B,MAAMoC,IAAavC,GAAS6B,EAAkBW,IAAIxC,EAAOyC,gBAEnDC,KAAEA,GAASC,GACdJ,GAAcP,EAAcA,EAAc,KAC3CC,EACAG,GAGIQ,EAAwBL,EAC1BvC,EACA0C,GAAMG,iBAAmB7C,GAAU,GAEjC8C,EAAyBF,EArHjC,SAAmBG,EAAmBb,GAChC,IAACa,EAAkB,MAAA,SACvB,GAAIb,EAAW,CACb,QAAwC,IAApCA,EAAUa,GAA0B,OAAOb,EAAUa,GACnD,MAAAC,EAAQD,EAAUN,cACxB,QAAoC,IAAhCP,EAAUc,GAAsB,OAAOd,EAAUc,EACvD,CACO,MAAA,QACT,CA8GMC,CAAUL,EAAeV,GACzB,UAEEhC,EAA6CiC,EAC/CA,EAAoBW,IACpBX,EAAoBS,IACpBT,EAAoBS,EAAcH,oBAClC,EAEExC,QACA,IAAAsC,GAAe1B,EACf,YAAqC,IAArC6B,GAAMQ,gBAAsCC,KAAKC,IAAI,EAAGV,EAAKQ,iBAC1C,gBAAnBJ,EAAyC,OAAzC,CAEH,KAEI,OAAA1C,EAACL,EAAA,CAAoBC,OAAQ8C,EAAgB7C,aAAwBC,eAA4BC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{useState as e,useRef as t,useEffect as n,useCallback as r}from"react";const s=new Set(["DONE","COMPLETED","FAILED"]);const o=new Map;function l(e,t,n){t.listeners.delete(n),0===t.listeners.size&&o.get(e)===t&&(clearInterval(t.keepAliveInterval),t.ws.readyState!==WebSocket.OPEN&&t.ws.readyState!==WebSocket.CONNECTING||t.ws.close(),o.delete(e))}function c(c,a){const[
|
|
1
|
+
import{useState as e,useRef as t,useEffect as n,useCallback as r}from"react";const s=new Set(["DONE","COMPLETED","FAILED"]);const o=new Map;function l(e,t,n){t.listeners.delete(n),0===t.listeners.size&&o.get(e)===t&&(clearInterval(t.keepAliveInterval),t.ws.readyState!==WebSocket.OPEN&&t.ws.readyState!==WebSocket.CONNECTING||t.ws.close(),o.delete(e))}function c(c,a,i){const[u,d]=e(null),[v,S]=e(!1),[p,f]=e(null),g=t(null),k=t(null),E=t(c);n(()=>{E.current=c},[c]);const w=r(()=>{const e=E.current;e&&g.current&&k.current&&l(e,g.current,k.current),g.current=null,k.current=null,S(!1)},[]);return n(()=>{if(!c)return;f(null);const e=function(e,t,n){if(!t||"string"!=typeof t||!t.trim())return console.error("useIngestionWebSocket: wsBaseUrl is missing or invalid; skipping connection."),null;const r=o.get(e);if(r&&r.ws.readyState!==WebSocket.CLOSED)return r;let l=`${t.trim()}/${e}`;n&&(l+=`?token=${n}`);const c=new WebSocket(l),a={ws:c,listeners:new Set,lastData:null,keepAliveInterval:setInterval(()=>{c.readyState===WebSocket.OPEN&&c.send(JSON.stringify({type:"ping"}))},5e3)};return c.onmessage=t=>{let n;try{n=JSON.parse(t.data)}catch{return void a.listeners.forEach(e=>e(null,"Failed to parse WebSocket message"))}if(!function(e){if(!e||"object"!=typeof e)return!1;const t=e;return"string"==typeof t.ingestionStatus&&"string"==typeof t.ingestionId}(n))return void a.listeners.forEach(e=>e(null,"Received malformed WebSocket payload"));const r=n;a.lastData=r,a.listeners.forEach(e=>e(r,null)),s.has(r.ingestionStatus.toUpperCase())&&(clearInterval(a.keepAliveInterval),c.close(),o.delete(e))},c.onerror=()=>{a.listeners.forEach(e=>e(null,"WebSocket connection error"))},c.onclose=()=>{clearInterval(a.keepAliveInterval),o.get(e)===a&&o.delete(e)},o.set(e,a),a}(c,a,i);if(!e)return f("Missing or invalid WebSocket base URL"),void S(!1);e.lastData&&d(e.lastData),S(e.ws.readyState===WebSocket.OPEN);const t=(e,t)=>{t?f(t):d(e)};e.listeners.add(t),g.current=e,k.current=t;const n=()=>S(!0),r=()=>S(!1);return e.ws.addEventListener("open",n),e.ws.addEventListener("close",r),()=>{e.ws.removeEventListener("open",n),e.ws.removeEventListener("close",r),l(c,e,t),g.current=null,k.current=null}},[c,a]),{data:u,connected:v,error:p,disconnect:w}}export{c as useIngestionWebSocket};
|
|
2
2
|
//# sourceMappingURL=useIngestionStatus.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useIngestionStatus.js","sources":["../../../src/features/IngestionStatus/useIngestionStatus.tsx"],"sourcesContent":["import { useState, useEffect, useCallback, useRef } from \"react\";\n\nexport interface ArtifactLayer {\n label: string;\n layerStatus: string;\n currentProgress: number;\n chunks: { total: number; completed: number; failed: number };\n}\n\nexport interface Artifact {\n artifactId: string;\n name: string;\n status: string;\n artifactSize: string;\n layers: ArtifactLayer[];\n}\n\nexport interface WebSocketIngestionData {\n ingestionStatus: string;\n ingestionId: string;\n currentProgress: number;\n createdAt: string;\n completedAt?: string | null;\n eta?: string | null;\n artifacts: Artifact[];\n total_artifacts?: number;\n layer_orchestration_count?: number;\n artifactStatus?: {\n \"in-progress\": number;\n completed: number;\n queued: number;\n };\n}\n\nconst TERMINAL_STATUSES = new Set([\"DONE\", \"COMPLETED\", \"FAILED\"]);\n\n// Minimal runtime shape check for incoming WS payloads. We don't pull in a\n// full schema library for one message type — just guard the fields we\n// actually branch on (ingestionStatus) and require an object shape overall.\nfunction isValidIngestionPayload(value: unknown): value is WebSocketIngestionData {\n if (!value || typeof value !== \"object\") return false;\n const candidate = value as Record<string, unknown>;\n return typeof candidate.ingestionStatus === \"string\" && typeof candidate.ingestionId === \"string\";\n}\n\n// --- Shared connection registry -------------------------------------------\n// One real WebSocket per ingestionId, fanned out to any number of subscribers.\n// This lets multiple TimelineItem/IngestionStatusComponent instances that\n// happen to share the same ingestionId (e.g. a batched multi-file upload)\n// observe the same socket instead of each opening (and closing) their own.\ntype Listener = (data: WebSocketIngestionData | null, error: string | null) => void;\n\ninterface SharedConnection {\n ws: WebSocket;\n keepAliveInterval: ReturnType<typeof setInterval>;\n listeners: Set<Listener>;\n lastData: WebSocketIngestionData | null;\n}\n\nconst sharedConnections = new Map<string, SharedConnection>();\n\nfunction releaseListener(ingestionId: string, conn: SharedConnection, listener: Listener) {\n conn.listeners.delete(listener);\n\n // Last subscriber leaving → actually tear down the socket.\n if (conn.listeners.size === 0 && sharedConnections.get(ingestionId) === conn) {\n clearInterval(conn.keepAliveInterval);\n if (conn.ws.readyState === WebSocket.OPEN || conn.ws.readyState === WebSocket.CONNECTING) {\n conn.ws.close();\n }\n sharedConnections.delete(ingestionId);\n }\n}\n\nfunction getOrCreateConnection(ingestionId: string, wsBaseUrl?: string): SharedConnection | null {\n if (!wsBaseUrl || typeof wsBaseUrl !== \"string\" || !wsBaseUrl.trim()) {\n console.error(\"useIngestionWebSocket: wsBaseUrl is missing or invalid; skipping connection.\");\n return null;\n }\n\n const existing = sharedConnections.get(ingestionId);\n if (existing && existing.ws.readyState !== WebSocket.CLOSED) {\n return existing;\n }\n\n const ws = new WebSocket(`${wsBaseUrl.trim()}/${ingestionId}`);\n const conn: SharedConnection = {\n ws,\n listeners: new Set(),\n lastData: null,\n keepAliveInterval: setInterval(() => {\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify({ type: \"ping\" }));\n }\n }, 5000),\n };\n\n ws.onmessage = (event) => {\n let rawData: unknown;\n try {\n rawData = JSON.parse(event.data);\n } catch {\n conn.listeners.forEach((listener) => listener(null, \"Failed to parse WebSocket message\"));\n return;\n }\n\n if (!isValidIngestionPayload(rawData)) {\n conn.listeners.forEach((listener) => listener(null, \"Received malformed WebSocket payload\"));\n return;\n }\n\n // Bind to a const so the narrowed type survives inside the closures below —\n // `let` bindings get widened back to their declared type inside closures\n // since TS can't prove they won't be reassigned before the closure runs.\n const payload: WebSocketIngestionData = rawData;\n\n conn.lastData = payload;\n conn.listeners.forEach((listener) => listener(payload, null));\n\n if (TERMINAL_STATUSES.has(payload.ingestionStatus.toUpperCase())) {\n clearInterval(conn.keepAliveInterval);\n ws.close();\n sharedConnections.delete(ingestionId);\n }\n};\n\n ws.onerror = () => {\n conn.listeners.forEach((listener) => listener(null, \"WebSocket connection error\"));\n };\n\n ws.onclose = () => {\n clearInterval(conn.keepAliveInterval);\n // Only remove from the registry if this is still the active connection\n // for this id (avoids racing a newer reconnect attempt).\n if (sharedConnections.get(ingestionId) === conn) {\n sharedConnections.delete(ingestionId);\n }\n };\n\n sharedConnections.set(ingestionId, conn);\n return conn;\n}\n\nexport function useIngestionWebSocket(ingestionId: string | null, wsBaseUrl?: string) {\n const [data, setData] = useState<WebSocketIngestionData | null>(null);\n const [connected, setConnected] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n // Track the current connection + listener so the imperative disconnect()\n // below can unsubscribe/close outside of the effect's own cleanup.\n const connRef = useRef<SharedConnection | null>(null);\n const listenerRef = useRef<Listener | null>(null);\n const ingestionIdRef = useRef<string | null>(ingestionId);\n\n useEffect(() => {\n ingestionIdRef.current = ingestionId;\n }, [ingestionId]);\n\n const disconnect = useCallback(() => {\n const currentId = ingestionIdRef.current;\n if (currentId && connRef.current && listenerRef.current) {\n releaseListener(currentId, connRef.current, listenerRef.current);\n }\n connRef.current = null;\n listenerRef.current = null;\n setConnected(false);\n }, []);\n\n useEffect(() => {\n if (!ingestionId) return;\n\n setError(null);\n\n const conn = getOrCreateConnection(ingestionId, wsBaseUrl);\n if (!conn) {\n setError(\"Missing or invalid WebSocket base URL\");\n setConnected(false);\n return;\n }\n\n // Seed with whatever the shared connection already has, so a late\n // subscriber isn't stuck blank until the next message arrives.\n if (conn.lastData) setData(conn.lastData);\n setConnected(conn.ws.readyState === WebSocket.OPEN);\n\n const listener: Listener = (newData, newError) => {\n if (newError) {\n setError(newError);\n return;\n }\n setData(newData);\n };\n\n conn.listeners.add(listener);\n connRef.current = conn;\n listenerRef.current = listener;\n\n const handleOpen = () => setConnected(true);\n const handleClose = () => setConnected(false);\n conn.ws.addEventListener(\"open\", handleOpen);\n conn.ws.addEventListener(\"close\", handleClose);\n\n return () => {\n conn.ws.removeEventListener(\"open\", handleOpen);\n conn.ws.removeEventListener(\"close\", handleClose);\n releaseListener(ingestionId, conn, listener);\n connRef.current = null;\n listenerRef.current = null;\n };\n }, [ingestionId, wsBaseUrl]);\n\n return { data, connected, error, disconnect };\n}"],"names":["TERMINAL_STATUSES","Set","sharedConnections","Map","releaseListener","ingestionId","conn","listener","listeners","delete","size","get","clearInterval","keepAliveInterval","ws","readyState","WebSocket","OPEN","CONNECTING","close","useIngestionWebSocket","wsBaseUrl","data","setData","useState","connected","setConnected","error","setError","connRef","useRef","listenerRef","ingestionIdRef","useEffect","current","disconnect","useCallback","currentId","trim","console","existing","CLOSED","lastData","setInterval","send","JSON","stringify","type","onmessage","event","rawData","parse","forEach","value","candidate","ingestionStatus","isValidIngestionPayload","payload","has","toUpperCase","onerror","onclose","set","getOrCreateConnection","newData","newError","add","handleOpen","handleClose","addEventListener","removeEventListener"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useIngestionStatus.js","sources":["../../../src/features/IngestionStatus/useIngestionStatus.tsx"],"sourcesContent":["import { useState, useEffect, useCallback, useRef } from \"react\";\n\nexport interface ArtifactLayer {\n label: string;\n layerStatus: string;\n currentProgress: number;\n chunks: { total: number; completed: number; failed: number };\n}\n\nexport interface Artifact {\n artifactId: string;\n name: string;\n status: string;\n artifactSize: string;\n layers: ArtifactLayer[];\n}\n\nexport interface WebSocketIngestionData {\n ingestionStatus: string;\n ingestionId: string;\n currentProgress: number;\n createdAt: string;\n completedAt?: string | null;\n eta?: string | null;\n artifacts: Artifact[];\n total_artifacts?: number;\n layer_orchestration_count?: number;\n artifactStatus?: {\n \"in-progress\": number;\n completed: number;\n queued: number;\n };\n}\n\nconst TERMINAL_STATUSES = new Set([\"DONE\", \"COMPLETED\", \"FAILED\"]);\n\n// Minimal runtime shape check for incoming WS payloads. We don't pull in a\n// full schema library for one message type — just guard the fields we\n// actually branch on (ingestionStatus) and require an object shape overall.\nfunction isValidIngestionPayload(value: unknown): value is WebSocketIngestionData {\n if (!value || typeof value !== \"object\") return false;\n const candidate = value as Record<string, unknown>;\n return typeof candidate.ingestionStatus === \"string\" && typeof candidate.ingestionId === \"string\";\n}\n\n// --- Shared connection registry -------------------------------------------\n// One real WebSocket per ingestionId, fanned out to any number of subscribers.\n// This lets multiple TimelineItem/IngestionStatusComponent instances that\n// happen to share the same ingestionId (e.g. a batched multi-file upload)\n// observe the same socket instead of each opening (and closing) their own.\ntype Listener = (data: WebSocketIngestionData | null, error: string | null) => void;\n\ninterface SharedConnection {\n ws: WebSocket;\n keepAliveInterval: ReturnType<typeof setInterval>;\n listeners: Set<Listener>;\n lastData: WebSocketIngestionData | null;\n}\n\nconst sharedConnections = new Map<string, SharedConnection>();\n\nfunction releaseListener(ingestionId: string, conn: SharedConnection, listener: Listener) {\n conn.listeners.delete(listener);\n\n // Last subscriber leaving → actually tear down the socket.\n if (conn.listeners.size === 0 && sharedConnections.get(ingestionId) === conn) {\n clearInterval(conn.keepAliveInterval);\n if (conn.ws.readyState === WebSocket.OPEN || conn.ws.readyState === WebSocket.CONNECTING) {\n conn.ws.close();\n }\n sharedConnections.delete(ingestionId);\n }\n}\n\nfunction getOrCreateConnection(ingestionId: string, wsBaseUrl?: string, authToken?: string): SharedConnection | null {\n if (!wsBaseUrl || typeof wsBaseUrl !== \"string\" || !wsBaseUrl.trim()) {\n console.error(\"useIngestionWebSocket: wsBaseUrl is missing or invalid; skipping connection.\");\n return null;\n }\n\n const existing = sharedConnections.get(ingestionId);\n if (existing && existing.ws.readyState !== WebSocket.CLOSED) {\n return existing;\n }\n let wsUrl = `${wsBaseUrl.trim()}/${ingestionId}`;\n if(authToken){\n wsUrl+=`?token=${authToken}`;\n }\n\n const ws = new WebSocket(wsUrl);\n const conn: SharedConnection = {\n ws,\n listeners: new Set(),\n lastData: null,\n keepAliveInterval: setInterval(() => {\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify({ type: \"ping\" }));\n }\n }, 5000),\n };\n\n ws.onmessage = (event) => {\n let rawData: unknown;\n try {\n rawData = JSON.parse(event.data);\n } catch {\n conn.listeners.forEach((listener) => listener(null, \"Failed to parse WebSocket message\"));\n return;\n }\n\n if (!isValidIngestionPayload(rawData)) {\n conn.listeners.forEach((listener) => listener(null, \"Received malformed WebSocket payload\"));\n return;\n }\n\n // Bind to a const so the narrowed type survives inside the closures below —\n // `let` bindings get widened back to their declared type inside closures\n // since TS can't prove they won't be reassigned before the closure runs.\n const payload: WebSocketIngestionData = rawData;\n\n conn.lastData = payload;\n conn.listeners.forEach((listener) => listener(payload, null));\n\n if (TERMINAL_STATUSES.has(payload.ingestionStatus.toUpperCase())) {\n clearInterval(conn.keepAliveInterval);\n ws.close();\n sharedConnections.delete(ingestionId);\n }\n};\n\n ws.onerror = () => {\n conn.listeners.forEach((listener) => listener(null, \"WebSocket connection error\"));\n };\n\n ws.onclose = () => {\n clearInterval(conn.keepAliveInterval);\n // Only remove from the registry if this is still the active connection\n // for this id (avoids racing a newer reconnect attempt).\n if (sharedConnections.get(ingestionId) === conn) {\n sharedConnections.delete(ingestionId);\n }\n };\n\n sharedConnections.set(ingestionId, conn);\n return conn;\n}\n\nexport function useIngestionWebSocket(ingestionId: string | null, wsBaseUrl?: string, authToken?: string) {\n const [data, setData] = useState<WebSocketIngestionData | null>(null);\n const [connected, setConnected] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n // Track the current connection + listener so the imperative disconnect()\n // below can unsubscribe/close outside of the effect's own cleanup.\n const connRef = useRef<SharedConnection | null>(null);\n const listenerRef = useRef<Listener | null>(null);\n const ingestionIdRef = useRef<string | null>(ingestionId);\n\n useEffect(() => {\n ingestionIdRef.current = ingestionId;\n }, [ingestionId]);\n\n const disconnect = useCallback(() => {\n const currentId = ingestionIdRef.current;\n if (currentId && connRef.current && listenerRef.current) {\n releaseListener(currentId, connRef.current, listenerRef.current);\n }\n connRef.current = null;\n listenerRef.current = null;\n setConnected(false);\n }, []);\n\n useEffect(() => {\n if (!ingestionId) return;\n\n setError(null);\n\n const conn = getOrCreateConnection(ingestionId, wsBaseUrl, authToken);\n if (!conn) {\n setError(\"Missing or invalid WebSocket base URL\");\n setConnected(false);\n return;\n }\n\n // Seed with whatever the shared connection already has, so a late\n // subscriber isn't stuck blank until the next message arrives.\n if (conn.lastData) setData(conn.lastData);\n setConnected(conn.ws.readyState === WebSocket.OPEN);\n\n const listener: Listener = (newData, newError) => {\n if (newError) {\n setError(newError);\n return;\n }\n setData(newData);\n };\n\n conn.listeners.add(listener);\n connRef.current = conn;\n listenerRef.current = listener;\n\n const handleOpen = () => setConnected(true);\n const handleClose = () => setConnected(false);\n conn.ws.addEventListener(\"open\", handleOpen);\n conn.ws.addEventListener(\"close\", handleClose);\n\n return () => {\n conn.ws.removeEventListener(\"open\", handleOpen);\n conn.ws.removeEventListener(\"close\", handleClose);\n releaseListener(ingestionId, conn, listener);\n connRef.current = null;\n listenerRef.current = null;\n };\n }, [ingestionId, wsBaseUrl]);\n\n return { data, connected, error, disconnect };\n}"],"names":["TERMINAL_STATUSES","Set","sharedConnections","Map","releaseListener","ingestionId","conn","listener","listeners","delete","size","get","clearInterval","keepAliveInterval","ws","readyState","WebSocket","OPEN","CONNECTING","close","useIngestionWebSocket","wsBaseUrl","authToken","data","setData","useState","connected","setConnected","error","setError","connRef","useRef","listenerRef","ingestionIdRef","useEffect","current","disconnect","useCallback","currentId","trim","console","existing","CLOSED","wsUrl","lastData","setInterval","send","JSON","stringify","type","onmessage","event","rawData","parse","forEach","value","candidate","ingestionStatus","isValidIngestionPayload","payload","has","toUpperCase","onerror","onclose","set","getOrCreateConnection","newData","newError","add","handleOpen","handleClose","addEventListener","removeEventListener"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{jsx as e,jsxs as t,Fragment as
|
|
1
|
+
import{jsx as e,jsxs as t,Fragment as n}from"react/jsx-runtime";import{SpecialZoomLevel as r}from"@react-pdf-viewer/core";import o from"./PdfContainer.js";import i from"./PdfToolbar.js";import{pdfStyles as a}from"./PdfStyle.js";import{PdfHighlightControls as s}from"./usePdfHighlight.js";import{rotationManager as c}from"./rotationManager.js";import"@react-pdf-viewer/zoom/lib/styles/index.css";import"@react-pdf-viewer/page-navigation/lib/styles/index.css";import"@react-pdf-viewer/core/lib/styles/index.css";import"@react-pdf-viewer/search/lib/styles/index.css";import l,{useRef as u,useState as d,useMemo as g,useEffect as h}from"react";import p from"../ScannedDocCitation/ScannedDocCitation.js";import"./PdfViewer.css.js";const f=({pdfUrl:f,highlightText:m,highlightPages:v,highlightCordinatePages:w,highlightColor:x="yellow",activeHighlightColor:y="#f7dc51",jumpToPageValue:P,pdfName:b,onClose:T,customStyles:C,customClasses:I,customIcons:S,useCoordinates:A,fallbackPages:R,activeCitationIndex:_,onActiveCitationChange:F,headerAction:N,isZoomEnabled:j=!0,showHighlightsAction:q=!0,defaultScale:L=r.ActualSize,useRange:H=!1,rangeOfPages:B=null,showFullScreenAction:E=!0,showRotateButton:M=!1,segments:V=[{title:"Document 2",start_page:52,end_page:52,page_count:1}],segmentTooltipText:k,onCurrentPageChange:z,navigationRequest:D,onNavigationSettled:W,disablePdfAnnotations:O=!1,disablePdfTextLayer:U=!1,renderPage:$,setRenderRange:Z,onError:J})=>{const K=u(null),G=(e=>{switch(e){case"ActualSize":return r.ActualSize;case"PageFit":return r.PageFit;case"PageWidth":return r.PageWidth;default:return e??r.PageWidth}})(L),Q=P??(A&&w.length>0?1:0),[X,Y]=d(0),[ee,te]=d(0),[ne,re]=d(null),[oe,ie]=d(0),ae=u(null),se=u(null),ce=u(0),le=u(null),ue=u(null),de=g(()=>{if(!f)return"";try{return new URL(f,window.location.origin).pathname.split("/").pop()||"default"}catch{return"default"}},[f]);h(()=>{de&&c.setPdfIdentifier(de)},[de]);h(()=>c.onRotationChange((e,t)=>{e===X+1&&ie(t)}),[X]),h(()=>{const e=new MutationObserver(()=>{const e=K.current?.querySelectorAll('[data-testid^="core__page-layer-"]'),t=new Set;e?.forEach(e=>{const n=e.getAttribute("data-testid")?.match(/core__page-layer-(\d+)/);if(n&&n.length>=2){const r=parseInt(n[1],10)+1;t.has(r)||(c.registerPageElement(r,e),t.add(r))}})});return K.current&&(e.observe(K.current,{childList:!0,subtree:!0,attributes:!1}),le.current=e),()=>{e.disconnect(),le.current=null}},[]),h(()=>()=>{c.clearAll(),le.current&&le.current.disconnect()},[]),h(()=>{const e=X+1;ie(c.getRotation(e))},[X]);const ge=g(()=>O||U?r=>{const o=U?e("div",{"aria-hidden":"true",style:{display:"none"},children:r.textLayer.children}):r.textLayer.children,i={...r,annotationLayer:{...r.annotationLayer,children:O?null:r.annotationLayer.children},textLayer:{...r.textLayer,children:o}};return $?$(i):t(n,{children:[r.canvasLayer.children,o,!O&&r.annotationLayer.children]})}:$,[O,U,$]),he=g(()=>{if(A)return new Set(w.map(e=>e.pageIndex));{const e=new Set;return Object.values(v).forEach(t=>{t>0&&e.add(t-1)}),e}},[w,v,A]),pe=(fe=m)&&0!==fe.length?fe.filter(e=>!fe.some(t=>t!==e&&t.includes(e))):fe;var fe;const{highlightIndex:me,setHighlightIndex:ve,cursorIndex:we,setCursorIndex:xe,orderedKeys:ye,totalHighlights:Pe,getValidPosition:be,tryJump:Te,jumpToPage:Ce,zoomTo:Ie,plugins:Se,controls:Ae,hideNonTargetHighlights:Re,deduplicateHighlights:_e,scrollToCoordAfterNav:Fe}=s(pe,A?{}:v,K,he,A,A?w:[],x,y);h(()=>{if(!A||H||ee<=0||ne!==(f??null))return;const e=Q-1,t=w[e];if(!t||t.pageIndex<0||t.pageIndex>=ee)return;const n=[f,e,t.pageIndex,t.top,t.height].join(":");ue.current!==n&&(ue.current=n,xe(e),Ce(t.pageIndex),Fe(t.pageIndex,t.top,t.height))},[w,Ce,ne,f,Q,Fe,xe,ee,A,H]);const Ne=be(we),je=g(()=>{const e=X+1;return V.find(t=>e>=t.start_page&&e<=t.end_page)},[X,V]);h(()=>{void 0!==_&&_!==we&&xe(_)},[_]);const qe={...Ae,goToNext:()=>{if(we>=Pe-1)return;const e=we+1;if(A){const t=w[e];if(!t)return;xe(e),Ce(t.pageIndex),Fe(t.pageIndex,Number.isFinite(t.top)?t.top:0,Number.isFinite(t.height)?t.height:0)}else Ae.goToNext();F?.(e)},goToPrevious:()=>{if(we<=0)return;const e=we-1;if(A){const t=w[e];if(!t)return;xe(e),Ce(t.pageIndex),Fe(t.pageIndex,Number.isFinite(t.top)?t.top:0,Number.isFinite(t.height)?t.height:0)}else Ae.goToPrevious();F?.(e)}},Le=l.useCallback((e,t)=>{ce.current+=1;const n=ce.current;null!=se.current&&window.clearTimeout(se.current);let r=null,o=0,i=0;const a=()=>{if(ce.current!==n)return;i+=1;const s=K.current?.querySelector(".rpv-core__inner-pages"),c=K.current?.querySelector(`[data-testid="core__page-layer-${t-1}"]`);if(!s||!c)return i>=40?(se.current=null,void W?.({pageNumber:t,requestId:e.requestId})):void(se.current=window.setTimeout(a,50));r===s.scrollTop?o+=1:(r=s.scrollTop,o=0);const l=s.getBoundingClientRect(),u=c.getBoundingClientRect(),d=Boolean(l&&u&&u.bottom>l.top&&u.top<l.bottom);if(o>=2&&d||i>=40)return se.current=null,void W?.({pageNumber:t,requestId:e.requestId});se.current=window.setTimeout(a,50)};se.current=window.setTimeout(a,50)},[W]);if(h(()=>()=>{ce.current+=1,null!=se.current&&window.clearTimeout(se.current)},[]),h(()=>{if(!D||ee<=0)return;const e=Math.min(Math.max(Math.trunc(D.pageNumber),1),ee),t=`${D.requestId??e}:${e}`;ae.current!==t&&(ae.current=t,Y(e-1),Ce(e-1),Le(D,e))},[Ce,D,ee,Le]),!f)return e(p,{pages:R,activeCitationIndex:_,onActiveCitationChange:F,headerAction:N});return t("div",{ref:K,className:["citation-pdf-viewer",I?.pdfViewerWrapper].filter(Boolean).join(" "),"data-disable-pdf-annotations":O?"true":void 0,"data-pdf-page-fit":G===r.PageFit?"true":void 0,style:{height:"100%",minHeight:0,minWidth:0,overflow:"hidden",display:"flex",flexDirection:"column",...a.pdfViewer,display:"flex",flexDirection:"column",height:"100%",width:"100%",backgroundColor:"#FAFAFA",...C?.pdfViewer,backgroundColor:"#F1F5F9"},children:[e(i,{highlightIndex:me,totalHighlights:Pe,controls:qe,currentPosition:Ne,pdfName:b,onClose:T,pdfUrl:f,viewerRef:K,customStyles:C,customClasses:I,customIcons:S,headerAction:N,isZoomEnabled:j,showHighlightsAction:q,showFullScreenAction:E,currentSegment:je,segmentTooltipText:k,currentPage:X+1,totalPages:ee,onPageNavigate:e=>{const t=Math.min(Math.max(e,1),ee||e);Y(t-1),Ce(t-1)},onRotatePage:()=>{const e=X+1;c.rotatePageBy90(e),ie(c.getRotation(e))},currentPageRotation:oe,showRotateButton:M}),e(o,{defaultScale:G,pdfUrl:f,plugins:Se,customStyles:C,onError:J,onLoad:e=>{te(e.doc.numPages),re(f??null);const t=!A&&!H&&Q<=0;if(!A&&Q>0&&!H){const e=Q-1,t=ye[e],n=void 0!==t?v?.[t]:void 0;xe(e),n>0&&(setTimeout(()=>{Re(he),_e(n-1)},1e3),Ce(n-1))}else if(H&&B&&2===B.length){(async()=>{const[e,t]=B;for(let n=e;n<=t;n++){const e=n-1;Ce(e),await new Promise(e=>setTimeout(e,1e3)),Re(he);const t=_e(e);if(t&&t>0)break}})()}else if(!A&&v){const e=ye.find(e=>v[e]>0);if(void 0!==e){const t=v[e]-1;Ce(t),setTimeout(()=>{Re(he),_e(t)},1e3)}}requestAnimationFrame(()=>{t&&Te(),!A&&Q>0&&!H&&(()=>{if(!K.current)return;const e=Q-1,t=ye[e],n=v[t],r=n>0?n-1:0,o={};ye.forEach((e,t)=>{const n=v[e];n>0&&(o[n]||(o[n]=[]),o[n].push(t))});const i=(o[n]||[]).indexOf(e);let a=0;const s=()=>{if(a++,a>40)return;const e=K.current?.querySelector(".rpv-core__inner-pages");if(!e)return void setTimeout(s,100);const t=K.current?.querySelector(`[data-testid="core__page-layer-${r}"]`);if(!t)return void setTimeout(s,100);const n=e.getBoundingClientRect(),o=t.getBoundingClientRect();if(!(o.top<n.bottom&&o.bottom>n.top))return void setTimeout(s,100);const c=t.querySelectorAll(".rpv-search__highlight")[i];if(!c)return void setTimeout(s,100);const l=c.getBoundingClientRect(),u=e.scrollTop+(l.top-n.top)-e.clientHeight/2+l.height/2;e.scrollTo({top:u,behavior:"smooth"})};setTimeout(s,500)})()})},onPageChange:e=>{const t=e.currentPage;Y(t),z?.(t+1),he.has(t)?(_e(t),Re(he)):Re(he)},renderPage:ge,setRenderRange:Z})]})};export{f as default};
|
|
2
2
|
//# sourceMappingURL=PdfViewer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PdfViewer.js","sources":["../../../src/features/PdfViewer/PdfViewer.tsx"],"sourcesContent":["import { DocumentLoadEvent, PageChangeEvent, RenderPage, SetRenderRange, SpecialZoomLevel, type LoadError } from \"@react-pdf-viewer/core\";\nimport PdfContainer from \"./PdfContainer\";\nimport PdfToolbar from \"./PdfToolbar\";\nimport { pdfStyles } from \"./PdfStyle\";\nimport { PdfHighlightControls } from \"./usePdfHighlight\";\nimport { rotationManager } from \"./rotationManager\";\nimport \"@react-pdf-viewer/zoom/lib/styles/index.css\";\nimport \"@react-pdf-viewer/page-navigation/lib/styles/index.css\";\nimport \"@react-pdf-viewer/core/lib/styles/index.css\";\nimport \"@react-pdf-viewer/search/lib/styles/index.css\";\nimport React, { useMemo, useRef, useEffect, useState } from \"react\";\nimport ScannedDocCitation, { CitationPage } from \"../ScannedDocCitation/ScannedDocCitation\";\nimport \"./PdfViewer.css\";\n\nexport type CustomIconsType = {\n pdfIcon?: React.ReactNode;\n fullScreenIcon?: React.ReactNode;\n downloadIcon?: React.ReactNode;\n closeIcon?: React.ReactNode;\n};\n\nexport type CustomStylesType = {\n pdfViewer?: React.CSSProperties;\n header?: React.CSSProperties;\n pdfIconWrapper?: React.CSSProperties;\n pdfName?: React.CSSProperties;\n pdfContainer?: React.CSSProperties;\n emptyState?: React.CSSProperties;\n};\n\nexport type CustomClassesType = {\n header?: string;\n pdfName?: string;\n actionButton?: string;\n pdfViewerWrapper?: string;\n};\n\nexport type PdfSegment = {\n title: string;\n start_page: number;\n end_page: number;\n page_count: number;\n};\n\ntype PdfScaleOption =\n | \"ActualSize\"\n | \"PageFit\"\n | \"PageWidth\"\n | number;\nexport interface PdfNavigationRequest {\n pageNumber: number;\n /** Change this value to navigate to the same page more than once. */\n requestId?: string | number;\n}\n\nexport interface PdfNavigationSettledEvent extends PdfNavigationRequest {\n pageNumber: number;\n}\n\nexport interface PdfViewerProps {\n pdfUrl?: string;\n highlightText: string[];\n highlightPages?: any;\n highlightCordinatePages: HighlightArea[];\n highlightColor?: string;\n activeHighlightColor?: string;\n jumpToPageValue?: number;\n pdfName?: string;\n onClose?: () => void;\n item?: any;\n customStyles?: CustomStylesType;\n customClasses?: CustomClassesType;\n customIcons?: CustomIconsType;\n useCoordinates: boolean;\n fallbackPages?: CitationPage[];\n activeCitationIndex?: number;\n onActiveCitationChange?: (index: number) => void;\n headerAction?: {\n icon?: React.ReactNode;\n onClick?: () => void;\n tooltip?: string;\n };\n isZoomEnabled?: boolean;\n showHighlightsAction?: boolean;\n defaultScale?: PdfScaleOption;\n useRange?: boolean; //\n rangeOfPages?: number[] | null;\n showFullScreenAction?: boolean;\n showRotateButton?: boolean;\n segments?: PdfSegment[];\n segmentTooltipText?: string;\n onCurrentPageChange?: (pageNumber: number) => void;\n navigationRequest?: PdfNavigationRequest | null;\n onNavigationSettled?: (event: PdfNavigationSettledEvent) => void;\n disablePdfAnnotations?: boolean;\n disablePdfTextLayer?: boolean;\n renderPage?: RenderPage;\n setRenderRange?: SetRenderRange;\n onError?: (error: LoadError) => void;\n}\n\nconst getResolvedScale = (\n scale?: PdfScaleOption\n): SpecialZoomLevel | number => {\n switch (scale) {\n case \"ActualSize\":\n return SpecialZoomLevel.ActualSize;\n\n case \"PageFit\":\n return SpecialZoomLevel.PageFit;\n\n case \"PageWidth\":\n return SpecialZoomLevel.PageWidth;\n\n default:\n return scale ?? SpecialZoomLevel.PageWidth;\n }\n};\n\nexport type HighlightArea = {\n pageIndex: number;\n left: number;\n top: number;\n width: number;\n height: number;\n pageNumber?: number;\n};\n\nconst PdfViewer = ({\n pdfUrl,\n highlightText,\n highlightPages,\n highlightCordinatePages,\n highlightColor = \"yellow\",\n activeHighlightColor = \"#f7dc51\",\n jumpToPageValue = 0,\n pdfName,\n onClose,\n customStyles,\n customClasses,\n customIcons,\n useCoordinates,\n fallbackPages,\n activeCitationIndex,\n onActiveCitationChange,\n headerAction,\n isZoomEnabled = true,\n showHighlightsAction = true,\n defaultScale = SpecialZoomLevel.ActualSize,\n useRange = false,\n rangeOfPages = null,\n showFullScreenAction=true,\n showRotateButton = false,\n segments = [\n {\n title: \"Document 2\",\n start_page: 52,\n end_page: 52,\n page_count: 1,\n },\n ],\n segmentTooltipText,\n onCurrentPageChange,\n navigationRequest,\n onNavigationSettled,\n disablePdfAnnotations = false,\n disablePdfTextLayer = false,\n renderPage,\n setRenderRange,\n onError\n}: PdfViewerProps) => {\n\n const viewerRef = useRef<HTMLDivElement | null>(null);\n const resolvedDefaultScale = getResolvedScale(defaultScale);\n const [currentPage, setCurrentPage] = useState(0);\n const [totalPages, setTotalPages] = useState(0);\n const [currentPageRotation, setCurrentPageRotation] = useState(0);\n const lastNavigationRequestRef = useRef<string | null>(null);\n const navigationSettleTimerRef = useRef<number | null>(null);\n const navigationSettleSequenceRef = useRef(0);\n const mutationObserverRef = useRef<MutationObserver | null>(null);\n\n // Generate PDF identifier for localStorage from URL\n const pdfIdentifier = useMemo(() => {\n if (!pdfUrl) return '';\n // Use last part of URL or hash it\n try {\n const url = new URL(pdfUrl, window.location.origin);\n return url.pathname.split('/').pop() || 'default';\n } catch {\n return 'default';\n }\n }, [pdfUrl]);\n\n // Set up rotation manager with PDF identifier\n useEffect(() => {\n if (pdfIdentifier) {\n rotationManager.setPdfIdentifier(pdfIdentifier);\n }\n }, [pdfIdentifier]);\n\n // Handler for rotating current page (no state update)\n const handleRotatePage = () => {\n const pageNumber = currentPage + 1;\n rotationManager.rotatePageBy90(pageNumber);\n // Manually update state to reflect rotation in UI\n setCurrentPageRotation(rotationManager.getRotation(pageNumber));\n };\n\n // Subscribe to rotation changes to sync UI state\n useEffect(() => {\n const unsubscribe = rotationManager.onRotationChange((pageNum, angle) => {\n // Only update state if current page rotated\n if (pageNum === currentPage + 1) {\n setCurrentPageRotation(angle);\n }\n });\n\n return unsubscribe;\n }, [currentPage]);\n\n // Register page elements with rotation manager\n useEffect(() => {\n const observer = new MutationObserver(() => {\n // Find all newly rendered page elements\n const pageElements = viewerRef.current?.querySelectorAll(\n '[data-testid^=\"core__page-layer-\"]'\n );\n\n const registeredPages = new Set<number>();\n\n pageElements?.forEach((pageElement) => {\n const match = (pageElement as HTMLElement)\n .getAttribute('data-testid')\n ?.match(/core__page-layer-(\\d+)/);\n if (match && match.length >= 2) {\n const pageIndex = parseInt(match[1], 10);\n const pageNumber = pageIndex + 1;\n\n // Only register once per page\n if (!registeredPages.has(pageNumber)) {\n rotationManager.registerPageElement(pageNumber, pageElement as HTMLElement);\n registeredPages.add(pageNumber);\n }\n }\n });\n });\n\n if (viewerRef.current) {\n observer.observe(viewerRef.current, {\n childList: true,\n subtree: true,\n attributes: false,\n });\n mutationObserverRef.current = observer;\n }\n\n return () => {\n observer.disconnect();\n mutationObserverRef.current = null;\n };\n }, []);\n\n // Clean up when unmounting\n useEffect(() => {\n return () => {\n rotationManager.clearAll();\n if (mutationObserverRef.current) {\n mutationObserverRef.current.disconnect();\n }\n };\n }, []);\n\n // Update current page rotation when page changes\n useEffect(() => {\n const pageNumber = currentPage + 1;\n setCurrentPageRotation(rotationManager.getRotation(pageNumber));\n }, [currentPage]);\n const resolvedRenderPage = useMemo<RenderPage | undefined>(() => {\n if (!disablePdfAnnotations && !disablePdfTextLayer) return renderPage;\n\n return (props) => {\n const resolvedTextLayerChildren = disablePdfTextLayer ? (\n <div aria-hidden=\"true\" style={{ display: \"none\" }}>\n {props.textLayer.children}\n </div>\n ) : props.textLayer.children;\n const resolvedProps = {\n ...props,\n annotationLayer: {\n ...props.annotationLayer,\n children: disablePdfAnnotations ? null : props.annotationLayer.children,\n },\n textLayer: {\n ...props.textLayer,\n children: resolvedTextLayerChildren,\n },\n };\n\n const renderedPage = renderPage\n ? renderPage(resolvedProps)\n : (\n <>\n {props.canvasLayer.children}\n {resolvedTextLayerChildren}\n {!disablePdfAnnotations && props.annotationLayer.children}\n </>\n );\n\n return renderedPage;\n };\n }, [disablePdfAnnotations, disablePdfTextLayer, renderPage]);\n\n const cleanHighlightTexts = (texts: string[]): string[] => {\n if (!texts || texts.length === 0) return texts;\n return texts.filter((text) => {\n return !texts.some(\n (otherText) => otherText !== text && otherText.includes(text)\n );\n });\n };\n\n const highlightPageSet = useMemo(() => {\n if (useCoordinates) {\n return new Set(highlightCordinatePages.map((h: any) => h.pageIndex));\n } else {\n const set = new Set<number>();\n Object.values(highlightPages).forEach((p: any) => {\n if (p > 0) set.add(p - 1);\n });\n return set;\n }\n }, [highlightCordinatePages, highlightPages, useCoordinates]);\n\n const removeRedundantHighlightTexts = cleanHighlightTexts(highlightText);\n\n const {\n highlightIndex,\n setHighlightIndex,\n cursorIndex,\n setCursorIndex,\n orderedKeys,\n totalHighlights,\n getValidPosition,\n tryJump,\n jumpToPage,\n zoomTo,\n plugins,\n controls,\n hideNonTargetHighlights,\n deduplicateHighlights,\n scrollToCoord,\n } = PdfHighlightControls(\n removeRedundantHighlightTexts,\n !useCoordinates ? highlightPages : {},\n viewerRef,\n highlightPageSet,\n useCoordinates,\n useCoordinates ? highlightCordinatePages : [],\n highlightColor,\n activeHighlightColor\n );\n\n const currentPosition = getValidPosition(cursorIndex);\n const currentSegment = useMemo(() => {\n const pageNumber = currentPage + 1;\n return segments.find(\n (segment) =>\n pageNumber >= segment.start_page && pageNumber <= segment.end_page\n );\n }, [currentPage, segments]);\n\n // sync external activeCitationIndex → cursorIndex\n useEffect(() => {\n if (activeCitationIndex === undefined) return;\n if (activeCitationIndex === cursorIndex) return;\n setCursorIndex(activeCitationIndex);\n }, [activeCitationIndex]);\n\n // wrap controls to fire onActiveCitationChange\n const handleGoToNext = () => {\n if (cursorIndex >= totalHighlights - 1) return;\n controls.goToNext();\n if (onActiveCitationChange) onActiveCitationChange(cursorIndex + 1);\n };\n\n const handleGoToPrevious = () => {\n if (cursorIndex <= 0) return;\n controls.goToPrevious();\n if (onActiveCitationChange) onActiveCitationChange(cursorIndex - 1);\n };\n\n const modifiedControls = {\n ...controls,\n goToNext: handleGoToNext,\n goToPrevious: handleGoToPrevious,\n };\n\n const handlePageNavigate = (pageNumber: number) => {\n const nextPage = Math.min(Math.max(pageNumber, 1), totalPages || pageNumber);\n setCurrentPage(nextPage - 1);\n jumpToPage(nextPage - 1);\n };\n\n const waitForNavigationToSettle = React.useCallback((\n request: PdfNavigationRequest,\n pageNumber: number\n ) => {\n navigationSettleSequenceRef.current += 1;\n const settleSequence = navigationSettleSequenceRef.current;\n if (navigationSettleTimerRef.current != null) {\n window.clearTimeout(navigationSettleTimerRef.current);\n }\n\n let previousScrollTop: number | null = null;\n let stableChecks = 0;\n let attempts = 0;\n\n const checkScrollPosition = () => {\n if (navigationSettleSequenceRef.current !== settleSequence) return;\n\n attempts += 1;\n\n const scrollContainer = viewerRef.current?.querySelector(\n '.rpv-core__inner-pages'\n ) as HTMLElement | null;\n const targetPage = viewerRef.current?.querySelector(\n `[data-testid=\"core__page-layer-${pageNumber - 1}\"]`\n ) as HTMLElement | null;\n\n // Virtualized page layers are not guaranteed to be mounted on the first\n // check after jumpToPage. Keep polling so navigation completion is not\n // lost while React PDF Viewer is creating the target page DOM.\n if (!scrollContainer || !targetPage) {\n if (attempts >= 40) {\n navigationSettleTimerRef.current = null;\n onNavigationSettled?.({\n pageNumber,\n requestId: request.requestId,\n });\n return;\n }\n\n navigationSettleTimerRef.current = window.setTimeout(checkScrollPosition, 50);\n return;\n }\n\n if (previousScrollTop === scrollContainer.scrollTop) {\n stableChecks += 1;\n } else {\n previousScrollTop = scrollContainer.scrollTop;\n stableChecks = 0;\n }\n\n const scrollRect = scrollContainer.getBoundingClientRect();\n const pageRect = targetPage.getBoundingClientRect();\n const isTargetVisible = Boolean(\n scrollRect &&\n pageRect &&\n pageRect.bottom > scrollRect.top &&\n pageRect.top < scrollRect.bottom\n );\n const hasSettled = stableChecks >= 2 && isTargetVisible;\n const reachedTimeout = attempts >= 40;\n\n if (hasSettled || reachedTimeout) {\n navigationSettleTimerRef.current = null;\n onNavigationSettled?.({\n pageNumber,\n requestId: request.requestId,\n });\n return;\n }\n\n navigationSettleTimerRef.current = window.setTimeout(checkScrollPosition, 50);\n };\n\n navigationSettleTimerRef.current = window.setTimeout(checkScrollPosition, 50);\n }, [onNavigationSettled]);\n\n useEffect(() => () => {\n navigationSettleSequenceRef.current += 1;\n if (navigationSettleTimerRef.current != null) {\n window.clearTimeout(navigationSettleTimerRef.current);\n }\n }, []);\n\n useEffect(() => {\n if (!navigationRequest || totalPages <= 0) return;\n\n const nextPage = Math.min(\n Math.max(Math.trunc(navigationRequest.pageNumber), 1),\n totalPages\n );\n const requestKey = `${navigationRequest.requestId ?? nextPage}:${nextPage}`;\n if (lastNavigationRequestRef.current === requestKey) return;\n\n lastNavigationRequestRef.current = requestKey;\n setCurrentPage(nextPage - 1);\n jumpToPage(nextPage - 1);\n waitForNavigationToSettle(navigationRequest, nextPage);\n }, [jumpToPage, navigationRequest, totalPages, waitForNavigationToSettle]);\n\n if (!pdfUrl) {\n return (\n <ScannedDocCitation\n pages={fallbackPages}\n activeCitationIndex={activeCitationIndex}\n onActiveCitationChange={onActiveCitationChange}\n headerAction={headerAction}\n />\n );\n }\n\n const defaultViewerStyles: React.CSSProperties = {\n display: \"flex\",\n flexDirection: \"column\",\n height: \"100%\",\n width: \"100%\",\n backgroundColor: \"#FAFAFA\",\n };\n\n const scrollToHighlight = () => {\n if (!viewerRef.current) return;\n\n const index = jumpToPageValue - 1;\n const key = orderedKeys[index];\n const page = highlightPages[key];\n const targetPage = page > 0 ? page - 1 : 0;\n\n const pageVisitMap: Record<number, number[]> = {};\n orderedKeys.forEach((k, i) => {\n const p = highlightPages[k];\n if (p > 0) {\n if (!pageVisitMap[p]) pageVisitMap[p] = [];\n pageVisitMap[p].push(i);\n }\n });\n const visits = pageVisitMap[page] || [];\n const occurrence = visits.indexOf(index);\n\n let attempts = 0;\n const maxAttempts = 40;\n\n const doScrollToHighlight = () => {\n attempts++;\n if (attempts > maxAttempts) return;\n\n const scrollContainer = viewerRef.current?.querySelector(\n \".rpv-core__inner-pages\"\n ) as HTMLElement;\n if (!scrollContainer) {\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) {\n setTimeout(doScrollToHighlight, 100);\n return;\n }\n\n const scrollContainerRect = scrollContainer.getBoundingClientRect();\n const pageRect = pageElement.getBoundingClientRect();\n const isPageVisible =\n pageRect.top < scrollContainerRect.bottom &&\n pageRect.bottom > scrollContainerRect.top;\n\n if (!isPageVisible) {\n setTimeout(doScrollToHighlight, 100);\n return;\n }\n\n const allHighlights = pageElement.querySelectorAll(\".rpv-search__highlight\");\n const target = allHighlights[occurrence] as HTMLElement;\n\n if (!target) {\n setTimeout(doScrollToHighlight, 100);\n return;\n }\n\n const highlightRect = target.getBoundingClientRect();\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, 500);\n };\n\n return (\n <div\n ref={viewerRef}\n className={[\"citation-pdf-viewer\", customClasses?.pdfViewerWrapper]\n .filter(Boolean)\n .join(\" \")}\n data-disable-pdf-annotations={\n disablePdfAnnotations ? \"true\" : undefined\n }\n data-pdf-page-fit={\n resolvedDefaultScale === SpecialZoomLevel.PageFit ? \"true\" : undefined\n }\n style={{\n height: \"100%\",\n minHeight: 0,\n minWidth: 0,\n overflow: \"hidden\",\n display: \"flex\",\n flexDirection: \"column\",\n ...pdfStyles.pdfViewer,\n ...defaultViewerStyles,\n ...customStyles?.pdfViewer,\n backgroundColor: \"#F1F5F9\",\n }}\n >\n <PdfToolbar\n highlightIndex={highlightIndex}\n totalHighlights={totalHighlights}\n controls={modifiedControls}\n currentPosition={currentPosition}\n pdfName={pdfName}\n onClose={onClose}\n pdfUrl={pdfUrl}\n viewerRef={viewerRef}\n customStyles={customStyles}\n customClasses={customClasses}\n customIcons={customIcons}\n headerAction={headerAction}\n isZoomEnabled={isZoomEnabled}\n showHighlightsAction={showHighlightsAction}\n showFullScreenAction={showFullScreenAction} \n currentSegment={currentSegment}\n segmentTooltipText={segmentTooltipText}\n currentPage={currentPage + 1}\n totalPages={totalPages}\n onPageNavigate={handlePageNavigate}\n onRotatePage={handleRotatePage}\n currentPageRotation={currentPageRotation}\n showRotateButton={showRotateButton}\n />\n <PdfContainer\n defaultScale={resolvedDefaultScale}\n pdfUrl={pdfUrl}\n plugins={plugins}\n customStyles={customStyles}\n onError={onError}\n onLoad={(e: DocumentLoadEvent) => {\n setTotalPages(e.doc.numPages);\n\n const shouldAutoJumpToFirstMatch =\n !useCoordinates && !useRange && jumpToPageValue <= 0;\n\n if (jumpToPageValue > 0 && !useRange) {\n const index = jumpToPageValue - 1;\n const key = orderedKeys[index];\n const page = highlightPages[key];\n const cordinateTargetHighlight = highlightCordinatePages[index];\n setCursorIndex(index);\n\n console.log(cordinateTargetHighlight, \"cordinateTargetHighlight\");\n if (useCoordinates && cordinateTargetHighlight.pageIndex > 0)\n jumpToPage(cordinateTargetHighlight.pageIndex);\n\n if (page > 0) {\n setTimeout(() => {\n hideNonTargetHighlights(highlightPageSet);\n deduplicateHighlights(page - 1);\n }, 1000);\n if (!useCoordinates) {\n jumpToPage(page - 1);\n }\n }\n } else if (useRange && rangeOfPages && rangeOfPages.length === 2) {\n \n // Async function to handle sequential jumping and waiting\n const scanRangeSequence = async () => {\n const [startPage, endPage] = rangeOfPages;\n \n for (let p = startPage; p <= endPage; p++) {\n const targetPageIndex = p - 1;\n \n jumpToPage(targetPageIndex);\n \n // Pause execution for 1 second to let the DOM render the highlights\n await new Promise((resolve) => setTimeout(resolve, 1000));\n \n hideNonTargetHighlights(highlightPageSet);\n const matchSize = deduplicateHighlights(targetPageIndex);\n \n // If the returned size is greater than 0, a match was found. Stop the loop.\n if (matchSize && matchSize > 0) {\n break; \n }\n }\n };\n\n scanRangeSequence();\n\n } else if (!useCoordinates && highlightPages) {\n const firstKey = orderedKeys.find(k => highlightPages[k] > 0);\n if (firstKey !== undefined) {\n const firstPage = highlightPages[firstKey] - 1;\n jumpToPage(firstPage);\n setTimeout(() => {\n hideNonTargetHighlights(highlightPageSet);\n deduplicateHighlights(firstPage);\n }, 1000);\n }\n }\n\n requestAnimationFrame(() => {\n if (shouldAutoJumpToFirstMatch) {\n tryJump();\n }\n if (!useCoordinates && jumpToPageValue > 0 && !useRange) {\n scrollToHighlight();\n }\n });\n }}\n onPageChange={(e: PageChangeEvent) => {\n const currentPage = e.currentPage;\n setCurrentPage(currentPage);\n onCurrentPageChange?.(currentPage + 1);\n if (!highlightPageSet.has(currentPage)) {\n hideNonTargetHighlights(highlightPageSet);\n return;\n }\n deduplicateHighlights(currentPage);\n hideNonTargetHighlights(highlightPageSet);\n }}\n renderPage={resolvedRenderPage}\n setRenderRange={setRenderRange}\n />\n </div>\n );\n};\n\nexport default PdfViewer;\n"],"names":["PdfViewer","pdfUrl","highlightText","highlightPages","highlightCordinatePages","highlightColor","activeHighlightColor","jumpToPageValue","pdfName","onClose","customStyles","customClasses","customIcons","useCoordinates","fallbackPages","activeCitationIndex","onActiveCitationChange","headerAction","isZoomEnabled","showHighlightsAction","defaultScale","SpecialZoomLevel","ActualSize","useRange","rangeOfPages","showFullScreenAction","showRotateButton","segments","title","start_page","end_page","page_count","segmentTooltipText","onCurrentPageChange","navigationRequest","onNavigationSettled","disablePdfAnnotations","disablePdfTextLayer","renderPage","setRenderRange","onError","viewerRef","useRef","resolvedDefaultScale","scale","PageFit","PageWidth","getResolvedScale","currentPage","setCurrentPage","useState","totalPages","setTotalPages","currentPageRotation","setCurrentPageRotation","lastNavigationRequestRef","navigationSettleTimerRef","navigationSettleSequenceRef","mutationObserverRef","pdfIdentifier","useMemo","URL","window","location","origin","pathname","split","pop","useEffect","rotationManager","setPdfIdentifier","onRotationChange","pageNum","angle","observer","MutationObserver","pageElements","current","querySelectorAll","registeredPages","Set","forEach","pageElement","match","getAttribute","length","pageNumber","parseInt","has","registerPageElement","add","observe","childList","subtree","attributes","disconnect","clearAll","getRotation","resolvedRenderPage","props","resolvedTextLayerChildren","jsx","style","display","children","textLayer","resolvedProps","annotationLayer","jsxs","Fragment","canvasLayer","highlightPageSet","map","h","pageIndex","set","Object","values","p","removeRedundantHighlightTexts","texts","filter","text","some","otherText","includes","highlightIndex","setHighlightIndex","cursorIndex","setCursorIndex","orderedKeys","totalHighlights","getValidPosition","tryJump","jumpToPage","zoomTo","plugins","controls","hideNonTargetHighlights","deduplicateHighlights","scrollToCoord","PdfHighlightControls","currentPosition","currentSegment","find","segment","modifiedControls","goToNext","goToPrevious","waitForNavigationToSettle","React","useCallback","request","settleSequence","clearTimeout","previousScrollTop","stableChecks","attempts","checkScrollPosition","scrollContainer","querySelector","targetPage","requestId","setTimeout","scrollTop","scrollRect","getBoundingClientRect","pageRect","isTargetVisible","Boolean","bottom","top","nextPage","Math","min","max","trunc","requestKey","ScannedDocCitation","pages","ref","className","pdfViewerWrapper","join","height","minHeight","minWidth","overflow","flexDirection","pdfStyles","pdfViewer","width","backgroundColor","PdfToolbar","onPageNavigate","onRotatePage","rotatePageBy90","PdfContainer","onLoad","e","doc","numPages","shouldAutoJumpToFirstMatch","index","key","page","cordinateTargetHighlight","console","log","async","startPage","endPage","targetPageIndex","Promise","resolve","matchSize","scanRangeSequence","firstKey","k","firstPage","requestAnimationFrame","pageVisitMap","i","push","occurrence","indexOf","doScrollToHighlight","scrollContainerRect","target","highlightRect","clientHeight","scrollTo","behavior","scrollToHighlight","onPageChange"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PdfViewer.js","sources":["../../../src/features/PdfViewer/PdfViewer.tsx"],"sourcesContent":["import { DocumentLoadEvent, PageChangeEvent, RenderPage, SetRenderRange, SpecialZoomLevel, type LoadError } from \"@react-pdf-viewer/core\";\nimport PdfContainer from \"./PdfContainer\";\nimport PdfToolbar from \"./PdfToolbar\";\nimport { pdfStyles } from \"./PdfStyle\";\nimport { PdfHighlightControls } from \"./usePdfHighlight\";\nimport { rotationManager } from \"./rotationManager\";\nimport \"@react-pdf-viewer/zoom/lib/styles/index.css\";\nimport \"@react-pdf-viewer/page-navigation/lib/styles/index.css\";\nimport \"@react-pdf-viewer/core/lib/styles/index.css\";\nimport \"@react-pdf-viewer/search/lib/styles/index.css\";\nimport React, { useMemo, useRef, useEffect, useState } from \"react\";\nimport ScannedDocCitation, { CitationPage } from \"../ScannedDocCitation/ScannedDocCitation\";\nimport \"./PdfViewer.css\";\n\nexport type CustomIconsType = {\n pdfIcon?: React.ReactNode;\n fullScreenIcon?: React.ReactNode;\n downloadIcon?: React.ReactNode;\n closeIcon?: React.ReactNode;\n};\n\nexport type CustomStylesType = {\n pdfViewer?: React.CSSProperties;\n header?: React.CSSProperties;\n pdfIconWrapper?: React.CSSProperties;\n pdfName?: React.CSSProperties;\n pdfContainer?: React.CSSProperties;\n emptyState?: React.CSSProperties;\n};\n\nexport type CustomClassesType = {\n header?: string;\n pdfName?: string;\n actionButton?: string;\n pdfViewerWrapper?: string;\n};\n\nexport type PdfSegment = {\n title: string;\n start_page: number;\n end_page: number;\n page_count: number;\n};\n\ntype PdfScaleOption =\n | \"ActualSize\"\n | \"PageFit\"\n | \"PageWidth\"\n | number;\nexport interface PdfNavigationRequest {\n pageNumber: number;\n /** Change this value to navigate to the same page more than once. */\n requestId?: string | number;\n}\n\nexport interface PdfNavigationSettledEvent extends PdfNavigationRequest {\n pageNumber: number;\n}\n\nexport interface PdfViewerProps {\n pdfUrl?: string;\n highlightText: string[];\n highlightPages?: any;\n highlightCordinatePages: HighlightArea[];\n highlightColor?: string;\n activeHighlightColor?: string;\n jumpToPageValue?: number;\n pdfName?: string;\n onClose?: () => void;\n item?: any;\n customStyles?: CustomStylesType;\n customClasses?: CustomClassesType;\n customIcons?: CustomIconsType;\n useCoordinates: boolean;\n fallbackPages?: CitationPage[];\n activeCitationIndex?: number;\n onActiveCitationChange?: (index: number) => void;\n headerAction?: {\n icon?: React.ReactNode;\n onClick?: () => void;\n tooltip?: string;\n };\n isZoomEnabled?: boolean;\n showHighlightsAction?: boolean;\n defaultScale?: PdfScaleOption;\n useRange?: boolean; //\n rangeOfPages?: number[] | null;\n showFullScreenAction?: boolean;\n showRotateButton?: boolean;\n segments?: PdfSegment[];\n segmentTooltipText?: string;\n onCurrentPageChange?: (pageNumber: number) => void;\n navigationRequest?: PdfNavigationRequest | null;\n onNavigationSettled?: (event: PdfNavigationSettledEvent) => void;\n disablePdfAnnotations?: boolean;\n disablePdfTextLayer?: boolean;\n renderPage?: RenderPage;\n setRenderRange?: SetRenderRange;\n onError?: (error: LoadError) => void;\n}\n\nconst getResolvedScale = (\n scale?: PdfScaleOption\n): SpecialZoomLevel | number => {\n switch (scale) {\n case \"ActualSize\":\n return SpecialZoomLevel.ActualSize;\n\n case \"PageFit\":\n return SpecialZoomLevel.PageFit;\n\n case \"PageWidth\":\n return SpecialZoomLevel.PageWidth;\n\n default:\n return scale ?? SpecialZoomLevel.PageWidth;\n }\n};\n\nexport type HighlightArea = {\n pageIndex: number;\n left: number;\n top: number;\n width: number;\n height: number;\n pageNumber?: number;\n};\n\nconst PdfViewer = ({\n pdfUrl,\n highlightText,\n highlightPages,\n highlightCordinatePages,\n highlightColor = \"yellow\",\n activeHighlightColor = \"#f7dc51\",\n jumpToPageValue,\n pdfName,\n onClose,\n customStyles,\n customClasses,\n customIcons,\n useCoordinates,\n fallbackPages,\n activeCitationIndex,\n onActiveCitationChange,\n headerAction,\n isZoomEnabled = true,\n showHighlightsAction = true,\n defaultScale = SpecialZoomLevel.ActualSize,\n useRange = false,\n rangeOfPages = null,\n showFullScreenAction=true,\n showRotateButton = false,\n segments = [\n {\n title: \"Document 2\",\n start_page: 52,\n end_page: 52,\n page_count: 1,\n },\n ],\n segmentTooltipText,\n onCurrentPageChange,\n navigationRequest,\n onNavigationSettled,\n disablePdfAnnotations = false,\n disablePdfTextLayer = false,\n renderPage,\n setRenderRange,\n onError\n}: PdfViewerProps) => {\n\n const viewerRef = useRef<HTMLDivElement | null>(null);\n const resolvedDefaultScale = getResolvedScale(defaultScale);\n const resolvedJumpToPageValue =\n jumpToPageValue ??\n (useCoordinates && highlightCordinatePages.length > 0 ? 1 : 0);\n const [currentPage, setCurrentPage] = useState(0);\n const [totalPages, setTotalPages] = useState(0);\n const [loadedPdfUrl, setLoadedPdfUrl] = useState<string | null>(null);\n const [currentPageRotation, setCurrentPageRotation] = useState(0);\n const lastNavigationRequestRef = useRef<string | null>(null);\n const navigationSettleTimerRef = useRef<number | null>(null);\n const navigationSettleSequenceRef = useRef(0);\n const mutationObserverRef = useRef<MutationObserver | null>(null);\n const coordinateAutoJumpKeyRef = useRef<string | null>(null);\n\n // Generate PDF identifier for localStorage from URL\n const pdfIdentifier = useMemo(() => {\n if (!pdfUrl) return '';\n // Use last part of URL or hash it\n try {\n const url = new URL(pdfUrl, window.location.origin);\n return url.pathname.split('/').pop() || 'default';\n } catch {\n return 'default';\n }\n }, [pdfUrl]);\n\n // Set up rotation manager with PDF identifier\n useEffect(() => {\n if (pdfIdentifier) {\n rotationManager.setPdfIdentifier(pdfIdentifier);\n }\n }, [pdfIdentifier]);\n\n // Handler for rotating current page (no state update)\n const handleRotatePage = () => {\n const pageNumber = currentPage + 1;\n rotationManager.rotatePageBy90(pageNumber);\n // Manually update state to reflect rotation in UI\n setCurrentPageRotation(rotationManager.getRotation(pageNumber));\n };\n\n // Subscribe to rotation changes to sync UI state\n useEffect(() => {\n const unsubscribe = rotationManager.onRotationChange((pageNum, angle) => {\n // Only update state if current page rotated\n if (pageNum === currentPage + 1) {\n setCurrentPageRotation(angle);\n }\n });\n\n return unsubscribe;\n }, [currentPage]);\n\n // Register page elements with rotation manager\n useEffect(() => {\n const observer = new MutationObserver(() => {\n // Find all newly rendered page elements\n const pageElements = viewerRef.current?.querySelectorAll(\n '[data-testid^=\"core__page-layer-\"]'\n );\n\n const registeredPages = new Set<number>();\n\n pageElements?.forEach((pageElement) => {\n const match = (pageElement as HTMLElement)\n .getAttribute('data-testid')\n ?.match(/core__page-layer-(\\d+)/);\n if (match && match.length >= 2) {\n const pageIndex = parseInt(match[1], 10);\n const pageNumber = pageIndex + 1;\n\n // Only register once per page\n if (!registeredPages.has(pageNumber)) {\n rotationManager.registerPageElement(pageNumber, pageElement as HTMLElement);\n registeredPages.add(pageNumber);\n }\n }\n });\n });\n\n if (viewerRef.current) {\n observer.observe(viewerRef.current, {\n childList: true,\n subtree: true,\n attributes: false,\n });\n mutationObserverRef.current = observer;\n }\n\n return () => {\n observer.disconnect();\n mutationObserverRef.current = null;\n };\n }, []);\n\n // Clean up when unmounting\n useEffect(() => {\n return () => {\n rotationManager.clearAll();\n if (mutationObserverRef.current) {\n mutationObserverRef.current.disconnect();\n }\n };\n }, []);\n\n // Update current page rotation when page changes\n useEffect(() => {\n const pageNumber = currentPage + 1;\n setCurrentPageRotation(rotationManager.getRotation(pageNumber));\n }, [currentPage]);\n const resolvedRenderPage = useMemo<RenderPage | undefined>(() => {\n if (!disablePdfAnnotations && !disablePdfTextLayer) return renderPage;\n\n return (props) => {\n const resolvedTextLayerChildren = disablePdfTextLayer ? (\n <div aria-hidden=\"true\" style={{ display: \"none\" }}>\n {props.textLayer.children}\n </div>\n ) : props.textLayer.children;\n const resolvedProps = {\n ...props,\n annotationLayer: {\n ...props.annotationLayer,\n children: disablePdfAnnotations ? null : props.annotationLayer.children,\n },\n textLayer: {\n ...props.textLayer,\n children: resolvedTextLayerChildren,\n },\n };\n\n const renderedPage = renderPage\n ? renderPage(resolvedProps)\n : (\n <>\n {props.canvasLayer.children}\n {resolvedTextLayerChildren}\n {!disablePdfAnnotations && props.annotationLayer.children}\n </>\n );\n\n return renderedPage;\n };\n }, [disablePdfAnnotations, disablePdfTextLayer, renderPage]);\n\n const cleanHighlightTexts = (texts: string[]): string[] => {\n if (!texts || texts.length === 0) return texts;\n return texts.filter((text) => {\n return !texts.some(\n (otherText) => otherText !== text && otherText.includes(text)\n );\n });\n };\n\n const highlightPageSet = useMemo(() => {\n if (useCoordinates) {\n return new Set(highlightCordinatePages.map((h: any) => h.pageIndex));\n } else {\n const set = new Set<number>();\n Object.values(highlightPages).forEach((p: any) => {\n if (p > 0) set.add(p - 1);\n });\n return set;\n }\n }, [highlightCordinatePages, highlightPages, useCoordinates]);\n\n const removeRedundantHighlightTexts = cleanHighlightTexts(highlightText);\n\n const {\n highlightIndex,\n setHighlightIndex,\n cursorIndex,\n setCursorIndex,\n orderedKeys,\n totalHighlights,\n getValidPosition,\n tryJump,\n jumpToPage,\n zoomTo,\n plugins,\n controls,\n hideNonTargetHighlights,\n deduplicateHighlights,\n scrollToCoordAfterNav,\n } = PdfHighlightControls(\n removeRedundantHighlightTexts,\n !useCoordinates ? highlightPages : {},\n viewerRef,\n highlightPageSet,\n useCoordinates,\n useCoordinates ? highlightCordinatePages : [],\n highlightColor,\n activeHighlightColor\n );\n\n useEffect(() => {\n if (\n !useCoordinates ||\n useRange ||\n totalPages <= 0 ||\n loadedPdfUrl !== (pdfUrl ?? null)\n ) {\n return;\n }\n\n const index = resolvedJumpToPageValue - 1;\n const target = highlightCordinatePages[index];\n if (!target || target.pageIndex < 0 || target.pageIndex >= totalPages) return;\n\n const jumpKey = [\n pdfUrl,\n index,\n target.pageIndex,\n target.top,\n target.height,\n ].join(\":\");\n if (coordinateAutoJumpKeyRef.current === jumpKey) return;\n coordinateAutoJumpKeyRef.current = jumpKey;\n\n setCursorIndex(index);\n jumpToPage(target.pageIndex);\n scrollToCoordAfterNav(target.pageIndex, target.top, target.height);\n }, [\n highlightCordinatePages,\n jumpToPage,\n loadedPdfUrl,\n pdfUrl,\n resolvedJumpToPageValue,\n scrollToCoordAfterNav,\n setCursorIndex,\n totalPages,\n useCoordinates,\n useRange,\n ]);\n\n const currentPosition = getValidPosition(cursorIndex);\n const currentSegment = useMemo(() => {\n const pageNumber = currentPage + 1;\n return segments.find(\n (segment) =>\n pageNumber >= segment.start_page && pageNumber <= segment.end_page\n );\n }, [currentPage, segments]);\n\n // sync external activeCitationIndex → cursorIndex\n useEffect(() => {\n if (activeCitationIndex === undefined) return;\n if (activeCitationIndex === cursorIndex) return;\n setCursorIndex(activeCitationIndex);\n }, [activeCitationIndex]);\n\n // wrap controls to fire onActiveCitationChange\n const handleGoToNext = () => {\n if (cursorIndex >= totalHighlights - 1) return;\n const nextIndex = cursorIndex + 1;\n\n if (useCoordinates) {\n const target = highlightCordinatePages[nextIndex];\n\n if (!target) return;\n\n setCursorIndex(nextIndex);\n jumpToPage(target.pageIndex);\n scrollToCoordAfterNav(\n target.pageIndex,\n Number.isFinite(target.top) ? target.top : 0,\n Number.isFinite(target.height) ? target.height : 0\n );\n } else {\n controls.goToNext();\n }\n\n onActiveCitationChange?.(nextIndex);\n };\n\n const handleGoToPrevious = () => {\n if (cursorIndex <= 0) return;\n const previousIndex = cursorIndex - 1;\n\n if (useCoordinates) {\n const target = highlightCordinatePages[previousIndex];\n\n if (!target) return;\n\n setCursorIndex(previousIndex);\n jumpToPage(target.pageIndex);\n scrollToCoordAfterNav(\n target.pageIndex,\n Number.isFinite(target.top) ? target.top : 0,\n Number.isFinite(target.height) ? target.height : 0\n );\n } else {\n controls.goToPrevious();\n }\n\n onActiveCitationChange?.(previousIndex);\n };\n\n const modifiedControls = {\n ...controls,\n goToNext: handleGoToNext,\n goToPrevious: handleGoToPrevious,\n };\n\n const handlePageNavigate = (pageNumber: number) => {\n const nextPage = Math.min(Math.max(pageNumber, 1), totalPages || pageNumber);\n setCurrentPage(nextPage - 1);\n jumpToPage(nextPage - 1);\n };\n\n const waitForNavigationToSettle = React.useCallback((\n request: PdfNavigationRequest,\n pageNumber: number\n ) => {\n navigationSettleSequenceRef.current += 1;\n const settleSequence = navigationSettleSequenceRef.current;\n if (navigationSettleTimerRef.current != null) {\n window.clearTimeout(navigationSettleTimerRef.current);\n }\n\n let previousScrollTop: number | null = null;\n let stableChecks = 0;\n let attempts = 0;\n\n const checkScrollPosition = () => {\n if (navigationSettleSequenceRef.current !== settleSequence) return;\n\n attempts += 1;\n\n const scrollContainer = viewerRef.current?.querySelector(\n '.rpv-core__inner-pages'\n ) as HTMLElement | null;\n const targetPage = viewerRef.current?.querySelector(\n `[data-testid=\"core__page-layer-${pageNumber - 1}\"]`\n ) as HTMLElement | null;\n\n // Virtualized page layers are not guaranteed to be mounted on the first\n // check after jumpToPage. Keep polling so navigation completion is not\n // lost while React PDF Viewer is creating the target page DOM.\n if (!scrollContainer || !targetPage) {\n if (attempts >= 40) {\n navigationSettleTimerRef.current = null;\n onNavigationSettled?.({\n pageNumber,\n requestId: request.requestId,\n });\n return;\n }\n\n navigationSettleTimerRef.current = window.setTimeout(checkScrollPosition, 50);\n return;\n }\n\n if (previousScrollTop === scrollContainer.scrollTop) {\n stableChecks += 1;\n } else {\n previousScrollTop = scrollContainer.scrollTop;\n stableChecks = 0;\n }\n\n const scrollRect = scrollContainer.getBoundingClientRect();\n const pageRect = targetPage.getBoundingClientRect();\n const isTargetVisible = Boolean(\n scrollRect &&\n pageRect &&\n pageRect.bottom > scrollRect.top &&\n pageRect.top < scrollRect.bottom\n );\n const hasSettled = stableChecks >= 2 && isTargetVisible;\n const reachedTimeout = attempts >= 40;\n\n if (hasSettled || reachedTimeout) {\n navigationSettleTimerRef.current = null;\n onNavigationSettled?.({\n pageNumber,\n requestId: request.requestId,\n });\n return;\n }\n\n navigationSettleTimerRef.current = window.setTimeout(checkScrollPosition, 50);\n };\n\n navigationSettleTimerRef.current = window.setTimeout(checkScrollPosition, 50);\n }, [onNavigationSettled]);\n\n useEffect(() => () => {\n navigationSettleSequenceRef.current += 1;\n if (navigationSettleTimerRef.current != null) {\n window.clearTimeout(navigationSettleTimerRef.current);\n }\n }, []);\n\n useEffect(() => {\n if (!navigationRequest || totalPages <= 0) return;\n\n const nextPage = Math.min(\n Math.max(Math.trunc(navigationRequest.pageNumber), 1),\n totalPages\n );\n const requestKey = `${navigationRequest.requestId ?? nextPage}:${nextPage}`;\n if (lastNavigationRequestRef.current === requestKey) return;\n\n lastNavigationRequestRef.current = requestKey;\n setCurrentPage(nextPage - 1);\n jumpToPage(nextPage - 1);\n waitForNavigationToSettle(navigationRequest, nextPage);\n }, [jumpToPage, navigationRequest, totalPages, waitForNavigationToSettle]);\n\n if (!pdfUrl) {\n return (\n <ScannedDocCitation\n pages={fallbackPages}\n activeCitationIndex={activeCitationIndex}\n onActiveCitationChange={onActiveCitationChange}\n headerAction={headerAction}\n />\n );\n }\n\n const defaultViewerStyles: React.CSSProperties = {\n display: \"flex\",\n flexDirection: \"column\",\n height: \"100%\",\n width: \"100%\",\n backgroundColor: \"#FAFAFA\",\n };\n\n const scrollToHighlight = () => {\n if (!viewerRef.current) return;\n\n const index = resolvedJumpToPageValue - 1;\n const key = orderedKeys[index];\n const page = highlightPages[key];\n const targetPage = page > 0 ? page - 1 : 0;\n\n const pageVisitMap: Record<number, number[]> = {};\n orderedKeys.forEach((k, i) => {\n const p = highlightPages[k];\n if (p > 0) {\n if (!pageVisitMap[p]) pageVisitMap[p] = [];\n pageVisitMap[p].push(i);\n }\n });\n const visits = pageVisitMap[page] || [];\n const occurrence = visits.indexOf(index);\n\n let attempts = 0;\n const maxAttempts = 40;\n\n const doScrollToHighlight = () => {\n attempts++;\n if (attempts > maxAttempts) return;\n\n const scrollContainer = viewerRef.current?.querySelector(\n \".rpv-core__inner-pages\"\n ) as HTMLElement;\n if (!scrollContainer) {\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) {\n setTimeout(doScrollToHighlight, 100);\n return;\n }\n\n const scrollContainerRect = scrollContainer.getBoundingClientRect();\n const pageRect = pageElement.getBoundingClientRect();\n const isPageVisible =\n pageRect.top < scrollContainerRect.bottom &&\n pageRect.bottom > scrollContainerRect.top;\n\n if (!isPageVisible) {\n setTimeout(doScrollToHighlight, 100);\n return;\n }\n\n const allHighlights = pageElement.querySelectorAll(\".rpv-search__highlight\");\n const target = allHighlights[occurrence] as HTMLElement;\n\n if (!target) {\n setTimeout(doScrollToHighlight, 100);\n return;\n }\n\n const highlightRect = target.getBoundingClientRect();\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, 500);\n };\n\n return (\n <div\n ref={viewerRef}\n className={[\"citation-pdf-viewer\", customClasses?.pdfViewerWrapper]\n .filter(Boolean)\n .join(\" \")}\n data-disable-pdf-annotations={\n disablePdfAnnotations ? \"true\" : undefined\n }\n data-pdf-page-fit={\n resolvedDefaultScale === SpecialZoomLevel.PageFit ? \"true\" : undefined\n }\n style={{\n height: \"100%\",\n minHeight: 0,\n minWidth: 0,\n overflow: \"hidden\",\n display: \"flex\",\n flexDirection: \"column\",\n ...pdfStyles.pdfViewer,\n ...defaultViewerStyles,\n ...customStyles?.pdfViewer,\n backgroundColor: \"#F1F5F9\",\n }}\n >\n <PdfToolbar\n highlightIndex={highlightIndex}\n totalHighlights={totalHighlights}\n controls={modifiedControls}\n currentPosition={currentPosition}\n pdfName={pdfName}\n onClose={onClose}\n pdfUrl={pdfUrl}\n viewerRef={viewerRef}\n customStyles={customStyles}\n customClasses={customClasses}\n customIcons={customIcons}\n headerAction={headerAction}\n isZoomEnabled={isZoomEnabled}\n showHighlightsAction={showHighlightsAction}\n showFullScreenAction={showFullScreenAction} \n currentSegment={currentSegment}\n segmentTooltipText={segmentTooltipText}\n currentPage={currentPage + 1}\n totalPages={totalPages}\n onPageNavigate={handlePageNavigate}\n onRotatePage={handleRotatePage}\n currentPageRotation={currentPageRotation}\n showRotateButton={showRotateButton}\n />\n <PdfContainer\n defaultScale={resolvedDefaultScale}\n pdfUrl={pdfUrl}\n plugins={plugins}\n customStyles={customStyles}\n onError={onError}\n onLoad={(e: DocumentLoadEvent) => {\n setTotalPages(e.doc.numPages);\n setLoadedPdfUrl(pdfUrl ?? null);\n\n const shouldAutoJumpToFirstMatch =\n !useCoordinates && !useRange && resolvedJumpToPageValue <= 0;\n\n if (\n !useCoordinates &&\n resolvedJumpToPageValue > 0 &&\n !useRange\n ) {\n const index = resolvedJumpToPageValue - 1;\n const key = orderedKeys[index];\n const page = key !== undefined ? highlightPages?.[key] : undefined;\n setCursorIndex(index);\n\n if (page > 0) {\n setTimeout(() => {\n hideNonTargetHighlights(highlightPageSet);\n deduplicateHighlights(page - 1);\n }, 1000);\n jumpToPage(page - 1);\n }\n } else if (useRange && rangeOfPages && rangeOfPages.length === 2) {\n \n // Async function to handle sequential jumping and waiting\n const scanRangeSequence = async () => {\n const [startPage, endPage] = rangeOfPages;\n \n for (let p = startPage; p <= endPage; p++) {\n const targetPageIndex = p - 1;\n \n jumpToPage(targetPageIndex);\n \n // Pause execution for 1 second to let the DOM render the highlights\n await new Promise((resolve) => setTimeout(resolve, 1000));\n \n hideNonTargetHighlights(highlightPageSet);\n const matchSize = deduplicateHighlights(targetPageIndex);\n \n // If the returned size is greater than 0, a match was found. Stop the loop.\n if (matchSize && matchSize > 0) {\n break; \n }\n }\n };\n\n scanRangeSequence();\n\n } else if (!useCoordinates && highlightPages) {\n const firstKey = orderedKeys.find(k => highlightPages[k] > 0);\n if (firstKey !== undefined) {\n const firstPage = highlightPages[firstKey] - 1;\n jumpToPage(firstPage);\n setTimeout(() => {\n hideNonTargetHighlights(highlightPageSet);\n deduplicateHighlights(firstPage);\n }, 1000);\n }\n }\n\n requestAnimationFrame(() => {\n if (shouldAutoJumpToFirstMatch) {\n tryJump();\n }\n if (!useCoordinates && resolvedJumpToPageValue > 0 && !useRange) {\n scrollToHighlight();\n }\n });\n }}\n onPageChange={(e: PageChangeEvent) => {\n const currentPage = e.currentPage;\n setCurrentPage(currentPage);\n onCurrentPageChange?.(currentPage + 1);\n if (!highlightPageSet.has(currentPage)) {\n hideNonTargetHighlights(highlightPageSet);\n return;\n }\n deduplicateHighlights(currentPage);\n hideNonTargetHighlights(highlightPageSet);\n }}\n renderPage={resolvedRenderPage}\n setRenderRange={setRenderRange}\n />\n </div>\n );\n};\n\nexport default PdfViewer;\n"],"names":["PdfViewer","pdfUrl","highlightText","highlightPages","highlightCordinatePages","highlightColor","activeHighlightColor","jumpToPageValue","pdfName","onClose","customStyles","customClasses","customIcons","useCoordinates","fallbackPages","activeCitationIndex","onActiveCitationChange","headerAction","isZoomEnabled","showHighlightsAction","defaultScale","SpecialZoomLevel","ActualSize","useRange","rangeOfPages","showFullScreenAction","showRotateButton","segments","title","start_page","end_page","page_count","segmentTooltipText","onCurrentPageChange","navigationRequest","onNavigationSettled","disablePdfAnnotations","disablePdfTextLayer","renderPage","setRenderRange","onError","viewerRef","useRef","resolvedDefaultScale","scale","PageFit","PageWidth","getResolvedScale","resolvedJumpToPageValue","length","currentPage","setCurrentPage","useState","totalPages","setTotalPages","loadedPdfUrl","setLoadedPdfUrl","currentPageRotation","setCurrentPageRotation","lastNavigationRequestRef","navigationSettleTimerRef","navigationSettleSequenceRef","mutationObserverRef","coordinateAutoJumpKeyRef","pdfIdentifier","useMemo","URL","window","location","origin","pathname","split","pop","useEffect","rotationManager","setPdfIdentifier","onRotationChange","pageNum","angle","observer","MutationObserver","pageElements","current","querySelectorAll","registeredPages","Set","forEach","pageElement","match","getAttribute","pageNumber","parseInt","has","registerPageElement","add","observe","childList","subtree","attributes","disconnect","clearAll","getRotation","resolvedRenderPage","props","resolvedTextLayerChildren","jsx","style","display","children","textLayer","resolvedProps","annotationLayer","jsxs","Fragment","canvasLayer","highlightPageSet","map","h","pageIndex","set","Object","values","p","removeRedundantHighlightTexts","texts","filter","text","some","otherText","includes","highlightIndex","setHighlightIndex","cursorIndex","setCursorIndex","orderedKeys","totalHighlights","getValidPosition","tryJump","jumpToPage","zoomTo","plugins","controls","hideNonTargetHighlights","deduplicateHighlights","scrollToCoordAfterNav","PdfHighlightControls","index","target","jumpKey","top","height","join","currentPosition","currentSegment","find","segment","modifiedControls","goToNext","nextIndex","Number","isFinite","goToPrevious","previousIndex","waitForNavigationToSettle","React","useCallback","request","settleSequence","clearTimeout","previousScrollTop","stableChecks","attempts","checkScrollPosition","scrollContainer","querySelector","targetPage","requestId","setTimeout","scrollTop","scrollRect","getBoundingClientRect","pageRect","isTargetVisible","Boolean","bottom","nextPage","Math","min","max","trunc","requestKey","ScannedDocCitation","pages","ref","className","pdfViewerWrapper","minHeight","minWidth","overflow","flexDirection","pdfStyles","pdfViewer","width","backgroundColor","PdfToolbar","onPageNavigate","onRotatePage","rotatePageBy90","PdfContainer","onLoad","e","doc","numPages","shouldAutoJumpToFirstMatch","key","page","async","startPage","endPage","targetPageIndex","Promise","resolve","matchSize","scanRangeSequence","firstKey","k","firstPage","requestAnimationFrame","pageVisitMap","i","push","occurrence","indexOf","doScrollToHighlight","scrollContainerRect","highlightRect","clientHeight","scrollTo","behavior","scrollToHighlight","onPageChange"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{jsx as e,Fragment as t}from"react/jsx-runtime";import{useState as r,useRef as n,useMemo as o}from"react";import{searchPlugin as l}from"@react-pdf-viewer/search";import{pageNavigationPlugin as i}from"@react-pdf-viewer/page-navigation";import{zoomPlugin as s}from"@react-pdf-viewer/zoom";import{highlightPlugin as c}from"@react-pdf-viewer/highlight";const a=(a,h,g,u,p,f,d="yellow",m="#F6D739")=>{const[x,T]=r(0),v=n(!1),[y,w]=r(0);n([]);const M=e=>e.replace(/[^\S\n]+/g," ").trim(),b=e=>(e||"").toLowerCase().replace(/\u00ad/g,"").replace(/[""]/g,'"').replace(/['']/g,"'").replace(/[\u2013\u2014]/g,"-").replace(/-/g," ").replace(/[^\w\s]/g,"").replace(/\s+/g," ").trim(),_=e=>{let t=e.trim();t=t.replace(/[\u200B-\u200D\uFEFF]/g,"").replace(/[\u00A0\u2009\u202F]/g," "),t=t.replace(/^[-•]\s+/,"");const r=t.match(/^((\d+(?:\.\d+)*[.)]?)|[A-Za-z][.)]|\([A-Za-z0-9]+\)|(?:i|ii|iii|iv|v|vi|vii|viii|ix|x)[.)])\s*/i);return r?t.slice(r[0].length).trim():t},I=e=>{const t=b(e),r=t.replace(/\s+/g,""),n=new Set;return t&&n.add(t),r&&n.add(r),n},S=e=>e.replace(/\\([''])/g,"$1").replace(/\]\s*\n\s*\(/g,"](").replace(/&[#\w]+;/g,e=>(e=>{const t=document.createElement("textarea");return t.innerHTML=e,t.value})(e)).replace(/<br\s*\/?>/gi,"\n").replace(/\[([^\]]+)\]\(([^)]+)\)/g,"$1").replace(/`([^`]+)`/g,"$1"),$=e=>{if(!e)return[];return S(e).split(/\n+/).map(_).flatMap(e=>{const t=e.match(/^\s*\|(.+)\|\s*$/);return t?t[1].split("|").map(e=>e.trim()).filter(Boolean):[e]}).map(e=>M((e=>e.replace(/(^|\W)[*_]{1,3}([^*_]+)[*_]{1,3}(?=\W|$)/g,"$1$2"))(e))).filter(Boolean)},E=Object.keys(h).map(Number).sort((e,t)=>e-t),A=o(()=>p?f.length:p?0:Object.values(h).filter(e=>e>0).length,[f,h]),k=e=>{if(!g.current)return;const t=g.current.querySelector(`[data-testid="search__highlights-${e}"]`);if(!t)return;const r=Array.from(t.querySelectorAll(".rpv-search__highlight"));if(0===r.length)return;const n=j.map(I),o=R.map(I);if(0===n.length&&0===o.length)return;const l=r.map(e=>{const t=(e=>{const t=e.getBoundingClientRect();if(t.height>0||t.width>0)return{top:t.top,left:t.left,right:t.right};const r=e.offsetTop,n=e.offsetLeft;return{top:r,left:n,right:n+e.offsetWidth}})(e),r=(e.textContent||"").trim(),n=(e.getAttribute("title")||"").trim();return{el:e,text:r||n,...t}}).filter(e=>e.text.length>0).sort((e,t)=>e.top-t.top||e.left-t.left);if(0===l.length)return;const i=[];let s=null,c=[];const h=()=>{if(!s)return;const e=c.join(" ");s.title=b(e),s.title&&i.push(s),s=null,c=[]};if(l.forEach(e=>{if(!s)return s={title:"",elements:[e.el],lastTop:e.top,lastRight:e.right},void(c=[e.text]);const t=Math.abs(e.top-s.lastTop)<=5,r=e.left<=s.lastRight+28;t&&r?(s.elements.push(e.el),s.lastTop=e.top,s.lastRight=Math.max(s.lastRight,e.right),c.push(e.text)):(h(),s={title:"",elements:[e.el],lastTop:e.top,lastRight:e.right},c=[e.text])}),h(),0===i.length)return;const u=(e,t)=>{if(!e)return!1;if(t.has(e))return!0;const r=e.replace(/\s+/g,"");for(const n of Array.from(t)){if(!n)continue;const t=n.replace(/\s+/g,"");if(t===r)return!0;if(n.length>=8&&e.length>=5&&n.includes(e))return!0;if(t.length>=8&&r.length>=5&&t.includes(r))return!0;if(e.length>=10&&n.length>=8&&e.includes(n))return!0;if(r.length>=10&&t.length>=8&&r.includes(t))return!0}return!1};let p=0,f=new Set;const d=Array.from(new Set([...j,...R].map(b).filter(e=>e.length>=8))).sort((e,t)=>t.length-e.length),m=e=>{if(!e||e.length<8)return null;const t=e.replace(/\s+/g,"");for(let r=0;r<i.length;r++){let n="",o="";const l=new Set;for(let s=r;s<i.length&&s<r+20;s++){const r=i[s].title;if(n=n?`${n} ${r}`:r,o=o?`${o}${r.replace(/\s+/g,"")}`:r.replace(/\s+/g,""),l.add(s),n.includes(e)||o.includes(t))return l;if(n.length>=15&&(e.includes(n)||t.includes(o)))return l;if(n.length>e.length+150)break}}return null};for(const e of d){const t=m(e);t&&t.size>0&&(t.forEach(e=>f.add(e)),p=f.size)}if(0===p){const e=(e=>{if(0===e.length)return null;let t=null;for(const r of e)for(const e of Array.from(r)){if(!e||e.length<5)continue;const r=e.replace(/\s+/g,"");for(let n=0;n<i.length;n++){let o="",l="";const s=new Set;for(let c=n;c<i.length&&c<n+15;c++){const n=i[c].title;if(o=o?`${o} ${n}`:n,l=l?`${l}${n.replace(/\s+/g,"")}`:n.replace(/\s+/g,""),s.add(c),o.includes(e)||l.includes(r)){const r=Math.max(0,o.length-e.length);(!t||r<t.extra)&&(t={blocks:new Set(s),extra:r});break}if(o.length>e.length+120)break}}}return t?t.blocks:null})(n);e&&e.size>0&&(e.forEach(e=>f.add(e)),p=f.size)}const x=(e=>{if(e.length<2)return 40;const t=[];for(let r=1;r<e.length;r++){const n=Math.abs(e[r].lastTop-e[r-1].lastTop);n>0&&t.push(n)}if(0===t.length)return 40;t.sort((e,t)=>e-t);const r=t[Math.floor(t.length/2)],n=Math.round(2.25*r);return Math.min(60,Math.max(24,n))})(i),T=R.map(b).filter(e=>e.length>=8),v=T.map(e=>e.split(/\s+/).filter(e=>e.length>=2));if(0===p){const e=o;for(let t=0;t<i.length;t++){const r=i[t].title;for(let n=0;n<e.length;n++){if(!u(r,e[n]))continue;let o=0;const l=new Set;let s=n,c=t-1;for(let r=t;r<i.length&&s<e.length;r++){if(u(i[r].title,e[s])){if(c>=0){const e=i[c].lastTop,t=i[r].lastTop;if(Math.abs(t-e)>x)break}o++,l.add(r),c=r,s++}else if(s>0&&u(i[r].title,e[s-1])){const e=i[c].lastTop,t=i[r].lastTop;Math.abs(t-e)<=3&&(l.add(r),c=r)}if(r-c>6)break}o>p&&(p=o,f=l)}}}if(p<Math.min(3,T.length)&&T.length>0){const e=new Set;i.forEach((t,r)=>{const n=t.title.split(/\s+/).filter(e=>e.length>=2);if(n.length<2)return;const o=new Set(n);for(const t of v){if(t.length<2)continue;let n=0;for(const e of t)o.has(e)&&n++;const l=n/t.length;if(n>=3||l>=.5){e.add(r);break}}}),e.size>0&&(f=e,p=Math.max(p,e.size))}const y=new Set;if(F.forEach(e=>{const t=b(e);t&&(y.add(t),y.add(t.replace(/\s+/g,"")))}),0===p){const e=new Set;if(i.forEach((t,r)=>{const n=t.title.replace(/\s+/g,"");if(y.has(t.title)||y.has(n))return void e.add(r);const o=Array.from(y);for(let n=0;n<o.length;n++){const l=o[n];if(l.length>=10&&l.includes(t.title)&&t.title.length>=5){e.add(r);break}}}),0===e.size)return 0;f=e}i.forEach((e,t)=>{const r=f.has(t);e.elements.forEach(e=>{r?(e.classList.add("verified-match"),e.style.display=""):(e.style.display="none",e.classList.remove("verified-match"))})});const w=[];return i.forEach((e,t)=>{f.has(t)&&e.elements.forEach(e=>w.push(e))}),requestAnimationFrame(()=>{const e=w.map(e=>({el:e,rect:e.getBoundingClientRect()})).filter(e=>e.rect.width>0&&e.rect.height>0).sort((e,t)=>t.rect.width*t.rect.height-e.rect.width*e.rect.height),t=[];e.forEach(({el:e,rect:r})=>{t.some(e=>((e,t)=>{const r=Math.max(0,Math.min(e.right,t.right)-Math.max(e.left,t.left))*Math.max(0,Math.min(e.bottom,t.bottom)-Math.max(e.top,t.top)),n=Math.min(e.width*e.height,t.width*t.height);return n>0?r/n:0})(e.rect,r)>.5)?(e.style.display="none",e.classList.remove("verified-match")):t.push({el:e,rect:r})})}),console.groupCollapsed(`[debug: PDF ordered matching - Page ${e}]`),console.log("input->",a),console.log("processed sentences->",j),console.log("processed lines->",R),console.log("Expected sentence count:",n.length),console.log("Expected line count:",o.length),console.log("Matched sequence length:",p),console.log("blocksToKeep",f,"size",f.size),console.groupEnd(),f.size},z=e=>{if(!g.current)return;g.current.querySelectorAll(".rpv-search__highlights").forEach(t=>{const r=t.getAttribute("data-testid"),n=parseInt(r?.replace(/search__highlights-/g,"")||"-1"),o=t.querySelectorAll(".rpv-search__highlight");e.has(n)||o.forEach(e=>{e.style.display="none"})})},q=a.map(e=>(e=>e?S(e).split(/\n{2,}/).map(e=>$(e).join(" ")).map(e=>M(e)).filter(Boolean):[])(e)).flat(),B=a.map(e=>$(e)).flat(),C=q.some(e=>e.length>=3)?3:1,j=q.filter(e=>e.length>=C),R=B.filter(e=>e.length>=C),H=R.flatMap(e=>((e,t=6,r=4)=>{const n=e.split(/\s+/).filter(Boolean);if(n.length<=t)return[];const o=[];for(let e=0;e+t<=n.length;e+=r)o.push(n.slice(e,e+t).join(" "));return n.length>t&&(n.length-t)%r!==0&&o.push(n.slice(n.length-t).join(" ")),o})(e)),F=Array.from(new Set([...j,...R,...H].flatMap(e=>{const t=M(e.replace(/[\u00A0\u2009\u202F]/g," ").replace(/\u00ad/g,"").replace(/[""]/g,'"').replace(/['']/g,"'"));if(!t)return[];const r=t.replace(/[\u2013\u2014]/g,"-"),n=M(r.replace(/(\w)-\s+(\w)/g,"$1$2")),o=M(r.replace(/-/g," ")),l=M(r.replace(/-/g,"")),i=M(t.replace(/[^\w\s]/g,"")),s=new Set([t,r,n,o,l,i]);return Array.from(s).filter(Boolean)}))).filter(e=>{const t=e.split(/\s+/).filter(Boolean);return!(e.length<C)&&(t.length>=3||e.length>=12)}),N=l({keyword:F}),P=i(),L=s(),{jumpToMatch:O}=N,{jumpToPage:Z}=P,{zoomTo:D,CurrentScale:W,ZoomPopover:K}=L,J=o(()=>(e=>{if(0===e.length)return[];const t=new Map;e.forEach((e,r)=>{const n=null!=e.pageNumber?e.pageNumber-1:e.pageIndex;t.has(n)||t.set(n,[]),t.get(n).push({...e,originalIndex:r})});const r=[];return t.forEach(e=>{const t=[...e].sort((e,t)=>e.top!==t.top?e.top-t.top:e.left-t.left),n=new Array(t.length).fill(!1);for(let e=0;e<t.length;e++){if(n[e])continue;let{left:o,top:l,width:i,height:s,pageIndex:c,pageNumber:a}=t[e],h=o+i,g=l+s;const u=[t[e].originalIndex];n[e]=!0;let p=!0;for(;p;){p=!1;for(let r=e+1;r<t.length;r++){if(n[r])continue;const e=t[r],c=e.left+e.width,a=e.top+e.height,f=Math.max(0,Math.min(h,c)-Math.max(o,e.left))*Math.max(0,Math.min(g,a)-Math.max(l,e.top)),d=Math.max(i*s,1e-4),m=Math.max(e.width*e.height,1e-4),x=Math.min(d,m);(x>0?f/x:0)>=.8&&(o=Math.min(o,e.left),l=Math.min(l,e.top),h=Math.max(h,c),g=Math.max(g,a),i=h-o,s=g-l,u.push(e.originalIndex),n[r]=!0,p=!0)}}r.push({pageIndex:c,pageNumber:a,left:o,top:l,width:i,height:s,originalIndexes:u})}}),r})(f),[f]),V=c({renderHighlights:r=>e(t,{children:J.filter(e=>null!=e.pageNumber?e.pageNumber-1===r.pageIndex:e.pageIndex===r.pageIndex).map(t=>{const r=t.originalIndexes.includes(y);return e("div",{style:{position:"absolute",left:`${t.left}%`,top:`${t.top+.08*t.height}%`,width:`${t.width}%`,height:.95*t.height+"%",background:r?m:d,opacity:r?.7:.4,transition:"background 0.2s, opacity 0.2s",border:r?"1px solid red":"1px solid transparent"}},t.originalIndexes.join("-"))})})}),G=()=>{if(!v.current)try{O(0),v.current=!0;const e=f[0];e&&p&&U(e.pageIndex,e.top)}catch{requestAnimationFrame(G)}},Q=(e,t)=>{if(!g.current)return;if(!g.current.querySelector(".rpv-core__viewer"))return;let r=-1;const n=()=>{const o=g.current?.querySelector(".rpv-core__inner-pages");if(!o)return;if(o.scrollTop!==r)return r=o.scrollTop,void setTimeout(n,100);const l=g.current?.querySelector(`[data-testid="core__page-layer-${e}"]`);if(!l)return;const i=l.querySelectorAll(".rpv-search__highlight")[t];if(!i)return;const s=o.getBoundingClientRect(),c=i.getBoundingClientRect(),a=o.scrollTop+(c.top-s.top)-o.clientHeight/2+c.height/2;o.scrollTo({top:a,behavior:"smooth"})};setTimeout(n,300)},U=(e,t,r=0)=>{if(!g.current)return;let n=0;const o=()=>{if(++n>60)return;const l=g.current?.querySelector(".rpv-core__inner-pages");if(!l)return void setTimeout(o,100);const i=g.current?.querySelector(`[data-testid="core__page-layer-${e}"]`);if(!i)return void setTimeout(o,100);const s=i.getBoundingClientRect();if(0===s.height)return void setTimeout(o,100);const c=l.getBoundingClientRect(),a=t/100*s.height,h=r/100*s.height,u=s.top-c.top+a,p=u+h;if(u>=80&&p<=l.clientHeight-80)return;const f=u<80?l.scrollTop+u-80:l.scrollTop+p-l.clientHeight+80;l.scrollTo({top:f,behavior:"smooth"})};setTimeout(o,100)},X=o(()=>{const e={};return E.forEach((t,r)=>{const n=h[t];n>0&&(e[n]||(e[n]=[]),e[n].push(r))}),e},[E,h]),Y=e=>{const t=h[E[e]];return(X[t]||[]).indexOf(e)},ee=(e,t,r=0)=>{if(!g.current)return;let n=-1,o=0;const l=()=>{if(++o>60)return;const i=g.current?.querySelector(".rpv-core__inner-pages");if(!i)return void setTimeout(l,100);if(i.scrollTop!==n)return n=i.scrollTop,void setTimeout(l,100);const s=g.current?.querySelector(`[data-testid="core__page-layer-${e}"]`);if(!s)return void setTimeout(l,100);const c=s.getBoundingClientRect();if(0===c.height)return void setTimeout(l,100);const a=i.getBoundingClientRect(),h=t/100*c.height,u=r/100*c.height,p=c.top-a.top+h,f=p+u;if(p>=80&&f<=i.clientHeight-80)return;const d=p<80?i.scrollTop+p-80:i.scrollTop+f-i.clientHeight+80;i.scrollTo({top:d,behavior:"instant"})};setTimeout(l,100)};return{setHighlightIndex:T,highlightIndex:x,cursorIndex:y,setCursorIndex:w,orderedKeys:E,totalHighlights:A,getValidPosition:e=>{if(p)return e+1;if(!h)return 0;let t=0;for(let r=0;r<=e;r++)h[E[r]]>0&&t++;return t},tryJump:G,jumpToPage:Z,zoomTo:D,hideNonTargetHighlights:z,deduplicateHighlights:k,scrollToCoord:U,plugins:[p?V:N,P,L],controls:{CurrentScale:W,ZoomPopover:K,zoomTo:D,goToNext:()=>{if(p&&f)for(let e=y+1;e<f.length;e++){const t=f[e],r=f[y];return w(e),void(t.pageIndex!==r.pageIndex?(Z(t.pageIndex),ee(t.pageIndex,t.top,t.height)):U(t.pageIndex,t.top,t.height))}else{for(let e=y+1;e<E.length;e++){const t=E[e];if(h[t]>0){const r=h[t]-1,n=Y(e);return w(e),Z(h[t]-1),Q(r,n),setTimeout(()=>{k(r)},500),void(1===Object.keys(h).length&&z(u))}}}},goToPrevious:()=>{if(p&&f)for(let e=y-1;e>=0;e--){const t=f[e],r=f[y];return w(e),void(t.pageIndex!==r.pageIndex?(Z(t.pageIndex),ee(t.pageIndex,t.top,t.height)):U(t.pageIndex,t.top,t.height))}else{for(let e=y-1;e>=0;e--){const t=E[e];if(h[t]>0){const r=h[t]-1,n=Y(e);return w(e),Z(h[t]-1),Q(r,n),setTimeout(()=>{k(r)},500),void(1===Object.keys(h).length&&z(u))}}}}}}};export{a as PdfHighlightControls};
|
|
1
|
+
import{jsx as e,Fragment as t}from"react/jsx-runtime";import{useState as r,useRef as n,useMemo as o}from"react";import{searchPlugin as l}from"@react-pdf-viewer/search";import{pageNavigationPlugin as i}from"@react-pdf-viewer/page-navigation";import{zoomPlugin as s}from"@react-pdf-viewer/zoom";import{highlightPlugin as c}from"@react-pdf-viewer/highlight";const a=(a,h,g,u,p,f,d="yellow",m="#F6D739")=>{const[x,v]=r(0),T=n(!1),[y,b]=r(0);n([]);const w=n(0),M=e=>e.replace(/[^\S\n]+/g," ").trim(),_=e=>(e||"").toLowerCase().replace(/\u00ad/g,"").replace(/[""]/g,'"').replace(/['']/g,"'").replace(/[\u2013\u2014]/g,"-").replace(/-/g," ").replace(/[^\w\s]/g,"").replace(/\s+/g," ").trim(),I=e=>{let t=e.trim();t=t.replace(/[\u200B-\u200D\uFEFF]/g,"").replace(/[\u00A0\u2009\u202F]/g," "),t=t.replace(/^[-•]\s+/,"");const r=t.match(/^((\d+(?:\.\d+)*[.)]?)|[A-Za-z][.)]|\([A-Za-z0-9]+\)|(?:i|ii|iii|iv|v|vi|vii|viii|ix|x)[.)])\s*/i);return r?t.slice(r[0].length).trim():t},S=e=>{const t=_(e),r=t.replace(/\s+/g,""),n=new Set;return t&&n.add(t),r&&n.add(r),n},$=e=>e.replace(/\\([''])/g,"$1").replace(/\]\s*\n\s*\(/g,"](").replace(/&[#\w]+;/g,e=>(e=>{const t=document.createElement("textarea");return t.innerHTML=e,t.value})(e)).replace(/<br\s*\/?>/gi,"\n").replace(/\[([^\]]+)\]\(([^)]+)\)/g,"$1").replace(/`([^`]+)`/g,"$1"),A=e=>{if(!e)return[];return $(e).split(/\n+/).map(I).flatMap(e=>{const t=e.match(/^\s*\|(.+)\|\s*$/);return t?t[1].split("|").map(e=>e.trim()).filter(Boolean):[e]}).map(e=>M((e=>e.replace(/(^|\W)[*_]{1,3}([^*_]+)[*_]{1,3}(?=\W|$)/g,"$1$2"))(e))).filter(Boolean)},E=Object.keys(h).map(Number).sort((e,t)=>e-t),k=o(()=>p?f.length:p?0:Object.values(h).filter(e=>e>0).length,[f,h]),z=e=>{if(!g.current)return;const t=g.current.querySelector(`[data-testid="search__highlights-${e}"]`);if(!t)return;const r=Array.from(t.querySelectorAll(".rpv-search__highlight"));if(0===r.length)return;const n=R.map(S),o=H.map(S);if(0===n.length&&0===o.length)return;const l=r.map(e=>{const t=(e=>{const t=e.getBoundingClientRect();if(t.height>0||t.width>0)return{top:t.top,left:t.left,right:t.right};const r=e.offsetTop,n=e.offsetLeft;return{top:r,left:n,right:n+e.offsetWidth}})(e),r=(e.textContent||"").trim(),n=(e.getAttribute("title")||"").trim();return{el:e,text:r||n,...t}}).filter(e=>e.text.length>0).sort((e,t)=>e.top-t.top||e.left-t.left);if(0===l.length)return;const i=[];let s=null,c=[];const h=()=>{if(!s)return;const e=c.join(" ");s.title=_(e),s.title&&i.push(s),s=null,c=[]};if(l.forEach(e=>{if(!s)return s={title:"",elements:[e.el],lastTop:e.top,lastRight:e.right},void(c=[e.text]);const t=Math.abs(e.top-s.lastTop)<=5,r=e.left<=s.lastRight+28;t&&r?(s.elements.push(e.el),s.lastTop=e.top,s.lastRight=Math.max(s.lastRight,e.right),c.push(e.text)):(h(),s={title:"",elements:[e.el],lastTop:e.top,lastRight:e.right},c=[e.text])}),h(),0===i.length)return;const u=(e,t)=>{if(!e)return!1;if(t.has(e))return!0;const r=e.replace(/\s+/g,"");for(const n of Array.from(t)){if(!n)continue;const t=n.replace(/\s+/g,"");if(t===r)return!0;if(n.length>=8&&e.length>=5&&n.includes(e))return!0;if(t.length>=8&&r.length>=5&&t.includes(r))return!0;if(e.length>=10&&n.length>=8&&e.includes(n))return!0;if(r.length>=10&&t.length>=8&&r.includes(t))return!0}return!1};let p=0,f=new Set;const d=Array.from(new Set([...R,...H].map(_).filter(e=>e.length>=8))).sort((e,t)=>t.length-e.length),m=e=>{if(!e||e.length<8)return null;const t=e.replace(/\s+/g,"");for(let r=0;r<i.length;r++){let n="",o="";const l=new Set;for(let s=r;s<i.length&&s<r+20;s++){const r=i[s].title;if(n=n?`${n} ${r}`:r,o=o?`${o}${r.replace(/\s+/g,"")}`:r.replace(/\s+/g,""),l.add(s),n.includes(e)||o.includes(t))return l;if(n.length>=15&&(e.includes(n)||t.includes(o)))return l;if(n.length>e.length+150)break}}return null};for(const e of d){const t=m(e);t&&t.size>0&&(t.forEach(e=>f.add(e)),p=f.size)}if(0===p){const e=(e=>{if(0===e.length)return null;let t=null;for(const r of e)for(const e of Array.from(r)){if(!e||e.length<5)continue;const r=e.replace(/\s+/g,"");for(let n=0;n<i.length;n++){let o="",l="";const s=new Set;for(let c=n;c<i.length&&c<n+15;c++){const n=i[c].title;if(o=o?`${o} ${n}`:n,l=l?`${l}${n.replace(/\s+/g,"")}`:n.replace(/\s+/g,""),s.add(c),o.includes(e)||l.includes(r)){const r=Math.max(0,o.length-e.length);(!t||r<t.extra)&&(t={blocks:new Set(s),extra:r});break}if(o.length>e.length+120)break}}}return t?t.blocks:null})(n);e&&e.size>0&&(e.forEach(e=>f.add(e)),p=f.size)}const x=(e=>{if(e.length<2)return 40;const t=[];for(let r=1;r<e.length;r++){const n=Math.abs(e[r].lastTop-e[r-1].lastTop);n>0&&t.push(n)}if(0===t.length)return 40;t.sort((e,t)=>e-t);const r=t[Math.floor(t.length/2)],n=Math.round(2.25*r);return Math.min(60,Math.max(24,n))})(i),v=H.map(_).filter(e=>e.length>=8),T=v.map(e=>e.split(/\s+/).filter(e=>e.length>=2));if(0===p){const e=o;for(let t=0;t<i.length;t++){const r=i[t].title;for(let n=0;n<e.length;n++){if(!u(r,e[n]))continue;let o=0;const l=new Set;let s=n,c=t-1;for(let r=t;r<i.length&&s<e.length;r++){if(u(i[r].title,e[s])){if(c>=0){const e=i[c].lastTop,t=i[r].lastTop;if(Math.abs(t-e)>x)break}o++,l.add(r),c=r,s++}else if(s>0&&u(i[r].title,e[s-1])){const e=i[c].lastTop,t=i[r].lastTop;Math.abs(t-e)<=3&&(l.add(r),c=r)}if(r-c>6)break}o>p&&(p=o,f=l)}}}if(p<Math.min(3,v.length)&&v.length>0){const e=new Set;i.forEach((t,r)=>{const n=t.title.split(/\s+/).filter(e=>e.length>=2);if(n.length<2)return;const o=new Set(n);for(const t of T){if(t.length<2)continue;let n=0;for(const e of t)o.has(e)&&n++;const l=n/t.length;if(n>=3||l>=.5){e.add(r);break}}}),e.size>0&&(f=e,p=Math.max(p,e.size))}const y=new Set;if(F.forEach(e=>{const t=_(e);t&&(y.add(t),y.add(t.replace(/\s+/g,"")))}),0===p){const e=new Set;if(i.forEach((t,r)=>{const n=t.title.replace(/\s+/g,"");if(y.has(t.title)||y.has(n))return void e.add(r);const o=Array.from(y);for(let n=0;n<o.length;n++){const l=o[n];if(l.length>=10&&l.includes(t.title)&&t.title.length>=5){e.add(r);break}}}),0===e.size)return 0;f=e}i.forEach((e,t)=>{const r=f.has(t);e.elements.forEach(e=>{r?(e.classList.add("verified-match"),e.style.display=""):(e.style.display="none",e.classList.remove("verified-match"))})});const b=[];return i.forEach((e,t)=>{f.has(t)&&e.elements.forEach(e=>b.push(e))}),requestAnimationFrame(()=>{const e=b.map(e=>({el:e,rect:e.getBoundingClientRect()})).filter(e=>e.rect.width>0&&e.rect.height>0).sort((e,t)=>t.rect.width*t.rect.height-e.rect.width*e.rect.height),t=[];e.forEach(({el:e,rect:r})=>{t.some(e=>((e,t)=>{const r=Math.max(0,Math.min(e.right,t.right)-Math.max(e.left,t.left))*Math.max(0,Math.min(e.bottom,t.bottom)-Math.max(e.top,t.top)),n=Math.min(e.width*e.height,t.width*t.height);return n>0?r/n:0})(e.rect,r)>.5)?(e.style.display="none",e.classList.remove("verified-match")):t.push({el:e,rect:r})})}),console.groupCollapsed(`[debug: PDF ordered matching - Page ${e}]`),console.log("input->",a),console.log("processed sentences->",R),console.log("processed lines->",H),console.log("Expected sentence count:",n.length),console.log("Expected line count:",o.length),console.log("Matched sequence length:",p),console.log("blocksToKeep",f,"size",f.size),console.groupEnd(),f.size},C=e=>{if(!g.current)return;g.current.querySelectorAll(".rpv-search__highlights").forEach(t=>{const r=t.getAttribute("data-testid"),n=parseInt(r?.replace(/search__highlights-/g,"")||"-1"),o=t.querySelectorAll(".rpv-search__highlight");e.has(n)||o.forEach(e=>{e.style.display="none"})})},q=a.map(e=>(e=>e?$(e).split(/\n{2,}/).map(e=>A(e).join(" ")).map(e=>M(e)).filter(Boolean):[])(e)).flat(),B=a.map(e=>A(e)).flat(),j=q.some(e=>e.length>=3)?3:1,R=q.filter(e=>e.length>=j),H=B.filter(e=>e.length>=j),N=H.flatMap(e=>((e,t=6,r=4)=>{const n=e.split(/\s+/).filter(Boolean);if(n.length<=t)return[];const o=[];for(let e=0;e+t<=n.length;e+=r)o.push(n.slice(e,e+t).join(" "));return n.length>t&&(n.length-t)%r!==0&&o.push(n.slice(n.length-t).join(" ")),o})(e)),F=Array.from(new Set([...R,...H,...N].flatMap(e=>{const t=M(e.replace(/[\u00A0\u2009\u202F]/g," ").replace(/\u00ad/g,"").replace(/[""]/g,'"').replace(/['']/g,"'"));if(!t)return[];const r=t.replace(/[\u2013\u2014]/g,"-"),n=M(r.replace(/(\w)-\s+(\w)/g,"$1$2")),o=M(r.replace(/-/g," ")),l=M(r.replace(/-/g,"")),i=M(t.replace(/[^\w\s]/g,"")),s=new Set([t,r,n,o,l,i]);return Array.from(s).filter(Boolean)}))).filter(e=>{const t=e.split(/\s+/).filter(Boolean);return!(e.length<j)&&(t.length>=3||e.length>=12)}),P=l({keyword:F}),L=i(),O=s(),{jumpToMatch:Z}=P,{jumpToPage:D}=L,{zoomTo:W,CurrentScale:K,ZoomPopover:J}=O,V=o(()=>(e=>{if(0===e.length)return[];const t=new Map;e.forEach((e,r)=>{const n=null!=e.pageNumber?e.pageNumber-1:e.pageIndex;t.has(n)||t.set(n,[]),t.get(n).push({...e,originalIndex:r})});const r=[];return t.forEach(e=>{const t=[...e].sort((e,t)=>e.top!==t.top?e.top-t.top:e.left-t.left),n=new Array(t.length).fill(!1);for(let e=0;e<t.length;e++){if(n[e])continue;let{left:o,top:l,width:i,height:s,pageIndex:c,pageNumber:a}=t[e],h=o+i,g=l+s;const u=[t[e].originalIndex];n[e]=!0;let p=!0;for(;p;){p=!1;for(let r=e+1;r<t.length;r++){if(n[r])continue;const e=t[r],c=e.left+e.width,a=e.top+e.height,f=Math.max(0,Math.min(h,c)-Math.max(o,e.left))*Math.max(0,Math.min(g,a)-Math.max(l,e.top)),d=Math.max(i*s,1e-4),m=Math.max(e.width*e.height,1e-4),x=Math.min(d,m);(x>0?f/x:0)>=.8&&(o=Math.min(o,e.left),l=Math.min(l,e.top),h=Math.max(h,c),g=Math.max(g,a),i=h-o,s=g-l,u.push(e.originalIndex),n[r]=!0,p=!0)}}r.push({pageIndex:c,pageNumber:a,left:o,top:l,width:i,height:s,originalIndexes:u})}}),r})(f),[f]),G=c({renderHighlights:r=>e(t,{children:V.filter(e=>null!=e.pageNumber?e.pageNumber-1===r.pageIndex:e.pageIndex===r.pageIndex).map(t=>{const r=t.originalIndexes.includes(y);return e("div",{style:{position:"absolute",left:`${t.left}%`,top:`${t.top+.08*t.height}%`,width:`${t.width}%`,height:.95*t.height+"%",background:r?m:d,opacity:r?.7:.4,transition:"background 0.2s, opacity 0.2s",border:r?"1px solid red":"1px solid transparent"}},t.originalIndexes.join("-"))})})}),Q=()=>{if(!T.current)try{Z(0),T.current=!0;const e=f[0];e&&p&&X(e.pageIndex,e.top)}catch{requestAnimationFrame(Q)}},U=(e,t)=>{if(!g.current)return;if(!g.current.querySelector(".rpv-core__viewer"))return;let r=-1;const n=()=>{const o=g.current?.querySelector(".rpv-core__inner-pages");if(!o)return;if(o.scrollTop!==r)return r=o.scrollTop,void setTimeout(n,100);const l=g.current?.querySelector(`[data-testid="core__page-layer-${e}"]`);if(!l)return;const i=l.querySelectorAll(".rpv-search__highlight")[t];if(!i)return;const s=o.getBoundingClientRect(),c=i.getBoundingClientRect(),a=o.scrollTop+(c.top-s.top)-o.clientHeight/2+c.height/2;o.scrollTo({top:a,behavior:"smooth"})};setTimeout(n,300)},X=(e,t,r=0)=>{if(!g.current)return;w.current+=1;let n=0;const o=()=>{if(++n>60)return;const l=g.current?.querySelector(".rpv-core__inner-pages");if(!l)return void setTimeout(o,100);const i=g.current?.querySelector(`[data-testid="core__page-layer-${e}"]`);if(!i)return void setTimeout(o,100);const s=i.getBoundingClientRect();if(0===s.height)return void setTimeout(o,100);const c=l.getBoundingClientRect(),a=t/100*s.height,h=r/100*s.height,u=s.top-c.top+a,p=u+h;if(u>=80&&p<=l.clientHeight-80)return;const f=u<80?l.scrollTop+u-80:l.scrollTop+p-l.clientHeight+80;l.scrollTo({top:f,behavior:"smooth"})};setTimeout(o,100)},Y=o(()=>{const e={};return E.forEach((t,r)=>{const n=h[t];n>0&&(e[n]||(e[n]=[]),e[n].push(r))}),e},[E,h]),ee=e=>{const t=h[E[e]];return(Y[t]||[]).indexOf(e)},te=(e,t,r=0)=>{if(!g.current)return;const n=++w.current;let o=null,l=0,i=0;const s=()=>{if(w.current!==n)return;if(++i>60)return;const c=g.current?.querySelector(".rpv-core__inner-pages");if(!c)return void setTimeout(s,100);const a=g.current?.querySelector(`[data-testid="core__page-layer-${e}"]`);if(!a)return void setTimeout(s,100);const h=a.getBoundingClientRect();if(0===h.height)return void setTimeout(s,100);const u=c.getBoundingClientRect(),p=h.bottom>u.top&&h.top<u.bottom;if(o===c.scrollTop?l+=1:(o=c.scrollTop,l=0),!p||l<2)return void setTimeout(s,100);const f=t/100*h.height,d=r/100*h.height,m=h.top-u.top+f+d/2,x=c.scrollTop+m-c.clientHeight/2;c.scrollTo({top:x,behavior:"smooth"})};setTimeout(s,100)};return{setHighlightIndex:v,highlightIndex:x,cursorIndex:y,setCursorIndex:b,orderedKeys:E,totalHighlights:k,getValidPosition:e=>{if(p)return e+1;if(!h)return 0;let t=0;for(let r=0;r<=e;r++)h[E[r]]>0&&t++;return t},tryJump:Q,jumpToPage:D,zoomTo:W,hideNonTargetHighlights:C,deduplicateHighlights:z,scrollToCoord:X,scrollToCoordAfterNav:te,plugins:[p?G:P,L,O],controls:{CurrentScale:K,ZoomPopover:J,zoomTo:W,goToNext:()=>{if(p&&f)for(let e=y+1;e<f.length;e++){const t=f[e],r=f[y];return b(e),void(t.pageIndex!==r.pageIndex?(D(t.pageIndex),te(t.pageIndex,t.top,t.height)):X(t.pageIndex,t.top,t.height))}else{for(let e=y+1;e<E.length;e++){const t=E[e];if(h[t]>0){const r=h[t]-1,n=ee(e);return b(e),D(h[t]-1),U(r,n),setTimeout(()=>{z(r)},500),void(1===Object.keys(h).length&&C(u))}}}},goToPrevious:()=>{if(p&&f)for(let e=y-1;e>=0;e--){const t=f[e],r=f[y];return b(e),void(t.pageIndex!==r.pageIndex?(D(t.pageIndex),te(t.pageIndex,t.top,t.height)):X(t.pageIndex,t.top,t.height))}else{for(let e=y-1;e>=0;e--){const t=E[e];if(h[t]>0){const r=h[t]-1,n=ee(e);return b(e),D(h[t]-1),U(r,n),setTimeout(()=>{z(r)},500),void(1===Object.keys(h).length&&C(u))}}}}}}};export{a as PdfHighlightControls};
|
|
2
2
|
//# sourceMappingURL=usePdfHighlight.js.map
|