@hzab/list-render 1.10.21-alpha.6 → 1.10.21-alpha.7

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,215 +0,0 @@
1
- import { useEffect, useMemo, useState } from "react";
2
-
3
- import {
4
- Cell,
5
- CellTemplate,
6
- Compatible,
7
- getCellProperty,
8
- getCharFromKey,
9
- isAlphaNumericKey,
10
- isNavigationKey,
11
- keyCodes,
12
- Uncertain,
13
- UncertainCompatible,
14
- } from "@silevis/reactgrid";
15
- import { getVal } from "@hzab/list-render/src/common/utils";
16
- import { InfoCircleOutlined } from "@ant-design/icons";
17
- import { Popover } from "antd";
18
-
19
- export type OptionType = {
20
- label: string;
21
- value: string | number;
22
- isDisabled?: boolean;
23
- };
24
-
25
- export interface BaseCell extends Cell {
26
- selectedValue?: string;
27
- value: string | number;
28
- values: OptionType[];
29
- isDisabled?: boolean;
30
- commit?: string;
31
- }
32
- interface DIProps {
33
- onCellChanged: (...args: any[]) => void;
34
- cell: Record<string, any>;
35
- isInEditMode?: boolean;
36
- }
37
-
38
- export const WidthWrapHoc = (WrapComponent: any) => {
39
- class createBaseCellTemplate implements CellTemplate<BaseCell> {
40
- getCompatibleCell(uncertainCell: Uncertain<BaseCell>): Compatible<BaseCell> {
41
- let selectedValue: string | undefined;
42
- try {
43
- selectedValue = getCellProperty(uncertainCell, "selectedValue", "number");
44
- } catch {
45
- selectedValue = undefined;
46
- }
47
- if (!selectedValue) {
48
- try {
49
- selectedValue = getCellProperty(uncertainCell, "selectedValue", "string");
50
- } catch {
51
- selectedValue = undefined;
52
- }
53
- }
54
- let commit: string;
55
-
56
- try {
57
- commit = getCellProperty(uncertainCell, "commit", "string");
58
- } catch {
59
- commit = "submit";
60
- }
61
-
62
- let values: any;
63
- try {
64
- values = getCellProperty(uncertainCell, "values", "object");
65
- } catch {
66
- values = [];
67
- }
68
- const value = selectedValue ? parseFloat(selectedValue) : NaN;
69
- let isDisabled = true;
70
- try {
71
- isDisabled = getCellProperty(uncertainCell, "isDisabled", "boolean");
72
- } catch {
73
- isDisabled = false;
74
- }
75
- const text = selectedValue || "";
76
- return { ...uncertainCell, selectedValue, text, value, values, isDisabled, commit };
77
- }
78
-
79
- update(cell: Compatible<BaseCell>, cellToMerge: UncertainCompatible<BaseCell>): Compatible<BaseCell> {
80
- const selectedValueFromText = cell.values.some((val: any) => val.value == cellToMerge.text)
81
- ? cellToMerge.text
82
- : cellToMerge?.text || undefined;
83
-
84
- return this.getCompatibleCell({
85
- ...cell,
86
- selectedValue: selectedValueFromText,
87
- commit: cellToMerge?.commit,
88
- });
89
- }
90
-
91
- getClassName(cell: Compatible<BaseCell>, isInEditMode: boolean): string {
92
- return "";
93
- }
94
- /** enableEditMode为true 时输入中文会报错 */
95
- handleCompositionEnd(
96
- cell: Compatible<BaseCell>,
97
- eventData: any,
98
- ): { cell: Compatible<BaseCell>; enableEditMode: boolean } {
99
- return {
100
- cell: {
101
- ...cell,
102
- },
103
- enableEditMode: false,
104
- };
105
- }
106
- /** render 不能抽出来组件,否则点击会失效 */
107
- render(cell: any, isInEditMode: boolean, onCellChanged: (cell: any, commit: boolean) => void): React.ReactNode {
108
- const [isOpen, setIsOpen] = useState<boolean>(false);
109
- const datatypeId = cell?.columnId + cell?.rowId;
110
- const [comValue, setComValue] = useState(cell?.text);
111
- useEffect(() => {
112
- // 处理下拉选项弹层失焦逻辑
113
- function onClick() {
114
- if ((window as any).gridEditId != datatypeId) {
115
- setIsOpen(false);
116
- }
117
- }
118
- document.addEventListener("click", onClick);
119
- return () => {
120
- document.removeEventListener("click", onClick);
121
- };
122
- }, []);
123
- const echoValue = useMemo(() => {
124
- if (!cell?.getField) {
125
- return;
126
- }
127
- return getVal(
128
- { ...cell?.getField(), enum: cell?.getField()?.enum || cell?.values },
129
- { [cell?.getField().name]: cell.text },
130
- );
131
- }, [cell]);
132
-
133
- const isValidator = useMemo(() => {
134
- let flag = false;
135
- let isVerify = false;
136
- for (let it of cell?.validatorList || []) {
137
- if (it?.pattern?.test(cell.text)) {
138
- flag = true;
139
- }
140
- break;
141
- }
142
- isVerify = !flag && cell?.validatorList?.length > 0;
143
-
144
- return isVerify;
145
- }, [cell?.validatorList, cell.text]);
146
-
147
- return (
148
- <div
149
- className="base-hoc"
150
- onDoubleClick={(e) => {
151
- if (cell?.nonEditable) {
152
- return;
153
- }
154
- (window as any).preCell = cell;
155
- setIsOpen(true);
156
- }}
157
- >
158
- <WrapComponent
159
- componentProps={{
160
- style: { width: "100%", display: "flex", alignItems: "center" },
161
- value: comValue,
162
- options: cell.values,
163
- onChange: (e) => {
164
- cell["commit"] = "change";
165
- const targetValue = e?.target?.value ?? e;
166
- setComValue(targetValue);
167
- onCellChanged(
168
- this.getCompatibleCell({
169
- ...cell,
170
- text: targetValue,
171
- selectedValue: targetValue,
172
- }),
173
- true,
174
- );
175
- },
176
- onBlur: (e) => {
177
- cell["commit"] = "submit";
178
- if (isValidator) {
179
- cell["commit"] = "verify";
180
- }
181
- const targetValue = cell?.text;
182
- onCellChanged(
183
- this.getCompatibleCell({
184
- ...cell,
185
- text: targetValue,
186
- selectedValue: targetValue,
187
- }),
188
- true,
189
- );
190
- setIsOpen(false);
191
- },
192
-
193
- onPointerDown: (e) => {
194
- e.stopPropagation();
195
- },
196
- onKeyDown: (e) => {
197
- if (isAlphaNumericKey(e.keyCode) || isNavigationKey(e.keyCode)) e.stopPropagation();
198
- },
199
- ...((cell?.getField && cell?.getField()["x-component-props"]) || {}),
200
- }}
201
- pattern={isOpen ? "" : "readPretty"}
202
- cell={cell}
203
- ></WrapComponent>
204
- {isValidator && (
205
- <Popover content="该字段不合法">
206
- <InfoCircleOutlined style={{ cursor: "pointer" }} />
207
- </Popover>
208
- )}
209
- </div>
210
- );
211
- }
212
- }
213
-
214
- return new createBaseCellTemplate();
215
- };
@@ -1,14 +0,0 @@
1
- import { DatePicker, Input, TimePicker } from "antd";
2
-
3
- export const childAntdComponent = {
4
- "DatePicker.MonthPicker": DatePicker.MonthPicker,
5
- "DatePicker.QuarterPicker": DatePicker.QuarterPicker,
6
- "DatePicker.RangePicker": DatePicker.RangePicker,
7
- "DatePicker.TimePicker": DatePicker.TimePicker,
8
- "DatePicker.WeekPicker": DatePicker.WeekPicker,
9
- "DatePicker.YearPicker": DatePicker.YearPicker,
10
- "Input.Password": Input.Password,
11
- "Input.Search": Input.Search,
12
- "Input.TextArea": Input.TextArea,
13
- "TimePicker.RangePicker": TimePicker.RangePicker,
14
- }
@@ -1,257 +0,0 @@
1
- export const getNavigatorLanguage = (): string => navigator.language || "en-US";
2
-
3
- function getLocaleSeparators(locale: string) {
4
- const testNumber = 123456.789;
5
- const localeFormattedNumber = Intl.NumberFormat(locale).format(testNumber);
6
-
7
- // Get the thousands separator of the locale
8
- const thousandsSeparator = localeFormattedNumber.split("123")[1][0];
9
-
10
- // Get the decimal separator of the locale
11
- const decimalSeparator = localeFormattedNumber.split("123")[1][4];
12
- return { thousandsSeparator, decimalSeparator };
13
- }
14
- export function parseLocaleNumber(stringNumber: string, locale = getNavigatorLanguage()): number {
15
- if (!stringNumber.trim()) return NaN;
16
- const { thousandsSeparator, decimalSeparator } = getLocaleSeparators(locale);
17
- const normalizedStringNumber = stringNumber.replace(/\u00A0/g, " "); // Replace non-breaking space with normal space
18
- const numberString = normalizedStringNumber
19
- .replace(new RegExp(`[${thousandsSeparator}\\s]`, "g"), "") // Replace thousands separator and white-space
20
- .replace(new RegExp(`\\${decimalSeparator}`, "g"), "."); // Replace decimal separator
21
-
22
- const trimmedNumberString = numberString.replace(/^(?!-)\D+|\D+$/g, ""); // Remove characters before first and after last number, but keep negative sign
23
- if (trimmedNumberString === null || trimmedNumberString.trim().length === 0) {
24
- return NaN;
25
- }
26
- return Number(trimmedNumberString);
27
- }
28
-
29
-
30
- function isReactElement(value) {
31
- return value !== null && typeof value === "object";
32
- }
33
- const getTitle = (item) => {
34
- return typeof item?.title == "function"
35
- ? isReactElement(item?.title())
36
- ? item?.title()?.props.children
37
- : String(item?.title()) || ""
38
- : String(item?.title) || ""
39
- }
40
-
41
- export function convertColumnsToRows(columns, headerRowHeight = 40) {
42
- // 获取所有叶子节点
43
- const getLeaves = (cols) => {
44
- return cols.reduce((acc, col) => {
45
- if (col.children?.length) {
46
- return [...acc, ...getLeaves(col.children)];
47
- }
48
- return [...acc, col];
49
- }, []);
50
- };
51
-
52
- // 计算最大深度
53
- const getDepth = (cols, depth = 1) => {
54
- return cols.reduce((max, col) => {
55
- if (col.children?.length) {
56
- return Math.max(max, getDepth(col.children, depth + 1));
57
- }
58
- return Math.max(max, depth);
59
- }, depth);
60
- };
61
-
62
- const leafColumns = getLeaves(columns);
63
- const totalDepth = getDepth(columns);
64
- const totalCols = leafColumns.length;
65
-
66
- // 构建表头树
67
- const buildTree = (cols, depth = 0) => {
68
- return cols.map((col) => {
69
- const hasChildren = col.children?.length > 0;
70
- if (!hasChildren) {
71
- return {
72
- ...col,
73
- rowspan: totalDepth - depth,
74
- colspan: 1,
75
- _depth: depth,
76
- _isLeaf: true,
77
- };
78
- }
79
- const leafCount = getLeaves(col.children).length;
80
- return {
81
- ...col,
82
- rowspan: 1,
83
- colspan: leafCount,
84
- _depth: depth,
85
- _isLeaf: false,
86
- children: buildTree(col.children, depth + 1),
87
- };
88
- });
89
- };
90
-
91
- const tree = buildTree(columns, 0);
92
-
93
- // 初始化行
94
- const rows: any = Array.from({ length: totalDepth }, (_, i) => ({
95
- rowId: `header-${i}`,
96
- height: headerRowHeight,
97
- cells: [],
98
- }));
99
-
100
-
101
- // 递归填充行
102
- const fillRow = (nodes, rowIndex = 0) => {
103
- nodes.forEach((node) => {
104
- if (node._isLeaf) {
105
- const cell = {
106
- ...node,
107
- type: node?.type == "rowSelection" ? "rowSelection" : "header",
108
- text: getTitle(node),
109
- dataIndex: node.dataIndex,
110
- width: node.width,
111
- rowspan: node.rowspan,
112
- style: node?.type == "rowSelection" ? node?.style : {},
113
- };
114
- if (node.sorter) cell.sorter = node.sorter;
115
- if (node.key) cell.key = node.key;
116
- rows[rowIndex].cells.push(cell);
117
- } else {
118
- // 父节点:添加colspan
119
- rows[rowIndex].cells.push({
120
- ...node,
121
- type: node?.type == "rowSelection" ? "rowSelection" : "header",
122
- text: getTitle(node),
123
- colspan: node.colspan,
124
- });
125
- if (node.children) {
126
- fillRow(node.children, rowIndex + 1);
127
- }
128
- }
129
- });
130
- };
131
-
132
- fillRow(tree, 0);
133
-
134
- // 补全每一行的cell,使长度一致
135
- rows.forEach((row, rowIndex) => {
136
- const newCells = [];
137
- let colIndex = 0;
138
- let cellIndex = 0;
139
-
140
- while (colIndex < totalCols) {
141
- const currentCell = row.cells[cellIndex];
142
-
143
- if (!currentCell) {
144
- // 如果当前行没有足够的cell,从叶子节点补充
145
- const leaf = leafColumns[colIndex];
146
- newCells.push({
147
- ...leaf,
148
- type: leaf?.type == "rowSelection" ? "rowSelection" : "header",
149
- text: getTitle(leaf),
150
- dataIndex: leaf.dataIndex,
151
- width: leaf.width,
152
- rowspan: rowIndex === totalDepth - 1 ? 1 : undefined,
153
- });
154
- colIndex++;
155
- cellIndex++;
156
- continue;
157
- }
158
-
159
- const colspan = currentCell.colspan || 1;
160
- const rowspan = currentCell.rowspan || 1;
161
-
162
- // 检查当前cell是否应该出现在这一行
163
- // 如果rowspan > 1,表示它跨多行,但只在第一行出现
164
- if (rowspan > 1 && rowIndex > 0) {
165
- // 这个cell不应该出现在当前行,跳过
166
- colIndex += colspan;
167
- cellIndex++;
168
- continue;
169
- }
170
-
171
- // 如果当前cell有colspan,需要补全后面的空cell
172
- newCells.push(currentCell);
173
- colIndex += colspan;
174
- cellIndex++;
175
-
176
- // 如果colspan > 1,后面补充空cell
177
- for (let i = 1; i < colspan; i++) {
178
- newCells.push({
179
- type: "header",
180
- text: "",
181
- });
182
- }
183
- }
184
-
185
- row.cells = newCells;
186
- });
187
-
188
- // 最后一行的特殊处理:确保所有叶子节点都有对应的cell
189
- const lastRow = rows[totalDepth - 1];
190
- const lastRowCells = [];
191
- let leafIndex = 0;
192
-
193
- // 遍历所有叶子节点
194
- leafColumns.forEach((leaf, index) => {
195
- // 检查是否已经在lastRow中有对应的cell
196
- const existingCell = lastRow.cells.find((cell) => cell.dataIndex === leaf.dataIndex && cell.text === leaf.title);
197
-
198
- if (existingCell) {
199
- lastRowCells.push(existingCell);
200
- } else {
201
- // 创建新的cell
202
- lastRowCells.push({
203
- ...leaf,
204
- type: leaf?.type == "rowSelection" ? "rowSelection" : "header",
205
- text: getTitle(leaf),
206
- dataIndex: leaf.dataIndex,
207
- width: leaf.width,
208
- rowspan: 1,
209
- });
210
- }
211
- });
212
-
213
- lastRow.cells = lastRowCells;
214
-
215
- // 确保所有行的cell数量等于totalCols
216
- rows.forEach((row) => {
217
- // 如果cell数量少于totalCols,补充空cell
218
- while (row.cells.length < totalCols) {
219
- row.cells.push({
220
- type: "header",
221
- text: "",
222
- });
223
- }
224
- });
225
-
226
- return rows;
227
- }
228
-
229
-
230
- export function flattenColumns(columns: any[]) {
231
- const result: any[] = [];
232
-
233
- function traverse(cols) {
234
- cols.forEach((col) => {
235
- if (col.children && col.children.length > 0) {
236
- traverse(col.children);
237
- } else {
238
- // 创建新对象,只保留需要的属性
239
- const { title, dataIndex, key, width, sorter, k, ...rest } = col;
240
- result.push({
241
- type: "Input",
242
- dataIndex,
243
- title,
244
- ...(key && { key }),
245
- ...(width && { width }),
246
- ...(sorter && { sorter }),
247
- ...(k && { k }),
248
- // 如果需要保留其他属性
249
- ...rest,
250
- });
251
- }
252
- });
253
- }
254
-
255
- traverse(columns);
256
- return result;
257
- }
@@ -1,28 +0,0 @@
1
- .grid-container {
2
- overflow: auto;
3
- position: relative;
4
- max-height: 80vh;
5
-
6
-
7
-
8
- .ant-select {
9
- width: 100% !important;
10
- }
11
-
12
-
13
- .reactgrid-content .rg-pane .rg-cell {
14
- padding: 0;
15
-
16
- >div:nth-child(1) {
17
- padding: 0 4px;
18
- }
19
- }
20
- }
21
-
22
- .base-hoc {
23
- width: 100%;
24
- height: 100%;
25
- display: flex;
26
- align-items: center;
27
- justify-content: center;
28
- }