@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.
@@ -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.