@cronocode/react-box 3.1.10 → 3.1.12
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/BOX_AI_CONTEXT.md +85 -215
- package/components/dataGrid/components/dataGridCellRowDetail.d.ts +6 -0
- package/components/dataGrid/components/dataGridDetailRow.d.ts +6 -0
- package/components/dataGrid/components/dataGridEmptyColumns.d.ts +6 -1
- package/components/dataGrid/components/dataGridPagination.d.ts +1 -1
- package/components/dataGrid/contracts/dataGridContract.d.ts +49 -3
- package/components/dataGrid/models/detailRowModel.d.ts +16 -0
- package/components/dataGrid/models/gridModel.d.ts +20 -2
- package/components/dataGrid/models/groupRowModel.d.ts +2 -1
- package/components/dataGrid/models/rowModel.d.ts +3 -1
- package/components/dataGrid.cjs +1 -1
- package/components/dataGrid.mjs +921 -585
- package/components/semantics.d.ts +25 -25
- package/core/boxStyles.d.ts +4 -2
- package/core/extends/boxComponents.d.ts +21 -0
- package/core.cjs +3 -3
- package/core.mjs +444 -412
- package/package.json +1 -1
package/BOX_AI_CONTEXT.md
CHANGED
|
@@ -603,6 +603,24 @@ Box.components({
|
|
|
603
603
|
</Box>;
|
|
604
604
|
```
|
|
605
605
|
|
|
606
|
+
#### Component Inheritance with `extends`
|
|
607
|
+
|
|
608
|
+
Components can inherit from other components using the `extends` property. The base component's full style tree (styles, variants, children) is used as the foundation, and the extending component's definitions are deep-merged on top:
|
|
609
|
+
|
|
610
|
+
```tsx
|
|
611
|
+
Box.components({
|
|
612
|
+
subgrid: {
|
|
613
|
+
extends: 'datagrid', // inherit all datagrid styles, variants, and children
|
|
614
|
+
styles: { b: 0, borderRadius: 0, shadow: 'none' },
|
|
615
|
+
children: {
|
|
616
|
+
header: { children: { cell: { styles: { fontSize: 12 } } } },
|
|
617
|
+
},
|
|
618
|
+
},
|
|
619
|
+
});
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
This is especially useful for DataGrid, where the internal style tree is complex (pinning, sticky headers, hover groups, etc.). With `extends`, you only need to declare overrides.
|
|
623
|
+
|
|
606
624
|
---
|
|
607
625
|
|
|
608
626
|
## Extension System
|
|
@@ -858,250 +876,102 @@ resetStyles();
|
|
|
858
876
|
|
|
859
877
|
## DataGrid Component
|
|
860
878
|
|
|
861
|
-
|
|
879
|
+
> **Full documentation:** See [`../docs/DATAGRID.md`](../docs/DATAGRID.md) for complete API reference, all features, component tree, style customization, and designs system.
|
|
862
880
|
|
|
863
|
-
|
|
881
|
+
A feature-rich data grid with sorting, filtering, grouping, row selection, column pinning, row detail, server-side pagination, virtualization, and full style customization via the component design system.
|
|
864
882
|
|
|
865
883
|
```tsx
|
|
866
884
|
import DataGrid from '@cronocode/react-box/components/dataGrid';
|
|
885
|
+
```
|
|
867
886
|
|
|
868
|
-
|
|
869
|
-
{ id: 1, name: 'John', email: 'john@example.com', age: 30 },
|
|
870
|
-
{ id: 2, name: 'Jane', email: 'jane@example.com', age: 25 },
|
|
871
|
-
];
|
|
887
|
+
### Quick Reference
|
|
872
888
|
|
|
889
|
+
```tsx
|
|
873
890
|
<DataGrid
|
|
874
|
-
data={
|
|
891
|
+
data={users}
|
|
875
892
|
def={{
|
|
893
|
+
rowKey: 'id',
|
|
894
|
+
title: 'Users',
|
|
895
|
+
topBar: true,
|
|
896
|
+
bottomBar: true,
|
|
897
|
+
globalFilter: true,
|
|
898
|
+
rowSelection: { pinned: true },
|
|
899
|
+
showRowNumber: { pinned: true },
|
|
900
|
+
rowHeight: 40,
|
|
901
|
+
visibleRowsCount: 15, // or 'all' to disable virtualization
|
|
876
902
|
columns: [
|
|
877
|
-
{ key: 'name', header: 'Name' },
|
|
878
|
-
{ key: '
|
|
879
|
-
{ key: '
|
|
903
|
+
{ key: 'name', header: 'Name', filterable: true },
|
|
904
|
+
{ key: 'age', header: 'Age', width: 80, align: 'right', filterable: { type: 'number' } },
|
|
905
|
+
{ key: 'email', header: 'Email', width: 250, filterable: true },
|
|
906
|
+
{ key: 'status', header: 'Status', filterable: { type: 'multiselect' } },
|
|
907
|
+
{ key: 'country', header: 'Country', pin: 'RIGHT' },
|
|
880
908
|
],
|
|
909
|
+
rowDetail: {
|
|
910
|
+
content: (user) => <UserDetails user={user} />,
|
|
911
|
+
height: 'auto',
|
|
912
|
+
expandOnRowClick: true,
|
|
913
|
+
},
|
|
914
|
+
// pagination: { totalCount: 500, pageSize: 25 }, // for server-side pagination
|
|
881
915
|
}}
|
|
882
|
-
|
|
916
|
+
component="subgrid" // optional: use a different component style tree
|
|
917
|
+
onSelectionChange={(e) => console.log(e.selectedRowKeys)}
|
|
918
|
+
// page={1} // controlled pagination
|
|
919
|
+
// onPageChange={(p, size) => {}} // page change handler
|
|
920
|
+
// onSortChange={(col, dir) => {}} // server-side sort handler
|
|
921
|
+
// onServerStateChange={(state) => fetch(state)} // unified server state callback
|
|
922
|
+
/>
|
|
883
923
|
```
|
|
884
924
|
|
|
885
|
-
###
|
|
886
|
-
|
|
887
|
-
| Prop | Type | Description |
|
|
888
|
-
|------|------|-------------|
|
|
889
|
-
| `columns` | `ColumnType[]` | Column definitions (required) |
|
|
890
|
-
| `rowKey` | `keyof TRow \| (row) => Key` | Unique key for each row |
|
|
891
|
-
| `rowHeight` | `number` | Row height in pixels (default: 36) |
|
|
892
|
-
| `visibleRowsCount` | `number` | Number of visible rows (default: 10) |
|
|
893
|
-
| `showRowNumber` | `boolean \| { pinned?: boolean; width?: number }` | Show row numbers |
|
|
894
|
-
| `rowSelection` | `boolean \| { pinned?: boolean }` | Enable row selection checkboxes |
|
|
895
|
-
| `topBar` | `boolean` | Show top bar with title and controls |
|
|
896
|
-
| `bottomBar` | `boolean` | Show bottom bar with row count |
|
|
897
|
-
| `title` | `ReactNode` | Title displayed in top bar |
|
|
898
|
-
| `topBarContent` | `ReactNode` | Custom content in top bar |
|
|
899
|
-
| `globalFilter` | `boolean` | Enable global search filter |
|
|
900
|
-
| `globalFilterKeys` | `Key[]` | Columns to search (default: all) |
|
|
901
|
-
| `sortable` | `boolean` | Enable sorting globally (default: true) |
|
|
902
|
-
| `resizable` | `boolean` | Enable column resizing globally (default: true) |
|
|
903
|
-
| `noDataComponent` | `ReactNode` | Custom empty state component |
|
|
904
|
-
|
|
905
|
-
### ColumnType Props
|
|
906
|
-
|
|
907
|
-
| Prop | Type | Description |
|
|
908
|
-
|------|------|-------------|
|
|
909
|
-
| `key` | `string \| number` | Column key matching data property (required) |
|
|
910
|
-
| `header` | `string` | Column header text |
|
|
911
|
-
| `width` | `number` | Column width in pixels |
|
|
912
|
-
| `align` | `'left' \| 'right' \| 'center'` | Text alignment |
|
|
913
|
-
| `pin` | `'LEFT' \| 'RIGHT'` | Pin column to side |
|
|
914
|
-
| `columns` | `ColumnType[]` | Nested columns for grouping |
|
|
915
|
-
| `sortable` | `boolean` | Override global sortable setting |
|
|
916
|
-
| `resizable` | `boolean` | Override global resizable setting |
|
|
917
|
-
| `flexible` | `boolean` | Participate in flex distribution (default: true) |
|
|
918
|
-
| `filterable` | `boolean \| FilterConfig` | Enable column filtering |
|
|
919
|
-
| `Cell` | `React.ComponentType<{ cell }>` | Custom cell renderer |
|
|
920
|
-
|
|
921
|
-
### DataGridProps
|
|
925
|
+
### Key Props
|
|
922
926
|
|
|
923
927
|
| Prop | Type | Description |
|
|
924
928
|
|------|------|-------------|
|
|
925
|
-
| `data` | `TRow[]` |
|
|
926
|
-
| `def` | `GridDefinition` | Grid
|
|
927
|
-
| `
|
|
929
|
+
| `data` | `TRow[]` | Row data array (required) |
|
|
930
|
+
| `def` | `GridDefinition` | Grid configuration (required) |
|
|
931
|
+
| `component` | `string` | Component style tree name (default: `'datagrid'`) |
|
|
932
|
+
| `loading` | `boolean` | Loading state |
|
|
933
|
+
| `filters` | `((row: TRow) => boolean)[]` | External predicate filters |
|
|
934
|
+
| `page` | `number` | Controlled page (1-indexed) |
|
|
935
|
+
| `onPageChange` | `(page, pageSize) => void` | Page change callback |
|
|
936
|
+
| `onSortChange` | `(columnKey, direction) => void` | Sort change callback |
|
|
937
|
+
| `onServerStateChange` | `(state: ServerState) => void` | Unified callback with full state (page, pageSize, sort, filters) |
|
|
928
938
|
| `onSelectionChange` | `(event) => void` | Selection change callback |
|
|
929
|
-
| `
|
|
930
|
-
| `onGlobalFilterChange` | `(value) => void` | Global filter change callback |
|
|
931
|
-
| `columnFilters` | `ColumnFilters` | Controlled column filters |
|
|
932
|
-
| `onColumnFiltersChange` | `(filters) => void` | Column filters change callback |
|
|
939
|
+
| `expandedRowKeys` | `Key[]` | Controlled expanded rows |
|
|
933
940
|
|
|
934
941
|
### Filter Types
|
|
935
942
|
|
|
936
943
|
```tsx
|
|
937
|
-
// Text
|
|
938
|
-
{ key: '
|
|
939
|
-
{ key: '
|
|
940
|
-
|
|
941
|
-
// Number filter - with comparison operators
|
|
942
|
-
{ key: 'age', filterable: { type: 'number', min: 0, max: 100 } }
|
|
943
|
-
|
|
944
|
-
// Multiselect filter - dropdown with checkboxes
|
|
945
|
-
{ key: 'status', filterable: { type: 'multiselect' } }
|
|
946
|
-
{ key: 'status', filterable: {
|
|
947
|
-
type: 'multiselect',
|
|
948
|
-
options: [
|
|
949
|
-
{ label: 'Active', value: 'active' },
|
|
950
|
-
{ label: 'Inactive', value: 'inactive' },
|
|
951
|
-
]
|
|
952
|
-
}}
|
|
944
|
+
{ key: 'name', filterable: true } // Text (fuzzy)
|
|
945
|
+
{ key: 'age', filterable: { type: 'number', min: 0, max: 100 } } // Number
|
|
946
|
+
{ key: 'status', filterable: { type: 'multiselect' } } // Multiselect
|
|
953
947
|
```
|
|
954
948
|
|
|
955
|
-
###
|
|
956
|
-
|
|
957
|
-
```tsx
|
|
958
|
-
columns: [
|
|
959
|
-
{
|
|
960
|
-
key: 'personal',
|
|
961
|
-
header: 'Personal Info',
|
|
962
|
-
columns: [
|
|
963
|
-
{ key: 'firstName', header: 'First Name' },
|
|
964
|
-
{ key: 'lastName', header: 'Last Name' },
|
|
965
|
-
],
|
|
966
|
-
},
|
|
967
|
-
{
|
|
968
|
-
key: 'contact',
|
|
969
|
-
header: 'Contact',
|
|
970
|
-
columns: [
|
|
971
|
-
{ key: 'email', header: 'Email' },
|
|
972
|
-
{ key: 'phone', header: 'Phone' },
|
|
973
|
-
],
|
|
974
|
-
},
|
|
975
|
-
]
|
|
976
|
-
```
|
|
949
|
+
### Style Customization
|
|
977
950
|
|
|
978
|
-
|
|
951
|
+
Every subcomponent is customizable via `Box.components()`. Register a separate component tree for different visual styles:
|
|
979
952
|
|
|
980
953
|
```tsx
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
py={1}
|
|
989
|
-
borderRadius={4}
|
|
990
|
-
bgColor={cell.value === 'active' ? 'green-100' : 'red-100'}
|
|
991
|
-
color={cell.value === 'active' ? 'green-800' : 'red-800'}
|
|
992
|
-
>
|
|
993
|
-
{cell.value}
|
|
994
|
-
</Box>
|
|
995
|
-
),
|
|
954
|
+
Box.components({
|
|
955
|
+
// Customize default datagrid
|
|
956
|
+
datagrid: {
|
|
957
|
+
children: {
|
|
958
|
+
body: { children: { detailRow: { styles: { bgColor: 'blue-50' } } } },
|
|
959
|
+
header: { children: { cell: { styles: { textTransform: 'uppercase' } } } },
|
|
960
|
+
},
|
|
996
961
|
},
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
962
|
+
// Extend datagrid styles for embedded grids — inherits all internal styles (pinning, sticky, etc.)
|
|
963
|
+
subgrid: {
|
|
964
|
+
extends: 'datagrid',
|
|
965
|
+
styles: { b: 0, shadow: 'none', bgColor: 'transparent' },
|
|
966
|
+
children: {
|
|
967
|
+
header: { children: { cell: { styles: { fontSize: 12, py: 1 } } } },
|
|
968
|
+
body: { children: { cell: { styles: { fontSize: 13 } } } },
|
|
969
|
+
},
|
|
1003
970
|
},
|
|
1004
|
-
|
|
1005
|
-
```
|
|
1006
|
-
|
|
1007
|
-
The `cell` object provides:
|
|
1008
|
-
- `cell.value` - Cell value
|
|
1009
|
-
- `cell.row` - Full row data
|
|
1010
|
-
- `cell.column` - Column model
|
|
1011
|
-
|
|
1012
|
-
### Row Selection
|
|
1013
|
-
|
|
1014
|
-
```tsx
|
|
1015
|
-
<DataGrid
|
|
1016
|
-
data={data}
|
|
1017
|
-
def={{
|
|
1018
|
-
rowSelection: true, // or { pinned: true } to pin checkbox column
|
|
1019
|
-
columns: [...],
|
|
1020
|
-
}}
|
|
1021
|
-
onSelectionChange={(event) => {
|
|
1022
|
-
console.log('Selected keys:', event.selectedRowKeys);
|
|
1023
|
-
console.log('Action:', event.action); // 'select' | 'deselect'
|
|
1024
|
-
console.log('All selected:', event.isAllSelected);
|
|
1025
|
-
}}
|
|
1026
|
-
/>
|
|
1027
|
-
```
|
|
1028
|
-
|
|
1029
|
-
### Sorting and Resizing Control
|
|
1030
|
-
|
|
1031
|
-
```tsx
|
|
1032
|
-
// Disable globally
|
|
1033
|
-
def={{
|
|
1034
|
-
sortable: false,
|
|
1035
|
-
resizable: false,
|
|
1036
|
-
columns: [...]
|
|
1037
|
-
}}
|
|
1038
|
-
|
|
1039
|
-
// Override per column
|
|
1040
|
-
def={{
|
|
1041
|
-
sortable: false, // Global: no sorting
|
|
1042
|
-
columns: [
|
|
1043
|
-
{ key: 'id', header: 'ID' }, // Not sortable (inherits global)
|
|
1044
|
-
{ key: 'name', header: 'Name', sortable: true }, // Sortable (override)
|
|
1045
|
-
]
|
|
1046
|
-
}}
|
|
1047
|
-
```
|
|
1048
|
-
|
|
1049
|
-
### Flexible Column Sizing
|
|
1050
|
-
|
|
1051
|
-
Columns automatically fill available space proportionally. Use `flexible: false` for fixed-width columns.
|
|
1052
|
-
|
|
1053
|
-
```tsx
|
|
1054
|
-
columns: [
|
|
1055
|
-
{ key: 'id', header: 'ID', width: 60, flexible: false }, // Fixed at 60px
|
|
1056
|
-
{ key: 'name', header: 'Name', width: 200 }, // Flexes (200 base)
|
|
1057
|
-
{ key: 'email', header: 'Email', width: 300 }, // Flexes more (300 base)
|
|
1058
|
-
]
|
|
1059
|
-
```
|
|
1060
|
-
|
|
1061
|
-
### Custom Empty State
|
|
1062
|
-
|
|
1063
|
-
```tsx
|
|
1064
|
-
def={{
|
|
1065
|
-
columns: [...],
|
|
1066
|
-
noDataComponent: (
|
|
1067
|
-
<Flex d="column" ai="center" gap={4} p={8}>
|
|
1068
|
-
<Box fontSize={48}>📭</Box>
|
|
1069
|
-
<Box color="gray-500">No records found</Box>
|
|
1070
|
-
</Flex>
|
|
1071
|
-
),
|
|
1072
|
-
}}
|
|
1073
|
-
```
|
|
1074
|
-
|
|
1075
|
-
### Full-Featured Example
|
|
971
|
+
});
|
|
1076
972
|
|
|
1077
|
-
|
|
1078
|
-
<DataGrid
|
|
1079
|
-
data={users}
|
|
1080
|
-
def={{
|
|
1081
|
-
title: 'Users Table',
|
|
1082
|
-
topBar: true,
|
|
1083
|
-
bottomBar: true,
|
|
1084
|
-
globalFilter: true,
|
|
1085
|
-
rowSelection: { pinned: true },
|
|
1086
|
-
showRowNumber: { pinned: true },
|
|
1087
|
-
rowHeight: 40,
|
|
1088
|
-
visibleRowsCount: 10,
|
|
1089
|
-
columns: [
|
|
1090
|
-
{
|
|
1091
|
-
key: 'personal',
|
|
1092
|
-
header: 'Personal',
|
|
1093
|
-
columns: [
|
|
1094
|
-
{ key: 'name', header: 'Name', filterable: true },
|
|
1095
|
-
{ key: 'age', header: 'Age', width: 80, align: 'right', filterable: { type: 'number' } },
|
|
1096
|
-
],
|
|
1097
|
-
},
|
|
1098
|
-
{ key: 'email', header: 'Email', width: 250, filterable: true },
|
|
1099
|
-
{ key: 'status', header: 'Status', filterable: { type: 'multiselect' } },
|
|
1100
|
-
{ key: 'country', header: 'Country', pin: 'RIGHT' },
|
|
1101
|
-
],
|
|
1102
|
-
}}
|
|
1103
|
-
onSelectionChange={(e) => setSelected(e.selectedRowKeys)}
|
|
1104
|
-
/>
|
|
973
|
+
// Use it — all children automatically resolve under "subgrid.*"
|
|
974
|
+
<DataGrid component="subgrid" data={data} def={def} />
|
|
1105
975
|
```
|
|
1106
976
|
|
|
1107
977
|
---
|
|
@@ -1 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import { default as GridModel } from '../models/gridModel';
|
|
2
|
+
interface Props<TRow> {
|
|
3
|
+
grid: GridModel<TRow>;
|
|
4
|
+
}
|
|
5
|
+
export default function DataGridEmptyColumns<TRow>(props: Props<TRow>): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export {};
|
|
@@ -2,5 +2,5 @@ import { default as GridModel } from '../models/gridModel';
|
|
|
2
2
|
interface Props<TRow> {
|
|
3
3
|
grid: GridModel<TRow>;
|
|
4
4
|
}
|
|
5
|
-
export default function DataGridPagination<TRow>(
|
|
5
|
+
export default function DataGridPagination<TRow>(props: Props<TRow>): import("react/jsx-runtime").JSX.Element | null;
|
|
6
6
|
export {};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ComponentsAndVariants } from '../../../types';
|
|
1
2
|
import { default as CellModel } from '../models/cellModel';
|
|
2
3
|
export type Key = string | number;
|
|
3
4
|
export type PinPosition = 'LEFT' | 'RIGHT';
|
|
@@ -15,9 +16,22 @@ export interface PaginationState {
|
|
|
15
16
|
totalItems: number;
|
|
16
17
|
totalPages: number;
|
|
17
18
|
}
|
|
18
|
-
|
|
19
|
+
/** Server-side pagination configuration on GridDefinition */
|
|
20
|
+
export interface PaginationConfig {
|
|
21
|
+
/** Total number of items across all pages (from server response) */
|
|
22
|
+
totalCount: number;
|
|
23
|
+
/** Page size override. If omitted, defaults to visibleRowsCount (or 10). */
|
|
24
|
+
pageSize?: number;
|
|
25
|
+
}
|
|
26
|
+
/** Snapshot of all server-relevant grid state, passed to onServerStateChange */
|
|
27
|
+
export interface ServerState<TRow> {
|
|
28
|
+
page: number;
|
|
19
29
|
pageSize: number;
|
|
20
|
-
|
|
30
|
+
sortColumn: Key | undefined;
|
|
31
|
+
sortDirection: SortDirection | undefined;
|
|
32
|
+
columnFilters: ColumnFilters<TRow>;
|
|
33
|
+
globalFilterValue: string;
|
|
34
|
+
}
|
|
21
35
|
/** Filter type for column-level filtering */
|
|
22
36
|
export type ColumnFilterType = 'text' | 'number' | 'multiselect';
|
|
23
37
|
/** Text filter configuration (fuzzy search) */
|
|
@@ -58,6 +72,19 @@ export interface ColumnFilterConfig {
|
|
|
58
72
|
/** For number: max value */
|
|
59
73
|
max?: number;
|
|
60
74
|
}
|
|
75
|
+
/** Configuration for expandable row detail panel */
|
|
76
|
+
export interface RowDetailConfig<TRow> {
|
|
77
|
+
/** Render function for the detail content */
|
|
78
|
+
content: (row: TRow) => React.ReactNode;
|
|
79
|
+
/** Height of the detail row. 'auto' sizes to content. Default: 'auto' */
|
|
80
|
+
height?: 'auto' | number | ((row: TRow) => number);
|
|
81
|
+
/** Whether clicking the row also toggles expansion. Default: false */
|
|
82
|
+
expandOnRowClick?: boolean;
|
|
83
|
+
/** Pin the expand column to LEFT. Default: false */
|
|
84
|
+
pinned?: boolean;
|
|
85
|
+
/** Width of the expand column. Default: 50 */
|
|
86
|
+
expandColumnWidth?: number;
|
|
87
|
+
}
|
|
61
88
|
export interface ColumnType<TRow> {
|
|
62
89
|
key: Key;
|
|
63
90
|
header?: string;
|
|
@@ -88,7 +115,8 @@ export interface GridDefinition<TRow> {
|
|
|
88
115
|
pinned?: boolean;
|
|
89
116
|
};
|
|
90
117
|
rowHeight?: number;
|
|
91
|
-
|
|
118
|
+
/** Number of visible rows. Set to 'all' to render all rows without virtualization or vertical scrollbar. */
|
|
119
|
+
visibleRowsCount?: number | 'all';
|
|
92
120
|
topBar?: boolean;
|
|
93
121
|
bottomBar?: boolean;
|
|
94
122
|
/** Title displayed in the top bar */
|
|
@@ -105,8 +133,14 @@ export interface GridDefinition<TRow> {
|
|
|
105
133
|
resizable?: boolean;
|
|
106
134
|
/** Custom component to render when data is empty */
|
|
107
135
|
noDataComponent?: React.ReactNode;
|
|
136
|
+
/** Enable expandable row detail panel */
|
|
137
|
+
rowDetail?: RowDetailConfig<TRow>;
|
|
138
|
+
/** Server-side pagination. Provide totalCount from the API response. */
|
|
139
|
+
pagination?: PaginationConfig;
|
|
108
140
|
}
|
|
109
141
|
export interface DataGridProps<TRow> {
|
|
142
|
+
/** Component name for style resolution. Default: 'datagrid'. Set to a custom name to use a different component style tree. */
|
|
143
|
+
component?: keyof ComponentsAndVariants;
|
|
110
144
|
data: TRow[];
|
|
111
145
|
def: GridDefinition<TRow>;
|
|
112
146
|
loading?: boolean;
|
|
@@ -121,6 +155,18 @@ export interface DataGridProps<TRow> {
|
|
|
121
155
|
onColumnFiltersChange?: (filters: ColumnFilters<TRow>) => void;
|
|
122
156
|
/** External predicate filters applied before global/column filters. Memoize with useMemo for performance. */
|
|
123
157
|
filters?: ((row: TRow) => boolean)[];
|
|
158
|
+
/** Controlled expanded detail row keys */
|
|
159
|
+
expandedRowKeys?: Key[];
|
|
160
|
+
/** Callback when expanded detail rows change */
|
|
161
|
+
onExpandedRowKeysChange?: (keys: Key[]) => void;
|
|
162
|
+
/** Controlled current page (1-indexed). Used with pagination. */
|
|
163
|
+
page?: number;
|
|
164
|
+
/** Callback when page changes. Receives page (1-indexed) and pageSize. */
|
|
165
|
+
onPageChange?: (page: number, pageSize: number) => void;
|
|
166
|
+
/** Callback when sort changes. For server-side sorting with pagination. */
|
|
167
|
+
onSortChange?: (columnKey: Key | undefined, direction: SortDirection | undefined) => void;
|
|
168
|
+
/** Fires on any server-relevant state change (page, sort, filter). Provides full state snapshot for API calls. */
|
|
169
|
+
onServerStateChange?: (state: ServerState<TRow>) => void;
|
|
124
170
|
}
|
|
125
171
|
interface SelectionChangeEvent<TRow, TKey = TRow[keyof TRow] | number | string> {
|
|
126
172
|
action: 'select' | 'deselect';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Key } from '../contracts/dataGridContract';
|
|
2
|
+
import { default as GridModel } from './gridModel';
|
|
3
|
+
import { default as RowModel } from './rowModel';
|
|
4
|
+
export default class DetailRowModel<TRow> {
|
|
5
|
+
readonly grid: GridModel<TRow>;
|
|
6
|
+
readonly parentRow: RowModel<TRow>;
|
|
7
|
+
constructor(grid: GridModel<TRow>, parentRow: RowModel<TRow>);
|
|
8
|
+
get key(): Key;
|
|
9
|
+
static readonly AUTO_HEIGHT_ESTIMATE = 200;
|
|
10
|
+
get height(): 'auto' | number;
|
|
11
|
+
/** Numeric height for virtualization offset calculations. Uses estimate for 'auto'. */
|
|
12
|
+
get heightForOffset(): number;
|
|
13
|
+
readonly count = 0;
|
|
14
|
+
get flatRows(): this[];
|
|
15
|
+
get allRows(): RowModel<TRow>[];
|
|
16
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ComponentsAndVariants } from '../../../types';
|
|
2
|
+
import { ColumnFilters, DataGridProps, FilterValue, Key, PaginationState, PinPosition } from '../contracts/dataGridContract';
|
|
2
3
|
import { default as ColumnModel } from './columnModel';
|
|
4
|
+
import { default as DetailRowModel } from './detailRowModel';
|
|
3
5
|
import { default as GroupRowModel } from './groupRowModel';
|
|
4
6
|
import { default as RowModel } from './rowModel';
|
|
5
7
|
export declare const EMPTY_CELL_KEY: Key;
|
|
@@ -7,10 +9,12 @@ export declare const ROW_NUMBER_CELL_KEY: Key;
|
|
|
7
9
|
export declare const DEFAULT_ROW_NUMBER_COLUMN_WIDTH = 70;
|
|
8
10
|
export declare const ROW_SELECTION_CELL_KEY: Key;
|
|
9
11
|
export declare const GROUPING_CELL_KEY: Key;
|
|
12
|
+
export declare const ROW_DETAIL_CELL_KEY: Key;
|
|
10
13
|
export default class GridModel<TRow> {
|
|
11
14
|
props: DataGridProps<TRow>;
|
|
12
15
|
readonly update: () => void;
|
|
13
16
|
constructor(props: DataGridProps<TRow>, update: () => void);
|
|
17
|
+
get componentName(): keyof ComponentsAndVariants;
|
|
14
18
|
readonly sourceColumns: import('../../../utils/memo').Memo<ColumnModel<TRow>[]>;
|
|
15
19
|
readonly columns: import('../../../utils/memo').Memo<{
|
|
16
20
|
left: ColumnModel<TRow>[];
|
|
@@ -48,6 +52,7 @@ export default class GridModel<TRow> {
|
|
|
48
52
|
* Get filtered data (applies external, global, then column filters)
|
|
49
53
|
*/
|
|
50
54
|
get filteredData(): TRow[];
|
|
55
|
+
private fireServerStateChange;
|
|
51
56
|
/**
|
|
52
57
|
* Set global filter value
|
|
53
58
|
*/
|
|
@@ -80,7 +85,7 @@ export default class GridModel<TRow> {
|
|
|
80
85
|
total: number;
|
|
81
86
|
};
|
|
82
87
|
readonly rows: import('../../../utils/memo').Memo<GroupRowModel<TRow>[] | RowModel<TRow>[]>;
|
|
83
|
-
readonly flatRows: import('../../../utils/memo').Memo<(GroupRowModel<TRow> | RowModel<TRow>)[]>;
|
|
88
|
+
readonly flatRows: import('../../../utils/memo').Memo<(GroupRowModel<TRow> | RowModel<TRow> | DetailRowModel<TRow>)[]>;
|
|
84
89
|
get rowHeight(): number;
|
|
85
90
|
readonly sizes: import('../../../utils/memo').Memo<Record<string, string>>;
|
|
86
91
|
private _containerWidth;
|
|
@@ -92,6 +97,19 @@ export default class GridModel<TRow> {
|
|
|
92
97
|
readonly MIN_COLUMN_WIDTH_PX = 48;
|
|
93
98
|
readonly DEFAULT_COLUMN_WIDTH_PX = 200;
|
|
94
99
|
expandedGroupRow: Set<Key>;
|
|
100
|
+
private _expandedDetailRows;
|
|
101
|
+
get expandedDetailRows(): Set<Key>;
|
|
102
|
+
toggleDetailRow: (rowKey: Key) => void;
|
|
103
|
+
private _page;
|
|
104
|
+
get page(): number;
|
|
105
|
+
get pageSize(): number;
|
|
106
|
+
get isPaginated(): boolean;
|
|
107
|
+
get paginationState(): PaginationState | undefined;
|
|
108
|
+
changePage: (page: number) => void;
|
|
109
|
+
readonly rowOffsets: import('../../../utils/memo').Memo<{
|
|
110
|
+
offsets: number[];
|
|
111
|
+
totalHeight: number;
|
|
112
|
+
}>;
|
|
95
113
|
selectedRows: Set<Key>;
|
|
96
114
|
get leftEdge(): number;
|
|
97
115
|
get rightEdge(): number;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Key } from '../contracts/dataGridContract';
|
|
2
2
|
import { default as ColumnModel } from './columnModel';
|
|
3
|
+
import { default as DetailRowModel } from './detailRowModel';
|
|
3
4
|
import { default as GridModel } from './gridModel';
|
|
4
5
|
import { default as GroupRowCellModel } from './groupRowCellModel';
|
|
5
6
|
import { default as RowModel } from './rowModel';
|
|
@@ -18,7 +19,7 @@ export default class GroupRowModel<TRow> {
|
|
|
18
19
|
get expanded(): boolean;
|
|
19
20
|
get depth(): number;
|
|
20
21
|
get count(): number;
|
|
21
|
-
get flatRows(): (RowModel<TRow> | GroupRowModel<TRow>)[];
|
|
22
|
+
get flatRows(): (RowModel<TRow> | GroupRowModel<TRow> | DetailRowModel<TRow>)[];
|
|
22
23
|
get allRows(): RowModel<TRow>[];
|
|
23
24
|
get groupingColumn(): ColumnModel<TRow>;
|
|
24
25
|
get groupingColumnGridColumn(): number;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Key } from '../contracts/dataGridContract';
|
|
2
2
|
import { default as CellModel } from './cellModel';
|
|
3
|
+
import { default as DetailRowModel } from './detailRowModel';
|
|
3
4
|
import { default as GridModel } from './gridModel';
|
|
4
5
|
import { default as GroupRowModel } from './groupRowModel';
|
|
5
6
|
export default class RowModel<TRow> {
|
|
@@ -12,6 +13,7 @@ export default class RowModel<TRow> {
|
|
|
12
13
|
readonly count = 1;
|
|
13
14
|
get cells(): CellModel<TRow>[];
|
|
14
15
|
get selected(): boolean;
|
|
15
|
-
get
|
|
16
|
+
get expanded(): boolean;
|
|
17
|
+
get flatRows(): (RowModel<TRow> | DetailRowModel<TRow>)[];
|
|
16
18
|
get allRows(): this;
|
|
17
19
|
}
|