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,594 @@
1
+ import Konva from "konva";
2
+ import { AnnotationType } from "../types.js";
3
+ import { SELECTOR_HOVER_STYLE, SHAPE_GROUP_NAME } from "../const.js";
4
+ import { defaultOptions } from "../config.js";
5
+ import { isStylusTouch } from "../input-device.js";
6
+ export class Selector {
7
+ onSelected;
8
+ onChanged;
9
+ onDelete;
10
+ onCancel;
11
+ onMultiSelected;
12
+ onRequestDeleteConfirm;
13
+ onFreeTextDoubleClick;
14
+ getStylusModeEnabled;
15
+ transformerStore = /* @__PURE__ */ new Map();
16
+ getAnnotationStore;
17
+ konvaCanvasStore;
18
+ _currentTransformerId = null;
19
+ selectedId = null;
20
+ selectedIds = [];
21
+ marqueeRect = null;
22
+ marqueeStartPos = null;
23
+ marqueeStage = null;
24
+ constructor({
25
+ konvaCanvasStore,
26
+ getAnnotationStore,
27
+ onDelete,
28
+ onSelected,
29
+ onMultiSelected,
30
+ onCancel,
31
+ onChanged,
32
+ onRequestDeleteConfirm,
33
+ onFreeTextDoubleClick,
34
+ getStylusModeEnabled
35
+ }) {
36
+ this.konvaCanvasStore = konvaCanvasStore;
37
+ this.getAnnotationStore = getAnnotationStore;
38
+ this.onDelete = onDelete;
39
+ this.onSelected = onSelected;
40
+ this.onMultiSelected = onMultiSelected;
41
+ this.onCancel = onCancel;
42
+ this.onChanged = onChanged;
43
+ this.onRequestDeleteConfirm = onRequestDeleteConfirm;
44
+ this.onFreeTextDoubleClick = onFreeTextDoubleClick;
45
+ this.getStylusModeEnabled = getStylusModeEnabled;
46
+ this.handleKeyDown = this.handleKeyDown.bind(this);
47
+ window.addEventListener("keydown", this.handleKeyDown);
48
+ }
49
+ /** Returns true if this event should be rejected (finger touch in stylus mode). */
50
+ isStylusRejected(evt) {
51
+ if (!this.getStylusModeEnabled?.() || !evt) return false;
52
+ if (evt instanceof PointerEvent) return evt.pointerType === "touch";
53
+ if (typeof TouchEvent !== "undefined" && evt instanceof TouchEvent) return !isStylusTouch(evt);
54
+ return false;
55
+ }
56
+ handleKeyDown(e) {
57
+ const target = e.target;
58
+ if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement || target?.isContentEditable) return;
59
+ if (e.key === "Backspace" || e.key === "Delete") {
60
+ if (this.selectedIds.length > 0) {
61
+ e.preventDefault();
62
+ this.selectedIds.forEach((id) => this.onDelete(id));
63
+ this.selectedIds = [];
64
+ this.clearTransformers();
65
+ } else if (this._currentTransformerId) {
66
+ e.preventDefault();
67
+ this.onDelete(this._currentTransformerId);
68
+ this.clearTransformers();
69
+ }
70
+ }
71
+ }
72
+ get currentTransformerId() {
73
+ return this._currentTransformerId;
74
+ }
75
+ set currentTransformerId(id) {
76
+ if (this._currentTransformerId !== id) {
77
+ this.selectedId = id;
78
+ this.deactivateTransformer(this._currentTransformerId);
79
+ this._currentTransformerId = id;
80
+ }
81
+ }
82
+ disableStageEvents(konvaStage) {
83
+ konvaStage.off(
84
+ "click mousedown mousemove mouseup touchstart touchmove touchend pointerdown pointermove pointerup"
85
+ );
86
+ }
87
+ bindStageEvents(konvaStage) {
88
+ konvaStage.on("click tap", (e) => {
89
+ if (e.target !== konvaStage) return;
90
+ if (this.isStylusRejected(e.evt)) return;
91
+ this.clearTransformers();
92
+ });
93
+ }
94
+ getBackgroundLayer(konvaStage) {
95
+ return konvaStage.getLayers()[0];
96
+ }
97
+ getPageShapeGroups(konvaStage) {
98
+ return this.getBackgroundLayer(konvaStage).getChildren(
99
+ (node) => node.name() === SHAPE_GROUP_NAME
100
+ );
101
+ }
102
+ getGroupById(konvaStage, groupId) {
103
+ const pageGroups = this.getPageShapeGroups(konvaStage);
104
+ return pageGroups.find((group) => group.id() === groupId) || null;
105
+ }
106
+ getFirstShapeInGroup(group) {
107
+ return group.getChildren().find((node) => node instanceof Konva.Shape) || null;
108
+ }
109
+ enableShapeGroups(groups, konvaStage) {
110
+ groups.forEach((group) => {
111
+ group.getChildren().forEach((shape) => {
112
+ if (shape instanceof Konva.Shape) {
113
+ this.removeShapeEvents(shape);
114
+ this.bindShapeEvents(shape, konvaStage);
115
+ }
116
+ });
117
+ });
118
+ }
119
+ disableShapeGroups(groups) {
120
+ groups.forEach((group) => {
121
+ group.getChildren().forEach((shape) => {
122
+ if (shape instanceof Konva.Shape) {
123
+ this.removeShapeEvents(shape);
124
+ }
125
+ });
126
+ });
127
+ }
128
+ bindShapeEvents(shape, konvaStage) {
129
+ shape.on("pointerdblclick", async (e) => {
130
+ if (this.isStylusRejected(e.evt)) return;
131
+ const group = shape.findAncestor(`.${SHAPE_GROUP_NAME}`);
132
+ if (!group) return;
133
+ const id = group.id();
134
+ const store = this.getAnnotationStore(id);
135
+ if (store?.type === AnnotationType.FREETEXT && this.onFreeTextDoubleClick) {
136
+ this.onFreeTextDoubleClick(id);
137
+ return;
138
+ }
139
+ if (defaultOptions.setting.DB_CLICK_DELETE) {
140
+ if (this.onRequestDeleteConfirm) {
141
+ const confirmed = await this.onRequestDeleteConfirm(this.currentTransformerId);
142
+ if (confirmed) {
143
+ this.onDelete(this.currentTransformerId);
144
+ this.clearTransformers();
145
+ }
146
+ } else {
147
+ this.onDelete(this.currentTransformerId);
148
+ this.clearTransformers();
149
+ }
150
+ }
151
+ });
152
+ shape.on("pointerclick", (e) => {
153
+ if (this.isStylusRejected(e.evt)) return;
154
+ if (e.evt.button === 0) {
155
+ this.handleShapeClick(shape, konvaStage, true);
156
+ }
157
+ });
158
+ shape.on("mouseover", (e) => {
159
+ if (e.evt.button === 0) {
160
+ this.handleShapeMouseover();
161
+ }
162
+ });
163
+ shape.on("mouseout", (e) => {
164
+ if (e.evt.button === 0) {
165
+ this.handleShapeMouseout();
166
+ }
167
+ });
168
+ }
169
+ removeShapeEvents(shape) {
170
+ shape.off("pointerclick mouseover mouseout pointerdblclick");
171
+ }
172
+ handleShapeClick(shape, konvaStage, isClick = false) {
173
+ const group = shape.findAncestor(
174
+ `.${SHAPE_GROUP_NAME}`
175
+ );
176
+ if (!group) return;
177
+ this.clearTransformers();
178
+ this.createTransformer(group, konvaStage, !isClick);
179
+ const selectorRect = this.transformerStore.get(group.id()).getClientRect();
180
+ this.onSelected(group.id(), isClick, selectorRect);
181
+ }
182
+ createTransformer(group, konvaStage, flash) {
183
+ const line = group.children[0];
184
+ const groupId = group.id();
185
+ this.currentTransformerId = groupId;
186
+ const rawAnnotationStore = this.getAnnotationStore(groupId);
187
+ group.off("dragend");
188
+ const transformer = new Konva.Transformer({
189
+ resizeEnabled: rawAnnotationStore.resizable,
190
+ rotateEnabled: false,
191
+ borderStrokeWidth: defaultOptions.chooseSetting.STROKEWIDTH,
192
+ borderStroke: defaultOptions.chooseSetting.COLOR,
193
+ anchorFill: defaultOptions.chooseSetting.COLOR,
194
+ anchorStroke: defaultOptions.chooseSetting.COLOR,
195
+ opacity: defaultOptions.chooseSetting.OPACITY,
196
+ anchorCornerRadius: 5,
197
+ anchorStrokeWidth: 2,
198
+ anchorSize: 8,
199
+ padding: 1,
200
+ boundBoxFunc: (_oldBox, newBox) => {
201
+ newBox.width = Math.max(30, newBox.width);
202
+ return newBox;
203
+ }
204
+ });
205
+ if (line?.attrs?.id && line.attrs.id === "note") {
206
+ transformer.resizeEnabled(false);
207
+ }
208
+ group.draggable(rawAnnotationStore.draggable);
209
+ if (this.getStylusModeEnabled?.()) {
210
+ group.preventDefault(false);
211
+ transformer.preventDefault(false);
212
+ let savedPos = null;
213
+ group.on("dragstart.stylusGuard", (e) => {
214
+ if (this.isStylusRejected(e.evt)) {
215
+ savedPos = group.absolutePosition();
216
+ setTimeout(() => {
217
+ group.stopDrag();
218
+ if (savedPos) group.absolutePosition(savedPos);
219
+ konvaStage.batchDraw();
220
+ }, 0);
221
+ }
222
+ });
223
+ }
224
+ transformer.off("transformend");
225
+ transformer.off("transformstart");
226
+ transformer.on("transformend", () => {
227
+ this.onChanged(
228
+ group.id(),
229
+ group.toJSON(),
230
+ { ...rawAnnotationStore },
231
+ Konva.Node.create(group.toJSON()).getClientRect(),
232
+ transformer.getClientRect()
233
+ );
234
+ });
235
+ transformer.on("transformstart", () => {
236
+ this.onCancel();
237
+ });
238
+ transformer.on("dragstart", () => {
239
+ this.onCancel();
240
+ });
241
+ transformer.on("dragend", () => {
242
+ this.onChanged(
243
+ group.id(),
244
+ group.toJSON(),
245
+ { ...rawAnnotationStore },
246
+ Konva.Node.create(group.toJSON()).getClientRect(),
247
+ transformer.getClientRect()
248
+ );
249
+ });
250
+ transformer.on("dragmove", () => {
251
+ const boxes = transformer.nodes().map((node) => node.getClientRect());
252
+ const box = this.getTotalBox(boxes);
253
+ transformer.nodes().forEach((shape) => {
254
+ const absPos = shape.getAbsolutePosition();
255
+ const offsetX = box.x - absPos.x;
256
+ const offsetY = box.y - absPos.y;
257
+ const halfWidth = box.width / 2;
258
+ const halfHeight = box.height / 2;
259
+ const newAbsPos = { ...absPos };
260
+ if (box.x + halfWidth < 0) {
261
+ newAbsPos.x = -offsetX - halfWidth;
262
+ }
263
+ if (box.y + halfHeight < 0) {
264
+ newAbsPos.y = -offsetY - halfHeight;
265
+ }
266
+ if (box.x + halfWidth > konvaStage.width()) {
267
+ newAbsPos.x = konvaStage.width() - halfWidth - offsetX;
268
+ }
269
+ if (box.y + halfHeight > konvaStage.height()) {
270
+ newAbsPos.y = konvaStage.height() - halfHeight - offsetY;
271
+ }
272
+ shape.setAbsolutePosition(newAbsPos);
273
+ });
274
+ });
275
+ transformer.nodes([group]);
276
+ this.getBackgroundLayer(konvaStage).add(transformer);
277
+ this.transformerStore.set(groupId, transformer);
278
+ if (flash) {
279
+ this.flashNodeWithTransformer(group, transformer, () => {
280
+ this.onSelected(group.id(), false, transformer.getClientRect());
281
+ });
282
+ }
283
+ }
284
+ flashNodeWithTransformer(group, transformer, onFinish) {
285
+ let flashCount = 0;
286
+ const maxFlashes = 1;
287
+ const fadeDuration = 0.1;
288
+ const originalStroke = transformer.borderStroke();
289
+ const highlightStroke = "red";
290
+ const fadeOut = () => {
291
+ const groupTween = new Konva.Tween({
292
+ node: group,
293
+ duration: fadeDuration,
294
+ opacity: 0,
295
+ onFinish: () => {
296
+ try {
297
+ transformer.borderStroke(highlightStroke);
298
+ transformer.getLayer()?.batchDraw();
299
+ fadeIn();
300
+ } catch {
301
+ }
302
+ }
303
+ });
304
+ groupTween.play();
305
+ };
306
+ const fadeIn = () => {
307
+ const groupTween = new Konva.Tween({
308
+ node: group,
309
+ duration: fadeDuration,
310
+ opacity: 1,
311
+ onFinish: () => {
312
+ try {
313
+ transformer.borderStroke(originalStroke);
314
+ transformer.getLayer()?.batchDraw();
315
+ flashCount++;
316
+ if (flashCount < maxFlashes) {
317
+ setTimeout(fadeOut, 100);
318
+ } else if (onFinish) {
319
+ onFinish();
320
+ }
321
+ } catch {
322
+ }
323
+ }
324
+ });
325
+ groupTween.play();
326
+ };
327
+ fadeOut();
328
+ }
329
+ getTotalBox(boxes) {
330
+ let minX = Infinity;
331
+ let minY = Infinity;
332
+ let maxX = -Infinity;
333
+ let maxY = -Infinity;
334
+ boxes.forEach((box) => {
335
+ minX = Math.min(minX, box.x);
336
+ minY = Math.min(minY, box.y);
337
+ maxX = Math.max(maxX, box.x + box.width);
338
+ maxY = Math.max(maxY, box.y + box.height);
339
+ });
340
+ return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
341
+ }
342
+ toggleCursorStyle(add) {
343
+ document.body.classList.toggle(SELECTOR_HOVER_STYLE, add);
344
+ }
345
+ handleShapeMouseover() {
346
+ this.toggleCursorStyle(true);
347
+ }
348
+ handleShapeMouseout() {
349
+ this.toggleCursorStyle(false);
350
+ }
351
+ clearTransformers() {
352
+ this.toggleCursorStyle(false);
353
+ this.transformerStore.forEach((transformer) => {
354
+ if (transformer) {
355
+ transformer.nodes().forEach((group) => {
356
+ if (group instanceof Konva.Group) {
357
+ group.draggable(false);
358
+ }
359
+ });
360
+ transformer.nodes([]);
361
+ transformer.destroy();
362
+ }
363
+ });
364
+ this.transformerStore.clear();
365
+ this.currentTransformerId = null;
366
+ this.onCancel();
367
+ }
368
+ deactivateTransformer(transformerId) {
369
+ if (transformerId) {
370
+ const transformer = this.transformerStore.get(transformerId);
371
+ if (transformer) {
372
+ transformer.nodes().forEach((group) => {
373
+ if (group instanceof Konva.Group) {
374
+ group.draggable(false);
375
+ }
376
+ });
377
+ }
378
+ }
379
+ }
380
+ selectedShape(id, konvaStage) {
381
+ const group = this.getGroupById(konvaStage, id);
382
+ if (!group) return;
383
+ const shape = this.getFirstShapeInGroup(group);
384
+ if (!shape) return;
385
+ this.handleShapeClick(shape, konvaStage, false);
386
+ }
387
+ clear() {
388
+ this.clearTransformers();
389
+ this.konvaCanvasStore.forEach((konvaCanvas) => {
390
+ const { konvaStage } = konvaCanvas;
391
+ const pageGroups = this.getPageShapeGroups(konvaStage);
392
+ this.disableStageEvents(konvaStage);
393
+ this.disableShapeGroups(pageGroups);
394
+ });
395
+ }
396
+ activate(pageNumber) {
397
+ const konvaCanvas = this.konvaCanvasStore.get(pageNumber);
398
+ if (!konvaCanvas) return;
399
+ const { konvaStage } = konvaCanvas;
400
+ const pageGroups = this.getPageShapeGroups(konvaStage);
401
+ this.disableStageEvents(konvaStage);
402
+ this.bindStageEvents(konvaStage);
403
+ this.enableShapeGroups(pageGroups, konvaStage);
404
+ if (this.selectedId) {
405
+ this.selectedShape(this.selectedId, konvaStage);
406
+ }
407
+ }
408
+ select(id) {
409
+ this.selectedId = id;
410
+ }
411
+ refreshCurrentSelection() {
412
+ const id = this._currentTransformerId;
413
+ if (!id) return null;
414
+ const transformer = this.transformerStore.get(id);
415
+ if (!transformer) return null;
416
+ transformer.forceUpdate();
417
+ transformer.getLayer()?.batchDraw();
418
+ return transformer.getClientRect();
419
+ }
420
+ delete() {
421
+ this.selectedIds = [];
422
+ this.clearTransformers();
423
+ }
424
+ activateMarquee(pageNumber) {
425
+ const konvaCanvas = this.konvaCanvasStore.get(pageNumber);
426
+ if (!konvaCanvas) return;
427
+ const { konvaStage } = konvaCanvas;
428
+ const pageGroups = this.getPageShapeGroups(konvaStage);
429
+ this.disableStageEvents(konvaStage);
430
+ this.enableShapeGroups(pageGroups, konvaStage);
431
+ this.bindMarqueeEvents(konvaStage);
432
+ }
433
+ bindMarqueeEvents(konvaStage) {
434
+ konvaStage.on("mousedown touchstart", (e) => {
435
+ if (e.target !== konvaStage) return;
436
+ if (this.isStylusRejected(e.evt)) return;
437
+ if (this.getStylusModeEnabled?.() && e.evt) e.evt.preventDefault();
438
+ this.clearTransformers();
439
+ this.selectedIds = [];
440
+ const pos = konvaStage.getRelativePointerPosition();
441
+ if (!pos) return;
442
+ this.marqueeStartPos = pos;
443
+ this.marqueeStage = konvaStage;
444
+ this.marqueeRect = new Konva.Rect({
445
+ x: pos.x,
446
+ y: pos.y,
447
+ width: 0,
448
+ height: 0,
449
+ stroke: defaultOptions.chooseSetting.COLOR,
450
+ strokeWidth: 1,
451
+ dash: [6, 4],
452
+ fill: `${defaultOptions.chooseSetting.COLOR}10`,
453
+ listening: false
454
+ });
455
+ this.getBackgroundLayer(konvaStage).add(this.marqueeRect);
456
+ });
457
+ konvaStage.on("mousemove touchmove", (e) => {
458
+ if (!this.marqueeRect || !this.marqueeStartPos || !this.marqueeStage) return;
459
+ if (this.isStylusRejected(e.evt)) return;
460
+ if (this.getStylusModeEnabled?.() && e.evt) e.evt.preventDefault();
461
+ const pos = this.marqueeStage.getRelativePointerPosition();
462
+ if (!pos) return;
463
+ const x = Math.min(pos.x, this.marqueeStartPos.x);
464
+ const y = Math.min(pos.y, this.marqueeStartPos.y);
465
+ const width = Math.abs(pos.x - this.marqueeStartPos.x);
466
+ const height = Math.abs(pos.y - this.marqueeStartPos.y);
467
+ this.marqueeRect.setAttrs({ x, y, width, height });
468
+ this.marqueeStage.batchDraw();
469
+ });
470
+ konvaStage.on("mouseup touchend", (e) => {
471
+ if (!this.marqueeRect || !this.marqueeStage) return;
472
+ if (this.isStylusRejected(e.evt)) return;
473
+ const selectionBox = this.marqueeRect.getClientRect();
474
+ this.marqueeRect.destroy();
475
+ this.marqueeRect = null;
476
+ this.marqueeStartPos = null;
477
+ if (selectionBox.width < 5 && selectionBox.height < 5) {
478
+ this.marqueeStage = null;
479
+ return;
480
+ }
481
+ const groups = this.getPageShapeGroups(this.marqueeStage);
482
+ const matchedIds = [];
483
+ groups.forEach((group) => {
484
+ const groupRect = group.getClientRect();
485
+ if (this.rectsIntersect(selectionBox, groupRect)) {
486
+ matchedIds.push(group.id());
487
+ }
488
+ });
489
+ if (matchedIds.length > 0) {
490
+ this.selectedIds = matchedIds;
491
+ const nodes = matchedIds.map((id) => this.getGroupById(this.marqueeStage, id)).filter((g) => g !== null);
492
+ if (nodes.length > 0) {
493
+ const transformer = new Konva.Transformer({
494
+ resizeEnabled: false,
495
+ rotateEnabled: false,
496
+ borderStrokeWidth: defaultOptions.chooseSetting.STROKEWIDTH,
497
+ borderStroke: defaultOptions.chooseSetting.COLOR,
498
+ anchorFill: defaultOptions.chooseSetting.COLOR,
499
+ anchorStroke: defaultOptions.chooseSetting.COLOR,
500
+ opacity: defaultOptions.chooseSetting.OPACITY,
501
+ anchorSize: 0,
502
+ padding: 2
503
+ });
504
+ nodes.forEach((node) => node.draggable(true));
505
+ transformer.nodes(nodes);
506
+ this.getBackgroundLayer(this.marqueeStage).add(transformer);
507
+ this.transformerStore.set("__multi__", transformer);
508
+ nodes.forEach((node) => {
509
+ node.on("dragstart.marquee", () => {
510
+ this.onCancel();
511
+ });
512
+ node.on("dragmove.marquee", () => {
513
+ this.onMultiSelected(matchedIds, transformer.getClientRect());
514
+ });
515
+ node.on("dragend.marquee", () => {
516
+ this.onMultiSelected(matchedIds, transformer.getClientRect());
517
+ });
518
+ });
519
+ const combinedRect = transformer.getClientRect();
520
+ this.onMultiSelected(matchedIds, combinedRect);
521
+ }
522
+ }
523
+ this.marqueeStage = null;
524
+ });
525
+ }
526
+ rectsIntersect(a, b) {
527
+ return a.x < b.x + b.width && a.x + a.width > b.x && a.y < b.y + b.height && a.y + a.height > b.y;
528
+ }
529
+ activateEraser(pageNumber) {
530
+ const konvaCanvas = this.konvaCanvasStore.get(pageNumber);
531
+ if (!konvaCanvas) return;
532
+ const { konvaStage } = konvaCanvas;
533
+ this.disableStageEvents(konvaStage);
534
+ this.bindEraserEvents(konvaStage);
535
+ }
536
+ eraserLine = null;
537
+ eraserStage = null;
538
+ bindEraserEvents(konvaStage) {
539
+ konvaStage.on("mousedown touchstart", (e) => {
540
+ if (e.target !== konvaStage && !(e.target instanceof Konva.Shape)) {
541
+ }
542
+ if (this.isStylusRejected(e.evt)) return;
543
+ if (this.getStylusModeEnabled?.() && e.evt) e.evt.preventDefault();
544
+ const pos = konvaStage.getRelativePointerPosition();
545
+ if (!pos) return;
546
+ this.eraserStage = konvaStage;
547
+ this.eraserLine = new Konva.Line({
548
+ stroke: "#888888",
549
+ strokeWidth: 12,
550
+ opacity: 0.4,
551
+ lineCap: "round",
552
+ lineJoin: "round",
553
+ strokeScaleEnabled: false,
554
+ listening: false,
555
+ points: [pos.x, pos.y]
556
+ });
557
+ this.getBackgroundLayer(konvaStage).add(this.eraserLine);
558
+ });
559
+ konvaStage.on("mousemove touchmove", (e) => {
560
+ if (!this.eraserLine || !this.eraserStage) return;
561
+ if (this.isStylusRejected(e.evt)) return;
562
+ if (this.getStylusModeEnabled?.() && e.evt) e.evt.preventDefault();
563
+ const pos = this.eraserStage.getRelativePointerPosition();
564
+ if (!pos) return;
565
+ const newPoints = this.eraserLine.points().concat([pos.x, pos.y]);
566
+ this.eraserLine.points(newPoints);
567
+ this.eraserStage.batchDraw();
568
+ });
569
+ konvaStage.on("mouseup touchend", (e) => {
570
+ if (!this.eraserLine || !this.eraserStage) return;
571
+ if (this.isStylusRejected(e.evt)) return;
572
+ const eraserRect = this.eraserLine.getClientRect();
573
+ this.eraserLine.destroy();
574
+ this.eraserLine = null;
575
+ if (eraserRect.width < 3 && eraserRect.height < 3) {
576
+ this.eraserStage = null;
577
+ return;
578
+ }
579
+ const groups = this.getPageShapeGroups(this.eraserStage);
580
+ const toDelete = [];
581
+ groups.forEach((group) => {
582
+ if (this.rectsIntersect(eraserRect, group.getClientRect())) {
583
+ toDelete.push(group.id());
584
+ }
585
+ });
586
+ this.eraserStage = null;
587
+ toDelete.forEach((id) => this.onDelete(id));
588
+ });
589
+ }
590
+ destroy() {
591
+ this.clear();
592
+ window.removeEventListener("keydown", this.handleKeyDown);
593
+ }
594
+ }
@@ -0,0 +1,5 @@
1
+ import { type IAnnotationStore } from './types.js';
2
+ export declare function normalizeImportedAnnotations(input: unknown, fallbackTitle?: string): {
3
+ annotations: IAnnotationStore[];
4
+ skipped: number;
5
+ };
@@ -0,0 +1,99 @@
1
+ import { annotationDefinitions } from "./config.js";
2
+ import {
3
+ AnnotationType
4
+ } from "./types.js";
5
+ import { formatTimestamp, generateUUID } from "./utils.js";
6
+ function isRecord(value) {
7
+ return !!value && typeof value === "object" && !Array.isArray(value);
8
+ }
9
+ function isNumber(value) {
10
+ return typeof value === "number" && Number.isFinite(value);
11
+ }
12
+ function isBoolean(value) {
13
+ return typeof value === "boolean";
14
+ }
15
+ function isString(value) {
16
+ return typeof value === "string";
17
+ }
18
+ function normalizeComment(comment, fallbackTitle) {
19
+ if (!isRecord(comment)) return null;
20
+ const content = comment.content;
21
+ if (!isString(content)) return null;
22
+ return {
23
+ id: isString(comment.id) && comment.id.length > 0 ? comment.id : generateUUID(),
24
+ title: isString(comment.title) && comment.title.length > 0 ? comment.title : fallbackTitle,
25
+ date: isString(comment.date) && comment.date.length > 0 ? comment.date : formatTimestamp(Date.now()),
26
+ content,
27
+ status: isString(comment.status) ? comment.status : void 0
28
+ };
29
+ }
30
+ function normalizeContentsObj(value) {
31
+ if (!isRecord(value)) return null;
32
+ const text = value.text;
33
+ if (!isString(text)) return null;
34
+ const image = isString(value.image) ? value.image : void 0;
35
+ return { text, image };
36
+ }
37
+ const validAnnotationTypes = new Set(
38
+ Object.values(AnnotationType).filter((value) => typeof value === "number")
39
+ );
40
+ function normalizeAnnotation(raw, fallbackTitle) {
41
+ if (!isRecord(raw)) return null;
42
+ const id = raw.id;
43
+ const pageNumber = raw.pageNumber;
44
+ const konvaString = raw.konvaString;
45
+ const konvaClientRect = raw.konvaClientRect;
46
+ const type = raw.type;
47
+ if (!isString(id) || id.length === 0) return null;
48
+ if (!isNumber(pageNumber) || pageNumber < 1) return null;
49
+ if (!isString(konvaString) || konvaString.length === 0) return null;
50
+ if (!isNumber(type) || !validAnnotationTypes.has(type)) return null;
51
+ if (!isRecord(konvaClientRect)) return null;
52
+ const x = konvaClientRect.x;
53
+ const y = konvaClientRect.y;
54
+ const width = konvaClientRect.width;
55
+ const height = konvaClientRect.height;
56
+ if (!isNumber(x) || !isNumber(y) || !isNumber(width) || !isNumber(height)) return null;
57
+ const def = annotationDefinitions.find((item) => item.type === type);
58
+ const subtype = isString(raw.subtype) ? raw.subtype : def?.subtype ?? "Text";
59
+ const pdfjsType = isNumber(raw.pdfjsType) ? raw.pdfjsType : def?.pdfjsAnnotationType;
60
+ const pdfjsEditorType = isNumber(raw.pdfjsEditorType) ? raw.pdfjsEditorType : def?.pdfjsEditorType;
61
+ if (!isNumber(pdfjsType) || !isNumber(pdfjsEditorType)) return null;
62
+ const commentsInput = Array.isArray(raw.comments) ? raw.comments : [];
63
+ const comments = commentsInput.map((comment) => normalizeComment(comment, fallbackTitle)).filter((comment) => !!comment);
64
+ const normalized = {
65
+ id,
66
+ pageNumber,
67
+ konvaString,
68
+ konvaClientRect: { x, y, width, height },
69
+ title: isString(raw.title) && raw.title.length > 0 ? raw.title : fallbackTitle,
70
+ type,
71
+ subtype,
72
+ pdfjsType,
73
+ pdfjsEditorType,
74
+ color: isString(raw.color) || raw.color === null ? raw.color : def?.style?.color ?? null,
75
+ fontSize: isNumber(raw.fontSize) ? raw.fontSize : def?.style?.fontSize ?? null,
76
+ date: isString(raw.date) && raw.date.length > 0 ? raw.date : formatTimestamp(Date.now()),
77
+ contentsObj: normalizeContentsObj(raw.contentsObj),
78
+ comments,
79
+ resizable: isBoolean(raw.resizable) ? raw.resizable : def?.resizable ?? false,
80
+ draggable: isBoolean(raw.draggable) ? raw.draggable : def?.draggable ?? false
81
+ };
82
+ return normalized;
83
+ }
84
+ export function normalizeImportedAnnotations(input, fallbackTitle = "User") {
85
+ if (!Array.isArray(input)) {
86
+ return { annotations: [], skipped: 0 };
87
+ }
88
+ const annotations = [];
89
+ let skipped = 0;
90
+ for (const item of input) {
91
+ const normalized = normalizeAnnotation(item, fallbackTitle);
92
+ if (normalized) {
93
+ annotations.push(normalized);
94
+ } else {
95
+ skipped++;
96
+ }
97
+ }
98
+ return { annotations, skipped };
99
+ }