ts-visio 1.15.0 → 1.16.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
@@ -1,5 +1,7 @@
1
1
  # ts-visio
2
2
 
3
+ [![API Docs](https://img.shields.io/badge/API%20Docs-TypeDoc-blue?style=flat-square)](https://zimmermanw84.github.io/ts-visio/)
4
+
3
5
  > [!WARNING]
4
6
  > **Under Construction**
5
7
  > This library is currently being developed with heavy assistance from AI and is primarily an experimental project. Use with caution.
@@ -14,7 +16,7 @@ Built using specific schema-level abstractions to handle the complex internal st
14
16
  - **Strict Typing**: Interact with `VisioPage`, `VisioShape`, and `VisioConnect` objects.
15
17
  - **ShapeSheet Access**: Read `Cells`, `Rows`, and `Sections` directly.
16
18
  - **Connections**: Analyze connectivity between shapes.
17
- - **Modular Architecture**: Use specialized components for loading, page management, shape reading, and modification.
19
+ - **Modular Architecture**: Clean layered architecture `VisioDocument` `Page` `Shape` is the full public surface; XML and OPC internals stay encapsulated.
18
20
  - **Modify Content**: Update text content of shapes.
19
21
  - **Create Shapes**: Rectangles, ellipses, diamonds, rounded rectangles, triangles, parallelograms.
20
22
  - **Connect Shapes**: Dynamic connectors with arrow styles, line styling, and routing (straight / orthogonal / curved).
@@ -710,6 +712,16 @@ const styles = doc.getStyles();
710
712
  `StyleProps` supports: `fillColor`, `lineColor`, `lineWeight` (pt), `linePattern`, `fontColor`, `fontSize` (pt), `bold`, `italic`, `underline`, `strikethrough`, `fontFamily`, `horzAlign`, `verticalAlign`, `spaceBefore`, `spaceAfter`, `lineSpacing`, `textMarginTop/Bottom/Left/Right` (in).
711
713
  Local shape properties always override inherited stylesheet values.
712
714
 
715
+ The alignment and style types are exported for use in typed consumers:
716
+
717
+ ```typescript
718
+ import type { HorzAlign, VertAlign, ShapeStyle } from 'ts-visio';
719
+
720
+ const style: ShapeStyle = { horzAlign: 'center', verticalAlign: 'middle', bold: true };
721
+ const align: HorzAlign = 'justify'; // 'left' | 'center' | 'right' | 'justify'
722
+ const valign: VertAlign = 'bottom'; // 'top' | 'middle' | 'bottom'
723
+ ```
724
+
713
725
  #### 30. Reading Connectors Back
714
726
  Enumerate connectors on a page — including those loaded from an existing `.vsdx` file — and inspect or delete them.
715
727
 
package/dist/Layer.d.ts CHANGED
@@ -1,5 +1,19 @@
1
1
  import { VisioPackage } from './VisioPackage';
2
2
  import { ShapeModifier } from './ShapeModifier';
3
+ /**
4
+ * A named display layer on a Visio page.
5
+ *
6
+ * Layers control the visibility and printability of groups of shapes.
7
+ * Obtain instances via `page.getLayers()` or `page.addLayer()`.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * const annotations = await page.addLayer('Annotations');
12
+ * ann.setVisible(false); // hide all shapes on this layer
13
+ * ```
14
+ *
15
+ * @category Layers
16
+ */
3
17
  export declare class Layer {
4
18
  name: string;
5
19
  index: number;
package/dist/Layer.js CHANGED
@@ -2,6 +2,20 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Layer = void 0;
4
4
  const ShapeModifier_1 = require("./ShapeModifier");
5
+ /**
6
+ * A named display layer on a Visio page.
7
+ *
8
+ * Layers control the visibility and printability of groups of shapes.
9
+ * Obtain instances via `page.getLayers()` or `page.addLayer()`.
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * const annotations = await page.addLayer('Annotations');
14
+ * ann.setVisible(false); // hide all shapes on this layer
15
+ * ```
16
+ *
17
+ * @category Layers
18
+ */
5
19
  class Layer {
6
20
  constructor(name, index, pageId, pkg, modifier, _visible = true, _locked = false) {
7
21
  this.name = name;
package/dist/Page.d.ts CHANGED
@@ -7,6 +7,21 @@ import { Shape } from './Shape';
7
7
  import { MediaManager } from './core/MediaManager';
8
8
  import { RelsManager } from './core/RelsManager';
9
9
  import { Layer } from './Layer';
10
+ /**
11
+ * Represents a single page (tab) inside a Visio document.
12
+ *
13
+ * Obtain a `Page` instance from {@link VisioDocument.pages},
14
+ * {@link VisioDocument.addPage}, or {@link VisioDocument.getPage}.
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * const doc = await VisioDocument.create();
19
+ * const page = doc.pages[0];
20
+ * await page.addShape({ text: 'Hello', x: 1, y: 1, width: 2, height: 1 });
21
+ * ```
22
+ *
23
+ * @category Pages
24
+ */
10
25
  export declare class Page {
11
26
  private internalPage;
12
27
  private pkg;
@@ -39,6 +54,10 @@ export declare class Page {
39
54
  * Swaps width and height when the current orientation does not match the requested one.
40
55
  */
41
56
  setOrientation(orientation: PageOrientation): this;
57
+ /**
58
+ * Return all top-level shapes on the page.
59
+ * Group children are not included; use {@link findShapes} to search the entire shape tree.
60
+ */
42
61
  getShapes(): Shape[];
43
62
  /**
44
63
  * Find a shape by its ID anywhere on the page, including shapes nested inside groups.
@@ -50,6 +69,29 @@ export declare class Page {
50
69
  * the predicate. Equivalent to getAllShapes().filter(predicate).
51
70
  */
52
71
  findShapes(predicate: (shape: Shape) => boolean): Shape[];
72
+ /**
73
+ * Add a new shape to the page and return a {@link Shape} handle to it.
74
+ *
75
+ * @param props Visual and text properties for the new shape.
76
+ * All geometry fields (`x`, `y`, `width`, `height`) are in inches.
77
+ * @param parentId Optional ID of an existing group shape to nest the new shape inside.
78
+ *
79
+ * @example
80
+ * ```typescript
81
+ * // Plain rectangle
82
+ * const box = await page.addShape({ text: 'Server', x: 2, y: 3, width: 2, height: 1 });
83
+ *
84
+ * // Ellipse with styling
85
+ * await page.addShape({
86
+ * text: 'Start', x: 1, y: 1, width: 1.5, height: 1.5,
87
+ * geometry: 'ellipse', fillColor: '#4472C4', fontColor: '#ffffff',
88
+ * });
89
+ *
90
+ * // Master instance (shape defined by a reusable master)
91
+ * const m = doc.createMaster('Router', 'ellipse');
92
+ * await page.addShape({ text: '', x: 4, y: 2, width: 1, height: 1, masterId: m.id });
93
+ * ```
94
+ */
53
95
  addShape(props: NewShapeProps, parentId?: string): Promise<Shape>;
54
96
  /**
55
97
  * Return all connector shapes on the page.
@@ -57,19 +99,50 @@ export declare class Page {
57
99
  * and a `delete()` method to remove the connector.
58
100
  */
59
101
  getConnectors(): Connector[];
102
+ /**
103
+ * Draw a connector (line/arrow) between two shapes on this page.
104
+ *
105
+ * @param fromShape Source shape.
106
+ * @param toShape Target shape.
107
+ * @param beginArrow Arrow head at the source end (use {@link ArrowHeads} constants).
108
+ * @param endArrow Arrow head at the target end (use {@link ArrowHeads} constants).
109
+ * @param style Line color, weight, pattern, and routing style.
110
+ * @param fromPort Named connection point on the source shape (e.g. `'Right'`).
111
+ * @param toPort Named connection point on the target shape (e.g. `'Left'`).
112
+ *
113
+ * @example
114
+ * ```typescript
115
+ * import { ArrowHeads } from 'ts-visio';
116
+ * const a = await page.addShape({ text: 'A', x: 1, y: 1, width: 1, height: 1 });
117
+ * const b = await page.addShape({ text: 'B', x: 4, y: 1, width: 1, height: 1 });
118
+ * await page.connectShapes(a, b, ArrowHeads.None, ArrowHeads.OpenArrow,
119
+ * { lineColor: '#333333', routing: 'orthogonal' });
120
+ * ```
121
+ */
60
122
  connectShapes(fromShape: Shape, toShape: Shape, beginArrow?: string, endArrow?: string, style?: ConnectorStyle, fromPort?: ConnectionTarget, toPort?: ConnectionTarget): Promise<void>;
123
+ /**
124
+ * Embed an image on the page and return the resulting Foreign shape.
125
+ *
126
+ * @param data Raw image bytes (PNG, JPEG, GIF, BMP, or TIFF).
127
+ * @param name Filename used to store the image inside the archive (e.g. `'logo.png'`).
128
+ * @param x Horizontal pin position in inches.
129
+ * @param y Vertical pin position in inches.
130
+ * @param width Display width in inches.
131
+ * @param height Display height in inches.
132
+ *
133
+ * @example
134
+ * ```typescript
135
+ * import fs from 'fs';
136
+ * const imgBuffer = fs.readFileSync('./logo.png');
137
+ * await page.addImage(imgBuffer, 'logo.png', 1, 1, 2, 1);
138
+ * ```
139
+ */
61
140
  addImage(data: Buffer, name: string, x: number, y: number, width: number, height: number): Promise<Shape>;
62
141
  addContainer(props: NewShapeProps): Promise<Shape>;
63
142
  addList(props: NewShapeProps, direction?: 'vertical' | 'horizontal'): Promise<Shape>;
64
- /**
65
- * Creates a Swimlane Pool (which is technically a Vertical List of Containers).
66
- * @param props Visual properties
67
- */
143
+ /** Creates a Swimlane Pool (a vertical List of Containers). */
68
144
  addSwimlanePool(props: NewShapeProps): Promise<Shape>;
69
- /**
70
- * Creates a Swimlane Lane (which is technically a Container).
71
- * @param props Visual properties
72
- */
145
+ /** Creates a Swimlane Lane (a Container inside a pool). */
73
146
  addSwimlaneLane(props: NewShapeProps): Promise<Shape>;
74
147
  addTable(x: number, y: number, title: string, columns: string[]): Promise<Shape>;
75
148
  addLayer(name: string, options?: {
package/dist/Page.js CHANGED
@@ -10,6 +10,23 @@ const MediaManager_1 = require("./core/MediaManager");
10
10
  const RelsManager_1 = require("./core/RelsManager");
11
11
  const StubHelpers_1 = require("./utils/StubHelpers");
12
12
  const Layer_1 = require("./Layer");
13
+ const TablePattern_1 = require("./diagrams/TablePattern");
14
+ const SwimlanePattern_1 = require("./diagrams/SwimlanePattern");
15
+ /**
16
+ * Represents a single page (tab) inside a Visio document.
17
+ *
18
+ * Obtain a `Page` instance from {@link VisioDocument.pages},
19
+ * {@link VisioDocument.addPage}, or {@link VisioDocument.getPage}.
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * const doc = await VisioDocument.create();
24
+ * const page = doc.pages[0];
25
+ * await page.addShape({ text: 'Hello', x: 1, y: 1, width: 2, height: 1 });
26
+ * ```
27
+ *
28
+ * @category Pages
29
+ */
13
30
  class Page {
14
31
  constructor(internalPage, pkg, media, rels, modifier) {
15
32
  this.internalPage = internalPage;
@@ -73,6 +90,10 @@ class Page {
73
90
  }
74
91
  return this;
75
92
  }
93
+ /**
94
+ * Return all top-level shapes on the page.
95
+ * Group children are not included; use {@link findShapes} to search the entire shape tree.
96
+ */
76
97
  getShapes() {
77
98
  const reader = new ShapeReader_1.ShapeReader(this.pkg);
78
99
  try {
@@ -106,6 +127,29 @@ class Page {
106
127
  .map(s => new Shape_1.Shape(s, this.id, this.pkg, this.modifier))
107
128
  .filter(predicate);
108
129
  }
130
+ /**
131
+ * Add a new shape to the page and return a {@link Shape} handle to it.
132
+ *
133
+ * @param props Visual and text properties for the new shape.
134
+ * All geometry fields (`x`, `y`, `width`, `height`) are in inches.
135
+ * @param parentId Optional ID of an existing group shape to nest the new shape inside.
136
+ *
137
+ * @example
138
+ * ```typescript
139
+ * // Plain rectangle
140
+ * const box = await page.addShape({ text: 'Server', x: 2, y: 3, width: 2, height: 1 });
141
+ *
142
+ * // Ellipse with styling
143
+ * await page.addShape({
144
+ * text: 'Start', x: 1, y: 1, width: 1.5, height: 1.5,
145
+ * geometry: 'ellipse', fillColor: '#4472C4', fontColor: '#ffffff',
146
+ * });
147
+ *
148
+ * // Master instance (shape defined by a reusable master)
149
+ * const m = doc.createMaster('Router', 'ellipse');
150
+ * await page.addShape({ text: '', x: 4, y: 2, width: 1, height: 1, masterId: m.id });
151
+ * ```
152
+ */
109
153
  async addShape(props, parentId) {
110
154
  const newId = await this.modifier.addShape(this.id, props, parentId);
111
155
  // Return a fresh Shape object representing the new shape
@@ -142,9 +186,46 @@ class Page {
142
186
  return [];
143
187
  }
144
188
  }
189
+ /**
190
+ * Draw a connector (line/arrow) between two shapes on this page.
191
+ *
192
+ * @param fromShape Source shape.
193
+ * @param toShape Target shape.
194
+ * @param beginArrow Arrow head at the source end (use {@link ArrowHeads} constants).
195
+ * @param endArrow Arrow head at the target end (use {@link ArrowHeads} constants).
196
+ * @param style Line color, weight, pattern, and routing style.
197
+ * @param fromPort Named connection point on the source shape (e.g. `'Right'`).
198
+ * @param toPort Named connection point on the target shape (e.g. `'Left'`).
199
+ *
200
+ * @example
201
+ * ```typescript
202
+ * import { ArrowHeads } from 'ts-visio';
203
+ * const a = await page.addShape({ text: 'A', x: 1, y: 1, width: 1, height: 1 });
204
+ * const b = await page.addShape({ text: 'B', x: 4, y: 1, width: 1, height: 1 });
205
+ * await page.connectShapes(a, b, ArrowHeads.None, ArrowHeads.OpenArrow,
206
+ * { lineColor: '#333333', routing: 'orthogonal' });
207
+ * ```
208
+ */
145
209
  async connectShapes(fromShape, toShape, beginArrow, endArrow, style, fromPort, toPort) {
146
210
  await this.modifier.addConnector(this.id, fromShape.id, toShape.id, beginArrow, endArrow, style, fromPort, toPort);
147
211
  }
212
+ /**
213
+ * Embed an image on the page and return the resulting Foreign shape.
214
+ *
215
+ * @param data Raw image bytes (PNG, JPEG, GIF, BMP, or TIFF).
216
+ * @param name Filename used to store the image inside the archive (e.g. `'logo.png'`).
217
+ * @param x Horizontal pin position in inches.
218
+ * @param y Vertical pin position in inches.
219
+ * @param width Display width in inches.
220
+ * @param height Display height in inches.
221
+ *
222
+ * @example
223
+ * ```typescript
224
+ * import fs from 'fs';
225
+ * const imgBuffer = fs.readFileSync('./logo.png');
226
+ * await page.addImage(imgBuffer, 'logo.png', 1, 1, 2, 1);
227
+ * ```
228
+ */
148
229
  async addImage(data, name, x, y, width, height) {
149
230
  const mediaPath = this.media.addMedia(name, data);
150
231
  const rId = await this.rels.addImageRelationship(this.pagePath, mediaPath);
@@ -194,51 +275,16 @@ class Page {
194
275
  });
195
276
  return new Shape_1.Shape(internalStub, this.id, this.pkg, this.modifier);
196
277
  }
197
- /**
198
- * Creates a Swimlane Pool (which is technically a Vertical List of Containers).
199
- * @param props Visual properties
200
- */
278
+ /** Creates a Swimlane Pool (a vertical List of Containers). */
201
279
  async addSwimlanePool(props) {
202
- return this.addList(props, 'vertical');
280
+ return SwimlanePattern_1.SwimlanePattern.addPool(this, props);
203
281
  }
204
- /**
205
- * Creates a Swimlane Lane (which is technically a Container).
206
- * @param props Visual properties
207
- */
282
+ /** Creates a Swimlane Lane (a Container inside a pool). */
208
283
  async addSwimlaneLane(props) {
209
- return this.addContainer(props);
284
+ return SwimlanePattern_1.SwimlanePattern.addLane(this, props);
210
285
  }
211
286
  async addTable(x, y, title, columns) {
212
- const width = 3;
213
- const headerHeight = 0.5;
214
- const lineItemHeight = 0.25;
215
- const bodyHeight = Math.max(0.5, columns.length * lineItemHeight + 0.1);
216
- const totalHeight = headerHeight + bodyHeight;
217
- // Group contains a header row and a body row; child coords are relative to the group origin.
218
- const groupShape = await this.addShape({
219
- text: '',
220
- x, y, width, height: totalHeight,
221
- type: 'Group'
222
- });
223
- const headerCenterY = bodyHeight + (headerHeight / 2);
224
- await this.addShape({
225
- text: title,
226
- x: width / 2,
227
- y: headerCenterY,
228
- width, height: headerHeight,
229
- fillColor: '#DDDDDD',
230
- bold: true
231
- }, groupShape.id);
232
- const bodyCenterY = bodyHeight / 2;
233
- await this.addShape({
234
- text: columns.join('\n'),
235
- x: width / 2,
236
- y: bodyCenterY,
237
- width, height: bodyHeight,
238
- fillColor: '#FFFFFF',
239
- fontColor: '#000000'
240
- }, groupShape.id);
241
- return groupShape;
287
+ return TablePattern_1.TablePattern.add(this, x, y, title, columns);
242
288
  }
243
289
  async addLayer(name, options) {
244
290
  const info = await this.modifier.addLayer(this.id, name, options);
package/dist/Shape.d.ts CHANGED
@@ -15,6 +15,21 @@ export interface ShapeHyperlink {
15
15
  description?: string;
16
16
  newWindow: boolean;
17
17
  }
18
+ /**
19
+ * A handle to a single shape on a Visio page.
20
+ *
21
+ * Obtain instances via {@link Page.addShape}, {@link Page.getShapes},
22
+ * {@link Page.getShapeById}, or {@link Page.findShapes}.
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * const shape = await page.addShape({ text: 'Box', x: 1, y: 1, width: 2, height: 1 });
27
+ * await shape.setStyle({ fillColor: '#4472C4', fontColor: '#ffffff', bold: true });
28
+ * console.log(shape.id, shape.x, shape.y);
29
+ * ```
30
+ *
31
+ * @category Shapes
32
+ */
18
33
  export declare class Shape {
19
34
  private internalShape;
20
35
  private pageId;
package/dist/Shape.js CHANGED
@@ -8,6 +8,21 @@ const VisioConstants_1 = require("./core/VisioConstants");
8
8
  function fmtCoord(n) {
9
9
  return parseFloat(n.toFixed(10)).toString();
10
10
  }
11
+ /**
12
+ * A handle to a single shape on a Visio page.
13
+ *
14
+ * Obtain instances via {@link Page.addShape}, {@link Page.getShapes},
15
+ * {@link Page.getShapeById}, or {@link Page.findShapes}.
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * const shape = await page.addShape({ text: 'Box', x: 1, y: 1, width: 2, height: 1 });
20
+ * await shape.setStyle({ fillColor: '#4472C4', fontColor: '#ffffff', bold: true });
21
+ * console.log(shape.id, shape.x, shape.y);
22
+ * ```
23
+ *
24
+ * @category Shapes
25
+ */
11
26
  class Shape {
12
27
  constructor(internalShape, pageId, pkg, modifier) {
13
28
  this.internalShape = internalShape;
@@ -1,5 +1,23 @@
1
1
  import { Page } from './Page';
2
2
  import { DocumentMetadata, StyleProps, StyleRecord, ColorEntry, MasterRecord, ShapeGeometry } from './types/VisioTypes';
3
+ /**
4
+ * The root object for reading and writing Visio (`.vsdx`) files.
5
+ *
6
+ * Create a blank document with {@link VisioDocument.create} or load an existing
7
+ * file with {@link VisioDocument.load}. Call {@link VisioDocument.save} when done.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * import { VisioDocument } from 'ts-visio';
12
+ *
13
+ * const doc = await VisioDocument.create();
14
+ * const page = doc.pages[0];
15
+ * await page.addShape({ text: 'Hello, Visio!', x: 1, y: 1, width: 3, height: 1 });
16
+ * await doc.save('output.vsdx');
17
+ * ```
18
+ *
19
+ * @category Documents
20
+ */
3
21
  export declare class VisioDocument {
4
22
  private pkg;
5
23
  private pageManager;
@@ -42,6 +42,24 @@ const MediaManager_1 = require("./core/MediaManager");
42
42
  const MetadataManager_1 = require("./core/MetadataManager");
43
43
  const StyleSheetManager_1 = require("./core/StyleSheetManager");
44
44
  const ColorManager_1 = require("./core/ColorManager");
45
+ /**
46
+ * The root object for reading and writing Visio (`.vsdx`) files.
47
+ *
48
+ * Create a blank document with {@link VisioDocument.create} or load an existing
49
+ * file with {@link VisioDocument.load}. Call {@link VisioDocument.save} when done.
50
+ *
51
+ * @example
52
+ * ```typescript
53
+ * import { VisioDocument } from 'ts-visio';
54
+ *
55
+ * const doc = await VisioDocument.create();
56
+ * const page = doc.pages[0];
57
+ * await page.addShape({ text: 'Hello, Visio!', x: 1, y: 1, width: 3, height: 1 });
58
+ * await doc.save('output.vsdx');
59
+ * ```
60
+ *
61
+ * @category Documents
62
+ */
45
63
  class VisioDocument {
46
64
  constructor(pkg) {
47
65
  this.pkg = pkg;
@@ -17,10 +17,9 @@ export declare class PageManager {
17
17
  constructor(pkg: VisioPackage);
18
18
  load(force?: boolean): PageEntry[];
19
19
  createPage(name: string): Promise<string>;
20
- /**
21
- * Create a background page
22
- */
20
+ /** Create a background page. */
23
21
  createBackgroundPage(name: string): Promise<string>;
22
+ private createPageInternal;
24
23
  /**
25
24
  * Delete a page and clean up all associated XML entries.
26
25
  * Removes the page file, its .rels file, the entry in pages.xml,
@@ -79,63 +79,13 @@ class PageManager {
79
79
  return this.pages;
80
80
  }
81
81
  async createPage(name) {
82
- this.load();
83
- let maxId = 0;
84
- for (const p of this.pages) {
85
- if (p.id > maxId)
86
- maxId = p.id;
87
- }
88
- const newId = maxId + 1;
89
- const fileName = `page${newId}.xml`;
90
- const relativePath = `visio/pages/${fileName}`;
91
- const pageContent = `<PageContents xmlns="${VisioConstants_1.XML_NAMESPACES.VISIO_MAIN}" xmlns:r="${VisioConstants_1.XML_NAMESPACES.RELATIONSHIPS_OFFICE}" xml:space="preserve">
92
- <PageSheet LineStyle="0" FillStyle="0" TextStyle="0">
93
- <Cell N="PageWidth" V="8.5"/>
94
- <Cell N="PageHeight" V="11"/>
95
- <Cell N="PageScale" V="1" Unit="MSG"/>
96
- <Cell N="DrawingScale" V="1" Unit="MSG"/>
97
- <Cell N="DrawingSizeType" V="0"/>
98
- <Cell N="DrawingScaleType" V="0"/>
99
- <Cell N="Inhibited" V="0"/>
100
- <Cell N="UIVisibility" V="0"/>
101
- <Cell N="PageDrawSizeType" V="0"/>
102
- </PageSheet>
103
- <Shapes/>
104
- <Connects/>
105
- </PageContents>`;
106
- this.pkg.updateFile(relativePath, pageContent);
107
- const ctPath = '[Content_Types].xml';
108
- const parsedCt = this.parser.parse(this.pkg.getFileText(ctPath));
109
- if (!parsedCt.Types.Override)
110
- parsedCt.Types.Override = [];
111
- if (!Array.isArray(parsedCt.Types.Override))
112
- parsedCt.Types.Override = [parsedCt.Types.Override];
113
- parsedCt.Types.Override.push({
114
- '@_PartName': `/${relativePath}`,
115
- '@_ContentType': VisioConstants_1.CONTENT_TYPES.VISIO_PAGE
116
- });
117
- this.pkg.updateFile(ctPath, (0, XmlHelper_1.buildXml)(this.builder, parsedCt));
118
- const rId = await this.relsManager.ensureRelationship('visio/pages/pages.xml', fileName, VisioConstants_1.RELATIONSHIP_TYPES.PAGE);
119
- const pagesPath = 'visio/pages/pages.xml';
120
- const parsedPages = this.parser.parse(this.pkg.getFileText(pagesPath));
121
- if (!parsedPages.Pages.Page)
122
- parsedPages.Pages.Page = [];
123
- if (!Array.isArray(parsedPages.Pages.Page))
124
- parsedPages.Pages.Page = [parsedPages.Pages.Page];
125
- parsedPages.Pages.Page.push({
126
- '@_ID': newId.toString(),
127
- '@_Name': name,
128
- '@_NameU': name,
129
- 'Rel': { '@_r:id': rId }
130
- });
131
- this.pkg.updateFile(pagesPath, (0, XmlHelper_1.buildXml)(this.builder, parsedPages));
132
- this.load(true);
133
- return newId.toString();
82
+ return this.createPageInternal(name, false);
134
83
  }
135
- /**
136
- * Create a background page
137
- */
84
+ /** Create a background page. */
138
85
  async createBackgroundPage(name) {
86
+ return this.createPageInternal(name, true);
87
+ }
88
+ async createPageInternal(name, isBackground) {
139
89
  this.load();
140
90
  let maxId = 0;
141
91
  for (const p of this.pages) {
@@ -179,13 +129,15 @@ class PageManager {
179
129
  parsedPages.Pages.Page = [];
180
130
  if (!Array.isArray(parsedPages.Pages.Page))
181
131
  parsedPages.Pages.Page = [parsedPages.Pages.Page];
182
- parsedPages.Pages.Page.push({
132
+ const entry = {
183
133
  '@_ID': newId.toString(),
184
134
  '@_Name': name,
185
135
  '@_NameU': name,
186
- '@_Background': '1',
187
- 'Rel': { '@_r:id': rId }
188
- });
136
+ };
137
+ if (isBackground)
138
+ entry['@_Background'] = '1';
139
+ entry['Rel'] = { '@_r:id': rId };
140
+ parsedPages.Pages.Page.push(entry);
189
141
  this.pkg.updateFile(pagesPath, (0, XmlHelper_1.buildXml)(this.builder, parsedPages));
190
142
  this.load(true);
191
143
  return newId.toString();
@@ -0,0 +1,22 @@
1
+ import type { Page } from '../Page';
2
+ import type { Shape } from '../Shape';
3
+ export type RelationType = '1:1' | '1:N';
4
+ export declare class SchemaDiagram {
5
+ private page;
6
+ constructor(page: Page);
7
+ /**
8
+ * Adds a table entity to the diagram.
9
+ * @param tableName Name of the table
10
+ * @param columns List of column names (e.g., "id: int")
11
+ * @param x X coordinate
12
+ * @param y Y coordinate
13
+ */
14
+ addTable(tableName: string, columns: string[], x?: number, y?: number): Promise<Shape>;
15
+ /**
16
+ * Connects two tables with a specific relationship type.
17
+ * @param fromTable Source table shape
18
+ * @param toTable Target table shape
19
+ * @param type Relationship type ('1:1' or '1:N')
20
+ */
21
+ addRelation(fromTable: Shape, toTable: Shape, type: RelationType): Promise<void>;
22
+ }
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SchemaDiagram = void 0;
4
+ class SchemaDiagram {
5
+ constructor(page) {
6
+ this.page = page;
7
+ }
8
+ /**
9
+ * Adds a table entity to the diagram.
10
+ * @param tableName Name of the table
11
+ * @param columns List of column names (e.g., "id: int")
12
+ * @param x X coordinate
13
+ * @param y Y coordinate
14
+ */
15
+ async addTable(tableName, columns, x = 0, y = 0) {
16
+ return this.page.addTable(x, y, tableName, columns);
17
+ }
18
+ /**
19
+ * Connects two tables with a specific relationship type.
20
+ * @param fromTable Source table shape
21
+ * @param toTable Target table shape
22
+ * @param type Relationship type ('1:1' or '1:N')
23
+ */
24
+ async addRelation(fromTable, toTable, type) {
25
+ let beginArrow = '0'; // No arrow at start
26
+ let endArrow = '1'; // Default standard arrow
27
+ if (type === '1:1') {
28
+ endArrow = '1'; // Standard Arrow
29
+ }
30
+ else if (type === '1:N') {
31
+ endArrow = '29'; // Crow's Foot
32
+ }
33
+ await this.page.connectShapes(fromTable, toTable, beginArrow, endArrow);
34
+ }
35
+ }
36
+ exports.SchemaDiagram = SchemaDiagram;
@@ -0,0 +1,14 @@
1
+ import type { Page } from '../Page';
2
+ import type { Shape } from '../Shape';
3
+ import type { NewShapeProps } from '../types/VisioTypes';
4
+ /**
5
+ * Swimlane composition helpers.
6
+ *
7
+ * A swimlane diagram is modelled as a vertical List (the pool) containing
8
+ * one or more Containers (the lanes). Used by `page.addSwimlanePool()` and
9
+ * `page.addSwimlaneLane()`.
10
+ */
11
+ export declare class SwimlanePattern {
12
+ static addPool(page: Page, props: NewShapeProps): Promise<Shape>;
13
+ static addLane(page: Page, props: NewShapeProps): Promise<Shape>;
14
+ }
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SwimlanePattern = void 0;
4
+ /**
5
+ * Swimlane composition helpers.
6
+ *
7
+ * A swimlane diagram is modelled as a vertical List (the pool) containing
8
+ * one or more Containers (the lanes). Used by `page.addSwimlanePool()` and
9
+ * `page.addSwimlaneLane()`.
10
+ */
11
+ class SwimlanePattern {
12
+ static async addPool(page, props) {
13
+ return page.addList(props, 'vertical');
14
+ }
15
+ static async addLane(page, props) {
16
+ return page.addContainer(props);
17
+ }
18
+ }
19
+ exports.SwimlanePattern = SwimlanePattern;
@@ -0,0 +1,11 @@
1
+ import type { Page } from '../Page';
2
+ import type { Shape } from '../Shape';
3
+ /**
4
+ * High-level table composition: a group shape containing a shaded header row
5
+ * and a body row whose text lists the column names.
6
+ *
7
+ * Used by `page.addTable()` and `SchemaDiagram.addTable()`.
8
+ */
9
+ export declare class TablePattern {
10
+ static add(page: Page, x: number, y: number, title: string, columns: string[]): Promise<Shape>;
11
+ }
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TablePattern = void 0;
4
+ /**
5
+ * High-level table composition: a group shape containing a shaded header row
6
+ * and a body row whose text lists the column names.
7
+ *
8
+ * Used by `page.addTable()` and `SchemaDiagram.addTable()`.
9
+ */
10
+ class TablePattern {
11
+ static async add(page, x, y, title, columns) {
12
+ const width = 3;
13
+ const headerHeight = 0.5;
14
+ const lineItemHeight = 0.25;
15
+ const bodyHeight = Math.max(0.5, columns.length * lineItemHeight + 0.1);
16
+ const totalHeight = headerHeight + bodyHeight;
17
+ // Group contains a header row and a body row; child coords are relative to the group origin.
18
+ const groupShape = await page.addShape({
19
+ text: '',
20
+ x, y, width, height: totalHeight,
21
+ type: 'Group',
22
+ });
23
+ const headerCenterY = bodyHeight + (headerHeight / 2);
24
+ await page.addShape({
25
+ text: title,
26
+ x: width / 2,
27
+ y: headerCenterY,
28
+ width, height: headerHeight,
29
+ fillColor: '#DDDDDD',
30
+ bold: true,
31
+ }, groupShape.id);
32
+ const bodyCenterY = bodyHeight / 2;
33
+ await page.addShape({
34
+ text: columns.join('\n'),
35
+ x: width / 2,
36
+ y: bodyCenterY,
37
+ width, height: bodyHeight,
38
+ fillColor: '#FFFFFF',
39
+ fontColor: '#000000',
40
+ }, groupShape.id);
41
+ return groupShape;
42
+ }
43
+ }
44
+ exports.TablePattern = TablePattern;
package/dist/index.d.ts CHANGED
@@ -5,7 +5,9 @@ export { Connector } from './Connector';
5
5
  export type { ConnectorData } from './Connector';
6
6
  export type { ShapeData, ShapeHyperlink } from './Shape';
7
7
  export { Layer } from './Layer';
8
- export { SchemaDiagram } from './SchemaDiagram';
8
+ export { SchemaDiagram } from './diagrams/SchemaDiagram';
9
+ export { TablePattern } from './diagrams/TablePattern';
10
+ export { SwimlanePattern } from './diagrams/SwimlanePattern';
9
11
  export { VisioValidator } from './core/VisioValidator';
10
12
  export * from './types/VisioTypes';
11
13
  export { ArrowHeads, hexToRgb } from './utils/StyleHelpers';
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.hexToRgb = exports.ArrowHeads = exports.VisioValidator = exports.SchemaDiagram = exports.Layer = exports.Connector = exports.Shape = exports.Page = exports.VisioDocument = void 0;
17
+ exports.hexToRgb = exports.ArrowHeads = exports.VisioValidator = exports.SwimlanePattern = exports.TablePattern = exports.SchemaDiagram = exports.Layer = exports.Connector = exports.Shape = exports.Page = exports.VisioDocument = void 0;
18
18
  var VisioDocument_1 = require("./VisioDocument");
19
19
  Object.defineProperty(exports, "VisioDocument", { enumerable: true, get: function () { return VisioDocument_1.VisioDocument; } });
20
20
  var Page_1 = require("./Page");
@@ -25,8 +25,12 @@ var Connector_1 = require("./Connector");
25
25
  Object.defineProperty(exports, "Connector", { enumerable: true, get: function () { return Connector_1.Connector; } });
26
26
  var Layer_1 = require("./Layer");
27
27
  Object.defineProperty(exports, "Layer", { enumerable: true, get: function () { return Layer_1.Layer; } });
28
- var SchemaDiagram_1 = require("./SchemaDiagram");
28
+ var SchemaDiagram_1 = require("./diagrams/SchemaDiagram");
29
29
  Object.defineProperty(exports, "SchemaDiagram", { enumerable: true, get: function () { return SchemaDiagram_1.SchemaDiagram; } });
30
+ var TablePattern_1 = require("./diagrams/TablePattern");
31
+ Object.defineProperty(exports, "TablePattern", { enumerable: true, get: function () { return TablePattern_1.TablePattern; } });
32
+ var SwimlanePattern_1 = require("./diagrams/SwimlanePattern");
33
+ Object.defineProperty(exports, "SwimlanePattern", { enumerable: true, get: function () { return SwimlanePattern_1.SwimlanePattern; } });
30
34
  var VisioValidator_1 = require("./core/VisioValidator");
31
35
  Object.defineProperty(exports, "VisioValidator", { enumerable: true, get: function () { return VisioValidator_1.VisioValidator; } });
32
36
  __exportStar(require("./types/VisioTypes"), exports);
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "ts-visio",
3
- "version": "1.15.0",
3
+ "version": "1.16.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "scripts": {
7
7
  "test": "vitest",
8
8
  "build": "tsc",
9
+ "docs:generate": "typedoc",
9
10
  "prepublishOnly": "npm run build"
10
11
  },
11
12
  "files": [
@@ -26,6 +27,7 @@
26
27
  "devDependencies": {
27
28
  "@types/node": "^25.0.9",
28
29
  "tsx": "^4.21.0",
30
+ "typedoc": "^0.28.17",
29
31
  "typescript": "^5.9.3",
30
32
  "vitest": "^4.0.17"
31
33
  }