@stll/folio-core 0.28.0 → 0.28.1
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/docx/styleParser.js +15 -14
- package/dist/layout-bridge/convert/toFlowBlocks.js +74 -23
- package/dist/layout-engine/footnoteColumnReflow.d.ts +15 -0
- package/dist/layout-engine/footnoteColumnReflow.js +74 -0
- package/dist/layout-engine/index.d.ts +3 -5
- package/dist/layout-engine/index.js +36 -15
- package/dist/layout-engine/measure/cache.d.ts +1 -1
- package/dist/layout-engine/measure/cache.js +11 -2
- package/dist/layout-engine/measure/listMarkerWidth.d.ts +3 -1
- package/dist/layout-engine/measure/listMarkerWidth.js +6 -4
- package/dist/layout-engine/paginator.d.ts +6 -0
- package/dist/layout-engine/paginator.js +30 -11
- package/dist/layout-engine/types.d.ts +11 -6
- package/dist/prosemirror/attrs/index.js +3 -2
- package/dist/prosemirror/commands/formatPainter.js +45 -1
- package/dist/prosemirror/conversion/fromProseDoc.d.ts +4 -1
- package/dist/prosemirror/conversion/fromProseDoc.js +59 -44
- package/dist/prosemirror/conversion/toProseDoc.d.ts +4 -1
- package/dist/prosemirror/conversion/toProseDoc.js +156 -33
- package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.js +22 -22
- package/dist/prosemirror/schema/marks.d.ts +3 -1
- package/dist/prosemirror/styles/styleResolver.d.ts +0 -1
- package/dist/prosemirror/styles/styleResolver.js +22 -29
- package/dist/prosemirror/styles/styleToggleCascade.d.ts +37 -0
- package/dist/prosemirror/styles/styleToggleCascade.js +52 -0
- package/dist/utils/textFormattingMerge.d.ts +9 -1
- package/dist/utils/textFormattingMerge.js +32 -1
- package/package.json +1 -1
|
@@ -8,6 +8,7 @@ import { setAutospacingBaseValue } from "../autospacingBase.js";
|
|
|
8
8
|
import { buildRunFormattingOverrideAttrs } from "../extensions/marks/RunFormattingOverrideExtension.js";
|
|
9
9
|
import { directionFromBidi } from "../paragraphDirection.js";
|
|
10
10
|
import { schema } from "../schema/index.js";
|
|
11
|
+
import { cascadeStyleTextFormatting } from "../styles/styleToggleCascade.js";
|
|
11
12
|
import { assertValidProseMirrorDocument } from "../validation.js";
|
|
12
13
|
import { resolveEffectiveTableCellFormatting } from "./effectiveTableCellFormatting.js";
|
|
13
14
|
import { marksToTextFormatting } from "./fromProseDoc.js";
|
|
@@ -144,22 +145,66 @@ function convertParagraph(paragraph, styleResolver, nextHyperlinkInstanceIndex,
|
|
|
144
145
|
emitInlineNodes([node]);
|
|
145
146
|
};
|
|
146
147
|
let styleRunFormatting;
|
|
148
|
+
let paragraphStyleRunFormatting;
|
|
147
149
|
let paragraphStyleFontFamily;
|
|
148
150
|
if (styleResolver) {
|
|
149
151
|
styleRunFormatting = styleResolver.resolveParagraphStyle(paragraph.formatting?.styleId).runFormatting;
|
|
152
|
+
const paragraphStyle = paragraph.formatting?.styleId ? styleResolver.getStyle(paragraph.formatting.styleId) ?? styleResolver.getDefaultParagraphStyle() : styleResolver.getDefaultParagraphStyle();
|
|
153
|
+
paragraphStyleRunFormatting = paragraphStyle?.type === "paragraph" ? paragraphStyle.rPr : void 0;
|
|
150
154
|
paragraphStyleFontFamily = resolveParagraphStyleFontFamily(paragraph.formatting?.styleId, styleResolver);
|
|
151
155
|
}
|
|
152
156
|
const paragraphRunFormatting = resolveRunFormattingWithoutDefaults(paragraph.formatting?.runProperties, styleResolver);
|
|
153
157
|
let inheritableParagraphRunFormatting;
|
|
154
158
|
if (paragraphRunFormatting && !isTocParagraph) inheritableParagraphRunFormatting = stripParagraphMarkFormattingForBodyRuns(paragraphRunFormatting);
|
|
155
|
-
|
|
159
|
+
const orderedToggleFormatting = cascadeStyleTextFormatting([
|
|
160
|
+
{
|
|
161
|
+
formatting: styleResolver?.getDocDefaults()?.rPr,
|
|
162
|
+
type: "defaults"
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
formatting: extraRunFormatting,
|
|
166
|
+
type: "style"
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
formatting: paragraphStyleRunFormatting,
|
|
170
|
+
type: "style"
|
|
171
|
+
}
|
|
172
|
+
], { ordinaryFormatting: mergeTextFormatting(styleRunFormatting, extraRunFormatting) });
|
|
173
|
+
let baseRunFormatting = orderedToggleFormatting.formatting;
|
|
156
174
|
if (paragraphStyleFontFamily) baseRunFormatting = mergeTextFormatting(baseRunFormatting, { fontFamily: paragraphStyleFontFamily });
|
|
157
175
|
const paragraphMarkPrecedesStyle = paragraph.formatting?.styleId !== void 0;
|
|
158
|
-
const
|
|
176
|
+
const ordinaryDefaultRunFormatting = paragraphMarkPrecedesStyle ? mergeTextFormatting(inheritableParagraphRunFormatting, baseRunFormatting) : mergeTextFormatting(baseRunFormatting, inheritableParagraphRunFormatting);
|
|
177
|
+
const defaultToggleCascade = paragraphMarkPrecedesStyle ? cascadeStyleTextFormatting([{
|
|
178
|
+
cascade: orderedToggleFormatting,
|
|
179
|
+
type: "carried"
|
|
180
|
+
}], { ordinaryFormatting: ordinaryDefaultRunFormatting }) : cascadeStyleTextFormatting([{
|
|
181
|
+
cascade: orderedToggleFormatting,
|
|
182
|
+
type: "carried"
|
|
183
|
+
}, {
|
|
184
|
+
formatting: inheritableParagraphRunFormatting,
|
|
185
|
+
type: "direct"
|
|
186
|
+
}], { ordinaryFormatting: ordinaryDefaultRunFormatting });
|
|
187
|
+
const defaultRunFormatting = defaultToggleCascade.formatting;
|
|
159
188
|
const getInheritedRunFormatting = (formatting, fieldType) => {
|
|
160
|
-
if (fieldType === "TOC") return
|
|
161
|
-
|
|
162
|
-
|
|
189
|
+
if (fieldType === "TOC") return {
|
|
190
|
+
formatting: hasDirectRunFormatting(formatting) ? suppressParagraphMarkFormatting(baseRunFormatting, void 0, formatting) : baseRunFormatting,
|
|
191
|
+
toggleCascade: orderedToggleFormatting
|
|
192
|
+
};
|
|
193
|
+
if (!(hasDirectRunFormatting(formatting) || formatting?.styleId !== void 0)) return {
|
|
194
|
+
formatting: defaultRunFormatting,
|
|
195
|
+
toggleCascade: defaultToggleCascade
|
|
196
|
+
};
|
|
197
|
+
const suppressedFormatting = suppressParagraphMarkFormatting(baseRunFormatting, inheritableParagraphRunFormatting, formatting, paragraphMarkPrecedesStyle);
|
|
198
|
+
const paragraphMarkOverrides = getParagraphMarkSuppressionOverrides({
|
|
199
|
+
directFormatting: formatting,
|
|
200
|
+
paragraphMarkFormatting: inheritableParagraphRunFormatting,
|
|
201
|
+
suppressedFormatting
|
|
202
|
+
});
|
|
203
|
+
return {
|
|
204
|
+
formatting: suppressedFormatting,
|
|
205
|
+
...paragraphMarkOverrides ? { paragraphMarkOverrides } : {},
|
|
206
|
+
toggleCascade: orderedToggleFormatting
|
|
207
|
+
};
|
|
163
208
|
};
|
|
164
209
|
const emitTrackedChange = (change, markType, moveKind) => {
|
|
165
210
|
emitInlineNodes(convertTrackedChange(change, markType, nextHyperlinkInstanceIndex, getInheritedRunFormatting, styleResolver, moveKind, textBoxAnchors));
|
|
@@ -499,27 +544,37 @@ function stripParagraphMarkFormattingForBodyRuns(formatting) {
|
|
|
499
544
|
const { fontFamily: _fontFamily, ...bodyRunFormatting } = paragraphMarkFormatting;
|
|
500
545
|
return Object.keys(bodyRunFormatting).length > 0 ? bodyRunFormatting : void 0;
|
|
501
546
|
}
|
|
547
|
+
const PARAGRAPH_MARK_BOOLEAN_KEYS = [
|
|
548
|
+
"bold",
|
|
549
|
+
"italic",
|
|
550
|
+
"strike",
|
|
551
|
+
"doubleStrike",
|
|
552
|
+
"allCaps",
|
|
553
|
+
"smallCaps",
|
|
554
|
+
"hidden",
|
|
555
|
+
"emboss",
|
|
556
|
+
"imprint",
|
|
557
|
+
"shadow",
|
|
558
|
+
"outline",
|
|
559
|
+
"rtl"
|
|
560
|
+
];
|
|
502
561
|
function suppressParagraphMarkFormatting(base, paragraphMark, direct, paragraphMarkPrecedesStyle = false) {
|
|
503
562
|
if (!paragraphMark) return base;
|
|
504
563
|
const result = (paragraphMarkPrecedesStyle ? mergeTextFormatting(paragraphMark, base) : mergeTextFormatting(base, paragraphMark)) ?? {};
|
|
505
|
-
suppressBooleanParagraphMark(result, base, paragraphMark, direct,
|
|
506
|
-
suppressBooleanParagraphMark(result, base, paragraphMark, direct, "italic");
|
|
507
|
-
suppressBooleanParagraphMark(result, base, paragraphMark, direct, "strike");
|
|
508
|
-
suppressBooleanParagraphMark(result, base, paragraphMark, direct, "doubleStrike");
|
|
509
|
-
suppressBooleanParagraphMark(result, base, paragraphMark, direct, "allCaps");
|
|
510
|
-
suppressBooleanParagraphMark(result, base, paragraphMark, direct, "smallCaps");
|
|
511
|
-
suppressBooleanParagraphMark(result, base, paragraphMark, direct, "hidden");
|
|
512
|
-
suppressBooleanParagraphMark(result, base, paragraphMark, direct, "emboss");
|
|
513
|
-
suppressBooleanParagraphMark(result, base, paragraphMark, direct, "imprint");
|
|
514
|
-
suppressBooleanParagraphMark(result, base, paragraphMark, direct, "shadow");
|
|
515
|
-
suppressBooleanParagraphMark(result, base, paragraphMark, direct, "outline");
|
|
516
|
-
suppressBooleanParagraphMark(result, base, paragraphMark, direct, "rtl");
|
|
564
|
+
for (const key of PARAGRAPH_MARK_BOOLEAN_KEYS) suppressBooleanParagraphMark(result, base, paragraphMark, direct, key);
|
|
517
565
|
if (paragraphMark.fontSize !== void 0 && direct?.fontSize === void 0 && base?.fontSize !== void 0) result.fontSize = base.fontSize;
|
|
518
566
|
if (paragraphMark.fontSizeCs !== void 0 && direct?.fontSizeCs === void 0 && base?.fontSizeCs !== void 0) result.fontSizeCs = base.fontSizeCs;
|
|
519
567
|
if (paragraphMark.underline !== void 0 && direct?.underline === void 0) result.underline = { style: "none" };
|
|
520
568
|
if (paragraphMark.spacing !== void 0 && direct?.spacing === void 0) result.spacing = 0;
|
|
521
569
|
return Object.keys(result).length > 0 ? result : void 0;
|
|
522
570
|
}
|
|
571
|
+
function getParagraphMarkSuppressionOverrides({ directFormatting, paragraphMarkFormatting, suppressedFormatting }) {
|
|
572
|
+
if (!paragraphMarkFormatting) return;
|
|
573
|
+
const overrides = {};
|
|
574
|
+
for (const key of PARAGRAPH_MARK_BOOLEAN_KEYS) if (paragraphMarkFormatting[key] !== void 0 && directFormatting?.[key] === void 0 && suppressedFormatting?.[key] === false) overrides[key] = false;
|
|
575
|
+
if (paragraphMarkFormatting.underline !== void 0 && directFormatting?.underline === void 0 && suppressedFormatting?.underline?.style === "none") overrides.underline = { style: "none" };
|
|
576
|
+
return Object.keys(overrides).length > 0 ? overrides : void 0;
|
|
577
|
+
}
|
|
523
578
|
function suppressBooleanParagraphMark(result, base, paragraphMark, direct, key) {
|
|
524
579
|
if (paragraphMark[key] === void 0 || direct?.[key] !== void 0) return;
|
|
525
580
|
result[key] = base?.[key] ?? false;
|
|
@@ -536,15 +591,45 @@ function resolveTextFormatting(formatting, styleResolver) {
|
|
|
536
591
|
*/
|
|
537
592
|
function resolveRunFormattingWithoutDefaults(formatting, styleResolver) {
|
|
538
593
|
if (!formatting || !styleResolver) return formatting;
|
|
539
|
-
return
|
|
594
|
+
return cascadeStyleTextFormatting([{
|
|
595
|
+
formatting: formatting.styleId ? styleResolver.getRunStyleOwnProperties(formatting.styleId) : void 0,
|
|
596
|
+
type: "style"
|
|
597
|
+
}, {
|
|
598
|
+
formatting,
|
|
599
|
+
type: "direct"
|
|
600
|
+
}]).formatting;
|
|
540
601
|
}
|
|
541
602
|
function resolveParagraphDefaultTextFormatting(styleId, formatting, styleResolver, options = {}) {
|
|
542
603
|
const style = styleId ? styleResolver.getStyle(styleId) ?? styleResolver.getDefaultParagraphStyle() : styleResolver.getDefaultParagraphStyle();
|
|
543
604
|
const paragraphStyleRpr = style?.type === "paragraph" ? style.rPr : void 0;
|
|
544
605
|
const rawParagraphMarkRpr = options.includeParagraphMarkRunProperties === false ? void 0 : formatting?.runProperties;
|
|
545
606
|
const paragraphRunProperties = rawParagraphMarkRpr ? stripParagraphMarkOnlyFormatting(resolveRunFormattingWithoutDefaults(rawParagraphMarkRpr, styleResolver) ?? {}) : void 0;
|
|
546
|
-
const
|
|
547
|
-
|
|
607
|
+
const orderedBodyToggleFormatting = cascadeStyleTextFormatting([
|
|
608
|
+
{
|
|
609
|
+
formatting: styleResolver.getDocDefaults()?.rPr,
|
|
610
|
+
type: "defaults"
|
|
611
|
+
},
|
|
612
|
+
{
|
|
613
|
+
formatting: paragraphStyleRpr,
|
|
614
|
+
type: "style"
|
|
615
|
+
},
|
|
616
|
+
{
|
|
617
|
+
formatting: styleResolver.getDefaultCharacterStyle()?.rPr,
|
|
618
|
+
type: "style"
|
|
619
|
+
}
|
|
620
|
+
], { ordinaryFormatting: mergeTextFormatting(mergeTextFormatting(styleResolver.getDocDefaults()?.rPr, styleResolver.getDefaultCharacterStyle()?.rPr), paragraphStyleRpr) });
|
|
621
|
+
const bodyRunDefaults = orderedBodyToggleFormatting.formatting;
|
|
622
|
+
if (styleId !== void 0) return cascadeStyleTextFormatting([{
|
|
623
|
+
cascade: orderedBodyToggleFormatting,
|
|
624
|
+
type: "carried"
|
|
625
|
+
}], { ordinaryFormatting: mergeTextFormatting(paragraphRunProperties, bodyRunDefaults) }).formatting;
|
|
626
|
+
return cascadeStyleTextFormatting([{
|
|
627
|
+
cascade: orderedBodyToggleFormatting,
|
|
628
|
+
type: "carried"
|
|
629
|
+
}, {
|
|
630
|
+
formatting: paragraphRunProperties,
|
|
631
|
+
type: "direct"
|
|
632
|
+
}], { ordinaryFormatting: mergeTextFormatting(bodyRunDefaults, paragraphRunProperties) }).formatting;
|
|
548
633
|
}
|
|
549
634
|
function calculateRowSpans(table) {
|
|
550
635
|
const result = /* @__PURE__ */ new Map();
|
|
@@ -1012,11 +1097,11 @@ function convertInlineSdt(sdt, nextHyperlinkInstanceIndex, getInheritedRunFormat
|
|
|
1012
1097
|
* Convert a Run to ProseMirror text nodes with marks
|
|
1013
1098
|
*
|
|
1014
1099
|
* @param run - The run to convert
|
|
1015
|
-
* @param
|
|
1100
|
+
* @param resolvedStyleFormatting - Paragraph formatting and its explicit style-toggle state
|
|
1016
1101
|
*/
|
|
1017
|
-
function convertRun(run,
|
|
1102
|
+
function convertRun(run, resolvedStyleFormatting, styleResolver, textBoxAnchors) {
|
|
1018
1103
|
const nodes = [];
|
|
1019
|
-
const { marks, mergedFormatting } = buildRunMarks(run.formatting,
|
|
1104
|
+
const { marks, mergedFormatting } = buildRunMarks(run.formatting, resolvedStyleFormatting, styleResolver);
|
|
1020
1105
|
if (run.propertyChanges && run.propertyChanges.length > 0) marks.push(schema.mark("runPropertyChange", { changes: [...run.propertyChanges] }));
|
|
1021
1106
|
for (const content of run.content) {
|
|
1022
1107
|
const contentNodes = convertRunContent(content, marks, mergedFormatting, textBoxAnchors);
|
|
@@ -1024,13 +1109,34 @@ function convertRun(run, styleFormatting, styleResolver, textBoxAnchors) {
|
|
|
1024
1109
|
}
|
|
1025
1110
|
return nodes;
|
|
1026
1111
|
}
|
|
1027
|
-
function buildRunMarks(runFormatting,
|
|
1112
|
+
function buildRunMarks(runFormatting, inherited, styleResolver) {
|
|
1028
1113
|
const styleId = runFormatting?.styleId;
|
|
1029
|
-
const
|
|
1030
|
-
|
|
1031
|
-
|
|
1114
|
+
const characterStyleFormatting = styleId ? styleResolver?.getRunStyleOwnProperties(styleId) : styleResolver?.getDefaultCharacterStyle()?.rPr;
|
|
1115
|
+
let ordinaryRunStyleFormatting = inherited.formatting ? { ...inherited.formatting } : {};
|
|
1116
|
+
if (styleId) ordinaryRunStyleFormatting = mergeTextFormatting(inherited.formatting, characterStyleFormatting) ?? {};
|
|
1117
|
+
const cascadedStyleFormatting = cascadeStyleTextFormatting([{
|
|
1118
|
+
cascade: inherited.toggleCascade,
|
|
1119
|
+
type: "carried"
|
|
1120
|
+
}, {
|
|
1121
|
+
formatting: characterStyleFormatting,
|
|
1122
|
+
type: "style"
|
|
1123
|
+
}], { ordinaryFormatting: ordinaryRunStyleFormatting });
|
|
1124
|
+
const runStyleFormatting = cascadedStyleFormatting.formatting;
|
|
1125
|
+
const mergedFormatting = cascadeStyleTextFormatting([{
|
|
1126
|
+
cascade: cascadedStyleFormatting,
|
|
1127
|
+
type: "carried"
|
|
1128
|
+
}, {
|
|
1129
|
+
formatting: runFormatting,
|
|
1130
|
+
type: "direct"
|
|
1131
|
+
}], { ordinaryFormatting: mergeTextFormatting(runStyleFormatting, runFormatting) }).formatting;
|
|
1132
|
+
const marks = textFormattingToMarks(mergedFormatting, { overrideFormatting: getRunFormattingOverrides({
|
|
1133
|
+
directFormatting: runFormatting,
|
|
1134
|
+
effectiveStyleFormatting: runStyleFormatting,
|
|
1135
|
+
hasCharacterStyle: styleId !== void 0,
|
|
1136
|
+
paragraphMarkOverrides: inherited.paragraphMarkOverrides
|
|
1137
|
+
}) });
|
|
1032
1138
|
if (styleId) {
|
|
1033
|
-
const styleRPr =
|
|
1139
|
+
const styleRPr = characterStyleFormatting ? marksToTextFormatting(textFormattingToMarks(characterStyleFormatting)) : void 0;
|
|
1034
1140
|
marks.push(schema.mark("characterStyle", {
|
|
1035
1141
|
styleId,
|
|
1036
1142
|
_styleRPr: styleRPr && Object.keys(styleRPr).length > 0 ? styleRPr : null
|
|
@@ -1041,6 +1147,26 @@ function buildRunMarks(runFormatting, inheritedFormatting, styleResolver) {
|
|
|
1041
1147
|
mergedFormatting
|
|
1042
1148
|
};
|
|
1043
1149
|
}
|
|
1150
|
+
const ORDINARY_STYLE_TOGGLE_KEYS = [
|
|
1151
|
+
"bold",
|
|
1152
|
+
"italic",
|
|
1153
|
+
"strike",
|
|
1154
|
+
"allCaps",
|
|
1155
|
+
"smallCaps",
|
|
1156
|
+
"hidden",
|
|
1157
|
+
"emboss",
|
|
1158
|
+
"imprint",
|
|
1159
|
+
"shadow",
|
|
1160
|
+
"outline"
|
|
1161
|
+
];
|
|
1162
|
+
function getRunFormattingOverrides({ directFormatting, effectiveStyleFormatting, hasCharacterStyle, paragraphMarkOverrides }) {
|
|
1163
|
+
const overrides = mergeTextFormatting(paragraphMarkOverrides, directFormatting);
|
|
1164
|
+
if (!overrides || !directFormatting) return overrides;
|
|
1165
|
+
for (const key of ORDINARY_STYLE_TOGGLE_KEYS) if (directFormatting[key] === true && (!hasCharacterStyle || effectiveStyleFormatting?.[key] !== true)) Reflect.deleteProperty(overrides, key);
|
|
1166
|
+
if (directFormatting.boldCs === true && directFormatting.boldCs === directFormatting.bold && (!hasCharacterStyle || effectiveStyleFormatting?.boldCs === void 0)) Reflect.deleteProperty(overrides, "boldCs");
|
|
1167
|
+
if (directFormatting.italicCs === true && directFormatting.italicCs === directFormatting.italic && (!hasCharacterStyle || effectiveStyleFormatting?.italicCs === void 0)) Reflect.deleteProperty(overrides, "italicCs");
|
|
1168
|
+
return overrides;
|
|
1169
|
+
}
|
|
1044
1170
|
/**
|
|
1045
1171
|
* Convert RunContent to ProseMirror nodes
|
|
1046
1172
|
*/
|
|
@@ -1220,13 +1346,10 @@ function convertHyperlink(hyperlink, { getInheritedRunFormatting, styleResolver,
|
|
|
1220
1346
|
}
|
|
1221
1347
|
return nodes;
|
|
1222
1348
|
}
|
|
1223
|
-
|
|
1224
|
-
* Convert TextFormatting to ProseMirror marks
|
|
1225
|
-
*/
|
|
1226
|
-
function textFormattingToMarks(formatting) {
|
|
1349
|
+
function textFormattingToMarks(formatting, options) {
|
|
1227
1350
|
if (!formatting) return [];
|
|
1228
1351
|
const marks = [];
|
|
1229
|
-
const overrideAttrs = buildRunFormattingOverrideAttrs(formatting);
|
|
1352
|
+
const overrideAttrs = buildRunFormattingOverrideAttrs(options ? options.overrideFormatting : formatting);
|
|
1230
1353
|
if (overrideAttrs) marks.push(schema.mark("runFormattingOverride", overrideAttrs));
|
|
1231
1354
|
if (formatting.bold) marks.push(schema.mark("bold"));
|
|
1232
1355
|
if (formatting.italic) marks.push(schema.mark("italic"));
|
|
@@ -4,38 +4,38 @@ import { createMarkExtension } from "../create.js";
|
|
|
4
4
|
function buildRunFormattingOverrideAttrs(formatting) {
|
|
5
5
|
if (!formatting) return;
|
|
6
6
|
const attrs = {};
|
|
7
|
-
if (formatting.bold
|
|
8
|
-
if (formatting.italic
|
|
7
|
+
if (formatting.bold !== void 0) attrs.bold = formatting.bold;
|
|
8
|
+
if (formatting.italic !== void 0) attrs.italic = formatting.italic;
|
|
9
9
|
if (formatting.underline?.style === "none") attrs.underline = "none";
|
|
10
|
-
if (formatting.strike
|
|
10
|
+
if (formatting.strike !== void 0) attrs.strike = formatting.strike;
|
|
11
11
|
if (formatting.doubleStrike === false) attrs.doubleStrike = false;
|
|
12
|
-
if (formatting.allCaps
|
|
13
|
-
if (formatting.smallCaps
|
|
14
|
-
if (formatting.hidden
|
|
15
|
-
if (formatting.emboss
|
|
16
|
-
if (formatting.imprint
|
|
17
|
-
if (formatting.shadow
|
|
18
|
-
if (formatting.outline
|
|
12
|
+
if (formatting.allCaps !== void 0) attrs.allCaps = formatting.allCaps;
|
|
13
|
+
if (formatting.smallCaps !== void 0) attrs.smallCaps = formatting.smallCaps;
|
|
14
|
+
if (formatting.hidden !== void 0) attrs.hidden = formatting.hidden;
|
|
15
|
+
if (formatting.emboss !== void 0) attrs.emboss = formatting.emboss;
|
|
16
|
+
if (formatting.imprint !== void 0) attrs.imprint = formatting.imprint;
|
|
17
|
+
if (formatting.shadow !== void 0) attrs.shadow = formatting.shadow;
|
|
18
|
+
if (formatting.outline !== void 0) attrs.outline = formatting.outline;
|
|
19
19
|
if (formatting.rtl === false) attrs.rtl = false;
|
|
20
|
-
if (formatting.boldCs !== void 0
|
|
21
|
-
if (formatting.italicCs !== void 0
|
|
20
|
+
if (formatting.boldCs !== void 0) attrs.boldCs = formatting.boldCs;
|
|
21
|
+
if (formatting.italicCs !== void 0) attrs.italicCs = formatting.italicCs;
|
|
22
22
|
if (formatting.fontSizeCs !== void 0 && formatting.fontSizeCs !== formatting.fontSize) attrs.fontSizeCs = formatting.fontSizeCs;
|
|
23
23
|
if (formatting.cs !== void 0) attrs.cs = formatting.cs;
|
|
24
24
|
return Object.keys(attrs).length > 0 ? attrs : void 0;
|
|
25
25
|
}
|
|
26
26
|
function applyRunFormattingOverrideAttrs(formatting, attrs) {
|
|
27
|
-
if (attrs.bold
|
|
28
|
-
if (attrs.italic
|
|
27
|
+
if (attrs.bold !== void 0) formatting.bold = attrs.bold;
|
|
28
|
+
if (attrs.italic !== void 0) formatting.italic = attrs.italic;
|
|
29
29
|
if (attrs.underline === "none") formatting.underline = { style: "none" };
|
|
30
|
-
if (attrs.strike
|
|
30
|
+
if (attrs.strike !== void 0) formatting.strike = attrs.strike;
|
|
31
31
|
if (attrs.doubleStrike === false) formatting.doubleStrike = false;
|
|
32
|
-
if (attrs.allCaps
|
|
33
|
-
if (attrs.smallCaps
|
|
34
|
-
if (attrs.hidden
|
|
35
|
-
if (attrs.emboss
|
|
36
|
-
if (attrs.imprint
|
|
37
|
-
if (attrs.shadow
|
|
38
|
-
if (attrs.outline
|
|
32
|
+
if (attrs.allCaps !== void 0) formatting.allCaps = attrs.allCaps;
|
|
33
|
+
if (attrs.smallCaps !== void 0) formatting.smallCaps = attrs.smallCaps;
|
|
34
|
+
if (attrs.hidden !== void 0) formatting.hidden = attrs.hidden;
|
|
35
|
+
if (attrs.emboss !== void 0) formatting.emboss = attrs.emboss;
|
|
36
|
+
if (attrs.imprint !== void 0) formatting.imprint = attrs.imprint;
|
|
37
|
+
if (attrs.shadow !== void 0) formatting.shadow = attrs.shadow;
|
|
38
|
+
if (attrs.outline !== void 0) formatting.outline = attrs.outline;
|
|
39
39
|
if (attrs.rtl === false) formatting.rtl = false;
|
|
40
40
|
if (attrs.boldCs !== void 0) formatting.boldCs = attrs.boldCs;
|
|
41
41
|
if (attrs.italicCs !== void 0) formatting.italicCs = attrs.italicCs;
|
|
@@ -121,7 +121,9 @@ type RunPropertyChangeMarkAttrs = {
|
|
|
121
121
|
provenance: TrackedChangeProvenance;
|
|
122
122
|
suggestionId?: string;
|
|
123
123
|
};
|
|
124
|
-
type RunFormattingOverrideAttrs = { [K in keyof Pick<document_d_exports.TextFormatting, "bold" | "italic" | "strike" | "
|
|
124
|
+
type RunFormattingOverrideAttrs = { [K in keyof Pick<document_d_exports.TextFormatting, "bold" | "italic" | "strike" | "allCaps" | "smallCaps" | "hidden" | "emboss" | "imprint" | "shadow" | "outline">]?: boolean; } & {
|
|
125
|
+
doubleStrike?: false;
|
|
126
|
+
rtl?: false;
|
|
125
127
|
/** Independent complex-script weight (`w:bCs`). */
|
|
126
128
|
boldCs?: boolean;
|
|
127
129
|
/** Force complex-script formatting for the full run (`w:cs`). */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { mergeParagraphFormatting } from "../../utils/paragraphFormattingMerge.js";
|
|
2
|
-
import {
|
|
2
|
+
import { cascadeStyleTextFormatting } from "./styleToggleCascade.js";
|
|
3
3
|
//#region src/prosemirror/styles/styleResolver.ts
|
|
4
4
|
/**
|
|
5
5
|
* Word's default-template Normal style, used as a last-resort fallback for a
|
|
@@ -102,21 +102,23 @@ var StyleResolver = class {
|
|
|
102
102
|
resolveParagraphStyleCascade(styleId, tableParagraphOverlay) {
|
|
103
103
|
const result = {};
|
|
104
104
|
if (this.docDefaults?.pPr) result.paragraphFormatting = { ...this.docDefaults.pPr };
|
|
105
|
-
if (this.docDefaults?.rPr) result.runFormatting = { ...this.docDefaults.rPr };
|
|
106
105
|
if (tableParagraphOverlay) {
|
|
107
106
|
const merged = mergeParagraphFormatting(result.paragraphFormatting, tableParagraphOverlay);
|
|
108
107
|
if (merged !== void 0) result.paragraphFormatting = merged;
|
|
109
108
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const style = this.stylesById.get(styleId);
|
|
115
|
-
if (!style) {
|
|
116
|
-
if (this.defaultParagraphStyle) this.mergeStyleIntoResult(result, this.defaultParagraphStyle);
|
|
117
|
-
return result;
|
|
109
|
+
const style = styleId ? this.stylesById.get(styleId) ?? this.defaultParagraphStyle : this.defaultParagraphStyle;
|
|
110
|
+
if (style?.pPr) {
|
|
111
|
+
const merged = mergeParagraphFormatting(result.paragraphFormatting, style.pPr);
|
|
112
|
+
if (merged) result.paragraphFormatting = merged;
|
|
118
113
|
}
|
|
119
|
-
|
|
114
|
+
const runFormatting = cascadeStyleTextFormatting([{
|
|
115
|
+
formatting: this.docDefaults?.rPr,
|
|
116
|
+
type: "defaults"
|
|
117
|
+
}, {
|
|
118
|
+
formatting: style?.rPr,
|
|
119
|
+
type: "style"
|
|
120
|
+
}]).formatting;
|
|
121
|
+
if (runFormatting) result.runFormatting = runFormatting;
|
|
120
122
|
return result;
|
|
121
123
|
}
|
|
122
124
|
/**
|
|
@@ -159,14 +161,15 @@ var StyleResolver = class {
|
|
|
159
161
|
* @returns Resolved text formatting
|
|
160
162
|
*/
|
|
161
163
|
resolveRunStyle(styleId) {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
164
|
+
const style = styleId ? this.stylesById.get(styleId) : this.defaultCharacterStyle;
|
|
165
|
+
const result = cascadeStyleTextFormatting([{
|
|
166
|
+
formatting: this.docDefaults?.rPr,
|
|
167
|
+
type: "defaults"
|
|
168
|
+
}, {
|
|
169
|
+
formatting: style?.rPr,
|
|
170
|
+
type: "style"
|
|
171
|
+
}]).formatting;
|
|
172
|
+
return result && Object.keys(result).length > 0 ? result : void 0;
|
|
170
173
|
}
|
|
171
174
|
/**
|
|
172
175
|
* Get a character style's own properties WITHOUT docDefaults.
|
|
@@ -213,16 +216,6 @@ var StyleResolver = class {
|
|
|
213
216
|
for (const style of this.stylesById.values()) if (style.type === type && style.default) return style;
|
|
214
217
|
if (type === "paragraph") return this.stylesById.get("Normal") ?? (this.docDefaults ? void 0 : BUILTIN_NORMAL_STYLE);
|
|
215
218
|
}
|
|
216
|
-
mergeStyleIntoResult(result, style) {
|
|
217
|
-
if (style.pPr) {
|
|
218
|
-
const merged = mergeParagraphFormatting(result.paragraphFormatting, style.pPr);
|
|
219
|
-
if (merged !== void 0) result.paragraphFormatting = merged;
|
|
220
|
-
}
|
|
221
|
-
if (style.rPr) {
|
|
222
|
-
const merged = mergeTextFormatting(result.runFormatting, style.rPr);
|
|
223
|
-
if (merged !== void 0) result.runFormatting = merged;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
219
|
};
|
|
227
220
|
/**
|
|
228
221
|
* Create a style resolver from document's style definitions
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { document_d_exports } from "../../types/document.js";
|
|
2
|
+
import { STYLE_TOGGLE_KEYS } from "../../utils/textFormattingMerge.js";
|
|
3
|
+
//#region src/prosemirror/styles/styleToggleCascade.d.ts
|
|
4
|
+
type StyleToggleKey = (typeof STYLE_TOGGLE_KEYS)[number];
|
|
5
|
+
type ToggleState = {
|
|
6
|
+
value: boolean;
|
|
7
|
+
defaultsActive: boolean;
|
|
8
|
+
};
|
|
9
|
+
/** Internal formatting value whose toggle history survives copying and separate cascade passes. */
|
|
10
|
+
type StyleTextFormattingCascade = {
|
|
11
|
+
formatting: document_d_exports.TextFormatting | undefined;
|
|
12
|
+
toggleStates: ReadonlyMap<StyleToggleKey, ToggleState>;
|
|
13
|
+
type: "styleToggleCascade";
|
|
14
|
+
};
|
|
15
|
+
type StyleToggleLevel = {
|
|
16
|
+
formatting: document_d_exports.TextFormatting | undefined;
|
|
17
|
+
type: "defaults" | "style" | "direct";
|
|
18
|
+
} | {
|
|
19
|
+
cascade: StyleTextFormattingCascade;
|
|
20
|
+
type: "carried";
|
|
21
|
+
};
|
|
22
|
+
type StyleToggleCascadeOptions = {
|
|
23
|
+
/** Existing ordinary-property merge whose toggle fields this cascade replaces. */
|
|
24
|
+
ordinaryFormatting: document_d_exports.TextFormatting | undefined;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Resolve run formatting across OOXML style hierarchy levels.
|
|
28
|
+
*
|
|
29
|
+
* Ordinary properties retain Folio's existing low-to-high, last-defined merge. Toggle
|
|
30
|
+
* properties reverse inherited state when a style level states `true`; `false` leaves inherited
|
|
31
|
+
* style state unchanged, while direct formatting remains an absolute value. The returned value
|
|
32
|
+
* carries its toggle history explicitly, so paragraph and character style resolution may happen
|
|
33
|
+
* in separate passes without an object-identity contract.
|
|
34
|
+
*/
|
|
35
|
+
declare function cascadeStyleTextFormatting(levels: readonly StyleToggleLevel[], options?: StyleToggleCascadeOptions): StyleTextFormattingCascade;
|
|
36
|
+
//#endregion
|
|
37
|
+
export { cascadeStyleTextFormatting };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { STYLE_TOGGLE_KEYS, mergeTextFormatting } from "../../utils/textFormattingMerge.js";
|
|
2
|
+
//#region src/prosemirror/styles/styleToggleCascade.ts
|
|
3
|
+
/**
|
|
4
|
+
* Resolve run formatting across OOXML style hierarchy levels.
|
|
5
|
+
*
|
|
6
|
+
* Ordinary properties retain Folio's existing low-to-high, last-defined merge. Toggle
|
|
7
|
+
* properties reverse inherited state when a style level states `true`; `false` leaves inherited
|
|
8
|
+
* style state unchanged, while direct formatting remains an absolute value. The returned value
|
|
9
|
+
* carries its toggle history explicitly, so paragraph and character style resolution may happen
|
|
10
|
+
* in separate passes without an object-identity contract.
|
|
11
|
+
*/
|
|
12
|
+
function cascadeStyleTextFormatting(levels, options) {
|
|
13
|
+
let formatting = options ? mergeTextFormatting(void 0, options.ordinaryFormatting) : void 0;
|
|
14
|
+
const mergeOrdinaryFormatting = options === void 0;
|
|
15
|
+
const toggleStates = /* @__PURE__ */ new Map();
|
|
16
|
+
for (const level of levels) {
|
|
17
|
+
if (level.type === "carried") {
|
|
18
|
+
if (mergeOrdinaryFormatting) formatting = mergeTextFormatting(formatting, level.cascade.formatting);
|
|
19
|
+
for (const [key, state] of level.cascade.toggleStates) toggleStates.set(key, state);
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (!level.formatting) continue;
|
|
23
|
+
if (mergeOrdinaryFormatting) formatting = mergeTextFormatting(formatting, level.formatting);
|
|
24
|
+
for (const key of STYLE_TOGGLE_KEYS) {
|
|
25
|
+
const value = level.formatting[key];
|
|
26
|
+
if (value === void 0) continue;
|
|
27
|
+
const inherited = toggleStates.get(key);
|
|
28
|
+
if (level.type === "direct") toggleStates.set(key, {
|
|
29
|
+
value,
|
|
30
|
+
defaultsActive: false
|
|
31
|
+
});
|
|
32
|
+
else if (!value) continue;
|
|
33
|
+
else if (level.type === "defaults") toggleStates.set(key, {
|
|
34
|
+
value: true,
|
|
35
|
+
defaultsActive: true
|
|
36
|
+
});
|
|
37
|
+
else toggleStates.set(key, {
|
|
38
|
+
value: inherited?.defaultsActive === true ? true : !(inherited?.value ?? false),
|
|
39
|
+
defaultsActive: inherited?.defaultsActive === true
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (!formatting && toggleStates.size > 0) formatting = {};
|
|
44
|
+
for (const [key, state] of toggleStates) if (formatting) formatting[key] = state.value;
|
|
45
|
+
return {
|
|
46
|
+
formatting,
|
|
47
|
+
toggleStates,
|
|
48
|
+
type: "styleToggleCascade"
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
export { cascadeStyleTextFormatting };
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { document_d_exports } from "../types/document.js";
|
|
2
2
|
//#region src/utils/textFormattingMerge.d.ts
|
|
3
|
+
declare const STYLE_TOGGLE_KEYS: readonly ["bold", "boldCs", "italic", "italicCs", "allCaps", "emboss", "imprint", "outline", "shadow", "smallCaps", "strike", "hidden"];
|
|
4
|
+
/**
|
|
5
|
+
* Merge the properties exposed by one resolved style definition.
|
|
6
|
+
*
|
|
7
|
+
* A false toggle at a child style level does not cancel the inherited state. The
|
|
8
|
+
* ordinary merge remains unchanged for direct formatting and non-toggle properties.
|
|
9
|
+
*/
|
|
10
|
+
declare function mergeStyleTextFormatting(target: document_d_exports.TextFormatting | undefined, source: document_d_exports.TextFormatting | undefined): document_d_exports.TextFormatting | undefined;
|
|
3
11
|
declare function mergeTextFormatting(target: document_d_exports.TextFormatting | undefined, source: document_d_exports.TextFormatting | undefined): document_d_exports.TextFormatting | undefined;
|
|
4
12
|
//#endregion
|
|
5
|
-
export { mergeTextFormatting };
|
|
13
|
+
export { STYLE_TOGGLE_KEYS, mergeStyleTextFormatting, mergeTextFormatting };
|
|
@@ -1,5 +1,36 @@
|
|
|
1
1
|
import { mergeFontFamily } from "./fontFamilyMerge.js";
|
|
2
2
|
//#region src/utils/textFormattingMerge.ts
|
|
3
|
+
const STYLE_TOGGLE_KEYS = [
|
|
4
|
+
"bold",
|
|
5
|
+
"boldCs",
|
|
6
|
+
"italic",
|
|
7
|
+
"italicCs",
|
|
8
|
+
"allCaps",
|
|
9
|
+
"emboss",
|
|
10
|
+
"imprint",
|
|
11
|
+
"outline",
|
|
12
|
+
"shadow",
|
|
13
|
+
"smallCaps",
|
|
14
|
+
"strike",
|
|
15
|
+
"hidden"
|
|
16
|
+
];
|
|
17
|
+
/**
|
|
18
|
+
* Merge the properties exposed by one resolved style definition.
|
|
19
|
+
*
|
|
20
|
+
* A false toggle at a child style level does not cancel the inherited state. The
|
|
21
|
+
* ordinary merge remains unchanged for direct formatting and non-toggle properties.
|
|
22
|
+
*/
|
|
23
|
+
function mergeStyleTextFormatting(target, source) {
|
|
24
|
+
const result = mergeTextFormatting(target, source);
|
|
25
|
+
if (!result || !source) return result;
|
|
26
|
+
for (const key of STYLE_TOGGLE_KEYS) {
|
|
27
|
+
if (source[key] !== false) continue;
|
|
28
|
+
const inherited = target?.[key];
|
|
29
|
+
if (inherited === void 0) Reflect.deleteProperty(result, key);
|
|
30
|
+
else result[key] = inherited;
|
|
31
|
+
}
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
3
34
|
function mergeTextFormatting(target, source) {
|
|
4
35
|
if (!source && !target) return;
|
|
5
36
|
if (!source) return target;
|
|
@@ -28,4 +59,4 @@ function mergeTextFormatting(target, source) {
|
|
|
28
59
|
return result;
|
|
29
60
|
}
|
|
30
61
|
//#endregion
|
|
31
|
-
export { mergeTextFormatting };
|
|
62
|
+
export { STYLE_TOGGLE_KEYS, mergeStyleTextFormatting, mergeTextFormatting };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stll/folio-core",
|
|
3
|
-
"version": "0.28.
|
|
3
|
+
"version": "0.28.1",
|
|
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",
|