@hzab/edit-table 0.0.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.
- package/CHANGELOG.md +3 -0
- package/README.md +76 -0
- package/package.json +59 -0
- package/src/Template/ExpandListTemplate/index.less +18 -0
- package/src/Template/ExpandListTemplate/index.tsx +65 -0
- package/src/Template/GetBaseTemplate.tsx +32 -0
- package/src/Template/NumberCellTemplate.tsx +168 -0
- package/src/Template/TextCellTemplate.tsx +123 -0
- package/src/Template/utils.ts +288 -0
- package/src/common/WidthWrapHoc.tsx +215 -0
- package/src/common/childAntdComponent.ts +14 -0
- package/src/common/test.ts +3 -0
- package/src/common/utils.ts +288 -0
- package/src/index.less +35 -0
- package/src/index.tsx +364 -0
package/CHANGELOG.md
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# @hzab/edit-table
|
|
2
|
+
|
|
3
|
+
组件模板
|
|
4
|
+
|
|
5
|
+
- node@16.16.0
|
|
6
|
+
|
|
7
|
+
- 注意:首次克隆先执行 npm run prepare 命令
|
|
8
|
+
|
|
9
|
+
# 组件
|
|
10
|
+
|
|
11
|
+
## 示例
|
|
12
|
+
|
|
13
|
+
```jsx
|
|
14
|
+
import Demo from "@hzab/edit-table";
|
|
15
|
+
|
|
16
|
+
<Demo />;
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## API
|
|
20
|
+
|
|
21
|
+
### InfoPanel Attributes
|
|
22
|
+
|
|
23
|
+
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|
|
24
|
+
| ------ | ------ | ---- | ------ | ----------------- |
|
|
25
|
+
| schema | Object | 是 | - | 数据信息的 schema |
|
|
26
|
+
|
|
27
|
+
# 组件开发流程
|
|
28
|
+
|
|
29
|
+
- 在 config/webpack.config.js 中按需修改 library 配置的文件名
|
|
30
|
+
- 在 config/webpack.config.js 中按需修改 alias 配置的包名,便于本地调试
|
|
31
|
+
- 在 tsconfig.json 中按需修改 paths 配置的包名,解决 ts 报错问题
|
|
32
|
+
- npm run dev
|
|
33
|
+
|
|
34
|
+
## 文件目录
|
|
35
|
+
|
|
36
|
+
- example 本地开发测试代码
|
|
37
|
+
- src 组件源码
|
|
38
|
+
|
|
39
|
+
## 命令
|
|
40
|
+
|
|
41
|
+
- Mac 执行该命令,设置 pre-commit 为可执行文件
|
|
42
|
+
- npm run mac-chmod
|
|
43
|
+
- chmod +x .husky && chmod +x .husky/pre-commit
|
|
44
|
+
|
|
45
|
+
- 生成文档:npm run docs
|
|
46
|
+
- 本地运行:npm run dev
|
|
47
|
+
|
|
48
|
+
## 发布
|
|
49
|
+
|
|
50
|
+
- npm 源和云效源都需要发布
|
|
51
|
+
|
|
52
|
+
- 命令:npm publish --access public
|
|
53
|
+
- 发布目录:
|
|
54
|
+
- src
|
|
55
|
+
|
|
56
|
+
### nrm
|
|
57
|
+
|
|
58
|
+
- 安装
|
|
59
|
+
npm install -g nrm
|
|
60
|
+
- 增加源
|
|
61
|
+
nrm add aliyun https://packages.aliyun.com/62046985b3ead41b374a17f7/npm/npm-registry/
|
|
62
|
+
- 切换源
|
|
63
|
+
nrm use aliyun
|
|
64
|
+
nrm use npm
|
|
65
|
+
- 登录(账号密码在 https://packages.aliyun.com/npm/npm-registry/guide 查看)
|
|
66
|
+
npm login --registry=https://packages.aliyun.com/62046985b3ead41b374a17f7/npm/npm-registry/
|
|
67
|
+
|
|
68
|
+
## 配置
|
|
69
|
+
|
|
70
|
+
### 配置文件
|
|
71
|
+
|
|
72
|
+
- 本地配置文件:config/config.js
|
|
73
|
+
|
|
74
|
+
### webpack 配置文件
|
|
75
|
+
|
|
76
|
+
- config/webpack.config.js
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hzab/edit-table",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "src",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "webpack serve -c ./config/webpack.config.js --env local",
|
|
8
|
+
"build": "webpack -c ./config/webpack.config.js --env production",
|
|
9
|
+
"version:alpha": "npm version prerelease --preid=alpha",
|
|
10
|
+
"publish:alpha": "npm publish --tag alpha",
|
|
11
|
+
"version:beta": "npm version prerelease --preid=beta",
|
|
12
|
+
"publish:beta": "npm publish --tag beta",
|
|
13
|
+
"version:patch": "npm version patch",
|
|
14
|
+
"version:minior": "npm version minor",
|
|
15
|
+
"version:major": "npm version major",
|
|
16
|
+
"publish:stable": "npm publish --access public",
|
|
17
|
+
"prepare": "husky install",
|
|
18
|
+
"mac-chmod": "chmod +x .husky && chmod +x .husky/pre-commit",
|
|
19
|
+
"docs": "typedoc"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"src",
|
|
23
|
+
"CHANGELOG.md"
|
|
24
|
+
],
|
|
25
|
+
"keywords": [],
|
|
26
|
+
"author": "CaiYansong",
|
|
27
|
+
"license": "ISC",
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@hzab/permissions": "1.0.0",
|
|
30
|
+
"@hzab/webpack-config": "1.1.4",
|
|
31
|
+
"@types/react": "17.0.62",
|
|
32
|
+
"@types/react-dom": "17.0.20",
|
|
33
|
+
"antd": "4.24.16",
|
|
34
|
+
"axios": "1.13.6",
|
|
35
|
+
"eslint": "8.30.0",
|
|
36
|
+
"less": "4.1.3",
|
|
37
|
+
"mobx": "6.7.0",
|
|
38
|
+
"mobx-react": "7.6.0",
|
|
39
|
+
"react": "17.0.2",
|
|
40
|
+
"react-dom": "17.0.2",
|
|
41
|
+
"react-router-dom": "6.14.1",
|
|
42
|
+
"typedoc": "0.24.8",
|
|
43
|
+
"typescript": "4.9.4",
|
|
44
|
+
"webpack": "5.75.0"
|
|
45
|
+
},
|
|
46
|
+
"directories": {
|
|
47
|
+
"src": "src"
|
|
48
|
+
},
|
|
49
|
+
"lint-staged": {
|
|
50
|
+
"**.{js,jsx,ts,tsx,css,scss,less,json,html}": [
|
|
51
|
+
"prettier --write"
|
|
52
|
+
]
|
|
53
|
+
},
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"@hzab/form-render": "^1.7.17",
|
|
56
|
+
"@hzab/list-render": "^1.11.0",
|
|
57
|
+
"@silevis/reactgrid": "^4.1.17"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
.expandList-template {
|
|
2
|
+
display: flex;
|
|
3
|
+
align-items: center;
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
.expandList-template-icon {
|
|
8
|
+
cursor: pointer;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.expandList-template-name {
|
|
12
|
+
margin-left: 8px;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.expandList-template-indent {
|
|
16
|
+
margin-left: 32px;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { MinusCircleOutlined, MinusSquareOutlined, PlusCircleOutlined } from "@ant-design/icons";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import "./index.less";
|
|
4
|
+
|
|
5
|
+
export const ExpandListTemplate = (props) => {
|
|
6
|
+
const { cell } = props;
|
|
7
|
+
const { Slots, setExpandKeys, expandKeys, rowKey, setNewDataSource, record, columnId } = cell;
|
|
8
|
+
const [expand, setExpand] = useState<boolean>(false);
|
|
9
|
+
const onExpand = (isExpand) => {
|
|
10
|
+
setNewDataSource((pre) => {
|
|
11
|
+
const tempPre = [...pre];
|
|
12
|
+
const childrenIds = record?.children?.map((el) => el?.[rowKey]);
|
|
13
|
+
if (isExpand) {
|
|
14
|
+
const findIndex = pre?.findIndex((el) => el?.[rowKey] == record?.[rowKey]);
|
|
15
|
+
const filterList = pre?.filter((el) => childrenIds?.includes(el?.[rowKey])) || [];
|
|
16
|
+
if (filterList?.length == 0) {
|
|
17
|
+
tempPre.splice(findIndex + 1, 0, ...(record?.children || []));
|
|
18
|
+
}
|
|
19
|
+
return [...tempPre];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return pre?.filter((el) => !childrenIds?.includes(el?.[rowKey]));
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (expandKeys?.includes(record?.[rowKey])) {
|
|
27
|
+
setExpand(true);
|
|
28
|
+
onExpand(true);
|
|
29
|
+
}
|
|
30
|
+
}, [cell?.record]);
|
|
31
|
+
|
|
32
|
+
const colRender = function (record) {
|
|
33
|
+
const Slot = Slots[columnId];
|
|
34
|
+
return <Slot record={record} />;
|
|
35
|
+
};
|
|
36
|
+
/** 展开关闭子项 */
|
|
37
|
+
const onClickExpand = () => {
|
|
38
|
+
setExpandKeys((preExpandKeys) => {
|
|
39
|
+
if (preExpandKeys?.includes(record?.[rowKey])) {
|
|
40
|
+
return preExpandKeys?.filter((el) => el != record?.[rowKey]);
|
|
41
|
+
}
|
|
42
|
+
return [...preExpandKeys, record?.[rowKey]];
|
|
43
|
+
});
|
|
44
|
+
setExpand(!expand);
|
|
45
|
+
onExpand(!expand);
|
|
46
|
+
};
|
|
47
|
+
return (
|
|
48
|
+
<div className="expandList-template">
|
|
49
|
+
{record?.children ? (
|
|
50
|
+
<>
|
|
51
|
+
{!expand ? (
|
|
52
|
+
<PlusCircleOutlined className="expandList-template-icon" onClick={onClickExpand} />
|
|
53
|
+
) : (
|
|
54
|
+
<MinusCircleOutlined className="expandList-template-icon" onClick={onClickExpand} />
|
|
55
|
+
)}
|
|
56
|
+
</>
|
|
57
|
+
) : (
|
|
58
|
+
<div style={{ width: 14 }}></div>
|
|
59
|
+
)}
|
|
60
|
+
<div className={`expandList-template-name`} style={{ marginLeft: record?.level * 8 }}>
|
|
61
|
+
{Slots?.[columnId] ? colRender(record) : record[columnId]}
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
import { getVal } from "@hzab/list-render/src/common/utils";
|
|
3
|
+
export const GetBaseTemplate = (props) => {
|
|
4
|
+
const { pattern, cell, componentProps, Com } = props;
|
|
5
|
+
|
|
6
|
+
const echoValue = useMemo(() => {
|
|
7
|
+
if (!cell?.getField) {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
return getVal(
|
|
11
|
+
{ ...(cell?.getField && cell?.getField()), enum: cell?.getField()?.enum || cell?.values },
|
|
12
|
+
{ [cell?.getField && cell?.getField().name]: cell.text },
|
|
13
|
+
);
|
|
14
|
+
}, [cell]);
|
|
15
|
+
return (
|
|
16
|
+
<div className="base-hoc">
|
|
17
|
+
{pattern == "readPretty" ? (
|
|
18
|
+
<div>{echoValue}</div>
|
|
19
|
+
) : (
|
|
20
|
+
<Com
|
|
21
|
+
className="rg-input"
|
|
22
|
+
ref={(input) => {
|
|
23
|
+
if (input) {
|
|
24
|
+
input.focus();
|
|
25
|
+
}
|
|
26
|
+
}}
|
|
27
|
+
{...componentProps}
|
|
28
|
+
/>
|
|
29
|
+
)}
|
|
30
|
+
</div>
|
|
31
|
+
);
|
|
32
|
+
};
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Cell,
|
|
3
|
+
CellTemplate,
|
|
4
|
+
Compatible,
|
|
5
|
+
getCellProperty,
|
|
6
|
+
getCharFromKey,
|
|
7
|
+
inNumericKey,
|
|
8
|
+
isAllowedOnNumberTypingKey,
|
|
9
|
+
isCharAllowedOnNumberInput,
|
|
10
|
+
isFunctionKey,
|
|
11
|
+
isNavigationKey,
|
|
12
|
+
isNumpadNumericKey,
|
|
13
|
+
keyCodes,
|
|
14
|
+
Uncertain,
|
|
15
|
+
UncertainCompatible,
|
|
16
|
+
} from "@silevis/reactgrid";
|
|
17
|
+
import * as React from "react";
|
|
18
|
+
import { parseLocaleNumber } from "./utils";
|
|
19
|
+
|
|
20
|
+
// NOTE: all modules imported below may be imported from '@silevis/reactgrid'
|
|
21
|
+
|
|
22
|
+
export interface NumberCell extends Cell {
|
|
23
|
+
type: "number";
|
|
24
|
+
value: number;
|
|
25
|
+
format?: Intl.NumberFormat;
|
|
26
|
+
validator?: (value: number) => boolean;
|
|
27
|
+
nanToZero?: boolean;
|
|
28
|
+
hideZero?: boolean;
|
|
29
|
+
errorMessage?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export class NumberCellTemplate implements CellTemplate<NumberCell> {
|
|
33
|
+
private wasEscKeyPressed = false;
|
|
34
|
+
|
|
35
|
+
getCompatibleCell(uncertainCell: Uncertain<NumberCell>): Compatible<NumberCell> {
|
|
36
|
+
let value: number;
|
|
37
|
+
try {
|
|
38
|
+
value = getCellProperty(uncertainCell, "value", "number");
|
|
39
|
+
} catch (error) {
|
|
40
|
+
value = NaN;
|
|
41
|
+
}
|
|
42
|
+
const numberFormat = uncertainCell.format || new Intl.NumberFormat(window.navigator.language);
|
|
43
|
+
const displayValue = uncertainCell.nanToZero && Number.isNaN(value) ? 0 : value;
|
|
44
|
+
const text =
|
|
45
|
+
Number.isNaN(displayValue) || (uncertainCell.hideZero && displayValue === 0)
|
|
46
|
+
? ""
|
|
47
|
+
: numberFormat.format(displayValue);
|
|
48
|
+
return { ...uncertainCell, value: displayValue, text };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
handleKeyDown(
|
|
52
|
+
cell: Compatible<NumberCell>,
|
|
53
|
+
keyCode: number,
|
|
54
|
+
ctrl: boolean,
|
|
55
|
+
shift: boolean,
|
|
56
|
+
alt: boolean,
|
|
57
|
+
key: string,
|
|
58
|
+
capsLock: boolean,
|
|
59
|
+
): { cell: Compatible<NumberCell>; enableEditMode: boolean } {
|
|
60
|
+
if (isNumpadNumericKey(keyCode)) keyCode -= 48;
|
|
61
|
+
if (isFunctionKey(keyCode)) {
|
|
62
|
+
if (keyCode === keyCodes.F2) return { cell, enableEditMode: true };
|
|
63
|
+
return { cell, enableEditMode: false };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const char = getCharFromKey(key);
|
|
67
|
+
|
|
68
|
+
if (!ctrl && isCharAllowedOnNumberInput(char)) {
|
|
69
|
+
const value = Number(char);
|
|
70
|
+
|
|
71
|
+
if (Number.isNaN(value) && isCharAllowedOnNumberInput(char))
|
|
72
|
+
return { cell: { ...this.getCompatibleCell({ ...cell, value }), text: char }, enableEditMode: true };
|
|
73
|
+
return { cell: this.getCompatibleCell({ ...cell, value }), enableEditMode: true };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
cell,
|
|
78
|
+
enableEditMode: keyCode === keyCodes.POINTER || keyCode === keyCodes.ENTER,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
update(cell: Compatible<NumberCell>, cellToMerge: UncertainCompatible<NumberCell>): Compatible<NumberCell> {
|
|
83
|
+
return this.getCompatibleCell({ ...cell, value: cellToMerge.value });
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private getTextFromCharCode = (cellText: string): string => {
|
|
87
|
+
switch (cellText.charCodeAt(0)) {
|
|
88
|
+
case keyCodes.DASH:
|
|
89
|
+
case keyCodes.FIREFOX_DASH:
|
|
90
|
+
case keyCodes.SUBTRACT:
|
|
91
|
+
return "-";
|
|
92
|
+
case keyCodes.COMMA:
|
|
93
|
+
return ",";
|
|
94
|
+
case keyCodes.PERIOD:
|
|
95
|
+
case keyCodes.DECIMAL:
|
|
96
|
+
return ".";
|
|
97
|
+
default:
|
|
98
|
+
return cellText;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
getClassName(cell: Compatible<NumberCell>, isInEditMode: boolean): string {
|
|
103
|
+
const isValid = cell.validator?.(cell.value) ?? true;
|
|
104
|
+
const className = cell.className || "";
|
|
105
|
+
return `${!isValid ? "rg-invalid" : ""} ${className}`;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
render(
|
|
109
|
+
cell: Compatible<NumberCell>,
|
|
110
|
+
isInEditMode: boolean,
|
|
111
|
+
onCellChanged: (cell: Compatible<NumberCell>, commit: boolean) => void,
|
|
112
|
+
): React.ReactNode {
|
|
113
|
+
if (!isInEditMode) {
|
|
114
|
+
const isValid = cell.validator?.(cell.value) ?? true;
|
|
115
|
+
const textToDisplay = !isValid && cell.errorMessage ? cell.errorMessage : cell.text;
|
|
116
|
+
return textToDisplay;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const locale = cell.format ? cell.format.resolvedOptions().locale : window.navigator.languages[0];
|
|
120
|
+
const format = new Intl.NumberFormat(locale, { useGrouping: false, maximumFractionDigits: 20 });
|
|
121
|
+
|
|
122
|
+
return (
|
|
123
|
+
<input
|
|
124
|
+
className="rg-input"
|
|
125
|
+
inputMode="decimal"
|
|
126
|
+
ref={(input) => {
|
|
127
|
+
if (input) {
|
|
128
|
+
input.focus();
|
|
129
|
+
input.setSelectionRange(input.value.length, input.value.length);
|
|
130
|
+
}
|
|
131
|
+
}}
|
|
132
|
+
defaultValue={Number.isNaN(cell.value) ? this.getTextFromCharCode(cell.text) : format.format(cell.value)}
|
|
133
|
+
onChange={(e) =>
|
|
134
|
+
onCellChanged(this.getCompatibleCell({ ...cell, value: parseLocaleNumber(e.currentTarget.value) }), false)
|
|
135
|
+
}
|
|
136
|
+
onBlur={(e) => {
|
|
137
|
+
onCellChanged(
|
|
138
|
+
this.getCompatibleCell({ ...cell, value: parseLocaleNumber(e.currentTarget.value) }),
|
|
139
|
+
!this.wasEscKeyPressed,
|
|
140
|
+
);
|
|
141
|
+
this.wasEscKeyPressed = false;
|
|
142
|
+
}}
|
|
143
|
+
onKeyDown={(e) => {
|
|
144
|
+
if (
|
|
145
|
+
inNumericKey(e.keyCode) ||
|
|
146
|
+
isNavigationKey(e.keyCode) ||
|
|
147
|
+
isAllowedOnNumberTypingKey(e.keyCode) ||
|
|
148
|
+
((e.ctrlKey || e.metaKey) && e.keyCode === keyCodes.KEY_A)
|
|
149
|
+
)
|
|
150
|
+
e.stopPropagation();
|
|
151
|
+
if (
|
|
152
|
+
!inNumericKey(e.keyCode) &&
|
|
153
|
+
!isNavigationKey(e.keyCode) &&
|
|
154
|
+
!isCharAllowedOnNumberInput(getCharFromKey(e.key))
|
|
155
|
+
)
|
|
156
|
+
e.preventDefault();
|
|
157
|
+
if (e.keyCode === keyCodes.ESCAPE) this.wasEscKeyPressed = true;
|
|
158
|
+
}}
|
|
159
|
+
onCopy={(e) => e.stopPropagation()}
|
|
160
|
+
onCut={(e) => e.stopPropagation()}
|
|
161
|
+
onPaste={(e) => e.stopPropagation()}
|
|
162
|
+
onPointerDown={(e) => e.stopPropagation()}
|
|
163
|
+
/>
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export const NumberTemplate = new NumberCellTemplate();
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Cell,
|
|
3
|
+
CellTemplate,
|
|
4
|
+
Compatible,
|
|
5
|
+
getCellProperty,
|
|
6
|
+
getCharFromKey,
|
|
7
|
+
isAlphaNumericKey,
|
|
8
|
+
isFunctionKey,
|
|
9
|
+
keyCodes,
|
|
10
|
+
Uncertain,
|
|
11
|
+
UncertainCompatible,
|
|
12
|
+
} from "@silevis/reactgrid";
|
|
13
|
+
import * as React from "react";
|
|
14
|
+
|
|
15
|
+
export interface TextCell extends Cell {
|
|
16
|
+
type: "Input";
|
|
17
|
+
text: string;
|
|
18
|
+
placeholder?: string;
|
|
19
|
+
validator?: (text: string) => boolean;
|
|
20
|
+
renderer?: (text: string) => React.ReactNode;
|
|
21
|
+
errorMessage?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class TextCellTemplate implements CellTemplate<TextCell> {
|
|
25
|
+
private wasEscKeyPressed = false;
|
|
26
|
+
|
|
27
|
+
getCompatibleCell(uncertainCell: Uncertain<TextCell>): Compatible<TextCell> {
|
|
28
|
+
const text = getCellProperty(uncertainCell, "text", "string");
|
|
29
|
+
let placeholder: string | undefined;
|
|
30
|
+
try {
|
|
31
|
+
placeholder = getCellProperty(uncertainCell, "placeholder", "string");
|
|
32
|
+
} catch {
|
|
33
|
+
placeholder = "";
|
|
34
|
+
}
|
|
35
|
+
const value = parseFloat(text); // TODO more advanced parsing for all text based cells
|
|
36
|
+
return { ...uncertainCell, text, value, placeholder };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
update(cell: Compatible<TextCell>, cellToMerge: UncertainCompatible<TextCell>): Compatible<TextCell> {
|
|
40
|
+
return this.getCompatibleCell({ ...cell, text: cellToMerge.text, placeholder: cellToMerge.placeholder });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
handleKeyDown(
|
|
44
|
+
cell: Compatible<TextCell>,
|
|
45
|
+
keyCode: number,
|
|
46
|
+
ctrl: boolean,
|
|
47
|
+
shift: boolean,
|
|
48
|
+
alt: boolean,
|
|
49
|
+
key: string,
|
|
50
|
+
capsLock: boolean,
|
|
51
|
+
): { cell: Compatible<TextCell>; enableEditMode: boolean } {
|
|
52
|
+
if (isFunctionKey(keyCode)) {
|
|
53
|
+
if (keyCode === keyCodes.F2) return { cell, enableEditMode: true };
|
|
54
|
+
return { cell, enableEditMode: false };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const char = getCharFromKey(key, shift, capsLock);
|
|
58
|
+
|
|
59
|
+
if (!ctrl && !alt && isAlphaNumericKey(keyCode) && !(shift && keyCode === keyCodes.SPACE))
|
|
60
|
+
return { cell: this.getCompatibleCell({ ...cell, text: char }), enableEditMode: true };
|
|
61
|
+
return {
|
|
62
|
+
cell,
|
|
63
|
+
enableEditMode: keyCode === keyCodes.POINTER || keyCode === keyCodes.ENTER,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
handleCompositionEnd(
|
|
68
|
+
cell: Compatible<TextCell>,
|
|
69
|
+
eventData: any,
|
|
70
|
+
): { cell: Compatible<TextCell>; enableEditMode: boolean } {
|
|
71
|
+
return { cell: { ...cell, text: eventData }, enableEditMode: true };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
getClassName(cell: Compatible<TextCell>, isInEditMode: boolean): string {
|
|
75
|
+
const isValid = cell.validator ? cell.validator(cell.text) : true;
|
|
76
|
+
const className = cell.className ? cell.className : "";
|
|
77
|
+
return `${isValid ? "valid" : "rg-invalid"} ${
|
|
78
|
+
cell.placeholder && cell.text === "" ? "placeholder" : ""
|
|
79
|
+
} ${className}`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
render(
|
|
83
|
+
cell: Compatible<TextCell>,
|
|
84
|
+
isInEditMode: boolean,
|
|
85
|
+
onCellChanged: (cell: Compatible<TextCell>, commit: boolean) => void,
|
|
86
|
+
): React.ReactNode {
|
|
87
|
+
if (!isInEditMode) {
|
|
88
|
+
const isValid = cell.validator ? cell.validator(cell.text) : true;
|
|
89
|
+
const cellText = cell.text || cell.placeholder || "";
|
|
90
|
+
const textToDisplay = !isValid && cell.errorMessage ? cell.errorMessage : cellText;
|
|
91
|
+
return cell.renderer ? cell.renderer(textToDisplay) : textToDisplay;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<input
|
|
96
|
+
className="rg-input"
|
|
97
|
+
ref={(input) => {
|
|
98
|
+
if (input) {
|
|
99
|
+
input.focus();
|
|
100
|
+
// input.setSelectionRange(input.value.length, input.value.length);
|
|
101
|
+
}
|
|
102
|
+
}}
|
|
103
|
+
defaultValue={cell.text}
|
|
104
|
+
onChange={(e) => onCellChanged(this.getCompatibleCell({ ...cell, text: e.currentTarget.value }), false)}
|
|
105
|
+
onBlur={(e) => {
|
|
106
|
+
onCellChanged(this.getCompatibleCell({ ...cell, text: e.currentTarget.value }), !this.wasEscKeyPressed);
|
|
107
|
+
this.wasEscKeyPressed = false;
|
|
108
|
+
}}
|
|
109
|
+
onCopy={(e) => e.stopPropagation()}
|
|
110
|
+
onCut={(e) => e.stopPropagation()}
|
|
111
|
+
onPaste={(e) => e.stopPropagation()}
|
|
112
|
+
onPointerDown={(e) => e.stopPropagation()}
|
|
113
|
+
placeholder={cell.placeholder}
|
|
114
|
+
onKeyDown={(e) => {
|
|
115
|
+
// if (isAlphaNumericKey(e.keyCode) || isNavigationKey(e.keyCode)) e.stopPropagation();
|
|
116
|
+
// if (e.keyCode === keyCodes.ESCAPE) this.wasEscKeyPressed = true;
|
|
117
|
+
}}
|
|
118
|
+
/>
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export const TextTemplate = new TextCellTemplate();
|