@stll/folio-core 0.47.7 → 0.48.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 (160) hide show
  1. package/dist/controller/fontReadiness.js +3 -3
  2. package/dist/controller/hyphenationReadiness.d.ts +19 -0
  3. package/dist/controller/hyphenationReadiness.js +47 -0
  4. package/dist/controller/layoutPipeline.d.ts +3 -0
  5. package/dist/controller/layoutPipeline.js +59 -17
  6. package/dist/display-list/build/buildDisplayList.js +39 -12
  7. package/dist/display-list/build/pageFurniture.d.ts +7 -1
  8. package/dist/display-list/build/pageFurniture.js +21 -8
  9. package/dist/display-list/build/paragraphPrimitives.js +5 -4
  10. package/dist/display-list/build/tablePrimitives.js +10 -6
  11. package/dist/docx/attributeRemainder.js +10 -2
  12. package/dist/docx/blockContentParser.d.ts +2 -0
  13. package/dist/docx/blockContentParser.js +77 -62
  14. package/dist/docx/commentParser.d.ts +2 -1
  15. package/dist/docx/commentParser.js +57 -45
  16. package/dist/docx/containerChildren.d.ts +21 -8
  17. package/dist/docx/containerChildren.js +39 -9
  18. package/dist/docx/documentParser.d.ts +5 -1
  19. package/dist/docx/documentParser.js +8 -5
  20. package/dist/docx/documentSectionFacts.d.ts +22 -0
  21. package/dist/docx/documentSectionFacts.js +43 -0
  22. package/dist/docx/fieldParser.d.ts +8 -1
  23. package/dist/docx/fieldParser.js +47 -3
  24. package/dist/docx/fontTableParser.js +34 -27
  25. package/dist/docx/footnoteParser.d.ts +3 -2
  26. package/dist/docx/footnoteParser.js +15 -12
  27. package/dist/docx/groupDrawingParser.d.ts +2 -1
  28. package/dist/docx/groupDrawingParser.js +3 -6
  29. package/dist/docx/headerFooterParser.d.ts +7 -2
  30. package/dist/docx/headerFooterParser.js +15 -5
  31. package/dist/docx/hyperlinkParser.d.ts +48 -36
  32. package/dist/docx/hyperlinkParser.js +97 -82
  33. package/dist/docx/numberingParser.js +108 -84
  34. package/dist/docx/paragraphParser.d.ts +5 -1
  35. package/dist/docx/paragraphParser.js +381 -362
  36. package/dist/docx/paragraphProperties.js +123 -109
  37. package/dist/docx/paragraphPropertySource.d.ts +6 -1
  38. package/dist/docx/paragraphPropertySource.js +9 -1
  39. package/dist/docx/paragraphTextBoxEnrichment.d.ts +2 -1
  40. package/dist/docx/paragraphTextBoxEnrichment.js +17 -6
  41. package/dist/docx/parser.d.ts +7 -1
  42. package/dist/docx/parser.js +33 -16
  43. package/dist/docx/previewBudget.d.ts +55 -33
  44. package/dist/docx/previewBudget.js +59 -65
  45. package/dist/docx/rezip.js +41 -58
  46. package/dist/docx/runParser.d.ts +4 -1
  47. package/dist/docx/runParser.js +172 -184
  48. package/dist/docx/sdtProperties.js +87 -84
  49. package/dist/docx/sectionParser.js +169 -160
  50. package/dist/docx/serializer/paragraphSerializer.js +42 -38
  51. package/dist/docx/serializer/settingsSerializer.js +19 -1
  52. package/dist/docx/settingsParser.js +8 -0
  53. package/dist/docx/streamingXmlParser.d.ts +6 -2
  54. package/dist/docx/streamingXmlParser.js +12 -7
  55. package/dist/docx/styleParser.js +34 -8
  56. package/dist/docx/tableParser.d.ts +21 -12
  57. package/dist/docx/tableParser.js +518 -441
  58. package/dist/docx/textBoxParser.d.ts +8 -3
  59. package/dist/docx/textBoxParser.js +3 -3
  60. package/dist/docx/verbatimCapture.d.ts +10 -8
  61. package/dist/docx/verbatimCapture.js +45 -2
  62. package/dist/docx/vmlImageParser.d.ts +15 -13
  63. package/dist/docx/vmlImageParser.js +75 -60
  64. package/dist/docx/vmlPreview.d.ts +3 -3
  65. package/dist/docx/vmlPreview.js +3 -4
  66. package/dist/docx/xmlNamespaceContext.d.ts +9 -0
  67. package/dist/docx/xmlNamespaceContext.js +54 -0
  68. package/dist/docx/xmlParser.d.ts +6 -3
  69. package/dist/docx/xmlParser.js +11 -41
  70. package/dist/docx/xmlResourceLimits.d.ts +2 -1
  71. package/dist/docx/xmlResourceLimits.js +4 -1
  72. package/dist/fonts/headlessMeasure.js +0 -0
  73. package/dist/headless-layout.d.ts +11 -2
  74. package/dist/headless-layout.js +153 -107
  75. package/dist/internal/paragraphFormattingSerialization.js +3 -3
  76. package/dist/layout-bridge/convert/endnoteLayout.d.ts +65 -0
  77. package/dist/layout-bridge/convert/endnoteLayout.js +227 -0
  78. package/dist/layout-bridge/convert/footnoteLayout.d.ts +19 -3
  79. package/dist/layout-bridge/convert/footnoteLayout.js +40 -31
  80. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -7
  81. package/dist/layout-bridge/convert/headerFooterLayout.js +5 -20
  82. package/dist/layout-bridge/convert/paragraphMarkFormatting.d.ts +10 -0
  83. package/dist/layout-bridge/convert/paragraphMarkFormatting.js +59 -0
  84. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +29 -1
  85. package/dist/layout-bridge/convert/toFlowBlocks.js +258 -35
  86. package/dist/layout-bridge/engine/hitTest.js +5 -3
  87. package/dist/layout-bridge/engine/selectionRects.js +5 -3
  88. package/dist/layout-engine/anchorLayoutInCellCompatibility.d.ts +10 -0
  89. package/dist/layout-engine/anchorLayoutInCellCompatibility.js +22 -0
  90. package/dist/layout-engine/index.d.ts +2 -2
  91. package/dist/layout-engine/index.js +70 -11
  92. package/dist/layout-engine/justificationCompatibility.d.ts +1 -1
  93. package/dist/layout-engine/justificationCompatibility.js +9 -5
  94. package/dist/layout-engine/keep-together.d.ts +11 -5
  95. package/dist/layout-engine/keep-together.js +39 -16
  96. package/dist/layout-engine/layoutInstrumentation.d.ts +8 -2
  97. package/dist/layout-engine/layoutInstrumentation.js +8 -1
  98. package/dist/layout-engine/measure/advanceComposition.js +4 -7
  99. package/dist/layout-engine/measure/hyphenationDictionaries.d.ts +74 -0
  100. package/dist/layout-engine/measure/hyphenationDictionaries.js +138 -0
  101. package/dist/layout-engine/measure/hyphenationPreload.d.ts +11 -0
  102. package/dist/layout-engine/measure/hyphenationPreload.js +24 -0
  103. package/dist/layout-engine/measure/lineBreakProvider.d.ts +12 -2
  104. package/dist/layout-engine/measure/lineBreakProvider.js +30 -30
  105. package/dist/layout-engine/measure/lineBreaks.d.ts +6 -1
  106. package/dist/layout-engine/measure/lineBreaks.js +10 -3
  107. package/dist/layout-engine/measure/listMarkerWidth.d.ts +9 -6
  108. package/dist/layout-engine/measure/listMarkerWidth.js +20 -22
  109. package/dist/layout-engine/measure/measureBlocks.js +42 -8
  110. package/dist/layout-engine/measure/measureContainer.js +5 -5
  111. package/dist/layout-engine/measure/measureHelpers.d.ts +15 -3
  112. package/dist/layout-engine/measure/measureHelpers.js +21 -5
  113. package/dist/layout-engine/measure/measureParagraph.js +109 -30
  114. package/dist/layout-engine/measure/measureTypes.d.ts +5 -0
  115. package/dist/layout-engine/measure/tabCalculator.d.ts +2 -0
  116. package/dist/layout-engine/measure/tabCalculator.js +2 -1
  117. package/dist/layout-engine/measure/tableCellFloating.d.ts +2 -0
  118. package/dist/layout-engine/measure/tableCellFloating.js +51 -19
  119. package/dist/layout-engine/measure/tableCellGrid.d.ts +28 -3
  120. package/dist/layout-engine/measure/tableCellGrid.js +45 -5
  121. package/dist/layout-engine/measure/tableFragmentBorderGeometry.js +2 -1
  122. package/dist/layout-engine/noteAreaFlow.d.ts +19 -0
  123. package/dist/layout-engine/noteAreaFlow.js +83 -0
  124. package/dist/layout-engine/paginator.d.ts +10 -1
  125. package/dist/layout-engine/paginator.js +13 -1
  126. package/dist/layout-engine/tableRowBreak.js +3 -1
  127. package/dist/layout-engine/types.d.ts +89 -3
  128. package/dist/layout-engine/types.js +96 -1
  129. package/dist/layout-painter/index.d.ts +3 -0
  130. package/dist/layout-painter/renderPage.js +32 -83
  131. package/dist/layout-painter/renderParagraph.d.ts +6 -1
  132. package/dist/layout-painter/renderParagraph.js +34 -22
  133. package/dist/layout-painter/renderTable.js +26 -13
  134. package/dist/prosemirror/attrs/index.d.ts +9 -9
  135. package/dist/prosemirror/attrs/index.js +43 -11
  136. package/dist/prosemirror/conversion/fromProseDoc.js +8 -1
  137. package/dist/prosemirror/conversion/markInterner.d.ts +21 -0
  138. package/dist/prosemirror/conversion/markInterner.js +90 -0
  139. package/dist/prosemirror/conversion/toProseDoc.js +77 -41
  140. package/dist/prosemirror/extensions/core/DocExtension.js +2 -1
  141. package/dist/prosemirror/extensions/core/ParagraphExtension.js +1 -0
  142. package/dist/prosemirror/extensions/marks/markUtils.d.ts +6 -2
  143. package/dist/prosemirror/extensions/marks/markUtils.js +39 -51
  144. package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +2 -1
  145. package/dist/prosemirror/listMarker.d.ts +1 -0
  146. package/dist/prosemirror/listMarker.js +2 -0
  147. package/dist/prosemirror/listRenderingAttrs.d.ts +1 -0
  148. package/dist/prosemirror/listRenderingAttrs.js +3 -0
  149. package/dist/prosemirror/schema/nodes.d.ts +13 -1
  150. package/dist/prosemirror/textBoxHostParagraph.d.ts +13 -0
  151. package/dist/prosemirror/textBoxHostParagraph.js +21 -0
  152. package/dist/prosemirror/validation.js +91 -80
  153. package/dist/utils/createDocument.js +10 -1
  154. package/dist/utils/scriptSegments.d.ts +33 -4
  155. package/dist/utils/scriptSegments.js +39 -6
  156. package/dist/utils/textFormattingMerge.d.ts +17 -3
  157. package/dist/utils/textFormattingMerge.js +18 -12
  158. package/dist/utils/trailingText.d.ts +22 -0
  159. package/dist/utils/trailingText.js +32 -0
  160. package/package.json +2 -2
@@ -228,6 +228,7 @@ const paragraphNodeSpec = {
228
228
  listMarkerSecondSlotOffsetTwips: { default: null },
229
229
  listLevelNumFmts: { default: null },
230
230
  listLevelStarts: { default: null },
231
+ listLevelTabs: { default: null },
231
232
  listAbstractNumId: { default: null },
232
233
  listStartOverride: { default: null },
233
234
  styleId: { default: null },
@@ -1,6 +1,6 @@
1
1
  import { document_d_exports } from "../../../types/document.js";
2
2
  import { Command, EditorState } from "prosemirror-state";
3
- import { Mark, MarkType, Schema } from "prosemirror-model";
3
+ import { Attrs, Mark, MarkType, Schema } from "prosemirror-model";
4
4
  //#region src/prosemirror/extensions/marks/markUtils.d.ts
5
5
  type MarkAttrs = Record<string, unknown>;
6
6
  declare function marksToTextFormatting(marks: readonly Mark[]): document_d_exports.TextFormatting;
@@ -23,6 +23,8 @@ declare function isMarkActive(state: EditorState, markType: MarkType, attrs?: Re
23
23
  */
24
24
  declare function getMarkAttr(state: EditorState, markType: MarkType, attr: string): unknown;
25
25
  type AuthoredRunFormattingCarrier = "preserve" | "reconstruct";
26
+ /** Builds a mark by type name; a conversion passes one that shares equal marks. */
27
+ type MarkFactory = (type: string, attrs?: Attrs | null) => Mark;
26
28
  /**
27
29
  * Convert TextFormatting to ProseMirror marks
28
30
  */
@@ -32,6 +34,8 @@ type TextFormattingToMarksOptions = {
32
34
  directFormatting?: document_d_exports.TextFormatting | undefined;
33
35
  /** Whether direct authorship is reconstructible from structural marks and the style context. */
34
36
  authoredCarrier?: AuthoredRunFormattingCarrier;
37
+ /** Builds each mark; defaults to `schema.mark`. */
38
+ createMark?: MarkFactory;
35
39
  };
36
40
  declare function textFormattingToMarks(formatting: document_d_exports.TextFormatting | undefined, schema: Schema, options?: TextFormattingToMarksOptions): Mark[];
37
41
  /**
@@ -47,4 +51,4 @@ declare function createSetMarkCommand(markType: MarkType, attrs?: Record<string,
47
51
  */
48
52
  declare function createRemoveMarkCommand(markType: MarkType): Command;
49
53
  //#endregion
50
- export { AuthoredRunFormattingCarrier, clearFontSizeForAllScripts, clearFormatting, createRemoveMarkCommand, createSetMarkCommand, getMarkAttr, isMarkActive, marksToTextFormatting, removeMark, setFontSizeForAllScripts, setMark, textFormattingToMarks, toggleMarkForAllScripts, toggleUnderlineMark };
54
+ export { AuthoredRunFormattingCarrier, MarkFactory, clearFontSizeForAllScripts, clearFormatting, createRemoveMarkCommand, createSetMarkCommand, getMarkAttr, isMarkActive, marksToTextFormatting, removeMark, setFontSizeForAllScripts, setMark, textFormattingToMarks, toggleMarkForAllScripts, toggleUnderlineMark };
@@ -375,23 +375,16 @@ function getMarkAttr(state, markType, attr) {
375
375
  });
376
376
  return value;
377
377
  }
378
- const addDirectFontProvenance = (marks, schema, directFormatting) => {
378
+ const withDirectFontProvenance = (attrs, directFormatting) => {
379
379
  const directFontProperties = [];
380
380
  if (directFormatting?.fontFamily !== void 0) directFontProperties.push("fontFamily");
381
381
  if (directFormatting?.fontSize !== void 0) directFontProperties.push("fontSize");
382
382
  if (directFormatting?.color !== void 0) directFontProperties.push("color");
383
- if (directFontProperties.length === 0) return;
384
- const index = marks.findIndex(({ type }) => type.name === "runFormattingOverride");
385
- const existing = index >= 0 ? marks.at(index) : void 0;
386
- const override = schema.mark("runFormattingOverride", {
387
- ...existing?.attrs,
383
+ if (directFontProperties.length === 0) return attrs;
384
+ return {
385
+ ...attrs,
388
386
  directFontProperties
389
- });
390
- if (index >= 0) {
391
- marks[index] = override;
392
- return;
393
- }
394
- marks.push(override);
387
+ };
395
388
  };
396
389
  const COMPLEX_SCRIPT_MIRRORS = [
397
390
  {
@@ -407,25 +400,19 @@ const COMPLEX_SCRIPT_MIRRORS = [
407
400
  complex: "fontSizeCs"
408
401
  }
409
402
  ];
410
- const addComplexScriptAbsenceProvenance = (marks, schema, directFormatting) => {
403
+ const withComplexScriptAbsenceProvenance = (attrs, directFormatting) => {
411
404
  const absent = COMPLEX_SCRIPT_MIRRORS.filter(({ ordinary, complex }) => directFormatting?.[ordinary] !== void 0 && directFormatting[complex] === void 0).map(({ complex }) => complex);
412
- if (absent.length === 0) return;
413
- const index = marks.findIndex(({ type }) => type.name === "runFormattingOverride");
414
- const existing = index >= 0 ? marks.at(index) : void 0;
415
- const existingAbsences = new Set(existing?.attrs["complexScriptPropertyAbsences"] ?? []);
405
+ if (absent.length === 0) return attrs;
406
+ const existingAbsences = new Set(attrs?.complexScriptPropertyAbsences ?? []);
416
407
  for (const property of absent) existingAbsences.add(property);
417
- const override = schema.mark("runFormattingOverride", {
418
- ...existing?.attrs,
408
+ return {
409
+ ...attrs,
419
410
  complexScriptPropertyAbsences: COMPLEX_SCRIPT_RUN_PROPERTY_KEYS.filter((property) => existingAbsences.has(property))
420
- });
421
- if (index >= 0) {
422
- marks[index] = override;
423
- return;
424
- }
425
- marks.push(override);
411
+ };
426
412
  };
427
413
  function textFormattingToMarks(formatting, schema, options) {
428
414
  if (!formatting) return [];
415
+ const createMark = options?.createMark ?? ((type, attrs) => schema.mark(type, attrs));
429
416
  const marks = [];
430
417
  const overrideFormatting = options ? options.overrideFormatting : formatting;
431
418
  let overrideAttrs;
@@ -435,25 +422,24 @@ function textFormattingToMarks(formatting, schema, options) {
435
422
  formatting: options.directFormatting
436
423
  });
437
424
  else overrideAttrs = buildRunFormattingOverrideAttrs(overrideFormatting);
438
- if (overrideAttrs) marks.push(schema.mark("runFormattingOverride", overrideAttrs));
439
- if (formatting.bold) marks.push(schema.mark("bold"));
440
- if (formatting.italic) marks.push(schema.mark("italic"));
441
- if (formatting.underline && formatting.underline.style !== "none") marks.push(schema.mark("underline", {
425
+ if (formatting.bold) marks.push(createMark("bold"));
426
+ if (formatting.italic) marks.push(createMark("italic"));
427
+ if (formatting.underline && formatting.underline.style !== "none") marks.push(createMark("underline", {
442
428
  style: formatting.underline.style,
443
429
  color: formatting.underline.color
444
430
  }));
445
- if (formatting.strike || formatting.doubleStrike) marks.push(schema.mark("strike", { double: formatting.doubleStrike || false }));
446
- if (formatting.color && !formatting.color.auto) marks.push(schema.mark("textColor", {
431
+ if (formatting.strike || formatting.doubleStrike) marks.push(createMark("strike", { double: formatting.doubleStrike || false }));
432
+ if (formatting.color && !formatting.color.auto) marks.push(createMark("textColor", {
447
433
  rgb: formatting.color.rgb,
448
434
  themeColor: formatting.color.themeColor,
449
435
  themeTint: formatting.color.themeTint,
450
436
  themeShade: formatting.color.themeShade
451
437
  }));
452
- if (formatting.highlight && formatting.highlight !== "none") marks.push(schema.mark("highlight", { color: formatting.highlight }));
438
+ if (formatting.highlight && formatting.highlight !== "none") marks.push(createMark("highlight", { color: formatting.highlight }));
453
439
  const runShadingMarkAttrs = shadingToRunShadingAttrs(formatting.shading);
454
- if (runShadingMarkAttrs) marks.push(schema.mark("runShading", runShadingMarkAttrs));
455
- if (formatting.fontSize) marks.push(schema.mark("fontSize", { size: formatting.fontSize }));
456
- if (formatting.fontFamily) marks.push(schema.mark("fontFamily", {
440
+ if (runShadingMarkAttrs) marks.push(createMark("runShading", runShadingMarkAttrs));
441
+ if (formatting.fontSize) marks.push(createMark("fontSize", { size: formatting.fontSize }));
442
+ if (formatting.fontFamily) marks.push(createMark("fontFamily", {
457
443
  ascii: formatting.fontFamily.ascii,
458
444
  hAnsi: formatting.fontFamily.hAnsi,
459
445
  eastAsia: formatting.fontFamily.eastAsia,
@@ -464,31 +450,33 @@ function textFormattingToMarks(formatting, schema, options) {
464
450
  eastAsiaTheme: formatting.fontFamily.eastAsiaTheme,
465
451
  csTheme: formatting.fontFamily.csTheme
466
452
  }));
467
- if (formatting.language) marks.push(schema.mark("language", formatting.language));
468
- if (formatting.vertAlign === "superscript") marks.push(schema.mark("superscript"));
469
- else if (formatting.vertAlign === "subscript") marks.push(schema.mark("subscript"));
470
- if (formatting.allCaps) marks.push(schema.mark("allCaps"));
471
- if (formatting.smallCaps) marks.push(schema.mark("smallCaps"));
453
+ if (formatting.language) marks.push(createMark("language", formatting.language));
454
+ if (formatting.vertAlign === "superscript") marks.push(createMark("superscript"));
455
+ else if (formatting.vertAlign === "subscript") marks.push(createMark("subscript"));
456
+ if (formatting.allCaps) marks.push(createMark("allCaps"));
457
+ if (formatting.smallCaps) marks.push(createMark("smallCaps"));
472
458
  const spacing = typeof formatting.spacing === "number" ? formatting.spacing : null;
473
459
  const position = typeof formatting.position === "number" ? formatting.position : null;
474
460
  const scale = normalizeHorizontalScalePercent(formatting.scale) ?? null;
475
461
  const kerning = typeof formatting.kerning === "number" ? formatting.kerning : null;
476
- if (spacing !== null || position !== null || scale !== null || kerning !== null) marks.push(schema.mark("characterSpacing", {
462
+ if (spacing !== null || position !== null || scale !== null || kerning !== null) marks.push(createMark("characterSpacing", {
477
463
  spacing,
478
464
  position,
479
465
  scale,
480
466
  kerning
481
467
  }));
482
- if (formatting.hidden === true) marks.push(schema.mark("hidden"));
483
- if (formatting.emboss) marks.push(schema.mark("emboss"));
484
- if (formatting.imprint) marks.push(schema.mark("imprint"));
485
- if (formatting.shadow) marks.push(schema.mark("textShadow"));
486
- if (formatting.emphasisMark && formatting.emphasisMark !== "none") marks.push(schema.mark("emphasisMark", { type: formatting.emphasisMark }));
487
- if (formatting.outline) marks.push(schema.mark("textOutline"));
488
- if (formatting.rtl) marks.push(schema.mark("rtl"));
489
- if (formatting.effect && formatting.effect !== "none") marks.push(schema.mark("textEffect", { effect: formatting.effect }));
490
- addDirectFontProvenance(marks, schema, options?.directFormatting);
491
- if (options?.authoredCarrier === "preserve") addComplexScriptAbsenceProvenance(marks, schema, options.directFormatting);
468
+ if (formatting.hidden === true) marks.push(createMark("hidden"));
469
+ if (formatting.emboss) marks.push(createMark("emboss"));
470
+ if (formatting.imprint) marks.push(createMark("imprint"));
471
+ if (formatting.shadow) marks.push(createMark("textShadow"));
472
+ if (formatting.emphasisMark && formatting.emphasisMark !== "none") marks.push(createMark("emphasisMark", { type: formatting.emphasisMark }));
473
+ if (formatting.outline) marks.push(createMark("textOutline"));
474
+ if (formatting.rtl) marks.push(createMark("rtl"));
475
+ if (formatting.effect && formatting.effect !== "none") marks.push(createMark("textEffect", { effect: formatting.effect }));
476
+ let provenanceAttrs = withDirectFontProvenance(overrideAttrs, options?.directFormatting);
477
+ if (options?.authoredCarrier === "preserve") provenanceAttrs = withComplexScriptAbsenceProvenance(provenanceAttrs, options.directFormatting);
478
+ if (overrideAttrs) marks.unshift(createMark("runFormattingOverride", provenanceAttrs));
479
+ else if (provenanceAttrs) marks.push(createMark("runFormattingOverride", provenanceAttrs));
492
480
  return marks;
493
481
  }
494
482
  /**
@@ -117,7 +117,8 @@ const TextBoxExtension = createNodeExtension({
117
117
  _docxTextBodyContentState: { default: { type: "authored" } },
118
118
  _docxTrackedChange: { default: null },
119
119
  _docxInlineSdts: { default: null },
120
- _preservedAttributes: { default: null }
120
+ _preservedAttributes: { default: null },
121
+ _docxHostParagraph: { default: null }
121
122
  },
122
123
  parseDOM: [{
123
124
  tag: "div.docx-textbox",
@@ -58,6 +58,7 @@ declare const CLEARED_LIST_RENDERING_ATTRS: Readonly<{
58
58
  listMarkerSecondSlotOffsetTwips: null;
59
59
  listLevelNumFmts: null;
60
60
  listLevelStarts: null;
61
+ listLevelTabs: null;
61
62
  listAbstractNumId: null;
62
63
  listStartOverride: null;
63
64
  }>;
@@ -20,6 +20,7 @@ const CLEARED_LIST_RENDERING_ATTRS = Object.freeze({
20
20
  listMarkerSecondSlotOffsetTwips: null,
21
21
  listLevelNumFmts: null,
22
22
  listLevelStarts: null,
23
+ listLevelTabs: null,
23
24
  listAbstractNumId: null,
24
25
  listStartOverride: null
25
26
  });
@@ -84,6 +85,7 @@ function previousListAttrs(attrs) {
84
85
  ...previous.listMarkerSecondSlotOffsetTwips !== void 0 ? { listMarkerSecondSlotOffsetTwips: previous.listMarkerSecondSlotOffsetTwips } : {},
85
86
  ...previous.listLevelNumFmts !== void 0 ? { listLevelNumFmts: previous.listLevelNumFmts } : {},
86
87
  ...previous.listLevelStarts !== void 0 ? { listLevelStarts: previous.listLevelStarts } : {},
88
+ ...previous.listLevelTabs !== void 0 ? { listLevelTabs: previous.listLevelTabs } : {},
87
89
  ...previous.listAbstractNumId !== void 0 ? { listAbstractNumId: previous.listAbstractNumId } : {},
88
90
  ...previous.listStartOverride !== void 0 ? { listStartOverride: previous.listStartOverride } : {}
89
91
  };
@@ -14,6 +14,7 @@ declare const LIST_RENDERING_ATTR_BY_FIELD: {
14
14
  readonly markerAlignment: "listMarkerAlignment";
15
15
  readonly markerAllCaps: "listMarkerAllCaps";
16
16
  readonly markerSuffix: "listMarkerSuffix";
17
+ readonly levelTabs: "listLevelTabs";
17
18
  readonly levelNumFmts: "listLevelNumFmts";
18
19
  readonly levelStarts: "listLevelStarts";
19
20
  readonly abstractNumId: "listAbstractNumId";
@@ -20,6 +20,7 @@ const LIST_RENDERING_ATTR_BY_FIELD = {
20
20
  markerAlignment: "listMarkerAlignment",
21
21
  markerAllCaps: "listMarkerAllCaps",
22
22
  markerSuffix: "listMarkerSuffix",
23
+ levelTabs: "listLevelTabs",
23
24
  levelNumFmts: "listLevelNumFmts",
24
25
  levelStarts: "listLevelStarts",
25
26
  abstractNumId: "listAbstractNumId",
@@ -48,6 +49,7 @@ const listRenderingAttrPatch = (rendering) => {
48
49
  listMarkerAlignment: rendering.markerAlignment || void 0,
49
50
  listMarkerAllCaps: rendering.markerAllCaps || void 0,
50
51
  listMarkerSuffix: rendering.markerSuffix || void 0,
52
+ listLevelTabs: rendering.levelTabs?.length ? rendering.levelTabs : void 0,
51
53
  listLevelNumFmts: rendering.levelNumFmts || void 0,
52
54
  listLevelStarts: rendering.levelStarts || void 0,
53
55
  listAbstractNumId: rendering.abstractNumId,
@@ -71,6 +73,7 @@ const listRenderingFromAttrs = ({ attrs, numId }) => {
71
73
  markerAlignment: attrs.listMarkerAlignment ?? void 0,
72
74
  markerAllCaps: attrs.listMarkerAllCaps ?? void 0,
73
75
  markerSuffix: attrs.listMarkerSuffix ?? void 0,
76
+ levelTabs: attrs.listLevelTabs ?? void 0,
74
77
  levelNumFmts: attrs.listLevelNumFmts ?? void 0,
75
78
  levelStarts: attrs.listLevelStarts ?? void 0,
76
79
  abstractNumId: attrs.listAbstractNumId ?? void 0,
@@ -167,6 +167,8 @@ type ParagraphAttrs = {
167
167
  listLevelNumFmts?: document_d_exports.CounterFormat[];
168
168
  /** Initial counter for each level used by multi-level marker templates. */
169
169
  listLevelStarts?: number[];
170
+ /** Custom tab stops of the numbering level (`w:lvl/w:pPr/w:tabs`). */
171
+ listLevelTabs?: document_d_exports.TabStop[];
170
172
  /** Abstract numbering ID shared by numbering instances. */
171
173
  listAbstractNumId?: number;
172
174
  /** Numbering start override for this numId/level. */
@@ -325,7 +327,7 @@ type ParagraphPropertyChangeAttrs = Omit<document_d_exports.ParagraphPropertyCha
325
327
  };
326
328
  previousFormatting?: Omit<document_d_exports.ParagraphFormatting, "numPr"> & {
327
329
  numPr?: ParagraphAttrs["numPr"] | null;
328
- } & Partial<Pick<ParagraphAttrs, "listIsBullet" | "listIsLegal" | "listNumFmt" | "listMarker" | "listMarkerTemplate" | "listMarkerHidden" | "listMarkerFormatting" | "listMarkerAlignment" | "listMarkerSuffix" | "listMarkerAllCaps" | "listImplicitChildLevelAdvances" | "listMarkerSecondSlotOffsetTwips" | "listLevelNumFmts" | "listLevelStarts" | "listAbstractNumId" | "listStartOverride" | "lineSpacingExplicit" | "direction" | "_autospacingBase">>;
330
+ } & Partial<Pick<ParagraphAttrs, "listIsBullet" | "listIsLegal" | "listNumFmt" | "listMarker" | "listMarkerTemplate" | "listMarkerHidden" | "listMarkerFormatting" | "listMarkerAlignment" | "listMarkerSuffix" | "listMarkerAllCaps" | "listImplicitChildLevelAdvances" | "listMarkerSecondSlotOffsetTwips" | "listLevelNumFmts" | "listLevelStarts" | "listLevelTabs" | "listAbstractNumId" | "listStartOverride" | "lineSpacingExplicit" | "direction" | "_autospacingBase">>;
329
331
  currentFormatting?: document_d_exports.ParagraphFormatting;
330
332
  };
331
333
  /**
@@ -878,6 +880,16 @@ type TextBoxAttrs = {
878
880
  * itself and keeps its own.
879
881
  */
880
882
  _preservedAttributes?: document_d_exports.PreservedAttribute[];
883
+ /**
884
+ * The paragraph properties of the `w:p` this node was lifted out of.
885
+ *
886
+ * An inline drawing is run content of its paragraph, so that paragraph's
887
+ * spacing, indentation and alignment still place the box and must be
888
+ * written back around it. Only a `"standalone"` placement has a host to
889
+ * speak for. The host's identity (`paraId`, source token, attribute
890
+ * remainder) is not carried here: a copied node must not duplicate it.
891
+ */
892
+ _docxHostParagraph?: Omit<ParagraphAttrs, "paraId" | "textId" | "_preservedAttributes">;
881
893
  };
882
894
  /** Internal inline position marker for an extracted text box block. */
883
895
  type TextBoxAnchorAttrs = {
@@ -0,0 +1,13 @@
1
+ import { Node } from "prosemirror-model";
2
+ //#region src/prosemirror/textBoxHostParagraph.d.ts
3
+ /**
4
+ * The `w:p` a standalone text box was lifted out of, as a childless paragraph
5
+ * node over the host's paragraph attributes, or `undefined` when the box
6
+ * carries none.
7
+ *
8
+ * Building the node runs the carried attributes through the paragraph schema,
9
+ * so every consumer reads them with the validation any paragraph's get.
10
+ */
11
+ declare const textBoxHostParagraph: (textBox: Node) => Node | undefined;
12
+ //#endregion
13
+ export { textBoxHostParagraph };
@@ -0,0 +1,21 @@
1
+ import { expectTextBoxAttrs } from "./attrs/index.js";
2
+ //#region src/prosemirror/textBoxHostParagraph.ts
3
+ const hostParagraphs = /* @__PURE__ */ new WeakMap();
4
+ /**
5
+ * The `w:p` a standalone text box was lifted out of, as a childless paragraph
6
+ * node over the host's paragraph attributes, or `undefined` when the box
7
+ * carries none.
8
+ *
9
+ * Building the node runs the carried attributes through the paragraph schema,
10
+ * so every consumer reads them with the validation any paragraph's get.
11
+ */
12
+ const textBoxHostParagraph = (textBox) => {
13
+ const cached = hostParagraphs.get(textBox);
14
+ if (cached !== void 0) return cached ?? void 0;
15
+ const host = expectTextBoxAttrs(textBox)._docxHostParagraph;
16
+ const paragraph = host ? textBox.type.schema.nodes["paragraph"]?.create(host) : void 0;
17
+ hostParagraphs.set(textBox, paragraph ?? null);
18
+ return paragraph;
19
+ };
20
+ //#endregion
21
+ export { textBoxHostParagraph };
@@ -303,88 +303,99 @@ const validateNodeAttrs = (node, path, issues) => {
303
303
  });
304
304
  }
305
305
  };
306
+ /**
307
+ * Marks already validated with no issues. A mark's attrs never change, and a
308
+ * conversion shares one instance per distinct mark across thousands of runs,
309
+ * so each distinct mark is validated once.
310
+ */
311
+ const validMarks = /* @__PURE__ */ new WeakSet();
306
312
  const validateMarks = (marks, path, issues) => {
307
313
  for (const [index, mark] of marks.entries()) {
308
- const markPath = `${path}.marks[${index}]`;
309
- switch (mark.type.name) {
310
- case "bold":
311
- case "italic":
312
- case "subscript":
313
- case "superscript":
314
- case "allCaps":
315
- case "smallCaps":
316
- case "emboss":
317
- case "imprint":
318
- case "hidden":
319
- case "textShadow":
320
- case "textOutline":
321
- case "rtl": continue;
322
- case "textEffect":
323
- appendAttrIssues(markPath, readTextEffectMarkAttrs(mark), issues);
324
- continue;
325
- case "underline":
326
- appendAttrIssues(markPath, readUnderlineMarkAttrs(mark), issues);
327
- continue;
328
- case "strike":
329
- appendAttrIssues(markPath, readStrikeMarkAttrs(mark), issues);
330
- continue;
331
- case "textColor":
332
- appendAttrIssues(markPath, readTextColorMarkAttrs(mark), issues);
333
- continue;
334
- case "highlight":
335
- appendAttrIssues(markPath, readHighlightMarkAttrs(mark), issues);
336
- continue;
337
- case "runShading":
338
- appendAttrIssues(markPath, readRunShadingMarkAttrs(mark), issues);
339
- continue;
340
- case "fontSize":
341
- appendAttrIssues(markPath, readFontSizeMarkAttrs(mark), issues);
342
- continue;
343
- case "fontFamily":
344
- appendAttrIssues(markPath, readFontFamilyMarkAttrs(mark), issues);
345
- continue;
346
- case "language":
347
- appendAttrIssues(markPath, readLanguageMarkAttrs(mark), issues);
348
- continue;
349
- case "characterSpacing":
350
- appendAttrIssues(markPath, readCharacterSpacingMarkAttrs(mark), issues);
351
- continue;
352
- case "characterStyle":
353
- appendAttrIssues(markPath, readCharacterStyleMarkAttrs(mark), issues);
354
- continue;
355
- case "emphasisMark":
356
- appendAttrIssues(markPath, readEmphasisMarkAttrs(mark), issues);
357
- continue;
358
- case "footnoteRef":
359
- appendAttrIssues(markPath, readFootnoteRefMarkAttrs(mark), issues);
360
- continue;
361
- case "comment":
362
- appendAttrIssues(markPath, readCommentMarkAttrs(mark), issues);
363
- continue;
364
- case "insertion":
365
- case "deletion":
366
- appendAttrIssues(markPath, readTrackedChangeMarkAttrs(mark), issues);
367
- continue;
368
- case "runPropertyChange":
369
- appendAttrIssues(markPath, readRunPropertyChangeMarkAttrs(mark), issues);
370
- continue;
371
- case "runIdentity":
372
- appendAttrIssues(markPath, readRunIdentityMarkAttrs(mark), issues);
373
- continue;
374
- case "runFormattingOverride":
375
- appendAttrIssues(markPath, readRunFormattingOverrideMarkAttrs(mark), issues);
376
- continue;
377
- case "hyperlink":
378
- appendAttrIssues(markPath, readHyperlinkMarkAttrs(mark), issues);
379
- continue;
380
- case "inlineWrapper":
381
- appendAttrIssues(markPath, readInlineWrapperMarkAttrs(mark), issues);
382
- continue;
383
- default: issues.push({
384
- path: `${markPath}.type.name`,
385
- message: `Unsupported ProseMirror mark type ${mark.type.name}.`
386
- });
387
- }
314
+ if (validMarks.has(mark)) continue;
315
+ const issueCount = issues.length;
316
+ validateMark(mark, `${path}.marks[${index}]`, issues);
317
+ if (issues.length === issueCount) validMarks.add(mark);
318
+ }
319
+ };
320
+ const validateMark = (mark, markPath, issues) => {
321
+ switch (mark.type.name) {
322
+ case "bold":
323
+ case "italic":
324
+ case "subscript":
325
+ case "superscript":
326
+ case "allCaps":
327
+ case "smallCaps":
328
+ case "emboss":
329
+ case "imprint":
330
+ case "hidden":
331
+ case "textShadow":
332
+ case "textOutline":
333
+ case "rtl": return;
334
+ case "textEffect":
335
+ appendAttrIssues(markPath, readTextEffectMarkAttrs(mark), issues);
336
+ return;
337
+ case "underline":
338
+ appendAttrIssues(markPath, readUnderlineMarkAttrs(mark), issues);
339
+ return;
340
+ case "strike":
341
+ appendAttrIssues(markPath, readStrikeMarkAttrs(mark), issues);
342
+ return;
343
+ case "textColor":
344
+ appendAttrIssues(markPath, readTextColorMarkAttrs(mark), issues);
345
+ return;
346
+ case "highlight":
347
+ appendAttrIssues(markPath, readHighlightMarkAttrs(mark), issues);
348
+ return;
349
+ case "runShading":
350
+ appendAttrIssues(markPath, readRunShadingMarkAttrs(mark), issues);
351
+ return;
352
+ case "fontSize":
353
+ appendAttrIssues(markPath, readFontSizeMarkAttrs(mark), issues);
354
+ return;
355
+ case "fontFamily":
356
+ appendAttrIssues(markPath, readFontFamilyMarkAttrs(mark), issues);
357
+ return;
358
+ case "language":
359
+ appendAttrIssues(markPath, readLanguageMarkAttrs(mark), issues);
360
+ return;
361
+ case "characterSpacing":
362
+ appendAttrIssues(markPath, readCharacterSpacingMarkAttrs(mark), issues);
363
+ return;
364
+ case "characterStyle":
365
+ appendAttrIssues(markPath, readCharacterStyleMarkAttrs(mark), issues);
366
+ return;
367
+ case "emphasisMark":
368
+ appendAttrIssues(markPath, readEmphasisMarkAttrs(mark), issues);
369
+ return;
370
+ case "footnoteRef":
371
+ appendAttrIssues(markPath, readFootnoteRefMarkAttrs(mark), issues);
372
+ return;
373
+ case "comment":
374
+ appendAttrIssues(markPath, readCommentMarkAttrs(mark), issues);
375
+ return;
376
+ case "insertion":
377
+ case "deletion":
378
+ appendAttrIssues(markPath, readTrackedChangeMarkAttrs(mark), issues);
379
+ return;
380
+ case "runPropertyChange":
381
+ appendAttrIssues(markPath, readRunPropertyChangeMarkAttrs(mark), issues);
382
+ return;
383
+ case "runIdentity":
384
+ appendAttrIssues(markPath, readRunIdentityMarkAttrs(mark), issues);
385
+ return;
386
+ case "runFormattingOverride":
387
+ appendAttrIssues(markPath, readRunFormattingOverrideMarkAttrs(mark), issues);
388
+ return;
389
+ case "hyperlink":
390
+ appendAttrIssues(markPath, readHyperlinkMarkAttrs(mark), issues);
391
+ return;
392
+ case "inlineWrapper":
393
+ appendAttrIssues(markPath, readInlineWrapperMarkAttrs(mark), issues);
394
+ return;
395
+ default: issues.push({
396
+ path: `${markPath}.type.name`,
397
+ message: `Unsupported ProseMirror mark type ${mark.type.name}.`
398
+ });
388
399
  }
389
400
  };
390
401
  const appendAttrIssues = (path, result, issues) => {
@@ -2,6 +2,7 @@ import { BUILT_IN_STYLE_NAME, builtInHeadingStyleName } from "../docx/builtInSty
2
2
  import "../docx/defaultParagraphStyle.js";
3
3
  import { createParseWarningCollector } from "../docx/parseContext.js";
4
4
  import { formatParseWarnings } from "../docx/parseWarningMessage.js";
5
+ import "../docx/settingsParser.js";
5
6
  import { STYLE_SET_PART, normalizeDocumentStyleSet } from "../style-sets/styleSetNormalization.js";
6
7
  import "../style-sets/types.js";
7
8
  import { panic } from "better-result";
@@ -13,6 +14,12 @@ import { DOCX_CONFORMANCE_CLASSES } from "@stll/docx-core/model";
13
14
  * Provides functions to create new documents programmatically.
14
15
  */
15
16
  /**
17
+ * `compatibilityMode` a new document declares, so it is laid out, and read
18
+ * back, with the current rules rather than the oldest ones a package without
19
+ * the setting gets.
20
+ */
21
+ const NEW_DOCUMENT_COMPATIBILITY_MODE = 15;
22
+ /**
16
23
  * Get default paragraph styles (matching Google Docs defaults)
17
24
  *
18
25
  * Font sizes are in half-points (e.g., 22 = 11pt, 40 = 20pt)
@@ -398,7 +405,9 @@ function createEmptyDocument(options = {}) {
398
405
  if (styleSet?.numbering) docxPackage.numbering = structuredClone(styleSet.numbering);
399
406
  if (styleSet?.theme) docxPackage.theme = structuredClone(styleSet.theme);
400
407
  if (styleSet?.fontTable) docxPackage.fontTable = structuredClone(styleSet.fontTable);
401
- if (styleSet?.settings) docxPackage.settings = structuredClone(styleSet.settings);
408
+ const settings = styleSet?.settings ? structuredClone(styleSet.settings) : { defaultTabStop: 720 };
409
+ settings.compatibilityMode ??= NEW_DOCUMENT_COMPATIBILITY_MODE;
410
+ docxPackage.settings = settings;
402
411
  const parseWarnings = styleSetWarnings();
403
412
  const document = {
404
413
  package: docxPackage,
@@ -50,8 +50,31 @@ declare function hasCjk(text: string): boolean;
50
50
  * overlap the presentation forms below.
51
51
  */
52
52
  declare function isComplexScriptCodePoint(cp: number): boolean;
53
- /** Which font slot a single code point selects. CJK wins where ranges meet. */
54
- declare function scriptClassOf(cp: number): ScriptClass;
53
+ /**
54
+ * True when `w:rFonts/@w:hint="eastAsia"` moves a code point from the
55
+ * `w:hAnsi` slot to the `w:eastAsia` slot (ECMA-376 §17.3.2.26): the ranges
56
+ * the font-slot table resolves to the East Asian font whenever the hint is
57
+ * `eastAsia`. Basic Latin never moves, and neither do the accented letters of
58
+ * Latin-1 Supplement and the Latin Extended blocks, whose move the table also
59
+ * conditions on the run's East Asian language.
60
+ */
61
+ declare function isEastAsiaHintCodePoint(cp: number): boolean;
62
+ /**
63
+ * Whether a run's `w:hint="eastAsia"` takes effect. A run under `w:cs` or
64
+ * `w:rtl` formats every character with the complex-script slot, which the
65
+ * hint does not override.
66
+ */
67
+ declare function eastAsiaHintApplies(run: {
68
+ readonly eastAsiaHint?: boolean | undefined;
69
+ readonly forceComplexScript?: boolean | undefined;
70
+ readonly rtl?: boolean | undefined;
71
+ }): boolean;
72
+ /**
73
+ * Which font slot a single code point selects. CJK wins where ranges meet.
74
+ * `eastAsiaHint` is the run's effective `w:hint="eastAsia"`
75
+ * (see {@link eastAsiaHintApplies}).
76
+ */
77
+ declare function scriptClassOf(cp: number, eastAsiaHint?: boolean): ScriptClass;
55
78
  /**
56
79
  * True when the text contains at least one complex-script code point. Callers
57
80
  * use this to skip segmentation entirely on the common all-Latin path.
@@ -68,11 +91,17 @@ declare function isRightToLeftCodePoint(cp: number): boolean;
68
91
  /** True when the text contains at least one right-to-left code point. */
69
92
  declare function hasRightToLeft(text: string): boolean;
70
93
  declare function hasComplexScript(text: string): boolean;
94
+ /**
95
+ * True when some code point of the text selects the `w:eastAsia` slot: a CJK
96
+ * code point, or under an effective `w:hint="eastAsia"` one the hint moves.
97
+ */
98
+ declare function hasEastAsiaSlotText(text: string, eastAsiaHint?: boolean): boolean;
71
99
  /**
72
100
  * Split text into maximal runs of one script class (CJK vs. non-CJK). Iterates
73
101
  * by code point so astral ideographs (surrogate pairs) are never split between
74
102
  * fonts. Empty input yields no segments; single-class input yields one.
103
+ * `eastAsiaHint` is the run's effective `w:hint="eastAsia"`.
75
104
  */
76
- declare function segmentByScript(text: string): ScriptSegment[];
105
+ declare function segmentByScript(text: string, eastAsiaHint?: boolean): ScriptSegment[];
77
106
  //#endregion
78
- export { SCRIPT_CLASS, ScriptClass, ScriptSegment, hasCjk, hasComplexScript, hasRightToLeft, isCjkCodePoint, isComplexScriptCodePoint, isRightToLeftCodePoint, scriptClassOf, segmentByScript };
107
+ export { SCRIPT_CLASS, ScriptClass, ScriptSegment, eastAsiaHintApplies, hasCjk, hasComplexScript, hasEastAsiaSlotText, hasRightToLeft, isCjkCodePoint, isComplexScriptCodePoint, isEastAsiaHintCodePoint, isRightToLeftCodePoint, scriptClassOf, segmentByScript };