kviewer 0.0.1

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.
Files changed (197) hide show
  1. package/README.md +134 -0
  2. package/dist/module.d.mts +15 -0
  3. package/dist/module.json +9 -0
  4. package/dist/module.mjs +26 -0
  5. package/dist/runtime/annotation/engine/config.d.ts +52 -0
  6. package/dist/runtime/annotation/engine/config.js +283 -0
  7. package/dist/runtime/annotation/engine/const.d.ts +6 -0
  8. package/dist/runtime/annotation/engine/const.js +7 -0
  9. package/dist/runtime/annotation/engine/cursor-preview.d.ts +2 -0
  10. package/dist/runtime/annotation/engine/cursor-preview.js +88 -0
  11. package/dist/runtime/annotation/engine/editor/editor.d.ts +69 -0
  12. package/dist/runtime/annotation/engine/editor/editor.js +233 -0
  13. package/dist/runtime/annotation/engine/editor/selector.d.ts +74 -0
  14. package/dist/runtime/annotation/engine/editor/selector.js +594 -0
  15. package/dist/runtime/annotation/engine/import-normalize.d.ts +5 -0
  16. package/dist/runtime/annotation/engine/import-normalize.js +99 -0
  17. package/dist/runtime/annotation/engine/input-device.d.ts +53 -0
  18. package/dist/runtime/annotation/engine/input-device.js +64 -0
  19. package/dist/runtime/annotation/engine/painter.d.ts +97 -0
  20. package/dist/runtime/annotation/engine/painter.js +591 -0
  21. package/dist/runtime/annotation/engine/store.d.ts +11 -0
  22. package/dist/runtime/annotation/engine/store.js +47 -0
  23. package/dist/runtime/annotation/engine/tools/arrow.d.ts +22 -0
  24. package/dist/runtime/annotation/engine/tools/arrow.js +126 -0
  25. package/dist/runtime/annotation/engine/tools/circle.d.ts +45 -0
  26. package/dist/runtime/annotation/engine/tools/circle.js +148 -0
  27. package/dist/runtime/annotation/engine/tools/cloud.d.ts +50 -0
  28. package/dist/runtime/annotation/engine/tools/cloud.js +244 -0
  29. package/dist/runtime/annotation/engine/tools/free-highlight.d.ts +43 -0
  30. package/dist/runtime/annotation/engine/tools/free-highlight.js +165 -0
  31. package/dist/runtime/annotation/engine/tools/free-text.d.ts +27 -0
  32. package/dist/runtime/annotation/engine/tools/free-text.js +114 -0
  33. package/dist/runtime/annotation/engine/tools/freehand.d.ts +44 -0
  34. package/dist/runtime/annotation/engine/tools/freehand.js +151 -0
  35. package/dist/runtime/annotation/engine/tools/highlight.d.ts +87 -0
  36. package/dist/runtime/annotation/engine/tools/highlight.js +215 -0
  37. package/dist/runtime/annotation/engine/tools/note.d.ts +9 -0
  38. package/dist/runtime/annotation/engine/tools/note.js +34 -0
  39. package/dist/runtime/annotation/engine/tools/rectangle.d.ts +45 -0
  40. package/dist/runtime/annotation/engine/tools/rectangle.js +142 -0
  41. package/dist/runtime/annotation/engine/tools/signature.d.ts +16 -0
  42. package/dist/runtime/annotation/engine/tools/signature.js +74 -0
  43. package/dist/runtime/annotation/engine/tools/stamp.d.ts +18 -0
  44. package/dist/runtime/annotation/engine/tools/stamp.js +94 -0
  45. package/dist/runtime/annotation/engine/types.d.ts +170 -0
  46. package/dist/runtime/annotation/engine/types.js +67 -0
  47. package/dist/runtime/annotation/engine/utils.d.ts +40 -0
  48. package/dist/runtime/annotation/engine/utils.js +257 -0
  49. package/dist/runtime/annotation/parsers/parseFormFields.d.ts +9 -0
  50. package/dist/runtime/annotation/parsers/parseFormFields.js +101 -0
  51. package/dist/runtime/annotation/pdf-export/download.d.ts +1 -0
  52. package/dist/runtime/annotation/pdf-export/download.js +10 -0
  53. package/dist/runtime/annotation/pdf-export/export-form-fields.d.ts +9 -0
  54. package/dist/runtime/annotation/pdf-export/export-form-fields.js +90 -0
  55. package/dist/runtime/annotation/pdf-export/export.d.ts +15 -0
  56. package/dist/runtime/annotation/pdf-export/export.js +145 -0
  57. package/dist/runtime/annotation/pdf-export/parse.d.ts +10 -0
  58. package/dist/runtime/annotation/pdf-export/parse.js +19 -0
  59. package/dist/runtime/annotation/pdf-export/parse_circle.d.ts +4 -0
  60. package/dist/runtime/annotation/pdf-export/parse_circle.js +41 -0
  61. package/dist/runtime/annotation/pdf-export/parse_freetext.d.ts +4 -0
  62. package/dist/runtime/annotation/pdf-export/parse_freetext.js +54 -0
  63. package/dist/runtime/annotation/pdf-export/parse_highlight.d.ts +4 -0
  64. package/dist/runtime/annotation/pdf-export/parse_highlight.js +134 -0
  65. package/dist/runtime/annotation/pdf-export/parse_ink.d.ts +4 -0
  66. package/dist/runtime/annotation/pdf-export/parse_ink.js +124 -0
  67. package/dist/runtime/annotation/pdf-export/parse_line.d.ts +4 -0
  68. package/dist/runtime/annotation/pdf-export/parse_line.js +71 -0
  69. package/dist/runtime/annotation/pdf-export/parse_polyline.d.ts +4 -0
  70. package/dist/runtime/annotation/pdf-export/parse_polyline.js +93 -0
  71. package/dist/runtime/annotation/pdf-export/parse_square.d.ts +4 -0
  72. package/dist/runtime/annotation/pdf-export/parse_square.js +41 -0
  73. package/dist/runtime/annotation/pdf-export/parse_stamp.d.ts +4 -0
  74. package/dist/runtime/annotation/pdf-export/parse_stamp.js +195 -0
  75. package/dist/runtime/annotation/pdf-export/parse_strikeout.d.ts +4 -0
  76. package/dist/runtime/annotation/pdf-export/parse_strikeout.js +59 -0
  77. package/dist/runtime/annotation/pdf-export/parse_text.d.ts +4 -0
  78. package/dist/runtime/annotation/pdf-export/parse_text.js +42 -0
  79. package/dist/runtime/annotation/pdf-export/parse_underline.d.ts +4 -0
  80. package/dist/runtime/annotation/pdf-export/parse_underline.js +59 -0
  81. package/dist/runtime/assets/kviewer.css +1 -0
  82. package/dist/runtime/components/AnnotationToolbar.d.vue.ts +3 -0
  83. package/dist/runtime/components/AnnotationToolbar.vue +125 -0
  84. package/dist/runtime/components/AnnotationToolbar.vue.d.ts +3 -0
  85. package/dist/runtime/components/FloatingPageIndicator.d.vue.ts +6 -0
  86. package/dist/runtime/components/FloatingPageIndicator.vue +93 -0
  87. package/dist/runtime/components/FloatingPageIndicator.vue.d.ts +6 -0
  88. package/dist/runtime/components/FormFieldLayer.d.vue.ts +11 -0
  89. package/dist/runtime/components/FormFieldLayer.vue +40 -0
  90. package/dist/runtime/components/FormFieldLayer.vue.d.ts +11 -0
  91. package/dist/runtime/components/PdfPage.d.vue.ts +9 -0
  92. package/dist/runtime/components/PdfPage.vue +199 -0
  93. package/dist/runtime/components/PdfPage.vue.d.ts +9 -0
  94. package/dist/runtime/components/ToolButton.d.vue.ts +13 -0
  95. package/dist/runtime/components/ToolButton.vue +26 -0
  96. package/dist/runtime/components/ToolButton.vue.d.ts +13 -0
  97. package/dist/runtime/components/Toolbar.d.vue.ts +3 -0
  98. package/dist/runtime/components/Toolbar.vue +11 -0
  99. package/dist/runtime/components/Toolbar.vue.d.ts +3 -0
  100. package/dist/runtime/components/Viewer.d.vue.ts +45 -0
  101. package/dist/runtime/components/Viewer.vue +617 -0
  102. package/dist/runtime/components/Viewer.vue.d.ts +45 -0
  103. package/dist/runtime/components/ViewerBar.d.vue.ts +3 -0
  104. package/dist/runtime/components/ViewerBar.vue +91 -0
  105. package/dist/runtime/components/ViewerBar.vue.d.ts +3 -0
  106. package/dist/runtime/components/ViewerTabs.d.vue.ts +381 -0
  107. package/dist/runtime/components/ViewerTabs.vue +171 -0
  108. package/dist/runtime/components/ViewerTabs.vue.d.ts +381 -0
  109. package/dist/runtime/components/form-fields/FormButton.d.vue.ts +7 -0
  110. package/dist/runtime/components/form-fields/FormButton.vue +39 -0
  111. package/dist/runtime/components/form-fields/FormButton.vue.d.ts +7 -0
  112. package/dist/runtime/components/form-fields/FormCheckbox.d.vue.ts +7 -0
  113. package/dist/runtime/components/form-fields/FormCheckbox.vue +28 -0
  114. package/dist/runtime/components/form-fields/FormCheckbox.vue.d.ts +7 -0
  115. package/dist/runtime/components/form-fields/FormDropdown.d.vue.ts +7 -0
  116. package/dist/runtime/components/form-fields/FormDropdown.vue +112 -0
  117. package/dist/runtime/components/form-fields/FormDropdown.vue.d.ts +7 -0
  118. package/dist/runtime/components/form-fields/FormFieldWrapper.d.vue.ts +8 -0
  119. package/dist/runtime/components/form-fields/FormFieldWrapper.vue +41 -0
  120. package/dist/runtime/components/form-fields/FormFieldWrapper.vue.d.ts +8 -0
  121. package/dist/runtime/components/form-fields/FormRadioButton.d.vue.ts +7 -0
  122. package/dist/runtime/components/form-fields/FormRadioButton.vue +30 -0
  123. package/dist/runtime/components/form-fields/FormRadioButton.vue.d.ts +7 -0
  124. package/dist/runtime/components/form-fields/FormSignatureField.d.vue.ts +7 -0
  125. package/dist/runtime/components/form-fields/FormSignatureField.vue +54 -0
  126. package/dist/runtime/components/form-fields/FormSignatureField.vue.d.ts +7 -0
  127. package/dist/runtime/components/form-fields/FormTextField.d.vue.ts +7 -0
  128. package/dist/runtime/components/form-fields/FormTextField.vue +66 -0
  129. package/dist/runtime/components/form-fields/FormTextField.vue.d.ts +7 -0
  130. package/dist/runtime/components/modals/FreeTextModal.d.vue.ts +25 -0
  131. package/dist/runtime/components/modals/FreeTextModal.vue +89 -0
  132. package/dist/runtime/components/modals/FreeTextModal.vue.d.ts +25 -0
  133. package/dist/runtime/components/modals/SignatureDrawModal.d.vue.ts +14 -0
  134. package/dist/runtime/components/modals/SignatureDrawModal.vue +120 -0
  135. package/dist/runtime/components/modals/SignatureDrawModal.vue.d.ts +14 -0
  136. package/dist/runtime/components/panels/SignaturePicker.d.vue.ts +3 -0
  137. package/dist/runtime/components/panels/SignaturePicker.vue +85 -0
  138. package/dist/runtime/components/panels/SignaturePicker.vue.d.ts +3 -0
  139. package/dist/runtime/components/panels/StampPicker.d.vue.ts +3 -0
  140. package/dist/runtime/components/panels/StampPicker.vue +46 -0
  141. package/dist/runtime/components/panels/StampPicker.vue.d.ts +3 -0
  142. package/dist/runtime/components/tools/ActionTools.d.vue.ts +3 -0
  143. package/dist/runtime/components/tools/ActionTools.vue +32 -0
  144. package/dist/runtime/components/tools/ActionTools.vue.d.ts +3 -0
  145. package/dist/runtime/components/tools/DrawingTools.d.vue.ts +6 -0
  146. package/dist/runtime/components/tools/DrawingTools.vue +57 -0
  147. package/dist/runtime/components/tools/DrawingTools.vue.d.ts +6 -0
  148. package/dist/runtime/components/tools/HandTool.d.vue.ts +3 -0
  149. package/dist/runtime/components/tools/HandTool.vue +14 -0
  150. package/dist/runtime/components/tools/HandTool.vue.d.ts +3 -0
  151. package/dist/runtime/components/tools/MarqueeTool.d.vue.ts +3 -0
  152. package/dist/runtime/components/tools/MarqueeTool.vue +15 -0
  153. package/dist/runtime/components/tools/MarqueeTool.vue.d.ts +3 -0
  154. package/dist/runtime/components/tools/PageInfo.d.vue.ts +3 -0
  155. package/dist/runtime/components/tools/PageInfo.vue +10 -0
  156. package/dist/runtime/components/tools/PageInfo.vue.d.ts +3 -0
  157. package/dist/runtime/components/tools/PageSettings.d.vue.ts +3 -0
  158. package/dist/runtime/components/tools/PageSettings.vue +92 -0
  159. package/dist/runtime/components/tools/PageSettings.vue.d.ts +3 -0
  160. package/dist/runtime/components/tools/SearchTool.d.vue.ts +3 -0
  161. package/dist/runtime/components/tools/SearchTool.vue +149 -0
  162. package/dist/runtime/components/tools/SearchTool.vue.d.ts +3 -0
  163. package/dist/runtime/components/tools/ToolProperties.d.vue.ts +7 -0
  164. package/dist/runtime/components/tools/ToolProperties.vue +174 -0
  165. package/dist/runtime/components/tools/ToolProperties.vue.d.ts +7 -0
  166. package/dist/runtime/components/tools/ZoomControls.d.vue.ts +3 -0
  167. package/dist/runtime/components/tools/ZoomControls.vue +59 -0
  168. package/dist/runtime/components/tools/ZoomControls.vue.d.ts +3 -0
  169. package/dist/runtime/composables/search-utils.d.ts +20 -0
  170. package/dist/runtime/composables/search-utils.js +55 -0
  171. package/dist/runtime/composables/useAnnotationEngine.d.ts +7 -0
  172. package/dist/runtime/composables/useAnnotationEngine.js +70 -0
  173. package/dist/runtime/composables/useAnnotationHistory.d.ts +12 -0
  174. package/dist/runtime/composables/useAnnotationHistory.js +69 -0
  175. package/dist/runtime/composables/useFormFields.d.ts +26 -0
  176. package/dist/runtime/composables/useFormFields.js +112 -0
  177. package/dist/runtime/composables/usePageProxyCache.d.ts +8 -0
  178. package/dist/runtime/composables/usePageProxyCache.js +73 -0
  179. package/dist/runtime/composables/usePageSettings.d.ts +16 -0
  180. package/dist/runtime/composables/usePageSettings.js +66 -0
  181. package/dist/runtime/composables/usePageVirtualization.d.ts +19 -0
  182. package/dist/runtime/composables/usePageVirtualization.js +203 -0
  183. package/dist/runtime/composables/useSearchIndex.d.ts +11 -0
  184. package/dist/runtime/composables/useSearchIndex.js +71 -0
  185. package/dist/runtime/composables/useViewerSearch.d.ts +32 -0
  186. package/dist/runtime/composables/useViewerSearch.js +418 -0
  187. package/dist/runtime/composables/useViewerState.d.ts +62 -0
  188. package/dist/runtime/composables/useViewerState.js +189 -0
  189. package/dist/runtime/composables/viewMode.d.ts +11 -0
  190. package/dist/runtime/composables/viewMode.js +19 -0
  191. package/dist/runtime/plugin.d.ts +2 -0
  192. package/dist/runtime/plugin.js +3 -0
  193. package/dist/runtime/public-types.d.ts +2 -0
  194. package/dist/runtime/public-types.js +0 -0
  195. package/dist/runtime/server/tsconfig.json +3 -0
  196. package/dist/types.d.mts +5 -0
  197. package/package.json +64 -0
@@ -0,0 +1,73 @@
1
+ import { provide, inject } from "vue";
2
+ const DEFAULT_MAX_SIZE = 50;
3
+ const PAGE_PROXY_CACHE_KEY = Symbol("kviewer-page-proxy-cache");
4
+ export function createPageProxyCache(maxSize = DEFAULT_MAX_SIZE) {
5
+ let doc = null;
6
+ const cache = /* @__PURE__ */ new Map();
7
+ const accessOrder = [];
8
+ const inflight = /* @__PURE__ */ new Map();
9
+ function touch(pageNumber) {
10
+ const idx = accessOrder.indexOf(pageNumber);
11
+ if (idx !== -1) {
12
+ accessOrder.splice(idx, 1);
13
+ }
14
+ accessOrder.push(pageNumber);
15
+ }
16
+ function evict() {
17
+ while (cache.size > maxSize && accessOrder.length > 0) {
18
+ const oldest = accessOrder.shift();
19
+ const proxy = cache.get(oldest);
20
+ if (proxy) {
21
+ proxy.cleanup();
22
+ cache.delete(oldest);
23
+ }
24
+ }
25
+ }
26
+ function setDocument(newDoc) {
27
+ clear();
28
+ doc = newDoc;
29
+ }
30
+ async function getPage(pageNumber) {
31
+ const cached = cache.get(pageNumber);
32
+ if (cached) {
33
+ touch(pageNumber);
34
+ return cached;
35
+ }
36
+ const pending = inflight.get(pageNumber);
37
+ if (pending) return pending;
38
+ if (!doc) {
39
+ throw new Error("PageProxyCache: no document set");
40
+ }
41
+ const promise = doc.getPage(pageNumber).then((proxy) => {
42
+ inflight.delete(pageNumber);
43
+ cache.set(pageNumber, proxy);
44
+ touch(pageNumber);
45
+ evict();
46
+ return proxy;
47
+ }).catch((err) => {
48
+ inflight.delete(pageNumber);
49
+ throw err;
50
+ });
51
+ inflight.set(pageNumber, promise);
52
+ return promise;
53
+ }
54
+ function clear() {
55
+ for (const proxy of cache.values()) {
56
+ proxy.cleanup();
57
+ }
58
+ cache.clear();
59
+ accessOrder.length = 0;
60
+ inflight.clear();
61
+ doc = null;
62
+ }
63
+ const cacheInstance = { setDocument, getPage, clear };
64
+ provide(PAGE_PROXY_CACHE_KEY, cacheInstance);
65
+ return cacheInstance;
66
+ }
67
+ export function usePageProxyCache() {
68
+ const cache = inject(PAGE_PROXY_CACHE_KEY);
69
+ if (!cache) {
70
+ throw new Error("usePageProxyCache() must be used inside a <KViewer> component");
71
+ }
72
+ return cache;
73
+ }
@@ -0,0 +1,16 @@
1
+ import { type Ref } from 'vue';
2
+ export type PageTransition = 'continuous' | 'single-page';
3
+ export type LayoutMode = 'single' | 'double';
4
+ export interface PageSettings {
5
+ pageTransition: Ref<PageTransition>;
6
+ setPageTransition: (mode: PageTransition) => void;
7
+ rotation: Ref<number>;
8
+ rotateCW: () => void;
9
+ rotateCCW: () => void;
10
+ layoutMode: Ref<LayoutMode>;
11
+ setLayoutMode: (mode: LayoutMode) => void;
12
+ isFullscreen: Ref<boolean>;
13
+ toggleFullscreen: () => void;
14
+ }
15
+ export declare function providePageSettings(viewerRoot: Ref<HTMLElement | null>): PageSettings;
16
+ export declare function usePageSettings(): PageSettings;
@@ -0,0 +1,66 @@
1
+ import {
2
+ ref,
3
+ provide,
4
+ inject,
5
+ onMounted,
6
+ onBeforeUnmount
7
+ } from "vue";
8
+ const PAGE_SETTINGS_KEY = Symbol("kviewer-page-settings");
9
+ export function providePageSettings(viewerRoot) {
10
+ const pageTransition = ref("continuous");
11
+ const rotation = ref(0);
12
+ const layoutMode = ref("single");
13
+ const isFullscreen = ref(false);
14
+ function setPageTransition(mode) {
15
+ pageTransition.value = mode;
16
+ }
17
+ function rotateCW() {
18
+ rotation.value = (rotation.value + 90) % 360;
19
+ }
20
+ function rotateCCW() {
21
+ rotation.value = (rotation.value - 90 + 360) % 360;
22
+ }
23
+ function setLayoutMode(mode) {
24
+ layoutMode.value = mode;
25
+ }
26
+ function toggleFullscreen() {
27
+ const el = viewerRoot.value;
28
+ if (!el) return;
29
+ if (document.fullscreenElement) {
30
+ document.exitFullscreen();
31
+ } else {
32
+ el.requestFullscreen();
33
+ }
34
+ }
35
+ function onFullscreenChange() {
36
+ isFullscreen.value = !!document.fullscreenElement;
37
+ }
38
+ onMounted(() => {
39
+ document.addEventListener("fullscreenchange", onFullscreenChange);
40
+ });
41
+ onBeforeUnmount(() => {
42
+ document.removeEventListener("fullscreenchange", onFullscreenChange);
43
+ });
44
+ const settings = {
45
+ pageTransition,
46
+ setPageTransition,
47
+ rotation,
48
+ rotateCW,
49
+ rotateCCW,
50
+ layoutMode,
51
+ setLayoutMode,
52
+ isFullscreen,
53
+ toggleFullscreen
54
+ };
55
+ provide(PAGE_SETTINGS_KEY, settings);
56
+ return settings;
57
+ }
58
+ export function usePageSettings() {
59
+ const settings = inject(PAGE_SETTINGS_KEY);
60
+ if (!settings) {
61
+ throw new Error(
62
+ "usePageSettings() must be used inside a <KViewer> component"
63
+ );
64
+ }
65
+ return settings;
66
+ }
@@ -0,0 +1,19 @@
1
+ import { type ShallowRef, type ComputedRef, type Ref } from 'vue';
2
+ import type { PDFDocumentProxy } from 'pdfjs-dist';
3
+ export interface PageMeta {
4
+ pageNumber: number;
5
+ width: number;
6
+ height: number;
7
+ }
8
+ export interface PageVirtualization {
9
+ pageMetas: ShallowRef<PageMeta[]>;
10
+ currentPage: Ref<number>;
11
+ renderedPages: ComputedRef<Set<number>>;
12
+ isPageRendered: (pageNumber: number) => boolean;
13
+ observePage: (pageNumber: number, element: HTMLElement) => void;
14
+ unobservePage: (pageNumber: number) => void;
15
+ scrollToPage: (pageNumber: number) => void;
16
+ init: (doc: PDFDocumentProxy, scrollRoot: HTMLElement) => Promise<void>;
17
+ destroy: () => void;
18
+ }
19
+ export declare function createPageVirtualization(): PageVirtualization;
@@ -0,0 +1,203 @@
1
+ import { shallowRef, ref, computed, triggerRef } from "vue";
2
+ const PAGE_BUFFER = 3;
3
+ const DIMENSION_BATCH_SIZE = 20;
4
+ export function createPageVirtualization() {
5
+ const pageMetas = shallowRef([]);
6
+ const currentPage = ref(1);
7
+ const visiblePages = shallowRef(/* @__PURE__ */ new Set());
8
+ let observer = null;
9
+ let scrollRoot = null;
10
+ let scrollListener = null;
11
+ const elementToPage = /* @__PURE__ */ new Map();
12
+ const pageToElement = /* @__PURE__ */ new Map();
13
+ const renderedPages = computed(() => {
14
+ const visible = visiblePages.value;
15
+ if (visible.size === 0) return /* @__PURE__ */ new Set();
16
+ const sorted = [...visible].sort((a, b) => a - b);
17
+ const minPage = sorted[0];
18
+ const maxPage = sorted[sorted.length - 1];
19
+ const totalPages = pageMetas.value.length;
20
+ const bufferMin = Math.max(1, minPage - PAGE_BUFFER);
21
+ const bufferMax = Math.min(totalPages, maxPage + PAGE_BUFFER);
22
+ const result = /* @__PURE__ */ new Set();
23
+ for (let i = bufferMin; i <= bufferMax; i++) {
24
+ result.add(i);
25
+ }
26
+ return result;
27
+ });
28
+ function isPageRendered(pageNumber) {
29
+ return renderedPages.value.has(pageNumber);
30
+ }
31
+ function handleIntersection(entries) {
32
+ let changed = false;
33
+ const current = new Set(visiblePages.value);
34
+ for (const entry of entries) {
35
+ const pageNumber = elementToPage.get(entry.target);
36
+ if (pageNumber === void 0) continue;
37
+ if (entry.isIntersecting) {
38
+ if (!current.has(pageNumber)) {
39
+ current.add(pageNumber);
40
+ changed = true;
41
+ }
42
+ } else {
43
+ if (current.has(pageNumber)) {
44
+ current.delete(pageNumber);
45
+ changed = true;
46
+ }
47
+ }
48
+ }
49
+ if (changed) {
50
+ visiblePages.value = current;
51
+ triggerRef(visiblePages);
52
+ }
53
+ }
54
+ function observePage(pageNumber, element) {
55
+ if (!observer) return;
56
+ const prev = pageToElement.get(pageNumber);
57
+ if (prev && prev !== element) {
58
+ observer.unobserve(prev);
59
+ elementToPage.delete(prev);
60
+ }
61
+ elementToPage.set(element, pageNumber);
62
+ pageToElement.set(pageNumber, element);
63
+ observer.observe(element);
64
+ }
65
+ function unobservePage(pageNumber) {
66
+ const element = pageToElement.get(pageNumber);
67
+ if (element) {
68
+ observer?.unobserve(element);
69
+ elementToPage.delete(element);
70
+ pageToElement.delete(pageNumber);
71
+ }
72
+ }
73
+ function updateCurrentPage() {
74
+ if (!scrollRoot) return;
75
+ const rootTop = scrollRoot.scrollTop;
76
+ const rootMid = rootTop + scrollRoot.clientHeight / 2;
77
+ let bestPage = currentPage.value;
78
+ let bestDist = Infinity;
79
+ for (const [pageNum, el] of pageToElement) {
80
+ const top = el.offsetTop;
81
+ const bottom = top + el.offsetHeight;
82
+ const dist = rootMid < top ? top - rootMid : rootMid > bottom ? rootMid - bottom : 0;
83
+ if (dist < bestDist) {
84
+ bestDist = dist;
85
+ bestPage = pageNum;
86
+ }
87
+ }
88
+ if (bestPage !== currentPage.value) {
89
+ currentPage.value = bestPage;
90
+ }
91
+ }
92
+ function scrollToPage(pageNumber) {
93
+ const element = pageToElement.get(pageNumber);
94
+ if (element && scrollRoot) {
95
+ element.scrollIntoView({ block: "start", behavior: "instant" });
96
+ currentPage.value = pageNumber;
97
+ }
98
+ }
99
+ async function fetchPageDimensions(doc, pageNumber) {
100
+ const proxy = await doc.getPage(pageNumber);
101
+ const view = proxy.view;
102
+ return {
103
+ pageNumber,
104
+ width: view[2] - view[0],
105
+ height: view[3] - view[1]
106
+ };
107
+ }
108
+ async function init(doc, root) {
109
+ destroy();
110
+ scrollRoot = root;
111
+ const totalPages = doc.numPages;
112
+ const firstMeta = await fetchPageDimensions(doc, 1);
113
+ const metas = [];
114
+ for (let i = 1; i <= totalPages; i++) {
115
+ if (i === 1) {
116
+ metas.push(firstMeta);
117
+ } else {
118
+ metas.push({
119
+ pageNumber: i,
120
+ width: firstMeta.width,
121
+ height: firstMeta.height
122
+ });
123
+ }
124
+ }
125
+ pageMetas.value = metas;
126
+ observer = new IntersectionObserver(handleIntersection, {
127
+ root,
128
+ rootMargin: "200% 0px",
129
+ threshold: 0
130
+ });
131
+ scrollListener = () => updateCurrentPage();
132
+ root.addEventListener("scroll", scrollListener, { passive: true });
133
+ if (totalPages > 1) {
134
+ fetchRemainingDimensions(doc, totalPages);
135
+ }
136
+ }
137
+ function fetchRemainingDimensions(doc, totalPages) {
138
+ let currentPage2 = 2;
139
+ function processBatch() {
140
+ if (currentPage2 > totalPages || !observer) return;
141
+ const batchEnd = Math.min(currentPage2 + DIMENSION_BATCH_SIZE - 1, totalPages);
142
+ const promises = [];
143
+ for (let i = currentPage2; i <= batchEnd; i++) {
144
+ promises.push(fetchPageDimensions(doc, i));
145
+ }
146
+ Promise.all(promises).then((results) => {
147
+ if (!observer) return;
148
+ const updated = [...pageMetas.value];
149
+ let changed = false;
150
+ for (const meta of results) {
151
+ const idx = meta.pageNumber - 1;
152
+ const existing = updated[idx];
153
+ if (existing && (existing.width !== meta.width || existing.height !== meta.height)) {
154
+ updated[idx] = meta;
155
+ changed = true;
156
+ }
157
+ }
158
+ if (changed) {
159
+ pageMetas.value = updated;
160
+ }
161
+ currentPage2 = batchEnd + 1;
162
+ if (currentPage2 <= totalPages) {
163
+ if (typeof requestIdleCallback === "function") {
164
+ requestIdleCallback(() => processBatch());
165
+ } else {
166
+ setTimeout(processBatch, 0);
167
+ }
168
+ }
169
+ });
170
+ }
171
+ if (typeof requestIdleCallback === "function") {
172
+ requestIdleCallback(() => processBatch());
173
+ } else {
174
+ setTimeout(processBatch, 0);
175
+ }
176
+ }
177
+ function destroy() {
178
+ if (observer) {
179
+ observer.disconnect();
180
+ observer = null;
181
+ }
182
+ if (scrollListener && scrollRoot) {
183
+ scrollRoot.removeEventListener("scroll", scrollListener);
184
+ scrollListener = null;
185
+ }
186
+ elementToPage.clear();
187
+ pageToElement.clear();
188
+ visiblePages.value = /* @__PURE__ */ new Set();
189
+ pageMetas.value = [];
190
+ scrollRoot = null;
191
+ }
192
+ return {
193
+ pageMetas,
194
+ currentPage,
195
+ renderedPages,
196
+ isPageRendered,
197
+ observePage,
198
+ unobservePage,
199
+ scrollToPage,
200
+ init,
201
+ destroy
202
+ };
203
+ }
@@ -0,0 +1,11 @@
1
+ import { type Ref } from 'vue';
2
+ import type { PDFDocumentProxy } from 'pdfjs-dist';
3
+ export interface SearchIndex {
4
+ isReady: Ref<boolean>;
5
+ totalPages: Ref<number>;
6
+ getPageText: (pageNumber: number) => string | null;
7
+ buildIndex: (doc: PDFDocumentProxy) => Promise<void>;
8
+ destroy: () => void;
9
+ }
10
+ export declare function createSearchIndex(): SearchIndex;
11
+ export declare function useSearchIndex(): SearchIndex;
@@ -0,0 +1,71 @@
1
+ import { ref, provide, inject } from "vue";
2
+ const SEARCH_INDEX_KEY = Symbol("kviewer-search-index");
3
+ const INDEX_BATCH_SIZE = 5;
4
+ export function createSearchIndex() {
5
+ const isReady = ref(false);
6
+ const totalPages = ref(0);
7
+ const pageTexts = /* @__PURE__ */ new Map();
8
+ let destroyed = false;
9
+ function getPageText(pageNumber) {
10
+ return pageTexts.get(pageNumber) ?? null;
11
+ }
12
+ async function extractPageText(doc, pageNumber) {
13
+ const page = await doc.getPage(pageNumber);
14
+ const content = await page.getTextContent({
15
+ includeMarkedContent: false,
16
+ disableNormalization: false
17
+ });
18
+ return content.items.filter((item) => "str" in item).map((item) => item.str).join("");
19
+ }
20
+ async function buildIndex(doc) {
21
+ destroyed = false;
22
+ isReady.value = false;
23
+ pageTexts.clear();
24
+ totalPages.value = doc.numPages;
25
+ let currentPage = 1;
26
+ while (currentPage <= doc.numPages && !destroyed) {
27
+ const batchEnd = Math.min(currentPage + INDEX_BATCH_SIZE - 1, doc.numPages);
28
+ const promises = [];
29
+ for (let i = currentPage; i <= batchEnd; i++) {
30
+ const pageNum = i;
31
+ promises.push(
32
+ extractPageText(doc, pageNum).then((text) => ({ pageNumber: pageNum, text }))
33
+ );
34
+ }
35
+ const results = await Promise.all(promises);
36
+ if (destroyed) return;
37
+ for (const { pageNumber, text } of results) {
38
+ pageTexts.set(pageNumber, text);
39
+ }
40
+ currentPage = batchEnd + 1;
41
+ if (currentPage <= doc.numPages) {
42
+ await new Promise((resolve) => {
43
+ if (typeof requestIdleCallback === "function") {
44
+ requestIdleCallback(() => resolve());
45
+ } else {
46
+ setTimeout(resolve, 0);
47
+ }
48
+ });
49
+ }
50
+ }
51
+ if (!destroyed) {
52
+ isReady.value = true;
53
+ }
54
+ }
55
+ function destroy() {
56
+ destroyed = true;
57
+ isReady.value = false;
58
+ totalPages.value = 0;
59
+ pageTexts.clear();
60
+ }
61
+ const index = { isReady, totalPages, getPageText, buildIndex, destroy };
62
+ provide(SEARCH_INDEX_KEY, index);
63
+ return index;
64
+ }
65
+ export function useSearchIndex() {
66
+ const index = inject(SEARCH_INDEX_KEY);
67
+ if (!index) {
68
+ throw new Error("useSearchIndex() must be used inside a <KViewer> component");
69
+ }
70
+ return index;
71
+ }
@@ -0,0 +1,32 @@
1
+ import { type Ref } from 'vue';
2
+ export interface ViewerSearchState {
3
+ isOpen: Ref<boolean>;
4
+ query: Ref<string>;
5
+ matchCase: Ref<boolean>;
6
+ wholeWord: Ref<boolean>;
7
+ highlightAll: Ref<boolean>;
8
+ currentMatch: Ref<number>;
9
+ totalMatches: Ref<number>;
10
+ notFound: Ref<boolean>;
11
+ open: () => void;
12
+ close: () => void;
13
+ reset: () => void;
14
+ setQuery: (value: string) => void;
15
+ toggleMatchCase: () => void;
16
+ toggleWholeWord: () => void;
17
+ toggleHighlightAll: () => void;
18
+ findNext: () => void;
19
+ findPrevious: () => void;
20
+ registerPageLayer: (pageNumber: number, textDivs: HTMLElement[], textContentItemsStr: string[]) => void;
21
+ updatePageLayer: (pageNumber: number, textDivs: HTMLElement[], textContentItemsStr: string[]) => void;
22
+ unregisterPageLayer: (pageNumber: number) => void;
23
+ setInputElement: (input: HTMLInputElement | null) => void;
24
+ focusInput: () => void;
25
+ setSearchIndex: (index: {
26
+ getPageText: (pageNumber: number) => string | null;
27
+ totalPages: number;
28
+ }) => void;
29
+ setScrollToPage: (fn: (pageNumber: number) => void) => void;
30
+ }
31
+ export declare function provideViewerSearch(): ViewerSearchState;
32
+ export declare function useViewerSearch(): ViewerSearchState;