kviewer 0.3.3 → 0.3.5

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 (47) hide show
  1. package/dist/module.d.mts +1 -1
  2. package/dist/module.json +1 -1
  3. package/dist/runtime/annotation/engine/editor/selector.d.ts +1 -0
  4. package/dist/runtime/annotation/engine/editor/selector.js +17 -5
  5. package/dist/runtime/annotation/engine/painter.d.ts +4 -2
  6. package/dist/runtime/annotation/engine/painter.js +4 -0
  7. package/dist/runtime/annotation/engine/tools/form-field.d.ts +5 -5
  8. package/dist/runtime/annotation/engine/tools/form-field.js +1 -1
  9. package/dist/runtime/annotation/engine/types.d.ts +18 -9
  10. package/dist/runtime/annotation/pdf-export/export-form-fields.js +6 -29
  11. package/dist/runtime/assets/kviewer.css +1 -1
  12. package/dist/runtime/components/AnnotationToolbar.vue +12 -1
  13. package/dist/runtime/components/FormFieldLayer.vue +7 -2
  14. package/dist/runtime/components/PdfPage.vue +24 -1
  15. package/dist/runtime/components/SelectionToolbarItems.d.vue.ts +8 -0
  16. package/dist/runtime/components/SelectionToolbarItems.vue +43 -0
  17. package/dist/runtime/components/SelectionToolbarItems.vue.d.ts +8 -0
  18. package/dist/runtime/components/Viewer.d.vue.ts +24 -17
  19. package/dist/runtime/components/Viewer.vue +60 -37
  20. package/dist/runtime/components/Viewer.vue.d.ts +24 -17
  21. package/dist/runtime/components/ViewerBar.d.vue.ts +4 -4
  22. package/dist/runtime/components/ViewerBar.vue +2 -1
  23. package/dist/runtime/components/ViewerBar.vue.d.ts +4 -4
  24. package/dist/runtime/components/ViewerTabs.d.vue.ts +16 -17
  25. package/dist/runtime/components/ViewerTabs.vue +5 -6
  26. package/dist/runtime/components/ViewerTabs.vue.d.ts +16 -17
  27. package/dist/runtime/components/form-fields/FormFieldWrapper.vue +35 -10
  28. package/dist/runtime/components/form-fields/FormSignatureField.vue +10 -2
  29. package/dist/runtime/components/form-fields/PlacedFieldChrome.d.vue.ts +4 -0
  30. package/dist/runtime/components/form-fields/PlacedFieldChrome.vue +35 -18
  31. package/dist/runtime/components/form-fields/PlacedFieldChrome.vue.d.ts +4 -0
  32. package/dist/runtime/components/form-fields/PlacedFieldToolbar.d.vue.ts +7 -0
  33. package/dist/runtime/components/form-fields/PlacedFieldToolbar.vue +51 -0
  34. package/dist/runtime/components/form-fields/PlacedFieldToolbar.vue.d.ts +7 -0
  35. package/dist/runtime/composables/useFormFields.d.ts +28 -17
  36. package/dist/runtime/composables/useFormFields.js +20 -24
  37. package/dist/runtime/embed/bridge-client.d.ts +4 -2
  38. package/dist/runtime/embed/bridge-client.js +2 -1
  39. package/dist/runtime/embed/bridge-host.d.ts +2 -0
  40. package/dist/runtime/embed/bridge-host.js +16 -0
  41. package/dist/runtime/embed/protocol.d.ts +12 -0
  42. package/dist/runtime/public-types.d.ts +2 -1
  43. package/dist/runtime/selection-items.d.ts +61 -0
  44. package/dist/runtime/selection-items.js +1 -0
  45. package/dist/runtime/toolbar-tools.d.ts +4 -1
  46. package/dist/types.d.mts +1 -1
  47. package/package.json +1 -1
package/dist/module.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _nuxt_schema from '@nuxt/schema';
2
- export { ActiveTool, AddFormFieldPayload, CheckboxStyle, ExportPdfOptions, FormFieldDefinition, FormFieldOrigin, FormFieldType, FormFieldValue, KVIEWER_EMBED_PROTOCOL_VERSION, KVIEWER_EMBED_UNSUPPORTED_METHOD_ERROR_NAME, KViewerApi, KViewerEmbedBridgeOptions, KViewerEmbedClient, KViewerEmbedClientOptions, KViewerEmbedEventName, KViewerEmbedEventPayloads, KViewerEmbedMethodName, KViewerHostApi, PlacedFieldDefaults, SignatureData, SignatureFieldStatus, SignatureHandlers, ViewMode, ViewerBottomToolId, ViewerLayoutToolId, ViewerMenuButtonItem, ViewerMenuCheckboxItem, ViewerMenuItem, ViewerMenuSeparatorItem, ViewerState, ViewerToolEntry, ViewerToolId, ViewerToolSlot, ViewerTopToolId, useKViewerEmbedBridge } from '../dist/runtime/public-types.js';
2
+ export { ActiveTool, AddFormFieldPayload, CheckboxStyle, ExportPdfOptions, FormFieldDefinition, FormFieldOrigin, FormFieldType, FormFieldValue, IAnnotationStore, KVIEWER_EMBED_PROTOCOL_VERSION, KVIEWER_EMBED_UNSUPPORTED_METHOD_ERROR_NAME, KViewerApi, KViewerEmbedBridgeOptions, KViewerEmbedClient, KViewerEmbedClientOptions, KViewerEmbedEventName, KViewerEmbedEventPayloads, KViewerEmbedMethodName, KViewerHostApi, PlacedFieldDefaults, SignatureData, SignatureFieldStatus, SignatureHandlers, ViewMode, ViewerBottomToolId, ViewerLayoutToolId, ViewerMenuButtonItem, ViewerMenuCheckboxItem, ViewerMenuItem, ViewerMenuSeparatorItem, ViewerSelectionButtonItem, ViewerSelectionContext, ViewerSelectionItem, ViewerSelectionSelectItem, ViewerState, ViewerToolEntry, ViewerToolId, ViewerToolSlot, ViewerTopToolId, useKViewerEmbedBridge } from '../dist/runtime/public-types.js';
3
3
 
4
4
  interface ModuleOptions {
5
5
  /**
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "kviewer",
3
3
  "configKey": "kviewer",
4
- "version": "0.3.3",
4
+ "version": "0.3.5",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "3.6.1"
@@ -52,6 +52,7 @@ export declare class Selector {
52
52
  private marqueeRect;
53
53
  private marqueeStartPos;
54
54
  private marqueeStage;
55
+ private suppressStageClick;
55
56
  constructor({ konvaCanvasStore, getAnnotationStore, onDelete, onSelected, onMultiSelected, onMultiChanged, onCancel, onChanged, onRequestDeleteConfirm, onFreeTextDoubleClick, getStylusModeEnabled, setExternalGesturesEnabled, }: ISelectorOptions);
56
57
  /** Returns true if this event should be rejected (finger touch in stylus mode). */
57
58
  private isStylusRejected;
@@ -24,6 +24,7 @@ export class Selector {
24
24
  marqueeRect = null;
25
25
  marqueeStartPos = null;
26
26
  marqueeStage = null;
27
+ suppressStageClick = false;
27
28
  constructor({
28
29
  konvaCanvasStore,
29
30
  getAnnotationStore,
@@ -88,13 +89,17 @@ export class Selector {
88
89
  }
89
90
  disableStageEvents(konvaStage) {
90
91
  konvaStage.off(
91
- "click mousedown mousemove mouseup touchstart touchmove touchend pointerdown pointermove pointerup"
92
+ "click tap mousedown mousemove mouseup touchstart touchmove touchend pointerdown pointermove pointerup"
92
93
  );
93
94
  }
94
95
  bindStageEvents(konvaStage) {
95
96
  konvaStage.on("click tap", (e) => {
96
97
  if (e.target !== konvaStage) return;
97
98
  if (this.isStylusRejected(e.evt)) return;
99
+ if (this.suppressStageClick) {
100
+ this.suppressStageClick = false;
101
+ return;
102
+ }
98
103
  this.clearTransformers();
99
104
  });
100
105
  }
@@ -474,6 +479,7 @@ export class Selector {
474
479
  this.handleShapeClick(shape, konvaStage, false);
475
480
  }
476
481
  clear() {
482
+ this.suppressStageClick = false;
477
483
  this.clearTransformers();
478
484
  this.konvaCanvasStore.forEach((konvaCanvas) => {
479
485
  const { konvaStage } = konvaCanvas;
@@ -489,6 +495,7 @@ export class Selector {
489
495
  const pageGroups = this.getPageShapeGroups(konvaStage);
490
496
  this.disableStageEvents(konvaStage);
491
497
  this.bindStageEvents(konvaStage);
498
+ this.bindMarqueeEvents(konvaStage, { mouseOnly: true });
492
499
  this.enableShapeGroups(pageGroups, konvaStage);
493
500
  if (this.selectedId) {
494
501
  this.selectedShape(this.selectedId, konvaStage);
@@ -519,13 +526,17 @@ export class Selector {
519
526
  this.enableShapeGroups(pageGroups, konvaStage);
520
527
  this.bindMarqueeEvents(konvaStage);
521
528
  }
522
- bindMarqueeEvents(konvaStage) {
523
- konvaStage.on("mousedown touchstart", (e) => {
529
+ bindMarqueeEvents(konvaStage, opts = {}) {
530
+ const { mouseOnly = false } = opts;
531
+ konvaStage.on(mouseOnly ? "mousedown" : "mousedown touchstart", (e) => {
524
532
  if (e.target !== konvaStage) return;
525
533
  if (this.isStylusRejected(e.evt)) return;
534
+ const button = e.evt?.button;
535
+ if (mouseOnly && button !== void 0 && button !== 0) return;
526
536
  if (this.getStylusModeEnabled?.() && e.evt) e.evt.preventDefault();
527
537
  this.clearTransformers();
528
538
  this.selectedIds = [];
539
+ this.marqueeRect?.destroy();
529
540
  const pos = konvaStage.getRelativePointerPosition();
530
541
  if (!pos) return;
531
542
  this.marqueeStartPos = pos;
@@ -543,7 +554,7 @@ export class Selector {
543
554
  });
544
555
  this.getBackgroundLayer(konvaStage).add(this.marqueeRect);
545
556
  });
546
- konvaStage.on("mousemove touchmove", (e) => {
557
+ konvaStage.on(mouseOnly ? "mousemove" : "mousemove touchmove", (e) => {
547
558
  if (!this.marqueeRect || !this.marqueeStartPos || !this.marqueeStage) return;
548
559
  if (this.isStylusRejected(e.evt)) return;
549
560
  if (this.getStylusModeEnabled?.() && e.evt) e.evt.preventDefault();
@@ -556,7 +567,7 @@ export class Selector {
556
567
  this.marqueeRect.setAttrs({ x, y, width, height });
557
568
  this.marqueeStage.batchDraw();
558
569
  });
559
- konvaStage.on("mouseup touchend", (e) => {
570
+ konvaStage.on(mouseOnly ? "mouseup" : "mouseup touchend", (e) => {
560
571
  if (!this.marqueeRect || !this.marqueeStage) return;
561
572
  if (this.isStylusRejected(e.evt)) return;
562
573
  const selectionBox = this.marqueeRect.getClientRect();
@@ -567,6 +578,7 @@ export class Selector {
567
578
  this.marqueeStage = null;
568
579
  return;
569
580
  }
581
+ if (mouseOnly) this.suppressStageClick = true;
570
582
  const groups = this.getPageShapeGroups(this.marqueeStage);
571
583
  const matchedIds = [];
572
584
  groups.forEach((group) => {
@@ -1,6 +1,6 @@
1
1
  import Konva from 'konva';
2
2
  import type { IRect } from 'konva/lib/types';
3
- import { type IAnnotationStore, type IAnnotationStyle, type IAnnotationType, type PlaceFieldPayload } from './types.js';
3
+ import { type FormFieldType, type IAnnotationStore, type IAnnotationStyle, type IAnnotationType, type PlaceFieldPayload } from './types.js';
4
4
  import { type IEditorFreeTextOptions } from './tools/free-text.js';
5
5
  export interface KonvaCanvas {
6
6
  pageNumber: number;
@@ -26,7 +26,7 @@ export interface PainterCallbacks {
26
26
  /** Optional accessor returning the color to use for the form-field
27
27
  * placement preview. Lets the active role color override the default
28
28
  * blue without rebuilding the editor between placements. */
29
- getFormFieldPreviewColor?: () => string | undefined;
29
+ getFormFieldPreviewColor?: (fieldType: FormFieldType) => string | undefined;
30
30
  }
31
31
  export declare class Painter {
32
32
  private userName?;
@@ -128,6 +128,8 @@ export declare class Painter {
128
128
  activateEraser(): void;
129
129
  highlightRange(range: Range, annotation: IAnnotationType): void;
130
130
  selectAnnotation(id: string): void;
131
+ /** Clears the current annotation selection without touching the store. */
132
+ clearSelection(): void;
131
133
  initAnnotations(annotations: IAnnotationStore[]): Promise<void>;
132
134
  update(id: string, updates: Partial<IAnnotationStore>): void;
133
135
  delete(id: string, emit?: boolean): void;
@@ -624,6 +624,10 @@ export class Painter {
624
624
  this.selector.select(id);
625
625
  this.callbacks.setDefaultMode();
626
626
  }
627
+ /** Clears the current annotation selection without touching the store. */
628
+ clearSelection() {
629
+ this.selector.delete();
630
+ }
627
631
  async initAnnotations(annotations) {
628
632
  annotations.forEach((annotation) => {
629
633
  this.saveToStore(annotation, true);
@@ -6,11 +6,11 @@ export interface IEditorFormFieldOptions {
6
6
  /** PDF-space page height, needed to flip Konva page-local Y → PDF Y. */
7
7
  pageHeight: number;
8
8
  onPlaceField: (payload: PlaceFieldPayload) => void;
9
- /** Resolves to the active role color so the placement preview matches
10
- * the color the field will be tagged with. Re-read on every drag start
11
- * so the user can switch roles between placements without rebuilding
12
- * the editor. */
13
- getPreviewColor?: () => string | undefined;
9
+ /** Resolves to the fieldColor preset for this field type so the
10
+ * placement preview matches the color the field will land with.
11
+ * Re-read on every drag start so the host can change defaults between
12
+ * placements without rebuilding the editor. */
13
+ getPreviewColor?: (fieldType: FormFieldType) => string | undefined;
14
14
  }
15
15
  export declare class EditorFormField extends Editor {
16
16
  private fieldType;
@@ -38,7 +38,7 @@ export class EditorFormField extends Editor {
38
38
  y: pos.y,
39
39
  width: 0,
40
40
  height: 0,
41
- stroke: this.getPreviewColor?.() ?? "#1677ff",
41
+ stroke: this.getPreviewColor?.(this.fieldType) ?? "#1677ff",
42
42
  strokeWidth: 1,
43
43
  dash: [4, 4],
44
44
  strokeScaleEnabled: false,
@@ -216,11 +216,17 @@ export interface FormFieldDefinition {
216
216
  color?: number[];
217
217
  backgroundColor?: number[];
218
218
  textAlignment?: number;
219
- /** Opaque role tag for color-coding in form-edit mode. The editor
220
- * doesn't own role definitions the host (integrating app) maps
221
- * roleId color via the `roleColors` prop on KViewer. Not exported
222
- * to the PDF. */
223
- roleId?: string;
219
+ /** CSS color driving the field's editor chrome (outline, grip, hover
220
+ * accents). Host-owned; falls back to the default blue when unset.
221
+ * Not exported to the PDF use `color`/`backgroundColor` for the
222
+ * widget's native appearance. Typically set per placement via
223
+ * `fieldDefaults` (e.g. one color per signer). */
224
+ fieldColor?: string;
225
+ /** Host-owned metadata bag. The editor carries it around untouched —
226
+ * it is never read, validated, or exported to the PDF. Must stay
227
+ * JSON-serializable so it survives the embed bridge. Replaced
228
+ * wholesale by an `updateFormField()` patch (no deep merge). */
229
+ meta?: Record<string, unknown>;
224
230
  }
225
231
  export interface FormFieldValue {
226
232
  fieldId: string;
@@ -251,8 +257,13 @@ export interface AddFormFieldPayload {
251
257
  * mirrored across them on edit. Radios with the same `fieldName` form
252
258
  * one option group. */
253
259
  fieldName?: string;
254
- /** Opaque role tag for color-coding in form-edit mode. */
255
- roleId?: string;
260
+ /** CSS color for the field's editor chrome (see
261
+ * {@link FormFieldDefinition.fieldColor}). */
262
+ fieldColor?: string;
263
+ /** Host-owned metadata bag, carried untouched (see
264
+ * {@link FormFieldDefinition.meta}). Also usable as a preset in
265
+ * `fieldDefaults` so tool placements get their metadata atomically. */
266
+ meta?: Record<string, unknown>;
256
267
  /** Default value for the field. Becomes the initial value too. */
257
268
  defaultValue?: string;
258
269
  readOnly?: boolean;
@@ -316,8 +327,6 @@ export interface SignatureFieldStatus {
316
327
  fieldName: string;
317
328
  pageNumber: number;
318
329
  signed: boolean;
319
- /** Present when the field is tagged with a host role. */
320
- roleId?: string;
321
330
  }
322
331
  export interface DetectedShapeRect {
323
332
  x: number;
@@ -6,8 +6,7 @@ import {
6
6
  PDFDict,
7
7
  PDFName,
8
8
  PDFRawStream,
9
- PDFString,
10
- StandardFonts
9
+ PDFString
11
10
  } from "pdf-lib";
12
11
  import { CHECKBOX_STYLE_TABLE } from "../checkbox-styles.js";
13
12
  export async function writeFormFieldsToPdf(pdfDoc, fieldValues, placedDefinitions = []) {
@@ -265,7 +264,7 @@ async function createSignatureField(pdfDoc, page, def, fv) {
265
264
  if (def.required) sig.setFlagTo(AcroFieldFlags.Required, true);
266
265
  const v = fv?.value;
267
266
  const signed = typeof v === "string" && v.startsWith("data:image");
268
- const appearanceRef = signed ? await buildSignedSignatureAppearance(pdfDoc, v, width, height) : await buildSignaturePlaceholderAppearance(pdfDoc, width, height);
267
+ const appearanceRef = signed ? await buildSignedSignatureAppearance(pdfDoc, v, width, height) : buildEmptySignatureAppearance(pdfDoc, width, height);
269
268
  const widgetDict = context.obj({
270
269
  Type: "Annot",
271
270
  Subtype: "Widget",
@@ -282,43 +281,21 @@ async function createSignatureField(pdfDoc, page, def, fv) {
282
281
  form.acroForm.addField(fieldRef);
283
282
  page.node.addAnnot(widgetRef);
284
283
  }
285
- async function buildSignaturePlaceholderAppearance(pdfDoc, width, height) {
284
+ function buildEmptySignatureAppearance(pdfDoc, width, height) {
286
285
  const { context } = pdfDoc;
287
- const font = await pdfDoc.embedFont(StandardFonts.Helvetica);
288
- const label = "Sign here";
289
- const fontSize = Math.max(6, Math.min(12, height * 0.4));
290
- const textWidth = font.widthOfTextAtSize(label, fontSize);
291
- const textHeight = font.heightAtSize(fontSize);
292
- const textX = (width - textWidth) / 2;
293
- const textY = (height - textHeight) / 2;
294
- const ops = [
295
- "q",
296
- "0.55 0.55 0.55 RG",
297
- "0.75 w",
298
- "[3 2] 0 d",
299
- `0.5 0.5 ${(width - 1).toFixed(3)} ${(height - 1).toFixed(3)} re`,
300
- "S",
301
- "0.55 0.55 0.55 rg",
302
- "BT",
303
- `/F1 ${fontSize.toFixed(3)} Tf`,
304
- `${textX.toFixed(3)} ${textY.toFixed(3)} Td`,
305
- `(${label}) Tj`,
306
- "ET",
307
- "Q"
308
- ].join("\n");
309
286
  const dict = context.obj({
310
287
  Type: "XObject",
311
288
  Subtype: "Form",
312
289
  BBox: [0, 0, width, height],
313
290
  Matrix: [1, 0, 0, 1, 0, 0],
314
- Resources: { Font: { F1: font.ref } }
291
+ Resources: {}
315
292
  });
316
- const stream = PDFRawStream.of(dict, new TextEncoder().encode(ops));
293
+ const stream = PDFRawStream.of(dict, new Uint8Array(0));
317
294
  return context.register(stream);
318
295
  }
319
296
  async function buildSignedSignatureAppearance(pdfDoc, dataUrl, width, height) {
320
297
  const match = dataUrl.match(/^data:(image\/[a-zA-Z0-9.+-]+);base64,(.+)$/);
321
- if (!match) return buildSignaturePlaceholderAppearance(pdfDoc, width, height);
298
+ if (!match) return buildEmptySignatureAppearance(pdfDoc, width, height);
322
299
  const mimeType = match[1] ?? "";
323
300
  const base64 = match[2] ?? "";
324
301
  const image = mimeType.includes("jpeg") || mimeType.includes("jpg") ? await pdfDoc.embedJpg(base64) : await pdfDoc.embedPng(base64);
@@ -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:color-mix(in srgb,var(--kvw-field-color,#1677ff) 14%,transparent);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:color-mix(in srgb,var(--kvw-field-color,#1677ff) 22%,transparent);border-color:rgba(0,0,0,.2)}.kviewer-form-input:focus{background-color:color-mix(in srgb,var(--kvw-field-color,#1677ff) 28%,transparent);border-color:var(--kvw-field-color,var(--color-primary,#3b82f6));outline:2px solid var(--kvw-field-color,var(--color-primary,#3b82f6))}.kviewer-form-uselect{align-items:center;background-color:color-mix(in srgb,var(--kvw-field-color,#1677ff) 14%,transparent);border:1px solid transparent;border-radius:0;box-sizing:border-box;color:#000;cursor:pointer;display:flex;height:100%;line-height:1;padding:0 11px 0 2px;width:100%}.kviewer-form-uselect:hover{background-color:color-mix(in srgb,var(--kvw-field-color,#1677ff) 22%,transparent);border-color:rgba(0,0,0,.2)}.kviewer-form-uselect:focus-visible{background-color:color-mix(in srgb,var(--kvw-field-color,#1677ff) 28%,transparent);outline:2px solid var(--kvw-field-color,var(--color-primary,#3b82f6));outline-offset:-2px}.kviewer-form-uselect:disabled{cursor:default}.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(--kvw-field-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(--kvw-field-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:color-mix(in srgb,var(--kvw-field-color,#3b82f6) 8%,transparent);border-color:var(--kvw-field-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}.kviewer-form-signature--static{cursor:default}.kviewer-form-signature--static:hover{background:rgba(255,255,200,.15);border-color:rgba(0,0,0,.2)}.kviewer-form-signature__marker{align-items:center;display:inline-flex;gap:4px}.kviewer-form-signature__marker-icon{flex:0 0 auto;height:12px;width:12px}
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-field--readonly.kviewer-form-field--placed{filter:grayscale(.6);opacity:.5}.kviewer-form-field--readonly .kviewer-form-signature,.kviewer-form-field--readonly .kviewer-form-signature:hover{background:rgba(255,255,200,.15);border-color:rgba(0,0,0,.2);cursor:not-allowed}.kviewer-form-input{background-color:color-mix(in srgb,var(--kvw-field-color,#1677ff) 14%,transparent);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:color-mix(in srgb,var(--kvw-field-color,#1677ff) 22%,transparent);border-color:rgba(0,0,0,.2)}.kviewer-form-input:focus{background-color:color-mix(in srgb,var(--kvw-field-color,#1677ff) 28%,transparent);border-color:var(--kvw-field-color,var(--color-primary,#3b82f6));outline:2px solid var(--kvw-field-color,var(--color-primary,#3b82f6))}.kviewer-form-uselect{align-items:center;background-color:color-mix(in srgb,var(--kvw-field-color,#1677ff) 14%,transparent);border:1px solid transparent;border-radius:0;box-sizing:border-box;color:#000;cursor:pointer;display:flex;height:100%;line-height:1;padding:0 11px 0 2px;width:100%}.kviewer-form-uselect:hover{background-color:color-mix(in srgb,var(--kvw-field-color,#1677ff) 22%,transparent);border-color:rgba(0,0,0,.2)}.kviewer-form-uselect:focus-visible{background-color:color-mix(in srgb,var(--kvw-field-color,#1677ff) 28%,transparent);outline:2px solid var(--kvw-field-color,var(--color-primary,#3b82f6));outline-offset:-2px}.kviewer-form-uselect:disabled{cursor:default}.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(--kvw-field-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(--kvw-field-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:color-mix(in srgb,var(--kvw-field-color,#3b82f6) 8%,transparent);border-color:var(--kvw-field-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}.kviewer-form-field--editable .kviewer-form-signature,.kviewer-form-field__body--locked .kviewer-form-signature,.kviewer-form-field__body--locked .kviewer-form-signature:hover{border-color:transparent}.kviewer-form-signature--static{cursor:default}.kviewer-form-signature--static:hover{background:rgba(255,255,200,.15);border-color:rgba(0,0,0,.2)}.kviewer-form-signature__marker{align-items:center;display:inline-flex;gap:4px}.kviewer-form-signature__marker-icon{flex:0 0 auto;height:12px;width:12px}
@@ -55,6 +55,9 @@
55
55
  <UIcon name="i-lucide-pencil" class="text-sm text-muted" />
56
56
  </button>
57
57
 
58
+ <!-- Host-supplied custom items (selectionItems prop) -->
59
+ <SelectionToolbarItems :items="customItems" :ctx="selectionCtx" />
60
+
58
61
  <!-- Delete -->
59
62
  <button
60
63
  class="flex items-center justify-center w-7 h-7 rounded-md hover:bg-default cursor-pointer"
@@ -69,12 +72,20 @@
69
72
  </template>
70
73
 
71
74
  <script setup>
72
- import { computed } from "vue";
75
+ import { computed, inject } from "vue";
73
76
  import { useViewerState } from "../composables/useViewerState";
74
77
  import { useKviewerI18n } from "../composables/useKviewerI18n";
75
78
  import { defaultOptions, annotationDefinitions } from "../annotation/engine/config";
76
79
  import { AnnotationType } from "../annotation/engine/types";
80
+ import { SELECTION_ITEMS_KEY } from "../selection-items";
81
+ import SelectionToolbarItems from "./SelectionToolbarItems.vue";
77
82
  const state = useViewerState();
83
+ const customItems = inject(SELECTION_ITEMS_KEY, void 0);
84
+ const selectionCtx = computed(() => ({
85
+ kind: "annotation",
86
+ annotations: state.selectedAnnotations.value.length > 0 ? state.selectedAnnotations.value : state.selectedAnnotation.value ? [state.selectedAnnotation.value] : [],
87
+ field: null
88
+ }));
78
89
  const { t } = useKviewerI18n();
79
90
  const colors = defaultOptions.colors;
80
91
  const isMultiSelect = computed(() => state.selectedAnnotations.value.length > 1);
@@ -2,6 +2,7 @@
2
2
  <div
3
3
  v-if="fields.length > 0"
4
4
  class="kviewer-form-layer"
5
+ :class="{ 'kviewer-form-layer--interactive': props.pointerEvents === 'auto' }"
5
6
  :style="{
6
7
  position: 'absolute',
7
8
  top: 0,
@@ -11,7 +12,6 @@
11
12
  transform: `scale(${props.scale})`,
12
13
  transformOrigin: '0 0',
13
14
  zIndex: props.zIndex,
14
- pointerEvents: props.pointerEvents,
15
15
  // Force native form controls (inputs, checkboxes, radios, scrollbars)
16
16
  // to render in light mode regardless of the user\'s OS theme — PDF
17
17
  // pages have a white background, so dark-mode controls clash.
@@ -57,7 +57,8 @@ watch(() => state.formEditMode.value, (enabled) => {
57
57
  });
58
58
  watch(() => state.activeTool.value, (tool) => {
59
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);
60
+ const keepsSelection = tool === "hand" || tool === AnnotationType.SELECT || isFormFieldTool;
61
+ if (!keepsSelection) formFields.selectPlacedField(null);
61
62
  });
62
63
  function onKeyDown(e) {
63
64
  if (!selectedFieldId.value) return;
@@ -75,3 +76,7 @@ onBeforeUnmount(() => {
75
76
  window.removeEventListener("keydown", onKeyDown);
76
77
  });
77
78
  </script>
79
+
80
+ <style>
81
+ .kviewer-form-layer{pointer-events:none}.kviewer-form-layer--interactive .kviewer-form-field{pointer-events:auto}.kviewer-form-layer:not(.kviewer-form-layer--interactive) .kviewer-form-field,.kviewer-form-layer:not(.kviewer-form-layer--interactive) .kviewer-placed-chrome,.kviewer-form-layer:not(.kviewer-form-layer--interactive) .kviewer-placed-toolbar{pointer-events:none}
82
+ </style>
@@ -63,6 +63,7 @@
63
63
  height: cssHeight + 'px',
64
64
  zIndex: 3,
65
65
  pointerEvents: annotationPointerEvents,
66
+ cursor: annotationCursor,
66
67
  transform: 'translateZ(0)',
67
68
  overflow: 'hidden'
68
69
  }"
@@ -134,9 +135,31 @@ const annotationPointerEvents = computed(() => {
134
135
  if (state.readonly.value) return "none";
135
136
  return isSearchTextInteractive.value ? "none" : isAnnotating.value ? "auto" : "none";
136
137
  });
138
+ const annotationCursor = computed(() => {
139
+ const tool = state.activeTool.value;
140
+ if (tool === "marquee" || tool === "eraser") return "crosshair";
141
+ if (typeof tool !== "number") return "";
142
+ switch (tool) {
143
+ case AnnotationType.NONE:
144
+ case AnnotationType.SELECT:
145
+ return "";
146
+ // Stamp/signature hide the native cursor behind a floating image
147
+ // preview (body cursor 'none'); an element cursor here would
148
+ // override that and bring the arrow back on top of the preview.
149
+ case AnnotationType.STAMP:
150
+ case AnnotationType.SIGNATURE:
151
+ return "";
152
+ case AnnotationType.HIGHLIGHT:
153
+ case AnnotationType.STRIKEOUT:
154
+ case AnnotationType.UNDERLINE:
155
+ return "text";
156
+ default:
157
+ return "crosshair";
158
+ }
159
+ });
137
160
  const isUsingAnnotationTool = computed(() => {
138
161
  const tool = state.activeTool.value;
139
- return tool === "marquee" || tool === "eraser" || typeof tool === "number" && tool !== AnnotationType.NONE;
162
+ return tool === "marquee" || tool === "eraser" || typeof tool === "number" && tool !== AnnotationType.NONE && tool !== AnnotationType.SELECT;
140
163
  });
141
164
  const formFieldPointerEvents = computed(() => {
142
165
  if (state.readonly.value) return "none";
@@ -0,0 +1,8 @@
1
+ import type { ViewerSelectionContext, ViewerSelectionItem } from '../selection-items.js';
2
+ type __VLS_Props = {
3
+ items: ViewerSelectionItem[] | undefined;
4
+ ctx: ViewerSelectionContext;
5
+ };
6
+ 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>;
7
+ declare const _default: typeof __VLS_export;
8
+ export default _default;
@@ -0,0 +1,43 @@
1
+ <template>
2
+ <template v-for="item in visibleItems" :key="item.key">
3
+ <button
4
+ v-if="item.type === 'button'"
5
+ class="flex items-center justify-center h-7 rounded-md hover:bg-default cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed"
6
+ :class="item.icon ? 'w-7' : 'px-2'"
7
+ :title="item.label"
8
+ :disabled="item.disabled"
9
+ :data-testid="`selection-item-${item.key}`"
10
+ @click="item.onSelect(props.ctx)"
11
+ >
12
+ <UIcon v-if="item.icon" :name="item.icon" class="text-sm text-muted" />
13
+ <span v-else class="text-xs text-muted whitespace-nowrap">{{ item.label }}</span>
14
+ </button>
15
+ <USelect
16
+ v-else-if="item.type === 'select'"
17
+ :model-value="selectValue(item)"
18
+ :items="item.items"
19
+ :placeholder="item.placeholder"
20
+ :disabled="item.disabled"
21
+ :aria-label="item.label"
22
+ :title="item.label"
23
+ class="w-24"
24
+ size="sm"
25
+ :data-testid="`selection-item-${item.key}`"
26
+ @update:model-value="(v) => item.onUpdate(String(v), props.ctx)"
27
+ />
28
+ </template>
29
+ </template>
30
+
31
+ <script setup>
32
+ import { computed } from "vue";
33
+ const props = defineProps({
34
+ items: { type: null, required: true },
35
+ ctx: { type: Object, required: true }
36
+ });
37
+ const visibleItems = computed(
38
+ () => (props.items ?? []).filter((item) => item.visible?.(props.ctx) ?? true)
39
+ );
40
+ function selectValue(item) {
41
+ return typeof item.value === "function" ? item.value(props.ctx) : item.value;
42
+ }
43
+ </script>
@@ -0,0 +1,8 @@
1
+ import type { ViewerSelectionContext, ViewerSelectionItem } from '../selection-items.js';
2
+ type __VLS_Props = {
3
+ items: ViewerSelectionItem[] | undefined;
4
+ ctx: ViewerSelectionContext;
5
+ };
6
+ 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>;
7
+ declare const _default: typeof __VLS_export;
8
+ export default _default;
@@ -3,6 +3,7 @@ import type { AddFormFieldPayload, FormFieldDefinition, IAnnotationStore, Placed
3
3
  import { type ExportPdfOptions } from '../annotation/pdf-export/export.js';
4
4
  import type { ViewerMenuItem } from '../menu-items.js';
5
5
  import type { ViewerToolEntry } from '../toolbar-tools.js';
6
+ import { type ViewerSelectionItem } from '../selection-items.js';
6
7
  import { type KviewerMessageOverrides } from '../composables/useKviewerI18n.js';
7
8
  import { type KviewerLocale } from '../i18n/messages.js';
8
9
  type __VLS_Props = {
@@ -25,16 +26,6 @@ type __VLS_Props = {
25
26
  * with selection chrome, can be moved/resized, and the property panel
26
27
  * is shown. Supports v-model via `v-model:form-edit-mode`. */
27
28
  formEditMode?: boolean;
28
- /** Map of roleId → CSS color used to color-code form fields in
29
- * form-edit mode. The editor stays unopinionated about role
30
- * definitions: the host owns the role list, names, and color picker,
31
- * and just hands a flat lookup table to the viewer. Unknown or
32
- * missing ids fall back to the default blue. */
33
- roleColors?: Record<string, string>;
34
- /** Active role id new field placements are auto-tagged with. The host
35
- * drives this — typically by binding it to a role picker in its own
36
- * UI. Supports v-model via `v-model:active-role-id`. */
37
- activeRoleId?: string | null;
38
29
  /** When true, clicking an unsigned signature field opens kviewer's own
39
30
  * signing flow (saved signature or draw modal). Off by default so hosts
40
31
  * that own the signing process (e.g. an embedding e-sign app) don't get
@@ -63,6 +54,11 @@ type __VLS_Props = {
63
54
  * toggles or actions without replacing the entire header. Ignored
64
55
  * when the host supplies a custom `#header` slot. */
65
56
  menuItems?: ViewerMenuItem[];
57
+ /** Custom controls appended to the floating selection popover — shown
58
+ * when an annotation or a placed form field (e.g. a signature field)
59
+ * is selected. Buttons and selects; every callback receives the
60
+ * current selection. See {@link ViewerSelectionItem}. */
61
+ selectionItems?: ViewerSelectionItem[];
66
62
  /** Configures which toolbar tools render and in what order. Entries are
67
63
  * built-in tool IDs (strings) or `{ type: 'slot', ... }` objects that
68
64
  * inject a custom button via a `#tool-<name>` slot. When omitted, the
@@ -116,9 +112,11 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
116
112
  * The new field is exported into the PDF on `exportPdf()` like any
117
113
  * field placed via the placement tool. */
118
114
  addFormField: (payload: AddFormFieldPayload) => FormFieldDefinition;
119
- /** Patch a form field by id (rect, name, flags, type-specific props). */
115
+ /** Patch a form field by id (rect, name, flags, type-specific props).
116
+ * Does not fire `field-updated` — that event is for user-driven edits. */
120
117
  updateFormField: (id: string, patch: Partial<FormFieldDefinition>) => void;
121
- /** Remove a form field by id (drops its value too). */
118
+ /** Remove a form field by id (drops its value too). Does not fire
119
+ * `field-removed` — that event is for user-driven removals. */
122
120
  removeFormField: (id: string) => void;
123
121
  /** All form-field definitions (parsed, detected, and placed), flat. */
124
122
  getFormFields: () => FormFieldDefinition[];
@@ -132,6 +130,14 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
132
130
  * `field-placed` event, used by the embed bridge). Returns an
133
131
  * unsubscribe function. */
134
132
  onFieldPlaced: (cb: (field: FormFieldDefinition) => void) => (() => void);
133
+ /** Subscribe to user-driven field edits (imperative mirror of the
134
+ * `field-updated` event, used by the embed bridge). Returns an
135
+ * unsubscribe function. */
136
+ onFieldUpdated: (cb: (field: FormFieldDefinition, patch: Partial<FormFieldDefinition>) => void) => (() => void);
137
+ /** Subscribe to user-driven field removals (imperative mirror of the
138
+ * `field-removed` event, used by the embed bridge). Returns an
139
+ * unsubscribe function. */
140
+ onFieldRemoved: (cb: (field: FormFieldDefinition) => void) => (() => void);
135
141
  /** True once every signature field in the document is signed — via a
136
142
  * value applied in this session or a digital signature already in the
137
143
  * source PDF. Vacuously true when the document has no signature
@@ -139,7 +145,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
139
145
  * need "at least one". Use to gate e.g. envelope finalization. */
140
146
  getSignedStatus: () => boolean;
141
147
  /** Per-widget signed-state snapshot (id, fieldName, pageNumber,
142
- * signed, roleId). */
148
+ * signed). Correlate to host data by `id`. */
143
149
  getSignatureFieldStatus: () => SignatureFieldStatus[];
144
150
  /** Subscribe to signed-status changes (imperative mirror of the
145
151
  * `signed-status-changed` event, used by the embed bridge). Returns
@@ -165,8 +171,9 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
165
171
  }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
166
172
  "all-pages-read": () => any;
167
173
  "field-placed": (field: FormFieldDefinition) => any;
174
+ "field-updated": (field: FormFieldDefinition, patch: Partial<FormFieldDefinition>) => any;
175
+ "field-removed": (field: FormFieldDefinition) => any;
168
176
  "update:formEditMode": (value: boolean) => any;
169
- "update:activeRoleId": (value: string | null) => any;
170
177
  "update:viewedPages": (pages: number[]) => any;
171
178
  "signed-status-changed": (payload: {
172
179
  allSigned: boolean;
@@ -175,8 +182,9 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
175
182
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
176
183
  "onAll-pages-read"?: (() => any) | undefined;
177
184
  "onField-placed"?: ((field: FormFieldDefinition) => any) | undefined;
185
+ "onField-updated"?: ((field: FormFieldDefinition, patch: Partial<FormFieldDefinition>) => any) | undefined;
186
+ "onField-removed"?: ((field: FormFieldDefinition) => any) | undefined;
178
187
  "onUpdate:formEditMode"?: ((value: boolean) => any) | undefined;
179
- "onUpdate:activeRoleId"?: ((value: string | null) => any) | undefined;
180
188
  "onUpdate:viewedPages"?: ((pages: number[]) => any) | undefined;
181
189
  "onSigned-status-changed"?: ((payload: {
182
190
  allSigned: boolean;
@@ -198,10 +206,9 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
198
206
  signatureHandlers: SignatureHandlers;
199
207
  viewMode: ViewMode;
200
208
  shapeDetection: boolean;
201
- roleColors: Record<string, string>;
202
- activeRoleId: string | null;
203
209
  editablePlacedFields: boolean;
204
210
  fieldDefaults: PlacedFieldDefaults;
211
+ selectionItems: ViewerSelectionItem[];
205
212
  messages: KviewerMessageOverrides;
206
213
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
207
214
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;