docxmlater 10.0.2 → 10.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/constants/legacyCompatFlags.d.ts.map +1 -1
- package/dist/constants/legacyCompatFlags.js.map +1 -1
- package/dist/constants/limits.d.ts +0 -27
- package/dist/constants/limits.d.ts.map +1 -1
- package/dist/constants/limits.js +13 -13
- package/dist/constants/limits.js.map +1 -1
- package/dist/core/Document.d.ts +23 -19
- package/dist/core/Document.d.ts.map +1 -1
- package/dist/core/Document.js +197 -63
- package/dist/core/Document.js.map +1 -1
- package/dist/core/DocumentContent.d.ts.map +1 -1
- package/dist/core/DocumentContent.js.map +1 -1
- package/dist/core/DocumentGenerator.d.ts.map +1 -1
- package/dist/core/DocumentGenerator.js +59 -24
- package/dist/core/DocumentGenerator.js.map +1 -1
- package/dist/core/DocumentIdManager.d.ts.map +1 -1
- package/dist/core/DocumentIdManager.js.map +1 -1
- package/dist/core/DocumentParser.d.ts +6 -6
- package/dist/core/DocumentParser.d.ts.map +1 -1
- package/dist/core/DocumentParser.js +60 -54
- package/dist/core/DocumentParser.js.map +1 -1
- package/dist/core/DocumentValidator.d.ts.map +1 -1
- package/dist/core/DocumentValidator.js.map +1 -1
- package/dist/core/Relationship.d.ts.map +1 -1
- package/dist/core/Relationship.js +1 -1
- package/dist/core/Relationship.js.map +1 -1
- package/dist/core/RelationshipManager.js +3 -3
- package/dist/core/RelationshipManager.js.map +1 -1
- package/dist/elements/AlternateContent.js.map +1 -1
- package/dist/elements/Bookmark.d.ts.map +1 -1
- package/dist/elements/Bookmark.js.map +1 -1
- package/dist/elements/BookmarkManager.d.ts.map +1 -1
- package/dist/elements/BookmarkManager.js.map +1 -1
- package/dist/elements/Comment.js +1 -1
- package/dist/elements/Comment.js.map +1 -1
- package/dist/elements/CommentManager.d.ts.map +1 -1
- package/dist/elements/CommentManager.js +8 -2
- package/dist/elements/CommentManager.js.map +1 -1
- package/dist/elements/CommonTypes.d.ts.map +1 -1
- package/dist/elements/CommonTypes.js +1 -2
- package/dist/elements/CommonTypes.js.map +1 -1
- package/dist/elements/CustomXml.js.map +1 -1
- package/dist/elements/Endnote.d.ts.map +1 -1
- package/dist/elements/Endnote.js.map +1 -1
- package/dist/elements/EndnoteManager.d.ts.map +1 -1
- package/dist/elements/EndnoteManager.js.map +1 -1
- package/dist/elements/Field.d.ts.map +1 -1
- package/dist/elements/Field.js +31 -28
- package/dist/elements/Field.js.map +1 -1
- package/dist/elements/FieldHelpers.d.ts.map +1 -1
- package/dist/elements/FieldHelpers.js +6 -6
- package/dist/elements/FieldHelpers.js.map +1 -1
- package/dist/elements/FontManager.d.ts.map +1 -1
- package/dist/elements/FontManager.js.map +1 -1
- package/dist/elements/Footer.js.map +1 -1
- package/dist/elements/Footnote.d.ts.map +1 -1
- package/dist/elements/Footnote.js.map +1 -1
- package/dist/elements/FootnoteManager.d.ts.map +1 -1
- package/dist/elements/FootnoteManager.js.map +1 -1
- package/dist/elements/Header.js.map +1 -1
- package/dist/elements/HeaderFooterManager.js.map +1 -1
- package/dist/elements/Hyperlink.d.ts.map +1 -1
- package/dist/elements/Hyperlink.js +5 -5
- package/dist/elements/Hyperlink.js.map +1 -1
- package/dist/elements/Image.d.ts +2 -2
- package/dist/elements/Image.d.ts.map +1 -1
- package/dist/elements/Image.js +21 -5
- package/dist/elements/Image.js.map +1 -1
- package/dist/elements/ImageManager.d.ts.map +1 -1
- package/dist/elements/ImageManager.js +2 -2
- package/dist/elements/ImageManager.js.map +1 -1
- package/dist/elements/ImageRun.js.map +1 -1
- package/dist/elements/MathElement.js.map +1 -1
- package/dist/elements/Paragraph.d.ts.map +1 -1
- package/dist/elements/Paragraph.js +128 -117
- package/dist/elements/Paragraph.js.map +1 -1
- package/dist/elements/PreservedElement.js.map +1 -1
- package/dist/elements/PropertyChangeTypes.js.map +1 -1
- package/dist/elements/RangeMarker.js.map +1 -1
- package/dist/elements/Revision.d.ts +1 -0
- package/dist/elements/Revision.d.ts.map +1 -1
- package/dist/elements/Revision.js +44 -5
- package/dist/elements/Revision.js.map +1 -1
- package/dist/elements/RevisionContent.js.map +1 -1
- package/dist/elements/RevisionManager.d.ts.map +1 -1
- package/dist/elements/RevisionManager.js.map +1 -1
- package/dist/elements/Run.d.ts.map +1 -1
- package/dist/elements/Run.js +1 -3
- package/dist/elements/Run.js.map +1 -1
- package/dist/elements/Section.d.ts.map +1 -1
- package/dist/elements/Section.js +127 -118
- package/dist/elements/Section.js.map +1 -1
- package/dist/elements/Shape.d.ts.map +1 -1
- package/dist/elements/Shape.js +21 -0
- package/dist/elements/Shape.js.map +1 -1
- package/dist/elements/StructuredDocumentTag.d.ts.map +1 -1
- package/dist/elements/StructuredDocumentTag.js +20 -8
- package/dist/elements/StructuredDocumentTag.js.map +1 -1
- package/dist/elements/Table.d.ts +2 -2
- package/dist/elements/Table.d.ts.map +1 -1
- package/dist/elements/Table.js +29 -35
- package/dist/elements/Table.js.map +1 -1
- package/dist/elements/TableCell.d.ts +2 -2
- package/dist/elements/TableCell.d.ts.map +1 -1
- package/dist/elements/TableCell.js +63 -67
- package/dist/elements/TableCell.js.map +1 -1
- package/dist/elements/TableGridChange.js.map +1 -1
- package/dist/elements/TableOfContents.d.ts +6 -6
- package/dist/elements/TableOfContents.d.ts.map +1 -1
- package/dist/elements/TableOfContents.js.map +1 -1
- package/dist/elements/TableOfContentsElement.js.map +1 -1
- package/dist/elements/TableRow.d.ts.map +1 -1
- package/dist/elements/TableRow.js +65 -47
- package/dist/elements/TableRow.js.map +1 -1
- package/dist/elements/TextBox.d.ts.map +1 -1
- package/dist/elements/TextBox.js +1 -1
- package/dist/elements/TextBox.js.map +1 -1
- package/dist/formatting/AbstractNumbering.d.ts +1 -1
- package/dist/formatting/AbstractNumbering.d.ts.map +1 -1
- package/dist/formatting/AbstractNumbering.js +11 -11
- package/dist/formatting/AbstractNumbering.js.map +1 -1
- package/dist/formatting/NumberingInstance.d.ts.map +1 -1
- package/dist/formatting/NumberingInstance.js +4 -4
- package/dist/formatting/NumberingInstance.js.map +1 -1
- package/dist/formatting/NumberingLevel.d.ts.map +1 -1
- package/dist/formatting/NumberingLevel.js +26 -26
- package/dist/formatting/NumberingLevel.js.map +1 -1
- package/dist/formatting/NumberingManager.d.ts +1 -1
- package/dist/formatting/NumberingManager.d.ts.map +1 -1
- package/dist/formatting/NumberingManager.js.map +1 -1
- package/dist/formatting/Style.d.ts.map +1 -1
- package/dist/formatting/Style.js +87 -95
- package/dist/formatting/Style.js.map +1 -1
- package/dist/formatting/StylesManager.d.ts +3 -3
- package/dist/formatting/StylesManager.d.ts.map +1 -1
- package/dist/formatting/StylesManager.js.map +1 -1
- package/dist/helpers/CleanupHelper.js.map +1 -1
- package/dist/images/ImageOptimizer.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/managers/DrawingManager.d.ts.map +1 -1
- package/dist/managers/DrawingManager.js.map +1 -1
- package/dist/tracking/DocumentTrackingContext.js.map +1 -1
- package/dist/tracking/TrackingContext.js.map +1 -1
- package/dist/types/compatibility-types.js.map +1 -1
- package/dist/types/formatting.js.map +1 -1
- package/dist/types/list-types.d.ts +4 -4
- package/dist/types/list-types.d.ts.map +1 -1
- package/dist/types/list-types.js.map +1 -1
- package/dist/types/settings-types.js.map +1 -1
- package/dist/types/styleConfig.js.map +1 -1
- package/dist/utils/ChangelogGenerator.d.ts.map +1 -1
- package/dist/utils/ChangelogGenerator.js.map +1 -1
- package/dist/utils/CompatibilityUpgrader.d.ts.map +1 -1
- package/dist/utils/CompatibilityUpgrader.js +7 -7
- package/dist/utils/CompatibilityUpgrader.js.map +1 -1
- package/dist/utils/InMemoryRevisionAcceptor.js +1 -1
- package/dist/utils/InMemoryRevisionAcceptor.js.map +1 -1
- package/dist/utils/MoveOperationHelper.js.map +1 -1
- package/dist/utils/RevisionAwareProcessor.js.map +1 -1
- package/dist/utils/RevisionWalker.js.map +1 -1
- package/dist/utils/SelectiveRevisionAcceptor.js.map +1 -1
- package/dist/utils/ShadingResolver.js +1 -1
- package/dist/utils/ShadingResolver.js.map +1 -1
- package/dist/utils/acceptRevisions.d.ts +0 -28
- package/dist/utils/acceptRevisions.d.ts.map +1 -1
- package/dist/utils/acceptRevisions.js +5 -7
- package/dist/utils/acceptRevisions.js.map +1 -1
- package/dist/utils/cnfStyleDecoder.js +1 -1
- package/dist/utils/cnfStyleDecoder.js.map +1 -1
- package/dist/utils/corruptionDetection.js.map +1 -1
- package/dist/utils/dateFormatting.js.map +1 -1
- package/dist/utils/deepClone.d.ts +0 -1
- package/dist/utils/deepClone.d.ts.map +1 -1
- package/dist/utils/deepClone.js +0 -7
- package/dist/utils/deepClone.js.map +1 -1
- package/dist/utils/diagnostics.d.ts +2 -2
- package/dist/utils/diagnostics.d.ts.map +1 -1
- package/dist/utils/diagnostics.js.map +1 -1
- package/dist/utils/errorHandling.js.map +1 -1
- package/dist/utils/formatting.js.map +1 -1
- package/dist/utils/list-detection.d.ts +2 -2
- package/dist/utils/list-detection.d.ts.map +1 -1
- package/dist/utils/list-detection.js +3 -3
- package/dist/utils/list-detection.js.map +1 -1
- package/dist/utils/logger.d.ts +2 -4
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +0 -2
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/parsingHelpers.js.map +1 -1
- package/dist/utils/stripTrackedChanges.d.ts +0 -19
- package/dist/utils/stripTrackedChanges.d.ts.map +1 -1
- package/dist/utils/stripTrackedChanges.js +0 -2
- package/dist/utils/stripTrackedChanges.js.map +1 -1
- package/dist/utils/textDiff.js.map +1 -1
- package/dist/utils/units.js.map +1 -1
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js.map +1 -1
- package/dist/utils/xmlSanitization.js.map +1 -1
- package/dist/validation/RevisionAutoFixer.js.map +1 -1
- package/dist/validation/RevisionValidator.js.map +1 -1
- package/dist/validation/ValidationRules.js.map +1 -1
- package/dist/validation/index.js.map +1 -1
- package/dist/xml/XMLBuilder.d.ts.map +1 -1
- package/dist/xml/XMLBuilder.js +10 -0
- package/dist/xml/XMLBuilder.js.map +1 -1
- package/dist/xml/XMLParser.d.ts.map +1 -1
- package/dist/xml/XMLParser.js +4 -5
- package/dist/xml/XMLParser.js.map +1 -1
- package/dist/zip/ZipHandler.js.map +1 -1
- package/dist/zip/ZipReader.js.map +1 -1
- package/dist/zip/ZipWriter.js.map +1 -1
- package/dist/zip/errors.js.map +1 -1
- package/dist/zip/types.js.map +1 -1
- package/package.json +34 -4
- package/src/__tests__/helper-methods.test.ts +512 -0
- package/src/constants/legacyCompatFlags.ts +138 -0
- package/src/constants/limits.ts +50 -0
- package/src/core/CLAUDE.md +109 -0
- package/src/core/Document.ts +15569 -0
- package/src/core/DocumentContent.ts +467 -0
- package/src/core/DocumentGenerator.ts +1104 -0
- package/src/core/DocumentIdManager.ts +158 -0
- package/src/core/DocumentParser.ts +10107 -0
- package/src/core/DocumentValidator.ts +372 -0
- package/src/core/Relationship.ts +367 -0
- package/src/core/RelationshipManager.ts +428 -0
- package/src/elements/AlternateContent.ts +42 -0
- package/src/elements/Bookmark.ts +210 -0
- package/src/elements/BookmarkManager.ts +250 -0
- package/src/elements/CLAUDE.md +126 -0
- package/src/elements/Comment.ts +359 -0
- package/src/elements/CommentManager.ts +502 -0
- package/src/elements/CommonTypes.ts +549 -0
- package/src/elements/CustomXml.ts +36 -0
- package/src/elements/Endnote.ts +217 -0
- package/src/elements/EndnoteManager.ts +249 -0
- package/src/elements/Field.ts +1233 -0
- package/src/elements/FieldHelpers.ts +333 -0
- package/src/elements/FontManager.ts +339 -0
- package/src/elements/Footer.ts +269 -0
- package/src/elements/Footnote.ts +217 -0
- package/src/elements/FootnoteManager.ts +249 -0
- package/src/elements/Header.ts +269 -0
- package/src/elements/HeaderFooterManager.ts +219 -0
- package/src/elements/Hyperlink.ts +1146 -0
- package/src/elements/Image.ts +1756 -0
- package/src/elements/ImageManager.ts +432 -0
- package/src/elements/ImageRun.ts +59 -0
- package/src/elements/MathElement.ts +65 -0
- package/src/elements/Paragraph.ts +4227 -0
- package/src/elements/PreservedElement.ts +53 -0
- package/src/elements/PropertyChangeTypes.ts +442 -0
- package/src/elements/RangeMarker.ts +400 -0
- package/src/elements/Revision.ts +1217 -0
- package/src/elements/RevisionContent.ts +73 -0
- package/src/elements/RevisionManager.ts +1070 -0
- package/src/elements/Run.ts +3068 -0
- package/src/elements/Section.ts +1421 -0
- package/src/elements/Shape.ts +873 -0
- package/src/elements/StructuredDocumentTag.ts +978 -0
- package/src/elements/Table.ts +2524 -0
- package/src/elements/TableCell.ts +1586 -0
- package/src/elements/TableGridChange.ts +151 -0
- package/src/elements/TableOfContents.ts +691 -0
- package/src/elements/TableOfContentsElement.ts +89 -0
- package/src/elements/TableRow.ts +906 -0
- package/src/elements/TextBox.ts +768 -0
- package/src/formatting/AbstractNumbering.ts +548 -0
- package/src/formatting/CLAUDE.md +74 -0
- package/src/formatting/NumberingInstance.ts +212 -0
- package/src/formatting/NumberingLevel.ts +1006 -0
- package/src/formatting/NumberingManager.ts +827 -0
- package/src/formatting/Style.ts +1833 -0
- package/src/formatting/StylesManager.ts +1005 -0
- package/src/helpers/CleanupHelper.ts +524 -0
- package/src/images/ImageOptimizer.ts +274 -0
- package/src/index.ts +554 -0
- package/src/managers/CLAUDE.md +47 -0
- package/src/managers/DrawingManager.ts +319 -0
- package/src/tracking/DocumentTrackingContext.ts +643 -0
- package/src/tracking/TrackingContext.ts +173 -0
- package/src/types/compatibility-types.ts +49 -0
- package/src/types/formatting.ts +210 -0
- package/src/types/list-types.ts +152 -0
- package/src/types/settings-types.ts +59 -0
- package/src/types/styleConfig.ts +189 -0
- package/src/utils/CLAUDE.md +153 -0
- package/src/utils/ChangelogGenerator.ts +1581 -0
- package/src/utils/CompatibilityUpgrader.ts +237 -0
- package/src/utils/InMemoryRevisionAcceptor.ts +668 -0
- package/src/utils/MoveOperationHelper.ts +238 -0
- package/src/utils/RevisionAwareProcessor.ts +526 -0
- package/src/utils/RevisionWalker.ts +457 -0
- package/src/utils/SelectiveRevisionAcceptor.ts +613 -0
- package/src/utils/ShadingResolver.ts +107 -0
- package/src/utils/acceptRevisions.ts +714 -0
- package/src/utils/cnfStyleDecoder.ts +217 -0
- package/src/utils/corruptionDetection.ts +345 -0
- package/src/utils/dateFormatting.ts +20 -0
- package/src/utils/deepClone.ts +78 -0
- package/src/utils/diagnostics.ts +129 -0
- package/src/utils/errorHandling.ts +80 -0
- package/src/utils/formatting.ts +213 -0
- package/src/utils/list-detection.ts +274 -0
- package/src/utils/logger.ts +404 -0
- package/src/utils/parsingHelpers.ts +190 -0
- package/src/utils/stripTrackedChanges.ts +353 -0
- package/src/utils/textDiff.ts +100 -0
- package/src/utils/units.ts +421 -0
- package/src/utils/validation.ts +542 -0
- package/src/utils/xmlSanitization.ts +182 -0
- package/src/validation/RevisionAutoFixer.ts +542 -0
- package/src/validation/RevisionValidator.ts +460 -0
- package/src/validation/ValidationRules.ts +338 -0
- package/src/validation/index.ts +30 -0
- package/src/xml/CLAUDE.md +65 -0
- package/src/xml/XMLBuilder.ts +871 -0
- package/src/xml/XMLParser.ts +919 -0
- package/src/zip/CLAUDE.md +55 -0
- package/src/zip/ZipHandler.ts +637 -0
- package/src/zip/ZipReader.ts +299 -0
- package/src/zip/ZipWriter.ts +390 -0
- package/src/zip/errors.ts +69 -0
- package/src/zip/types.ts +116 -0
- package/dist/core/ListNormalizer.d.ts +0 -23
- package/dist/core/ListNormalizer.d.ts.map +0 -1
- package/dist/core/ListNormalizer.js +0 -624
- package/dist/core/ListNormalizer.js.map +0 -1
- package/dist/images/index.d.ts +0 -2
- package/dist/images/index.d.ts.map +0 -1
- package/dist/images/index.js +0 -8
- package/dist/images/index.js.map +0 -1
- package/dist/ms-doc/cfb/CFBReader.d.ts +0 -35
- package/dist/ms-doc/cfb/CFBReader.d.ts.map +0 -1
- package/dist/ms-doc/cfb/CFBReader.js +0 -360
- package/dist/ms-doc/cfb/CFBReader.js.map +0 -1
- package/dist/ms-doc/converter/DocToDocxConverter.d.ts +0 -55
- package/dist/ms-doc/converter/DocToDocxConverter.d.ts.map +0 -1
- package/dist/ms-doc/converter/DocToDocxConverter.js +0 -324
- package/dist/ms-doc/converter/DocToDocxConverter.js.map +0 -1
- package/dist/ms-doc/fib/FIB.d.ts +0 -18
- package/dist/ms-doc/fib/FIB.d.ts.map +0 -1
- package/dist/ms-doc/fib/FIB.js +0 -342
- package/dist/ms-doc/fib/FIB.js.map +0 -1
- package/dist/ms-doc/fields/FieldParser.d.ts +0 -31
- package/dist/ms-doc/fields/FieldParser.d.ts.map +0 -1
- package/dist/ms-doc/fields/FieldParser.js +0 -266
- package/dist/ms-doc/fields/FieldParser.js.map +0 -1
- package/dist/ms-doc/images/PictureExtractor.d.ts +0 -22
- package/dist/ms-doc/images/PictureExtractor.d.ts.map +0 -1
- package/dist/ms-doc/images/PictureExtractor.js +0 -233
- package/dist/ms-doc/images/PictureExtractor.js.map +0 -1
- package/dist/ms-doc/index.d.ts +0 -20
- package/dist/ms-doc/index.d.ts.map +0 -1
- package/dist/ms-doc/index.js +0 -59
- package/dist/ms-doc/index.js.map +0 -1
- package/dist/ms-doc/properties/SPRM.d.ts +0 -210
- package/dist/ms-doc/properties/SPRM.d.ts.map +0 -1
- package/dist/ms-doc/properties/SPRM.js +0 -633
- package/dist/ms-doc/properties/SPRM.js.map +0 -1
- package/dist/ms-doc/sections/SectionParser.d.ts +0 -25
- package/dist/ms-doc/sections/SectionParser.d.ts.map +0 -1
- package/dist/ms-doc/sections/SectionParser.js +0 -214
- package/dist/ms-doc/sections/SectionParser.js.map +0 -1
- package/dist/ms-doc/styles/StyleSheet.d.ts +0 -23
- package/dist/ms-doc/styles/StyleSheet.d.ts.map +0 -1
- package/dist/ms-doc/styles/StyleSheet.js +0 -268
- package/dist/ms-doc/styles/StyleSheet.js.map +0 -1
- package/dist/ms-doc/subdocuments/SubdocumentParser.d.ts +0 -61
- package/dist/ms-doc/subdocuments/SubdocumentParser.d.ts.map +0 -1
- package/dist/ms-doc/subdocuments/SubdocumentParser.js +0 -208
- package/dist/ms-doc/subdocuments/SubdocumentParser.js.map +0 -1
- package/dist/ms-doc/tables/TableParser.d.ts +0 -29
- package/dist/ms-doc/tables/TableParser.d.ts.map +0 -1
- package/dist/ms-doc/tables/TableParser.js +0 -176
- package/dist/ms-doc/tables/TableParser.js.map +0 -1
- package/dist/ms-doc/text/PieceTable.d.ts +0 -21
- package/dist/ms-doc/text/PieceTable.d.ts.map +0 -1
- package/dist/ms-doc/text/PieceTable.js +0 -171
- package/dist/ms-doc/text/PieceTable.js.map +0 -1
- package/dist/ms-doc/types/Constants.d.ts +0 -99
- package/dist/ms-doc/types/Constants.d.ts.map +0 -1
- package/dist/ms-doc/types/Constants.js +0 -102
- package/dist/ms-doc/types/Constants.js.map +0 -1
- package/dist/ms-doc/types/DocTypes.d.ts +0 -368
- package/dist/ms-doc/types/DocTypes.d.ts.map +0 -1
- package/dist/ms-doc/types/DocTypes.js +0 -3
- package/dist/ms-doc/types/DocTypes.js.map +0 -1
- package/dist/tracking/index.d.ts +0 -3
- package/dist/tracking/index.d.ts.map +0 -1
- package/dist/tracking/index.js +0 -6
- package/dist/tracking/index.js.map +0 -1
|
@@ -0,0 +1,1833 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Style - Represents a style definition in a Word document
|
|
3
|
+
* Supports paragraph, character, table, and numbering styles
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { XMLBuilder, XMLElement } from "../xml/XMLBuilder";
|
|
7
|
+
import { ParagraphFormatting } from "../elements/Paragraph";
|
|
8
|
+
import { RunFormatting } from "../elements/Run";
|
|
9
|
+
import { ShadingConfig, ShadingPattern, buildShadingAttributes } from "../elements/CommonTypes";
|
|
10
|
+
import { Heading2TableOptions } from "../types/styleConfig";
|
|
11
|
+
import { deepClone } from "../utils/deepClone";
|
|
12
|
+
import { pointsToHalfPoints } from "../utils/units";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Style type
|
|
16
|
+
*/
|
|
17
|
+
export type StyleType = "paragraph" | "character" | "table" | "numbering";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Table alignment
|
|
21
|
+
*/
|
|
22
|
+
export type TableAlignment = "left" | "center" | "right";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Border properties
|
|
26
|
+
*/
|
|
27
|
+
export interface BorderProperties {
|
|
28
|
+
/** Border style */
|
|
29
|
+
style?: "none" | "single" | "double" | "dashed" | "dotted" | "thick";
|
|
30
|
+
/** Border size in eighths of a point */
|
|
31
|
+
size?: number;
|
|
32
|
+
/** Border spacing/padding in points */
|
|
33
|
+
space?: number;
|
|
34
|
+
/** Border color (hex without #) */
|
|
35
|
+
color?: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Table borders (6 possible borders)
|
|
40
|
+
*/
|
|
41
|
+
export interface TableBorders {
|
|
42
|
+
top?: BorderProperties;
|
|
43
|
+
bottom?: BorderProperties;
|
|
44
|
+
left?: BorderProperties;
|
|
45
|
+
right?: BorderProperties;
|
|
46
|
+
/** Inside horizontal borders */
|
|
47
|
+
insideH?: BorderProperties;
|
|
48
|
+
/** Inside vertical borders */
|
|
49
|
+
insideV?: BorderProperties;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Cell borders (8 possible borders, includes diagonals)
|
|
54
|
+
*/
|
|
55
|
+
export interface CellBorders extends TableBorders {
|
|
56
|
+
/** Top-left to bottom-right diagonal */
|
|
57
|
+
tl2br?: BorderProperties;
|
|
58
|
+
/** Top-right to bottom-left diagonal */
|
|
59
|
+
tr2bl?: BorderProperties;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Shading properties
|
|
64
|
+
* @see ShadingConfig in CommonTypes.ts for the canonical definition
|
|
65
|
+
*/
|
|
66
|
+
export type ShadingProperties = ShadingConfig;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Cell margins
|
|
70
|
+
*/
|
|
71
|
+
export interface CellMargins {
|
|
72
|
+
/** Top margin in twips */
|
|
73
|
+
top?: number;
|
|
74
|
+
/** Bottom margin in twips */
|
|
75
|
+
bottom?: number;
|
|
76
|
+
/** Left margin in twips */
|
|
77
|
+
left?: number;
|
|
78
|
+
/** Right margin in twips */
|
|
79
|
+
right?: number;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Table-level formatting properties (tblPr)
|
|
84
|
+
*/
|
|
85
|
+
export interface TableStyleFormatting {
|
|
86
|
+
/** Table indentation from left margin in twips */
|
|
87
|
+
indent?: number;
|
|
88
|
+
/** Default cell spacing in twips */
|
|
89
|
+
cellSpacing?: number;
|
|
90
|
+
/** Table borders */
|
|
91
|
+
borders?: TableBorders;
|
|
92
|
+
/** Default cell margins */
|
|
93
|
+
cellMargins?: CellMargins;
|
|
94
|
+
/** Table background shading */
|
|
95
|
+
shading?: ShadingProperties;
|
|
96
|
+
/** Table alignment */
|
|
97
|
+
alignment?: TableAlignment;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Table cell formatting properties (tcPr)
|
|
102
|
+
*/
|
|
103
|
+
export interface TableCellStyleFormatting {
|
|
104
|
+
/** Cell borders (8 possible borders) */
|
|
105
|
+
borders?: CellBorders;
|
|
106
|
+
/** Cell background shading */
|
|
107
|
+
shading?: ShadingProperties;
|
|
108
|
+
/** Cell-specific margins */
|
|
109
|
+
margins?: CellMargins;
|
|
110
|
+
/** Vertical alignment in cell */
|
|
111
|
+
verticalAlignment?: "top" | "center" | "bottom";
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Table row formatting properties (trPr)
|
|
116
|
+
*/
|
|
117
|
+
export interface TableRowStyleFormatting {
|
|
118
|
+
/** Prevent row from splitting across pages */
|
|
119
|
+
cantSplit?: boolean;
|
|
120
|
+
/** Mark row as header row */
|
|
121
|
+
isHeader?: boolean;
|
|
122
|
+
/** Row height in twips */
|
|
123
|
+
height?: number;
|
|
124
|
+
/** Row height rule */
|
|
125
|
+
heightRule?: "auto" | "exact" | "atLeast";
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Conditional formatting type for table regions
|
|
130
|
+
*/
|
|
131
|
+
export type ConditionalFormattingType =
|
|
132
|
+
| "wholeTable" // Entire table
|
|
133
|
+
| "firstRow" // First row
|
|
134
|
+
| "lastRow" // Last row
|
|
135
|
+
| "firstCol" // First column
|
|
136
|
+
| "lastCol" // Last column
|
|
137
|
+
| "band1Vert" // Odd column banding
|
|
138
|
+
| "band2Vert" // Even column banding
|
|
139
|
+
| "band1Horz" // Odd row banding
|
|
140
|
+
| "band2Horz" // Even row banding
|
|
141
|
+
| "nwCell" // Northwest (top-left) corner cell
|
|
142
|
+
| "neCell" // Northeast (top-right) corner cell
|
|
143
|
+
| "swCell" // Southwest (bottom-left) corner cell
|
|
144
|
+
| "seCell"; // Southeast (bottom-right) corner cell
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Conditional table formatting for a specific region
|
|
148
|
+
*/
|
|
149
|
+
export interface ConditionalTableFormatting {
|
|
150
|
+
/** Region type */
|
|
151
|
+
type: ConditionalFormattingType;
|
|
152
|
+
/** Paragraph formatting for this region */
|
|
153
|
+
paragraphFormatting?: ParagraphFormatting;
|
|
154
|
+
/** Run formatting for this region */
|
|
155
|
+
runFormatting?: RunFormatting;
|
|
156
|
+
/** Table formatting for this region */
|
|
157
|
+
tableFormatting?: TableStyleFormatting;
|
|
158
|
+
/** Cell formatting for this region */
|
|
159
|
+
cellFormatting?: TableCellStyleFormatting;
|
|
160
|
+
/** Row formatting for this region */
|
|
161
|
+
rowFormatting?: TableRowStyleFormatting;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Table style properties (Phase 5.1)
|
|
166
|
+
*/
|
|
167
|
+
export interface TableStyleProperties {
|
|
168
|
+
/** Table-level formatting */
|
|
169
|
+
table?: TableStyleFormatting;
|
|
170
|
+
/** Default cell formatting */
|
|
171
|
+
cell?: TableCellStyleFormatting;
|
|
172
|
+
/** Default row formatting */
|
|
173
|
+
row?: TableRowStyleFormatting;
|
|
174
|
+
/** Rows per band for row banding (default 1) */
|
|
175
|
+
rowBandSize?: number;
|
|
176
|
+
/** Columns per band for column banding (default 1) */
|
|
177
|
+
colBandSize?: number;
|
|
178
|
+
/** Conditional formatting for specific table regions */
|
|
179
|
+
conditionalFormatting?: ConditionalTableFormatting[];
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Style properties
|
|
184
|
+
*/
|
|
185
|
+
export interface StyleProperties {
|
|
186
|
+
/** Unique style identifier */
|
|
187
|
+
styleId: string;
|
|
188
|
+
/** Display name */
|
|
189
|
+
name: string;
|
|
190
|
+
/** Style type */
|
|
191
|
+
type: StyleType;
|
|
192
|
+
/** Parent style ID for inheritance */
|
|
193
|
+
basedOn?: string;
|
|
194
|
+
/** Next style ID (auto-next paragraph style) */
|
|
195
|
+
next?: string;
|
|
196
|
+
/** Whether this is a default style */
|
|
197
|
+
isDefault?: boolean;
|
|
198
|
+
/** Whether this is a custom style */
|
|
199
|
+
customStyle?: boolean;
|
|
200
|
+
/** Paragraph formatting (for paragraph and table styles) */
|
|
201
|
+
paragraphFormatting?: ParagraphFormatting;
|
|
202
|
+
/** Numbering properties for styles that inherit list formatting */
|
|
203
|
+
numPr?: {
|
|
204
|
+
numId?: number;
|
|
205
|
+
ilvl?: number;
|
|
206
|
+
};
|
|
207
|
+
/** Run formatting (for character and paragraph styles) */
|
|
208
|
+
runFormatting?: RunFormatting;
|
|
209
|
+
/** Table style properties (for table styles only - Phase 5.1) */
|
|
210
|
+
tableStyle?: TableStyleProperties;
|
|
211
|
+
|
|
212
|
+
// Style Gallery Metadata (Phase 5.3)
|
|
213
|
+
/** Quick style - show in style gallery */
|
|
214
|
+
qFormat?: boolean;
|
|
215
|
+
/** UI priority - sort order in style picker (0-99, lower = higher priority) */
|
|
216
|
+
uiPriority?: number;
|
|
217
|
+
/** Semi-hidden - hide from gallery unless in use */
|
|
218
|
+
semiHidden?: boolean;
|
|
219
|
+
/** Unhide when used - auto-show when applied */
|
|
220
|
+
unhideWhenUsed?: boolean;
|
|
221
|
+
/** Locked - prevent modification */
|
|
222
|
+
locked?: boolean;
|
|
223
|
+
/** Personal - user-specific style */
|
|
224
|
+
personal?: boolean;
|
|
225
|
+
/** Link - linked character/paragraph style ID */
|
|
226
|
+
link?: string;
|
|
227
|
+
/** Auto-redefine - update style from manual formatting */
|
|
228
|
+
autoRedefine?: boolean;
|
|
229
|
+
/** Aliases - alternative names (comma-separated) */
|
|
230
|
+
aliases?: string;
|
|
231
|
+
|
|
232
|
+
// Document Helper Metadata
|
|
233
|
+
/**
|
|
234
|
+
* Table options for Heading2 wrapping
|
|
235
|
+
* Used by Document.applyCustomFormattingToExistingStyles() to configure
|
|
236
|
+
* how Heading2 paragraphs are wrapped in tables
|
|
237
|
+
*/
|
|
238
|
+
heading2TableOptions?: Heading2TableOptions;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Represents a style definition
|
|
243
|
+
*/
|
|
244
|
+
export class Style {
|
|
245
|
+
private properties: StyleProperties;
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Creates a new Style
|
|
249
|
+
* @param properties - Style properties
|
|
250
|
+
*/
|
|
251
|
+
constructor(properties: StyleProperties) {
|
|
252
|
+
this.properties = { ...properties };
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Gets the style ID
|
|
257
|
+
* @returns Style ID
|
|
258
|
+
*/
|
|
259
|
+
getStyleId(): string {
|
|
260
|
+
return this.properties.styleId;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Gets the style name
|
|
265
|
+
* @returns Style name
|
|
266
|
+
*/
|
|
267
|
+
getName(): string {
|
|
268
|
+
return this.properties.name;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Gets the style type
|
|
273
|
+
* @returns Style type
|
|
274
|
+
*/
|
|
275
|
+
getType(): StyleType {
|
|
276
|
+
return this.properties.type;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Gets all style properties
|
|
281
|
+
* @returns Style properties
|
|
282
|
+
*/
|
|
283
|
+
getProperties(): StyleProperties {
|
|
284
|
+
return { ...this.properties };
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Gets whether this is a default style
|
|
289
|
+
* @returns True if this is a default style for its type
|
|
290
|
+
*/
|
|
291
|
+
getIsDefault(): boolean {
|
|
292
|
+
return this.properties.isDefault ?? false;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Sets whether this is a default style
|
|
297
|
+
* @param value - True to mark as default style
|
|
298
|
+
* @returns This style for chaining
|
|
299
|
+
*/
|
|
300
|
+
setIsDefault(value: boolean): this {
|
|
301
|
+
this.properties.isDefault = value;
|
|
302
|
+
return this;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Sets the base style
|
|
307
|
+
* @param styleId - Parent style ID
|
|
308
|
+
* @returns This style for chaining
|
|
309
|
+
*/
|
|
310
|
+
setBasedOn(styleId: string): this {
|
|
311
|
+
this.properties.basedOn = styleId;
|
|
312
|
+
return this;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Sets the next style
|
|
317
|
+
* @param styleId - Next style ID
|
|
318
|
+
* @returns This style for chaining
|
|
319
|
+
*/
|
|
320
|
+
setNext(styleId: string): this {
|
|
321
|
+
this.properties.next = styleId;
|
|
322
|
+
return this;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Sets paragraph formatting
|
|
327
|
+
* @param formatting - Paragraph formatting options
|
|
328
|
+
* @returns This style for chaining
|
|
329
|
+
*/
|
|
330
|
+
setParagraphFormatting(formatting: ParagraphFormatting): this {
|
|
331
|
+
this.properties.paragraphFormatting = { ...formatting };
|
|
332
|
+
return this;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Sets run formatting
|
|
337
|
+
* @param formatting - Run formatting options
|
|
338
|
+
* @returns This style for chaining
|
|
339
|
+
*/
|
|
340
|
+
setRunFormatting(formatting: RunFormatting): this {
|
|
341
|
+
this.properties.runFormatting = { ...formatting };
|
|
342
|
+
return this;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Gets the current run formatting
|
|
347
|
+
* @returns Run formatting or undefined if not set
|
|
348
|
+
*/
|
|
349
|
+
getRunFormatting(): RunFormatting | undefined {
|
|
350
|
+
return this.properties.runFormatting;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Gets the current paragraph formatting
|
|
355
|
+
* @returns Paragraph formatting or undefined if not set
|
|
356
|
+
*/
|
|
357
|
+
getParagraphFormatting(): ParagraphFormatting | undefined {
|
|
358
|
+
return this.properties.paragraphFormatting;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Sets Heading2 table wrapping options
|
|
363
|
+
* Used by Document.applyCustomFormattingToExistingStyles() when styleId is 'Heading2'
|
|
364
|
+
* @param options - Table options for wrapping Heading2 paragraphs
|
|
365
|
+
* @returns This style for chaining
|
|
366
|
+
*/
|
|
367
|
+
setHeading2TableOptions(options: Heading2TableOptions): this {
|
|
368
|
+
this.properties.heading2TableOptions = options;
|
|
369
|
+
return this;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Gets the current Heading2 table options
|
|
374
|
+
* @returns Heading2 table options or undefined if not set
|
|
375
|
+
*/
|
|
376
|
+
getHeading2TableOptions(): Heading2TableOptions | undefined {
|
|
377
|
+
return this.properties.heading2TableOptions;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Sets whether this is a quick style (appears in style gallery)
|
|
382
|
+
* @param enabled - True to show in quick style gallery
|
|
383
|
+
* @returns This style for chaining
|
|
384
|
+
*/
|
|
385
|
+
setQFormat(enabled: boolean): this {
|
|
386
|
+
this.properties.qFormat = enabled;
|
|
387
|
+
return this;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Sets the UI priority (sort order in style picker)
|
|
392
|
+
* @param priority - Priority value (0-99, lower = higher priority)
|
|
393
|
+
* @returns This style for chaining
|
|
394
|
+
*/
|
|
395
|
+
setUiPriority(priority: number): this {
|
|
396
|
+
if (priority < 0 || priority > 99) {
|
|
397
|
+
throw new Error("UI priority must be between 0 and 99");
|
|
398
|
+
}
|
|
399
|
+
this.properties.uiPriority = priority;
|
|
400
|
+
return this;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Sets whether this style is semi-hidden (hidden from recommended list)
|
|
405
|
+
* @param hidden - True to hide from recommended list
|
|
406
|
+
* @returns This style for chaining
|
|
407
|
+
*/
|
|
408
|
+
setSemiHidden(hidden: boolean): this {
|
|
409
|
+
this.properties.semiHidden = hidden;
|
|
410
|
+
return this;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* Sets whether to unhide this style when first used
|
|
415
|
+
* @param enabled - True to auto-show when applied
|
|
416
|
+
* @returns This style for chaining
|
|
417
|
+
*/
|
|
418
|
+
setUnhideWhenUsed(enabled: boolean): this {
|
|
419
|
+
this.properties.unhideWhenUsed = enabled;
|
|
420
|
+
return this;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Sets whether this style is locked (prevents modification)
|
|
425
|
+
* @param locked - True to lock the style
|
|
426
|
+
* @returns This style for chaining
|
|
427
|
+
*/
|
|
428
|
+
setLocked(locked: boolean): this {
|
|
429
|
+
this.properties.locked = locked;
|
|
430
|
+
return this;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Sets whether this is a personal style (user-specific)
|
|
435
|
+
* @param personal - True to mark as personal
|
|
436
|
+
* @returns This style for chaining
|
|
437
|
+
*/
|
|
438
|
+
setPersonal(personal: boolean): this {
|
|
439
|
+
this.properties.personal = personal;
|
|
440
|
+
return this;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Sets the linked style ID (for character/paragraph style linking)
|
|
445
|
+
* @param styleId - ID of the linked style
|
|
446
|
+
* @returns This style for chaining
|
|
447
|
+
*/
|
|
448
|
+
setLink(styleId: string): this {
|
|
449
|
+
this.properties.link = styleId;
|
|
450
|
+
return this;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Sets whether to auto-redefine this style from manual formatting
|
|
455
|
+
* @param enabled - True to enable auto-redefine
|
|
456
|
+
* @returns This style for chaining
|
|
457
|
+
*/
|
|
458
|
+
setAutoRedefine(enabled: boolean): this {
|
|
459
|
+
this.properties.autoRedefine = enabled;
|
|
460
|
+
return this;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Sets alternative names for this style (comma-separated)
|
|
465
|
+
* @param aliases - Comma-separated list of alternative names
|
|
466
|
+
* @returns This style for chaining
|
|
467
|
+
*/
|
|
468
|
+
setAliases(aliases: string): this {
|
|
469
|
+
this.properties.aliases = aliases;
|
|
470
|
+
return this;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Sets table-level formatting properties (Phase 5.1)
|
|
475
|
+
* @param formatting - Table formatting options
|
|
476
|
+
* @returns This style for chaining
|
|
477
|
+
*/
|
|
478
|
+
setTableFormatting(formatting: TableStyleFormatting): this {
|
|
479
|
+
if (!this.properties.tableStyle) {
|
|
480
|
+
this.properties.tableStyle = {};
|
|
481
|
+
}
|
|
482
|
+
this.properties.tableStyle.table = { ...formatting };
|
|
483
|
+
return this;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Sets table cell formatting properties (Phase 5.1)
|
|
488
|
+
* @param formatting - Cell formatting options
|
|
489
|
+
* @returns This style for chaining
|
|
490
|
+
*/
|
|
491
|
+
setTableCellFormatting(formatting: TableCellStyleFormatting): this {
|
|
492
|
+
if (!this.properties.tableStyle) {
|
|
493
|
+
this.properties.tableStyle = {};
|
|
494
|
+
}
|
|
495
|
+
this.properties.tableStyle.cell = { ...formatting };
|
|
496
|
+
return this;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* Sets table row formatting properties (Phase 5.1)
|
|
501
|
+
* @param formatting - Row formatting options
|
|
502
|
+
* @returns This style for chaining
|
|
503
|
+
*/
|
|
504
|
+
setTableRowFormatting(formatting: TableRowStyleFormatting): this {
|
|
505
|
+
if (!this.properties.tableStyle) {
|
|
506
|
+
this.properties.tableStyle = {};
|
|
507
|
+
}
|
|
508
|
+
this.properties.tableStyle.row = { ...formatting };
|
|
509
|
+
return this;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Sets row band size for row banding (Phase 5.1)
|
|
514
|
+
* @param size - Number of rows per band (default 1)
|
|
515
|
+
* @returns This style for chaining
|
|
516
|
+
*/
|
|
517
|
+
setRowBandSize(size: number): this {
|
|
518
|
+
if (!this.properties.tableStyle) {
|
|
519
|
+
this.properties.tableStyle = {};
|
|
520
|
+
}
|
|
521
|
+
if (size < 0) {
|
|
522
|
+
throw new Error("Row band size must be non-negative");
|
|
523
|
+
}
|
|
524
|
+
this.properties.tableStyle.rowBandSize = size;
|
|
525
|
+
return this;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* Sets column band size for column banding (Phase 5.1)
|
|
530
|
+
* @param size - Number of columns per band (default 1)
|
|
531
|
+
* @returns This style for chaining
|
|
532
|
+
*/
|
|
533
|
+
setColBandSize(size: number): this {
|
|
534
|
+
if (!this.properties.tableStyle) {
|
|
535
|
+
this.properties.tableStyle = {};
|
|
536
|
+
}
|
|
537
|
+
if (size < 0) {
|
|
538
|
+
throw new Error("Column band size must be non-negative");
|
|
539
|
+
}
|
|
540
|
+
this.properties.tableStyle.colBandSize = size;
|
|
541
|
+
return this;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* Adds conditional formatting for a specific table region (Phase 5.1)
|
|
546
|
+
* @param conditional - Conditional formatting definition
|
|
547
|
+
* @returns This style for chaining
|
|
548
|
+
*/
|
|
549
|
+
addConditionalFormatting(conditional: ConditionalTableFormatting): this {
|
|
550
|
+
if (!this.properties.tableStyle) {
|
|
551
|
+
this.properties.tableStyle = {};
|
|
552
|
+
}
|
|
553
|
+
if (!this.properties.tableStyle.conditionalFormatting) {
|
|
554
|
+
this.properties.tableStyle.conditionalFormatting = [];
|
|
555
|
+
}
|
|
556
|
+
this.properties.tableStyle.conditionalFormatting.push({ ...conditional });
|
|
557
|
+
return this;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* Validates that this style definition is valid
|
|
562
|
+
*
|
|
563
|
+
* Checks:
|
|
564
|
+
* - Required fields (styleId, name, type)
|
|
565
|
+
* - Valid type value
|
|
566
|
+
* - No circular references (basedOn != styleId)
|
|
567
|
+
* - Valid formatting values
|
|
568
|
+
*
|
|
569
|
+
* @returns True if the style is valid, false otherwise
|
|
570
|
+
*/
|
|
571
|
+
isValid(): boolean {
|
|
572
|
+
try {
|
|
573
|
+
// Required fields
|
|
574
|
+
if (
|
|
575
|
+
!this.properties.styleId ||
|
|
576
|
+
!this.properties.name ||
|
|
577
|
+
!this.properties.type
|
|
578
|
+
) {
|
|
579
|
+
return false;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// Valid type
|
|
583
|
+
const validTypes: StyleType[] = [
|
|
584
|
+
"paragraph",
|
|
585
|
+
"character",
|
|
586
|
+
"table",
|
|
587
|
+
"numbering",
|
|
588
|
+
];
|
|
589
|
+
if (!validTypes.includes(this.properties.type)) {
|
|
590
|
+
return false;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
// No circular reference
|
|
594
|
+
if (this.properties.basedOn === this.properties.styleId) {
|
|
595
|
+
return false;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// Check paragraph formatting if present
|
|
599
|
+
if (this.properties.paragraphFormatting) {
|
|
600
|
+
const pf = this.properties.paragraphFormatting;
|
|
601
|
+
|
|
602
|
+
// Check alignment
|
|
603
|
+
if (pf.alignment) {
|
|
604
|
+
const validAlignments = [
|
|
605
|
+
"left",
|
|
606
|
+
"center",
|
|
607
|
+
"right",
|
|
608
|
+
"justify",
|
|
609
|
+
"both",
|
|
610
|
+
"distribute",
|
|
611
|
+
];
|
|
612
|
+
if (!validAlignments.includes(pf.alignment)) {
|
|
613
|
+
return false;
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// Check spacing values
|
|
618
|
+
if (pf.spacing) {
|
|
619
|
+
const spacing = pf.spacing;
|
|
620
|
+
if (spacing.before !== undefined && spacing.before < 0) return false;
|
|
621
|
+
if (spacing.after !== undefined && spacing.after < 0) return false;
|
|
622
|
+
if (spacing.line !== undefined && spacing.line < 0) return false;
|
|
623
|
+
if (
|
|
624
|
+
spacing.lineRule &&
|
|
625
|
+
!["auto", "exact", "atLeast"].includes(spacing.lineRule)
|
|
626
|
+
) {
|
|
627
|
+
return false;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// Check indentation values
|
|
632
|
+
if (pf.indentation) {
|
|
633
|
+
const ind = pf.indentation;
|
|
634
|
+
// Indentation values can be negative for hanging indent
|
|
635
|
+
if (ind.left !== undefined && ind.left < -100000) return false;
|
|
636
|
+
if (ind.right !== undefined && ind.right < -100000) return false;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// Check run formatting if present
|
|
641
|
+
if (this.properties.runFormatting) {
|
|
642
|
+
const rf = this.properties.runFormatting;
|
|
643
|
+
|
|
644
|
+
// Check font size
|
|
645
|
+
if (rf.size !== undefined && (rf.size <= 0 || rf.size > 1638)) {
|
|
646
|
+
return false; // Max font size in Word is 1638
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
// Check color format (should be 6 hex characters)
|
|
650
|
+
if (rf.color && !/^[0-9A-Fa-f]{6}$/.test(rf.color)) {
|
|
651
|
+
return false;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
// Check highlight color
|
|
655
|
+
if (rf.highlight) {
|
|
656
|
+
const validHighlights = [
|
|
657
|
+
"black",
|
|
658
|
+
"blue",
|
|
659
|
+
"cyan",
|
|
660
|
+
"darkBlue",
|
|
661
|
+
"darkCyan",
|
|
662
|
+
"darkGray",
|
|
663
|
+
"darkGreen",
|
|
664
|
+
"darkMagenta",
|
|
665
|
+
"darkRed",
|
|
666
|
+
"darkYellow",
|
|
667
|
+
"green",
|
|
668
|
+
"lightGray",
|
|
669
|
+
"magenta",
|
|
670
|
+
"none",
|
|
671
|
+
"red",
|
|
672
|
+
"white",
|
|
673
|
+
"yellow",
|
|
674
|
+
];
|
|
675
|
+
if (!validHighlights.includes(rf.highlight)) {
|
|
676
|
+
return false;
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// Check metadata properties (Phase 5.3)
|
|
682
|
+
if (this.properties.uiPriority !== undefined) {
|
|
683
|
+
if (this.properties.uiPriority < 0 || this.properties.uiPriority > 99) {
|
|
684
|
+
return false;
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
// Check linked style doesn't reference self
|
|
689
|
+
if (this.properties.link === this.properties.styleId) {
|
|
690
|
+
return false;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
return true;
|
|
694
|
+
} catch {
|
|
695
|
+
return false;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* Converts the style to WordprocessingML XML element
|
|
701
|
+
* @returns XMLElement representing the style
|
|
702
|
+
*/
|
|
703
|
+
toXML(): XMLElement {
|
|
704
|
+
const styleAttrs: Record<string, string> = {
|
|
705
|
+
"w:type": this.properties.type,
|
|
706
|
+
"w:styleId": this.properties.styleId,
|
|
707
|
+
};
|
|
708
|
+
|
|
709
|
+
if (this.properties.isDefault) {
|
|
710
|
+
styleAttrs["w:default"] = "1";
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
if (this.properties.customStyle) {
|
|
714
|
+
styleAttrs["w:customStyle"] = "1";
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
const styleChildren: XMLElement[] = [];
|
|
718
|
+
|
|
719
|
+
// Add style name
|
|
720
|
+
styleChildren.push(
|
|
721
|
+
XMLBuilder.wSelf("name", { "w:val": this.properties.name })
|
|
722
|
+
);
|
|
723
|
+
|
|
724
|
+
// aliases - Alternative names (must follow name per CT_Style)
|
|
725
|
+
if (this.properties.aliases) {
|
|
726
|
+
styleChildren.push(
|
|
727
|
+
XMLBuilder.wSelf("aliases", { "w:val": this.properties.aliases })
|
|
728
|
+
);
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
// Add basedOn
|
|
732
|
+
if (this.properties.basedOn) {
|
|
733
|
+
styleChildren.push(
|
|
734
|
+
XMLBuilder.wSelf("basedOn", { "w:val": this.properties.basedOn })
|
|
735
|
+
);
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
// Add next
|
|
739
|
+
if (this.properties.next) {
|
|
740
|
+
styleChildren.push(
|
|
741
|
+
XMLBuilder.wSelf("next", { "w:val": this.properties.next })
|
|
742
|
+
);
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// Add link (linked character/paragraph style)
|
|
746
|
+
if (this.properties.link) {
|
|
747
|
+
styleChildren.push(
|
|
748
|
+
XMLBuilder.wSelf("link", { "w:val": this.properties.link })
|
|
749
|
+
);
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
// Add autoRedefine
|
|
753
|
+
if (this.properties.autoRedefine) {
|
|
754
|
+
styleChildren.push(XMLBuilder.wSelf("autoRedefine"));
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
// Add metadata properties — ordered per ECMA-376 CT_Style
|
|
758
|
+
// uiPriority - Sort order in style picker
|
|
759
|
+
if (this.properties.uiPriority !== undefined) {
|
|
760
|
+
styleChildren.push(
|
|
761
|
+
XMLBuilder.wSelf("uiPriority", {
|
|
762
|
+
"w:val": String(this.properties.uiPriority),
|
|
763
|
+
})
|
|
764
|
+
);
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
// semiHidden - Hide from recommended list
|
|
768
|
+
if (this.properties.semiHidden) {
|
|
769
|
+
styleChildren.push(XMLBuilder.wSelf("semiHidden"));
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
// unhideWhenUsed - Auto-show when applied
|
|
773
|
+
if (this.properties.unhideWhenUsed) {
|
|
774
|
+
styleChildren.push(XMLBuilder.wSelf("unhideWhenUsed"));
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
// qFormat - Quick style gallery appearance
|
|
778
|
+
if (this.properties.qFormat !== undefined) {
|
|
779
|
+
if (this.properties.qFormat) {
|
|
780
|
+
styleChildren.push(XMLBuilder.wSelf("qFormat"));
|
|
781
|
+
}
|
|
782
|
+
} else if (!this.properties.customStyle) {
|
|
783
|
+
// Default: built-in styles have qFormat
|
|
784
|
+
styleChildren.push(XMLBuilder.wSelf("qFormat"));
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
// locked - Prevent modification
|
|
788
|
+
if (this.properties.locked) {
|
|
789
|
+
styleChildren.push(XMLBuilder.wSelf("locked"));
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
// personal - User-specific style
|
|
793
|
+
if (this.properties.personal) {
|
|
794
|
+
styleChildren.push(XMLBuilder.wSelf("personal"));
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
// Add paragraph properties
|
|
798
|
+
if (this.properties.paragraphFormatting || this.properties.numPr) {
|
|
799
|
+
const pPr = this.generateParagraphProperties(
|
|
800
|
+
this.properties.paragraphFormatting || {}
|
|
801
|
+
);
|
|
802
|
+
// Add numPr (numbering properties) if present - styles can inherit list formatting
|
|
803
|
+
if (this.properties.numPr) {
|
|
804
|
+
const numPrChildren: XMLElement[] = [];
|
|
805
|
+
if (this.properties.numPr.ilvl !== undefined) {
|
|
806
|
+
numPrChildren.push(
|
|
807
|
+
XMLBuilder.wSelf("ilvl", { "w:val": String(this.properties.numPr.ilvl) })
|
|
808
|
+
);
|
|
809
|
+
}
|
|
810
|
+
if (this.properties.numPr.numId !== undefined) {
|
|
811
|
+
numPrChildren.push(
|
|
812
|
+
XMLBuilder.wSelf("numId", { "w:val": String(this.properties.numPr.numId) })
|
|
813
|
+
);
|
|
814
|
+
}
|
|
815
|
+
if (numPrChildren.length > 0) {
|
|
816
|
+
// Insert numPr at the beginning of pPr children (per ECMA-376 element order)
|
|
817
|
+
if (pPr.children) {
|
|
818
|
+
pPr.children.unshift(XMLBuilder.w("numPr", undefined, numPrChildren));
|
|
819
|
+
} else {
|
|
820
|
+
pPr.children = [XMLBuilder.w("numPr", undefined, numPrChildren)];
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
if (pPr.children && pPr.children.length > 0) {
|
|
825
|
+
styleChildren.push(pPr);
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
// Add run properties
|
|
830
|
+
if (this.properties.runFormatting) {
|
|
831
|
+
const rPr = this.generateRunProperties(this.properties.runFormatting);
|
|
832
|
+
if (rPr.children && rPr.children.length > 0) {
|
|
833
|
+
styleChildren.push(rPr);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
// Add table style properties (Phase 5.1)
|
|
838
|
+
if (this.properties.tableStyle) {
|
|
839
|
+
// Add tblPr (table properties)
|
|
840
|
+
if (this.properties.tableStyle.table) {
|
|
841
|
+
const tblPr = this.generateTableProperties(
|
|
842
|
+
this.properties.tableStyle.table,
|
|
843
|
+
this.properties.tableStyle
|
|
844
|
+
);
|
|
845
|
+
if (tblPr.children && tblPr.children.length > 0) {
|
|
846
|
+
styleChildren.push(tblPr);
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
// Add trPr (table row properties) — per CT_Style: tblPr → trPr → tcPr
|
|
851
|
+
if (this.properties.tableStyle.row) {
|
|
852
|
+
const trPr = this.generateTableRowProperties(
|
|
853
|
+
this.properties.tableStyle.row
|
|
854
|
+
);
|
|
855
|
+
if (trPr.children && trPr.children.length > 0) {
|
|
856
|
+
styleChildren.push(trPr);
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
// Add tcPr (table cell properties)
|
|
861
|
+
if (this.properties.tableStyle.cell) {
|
|
862
|
+
const tcPr = this.generateTableCellProperties(
|
|
863
|
+
this.properties.tableStyle.cell
|
|
864
|
+
);
|
|
865
|
+
if (tcPr.children && tcPr.children.length > 0) {
|
|
866
|
+
styleChildren.push(tcPr);
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
// Add conditional formatting (tblStylePr)
|
|
871
|
+
if (this.properties.tableStyle.conditionalFormatting) {
|
|
872
|
+
for (const conditional of this.properties.tableStyle
|
|
873
|
+
.conditionalFormatting) {
|
|
874
|
+
const tblStylePr = this.generateConditionalFormatting(conditional);
|
|
875
|
+
if (tblStylePr.children && tblStylePr.children.length > 0) {
|
|
876
|
+
styleChildren.push(tblStylePr);
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
return XMLBuilder.w("style", styleAttrs, styleChildren);
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
/**
|
|
886
|
+
* Generates paragraph properties XML
|
|
887
|
+
*/
|
|
888
|
+
private generateParagraphProperties(
|
|
889
|
+
formatting: ParagraphFormatting
|
|
890
|
+
): XMLElement {
|
|
891
|
+
const pPrChildren: XMLElement[] = [];
|
|
892
|
+
|
|
893
|
+
// Ordered per ECMA-376 CT_PPrBase
|
|
894
|
+
if (formatting.keepNext) {
|
|
895
|
+
pPrChildren.push(XMLBuilder.wSelf("keepNext"));
|
|
896
|
+
}
|
|
897
|
+
if (formatting.keepLines) {
|
|
898
|
+
pPrChildren.push(XMLBuilder.wSelf("keepLines"));
|
|
899
|
+
}
|
|
900
|
+
if (formatting.pageBreakBefore) {
|
|
901
|
+
pPrChildren.push(XMLBuilder.wSelf("pageBreakBefore"));
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
// Add spacing
|
|
905
|
+
if (formatting.spacing) {
|
|
906
|
+
const spc = formatting.spacing;
|
|
907
|
+
const attributes: Record<string, number | string> = {};
|
|
908
|
+
if (spc.before !== undefined) attributes["w:before"] = spc.before;
|
|
909
|
+
if (spc.after !== undefined) attributes["w:after"] = spc.after;
|
|
910
|
+
if (spc.line !== undefined) attributes["w:line"] = spc.line;
|
|
911
|
+
if (spc.lineRule) attributes["w:lineRule"] = spc.lineRule;
|
|
912
|
+
if (Object.keys(attributes).length > 0) {
|
|
913
|
+
pPrChildren.push(XMLBuilder.wSelf("spacing", attributes));
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
// Add indentation
|
|
918
|
+
if (formatting.indentation) {
|
|
919
|
+
const ind = formatting.indentation;
|
|
920
|
+
const attributes: Record<string, number> = {};
|
|
921
|
+
if (ind.left !== undefined) attributes["w:left"] = ind.left;
|
|
922
|
+
if (ind.right !== undefined) attributes["w:right"] = ind.right;
|
|
923
|
+
if (ind.firstLine !== undefined)
|
|
924
|
+
attributes["w:firstLine"] = ind.firstLine;
|
|
925
|
+
if (ind.hanging !== undefined) attributes["w:hanging"] = ind.hanging;
|
|
926
|
+
if (Object.keys(attributes).length > 0) {
|
|
927
|
+
pPrChildren.push(XMLBuilder.wSelf("ind", attributes));
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
// Contextual spacing per ECMA-376 Part 1 §17.3.1.8
|
|
932
|
+
// Removes spacing between paragraphs of the same style
|
|
933
|
+
if (formatting.contextualSpacing) {
|
|
934
|
+
pPrChildren.push(XMLBuilder.wSelf("contextualSpacing", { "w:val": "1" }));
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
// Add alignment
|
|
938
|
+
if (formatting.alignment) {
|
|
939
|
+
// Map 'justify' to 'both' per ECMA-376 (Word uses 'both' for justified text)
|
|
940
|
+
const alignmentValue =
|
|
941
|
+
formatting.alignment === "justify" ? "both" : formatting.alignment;
|
|
942
|
+
pPrChildren.push(XMLBuilder.wSelf("jc", { "w:val": alignmentValue }));
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
// Add outline level for TOC support (Heading 1 = 0, Heading 2 = 1, etc.)
|
|
946
|
+
if (formatting.outlineLevel !== undefined) {
|
|
947
|
+
pPrChildren.push(
|
|
948
|
+
XMLBuilder.wSelf("outlineLvl", { "w:val": formatting.outlineLevel.toString() })
|
|
949
|
+
);
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
return XMLBuilder.w("pPr", undefined, pPrChildren);
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
/**
|
|
956
|
+
* Generates run properties XML
|
|
957
|
+
*/
|
|
958
|
+
private generateRunProperties(formatting: RunFormatting): XMLElement {
|
|
959
|
+
const rPrChildren: XMLElement[] = [];
|
|
960
|
+
|
|
961
|
+
// Add formatting elements — ordered per ECMA-376 CT_RPr
|
|
962
|
+
if (formatting.font) {
|
|
963
|
+
rPrChildren.push(
|
|
964
|
+
XMLBuilder.wSelf("rFonts", {
|
|
965
|
+
"w:ascii": formatting.font,
|
|
966
|
+
"w:hAnsi": formatting.font,
|
|
967
|
+
"w:cs": formatting.font,
|
|
968
|
+
})
|
|
969
|
+
);
|
|
970
|
+
}
|
|
971
|
+
if (formatting.bold) {
|
|
972
|
+
rPrChildren.push(XMLBuilder.wSelf("b"));
|
|
973
|
+
}
|
|
974
|
+
if (formatting.italic) {
|
|
975
|
+
rPrChildren.push(XMLBuilder.wSelf("i"));
|
|
976
|
+
}
|
|
977
|
+
if (formatting.allCaps) {
|
|
978
|
+
rPrChildren.push(XMLBuilder.wSelf("caps"));
|
|
979
|
+
}
|
|
980
|
+
if (formatting.smallCaps) {
|
|
981
|
+
rPrChildren.push(XMLBuilder.wSelf("smallCaps"));
|
|
982
|
+
}
|
|
983
|
+
if (formatting.strike) {
|
|
984
|
+
rPrChildren.push(XMLBuilder.wSelf("strike"));
|
|
985
|
+
}
|
|
986
|
+
if (formatting.dstrike) {
|
|
987
|
+
rPrChildren.push(XMLBuilder.wSelf("dstrike"));
|
|
988
|
+
}
|
|
989
|
+
if (formatting.color) {
|
|
990
|
+
rPrChildren.push(
|
|
991
|
+
XMLBuilder.wSelf("color", { "w:val": formatting.color })
|
|
992
|
+
);
|
|
993
|
+
}
|
|
994
|
+
if (formatting.size !== undefined) {
|
|
995
|
+
const halfPoints = pointsToHalfPoints(formatting.size);
|
|
996
|
+
rPrChildren.push(XMLBuilder.wSelf("sz", { "w:val": halfPoints }));
|
|
997
|
+
rPrChildren.push(XMLBuilder.wSelf("szCs", { "w:val": halfPoints }));
|
|
998
|
+
}
|
|
999
|
+
if (formatting.highlight) {
|
|
1000
|
+
rPrChildren.push(
|
|
1001
|
+
XMLBuilder.wSelf("highlight", { "w:val": formatting.highlight })
|
|
1002
|
+
);
|
|
1003
|
+
}
|
|
1004
|
+
if (formatting.underline) {
|
|
1005
|
+
const underlineValue =
|
|
1006
|
+
typeof formatting.underline === "string"
|
|
1007
|
+
? formatting.underline
|
|
1008
|
+
: "single";
|
|
1009
|
+
rPrChildren.push(XMLBuilder.wSelf("u", { "w:val": underlineValue }));
|
|
1010
|
+
}
|
|
1011
|
+
if (formatting.subscript) {
|
|
1012
|
+
rPrChildren.push(XMLBuilder.wSelf("vertAlign", { "w:val": "subscript" }));
|
|
1013
|
+
}
|
|
1014
|
+
if (formatting.superscript) {
|
|
1015
|
+
rPrChildren.push(
|
|
1016
|
+
XMLBuilder.wSelf("vertAlign", { "w:val": "superscript" })
|
|
1017
|
+
);
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
return XMLBuilder.w("rPr", undefined, rPrChildren);
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
/**
|
|
1024
|
+
* Generates table properties XML (tblPr) - Phase 5.1
|
|
1025
|
+
*/
|
|
1026
|
+
private generateTableProperties(
|
|
1027
|
+
formatting: TableStyleFormatting,
|
|
1028
|
+
tableStyle: TableStyleProperties,
|
|
1029
|
+
isConditional = false
|
|
1030
|
+
): XMLElement {
|
|
1031
|
+
const tblPrChildren: XMLElement[] = [];
|
|
1032
|
+
|
|
1033
|
+
// Ordered per CT_TblPrBase (ECMA-376 §17.4.60):
|
|
1034
|
+
// tblStyleRowBandSize → tblStyleColBandSize → tblW → jc →
|
|
1035
|
+
// tblCellSpacing → tblInd → tblBorders → shd → tblCellMar
|
|
1036
|
+
|
|
1037
|
+
// Row band size (must come first)
|
|
1038
|
+
if (tableStyle.rowBandSize !== undefined) {
|
|
1039
|
+
tblPrChildren.push(
|
|
1040
|
+
XMLBuilder.wSelf("tblStyleRowBandSize", {
|
|
1041
|
+
"w:val": tableStyle.rowBandSize,
|
|
1042
|
+
})
|
|
1043
|
+
);
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
// Column band size
|
|
1047
|
+
if (tableStyle.colBandSize !== undefined) {
|
|
1048
|
+
tblPrChildren.push(
|
|
1049
|
+
XMLBuilder.wSelf("tblStyleColBandSize", {
|
|
1050
|
+
"w:val": tableStyle.colBandSize,
|
|
1051
|
+
})
|
|
1052
|
+
);
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
// Note: tblW is omitted for table styles. It's only valid in inline tblPr
|
|
1056
|
+
// (CT_TblPr in table elements), not in CT_Style's tblPr.
|
|
1057
|
+
|
|
1058
|
+
// Table alignment
|
|
1059
|
+
if (formatting.alignment) {
|
|
1060
|
+
tblPrChildren.push(
|
|
1061
|
+
XMLBuilder.wSelf("jc", { "w:val": formatting.alignment })
|
|
1062
|
+
);
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
// Cell spacing
|
|
1066
|
+
if (formatting.cellSpacing !== undefined) {
|
|
1067
|
+
tblPrChildren.push(
|
|
1068
|
+
XMLBuilder.wSelf("tblCellSpacing", {
|
|
1069
|
+
"w:w": formatting.cellSpacing,
|
|
1070
|
+
"w:type": "dxa",
|
|
1071
|
+
})
|
|
1072
|
+
);
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
// Table indentation
|
|
1076
|
+
if (formatting.indent !== undefined) {
|
|
1077
|
+
tblPrChildren.push(
|
|
1078
|
+
XMLBuilder.wSelf("tblInd", {
|
|
1079
|
+
"w:w": formatting.indent,
|
|
1080
|
+
"w:type": "dxa",
|
|
1081
|
+
})
|
|
1082
|
+
);
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
// Table borders
|
|
1086
|
+
if (formatting.borders) {
|
|
1087
|
+
const borderElements = this.generateBorderElements(
|
|
1088
|
+
formatting.borders,
|
|
1089
|
+
false
|
|
1090
|
+
);
|
|
1091
|
+
if (borderElements.length > 0) {
|
|
1092
|
+
tblPrChildren.push(
|
|
1093
|
+
XMLBuilder.w("tblBorders", undefined, borderElements)
|
|
1094
|
+
);
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
// Table shading (not valid in tblStylePr conditional context)
|
|
1099
|
+
if (formatting.shading && !isConditional) {
|
|
1100
|
+
tblPrChildren.push(this.generateShadingElement(formatting.shading));
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
// Cell margins
|
|
1104
|
+
if (formatting.cellMargins) {
|
|
1105
|
+
const marginElements: XMLElement[] = [];
|
|
1106
|
+
if (formatting.cellMargins.top !== undefined) {
|
|
1107
|
+
marginElements.push(
|
|
1108
|
+
XMLBuilder.wSelf("top", {
|
|
1109
|
+
"w:w": formatting.cellMargins.top,
|
|
1110
|
+
"w:type": "dxa",
|
|
1111
|
+
})
|
|
1112
|
+
);
|
|
1113
|
+
}
|
|
1114
|
+
if (formatting.cellMargins.left !== undefined) {
|
|
1115
|
+
marginElements.push(
|
|
1116
|
+
XMLBuilder.wSelf("left", {
|
|
1117
|
+
"w:w": formatting.cellMargins.left,
|
|
1118
|
+
"w:type": "dxa",
|
|
1119
|
+
})
|
|
1120
|
+
);
|
|
1121
|
+
}
|
|
1122
|
+
if (formatting.cellMargins.bottom !== undefined) {
|
|
1123
|
+
marginElements.push(
|
|
1124
|
+
XMLBuilder.wSelf("bottom", {
|
|
1125
|
+
"w:w": formatting.cellMargins.bottom,
|
|
1126
|
+
"w:type": "dxa",
|
|
1127
|
+
})
|
|
1128
|
+
);
|
|
1129
|
+
}
|
|
1130
|
+
if (formatting.cellMargins.right !== undefined) {
|
|
1131
|
+
marginElements.push(
|
|
1132
|
+
XMLBuilder.wSelf("right", {
|
|
1133
|
+
"w:w": formatting.cellMargins.right,
|
|
1134
|
+
"w:type": "dxa",
|
|
1135
|
+
})
|
|
1136
|
+
);
|
|
1137
|
+
}
|
|
1138
|
+
if (marginElements.length > 0) {
|
|
1139
|
+
tblPrChildren.push(
|
|
1140
|
+
XMLBuilder.w("tblCellMar", undefined, marginElements)
|
|
1141
|
+
);
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
return XMLBuilder.w("tblPr", undefined, tblPrChildren);
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
/**
|
|
1149
|
+
* Generates table cell properties XML (tcPr) - Phase 5.1
|
|
1150
|
+
*/
|
|
1151
|
+
private generateTableCellProperties(
|
|
1152
|
+
formatting: TableCellStyleFormatting
|
|
1153
|
+
): XMLElement {
|
|
1154
|
+
const tcPrChildren: XMLElement[] = [];
|
|
1155
|
+
|
|
1156
|
+
// Cell borders
|
|
1157
|
+
if (formatting.borders) {
|
|
1158
|
+
const borderElements = this.generateBorderElements(
|
|
1159
|
+
formatting.borders,
|
|
1160
|
+
true
|
|
1161
|
+
);
|
|
1162
|
+
if (borderElements.length > 0) {
|
|
1163
|
+
tcPrChildren.push(XMLBuilder.w("tcBorders", undefined, borderElements));
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
// Cell shading
|
|
1168
|
+
if (formatting.shading) {
|
|
1169
|
+
tcPrChildren.push(this.generateShadingElement(formatting.shading));
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
// Cell margins
|
|
1173
|
+
if (formatting.margins) {
|
|
1174
|
+
const marginElements: XMLElement[] = [];
|
|
1175
|
+
if (formatting.margins.top !== undefined) {
|
|
1176
|
+
marginElements.push(
|
|
1177
|
+
XMLBuilder.wSelf("top", {
|
|
1178
|
+
"w:w": formatting.margins.top,
|
|
1179
|
+
"w:type": "dxa",
|
|
1180
|
+
})
|
|
1181
|
+
);
|
|
1182
|
+
}
|
|
1183
|
+
if (formatting.margins.left !== undefined) {
|
|
1184
|
+
marginElements.push(
|
|
1185
|
+
XMLBuilder.wSelf("left", {
|
|
1186
|
+
"w:w": formatting.margins.left,
|
|
1187
|
+
"w:type": "dxa",
|
|
1188
|
+
})
|
|
1189
|
+
);
|
|
1190
|
+
}
|
|
1191
|
+
if (formatting.margins.bottom !== undefined) {
|
|
1192
|
+
marginElements.push(
|
|
1193
|
+
XMLBuilder.wSelf("bottom", {
|
|
1194
|
+
"w:w": formatting.margins.bottom,
|
|
1195
|
+
"w:type": "dxa",
|
|
1196
|
+
})
|
|
1197
|
+
);
|
|
1198
|
+
}
|
|
1199
|
+
if (formatting.margins.right !== undefined) {
|
|
1200
|
+
marginElements.push(
|
|
1201
|
+
XMLBuilder.wSelf("right", {
|
|
1202
|
+
"w:w": formatting.margins.right,
|
|
1203
|
+
"w:type": "dxa",
|
|
1204
|
+
})
|
|
1205
|
+
);
|
|
1206
|
+
}
|
|
1207
|
+
if (marginElements.length > 0) {
|
|
1208
|
+
tcPrChildren.push(XMLBuilder.w("tcMar", undefined, marginElements));
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
// Vertical alignment
|
|
1213
|
+
if (formatting.verticalAlignment) {
|
|
1214
|
+
tcPrChildren.push(
|
|
1215
|
+
XMLBuilder.wSelf("vAlign", { "w:val": formatting.verticalAlignment })
|
|
1216
|
+
);
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
return XMLBuilder.w("tcPr", undefined, tcPrChildren);
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
/**
|
|
1223
|
+
* Generates table row properties XML (trPr) - Phase 5.1
|
|
1224
|
+
*/
|
|
1225
|
+
private generateTableRowProperties(
|
|
1226
|
+
formatting: TableRowStyleFormatting
|
|
1227
|
+
): XMLElement {
|
|
1228
|
+
const trPrChildren: XMLElement[] = [];
|
|
1229
|
+
|
|
1230
|
+
// Style-level trPr has a restricted content model compared to inline trPr.
|
|
1231
|
+
// Valid children: cantSplit, tblHeader, tblCellSpacing, jc, hidden
|
|
1232
|
+
// NOTE: trHeight is NOT valid in style-level trPr per OOXML strict schema.
|
|
1233
|
+
|
|
1234
|
+
// Can't split row across pages
|
|
1235
|
+
if (formatting.cantSplit) {
|
|
1236
|
+
trPrChildren.push(XMLBuilder.wSelf("cantSplit"));
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
// Header row
|
|
1240
|
+
if (formatting.isHeader) {
|
|
1241
|
+
trPrChildren.push(XMLBuilder.wSelf("tblHeader"));
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
return XMLBuilder.w("trPr", undefined, trPrChildren);
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
/**
|
|
1248
|
+
* Generates conditional formatting XML (tblStylePr) - Phase 5.1
|
|
1249
|
+
*/
|
|
1250
|
+
private generateConditionalFormatting(
|
|
1251
|
+
conditional: ConditionalTableFormatting
|
|
1252
|
+
): XMLElement {
|
|
1253
|
+
const tblStylePrChildren: XMLElement[] = [];
|
|
1254
|
+
|
|
1255
|
+
// Add paragraph properties if specified
|
|
1256
|
+
if (conditional.paragraphFormatting) {
|
|
1257
|
+
const pPr = this.generateParagraphProperties(
|
|
1258
|
+
conditional.paragraphFormatting
|
|
1259
|
+
);
|
|
1260
|
+
if (pPr.children && pPr.children.length > 0) {
|
|
1261
|
+
tblStylePrChildren.push(pPr);
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
// Add run properties if specified
|
|
1266
|
+
if (conditional.runFormatting) {
|
|
1267
|
+
const rPr = this.generateRunProperties(conditional.runFormatting);
|
|
1268
|
+
if (rPr.children && rPr.children.length > 0) {
|
|
1269
|
+
tblStylePrChildren.push(rPr);
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
// Add table properties if specified
|
|
1274
|
+
if (conditional.tableFormatting) {
|
|
1275
|
+
const tblPr = this.generateTableProperties(
|
|
1276
|
+
conditional.tableFormatting,
|
|
1277
|
+
{},
|
|
1278
|
+
true
|
|
1279
|
+
);
|
|
1280
|
+
if (tblPr.children && tblPr.children.length > 0) {
|
|
1281
|
+
tblStylePrChildren.push(tblPr);
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
// Add cell properties if specified
|
|
1286
|
+
if (conditional.cellFormatting) {
|
|
1287
|
+
const tcPr = this.generateTableCellProperties(conditional.cellFormatting);
|
|
1288
|
+
if (tcPr.children && tcPr.children.length > 0) {
|
|
1289
|
+
tblStylePrChildren.push(tcPr);
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
// Add row properties if specified
|
|
1294
|
+
if (conditional.rowFormatting) {
|
|
1295
|
+
const trPr = this.generateTableRowProperties(conditional.rowFormatting);
|
|
1296
|
+
if (trPr.children && trPr.children.length > 0) {
|
|
1297
|
+
tblStylePrChildren.push(trPr);
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
return XMLBuilder.w(
|
|
1302
|
+
"tblStylePr",
|
|
1303
|
+
{ "w:type": conditional.type },
|
|
1304
|
+
tblStylePrChildren
|
|
1305
|
+
);
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
/**
|
|
1309
|
+
* Generates border elements for tables or cells - Phase 5.1
|
|
1310
|
+
* @param borders - Border properties
|
|
1311
|
+
* @param includeDiagonals - Whether to include diagonal borders (for cells)
|
|
1312
|
+
*/
|
|
1313
|
+
private generateBorderElements(
|
|
1314
|
+
borders: TableBorders | CellBorders,
|
|
1315
|
+
includeDiagonals: boolean
|
|
1316
|
+
): XMLElement[] {
|
|
1317
|
+
const borderElements: XMLElement[] = [];
|
|
1318
|
+
|
|
1319
|
+
// Ordered per ECMA-376 CT_TblBorders / CT_TcBorders: top, left, bottom, right
|
|
1320
|
+
const borderProps = [
|
|
1321
|
+
"top",
|
|
1322
|
+
"left",
|
|
1323
|
+
"bottom",
|
|
1324
|
+
"right",
|
|
1325
|
+
"insideH",
|
|
1326
|
+
"insideV",
|
|
1327
|
+
] as const;
|
|
1328
|
+
for (const prop of borderProps) {
|
|
1329
|
+
const border = borders[prop];
|
|
1330
|
+
if (border) {
|
|
1331
|
+
const attrs: Record<string, string | number> = {};
|
|
1332
|
+
if (border.style) attrs["w:val"] = border.style;
|
|
1333
|
+
if (border.size !== undefined) attrs["w:sz"] = border.size;
|
|
1334
|
+
if (border.space !== undefined) attrs["w:space"] = border.space;
|
|
1335
|
+
if (border.color) attrs["w:color"] = border.color;
|
|
1336
|
+
|
|
1337
|
+
if (Object.keys(attrs).length > 0) {
|
|
1338
|
+
borderElements.push(XMLBuilder.wSelf(prop, attrs));
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
// Add diagonal borders for cells
|
|
1344
|
+
if (includeDiagonals) {
|
|
1345
|
+
const cellBorders = borders as CellBorders;
|
|
1346
|
+
if (cellBorders.tl2br) {
|
|
1347
|
+
const attrs: Record<string, string | number> = {};
|
|
1348
|
+
if (cellBorders.tl2br.style) attrs["w:val"] = cellBorders.tl2br.style;
|
|
1349
|
+
if (cellBorders.tl2br.size !== undefined)
|
|
1350
|
+
attrs["w:sz"] = cellBorders.tl2br.size;
|
|
1351
|
+
if (cellBorders.tl2br.space !== undefined)
|
|
1352
|
+
attrs["w:space"] = cellBorders.tl2br.space;
|
|
1353
|
+
if (cellBorders.tl2br.color) attrs["w:color"] = cellBorders.tl2br.color;
|
|
1354
|
+
|
|
1355
|
+
if (Object.keys(attrs).length > 0) {
|
|
1356
|
+
borderElements.push(XMLBuilder.wSelf("tl2br", attrs));
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
if (cellBorders.tr2bl) {
|
|
1360
|
+
const attrs: Record<string, string | number> = {};
|
|
1361
|
+
if (cellBorders.tr2bl.style) attrs["w:val"] = cellBorders.tr2bl.style;
|
|
1362
|
+
if (cellBorders.tr2bl.size !== undefined)
|
|
1363
|
+
attrs["w:sz"] = cellBorders.tr2bl.size;
|
|
1364
|
+
if (cellBorders.tr2bl.space !== undefined)
|
|
1365
|
+
attrs["w:space"] = cellBorders.tr2bl.space;
|
|
1366
|
+
if (cellBorders.tr2bl.color) attrs["w:color"] = cellBorders.tr2bl.color;
|
|
1367
|
+
|
|
1368
|
+
if (Object.keys(attrs).length > 0) {
|
|
1369
|
+
borderElements.push(XMLBuilder.wSelf("tr2bl", attrs));
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
return borderElements;
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
/**
|
|
1378
|
+
* Generates shading element - Phase 5.1
|
|
1379
|
+
*/
|
|
1380
|
+
private generateShadingElement(shading: ShadingProperties): XMLElement {
|
|
1381
|
+
const attrs = buildShadingAttributes(shading);
|
|
1382
|
+
return XMLBuilder.wSelf("shd", attrs);
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
/**
|
|
1386
|
+
* Creates a new Style
|
|
1387
|
+
* @param properties - Style properties
|
|
1388
|
+
* @returns New Style instance
|
|
1389
|
+
*/
|
|
1390
|
+
static create(properties: StyleProperties): Style {
|
|
1391
|
+
return new Style(properties);
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
/**
|
|
1395
|
+
* Creates the Normal style (default paragraph style)
|
|
1396
|
+
* @returns Normal style
|
|
1397
|
+
*/
|
|
1398
|
+
static createNormalStyle(): Style {
|
|
1399
|
+
return new Style({
|
|
1400
|
+
styleId: "Normal",
|
|
1401
|
+
name: "Normal",
|
|
1402
|
+
type: "paragraph",
|
|
1403
|
+
isDefault: true,
|
|
1404
|
+
next: "Normal",
|
|
1405
|
+
qFormat: true,
|
|
1406
|
+
uiPriority: 0,
|
|
1407
|
+
paragraphFormatting: {
|
|
1408
|
+
alignment: "left",
|
|
1409
|
+
spacing: {
|
|
1410
|
+
before: 60, // 3pt
|
|
1411
|
+
after: 60, // 3pt
|
|
1412
|
+
line: 240, // Single line spacing
|
|
1413
|
+
lineRule: "auto",
|
|
1414
|
+
},
|
|
1415
|
+
},
|
|
1416
|
+
runFormatting: {
|
|
1417
|
+
font: "Verdana",
|
|
1418
|
+
size: 12,
|
|
1419
|
+
color: "000000",
|
|
1420
|
+
},
|
|
1421
|
+
});
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
/**
|
|
1425
|
+
* Creates a Heading style
|
|
1426
|
+
* @param level - Heading level (1-9)
|
|
1427
|
+
* @returns Heading style
|
|
1428
|
+
*/
|
|
1429
|
+
static createHeadingStyle(level: number): Style {
|
|
1430
|
+
if (level < 1 || level > 9) {
|
|
1431
|
+
throw new Error("Heading level must be between 1 and 9");
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
// Font sizes: H1=18pt, H2=14pt, H3=12pt, H4-9=12pt
|
|
1435
|
+
const sizes = [18, 14, 12, 12, 12, 12, 12, 12, 12];
|
|
1436
|
+
|
|
1437
|
+
// Spacing before: H1=0pt, H2=6pt, H3=3pt, H4-9=6pt (in twips: 1pt = 20 twips)
|
|
1438
|
+
const spacingBefore =
|
|
1439
|
+
level === 1 ? 0 : level === 2 ? 120 : level === 3 ? 60 : 120;
|
|
1440
|
+
|
|
1441
|
+
// Spacing after: H1=12pt, H2=6pt, H3=3pt, H4-9=6pt (in twips)
|
|
1442
|
+
const spacingAfter =
|
|
1443
|
+
level === 1 ? 240 : level === 2 ? 120 : level === 3 ? 60 : 120;
|
|
1444
|
+
|
|
1445
|
+
return new Style({
|
|
1446
|
+
styleId: `Heading${level}`,
|
|
1447
|
+
name: `Heading ${level}`,
|
|
1448
|
+
type: "paragraph",
|
|
1449
|
+
basedOn: "Normal",
|
|
1450
|
+
next: "Normal",
|
|
1451
|
+
link: `Heading${level}Char`,
|
|
1452
|
+
qFormat: true,
|
|
1453
|
+
uiPriority: 9,
|
|
1454
|
+
paragraphFormatting: {
|
|
1455
|
+
alignment: "left",
|
|
1456
|
+
spacing: {
|
|
1457
|
+
before: spacingBefore,
|
|
1458
|
+
after: spacingAfter,
|
|
1459
|
+
line: 240, // Single line spacing
|
|
1460
|
+
lineRule: "auto",
|
|
1461
|
+
},
|
|
1462
|
+
keepNext: true,
|
|
1463
|
+
keepLines: true,
|
|
1464
|
+
outlineLevel: level - 1, // Heading 1 = 0, Heading 2 = 1, etc. Required for TOC
|
|
1465
|
+
},
|
|
1466
|
+
runFormatting: {
|
|
1467
|
+
font: "Verdana",
|
|
1468
|
+
size: sizes[level - 1],
|
|
1469
|
+
bold: true,
|
|
1470
|
+
color: "000000",
|
|
1471
|
+
},
|
|
1472
|
+
});
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
/**
|
|
1476
|
+
* Creates a Heading character style (linked to paragraph style)
|
|
1477
|
+
* @param level - Heading level (1-9)
|
|
1478
|
+
* @returns Heading character style
|
|
1479
|
+
*/
|
|
1480
|
+
static createHeadingCharStyle(level: number): Style {
|
|
1481
|
+
if (level < 1 || level > 9) {
|
|
1482
|
+
throw new Error("Heading level must be between 1 and 9");
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
// Font sizes: H1=18pt, H2=14pt, H3=12pt, H4-9=12pt
|
|
1486
|
+
const sizes = [18, 14, 12, 12, 12, 12, 12, 12, 12];
|
|
1487
|
+
|
|
1488
|
+
return new Style({
|
|
1489
|
+
styleId: `Heading${level}Char`,
|
|
1490
|
+
name: `Heading ${level} Char`,
|
|
1491
|
+
type: "character",
|
|
1492
|
+
link: `Heading${level}`,
|
|
1493
|
+
qFormat: true,
|
|
1494
|
+
uiPriority: 9,
|
|
1495
|
+
runFormatting: {
|
|
1496
|
+
font: "Verdana",
|
|
1497
|
+
size: sizes[level - 1],
|
|
1498
|
+
bold: true,
|
|
1499
|
+
color: "000000",
|
|
1500
|
+
},
|
|
1501
|
+
});
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
/**
|
|
1505
|
+
* Creates the Title style
|
|
1506
|
+
* @returns Title style
|
|
1507
|
+
*/
|
|
1508
|
+
static createTitleStyle(): Style {
|
|
1509
|
+
return new Style({
|
|
1510
|
+
styleId: "Title",
|
|
1511
|
+
name: "Title",
|
|
1512
|
+
type: "paragraph",
|
|
1513
|
+
basedOn: "Normal",
|
|
1514
|
+
next: "Normal",
|
|
1515
|
+
paragraphFormatting: {
|
|
1516
|
+
spacing: {
|
|
1517
|
+
after: 120,
|
|
1518
|
+
},
|
|
1519
|
+
},
|
|
1520
|
+
runFormatting: {
|
|
1521
|
+
font: "Verdana",
|
|
1522
|
+
size: 28,
|
|
1523
|
+
color: "000000",
|
|
1524
|
+
},
|
|
1525
|
+
});
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
/**
|
|
1529
|
+
* Creates the Subtitle style
|
|
1530
|
+
* @returns Subtitle style
|
|
1531
|
+
*/
|
|
1532
|
+
static createSubtitleStyle(): Style {
|
|
1533
|
+
return new Style({
|
|
1534
|
+
styleId: "Subtitle",
|
|
1535
|
+
name: "Subtitle",
|
|
1536
|
+
type: "paragraph",
|
|
1537
|
+
basedOn: "Normal",
|
|
1538
|
+
next: "Normal",
|
|
1539
|
+
paragraphFormatting: {
|
|
1540
|
+
spacing: {
|
|
1541
|
+
after: 120,
|
|
1542
|
+
},
|
|
1543
|
+
},
|
|
1544
|
+
runFormatting: {
|
|
1545
|
+
font: "Verdana",
|
|
1546
|
+
size: 14,
|
|
1547
|
+
color: "000000",
|
|
1548
|
+
italic: true,
|
|
1549
|
+
},
|
|
1550
|
+
});
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
/**
|
|
1554
|
+
* Creates a List Paragraph style (for lists)
|
|
1555
|
+
* @returns List Paragraph style
|
|
1556
|
+
*/
|
|
1557
|
+
static createListParagraphStyle(): Style {
|
|
1558
|
+
return new Style({
|
|
1559
|
+
styleId: "ListParagraph",
|
|
1560
|
+
name: "List Paragraph",
|
|
1561
|
+
type: "paragraph",
|
|
1562
|
+
basedOn: "Normal",
|
|
1563
|
+
next: "ListParagraph",
|
|
1564
|
+
qFormat: true,
|
|
1565
|
+
uiPriority: 34,
|
|
1566
|
+
paragraphFormatting: {
|
|
1567
|
+
alignment: "left",
|
|
1568
|
+
indentation: {
|
|
1569
|
+
left: 720, // 0.5 inch (text indentation)
|
|
1570
|
+
hanging: 360, // 0.25 inch (bullet/number indentation)
|
|
1571
|
+
},
|
|
1572
|
+
spacing: {
|
|
1573
|
+
before: 0, // 0pt
|
|
1574
|
+
after: 60, // 3pt
|
|
1575
|
+
line: 240, // Single line spacing
|
|
1576
|
+
lineRule: "auto",
|
|
1577
|
+
},
|
|
1578
|
+
contextualSpacing: true, // No space between similar paragraphs
|
|
1579
|
+
},
|
|
1580
|
+
runFormatting: {
|
|
1581
|
+
font: "Verdana",
|
|
1582
|
+
size: 12,
|
|
1583
|
+
color: "000000",
|
|
1584
|
+
},
|
|
1585
|
+
});
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
/**
|
|
1589
|
+
* Creates a TOC Heading style (for table of contents titles)
|
|
1590
|
+
* @returns TOC Heading style
|
|
1591
|
+
*/
|
|
1592
|
+
static createTOCHeadingStyle(): Style {
|
|
1593
|
+
return new Style({
|
|
1594
|
+
styleId: "TOCHeading",
|
|
1595
|
+
name: "TOC Heading",
|
|
1596
|
+
type: "paragraph",
|
|
1597
|
+
basedOn: "Heading1",
|
|
1598
|
+
next: "Normal",
|
|
1599
|
+
runFormatting: {
|
|
1600
|
+
bold: true,
|
|
1601
|
+
font: "Verdana",
|
|
1602
|
+
size: 14,
|
|
1603
|
+
color: "000000", // Black
|
|
1604
|
+
},
|
|
1605
|
+
paragraphFormatting: {
|
|
1606
|
+
spacing: {
|
|
1607
|
+
before: 480, // Larger spacing before TOC
|
|
1608
|
+
after: 240,
|
|
1609
|
+
},
|
|
1610
|
+
},
|
|
1611
|
+
});
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
/**
|
|
1615
|
+
* Creates a TOC entry style for a specific level (1-9).
|
|
1616
|
+
* TOC 1-9 are built-in Word styles for Table of Contents entries.
|
|
1617
|
+
* When Word updates a TOC field, it applies these styles to the generated entries.
|
|
1618
|
+
*
|
|
1619
|
+
* @param level - TOC level (1-9)
|
|
1620
|
+
* @param formatting - Optional run and paragraph formatting overrides
|
|
1621
|
+
* @returns TOC style for the specified level
|
|
1622
|
+
*/
|
|
1623
|
+
static createTOCStyle(
|
|
1624
|
+
level: number,
|
|
1625
|
+
formatting?: {
|
|
1626
|
+
run?: RunFormatting;
|
|
1627
|
+
paragraph?: ParagraphFormatting;
|
|
1628
|
+
}
|
|
1629
|
+
): Style {
|
|
1630
|
+
if (level < 1 || level > 9) {
|
|
1631
|
+
throw new Error("TOC level must be between 1 and 9");
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
// Default indentation: 220 twips per level (11pt)
|
|
1635
|
+
const defaultLeftIndent = (level - 1) * 220;
|
|
1636
|
+
|
|
1637
|
+
return Style.create({
|
|
1638
|
+
styleId: `TOC${level}`,
|
|
1639
|
+
name: `toc ${level}`,
|
|
1640
|
+
type: "paragraph",
|
|
1641
|
+
basedOn: "Normal",
|
|
1642
|
+
uiPriority: 39,
|
|
1643
|
+
semiHidden: true,
|
|
1644
|
+
unhideWhenUsed: true,
|
|
1645
|
+
runFormatting: formatting?.run,
|
|
1646
|
+
paragraphFormatting: {
|
|
1647
|
+
indentation: { left: defaultLeftIndent },
|
|
1648
|
+
...formatting?.paragraph,
|
|
1649
|
+
},
|
|
1650
|
+
});
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
/**
|
|
1654
|
+
* Creates a Table Normal style (Phase 5.1)
|
|
1655
|
+
* @returns Table Normal style
|
|
1656
|
+
*/
|
|
1657
|
+
static createTableNormalStyle(): Style {
|
|
1658
|
+
return new Style({
|
|
1659
|
+
styleId: "TableNormal",
|
|
1660
|
+
name: "Table Normal",
|
|
1661
|
+
type: "table",
|
|
1662
|
+
basedOn: "Normal",
|
|
1663
|
+
tableStyle: {
|
|
1664
|
+
table: {
|
|
1665
|
+
cellMargins: {
|
|
1666
|
+
top: 0,
|
|
1667
|
+
left: 108, // ~0.075 inch
|
|
1668
|
+
bottom: 0,
|
|
1669
|
+
right: 108,
|
|
1670
|
+
},
|
|
1671
|
+
},
|
|
1672
|
+
rowBandSize: 1,
|
|
1673
|
+
colBandSize: 1,
|
|
1674
|
+
},
|
|
1675
|
+
});
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
/**
|
|
1679
|
+
* Creates a Table Grid style with borders (Phase 5.1)
|
|
1680
|
+
* @returns Table Grid style
|
|
1681
|
+
*/
|
|
1682
|
+
static createTableGridStyle(): Style {
|
|
1683
|
+
return new Style({
|
|
1684
|
+
styleId: "TableGrid",
|
|
1685
|
+
name: "Table Grid",
|
|
1686
|
+
type: "table",
|
|
1687
|
+
basedOn: "TableNormal",
|
|
1688
|
+
tableStyle: {
|
|
1689
|
+
table: {
|
|
1690
|
+
borders: {
|
|
1691
|
+
top: { style: "single", size: 4, color: "000000" },
|
|
1692
|
+
bottom: { style: "single", size: 4, color: "000000" },
|
|
1693
|
+
left: { style: "single", size: 4, color: "000000" },
|
|
1694
|
+
right: { style: "single", size: 4, color: "000000" },
|
|
1695
|
+
insideH: { style: "single", size: 4, color: "000000" },
|
|
1696
|
+
insideV: { style: "single", size: 4, color: "000000" },
|
|
1697
|
+
},
|
|
1698
|
+
cellMargins: {
|
|
1699
|
+
top: 0,
|
|
1700
|
+
left: 108,
|
|
1701
|
+
bottom: 0,
|
|
1702
|
+
right: 108,
|
|
1703
|
+
},
|
|
1704
|
+
},
|
|
1705
|
+
rowBandSize: 1,
|
|
1706
|
+
colBandSize: 1,
|
|
1707
|
+
},
|
|
1708
|
+
});
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
/**
|
|
1712
|
+
* Creates a deep clone of this style
|
|
1713
|
+
* @returns New Style instance with copied properties
|
|
1714
|
+
* @example
|
|
1715
|
+
* ```typescript
|
|
1716
|
+
* const original = Style.createHeadingStyle(1);
|
|
1717
|
+
* const copy = original.clone();
|
|
1718
|
+
* copy.setRunFormatting({ color: 'FF0000' }); // Doesn't affect original
|
|
1719
|
+
* ```
|
|
1720
|
+
*/
|
|
1721
|
+
clone(): Style {
|
|
1722
|
+
// Deep copy all properties
|
|
1723
|
+
const clonedProps: StyleProperties = deepClone(this.properties);
|
|
1724
|
+
return new Style(clonedProps);
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
/**
|
|
1728
|
+
* Resets the style to its minimal state
|
|
1729
|
+
* Clears all paragraph and run formatting while preserving the style identity
|
|
1730
|
+
* @returns This style for chaining
|
|
1731
|
+
* @example
|
|
1732
|
+
* ```typescript
|
|
1733
|
+
* const style = Style.createHeadingStyle(1);
|
|
1734
|
+
* style.reset(); // Clears all formatting, keeps styleId and name
|
|
1735
|
+
* ```
|
|
1736
|
+
*/
|
|
1737
|
+
reset(): this {
|
|
1738
|
+
// Preserve identity properties
|
|
1739
|
+
const { styleId, name, type, basedOn } = this.properties;
|
|
1740
|
+
|
|
1741
|
+
// Reset to minimal properties
|
|
1742
|
+
this.properties = {
|
|
1743
|
+
styleId,
|
|
1744
|
+
name,
|
|
1745
|
+
type,
|
|
1746
|
+
basedOn,
|
|
1747
|
+
};
|
|
1748
|
+
|
|
1749
|
+
return this;
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
/**
|
|
1753
|
+
* Merges properties from another style into this one
|
|
1754
|
+
* @param otherStyle - Style to merge from
|
|
1755
|
+
* @returns This style for chaining
|
|
1756
|
+
* @example
|
|
1757
|
+
* ```typescript
|
|
1758
|
+
* const base = Style.createNormalStyle();
|
|
1759
|
+
* const override = Style.create({
|
|
1760
|
+
* styleId: 'Override',
|
|
1761
|
+
* name: 'Override',
|
|
1762
|
+
* type: 'paragraph',
|
|
1763
|
+
* runFormatting: { bold: true, color: 'FF0000' }
|
|
1764
|
+
* });
|
|
1765
|
+
* base.mergeWith(override); // base now has bold red text
|
|
1766
|
+
* ```
|
|
1767
|
+
*/
|
|
1768
|
+
mergeWith(otherStyle: Style): this {
|
|
1769
|
+
const otherProps = otherStyle.getProperties();
|
|
1770
|
+
|
|
1771
|
+
// Merge paragraph formatting
|
|
1772
|
+
if (otherProps.paragraphFormatting) {
|
|
1773
|
+
if (!this.properties.paragraphFormatting) {
|
|
1774
|
+
this.properties.paragraphFormatting = {};
|
|
1775
|
+
}
|
|
1776
|
+
|
|
1777
|
+
// Merge top-level paragraph properties
|
|
1778
|
+
if (otherProps.paragraphFormatting.alignment) {
|
|
1779
|
+
this.properties.paragraphFormatting.alignment =
|
|
1780
|
+
otherProps.paragraphFormatting.alignment;
|
|
1781
|
+
}
|
|
1782
|
+
if (otherProps.paragraphFormatting.keepNext !== undefined) {
|
|
1783
|
+
this.properties.paragraphFormatting.keepNext =
|
|
1784
|
+
otherProps.paragraphFormatting.keepNext;
|
|
1785
|
+
}
|
|
1786
|
+
if (otherProps.paragraphFormatting.keepLines !== undefined) {
|
|
1787
|
+
this.properties.paragraphFormatting.keepLines =
|
|
1788
|
+
otherProps.paragraphFormatting.keepLines;
|
|
1789
|
+
}
|
|
1790
|
+
if (otherProps.paragraphFormatting.pageBreakBefore !== undefined) {
|
|
1791
|
+
this.properties.paragraphFormatting.pageBreakBefore =
|
|
1792
|
+
otherProps.paragraphFormatting.pageBreakBefore;
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
// Merge indentation
|
|
1796
|
+
if (otherProps.paragraphFormatting.indentation) {
|
|
1797
|
+
if (!this.properties.paragraphFormatting.indentation) {
|
|
1798
|
+
this.properties.paragraphFormatting.indentation = {};
|
|
1799
|
+
}
|
|
1800
|
+
Object.assign(
|
|
1801
|
+
this.properties.paragraphFormatting.indentation,
|
|
1802
|
+
otherProps.paragraphFormatting.indentation
|
|
1803
|
+
);
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1806
|
+
// Merge spacing
|
|
1807
|
+
if (otherProps.paragraphFormatting.spacing) {
|
|
1808
|
+
if (!this.properties.paragraphFormatting.spacing) {
|
|
1809
|
+
this.properties.paragraphFormatting.spacing = {};
|
|
1810
|
+
}
|
|
1811
|
+
Object.assign(
|
|
1812
|
+
this.properties.paragraphFormatting.spacing,
|
|
1813
|
+
otherProps.paragraphFormatting.spacing
|
|
1814
|
+
);
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1818
|
+
// Merge run formatting
|
|
1819
|
+
if (otherProps.runFormatting) {
|
|
1820
|
+
if (!this.properties.runFormatting) {
|
|
1821
|
+
this.properties.runFormatting = {};
|
|
1822
|
+
}
|
|
1823
|
+
Object.assign(this.properties.runFormatting, otherProps.runFormatting);
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
// Merge other properties (but don't override styleId)
|
|
1827
|
+
if (otherProps.name) this.properties.name = otherProps.name;
|
|
1828
|
+
if (otherProps.basedOn) this.properties.basedOn = otherProps.basedOn;
|
|
1829
|
+
if (otherProps.next) this.properties.next = otherProps.next;
|
|
1830
|
+
|
|
1831
|
+
return this;
|
|
1832
|
+
}
|
|
1833
|
+
}
|