@stll/folio-core 0.28.1 → 0.30.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/controller/folioEditor.d.ts +28 -1
- package/dist/controller/folioEditor.js +37 -26
- package/dist/controller/fontReadiness.js +28 -24
- package/dist/controller/hiddenEditorManager.d.ts +2 -7
- package/dist/controller/layoutPipeline.js +33 -3
- package/dist/controller/noteEditorManager.d.ts +3 -6
- package/dist/docx/metafileSvg.d.ts +12 -0
- package/dist/docx/metafileSvg.js +462 -0
- package/dist/docx/paragraphTextBoxEnrichment.js +55 -4
- package/dist/docx/parser.d.ts +2 -2
- package/dist/docx/parser.js +26 -0
- package/dist/docx/runParser.js +2 -1
- package/dist/docx/serializer/runSerializer.js +14 -2
- package/dist/docx/styleParser.js +2 -1
- package/dist/docx/textBoxParser.js +14 -0
- package/dist/docx/vmlImageParser.js +72 -152
- package/dist/docx/vmlPreview.d.ts +31 -0
- package/dist/docx/vmlPreview.js +535 -0
- package/dist/docx/wrapTypes.d.ts +2 -36
- package/dist/docx/wrapTypes.js +1 -39
- package/dist/fonts/fontAlternates.d.ts +8 -0
- package/dist/fonts/fontAlternates.js +16 -0
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
- package/dist/layout-bridge/convert/footnoteLayout.js +34 -3
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
- package/dist/layout-bridge/convert/headerFooterLayout.js +5 -0
- package/dist/layout-bridge/convert/toFlowBlocks.d.ts +4 -2
- package/dist/layout-bridge/convert/toFlowBlocks.js +136 -120
- package/dist/layout-bridge/dom/noteStoryDom.d.ts +1 -1
- package/dist/layout-bridge/engine/selectionRects.js +3 -1
- package/dist/layout-engine/index.js +65 -32
- package/dist/layout-engine/justifiedLineFit.d.ts +7 -0
- package/dist/layout-engine/justifiedLineFit.js +6 -0
- package/dist/layout-engine/keep-together.js +15 -10
- package/dist/layout-engine/measure/complexScriptFormatting.d.ts +6 -1
- package/dist/layout-engine/measure/complexScriptFormatting.js +11 -2
- package/dist/layout-engine/measure/floatingTablePosition.d.ts +16 -1
- package/dist/layout-engine/measure/floatingTablePosition.js +29 -6
- package/dist/layout-engine/measure/lineBreakProvider.js +67 -8
- package/dist/layout-engine/measure/listMarkerWidth.d.ts +1 -0
- package/dist/layout-engine/measure/listMarkerWidth.js +23 -10
- package/dist/layout-engine/measure/measureBlocks.d.ts +15 -0
- package/dist/layout-engine/measure/measureBlocks.js +197 -30
- package/dist/layout-engine/measure/measureContainer.js +20 -24
- package/dist/layout-engine/measure/measureHelpers.d.ts +1 -1
- package/dist/layout-engine/measure/measureHelpers.js +14 -8
- package/dist/layout-engine/measure/measureParagraph.js +111 -37
- package/dist/layout-engine/measure/measureTypes.d.ts +3 -0
- package/dist/layout-engine/measure/tabCalculator.d.ts +123 -0
- package/dist/layout-engine/measure/tabCalculator.js +144 -0
- package/dist/layout-engine/measure/tableCellFlow.d.ts +21 -1
- package/dist/layout-engine/measure/tableCellFlow.js +45 -8
- package/dist/layout-engine/measure/tableInlinePlacement.d.ts +10 -2
- package/dist/layout-engine/measure/tableInlinePlacement.js +17 -15
- package/dist/layout-engine/paginator.d.ts +26 -2
- package/dist/layout-engine/paginator.js +76 -14
- package/dist/layout-engine/paragraphSpacing.d.ts +3 -1
- package/dist/layout-engine/paragraphSpacing.js +4 -3
- package/dist/layout-engine/renderedBreakReconciliation.d.ts +14 -3
- package/dist/layout-engine/renderedBreakReconciliation.js +45 -14
- package/dist/layout-engine/section-breaks.d.ts +3 -1
- package/dist/layout-engine/section-breaks.js +6 -2
- package/dist/layout-engine/types.d.ts +18 -1
- package/dist/layout-engine/types.js +1 -1
- package/dist/layout-painter/imageLayout.d.ts +1 -1
- package/dist/layout-painter/renderPage.js +6 -1
- package/dist/layout-painter/renderParagraph.js +169 -82
- package/dist/layout-painter/renderTable.d.ts +1 -1
- package/dist/layout-painter/renderTable.js +18 -7
- package/dist/layout-painter/renderTextBox.d.ts +1 -1
- package/dist/layout-painter/renderTextBox.js +6 -1
- package/dist/markdown/renderParagraph.js +7 -2
- package/dist/model.d.ts +3 -3
- package/dist/model.js +2 -2
- package/dist/paged-layout/sectionBlockWidths.d.ts +14 -0
- package/dist/paged-layout/sectionBlockWidths.js +103 -14
- package/dist/prosemirror/attrs/index.js +14 -2
- package/dist/prosemirror/bookmarkBoundaryAttrs.d.ts +8 -0
- package/dist/prosemirror/bookmarkBoundaryAttrs.js +66 -0
- package/dist/prosemirror/conversion/fromProseDoc.js +176 -54
- package/dist/prosemirror/conversion/toProseDoc.js +179 -64
- package/dist/prosemirror/extensions/StarterKit.js +11 -3
- package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +8 -4
- package/dist/prosemirror/extensions/features/PasteCleanupExtension.d.ts +4 -1
- package/dist/prosemirror/extensions/features/PasteCleanupExtension.js +9 -5
- package/dist/prosemirror/extensions/features/pasteCleanup.d.ts +10 -23
- package/dist/prosemirror/extensions/features/pasteCleanup.js +77 -22
- package/dist/prosemirror/extensions/marks/CharacterSpacingExtension.js +9 -5
- package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.d.ts +9 -0
- package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.js +67 -0
- package/dist/prosemirror/extensions/nodes/FieldExtension.d.ts +10 -4
- package/dist/prosemirror/extensions/nodes/FieldExtension.js +77 -59
- package/dist/prosemirror/extensions/nodes/TableExtension.js +2 -0
- package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.d.ts +4 -1
- package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.js +4 -3
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +6 -2
- package/dist/prosemirror/listMarker.d.ts +58 -0
- package/dist/prosemirror/listMarker.js +185 -0
- package/dist/prosemirror/numberedRefFields.d.ts +24 -0
- package/dist/prosemirror/numberedRefFields.js +276 -0
- package/dist/prosemirror/paraText.js +56 -17
- package/dist/prosemirror/plugins/anonymizationDecorations.js +1 -1
- package/dist/prosemirror/plugins/pmTextScan.d.ts +3 -1
- package/dist/prosemirror/plugins/pmTextScan.js +28 -7
- package/dist/prosemirror/plugins/templateDirectives.js +2 -2
- package/dist/prosemirror/schema/index.d.ts +2 -2
- package/dist/prosemirror/schema/nodes.d.ts +17 -1
- package/dist/prosemirror/utils/tabCalculator.d.ts +2 -123
- package/dist/prosemirror/utils/tabCalculator.js +1 -140
- package/dist/prosemirror/validation.js +93 -0
- package/dist/render-dom/RemoteSelectionOverlay.d.ts +4 -4
- package/dist/types/documentEnumValues.d.ts +4 -1
- package/dist/types/documentEnumValues.js +12 -1
- package/dist/types/editor-story.d.ts +8 -0
- package/dist/types/editor-story.js +0 -0
- package/dist/types/remote-selection.d.ts +11 -0
- package/dist/types/remote-selection.js +0 -0
- package/dist/types/wrap.d.ts +36 -0
- package/dist/types/wrap.js +40 -0
- package/dist/utils/fontResolver.d.ts +1 -1
- package/dist/utils/fontResolver.js +42 -2
- package/dist/utils/formatToStyle.js +4 -2
- package/dist/utils/horizontalScale.d.ts +28 -0
- package/dist/utils/horizontalScale.js +42 -0
- package/package.json +2 -2
|
@@ -813,7 +813,7 @@ let embeddedFontFamilyMap = null;
|
|
|
813
813
|
const setEmbeddedFontFamilyMap = (map) => {
|
|
814
814
|
embeddedFontFamilyMap = map;
|
|
815
815
|
};
|
|
816
|
-
function resolveFontFamily(docxFontName) {
|
|
816
|
+
function resolveFontFamily(docxFontName, alternateFontName) {
|
|
817
817
|
const normalizedName = docxFontName.trim().toLowerCase();
|
|
818
818
|
const scopedFamily = embeddedFontFamilyMap?.get(docxFontName) ?? null;
|
|
819
819
|
const aliasTarget = CJK_FONT_ALIASES[normalizedName];
|
|
@@ -821,13 +821,41 @@ function resolveFontFamily(docxFontName) {
|
|
|
821
821
|
if (mapping) {
|
|
822
822
|
const fallbackStack = aliasTarget && !mapping.fallbackStack.some((f) => f.toLowerCase() === normalizedName) ? [docxFontName, ...mapping.fallbackStack] : mapping.fallbackStack;
|
|
823
823
|
const primaryStack = scopedFamily ? [scopedFamily, ...fallbackStack.filter((f) => f.toLowerCase() !== normalizedName)] : fallbackStack;
|
|
824
|
-
return {
|
|
824
|
+
if (alternateFontName === void 0 || alternateFontName.trim().length === 0 || alternateFontName.trim().toLowerCase() === normalizedName) return {
|
|
825
825
|
googleFont: googleFontsEnabled ? mapping.googleFont : null,
|
|
826
826
|
cssFallback: withArabicFallback(primaryStack.map(quoteFontName).join(", ")),
|
|
827
827
|
originalFont: docxFontName,
|
|
828
828
|
hasGoogleEquivalent: googleFontsEnabled,
|
|
829
829
|
singleLineRatio: mapping.singleLineRatio
|
|
830
830
|
};
|
|
831
|
+
const alternate = resolveFontFamily(alternateFontName);
|
|
832
|
+
const category = mapping.category;
|
|
833
|
+
const concreteStack = dedupeFontFamilies([
|
|
834
|
+
scopedFamily ?? docxFontName,
|
|
835
|
+
...parseFontFamilyList(alternate.cssFallback),
|
|
836
|
+
...primaryStack
|
|
837
|
+
]).filter((family) => !isCssGenericFontFamily(family));
|
|
838
|
+
const cssFallback = withArabicFallback([...concreteStack, category].map(quoteFontName).join(", "));
|
|
839
|
+
return {
|
|
840
|
+
googleFont: googleFontsEnabled ? mapping.googleFont : null,
|
|
841
|
+
cssFallback,
|
|
842
|
+
originalFont: docxFontName,
|
|
843
|
+
hasGoogleEquivalent: googleFontsEnabled,
|
|
844
|
+
singleLineRatio: mapping.singleLineRatio
|
|
845
|
+
};
|
|
846
|
+
}
|
|
847
|
+
const alternateName = alternateFontName?.trim();
|
|
848
|
+
if (alternateName && alternateName.toLowerCase() !== normalizedName) {
|
|
849
|
+
const alternate = resolveFontFamily(alternateName);
|
|
850
|
+
const category = detectFontCategory(docxFontName);
|
|
851
|
+
const concreteStack = dedupeFontFamilies([scopedFamily ?? docxFontName, ...parseFontFamilyList(alternate.cssFallback)]).filter((family) => !isCssGenericFontFamily(family));
|
|
852
|
+
return {
|
|
853
|
+
googleFont: googleFontsEnabled ? alternate.googleFont : null,
|
|
854
|
+
cssFallback: withArabicFallback([...concreteStack, category].map(quoteFontName).join(", ")),
|
|
855
|
+
originalFont: docxFontName,
|
|
856
|
+
hasGoogleEquivalent: googleFontsEnabled && alternate.hasGoogleEquivalent,
|
|
857
|
+
singleLineRatio: alternate.singleLineRatio
|
|
858
|
+
};
|
|
831
859
|
}
|
|
832
860
|
const category = detectFontCategory(docxFontName);
|
|
833
861
|
const defaultFallback = DEFAULT_FALLBACKS[category];
|
|
@@ -839,6 +867,18 @@ function resolveFontFamily(docxFontName) {
|
|
|
839
867
|
singleLineRatio: DEFAULT_SINGLE_LINE_RATIO
|
|
840
868
|
};
|
|
841
869
|
}
|
|
870
|
+
const isCssGenericFontFamily = (family) => /^(?:sans-serif|serif|monospace|cursive|fantasy|system-ui)$/u.test(family.trim().toLowerCase());
|
|
871
|
+
const dedupeFontFamilies = (families) => {
|
|
872
|
+
const seen = /* @__PURE__ */ new Set();
|
|
873
|
+
const result = [];
|
|
874
|
+
for (const family of families) {
|
|
875
|
+
const normalized = family.trim().toLowerCase();
|
|
876
|
+
if (!normalized || seen.has(normalized)) continue;
|
|
877
|
+
seen.add(normalized);
|
|
878
|
+
result.push(family.trim());
|
|
879
|
+
}
|
|
880
|
+
return result;
|
|
881
|
+
};
|
|
842
882
|
const CSS_NEWLINE_ESCAPES = {
|
|
843
883
|
"\n": "\\a ",
|
|
844
884
|
"\r": "\\d ",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { resolveColor, resolveHighlightToCss, resolveShadingColor } from "./colorResolver.js";
|
|
2
2
|
import { resolveFontFamily, resolveThemeFont } from "./fontResolver.js";
|
|
3
|
+
import { getHorizontalScaleFactor, normalizeHorizontalScalePercent } from "./horizontalScale.js";
|
|
3
4
|
import { AUTO_PARAGRAPH_SPACING_PX, eighthsToPixels, formatPx, halfPointsToPixels, halfPointsToPoints, twipsToPixels } from "./units.js";
|
|
4
5
|
//#region src/utils/formatToStyle.ts
|
|
5
6
|
/**
|
|
@@ -63,8 +64,9 @@ function textToStyle(formatting, theme) {
|
|
|
63
64
|
if (formatting.allCaps) style.textTransform = "uppercase";
|
|
64
65
|
else if (formatting.smallCaps) style.fontVariant = "small-caps";
|
|
65
66
|
if (formatting.spacing !== void 0 && formatting.spacing !== 0) style.letterSpacing = formatPx(twipsToPixels(formatting.spacing));
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
const horizontalScale = normalizeHorizontalScalePercent(formatting.scale);
|
|
68
|
+
if (horizontalScale !== void 0 && horizontalScale !== 100) {
|
|
69
|
+
style.transform = `scaleX(${getHorizontalScaleFactor(horizontalScale)})`;
|
|
68
70
|
style.display = "inline-block";
|
|
69
71
|
}
|
|
70
72
|
if (formatting.hidden) style.display = "none";
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
//#region src/utils/horizontalScale.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Normalize OOXML `w:w` horizontal text scale percentages.
|
|
4
|
+
*
|
|
5
|
+
* The OOXML value is bounded from 0% through 600%. Missing or malformed
|
|
6
|
+
* values use the document default (100%) and stay absent in the model.
|
|
7
|
+
*/
|
|
8
|
+
declare function normalizeHorizontalScalePercent(horizontalScale: number | null | undefined): number | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* Parse the lexical forms accepted by OOXML `ST_TextScale`.
|
|
11
|
+
*
|
|
12
|
+
* Decimal values use the XML Schema integer grammar; percent values use the
|
|
13
|
+
* unsigned decimal grammar defined by `ST_TextScalePercent`. Surrounding
|
|
14
|
+
* whitespace is ignored, but an empty value or partial numeric prefix is not.
|
|
15
|
+
*/
|
|
16
|
+
declare function parseHorizontalScalePercent(horizontalScale: string | null | undefined): number | undefined;
|
|
17
|
+
declare function getHorizontalScaleFactor(horizontalScale: number | null | undefined): number;
|
|
18
|
+
/**
|
|
19
|
+
* Quantize an in-range model value for OOXML's integer-only representation.
|
|
20
|
+
*
|
|
21
|
+
* Imported documents use strict integer normalization. Serialization also
|
|
22
|
+
* tolerates finite floating-point residue produced by editing calculations,
|
|
23
|
+
* preserving the existing integer-attribute contract without emitting an
|
|
24
|
+
* invalid fractional value.
|
|
25
|
+
*/
|
|
26
|
+
declare function roundHorizontalScalePercentForSerialization(horizontalScale: number | null | undefined): number | undefined;
|
|
27
|
+
//#endregion
|
|
28
|
+
export { getHorizontalScaleFactor, normalizeHorizontalScalePercent, parseHorizontalScalePercent, roundHorizontalScalePercentForSerialization };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
//#region src/utils/horizontalScale.ts
|
|
2
|
+
/**
|
|
3
|
+
* Normalize OOXML `w:w` horizontal text scale percentages.
|
|
4
|
+
*
|
|
5
|
+
* The OOXML value is bounded from 0% through 600%. Missing or malformed
|
|
6
|
+
* values use the document default (100%) and stay absent in the model.
|
|
7
|
+
*/
|
|
8
|
+
function normalizeHorizontalScalePercent(horizontalScale) {
|
|
9
|
+
if (horizontalScale === null || horizontalScale === void 0 || !Number.isFinite(horizontalScale) || !Number.isInteger(horizontalScale) || horizontalScale < 0 || horizontalScale > 600) return;
|
|
10
|
+
return horizontalScale;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Parse the lexical forms accepted by OOXML `ST_TextScale`.
|
|
14
|
+
*
|
|
15
|
+
* Decimal values use the XML Schema integer grammar; percent values use the
|
|
16
|
+
* unsigned decimal grammar defined by `ST_TextScalePercent`. Surrounding
|
|
17
|
+
* whitespace is ignored, but an empty value or partial numeric prefix is not.
|
|
18
|
+
*/
|
|
19
|
+
function parseHorizontalScalePercent(horizontalScale) {
|
|
20
|
+
if (horizontalScale === null || horizontalScale === void 0) return;
|
|
21
|
+
const lexicalValue = horizontalScale.trim();
|
|
22
|
+
if (!/^(?:[+-]?\d+|\d+%)$/u.test(lexicalValue)) return;
|
|
23
|
+
const numericValue = lexicalValue.endsWith("%") ? lexicalValue.slice(0, -1) : lexicalValue;
|
|
24
|
+
return normalizeHorizontalScalePercent(Number(numericValue));
|
|
25
|
+
}
|
|
26
|
+
function getHorizontalScaleFactor(horizontalScale) {
|
|
27
|
+
return (normalizeHorizontalScalePercent(horizontalScale) ?? 100) / 100;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Quantize an in-range model value for OOXML's integer-only representation.
|
|
31
|
+
*
|
|
32
|
+
* Imported documents use strict integer normalization. Serialization also
|
|
33
|
+
* tolerates finite floating-point residue produced by editing calculations,
|
|
34
|
+
* preserving the existing integer-attribute contract without emitting an
|
|
35
|
+
* invalid fractional value.
|
|
36
|
+
*/
|
|
37
|
+
function roundHorizontalScalePercentForSerialization(horizontalScale) {
|
|
38
|
+
if (horizontalScale === null || horizontalScale === void 0 || !Number.isFinite(horizontalScale) || horizontalScale < 0 || horizontalScale > 600) return;
|
|
39
|
+
return Math.round(horizontalScale);
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
42
|
+
export { getHorizontalScaleFactor, normalizeHorizontalScalePercent, parseHorizontalScalePercent, roundHorizontalScalePercentForSerialization };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stll/folio-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.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",
|
|
@@ -113,7 +113,7 @@
|
|
|
113
113
|
"perf": "bun scripts/profile-editor.ts"
|
|
114
114
|
},
|
|
115
115
|
"dependencies": {
|
|
116
|
-
"@stll/docx-core": "^0.17.
|
|
116
|
+
"@stll/docx-core": "^0.17.3",
|
|
117
117
|
"@stll/docx-utils": "^0.1.0",
|
|
118
118
|
"@stll/template-conditions": "^0.1.0",
|
|
119
119
|
"better-result": "3.0.1",
|