@zhenliang/sheet 0.2.5-beta.6 → 0.2.5-beta.9

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.
@@ -1,18 +1,5 @@
1
1
  import type { SheetType } from "../../../type";
2
- import { InputNumberProps } from 'antd';
3
2
  import './index.less';
4
- export interface OptionItem {
5
- label: string;
6
- value: string;
7
- info?: string;
8
- children?: OptionItem[];
9
- }
10
- type inputProps = Partial<Pick<InputNumberProps, 'max' | 'min' | 'addonBefore' | 'addonAfter' | 'precision'> & {
11
- warnMethod?: (record: any) => void;
12
- rangeMethod?: (record: any) => {
13
- max?: number;
14
- min?: number;
15
- };
16
- }>;
3
+ import { OptionItem, inputProps } from './utils';
17
4
  export declare const getFormulaInputEditor: (options: OptionItem[], replaceIndex?: string, extraProps?: inputProps, getExtraProps?: ((props: SheetType.CellEditorProps) => inputProps) | undefined, choseEditor?: ((record: any) => boolean) | undefined) => SheetType.CellEditor;
18
5
  export default getFormulaInputEditor;
@@ -18,22 +18,28 @@ import { get, head, isEmpty, isNil } from 'lodash';
18
18
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
19
19
  import { formulaString } from "../numberEditor";
20
20
  import "./index.less";
21
- import { flattenOptions, getCursorPositionInSpan, getStringDiff, replaceLabelsWithValues, replaceLongestDiff, replaceValuesWithLabels, tokenize, validateVariables } from "./utils";
21
+ import { flattenOptions, getCursorPositionInSpan, getSpanAtCursor, getStringDiff, moveCursorToSpan, replaceLabelsWithValues, replaceLongestDiff, replaceValuesWithLabels, tokenize, validateVariables } from "./utils";
22
22
  import validateCalculationExpr from "./vaildFormula";
23
23
  import { jsx as _jsx } from "react/jsx-runtime";
24
24
  import { jsxs as _jsxs } from "react/jsx-runtime";
25
- var OPERATORS = ['=', '+', '-', '*', '/'];
26
-
27
- // 获取光标所在的 span
28
- var getSpanAtCursor = function getSpanAtCursor(startContainer) {
29
- if (startContainer.nodeType === Node.TEXT_NODE) {
30
- return startContainer.parentElement;
31
- }
32
- if (startContainer.nodeType === Node.ELEMENT_NODE) {
33
- return startContainer;
34
- }
35
- return null;
36
- };
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
+
37
43
  export var getFormulaInputEditor = function getFormulaInputEditor(options, replaceIndex, extraProps, getExtraProps, choseEditor) {
38
44
  var _ref = extraProps || {},
39
45
  warnMethod = _ref.warnMethod,
@@ -74,6 +80,7 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options, repla
74
80
  _useState10 = _slicedToArray(_useState9, 2),
75
81
  inputAfterDropDownShow = _useState10[0],
76
82
  setInputAfterDropDownShow = _useState10[1];
83
+ var tempSpanRef = useRef(null);
77
84
  var containerRef = useRef(null);
78
85
  var inputOperatorPosition = useRef(0);
79
86
 
@@ -123,23 +130,56 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options, repla
123
130
  useEffect(function () {
124
131
  if (!open) {
125
132
  containerValueSnapShot.current = '';
133
+ tempSpanRef.current = null;
126
134
  }
127
135
  setInputAfterDropDownShow('');
128
136
  }, [open]);
137
+ var closeDorpDown = useCallback(function () {
138
+ setInputAfterDropDownShow('');
139
+ tempSpanRef.current = null;
140
+ // 点击div内直接关闭
141
+ setOpen(false);
142
+ }, []);
129
143
 
130
- // 处理选项点击:删除用户刚输入的值,将选中的 label 放到运算符后面
144
+ // 处理选项点击
131
145
  var handleOptionClick = useCallback(function (opt) {
132
146
  var container = containerRef.current;
133
147
  if (!container) return;
134
- var newValue = replaceLongestDiff(containerValueSnapShot.current, opt.label, inputOperatorPosition.current);
135
148
  setOpen(false);
136
149
  containerValueSnapShot.current = '';
137
- var expr = newValue;
138
- var valueExpr = replaceLabelsWithValues(expr, flatOptions);
139
- setContainerValue(valueExpr);
140
- onChange(valueExpr);
141
150
 
142
- // 获取当前光标所在的 span
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);
168
+
169
+ // 更新 containerValue
170
+ var newValue = container.textContent || '';
171
+ var valueExpr = replaceLabelsWithValues(newValue, flatOptions);
172
+ setContainerValue(valueExpr);
173
+ onChange(valueExpr);
174
+ return;
175
+ }
176
+
177
+ // 原逻辑:删除 inputAfterDropDownShow,插入新 label
178
+ var newValueUser = replaceLongestDiff(containerValueSnapShot.current, opt.label, inputOperatorPosition.current);
179
+ var expr = newValueUser;
180
+ var valueExprUser = replaceLabelsWithValues(expr, flatOptions);
181
+ setContainerValue(valueExprUser);
182
+ onChange(valueExprUser);
143
183
  var selection = window.getSelection();
144
184
  if (!selection || selection.rangeCount === 0) return;
145
185
  var range = selection.getRangeAt(0);
@@ -194,19 +234,16 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options, repla
194
234
  targetSpan.textContent = '';
195
235
  labelSpan.after(targetSpan);
196
236
  }
197
-
198
- // 将光标移到目标 span 的开头
199
- var newRange = document.createRange();
200
- newRange.selectNodeContents(targetSpan);
201
- newRange.collapse(true);
202
- selection.removeAllRanges();
203
- selection.addRange(newRange);
237
+ moveCursorToSpan(targetSpan);
204
238
  }, [inputAfterDropDownShow]);
205
239
 
206
240
  // 处理输入变化
207
241
  var handleInput = useCallback(function () {
208
242
  var container = containerRef.current;
209
243
  if (!container) return;
244
+ if (tempSpanRef.current) {
245
+ closeDorpDown();
246
+ }
210
247
  var newValue = container.textContent || '';
211
248
  var processedValue = newValue;
212
249
  var expr = processedValue;
@@ -267,12 +304,8 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options, repla
267
304
  (_containerRef$current2 = containerRef.current) === null || _containerRef$current2 === void 0 || _containerRef$current2.focus();
268
305
  }
269
306
  }, [isEditing]);
270
- var closeDorpDown = useCallback(function () {
271
- // 点击div内直接关闭
272
- setOpen(false);
273
- }, []);
274
307
 
275
- // 鼠标释放时,如果光标在 label span 内,移动到后一个 span 的开头
308
+ // 鼠标释放时,如果光标在 label span 内,打开下拉框并记录 tempSpan
276
309
  var handleMouseUp = useCallback(function () {
277
310
  var div = containerRef.current;
278
311
  if (!div) return;
@@ -285,8 +318,20 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options, repla
285
318
  if (!currentSpan || currentSpan === div) return;
286
319
  var isLabelSpan = currentSpan.classList.contains('formula-editor-token-label');
287
320
 
288
- // 如果在 label span 内,移动到下一个 span 的开头
321
+ // 如果在 label span 内,打开下拉框并记录 tempSpan
289
322
  if (isLabelSpan) {
323
+ // 更新 offsetX 位置
324
+ var containerRect = div.getBoundingClientRect();
325
+ var cursorRect = range.getBoundingClientRect();
326
+ var cursorDistance = cursorRect ? cursorRect.left - containerRect.left : 0;
327
+ setOffsetX(cursorDistance < 150 ? 0 : cursorDistance - 8);
328
+
329
+ // 记录当前 label span 作为 tempSpan
330
+ tempSpanRef.current = currentSpan;
331
+
332
+ // 打开下拉框
333
+ setOpen(true);
334
+ // 移动到下一个 span 的开头
290
335
  var allSpans = Array.from(div.querySelectorAll('span'));
291
336
  var currentIndex = allSpans.indexOf(currentSpan);
292
337
  if (currentIndex < allSpans.length - 1) {
@@ -298,7 +343,7 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options, repla
298
343
  selection.addRange(newRange);
299
344
  }
300
345
  }
301
- }, [closeDorpDown]);
346
+ }, [closeDorpDown, setOffsetX, setOpen]);
302
347
  var handleKeyDown = useCallback(function (e) {
303
348
  var _currentSpan$textCont, _currentSpan$textCont2;
304
349
  if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
@@ -321,13 +366,13 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options, repla
321
366
 
322
367
  // 方向键:跳过 label span
323
368
  if (e.key === 'ArrowRight' || e.key === 'ArrowLeft') {
324
- closeDorpDown();
325
369
  var position = getCursorPositionInSpan(currentSpan);
326
370
  var isAtEnd = startOffset >= textLen;
327
371
  var isAtStart = startOffset === 0;
328
372
  var isAlmostEnd = startOffset >= textLen - 1;
329
373
  var isAlmostStart = position === 1;
330
374
  if (e.key === 'ArrowRight' && isAtEnd) {
375
+ closeDorpDown();
331
376
  // 向右 + 在末尾 -> 跳到下一个 span 的开头(跳过 label span)
332
377
  var targetIndex = currentIndex + 1;
333
378
  while (targetIndex < allSpans.length && allSpans[targetIndex].classList.contains('formula-editor-token-label')) {
@@ -336,48 +381,35 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options, repla
336
381
  if (targetIndex < allSpans.length && targetIndex !== currentIndex + 1) {
337
382
  e.preventDefault();
338
383
  var targetSpan = allSpans[targetIndex];
339
- var newRange = document.createRange();
340
- newRange.selectNodeContents(targetSpan);
341
- newRange.collapse(true);
342
- selection.removeAllRanges();
343
- selection.addRange(newRange);
384
+ moveCursorToSpan(targetSpan);
385
+ }
386
+ } else if (e.key === 'ArrowRight' && isAlmostEnd) {
387
+ closeDorpDown();
388
+ var _targetIndex = currentIndex + 1;
389
+ if (_targetIndex < allSpans.length && !allSpans[_targetIndex].classList.contains('formula-editor-token-label')) {
390
+ e.preventDefault();
391
+ var _targetSpan2 = allSpans[_targetIndex];
392
+ moveCursorToSpan(_targetSpan2);
344
393
  }
345
394
  } else if (e.key === 'ArrowLeft' && isAtStart) {
395
+ closeDorpDown();
346
396
  // 向左 + 在开头 -> 跳到上一个 span 的末尾(跳过 label span)
347
- var _targetIndex = currentIndex - 1;
348
- while (_targetIndex >= 0 && allSpans[_targetIndex].classList.contains('formula-editor-token-label')) {
349
- _targetIndex--;
397
+ var _targetIndex2 = currentIndex - 1;
398
+ while (_targetIndex2 >= 0 && allSpans[_targetIndex2].classList.contains('formula-editor-token-label')) {
399
+ _targetIndex2--;
350
400
  }
351
- if (_targetIndex >= 0 && _targetIndex !== currentIndex - 1) {
352
- e.preventDefault();
353
- var _targetSpan = allSpans[_targetIndex];
354
- var _newRange = document.createRange();
355
- _newRange.selectNodeContents(_targetSpan);
356
- _newRange.collapse(false);
357
- selection.removeAllRanges();
358
- selection.addRange(_newRange);
359
- }
360
- } else if (e.key === 'ArrowRight' && isAlmostEnd) {
361
- var _targetIndex2 = currentIndex + 1;
362
- if (_targetIndex2 < allSpans.length && !allSpans[_targetIndex2].classList.contains('formula-editor-token-label')) {
401
+ if (_targetIndex2 >= 0 && _targetIndex2 !== currentIndex - 1) {
363
402
  e.preventDefault();
364
- var _targetSpan2 = allSpans[_targetIndex2];
365
- var _newRange2 = document.createRange();
366
- _newRange2.selectNodeContents(_targetSpan2);
367
- _newRange2.collapse(true);
368
- selection.removeAllRanges();
369
- selection.addRange(_newRange2);
403
+ var _targetSpan3 = allSpans[_targetIndex2];
404
+ moveCursorToSpan(_targetSpan3, false);
370
405
  }
371
406
  } else if (e.key === 'ArrowLeft' && isAlmostStart) {
407
+ closeDorpDown();
372
408
  var _targetIndex3 = currentIndex - 1;
373
409
  if (_targetIndex3 >= 0 && !allSpans[_targetIndex3].classList.contains('formula-editor-token-label')) {
374
410
  e.preventDefault();
375
- var _targetSpan3 = allSpans[_targetIndex3];
376
- var _newRange3 = document.createRange();
377
- _newRange3.selectNodeContents(_targetSpan3);
378
- _newRange3.collapse(false);
379
- selection.removeAllRanges();
380
- selection.addRange(_newRange3);
411
+ var _targetSpan4 = allSpans[_targetIndex3];
412
+ moveCursorToSpan(_targetSpan4, false);
381
413
  }
382
414
  }
383
415
  return;
@@ -385,7 +417,10 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options, repla
385
417
 
386
418
  // 删除键逻辑
387
419
  if (e.key !== 'Delete' && e.key !== 'Backspace') return;
388
- if (e.key === 'Backspace') {
420
+ if (e.key === 'Backspace' || e.key === 'Delete') {
421
+ if (tempSpanRef.current) {
422
+ closeDorpDown();
423
+ }
389
424
  // 检查删除后是否只剩一个空的 span
390
425
  var allSpansNow = Array.from(div.querySelectorAll('span'));
391
426
  var isOnlyOneEmptySpan = allSpansNow.length === 1 && allSpansNow[0].textContent === '';
@@ -403,31 +438,31 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options, repla
403
438
  e.preventDefault();
404
439
  e.stopPropagation();
405
440
  prevSpan.remove();
406
- var _newRange4 = document.createRange();
441
+ var newRange = document.createRange();
407
442
 
408
443
  // 如果当前 span 有内容,光标放在开头;否则找最近的有内容的 span
409
444
  if (currentSpan.textContent !== '') {
410
- _newRange4.selectNodeContents(currentSpan);
411
- _newRange4.collapse(true);
445
+ newRange.selectNodeContents(currentSpan);
446
+ newRange.collapse(true);
412
447
  } else {
413
448
  // 找前一个最近的有内容的 span
414
- var _targetSpan4;
449
+ var _targetSpan5;
415
450
  for (var i = currentIndex - 2; i >= 0; i--) {
416
451
  if (allSpans[i].textContent !== '') {
417
- _targetSpan4 = allSpans[i];
452
+ _targetSpan5 = allSpans[i];
418
453
  break;
419
454
  }
420
455
  }
421
- if (_targetSpan4) {
422
- _newRange4.selectNodeContents(_targetSpan4);
423
- _newRange4.collapse(false);
456
+ if (_targetSpan5) {
457
+ newRange.selectNodeContents(_targetSpan5);
458
+ newRange.collapse(false);
424
459
  } else {
425
- _newRange4.selectNodeContents(div);
426
- _newRange4.collapse(true);
460
+ newRange.selectNodeContents(div);
461
+ newRange.collapse(true);
427
462
  }
428
463
  }
429
464
  selection.removeAllRanges();
430
- selection.addRange(_newRange4);
465
+ selection.addRange(newRange);
431
466
  return;
432
467
  }
433
468
  }
@@ -443,11 +478,11 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options, repla
443
478
  if (prevText.length > 0) {
444
479
  _prevSpan.textContent = prevText.slice(0, -1);
445
480
  }
446
- var _newRange5 = document.createRange();
447
- _newRange5.selectNodeContents(_prevSpan);
448
- _newRange5.collapse(false);
481
+ var _newRange = document.createRange();
482
+ _newRange.selectNodeContents(_prevSpan);
483
+ _newRange.collapse(false);
449
484
  selection.removeAllRanges();
450
- selection.addRange(_newRange5);
485
+ selection.addRange(_newRange);
451
486
  }
452
487
  }
453
488
 
@@ -462,73 +497,73 @@ export var getFormulaInputEditor = function getFormulaInputEditor(options, repla
462
497
  // 如果光标在 span 开头 + Delete 键,currentIndex 指向的是被删 span 的后一个,所以要 -1
463
498
  var searchIndex = startOffset === 0 ? currentIndex - 1 : currentIndex;
464
499
  // 从 searchIndex 位置往前找
465
- var _targetSpan5;
500
+ var _targetSpan6;
466
501
  for (var _i = searchIndex; _i >= 0; _i--) {
467
502
  var span = allSpansNow[_i];
468
503
  if (span.textContent !== '') {
469
- _targetSpan5 = span;
504
+ _targetSpan6 = span;
470
505
  break;
471
506
  }
472
507
  }
473
508
  // 如果找到的有内容 span 是 label,则把光标放在 label span 的后一个 span 的开头
474
- if (_targetSpan5 && _targetSpan5.classList.contains('formula-editor-token-label')) {
475
- var labelIndex = allSpansNow.indexOf(_targetSpan5);
509
+ if (_targetSpan6 && _targetSpan6.classList.contains('formula-editor-token-label')) {
510
+ var labelIndex = allSpansNow.indexOf(_targetSpan6);
476
511
  if (labelIndex < allSpansNow.length - 1) {
477
512
  var nextSpan = allSpansNow[labelIndex + 1];
478
- var _newRange6 = document.createRange();
479
- _newRange6.selectNodeContents(nextSpan);
480
- _newRange6.collapse(true);
513
+ var _newRange2 = document.createRange();
514
+ _newRange2.selectNodeContents(nextSpan);
515
+ _newRange2.collapse(true);
481
516
  selection.removeAllRanges();
482
- selection.addRange(_newRange6);
517
+ selection.addRange(_newRange2);
483
518
  return;
484
519
  }
485
520
  }
486
521
 
487
522
  // 否则把光标放在找到的 span 的末尾
488
- if (_targetSpan5) {
489
- var _newRange7 = document.createRange();
490
- _newRange7.selectNodeContents(_targetSpan5);
491
- _newRange7.collapse(false);
523
+ if (_targetSpan6) {
524
+ var _newRange3 = document.createRange();
525
+ _newRange3.selectNodeContents(_targetSpan6);
526
+ _newRange3.collapse(false);
492
527
  selection.removeAllRanges();
493
- selection.addRange(_newRange7);
528
+ selection.addRange(_newRange3);
494
529
  return;
495
530
  }
496
531
  }
497
532
  if (!currentSpanNow || currentSpanNow === div) return;
498
533
  if (currentSpanNow.textContent === '') {
499
534
  var currentIndexNow = allSpansNow.indexOf(currentSpanNow);
500
- var _newRange8 = document.createRange();
535
+ var _newRange4 = document.createRange();
501
536
  if (currentIndexNow > 0) {
502
537
  // 移到前一个 span 的末尾,但如果前一个 span 是 label,则移到后一个 span 的开头
503
- var _targetSpan6 = allSpansNow[currentIndexNow - 1];
504
- if (_targetSpan6.classList.contains('formula-editor-token-label')) {
538
+ var _targetSpan7 = allSpansNow[currentIndexNow - 1];
539
+ if (_targetSpan7.classList.contains('formula-editor-token-label')) {
505
540
  // 移到 label span 的后一个 span 的开头
506
541
  if (currentIndexNow < allSpansNow.length - 1) {
507
542
  var _nextSpan = allSpansNow[currentIndexNow + 1];
508
- _newRange8.selectNodeContents(_nextSpan);
509
- _newRange8.collapse(true);
543
+ _newRange4.selectNodeContents(_nextSpan);
544
+ _newRange4.collapse(true);
510
545
  } else {
511
- _newRange8.selectNodeContents(div);
512
- _newRange8.collapse(false);
546
+ _newRange4.selectNodeContents(div);
547
+ _newRange4.collapse(false);
513
548
  }
514
549
  } else {
515
- _newRange8.selectNodeContents(_targetSpan6);
516
- _newRange8.collapse(false);
550
+ _newRange4.selectNodeContents(_targetSpan7);
551
+ _newRange4.collapse(false);
517
552
  }
518
553
  currentSpanNow.remove();
519
554
  } else if (allSpansNow.length > 1) {
520
555
  // 第一个 span 为空,移到下一个 span 的开头
521
556
  var _nextSpan2 = allSpansNow[currentIndexNow + 1];
522
- _newRange8.selectNodeContents(_nextSpan2);
523
- _newRange8.collapse(true);
557
+ _newRange4.selectNodeContents(_nextSpan2);
558
+ _newRange4.collapse(true);
524
559
  currentSpanNow.remove();
525
560
  } else {
526
561
  // 只有一个空 span,保持空
527
- _newRange8.selectNodeContents(div);
528
- _newRange8.collapse(true);
562
+ _newRange4.selectNodeContents(div);
563
+ _newRange4.collapse(true);
529
564
  }
530
565
  selection.removeAllRanges();
531
- selection.addRange(_newRange8);
566
+ selection.addRange(_newRange4);
532
567
  }
533
568
  }, 0);
534
569
  }, []);
@@ -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;
@@ -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) => void;
@@ -338,4 +338,26 @@ export var getCursorPositionInSpan = function getCursorPositionInSpan(span) {
338
338
  preCaretRange.selectNodeContents(span);
339
339
  preCaretRange.setEnd(range.startContainer, range.startOffset);
340
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 = window.getSelection();
357
+ if (!selection) return;
358
+ var newRange = document.createRange();
359
+ newRange.selectNodeContents(targetSpan);
360
+ newRange.collapse(atStart);
361
+ selection.removeAllRanges();
362
+ selection.addRange(newRange);
341
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++;
@@ -181,7 +181,7 @@ var data = [{
181
181
  age: 41,
182
182
  address: 'Sidney No. 1 Lake Park',
183
183
  tags: ['cool', 'teacher'],
184
- formula: null,
184
+ formula: '=(123 + -456) * price *-discount',
185
185
  amount: 100
186
186
  }];
187
187
  var App = function App() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhenliang/sheet",
3
- "version": "0.2.5-beta.6",
3
+ "version": "0.2.5-beta.9",
4
4
  "description": "A react library developed with dumi",
5
5
  "license": "MIT",
6
6
  "module": "dist/index.js",