@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/dist/index.js CHANGED
@@ -1,76 +1,164 @@
1
1
  // src/formula-modal.ts
2
2
  import { createEmptyState, parseLatex } from "@formulaxjs/core";
3
3
  import { mountKityEditor } from "@formulaxjs/kity-runtime";
4
+ import { escapeHtml, ensureFormulaXBaseStyles } from "@formulaxjs/renderer";
5
+ import {
6
+ serializeKityFormulaFromRoot,
7
+ waitForKityFormulaSvgLayout
8
+ } from "@formulaxjs/renderer-kity";
4
9
 
5
- // src/formula-node.ts
6
- var DEFAULT_FORMULA_ATTRIBUTE = "data-formulax-latex";
7
- var FORMULA_FLAG_ATTRIBUTE = "data-formulax";
8
- var DEFAULT_FORMULA_CLASS = "formulax-math";
9
- function escapeAttribute(value) {
10
- return value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
11
- }
12
- function escapeHtml(value) {
13
- return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
14
- }
15
- function createFormulaMarkup(latex, options = {}) {
16
- const attributeName = options.attributeName ?? DEFAULT_FORMULA_ATTRIBUTE;
17
- const className = options.className ?? DEFAULT_FORMULA_CLASS;
18
- const displayClass = options.displayMode ? `${className} ${className}--block` : className;
19
- const safeLatex = escapeAttribute(latex);
20
- const cursorStyle = options.cursorStyle?.trim() || "pointer";
21
- const extraAttributes = {
22
- ...options.extraAttributes ?? {},
23
- style: mergeInlineStyles(
24
- typeof options.extraAttributes?.style === "string" ? options.extraAttributes.style : "",
25
- cursorStyle ? `cursor: ${cursorStyle}` : ""
26
- )
10
+ // src/perf.ts
11
+ import { ensureKityRuntime } from "@formulaxjs/kity-runtime";
12
+ function getPerfHost() {
13
+ return globalThis;
14
+ }
15
+ function getPerfState() {
16
+ const host = getPerfHost();
17
+ host.__FORMULAX_PERF_STATE__ ??= {
18
+ reportedMeasureCount: 0,
19
+ reportScheduled: false
27
20
  };
28
- const serializedAttributes = Object.entries(extraAttributes).filter(([, value]) => value !== null && value !== void 0 && value !== false).map(([key, value]) => value === true ? key : `${key}="${escapeAttribute(String(value))}"`);
29
- return [
30
- "<span",
31
- ` class="${escapeAttribute(displayClass)}"`,
32
- ` ${FORMULA_FLAG_ATTRIBUTE}="true"`,
33
- ` ${attributeName}="${safeLatex}"`,
34
- ` data-latex="${safeLatex}"`,
35
- ' contenteditable="false"',
36
- ' role="button"',
37
- ' tabindex="0"',
38
- serializedAttributes.length ? ` ${serializedAttributes.join(" ")}` : "",
39
- ">",
40
- options.renderHtml ?? `<span class="${escapeAttribute(className)}__render">${escapeHtml(latex || "\\square")}</span>`,
41
- "</span>"
42
- ].join("");
43
- }
44
- function mergeInlineStyles(existingStyle, nextStyle) {
45
- const existing = existingStyle.trim().replace(/;+\s*$/, "");
46
- const next = nextStyle.trim().replace(/;+\s*$/, "");
47
- if (!existing) return next;
48
- if (!next) return existing;
49
- return `${existing}; ${next}`;
50
- }
51
- function createFormulaElement(ownerDocument, latex, options = {}) {
52
- const wrapper = ownerDocument.createElement("span");
53
- wrapper.innerHTML = createFormulaMarkup(latex, options);
54
- return wrapper.firstElementChild;
55
- }
56
- function replaceFormulaElement(target, latex, options = {}) {
57
- const next = createFormulaElement(target.ownerDocument ?? document, latex, options);
58
- if (!next) return null;
59
- target.replaceWith(next);
60
- return next;
61
- }
62
- function getFormulaLatexFromElement(element, attributeName = DEFAULT_FORMULA_ATTRIBUTE) {
63
- return element.getAttribute(attributeName) ?? element.getAttribute("data-latex") ?? "";
64
- }
65
- function isFormulaElement(node) {
66
- if (!node || typeof node !== "object") return false;
67
- const element = node;
68
- return typeof element.getAttribute === "function" && element.getAttribute(FORMULA_FLAG_ATTRIBUTE) === "true";
69
- }
70
- function findFormulaElement(node) {
71
- if (!node) return null;
72
- const element = node.nodeType === 1 ? node : node.parentElement;
73
- return element?.closest?.(`[${FORMULA_FLAG_ATTRIBUTE}="true"]`);
21
+ return host.__FORMULAX_PERF_STATE__;
22
+ }
23
+ function hasPerfSupport() {
24
+ return typeof performance !== "undefined" && typeof performance.mark === "function" && typeof performance.measure === "function" && typeof performance.getEntriesByType === "function";
25
+ }
26
+ function isPerfDebugEnabled() {
27
+ return getPerfHost().__FORMULAX_PERF__ === true;
28
+ }
29
+ function schedulePerfReport() {
30
+ if (!hasPerfSupport() || !isPerfDebugEnabled()) {
31
+ return;
32
+ }
33
+ const state = getPerfState();
34
+ if (state.reportScheduled) {
35
+ return;
36
+ }
37
+ state.reportScheduled = true;
38
+ queueMicrotask(() => {
39
+ state.reportScheduled = false;
40
+ const entries = performance.getEntriesByType("measure").filter((entry) => entry.name.startsWith("fx:")).sort((left, right) => left.startTime - right.startTime);
41
+ const nextEntries = entries.slice(state.reportedMeasureCount);
42
+ state.reportedMeasureCount = entries.length;
43
+ if (!nextEntries.length) {
44
+ return;
45
+ }
46
+ console.table(nextEntries.map((entry) => ({
47
+ name: entry.name,
48
+ duration: Number(entry.duration.toFixed(2)),
49
+ startTime: Number(entry.startTime.toFixed(2))
50
+ })));
51
+ });
52
+ }
53
+ function markFormulaXPerf(name) {
54
+ if (!hasPerfSupport()) {
55
+ return null;
56
+ }
57
+ const markName = `${name}::${Date.now()}::${Math.random().toString(36).slice(2, 8)}`;
58
+ performance.mark(markName);
59
+ return markName;
60
+ }
61
+ function measureFormulaXPerf(name, startMark, endMark) {
62
+ if (!hasPerfSupport() || !startMark) {
63
+ return null;
64
+ }
65
+ const resolvedEndMark = endMark ?? markFormulaXPerf(`${name}:end`);
66
+ if (!resolvedEndMark) {
67
+ return null;
68
+ }
69
+ performance.measure(name, startMark, resolvedEndMark);
70
+ schedulePerfReport();
71
+ return resolvedEndMark;
72
+ }
73
+ function recordFormulaXPerfPoint(name) {
74
+ const markName = markFormulaXPerf(name);
75
+ if (!markName) {
76
+ return;
77
+ }
78
+ measureFormulaXPerf(name, markName, markName);
79
+ clearFormulaXPerfMarks(markName);
80
+ }
81
+ function clearFormulaXPerfMarks(...marks) {
82
+ if (!hasPerfSupport()) {
83
+ return;
84
+ }
85
+ for (const mark of marks) {
86
+ if (!mark) {
87
+ continue;
88
+ }
89
+ performance.clearMarks(mark);
90
+ }
91
+ }
92
+ async function preloadFormulaXEditor() {
93
+ await ensureKityRuntime();
94
+ }
95
+ function scheduleFormulaXEditorPreload(mode, target) {
96
+ if (mode === false || typeof window === "undefined") {
97
+ return () => void 0;
98
+ }
99
+ let disposed = false;
100
+ let triggered = false;
101
+ const cleanupCallbacks = [];
102
+ const trigger = () => {
103
+ if (disposed || triggered) {
104
+ return;
105
+ }
106
+ triggered = true;
107
+ while (cleanupCallbacks.length) {
108
+ cleanupCallbacks.pop()?.();
109
+ }
110
+ void preloadFormulaXEditor();
111
+ };
112
+ if (mode === "idle") {
113
+ const host = getPerfHost();
114
+ if (typeof host.requestIdleCallback === "function") {
115
+ const handle = host.requestIdleCallback(() => {
116
+ trigger();
117
+ });
118
+ cleanupCallbacks.push(() => {
119
+ host.cancelIdleCallback?.(handle);
120
+ });
121
+ } else {
122
+ const handle = window.setTimeout(() => {
123
+ trigger();
124
+ }, 1);
125
+ cleanupCallbacks.push(() => {
126
+ window.clearTimeout(handle);
127
+ });
128
+ }
129
+ return () => {
130
+ disposed = true;
131
+ while (cleanupCallbacks.length) {
132
+ cleanupCallbacks.pop()?.();
133
+ }
134
+ };
135
+ }
136
+ if (target && "addEventListener" in target && "removeEventListener" in target) {
137
+ const eventTarget = target;
138
+ const onActivate = () => {
139
+ trigger();
140
+ };
141
+ eventTarget.addEventListener("pointerenter", onActivate, { once: true, passive: true });
142
+ eventTarget.addEventListener("focusin", onActivate, { once: true });
143
+ cleanupCallbacks.push(() => {
144
+ eventTarget.removeEventListener("pointerenter", onActivate);
145
+ eventTarget.removeEventListener("focusin", onActivate);
146
+ });
147
+ }
148
+ return () => {
149
+ disposed = true;
150
+ while (cleanupCallbacks.length) {
151
+ cleanupCallbacks.pop()?.();
152
+ }
153
+ };
154
+ }
155
+ function waitForFormulaXAnimationFrame() {
156
+ if (typeof window === "undefined" || typeof window.requestAnimationFrame !== "function") {
157
+ return Promise.resolve();
158
+ }
159
+ return new Promise((resolve) => {
160
+ window.requestAnimationFrame(() => resolve());
161
+ });
74
162
  }
75
163
 
76
164
  // src/formula-modal.ts
@@ -179,6 +267,8 @@ var formulaXModalStyles = `
179
267
  }
180
268
 
181
269
  .fx-formula-kity-host .kf-editor {
270
+ box-sizing: border-box;
271
+ width: 100%;
182
272
  height: var(--fx-formula-editor-body-height) !important;
183
273
  overflow: visible !important;
184
274
  }
@@ -211,8 +301,7 @@ var formulaXModalStyles = `
211
301
  .fx-formula-kity-host .kf-editor svg text,
212
302
  .fx-formula-kity-host .kf-editor-ui-area-item-text,
213
303
  .fx-formula-kity-host .kf-editor-ui-box-item-text,
214
- .fx-formula-kity-host .kf-editor-ui-box-item-val,
215
- .formulax-math__render {
304
+ .fx-formula-kity-host .kf-editor-ui-box-item-val {
216
305
  font-family: "KF AMS MAIN", "Cambria Math", "Latin Modern Math", "Times New Roman", serif !important;
217
306
  }
218
307
 
@@ -287,59 +376,34 @@ var formulaXModalStyles = `
287
376
  background: #2563eb;
288
377
  color: #fff;
289
378
  }
290
-
291
- .formulax-math {
292
- display: inline-flex;
293
- align-items: center;
294
- vertical-align: middle;
295
- line-height: 1;
296
- padding: 0 2px;
297
- margin: 0 1px;
298
- border-radius: 3px;
299
- background: transparent;
300
- cursor: pointer;
301
- user-select: none;
302
- }
303
-
304
- .formulax-math:hover {
305
- outline: 1px solid rgba(37, 99, 235, 0.35);
306
- background: rgba(37, 99, 235, 0.06);
307
- }
308
-
309
- .formulax-math__svg {
310
- display: inline-block;
311
- flex: 0 0 auto;
312
- max-width: 100%;
313
- vertical-align: -0.35em;
314
- pointer-events: none;
315
- }
316
-
317
- .formulax-math__image {
318
- display: inline-block;
319
- max-width: 100%;
320
- height: auto;
321
- vertical-align: middle;
322
- pointer-events: none;
323
- }
324
379
  `;
325
380
  function ensureFormulaXModalStyles(doc = document) {
381
+ ensureFormulaXBaseStyles(doc);
326
382
  if (doc.getElementById(STYLE_ID)) return;
327
383
  const style = doc.createElement("style");
328
384
  style.id = STYLE_ID;
329
385
  style.textContent = formulaXModalStyles;
330
386
  doc.head.appendChild(style);
331
387
  }
332
- function mountFormulaXEditor(root, options = {}) {
333
- let destroyed = false;
334
- let latestLatex = options.initialLatex ?? "";
335
- let handle = null;
336
- const initialLatex = latestLatex.trim() ? latestLatex : EMPTY_FORMULA_PLACEHOLDER;
388
+ function renderFormulaXEditorLoadingState(root) {
337
389
  root.classList.add("fx-formula-kity-host");
338
390
  root.innerHTML = `
339
391
  <div class="fx-formula-editor-loading" role="status" aria-live="polite">
340
392
  Loading FormulaX editor...
341
393
  </div>
342
394
  `;
395
+ }
396
+ function mountFormulaXEditor(root, options = {}) {
397
+ recordFormulaXPerfPoint("fx:formula-editor:mount:start");
398
+ const mountStart = markFormulaXPerf("fx:formula-editor:mount:start:scope");
399
+ let destroyed = false;
400
+ let latestLatex = options.initialLatex ?? "";
401
+ let handle = null;
402
+ const initialLatex = latestLatex.trim() ? latestLatex : EMPTY_FORMULA_PLACEHOLDER;
403
+ renderFormulaXEditorLoadingState(root);
404
+ const loadingVisibleMark = markFormulaXPerf("fx:formula-editor:loading-visible");
405
+ measureFormulaXPerf("fx:formula-editor:loading-visible", mountStart, loadingVisibleMark);
406
+ clearFormulaXPerfMarks(loadingVisibleMark);
343
407
  const readyPromise = mountKityEditor(root, {
344
408
  initialLatex,
345
409
  height: options.height ?? "100%",
@@ -353,6 +417,9 @@ function mountFormulaXEditor(root, options = {}) {
353
417
  nextHandle.destroy();
354
418
  throw new Error("FormulaX editor mount cancelled");
355
419
  }
420
+ const readyMark = markFormulaXPerf("fx:kity-editor:ready");
421
+ measureFormulaXPerf("fx:kity-editor:ready", mountStart, readyMark);
422
+ clearFormulaXPerfMarks(readyMark);
356
423
  handle = nextHandle;
357
424
  return nextHandle;
358
425
  }).catch((error) => {
@@ -366,6 +433,8 @@ function mountFormulaXEditor(root, options = {}) {
366
433
  `;
367
434
  }
368
435
  throw error;
436
+ }).finally(() => {
437
+ clearFormulaXPerfMarks(mountStart);
369
438
  });
370
439
  const getCurrentLatex = async () => {
371
440
  const readyHandle = handle ?? await readyPromise;
@@ -391,8 +460,8 @@ function mountFormulaXEditor(root, options = {}) {
391
460
  },
392
461
  async getRenderHtml() {
393
462
  await readyPromise;
394
- await waitForFormulaSvgLayout(root);
395
- return renderCurrentFormulaAsSvgHtml(root);
463
+ await waitForKityFormulaSvgLayout(root);
464
+ return serializeKityFormulaFromRoot(root);
396
465
  },
397
466
  destroy() {
398
467
  if (destroyed) return;
@@ -442,329 +511,17 @@ async function tryReadLatexFromKityHandle(handle) {
442
511
  }
443
512
  return null;
444
513
  }
445
- function renderCurrentFormulaAsSvgHtml(root) {
446
- const svg = findFormulaSvg(root);
447
- if (!svg) {
448
- return "";
449
- }
450
- return serializeSvgForInsertion(svg);
451
- }
452
- async function waitForFormulaSvgLayout(root) {
453
- const doc = root.ownerDocument ?? document;
454
- const view = doc.defaultView ?? window;
455
- await waitForDocumentFonts(doc);
456
- let previous = readRenderedFormulaBox(root);
457
- for (let attempt = 0; attempt < 4; attempt += 1) {
458
- await waitForAnimationFrame(view);
459
- const current = readRenderedFormulaBox(root);
460
- if (previous && current && areSvgBoxesClose(previous, current)) {
461
- return;
462
- }
463
- previous = current;
464
- }
465
- }
466
- function findFormulaSvg(root) {
467
- return root.querySelector(
468
- ".kf-editor-edit-area svg, .kf-editor-canvas-container svg, svg"
469
- );
470
- }
471
- function readRenderedFormulaBox(root) {
472
- const svg = findFormulaSvg(root);
473
- if (!svg) {
474
- return null;
475
- }
476
- return getInlineSvgContent(svg)?.box ?? readSvgBox(svg);
477
- }
478
- function areSvgBoxesClose(left, right) {
479
- 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;
480
- }
481
- async function waitForDocumentFonts(doc) {
482
- if (!doc.fonts?.ready) {
483
- return;
484
- }
485
- try {
486
- await doc.fonts.ready;
487
- } catch {
488
- }
489
- }
490
- function waitForAnimationFrame(view) {
491
- return new Promise((resolve) => {
492
- view.requestAnimationFrame(() => resolve());
493
- });
494
- }
495
- function serializeSvgForInsertion(svg) {
496
- const content = getInlineSvgContent(svg);
497
- const inlineViewport = content ? createInlineSvgViewport(content.box) : null;
498
- const clone = content && inlineViewport ? createInlineSvgClone(svg, content, inlineViewport) : svg.cloneNode(true);
499
- uniquifySvgIds(clone);
500
- sizeSvgForInlineDisplay(clone, svg, inlineViewport);
501
- clone.removeAttribute("id");
502
- clone.removeAttribute("xmlns");
503
- clone.removeAttribute("xmlns:xlink");
504
- clone.setAttribute("class", mergeClassNames(clone.getAttribute("class"), "formulax-math__svg"));
505
- clone.setAttribute("focusable", "false");
506
- clone.setAttribute("aria-hidden", "true");
507
- clone.setAttribute("preserveAspectRatio", clone.getAttribute("preserveAspectRatio") || "xMinYMin meet");
508
- return new XMLSerializer().serializeToString(clone);
509
- }
510
- function getInlineSvgContent(svg) {
511
- const candidates = [
512
- '[data-root="true"] > g[data-type="kf-editor-exp-content-box"]',
513
- 'g[data-type="kf-editor-exp-content-box"]',
514
- 'g[data-type="kf-container"]',
515
- "svg > g, g"
516
- ];
517
- for (const selector of candidates) {
518
- const content = svg.querySelector(selector);
519
- const rootSpace = content ? readSvgBoxInRootSpace(content) : null;
520
- if (content && rootSpace) {
521
- return {
522
- root: content,
523
- box: rootSpace.box,
524
- matrix: rootSpace.matrix
525
- };
526
- }
527
- }
528
- return null;
529
- }
530
- function readSvgBoxInRootSpace(element) {
531
- const box = readSvgBox(element);
532
- const matrix = getSvgRootSpaceMatrix(element);
533
- if (!box || !matrix) {
534
- return null;
535
- }
536
- const points = [
537
- { x: box.x, y: box.y },
538
- { x: box.x + box.width, y: box.y },
539
- { x: box.x, y: box.y + box.height },
540
- { x: box.x + box.width, y: box.y + box.height }
541
- ].map((point) => ({
542
- x: matrix.a * point.x + matrix.c * point.y + matrix.e,
543
- y: matrix.b * point.x + matrix.d * point.y + matrix.f
544
- }));
545
- const xs = points.map((point) => point.x);
546
- const ys = points.map((point) => point.y);
547
- const x = Math.min(...xs);
548
- const y = Math.min(...ys);
549
- const width = Math.max(...xs) - x;
550
- const height = Math.max(...ys) - y;
551
- if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {
552
- return null;
553
- }
554
- return {
555
- box: { x, y, width, height },
556
- matrix
557
- };
558
- }
559
- function getSvgRootSpaceMatrix(element) {
560
- const elementMatrix = typeof element.getCTM === "function" ? element.getCTM() : null;
561
- const rootMatrix = typeof element.ownerSVGElement?.getCTM === "function" ? element.ownerSVGElement.getCTM() : null;
562
- if (!elementMatrix) {
563
- return null;
564
- }
565
- return rootMatrix ? multiplySvgMatrices(invertSvgMatrix(rootMatrix), elementMatrix) : toSvgMatrixLike(elementMatrix);
566
- }
567
- function invertSvgMatrix(matrix) {
568
- const determinant = matrix.a * matrix.d - matrix.b * matrix.c;
569
- if (!Number.isFinite(determinant) || determinant === 0) {
570
- return {
571
- a: 1,
572
- b: 0,
573
- c: 0,
574
- d: 1,
575
- e: 0,
576
- f: 0
577
- };
578
- }
579
- return {
580
- a: matrix.d / determinant,
581
- b: -matrix.b / determinant,
582
- c: -matrix.c / determinant,
583
- d: matrix.a / determinant,
584
- e: (matrix.c * matrix.f - matrix.d * matrix.e) / determinant,
585
- f: (matrix.b * matrix.e - matrix.a * matrix.f) / determinant
586
- };
587
- }
588
- function multiplySvgMatrices(left, right) {
589
- return {
590
- a: left.a * right.a + left.c * right.b,
591
- b: left.b * right.a + left.d * right.b,
592
- c: left.a * right.c + left.c * right.d,
593
- d: left.b * right.c + left.d * right.d,
594
- e: left.a * right.e + left.c * right.f + left.e,
595
- f: left.b * right.e + left.d * right.f + left.f
596
- };
597
- }
598
- function toSvgMatrixLike(matrix) {
599
- return {
600
- a: matrix.a,
601
- b: matrix.b,
602
- c: matrix.c,
603
- d: matrix.d,
604
- e: matrix.e,
605
- f: matrix.f
606
- };
607
- }
608
- function readSvgBox(element) {
609
- if (typeof element.getBBox !== "function") {
610
- return null;
611
- }
612
- try {
613
- const box = element.getBBox();
614
- if (!Number.isFinite(box.width) || !Number.isFinite(box.height) || box.width <= 0 || box.height <= 0) {
615
- return null;
616
- }
617
- return {
618
- x: box.x,
619
- y: box.y,
620
- width: box.width,
621
- height: box.height
622
- };
623
- } catch {
624
- return null;
625
- }
626
- }
627
- function createInlineSvgViewport(contentBox) {
628
- const edgePadding = Math.max(0.5, Math.min(contentBox.width, contentBox.height) * 6e-3);
629
- const inset = edgePadding / 2;
630
- return {
631
- x: contentBox.x - inset,
632
- y: contentBox.y - inset,
633
- width: contentBox.width + edgePadding,
634
- height: contentBox.height + edgePadding
635
- };
636
- }
637
- function createInlineSvgClone(source, content, viewport) {
638
- const clone = source.cloneNode(false);
639
- const ownerDocument = source.ownerDocument;
640
- copySvgRootAttributes(source, clone);
641
- clone.setAttribute(
642
- "viewBox",
643
- `0 0 ${roundLength(viewport.width)} ${roundLength(viewport.height)}`
644
- );
645
- Array.from(source.children).forEach((child) => {
646
- if (child.tagName.toLowerCase() === "defs") {
647
- clone.appendChild(child.cloneNode(true));
648
- }
649
- });
650
- const wrapper = ownerDocument.createElementNS("http://www.w3.org/2000/svg", "g");
651
- wrapper.setAttribute(
652
- "transform",
653
- `translate(${roundLength(-viewport.x)} ${roundLength(-viewport.y)})`
654
- );
655
- const flattened = ownerDocument.createElementNS("http://www.w3.org/2000/svg", "g");
656
- flattened.setAttribute(
657
- "transform",
658
- `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)})`
659
- );
660
- flattened.appendChild(content.root.cloneNode(true));
661
- wrapper.appendChild(flattened);
662
- clone.appendChild(wrapper);
663
- return clone;
664
- }
665
- function copySvgRootAttributes(source, target) {
666
- const excluded = /* @__PURE__ */ new Set([
667
- "id",
668
- "width",
669
- "height",
670
- "viewBox",
671
- "class",
672
- "focusable",
673
- "aria-hidden",
674
- "xmlns",
675
- "xmlns:xlink"
676
- ]);
677
- Array.from(source.attributes).forEach((attribute) => {
678
- if (excluded.has(attribute.name)) return;
679
- target.setAttribute(attribute.name, attribute.value);
680
- });
681
- }
682
- function sizeSvgForInlineDisplay(clone, source, viewport) {
683
- const viewBox = clone.viewBox?.baseVal;
684
- const rect = source.getBoundingClientRect();
685
- const width = viewport?.width || viewBox?.width || rect.width || Number(clone.getAttribute("width")) || 1;
686
- const height = viewport?.height || viewBox?.height || rect.height || Number(clone.getAttribute("height")) || 1;
687
- const ratio = Math.max(0.1, width / Math.max(1, height));
688
- const inlineHeightEm = 0.875;
689
- const inlineWidthEm = Math.min(40, Math.max(0.75, ratio * inlineHeightEm));
690
- clone.setAttribute("width", roundLength(width));
691
- clone.setAttribute("height", roundLength(height));
692
- clone.setAttribute(
693
- "style",
694
- mergeInlineStyles2(
695
- clone.getAttribute("style"),
696
- `width:${roundLength(inlineWidthEm)}em`,
697
- `height:${inlineHeightEm}em`
698
- )
699
- );
700
- }
701
- function roundLength(value) {
702
- return String(Math.round(value * 1e3) / 1e3);
703
- }
704
- function uniquifySvgIds(svg) {
705
- const idMap = /* @__PURE__ */ new Map();
706
- const prefix = `fx-${randomIdPrefix()}-`;
707
- const elementsWithId = svg.querySelectorAll("[id]");
708
- elementsWithId.forEach((element) => {
709
- const id = element.getAttribute("id");
710
- if (!id) return;
711
- const nextId = `${prefix}${id}`;
712
- idMap.set(id, nextId);
713
- element.setAttribute("id", nextId);
714
- });
715
- if (!idMap.size) return;
716
- svg.querySelectorAll("*").forEach((element) => {
717
- Array.from(element.attributes).forEach((attribute) => {
718
- const nextValue = rewriteSvgReferences(attribute.value, idMap);
719
- if (nextValue !== attribute.value) {
720
- element.setAttribute(attribute.name, nextValue);
721
- }
722
- });
723
- });
724
- }
725
- function randomIdPrefix() {
726
- return Math.random().toString(36).slice(2, 5).padEnd(3, "0");
727
- }
728
- function rewriteSvgReferences(value, idMap) {
729
- let nextValue = value;
730
- idMap.forEach((nextId, id) => {
731
- nextValue = nextValue.replaceAll(`#${id}`, `#${nextId}`).replaceAll(`url(${id})`, `url(${nextId})`).replaceAll(`url(#${id})`, `url(#${nextId})`);
732
- });
733
- return nextValue;
734
- }
735
- function mergeClassNames(...values) {
736
- return values.flatMap((value) => value?.split(/\s+/) ?? []).filter(Boolean).filter((value, index, list) => list.indexOf(value) === index).join(" ");
737
- }
738
- function mergeInlineStyles2(...values) {
739
- return values.flatMap((value) => value?.split(";") ?? []).map((value) => value.trim()).filter(Boolean).join("; ");
740
- }
741
-
742
- // src/index.ts
743
- import {
744
- FormulaXEditor,
745
- createKityEditor,
746
- ensureKityRuntime,
747
- mountKityEditor as mountKityEditor2
748
- } from "@formulaxjs/kity-runtime";
749
514
  export {
750
- DEFAULT_FORMULA_ATTRIBUTE,
751
- DEFAULT_FORMULA_CLASS,
752
- FORMULA_FLAG_ATTRIBUTE,
753
- FormulaXEditor,
754
- createFormulaElement,
755
- createFormulaMarkup,
756
- createKityEditor,
515
+ clearFormulaXPerfMarks,
757
516
  ensureFormulaXModalStyles,
758
- ensureKityRuntime,
759
- escapeAttribute,
760
- escapeHtml,
761
- findFormulaElement,
762
517
  formulaXModalStyles,
763
- getFormulaLatexFromElement,
764
- isFormulaElement,
518
+ markFormulaXPerf,
519
+ measureFormulaXPerf,
765
520
  mountFormulaXEditor,
766
- mountKityEditor2 as mountKityEditor,
767
- replaceFormulaElement,
768
- serializeSvgForInsertion
521
+ preloadFormulaXEditor,
522
+ recordFormulaXPerfPoint,
523
+ renderFormulaXEditorLoadingState,
524
+ scheduleFormulaXEditorPreload,
525
+ waitForFormulaXAnimationFrame
769
526
  };
770
527
  //# sourceMappingURL=index.js.map