kviewer 0.0.9 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +19 -0
- package/dist/runtime/annotation/checkbox-styles.d.ts +19 -0
- package/dist/runtime/annotation/checkbox-styles.js +27 -0
- package/dist/runtime/annotation/engine/config.js +44 -0
- package/dist/runtime/annotation/engine/editor/editor.d.ts +6 -3
- package/dist/runtime/annotation/engine/editor/editor.js +22 -9
- package/dist/runtime/annotation/engine/editor/selector.d.ts +9 -1
- package/dist/runtime/annotation/engine/editor/selector.js +72 -30
- package/dist/runtime/annotation/engine/painter.d.ts +6 -2
- package/dist/runtime/annotation/engine/painter.js +42 -5
- package/dist/runtime/annotation/engine/tools/form-field.d.ts +24 -0
- package/dist/runtime/annotation/engine/tools/form-field.js +117 -0
- package/dist/runtime/annotation/engine/types.d.ts +54 -1
- package/dist/runtime/annotation/engine/types.js +4 -0
- package/dist/runtime/annotation/font-style.d.ts +23 -0
- package/dist/runtime/annotation/font-style.js +57 -0
- package/dist/runtime/annotation/parsers/extractCheckboxStyles.d.ts +21 -0
- package/dist/runtime/annotation/parsers/extractCheckboxStyles.js +75 -0
- package/dist/runtime/annotation/parsers/parseFormFields.js +16 -3
- package/dist/runtime/annotation/pdf-export/export-form-fields.d.ts +8 -5
- package/dist/runtime/annotation/pdf-export/export-form-fields.js +245 -1
- package/dist/runtime/annotation/pdf-export/export.d.ts +3 -2
- package/dist/runtime/annotation/pdf-export/export.js +9 -2
- package/dist/runtime/assets/kviewer.css +1 -1
- package/dist/runtime/components/FormFieldLayer.d.vue.ts +5 -0
- package/dist/runtime/components/FormFieldLayer.vue +40 -3
- package/dist/runtime/components/FormFieldLayer.vue.d.ts +5 -0
- package/dist/runtime/components/PdfPage.d.vue.ts +6 -1
- package/dist/runtime/components/PdfPage.vue +75 -18
- package/dist/runtime/components/PdfPage.vue.d.ts +6 -1
- package/dist/runtime/components/ToolButton.d.vue.ts +4 -2
- package/dist/runtime/components/ToolButton.vue.d.ts +4 -2
- package/dist/runtime/components/Viewer.d.vue.ts +18 -3
- package/dist/runtime/components/Viewer.vue +278 -170
- package/dist/runtime/components/Viewer.vue.d.ts +18 -3
- package/dist/runtime/components/ViewerBar.vue +24 -2
- package/dist/runtime/components/form-fields/FormButton.vue +16 -4
- package/dist/runtime/components/form-fields/FormCheckbox.vue +31 -15
- package/dist/runtime/components/form-fields/FormDropdown.vue +3 -1
- package/dist/runtime/components/form-fields/FormFieldWrapper.d.vue.ts +12 -1
- package/dist/runtime/components/form-fields/FormFieldWrapper.vue +45 -9
- package/dist/runtime/components/form-fields/FormFieldWrapper.vue.d.ts +12 -1
- package/dist/runtime/components/form-fields/FormRadioButton.vue +3 -1
- package/dist/runtime/components/form-fields/FormSignatureField.vue +2 -1
- package/dist/runtime/components/form-fields/FormTextField.vue +47 -7
- package/dist/runtime/components/form-fields/PlacedFieldChrome.d.vue.ts +16 -0
- package/dist/runtime/components/form-fields/PlacedFieldChrome.vue +131 -0
- package/dist/runtime/components/form-fields/PlacedFieldChrome.vue.d.ts +16 -0
- package/dist/runtime/components/modals/FreeTextModal.vue +27 -3
- package/dist/runtime/components/modals/SignatureDrawModal.vue +70 -15
- package/dist/runtime/components/panels/PlacedFieldSidebar.d.vue.ts +3 -0
- package/dist/runtime/components/panels/PlacedFieldSidebar.vue +505 -0
- package/dist/runtime/components/panels/PlacedFieldSidebar.vue.d.ts +3 -0
- package/dist/runtime/components/tools/ActionTools.vue +4 -5
- package/dist/runtime/components/tools/FormFieldTools.d.vue.ts +3 -0
- package/dist/runtime/components/tools/FormFieldTools.vue +35 -0
- package/dist/runtime/components/tools/FormFieldTools.vue.d.ts +3 -0
- package/dist/runtime/composables/useAnnotationEngine.d.ts +2 -0
- package/dist/runtime/composables/useAnnotationEngine.js +6 -2
- package/dist/runtime/composables/useAnnotationHistory.d.ts +1 -0
- package/dist/runtime/composables/useAnnotationHistory.js +10 -3
- package/dist/runtime/composables/useFormFields.d.ts +29 -2
- package/dist/runtime/composables/useFormFields.js +259 -5
- package/dist/runtime/composables/useInertiaPanzoom.d.ts +40 -0
- package/dist/runtime/composables/useInertiaPanzoom.js +475 -0
- package/dist/runtime/composables/usePageVirtualization.d.ts +9 -0
- package/dist/runtime/composables/usePageVirtualization.js +34 -3
- package/dist/runtime/composables/useViewerSearch.d.ts +1 -0
- package/dist/runtime/composables/useViewerSearch.js +15 -5
- package/dist/runtime/composables/useViewerState.d.ts +3 -0
- package/dist/runtime/composables/useViewerState.js +22 -1
- package/package.json +2 -2
|
@@ -1,6 +1,32 @@
|
|
|
1
|
-
|
|
1
|
+
import { PDFBool, PDFDict, PDFName, PDFString, StandardFonts, rgb } from "pdf-lib";
|
|
2
|
+
import { CHECKBOX_STYLE_TABLE } from "../checkbox-styles.js";
|
|
3
|
+
export async function writeFormFieldsToPdf(pdfDoc, fieldValues, placedDefinitions = []) {
|
|
4
|
+
const valueByFieldId = new Map(fieldValues.map((v) => [v.fieldId, v]));
|
|
5
|
+
const createdFieldNames = /* @__PURE__ */ new Set();
|
|
6
|
+
const radioGroupCache = /* @__PURE__ */ new Map();
|
|
7
|
+
for (const def of placedDefinitions) {
|
|
8
|
+
try {
|
|
9
|
+
if (def.origin === "parsed") {
|
|
10
|
+
updateParsedField(pdfDoc, def);
|
|
11
|
+
} else {
|
|
12
|
+
await createWidgetForDefinition(
|
|
13
|
+
pdfDoc,
|
|
14
|
+
def,
|
|
15
|
+
valueByFieldId.get(def.id),
|
|
16
|
+
radioGroupCache
|
|
17
|
+
);
|
|
18
|
+
createdFieldNames.add(def.fieldName);
|
|
19
|
+
}
|
|
20
|
+
} catch (err) {
|
|
21
|
+
console.warn(
|
|
22
|
+
`Failed to write form field "${def.fieldName}" (${def.fieldType}, origin=${def.origin ?? "parsed"}):`,
|
|
23
|
+
err
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
2
27
|
const form = pdfDoc.getForm();
|
|
3
28
|
for (const field of fieldValues) {
|
|
29
|
+
if (createdFieldNames.has(field.fieldName)) continue;
|
|
4
30
|
try {
|
|
5
31
|
switch (field.fieldType) {
|
|
6
32
|
case "text": {
|
|
@@ -50,6 +76,224 @@ export async function writeFormFieldsToPdf(pdfDoc, fieldValues) {
|
|
|
50
76
|
}
|
|
51
77
|
}
|
|
52
78
|
}
|
|
79
|
+
function applyCheckboxStyle(pdfDoc, cb, def) {
|
|
80
|
+
const style = def.checkboxStyle;
|
|
81
|
+
if (!style) return;
|
|
82
|
+
const caption = CHECKBOX_STYLE_TABLE[style]?.caption;
|
|
83
|
+
if (!caption) return;
|
|
84
|
+
const widgets = cb.acroField.getWidgets();
|
|
85
|
+
for (const widget of widgets) {
|
|
86
|
+
let mk = widget.dict.get(PDFName.of("MK"));
|
|
87
|
+
if (!(mk instanceof PDFDict)) {
|
|
88
|
+
mk = pdfDoc.context.obj({});
|
|
89
|
+
widget.dict.set(PDFName.of("MK"), mk);
|
|
90
|
+
}
|
|
91
|
+
mk.set(PDFName.of("CA"), PDFString.of(caption));
|
|
92
|
+
}
|
|
93
|
+
const form = pdfDoc.getForm();
|
|
94
|
+
form.acroForm.dict.set(PDFName.of("NeedAppearances"), PDFBool.True);
|
|
95
|
+
}
|
|
96
|
+
function updateParsedField(pdfDoc, def) {
|
|
97
|
+
const form = pdfDoc.getForm();
|
|
98
|
+
let field;
|
|
99
|
+
try {
|
|
100
|
+
field = form.getField(def.fieldName);
|
|
101
|
+
} catch {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const widgets = field.acroField.getWidgets();
|
|
105
|
+
if (widgets.length === 0) return;
|
|
106
|
+
const target = def.originalRect ? pickWidgetByRect(widgets, def.originalRect) : widgets[0];
|
|
107
|
+
if (!target) return;
|
|
108
|
+
if (def.originalRect && !rectsEqual(def.rect, def.originalRect)) {
|
|
109
|
+
const [x1, y1, x2, y2] = def.rect;
|
|
110
|
+
target.setRectangle({
|
|
111
|
+
x: x1,
|
|
112
|
+
y: y1,
|
|
113
|
+
width: Math.max(1, x2 - x1),
|
|
114
|
+
height: Math.max(1, y2 - y1)
|
|
115
|
+
});
|
|
116
|
+
if (def.fieldType === "text" && def.comb) {
|
|
117
|
+
form.acroForm.dict.set(PDFName.of("NeedAppearances"), PDFBool.True);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (def.fieldType === "checkbox" && (def.checkboxStyle ?? "check") !== (def.originalCheckboxStyle ?? "check")) {
|
|
121
|
+
const caption = CHECKBOX_STYLE_TABLE[def.checkboxStyle ?? "check"]?.caption;
|
|
122
|
+
if (caption) {
|
|
123
|
+
for (const widget of widgets) {
|
|
124
|
+
let mk = widget.dict.get(PDFName.of("MK"));
|
|
125
|
+
if (!(mk instanceof PDFDict)) {
|
|
126
|
+
mk = pdfDoc.context.obj({});
|
|
127
|
+
widget.dict.set(PDFName.of("MK"), mk);
|
|
128
|
+
}
|
|
129
|
+
mk.set(PDFName.of("CA"), PDFString.of(caption));
|
|
130
|
+
}
|
|
131
|
+
form.acroForm.dict.set(PDFName.of("NeedAppearances"), PDFBool.True);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function rectsEqual(a, b) {
|
|
136
|
+
for (let i = 0; i < 4; i++) {
|
|
137
|
+
if (Math.abs((a[i] ?? 0) - (b[i] ?? 0)) > 0.01) return false;
|
|
138
|
+
}
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
function pickWidgetByRect(widgets, expected) {
|
|
142
|
+
const [ex1, ey1, ex2, ey2] = expected;
|
|
143
|
+
const ew = ex2 - ex1;
|
|
144
|
+
const eh = ey2 - ey1;
|
|
145
|
+
const tolerance = 0.5;
|
|
146
|
+
for (const w of widgets) {
|
|
147
|
+
const r = w.getRectangle();
|
|
148
|
+
if (Math.abs(r.x - ex1) <= tolerance && Math.abs(r.y - ey1) <= tolerance && Math.abs(r.width - ew) <= tolerance && Math.abs(r.height - eh) <= tolerance) return w;
|
|
149
|
+
}
|
|
150
|
+
return void 0;
|
|
151
|
+
}
|
|
152
|
+
async function createWidgetForDefinition(pdfDoc, def, fv, radioGroupCache) {
|
|
153
|
+
const form = pdfDoc.getForm();
|
|
154
|
+
const pageIndex = def.pageNumber - 1;
|
|
155
|
+
const pages = pdfDoc.getPages();
|
|
156
|
+
const page = pages[pageIndex];
|
|
157
|
+
if (!page) return;
|
|
158
|
+
const [x1, y1, x2, y2] = def.rect;
|
|
159
|
+
const box = {
|
|
160
|
+
x: x1,
|
|
161
|
+
y: y1,
|
|
162
|
+
width: Math.max(1, x2 - x1),
|
|
163
|
+
height: Math.max(1, y2 - y1)
|
|
164
|
+
};
|
|
165
|
+
switch (def.fieldType) {
|
|
166
|
+
case "text": {
|
|
167
|
+
const tf = form.createTextField(def.fieldName);
|
|
168
|
+
if (def.maxLen && def.maxLen > 0) tf.setMaxLength(def.maxLen);
|
|
169
|
+
if (def.multiLine) tf.enableMultiline();
|
|
170
|
+
const v = fv?.value;
|
|
171
|
+
if (typeof v === "string" && v !== "") tf.setText(v);
|
|
172
|
+
tf.addToPage(page, box);
|
|
173
|
+
applyFlags(tf, def);
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
case "checkbox": {
|
|
177
|
+
const cb = form.createCheckBox(def.fieldName);
|
|
178
|
+
cb.addToPage(page, box);
|
|
179
|
+
if (fv?.value === true) cb.check();
|
|
180
|
+
applyFlags(cb, def);
|
|
181
|
+
applyCheckboxStyle(pdfDoc, cb, def);
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
case "radio": {
|
|
185
|
+
let group = radioGroupCache.get(def.fieldName);
|
|
186
|
+
if (!group) {
|
|
187
|
+
try {
|
|
188
|
+
group = form.getRadioGroup(def.fieldName);
|
|
189
|
+
} catch {
|
|
190
|
+
group = form.createRadioGroup(def.fieldName);
|
|
191
|
+
}
|
|
192
|
+
radioGroupCache.set(def.fieldName, group);
|
|
193
|
+
}
|
|
194
|
+
const existingOptions = new Set(group.getOptions());
|
|
195
|
+
let optionValue = def.buttonValue || `Option_${existingOptions.size + 1}`;
|
|
196
|
+
if (existingOptions.has(optionValue)) {
|
|
197
|
+
let n = existingOptions.size + 1;
|
|
198
|
+
while (existingOptions.has(`Option_${n}`)) n += 1;
|
|
199
|
+
optionValue = `Option_${n}`;
|
|
200
|
+
}
|
|
201
|
+
group.addOptionToPage(optionValue, page, box);
|
|
202
|
+
if (typeof fv?.value === "string" && fv.value === optionValue) {
|
|
203
|
+
group.select(optionValue);
|
|
204
|
+
}
|
|
205
|
+
applyFlags(group, def);
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
case "signature": {
|
|
209
|
+
const v = fv?.value;
|
|
210
|
+
const signed = typeof v === "string" && v.startsWith("data:image");
|
|
211
|
+
if (signed) {
|
|
212
|
+
await drawSignatureImage(pdfDoc, page, v, box);
|
|
213
|
+
} else {
|
|
214
|
+
await drawSignaturePlaceholder(pdfDoc, page, box);
|
|
215
|
+
}
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
case "dropdown": {
|
|
219
|
+
const labels = (def.options ?? []).map((o) => o.displayValue);
|
|
220
|
+
if (def.combo === false) {
|
|
221
|
+
const list = form.createOptionList(def.fieldName);
|
|
222
|
+
if (labels.length > 0) list.setOptions(labels);
|
|
223
|
+
list.addToPage(page, box);
|
|
224
|
+
if (def.multiSelect) list.enableMultiselect();
|
|
225
|
+
const v = fv?.value;
|
|
226
|
+
if (Array.isArray(v) && v.length > 0) list.select(v);
|
|
227
|
+
else if (typeof v === "string" && v) list.select(v);
|
|
228
|
+
applyFlags(list, def);
|
|
229
|
+
} else {
|
|
230
|
+
const dd = form.createDropdown(def.fieldName);
|
|
231
|
+
if (labels.length > 0) dd.setOptions(labels);
|
|
232
|
+
dd.addToPage(page, box);
|
|
233
|
+
if (def.editable) dd.enableEditing();
|
|
234
|
+
const v = fv?.value;
|
|
235
|
+
if (typeof v === "string" && v) dd.select(v);
|
|
236
|
+
else if (Array.isArray(v) && v[0]) dd.select(v[0]);
|
|
237
|
+
applyFlags(dd, def);
|
|
238
|
+
}
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
function applyFlags(field, def) {
|
|
244
|
+
if (def.readOnly) field.enableReadOnly();
|
|
245
|
+
if (def.required) field.enableRequired();
|
|
246
|
+
}
|
|
247
|
+
async function drawSignatureImage(pdfDoc, page, dataUrl, box) {
|
|
248
|
+
const match = dataUrl.match(/^data:(image\/[a-zA-Z0-9.+-]+);base64,(.+)$/);
|
|
249
|
+
if (!match) return;
|
|
250
|
+
const mimeType = match[1] ?? "";
|
|
251
|
+
const base64 = match[2] ?? "";
|
|
252
|
+
let image;
|
|
253
|
+
if (mimeType.includes("jpeg") || mimeType.includes("jpg")) {
|
|
254
|
+
image = await pdfDoc.embedJpg(base64);
|
|
255
|
+
} else {
|
|
256
|
+
image = await pdfDoc.embedPng(base64);
|
|
257
|
+
}
|
|
258
|
+
const imgAspect = image.width / image.height;
|
|
259
|
+
const boxAspect = box.width / box.height;
|
|
260
|
+
let drawW = box.width;
|
|
261
|
+
let drawH = box.height;
|
|
262
|
+
if (imgAspect > boxAspect) {
|
|
263
|
+
drawH = box.width / imgAspect;
|
|
264
|
+
} else {
|
|
265
|
+
drawW = box.height * imgAspect;
|
|
266
|
+
}
|
|
267
|
+
const drawX = box.x + (box.width - drawW) / 2;
|
|
268
|
+
const drawY = box.y + (box.height - drawH) / 2;
|
|
269
|
+
page.drawImage(image, { x: drawX, y: drawY, width: drawW, height: drawH });
|
|
270
|
+
}
|
|
271
|
+
async function drawSignaturePlaceholder(pdfDoc, page, box) {
|
|
272
|
+
page.drawRectangle({
|
|
273
|
+
x: box.x,
|
|
274
|
+
y: box.y,
|
|
275
|
+
width: box.width,
|
|
276
|
+
height: box.height,
|
|
277
|
+
borderColor: rgb(0.55, 0.55, 0.55),
|
|
278
|
+
borderWidth: 0.75,
|
|
279
|
+
borderDashArray: [3, 2]
|
|
280
|
+
});
|
|
281
|
+
try {
|
|
282
|
+
const font = await pdfDoc.embedFont(StandardFonts.Helvetica);
|
|
283
|
+
const label = "Sign here";
|
|
284
|
+
const fontSize = Math.max(6, Math.min(12, box.height * 0.4));
|
|
285
|
+
const textWidth = font.widthOfTextAtSize(label, fontSize);
|
|
286
|
+
const textHeight = font.heightAtSize(fontSize);
|
|
287
|
+
page.drawText(label, {
|
|
288
|
+
x: box.x + (box.width - textWidth) / 2,
|
|
289
|
+
y: box.y + (box.height - textHeight) / 2,
|
|
290
|
+
size: fontSize,
|
|
291
|
+
font,
|
|
292
|
+
color: rgb(0.55, 0.55, 0.55)
|
|
293
|
+
});
|
|
294
|
+
} catch {
|
|
295
|
+
}
|
|
296
|
+
}
|
|
53
297
|
async function embedSignatureImage(pdfDoc, field) {
|
|
54
298
|
const dataUrl = field.value;
|
|
55
299
|
const match = dataUrl.match(/^data:(image\/[a-zA-Z0-9.+-]+);base64,(.+)$/);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type IAnnotationStore, type FormFieldValue } from '../engine/types.js';
|
|
1
|
+
import { type IAnnotationStore, type FormFieldDefinition, type FormFieldValue } from '../engine/types.js';
|
|
2
2
|
export interface ExportPdfOptions {
|
|
3
3
|
flatten?: boolean;
|
|
4
4
|
download?: boolean;
|
|
@@ -10,9 +10,10 @@ interface ExportPdfParams {
|
|
|
10
10
|
annotations: IAnnotationStore[];
|
|
11
11
|
options?: ExportPdfOptions;
|
|
12
12
|
formFieldValues?: FormFieldValue[];
|
|
13
|
+
placedFormFieldDefinitions?: FormFieldDefinition[];
|
|
13
14
|
originalAnnotationIds?: Set<string>;
|
|
14
15
|
modifiedAnnotationIds?: Set<string>;
|
|
15
16
|
deletedAnnotationIds?: Set<string>;
|
|
16
17
|
}
|
|
17
|
-
export declare function exportAnnotationsToPdf({ pdfData, annotations, options, formFieldValues, originalAnnotationIds, modifiedAnnotationIds, deletedAnnotationIds, }: ExportPdfParams): Promise<Uint8Array>;
|
|
18
|
+
export declare function exportAnnotationsToPdf({ pdfData, annotations, options, formFieldValues, placedFormFieldDefinitions, originalAnnotationIds, modifiedAnnotationIds, deletedAnnotationIds, }: ExportPdfParams): Promise<Uint8Array>;
|
|
18
19
|
export {};
|
|
@@ -198,6 +198,7 @@ export async function exportAnnotationsToPdf({
|
|
|
198
198
|
annotations,
|
|
199
199
|
options,
|
|
200
200
|
formFieldValues,
|
|
201
|
+
placedFormFieldDefinitions,
|
|
201
202
|
originalAnnotationIds,
|
|
202
203
|
modifiedAnnotationIds,
|
|
203
204
|
deletedAnnotationIds
|
|
@@ -205,8 +206,14 @@ export async function exportAnnotationsToPdf({
|
|
|
205
206
|
const flatten = options?.flatten ?? false;
|
|
206
207
|
const preserveOriginalAnnotations = options?.preserveOriginalAnnotations ?? false;
|
|
207
208
|
const pdfDoc = await PDFDocument.load(toUint8Array(pdfData));
|
|
208
|
-
|
|
209
|
-
|
|
209
|
+
const hasValues = formFieldValues && formFieldValues.length > 0;
|
|
210
|
+
const hasPlaced = placedFormFieldDefinitions && placedFormFieldDefinitions.length > 0;
|
|
211
|
+
if (hasValues || hasPlaced) {
|
|
212
|
+
await writeFormFieldsToPdf(
|
|
213
|
+
pdfDoc,
|
|
214
|
+
formFieldValues ?? [],
|
|
215
|
+
placedFormFieldDefinitions ?? []
|
|
216
|
+
);
|
|
210
217
|
}
|
|
211
218
|
let annotationsToWrite = annotations;
|
|
212
219
|
if (!preserveOriginalAnnotations) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
.kviewer-text-layer{left:0;line-height:1;overflow:hidden;position:absolute;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none;z-index:1}.kviewer-text-layer--interactive{cursor:text;-webkit-user-select:text;-moz-user-select:text;user-select:text}.KViewer_is_painting.KViewer_painting_type_12 .kviewer-annotation-layer,.KViewer_is_painting.KViewer_painting_type_12 .kviewer-annotation-layer *,.KViewer_is_painting.KViewer_painting_type_13 .kviewer-annotation-layer,.KViewer_is_painting.KViewer_painting_type_13 .kviewer-annotation-layer *,.KViewer_is_painting.KViewer_painting_type_5 .kviewer-annotation-layer,.KViewer_is_painting.KViewer_painting_type_5 .kviewer-annotation-layer *,.KViewer_is_painting.KViewer_painting_type_6 .kviewer-annotation-layer,.KViewer_is_painting.KViewer_painting_type_6 .kviewer-annotation-layer *,.KViewer_is_painting.KViewer_painting_type_7 .kviewer-annotation-layer,.KViewer_is_painting.KViewer_painting_type_7 .kviewer-annotation-layer *,.KViewer_is_painting.KViewer_painting_type_8 .kviewer-annotation-layer,.KViewer_is_painting.KViewer_painting_type_8 .kviewer-annotation-layer *{cursor:crosshair!important}.KViewer_is_painting.KViewer_painting_type_4 .kviewer-annotation-layer,.KViewer_is_painting.KViewer_painting_type_4 .kviewer-annotation-layer *{cursor:text!important}.KViewer_is_painting.KViewer_painting_type_11 .kviewer-annotation-layer,.KViewer_is_painting.KViewer_painting_type_11 .kviewer-annotation-layer *{cursor:crosshair!important}.KViewer_selector_hover{cursor:pointer!important}.kviewer-form-layer{left:0;overflow:hidden;position:absolute;top:0}.kviewer-form-field{box-sizing:border-box;position:absolute}.kviewer-form-input{background-color:rgba(224,232,255,.6);border:1px solid transparent;box-sizing:border-box;color:#000;font-family:
|
|
1
|
+
.kviewer-text-layer{left:0;line-height:1;overflow:hidden;position:absolute;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none;z-index:1}.kviewer-text-layer--interactive{cursor:text;-webkit-user-select:text;-moz-user-select:text;user-select:text}.KViewer_is_painting.KViewer_painting_type_12 .kviewer-annotation-layer,.KViewer_is_painting.KViewer_painting_type_12 .kviewer-annotation-layer *,.KViewer_is_painting.KViewer_painting_type_13 .kviewer-annotation-layer,.KViewer_is_painting.KViewer_painting_type_13 .kviewer-annotation-layer *,.KViewer_is_painting.KViewer_painting_type_5 .kviewer-annotation-layer,.KViewer_is_painting.KViewer_painting_type_5 .kviewer-annotation-layer *,.KViewer_is_painting.KViewer_painting_type_6 .kviewer-annotation-layer,.KViewer_is_painting.KViewer_painting_type_6 .kviewer-annotation-layer *,.KViewer_is_painting.KViewer_painting_type_7 .kviewer-annotation-layer,.KViewer_is_painting.KViewer_painting_type_7 .kviewer-annotation-layer *,.KViewer_is_painting.KViewer_painting_type_8 .kviewer-annotation-layer,.KViewer_is_painting.KViewer_painting_type_8 .kviewer-annotation-layer *{cursor:crosshair!important}.KViewer_is_painting.KViewer_painting_type_4 .kviewer-annotation-layer,.KViewer_is_painting.KViewer_painting_type_4 .kviewer-annotation-layer *{cursor:text!important}.KViewer_is_painting.KViewer_painting_type_11 .kviewer-annotation-layer,.KViewer_is_painting.KViewer_painting_type_11 .kviewer-annotation-layer *{cursor:crosshair!important}.KViewer_selector_hover{cursor:pointer!important}.kviewer-form-layer{left:0;overflow:hidden;position:absolute;top:0}.kviewer-form-field{box-sizing:border-box;position:absolute}.kviewer-form-input{background-color:rgba(224,232,255,.6);border:1px solid transparent;box-sizing:border-box;color:#000;display:block;font-family:-apple-system,BlinkMacSystemFont,Helvetica Neue,Helvetica,Arial,sans-serif;font-weight:500;height:100%;line-height:normal;margin:0;outline:none;padding:1px 2px;resize:none;width:100%;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizeLegibility;vertical-align:top}.kviewer-form-input:hover{background-color:rgba(224,232,255,.8);border-color:rgba(0,0,0,.2)}.kviewer-form-input:focus{background-color:rgba(224,232,255,.9);border-color:var(--color-primary,#3b82f6);outline:2px solid var(--color-primary,#3b82f6)}.kviewer-form-select{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto;cursor:pointer}.kviewer-form-listbox{overflow-y:auto;padding:0}.kviewer-form-listbox option{padding:1px 3px}.kviewer-form-editable-combo{height:100%;position:relative;width:100%}.kviewer-form-editable-combo input{height:100%;width:100%}.kviewer-form-checkbox,.kviewer-form-radio{align-items:center;background:#fff;box-sizing:border-box;cursor:pointer;display:flex;height:100%;justify-content:center;width:100%}.kviewer-form-checkbox input,.kviewer-form-radio input{accent-color:var(--color-primary,#3b82f6);cursor:pointer;height:80%;margin:0;max-height:18px;max-width:18px;width:80%}.kviewer-form-checkbox--detected{background:transparent}.kviewer-form-checkbox--circle{border-radius:50%}.kviewer-form-checkbox__icon{color:#1a1a1a;height:65%;width:65%}.kviewer-form-checkbox--circle .kviewer-form-checkbox__icon{height:50%;width:50%}.kviewer-form-radio input{accent-color:var(--color-primary,#3b82f6);cursor:pointer;height:80%;margin:0;max-height:18px;max-width:18px;width:80%}.kviewer-form-button{align-items:center;background:#c8c8c8;border:1px solid rgba(0,0,0,.35);box-sizing:border-box;color:#000;cursor:pointer;display:flex;font-family:inherit;font-weight:700;height:100%;justify-content:center;line-height:1;padding:0 6px;text-align:center;width:100%;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.kviewer-form-button:hover{background:#bdbdbd}.kviewer-form-button:active{background:#b0b0b0}.kviewer-form-signature{align-items:center;background:rgba(255,255,200,.15);border:1px dashed rgba(0,0,0,.2);cursor:pointer;display:flex;height:100%;justify-content:center;width:100%}.kviewer-form-signature:hover{background:rgba(59,130,246,.08);border-color:var(--color-primary,#3b82f6)}.kviewer-form-signature--filled{background:transparent;border-color:transparent;border-style:solid}.kviewer-form-signature__preview{max-height:100%;max-width:100%;-o-object-fit:contain;object-fit:contain}.kviewer-form-signature__placeholder{color:rgba(0,0,0,.4);font-size:10px;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}
|
|
@@ -5,6 +5,11 @@ type __VLS_Props = {
|
|
|
5
5
|
pageHeight: number;
|
|
6
6
|
pointerEvents: string;
|
|
7
7
|
zIndex: number;
|
|
8
|
+
/** PDF user-space origin offsets (`view[0]`, `view[1]`). Forwarded to
|
|
9
|
+
* FormFieldWrapper so /Rect coordinates can be mapped to canvas space
|
|
10
|
+
* when the page's MediaBox is not at (0, 0). */
|
|
11
|
+
viewOffsetX?: number;
|
|
12
|
+
viewOffsetY?: number;
|
|
8
13
|
};
|
|
9
14
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
10
15
|
declare const _default: typeof __VLS_export;
|
|
@@ -11,7 +11,11 @@
|
|
|
11
11
|
transform: `scale(${props.scale})`,
|
|
12
12
|
transformOrigin: '0 0',
|
|
13
13
|
zIndex: props.zIndex,
|
|
14
|
-
pointerEvents: props.pointerEvents
|
|
14
|
+
pointerEvents: props.pointerEvents,
|
|
15
|
+
// Force native form controls (inputs, checkboxes, radios, scrollbars)
|
|
16
|
+
// to render in light mode regardless of the user\'s OS theme — PDF
|
|
17
|
+
// pages have a white background, so dark-mode controls clash.
|
|
18
|
+
colorScheme: 'light'
|
|
15
19
|
}"
|
|
16
20
|
>
|
|
17
21
|
<FormFieldWrapper
|
|
@@ -19,13 +23,20 @@
|
|
|
19
23
|
:key="field.id"
|
|
20
24
|
:field="field"
|
|
21
25
|
:page-height="props.pageHeight"
|
|
26
|
+
:scale="props.scale"
|
|
27
|
+
:view-offset-x="props.viewOffsetX ?? 0"
|
|
28
|
+
:view-offset-y="props.viewOffsetY ?? 0"
|
|
29
|
+
:selected="selectedFieldId === field.id"
|
|
30
|
+
@select="formFields.selectPlacedField(field.id)"
|
|
22
31
|
/>
|
|
23
32
|
</div>
|
|
24
33
|
</template>
|
|
25
34
|
|
|
26
35
|
<script setup>
|
|
27
|
-
import { computed } from "vue";
|
|
36
|
+
import { computed, onMounted, onBeforeUnmount, watch } from "vue";
|
|
28
37
|
import { useFormFields } from "../composables/useFormFields";
|
|
38
|
+
import { useViewerState } from "../composables/useViewerState";
|
|
39
|
+
import { AnnotationType } from "../annotation/engine/types";
|
|
29
40
|
import FormFieldWrapper from "./form-fields/FormFieldWrapper.vue";
|
|
30
41
|
const props = defineProps({
|
|
31
42
|
pageNumber: { type: Number, required: true },
|
|
@@ -33,8 +44,34 @@ const props = defineProps({
|
|
|
33
44
|
pageWidth: { type: Number, required: true },
|
|
34
45
|
pageHeight: { type: Number, required: true },
|
|
35
46
|
pointerEvents: { type: String, required: true },
|
|
36
|
-
zIndex: { type: Number, required: true }
|
|
47
|
+
zIndex: { type: Number, required: true },
|
|
48
|
+
viewOffsetX: { type: Number, required: false },
|
|
49
|
+
viewOffsetY: { type: Number, required: false }
|
|
37
50
|
});
|
|
38
51
|
const formFields = useFormFields();
|
|
52
|
+
const state = useViewerState();
|
|
39
53
|
const fields = computed(() => formFields.getFieldsForPage(props.pageNumber));
|
|
54
|
+
const selectedFieldId = formFields.selectedPlacedFieldId;
|
|
55
|
+
watch(() => state.formEditMode.value, (enabled) => {
|
|
56
|
+
if (!enabled) formFields.selectPlacedField(null);
|
|
57
|
+
});
|
|
58
|
+
watch(() => state.activeTool.value, (tool) => {
|
|
59
|
+
const isFormFieldTool = typeof tool === "number" && (tool === AnnotationType.FORM_TEXT || tool === AnnotationType.FORM_CHECKBOX || tool === AnnotationType.FORM_RADIO || tool === AnnotationType.FORM_SIGNATURE);
|
|
60
|
+
if (tool !== "hand" && !isFormFieldTool) formFields.selectPlacedField(null);
|
|
61
|
+
});
|
|
62
|
+
function onKeyDown(e) {
|
|
63
|
+
if (!selectedFieldId.value) return;
|
|
64
|
+
if (e.key !== "Delete" && e.key !== "Backspace") return;
|
|
65
|
+
const target = e.target;
|
|
66
|
+
const tag = target?.tagName.toLowerCase();
|
|
67
|
+
if (tag === "input" || tag === "textarea" || target?.isContentEditable) return;
|
|
68
|
+
const id = selectedFieldId.value;
|
|
69
|
+
formFields.removePlacedField(id);
|
|
70
|
+
}
|
|
71
|
+
onMounted(() => {
|
|
72
|
+
window.addEventListener("keydown", onKeyDown);
|
|
73
|
+
});
|
|
74
|
+
onBeforeUnmount(() => {
|
|
75
|
+
window.removeEventListener("keydown", onKeyDown);
|
|
76
|
+
});
|
|
40
77
|
</script>
|
|
@@ -5,6 +5,11 @@ type __VLS_Props = {
|
|
|
5
5
|
pageHeight: number;
|
|
6
6
|
pointerEvents: string;
|
|
7
7
|
zIndex: number;
|
|
8
|
+
/** PDF user-space origin offsets (`view[0]`, `view[1]`). Forwarded to
|
|
9
|
+
* FormFieldWrapper so /Rect coordinates can be mapped to canvas space
|
|
10
|
+
* when the page's MediaBox is not at (0, 0). */
|
|
11
|
+
viewOffsetX?: number;
|
|
12
|
+
viewOffsetY?: number;
|
|
8
13
|
};
|
|
9
14
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
10
15
|
declare const _default: typeof __VLS_export;
|
|
@@ -3,7 +3,12 @@ type __VLS_Props = {
|
|
|
3
3
|
pageNumber: number;
|
|
4
4
|
pageMeta: PageMeta;
|
|
5
5
|
scale: number;
|
|
6
|
+
/** Canvas internal resolution multiplier (CSS size unchanged).
|
|
7
|
+
* Used by panzoom to sharpen the PDF when visually zoomed in. */
|
|
8
|
+
renderQuality?: number;
|
|
6
9
|
};
|
|
7
|
-
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
10
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
11
|
+
renderQuality: number;
|
|
12
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
8
13
|
declare const _default: typeof __VLS_export;
|
|
9
14
|
export default _default;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
|
-
class="kviewer-page"
|
|
3
|
+
class="kviewer-page shadow-lg"
|
|
4
4
|
:style="{
|
|
5
5
|
position: 'relative',
|
|
6
6
|
width: cssWidth + 'px',
|
|
@@ -31,6 +31,8 @@
|
|
|
31
31
|
:scale="props.scale"
|
|
32
32
|
:page-width="baseWidth"
|
|
33
33
|
:page-height="baseHeight"
|
|
34
|
+
:view-offset-x="viewOffsetX"
|
|
35
|
+
:view-offset-y="viewOffsetY"
|
|
34
36
|
:pointer-events="formFieldPointerEvents"
|
|
35
37
|
:z-index="formFieldZIndex"
|
|
36
38
|
/>
|
|
@@ -63,7 +65,8 @@ const PDFJS_ANNOTATION_MODE_DISABLE = 0;
|
|
|
63
65
|
const props = defineProps({
|
|
64
66
|
pageNumber: { type: Number, required: true },
|
|
65
67
|
pageMeta: { type: Object, required: true },
|
|
66
|
-
scale: { type: Number, required: true }
|
|
68
|
+
scale: { type: Number, required: true },
|
|
69
|
+
renderQuality: { type: Number, required: false, default: 1 }
|
|
67
70
|
});
|
|
68
71
|
const canvasRef = ref(null);
|
|
69
72
|
const textLayerRef = ref(null);
|
|
@@ -78,6 +81,8 @@ let currentRenderTask = null;
|
|
|
78
81
|
let textLayer = null;
|
|
79
82
|
const baseWidth = props.pageMeta.width;
|
|
80
83
|
const baseHeight = props.pageMeta.height;
|
|
84
|
+
const viewOffsetX = props.pageMeta.viewOffsetX ?? 0;
|
|
85
|
+
const viewOffsetY = props.pageMeta.viewOffsetY ?? 0;
|
|
81
86
|
const cssWidth = computed(() => baseWidth * props.scale);
|
|
82
87
|
const cssHeight = computed(() => baseHeight * props.scale);
|
|
83
88
|
const isAnnotating = computed(() => {
|
|
@@ -124,6 +129,26 @@ onMounted(async () => {
|
|
|
124
129
|
}
|
|
125
130
|
}
|
|
126
131
|
});
|
|
132
|
+
watch(
|
|
133
|
+
() => state.shapeDetection.value,
|
|
134
|
+
async (enabled) => {
|
|
135
|
+
if (!enabled || !pageProxy.value) return;
|
|
136
|
+
const viewport = pageProxy.value.getViewport({ scale: props.scale });
|
|
137
|
+
const shapes = await shapeDetection.preprocessShapesForPage(
|
|
138
|
+
props.pageNumber,
|
|
139
|
+
pageProxy.value,
|
|
140
|
+
viewport
|
|
141
|
+
);
|
|
142
|
+
if (shapes.length > 0) {
|
|
143
|
+
formFields.registerDetectedCheckboxes(
|
|
144
|
+
props.pageNumber,
|
|
145
|
+
shapes,
|
|
146
|
+
props.scale,
|
|
147
|
+
baseHeight
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
);
|
|
127
152
|
watch(
|
|
128
153
|
() => props.scale,
|
|
129
154
|
async () => {
|
|
@@ -141,7 +166,14 @@ watch(
|
|
|
141
166
|
}
|
|
142
167
|
}
|
|
143
168
|
);
|
|
144
|
-
|
|
169
|
+
watch(
|
|
170
|
+
() => props.renderQuality,
|
|
171
|
+
async () => {
|
|
172
|
+
if (!pageProxy.value) return;
|
|
173
|
+
await renderCanvas({ doubleBuffer: true });
|
|
174
|
+
}
|
|
175
|
+
);
|
|
176
|
+
async function renderCanvas(opts) {
|
|
145
177
|
const canvas = canvasRef.value;
|
|
146
178
|
const proxy = pageProxy.value;
|
|
147
179
|
if (!canvas || !proxy) return;
|
|
@@ -150,23 +182,48 @@ async function renderCanvas() {
|
|
|
150
182
|
currentRenderTask = null;
|
|
151
183
|
}
|
|
152
184
|
const dpr = window.devicePixelRatio || 1;
|
|
185
|
+
const quality = props.renderQuality ?? 1;
|
|
153
186
|
const viewport = proxy.getViewport({
|
|
154
|
-
scale: props.scale * dpr
|
|
187
|
+
scale: props.scale * quality * dpr
|
|
155
188
|
});
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
189
|
+
if (opts?.doubleBuffer) {
|
|
190
|
+
const tmp = document.createElement("canvas");
|
|
191
|
+
tmp.width = viewport.width;
|
|
192
|
+
tmp.height = viewport.height;
|
|
193
|
+
try {
|
|
194
|
+
currentRenderTask = proxy.render({
|
|
195
|
+
canvasContext: tmp.getContext("2d"),
|
|
196
|
+
viewport,
|
|
197
|
+
annotationMode: PDFJS_ANNOTATION_MODE_DISABLE
|
|
198
|
+
});
|
|
199
|
+
await currentRenderTask.promise;
|
|
200
|
+
canvas.width = viewport.width;
|
|
201
|
+
canvas.height = viewport.height;
|
|
202
|
+
canvas.getContext("2d").drawImage(tmp, 0, 0);
|
|
203
|
+
} catch (e) {
|
|
204
|
+
if (e instanceof Error && e.message?.includes("Rendering cancelled")) return;
|
|
205
|
+
throw e;
|
|
206
|
+
} finally {
|
|
207
|
+
currentRenderTask = null;
|
|
208
|
+
tmp.width = 0;
|
|
209
|
+
tmp.height = 0;
|
|
210
|
+
}
|
|
211
|
+
} else {
|
|
212
|
+
canvas.width = viewport.width;
|
|
213
|
+
canvas.height = viewport.height;
|
|
214
|
+
try {
|
|
215
|
+
currentRenderTask = proxy.render({
|
|
216
|
+
canvasContext: canvas.getContext("2d"),
|
|
217
|
+
viewport,
|
|
218
|
+
annotationMode: PDFJS_ANNOTATION_MODE_DISABLE
|
|
219
|
+
});
|
|
220
|
+
await currentRenderTask.promise;
|
|
221
|
+
} catch (e) {
|
|
222
|
+
if (e instanceof Error && e.message?.includes("Rendering cancelled")) return;
|
|
223
|
+
throw e;
|
|
224
|
+
} finally {
|
|
225
|
+
currentRenderTask = null;
|
|
226
|
+
}
|
|
170
227
|
}
|
|
171
228
|
}
|
|
172
229
|
function initKonva() {
|
|
@@ -3,7 +3,12 @@ type __VLS_Props = {
|
|
|
3
3
|
pageNumber: number;
|
|
4
4
|
pageMeta: PageMeta;
|
|
5
5
|
scale: number;
|
|
6
|
+
/** Canvas internal resolution multiplier (CSS size unchanged).
|
|
7
|
+
* Used by panzoom to sharpen the PDF when visually zoomed in. */
|
|
8
|
+
renderQuality?: number;
|
|
6
9
|
};
|
|
7
|
-
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
10
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
11
|
+
renderQuality: number;
|
|
12
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
8
13
|
declare const _default: typeof __VLS_export;
|
|
9
14
|
export default _default;
|
|
@@ -17,6 +17,10 @@ type __VLS_Props = {
|
|
|
17
17
|
active?: boolean;
|
|
18
18
|
/** Delay in ms before consecutive freehand strokes are finalized as a single annotation. Set to 0 to disable grouping. Default: 1000. */
|
|
19
19
|
freehandGroupingDelay?: number;
|
|
20
|
+
/** Whether the viewer is in form-edit mode: every form field renders
|
|
21
|
+
* with selection chrome, can be moved/resized, and the property panel
|
|
22
|
+
* is shown. Supports v-model via `v-model:form-edit-mode`. */
|
|
23
|
+
formEditMode?: boolean;
|
|
20
24
|
};
|
|
21
25
|
declare function exportPdf(options?: ExportPdfOptions): Promise<Uint8Array>;
|
|
22
26
|
type ImportMode = 'replace' | 'merge';
|
|
@@ -27,11 +31,11 @@ declare function importAnnotations(annotations: IAnnotationStore[], options?: {
|
|
|
27
31
|
skipped: number;
|
|
28
32
|
}>;
|
|
29
33
|
declare function getKonvaCanvasState(): Record<number, string>;
|
|
30
|
-
declare var __VLS_1: {},
|
|
34
|
+
declare var __VLS_1: {}, __VLS_51: {};
|
|
31
35
|
type __VLS_Slots = {} & {
|
|
32
36
|
header?: (props: typeof __VLS_1) => any;
|
|
33
37
|
} & {
|
|
34
|
-
footer?: (props: typeof
|
|
38
|
+
footer?: (props: typeof __VLS_51) => any;
|
|
35
39
|
};
|
|
36
40
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
|
|
37
41
|
getAnnotations: () => IAnnotationStore[];
|
|
@@ -40,7 +44,17 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
|
|
|
40
44
|
getKonvaCanvasState: typeof getKonvaCanvasState;
|
|
41
45
|
getFormFieldValues: () => import("../annotation/engine/types.js").FormFieldValue[];
|
|
42
46
|
setFormFieldValue: (fieldName: string, value: string | boolean | string[]) => void;
|
|
43
|
-
|
|
47
|
+
/** Reactive form-edit-mode flag — read with `.value`. */
|
|
48
|
+
formEditMode: import("vue").Ref<boolean, boolean>;
|
|
49
|
+
/** Programmatically enter or leave form-edit mode. */
|
|
50
|
+
setFormEditMode: (enabled: boolean) => void;
|
|
51
|
+
/** Flip form-edit mode. Returns the new state. */
|
|
52
|
+
toggleFormEditMode: () => boolean;
|
|
53
|
+
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
54
|
+
"update:formEditMode": (value: boolean) => any;
|
|
55
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
56
|
+
"onUpdate:formEditMode"?: ((value: boolean) => any) | undefined;
|
|
57
|
+
}>, {
|
|
44
58
|
userName: string;
|
|
45
59
|
freehandGroupingDelay: number;
|
|
46
60
|
zoom: number;
|
|
@@ -50,6 +64,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
|
|
|
50
64
|
signatureHandlers: SignatureHandlers;
|
|
51
65
|
viewMode: ViewMode;
|
|
52
66
|
shapeDetection: boolean;
|
|
67
|
+
formEditMode: boolean;
|
|
53
68
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
54
69
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
55
70
|
declare const _default: typeof __VLS_export;
|