@formulaxjs/editor 0.2.0 → 0.3.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/README.md +42 -10
- package/dist/index.cjs +194 -445
- package/dist/index.cjs.map +1 -1
- package/dist/index.global.js +1064 -765
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +186 -431
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
package/dist/index.cjs
CHANGED
|
@@ -20,101 +20,178 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
-
|
|
24
|
-
DEFAULT_FORMULA_CLASS: () => DEFAULT_FORMULA_CLASS,
|
|
25
|
-
FORMULA_FLAG_ATTRIBUTE: () => FORMULA_FLAG_ATTRIBUTE,
|
|
26
|
-
FormulaXEditor: () => import_kity_runtime2.FormulaXEditor,
|
|
27
|
-
createFormulaElement: () => createFormulaElement,
|
|
28
|
-
createFormulaMarkup: () => createFormulaMarkup,
|
|
29
|
-
createKityEditor: () => import_kity_runtime2.createKityEditor,
|
|
23
|
+
clearFormulaXPerfMarks: () => clearFormulaXPerfMarks,
|
|
30
24
|
ensureFormulaXModalStyles: () => ensureFormulaXModalStyles,
|
|
31
|
-
ensureKityRuntime: () => import_kity_runtime2.ensureKityRuntime,
|
|
32
|
-
escapeAttribute: () => escapeAttribute,
|
|
33
|
-
escapeHtml: () => escapeHtml,
|
|
34
|
-
findFormulaElement: () => findFormulaElement,
|
|
35
25
|
formulaXModalStyles: () => formulaXModalStyles,
|
|
36
|
-
|
|
37
|
-
|
|
26
|
+
markFormulaXPerf: () => markFormulaXPerf,
|
|
27
|
+
measureFormulaXPerf: () => measureFormulaXPerf,
|
|
38
28
|
mountFormulaXEditor: () => mountFormulaXEditor,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
29
|
+
preloadFormulaXEditor: () => preloadFormulaXEditor,
|
|
30
|
+
recordFormulaXPerfPoint: () => recordFormulaXPerfPoint,
|
|
31
|
+
renderFormulaXEditorLoadingState: () => renderFormulaXEditorLoadingState,
|
|
32
|
+
scheduleFormulaXEditorPreload: () => scheduleFormulaXEditorPreload,
|
|
33
|
+
waitForFormulaXAnimationFrame: () => waitForFormulaXAnimationFrame
|
|
42
34
|
});
|
|
43
35
|
module.exports = __toCommonJS(index_exports);
|
|
44
36
|
|
|
45
37
|
// src/formula-modal.ts
|
|
46
38
|
var import_core = require("@formulaxjs/core");
|
|
47
|
-
var
|
|
39
|
+
var import_kity_runtime2 = require("@formulaxjs/kity-runtime");
|
|
40
|
+
var import_renderer = require("@formulaxjs/renderer");
|
|
41
|
+
var import_renderer_kity = require("@formulaxjs/renderer-kity");
|
|
48
42
|
|
|
49
|
-
// src/
|
|
50
|
-
var
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
43
|
+
// src/perf.ts
|
|
44
|
+
var import_kity_runtime = require("@formulaxjs/kity-runtime");
|
|
45
|
+
function getPerfHost() {
|
|
46
|
+
return globalThis;
|
|
47
|
+
}
|
|
48
|
+
function getPerfState() {
|
|
49
|
+
const host = getPerfHost();
|
|
50
|
+
host.__FORMULAX_PERF_STATE__ ??= {
|
|
51
|
+
reportedMeasureCount: 0,
|
|
52
|
+
reportScheduled: false
|
|
53
|
+
};
|
|
54
|
+
return host.__FORMULAX_PERF_STATE__;
|
|
55
|
+
}
|
|
56
|
+
function hasPerfSupport() {
|
|
57
|
+
return typeof performance !== "undefined" && typeof performance.mark === "function" && typeof performance.measure === "function" && typeof performance.getEntriesByType === "function";
|
|
58
|
+
}
|
|
59
|
+
function isPerfDebugEnabled() {
|
|
60
|
+
return getPerfHost().__FORMULAX_PERF__ === true;
|
|
61
|
+
}
|
|
62
|
+
function schedulePerfReport() {
|
|
63
|
+
if (!hasPerfSupport() || !isPerfDebugEnabled()) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const state = getPerfState();
|
|
67
|
+
if (state.reportScheduled) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
state.reportScheduled = true;
|
|
71
|
+
queueMicrotask(() => {
|
|
72
|
+
state.reportScheduled = false;
|
|
73
|
+
const entries = performance.getEntriesByType("measure").filter((entry) => entry.name.startsWith("fx:")).sort((left, right) => left.startTime - right.startTime);
|
|
74
|
+
const nextEntries = entries.slice(state.reportedMeasureCount);
|
|
75
|
+
state.reportedMeasureCount = entries.length;
|
|
76
|
+
if (!nextEntries.length) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
console.table(nextEntries.map((entry) => ({
|
|
80
|
+
name: entry.name,
|
|
81
|
+
duration: Number(entry.duration.toFixed(2)),
|
|
82
|
+
startTime: Number(entry.startTime.toFixed(2))
|
|
83
|
+
})));
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
function markFormulaXPerf(name) {
|
|
87
|
+
if (!hasPerfSupport()) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
const markName = `${name}::${Date.now()}::${Math.random().toString(36).slice(2, 8)}`;
|
|
91
|
+
performance.mark(markName);
|
|
92
|
+
return markName;
|
|
93
|
+
}
|
|
94
|
+
function measureFormulaXPerf(name, startMark, endMark) {
|
|
95
|
+
if (!hasPerfSupport() || !startMark) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
const resolvedEndMark = endMark ?? markFormulaXPerf(`${name}:end`);
|
|
99
|
+
if (!resolvedEndMark) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
performance.measure(name, startMark, resolvedEndMark);
|
|
103
|
+
schedulePerfReport();
|
|
104
|
+
return resolvedEndMark;
|
|
105
|
+
}
|
|
106
|
+
function recordFormulaXPerfPoint(name) {
|
|
107
|
+
const markName = markFormulaXPerf(name);
|
|
108
|
+
if (!markName) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
measureFormulaXPerf(name, markName, markName);
|
|
112
|
+
clearFormulaXPerfMarks(markName);
|
|
113
|
+
}
|
|
114
|
+
function clearFormulaXPerfMarks(...marks) {
|
|
115
|
+
if (!hasPerfSupport()) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
for (const mark of marks) {
|
|
119
|
+
if (!mark) {
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
performance.clearMarks(mark);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
async function preloadFormulaXEditor() {
|
|
126
|
+
await (0, import_kity_runtime.ensureKityRuntime)();
|
|
127
|
+
}
|
|
128
|
+
function scheduleFormulaXEditorPreload(mode, target) {
|
|
129
|
+
if (mode === false || typeof window === "undefined") {
|
|
130
|
+
return () => void 0;
|
|
131
|
+
}
|
|
132
|
+
let disposed = false;
|
|
133
|
+
let triggered = false;
|
|
134
|
+
const cleanupCallbacks = [];
|
|
135
|
+
const trigger = () => {
|
|
136
|
+
if (disposed || triggered) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
triggered = true;
|
|
140
|
+
while (cleanupCallbacks.length) {
|
|
141
|
+
cleanupCallbacks.pop()?.();
|
|
142
|
+
}
|
|
143
|
+
void preloadFormulaXEditor();
|
|
144
|
+
};
|
|
145
|
+
if (mode === "idle") {
|
|
146
|
+
const host = getPerfHost();
|
|
147
|
+
if (typeof host.requestIdleCallback === "function") {
|
|
148
|
+
const handle = host.requestIdleCallback(() => {
|
|
149
|
+
trigger();
|
|
150
|
+
});
|
|
151
|
+
cleanupCallbacks.push(() => {
|
|
152
|
+
host.cancelIdleCallback?.(handle);
|
|
153
|
+
});
|
|
154
|
+
} else {
|
|
155
|
+
const handle = window.setTimeout(() => {
|
|
156
|
+
trigger();
|
|
157
|
+
}, 1);
|
|
158
|
+
cleanupCallbacks.push(() => {
|
|
159
|
+
window.clearTimeout(handle);
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
return () => {
|
|
163
|
+
disposed = true;
|
|
164
|
+
while (cleanupCallbacks.length) {
|
|
165
|
+
cleanupCallbacks.pop()?.();
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
if (target && "addEventListener" in target && "removeEventListener" in target) {
|
|
170
|
+
const eventTarget = target;
|
|
171
|
+
const onActivate = () => {
|
|
172
|
+
trigger();
|
|
173
|
+
};
|
|
174
|
+
eventTarget.addEventListener("pointerenter", onActivate, { once: true, passive: true });
|
|
175
|
+
eventTarget.addEventListener("focusin", onActivate, { once: true });
|
|
176
|
+
cleanupCallbacks.push(() => {
|
|
177
|
+
eventTarget.removeEventListener("pointerenter", onActivate);
|
|
178
|
+
eventTarget.removeEventListener("focusin", onActivate);
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
return () => {
|
|
182
|
+
disposed = true;
|
|
183
|
+
while (cleanupCallbacks.length) {
|
|
184
|
+
cleanupCallbacks.pop()?.();
|
|
185
|
+
}
|
|
71
186
|
};
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
' role="button"',
|
|
81
|
-
' tabindex="0"',
|
|
82
|
-
serializedAttributes.length ? ` ${serializedAttributes.join(" ")}` : "",
|
|
83
|
-
">",
|
|
84
|
-
options.renderHtml ?? `<span class="${escapeAttribute(className)}__render">${escapeHtml(latex || "\\square")}</span>`,
|
|
85
|
-
"</span>"
|
|
86
|
-
].join("");
|
|
87
|
-
}
|
|
88
|
-
function mergeInlineStyles(existingStyle, nextStyle) {
|
|
89
|
-
const existing = existingStyle.trim().replace(/;+\s*$/, "");
|
|
90
|
-
const next = nextStyle.trim().replace(/;+\s*$/, "");
|
|
91
|
-
if (!existing) return next;
|
|
92
|
-
if (!next) return existing;
|
|
93
|
-
return `${existing}; ${next}`;
|
|
94
|
-
}
|
|
95
|
-
function createFormulaElement(ownerDocument, latex, options = {}) {
|
|
96
|
-
const wrapper = ownerDocument.createElement("span");
|
|
97
|
-
wrapper.innerHTML = createFormulaMarkup(latex, options);
|
|
98
|
-
return wrapper.firstElementChild;
|
|
99
|
-
}
|
|
100
|
-
function replaceFormulaElement(target, latex, options = {}) {
|
|
101
|
-
const next = createFormulaElement(target.ownerDocument ?? document, latex, options);
|
|
102
|
-
if (!next) return null;
|
|
103
|
-
target.replaceWith(next);
|
|
104
|
-
return next;
|
|
105
|
-
}
|
|
106
|
-
function getFormulaLatexFromElement(element, attributeName = DEFAULT_FORMULA_ATTRIBUTE) {
|
|
107
|
-
return element.getAttribute(attributeName) ?? element.getAttribute("data-latex") ?? "";
|
|
108
|
-
}
|
|
109
|
-
function isFormulaElement(node) {
|
|
110
|
-
if (!node || typeof node !== "object") return false;
|
|
111
|
-
const element = node;
|
|
112
|
-
return typeof element.getAttribute === "function" && element.getAttribute(FORMULA_FLAG_ATTRIBUTE) === "true";
|
|
113
|
-
}
|
|
114
|
-
function findFormulaElement(node) {
|
|
115
|
-
if (!node) return null;
|
|
116
|
-
const element = node.nodeType === 1 ? node : node.parentElement;
|
|
117
|
-
return element?.closest?.(`[${FORMULA_FLAG_ATTRIBUTE}="true"]`);
|
|
187
|
+
}
|
|
188
|
+
function waitForFormulaXAnimationFrame() {
|
|
189
|
+
if (typeof window === "undefined" || typeof window.requestAnimationFrame !== "function") {
|
|
190
|
+
return Promise.resolve();
|
|
191
|
+
}
|
|
192
|
+
return new Promise((resolve) => {
|
|
193
|
+
window.requestAnimationFrame(() => resolve());
|
|
194
|
+
});
|
|
118
195
|
}
|
|
119
196
|
|
|
120
197
|
// src/formula-modal.ts
|
|
@@ -255,8 +332,7 @@ var formulaXModalStyles = `
|
|
|
255
332
|
.fx-formula-kity-host .kf-editor svg text,
|
|
256
333
|
.fx-formula-kity-host .kf-editor-ui-area-item-text,
|
|
257
334
|
.fx-formula-kity-host .kf-editor-ui-box-item-text,
|
|
258
|
-
.fx-formula-kity-host .kf-editor-ui-box-item-val
|
|
259
|
-
.formulax-math__render {
|
|
335
|
+
.fx-formula-kity-host .kf-editor-ui-box-item-val {
|
|
260
336
|
font-family: "KF AMS MAIN", "Cambria Math", "Latin Modern Math", "Times New Roman", serif !important;
|
|
261
337
|
}
|
|
262
338
|
|
|
@@ -331,60 +407,35 @@ var formulaXModalStyles = `
|
|
|
331
407
|
background: #2563eb;
|
|
332
408
|
color: #fff;
|
|
333
409
|
}
|
|
334
|
-
|
|
335
|
-
.formulax-math {
|
|
336
|
-
display: inline-flex;
|
|
337
|
-
align-items: center;
|
|
338
|
-
vertical-align: middle;
|
|
339
|
-
line-height: 1;
|
|
340
|
-
padding: 0 2px;
|
|
341
|
-
margin: 0 1px;
|
|
342
|
-
border-radius: 3px;
|
|
343
|
-
background: transparent;
|
|
344
|
-
cursor: pointer;
|
|
345
|
-
user-select: none;
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
.formulax-math:hover {
|
|
349
|
-
outline: 1px solid rgba(37, 99, 235, 0.35);
|
|
350
|
-
background: rgba(37, 99, 235, 0.06);
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
.formulax-math__svg {
|
|
354
|
-
display: inline-block;
|
|
355
|
-
flex: 0 0 auto;
|
|
356
|
-
max-width: 100%;
|
|
357
|
-
vertical-align: -0.35em;
|
|
358
|
-
pointer-events: none;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
.formulax-math__image {
|
|
362
|
-
display: inline-block;
|
|
363
|
-
max-width: 100%;
|
|
364
|
-
height: auto;
|
|
365
|
-
vertical-align: middle;
|
|
366
|
-
pointer-events: none;
|
|
367
|
-
}
|
|
368
410
|
`;
|
|
369
411
|
function ensureFormulaXModalStyles(doc = document) {
|
|
412
|
+
(0, import_renderer.ensureFormulaXBaseStyles)(doc);
|
|
370
413
|
if (doc.getElementById(STYLE_ID)) return;
|
|
371
414
|
const style = doc.createElement("style");
|
|
372
415
|
style.id = STYLE_ID;
|
|
373
416
|
style.textContent = formulaXModalStyles;
|
|
374
417
|
doc.head.appendChild(style);
|
|
375
418
|
}
|
|
376
|
-
function
|
|
377
|
-
let destroyed = false;
|
|
378
|
-
let latestLatex = options.initialLatex ?? "";
|
|
379
|
-
let handle = null;
|
|
380
|
-
const initialLatex = latestLatex.trim() ? latestLatex : EMPTY_FORMULA_PLACEHOLDER;
|
|
419
|
+
function renderFormulaXEditorLoadingState(root) {
|
|
381
420
|
root.classList.add("fx-formula-kity-host");
|
|
382
421
|
root.innerHTML = `
|
|
383
422
|
<div class="fx-formula-editor-loading" role="status" aria-live="polite">
|
|
384
423
|
Loading FormulaX editor...
|
|
385
424
|
</div>
|
|
386
425
|
`;
|
|
387
|
-
|
|
426
|
+
}
|
|
427
|
+
function mountFormulaXEditor(root, options = {}) {
|
|
428
|
+
recordFormulaXPerfPoint("fx:formula-editor:mount:start");
|
|
429
|
+
const mountStart = markFormulaXPerf("fx:formula-editor:mount:start:scope");
|
|
430
|
+
let destroyed = false;
|
|
431
|
+
let latestLatex = options.initialLatex ?? "";
|
|
432
|
+
let handle = null;
|
|
433
|
+
const initialLatex = latestLatex.trim() ? latestLatex : EMPTY_FORMULA_PLACEHOLDER;
|
|
434
|
+
renderFormulaXEditorLoadingState(root);
|
|
435
|
+
const loadingVisibleMark = markFormulaXPerf("fx:formula-editor:loading-visible");
|
|
436
|
+
measureFormulaXPerf("fx:formula-editor:loading-visible", mountStart, loadingVisibleMark);
|
|
437
|
+
clearFormulaXPerfMarks(loadingVisibleMark);
|
|
438
|
+
const readyPromise = (0, import_kity_runtime2.mountKityEditor)(root, {
|
|
388
439
|
initialLatex,
|
|
389
440
|
height: options.height ?? "100%",
|
|
390
441
|
autofocus: options.autofocus ?? true,
|
|
@@ -397,6 +448,9 @@ function mountFormulaXEditor(root, options = {}) {
|
|
|
397
448
|
nextHandle.destroy();
|
|
398
449
|
throw new Error("FormulaX editor mount cancelled");
|
|
399
450
|
}
|
|
451
|
+
const readyMark = markFormulaXPerf("fx:kity-editor:ready");
|
|
452
|
+
measureFormulaXPerf("fx:kity-editor:ready", mountStart, readyMark);
|
|
453
|
+
clearFormulaXPerfMarks(readyMark);
|
|
400
454
|
handle = nextHandle;
|
|
401
455
|
return nextHandle;
|
|
402
456
|
}).catch((error) => {
|
|
@@ -405,11 +459,13 @@ function mountFormulaXEditor(root, options = {}) {
|
|
|
405
459
|
root.innerHTML = `
|
|
406
460
|
<div class="fx-formula-editor-error">
|
|
407
461
|
Failed to load FormulaX editor.
|
|
408
|
-
<pre>${escapeHtml(error instanceof Error ? error.message : String(error))}</pre>
|
|
462
|
+
<pre>${(0, import_renderer.escapeHtml)(error instanceof Error ? error.message : String(error))}</pre>
|
|
409
463
|
</div>
|
|
410
464
|
`;
|
|
411
465
|
}
|
|
412
466
|
throw error;
|
|
467
|
+
}).finally(() => {
|
|
468
|
+
clearFormulaXPerfMarks(mountStart);
|
|
413
469
|
});
|
|
414
470
|
const getCurrentLatex = async () => {
|
|
415
471
|
const readyHandle = handle ?? await readyPromise;
|
|
@@ -435,8 +491,8 @@ function mountFormulaXEditor(root, options = {}) {
|
|
|
435
491
|
},
|
|
436
492
|
async getRenderHtml() {
|
|
437
493
|
await readyPromise;
|
|
438
|
-
await
|
|
439
|
-
return
|
|
494
|
+
await (0, import_renderer_kity.waitForKityFormulaSvgLayout)(root);
|
|
495
|
+
return (0, import_renderer_kity.serializeKityFormulaFromRoot)(root);
|
|
440
496
|
},
|
|
441
497
|
destroy() {
|
|
442
498
|
if (destroyed) return;
|
|
@@ -486,325 +542,18 @@ async function tryReadLatexFromKityHandle(handle) {
|
|
|
486
542
|
}
|
|
487
543
|
return null;
|
|
488
544
|
}
|
|
489
|
-
function renderCurrentFormulaAsSvgHtml(root) {
|
|
490
|
-
const svg = findFormulaSvg(root);
|
|
491
|
-
if (!svg) {
|
|
492
|
-
return "";
|
|
493
|
-
}
|
|
494
|
-
return serializeSvgForInsertion(svg);
|
|
495
|
-
}
|
|
496
|
-
async function waitForFormulaSvgLayout(root) {
|
|
497
|
-
const doc = root.ownerDocument ?? document;
|
|
498
|
-
const view = doc.defaultView ?? window;
|
|
499
|
-
await waitForDocumentFonts(doc);
|
|
500
|
-
let previous = readRenderedFormulaBox(root);
|
|
501
|
-
for (let attempt = 0; attempt < 4; attempt += 1) {
|
|
502
|
-
await waitForAnimationFrame(view);
|
|
503
|
-
const current = readRenderedFormulaBox(root);
|
|
504
|
-
if (previous && current && areSvgBoxesClose(previous, current)) {
|
|
505
|
-
return;
|
|
506
|
-
}
|
|
507
|
-
previous = current;
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
function findFormulaSvg(root) {
|
|
511
|
-
return root.querySelector(
|
|
512
|
-
".kf-editor-edit-area svg, .kf-editor-canvas-container svg, svg"
|
|
513
|
-
);
|
|
514
|
-
}
|
|
515
|
-
function readRenderedFormulaBox(root) {
|
|
516
|
-
const svg = findFormulaSvg(root);
|
|
517
|
-
if (!svg) {
|
|
518
|
-
return null;
|
|
519
|
-
}
|
|
520
|
-
return getInlineSvgContent(svg)?.box ?? readSvgBox(svg);
|
|
521
|
-
}
|
|
522
|
-
function areSvgBoxesClose(left, right) {
|
|
523
|
-
return Math.abs(left.x - right.x) < 0.01 && Math.abs(left.y - right.y) < 0.01 && Math.abs(left.width - right.width) < 0.01 && Math.abs(left.height - right.height) < 0.01;
|
|
524
|
-
}
|
|
525
|
-
async function waitForDocumentFonts(doc) {
|
|
526
|
-
if (!doc.fonts?.ready) {
|
|
527
|
-
return;
|
|
528
|
-
}
|
|
529
|
-
try {
|
|
530
|
-
await doc.fonts.ready;
|
|
531
|
-
} catch {
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
function waitForAnimationFrame(view) {
|
|
535
|
-
return new Promise((resolve) => {
|
|
536
|
-
view.requestAnimationFrame(() => resolve());
|
|
537
|
-
});
|
|
538
|
-
}
|
|
539
|
-
function serializeSvgForInsertion(svg) {
|
|
540
|
-
const content = getInlineSvgContent(svg);
|
|
541
|
-
const inlineViewport = content ? createInlineSvgViewport(content.box) : null;
|
|
542
|
-
const clone = content && inlineViewport ? createInlineSvgClone(svg, content, inlineViewport) : svg.cloneNode(true);
|
|
543
|
-
uniquifySvgIds(clone);
|
|
544
|
-
sizeSvgForInlineDisplay(clone, svg, inlineViewport);
|
|
545
|
-
clone.removeAttribute("id");
|
|
546
|
-
clone.removeAttribute("xmlns");
|
|
547
|
-
clone.removeAttribute("xmlns:xlink");
|
|
548
|
-
clone.setAttribute("class", mergeClassNames(clone.getAttribute("class"), "formulax-math__svg"));
|
|
549
|
-
clone.setAttribute("focusable", "false");
|
|
550
|
-
clone.setAttribute("aria-hidden", "true");
|
|
551
|
-
clone.setAttribute("preserveAspectRatio", clone.getAttribute("preserveAspectRatio") || "xMinYMin meet");
|
|
552
|
-
return new XMLSerializer().serializeToString(clone);
|
|
553
|
-
}
|
|
554
|
-
function getInlineSvgContent(svg) {
|
|
555
|
-
const candidates = [
|
|
556
|
-
'[data-root="true"] > g[data-type="kf-editor-exp-content-box"]',
|
|
557
|
-
'g[data-type="kf-editor-exp-content-box"]',
|
|
558
|
-
'g[data-type="kf-container"]',
|
|
559
|
-
"svg > g, g"
|
|
560
|
-
];
|
|
561
|
-
for (const selector of candidates) {
|
|
562
|
-
const content = svg.querySelector(selector);
|
|
563
|
-
const rootSpace = content ? readSvgBoxInRootSpace(content) : null;
|
|
564
|
-
if (content && rootSpace) {
|
|
565
|
-
return {
|
|
566
|
-
root: content,
|
|
567
|
-
box: rootSpace.box,
|
|
568
|
-
matrix: rootSpace.matrix
|
|
569
|
-
};
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
return null;
|
|
573
|
-
}
|
|
574
|
-
function readSvgBoxInRootSpace(element) {
|
|
575
|
-
const box = readSvgBox(element);
|
|
576
|
-
const matrix = getSvgRootSpaceMatrix(element);
|
|
577
|
-
if (!box || !matrix) {
|
|
578
|
-
return null;
|
|
579
|
-
}
|
|
580
|
-
const points = [
|
|
581
|
-
{ x: box.x, y: box.y },
|
|
582
|
-
{ x: box.x + box.width, y: box.y },
|
|
583
|
-
{ x: box.x, y: box.y + box.height },
|
|
584
|
-
{ x: box.x + box.width, y: box.y + box.height }
|
|
585
|
-
].map((point) => ({
|
|
586
|
-
x: matrix.a * point.x + matrix.c * point.y + matrix.e,
|
|
587
|
-
y: matrix.b * point.x + matrix.d * point.y + matrix.f
|
|
588
|
-
}));
|
|
589
|
-
const xs = points.map((point) => point.x);
|
|
590
|
-
const ys = points.map((point) => point.y);
|
|
591
|
-
const x = Math.min(...xs);
|
|
592
|
-
const y = Math.min(...ys);
|
|
593
|
-
const width = Math.max(...xs) - x;
|
|
594
|
-
const height = Math.max(...ys) - y;
|
|
595
|
-
if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {
|
|
596
|
-
return null;
|
|
597
|
-
}
|
|
598
|
-
return {
|
|
599
|
-
box: { x, y, width, height },
|
|
600
|
-
matrix
|
|
601
|
-
};
|
|
602
|
-
}
|
|
603
|
-
function getSvgRootSpaceMatrix(element) {
|
|
604
|
-
const elementMatrix = typeof element.getCTM === "function" ? element.getCTM() : null;
|
|
605
|
-
const rootMatrix = typeof element.ownerSVGElement?.getCTM === "function" ? element.ownerSVGElement.getCTM() : null;
|
|
606
|
-
if (!elementMatrix) {
|
|
607
|
-
return null;
|
|
608
|
-
}
|
|
609
|
-
return rootMatrix ? multiplySvgMatrices(invertSvgMatrix(rootMatrix), elementMatrix) : toSvgMatrixLike(elementMatrix);
|
|
610
|
-
}
|
|
611
|
-
function invertSvgMatrix(matrix) {
|
|
612
|
-
const determinant = matrix.a * matrix.d - matrix.b * matrix.c;
|
|
613
|
-
if (!Number.isFinite(determinant) || determinant === 0) {
|
|
614
|
-
return {
|
|
615
|
-
a: 1,
|
|
616
|
-
b: 0,
|
|
617
|
-
c: 0,
|
|
618
|
-
d: 1,
|
|
619
|
-
e: 0,
|
|
620
|
-
f: 0
|
|
621
|
-
};
|
|
622
|
-
}
|
|
623
|
-
return {
|
|
624
|
-
a: matrix.d / determinant,
|
|
625
|
-
b: -matrix.b / determinant,
|
|
626
|
-
c: -matrix.c / determinant,
|
|
627
|
-
d: matrix.a / determinant,
|
|
628
|
-
e: (matrix.c * matrix.f - matrix.d * matrix.e) / determinant,
|
|
629
|
-
f: (matrix.b * matrix.e - matrix.a * matrix.f) / determinant
|
|
630
|
-
};
|
|
631
|
-
}
|
|
632
|
-
function multiplySvgMatrices(left, right) {
|
|
633
|
-
return {
|
|
634
|
-
a: left.a * right.a + left.c * right.b,
|
|
635
|
-
b: left.b * right.a + left.d * right.b,
|
|
636
|
-
c: left.a * right.c + left.c * right.d,
|
|
637
|
-
d: left.b * right.c + left.d * right.d,
|
|
638
|
-
e: left.a * right.e + left.c * right.f + left.e,
|
|
639
|
-
f: left.b * right.e + left.d * right.f + left.f
|
|
640
|
-
};
|
|
641
|
-
}
|
|
642
|
-
function toSvgMatrixLike(matrix) {
|
|
643
|
-
return {
|
|
644
|
-
a: matrix.a,
|
|
645
|
-
b: matrix.b,
|
|
646
|
-
c: matrix.c,
|
|
647
|
-
d: matrix.d,
|
|
648
|
-
e: matrix.e,
|
|
649
|
-
f: matrix.f
|
|
650
|
-
};
|
|
651
|
-
}
|
|
652
|
-
function readSvgBox(element) {
|
|
653
|
-
if (typeof element.getBBox !== "function") {
|
|
654
|
-
return null;
|
|
655
|
-
}
|
|
656
|
-
try {
|
|
657
|
-
const box = element.getBBox();
|
|
658
|
-
if (!Number.isFinite(box.width) || !Number.isFinite(box.height) || box.width <= 0 || box.height <= 0) {
|
|
659
|
-
return null;
|
|
660
|
-
}
|
|
661
|
-
return {
|
|
662
|
-
x: box.x,
|
|
663
|
-
y: box.y,
|
|
664
|
-
width: box.width,
|
|
665
|
-
height: box.height
|
|
666
|
-
};
|
|
667
|
-
} catch {
|
|
668
|
-
return null;
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
function createInlineSvgViewport(contentBox) {
|
|
672
|
-
const edgePadding = Math.max(0.5, Math.min(contentBox.width, contentBox.height) * 6e-3);
|
|
673
|
-
const inset = edgePadding / 2;
|
|
674
|
-
return {
|
|
675
|
-
x: contentBox.x - inset,
|
|
676
|
-
y: contentBox.y - inset,
|
|
677
|
-
width: contentBox.width + edgePadding,
|
|
678
|
-
height: contentBox.height + edgePadding
|
|
679
|
-
};
|
|
680
|
-
}
|
|
681
|
-
function createInlineSvgClone(source, content, viewport) {
|
|
682
|
-
const clone = source.cloneNode(false);
|
|
683
|
-
const ownerDocument = source.ownerDocument;
|
|
684
|
-
copySvgRootAttributes(source, clone);
|
|
685
|
-
clone.setAttribute(
|
|
686
|
-
"viewBox",
|
|
687
|
-
`0 0 ${roundLength(viewport.width)} ${roundLength(viewport.height)}`
|
|
688
|
-
);
|
|
689
|
-
Array.from(source.children).forEach((child) => {
|
|
690
|
-
if (child.tagName.toLowerCase() === "defs") {
|
|
691
|
-
clone.appendChild(child.cloneNode(true));
|
|
692
|
-
}
|
|
693
|
-
});
|
|
694
|
-
const wrapper = ownerDocument.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
695
|
-
wrapper.setAttribute(
|
|
696
|
-
"transform",
|
|
697
|
-
`translate(${roundLength(-viewport.x)} ${roundLength(-viewport.y)})`
|
|
698
|
-
);
|
|
699
|
-
const flattened = ownerDocument.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
700
|
-
flattened.setAttribute(
|
|
701
|
-
"transform",
|
|
702
|
-
`matrix(${roundLength(content.matrix.a)} ${roundLength(content.matrix.b)} ${roundLength(content.matrix.c)} ${roundLength(content.matrix.d)} ${roundLength(content.matrix.e)} ${roundLength(content.matrix.f)})`
|
|
703
|
-
);
|
|
704
|
-
flattened.appendChild(content.root.cloneNode(true));
|
|
705
|
-
wrapper.appendChild(flattened);
|
|
706
|
-
clone.appendChild(wrapper);
|
|
707
|
-
return clone;
|
|
708
|
-
}
|
|
709
|
-
function copySvgRootAttributes(source, target) {
|
|
710
|
-
const excluded = /* @__PURE__ */ new Set([
|
|
711
|
-
"id",
|
|
712
|
-
"width",
|
|
713
|
-
"height",
|
|
714
|
-
"viewBox",
|
|
715
|
-
"class",
|
|
716
|
-
"focusable",
|
|
717
|
-
"aria-hidden",
|
|
718
|
-
"xmlns",
|
|
719
|
-
"xmlns:xlink"
|
|
720
|
-
]);
|
|
721
|
-
Array.from(source.attributes).forEach((attribute) => {
|
|
722
|
-
if (excluded.has(attribute.name)) return;
|
|
723
|
-
target.setAttribute(attribute.name, attribute.value);
|
|
724
|
-
});
|
|
725
|
-
}
|
|
726
|
-
function sizeSvgForInlineDisplay(clone, source, viewport) {
|
|
727
|
-
const viewBox = clone.viewBox?.baseVal;
|
|
728
|
-
const rect = source.getBoundingClientRect();
|
|
729
|
-
const width = viewport?.width || viewBox?.width || rect.width || Number(clone.getAttribute("width")) || 1;
|
|
730
|
-
const height = viewport?.height || viewBox?.height || rect.height || Number(clone.getAttribute("height")) || 1;
|
|
731
|
-
const ratio = Math.max(0.1, width / Math.max(1, height));
|
|
732
|
-
const inlineHeightEm = 0.875;
|
|
733
|
-
const inlineWidthEm = Math.min(40, Math.max(0.75, ratio * inlineHeightEm));
|
|
734
|
-
clone.setAttribute("width", roundLength(width));
|
|
735
|
-
clone.setAttribute("height", roundLength(height));
|
|
736
|
-
clone.setAttribute(
|
|
737
|
-
"style",
|
|
738
|
-
mergeInlineStyles2(
|
|
739
|
-
clone.getAttribute("style"),
|
|
740
|
-
`width:${roundLength(inlineWidthEm)}em`,
|
|
741
|
-
`height:${inlineHeightEm}em`
|
|
742
|
-
)
|
|
743
|
-
);
|
|
744
|
-
}
|
|
745
|
-
function roundLength(value) {
|
|
746
|
-
return String(Math.round(value * 1e3) / 1e3);
|
|
747
|
-
}
|
|
748
|
-
function uniquifySvgIds(svg) {
|
|
749
|
-
const idMap = /* @__PURE__ */ new Map();
|
|
750
|
-
const prefix = `fx-${randomIdPrefix()}-`;
|
|
751
|
-
const elementsWithId = svg.querySelectorAll("[id]");
|
|
752
|
-
elementsWithId.forEach((element) => {
|
|
753
|
-
const id = element.getAttribute("id");
|
|
754
|
-
if (!id) return;
|
|
755
|
-
const nextId = `${prefix}${id}`;
|
|
756
|
-
idMap.set(id, nextId);
|
|
757
|
-
element.setAttribute("id", nextId);
|
|
758
|
-
});
|
|
759
|
-
if (!idMap.size) return;
|
|
760
|
-
svg.querySelectorAll("*").forEach((element) => {
|
|
761
|
-
Array.from(element.attributes).forEach((attribute) => {
|
|
762
|
-
const nextValue = rewriteSvgReferences(attribute.value, idMap);
|
|
763
|
-
if (nextValue !== attribute.value) {
|
|
764
|
-
element.setAttribute(attribute.name, nextValue);
|
|
765
|
-
}
|
|
766
|
-
});
|
|
767
|
-
});
|
|
768
|
-
}
|
|
769
|
-
function randomIdPrefix() {
|
|
770
|
-
return Math.random().toString(36).slice(2, 5).padEnd(3, "0");
|
|
771
|
-
}
|
|
772
|
-
function rewriteSvgReferences(value, idMap) {
|
|
773
|
-
let nextValue = value;
|
|
774
|
-
idMap.forEach((nextId, id) => {
|
|
775
|
-
nextValue = nextValue.replaceAll(`#${id}`, `#${nextId}`).replaceAll(`url(${id})`, `url(${nextId})`).replaceAll(`url(#${id})`, `url(#${nextId})`);
|
|
776
|
-
});
|
|
777
|
-
return nextValue;
|
|
778
|
-
}
|
|
779
|
-
function mergeClassNames(...values) {
|
|
780
|
-
return values.flatMap((value) => value?.split(/\s+/) ?? []).filter(Boolean).filter((value, index, list) => list.indexOf(value) === index).join(" ");
|
|
781
|
-
}
|
|
782
|
-
function mergeInlineStyles2(...values) {
|
|
783
|
-
return values.flatMap((value) => value?.split(";") ?? []).map((value) => value.trim()).filter(Boolean).join("; ");
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
// src/index.ts
|
|
787
|
-
var import_kity_runtime2 = require("@formulaxjs/kity-runtime");
|
|
788
545
|
// Annotate the CommonJS export names for ESM import in node:
|
|
789
546
|
0 && (module.exports = {
|
|
790
|
-
|
|
791
|
-
DEFAULT_FORMULA_CLASS,
|
|
792
|
-
FORMULA_FLAG_ATTRIBUTE,
|
|
793
|
-
FormulaXEditor,
|
|
794
|
-
createFormulaElement,
|
|
795
|
-
createFormulaMarkup,
|
|
796
|
-
createKityEditor,
|
|
547
|
+
clearFormulaXPerfMarks,
|
|
797
548
|
ensureFormulaXModalStyles,
|
|
798
|
-
ensureKityRuntime,
|
|
799
|
-
escapeAttribute,
|
|
800
|
-
escapeHtml,
|
|
801
|
-
findFormulaElement,
|
|
802
549
|
formulaXModalStyles,
|
|
803
|
-
|
|
804
|
-
|
|
550
|
+
markFormulaXPerf,
|
|
551
|
+
measureFormulaXPerf,
|
|
805
552
|
mountFormulaXEditor,
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
553
|
+
preloadFormulaXEditor,
|
|
554
|
+
recordFormulaXPerfPoint,
|
|
555
|
+
renderFormulaXEditorLoadingState,
|
|
556
|
+
scheduleFormulaXEditorPreload,
|
|
557
|
+
waitForFormulaXAnimationFrame
|
|
809
558
|
});
|
|
810
559
|
//# sourceMappingURL=index.cjs.map
|