@zhenliang/sheet 0.2.5-beta.0 → 0.2.5-beta.10
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/core/editor/InputOptionsEditor/index.d.ts +2 -11
- package/dist/core/editor/InputOptionsEditor/index.js +330 -174
- package/dist/core/editor/InputOptionsEditor/index.less +2 -1
- package/dist/core/editor/InputOptionsEditor/utils.d.ts +17 -1
- package/dist/core/editor/InputOptionsEditor/utils.js +34 -6
- package/dist/core/editor/InputOptionsEditor/vaildFormula.js +14 -2
- package/dist/core/editor/numberEditor/index.d.ts +1 -0
- package/dist/core/editor/numberEditor/index.js +2 -2
- package/dist/core/sheet/Cell.js +15 -15
- package/dist/core/table/useRowSelection.d.ts +1 -1
- package/dist/example/basic.js +19 -7
- package/package.json +1 -1
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
import type { SheetType } from "../../../type";
|
|
2
2
|
import './index.less';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
value: string;
|
|
6
|
-
info?: string;
|
|
7
|
-
children?: OptionItem[];
|
|
8
|
-
}
|
|
9
|
-
export interface FormulaInputProps {
|
|
10
|
-
options: OptionItem[];
|
|
11
|
-
value?: string;
|
|
12
|
-
}
|
|
13
|
-
export declare const getFormulaInputEditor: (options: OptionItem[]) => SheetType.CellEditor;
|
|
3
|
+
import { OptionItem, inputProps } from './utils';
|
|
4
|
+
export declare const getFormulaInputEditor: (options: OptionItem[], replaceIndex?: string, extraProps?: inputProps, getExtraProps?: ((props: SheetType.CellEditorProps) => inputProps) | undefined, choseEditor?: ((record: any) => boolean) | undefined) => SheetType.CellEditor;
|
|
14
5
|
export default getFormulaInputEditor;
|
|
@@ -11,42 +11,63 @@ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o =
|
|
|
11
11
|
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
12
12
|
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
13
13
|
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
14
|
-
|
|
15
|
-
import { head, isEmpty, isNil } from 'lodash';
|
|
16
|
-
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
14
|
+
function _objectDestructuringEmpty(obj) { if (obj == null) throw new TypeError("Cannot destructure " + obj); }
|
|
17
15
|
import { InfoCircleOutlined } from '@ant-design/icons';
|
|
18
|
-
import {
|
|
19
|
-
import
|
|
16
|
+
import { Dropdown, Input, Menu, Tooltip } from 'antd';
|
|
17
|
+
import { get, head, isEmpty, isNil } from 'lodash';
|
|
18
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
19
|
+
import { formulaString } from "../numberEditor";
|
|
20
20
|
import "./index.less";
|
|
21
|
+
import { flattenOptions, getCursorPositionInSpan, getSpanAtCursor, getStringDiff, moveCursorToSpan, replaceLabelsWithValues, replaceLongestDiff, replaceValuesWithLabels, tokenize, validateVariables } from "./utils";
|
|
22
|
+
import validateCalculationExpr from "./vaildFormula";
|
|
21
23
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
22
24
|
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
23
|
-
var OPERATORS = ['=', '+', '-', '*', '/'];
|
|
24
|
-
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
25
|
+
var OPERATORS = ['=', '+', '-', '*', '/', '('];
|
|
26
|
+
|
|
27
|
+
// // 创建 label span
|
|
28
|
+
// const createLabelSpan = (label: string): HTMLElement => {
|
|
29
|
+
// const span = document.createElement('span');
|
|
30
|
+
// span.className = 'formula-editor-token-label';
|
|
31
|
+
// span.textContent = label;
|
|
32
|
+
// return span;
|
|
33
|
+
// };
|
|
34
|
+
|
|
35
|
+
// // 创建 empty other span
|
|
36
|
+
// const createEmptyOtherSpan = (): HTMLElement => {
|
|
37
|
+
// const span = document.createElement('span');
|
|
38
|
+
// span.className = 'formula-editor-token-other';
|
|
39
|
+
// span.textContent = '';
|
|
40
|
+
// return span;
|
|
41
|
+
// };
|
|
42
|
+
|
|
43
|
+
export var getFormulaInputEditor = function getFormulaInputEditor(options, replaceIndex, extraProps, getExtraProps, choseEditor) {
|
|
44
|
+
var _ref = extraProps || {},
|
|
45
|
+
warnMethod = _ref.warnMethod,
|
|
46
|
+
rangeMethod = _ref.rangeMethod,
|
|
47
|
+
precision = _ref.precision,
|
|
48
|
+
max = _ref.max,
|
|
49
|
+
min = _ref.min;
|
|
36
50
|
var FormulaInputEditor = function FormulaInputEditor(props) {
|
|
37
|
-
var
|
|
51
|
+
var _get;
|
|
52
|
+
var originValue = props.value,
|
|
38
53
|
onChange = props.onChange,
|
|
39
|
-
isEditing = props.isEditing
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
54
|
+
isEditing = props.isEditing,
|
|
55
|
+
record = props.record;
|
|
56
|
+
// 兼容number
|
|
57
|
+
var inputNumberRef = useRef(null);
|
|
58
|
+
var _ref2 = getExtraProps ? getExtraProps(props) : extraProps !== null && extraProps !== void 0 ? extraProps : {},
|
|
59
|
+
inputArgs = Object.assign({}, (_objectDestructuringEmpty(_ref2), _ref2));
|
|
60
|
+
var replaceValue = replaceIndex ? (_get = get(record, [replaceIndex])) !== null && _get !== void 0 ? _get : '' : originValue;
|
|
61
|
+
var calcValue = replaceValue.startsWith('=') ? replaceValue : "=".concat(replaceValue);
|
|
62
|
+
var _useState = useState(calcValue),
|
|
63
|
+
_useState2 = _slicedToArray(_useState, 1),
|
|
64
|
+
inputValue = _useState2[0];
|
|
44
65
|
var _useState3 = useState(0),
|
|
45
66
|
_useState4 = _slicedToArray(_useState3, 2),
|
|
46
67
|
offsetX = _useState4[0],
|
|
47
68
|
setOffsetX = _useState4[1];
|
|
48
69
|
// 为了不重新render,再写一个
|
|
49
|
-
var _useState5 = useState(
|
|
70
|
+
var _useState5 = useState(replaceValue),
|
|
50
71
|
_useState6 = _slicedToArray(_useState5, 2),
|
|
51
72
|
containerValue = _useState6[0],
|
|
52
73
|
setContainerValue = _useState6[1];
|
|
@@ -59,6 +80,7 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options) {
|
|
|
59
80
|
_useState10 = _slicedToArray(_useState9, 2),
|
|
60
81
|
inputAfterDropDownShow = _useState10[0],
|
|
61
82
|
setInputAfterDropDownShow = _useState10[1];
|
|
83
|
+
var tempSpanRef = useRef(null);
|
|
62
84
|
var containerRef = useRef(null);
|
|
63
85
|
var inputOperatorPosition = useRef(0);
|
|
64
86
|
|
|
@@ -73,7 +95,7 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options) {
|
|
|
73
95
|
}, [inputValue, flatOptions]);
|
|
74
96
|
// 根据搜索文本获取筛选后的层级选项(保持层级结构)
|
|
75
97
|
var filteredHierarchyOptions = useMemo(function () {
|
|
76
|
-
var searchText = inputAfterDropDownShow;
|
|
98
|
+
var searchText = inputAfterDropDownShow.trim();
|
|
77
99
|
// 如果搜索文本为空,显示所有选项(保持层级)
|
|
78
100
|
if (!searchText) {
|
|
79
101
|
return options;
|
|
@@ -108,43 +130,94 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options) {
|
|
|
108
130
|
useEffect(function () {
|
|
109
131
|
if (!open) {
|
|
110
132
|
containerValueSnapShot.current = '';
|
|
133
|
+
tempSpanRef.current = null;
|
|
111
134
|
}
|
|
112
135
|
setInputAfterDropDownShow('');
|
|
113
136
|
}, [open]);
|
|
137
|
+
var closeDorpDown = useCallback(function () {
|
|
138
|
+
setInputAfterDropDownShow('');
|
|
139
|
+
tempSpanRef.current = null;
|
|
140
|
+
// 点击div内直接关闭
|
|
141
|
+
setOpen(false);
|
|
142
|
+
}, []);
|
|
114
143
|
|
|
115
|
-
//
|
|
144
|
+
// 处理选项点击
|
|
116
145
|
var handleOptionClick = useCallback(function (opt) {
|
|
117
146
|
var container = containerRef.current;
|
|
118
147
|
if (!container) return;
|
|
119
|
-
var newValue = replaceLongestDiff(containerValueSnapShot.current, opt.label, inputOperatorPosition.current);
|
|
120
|
-
setOpen(false);
|
|
121
|
-
containerValueSnapShot.current = '';
|
|
122
|
-
var expr = newValue;
|
|
123
|
-
var valueExpr = replaceLabelsWithValues(expr, flatOptions);
|
|
124
|
-
setContainerValue(valueExpr);
|
|
125
|
-
onChange(valueExpr);
|
|
126
|
-
|
|
127
|
-
// 获取当前光标所在的 span
|
|
128
148
|
var selection = window.getSelection();
|
|
129
149
|
if (!selection || selection.rangeCount === 0) return;
|
|
150
|
+
|
|
151
|
+
// 如果有 tempSpanRef,用新逻辑:直接替换该 span 的内容
|
|
152
|
+
if (tempSpanRef.current) {
|
|
153
|
+
tempSpanRef.current.textContent = opt.label;
|
|
154
|
+
var replacedSpan = tempSpanRef.current;
|
|
155
|
+
tempSpanRef.current = null;
|
|
156
|
+
|
|
157
|
+
// 光标移到替换后的 span 后面
|
|
158
|
+
var _allSpans = Array.from(container.querySelectorAll('span'));
|
|
159
|
+
var replacedIndex = _allSpans.indexOf(replacedSpan);
|
|
160
|
+
var _targetSpan = _allSpans[replacedIndex + 1];
|
|
161
|
+
if (!_targetSpan || _targetSpan.classList.contains('formula-editor-token-label')) {
|
|
162
|
+
_targetSpan = document.createElement('span');
|
|
163
|
+
_targetSpan.className = 'formula-editor-token-other';
|
|
164
|
+
_targetSpan.textContent = '';
|
|
165
|
+
replacedSpan.after(_targetSpan);
|
|
166
|
+
}
|
|
167
|
+
moveCursorToSpan(_targetSpan, true, selection);
|
|
168
|
+
// 更新 containerValue
|
|
169
|
+
var newValue = container.textContent || '';
|
|
170
|
+
var valueExpr = replaceLabelsWithValues(newValue, flatOptions);
|
|
171
|
+
setContainerValue(valueExpr);
|
|
172
|
+
onChange(valueExpr);
|
|
173
|
+
setOpen(false);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
// 原逻辑:删除 inputAfterDropDownShow,插入新 label
|
|
177
|
+
var newValueUser = replaceLongestDiff(containerValueSnapShot.current, opt.label, inputOperatorPosition.current);
|
|
178
|
+
var expr = newValueUser;
|
|
179
|
+
var valueExprUser = replaceLabelsWithValues(expr, flatOptions);
|
|
180
|
+
setContainerValue(valueExprUser);
|
|
181
|
+
onChange(valueExprUser);
|
|
130
182
|
var range = selection.getRangeAt(0);
|
|
131
183
|
var startContainer = range.startContainer;
|
|
132
184
|
var currentSpan = startContainer.nodeType === Node.TEXT_NODE ? startContainer.parentElement : startContainer;
|
|
133
185
|
if (!currentSpan || currentSpan === container) return;
|
|
134
186
|
|
|
135
|
-
//
|
|
187
|
+
// 获取删除 inputAfterDropDownShow 后的前半部分和后半部分
|
|
136
188
|
var spanText = currentSpan.textContent || '';
|
|
137
189
|
var deleteText = inputAfterDropDownShow;
|
|
138
190
|
var deleteIndex = spanText.indexOf(deleteText);
|
|
139
|
-
|
|
140
|
-
|
|
191
|
+
// 如果找不到 deleteText,用当前光标位置作为 deleteIndex
|
|
192
|
+
if (deleteIndex === -1 || !deleteText) {
|
|
193
|
+
deleteIndex = range.startOffset;
|
|
141
194
|
}
|
|
195
|
+
var beforePart = spanText.slice(0, deleteIndex);
|
|
196
|
+
var afterPart = spanText.slice(deleteIndex + deleteText.length);
|
|
142
197
|
|
|
143
|
-
//
|
|
198
|
+
// 删除当前 span,用三个 span 替换:other(前)、label、other(后)
|
|
144
199
|
var labelSpan = document.createElement('span');
|
|
145
200
|
labelSpan.className = 'formula-editor-token-label';
|
|
146
201
|
labelSpan.textContent = opt.label;
|
|
147
|
-
|
|
202
|
+
|
|
203
|
+
// 创建待插入的 span 列表
|
|
204
|
+
var spansToInsert = [];
|
|
205
|
+
if (beforePart) {
|
|
206
|
+
var beforeSpan = document.createElement('span');
|
|
207
|
+
beforeSpan.className = 'formula-editor-token-other';
|
|
208
|
+
beforeSpan.textContent = beforePart;
|
|
209
|
+
spansToInsert.push(beforeSpan);
|
|
210
|
+
}
|
|
211
|
+
spansToInsert.push(labelSpan);
|
|
212
|
+
if (afterPart) {
|
|
213
|
+
var afterSpan = document.createElement('span');
|
|
214
|
+
afterSpan.className = 'formula-editor-token-other';
|
|
215
|
+
afterSpan.textContent = afterPart;
|
|
216
|
+
spansToInsert.push(afterSpan);
|
|
217
|
+
}
|
|
218
|
+
// 插入所有 span
|
|
219
|
+
currentSpan.after.apply(currentSpan, spansToInsert);
|
|
220
|
+
currentSpan.remove();
|
|
148
221
|
|
|
149
222
|
// 将光标移到下一个 span 的开头
|
|
150
223
|
var allSpans = Array.from(container.querySelectorAll('span'));
|
|
@@ -158,19 +231,17 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options) {
|
|
|
158
231
|
targetSpan.textContent = '';
|
|
159
232
|
labelSpan.after(targetSpan);
|
|
160
233
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
var newRange = document.createRange();
|
|
164
|
-
newRange.selectNodeContents(targetSpan);
|
|
165
|
-
newRange.collapse(true);
|
|
166
|
-
selection.removeAllRanges();
|
|
167
|
-
selection.addRange(newRange);
|
|
234
|
+
moveCursorToSpan(targetSpan, true, selection);
|
|
235
|
+
setOpen(false);
|
|
168
236
|
}, [inputAfterDropDownShow]);
|
|
169
237
|
|
|
170
238
|
// 处理输入变化
|
|
171
239
|
var handleInput = useCallback(function () {
|
|
172
240
|
var container = containerRef.current;
|
|
173
241
|
if (!container) return;
|
|
242
|
+
if (tempSpanRef.current) {
|
|
243
|
+
closeDorpDown();
|
|
244
|
+
}
|
|
174
245
|
var newValue = container.textContent || '';
|
|
175
246
|
var processedValue = newValue;
|
|
176
247
|
var expr = processedValue;
|
|
@@ -194,7 +265,7 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options) {
|
|
|
194
265
|
if (open) {
|
|
195
266
|
var _getStringDiff2 = getStringDiff(containerValueSnapShot.current, newValue),
|
|
196
267
|
addedOnSnapShot = _getStringDiff2.added;
|
|
197
|
-
isBeginWithNumber = /^\d$/.test(head(addedOnSnapShot));
|
|
268
|
+
isBeginWithNumber = /^\d$/.test(head(addedOnSnapShot.join('').trim()));
|
|
198
269
|
inputStringAfterDropDownShow = addedOnSnapShot.join('');
|
|
199
270
|
}
|
|
200
271
|
if (pressAOperator) {
|
|
@@ -231,12 +302,8 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options) {
|
|
|
231
302
|
(_containerRef$current2 = containerRef.current) === null || _containerRef$current2 === void 0 || _containerRef$current2.focus();
|
|
232
303
|
}
|
|
233
304
|
}, [isEditing]);
|
|
234
|
-
var closeDorpDown = useCallback(function () {
|
|
235
|
-
// 点击div内直接关闭
|
|
236
|
-
setOpen(false);
|
|
237
|
-
}, []);
|
|
238
305
|
|
|
239
|
-
// 鼠标释放时,如果光标在 label span
|
|
306
|
+
// 鼠标释放时,如果光标在 label span 内,打开下拉框并记录 tempSpan
|
|
240
307
|
var handleMouseUp = useCallback(function () {
|
|
241
308
|
var div = containerRef.current;
|
|
242
309
|
if (!div) return;
|
|
@@ -249,8 +316,20 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options) {
|
|
|
249
316
|
if (!currentSpan || currentSpan === div) return;
|
|
250
317
|
var isLabelSpan = currentSpan.classList.contains('formula-editor-token-label');
|
|
251
318
|
|
|
252
|
-
// 如果在 label span
|
|
319
|
+
// 如果在 label span 内,打开下拉框并记录 tempSpan
|
|
253
320
|
if (isLabelSpan) {
|
|
321
|
+
// 更新 offsetX 位置
|
|
322
|
+
var containerRect = div.getBoundingClientRect();
|
|
323
|
+
var cursorRect = range.getBoundingClientRect();
|
|
324
|
+
var cursorDistance = cursorRect ? cursorRect.left - containerRect.left : 0;
|
|
325
|
+
setOffsetX(cursorDistance < 150 ? 0 : cursorDistance - 8);
|
|
326
|
+
|
|
327
|
+
// 记录当前 label span 作为 tempSpan
|
|
328
|
+
tempSpanRef.current = currentSpan;
|
|
329
|
+
|
|
330
|
+
// 打开下拉框
|
|
331
|
+
setOpen(true);
|
|
332
|
+
// 移动到下一个 span 的开头
|
|
254
333
|
var allSpans = Array.from(div.querySelectorAll('span'));
|
|
255
334
|
var currentIndex = allSpans.indexOf(currentSpan);
|
|
256
335
|
if (currentIndex < allSpans.length - 1) {
|
|
@@ -262,9 +341,14 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options) {
|
|
|
262
341
|
selection.addRange(newRange);
|
|
263
342
|
}
|
|
264
343
|
}
|
|
265
|
-
}, [closeDorpDown]);
|
|
344
|
+
}, [closeDorpDown, setOffsetX, setOpen]);
|
|
266
345
|
var handleKeyDown = useCallback(function (e) {
|
|
267
346
|
var _currentSpan$textCont, _currentSpan$textCont2;
|
|
347
|
+
if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
|
|
348
|
+
e.preventDefault();
|
|
349
|
+
e.stopPropagation();
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
268
352
|
var div = containerRef.current;
|
|
269
353
|
if (!div) return;
|
|
270
354
|
var selection = window.getSelection();
|
|
@@ -280,13 +364,13 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options) {
|
|
|
280
364
|
|
|
281
365
|
// 方向键:跳过 label span
|
|
282
366
|
if (e.key === 'ArrowRight' || e.key === 'ArrowLeft') {
|
|
283
|
-
closeDorpDown();
|
|
284
367
|
var position = getCursorPositionInSpan(currentSpan);
|
|
285
368
|
var isAtEnd = startOffset >= textLen;
|
|
286
369
|
var isAtStart = startOffset === 0;
|
|
287
370
|
var isAlmostEnd = startOffset >= textLen - 1;
|
|
288
371
|
var isAlmostStart = position === 1;
|
|
289
372
|
if (e.key === 'ArrowRight' && isAtEnd) {
|
|
373
|
+
closeDorpDown();
|
|
290
374
|
// 向右 + 在末尾 -> 跳到下一个 span 的开头(跳过 label span)
|
|
291
375
|
var targetIndex = currentIndex + 1;
|
|
292
376
|
while (targetIndex < allSpans.length && allSpans[targetIndex].classList.contains('formula-editor-token-label')) {
|
|
@@ -295,48 +379,35 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options) {
|
|
|
295
379
|
if (targetIndex < allSpans.length && targetIndex !== currentIndex + 1) {
|
|
296
380
|
e.preventDefault();
|
|
297
381
|
var targetSpan = allSpans[targetIndex];
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
382
|
+
moveCursorToSpan(targetSpan, true, selection);
|
|
383
|
+
}
|
|
384
|
+
} else if (e.key === 'ArrowRight' && isAlmostEnd) {
|
|
385
|
+
closeDorpDown();
|
|
386
|
+
var _targetIndex = currentIndex + 1;
|
|
387
|
+
if (_targetIndex < allSpans.length && !allSpans[_targetIndex].classList.contains('formula-editor-token-label')) {
|
|
388
|
+
e.preventDefault();
|
|
389
|
+
var _targetSpan2 = allSpans[_targetIndex];
|
|
390
|
+
moveCursorToSpan(_targetSpan2, true, selection);
|
|
303
391
|
}
|
|
304
392
|
} else if (e.key === 'ArrowLeft' && isAtStart) {
|
|
393
|
+
closeDorpDown();
|
|
305
394
|
// 向左 + 在开头 -> 跳到上一个 span 的末尾(跳过 label span)
|
|
306
|
-
var
|
|
307
|
-
while (
|
|
308
|
-
|
|
309
|
-
}
|
|
310
|
-
if (_targetIndex >= 0 && _targetIndex !== currentIndex - 1) {
|
|
311
|
-
e.preventDefault();
|
|
312
|
-
var _targetSpan = allSpans[_targetIndex];
|
|
313
|
-
var _newRange = document.createRange();
|
|
314
|
-
_newRange.selectNodeContents(_targetSpan);
|
|
315
|
-
_newRange.collapse(false);
|
|
316
|
-
selection.removeAllRanges();
|
|
317
|
-
selection.addRange(_newRange);
|
|
395
|
+
var _targetIndex2 = currentIndex - 1;
|
|
396
|
+
while (_targetIndex2 >= 0 && allSpans[_targetIndex2].classList.contains('formula-editor-token-label')) {
|
|
397
|
+
_targetIndex2--;
|
|
318
398
|
}
|
|
319
|
-
|
|
320
|
-
var _targetIndex2 = currentIndex + 1;
|
|
321
|
-
if (_targetIndex2 < allSpans.length && !allSpans[_targetIndex2].classList.contains('formula-editor-token-label')) {
|
|
399
|
+
if (_targetIndex2 >= 0 && _targetIndex2 !== currentIndex - 1) {
|
|
322
400
|
e.preventDefault();
|
|
323
|
-
var
|
|
324
|
-
|
|
325
|
-
_newRange2.selectNodeContents(_targetSpan2);
|
|
326
|
-
_newRange2.collapse(true);
|
|
327
|
-
selection.removeAllRanges();
|
|
328
|
-
selection.addRange(_newRange2);
|
|
401
|
+
var _targetSpan3 = allSpans[_targetIndex2];
|
|
402
|
+
moveCursorToSpan(_targetSpan3, false, selection);
|
|
329
403
|
}
|
|
330
404
|
} else if (e.key === 'ArrowLeft' && isAlmostStart) {
|
|
405
|
+
closeDorpDown();
|
|
331
406
|
var _targetIndex3 = currentIndex - 1;
|
|
332
407
|
if (_targetIndex3 >= 0 && !allSpans[_targetIndex3].classList.contains('formula-editor-token-label')) {
|
|
333
408
|
e.preventDefault();
|
|
334
|
-
var
|
|
335
|
-
|
|
336
|
-
_newRange3.selectNodeContents(_targetSpan3);
|
|
337
|
-
_newRange3.collapse(false);
|
|
338
|
-
selection.removeAllRanges();
|
|
339
|
-
selection.addRange(_newRange3);
|
|
409
|
+
var _targetSpan4 = allSpans[_targetIndex3];
|
|
410
|
+
moveCursorToSpan(_targetSpan4, false, selection);
|
|
340
411
|
}
|
|
341
412
|
}
|
|
342
413
|
return;
|
|
@@ -344,6 +415,19 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options) {
|
|
|
344
415
|
|
|
345
416
|
// 删除键逻辑
|
|
346
417
|
if (e.key !== 'Delete' && e.key !== 'Backspace') return;
|
|
418
|
+
if (e.key === 'Backspace' || e.key === 'Delete') {
|
|
419
|
+
if (tempSpanRef.current) {
|
|
420
|
+
closeDorpDown();
|
|
421
|
+
}
|
|
422
|
+
// 检查删除后是否只剩一个空的 span
|
|
423
|
+
var allSpansNow = Array.from(div.querySelectorAll('span'));
|
|
424
|
+
var isOnlyOneEmptySpan = allSpansNow.length === 1 && allSpansNow[0].textContent === '';
|
|
425
|
+
if (isOnlyOneEmptySpan) {
|
|
426
|
+
e.preventDefault();
|
|
427
|
+
e.stopPropagation();
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
347
431
|
|
|
348
432
|
// 不在 label span 内,在 span 开头且前一个是 label 时,删除整个 label span
|
|
349
433
|
if (startOffset === 0 && e.key === 'Backspace' && currentIndex > 0) {
|
|
@@ -352,31 +436,31 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options) {
|
|
|
352
436
|
e.preventDefault();
|
|
353
437
|
e.stopPropagation();
|
|
354
438
|
prevSpan.remove();
|
|
355
|
-
var
|
|
439
|
+
var newRange = document.createRange();
|
|
356
440
|
|
|
357
441
|
// 如果当前 span 有内容,光标放在开头;否则找最近的有内容的 span
|
|
358
442
|
if (currentSpan.textContent !== '') {
|
|
359
|
-
|
|
360
|
-
|
|
443
|
+
newRange.selectNodeContents(currentSpan);
|
|
444
|
+
newRange.collapse(true);
|
|
361
445
|
} else {
|
|
362
446
|
// 找前一个最近的有内容的 span
|
|
363
|
-
var
|
|
447
|
+
var _targetSpan5;
|
|
364
448
|
for (var i = currentIndex - 2; i >= 0; i--) {
|
|
365
449
|
if (allSpans[i].textContent !== '') {
|
|
366
|
-
|
|
450
|
+
_targetSpan5 = allSpans[i];
|
|
367
451
|
break;
|
|
368
452
|
}
|
|
369
453
|
}
|
|
370
|
-
if (
|
|
371
|
-
|
|
372
|
-
|
|
454
|
+
if (_targetSpan5) {
|
|
455
|
+
newRange.selectNodeContents(_targetSpan5);
|
|
456
|
+
newRange.collapse(false);
|
|
373
457
|
} else {
|
|
374
|
-
|
|
375
|
-
|
|
458
|
+
newRange.selectNodeContents(div);
|
|
459
|
+
newRange.collapse(true);
|
|
376
460
|
}
|
|
377
461
|
}
|
|
378
462
|
selection.removeAllRanges();
|
|
379
|
-
selection.addRange(
|
|
463
|
+
selection.addRange(newRange);
|
|
380
464
|
return;
|
|
381
465
|
}
|
|
382
466
|
}
|
|
@@ -392,11 +476,11 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options) {
|
|
|
392
476
|
if (prevText.length > 0) {
|
|
393
477
|
_prevSpan.textContent = prevText.slice(0, -1);
|
|
394
478
|
}
|
|
395
|
-
var
|
|
396
|
-
|
|
397
|
-
|
|
479
|
+
var _newRange = document.createRange();
|
|
480
|
+
_newRange.selectNodeContents(_prevSpan);
|
|
481
|
+
_newRange.collapse(false);
|
|
398
482
|
selection.removeAllRanges();
|
|
399
|
-
selection.addRange(
|
|
483
|
+
selection.addRange(_newRange);
|
|
400
484
|
}
|
|
401
485
|
}
|
|
402
486
|
|
|
@@ -411,76 +495,104 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options) {
|
|
|
411
495
|
// 如果光标在 span 开头 + Delete 键,currentIndex 指向的是被删 span 的后一个,所以要 -1
|
|
412
496
|
var searchIndex = startOffset === 0 ? currentIndex - 1 : currentIndex;
|
|
413
497
|
// 从 searchIndex 位置往前找
|
|
414
|
-
var
|
|
498
|
+
var _targetSpan6;
|
|
415
499
|
for (var _i = searchIndex; _i >= 0; _i--) {
|
|
416
500
|
var span = allSpansNow[_i];
|
|
417
501
|
if (span.textContent !== '') {
|
|
418
|
-
|
|
502
|
+
_targetSpan6 = span;
|
|
419
503
|
break;
|
|
420
504
|
}
|
|
421
505
|
}
|
|
422
506
|
// 如果找到的有内容 span 是 label,则把光标放在 label span 的后一个 span 的开头
|
|
423
|
-
if (
|
|
424
|
-
var labelIndex = allSpansNow.indexOf(
|
|
507
|
+
if (_targetSpan6 && _targetSpan6.classList.contains('formula-editor-token-label')) {
|
|
508
|
+
var labelIndex = allSpansNow.indexOf(_targetSpan6);
|
|
425
509
|
if (labelIndex < allSpansNow.length - 1) {
|
|
426
510
|
var nextSpan = allSpansNow[labelIndex + 1];
|
|
427
|
-
var
|
|
428
|
-
|
|
429
|
-
|
|
511
|
+
var _newRange2 = document.createRange();
|
|
512
|
+
_newRange2.selectNodeContents(nextSpan);
|
|
513
|
+
_newRange2.collapse(true);
|
|
430
514
|
selection.removeAllRanges();
|
|
431
|
-
selection.addRange(
|
|
515
|
+
selection.addRange(_newRange2);
|
|
432
516
|
return;
|
|
433
517
|
}
|
|
434
518
|
}
|
|
435
519
|
|
|
436
520
|
// 否则把光标放在找到的 span 的末尾
|
|
437
|
-
if (
|
|
438
|
-
var
|
|
439
|
-
|
|
440
|
-
|
|
521
|
+
if (_targetSpan6) {
|
|
522
|
+
var _newRange3 = document.createRange();
|
|
523
|
+
_newRange3.selectNodeContents(_targetSpan6);
|
|
524
|
+
_newRange3.collapse(false);
|
|
441
525
|
selection.removeAllRanges();
|
|
442
|
-
selection.addRange(
|
|
526
|
+
selection.addRange(_newRange3);
|
|
443
527
|
return;
|
|
444
528
|
}
|
|
445
529
|
}
|
|
446
530
|
if (!currentSpanNow || currentSpanNow === div) return;
|
|
447
531
|
if (currentSpanNow.textContent === '') {
|
|
448
532
|
var currentIndexNow = allSpansNow.indexOf(currentSpanNow);
|
|
449
|
-
var
|
|
533
|
+
var _newRange4 = document.createRange();
|
|
450
534
|
if (currentIndexNow > 0) {
|
|
451
535
|
// 移到前一个 span 的末尾,但如果前一个 span 是 label,则移到后一个 span 的开头
|
|
452
|
-
var
|
|
453
|
-
if (
|
|
536
|
+
var _targetSpan7 = allSpansNow[currentIndexNow - 1];
|
|
537
|
+
if (_targetSpan7.classList.contains('formula-editor-token-label')) {
|
|
454
538
|
// 移到 label span 的后一个 span 的开头
|
|
455
539
|
if (currentIndexNow < allSpansNow.length - 1) {
|
|
456
540
|
var _nextSpan = allSpansNow[currentIndexNow + 1];
|
|
457
|
-
|
|
458
|
-
|
|
541
|
+
_newRange4.selectNodeContents(_nextSpan);
|
|
542
|
+
_newRange4.collapse(true);
|
|
459
543
|
} else {
|
|
460
|
-
|
|
461
|
-
|
|
544
|
+
_newRange4.selectNodeContents(div);
|
|
545
|
+
_newRange4.collapse(false);
|
|
462
546
|
}
|
|
463
547
|
} else {
|
|
464
|
-
|
|
465
|
-
|
|
548
|
+
_newRange4.selectNodeContents(_targetSpan7);
|
|
549
|
+
_newRange4.collapse(false);
|
|
466
550
|
}
|
|
467
551
|
currentSpanNow.remove();
|
|
468
552
|
} else if (allSpansNow.length > 1) {
|
|
469
553
|
// 第一个 span 为空,移到下一个 span 的开头
|
|
470
554
|
var _nextSpan2 = allSpansNow[currentIndexNow + 1];
|
|
471
|
-
|
|
472
|
-
|
|
555
|
+
_newRange4.selectNodeContents(_nextSpan2);
|
|
556
|
+
_newRange4.collapse(true);
|
|
473
557
|
currentSpanNow.remove();
|
|
474
558
|
} else {
|
|
475
559
|
// 只有一个空 span,保持空
|
|
476
|
-
|
|
477
|
-
|
|
560
|
+
_newRange4.selectNodeContents(div);
|
|
561
|
+
_newRange4.collapse(true);
|
|
478
562
|
}
|
|
479
563
|
selection.removeAllRanges();
|
|
480
|
-
selection.addRange(
|
|
564
|
+
selection.addRange(_newRange4);
|
|
481
565
|
}
|
|
482
566
|
}, 0);
|
|
483
567
|
}, []);
|
|
568
|
+
|
|
569
|
+
// 递归渲染多级菜单
|
|
570
|
+
var renderMenuItems = function renderMenuItems(items) {
|
|
571
|
+
return items.map(function (opt) {
|
|
572
|
+
if (opt.children && opt.children.length > 0) {
|
|
573
|
+
return /*#__PURE__*/_jsx(Menu.SubMenu, {
|
|
574
|
+
title: opt.label,
|
|
575
|
+
className: "formula-editor-dropdown-submenu",
|
|
576
|
+
children: renderMenuItems(opt.children)
|
|
577
|
+
}, opt.value);
|
|
578
|
+
}
|
|
579
|
+
return /*#__PURE__*/_jsxs(Menu.Item, {
|
|
580
|
+
className: "formula-editor-dropdown-item",
|
|
581
|
+
onClick: function onClick() {
|
|
582
|
+
return handleOptionClick(opt);
|
|
583
|
+
},
|
|
584
|
+
children: [opt.label, opt.info ? /*#__PURE__*/_jsx(Tooltip, {
|
|
585
|
+
title: opt.info,
|
|
586
|
+
children: /*#__PURE__*/_jsx(InfoCircleOutlined, {
|
|
587
|
+
style: {
|
|
588
|
+
color: '#FF9900',
|
|
589
|
+
marginLeft: 4
|
|
590
|
+
}
|
|
591
|
+
})
|
|
592
|
+
}) : null]
|
|
593
|
+
}, opt.value);
|
|
594
|
+
});
|
|
595
|
+
};
|
|
484
596
|
var dropdownContent = /*#__PURE__*/_jsx(Menu, {
|
|
485
597
|
className: "formula-editor-dropdown",
|
|
486
598
|
style: {
|
|
@@ -496,36 +608,39 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options) {
|
|
|
496
608
|
className: "formula-editor-dropdown-no-data",
|
|
497
609
|
children: "\u6682\u65E0\u6570\u636E"
|
|
498
610
|
})
|
|
499
|
-
}, "no-data") : filteredHierarchyOptions
|
|
500
|
-
return opt.children && opt.children.length > 0 ? /*#__PURE__*/_jsx(Menu.SubMenu, {
|
|
501
|
-
title: opt.label,
|
|
502
|
-
className: "formula-editor-dropdown-submenu",
|
|
503
|
-
children: opt.children.map(function (child) {
|
|
504
|
-
return /*#__PURE__*/_jsx(Menu.Item, {
|
|
505
|
-
className: "formula-editor-dropdown-item",
|
|
506
|
-
onClick: function onClick() {
|
|
507
|
-
return handleOptionClick(child);
|
|
508
|
-
},
|
|
509
|
-
children: child.label
|
|
510
|
-
}, child.value);
|
|
511
|
-
})
|
|
512
|
-
}, opt.value) : /*#__PURE__*/_jsxs(Menu.Item, {
|
|
513
|
-
className: "formula-editor-dropdown-item",
|
|
514
|
-
onClick: function onClick() {
|
|
515
|
-
return handleOptionClick(opt);
|
|
516
|
-
},
|
|
517
|
-
children: [opt.label, opt.info ? /*#__PURE__*/_jsx(Tooltip, {
|
|
518
|
-
title: opt.info,
|
|
519
|
-
children: /*#__PURE__*/_jsx(InfoCircleOutlined, {
|
|
520
|
-
style: {
|
|
521
|
-
color: '#FF9900',
|
|
522
|
-
marginLeft: 4
|
|
523
|
-
}
|
|
524
|
-
})
|
|
525
|
-
}) : null]
|
|
526
|
-
}, opt.value);
|
|
527
|
-
})
|
|
611
|
+
}, "no-data") : renderMenuItems(filteredHierarchyOptions)
|
|
528
612
|
});
|
|
613
|
+
var handleChange = useCallback(function (value) {
|
|
614
|
+
onChange(!isNil(value) ? value : null);
|
|
615
|
+
}, [onChange]);
|
|
616
|
+
useEffect(function () {
|
|
617
|
+
if (isEditing) {
|
|
618
|
+
var _inputNumberRef$curre;
|
|
619
|
+
inputNumberRef === null || inputNumberRef === void 0 || (_inputNumberRef$curre = inputNumberRef.current) === null || _inputNumberRef$curre === void 0 || _inputNumberRef$curre.focus();
|
|
620
|
+
}
|
|
621
|
+
}, [isEditing]);
|
|
622
|
+
var reFocus = useCallback(function () {
|
|
623
|
+
if (isEditing) {
|
|
624
|
+
var _inputNumberRef$curre2;
|
|
625
|
+
inputNumberRef === null || inputNumberRef === void 0 || (_inputNumberRef$curre2 = inputNumberRef.current) === null || _inputNumberRef$curre2 === void 0 || _inputNumberRef$curre2.focus();
|
|
626
|
+
}
|
|
627
|
+
}, [isEditing]);
|
|
628
|
+
if (choseEditor && choseEditor(record)) {
|
|
629
|
+
var _ref3;
|
|
630
|
+
return /*#__PURE__*/_jsx(Input, _objectSpread(_objectSpread({
|
|
631
|
+
ref: inputNumberRef,
|
|
632
|
+
onBlur: reFocus
|
|
633
|
+
}, inputArgs), {}, {
|
|
634
|
+
className: "number-editor",
|
|
635
|
+
onMouseDown: function onMouseDown(e) {
|
|
636
|
+
return e.stopPropagation();
|
|
637
|
+
},
|
|
638
|
+
value: (_ref3 = originValue) !== null && _ref3 !== void 0 ? _ref3 : '',
|
|
639
|
+
onChange: function onChange(e) {
|
|
640
|
+
handleChange(e.target.value);
|
|
641
|
+
}
|
|
642
|
+
}));
|
|
643
|
+
}
|
|
529
644
|
return /*#__PURE__*/_jsx(Dropdown, {
|
|
530
645
|
overlayClassName: "dropDownOffset",
|
|
531
646
|
overlay: dropdownContent,
|
|
@@ -544,13 +659,13 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options) {
|
|
|
544
659
|
spellCheck: false,
|
|
545
660
|
children: isEmpty(tokens) ? /*#__PURE__*/_jsx("span", {
|
|
546
661
|
style: {
|
|
547
|
-
minWidth:
|
|
662
|
+
minWidth: 1,
|
|
548
663
|
height: 40
|
|
549
664
|
}
|
|
550
665
|
}) : tokens.map(function (token, index) {
|
|
551
666
|
return token.type === 'end' ? /*#__PURE__*/_jsx("span", {
|
|
552
667
|
style: {
|
|
553
|
-
minWidth:
|
|
668
|
+
minWidth: 1,
|
|
554
669
|
height: 40
|
|
555
670
|
}
|
|
556
671
|
}, index) : /*#__PURE__*/_jsx("span", {
|
|
@@ -566,22 +681,40 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options) {
|
|
|
566
681
|
var flatOptions = flattenOptions(options);
|
|
567
682
|
|
|
568
683
|
// checker:使用 validateCalculationExpr 校验语法 + 校验变量是否都在 options 中
|
|
569
|
-
FormulaInputEditor.checker = function (value) {
|
|
684
|
+
FormulaInputEditor.checker = function (value, record, currentValue) {
|
|
570
685
|
if (isNil(value)) return true;
|
|
686
|
+
if (choseEditor && choseEditor(record)) {
|
|
687
|
+
var _String;
|
|
688
|
+
var result = (_String = String(value)) === null || _String === void 0 ? void 0 : _String.replace(/,/g, '');
|
|
689
|
+
result = formulaString(result, currentValue, precision);
|
|
690
|
+
// parse number with thousands separator
|
|
691
|
+
var range = rangeMethod === null || rangeMethod === void 0 ? void 0 : rangeMethod(record);
|
|
692
|
+
if (!isNil(range === null || range === void 0 ? void 0 : range.max) && !isNil(range === null || range === void 0 ? void 0 : range.min)) {
|
|
693
|
+
var _ref4 = range || {},
|
|
694
|
+
_ref4$max = _ref4.max,
|
|
695
|
+
_max = _ref4$max === void 0 ? 0 : _ref4$max,
|
|
696
|
+
_ref4$min = _ref4.min,
|
|
697
|
+
_min = _ref4$min === void 0 ? 0 : _ref4$min;
|
|
698
|
+
if (result < _min || result > _max) {
|
|
699
|
+
warnMethod === null || warnMethod === void 0 || warnMethod(record);
|
|
700
|
+
return false;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
if (isNaN(result)) {
|
|
704
|
+
return false;
|
|
705
|
+
}
|
|
706
|
+
return true;
|
|
707
|
+
}
|
|
571
708
|
var strValue = String(value);
|
|
572
|
-
|
|
573
709
|
// 如果以 = 开头,去掉 = 后校验
|
|
574
710
|
var expr = strValue.startsWith('=') ? strValue.slice(1) : strValue;
|
|
575
711
|
var parsedExpr = replaceLabelsWithValues(expr, flatOptions);
|
|
576
|
-
|
|
577
712
|
// 空表达式不校验
|
|
578
713
|
if (!parsedExpr.trim()) return true;
|
|
579
|
-
|
|
580
714
|
// 1. 语法校验
|
|
581
715
|
if (!validateCalculationExpr(parsedExpr)) {
|
|
582
716
|
return false;
|
|
583
717
|
}
|
|
584
|
-
|
|
585
718
|
// 2. 变量校验:所有变量必须在 options 中
|
|
586
719
|
if (!validateVariables(parsedExpr, flatOptions)) {
|
|
587
720
|
return false;
|
|
@@ -590,10 +723,15 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options) {
|
|
|
590
723
|
};
|
|
591
724
|
|
|
592
725
|
// formula:校验公式,校验成功返回 currentValue
|
|
593
|
-
FormulaInputEditor.formula = function (value, currentValue) {
|
|
726
|
+
FormulaInputEditor.formula = function (value, record, currentValue) {
|
|
594
727
|
if (isNil(value)) {
|
|
595
728
|
return null;
|
|
596
729
|
}
|
|
730
|
+
if (choseEditor && choseEditor(record)) {
|
|
731
|
+
var _String2;
|
|
732
|
+
var formatValue = (_String2 = String(value)) === null || _String2 === void 0 ? void 0 : _String2.replace(/,/g, '');
|
|
733
|
+
return formulaString(formatValue, currentValue, precision, max, min, true);
|
|
734
|
+
}
|
|
597
735
|
var strValue = String(value);
|
|
598
736
|
var hasEqualSign = strValue.startsWith('=');
|
|
599
737
|
var expr = hasEqualSign ? strValue.slice(1) : strValue;
|
|
@@ -614,12 +752,21 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options) {
|
|
|
614
752
|
if (!validateVariables(expr, flatOptions)) {
|
|
615
753
|
return Infinity;
|
|
616
754
|
}
|
|
617
|
-
return
|
|
755
|
+
return value;
|
|
618
756
|
};
|
|
619
757
|
|
|
620
758
|
// parser:粘贴时处理,将 label 转换为 value
|
|
621
|
-
FormulaInputEditor.parser = function (value) {
|
|
759
|
+
FormulaInputEditor.parser = function (value, record, currentValue) {
|
|
622
760
|
if (isNil(value)) return null;
|
|
761
|
+
if (choseEditor && choseEditor(record)) {
|
|
762
|
+
var _String3;
|
|
763
|
+
var result = (_String3 = String(value)) === null || _String3 === void 0 ? void 0 : _String3.replace(/[,|%]/g, '');
|
|
764
|
+
result = formulaString(result, currentValue, precision);
|
|
765
|
+
if (isNil(result) || isNaN(result)) {
|
|
766
|
+
return null;
|
|
767
|
+
}
|
|
768
|
+
return result;
|
|
769
|
+
}
|
|
623
770
|
var strValue = String(value);
|
|
624
771
|
var hasEqualSign = strValue.startsWith('=');
|
|
625
772
|
var expr = hasEqualSign ? strValue.slice(1) : strValue;
|
|
@@ -630,15 +777,24 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options) {
|
|
|
630
777
|
};
|
|
631
778
|
|
|
632
779
|
// formatter:复制时触发,将 value 转换为 label
|
|
633
|
-
FormulaInputEditor.formatter = function (value) {
|
|
634
|
-
if (
|
|
635
|
-
|
|
780
|
+
FormulaInputEditor.formatter = function (value, record) {
|
|
781
|
+
if (choseEditor && choseEditor(record)) {
|
|
782
|
+
var _String4;
|
|
783
|
+
if (isNil(value) || isNaN(value)) {
|
|
784
|
+
return null;
|
|
785
|
+
}
|
|
786
|
+
var result = parseFloat((_String4 = String(value)) === null || _String4 === void 0 ? void 0 : _String4.replace(/,/g, ''));
|
|
787
|
+
return result;
|
|
788
|
+
}
|
|
789
|
+
var replaceValue = replaceIndex ? get(record, [replaceIndex]) : value;
|
|
790
|
+
if (isNil(replaceValue)) return null;
|
|
791
|
+
var strValue = String(replaceValue);
|
|
636
792
|
var hasEqualSign = strValue.startsWith('=');
|
|
637
793
|
var expr = hasEqualSign ? strValue.slice(1) : strValue;
|
|
638
794
|
|
|
639
795
|
// 将 value 替换为 label
|
|
640
796
|
var displayExpr = replaceValuesWithLabels(expr, flatOptions);
|
|
641
|
-
return hasEqualSign ? '=' + displayExpr
|
|
797
|
+
return hasEqualSign ? displayExpr : '=' + displayExpr;
|
|
642
798
|
};
|
|
643
799
|
return FormulaInputEditor;
|
|
644
800
|
};
|
|
@@ -4,12 +4,13 @@
|
|
|
4
4
|
white-space: nowrap;
|
|
5
5
|
overflow: hidden;
|
|
6
6
|
outline: none;
|
|
7
|
-
min-width:
|
|
7
|
+
min-width: 90%;
|
|
8
8
|
max-height: 100%;
|
|
9
9
|
box-shadow: inset 0 -100px 0 rgba(33, 133, 208, 15%);
|
|
10
10
|
position: absolute;
|
|
11
11
|
top: 0;
|
|
12
12
|
background: #fff;
|
|
13
|
+
padding-right: 8px;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
.formula-editor-equal {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { InputNumberProps } from "antd";
|
|
1
2
|
export declare const OPERATORS: string[];
|
|
2
3
|
export declare const VARIABLE_REGEX: RegExp;
|
|
3
4
|
export declare const NUMBER_REGEX: RegExp;
|
|
@@ -40,7 +41,7 @@ export declare const validateVariables: (expr: string, flatOptions: {
|
|
|
40
41
|
value: string;
|
|
41
42
|
}[]) => boolean;
|
|
42
43
|
/**
|
|
43
|
-
*
|
|
44
|
+
* 扁平化选项列表(只获取叶子节点)
|
|
44
45
|
*/
|
|
45
46
|
export declare const flattenOptions: (options: {
|
|
46
47
|
label: string;
|
|
@@ -57,3 +58,18 @@ export declare const longestCommonSubsequence: (arr1: string, arr2: string) => s
|
|
|
57
58
|
export declare const getStringDiff: (str1: any, str2: any, mode?: string) => any;
|
|
58
59
|
export declare const replaceLongestDiff: (a: string, str: string, position: number) => string;
|
|
59
60
|
export declare const getCursorPositionInSpan: (span: any) => any;
|
|
61
|
+
export interface OptionItem {
|
|
62
|
+
label: string;
|
|
63
|
+
value: string;
|
|
64
|
+
info?: string;
|
|
65
|
+
children?: OptionItem[];
|
|
66
|
+
}
|
|
67
|
+
export type inputProps = Partial<Pick<InputNumberProps, 'max' | 'min' | 'addonBefore' | 'addonAfter' | 'precision'> & {
|
|
68
|
+
warnMethod?: (record: any) => void;
|
|
69
|
+
rangeMethod?: (record: any) => {
|
|
70
|
+
max?: number;
|
|
71
|
+
min?: number;
|
|
72
|
+
};
|
|
73
|
+
}>;
|
|
74
|
+
export declare const getSpanAtCursor: (startContainer: any) => HTMLElement | null;
|
|
75
|
+
export declare const moveCursorToSpan: (targetSpan: HTMLElement, atStart: boolean | undefined, selection: any) => void;
|
|
@@ -38,7 +38,7 @@ export var replaceValuesWithLabels = function replaceValuesWithLabels(expr, flat
|
|
|
38
38
|
} finally {
|
|
39
39
|
_iterator.f();
|
|
40
40
|
}
|
|
41
|
-
return result.
|
|
41
|
+
return result.trim();
|
|
42
42
|
};
|
|
43
43
|
|
|
44
44
|
/**
|
|
@@ -115,6 +115,9 @@ var splitSegmentByLabels = function splitSegmentByLabels(segment, sortedLabels)
|
|
|
115
115
|
* 有效 label 为 type 'label',其他为 'other'
|
|
116
116
|
*/
|
|
117
117
|
export var tokenize = function tokenize(text, flatOptions) {
|
|
118
|
+
if (!text) {
|
|
119
|
+
return [];
|
|
120
|
+
}
|
|
118
121
|
var tokens = [];
|
|
119
122
|
|
|
120
123
|
// 将 value 转换为 label
|
|
@@ -204,7 +207,7 @@ export var validateVariables = function validateVariables(expr, flatOptions) {
|
|
|
204
207
|
};
|
|
205
208
|
|
|
206
209
|
/**
|
|
207
|
-
*
|
|
210
|
+
* 扁平化选项列表(只获取叶子节点)
|
|
208
211
|
*/
|
|
209
212
|
export var flattenOptions = function flattenOptions(options) {
|
|
210
213
|
var result = [];
|
|
@@ -213,12 +216,15 @@ export var flattenOptions = function flattenOptions(options) {
|
|
|
213
216
|
try {
|
|
214
217
|
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
|
|
215
218
|
var opt = _step5.value;
|
|
216
|
-
result.push({
|
|
217
|
-
label: opt.label,
|
|
218
|
-
value: opt.value
|
|
219
|
-
});
|
|
220
219
|
if (opt.children && opt.children.length > 0) {
|
|
220
|
+
// 有 children,递归获取叶子节点,不添加当前节点
|
|
221
221
|
result.push.apply(result, _toConsumableArray(flattenOptions(opt.children)));
|
|
222
|
+
} else {
|
|
223
|
+
// 没有 children,是叶子节点,添加到结果
|
|
224
|
+
result.push({
|
|
225
|
+
label: opt.label,
|
|
226
|
+
value: opt.value
|
|
227
|
+
});
|
|
222
228
|
}
|
|
223
229
|
}
|
|
224
230
|
} catch (err) {
|
|
@@ -332,4 +338,26 @@ export var getCursorPositionInSpan = function getCursorPositionInSpan(span) {
|
|
|
332
338
|
preCaretRange.selectNodeContents(span);
|
|
333
339
|
preCaretRange.setEnd(range.startContainer, range.startOffset);
|
|
334
340
|
return preCaretRange.toString().length;
|
|
341
|
+
};
|
|
342
|
+
// 获取光标所在的 span
|
|
343
|
+
export var getSpanAtCursor = function getSpanAtCursor(startContainer) {
|
|
344
|
+
if (startContainer.nodeType === Node.TEXT_NODE) {
|
|
345
|
+
return startContainer.parentElement;
|
|
346
|
+
}
|
|
347
|
+
if (startContainer.nodeType === Node.ELEMENT_NODE) {
|
|
348
|
+
return startContainer;
|
|
349
|
+
}
|
|
350
|
+
return null;
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
// 将光标移到目标 span 的开头或末尾
|
|
354
|
+
export var moveCursorToSpan = function moveCursorToSpan(targetSpan) {
|
|
355
|
+
var atStart = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
|
|
356
|
+
var selection = arguments.length > 2 ? arguments[2] : undefined;
|
|
357
|
+
if (!selection) return;
|
|
358
|
+
var newRange = document.createRange();
|
|
359
|
+
newRange.selectNodeContents(targetSpan);
|
|
360
|
+
newRange.collapse(atStart);
|
|
361
|
+
selection.removeAllRanges();
|
|
362
|
+
selection.addRange(newRange);
|
|
335
363
|
};
|
|
@@ -257,14 +257,26 @@ var Parser = /*#__PURE__*/function () {
|
|
|
257
257
|
return true;
|
|
258
258
|
}
|
|
259
259
|
|
|
260
|
-
//
|
|
261
|
-
// factor: '(' expr ')' | NUMBER | PERCENT | REFVAR
|
|
260
|
+
// 解析基本表达式(括号、数字、百分比、变量、带符号的数字)
|
|
261
|
+
// factor: '(' expr ')' | NUMBER | PERCENT | REFVAR | ('+' | '-') factor
|
|
262
|
+
// 注意:一元正负号后不能紧跟另一个一元正负号
|
|
262
263
|
}, {
|
|
263
264
|
key: "parseFactor",
|
|
264
265
|
value: function parseFactor() {
|
|
265
266
|
var token = this.currentToken();
|
|
266
267
|
if (!token) return false;
|
|
267
268
|
|
|
269
|
+
// 处理一元正负号
|
|
270
|
+
if (token.type === 'ADD' || token.type === 'SUB') {
|
|
271
|
+
this.pos++;
|
|
272
|
+
var nextToken = this.currentToken();
|
|
273
|
+
// 一元正负号后不能是另一个一元正负号
|
|
274
|
+
if (nextToken && (nextToken.type === 'ADD' || nextToken.type === 'SUB')) {
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
277
|
+
return this.parseFactor();
|
|
278
|
+
}
|
|
279
|
+
|
|
268
280
|
// 处理括号表达式
|
|
269
281
|
if (token.type === 'LPAREN') {
|
|
270
282
|
this.pos++;
|
|
@@ -9,6 +9,7 @@ type inputProps = Partial<Pick<InputNumberProps, 'max' | 'min' | 'addonBefore' |
|
|
|
9
9
|
min?: number;
|
|
10
10
|
};
|
|
11
11
|
}>;
|
|
12
|
+
export declare const formulaString: (value: unknown, currentValue: unknown, precision?: number, max?: number, min?: number, isEdit?: boolean) => unknown;
|
|
12
13
|
export declare const NumberEditor: SheetType.CellEditor;
|
|
13
14
|
export declare const getNumberEditor: (extraProps?: inputProps, getExtraProps?: ((props: SheetType.CellEditorProps) => inputProps) | undefined) => SheetType.CellEditor;
|
|
14
15
|
export {};
|
|
@@ -13,7 +13,7 @@ import { evaluate } from 'mathjs';
|
|
|
13
13
|
import { useCallback, useEffect, useRef } from 'react';
|
|
14
14
|
import "./index.less";
|
|
15
15
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
16
|
-
var formulaString = function formulaString(value, currentValue, precision, max, min, isEdit) {
|
|
16
|
+
export var formulaString = function formulaString(value, currentValue, precision, max, min, isEdit) {
|
|
17
17
|
var curNumber = currentValue !== null && currentValue !== void 0 ? currentValue : 0;
|
|
18
18
|
var headStr = head(String(value).trim());
|
|
19
19
|
var formula = String(value).replace('=', '');
|
|
@@ -106,7 +106,7 @@ export var getNumberEditor = function getNumberEditor(extraProps, getExtraProps)
|
|
|
106
106
|
}
|
|
107
107
|
}));
|
|
108
108
|
};
|
|
109
|
-
NumberEditor.formula = function (value, currentValue) {
|
|
109
|
+
NumberEditor.formula = function (value, record, currentValue) {
|
|
110
110
|
var _String;
|
|
111
111
|
if (isNil(value)) {
|
|
112
112
|
return null;
|
package/dist/core/sheet/Cell.js
CHANGED
|
@@ -78,15 +78,18 @@ var Cell = function Cell(props) {
|
|
|
78
78
|
return;
|
|
79
79
|
}
|
|
80
80
|
if (confirm) {
|
|
81
|
-
var _cell$dataEditor3;
|
|
81
|
+
var _cell$dataEditor3, _cell$dataEditor5, _cell$dataEditor6, _cell$dataEditor6$che;
|
|
82
82
|
setEventState({
|
|
83
83
|
confirm: false
|
|
84
84
|
});
|
|
85
85
|
var newValue = value;
|
|
86
|
+
if (newValue === valueRef.current) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
86
89
|
// 转化一下公式
|
|
87
90
|
if (cell !== null && cell !== void 0 && (_cell$dataEditor3 = cell.dataEditor) !== null && _cell$dataEditor3 !== void 0 && _cell$dataEditor3.formula) {
|
|
88
91
|
var _cell$dataEditor4;
|
|
89
|
-
newValue = cell === null || cell === void 0 || (_cell$dataEditor4 = cell.dataEditor) === null || _cell$dataEditor4 === void 0 ? void 0 : _cell$dataEditor4.formula(value, valueRef.current);
|
|
92
|
+
newValue = cell === null || cell === void 0 || (_cell$dataEditor4 = cell.dataEditor) === null || _cell$dataEditor4 === void 0 ? void 0 : _cell$dataEditor4.formula(value, cell.record, valueRef.current);
|
|
90
93
|
if (newValue === Infinity) {
|
|
91
94
|
antConfirm({
|
|
92
95
|
title: '公式有误',
|
|
@@ -113,20 +116,17 @@ var Cell = function Cell(props) {
|
|
|
113
116
|
return;
|
|
114
117
|
}
|
|
115
118
|
}
|
|
116
|
-
if (
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
setValue(valueRef.current);
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
eventBus.emit('cell-change', {
|
|
123
|
-
row: row,
|
|
124
|
-
col: col,
|
|
125
|
-
id: cell.id,
|
|
126
|
-
value: newValue,
|
|
127
|
-
key: cell.dataIndex
|
|
128
|
-
});
|
|
119
|
+
if (cell !== null && cell !== void 0 && (_cell$dataEditor5 = cell.dataEditor) !== null && _cell$dataEditor5 !== void 0 && _cell$dataEditor5.checker && ((_cell$dataEditor6 = cell.dataEditor) === null || _cell$dataEditor6 === void 0 || (_cell$dataEditor6$che = _cell$dataEditor6.checker) === null || _cell$dataEditor6$che === void 0 ? void 0 : _cell$dataEditor6$che.call(_cell$dataEditor6, newValue, cell.record)) === false) {
|
|
120
|
+
setValue(valueRef.current);
|
|
121
|
+
return;
|
|
129
122
|
}
|
|
123
|
+
eventBus.emit('cell-change', {
|
|
124
|
+
row: row,
|
|
125
|
+
col: col,
|
|
126
|
+
id: cell.id,
|
|
127
|
+
value: newValue,
|
|
128
|
+
key: cell.dataIndex
|
|
129
|
+
});
|
|
130
130
|
}
|
|
131
131
|
}, [confirm, eventBus, value, cell]);
|
|
132
132
|
var handleCommit = useCallback(function (value) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SheetTableType } from "../..";
|
|
2
2
|
export declare const useRowSelection: (dataSource: Record<string, unknown>[], rowSelection?: SheetTableType.TableRowSelection, hasChildren?: boolean) => [boolean[], (value: boolean[]) => void];
|
|
3
|
-
export declare const formatSelectionData: (param: Pick<SheetTableType.TableProps, "columns" | "
|
|
3
|
+
export declare const formatSelectionData: (param: Pick<SheetTableType.TableProps, "columns" | "showRemark" | "rowSelection" | "dataSource" | "rowKey"> & {
|
|
4
4
|
checked: boolean[];
|
|
5
5
|
}) => any[][];
|
package/dist/example/basic.js
CHANGED
|
@@ -67,8 +67,7 @@ var columns = [{
|
|
|
67
67
|
})
|
|
68
68
|
}, {
|
|
69
69
|
title: 'Formula',
|
|
70
|
-
dataIndex: '
|
|
71
|
-
key: 'formula',
|
|
70
|
+
dataIndex: 'amount',
|
|
72
71
|
width: 200,
|
|
73
72
|
cellConfig: {
|
|
74
73
|
className: 'testCell'
|
|
@@ -93,7 +92,7 @@ var columns = [{
|
|
|
93
92
|
label: '批发价',
|
|
94
93
|
value: 'wholesale'
|
|
95
94
|
}]
|
|
96
|
-
}])
|
|
95
|
+
}], 'formula')
|
|
97
96
|
}, {
|
|
98
97
|
title: 'Address',
|
|
99
98
|
editable: false,
|
|
@@ -142,17 +141,20 @@ var data = [{
|
|
|
142
141
|
age: 32,
|
|
143
142
|
address: 'New York No. 1 Lake Park',
|
|
144
143
|
tags: ['nice', 'developer'],
|
|
145
|
-
formula: '=price*qty'
|
|
144
|
+
formula: '=price*qty',
|
|
145
|
+
amount: 100
|
|
146
146
|
}, {
|
|
147
147
|
key: '2',
|
|
148
148
|
name: 'Jim Green',
|
|
149
149
|
age: 42,
|
|
150
150
|
address: 'London No. 1 Lake Park',
|
|
151
151
|
tags: ['loser'],
|
|
152
|
-
formula: '=price+discount'
|
|
152
|
+
formula: '=price+discount',
|
|
153
|
+
amount: 100
|
|
153
154
|
}, {
|
|
154
155
|
key: '3',
|
|
155
156
|
name: 'Joe Black',
|
|
157
|
+
amount: 100,
|
|
156
158
|
age: 32,
|
|
157
159
|
address: 'Sidney No. 1 Lake Park',
|
|
158
160
|
tags: ['cool', 'teacher'],
|
|
@@ -163,14 +165,24 @@ var data = [{
|
|
|
163
165
|
age: 92,
|
|
164
166
|
address: 'Sidney No. 1 Lake Park',
|
|
165
167
|
tags: ['cool', 'teacher'],
|
|
166
|
-
formula: '=(123 + 456) * price'
|
|
168
|
+
formula: '=(123 + 456) * price',
|
|
169
|
+
amount: 100
|
|
167
170
|
}, {
|
|
168
171
|
key: '5',
|
|
169
172
|
name: 'Joe ll',
|
|
170
173
|
age: 37,
|
|
171
174
|
address: 'Sidney No. 1 Lake Park',
|
|
172
175
|
tags: ['cool', 'teacher'],
|
|
173
|
-
formula: '=(123 + 456) * price + 888'
|
|
176
|
+
formula: '=(123 + 456) * price + 888',
|
|
177
|
+
amount: 100
|
|
178
|
+
}, {
|
|
179
|
+
key: '6',
|
|
180
|
+
name: 'Joe 23',
|
|
181
|
+
age: 41,
|
|
182
|
+
address: 'Sidney No. 1 Lake Park',
|
|
183
|
+
tags: ['cool', 'teacher'],
|
|
184
|
+
formula: '=(123 + -456) * price *-discount',
|
|
185
|
+
amount: 100
|
|
174
186
|
}];
|
|
175
187
|
var App = function App() {
|
|
176
188
|
var _useState = useState(data),
|