kviewer 0.0.10 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -0
- package/dist/module.d.mts +9 -1
- package/dist/module.json +1 -1
- package/dist/module.mjs +25 -1
- 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/painter.d.ts +12 -2
- package/dist/runtime/annotation/engine/painter.js +36 -6
- package/dist/runtime/annotation/engine/tools/form-field.d.ts +30 -0
- package/dist/runtime/annotation/engine/tools/form-field.js +119 -0
- package/dist/runtime/annotation/engine/types.d.ts +118 -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 +295 -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.vue +30 -1
- package/dist/runtime/components/Viewer.d.vue.ts +43 -4
- package/dist/runtime/components/Viewer.vue +106 -7
- package/dist/runtime/components/Viewer.vue.d.ts +43 -4
- package/dist/runtime/components/ViewerBar.vue +24 -2
- package/dist/runtime/components/ViewerTabs.d.vue.ts +15 -6
- package/dist/runtime/components/ViewerTabs.vue +7 -2
- package/dist/runtime/components/ViewerTabs.vue.d.ts +15 -6
- 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 +53 -10
- 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/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/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 +3 -1
- package/dist/runtime/composables/useFormFields.d.ts +48 -2
- package/dist/runtime/composables/useFormFields.js +338 -6
- package/dist/runtime/composables/useInertiaPanzoom.js +4 -0
- package/dist/runtime/composables/usePageVirtualization.d.ts +6 -0
- package/dist/runtime/composables/usePageVirtualization.js +11 -3
- package/dist/runtime/composables/useViewerState.d.ts +3 -0
- package/dist/runtime/composables/useViewerState.js +22 -1
- package/dist/runtime/public-types.d.ts +1 -1
- package/dist/types.d.mts +1 -1
- package/package.json +2 -2
|
@@ -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;
|
|
@@ -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
|
/>
|
|
@@ -52,6 +54,7 @@
|
|
|
52
54
|
|
|
53
55
|
<script setup>
|
|
54
56
|
import { ref, shallowRef, computed, onMounted, onBeforeUnmount, watch } from "vue";
|
|
57
|
+
import { useRuntimeConfig } from "#imports";
|
|
55
58
|
import { useViewerState } from "../composables/useViewerState";
|
|
56
59
|
import { useViewerSearch } from "../composables/useViewerSearch";
|
|
57
60
|
import { usePageProxyCache } from "../composables/usePageProxyCache";
|
|
@@ -69,6 +72,10 @@ const props = defineProps({
|
|
|
69
72
|
const canvasRef = ref(null);
|
|
70
73
|
const textLayerRef = ref(null);
|
|
71
74
|
const annotationRef = ref(null);
|
|
75
|
+
const runtimeConfig = useRuntimeConfig();
|
|
76
|
+
const minRenderPixelRatio = Number(
|
|
77
|
+
runtimeConfig.public.kviewer?.minRenderPixelRatio ?? 2
|
|
78
|
+
);
|
|
72
79
|
const state = useViewerState();
|
|
73
80
|
const search = useViewerSearch();
|
|
74
81
|
const proxyCache = usePageProxyCache();
|
|
@@ -79,6 +86,8 @@ let currentRenderTask = null;
|
|
|
79
86
|
let textLayer = null;
|
|
80
87
|
const baseWidth = props.pageMeta.width;
|
|
81
88
|
const baseHeight = props.pageMeta.height;
|
|
89
|
+
const viewOffsetX = props.pageMeta.viewOffsetX ?? 0;
|
|
90
|
+
const viewOffsetY = props.pageMeta.viewOffsetY ?? 0;
|
|
82
91
|
const cssWidth = computed(() => baseWidth * props.scale);
|
|
83
92
|
const cssHeight = computed(() => baseHeight * props.scale);
|
|
84
93
|
const isAnnotating = computed(() => {
|
|
@@ -125,6 +134,26 @@ onMounted(async () => {
|
|
|
125
134
|
}
|
|
126
135
|
}
|
|
127
136
|
});
|
|
137
|
+
watch(
|
|
138
|
+
() => state.shapeDetection.value,
|
|
139
|
+
async (enabled) => {
|
|
140
|
+
if (!enabled || !pageProxy.value) return;
|
|
141
|
+
const viewport = pageProxy.value.getViewport({ scale: props.scale });
|
|
142
|
+
const shapes = await shapeDetection.preprocessShapesForPage(
|
|
143
|
+
props.pageNumber,
|
|
144
|
+
pageProxy.value,
|
|
145
|
+
viewport
|
|
146
|
+
);
|
|
147
|
+
if (shapes.length > 0) {
|
|
148
|
+
formFields.registerDetectedCheckboxes(
|
|
149
|
+
props.pageNumber,
|
|
150
|
+
shapes,
|
|
151
|
+
props.scale,
|
|
152
|
+
baseHeight
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
);
|
|
128
157
|
watch(
|
|
129
158
|
() => props.scale,
|
|
130
159
|
async () => {
|
|
@@ -157,7 +186,7 @@ async function renderCanvas(opts) {
|
|
|
157
186
|
currentRenderTask.cancel();
|
|
158
187
|
currentRenderTask = null;
|
|
159
188
|
}
|
|
160
|
-
const dpr = window.devicePixelRatio || 1;
|
|
189
|
+
const dpr = Math.max(window.devicePixelRatio || 1, minRenderPixelRatio);
|
|
161
190
|
const quality = props.renderQuality ?? 1;
|
|
162
191
|
const viewport = proxy.getViewport({
|
|
163
192
|
scale: props.scale * quality * dpr
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ViewMode } from '../composables/useViewerState.js';
|
|
2
|
-
import type { IAnnotationStore, StampDefinition, SignatureHandlers } from '../annotation/engine/types.js';
|
|
2
|
+
import type { AddFormFieldPayload, FormFieldDefinition, IAnnotationStore, StampDefinition, SignatureHandlers } from '../annotation/engine/types.js';
|
|
3
3
|
import { type ExportPdfOptions } from '../annotation/pdf-export/export.js';
|
|
4
4
|
type __VLS_Props = {
|
|
5
5
|
source: string | Uint8Array | object;
|
|
@@ -17,6 +17,20 @@ 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;
|
|
24
|
+
/** Map of roleId → CSS color used to color-code form fields in
|
|
25
|
+
* form-edit mode. The editor stays unopinionated about role
|
|
26
|
+
* definitions: the host owns the role list, names, and color picker,
|
|
27
|
+
* and just hands a flat lookup table to the viewer. Unknown or
|
|
28
|
+
* missing ids fall back to the default blue. */
|
|
29
|
+
roleColors?: Record<string, string>;
|
|
30
|
+
/** Active role id new field placements are auto-tagged with. The host
|
|
31
|
+
* drives this — typically by binding it to a role picker in its own
|
|
32
|
+
* UI. Supports v-model via `v-model:active-role-id`. */
|
|
33
|
+
activeRoleId?: string | null;
|
|
20
34
|
};
|
|
21
35
|
declare function exportPdf(options?: ExportPdfOptions): Promise<Uint8Array>;
|
|
22
36
|
type ImportMode = 'replace' | 'merge';
|
|
@@ -27,11 +41,11 @@ declare function importAnnotations(annotations: IAnnotationStore[], options?: {
|
|
|
27
41
|
skipped: number;
|
|
28
42
|
}>;
|
|
29
43
|
declare function getKonvaCanvasState(): Record<number, string>;
|
|
30
|
-
declare var __VLS_1: {},
|
|
44
|
+
declare var __VLS_1: {}, __VLS_51: {};
|
|
31
45
|
type __VLS_Slots = {} & {
|
|
32
46
|
header?: (props: typeof __VLS_1) => any;
|
|
33
47
|
} & {
|
|
34
|
-
footer?: (props: typeof
|
|
48
|
+
footer?: (props: typeof __VLS_51) => any;
|
|
35
49
|
};
|
|
36
50
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
|
|
37
51
|
getAnnotations: () => IAnnotationStore[];
|
|
@@ -40,7 +54,29 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
|
|
|
40
54
|
getKonvaCanvasState: typeof getKonvaCanvasState;
|
|
41
55
|
getFormFieldValues: () => import("../annotation/engine/types.js").FormFieldValue[];
|
|
42
56
|
setFormFieldValue: (fieldName: string, value: string | boolean | string[]) => void;
|
|
43
|
-
|
|
57
|
+
/** Add a form field programmatically. Returns the created definition.
|
|
58
|
+
* The new field is exported into the PDF on `exportPdf()` like any
|
|
59
|
+
* field placed via the placement tool. */
|
|
60
|
+
addFormField: (payload: AddFormFieldPayload) => FormFieldDefinition;
|
|
61
|
+
/** Patch a form field by id (rect, name, flags, type-specific props). */
|
|
62
|
+
updateFormField: (id: string, patch: Partial<FormFieldDefinition>) => void;
|
|
63
|
+
/** Remove a form field by id (drops its value too). */
|
|
64
|
+
removeFormField: (id: string) => void;
|
|
65
|
+
/** All form-field definitions (parsed, detected, and placed), flat. */
|
|
66
|
+
getFormFields: () => FormFieldDefinition[];
|
|
67
|
+
/** Reactive form-edit-mode flag — read with `.value`. */
|
|
68
|
+
formEditMode: import("vue").Ref<boolean, boolean>;
|
|
69
|
+
/** Programmatically enter or leave form-edit mode. */
|
|
70
|
+
setFormEditMode: (enabled: boolean) => void;
|
|
71
|
+
/** Flip form-edit mode. Returns the new state. */
|
|
72
|
+
toggleFormEditMode: () => boolean;
|
|
73
|
+
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
74
|
+
"update:formEditMode": (value: boolean) => any;
|
|
75
|
+
"update:activeRoleId": (value: string | null) => any;
|
|
76
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
77
|
+
"onUpdate:formEditMode"?: ((value: boolean) => any) | undefined;
|
|
78
|
+
"onUpdate:activeRoleId"?: ((value: string | null) => any) | undefined;
|
|
79
|
+
}>, {
|
|
44
80
|
userName: string;
|
|
45
81
|
freehandGroupingDelay: number;
|
|
46
82
|
zoom: number;
|
|
@@ -50,6 +86,9 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
|
|
|
50
86
|
signatureHandlers: SignatureHandlers;
|
|
51
87
|
viewMode: ViewMode;
|
|
52
88
|
shapeDetection: boolean;
|
|
89
|
+
formEditMode: boolean;
|
|
90
|
+
roleColors: Record<string, string>;
|
|
91
|
+
activeRoleId: string | null;
|
|
53
92
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
54
93
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
55
94
|
declare const _default: typeof __VLS_export;
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
<ViewerBar />
|
|
6
6
|
</slot>
|
|
7
7
|
|
|
8
|
-
<div class="
|
|
8
|
+
<div class="flex flex-1 min-h-0">
|
|
9
|
+
<div class="relative flex-1 min-w-0">
|
|
9
10
|
<div
|
|
10
11
|
ref="scrollContainer"
|
|
11
12
|
class="absolute inset-0 overflow-hidden bg-[#F0F3F5] dark:bg-muted/50"
|
|
@@ -133,6 +134,11 @@
|
|
|
133
134
|
<ClientOnly>
|
|
134
135
|
<FloatingPageIndicator :scroll-container="scrollContainer" />
|
|
135
136
|
</ClientOnly>
|
|
137
|
+
</div>
|
|
138
|
+
|
|
139
|
+
<ClientOnly v-if="!viewerState.readonly.value">
|
|
140
|
+
<PlacedFieldSidebar />
|
|
141
|
+
</ClientOnly>
|
|
136
142
|
</div>
|
|
137
143
|
|
|
138
144
|
<!-- Footer slot: empty by default -->
|
|
@@ -180,6 +186,7 @@ import {
|
|
|
180
186
|
import ViewerBar from "./ViewerBar.vue";
|
|
181
187
|
import PdfPage from "./PdfPage.vue";
|
|
182
188
|
import FreeTextModal from "./modals/FreeTextModal.vue";
|
|
189
|
+
import PlacedFieldSidebar from "./panels/PlacedFieldSidebar.vue";
|
|
183
190
|
import AnnotationToolbar from "./AnnotationToolbar.vue";
|
|
184
191
|
import FloatingPageIndicator from "./FloatingPageIndicator.vue";
|
|
185
192
|
import { providePageSettings } from "../composables/usePageSettings";
|
|
@@ -199,6 +206,7 @@ import { createPageProxyCache } from "../composables/usePageProxyCache";
|
|
|
199
206
|
import { createSearchIndex } from "../composables/useSearchIndex";
|
|
200
207
|
import { createShapeDetection } from "../composables/useShapeDetection";
|
|
201
208
|
import { provideFormFields } from "../composables/useFormFields";
|
|
209
|
+
import { extractCheckboxStyles, extractButtonCaptions } from "../annotation/parsers/extractCheckboxStyles";
|
|
202
210
|
import { isIPad } from "../annotation/engine/input-device";
|
|
203
211
|
import { useInertiaPanzoom } from "../composables/useInertiaPanzoom";
|
|
204
212
|
const props = defineProps({
|
|
@@ -212,8 +220,12 @@ const props = defineProps({
|
|
|
212
220
|
readonly: { type: Boolean, required: false, default: false },
|
|
213
221
|
shapeDetection: { type: Boolean, required: false, default: false },
|
|
214
222
|
active: { type: Boolean, required: false, default: true },
|
|
215
|
-
freehandGroupingDelay: { type: Number, required: false, default: 1e3 }
|
|
223
|
+
freehandGroupingDelay: { type: Number, required: false, default: 1e3 },
|
|
224
|
+
formEditMode: { type: Boolean, required: false, default: void 0 },
|
|
225
|
+
roleColors: { type: Object, required: false, default: void 0 },
|
|
226
|
+
activeRoleId: { type: [String, null], required: false, default: void 0 }
|
|
216
227
|
});
|
|
228
|
+
const emit = defineEmits(["update:formEditMode", "update:activeRoleId"]);
|
|
217
229
|
const viewerRoot = ref(null);
|
|
218
230
|
const scrollContainer = ref(null);
|
|
219
231
|
const { state: viewerState, setScrollToPageFn, setDownloadPdfFn } = provideViewerState();
|
|
@@ -223,8 +235,45 @@ watchEffect(() => {
|
|
|
223
235
|
watchEffect(() => {
|
|
224
236
|
viewerState.shapeDetection.value = props.shapeDetection ?? false;
|
|
225
237
|
});
|
|
238
|
+
watch(
|
|
239
|
+
() => props.formEditMode,
|
|
240
|
+
(v) => {
|
|
241
|
+
if (v === void 0) return;
|
|
242
|
+
if (viewerState.formEditMode.value !== v) viewerState.formEditMode.value = v;
|
|
243
|
+
},
|
|
244
|
+
{ immediate: true }
|
|
245
|
+
);
|
|
246
|
+
watch(
|
|
247
|
+
() => viewerState.formEditMode.value,
|
|
248
|
+
(v) => {
|
|
249
|
+
if (props.formEditMode !== v) emit("update:formEditMode", v);
|
|
250
|
+
}
|
|
251
|
+
);
|
|
226
252
|
const viewerSearch = provideViewerSearch();
|
|
227
253
|
const formFieldsState = provideFormFields();
|
|
254
|
+
watch(
|
|
255
|
+
() => props.roleColors,
|
|
256
|
+
(v) => {
|
|
257
|
+
formFieldsState.setRoleColors(v ?? {});
|
|
258
|
+
},
|
|
259
|
+
{ immediate: true }
|
|
260
|
+
);
|
|
261
|
+
watch(
|
|
262
|
+
() => props.activeRoleId,
|
|
263
|
+
(v) => {
|
|
264
|
+
if (v === void 0) return;
|
|
265
|
+
if (formFieldsState.activeRoleId.value !== v) {
|
|
266
|
+
formFieldsState.setActiveRole(v);
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
{ immediate: true }
|
|
270
|
+
);
|
|
271
|
+
watch(
|
|
272
|
+
() => formFieldsState.activeRoleId.value,
|
|
273
|
+
(v) => {
|
|
274
|
+
if (props.activeRoleId !== v) emit("update:activeRoleId", v);
|
|
275
|
+
}
|
|
276
|
+
);
|
|
228
277
|
const pageSettings = providePageSettings(viewerRoot);
|
|
229
278
|
const virtualization = createPageVirtualization();
|
|
230
279
|
setScrollToPageFn((pageNumber) => {
|
|
@@ -368,14 +417,28 @@ async function loadDocument() {
|
|
|
368
417
|
pdfjs.GlobalWorkerOptions.workerSrc = workerModule.default;
|
|
369
418
|
}
|
|
370
419
|
const source = props.source;
|
|
371
|
-
const
|
|
372
|
-
|
|
373
|
-
|
|
420
|
+
const baseParams = source instanceof Uint8Array || typeof source === "string" ? { url: typeof source === "string" ? source : void 0, data: source instanceof Uint8Array ? source : void 0 } : { ...source };
|
|
421
|
+
const docParams = {
|
|
422
|
+
...baseParams,
|
|
423
|
+
standardFontDataUrl: "/_kviewer/standard_fonts/",
|
|
424
|
+
cMapUrl: "/_kviewer/cmaps/",
|
|
425
|
+
cMapPacked: true,
|
|
426
|
+
useSystemFonts: true
|
|
427
|
+
};
|
|
428
|
+
const loadingTask = pdfjs.getDocument(docParams);
|
|
374
429
|
const pdfDoc = await loadingTask.promise;
|
|
375
430
|
doc.value = pdfDoc;
|
|
376
431
|
viewerState.doc.value = pdfDoc;
|
|
377
432
|
viewerState.totalPages.value = pdfDoc.numPages;
|
|
378
433
|
proxyCache.setDocument(pdfDoc);
|
|
434
|
+
pdfDoc.getData().then(async (bytes) => {
|
|
435
|
+
const [styles, captions] = await Promise.all([
|
|
436
|
+
extractCheckboxStyles(bytes),
|
|
437
|
+
extractButtonCaptions(bytes)
|
|
438
|
+
]);
|
|
439
|
+
if (styles.size > 0) formFieldsState.applyCheckboxStyles(styles);
|
|
440
|
+
if (captions.size > 0) formFieldsState.applyButtonCaptions(captions);
|
|
441
|
+
}).catch((err) => console.warn("[KViewer] Failed to read MK data from source PDF:", err));
|
|
379
442
|
if (!scrollContainer.value) {
|
|
380
443
|
await nextTick();
|
|
381
444
|
}
|
|
@@ -487,11 +550,13 @@ async function exportPdf(options = {}) {
|
|
|
487
550
|
const pdfData = await doc.value.getData();
|
|
488
551
|
const exportContext = painter.getExportContext();
|
|
489
552
|
const formFieldValues = formFieldsState.getAllFieldValues();
|
|
553
|
+
const placedFormFieldDefinitions = formFieldsState.getPlacedFields();
|
|
490
554
|
const bytes = await exportAnnotationsToPdf({
|
|
491
555
|
pdfData,
|
|
492
556
|
annotations: exportContext.annotations,
|
|
493
557
|
options: mergedOptions,
|
|
494
558
|
formFieldValues,
|
|
559
|
+
placedFormFieldDefinitions,
|
|
495
560
|
originalAnnotationIds: exportContext.originalIds,
|
|
496
561
|
modifiedAnnotationIds: exportContext.modifiedIds,
|
|
497
562
|
deletedAnnotationIds: exportContext.deletedIds
|
|
@@ -642,6 +707,15 @@ onMounted(() => {
|
|
|
642
707
|
painter = createAnnotationEngine(viewerState, {
|
|
643
708
|
userName: props.userName,
|
|
644
709
|
onRequestTextInput,
|
|
710
|
+
onPlaceField: (payload) => {
|
|
711
|
+
formFieldsState.addPlacedField(payload);
|
|
712
|
+
viewerState.selectTool("hand");
|
|
713
|
+
},
|
|
714
|
+
getFormFieldPreviewColor: () => {
|
|
715
|
+
const id = formFieldsState.activeRoleId.value;
|
|
716
|
+
if (!id) return void 0;
|
|
717
|
+
return formFieldsState.roleColors.value[id];
|
|
718
|
+
},
|
|
645
719
|
freehandGroupingDelay: props.freehandGroupingDelay,
|
|
646
720
|
// Suspend panzoom gestures while an annotation is being dragged or
|
|
647
721
|
// transformed. Otherwise single-finger pan runs in parallel with the
|
|
@@ -670,6 +744,8 @@ onMounted(() => {
|
|
|
670
744
|
inertiaPanzoom.onChange(() => {
|
|
671
745
|
if (viewerState.selectionRect.value) viewerState.selectionRect.value = null;
|
|
672
746
|
if (!isSinglePageMode.value) virtualization.updateCurrentPageByRect();
|
|
747
|
+
const z = inertiaPanzoom.getScale();
|
|
748
|
+
if (z !== viewerState.visualZoom.value) viewerState.visualZoom.value = z;
|
|
673
749
|
});
|
|
674
750
|
nextTick(() => initPanzoom());
|
|
675
751
|
watch(
|
|
@@ -684,7 +760,10 @@ onMounted(() => {
|
|
|
684
760
|
},
|
|
685
761
|
{ immediate: true }
|
|
686
762
|
);
|
|
687
|
-
watch(() => viewerState.scale.value, () =>
|
|
763
|
+
watch(() => viewerState.scale.value, async () => {
|
|
764
|
+
await nextTick();
|
|
765
|
+
inertiaPanzoom.reset();
|
|
766
|
+
});
|
|
688
767
|
watch(() => viewerState.currentPage.value, () => inertiaPanzoom.reset());
|
|
689
768
|
}
|
|
690
769
|
if (isIPad()) {
|
|
@@ -752,7 +831,27 @@ defineExpose({
|
|
|
752
831
|
exportPdf,
|
|
753
832
|
getKonvaCanvasState,
|
|
754
833
|
getFormFieldValues: () => formFieldsState.getAllFieldValues(),
|
|
755
|
-
setFormFieldValue: (fieldName, value) => formFieldsState.setFieldValueByName(fieldName, value)
|
|
834
|
+
setFormFieldValue: (fieldName, value) => formFieldsState.setFieldValueByName(fieldName, value),
|
|
835
|
+
/** Add a form field programmatically. Returns the created definition.
|
|
836
|
+
* The new field is exported into the PDF on `exportPdf()` like any
|
|
837
|
+
* field placed via the placement tool. */
|
|
838
|
+
addFormField: (payload) => formFieldsState.addFormField(payload),
|
|
839
|
+
/** Patch a form field by id (rect, name, flags, type-specific props). */
|
|
840
|
+
updateFormField: (id, patch) => formFieldsState.updatePlacedField(id, patch),
|
|
841
|
+
/** Remove a form field by id (drops its value too). */
|
|
842
|
+
removeFormField: (id) => formFieldsState.removePlacedField(id),
|
|
843
|
+
/** All form-field definitions (parsed, detected, and placed), flat. */
|
|
844
|
+
getFormFields: () => formFieldsState.getAllFields(),
|
|
845
|
+
/** Reactive form-edit-mode flag — read with `.value`. */
|
|
846
|
+
formEditMode: viewerState.formEditMode,
|
|
847
|
+
/** Programmatically enter or leave form-edit mode. */
|
|
848
|
+
setFormEditMode: (enabled) => viewerState.setFormEditMode(enabled),
|
|
849
|
+
/** Flip form-edit mode. Returns the new state. */
|
|
850
|
+
toggleFormEditMode: () => {
|
|
851
|
+
const next = !viewerState.formEditMode.value;
|
|
852
|
+
viewerState.setFormEditMode(next);
|
|
853
|
+
return next;
|
|
854
|
+
}
|
|
756
855
|
});
|
|
757
856
|
</script>
|
|
758
857
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ViewMode } from '../composables/useViewerState.js';
|
|
2
|
-
import type { IAnnotationStore, StampDefinition, SignatureHandlers } from '../annotation/engine/types.js';
|
|
2
|
+
import type { AddFormFieldPayload, FormFieldDefinition, IAnnotationStore, StampDefinition, SignatureHandlers } from '../annotation/engine/types.js';
|
|
3
3
|
import { type ExportPdfOptions } from '../annotation/pdf-export/export.js';
|
|
4
4
|
type __VLS_Props = {
|
|
5
5
|
source: string | Uint8Array | object;
|
|
@@ -17,6 +17,20 @@ 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;
|
|
24
|
+
/** Map of roleId → CSS color used to color-code form fields in
|
|
25
|
+
* form-edit mode. The editor stays unopinionated about role
|
|
26
|
+
* definitions: the host owns the role list, names, and color picker,
|
|
27
|
+
* and just hands a flat lookup table to the viewer. Unknown or
|
|
28
|
+
* missing ids fall back to the default blue. */
|
|
29
|
+
roleColors?: Record<string, string>;
|
|
30
|
+
/** Active role id new field placements are auto-tagged with. The host
|
|
31
|
+
* drives this — typically by binding it to a role picker in its own
|
|
32
|
+
* UI. Supports v-model via `v-model:active-role-id`. */
|
|
33
|
+
activeRoleId?: string | null;
|
|
20
34
|
};
|
|
21
35
|
declare function exportPdf(options?: ExportPdfOptions): Promise<Uint8Array>;
|
|
22
36
|
type ImportMode = 'replace' | 'merge';
|
|
@@ -27,11 +41,11 @@ declare function importAnnotations(annotations: IAnnotationStore[], options?: {
|
|
|
27
41
|
skipped: number;
|
|
28
42
|
}>;
|
|
29
43
|
declare function getKonvaCanvasState(): Record<number, string>;
|
|
30
|
-
declare var __VLS_1: {},
|
|
44
|
+
declare var __VLS_1: {}, __VLS_51: {};
|
|
31
45
|
type __VLS_Slots = {} & {
|
|
32
46
|
header?: (props: typeof __VLS_1) => any;
|
|
33
47
|
} & {
|
|
34
|
-
footer?: (props: typeof
|
|
48
|
+
footer?: (props: typeof __VLS_51) => any;
|
|
35
49
|
};
|
|
36
50
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
|
|
37
51
|
getAnnotations: () => IAnnotationStore[];
|
|
@@ -40,7 +54,29 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
|
|
|
40
54
|
getKonvaCanvasState: typeof getKonvaCanvasState;
|
|
41
55
|
getFormFieldValues: () => import("../annotation/engine/types.js").FormFieldValue[];
|
|
42
56
|
setFormFieldValue: (fieldName: string, value: string | boolean | string[]) => void;
|
|
43
|
-
|
|
57
|
+
/** Add a form field programmatically. Returns the created definition.
|
|
58
|
+
* The new field is exported into the PDF on `exportPdf()` like any
|
|
59
|
+
* field placed via the placement tool. */
|
|
60
|
+
addFormField: (payload: AddFormFieldPayload) => FormFieldDefinition;
|
|
61
|
+
/** Patch a form field by id (rect, name, flags, type-specific props). */
|
|
62
|
+
updateFormField: (id: string, patch: Partial<FormFieldDefinition>) => void;
|
|
63
|
+
/** Remove a form field by id (drops its value too). */
|
|
64
|
+
removeFormField: (id: string) => void;
|
|
65
|
+
/** All form-field definitions (parsed, detected, and placed), flat. */
|
|
66
|
+
getFormFields: () => FormFieldDefinition[];
|
|
67
|
+
/** Reactive form-edit-mode flag — read with `.value`. */
|
|
68
|
+
formEditMode: import("vue").Ref<boolean, boolean>;
|
|
69
|
+
/** Programmatically enter or leave form-edit mode. */
|
|
70
|
+
setFormEditMode: (enabled: boolean) => void;
|
|
71
|
+
/** Flip form-edit mode. Returns the new state. */
|
|
72
|
+
toggleFormEditMode: () => boolean;
|
|
73
|
+
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
74
|
+
"update:formEditMode": (value: boolean) => any;
|
|
75
|
+
"update:activeRoleId": (value: string | null) => any;
|
|
76
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
77
|
+
"onUpdate:formEditMode"?: ((value: boolean) => any) | undefined;
|
|
78
|
+
"onUpdate:activeRoleId"?: ((value: string | null) => any) | undefined;
|
|
79
|
+
}>, {
|
|
44
80
|
userName: string;
|
|
45
81
|
freehandGroupingDelay: number;
|
|
46
82
|
zoom: number;
|
|
@@ -50,6 +86,9 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
|
|
|
50
86
|
signatureHandlers: SignatureHandlers;
|
|
51
87
|
viewMode: ViewMode;
|
|
52
88
|
shapeDetection: boolean;
|
|
89
|
+
formEditMode: boolean;
|
|
90
|
+
roleColors: Record<string, string>;
|
|
91
|
+
activeRoleId: string | null;
|
|
53
92
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
54
93
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
55
94
|
declare const _default: typeof __VLS_export;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<UPopover>
|
|
6
6
|
<UButton icon="i-lucide-menu" variant="ghost" color="neutral" size="xs" data-testid="viewer-menu" />
|
|
7
7
|
<template #content>
|
|
8
|
-
<div class="p-1">
|
|
8
|
+
<div class="p-1 flex flex-col gap-0.5">
|
|
9
9
|
<UButton
|
|
10
10
|
icon="i-lucide-download"
|
|
11
11
|
label="Download"
|
|
@@ -16,6 +16,16 @@
|
|
|
16
16
|
data-testid="viewer-download"
|
|
17
17
|
@click="onDownload"
|
|
18
18
|
/>
|
|
19
|
+
<UButton
|
|
20
|
+
:icon="state.shapeDetection.value ? 'i-lucide-square-check-big' : 'i-lucide-square-dashed'"
|
|
21
|
+
:label="state.shapeDetection.value ? 'Disable form field detection' : 'Detect form fields'"
|
|
22
|
+
:variant="state.shapeDetection.value ? 'soft' : 'ghost'"
|
|
23
|
+
:color="state.shapeDetection.value ? 'primary' : 'neutral'"
|
|
24
|
+
size="xs"
|
|
25
|
+
class="w-full justify-start"
|
|
26
|
+
data-testid="viewer-toggle-shape-detection"
|
|
27
|
+
@click="state.shapeDetection.value = !state.shapeDetection.value"
|
|
28
|
+
/>
|
|
19
29
|
</div>
|
|
20
30
|
</template>
|
|
21
31
|
</UPopover>
|
|
@@ -30,6 +40,16 @@
|
|
|
30
40
|
|
|
31
41
|
<HandTool />
|
|
32
42
|
<MarqueeTool />
|
|
43
|
+
|
|
44
|
+
<UButton
|
|
45
|
+
icon="i-lucide-form-input"
|
|
46
|
+
:variant="state.formEditMode.value ? 'soft' : 'ghost'"
|
|
47
|
+
:color="state.formEditMode.value ? 'primary' : 'neutral'"
|
|
48
|
+
size="xs"
|
|
49
|
+
:title="state.formEditMode.value ? 'Exit form-edit mode' : 'Enter form-edit mode'"
|
|
50
|
+
data-testid="form-edit-toggle"
|
|
51
|
+
@click="state.setFormEditMode(!state.formEditMode.value)"
|
|
52
|
+
/>
|
|
33
53
|
</template>
|
|
34
54
|
|
|
35
55
|
<div class="ml-auto flex items-center gap-2">
|
|
@@ -45,7 +65,8 @@
|
|
|
45
65
|
</div>
|
|
46
66
|
|
|
47
67
|
<div class="justify-self-center">
|
|
48
|
-
<
|
|
68
|
+
<FormFieldTools v-if="state.formEditMode.value" />
|
|
69
|
+
<DrawingTools v-else :style-version="styleVersion" />
|
|
49
70
|
</div>
|
|
50
71
|
|
|
51
72
|
<div class="justify-self-end flex items-center gap-1">
|
|
@@ -63,6 +84,7 @@ import ZoomControls from "./tools/ZoomControls.vue";
|
|
|
63
84
|
import HandTool from "./tools/HandTool.vue";
|
|
64
85
|
import MarqueeTool from "./tools/MarqueeTool.vue";
|
|
65
86
|
import DrawingTools from "./tools/DrawingTools.vue";
|
|
87
|
+
import FormFieldTools from "./tools/FormFieldTools.vue";
|
|
66
88
|
import ActionTools from "./tools/ActionTools.vue";
|
|
67
89
|
import PageInfo from "./tools/PageInfo.vue";
|
|
68
90
|
import SearchTool from "./tools/SearchTool.vue";
|
|
@@ -48,6 +48,11 @@ type __VLS_Props = {
|
|
|
48
48
|
zoom?: number;
|
|
49
49
|
/** Minimum number of tabs -- prevents closing below this count. */
|
|
50
50
|
minTabs?: number;
|
|
51
|
+
/** Forwarded to every Viewer instance — see KViewer's `roleColors`. */
|
|
52
|
+
roleColors?: Record<string, string>;
|
|
53
|
+
/** Forwarded to every Viewer instance — see KViewer's `activeRoleId`.
|
|
54
|
+
* Supports v-model via `v-model:active-role-id`. */
|
|
55
|
+
activeRoleId?: string | null;
|
|
51
56
|
};
|
|
52
57
|
declare function addTab(item: Omit<ViewerTabItem, 'id'> & {
|
|
53
58
|
id?: string;
|
|
@@ -55,7 +60,7 @@ declare function addTab(item: Omit<ViewerTabItem, 'id'> & {
|
|
|
55
60
|
declare function removeTab(id: string): boolean;
|
|
56
61
|
declare function activateTab(id: string): void;
|
|
57
62
|
declare function getViewer(id: string): ComponentPublicInstance | null;
|
|
58
|
-
declare var __VLS_7: {}, __VLS_21: {},
|
|
63
|
+
declare var __VLS_7: {}, __VLS_21: {}, __VLS_32: {
|
|
59
64
|
tab: {
|
|
60
65
|
id: string;
|
|
61
66
|
label: string;
|
|
@@ -154,7 +159,7 @@ declare var __VLS_7: {}, __VLS_21: {}, __VLS_30: {
|
|
|
154
159
|
zoom?: number | undefined;
|
|
155
160
|
shapeDetection?: boolean | undefined;
|
|
156
161
|
};
|
|
157
|
-
},
|
|
162
|
+
}, __VLS_35: {
|
|
158
163
|
tab: {
|
|
159
164
|
id: string;
|
|
160
165
|
label: string;
|
|
@@ -253,17 +258,17 @@ declare var __VLS_7: {}, __VLS_21: {}, __VLS_30: {
|
|
|
253
258
|
zoom?: number | undefined;
|
|
254
259
|
shapeDetection?: boolean | undefined;
|
|
255
260
|
};
|
|
256
|
-
},
|
|
261
|
+
}, __VLS_37: {};
|
|
257
262
|
type __VLS_Slots = {} & {
|
|
258
263
|
'tabs-leading'?: (props: typeof __VLS_7) => any;
|
|
259
264
|
} & {
|
|
260
265
|
'tabs-trailing'?: (props: typeof __VLS_21) => any;
|
|
261
266
|
} & {
|
|
262
|
-
header?: (props: typeof
|
|
267
|
+
header?: (props: typeof __VLS_32) => any;
|
|
263
268
|
} & {
|
|
264
|
-
footer?: (props: typeof
|
|
269
|
+
footer?: (props: typeof __VLS_35) => any;
|
|
265
270
|
} & {
|
|
266
|
-
empty?: (props: typeof
|
|
271
|
+
empty?: (props: typeof __VLS_37) => any;
|
|
267
272
|
};
|
|
268
273
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
|
|
269
274
|
addTab: typeof addTab;
|
|
@@ -370,11 +375,13 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
|
|
|
370
375
|
shapeDetection?: boolean | undefined;
|
|
371
376
|
}[];
|
|
372
377
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
378
|
+
"update:activeRoleId": (value: string | null) => any;
|
|
373
379
|
"update:activeTab": (id: string) => any;
|
|
374
380
|
"tab-added": (tab: ViewerTabItem) => any;
|
|
375
381
|
"tab-close": (id: string) => any;
|
|
376
382
|
"tab-removed": (id: string) => any;
|
|
377
383
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
384
|
+
"onUpdate:activeRoleId"?: ((value: string | null) => any) | undefined;
|
|
378
385
|
"onUpdate:activeTab"?: ((id: string) => any) | undefined;
|
|
379
386
|
"onTab-added"?: ((tab: ViewerTabItem) => any) | undefined;
|
|
380
387
|
"onTab-close"?: ((id: string) => any) | undefined;
|
|
@@ -385,6 +392,8 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
|
|
|
385
392
|
stamps: StampDefinition[];
|
|
386
393
|
signatureHandlers: SignatureHandlers;
|
|
387
394
|
viewMode: ViewMode;
|
|
395
|
+
roleColors: Record<string, string>;
|
|
396
|
+
activeRoleId: string | null;
|
|
388
397
|
defaultActiveTab: string;
|
|
389
398
|
minTabs: number;
|
|
390
399
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|