@stll/folio-core 0.22.1 → 0.22.3

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 (62) hide show
  1. package/dist/ai-edits/headless.d.ts +6 -6
  2. package/dist/ai-edits/headless.js +2 -2
  3. package/dist/content-controls/errors.d.ts +17 -17
  4. package/dist/content-controls/errors.js +3 -3
  5. package/dist/controller/layoutPipeline.js +28 -0
  6. package/dist/document-operations.d.ts +6 -6
  7. package/dist/document-operations.js +2 -2
  8. package/dist/docx/encryption/errors.d.ts +3 -3
  9. package/dist/docx/encryption/errors.js +1 -1
  10. package/dist/docx/ensureParaIds.d.ts +4 -4
  11. package/dist/docx/ensureParaIds.js +1 -1
  12. package/dist/docx/imageParser.js +6 -9
  13. package/dist/docx/metadataPrivacy.d.ts +6 -6
  14. package/dist/docx/metadataPrivacy.js +2 -2
  15. package/dist/docx/parser.d.ts +5 -5
  16. package/dist/docx/parser.js +1 -1
  17. package/dist/docx/server/applyDocxXmlPatchProposal.d.ts +6 -6
  18. package/dist/docx/server/applyDocxXmlPatchProposal.js +2 -2
  19. package/dist/docx/server/boundedArchive.d.ts +4 -4
  20. package/dist/docx/server/boundedArchive.js +1 -1
  21. package/dist/docx/server/build.d.ts +5 -5
  22. package/dist/docx/server/build.js +1 -1
  23. package/dist/docx/server/createBilingualDocument.d.ts +3 -3
  24. package/dist/docx/server/createBilingualDocument.js +1 -1
  25. package/dist/docx/server/evaluateDocxXmlPatchProposal.d.ts +6 -6
  26. package/dist/docx/server/evaluateDocxXmlPatchProposal.js +2 -2
  27. package/dist/docx/server/inspectDocxPackage.d.ts +3 -3
  28. package/dist/docx/server/inspectDocxPackage.js +9 -8
  29. package/dist/docx/styleParser.js +16 -16
  30. package/dist/docx/xmlParser.d.ts +7 -3
  31. package/dist/docx/xmlParser.js +20 -7
  32. package/dist/docx/xmlResourceLimits.d.ts +4 -4
  33. package/dist/docx/xmlResourceLimits.js +1 -1
  34. package/dist/layout-engine/measure/font-metrics.worker.js +1 -1
  35. package/dist/layout-engine/measure/measureHelpers.d.ts +2 -1
  36. package/dist/layout-engine/measure/measureHelpers.js +5 -2
  37. package/dist/layout-engine/types.d.ts +6 -0
  38. package/dist/layout-painter/anchoredImagePosition.d.ts +2 -1
  39. package/dist/layout-painter/anchoredImagePosition.js +14 -6
  40. package/dist/layout-painter/renderPage.js +11 -1
  41. package/dist/layout-painter/renderParagraph.js +3 -4
  42. package/dist/prosemirror/attrs/index.js +6 -5
  43. package/dist/prosemirror/commands/propertyChangeScope.d.ts +1 -1
  44. package/dist/prosemirror/commands/propertyChangeScope.js +1 -0
  45. package/dist/prosemirror/conversion/fromProseDoc.js +13 -3
  46. package/dist/prosemirror/conversion/toProseDoc.js +1 -0
  47. package/dist/prosemirror/extensions/core/ParagraphExtension.js +30 -3
  48. package/dist/prosemirror/extensions/marks/UnderlineExtension.js +9 -7
  49. package/dist/prosemirror/extensions/marks/markUtils.d.ts +2 -1
  50. package/dist/prosemirror/extensions/marks/markUtils.js +92 -16
  51. package/dist/prosemirror/plugins/selectionTracker.js +10 -5
  52. package/dist/prosemirror/schema/nodes.d.ts +1 -0
  53. package/dist/prosemirror/selectionMarks.d.ts +11 -0
  54. package/dist/prosemirror/selectionMarks.js +19 -0
  55. package/dist/prosemirror/selectionState.js +8 -20
  56. package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -0
  57. package/dist/redline.d.ts +4 -4
  58. package/dist/redline.js +1 -1
  59. package/dist/utils/formatToStyle.js +1 -1
  60. package/dist/version-comparison.d.ts +3 -3
  61. package/dist/version-comparison.js +1 -1
  62. package/package.json +3 -3
@@ -1,5 +1,20 @@
1
+ import { FONT_THEME_VALUES } from "../../../types/documentEnumValues.js";
2
+ import { mergeFontFamily } from "../../../utils/fontFamilyMerge.js";
3
+ import { expectFontFamilyMarkAttrs } from "../../attrs/index.js";
1
4
  import { applyRunFormattingOverrideMark, buildRunFormattingOverrideAttrs } from "./RunFormattingOverrideExtension.js";
2
5
  //#region src/prosemirror/extensions/marks/markUtils.ts
6
+ const isFontTheme = (value) => value !== void 0 && FONT_THEME_VALUES.some((theme) => theme === value);
7
+ const fontFamilyAttrsToFormatting = ({ ascii, hAnsi, eastAsia, cs, hint, asciiTheme, hAnsiTheme, eastAsiaTheme, csTheme }) => ({
8
+ ...ascii !== void 0 ? { ascii } : {},
9
+ ...hAnsi !== void 0 ? { hAnsi } : {},
10
+ ...eastAsia !== void 0 ? { eastAsia } : {},
11
+ ...cs !== void 0 ? { cs } : {},
12
+ ...hint !== void 0 ? { hint } : {},
13
+ ...isFontTheme(asciiTheme) ? { asciiTheme } : {},
14
+ ...hAnsiTheme !== void 0 ? { hAnsiTheme } : {},
15
+ ...eastAsiaTheme !== void 0 ? { eastAsiaTheme } : {},
16
+ ...csTheme !== void 0 ? { csTheme } : {}
17
+ });
3
18
  function marksToTextFormatting(marks) {
4
19
  const formatting = {};
5
20
  for (const mark of marks) switch (mark.type.name) {
@@ -10,7 +25,10 @@ function marksToTextFormatting(marks) {
10
25
  formatting.italic = true;
11
26
  break;
12
27
  case "underline":
13
- formatting.underline = { style: typeof mark.attrs["style"] === "string" ? mark.attrs["style"] : "single" };
28
+ formatting.underline = {
29
+ style: typeof mark.attrs["style"] === "string" ? mark.attrs["style"] : "single",
30
+ ...mark.attrs["color"] !== null && mark.attrs["color"] !== void 0 ? { color: mark.attrs["color"] } : {}
31
+ };
14
32
  break;
15
33
  case "strike":
16
34
  formatting.strike = true;
@@ -34,17 +52,9 @@ function marksToTextFormatting(marks) {
34
52
  case "fontSize":
35
53
  formatting.fontSize = Number(mark.attrs["size"]);
36
54
  break;
37
- case "fontFamily": {
38
- const ascii = mark.attrs["ascii"] !== null && mark.attrs["ascii"] !== void 0 ? String(mark.attrs["ascii"]) : void 0;
39
- const hAnsi = mark.attrs["hAnsi"] !== null && mark.attrs["hAnsi"] !== void 0 ? String(mark.attrs["hAnsi"]) : void 0;
40
- const hint = mark.attrs["hint"];
41
- formatting.fontFamily = {
42
- ...ascii !== void 0 ? { ascii } : {},
43
- ...hAnsi !== void 0 ? { hAnsi } : {},
44
- ...hint === "default" || hint === "eastAsia" || hint === "cs" ? { hint } : {}
45
- };
55
+ case "fontFamily":
56
+ formatting.fontFamily = fontFamilyAttrsToFormatting(expectFontFamilyMarkAttrs(mark));
46
57
  break;
47
- }
48
58
  case "language": {
49
59
  const val = mark.attrs["val"];
50
60
  const eastAsia = mark.attrs["eastAsia"];
@@ -93,21 +103,82 @@ function dispatchStoredMarks(state, dispatch, marks) {
93
103
  tr.setStoredMarks(marks);
94
104
  dispatch(tr);
95
105
  }
106
+ function compactAttrs(attrs) {
107
+ if (!attrs) return {};
108
+ const result = {};
109
+ for (const [key, value] of Object.entries(attrs)) if (value !== null && value !== void 0) result[key] = value;
110
+ return result;
111
+ }
112
+ function mergeMarkAttrs(markType, currentMark, nextAttrs) {
113
+ const next = compactAttrs(nextAttrs);
114
+ switch (markType.name) {
115
+ case "fontFamily": return mergeFontFamily(currentMark ? fontFamilyAttrsToFormatting(expectFontFamilyMarkAttrs(currentMark)) : void 0, fontFamilyAttrsToFormatting(expectFontFamilyMarkAttrs(markType.create(next))));
116
+ case "underline": return {
117
+ ...compactAttrs(currentMark?.attrs),
118
+ ...next
119
+ };
120
+ default: return nextAttrs;
121
+ }
122
+ }
123
+ function markRequiresAttrMerge(markType) {
124
+ return markType.name === "fontFamily" || markType.name === "underline";
125
+ }
126
+ function createMarkWithMergedAttrs(markType, currentMark, nextAttrs) {
127
+ if (!markRequiresAttrMerge(markType)) return markType.create(nextAttrs);
128
+ return markType.create(mergeMarkAttrs(markType, currentMark, nextAttrs));
129
+ }
96
130
  function setMark(markType, attrs) {
97
131
  return (state, dispatch) => {
98
132
  const { from, to, empty } = state.selection;
99
- const mark = markType.create(attrs);
100
133
  if (empty) {
101
134
  if (dispatch) {
102
135
  const current = state.storedMarks ?? state.selection.$from.marks();
103
- dispatchStoredMarks(state, dispatch, [...markType.isInSet(current) ? current.filter((m) => m.type !== markType) : current, mark]);
136
+ const currentMark = markType.isInSet(current);
137
+ const marks = markType.isInSet(current) ? current.filter((m) => m.type !== markType) : current;
138
+ const mark = createMarkWithMergedAttrs(markType, currentMark, attrs);
139
+ dispatchStoredMarks(state, dispatch, [...marks, mark]);
104
140
  }
105
141
  return true;
106
142
  }
107
- if (dispatch) dispatch(state.tr.addMark(from, to, mark).scrollIntoView());
143
+ if (dispatch) {
144
+ if (!markRequiresAttrMerge(markType)) {
145
+ dispatch(state.tr.addMark(from, to, markType.create(attrs)).scrollIntoView());
146
+ return true;
147
+ }
148
+ let tr = state.tr;
149
+ state.doc.nodesBetween(from, to, (node, pos) => {
150
+ if (!node.isText) return;
151
+ const start = Math.max(from, pos);
152
+ const end = Math.min(to, pos + node.nodeSize);
153
+ const mark = createMarkWithMergedAttrs(markType, markType.isInSet(node.marks), attrs);
154
+ tr = tr.addMark(start, end, mark);
155
+ });
156
+ dispatch(tr.scrollIntoView());
157
+ }
108
158
  return true;
109
159
  };
110
160
  }
161
+ function selectionHasVisibleUnderline(state, markType) {
162
+ const { from, to, empty, $from } = state.selection;
163
+ if (empty) {
164
+ const mark = markType.isInSet(state.storedMarks ?? $from.marks());
165
+ return mark !== void 0 && mark.attrs["style"] !== "none";
166
+ }
167
+ let hasVisibleUnderline = false;
168
+ state.doc.nodesBetween(from, to, (node) => {
169
+ if (!node.isText) return true;
170
+ const mark = markType.isInSet(node.marks);
171
+ if (mark && mark.attrs["style"] !== "none") {
172
+ hasVisibleUnderline = true;
173
+ return false;
174
+ }
175
+ return true;
176
+ });
177
+ return hasVisibleUnderline;
178
+ }
179
+ function toggleUnderlineMark(markType) {
180
+ return (state, dispatch) => setMark(markType, { style: selectionHasVisibleUnderline(state, markType) ? "none" : "single" })(state, dispatch);
181
+ }
111
182
  function removeMark(markType) {
112
183
  return (state, dispatch) => {
113
184
  const { from, to, empty } = state.selection;
@@ -197,8 +268,13 @@ function textFormattingToMarks(formatting, schema) {
197
268
  if (formatting.fontFamily && schema.marks["fontFamily"]) marks.push(schema.marks["fontFamily"].create({
198
269
  ascii: formatting.fontFamily.ascii,
199
270
  hAnsi: formatting.fontFamily.hAnsi,
271
+ eastAsia: formatting.fontFamily.eastAsia,
272
+ cs: formatting.fontFamily.cs,
200
273
  hint: formatting.fontFamily.hint,
201
- asciiTheme: formatting.fontFamily.asciiTheme
274
+ asciiTheme: formatting.fontFamily.asciiTheme,
275
+ hAnsiTheme: formatting.fontFamily.hAnsiTheme,
276
+ eastAsiaTheme: formatting.fontFamily.eastAsiaTheme,
277
+ csTheme: formatting.fontFamily.csTheme
202
278
  }));
203
279
  if (formatting.language && schema.marks["language"]) marks.push(schema.marks["language"].create(formatting.language));
204
280
  if (formatting.vertAlign === "superscript" && schema.marks["superscript"]) marks.push(schema.marks["superscript"].create());
@@ -245,4 +321,4 @@ function createRemoveMarkCommand(markType) {
245
321
  return removeMark(markType);
246
322
  }
247
323
  //#endregion
248
- export { clearFormatting, createRemoveMarkCommand, createSetMarkCommand, getMarkAttr, isMarkActive, removeMark, setMark, textFormattingToMarks };
324
+ export { clearFormatting, createRemoveMarkCommand, createSetMarkCommand, getMarkAttr, isMarkActive, removeMark, setMark, textFormattingToMarks, toggleUnderlineMark };
@@ -1,3 +1,4 @@
1
+ import { collectMarksInRange } from "../selectionMarks.js";
1
2
  import { Plugin, PluginKey } from "prosemirror-state";
2
3
  //#region src/prosemirror/plugins/selectionTracker.ts
3
4
  /**
@@ -32,7 +33,7 @@ function extractSelectionContext(state) {
32
33
  const paragraphFormatting = {};
33
34
  if (paragraph.type.name === "paragraph") {
34
35
  if (paragraph.attrs["alignment"]) paragraphFormatting.alignment = paragraph.attrs["alignment"];
35
- if (paragraph.attrs["lineSpacing"]) {
36
+ if (typeof paragraph.attrs["lineSpacing"] === "number") {
36
37
  paragraphFormatting.lineSpacing = paragraph.attrs["lineSpacing"];
37
38
  paragraphFormatting.lineSpacingRule = paragraph.attrs["lineSpacingRule"];
38
39
  }
@@ -79,9 +80,13 @@ function extractSelectionContext(state) {
79
80
  * Extract text formatting from current selection/cursor marks
80
81
  */
81
82
  function extractTextFormatting(state) {
82
- const { selection } = state;
83
- const { empty, $from } = selection;
84
- const marks = state.storedMarks || (empty ? $from.marks() : []);
83
+ const { selection, doc } = state;
84
+ const { from, to, empty, $from } = selection;
85
+ const marks = empty ? state.storedMarks || $from.marks() : collectMarksInRange({
86
+ doc,
87
+ from,
88
+ to
89
+ });
85
90
  const formatting = {};
86
91
  for (const mark of marks) switch (mark.type.name) {
87
92
  case "bold":
@@ -91,7 +96,7 @@ function extractTextFormatting(state) {
91
96
  formatting.italic = true;
92
97
  break;
93
98
  case "underline":
94
- formatting.underline = {
99
+ if (mark.attrs["style"] !== "none") formatting.underline = {
95
100
  style: mark.attrs["style"] || "single",
96
101
  color: mark.attrs["color"]
97
102
  };
@@ -32,6 +32,7 @@ type ParagraphAttrs = {
32
32
  spaceAfter?: number;
33
33
  lineSpacing?: number;
34
34
  lineSpacingRule?: document_d_exports.LineSpacingRule;
35
+ lineSpacingExplicit?: boolean;
35
36
  snapToGrid?: boolean;
36
37
  spacingExplicit?: SpacingExplicit;
37
38
  /** Layout provenance: document defaults survive on empty paragraphs. */
@@ -0,0 +1,11 @@
1
+ import { Mark, Node } from "prosemirror-model";
2
+ //#region src/prosemirror/selectionMarks.d.ts
3
+ type CollectMarksInRangeOptions = {
4
+ doc: Node;
5
+ from: number;
6
+ to: number;
7
+ };
8
+ /** Collect one representative per mark type, preferring visible underline state. */
9
+ declare const collectMarksInRange: ({ doc, from, to }: CollectMarksInRangeOptions) => Mark[];
10
+ //#endregion
11
+ export { collectMarksInRange };
@@ -0,0 +1,19 @@
1
+ //#region src/prosemirror/selectionMarks.ts
2
+ const UNDERLINE_MARK = "underline";
3
+ const HIDDEN_UNDERLINE_STYLE = "none";
4
+ const shouldReplaceMark = (current, incoming) => current.type.name === UNDERLINE_MARK && current.attrs["style"] === HIDDEN_UNDERLINE_STYLE && incoming.attrs["style"] !== HIDDEN_UNDERLINE_STYLE;
5
+ /** Collect one representative per mark type, preferring visible underline state. */
6
+ const collectMarksInRange = ({ doc, from, to }) => {
7
+ const seen = /* @__PURE__ */ new Map();
8
+ doc.nodesBetween(from, to, (node) => {
9
+ if (!node.isText) return;
10
+ for (const mark of node.marks) {
11
+ const name = mark.type.name;
12
+ const current = seen.get(name);
13
+ if (!current || shouldReplaceMark(current, mark)) seen.set(name, mark);
14
+ }
15
+ });
16
+ return Array.from(seen.values());
17
+ };
18
+ //#endregion
19
+ export { collectMarksInRange };
@@ -1,4 +1,5 @@
1
1
  import { directionIsRtl } from "./paragraphDirection.js";
2
+ import { collectMarksInRange } from "./selectionMarks.js";
2
3
  //#region src/prosemirror/selectionState.ts
3
4
  /**
4
5
  * Extract selection state from editor state.
@@ -18,7 +19,11 @@ function extractSelectionState(state) {
18
19
  const paragraph = $from.parent;
19
20
  const isEmptyParagraph = paragraph.type.name === "paragraph" && paragraph.textContent.length === 0;
20
21
  const paragraphDefaultFormatting = paragraph.attrs["defaultTextFormatting"];
21
- const marks = empty ? state.storedMarks || selection.$from.marks() : collectMarksInRange(doc, from, to);
22
+ const marks = empty ? state.storedMarks || selection.$from.marks() : collectMarksInRange({
23
+ doc,
24
+ from,
25
+ to
26
+ });
22
27
  if (isEmptyParagraph && marks.length === 0 && paragraphDefaultFormatting) textFormatting = { ...paragraphDefaultFormatting };
23
28
  for (const mark of marks) switch (mark.type.name) {
24
29
  case "bold":
@@ -28,7 +33,7 @@ function extractSelectionState(state) {
28
33
  textFormatting.italic = true;
29
34
  break;
30
35
  case "underline":
31
- textFormatting.underline = {
36
+ if (mark.attrs["style"] !== "none") textFormatting.underline = {
32
37
  style: mark.attrs["style"] || "single",
33
38
  color: mark.attrs["color"]
34
39
  };
@@ -67,7 +72,7 @@ function extractSelectionState(state) {
67
72
  let styleId = null;
68
73
  if (paragraph.type.name === "paragraph") {
69
74
  if (paragraph.attrs["alignment"]) paragraphFormatting.alignment = paragraph.attrs["alignment"];
70
- if (paragraph.attrs["lineSpacing"]) {
75
+ if (typeof paragraph.attrs["lineSpacing"] === "number") {
71
76
  paragraphFormatting.lineSpacing = paragraph.attrs["lineSpacing"];
72
77
  paragraphFormatting.lineSpacingRule = paragraph.attrs["lineSpacingRule"];
73
78
  }
@@ -91,22 +96,5 @@ function extractSelectionState(state) {
91
96
  endParagraphIndex
92
97
  };
93
98
  }
94
- /**
95
- * Collect the first occurrence of each mark type found on any text node within
96
- * the range. Mirrors the "any inline child has this mark" semantics that
97
- * prosemirror-commands' toggleMark uses to decide add-vs-remove, so the
98
- * toolbar's active state stays consistent with what a toggle click will do.
99
- */
100
- function collectMarksInRange(doc, from, to) {
101
- const seen = /* @__PURE__ */ new Map();
102
- doc.nodesBetween(from, to, (node) => {
103
- if (!node.isText) return;
104
- for (const mark of node.marks) {
105
- const name = mark.type.name;
106
- if (!seen.has(name)) seen.set(name, mark);
107
- }
108
- });
109
- return Array.from(seen.values());
110
- }
111
99
  //#endregion
112
100
  export { extractSelectionState };
@@ -27,6 +27,7 @@ function paragraphAttrsFromResolvedStyle(resolved) {
27
27
  spaceAfter: ppr?.spaceAfter ?? null,
28
28
  lineSpacing: ppr?.lineSpacing ?? null,
29
29
  lineSpacingRule: ppr?.lineSpacingRule ?? null,
30
+ lineSpacingExplicit: null,
30
31
  snapToGrid: ppr?.snapToGrid ?? null,
31
32
  indentLeft: ppr?.indentLeft ?? null,
32
33
  indentRight: ppr?.indentRight ?? null,
package/dist/redline.d.ts CHANGED
@@ -13,13 +13,13 @@ type GenerateRedlineDocxOptions = {
13
13
  /** Optional output-only package-metadata privacy transforms. */
14
14
  privacy?: FolioDocumentPrivacyOptions;
15
15
  };
16
- declare const InvalidGenerateRedlineDocxOptionsError_base: import("better-result").TaggedErrorClass<"InvalidGenerateRedlineDocxOptionsError", {
16
+ declare const InvalidGenerateRedlineDocxOptionsError_base: import("better-result").TaggedErrorClass<"InvalidGenerateRedlineDocxOptionsError">;
17
+ /** Raised when a resolved input view is not `"original"` or `"final"`. */
18
+ declare class InvalidGenerateRedlineDocxOptionsError extends InvalidGenerateRedlineDocxOptionsError_base<{
17
19
  message: string;
18
20
  option: "baseView" | "revisedView";
19
21
  receivedValue: unknown;
20
- }>;
21
- /** Raised when a resolved input view is not `"original"` or `"final"`. */
22
- declare class InvalidGenerateRedlineDocxOptionsError extends InvalidGenerateRedlineDocxOptionsError_base {}
22
+ }> {}
23
23
  /** A document story that could not be paired across the two input packages. */
24
24
  type GenerateRedlineUnprocessedStory = {
25
25
  /** Story in the base package, or `null` when it exists only in the revision. */
package/dist/redline.js CHANGED
@@ -18,7 +18,7 @@ import { TaggedError, panic } from "better-result";
18
18
  * @packageDocumentation
19
19
  */
20
20
  /** Raised when a resolved input view is not `"original"` or `"final"`. */
21
- var InvalidGenerateRedlineDocxOptionsError = class extends TaggedError("InvalidGenerateRedlineDocxOptionsError")() {};
21
+ var InvalidGenerateRedlineDocxOptionsError = class extends TaggedError("InvalidGenerateRedlineDocxOptionsError") {};
22
22
  const nextBaseBlockIdByIndex = (events) => {
23
23
  const nextIds = Array.from({ length: events.length });
24
24
  let nextId = null;
@@ -108,7 +108,7 @@ function paragraphToStyle(formatting, theme) {
108
108
  }
109
109
  if (formatting.indentLeft !== void 0) style.marginLeft = formatPx(twipsToPixels(formatting.indentLeft));
110
110
  if (formatting.indentRight !== void 0) style.marginRight = formatPx(twipsToPixels(formatting.indentRight));
111
- if (formatting.indentFirstLine !== void 0) style.textIndent = formatPx(twipsToPixels(formatting.indentFirstLine));
111
+ if (formatting.indentFirstLine !== void 0) style.textIndent = formatPx(twipsToPixels(formatting.hangingIndent ? -Math.abs(formatting.indentFirstLine) : formatting.indentFirstLine));
112
112
  if (formatting.borders) {
113
113
  if (formatting.borders.top) Object.assign(style, borderToStyle(formatting.borders.top, "Top", theme));
114
114
  if (formatting.borders.bottom) Object.assign(style, borderToStyle(formatting.borders.bottom, "Bottom", theme));
@@ -15,12 +15,12 @@ type FolioCompareDocxVersionsOptions = {
15
15
  /** Optional output-only privacy transforms. Source buffers are never mutated. */
16
16
  privacy?: FolioVersionDiffPrivacyOptions;
17
17
  };
18
- declare const InvalidFolioVersionComparisonOptionsError_base: import("better-result").TaggedErrorClass<"InvalidFolioVersionComparisonOptionsError", {
18
+ declare const InvalidFolioVersionComparisonOptionsError_base: import("better-result").TaggedErrorClass<"InvalidFolioVersionComparisonOptionsError">;
19
+ declare class InvalidFolioVersionComparisonOptionsError extends InvalidFolioVersionComparisonOptionsError_base<{
19
20
  message: string;
20
21
  option: "include" | "privacy.transforms";
21
22
  receivedValue: unknown;
22
- }>;
23
- declare class InvalidFolioVersionComparisonOptionsError extends InvalidFolioVersionComparisonOptionsError_base {}
23
+ }> {}
24
24
  type FolioDocumentMetadataValue = string | number | null;
25
25
  type FolioMetadataDiff = {
26
26
  property: FolioDocumentMetadataProperty;
@@ -86,7 +86,7 @@ const FOLIO_VERSION_COMPARISON_SCOPES = Object.freeze([
86
86
  "metadata"
87
87
  ]);
88
88
  const isFolioVersionComparisonScope = (value) => FOLIO_VERSION_COMPARISON_SCOPES.some((scope) => scope === value);
89
- var InvalidFolioVersionComparisonOptionsError = class extends TaggedError("InvalidFolioVersionComparisonOptionsError")() {};
89
+ var InvalidFolioVersionComparisonOptionsError = class extends TaggedError("InvalidFolioVersionComparisonOptionsError") {};
90
90
  const FOLIO_VERSION_COMPARISON_PRIVACY_TRANSFORMS = FOLIO_DOCUMENT_PRIVACY_TRANSFORMS;
91
91
  const isFolioVersionComparisonPrivacyTransform = (value) => isFolioDocumentPrivacyTransform(value);
92
92
  /** Run-level formatting properties compared for `formatChanged` detection. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stll/folio-core",
3
- "version": "0.22.1",
3
+ "version": "0.22.3",
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",
@@ -113,10 +113,10 @@
113
113
  "perf": "bun scripts/profile-editor.ts"
114
114
  },
115
115
  "dependencies": {
116
- "@stll/docx-core": "^0.15.0",
116
+ "@stll/docx-core": "^0.15.1",
117
117
  "@stll/docx-utils": "^0.1.0",
118
118
  "@stll/template-conditions": "^0.1.0",
119
- "better-result": "2.10.0",
119
+ "better-result": "3.0.1",
120
120
  "csstype": "^3.1.3",
121
121
  "dompurify": "^3.4.13",
122
122
  "fast-xml-parser": "^5.9.3",