kviewer 0.0.8 → 0.0.10

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 (34) hide show
  1. package/dist/module.d.mts +1 -1
  2. package/dist/module.json +1 -1
  3. package/dist/runtime/annotation/engine/editor/editor.d.ts +11 -5
  4. package/dist/runtime/annotation/engine/editor/editor.js +27 -11
  5. package/dist/runtime/annotation/engine/editor/selector.d.ts +20 -1
  6. package/dist/runtime/annotation/engine/editor/selector.js +132 -33
  7. package/dist/runtime/annotation/engine/painter.d.ts +4 -1
  8. package/dist/runtime/annotation/engine/painter.js +21 -5
  9. package/dist/runtime/annotation/engine/tools/freehand.js +2 -2
  10. package/dist/runtime/components/PdfPage.d.vue.ts +6 -1
  11. package/dist/runtime/components/PdfPage.vue +51 -18
  12. package/dist/runtime/components/PdfPage.vue.d.ts +6 -1
  13. package/dist/runtime/components/ToolButton.d.vue.ts +4 -2
  14. package/dist/runtime/components/ToolButton.vue.d.ts +4 -2
  15. package/dist/runtime/components/Viewer.d.vue.ts +3 -0
  16. package/dist/runtime/components/Viewer.vue +225 -165
  17. package/dist/runtime/components/Viewer.vue.d.ts +3 -0
  18. package/dist/runtime/components/form-fields/FormSignatureField.vue +23 -1
  19. package/dist/runtime/components/modals/FreeTextModal.vue +27 -3
  20. package/dist/runtime/components/tools/ActionTools.vue +4 -5
  21. package/dist/runtime/components/tools/DrawingTools.vue +1 -1
  22. package/dist/runtime/composables/useAnnotationEngine.d.ts +2 -0
  23. package/dist/runtime/composables/useAnnotationEngine.js +5 -1
  24. package/dist/runtime/composables/useAnnotationHistory.d.ts +1 -0
  25. package/dist/runtime/composables/useAnnotationHistory.js +10 -3
  26. package/dist/runtime/composables/useInertiaPanzoom.d.ts +40 -0
  27. package/dist/runtime/composables/useInertiaPanzoom.js +472 -0
  28. package/dist/runtime/composables/usePageVirtualization.d.ts +3 -0
  29. package/dist/runtime/composables/usePageVirtualization.js +23 -0
  30. package/dist/runtime/composables/useViewerSearch.d.ts +1 -0
  31. package/dist/runtime/composables/useViewerSearch.js +15 -5
  32. package/dist/runtime/public-types.d.ts +2 -0
  33. package/dist/types.d.mts +1 -1
  34. package/package.json +1 -1
@@ -7,10 +7,10 @@
7
7
  <template #body>
8
8
  <div class="flex flex-col gap-3">
9
9
  <UTextarea
10
+ ref="textareaRef"
10
11
  v-model="inputValue"
11
12
  placeholder="Start typing..."
12
13
  :rows="3"
13
- autofocus
14
14
  />
15
15
  <div class="flex items-center justify-between">
16
16
  <div class="flex gap-1">
@@ -22,6 +22,7 @@
22
22
  c === currentColor ? 'border-white ring-2 ring-blue-500' : 'border-transparent'
23
23
  "
24
24
  :style="{ backgroundColor: c }"
25
+ @pointerdown="onPreserveFocus"
25
26
  @click="currentColor = c"
26
27
  />
27
28
  </div>
@@ -39,14 +40,19 @@
39
40
  <UButton variant="ghost" color="neutral" @click="cancel">
40
41
  Cancel
41
42
  </UButton>
42
- <UButton :disabled="!inputValue.trim()" @click="submit">OK</UButton>
43
+ <UButton
44
+ :disabled="!inputValue.trim()"
45
+ @click="submit"
46
+ >
47
+ OK
48
+ </UButton>
43
49
  </div>
44
50
  </template>
45
51
  </UModal>
46
52
  </template>
47
53
 
48
54
  <script setup>
49
- import { ref, watch } from "vue";
55
+ import { ref, watch, nextTick } from "vue";
50
56
  import { defaultOptions } from "../../annotation/engine/config";
51
57
  const props = defineProps({
52
58
  open: { type: Boolean, required: true },
@@ -55,6 +61,20 @@ const props = defineProps({
55
61
  initialText: { type: String, required: false }
56
62
  });
57
63
  const emit = defineEmits(["update:open", "submit", "cancel"]);
64
+ const textareaRef = ref(null);
65
+ function focusTextarea() {
66
+ const instance = textareaRef.value;
67
+ if (!instance) return;
68
+ const el = instance.inputRef ?? instance.$el?.querySelector?.("textarea") ?? instance;
69
+ if (el && typeof el.focus === "function") {
70
+ el.focus();
71
+ const len = el.value?.length ?? 0;
72
+ try {
73
+ el.setSelectionRange(len, len);
74
+ } catch {
75
+ }
76
+ }
77
+ }
58
78
  const isOpen = ref(props.open);
59
79
  watch(
60
80
  () => props.open,
@@ -64,6 +84,7 @@ watch(
64
84
  inputValue.value = props.initialText ?? "";
65
85
  currentColor.value = props.defaultColor;
66
86
  currentFontSize.value = String(props.defaultFontSize);
87
+ nextTick(() => requestAnimationFrame(() => focusTextarea()));
67
88
  }
68
89
  }
69
90
  );
@@ -86,4 +107,7 @@ function submit() {
86
107
  function cancel() {
87
108
  emit("cancel");
88
109
  }
110
+ function onPreserveFocus(e) {
111
+ if (e.pointerType === "mouse") e.preventDefault();
112
+ }
89
113
  </script>
@@ -18,11 +18,9 @@
18
18
  :disabled="!state.history.canRedo.value"
19
19
  @click="state.history.redo"
20
20
  />
21
- <UButton
22
- icon="i-lucide-eraser"
23
- :variant="state.activeTool.value === 'eraser' ? 'soft' : 'ghost'"
24
- color="neutral"
25
- size="sm"
21
+ <ToolButton
22
+ :tool="{ name: 'Eraser', icon: 'i-lucide-eraser' }"
23
+ :active="state.activeTool.value === 'eraser'"
26
24
  data-testid="action-eraser"
27
25
  @click="state.selectTool('eraser')"
28
26
  />
@@ -31,5 +29,6 @@
31
29
 
32
30
  <script setup>
33
31
  import { useViewerState } from "../../composables/useViewerState";
32
+ import ToolButton from "../ToolButton.vue";
34
33
  const state = useViewerState();
35
34
  </script>
@@ -18,7 +18,7 @@
18
18
  @click="state.selectTool(AnnotationType.FREETEXT)"
19
19
  />
20
20
  <StampPicker />
21
- <SignaturePicker />
21
+ <SignaturePicker v-if="state.signatureHandlers" />
22
22
  <ToolButton
23
23
  :tool="getDef(AnnotationType.RECTANGLE)"
24
24
  :active="state.activeTool.value === AnnotationType.RECTANGLE"
@@ -4,4 +4,6 @@ export declare function createAnnotationEngine(viewerState: ViewerState, options
4
4
  userName?: string;
5
5
  onRequestTextInput: PainterCallbacks['onRequestTextInput'];
6
6
  onRequestDeleteConfirm?: PainterCallbacks['onRequestDeleteConfirm'];
7
+ freehandGroupingDelay?: number;
8
+ setExternalGesturesEnabled?: (enabled: boolean) => void;
7
9
  }): Painter;
@@ -21,6 +21,8 @@ export function createAnnotationEngine(viewerState, options) {
21
21
  if (annotationStore.type === AnnotationType.FREETEXT) {
22
22
  viewerState.painter.value?.selectAnnotation(annotationStore.id);
23
23
  }
24
+ } else {
25
+ viewerState.history.rebaseline();
24
26
  }
25
27
  },
26
28
  onStoreDelete: (id) => {
@@ -64,7 +66,9 @@ export function createAnnotationEngine(viewerState, options) {
64
66
  userName: options.userName ?? "User",
65
67
  callbacks,
66
68
  getStylusModeEnabled: () => viewerState.stylusMode.value,
67
- getReadonly: () => viewerState.readonly.value
69
+ getReadonly: () => viewerState.readonly.value,
70
+ freehandGroupingDelay: options.freehandGroupingDelay,
71
+ setExternalGesturesEnabled: options.setExternalGesturesEnabled
68
72
  });
69
73
  viewerState.painter.value = painter;
70
74
  return painter;
@@ -6,6 +6,7 @@ export interface AnnotationHistory {
6
6
  undo: () => void;
7
7
  redo: () => void;
8
8
  reset: () => void;
9
+ rebaseline: () => void;
9
10
  canUndo: ComputedRef<boolean>;
10
11
  canRedo: ComputedRef<boolean>;
11
12
  }
@@ -6,15 +6,19 @@ function cloneAnnotations(map) {
6
6
  export function createAnnotationHistory(annotations, painter) {
7
7
  const undoStack = ref([]);
8
8
  const redoStack = ref([]);
9
+ let baseline = cloneAnnotations(annotations.value);
9
10
  const canUndo = computed(() => undoStack.value.length > 0);
10
11
  const canRedo = computed(() => redoStack.value.length > 0);
11
12
  function commit() {
12
- const snapshot = cloneAnnotations(annotations.value);
13
- undoStack.value.push(snapshot);
13
+ undoStack.value.push(baseline);
14
14
  if (undoStack.value.length > MAX_HISTORY) {
15
15
  undoStack.value.shift();
16
16
  }
17
17
  redoStack.value = [];
18
+ baseline = cloneAnnotations(annotations.value);
19
+ }
20
+ function rebaseline() {
21
+ baseline = cloneAnnotations(annotations.value);
18
22
  }
19
23
  function restoreSnapshot(target) {
20
24
  const p = painter.value;
@@ -53,6 +57,7 @@ export function createAnnotationHistory(annotations, painter) {
53
57
  redoStack.value.push(currentSnapshot);
54
58
  const target = undoStack.value.pop();
55
59
  restoreSnapshot(target);
60
+ baseline = cloneAnnotations(annotations.value);
56
61
  }
57
62
  function redo() {
58
63
  if (!canRedo.value) return;
@@ -60,10 +65,12 @@ export function createAnnotationHistory(annotations, painter) {
60
65
  undoStack.value.push(currentSnapshot);
61
66
  const target = redoStack.value.pop();
62
67
  restoreSnapshot(target);
68
+ baseline = cloneAnnotations(annotations.value);
63
69
  }
64
70
  function reset() {
65
71
  undoStack.value = [];
66
72
  redoStack.value = [];
73
+ baseline = cloneAnnotations(annotations.value);
67
74
  }
68
- return { commit, undo, redo, reset, canUndo, canRedo };
75
+ return { commit, undo, redo, reset, rebaseline, canUndo, canRedo };
69
76
  }
@@ -0,0 +1,40 @@
1
+ export interface InertiaPanzoomOptions {
2
+ minScale?: number;
3
+ maxScale?: number;
4
+ /** Minimum pointer movement (px) before axis direction is committed. */
5
+ axisLockThreshold?: number;
6
+ /** Vertical must exceed horizontal by this ratio to lock to Y-axis. */
7
+ axisLockRatio?: number;
8
+ }
9
+ export interface ScrollToElementOptions {
10
+ /** Vertical alignment within the viewport. Default: 'start'. */
11
+ block?: 'start' | 'center';
12
+ /** Animate to the target with inertia, or snap instantly. Default: true. */
13
+ animate?: boolean;
14
+ }
15
+ export interface Transform {
16
+ scale: number;
17
+ tx: number;
18
+ ty: number;
19
+ }
20
+ export interface InertiaPanzoomHandle {
21
+ /** Bind gesture handlers to the given element (its parent becomes the viewport). */
22
+ attach: (target: HTMLElement) => void;
23
+ /** Remove handlers and clear inline styles. */
24
+ detach: () => void;
25
+ /** Reset transform and cancel any in-flight momentum. */
26
+ reset: () => void;
27
+ /** Cancel in-flight momentum without changing transform. */
28
+ stop: () => void;
29
+ getScale: () => number;
30
+ getTransform: () => Transform;
31
+ /** Animate the view so `elem` is at the top (or center) of the viewport. */
32
+ scrollToElement: (elem: HTMLElement, opts?: ScrollToElementOptions) => void;
33
+ /** Pan by a delta in viewport pixels (clamped to bounds). */
34
+ scrollBy: (dx: number, dy: number) => void;
35
+ /** Enable/disable pan+pinch gestures (wheel/scrollbar/keyboard still work). */
36
+ setGesturesEnabled: (enabled: boolean) => void;
37
+ /** Subscribe to transform updates. Returns an unsubscribe function. */
38
+ onChange: (cb: (t: Transform) => void) => () => void;
39
+ }
40
+ export declare function useInertiaPanzoom(options?: InertiaPanzoomOptions): InertiaPanzoomHandle;