ts-visio 1.3.0 → 1.5.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 +69 -1
- package/dist/ShapeModifier.d.ts +20 -0
- package/dist/ShapeModifier.js +37 -4
- package/dist/VisioDocument.d.ts +15 -0
- package/dist/VisioDocument.js +19 -0
- package/dist/core/MetadataManager.d.ts +22 -0
- package/dist/core/MetadataManager.js +154 -0
- package/dist/shapes/ShapeBuilder.js +34 -3
- package/dist/types/VisioTypes.d.ts +41 -0
- package/dist/utils/StyleHelpers.d.ts +38 -1
- package/dist/utils/StyleHelpers.js +40 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,12 +18,13 @@ Built using specific schema-level abstractions to handle the complex internal st
|
|
|
18
18
|
- **Modify Content**: Update text content of shapes.
|
|
19
19
|
- **Create Shapes**: Rectangles, ellipses, diamonds, rounded rectangles, triangles, parallelograms.
|
|
20
20
|
- **Connect Shapes**: Dynamic connectors with arrow styles, line styling, and routing (straight / orthogonal / curved).
|
|
21
|
-
- **Text Styling**: Font size, font family, bold, color,
|
|
21
|
+
- **Text Styling**: Font size, font family, bold, italic, underline, strikethrough, color, alignment, paragraph spacing, and text margins.
|
|
22
22
|
- **Shape Transformations**: Rotate, flip (X/Y), and resize shapes via a fluent API.
|
|
23
23
|
- **Deletion**: Remove shapes and pages cleanly (including orphaned connectors and relationships).
|
|
24
24
|
- **Lookup API**: Find shapes by ID, predicate, or look up pages by name.
|
|
25
25
|
- **Read-Back API**: Read custom properties, hyperlinks, and layer assignments from existing shapes.
|
|
26
26
|
- **Page Size & Orientation**: Set canvas dimensions with named sizes (`Letter`, `A4`, …) or raw inches; rotate between portrait and landscape.
|
|
27
|
+
- **Document Metadata**: Read and write document properties (title, author, description, keywords, company, dates) via `doc.getMetadata()` / `doc.setMetadata()`.
|
|
27
28
|
|
|
28
29
|
Feature gaps are being tracked in [FEATURES.md](./FEATURES.md).
|
|
29
30
|
|
|
@@ -490,6 +491,73 @@ Available named sizes in `PageSizes`: `Letter`, `Legal`, `Tabloid`, `A3`, `A4`,
|
|
|
490
491
|
|
|
491
492
|
---
|
|
492
493
|
|
|
494
|
+
#### 26. Document Metadata
|
|
495
|
+
Set and read document-level properties that appear in Visio's Document Properties dialog.
|
|
496
|
+
|
|
497
|
+
```typescript
|
|
498
|
+
// Write metadata (only supplied fields are changed)
|
|
499
|
+
doc.setMetadata({
|
|
500
|
+
title: 'Network Topology',
|
|
501
|
+
author: 'Alice',
|
|
502
|
+
description: 'Data-centre interconnect diagram',
|
|
503
|
+
keywords: 'network datacenter cloud',
|
|
504
|
+
lastModifiedBy: 'CI pipeline',
|
|
505
|
+
company: 'ACME Corp',
|
|
506
|
+
manager: 'Bob',
|
|
507
|
+
created: new Date('2025-01-01T00:00:00Z'),
|
|
508
|
+
modified: new Date(),
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
// Read back all metadata fields
|
|
512
|
+
const meta = doc.getMetadata();
|
|
513
|
+
console.log(meta.title); // 'Network Topology'
|
|
514
|
+
console.log(meta.author); // 'Alice'
|
|
515
|
+
console.log(meta.company); // 'ACME Corp'
|
|
516
|
+
console.log(meta.created); // Date object
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
Fields map to OPC parts: `title`, `author`, `description`, `keywords`, `lastModifiedBy`,
|
|
520
|
+
`created`, `modified` → `docProps/core.xml`; `company`, `manager` → `docProps/app.xml`.
|
|
521
|
+
|
|
522
|
+
---
|
|
523
|
+
|
|
524
|
+
#### 27. Rich Text Formatting
|
|
525
|
+
Italic, underline, strikethrough, paragraph spacing, and text block margins are available both at shape-creation time and via `shape.setStyle()`.
|
|
526
|
+
|
|
527
|
+
```typescript
|
|
528
|
+
// At creation time
|
|
529
|
+
const shape = await page.addShape({
|
|
530
|
+
text: 'Important',
|
|
531
|
+
x: 2, y: 3, width: 3, height: 1,
|
|
532
|
+
bold: true,
|
|
533
|
+
italic: true,
|
|
534
|
+
underline: true,
|
|
535
|
+
strikethrough: false,
|
|
536
|
+
// Paragraph spacing (in points)
|
|
537
|
+
spaceBefore: 6,
|
|
538
|
+
spaceAfter: 6,
|
|
539
|
+
lineSpacing: 1.5, // 1.5× line height
|
|
540
|
+
// Text block margins (in inches)
|
|
541
|
+
textMarginTop: 0.1,
|
|
542
|
+
textMarginBottom: 0.1,
|
|
543
|
+
textMarginLeft: 0.1,
|
|
544
|
+
textMarginRight: 0.1,
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
// Post-creation via setStyle()
|
|
548
|
+
await shape.setStyle({
|
|
549
|
+
italic: true,
|
|
550
|
+
lineSpacing: 2.0, // double spacing
|
|
551
|
+
textMarginTop: 0.15,
|
|
552
|
+
textMarginLeft: 0.05,
|
|
553
|
+
});
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
`lineSpacing` is a multiplier: `1.0` = single, `1.5` = 1.5×, `2.0` = double.
|
|
557
|
+
`spaceBefore` / `spaceAfter` are in **points**. Text margins are in **inches**.
|
|
558
|
+
|
|
559
|
+
---
|
|
560
|
+
|
|
493
561
|
## Examples
|
|
494
562
|
|
|
495
563
|
Check out the [examples](./examples) directory for complete scripts.
|
package/dist/ShapeModifier.d.ts
CHANGED
|
@@ -121,6 +121,12 @@ export interface ShapeStyle {
|
|
|
121
121
|
fillColor?: string;
|
|
122
122
|
fontColor?: string;
|
|
123
123
|
bold?: boolean;
|
|
124
|
+
/** Italic text. */
|
|
125
|
+
italic?: boolean;
|
|
126
|
+
/** Underline text. */
|
|
127
|
+
underline?: boolean;
|
|
128
|
+
/** Strikethrough text. */
|
|
129
|
+
strikethrough?: boolean;
|
|
124
130
|
/** Font size in points (e.g. 14 for 14pt). */
|
|
125
131
|
fontSize?: number;
|
|
126
132
|
/** Font family name (e.g. "Arial"). */
|
|
@@ -129,4 +135,18 @@ export interface ShapeStyle {
|
|
|
129
135
|
horzAlign?: HorzAlign;
|
|
130
136
|
/** Vertical text alignment. */
|
|
131
137
|
verticalAlign?: VertAlign;
|
|
138
|
+
/** Space before each paragraph in **points**. */
|
|
139
|
+
spaceBefore?: number;
|
|
140
|
+
/** Space after each paragraph in **points**. */
|
|
141
|
+
spaceAfter?: number;
|
|
142
|
+
/** Line-height multiplier (1.0 = single, 1.5 = 1.5×, 2.0 = double). */
|
|
143
|
+
lineSpacing?: number;
|
|
144
|
+
/** Top text margin in inches. */
|
|
145
|
+
textMarginTop?: number;
|
|
146
|
+
/** Bottom text margin in inches. */
|
|
147
|
+
textMarginBottom?: number;
|
|
148
|
+
/** Left text margin in inches. */
|
|
149
|
+
textMarginLeft?: number;
|
|
150
|
+
/** Right text margin in inches. */
|
|
151
|
+
textMarginRight?: number;
|
|
132
152
|
}
|
package/dist/ShapeModifier.js
CHANGED
|
@@ -349,19 +349,52 @@ class ShapeModifier {
|
|
|
349
349
|
shape.Section.push((0, StyleHelpers_1.createFillSection)(style.fillColor));
|
|
350
350
|
}
|
|
351
351
|
// Update/Add Character (Font/Text Style)
|
|
352
|
-
|
|
352
|
+
const hasCharProps = style.fontColor !== undefined
|
|
353
|
+
|| style.bold !== undefined
|
|
354
|
+
|| style.italic !== undefined
|
|
355
|
+
|| style.underline !== undefined
|
|
356
|
+
|| style.strikethrough !== undefined
|
|
357
|
+
|| style.fontSize !== undefined
|
|
358
|
+
|| style.fontFamily !== undefined;
|
|
359
|
+
if (hasCharProps) {
|
|
353
360
|
shape.Section = shape.Section.filter((s) => s['@_N'] !== 'Character');
|
|
354
361
|
shape.Section.push((0, StyleHelpers_1.createCharacterSection)({
|
|
355
362
|
bold: style.bold,
|
|
363
|
+
italic: style.italic,
|
|
364
|
+
underline: style.underline,
|
|
365
|
+
strikethrough: style.strikethrough,
|
|
356
366
|
color: style.fontColor,
|
|
357
367
|
fontSize: style.fontSize,
|
|
358
368
|
fontFamily: style.fontFamily,
|
|
359
369
|
}));
|
|
360
370
|
}
|
|
361
|
-
// Update/Add Paragraph
|
|
362
|
-
|
|
371
|
+
// Update/Add Paragraph
|
|
372
|
+
const hasParagraphProps = style.horzAlign !== undefined
|
|
373
|
+
|| style.spaceBefore !== undefined
|
|
374
|
+
|| style.spaceAfter !== undefined
|
|
375
|
+
|| style.lineSpacing !== undefined;
|
|
376
|
+
if (hasParagraphProps) {
|
|
363
377
|
shape.Section = shape.Section.filter((s) => s['@_N'] !== 'Paragraph');
|
|
364
|
-
shape.Section.push((0, StyleHelpers_1.createParagraphSection)(
|
|
378
|
+
shape.Section.push((0, StyleHelpers_1.createParagraphSection)({
|
|
379
|
+
horzAlign: style.horzAlign,
|
|
380
|
+
spaceBefore: style.spaceBefore,
|
|
381
|
+
spaceAfter: style.spaceAfter,
|
|
382
|
+
lineSpacing: style.lineSpacing,
|
|
383
|
+
}));
|
|
384
|
+
}
|
|
385
|
+
// Update/Add TextBlock (text margins)
|
|
386
|
+
const hasTextBlockProps = style.textMarginTop !== undefined
|
|
387
|
+
|| style.textMarginBottom !== undefined
|
|
388
|
+
|| style.textMarginLeft !== undefined
|
|
389
|
+
|| style.textMarginRight !== undefined;
|
|
390
|
+
if (hasTextBlockProps) {
|
|
391
|
+
shape.Section = shape.Section.filter((s) => s['@_N'] !== 'TextBlock');
|
|
392
|
+
shape.Section.push((0, StyleHelpers_1.createTextBlockSection)({
|
|
393
|
+
topMargin: style.textMarginTop,
|
|
394
|
+
bottomMargin: style.textMarginBottom,
|
|
395
|
+
leftMargin: style.textMarginLeft,
|
|
396
|
+
rightMargin: style.textMarginRight,
|
|
397
|
+
}));
|
|
365
398
|
}
|
|
366
399
|
// Update/Add VerticalAlign (top-level shape Cell)
|
|
367
400
|
if (style.verticalAlign !== undefined) {
|
package/dist/VisioDocument.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { Page } from './Page';
|
|
2
|
+
import { DocumentMetadata } from './types/VisioTypes';
|
|
2
3
|
export declare class VisioDocument {
|
|
3
4
|
private pkg;
|
|
4
5
|
private pageManager;
|
|
5
6
|
private _pageCache;
|
|
6
7
|
private mediaManager;
|
|
8
|
+
private metadataManager;
|
|
7
9
|
private constructor();
|
|
8
10
|
static create(): Promise<VisioDocument>;
|
|
9
11
|
static load(pathOrBuffer: string | Buffer | ArrayBuffer | Uint8Array): Promise<VisioDocument>;
|
|
@@ -27,5 +29,18 @@ export declare class VisioDocument {
|
|
|
27
29
|
* and any BackPage references from other pages.
|
|
28
30
|
*/
|
|
29
31
|
deletePage(page: Page): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Read document metadata from `docProps/core.xml` and `docProps/app.xml`.
|
|
34
|
+
* Fields not present in the file are returned as `undefined`.
|
|
35
|
+
*/
|
|
36
|
+
getMetadata(): DocumentMetadata;
|
|
37
|
+
/**
|
|
38
|
+
* Write document metadata. Only the supplied fields are changed;
|
|
39
|
+
* all other fields keep their existing values.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* doc.setMetadata({ title: 'My Diagram', author: 'Alice', company: 'ACME' });
|
|
43
|
+
*/
|
|
44
|
+
setMetadata(props: Partial<DocumentMetadata>): void;
|
|
30
45
|
save(filename?: string): Promise<Buffer>;
|
|
31
46
|
}
|
package/dist/VisioDocument.js
CHANGED
|
@@ -38,12 +38,14 @@ const VisioPackage_1 = require("./VisioPackage");
|
|
|
38
38
|
const PageManager_1 = require("./core/PageManager");
|
|
39
39
|
const Page_1 = require("./Page");
|
|
40
40
|
const MediaManager_1 = require("./core/MediaManager");
|
|
41
|
+
const MetadataManager_1 = require("./core/MetadataManager");
|
|
41
42
|
class VisioDocument {
|
|
42
43
|
constructor(pkg) {
|
|
43
44
|
this.pkg = pkg;
|
|
44
45
|
this._pageCache = null;
|
|
45
46
|
this.pageManager = new PageManager_1.PageManager(pkg);
|
|
46
47
|
this.mediaManager = new MediaManager_1.MediaManager(pkg);
|
|
48
|
+
this.metadataManager = new MetadataManager_1.MetadataManager(pkg);
|
|
47
49
|
}
|
|
48
50
|
static async create() {
|
|
49
51
|
const pkg = await VisioPackage_1.VisioPackage.create();
|
|
@@ -131,6 +133,23 @@ class VisioDocument {
|
|
|
131
133
|
await this.pageManager.deletePage(page.id);
|
|
132
134
|
this._pageCache = null;
|
|
133
135
|
}
|
|
136
|
+
/**
|
|
137
|
+
* Read document metadata from `docProps/core.xml` and `docProps/app.xml`.
|
|
138
|
+
* Fields not present in the file are returned as `undefined`.
|
|
139
|
+
*/
|
|
140
|
+
getMetadata() {
|
|
141
|
+
return this.metadataManager.getMetadata();
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Write document metadata. Only the supplied fields are changed;
|
|
145
|
+
* all other fields keep their existing values.
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* doc.setMetadata({ title: 'My Diagram', author: 'Alice', company: 'ACME' });
|
|
149
|
+
*/
|
|
150
|
+
setMetadata(props) {
|
|
151
|
+
this.metadataManager.setMetadata(props);
|
|
152
|
+
}
|
|
134
153
|
async save(filename) {
|
|
135
154
|
return this.pkg.save(filename);
|
|
136
155
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { VisioPackage } from '../VisioPackage';
|
|
2
|
+
import { DocumentMetadata } from '../types/VisioTypes';
|
|
3
|
+
export declare class MetadataManager {
|
|
4
|
+
private pkg;
|
|
5
|
+
private parser;
|
|
6
|
+
private builder;
|
|
7
|
+
constructor(pkg: VisioPackage);
|
|
8
|
+
/** Read document metadata from `docProps/core.xml` and `docProps/app.xml`. */
|
|
9
|
+
getMetadata(): DocumentMetadata;
|
|
10
|
+
/** Merge the supplied fields into the existing metadata and persist to the package. */
|
|
11
|
+
setMetadata(props: Partial<DocumentMetadata>): void;
|
|
12
|
+
/** Extract a string from a parsed XML node (handles plain strings and #text objects). */
|
|
13
|
+
private str;
|
|
14
|
+
/** Parse an ISO datetime string into a Date (returns undefined on failure). */
|
|
15
|
+
private date;
|
|
16
|
+
private parsedCore;
|
|
17
|
+
private parsedApp;
|
|
18
|
+
private writeCore;
|
|
19
|
+
private writeApp;
|
|
20
|
+
private blankCoreParsed;
|
|
21
|
+
private blankAppParsed;
|
|
22
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MetadataManager = void 0;
|
|
4
|
+
const VisioConstants_1 = require("./VisioConstants");
|
|
5
|
+
const XmlHelper_1 = require("../utils/XmlHelper");
|
|
6
|
+
class MetadataManager {
|
|
7
|
+
constructor(pkg) {
|
|
8
|
+
this.pkg = pkg;
|
|
9
|
+
this.parser = (0, XmlHelper_1.createXmlParser)();
|
|
10
|
+
this.builder = (0, XmlHelper_1.createXmlBuilder)();
|
|
11
|
+
}
|
|
12
|
+
// ---- public API --------------------------------------------------------
|
|
13
|
+
/** Read document metadata from `docProps/core.xml` and `docProps/app.xml`. */
|
|
14
|
+
getMetadata() {
|
|
15
|
+
const core = this.parsedCore();
|
|
16
|
+
const app = this.parsedApp();
|
|
17
|
+
return {
|
|
18
|
+
title: this.str(core['dc:title']),
|
|
19
|
+
author: this.str(core['dc:creator']),
|
|
20
|
+
description: this.str(core['dc:description']),
|
|
21
|
+
keywords: this.str(core['cp:keywords']),
|
|
22
|
+
lastModifiedBy: this.str(core['cp:lastModifiedBy']),
|
|
23
|
+
created: this.date(core['dcterms:created']),
|
|
24
|
+
modified: this.date(core['dcterms:modified']),
|
|
25
|
+
company: this.str(app['Company']),
|
|
26
|
+
manager: this.str(app['Manager']),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/** Merge the supplied fields into the existing metadata and persist to the package. */
|
|
30
|
+
setMetadata(props) {
|
|
31
|
+
const coreKeys = [
|
|
32
|
+
'title', 'author', 'description', 'keywords', 'lastModifiedBy', 'created', 'modified',
|
|
33
|
+
];
|
|
34
|
+
const appKeys = ['company', 'manager'];
|
|
35
|
+
if (coreKeys.some(k => k in props))
|
|
36
|
+
this.writeCore(props);
|
|
37
|
+
if (appKeys.some(k => k in props))
|
|
38
|
+
this.writeApp(props);
|
|
39
|
+
}
|
|
40
|
+
// ---- private helpers ---------------------------------------------------
|
|
41
|
+
/** Extract a string from a parsed XML node (handles plain strings and #text objects). */
|
|
42
|
+
str(val) {
|
|
43
|
+
if (val === undefined || val === null)
|
|
44
|
+
return undefined;
|
|
45
|
+
if (typeof val === 'string')
|
|
46
|
+
return val || undefined;
|
|
47
|
+
if (typeof val === 'object' && '#text' in val) {
|
|
48
|
+
const t = val['#text'];
|
|
49
|
+
const s = typeof t === 'string' ? t : String(t);
|
|
50
|
+
return s || undefined;
|
|
51
|
+
}
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
/** Parse an ISO datetime string into a Date (returns undefined on failure). */
|
|
55
|
+
date(val) {
|
|
56
|
+
const text = this.str(val);
|
|
57
|
+
if (!text)
|
|
58
|
+
return undefined;
|
|
59
|
+
const d = new Date(text);
|
|
60
|
+
return isNaN(d.getTime()) ? undefined : d;
|
|
61
|
+
}
|
|
62
|
+
parsedCore() {
|
|
63
|
+
try {
|
|
64
|
+
const xml = this.pkg.getFileText('docProps/core.xml');
|
|
65
|
+
const parsed = this.parser.parse(xml);
|
|
66
|
+
return parsed['cp:coreProperties'] ?? {};
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return {};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
parsedApp() {
|
|
73
|
+
try {
|
|
74
|
+
const xml = this.pkg.getFileText('docProps/app.xml');
|
|
75
|
+
const parsed = this.parser.parse(xml);
|
|
76
|
+
return parsed['Properties'] ?? {};
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return {};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
writeCore(props) {
|
|
83
|
+
let parsed;
|
|
84
|
+
try {
|
|
85
|
+
const xml = this.pkg.getFileText('docProps/core.xml');
|
|
86
|
+
parsed = this.parser.parse(xml);
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
parsed = this.blankCoreParsed();
|
|
90
|
+
}
|
|
91
|
+
const root = parsed['cp:coreProperties'];
|
|
92
|
+
if ('title' in props)
|
|
93
|
+
root['dc:title'] = props.title ?? '';
|
|
94
|
+
if ('author' in props)
|
|
95
|
+
root['dc:creator'] = props.author ?? '';
|
|
96
|
+
if ('description' in props)
|
|
97
|
+
root['dc:description'] = props.description ?? '';
|
|
98
|
+
if ('keywords' in props)
|
|
99
|
+
root['cp:keywords'] = props.keywords ?? '';
|
|
100
|
+
if ('lastModifiedBy' in props)
|
|
101
|
+
root['cp:lastModifiedBy'] = props.lastModifiedBy ?? '';
|
|
102
|
+
if ('created' in props && props.created !== undefined) {
|
|
103
|
+
root['dcterms:created'] = {
|
|
104
|
+
'@_xsi:type': 'dcterms:W3CDTF',
|
|
105
|
+
'#text': props.created.toISOString(),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
if ('modified' in props && props.modified !== undefined) {
|
|
109
|
+
root['dcterms:modified'] = {
|
|
110
|
+
'@_xsi:type': 'dcterms:W3CDTF',
|
|
111
|
+
'#text': props.modified.toISOString(),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
this.pkg.updateFile('docProps/core.xml', (0, XmlHelper_1.buildXml)(this.builder, parsed));
|
|
115
|
+
}
|
|
116
|
+
writeApp(props) {
|
|
117
|
+
let parsed;
|
|
118
|
+
try {
|
|
119
|
+
const xml = this.pkg.getFileText('docProps/app.xml');
|
|
120
|
+
parsed = this.parser.parse(xml);
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
parsed = this.blankAppParsed();
|
|
124
|
+
}
|
|
125
|
+
const root = parsed['Properties'];
|
|
126
|
+
if ('company' in props)
|
|
127
|
+
root['Company'] = props.company ?? '';
|
|
128
|
+
if ('manager' in props)
|
|
129
|
+
root['Manager'] = props.manager ?? '';
|
|
130
|
+
this.pkg.updateFile('docProps/app.xml', (0, XmlHelper_1.buildXml)(this.builder, parsed));
|
|
131
|
+
}
|
|
132
|
+
blankCoreParsed() {
|
|
133
|
+
return {
|
|
134
|
+
'cp:coreProperties': {
|
|
135
|
+
'@_xmlns:cp': VisioConstants_1.XML_NAMESPACES.CORE_PROPERTIES,
|
|
136
|
+
'@_xmlns:dc': VisioConstants_1.XML_NAMESPACES.DC_ELEMENTS,
|
|
137
|
+
'@_xmlns:dcterms': VisioConstants_1.XML_NAMESPACES.DC_TERMS,
|
|
138
|
+
'@_xmlns:dcmitype': VisioConstants_1.XML_NAMESPACES.DC_DCMITYPE,
|
|
139
|
+
'@_xmlns:xsi': VisioConstants_1.XML_NAMESPACES.XSI,
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
blankAppParsed() {
|
|
144
|
+
return {
|
|
145
|
+
'Properties': {
|
|
146
|
+
'@_xmlns': VisioConstants_1.XML_NAMESPACES.EXTENDED_PROPERTIES,
|
|
147
|
+
'@_xmlns:vt': VisioConstants_1.XML_NAMESPACES.DOC_PROPS_VTYPES,
|
|
148
|
+
'Application': 'ts-visio',
|
|
149
|
+
'Template': 'Basic',
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
exports.MetadataManager = MetadataManager;
|
|
@@ -37,16 +37,47 @@ class ShapeBuilder {
|
|
|
37
37
|
weight: '0.01'
|
|
38
38
|
}));
|
|
39
39
|
}
|
|
40
|
-
|
|
40
|
+
const hasCharProps = props.fontColor !== undefined
|
|
41
|
+
|| props.bold !== undefined
|
|
42
|
+
|| props.italic !== undefined
|
|
43
|
+
|| props.underline !== undefined
|
|
44
|
+
|| props.strikethrough !== undefined
|
|
45
|
+
|| props.fontSize !== undefined
|
|
46
|
+
|| props.fontFamily !== undefined;
|
|
47
|
+
if (hasCharProps) {
|
|
41
48
|
shape.Section.push((0, StyleHelpers_1.createCharacterSection)({
|
|
42
49
|
bold: props.bold,
|
|
50
|
+
italic: props.italic,
|
|
51
|
+
underline: props.underline,
|
|
52
|
+
strikethrough: props.strikethrough,
|
|
43
53
|
color: props.fontColor,
|
|
44
54
|
fontSize: props.fontSize,
|
|
45
55
|
fontFamily: props.fontFamily,
|
|
46
56
|
}));
|
|
47
57
|
}
|
|
48
|
-
|
|
49
|
-
|
|
58
|
+
const hasParagraphProps = props.horzAlign !== undefined
|
|
59
|
+
|| props.spaceBefore !== undefined
|
|
60
|
+
|| props.spaceAfter !== undefined
|
|
61
|
+
|| props.lineSpacing !== undefined;
|
|
62
|
+
if (hasParagraphProps) {
|
|
63
|
+
shape.Section.push((0, StyleHelpers_1.createParagraphSection)({
|
|
64
|
+
horzAlign: props.horzAlign,
|
|
65
|
+
spaceBefore: props.spaceBefore,
|
|
66
|
+
spaceAfter: props.spaceAfter,
|
|
67
|
+
lineSpacing: props.lineSpacing,
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
70
|
+
const hasTextBlockProps = props.textMarginTop !== undefined
|
|
71
|
+
|| props.textMarginBottom !== undefined
|
|
72
|
+
|| props.textMarginLeft !== undefined
|
|
73
|
+
|| props.textMarginRight !== undefined;
|
|
74
|
+
if (hasTextBlockProps) {
|
|
75
|
+
shape.Section.push((0, StyleHelpers_1.createTextBlockSection)({
|
|
76
|
+
topMargin: props.textMarginTop,
|
|
77
|
+
bottomMargin: props.textMarginBottom,
|
|
78
|
+
leftMargin: props.textMarginLeft,
|
|
79
|
+
rightMargin: props.textMarginRight,
|
|
80
|
+
}));
|
|
50
81
|
}
|
|
51
82
|
if (props.verticalAlign !== undefined) {
|
|
52
83
|
shape.Cell.push({ '@_N': 'VerticalAlign', '@_V': (0, StyleHelpers_1.vertAlignValue)(props.verticalAlign) });
|
|
@@ -72,6 +72,27 @@ export declare enum VisioPropType {
|
|
|
72
72
|
Duration = 6,
|
|
73
73
|
Currency = 7
|
|
74
74
|
}
|
|
75
|
+
/** Document-level metadata that maps to `docProps/core.xml` and `docProps/app.xml`. */
|
|
76
|
+
export interface DocumentMetadata {
|
|
77
|
+
/** Document title (`dc:title`). */
|
|
78
|
+
title?: string;
|
|
79
|
+
/** Author / creator (`dc:creator`). */
|
|
80
|
+
author?: string;
|
|
81
|
+
/** Short description (`dc:description`). */
|
|
82
|
+
description?: string;
|
|
83
|
+
/** Space-separated keywords (`cp:keywords`). */
|
|
84
|
+
keywords?: string;
|
|
85
|
+
/** Last-modified-by user (`cp:lastModifiedBy`). */
|
|
86
|
+
lastModifiedBy?: string;
|
|
87
|
+
/** Company name from `app.xml` `<Company>`. */
|
|
88
|
+
company?: string;
|
|
89
|
+
/** Manager name from `app.xml` `<Manager>`. */
|
|
90
|
+
manager?: string;
|
|
91
|
+
/** Document creation timestamp (`dcterms:created`). */
|
|
92
|
+
created?: Date;
|
|
93
|
+
/** Last-modified timestamp (`dcterms:modified`). */
|
|
94
|
+
modified?: Date;
|
|
95
|
+
}
|
|
75
96
|
export type PageOrientation = 'portrait' | 'landscape';
|
|
76
97
|
/** Common paper sizes in inches (width × height in portrait orientation). */
|
|
77
98
|
export declare const PageSizes: {
|
|
@@ -151,4 +172,24 @@ export interface NewShapeProps {
|
|
|
151
172
|
masterId?: string;
|
|
152
173
|
imgRelId?: string;
|
|
153
174
|
lineColor?: string;
|
|
175
|
+
/** Italic text. */
|
|
176
|
+
italic?: boolean;
|
|
177
|
+
/** Underline text. */
|
|
178
|
+
underline?: boolean;
|
|
179
|
+
/** Strikethrough text. */
|
|
180
|
+
strikethrough?: boolean;
|
|
181
|
+
/** Space before each paragraph in **points**. */
|
|
182
|
+
spaceBefore?: number;
|
|
183
|
+
/** Space after each paragraph in **points**. */
|
|
184
|
+
spaceAfter?: number;
|
|
185
|
+
/** Line-height multiplier (1.0 = single, 1.5 = 1.5×, 2.0 = double). */
|
|
186
|
+
lineSpacing?: number;
|
|
187
|
+
/** Top text margin in inches. */
|
|
188
|
+
textMarginTop?: number;
|
|
189
|
+
/** Bottom text margin in inches. */
|
|
190
|
+
textMarginBottom?: number;
|
|
191
|
+
/** Left text margin in inches. */
|
|
192
|
+
textMarginLeft?: number;
|
|
193
|
+
/** Right text margin in inches. */
|
|
194
|
+
textMarginRight?: number;
|
|
154
195
|
}
|
|
@@ -32,13 +32,50 @@ export declare function horzAlignValue(align: HorzAlign): string;
|
|
|
32
32
|
export declare function vertAlignValue(align: VertAlign): string;
|
|
33
33
|
export declare function createCharacterSection(props: {
|
|
34
34
|
bold?: boolean;
|
|
35
|
+
/** Italic text (Style bit 2). */
|
|
36
|
+
italic?: boolean;
|
|
37
|
+
/** Underline text (Style bit 4). */
|
|
38
|
+
underline?: boolean;
|
|
39
|
+
/** Strikethrough text (Style bit 8). */
|
|
40
|
+
strikethrough?: boolean;
|
|
35
41
|
color?: string;
|
|
36
42
|
/** Font size in points (e.g. 12 for 12pt). Stored internally as inches (pt / 72). */
|
|
37
43
|
fontSize?: number;
|
|
38
44
|
/** Font family name (e.g. "Arial"). Uses FONT() formula for portability. */
|
|
39
45
|
fontFamily?: string;
|
|
40
46
|
}): VisioSection;
|
|
41
|
-
export
|
|
47
|
+
export interface ParagraphProps {
|
|
48
|
+
/** Horizontal text alignment within the paragraph. */
|
|
49
|
+
horzAlign?: HorzAlign;
|
|
50
|
+
/**
|
|
51
|
+
* Space before each paragraph in **points**.
|
|
52
|
+
* Converted to inches internally (pt / 72).
|
|
53
|
+
*/
|
|
54
|
+
spaceBefore?: number;
|
|
55
|
+
/**
|
|
56
|
+
* Space after each paragraph in **points**.
|
|
57
|
+
* Converted to inches internally (pt / 72).
|
|
58
|
+
*/
|
|
59
|
+
spaceAfter?: number;
|
|
60
|
+
/**
|
|
61
|
+
* Line-height multiplier (1.0 = single, 1.5 = 1.5×, 2.0 = double).
|
|
62
|
+
* Stored as a negative value in Visio's `SpLine` cell (negative means
|
|
63
|
+
* proportional; positive means absolute in inches).
|
|
64
|
+
*/
|
|
65
|
+
lineSpacing?: number;
|
|
66
|
+
}
|
|
67
|
+
export declare function createParagraphSection(props: ParagraphProps): VisioSection;
|
|
68
|
+
export interface TextBlockProps {
|
|
69
|
+
/** Top text margin in inches. */
|
|
70
|
+
topMargin?: number;
|
|
71
|
+
/** Bottom text margin in inches. */
|
|
72
|
+
bottomMargin?: number;
|
|
73
|
+
/** Left text margin in inches. */
|
|
74
|
+
leftMargin?: number;
|
|
75
|
+
/** Right text margin in inches. */
|
|
76
|
+
rightMargin?: number;
|
|
77
|
+
}
|
|
78
|
+
export declare function createTextBlockSection(props: TextBlockProps): VisioSection;
|
|
42
79
|
export declare function createLineSection(props: {
|
|
43
80
|
color?: string;
|
|
44
81
|
pattern?: string;
|
|
@@ -6,6 +6,7 @@ exports.horzAlignValue = horzAlignValue;
|
|
|
6
6
|
exports.vertAlignValue = vertAlignValue;
|
|
7
7
|
exports.createCharacterSection = createCharacterSection;
|
|
8
8
|
exports.createParagraphSection = createParagraphSection;
|
|
9
|
+
exports.createTextBlockSection = createTextBlockSection;
|
|
9
10
|
exports.createLineSection = createLineSection;
|
|
10
11
|
const hexToRgb = (hex) => {
|
|
11
12
|
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
|
|
@@ -57,9 +58,14 @@ function vertAlignValue(align) {
|
|
|
57
58
|
}
|
|
58
59
|
function createCharacterSection(props) {
|
|
59
60
|
let styleVal = 0;
|
|
60
|
-
if (props.bold)
|
|
61
|
-
styleVal
|
|
62
|
-
|
|
61
|
+
if (props.bold)
|
|
62
|
+
styleVal |= 1;
|
|
63
|
+
if (props.italic)
|
|
64
|
+
styleVal |= 2;
|
|
65
|
+
if (props.underline)
|
|
66
|
+
styleVal |= 4;
|
|
67
|
+
if (props.strikethrough)
|
|
68
|
+
styleVal |= 8;
|
|
63
69
|
const colorVal = props.color || '#000000';
|
|
64
70
|
const cells = [
|
|
65
71
|
{ '@_N': 'Color', '@_V': colorVal, '@_F': hexToRgb(colorVal) },
|
|
@@ -89,20 +95,47 @@ function createCharacterSection(props) {
|
|
|
89
95
|
]
|
|
90
96
|
};
|
|
91
97
|
}
|
|
92
|
-
function createParagraphSection(
|
|
98
|
+
function createParagraphSection(props) {
|
|
99
|
+
const cells = [];
|
|
100
|
+
if (props.horzAlign !== undefined) {
|
|
101
|
+
cells.push({ '@_N': 'HorzAlign', '@_V': HORZ_ALIGN_VALUES[props.horzAlign] });
|
|
102
|
+
}
|
|
103
|
+
if (props.spaceBefore !== undefined) {
|
|
104
|
+
cells.push({ '@_N': 'SpBefore', '@_V': (props.spaceBefore / 72).toString(), '@_U': 'PT' });
|
|
105
|
+
}
|
|
106
|
+
if (props.spaceAfter !== undefined) {
|
|
107
|
+
cells.push({ '@_N': 'SpAfter', '@_V': (props.spaceAfter / 72).toString(), '@_U': 'PT' });
|
|
108
|
+
}
|
|
109
|
+
if (props.lineSpacing !== undefined) {
|
|
110
|
+
// Negative value = proportional multiplier; positive = absolute (inches)
|
|
111
|
+
cells.push({ '@_N': 'SpLine', '@_V': (-props.lineSpacing).toString() });
|
|
112
|
+
}
|
|
93
113
|
return {
|
|
94
114
|
'@_N': 'Paragraph',
|
|
95
115
|
Row: [
|
|
96
116
|
{
|
|
97
117
|
'@_T': 'Paragraph',
|
|
98
118
|
'@_IX': '0',
|
|
99
|
-
Cell:
|
|
100
|
-
{ '@_N': 'HorzAlign', '@_V': HORZ_ALIGN_VALUES[horzAlign] },
|
|
101
|
-
]
|
|
119
|
+
Cell: cells,
|
|
102
120
|
}
|
|
103
121
|
]
|
|
104
122
|
};
|
|
105
123
|
}
|
|
124
|
+
function createTextBlockSection(props) {
|
|
125
|
+
const cells = [];
|
|
126
|
+
if (props.topMargin !== undefined)
|
|
127
|
+
cells.push({ '@_N': 'TopMargin', '@_V': props.topMargin.toString(), '@_U': 'IN' });
|
|
128
|
+
if (props.bottomMargin !== undefined)
|
|
129
|
+
cells.push({ '@_N': 'BottomMargin', '@_V': props.bottomMargin.toString(), '@_U': 'IN' });
|
|
130
|
+
if (props.leftMargin !== undefined)
|
|
131
|
+
cells.push({ '@_N': 'LeftMargin', '@_V': props.leftMargin.toString(), '@_U': 'IN' });
|
|
132
|
+
if (props.rightMargin !== undefined)
|
|
133
|
+
cells.push({ '@_N': 'RightMargin', '@_V': props.rightMargin.toString(), '@_U': 'IN' });
|
|
134
|
+
return {
|
|
135
|
+
'@_N': 'TextBlock',
|
|
136
|
+
Cell: cells,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
106
139
|
function createLineSection(props) {
|
|
107
140
|
const cells = [
|
|
108
141
|
{ '@_N': 'LineColor', '@_V': props.color || '#000000' },
|