@nguyenphp/antigravity-marketing 1.0.18 → 1.0.19

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.
Files changed (127) hide show
  1. package/README.md +186 -78
  2. package/package.json +4 -3
  3. package/templates/.agent/skills/marketing-report-expert/SKILL.md +70 -0
  4. package/templates/.agent/skills/minimax-docx/LICENSE +21 -0
  5. package/templates/.agent/skills/minimax-docx/SKILL.md +274 -0
  6. package/templates/.agent/skills/minimax-docx/assets/styles/academic_styles.xml +250 -0
  7. package/templates/.agent/skills/minimax-docx/assets/styles/corporate_styles.xml +284 -0
  8. package/templates/.agent/skills/minimax-docx/assets/styles/default_styles.xml +449 -0
  9. package/templates/.agent/skills/minimax-docx/assets/xsd/aesthetic-rules.xsd +470 -0
  10. package/templates/.agent/skills/minimax-docx/assets/xsd/business-rules.xsd +130 -0
  11. package/templates/.agent/skills/minimax-docx/assets/xsd/common-types.xsd +159 -0
  12. package/templates/.agent/skills/minimax-docx/assets/xsd/wml-subset.xsd +589 -0
  13. package/templates/.agent/skills/minimax-docx/references/cjk_typography.md +357 -0
  14. package/templates/.agent/skills/minimax-docx/references/cjk_university_template_guide.md +184 -0
  15. package/templates/.agent/skills/minimax-docx/references/comments_guide.md +191 -0
  16. package/templates/.agent/skills/minimax-docx/references/design_good_bad_examples.md +829 -0
  17. package/templates/.agent/skills/minimax-docx/references/design_principles.md +819 -0
  18. package/templates/.agent/skills/minimax-docx/references/openxml_element_order.md +308 -0
  19. package/templates/.agent/skills/minimax-docx/references/openxml_encyclopedia_part1.md +4061 -0
  20. package/templates/.agent/skills/minimax-docx/references/openxml_encyclopedia_part2.md +2820 -0
  21. package/templates/.agent/skills/minimax-docx/references/openxml_encyclopedia_part3.md +3381 -0
  22. package/templates/.agent/skills/minimax-docx/references/openxml_namespaces.md +82 -0
  23. package/templates/.agent/skills/minimax-docx/references/openxml_units.md +72 -0
  24. package/templates/.agent/skills/minimax-docx/references/scenario_a_create.md +284 -0
  25. package/templates/.agent/skills/minimax-docx/references/scenario_b_edit_content.md +295 -0
  26. package/templates/.agent/skills/minimax-docx/references/scenario_c_apply_template.md +456 -0
  27. package/templates/.agent/skills/minimax-docx/references/track_changes_guide.md +200 -0
  28. package/templates/.agent/skills/minimax-docx/references/troubleshooting.md +506 -0
  29. package/templates/.agent/skills/minimax-docx/references/typography_guide.md +294 -0
  30. package/templates/.agent/skills/minimax-docx/references/xsd_validation_guide.md +158 -0
  31. package/templates/.agent/skills/minimax-docx/scripts/doc_to_docx.sh +40 -0
  32. package/templates/.agent/skills/minimax-docx/scripts/docx_preview.sh +37 -0
  33. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Cli/MiniMaxAIDocx.Cli.csproj +19 -0
  34. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Cli/Program.cs +18 -0
  35. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/AnalyzeCommand.cs +147 -0
  36. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/ApplyTemplateCommand.cs +322 -0
  37. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/CreateCommand.cs +324 -0
  38. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/DiffCommand.cs +155 -0
  39. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/EditContentCommand.cs +487 -0
  40. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/FixOrderCommand.cs +108 -0
  41. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/MergeRunsCommand.cs +122 -0
  42. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/ValidateCommand.cs +107 -0
  43. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/MiniMaxAIDocx.Core.csproj +15 -0
  44. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/CommentSynchronizer.cs +169 -0
  45. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/ElementOrder.cs +80 -0
  46. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/NamespaceConstants.cs +42 -0
  47. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/RunMerger.cs +81 -0
  48. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/StyleAnalyzer.cs +81 -0
  49. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/TrackChangesHelper.cs +99 -0
  50. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/UnitConverter.cs +23 -0
  51. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples.cs +1832 -0
  52. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples_Batch1.cs +910 -0
  53. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples_Batch2.cs +999 -0
  54. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples_Batch3.cs +1048 -0
  55. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples_Batch4.cs +1038 -0
  56. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/CharacterFormattingSamples.cs +1020 -0
  57. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/DocumentCreationSamples.cs +1121 -0
  58. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/FieldAndTocSamples.cs +624 -0
  59. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/FootnoteAndCommentSamples.cs +675 -0
  60. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/HeaderFooterSamples.cs +838 -0
  61. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/ImageSamples.cs +917 -0
  62. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/ListAndNumberingSamples.cs +826 -0
  63. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/ParagraphFormattingSamples.cs +1199 -0
  64. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/StyleSystemSamples.cs +1487 -0
  65. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/TableSamples.cs +1163 -0
  66. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/TrackChangesSamples.cs +595 -0
  67. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Typography/CjkHelper.cs +39 -0
  68. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Typography/FontDefaults.cs +24 -0
  69. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Typography/PageSizes.cs +20 -0
  70. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Validation/BusinessRuleValidator.cs +224 -0
  71. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Validation/GateCheckValidator.cs +148 -0
  72. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Validation/ValidationResult.cs +23 -0
  73. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Validation/XsdValidator.cs +69 -0
  74. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.slnx +4 -0
  75. package/templates/.agent/skills/minimax-docx/scripts/env_check.sh +196 -0
  76. package/templates/.agent/skills/minimax-docx/scripts/setup.ps1 +274 -0
  77. package/templates/.agent/skills/minimax-docx/scripts/setup.sh +504 -0
  78. package/templates/.agent/skills/minimax-multimodal-toolkit/SKILL.md +359 -0
  79. package/templates/.agent/skills/minimax-pdf/README.md +222 -0
  80. package/templates/.agent/skills/minimax-pdf/SKILL.md +201 -0
  81. package/templates/.agent/skills/minimax-pdf/design/design.md +381 -0
  82. package/templates/.agent/skills/minimax-pdf/scripts/cover.py +1579 -0
  83. package/templates/.agent/skills/minimax-pdf/scripts/fill_inspect.py +200 -0
  84. package/templates/.agent/skills/minimax-pdf/scripts/fill_write.py +242 -0
  85. package/templates/.agent/skills/minimax-pdf/scripts/make.sh +491 -0
  86. package/templates/.agent/skills/minimax-pdf/scripts/merge.py +112 -0
  87. package/templates/.agent/skills/minimax-pdf/scripts/palette.py +559 -0
  88. package/templates/.agent/skills/minimax-pdf/scripts/reformat_parse.py +374 -0
  89. package/templates/.agent/skills/minimax-pdf/scripts/render_body.py +1055 -0
  90. package/templates/.agent/skills/minimax-pdf/scripts/render_cover.cjs +111 -0
  91. package/templates/.agent/skills/minimax-xlsx/SKILL.md +138 -0
  92. package/templates/.agent/skills/minimax-xlsx/references/create.md +691 -0
  93. package/templates/.agent/skills/minimax-xlsx/references/edit.md +684 -0
  94. package/templates/.agent/skills/minimax-xlsx/references/fix.md +37 -0
  95. package/templates/.agent/skills/minimax-xlsx/references/format.md +768 -0
  96. package/templates/.agent/skills/minimax-xlsx/references/ooxml-cheatsheet.md +231 -0
  97. package/templates/.agent/skills/minimax-xlsx/references/read-analyze.md +97 -0
  98. package/templates/.agent/skills/minimax-xlsx/references/validate.md +772 -0
  99. package/templates/.agent/skills/minimax-xlsx/scripts/formula_check.py +422 -0
  100. package/templates/.agent/skills/minimax-xlsx/scripts/libreoffice_recalc.py +248 -0
  101. package/templates/.agent/skills/minimax-xlsx/scripts/shared_strings_builder.py +163 -0
  102. package/templates/.agent/skills/minimax-xlsx/scripts/style_audit.py +575 -0
  103. package/templates/.agent/skills/minimax-xlsx/scripts/xlsx_add_column.py +395 -0
  104. package/templates/.agent/skills/minimax-xlsx/scripts/xlsx_insert_row.py +274 -0
  105. package/templates/.agent/skills/minimax-xlsx/scripts/xlsx_pack.py +87 -0
  106. package/templates/.agent/skills/minimax-xlsx/scripts/xlsx_reader.py +362 -0
  107. package/templates/.agent/skills/minimax-xlsx/scripts/xlsx_shift_rows.py +396 -0
  108. package/templates/.agent/skills/minimax-xlsx/scripts/xlsx_unpack.py +130 -0
  109. package/templates/.agent/skills/minimax-xlsx/templates/minimal_xlsx/[Content_Types].xml +9 -0
  110. package/templates/.agent/skills/minimax-xlsx/templates/minimal_xlsx/_rels/.rels +6 -0
  111. package/templates/.agent/skills/minimax-xlsx/templates/minimal_xlsx/xl/_rels/workbook.xml.rels +19 -0
  112. package/templates/.agent/skills/minimax-xlsx/templates/minimal_xlsx/xl/sharedStrings.xml +33 -0
  113. package/templates/.agent/skills/minimax-xlsx/templates/minimal_xlsx/xl/styles.xml +160 -0
  114. package/templates/.agent/skills/minimax-xlsx/templates/minimal_xlsx/xl/workbook.xml +30 -0
  115. package/templates/.agent/skills/minimax-xlsx/templates/minimal_xlsx/xl/worksheets/sheet1.xml +70 -0
  116. package/templates/.agent/skills/pptx-generator/SKILL.md +249 -0
  117. package/templates/.agent/skills/pptx-generator/references/design-system.md +392 -0
  118. package/templates/.agent/skills/pptx-generator/references/editing.md +162 -0
  119. package/templates/.agent/skills/pptx-generator/references/pitfalls.md +112 -0
  120. package/templates/.agent/skills/pptx-generator/references/pptxgenjs.md +420 -0
  121. package/templates/.agent/skills/pptx-generator/references/slide-types.md +413 -0
  122. package/templates/.agent/skills/tutorial-video-expert/SKILL.md +88 -0
  123. package/templates/.agent/skills/ui-ux-pro-max/SKILL.md +170 -585
  124. package/templates/.agent/skills/vision-analysis/SKILL.md +174 -0
  125. package/templates/.agent/workflows/analyze.md +3 -0
  126. package/templates/.agent/workflows/brand-report.md +44 -0
  127. package/templates/.agent/workflows/report.md +49 -0
@@ -0,0 +1,1163 @@
1
+ using DocumentFormat.OpenXml;
2
+ using DocumentFormat.OpenXml.Wordprocessing;
3
+
4
+ namespace MiniMaxAIDocx.Core.Samples;
5
+
6
+ /// <summary>
7
+ /// Comprehensive reference for OpenXML table creation and formatting.
8
+ ///
9
+ /// KEY GOTCHA: Every TableCell MUST contain at least one Paragraph, even if empty.
10
+ /// Omitting it produces a corrupt document that Word will attempt to repair.
11
+ ///
12
+ /// Border size units: eighth-points (1/8 pt). Size="12" = 1.5pt line.
13
+ /// Width units: DXA (twentieths of a point). 1440 DXA = 1 inch.
14
+ /// Pct width: fiftieths of a percent. 5000 = 100%.
15
+ ///
16
+ /// XML structure:
17
+ /// <w:tbl>
18
+ /// <w:tblPr> — table-level properties (width, alignment, borders, layout)
19
+ /// <w:tblGrid> — column definitions
20
+ /// <w:tr> — table row
21
+ /// <w:trPr> — row properties (height, header repeat)
22
+ /// <w:tc> — table cell
23
+ /// <w:tcPr> — cell properties (width, merge, shading, borders)
24
+ /// <w:p> — paragraph (REQUIRED, at least one)
25
+ /// </summary>
26
+ public static class TableSamples
27
+ {
28
+ // ──────────────────────────────────────────────────────────────
29
+ // 1. CreateSimpleTable — basic table with single-line borders
30
+ // ──────────────────────────────────────────────────────────────
31
+ /// <summary>
32
+ /// Creates a simple table with uniform single borders.
33
+ ///
34
+ /// XML produced:
35
+ /// <w:tbl>
36
+ /// <w:tblPr>
37
+ /// <w:tblBorders>
38
+ /// <w:top w:val="single" w:sz="4" w:space="0" w:color="000000"/>
39
+ /// <w:left w:val="single" .../> <w:bottom .../> <w:right .../>
40
+ /// <w:insideH .../> <w:insideV .../>
41
+ /// </w:tblBorders>
42
+ /// <w:tblW w:w="5000" w:type="pct"/>
43
+ /// </w:tblPr>
44
+ /// <w:tblGrid> <w:gridCol w:w="..."/> ... </w:tblGrid>
45
+ /// <w:tr> <w:tc> <w:p><w:r><w:t>Header1</w:t></w:r></w:p> </w:tc> ... </w:tr>
46
+ /// ...
47
+ /// </w:tbl>
48
+ /// </summary>
49
+ /// <param name="body">The document body to append the table to.</param>
50
+ /// <param name="headers">Column header strings.</param>
51
+ /// <param name="data">Rows of data; each inner array matches headers length.</param>
52
+ public static Table CreateSimpleTable(Body body, string[] headers, string[][] data)
53
+ {
54
+ var table = new Table();
55
+
56
+ // -- Table Properties --
57
+ var tblPr = new TableProperties();
58
+
59
+ // Full-width table: Pct 5000 = 100%
60
+ tblPr.Append(new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct });
61
+
62
+ // Single borders all around + inside gridlines
63
+ // Border Size is in eighth-points: 4 = 0.5pt (thin), 12 = 1.5pt, 24 = 3pt
64
+ var borders = new TableBorders(
65
+ new TopBorder { Val = BorderValues.Single, Size = 4, Space = 0, Color = "000000" },
66
+ new LeftBorder { Val = BorderValues.Single, Size = 4, Space = 0, Color = "000000" },
67
+ new BottomBorder { Val = BorderValues.Single, Size = 4, Space = 0, Color = "000000" },
68
+ new RightBorder { Val = BorderValues.Single, Size = 4, Space = 0, Color = "000000" },
69
+ new InsideHorizontalBorder { Val = BorderValues.Single, Size = 4, Space = 0, Color = "000000" },
70
+ new InsideVerticalBorder { Val = BorderValues.Single, Size = 4, Space = 0, Color = "000000" }
71
+ );
72
+ tblPr.Append(borders);
73
+ table.Append(tblPr);
74
+
75
+ // -- Table Grid: equal column widths --
76
+ // Grid columns define the default width in DXA.
77
+ // Total page width ~9360 DXA for letter with 1" margins (8.5" - 2" = 6.5" = 9360 DXA)
78
+ var grid = new TableGrid();
79
+ int colWidth = 9360 / headers.Length;
80
+ foreach (var _ in headers)
81
+ {
82
+ grid.Append(new GridColumn { Width = colWidth.ToString() });
83
+ }
84
+ table.Append(grid);
85
+
86
+ // -- Header Row --
87
+ var headerRow = new TableRow();
88
+ foreach (var h in headers)
89
+ {
90
+ var cell = new TableCell();
91
+ // GOTCHA: every cell MUST have at least one Paragraph
92
+ cell.Append(new Paragraph(
93
+ new Run(
94
+ new RunProperties(new Bold()),
95
+ new Text(h) { Space = SpaceProcessingModeValues.Preserve })));
96
+ headerRow.Append(cell);
97
+ }
98
+ table.Append(headerRow);
99
+
100
+ // -- Data Rows --
101
+ foreach (var rowData in data)
102
+ {
103
+ var row = new TableRow();
104
+ foreach (var cellText in rowData)
105
+ {
106
+ var cell = new TableCell();
107
+ cell.Append(new Paragraph(
108
+ new Run(new Text(cellText) { Space = SpaceProcessingModeValues.Preserve })));
109
+ row.Append(cell);
110
+ }
111
+ table.Append(row);
112
+ }
113
+
114
+ body.Append(table);
115
+ // Add an empty paragraph after the table (Word best practice)
116
+ body.Append(new Paragraph());
117
+ return table;
118
+ }
119
+
120
+ // ──────────────────────────────────────────────────────────────
121
+ // 2. CreateStyledTable — header shading, zebra striping, totals
122
+ // ──────────────────────────────────────────────────────────────
123
+ /// <summary>
124
+ /// Creates a professionally styled table with:
125
+ /// - Dark header row (navy background, white bold text)
126
+ /// - Alternating row shading (zebra striping)
127
+ /// - Bold totals row at the bottom
128
+ ///
129
+ /// XML for shaded cell:
130
+ /// <w:tc>
131
+ /// <w:tcPr>
132
+ /// <w:shd w:val="clear" w:color="auto" w:fill="1F3864"/>
133
+ /// </w:tcPr>
134
+ /// <w:p>
135
+ /// <w:pPr><w:jc w:val="center"/></w:pPr>
136
+ /// <w:r>
137
+ /// <w:rPr><w:b/><w:color w:val="FFFFFF"/></w:rPr>
138
+ /// <w:t>Header</w:t>
139
+ /// </w:r>
140
+ /// </w:p>
141
+ /// </w:tc>
142
+ /// </summary>
143
+ public static Table CreateStyledTable(Body body)
144
+ {
145
+ var table = new Table();
146
+
147
+ // Table properties: full width, single borders
148
+ var tblPr = new TableProperties(
149
+ new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct },
150
+ new TableBorders(
151
+ new TopBorder { Val = BorderValues.Single, Size = 4, Space = 0, Color = "1F3864" },
152
+ new LeftBorder { Val = BorderValues.Single, Size = 4, Space = 0, Color = "1F3864" },
153
+ new BottomBorder { Val = BorderValues.Single, Size = 4, Space = 0, Color = "1F3864" },
154
+ new RightBorder { Val = BorderValues.Single, Size = 4, Space = 0, Color = "1F3864" },
155
+ new InsideHorizontalBorder { Val = BorderValues.Single, Size = 4, Space = 0, Color = "1F3864" },
156
+ new InsideVerticalBorder { Val = BorderValues.Single, Size = 4, Space = 0, Color = "1F3864" }
157
+ ));
158
+ table.Append(tblPr);
159
+
160
+ // Grid: 3 columns
161
+ var grid = new TableGrid(
162
+ new GridColumn { Width = "3120" },
163
+ new GridColumn { Width = "3120" },
164
+ new GridColumn { Width = "3120" });
165
+ table.Append(grid);
166
+
167
+ string[] headers = ["Item", "Quantity", "Price"];
168
+ string[][] data =
169
+ [
170
+ ["Widget A", "10", "$5.00"],
171
+ ["Widget B", "25", "$3.50"],
172
+ ["Widget C", "15", "$7.25"],
173
+ ];
174
+
175
+ // -- Header row: dark navy background, white bold text --
176
+ var headerRow = new TableRow();
177
+ foreach (var h in headers)
178
+ {
179
+ var cell = new TableCell(
180
+ new TableCellProperties(
181
+ new Shading
182
+ {
183
+ Val = ShadingPatternValues.Clear,
184
+ Color = "auto",
185
+ Fill = "1F3864" // Dark navy
186
+ }),
187
+ new Paragraph(
188
+ new ParagraphProperties(
189
+ new Justification { Val = JustificationValues.Center }),
190
+ new Run(
191
+ new RunProperties(
192
+ new Bold(),
193
+ new Color { Val = "FFFFFF" }), // White text
194
+ new Text(h))));
195
+ headerRow.Append(cell);
196
+ }
197
+ table.Append(headerRow);
198
+
199
+ // -- Data rows with zebra striping --
200
+ for (int i = 0; i < data.Length; i++)
201
+ {
202
+ var row = new TableRow();
203
+ // Alternate rows get light gray background
204
+ string? fillColor = (i % 2 == 1) ? "D9E2F3" : null;
205
+
206
+ foreach (var cellText in data[i])
207
+ {
208
+ var tcPr = new TableCellProperties();
209
+ if (fillColor != null)
210
+ {
211
+ tcPr.Append(new Shading
212
+ {
213
+ Val = ShadingPatternValues.Clear,
214
+ Color = "auto",
215
+ Fill = fillColor
216
+ });
217
+ }
218
+ var cell = new TableCell(
219
+ tcPr,
220
+ new Paragraph(
221
+ new Run(new Text(cellText) { Space = SpaceProcessingModeValues.Preserve })));
222
+ row.Append(cell);
223
+ }
224
+ table.Append(row);
225
+ }
226
+
227
+ // -- Totals row: bold text, top border emphasis --
228
+ var totalsRow = new TableRow();
229
+ string[] totals = ["Total", "50", "$257.50"];
230
+ foreach (var t in totals)
231
+ {
232
+ var cell = new TableCell(
233
+ new TableCellProperties(
234
+ new Shading
235
+ {
236
+ Val = ShadingPatternValues.Clear,
237
+ Color = "auto",
238
+ Fill = "1F3864"
239
+ }),
240
+ new Paragraph(
241
+ new Run(
242
+ new RunProperties(
243
+ new Bold(),
244
+ new Color { Val = "FFFFFF" }),
245
+ new Text(t) { Space = SpaceProcessingModeValues.Preserve })));
246
+ totalsRow.Append(cell);
247
+ }
248
+ table.Append(totalsRow);
249
+
250
+ body.Append(table);
251
+ body.Append(new Paragraph());
252
+ return table;
253
+ }
254
+
255
+ // ──────────────────────────────────────────────────────────────
256
+ // 3. CreateThreeLineTable — academic 三线表
257
+ // ──────────────────────────────────────────────────────────────
258
+ /// <summary>
259
+ /// Creates an academic three-line table (三线表):
260
+ /// - Thick top border (1.5pt = Size 12)
261
+ /// - Thin border below header row (0.75pt = Size 6)
262
+ /// - Thick bottom border (1.5pt = Size 12)
263
+ /// - NO vertical borders, NO inside vertical borders
264
+ /// - NO left/right borders
265
+ ///
266
+ /// This is the standard table style for Chinese academic papers (GB/T 7713).
267
+ ///
268
+ /// XML produced:
269
+ /// <w:tbl>
270
+ /// <w:tblPr>
271
+ /// <w:tblBorders>
272
+ /// <w:top w:val="single" w:sz="12" w:space="0" w:color="000000"/>
273
+ /// <w:bottom w:val="single" w:sz="12" w:space="0" w:color="000000"/>
274
+ /// <!-- No left, right, insideV borders -->
275
+ /// <w:insideH w:val="none" w:sz="0" w:space="0" w:color="auto"/>
276
+ /// <w:insideV w:val="none" w:sz="0" w:space="0" w:color="auto"/>
277
+ /// </w:tblBorders>
278
+ /// </w:tblPr>
279
+ /// ...
280
+ /// <!-- Header row uses per-cell bottom border for the thin line -->
281
+ /// </w:tbl>
282
+ /// </summary>
283
+ public static Table CreateThreeLineTable(Body body)
284
+ {
285
+ var table = new Table();
286
+
287
+ // Table borders: only top and bottom (thick), no sides, no inside
288
+ var tblPr = new TableProperties(
289
+ new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct },
290
+ new TableBorders(
291
+ new TopBorder { Val = BorderValues.Single, Size = 12, Space = 0, Color = "000000" },
292
+ new BottomBorder { Val = BorderValues.Single, Size = 12, Space = 0, Color = "000000" },
293
+ // Explicitly set left/right/insideH/insideV to none
294
+ new LeftBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
295
+ new RightBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
296
+ new InsideHorizontalBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
297
+ new InsideVerticalBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" }
298
+ ));
299
+ table.Append(tblPr);
300
+
301
+ var grid = new TableGrid(
302
+ new GridColumn { Width = "3120" },
303
+ new GridColumn { Width = "3120" },
304
+ new GridColumn { Width = "3120" });
305
+ table.Append(grid);
306
+
307
+ string[] headers = ["Variable", "Mean", "SD"];
308
+
309
+ // -- Header row: centered, bold, with thin bottom border on each cell --
310
+ var headerRow = new TableRow();
311
+ foreach (var h in headers)
312
+ {
313
+ // Per-cell bottom border creates the thin "second line" of the three-line table
314
+ var tcPr = new TableCellProperties(
315
+ new TableCellBorders(
316
+ new BottomBorder { Val = BorderValues.Single, Size = 6, Space = 0, Color = "000000" }
317
+ ));
318
+
319
+ var cell = new TableCell(
320
+ tcPr,
321
+ new Paragraph(
322
+ new ParagraphProperties(
323
+ new Justification { Val = JustificationValues.Center }),
324
+ new Run(
325
+ new RunProperties(new Bold()),
326
+ new Text(h))));
327
+ headerRow.Append(cell);
328
+ }
329
+ table.Append(headerRow);
330
+
331
+ // -- Data rows: centered text, no borders --
332
+ string[][] data =
333
+ [
334
+ ["Age", "25.3", "4.2"],
335
+ ["Height", "170.5", "8.1"],
336
+ ["Weight", "65.2", "10.3"],
337
+ ];
338
+ foreach (var rowData in data)
339
+ {
340
+ var row = new TableRow();
341
+ foreach (var cellText in rowData)
342
+ {
343
+ var cell = new TableCell(
344
+ new Paragraph(
345
+ new ParagraphProperties(
346
+ new Justification { Val = JustificationValues.Center }),
347
+ new Run(new Text(cellText))));
348
+ row.Append(cell);
349
+ }
350
+ table.Append(row);
351
+ }
352
+
353
+ body.Append(table);
354
+ body.Append(new Paragraph());
355
+ return table;
356
+ }
357
+
358
+ // ──────────────────────────────────────────────────────────────
359
+ // 4. CreateBorderedTable — multiple border styles
360
+ // ──────────────────────────────────────────────────────────────
361
+ /// <summary>
362
+ /// Creates a table demonstrating different border styles.
363
+ ///
364
+ /// Border Val options:
365
+ /// BorderValues.Single — normal single line
366
+ /// BorderValues.Double — double line
367
+ /// BorderValues.Thick — thick single line
368
+ /// BorderValues.Dashed — dashed line
369
+ /// BorderValues.DashSmallGap — dashed with small gaps
370
+ /// BorderValues.DotDash — dot-dash pattern
371
+ /// BorderValues.Dotted — dotted line
372
+ /// BorderValues.Wave — wavy line
373
+ /// BorderValues.None — no border
374
+ ///
375
+ /// Size is in eighth-points: 4 = 0.5pt, 8 = 1pt, 12 = 1.5pt, 24 = 3pt
376
+ /// </summary>
377
+ public static Table CreateBorderedTable(Body body)
378
+ {
379
+ var table = new Table();
380
+
381
+ // Use different border styles on each side to demonstrate the options
382
+ var tblPr = new TableProperties(
383
+ new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct },
384
+ new TableBorders(
385
+ new TopBorder { Val = BorderValues.Double, Size = 4, Space = 0, Color = "000000" },
386
+ new BottomBorder { Val = BorderValues.Double, Size = 4, Space = 0, Color = "000000" },
387
+ new LeftBorder { Val = BorderValues.Thick, Size = 12, Space = 0, Color = "333333" },
388
+ new RightBorder { Val = BorderValues.Thick, Size = 12, Space = 0, Color = "333333" },
389
+ new InsideHorizontalBorder { Val = BorderValues.Dashed, Size = 4, Space = 0, Color = "999999" },
390
+ new InsideVerticalBorder { Val = BorderValues.Dotted, Size = 4, Space = 0, Color = "999999" }
391
+ ));
392
+ table.Append(tblPr);
393
+
394
+ var grid = new TableGrid(
395
+ new GridColumn { Width = "4680" },
396
+ new GridColumn { Width = "4680" });
397
+ table.Append(grid);
398
+
399
+ // Sample data
400
+ string[][] rows =
401
+ [
402
+ ["Double top / Thick sides", "Dotted vertical inside"],
403
+ ["Dashed horizontal inside", "Double bottom"],
404
+ ];
405
+ foreach (var rowData in rows)
406
+ {
407
+ var row = new TableRow();
408
+ foreach (var cellText in rowData)
409
+ {
410
+ var cell = new TableCell(
411
+ new Paragraph(new Run(new Text(cellText))));
412
+ row.Append(cell);
413
+ }
414
+ table.Append(row);
415
+ }
416
+
417
+ body.Append(table);
418
+ body.Append(new Paragraph());
419
+ return table;
420
+ }
421
+
422
+ // ──────────────────────────────────────────────────────────────
423
+ // 5. SetTableWidth — Pct, DXA, Auto
424
+ // ──────────────────────────────────────────────────────────────
425
+ /// <summary>
426
+ /// Demonstrates three table width modes:
427
+ ///
428
+ /// 1. Pct (percentage): Value in fiftieths of a percent. 5000 = 100%, 2500 = 50%.
429
+ /// XML: <w:tblW w:w="5000" w:type="pct"/>
430
+ ///
431
+ /// 2. Dxa (absolute): Value in twentieths of a point. 1440 = 1 inch, 9360 = 6.5 inches.
432
+ /// XML: <w:tblW w:w="9360" w:type="dxa"/>
433
+ ///
434
+ /// 3. Auto: Word determines width from content.
435
+ /// XML: <w:tblW w:w="0" w:type="auto"/>
436
+ /// </summary>
437
+ public static void SetTableWidth(Table table)
438
+ {
439
+ var tblPr = table.GetFirstChild<TableProperties>()
440
+ ?? table.PrependChild(new TableProperties());
441
+
442
+ // --- Option A: Percentage width (100%) ---
443
+ // Pct value is in fiftieths of a percent: 5000 = 100%
444
+ tblPr.TableWidth = new TableWidth
445
+ {
446
+ Width = "5000",
447
+ Type = TableWidthUnitValues.Pct
448
+ };
449
+
450
+ // --- Option B: Absolute width (6.5 inches = 9360 DXA) ---
451
+ // tblPr.TableWidth = new TableWidth
452
+ // {
453
+ // Width = "9360", // 6.5 * 1440 = 9360 DXA
454
+ // Type = TableWidthUnitValues.Dxa
455
+ // };
456
+
457
+ // --- Option C: Auto width ---
458
+ // tblPr.TableWidth = new TableWidth
459
+ // {
460
+ // Width = "0",
461
+ // Type = TableWidthUnitValues.Auto
462
+ // };
463
+ }
464
+
465
+ // ──────────────────────────────────────────────────────────────
466
+ // 6. SetTableLayout — Fixed vs AutoFit
467
+ // ──────────────────────────────────────────────────────────────
468
+ /// <summary>
469
+ /// Controls whether the table uses fixed column widths or auto-fits to content.
470
+ ///
471
+ /// Fixed layout: columns keep their exact width from TableGrid; content wraps.
472
+ /// XML: <w:tblLayout w:type="fixed"/>
473
+ ///
474
+ /// AutoFit layout: Word adjusts column widths based on content. This is the default.
475
+ /// XML: <w:tblLayout w:type="autofit"/>
476
+ ///
477
+ /// GOTCHA: Fixed layout is required for predictable column widths; AutoFit
478
+ /// may override your GridColumn values.
479
+ /// </summary>
480
+ public static void SetTableLayout(Table table)
481
+ {
482
+ var tblPr = table.GetFirstChild<TableProperties>()
483
+ ?? table.PrependChild(new TableProperties());
484
+
485
+ // Fixed layout — columns respect GridColumn widths exactly
486
+ tblPr.TableLayout = new TableLayout
487
+ {
488
+ Type = TableLayoutValues.Fixed
489
+ };
490
+
491
+ // AutoFit layout (default) — Word adjusts widths to content
492
+ // tblPr.TableLayout = new TableLayout
493
+ // {
494
+ // Type = TableLayoutValues.Autofit
495
+ // };
496
+ }
497
+
498
+ // ──────────────────────────────────────────────────────────────
499
+ // 7. SetTableAlignment — center, right, left with indent
500
+ // ──────────────────────────────────────────────────────────────
501
+ /// <summary>
502
+ /// Controls horizontal alignment of the table on the page.
503
+ ///
504
+ /// XML: <w:jc w:val="center"/>
505
+ ///
506
+ /// For left alignment with indent:
507
+ /// XML: <w:tblInd w:w="720" w:type="dxa"/>
508
+ ///
509
+ /// GOTCHA: TableJustification (w:jc) inside tblPr is DIFFERENT from paragraph Justification.
510
+ /// </summary>
511
+ public static void SetTableAlignment(Table table)
512
+ {
513
+ var tblPr = table.GetFirstChild<TableProperties>()
514
+ ?? table.PrependChild(new TableProperties());
515
+
516
+ // --- Option A: Center the table ---
517
+ tblPr.TableJustification = new TableJustification
518
+ {
519
+ Val = TableRowAlignmentValues.Center
520
+ };
521
+
522
+ // --- Option B: Right-align ---
523
+ // tblPr.TableJustification = new TableJustification
524
+ // {
525
+ // Val = TableRowAlignmentValues.Right
526
+ // };
527
+
528
+ // --- Option C: Left with indent (0.5 inch = 720 DXA) ---
529
+ // tblPr.TableJustification = new TableJustification
530
+ // {
531
+ // Val = TableRowAlignmentValues.Left
532
+ // };
533
+ // tblPr.TableIndentation = new TableIndentation
534
+ // {
535
+ // Width = 720,
536
+ // Type = TableWidthUnitValues.Dxa
537
+ // };
538
+ }
539
+
540
+ // ──────────────────────────────────────────────────────────────
541
+ // 8. ConfigureTableGrid — column widths
542
+ // ──────────────────────────────────────────────────────────────
543
+ /// <summary>
544
+ /// Sets explicit column widths via TableGrid / GridColumn elements.
545
+ ///
546
+ /// GridColumn.Width is in DXA (twentieths of a point).
547
+ /// 1440 DXA = 1 inch. Common page width = 9360 DXA (6.5" printable on letter).
548
+ ///
549
+ /// XML:
550
+ /// <w:tblGrid>
551
+ /// <w:gridCol w:w="1440"/> <!-- 1 inch -->
552
+ /// <w:gridCol w:w="4680"/> <!-- 3.25 inches -->
553
+ /// <w:gridCol w:w="3240"/> <!-- 2.25 inches -->
554
+ /// </w:tblGrid>
555
+ ///
556
+ /// GOTCHA: The number of GridColumn elements should match the maximum number
557
+ /// of cells in any row (before merging). Merged cells still correspond to
558
+ /// multiple grid columns via GridSpan.
559
+ /// </summary>
560
+ public static void ConfigureTableGrid(Table table)
561
+ {
562
+ // Remove existing grid if present
563
+ var existingGrid = table.GetFirstChild<TableGrid>();
564
+ existingGrid?.Remove();
565
+
566
+ // 3 columns: narrow (1"), wide (3.25"), medium (2.25") = 6.5" total
567
+ var grid = new TableGrid(
568
+ new GridColumn { Width = "1440" }, // 1 inch
569
+ new GridColumn { Width = "4680" }, // 3.25 inches
570
+ new GridColumn { Width = "3240" } // 2.25 inches
571
+ );
572
+
573
+ // Grid must come after TableProperties, before any TableRow
574
+ var tblPr = table.GetFirstChild<TableProperties>();
575
+ if (tblPr != null)
576
+ tblPr.InsertAfterSelf(grid);
577
+ else
578
+ table.PrependChild(grid);
579
+ }
580
+
581
+ // ──────────────────────────────────────────────────────────────
582
+ // 9. SetCellProperties — width, vAlign, text direction, no-wrap, shading
583
+ // ──────────────────────────────────────────────────────────────
584
+ /// <summary>
585
+ /// Demonstrates the key TableCellProperties settings.
586
+ ///
587
+ /// XML:
588
+ /// <w:tcPr>
589
+ /// <w:tcW w:w="2880" w:type="dxa"/>
590
+ /// <w:vAlign w:val="center"/>
591
+ /// <w:textDirection w:val="btLr"/>
592
+ /// <w:noWrap/>
593
+ /// <w:shd w:val="clear" w:color="auto" w:fill="E2EFDA"/>
594
+ /// </w:tcPr>
595
+ ///
596
+ /// Vertical alignment values:
597
+ /// TableVerticalAlignmentValues.Top — default
598
+ /// TableVerticalAlignmentValues.Center — vertically centered
599
+ /// TableVerticalAlignmentValues.Bottom — bottom-aligned
600
+ ///
601
+ /// Text direction values:
602
+ /// TextDirectionValues.LefToRightTopToBottom — normal horizontal (default)
603
+ /// TextDirectionValues.TopToBottomRightToLeft — vertical (CJK style)
604
+ /// TextDirectionValues.BottomToTopLeftToRight — rotated 90 CCW
605
+ /// </summary>
606
+ public static void SetCellProperties(TableCell cell)
607
+ {
608
+ var tcPr = cell.GetFirstChild<TableCellProperties>()
609
+ ?? cell.PrependChild(new TableCellProperties());
610
+
611
+ // Cell width: 2 inches = 2880 DXA
612
+ tcPr.TableCellWidth = new TableCellWidth
613
+ {
614
+ Width = "2880",
615
+ Type = TableWidthUnitValues.Dxa
616
+ };
617
+
618
+ // Vertical alignment: center content vertically in cell
619
+ tcPr.TableCellVerticalAlignment = new TableCellVerticalAlignment
620
+ {
621
+ Val = TableVerticalAlignmentValues.Center
622
+ };
623
+
624
+ // Text direction: bottom-to-top (rotated 90 degrees counterclockwise)
625
+ // Useful for narrow column headers
626
+ tcPr.TextDirection = new TextDirection
627
+ {
628
+ Val = TextDirectionValues.BottomToTopLeftToRight
629
+ };
630
+
631
+ // No-wrap: prevent text wrapping, force cell to expand horizontally
632
+ tcPr.NoWrap = new NoWrap();
633
+
634
+ // Shading (background color): light green
635
+ // Fill is the background color; Color is the pattern color (usually "auto")
636
+ tcPr.Shading = new Shading
637
+ {
638
+ Val = ShadingPatternValues.Clear,
639
+ Color = "auto",
640
+ Fill = "E2EFDA"
641
+ };
642
+ }
643
+
644
+ // ──────────────────────────────────────────────────────────────
645
+ // 10. SetTableCellMargins — table-level default cell margins
646
+ // ──────────────────────────────────────────────────────────────
647
+ /// <summary>
648
+ /// Sets default cell margins (padding) for the entire table.
649
+ /// These apply to ALL cells unless overridden per-cell.
650
+ ///
651
+ /// XML:
652
+ /// <w:tblPr>
653
+ /// <w:tblCellMar>
654
+ /// <w:top w:w="72" w:type="dxa"/>
655
+ /// <w:start w:w="115" w:type="dxa"/>
656
+ /// <w:bottom w:w="72" w:type="dxa"/>
657
+ /// <w:end w:w="115" w:type="dxa"/>
658
+ /// </w:tblCellMar>
659
+ /// </w:tblPr>
660
+ ///
661
+ /// Units: DXA. Default Word margins are approximately top/bottom=0, left/right=108 DXA.
662
+ ///
663
+ /// GOTCHA: Use StartMargin/EndMargin (not LeftMargin/RightMargin) for OOXML Strict
664
+ /// compliance, but Word also accepts Left/Right.
665
+ /// </summary>
666
+ public static void SetTableCellMargins(Table table)
667
+ {
668
+ var tblPr = table.GetFirstChild<TableProperties>()
669
+ ?? table.PrependChild(new TableProperties());
670
+
671
+ tblPr.TableCellMarginDefault = new TableCellMarginDefault(
672
+ new TopMargin { Width = "72", Type = TableWidthUnitValues.Dxa }, // ~0.05 inch
673
+ new StartMargin { Width = "115", Type = TableWidthUnitValues.Dxa }, // ~0.08 inch
674
+ new BottomMargin { Width = "72", Type = TableWidthUnitValues.Dxa },
675
+ new EndMargin { Width = "115", Type = TableWidthUnitValues.Dxa }
676
+ );
677
+ }
678
+
679
+ // ──────────────────────────────────────────────────────────────
680
+ // 11. SetPerCellMargins — per-cell override
681
+ // ──────────────────────────────────────────────────────────────
682
+ /// <summary>
683
+ /// Overrides the table-level cell margins for a specific cell.
684
+ ///
685
+ /// XML:
686
+ /// <w:tcPr>
687
+ /// <w:tcMar>
688
+ /// <w:top w:w="144" w:type="dxa"/>
689
+ /// <w:start w:w="216" w:type="dxa"/>
690
+ /// <w:bottom w:w="144" w:type="dxa"/>
691
+ /// <w:end w:w="216" w:type="dxa"/>
692
+ /// </w:tcMar>
693
+ /// </w:tcPr>
694
+ ///
695
+ /// GOTCHA: Per-cell margins fully replace the table defaults for that cell.
696
+ /// You must specify all four sides; omitted sides get zero margin (not the table default).
697
+ /// </summary>
698
+ public static void SetPerCellMargins(TableCell cell)
699
+ {
700
+ var tcPr = cell.GetFirstChild<TableCellProperties>()
701
+ ?? cell.PrependChild(new TableCellProperties());
702
+
703
+ tcPr.TableCellMargin = new TableCellMargin(
704
+ new TopMargin { Width = "144", Type = TableWidthUnitValues.Dxa }, // 0.1 inch
705
+ new StartMargin { Width = "216", Type = TableWidthUnitValues.Dxa }, // 0.15 inch
706
+ new BottomMargin { Width = "144", Type = TableWidthUnitValues.Dxa },
707
+ new EndMargin { Width = "216", Type = TableWidthUnitValues.Dxa }
708
+ );
709
+ }
710
+
711
+ // ──────────────────────────────────────────────────────────────
712
+ // 12. SetRowHeight — exact, atLeast, auto
713
+ // ──────────────────────────────────────────────────────────────
714
+ /// <summary>
715
+ /// Controls the height of a table row.
716
+ ///
717
+ /// XML: <w:trPr><w:trHeight w:val="720" w:hRule="exact"/></w:trPr>
718
+ ///
719
+ /// Height rule values:
720
+ /// HeightRuleValues.Exact — row is exactly the specified height; content may clip
721
+ /// HeightRuleValues.AtLeast — row is at least the specified height; expands for content
722
+ /// HeightRuleValues.Auto — row height determined by content (default)
723
+ ///
724
+ /// Height value is in DXA (twentieths of a point). 1440 DXA = 1 inch.
725
+ /// </summary>
726
+ public static void SetRowHeight(TableRow row)
727
+ {
728
+ var trPr = row.GetFirstChild<TableRowProperties>()
729
+ ?? row.PrependChild(new TableRowProperties());
730
+
731
+ // Option A: Exact height of 0.5 inch (720 DXA)
732
+ trPr.Append(new TableRowHeight
733
+ {
734
+ Val = 720, // 0.5 inch in DXA
735
+ HeightType = HeightRuleValues.Exact
736
+ });
737
+
738
+ // Option B: Minimum height (grows if content needs more)
739
+ // trPr.Append(new TableRowHeight
740
+ // {
741
+ // Val = 360, // 0.25 inch minimum
742
+ // HeightType = HeightRuleValues.AtLeast
743
+ // });
744
+ }
745
+
746
+ // ──────────────────────────────────────────────────────────────
747
+ // 13. SetHeaderRowRepeat — repeat on each page
748
+ // ──────────────────────────────────────────────────────────────
749
+ /// <summary>
750
+ /// Marks a row as a header row that repeats at the top of each page
751
+ /// when the table spans multiple pages.
752
+ ///
753
+ /// XML:
754
+ /// <w:trPr>
755
+ /// <w:tblHeader/>
756
+ /// </w:trPr>
757
+ ///
758
+ /// GOTCHA: Only works on contiguous rows starting from the FIRST row of the table.
759
+ /// If row 1 and row 2 are both headers, both must have TableHeader set.
760
+ /// You cannot make row 3 a repeating header if row 2 is not.
761
+ /// </summary>
762
+ public static void SetHeaderRowRepeat(TableRow row)
763
+ {
764
+ var trPr = row.GetFirstChild<TableRowProperties>()
765
+ ?? row.PrependChild(new TableRowProperties());
766
+
767
+ trPr.Append(new TableHeader());
768
+ }
769
+
770
+ // ──────────────────────────────────────────────────────────────
771
+ // 14. SetPerCellBorders — override table borders on specific cells
772
+ // ──────────────────────────────────────────────────────────────
773
+ /// <summary>
774
+ /// Overrides the table-level borders for a specific cell.
775
+ /// Per-cell borders take precedence over table-level borders.
776
+ ///
777
+ /// XML:
778
+ /// <w:tcPr>
779
+ /// <w:tcBorders>
780
+ /// <w:top w:val="double" w:sz="4" w:space="0" w:color="FF0000"/>
781
+ /// <w:bottom w:val="single" w:sz="12" w:space="0" w:color="0000FF"/>
782
+ /// <w:start w:val="none" w:sz="0" w:space="0" w:color="auto"/>
783
+ /// <w:end w:val="none" w:sz="0" w:space="0" w:color="auto"/>
784
+ /// </w:tcBorders>
785
+ /// </w:tcPr>
786
+ ///
787
+ /// GOTCHA: When two adjacent cells define conflicting borders, the conflict
788
+ /// resolution follows the ECMA-376 spec: wider borders win; if same width,
789
+ /// the cell on the "end" side wins.
790
+ /// </summary>
791
+ public static void SetPerCellBorders(TableCell cell)
792
+ {
793
+ var tcPr = cell.GetFirstChild<TableCellProperties>()
794
+ ?? cell.PrependChild(new TableCellProperties());
795
+
796
+ tcPr.TableCellBorders = new TableCellBorders(
797
+ new TopBorder { Val = BorderValues.Double, Size = 4, Space = 0, Color = "FF0000" },
798
+ new BottomBorder { Val = BorderValues.Single, Size = 12, Space = 0, Color = "0000FF" },
799
+ new LeftBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
800
+ new RightBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" }
801
+ );
802
+ }
803
+
804
+ // ──────────────────────────────────────────────────────────────
805
+ // 15. CreateHorizontalMerge — GridSpan (column span)
806
+ // ──────────────────────────────────────────────────────────────
807
+ /// <summary>
808
+ /// Creates a row with horizontal cell merging using GridSpan.
809
+ ///
810
+ /// To merge 3 columns into one cell, set GridSpan.Val = 3 on that cell.
811
+ /// The row still references the same grid columns, but one cell spans multiple.
812
+ ///
813
+ /// XML for a row in a 4-column table where first cell spans columns 1-3:
814
+ /// <w:tr>
815
+ /// <w:tc>
816
+ /// <w:tcPr>
817
+ /// <w:gridSpan w:val="3"/> <!-- this cell spans 3 grid columns -->
818
+ /// </w:tcPr>
819
+ /// <w:p><w:r><w:t>Merged across 3 columns</w:t></w:r></w:p>
820
+ /// </w:tc>
821
+ /// <w:tc>
822
+ /// <w:p><w:r><w:t>Normal cell</w:t></w:r></w:p>
823
+ /// </w:tc>
824
+ /// </w:tr>
825
+ ///
826
+ /// GOTCHA: The total GridSpan values across all cells in a row must equal
827
+ /// the number of GridColumn elements in TblGrid.
828
+ /// </summary>
829
+ public static TableRow CreateHorizontalMerge(TableRow row)
830
+ {
831
+ // Assume a 4-column grid: first cell spans 3 columns, second cell is normal
832
+
833
+ // Cell spanning 3 columns
834
+ var mergedCell = new TableCell(
835
+ new TableCellProperties(
836
+ new GridSpan { Val = 3 }),
837
+ new Paragraph(
838
+ new Run(new Text("This cell spans 3 columns"))));
839
+ row.Append(mergedCell);
840
+
841
+ // Normal cell (1 column, GridSpan defaults to 1 when omitted)
842
+ var normalCell = new TableCell(
843
+ new Paragraph(
844
+ new Run(new Text("Normal cell"))));
845
+ row.Append(normalCell);
846
+
847
+ return row;
848
+ }
849
+
850
+ // ──────────────────────────────────────────────────────────────
851
+ // 16. CreateVerticalMerge — VerticalMerge Restart + Continue
852
+ // ──────────────────────────────────────────────────────────────
853
+ /// <summary>
854
+ /// Creates vertical cell merging using VerticalMerge with Restart/Continue pattern.
855
+ ///
856
+ /// Vertical merge pattern:
857
+ /// - First row: VerticalMerge.Val = MergedCellValues.Restart (starts the merge)
858
+ /// - Subsequent rows: VerticalMerge.Val = MergedCellValues.Continue (continues)
859
+ /// - Last continuation can also use VerticalMerge with no Val attribute
860
+ ///
861
+ /// XML:
862
+ /// Row 1: <w:tcPr><w:vMerge w:val="restart"/></w:tcPr>
863
+ /// <w:p><w:r><w:t>Visible content</w:t></w:r></w:p>
864
+ /// Row 2: <w:tcPr><w:vMerge/></w:tcPr>
865
+ /// <w:p/> <!-- MUST still have a paragraph, even though cell is merged -->
866
+ /// Row 3: <w:tcPr><w:vMerge/></w:tcPr>
867
+ /// <w:p/> <!-- MUST still have a paragraph -->
868
+ ///
869
+ /// GOTCHA: The "continue" cells MUST still contain at least one empty Paragraph.
870
+ /// They also MUST have the same column position in the grid as the "restart" cell.
871
+ /// </summary>
872
+ public static Table CreateVerticalMerge(Table table)
873
+ {
874
+ var grid = new TableGrid(
875
+ new GridColumn { Width = "3120" },
876
+ new GridColumn { Width = "3120" },
877
+ new GridColumn { Width = "3120" });
878
+ // Only add grid if not already present
879
+ if (table.GetFirstChild<TableGrid>() == null)
880
+ {
881
+ var tblPr = table.GetFirstChild<TableProperties>();
882
+ if (tblPr != null)
883
+ tblPr.InsertAfterSelf(grid);
884
+ else
885
+ table.PrependChild(grid);
886
+ }
887
+
888
+ // Row 1: first cell starts vertical merge
889
+ var row1 = new TableRow(
890
+ new TableCell(
891
+ new TableCellProperties(
892
+ new VerticalMerge { Val = MergedCellValues.Restart }), // Start merge
893
+ new Paragraph(new Run(new Text("Spans 3 rows")))),
894
+ new TableCell(
895
+ new Paragraph(new Run(new Text("Row 1, Col 2")))),
896
+ new TableCell(
897
+ new Paragraph(new Run(new Text("Row 1, Col 3")))));
898
+ table.Append(row1);
899
+
900
+ // Row 2: first cell continues vertical merge
901
+ var row2 = new TableRow(
902
+ new TableCell(
903
+ new TableCellProperties(
904
+ new VerticalMerge()), // Continue (no Val)
905
+ new Paragraph()), // Empty paragraph required!
906
+ new TableCell(
907
+ new Paragraph(new Run(new Text("Row 2, Col 2")))),
908
+ new TableCell(
909
+ new Paragraph(new Run(new Text("Row 2, Col 3")))));
910
+ table.Append(row2);
911
+
912
+ // Row 3: first cell continues vertical merge
913
+ var row3 = new TableRow(
914
+ new TableCell(
915
+ new TableCellProperties(
916
+ new VerticalMerge()), // Continue
917
+ new Paragraph()), // Empty paragraph required!
918
+ new TableCell(
919
+ new Paragraph(new Run(new Text("Row 3, Col 2")))),
920
+ new TableCell(
921
+ new Paragraph(new Run(new Text("Row 3, Col 3")))));
922
+ table.Append(row3);
923
+
924
+ return table;
925
+ }
926
+
927
+ // ──────────────────────────────────────────────────────────────
928
+ // 17. CreateNestedTable — table inside a table cell
929
+ // ──────────────────────────────────────────────────────────────
930
+ /// <summary>
931
+ /// Inserts a table inside a table cell.
932
+ ///
933
+ /// GOTCHA: The nested table is a direct child of the TableCell, placed BEFORE
934
+ /// the required trailing Paragraph. The cell structure is:
935
+ ///
936
+ /// <w:tc>
937
+ /// <w:tcPr>...</w:tcPr>
938
+ /// <w:tbl> <!-- nested table -->
939
+ /// <w:tblPr>...</w:tblPr>
940
+ /// <w:tblGrid>...</w:tblGrid>
941
+ /// <w:tr>...</w:tr>
942
+ /// </w:tbl>
943
+ /// <w:p/> <!-- REQUIRED trailing paragraph -->
944
+ /// </w:tc>
945
+ ///
946
+ /// GOTCHA: The parent cell still MUST end with a Paragraph after the nested table.
947
+ /// </summary>
948
+ public static Table CreateNestedTable(TableCell parentCell)
949
+ {
950
+ var nestedTable = new Table();
951
+
952
+ var tblPr = new TableProperties(
953
+ new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct },
954
+ new TableBorders(
955
+ new TopBorder { Val = BorderValues.Single, Size = 4, Space = 0, Color = "999999" },
956
+ new LeftBorder { Val = BorderValues.Single, Size = 4, Space = 0, Color = "999999" },
957
+ new BottomBorder { Val = BorderValues.Single, Size = 4, Space = 0, Color = "999999" },
958
+ new RightBorder { Val = BorderValues.Single, Size = 4, Space = 0, Color = "999999" },
959
+ new InsideHorizontalBorder { Val = BorderValues.Single, Size = 4, Space = 0, Color = "999999" },
960
+ new InsideVerticalBorder { Val = BorderValues.Single, Size = 4, Space = 0, Color = "999999" }
961
+ ));
962
+ nestedTable.Append(tblPr);
963
+
964
+ var grid = new TableGrid(
965
+ new GridColumn { Width = "2000" },
966
+ new GridColumn { Width = "2000" });
967
+ nestedTable.Append(grid);
968
+
969
+ // 2x2 nested table
970
+ for (int r = 0; r < 2; r++)
971
+ {
972
+ var row = new TableRow();
973
+ for (int c = 0; c < 2; c++)
974
+ {
975
+ var cell = new TableCell(
976
+ new Paragraph(
977
+ new Run(new Text($"Nested R{r + 1}C{c + 1}"))));
978
+ row.Append(cell);
979
+ }
980
+ nestedTable.Append(row);
981
+ }
982
+
983
+ // Insert the nested table in the parent cell.
984
+ // The parent cell must still end with a paragraph.
985
+ parentCell.Append(nestedTable);
986
+ parentCell.Append(new Paragraph()); // REQUIRED trailing paragraph
987
+
988
+ return nestedTable;
989
+ }
990
+
991
+ // ──────────────────────────────────────────────────────────────
992
+ // 18. CreateFloatingTable — absolute positioning
993
+ // ──────────────────────────────────────────────────────────────
994
+ /// <summary>
995
+ /// Creates a floating (absolutely positioned) table using TablePositionProperties.
996
+ ///
997
+ /// XML:
998
+ /// <w:tblPr>
999
+ /// <w:tblpPr
1000
+ /// w:leftFromText="180"
1001
+ /// w:rightFromText="180"
1002
+ /// w:topFromText="180"
1003
+ /// w:bottomFromText="180"
1004
+ /// w:vertAnchor="page"
1005
+ /// w:horzAnchor="page"
1006
+ /// w:tblpX="2880"
1007
+ /// w:tblpY="4320"/>
1008
+ /// </w:tblPr>
1009
+ ///
1010
+ /// Anchor values:
1011
+ /// VerticalAnchorValues.Page / Margin / Text
1012
+ /// HorizontalAnchorValues.Page / Margin / Text
1013
+ ///
1014
+ /// Position values (tblpX, tblpY) are in DXA from the anchor.
1015
+ /// FromText values are spacing between table and surrounding text, in DXA.
1016
+ ///
1017
+ /// GOTCHA: Floating tables allow text to wrap around them, similar to
1018
+ /// text-wrapped images. This can produce unexpected layouts.
1019
+ /// </summary>
1020
+ public static Table CreateFloatingTable(Body body)
1021
+ {
1022
+ var table = new Table();
1023
+
1024
+ var tblPr = new TableProperties();
1025
+
1026
+ // Floating position: 2 inches from left of page, 3 inches from top of page
1027
+ tblPr.TablePositionProperties = new TablePositionProperties
1028
+ {
1029
+ LeftFromText = 180, // 0.125" spacing from text
1030
+ RightFromText = 180,
1031
+ TopFromText = 180,
1032
+ BottomFromText = 180,
1033
+ VerticalAnchor = VerticalAnchorValues.Page,
1034
+ HorizontalAnchor = HorizontalAnchorValues.Page,
1035
+ TablePositionX = 2880, // 2 inches from left edge of page
1036
+ TablePositionY = 4320 // 3 inches from top of page
1037
+ };
1038
+
1039
+ tblPr.Append(new TableWidth { Width = "3600", Type = TableWidthUnitValues.Dxa });
1040
+ tblPr.Append(new TableBorders(
1041
+ new TopBorder { Val = BorderValues.Single, Size = 4, Space = 0, Color = "000000" },
1042
+ new LeftBorder { Val = BorderValues.Single, Size = 4, Space = 0, Color = "000000" },
1043
+ new BottomBorder { Val = BorderValues.Single, Size = 4, Space = 0, Color = "000000" },
1044
+ new RightBorder { Val = BorderValues.Single, Size = 4, Space = 0, Color = "000000" },
1045
+ new InsideHorizontalBorder { Val = BorderValues.Single, Size = 4, Space = 0, Color = "000000" },
1046
+ new InsideVerticalBorder { Val = BorderValues.Single, Size = 4, Space = 0, Color = "000000" }
1047
+ ));
1048
+ table.Append(tblPr);
1049
+
1050
+ var grid = new TableGrid(
1051
+ new GridColumn { Width = "1800" },
1052
+ new GridColumn { Width = "1800" });
1053
+ table.Append(grid);
1054
+
1055
+ // Simple 2x2 floating table
1056
+ for (int r = 0; r < 2; r++)
1057
+ {
1058
+ var row = new TableRow();
1059
+ for (int c = 0; c < 2; c++)
1060
+ {
1061
+ var cell = new TableCell(
1062
+ new Paragraph(
1063
+ new Run(new Text($"Float R{r + 1}C{c + 1}"))));
1064
+ row.Append(cell);
1065
+ }
1066
+ table.Append(row);
1067
+ }
1068
+
1069
+ body.Append(table);
1070
+ return table;
1071
+ }
1072
+
1073
+ // ──────────────────────────────────────────────────────────────
1074
+ // 19. ApplyTableLook — conditional formatting flags
1075
+ // ──────────────────────────────────────────────────────────────
1076
+ /// <summary>
1077
+ /// Sets the TableLook element which controls which parts of a table style are applied.
1078
+ ///
1079
+ /// XML:
1080
+ /// <w:tblPr>
1081
+ /// <w:tblLook w:val="04A0"
1082
+ /// w:firstRow="1"
1083
+ /// w:lastRow="0"
1084
+ /// w:firstColumn="1"
1085
+ /// w:lastColumn="0"
1086
+ /// w:noHBand="0"
1087
+ /// w:noVBand="1"/>
1088
+ /// </w:tblPr>
1089
+ ///
1090
+ /// These flags control conditional formatting from the applied table style:
1091
+ /// FirstRow = apply special header row formatting
1092
+ /// LastRow = apply special last row formatting
1093
+ /// FirstColumn = apply special first column formatting
1094
+ /// LastColumn = apply special last column formatting
1095
+ /// NoHorizontalBand = disable banded row shading
1096
+ /// NoVerticalBand = disable banded column shading
1097
+ ///
1098
+ /// The Val attribute is a bitmask but the individual boolean attributes are preferred.
1099
+ /// </summary>
1100
+ public static void ApplyTableLook(Table table)
1101
+ {
1102
+ var tblPr = table.GetFirstChild<TableProperties>()
1103
+ ?? table.PrependChild(new TableProperties());
1104
+
1105
+ tblPr.TableLook = new TableLook
1106
+ {
1107
+ Val = "04A0",
1108
+ FirstRow = true,
1109
+ LastRow = false,
1110
+ FirstColumn = true,
1111
+ LastColumn = false,
1112
+ NoHorizontalBand = false, // false = DO apply banded row shading
1113
+ NoVerticalBand = true // true = do NOT apply banded column shading
1114
+ };
1115
+ }
1116
+
1117
+ // ──────────────────────────────────────────────────────────────
1118
+ // 20. ApplyTableStyle — reference a named style
1119
+ // ──────────────────────────────────────────────────────────────
1120
+ /// <summary>
1121
+ /// References a named table style defined in the styles part.
1122
+ ///
1123
+ /// XML:
1124
+ /// <w:tblPr>
1125
+ /// <w:tblStyle w:val="TableGrid"/>
1126
+ /// </w:tblPr>
1127
+ ///
1128
+ /// Common built-in style IDs:
1129
+ /// "TableGrid" — basic grid with all borders
1130
+ /// "TableNormal" — no borders or shading
1131
+ /// "LightShading" — light shading style
1132
+ /// "MediumShading1" — medium shading
1133
+ /// "GridTable4-Accent1" — colorful banded table (Office 2013+)
1134
+ ///
1135
+ /// GOTCHA: The style ID must exist in the StyleDefinitionsPart. If you reference
1136
+ /// a style that doesn't exist, Word will silently ignore it and use defaults.
1137
+ /// Built-in styles are only available if they have been added to the styles part
1138
+ /// (Word adds them lazily on first use).
1139
+ ///
1140
+ /// GOTCHA: Combine with TableLook to control which conditional parts of the
1141
+ /// style are applied (header row, banded rows, etc.).
1142
+ /// </summary>
1143
+ public static void ApplyTableStyle(Table table)
1144
+ {
1145
+ var tblPr = table.GetFirstChild<TableProperties>()
1146
+ ?? table.PrependChild(new TableProperties());
1147
+
1148
+ // Reference the "TableGrid" built-in style
1149
+ tblPr.TableStyle = new TableStyle { Val = "TableGrid" };
1150
+
1151
+ // Combine with TableLook for conditional formatting
1152
+ tblPr.TableLook = new TableLook
1153
+ {
1154
+ Val = "04A0",
1155
+ FirstRow = true,
1156
+ LastRow = false,
1157
+ FirstColumn = true,
1158
+ LastColumn = false,
1159
+ NoHorizontalBand = false,
1160
+ NoVerticalBand = true
1161
+ };
1162
+ }
1163
+ }