logisheets-formula-editor 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +192 -0
- package/dist/FormulaEditor.d.ts +17 -0
- package/dist/FormulaEditor.d.ts.map +1 -0
- package/dist/builtin-functions.json.d.ts +1510 -0
- package/dist/core.d.ts +18 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +13946 -0
- package/dist/editor.d.ts +57 -0
- package/dist/editor.d.ts.map +1 -0
- package/dist/engine.d.ts +34 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +23 -0
- package/dist/functions-Cxg5fTo6.js +1510 -0
- package/dist/functions.d.ts +3 -0
- package/dist/functions.d.ts.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +94 -0
- package/dist/inline.d.ts +53 -0
- package/dist/inline.d.ts.map +1 -0
- package/dist/inline.js +164 -0
- package/dist/types.d.ts +159 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils.d.ts +43 -0
- package/dist/utils.d.ts.map +1 -0
- package/package.json +62 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"functions.d.ts","sourceRoot":"","sources":["../src/lib/functions.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,SAAS,CAAA;AAG5C,eAAO,MAAM,uBAAuB,EAAE,eAAe,EACxB,CAAA"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* logisheets-formula-editor
|
|
3
|
+
*
|
|
4
|
+
* A spreadsheet formula editor with token-based syntax highlighting (via a
|
|
5
|
+
* host callback), function autocomplete, signature help, and cell-reference
|
|
6
|
+
* coloring. Built on CodeMirror 6.
|
|
7
|
+
*
|
|
8
|
+
* This root entry includes the React `<FormulaEditor>` component. For a
|
|
9
|
+
* framework-agnostic (vanilla / Vue / Svelte / Angular) build with no React
|
|
10
|
+
* dependency, import from `logisheets-formula-editor/core` instead.
|
|
11
|
+
*/
|
|
12
|
+
export { FormulaEditor } from './FormulaEditor';
|
|
13
|
+
export type { FormulaEditorRef } from './FormulaEditor';
|
|
14
|
+
export * from './core';
|
|
15
|
+
export * from './engine';
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/lib/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAA;AAC7C,YAAY,EAAC,gBAAgB,EAAC,MAAM,iBAAiB,CAAA;AAGrD,cAAc,QAAQ,CAAA;AAGtB,cAAc,UAAU,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { jsx as s } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef as m, useRef as a, useEffect as i, useImperativeHandle as f } from "react";
|
|
3
|
+
import { createFormulaEditor as g } from "./core.js";
|
|
4
|
+
import { CELL_REF_COLORS as b, EOF as x, convertToDisplayUnits as E, fuzzyMatch as V, getCellRefColor as v, isFormula as N, isLocalCellRef as S, measureText as U, simpleUuid as D } from "./core.js";
|
|
5
|
+
import { b as L } from "./functions-Cxg5fTo6.js";
|
|
6
|
+
import { createEngineFormulaSource as P } from "./engine.js";
|
|
7
|
+
const C = m(
|
|
8
|
+
(n, o) => {
|
|
9
|
+
const r = a(null), t = a(null);
|
|
10
|
+
return i(() => {
|
|
11
|
+
if (!r.current) return;
|
|
12
|
+
const e = g(r.current, {
|
|
13
|
+
value: n.value,
|
|
14
|
+
defaultValue: n.defaultValue,
|
|
15
|
+
initialCursorPosition: n.initialCursorPosition,
|
|
16
|
+
onChange: n.onChange,
|
|
17
|
+
onBlur: n.onBlur,
|
|
18
|
+
onSubmit: n.onSubmit,
|
|
19
|
+
onCancel: n.onCancel,
|
|
20
|
+
getDisplayUnits: n.getDisplayUnits,
|
|
21
|
+
formulaFunctions: n.formulaFunctions,
|
|
22
|
+
sheetName: n.sheetName,
|
|
23
|
+
config: n.config,
|
|
24
|
+
className: n.className,
|
|
25
|
+
style: n.style
|
|
26
|
+
});
|
|
27
|
+
return t.current = e, () => {
|
|
28
|
+
e.destroy(), t.current = null;
|
|
29
|
+
};
|
|
30
|
+
}, []), i(() => {
|
|
31
|
+
var e;
|
|
32
|
+
(e = t.current) == null || e.updateOptions({
|
|
33
|
+
value: n.value,
|
|
34
|
+
onChange: n.onChange,
|
|
35
|
+
onBlur: n.onBlur,
|
|
36
|
+
onSubmit: n.onSubmit,
|
|
37
|
+
onCancel: n.onCancel,
|
|
38
|
+
getDisplayUnits: n.getDisplayUnits,
|
|
39
|
+
formulaFunctions: n.formulaFunctions,
|
|
40
|
+
sheetName: n.sheetName,
|
|
41
|
+
config: n.config
|
|
42
|
+
});
|
|
43
|
+
}), f(o, () => ({
|
|
44
|
+
focus: () => {
|
|
45
|
+
var e;
|
|
46
|
+
return (e = t.current) == null ? void 0 : e.focus();
|
|
47
|
+
},
|
|
48
|
+
blur: () => {
|
|
49
|
+
var e;
|
|
50
|
+
return (e = t.current) == null ? void 0 : e.blur();
|
|
51
|
+
},
|
|
52
|
+
getValue: () => {
|
|
53
|
+
var e;
|
|
54
|
+
return ((e = t.current) == null ? void 0 : e.getValue()) ?? "";
|
|
55
|
+
},
|
|
56
|
+
setValue: (e) => {
|
|
57
|
+
var u;
|
|
58
|
+
return (u = t.current) == null ? void 0 : u.setValue(e);
|
|
59
|
+
},
|
|
60
|
+
insertText: (e) => {
|
|
61
|
+
var u;
|
|
62
|
+
return (u = t.current) == null ? void 0 : u.insertText(e);
|
|
63
|
+
},
|
|
64
|
+
replaceRange: (e, u, c) => {
|
|
65
|
+
var l;
|
|
66
|
+
return (l = t.current) == null ? void 0 : l.replaceRange(e, u, c);
|
|
67
|
+
},
|
|
68
|
+
getCursorPosition: () => {
|
|
69
|
+
var e;
|
|
70
|
+
return ((e = t.current) == null ? void 0 : e.getCursorPosition()) ?? 0;
|
|
71
|
+
},
|
|
72
|
+
getView: () => {
|
|
73
|
+
var e;
|
|
74
|
+
return ((e = t.current) == null ? void 0 : e.getView()) ?? null;
|
|
75
|
+
}
|
|
76
|
+
})), /* @__PURE__ */ s("div", { ref: r });
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
C.displayName = "FormulaEditor";
|
|
80
|
+
export {
|
|
81
|
+
b as CELL_REF_COLORS,
|
|
82
|
+
x as EOF,
|
|
83
|
+
C as FormulaEditor,
|
|
84
|
+
L as builtinFormulaFunctions,
|
|
85
|
+
E as convertToDisplayUnits,
|
|
86
|
+
P as createEngineFormulaSource,
|
|
87
|
+
g as createFormulaEditor,
|
|
88
|
+
V as fuzzyMatch,
|
|
89
|
+
v as getCellRefColor,
|
|
90
|
+
N as isFormula,
|
|
91
|
+
S as isLocalCellRef,
|
|
92
|
+
U as measureText,
|
|
93
|
+
D as simpleUuid
|
|
94
|
+
};
|
package/dist/inline.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { EngineFormulaServices } from './engine';
|
|
2
|
+
import { FormulaEditorConfig, FormulaFunction } from './types';
|
|
3
|
+
import { Grid, SelectedData, Session } from 'logisheets-engine';
|
|
4
|
+
export interface InlineCellEditorOptions {
|
|
5
|
+
/** Element the editor + highlight overlays mount into (the view's canvas
|
|
6
|
+
* container; also the positioning origin and refocus target). */
|
|
7
|
+
container: HTMLElement;
|
|
8
|
+
/** Emits startEdit / selectionChange / invalidFormula for this view
|
|
9
|
+
* (an engine `Session`, or the `Engine` itself for the main view). */
|
|
10
|
+
eventSource: Pick<Session, 'on' | 'off'>;
|
|
11
|
+
/** Engine data service — `getWorkbook()` + `checkFormula()`. */
|
|
12
|
+
dataService: EngineFormulaServices;
|
|
13
|
+
/** This view's sheet index. */
|
|
14
|
+
sheetIdx: number;
|
|
15
|
+
/** Current sheet name (read fresh; used for local cell-ref coloring). */
|
|
16
|
+
getSheetName: () => string;
|
|
17
|
+
/** Commit a cell value (the host's input/ops layer). The return value is
|
|
18
|
+
* awaited but otherwise ignored, so `void`/any Promise is fine. */
|
|
19
|
+
inputCell: (sheetIdx: number, row: number, col: number, text: string) => unknown;
|
|
20
|
+
/** Move the view's selection (e.g. after committing). */
|
|
21
|
+
setSelection: (data: SelectedData) => void;
|
|
22
|
+
/** Initial grid; keep updated via {@link InlineCellEditorHandle.setGrid}. */
|
|
23
|
+
grid?: Grid | null;
|
|
24
|
+
/** Header panel offsets (engine config leftTopWidth/Height). Default 32/24. */
|
|
25
|
+
origin?: {
|
|
26
|
+
x: number;
|
|
27
|
+
y: number;
|
|
28
|
+
};
|
|
29
|
+
/** Permission gate before opening. Default: always editable. */
|
|
30
|
+
canEdit?: (sheetIdx: number, row: number, col: number, grid: Grid) => boolean;
|
|
31
|
+
/** Autocomplete / signature functions. Default: bundled built-ins. */
|
|
32
|
+
formulaFunctions?: FormulaFunction[];
|
|
33
|
+
/** Maps a reference index to a CSS color. Default: built-in palette. */
|
|
34
|
+
getHighlightColor?: (index: number) => string;
|
|
35
|
+
/** Base editor config (merged over the in-cell defaults). */
|
|
36
|
+
editorConfig?: FormulaEditorConfig;
|
|
37
|
+
/** Called when a committed formula fails validation. */
|
|
38
|
+
onInvalidFormula?: () => void;
|
|
39
|
+
/** Reports whether an editor is open (so the canvas can avoid stealing focus). */
|
|
40
|
+
onEditingChange?: (editing: boolean) => void;
|
|
41
|
+
/** Bumped after commits / selection moves so dependents re-read content. */
|
|
42
|
+
onContentChanged?: () => void;
|
|
43
|
+
}
|
|
44
|
+
export interface InlineCellEditorHandle {
|
|
45
|
+
/** Call on every grid change/render: repositions the editor and repaints
|
|
46
|
+
* highlights (parks the editor off-screen if its cell scrolled away). */
|
|
47
|
+
setGrid(grid: Grid | null): void;
|
|
48
|
+
isEditing(): boolean;
|
|
49
|
+
isEditingFormula(): boolean;
|
|
50
|
+
destroy(): void;
|
|
51
|
+
}
|
|
52
|
+
export declare function createInlineCellEditor(options: InlineCellEditorOptions): InlineCellEditorHandle;
|
|
53
|
+
//# sourceMappingURL=inline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inline.d.ts","sourceRoot":"","sources":["../src/lib/inline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,EAA4B,KAAK,qBAAqB,EAAC,MAAM,UAAU,CAAA;AAG9E,OAAO,EAAkB,KAAK,mBAAmB,EAAE,KAAK,eAAe,EAAC,MAAM,SAAS,CAAA;AAQvF,OAAO,KAAK,EACR,IAAI,EACJ,YAAY,EACZ,OAAO,EAEV,MAAM,mBAAmB,CAAA;AAE1B,MAAM,WAAW,uBAAuB;IACpC;sEACkE;IAClE,SAAS,EAAE,WAAW,CAAA;IACtB;2EACuE;IACvE,WAAW,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,GAAG,KAAK,CAAC,CAAA;IACxC,gEAAgE;IAChE,WAAW,EAAE,qBAAqB,CAAA;IAClC,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAA;IAChB,yEAAyE;IACzE,YAAY,EAAE,MAAM,MAAM,CAAA;IAC1B;wEACoE;IACpE,SAAS,EAAE,CACP,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,KACX,OAAO,CAAA;IACZ,yDAAyD;IACzD,YAAY,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAA;IAC1C,6EAA6E;IAC7E,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAA;IAClB,+EAA+E;IAC/E,MAAM,CAAC,EAAE;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAC,CAAA;IAC/B,gEAAgE;IAChE,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,KAAK,OAAO,CAAA;IAC7E,sEAAsE;IACtE,gBAAgB,CAAC,EAAE,eAAe,EAAE,CAAA;IACpC,wEAAwE;IACxE,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;IAC7C,6DAA6D;IAC7D,YAAY,CAAC,EAAE,mBAAmB,CAAA;IAClC,wDAAwD;IACxD,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAA;IAC7B,kFAAkF;IAClF,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;IAC5C,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAA;CAChC;AAED,MAAM,WAAW,sBAAsB;IACnC;8EAC0E;IAC1E,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IAChC,SAAS,IAAI,OAAO,CAAA;IACpB,gBAAgB,IAAI,OAAO,CAAA;IAC3B,OAAO,IAAI,IAAI,CAAA;CAClB;AAWD,wBAAgB,sBAAsB,CAClC,OAAO,EAAE,uBAAuB,GACjC,sBAAsB,CAoRxB"}
|
package/dist/inline.js
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { getCellRefColor as Q, createFormulaEditor as Z, measureText as tt } from "./core.js";
|
|
2
|
+
import { createEngineFormulaSource as et } from "./engine.js";
|
|
3
|
+
import { b as it } from "./functions-Cxg5fTo6.js";
|
|
4
|
+
import { getReferenceHighlightRects as ot, getReferenceString as nt, isCellInGridWindow as rt, getCellRect as B, buildSelectedDataFromCell as lt } from "logisheets-engine";
|
|
5
|
+
const st = '13px Consolas, Monaco, "Courier New", monospace';
|
|
6
|
+
function dt(P) {
|
|
7
|
+
const {
|
|
8
|
+
container: w,
|
|
9
|
+
eventSource: a,
|
|
10
|
+
dataService: G,
|
|
11
|
+
sheetIdx: $,
|
|
12
|
+
getSheetName: z,
|
|
13
|
+
inputCell: q,
|
|
14
|
+
setSelection: N,
|
|
15
|
+
origin: u = { x: 32, y: 24 },
|
|
16
|
+
canEdit: A = () => !0,
|
|
17
|
+
formulaFunctions: I = it,
|
|
18
|
+
getHighlightColor: O = Q,
|
|
19
|
+
editorConfig: V,
|
|
20
|
+
onInvalidFormula: f,
|
|
21
|
+
onEditingChange: d,
|
|
22
|
+
onContentChanged: g
|
|
23
|
+
} = P;
|
|
24
|
+
let l = P.grid ?? null, c = !1, e = null, s = null, E = [], r = null, m = !1, p = "", C = "", n = null;
|
|
25
|
+
const S = [], R = et(G, {
|
|
26
|
+
formulaFunctions: I,
|
|
27
|
+
onCellRefs: (t) => {
|
|
28
|
+
E = t, k();
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
function T() {
|
|
32
|
+
return c && p.trim().startsWith("=");
|
|
33
|
+
}
|
|
34
|
+
function W() {
|
|
35
|
+
const t = w.querySelector("canvas");
|
|
36
|
+
t == null || t.focus({ preventScroll: !0 });
|
|
37
|
+
}
|
|
38
|
+
function H() {
|
|
39
|
+
for (const t of S) t.remove();
|
|
40
|
+
S.length = 0;
|
|
41
|
+
}
|
|
42
|
+
function k() {
|
|
43
|
+
if (H(), !l) return;
|
|
44
|
+
const t = ot(E, l, z(), {
|
|
45
|
+
originX: u.x,
|
|
46
|
+
originY: u.y
|
|
47
|
+
});
|
|
48
|
+
for (const i of t) {
|
|
49
|
+
const o = document.createElement("div");
|
|
50
|
+
o.style.cssText = `position:absolute;pointer-events:none;opacity:0.3;z-index:0;left:${i.x}px;top:${i.y}px;width:${i.width}px;height:${i.height}px;background-color:${O(i.colorIndex)};`, w.appendChild(o), S.push(o);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function D() {
|
|
54
|
+
!n || !e || (n.style.left = `${e.position.x}px`, n.style.top = `${e.position.y}px`, n.style.height = `${e.position.height}px`);
|
|
55
|
+
}
|
|
56
|
+
function M(t) {
|
|
57
|
+
if (!n || !e) return;
|
|
58
|
+
const i = tt(t, st) + 20;
|
|
59
|
+
n.style.width = `${Math.max(e.position.width, i)}px`;
|
|
60
|
+
}
|
|
61
|
+
function _(t) {
|
|
62
|
+
p = t, M(t), m || (r = null), m = !1;
|
|
63
|
+
}
|
|
64
|
+
function j(t) {
|
|
65
|
+
if (!s) return;
|
|
66
|
+
const i = s.getCursorPosition();
|
|
67
|
+
m = !0, r ? s.replaceRange(
|
|
68
|
+
r.startPos,
|
|
69
|
+
r.startPos + r.text.length,
|
|
70
|
+
t
|
|
71
|
+
) : s.insertText(t), r = { text: t, startPos: (r == null ? void 0 : r.startPos) ?? i };
|
|
72
|
+
}
|
|
73
|
+
function J() {
|
|
74
|
+
s == null || s.destroy(), s = null, n == null || n.remove(), n = null;
|
|
75
|
+
}
|
|
76
|
+
function y() {
|
|
77
|
+
c = !1, e = null, E = [], r = null, m = !1, p = "", C = "", J(), H(), d == null || d(!1);
|
|
78
|
+
}
|
|
79
|
+
function K(t, i, o, h = "end") {
|
|
80
|
+
if (!l || !A($, t, i, l)) return;
|
|
81
|
+
c && y();
|
|
82
|
+
const b = B(l, t, i, {
|
|
83
|
+
originX: u.x,
|
|
84
|
+
originY: u.y,
|
|
85
|
+
defaultWidth: 100,
|
|
86
|
+
defaultHeight: 25
|
|
87
|
+
});
|
|
88
|
+
p = o, e = { sheetName: z(), row: t, col: i, position: b }, c = !0, d == null || d(!0), n = document.createElement("div"), n.style.cssText = "position:absolute;display:flex;align-items:center;box-sizing:border-box;z-index:1000;background:#fff;overflow:hidden;border:1px solid #4a90d9;box-shadow:0 1px 4px rgba(0,0,0,0.18);", w.appendChild(n);
|
|
89
|
+
const x = document.createElement("div");
|
|
90
|
+
x.style.width = "100%", x.style.boxSizing = "border-box", n.appendChild(x), D(), M(o), s = Z(x, {
|
|
91
|
+
getDisplayUnits: R.getDisplayUnits,
|
|
92
|
+
formulaFunctions: R.formulaFunctions,
|
|
93
|
+
sheetName: e.sheetName,
|
|
94
|
+
defaultValue: o,
|
|
95
|
+
initialCursorPosition: h,
|
|
96
|
+
config: {
|
|
97
|
+
fontSize: 12,
|
|
98
|
+
lineHeight: 1.2,
|
|
99
|
+
autoFocus: !0,
|
|
100
|
+
placeholder: "",
|
|
101
|
+
showBorder: !1,
|
|
102
|
+
...V
|
|
103
|
+
},
|
|
104
|
+
style: { width: "100%", boxSizing: "border-box" },
|
|
105
|
+
onChange: _,
|
|
106
|
+
onBlur: (F) => v(F, !1),
|
|
107
|
+
onSubmit: (F) => v(F, !0),
|
|
108
|
+
onCancel: L
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
async function v(t, i = !0) {
|
|
112
|
+
if (!e) return;
|
|
113
|
+
const o = t.trim();
|
|
114
|
+
if (o.startsWith("=") && !await R.checkFormula(o)) {
|
|
115
|
+
f == null || f();
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const { row: h, col: b } = e;
|
|
119
|
+
await q($, h, b, o), i && N(lt(h, b, "none")), y(), g == null || g(), W();
|
|
120
|
+
}
|
|
121
|
+
function L() {
|
|
122
|
+
y(), W();
|
|
123
|
+
}
|
|
124
|
+
const U = async (t) => {
|
|
125
|
+
await Promise.resolve(), K(t.row, t.col, t.initialText);
|
|
126
|
+
}, X = (t) => {
|
|
127
|
+
var i;
|
|
128
|
+
if (T()) {
|
|
129
|
+
const o = nt(t);
|
|
130
|
+
o && o !== C && (C = o, j(o));
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (c && e && ((i = t.data) == null ? void 0 : i.ty) === "cellRange") {
|
|
134
|
+
const { startRow: o, startCol: h } = t.data.d;
|
|
135
|
+
(o !== e.row || h !== e.col) && v(p, !1);
|
|
136
|
+
}
|
|
137
|
+
N(t), g == null || g();
|
|
138
|
+
}, Y = () => f == null ? void 0 : f();
|
|
139
|
+
return a.on("startEdit", U), a.on("selectionChange", X), a.on("invalidFormula", Y), {
|
|
140
|
+
setGrid(t) {
|
|
141
|
+
if (l = t, c && e && l) {
|
|
142
|
+
if (!rt(l, e.row, e.col))
|
|
143
|
+
e.position.x = -9999, e.position.y = -9999;
|
|
144
|
+
else {
|
|
145
|
+
const { x: i, y: o } = B(l, e.row, e.col, {
|
|
146
|
+
originX: u.x,
|
|
147
|
+
originY: u.y
|
|
148
|
+
});
|
|
149
|
+
e.position.x = i, e.position.y = o;
|
|
150
|
+
}
|
|
151
|
+
D();
|
|
152
|
+
}
|
|
153
|
+
k();
|
|
154
|
+
},
|
|
155
|
+
isEditing: () => c,
|
|
156
|
+
isEditingFormula: T,
|
|
157
|
+
destroy() {
|
|
158
|
+
a.off("startEdit", U), a.off("selectionChange", X), a.off("invalidFormula", Y), y();
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
export {
|
|
163
|
+
dt as createInlineCellEditor
|
|
164
|
+
};
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for the Formula Editor
|
|
3
|
+
*
|
|
4
|
+
* These match the backend API types from logisheets-web
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Token types returned by the backend lexer.
|
|
8
|
+
* The editor does NOT tokenize formulas itself - it calls a backend API.
|
|
9
|
+
*/
|
|
10
|
+
export type TokenType = 'funcName' | 'funcArg' | 'cellReference' | 'errorConstant' | 'wrongSuffix' | 'other';
|
|
11
|
+
/**
|
|
12
|
+
* A token unit representing a slice of the formula.
|
|
13
|
+
* The backend returns an array of these for syntax highlighting.
|
|
14
|
+
*/
|
|
15
|
+
export interface TokenUnit {
|
|
16
|
+
tokenType: TokenType;
|
|
17
|
+
/** Start index in the formula string (0-based, excludes leading '=') */
|
|
18
|
+
start: number;
|
|
19
|
+
/** End index in the formula string (exclusive) */
|
|
20
|
+
end: number;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Cell reference info parsed by the backend.
|
|
24
|
+
* Used for highlighting cell references with colors.
|
|
25
|
+
*/
|
|
26
|
+
export interface CellRef {
|
|
27
|
+
workbook?: string;
|
|
28
|
+
sheet1?: string;
|
|
29
|
+
sheet2?: string;
|
|
30
|
+
row1?: number;
|
|
31
|
+
col1?: number;
|
|
32
|
+
row2?: number;
|
|
33
|
+
col2?: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The complete display info returned by the backend for a formula.
|
|
37
|
+
* This is what the editor receives from `getDisplayUnitsOfFormula`.
|
|
38
|
+
*/
|
|
39
|
+
export interface FormulaDisplayInfo {
|
|
40
|
+
cellRefs: readonly CellRef[];
|
|
41
|
+
tokenUnits: readonly TokenUnit[];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Function to fetch formula display info from backend.
|
|
45
|
+
* The editor calls this whenever the text changes.
|
|
46
|
+
*
|
|
47
|
+
* @param formula - The formula text (with leading '=' stripped)
|
|
48
|
+
* @returns Promise resolving to FormulaDisplayInfo or undefined if not a formula
|
|
49
|
+
*/
|
|
50
|
+
export type GetDisplayUnitsFunc = (formula: string) => Promise<FormulaDisplayInfo | undefined>;
|
|
51
|
+
/**
|
|
52
|
+
* A formula function definition for autocomplete.
|
|
53
|
+
*/
|
|
54
|
+
export interface FormulaFunction {
|
|
55
|
+
/** Function name, e.g. "SUM" */
|
|
56
|
+
name: string;
|
|
57
|
+
/** Description of what the function does */
|
|
58
|
+
description: string;
|
|
59
|
+
/** Function arguments */
|
|
60
|
+
args: FormulaArg[];
|
|
61
|
+
/** Argument count constraints */
|
|
62
|
+
argCount: {
|
|
63
|
+
eq?: number;
|
|
64
|
+
ge?: number;
|
|
65
|
+
le?: number;
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* A function argument definition.
|
|
70
|
+
*/
|
|
71
|
+
export interface FormulaArg {
|
|
72
|
+
argName: string;
|
|
73
|
+
description: string;
|
|
74
|
+
/** If true, this argument can repeat */
|
|
75
|
+
startRepeated?: boolean;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* An autocomplete candidate.
|
|
79
|
+
*/
|
|
80
|
+
export interface Candidate {
|
|
81
|
+
/** Plain text to insert when selected */
|
|
82
|
+
text: string;
|
|
83
|
+
/** Display spans with optional highlighting */
|
|
84
|
+
spans: CandidateSpan[];
|
|
85
|
+
/** Description shown in the dropdown */
|
|
86
|
+
description?: string;
|
|
87
|
+
/** If true, pressing Enter won't insert this candidate */
|
|
88
|
+
isInfoOnly?: boolean;
|
|
89
|
+
/** Position where cursor should be placed after insertion (for adding between parentheses) */
|
|
90
|
+
cursorOffset?: number;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* A span within a candidate's display text.
|
|
94
|
+
*/
|
|
95
|
+
export interface CandidateSpan {
|
|
96
|
+
text: string;
|
|
97
|
+
highlight?: boolean;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Editor configuration options.
|
|
101
|
+
*/
|
|
102
|
+
export interface FormulaEditorConfig {
|
|
103
|
+
/** Font size in pixels */
|
|
104
|
+
fontSize?: number;
|
|
105
|
+
/** Font family */
|
|
106
|
+
fontFamily?: string;
|
|
107
|
+
/** Line height multiplier */
|
|
108
|
+
lineHeight?: number;
|
|
109
|
+
/** Text alignment: 'left' | 'center' | 'right' */
|
|
110
|
+
textAlign?: 'left' | 'center' | 'right';
|
|
111
|
+
/** Enable word wrap */
|
|
112
|
+
wordWrap?: boolean;
|
|
113
|
+
/** Placeholder text when empty */
|
|
114
|
+
placeholder?: string;
|
|
115
|
+
/** Read-only mode */
|
|
116
|
+
readOnly?: boolean;
|
|
117
|
+
/** Auto-focus on mount */
|
|
118
|
+
autoFocus?: boolean;
|
|
119
|
+
/** Show border around the editor */
|
|
120
|
+
showBorder?: boolean;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Props for the FormulaEditor component.
|
|
124
|
+
*/
|
|
125
|
+
export interface FormulaEditorProps {
|
|
126
|
+
/** Current value (controlled) */
|
|
127
|
+
value?: string;
|
|
128
|
+
/** Default value (uncontrolled) */
|
|
129
|
+
defaultValue?: string;
|
|
130
|
+
/** Initial cursor position: 'start' or 'end' (default: 'end') */
|
|
131
|
+
initialCursorPosition?: 'start' | 'end';
|
|
132
|
+
/** Called when value changes */
|
|
133
|
+
onChange?: (value: string) => void;
|
|
134
|
+
/** Called when editor loses focus - use this to commit the value */
|
|
135
|
+
onBlur?: (value: string) => void;
|
|
136
|
+
/** Called when Enter is pressed (without modifier keys) */
|
|
137
|
+
onSubmit?: (value: string) => void;
|
|
138
|
+
/** Called when Escape is pressed */
|
|
139
|
+
onCancel?: () => void;
|
|
140
|
+
/** Function to get display units from backend */
|
|
141
|
+
getDisplayUnits: GetDisplayUnitsFunc;
|
|
142
|
+
/** List of available formula functions for autocomplete */
|
|
143
|
+
formulaFunctions?: FormulaFunction[];
|
|
144
|
+
/** Current sheet name (for determining if cell refs are local) */
|
|
145
|
+
sheetName?: string;
|
|
146
|
+
/** Configuration options */
|
|
147
|
+
config?: FormulaEditorConfig;
|
|
148
|
+
/** Custom class name */
|
|
149
|
+
className?: string;
|
|
150
|
+
/** Custom style */
|
|
151
|
+
style?: React.CSSProperties;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Colors for cell reference highlighting.
|
|
155
|
+
* Returns a different color for each reference index to distinguish them.
|
|
156
|
+
*/
|
|
157
|
+
export declare const CELL_REF_COLORS: string[];
|
|
158
|
+
export declare function getCellRefColor(index: number): string;
|
|
159
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/lib/types.ts"],"names":[],"mappings":"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"}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { TokenType, FormulaDisplayInfo, CellRef } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Special character used to represent line breaks in the editor.
|
|
4
|
+
*/
|
|
5
|
+
export declare const EOF = "\n";
|
|
6
|
+
/**
|
|
7
|
+
* Display unit for rendering - combines token info with content.
|
|
8
|
+
*/
|
|
9
|
+
export interface DisplayUnit {
|
|
10
|
+
content: string;
|
|
11
|
+
type: TokenType | 'eof' | 'plain';
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Convert formula display info to display units for rendering.
|
|
15
|
+
* The offset accounts for the leading '=' being stripped before sending to backend.
|
|
16
|
+
*
|
|
17
|
+
* @param formula - The full formula string (including leading '=')
|
|
18
|
+
* @param displayInfo - Token info from backend
|
|
19
|
+
* @returns Array of display units for rendering
|
|
20
|
+
*/
|
|
21
|
+
export declare function convertToDisplayUnits(formula: string, displayInfo: FormulaDisplayInfo): DisplayUnit[];
|
|
22
|
+
/**
|
|
23
|
+
* Check if a cell reference is local to the current sheet.
|
|
24
|
+
* Local refs get colored backgrounds, external refs are plain text.
|
|
25
|
+
*/
|
|
26
|
+
export declare function isLocalCellRef(cellRef: CellRef, currentSheet: string): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Simple fuzzy match using longest common subsequence.
|
|
29
|
+
*/
|
|
30
|
+
export declare function fuzzyMatch(query: string, target: string): {
|
|
31
|
+
matched: boolean;
|
|
32
|
+
indices: number[];
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Check if text starts with '=' indicating a formula.
|
|
36
|
+
*/
|
|
37
|
+
export declare function isFormula(text: string): boolean;
|
|
38
|
+
export declare function measureText(text: string, font: string): number;
|
|
39
|
+
/**
|
|
40
|
+
* Generate a simple UUID.
|
|
41
|
+
*/
|
|
42
|
+
export declare function simpleUuid(): string;
|
|
43
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/lib/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAE,kBAAkB,EAAE,OAAO,EAAC,MAAM,SAAS,CAAA;AAEnE;;GAEG;AACH,eAAO,MAAM,GAAG,OAAO,CAAA;AAEvB;;GAEG;AACH,MAAM,WAAW,WAAW;IACxB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,SAAS,GAAG,KAAK,GAAG,OAAO,CAAA;CACpC;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACjC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,kBAAkB,GAChC,WAAW,EAAE,CAqCf;AAqBD;;;GAGG;AACH,wBAAgB,cAAc,CAC1B,OAAO,EAAE,OAAO,EAChB,YAAY,EAAE,MAAM,GACrB,OAAO,CAcT;AAED;;GAEG;AACH,wBAAgB,UAAU,CACtB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACf;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAC,CAqBvC;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAQ/C;AAQD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAS9D;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAMnC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "logisheets-formula-editor",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
},
|
|
13
|
+
"./core": {
|
|
14
|
+
"import": "./dist/core.js",
|
|
15
|
+
"types": "./dist/core.d.ts"
|
|
16
|
+
},
|
|
17
|
+
"./engine": {
|
|
18
|
+
"import": "./dist/engine.js",
|
|
19
|
+
"types": "./dist/engine.d.ts"
|
|
20
|
+
},
|
|
21
|
+
"./inline": {
|
|
22
|
+
"import": "./dist/inline.js",
|
|
23
|
+
"types": "./dist/inline.d.ts"
|
|
24
|
+
},
|
|
25
|
+
"./styles.css": "./dist/styles.css"
|
|
26
|
+
},
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"logisheets-engine": "*",
|
|
29
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
30
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
31
|
+
},
|
|
32
|
+
"peerDependenciesMeta": {
|
|
33
|
+
"logisheets-engine": {
|
|
34
|
+
"optional": true
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"files": [
|
|
38
|
+
"dist"
|
|
39
|
+
],
|
|
40
|
+
"scripts": {
|
|
41
|
+
"dev": "vite",
|
|
42
|
+
"build": "tsc && vite build",
|
|
43
|
+
"preview": "vite preview",
|
|
44
|
+
"typecheck": "tsc --noEmit",
|
|
45
|
+
"gen:functions": "node scripts/gen-builtin-functions.mjs",
|
|
46
|
+
"prepack": "yarn build"
|
|
47
|
+
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"@codemirror/autocomplete": "^6.18.0",
|
|
50
|
+
"@codemirror/commands": "^6.6.0",
|
|
51
|
+
"@codemirror/language": "^6.10.0",
|
|
52
|
+
"@codemirror/state": "^6.4.0",
|
|
53
|
+
"@codemirror/view": "^6.30.0",
|
|
54
|
+
"@lezer/highlight": "^1.2.0"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@vitejs/plugin-react": "^4.3.1",
|
|
58
|
+
"typescript": "^5.5.3",
|
|
59
|
+
"vite": "^5.4.0",
|
|
60
|
+
"vite-plugin-dts": "^4.0.0"
|
|
61
|
+
}
|
|
62
|
+
}
|