@zhenliang/sheet 0.2.4 → 0.2.5-beta.1

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.
@@ -0,0 +1,333 @@
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 _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
3
+ function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
4
+ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
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
+ /**
8
+ * 词法分析器:分词
9
+ */
10
+ var Lexer = /*#__PURE__*/function () {
11
+ function Lexer(input) {
12
+ _classCallCheck(this, Lexer);
13
+ this.input = input;
14
+ this.pos = 0;
15
+ this.tokens = [];
16
+ }
17
+
18
+ // 词法规则:NUMBER
19
+ _createClass(Lexer, [{
20
+ key: "isNumberStart",
21
+ value: function isNumberStart(char) {
22
+ return char >= '0' && char <= '9';
23
+ }
24
+ }, {
25
+ key: "isDigit",
26
+ value: function isDigit(char) {
27
+ return char >= '0' && char <= '9';
28
+ }
29
+
30
+ // 词法规则:REFVAR
31
+ }, {
32
+ key: "isIdentifierStart",
33
+ value: function isIdentifierStart(char) {
34
+ return char >= 'a' && char <= 'z' || char >= 'A' && char <= 'Z' || char === '_';
35
+ }
36
+ }, {
37
+ key: "isIdentifierChar",
38
+ value: function isIdentifierChar(char) {
39
+ return this.isIdentifierStart(char) || this.isDigit(char);
40
+ }
41
+
42
+ // 词法规则:PERCENT
43
+ }, {
44
+ key: "isPercent",
45
+ value: function isPercent(char) {
46
+ return char === '%';
47
+ }
48
+
49
+ // 执行词法分析
50
+ }, {
51
+ key: "tokenize",
52
+ value: function tokenize() {
53
+ while (this.pos < this.input.length) {
54
+ var char = this.input[this.pos];
55
+
56
+ // 跳过空白字符
57
+ if (char === ' ' || char === '\t' || char === '\r' || char === '\n') {
58
+ this.pos++;
59
+ continue;
60
+ }
61
+
62
+ // 尝试解析 NUMBER 或 PERCENT
63
+ if (this.isNumberStart(char)) {
64
+ var start = this.pos;
65
+ var hasDecimal = false;
66
+
67
+ // 匹配整数部分
68
+ if (char === '0') {
69
+ this.pos++;
70
+ } else {
71
+ while (this.pos < this.input.length && this.isDigit(this.input[this.pos])) {
72
+ this.pos++;
73
+ }
74
+ }
75
+
76
+ // 匹配小数部分
77
+ if (this.pos < this.input.length && this.input[this.pos] === '.') {
78
+ hasDecimal = true;
79
+ this.pos++;
80
+ if (this.pos < this.input.length && this.isDigit(this.input[this.pos])) {
81
+ while (this.pos < this.input.length && this.isDigit(this.input[this.pos])) {
82
+ this.pos++;
83
+ }
84
+ } else {
85
+ // 小数点后没有数字,语法错误
86
+ this.pos = start + 1; // 回退到起始位置之后
87
+ return false;
88
+ }
89
+ }
90
+
91
+ // 检查是否是 PERCENT
92
+ if (this.pos < this.input.length && this.input[this.pos] === '%') {
93
+ this.tokens.push({
94
+ type: 'PERCENT',
95
+ value: this.input.substring(start, this.pos + 1)
96
+ });
97
+ this.pos++;
98
+ } else {
99
+ this.tokens.push({
100
+ type: 'NUMBER',
101
+ value: this.input.substring(start, this.pos)
102
+ });
103
+ }
104
+ continue;
105
+ }
106
+
107
+ // 尝试解析 REFVAR
108
+ if (this.isIdentifierStart(char)) {
109
+ var _start = this.pos;
110
+ while (this.pos < this.input.length && this.isIdentifierChar(this.input[this.pos])) {
111
+ this.pos++;
112
+ }
113
+ this.tokens.push({
114
+ type: 'REFVAR',
115
+ value: this.input.substring(_start, this.pos)
116
+ });
117
+ continue;
118
+ }
119
+
120
+ // 解析运算符
121
+ if (char === '(') {
122
+ this.tokens.push({
123
+ type: 'LPAREN',
124
+ value: '('
125
+ });
126
+ this.pos++;
127
+ continue;
128
+ }
129
+ if (char === ')') {
130
+ this.tokens.push({
131
+ type: 'RPAREN',
132
+ value: ')'
133
+ });
134
+ this.pos++;
135
+ continue;
136
+ }
137
+ if (char === '*') {
138
+ this.tokens.push({
139
+ type: 'MUL',
140
+ value: '*'
141
+ });
142
+ this.pos++;
143
+ continue;
144
+ }
145
+ if (char === '/') {
146
+ this.tokens.push({
147
+ type: 'DIV',
148
+ value: '/'
149
+ });
150
+ this.pos++;
151
+ continue;
152
+ }
153
+ if (char === '+') {
154
+ this.tokens.push({
155
+ type: 'ADD',
156
+ value: '+'
157
+ });
158
+ this.pos++;
159
+ continue;
160
+ }
161
+ if (char === '-') {
162
+ this.tokens.push({
163
+ type: 'SUB',
164
+ value: '-'
165
+ });
166
+ this.pos++;
167
+ continue;
168
+ }
169
+
170
+ // 无法识别的字符
171
+ return false;
172
+ }
173
+ return true;
174
+ }
175
+ }, {
176
+ key: "getTokens",
177
+ value: function getTokens() {
178
+ return this.tokens;
179
+ }
180
+ }]);
181
+ return Lexer;
182
+ }();
183
+ /**
184
+ * 语法分析器:递归下降解析器
185
+ * 实现标准优先级爬山算法处理运算符优先级
186
+ */
187
+ var Parser = /*#__PURE__*/function () {
188
+ function Parser(tokens) {
189
+ _classCallCheck(this, Parser);
190
+ this.tokens = tokens;
191
+ this.pos = 0;
192
+ }
193
+
194
+ // prog: expr EOF
195
+ _createClass(Parser, [{
196
+ key: "parseProg",
197
+ value: function parseProg() {
198
+ var result = this.parseExpr();
199
+ if (!result) return false;
200
+
201
+ // 检查是否解析完所有 token
202
+ return this.pos >= this.tokens.length;
203
+ }
204
+
205
+ // 入口表达式解析(处理最低优先级的加减运算)
206
+ }, {
207
+ key: "parseExpr",
208
+ value: function parseExpr() {
209
+ return this.parseAddSub();
210
+ }
211
+
212
+ // 解析加减表达式(优先级低于乘除)
213
+ // expr: expr ('+' | '-') expr | term
214
+ }, {
215
+ key: "parseAddSub",
216
+ value: function parseAddSub() {
217
+ // 先解析左操作数
218
+ var left = this.parseMulDiv();
219
+ if (!left) return false;
220
+
221
+ // 用循环处理多个连续的加减运算符
222
+ while (true) {
223
+ var token = this.currentToken();
224
+ if (token && (token.type === 'ADD' || token.type === 'SUB')) {
225
+ this.pos++;
226
+ // 解析右操作数(使用更高优先级的规则)
227
+ var right = this.parseMulDiv();
228
+ if (!right) return false;
229
+ } else {
230
+ break;
231
+ }
232
+ }
233
+ return true;
234
+ }
235
+
236
+ // 解析乘除表达式(优先级高于加减)
237
+ // term: term ('*' | '/') factor | factor
238
+ }, {
239
+ key: "parseMulDiv",
240
+ value: function parseMulDiv() {
241
+ // 先解析左操作数
242
+ var left = this.parseFactor();
243
+ if (!left) return false;
244
+
245
+ // 用循环处理多个连续的乘除运算符
246
+ while (true) {
247
+ var token = this.currentToken();
248
+ if (token && (token.type === 'MUL' || token.type === 'DIV')) {
249
+ this.pos++;
250
+ // 解析右操作数
251
+ var right = this.parseFactor();
252
+ if (!right) return false;
253
+ } else {
254
+ break;
255
+ }
256
+ }
257
+ return true;
258
+ }
259
+
260
+ // 解析基本表达式(括号、数字、百分比、变量)
261
+ // factor: '(' expr ')' | NUMBER | PERCENT | REFVAR
262
+ }, {
263
+ key: "parseFactor",
264
+ value: function parseFactor() {
265
+ var token = this.currentToken();
266
+ if (!token) return false;
267
+
268
+ // 处理括号表达式
269
+ if (token.type === 'LPAREN') {
270
+ this.pos++;
271
+ var exprResult = this.parseExpr();
272
+ if (!exprResult) return false;
273
+ var closeToken = this.currentToken();
274
+ if (!closeToken || closeToken.type !== 'RPAREN') return false;
275
+ this.pos++;
276
+ return true;
277
+ }
278
+
279
+ // 处理数字
280
+ if (token.type === 'NUMBER') {
281
+ this.pos++;
282
+ return true;
283
+ }
284
+
285
+ // 处理百分比数字
286
+ if (token.type === 'PERCENT') {
287
+ this.pos++;
288
+ return true;
289
+ }
290
+
291
+ // 处理引用变量
292
+ if (token.type === 'REFVAR') {
293
+ this.pos++;
294
+ return true;
295
+ }
296
+ return false;
297
+ }
298
+ }, {
299
+ key: "currentToken",
300
+ value: function currentToken() {
301
+ return this.tokens[this.pos];
302
+ }
303
+ }]);
304
+ return Parser;
305
+ }();
306
+ /**
307
+ * 校验主函数
308
+ * @param {string} input - 要校验的表达式字符串
309
+ * @returns {boolean} - 校验通过返回 true,失败返回 false
310
+ */
311
+ function validateCalculationExpr(input) {
312
+ // 输入验证
313
+ if (!input || typeof input !== 'string') {
314
+ return false;
315
+ }
316
+
317
+ // 词法分析
318
+ var lexer = new Lexer(input);
319
+ if (!lexer.tokenize()) {
320
+ return false;
321
+ }
322
+ var tokens = lexer.getTokens();
323
+
324
+ // 检查是否有有效 token
325
+ if (tokens.length === 0) {
326
+ return false;
327
+ }
328
+
329
+ // 语法分析
330
+ var parser = new Parser(tokens);
331
+ return parser.parseProg();
332
+ }
333
+ export default validateCalculationExpr;
@@ -3,3 +3,4 @@ export { getDateEditor } from './dateEditor';
3
3
  export { getNumberEditor, NumberEditor } from './numberEditor';
4
4
  export { default as getSelectEditor } from './selectEditor';
5
5
  export { default as getInputSelectEditor } from './inputSelectEditor/inputSelect';
6
+ export { default as getFormulaInputEditor } from './InputOptionsEditor';
@@ -2,4 +2,5 @@ export { default as getCascaderEditor } from "./cascaderEditor";
2
2
  export { getDateEditor } from "./dateEditor";
3
3
  export { getNumberEditor, NumberEditor } from "./numberEditor";
4
4
  export { default as getSelectEditor } from "./selectEditor";
5
- export { default as getInputSelectEditor } from "./inputSelectEditor/inputSelect";
5
+ export { default as getInputSelectEditor } from "./inputSelectEditor/inputSelect";
6
+ export { default as getFormulaInputEditor } from "./InputOptionsEditor";
@@ -78,11 +78,14 @@ 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;
@@ -113,20 +116,17 @@ var Cell = function Cell(props) {
113
116
  return;
114
117
  }
115
118
  }
116
- if (newValue !== valueRef.current) {
117
- var _cell$dataEditor5, _cell$dataEditor6, _cell$dataEditor6$che;
118
- 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) {
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,4 +1,5 @@
1
1
  import 'antd/dist/antd.css';
2
2
  import React from 'react';
3
+ import './index.less';
3
4
  declare const App: React.FC;
4
5
  export default App;
@@ -14,10 +14,11 @@ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o =
14
14
  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; }
15
15
  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; } }
16
16
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
17
- import { Table, getNumberEditor, getInputSelectEditor } from "./..";
18
- import { Space, Tag, Select } from 'antd';
17
+ import { Table, getFormulaInputEditor, getInputSelectEditor, getNumberEditor } from "./..";
18
+ import { Select, Space, Tag } from 'antd';
19
19
  import 'antd/dist/antd.css';
20
20
  import React, { useCallback, useState } from 'react';
21
+ import "./index.less";
21
22
  import { jsx as _jsx } from "react/jsx-runtime";
22
23
  import { Fragment as _Fragment } from "react/jsx-runtime";
23
24
  import { jsxs as _jsxs } from "react/jsx-runtime";
@@ -64,6 +65,34 @@ var columns = [{
64
65
  min: 0,
65
66
  precision: 2
66
67
  })
68
+ }, {
69
+ title: 'Formula',
70
+ dataIndex: 'amount',
71
+ width: 200,
72
+ cellConfig: {
73
+ className: 'testCell'
74
+ },
75
+ editor: getFormulaInputEditor([{
76
+ label: '单价',
77
+ value: 'price'
78
+ }, {
79
+ label: '数量',
80
+ value: 'qty'
81
+ }, {
82
+ label: '折扣',
83
+ value: 'discount',
84
+ info: '注意这个有点皮'
85
+ }, {
86
+ label: '价格相关',
87
+ value: 'priceGroup',
88
+ children: [{
89
+ label: '成本价',
90
+ value: 'cost'
91
+ }, {
92
+ label: '批发价',
93
+ value: 'wholesale'
94
+ }]
95
+ }], 'formula')
67
96
  }, {
68
97
  title: 'Address',
69
98
  editable: false,
@@ -111,19 +140,41 @@ var data = [{
111
140
  name: 'John Brown',
112
141
  age: 32,
113
142
  address: 'New York No. 1 Lake Park',
114
- tags: ['nice', 'developer']
143
+ tags: ['nice', 'developer'],
144
+ formula: '=price*qty',
145
+ amount: 100
115
146
  }, {
116
147
  key: '2',
117
148
  name: 'Jim Green',
118
149
  age: 42,
119
150
  address: 'London No. 1 Lake Park',
120
- tags: ['loser']
151
+ tags: ['loser'],
152
+ formula: '=price+discount',
153
+ amount: 100
121
154
  }, {
122
155
  key: '3',
123
156
  name: 'Joe Black',
157
+ amount: 100,
124
158
  age: 32,
125
159
  address: 'Sidney No. 1 Lake Park',
126
- tags: ['cool', 'teacher']
160
+ tags: ['cool', 'teacher'],
161
+ formula: '=123* 4569797 * discount*123* 4569797 * discount*123* 4569797 * discount*123* 4569797 * discount*123* 4569797 * discount*123* 4569797 * discount*123* 4569797 * discount'
162
+ }, {
163
+ key: '4',
164
+ name: 'Joe ll',
165
+ age: 92,
166
+ address: 'Sidney No. 1 Lake Park',
167
+ tags: ['cool', 'teacher'],
168
+ formula: '=(123 + 456) * price',
169
+ amount: 100
170
+ }, {
171
+ key: '5',
172
+ name: 'Joe ll',
173
+ age: 37,
174
+ address: 'Sidney No. 1 Lake Park',
175
+ tags: ['cool', 'teacher'],
176
+ formula: '=(123 + 456) * price + 888',
177
+ amount: 100
127
178
  }];
128
179
  var App = function App() {
129
180
  var _useState = useState(data),
@@ -1,5 +1,8 @@
1
- .excel-sheet{
2
- --row-height:30px;
3
- --line-height:30px;
1
+ .excel-sheet {
2
+ --row-height: 30px;
3
+ --line-height: 30px;
4
4
  --cell-inner-height: 29px;
5
- }
5
+ }
6
+ .testCell {
7
+ position: relative !important;
8
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhenliang/sheet",
3
- "version": "0.2.4",
3
+ "version": "0.2.5-beta.1",
4
4
  "description": "A react library developed with dumi",
5
5
  "license": "MIT",
6
6
  "module": "dist/index.js",