@zhenliang/sheet 0.2.5-beta.1 → 0.2.5-beta.11

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.
@@ -4,12 +4,13 @@
4
4
  white-space: nowrap;
5
5
  overflow: hidden;
6
6
  outline: none;
7
- min-width: 95%;
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 {
@@ -0,0 +1,16 @@
1
+ import type { KeyboardEvent as ReactKeyboardEvent } from 'react';
2
+ import { OptionItem } from './utils';
3
+ declare const useKeyEventEffect: ({ closeDorpDown, setOffsetX, setOpen, containerRef, tempSpanRef, inputAfterDropDownShow, options }: {
4
+ closeDorpDown: () => void;
5
+ setOffsetX: (value: React.SetStateAction<number>) => void;
6
+ setOpen: (value: React.SetStateAction<boolean>) => void;
7
+ containerRef: React.RefObject<HTMLDivElement>;
8
+ tempSpanRef: React.MutableRefObject<HTMLElement | null>;
9
+ inputAfterDropDownShow: string;
10
+ options: OptionItem[];
11
+ }) => {
12
+ handleMouseUp: () => void;
13
+ handleKeyDown: (e: ReactKeyboardEvent<HTMLDivElement>) => void;
14
+ filteredHierarchyOptions: OptionItem[];
15
+ };
16
+ export { useKeyEventEffect };
@@ -0,0 +1,305 @@
1
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
2
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
+ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
5
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
6
+ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
7
+ function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
8
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
9
+ 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; }
10
+ import { useCallback, useMemo } from 'react';
11
+ import { getCursorPositionInSpan, getSpanAtCursor, moveCursorToSpan } from "./utils";
12
+ var useKeyEventEffect = function useKeyEventEffect(_ref) {
13
+ var closeDorpDown = _ref.closeDorpDown,
14
+ setOffsetX = _ref.setOffsetX,
15
+ setOpen = _ref.setOpen,
16
+ containerRef = _ref.containerRef,
17
+ tempSpanRef = _ref.tempSpanRef,
18
+ inputAfterDropDownShow = _ref.inputAfterDropDownShow,
19
+ options = _ref.options;
20
+ // 鼠标释放时,如果光标在 label span 内,打开下拉框并记录 tempSpan
21
+ var handleMouseUp = useCallback(function () {
22
+ var div = containerRef.current;
23
+ if (!div) return;
24
+ closeDorpDown();
25
+ var selection = window.getSelection();
26
+ if (!selection || selection.rangeCount === 0) return;
27
+ var range = selection.getRangeAt(0);
28
+ var startContainer = range.startContainer;
29
+ var currentSpan = getSpanAtCursor(startContainer);
30
+ if (!currentSpan || currentSpan === div) return;
31
+ var isLabelSpan = currentSpan.classList.contains('formula-editor-token-label');
32
+
33
+ // 如果在 label span 内,打开下拉框并记录 tempSpan
34
+ if (isLabelSpan) {
35
+ // 更新 offsetX 位置
36
+ var containerRect = div.getBoundingClientRect();
37
+ var cursorRect = range.getBoundingClientRect();
38
+ var cursorDistance = cursorRect ? cursorRect.left - containerRect.left : 0;
39
+ setOffsetX(cursorDistance < 150 ? 0 : cursorDistance - 8);
40
+
41
+ // 记录当前 label span 作为 tempSpan
42
+ tempSpanRef.current = currentSpan;
43
+
44
+ // 打开下拉框
45
+ setOpen(true);
46
+ // 移动到下一个 span 的开头
47
+ var allSpans = Array.from(div.querySelectorAll('span'));
48
+ var currentIndex = allSpans.indexOf(currentSpan);
49
+ if (currentIndex < allSpans.length - 1) {
50
+ var nextSpan = allSpans[currentIndex + 1];
51
+ moveCursorToSpan(nextSpan, true, selection);
52
+ }
53
+ }
54
+ }, [closeDorpDown, setOffsetX, setOpen]);
55
+ var handleKeyDown = useCallback(function (e) {
56
+ var _currentSpan$textCont, _currentSpan$textCont2;
57
+ if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
58
+ e.preventDefault();
59
+ e.stopPropagation();
60
+ return;
61
+ }
62
+ var div = containerRef.current;
63
+ if (!div) return;
64
+ var selection = window.getSelection();
65
+ if (!selection || selection.rangeCount === 0) return;
66
+ var range = selection.getRangeAt(0);
67
+ var startContainer = range.startContainer,
68
+ startOffset = range.startOffset;
69
+ var currentSpan = getSpanAtCursor(startContainer);
70
+ if (!currentSpan || currentSpan === div) return;
71
+ var allSpans = Array.from(div.querySelectorAll('span'));
72
+ var currentIndex = allSpans.indexOf(currentSpan);
73
+ var textLen = (_currentSpan$textCont = (_currentSpan$textCont2 = currentSpan.textContent) === null || _currentSpan$textCont2 === void 0 ? void 0 : _currentSpan$textCont2.length) !== null && _currentSpan$textCont !== void 0 ? _currentSpan$textCont : 0;
74
+
75
+ // 方向键:跳过 label span
76
+ if (e.key === 'ArrowRight' || e.key === 'ArrowLeft') {
77
+ var position = getCursorPositionInSpan(currentSpan);
78
+ var isAtEnd = startOffset >= textLen;
79
+ var isAtStart = startOffset === 0;
80
+ var isAlmostEnd = startOffset >= textLen - 1;
81
+ var isAlmostStart = position === 1;
82
+ if (e.key === 'ArrowRight' && isAtEnd) {
83
+ closeDorpDown();
84
+ // 向右 + 在末尾 -> 跳到下一个 span 的开头(跳过 label span)
85
+ var targetIndex = currentIndex + 1;
86
+ while (targetIndex < allSpans.length && allSpans[targetIndex].classList.contains('formula-editor-token-label')) {
87
+ targetIndex++;
88
+ }
89
+ if (targetIndex < allSpans.length && targetIndex !== currentIndex + 1) {
90
+ e.preventDefault();
91
+ var targetSpan = allSpans[targetIndex];
92
+ moveCursorToSpan(targetSpan, true, selection);
93
+ }
94
+ } else if (e.key === 'ArrowRight' && isAlmostEnd) {
95
+ closeDorpDown();
96
+ var _targetIndex = currentIndex + 1;
97
+ if (_targetIndex < allSpans.length && !allSpans[_targetIndex].classList.contains('formula-editor-token-label')) {
98
+ e.preventDefault();
99
+ var _targetSpan = allSpans[_targetIndex];
100
+ moveCursorToSpan(_targetSpan, true, selection);
101
+ }
102
+ } else if (e.key === 'ArrowLeft' && isAtStart) {
103
+ closeDorpDown();
104
+ // 向左 + 在开头 -> 跳到上一个 span 的末尾(跳过 label span)
105
+ var _targetIndex2 = currentIndex - 1;
106
+ while (_targetIndex2 >= 0 && allSpans[_targetIndex2].classList.contains('formula-editor-token-label')) {
107
+ _targetIndex2--;
108
+ }
109
+ if (_targetIndex2 >= 0 && _targetIndex2 !== currentIndex - 1) {
110
+ e.preventDefault();
111
+ var _targetSpan2 = allSpans[_targetIndex2];
112
+ moveCursorToSpan(_targetSpan2, false, selection);
113
+ }
114
+ } else if (e.key === 'ArrowLeft' && isAlmostStart) {
115
+ closeDorpDown();
116
+ var _targetIndex3 = currentIndex - 1;
117
+ if (_targetIndex3 >= 0 && !allSpans[_targetIndex3].classList.contains('formula-editor-token-label')) {
118
+ e.preventDefault();
119
+ var _targetSpan3 = allSpans[_targetIndex3];
120
+ moveCursorToSpan(_targetSpan3, false, selection);
121
+ }
122
+ }
123
+ return;
124
+ }
125
+
126
+ // 删除键逻辑
127
+ if (e.key !== 'Delete' && e.key !== 'Backspace') return;
128
+ if (e.key === 'Backspace' || e.key === 'Delete') {
129
+ if (tempSpanRef.current) {
130
+ closeDorpDown();
131
+ }
132
+ // 检查删除后是否只剩一个空的 span
133
+ var allSpansNow = Array.from(div.querySelectorAll('span'));
134
+ var isOnlyOneEmptySpan = allSpansNow.length === 1 && allSpansNow[0].textContent === '';
135
+ if (isOnlyOneEmptySpan) {
136
+ e.preventDefault();
137
+ e.stopPropagation();
138
+ return;
139
+ }
140
+ }
141
+
142
+ // 不在 label span 内,在 span 开头且前一个是 label 时,删除整个 label span
143
+ if (startOffset === 0 && e.key === 'Backspace' && currentIndex > 0) {
144
+ var prevSpan = allSpans[currentIndex - 1];
145
+ if (prevSpan.classList.contains('formula-editor-token-label')) {
146
+ e.preventDefault();
147
+ e.stopPropagation();
148
+ prevSpan.remove();
149
+ var newRange = document.createRange();
150
+
151
+ // 如果当前 span 有内容,光标放在开头;否则找最近的有内容的 span
152
+ if (currentSpan.textContent !== '') {
153
+ newRange.selectNodeContents(currentSpan);
154
+ newRange.collapse(true);
155
+ } else {
156
+ // 找前一个最近的有内容的 span
157
+ var _targetSpan4;
158
+ for (var i = currentIndex - 2; i >= 0; i--) {
159
+ if (allSpans[i].textContent !== '') {
160
+ _targetSpan4 = allSpans[i];
161
+ break;
162
+ }
163
+ }
164
+ if (_targetSpan4) {
165
+ newRange.selectNodeContents(_targetSpan4);
166
+ newRange.collapse(false);
167
+ } else {
168
+ newRange.selectNodeContents(div);
169
+ newRange.collapse(true);
170
+ }
171
+ }
172
+ selection.removeAllRanges();
173
+ selection.addRange(newRange);
174
+ return;
175
+ }
176
+ }
177
+
178
+ // 在 span 开头 + Delete 键,光标移到前一个 span 的末尾
179
+ if (startOffset === 0 && e.key === 'Backspace' && currentIndex > 0) {
180
+ var _prevSpan = allSpans[currentIndex - 1];
181
+ // 前一个 span 是非 label span 时,光标移到其末尾
182
+ if (!_prevSpan.classList.contains('formula-editor-token-label')) {
183
+ e.preventDefault();
184
+ e.stopPropagation();
185
+ var prevText = _prevSpan.textContent || '';
186
+ if (prevText.length > 0) {
187
+ _prevSpan.textContent = prevText.slice(0, -1);
188
+ }
189
+ moveCursorToSpan(_prevSpan, false, selection);
190
+ }
191
+ }
192
+
193
+ // 其他情况:等待浏览器完成默认删除后,检查当前 span 是否为空
194
+ setTimeout(function () {
195
+ var currentSpanNow = getSpanAtCursor(startContainer);
196
+ var allSpansNow = Array.from(div.querySelectorAll('span'));
197
+
198
+ // 如果 currentSpanNow 不在 allSpansNow 里(被浏览器删除了)
199
+ // 且还有 span 存在,用按下删除键时的 currentSpan 位置往前找
200
+ if (allSpansNow.length > 0 && !allSpansNow.includes(currentSpanNow)) {
201
+ // 如果光标在 span 开头 + Delete 键,currentIndex 指向的是被删 span 的后一个,所以要 -1
202
+ var searchIndex = startOffset === 0 ? currentIndex - 1 : currentIndex;
203
+ // 从 searchIndex 位置往前找
204
+ var _targetSpan5;
205
+ for (var _i = searchIndex; _i >= 0; _i--) {
206
+ var span = allSpansNow[_i];
207
+ if (span.textContent !== '') {
208
+ _targetSpan5 = span;
209
+ break;
210
+ }
211
+ }
212
+ // 如果找到的有内容 span 是 label,则把光标放在 label span 的后一个 span 的开头
213
+ if (_targetSpan5 && _targetSpan5.classList.contains('formula-editor-token-label')) {
214
+ var labelIndex = allSpansNow.indexOf(_targetSpan5);
215
+ if (labelIndex < allSpansNow.length - 1) {
216
+ var nextSpan = allSpansNow[labelIndex + 1];
217
+ moveCursorToSpan(nextSpan, true, selection);
218
+ return;
219
+ }
220
+ }
221
+
222
+ // 否则把光标放在找到的 span 的末尾
223
+ if (_targetSpan5) {
224
+ moveCursorToSpan(_targetSpan5, false, selection);
225
+ return;
226
+ }
227
+ }
228
+ if (!currentSpanNow || currentSpanNow === div) return;
229
+ if (currentSpanNow.textContent === '') {
230
+ var currentIndexNow = allSpansNow.indexOf(currentSpanNow);
231
+ var _newRange = document.createRange();
232
+ if (currentIndexNow > 0) {
233
+ // 移到前一个 span 的末尾,但如果前一个 span 是 label,则移到后一个 span 的开头
234
+ var _targetSpan6 = allSpansNow[currentIndexNow - 1];
235
+ if (_targetSpan6.classList.contains('formula-editor-token-label')) {
236
+ // 移到 label span 的后一个 span 的开头
237
+ if (currentIndexNow < allSpansNow.length - 1) {
238
+ var _nextSpan = allSpansNow[currentIndexNow + 1];
239
+ _newRange.selectNodeContents(_nextSpan);
240
+ _newRange.collapse(true);
241
+ } else {
242
+ _newRange.selectNodeContents(div);
243
+ _newRange.collapse(false);
244
+ }
245
+ } else {
246
+ _newRange.selectNodeContents(_targetSpan6);
247
+ _newRange.collapse(false);
248
+ }
249
+ currentSpanNow.remove();
250
+ } else if (allSpansNow.length > 1) {
251
+ // 第一个 span 为空,移到下一个 span 的开头
252
+ var _nextSpan2 = allSpansNow[currentIndexNow + 1];
253
+ _newRange.selectNodeContents(_nextSpan2);
254
+ _newRange.collapse(true);
255
+ currentSpanNow.remove();
256
+ } else {
257
+ // 只有一个空 span,保持空
258
+ _newRange.selectNodeContents(div);
259
+ _newRange.collapse(true);
260
+ }
261
+ selection.removeAllRanges();
262
+ selection.addRange(_newRange);
263
+ }
264
+ }, 0);
265
+ }, [closeDorpDown, containerRef.current]);
266
+ var filteredHierarchyOptions = useMemo(function () {
267
+ var searchText = inputAfterDropDownShow.trim();
268
+ // 如果搜索文本为空,显示所有选项(保持层级)
269
+ if (!searchText) {
270
+ return options;
271
+ }
272
+
273
+ // 根据搜索文本筛选,保持层级结构
274
+ var filterWithHierarchy = function filterWithHierarchy(items) {
275
+ var result = [];
276
+ var _iterator = _createForOfIteratorHelper(items),
277
+ _step;
278
+ try {
279
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
280
+ var item = _step.value;
281
+ var labelMatch = item.label.includes(searchText);
282
+ // 筛选 children
283
+ var filteredChildren = item.children ? filterWithHierarchy(item.children) : [];
284
+ if (labelMatch || filteredChildren.length > 0) {
285
+ result.push(_objectSpread(_objectSpread({}, item), {}, {
286
+ children: filteredChildren.length > 0 ? filteredChildren : item.children
287
+ }));
288
+ }
289
+ }
290
+ } catch (err) {
291
+ _iterator.e(err);
292
+ } finally {
293
+ _iterator.f();
294
+ }
295
+ return result;
296
+ };
297
+ return filterWithHierarchy(options);
298
+ }, [inputAfterDropDownShow]);
299
+ return {
300
+ handleMouseUp: handleMouseUp,
301
+ handleKeyDown: handleKeyDown,
302
+ filteredHierarchyOptions: filteredHierarchyOptions
303
+ };
304
+ };
305
+ export { useKeyEventEffect };
@@ -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
- * 扁平化选项列表(将 children 展开)
44
+ * 扁平化选项列表(只获取叶子节点)
44
45
  */
45
46
  export declare const flattenOptions: (options: {
46
47
  label: string;
@@ -57,3 +58,23 @@ 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;
76
+ export declare enum SpanType {
77
+ LABEL = "label",
78
+ OTHER = "other"
79
+ }
80
+ export declare const createSpan: (type: string, content: string) => HTMLElement;
@@ -5,6 +5,8 @@ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o =
5
5
  function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
6
6
  function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
7
7
  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; }
8
+ import { get } from "lodash";
9
+
8
10
  // 运算符列表
9
11
  export var OPERATORS = ['+', '-', '*', '/'];
10
12
 
@@ -38,7 +40,7 @@ export var replaceValuesWithLabels = function replaceValuesWithLabels(expr, flat
38
40
  } finally {
39
41
  _iterator.f();
40
42
  }
41
- return result.replace(/\s/g, '');
43
+ return result.trim();
42
44
  };
43
45
 
44
46
  /**
@@ -115,6 +117,9 @@ var splitSegmentByLabels = function splitSegmentByLabels(segment, sortedLabels)
115
117
  * 有效 label 为 type 'label',其他为 'other'
116
118
  */
117
119
  export var tokenize = function tokenize(text, flatOptions) {
120
+ if (!text) {
121
+ return [];
122
+ }
118
123
  var tokens = [];
119
124
 
120
125
  // 将 value 转换为 label
@@ -204,7 +209,7 @@ export var validateVariables = function validateVariables(expr, flatOptions) {
204
209
  };
205
210
 
206
211
  /**
207
- * 扁平化选项列表(将 children 展开)
212
+ * 扁平化选项列表(只获取叶子节点)
208
213
  */
209
214
  export var flattenOptions = function flattenOptions(options) {
210
215
  var result = [];
@@ -213,12 +218,15 @@ export var flattenOptions = function flattenOptions(options) {
213
218
  try {
214
219
  for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
215
220
  var opt = _step5.value;
216
- result.push({
217
- label: opt.label,
218
- value: opt.value
219
- });
220
221
  if (opt.children && opt.children.length > 0) {
222
+ // 有 children,递归获取叶子节点,不添加当前节点
221
223
  result.push.apply(result, _toConsumableArray(flattenOptions(opt.children)));
224
+ } else {
225
+ // 没有 children,是叶子节点,添加到结果
226
+ result.push({
227
+ label: opt.label,
228
+ value: opt.value
229
+ });
222
230
  }
223
231
  }
224
232
  } catch (err) {
@@ -332,4 +340,41 @@ export var getCursorPositionInSpan = function getCursorPositionInSpan(span) {
332
340
  preCaretRange.selectNodeContents(span);
333
341
  preCaretRange.setEnd(range.startContainer, range.startOffset);
334
342
  return preCaretRange.toString().length;
343
+ };
344
+ // 获取光标所在的 span
345
+ export var getSpanAtCursor = function getSpanAtCursor(startContainer) {
346
+ if (startContainer.nodeType === Node.TEXT_NODE) {
347
+ return startContainer.parentElement;
348
+ }
349
+ if (startContainer.nodeType === Node.ELEMENT_NODE) {
350
+ return startContainer;
351
+ }
352
+ return null;
353
+ };
354
+
355
+ // 将光标移到目标 span 的开头或末尾
356
+ export var moveCursorToSpan = function moveCursorToSpan(targetSpan) {
357
+ var atStart = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
358
+ var selection = arguments.length > 2 ? arguments[2] : undefined;
359
+ if (!selection) return;
360
+ var newRange = document.createRange();
361
+ newRange.selectNodeContents(targetSpan);
362
+ newRange.collapse(atStart);
363
+ selection.removeAllRanges();
364
+ selection.addRange(newRange);
365
+ };
366
+ export var SpanType = /*#__PURE__*/function (SpanType) {
367
+ SpanType["LABEL"] = "label";
368
+ SpanType["OTHER"] = "other";
369
+ return SpanType;
370
+ }({});
371
+ var spanTypeStyle = {
372
+ label: 'formula-editor-token-label',
373
+ other: 'formula-editor-token-other'
374
+ };
375
+ export var createSpan = function createSpan(type, content) {
376
+ var span = document.createElement('span');
377
+ span.className = get(spanTypeStyle, [type]);
378
+ span.textContent = content;
379
+ return span;
335
380
  };
@@ -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;
@@ -89,7 +89,7 @@ var Cell = function Cell(props) {
89
89
  // 转化一下公式
90
90
  if (cell !== null && cell !== void 0 && (_cell$dataEditor3 = cell.dataEditor) !== null && _cell$dataEditor3 !== void 0 && _cell$dataEditor3.formula) {
91
91
  var _cell$dataEditor4;
92
- 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);
93
93
  if (newValue === Infinity) {
94
94
  antConfirm({
95
95
  title: '公式有误',
@@ -175,6 +175,14 @@ var data = [{
175
175
  tags: ['cool', 'teacher'],
176
176
  formula: '=(123 + 456) * price + 888',
177
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
178
186
  }];
179
187
  var App = function App() {
180
188
  var _useState = useState(data),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhenliang/sheet",
3
- "version": "0.2.5-beta.1",
3
+ "version": "0.2.5-beta.11",
4
4
  "description": "A react library developed with dumi",
5
5
  "license": "MIT",
6
6
  "module": "dist/index.js",