@stll/folio-core 0.22.2 → 0.23.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 (62) hide show
  1. package/dist/ai-edits/apply.d.ts +1 -1
  2. package/dist/controller/layoutPipeline.js +28 -0
  3. package/dist/document-operations.d.ts +4 -4
  4. package/dist/document-operations.js +17 -1
  5. package/dist/docx/imageParser.js +6 -9
  6. package/dist/docx/rezip.d.ts +1 -1
  7. package/dist/docx/rezip.js +12 -31
  8. package/dist/docx/server/inspectDocxPackage.js +8 -7
  9. package/dist/docx/styleParser.js +16 -16
  10. package/dist/docx/xmlParser.d.ts +7 -3
  11. package/dist/docx/xmlParser.js +20 -7
  12. package/dist/layout-bridge/convert/toFlowBlocks.js +35 -61
  13. package/dist/layout-engine/measure/measureHelpers.d.ts +2 -1
  14. package/dist/layout-engine/measure/measureHelpers.js +5 -2
  15. package/dist/layout-engine/types.d.ts +6 -0
  16. package/dist/layout-painter/anchoredImagePosition.d.ts +2 -1
  17. package/dist/layout-painter/anchoredImagePosition.js +14 -6
  18. package/dist/layout-painter/imageLayout.d.ts +1 -1
  19. package/dist/layout-painter/renderPage.js +11 -1
  20. package/dist/layout-painter/renderParagraph.js +3 -4
  21. package/dist/managers/AutoSaveManager.js +8 -40
  22. package/dist/managers/TableSelectionManager.d.ts +1 -1
  23. package/dist/managers/autoSaveCodec.d.ts +17 -0
  24. package/dist/managers/autoSaveCodec.js +109 -0
  25. package/dist/prosemirror/attrs/index.js +278 -29
  26. package/dist/prosemirror/commands/comments.js +3 -3
  27. package/dist/prosemirror/commands/formatting.js +19 -19
  28. package/dist/prosemirror/commands/index.d.ts +2 -2
  29. package/dist/prosemirror/commands/paragraph.js +32 -32
  30. package/dist/prosemirror/commands/propertyChangeScope.d.ts +5 -3
  31. package/dist/prosemirror/commands/propertyChangeScope.js +9 -8
  32. package/dist/prosemirror/commands/table.d.ts +10 -52
  33. package/dist/prosemirror/commands/table.js +34 -34
  34. package/dist/prosemirror/conversion/fromProseDoc.js +33 -20
  35. package/dist/prosemirror/conversion/sdtAttrs.d.ts +2 -1
  36. package/dist/prosemirror/conversion/sdtAttrs.js +9 -4
  37. package/dist/prosemirror/conversion/toProseDoc.js +1 -0
  38. package/dist/prosemirror/extensions/ExtensionManager.d.ts +6 -3
  39. package/dist/prosemirror/extensions/ExtensionManager.js +5 -3
  40. package/dist/prosemirror/extensions/core/ParagraphExtension.d.ts +1 -1
  41. package/dist/prosemirror/extensions/core/ParagraphExtension.js +30 -3
  42. package/dist/prosemirror/extensions/features/ListExtension.js +4 -4
  43. package/dist/prosemirror/extensions/marks/UnderlineExtension.js +9 -7
  44. package/dist/prosemirror/extensions/marks/markUtils.d.ts +2 -1
  45. package/dist/prosemirror/extensions/marks/markUtils.js +92 -16
  46. package/dist/prosemirror/extensions/nodes/ShapeExtension.d.ts +1 -1
  47. package/dist/prosemirror/extensions/nodes/TextBoxExtension.d.ts +1 -1
  48. package/dist/prosemirror/extensions/types.d.ts +134 -1
  49. package/dist/prosemirror/index.d.ts +2 -2
  50. package/dist/prosemirror/plugins/selectionTracker.js +25 -94
  51. package/dist/prosemirror/revisionCarriers.js +3 -1
  52. package/dist/prosemirror/schema/index.d.ts +2 -2
  53. package/dist/prosemirror/schema/index.js +87 -0
  54. package/dist/prosemirror/schema/nodes.d.ts +14 -2
  55. package/dist/prosemirror/selectionMarks.d.ts +11 -0
  56. package/dist/prosemirror/selectionMarks.js +19 -0
  57. package/dist/prosemirror/selectionState.d.ts +11 -5
  58. package/dist/prosemirror/selectionState.js +99 -74
  59. package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -0
  60. package/dist/utils/formatToStyle.js +1 -1
  61. package/dist/utils/tableOperations.d.ts +7 -6
  62. package/package.json +3 -3
@@ -1,4 +1,4 @@
1
- import { ImageRun } from "../layout-engine/types.js";
1
+ import { ImageRun, PageMargins } from "../layout-engine/types.js";
2
2
  //#region src/layout-painter/anchoredImagePosition.d.ts
3
3
  type PageGeometry = {
4
4
  pageWidth: number;
@@ -7,6 +7,7 @@ type PageGeometry = {
7
7
  marginTop: number;
8
8
  marginRight: number;
9
9
  marginBottom: number;
10
+ authoredMargins?: PageMargins;
10
11
  contentWidth: number;
11
12
  contentHeight: number;
12
13
  };
@@ -1,6 +1,13 @@
1
1
  import { emuToPixels } from "./renderUtils.js";
2
2
  //#region src/layout-painter/anchoredImagePosition.ts
3
+ const authoredMargins = (geometry) => geometry.authoredMargins ?? {
4
+ top: geometry.marginTop,
5
+ right: geometry.marginRight,
6
+ bottom: geometry.marginBottom,
7
+ left: geometry.marginLeft
8
+ };
3
9
  function resolveHorizontalBand(relativeTo, geometry) {
10
+ const margins = authoredMargins(geometry);
4
11
  switch (relativeTo) {
5
12
  case "page": return {
6
13
  baseX: -geometry.marginLeft,
@@ -9,12 +16,12 @@ function resolveHorizontalBand(relativeTo, geometry) {
9
16
  case "leftMargin":
10
17
  case "insideMargin": return {
11
18
  baseX: -geometry.marginLeft,
12
- bandWidth: geometry.marginLeft
19
+ bandWidth: margins.left
13
20
  };
14
21
  case "rightMargin":
15
22
  case "outsideMargin": return {
16
- baseX: geometry.contentWidth,
17
- bandWidth: geometry.marginRight
23
+ baseX: geometry.pageWidth - geometry.marginLeft - margins.right,
24
+ bandWidth: margins.right
18
25
  };
19
26
  case "character": return {
20
27
  baseX: 0,
@@ -27,6 +34,7 @@ function resolveHorizontalBand(relativeTo, geometry) {
27
34
  }
28
35
  }
29
36
  function resolveVerticalBand(relativeTo, fragmentY, geometry) {
37
+ const margins = authoredMargins(geometry);
30
38
  switch (relativeTo) {
31
39
  case "page": return {
32
40
  baseY: -geometry.marginTop,
@@ -34,11 +42,11 @@ function resolveVerticalBand(relativeTo, fragmentY, geometry) {
34
42
  };
35
43
  case "topMargin": return {
36
44
  baseY: -geometry.marginTop,
37
- bandHeight: geometry.marginTop
45
+ bandHeight: margins.top
38
46
  };
39
47
  case "bottomMargin": return {
40
- baseY: geometry.contentHeight,
41
- bandHeight: geometry.marginBottom
48
+ baseY: geometry.pageHeight - geometry.marginTop - margins.bottom,
49
+ bandHeight: margins.bottom
42
50
  };
43
51
  case "paragraph":
44
52
  case "line": return {
@@ -1,7 +1,7 @@
1
1
  import { FlowBlock, Measure } from "../layout-engine/types.js";
2
+ import { ImageAttrs } from "../prosemirror/schema/nodes.js";
2
3
  import { BlockLookup } from "./index.js";
3
4
  import { WrapType } from "../docx/wrapTypes.js";
4
- import { ImageAttrs } from "../prosemirror/schema/nodes.js";
5
5
  //#region src/layout-painter/imageLayout.d.ts
6
6
  /**
7
7
  * Anchored wrap-type targets — the OOXML wrap types except `inline`.
@@ -797,6 +797,7 @@ function renderPage(page, context, options = {}) {
797
797
  marginTop: page.margins.top,
798
798
  marginRight: page.margins.right,
799
799
  marginBottom: page.margins.bottom,
800
+ ...page.authoredMargins ? { authoredMargins: page.authoredMargins } : {},
800
801
  contentWidth,
801
802
  contentHeight: page.size.h - page.margins.top - page.margins.bottom
802
803
  };
@@ -1209,10 +1210,19 @@ function computePageFingerprint(page, blockLookup) {
1209
1210
  function computePageRenderFingerprint(page, blockLookup) {
1210
1211
  return computePageFingerprintInternal(page, blockLookup, { includePmPositions: false });
1211
1212
  }
1213
+ const pageMarginsFingerprint = (margins) => [
1214
+ margins.top,
1215
+ margins.right,
1216
+ margins.bottom,
1217
+ margins.left,
1218
+ margins.header ?? "",
1219
+ margins.footer ?? ""
1220
+ ].join(",");
1212
1221
  function computePageFingerprintInternal(page, blockLookup, options) {
1213
1222
  const parts = [];
1214
1223
  parts.push(`s:${page.size.w},${page.size.h}`);
1215
- parts.push(`m:${page.margins.top},${page.margins.right},${page.margins.bottom},${page.margins.left}`);
1224
+ parts.push(`m:${pageMarginsFingerprint(page.margins)}`);
1225
+ if (page.authoredMargins) parts.push(`am:${pageMarginsFingerprint(page.authoredMargins)}`);
1216
1226
  parts.push(`n:${page.number}`);
1217
1227
  if (page.sectionIndex !== void 0) parts.push(`si:${page.sectionIndex}`);
1218
1228
  if (page.sectionPageNumber !== void 0) parts.push(`sp:${page.sectionPageNumber}`);
@@ -2,7 +2,7 @@ import { ommlToMathml } from "../docx/mathToMathml.js";
2
2
  import { parseXmlDocument } from "../docx/xmlParser.js";
3
3
  import { evaluateFieldInstruction } from "../fields/evaluateField.js";
4
4
  import { getListMarkerInlineWidth, getListMarkerVisualOffset } from "../layout-engine/measure/listMarkerWidth.js";
5
- import "../layout-engine/measure/measureHelpers.js";
5
+ import { DOCX_SCRIPT_FONT_SCALE } from "../layout-engine/measure/measureHelpers.js";
6
6
  import { FONT_KERNING_MODE, countCompressibleSpaces, getFontKerningMode, getRunFontKerningMode, toPaintedText } from "../layout-engine/measure/textMeasurementPolicy.js";
7
7
  import { isFloatingImageRun } from "../layout-engine/types.js";
8
8
  import { calculateTabWidth } from "../prosemirror/utils/tabCalculator.js";
@@ -76,7 +76,6 @@ function isMathRun(run) {
76
76
  }
77
77
  const AUTOMATIC_TEXT_COLOR_VALUES = /* @__PURE__ */ new Set(["auto", "windowtext"]);
78
78
  const DEFAULT_BLACK_TEXT_COLOR_VALUES = /* @__PURE__ */ new Set(["000000", "000"]);
79
- const DOCX_SUPERSCRIPT_SCALE = .75;
80
79
  const SUGGESTION_COLOR_CSS = "var(--suggestion-color, #6d3bd6)";
81
80
  const SUGGESTION_TINT_CSS = "var(--suggestion-bg, color-mix(in oklch, #6d3bd6 12%, transparent))";
82
81
  const SUGGESTION_TINT_LAYER_CSS = `linear-gradient(${SUGGESTION_TINT_CSS}, ${SUGGESTION_TINT_CSS})`;
@@ -109,8 +108,8 @@ function fontSizePtToPx(fontSizePt) {
109
108
  return fontSizePt * 96 / 72;
110
109
  }
111
110
  function getRaisedRunFontSize(run) {
112
- if (run.fontSize) return `${fontSizePtToPx(run.fontSize) * DOCX_SUPERSCRIPT_SCALE}px`;
113
- return `${DOCX_SUPERSCRIPT_SCALE}em`;
111
+ if (run.fontSize) return `${fontSizePtToPx(run.fontSize) * DOCX_SCRIPT_FONT_SCALE}px`;
112
+ return `${DOCX_SCRIPT_FONT_SCALE}em`;
114
113
  }
115
114
  /**
116
115
  * Apply text run styles to an element
@@ -1,10 +1,10 @@
1
1
  import { Subscribable } from "./Subscribable.js";
2
+ import { decodeAutoSaveEnvelope, encodeAutoSaveDocument, encodeAutoSaveEnvelopeFromDocument } from "./autoSaveCodec.js";
2
3
  //#region src/managers/AutoSaveManager.ts
3
4
  const DEFAULT_STORAGE_KEY = "docx-editor-autosave";
4
5
  const DEFAULT_INTERVAL = 3e4;
5
6
  const DEFAULT_MAX_AGE = 1440 * 60 * 1e3;
6
7
  const DEFAULT_DEBOUNCE_DELAY = 2e3;
7
- const SAVE_VERSION = 1;
8
8
  function isLocalStorageAvailable() {
9
9
  try {
10
10
  const testKey = "__docx_editor_test__";
@@ -16,31 +16,7 @@ function isLocalStorageAvailable() {
16
16
  }
17
17
  }
18
18
  function serializeForStorage(document) {
19
- return JSON.stringify({
20
- ...document,
21
- originalBuffer: null
22
- });
23
- }
24
- function isDocumentLike(value) {
25
- return typeof value === "object" && value !== null && "package" in value;
26
- }
27
- function parseSavedData(json) {
28
- let parsed;
29
- try {
30
- parsed = JSON.parse(json);
31
- } catch {
32
- return null;
33
- }
34
- if (typeof parsed !== "object" || parsed === null) return null;
35
- if (!("document" in parsed) || !("savedAt" in parsed) || !("version" in parsed)) return null;
36
- const { document, savedAt, version } = parsed;
37
- if (typeof savedAt !== "string" || typeof version !== "number") return null;
38
- if (!isDocumentLike(document)) return null;
39
- return {
40
- document,
41
- savedAt,
42
- version
43
- };
19
+ return encodeAutoSaveDocument(document);
44
20
  }
45
21
  function isStale(savedAt, maxAge) {
46
22
  const savedTime = new Date(savedAt).getTime();
@@ -99,12 +75,12 @@ var AutoSaveManager = class extends Subscribable {
99
75
  this.updateStatus("saving");
100
76
  try {
101
77
  const serialized = serializeForStorage(doc);
102
- if (serialized === this.lastSavedJson) {
78
+ if (serialized.json === this.lastSavedJson) {
103
79
  this.updateStatus("saved");
104
80
  return true;
105
81
  }
106
- this.persistToStorage(doc);
107
- this.lastSavedJson = serialized;
82
+ this.persistToStorage(serialized);
83
+ this.lastSavedJson = serialized.json;
108
84
  const saveTime = /* @__PURE__ */ new Date();
109
85
  this.lastSaveTime = saveTime;
110
86
  this.updateStatus("saved");
@@ -133,7 +109,7 @@ var AutoSaveManager = class extends Subscribable {
133
109
  if (!this.storageAvailable) return null;
134
110
  const savedJson = localStorage.getItem(this.storageKey);
135
111
  if (!savedJson) return null;
136
- const savedData = parseSavedData(savedJson);
112
+ const savedData = decodeAutoSaveEnvelope(savedJson);
137
113
  if (!savedData) return null;
138
114
  if (isStale(savedData.savedAt, this.maxAge)) {
139
115
  this.clear();
@@ -179,7 +155,7 @@ var AutoSaveManager = class extends Subscribable {
179
155
  destroy() {
180
156
  this.stopTimers();
181
157
  if (this.isEnabled && this.currentDocument && this.storageAvailable) try {
182
- this.persistToStorage(this.currentDocument);
158
+ this.persistToStorage(serializeForStorage(this.currentDocument));
183
159
  } catch (error) {
184
160
  this.onErrorCallback?.(error instanceof Error ? error : new Error(String(error)));
185
161
  }
@@ -194,15 +170,7 @@ var AutoSaveManager = class extends Subscribable {
194
170
  }
195
171
  }
196
172
  persistToStorage(document) {
197
- const dataToSave = {
198
- document: {
199
- ...document,
200
- originalBuffer: null
201
- },
202
- savedAt: (/* @__PURE__ */ new Date()).toISOString(),
203
- version: SAVE_VERSION
204
- };
205
- localStorage.setItem(this.storageKey, JSON.stringify(dataToSave));
173
+ localStorage.setItem(this.storageKey, encodeAutoSaveEnvelopeFromDocument(document, (/* @__PURE__ */ new Date()).toISOString()));
206
174
  }
207
175
  debounceSave() {
208
176
  if (this.debounceTimer) clearTimeout(this.debounceTimer);
@@ -1,7 +1,7 @@
1
1
  import { document_d_exports } from "../types/document.js";
2
+ import { TableAction, TableContext } from "../utils/tableOperations.js";
2
3
  import { Subscribable } from "./Subscribable.js";
3
4
  import { CellCoordinates } from "./types.js";
4
- import { TableAction, TableContext } from "../utils/tableOperations.js";
5
5
  //#region src/managers/TableSelectionManager.d.ts
6
6
  /** Data attributes for table elements in the rendered DOM */
7
7
  declare const TABLE_DATA_ATTRIBUTES: {
@@ -0,0 +1,17 @@
1
+ import { document_d_exports } from "../types/document.js";
2
+ //#region src/managers/autoSaveCodec.d.ts
3
+ declare const AUTOSAVE_FORMAT_VERSION = 2;
4
+ type DecodedAutoSave = {
5
+ document: document_d_exports.Document;
6
+ savedAt: string;
7
+ version: typeof AUTOSAVE_FORMAT_VERSION;
8
+ };
9
+ type EncodedAutoSaveDocument = {
10
+ json: string;
11
+ };
12
+ declare const encodeAutoSaveDocument: (document: document_d_exports.Document) => EncodedAutoSaveDocument;
13
+ declare const encodeAutoSaveEnvelopeFromDocument: (document: EncodedAutoSaveDocument, savedAt: string) => string;
14
+ declare const encodeAutoSaveEnvelope: (document: document_d_exports.Document, savedAt: string) => string;
15
+ declare const decodeAutoSaveEnvelope: (json: string) => DecodedAutoSave | null;
16
+ //#endregion
17
+ export { AUTOSAVE_FORMAT_VERSION, DecodedAutoSave, EncodedAutoSaveDocument, decodeAutoSaveEnvelope, encodeAutoSaveDocument, encodeAutoSaveEnvelope, encodeAutoSaveEnvelopeFromDocument };
@@ -0,0 +1,109 @@
1
+ import { validateFolioDocumentModel } from "../docx/modelValidation.js";
2
+ //#region src/managers/autoSaveCodec.ts
3
+ const AUTOSAVE_FORMAT_VERSION = 2;
4
+ const BASE64_CHUNK_BYTES = 32768;
5
+ const encodeBase64 = (buffer) => {
6
+ const bytes = new Uint8Array(buffer);
7
+ const chunks = [];
8
+ for (let offset = 0; offset < bytes.length; offset += BASE64_CHUNK_BYTES) chunks.push(String.fromCharCode(...bytes.subarray(offset, offset + BASE64_CHUNK_BYTES)));
9
+ return btoa(chunks.join(""));
10
+ };
11
+ const decodeBase64 = (value) => {
12
+ const binary = atob(value);
13
+ const bytes = new Uint8Array(binary.length);
14
+ for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);
15
+ return bytes.buffer;
16
+ };
17
+ const encodeValue = (value) => {
18
+ if (value === void 0) return { type: "undefined" };
19
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
20
+ if (value instanceof Date) return {
21
+ type: "date",
22
+ value: value.toISOString()
23
+ };
24
+ if (value instanceof ArrayBuffer) return {
25
+ type: "arrayBuffer",
26
+ value: encodeBase64(value)
27
+ };
28
+ if (value instanceof Map) return {
29
+ type: "map",
30
+ value: [...value.entries()].map(([key, entry]) => [encodeValue(key), encodeValue(entry)])
31
+ };
32
+ if (Array.isArray(value)) return {
33
+ type: "array",
34
+ value: value.map(encodeValue)
35
+ };
36
+ if (typeof value === "object") {
37
+ const encoded = {};
38
+ for (const [key, entry] of Object.entries(value)) encoded[key] = encodeValue(entry);
39
+ return {
40
+ type: "object",
41
+ value: encoded
42
+ };
43
+ }
44
+ throw new TypeError(`Unsupported auto-save value: ${typeof value}`);
45
+ };
46
+ const decodeValue = (value) => {
47
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
48
+ if (typeof value !== "object" || !value || !("type" in value)) throw new TypeError("Invalid auto-save encoded value");
49
+ const type = value.type;
50
+ if (type === "undefined") return;
51
+ if (type === "date") {
52
+ if (!("value" in value) || typeof value.value !== "string" || !Number.isFinite(Date.parse(value.value))) throw new TypeError("Invalid auto-save date");
53
+ return new Date(value.value);
54
+ }
55
+ if (type === "arrayBuffer") {
56
+ if (!("value" in value) || typeof value.value !== "string") throw new TypeError("Invalid auto-save binary data");
57
+ return decodeBase64(value.value);
58
+ }
59
+ if (type === "array") {
60
+ if (!("value" in value) || !Array.isArray(value.value)) throw new TypeError("Invalid auto-save array");
61
+ return value.value.map(decodeValue);
62
+ }
63
+ if (type === "map") {
64
+ if (!("value" in value) || !Array.isArray(value.value)) throw new TypeError("Invalid auto-save map");
65
+ return new Map(value.value.map((entry) => {
66
+ if (!Array.isArray(entry) || entry.length !== 2) throw new TypeError("Invalid auto-save map entry");
67
+ return [decodeValue(entry[0]), decodeValue(entry[1])];
68
+ }));
69
+ }
70
+ if (type === "object") {
71
+ if (!("value" in value) || typeof value.value !== "object" || !value.value) throw new TypeError("Invalid auto-save object");
72
+ const decoded = Object.create(null);
73
+ for (const [key, entry] of Object.entries(value.value)) {
74
+ if (key === "__proto__" || key === "constructor" || key === "prototype") throw new TypeError("Invalid auto-save object key");
75
+ const decodedEntry = decodeValue(entry);
76
+ if (decodedEntry !== void 0) decoded[key] = decodedEntry;
77
+ }
78
+ return decoded;
79
+ }
80
+ throw new TypeError("Unknown auto-save encoded value");
81
+ };
82
+ const encodeAutoSaveDocument = (document) => {
83
+ const snapshot = {
84
+ ...document,
85
+ originalBuffer: null
86
+ };
87
+ return { json: JSON.stringify(encodeValue(snapshot)) };
88
+ };
89
+ const encodeAutoSaveEnvelopeFromDocument = (document, savedAt) => `{"document":${document.json},"savedAt":${JSON.stringify(savedAt)},"version":2}`;
90
+ const encodeAutoSaveEnvelope = (document, savedAt) => encodeAutoSaveEnvelopeFromDocument(encodeAutoSaveDocument(document), savedAt);
91
+ const decodeAutoSaveEnvelope = (json) => {
92
+ try {
93
+ const parsed = JSON.parse(json);
94
+ if (typeof parsed !== "object" || !parsed || !("document" in parsed) || !("savedAt" in parsed) || !("version" in parsed)) return null;
95
+ if (parsed.version !== 2 || typeof parsed.savedAt !== "string" || !Number.isFinite(Date.parse(parsed.savedAt))) return null;
96
+ const document = decodeValue(parsed.document);
97
+ if (typeof document !== "object" || !document) return null;
98
+ if (!validateFolioDocumentModel(document).valid) return null;
99
+ return {
100
+ document,
101
+ savedAt: parsed.savedAt,
102
+ version: 2
103
+ };
104
+ } catch {
105
+ return null;
106
+ }
107
+ };
108
+ //#endregion
109
+ export { AUTOSAVE_FORMAT_VERSION, decodeAutoSaveEnvelope, encodeAutoSaveDocument, encodeAutoSaveEnvelope, encodeAutoSaveEnvelopeFromDocument };