@a3s-lab/office 0.10.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/COLLABORATION_ROADMAP.md +22 -12
  2. package/README.md +40 -15
  3. package/dist/{0~4705.js → 0~5093.js} +959 -10
  4. package/dist/0~document-editor.js +1 -0
  5. package/dist/0~spreadsheet-editor.js +189 -104
  6. package/dist/0~work-docx-export.js +225 -6
  7. package/dist/0~work-docx-import.js +26 -755
  8. package/dist/0~work-office-diagnostics.js +12 -8
  9. package/dist/0~work-pptx-import.js +2 -2
  10. package/dist/4104.js +330 -122
  11. package/dist/4476.js +82 -65
  12. package/dist/8715.js +41 -3
  13. package/dist/8928.js +448 -137
  14. package/dist/9356.js +126 -8
  15. package/dist/core.d.ts +1 -0
  16. package/dist/internal/features/work/editors/spreadsheet-editor-support.d.ts +1 -0
  17. package/dist/internal/features/work/editors/use-spreadsheet-collaboration.d.ts +2 -1
  18. package/dist/internal/features/work/spreadsheet-sparse.d.ts +5 -0
  19. package/dist/internal/features/work/work-document-file-io.d.ts +2 -1
  20. package/dist/internal/features/work/work-document-format-change-tracking.d.ts +1 -1
  21. package/dist/internal/features/work/work-document-paragraph-format-change-tracking.d.ts +7 -0
  22. package/dist/internal/features/work/work-document-paragraph-format-changes.d.ts +8 -0
  23. package/dist/internal/features/work/work-docx-import.d.ts +5 -2
  24. package/dist/internal/features/work/work-docx-paragraph-alignment-import.d.ts +1 -0
  25. package/dist/internal/features/work/work-docx-paragraph-borders-import.d.ts +1 -0
  26. package/dist/internal/features/work/work-docx-paragraph-direction-import.d.ts +1 -0
  27. package/dist/internal/features/work/work-docx-paragraph-format-change-export.d.ts +13 -0
  28. package/dist/internal/features/work/work-docx-paragraph-format-change-import.d.ts +17 -0
  29. package/dist/internal/features/work/work-docx-paragraph-indent-import.d.ts +1 -0
  30. package/dist/internal/features/work/work-docx-paragraph-pagination-import.d.ts +1 -0
  31. package/dist/internal/features/work/work-docx-paragraph-shading-import.d.ts +1 -0
  32. package/dist/internal/features/work/work-docx-paragraph-spacing-import.d.ts +1 -0
  33. package/dist/internal/features/work/work-docx-tab-stop-import.d.ts +1 -0
  34. package/dist/internal/features/work/work-file-data.d.ts +7 -1
  35. package/dist/internal/features/work/work-file-import.d.ts +28 -0
  36. package/dist/internal/features/work/work-file-io.d.ts +2 -1
  37. package/dist/internal/features/work/work-markdown-file-io.d.ts +2 -1
  38. package/dist/internal/features/work/work-office-diagnostics.d.ts +3 -2
  39. package/dist/internal/features/work/work-pptx-import.d.ts +1 -1
  40. package/dist/internal/features/work/work-presentation-file-io.d.ts +2 -1
  41. package/dist/internal/features/work/work-spreadsheet-protection.d.ts +2 -0
  42. package/dist/internal/features/work/work-types.d.ts +23 -1
  43. package/dist/internal/features/work/work-xlsx-interop.d.ts +4 -14
  44. package/dist/office-kernel.wasm +0 -0
  45. package/dist/styles.css +8 -0
  46. package/docs/latest/en/browser-editor-architecture.md +18 -0
  47. package/package.json +10 -4
@@ -1,5 +1,5 @@
1
1
  import jszip from "jszip";
2
- import { normalizeDocumentBookmarkName, applyDocumentImageIdentityToElement, DOCUMENT_PAGE_BORDER_EDGES, createDocumentImageIdentityRegistry, normalizeDocumentColumns, normalizeDocumentTableVerticalAlign, uniqueDocumentParagraphIdentity, documentTableColumnPercentagesFromElement, documentTableCellMarginOverridesFromElement, applyDocumentTableRowIdentityToElement, normalizeDocumentBookmarksHtml, documentImageIdentityFromElement, documentTableGeometryFromElement, normalizeDocumentTableRowHeightRule, documentNoteKey, normalizeDocumentParagraphBorders, normalizeDocumentTableBorderWidth, normalizeDocumentParagraphId, normalizeDocumentTableBorderStyle, normalizeDocumentBookmarkReferencesHtml, documentCitationInstruction, parseDocumentParagraphBordersElement, documentImageWrapContourFromElement, documentImagePositionFromElement, normalizeDocumentPageChrome, documentPageMarginsForLayout, normalizeDocumentImageLayer, documentBookmarkReferenceInstruction, documentImageCropFromElement, normalizeDocumentPageBorders, documentImageLayerFromElement, parseDocxThemeReference, documentCaptionLabel, documentCaptionKind, applyDocumentParagraphIdentityToElement, isContourImageLayout, normalizeDocumentImageIdentity, normalizeTableColor, documentTableBordersFromElement, documentSections, createDocumentParagraphIdentityRegistry, documentCitationTags, docxDocumentFieldKind, wrapsBesideImage, DocxThemePatchCollector, defaultDocumentImageWrapContour, normalizeDocumentParagraphIdentity, normalizeDocumentPaperSource, documentEquationFromElement, DOCUMENT_PARAGRAPH_BORDER_EDGES, parseDocumentCharacterFormatting, patchDocxThemeReferences, parseDocumentParagraphShadingElement, documentParagraphIdentityFromElement, normalizeDocumentEquation, documentTableRowIdentityFromElement, collectDocumentNotes, normalizeDocumentBookmarkNativeId, DOCUMENT_PAGE_MARGIN_KEYS, uniqueDocumentImageIdentity, documentImageLayoutFromElement, documentPageHorizontalMarginTwips, documentPageGeometryForLayout, normalizeDocumentPageMargins, documentNoteKind } from "./8928.js";
2
+ import { normalizeDocumentBookmarkName, applyDocumentImageIdentityToElement, DOCUMENT_PAGE_BORDER_EDGES, createDocumentImageIdentityRegistry, normalizeDocumentColumns, normalizeDocumentTableVerticalAlign, uniqueDocumentParagraphIdentity, documentTableColumnPercentagesFromElement, documentTableCellMarginOverridesFromElement, applyDocumentTableRowIdentityToElement, normalizeDocumentBookmarksHtml, documentImageIdentityFromElement, documentTableGeometryFromElement, normalizeDocumentTableRowHeightRule, documentNoteKey, normalizeDocumentParagraphBorders, normalizeDocumentTableBorderWidth, normalizeDocumentParagraphId, normalizeDocumentTableBorderStyle, normalizeDocumentBookmarkReferencesHtml, documentCitationInstruction, parseDocumentParagraphBordersElement, documentImageWrapContourFromElement, documentImagePositionFromElement, normalizeDocumentPageChrome, documentPageMarginsForLayout, normalizeDocumentImageLayer, documentBookmarkReferenceInstruction, documentImageCropFromElement, normalizeDocumentPageBorders, documentImageLayerFromElement, parseDocxThemeReference, documentCaptionLabel, documentCaptionKind, applyDocumentParagraphIdentityToElement, isContourImageLayout, normalizeDocumentImageIdentity, normalizeTableColor, documentTableBordersFromElement, documentSections, createDocumentParagraphIdentityRegistry, documentCitationTags, docxDocumentFieldKind, wrapsBesideImage, DocxThemePatchCollector, defaultDocumentImageWrapContour, normalizeDocumentParagraphIdentity, normalizeDocumentPaperSource, documentEquationFromElement, DOCUMENT_PARAGRAPH_BORDER_EDGES, parseDocumentCharacterFormatting, patchDocxThemeReferences, parseDocumentParagraphShadingElement, documentParagraphIdentityFromElement, normalizeDocumentEquation, parseDocumentParagraphFormatting, documentTableRowIdentityFromElement, normalizeDocumentBookmarkNativeId, collectDocumentNotes, DOCUMENT_PAGE_MARGIN_KEYS, uniqueDocumentImageIdentity, documentImageLayoutFromElement, documentPageHorizontalMarginTwips, documentPageGeometryForLayout, normalizeDocumentPageMargins, documentNoteKind } from "./8928.js";
3
3
  import { serializeUtf8Xml, directChildren, xmlNamespacePrefix, parseXml, decodeXmlBytes, descendants, resolvePartTarget, directChild, attribute as work_ooxml_package_attribute } from "./5184.js";
4
4
  import { assignDocxNoteIds, patchDocxPageColor, normalizeDocxCommentId, assignDocxCommentThreads } from "./0~4980.js";
5
5
  import { paragraphTabStops, mergeDocxIgnorableExtensionsAtPairs, patchDocxBibliography, XMLNS_NAMESPACE as work_docx_settings_xml_XMLNS_NAMESPACE, paragraphAlignment, paragraphSpacingOptions, xmlNamespaceUri, hasNonWhitespaceXmlText, cloneXmlElement, cssColorToHex, DocxParagraphDefaultCollapsedPatchCollector, assertXmlRoot, xmlDeclaredPrefix, paragraphIndent, domDirection, DOCX_WORDPROCESSING_NAMESPACES, paragraphBidirectional, XML_NAMESPACE as work_docx_settings_xml_XML_NAMESPACE, patchDocxParagraphDefaultCollapsed, xmlAttributeNamespace, dataBoolean, mergeDocxIgnorableExtensions, parseDocxColorSchemeMappingElement, paragraphPaginationOptions, DOCX_COLOR_SCHEME_MAPPING_ATTRIBUTES, xmlAttributeLocalName, cssFontSize, paragraphDirectionOptions, cssFontFamily } from "./0~2805.js";
@@ -3104,10 +3104,223 @@ async function patchDocxNumberingRestartRules(buffer, rules) {
3104
3104
  function wordQualifiedName(root, localName) {
3105
3105
  return `${xmlNamespacePrefix(root, work_docx_numbering_WORD_NAMESPACE) ?? root.prefix ?? 'w'}:${localName}`;
3106
3106
  }
3107
+ const work_docx_paragraph_format_change_export_WORD_NAMESPACE = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';
3108
+ const work_docx_paragraph_format_change_export_WORD_2012_NAMESPACE = 'http://schemas.microsoft.com/office/word/2012/wordml';
3109
+ const work_docx_paragraph_format_change_export_XMLNS_NAMESPACE = 'http://www.w3.org/2000/xmlns/';
3110
+ const MAX_PARAGRAPH_FORMATTING_CHANGE_PATCHES = 65536;
3111
+ const PARAGRAPH_PART_PATTERN = /^word\/(?:document|header\d*|footer\d*|footnotes|endnotes)\.xml$/i;
3112
+ class DocxParagraphFormattingChangePatchCollector {
3113
+ patches = [];
3114
+ register(element, id) {
3115
+ if ('paragraph-formatting' !== element.dataset.changeKind || !element.hasAttribute('data-document-change')) return null;
3116
+ const key = element.dataset.changeId?.trim() ?? '';
3117
+ const author = element.dataset.changeAuthor?.trim() ?? '';
3118
+ const date = work_docx_paragraph_format_change_export_normalizedRevisionDate(element.dataset.changeDate);
3119
+ const before = element.dataset.changeBefore ?? '';
3120
+ if (!key || !author || author.length > 255 || !parseDocumentParagraphFormatting(before)) throw new Error('Document contains an invalid paragraph-formatting revision.');
3121
+ if (this.patches.length >= MAX_PARAGRAPH_FORMATTING_CHANGE_PATCHES) throw new Error('Document exceeds the paragraph-formatting revision limit.');
3122
+ const marker = `__A3S_WORK_PARAGRAPH_FORMAT_CHANGE_EXPORT_${this.patches.length + 1}__`;
3123
+ this.patches.push({
3124
+ marker,
3125
+ id,
3126
+ author,
3127
+ date,
3128
+ before
3129
+ });
3130
+ return marker;
3131
+ }
3132
+ }
3133
+ async function patchDocxParagraphFormattingChanges(buffer, patches) {
3134
+ if (!patches.length) return buffer;
3135
+ if (patches.length > MAX_PARAGRAPH_FORMATTING_CHANGE_PATCHES) throw new Error('Document exceeds the paragraph-formatting revision limit.');
3136
+ const archive = await jszip.loadAsync(buffer);
3137
+ const byMarker = new Map(patches.map((patch)=>[
3138
+ patch.marker,
3139
+ patch
3140
+ ]));
3141
+ const applied = new Set();
3142
+ for (const entry of Object.values(archive.files)){
3143
+ if (entry.dir || !PARAGRAPH_PART_PATTERN.test(entry.name)) continue;
3144
+ const document = parseXml(decodeXmlBytes(await entry.async('uint8array'), `generated DOCX ${entry.name}`), `generated DOCX ${entry.name}`);
3145
+ let changed = false;
3146
+ for (const paragraph of descendants(document, 'p').filter((element)=>element.namespaceURI === work_docx_paragraph_format_change_export_WORD_NAMESPACE)){
3147
+ const marker = paragraphFormattingMarker(paragraph, byMarker);
3148
+ if (marker) {
3149
+ setParagraphFormattingChange(document, paragraph, marker.patch);
3150
+ marker.run.remove();
3151
+ applied.add(marker.patch.marker);
3152
+ changed = true;
3153
+ }
3154
+ }
3155
+ if (changed) archive.file(entry.name, serializeUtf8Xml(document));
3156
+ }
3157
+ const missing = patches.filter((patch)=>!applied.has(patch.marker));
3158
+ if (missing.length) throw new Error(`DOCX paragraph-formatting revision markers were not emitted: ${missing.map((patch)=>patch.marker).join(', ')}.`);
3159
+ return archive.generateAsync({
3160
+ type: 'arraybuffer'
3161
+ });
3162
+ }
3163
+ function paragraphFormattingMarker(paragraph, patches) {
3164
+ const matches = directChildren(paragraph, 'r').flatMap((run)=>{
3165
+ if (run.namespaceURI !== work_docx_paragraph_format_change_export_WORD_NAMESPACE) return [];
3166
+ const texts = directChildren(run, 't').filter((text)=>text.namespaceURI === work_docx_paragraph_format_change_export_WORD_NAMESPACE);
3167
+ if (1 !== texts.length || !work_docx_paragraph_format_change_export_runHasOnlyMarkerText(run, texts[0])) return [];
3168
+ const patch = patches.get(texts[0]?.textContent ?? '');
3169
+ return patch ? [
3170
+ {
3171
+ patch,
3172
+ run
3173
+ }
3174
+ ] : [];
3175
+ });
3176
+ if (matches.length > 1) throw new Error('Generated DOCX paragraph has duplicate revision markers.');
3177
+ return matches[0] ?? null;
3178
+ }
3179
+ function work_docx_paragraph_format_change_export_runHasOnlyMarkerText(run, markerText) {
3180
+ return Boolean(markerText && directChildren(run).every((child)=>child === markerText || 'rPr' === child.localName && child.namespaceURI === work_docx_paragraph_format_change_export_WORD_NAMESPACE));
3181
+ }
3182
+ function setParagraphFormattingChange(document, paragraph, patch) {
3183
+ const propertyNodes = directChildren(paragraph, 'pPr').filter((element)=>element.namespaceURI === work_docx_paragraph_format_change_export_WORD_NAMESPACE);
3184
+ if (propertyNodes.length > 1) throw new Error('Generated DOCX paragraph contains duplicate properties.');
3185
+ const prefix = xmlNamespacePrefix(document.documentElement, work_docx_paragraph_format_change_export_WORD_NAMESPACE) ?? 'w';
3186
+ const properties = propertyNodes[0] ?? insertParagraphProperties(document, paragraph, prefix);
3187
+ if (directChildren(properties, 'pPrChange').some((element)=>element.namespaceURI === work_docx_paragraph_format_change_export_WORD_NAMESPACE)) throw new Error('Generated DOCX paragraph already contains a formatting revision.');
3188
+ const change = work_docx_paragraph_format_change_export_wordElement(document, prefix, 'pPrChange');
3189
+ work_docx_paragraph_format_change_export_setWordAttribute(document, change, 'id', String(patch.id));
3190
+ work_docx_paragraph_format_change_export_setWordAttribute(document, change, 'author', patch.author);
3191
+ work_docx_paragraph_format_change_export_setWordAttribute(document, change, 'date', patch.date);
3192
+ const before = work_docx_paragraph_format_change_export_wordElement(document, prefix, 'pPr');
3193
+ appendParagraphFormattingProperties(document, before, patch.before, prefix);
3194
+ change.append(before);
3195
+ properties.append(change);
3196
+ }
3197
+ function appendParagraphFormattingProperties(document, properties, serialized, prefix) {
3198
+ const parsed = parseDocumentParagraphFormatting(serialized);
3199
+ if (!parsed) throw new Error('Document contains an invalid paragraph-formatting revision.');
3200
+ const formatting = parsed;
3201
+ appendOnOff(document, properties, prefix, 'keepNext', formatting.keepWithNext);
3202
+ appendOnOff(document, properties, prefix, 'keepLines', formatting.keepLines);
3203
+ appendOnOff(document, properties, prefix, 'pageBreakBefore', formatting.pageBreakBefore);
3204
+ appendOnOff(document, properties, prefix, 'widowControl', formatting.widowControl);
3205
+ appendBorders(document, properties, prefix, formatting.paragraphBorders);
3206
+ appendShading(document, properties, prefix, formatting.paragraphShading);
3207
+ appendTabStops(document, properties, prefix, formatting.tabStops);
3208
+ if (formatting.paragraphDirection) appendOnOff(document, properties, prefix, 'bidi', 'rtl' === formatting.paragraphDirection);
3209
+ appendSpacing(document, properties, prefix, formatting);
3210
+ appendIndent(document, properties, prefix, formatting);
3211
+ appendOnOff(document, properties, prefix, 'contextualSpacing', formatting.contextualSpacing);
3212
+ if (formatting.textAlign) work_docx_paragraph_format_change_export_appendValuedProperty(document, properties, prefix, 'jc', 'justify' === formatting.textAlign ? 'both' : formatting.textAlign);
3213
+ if (null !== formatting.outlineLevel) work_docx_paragraph_format_change_export_appendValuedProperty(document, properties, prefix, 'outlineLvl', String(formatting.outlineLevel));
3214
+ appendDefaultCollapsed(document, properties, prefix, formatting.defaultCollapsed);
3215
+ }
3216
+ function appendSpacing(document, properties, prefix, formatting) {
3217
+ const spacing = work_docx_paragraph_format_change_export_wordElement(document, prefix, 'spacing');
3218
+ if (null !== formatting.spaceBefore) work_docx_paragraph_format_change_export_setWordAttribute(document, spacing, 'before', String(Math.round(20 * formatting.spaceBefore)));
3219
+ if (null !== formatting.spaceAfter) work_docx_paragraph_format_change_export_setWordAttribute(document, spacing, 'after', String(Math.round(20 * formatting.spaceAfter)));
3220
+ if (formatting.lineHeight && formatting.lineRule) {
3221
+ const line = docxLineHeight(formatting.lineHeight, formatting.lineRule);
3222
+ if (null !== line) {
3223
+ work_docx_paragraph_format_change_export_setWordAttribute(document, spacing, 'line', String(line));
3224
+ work_docx_paragraph_format_change_export_setWordAttribute(document, spacing, 'lineRule', formatting.lineRule);
3225
+ }
3226
+ }
3227
+ if (spacing.attributes.length) properties.append(spacing);
3228
+ }
3229
+ function docxLineHeight(value, rule) {
3230
+ if ('auto' === rule) {
3231
+ const multiple = Number(value.replace(/%$/, ''));
3232
+ if (!Number.isFinite(multiple)) return null;
3233
+ return Math.round((value.endsWith('%') ? multiple / 100 : multiple) * 240);
3234
+ }
3235
+ const length = /^(\d+(?:\.\d+)?)(px|pt)?$/i.exec(value);
3236
+ if (!length?.[1]) return null;
3237
+ const points = length[2]?.toLowerCase() === 'px' ? 0.75 * Number(length[1]) : Number(length[1]);
3238
+ return Math.round(20 * points);
3239
+ }
3240
+ function appendIndent(document, properties, prefix, formatting) {
3241
+ const indent = work_docx_paragraph_format_change_export_wordElement(document, prefix, 'ind');
3242
+ work_docx_paragraph_format_change_export_setWordAttribute(document, indent, 'left', String(Math.round(24 * formatting.indentLevel * 15)));
3243
+ work_docx_paragraph_format_change_export_setWordAttribute(document, indent, 'right', String(Math.round(15 * formatting.rightIndent)));
3244
+ formatting.firstLineIndent < 0 ? work_docx_paragraph_format_change_export_setWordAttribute(document, indent, 'hanging', String(Math.round(15 * Math.abs(formatting.firstLineIndent)))) : work_docx_paragraph_format_change_export_setWordAttribute(document, indent, 'firstLine', String(Math.round(15 * formatting.firstLineIndent)));
3245
+ properties.append(indent);
3246
+ }
3247
+ function appendTabStops(document, properties, prefix, tabStops) {
3248
+ if (!tabStops?.length) return;
3249
+ const tabs = work_docx_paragraph_format_change_export_wordElement(document, prefix, 'tabs');
3250
+ for (const stop of tabStops){
3251
+ const tab = work_docx_paragraph_format_change_export_wordElement(document, prefix, 'tab');
3252
+ work_docx_paragraph_format_change_export_setWordAttribute(document, tab, 'val', stop.alignment);
3253
+ work_docx_paragraph_format_change_export_setWordAttribute(document, tab, 'pos', String(Math.round(15 * stop.position)));
3254
+ if ('none' !== stop.leader) work_docx_paragraph_format_change_export_setWordAttribute(document, tab, 'leader', stop.leader);
3255
+ tabs.append(tab);
3256
+ }
3257
+ properties.append(tabs);
3258
+ }
3259
+ function appendBorders(document, properties, prefix, borders) {
3260
+ if (!borders) return;
3261
+ const container = work_docx_paragraph_format_change_export_wordElement(document, prefix, 'pBdr');
3262
+ for (const edge of DOCUMENT_PARAGRAPH_BORDER_EDGES){
3263
+ const border = borders[edge];
3264
+ if (!border) continue;
3265
+ const element = work_docx_paragraph_format_change_export_wordElement(document, prefix, edge);
3266
+ setDocxBorderAttributes(document, element, border);
3267
+ container.append(element);
3268
+ }
3269
+ if (container.children.length) properties.append(container);
3270
+ }
3271
+ function appendShading(document, properties, prefix, shading) {
3272
+ if (!shading) return;
3273
+ const element = work_docx_paragraph_format_change_export_wordElement(document, prefix, 'shd');
3274
+ work_docx_paragraph_format_change_export_setWordAttribute(document, element, 'val', shading.pattern);
3275
+ appendShadingColor(document, element, 'color', shading.color);
3276
+ appendShadingColor(document, element, 'fill', shading.fill);
3277
+ properties.append(element);
3278
+ }
3279
+ function appendShadingColor(document, element, kind, color) {
3280
+ if (!color) return;
3281
+ work_docx_paragraph_format_change_export_setWordAttribute(document, element, kind, 'auto' === color.value ? 'auto' : color.value.slice(1).toUpperCase());
3282
+ if (!color.theme) return;
3283
+ const themeName = 'color' === kind ? 'themeColor' : 'themeFill';
3284
+ work_docx_paragraph_format_change_export_setWordAttribute(document, element, themeName, color.theme.theme);
3285
+ if (color.theme.tint) work_docx_paragraph_format_change_export_setWordAttribute(document, element, `${themeName}Tint`, color.theme.tint);
3286
+ if (color.theme.shade) work_docx_paragraph_format_change_export_setWordAttribute(document, element, `${themeName}Shade`, color.theme.shade);
3287
+ }
3288
+ function appendDefaultCollapsed(document, properties, wordPrefix, value) {
3289
+ if (null === value) return;
3290
+ const element = document.createElementNS(work_docx_paragraph_format_change_export_WORD_2012_NAMESPACE, 'w15:collapsed');
3291
+ element.setAttributeNS(work_docx_paragraph_format_change_export_XMLNS_NAMESPACE, 'xmlns:w15', work_docx_paragraph_format_change_export_WORD_2012_NAMESPACE);
3292
+ element.setAttributeNS(work_docx_paragraph_format_change_export_WORD_NAMESPACE, `${wordPrefix}:val`, value ? '1' : '0');
3293
+ properties.append(element);
3294
+ }
3295
+ function appendOnOff(document, properties, prefix, name, value) {
3296
+ if (null === value) return;
3297
+ work_docx_paragraph_format_change_export_appendValuedProperty(document, properties, prefix, name, value ? '1' : '0');
3298
+ }
3299
+ function work_docx_paragraph_format_change_export_appendValuedProperty(document, properties, prefix, name, value) {
3300
+ const element = work_docx_paragraph_format_change_export_wordElement(document, prefix, name);
3301
+ work_docx_paragraph_format_change_export_setWordAttribute(document, element, 'val', value);
3302
+ properties.append(element);
3303
+ }
3304
+ function insertParagraphProperties(document, paragraph, prefix) {
3305
+ const properties = work_docx_paragraph_format_change_export_wordElement(document, prefix, 'pPr');
3306
+ paragraph.insertBefore(properties, paragraph.firstChild);
3307
+ return properties;
3308
+ }
3309
+ function work_docx_paragraph_format_change_export_wordElement(document, prefix, name) {
3310
+ return document.createElementNS(work_docx_paragraph_format_change_export_WORD_NAMESPACE, `${prefix}:${name}`);
3311
+ }
3312
+ function work_docx_paragraph_format_change_export_setWordAttribute(document, element, name, value) {
3313
+ const prefix = xmlNamespacePrefix(document.documentElement, work_docx_paragraph_format_change_export_WORD_NAMESPACE) ?? 'w';
3314
+ element.setAttributeNS(work_docx_paragraph_format_change_export_WORD_NAMESPACE, `${prefix}:${name}`, value);
3315
+ }
3316
+ function work_docx_paragraph_format_change_export_normalizedRevisionDate(value) {
3317
+ const time = Date.parse(value?.trim() ?? '');
3318
+ return Number.isFinite(time) ? new Date(time).toISOString() : new Date().toISOString();
3319
+ }
3107
3320
  const work_docx_paragraph_identity_WORD_2010_NAMESPACE = 'http://schemas.microsoft.com/office/word/2010/wordml';
3108
3321
  const work_docx_paragraph_identity_MARKUP_COMPATIBILITY_NAMESPACE = 'http://schemas.openxmlformats.org/markup-compatibility/2006';
3109
3322
  const MAX_PARAGRAPH_IDENTITY_PATCHES = 65536;
3110
- const PARAGRAPH_PART_PATTERN = /^word\/(?:document|header\d*|footer\d*|footnotes|endnotes)\.xml$/i;
3323
+ const work_docx_paragraph_identity_PARAGRAPH_PART_PATTERN = /^word\/(?:document|header\d*|footer\d*|footnotes|endnotes)\.xml$/i;
3111
3324
  class DocxParagraphIdentityPatchCollector {
3112
3325
  source;
3113
3326
  patches = [];
@@ -3157,7 +3370,7 @@ async function patchDocxParagraphIdentities(buffer, patches) {
3157
3370
  patch
3158
3371
  ]));
3159
3372
  const applied = new Set();
3160
- const entries = Object.values(archive.files).filter((entry)=>!entry.dir && PARAGRAPH_PART_PATTERN.test(entry.name));
3373
+ const entries = Object.values(archive.files).filter((entry)=>!entry.dir && work_docx_paragraph_identity_PARAGRAPH_PART_PATTERN.test(entry.name));
3161
3374
  for (const entry of entries){
3162
3375
  const document = parseXml(decodeXmlBytes(await entry.async('uint8array'), `generated DOCX ${entry.name}`), `generated DOCX ${entry.name}`);
3163
3376
  if (!isParagraphPartRoot(document.documentElement, entry.name)) continue;
@@ -7103,7 +7316,8 @@ async function createDocxBlob(content, sourcePackage) {
7103
7316
  paragraphDefaultCollapsedPatches: new DocxParagraphDefaultCollapsedPatchCollector(),
7104
7317
  paragraphIdentityPatches: new DocxParagraphIdentityPatchCollector(JSON.stringify(normalizedContent)),
7105
7318
  equationPatches: new DocxEquationPatchCollector(JSON.stringify(normalizedContent)),
7106
- formattingChangePatches: new DocxRunFormattingChangePatchCollector()
7319
+ formattingChangePatches: new DocxRunFormattingChangePatchCollector(),
7320
+ paragraphFormattingChangePatches: new DocxParagraphFormattingChangePatchCollector()
7107
7321
  };
7108
7322
  const commentRecords = createDocxCommentRecords(commentThreads, docx, noteContext.commentIds);
7109
7323
  const sections = [];
@@ -7165,7 +7379,8 @@ async function createDocxBlob(content, sourcePackage) {
7165
7379
  const bookmarkPatched = await patchDocxBookmarks(imageIdentityPatched, noteContext.bookmarkPatches.patches);
7166
7380
  const paragraphDefaultCollapsedPatched = await patchDocxParagraphDefaultCollapsed(bookmarkPatched, noteContext.paragraphDefaultCollapsedPatches.patches);
7167
7381
  const paragraphIdentityPatched = await patchDocxParagraphIdentities(paragraphDefaultCollapsedPatched, noteContext.paragraphIdentityPatches.patches);
7168
- const equationPatched = await patchDocxEquations(paragraphIdentityPatched, noteContext.equationPatches.patches);
7382
+ const paragraphFormattingChangesPatched = await patchDocxParagraphFormattingChanges(paragraphIdentityPatched, noteContext.paragraphFormattingChangePatches.patches);
7383
+ const equationPatched = await patchDocxEquations(paragraphFormattingChangesPatched, noteContext.equationPatches.patches);
7169
7384
  const patched = await patchDocxPageColor(equationPatched, normalizedContent.pageColor);
7170
7385
  const preserved = sourcePackage ? await preserveDocxSourcePackage(patched, sourcePackage, {
7171
7386
  numberingIdentities: noteContext.numberingSourceIdentities
@@ -7331,8 +7546,12 @@ async function pageChromeBlocks(html, docx, noteContext) {
7331
7546
  async function paragraphRuns(element, docx, noteContext) {
7332
7547
  const identityMarker = noteContext.paragraphIdentityPatches.marker(element);
7333
7548
  noteContext.paragraphDefaultCollapsedPatches.register(identityMarker, element);
7549
+ const paragraphFormattingChangeMarker = element.hasAttribute('data-document-change') && 'paragraph-formatting' === element.dataset.changeKind ? noteContext.paragraphFormattingChangePatches.register(element, docxRevisionId(element, noteContext)) : null;
7334
7550
  return [
7335
7551
  new docx.TextRun(identityMarker),
7552
+ ...paragraphFormattingChangeMarker ? [
7553
+ new docx.TextRun(paragraphFormattingChangeMarker)
7554
+ ] : [],
7336
7555
  ...await work_docx_export_inlineRuns(element, docx, noteContext)
7337
7556
  ];
7338
7557
  }
@@ -7496,7 +7715,7 @@ function docxRevisionId(element, context) {
7496
7715
  }
7497
7716
  function documentHasTrackedChanges(html) {
7498
7717
  const document = new DOMParser().parseFromString(html, 'text/html');
7499
- return Boolean(document.body.querySelector('ins[data-document-change], del[data-document-change], span[data-document-change][data-change-kind="formatting"]'));
7718
+ return Boolean(document.body.querySelector('ins[data-document-change], del[data-document-change], span[data-document-change][data-change-kind="formatting"], [data-document-change][data-change-kind="paragraph-formatting"]'));
7500
7719
  }
7501
7720
  function anchoredDocumentComments(content) {
7502
7721
  const document = new DOMParser().parseFromString(content.html, 'text/html');