pdf-search-highlight 0.2.2 → 0.3.0

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.
@@ -5,7 +5,7 @@
5
5
 
6
6
 
7
7
 
8
- var _chunkY5LFTIMYcjs = require('../chunk-Y5LFTIMY.cjs');
8
+ var _chunkGDUHZCFRcjs = require('../chunk-GDUHZCFR.cjs');
9
9
 
10
10
  // src/react/usePDFRenderer.ts
11
11
  var _react = require('react');
@@ -27,7 +27,7 @@ function usePDFRenderer(pdfjsLib, options = {}) {
27
27
  const getRenderer = _react.useCallback.call(void 0, () => {
28
28
  if (!containerRef.current) throw new Error("Container ref not attached");
29
29
  if (!rendererRef.current) {
30
- const r = new (0, _chunkY5LFTIMYcjs.PDFRenderer)(containerRef.current, optionsRef.current);
30
+ const r = new (0, _chunkGDUHZCFRcjs.PDFRenderer)(containerRef.current, optionsRef.current);
31
31
  r.setPdfjsLib(pdfjsLib);
32
32
  rendererRef.current = r;
33
33
  }
@@ -64,13 +64,13 @@ function usePDFRenderer(pdfjsLib, options = {}) {
64
64
  const zoomIn = _react.useCallback.call(void 0, async () => {
65
65
  const renderer = getRenderer();
66
66
  const current = renderer.getScale() === "auto" ? renderer.getEffectiveScale() : renderer.getScale();
67
- const newScale = Math.min(current + _chunkY5LFTIMYcjs.ZOOM_STEP, _chunkY5LFTIMYcjs.MAX_SCALE);
67
+ const newScale = Math.min(current + _chunkGDUHZCFRcjs.ZOOM_STEP, _chunkGDUHZCFRcjs.MAX_SCALE);
68
68
  return setScale(newScale);
69
69
  }, [getRenderer, setScale]);
70
70
  const zoomOut = _react.useCallback.call(void 0, async () => {
71
71
  const renderer = getRenderer();
72
72
  const current = renderer.getScale() === "auto" ? renderer.getEffectiveScale() : renderer.getScale();
73
- const newScale = Math.max(current - _chunkY5LFTIMYcjs.ZOOM_STEP, _chunkY5LFTIMYcjs.MIN_SCALE);
73
+ const newScale = Math.max(current - _chunkGDUHZCFRcjs.ZOOM_STEP, _chunkGDUHZCFRcjs.MIN_SCALE);
74
74
  return setScale(newScale);
75
75
  }, [getRenderer, setScale]);
76
76
  const download = _react.useCallback.call(void 0,
@@ -108,7 +108,7 @@ function useSearchController(pages, options = {}) {
108
108
  const [current, setCurrent] = _react.useState.call(void 0, -1);
109
109
  const [total, setTotal] = _react.useState.call(void 0, 0);
110
110
  if (!controllerRef.current) {
111
- controllerRef.current = new (0, _chunkY5LFTIMYcjs.SearchController)(options);
111
+ controllerRef.current = new (0, _chunkGDUHZCFRcjs.SearchController)(options);
112
112
  }
113
113
  _react.useEffect.call(void 0, () => {
114
114
  const ctrl = controllerRef.current;
@@ -126,6 +126,12 @@ function useSearchController(pages, options = {}) {
126
126
  const search = _react.useCallback.call(void 0, (query, opts) => {
127
127
  return controllerRef.current.search(query, opts);
128
128
  }, []);
129
+ const searchMultiple = _react.useCallback.call(void 0,
130
+ (contexts, opts) => {
131
+ return controllerRef.current.searchMultiple(contexts, opts);
132
+ },
133
+ []
134
+ );
129
135
  const next = _react.useCallback.call(void 0, () => {
130
136
  controllerRef.current.next();
131
137
  }, []);
@@ -138,7 +144,7 @@ function useSearchController(pages, options = {}) {
138
144
  const clear = _react.useCallback.call(void 0, () => {
139
145
  controllerRef.current.clear();
140
146
  }, []);
141
- return { search, next, prev, goTo, clear, current, total };
147
+ return { search, searchMultiple, next, prev, goTo, clear, current, total };
142
148
  }
143
149
 
144
150
  // src/react/PDFSearchViewer.tsx
@@ -154,10 +160,12 @@ var PDFSearchViewer2 = _react.forwardRef.call(void 0, function PDFSearchViewer3(
154
160
  pdfjsLib,
155
161
  source,
156
162
  searchQuery,
163
+ searchContexts,
157
164
  searchOptions,
158
165
  viewerOptions,
159
166
  onLoad,
160
167
  onSearch,
168
+ onSearchMultiple,
161
169
  onMatchChange,
162
170
  onZoom,
163
171
  onError,
@@ -166,20 +174,21 @@ var PDFSearchViewer2 = _react.forwardRef.call(void 0, function PDFSearchViewer3(
166
174
  } = props;
167
175
  const containerRef = _react.useRef.call(void 0, null);
168
176
  const coreRef = _react.useRef.call(void 0, null);
169
- const callbackRefs = _react.useRef.call(void 0, { onLoad, onSearch, onMatchChange, onZoom, onError });
170
- callbackRefs.current = { onLoad, onSearch, onMatchChange, onZoom, onError };
177
+ const callbackRefs = _react.useRef.call(void 0, { onLoad, onSearch, onSearchMultiple, onMatchChange, onZoom, onError });
178
+ callbackRefs.current = { onLoad, onSearch, onSearchMultiple, onMatchChange, onZoom, onError };
171
179
  _react.useEffect.call(void 0, () => {
172
180
  if (!containerRef.current || !pdfjsLib) return;
173
- const core = new (0, _chunkY5LFTIMYcjs.PDFSearchViewer)(
181
+ const core = new (0, _chunkGDUHZCFRcjs.PDFSearchViewer)(
174
182
  containerRef.current,
175
183
  pdfjsLib,
176
184
  _nullishCoalesce(viewerOptions, () => ( {}))
177
185
  );
178
186
  core.on("load", (data) => _optionalChain([callbackRefs, 'access', _7 => _7.current, 'access', _8 => _8.onLoad, 'optionalCall', _9 => _9(data)]));
179
187
  core.on("search", (data) => _optionalChain([callbackRefs, 'access', _10 => _10.current, 'access', _11 => _11.onSearch, 'optionalCall', _12 => _12(data)]));
180
- core.on("matchchange", (data) => _optionalChain([callbackRefs, 'access', _13 => _13.current, 'access', _14 => _14.onMatchChange, 'optionalCall', _15 => _15(data)]));
181
- core.on("zoom", (data) => _optionalChain([callbackRefs, 'access', _16 => _16.current, 'access', _17 => _17.onZoom, 'optionalCall', _18 => _18(data)]));
182
- core.on("error", (data) => _optionalChain([callbackRefs, 'access', _19 => _19.current, 'access', _20 => _20.onError, 'optionalCall', _21 => _21(data)]));
188
+ core.on("searchmultiple", (data) => _optionalChain([callbackRefs, 'access', _13 => _13.current, 'access', _14 => _14.onSearchMultiple, 'optionalCall', _15 => _15(data)]));
189
+ core.on("matchchange", (data) => _optionalChain([callbackRefs, 'access', _16 => _16.current, 'access', _17 => _17.onMatchChange, 'optionalCall', _18 => _18(data)]));
190
+ core.on("zoom", (data) => _optionalChain([callbackRefs, 'access', _19 => _19.current, 'access', _20 => _20.onZoom, 'optionalCall', _21 => _21(data)]));
191
+ core.on("error", (data) => _optionalChain([callbackRefs, 'access', _22 => _22.current, 'access', _23 => _23.onError, 'optionalCall', _24 => _24(data)]));
183
192
  coreRef.current = core;
184
193
  return () => {
185
194
  core.destroy();
@@ -193,30 +202,33 @@ var PDFSearchViewer2 = _react.forwardRef.call(void 0, function PDFSearchViewer3(
193
202
  }, [source]);
194
203
  _react.useEffect.call(void 0, () => {
195
204
  if (!coreRef.current) return;
196
- if (searchQuery && searchQuery.trim().length > 0) {
205
+ if (searchContexts && searchContexts.length > 0) {
206
+ coreRef.current.searchMultiple(searchContexts, searchOptions);
207
+ } else if (searchQuery && searchQuery.trim().length > 0) {
197
208
  coreRef.current.search(searchQuery, searchOptions);
198
209
  } else {
199
210
  coreRef.current.clearSearch();
200
211
  }
201
- }, [searchQuery, searchOptions]);
212
+ }, [searchQuery, searchContexts, searchOptions]);
202
213
  _react.useImperativeHandle.call(void 0, ref, () => ({
203
- nextMatch: () => _nullishCoalesce(_optionalChain([coreRef, 'access', _22 => _22.current, 'optionalAccess', _23 => _23.nextMatch, 'call', _24 => _24()]), () => ( -1)),
204
- prevMatch: () => _nullishCoalesce(_optionalChain([coreRef, 'access', _25 => _25.current, 'optionalAccess', _26 => _26.prevMatch, 'call', _27 => _27()]), () => ( -1)),
205
- clearSearch: () => _optionalChain([coreRef, 'access', _28 => _28.current, 'optionalAccess', _29 => _29.clearSearch, 'call', _30 => _30()]),
206
- getMatchCount: () => _nullishCoalesce(_optionalChain([coreRef, 'access', _31 => _31.current, 'optionalAccess', _32 => _32.getMatchCount, 'call', _33 => _33()]), () => ( 0)),
207
- getCurrentMatchIndex: () => _nullishCoalesce(_optionalChain([coreRef, 'access', _34 => _34.current, 'optionalAccess', _35 => _35.getCurrentMatchIndex, 'call', _36 => _36()]), () => ( -1)),
214
+ nextMatch: () => _nullishCoalesce(_optionalChain([coreRef, 'access', _25 => _25.current, 'optionalAccess', _26 => _26.nextMatch, 'call', _27 => _27()]), () => ( -1)),
215
+ prevMatch: () => _nullishCoalesce(_optionalChain([coreRef, 'access', _28 => _28.current, 'optionalAccess', _29 => _29.prevMatch, 'call', _30 => _30()]), () => ( -1)),
216
+ clearSearch: () => _optionalChain([coreRef, 'access', _31 => _31.current, 'optionalAccess', _32 => _32.clearSearch, 'call', _33 => _33()]),
217
+ searchMultiple: (contexts, opts) => _nullishCoalesce(_optionalChain([coreRef, 'access', _34 => _34.current, 'optionalAccess', _35 => _35.searchMultiple, 'call', _36 => _36(contexts, opts)]), () => ( 0)),
218
+ getMatchCount: () => _nullishCoalesce(_optionalChain([coreRef, 'access', _37 => _37.current, 'optionalAccess', _38 => _38.getMatchCount, 'call', _39 => _39()]), () => ( 0)),
219
+ getCurrentMatchIndex: () => _nullishCoalesce(_optionalChain([coreRef, 'access', _40 => _40.current, 'optionalAccess', _41 => _41.getCurrentMatchIndex, 'call', _42 => _42()]), () => ( -1)),
208
220
  zoomIn: async () => {
209
- await _optionalChain([coreRef, 'access', _37 => _37.current, 'optionalAccess', _38 => _38.zoomIn, 'call', _39 => _39()]);
221
+ await _optionalChain([coreRef, 'access', _43 => _43.current, 'optionalAccess', _44 => _44.zoomIn, 'call', _45 => _45()]);
210
222
  },
211
223
  zoomOut: async () => {
212
- await _optionalChain([coreRef, 'access', _40 => _40.current, 'optionalAccess', _41 => _41.zoomOut, 'call', _42 => _42()]);
224
+ await _optionalChain([coreRef, 'access', _46 => _46.current, 'optionalAccess', _47 => _47.zoomOut, 'call', _48 => _48()]);
213
225
  },
214
226
  setScale: async (s) => {
215
- await _optionalChain([coreRef, 'access', _43 => _43.current, 'optionalAccess', _44 => _44.setScale, 'call', _45 => _45(s)]);
227
+ await _optionalChain([coreRef, 'access', _49 => _49.current, 'optionalAccess', _50 => _50.setScale, 'call', _51 => _51(s)]);
216
228
  },
217
- getScale: () => _nullishCoalesce(_optionalChain([coreRef, 'access', _46 => _46.current, 'optionalAccess', _47 => _47.getScale, 'call', _48 => _48()]), () => ( "auto")),
229
+ getScale: () => _nullishCoalesce(_optionalChain([coreRef, 'access', _52 => _52.current, 'optionalAccess', _53 => _53.getScale, 'call', _54 => _54()]), () => ( "auto")),
218
230
  download: async (filename) => {
219
- await _optionalChain([coreRef, 'access', _49 => _49.current, 'optionalAccess', _50 => _50.download, 'call', _51 => _51(filename)]);
231
+ await _optionalChain([coreRef, 'access', _55 => _55.current, 'optionalAccess', _56 => _56.download, 'call', _57 => _57(filename)]);
220
232
  },
221
233
  getCore: () => coreRef.current
222
234
  }));
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/hoangnguyen/Desktop/pdf-search-highlight/dist/react/index.cjs","../../src/react/usePDFRenderer.ts","../../src/react/useSearchController.ts","../../src/react/PDFSearchViewer.tsx"],"names":["useRef","useState","useEffect","useCallback","PDFSearchViewer"],"mappings":"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","file":"/Users/hoangnguyen/Desktop/pdf-search-highlight/dist/react/index.cjs","sourcesContent":[null,"import { useRef, useEffect, useCallback, useState } from 'react';\nimport { PDFRenderer } from '../core/PDFRenderer';\nimport { ZOOM_STEP, MIN_SCALE, MAX_SCALE } from '../core/constants';\nimport type { PDFSearchViewerOptions, PageData, PDFSource } from '../core';\n\nexport interface UsePDFRendererReturn {\n /** Ref to attach to the container div */\n containerRef: React.RefObject<HTMLDivElement | null>;\n /** Rendered page data (available after loading) */\n pages: PageData[];\n /** Number of pages */\n pageCount: number;\n /** Whether PDF is currently loading */\n loading: boolean;\n /** Current scale value */\n scale: number | 'auto';\n /** Load a PDF source */\n loadPDF: (source: PDFSource) => Promise<PageData[]>;\n /** Set scale and re-render */\n setScale: (scale: number | 'auto') => Promise<PageData[]>;\n /** Zoom in by one step */\n zoomIn: () => Promise<PageData[]>;\n /** Zoom out by one step */\n zoomOut: () => Promise<PageData[]>;\n /** Download the loaded PDF */\n download: (filename?: string) => Promise<void>;\n /** Clean up renderer */\n cleanup: () => void;\n}\n\n/**\n * Hook for rendering PDF into a container div.\n * Returns pages data that can be passed to useSearchController.\n *\n * ```tsx\n * const { containerRef, pages, loadPDF, zoomIn, zoomOut, download } = usePDFRenderer(pdfjsLib);\n *\n * return <div ref={containerRef} style={{ height: '80vh', overflow: 'auto' }} />;\n * ```\n */\nexport function usePDFRenderer(\n pdfjsLib: any,\n options: PDFSearchViewerOptions = {}\n): UsePDFRendererReturn {\n const containerRef = useRef<HTMLDivElement | null>(null);\n const rendererRef = useRef<PDFRenderer | null>(null);\n const [pages, setPages] = useState<PageData[]>([]);\n const [pageCount, setPageCount] = useState(0);\n const [loading, setLoading] = useState(false);\n const [scale, setScaleState] = useState<number | 'auto'>(options.scale ?? 'auto');\n\n // Init renderer when container is available\n useEffect(() => {\n return () => {\n rendererRef.current?.cleanup();\n rendererRef.current = null;\n };\n }, []);\n\n // Store options in a ref so getRenderer/loadPDF don't depend on object identity\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const getRenderer = useCallback(() => {\n if (!containerRef.current) throw new Error('Container ref not attached');\n if (!rendererRef.current) {\n const r = new PDFRenderer(containerRef.current, optionsRef.current);\n r.setPdfjsLib(pdfjsLib);\n rendererRef.current = r;\n }\n return rendererRef.current;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [pdfjsLib]);\n\n const loadPDF = useCallback(\n async (source: PDFSource): Promise<PageData[]> => {\n const renderer = getRenderer();\n setLoading(true);\n try {\n const count = await renderer.loadDocument(source);\n const p = await renderer.renderAllPages();\n setPages(p);\n setPageCount(count);\n setScaleState(renderer.getScale());\n return p;\n } finally {\n setLoading(false);\n }\n },\n [getRenderer]\n );\n\n const setScale = useCallback(\n async (newScale: number | 'auto'): Promise<PageData[]> => {\n const renderer = getRenderer();\n renderer.setScale(newScale);\n const p = await renderer.renderAllPages();\n setPages(p);\n setScaleState(newScale);\n return p;\n },\n [getRenderer]\n );\n\n const zoomIn = useCallback(async (): Promise<PageData[]> => {\n const renderer = getRenderer();\n const current = renderer.getScale() === 'auto'\n ? renderer.getEffectiveScale()\n : (renderer.getScale() as number);\n const newScale = Math.min(current + ZOOM_STEP, MAX_SCALE);\n return setScale(newScale);\n }, [getRenderer, setScale]);\n\n const zoomOut = useCallback(async (): Promise<PageData[]> => {\n const renderer = getRenderer();\n const current = renderer.getScale() === 'auto'\n ? renderer.getEffectiveScale()\n : (renderer.getScale() as number);\n const newScale = Math.max(current - ZOOM_STEP, MIN_SCALE);\n return setScale(newScale);\n }, [getRenderer, setScale]);\n\n const download = useCallback(\n async (filename?: string) => {\n const renderer = getRenderer();\n await renderer.download(filename);\n },\n [getRenderer]\n );\n\n const cleanup = useCallback(() => {\n rendererRef.current?.cleanup();\n rendererRef.current = null;\n setPages([]);\n setPageCount(0);\n }, []);\n\n return {\n containerRef, pages, pageCount, loading, scale,\n loadPDF, setScale, zoomIn, zoomOut, download, cleanup,\n };\n}\n","import { useRef, useEffect, useCallback, useState } from 'react';\nimport { SearchController } from '../core/SearchController';\nimport type { SearchOptions, ClassNames, PageData } from '../core';\n\nexport interface UseSearchControllerReturn {\n /** Run a search query */\n search: (query: string, options?: SearchOptions) => number;\n /** Go to next match */\n next: () => void;\n /** Go to previous match */\n prev: () => void;\n /** Go to specific match index */\n goTo: (index: number) => void;\n /** Clear all highlights */\n clear: () => void;\n /** Current active match index (0-based), -1 if none */\n current: number;\n /** Total number of matches */\n total: number;\n}\n\nexport interface UseSearchControllerOptions {\n classNames?: Pick<ClassNames, 'highlight' | 'activeHighlight'>;\n}\n\n/**\n * Hook for search + highlight logic (headless).\n * Pass pages from usePDFRenderer to connect them.\n *\n * ```tsx\n * const { containerRef, pages, loadPDF } = usePDFRenderer(pdfjsLib);\n * const { search, next, prev, current, total } = useSearchController(pages);\n *\n * return (\n * <>\n * <input onChange={e => search(e.target.value)} />\n * <span>{current + 1}/{total}</span>\n * <button onClick={prev}>Prev</button>\n * <button onClick={next}>Next</button>\n * <div ref={containerRef} />\n * </>\n * );\n * ```\n */\nexport function useSearchController(\n pages: PageData[],\n options: UseSearchControllerOptions = {}\n): UseSearchControllerReturn {\n const controllerRef = useRef<SearchController | null>(null);\n const [current, setCurrent] = useState(-1);\n const [total, setTotal] = useState(0);\n\n // Create controller once\n if (!controllerRef.current) {\n controllerRef.current = new SearchController(options);\n }\n\n // Sync onChange callback\n useEffect(() => {\n const ctrl = controllerRef.current!;\n ctrl.onChange = ({ current: c, total: t }) => {\n setCurrent(c);\n setTotal(t);\n };\n return () => {\n ctrl.onChange = null;\n };\n }, []);\n\n // Update pages when they change\n useEffect(() => {\n controllerRef.current!.setPages(pages);\n }, [pages]);\n\n const search = useCallback((query: string, opts?: SearchOptions) => {\n return controllerRef.current!.search(query, opts);\n }, []);\n\n const next = useCallback(() => {\n controllerRef.current!.next();\n }, []);\n\n const prev = useCallback(() => {\n controllerRef.current!.prev();\n }, []);\n\n const goTo = useCallback((index: number) => {\n controllerRef.current!.goTo(index);\n }, []);\n\n const clear = useCallback(() => {\n controllerRef.current!.clear();\n }, []);\n\n return { search, next, prev, goTo, clear, current, total };\n}\n","import {\n useRef,\n useEffect,\n useImperativeHandle,\n forwardRef,\n type Ref,\n type CSSProperties,\n} from 'react';\nimport {\n PDFSearchViewer as CorePDFSearchViewer,\n type PDFSearchViewerOptions,\n type SearchOptions,\n type PDFSource,\n} from '../core';\n\nexport interface PDFSearchViewerProps {\n /** pdfjs-dist library instance. Must be passed by consumer. */\n pdfjsLib: any;\n\n /** PDF source: URL string, File, ArrayBuffer, or Uint8Array. */\n source?: PDFSource | null;\n\n /** Search query string. Empty/undefined clears the search. */\n searchQuery?: string;\n\n /** Search options. */\n searchOptions?: SearchOptions;\n\n /** Viewer options (applied once on mount). */\n viewerOptions?: PDFSearchViewerOptions;\n\n /** Called when PDF finishes loading. */\n onLoad?: (data: { pageCount: number }) => void;\n\n /** Called when search completes. */\n onSearch?: (data: { query: string; total: number }) => void;\n\n /** Called when active match changes. */\n onMatchChange?: (data: { current: number; total: number }) => void;\n\n /** Called when zoom/scale changes. */\n onZoom?: (data: { scale: number }) => void;\n\n /** Called on error. */\n onError?: (data: { error: Error; context: string }) => void;\n\n /** Additional className for the container div. */\n className?: string;\n\n /** Inline style for the container div. */\n style?: CSSProperties;\n}\n\nexport interface PDFSearchViewerHandle {\n /** Navigate to next match. Returns new index. */\n nextMatch: () => number;\n /** Navigate to previous match. Returns new index. */\n prevMatch: () => number;\n /** Clear all search highlights. */\n clearSearch: () => void;\n /** Get total match count. */\n getMatchCount: () => number;\n /** Get current match index. */\n getCurrentMatchIndex: () => number;\n /** Zoom in by one step. */\n zoomIn: () => Promise<void>;\n /** Zoom out by one step. */\n zoomOut: () => Promise<void>;\n /** Set scale and re-render. */\n setScale: (scale: number | 'auto') => Promise<void>;\n /** Get current scale. */\n getScale: () => number | 'auto';\n /** Download the loaded PDF. */\n download: (filename?: string) => Promise<void>;\n /** Get underlying core instance. */\n getCore: () => CorePDFSearchViewer | null;\n}\n\nexport const PDFSearchViewer = forwardRef(function PDFSearchViewer(\n props: PDFSearchViewerProps,\n ref: Ref<PDFSearchViewerHandle>\n) {\n const {\n pdfjsLib,\n source,\n searchQuery,\n searchOptions,\n viewerOptions,\n onLoad,\n onSearch,\n onMatchChange,\n onZoom,\n onError,\n className,\n style,\n } = props;\n\n const containerRef = useRef<HTMLDivElement>(null);\n const coreRef = useRef<CorePDFSearchViewer | null>(null);\n\n // Store latest callbacks in refs to avoid re-subscribing\n const callbackRefs = useRef({ onLoad, onSearch, onMatchChange, onZoom, onError });\n callbackRefs.current = { onLoad, onSearch, onMatchChange, onZoom, onError };\n\n // Initialize core on mount\n useEffect(() => {\n if (!containerRef.current || !pdfjsLib) return;\n\n const core = new CorePDFSearchViewer(\n containerRef.current,\n pdfjsLib,\n viewerOptions ?? {}\n );\n\n core.on('load', (data) => callbackRefs.current.onLoad?.(data));\n core.on('search', (data) => callbackRefs.current.onSearch?.(data));\n core.on('matchchange', (data) => callbackRefs.current.onMatchChange?.(data));\n core.on('zoom', (data) => callbackRefs.current.onZoom?.(data));\n core.on('error', (data) => callbackRefs.current.onError?.(data));\n\n coreRef.current = core;\n\n return () => {\n core.destroy();\n coreRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [pdfjsLib]);\n\n // Load PDF when source changes\n useEffect(() => {\n if (!coreRef.current || !source) return;\n coreRef.current.loadPDF(source).catch(() => {\n // Error already emitted via 'error' event\n });\n }, [source]);\n\n // Run search when query or options change\n useEffect(() => {\n if (!coreRef.current) return;\n\n if (searchQuery && searchQuery.trim().length > 0) {\n coreRef.current.search(searchQuery, searchOptions);\n } else {\n coreRef.current.clearSearch();\n }\n }, [searchQuery, searchOptions]);\n\n // Expose imperative methods via ref\n useImperativeHandle(ref, () => ({\n nextMatch: () => coreRef.current?.nextMatch() ?? -1,\n prevMatch: () => coreRef.current?.prevMatch() ?? -1,\n clearSearch: () => coreRef.current?.clearSearch(),\n getMatchCount: () => coreRef.current?.getMatchCount() ?? 0,\n getCurrentMatchIndex: () => coreRef.current?.getCurrentMatchIndex() ?? -1,\n zoomIn: async () => { await coreRef.current?.zoomIn(); },\n zoomOut: async () => { await coreRef.current?.zoomOut(); },\n setScale: async (s: number | 'auto') => { await coreRef.current?.setScale(s); },\n getScale: () => coreRef.current?.getScale() ?? 'auto',\n download: async (filename?: string) => { await coreRef.current?.download(filename); },\n getCore: () => coreRef.current,\n }));\n\n return <div ref={containerRef} className={className} style={style} />;\n});\n"]}
1
+ {"version":3,"sources":["/Users/hoangnguyen/Desktop/labs/pdf-search-highlight/dist/react/index.cjs","../../src/react/usePDFRenderer.ts","../../src/react/useSearchController.ts","../../src/react/PDFSearchViewer.tsx"],"names":["useRef","useState","useEffect","useCallback","PDFSearchViewer"],"mappings":"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","file":"/Users/hoangnguyen/Desktop/labs/pdf-search-highlight/dist/react/index.cjs","sourcesContent":[null,"import { useRef, useEffect, useCallback, useState } from 'react';\nimport { PDFRenderer } from '../core/PDFRenderer';\nimport { ZOOM_STEP, MIN_SCALE, MAX_SCALE } from '../core/constants';\nimport type { PDFSearchViewerOptions, PageData, PDFSource } from '../core';\n\nexport interface UsePDFRendererReturn {\n /** Ref to attach to the container div */\n containerRef: React.RefObject<HTMLDivElement | null>;\n /** Rendered page data (available after loading) */\n pages: PageData[];\n /** Number of pages */\n pageCount: number;\n /** Whether PDF is currently loading */\n loading: boolean;\n /** Current scale value */\n scale: number | 'auto';\n /** Load a PDF source */\n loadPDF: (source: PDFSource) => Promise<PageData[]>;\n /** Set scale and re-render */\n setScale: (scale: number | 'auto') => Promise<PageData[]>;\n /** Zoom in by one step */\n zoomIn: () => Promise<PageData[]>;\n /** Zoom out by one step */\n zoomOut: () => Promise<PageData[]>;\n /** Download the loaded PDF */\n download: (filename?: string) => Promise<void>;\n /** Clean up renderer */\n cleanup: () => void;\n}\n\n/**\n * Hook for rendering PDF into a container div.\n * Returns pages data that can be passed to useSearchController.\n *\n * ```tsx\n * const { containerRef, pages, loadPDF, zoomIn, zoomOut, download } = usePDFRenderer(pdfjsLib);\n *\n * return <div ref={containerRef} style={{ height: '80vh', overflow: 'auto' }} />;\n * ```\n */\nexport function usePDFRenderer(\n pdfjsLib: any,\n options: PDFSearchViewerOptions = {}\n): UsePDFRendererReturn {\n const containerRef = useRef<HTMLDivElement | null>(null);\n const rendererRef = useRef<PDFRenderer | null>(null);\n const [pages, setPages] = useState<PageData[]>([]);\n const [pageCount, setPageCount] = useState(0);\n const [loading, setLoading] = useState(false);\n const [scale, setScaleState] = useState<number | 'auto'>(options.scale ?? 'auto');\n\n // Init renderer when container is available\n useEffect(() => {\n return () => {\n rendererRef.current?.cleanup();\n rendererRef.current = null;\n };\n }, []);\n\n // Store options in a ref so getRenderer/loadPDF don't depend on object identity\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const getRenderer = useCallback(() => {\n if (!containerRef.current) throw new Error('Container ref not attached');\n if (!rendererRef.current) {\n const r = new PDFRenderer(containerRef.current, optionsRef.current);\n r.setPdfjsLib(pdfjsLib);\n rendererRef.current = r;\n }\n return rendererRef.current;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [pdfjsLib]);\n\n const loadPDF = useCallback(\n async (source: PDFSource): Promise<PageData[]> => {\n const renderer = getRenderer();\n setLoading(true);\n try {\n const count = await renderer.loadDocument(source);\n const p = await renderer.renderAllPages();\n setPages(p);\n setPageCount(count);\n setScaleState(renderer.getScale());\n return p;\n } finally {\n setLoading(false);\n }\n },\n [getRenderer]\n );\n\n const setScale = useCallback(\n async (newScale: number | 'auto'): Promise<PageData[]> => {\n const renderer = getRenderer();\n renderer.setScale(newScale);\n const p = await renderer.renderAllPages();\n setPages(p);\n setScaleState(newScale);\n return p;\n },\n [getRenderer]\n );\n\n const zoomIn = useCallback(async (): Promise<PageData[]> => {\n const renderer = getRenderer();\n const current = renderer.getScale() === 'auto'\n ? renderer.getEffectiveScale()\n : (renderer.getScale() as number);\n const newScale = Math.min(current + ZOOM_STEP, MAX_SCALE);\n return setScale(newScale);\n }, [getRenderer, setScale]);\n\n const zoomOut = useCallback(async (): Promise<PageData[]> => {\n const renderer = getRenderer();\n const current = renderer.getScale() === 'auto'\n ? renderer.getEffectiveScale()\n : (renderer.getScale() as number);\n const newScale = Math.max(current - ZOOM_STEP, MIN_SCALE);\n return setScale(newScale);\n }, [getRenderer, setScale]);\n\n const download = useCallback(\n async (filename?: string) => {\n const renderer = getRenderer();\n await renderer.download(filename);\n },\n [getRenderer]\n );\n\n const cleanup = useCallback(() => {\n rendererRef.current?.cleanup();\n rendererRef.current = null;\n setPages([]);\n setPageCount(0);\n }, []);\n\n return {\n containerRef, pages, pageCount, loading, scale,\n loadPDF, setScale, zoomIn, zoomOut, download, cleanup,\n };\n}\n","import { useRef, useEffect, useCallback, useState } from 'react';\nimport { SearchController } from '../core/SearchController';\nimport type { SearchOptions, ClassNames, PageData, SearchContext } from '../core';\n\nexport interface UseSearchControllerReturn {\n /** Run a search query */\n search: (query: string, options?: SearchOptions) => number;\n /** Search multiple contexts with different highlight colors */\n searchMultiple: (contexts: SearchContext[], options?: SearchOptions) => number;\n /** Go to next match */\n next: () => void;\n /** Go to previous match */\n prev: () => void;\n /** Go to specific match index */\n goTo: (index: number) => void;\n /** Clear all highlights */\n clear: () => void;\n /** Current active match index (0-based), -1 if none */\n current: number;\n /** Total number of matches */\n total: number;\n}\n\nexport interface UseSearchControllerOptions {\n classNames?: Pick<ClassNames, 'highlight' | 'activeHighlight'>;\n}\n\n/**\n * Hook for search + highlight logic (headless).\n * Pass pages from usePDFRenderer to connect them.\n *\n * ```tsx\n * const { containerRef, pages, loadPDF } = usePDFRenderer(pdfjsLib);\n * const { search, searchMultiple, next, prev, current, total } = useSearchController(pages);\n *\n * return (\n * <>\n * <input onChange={e => search(e.target.value)} />\n * <span>{current + 1}/{total}</span>\n * <button onClick={prev}>Prev</button>\n * <button onClick={next}>Next</button>\n * <div ref={containerRef} />\n * </>\n * );\n * ```\n */\nexport function useSearchController(\n pages: PageData[],\n options: UseSearchControllerOptions = {}\n): UseSearchControllerReturn {\n const controllerRef = useRef<SearchController | null>(null);\n const [current, setCurrent] = useState(-1);\n const [total, setTotal] = useState(0);\n\n // Create controller once\n if (!controllerRef.current) {\n controllerRef.current = new SearchController(options);\n }\n\n // Sync onChange callback\n useEffect(() => {\n const ctrl = controllerRef.current!;\n ctrl.onChange = ({ current: c, total: t }) => {\n setCurrent(c);\n setTotal(t);\n };\n return () => {\n ctrl.onChange = null;\n };\n }, []);\n\n // Update pages when they change\n useEffect(() => {\n controllerRef.current!.setPages(pages);\n }, [pages]);\n\n const search = useCallback((query: string, opts?: SearchOptions) => {\n return controllerRef.current!.search(query, opts);\n }, []);\n\n const searchMultiple = useCallback(\n (contexts: SearchContext[], opts?: SearchOptions) => {\n return controllerRef.current!.searchMultiple(contexts, opts);\n },\n []\n );\n\n const next = useCallback(() => {\n controllerRef.current!.next();\n }, []);\n\n const prev = useCallback(() => {\n controllerRef.current!.prev();\n }, []);\n\n const goTo = useCallback((index: number) => {\n controllerRef.current!.goTo(index);\n }, []);\n\n const clear = useCallback(() => {\n controllerRef.current!.clear();\n }, []);\n\n return { search, searchMultiple, next, prev, goTo, clear, current, total };\n}\n","import {\n useRef,\n useEffect,\n useImperativeHandle,\n forwardRef,\n type Ref,\n type CSSProperties,\n} from 'react';\nimport {\n PDFSearchViewer as CorePDFSearchViewer,\n type PDFSearchViewerOptions,\n type SearchOptions,\n type SearchContext,\n type PDFSource,\n} from '../core';\n\nexport interface PDFSearchViewerProps {\n /** pdfjs-dist library instance. Must be passed by consumer. */\n pdfjsLib: any;\n\n /** PDF source: URL string, File, ArrayBuffer, or Uint8Array. */\n source?: PDFSource | null;\n\n /** Search query string. Empty/undefined clears the search. */\n searchQuery?: string;\n\n /** Multiple search contexts (alternative to searchQuery). Each context highlighted with different color. */\n searchContexts?: SearchContext[];\n\n /** Search options. */\n searchOptions?: SearchOptions;\n\n /** Viewer options (applied once on mount). */\n viewerOptions?: PDFSearchViewerOptions;\n\n /** Called when PDF finishes loading. */\n onLoad?: (data: { pageCount: number }) => void;\n\n /** Called when search completes. */\n onSearch?: (data: { query: string; total: number }) => void;\n\n /** Called when multi-context search completes. */\n onSearchMultiple?: (data: { contexts: SearchContext[]; total: number; totalsPerContext: number[] }) => void;\n\n /** Called when active match changes. */\n onMatchChange?: (data: { current: number; total: number }) => void;\n\n /** Called when zoom/scale changes. */\n onZoom?: (data: { scale: number }) => void;\n\n /** Called on error. */\n onError?: (data: { error: Error; context: string }) => void;\n\n /** Additional className for the container div. */\n className?: string;\n\n /** Inline style for the container div. */\n style?: CSSProperties;\n}\n\nexport interface PDFSearchViewerHandle {\n /** Navigate to next match. Returns new index. */\n nextMatch: () => number;\n /** Navigate to previous match. Returns new index. */\n prevMatch: () => number;\n /** Clear all search highlights. */\n clearSearch: () => void;\n /** Search multiple contexts. Returns total match count. */\n searchMultiple: (contexts: SearchContext[], options?: SearchOptions) => number;\n /** Get total match count. */\n getMatchCount: () => number;\n /** Get current match index. */\n getCurrentMatchIndex: () => number;\n /** Zoom in by one step. */\n zoomIn: () => Promise<void>;\n /** Zoom out by one step. */\n zoomOut: () => Promise<void>;\n /** Set scale and re-render. */\n setScale: (scale: number | 'auto') => Promise<void>;\n /** Get current scale. */\n getScale: () => number | 'auto';\n /** Download the loaded PDF. */\n download: (filename?: string) => Promise<void>;\n /** Get underlying core instance. */\n getCore: () => CorePDFSearchViewer | null;\n}\n\nexport const PDFSearchViewer = forwardRef(function PDFSearchViewer(\n props: PDFSearchViewerProps,\n ref: Ref<PDFSearchViewerHandle>\n) {\n const {\n pdfjsLib,\n source,\n searchQuery,\n searchContexts,\n searchOptions,\n viewerOptions,\n onLoad,\n onSearch,\n onSearchMultiple,\n onMatchChange,\n onZoom,\n onError,\n className,\n style,\n } = props;\n\n const containerRef = useRef<HTMLDivElement>(null);\n const coreRef = useRef<CorePDFSearchViewer | null>(null);\n\n // Store latest callbacks in refs to avoid re-subscribing\n const callbackRefs = useRef({ onLoad, onSearch, onSearchMultiple, onMatchChange, onZoom, onError });\n callbackRefs.current = { onLoad, onSearch, onSearchMultiple, onMatchChange, onZoom, onError };\n\n // Initialize core on mount\n useEffect(() => {\n if (!containerRef.current || !pdfjsLib) return;\n\n const core = new CorePDFSearchViewer(\n containerRef.current,\n pdfjsLib,\n viewerOptions ?? {}\n );\n\n core.on('load', (data) => callbackRefs.current.onLoad?.(data));\n core.on('search', (data) => callbackRefs.current.onSearch?.(data));\n core.on('searchmultiple', (data) => callbackRefs.current.onSearchMultiple?.(data));\n core.on('matchchange', (data) => callbackRefs.current.onMatchChange?.(data));\n core.on('zoom', (data) => callbackRefs.current.onZoom?.(data));\n core.on('error', (data) => callbackRefs.current.onError?.(data));\n\n coreRef.current = core;\n\n return () => {\n core.destroy();\n coreRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [pdfjsLib]);\n\n // Load PDF when source changes\n useEffect(() => {\n if (!coreRef.current || !source) return;\n coreRef.current.loadPDF(source).catch(() => {\n // Error already emitted via 'error' event\n });\n }, [source]);\n\n // Run search when query, contexts, or options change\n useEffect(() => {\n if (!coreRef.current) return;\n\n if (searchContexts && searchContexts.length > 0) {\n coreRef.current.searchMultiple(searchContexts, searchOptions);\n } else if (searchQuery && searchQuery.trim().length > 0) {\n coreRef.current.search(searchQuery, searchOptions);\n } else {\n coreRef.current.clearSearch();\n }\n }, [searchQuery, searchContexts, searchOptions]);\n\n // Expose imperative methods via ref\n useImperativeHandle(ref, () => ({\n nextMatch: () => coreRef.current?.nextMatch() ?? -1,\n prevMatch: () => coreRef.current?.prevMatch() ?? -1,\n clearSearch: () => coreRef.current?.clearSearch(),\n searchMultiple: (contexts: SearchContext[], opts?: SearchOptions) =>\n coreRef.current?.searchMultiple(contexts, opts) ?? 0,\n getMatchCount: () => coreRef.current?.getMatchCount() ?? 0,\n getCurrentMatchIndex: () => coreRef.current?.getCurrentMatchIndex() ?? -1,\n zoomIn: async () => { await coreRef.current?.zoomIn(); },\n zoomOut: async () => { await coreRef.current?.zoomOut(); },\n setScale: async (s: number | 'auto') => { await coreRef.current?.setScale(s); },\n getScale: () => coreRef.current?.getScale() ?? 'auto',\n download: async (filename?: string) => { await coreRef.current?.download(filename); },\n getCore: () => coreRef.current,\n }));\n\n return <div ref={containerRef} className={className} style={style} />;\n});\n"]}
@@ -1,5 +1,5 @@
1
- import { P as PageData, f as PDFSource, a as PDFSearchViewerOptions, C as ClassNames, S as SearchOptions, d as PDFSearchViewer$1 } from '../PDFSearchViewer-rNp5NirR.cjs';
2
- export { c as SearchMatch } from '../PDFSearchViewer-rNp5NirR.cjs';
1
+ import { P as PageData, g as PDFSource, b as PDFSearchViewerOptions, C as ClassNames, S as SearchOptions, a as SearchContext, e as PDFSearchViewer$1 } from '../PDFSearchViewer-DzKHoKTp.cjs';
2
+ export { d as SearchMatch } from '../PDFSearchViewer-DzKHoKTp.cjs';
3
3
  import * as react from 'react';
4
4
  import { CSSProperties } from 'react';
5
5
 
@@ -42,6 +42,8 @@ declare function usePDFRenderer(pdfjsLib: any, options?: PDFSearchViewerOptions)
42
42
  interface UseSearchControllerReturn {
43
43
  /** Run a search query */
44
44
  search: (query: string, options?: SearchOptions) => number;
45
+ /** Search multiple contexts with different highlight colors */
46
+ searchMultiple: (contexts: SearchContext[], options?: SearchOptions) => number;
45
47
  /** Go to next match */
46
48
  next: () => void;
47
49
  /** Go to previous match */
@@ -64,7 +66,7 @@ interface UseSearchControllerOptions {
64
66
  *
65
67
  * ```tsx
66
68
  * const { containerRef, pages, loadPDF } = usePDFRenderer(pdfjsLib);
67
- * const { search, next, prev, current, total } = useSearchController(pages);
69
+ * const { search, searchMultiple, next, prev, current, total } = useSearchController(pages);
68
70
  *
69
71
  * return (
70
72
  * <>
@@ -86,6 +88,8 @@ interface PDFSearchViewerProps {
86
88
  source?: PDFSource | null;
87
89
  /** Search query string. Empty/undefined clears the search. */
88
90
  searchQuery?: string;
91
+ /** Multiple search contexts (alternative to searchQuery). Each context highlighted with different color. */
92
+ searchContexts?: SearchContext[];
89
93
  /** Search options. */
90
94
  searchOptions?: SearchOptions;
91
95
  /** Viewer options (applied once on mount). */
@@ -99,6 +103,12 @@ interface PDFSearchViewerProps {
99
103
  query: string;
100
104
  total: number;
101
105
  }) => void;
106
+ /** Called when multi-context search completes. */
107
+ onSearchMultiple?: (data: {
108
+ contexts: SearchContext[];
109
+ total: number;
110
+ totalsPerContext: number[];
111
+ }) => void;
102
112
  /** Called when active match changes. */
103
113
  onMatchChange?: (data: {
104
114
  current: number;
@@ -125,6 +135,8 @@ interface PDFSearchViewerHandle {
125
135
  prevMatch: () => number;
126
136
  /** Clear all search highlights. */
127
137
  clearSearch: () => void;
138
+ /** Search multiple contexts. Returns total match count. */
139
+ searchMultiple: (contexts: SearchContext[], options?: SearchOptions) => number;
128
140
  /** Get total match count. */
129
141
  getMatchCount: () => number;
130
142
  /** Get current match index. */
@@ -144,4 +156,4 @@ interface PDFSearchViewerHandle {
144
156
  }
145
157
  declare const PDFSearchViewer: react.ForwardRefExoticComponent<PDFSearchViewerProps & react.RefAttributes<PDFSearchViewerHandle>>;
146
158
 
147
- export { ClassNames, PDFSearchViewer, type PDFSearchViewerHandle, PDFSearchViewerOptions, type PDFSearchViewerProps, PDFSource, PageData, SearchOptions, type UsePDFRendererReturn, type UseSearchControllerOptions, type UseSearchControllerReturn, usePDFRenderer, useSearchController };
159
+ export { ClassNames, PDFSearchViewer, type PDFSearchViewerHandle, PDFSearchViewerOptions, type PDFSearchViewerProps, PDFSource, PageData, SearchContext, SearchOptions, type UsePDFRendererReturn, type UseSearchControllerOptions, type UseSearchControllerReturn, usePDFRenderer, useSearchController };
@@ -1,5 +1,5 @@
1
- import { P as PageData, f as PDFSource, a as PDFSearchViewerOptions, C as ClassNames, S as SearchOptions, d as PDFSearchViewer$1 } from '../PDFSearchViewer-rNp5NirR.js';
2
- export { c as SearchMatch } from '../PDFSearchViewer-rNp5NirR.js';
1
+ import { P as PageData, g as PDFSource, b as PDFSearchViewerOptions, C as ClassNames, S as SearchOptions, a as SearchContext, e as PDFSearchViewer$1 } from '../PDFSearchViewer-DzKHoKTp.js';
2
+ export { d as SearchMatch } from '../PDFSearchViewer-DzKHoKTp.js';
3
3
  import * as react from 'react';
4
4
  import { CSSProperties } from 'react';
5
5
 
@@ -42,6 +42,8 @@ declare function usePDFRenderer(pdfjsLib: any, options?: PDFSearchViewerOptions)
42
42
  interface UseSearchControllerReturn {
43
43
  /** Run a search query */
44
44
  search: (query: string, options?: SearchOptions) => number;
45
+ /** Search multiple contexts with different highlight colors */
46
+ searchMultiple: (contexts: SearchContext[], options?: SearchOptions) => number;
45
47
  /** Go to next match */
46
48
  next: () => void;
47
49
  /** Go to previous match */
@@ -64,7 +66,7 @@ interface UseSearchControllerOptions {
64
66
  *
65
67
  * ```tsx
66
68
  * const { containerRef, pages, loadPDF } = usePDFRenderer(pdfjsLib);
67
- * const { search, next, prev, current, total } = useSearchController(pages);
69
+ * const { search, searchMultiple, next, prev, current, total } = useSearchController(pages);
68
70
  *
69
71
  * return (
70
72
  * <>
@@ -86,6 +88,8 @@ interface PDFSearchViewerProps {
86
88
  source?: PDFSource | null;
87
89
  /** Search query string. Empty/undefined clears the search. */
88
90
  searchQuery?: string;
91
+ /** Multiple search contexts (alternative to searchQuery). Each context highlighted with different color. */
92
+ searchContexts?: SearchContext[];
89
93
  /** Search options. */
90
94
  searchOptions?: SearchOptions;
91
95
  /** Viewer options (applied once on mount). */
@@ -99,6 +103,12 @@ interface PDFSearchViewerProps {
99
103
  query: string;
100
104
  total: number;
101
105
  }) => void;
106
+ /** Called when multi-context search completes. */
107
+ onSearchMultiple?: (data: {
108
+ contexts: SearchContext[];
109
+ total: number;
110
+ totalsPerContext: number[];
111
+ }) => void;
102
112
  /** Called when active match changes. */
103
113
  onMatchChange?: (data: {
104
114
  current: number;
@@ -125,6 +135,8 @@ interface PDFSearchViewerHandle {
125
135
  prevMatch: () => number;
126
136
  /** Clear all search highlights. */
127
137
  clearSearch: () => void;
138
+ /** Search multiple contexts. Returns total match count. */
139
+ searchMultiple: (contexts: SearchContext[], options?: SearchOptions) => number;
128
140
  /** Get total match count. */
129
141
  getMatchCount: () => number;
130
142
  /** Get current match index. */
@@ -144,4 +156,4 @@ interface PDFSearchViewerHandle {
144
156
  }
145
157
  declare const PDFSearchViewer: react.ForwardRefExoticComponent<PDFSearchViewerProps & react.RefAttributes<PDFSearchViewerHandle>>;
146
158
 
147
- export { ClassNames, PDFSearchViewer, type PDFSearchViewerHandle, PDFSearchViewerOptions, type PDFSearchViewerProps, PDFSource, PageData, SearchOptions, type UsePDFRendererReturn, type UseSearchControllerOptions, type UseSearchControllerReturn, usePDFRenderer, useSearchController };
159
+ export { ClassNames, PDFSearchViewer, type PDFSearchViewerHandle, PDFSearchViewerOptions, type PDFSearchViewerProps, PDFSource, PageData, SearchContext, SearchOptions, type UsePDFRendererReturn, type UseSearchControllerOptions, type UseSearchControllerReturn, usePDFRenderer, useSearchController };
@@ -5,7 +5,7 @@ import {
5
5
  PDFSearchViewer,
6
6
  SearchController,
7
7
  ZOOM_STEP
8
- } from "../chunk-AA4UECNB.js";
8
+ } from "../chunk-XFH7JUDJ.js";
9
9
 
10
10
  // src/react/usePDFRenderer.ts
11
11
  import { useRef, useEffect, useCallback, useState } from "react";
@@ -126,6 +126,12 @@ function useSearchController(pages, options = {}) {
126
126
  const search = useCallback2((query, opts) => {
127
127
  return controllerRef.current.search(query, opts);
128
128
  }, []);
129
+ const searchMultiple = useCallback2(
130
+ (contexts, opts) => {
131
+ return controllerRef.current.searchMultiple(contexts, opts);
132
+ },
133
+ []
134
+ );
129
135
  const next = useCallback2(() => {
130
136
  controllerRef.current.next();
131
137
  }, []);
@@ -138,7 +144,7 @@ function useSearchController(pages, options = {}) {
138
144
  const clear = useCallback2(() => {
139
145
  controllerRef.current.clear();
140
146
  }, []);
141
- return { search, next, prev, goTo, clear, current, total };
147
+ return { search, searchMultiple, next, prev, goTo, clear, current, total };
142
148
  }
143
149
 
144
150
  // src/react/PDFSearchViewer.tsx
@@ -154,10 +160,12 @@ var PDFSearchViewer2 = forwardRef(function PDFSearchViewer3(props, ref) {
154
160
  pdfjsLib,
155
161
  source,
156
162
  searchQuery,
163
+ searchContexts,
157
164
  searchOptions,
158
165
  viewerOptions,
159
166
  onLoad,
160
167
  onSearch,
168
+ onSearchMultiple,
161
169
  onMatchChange,
162
170
  onZoom,
163
171
  onError,
@@ -166,8 +174,8 @@ var PDFSearchViewer2 = forwardRef(function PDFSearchViewer3(props, ref) {
166
174
  } = props;
167
175
  const containerRef = useRef3(null);
168
176
  const coreRef = useRef3(null);
169
- const callbackRefs = useRef3({ onLoad, onSearch, onMatchChange, onZoom, onError });
170
- callbackRefs.current = { onLoad, onSearch, onMatchChange, onZoom, onError };
177
+ const callbackRefs = useRef3({ onLoad, onSearch, onSearchMultiple, onMatchChange, onZoom, onError });
178
+ callbackRefs.current = { onLoad, onSearch, onSearchMultiple, onMatchChange, onZoom, onError };
171
179
  useEffect3(() => {
172
180
  if (!containerRef.current || !pdfjsLib) return;
173
181
  const core = new PDFSearchViewer(
@@ -177,6 +185,7 @@ var PDFSearchViewer2 = forwardRef(function PDFSearchViewer3(props, ref) {
177
185
  );
178
186
  core.on("load", (data) => callbackRefs.current.onLoad?.(data));
179
187
  core.on("search", (data) => callbackRefs.current.onSearch?.(data));
188
+ core.on("searchmultiple", (data) => callbackRefs.current.onSearchMultiple?.(data));
180
189
  core.on("matchchange", (data) => callbackRefs.current.onMatchChange?.(data));
181
190
  core.on("zoom", (data) => callbackRefs.current.onZoom?.(data));
182
191
  core.on("error", (data) => callbackRefs.current.onError?.(data));
@@ -193,16 +202,19 @@ var PDFSearchViewer2 = forwardRef(function PDFSearchViewer3(props, ref) {
193
202
  }, [source]);
194
203
  useEffect3(() => {
195
204
  if (!coreRef.current) return;
196
- if (searchQuery && searchQuery.trim().length > 0) {
205
+ if (searchContexts && searchContexts.length > 0) {
206
+ coreRef.current.searchMultiple(searchContexts, searchOptions);
207
+ } else if (searchQuery && searchQuery.trim().length > 0) {
197
208
  coreRef.current.search(searchQuery, searchOptions);
198
209
  } else {
199
210
  coreRef.current.clearSearch();
200
211
  }
201
- }, [searchQuery, searchOptions]);
212
+ }, [searchQuery, searchContexts, searchOptions]);
202
213
  useImperativeHandle(ref, () => ({
203
214
  nextMatch: () => coreRef.current?.nextMatch() ?? -1,
204
215
  prevMatch: () => coreRef.current?.prevMatch() ?? -1,
205
216
  clearSearch: () => coreRef.current?.clearSearch(),
217
+ searchMultiple: (contexts, opts) => coreRef.current?.searchMultiple(contexts, opts) ?? 0,
206
218
  getMatchCount: () => coreRef.current?.getMatchCount() ?? 0,
207
219
  getCurrentMatchIndex: () => coreRef.current?.getCurrentMatchIndex() ?? -1,
208
220
  zoomIn: async () => {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/react/usePDFRenderer.ts","../../src/react/useSearchController.ts","../../src/react/PDFSearchViewer.tsx"],"sourcesContent":["import { useRef, useEffect, useCallback, useState } from 'react';\nimport { PDFRenderer } from '../core/PDFRenderer';\nimport { ZOOM_STEP, MIN_SCALE, MAX_SCALE } from '../core/constants';\nimport type { PDFSearchViewerOptions, PageData, PDFSource } from '../core';\n\nexport interface UsePDFRendererReturn {\n /** Ref to attach to the container div */\n containerRef: React.RefObject<HTMLDivElement | null>;\n /** Rendered page data (available after loading) */\n pages: PageData[];\n /** Number of pages */\n pageCount: number;\n /** Whether PDF is currently loading */\n loading: boolean;\n /** Current scale value */\n scale: number | 'auto';\n /** Load a PDF source */\n loadPDF: (source: PDFSource) => Promise<PageData[]>;\n /** Set scale and re-render */\n setScale: (scale: number | 'auto') => Promise<PageData[]>;\n /** Zoom in by one step */\n zoomIn: () => Promise<PageData[]>;\n /** Zoom out by one step */\n zoomOut: () => Promise<PageData[]>;\n /** Download the loaded PDF */\n download: (filename?: string) => Promise<void>;\n /** Clean up renderer */\n cleanup: () => void;\n}\n\n/**\n * Hook for rendering PDF into a container div.\n * Returns pages data that can be passed to useSearchController.\n *\n * ```tsx\n * const { containerRef, pages, loadPDF, zoomIn, zoomOut, download } = usePDFRenderer(pdfjsLib);\n *\n * return <div ref={containerRef} style={{ height: '80vh', overflow: 'auto' }} />;\n * ```\n */\nexport function usePDFRenderer(\n pdfjsLib: any,\n options: PDFSearchViewerOptions = {}\n): UsePDFRendererReturn {\n const containerRef = useRef<HTMLDivElement | null>(null);\n const rendererRef = useRef<PDFRenderer | null>(null);\n const [pages, setPages] = useState<PageData[]>([]);\n const [pageCount, setPageCount] = useState(0);\n const [loading, setLoading] = useState(false);\n const [scale, setScaleState] = useState<number | 'auto'>(options.scale ?? 'auto');\n\n // Init renderer when container is available\n useEffect(() => {\n return () => {\n rendererRef.current?.cleanup();\n rendererRef.current = null;\n };\n }, []);\n\n // Store options in a ref so getRenderer/loadPDF don't depend on object identity\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const getRenderer = useCallback(() => {\n if (!containerRef.current) throw new Error('Container ref not attached');\n if (!rendererRef.current) {\n const r = new PDFRenderer(containerRef.current, optionsRef.current);\n r.setPdfjsLib(pdfjsLib);\n rendererRef.current = r;\n }\n return rendererRef.current;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [pdfjsLib]);\n\n const loadPDF = useCallback(\n async (source: PDFSource): Promise<PageData[]> => {\n const renderer = getRenderer();\n setLoading(true);\n try {\n const count = await renderer.loadDocument(source);\n const p = await renderer.renderAllPages();\n setPages(p);\n setPageCount(count);\n setScaleState(renderer.getScale());\n return p;\n } finally {\n setLoading(false);\n }\n },\n [getRenderer]\n );\n\n const setScale = useCallback(\n async (newScale: number | 'auto'): Promise<PageData[]> => {\n const renderer = getRenderer();\n renderer.setScale(newScale);\n const p = await renderer.renderAllPages();\n setPages(p);\n setScaleState(newScale);\n return p;\n },\n [getRenderer]\n );\n\n const zoomIn = useCallback(async (): Promise<PageData[]> => {\n const renderer = getRenderer();\n const current = renderer.getScale() === 'auto'\n ? renderer.getEffectiveScale()\n : (renderer.getScale() as number);\n const newScale = Math.min(current + ZOOM_STEP, MAX_SCALE);\n return setScale(newScale);\n }, [getRenderer, setScale]);\n\n const zoomOut = useCallback(async (): Promise<PageData[]> => {\n const renderer = getRenderer();\n const current = renderer.getScale() === 'auto'\n ? renderer.getEffectiveScale()\n : (renderer.getScale() as number);\n const newScale = Math.max(current - ZOOM_STEP, MIN_SCALE);\n return setScale(newScale);\n }, [getRenderer, setScale]);\n\n const download = useCallback(\n async (filename?: string) => {\n const renderer = getRenderer();\n await renderer.download(filename);\n },\n [getRenderer]\n );\n\n const cleanup = useCallback(() => {\n rendererRef.current?.cleanup();\n rendererRef.current = null;\n setPages([]);\n setPageCount(0);\n }, []);\n\n return {\n containerRef, pages, pageCount, loading, scale,\n loadPDF, setScale, zoomIn, zoomOut, download, cleanup,\n };\n}\n","import { useRef, useEffect, useCallback, useState } from 'react';\nimport { SearchController } from '../core/SearchController';\nimport type { SearchOptions, ClassNames, PageData } from '../core';\n\nexport interface UseSearchControllerReturn {\n /** Run a search query */\n search: (query: string, options?: SearchOptions) => number;\n /** Go to next match */\n next: () => void;\n /** Go to previous match */\n prev: () => void;\n /** Go to specific match index */\n goTo: (index: number) => void;\n /** Clear all highlights */\n clear: () => void;\n /** Current active match index (0-based), -1 if none */\n current: number;\n /** Total number of matches */\n total: number;\n}\n\nexport interface UseSearchControllerOptions {\n classNames?: Pick<ClassNames, 'highlight' | 'activeHighlight'>;\n}\n\n/**\n * Hook for search + highlight logic (headless).\n * Pass pages from usePDFRenderer to connect them.\n *\n * ```tsx\n * const { containerRef, pages, loadPDF } = usePDFRenderer(pdfjsLib);\n * const { search, next, prev, current, total } = useSearchController(pages);\n *\n * return (\n * <>\n * <input onChange={e => search(e.target.value)} />\n * <span>{current + 1}/{total}</span>\n * <button onClick={prev}>Prev</button>\n * <button onClick={next}>Next</button>\n * <div ref={containerRef} />\n * </>\n * );\n * ```\n */\nexport function useSearchController(\n pages: PageData[],\n options: UseSearchControllerOptions = {}\n): UseSearchControllerReturn {\n const controllerRef = useRef<SearchController | null>(null);\n const [current, setCurrent] = useState(-1);\n const [total, setTotal] = useState(0);\n\n // Create controller once\n if (!controllerRef.current) {\n controllerRef.current = new SearchController(options);\n }\n\n // Sync onChange callback\n useEffect(() => {\n const ctrl = controllerRef.current!;\n ctrl.onChange = ({ current: c, total: t }) => {\n setCurrent(c);\n setTotal(t);\n };\n return () => {\n ctrl.onChange = null;\n };\n }, []);\n\n // Update pages when they change\n useEffect(() => {\n controllerRef.current!.setPages(pages);\n }, [pages]);\n\n const search = useCallback((query: string, opts?: SearchOptions) => {\n return controllerRef.current!.search(query, opts);\n }, []);\n\n const next = useCallback(() => {\n controllerRef.current!.next();\n }, []);\n\n const prev = useCallback(() => {\n controllerRef.current!.prev();\n }, []);\n\n const goTo = useCallback((index: number) => {\n controllerRef.current!.goTo(index);\n }, []);\n\n const clear = useCallback(() => {\n controllerRef.current!.clear();\n }, []);\n\n return { search, next, prev, goTo, clear, current, total };\n}\n","import {\n useRef,\n useEffect,\n useImperativeHandle,\n forwardRef,\n type Ref,\n type CSSProperties,\n} from 'react';\nimport {\n PDFSearchViewer as CorePDFSearchViewer,\n type PDFSearchViewerOptions,\n type SearchOptions,\n type PDFSource,\n} from '../core';\n\nexport interface PDFSearchViewerProps {\n /** pdfjs-dist library instance. Must be passed by consumer. */\n pdfjsLib: any;\n\n /** PDF source: URL string, File, ArrayBuffer, or Uint8Array. */\n source?: PDFSource | null;\n\n /** Search query string. Empty/undefined clears the search. */\n searchQuery?: string;\n\n /** Search options. */\n searchOptions?: SearchOptions;\n\n /** Viewer options (applied once on mount). */\n viewerOptions?: PDFSearchViewerOptions;\n\n /** Called when PDF finishes loading. */\n onLoad?: (data: { pageCount: number }) => void;\n\n /** Called when search completes. */\n onSearch?: (data: { query: string; total: number }) => void;\n\n /** Called when active match changes. */\n onMatchChange?: (data: { current: number; total: number }) => void;\n\n /** Called when zoom/scale changes. */\n onZoom?: (data: { scale: number }) => void;\n\n /** Called on error. */\n onError?: (data: { error: Error; context: string }) => void;\n\n /** Additional className for the container div. */\n className?: string;\n\n /** Inline style for the container div. */\n style?: CSSProperties;\n}\n\nexport interface PDFSearchViewerHandle {\n /** Navigate to next match. Returns new index. */\n nextMatch: () => number;\n /** Navigate to previous match. Returns new index. */\n prevMatch: () => number;\n /** Clear all search highlights. */\n clearSearch: () => void;\n /** Get total match count. */\n getMatchCount: () => number;\n /** Get current match index. */\n getCurrentMatchIndex: () => number;\n /** Zoom in by one step. */\n zoomIn: () => Promise<void>;\n /** Zoom out by one step. */\n zoomOut: () => Promise<void>;\n /** Set scale and re-render. */\n setScale: (scale: number | 'auto') => Promise<void>;\n /** Get current scale. */\n getScale: () => number | 'auto';\n /** Download the loaded PDF. */\n download: (filename?: string) => Promise<void>;\n /** Get underlying core instance. */\n getCore: () => CorePDFSearchViewer | null;\n}\n\nexport const PDFSearchViewer = forwardRef(function PDFSearchViewer(\n props: PDFSearchViewerProps,\n ref: Ref<PDFSearchViewerHandle>\n) {\n const {\n pdfjsLib,\n source,\n searchQuery,\n searchOptions,\n viewerOptions,\n onLoad,\n onSearch,\n onMatchChange,\n onZoom,\n onError,\n className,\n style,\n } = props;\n\n const containerRef = useRef<HTMLDivElement>(null);\n const coreRef = useRef<CorePDFSearchViewer | null>(null);\n\n // Store latest callbacks in refs to avoid re-subscribing\n const callbackRefs = useRef({ onLoad, onSearch, onMatchChange, onZoom, onError });\n callbackRefs.current = { onLoad, onSearch, onMatchChange, onZoom, onError };\n\n // Initialize core on mount\n useEffect(() => {\n if (!containerRef.current || !pdfjsLib) return;\n\n const core = new CorePDFSearchViewer(\n containerRef.current,\n pdfjsLib,\n viewerOptions ?? {}\n );\n\n core.on('load', (data) => callbackRefs.current.onLoad?.(data));\n core.on('search', (data) => callbackRefs.current.onSearch?.(data));\n core.on('matchchange', (data) => callbackRefs.current.onMatchChange?.(data));\n core.on('zoom', (data) => callbackRefs.current.onZoom?.(data));\n core.on('error', (data) => callbackRefs.current.onError?.(data));\n\n coreRef.current = core;\n\n return () => {\n core.destroy();\n coreRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [pdfjsLib]);\n\n // Load PDF when source changes\n useEffect(() => {\n if (!coreRef.current || !source) return;\n coreRef.current.loadPDF(source).catch(() => {\n // Error already emitted via 'error' event\n });\n }, [source]);\n\n // Run search when query or options change\n useEffect(() => {\n if (!coreRef.current) return;\n\n if (searchQuery && searchQuery.trim().length > 0) {\n coreRef.current.search(searchQuery, searchOptions);\n } else {\n coreRef.current.clearSearch();\n }\n }, [searchQuery, searchOptions]);\n\n // Expose imperative methods via ref\n useImperativeHandle(ref, () => ({\n nextMatch: () => coreRef.current?.nextMatch() ?? -1,\n prevMatch: () => coreRef.current?.prevMatch() ?? -1,\n clearSearch: () => coreRef.current?.clearSearch(),\n getMatchCount: () => coreRef.current?.getMatchCount() ?? 0,\n getCurrentMatchIndex: () => coreRef.current?.getCurrentMatchIndex() ?? -1,\n zoomIn: async () => { await coreRef.current?.zoomIn(); },\n zoomOut: async () => { await coreRef.current?.zoomOut(); },\n setScale: async (s: number | 'auto') => { await coreRef.current?.setScale(s); },\n getScale: () => coreRef.current?.getScale() ?? 'auto',\n download: async (filename?: string) => { await coreRef.current?.download(filename); },\n getCore: () => coreRef.current,\n }));\n\n return <div ref={containerRef} className={className} style={style} />;\n});\n"],"mappings":"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","names":["useRef","useEffect","useCallback","useState","useRef","useState","useEffect","useCallback","useRef","useEffect","PDFSearchViewer","useRef","useEffect"]}
1
+ {"version":3,"sources":["../../src/react/usePDFRenderer.ts","../../src/react/useSearchController.ts","../../src/react/PDFSearchViewer.tsx"],"sourcesContent":["import { useRef, useEffect, useCallback, useState } from 'react';\nimport { PDFRenderer } from '../core/PDFRenderer';\nimport { ZOOM_STEP, MIN_SCALE, MAX_SCALE } from '../core/constants';\nimport type { PDFSearchViewerOptions, PageData, PDFSource } from '../core';\n\nexport interface UsePDFRendererReturn {\n /** Ref to attach to the container div */\n containerRef: React.RefObject<HTMLDivElement | null>;\n /** Rendered page data (available after loading) */\n pages: PageData[];\n /** Number of pages */\n pageCount: number;\n /** Whether PDF is currently loading */\n loading: boolean;\n /** Current scale value */\n scale: number | 'auto';\n /** Load a PDF source */\n loadPDF: (source: PDFSource) => Promise<PageData[]>;\n /** Set scale and re-render */\n setScale: (scale: number | 'auto') => Promise<PageData[]>;\n /** Zoom in by one step */\n zoomIn: () => Promise<PageData[]>;\n /** Zoom out by one step */\n zoomOut: () => Promise<PageData[]>;\n /** Download the loaded PDF */\n download: (filename?: string) => Promise<void>;\n /** Clean up renderer */\n cleanup: () => void;\n}\n\n/**\n * Hook for rendering PDF into a container div.\n * Returns pages data that can be passed to useSearchController.\n *\n * ```tsx\n * const { containerRef, pages, loadPDF, zoomIn, zoomOut, download } = usePDFRenderer(pdfjsLib);\n *\n * return <div ref={containerRef} style={{ height: '80vh', overflow: 'auto' }} />;\n * ```\n */\nexport function usePDFRenderer(\n pdfjsLib: any,\n options: PDFSearchViewerOptions = {}\n): UsePDFRendererReturn {\n const containerRef = useRef<HTMLDivElement | null>(null);\n const rendererRef = useRef<PDFRenderer | null>(null);\n const [pages, setPages] = useState<PageData[]>([]);\n const [pageCount, setPageCount] = useState(0);\n const [loading, setLoading] = useState(false);\n const [scale, setScaleState] = useState<number | 'auto'>(options.scale ?? 'auto');\n\n // Init renderer when container is available\n useEffect(() => {\n return () => {\n rendererRef.current?.cleanup();\n rendererRef.current = null;\n };\n }, []);\n\n // Store options in a ref so getRenderer/loadPDF don't depend on object identity\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const getRenderer = useCallback(() => {\n if (!containerRef.current) throw new Error('Container ref not attached');\n if (!rendererRef.current) {\n const r = new PDFRenderer(containerRef.current, optionsRef.current);\n r.setPdfjsLib(pdfjsLib);\n rendererRef.current = r;\n }\n return rendererRef.current;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [pdfjsLib]);\n\n const loadPDF = useCallback(\n async (source: PDFSource): Promise<PageData[]> => {\n const renderer = getRenderer();\n setLoading(true);\n try {\n const count = await renderer.loadDocument(source);\n const p = await renderer.renderAllPages();\n setPages(p);\n setPageCount(count);\n setScaleState(renderer.getScale());\n return p;\n } finally {\n setLoading(false);\n }\n },\n [getRenderer]\n );\n\n const setScale = useCallback(\n async (newScale: number | 'auto'): Promise<PageData[]> => {\n const renderer = getRenderer();\n renderer.setScale(newScale);\n const p = await renderer.renderAllPages();\n setPages(p);\n setScaleState(newScale);\n return p;\n },\n [getRenderer]\n );\n\n const zoomIn = useCallback(async (): Promise<PageData[]> => {\n const renderer = getRenderer();\n const current = renderer.getScale() === 'auto'\n ? renderer.getEffectiveScale()\n : (renderer.getScale() as number);\n const newScale = Math.min(current + ZOOM_STEP, MAX_SCALE);\n return setScale(newScale);\n }, [getRenderer, setScale]);\n\n const zoomOut = useCallback(async (): Promise<PageData[]> => {\n const renderer = getRenderer();\n const current = renderer.getScale() === 'auto'\n ? renderer.getEffectiveScale()\n : (renderer.getScale() as number);\n const newScale = Math.max(current - ZOOM_STEP, MIN_SCALE);\n return setScale(newScale);\n }, [getRenderer, setScale]);\n\n const download = useCallback(\n async (filename?: string) => {\n const renderer = getRenderer();\n await renderer.download(filename);\n },\n [getRenderer]\n );\n\n const cleanup = useCallback(() => {\n rendererRef.current?.cleanup();\n rendererRef.current = null;\n setPages([]);\n setPageCount(0);\n }, []);\n\n return {\n containerRef, pages, pageCount, loading, scale,\n loadPDF, setScale, zoomIn, zoomOut, download, cleanup,\n };\n}\n","import { useRef, useEffect, useCallback, useState } from 'react';\nimport { SearchController } from '../core/SearchController';\nimport type { SearchOptions, ClassNames, PageData, SearchContext } from '../core';\n\nexport interface UseSearchControllerReturn {\n /** Run a search query */\n search: (query: string, options?: SearchOptions) => number;\n /** Search multiple contexts with different highlight colors */\n searchMultiple: (contexts: SearchContext[], options?: SearchOptions) => number;\n /** Go to next match */\n next: () => void;\n /** Go to previous match */\n prev: () => void;\n /** Go to specific match index */\n goTo: (index: number) => void;\n /** Clear all highlights */\n clear: () => void;\n /** Current active match index (0-based), -1 if none */\n current: number;\n /** Total number of matches */\n total: number;\n}\n\nexport interface UseSearchControllerOptions {\n classNames?: Pick<ClassNames, 'highlight' | 'activeHighlight'>;\n}\n\n/**\n * Hook for search + highlight logic (headless).\n * Pass pages from usePDFRenderer to connect them.\n *\n * ```tsx\n * const { containerRef, pages, loadPDF } = usePDFRenderer(pdfjsLib);\n * const { search, searchMultiple, next, prev, current, total } = useSearchController(pages);\n *\n * return (\n * <>\n * <input onChange={e => search(e.target.value)} />\n * <span>{current + 1}/{total}</span>\n * <button onClick={prev}>Prev</button>\n * <button onClick={next}>Next</button>\n * <div ref={containerRef} />\n * </>\n * );\n * ```\n */\nexport function useSearchController(\n pages: PageData[],\n options: UseSearchControllerOptions = {}\n): UseSearchControllerReturn {\n const controllerRef = useRef<SearchController | null>(null);\n const [current, setCurrent] = useState(-1);\n const [total, setTotal] = useState(0);\n\n // Create controller once\n if (!controllerRef.current) {\n controllerRef.current = new SearchController(options);\n }\n\n // Sync onChange callback\n useEffect(() => {\n const ctrl = controllerRef.current!;\n ctrl.onChange = ({ current: c, total: t }) => {\n setCurrent(c);\n setTotal(t);\n };\n return () => {\n ctrl.onChange = null;\n };\n }, []);\n\n // Update pages when they change\n useEffect(() => {\n controllerRef.current!.setPages(pages);\n }, [pages]);\n\n const search = useCallback((query: string, opts?: SearchOptions) => {\n return controllerRef.current!.search(query, opts);\n }, []);\n\n const searchMultiple = useCallback(\n (contexts: SearchContext[], opts?: SearchOptions) => {\n return controllerRef.current!.searchMultiple(contexts, opts);\n },\n []\n );\n\n const next = useCallback(() => {\n controllerRef.current!.next();\n }, []);\n\n const prev = useCallback(() => {\n controllerRef.current!.prev();\n }, []);\n\n const goTo = useCallback((index: number) => {\n controllerRef.current!.goTo(index);\n }, []);\n\n const clear = useCallback(() => {\n controllerRef.current!.clear();\n }, []);\n\n return { search, searchMultiple, next, prev, goTo, clear, current, total };\n}\n","import {\n useRef,\n useEffect,\n useImperativeHandle,\n forwardRef,\n type Ref,\n type CSSProperties,\n} from 'react';\nimport {\n PDFSearchViewer as CorePDFSearchViewer,\n type PDFSearchViewerOptions,\n type SearchOptions,\n type SearchContext,\n type PDFSource,\n} from '../core';\n\nexport interface PDFSearchViewerProps {\n /** pdfjs-dist library instance. Must be passed by consumer. */\n pdfjsLib: any;\n\n /** PDF source: URL string, File, ArrayBuffer, or Uint8Array. */\n source?: PDFSource | null;\n\n /** Search query string. Empty/undefined clears the search. */\n searchQuery?: string;\n\n /** Multiple search contexts (alternative to searchQuery). Each context highlighted with different color. */\n searchContexts?: SearchContext[];\n\n /** Search options. */\n searchOptions?: SearchOptions;\n\n /** Viewer options (applied once on mount). */\n viewerOptions?: PDFSearchViewerOptions;\n\n /** Called when PDF finishes loading. */\n onLoad?: (data: { pageCount: number }) => void;\n\n /** Called when search completes. */\n onSearch?: (data: { query: string; total: number }) => void;\n\n /** Called when multi-context search completes. */\n onSearchMultiple?: (data: { contexts: SearchContext[]; total: number; totalsPerContext: number[] }) => void;\n\n /** Called when active match changes. */\n onMatchChange?: (data: { current: number; total: number }) => void;\n\n /** Called when zoom/scale changes. */\n onZoom?: (data: { scale: number }) => void;\n\n /** Called on error. */\n onError?: (data: { error: Error; context: string }) => void;\n\n /** Additional className for the container div. */\n className?: string;\n\n /** Inline style for the container div. */\n style?: CSSProperties;\n}\n\nexport interface PDFSearchViewerHandle {\n /** Navigate to next match. Returns new index. */\n nextMatch: () => number;\n /** Navigate to previous match. Returns new index. */\n prevMatch: () => number;\n /** Clear all search highlights. */\n clearSearch: () => void;\n /** Search multiple contexts. Returns total match count. */\n searchMultiple: (contexts: SearchContext[], options?: SearchOptions) => number;\n /** Get total match count. */\n getMatchCount: () => number;\n /** Get current match index. */\n getCurrentMatchIndex: () => number;\n /** Zoom in by one step. */\n zoomIn: () => Promise<void>;\n /** Zoom out by one step. */\n zoomOut: () => Promise<void>;\n /** Set scale and re-render. */\n setScale: (scale: number | 'auto') => Promise<void>;\n /** Get current scale. */\n getScale: () => number | 'auto';\n /** Download the loaded PDF. */\n download: (filename?: string) => Promise<void>;\n /** Get underlying core instance. */\n getCore: () => CorePDFSearchViewer | null;\n}\n\nexport const PDFSearchViewer = forwardRef(function PDFSearchViewer(\n props: PDFSearchViewerProps,\n ref: Ref<PDFSearchViewerHandle>\n) {\n const {\n pdfjsLib,\n source,\n searchQuery,\n searchContexts,\n searchOptions,\n viewerOptions,\n onLoad,\n onSearch,\n onSearchMultiple,\n onMatchChange,\n onZoom,\n onError,\n className,\n style,\n } = props;\n\n const containerRef = useRef<HTMLDivElement>(null);\n const coreRef = useRef<CorePDFSearchViewer | null>(null);\n\n // Store latest callbacks in refs to avoid re-subscribing\n const callbackRefs = useRef({ onLoad, onSearch, onSearchMultiple, onMatchChange, onZoom, onError });\n callbackRefs.current = { onLoad, onSearch, onSearchMultiple, onMatchChange, onZoom, onError };\n\n // Initialize core on mount\n useEffect(() => {\n if (!containerRef.current || !pdfjsLib) return;\n\n const core = new CorePDFSearchViewer(\n containerRef.current,\n pdfjsLib,\n viewerOptions ?? {}\n );\n\n core.on('load', (data) => callbackRefs.current.onLoad?.(data));\n core.on('search', (data) => callbackRefs.current.onSearch?.(data));\n core.on('searchmultiple', (data) => callbackRefs.current.onSearchMultiple?.(data));\n core.on('matchchange', (data) => callbackRefs.current.onMatchChange?.(data));\n core.on('zoom', (data) => callbackRefs.current.onZoom?.(data));\n core.on('error', (data) => callbackRefs.current.onError?.(data));\n\n coreRef.current = core;\n\n return () => {\n core.destroy();\n coreRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [pdfjsLib]);\n\n // Load PDF when source changes\n useEffect(() => {\n if (!coreRef.current || !source) return;\n coreRef.current.loadPDF(source).catch(() => {\n // Error already emitted via 'error' event\n });\n }, [source]);\n\n // Run search when query, contexts, or options change\n useEffect(() => {\n if (!coreRef.current) return;\n\n if (searchContexts && searchContexts.length > 0) {\n coreRef.current.searchMultiple(searchContexts, searchOptions);\n } else if (searchQuery && searchQuery.trim().length > 0) {\n coreRef.current.search(searchQuery, searchOptions);\n } else {\n coreRef.current.clearSearch();\n }\n }, [searchQuery, searchContexts, searchOptions]);\n\n // Expose imperative methods via ref\n useImperativeHandle(ref, () => ({\n nextMatch: () => coreRef.current?.nextMatch() ?? -1,\n prevMatch: () => coreRef.current?.prevMatch() ?? -1,\n clearSearch: () => coreRef.current?.clearSearch(),\n searchMultiple: (contexts: SearchContext[], opts?: SearchOptions) =>\n coreRef.current?.searchMultiple(contexts, opts) ?? 0,\n getMatchCount: () => coreRef.current?.getMatchCount() ?? 0,\n getCurrentMatchIndex: () => coreRef.current?.getCurrentMatchIndex() ?? -1,\n zoomIn: async () => { await coreRef.current?.zoomIn(); },\n zoomOut: async () => { await coreRef.current?.zoomOut(); },\n setScale: async (s: number | 'auto') => { await coreRef.current?.setScale(s); },\n getScale: () => coreRef.current?.getScale() ?? 'auto',\n download: async (filename?: string) => { await coreRef.current?.download(filename); },\n getCore: () => coreRef.current,\n }));\n\n return <div ref={containerRef} className={className} style={style} />;\n});\n"],"mappings":"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","names":["useRef","useEffect","useCallback","useState","useRef","useState","useEffect","useCallback","useRef","useEffect","PDFSearchViewer","useRef","useEffect"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pdf-search-highlight",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "description": "Drop-in PDF viewer with text search and highlight. Vanilla JS core + React wrapper.",
5
5
  "type": "module",
6
6
  "main": "./dist/core/index.cjs",