@formulaxjs/editor 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,363 +1,5 @@
1
- // src/dom-renderer.ts
2
- var joinPath = (path) => path.join(".");
3
- var renderInteractiveHtml = (doc, activePath) => `
4
- <div class="fx-editor-surface" data-role="surface">
5
- ${renderChildren(doc.body, [], activePath)}
6
- </div>
7
- `;
8
- var renderChildren = (nodes, basePath, activePath) => {
9
- const html = [];
10
- for (let index = 0; index <= nodes.length; index += 1) {
11
- const path = joinPath([...basePath, index]);
12
- const isActive = path === joinPath(activePath);
13
- html.push(
14
- `<button class="fx-slot${isActive ? " is-active" : ""}" data-path="${path}" type="button" title="${path}"></button>`
15
- );
16
- if (index < nodes.length) {
17
- html.push(renderNode(nodes[index], [...basePath, index], activePath));
18
- }
19
- }
20
- return html.join("");
21
- };
22
- var renderNode = (node, path, activePath) => {
23
- const pathValue = joinPath(path);
24
- const isActive = (p) => joinPath(p) === joinPath(activePath);
25
- switch (node.type) {
26
- case "text":
27
- return `<span class="fx-node fx-text" data-node-path="${pathValue}">${node.value}</span>`;
28
- case "group":
29
- return `<span class="fx-node fx-group" data-node-path="${pathValue}">${renderChildren(node.body, [...path, 0], activePath)}</span>`;
30
- case "frac":
31
- return `<span class="fx-node fx-frac" data-node-path="${pathValue}">
32
- <span class="fx-frac-num${isActive([...path, 0]) ? " is-active" : ""}" data-path="${joinPath([...path, 0])}">${renderChildren(node.numerator, [...path, 0], activePath)}</span>
33
- <span class="fx-frac-line"></span>
34
- <span class="fx-frac-den${isActive([...path, 1]) ? " is-active" : ""}" data-path="${joinPath([...path, 1])}">${renderChildren(node.denominator, [...path, 1], activePath)}</span>
35
- </span>`;
36
- case "supsub":
37
- return `<span class="fx-node fx-supsub" data-node-path="${pathValue}">
38
- <span class="fx-supsub-base">${renderChildren(node.base, [...path, 0], activePath)}</span>
39
- <span class="fx-supsub-stack">
40
- <span class="fx-sup${isActive([...path, 1]) ? " is-active" : ""}" data-path="${joinPath([...path, 1])}">${renderChildren(node.sup ?? [], [...path, 1], activePath)}</span>
41
- <span class="fx-sub${isActive([...path, 2]) ? " is-active" : ""}" data-path="${joinPath([...path, 2])}">${renderChildren(node.sub ?? [], [...path, 2], activePath)}</span>
42
- </span>
43
- </span>`;
44
- case "sqrt":
45
- return `<span class="fx-node fx-sqrt" data-node-path="${pathValue}">
46
- <span class="fx-sqrt-symbol">\u221A</span>
47
- <span class="fx-sqrt-body${isActive([...path, 0]) ? " is-active" : ""}" data-path="${joinPath([...path, 0])}">${renderChildren(node.value, [...path, 0], activePath)}</span>
48
- </span>`;
49
- case "fenced":
50
- return `<span class="fx-node fx-fenced" data-node-path="${pathValue}">
51
- <span class="fx-fence">${node.left}</span>
52
- <span class="fx-fenced-body${isActive([...path, 0]) ? " is-active" : ""}" data-path="${joinPath([...path, 0])}">${renderChildren(node.body, [...path, 0], activePath)}</span>
53
- <span class="fx-fence">${node.right}</span>
54
- </span>`;
55
- case "doc":
56
- return renderChildren(node.body, [0], activePath);
57
- }
58
- throw new Error(`Unsupported node type: ${String(node.type)}`);
59
- };
60
-
61
- // src/editor.ts
62
- import {
63
- applyCommand,
64
- backspace,
65
- createEmptyState,
66
- insertFenced,
67
- insertFraction,
68
- insertSqrt,
69
- insertSubscript,
70
- insertSuperscript,
71
- insertText
72
- } from "@formulaxjs/core";
73
-
74
- // src/styles.ts
75
- var editorStyles = `
76
- @keyframes fx-blink {
77
- 0%, 50% { opacity: 1; }
78
- 51%, 100% { opacity: 0; }
79
- }
80
- .fx-editor {
81
- border: 1px solid #d8d4c7;
82
- border-radius: 2px;
83
- background: #fffefb;
84
- box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.7);
85
- padding: 24px 28px;
86
- font-family: Cambria, 'Times New Roman', serif;
87
- font-size: 25px;
88
- line-height: 1.7;
89
- min-height: 120px;
90
- position: relative;
91
- }
92
- .fx-editor:focus-within {
93
- border-color: #7bbb59;
94
- box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.7), 0 0 0 3px rgba(123, 187, 89, 0.18);
95
- }
96
- .fx-editor-surface {
97
- display: flex;
98
- flex-wrap: wrap;
99
- align-items: baseline;
100
- gap: 3px;
101
- cursor: text;
102
- }
103
- .fx-node {
104
- position: relative;
105
- display: inline-flex;
106
- align-items: center;
107
- padding: 2px 3px;
108
- border-radius: 2px;
109
- transition: background 0.12s ease;
110
- }
111
- .fx-node:hover {
112
- background: rgba(122, 186, 89, 0.12);
113
- }
114
- .fx-text {
115
- color: #2b2925;
116
- }
117
- .fx-group {
118
- background: rgba(243, 241, 230, 0.82);
119
- border: 1px dashed #c8c0a8;
120
- }
121
- .fx-frac {
122
- display: inline-flex;
123
- flex-direction: column;
124
- align-items: center;
125
- vertical-align: middle;
126
- padding: 0 5px;
127
- }
128
- .fx-frac-num, .fx-frac-den {
129
- display: flex;
130
- flex-wrap: wrap;
131
- align-items: center;
132
- justify-content: center;
133
- padding: 3px 8px;
134
- min-width: 24px;
135
- min-height: 28px;
136
- border-radius: 2px;
137
- transition: all 0.15s ease;
138
- }
139
- .fx-frac-num {
140
- border-bottom: 2px solid #2e2c29;
141
- padding-bottom: 6px;
142
- }
143
- .fx-frac-den {
144
- border-top: 2px solid #2e2c29;
145
- padding-top: 6px;
146
- }
147
- .fx-frac-num:hover, .fx-frac-den:hover {
148
- background: rgba(122, 186, 89, 0.1);
149
- }
150
- .fx-frac-num.is-active, .fx-frac-den.is-active {
151
- background: rgba(122, 186, 89, 0.16);
152
- box-shadow: inset 0 0 0 1px rgba(83, 184, 86, 0.5);
153
- }
154
- .fx-supsub {
155
- display: inline-flex;
156
- align-items: baseline;
157
- gap: 0;
158
- }
159
- .fx-supsub-base {
160
- display: inline-flex;
161
- align-items: center;
162
- padding: 0 2px;
163
- }
164
- .fx-supsub-stack {
165
- display: inline-flex;
166
- flex-direction: column;
167
- align-items: flex-start;
168
- font-size: 0.65em;
169
- margin-left: 2px;
170
- }
171
- .fx-sup, .fx-sub {
172
- display: flex;
173
- align-items: center;
174
- min-width: 16px;
175
- min-height: 20px;
176
- padding: 0 4px;
177
- border-radius: 2px;
178
- transition: all 0.15s ease;
179
- }
180
- .fx-sup {
181
- vertical-align: super;
182
- }
183
- .fx-sub {
184
- vertical-align: sub;
185
- }
186
- .fx-sup:hover, .fx-sub:hover {
187
- background: rgba(122, 186, 89, 0.1);
188
- }
189
- .fx-sup.is-active, .fx-sub.is-active {
190
- background: rgba(122, 186, 89, 0.16);
191
- box-shadow: inset 0 0 0 1px rgba(83, 184, 86, 0.5);
192
- }
193
- .fx-sqrt {
194
- display: inline-flex;
195
- align-items: baseline;
196
- }
197
- .fx-sqrt-symbol {
198
- font-size: 1.1em;
199
- color: #2e2c29;
200
- margin-right: 2px;
201
- }
202
- .fx-sqrt-body {
203
- display: inline-flex;
204
- align-items: center;
205
- border-top: 2px solid #2e2c29;
206
- padding: 4px 6px 0;
207
- margin-left: 2px;
208
- }
209
- .fx-sqrt-body:hover {
210
- background: rgba(122, 186, 89, 0.1);
211
- }
212
- .fx-sqrt-body.is-active {
213
- background: rgba(122, 186, 89, 0.16);
214
- }
215
- .fx-fenced {
216
- display: inline-flex;
217
- align-items: center;
218
- background: rgba(243, 241, 230, 0.78);
219
- border-radius: 3px;
220
- padding: 0 4px;
221
- }
222
- .fx-fence {
223
- color: #59554d;
224
- font-size: 1.2em;
225
- padding: 0 2px;
226
- }
227
- .fx-fenced-body {
228
- display: inline-flex;
229
- align-items: center;
230
- padding: 0 6px;
231
- }
232
- .fx-fenced-body:hover {
233
- background: rgba(122, 186, 89, 0.1);
234
- border-radius: 2px;
235
- }
236
- .fx-fenced-body.is-active {
237
- background: rgba(122, 186, 89, 0.16);
238
- border-radius: 2px;
239
- }
240
- .fx-slot {
241
- width: 3px;
242
- height: 1.2em;
243
- border: none;
244
- background: #53b856;
245
- padding: 0;
246
- margin: 0 1px;
247
- cursor: text;
248
- border-radius: 1px;
249
- vertical-align: middle;
250
- }
251
- .fx-slot.is-active {
252
- animation: fx-blink 1s infinite;
253
- }
254
- .fx-slot:hover {
255
- background: #77c75b;
256
- }
257
- `;
258
-
259
- // src/editor.ts
260
- var FormulaEditor = class {
261
- state;
262
- root;
263
- onChange;
264
- locale;
265
- constructor(options) {
266
- this.root = options.root;
267
- this.state = options.initialState ?? createEmptyState();
268
- this.onChange = options.onChange;
269
- this.locale = options.locale ?? "en";
270
- this.root.classList.add("fx-editor");
271
- this.root.tabIndex = 0;
272
- this.ensureStyles();
273
- this.bindEvents();
274
- this.render();
275
- }
276
- getState() {
277
- return structuredClone(this.state);
278
- }
279
- getLocale() {
280
- return this.locale;
281
- }
282
- setState(state) {
283
- this.state = structuredClone(state);
284
- this.render();
285
- }
286
- dispatch(command) {
287
- this.state = applyCommand(this.state, command);
288
- this.render();
289
- this.onChange?.(this.getState());
290
- }
291
- ensureStyles() {
292
- if (document.getElementById("fx-editor-styles")) return;
293
- const style = document.createElement("style");
294
- style.id = "fx-editor-styles";
295
- style.textContent = editorStyles;
296
- document.head.appendChild(style);
297
- }
298
- bindEvents() {
299
- this.root.addEventListener("click", (event) => {
300
- const target = event.target;
301
- const pathValue = target.dataset.path;
302
- if (pathValue === void 0) return;
303
- const path = pathValue === "" ? [] : pathValue.split(".").map(Number);
304
- this.moveSelection(path);
305
- });
306
- this.root.addEventListener("keydown", (event) => {
307
- if (event.key === "Backspace") {
308
- event.preventDefault();
309
- this.dispatch(backspace());
310
- return;
311
- }
312
- if (event.key === "/") {
313
- event.preventDefault();
314
- this.dispatch(insertFraction());
315
- return;
316
- }
317
- if (event.key === "^") {
318
- event.preventDefault();
319
- this.dispatch(insertSuperscript());
320
- return;
321
- }
322
- if (event.key === "_") {
323
- event.preventDefault();
324
- this.dispatch(insertSubscript());
325
- return;
326
- }
327
- if (event.key === "r" && event.ctrlKey) {
328
- event.preventDefault();
329
- this.dispatch(insertSqrt());
330
- return;
331
- }
332
- if (event.key === "(") {
333
- event.preventDefault();
334
- this.dispatch(insertFenced("(", ")"));
335
- return;
336
- }
337
- if (event.key.length === 1 && !event.ctrlKey && !event.metaKey) {
338
- event.preventDefault();
339
- this.dispatch(insertText(event.key));
340
- }
341
- });
342
- }
343
- moveSelection(path) {
344
- this.state = {
345
- ...this.state,
346
- selection: {
347
- anchor: [...path],
348
- focus: [...path]
349
- }
350
- };
351
- this.render();
352
- this.onChange?.(this.getState());
353
- }
354
- render() {
355
- this.root.innerHTML = renderInteractiveHtml(this.state.doc, this.state.selection.focus);
356
- }
357
- };
358
-
359
1
  // src/formula-modal.ts
360
- import { createEmptyState as createEmptyState2, parseLatex } from "@formulaxjs/core";
2
+ import { createEmptyState, parseLatex } from "@formulaxjs/core";
361
3
  import { mountKityEditor } from "@formulaxjs/kity-runtime";
362
4
 
363
5
  // src/formula-node.ts
@@ -687,7 +329,7 @@ function ensureFormulaXModalStyles(doc = document) {
687
329
  style.textContent = formulaXModalStyles;
688
330
  doc.head.appendChild(style);
689
331
  }
690
- function mountFormulaXKityEditor(root, options = {}) {
332
+ function mountFormulaXEditor(root, options = {}) {
691
333
  let destroyed = false;
692
334
  let latestLatex = options.initialLatex ?? "";
693
335
  let handle = null;
@@ -740,11 +382,11 @@ function mountFormulaXKityEditor(root, options = {}) {
740
382
  const latex = await getCurrentLatex();
741
383
  try {
742
384
  return {
743
- ...createEmptyState2(),
385
+ ...createEmptyState(),
744
386
  doc: parseLatex(latex)
745
387
  };
746
388
  } catch {
747
- return createEmptyState2();
389
+ return createEmptyState();
748
390
  }
749
391
  },
750
392
  async getRenderHtml() {
@@ -1097,102 +739,32 @@ function mergeInlineStyles2(...values) {
1097
739
  return values.flatMap((value) => value?.split(";") ?? []).map((value) => value.trim()).filter(Boolean).join("; ");
1098
740
  }
1099
741
 
1100
- // src/i18n.ts
1101
- var translations = {
1102
- en: {
1103
- equation: "Equation",
1104
- structures: "Structures",
1105
- symbols: "Symbols",
1106
- matrices: "Matrices",
1107
- templates: "Templates",
1108
- insert: "Insert",
1109
- greek: "Greek",
1110
- operators: "Operators",
1111
- relations: "Relations",
1112
- fraction: "Fraction",
1113
- superscript: "Superscript",
1114
- subscript: "Subscript",
1115
- squareRoot: "Square Root",
1116
- parentheses: "Parentheses",
1117
- plusMinus: "Plus Minus",
1118
- multiply: "Multiply",
1119
- divide: "Divide",
1120
- dot: "Dot",
1121
- union: "Union",
1122
- intersect: "Intersection",
1123
- lessOrEqual: "Less or Equal",
1124
- greaterOrEqual: "Greater or Equal",
1125
- notEqual: "Not Equal",
1126
- approximate: "Approximate",
1127
- infinity: "Infinity",
1128
- arrow: "Arrow",
1129
- limit: "Limit",
1130
- sine: "Sine",
1131
- logarithm: "Logarithm",
1132
- matrix: "Matrix",
1133
- summation: "Summation",
1134
- integral: "Integral",
1135
- placeholder: "WPS-inspired ribbon layout. Some tiles are placeholders for future SDK features."
1136
- },
1137
- zh: {
1138
- equation: "\u516C\u5F0F",
1139
- structures: "\u7ED3\u6784",
1140
- symbols: "\u7B26\u53F7",
1141
- matrices: "\u77E9\u9635",
1142
- templates: "\u6A21\u677F",
1143
- insert: "\u63D2\u5165",
1144
- greek: "\u5E0C\u814A\u5B57\u6BCD",
1145
- operators: "\u8FD0\u7B97\u7B26",
1146
- relations: "\u5173\u7CFB",
1147
- fraction: "\u5206\u6570",
1148
- superscript: "\u4E0A\u6807",
1149
- subscript: "\u4E0B\u6807",
1150
- squareRoot: "\u5E73\u65B9\u6839",
1151
- parentheses: "\u62EC\u53F7",
1152
- plusMinus: "\u52A0\u51CF",
1153
- multiply: "\u4E58",
1154
- divide: "\u9664",
1155
- dot: "\u70B9\u4E58",
1156
- union: "\u5E76\u96C6",
1157
- intersect: "\u4EA4\u96C6",
1158
- lessOrEqual: "\u5C0F\u4E8E\u7B49\u4E8E",
1159
- greaterOrEqual: "\u5927\u4E8E\u7B49\u4E8E",
1160
- notEqual: "\u4E0D\u7B49\u4E8E",
1161
- approximate: "\u7EA6\u7B49\u4E8E",
1162
- infinity: "\u65E0\u7A77",
1163
- arrow: "\u7BAD\u5934",
1164
- limit: "\u6781\u9650",
1165
- sine: "\u6B63\u5F26",
1166
- logarithm: "\u5BF9\u6570",
1167
- matrix: "\u77E9\u9635",
1168
- summation: "\u6C42\u548C",
1169
- integral: "\u79EF\u5206",
1170
- placeholder: "WPS \u98CE\u683C\u7684\u5DE5\u5177\u680F\u5E03\u5C40\u3002\u90E8\u5206\u6309\u94AE\u4ECD\u662F\u672A\u6765 SDK \u529F\u80FD\u7684\u5360\u4F4D\u9879\u3002"
1171
- }
1172
- };
1173
- function t(locale, key) {
1174
- return translations[locale][key] ?? translations.en[key];
1175
- }
742
+ // src/index.ts
743
+ import {
744
+ FormulaXEditor,
745
+ createKityEditor,
746
+ ensureKityRuntime,
747
+ mountKityEditor as mountKityEditor2
748
+ } from "@formulaxjs/kity-runtime";
1176
749
  export {
1177
750
  DEFAULT_FORMULA_ATTRIBUTE,
1178
751
  DEFAULT_FORMULA_CLASS,
1179
752
  FORMULA_FLAG_ATTRIBUTE,
1180
- FormulaEditor,
753
+ FormulaXEditor,
1181
754
  createFormulaElement,
1182
755
  createFormulaMarkup,
1183
- editorStyles,
756
+ createKityEditor,
1184
757
  ensureFormulaXModalStyles,
758
+ ensureKityRuntime,
1185
759
  escapeAttribute,
1186
760
  escapeHtml,
1187
761
  findFormulaElement,
1188
762
  formulaXModalStyles,
1189
763
  getFormulaLatexFromElement,
1190
764
  isFormulaElement,
1191
- mountFormulaXKityEditor,
1192
- renderInteractiveHtml,
765
+ mountFormulaXEditor,
766
+ mountKityEditor2 as mountKityEditor,
1193
767
  replaceFormulaElement,
1194
- serializeSvgForInsertion,
1195
- t,
1196
- translations
768
+ serializeSvgForInsertion
1197
769
  };
1198
770
  //# sourceMappingURL=index.js.map