@stll/folio-core 0.33.1 → 0.34.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 (121) hide show
  1. package/dist/ai-edits/apply.d.ts +15 -0
  2. package/dist/ai-edits/apply.js +271 -48
  3. package/dist/ai-edits/headless.d.ts +47 -3
  4. package/dist/ai-edits/headless.js +53 -3
  5. package/dist/ai-edits/index.d.ts +1 -1
  6. package/dist/ai-edits/snapshot.d.ts +19 -1
  7. package/dist/ai-edits/snapshot.js +49 -5
  8. package/dist/ai-edits/table-geometry.d.ts +56 -0
  9. package/dist/ai-edits/table-geometry.js +217 -0
  10. package/dist/ai-edits/table-row-column-mutations.d.ts +34 -16
  11. package/dist/ai-edits/table-row-column-mutations.js +12 -4
  12. package/dist/ai-edits/table-template.d.ts +60 -0
  13. package/dist/ai-edits/table-template.js +176 -0
  14. package/dist/ai-edits/types.d.ts +13 -6
  15. package/dist/compare/__fixtures__/body-sequence.d.ts +61 -2
  16. package/dist/compare/__fixtures__/body-sequence.js +94 -6
  17. package/dist/compare/compare.d.ts +14 -7
  18. package/dist/compare/compare.js +136 -38
  19. package/dist/compare/formatting.d.ts +1 -1
  20. package/dist/compare/formatting.js +38 -9
  21. package/dist/compare/plan.d.ts +31 -1
  22. package/dist/compare/plan.js +233 -66
  23. package/dist/compare/types.d.ts +9 -7
  24. package/dist/compare/types.js +7 -5
  25. package/dist/compare/verification.d.ts +31 -12
  26. package/dist/compare/verification.js +106 -18
  27. package/dist/compat/eigenpal.d.ts +4 -4
  28. package/dist/compat/eigenpal.js +2 -2
  29. package/dist/controller/headerFooterEditorManager.js +11 -9
  30. package/dist/controller/layoutPipeline.js +24 -3
  31. package/dist/display-list/build/watermarkPrimitives.js +15 -3
  32. package/dist/display-list/primitives.d.ts +1 -1
  33. package/dist/document-operations.d.ts +10 -1
  34. package/dist/document-operations.js +33 -5
  35. package/dist/docx/appVersionNormalization.d.ts +49 -0
  36. package/dist/docx/appVersionNormalization.js +74 -0
  37. package/dist/docx/blockContentParser.js +3 -2
  38. package/dist/docx/drawingUtils.js +4 -3
  39. package/dist/docx/headerFooterParser.js +8 -14
  40. package/dist/docx/paragraphParser.js +48 -2
  41. package/dist/docx/rezip.d.ts +10 -4
  42. package/dist/docx/rezip.js +54 -18
  43. package/dist/docx/runParser.js +9 -8
  44. package/dist/docx/sdtProperties.js +4 -3
  45. package/dist/docx/selectiveSave.js +7 -6
  46. package/dist/docx/serializer/commentSerializer.d.ts +1 -1
  47. package/dist/docx/serializer/commentSerializer.js +43 -19
  48. package/dist/docx/serializer/documentSerializer.d.ts +3 -1
  49. package/dist/docx/serializer/documentSerializer.js +42 -78
  50. package/dist/docx/serializer/fontTableSerializer.js +8 -5
  51. package/dist/docx/serializer/headerFooterSerializer.d.ts +4 -1
  52. package/dist/docx/serializer/headerFooterSerializer.js +55 -31
  53. package/dist/docx/serializer/noteSerializer.js +34 -30
  54. package/dist/docx/serializer/numberingSerializer.js +8 -4
  55. package/dist/docx/serializer/paragraphSerializer.d.ts +1 -1
  56. package/dist/docx/serializer/paragraphSerializer.js +22 -12
  57. package/dist/docx/serializer/partNamespaces.d.ts +78 -0
  58. package/dist/docx/serializer/partNamespaces.js +324 -0
  59. package/dist/docx/serializer/runSerializer.js +1 -1
  60. package/dist/docx/serializer/settingsSerializer.js +8 -2
  61. package/dist/docx/serializer/stylesSerializer.js +8 -5
  62. package/dist/docx/serializer/tableSerializer.js +83 -18
  63. package/dist/docx/serializer/themeSerializer.js +10 -2
  64. package/dist/docx/server/build.d.ts +1 -1
  65. package/dist/docx/settingsParser.js +3 -0
  66. package/dist/docx/strictValueEncodings.gen.d.ts +15 -0
  67. package/dist/docx/strictValueEncodings.gen.js +275 -0
  68. package/dist/docx/tableParser.d.ts +0 -6
  69. package/dist/docx/tableParser.js +52 -7
  70. package/dist/docx/transitionalSpelling.d.ts +23 -0
  71. package/dist/docx/transitionalSpelling.js +36 -0
  72. package/dist/docx/universalMeasure.d.ts +20 -0
  73. package/dist/docx/universalMeasure.js +32 -0
  74. package/dist/docx/verbatimCapture.d.ts +20 -0
  75. package/dist/docx/verbatimCapture.js +131 -0
  76. package/dist/docx/vmlImageParser.js +4 -3
  77. package/dist/docx/watermarkParser.d.ts +2 -4
  78. package/dist/docx/watermarkParser.js +8 -9
  79. package/dist/docx/xmlParser.d.ts +23 -2
  80. package/dist/docx/xmlParser.js +43 -11
  81. package/dist/headless-layout.js +14 -2
  82. package/dist/index.d.ts +4 -4
  83. package/dist/index.js +2 -2
  84. package/dist/layout-bridge/convert/footnoteLayout.d.ts +2 -2
  85. package/dist/layout-bridge/convert/footnoteLayout.js +23 -10
  86. package/dist/layout-bridge/convert/headerFooterLayout.js +13 -2
  87. package/dist/layout-bridge/convert/toFlowBlocks.js +96 -13
  88. package/dist/layout-engine/index.js +11 -4
  89. package/dist/layout-engine/justifiedLineFit.d.ts +4 -4
  90. package/dist/layout-engine/justifiedLineFit.js +4 -4
  91. package/dist/layout-engine/measure/lineBreakProvider.js +1 -0
  92. package/dist/layout-engine/measure/measureBlocks.js +1 -1
  93. package/dist/layout-engine/measure/measureParagraph.js +29 -29
  94. package/dist/layout-painter/renderPage.js +6 -1
  95. package/dist/layout-painter/renderParagraph.js +18 -8
  96. package/dist/layout-painter/renderWatermark.js +11 -4
  97. package/dist/model.d.ts +3 -3
  98. package/dist/model.js +2 -2
  99. package/dist/prosemirror/attrs/index.js +11 -0
  100. package/dist/prosemirror/commands/comments.js +24 -3
  101. package/dist/prosemirror/containerFinalParagraph.d.ts +47 -0
  102. package/dist/prosemirror/containerFinalParagraph.js +92 -0
  103. package/dist/prosemirror/conversion/fromProseDoc.d.ts +8 -1
  104. package/dist/prosemirror/conversion/fromProseDoc.js +47 -9
  105. package/dist/prosemirror/conversion/toProseDoc.js +61 -14
  106. package/dist/prosemirror/extensions/core/DocExtension.js +7 -1
  107. package/dist/prosemirror/extensions/core/ParagraphExtension.js +1 -0
  108. package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.js +1 -0
  109. package/dist/prosemirror/extensions/nodes/TableExtension.js +5 -0
  110. package/dist/prosemirror/schema/marks.d.ts +3 -9
  111. package/dist/prosemirror/schema/nodes.d.ts +22 -0
  112. package/dist/server.d.ts +1 -1
  113. package/dist/types/block-id.d.ts +12 -1
  114. package/dist/types/block-id.js +17 -1
  115. package/dist/utils/canonicalJson.d.ts +14 -0
  116. package/dist/utils/canonicalJson.js +19 -0
  117. package/dist/utils/fontResolver.js +51 -0
  118. package/dist/utils/formatToStyle.d.ts +1 -1
  119. package/dist/utils/formatToStyle.js +41 -1
  120. package/dist/watermark/index.js +7 -0
  121. package/package.json +2 -2
package/dist/server.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { FolioAIBlock, FolioAIBlockAnchor, FolioAIBlockKind, FolioAIBlockPreviewRun, FolioAIComment, FolioAIEditApplyMode, FolioAIEditApplyResult, FolioAIEditNormalization, FolioAIEditNormalizationCode, FolioAIEditOperation, FolioAIEditPrecondition, FolioAIEditSnapshot, FolioAIInlineFormatting, FolioAITextRangeHandle, FolioDocumentNavigationTarget, FolioDocumentOutline, FolioDocumentOutlineEntry, FolioDocumentSection, FolioDocumentSectionHandle, FolioDocumentSectionReadResult } from "./ai-edits/types.js";
2
2
  import { FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_BATCH_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FolioDocumentOperation, FolioDocumentOperationAffectedTarget, FolioDocumentOperationBatch, FolioDocumentOperationBatchPrecondition, FolioDocumentOperationCapabilities, FolioDocumentOperationIssue, FolioDocumentOperationMode, FolioDocumentOperationPrecondition, FolioDocumentOperationQueuedOperation, FolioDocumentOperationReceipt, FolioDocumentOperationRecovery, FolioDocumentOperationResult, FolioDocumentOperationResultBase, FolioDocumentOperationStatus, FolioDocumentOperationStory, FolioDocumentOperationType, FolioDocumentOperationUndoFailureReason, FolioDocumentOperationUndoHandle, FolioDocumentOperationUndoResult, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch } from "./document-operations.js";
3
3
  import { FolioReviewChange, FolioReviewChangeKind } from "./ai-edits/read.js";
4
- import { ApplyFolioAIEditsToBufferOptions, ApplyFolioAIEditsToBufferResult, FOLIO_RESOLVED_REVIEWED_VIEWS, FOLIO_REVIEWED_VIEWS, FolioApplyDocumentOperationsOptions, FolioApplyDocumentOperationsToStoryOptions, FolioApplyOperationsOptions, FolioDocumentStory, FolioDocumentStoryHandle, FolioDocumentStoryNotFoundError, FolioDocxReviewer, FolioDocxReviewerOptions, FolioEditableDocumentStoryHandle, FolioReadReviewedStoryOptions, FolioResolveReviewedStoryOptions, FolioResolvedReviewedView, FolioReviewChangeFilter, FolioReviewComment, FolioReviewCommentFilter, FolioReviewCommentReply, FolioReviewReplyInput, FolioReviewedStory, FolioReviewedView, UnsupportedFolioReviewedViewError, applyFolioAIEditsToBuffer, isFolioResolvedReviewedView, isFolioReviewedView } from "./ai-edits/headless.js";
5
4
  import { createFolioAITextRangeHandle, hashFolioAIBlockText, isFolioAIContentBlock, normalizeFolioAIBlockText } from "./ai-edits/snapshot.js";
5
+ import { ApplyFolioAIEditsToBufferOptions, ApplyFolioAIEditsToBufferResult, FOLIO_RESOLVED_REVIEWED_VIEWS, FOLIO_REVIEWED_VIEWS, FolioApplyDocumentOperationsOptions, FolioApplyDocumentOperationsToStoryOptions, FolioApplyOperationsOptions, FolioDocumentStory, FolioDocumentStoryHandle, FolioDocumentStoryNotFoundError, FolioDocxReviewer, FolioDocxReviewerOptions, FolioEditableDocumentStoryHandle, FolioReadReviewedStoryOptions, FolioResolveReviewedStoryOptions, FolioResolvedReviewedView, FolioReviewChangeFilter, FolioReviewComment, FolioReviewCommentFilter, FolioReviewCommentReply, FolioReviewReplyInput, FolioReviewedStory, FolioReviewedView, UnsupportedFolioReviewedViewError, applyFolioAIEditsToBuffer, isFolioResolvedReviewedView, isFolioReviewedView } from "./ai-edits/headless.js";
6
6
  import { getFolioDocumentOutline, readFolioDocumentSection } from "./ai-edits/scoped-reading.js";
7
7
  import { DeriveBlockIdInput, FolioBlockId, deriveBlockId, getFolioParaIdFromBlockId, isFolioBlockId, isSequentialFolioBlockId } from "./types/block-id.js";
8
8
  import { DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION, DocumentPreset, DocumentStyleSet } from "./style-sets/types.js";
@@ -61,6 +61,17 @@ declare const isBlankFolioBlockId: (id: string) => boolean;
61
61
  * without an upfront brand check.
62
62
  */
63
63
  declare const getFolioParaIdFromBlockId: (id: string) => string | null;
64
+ /**
65
+ * The id a block recorded earlier answers to in the document as parsed now.
66
+ *
67
+ * A paragraph id above the 31-bit bound the schema sets is brought into range
68
+ * on parse, so an id recorded from such a paragraph before that no longer
69
+ * names it. The mapping is a pure function of the id alone, so the recorded id
70
+ * resolves to the current one with no document in hand. Sequential and blank
71
+ * ids carry no paragraph id, and an id the parser would not have mapped is
72
+ * returned as it is.
73
+ */
74
+ declare const currentFolioBlockId: (id: string) => string;
64
75
  /**
65
76
  * The 1-based document position encoded in a sequential fallback id
66
77
  * (`seq-0011` -> 11), or `null` for paraId-backed ids. The number is
@@ -76,4 +87,4 @@ declare const getSequentialFolioBlockIdIndex: (id: string) => number | null;
76
87
  */
77
88
  declare const isFolioBlockId: (value: unknown) => value is FolioBlockId;
78
89
  //#endregion
79
- export { DeriveBlockIdInput, FolioBlockId, deriveBlankBlockId, deriveBlockId, getFolioParaIdFromBlockId, getSequentialFolioBlockIdIndex, isBlankFolioBlockId, isFolioBlockId, isSequentialFolioBlockId };
90
+ export { DeriveBlockIdInput, FolioBlockId, currentFolioBlockId, deriveBlankBlockId, deriveBlockId, getFolioParaIdFromBlockId, getSequentialFolioBlockIdIndex, isBlankFolioBlockId, isFolioBlockId, isSequentialFolioBlockId };
@@ -1,3 +1,5 @@
1
+ import { paraIdInRange } from "../docx/paraIdRangeNormalization.js";
2
+ import { isValidHexId } from "../utils/hexId.js";
1
3
  //#region src/types/block-id.ts
2
4
  /**
3
5
  * Single source of truth for folio block ids.
@@ -91,6 +93,20 @@ const isBlankFolioBlockId = (id) => BLANK_BLOCK_ID_PATTERN.test(id);
91
93
  */
92
94
  const getFolioParaIdFromBlockId = (id) => isSequentialFolioBlockId(id) || isBlankFolioBlockId(id) ? null : id;
93
95
  /**
96
+ * The id a block recorded earlier answers to in the document as parsed now.
97
+ *
98
+ * A paragraph id above the 31-bit bound the schema sets is brought into range
99
+ * on parse, so an id recorded from such a paragraph before that no longer
100
+ * names it. The mapping is a pure function of the id alone, so the recorded id
101
+ * resolves to the current one with no document in hand. Sequential and blank
102
+ * ids carry no paragraph id, and an id the parser would not have mapped is
103
+ * returned as it is.
104
+ */
105
+ const currentFolioBlockId = (id) => {
106
+ const paraId = getFolioParaIdFromBlockId(id);
107
+ return paraId !== null && isValidHexId(paraId) ? paraIdInRange(paraId) : id;
108
+ };
109
+ /**
94
110
  * The 1-based document position encoded in a sequential fallback id
95
111
  * (`seq-0011` -> 11), or `null` for paraId-backed ids. The number is
96
112
  * the block's position in the same non-empty-block walk both the
@@ -114,4 +130,4 @@ const isFolioBlockId = (value) => {
114
130
  return true;
115
131
  };
116
132
  //#endregion
117
- export { deriveBlankBlockId, deriveBlockId, getFolioParaIdFromBlockId, getSequentialFolioBlockIdIndex, isBlankFolioBlockId, isFolioBlockId, isSequentialFolioBlockId };
133
+ export { currentFolioBlockId, deriveBlankBlockId, deriveBlockId, getFolioParaIdFromBlockId, getSequentialFolioBlockIdIndex, isBlankFolioBlockId, isFolioBlockId, isSequentialFolioBlockId };
@@ -0,0 +1,14 @@
1
+ //#region src/utils/canonicalJson.d.ts
2
+ /**
3
+ * JSON with object keys in a fixed order, for comparing two values that were
4
+ * built by different code paths.
5
+ *
6
+ * `JSON.stringify` writes keys in insertion order, so two objects holding the
7
+ * same properties compare unequal whenever one was assembled in a different
8
+ * sequence — which is what happens whenever a parsed record is compared with a
9
+ * rebuilt one. `undefined` members are omitted, so an absent property and one
10
+ * explicitly set to `undefined` read alike.
11
+ */
12
+ declare const canonicalJson: (value: unknown) => string;
13
+ //#endregion
14
+ export { canonicalJson };
@@ -0,0 +1,19 @@
1
+ //#region src/utils/canonicalJson.ts
2
+ /**
3
+ * JSON with object keys in a fixed order, for comparing two values that were
4
+ * built by different code paths.
5
+ *
6
+ * `JSON.stringify` writes keys in insertion order, so two objects holding the
7
+ * same properties compare unequal whenever one was assembled in a different
8
+ * sequence — which is what happens whenever a parsed record is compared with a
9
+ * rebuilt one. `undefined` members are omitted, so an absent property and one
10
+ * explicitly set to `undefined` read alike.
11
+ */
12
+ const canonicalJson = (value) => {
13
+ if (value === null || value === void 0) return "null";
14
+ if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
15
+ if (typeof value !== "object") return JSON.stringify(value) ?? "null";
16
+ return `{${Object.entries(value).filter(([, entry]) => entry !== void 0).toSorted(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => `${JSON.stringify(key)}:${canonicalJson(entry)}`).join(",")}}`;
17
+ };
18
+ //#endregion
19
+ export { canonicalJson };
@@ -191,6 +191,23 @@ const FONT_MAPPINGS = {
191
191
  unitsPerEm: 2048
192
192
  })
193
193
  },
194
+ david: {
195
+ googleFont: "Noto Serif Hebrew",
196
+ category: "serif",
197
+ fallbackStack: [
198
+ "David",
199
+ "Noto Serif Hebrew",
200
+ "Times New Roman",
201
+ "serif"
202
+ ],
203
+ singleLineRatio: singleLineRatioOf({
204
+ source: "hhea",
205
+ hheaAscent: 1505,
206
+ hheaDescent: -510,
207
+ hheaLineGap: 0,
208
+ unitsPerEm: 2048
209
+ })
210
+ },
194
211
  georgia: {
195
212
  googleFont: "Tinos",
196
213
  category: "serif",
@@ -628,6 +645,40 @@ const FONT_MAPPINGS = {
628
645
  note: "Measured at 11pt against a 15.36pt reference-layout line pitch; the face ships with the office suite, not as a readable font file."
629
646
  })
630
647
  },
648
+ frankruehl: {
649
+ googleFont: "Frank Ruhl Libre",
650
+ category: "serif",
651
+ fallbackStack: [
652
+ "FrankRuehl",
653
+ "Frank Ruhl Libre",
654
+ "Times New Roman",
655
+ "serif"
656
+ ],
657
+ singleLineRatio: singleLineRatioOf({
658
+ source: "hhea",
659
+ hheaAscent: 1462,
660
+ hheaDescent: -442,
661
+ hheaLineGap: 0,
662
+ unitsPerEm: 2048
663
+ })
664
+ },
665
+ miriam: {
666
+ googleFont: "Miriam Libre",
667
+ category: "sans-serif",
668
+ fallbackStack: [
669
+ "Miriam",
670
+ "Miriam Libre",
671
+ "Arial",
672
+ "sans-serif"
673
+ ],
674
+ singleLineRatio: singleLineRatioOf({
675
+ source: "hhea",
676
+ hheaAscent: 1546,
677
+ hheaDescent: -512,
678
+ hheaLineGap: 0,
679
+ unitsPerEm: 2048
680
+ })
681
+ },
631
682
  "ms mincho": {
632
683
  googleFont: "Noto Serif JP",
633
684
  category: "serif",
@@ -1,5 +1,5 @@
1
- import { document_d_exports } from "../types/document.js";
2
1
  import { ColorValue } from "../types/colors.js";
2
+ import { document_d_exports } from "../types/document.js";
3
3
  import { Properties } from "csstype";
4
4
  //#region src/utils/formatToStyle.d.ts
5
5
  type CSSProperties = Properties<string | number>;
@@ -151,6 +151,33 @@ function borderToStyle(border, side = "", theme) {
151
151
  });
152
152
  return style;
153
153
  }
154
+ const HALF_STEP_SHADING_PATTERNS = /* @__PURE__ */ new Set([
155
+ "pct12",
156
+ "pct37",
157
+ "pct62",
158
+ "pct87"
159
+ ]);
160
+ const AUTO_PATTERN_COLOR = "000000";
161
+ const AUTO_PATTERN_BACKGROUND = "FFFFFF";
162
+ function percentageShadingRatio(pattern) {
163
+ if (!pattern?.startsWith("pct")) return;
164
+ const percentage = Number.parseInt(pattern.slice(3), 10);
165
+ if (!Number.isFinite(percentage)) return;
166
+ return (percentage + (HALF_STEP_SHADING_PATTERNS.has(pattern) ? .5 : 0)) / 100;
167
+ }
168
+ function resolvePatternHex({ color, fallback, theme }) {
169
+ const resolved = resolveShadingColor(color, theme);
170
+ return /^#(?<hex>[0-9A-F]{6})$/iu.exec(resolved)?.groups?.["hex"]?.toUpperCase() ?? fallback;
171
+ }
172
+ function blendShadingColors({ foreground, background, ratio }) {
173
+ const channels = [];
174
+ for (let offset = 0; offset < 6; offset += 2) {
175
+ const foregroundChannel = Number.parseInt(foreground.slice(offset, offset + 2), 16);
176
+ const backgroundChannel = Number.parseInt(background.slice(offset, offset + 2), 16);
177
+ channels.push(Math.round(foregroundChannel * ratio + backgroundChannel * (1 - ratio)).toString(16).padStart(2, "0"));
178
+ }
179
+ return `#${channels.join("").toUpperCase()}`;
180
+ }
154
181
  /**
155
182
  * Convert ShadingProperties to background color
156
183
  *
@@ -161,13 +188,26 @@ function borderToStyle(border, side = "", theme) {
161
188
  function resolveShadingFill(shading, theme) {
162
189
  if (!shading) return "";
163
190
  if (shading.pattern === "nil") return "";
191
+ const percentageRatio = percentageShadingRatio(shading.pattern);
192
+ if (percentageRatio !== void 0) return blendShadingColors({
193
+ foreground: resolvePatternHex({
194
+ color: shading.color,
195
+ fallback: AUTO_PATTERN_COLOR,
196
+ theme
197
+ }),
198
+ background: resolvePatternHex({
199
+ color: shading.fill,
200
+ fallback: AUTO_PATTERN_BACKGROUND,
201
+ theme
202
+ }),
203
+ ratio: percentageRatio
204
+ });
164
205
  if (shading.fill) {
165
206
  if (shading.fill.auto) return "";
166
207
  if (shading.fill.rgb === "auto" || shading.fill.rgb === "FFFFFF") return "";
167
208
  return resolveShadingColor(shading.fill, theme);
168
209
  }
169
210
  if (shading.pattern === "solid" && shading.color) return resolveShadingColor(shading.color, theme);
170
- if (shading.pattern && shading.pattern.startsWith("pct") && shading.color) return resolveShadingColor(shading.color, theme);
171
211
  return "";
172
212
  }
173
213
  /**
@@ -1,3 +1,4 @@
1
+ import { isEmptyParagraph } from "../docx/paragraphParser.js";
1
2
  //#region src/watermark/index.ts
2
3
  /**
3
4
  * Schemes allowed for a picture watermark's external image target
@@ -42,6 +43,12 @@ function setDocumentWatermark(doc, watermark) {
42
43
  const nextHeaders = /* @__PURE__ */ new Map();
43
44
  if (headers) for (const [rId, header] of headers) {
44
45
  const next = { ...header };
46
+ const retainedHostIndex = next.watermarkBlockIndex;
47
+ const retainedHost = next.rawWatermarkXml !== void 0 && retainedHostIndex !== void 0 ? next.content.at(retainedHostIndex) : void 0;
48
+ if (retainedHostIndex !== void 0 && retainedHost?.type === "paragraph" && isEmptyParagraph(retainedHost)) {
49
+ next.content = [...next.content];
50
+ next.content.splice(retainedHostIndex, 1);
51
+ }
45
52
  if (watermark === void 0) {
46
53
  delete next.watermark;
47
54
  delete next.watermarkBlockIndex;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stll/folio-core",
3
- "version": "0.33.1",
3
+ "version": "0.34.0",
4
4
  "description": "Headless, framework-neutral core of folio: the OOXML (.docx) parser, document model, ProseMirror integration, and page-layout engine. No React.",
5
5
  "keywords": [
6
6
  "document-model",
@@ -115,7 +115,7 @@
115
115
  "perf": "bun scripts/profile-editor.ts"
116
116
  },
117
117
  "dependencies": {
118
- "@stll/docx-core": "^0.19.0",
118
+ "@stll/docx-core": "^0.19.2",
119
119
  "@stll/docx-utils": "^0.1.0",
120
120
  "@stll/template-conditions": "^0.1.0",
121
121
  "better-result": "3.0.1",