@meta-1/design 0.0.210 → 0.0.211
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/package.json
CHANGED
|
@@ -15,7 +15,6 @@ import { AgGridReact } from "ag-grid-react";
|
|
|
15
15
|
import get from "lodash/get";
|
|
16
16
|
import isArray from "lodash/isArray";
|
|
17
17
|
import isFunction from "lodash/isFunction";
|
|
18
|
-
import isString from "lodash/isString";
|
|
19
18
|
import isUndefined from "lodash/isUndefined";
|
|
20
19
|
import { useTheme } from "next-themes";
|
|
21
20
|
|
|
@@ -26,12 +25,10 @@ import {
|
|
|
26
25
|
type DropdownMenuItemProps,
|
|
27
26
|
Filters,
|
|
28
27
|
type FiltersProps,
|
|
29
|
-
type Formatters,
|
|
30
28
|
generateColumnStorageKey,
|
|
31
29
|
Pagination,
|
|
32
30
|
type PaginationProps,
|
|
33
31
|
Spin,
|
|
34
|
-
ValueFormatter,
|
|
35
32
|
} from "@meta-1/design";
|
|
36
33
|
import { UIXContext } from "@meta-1/design/components/uix/config-provider";
|
|
37
34
|
import { NoRowsOverlay } from "./overlays";
|
|
@@ -46,37 +43,8 @@ export interface StickyColumnProps {
|
|
|
46
43
|
size: number;
|
|
47
44
|
}
|
|
48
45
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
id?: string;
|
|
52
|
-
/** 数据字段路径,支持点号分隔的嵌套路径,如 "user.name" */
|
|
53
|
-
accessorKey?: string;
|
|
54
|
-
/** 列标题,可以是字符串或返回 React 元素的函数 */
|
|
55
|
-
header?: string | ((params: { column: any; header: any; table: any }) => React.ReactNode);
|
|
56
|
-
/** 自定义单元格渲染函数 */
|
|
57
|
-
cell?: (params: {
|
|
58
|
-
getValue: () => any;
|
|
59
|
-
row: { original: TData; getValue: (key: string) => any };
|
|
60
|
-
column: any;
|
|
61
|
-
table: any;
|
|
62
|
-
}) => React.ReactNode;
|
|
63
|
-
/** 是否启用排序 */
|
|
64
|
-
enableSorting?: boolean;
|
|
65
|
-
/** 是否启用调整大小 */
|
|
66
|
-
enableResizing?: boolean;
|
|
67
|
-
/** 是否启用隐藏 */
|
|
68
|
-
enableHiding?: boolean;
|
|
69
|
-
/** 列宽 */
|
|
70
|
-
size?: number;
|
|
71
|
-
/** 最小列宽 */
|
|
72
|
-
minSize?: number;
|
|
73
|
-
/** 最大列宽 */
|
|
74
|
-
maxSize?: number;
|
|
75
|
-
/** 单元格 CSS 类名 */
|
|
76
|
-
className?: string;
|
|
77
|
-
/** 格式化函数数组,按顺序应用 */
|
|
78
|
-
formatters?: Formatters;
|
|
79
|
-
};
|
|
46
|
+
/** DataGrid 列定义,直接使用 AG Grid 的 ColDef 规范 */
|
|
47
|
+
export type DataGridColumn<TData> = ColDef<TData>;
|
|
80
48
|
|
|
81
49
|
export interface DataGridProps<TData> {
|
|
82
50
|
columns: DataGridColumn<TData>[];
|
|
@@ -136,109 +104,23 @@ const hasActions = (rowActions: DropdownMenuItemProps[] | ((cell: any) => Dropdo
|
|
|
136
104
|
return false;
|
|
137
105
|
};
|
|
138
106
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
columnDef
|
|
142
|
-
|
|
143
|
-
): ColDef<TData> {
|
|
144
|
-
const accessorKey = columnDef.accessorKey;
|
|
145
|
-
const colId =
|
|
146
|
-
columnDef.id || columnDef.colId || (typeof accessorKey === "string" ? accessorKey.replace(/\./g, "_") : undefined);
|
|
147
|
-
|
|
148
|
-
// 检查是否是粘性列
|
|
149
|
-
// 支持通过 id、accessorKey 或 colId 匹配
|
|
107
|
+
function applyStickyColumnConfig<TData>(columnDef: ColDef<TData>, stickyColumns: StickyColumnProps[]): ColDef<TData> {
|
|
108
|
+
const colId = columnDef.colId || columnDef.field;
|
|
109
|
+
if (!colId) return columnDef;
|
|
110
|
+
|
|
150
111
|
const stickyCol = stickyColumns.find((sc) => {
|
|
151
112
|
const key = sc.key;
|
|
152
|
-
|
|
153
|
-
if (key === colId) return true;
|
|
154
|
-
// 匹配原始 accessorKey(如果 key 包含点号)
|
|
155
|
-
if (typeof accessorKey === "string" && key === accessorKey) return true;
|
|
156
|
-
// 匹配 id
|
|
157
|
-
if (columnDef.id && key === columnDef.id) return true;
|
|
158
|
-
return false;
|
|
113
|
+
return key === colId || key === columnDef.field;
|
|
159
114
|
});
|
|
160
|
-
const pinned = stickyCol ? (stickyCol.position === "left" ? "left" : "right") : undefined;
|
|
161
115
|
|
|
162
|
-
|
|
163
|
-
|
|
116
|
+
if (!stickyCol) return columnDef;
|
|
117
|
+
|
|
118
|
+
const pinned = stickyCol.position === "left" ? "left" : "right";
|
|
119
|
+
return {
|
|
164
120
|
...columnDef,
|
|
165
|
-
colId: colId || columnDef.colId || String(Math.random()),
|
|
166
121
|
pinned: pinned || columnDef.pinned,
|
|
167
|
-
|
|
168
|
-
filter: columnDef.filter ?? false,
|
|
169
|
-
resizable: columnDef.enableResizing !== false ? columnDef.resizable !== false : false,
|
|
170
|
-
hide: columnDef.enableHiding === false ? false : columnDef.hide,
|
|
171
|
-
cellClass: columnDef.className || columnDef.cellClass,
|
|
122
|
+
width: stickyCol.size || columnDef.width,
|
|
172
123
|
};
|
|
173
|
-
|
|
174
|
-
if (pinned) {
|
|
175
|
-
if (columnDef.size) agColDef.width = columnDef.size;
|
|
176
|
-
if (columnDef.minSize) agColDef.minWidth = columnDef.minSize;
|
|
177
|
-
if (columnDef.maxSize) agColDef.maxWidth = columnDef.maxSize;
|
|
178
|
-
} else {
|
|
179
|
-
if (columnDef.size) {
|
|
180
|
-
agColDef.width = columnDef.size;
|
|
181
|
-
if (columnDef.minSize) agColDef.minWidth = columnDef.minSize;
|
|
182
|
-
if (columnDef.maxSize) agColDef.maxWidth = columnDef.maxSize;
|
|
183
|
-
} else if (!agColDef.width && !agColDef.flex) {
|
|
184
|
-
agColDef.flex = 1;
|
|
185
|
-
agColDef.minWidth = columnDef.minSize || 100;
|
|
186
|
-
if (columnDef.maxSize) agColDef.maxWidth = columnDef.maxSize;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
if (!agColDef.field && typeof accessorKey === "string") {
|
|
191
|
-
agColDef.field = accessorKey as any;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
if (isString(columnDef.header)) {
|
|
195
|
-
agColDef.headerName = columnDef.header;
|
|
196
|
-
} else if (isFunction(columnDef.header)) {
|
|
197
|
-
agColDef.headerComponent = (params: any) => {
|
|
198
|
-
const headerFn = columnDef.header as (params: { column: any; header: any; table: any }) => React.ReactNode;
|
|
199
|
-
const result = headerFn({
|
|
200
|
-
column: params.column,
|
|
201
|
-
header: params,
|
|
202
|
-
table: params.api,
|
|
203
|
-
});
|
|
204
|
-
if (typeof result === "string" || typeof result === "number") {
|
|
205
|
-
return result;
|
|
206
|
-
}
|
|
207
|
-
return result;
|
|
208
|
-
};
|
|
209
|
-
} else if (columnDef.headerName) {
|
|
210
|
-
agColDef.headerName = columnDef.headerName;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
const formatters = columnDef.formatters || [];
|
|
214
|
-
const hasFormatters = formatters.length > 0;
|
|
215
|
-
const hasCustomCell = !!columnDef.cell;
|
|
216
|
-
|
|
217
|
-
if (hasCustomCell || hasFormatters) {
|
|
218
|
-
agColDef.cellRenderer = (params: any) => {
|
|
219
|
-
let cellContent: any;
|
|
220
|
-
|
|
221
|
-
if (hasCustomCell && isFunction(columnDef.cell)) {
|
|
222
|
-
const cellContext = {
|
|
223
|
-
getValue: () => params.value,
|
|
224
|
-
row: { original: params.data, getValue: (key: string) => get(params.data, key) },
|
|
225
|
-
column: params.column,
|
|
226
|
-
table: params.api,
|
|
227
|
-
};
|
|
228
|
-
cellContent = columnDef.cell(cellContext);
|
|
229
|
-
} else {
|
|
230
|
-
cellContent = params.value;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
if (hasFormatters) {
|
|
234
|
-
return <ValueFormatter formatters={formatters} value={cellContent} />;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
return cellContent;
|
|
238
|
-
};
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
return agColDef;
|
|
242
124
|
}
|
|
243
125
|
|
|
244
126
|
export function DataGrid<TData>(props: DataGridProps<TData>) {
|
|
@@ -271,7 +153,12 @@ export function DataGrid<TData>(props: DataGridProps<TData>) {
|
|
|
271
153
|
const [columnVisibility, setColumnVisibility] = useState<Record<string, boolean>>({});
|
|
272
154
|
|
|
273
155
|
const storageKey = useMemo(() => {
|
|
274
|
-
return generateColumnStorageKey(
|
|
156
|
+
return generateColumnStorageKey(
|
|
157
|
+
columns.map((col) => ({
|
|
158
|
+
id: col.colId as string | undefined,
|
|
159
|
+
accessorKey: col.field as string | number | symbol | undefined,
|
|
160
|
+
})),
|
|
161
|
+
);
|
|
275
162
|
}, [columns]);
|
|
276
163
|
|
|
277
164
|
useEffect(() => {
|
|
@@ -301,45 +188,22 @@ export function DataGrid<TData>(props: DataGridProps<TData>) {
|
|
|
301
188
|
}
|
|
302
189
|
}, [columnVisibility, mounted]);
|
|
303
190
|
|
|
304
|
-
// 转换列定义
|
|
305
191
|
const agGridColumns = useMemo<ColDef<TData>[]>(() => {
|
|
306
192
|
const newColumns: ColDef<TData>[] = [];
|
|
307
193
|
|
|
308
|
-
// 添加 checkbox 列
|
|
309
|
-
if (checkbox) {
|
|
310
|
-
// 检查是否在 stickyColumns 中明确配置,如果没有则默认固定在左侧
|
|
311
|
-
const stickySelect = stickyColumns.find((sc) => sc.key === "select");
|
|
312
|
-
const pinnedSelect = stickySelect
|
|
313
|
-
? stickySelect.position === "left"
|
|
314
|
-
? "left"
|
|
315
|
-
: stickySelect.position === "right"
|
|
316
|
-
? "right"
|
|
317
|
-
: undefined
|
|
318
|
-
: "left"; // 默认固定在左侧
|
|
319
|
-
|
|
320
|
-
newColumns.push({
|
|
321
|
-
colId: "select",
|
|
322
|
-
checkboxSelection: true,
|
|
323
|
-
headerCheckboxSelection: true,
|
|
324
|
-
width: 40,
|
|
325
|
-
pinned: pinnedSelect,
|
|
326
|
-
lockPosition: pinnedSelect === "left" ? "left" : pinnedSelect === "right" ? "right" : undefined,
|
|
327
|
-
suppressMovable: true,
|
|
328
|
-
resizable: false,
|
|
329
|
-
sortable: false,
|
|
330
|
-
filter: false,
|
|
331
|
-
headerName: "",
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
// 转换用户定义的列
|
|
336
194
|
columns.forEach((col) => {
|
|
337
|
-
|
|
195
|
+
const processedCol = applyStickyColumnConfig(col, stickyColumns);
|
|
196
|
+
if (!processedCol.colId && !processedCol.field) {
|
|
197
|
+
processedCol.colId = String(Math.random());
|
|
198
|
+
}
|
|
199
|
+
if (!processedCol.width && !processedCol.flex) {
|
|
200
|
+
processedCol.flex = 1;
|
|
201
|
+
processedCol.minWidth = processedCol.minWidth || 100;
|
|
202
|
+
}
|
|
203
|
+
newColumns.push(processedCol);
|
|
338
204
|
});
|
|
339
205
|
|
|
340
|
-
// 添加 actions 列
|
|
341
206
|
if (hasActions(rowActions!)) {
|
|
342
|
-
// 检查是否在 stickyColumns 中明确配置,如果没有则默认固定在右侧
|
|
343
207
|
const stickyActions = stickyColumns.find((sc) => sc.key === "actions");
|
|
344
208
|
const pinnedActions = stickyActions
|
|
345
209
|
? stickyActions.position === "left"
|
|
@@ -383,7 +247,31 @@ export function DataGrid<TData>(props: DataGridProps<TData>) {
|
|
|
383
247
|
}
|
|
384
248
|
|
|
385
249
|
return newColumns;
|
|
386
|
-
}, [columns,
|
|
250
|
+
}, [columns, rowActions, onRowActionClick, stickyColumns]);
|
|
251
|
+
|
|
252
|
+
const selectionColumnDef = useMemo<ColDef<TData> | undefined>(() => {
|
|
253
|
+
if (!checkbox) return undefined;
|
|
254
|
+
|
|
255
|
+
const stickySelect = stickyColumns.find((sc) => sc.key === "select");
|
|
256
|
+
const pinnedSelect = stickySelect
|
|
257
|
+
? stickySelect.position === "left"
|
|
258
|
+
? "left"
|
|
259
|
+
: stickySelect.position === "right"
|
|
260
|
+
? "right"
|
|
261
|
+
: undefined
|
|
262
|
+
: "left";
|
|
263
|
+
|
|
264
|
+
return {
|
|
265
|
+
width: 40,
|
|
266
|
+
pinned: pinnedSelect,
|
|
267
|
+
lockPosition: pinnedSelect === "left" ? "left" : pinnedSelect === "right" ? "right" : undefined,
|
|
268
|
+
suppressMovable: true,
|
|
269
|
+
resizable: false,
|
|
270
|
+
sortable: false,
|
|
271
|
+
filter: false,
|
|
272
|
+
headerName: "",
|
|
273
|
+
};
|
|
274
|
+
}, [checkbox, stickyColumns]);
|
|
387
275
|
|
|
388
276
|
// ag-grid 主题
|
|
389
277
|
const gridTheme = useMemo(() => {
|
|
@@ -451,8 +339,10 @@ export function DataGrid<TData>(props: DataGridProps<TData>) {
|
|
|
451
339
|
const allColumns = gridApiRef.current.getColumns() || [];
|
|
452
340
|
const visibility: Record<string, boolean> = {};
|
|
453
341
|
allColumns.forEach((col) => {
|
|
454
|
-
|
|
455
|
-
|
|
342
|
+
const colId = col.getColId();
|
|
343
|
+
const isSelectionColumn = colId?.startsWith("ag-Grid-AutoColumn") || colId === "select";
|
|
344
|
+
if (!isSelectionColumn && colId !== "actions") {
|
|
345
|
+
visibility[colId] = col.isVisible() ?? true;
|
|
456
346
|
}
|
|
457
347
|
});
|
|
458
348
|
setColumnVisibility(visibility);
|
|
@@ -466,24 +356,13 @@ export function DataGrid<TData>(props: DataGridProps<TData>) {
|
|
|
466
356
|
return allColumns
|
|
467
357
|
.filter((col) => {
|
|
468
358
|
const colId = col.getColId();
|
|
469
|
-
|
|
359
|
+
const isSelectionColumn = colId?.startsWith("ag-Grid-AutoColumn") || colId === "select";
|
|
360
|
+
return !isSelectionColumn && colId !== "actions" && col.getUserProvidedColDef()?.hide !== false;
|
|
470
361
|
})
|
|
471
362
|
.map((col) => {
|
|
472
363
|
const colId = col.getColId();
|
|
473
|
-
const columnDef = columns.find((c) =>
|
|
474
|
-
|
|
475
|
-
const key = c.id || (typeof accessorKey === "string" ? accessorKey.replace(/\./g, "_") : undefined);
|
|
476
|
-
return key === colId;
|
|
477
|
-
});
|
|
478
|
-
let label = colId;
|
|
479
|
-
if (columnDef) {
|
|
480
|
-
if (isString(columnDef.header)) {
|
|
481
|
-
label = columnDef.header;
|
|
482
|
-
} else if (isFunction(columnDef.header)) {
|
|
483
|
-
// 简化处理,使用 colId 作为 label
|
|
484
|
-
label = colId;
|
|
485
|
-
}
|
|
486
|
-
}
|
|
364
|
+
const columnDef = columns.find((c) => c.colId === colId || c.field === colId);
|
|
365
|
+
const label = columnDef?.headerName || colId;
|
|
487
366
|
const checked = columnVisibility[colId];
|
|
488
367
|
return {
|
|
489
368
|
id: colId,
|
|
@@ -582,11 +461,20 @@ export function DataGrid<TData>(props: DataGridProps<TData>) {
|
|
|
582
461
|
onSelectionChanged={onSelectionChanged}
|
|
583
462
|
rowData={data}
|
|
584
463
|
rowHeight={autoRowHeight ? undefined : typeof rowHeight === "number" ? rowHeight : undefined}
|
|
585
|
-
rowSelection={
|
|
464
|
+
rowSelection={
|
|
465
|
+
checkbox
|
|
466
|
+
? {
|
|
467
|
+
mode: "multiRow",
|
|
468
|
+
checkboxes: true,
|
|
469
|
+
headerCheckbox: true,
|
|
470
|
+
enableClickSelection: false,
|
|
471
|
+
}
|
|
472
|
+
: undefined
|
|
473
|
+
}
|
|
474
|
+
selectionColumnDef={selectionColumnDef}
|
|
586
475
|
suppressAnimationFrame={false}
|
|
587
476
|
suppressColumnVirtualisation={false}
|
|
588
477
|
suppressHorizontalScroll={false}
|
|
589
|
-
suppressRowClickSelection={!checkbox}
|
|
590
478
|
suppressRowVirtualisation={gridHeight ? false : true}
|
|
591
479
|
theme={gridTheme}
|
|
592
480
|
tooltipHideDelay={200}
|