ts-visio 1.4.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 +38 -1
- package/dist/ShapeModifier.d.ts +20 -0
- package/dist/ShapeModifier.js +37 -4
- package/dist/shapes/ShapeBuilder.js +34 -3
- package/dist/types/VisioTypes.d.ts +20 -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,7 +18,7 @@ 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.
|
|
@@ -521,6 +521,43 @@ Fields map to OPC parts: `title`, `author`, `description`, `keywords`, `lastModi
|
|
|
521
521
|
|
|
522
522
|
---
|
|
523
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
|
+
|
|
524
561
|
## Examples
|
|
525
562
|
|
|
526
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) {
|
|
@@ -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) });
|
|
@@ -172,4 +172,24 @@ export interface NewShapeProps {
|
|
|
172
172
|
masterId?: string;
|
|
173
173
|
imgRelId?: string;
|
|
174
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;
|
|
175
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' },
|