visio-angular-viewer 0.8.0 → 1.0.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/dist/index.js CHANGED
@@ -180,6 +180,7 @@ var VisioViewerComponent = class VisioViewerComponent {
180
180
  this.shapeSelect = new EventEmitter();
181
181
  this.selectionChange = new EventEmitter();
182
182
  this.ribbonAddIn = new EventEmitter();
183
+ this.collaborationChange = new EventEmitter();
183
184
  this.host = inject(ElementRef);
184
185
  this.handle = viewerHandle(() => this.binding);
185
186
  this.stopState = () => {};
@@ -193,7 +194,8 @@ var VisioViewerComponent = class VisioViewerComponent {
193
194
  "zoom-change": this.zoomChange,
194
195
  "shape-select": this.shapeSelect,
195
196
  "selection-change": this.selectionChange,
196
- "office-ribbon-add-in": this.ribbonAddIn
197
+ "office-ribbon-add-in": this.ribbonAddIn,
198
+ "collaboration-change": this.collaborationChange
197
199
  };
198
200
  }
199
201
  options() {
@@ -291,6 +293,7 @@ __decorate([Input()], VisioViewerComponent.prototype, "zoom", void 0);
291
293
  __decorate([Input()], VisioViewerComponent.prototype, "showToolbar", void 0);
292
294
  __decorate([Input()], VisioViewerComponent.prototype, "canEdit", void 0);
293
295
  __decorate([Input()], VisioViewerComponent.prototype, "ribbonAddIns", void 0);
296
+ __decorate([Input()], VisioViewerComponent.prototype, "collaboration", void 0);
294
297
  __decorate([Input()], VisioViewerComponent.prototype, "events", void 0);
295
298
  __decorate([Output()], VisioViewerComponent.prototype, "documentLoad", void 0);
296
299
  __decorate([Output()], VisioViewerComponent.prototype, "documentChange", void 0);
@@ -300,6 +303,7 @@ __decorate([Output()], VisioViewerComponent.prototype, "zoomChange", void 0);
300
303
  __decorate([Output()], VisioViewerComponent.prototype, "shapeSelect", void 0);
301
304
  __decorate([Output()], VisioViewerComponent.prototype, "selectionChange", void 0);
302
305
  __decorate([Output()], VisioViewerComponent.prototype, "ribbonAddIn", void 0);
306
+ __decorate([Output()], VisioViewerComponent.prototype, "collaborationChange", void 0);
303
307
  VisioViewerComponent = __decorate([Component({
304
308
  selector: "visio-viewer-host",
305
309
  standalone: true,
@@ -312,10 +316,15 @@ function buildingBlock(key) {
312
316
  if (typeof value !== "function") throw new Error("Update ooxml-ui to use Visio building blocks.");
313
317
  return value;
314
318
  }
319
+ /** The mode a host sees: 'edit' only when permission is granted and the file can be saved back. */
320
+ function effectiveMode(state) {
321
+ return buildingBlock("diagramMode")(state);
322
+ }
315
323
  /** Framework-neutral ownership only; each adapter supplies its own reactive state. */
316
- function createBuildingBlockSession() {
324
+ function createBuildingBlockSession(initial = {}) {
317
325
  const controller = new ViewerController(createWorkerParser());
318
- let options = {};
326
+ controller.canEdit = initial.canEdit === true;
327
+ let options = initial;
319
328
  let source;
320
329
  let host = null;
321
330
  let disposeCanvas;
@@ -339,13 +348,23 @@ function createBuildingBlockSession() {
339
348
  host = node;
340
349
  if (node) disposeCanvas = buildingBlock("mountDiagramCanvas")(node, controller);
341
350
  },
342
- toolbar(locale = options.locale) {
343
- return buildingBlock("diagramToolbarProps")(controller, fit, locale);
351
+ /** Flat control props; pass the framework's latest options so callbacks stay current. */
352
+ toolbar(latest = options) {
353
+ return buildingBlock("diagramToolbarProps")(controller, fit, latest.locale, {
354
+ onOpenFile: latest.onOpenFile,
355
+ onOpenPageSetup: latest.onOpenPageSetup,
356
+ onOpenSettings: latest.onOpenSettings,
357
+ onOpenShareDialog: latest.onOpenShareDialog
358
+ });
359
+ },
360
+ /** Acknowledge a host save: clears dirty and emits the dirty change. */
361
+ markClean() {
362
+ controller.markClean();
344
363
  },
345
364
  update(next) {
346
365
  if (destroyed) return;
347
366
  options = next;
348
- controller.canEdit = next.canEdit !== false;
367
+ controller.canEdit = next.canEdit === true;
349
368
  if (source === next.content) return;
350
369
  source = next.content;
351
370
  controller.cancelLoad();
@@ -374,25 +393,110 @@ function prepareDiagramBlock(host, kind) {
374
393
  prepare(host, kind, "visio");
375
394
  }
376
395
  //#endregion
396
+ //#region packages/bindings/src/toolbar-controls.ts
397
+ var TOOLBAR_GROUPS = [
398
+ "file",
399
+ "history",
400
+ "zoom",
401
+ "selection",
402
+ "clipboard",
403
+ "tools",
404
+ "search"
405
+ ];
406
+ var fire = (action) => () => {
407
+ Promise.resolve().then(action).catch(() => {});
408
+ };
409
+ var button = (id, label, enabled, action, pressed) => ({
410
+ kind: "button",
411
+ id,
412
+ label,
413
+ disabled: !enabled,
414
+ ...pressed === void 0 ? {} : { pressed },
415
+ run: fire(action)
416
+ });
417
+ /**
418
+ * What the library Toolbar shows, as plain data every framework maps onto its own elements.
419
+ * Every control reflects `toolbarProps`: edit actions are disabled while the diagram is read-only,
420
+ * viewing actions (zoom, fit, search) never are, and a host dialog button appears only when the
421
+ * host supplied its callback.
422
+ */
423
+ function toolbarGroups(props, include = TOOLBAR_GROUPS) {
424
+ const { labels } = props;
425
+ const has = props.pages.length > 0;
426
+ const groups = [];
427
+ const add = (id, controls) => {
428
+ if (include.includes(id) && controls.length) groups.push({
429
+ id,
430
+ controls
431
+ });
432
+ };
433
+ add("file", [
434
+ ...props.onOpenFile ? [button("open", labels.Open, true, props.onOpenFile)] : [],
435
+ ...props.onOpenPageSetup ? [button("page-setup", labels["Page Setup"], has, props.onOpenPageSetup)] : [],
436
+ ...props.onOpenShareDialog ? [button("share", labels.Share, has, props.onOpenShareDialog)] : [],
437
+ ...props.onOpenSettings ? [button("settings", labels.Options, true, props.onOpenSettings)] : []
438
+ ]);
439
+ add("history", [button("undo", labels.Undo, props.canUndo, props.onUndo), button("redo", labels.Redo, props.canRedo, props.onRedo)]);
440
+ add("zoom", [
441
+ button("zoom-out", labels["Zoom Out"], props.canZoomOut, props.onZoomOut),
442
+ {
443
+ kind: "text",
444
+ id: "zoom",
445
+ text: `${Math.round(props.zoom * 100)}%`
446
+ },
447
+ button("zoom-in", labels["Zoom In"], props.canZoomIn, props.onZoomIn),
448
+ button("fit", labels["Fit to Window"], has, props.onFit)
449
+ ]);
450
+ add("selection", [
451
+ button("duplicate", labels.Duplicate, props.canDuplicate, props.onDuplicate),
452
+ button("group", labels.Group, props.canGroup, props.onGroup),
453
+ button("ungroup", labels.Ungroup, props.canUngroup, props.onUngroup),
454
+ button("delete", labels.Delete, props.canDelete, props.onDelete)
455
+ ]);
456
+ add("clipboard", [
457
+ button("cut", labels.Cut, props.canCut, props.onCut),
458
+ button("copy", labels.Copy, props.canCopy, props.onCopy),
459
+ button("paste", labels.Paste, props.canPaste, props.onPaste)
460
+ ]);
461
+ add("tools", props.tools.map((tool) => button(`tool-${tool.id}`, tool.label, tool.id === "pointer" || props.canDraw, () => props.onToolChange(tool.id), tool.active)));
462
+ const { search } = props;
463
+ add("search", [{
464
+ kind: "search",
465
+ id: "search",
466
+ label: labels.Find,
467
+ query: search.query,
468
+ summary: search.query ? search.resultCount ? `${search.activeIndex >= 0 ? search.activeIndex + 1 : "-"} / ${search.resultCount}` : "0" : "",
469
+ previous: button("search-previous", labels["Previous Result"], search.resultCount > 0, props.onPreviousSearchResult),
470
+ next: button("search-next", labels["Next Result"], search.resultCount > 0, props.onNextSearchResult),
471
+ change: (query) => props.onSearchChange(query)
472
+ }]);
473
+ return groups;
474
+ }
475
+ //#endregion
377
476
  //#region packages/angular/src/building-blocks.ts
378
477
  var ViewerBuildingBlocks = class ViewerBuildingBlocks {
379
478
  session = createBuildingBlockSession();
380
479
  controller = this.session.controller;
381
480
  current = signal(this.controller.state);
382
481
  state = this.current.asReadonly();
383
- locale = signal(void 0);
482
+ latest = signal({});
384
483
  toolbarProps = computed(() => {
385
484
  this.state();
386
- return this.session.toolbar(this.locale());
485
+ return this.session.toolbar(this.latest());
387
486
  });
388
487
  loading = computed(() => this.state().loading);
389
488
  error = computed(() => this.state().error ?? this.state().edit.error);
390
- mode = computed(() => this.state().canEdit ? "edit" : "view");
489
+ /** Effective permission: host `canEdit` and a drawing that can be saved back. */
490
+ mode = computed(() => effectiveMode(this.state()));
391
491
  documentChange = new EventEmitter();
392
492
  dirtyChange = new EventEmitter();
393
493
  documentError = new EventEmitter();
394
494
  canvasProps = { mount: (node) => this.session.mount(node) };
395
495
  inspectorProps = { controller: this.controller };
496
+ shapesProps = computed(() => ({
497
+ controller: this.controller,
498
+ locale: this.latest().locale
499
+ }));
396
500
  constructor() {
397
501
  this.update({});
398
502
  const stop = this.controller.subscribe((state) => this.current.set(state));
@@ -401,8 +505,12 @@ var ViewerBuildingBlocks = class ViewerBuildingBlocks {
401
505
  this.session.destroy();
402
506
  });
403
507
  }
508
+ /** Acknowledge a host save: clears dirty and emits `dirtyChange(false)`. */
509
+ markClean() {
510
+ this.session.markClean();
511
+ }
404
512
  update(options) {
405
- this.locale.set(options.locale);
513
+ this.latest.set(options);
406
514
  this.session.update({
407
515
  ...options,
408
516
  onDocumentChange: (document) => {
@@ -433,8 +541,13 @@ function createViewerBuildingBlocks(options = () => ({})) {
433
541
  var ViewerBuildingBlocksComponent = class ViewerBuildingBlocksComponent {
434
542
  blocks = inject(ViewerBuildingBlocks);
435
543
  content;
436
- canEdit = true;
544
+ /** Host edit permission. Read-only until `true`. */
545
+ canEdit = false;
437
546
  locale;
547
+ onOpenFile;
548
+ onOpenPageSetup;
549
+ onOpenSettings;
550
+ onOpenShareDialog;
438
551
  documentChange = this.blocks.documentChange;
439
552
  dirtyChange = this.blocks.dirtyChange;
440
553
  documentError = this.blocks.documentError;
@@ -445,13 +558,21 @@ var ViewerBuildingBlocksComponent = class ViewerBuildingBlocksComponent {
445
558
  this.blocks.update({
446
559
  content: this.content,
447
560
  canEdit: this.canEdit,
448
- locale: this.locale
561
+ locale: this.locale,
562
+ onOpenFile: this.onOpenFile,
563
+ onOpenPageSetup: this.onOpenPageSetup,
564
+ onOpenSettings: this.onOpenSettings,
565
+ onOpenShareDialog: this.onOpenShareDialog
449
566
  });
450
567
  }
451
568
  };
452
569
  __decorate([Input()], ViewerBuildingBlocksComponent.prototype, "content", void 0);
453
570
  __decorate([Input()], ViewerBuildingBlocksComponent.prototype, "canEdit", void 0);
454
571
  __decorate([Input()], ViewerBuildingBlocksComponent.prototype, "locale", void 0);
572
+ __decorate([Input()], ViewerBuildingBlocksComponent.prototype, "onOpenFile", void 0);
573
+ __decorate([Input()], ViewerBuildingBlocksComponent.prototype, "onOpenPageSetup", void 0);
574
+ __decorate([Input()], ViewerBuildingBlocksComponent.prototype, "onOpenSettings", void 0);
575
+ __decorate([Input()], ViewerBuildingBlocksComponent.prototype, "onOpenShareDialog", void 0);
455
576
  __decorate([Output()], ViewerBuildingBlocksComponent.prototype, "documentChange", void 0);
456
577
  __decorate([Output()], ViewerBuildingBlocksComponent.prototype, "dirtyChange", void 0);
457
578
  __decorate([Output()], ViewerBuildingBlocksComponent.prototype, "documentError", void 0);
@@ -478,30 +599,83 @@ DiagramCanvasComponent = __decorate([Component({
478
599
  })], DiagramCanvasComponent);
479
600
  var ToolbarComponent = class ToolbarComponent {
480
601
  host = inject(ElementRef);
602
+ /** Groups to show; omit for all. Hosts may build their own controls from toolbarProps. */
603
+ include;
481
604
  ngAfterViewInit() {
482
605
  prepareDiagramBlock(this.host.nativeElement.querySelector("div"), "toolbar");
483
606
  }
484
607
  blocks = inject(ViewerBuildingBlocks);
608
+ groups() {
609
+ return toolbarGroups(this.blocks.toolbarProps(), this.include);
610
+ }
611
+ asText(control) {
612
+ return control;
613
+ }
614
+ asButton(control) {
615
+ return control;
616
+ }
617
+ asSearch(control) {
618
+ return control;
619
+ }
620
+ value(event) {
621
+ return event.target.value;
622
+ }
485
623
  };
624
+ __decorate([Input()], ToolbarComponent.prototype, "include", void 0);
486
625
  ToolbarComponent = __decorate([Component({
487
626
  selector: "visio-diagram-toolbar",
488
627
  standalone: true,
489
628
  template: `<div role="toolbar">
490
- <button
491
- type="button"
492
- [disabled]="!blocks.toolbarProps().canUndo"
493
- (click)="blocks.toolbarProps().onUndo()"
494
- >
495
- {{ blocks.toolbarProps().labels['Undo'] }}</button
496
- ><button
497
- type="button"
498
- [disabled]="!blocks.toolbarProps().canRedo"
499
- (click)="blocks.toolbarProps().onRedo()"
500
- >
501
- {{ blocks.toolbarProps().labels['Redo'] }}</button
502
- ><button type="button" (click)="blocks.toolbarProps().onFit()">
503
- {{ blocks.toolbarProps().labels['Fit to Window'] }}
504
- </button>
629
+ @for (group of groups(); track group.id) {
630
+ <span [attr.data-group]="group.id">
631
+ @for (control of group.controls; track control.id) {
632
+ @switch (control.kind) {
633
+ @case ('text') {
634
+ <span [attr.data-control]="control.id">{{ asText(control).text }}</span>
635
+ }
636
+ @case ('button') {
637
+ <button
638
+ type="button"
639
+ [attr.data-control]="control.id"
640
+ [disabled]="asButton(control).disabled"
641
+ [attr.aria-pressed]="asButton(control).pressed ?? null"
642
+ (click)="asButton(control).run()"
643
+ >
644
+ {{ asButton(control).label }}
645
+ </button>
646
+ }
647
+ @default {
648
+ <span data-control="search">
649
+ <input
650
+ type="search"
651
+ [attr.aria-label]="asSearch(control).label"
652
+ [attr.placeholder]="asSearch(control).label"
653
+ [value]="asSearch(control).query"
654
+ (input)="asSearch(control).change(value($event))"
655
+ />
656
+ <span aria-live="polite">{{ asSearch(control).summary }}</span>
657
+ <button
658
+ type="button"
659
+ [attr.data-control]="asSearch(control).previous.id"
660
+ [disabled]="asSearch(control).previous.disabled"
661
+ (click)="asSearch(control).previous.run()"
662
+ >
663
+ {{ asSearch(control).previous.label }}
664
+ </button>
665
+ <button
666
+ type="button"
667
+ [attr.data-control]="asSearch(control).next.id"
668
+ [disabled]="asSearch(control).next.disabled"
669
+ (click)="asSearch(control).next.run()"
670
+ >
671
+ {{ asSearch(control).next.label }}
672
+ </button>
673
+ </span>
674
+ }
675
+ }
676
+ }
677
+ </span>
678
+ }
505
679
  </div>`
506
680
  })], ToolbarComponent);
507
681
  var PageNavigationComponent = class PageNavigationComponent {
@@ -543,5 +717,21 @@ InspectorComponent = __decorate([Component({
543
717
  standalone: true,
544
718
  template: ""
545
719
  })], InspectorComponent);
720
+ var ShapesPaneComponent = class ShapesPaneComponent {
721
+ blocks = inject(ViewerBuildingBlocks);
722
+ host = inject(ElementRef);
723
+ stop;
724
+ ngAfterViewInit() {
725
+ this.stop = buildingBlock("mountDiagramShapes")(this.host.nativeElement, this.blocks.controller, { locale: this.blocks.shapesProps().locale });
726
+ }
727
+ ngOnDestroy() {
728
+ this.stop?.();
729
+ }
730
+ };
731
+ ShapesPaneComponent = __decorate([Component({
732
+ selector: "visio-shapes-pane",
733
+ standalone: true,
734
+ template: ""
735
+ })], ShapesPaneComponent);
546
736
  //#endregion
547
- export { DiagramCanvasComponent, InspectorComponent, PageNavigationComponent, ToolbarComponent, ViewerBuildingBlocks, ViewerBuildingBlocksComponent, VisioViewerComponent, createViewerBuildingBlocks };
737
+ export { DiagramCanvasComponent, InspectorComponent, PageNavigationComponent, ShapesPaneComponent, ToolbarComponent, ViewerBuildingBlocks, ViewerBuildingBlocksComponent, VisioViewerComponent, createViewerBuildingBlocks };
@@ -1,15 +1,15 @@
1
1
  import { EventEmitter, type AfterViewInit, type OnChanges, type OnDestroy, type OnInit } from '@angular/core';
2
2
  import { type BuildingBlockOptions } from '../../bindings/src/building-blocks.js';
3
+ import { type ToolbarButton, type ToolbarControl, type ToolbarGroupId, type ToolbarSearch, type ToolbarText } from '../../bindings/src/toolbar-controls.js';
3
4
  export declare class ViewerBuildingBlocks {
4
5
  private readonly session;
5
6
  readonly controller: import("ooxml-ui/visio").ViewerController;
6
7
  private readonly current;
7
8
  readonly state: import("@angular/core").Signal<import("ooxml-ui/visio").ViewerState>;
8
- private readonly locale;
9
+ private readonly latest;
9
10
  readonly toolbarProps: import("@angular/core").Signal<{
10
- labels: {
11
- [k: string]: string;
12
- };
11
+ labels: Readonly<Record<"Arc" | "Copy" | "Cut" | "Delete" | "Duplicate" | "Ellipse" | "Find" | "Fit to Window" | "Freeform" | "Group" | "Line" | "Next Result" | "Open" | "Options" | "Page" | "Page Setup" | "Paste" | "Pencil" | "Pointer Tool" | "Previous Result" | "Rectangle" | "Redo" | "Shapes" | "Share" | "Undo" | "Ungroup" | "Zoom In" | "Zoom Out", string>>;
12
+ mode: import("ooxml-ui/visio").DiagramMode;
13
13
  canEdit: boolean;
14
14
  pageIndex: number;
15
15
  pages: {
@@ -23,21 +23,52 @@ export declare class ViewerBuildingBlocks {
23
23
  canDuplicate: boolean;
24
24
  canGroup: boolean;
25
25
  canUngroup: boolean;
26
+ canDelete: boolean;
27
+ canCut: boolean;
28
+ canCopy: boolean;
29
+ canPaste: boolean;
30
+ canDraw: boolean;
31
+ canZoomIn: boolean;
32
+ canZoomOut: boolean;
33
+ tool: import("ooxml-ui/visio").DiagramTool;
34
+ tools: import("ooxml-ui/visio").DiagramToolSummary[];
35
+ search: {
36
+ query: string;
37
+ resultCount: number;
38
+ activeIndex: number;
39
+ truncated: boolean;
40
+ };
26
41
  onPageChange: (index: number) => void;
27
42
  onZoomChange: (zoom: number) => void;
43
+ onZoomIn: () => void;
44
+ onZoomOut: () => void;
28
45
  onFit: () => void;
29
46
  onUndo: () => Promise<void>;
30
47
  onRedo: () => Promise<void>;
31
48
  onDuplicate: () => Promise<void>;
32
49
  onGroup: () => Promise<void>;
33
50
  onUngroup: () => Promise<void>;
51
+ onDelete: () => Promise<void>;
52
+ onCut: () => Promise<void>;
53
+ onCopy: () => Promise<void>;
54
+ onPaste: () => Promise<void>;
55
+ onToolChange: (tool: import("ooxml-ui/visio").DiagramTool) => void;
34
56
  onTextChange: (pageId: string, shapeId: string, text: string) => Promise<void>;
35
57
  onSearchChange: (query: string) => void;
36
58
  onNextSearchResult: () => void;
37
59
  onPreviousSearchResult: () => void;
60
+ canOpenFile: boolean;
61
+ canOpenPageSetup: boolean;
62
+ canOpenSettings: boolean;
63
+ canOpenShareDialog: boolean;
64
+ onOpenFile?: () => void;
65
+ onOpenPageSetup?: () => void;
66
+ onOpenSettings?: () => void;
67
+ onOpenShareDialog?: () => void;
38
68
  }>;
39
69
  readonly loading: import("@angular/core").Signal<boolean>;
40
70
  readonly error: import("@angular/core").Signal<Error | null>;
71
+ /** Effective permission: host `canEdit` and a drawing that can be saved back. */
41
72
  readonly mode: import("@angular/core").Signal<"edit" | "view">;
42
73
  readonly documentChange: EventEmitter<import("visio-core").VisioDocument>;
43
74
  readonly dirtyChange: EventEmitter<boolean>;
@@ -48,7 +79,13 @@ export declare class ViewerBuildingBlocks {
48
79
  readonly inspectorProps: {
49
80
  controller: import("ooxml-ui/visio").ViewerController;
50
81
  };
82
+ readonly shapesProps: import("@angular/core").Signal<{
83
+ controller: import("ooxml-ui/visio").ViewerController;
84
+ locale: string | undefined;
85
+ }>;
51
86
  constructor();
87
+ /** Acknowledge a host save: clears dirty and emits `dirtyChange(false)`. */
88
+ markClean(): void;
52
89
  update(options: BuildingBlockOptions): void;
53
90
  }
54
91
  /** Connect host signals to the scoped owner within an Angular injection context. */
@@ -56,8 +93,13 @@ export declare function createViewerBuildingBlocks(options?: () => BuildingBlock
56
93
  export declare class ViewerBuildingBlocksComponent implements OnChanges, OnInit {
57
94
  readonly blocks: ViewerBuildingBlocks;
58
95
  content?: BuildingBlockOptions['content'];
96
+ /** Host edit permission. Read-only until `true`. */
59
97
  canEdit: boolean;
60
98
  locale?: string;
99
+ onOpenFile?: () => void;
100
+ onOpenPageSetup?: () => void;
101
+ onOpenSettings?: () => void;
102
+ onOpenShareDialog?: () => void;
61
103
  readonly documentChange: EventEmitter<import("visio-core").VisioDocument>;
62
104
  readonly dirtyChange: EventEmitter<boolean>;
63
105
  readonly documentError: EventEmitter<Error>;
@@ -72,8 +114,15 @@ export declare class DiagramCanvasComponent implements AfterViewInit, OnDestroy
72
114
  }
73
115
  export declare class ToolbarComponent implements AfterViewInit {
74
116
  private readonly host;
117
+ /** Groups to show; omit for all. Hosts may build their own controls from toolbarProps. */
118
+ include?: readonly ToolbarGroupId[];
75
119
  ngAfterViewInit(): void;
76
120
  readonly blocks: ViewerBuildingBlocks;
121
+ groups(): import("../../bindings/src/toolbar-controls.js").ToolbarGroup[];
122
+ asText(control: ToolbarControl): ToolbarText;
123
+ asButton(control: ToolbarControl): ToolbarButton;
124
+ asSearch(control: ToolbarControl): ToolbarSearch;
125
+ value(event: Event): string;
77
126
  }
78
127
  export declare class PageNavigationComponent implements AfterViewInit {
79
128
  private readonly host;
@@ -88,4 +137,12 @@ export declare class InspectorComponent implements AfterViewInit, OnDestroy {
88
137
  ngAfterViewInit(): void;
89
138
  ngOnDestroy(): void;
90
139
  }
91
- export type { BuildingBlockOptions, DiagramToolbarProps } from '../../bindings/src/building-blocks.js';
140
+ export declare class ShapesPaneComponent implements AfterViewInit, OnDestroy {
141
+ readonly blocks: ViewerBuildingBlocks;
142
+ private readonly host;
143
+ private stop;
144
+ ngAfterViewInit(): void;
145
+ ngOnDestroy(): void;
146
+ }
147
+ export type { BuildingBlockOptions, BuildingBlockHostCallbacks, DiagramToolbarProps, } from '../../bindings/src/building-blocks.js';
148
+ export type { ToolbarGroupId } from '../../bindings/src/toolbar-controls.js';
@@ -8,12 +8,13 @@ export declare class VisioViewerComponent implements AfterViewInit, OnChanges, O
8
8
  showToolbar?: boolean;
9
9
  canEdit?: boolean;
10
10
  ribbonAddIns?: ViewerProperties['ribbonAddIns'];
11
+ collaboration?: ViewerProperties['collaboration'];
11
12
  events?: ViewerCallbacks;
12
13
  documentLoad: EventEmitter<import("visio-core").VisioDocument>;
13
14
  documentChange: EventEmitter<{
14
15
  document: import("visio-core").VisioDocument;
15
16
  dirty: boolean;
16
- kind: "edit" | "undo" | "redo" | "remote";
17
+ kind: "edit" | "undo" | "redo" | "remote" | "save";
17
18
  }>;
18
19
  documentError: EventEmitter<Error>;
19
20
  pageChange: EventEmitter<number>;
@@ -21,6 +22,7 @@ export declare class VisioViewerComponent implements AfterViewInit, OnChanges, O
21
22
  shapeSelect: EventEmitter<VisioShapeSelection | null>;
22
23
  selectionChange: EventEmitter<readonly VisioShapeSelection[]>;
23
24
  ribbonAddIn: EventEmitter<import("ooxml-core/ribbon").RibbonAddInCommandDetail>;
25
+ collaborationChange: EventEmitter<import("ooxml-core/collab").CollaborationState>;
24
26
  private readonly host;
25
27
  private binding;
26
28
  private readonly handle;
@@ -1,23 +1,33 @@
1
1
  import { ViewerController, type VsdxSource } from 'ooxml-ui/visio';
2
2
  import * as ui from 'ooxml-ui/visio';
3
- export interface BuildingBlockOptions {
3
+ /** Host-owned dialogs, as in the PowerPoint building blocks; omitted ones report not-enabled. */
4
+ export interface BuildingBlockHostCallbacks {
5
+ onOpenFile?: (() => void) | undefined;
6
+ onOpenPageSetup?: (() => void) | undefined;
7
+ onOpenSettings?: (() => void) | undefined;
8
+ onOpenShareDialog?: (() => void) | undefined;
9
+ }
10
+ export interface BuildingBlockOptions extends BuildingBlockHostCallbacks {
4
11
  content?: VsdxSource | undefined;
12
+ /** Host edit permission. Read-only until it is `true`, so nothing is editable before the host says so. */
5
13
  canEdit?: boolean | undefined;
6
14
  locale?: string | undefined;
7
15
  onDocumentChange?: ((document: NonNullable<ViewerController['state']['document']>) => void) | undefined;
8
16
  onDirtyChange?: ((dirty: boolean) => void) | undefined;
9
17
  onDocumentError?: ((error: Error) => void) | undefined;
10
18
  }
11
- type Api = Pick<typeof ui, 'mountDiagramCanvas' | 'fitDiagramCanvas' | 'mountDiagramInspector' | 'diagramToolbarProps'>;
19
+ type Api = Pick<typeof ui, 'mountDiagramCanvas' | 'fitDiagramCanvas' | 'mountDiagramInspector' | 'mountDiagramShapes' | 'diagramToolbarProps' | 'diagramMode'>;
12
20
  export declare function buildingBlock<K extends keyof Api>(key: K): Api[K];
21
+ /** The mode a host sees: 'edit' only when permission is granted and the file can be saved back. */
22
+ export declare function effectiveMode(state: ViewerController['state']): 'edit' | 'view';
13
23
  /** Framework-neutral ownership only; each adapter supplies its own reactive state. */
14
- export declare function createBuildingBlockSession(): {
24
+ export declare function createBuildingBlockSession(initial?: BuildingBlockOptions): {
15
25
  controller: ViewerController;
16
26
  mount(node: HTMLElement | null): void;
17
- toolbar(locale?: string | undefined): {
18
- labels: {
19
- [k: string]: string;
20
- };
27
+ /** Flat control props; pass the framework's latest options so callbacks stay current. */
28
+ toolbar(latest?: BuildingBlockOptions): {
29
+ labels: Readonly<Record<"Arc" | "Copy" | "Cut" | "Delete" | "Duplicate" | "Ellipse" | "Find" | "Fit to Window" | "Freeform" | "Group" | "Line" | "Next Result" | "Open" | "Options" | "Page" | "Page Setup" | "Paste" | "Pencil" | "Pointer Tool" | "Previous Result" | "Rectangle" | "Redo" | "Shapes" | "Share" | "Undo" | "Ungroup" | "Zoom In" | "Zoom Out", string>>;
30
+ mode: ui.DiagramMode;
21
31
  canEdit: boolean;
22
32
  pageIndex: number;
23
33
  pages: {
@@ -31,23 +41,55 @@ export declare function createBuildingBlockSession(): {
31
41
  canDuplicate: boolean;
32
42
  canGroup: boolean;
33
43
  canUngroup: boolean;
44
+ canDelete: boolean;
45
+ canCut: boolean;
46
+ canCopy: boolean;
47
+ canPaste: boolean;
48
+ canDraw: boolean;
49
+ canZoomIn: boolean;
50
+ canZoomOut: boolean;
51
+ tool: ui.DiagramTool;
52
+ tools: ui.DiagramToolSummary[];
53
+ search: {
54
+ query: string;
55
+ resultCount: number;
56
+ activeIndex: number;
57
+ truncated: boolean;
58
+ };
34
59
  onPageChange: (index: number) => void;
35
60
  onZoomChange: (zoom: number) => void;
61
+ onZoomIn: () => void;
62
+ onZoomOut: () => void;
36
63
  onFit: () => void;
37
64
  onUndo: () => Promise<void>;
38
65
  onRedo: () => Promise<void>;
39
66
  onDuplicate: () => Promise<void>;
40
67
  onGroup: () => Promise<void>;
41
68
  onUngroup: () => Promise<void>;
69
+ onDelete: () => Promise<void>;
70
+ onCut: () => Promise<void>;
71
+ onCopy: () => Promise<void>;
72
+ onPaste: () => Promise<void>;
73
+ onToolChange: (tool: ui.DiagramTool) => void;
42
74
  onTextChange: (pageId: string, shapeId: string, text: string) => Promise<void>;
43
75
  onSearchChange: (query: string) => void;
44
76
  onNextSearchResult: () => void;
45
77
  onPreviousSearchResult: () => void;
78
+ canOpenFile: boolean;
79
+ canOpenPageSetup: boolean;
80
+ canOpenSettings: boolean;
81
+ canOpenShareDialog: boolean;
82
+ onOpenFile?: () => void;
83
+ onOpenPageSetup?: () => void;
84
+ onOpenSettings?: () => void;
85
+ onOpenShareDialog?: () => void;
46
86
  };
87
+ /** Acknowledge a host save: clears dirty and emits the dirty change. */
88
+ markClean(): void;
47
89
  update(next: BuildingBlockOptions): void;
48
90
  destroy(): void;
49
91
  };
50
92
  export type BuildingBlockSession = ReturnType<typeof createBuildingBlockSession>;
51
- export type { DiagramToolbarProps, ViewerController } from 'ooxml-ui/visio';
93
+ export type { DiagramToolbarProps, DiagramToolbarLabels, DiagramToolbarHostCallbacks, DiagramMode, DiagramTool, ViewerController, } from 'ooxml-ui/visio';
52
94
  /** Resolve the new optional-control theme API only when that control is mounted. */
53
95
  export declare function prepareDiagramBlock(host: HTMLElement | null, kind: 'toolbar' | 'tabs'): void;
@@ -0,0 +1,41 @@
1
+ import type { DiagramToolbarProps } from 'ooxml-ui/visio';
2
+ /** The groups of the library toolbar; a host picks the ones it wants with `include`. */
3
+ export type ToolbarGroupId = 'file' | 'history' | 'zoom' | 'selection' | 'clipboard' | 'tools' | 'search';
4
+ export declare const TOOLBAR_GROUPS: readonly ToolbarGroupId[];
5
+ export interface ToolbarButton {
6
+ readonly kind: 'button';
7
+ readonly id: string;
8
+ readonly label: string;
9
+ readonly disabled: boolean;
10
+ /** Set for toggles such as the drawing tools. */
11
+ readonly pressed?: boolean;
12
+ run(): void;
13
+ }
14
+ export interface ToolbarText {
15
+ readonly kind: 'text';
16
+ readonly id: string;
17
+ readonly text: string;
18
+ }
19
+ export interface ToolbarSearch {
20
+ readonly kind: 'search';
21
+ readonly id: 'search';
22
+ readonly label: string;
23
+ readonly query: string;
24
+ /** Result summary for assistive technology, e.g. "2 of 5". */
25
+ readonly summary: string;
26
+ readonly previous: ToolbarButton;
27
+ readonly next: ToolbarButton;
28
+ change(query: string): void;
29
+ }
30
+ export type ToolbarControl = ToolbarButton | ToolbarText | ToolbarSearch;
31
+ export interface ToolbarGroup {
32
+ readonly id: ToolbarGroupId;
33
+ readonly controls: readonly ToolbarControl[];
34
+ }
35
+ /**
36
+ * What the library Toolbar shows, as plain data every framework maps onto its own elements.
37
+ * Every control reflects `toolbarProps`: edit actions are disabled while the diagram is read-only,
38
+ * viewing actions (zoom, fit, search) never are, and a host dialog button appears only when the
39
+ * host supplied its callback.
40
+ */
41
+ export declare function toolbarGroups(props: DiagramToolbarProps, include?: readonly ToolbarGroupId[]): ToolbarGroup[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "visio-angular-viewer",
3
- "version": "0.8.0",
3
+ "version": "1.0.0",
4
4
  "description": "Local-first Visio viewer for angular",
5
5
  "homepage": "https://christophervr.github.io/ooxml/visio/",
6
6
  "bugs": {
@@ -31,9 +31,9 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "emf-converter": "4.21.0",
34
- "ooxml-core": "^1.20.0",
35
- "ooxml-ui": "^1.19.0",
36
- "visio-core": "^0.5.0"
34
+ "ooxml-core": "^1.22.0",
35
+ "ooxml-ui": "^1.21.0",
36
+ "visio-core": "^1.0.0"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@angular/compiler": "^22.2.3",