@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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meta-1/design",
3
- "version": "0.0.210",
3
+ "version": "0.0.211",
4
4
  "keywords": [
5
5
  "easykit",
6
6
  "design",
@@ -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
- export type DataGridColumn<TData> = Partial<ColDef<TData>> & {
50
- /** 列的 ID,如果不提供则使用 accessorKey 或 field */
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
- // DataGridColumn 转换为 ag-grid ColDef
140
- function convertColumnDefToAgGrid<TData>(
141
- columnDef: DataGridColumn<TData>,
142
- stickyColumns: StickyColumnProps[],
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
- // 直接匹配 colId
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
- // columnDef 中提取 ag-grid 支持的属性
163
- const agColDef: ColDef<TData> = {
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
- sortable: columnDef.enableSorting !== false ? columnDef.sortable !== false : false,
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(columns);
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
- newColumns.push(convertColumnDefToAgGrid(col, stickyColumns));
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, checkbox, rowActions, onRowActionClick, stickyColumns]);
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
- if (col.getColId() !== "select" && col.getColId() !== "actions") {
455
- visibility[col.getColId()] = col.isVisible() ?? true;
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
- return colId !== "select" && colId !== "actions" && col.getUserProvidedColDef()?.hide !== false;
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
- const accessorKey = (c as any).accessorKey;
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={checkbox ? "multiple" : undefined}
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}