@stll/folio-core 0.37.1 → 0.37.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.
- package/dist/ai-edits/headless.d.ts +24 -1
- package/dist/ai-edits/headless.js +108 -71
- package/dist/ai-edits/read.d.ts +9 -1
- package/dist/ai-edits/read.js +34 -16
- package/dist/ai-edits/snapshot.d.ts +7 -5
- package/dist/ai-edits/snapshot.js +39 -12
- package/dist/ai-edits/table-cell-mutations.js +10 -5
- package/dist/ai-edits/table-template.js +19 -5
- package/dist/compare/compare.d.ts +2 -3
- package/dist/compare/compare.js +41 -64
- package/dist/compare/content-alignment.js +0 -1
- package/dist/compare/scenario.d.ts +11 -2
- package/dist/compare/scenario.js +6 -2
- package/dist/controller/hiddenEditorManager.js +11 -0
- package/dist/controller/layoutPipeline.js +1 -1
- package/dist/display-list/build/textBoxPrimitives.js +34 -1
- package/dist/display-list/dom/renderDisplayListToDom.js +5 -2
- package/dist/display-list/primitives.d.ts +1 -1
- package/dist/display-list/types.d.ts +8 -4
- package/dist/docx/paragraphPropertySource.d.ts +82 -2
- package/dist/docx/paragraphPropertySource.js +569 -3
- package/dist/docx/parser.js +9 -0
- package/dist/docx/server/materializeYjsDocx.d.ts +1 -1
- package/dist/docx/server/materializeYjsDocx.js +21 -2
- package/dist/headless-layout.js +1 -1
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +7 -1
- package/dist/layout-bridge/convert/headerFooterLayout.js +20 -3
- package/dist/layout-bridge/convert/toFlowBlocks.js +43 -12
- package/dist/layout-engine/index.js +20 -10
- package/dist/layout-engine/measure/measureBlocks.d.ts +7 -3
- package/dist/layout-engine/measure/measureBlocks.js +10 -7
- package/dist/layout-engine/measure/measureParagraph.d.ts +2 -0
- package/dist/layout-engine/measure/measureParagraph.js +1 -1
- package/dist/layout-engine/paginator.d.ts +1 -1
- package/dist/layout-engine/paginator.js +41 -4
- package/dist/layout-engine/textBoxFlow.d.ts +2 -0
- package/dist/layout-engine/textBoxFlow.js +9 -5
- package/dist/layout-engine/types.d.ts +6 -0
- package/dist/layout-painter/documentColors.d.ts +10 -1
- package/dist/layout-painter/documentColors.js +16 -1
- package/dist/layout-painter/renderParagraph.js +9 -24
- package/dist/layout-painter/renderTable.js +3 -3
- package/dist/layout-painter/renderTextBox.js +2 -1
- package/dist/pdf/pageSpace.d.ts +12 -1
- package/dist/pdf/pageSpace.js +24 -1
- package/dist/pdf/paint.js +2 -2
- package/dist/prosemirror/attrs/index.js +19 -8
- package/dist/prosemirror/commands/comments.js +12 -3
- package/dist/prosemirror/commands/tableCellMergeResolution.js +18 -11
- package/dist/prosemirror/conversion/fromProseDoc.js +94 -21
- package/dist/prosemirror/conversion/toProseDoc.js +100 -8
- package/dist/prosemirror/extensions/core/DocExtension.js +2 -0
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +2 -0
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +5 -1
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +132 -41
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.d.ts +2 -0
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +7 -0
- package/dist/prosemirror/schema/nodes.d.ts +3 -1
- package/dist/prosemirror/yjsParagraphSourceContract.d.ts +9 -0
- package/dist/prosemirror/yjsParagraphSourceContract.js +26 -0
- package/dist/utils/rotationBoundingBox.d.ts +5 -1
- package/dist/utils/rotationBoundingBox.js +9 -1
- package/package.json +2 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { resolveColorValueToHex } from "../../docx/drawingUtils.js";
|
|
2
|
-
import {
|
|
2
|
+
import { PROSE_PARAGRAPH_SOURCE_CONTRACT_ATTR, createProseParagraphWithPropertySource, getDocumentParagraphPropertySourceContract, recreateProseNodeWithParagraphPropertySource, transportTableCellsWithParagraphPropertySources } from "../../docx/paragraphPropertySource.js";
|
|
3
3
|
import { buildPageBreakRunSourceDescendantIndex } from "../../internal/pageBreakRunSourceDescendantIndex.js";
|
|
4
4
|
import { createStyleEngine } from "../../style-engine/styleEngine.js";
|
|
5
5
|
import { normalizeHorizontalScalePercent } from "../../utils/horizontalScale.js";
|
|
@@ -131,6 +131,7 @@ function toProseDoc(document, options) {
|
|
|
131
131
|
const finalSectionStart = document.package.document.sections?.at(-1)?.properties.sectionStart ?? null;
|
|
132
132
|
const adjustLineHeightInTable = document.package.settings?.adjustLineHeightInTable === true;
|
|
133
133
|
const pmDoc = stampNumberedRefFieldBaselines(schema.node("doc", {
|
|
134
|
+
[PROSE_PARAGRAPH_SOURCE_CONTRACT_ATTR]: getDocumentParagraphPropertySourceContract(document) ?? null,
|
|
134
135
|
_finalSectionStart: finalSectionStart,
|
|
135
136
|
_adjustLineHeightInTable: adjustLineHeightInTable
|
|
136
137
|
}, nodes));
|
|
@@ -205,7 +206,8 @@ function convertParagraph(paragraph, styleResolver, context, activeCommentIds, e
|
|
|
205
206
|
let paragraphStyleRunFormatting;
|
|
206
207
|
let paragraphStyleFontFamily;
|
|
207
208
|
if (styleResolver) {
|
|
208
|
-
|
|
209
|
+
const resolved = styleResolver.resolveParagraphStyle(paragraph.formatting?.styleId);
|
|
210
|
+
styleRunFormatting = extraRunFormatting === void 0 ? resolved.runFormatting : withoutFontFamily(resolved.runFormatting);
|
|
209
211
|
const paragraphStyle = paragraph.formatting?.styleId ? styleResolver.getStyle(paragraph.formatting.styleId) ?? styleResolver.getDefaultParagraphStyle() : styleResolver.getDefaultParagraphStyle();
|
|
210
212
|
paragraphStyleRunFormatting = paragraphStyle?.type === "paragraph" ? paragraphStyle.rPr : void 0;
|
|
211
213
|
paragraphStyleFontFamily = resolveParagraphStyleFontFamily(paragraph.formatting?.styleId, styleResolver);
|
|
@@ -343,18 +345,28 @@ function convertParagraph(paragraph, styleResolver, context, activeCommentIds, e
|
|
|
343
345
|
}
|
|
344
346
|
if (bookmarksArr) attrs.bookmarks = bookmarksArr;
|
|
345
347
|
if (emptyHyperlinks) attrs._emptyHyperlinks = emptyHyperlinks;
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
348
|
+
return createProseParagraphWithPropertySource(schema.nodes["paragraph"], paragraph, {
|
|
349
|
+
attrs,
|
|
350
|
+
content: inlineNodes
|
|
351
|
+
});
|
|
349
352
|
}
|
|
353
|
+
const withoutFontFamily = (formatting) => {
|
|
354
|
+
if (!formatting?.fontFamily) return formatting;
|
|
355
|
+
const { fontFamily: _fontFamily, ...withoutFont } = formatting;
|
|
356
|
+
return Object.keys(withoutFont).length > 0 ? withoutFont : void 0;
|
|
357
|
+
};
|
|
350
358
|
const resolveParagraphStyleFontFamily = (styleId, styleResolver) => {
|
|
351
359
|
let style = styleId ? styleResolver.getStyle(styleId) : styleResolver.getDefaultParagraphStyle();
|
|
352
360
|
const visited = /* @__PURE__ */ new Set();
|
|
361
|
+
const styleChain = [];
|
|
353
362
|
while (style?.type === "paragraph" && !visited.has(style.styleId)) {
|
|
354
363
|
visited.add(style.styleId);
|
|
355
|
-
if (style.rPr?.fontFamily)
|
|
364
|
+
if (style.rPr?.fontFamily) styleChain.push({ fontFamily: style.rPr.fontFamily });
|
|
356
365
|
style = style.basedOn ? styleResolver.getStyle(style.basedOn) : void 0;
|
|
357
366
|
}
|
|
367
|
+
let formatting;
|
|
368
|
+
for (const styleFormatting of styleChain.toReversed()) formatting = mergeTextFormatting(formatting, styleFormatting);
|
|
369
|
+
return formatting?.fontFamily;
|
|
358
370
|
};
|
|
359
371
|
/**
|
|
360
372
|
* Apply comment marks to PM nodes within a comment range.
|
|
@@ -789,7 +801,14 @@ function paragraphContentHasMeaningfulContent(content) {
|
|
|
789
801
|
return true;
|
|
790
802
|
}
|
|
791
803
|
function convertTable(table, styleResolver, context) {
|
|
792
|
-
for (const row of table.rows) for (const cell of row.cells)
|
|
804
|
+
for (const row of table.rows) for (const cell of row.cells) {
|
|
805
|
+
if (cell.formatting?.vMerge === "continue" && context.pageBreakRunSourceDescendants.containsPageBreakRun(cell.content)) throw new UnsupportedDocxToProseMirrorConversionError({
|
|
806
|
+
message: `${PAGE_BREAK_CONTAINER_DESCRIPTIONS["table-cell"]} cannot be represented in the editor model`,
|
|
807
|
+
owner: "table-cell",
|
|
808
|
+
contentType: "break"
|
|
809
|
+
});
|
|
810
|
+
assertSourceContainerHasNoPageBreakRun(cell.content, "table-cell", context.pageBreakRunSourceDescendants);
|
|
811
|
+
}
|
|
793
812
|
const rowSpanMap = calculateRowSpans(table);
|
|
794
813
|
const columnWidths = table.columnWidths;
|
|
795
814
|
const totalWidth = columnWidths?.reduce((sum, w) => sum + w, 0) ?? 0;
|
|
@@ -1077,7 +1096,7 @@ function convertTableCell({ cell, styleResolver, context, isHeader, gridWidthPer
|
|
|
1077
1096
|
...cell.structuralChange.verticalMergeOriginal !== void 0 ? { verticalMergeOriginal: cell.structuralChange.verticalMergeOriginal } : {}
|
|
1078
1097
|
};
|
|
1079
1098
|
if (preserveVMergeRestart) attrs._preserveVMergeRestart = true;
|
|
1080
|
-
if (vMergeContinuationCells && vMergeContinuationCells.length > 0) attrs._docxVMergeContinuationCells = vMergeContinuationCells;
|
|
1099
|
+
if (vMergeContinuationCells && vMergeContinuationCells.length > 0) attrs._docxVMergeContinuationCells = transportTableCellsWithParagraphPropertySources(vMergeContinuationCells);
|
|
1081
1100
|
const contentNodes = [];
|
|
1082
1101
|
for (const content of cell.content) if (content.type === "paragraph") contentNodes.push(...convertParagraphWithTextBoxes(content, styleResolver, {
|
|
1083
1102
|
textBoxGroupId: context.nextTextBoxGroupId(),
|
|
@@ -1255,12 +1274,74 @@ const PAGE_BREAK_PARAGRAPH_OWNERS = {
|
|
|
1255
1274
|
};
|
|
1256
1275
|
function assertSourceContainerHasNoPageBreakRun(content, owner, sourceDescendants) {
|
|
1257
1276
|
if (!sourceDescendants.containsPageBreakRun(content)) return;
|
|
1277
|
+
if (owner === "table-cell" && hasSingleLeadingTableCellPageBreak(content)) return;
|
|
1258
1278
|
throw new UnsupportedDocxToProseMirrorConversionError({
|
|
1259
1279
|
message: `${PAGE_BREAK_CONTAINER_DESCRIPTIONS[owner]} cannot be represented in the editor model`,
|
|
1260
1280
|
owner,
|
|
1261
1281
|
contentType: "break"
|
|
1262
1282
|
});
|
|
1263
1283
|
}
|
|
1284
|
+
/** A leading page-break run in a cell advances the whole row during pagination. This
|
|
1285
|
+
* narrow shape has a lossless PM representation and a row-wide layout
|
|
1286
|
+
* projection; interior breaks still require table-fragment ownership. */
|
|
1287
|
+
function hasSingleLeadingTableCellPageBreak(content) {
|
|
1288
|
+
const paragraph = content.length === 1 && content[0]?.type === "paragraph" ? content[0] : void 0;
|
|
1289
|
+
return paragraph !== void 0 && hasSingleLeadingParagraphPageBreak(paragraph);
|
|
1290
|
+
}
|
|
1291
|
+
const scanLeadingPageBreakRun = (run, scan) => {
|
|
1292
|
+
for (const content of run.content) {
|
|
1293
|
+
if (content.type === "renderedPageBreak") continue;
|
|
1294
|
+
if (content.type === "break" && content.breakType === "page") {
|
|
1295
|
+
scan.pageBreaks += 1;
|
|
1296
|
+
continue;
|
|
1297
|
+
}
|
|
1298
|
+
if (scan.pageBreaks === 0) scan.contentBeforeBreak = true;
|
|
1299
|
+
}
|
|
1300
|
+
};
|
|
1301
|
+
const scanLeadingPageBreakContent = (content, scan) => {
|
|
1302
|
+
switch (content.type) {
|
|
1303
|
+
case "run":
|
|
1304
|
+
scanLeadingPageBreakRun(content, scan);
|
|
1305
|
+
return;
|
|
1306
|
+
case "hyperlink":
|
|
1307
|
+
for (const child of content.children) scanLeadingPageBreakContent(child, scan);
|
|
1308
|
+
return;
|
|
1309
|
+
case "insertion":
|
|
1310
|
+
case "deletion":
|
|
1311
|
+
case "moveFrom":
|
|
1312
|
+
case "moveTo":
|
|
1313
|
+
case "inlineSdt":
|
|
1314
|
+
for (const child of content.content) scanLeadingPageBreakContent(child, scan);
|
|
1315
|
+
return;
|
|
1316
|
+
case "simpleField":
|
|
1317
|
+
for (const child of content.content) scanLeadingPageBreakContent(child, scan);
|
|
1318
|
+
return;
|
|
1319
|
+
case "complexField":
|
|
1320
|
+
for (const child of content.fieldResult) scanLeadingPageBreakRun(child, scan);
|
|
1321
|
+
return;
|
|
1322
|
+
case "bookmarkStart":
|
|
1323
|
+
case "bookmarkEnd":
|
|
1324
|
+
case "commentRangeStart":
|
|
1325
|
+
case "commentRangeEnd":
|
|
1326
|
+
case "moveFromRangeStart":
|
|
1327
|
+
case "moveFromRangeEnd":
|
|
1328
|
+
case "moveToRangeStart":
|
|
1329
|
+
case "moveToRangeEnd": return;
|
|
1330
|
+
case "commentReference":
|
|
1331
|
+
case "mathEquation":
|
|
1332
|
+
if (scan.pageBreaks === 0) scan.contentBeforeBreak = true;
|
|
1333
|
+
return;
|
|
1334
|
+
default: return content;
|
|
1335
|
+
}
|
|
1336
|
+
};
|
|
1337
|
+
const hasSingleLeadingParagraphPageBreak = (paragraph) => {
|
|
1338
|
+
const scan = {
|
|
1339
|
+
contentBeforeBreak: false,
|
|
1340
|
+
pageBreaks: 0
|
|
1341
|
+
};
|
|
1342
|
+
for (const content of paragraph.content) scanLeadingPageBreakContent(content, scan);
|
|
1343
|
+
return !scan.contentBeforeBreak && scan.pageBreaks === 1;
|
|
1344
|
+
};
|
|
1264
1345
|
function assertParagraphPageBreakCanBeProjected({ paragraph, attrs, effectiveFrame, sourceDescendants }) {
|
|
1265
1346
|
const sourceFeatures = sourceDescendants.paragraphFeatures(paragraph);
|
|
1266
1347
|
if (!sourceFeatures.hasPageBreakRun) return;
|
|
@@ -1270,6 +1351,7 @@ function assertParagraphPageBreakCanBeProjected({ paragraph, attrs, effectiveFra
|
|
|
1270
1351
|
hasTextBoxAnchor: sourceFeatures.hasTextBoxShape && !sourceFeatures.pageBreakSharesTextBoxShape
|
|
1271
1352
|
});
|
|
1272
1353
|
if (disposition.status === "supported") return;
|
|
1354
|
+
if (disposition.reason !== "textBoxAnchor" && hasSingleLeadingParagraphPageBreak(paragraph)) return;
|
|
1273
1355
|
throw new UnsupportedDocxToProseMirrorConversionError({
|
|
1274
1356
|
message: disposition.message,
|
|
1275
1357
|
owner: PAGE_BREAK_PARAGRAPH_OWNERS[disposition.reason],
|
|
@@ -2065,6 +2147,7 @@ function textBoxFromShape(shape, textBody) {
|
|
|
2065
2147
|
if (shape.wrap) textBox.wrap = shape.wrap;
|
|
2066
2148
|
if (shape.fill) textBox.fill = shape.fill;
|
|
2067
2149
|
if (shape.outline) textBox.outline = shape.outline;
|
|
2150
|
+
if (shape.transform) textBox.transform = shape.transform;
|
|
2068
2151
|
if (textBody.margins) textBox.margins = textBody.margins;
|
|
2069
2152
|
if (textBody.autoFit) textBox.autoFit = textBody.autoFit;
|
|
2070
2153
|
if (textBody.textWrap) textBox.textWrap = textBody.textWrap;
|
|
@@ -2089,6 +2172,14 @@ function convertTextBox(textBox, styleResolver, options) {
|
|
|
2089
2172
|
if (textBox.outline.color?.rgb) outlineColor = `#${textBox.outline.color.rgb}`;
|
|
2090
2173
|
outlineStyle = textBox.outline.style || "solid";
|
|
2091
2174
|
}
|
|
2175
|
+
let transform;
|
|
2176
|
+
if (textBox.transform) {
|
|
2177
|
+
const transforms = [];
|
|
2178
|
+
if (textBox.transform.rotation) transforms.push(`rotate(${textBox.transform.rotation}deg)`);
|
|
2179
|
+
if (textBox.transform.flipH) transforms.push("scaleX(-1)");
|
|
2180
|
+
if (textBox.transform.flipV) transforms.push("scaleY(-1)");
|
|
2181
|
+
if (transforms.length > 0) transform = transforms.join(" ");
|
|
2182
|
+
}
|
|
2092
2183
|
const marginTop = textBox.margins?.top !== void 0 ? emuToPixels(textBox.margins.top) : 4;
|
|
2093
2184
|
const marginBottom = textBox.margins?.bottom !== void 0 ? emuToPixels(textBox.margins.bottom) : 4;
|
|
2094
2185
|
const marginLeft = textBox.margins?.left !== void 0 ? emuToPixels(textBox.margins.left) : 7;
|
|
@@ -2151,6 +2242,7 @@ function convertTextBox(textBox, styleResolver, options) {
|
|
|
2151
2242
|
outlineWidth,
|
|
2152
2243
|
outlineColor,
|
|
2153
2244
|
outlineStyle,
|
|
2245
|
+
transform,
|
|
2154
2246
|
marginTop,
|
|
2155
2247
|
marginBottom,
|
|
2156
2248
|
marginLeft,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PROSE_PARAGRAPH_SOURCE_CONTRACT_ATTR } from "../../../docx/paragraphPropertySource.js";
|
|
1
2
|
import { createNodeExtension } from "../create.js";
|
|
2
3
|
//#region src/prosemirror/extensions/core/DocExtension.ts
|
|
3
4
|
/**
|
|
@@ -8,6 +9,7 @@ const DocExtension = createNodeExtension({
|
|
|
8
9
|
schemaNodeName: "doc",
|
|
9
10
|
nodeSpec: {
|
|
10
11
|
attrs: {
|
|
12
|
+
[PROSE_PARAGRAPH_SOURCE_CONTRACT_ATTR]: { default: null },
|
|
11
13
|
_finalSectionStart: { default: null },
|
|
12
14
|
_adjustLineHeightInTable: { default: false }
|
|
13
15
|
},
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PROSE_PARAGRAPH_SOURCE_TOKEN_ATTR } from "../../../docx/paragraphPropertySource.js";
|
|
1
2
|
import { PARAGRAPH_ALIGNMENT_VALUES } from "../../../types/documentEnumValues.js";
|
|
2
3
|
import { paragraphToStyle } from "../../../utils/formatToStyle.js";
|
|
3
4
|
import { collectHeadings } from "../../../utils/headingCollector.js";
|
|
@@ -184,6 +185,7 @@ const paragraphNodeSpec = {
|
|
|
184
185
|
group: "block",
|
|
185
186
|
attrs: {
|
|
186
187
|
paraId: { default: null },
|
|
188
|
+
[PROSE_PARAGRAPH_SOURCE_TOKEN_ATTR]: { default: null },
|
|
187
189
|
idStability: { default: void 0 },
|
|
188
190
|
textId: { default: null },
|
|
189
191
|
alignment: { default: null },
|
|
@@ -2,7 +2,11 @@ import { Extension } from "../types.js";
|
|
|
2
2
|
import { EditorState, PluginKey, Transaction } from "prosemirror-state";
|
|
3
3
|
import { Node } from "prosemirror-model";
|
|
4
4
|
//#region src/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts
|
|
5
|
-
|
|
5
|
+
type ParagraphPropertySourceSeed = {
|
|
6
|
+
contract: string | null;
|
|
7
|
+
tokens: ReadonlySet<string>;
|
|
8
|
+
};
|
|
9
|
+
declare const paraIdAllocatorKey: PluginKey<ParagraphPropertySourceSeed>;
|
|
6
10
|
/**
|
|
7
11
|
* Transaction meta asking this plugin to derive the ids it mints from a
|
|
8
12
|
* caller-supplied seed instead of `Math.random()`.
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { recreateProseNodeWithParagraphPropertySource, setProseParagraphMarkupWithPropertySource, transferProseParagraphPropertySource } from "../../../docx/paragraphPropertySource.js";
|
|
1
|
+
import { PROSE_PARAGRAPH_SOURCE_TOKEN_ATTR, getExplicitParagraphPropertySourceTransfers, getProseDocumentParagraphPropertySourceContract, getProseParagraphPropertySourceToken, paragraphPropertySourceTokenMatchesContract, recreateProseNodeWithParagraphPropertySource, setProseParagraphMarkupWithPropertySource, transferProseParagraphPropertySource } from "../../../docx/paragraphPropertySource.js";
|
|
2
2
|
import { deterministicHexId, generateHexId } from "../../../utils/hexId.js";
|
|
3
3
|
import { createExtension } from "../create.js";
|
|
4
4
|
import { ignoreTrackedChanges } from "./ParagraphChangeTrackerExtension.js";
|
|
5
|
+
import { panic } from "better-result";
|
|
5
6
|
import { Fragment } from "prosemirror-model";
|
|
6
7
|
import { Plugin, PluginKey } from "prosemirror-state";
|
|
7
8
|
//#region src/prosemirror/extensions/features/ParaIdAllocatorExtension.ts
|
|
@@ -73,61 +74,100 @@ const mintParaId = (taken, seed, pos) => {
|
|
|
73
74
|
return id;
|
|
74
75
|
};
|
|
75
76
|
const isUsableParaId = (value) => typeof value === "string" && value.length > 0 && value !== "00000000";
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const
|
|
83
|
-
|
|
77
|
+
const collectParagraphPropertySourceSeed = (doc) => {
|
|
78
|
+
const contract = getProseDocumentParagraphPropertySourceContract(doc);
|
|
79
|
+
if (!contract) return {
|
|
80
|
+
contract: null,
|
|
81
|
+
tokens: /* @__PURE__ */ new Set()
|
|
82
|
+
};
|
|
83
|
+
const counts = /* @__PURE__ */ new Map();
|
|
84
|
+
doc.descendants((node) => {
|
|
85
|
+
if (node.type.name !== "paragraph") return true;
|
|
86
|
+
const token = getProseParagraphPropertySourceToken(node);
|
|
87
|
+
if (paragraphPropertySourceTokenMatchesContract(token, contract)) counts.set(token, (counts.get(token) ?? 0) + 1);
|
|
88
|
+
return false;
|
|
89
|
+
});
|
|
90
|
+
return {
|
|
91
|
+
contract,
|
|
92
|
+
tokens: new Set([...counts].filter(([, count]) => count === 1).map(([token]) => token))
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
const mapParagraphKeepers = (oldDoc, transactions, sourceSeed) => {
|
|
96
|
+
const paraIds = /* @__PURE__ */ new Map();
|
|
97
|
+
const sourceTokens = /* @__PURE__ */ new Map();
|
|
84
98
|
oldDoc.descendants((node, pos) => {
|
|
85
99
|
if (node.type.name !== "paragraph") return true;
|
|
86
100
|
const id = node.attrs["paraId"];
|
|
87
|
-
|
|
101
|
+
const token = getProseParagraphPropertySourceToken(node);
|
|
102
|
+
const mapsParaId = isUsableParaId(id) && !paraIds.has(id);
|
|
103
|
+
const mapsSourceToken = typeof token === "string" && sourceSeed.tokens.has(token);
|
|
104
|
+
if (!mapsParaId && !mapsSourceToken) return false;
|
|
88
105
|
let mapped = pos;
|
|
106
|
+
let mappedInterior = pos + 1;
|
|
89
107
|
let deleted = false;
|
|
90
|
-
for (const
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
mapped = result.pos;
|
|
108
|
+
for (const transaction of transactions) {
|
|
109
|
+
const ownerResult = transaction.mapping.mapResult(mapped);
|
|
110
|
+
const interiorResult = transaction.mapping.mapResult(mappedInterior, -1);
|
|
111
|
+
deleted ||= interiorResult.deletedAcross;
|
|
112
|
+
mapped = ownerResult.pos;
|
|
113
|
+
mappedInterior = interiorResult.pos;
|
|
97
114
|
}
|
|
98
|
-
if (!deleted)
|
|
115
|
+
if (mapsParaId && !deleted) paraIds.set(id, mapped);
|
|
116
|
+
if (mapsSourceToken) sourceTokens.set(token, sourceTokens.has(token) ? { status: "ambiguous" } : {
|
|
117
|
+
pos: mapped,
|
|
118
|
+
status: deleted ? "deleted" : "mapped"
|
|
119
|
+
});
|
|
99
120
|
return false;
|
|
100
121
|
});
|
|
101
|
-
return
|
|
122
|
+
return {
|
|
123
|
+
paraIds,
|
|
124
|
+
sourceTokens
|
|
125
|
+
};
|
|
102
126
|
};
|
|
103
|
-
const
|
|
104
|
-
const
|
|
105
|
-
|
|
127
|
+
const collectParagraphCensus = (doc, sourceSeed) => {
|
|
128
|
+
const census = {
|
|
129
|
+
invalidSourceTokens: [],
|
|
130
|
+
missingParaIds: [],
|
|
131
|
+
paragraphs: /* @__PURE__ */ new Map(),
|
|
132
|
+
paraIds: /* @__PURE__ */ new Map(),
|
|
133
|
+
sourceTokens: /* @__PURE__ */ new Map()
|
|
134
|
+
};
|
|
135
|
+
const contractMatchesSeed = sourceSeed?.contract !== null && sourceSeed?.contract !== void 0 && getProseDocumentParagraphPropertySourceContract(doc) === sourceSeed.contract;
|
|
106
136
|
doc.descendants((node, pos) => {
|
|
107
137
|
if (node.type.name !== "paragraph") return true;
|
|
108
|
-
const
|
|
109
|
-
if (!isUsableParaId(id)) missing.push({
|
|
138
|
+
const occurrence = {
|
|
110
139
|
pos,
|
|
111
140
|
attrs: node.attrs
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
141
|
+
};
|
|
142
|
+
census.paragraphs.set(pos, occurrence);
|
|
143
|
+
const id = node.attrs["paraId"];
|
|
144
|
+
if (isUsableParaId(id)) {
|
|
145
|
+
const occurrences = census.paraIds.get(id) ?? [];
|
|
146
|
+
occurrences.push(occurrence);
|
|
147
|
+
census.paraIds.set(id, occurrences);
|
|
148
|
+
} else census.missingParaIds.push(occurrence);
|
|
149
|
+
if (sourceSeed) {
|
|
150
|
+
const token = getProseParagraphPropertySourceToken(node);
|
|
151
|
+
if (token !== null && token !== void 0) if (typeof token !== "string" || !contractMatchesSeed || !sourceSeed.contract || !sourceSeed.tokens.has(token) || !paragraphPropertySourceTokenMatchesContract(token, sourceSeed.contract)) census.invalidSourceTokens.push(occurrence);
|
|
152
|
+
else {
|
|
153
|
+
const occurrences = census.sourceTokens.get(token) ?? [];
|
|
154
|
+
occurrences.push(occurrence);
|
|
155
|
+
census.sourceTokens.set(token, occurrences);
|
|
156
|
+
}
|
|
120
157
|
}
|
|
121
158
|
return false;
|
|
122
159
|
});
|
|
123
|
-
|
|
124
|
-
|
|
160
|
+
return census;
|
|
161
|
+
};
|
|
162
|
+
const collectParaIdUpdatesFromCensus = (census, keeperPositions, deterministicSeed = null) => {
|
|
163
|
+
const needFreshId = [...census.missingParaIds];
|
|
164
|
+
for (const [id, occurrences] of census.paraIds) {
|
|
125
165
|
if (occurrences.length === 1) continue;
|
|
126
166
|
const keeperPos = keeperPositions?.get(id);
|
|
127
|
-
const keeper = occurrences.find((
|
|
167
|
+
const keeper = occurrences.find(({ pos }) => pos === keeperPos) ?? occurrences[0];
|
|
128
168
|
for (const occurrence of occurrences) if (occurrence !== keeper) needFreshId.push(occurrence);
|
|
129
169
|
}
|
|
130
|
-
const taken = new Set(
|
|
170
|
+
const taken = new Set(census.paraIds.keys());
|
|
131
171
|
const updates = [];
|
|
132
172
|
for (const { pos, attrs } of needFreshId) {
|
|
133
173
|
const newId = mintParaId(taken, deterministicSeed, pos);
|
|
@@ -140,9 +180,39 @@ const collectParaIdUpdates = (doc, keeperPositions, deterministicSeed = null) =>
|
|
|
140
180
|
}
|
|
141
181
|
});
|
|
142
182
|
}
|
|
143
|
-
updates.sort((
|
|
183
|
+
updates.sort((left, right) => left.pos - right.pos);
|
|
144
184
|
return updates;
|
|
145
185
|
};
|
|
186
|
+
const collectParaIdUpdates = (doc) => collectParaIdUpdatesFromCensus(collectParagraphCensus(doc));
|
|
187
|
+
const collectParagraphPropertySourceUpdates = (census, keeperPositions, transactions) => {
|
|
188
|
+
const updates = /* @__PURE__ */ new Map();
|
|
189
|
+
for (const { pos } of census.invalidSourceTokens) updates.set(pos, null);
|
|
190
|
+
const explicitTransfers = transactions.flatMap((transaction) => [...getExplicitParagraphPropertySourceTransfers(transaction)]);
|
|
191
|
+
const explicitlySelected = new Set(explicitTransfers.map(({ selectedToken }) => selectedToken).filter((token) => token !== null));
|
|
192
|
+
const explicitlyDisplaced = new Set(explicitTransfers.map(({ displacedToken }) => displacedToken).filter((token) => token !== null));
|
|
193
|
+
const keptPositions = /* @__PURE__ */ new Set();
|
|
194
|
+
const keptTokens = /* @__PURE__ */ new Set();
|
|
195
|
+
for (const [token, occurrences] of census.sourceTokens) {
|
|
196
|
+
const mappedOwner = keeperPositions.get(token);
|
|
197
|
+
const mappedKeeper = mappedOwner?.status === "mapped" ? occurrences.find(({ pos }) => pos === mappedOwner.pos) : void 0;
|
|
198
|
+
const transferredKeeper = !mappedKeeper && explicitlySelected.has(token) && occurrences.length === 1 ? occurrences.at(0) : void 0;
|
|
199
|
+
const detachedKeeper = !mappedKeeper && !transferredKeeper && occurrences.length === 1 && (mappedOwner === void 0 || mappedOwner.status === "deleted" && mappedOwner.pos === occurrences.at(0)?.pos) ? occurrences.at(0) : void 0;
|
|
200
|
+
const keeper = mappedKeeper ?? transferredKeeper ?? detachedKeeper;
|
|
201
|
+
if (keeper) {
|
|
202
|
+
keptPositions.add(keeper.pos);
|
|
203
|
+
keptTokens.add(token);
|
|
204
|
+
}
|
|
205
|
+
for (const occurrence of occurrences) if (occurrence !== keeper) updates.set(occurrence.pos, null);
|
|
206
|
+
}
|
|
207
|
+
for (const [token, mappedOwner] of keeperPositions) {
|
|
208
|
+
if (mappedOwner.status !== "mapped" || keptTokens.has(token) || explicitlyDisplaced.has(token) || keptPositions.has(mappedOwner.pos) || !census.paragraphs.has(mappedOwner.pos)) continue;
|
|
209
|
+
updates.set(mappedOwner.pos, token);
|
|
210
|
+
}
|
|
211
|
+
return [...updates].map(([pos, token]) => ({
|
|
212
|
+
pos,
|
|
213
|
+
token
|
|
214
|
+
})).sort((left, right) => left.pos - right.pos);
|
|
215
|
+
};
|
|
146
216
|
const collectInitialParaIds = (doc) => {
|
|
147
217
|
let needsRewrite = false;
|
|
148
218
|
const taken = /* @__PURE__ */ new Set();
|
|
@@ -215,12 +285,20 @@ const ensureParaIdsInState = (state) => {
|
|
|
215
285
|
};
|
|
216
286
|
const createParaIdAllocatorPlugin = () => new Plugin({
|
|
217
287
|
key: paraIdAllocatorKey,
|
|
288
|
+
state: {
|
|
289
|
+
init: (_config, state) => collectParagraphPropertySourceSeed(state.doc),
|
|
290
|
+
apply: (_transaction, seed) => seed
|
|
291
|
+
},
|
|
218
292
|
appendTransaction(transactions, oldState, newState) {
|
|
219
293
|
if (!transactions.some((t) => t.docChanged)) return null;
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
const
|
|
223
|
-
|
|
294
|
+
const paragraphSourceSeed = paraIdAllocatorKey.getState(oldState);
|
|
295
|
+
if (!paragraphSourceSeed) panic("ParaId allocator lost its paragraph-property source seed");
|
|
296
|
+
const keeperPositions = mapParagraphKeepers(oldState.doc, transactions, paragraphSourceSeed);
|
|
297
|
+
const deterministicSeed = transactions.map((transaction) => transaction.getMeta(deterministicParaIdSeedKey)).find((value) => typeof value === "string") ?? null;
|
|
298
|
+
const census = collectParagraphCensus(newState.doc, paragraphSourceSeed);
|
|
299
|
+
const updates = collectParaIdUpdatesFromCensus(census, keeperPositions.paraIds, deterministicSeed);
|
|
300
|
+
const paragraphSourceUpdates = collectParagraphPropertySourceUpdates(census, keeperPositions.sourceTokens, transactions);
|
|
301
|
+
if (updates.length === 0 && paragraphSourceUpdates.length === 0) return null;
|
|
224
302
|
const tr = newState.tr;
|
|
225
303
|
for (const u of updates) setProseParagraphMarkupWithPropertySource({
|
|
226
304
|
attrs: u.attrs,
|
|
@@ -228,6 +306,19 @@ const createParaIdAllocatorPlugin = () => new Plugin({
|
|
|
228
306
|
pos: u.pos,
|
|
229
307
|
transaction: tr
|
|
230
308
|
});
|
|
309
|
+
for (const { pos, token } of paragraphSourceUpdates) {
|
|
310
|
+
const paragraph = tr.doc.nodeAt(pos);
|
|
311
|
+
if (!paragraph || paragraph.type.name !== "paragraph") panic("Paragraph-property token update lost its paragraph");
|
|
312
|
+
setProseParagraphMarkupWithPropertySource({
|
|
313
|
+
attrs: {
|
|
314
|
+
...paragraph.attrs,
|
|
315
|
+
[PROSE_PARAGRAPH_SOURCE_TOKEN_ATTR]: token
|
|
316
|
+
},
|
|
317
|
+
ownership: "preserve",
|
|
318
|
+
pos,
|
|
319
|
+
transaction: tr
|
|
320
|
+
});
|
|
321
|
+
}
|
|
231
322
|
ignoreTrackedChanges(tr);
|
|
232
323
|
tr.setMeta(paraIdAllocatorKey, "allocated");
|
|
233
324
|
tr.setMeta("addToHistory", false);
|
|
@@ -22,6 +22,8 @@ type TextBoxAttrs = {
|
|
|
22
22
|
outlineColor?: string;
|
|
23
23
|
/** Outline dash style, or `"none"` for an explicit no-outline. */
|
|
24
24
|
outlineStyle?: OutlineStyleAttr;
|
|
25
|
+
/** DrawingML rotation and/or flips, serialized as CSS transform functions. */
|
|
26
|
+
transform?: string;
|
|
25
27
|
/** Internal margin top in pixels */
|
|
26
28
|
marginTop?: number;
|
|
27
29
|
/** Internal margin bottom in pixels */
|
|
@@ -42,6 +42,7 @@ const TextBoxExtension = createNodeExtension({
|
|
|
42
42
|
outlineWidth: { default: null },
|
|
43
43
|
outlineColor: { default: null },
|
|
44
44
|
outlineStyle: { default: null },
|
|
45
|
+
transform: { default: null },
|
|
45
46
|
marginTop: { default: 4 },
|
|
46
47
|
marginBottom: { default: 4 },
|
|
47
48
|
marginLeft: { default: 7 },
|
|
@@ -82,6 +83,7 @@ const TextBoxExtension = createNodeExtension({
|
|
|
82
83
|
...d["outlineWidth"] ? { outlineWidth: Number(d["outlineWidth"]) } : {},
|
|
83
84
|
...d["outlineColor"] ? { outlineColor: d["outlineColor"] } : {},
|
|
84
85
|
...d["outlineStyle"] ? { outlineStyle: d["outlineStyle"] } : {},
|
|
86
|
+
...d["transform"] ? { transform: d["transform"] } : {},
|
|
85
87
|
...d["marginTop"] ? { marginTop: Number(d["marginTop"]) } : {},
|
|
86
88
|
...d["marginBottom"] ? { marginBottom: Number(d["marginBottom"]) } : {},
|
|
87
89
|
...d["marginLeft"] ? { marginLeft: Number(d["marginLeft"]) } : {},
|
|
@@ -111,6 +113,7 @@ const TextBoxExtension = createNodeExtension({
|
|
|
111
113
|
if (attrs.outlineWidth) domAttrs["data-outline-width"] = String(attrs.outlineWidth);
|
|
112
114
|
if (attrs.outlineColor) domAttrs["data-outline-color"] = attrs.outlineColor;
|
|
113
115
|
if (attrs.outlineStyle) domAttrs["data-outline-style"] = attrs.outlineStyle;
|
|
116
|
+
if (attrs.transform) domAttrs["data-transform"] = attrs.transform;
|
|
114
117
|
if (typeof attrs.marginTop === "number") domAttrs["data-margin-top"] = String(attrs.marginTop);
|
|
115
118
|
if (typeof attrs.marginBottom === "number") domAttrs["data-margin-bottom"] = String(attrs.marginBottom);
|
|
116
119
|
if (typeof attrs.marginLeft === "number") domAttrs["data-margin-left"] = String(attrs.marginLeft);
|
|
@@ -158,6 +161,10 @@ const TextBoxExtension = createNodeExtension({
|
|
|
158
161
|
styles.push("box-sizing: border-box");
|
|
159
162
|
styles.push("overflow: hidden");
|
|
160
163
|
styles.push("position: relative");
|
|
164
|
+
if (attrs.transform) {
|
|
165
|
+
styles.push(`transform: ${attrs.transform}`);
|
|
166
|
+
styles.push("transform-origin: center center");
|
|
167
|
+
}
|
|
161
168
|
domAttrs["style"] = styles.join("; ");
|
|
162
169
|
return [
|
|
163
170
|
"div",
|
|
@@ -507,6 +507,8 @@ type TextBoxAttrs = {
|
|
|
507
507
|
outlineColor?: string;
|
|
508
508
|
/** Outline dash style, or `"none"` for an explicit no-outline. */
|
|
509
509
|
outlineStyle?: OutlineStyleAttr;
|
|
510
|
+
/** DrawingML rotation and/or flips, serialized as CSS transform functions. */
|
|
511
|
+
transform?: string;
|
|
510
512
|
/** Internal margin top in pixels */
|
|
511
513
|
marginTop?: number;
|
|
512
514
|
/** Internal margin bottom in pixels */
|
|
@@ -765,7 +767,7 @@ type TableCellAttrs = {
|
|
|
765
767
|
/** Preserve a DOCX vMerge restart even when PM cannot model it as a rowspan. */
|
|
766
768
|
_preserveVMergeRestart?: boolean;
|
|
767
769
|
/** Original DOCX vMerge continuation cells skipped into this PM rowspan. */
|
|
768
|
-
_docxVMergeContinuationCells?:
|
|
770
|
+
_docxVMergeContinuationCells?: unknown;
|
|
769
771
|
};
|
|
770
772
|
//#endregion
|
|
771
773
|
export { BlockSdtAttrs, BookmarkBoundaryAttrs, FieldAttrs, HardBreakAttrs, ImageAttrs, ImagePositionAttrs, MathAttrs, PageBreakRunAttrs, ParagraphAttrs, ParagraphPropertyChangeAttrs, SdtAttrs, ShapeAttrs, SuggestedStructuralMarker, SymbolAttrs, TabAttrs, TableAttrs, TableCellAttrs, TableRowAttrs, TextBoxAnchorAttrs, TextBoxAttrs };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Node } from "prosemirror-model";
|
|
2
|
+
import * as Y from "yjs";
|
|
3
|
+
//#region src/prosemirror/yjsParagraphSourceContract.d.ts
|
|
4
|
+
declare const proseDocumentParagraphSourceContract: (document: Node) => string | null;
|
|
5
|
+
declare const writeYjsParagraphSourceContract: (ydoc: Y.Doc, document: Node) => void;
|
|
6
|
+
declare const readYjsParagraphSourceContract: (ydoc: Y.Doc) => string | null;
|
|
7
|
+
declare const withParagraphSourceContract: (document: Node, contract: string) => Node;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { proseDocumentParagraphSourceContract, readYjsParagraphSourceContract, withParagraphSourceContract, writeYjsParagraphSourceContract };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { PROSE_PARAGRAPH_SOURCE_CONTRACT_ATTR, getProseDocumentParagraphPropertySourceContract } from "../docx/paragraphPropertySource.js";
|
|
2
|
+
import { panic } from "better-result";
|
|
3
|
+
//#region src/prosemirror/yjsParagraphSourceContract.ts
|
|
4
|
+
const FOLIO_YJS_METADATA_MAP_NAME = "folio:document-metadata";
|
|
5
|
+
const PARAGRAPH_SOURCE_CONTRACT_KEY = "paragraphSourceContract";
|
|
6
|
+
const proseDocumentParagraphSourceContract = (document) => {
|
|
7
|
+
return getProseDocumentParagraphPropertySourceContract(document);
|
|
8
|
+
};
|
|
9
|
+
const writeYjsParagraphSourceContract = (ydoc, document) => {
|
|
10
|
+
const contract = proseDocumentParagraphSourceContract(document);
|
|
11
|
+
if (!contract) panic("Cannot seed collaboration without a paragraph-property source contract");
|
|
12
|
+
ydoc.getMap(FOLIO_YJS_METADATA_MAP_NAME).set(PARAGRAPH_SOURCE_CONTRACT_KEY, contract);
|
|
13
|
+
};
|
|
14
|
+
const readYjsParagraphSourceContract = (ydoc) => {
|
|
15
|
+
const contract = ydoc.getMap(FOLIO_YJS_METADATA_MAP_NAME).get(PARAGRAPH_SOURCE_CONTRACT_KEY);
|
|
16
|
+
return typeof contract === "string" ? contract : null;
|
|
17
|
+
};
|
|
18
|
+
const withParagraphSourceContract = (document, contract) => {
|
|
19
|
+
if (document.type.name !== "doc") panic("A paragraph-property source contract can only attach to a document node");
|
|
20
|
+
return document.type.create({
|
|
21
|
+
...document.attrs,
|
|
22
|
+
[PROSE_PARAGRAPH_SOURCE_CONTRACT_ATTR]: contract
|
|
23
|
+
}, document.content, document.marks);
|
|
24
|
+
};
|
|
25
|
+
//#endregion
|
|
26
|
+
export { proseDocumentParagraphSourceContract, readYjsParagraphSourceContract, withParagraphSourceContract, writeYjsParagraphSourceContract };
|
|
@@ -5,7 +5,11 @@ type BoundingBox = {
|
|
|
5
5
|
height: number;
|
|
6
6
|
};
|
|
7
7
|
declare function parseRotationDegrees(transform: string | undefined): number;
|
|
8
|
+
/** Whether a DrawingML/CSS transform reflects around the vertical centre line. */
|
|
9
|
+
declare function hasHorizontalFlip(transform: string | undefined): boolean;
|
|
10
|
+
/** Whether a DrawingML/CSS transform reflects around the horizontal centre line. */
|
|
11
|
+
declare function hasVerticalFlip(transform: string | undefined): boolean;
|
|
8
12
|
declare function rotatedBoundingBox(w: number, h: number, deg: number): BoundingBox;
|
|
9
13
|
declare function inlineImageBoundingBox(run: ImageRun): BoundingBox;
|
|
10
14
|
//#endregion
|
|
11
|
-
export { BoundingBox, inlineImageBoundingBox, parseRotationDegrees, rotatedBoundingBox };
|
|
15
|
+
export { BoundingBox, hasHorizontalFlip, hasVerticalFlip, inlineImageBoundingBox, parseRotationDegrees, rotatedBoundingBox };
|
|
@@ -7,6 +7,14 @@ function parseRotationDegrees(transform) {
|
|
|
7
7
|
if (!Number.isFinite(raw)) return 0;
|
|
8
8
|
return (raw % 360 + 360) % 360;
|
|
9
9
|
}
|
|
10
|
+
/** Whether a DrawingML/CSS transform reflects around the vertical centre line. */
|
|
11
|
+
function hasHorizontalFlip(transform) {
|
|
12
|
+
return /scaleX\(\s*-1\s*\)/iu.test(transform ?? "");
|
|
13
|
+
}
|
|
14
|
+
/** Whether a DrawingML/CSS transform reflects around the horizontal centre line. */
|
|
15
|
+
function hasVerticalFlip(transform) {
|
|
16
|
+
return /scaleY\(\s*-1\s*\)/iu.test(transform ?? "");
|
|
17
|
+
}
|
|
10
18
|
function rotatedBoundingBox(w, h, deg) {
|
|
11
19
|
if (deg === 0 || deg === 180) return {
|
|
12
20
|
width: w,
|
|
@@ -33,4 +41,4 @@ function inlineImageBoundingBox(run) {
|
|
|
33
41
|
return rotatedBoundingBox(run.width, run.height, rotation);
|
|
34
42
|
}
|
|
35
43
|
//#endregion
|
|
36
|
-
export { inlineImageBoundingBox, parseRotationDegrees, rotatedBoundingBox };
|
|
44
|
+
export { hasHorizontalFlip, hasVerticalFlip, inlineImageBoundingBox, parseRotationDegrees, rotatedBoundingBox };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stll/folio-core",
|
|
3
|
-
"version": "0.37.
|
|
3
|
+
"version": "0.37.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",
|
|
@@ -121,7 +121,7 @@
|
|
|
121
121
|
"perf": "bun scripts/profile-editor.ts"
|
|
122
122
|
},
|
|
123
123
|
"dependencies": {
|
|
124
|
-
"@stll/docx-core": "^0.19.
|
|
124
|
+
"@stll/docx-core": "^0.19.4",
|
|
125
125
|
"@stll/docx-utils": "^0.1.0",
|
|
126
126
|
"@stll/template-conditions": ">=0.4.0 <1.0.0",
|
|
127
127
|
"better-result": "3.0.1",
|