@stll/folio-core 0.1.2 → 0.2.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/docx/headerFooterParser.js +3 -0
- package/dist/docx/headerFooterVerbatim.d.ts +19 -0
- package/dist/docx/headerFooterVerbatim.js +25 -0
- package/dist/docx/index.d.ts +2 -0
- package/dist/docx/index.js +2 -0
- package/dist/docx/metafileRaster.d.ts +30 -0
- package/dist/docx/metafileRaster.js +80 -0
- package/dist/docx/paragraphParser.js +5 -1
- package/dist/docx/parser.d.ts +12 -2
- package/dist/docx/parser.js +31 -1
- package/dist/docx/serializer/headerFooterSerializer.js +3 -0
- package/dist/docx/styleParser.js +2 -2
- package/dist/docx/tableParser.js +2 -3
- package/dist/docx/unzip.js +7 -1
- package/dist/docx/wrapTypes.d.ts +8 -1
- package/dist/docx/wrapTypes.js +0 -8
- package/dist/docx/xmlParser.d.ts +7 -1
- package/dist/docx/xmlParser.js +17 -1
- package/dist/i18n/messages/catalogs.gen.d.ts +2776 -0
- package/dist/i18n/messages/catalogs.gen.js +2742 -0
- package/dist/i18n/messages/messages.gen.d.ts +166 -0
- package/dist/i18n/messages/messages.gen.js +0 -0
- package/dist/i18n/messages.d.ts +13 -0
- package/dist/i18n/messages.js +39 -0
- package/dist/layout-bridge/cellSelectionHighlight.d.ts +18 -0
- package/dist/layout-bridge/cellSelectionHighlight.js +36 -0
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +3 -2
- package/dist/layout-bridge/convert/headerFooterLayout.js +39 -15
- package/dist/layout-bridge/convert/toFlowBlocks.js +1 -0
- package/dist/layout-bridge/headerFooterLayout.d.ts +50 -0
- package/dist/layout-bridge/headerFooterLayout.js +216 -0
- package/dist/layout-bridge/measuring/measureBlocksPipeline.d.ts +33 -0
- package/dist/layout-bridge/measuring/measureBlocksPipeline.js +0 -0
- package/dist/layout-bridge/sectionColumns.d.ts +11 -0
- package/dist/layout-bridge/sectionColumns.js +21 -0
- package/dist/layout-bridge/tableInsertHover.d.ts +42 -0
- package/dist/layout-bridge/tableInsertHover.js +102 -0
- package/dist/layout-engine/index.d.ts +2 -1
- package/dist/layout-engine/index.js +2 -1
- package/dist/layout-engine/measure/lineBreaks.d.ts +10 -0
- package/dist/layout-engine/measure/lineBreaks.js +30 -0
- package/dist/layout-engine/measure/measureContainer.js +1 -1
- package/dist/layout-engine/measure/measureParagraph.js +63 -22
- package/dist/layout-engine/pmPageIndex.d.ts +24 -0
- package/dist/layout-engine/pmPageIndex.js +37 -0
- package/dist/layout-engine/types.d.ts +2 -1
- package/dist/layout-painter/imageLayout.d.ts +101 -0
- package/dist/layout-painter/imageLayout.js +161 -0
- package/dist/layout-painter/renderPage.d.ts +16 -1
- package/dist/layout-painter/renderPage.js +28 -1
- package/dist/layout-painter/renderParagraph.js +2 -1
- package/dist/layout-painter/sdtBoundary.d.ts +24 -1
- package/dist/layout-painter/sdtBoundary.js +40 -1
- package/dist/managers/AutoSaveManager.d.ts +89 -0
- package/dist/managers/AutoSaveManager.js +279 -0
- package/dist/managers/ClipboardManager.d.ts +31 -0
- package/dist/managers/ClipboardManager.js +147 -0
- package/dist/paged-layout/paragraphFlash.d.ts +17 -0
- package/dist/paged-layout/paragraphFlash.js +56 -0
- package/dist/paged-layout/paragraphFlashTypes.d.ts +18 -0
- package/dist/paged-layout/paragraphFlashTypes.js +0 -0
- package/dist/paged-layout/rangeProjection.d.ts +23 -1
- package/dist/paged-layout/rangeProjection.js +34 -1
- package/dist/prosemirror/cellDragSelection.d.ts +34 -0
- package/dist/prosemirror/cellDragSelection.js +69 -0
- package/dist/prosemirror/commands/sectionBreak.d.ts +15 -0
- package/dist/prosemirror/commands/sectionBreak.js +54 -0
- package/dist/prosemirror/commentIdAllocator.d.ts +32 -0
- package/dist/prosemirror/commentIdAllocator.js +35 -0
- package/dist/prosemirror/commentOps.d.ts +35 -0
- package/dist/prosemirror/commentOps.js +104 -0
- package/dist/prosemirror/conversion/toProseDoc.js +29 -6
- package/dist/prosemirror/extensions/index.d.ts +3 -0
- package/dist/prosemirror/extensions/index.js +3 -0
- package/dist/prosemirror/imageCommit.d.ts +42 -0
- package/dist/prosemirror/imageCommit.js +118 -0
- package/dist/prosemirror/paraText.d.ts +26 -0
- package/dist/prosemirror/paraText.js +73 -0
- package/dist/prosemirror/plugins/templateDirectives.d.ts +21 -1
- package/dist/prosemirror/plugins/templateDirectives.js +40 -1
- package/dist/prosemirror/queries.d.ts +46 -0
- package/dist/prosemirror/queries.js +74 -0
- package/dist/prosemirror/styles/styleResolver.d.ts +43 -1
- package/dist/prosemirror/styles/styleResolver.js +34 -0
- package/dist/prosemirror/tableResize.d.ts +49 -0
- package/dist/prosemirror/tableResize.js +162 -0
- package/dist/prosemirror/utils/extractTrackedChanges.d.ts +106 -0
- package/dist/prosemirror/utils/extractTrackedChanges.js +379 -0
- package/dist/prosemirror/utils/visualLineNavigation.d.ts +27 -0
- package/dist/prosemirror/utils/visualLineNavigation.js +217 -0
- package/dist/style-engine/index.d.ts +2 -2
- package/dist/style-engine/styleEngine.d.ts +14 -1
- package/dist/style-engine/styleEngine.js +15 -0
- package/dist/utils/colorResolver.d.ts +8 -1
- package/dist/utils/colorResolver.js +12 -1
- package/dist/utils/findVerticalScrollParent.d.ts +20 -0
- package/dist/utils/findVerticalScrollParent.js +30 -0
- package/dist/utils/fontResolver.d.ts +22 -3
- package/dist/utils/fontResolver.js +216 -31
- package/dist/utils/headerFooter.js +2 -0
- package/package.json +9 -1
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { findVerticalScrollParent } from "../../utils/findVerticalScrollParent.js";
|
|
2
|
+
import { TextSelection } from "prosemirror-state";
|
|
3
|
+
//#region src/prosemirror/utils/visualLineNavigation.ts
|
|
4
|
+
/**
|
|
5
|
+
* Visual line navigation helpers — implements Word/Google-Docs-style
|
|
6
|
+
* ArrowUp / ArrowDown with sticky X across visual lines (not just
|
|
7
|
+
* paragraphs). Lifted from packages/react/src/paged-editor/
|
|
8
|
+
* useVisualLineNavigation.ts so both adapters share the algorithm.
|
|
9
|
+
*
|
|
10
|
+
* Frontend-agnostic: takes a `getContainer: () => HTMLElement | null`
|
|
11
|
+
* callback and a mutable sticky-state object, returns the same
|
|
12
|
+
* function quartet React's hook returns.
|
|
13
|
+
*
|
|
14
|
+
* @packageDocumentation
|
|
15
|
+
* @internal
|
|
16
|
+
*/
|
|
17
|
+
const CONTENT_LINE_SELECTOR = ".layout-page-content .layout-line";
|
|
18
|
+
/** @internal */
|
|
19
|
+
function createVisualLineState() {
|
|
20
|
+
return {
|
|
21
|
+
stickyX: null,
|
|
22
|
+
lastVisualLineIndex: -1
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function scrollIntoViewIfNeeded(el) {
|
|
26
|
+
const container = findVerticalScrollParent(el);
|
|
27
|
+
if (!container) return;
|
|
28
|
+
const elRect = el.getBoundingClientRect();
|
|
29
|
+
const containerRect = container.getBoundingClientRect();
|
|
30
|
+
const margin = 40;
|
|
31
|
+
if (elRect.bottom > containerRect.bottom - margin) container.scrollTop += elRect.bottom - containerRect.bottom + margin;
|
|
32
|
+
else if (elRect.top < containerRect.top + margin) container.scrollTop -= containerRect.top - elRect.top + margin;
|
|
33
|
+
}
|
|
34
|
+
/** @internal */
|
|
35
|
+
function getCaretClientX(container, pmPos) {
|
|
36
|
+
const spans = container.querySelectorAll("span[data-pm-start][data-pm-end]");
|
|
37
|
+
for (const span of Array.from(spans)) {
|
|
38
|
+
const spanEl = span;
|
|
39
|
+
const pmStart = Number(spanEl.dataset["pmStart"]);
|
|
40
|
+
const pmEnd = Number(spanEl.dataset["pmEnd"]);
|
|
41
|
+
if (spanEl.classList.contains("layout-run-tab")) {
|
|
42
|
+
if (pmPos >= pmStart && pmPos < pmEnd) return spanEl.getBoundingClientRect().left;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (pmPos >= pmStart && pmPos <= pmEnd && span.firstChild?.nodeType === Node.TEXT_NODE) {
|
|
46
|
+
const textNode = span.firstChild;
|
|
47
|
+
const charIndex = Math.min(pmPos - pmStart, textNode.length);
|
|
48
|
+
const ownerDoc = spanEl.ownerDocument;
|
|
49
|
+
if (!ownerDoc) continue;
|
|
50
|
+
const range = ownerDoc.createRange();
|
|
51
|
+
range.setStart(textNode, charIndex);
|
|
52
|
+
range.setEnd(textNode, charIndex);
|
|
53
|
+
return range.getBoundingClientRect().left;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const emptyRuns = container.querySelectorAll(".layout-empty-run");
|
|
57
|
+
for (const emptyRun of Array.from(emptyRuns)) {
|
|
58
|
+
const paragraph = emptyRun.closest(".layout-paragraph");
|
|
59
|
+
if (!paragraph) continue;
|
|
60
|
+
const pmStart = Number(paragraph.dataset["pmStart"]);
|
|
61
|
+
const pmEnd = Number(paragraph.dataset["pmEnd"]);
|
|
62
|
+
if (pmPos >= pmStart && pmPos <= pmEnd) return emptyRun.getBoundingClientRect().left;
|
|
63
|
+
}
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
/** @internal */
|
|
67
|
+
function findLineElementAtPosition(container, pmPos) {
|
|
68
|
+
const allLines = container.querySelectorAll(CONTENT_LINE_SELECTOR);
|
|
69
|
+
for (const line of Array.from(allLines)) {
|
|
70
|
+
const lineEl = line;
|
|
71
|
+
const spans = lineEl.querySelectorAll("span[data-pm-start][data-pm-end]");
|
|
72
|
+
for (const span of Array.from(spans)) {
|
|
73
|
+
const s = span;
|
|
74
|
+
const start = Number(s.dataset["pmStart"]);
|
|
75
|
+
const end = Number(s.dataset["pmEnd"]);
|
|
76
|
+
if (pmPos >= start && pmPos <= end) return lineEl;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
for (const line of Array.from(allLines)) {
|
|
80
|
+
const lineEl = line;
|
|
81
|
+
const paragraph = lineEl.closest(".layout-paragraph");
|
|
82
|
+
if (!paragraph) continue;
|
|
83
|
+
const pStart = Number(paragraph.dataset["pmStart"]);
|
|
84
|
+
const pEnd = Number(paragraph.dataset["pmEnd"]);
|
|
85
|
+
if (pmPos >= pStart && pmPos <= pEnd) {
|
|
86
|
+
if (paragraph.querySelector(".layout-line") === lineEl) return lineEl;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
/** @internal */
|
|
92
|
+
function findPositionOnLineAtClientX(lineEl, clientX) {
|
|
93
|
+
const spans = lineEl.querySelectorAll("span[data-pm-start][data-pm-end]");
|
|
94
|
+
if (spans.length === 0) {
|
|
95
|
+
const paragraph = lineEl.closest(".layout-paragraph");
|
|
96
|
+
if (paragraph?.dataset["pmStart"]) return Number(paragraph.dataset["pmStart"]) + 1;
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
for (const span of Array.from(spans)) {
|
|
100
|
+
const spanEl = span;
|
|
101
|
+
const rect = spanEl.getBoundingClientRect();
|
|
102
|
+
const pmStart = Number(spanEl.dataset["pmStart"]);
|
|
103
|
+
const pmEnd = Number(spanEl.dataset["pmEnd"]);
|
|
104
|
+
if (spanEl.classList.contains("layout-run-tab")) {
|
|
105
|
+
if (clientX >= rect.left && clientX <= rect.right) return clientX < (rect.left + rect.right) / 2 ? pmStart : pmEnd;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (clientX >= rect.left && clientX <= rect.right) {
|
|
109
|
+
const textNode = spanEl.firstChild;
|
|
110
|
+
if (!textNode || textNode.nodeType !== Node.TEXT_NODE) return pmStart;
|
|
111
|
+
const text = textNode;
|
|
112
|
+
const ownerDoc = spanEl.ownerDocument;
|
|
113
|
+
if (!ownerDoc) return pmStart;
|
|
114
|
+
let lo = 0;
|
|
115
|
+
let hi = text.length;
|
|
116
|
+
while (lo < hi) {
|
|
117
|
+
const mid = Math.floor((lo + hi) / 2);
|
|
118
|
+
const r = ownerDoc.createRange();
|
|
119
|
+
r.setStart(text, mid);
|
|
120
|
+
r.setEnd(text, mid);
|
|
121
|
+
if (clientX < r.getBoundingClientRect().left) hi = mid;
|
|
122
|
+
else lo = mid + 1;
|
|
123
|
+
}
|
|
124
|
+
if (lo > 0 && lo <= text.length) {
|
|
125
|
+
const r = ownerDoc.createRange();
|
|
126
|
+
r.setStart(text, lo - 1);
|
|
127
|
+
r.setEnd(text, lo - 1);
|
|
128
|
+
const leftX = r.getBoundingClientRect().left;
|
|
129
|
+
r.setStart(text, Math.min(lo, text.length));
|
|
130
|
+
r.setEnd(text, Math.min(lo, text.length));
|
|
131
|
+
const rightX = r.getBoundingClientRect().left;
|
|
132
|
+
if (Math.abs(clientX - leftX) < Math.abs(clientX - rightX)) return pmStart + (lo - 1);
|
|
133
|
+
}
|
|
134
|
+
return pmStart + Math.min(lo, pmEnd - pmStart);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
let closestSpan = null;
|
|
138
|
+
let closestDist = Infinity;
|
|
139
|
+
for (const span of Array.from(spans)) {
|
|
140
|
+
const spanEl = span;
|
|
141
|
+
const rect = spanEl.getBoundingClientRect();
|
|
142
|
+
const dist = clientX < rect.left ? rect.left - clientX : clientX - rect.right;
|
|
143
|
+
if (dist < closestDist) {
|
|
144
|
+
closestDist = dist;
|
|
145
|
+
closestSpan = spanEl;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (!closestSpan) return null;
|
|
149
|
+
return clientX < closestSpan.getBoundingClientRect().left ? Number(closestSpan.dataset["pmStart"]) : Number(closestSpan.dataset["pmEnd"]);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Handle PM ArrowUp / ArrowDown with visual-line awareness + sticky
|
|
153
|
+
* X. Returns true if the event was handled and PM should not run
|
|
154
|
+
* its default behaviour. Mutates `state` so consecutive presses
|
|
155
|
+
* keep the same sticky X.
|
|
156
|
+
*
|
|
157
|
+
* @internal
|
|
158
|
+
*/
|
|
159
|
+
function handleVisualLineKeyDown(state, view, event, container) {
|
|
160
|
+
if (event.key !== "ArrowUp" && event.key !== "ArrowDown") {
|
|
161
|
+
if ([
|
|
162
|
+
"ArrowLeft",
|
|
163
|
+
"ArrowRight",
|
|
164
|
+
"Home",
|
|
165
|
+
"End"
|
|
166
|
+
].includes(event.key) || event.key.length === 1 && !event.ctrlKey && !event.metaKey) {
|
|
167
|
+
state.stickyX = null;
|
|
168
|
+
state.lastVisualLineIndex = -1;
|
|
169
|
+
}
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
if (event.ctrlKey || event.metaKey) {
|
|
173
|
+
state.stickyX = null;
|
|
174
|
+
state.lastVisualLineIndex = -1;
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
if (!container) return false;
|
|
178
|
+
const allLines = Array.from(container.querySelectorAll(CONTENT_LINE_SELECTOR));
|
|
179
|
+
if (allLines.length === 0) return false;
|
|
180
|
+
const { from, anchor } = view.state.selection;
|
|
181
|
+
if (state.stickyX === null) {
|
|
182
|
+
const clientX = getCaretClientX(container, from);
|
|
183
|
+
if (clientX === null) return false;
|
|
184
|
+
state.stickyX = clientX;
|
|
185
|
+
}
|
|
186
|
+
let currentIndex;
|
|
187
|
+
if (state.lastVisualLineIndex >= 0 && state.lastVisualLineIndex < allLines.length) currentIndex = state.lastVisualLineIndex;
|
|
188
|
+
else {
|
|
189
|
+
const currentLine = findLineElementAtPosition(container, from);
|
|
190
|
+
if (!currentLine) return false;
|
|
191
|
+
currentIndex = allLines.indexOf(currentLine);
|
|
192
|
+
if (currentIndex === -1) return false;
|
|
193
|
+
}
|
|
194
|
+
const targetIndex = event.key === "ArrowUp" ? currentIndex - 1 : currentIndex + 1;
|
|
195
|
+
if (targetIndex < 0 || targetIndex >= allLines.length) {
|
|
196
|
+
state.lastVisualLineIndex = -1;
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
const targetLine = allLines[targetIndex];
|
|
200
|
+
const newPos = findPositionOnLineAtClientX(targetLine, state.stickyX);
|
|
201
|
+
if (newPos === null) return false;
|
|
202
|
+
state.lastVisualLineIndex = targetIndex;
|
|
203
|
+
const { state: pmState, dispatch } = view;
|
|
204
|
+
const clampedPos = Math.max(0, Math.min(newPos, pmState.doc.content.size));
|
|
205
|
+
try {
|
|
206
|
+
const sel = event.shiftKey ? TextSelection.create(pmState.doc, anchor, clampedPos) : TextSelection.create(pmState.doc, clampedPos);
|
|
207
|
+
dispatch(pmState.tr.setSelection(sel));
|
|
208
|
+
} catch {
|
|
209
|
+
const $newPos = pmState.doc.resolve(clampedPos);
|
|
210
|
+
const sel = event.shiftKey ? TextSelection.between(pmState.doc.resolve(anchor), $newPos) : TextSelection.near($newPos);
|
|
211
|
+
dispatch(pmState.tr.setSelection(sel));
|
|
212
|
+
}
|
|
213
|
+
scrollIntoViewIfNeeded(targetLine);
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
216
|
+
//#endregion
|
|
217
|
+
export { createVisualLineState, findLineElementAtPosition, findPositionOnLineAtClientX, getCaretClientX, handleVisualLineKeyDown };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { ResolvedParagraphStyle } from "../prosemirror/styles/styleResolver.js";
|
|
1
|
+
import { ResolvedParagraphStyle, TableCellParagraphSpacingOverlay } from "../prosemirror/styles/styleResolver.js";
|
|
2
2
|
import { StyleEngine, StyleEngineCacheStats, StyleEngineOptions, createStyleEngine } from "./styleEngine.js";
|
|
3
|
-
export { type ResolvedParagraphStyle, type StyleEngine, type StyleEngineCacheStats, type StyleEngineOptions, createStyleEngine };
|
|
3
|
+
export { type ResolvedParagraphStyle, type StyleEngine, type StyleEngineCacheStats, type StyleEngineOptions, type TableCellParagraphSpacingOverlay, createStyleEngine };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { document_d_exports } from "../types/document.js";
|
|
2
|
-
import { ResolvedParagraphStyle } from "../prosemirror/styles/styleResolver.js";
|
|
2
|
+
import { ResolvedParagraphStyle, TableCellParagraphSpacingOverlay } from "../prosemirror/styles/styleResolver.js";
|
|
3
3
|
|
|
4
4
|
//#region src/style-engine/styleEngine.d.ts
|
|
5
5
|
/** Engine construction options. */
|
|
@@ -41,6 +41,19 @@ type StyleEngine = {
|
|
|
41
41
|
* Returned object is cached and must not be mutated.
|
|
42
42
|
*/
|
|
43
43
|
resolveParagraphStyle: (styleId: string | undefined | null) => ResolvedParagraphStyle;
|
|
44
|
+
/**
|
|
45
|
+
* Resolve the paragraph cascade for a paragraph inside a table cell,
|
|
46
|
+
* layering the enclosing table style's paragraph-spacing fields between
|
|
47
|
+
* docDefaults and the paragraph's own style chain — see
|
|
48
|
+
* {@link StyleResolver.resolveParagraphStyleInTable}.
|
|
49
|
+
*
|
|
50
|
+
* Pass the *same* `tableParagraphOverlay` object reference for every
|
|
51
|
+
* paragraph governed by the same table style region (folio's table
|
|
52
|
+
* conversion already computes it once per region) — the cache below keys
|
|
53
|
+
* on object identity, so a fresh object per call defeats memoization.
|
|
54
|
+
* Returned object is cached and must not be mutated.
|
|
55
|
+
*/
|
|
56
|
+
resolveParagraphStyleInTable: (styleId: string | undefined | null, tableParagraphOverlay: TableCellParagraphSpacingOverlay | undefined) => ResolvedParagraphStyle;
|
|
44
57
|
/**
|
|
45
58
|
* Resolve a run/character style with docDefaults applied.
|
|
46
59
|
* Returns `undefined` when the cascade yields nothing.
|
|
@@ -23,6 +23,7 @@ function createStyleEngine(styleDefinitions, options) {
|
|
|
23
23
|
const paragraphCache = /* @__PURE__ */ new Map();
|
|
24
24
|
const runCache = /* @__PURE__ */ new Map();
|
|
25
25
|
const ownPropsCache = /* @__PURE__ */ new Map();
|
|
26
|
+
let tableOverlayCache = /* @__PURE__ */ new WeakMap();
|
|
26
27
|
let hits = 0;
|
|
27
28
|
let misses = 0;
|
|
28
29
|
const memoize = (cache, key, compute) => {
|
|
@@ -40,6 +41,18 @@ function createStyleEngine(styleDefinitions, options) {
|
|
|
40
41
|
cache.set(key, { value });
|
|
41
42
|
return value;
|
|
42
43
|
};
|
|
44
|
+
const memoizeInTable = (styleId, tableParagraphOverlay) => {
|
|
45
|
+
if (!cacheEnabled) {
|
|
46
|
+
misses += 1;
|
|
47
|
+
return resolver.resolveParagraphStyleInTable(styleId, tableParagraphOverlay);
|
|
48
|
+
}
|
|
49
|
+
let overlayCache = tableOverlayCache.get(tableParagraphOverlay);
|
|
50
|
+
if (!overlayCache) {
|
|
51
|
+
overlayCache = /* @__PURE__ */ new Map();
|
|
52
|
+
tableOverlayCache.set(tableParagraphOverlay, overlayCache);
|
|
53
|
+
}
|
|
54
|
+
return memoize(overlayCache, cacheKey(styleId), () => resolver.resolveParagraphStyleInTable(styleId, tableParagraphOverlay));
|
|
55
|
+
};
|
|
43
56
|
return {
|
|
44
57
|
getStyle: (styleId) => resolver.getStyle(styleId),
|
|
45
58
|
hasStyle: (styleId) => resolver.hasStyle(styleId),
|
|
@@ -50,12 +63,14 @@ function createStyleEngine(styleDefinitions, options) {
|
|
|
50
63
|
getParagraphStyles: () => resolver.getParagraphStyles(),
|
|
51
64
|
getTableStyles: () => resolver.getTableStyles(),
|
|
52
65
|
resolveParagraphStyle: (styleId) => memoize(paragraphCache, cacheKey(styleId), () => resolver.resolveParagraphStyle(styleId)),
|
|
66
|
+
resolveParagraphStyleInTable: (styleId, tableParagraphOverlay) => tableParagraphOverlay === void 0 ? memoize(paragraphCache, cacheKey(styleId), () => resolver.resolveParagraphStyleInTable(styleId, void 0)) : memoizeInTable(styleId, tableParagraphOverlay),
|
|
53
67
|
resolveRunStyle: (styleId) => memoize(runCache, cacheKey(styleId), () => resolver.resolveRunStyle(styleId)),
|
|
54
68
|
getRunStyleOwnProperties: (styleId) => memoize(ownPropsCache, cacheKey(styleId), () => resolver.getRunStyleOwnProperties(styleId)),
|
|
55
69
|
invalidate: () => {
|
|
56
70
|
paragraphCache.clear();
|
|
57
71
|
runCache.clear();
|
|
58
72
|
ownPropsCache.clear();
|
|
73
|
+
tableOverlayCache = /* @__PURE__ */ new WeakMap();
|
|
59
74
|
hits = 0;
|
|
60
75
|
misses = 0;
|
|
61
76
|
},
|
|
@@ -16,6 +16,13 @@ declare function resolveColor(color: document_d_exports.ColorValue | undefined |
|
|
|
16
16
|
* @param highlight - Highlight color name (e.g., "yellow", "cyan")
|
|
17
17
|
* @returns CSS color string or empty string for "none"
|
|
18
18
|
*/
|
|
19
|
+
/**
|
|
20
|
+
* Resolve a `ColorValue` to a bare 6-digit hex string (no leading `#`), or
|
|
21
|
+
* `undefined` for an `auto`/absent color. Theme colors resolve through the
|
|
22
|
+
* document theme; explicit `rgb` values are upper-cased. Used by adapters that
|
|
23
|
+
* need a normalized hex (e.g. comparing a cell fill against a swatch).
|
|
24
|
+
*/
|
|
25
|
+
declare function resolveColorToHex(color: document_d_exports.ColorValue | undefined | null, theme: document_d_exports.Theme | null | undefined): string | undefined;
|
|
19
26
|
declare function resolveHighlightColor(highlight: string | undefined): string;
|
|
20
27
|
/**
|
|
21
28
|
* Resolve a shading fill or pattern color to CSS
|
|
@@ -155,4 +162,4 @@ declare function generateThemeTintShadeMatrix(colorScheme?: document_d_exports.T
|
|
|
155
162
|
*/
|
|
156
163
|
declare function colorsEqual(color1: document_d_exports.ColorValue | undefined | null, color2: document_d_exports.ColorValue | undefined | null, theme: document_d_exports.Theme | null | undefined): boolean;
|
|
157
164
|
//#endregion
|
|
158
|
-
export { STANDARD_TEXT_COLORS, ThemeMatrixCell, blendColors, colorsEqual, createRgbColor, createThemeColor, darkenColor, ensureHexPrefix, generateThemeTintShadeMatrix, getContrastingColor, getThemeTintShadeHex, isBlack, isWhite, lightenColor, parseColorString, resolveColor, resolveHighlightColor, resolveHighlightToCss, resolveShadingColor };
|
|
165
|
+
export { STANDARD_TEXT_COLORS, ThemeMatrixCell, blendColors, colorsEqual, createRgbColor, createThemeColor, darkenColor, ensureHexPrefix, generateThemeTintShadeMatrix, getContrastingColor, getThemeTintShadeHex, isBlack, isWhite, lightenColor, parseColorString, resolveColor, resolveColorToHex, resolveHighlightColor, resolveHighlightToCss, resolveShadingColor };
|
|
@@ -218,6 +218,17 @@ function resolveColor(color, theme, defaultColor = "000000") {
|
|
|
218
218
|
* @param highlight - Highlight color name (e.g., "yellow", "cyan")
|
|
219
219
|
* @returns CSS color string or empty string for "none"
|
|
220
220
|
*/
|
|
221
|
+
/**
|
|
222
|
+
* Resolve a `ColorValue` to a bare 6-digit hex string (no leading `#`), or
|
|
223
|
+
* `undefined` for an `auto`/absent color. Theme colors resolve through the
|
|
224
|
+
* document theme; explicit `rgb` values are upper-cased. Used by adapters that
|
|
225
|
+
* need a normalized hex (e.g. comparing a cell fill against a swatch).
|
|
226
|
+
*/
|
|
227
|
+
function resolveColorToHex(color, theme) {
|
|
228
|
+
if (!color || color.auto) return void 0;
|
|
229
|
+
if (color.themeColor && theme) return resolveColor(color, theme).slice(1);
|
|
230
|
+
if (color.rgb && color.rgb !== "auto") return color.rgb.toUpperCase().replace(/^#/, "");
|
|
231
|
+
}
|
|
221
232
|
function resolveHighlightColor(highlight) {
|
|
222
233
|
if (!highlight || highlight === "none") return "";
|
|
223
234
|
const hex = HIGHLIGHT_COLORS[highlight];
|
|
@@ -554,4 +565,4 @@ function colorsEqual(color1, color2, theme) {
|
|
|
554
565
|
return resolveColor(color1, theme).toUpperCase() === resolveColor(color2, theme).toUpperCase();
|
|
555
566
|
}
|
|
556
567
|
//#endregion
|
|
557
|
-
export { STANDARD_TEXT_COLORS, blendColors, colorsEqual, createRgbColor, createThemeColor, darkenColor, ensureHexPrefix, generateThemeTintShadeMatrix, getContrastingColor, getThemeTintShadeHex, isBlack, isWhite, lightenColor, parseColorString, resolveColor, resolveHighlightColor, resolveHighlightToCss, resolveShadingColor };
|
|
568
|
+
export { STANDARD_TEXT_COLORS, blendColors, colorsEqual, createRgbColor, createThemeColor, darkenColor, ensureHexPrefix, generateThemeTintShadeMatrix, getContrastingColor, getThemeTintShadeHex, isBlack, isWhite, lightenColor, parseColorString, resolveColor, resolveColorToHex, resolveHighlightColor, resolveHighlightToCss, resolveShadingColor };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//#region src/utils/findVerticalScrollParent.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Pure DOM helpers — locate the element that vertically scrolls the paginated
|
|
4
|
+
* editor. Shared by scroll-to-position, arrow-key line navigation, and drag
|
|
5
|
+
* auto-scroll so every framework adapter uses the same logic.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* First ancestor of `el` with `overflow-y: auto|scroll` and a scrollable
|
|
9
|
+
* overflow height. The walk starts at `el.parentElement` (it does not treat
|
|
10
|
+
* `el` itself as the scroller). Returns `null` when no such ancestor exists
|
|
11
|
+
* before `document.documentElement`.
|
|
12
|
+
*/
|
|
13
|
+
declare function findVerticalScrollParent(el: HTMLElement): HTMLElement | null;
|
|
14
|
+
/**
|
|
15
|
+
* Same as {@link findVerticalScrollParent} but falls back to
|
|
16
|
+
* `document.documentElement` so callers always get a valid scroll target.
|
|
17
|
+
*/
|
|
18
|
+
declare function findVerticalScrollParentOrRoot(el: HTMLElement): HTMLElement;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { findVerticalScrollParent, findVerticalScrollParentOrRoot };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//#region src/utils/findVerticalScrollParent.ts
|
|
2
|
+
/**
|
|
3
|
+
* Pure DOM helpers — locate the element that vertically scrolls the paginated
|
|
4
|
+
* editor. Shared by scroll-to-position, arrow-key line navigation, and drag
|
|
5
|
+
* auto-scroll so every framework adapter uses the same logic.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* First ancestor of `el` with `overflow-y: auto|scroll` and a scrollable
|
|
9
|
+
* overflow height. The walk starts at `el.parentElement` (it does not treat
|
|
10
|
+
* `el` itself as the scroller). Returns `null` when no such ancestor exists
|
|
11
|
+
* before `document.documentElement`.
|
|
12
|
+
*/
|
|
13
|
+
function findVerticalScrollParent(el) {
|
|
14
|
+
let parent = el.parentElement;
|
|
15
|
+
while (parent && parent !== document.documentElement) {
|
|
16
|
+
const { overflowY } = getComputedStyle(parent);
|
|
17
|
+
if ((overflowY === "auto" || overflowY === "scroll") && parent.scrollHeight > parent.clientHeight + 1) return parent;
|
|
18
|
+
parent = parent.parentElement;
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Same as {@link findVerticalScrollParent} but falls back to
|
|
24
|
+
* `document.documentElement` so callers always get a valid scroll target.
|
|
25
|
+
*/
|
|
26
|
+
function findVerticalScrollParentOrRoot(el) {
|
|
27
|
+
return findVerticalScrollParent(el) ?? document.documentElement;
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { findVerticalScrollParent, findVerticalScrollParentOrRoot };
|
|
@@ -7,7 +7,7 @@ type ResolvedFont = {
|
|
|
7
7
|
/** Google Font name to load (null if no mapping available) */googleFont: string | null; /** CSS font-family value with proper fallback stack */
|
|
8
8
|
cssFallback: string; /** Original font name from the DOCX */
|
|
9
9
|
originalFont: string; /** Whether this font has a Google Fonts equivalent */
|
|
10
|
-
hasGoogleEquivalent: boolean; /**
|
|
10
|
+
hasGoogleEquivalent: boolean; /** Single-line height ratio (single-line height ÷ font size). See `FontLineHeight`. */
|
|
11
11
|
singleLineRatio: number;
|
|
12
12
|
};
|
|
13
13
|
/**
|
|
@@ -15,10 +15,29 @@ type ResolvedFont = {
|
|
|
15
15
|
*/
|
|
16
16
|
type FontCategory = "sans-serif" | "serif" | "monospace" | "cursive" | "fantasy" | "system-ui";
|
|
17
17
|
/**
|
|
18
|
-
* Default
|
|
18
|
+
* Default single-line ratio for unmapped fonts.
|
|
19
19
|
* Middle of the common range (1.07–1.27) for standard DOCX fonts.
|
|
20
20
|
*/
|
|
21
21
|
declare const DEFAULT_SINGLE_LINE_RATIO = 1.15;
|
|
22
|
+
/**
|
|
23
|
+
* True when `family` is a known East-Asian (CJK) typeface — a direct
|
|
24
|
+
* `FONT_MAPPINGS` CJK entry or a romanized alias of one. Used by the measurer
|
|
25
|
+
* to decide whether a run's `w:eastAsia` font can supply the line height for
|
|
26
|
+
* CJK text, or whether Word would font-link to a default East-Asian face
|
|
27
|
+
* instead (see `CJK_FALLBACK_FONT_FAMILY`). Unmapped families return false:
|
|
28
|
+
* we cannot know their metrics, so the caller falls back.
|
|
29
|
+
*/
|
|
30
|
+
declare function isCjkFont(family: string): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Font family whose `singleLineRatio` stands in for Word's default East-Asian
|
|
33
|
+
* face when a CJK-text run declares no usable CJK font (its `w:eastAsia` slot
|
|
34
|
+
* is absent or names a Latin face like "Century"). Word font-links those
|
|
35
|
+
* glyphs to the OS default East-Asian font and takes THAT face's taller line
|
|
36
|
+
* height; MS Mincho carries the measured ratio for it
|
|
37
|
+
* (`JP_MEASURED_LINE_HEIGHT`, ≈1.303). Line-height resolution only — never
|
|
38
|
+
* used for width measurement or painting.
|
|
39
|
+
*/
|
|
40
|
+
declare const CJK_FALLBACK_FONT_FAMILY = "MS Mincho";
|
|
22
41
|
declare function resolveFontFamily(docxFontName: string): ResolvedFont;
|
|
23
42
|
/**
|
|
24
43
|
* Resolve a theme font reference to actual font names
|
|
@@ -58,4 +77,4 @@ declare function getGoogleFontEquivalent(docxFontName: string): string | null;
|
|
|
58
77
|
*/
|
|
59
78
|
declare function hasGoogleFontEquivalent(docxFontName: string): boolean;
|
|
60
79
|
//#endregion
|
|
61
|
-
export { DEFAULT_SINGLE_LINE_RATIO, ResolvedFont, buildFontFamilyString, getGoogleFontEquivalent, getGoogleFontsToLoad, hasGoogleFontEquivalent, resolveFontFamily, resolveThemeFont };
|
|
80
|
+
export { CJK_FALLBACK_FONT_FAMILY, DEFAULT_SINGLE_LINE_RATIO, ResolvedFont, buildFontFamilyString, getGoogleFontEquivalent, getGoogleFontsToLoad, hasGoogleFontEquivalent, isCjkFont, resolveFontFamily, resolveThemeFont };
|