@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,826 @@
1
+ // ============================================================================
2
+ // ListAndNumberingSamples.cs — OpenXML numbering system deep dive
3
+ // ============================================================================
4
+ // OpenXML list/numbering architecture (3 layers):
5
+ //
6
+ // 1. AbstractNum — defines the numbering FORMAT (bullet chars, number formats,
7
+ // indentation, fonts). Contains Level elements (0-8) for multi-level lists.
8
+ //
9
+ // 2. NumberingInstance (Num) — a concrete "instance" that references an
10
+ // AbstractNum. Multiple paragraphs share the same NumId to form one list.
11
+ // LevelOverride on a NumberingInstance can restart numbering.
12
+ //
13
+ // 3. NumberingProperties on Paragraph — links a paragraph to a NumberingInstance
14
+ // via NumId + Level (ilvl). This is what makes a paragraph a list item.
15
+ //
16
+ // CRITICAL RULES:
17
+ // - In the Numbering root element, ALL AbstractNum elements MUST appear
18
+ // BEFORE any NumberingInstance (Num) elements. Violating this order causes
19
+ // Word to report corruption.
20
+ // - LevelText uses %1, %2, %3 etc. as placeholders for the current value
21
+ // at each level. %1 = level 0's value, %2 = level 1's value, etc.
22
+ // - NumberingSymbolRunProperties (rPr inside Level) sets the font for the
23
+ // bullet character or number. Without it, the bullet may render in the
24
+ // paragraph's font, which can produce wrong glyphs.
25
+ // - IsLegalNumberingStyle on a Level forces "legal" flat numbering
26
+ // (e.g., "1.1.1" instead of outline style) regardless of heading level.
27
+ //
28
+ // Storage: Numbering definitions live in numbering.xml, accessed via
29
+ // NumberingDefinitionsPart on the MainDocumentPart.
30
+ // ============================================================================
31
+
32
+ using DocumentFormat.OpenXml;
33
+ using DocumentFormat.OpenXml.Packaging;
34
+ using DocumentFormat.OpenXml.Wordprocessing;
35
+
36
+ using A = DocumentFormat.OpenXml.Drawing;
37
+ using DW = DocumentFormat.OpenXml.Drawing.Wordprocessing;
38
+ using PIC = DocumentFormat.OpenXml.Drawing.Pictures;
39
+
40
+ namespace MiniMaxAIDocx.Core.Samples;
41
+
42
+ /// <summary>
43
+ /// Reference implementations for bullet lists, numbered lists, custom numbering,
44
+ /// and all related numbering infrastructure in OpenXML.
45
+ /// </summary>
46
+ public static class ListAndNumberingSamples
47
+ {
48
+ // ── 1. Bullet List (3 levels) ──────────────────────────────────────
49
+
50
+ /// <summary>
51
+ /// Creates a 3-level bullet list: bullet (•) → circle (○) → square (■).
52
+ /// Uses Symbol font for standard bullet characters.
53
+ /// </summary>
54
+ public static void CreateBulletList(
55
+ NumberingDefinitionsPart numPart, Body body)
56
+ {
57
+ int abstractNumId = 0;
58
+ int numId = 1;
59
+
60
+ // Level 0: solid bullet • (Unicode F0B7 in Symbol font)
61
+ // Level 1: open circle ○ (Unicode F06F in Symbol font = ○, or "o" in Courier New)
62
+ // Level 2: solid square ■ (Unicode F0A7 in Wingdings)
63
+ var levels = new Level[]
64
+ {
65
+ CreateBulletLevel(
66
+ levelIndex: 0,
67
+ bulletChar: "\xF0B7", // • in Symbol
68
+ font: "Symbol",
69
+ indentLeftDxa: 720, // 0.5 inch
70
+ hangingDxa: 360), // bullet hangs 0.25 inch
71
+
72
+ CreateBulletLevel(
73
+ levelIndex: 1,
74
+ bulletChar: "o", // ○ in Courier New
75
+ font: "Courier New",
76
+ indentLeftDxa: 1440, // 1.0 inch
77
+ hangingDxa: 360),
78
+
79
+ CreateBulletLevel(
80
+ levelIndex: 2,
81
+ bulletChar: "\xF0A7", // ■ in Wingdings
82
+ font: "Wingdings",
83
+ indentLeftDxa: 2160, // 1.5 inch
84
+ hangingDxa: 360)
85
+ };
86
+
87
+ // Build the abstract numbering definition and instance
88
+ SetupAbstractNum(numPart, abstractNumId, levels);
89
+ SetupNumberingInstance(numPart, numId, abstractNumId);
90
+
91
+ // Create sample list items at each level
92
+ string[] level0Items = ["First item", "Second item", "Third item"];
93
+ string[] level1Items = ["Sub-item A", "Sub-item B"];
94
+ string[] level2Items = ["Detail 1", "Detail 2"];
95
+
96
+ foreach (string text in level0Items)
97
+ {
98
+ Paragraph para = CreateListParagraph(text, numId, level: 0);
99
+ body.AppendChild(para);
100
+ }
101
+ foreach (string text in level1Items)
102
+ {
103
+ Paragraph para = CreateListParagraph(text, numId, level: 1);
104
+ body.AppendChild(para);
105
+ }
106
+ foreach (string text in level2Items)
107
+ {
108
+ Paragraph para = CreateListParagraph(text, numId, level: 2);
109
+ body.AppendChild(para);
110
+ }
111
+ }
112
+
113
+ // ── 2. Numbered List (3 levels) ────────────────────────────────────
114
+
115
+ /// <summary>
116
+ /// Creates a 3-level numbered list: 1. → 1.1. → 1.1.1.
117
+ /// Uses NumberFormatValues.Decimal with compound LevelText patterns.
118
+ /// </summary>
119
+ public static void CreateNumberedList(
120
+ NumberingDefinitionsPart numPart, Body body)
121
+ {
122
+ int abstractNumId = 1;
123
+ int numId = 2;
124
+
125
+ // LevelText explanation:
126
+ // "%1" → just the level-0 counter: 1, 2, 3...
127
+ // "%1.%2" → level-0.level-1: 1.1, 1.2, 2.1...
128
+ // "%1.%2.%3" → level-0.level-1.level-2: 1.1.1, 1.1.2...
129
+ var levels = new Level[]
130
+ {
131
+ CreateNumberLevel(
132
+ levelIndex: 0,
133
+ format: NumberFormatValues.Decimal,
134
+ levelText: "%1.", // "1.", "2.", "3."
135
+ indentLeftDxa: 720,
136
+ hangingDxa: 360,
137
+ start: 1),
138
+
139
+ CreateNumberLevel(
140
+ levelIndex: 1,
141
+ format: NumberFormatValues.Decimal,
142
+ levelText: "%1.%2.", // "1.1.", "1.2.", "2.1."
143
+ indentLeftDxa: 1440,
144
+ hangingDxa: 720, // wider hanging for "1.1."
145
+ start: 1),
146
+
147
+ CreateNumberLevel(
148
+ levelIndex: 2,
149
+ format: NumberFormatValues.Decimal,
150
+ levelText: "%1.%2.%3.", // "1.1.1.", "1.1.2."
151
+ indentLeftDxa: 2160,
152
+ hangingDxa: 1080,
153
+ start: 1)
154
+ };
155
+
156
+ SetupAbstractNum(numPart, abstractNumId, levels);
157
+ SetupNumberingInstance(numPart, numId, abstractNumId);
158
+
159
+ // Sample items
160
+ body.AppendChild(CreateListParagraph("Chapter One", numId, level: 0));
161
+ body.AppendChild(CreateListParagraph("Section One", numId, level: 1));
162
+ body.AppendChild(CreateListParagraph("Detail A", numId, level: 2));
163
+ body.AppendChild(CreateListParagraph("Detail B", numId, level: 2));
164
+ body.AppendChild(CreateListParagraph("Section Two", numId, level: 1));
165
+ body.AppendChild(CreateListParagraph("Chapter Two", numId, level: 0));
166
+ }
167
+
168
+ // ── 3. Custom Bullet Characters ────────────────────────────────────
169
+
170
+ /// <summary>
171
+ /// Creates bullets with custom Unicode characters: ✓ (check), ➢ (arrow), ★ (star).
172
+ /// Uses specific fonts that contain these glyphs.
173
+ /// </summary>
174
+ public static void CreateCustomBullets(
175
+ NumberingDefinitionsPart numPart, Body body)
176
+ {
177
+ int abstractNumId = 2;
178
+ int numId = 3;
179
+
180
+ // For custom Unicode bullets, the font in NumberingSymbolRunProperties
181
+ // MUST contain the glyph. Common choices:
182
+ // - "Segoe UI Symbol" — broad Unicode coverage on Windows
183
+ // - "Arial Unicode MS" — wide coverage
184
+ // - "Wingdings" / "Webdings" — symbol fonts (use their private codepoints)
185
+ var levels = new Level[]
186
+ {
187
+ CreateBulletLevel(
188
+ levelIndex: 0,
189
+ bulletChar: "\u2713", // ✓ CHECK MARK
190
+ font: "Segoe UI Symbol",
191
+ indentLeftDxa: 720,
192
+ hangingDxa: 360),
193
+
194
+ CreateBulletLevel(
195
+ levelIndex: 1,
196
+ bulletChar: "\u27A2", // ➢ THREE-D TOP-LIGHTED RIGHTWARDS ARROWHEAD
197
+ font: "Segoe UI Symbol",
198
+ indentLeftDxa: 1440,
199
+ hangingDxa: 360),
200
+
201
+ CreateBulletLevel(
202
+ levelIndex: 2,
203
+ bulletChar: "\u2605", // ★ BLACK STAR
204
+ font: "Segoe UI Symbol",
205
+ indentLeftDxa: 2160,
206
+ hangingDxa: 360)
207
+ };
208
+
209
+ SetupAbstractNum(numPart, abstractNumId, levels);
210
+ SetupNumberingInstance(numPart, numId, abstractNumId);
211
+
212
+ body.AppendChild(CreateListParagraph("Completed task", numId, level: 0));
213
+ body.AppendChild(CreateListParagraph("Action item", numId, level: 1));
214
+ body.AppendChild(CreateListParagraph("Starred note", numId, level: 2));
215
+ }
216
+
217
+ // ── 4. Outline Numbering Linked to Heading Styles ──────────────────
218
+
219
+ /// <summary>
220
+ /// Creates outline numbering (Article 1, Section 1.1, etc.) linked to
221
+ /// Heading1, Heading2, Heading3 styles. This is how Word's built-in
222
+ /// "List Number" styles work for legal/technical documents.
223
+ /// </summary>
224
+ /// <remarks>
225
+ /// When a Level has ParagraphStyleIdInLevel, any paragraph with that
226
+ /// style ID automatically gets numbered. The numbering is "linked" to
227
+ /// the style — you don't need NumberingProperties on each paragraph
228
+ /// (though it's also valid to add them explicitly).
229
+ /// </remarks>
230
+ public static void CreateOutlineNumbering(
231
+ NumberingDefinitionsPart numPart,
232
+ StyleDefinitionsPart stylesPart)
233
+ {
234
+ int abstractNumId = 3;
235
+ int numId = 4;
236
+
237
+ var abstractNum = new AbstractNum(
238
+ // Level 0: "1" — linked to Heading1
239
+ new Level(
240
+ new StartNumberingValue { Val = 1 },
241
+ new NumberingFormat { Val = NumberFormatValues.Decimal },
242
+ new LevelText { Val = "%1" },
243
+ new LevelJustification { Val = LevelJustificationValues.Left },
244
+ new ParagraphStyleIdInLevel { Val = "Heading1" },
245
+ new PreviousParagraphProperties(
246
+ new Indentation { Left = "432", Hanging = "432" })
247
+ )
248
+ { LevelIndex = 0 },
249
+
250
+ // Level 1: "1.1" — linked to Heading2
251
+ new Level(
252
+ new StartNumberingValue { Val = 1 },
253
+ new NumberingFormat { Val = NumberFormatValues.Decimal },
254
+ new LevelText { Val = "%1.%2" },
255
+ new LevelJustification { Val = LevelJustificationValues.Left },
256
+ new ParagraphStyleIdInLevel { Val = "Heading2" },
257
+ new PreviousParagraphProperties(
258
+ new Indentation { Left = "576", Hanging = "576" })
259
+ )
260
+ { LevelIndex = 1 },
261
+
262
+ // Level 2: "1.1.1" — linked to Heading3
263
+ new Level(
264
+ new StartNumberingValue { Val = 1 },
265
+ new NumberingFormat { Val = NumberFormatValues.Decimal },
266
+ new LevelText { Val = "%1.%2.%3" },
267
+ new LevelJustification { Val = LevelJustificationValues.Left },
268
+ new ParagraphStyleIdInLevel { Val = "Heading3" },
269
+ new PreviousParagraphProperties(
270
+ new Indentation { Left = "720", Hanging = "720" })
271
+ )
272
+ { LevelIndex = 2 }
273
+ )
274
+ {
275
+ AbstractNumberId = abstractNumId,
276
+ // MultiLevelType controls how Word treats level transitions:
277
+ // - HybridMultilevel: each level is somewhat independent (most common)
278
+ // - Multilevel: true outline numbering where sub-levels nest under parents
279
+ // - SingleLevel: only one level
280
+ MultiLevelType = new MultiLevelType
281
+ {
282
+ Val = MultiLevelValues.Multilevel
283
+ }
284
+ };
285
+
286
+ // Ensure AbstractNum appears first, then NumberingInstance
287
+ EnsureNumberingRoot(numPart);
288
+ numPart.Numbering.Append(abstractNum);
289
+
290
+ var numInstance = new NumberingInstance(
291
+ new AbstractNumId { Val = abstractNumId })
292
+ { NumberID = numId };
293
+ numPart.Numbering.Append(numInstance);
294
+
295
+ // Link the styles to the numbering definition.
296
+ // Each heading style gets a NumberingProperties pointing to this numId.
297
+ Styles styles = stylesPart.Styles ?? (stylesPart.Styles = new Styles());
298
+
299
+ LinkStyleToNumbering(styles, "Heading1", numId, level: 0);
300
+ LinkStyleToNumbering(styles, "Heading2", numId, level: 1);
301
+ LinkStyleToNumbering(styles, "Heading3", numId, level: 2);
302
+ }
303
+
304
+ // ── 5. Legal Numbering ─────────────────────────────────────────────
305
+
306
+ /// <summary>
307
+ /// Creates a legal document numbering pattern:
308
+ /// Article I, Article II (Roman numerals)
309
+ /// Section 1, Section 2 (Decimal)
310
+ /// (a), (b), (c) (Lowercase letters)
311
+ /// </summary>
312
+ public static void CreateLegalNumbering(
313
+ NumberingDefinitionsPart numPart, Body body)
314
+ {
315
+ int abstractNumId = 4;
316
+ int numId = 5;
317
+
318
+ var abstractNum = new AbstractNum(
319
+ // Level 0: "Article I" — Upper Roman
320
+ new Level(
321
+ new StartNumberingValue { Val = 1 },
322
+ new NumberingFormat { Val = NumberFormatValues.UpperRoman },
323
+ new LevelText { Val = "Article %1" },
324
+ new LevelJustification { Val = LevelJustificationValues.Left },
325
+ new PreviousParagraphProperties(
326
+ new Indentation { Left = "720", Hanging = "720" }),
327
+ new NumberingSymbolRunProperties(
328
+ new Bold(),
329
+ new RunFonts { Ascii = "Times New Roman", HighAnsi = "Times New Roman" })
330
+ )
331
+ { LevelIndex = 0 },
332
+
333
+ // Level 1: "Section 1" — Decimal
334
+ new Level(
335
+ new StartNumberingValue { Val = 1 },
336
+ new NumberingFormat { Val = NumberFormatValues.Decimal },
337
+ new LevelText { Val = "Section %2" },
338
+ new LevelJustification { Val = LevelJustificationValues.Left },
339
+ new PreviousParagraphProperties(
340
+ new Indentation { Left = "1440", Hanging = "720" })
341
+ )
342
+ { LevelIndex = 1 },
343
+
344
+ // Level 2: "(a)" — Lowercase letter
345
+ new Level(
346
+ new StartNumberingValue { Val = 1 },
347
+ new NumberingFormat { Val = NumberFormatValues.LowerLetter },
348
+ new LevelText { Val = "(%3)" },
349
+ new LevelJustification { Val = LevelJustificationValues.Left },
350
+ new PreviousParagraphProperties(
351
+ new Indentation { Left = "2160", Hanging = "720" })
352
+ )
353
+ { LevelIndex = 2 }
354
+ )
355
+ {
356
+ AbstractNumberId = abstractNumId,
357
+ MultiLevelType = new MultiLevelType { Val = MultiLevelValues.Multilevel }
358
+ };
359
+
360
+ EnsureNumberingRoot(numPart);
361
+ numPart.Numbering.Append(abstractNum);
362
+ SetupNumberingInstance(numPart, numId, abstractNumId);
363
+
364
+ // Sample legal document structure
365
+ body.AppendChild(CreateListParagraph("Definitions", numId, level: 0));
366
+ body.AppendChild(CreateListParagraph("General Terms", numId, level: 1));
367
+ body.AppendChild(CreateListParagraph(
368
+ "\"Agreement\" means this document and all exhibits.", numId, level: 2));
369
+ body.AppendChild(CreateListParagraph(
370
+ "\"Party\" means any signatory to this Agreement.", numId, level: 2));
371
+ body.AppendChild(CreateListParagraph("Scope of Work", numId, level: 1));
372
+ body.AppendChild(CreateListParagraph("Obligations", numId, level: 0));
373
+ }
374
+
375
+ // ── 6. Chinese Numbering ───────────────────────────────────────────
376
+
377
+ /// <summary>
378
+ /// Creates a Chinese document numbering hierarchy:
379
+ /// Level 0: 一、二、三、 (Chinese ideographic, followed by 、)
380
+ /// Level 1: (一)(二)(三) (Chinese ideographic in parentheses)
381
+ /// Level 2: 1. 2. 3. (Decimal, Arabic numerals)
382
+ /// Level 3: (1) (2) (3) (Decimal in parentheses)
383
+ ///
384
+ /// Chinese numbering uses NumberFormatValues.ChineseCounting or
385
+ /// ChineseCountingThousand for 一二三 style characters.
386
+ /// The font for Chinese number characters should be a CJK font like SimSun or SimHei.
387
+ /// </summary>
388
+ public static void CreateChineseNumbering(
389
+ NumberingDefinitionsPart numPart, Body body)
390
+ {
391
+ int abstractNumId = 5;
392
+ int numId = 6;
393
+
394
+ var abstractNum = new AbstractNum(
395
+ // Level 0: 一、 二、 三、
396
+ // ChineseCountingThousand produces 一 二 三 四 五 六 七 八 九 十
397
+ new Level(
398
+ new StartNumberingValue { Val = 1 },
399
+ new NumberingFormat { Val = NumberFormatValues.ChineseCountingThousand },
400
+ new LevelText { Val = "%1\u3001" }, // 、 is the Chinese enumeration comma
401
+ new LevelJustification { Val = LevelJustificationValues.Left },
402
+ new PreviousParagraphProperties(
403
+ new Indentation { Left = "840", Hanging = "420" }),
404
+ // NumberingSymbolRunProperties MUST specify a CJK font
405
+ // so the Chinese number renders correctly
406
+ new NumberingSymbolRunProperties(
407
+ new RunFonts
408
+ {
409
+ Ascii = "SimSun",
410
+ HighAnsi = "SimSun",
411
+ EastAsia = "SimSun", // Critical for CJK rendering
412
+ ComplexScript = "SimSun"
413
+ })
414
+ )
415
+ { LevelIndex = 0 },
416
+
417
+ // Level 1: (一)(二)(三)
418
+ new Level(
419
+ new StartNumberingValue { Val = 1 },
420
+ new NumberingFormat { Val = NumberFormatValues.ChineseCountingThousand },
421
+ new LevelText { Val = "\uFF08%2\uFF09" }, // ( and ) are fullwidth parens
422
+ new LevelJustification { Val = LevelJustificationValues.Left },
423
+ new PreviousParagraphProperties(
424
+ new Indentation { Left = "1260", Hanging = "420" }),
425
+ new NumberingSymbolRunProperties(
426
+ new RunFonts
427
+ {
428
+ Ascii = "SimSun",
429
+ HighAnsi = "SimSun",
430
+ EastAsia = "SimSun",
431
+ ComplexScript = "SimSun"
432
+ })
433
+ )
434
+ { LevelIndex = 1 },
435
+
436
+ // Level 2: 1. 2. 3.
437
+ new Level(
438
+ new StartNumberingValue { Val = 1 },
439
+ new NumberingFormat { Val = NumberFormatValues.Decimal },
440
+ new LevelText { Val = "%3." },
441
+ new LevelJustification { Val = LevelJustificationValues.Left },
442
+ new PreviousParagraphProperties(
443
+ new Indentation { Left = "1680", Hanging = "420" })
444
+ )
445
+ { LevelIndex = 2 },
446
+
447
+ // Level 3: (1) (2) (3)
448
+ new Level(
449
+ new StartNumberingValue { Val = 1 },
450
+ new NumberingFormat { Val = NumberFormatValues.Decimal },
451
+ new LevelText { Val = "(%4)" },
452
+ new LevelJustification { Val = LevelJustificationValues.Left },
453
+ new PreviousParagraphProperties(
454
+ new Indentation { Left = "2100", Hanging = "420" })
455
+ )
456
+ { LevelIndex = 3 }
457
+ )
458
+ {
459
+ AbstractNumberId = abstractNumId,
460
+ MultiLevelType = new MultiLevelType { Val = MultiLevelValues.Multilevel }
461
+ };
462
+
463
+ EnsureNumberingRoot(numPart);
464
+ numPart.Numbering.Append(abstractNum);
465
+ SetupNumberingInstance(numPart, numId, abstractNumId);
466
+
467
+ body.AppendChild(CreateListParagraph("总则", numId, level: 0));
468
+ body.AppendChild(CreateListParagraph("目的和依据", numId, level: 1));
469
+ body.AppendChild(CreateListParagraph("本办法适用于全体员工。", numId, level: 2));
470
+ body.AppendChild(CreateListParagraph("自发布之日起施行。", numId, level: 3));
471
+ body.AppendChild(CreateListParagraph("适用范围", numId, level: 1));
472
+ body.AppendChild(CreateListParagraph("职责与权限", numId, level: 0));
473
+ }
474
+
475
+ // ── 7. Restart Numbering ───────────────────────────────────────────
476
+
477
+ /// <summary>
478
+ /// Demonstrates how to restart a numbered list at 1 using LevelOverride
479
+ /// with StartOverride. This creates a new NumberingInstance that shares
480
+ /// the same AbstractNum but overrides the start value.
481
+ /// </summary>
482
+ /// <remarks>
483
+ /// Scenario: You have items 1-5 in one list, then want a separate list
484
+ /// that starts again at 1 with the same formatting. You need a new
485
+ /// NumberingInstance (new NumId) with LevelOverride.
486
+ /// </remarks>
487
+ public static void RestartNumbering(
488
+ NumberingDefinitionsPart numPart, Body body)
489
+ {
490
+ int abstractNumId = 6;
491
+ int numId1 = 7;
492
+ int numId2 = 8; // Second instance for restarted list
493
+
494
+ // Simple single-level numbered list
495
+ var levels = new Level[]
496
+ {
497
+ CreateNumberLevel(
498
+ levelIndex: 0,
499
+ format: NumberFormatValues.Decimal,
500
+ levelText: "%1.",
501
+ indentLeftDxa: 720,
502
+ hangingDxa: 360,
503
+ start: 1)
504
+ };
505
+
506
+ SetupAbstractNum(numPart, abstractNumId, levels);
507
+ SetupNumberingInstance(numPart, numId1, abstractNumId);
508
+
509
+ // First list: 1, 2, 3
510
+ body.AppendChild(CreateListParagraph("First list item 1", numId1, level: 0));
511
+ body.AppendChild(CreateListParagraph("First list item 2", numId1, level: 0));
512
+ body.AppendChild(CreateListParagraph("First list item 3", numId1, level: 0));
513
+
514
+ // Non-list paragraph between the lists
515
+ body.AppendChild(new Paragraph(
516
+ new Run(new Text("Some text between lists."))));
517
+
518
+ // Create a NEW NumberingInstance with LevelOverride to restart at 1.
519
+ // LevelOverride on a NumberingInstance overrides a specific level's
520
+ // start value WITHOUT creating a new AbstractNum.
521
+ var restartedInstance = new NumberingInstance(
522
+ new AbstractNumId { Val = abstractNumId },
523
+ // LevelOverride resets level 0 to start at 1
524
+ new LevelOverride(
525
+ new StartOverrideNumberingValue { Val = 1 }
526
+ )
527
+ { LevelIndex = 0 }
528
+ )
529
+ { NumberID = numId2 };
530
+
531
+ numPart.Numbering.Append(restartedInstance);
532
+
533
+ // Second list uses numId2: starts at 1 again
534
+ body.AppendChild(CreateListParagraph("Restarted item 1", numId2, level: 0));
535
+ body.AppendChild(CreateListParagraph("Restarted item 2", numId2, level: 0));
536
+ body.AppendChild(CreateListParagraph("Restarted item 3", numId2, level: 0));
537
+ }
538
+
539
+ // ── 8. Continue Numbering ──────────────────────────────────────────
540
+
541
+ /// <summary>
542
+ /// Continues numbering from a previous list by using the same NumId.
543
+ /// All paragraphs sharing a NumId form a single continuous sequence.
544
+ /// Inserting non-list paragraphs between them does NOT break the sequence.
545
+ /// </summary>
546
+ /// <param name="body">The Body to append paragraphs to.</param>
547
+ /// <param name="existingNumId">The NumId of the list to continue.</param>
548
+ public static void ContinueNumbering(Body body, int existingNumId)
549
+ {
550
+ // Simply use the SAME numId as the existing list.
551
+ // Word automatically continues the counter from wherever it left off.
552
+ // Even if there are non-list paragraphs in between, the numbering
553
+ // picks up seamlessly.
554
+
555
+ body.AppendChild(new Paragraph(
556
+ new Run(new Text("(Non-list paragraph — numbering continues after this.)"))));
557
+
558
+ // These will be numbered 4, 5 (assuming previous list ended at 3)
559
+ body.AppendChild(CreateListParagraph(
560
+ "Continued item", existingNumId, level: 0));
561
+ body.AppendChild(CreateListParagraph(
562
+ "Another continued item", existingNumId, level: 0));
563
+ }
564
+
565
+ // ── 9. Setup AbstractNum (Helper) ──────────────────────────────────
566
+
567
+ /// <summary>
568
+ /// Builds an AbstractNum from an array of Level definitions and appends
569
+ /// it to the Numbering root. AbstractNum defines the *format* of a list
570
+ /// (bullet characters, number format, indentation, fonts).
571
+ /// </summary>
572
+ /// <param name="numPart">The NumberingDefinitionsPart to append to.</param>
573
+ /// <param name="abstractNumId">Unique ID for this abstract definition.</param>
574
+ /// <param name="levels">Array of Level elements (one per nesting level, max 9).</param>
575
+ public static void SetupAbstractNum(
576
+ NumberingDefinitionsPart numPart, int abstractNumId, Level[] levels)
577
+ {
578
+ EnsureNumberingRoot(numPart);
579
+
580
+ var abstractNum = new AbstractNum
581
+ {
582
+ AbstractNumberId = abstractNumId,
583
+ // MultiLevelType:
584
+ // HybridMultilevel — most common; each level can have independent formatting
585
+ // Multilevel — true outline; sub-levels inherit parent context
586
+ // SingleLevel — only level 0 is used
587
+ MultiLevelType = new MultiLevelType
588
+ {
589
+ Val = levels.Length > 1
590
+ ? MultiLevelValues.HybridMultilevel
591
+ : MultiLevelValues.SingleLevel
592
+ }
593
+ };
594
+
595
+ foreach (Level level in levels)
596
+ {
597
+ abstractNum.Append(level.CloneNode(true));
598
+ }
599
+
600
+ // IMPORTANT: AbstractNum must be inserted BEFORE any NumberingInstance
601
+ // elements in the Numbering root. Find the right position.
602
+ NumberingInstance? firstNumInstance =
603
+ numPart.Numbering.GetFirstChild<NumberingInstance>();
604
+
605
+ if (firstNumInstance is not null)
606
+ {
607
+ numPart.Numbering.InsertBefore(abstractNum, firstNumInstance);
608
+ }
609
+ else
610
+ {
611
+ numPart.Numbering.Append(abstractNum);
612
+ }
613
+ }
614
+
615
+ // ── 10. Setup NumberingInstance (Helper) ────────────────────────────
616
+
617
+ /// <summary>
618
+ /// Creates a NumberingInstance (Num element) that references an AbstractNum.
619
+ /// The NumberingInstance is what paragraphs actually point to via NumId.
620
+ /// Multiple paragraphs with the same NumId form one continuous list.
621
+ /// </summary>
622
+ /// <param name="numPart">The NumberingDefinitionsPart to append to.</param>
623
+ /// <param name="numId">Unique instance ID (referenced by paragraphs).
624
+ /// Must be &gt;= 1; value 0 is reserved for "no numbering".</param>
625
+ /// <param name="abstractNumId">The AbstractNum this instance uses.</param>
626
+ public static void SetupNumberingInstance(
627
+ NumberingDefinitionsPart numPart, int numId, int abstractNumId)
628
+ {
629
+ EnsureNumberingRoot(numPart);
630
+
631
+ // NumberingInstance (w:num) links to AbstractNum via AbstractNumId child
632
+ var numInstance = new NumberingInstance(
633
+ new AbstractNumId { Val = abstractNumId })
634
+ {
635
+ // NumberID is the w:numId attribute; this is what paragraphs reference
636
+ NumberID = numId
637
+ };
638
+
639
+ // NumberingInstance MUST come after all AbstractNum elements
640
+ numPart.Numbering.Append(numInstance);
641
+ }
642
+
643
+ // ── 11. Apply Numbering to Paragraph (Helper) ──────────────────────
644
+
645
+ /// <summary>
646
+ /// Applies numbering to an existing paragraph by setting NumberingProperties
647
+ /// in the ParagraphProperties. This is the final link that makes a
648
+ /// paragraph display as a list item.
649
+ /// </summary>
650
+ /// <param name="para">The paragraph to make into a list item.</param>
651
+ /// <param name="numId">The NumberingInstance ID to use.</param>
652
+ /// <param name="level">The indentation level (0 = top level, max 8).</param>
653
+ public static void ApplyNumberingToParagraph(Paragraph para, int numId, int level)
654
+ {
655
+ // NumberingProperties contains:
656
+ // - NumberingLevelReference (w:ilvl) — which level (0-8)
657
+ // - NumberingId (w:numId) — which NumberingInstance to use
658
+ var numberingProperties = new NumberingProperties(
659
+ new NumberingLevelReference { Val = level },
660
+ new NumberingId { Val = numId });
661
+
662
+ // Ensure ParagraphProperties exists
663
+ ParagraphProperties pPr = para.GetFirstChild<ParagraphProperties>()
664
+ ?? para.PrependChild(new ParagraphProperties());
665
+
666
+ // Replace existing NumberingProperties if present
667
+ NumberingProperties? existing = pPr.GetFirstChild<NumberingProperties>();
668
+ if (existing is not null)
669
+ {
670
+ pPr.ReplaceChild(numberingProperties, existing);
671
+ }
672
+ else
673
+ {
674
+ // NumberingProperties should appear early in ParagraphProperties
675
+ // (after ParagraphStyleId if present)
676
+ ParagraphStyleId? styleId = pPr.GetFirstChild<ParagraphStyleId>();
677
+ if (styleId is not null)
678
+ {
679
+ pPr.InsertAfter(numberingProperties, styleId);
680
+ }
681
+ else
682
+ {
683
+ pPr.PrependChild(numberingProperties);
684
+ }
685
+ }
686
+ }
687
+
688
+ // ── Private Helper Methods ─────────────────────────────────────────
689
+
690
+ /// <summary>
691
+ /// Creates a bullet-type Level definition.
692
+ /// </summary>
693
+ private static Level CreateBulletLevel(
694
+ int levelIndex,
695
+ string bulletChar,
696
+ string font,
697
+ int indentLeftDxa,
698
+ int hangingDxa)
699
+ {
700
+ return new Level(
701
+ // Bullets don't increment, but StartNumberingValue is still required
702
+ new StartNumberingValue { Val = 1 },
703
+ // NumberFormatValues.Bullet tells Word this is a bullet, not a number
704
+ new NumberingFormat { Val = NumberFormatValues.Bullet },
705
+ // LevelText.Val is the actual bullet character
706
+ new LevelText { Val = bulletChar },
707
+ new LevelJustification { Val = LevelJustificationValues.Left },
708
+ // PreviousParagraphProperties controls indentation of the text
709
+ // (confusingly named; it's the paragraph indent for THIS level)
710
+ new PreviousParagraphProperties(
711
+ new Indentation
712
+ {
713
+ Left = indentLeftDxa.ToString(),
714
+ Hanging = hangingDxa.ToString()
715
+ }),
716
+ // NumberingSymbolRunProperties sets the font for the bullet character.
717
+ // Without this, the bullet renders in the paragraph's body font,
718
+ // which may not contain the glyph (e.g., Symbol characters).
719
+ new NumberingSymbolRunProperties(
720
+ new RunFonts
721
+ {
722
+ Ascii = font,
723
+ HighAnsi = font,
724
+ Hint = FontTypeHintValues.Default
725
+ })
726
+ )
727
+ { LevelIndex = levelIndex };
728
+ }
729
+
730
+ /// <summary>
731
+ /// Creates a number-type Level definition.
732
+ /// </summary>
733
+ private static Level CreateNumberLevel(
734
+ int levelIndex,
735
+ NumberFormatValues format,
736
+ string levelText,
737
+ int indentLeftDxa,
738
+ int hangingDxa,
739
+ int start)
740
+ {
741
+ return new Level(
742
+ new StartNumberingValue { Val = start },
743
+ new NumberingFormat { Val = format },
744
+ new LevelText { Val = levelText },
745
+ new LevelJustification { Val = LevelJustificationValues.Left },
746
+ new PreviousParagraphProperties(
747
+ new Indentation
748
+ {
749
+ Left = indentLeftDxa.ToString(),
750
+ Hanging = hangingDxa.ToString()
751
+ })
752
+ )
753
+ { LevelIndex = levelIndex };
754
+ }
755
+
756
+ /// <summary>
757
+ /// Creates a paragraph with text and numbering properties applied.
758
+ /// </summary>
759
+ private static Paragraph CreateListParagraph(string text, int numId, int level)
760
+ {
761
+ var para = new Paragraph(
762
+ new ParagraphProperties(
763
+ new NumberingProperties(
764
+ new NumberingLevelReference { Val = level },
765
+ new NumberingId { Val = numId })),
766
+ new Run(new Text(text)));
767
+ return para;
768
+ }
769
+
770
+ /// <summary>
771
+ /// Ensures the Numbering root element exists on the NumberingDefinitionsPart.
772
+ /// </summary>
773
+ private static void EnsureNumberingRoot(NumberingDefinitionsPart numPart)
774
+ {
775
+ if (numPart.Numbering is null)
776
+ {
777
+ numPart.Numbering = new Numbering();
778
+ }
779
+ }
780
+
781
+ /// <summary>
782
+ /// Links a named style to a numbering definition by adding NumberingProperties
783
+ /// to the style's ParagraphProperties.
784
+ /// </summary>
785
+ private static void LinkStyleToNumbering(
786
+ Styles styles, string styleId, int numId, int level)
787
+ {
788
+ // Find existing style or create it
789
+ Style? style = styles.Elements<Style>()
790
+ .FirstOrDefault(s => s.StyleId?.Value == styleId);
791
+
792
+ if (style is null)
793
+ {
794
+ style = new Style
795
+ {
796
+ Type = StyleValues.Paragraph,
797
+ StyleId = styleId,
798
+ StyleName = new StyleName { Val = styleId }
799
+ };
800
+ styles.Append(style);
801
+ }
802
+
803
+ // Ensure StyleParagraphProperties exists
804
+ StyleParagraphProperties? spPr = style.GetFirstChild<StyleParagraphProperties>();
805
+ if (spPr is null)
806
+ {
807
+ spPr = new StyleParagraphProperties();
808
+ style.Append(spPr);
809
+ }
810
+
811
+ // Set NumberingProperties on the style
812
+ NumberingProperties? existingNumPr = spPr.GetFirstChild<NumberingProperties>();
813
+ var newNumPr = new NumberingProperties(
814
+ new NumberingLevelReference { Val = level },
815
+ new NumberingId { Val = numId });
816
+
817
+ if (existingNumPr is not null)
818
+ {
819
+ spPr.ReplaceChild(newNumPr, existingNumPr);
820
+ }
821
+ else
822
+ {
823
+ spPr.Append(newNumPr);
824
+ }
825
+ }
826
+ }