@stll/folio-core 0.33.2 → 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.
- package/dist/ai-edits/apply.js +137 -23
- package/dist/ai-edits/snapshot.js +24 -2
- package/dist/ai-edits/types.d.ts +6 -6
- package/dist/compare/formatting.d.ts +1 -1
- package/dist/compare/formatting.js +38 -9
- package/dist/compare/verification.js +18 -1
- package/dist/controller/headerFooterEditorManager.js +11 -9
- package/dist/controller/layoutPipeline.js +24 -3
- package/dist/display-list/build/watermarkPrimitives.js +15 -3
- package/dist/document-operations.js +30 -3
- package/dist/docx/headerFooterParser.js +8 -14
- package/dist/docx/paragraphParser.js +45 -0
- package/dist/docx/serializer/headerFooterSerializer.js +21 -2
- package/dist/docx/serializer/paragraphSerializer.d.ts +1 -1
- package/dist/docx/serializer/paragraphSerializer.js +19 -9
- package/dist/docx/settingsParser.js +3 -0
- package/dist/docx/watermarkParser.d.ts +2 -4
- package/dist/docx/watermarkParser.js +4 -6
- package/dist/headless-layout.js +14 -2
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +2 -2
- package/dist/layout-bridge/convert/footnoteLayout.js +23 -10
- package/dist/layout-bridge/convert/headerFooterLayout.js +13 -2
- package/dist/layout-bridge/convert/toFlowBlocks.js +96 -13
- package/dist/layout-engine/index.js +11 -4
- package/dist/layout-engine/justifiedLineFit.d.ts +4 -4
- package/dist/layout-engine/justifiedLineFit.js +4 -4
- package/dist/layout-engine/measure/lineBreakProvider.js +1 -0
- package/dist/layout-engine/measure/measureBlocks.js +1 -1
- package/dist/layout-engine/measure/measureParagraph.js +29 -29
- package/dist/layout-painter/renderPage.js +6 -1
- package/dist/layout-painter/renderParagraph.js +18 -8
- package/dist/layout-painter/renderWatermark.js +11 -4
- package/dist/prosemirror/attrs/index.js +11 -0
- package/dist/prosemirror/commands/comments.js +22 -2
- package/dist/prosemirror/conversion/fromProseDoc.js +32 -5
- package/dist/prosemirror/conversion/toProseDoc.js +49 -11
- package/dist/prosemirror/extensions/core/DocExtension.js +7 -1
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +1 -0
- package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.js +1 -0
- package/dist/prosemirror/schema/marks.d.ts +2 -8
- package/dist/utils/fontResolver.js +51 -0
- package/dist/utils/formatToStyle.js +41 -1
- package/dist/watermark/index.js +7 -0
- package/package.json +2 -2
|
@@ -223,6 +223,7 @@ const paragraphNodeSpec = {
|
|
|
223
223
|
pageBreakBefore: { default: null },
|
|
224
224
|
renderedPageBreakBefore: { default: null },
|
|
225
225
|
_pageBreakCarrier: { default: null },
|
|
226
|
+
_detachedWatermarkHost: { default: null },
|
|
226
227
|
_trailingPageBreak: { default: null },
|
|
227
228
|
keepNext: { default: null },
|
|
228
229
|
keepLines: { default: null },
|
|
@@ -50,6 +50,7 @@ const RunFormattingOverrideExtension = createMarkExtension({
|
|
|
50
50
|
schemaMarkName: "runFormattingOverride",
|
|
51
51
|
markSpec: {
|
|
52
52
|
attrs: {
|
|
53
|
+
directFontProperties: { default: null },
|
|
53
54
|
bold: { default: null },
|
|
54
55
|
italic: { default: null },
|
|
55
56
|
underline: { default: null },
|
|
@@ -121,17 +121,11 @@ type RunPropertyChangeMarkAttrs = {
|
|
|
121
121
|
provenance: TrackedChangeProvenance;
|
|
122
122
|
suggestionId?: string;
|
|
123
123
|
};
|
|
124
|
-
type RunFormattingOverrideAttrs =
|
|
124
|
+
type RunFormattingOverrideAttrs = Partial<Record<"bold" | "boldCs" | "cs" | "italic" | "italicCs" | "strike" | "allCaps" | "smallCaps" | "hidden" | "emboss" | "imprint" | "shadow" | "outline", boolean>> & {
|
|
125
|
+
directFontProperties?: readonly ("fontFamily" | "fontSize" | "color")[];
|
|
125
126
|
doubleStrike?: false;
|
|
126
127
|
rtl?: false;
|
|
127
|
-
/** Independent complex-script weight (`w:bCs`). */
|
|
128
|
-
boldCs?: boolean;
|
|
129
|
-
/** Force complex-script formatting for the full run (`w:cs`). */
|
|
130
|
-
cs?: boolean;
|
|
131
|
-
/** Independent complex-script size in half-points (`w:szCs`). */
|
|
132
128
|
fontSizeCs?: number;
|
|
133
|
-
/** Independent complex-script slant (`w:iCs`). */
|
|
134
|
-
italicCs?: boolean;
|
|
135
129
|
underline?: "none";
|
|
136
130
|
};
|
|
137
131
|
/**
|
|
@@ -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",
|
|
@@ -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
|
/**
|
package/dist/watermark/index.js
CHANGED
|
@@ -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.
|
|
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.
|
|
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",
|