ts-visio 1.1.0 → 1.3.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 CHANGED
@@ -8,18 +8,24 @@
8
8
  A Node.js library to strict-type interact with Visio (`.vsdx`) files.
9
9
  Built using specific schema-level abstractions to handle the complex internal structure of Visio documents (ShapeSheets, Pages, Masters).
10
10
 
11
- > **Status**: Work In Progress (TDD).
12
-
13
11
  ## Features
14
12
 
15
- - **Read VSDX**: Open and parse `.vsdx` files (zippped XML).
13
+ - **Read VSDX**: Open and parse `.vsdx` files (zipped XML).
16
14
  - **Strict Typing**: Interact with `VisioPage`, `VisioShape`, and `VisioConnect` objects.
17
15
  - **ShapeSheet Access**: Read `Cells`, `Rows`, and `Sections` directly.
18
16
  - **Connections**: Analyze connectivity between shapes.
19
17
  - **Modular Architecture**: Use specialized components for loading, page management, shape reading, and modification.
20
18
  - **Modify Content**: Update text content of shapes.
21
- - **Create Shapes**: Add new rectangular shapes with text to pages.
22
- - **Connect Shapes**: Create dynamic connectors between shapes.
19
+ - **Create Shapes**: Rectangles, ellipses, diamonds, rounded rectangles, triangles, parallelograms.
20
+ - **Connect Shapes**: Dynamic connectors with arrow styles, line styling, and routing (straight / orthogonal / curved).
21
+ - **Text Styling**: Font size, font family, bold, color, horizontal/vertical alignment.
22
+ - **Shape Transformations**: Rotate, flip (X/Y), and resize shapes via a fluent API.
23
+ - **Deletion**: Remove shapes and pages cleanly (including orphaned connectors and relationships).
24
+ - **Lookup API**: Find shapes by ID, predicate, or look up pages by name.
25
+ - **Read-Back API**: Read custom properties, hyperlinks, and layer assignments from existing shapes.
26
+ - **Page Size & Orientation**: Set canvas dimensions with named sizes (`Letter`, `A4`, …) or raw inches; rotate between portrait and landscape.
27
+
28
+ Feature gaps are being tracked in [FEATURES.md](./FEATURES.md).
23
29
 
24
30
  ## Installation
25
31
 
@@ -63,9 +69,13 @@ const shape = await page.addShape({
63
69
  y: 1,
64
70
  width: 3,
65
71
  height: 1,
66
- fillColor: "#ff0000", // Option hexadecimal fill color
72
+ fillColor: "#ff0000", // Hex fill color
67
73
  fontColor: "#ffffff",
68
- bold: true
74
+ bold: true,
75
+ fontSize: 14, // Points
76
+ fontFamily: "Segoe UI",
77
+ horzAlign: "center", // "left" | "center" | "right" | "justify"
78
+ verticalAlign: "middle" // "top" | "middle" | "bottom"
69
79
  });
70
80
 
71
81
  // Modify text
@@ -345,6 +355,141 @@ await lane1.addMember(startShape);
345
355
  await lane2.addMember(serverShape);
346
356
  ```
347
357
 
358
+ #### 19. Shape Transformations
359
+ Rotate, flip, and resize shapes using a fluent API.
360
+
361
+ ```typescript
362
+ const shape = await page.addShape({ text: "Widget", x: 3, y: 3, width: 2, height: 1 });
363
+
364
+ // Rotate 45 degrees (clockwise)
365
+ await shape.rotate(45);
366
+ console.log(shape.angle); // 45
367
+
368
+ // Mirror horizontally or vertically
369
+ await shape.flipX();
370
+ await shape.flipY(false); // un-flip
371
+
372
+ // Resize (keeps the pin point centred)
373
+ await shape.resize(4, 2);
374
+ console.log(shape.width, shape.height); // 4, 2
375
+
376
+ // Chainable
377
+ await shape.rotate(90).then(s => s.resize(3, 1));
378
+ ```
379
+
380
+ #### 20. Deleting Shapes and Pages
381
+ Remove shapes or entire pages. Orphaned connectors and relationships are cleaned up automatically.
382
+
383
+ ```typescript
384
+ // Delete a shape
385
+ await shape.delete();
386
+
387
+ // Delete a page (removes page file, rels, and all back-page references)
388
+ await doc.deletePage(page2);
389
+ ```
390
+
391
+ #### 21. Lookup API
392
+ Find shapes and pages without iterating manually.
393
+
394
+ ```typescript
395
+ // Find a shape by its numeric ID (searches nested groups too)
396
+ const target = await page.getShapeById("42");
397
+
398
+ // Find all shapes matching a predicate
399
+ const servers = await page.findShapes(s => s.text.startsWith("Server"));
400
+
401
+ // Look up a page by name (exact, case-sensitive)
402
+ const detailPage = doc.getPage("Architecture Diagram");
403
+ ```
404
+
405
+ #### 22. Reading Shape Data Back
406
+ Retrieve custom properties, hyperlinks, and layer assignments that were previously written.
407
+
408
+ ```typescript
409
+ // Custom properties (shape data)
410
+ const props = shape.getProperties();
411
+ console.log(props["IP"].value); // "192.168.1.10"
412
+ console.log(props["Port"].type); // VisioPropType.Number
413
+
414
+ // Hyperlinks
415
+ const links = shape.getHyperlinks();
416
+ // [ { address: "https://example.com", description: "Docs", newWindow: false } ]
417
+
418
+ // Layer indices
419
+ const indices = shape.getLayerIndices(); // e.g. [0, 2]
420
+ ```
421
+
422
+ #### 23. Non-Rectangular Geometry
423
+ Use the `geometry` prop on `addShape()` to create common flowchart primitives without touching XML.
424
+
425
+ ```typescript
426
+ // Ellipse / circle
427
+ await page.addShape({ text: "Start", x: 1, y: 5, width: 2, height: 2, geometry: 'ellipse' });
428
+
429
+ // Decision diamond
430
+ await page.addShape({ text: "Yes?", x: 4, y: 5, width: 2, height: 2, geometry: 'diamond' });
431
+
432
+ // Rounded rectangle (optional corner radius in inches)
433
+ await page.addShape({ text: "Process", x: 7, y: 5, width: 3, height: 2,
434
+ geometry: 'rounded-rectangle', cornerRadius: 0.2 });
435
+
436
+ // Right-pointing triangle
437
+ await page.addShape({ text: "Extract", x: 1, y: 2, width: 2, height: 2, geometry: 'triangle' });
438
+
439
+ // Parallelogram (Data / IO shape)
440
+ await page.addShape({ text: "Input", x: 4, y: 2, width: 3, height: 1.5, geometry: 'parallelogram' });
441
+ ```
442
+
443
+ Supported values: `'rectangle'` (default), `'ellipse'`, `'diamond'`, `'rounded-rectangle'`, `'triangle'`, `'parallelogram'`.
444
+
445
+ #### 24. Connector Styling
446
+ Control line appearance and routing algorithm on any connector.
447
+
448
+ ```typescript
449
+ import { ArrowHeads } from 'ts-visio/utils/StyleHelpers';
450
+
451
+ // Styled connector with crow's foot arrow and custom line
452
+ await shape1.connectTo(shape2, ArrowHeads.One, ArrowHeads.CrowsFoot, {
453
+ lineColor: '#cc0000', // Hex stroke color
454
+ lineWeight: 1.5, // Stroke width in points
455
+ linePattern: 2, // 1=solid, 2=dash, 3=dot, 4=dash-dot
456
+ routing: 'curved', // 'straight' | 'orthogonal' (default) | 'curved'
457
+ });
458
+
459
+ // Via page.connectShapes()
460
+ await page.connectShapes(a, b, undefined, undefined, { routing: 'straight' });
461
+ ```
462
+
463
+ #### 25. Page Size & Orientation
464
+ Control the canvas dimensions using named paper sizes or raw inch values.
465
+
466
+ ```typescript
467
+ import { PageSizes } from 'ts-visio';
468
+
469
+ // Use a named paper size (portrait by default)
470
+ page.setNamedSize('A4'); // 8.268" × 11.693"
471
+ page.setNamedSize('Letter', 'landscape'); // 11" × 8.5"
472
+
473
+ // Set arbitrary dimensions in inches
474
+ page.setSize(13.33, 7.5); // 13.33" × 7.5" widescreen
475
+
476
+ // Rotate the existing canvas without changing the paper size
477
+ page.setOrientation('landscape'); // swaps width and height if needed
478
+ page.setOrientation('portrait');
479
+
480
+ // Read current dimensions
481
+ console.log(page.pageWidth); // e.g. 11
482
+ console.log(page.pageHeight); // e.g. 8.5
483
+ console.log(page.orientation); // 'landscape' | 'portrait'
484
+
485
+ // All size methods are chainable
486
+ page.setNamedSize('A3').setOrientation('landscape');
487
+ ```
488
+
489
+ Available named sizes in `PageSizes`: `Letter`, `Legal`, `Tabloid`, `A3`, `A4`, `A5`.
490
+
491
+ ---
492
+
348
493
  ## Examples
349
494
 
350
495
  Check out the [examples](./examples) directory for complete scripts.
package/dist/Page.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { VisioPage } from './types/VisioTypes';
1
+ import { VisioPage, ConnectorStyle, PageOrientation, PageSizeName } from './types/VisioTypes';
2
2
  import { VisioPackage } from './VisioPackage';
3
3
  import { ShapeModifier } from './ShapeModifier';
4
4
  import { NewShapeProps } from './types/VisioTypes';
@@ -17,9 +17,40 @@ export declare class Page {
17
17
  constructor(internalPage: VisioPage, pkg: VisioPackage, media?: MediaManager, rels?: RelsManager, modifier?: ShapeModifier);
18
18
  get id(): string;
19
19
  get name(): string;
20
+ /** Width of the page canvas in inches. */
21
+ get pageWidth(): number;
22
+ /** Height of the page canvas in inches. */
23
+ get pageHeight(): number;
24
+ /** Current page orientation derived from the canvas dimensions. */
25
+ get orientation(): PageOrientation;
26
+ /**
27
+ * Set the page canvas size in inches.
28
+ * @example page.setSize(11, 8.5) // landscape letter
29
+ */
30
+ setSize(width: number, height: number): this;
31
+ /**
32
+ * Convenience: change the page to a named standard size (portrait by default).
33
+ * @example page.setNamedSize('A4')
34
+ */
35
+ setNamedSize(sizeName: PageSizeName, orientation?: PageOrientation): this;
36
+ /**
37
+ * Rotate the canvas between portrait and landscape without changing the paper size.
38
+ * Swaps width and height when the current orientation does not match the requested one.
39
+ */
40
+ setOrientation(orientation: PageOrientation): this;
20
41
  getShapes(): Shape[];
42
+ /**
43
+ * Find a shape by its ID anywhere on the page, including shapes nested inside groups.
44
+ * Returns undefined if no shape with that ID exists.
45
+ */
46
+ getShapeById(id: string): Shape | undefined;
47
+ /**
48
+ * Return all shapes on the page (including nested group children) that satisfy
49
+ * the predicate. Equivalent to getAllShapes().filter(predicate).
50
+ */
51
+ findShapes(predicate: (shape: Shape) => boolean): Shape[];
21
52
  addShape(props: NewShapeProps, parentId?: string): Promise<Shape>;
22
- connectShapes(fromShape: Shape, toShape: Shape, beginArrow?: string, endArrow?: string): Promise<void>;
53
+ connectShapes(fromShape: Shape, toShape: Shape, beginArrow?: string, endArrow?: string, style?: ConnectorStyle): Promise<void>;
23
54
  addImage(data: Buffer, name: string, x: number, y: number, width: number, height: number): Promise<Shape>;
24
55
  addContainer(props: NewShapeProps): Promise<Shape>;
25
56
  addList(props: NewShapeProps, direction?: 'vertical' | 'horizontal'): Promise<Shape>;
package/dist/Page.js CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Page = void 0;
4
+ const VisioTypes_1 = require("./types/VisioTypes");
4
5
  const ShapeReader_1 = require("./ShapeReader");
5
6
  const ShapeModifier_1 = require("./ShapeModifier");
6
7
  const Shape_1 = require("./Shape");
@@ -26,6 +27,51 @@ class Page {
26
27
  get name() {
27
28
  return this.internalPage.Name;
28
29
  }
30
+ /** Width of the page canvas in inches. */
31
+ get pageWidth() {
32
+ return this.modifier.getPageDimensions(this.id).width;
33
+ }
34
+ /** Height of the page canvas in inches. */
35
+ get pageHeight() {
36
+ return this.modifier.getPageDimensions(this.id).height;
37
+ }
38
+ /** Current page orientation derived from the canvas dimensions. */
39
+ get orientation() {
40
+ return this.pageWidth > this.pageHeight ? 'landscape' : 'portrait';
41
+ }
42
+ /**
43
+ * Set the page canvas size in inches.
44
+ * @example page.setSize(11, 8.5) // landscape letter
45
+ */
46
+ setSize(width, height) {
47
+ this.modifier.setPageSize(this.id, width, height);
48
+ return this;
49
+ }
50
+ /**
51
+ * Convenience: change the page to a named standard size (portrait by default).
52
+ * @example page.setNamedSize('A4')
53
+ */
54
+ setNamedSize(sizeName, orientation = 'portrait') {
55
+ const { width, height } = VisioTypes_1.PageSizes[sizeName];
56
+ return orientation === 'landscape'
57
+ ? this.setSize(height, width)
58
+ : this.setSize(width, height);
59
+ }
60
+ /**
61
+ * Rotate the canvas between portrait and landscape without changing the paper size.
62
+ * Swaps width and height when the current orientation does not match the requested one.
63
+ */
64
+ setOrientation(orientation) {
65
+ const w = this.pageWidth;
66
+ const h = this.pageHeight;
67
+ if (orientation === 'landscape' && h > w) {
68
+ this.modifier.setPageSize(this.id, h, w);
69
+ }
70
+ else if (orientation === 'portrait' && w > h) {
71
+ this.modifier.setPageSize(this.id, h, w);
72
+ }
73
+ return this;
74
+ }
29
75
  getShapes() {
30
76
  const reader = new ShapeReader_1.ShapeReader(this.pkg);
31
77
  try {
@@ -33,11 +79,32 @@ class Page {
33
79
  return internalShapes.map(s => new Shape_1.Shape(s, this.id, this.pkg, this.modifier));
34
80
  }
35
81
  catch (e) {
36
- // If page file doesn't exist or is empty, return empty array
37
82
  console.warn(`Could not read shapes for page ${this.id}:`, e);
38
83
  return [];
39
84
  }
40
85
  }
86
+ /**
87
+ * Find a shape by its ID anywhere on the page, including shapes nested inside groups.
88
+ * Returns undefined if no shape with that ID exists.
89
+ */
90
+ getShapeById(id) {
91
+ const reader = new ShapeReader_1.ShapeReader(this.pkg);
92
+ const internal = reader.readShapeById(this.pagePath, id);
93
+ if (!internal)
94
+ return undefined;
95
+ return new Shape_1.Shape(internal, this.id, this.pkg, this.modifier);
96
+ }
97
+ /**
98
+ * Return all shapes on the page (including nested group children) that satisfy
99
+ * the predicate. Equivalent to getAllShapes().filter(predicate).
100
+ */
101
+ findShapes(predicate) {
102
+ const reader = new ShapeReader_1.ShapeReader(this.pkg);
103
+ const all = reader.readAllShapes(this.pagePath);
104
+ return all
105
+ .map(s => new Shape_1.Shape(s, this.id, this.pkg, this.modifier))
106
+ .filter(predicate);
107
+ }
41
108
  async addShape(props, parentId) {
42
109
  const newId = await this.modifier.addShape(this.id, props, parentId);
43
110
  // Return a fresh Shape object representing the new shape
@@ -57,8 +124,8 @@ class Page {
57
124
  });
58
125
  return new Shape_1.Shape(internalStub, this.id, this.pkg, this.modifier);
59
126
  }
60
- async connectShapes(fromShape, toShape, beginArrow, endArrow) {
61
- await this.modifier.addConnector(this.id, fromShape.id, toShape.id, beginArrow, endArrow);
127
+ async connectShapes(fromShape, toShape, beginArrow, endArrow, style) {
128
+ await this.modifier.addConnector(this.id, fromShape.id, toShape.id, beginArrow, endArrow, style);
62
129
  }
63
130
  async addImage(data, name, x, y, width, height) {
64
131
  // 1. Upload Media
package/dist/Shape.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { VisioShape } from './types/VisioTypes';
1
+ import { VisioShape, ConnectorStyle } from './types/VisioTypes';
2
2
  import { VisioPackage } from './VisioPackage';
3
3
  import { ShapeModifier, ShapeStyle } from './ShapeModifier';
4
4
  import { VisioPropType } from './types/VisioTypes';
@@ -9,6 +9,12 @@ export interface ShapeData {
9
9
  hidden?: boolean;
10
10
  type?: VisioPropType;
11
11
  }
12
+ export interface ShapeHyperlink {
13
+ address?: string;
14
+ subAddress?: string;
15
+ description?: string;
16
+ newWindow: boolean;
17
+ }
12
18
  export declare class Shape {
13
19
  private internalShape;
14
20
  private pageId;
@@ -23,7 +29,8 @@ export declare class Shape {
23
29
  get height(): number;
24
30
  get x(): number;
25
31
  get y(): number;
26
- connectTo(targetShape: Shape, beginArrow?: string, endArrow?: string): Promise<this>;
32
+ delete(): Promise<void>;
33
+ connectTo(targetShape: Shape, beginArrow?: string, endArrow?: string, style?: ConnectorStyle): Promise<this>;
27
34
  setStyle(style: ShapeStyle): Promise<this>;
28
35
  placeRightOf(targetShape: Shape, options?: {
29
36
  gap: number;
@@ -37,6 +44,41 @@ export declare class Shape {
37
44
  }): this;
38
45
  setPropertyValue(name: string, value: string | number | boolean | Date): this;
39
46
  addData(key: string, data: ShapeData): this;
47
+ /**
48
+ * Read back all custom property (shape data) entries written to this shape.
49
+ * Returns a map of property key → ShapeData. Values are coerced to the
50
+ * declared Visio type (Number, Boolean, Date, or String).
51
+ */
52
+ getProperties(): Record<string, ShapeData>;
53
+ /**
54
+ * Read back all hyperlinks attached to this shape.
55
+ */
56
+ getHyperlinks(): ShapeHyperlink[];
57
+ /**
58
+ * Read back the layer indices this shape is assigned to.
59
+ * Returns an empty array if the shape has no layer assignment.
60
+ */
61
+ getLayerIndices(): number[];
62
+ /** Current rotation angle in degrees (0 if no Angle cell is set). */
63
+ get angle(): number;
64
+ /**
65
+ * Rotate the shape to an absolute angle (degrees, clockwise).
66
+ * Replaces any existing rotation.
67
+ */
68
+ rotate(degrees: number): Promise<this>;
69
+ /**
70
+ * Resize the shape to the given width and height (in inches).
71
+ * Updates LocPinX/LocPinY to keep the centre-pin at width/2, height/2.
72
+ */
73
+ resize(width: number, height: number): Promise<this>;
74
+ /**
75
+ * Flip the shape horizontally. Pass `false` to un-flip.
76
+ */
77
+ flipX(enabled?: boolean): Promise<this>;
78
+ /**
79
+ * Flip the shape vertically. Pass `false` to un-flip.
80
+ */
81
+ flipY(enabled?: boolean): Promise<this>;
40
82
  addMember(memberShape: Shape): Promise<this>;
41
83
  addListItem(item: Shape): Promise<this>;
42
84
  resizeToFit(padding?: number): Promise<this>;
@@ -67,4 +109,5 @@ export declare class Shape {
67
109
  */
68
110
  addToLayer(layer: Layer | number): Promise<this>;
69
111
  private setLocalCoord;
112
+ private setLocalRawCell;
70
113
  }
package/dist/Shape.js CHANGED
@@ -39,8 +39,11 @@ class Shape {
39
39
  get y() {
40
40
  return this.internalShape.Cells['PinY'] ? Number(this.internalShape.Cells['PinY'].V) : 0;
41
41
  }
42
- async connectTo(targetShape, beginArrow, endArrow) {
43
- await this.modifier.addConnector(this.pageId, this.id, targetShape.id, beginArrow, endArrow);
42
+ async delete() {
43
+ await this.modifier.deleteShape(this.pageId, this.id);
44
+ }
45
+ async connectTo(targetShape, beginArrow, endArrow, style) {
46
+ await this.modifier.addConnector(this.pageId, this.id, targetShape.id, beginArrow, endArrow, style);
44
47
  return this;
45
48
  }
46
49
  async setStyle(style) {
@@ -96,6 +99,72 @@ class Shape {
96
99
  this.setPropertyValue(key, data.value);
97
100
  return this;
98
101
  }
102
+ /**
103
+ * Read back all custom property (shape data) entries written to this shape.
104
+ * Returns a map of property key → ShapeData. Values are coerced to the
105
+ * declared Visio type (Number, Boolean, Date, or String).
106
+ */
107
+ getProperties() {
108
+ return this.modifier.getShapeProperties(this.pageId, this.id);
109
+ }
110
+ /**
111
+ * Read back all hyperlinks attached to this shape.
112
+ */
113
+ getHyperlinks() {
114
+ return this.modifier.getShapeHyperlinks(this.pageId, this.id);
115
+ }
116
+ /**
117
+ * Read back the layer indices this shape is assigned to.
118
+ * Returns an empty array if the shape has no layer assignment.
119
+ */
120
+ getLayerIndices() {
121
+ return this.modifier.getShapeLayerIndices(this.pageId, this.id);
122
+ }
123
+ /** Current rotation angle in degrees (0 if no Angle cell is set). */
124
+ get angle() {
125
+ const cell = this.internalShape.Cells['Angle'];
126
+ return cell ? (parseFloat(cell.V) * 180) / Math.PI : 0;
127
+ }
128
+ /**
129
+ * Rotate the shape to an absolute angle (degrees, clockwise).
130
+ * Replaces any existing rotation.
131
+ */
132
+ async rotate(degrees) {
133
+ await this.modifier.rotateShape(this.pageId, this.id, degrees);
134
+ const radians = (degrees * Math.PI) / 180;
135
+ this.setLocalCoord('Angle', radians);
136
+ return this;
137
+ }
138
+ /**
139
+ * Resize the shape to the given width and height (in inches).
140
+ * Updates LocPinX/LocPinY to keep the centre-pin at width/2, height/2.
141
+ */
142
+ async resize(width, height) {
143
+ if (width <= 0 || height <= 0)
144
+ throw new Error('Shape dimensions must be positive');
145
+ await this.modifier.resizeShape(this.pageId, this.id, width, height);
146
+ this.setLocalCoord('Width', width);
147
+ this.setLocalCoord('Height', height);
148
+ this.setLocalCoord('LocPinX', width / 2);
149
+ this.setLocalCoord('LocPinY', height / 2);
150
+ return this;
151
+ }
152
+ /**
153
+ * Flip the shape horizontally. Pass `false` to un-flip.
154
+ */
155
+ async flipX(enabled = true) {
156
+ this.modifier.setShapeFlip(this.pageId, this.id, 'x', enabled);
157
+ this.setLocalRawCell('FlipX', enabled ? '1' : '0');
158
+ return this;
159
+ }
160
+ /**
161
+ * Flip the shape vertically. Pass `false` to un-flip.
162
+ */
163
+ async flipY(enabled = true) {
164
+ this.modifier.setShapeFlip(this.pageId, this.id, 'y', enabled);
165
+ this.setLocalRawCell('FlipY', enabled ? '1' : '0');
166
+ return this;
167
+ }
99
168
  async addMember(memberShape) {
100
169
  await this.modifier.addRelationship(this.pageId, this.id, memberShape.id, 'Container');
101
170
  return this;
@@ -165,5 +234,11 @@ class Shape {
165
234
  else
166
235
  this.internalShape.Cells[name] = { V: v, N: name };
167
236
  }
237
+ setLocalRawCell(name, value) {
238
+ if (this.internalShape.Cells[name])
239
+ this.internalShape.Cells[name].V = value;
240
+ else
241
+ this.internalShape.Cells[name] = { V: value, N: name };
242
+ }
168
243
  }
169
244
  exports.Shape = Shape;
@@ -1,5 +1,7 @@
1
1
  import { VisioPackage } from './VisioPackage';
2
- import { NewShapeProps } from './types/VisioTypes';
2
+ import { HorzAlign, VertAlign } from './utils/StyleHelpers';
3
+ import { NewShapeProps, ConnectorStyle } from './types/VisioTypes';
4
+ import type { ShapeData, ShapeHyperlink } from './Shape';
3
5
  export declare class ShapeModifier {
4
6
  private pkg;
5
7
  addContainer(pageId: string, props: NewShapeProps): Promise<string>;
@@ -29,11 +31,30 @@ export declare class ShapeModifier {
29
31
  private saveParsed;
30
32
  private performSave;
31
33
  flush(): void;
32
- addConnector(pageId: string, fromShapeId: string, toShapeId: string, beginArrow?: string, endArrow?: string): Promise<string>;
34
+ addConnector(pageId: string, fromShapeId: string, toShapeId: string, beginArrow?: string, endArrow?: string, style?: ConnectorStyle): Promise<string>;
33
35
  addShape(pageId: string, props: NewShapeProps, parentId?: string): Promise<string>;
36
+ deleteShape(pageId: string, shapeId: string): Promise<void>;
37
+ private removeShapeFromTree;
34
38
  updateShapeText(pageId: string, shapeId: string, newText: string): Promise<void>;
35
39
  updateShapeStyle(pageId: string, shapeId: string, style: ShapeStyle): Promise<void>;
36
40
  updateShapeDimensions(pageId: string, shapeId: string, w: number, h: number): Promise<void>;
41
+ /**
42
+ * Set the rotation angle of a shape. Degrees are converted to radians
43
+ * for storage in the Angle cell (Visio's native unit).
44
+ */
45
+ rotateShape(pageId: string, shapeId: string, degrees: number): Promise<void>;
46
+ /**
47
+ * Set the flip state for a shape along the X or Y axis.
48
+ * FlipX mirrors left-to-right; FlipY mirrors top-to-bottom.
49
+ */
50
+ setShapeFlip(pageId: string, shapeId: string, axis: 'x' | 'y', enabled: boolean): void;
51
+ /**
52
+ * Resize a shape, keeping it centred on its current PinX/PinY.
53
+ * Updates Width, Height, LocPinX, LocPinY, and the cached @_V on any
54
+ * Geometry cells whose @_F formula references Width or Height, so that
55
+ * non-Visio renderers see consistent values.
56
+ */
57
+ resizeShape(pageId: string, shapeId: string, width: number, height: number): Promise<void>;
37
58
  updateShapePosition(pageId: string, shapeId: string, x: number, y: number): Promise<void>;
38
59
  addPropertyDefinition(pageId: string, shapeId: string, name: string, type: number, options?: {
39
60
  label?: string;
@@ -67,9 +88,45 @@ export declare class ShapeModifier {
67
88
  }>;
68
89
  assignLayer(pageId: string, shapeId: string, layerIndex: number): Promise<void>;
69
90
  updateLayerProperty(pageId: string, layerIndex: number, propName: string, value: string): Promise<void>;
91
+ /**
92
+ * Read back all custom property (shape data) entries for a shape.
93
+ * Returns a map of property key → ShapeData, with values coerced to
94
+ * the declared type (Number, Boolean, Date, or String).
95
+ */
96
+ getShapeProperties(pageId: string, shapeId: string): Record<string, ShapeData>;
97
+ /**
98
+ * Set the page canvas size. Writes PageWidth / PageHeight into the PageSheet
99
+ * and sets DrawingSizeType=0 (Custom) so Visio does not override the values.
100
+ */
101
+ setPageSize(pageId: string, width: number, height: number): void;
102
+ /**
103
+ * Read the current page canvas dimensions.
104
+ * Returns 8.5 × 11 (US Letter) if no PageSheet cells are present.
105
+ */
106
+ getPageDimensions(pageId: string): {
107
+ width: number;
108
+ height: number;
109
+ };
110
+ /**
111
+ * Read back all hyperlinks attached to a shape.
112
+ */
113
+ getShapeHyperlinks(pageId: string, shapeId: string): ShapeHyperlink[];
114
+ /**
115
+ * Read back the layer indices a shape is assigned to.
116
+ * Returns an empty array if the shape has no layer assignment.
117
+ */
118
+ getShapeLayerIndices(pageId: string, shapeId: string): number[];
70
119
  }
71
120
  export interface ShapeStyle {
72
121
  fillColor?: string;
73
122
  fontColor?: string;
74
123
  bold?: boolean;
124
+ /** Font size in points (e.g. 14 for 14pt). */
125
+ fontSize?: number;
126
+ /** Font family name (e.g. "Arial"). */
127
+ fontFamily?: string;
128
+ /** Horizontal text alignment. */
129
+ horzAlign?: HorzAlign;
130
+ /** Vertical text alignment. */
131
+ verticalAlign?: VertAlign;
75
132
  }