@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.
@@ -21,6 +21,105 @@ var FormulaX = (() => {
21
21
  };
22
22
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
23
23
 
24
+ // ../kity-runtime/public/assets/images/toolbar/btn.png
25
+ var btn_default;
26
+ var init_btn = __esm({
27
+ "../kity-runtime/public/assets/images/toolbar/btn.png"() {
28
+ btn_default = "./btn-5DANP6JY.png";
29
+ }
30
+ });
31
+
32
+ // ../kity-runtime/public/assets/images/toolbar/other.png
33
+ var other_default;
34
+ var init_other = __esm({
35
+ "../kity-runtime/public/assets/images/toolbar/other.png"() {
36
+ other_default = "./other-OMWJFGL5.png";
37
+ }
38
+ });
39
+
40
+ // ../kity-runtime/public/assets/styles/editor.css?url
41
+ var editor_default;
42
+ var init_editor = __esm({
43
+ "../kity-runtime/public/assets/styles/editor.css?url"() {
44
+ editor_default = "./editor-JT5KLVXX.css?url";
45
+ }
46
+ });
47
+
48
+ // ../kity-runtime/public/resource/KF_AMS_BB.woff
49
+ var KF_AMS_BB_default;
50
+ var init_KF_AMS_BB = __esm({
51
+ "../kity-runtime/public/resource/KF_AMS_BB.woff"() {
52
+ KF_AMS_BB_default = "./KF_AMS_BB-5QF7FUSO.woff";
53
+ }
54
+ });
55
+
56
+ // ../kity-runtime/public/resource/KF_AMS_CAL.woff
57
+ var KF_AMS_CAL_default;
58
+ var init_KF_AMS_CAL = __esm({
59
+ "../kity-runtime/public/resource/KF_AMS_CAL.woff"() {
60
+ KF_AMS_CAL_default = "./KF_AMS_CAL-NXRNLAZN.woff";
61
+ }
62
+ });
63
+
64
+ // ../kity-runtime/public/resource/KF_AMS_FRAK.woff
65
+ var KF_AMS_FRAK_default;
66
+ var init_KF_AMS_FRAK = __esm({
67
+ "../kity-runtime/public/resource/KF_AMS_FRAK.woff"() {
68
+ KF_AMS_FRAK_default = "./KF_AMS_FRAK-CO33WWN4.woff";
69
+ }
70
+ });
71
+
72
+ // ../kity-runtime/public/resource/KF_AMS_MAIN.woff
73
+ var KF_AMS_MAIN_default;
74
+ var init_KF_AMS_MAIN = __esm({
75
+ "../kity-runtime/public/resource/KF_AMS_MAIN.woff"() {
76
+ KF_AMS_MAIN_default = "./KF_AMS_MAIN-25QJVAWY.woff";
77
+ }
78
+ });
79
+
80
+ // ../kity-runtime/public/resource/KF_AMS_ROMAN.woff
81
+ var KF_AMS_ROMAN_default;
82
+ var init_KF_AMS_ROMAN = __esm({
83
+ "../kity-runtime/public/resource/KF_AMS_ROMAN.woff"() {
84
+ KF_AMS_ROMAN_default = "./KF_AMS_ROMAN-243BR7HH.woff";
85
+ }
86
+ });
87
+
88
+ // ../kity-runtime/src/asset-manifest.ts
89
+ var kityFontAssets, kityToolbarAssets, kityStyleAssets, kityAssetManifest;
90
+ var init_asset_manifest = __esm({
91
+ "../kity-runtime/src/asset-manifest.ts"() {
92
+ "use strict";
93
+ init_btn();
94
+ init_other();
95
+ init_editor();
96
+ init_KF_AMS_BB();
97
+ init_KF_AMS_CAL();
98
+ init_KF_AMS_FRAK();
99
+ init_KF_AMS_MAIN();
100
+ init_KF_AMS_ROMAN();
101
+ kityFontAssets = {
102
+ KF_AMS_BB: KF_AMS_BB_default,
103
+ KF_AMS_CAL: KF_AMS_CAL_default,
104
+ KF_AMS_FRAK: KF_AMS_FRAK_default,
105
+ KF_AMS_MAIN: KF_AMS_MAIN_default,
106
+ KF_AMS_ROMAN: KF_AMS_ROMAN_default
107
+ };
108
+ kityToolbarAssets = {
109
+ btn: btn_default,
110
+ other: other_default
111
+ };
112
+ kityStyleAssets = {
113
+ editor: editor_default
114
+ };
115
+ kityAssetManifest = {
116
+ fonts: kityFontAssets,
117
+ toolbar: kityToolbarAssets,
118
+ styles: kityStyleAssets
119
+ };
120
+ }
121
+ });
122
+
24
123
  // ../kity-runtime/src/vendor/legacy-box-type.ts
25
124
  var legacyBoxType;
26
125
  var init_legacy_box_type = __esm({
@@ -4965,7 +5064,11 @@ var FormulaX = (() => {
4965
5064
  var init_toolbar_assets = __esm({
4966
5065
  "../kity-runtime/src/toolbar-assets.ts"() {
4967
5066
  "use strict";
4968
- toolbarAssetFileMap = {};
5067
+ init_asset_manifest();
5068
+ toolbarAssetFileMap = {
5069
+ "btn.png": kityToolbarAssets.btn,
5070
+ "other.png": kityToolbarAssets.other
5071
+ };
4969
5072
  }
4970
5073
  });
4971
5074
 
@@ -14873,7 +14976,7 @@ var FormulaX = (() => {
14873
14976
  return serviceObject;
14874
14977
  }
14875
14978
  var defaultOptions, components, kity2, kf, KFEditor, editor_default2;
14876
- var init_editor = __esm({
14979
+ var init_editor2 = __esm({
14877
14980
  "../kity-runtime/src/legacy/editor.ts"() {
14878
14981
  "use strict";
14879
14982
  init_legacy_utils();
@@ -14993,7 +15096,7 @@ var FormulaX = (() => {
14993
15096
  var init_factory = __esm({
14994
15097
  "../kity-runtime/src/legacy/factory.ts"() {
14995
15098
  "use strict";
14996
- init_editor();
15099
+ init_editor2();
14997
15100
  init_runtime_interop();
14998
15101
  EditorWrapper = class {
14999
15102
  callbacks = [];
@@ -19951,7 +20054,7 @@ var FormulaX = (() => {
19951
20054
  var init_start = __esm({
19952
20055
  "../kity-runtime/src/boot/start.ts"() {
19953
20056
  "use strict";
19954
- init_editor();
20057
+ init_editor2();
19955
20058
  init_factory();
19956
20059
  init_ui();
19957
20060
  init_parser();
@@ -19968,25 +20071,17 @@ var FormulaX = (() => {
19968
20071
  // src/index.ts
19969
20072
  var index_exports = {};
19970
20073
  __export(index_exports, {
19971
- DEFAULT_FORMULA_ATTRIBUTE: () => DEFAULT_FORMULA_ATTRIBUTE,
19972
- DEFAULT_FORMULA_CLASS: () => DEFAULT_FORMULA_CLASS,
19973
- FORMULA_FLAG_ATTRIBUTE: () => FORMULA_FLAG_ATTRIBUTE,
19974
- FormulaXEditor: () => FormulaXEditor,
19975
- createFormulaElement: () => createFormulaElement,
19976
- createFormulaMarkup: () => createFormulaMarkup,
19977
- createKityEditor: () => createKityEditor,
20074
+ clearFormulaXPerfMarks: () => clearFormulaXPerfMarks2,
19978
20075
  ensureFormulaXModalStyles: () => ensureFormulaXModalStyles,
19979
- ensureKityRuntime: () => ensureKityRuntime,
19980
- escapeAttribute: () => escapeAttribute,
19981
- escapeHtml: () => escapeHtml,
19982
- findFormulaElement: () => findFormulaElement,
19983
20076
  formulaXModalStyles: () => formulaXModalStyles,
19984
- getFormulaLatexFromElement: () => getFormulaLatexFromElement,
19985
- isFormulaElement: () => isFormulaElement,
20077
+ markFormulaXPerf: () => markFormulaXPerf2,
20078
+ measureFormulaXPerf: () => measureFormulaXPerf2,
19986
20079
  mountFormulaXEditor: () => mountFormulaXEditor,
19987
- mountKityEditor: () => mountKityEditor,
19988
- replaceFormulaElement: () => replaceFormulaElement,
19989
- serializeSvgForInsertion: () => serializeSvgForInsertion
20080
+ preloadFormulaXEditor: () => preloadFormulaXEditor,
20081
+ recordFormulaXPerfPoint: () => recordFormulaXPerfPoint,
20082
+ renderFormulaXEditorLoadingState: () => renderFormulaXEditorLoadingState,
20083
+ scheduleFormulaXEditorPreload: () => scheduleFormulaXEditorPreload,
20084
+ waitForFormulaXAnimationFrame: () => waitForFormulaXAnimationFrame
19990
20085
  });
19991
20086
 
19992
20087
  // ../core/src/ast.ts
@@ -20274,52 +20369,11 @@ var FormulaX = (() => {
20274
20369
  };
20275
20370
  var parseLatex = (input) => new LatexParser(input).parse();
20276
20371
 
20277
- // ../kity-runtime/public/assets/images/toolbar/btn.png
20278
- var btn_default = "./btn-5DANP6JY.png";
20279
-
20280
- // ../kity-runtime/public/assets/images/toolbar/other.png
20281
- var other_default = "./other-OMWJFGL5.png";
20282
-
20283
- // ../kity-runtime/public/assets/styles/editor.css?url
20284
- var editor_default = "./editor-JT5KLVXX.css?url";
20285
-
20286
- // ../kity-runtime/public/resource/KF_AMS_BB.woff
20287
- var KF_AMS_BB_default = "./KF_AMS_BB-5QF7FUSO.woff";
20288
-
20289
- // ../kity-runtime/public/resource/KF_AMS_CAL.woff
20290
- var KF_AMS_CAL_default = "./KF_AMS_CAL-NXRNLAZN.woff";
20291
-
20292
- // ../kity-runtime/public/resource/KF_AMS_FRAK.woff
20293
- var KF_AMS_FRAK_default = "./KF_AMS_FRAK-CO33WWN4.woff";
20294
-
20295
- // ../kity-runtime/public/resource/KF_AMS_MAIN.woff
20296
- var KF_AMS_MAIN_default = "./KF_AMS_MAIN-25QJVAWY.woff";
20297
-
20298
- // ../kity-runtime/public/resource/KF_AMS_ROMAN.woff
20299
- var KF_AMS_ROMAN_default = "./KF_AMS_ROMAN-243BR7HH.woff";
20300
-
20301
- // ../kity-runtime/src/asset-manifest.ts
20302
- var kityFontAssets = {
20303
- KF_AMS_BB: KF_AMS_BB_default,
20304
- KF_AMS_CAL: KF_AMS_CAL_default,
20305
- KF_AMS_FRAK: KF_AMS_FRAK_default,
20306
- KF_AMS_MAIN: KF_AMS_MAIN_default,
20307
- KF_AMS_ROMAN: KF_AMS_ROMAN_default
20308
- };
20309
- var kityToolbarAssets = {
20310
- btn: btn_default,
20311
- other: other_default
20312
- };
20313
- var kityStyleAssets = {
20314
- editor: editor_default
20315
- };
20316
- var kityAssetManifest = {
20317
- fonts: kityFontAssets,
20318
- toolbar: kityToolbarAssets,
20319
- styles: kityStyleAssets
20320
- };
20372
+ // ../kity-runtime/src/index.ts
20373
+ init_asset_manifest();
20321
20374
 
20322
20375
  // ../kity-runtime/src/create-editor.ts
20376
+ init_asset_manifest();
20323
20377
  init_legacy_box_type();
20324
20378
 
20325
20379
  // ../kity-runtime/src/vendor/char-position.ts
@@ -23722,6 +23776,80 @@ var FormulaX = (() => {
23722
23776
  targetWindow.kity = kity;
23723
23777
  }
23724
23778
 
23779
+ // ../kity-runtime/src/perf.ts
23780
+ function getPerfHost() {
23781
+ return globalThis;
23782
+ }
23783
+ function getPerfState() {
23784
+ const host = getPerfHost();
23785
+ host.__FORMULAX_PERF_STATE__ ??= {
23786
+ reportedMeasureCount: 0,
23787
+ reportScheduled: false
23788
+ };
23789
+ return host.__FORMULAX_PERF_STATE__;
23790
+ }
23791
+ function hasPerfSupport() {
23792
+ return typeof performance !== "undefined" && typeof performance.mark === "function" && typeof performance.measure === "function" && typeof performance.getEntriesByType === "function";
23793
+ }
23794
+ function isPerfDebugEnabled() {
23795
+ return getPerfHost().__FORMULAX_PERF__ === true;
23796
+ }
23797
+ function schedulePerfReport() {
23798
+ if (!hasPerfSupport() || !isPerfDebugEnabled()) {
23799
+ return;
23800
+ }
23801
+ const state = getPerfState();
23802
+ if (state.reportScheduled) {
23803
+ return;
23804
+ }
23805
+ state.reportScheduled = true;
23806
+ queueMicrotask(() => {
23807
+ state.reportScheduled = false;
23808
+ const entries = performance.getEntriesByType("measure").filter((entry) => entry.name.startsWith("fx:")).sort((left, right) => left.startTime - right.startTime);
23809
+ const nextEntries = entries.slice(state.reportedMeasureCount);
23810
+ state.reportedMeasureCount = entries.length;
23811
+ if (!nextEntries.length) {
23812
+ return;
23813
+ }
23814
+ console.table(nextEntries.map((entry) => ({
23815
+ name: entry.name,
23816
+ duration: Number(entry.duration.toFixed(2)),
23817
+ startTime: Number(entry.startTime.toFixed(2))
23818
+ })));
23819
+ });
23820
+ }
23821
+ function markFormulaXPerf(name) {
23822
+ if (!hasPerfSupport()) {
23823
+ return null;
23824
+ }
23825
+ const markName = `${name}::${Date.now()}::${Math.random().toString(36).slice(2, 8)}`;
23826
+ performance.mark(markName);
23827
+ return markName;
23828
+ }
23829
+ function measureFormulaXPerf(name, startMark, endMark) {
23830
+ if (!hasPerfSupport() || !startMark) {
23831
+ return null;
23832
+ }
23833
+ const resolvedEndMark = endMark ?? markFormulaXPerf(`${name}:end`);
23834
+ if (!resolvedEndMark) {
23835
+ return null;
23836
+ }
23837
+ performance.measure(name, startMark, resolvedEndMark);
23838
+ schedulePerfReport();
23839
+ return resolvedEndMark;
23840
+ }
23841
+ function clearFormulaXPerfMarks(...marks) {
23842
+ if (!hasPerfSupport()) {
23843
+ return;
23844
+ }
23845
+ for (const mark of marks) {
23846
+ if (!mark) {
23847
+ continue;
23848
+ }
23849
+ performance.clearMarks(mark);
23850
+ }
23851
+ }
23852
+
23725
23853
  // ../kity-runtime/src/create-editor.ts
23726
23854
  init_toolbar_assets();
23727
23855
  var DEFAULT_LATEX = "x=\\frac{-b\\pm\\sqrt{b^2-4ac}}{2a}";
@@ -23762,13 +23890,14 @@ var FormulaX = (() => {
23762
23890
  }
23763
23891
  function ensureKityStylesheet(doc2, href) {
23764
23892
  if (doc2.getElementById(KITY_STYLE_ID)) {
23765
- return;
23893
+ return false;
23766
23894
  }
23767
23895
  const link = doc2.createElement("link");
23768
23896
  link.id = KITY_STYLE_ID;
23769
23897
  link.rel = "stylesheet";
23770
23898
  link.href = href;
23771
23899
  doc2.head.appendChild(link);
23900
+ return true;
23772
23901
  }
23773
23902
  function hydrateLegacyKf(runtimeWindow) {
23774
23903
  const requireFormula = runtimeWindow.__kityFormulaRequire__;
@@ -23824,64 +23953,114 @@ var FormulaX = (() => {
23824
23953
  return runtimePromise;
23825
23954
  }
23826
23955
  runtimePromise = (async () => {
23956
+ const runtimeTotalStart = markFormulaXPerf("fx:kity-runtime:total");
23827
23957
  const runtimeWindow = window;
23828
23958
  runtimeWindow.kf = runtimeWindow.kf ?? {};
23829
23959
  installKityRuntime(runtimeWindow);
23830
- const { installLegacyKityFormulaRuntime: installLegacyKityFormulaRuntime2 } = await Promise.resolve().then(() => (init_install(), install_exports));
23831
- installLegacyKityFormulaRuntime2(runtimeWindow);
23832
- hydrateLegacyKf(runtimeWindow);
23833
- const { installLegacyParserRuntime: installLegacyParserRuntime2 } = await Promise.resolve().then(() => (init_install2(), install_exports2));
23834
- installLegacyParserRuntime2(runtimeWindow);
23835
- installLegacyRuntime(runtimeWindow);
23836
- const { installKityEditorStart: installKityEditorStart2 } = await Promise.resolve().then(() => (init_start(), start_exports));
23837
- installKityEditorStart2(runtimeWindow);
23960
+ try {
23961
+ const formulaImportStart = markFormulaXPerf("fx:kity-runtime:formula-import");
23962
+ const { installLegacyKityFormulaRuntime: installLegacyKityFormulaRuntime2 } = await Promise.resolve().then(() => (init_install(), install_exports));
23963
+ const formulaImportEnd = markFormulaXPerf("fx:kity-runtime:formula-import:end");
23964
+ measureFormulaXPerf("fx:kity-runtime:formula-import", formulaImportStart, formulaImportEnd);
23965
+ clearFormulaXPerfMarks(formulaImportStart, formulaImportEnd);
23966
+ const formulaInstallStart = markFormulaXPerf("fx:kity-runtime:formula-install");
23967
+ installLegacyKityFormulaRuntime2(runtimeWindow);
23968
+ hydrateLegacyKf(runtimeWindow);
23969
+ const formulaInstallEnd = markFormulaXPerf("fx:kity-runtime:formula-install:end");
23970
+ measureFormulaXPerf("fx:kity-runtime:formula-install", formulaInstallStart, formulaInstallEnd);
23971
+ clearFormulaXPerfMarks(formulaInstallStart, formulaInstallEnd);
23972
+ const parserImportStart = markFormulaXPerf("fx:kity-runtime:parser-import");
23973
+ const { installLegacyParserRuntime: installLegacyParserRuntime2 } = await Promise.resolve().then(() => (init_install2(), install_exports2));
23974
+ const parserImportEnd = markFormulaXPerf("fx:kity-runtime:parser-import:end");
23975
+ measureFormulaXPerf("fx:kity-runtime:parser-import", parserImportStart, parserImportEnd);
23976
+ clearFormulaXPerfMarks(parserImportStart, parserImportEnd);
23977
+ const parserInstallStart = markFormulaXPerf("fx:kity-runtime:parser-install");
23978
+ installLegacyParserRuntime2(runtimeWindow);
23979
+ const parserInstallEnd = markFormulaXPerf("fx:kity-runtime:parser-install:end");
23980
+ measureFormulaXPerf("fx:kity-runtime:parser-install", parserInstallStart, parserInstallEnd);
23981
+ clearFormulaXPerfMarks(parserInstallStart, parserInstallEnd);
23982
+ installLegacyRuntime(runtimeWindow);
23983
+ const bootImportStart = markFormulaXPerf("fx:kity-runtime:boot-import");
23984
+ const { installKityEditorStart: installKityEditorStart2 } = await Promise.resolve().then(() => (init_start(), start_exports));
23985
+ const bootImportEnd = markFormulaXPerf("fx:kity-runtime:boot-import:end");
23986
+ measureFormulaXPerf("fx:kity-runtime:boot-import", bootImportStart, bootImportEnd);
23987
+ clearFormulaXPerfMarks(bootImportStart, bootImportEnd);
23988
+ const bootInstallStart = markFormulaXPerf("fx:kity-runtime:boot-install");
23989
+ installKityEditorStart2(runtimeWindow);
23990
+ const bootInstallEnd = markFormulaXPerf("fx:kity-runtime:boot-install:end");
23991
+ measureFormulaXPerf("fx:kity-runtime:boot-install", bootInstallStart, bootInstallEnd);
23992
+ clearFormulaXPerfMarks(bootInstallStart, bootInstallEnd);
23993
+ } finally {
23994
+ const runtimeTotalEnd = markFormulaXPerf("fx:kity-runtime:total:end");
23995
+ measureFormulaXPerf("fx:kity-runtime:total", runtimeTotalStart, runtimeTotalEnd);
23996
+ clearFormulaXPerfMarks(runtimeTotalStart, runtimeTotalEnd);
23997
+ }
23838
23998
  })();
23839
23999
  return runtimePromise;
23840
24000
  }
23841
24001
  async function createKityEditor(container, options = {}) {
24002
+ const createEditorStart = markFormulaXPerf("fx:create-kity-editor:total");
23842
24003
  const fontsize = options.render?.fontsize ?? 40;
23843
24004
  const editorHeight = normalizeCssSize(options.height, DEFAULT_EDITOR_HEIGHT);
23844
24005
  const assets = resolveEditorAssets(options.assets);
23845
- ensureKityStylesheet(document, assets.styles.editor);
23846
- setToolbarAssetUrls(assets.toolbar);
23847
- await ensureKityRuntime();
23848
- const runtimeWindow = window;
23849
- if (!runtimeWindow.kf?.EditorFactory) {
23850
- throw new Error("Kity editor runtime did not initialize");
23851
- }
23852
- container.innerHTML = "";
23853
- const host = document.createElement("div");
23854
- host.className = "kf-editor";
23855
- host.style.width = "100%";
23856
- host.style.height = editorHeight;
23857
- container.appendChild(host);
23858
- const factory2 = runtimeWindow.kf.EditorFactory.create(host, {
23859
- render: {
23860
- fontsize
23861
- },
23862
- resource: {
23863
- path: "",
23864
- fonts: assets.fonts
24006
+ try {
24007
+ const stylesheetInserted = ensureKityStylesheet(document, assets.styles.editor);
24008
+ if (stylesheetInserted) {
24009
+ const stylesheetInsertedMark = markFormulaXPerf("fx:kity-css:link-inserted");
24010
+ measureFormulaXPerf("fx:kity-css:link-inserted", createEditorStart, stylesheetInsertedMark);
24011
+ clearFormulaXPerfMarks(stylesheetInsertedMark);
23865
24012
  }
23866
- });
23867
- return {
23868
- ready: factory2.ready.bind(factory2),
23869
- execCommand(name, value) {
23870
- factory2.ready(function execWhenReady() {
23871
- this.execCommand(name, value);
23872
- });
23873
- },
23874
- focus() {
23875
- factory2.ready(function focusWhenReady() {
23876
- this.execCommand("focus");
23877
- });
23878
- },
23879
- destroy() {
23880
- container.innerHTML = "";
23881
- },
23882
- host,
23883
- raw: factory2
23884
- };
24013
+ setToolbarAssetUrls(assets.toolbar);
24014
+ await ensureKityRuntime();
24015
+ const runtimeReadyMark = markFormulaXPerf("fx:kity-runtime:ready-for-editor");
24016
+ measureFormulaXPerf("fx:kity-runtime:ready-for-editor", createEditorStart, runtimeReadyMark);
24017
+ clearFormulaXPerfMarks(runtimeReadyMark);
24018
+ const runtimeWindow = window;
24019
+ if (!runtimeWindow.kf?.EditorFactory) {
24020
+ throw new Error("Kity editor runtime did not initialize");
24021
+ }
24022
+ container.innerHTML = "";
24023
+ const host = document.createElement("div");
24024
+ host.className = "kf-editor";
24025
+ host.style.width = "100%";
24026
+ host.style.height = editorHeight;
24027
+ container.appendChild(host);
24028
+ const factoryCreateStart = markFormulaXPerf("fx:kity-editor-factory:create");
24029
+ const factory2 = runtimeWindow.kf.EditorFactory.create(host, {
24030
+ render: {
24031
+ fontsize
24032
+ },
24033
+ resource: {
24034
+ path: "",
24035
+ fonts: assets.fonts
24036
+ }
24037
+ });
24038
+ const factoryCreateEnd = markFormulaXPerf("fx:kity-editor-factory:create:end");
24039
+ measureFormulaXPerf("fx:kity-editor-factory:create", factoryCreateStart, factoryCreateEnd);
24040
+ clearFormulaXPerfMarks(factoryCreateStart, factoryCreateEnd);
24041
+ return {
24042
+ ready: factory2.ready.bind(factory2),
24043
+ execCommand(name, value) {
24044
+ factory2.ready(function execWhenReady() {
24045
+ this.execCommand(name, value);
24046
+ });
24047
+ },
24048
+ focus() {
24049
+ factory2.ready(function focusWhenReady() {
24050
+ this.execCommand("focus");
24051
+ });
24052
+ },
24053
+ destroy() {
24054
+ container.innerHTML = "";
24055
+ },
24056
+ host,
24057
+ raw: factory2
24058
+ };
24059
+ } finally {
24060
+ const createEditorEnd = markFormulaXPerf("fx:create-kity-editor:total:end");
24061
+ measureFormulaXPerf("fx:create-kity-editor:total", createEditorStart, createEditorEnd);
24062
+ clearFormulaXPerfMarks(createEditorStart, createEditorEnd);
24063
+ }
23885
24064
  }
23886
24065
  async function mountKityEditor(container, options = {}) {
23887
24066
  const editor = await createKityEditor(container, options);
@@ -23952,454 +24131,337 @@ var FormulaX = (() => {
23952
24131
  init_legacy_ui_utils();
23953
24132
  init_legacy_utils();
23954
24133
 
23955
- // src/formula-node.ts
23956
- var DEFAULT_FORMULA_ATTRIBUTE = "data-formulax-latex";
23957
- var FORMULA_FLAG_ATTRIBUTE = "data-formulax";
23958
- var DEFAULT_FORMULA_CLASS = "formulax-math";
23959
- function escapeAttribute(value) {
23960
- return value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
23961
- }
24134
+ // ../renderer/src/markup.ts
23962
24135
  function escapeHtml(value) {
23963
24136
  return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
23964
24137
  }
23965
- function createFormulaMarkup(latex, options = {}) {
23966
- const attributeName = options.attributeName ?? DEFAULT_FORMULA_ATTRIBUTE;
23967
- const className = options.className ?? DEFAULT_FORMULA_CLASS;
23968
- const displayClass = options.displayMode ? `${className} ${className}--block` : className;
23969
- const safeLatex = escapeAttribute(latex);
23970
- const cursorStyle = options.cursorStyle?.trim() || "pointer";
23971
- const extraAttributes = {
23972
- ...options.extraAttributes ?? {},
23973
- style: mergeInlineStyles(
23974
- typeof options.extraAttributes?.style === "string" ? options.extraAttributes.style : "",
23975
- cursorStyle ? `cursor: ${cursorStyle}` : ""
23976
- )
23977
- };
23978
- const serializedAttributes = Object.entries(extraAttributes).filter(([, value]) => value !== null && value !== void 0 && value !== false).map(([key, value]) => value === true ? key : `${key}="${escapeAttribute(String(value))}"`);
23979
- return [
23980
- "<span",
23981
- ` class="${escapeAttribute(displayClass)}"`,
23982
- ` ${FORMULA_FLAG_ATTRIBUTE}="true"`,
23983
- ` ${attributeName}="${safeLatex}"`,
23984
- ` data-latex="${safeLatex}"`,
23985
- ' contenteditable="false"',
23986
- ' role="button"',
23987
- ' tabindex="0"',
23988
- serializedAttributes.length ? ` ${serializedAttributes.join(" ")}` : "",
23989
- ">",
23990
- options.renderHtml ?? `<span class="${escapeAttribute(className)}__render">${escapeHtml(latex || "\\square")}</span>`,
23991
- "</span>"
23992
- ].join("");
23993
- }
23994
- function mergeInlineStyles(existingStyle, nextStyle) {
23995
- const existing = existingStyle.trim().replace(/;+\s*$/, "");
23996
- const next = nextStyle.trim().replace(/;+\s*$/, "");
23997
- if (!existing) return next;
23998
- if (!next) return existing;
23999
- return `${existing}; ${next}`;
24000
- }
24001
- function createFormulaElement(ownerDocument, latex, options = {}) {
24002
- const wrapper = ownerDocument.createElement("span");
24003
- wrapper.innerHTML = createFormulaMarkup(latex, options);
24004
- return wrapper.firstElementChild;
24005
- }
24006
- function replaceFormulaElement(target, latex, options = {}) {
24007
- const next = createFormulaElement(target.ownerDocument ?? document, latex, options);
24008
- if (!next) return null;
24009
- target.replaceWith(next);
24010
- return next;
24011
- }
24012
- function getFormulaLatexFromElement(element, attributeName = DEFAULT_FORMULA_ATTRIBUTE) {
24013
- return element.getAttribute(attributeName) ?? element.getAttribute("data-latex") ?? "";
24014
- }
24015
- function isFormulaElement(node) {
24016
- if (!node || typeof node !== "object") return false;
24017
- const element = node;
24018
- return typeof element.getAttribute === "function" && element.getAttribute(FORMULA_FLAG_ATTRIBUTE) === "true";
24019
- }
24020
- function findFormulaElement(node) {
24021
- if (!node) return null;
24022
- const element = node.nodeType === 1 ? node : node.parentElement;
24023
- return element?.closest?.(`[${FORMULA_FLAG_ATTRIBUTE}="true"]`);
24024
- }
24025
-
24026
- // src/formula-modal.ts
24027
- var EMPTY_FORMULA_PLACEHOLDER = "\\placeholder ";
24028
- var STYLE_ID = "fx-formula-modal-styles";
24029
- var formulaXModalStyles = `
24030
- .fx-formula-modal-open {
24031
- overflow: hidden;
24032
- }
24033
24138
 
24034
- .fx-formula-modal-root {
24035
- position: fixed;
24036
- inset: 0;
24037
- z-index: 2147483000;
24038
- display: flex;
24139
+ // ../renderer/src/styles.ts
24140
+ var FORMULAX_BASE_STYLE_ID = "fx-formulax-base-styles";
24141
+ var formulaXBaseStyles = `
24142
+ .formulax-math {
24143
+ display: inline-flex;
24039
24144
  align-items: center;
24040
- justify-content: center;
24041
- }
24042
-
24043
- .fx-formula-modal-backdrop {
24044
- position: absolute;
24045
- inset: 0;
24046
- background: rgba(15, 23, 42, 0.48);
24047
- }
24048
-
24049
- .fx-formula-modal {
24050
- --fx-formula-editor-body-height: 264px;
24051
- --fx-formula-workspace-height: 168px;
24052
- position: relative;
24053
- width: min(860px, calc(100vw - 32px));
24054
- height: auto;
24055
- max-height: calc(100vh - 32px);
24056
- background: #fff;
24057
- border-radius: 14px;
24058
- box-shadow: 0 24px 80px rgba(15, 23, 42, 0.28);
24059
- display: flex;
24060
- flex-direction: column;
24061
- overflow: visible;
24062
- isolation: isolate;
24063
- }
24064
-
24065
- .fx-formula-modal__header,
24066
- .fx-formula-modal__footer,
24067
- .fx-formula-modal__title,
24068
- .fx-formula-modal__close,
24069
- .fx-formula-modal__button,
24070
- .fx-formula-editor-loading,
24071
- .fx-formula-editor-error {
24072
- font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
24145
+ vertical-align: middle;
24146
+ line-height: 1;
24147
+ padding: 0 2px;
24148
+ margin: 0 1px;
24149
+ border-radius: 3px;
24150
+ background: transparent;
24151
+ cursor: pointer;
24152
+ user-select: none;
24073
24153
  }
24074
24154
 
24075
- .fx-formula-modal__header {
24076
- min-height: 56px;
24077
- padding: 0 20px;
24078
- border-bottom: 1px solid #e5e7eb;
24079
- display: flex;
24080
- align-items: center;
24081
- justify-content: space-between;
24082
- flex-shrink: 0;
24083
- position: relative;
24084
- z-index: 3;
24085
- background: #fff;
24086
- border-radius: 14px 14px 0 0;
24155
+ .formulax-math:hover {
24156
+ outline: 1px solid rgba(37, 99, 235, 0.35);
24157
+ background: rgba(37, 99, 235, 0.06);
24087
24158
  }
24088
24159
 
24089
- .fx-formula-modal__title {
24090
- font-size: 16px;
24091
- font-weight: 650;
24092
- margin: 0;
24093
- color: #111827;
24160
+ .formulax-math__render,
24161
+ .formulax-math__svg,
24162
+ .formulax-math__image {
24163
+ display: inline-block;
24164
+ max-width: 100%;
24165
+ pointer-events: none;
24094
24166
  }
24095
24167
 
24096
- .fx-formula-modal__close {
24097
- border: 0;
24098
- background: transparent;
24099
- font-size: 24px;
24100
- line-height: 1;
24101
- cursor: pointer;
24102
- color: #6b7280;
24168
+ .formulax-math__render {
24169
+ vertical-align: middle;
24170
+ font-family: "KF AMS MAIN", "Cambria Math", "Latin Modern Math", "Times New Roman", serif;
24103
24171
  }
24104
24172
 
24105
- .fx-formula-modal__body {
24173
+ .formulax-math__svg {
24106
24174
  flex: 0 0 auto;
24107
- height: var(--fx-formula-editor-body-height);
24108
- padding: 0;
24109
- overflow: visible;
24110
- min-height: var(--fx-formula-editor-body-height);
24111
- position: relative;
24112
- z-index: 2;
24113
- }
24114
-
24115
- .fx-formula-editor-host {
24116
- width: 100%;
24117
- height: var(--fx-formula-editor-body-height);
24118
- min-height: var(--fx-formula-editor-body-height);
24119
- overflow: visible;
24120
- position: relative;
24175
+ vertical-align: -0.35em;
24121
24176
  }
24122
24177
 
24123
- .fx-formula-kity-host {
24124
- width: 100%;
24125
- height: var(--fx-formula-editor-body-height);
24126
- min-height: var(--fx-formula-editor-body-height);
24127
- overflow: visible;
24128
- position: relative;
24178
+ .formulax-math__image {
24179
+ height: auto;
24180
+ vertical-align: middle;
24129
24181
  }
24182
+ `;
24183
+ function ensureFormulaXBaseStyles(doc2 = document) {
24184
+ if (doc2.getElementById(FORMULAX_BASE_STYLE_ID)) return;
24185
+ const style = doc2.createElement("style");
24186
+ style.id = FORMULAX_BASE_STYLE_ID;
24187
+ style.textContent = formulaXBaseStyles;
24188
+ doc2.head.appendChild(style);
24189
+ }
24130
24190
 
24131
- .fx-formula-kity-host .kf-editor {
24132
- height: var(--fx-formula-editor-body-height) !important;
24133
- overflow: visible !important;
24134
- }
24135
-
24136
- .fx-formula-kity-host .kf-editor-toolbar {
24137
- overflow: visible;
24138
- position: relative;
24139
- z-index: 20;
24140
- }
24141
-
24142
- .fx-formula-kity-host .kf-editor-ui-button-mount-point,
24143
- .fx-formula-kity-host .kf-editor-ui-area-mount,
24144
- .fx-formula-kity-host .kf-editor-ui-box,
24145
- .fx-formula-kity-host .kf-editor-ui-list {
24146
- z-index: 1000;
24147
- }
24148
-
24149
- .fx-formula-kity-host .kf-editor-edit-area,
24150
- .fx-formula-kity-host .kf-editor-canvas-container {
24151
- min-height: var(--fx-formula-workspace-height);
24152
- height: var(--fx-formula-workspace-height);
24153
- }
24154
-
24155
- .fx-formula-kity-host .kf-editor-edit-area {
24156
- flex: 0 0 auto;
24157
- overflow: hidden;
24158
- }
24159
-
24160
- .fx-formula-kity-host .kf-editor,
24161
- .fx-formula-kity-host .kf-editor svg text,
24162
- .fx-formula-kity-host .kf-editor-ui-area-item-text,
24163
- .fx-formula-kity-host .kf-editor-ui-box-item-text,
24164
- .fx-formula-kity-host .kf-editor-ui-box-item-val,
24165
- .formulax-math__render {
24166
- font-family: "KF AMS MAIN", "Cambria Math", "Latin Modern Math", "Times New Roman", serif !important;
24167
- }
24168
-
24169
- .fx-formula-kity-host .kf-editor-ui-box-item-content,
24170
- .fx-formula-kity-host .kf-editor-ui-box-item-val {
24171
- min-width: 32px;
24172
- min-height: 32px;
24173
- }
24174
-
24175
- .fx-formula-kity-host .kf-editor-ui-box-item-val svg,
24176
- .fx-formula-kity-host .kf-editor-ui-box-item-val img,
24177
- .fx-formula-kity-host .kf-editor-ui-area-item-img,
24178
- .fx-formula-kity-host .kf-editor-ui-area-item-text {
24179
- display: block;
24180
- }
24181
-
24182
- .fx-formula-editor-loading {
24183
- height: var(--fx-formula-editor-body-height);
24184
- padding: 24px;
24185
- color: #4b5563;
24186
- text-align: center;
24187
- display: flex;
24188
- align-items: center;
24189
- justify-content: center;
24190
- }
24191
-
24192
- .fx-formula-editor-error {
24193
- padding: 24px;
24194
- color: #dc2626;
24195
- font-size: 14px;
24196
- }
24197
-
24198
- .fx-formula-editor-error pre {
24199
- white-space: pre-wrap;
24200
- word-break: break-all;
24201
- color: #991b1b;
24202
- background: #fef2f2;
24203
- border: 1px solid #fecaca;
24204
- border-radius: 8px;
24205
- padding: 12px;
24206
- margin-top: 8px;
24207
- }
24208
-
24209
- .fx-formula-modal__footer {
24210
- min-height: 64px;
24211
- padding: 12px 20px;
24212
- border-top: 1px solid #e5e7eb;
24213
- display: flex;
24214
- align-items: center;
24215
- justify-content: flex-end;
24216
- gap: 12px;
24217
- flex-shrink: 0;
24218
- position: relative;
24219
- z-index: 1;
24220
- background: #fff;
24221
- border-radius: 0 0 14px 14px;
24222
- }
24223
-
24224
- .fx-formula-modal__button {
24225
- appearance: none;
24226
- border: 1px solid #d1d5db;
24227
- background: #fff;
24228
- color: #111827;
24229
- border-radius: 8px;
24230
- padding: 8px 14px;
24231
- font-size: 14px;
24232
- cursor: pointer;
24233
- }
24234
-
24235
- .fx-formula-modal__button--primary {
24236
- border-color: #2563eb;
24237
- background: #2563eb;
24238
- color: #fff;
24239
- }
24240
-
24241
- .formulax-math {
24242
- display: inline-flex;
24243
- align-items: center;
24244
- vertical-align: middle;
24245
- line-height: 1;
24246
- padding: 0 2px;
24247
- margin: 0 1px;
24248
- border-radius: 3px;
24249
- background: transparent;
24250
- cursor: pointer;
24251
- user-select: none;
24252
- }
24253
-
24254
- .formulax-math:hover {
24255
- outline: 1px solid rgba(37, 99, 235, 0.35);
24256
- background: rgba(37, 99, 235, 0.06);
24257
- }
24258
-
24259
- .formulax-math__svg {
24260
- display: inline-block;
24261
- flex: 0 0 auto;
24262
- max-width: 100%;
24263
- vertical-align: -0.35em;
24264
- pointer-events: none;
24265
- }
24266
-
24267
- .formulax-math__image {
24268
- display: inline-block;
24269
- max-width: 100%;
24270
- height: auto;
24271
- vertical-align: middle;
24272
- pointer-events: none;
24273
- }
24274
- `;
24275
- function ensureFormulaXModalStyles(doc2 = document) {
24276
- if (doc2.getElementById(STYLE_ID)) return;
24277
- const style = doc2.createElement("style");
24278
- style.id = STYLE_ID;
24279
- style.textContent = formulaXModalStyles;
24280
- doc2.head.appendChild(style);
24191
+ // ../renderer/src/svg.ts
24192
+ function readRenderedFormulaSvgBox(svg2) {
24193
+ return getInlineSvgContent(svg2)?.box ?? readSvgBox(svg2);
24281
24194
  }
24282
- function mountFormulaXEditor(root2, options = {}) {
24283
- let destroyed = false;
24284
- let latestLatex = options.initialLatex ?? "";
24285
- let handle = null;
24286
- const initialLatex = latestLatex.trim() ? latestLatex : EMPTY_FORMULA_PLACEHOLDER;
24287
- root2.classList.add("fx-formula-kity-host");
24288
- root2.innerHTML = `
24289
- <div class="fx-formula-editor-loading" role="status" aria-live="polite">
24290
- Loading FormulaX editor...
24291
- </div>
24292
- `;
24293
- const readyPromise = mountKityEditor(root2, {
24294
- initialLatex,
24295
- height: options.height ?? "100%",
24296
- autofocus: options.autofocus ?? true,
24297
- assets: options.assets,
24298
- render: {
24299
- fontsize: options.render?.fontsize ?? 40
24300
- }
24301
- }).then((nextHandle) => {
24302
- if (destroyed) {
24303
- nextHandle.destroy();
24304
- throw new Error("FormulaX editor mount cancelled");
24305
- }
24306
- handle = nextHandle;
24307
- return nextHandle;
24308
- }).catch((error) => {
24309
- console.error("[FormulaX] Failed to load FormulaX editor:", error);
24310
- if (!destroyed) {
24311
- root2.innerHTML = `
24312
- <div class="fx-formula-editor-error">
24313
- Failed to load FormulaX editor.
24314
- <pre>${escapeHtml(error instanceof Error ? error.message : String(error))}</pre>
24315
- </div>
24316
- `;
24317
- }
24318
- throw error;
24319
- });
24320
- const getCurrentLatex = async () => {
24321
- const readyHandle = handle ?? await readyPromise;
24322
- const latex = await tryReadLatexFromKityHandle(readyHandle);
24323
- if (latex !== null) {
24324
- latestLatex = latex;
24325
- }
24326
- return latestLatex;
24195
+ function serializeSvgForInsertion(svg2) {
24196
+ const content = getInlineSvgContent(svg2);
24197
+ const inlineViewport = content ? createInlineSvgViewport(content.box) : null;
24198
+ const clone = content && inlineViewport ? createInlineSvgClone(svg2, content, inlineViewport) : svg2.cloneNode(true);
24199
+ uniquifySvgIds(clone);
24200
+ sizeSvgForInlineDisplay(clone, svg2, inlineViewport);
24201
+ clone.setAttribute("focusable", "false");
24202
+ clone.setAttribute("aria-hidden", "true");
24203
+ clone.setAttribute("class", mergeClassNames(clone.getAttribute("class"), "formulax-math__svg"));
24204
+ return clone.outerHTML;
24205
+ }
24206
+ function getInlineSvgContent(svg2) {
24207
+ const selectorCandidates = [
24208
+ '[data-type="kf-editor-exp-content-box"]',
24209
+ '[data-root="true"] [data-type="kf-editor-exp-content-box"]',
24210
+ 'g[data-root="true"]'
24211
+ ];
24212
+ for (const selector of selectorCandidates) {
24213
+ const element = svg2.querySelector(selector);
24214
+ if (!element) continue;
24215
+ const rootSpace = readSvgBoxInRootSpace(element);
24216
+ if (!rootSpace) continue;
24217
+ return {
24218
+ box: rootSpace.box,
24219
+ matrix: rootSpace.matrix,
24220
+ root: element
24221
+ };
24222
+ }
24223
+ return null;
24224
+ }
24225
+ function readSvgBoxInRootSpace(element) {
24226
+ const box = readSvgBox(element);
24227
+ const matrix = getSvgRootSpaceMatrix(element);
24228
+ if (!box || !matrix) {
24229
+ return null;
24230
+ }
24231
+ const points = [
24232
+ { x: box.x, y: box.y },
24233
+ { x: box.x + box.width, y: box.y },
24234
+ { x: box.x, y: box.y + box.height },
24235
+ { x: box.x + box.width, y: box.y + box.height }
24236
+ ].map((point) => ({
24237
+ x: matrix.a * point.x + matrix.c * point.y + matrix.e,
24238
+ y: matrix.b * point.x + matrix.d * point.y + matrix.f
24239
+ }));
24240
+ const xs = points.map((point) => point.x);
24241
+ const ys = points.map((point) => point.y);
24242
+ const x = Math.min(...xs);
24243
+ const y = Math.min(...ys);
24244
+ const width2 = Math.max(...xs) - x;
24245
+ const height2 = Math.max(...ys) - y;
24246
+ if (!Number.isFinite(width2) || !Number.isFinite(height2) || width2 <= 0 || height2 <= 0) {
24247
+ return null;
24248
+ }
24249
+ return {
24250
+ box: { x, y, width: width2, height: height2 },
24251
+ matrix
24327
24252
  };
24253
+ }
24254
+ function getSvgRootSpaceMatrix(element) {
24255
+ const elementMatrix = typeof element.getCTM === "function" ? element.getCTM() : null;
24256
+ const rootMatrix = typeof element.ownerSVGElement?.getCTM === "function" ? element.ownerSVGElement.getCTM() : null;
24257
+ if (!elementMatrix) {
24258
+ return null;
24259
+ }
24260
+ return rootMatrix ? multiplySvgMatrices(invertSvgMatrix(rootMatrix), elementMatrix) : toSvgMatrixLike(elementMatrix);
24261
+ }
24262
+ function invertSvgMatrix(matrix) {
24263
+ const determinant = matrix.a * matrix.d - matrix.b * matrix.c;
24264
+ if (!Number.isFinite(determinant) || determinant === 0) {
24265
+ return {
24266
+ a: 1,
24267
+ b: 0,
24268
+ c: 0,
24269
+ d: 1,
24270
+ e: 0,
24271
+ f: 0
24272
+ };
24273
+ }
24328
24274
  return {
24329
- root: root2,
24330
- getLatex: getCurrentLatex,
24331
- async getState() {
24332
- const latex = await getCurrentLatex();
24333
- try {
24334
- return {
24335
- ...createEmptyState(),
24336
- doc: parseLatex(latex)
24337
- };
24338
- } catch {
24339
- return createEmptyState();
24340
- }
24341
- },
24342
- async getRenderHtml() {
24343
- await readyPromise;
24344
- await waitForFormulaSvgLayout(root2);
24345
- return renderCurrentFormulaAsSvgHtml(root2);
24346
- },
24347
- destroy() {
24348
- if (destroyed) return;
24349
- destroyed = true;
24350
- void readyPromise.then((readyHandle) => readyHandle.destroy()).catch(() => void 0);
24351
- root2.innerHTML = "";
24352
- }
24275
+ a: matrix.d / determinant,
24276
+ b: -matrix.b / determinant,
24277
+ c: -matrix.c / determinant,
24278
+ d: matrix.a / determinant,
24279
+ e: (matrix.c * matrix.f - matrix.d * matrix.e) / determinant,
24280
+ f: (matrix.b * matrix.e - matrix.a * matrix.f) / determinant
24281
+ };
24282
+ }
24283
+ function multiplySvgMatrices(left, right) {
24284
+ return {
24285
+ a: left.a * right.a + left.c * right.b,
24286
+ b: left.b * right.a + left.d * right.b,
24287
+ c: left.a * right.c + left.c * right.d,
24288
+ d: left.b * right.c + left.d * right.d,
24289
+ e: left.a * right.e + left.c * right.f + left.e,
24290
+ f: left.b * right.e + left.d * right.f + left.f
24353
24291
  };
24354
24292
  }
24355
- async function tryReadLatexFromKityHandle(handle) {
24293
+ function toSvgMatrixLike(matrix) {
24294
+ return {
24295
+ a: matrix.a,
24296
+ b: matrix.b,
24297
+ c: matrix.c,
24298
+ d: matrix.d,
24299
+ e: matrix.e,
24300
+ f: matrix.f
24301
+ };
24302
+ }
24303
+ function readSvgBox(element) {
24304
+ if (typeof element.getBBox !== "function") {
24305
+ return null;
24306
+ }
24356
24307
  try {
24357
- let isEmpty = false;
24358
- handle.ready(function ready() {
24359
- const result = this.execCommand("content.is.empty");
24360
- isEmpty = result === true;
24361
- });
24362
- if (isEmpty) {
24363
- return "";
24308
+ const box = element.getBBox();
24309
+ if (!Number.isFinite(box.width) || !Number.isFinite(box.height) || box.width <= 0 || box.height <= 0) {
24310
+ return null;
24364
24311
  }
24312
+ return {
24313
+ x: box.x,
24314
+ y: box.y,
24315
+ width: box.width,
24316
+ height: box.height
24317
+ };
24365
24318
  } catch {
24319
+ return null;
24366
24320
  }
24367
- const candidates = [
24368
- "get.source",
24369
- "getSource",
24370
- "getLatex",
24371
- "get.latex",
24372
- "get.content",
24373
- "getContent"
24374
- ];
24375
- for (const command of candidates) {
24376
- try {
24377
- let value = null;
24378
- handle.ready(function ready() {
24379
- value = this.execCommand(command);
24380
- });
24381
- if (typeof value === "string" && value.trim()) {
24382
- return value;
24383
- }
24384
- if (value && typeof value === "object" && "latex" in value) {
24385
- const latex = value.latex;
24386
- if (typeof latex === "string" && latex.trim()) {
24387
- return latex;
24388
- }
24389
- }
24390
- } catch {
24321
+ }
24322
+ function createInlineSvgViewport(contentBox) {
24323
+ const edgePadding = Math.max(0.5, Math.min(contentBox.width, contentBox.height) * 6e-3);
24324
+ const inset = edgePadding / 2;
24325
+ return {
24326
+ x: contentBox.x - inset,
24327
+ y: contentBox.y - inset,
24328
+ width: contentBox.width + edgePadding,
24329
+ height: contentBox.height + edgePadding
24330
+ };
24331
+ }
24332
+ function createInlineSvgClone(source, content, viewport) {
24333
+ const clone = source.cloneNode(false);
24334
+ const ownerDocument = source.ownerDocument;
24335
+ copySvgRootAttributes(source, clone);
24336
+ clone.setAttribute(
24337
+ "viewBox",
24338
+ `0 0 ${roundLength(viewport.width)} ${roundLength(viewport.height)}`
24339
+ );
24340
+ Array.from(source.children).forEach((child) => {
24341
+ if (child.tagName.toLowerCase() === "defs") {
24342
+ clone.appendChild(child.cloneNode(true));
24391
24343
  }
24344
+ });
24345
+ const wrapper = ownerDocument.createElementNS("http://www.w3.org/2000/svg", "g");
24346
+ wrapper.setAttribute(
24347
+ "transform",
24348
+ `translate(${roundLength(-viewport.x)} ${roundLength(-viewport.y)})`
24349
+ );
24350
+ const flattened = ownerDocument.createElementNS("http://www.w3.org/2000/svg", "g");
24351
+ flattened.setAttribute(
24352
+ "transform",
24353
+ `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)})`
24354
+ );
24355
+ flattened.appendChild(content.root.cloneNode(true));
24356
+ wrapper.appendChild(flattened);
24357
+ clone.appendChild(wrapper);
24358
+ return clone;
24359
+ }
24360
+ function copySvgRootAttributes(source, target) {
24361
+ const excluded = /* @__PURE__ */ new Set([
24362
+ "id",
24363
+ "width",
24364
+ "height",
24365
+ "viewBox",
24366
+ "class",
24367
+ "focusable",
24368
+ "aria-hidden",
24369
+ "xmlns",
24370
+ "xmlns:xlink"
24371
+ ]);
24372
+ Array.from(source.attributes).forEach((attribute) => {
24373
+ if (excluded.has(attribute.name)) return;
24374
+ target.setAttribute(attribute.name, attribute.value);
24375
+ });
24376
+ }
24377
+ function sizeSvgForInlineDisplay(clone, source, viewport) {
24378
+ const viewBox = clone.viewBox?.baseVal;
24379
+ const rect = source.getBoundingClientRect();
24380
+ const width2 = viewport?.width || viewBox?.width || rect.width || Number(clone.getAttribute("width")) || 1;
24381
+ const height2 = viewport?.height || viewBox?.height || rect.height || Number(clone.getAttribute("height")) || 1;
24382
+ const ratio = Math.max(0.1, width2 / Math.max(1, height2));
24383
+ const inlineHeightEm = 0.875;
24384
+ const inlineWidthEm = Math.min(40, Math.max(0.75, ratio * inlineHeightEm));
24385
+ clone.setAttribute("width", roundLength(width2));
24386
+ clone.setAttribute("height", roundLength(height2));
24387
+ clone.setAttribute(
24388
+ "style",
24389
+ mergeInlineStyles(
24390
+ clone.getAttribute("style"),
24391
+ `width:${roundLength(inlineWidthEm)}em`,
24392
+ `height:${inlineHeightEm}em`
24393
+ )
24394
+ );
24395
+ }
24396
+ function roundLength(value) {
24397
+ return String(Math.round(value * 1e3) / 1e3);
24398
+ }
24399
+ function uniquifySvgIds(svg2) {
24400
+ const idMap = /* @__PURE__ */ new Map();
24401
+ const prefix = `fx-${randomIdPrefix()}-`;
24402
+ const elementsWithId = svg2.querySelectorAll("[id]");
24403
+ elementsWithId.forEach((element) => {
24404
+ const id = element.getAttribute("id");
24405
+ if (!id) return;
24406
+ const nextId = `${prefix}${id}`;
24407
+ idMap.set(id, nextId);
24408
+ element.setAttribute("id", nextId);
24409
+ });
24410
+ if (!idMap.size) return;
24411
+ svg2.querySelectorAll("*").forEach((element) => {
24412
+ Array.from(element.attributes).forEach((attribute) => {
24413
+ const nextValue = rewriteSvgReferences(attribute.value, idMap);
24414
+ if (nextValue !== attribute.value) {
24415
+ element.setAttribute(attribute.name, nextValue);
24416
+ }
24417
+ });
24418
+ });
24419
+ }
24420
+ function randomIdPrefix() {
24421
+ return Math.random().toString(36).slice(2, 5).padEnd(3, "0");
24422
+ }
24423
+ function rewriteSvgReferences(value, idMap) {
24424
+ let nextValue = value;
24425
+ idMap.forEach((nextId, id) => {
24426
+ nextValue = nextValue.replaceAll(`#${id}`, `#${nextId}`).replaceAll(`url(${id})`, `url(${nextId})`).replaceAll(`url(#${id})`, `url(#${nextId})`);
24427
+ });
24428
+ return nextValue;
24429
+ }
24430
+ function mergeClassNames(...values) {
24431
+ return values.flatMap((value) => value?.split(/\s+/) ?? []).filter(Boolean).filter((value, index, list) => list.indexOf(value) === index).join(" ");
24432
+ }
24433
+ function mergeInlineStyles(...values) {
24434
+ return values.flatMap((value) => value?.split(";") ?? []).map((value) => value.trim()).filter(Boolean).join("; ");
24435
+ }
24436
+
24437
+ // ../renderer-kity/src/dom.ts
24438
+ async function waitForDocumentFonts(doc2) {
24439
+ if (!doc2.fonts?.ready) return;
24440
+ try {
24441
+ await doc2.fonts.ready;
24442
+ } catch {
24392
24443
  }
24393
- return null;
24394
24444
  }
24395
- function renderCurrentFormulaAsSvgHtml(root2) {
24396
- const svg2 = findFormulaSvg(root2);
24445
+ function waitForAnimationFrame(view) {
24446
+ return new Promise((resolve) => {
24447
+ view.requestAnimationFrame(() => resolve());
24448
+ });
24449
+ }
24450
+
24451
+ // ../renderer-kity/src/serialize.ts
24452
+ function findKityFormulaSvg(root2) {
24453
+ return root2.querySelector(
24454
+ ".kf-editor-edit-area svg, .kf-editor-canvas-container svg, svg"
24455
+ );
24456
+ }
24457
+ function serializeKityFormulaFromRoot(root2) {
24458
+ const svg2 = findKityFormulaSvg(root2);
24397
24459
  if (!svg2) {
24398
24460
  return "";
24399
24461
  }
24400
24462
  return serializeSvgForInsertion(svg2);
24401
24463
  }
24402
- async function waitForFormulaSvgLayout(root2) {
24464
+ async function waitForKityFormulaSvgLayout(root2) {
24403
24465
  const doc2 = root2.ownerDocument ?? document;
24404
24466
  const view = doc2.defaultView ?? window;
24405
24467
  await waitForDocumentFonts(doc2);
@@ -24413,280 +24475,517 @@ var FormulaX = (() => {
24413
24475
  previous = current;
24414
24476
  }
24415
24477
  }
24416
- function findFormulaSvg(root2) {
24417
- return root2.querySelector(
24418
- ".kf-editor-edit-area svg, .kf-editor-canvas-container svg, svg"
24419
- );
24420
- }
24421
24478
  function readRenderedFormulaBox(root2) {
24422
- const svg2 = findFormulaSvg(root2);
24479
+ const svg2 = findKityFormulaSvg(root2);
24423
24480
  if (!svg2) {
24424
24481
  return null;
24425
24482
  }
24426
- return getInlineSvgContent(svg2)?.box ?? readSvgBox(svg2);
24483
+ return readRenderedFormulaSvgBox(svg2);
24427
24484
  }
24428
24485
  function areSvgBoxesClose(left, right) {
24429
24486
  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;
24430
24487
  }
24431
- async function waitForDocumentFonts(doc2) {
24432
- if (!doc2.fonts?.ready) {
24488
+
24489
+ // src/perf.ts
24490
+ function getPerfHost2() {
24491
+ return globalThis;
24492
+ }
24493
+ function getPerfState2() {
24494
+ const host = getPerfHost2();
24495
+ host.__FORMULAX_PERF_STATE__ ??= {
24496
+ reportedMeasureCount: 0,
24497
+ reportScheduled: false
24498
+ };
24499
+ return host.__FORMULAX_PERF_STATE__;
24500
+ }
24501
+ function hasPerfSupport2() {
24502
+ return typeof performance !== "undefined" && typeof performance.mark === "function" && typeof performance.measure === "function" && typeof performance.getEntriesByType === "function";
24503
+ }
24504
+ function isPerfDebugEnabled2() {
24505
+ return getPerfHost2().__FORMULAX_PERF__ === true;
24506
+ }
24507
+ function schedulePerfReport2() {
24508
+ if (!hasPerfSupport2() || !isPerfDebugEnabled2()) {
24433
24509
  return;
24434
24510
  }
24435
- try {
24436
- await doc2.fonts.ready;
24437
- } catch {
24511
+ const state = getPerfState2();
24512
+ if (state.reportScheduled) {
24513
+ return;
24438
24514
  }
24439
- }
24440
- function waitForAnimationFrame(view) {
24441
- return new Promise((resolve) => {
24442
- view.requestAnimationFrame(() => resolve());
24515
+ state.reportScheduled = true;
24516
+ queueMicrotask(() => {
24517
+ state.reportScheduled = false;
24518
+ const entries = performance.getEntriesByType("measure").filter((entry) => entry.name.startsWith("fx:")).sort((left, right) => left.startTime - right.startTime);
24519
+ const nextEntries = entries.slice(state.reportedMeasureCount);
24520
+ state.reportedMeasureCount = entries.length;
24521
+ if (!nextEntries.length) {
24522
+ return;
24523
+ }
24524
+ console.table(nextEntries.map((entry) => ({
24525
+ name: entry.name,
24526
+ duration: Number(entry.duration.toFixed(2)),
24527
+ startTime: Number(entry.startTime.toFixed(2))
24528
+ })));
24443
24529
  });
24444
24530
  }
24445
- function serializeSvgForInsertion(svg2) {
24446
- const content = getInlineSvgContent(svg2);
24447
- const inlineViewport = content ? createInlineSvgViewport(content.box) : null;
24448
- const clone = content && inlineViewport ? createInlineSvgClone(svg2, content, inlineViewport) : svg2.cloneNode(true);
24449
- uniquifySvgIds(clone);
24450
- sizeSvgForInlineDisplay(clone, svg2, inlineViewport);
24451
- clone.removeAttribute("id");
24452
- clone.removeAttribute("xmlns");
24453
- clone.removeAttribute("xmlns:xlink");
24454
- clone.setAttribute("class", mergeClassNames(clone.getAttribute("class"), "formulax-math__svg"));
24455
- clone.setAttribute("focusable", "false");
24456
- clone.setAttribute("aria-hidden", "true");
24457
- clone.setAttribute("preserveAspectRatio", clone.getAttribute("preserveAspectRatio") || "xMinYMin meet");
24458
- return new XMLSerializer().serializeToString(clone);
24459
- }
24460
- function getInlineSvgContent(svg2) {
24461
- const candidates = [
24462
- '[data-root="true"] > g[data-type="kf-editor-exp-content-box"]',
24463
- 'g[data-type="kf-editor-exp-content-box"]',
24464
- 'g[data-type="kf-container"]',
24465
- "svg > g, g"
24466
- ];
24467
- for (const selector of candidates) {
24468
- const content = svg2.querySelector(selector);
24469
- const rootSpace = content ? readSvgBoxInRootSpace(content) : null;
24470
- if (content && rootSpace) {
24471
- return {
24472
- root: content,
24473
- box: rootSpace.box,
24474
- matrix: rootSpace.matrix
24475
- };
24476
- }
24531
+ function markFormulaXPerf2(name) {
24532
+ if (!hasPerfSupport2()) {
24533
+ return null;
24477
24534
  }
24478
- return null;
24535
+ const markName = `${name}::${Date.now()}::${Math.random().toString(36).slice(2, 8)}`;
24536
+ performance.mark(markName);
24537
+ return markName;
24479
24538
  }
24480
- function readSvgBoxInRootSpace(element) {
24481
- const box = readSvgBox(element);
24482
- const matrix = getSvgRootSpaceMatrix(element);
24483
- if (!box || !matrix) {
24539
+ function measureFormulaXPerf2(name, startMark, endMark) {
24540
+ if (!hasPerfSupport2() || !startMark) {
24484
24541
  return null;
24485
24542
  }
24486
- const points = [
24487
- { x: box.x, y: box.y },
24488
- { x: box.x + box.width, y: box.y },
24489
- { x: box.x, y: box.y + box.height },
24490
- { x: box.x + box.width, y: box.y + box.height }
24491
- ].map((point) => ({
24492
- x: matrix.a * point.x + matrix.c * point.y + matrix.e,
24493
- y: matrix.b * point.x + matrix.d * point.y + matrix.f
24494
- }));
24495
- const xs = points.map((point) => point.x);
24496
- const ys = points.map((point) => point.y);
24497
- const x = Math.min(...xs);
24498
- const y = Math.min(...ys);
24499
- const width2 = Math.max(...xs) - x;
24500
- const height2 = Math.max(...ys) - y;
24501
- if (!Number.isFinite(width2) || !Number.isFinite(height2) || width2 <= 0 || height2 <= 0) {
24543
+ const resolvedEndMark = endMark ?? markFormulaXPerf2(`${name}:end`);
24544
+ if (!resolvedEndMark) {
24502
24545
  return null;
24503
24546
  }
24504
- return {
24505
- box: { x, y, width: width2, height: height2 },
24506
- matrix
24547
+ performance.measure(name, startMark, resolvedEndMark);
24548
+ schedulePerfReport2();
24549
+ return resolvedEndMark;
24550
+ }
24551
+ function recordFormulaXPerfPoint(name) {
24552
+ const markName = markFormulaXPerf2(name);
24553
+ if (!markName) {
24554
+ return;
24555
+ }
24556
+ measureFormulaXPerf2(name, markName, markName);
24557
+ clearFormulaXPerfMarks2(markName);
24558
+ }
24559
+ function clearFormulaXPerfMarks2(...marks) {
24560
+ if (!hasPerfSupport2()) {
24561
+ return;
24562
+ }
24563
+ for (const mark of marks) {
24564
+ if (!mark) {
24565
+ continue;
24566
+ }
24567
+ performance.clearMarks(mark);
24568
+ }
24569
+ }
24570
+ async function preloadFormulaXEditor() {
24571
+ await ensureKityRuntime();
24572
+ }
24573
+ function scheduleFormulaXEditorPreload(mode, target) {
24574
+ if (mode === false || typeof window === "undefined") {
24575
+ return () => void 0;
24576
+ }
24577
+ let disposed = false;
24578
+ let triggered = false;
24579
+ const cleanupCallbacks = [];
24580
+ const trigger = () => {
24581
+ if (disposed || triggered) {
24582
+ return;
24583
+ }
24584
+ triggered = true;
24585
+ while (cleanupCallbacks.length) {
24586
+ cleanupCallbacks.pop()?.();
24587
+ }
24588
+ void preloadFormulaXEditor();
24507
24589
  };
24508
- }
24509
- function getSvgRootSpaceMatrix(element) {
24510
- const elementMatrix = typeof element.getCTM === "function" ? element.getCTM() : null;
24511
- const rootMatrix = typeof element.ownerSVGElement?.getCTM === "function" ? element.ownerSVGElement.getCTM() : null;
24512
- if (!elementMatrix) {
24513
- return null;
24590
+ if (mode === "idle") {
24591
+ const host = getPerfHost2();
24592
+ if (typeof host.requestIdleCallback === "function") {
24593
+ const handle = host.requestIdleCallback(() => {
24594
+ trigger();
24595
+ });
24596
+ cleanupCallbacks.push(() => {
24597
+ host.cancelIdleCallback?.(handle);
24598
+ });
24599
+ } else {
24600
+ const handle = window.setTimeout(() => {
24601
+ trigger();
24602
+ }, 1);
24603
+ cleanupCallbacks.push(() => {
24604
+ window.clearTimeout(handle);
24605
+ });
24606
+ }
24607
+ return () => {
24608
+ disposed = true;
24609
+ while (cleanupCallbacks.length) {
24610
+ cleanupCallbacks.pop()?.();
24611
+ }
24612
+ };
24514
24613
  }
24515
- return rootMatrix ? multiplySvgMatrices(invertSvgMatrix(rootMatrix), elementMatrix) : toSvgMatrixLike(elementMatrix);
24516
- }
24517
- function invertSvgMatrix(matrix) {
24518
- const determinant = matrix.a * matrix.d - matrix.b * matrix.c;
24519
- if (!Number.isFinite(determinant) || determinant === 0) {
24520
- return {
24521
- a: 1,
24522
- b: 0,
24523
- c: 0,
24524
- d: 1,
24525
- e: 0,
24526
- f: 0
24614
+ if (target && "addEventListener" in target && "removeEventListener" in target) {
24615
+ const eventTarget = target;
24616
+ const onActivate = () => {
24617
+ trigger();
24527
24618
  };
24619
+ eventTarget.addEventListener("pointerenter", onActivate, { once: true, passive: true });
24620
+ eventTarget.addEventListener("focusin", onActivate, { once: true });
24621
+ cleanupCallbacks.push(() => {
24622
+ eventTarget.removeEventListener("pointerenter", onActivate);
24623
+ eventTarget.removeEventListener("focusin", onActivate);
24624
+ });
24528
24625
  }
24529
- return {
24530
- a: matrix.d / determinant,
24531
- b: -matrix.b / determinant,
24532
- c: -matrix.c / determinant,
24533
- d: matrix.a / determinant,
24534
- e: (matrix.c * matrix.f - matrix.d * matrix.e) / determinant,
24535
- f: (matrix.b * matrix.e - matrix.a * matrix.f) / determinant
24626
+ return () => {
24627
+ disposed = true;
24628
+ while (cleanupCallbacks.length) {
24629
+ cleanupCallbacks.pop()?.();
24630
+ }
24536
24631
  };
24537
24632
  }
24538
- function multiplySvgMatrices(left, right) {
24539
- return {
24540
- a: left.a * right.a + left.c * right.b,
24541
- b: left.b * right.a + left.d * right.b,
24542
- c: left.a * right.c + left.c * right.d,
24543
- d: left.b * right.c + left.d * right.d,
24544
- e: left.a * right.e + left.c * right.f + left.e,
24545
- f: left.b * right.e + left.d * right.f + left.f
24546
- };
24633
+ function waitForFormulaXAnimationFrame() {
24634
+ if (typeof window === "undefined" || typeof window.requestAnimationFrame !== "function") {
24635
+ return Promise.resolve();
24636
+ }
24637
+ return new Promise((resolve) => {
24638
+ window.requestAnimationFrame(() => resolve());
24639
+ });
24640
+ }
24641
+
24642
+ // src/formula-modal.ts
24643
+ var EMPTY_FORMULA_PLACEHOLDER = "\\placeholder ";
24644
+ var STYLE_ID = "fx-formula-modal-styles";
24645
+ var formulaXModalStyles = `
24646
+ .fx-formula-modal-open {
24647
+ overflow: hidden;
24648
+ }
24649
+
24650
+ .fx-formula-modal-root {
24651
+ position: fixed;
24652
+ inset: 0;
24653
+ z-index: 2147483000;
24654
+ display: flex;
24655
+ align-items: center;
24656
+ justify-content: center;
24657
+ }
24658
+
24659
+ .fx-formula-modal-backdrop {
24660
+ position: absolute;
24661
+ inset: 0;
24662
+ background: rgba(15, 23, 42, 0.48);
24663
+ }
24664
+
24665
+ .fx-formula-modal {
24666
+ --fx-formula-editor-body-height: 264px;
24667
+ --fx-formula-workspace-height: 168px;
24668
+ position: relative;
24669
+ width: min(860px, calc(100vw - 32px));
24670
+ height: auto;
24671
+ max-height: calc(100vh - 32px);
24672
+ background: #fff;
24673
+ border-radius: 14px;
24674
+ box-shadow: 0 24px 80px rgba(15, 23, 42, 0.28);
24675
+ display: flex;
24676
+ flex-direction: column;
24677
+ overflow: visible;
24678
+ isolation: isolate;
24679
+ }
24680
+
24681
+ .fx-formula-modal__header,
24682
+ .fx-formula-modal__footer,
24683
+ .fx-formula-modal__title,
24684
+ .fx-formula-modal__close,
24685
+ .fx-formula-modal__button,
24686
+ .fx-formula-editor-loading,
24687
+ .fx-formula-editor-error {
24688
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
24689
+ }
24690
+
24691
+ .fx-formula-modal__header {
24692
+ min-height: 56px;
24693
+ padding: 0 20px;
24694
+ border-bottom: 1px solid #e5e7eb;
24695
+ display: flex;
24696
+ align-items: center;
24697
+ justify-content: space-between;
24698
+ flex-shrink: 0;
24699
+ position: relative;
24700
+ z-index: 3;
24701
+ background: #fff;
24702
+ border-radius: 14px 14px 0 0;
24703
+ }
24704
+
24705
+ .fx-formula-modal__title {
24706
+ font-size: 16px;
24707
+ font-weight: 650;
24708
+ margin: 0;
24709
+ color: #111827;
24710
+ }
24711
+
24712
+ .fx-formula-modal__close {
24713
+ border: 0;
24714
+ background: transparent;
24715
+ font-size: 24px;
24716
+ line-height: 1;
24717
+ cursor: pointer;
24718
+ color: #6b7280;
24719
+ }
24720
+
24721
+ .fx-formula-modal__body {
24722
+ flex: 0 0 auto;
24723
+ height: var(--fx-formula-editor-body-height);
24724
+ padding: 0;
24725
+ overflow: visible;
24726
+ min-height: var(--fx-formula-editor-body-height);
24727
+ position: relative;
24728
+ z-index: 2;
24729
+ }
24730
+
24731
+ .fx-formula-editor-host {
24732
+ width: 100%;
24733
+ height: var(--fx-formula-editor-body-height);
24734
+ min-height: var(--fx-formula-editor-body-height);
24735
+ overflow: visible;
24736
+ position: relative;
24737
+ }
24738
+
24739
+ .fx-formula-kity-host {
24740
+ width: 100%;
24741
+ height: var(--fx-formula-editor-body-height);
24742
+ min-height: var(--fx-formula-editor-body-height);
24743
+ overflow: visible;
24744
+ position: relative;
24745
+ }
24746
+
24747
+ .fx-formula-kity-host .kf-editor {
24748
+ height: var(--fx-formula-editor-body-height) !important;
24749
+ overflow: visible !important;
24750
+ }
24751
+
24752
+ .fx-formula-kity-host .kf-editor-toolbar {
24753
+ overflow: visible;
24754
+ position: relative;
24755
+ z-index: 20;
24756
+ }
24757
+
24758
+ .fx-formula-kity-host .kf-editor-ui-button-mount-point,
24759
+ .fx-formula-kity-host .kf-editor-ui-area-mount,
24760
+ .fx-formula-kity-host .kf-editor-ui-box,
24761
+ .fx-formula-kity-host .kf-editor-ui-list {
24762
+ z-index: 1000;
24763
+ }
24764
+
24765
+ .fx-formula-kity-host .kf-editor-edit-area,
24766
+ .fx-formula-kity-host .kf-editor-canvas-container {
24767
+ min-height: var(--fx-formula-workspace-height);
24768
+ height: var(--fx-formula-workspace-height);
24769
+ }
24770
+
24771
+ .fx-formula-kity-host .kf-editor-edit-area {
24772
+ flex: 0 0 auto;
24773
+ overflow: hidden;
24774
+ }
24775
+
24776
+ .fx-formula-kity-host .kf-editor,
24777
+ .fx-formula-kity-host .kf-editor svg text,
24778
+ .fx-formula-kity-host .kf-editor-ui-area-item-text,
24779
+ .fx-formula-kity-host .kf-editor-ui-box-item-text,
24780
+ .fx-formula-kity-host .kf-editor-ui-box-item-val {
24781
+ font-family: "KF AMS MAIN", "Cambria Math", "Latin Modern Math", "Times New Roman", serif !important;
24782
+ }
24783
+
24784
+ .fx-formula-kity-host .kf-editor-ui-box-item-content,
24785
+ .fx-formula-kity-host .kf-editor-ui-box-item-val {
24786
+ min-width: 32px;
24787
+ min-height: 32px;
24788
+ }
24789
+
24790
+ .fx-formula-kity-host .kf-editor-ui-box-item-val svg,
24791
+ .fx-formula-kity-host .kf-editor-ui-box-item-val img,
24792
+ .fx-formula-kity-host .kf-editor-ui-area-item-img,
24793
+ .fx-formula-kity-host .kf-editor-ui-area-item-text {
24794
+ display: block;
24795
+ }
24796
+
24797
+ .fx-formula-editor-loading {
24798
+ height: var(--fx-formula-editor-body-height);
24799
+ padding: 24px;
24800
+ color: #4b5563;
24801
+ text-align: center;
24802
+ display: flex;
24803
+ align-items: center;
24804
+ justify-content: center;
24805
+ }
24806
+
24807
+ .fx-formula-editor-error {
24808
+ padding: 24px;
24809
+ color: #dc2626;
24810
+ font-size: 14px;
24811
+ }
24812
+
24813
+ .fx-formula-editor-error pre {
24814
+ white-space: pre-wrap;
24815
+ word-break: break-all;
24816
+ color: #991b1b;
24817
+ background: #fef2f2;
24818
+ border: 1px solid #fecaca;
24819
+ border-radius: 8px;
24820
+ padding: 12px;
24821
+ margin-top: 8px;
24822
+ }
24823
+
24824
+ .fx-formula-modal__footer {
24825
+ min-height: 64px;
24826
+ padding: 12px 20px;
24827
+ border-top: 1px solid #e5e7eb;
24828
+ display: flex;
24829
+ align-items: center;
24830
+ justify-content: flex-end;
24831
+ gap: 12px;
24832
+ flex-shrink: 0;
24833
+ position: relative;
24834
+ z-index: 1;
24835
+ background: #fff;
24836
+ border-radius: 0 0 14px 14px;
24837
+ }
24838
+
24839
+ .fx-formula-modal__button {
24840
+ appearance: none;
24841
+ border: 1px solid #d1d5db;
24842
+ background: #fff;
24843
+ color: #111827;
24844
+ border-radius: 8px;
24845
+ padding: 8px 14px;
24846
+ font-size: 14px;
24847
+ cursor: pointer;
24848
+ }
24849
+
24850
+ .fx-formula-modal__button--primary {
24851
+ border-color: #2563eb;
24852
+ background: #2563eb;
24853
+ color: #fff;
24854
+ }
24855
+ `;
24856
+ function ensureFormulaXModalStyles(doc2 = document) {
24857
+ ensureFormulaXBaseStyles(doc2);
24858
+ if (doc2.getElementById(STYLE_ID)) return;
24859
+ const style = doc2.createElement("style");
24860
+ style.id = STYLE_ID;
24861
+ style.textContent = formulaXModalStyles;
24862
+ doc2.head.appendChild(style);
24863
+ }
24864
+ function renderFormulaXEditorLoadingState(root2) {
24865
+ root2.classList.add("fx-formula-kity-host");
24866
+ root2.innerHTML = `
24867
+ <div class="fx-formula-editor-loading" role="status" aria-live="polite">
24868
+ Loading FormulaX editor...
24869
+ </div>
24870
+ `;
24547
24871
  }
24548
- function toSvgMatrixLike(matrix) {
24872
+ function mountFormulaXEditor(root2, options = {}) {
24873
+ recordFormulaXPerfPoint("fx:formula-editor:mount:start");
24874
+ const mountStart = markFormulaXPerf2("fx:formula-editor:mount:start:scope");
24875
+ let destroyed = false;
24876
+ let latestLatex = options.initialLatex ?? "";
24877
+ let handle = null;
24878
+ const initialLatex = latestLatex.trim() ? latestLatex : EMPTY_FORMULA_PLACEHOLDER;
24879
+ renderFormulaXEditorLoadingState(root2);
24880
+ const loadingVisibleMark = markFormulaXPerf2("fx:formula-editor:loading-visible");
24881
+ measureFormulaXPerf2("fx:formula-editor:loading-visible", mountStart, loadingVisibleMark);
24882
+ clearFormulaXPerfMarks2(loadingVisibleMark);
24883
+ const readyPromise = mountKityEditor(root2, {
24884
+ initialLatex,
24885
+ height: options.height ?? "100%",
24886
+ autofocus: options.autofocus ?? true,
24887
+ assets: options.assets,
24888
+ render: {
24889
+ fontsize: options.render?.fontsize ?? 40
24890
+ }
24891
+ }).then((nextHandle) => {
24892
+ if (destroyed) {
24893
+ nextHandle.destroy();
24894
+ throw new Error("FormulaX editor mount cancelled");
24895
+ }
24896
+ const readyMark = markFormulaXPerf2("fx:kity-editor:ready");
24897
+ measureFormulaXPerf2("fx:kity-editor:ready", mountStart, readyMark);
24898
+ clearFormulaXPerfMarks2(readyMark);
24899
+ handle = nextHandle;
24900
+ return nextHandle;
24901
+ }).catch((error) => {
24902
+ console.error("[FormulaX] Failed to load FormulaX editor:", error);
24903
+ if (!destroyed) {
24904
+ root2.innerHTML = `
24905
+ <div class="fx-formula-editor-error">
24906
+ Failed to load FormulaX editor.
24907
+ <pre>${escapeHtml(error instanceof Error ? error.message : String(error))}</pre>
24908
+ </div>
24909
+ `;
24910
+ }
24911
+ throw error;
24912
+ }).finally(() => {
24913
+ clearFormulaXPerfMarks2(mountStart);
24914
+ });
24915
+ const getCurrentLatex = async () => {
24916
+ const readyHandle = handle ?? await readyPromise;
24917
+ const latex = await tryReadLatexFromKityHandle(readyHandle);
24918
+ if (latex !== null) {
24919
+ latestLatex = latex;
24920
+ }
24921
+ return latestLatex;
24922
+ };
24549
24923
  return {
24550
- a: matrix.a,
24551
- b: matrix.b,
24552
- c: matrix.c,
24553
- d: matrix.d,
24554
- e: matrix.e,
24555
- f: matrix.f
24924
+ root: root2,
24925
+ getLatex: getCurrentLatex,
24926
+ async getState() {
24927
+ const latex = await getCurrentLatex();
24928
+ try {
24929
+ return {
24930
+ ...createEmptyState(),
24931
+ doc: parseLatex(latex)
24932
+ };
24933
+ } catch {
24934
+ return createEmptyState();
24935
+ }
24936
+ },
24937
+ async getRenderHtml() {
24938
+ await readyPromise;
24939
+ await waitForKityFormulaSvgLayout(root2);
24940
+ return serializeKityFormulaFromRoot(root2);
24941
+ },
24942
+ destroy() {
24943
+ if (destroyed) return;
24944
+ destroyed = true;
24945
+ void readyPromise.then((readyHandle) => readyHandle.destroy()).catch(() => void 0);
24946
+ root2.innerHTML = "";
24947
+ }
24556
24948
  };
24557
24949
  }
24558
- function readSvgBox(element) {
24559
- if (typeof element.getBBox !== "function") {
24560
- return null;
24561
- }
24950
+ async function tryReadLatexFromKityHandle(handle) {
24562
24951
  try {
24563
- const box = element.getBBox();
24564
- if (!Number.isFinite(box.width) || !Number.isFinite(box.height) || box.width <= 0 || box.height <= 0) {
24565
- return null;
24952
+ let isEmpty = false;
24953
+ handle.ready(function ready() {
24954
+ const result = this.execCommand("content.is.empty");
24955
+ isEmpty = result === true;
24956
+ });
24957
+ if (isEmpty) {
24958
+ return "";
24566
24959
  }
24567
- return {
24568
- x: box.x,
24569
- y: box.y,
24570
- width: box.width,
24571
- height: box.height
24572
- };
24573
24960
  } catch {
24574
- return null;
24575
24961
  }
24576
- }
24577
- function createInlineSvgViewport(contentBox) {
24578
- const edgePadding = Math.max(0.5, Math.min(contentBox.width, contentBox.height) * 6e-3);
24579
- const inset = edgePadding / 2;
24580
- return {
24581
- x: contentBox.x - inset,
24582
- y: contentBox.y - inset,
24583
- width: contentBox.width + edgePadding,
24584
- height: contentBox.height + edgePadding
24585
- };
24586
- }
24587
- function createInlineSvgClone(source, content, viewport) {
24588
- const clone = source.cloneNode(false);
24589
- const ownerDocument = source.ownerDocument;
24590
- copySvgRootAttributes(source, clone);
24591
- clone.setAttribute(
24592
- "viewBox",
24593
- `0 0 ${roundLength(viewport.width)} ${roundLength(viewport.height)}`
24594
- );
24595
- Array.from(source.children).forEach((child) => {
24596
- if (child.tagName.toLowerCase() === "defs") {
24597
- clone.appendChild(child.cloneNode(true));
24598
- }
24599
- });
24600
- const wrapper = ownerDocument.createElementNS("http://www.w3.org/2000/svg", "g");
24601
- wrapper.setAttribute(
24602
- "transform",
24603
- `translate(${roundLength(-viewport.x)} ${roundLength(-viewport.y)})`
24604
- );
24605
- const flattened = ownerDocument.createElementNS("http://www.w3.org/2000/svg", "g");
24606
- flattened.setAttribute(
24607
- "transform",
24608
- `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)})`
24609
- );
24610
- flattened.appendChild(content.root.cloneNode(true));
24611
- wrapper.appendChild(flattened);
24612
- clone.appendChild(wrapper);
24613
- return clone;
24614
- }
24615
- function copySvgRootAttributes(source, target) {
24616
- const excluded = /* @__PURE__ */ new Set([
24617
- "id",
24618
- "width",
24619
- "height",
24620
- "viewBox",
24621
- "class",
24622
- "focusable",
24623
- "aria-hidden",
24624
- "xmlns",
24625
- "xmlns:xlink"
24626
- ]);
24627
- Array.from(source.attributes).forEach((attribute) => {
24628
- if (excluded.has(attribute.name)) return;
24629
- target.setAttribute(attribute.name, attribute.value);
24630
- });
24631
- }
24632
- function sizeSvgForInlineDisplay(clone, source, viewport) {
24633
- const viewBox = clone.viewBox?.baseVal;
24634
- const rect = source.getBoundingClientRect();
24635
- const width2 = viewport?.width || viewBox?.width || rect.width || Number(clone.getAttribute("width")) || 1;
24636
- const height2 = viewport?.height || viewBox?.height || rect.height || Number(clone.getAttribute("height")) || 1;
24637
- const ratio = Math.max(0.1, width2 / Math.max(1, height2));
24638
- const inlineHeightEm = 0.875;
24639
- const inlineWidthEm = Math.min(40, Math.max(0.75, ratio * inlineHeightEm));
24640
- clone.setAttribute("width", roundLength(width2));
24641
- clone.setAttribute("height", roundLength(height2));
24642
- clone.setAttribute(
24643
- "style",
24644
- mergeInlineStyles2(
24645
- clone.getAttribute("style"),
24646
- `width:${roundLength(inlineWidthEm)}em`,
24647
- `height:${inlineHeightEm}em`
24648
- )
24649
- );
24650
- }
24651
- function roundLength(value) {
24652
- return String(Math.round(value * 1e3) / 1e3);
24653
- }
24654
- function uniquifySvgIds(svg2) {
24655
- const idMap = /* @__PURE__ */ new Map();
24656
- const prefix = `fx-${randomIdPrefix()}-`;
24657
- const elementsWithId = svg2.querySelectorAll("[id]");
24658
- elementsWithId.forEach((element) => {
24659
- const id = element.getAttribute("id");
24660
- if (!id) return;
24661
- const nextId = `${prefix}${id}`;
24662
- idMap.set(id, nextId);
24663
- element.setAttribute("id", nextId);
24664
- });
24665
- if (!idMap.size) return;
24666
- svg2.querySelectorAll("*").forEach((element) => {
24667
- Array.from(element.attributes).forEach((attribute) => {
24668
- const nextValue = rewriteSvgReferences(attribute.value, idMap);
24669
- if (nextValue !== attribute.value) {
24670
- element.setAttribute(attribute.name, nextValue);
24962
+ const candidates = [
24963
+ "get.source",
24964
+ "getSource",
24965
+ "getLatex",
24966
+ "get.latex",
24967
+ "get.content",
24968
+ "getContent"
24969
+ ];
24970
+ for (const command of candidates) {
24971
+ try {
24972
+ let value = null;
24973
+ handle.ready(function ready() {
24974
+ value = this.execCommand(command);
24975
+ });
24976
+ if (typeof value === "string" && value.trim()) {
24977
+ return value;
24671
24978
  }
24672
- });
24673
- });
24674
- }
24675
- function randomIdPrefix() {
24676
- return Math.random().toString(36).slice(2, 5).padEnd(3, "0");
24677
- }
24678
- function rewriteSvgReferences(value, idMap) {
24679
- let nextValue = value;
24680
- idMap.forEach((nextId, id) => {
24681
- nextValue = nextValue.replaceAll(`#${id}`, `#${nextId}`).replaceAll(`url(${id})`, `url(${nextId})`).replaceAll(`url(#${id})`, `url(#${nextId})`);
24682
- });
24683
- return nextValue;
24684
- }
24685
- function mergeClassNames(...values) {
24686
- return values.flatMap((value) => value?.split(/\s+/) ?? []).filter(Boolean).filter((value, index, list) => list.indexOf(value) === index).join(" ");
24687
- }
24688
- function mergeInlineStyles2(...values) {
24689
- return values.flatMap((value) => value?.split(";") ?? []).map((value) => value.trim()).filter(Boolean).join("; ");
24979
+ if (value && typeof value === "object" && "latex" in value) {
24980
+ const latex = value.latex;
24981
+ if (typeof latex === "string" && latex.trim()) {
24982
+ return latex;
24983
+ }
24984
+ }
24985
+ } catch {
24986
+ }
24987
+ }
24988
+ return null;
24690
24989
  }
24691
24990
  return __toCommonJS(index_exports);
24692
24991
  })();