@ceed/ads 1.26.0 → 1.28.0
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/dist/components/DataTable/hooks.d.ts +1 -1
- package/dist/components/DataTable/styled.d.ts +1 -0
- package/dist/components/DataTable/types.d.ts +14 -0
- package/dist/components/DataTable/utils.d.ts +2 -2
- package/dist/components/data-display/DataTable.md +255 -6
- package/dist/index.browser.js +2 -2
- package/dist/index.browser.js.map +3 -3
- package/dist/index.cjs +101 -37
- package/dist/index.js +106 -42
- package/framer/index.js +1 -1
- package/package.json +1 -1
|
@@ -5,7 +5,7 @@ export declare function useColumnWidths<T>(columnsByField: {
|
|
|
5
5
|
headerRef: React.RefObject<HTMLTableCellElement>;
|
|
6
6
|
};
|
|
7
7
|
}): Record<string, number>;
|
|
8
|
-
export declare function useDataTableRenderer<T extends Record<PropertyKey, unknown>, GetId extends ((row: T) => any) | undefined = undefined>({ rows: _rows, columns: columnsProp, pinnedColumns, rowCount: totalRowsProp, initialState, pagination, paginationMode, paginationModel, onPaginationModelChange, sortModel: controlledSortModel, sortOrder: _sortOrder, selectionModel, onSortModelChange, onSelectionModelChange, editMode, getId: _getId, isTotalSelected: _isTotalSelected, isRowSelectable, columnGroupingModel, }: DataTableProps<T, GetId>): {
|
|
8
|
+
export declare function useDataTableRenderer<T extends Record<PropertyKey, unknown>, GetId extends ((row: T) => any) | undefined = undefined>({ rows: _rows, columns: columnsProp, pinnedColumns, rowCount: totalRowsProp, initialState, pagination, paginationMode, paginationModel, onPaginationModelChange, sortModel: controlledSortModel, sortOrder: _sortOrder, selectionModel, onSortModelChange, onSelectionModelChange, editMode, getId: _getId, isTotalSelected: _isTotalSelected, isRowSelectable, columnGroupingModel, columnVisibilityModel, onColumnVisibilityModelChange, }: DataTableProps<T, GetId>): {
|
|
9
9
|
rowCount: number;
|
|
10
10
|
selectableRowCount: number;
|
|
11
11
|
page: number;
|
|
@@ -280,4 +280,5 @@ export declare const MotionSortIcon: import("framer-motion").CustomDomComponent<
|
|
|
280
280
|
ref?: ((instance: SVGSVGElement | null) => void) | React.RefObject<SVGSVGElement> | null | undefined;
|
|
281
281
|
}, "style" | "children" | "color" | "fontSize" | "shapeRendering" | "className" | "sx" | "viewBox" | "classes" | "htmlColor" | "inheritViewBox" | "titleAccess">>;
|
|
282
282
|
export declare const DefaultLoadingOverlay: () => React.JSX.Element;
|
|
283
|
+
export declare const DefaultNoRowsOverlay: () => React.JSX.Element;
|
|
283
284
|
export declare const Resizer: (ref: RefObject<HTMLTableCellElement>, targetRef?: RefObject<any>) => React.JSX.Element;
|
|
@@ -148,6 +148,7 @@ export type ActionsColumnDef<T extends Record<PropertyKey, string>, ID> = BaseCo
|
|
|
148
148
|
}) => ReactNode[];
|
|
149
149
|
};
|
|
150
150
|
export type ColumnDef<T extends Record<PropertyKey, any>, ID = unknown> = AutocompleteColumnDef<T, ID> | CurrencyColumnDef<T, ID> | DateColumnDef<T, ID> | NumberColumnDef<T, ID> | TextColumnDef<T, ID> | LongTextColumnDef<T, ID> | LinkColumnDef<T, ID> | SelectColumnDef<T, ID> | ActionsColumnDef<T, ID>;
|
|
151
|
+
export type ColumnVisibilityModel = Record<string, boolean>;
|
|
151
152
|
export type Sort = 'asc' | 'desc' | null;
|
|
152
153
|
export type SortModel<T extends Record<PropertyKey, any>> = {
|
|
153
154
|
[K in keyof T]: {
|
|
@@ -165,6 +166,12 @@ export type DataTableProps<T extends Record<PropertyKey, any>, GetId extends ((r
|
|
|
165
166
|
columns: ColumnDef<T, InferredIdType<T, GetId>>[];
|
|
166
167
|
pinnedColumns?: PinnedColumns;
|
|
167
168
|
columnGroupingModel?: ColumnGroupingModel<T, InferredIdType<T, GetId>>;
|
|
169
|
+
/**
|
|
170
|
+
* 컬럼의 표시/숨김 상태를 제어한다. field를 key로, boolean을 value로 사용한다.
|
|
171
|
+
* false로 설정된 컬럼만 숨겨지며, 모델에 포함되지 않은 컬럼은 기본적으로 표시된다.
|
|
172
|
+
*/
|
|
173
|
+
columnVisibilityModel?: ColumnVisibilityModel;
|
|
174
|
+
onColumnVisibilityModelChange?: (model: ColumnVisibilityModel) => void;
|
|
168
175
|
editMode?: boolean;
|
|
169
176
|
/**
|
|
170
177
|
* 체크박스가 있는 경우, 체크박스를 클릭했을 때 선택된 row의 index를 지정한다.
|
|
@@ -188,6 +195,9 @@ export type DataTableProps<T extends Record<PropertyKey, any>, GetId extends ((r
|
|
|
188
195
|
sorting: Partial<{
|
|
189
196
|
sortModel: SortModel<T>[];
|
|
190
197
|
}>;
|
|
198
|
+
columns: Partial<{
|
|
199
|
+
columnVisibilityModel: ColumnVisibilityModel;
|
|
200
|
+
}>;
|
|
191
201
|
}>;
|
|
192
202
|
pagination?: boolean;
|
|
193
203
|
paginationMode?: 'client' | 'server';
|
|
@@ -227,6 +237,7 @@ export type DataTableProps<T extends Record<PropertyKey, any>, GetId extends ((r
|
|
|
227
237
|
toolbar?: React.ElementType;
|
|
228
238
|
footer?: React.ElementType;
|
|
229
239
|
loadingOverlay?: React.ElementType;
|
|
240
|
+
noRowsOverlay?: React.ElementType;
|
|
230
241
|
};
|
|
231
242
|
slotProps?: {
|
|
232
243
|
checkbox?: Partial<{
|
|
@@ -239,6 +250,9 @@ export type DataTableProps<T extends Record<PropertyKey, any>, GetId extends ((r
|
|
|
239
250
|
background?: Partial<{
|
|
240
251
|
[key: string]: any;
|
|
241
252
|
}>;
|
|
253
|
+
noRowsOverlay?: Partial<{
|
|
254
|
+
[key: string]: any;
|
|
255
|
+
}>;
|
|
242
256
|
};
|
|
243
257
|
} & ComponentProps<typeof Table>;
|
|
244
258
|
export {};
|
|
@@ -3,8 +3,8 @@ export declare function extractFieldsFromGroupingModel<T extends Record<Property
|
|
|
3
3
|
export declare function reorderColumnsByGroupingModel<T extends Record<PropertyKey, any>, ID>(columns: ColumnDef<T, ID>[], columnGroupingModel: ColumnGroupingModel<T, ID>): ColumnDef<T, ID>[];
|
|
4
4
|
export declare function flattenColumnGroups<T extends Record<PropertyKey, any>, ID>(items: ColumnGroupingModel<T, ID> | ColumnDef<T, ID>[], groupPath?: string[], columnIndex?: {
|
|
5
5
|
current: number;
|
|
6
|
-
}): FlattenedColumn<T, ID>[];
|
|
7
|
-
export declare function calculateColumnGroups<T extends Record<PropertyKey, any>, ID>(columnGroupingModel: ColumnGroupingModel<T, ID>, columns: ColumnDef<T, ID>[]): {
|
|
6
|
+
}, visibleFields?: Set<string>): FlattenedColumn<T, ID>[];
|
|
7
|
+
export declare function calculateColumnGroups<T extends Record<PropertyKey, any>, ID>(columnGroupingModel: ColumnGroupingModel<T, ID>, columns: ColumnDef<T, ID>[], visibleFields?: Set<string>): {
|
|
8
8
|
groups: ProcessedColumnGroup[][];
|
|
9
9
|
maxLevel: number;
|
|
10
10
|
fieldsInGroupingModel: Set<keyof T>;
|
|
@@ -509,12 +509,13 @@ DataTable allows customization of various parts through `slots` and `slotProps`.
|
|
|
509
509
|
|
|
510
510
|
### Available Slots
|
|
511
511
|
|
|
512
|
-
| Slot | Description
|
|
513
|
-
| ---------------- |
|
|
514
|
-
| `checkbox` | Customize checkbox component
|
|
515
|
-
| `toolbar` | Table top toolbar
|
|
516
|
-
| `footer` | Table bottom footer
|
|
517
|
-
| `loadingOverlay` | Loading overlay
|
|
512
|
+
| Slot | Description |
|
|
513
|
+
| ---------------- | ----------------------------- |
|
|
514
|
+
| `checkbox` | Customize checkbox component |
|
|
515
|
+
| `toolbar` | Table top toolbar |
|
|
516
|
+
| `footer` | Table bottom footer |
|
|
517
|
+
| `loadingOverlay` | Loading overlay |
|
|
518
|
+
| `noRowsOverlay` | Empty state overlay (no rows) |
|
|
518
519
|
|
|
519
520
|
### Custom Toolbar
|
|
520
521
|
|
|
@@ -581,6 +582,154 @@ const CustomLoadingOverlay = () => (
|
|
|
581
582
|
<DataTable rows={rows} columns={columns} loading slots={{ loadingOverlay: CustomLoadingOverlay }} />;
|
|
582
583
|
```
|
|
583
584
|
|
|
585
|
+
### No Rows Overlay
|
|
586
|
+
|
|
587
|
+
When `rows` is empty and `loading` is not `true`, a no rows overlay is displayed in the table body.
|
|
588
|
+
|
|
589
|
+
```tsx
|
|
590
|
+
<DataTable
|
|
591
|
+
onPaginationModelChange={fn()}
|
|
592
|
+
onSelectionModelChange={fn()}
|
|
593
|
+
onRowClick={fn()}
|
|
594
|
+
columns={[{
|
|
595
|
+
field: 'dessert',
|
|
596
|
+
headerName: 'Dessert (100g serving)',
|
|
597
|
+
width: '40%'
|
|
598
|
+
}, {
|
|
599
|
+
field: 'calories',
|
|
600
|
+
headerName: 'Calories',
|
|
601
|
+
type: 'number'
|
|
602
|
+
}, {
|
|
603
|
+
field: 'fat',
|
|
604
|
+
headerName: 'Fat (g)',
|
|
605
|
+
type: 'number'
|
|
606
|
+
}, {
|
|
607
|
+
field: 'carbs',
|
|
608
|
+
headerName: 'Carbs (g)',
|
|
609
|
+
type: 'number'
|
|
610
|
+
}, {
|
|
611
|
+
field: 'protein',
|
|
612
|
+
headerName: 'Protein (g)',
|
|
613
|
+
type: 'number'
|
|
614
|
+
}]}
|
|
615
|
+
rows={[]}
|
|
616
|
+
noWrap
|
|
617
|
+
/>
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
### Custom No Rows Overlay
|
|
621
|
+
|
|
622
|
+
You can customize the empty state UI using `slots.noRowsOverlay`.
|
|
623
|
+
|
|
624
|
+
```tsx
|
|
625
|
+
<DataTable rows={[]} columns={tableColumns} noWrap slots={{
|
|
626
|
+
noRowsOverlay: CustomOverlay
|
|
627
|
+
}} slotProps={{
|
|
628
|
+
noRowsOverlay: {
|
|
629
|
+
message: 'Custom message via slotProps'
|
|
630
|
+
}
|
|
631
|
+
}} />
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
```tsx
|
|
635
|
+
const CustomNoRowsOverlay = ({ message }: { message?: string }) => (
|
|
636
|
+
<Stack alignItems="center" spacing={1}>
|
|
637
|
+
<Typography level="title-md">No data available</Typography>
|
|
638
|
+
<Typography level="body-sm" textColor="text.secondary">
|
|
639
|
+
{message || 'Try adding new records.'}
|
|
640
|
+
</Typography>
|
|
641
|
+
</Stack>
|
|
642
|
+
);
|
|
643
|
+
|
|
644
|
+
<DataTable
|
|
645
|
+
rows={[]}
|
|
646
|
+
columns={columns}
|
|
647
|
+
slots={{ noRowsOverlay: CustomNoRowsOverlay }}
|
|
648
|
+
slotProps={{ noRowsOverlay: { message: 'Custom message via slotProps' } }}
|
|
649
|
+
/>;
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
### No Rows Overlay with Checkbox
|
|
653
|
+
|
|
654
|
+
The overlay correctly spans the full table width including the checkbox column.
|
|
655
|
+
|
|
656
|
+
```tsx
|
|
657
|
+
<DataTable
|
|
658
|
+
onPaginationModelChange={fn()}
|
|
659
|
+
onSelectionModelChange={fn()}
|
|
660
|
+
onRowClick={fn()}
|
|
661
|
+
columns={[{
|
|
662
|
+
field: 'dessert',
|
|
663
|
+
headerName: 'Dessert (100g serving)',
|
|
664
|
+
width: '40%'
|
|
665
|
+
}, {
|
|
666
|
+
field: 'calories',
|
|
667
|
+
headerName: 'Calories',
|
|
668
|
+
type: 'number'
|
|
669
|
+
}, {
|
|
670
|
+
field: 'fat',
|
|
671
|
+
headerName: 'Fat (g)',
|
|
672
|
+
type: 'number'
|
|
673
|
+
}, {
|
|
674
|
+
field: 'carbs',
|
|
675
|
+
headerName: 'Carbs (g)',
|
|
676
|
+
type: 'number'
|
|
677
|
+
}, {
|
|
678
|
+
field: 'protein',
|
|
679
|
+
headerName: 'Protein (g)',
|
|
680
|
+
type: 'number'
|
|
681
|
+
}]}
|
|
682
|
+
rows={[]}
|
|
683
|
+
noWrap
|
|
684
|
+
checkboxSelection
|
|
685
|
+
/>
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
### No Rows Overlay Loading Priority
|
|
689
|
+
|
|
690
|
+
When `loading` is `true`, the loading overlay takes priority over the no rows overlay.
|
|
691
|
+
|
|
692
|
+
```tsx
|
|
693
|
+
<Stack gap={2}>
|
|
694
|
+
<Button onClick={() => setLoading(!loading)}>{loading ? 'Stop Loading' : 'Start Loading'}</Button>
|
|
695
|
+
<Typography level="body-sm">
|
|
696
|
+
{loading ? 'Loading overlay is shown (noRowsOverlay hidden)' : 'NoRowsOverlay is shown'}
|
|
697
|
+
</Typography>
|
|
698
|
+
<DataTable rows={[]} columns={tableColumns} loading={loading} noWrap slotProps={{
|
|
699
|
+
background: {
|
|
700
|
+
style: {
|
|
701
|
+
height: '300px'
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
}} />
|
|
705
|
+
</Stack>
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
### Combined Custom Loading + No Rows Overlay
|
|
709
|
+
|
|
710
|
+
Both `loadingOverlay` and `noRowsOverlay` slots can be customized simultaneously.
|
|
711
|
+
|
|
712
|
+
```tsx
|
|
713
|
+
<Stack gap={2}>
|
|
714
|
+
<Stack direction="row" gap={1} alignItems="center">
|
|
715
|
+
<Button onClick={() => setLoading(!loading)}>{loading ? 'Stop Loading' : 'Start Loading'}</Button>
|
|
716
|
+
<Typography level="body-xs" textColor="text.tertiary">
|
|
717
|
+
{loading ? 'Custom loading overlay shown' : 'Custom no rows overlay shown'}
|
|
718
|
+
</Typography>
|
|
719
|
+
</Stack>
|
|
720
|
+
<DataTable rows={[]} columns={tableColumns} loading={loading} noWrap slots={{
|
|
721
|
+
loadingOverlay: CustomLoadingOverlay,
|
|
722
|
+
noRowsOverlay: CustomNoRowsOverlay
|
|
723
|
+
}} slotProps={{
|
|
724
|
+
background: {
|
|
725
|
+
style: {
|
|
726
|
+
height: '300px'
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
}} />
|
|
730
|
+
</Stack>
|
|
731
|
+
```
|
|
732
|
+
|
|
584
733
|
### Custom Checkbox
|
|
585
734
|
|
|
586
735
|
```tsx
|
|
@@ -865,6 +1014,106 @@ const columnGroupingModel = [
|
|
|
865
1014
|
<DataTable rows={rows} columns={columns} columnGroupingModel={columnGroupingModel} />;
|
|
866
1015
|
```
|
|
867
1016
|
|
|
1017
|
+
### Column Visibility
|
|
1018
|
+
|
|
1019
|
+
You can control which columns are visible using `columnVisibilityModel`.
|
|
1020
|
+
Columns set to `false` are hidden. Columns not in the model are visible by default.
|
|
1021
|
+
Hidden columns are completely removed from the DOM for optimal rendering performance.
|
|
1022
|
+
|
|
1023
|
+
```tsx
|
|
1024
|
+
<Stack spacing={2}>
|
|
1025
|
+
<Stack direction="row" spacing={1} sx={{
|
|
1026
|
+
flexWrap: 'wrap'
|
|
1027
|
+
}}>
|
|
1028
|
+
{allColumns.map(col => <label key={col.field as string} style={{
|
|
1029
|
+
display: 'flex',
|
|
1030
|
+
alignItems: 'center',
|
|
1031
|
+
gap: 4
|
|
1032
|
+
}}>
|
|
1033
|
+
<input type="checkbox" checked={visibilityModel[col.field as string] !== false} onChange={e => setVisibilityModel(prev => ({
|
|
1034
|
+
...prev,
|
|
1035
|
+
[col.field as string]: e.target.checked
|
|
1036
|
+
}))} />
|
|
1037
|
+
{col.headerName}
|
|
1038
|
+
</label>)}
|
|
1039
|
+
</Stack>
|
|
1040
|
+
<DataTable rows={rows2} columns={allColumns} columnVisibilityModel={visibilityModel} onColumnVisibilityModelChange={setVisibilityModel} noWrap />
|
|
1041
|
+
</Stack>
|
|
1042
|
+
```
|
|
1043
|
+
|
|
1044
|
+
#### Controlled Mode
|
|
1045
|
+
|
|
1046
|
+
```tsx
|
|
1047
|
+
const [visibilityModel, setVisibilityModel] = useState({ fat: false });
|
|
1048
|
+
|
|
1049
|
+
<DataTable
|
|
1050
|
+
rows={rows}
|
|
1051
|
+
columns={columns}
|
|
1052
|
+
columnVisibilityModel={visibilityModel}
|
|
1053
|
+
onColumnVisibilityModelChange={setVisibilityModel}
|
|
1054
|
+
/>
|
|
1055
|
+
```
|
|
1056
|
+
|
|
1057
|
+
#### Uncontrolled Mode (initialState)
|
|
1058
|
+
|
|
1059
|
+
```tsx
|
|
1060
|
+
<DataTable
|
|
1061
|
+
rows={rows}
|
|
1062
|
+
columns={columns}
|
|
1063
|
+
initialState={{
|
|
1064
|
+
columns: { columnVisibilityModel: { fat: false, carbs: false } },
|
|
1065
|
+
}}
|
|
1066
|
+
/>
|
|
1067
|
+
```
|
|
1068
|
+
|
|
1069
|
+
#### Column Visibility with Column Groups
|
|
1070
|
+
|
|
1071
|
+
```tsx
|
|
1072
|
+
<Stack spacing={2}>
|
|
1073
|
+
<Stack direction="row" spacing={1} sx={{
|
|
1074
|
+
flexWrap: 'wrap'
|
|
1075
|
+
}}>
|
|
1076
|
+
{columns.map(col => <label key={col.field as string} style={{
|
|
1077
|
+
display: 'flex',
|
|
1078
|
+
alignItems: 'center',
|
|
1079
|
+
gap: 4
|
|
1080
|
+
}}>
|
|
1081
|
+
<input type="checkbox" checked={visibilityModel[col.field as string] !== false} onChange={e => setVisibilityModel(prev => ({
|
|
1082
|
+
...prev,
|
|
1083
|
+
[col.field as string]: e.target.checked
|
|
1084
|
+
}))} />
|
|
1085
|
+
{col.headerName}
|
|
1086
|
+
</label>)}
|
|
1087
|
+
</Stack>
|
|
1088
|
+
<DataTable rows={rows4} columns={columns} columnGroupingModel={[{
|
|
1089
|
+
groupId: 'group1',
|
|
1090
|
+
headerName: 'Group 1',
|
|
1091
|
+
children: [{
|
|
1092
|
+
field: 'id'
|
|
1093
|
+
}, {
|
|
1094
|
+
field: 'number'
|
|
1095
|
+
}, {
|
|
1096
|
+
field: 'string'
|
|
1097
|
+
}]
|
|
1098
|
+
}, {
|
|
1099
|
+
groupId: 'group2',
|
|
1100
|
+
headerName: 'Group 2',
|
|
1101
|
+
children: [{
|
|
1102
|
+
field: 'date'
|
|
1103
|
+
}, {
|
|
1104
|
+
field: 'object'
|
|
1105
|
+
}]
|
|
1106
|
+
}]} columnVisibilityModel={visibilityModel} onColumnVisibilityModelChange={setVisibilityModel} noWrap />
|
|
1107
|
+
</Stack>
|
|
1108
|
+
```
|
|
1109
|
+
|
|
1110
|
+
#### Notes
|
|
1111
|
+
|
|
1112
|
+
- Hidden columns are completely removed from the DOM for optimal performance.
|
|
1113
|
+
- Sorting on hidden columns is preserved — row order is maintained even if the sort column is hidden.
|
|
1114
|
+
- Works with column grouping: hidden columns reduce group colspan, and fully hidden groups disappear.
|
|
1115
|
+
- Works with pinned columns: hidden pinned columns are excluded from sticky position calculations.
|
|
1116
|
+
|
|
868
1117
|
### Column Resizing
|
|
869
1118
|
|
|
870
1119
|
Setting `resizable: true` on a column allows you to adjust the column width by dragging.
|