@stll/folio-core 0.37.3 → 0.37.5
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/dist/ai-edits/index.d.ts +2 -1
- package/dist/ai-edits/types.d.ts +2 -2
- package/dist/compare/content-alignment.js +213 -135
- package/dist/compare/content-types.d.ts +3 -1
- package/dist/compat/eigenpal.d.ts +2 -2
- package/dist/docx/numberingParser.d.ts +1 -13
- package/dist/docx/numberingParser.js +1 -10
- package/dist/docx/paragraphParser.js +1 -5
- package/dist/docx/paragraphPropertySource.d.ts +8 -5
- package/dist/docx/paragraphPropertySource.js +16 -4
- package/dist/docx/serializer/borderSerializer.d.ts +4 -1
- package/dist/docx/serializer/borderSerializer.js +20 -18
- package/dist/docx/serializer/commentSerializer.js +1 -1
- package/dist/docx/serializer/numberingSerializer.js +1 -1
- package/dist/docx/serializer/paragraphSerializer.js +11 -177
- package/dist/docx/serializer/runSerializer.d.ts +1 -5
- package/dist/docx/serializer/runSerializer.js +2 -129
- package/dist/docx/serializer/stylesSerializer.js +1 -1
- package/dist/docx/serializer/textFormattingSerializer.d.ts +17 -0
- package/dist/docx/serializer/textFormattingSerializer.js +142 -0
- package/dist/index.d.ts +2 -2
- package/dist/internal/paragraphFormattingSerialization.d.ts +23 -0
- package/dist/internal/paragraphFormattingSerialization.js +157 -0
- package/dist/prosemirror/attrs/index.js +13 -0
- package/dist/prosemirror/conversion/fromProseDoc.js +28 -20
- package/dist/prosemirror/conversion/toProseDoc.js +1 -0
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.d.ts +2 -63
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +9 -0
- package/dist/prosemirror/schema/nodes.d.ts +11 -1
- package/dist/prosemirror/schema/nodes.js +7 -0
- package/dist/server.d.ts +2 -1
- package/dist/version-comparison.js +23 -27
- package/package.json +1 -1
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { HIGHLIGHT_COLOR_VALUES } from "../../types/documentEnumValues.js";
|
|
2
|
+
import { isValidHexColor } from "../../utils/colorResolver.js";
|
|
3
|
+
import { roundHorizontalScalePercentForSerialization } from "../../utils/horizontalScale.js";
|
|
4
|
+
import { escapeXml, intAttr } from "./xmlUtils.js";
|
|
5
|
+
//#region src/docx/serializer/textFormattingSerializer.ts
|
|
6
|
+
const VALID_HIGHLIGHT_COLORS = new Set(HIGHLIGHT_COLOR_VALUES);
|
|
7
|
+
/**
|
|
8
|
+
* Serialize a color element (w:color)
|
|
9
|
+
*/
|
|
10
|
+
function serializeColorElement(color) {
|
|
11
|
+
if (!color) return "";
|
|
12
|
+
const { auto, rgb, themeColor, themeTint, themeShade } = color;
|
|
13
|
+
const attrs = [];
|
|
14
|
+
if (auto) attrs.push("w:val=\"auto\"");
|
|
15
|
+
else if (rgb && isValidHexColor(rgb)) attrs.push(`w:val="${escapeXml(rgb)}"`);
|
|
16
|
+
if (themeColor) attrs.push(`w:themeColor="${escapeXml(themeColor)}"`);
|
|
17
|
+
if (themeTint) attrs.push(`w:themeTint="${escapeXml(themeTint)}"`);
|
|
18
|
+
if (themeShade) attrs.push(`w:themeShade="${escapeXml(themeShade)}"`);
|
|
19
|
+
return attrs.length === 0 ? "" : `<w:color ${attrs.join(" ")}/>`;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Serialize shading properties (w:shd)
|
|
23
|
+
*/
|
|
24
|
+
function serializeShading(shading) {
|
|
25
|
+
if (!shading) return "";
|
|
26
|
+
const { pattern, color, fill } = shading;
|
|
27
|
+
const attrs = [];
|
|
28
|
+
if (pattern) attrs.push(`w:val="${escapeXml(pattern)}"`);
|
|
29
|
+
else attrs.push("w:val=\"clear\"");
|
|
30
|
+
if (color) {
|
|
31
|
+
const { rgb, auto, themeColor: _themeColor, themeTint: _themeTint, themeShade: _themeShade } = color;
|
|
32
|
+
if (rgb && isValidHexColor(rgb)) attrs.push(`w:color="${escapeXml(rgb)}"`);
|
|
33
|
+
else if (auto) attrs.push("w:color=\"auto\"");
|
|
34
|
+
}
|
|
35
|
+
if (fill) {
|
|
36
|
+
const { rgb, auto, themeColor, themeTint, themeShade } = fill;
|
|
37
|
+
if (rgb && isValidHexColor(rgb)) attrs.push(`w:fill="${escapeXml(rgb)}"`);
|
|
38
|
+
else if (auto) attrs.push("w:fill=\"auto\"");
|
|
39
|
+
if (themeColor) attrs.push(`w:themeFill="${escapeXml(themeColor)}"`);
|
|
40
|
+
if (themeTint) attrs.push(`w:themeFillTint="${escapeXml(themeTint)}"`);
|
|
41
|
+
if (themeShade) attrs.push(`w:themeFillShade="${escapeXml(themeShade)}"`);
|
|
42
|
+
}
|
|
43
|
+
return attrs.length === 0 ? "" : `<w:shd ${attrs.join(" ")}/>`;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Serialize text formatting properties to w:rPr XML
|
|
47
|
+
*/
|
|
48
|
+
function serializeTextFormatting(input) {
|
|
49
|
+
if (!input) return "";
|
|
50
|
+
const { bold, boldCs, italic, italicCs, underline, strike, doubleStrike, vertAlign, smallCaps, allCaps, hidden, color, highlight, shading, fontSize, fontSizeCs, fontFamily, language, spacing, position, scale, kerning, effect, emphasisMark, emboss, imprint, outline, shadow, rtl, cs, styleId } = input;
|
|
51
|
+
const parts = [];
|
|
52
|
+
if (styleId) parts.push(`<w:rStyle w:val="${escapeXml(styleId)}"/>`);
|
|
53
|
+
if (fontFamily) {
|
|
54
|
+
const { ascii, hAnsi, eastAsia, cs: complexScript, hint, asciiTheme, hAnsiTheme, eastAsiaTheme, csTheme } = fontFamily;
|
|
55
|
+
const fontAttrs = [];
|
|
56
|
+
if (ascii) fontAttrs.push(`w:ascii="${escapeXml(ascii)}"`);
|
|
57
|
+
if (hAnsi) fontAttrs.push(`w:hAnsi="${escapeXml(hAnsi)}"`);
|
|
58
|
+
if (eastAsia) fontAttrs.push(`w:eastAsia="${escapeXml(eastAsia)}"`);
|
|
59
|
+
if (complexScript) fontAttrs.push(`w:cs="${escapeXml(complexScript)}"`);
|
|
60
|
+
if (hint) fontAttrs.push(`w:hint="${escapeXml(hint)}"`);
|
|
61
|
+
if (asciiTheme) fontAttrs.push(`w:asciiTheme="${escapeXml(asciiTheme)}"`);
|
|
62
|
+
if (hAnsiTheme) fontAttrs.push(`w:hAnsiTheme="${escapeXml(hAnsiTheme)}"`);
|
|
63
|
+
if (eastAsiaTheme) fontAttrs.push(`w:eastAsiaTheme="${escapeXml(eastAsiaTheme)}"`);
|
|
64
|
+
if (csTheme) fontAttrs.push(`w:cstheme="${escapeXml(csTheme)}"`);
|
|
65
|
+
if (fontAttrs.length > 0) parts.push(`<w:rFonts ${fontAttrs.join(" ")}/>`);
|
|
66
|
+
}
|
|
67
|
+
if (bold === true) parts.push("<w:b/>");
|
|
68
|
+
else if (bold === false) parts.push("<w:b w:val=\"0\"/>");
|
|
69
|
+
if (boldCs === true) parts.push("<w:bCs/>");
|
|
70
|
+
else if (boldCs === false) parts.push("<w:bCs w:val=\"0\"/>");
|
|
71
|
+
if (italic === true) parts.push("<w:i/>");
|
|
72
|
+
else if (italic === false) parts.push("<w:i w:val=\"0\"/>");
|
|
73
|
+
if (italicCs === true) parts.push("<w:iCs/>");
|
|
74
|
+
else if (italicCs === false) parts.push("<w:iCs w:val=\"0\"/>");
|
|
75
|
+
if (allCaps === true) parts.push("<w:caps/>");
|
|
76
|
+
else if (allCaps === false) parts.push("<w:caps w:val=\"0\"/>");
|
|
77
|
+
if (smallCaps === true) parts.push("<w:smallCaps/>");
|
|
78
|
+
else if (smallCaps === false) parts.push("<w:smallCaps w:val=\"0\"/>");
|
|
79
|
+
if (strike === true) parts.push("<w:strike/>");
|
|
80
|
+
else if (strike === false) parts.push("<w:strike w:val=\"0\"/>");
|
|
81
|
+
if (doubleStrike === true) parts.push("<w:dstrike/>");
|
|
82
|
+
else if (doubleStrike === false) parts.push("<w:dstrike w:val=\"0\"/>");
|
|
83
|
+
if (outline === true) parts.push("<w:outline/>");
|
|
84
|
+
else if (outline === false) parts.push("<w:outline w:val=\"0\"/>");
|
|
85
|
+
if (shadow === true) parts.push("<w:shadow/>");
|
|
86
|
+
else if (shadow === false) parts.push("<w:shadow w:val=\"0\"/>");
|
|
87
|
+
if (emboss === true) parts.push("<w:emboss/>");
|
|
88
|
+
else if (emboss === false) parts.push("<w:emboss w:val=\"0\"/>");
|
|
89
|
+
if (imprint === true) parts.push("<w:imprint/>");
|
|
90
|
+
else if (imprint === false) parts.push("<w:imprint w:val=\"0\"/>");
|
|
91
|
+
if (hidden === true) parts.push("<w:vanish/>");
|
|
92
|
+
else if (hidden === false) parts.push("<w:vanish w:val=\"0\"/>");
|
|
93
|
+
const colorXml = serializeColorElement(color);
|
|
94
|
+
if (colorXml) parts.push(colorXml);
|
|
95
|
+
if (spacing !== void 0) parts.push(`<w:spacing w:val="${intAttr(spacing)}"/>`);
|
|
96
|
+
const horizontalScale = roundHorizontalScalePercentForSerialization(scale);
|
|
97
|
+
if (horizontalScale !== void 0) parts.push(`<w:w w:val="${intAttr(horizontalScale)}"/>`);
|
|
98
|
+
if (kerning !== void 0) parts.push(`<w:kern w:val="${intAttr(kerning)}"/>`);
|
|
99
|
+
if (position !== void 0) parts.push(`<w:position w:val="${intAttr(position)}"/>`);
|
|
100
|
+
if (fontSize !== void 0) parts.push(`<w:sz w:val="${intAttr(fontSize)}"/>`);
|
|
101
|
+
if (fontSizeCs !== void 0) parts.push(`<w:szCs w:val="${intAttr(fontSizeCs)}"/>`);
|
|
102
|
+
let customHighlightShadingXml = "";
|
|
103
|
+
if (highlight) {
|
|
104
|
+
if (VALID_HIGHLIGHT_COLORS.has(highlight)) parts.push(`<w:highlight w:val="${highlight}"/>`);
|
|
105
|
+
else if (!shading) {
|
|
106
|
+
const hex = highlight.replace(/^#/u, "");
|
|
107
|
+
if (/^[0-9a-fA-F]{6}$/u.test(hex)) customHighlightShadingXml = `<w:shd w:val="clear" w:color="auto" w:fill="${hex}"/>`;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (underline) {
|
|
111
|
+
const { style, color: underlineColor } = underline;
|
|
112
|
+
const uAttrs = [`w:val="${style}"`];
|
|
113
|
+
if (underlineColor) {
|
|
114
|
+
const { rgb, themeColor, themeTint, themeShade, auto: _auto } = underlineColor;
|
|
115
|
+
if (rgb && isValidHexColor(rgb)) uAttrs.push(`w:color="${escapeXml(rgb)}"`);
|
|
116
|
+
if (themeColor) uAttrs.push(`w:themeColor="${escapeXml(themeColor)}"`);
|
|
117
|
+
if (themeTint) uAttrs.push(`w:themeTint="${escapeXml(themeTint)}"`);
|
|
118
|
+
if (themeShade) uAttrs.push(`w:themeShade="${escapeXml(themeShade)}"`);
|
|
119
|
+
}
|
|
120
|
+
parts.push(`<w:u ${uAttrs.join(" ")}/>`);
|
|
121
|
+
}
|
|
122
|
+
if (effect) parts.push(`<w:effect w:val="${effect}"/>`);
|
|
123
|
+
const shadingXml = serializeShading(shading) || customHighlightShadingXml;
|
|
124
|
+
if (shadingXml) parts.push(shadingXml);
|
|
125
|
+
if (vertAlign) parts.push(`<w:vertAlign w:val="${vertAlign}"/>`);
|
|
126
|
+
if (rtl === true) parts.push("<w:rtl/>");
|
|
127
|
+
else if (rtl === false) parts.push("<w:rtl w:val=\"0\"/>");
|
|
128
|
+
if (cs === true) parts.push("<w:cs/>");
|
|
129
|
+
else if (cs === false) parts.push("<w:cs w:val=\"0\"/>");
|
|
130
|
+
if (emphasisMark) parts.push(`<w:em w:val="${emphasisMark}"/>`);
|
|
131
|
+
if (language) {
|
|
132
|
+
const { val, eastAsia, bidi } = language;
|
|
133
|
+
const languageAttrs = [];
|
|
134
|
+
if (val) languageAttrs.push(`w:val="${escapeXml(val)}"`);
|
|
135
|
+
if (eastAsia) languageAttrs.push(`w:eastAsia="${escapeXml(eastAsia)}"`);
|
|
136
|
+
if (bidi) languageAttrs.push(`w:bidi="${escapeXml(bidi)}"`);
|
|
137
|
+
if (languageAttrs.length > 0) parts.push(`<w:lang ${languageAttrs.join(" ")}/>`);
|
|
138
|
+
}
|
|
139
|
+
return parts.length === 0 ? "" : `<w:rPr>${parts.join("")}</w:rPr>`;
|
|
140
|
+
}
|
|
141
|
+
//#endregion
|
|
142
|
+
export { serializeShading, serializeTextFormatting };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { document_d_exports } from "./types/document.js";
|
|
2
|
-
import { FolioContentBlock, FolioContentContainerPathEntry, FolioContentIdStability, FolioContentInlineBooleanProperty, FolioContentInlineFormatting, FolioContentInlineFormattingPatch, FolioContentLineSpacingRule, FolioContentParagraphAlignment, FolioContentParagraphSpacing, FolioContentRun, FolioContentSnapshot, FolioContentTableLocation } from "./compare/content-types.js";
|
|
2
|
+
import { FolioContentBlock, FolioContentContainerPathEntry, FolioContentIdStability, FolioContentInlineBooleanProperty, FolioContentInlineFormatting, FolioContentInlineFormattingPatch, FolioContentLineSpacingRule, FolioContentParagraphAlignment, FolioContentParagraphKind, FolioContentParagraphSpacing, FolioContentRun, FolioContentSnapshot, FolioContentTableLocation } from "./compare/content-types.js";
|
|
3
3
|
import { FolioAIBlock, FolioAIBlockAnchor, FolioAIBlockKind, FolioAIBlockPreviewRun, FolioAIBlockStructuralBoundary, FolioAIBlockTableLocation, FolioAIComment, FolioAIEditAppliedOperation, FolioAIEditApplyMode, FolioAIEditApplyResult, FolioAIEditNormalization, FolioAIEditNormalizationCode, FolioAIEditOperation, FolioAIEditPrecondition, FolioAIEditReviewMeta, FolioAIEditSeverity, FolioAIEditSkipReason, FolioAIEditSkippedOperation, FolioAIEditSnapshot, FolioAIInlineBooleanProperty, FolioAIInlineFormatting, FolioAIInlineFormattingPatch, FolioAIParagraphSpacing, FolioAISignatureParty } from "./ai-edits/types.js";
|
|
4
4
|
import { WORD_DIFF_GRANULARITIES, WordDiffGranularity, WordDiffNormalization, WordDiffOptions, WordDiffSegment, diffWordSegments } from "./ai-edits/word-diff.js";
|
|
5
5
|
import { FolioAIEditApplyOutcome, FolioRevisionStamp, FolioWordDiffOptions, applyFolioAIEditOperations } from "./ai-edits/apply.js";
|
|
@@ -40,4 +40,4 @@ import { getGoogleFontsEnabled, setEmbeddedFontFamilyMap, setGoogleFontsEnabled
|
|
|
40
40
|
import { DOCX_CONFORMANCE_CLASSES } from "@stll/docx-core/model";
|
|
41
41
|
type Document = document_d_exports.Document;
|
|
42
42
|
type DocxConformanceClass = document_d_exports.DocxConformanceClass;
|
|
43
|
-
export { type AIBarStatus, type AIChatMode, type AICitation, type AICitationRange, type AICitationSource, type AIGenerateInput, type AISuggestion, type AISuggestionApplyMode, type AISuggestionPreset, type AISuggestionSeverity, type AISuggestionStatus, type AcceptAutocompleteResult, type AnonymizationMatch, type AnonymizationTerm, type ApplyFolioDocumentOperationsOptions, type ApplyResult, type AutocompleteSuggestionPluginOptions, type AutocompleteSuggestionState, type AutocompleteSuggestionStatus, type AutocompleteTriggerCheck, type AutocompleteTriggerOptions, type AutocompleteTriggerSkipReason, type BlockRect, COMPARE_UNSUPPORTED_REASONS, COMPARE_VERIFICATION_CAUSES, COMPARE_VERIFICATION_INVARIANTS, type CompareChange, type CompareChangeLocation, type CompareContentOptions, CompareDocxApplyError, type CompareDocxError, CompareDocxFinalParagraphMarkError, CompareDocxOperationLimitError, type CompareDocxOptions, CompareDocxParseError, CompareDocxRoundTripError, CompareDocxSerializeError, type CompareFormatRange, type CompareResult, type CompareUnsupportedPart, type CompareUnsupportedReason, type CompareVerification, type CompareVerificationCause, type CompareVerificationFailure, type CompareVerificationInvariant, type CreateEmptyDocumentOptions, DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION, DOCX_CONFORMANCE_CLASSES, type DeriveBlockIdInput, type DirectiveKind, type DirectiveRange, type Document, type DocumentPreset, type DocumentStyleCatalog, type DocumentStyleCatalogEntry, type DocumentStyleSet, type DocxCompatibility, type DocxCompatibilityContext, type DocxCompatibilityIssue, type DocxCompatibilityLocation, type DocxCompatibilityPart, type DocxConformanceClass, type EmbeddedFont, type EmbeddedFontParts, type ExtractDocumentStyleSetOptions, FOLIO_CONTENT_COMPARISON_LIMITS, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FOLIO_LINE_SPACING_RULE_VALUES, FOLIO_PARAGRAPH_ALIGNMENT_VALUES, type FinalParagraphMarkRevision, type FolioAIBlock, type FolioAIBlockAnchor, type FolioAIBlockKind, type FolioAIBlockPreviewRun, type FolioAIBlockStructuralBoundary, type FolioAIBlockTableLocation, type FolioAIComment, type FolioAIEditAppliedOperation, type FolioAIEditApplyMode, type FolioAIEditApplyOutcome, type FolioAIEditApplyResult, type FolioAIEditNormalization, type FolioAIEditNormalizationCode, type FolioAIEditOperation, type FolioAIEditPrecondition, type FolioAIEditReviewMeta, type FolioAIEditSeverity, type FolioAIEditSkipReason, type FolioAIEditSkippedOperation, type FolioAIEditSnapshot, type FolioAIInlineBooleanProperty, type FolioAIInlineFormatting, type FolioAIInlineFormattingPatch, type FolioAIParagraphSpacing, type FolioAISignatureParty, type FolioBlockId, type FolioContentBlock, type FolioContentBlockProperty, type FolioContentComparison, type FolioContentComparisonError, type FolioContentComparisonEvent, type FolioContentComparisonLimit, FolioContentComparisonLimitError, type FolioContentContainerPathEntry, type FolioContentFormatRange, type FolioContentFormattingChange, type FolioContentIdStability, type FolioContentInlineBooleanProperty, type FolioContentInlineFormatting, type FolioContentInlineFormattingPatch, type FolioContentLineSpacingRule, type FolioContentParagraphAlignment, type FolioContentParagraphFormattingPatch, type FolioContentParagraphSpacing, type FolioContentRun, type FolioContentSnapshot, type FolioContentStructuralChange, type FolioContentTableLocation, type FolioContentTextSegment, type FolioDocumentOperation, type FolioDocumentOperationAffectedTarget, type FolioDocumentOperationBatch, type FolioDocumentOperationCapabilities, type FolioDocumentOperationIssue, type FolioDocumentOperationMode, type FolioDocumentOperationPrecondition, type FolioDocumentOperationReceipt, type FolioDocumentOperationRecovery, type FolioDocumentOperationResult, type FolioDocumentOperationResultBase, type FolioDocumentOperationStatus, type FolioDocumentOperationStory, type FolioDocumentOperationType, type FolioDocumentOperationUndoFailureReason, type FolioDocumentOperationUndoHandle, type FolioDocumentOperationUndoResult, type FolioDocxCompatibilityHost, type FolioDocxCompatibilityProfile, type FolioRevisionStamp, type FolioWordDiffOptions, type ImageMeta, type ImageRef, type InspectDocxCompatibilityOptions, InvalidCompareDocxOptionsError, InvalidFolioContentComparisonError, InvalidFolioDocumentOperationBatchError, MAX_COMPARE_OPERATIONS, type MarkdownOptions, type MarkdownResult, type PositionalText, type ResolvedAnchor, STELLA_STYLE_SET_NAME, type TemplatePreviewSpan, type TemplatePreviewValue, type TemplatePreviewValues, type TemplateSlashMenuKeyAction, type TemplateSlashMenuState, UnsupportedFolioDocumentOperationVersionError, WORD_DIFF_GRANULARITIES, type WordDiffGranularity, type WordDiffNormalization, type WordDiffOptions, type WordDiffSegment, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applyFolioDocumentOperations, applySuggestions, assertSupportedFolioDocumentOperationVersion, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildEmbeddedFontFamilyMap, buildPositionalText, clearAutocompleteSuggestion, clearTemplateSlashMenu, compareContent, compareDocx, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, createStellaStyleDocumentPreset, createStellaStyleSet, currentFolioBlockId, deriveBlockId, diffWordSegments, extractDocumentStyleSet, extractDocumentStyleSetFromDocx, extractEmbeddedFonts, finishAutocompleteSuggestion, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getEmbeddedFontFaces, getFolioCaretViewportRect, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getGoogleFontsEnabled, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, inspectDocumentStyles, inspectDocumentStylesFromDocx, inspectDocxCompatibility, isFolioAIContentBlock, isFolioBlockId, isFolioDocumentOperationModeSupported, isSequentialFolioBlockId, isSuggestionStale, isSupportedFolioDocumentOperationVersion, mergeDocumentContent, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scopeEmbeddedFontFamily, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setEmbeddedFontFamilyMap, setFocusedSuggestionMeta, setGoogleFontsEnabled, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult };
|
|
43
|
+
export { type AIBarStatus, type AIChatMode, type AICitation, type AICitationRange, type AICitationSource, type AIGenerateInput, type AISuggestion, type AISuggestionApplyMode, type AISuggestionPreset, type AISuggestionSeverity, type AISuggestionStatus, type AcceptAutocompleteResult, type AnonymizationMatch, type AnonymizationTerm, type ApplyFolioDocumentOperationsOptions, type ApplyResult, type AutocompleteSuggestionPluginOptions, type AutocompleteSuggestionState, type AutocompleteSuggestionStatus, type AutocompleteTriggerCheck, type AutocompleteTriggerOptions, type AutocompleteTriggerSkipReason, type BlockRect, COMPARE_UNSUPPORTED_REASONS, COMPARE_VERIFICATION_CAUSES, COMPARE_VERIFICATION_INVARIANTS, type CompareChange, type CompareChangeLocation, type CompareContentOptions, CompareDocxApplyError, type CompareDocxError, CompareDocxFinalParagraphMarkError, CompareDocxOperationLimitError, type CompareDocxOptions, CompareDocxParseError, CompareDocxRoundTripError, CompareDocxSerializeError, type CompareFormatRange, type CompareResult, type CompareUnsupportedPart, type CompareUnsupportedReason, type CompareVerification, type CompareVerificationCause, type CompareVerificationFailure, type CompareVerificationInvariant, type CreateEmptyDocumentOptions, DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION, DOCX_CONFORMANCE_CLASSES, type DeriveBlockIdInput, type DirectiveKind, type DirectiveRange, type Document, type DocumentPreset, type DocumentStyleCatalog, type DocumentStyleCatalogEntry, type DocumentStyleSet, type DocxCompatibility, type DocxCompatibilityContext, type DocxCompatibilityIssue, type DocxCompatibilityLocation, type DocxCompatibilityPart, type DocxConformanceClass, type EmbeddedFont, type EmbeddedFontParts, type ExtractDocumentStyleSetOptions, FOLIO_CONTENT_COMPARISON_LIMITS, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FOLIO_LINE_SPACING_RULE_VALUES, FOLIO_PARAGRAPH_ALIGNMENT_VALUES, type FinalParagraphMarkRevision, type FolioAIBlock, type FolioAIBlockAnchor, type FolioAIBlockKind, type FolioAIBlockPreviewRun, type FolioAIBlockStructuralBoundary, type FolioAIBlockTableLocation, type FolioAIComment, type FolioAIEditAppliedOperation, type FolioAIEditApplyMode, type FolioAIEditApplyOutcome, type FolioAIEditApplyResult, type FolioAIEditNormalization, type FolioAIEditNormalizationCode, type FolioAIEditOperation, type FolioAIEditPrecondition, type FolioAIEditReviewMeta, type FolioAIEditSeverity, type FolioAIEditSkipReason, type FolioAIEditSkippedOperation, type FolioAIEditSnapshot, type FolioAIInlineBooleanProperty, type FolioAIInlineFormatting, type FolioAIInlineFormattingPatch, type FolioAIParagraphSpacing, type FolioAISignatureParty, type FolioBlockId, type FolioContentBlock, type FolioContentBlockProperty, type FolioContentComparison, type FolioContentComparisonError, type FolioContentComparisonEvent, type FolioContentComparisonLimit, FolioContentComparisonLimitError, type FolioContentContainerPathEntry, type FolioContentFormatRange, type FolioContentFormattingChange, type FolioContentIdStability, type FolioContentInlineBooleanProperty, type FolioContentInlineFormatting, type FolioContentInlineFormattingPatch, type FolioContentLineSpacingRule, type FolioContentParagraphAlignment, type FolioContentParagraphFormattingPatch, type FolioContentParagraphKind, type FolioContentParagraphSpacing, type FolioContentRun, type FolioContentSnapshot, type FolioContentStructuralChange, type FolioContentTableLocation, type FolioContentTextSegment, type FolioDocumentOperation, type FolioDocumentOperationAffectedTarget, type FolioDocumentOperationBatch, type FolioDocumentOperationCapabilities, type FolioDocumentOperationIssue, type FolioDocumentOperationMode, type FolioDocumentOperationPrecondition, type FolioDocumentOperationReceipt, type FolioDocumentOperationRecovery, type FolioDocumentOperationResult, type FolioDocumentOperationResultBase, type FolioDocumentOperationStatus, type FolioDocumentOperationStory, type FolioDocumentOperationType, type FolioDocumentOperationUndoFailureReason, type FolioDocumentOperationUndoHandle, type FolioDocumentOperationUndoResult, type FolioDocxCompatibilityHost, type FolioDocxCompatibilityProfile, type FolioRevisionStamp, type FolioWordDiffOptions, type ImageMeta, type ImageRef, type InspectDocxCompatibilityOptions, InvalidCompareDocxOptionsError, InvalidFolioContentComparisonError, InvalidFolioDocumentOperationBatchError, MAX_COMPARE_OPERATIONS, type MarkdownOptions, type MarkdownResult, type PositionalText, type ResolvedAnchor, STELLA_STYLE_SET_NAME, type TemplatePreviewSpan, type TemplatePreviewValue, type TemplatePreviewValues, type TemplateSlashMenuKeyAction, type TemplateSlashMenuState, UnsupportedFolioDocumentOperationVersionError, WORD_DIFF_GRANULARITIES, type WordDiffGranularity, type WordDiffNormalization, type WordDiffOptions, type WordDiffSegment, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applyFolioDocumentOperations, applySuggestions, assertSupportedFolioDocumentOperationVersion, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildEmbeddedFontFamilyMap, buildPositionalText, clearAutocompleteSuggestion, clearTemplateSlashMenu, compareContent, compareDocx, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, createStellaStyleDocumentPreset, createStellaStyleSet, currentFolioBlockId, deriveBlockId, diffWordSegments, extractDocumentStyleSet, extractDocumentStyleSetFromDocx, extractEmbeddedFonts, finishAutocompleteSuggestion, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getEmbeddedFontFaces, getFolioCaretViewportRect, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getGoogleFontsEnabled, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, inspectDocumentStyles, inspectDocumentStylesFromDocx, inspectDocxCompatibility, isFolioAIContentBlock, isFolioBlockId, isFolioDocumentOperationModeSupported, isSequentialFolioBlockId, isSuggestionStale, isSupportedFolioDocumentOperationVersion, mergeDocumentContent, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scopeEmbeddedFontFamily, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setEmbeddedFontFamilyMap, setFocusedSuggestionMeta, setGoogleFontsEnabled, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { document_d_exports } from "../types/document.js";
|
|
2
|
+
//#region src/internal/paragraphFormattingSerialization.d.ts
|
|
3
|
+
type ExhaustiveFields<Source, Classified extends keyof Source> = Exclude<keyof Source, Classified> extends never ? Source : never;
|
|
4
|
+
type ParagraphNumberingReference = document_d_exports.ParagraphFormatting["numPr"] | null;
|
|
5
|
+
type ClassifiedParagraphFormattingField = "alignment" | "bidi" | "kinsoku" | "overflowPunctuation" | "spaceBefore" | "spaceAfter" | "lineSpacing" | "lineSpacingRule" | "snapToGrid" | "beforeAutospacing" | "afterAutospacing" | "spacingExplicit" | "indentLeft" | "indentRight" | "indentFirstLine" | "hangingIndent" | "borders" | "shading" | "tabs" | "keepNext" | "keepLines" | "widowControl" | "pageBreakBefore" | "contextualSpacing" | "numPr" | "numPrFromStyle" | "outlineLevel" | "styleId" | "frame" | "suppressLineNumbers" | "suppressAutoHyphens" | "runProperties" | "runInWithNext";
|
|
6
|
+
type ExhaustiveParagraphFormatting = ExhaustiveFields<document_d_exports.ParagraphFormatting, ClassifiedParagraphFormattingField>;
|
|
7
|
+
/** Compare numbering references by their emitted id and effective level. */
|
|
8
|
+
declare const paragraphNumberingReferencesEqual: (left: ParagraphNumberingReference, right: ParagraphNumberingReference) => boolean;
|
|
9
|
+
/** Whether resolved numbering still belongs to the paragraph's style tier. */
|
|
10
|
+
declare const isStyleSourcedParagraphNumbering: (numPr: ParagraphNumberingReference, numPrFromStyle: ParagraphNumberingReference) => boolean;
|
|
11
|
+
/** Exact fallback-emission instructions for the modeled part of `w:pPr`. */
|
|
12
|
+
type ModeledParagraphFormattingEmission = Readonly<{
|
|
13
|
+
propertiesXml?: string;
|
|
14
|
+
paragraphMarkPropertiesInnerXml?: string;
|
|
15
|
+
}>;
|
|
16
|
+
/**
|
|
17
|
+
* Resolve paragraph formatting into its exact fallback `w:pPr` instructions.
|
|
18
|
+
* Every input field is classified here so parser capture fingerprints and the
|
|
19
|
+
* serializer cannot drift apart when paragraph formatting grows.
|
|
20
|
+
*/
|
|
21
|
+
declare const modelParagraphFormattingEmission: (input: ExhaustiveParagraphFormatting | undefined) => ModeledParagraphFormattingEmission;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { ModeledParagraphFormattingEmission, isStyleSourcedParagraphNumbering, modelParagraphFormattingEmission, paragraphNumberingReferencesEqual };
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { serializeBorder } from "../docx/serializer/borderSerializer.js";
|
|
2
|
+
import { serializeShading, serializeTextFormatting } from "../docx/serializer/textFormattingSerializer.js";
|
|
3
|
+
import { escapeXml, intAttr } from "../docx/serializer/xmlUtils.js";
|
|
4
|
+
//#region src/internal/paragraphFormattingSerialization.ts
|
|
5
|
+
const modelParagraphNumberingReference = (reference) => {
|
|
6
|
+
if (!reference) return null;
|
|
7
|
+
const { numId, ilvl } = reference;
|
|
8
|
+
return {
|
|
9
|
+
...numId !== void 0 ? { numId } : {},
|
|
10
|
+
...ilvl !== void 0 ? { ilvl } : {}
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
/** Compare numbering references by their emitted id and effective level. */
|
|
14
|
+
const paragraphNumberingReferencesEqual = (left, right) => {
|
|
15
|
+
const modeledLeft = modelParagraphNumberingReference(left);
|
|
16
|
+
const modeledRight = modelParagraphNumberingReference(right);
|
|
17
|
+
if (modeledLeft === null || modeledRight === null) return modeledLeft === null && modeledRight === null;
|
|
18
|
+
return modeledLeft.numId === modeledRight.numId && (modeledLeft.ilvl ?? 0) === (modeledRight.ilvl ?? 0);
|
|
19
|
+
};
|
|
20
|
+
/** Whether resolved numbering still belongs to the paragraph's style tier. */
|
|
21
|
+
const isStyleSourcedParagraphNumbering = (numPr, numPrFromStyle) => numPr != null && numPrFromStyle != null && paragraphNumberingReferencesEqual(numPr, numPrFromStyle);
|
|
22
|
+
const serializeToggle = (name, value) => {
|
|
23
|
+
if (value === true) return `<w:${name}/>`;
|
|
24
|
+
if (value === false) return `<w:${name} w:val="0"/>`;
|
|
25
|
+
return "";
|
|
26
|
+
};
|
|
27
|
+
const serializeParagraphBorders = (borders) => {
|
|
28
|
+
if (!borders) return "";
|
|
29
|
+
const { top, left, bottom, right, between, bar } = borders;
|
|
30
|
+
const parts = [
|
|
31
|
+
serializeBorder(top, "top"),
|
|
32
|
+
serializeBorder(left, "left"),
|
|
33
|
+
serializeBorder(bottom, "bottom"),
|
|
34
|
+
serializeBorder(right, "right"),
|
|
35
|
+
serializeBorder(between, "between"),
|
|
36
|
+
serializeBorder(bar, "bar")
|
|
37
|
+
].filter(Boolean);
|
|
38
|
+
return parts.length === 0 ? "" : `<w:pBdr>${parts.join("")}</w:pBdr>`;
|
|
39
|
+
};
|
|
40
|
+
const serializeTabStops = (tabs) => {
|
|
41
|
+
if (!tabs || tabs.length === 0) return "";
|
|
42
|
+
return `<w:tabs>${tabs.map((tab) => {
|
|
43
|
+
const { alignment, position, leader } = tab;
|
|
44
|
+
const attrs = [`w:val="${alignment}"`, `w:pos="${intAttr(position)}"`];
|
|
45
|
+
if (leader && leader !== "none") attrs.push(`w:leader="${leader}"`);
|
|
46
|
+
return `<w:tab ${attrs.join(" ")}/>`;
|
|
47
|
+
}).join("")}</w:tabs>`;
|
|
48
|
+
};
|
|
49
|
+
const serializeSpacing = (formatting) => {
|
|
50
|
+
const attrs = [];
|
|
51
|
+
if (formatting.spaceBefore !== void 0) attrs.push(`w:before="${intAttr(formatting.spaceBefore)}"`);
|
|
52
|
+
if (formatting.spaceAfter !== void 0) attrs.push(`w:after="${intAttr(formatting.spaceAfter)}"`);
|
|
53
|
+
if (formatting.lineSpacing !== void 0) attrs.push(`w:line="${intAttr(formatting.lineSpacing)}"`);
|
|
54
|
+
if (formatting.lineSpacingRule) attrs.push(`w:lineRule="${formatting.lineSpacingRule}"`);
|
|
55
|
+
if (formatting.beforeAutospacing !== void 0) attrs.push(`w:beforeAutospacing="${formatting.beforeAutospacing ? "1" : "0"}"`);
|
|
56
|
+
if (formatting.afterAutospacing !== void 0) attrs.push(`w:afterAutospacing="${formatting.afterAutospacing ? "1" : "0"}"`);
|
|
57
|
+
return attrs.length === 0 ? "" : `<w:spacing ${attrs.join(" ")}/>`;
|
|
58
|
+
};
|
|
59
|
+
const serializeIndentation = (formatting) => {
|
|
60
|
+
const attrs = [];
|
|
61
|
+
if (formatting.indentLeft !== void 0) attrs.push(`w:left="${intAttr(formatting.indentLeft)}"`);
|
|
62
|
+
if (formatting.indentRight !== void 0) attrs.push(`w:right="${intAttr(formatting.indentRight)}"`);
|
|
63
|
+
if (formatting.indentFirstLine !== void 0) {
|
|
64
|
+
const attribute = formatting.hangingIndent ? "hanging" : "firstLine";
|
|
65
|
+
const value = formatting.hangingIndent ? Math.abs(formatting.indentFirstLine) : formatting.indentFirstLine;
|
|
66
|
+
attrs.push(`w:${attribute}="${intAttr(value)}"`);
|
|
67
|
+
}
|
|
68
|
+
return attrs.length === 0 ? "" : `<w:ind ${attrs.join(" ")}/>`;
|
|
69
|
+
};
|
|
70
|
+
const serializeNumbering = (numPr) => {
|
|
71
|
+
const modeled = modelParagraphNumberingReference(numPr ?? null);
|
|
72
|
+
if (!modeled) return "";
|
|
73
|
+
const parts = [];
|
|
74
|
+
if (modeled.ilvl !== void 0) parts.push(`<w:ilvl w:val="${intAttr(modeled.ilvl)}"/>`);
|
|
75
|
+
if (modeled.numId !== void 0) parts.push(`<w:numId w:val="${intAttr(modeled.numId)}"/>`);
|
|
76
|
+
return parts.length === 0 ? "" : `<w:numPr>${parts.join("")}</w:numPr>`;
|
|
77
|
+
};
|
|
78
|
+
const serializeFrameProperties = (frame) => {
|
|
79
|
+
if (!frame) return "";
|
|
80
|
+
const { dropCap, lines, width, height, hSpace, vSpace, hAnchor, vAnchor, x, y, xAlign, yAlign, wrap } = frame;
|
|
81
|
+
const attrs = [];
|
|
82
|
+
if (dropCap) attrs.push(`w:dropCap="${dropCap}"`);
|
|
83
|
+
if (lines !== void 0) attrs.push(`w:lines="${intAttr(lines)}"`);
|
|
84
|
+
if (width !== void 0) attrs.push(`w:w="${intAttr(width)}"`);
|
|
85
|
+
if (height !== void 0) attrs.push(`w:h="${intAttr(height)}"`);
|
|
86
|
+
if (hSpace !== void 0) attrs.push(`w:hSpace="${intAttr(hSpace)}"`);
|
|
87
|
+
if (vSpace !== void 0) attrs.push(`w:vSpace="${intAttr(vSpace)}"`);
|
|
88
|
+
if (hAnchor) attrs.push(`w:hAnchor="${hAnchor}"`);
|
|
89
|
+
if (vAnchor) attrs.push(`w:vAnchor="${vAnchor}"`);
|
|
90
|
+
if (x !== void 0) attrs.push(`w:x="${x}"`);
|
|
91
|
+
if (y !== void 0) attrs.push(`w:y="${y}"`);
|
|
92
|
+
if (xAlign) attrs.push(`w:xAlign="${xAlign}"`);
|
|
93
|
+
if (yAlign) attrs.push(`w:yAlign="${yAlign}"`);
|
|
94
|
+
if (wrap) attrs.push(`w:wrap="${wrap}"`);
|
|
95
|
+
return attrs.length === 0 ? "" : `<w:framePr ${attrs.join(" ")}/>`;
|
|
96
|
+
};
|
|
97
|
+
const modelSpacingProvenance = (spacingExplicit) => {
|
|
98
|
+
if (spacingExplicit) {
|
|
99
|
+
const { before: _before, after: _after } = spacingExplicit;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
const extractRunPropertiesInnerXml = (runPropertiesXml) => {
|
|
103
|
+
if (!runPropertiesXml.startsWith("<w:rPr>") || !runPropertiesXml.endsWith("</w:rPr>")) return "";
|
|
104
|
+
return runPropertiesXml.slice(7, -8);
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Resolve paragraph formatting into its exact fallback `w:pPr` instructions.
|
|
108
|
+
* Every input field is classified here so parser capture fingerprints and the
|
|
109
|
+
* serializer cannot drift apart when paragraph formatting grows.
|
|
110
|
+
*/
|
|
111
|
+
const modelParagraphFormattingEmission = (input) => {
|
|
112
|
+
if (!input) return {};
|
|
113
|
+
const { alignment, bidi, kinsoku, overflowPunctuation, spaceBefore, spaceAfter, lineSpacing, lineSpacingRule, snapToGrid, beforeAutospacing, afterAutospacing, spacingExplicit, indentLeft, indentRight, indentFirstLine, hangingIndent, borders, shading, tabs, keepNext, keepLines, widowControl, pageBreakBefore, contextualSpacing, numPr, numPrFromStyle, outlineLevel, styleId, frame, suppressLineNumbers, suppressAutoHyphens, runProperties, runInWithNext } = input;
|
|
114
|
+
modelSpacingProvenance(spacingExplicit);
|
|
115
|
+
const propertiesXml = [
|
|
116
|
+
styleId ? `<w:pStyle w:val="${escapeXml(styleId)}"/>` : "",
|
|
117
|
+
serializeToggle("keepNext", keepNext),
|
|
118
|
+
serializeToggle("keepLines", keepLines),
|
|
119
|
+
serializeToggle("pageBreakBefore", pageBreakBefore),
|
|
120
|
+
serializeFrameProperties(frame),
|
|
121
|
+
serializeToggle("widowControl", widowControl),
|
|
122
|
+
isStyleSourcedParagraphNumbering(numPr, numPrFromStyle) ? "" : serializeNumbering(numPr),
|
|
123
|
+
serializeToggle("suppressLineNumbers", suppressLineNumbers),
|
|
124
|
+
serializeParagraphBorders(borders),
|
|
125
|
+
serializeShading(shading),
|
|
126
|
+
serializeTabStops(tabs),
|
|
127
|
+
serializeToggle("suppressAutoHyphens", suppressAutoHyphens),
|
|
128
|
+
serializeToggle("kinsoku", kinsoku),
|
|
129
|
+
serializeToggle("overflowPunct", overflowPunctuation),
|
|
130
|
+
serializeToggle("bidi", bidi),
|
|
131
|
+
serializeToggle("snapToGrid", snapToGrid),
|
|
132
|
+
serializeSpacing({
|
|
133
|
+
spaceBefore,
|
|
134
|
+
spaceAfter,
|
|
135
|
+
lineSpacing,
|
|
136
|
+
lineSpacingRule,
|
|
137
|
+
beforeAutospacing,
|
|
138
|
+
afterAutospacing
|
|
139
|
+
}),
|
|
140
|
+
serializeIndentation({
|
|
141
|
+
indentLeft,
|
|
142
|
+
indentRight,
|
|
143
|
+
indentFirstLine,
|
|
144
|
+
hangingIndent
|
|
145
|
+
}),
|
|
146
|
+
serializeToggle("contextualSpacing", contextualSpacing),
|
|
147
|
+
alignment ? `<w:jc w:val="${alignment}"/>` : "",
|
|
148
|
+
outlineLevel !== void 0 ? `<w:outlineLvl w:val="${outlineLevel}"/>` : ""
|
|
149
|
+
].join("");
|
|
150
|
+
const paragraphMarkPropertiesInnerXml = `${extractRunPropertiesInnerXml(serializeTextFormatting(runProperties))}${runInWithNext === true ? "<w:specVanish/>" : ""}`;
|
|
151
|
+
const emission = {};
|
|
152
|
+
if (propertiesXml) emission.propertiesXml = propertiesXml;
|
|
153
|
+
if (paragraphMarkPropertiesInnerXml) emission.paragraphMarkPropertiesInnerXml = paragraphMarkPropertiesInnerXml;
|
|
154
|
+
return emission;
|
|
155
|
+
};
|
|
156
|
+
//#endregion
|
|
157
|
+
export { isStyleSourcedParagraphNumbering, modelParagraphFormattingEmission, paragraphNumberingReferencesEqual };
|
|
@@ -2,6 +2,7 @@ import { EMPHASIS_MARK_VALUES, FIELD_TYPE_VALUES, FONT_HINT_VALUES, FONT_THEME_V
|
|
|
2
2
|
import { normalizeHorizontalScalePercent } from "../../utils/horizontalScale.js";
|
|
3
3
|
import { isParagraphDirection } from "../paragraphDirection.js";
|
|
4
4
|
import { COMPLEX_SCRIPT_RUN_PROPERTY_KEYS, RUN_FORMATTING_BOOLEAN_PROPERTIES, RUN_FORMATTING_VALUE_PROPERTIES, TRACKED_CHANGE_PROVENANCE_VALUES } from "../schema/marks.js";
|
|
5
|
+
import { TEXT_BOX_TEXT_BODY_CONTENT_STATE_TYPES } from "../schema/nodes.js";
|
|
5
6
|
import { panic } from "better-result";
|
|
6
7
|
import { DRAWING_RAW_XML_MODES, isOoxmlSymbolCharacter } from "@stll/docx-core/model";
|
|
7
8
|
//#region src/prosemirror/attrs/index.ts
|
|
@@ -540,6 +541,7 @@ const readTextBoxAttrs = (node) => {
|
|
|
540
541
|
optionalOneOf(attrs, "_docxPlacement", "textBox.attrs._docxPlacement", issues, TEXT_BOX_DOCX_PLACEMENTS);
|
|
541
542
|
optionalString(attrs, "_docxGroupId", "textBox.attrs._docxGroupId", issues);
|
|
542
543
|
optionalString(attrs, "_docxAnchorId", "textBox.attrs._docxAnchorId", issues);
|
|
544
|
+
requiredTextBoxBodyContentState(attrs, issues);
|
|
543
545
|
optionalTextBoxTrackedChange(attrs, issues);
|
|
544
546
|
optionalTextBoxInlineSdts(attrs, issues);
|
|
545
547
|
return attrsResult(attrs, issues);
|
|
@@ -1203,6 +1205,17 @@ const optionalTextBoxTrackedChange = (attrs, issues) => {
|
|
|
1203
1205
|
requiredString(info, "author", "textBox.attrs._docxTrackedChange.info.author", issues);
|
|
1204
1206
|
optionalString(info, "date", "textBox.attrs._docxTrackedChange.info.date", issues);
|
|
1205
1207
|
};
|
|
1208
|
+
const requiredTextBoxBodyContentState = (attrs, issues) => {
|
|
1209
|
+
const value = attrs["_docxTextBodyContentState"];
|
|
1210
|
+
if (!isRecord(value)) {
|
|
1211
|
+
issues.push({
|
|
1212
|
+
path: "textBox.attrs._docxTextBodyContentState",
|
|
1213
|
+
message: "Expected an object."
|
|
1214
|
+
});
|
|
1215
|
+
return;
|
|
1216
|
+
}
|
|
1217
|
+
requiredOneOf(value, "type", "textBox.attrs._docxTextBodyContentState.type", issues, TEXT_BOX_TEXT_BODY_CONTENT_STATE_TYPES);
|
|
1218
|
+
};
|
|
1206
1219
|
const optionalTextBoxInlineSdts = (attrs, issues) => {
|
|
1207
1220
|
const value = attrs["_docxInlineSdts"];
|
|
1208
1221
|
if (value === void 0 || value === null) return;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { numPrEqual } from "../../docx/numberingParser.js";
|
|
2
1
|
import { PROSE_PARAGRAPH_SOURCE_CONTRACT_ATTR, ParagraphPropertySourceValidationError, copyDocumentParagraphPropertySourceContract, copyDocumentParagraphPropertySources, copyParagraphPropertyCapture, copyParagraphPropertySource, decodeTableCellParagraphSourcePayload, getDocumentParagraphPropertySourceContract, getParagraphPropertySource, getParagraphPropertySourceCandidate, getParagraphPropertySourceToken, getParagraphPropertySourceTransferId, getProseDocumentParagraphPropertySourceContract, getProseParagraphPropertySourceToken, isParagraphPropertySourceToken, linkParagraphPropertySourceCandidate, paragraphPropertySourceBelongsToDocument, paragraphPropertySourceTokenMatchesContract, recreateProseNodeWithParagraphPropertySource, restoreTableCellsWithParagraphPropertySources, visitDocumentStoryParagraphs, visitTableCellParagraphPropertySourceBindings } from "../../docx/paragraphPropertySource.js";
|
|
3
2
|
import { visitDocxParagraphs } from "../../docx/paragraphTraversal.js";
|
|
4
3
|
import { ShapeOutlineStyleSchema, narrowEnum } from "../../docx/parserEnums.js";
|
|
5
4
|
import { DATE_UTC_ATTRIBUTE } from "../../docx/trackedChangeInfo.js";
|
|
5
|
+
import { isStyleSourcedParagraphNumbering, modelParagraphFormattingEmission, paragraphNumberingReferencesEqual } from "../../internal/paragraphFormattingSerialization.js";
|
|
6
6
|
import { createStyleEngine } from "../../style-engine/styleEngine.js";
|
|
7
7
|
import { OUTLINE_STYLE_CSS_ALIASES, normalizeShapeTextAnchor } from "../../types/documentEnumValues.js";
|
|
8
8
|
import { canonicalJson } from "../../utils/canonicalJson.js";
|
|
@@ -106,9 +106,10 @@ const uniqueParagraphsById = (content, includeTransferIds = false) => {
|
|
|
106
106
|
const restoreParagraphPropertySource = (paragraph, baseParagraph) => {
|
|
107
107
|
copyParagraphPropertySource(paragraph, baseParagraph);
|
|
108
108
|
const baseFormatting = baseParagraph.formatting;
|
|
109
|
-
if (!baseFormatting
|
|
110
|
-
const { numPr, numPrFromStyle
|
|
111
|
-
if (
|
|
109
|
+
if (!baseFormatting) return;
|
|
110
|
+
const { numPr, numPrFromStyle } = baseFormatting;
|
|
111
|
+
if (!numPr || !numPrFromStyle || !isStyleSourcedParagraphNumbering(numPr, numPrFromStyle)) return;
|
|
112
|
+
if (canonicalJson(modelParagraphFormattingEmission(paragraph.formatting)) !== canonicalJson(modelParagraphFormattingEmission(baseFormatting))) return;
|
|
112
113
|
paragraph.formatting = {
|
|
113
114
|
...paragraph.formatting,
|
|
114
115
|
numPr,
|
|
@@ -777,15 +778,6 @@ const propertyChangeFromAttrs = (change) => {
|
|
|
777
778
|
...currentFormatting !== void 0 && { currentFormatting }
|
|
778
779
|
};
|
|
779
780
|
};
|
|
780
|
-
/**
|
|
781
|
-
* Whether the paragraph's numbering still comes verbatim from its style —
|
|
782
|
-
* serialize no direct `<w:numPr>` then. The moment a list command changes
|
|
783
|
-
* `numPr` the values diverge and the numbering serializes as direct
|
|
784
|
-
* formatting, so a stale provenance value can never swallow a user edit.
|
|
785
|
-
*/
|
|
786
|
-
function isStyleSourcedNumPr(attrs) {
|
|
787
|
-
return attrs.numPrFromStyle != null && attrs.numPr != null && numPrEqual(attrs.numPr, attrs.numPrFromStyle);
|
|
788
|
-
}
|
|
789
781
|
function assignBooleanToggle(result, attrs, orig, key) {
|
|
790
782
|
const value = attrs[key] ?? void 0;
|
|
791
783
|
if (value === (orig[key] ?? void 0)) return;
|
|
@@ -834,10 +826,10 @@ function paragraphAttrsToFormatting(attrs) {
|
|
|
834
826
|
else Reflect.deleteProperty(result, "lineSpacingRule");
|
|
835
827
|
if (directAlignment === void 0) Reflect.deleteProperty(result, "alignment");
|
|
836
828
|
else result.alignment = directAlignment;
|
|
837
|
-
if (
|
|
829
|
+
if (isStyleSourcedParagraphNumbering(attrs.numPr, attrs.numPrFromStyle)) {
|
|
838
830
|
delete result.numPr;
|
|
839
831
|
delete result.numPrFromStyle;
|
|
840
|
-
} else if (attrs.numPr !== orig.numPr && !
|
|
832
|
+
} else if (attrs.numPr !== orig.numPr && !paragraphNumberingReferencesEqual(attrs.numPr, orig.numPr)) {
|
|
841
833
|
if (attrs.numPr) result.numPr = attrs.numPr;
|
|
842
834
|
else delete result.numPr;
|
|
843
835
|
delete result.numPrFromStyle;
|
|
@@ -874,7 +866,7 @@ function paragraphAttrsToFormatting(attrs) {
|
|
|
874
866
|
if (attrs.indentRight) f.indentRight = attrs.indentRight;
|
|
875
867
|
if (attrs.indentFirstLine) f.indentFirstLine = attrs.indentFirstLine;
|
|
876
868
|
if (attrs.hangingIndent) f.hangingIndent = attrs.hangingIndent;
|
|
877
|
-
if (attrs.numPr && !
|
|
869
|
+
if (attrs.numPr && !isStyleSourcedParagraphNumbering(attrs.numPr, attrs.numPrFromStyle)) f.numPr = attrs.numPr;
|
|
878
870
|
if (attrs.styleId) f.styleId = attrs.styleId;
|
|
879
871
|
if (attrs.borders) f.borders = attrs.borders;
|
|
880
872
|
if (attrs.shading) f.shading = attrs.shading;
|
|
@@ -2862,6 +2854,24 @@ function tableCellAttrsToFormatting(attrs) {
|
|
|
2862
2854
|
if (attrs.margins) f.margins = buildCellMarginsFromAttrs(attrs.margins);
|
|
2863
2855
|
return f;
|
|
2864
2856
|
}
|
|
2857
|
+
const isUnchangedSourceEmptyPlaceholder = (blocks) => {
|
|
2858
|
+
const paragraph = blocks.at(0);
|
|
2859
|
+
if (blocks.length !== 1 || paragraph?.type !== "paragraph" || paragraph.content.length !== 0) return false;
|
|
2860
|
+
return Object.keys(paragraph).every((key) => key === "type" || key === "content" || key === "paraId" || key === "textId");
|
|
2861
|
+
};
|
|
2862
|
+
const projectTextBoxBodyContent = (state, blocks) => {
|
|
2863
|
+
switch (state.type) {
|
|
2864
|
+
case "source-empty": return isUnchangedSourceEmptyPlaceholder(blocks) ? { type: "source-empty" } : {
|
|
2865
|
+
type: "authored",
|
|
2866
|
+
content: blocks
|
|
2867
|
+
};
|
|
2868
|
+
case "authored": return {
|
|
2869
|
+
type: "authored",
|
|
2870
|
+
content: blocks
|
|
2871
|
+
};
|
|
2872
|
+
default: return state;
|
|
2873
|
+
}
|
|
2874
|
+
};
|
|
2865
2875
|
/**
|
|
2866
2876
|
* Convert a ProseMirror textBox node back to a Paragraph wrapping a ShapeContent run.
|
|
2867
2877
|
* The text box content becomes a Shape with textBody.
|
|
@@ -2874,6 +2884,7 @@ function convertPMTextBox(node, styleResolver = null) {
|
|
|
2874
2884
|
if (child.type.name === "paragraph") childBlocks.push(convertPMParagraph(child, void 0, void 0, styleResolver));
|
|
2875
2885
|
else if (child.type.name === "table") childBlocks.push(convertPMTable(child, void 0, styleResolver));
|
|
2876
2886
|
});
|
|
2887
|
+
const textBodyContent = projectTextBoxBodyContent(attrs._docxTextBodyContentState, childBlocks);
|
|
2877
2888
|
const shape = {
|
|
2878
2889
|
type: "shape",
|
|
2879
2890
|
shapeType: "textBox",
|
|
@@ -2882,10 +2893,7 @@ function convertPMTextBox(node, styleResolver = null) {
|
|
|
2882
2893
|
height: attrs.height ? pixelsToEmu(attrs.height) : 0
|
|
2883
2894
|
},
|
|
2884
2895
|
textBody: {
|
|
2885
|
-
content:
|
|
2886
|
-
type: "paragraph",
|
|
2887
|
-
content: []
|
|
2888
|
-
}],
|
|
2896
|
+
content: textBodyContent.type === "source-empty" ? [] : textBodyContent.content,
|
|
2889
2897
|
...attrs.autoFit !== void 0 ? { autoFit: attrs.autoFit } : {},
|
|
2890
2898
|
...attrs.textWrap !== void 0 ? { textWrap: attrs.textWrap } : {},
|
|
2891
2899
|
...verticalAlign !== void 0 ? { anchor: verticalAlign } : {},
|
|
@@ -2259,6 +2259,7 @@ function convertTextBox(textBox, styleResolver, options) {
|
|
|
2259
2259
|
_docxPlacement: options.placement,
|
|
2260
2260
|
_docxGroupId: options.groupId,
|
|
2261
2261
|
_docxAnchorId: options.anchorId,
|
|
2262
|
+
_docxTextBodyContentState: textBox.content.length === 0 ? { type: "source-empty" } : { type: "authored" },
|
|
2262
2263
|
_docxTrackedChange: options.trackedChange,
|
|
2263
2264
|
_docxInlineSdts: options.inlineSdts.length > 0 ? options.inlineSdts : void 0
|
|
2264
2265
|
}, contentNodes);
|
|
@@ -1,68 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { OutlineStyleAttr } from "../../../types/documentEnumValues.js";
|
|
3
|
-
import { ImagePositionAttrs, TextBoxAttrs as TextBoxAttrs$1 } from "../../schema/nodes.js";
|
|
1
|
+
import { TextBoxAttrs as TextBoxAttrs$1 } from "../../schema/nodes.js";
|
|
4
2
|
import { NodeExtension } from "../types.js";
|
|
5
3
|
//#region src/prosemirror/extensions/nodes/TextBoxExtension.d.ts
|
|
6
|
-
type TextBoxAttrs =
|
|
7
|
-
/** Width in pixels */
|
|
8
|
-
width?: number;
|
|
9
|
-
/** Height in pixels */
|
|
10
|
-
height?: number;
|
|
11
|
-
/** Text fitting behavior */
|
|
12
|
-
autoFit?: document_d_exports.ShapeTextBody["autoFit"];
|
|
13
|
-
/** Horizontal text wrapping inside the box */
|
|
14
|
-
textWrap?: document_d_exports.ShapeTextBody["textWrap"];
|
|
15
|
-
/** Unique identifier */
|
|
16
|
-
textBoxId?: string;
|
|
17
|
-
/** Fill color as CSS color */
|
|
18
|
-
fillColor?: string;
|
|
19
|
-
/** Outline width in pixels */
|
|
20
|
-
outlineWidth?: number;
|
|
21
|
-
/** Outline color as CSS color */
|
|
22
|
-
outlineColor?: string;
|
|
23
|
-
/** Outline dash style, or `"none"` for an explicit no-outline. */
|
|
24
|
-
outlineStyle?: OutlineStyleAttr;
|
|
25
|
-
/** DrawingML rotation and/or flips, serialized as CSS transform functions. */
|
|
26
|
-
transform?: string;
|
|
27
|
-
/** Internal margin top in pixels */
|
|
28
|
-
marginTop?: number;
|
|
29
|
-
/** Internal margin bottom in pixels */
|
|
30
|
-
marginBottom?: number;
|
|
31
|
-
/** Internal margin left in pixels */
|
|
32
|
-
marginLeft?: number;
|
|
33
|
-
/** Internal margin right in pixels */
|
|
34
|
-
marginRight?: number;
|
|
35
|
-
/** Vertical text alignment */
|
|
36
|
-
verticalAlign?: string;
|
|
37
|
-
/** Display mode */
|
|
38
|
-
displayMode?: "inline" | "float" | "block";
|
|
39
|
-
/** CSS float direction */
|
|
40
|
-
cssFloat?: "left" | "right" | "none";
|
|
41
|
-
/** Wrap type */
|
|
42
|
-
wrapType?: document_d_exports.ImageWrap["type"];
|
|
43
|
-
/** OOXML wrapText direction for anchored text boxes (eigenpal #474). */
|
|
44
|
-
wrapText?: "bothSides" | "left" | "right" | "largest";
|
|
45
|
-
/** Wrap distance from top edge, in pixels (OOXML distT, EMU-converted). */
|
|
46
|
-
distTop?: number;
|
|
47
|
-
/** Wrap distance from bottom edge, in pixels. */
|
|
48
|
-
distBottom?: number;
|
|
49
|
-
/** Wrap distance from left edge, in pixels. */
|
|
50
|
-
distLeft?: number;
|
|
51
|
-
/** Wrap distance from right edge, in pixels. */
|
|
52
|
-
distRight?: number;
|
|
53
|
-
/** Position for floating/anchored text boxes. */
|
|
54
|
-
position?: ImagePositionAttrs;
|
|
55
|
-
/** Original DOCX placement hint for save-path reconstruction. */
|
|
56
|
-
_docxPlacement?: "standalone" | "inlineWithPrevious";
|
|
57
|
-
/** Original DOCX paragraph group for standalone text-box reconstruction. */
|
|
58
|
-
_docxGroupId?: string;
|
|
59
|
-
/** Inline anchor linking this block node to its source run position. */
|
|
60
|
-
_docxAnchorId?: string;
|
|
61
|
-
/** Original run-level revision wrapper for save-path reconstruction. */
|
|
62
|
-
_docxTrackedChange?: TextBoxAttrs$1["_docxTrackedChange"];
|
|
63
|
-
/** Original inline content-control ancestry for save-path reconstruction. */
|
|
64
|
-
_docxInlineSdts?: TextBoxAttrs$1["_docxInlineSdts"];
|
|
65
|
-
};
|
|
4
|
+
type TextBoxAttrs = TextBoxAttrs$1;
|
|
66
5
|
declare const TextBoxExtension: (options?: Partial<Record<string, unknown>> | undefined) => NodeExtension;
|
|
67
6
|
//#endregion
|
|
68
7
|
export { TextBoxAttrs, TextBoxExtension };
|
|
@@ -2,6 +2,13 @@ import { IMAGE_WRAP_TYPE_VALUES, normalizeShapeTextAnchor } from "../../../types
|
|
|
2
2
|
import { expectTextBoxAttrs } from "../../attrs/index.js";
|
|
3
3
|
import { createNodeExtension } from "../create.js";
|
|
4
4
|
//#region src/prosemirror/extensions/nodes/TextBoxExtension.ts
|
|
5
|
+
/**
|
|
6
|
+
* TextBox Extension — editable text box node
|
|
7
|
+
*
|
|
8
|
+
* An isolating block node that contains paragraphs (and tables).
|
|
9
|
+
* Rendered as a positioned container with optional fill, outline, and margins.
|
|
10
|
+
* Supports inline and floating positioning.
|
|
11
|
+
*/
|
|
5
12
|
function parseTextBoxPosition(raw) {
|
|
6
13
|
if (!raw) return;
|
|
7
14
|
try {
|
|
@@ -60,6 +67,7 @@ const TextBoxExtension = createNodeExtension({
|
|
|
60
67
|
_docxPlacement: { default: null },
|
|
61
68
|
_docxGroupId: { default: null },
|
|
62
69
|
_docxAnchorId: { default: null },
|
|
70
|
+
_docxTextBodyContentState: { default: { type: "authored" } },
|
|
63
71
|
_docxTrackedChange: { default: null },
|
|
64
72
|
_docxInlineSdts: { default: null }
|
|
65
73
|
},
|
|
@@ -74,6 +82,7 @@ const TextBoxExtension = createNodeExtension({
|
|
|
74
82
|
const textWrap = parseTextBoxTextWrap(d["textWrap"]);
|
|
75
83
|
const verticalAlign = parseTextBoxVerticalAlign(d["verticalAlign"]);
|
|
76
84
|
return {
|
|
85
|
+
_docxTextBodyContentState: { type: "authored" },
|
|
77
86
|
...d["width"] ? { width: Number(d["width"]) } : {},
|
|
78
87
|
...d["height"] ? { height: Number(d["height"]) } : {},
|
|
79
88
|
...autoFit ? { autoFit } : {},
|