@formulaxjs/editor 0.2.0 → 0.3.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/README.md +66 -34
- package/dist/index.cjs +196 -445
- package/dist/index.cjs.map +1 -1
- package/dist/index.global.js +1241 -804
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +188 -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
|
-
function createFormulaMarkup(latex, options = {}) {
|
|
60
|
-
const attributeName = options.attributeName ?? DEFAULT_FORMULA_ATTRIBUTE;
|
|
61
|
-
const className = options.className ?? DEFAULT_FORMULA_CLASS;
|
|
62
|
-
const displayClass = options.displayMode ? `${className} ${className}--block` : className;
|
|
63
|
-
const safeLatex = escapeAttribute(latex);
|
|
64
|
-
const cursorStyle = options.cursorStyle?.trim() || "pointer";
|
|
65
|
-
const extraAttributes = {
|
|
66
|
-
...options.extraAttributes ?? {},
|
|
67
|
-
style: mergeInlineStyles(
|
|
68
|
-
typeof options.extraAttributes?.style === "string" ? options.extraAttributes.style : "",
|
|
69
|
-
cursorStyle ? `cursor: ${cursorStyle}` : ""
|
|
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
|
|
71
53
|
};
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const
|
|
117
|
-
|
|
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
|
+
}
|
|
186
|
+
};
|
|
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
|
|
@@ -223,6 +300,8 @@ var formulaXModalStyles = `
|
|
|
223
300
|
}
|
|
224
301
|
|
|
225
302
|
.fx-formula-kity-host .kf-editor {
|
|
303
|
+
box-sizing: border-box;
|
|
304
|
+
width: 100%;
|
|
226
305
|
height: var(--fx-formula-editor-body-height) !important;
|
|
227
306
|
overflow: visible !important;
|
|
228
307
|
}
|
|
@@ -255,8 +334,7 @@ var formulaXModalStyles = `
|
|
|
255
334
|
.fx-formula-kity-host .kf-editor svg text,
|
|
256
335
|
.fx-formula-kity-host .kf-editor-ui-area-item-text,
|
|
257
336
|
.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 {
|
|
337
|
+
.fx-formula-kity-host .kf-editor-ui-box-item-val {
|
|
260
338
|
font-family: "KF AMS MAIN", "Cambria Math", "Latin Modern Math", "Times New Roman", serif !important;
|
|
261
339
|
}
|
|
262
340
|
|
|
@@ -331,60 +409,35 @@ var formulaXModalStyles = `
|
|
|
331
409
|
background: #2563eb;
|
|
332
410
|
color: #fff;
|
|
333
411
|
}
|
|
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
412
|
`;
|
|
369
413
|
function ensureFormulaXModalStyles(doc = document) {
|
|
414
|
+
(0, import_renderer.ensureFormulaXBaseStyles)(doc);
|
|
370
415
|
if (doc.getElementById(STYLE_ID)) return;
|
|
371
416
|
const style = doc.createElement("style");
|
|
372
417
|
style.id = STYLE_ID;
|
|
373
418
|
style.textContent = formulaXModalStyles;
|
|
374
419
|
doc.head.appendChild(style);
|
|
375
420
|
}
|
|
376
|
-
function
|
|
377
|
-
let destroyed = false;
|
|
378
|
-
let latestLatex = options.initialLatex ?? "";
|
|
379
|
-
let handle = null;
|
|
380
|
-
const initialLatex = latestLatex.trim() ? latestLatex : EMPTY_FORMULA_PLACEHOLDER;
|
|
421
|
+
function renderFormulaXEditorLoadingState(root) {
|
|
381
422
|
root.classList.add("fx-formula-kity-host");
|
|
382
423
|
root.innerHTML = `
|
|
383
424
|
<div class="fx-formula-editor-loading" role="status" aria-live="polite">
|
|
384
425
|
Loading FormulaX editor...
|
|
385
426
|
</div>
|
|
386
427
|
`;
|
|
387
|
-
|
|
428
|
+
}
|
|
429
|
+
function mountFormulaXEditor(root, options = {}) {
|
|
430
|
+
recordFormulaXPerfPoint("fx:formula-editor:mount:start");
|
|
431
|
+
const mountStart = markFormulaXPerf("fx:formula-editor:mount:start:scope");
|
|
432
|
+
let destroyed = false;
|
|
433
|
+
let latestLatex = options.initialLatex ?? "";
|
|
434
|
+
let handle = null;
|
|
435
|
+
const initialLatex = latestLatex.trim() ? latestLatex : EMPTY_FORMULA_PLACEHOLDER;
|
|
436
|
+
renderFormulaXEditorLoadingState(root);
|
|
437
|
+
const loadingVisibleMark = markFormulaXPerf("fx:formula-editor:loading-visible");
|
|
438
|
+
measureFormulaXPerf("fx:formula-editor:loading-visible", mountStart, loadingVisibleMark);
|
|
439
|
+
clearFormulaXPerfMarks(loadingVisibleMark);
|
|
440
|
+
const readyPromise = (0, import_kity_runtime2.mountKityEditor)(root, {
|
|
388
441
|
initialLatex,
|
|
389
442
|
height: options.height ?? "100%",
|
|
390
443
|
autofocus: options.autofocus ?? true,
|
|
@@ -397,6 +450,9 @@ function mountFormulaXEditor(root, options = {}) {
|
|
|
397
450
|
nextHandle.destroy();
|
|
398
451
|
throw new Error("FormulaX editor mount cancelled");
|
|
399
452
|
}
|
|
453
|
+
const readyMark = markFormulaXPerf("fx:kity-editor:ready");
|
|
454
|
+
measureFormulaXPerf("fx:kity-editor:ready", mountStart, readyMark);
|
|
455
|
+
clearFormulaXPerfMarks(readyMark);
|
|
400
456
|
handle = nextHandle;
|
|
401
457
|
return nextHandle;
|
|
402
458
|
}).catch((error) => {
|
|
@@ -405,11 +461,13 @@ function mountFormulaXEditor(root, options = {}) {
|
|
|
405
461
|
root.innerHTML = `
|
|
406
462
|
<div class="fx-formula-editor-error">
|
|
407
463
|
Failed to load FormulaX editor.
|
|
408
|
-
<pre>${escapeHtml(error instanceof Error ? error.message : String(error))}</pre>
|
|
464
|
+
<pre>${(0, import_renderer.escapeHtml)(error instanceof Error ? error.message : String(error))}</pre>
|
|
409
465
|
</div>
|
|
410
466
|
`;
|
|
411
467
|
}
|
|
412
468
|
throw error;
|
|
469
|
+
}).finally(() => {
|
|
470
|
+
clearFormulaXPerfMarks(mountStart);
|
|
413
471
|
});
|
|
414
472
|
const getCurrentLatex = async () => {
|
|
415
473
|
const readyHandle = handle ?? await readyPromise;
|
|
@@ -435,8 +493,8 @@ function mountFormulaXEditor(root, options = {}) {
|
|
|
435
493
|
},
|
|
436
494
|
async getRenderHtml() {
|
|
437
495
|
await readyPromise;
|
|
438
|
-
await
|
|
439
|
-
return
|
|
496
|
+
await (0, import_renderer_kity.waitForKityFormulaSvgLayout)(root);
|
|
497
|
+
return (0, import_renderer_kity.serializeKityFormulaFromRoot)(root);
|
|
440
498
|
},
|
|
441
499
|
destroy() {
|
|
442
500
|
if (destroyed) return;
|
|
@@ -486,325 +544,18 @@ async function tryReadLatexFromKityHandle(handle) {
|
|
|
486
544
|
}
|
|
487
545
|
return null;
|
|
488
546
|
}
|
|
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
547
|
// Annotate the CommonJS export names for ESM import in node:
|
|
789
548
|
0 && (module.exports = {
|
|
790
|
-
|
|
791
|
-
DEFAULT_FORMULA_CLASS,
|
|
792
|
-
FORMULA_FLAG_ATTRIBUTE,
|
|
793
|
-
FormulaXEditor,
|
|
794
|
-
createFormulaElement,
|
|
795
|
-
createFormulaMarkup,
|
|
796
|
-
createKityEditor,
|
|
549
|
+
clearFormulaXPerfMarks,
|
|
797
550
|
ensureFormulaXModalStyles,
|
|
798
|
-
ensureKityRuntime,
|
|
799
|
-
escapeAttribute,
|
|
800
|
-
escapeHtml,
|
|
801
|
-
findFormulaElement,
|
|
802
551
|
formulaXModalStyles,
|
|
803
|
-
|
|
804
|
-
|
|
552
|
+
markFormulaXPerf,
|
|
553
|
+
measureFormulaXPerf,
|
|
805
554
|
mountFormulaXEditor,
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
555
|
+
preloadFormulaXEditor,
|
|
556
|
+
recordFormulaXPerfPoint,
|
|
557
|
+
renderFormulaXEditorLoadingState,
|
|
558
|
+
scheduleFormulaXEditorPreload,
|
|
559
|
+
waitForFormulaXAnimationFrame
|
|
809
560
|
});
|
|
810
561
|
//# sourceMappingURL=index.cjs.map
|