@beyondwork/docx-react-component 1.0.101 → 1.0.103

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 (41) hide show
  1. package/package.json +1 -1
  2. package/src/core/commands/formatting-commands.ts +8 -7
  3. package/src/core/commands/paragraph-layout-commands.ts +11 -10
  4. package/src/core/commands/section-layout-commands.ts +7 -6
  5. package/src/core/commands/style-commands.ts +3 -2
  6. package/src/io/export/build-app-properties-xml.ts +24 -0
  7. package/src/io/normalize/normalize-text.ts +6 -5
  8. package/src/io/ooxml/docprops.ts +298 -0
  9. package/src/io/ooxml/parse-anchor.ts +15 -15
  10. package/src/io/ooxml/parse-drawing.ts +5 -5
  11. package/src/io/ooxml/parse-fields.ts +16 -15
  12. package/src/io/ooxml/parse-font-table.ts +2 -1
  13. package/src/io/ooxml/parse-footnotes.ts +3 -2
  14. package/src/io/ooxml/parse-headers-footers.ts +7 -6
  15. package/src/io/ooxml/parse-main-document.ts +41 -40
  16. package/src/io/ooxml/parse-numbering.ts +3 -2
  17. package/src/io/ooxml/parse-object.ts +6 -6
  18. package/src/io/ooxml/parse-paragraph-formatting.ts +12 -11
  19. package/src/io/ooxml/parse-picture.ts +16 -16
  20. package/src/io/ooxml/parse-run-formatting.ts +11 -10
  21. package/src/io/ooxml/parse-settings.ts +2 -1
  22. package/src/io/ooxml/parse-shapes.ts +18 -17
  23. package/src/io/ooxml/parse-styles.ts +16 -16
  24. package/src/io/ooxml/parse-theme.ts +5 -4
  25. package/src/model/canonical-document.ts +920 -815
  26. package/src/runtime/formatting/document-lookup.ts +3 -2
  27. package/src/runtime/formatting/formatting-context.ts +66 -25
  28. package/src/runtime/formatting/index.ts +18 -0
  29. package/src/runtime/formatting/layout-inputs.ts +256 -0
  30. package/src/runtime/formatting/numbering/geometry.ts +13 -12
  31. package/src/runtime/formatting/style-cascade.ts +2 -1
  32. package/src/runtime/formatting/table-style-resolver.ts +8 -7
  33. package/src/runtime/surface-projection.ts +31 -36
  34. package/src/session/export/stateful-export-pipeline.ts +9 -4
  35. package/src/session/export/stateful-export.ts +22 -6
  36. package/src/session/import/canonical-assembly.ts +2 -3
  37. package/src/session/import/loader-types.ts +3 -1
  38. package/src/session/import/loader.ts +12 -0
  39. package/src/session/import/normalize.ts +2 -1
  40. package/src/session/import/source-package-evidence.ts +1016 -0
  41. package/src/session/shared/session-utils.ts +9 -0
@@ -1,4 +1,4 @@
1
- import type { PictureContent } from "../../model/canonical-document.ts";
1
+ import type { PictureContent, Mutable } from "../../model/canonical-document.ts";
2
2
  import {
3
3
  type XmlElementNode,
4
4
  findFirstChild,
@@ -100,21 +100,21 @@ export function parsePicture(graphicDataEl: XmlElementNode): PictureContent | nu
100
100
  const glowEl = effectLst ? findFirstChild(effectLst, "glow") : undefined;
101
101
  const glow = glowEl ? parseGlow(glowEl) : undefined;
102
102
 
103
- const result: PictureContent = { type: "picture", blipRef };
104
- if (isLinked) result.isLinked = true;
103
+ const result: Mutable<PictureContent> = { type: "picture", blipRef };
104
+ if (isLinked) (result as Mutable<typeof result>).isLinked = true;
105
105
  if (lum && (lum.bright !== undefined || lum.contrast !== undefined)) {
106
- result.lum = lum;
106
+ (result as Mutable<typeof result>).lum = lum;
107
107
  }
108
- if (srcRect) result.srcRect = srcRect;
109
- if (stretch !== undefined) result.stretch = stretch;
108
+ if (srcRect) (result as Mutable<typeof result>).srcRect = srcRect;
109
+ if (stretch !== undefined) (result as Mutable<typeof result>).stretch = stretch;
110
110
  if (tile !== undefined) result.tile = tile;
111
- if (rotation !== undefined) result.rotation = rotation;
112
- if (flipH !== undefined) result.flipH = flipH;
113
- if (flipV !== undefined) result.flipV = flipV;
114
- if (presetGeom) result.presetGeom = presetGeom;
115
- if (softEdgeRadius !== undefined) result.softEdgeRadius = softEdgeRadius;
116
- if (outerShadow) result.outerShadow = outerShadow;
117
- if (glow) result.glow = glow;
111
+ if (rotation !== undefined) (result as Mutable<typeof result>).rotation = rotation;
112
+ if (flipH !== undefined) (result as Mutable<typeof result>).flipH = flipH;
113
+ if (flipV !== undefined) (result as Mutable<typeof result>).flipV = flipV;
114
+ if (presetGeom) (result as Mutable<typeof result>).presetGeom = presetGeom;
115
+ if (softEdgeRadius !== undefined) (result as Mutable<typeof result>).softEdgeRadius = softEdgeRadius;
116
+ if (outerShadow) (result as Mutable<typeof result>).outerShadow = outerShadow;
117
+ if (glow) (result as Mutable<typeof result>).glow = glow;
118
118
  return result;
119
119
  }
120
120
 
@@ -172,13 +172,13 @@ function readTileAttrs(
172
172
  const v = tileEl.attributes[key];
173
173
  if (v !== undefined) {
174
174
  const n = parseInt(v, 10);
175
- if (Number.isFinite(n)) result[key] = n;
175
+ if (Number.isFinite(n)) (result as Mutable<typeof result>)[key] = n;
176
176
  }
177
177
  }
178
178
  const flip = tileEl.attributes.flip;
179
- if (flip === "x" || flip === "y" || flip === "xy") result.flip = flip;
179
+ if (flip === "x" || flip === "y" || flip === "xy") (result as Mutable<typeof result>).flip = flip;
180
180
  const algn = tileEl.attributes.algn;
181
- if (algn) result.algn = algn;
181
+ if (algn) (result as Mutable<typeof result>).algn = algn;
182
182
  return Object.keys(result).length > 0 ? result : {};
183
183
  }
184
184
 
@@ -1,6 +1,7 @@
1
1
  import type {
2
2
  CanonicalRunFormatting,
3
3
  ThemeFontSlot,
4
+ Mutable,
4
5
  } from "../../model/canonical-document.ts";
5
6
  import { findChildOptional, readIntVal, readOnOff, readStringAttr } from "./xml-attr-helpers.ts";
6
7
  import type { XmlElementNode } from "./xml-element.ts";
@@ -58,7 +59,7 @@ export function readRunProperties(
58
59
  ): CanonicalRunFormatting | undefined {
59
60
  if (!node) return undefined;
60
61
 
61
- const rPr: CanonicalRunFormatting = {};
62
+ const rPr: Mutable<CanonicalRunFormatting> = {};
62
63
 
63
64
  const bold = readOnOff(findChildOptional(node, "b"));
64
65
  if (bold !== undefined) rPr.bold = bold;
@@ -121,9 +122,9 @@ export function readRunProperties(
121
122
  const hAnsi = rFonts.attributes["w:hAnsi"] ?? rFonts.attributes.hAnsi;
122
123
  const eastAsia = rFonts.attributes["w:eastAsia"] ?? rFonts.attributes.eastAsia;
123
124
  const cs = rFonts.attributes["w:cs"] ?? rFonts.attributes.cs;
124
- if (ascii) rPr.fontFamilyAscii = ascii;
125
- if (hAnsi) rPr.fontFamilyHAnsi = hAnsi;
126
- if (eastAsia) rPr.fontFamilyEastAsia = eastAsia;
125
+ if (ascii) (rPr as Mutable<typeof rPr>).fontFamilyAscii = ascii;
126
+ if (hAnsi) (rPr as Mutable<typeof rPr>).fontFamilyHAnsi = hAnsi;
127
+ if (eastAsia) (rPr as Mutable<typeof rPr>).fontFamilyEastAsia = eastAsia;
127
128
  if (cs) rPr.fontFamilyCs = cs;
128
129
  const primary = ascii ?? hAnsi ?? eastAsia ?? cs;
129
130
  if (primary) rPr.fontFamily = primary;
@@ -150,9 +151,9 @@ export function readRunProperties(
150
151
  rFonts.attributes["w:csTheme"] ??
151
152
  rFonts.attributes.csTheme,
152
153
  );
153
- if (asciiTheme) rPr.asciiTheme = asciiTheme;
154
- if (hAnsiTheme) rPr.hAnsiTheme = hAnsiTheme;
155
- if (eastAsiaTheme) rPr.eastAsiaTheme = eastAsiaTheme;
154
+ if (asciiTheme) (rPr as Mutable<typeof rPr>).asciiTheme = asciiTheme;
155
+ if (hAnsiTheme) (rPr as Mutable<typeof rPr>).hAnsiTheme = hAnsiTheme;
156
+ if (eastAsiaTheme) (rPr as Mutable<typeof rPr>).eastAsiaTheme = eastAsiaTheme;
156
157
  if (csTheme) rPr.csTheme = csTheme;
157
158
  }
158
159
 
@@ -171,9 +172,9 @@ export function readRunProperties(
171
172
  color.attributes["w:themeTint"] ?? color.attributes["themeTint"];
172
173
  const shade =
173
174
  color.attributes["w:themeShade"] ?? color.attributes["themeShade"];
174
- if (val) rPr.colorHex = val;
175
- if (theme) rPr.colorThemeSlot = theme;
176
- if (tint) rPr.colorThemeTint = tint;
175
+ if (val) (rPr as Mutable<typeof rPr>).colorHex = val;
176
+ if (theme) (rPr as Mutable<typeof rPr>).colorThemeSlot = theme;
177
+ if (tint) (rPr as Mutable<typeof rPr>).colorThemeTint = tint;
177
178
  if (shade) rPr.colorThemeShade = shade;
178
179
  }
179
180
 
@@ -5,6 +5,7 @@ import type {
5
5
  DocumentSettings,
6
6
  FootnoteProperties,
7
7
  ThemeColorSlot,
8
+ Mutable,
8
9
  } from "../../model/canonical-document.ts";
9
10
  import { parseXml } from "./xml-parser.ts";
10
11
  import { localName } from "./xml-attr-helpers.ts";
@@ -160,7 +161,7 @@ function readFootnoteLikeProperties(
160
161
  ): FootnoteProperties | undefined {
161
162
  if (!element) return undefined;
162
163
 
163
- const result: FootnoteProperties = {};
164
+ const result: Mutable<FootnoteProperties> = {};
164
165
  for (const child of element.children) {
165
166
  if (child.type !== "element") continue;
166
167
  const name = localName(child.name);
@@ -14,6 +14,7 @@ import type {
14
14
  BlockNode,
15
15
  ShapeContent,
16
16
  TextBoxBodyProperties,
17
+ Mutable,
17
18
  } from "../../model/canonical-document.ts";
18
19
  import { parseFill } from "./parse-fill.ts";
19
20
  import {
@@ -46,7 +47,7 @@ export interface ParsedWpsShape {
46
47
  * shape-textbox paragraphs). Same shape + semantics as
47
48
  * `ShapeContent.txbxBlocks` on the drawing-frame path.
48
49
  */
49
- txbxBlocks?: ReadonlyArray<BlockNode>;
50
+ txbxBlocks?: BlockNode[];
50
51
  /** DrawML geometry preset, e.g. "rect", "roundRect". */
51
52
  geometry?: string;
52
53
  /** Original drawing XML for lossless round-trip export. */
@@ -129,7 +130,7 @@ export function parseShapeXml(
129
130
  // content (CCEP "Copyright CCEP STRICTLY CONFIDENTIAL" footer band)
130
131
  // is reachable only via the `.text` summary string — L03 cascade +
131
132
  // L11 render can't walk runs/marks.
132
- let txbxBlocks: ReadonlyArray<BlockNode> | undefined;
133
+ let txbxBlocks: BlockNode[] | undefined;
133
134
  if (txbxContentXml && blockParser) {
134
135
  try {
135
136
  // The `blockParser` callback is supplied by parse-main-document.ts
@@ -142,7 +143,7 @@ export function parseShapeXml(
142
143
  // canonical; a structural `as unknown as BlockNode[]` preserves
143
144
  // type safety at every consumer site (L03 cascade, L11 render,
144
145
  // validator walk).
145
- txbxBlocks = blockParser(txbxContentXml) as unknown as ReadonlyArray<BlockNode>;
146
+ txbxBlocks = blockParser(txbxContentXml) as unknown as BlockNode[];
146
147
  } catch {
147
148
  txbxBlocks = undefined;
148
149
  }
@@ -271,7 +272,7 @@ export function parseShapeContent(
271
272
  const txbxContentXml = txbxContent ? extractRawXml(txbxContent) : undefined;
272
273
  const text = txbxContent ? extractAllText(txbxContent).trim() || undefined : undefined;
273
274
 
274
- let txbxBlocks: ReadonlyArray<BlockNode> | undefined;
275
+ let txbxBlocks: BlockNode[] | undefined;
275
276
  if (txbxContentXml && blockParser) {
276
277
  try {
277
278
  // See `TxbxBlockParser` doc above: runtime output is canonical
@@ -279,7 +280,7 @@ export function parseShapeContent(
279
280
  // footer fixture 2026-04-24). Cast at the assembly seam so
280
281
  // downstream consumers (L03, L11, validator) get canonical types
281
282
  // without local `as unknown` ceremony.
282
- txbxBlocks = blockParser(txbxContentXml) as unknown as ReadonlyArray<BlockNode>;
283
+ txbxBlocks = blockParser(txbxContentXml) as unknown as BlockNode[];
283
284
  } catch {
284
285
  // Preserve-only fallback: keep txbxContentXml for serialization; leave
285
286
  // txbxBlocks undefined so consumers know recursion did not succeed.
@@ -294,15 +295,15 @@ export function parseShapeContent(
294
295
  // roundRect text boxes + callout/ellipse shapes as non-text.
295
296
  const isTextBox = Boolean(txbxContent);
296
297
 
297
- const result: ShapeContent = { type: "shape", rawXml: drawingRawXml };
298
- if (geometry) result.geometry = geometry;
298
+ const result: Mutable<ShapeContent> = { type: "shape", rawXml: drawingRawXml };
299
+ if (geometry) (result as Mutable<typeof result>).geometry = geometry;
299
300
  if (text) result.text = text;
300
- if (fill) result.fill = fill;
301
- if (line) result.line = line;
302
- if (isTextBox) result.isTextBox = true;
303
- if (textBoxBody) result.textBoxBody = textBoxBody;
304
- if (txbxContentXml) result.txbxContentXml = txbxContentXml;
305
- if (txbxBlocks && txbxBlocks.length > 0) result.txbxBlocks = txbxBlocks;
301
+ if (fill) (result as Mutable<typeof result>).fill = fill;
302
+ if (line) (result as Mutable<typeof result>).line = line;
303
+ if (isTextBox) (result as Mutable<typeof result>).isTextBox = true;
304
+ if (textBoxBody) (result as Mutable<typeof result>).textBoxBody = textBoxBody;
305
+ if (txbxContentXml) (result as Mutable<typeof result>).txbxContentXml = txbxContentXml;
306
+ if (txbxBlocks && txbxBlocks.length > 0) (result as Mutable<typeof result>).txbxBlocks = txbxBlocks;
306
307
  return result;
307
308
  }
308
309
 
@@ -310,7 +311,7 @@ function readTextBoxBody(wsp: XmlElementNode): TextBoxBodyProperties | undefined
310
311
  const bodyPr = findFirstChild(wsp, "bodyPr");
311
312
  if (!bodyPr) return undefined;
312
313
 
313
- const result: TextBoxBodyProperties = {};
314
+ const result: Mutable<TextBoxBodyProperties> = {};
314
315
  const anchor = bodyPr.attributes.anchor;
315
316
  if (anchor === "t" || anchor === "ctr" || anchor === "b") {
316
317
  result.anchor = anchor;
@@ -319,9 +320,9 @@ function readTextBoxBody(wsp: XmlElementNode): TextBoxBodyProperties | undefined
319
320
  const top = readIntAttr(bodyPr, "tIns");
320
321
  const right = readIntAttr(bodyPr, "rIns");
321
322
  const bottom = readIntAttr(bodyPr, "bIns");
322
- if (left !== undefined) result.insetLeftEmu = left;
323
- if (top !== undefined) result.insetTopEmu = top;
324
- if (right !== undefined) result.insetRightEmu = right;
323
+ if (left !== undefined) (result as Mutable<typeof result>).insetLeftEmu = left;
324
+ if (top !== undefined) (result as Mutable<typeof result>).insetTopEmu = top;
325
+ if (right !== undefined) (result as Mutable<typeof result>).insetRightEmu = right;
325
326
  if (bottom !== undefined) result.insetBottomEmu = bottom;
326
327
 
327
328
  return Object.keys(result).length > 0 ? result : undefined;
@@ -23,6 +23,7 @@ import type {
23
23
  TableStyleDefinition,
24
24
  TableStyleFormatting,
25
25
  TableWidth,
26
+ Mutable,
26
27
  } from "../../model/canonical-document.ts";
27
28
  import {
28
29
  readCellBorders,
@@ -372,8 +373,8 @@ function resolveStyleLinkReciprocals(
372
373
  );
373
374
  continue;
374
375
  }
375
- if (partner.linkedStyleId === undefined) {
376
- partner.linkedStyleId = style.styleId;
376
+ if ((partner as Mutable<typeof partner>).linkedStyleId === undefined) {
377
+ (partner as Mutable<typeof partner>).linkedStyleId = style.styleId;
377
378
  } else if (partner.linkedStyleId !== style.styleId) {
378
379
  diagnostics.push(
379
380
  `style ${label} "${style.styleId}" links to "${target}" but partner already links to "${partner.linkedStyleId}"; partner link retained`,
@@ -439,7 +440,7 @@ function readTableStyleFormatting(styleNode: XmlElementNode): TableStyleFormatti
439
440
  const cellProperties = findChildElementOptional(styleNode, "tcPr");
440
441
  const pPrNode = findChildElementOptional(styleNode, "pPr");
441
442
  const rPrNode = findChildElementOptional(styleNode, "rPr");
442
- const formatting: TableStyleFormatting = {};
443
+ const formatting: Mutable<TableStyleFormatting> = {};
443
444
 
444
445
  const paragraphProperties = readParagraphProperties(pPrNode);
445
446
  if (paragraphProperties) formatting.paragraphProperties = paragraphProperties;
@@ -454,11 +455,11 @@ function readTableStyleFormatting(styleNode: XmlElementNode): TableStyleFormatti
454
455
  const cellMargins = readTableCellMargins(tableProperties);
455
456
  const tblLook = readTableLook(tableProperties);
456
457
 
457
- if (width) table.width = width as TableWidth;
458
- if (alignment) table.alignment = alignment;
459
- if (borders) table.borders = borders as TableBorders;
460
- if (cellMargins) table.cellMargins = cellMargins as TableCellMargins;
461
- if (tblLook) table.tblLook = tblLook as TableLook;
458
+ if (width) (table as Mutable<typeof table>).width = width as TableWidth;
459
+ if (alignment) (table as Mutable<typeof table>).alignment = alignment;
460
+ if (borders) (table as Mutable<typeof table>).borders = borders as TableBorders;
461
+ if (cellMargins) (table as Mutable<typeof table>).cellMargins = cellMargins as TableCellMargins;
462
+ if (tblLook) (table as Mutable<typeof table>).tblLook = tblLook as TableLook;
462
463
 
463
464
  if (Object.keys(table).length > 0) {
464
465
  formatting.table = table;
@@ -471,9 +472,9 @@ function readTableStyleFormatting(styleNode: XmlElementNode): TableStyleFormatti
471
472
  const heightRule = readRowHeightRule(rowProperties);
472
473
  const isHeader = readRowIsHeader(rowProperties);
473
474
 
474
- if (height !== undefined) row.height = height;
475
- if (heightRule) row.heightRule = heightRule;
476
- if (isHeader !== undefined) row.isHeader = isHeader;
475
+ if (height !== undefined) (row as Mutable<typeof row>).height = height;
476
+ if (heightRule) (row as Mutable<typeof row>).heightRule = heightRule;
477
+ if (isHeader !== undefined) (row as Mutable<typeof row>).isHeader = isHeader;
477
478
 
478
479
  if (Object.keys(row).length > 0) {
479
480
  formatting.row = row;
@@ -487,10 +488,10 @@ function readTableStyleFormatting(styleNode: XmlElementNode): TableStyleFormatti
487
488
  const shading = readCellShading(cellProperties);
488
489
  const verticalAlign = readCellVerticalAlign(cellProperties);
489
490
 
490
- if (width) cell.width = width as TableWidth;
491
- if (borders) cell.borders = borders as TableCellBorders;
492
- if (shading) cell.shading = shading as CellShading;
493
- if (verticalAlign) cell.verticalAlign = verticalAlign;
491
+ if (width) (cell as Mutable<typeof cell>).width = width as TableWidth;
492
+ if (borders) (cell as Mutable<typeof cell>).borders = borders as TableCellBorders;
493
+ if (shading) (cell as Mutable<typeof cell>).shading = shading as CellShading;
494
+ if (verticalAlign) (cell as Mutable<typeof cell>).verticalAlign = verticalAlign;
494
495
 
495
496
  if (Object.keys(cell).length > 0) {
496
497
  formatting.cell = cell;
@@ -590,4 +591,3 @@ function findChildElementOptional(
590
591
  );
591
592
  }
592
593
 
593
-
@@ -5,6 +5,7 @@ import type {
5
5
  ResolvedTheme,
6
6
  CanonicalTheme,
7
7
  ClrSchemeMapping,
8
+ Mutable,
8
9
  } from "../../model/canonical-document.ts";
9
10
  import type { XmlElementNode } from "./xml-element.ts";
10
11
  import { parseXml } from "./xml-parser.ts";
@@ -61,7 +62,7 @@ export function parseThemeXml(xml: string): ThemeDefinition {
61
62
  findChildElementOptional(themeElements, "fontScheme"),
62
63
  );
63
64
 
64
- const result: ThemeDefinition = {};
65
+ const result: Mutable<ThemeDefinition> = {};
65
66
  if (themeName) {
66
67
  result.name = themeName;
67
68
  }
@@ -79,7 +80,7 @@ export function parseThemeXml(xml: string): ThemeDefinition {
79
80
  * Resolve a ThemeDefinition into flattened runtime theme inputs.
80
81
  * Maps OOXML theme slot names to CSS-usable color values and font families.
81
82
  */
82
- export function resolveTheme(theme: ThemeDefinition): ResolvedTheme {
83
+ export function resolveTheme(theme: Mutable<ThemeDefinition>): ResolvedTheme {
83
84
  const colors: Record<string, string> = {};
84
85
 
85
86
  if (theme.colorScheme?.colors) {
@@ -142,7 +143,7 @@ export const DEFAULT_CLR_SCHEME_MAPPING: ClrSchemeMapping = Object.freeze({
142
143
  * CLAUDE.md §3.
143
144
  */
144
145
  export function materializeCanonicalTheme(
145
- theme: ThemeDefinition,
146
+ theme: Mutable<ThemeDefinition>,
146
147
  clrMap: ClrSchemeMapping,
147
148
  ): CanonicalTheme {
148
149
  const clrScheme: ThemeColorScheme = theme.colorScheme ?? { name: "", colors: {} };
@@ -240,7 +241,7 @@ function parseFontScheme(
240
241
  ? extractFontTypeface(minorFontElement)
241
242
  : undefined;
242
243
 
243
- const result: ThemeFontScheme = { name: schemeName };
244
+ const result: Mutable<ThemeFontScheme> = { name: schemeName };
244
245
  if (majorFont) {
245
246
  result.majorFont = majorFont;
246
247
  }