@opencorestack/opengridx 1.0.4 β 1.0.6
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/CHANGELOG.md +22 -0
- package/README.md +48 -1
- package/dist/index.d.ts +46 -1
- package/dist/opengridx.es.js +1902 -1872
- package/dist/opengridx.es.js.map +1 -1
- package/dist/opengridx.umd.js +9 -9
- package/dist/opengridx.umd.js.map +1 -1
- package/docs/API_REFERENCE.md +53 -0
- package/docs/components/toolbar.md +200 -19
- package/docs/features/toolbar-customization.md +205 -0
- package/lib/components/DataGrid/DataGrid.tsx +14 -1
- package/lib/components/Toolbar/GridToolbar.tsx +161 -69
- package/lib/index.ts +1 -1
- package/package.json +1 -1
package/docs/API_REFERENCE.md
CHANGED
|
@@ -164,6 +164,59 @@ The main component for displaying and interacting with data.
|
|
|
164
164
|
|
|
165
165
|
---
|
|
166
166
|
|
|
167
|
+
## π οΈ `GridToolbar`
|
|
168
|
+
|
|
169
|
+
The built-in toolbar component. Mount it via `slots={{ toolbar: GridToolbar }}`. All props below are passed through `slotProps.toolbar` (or directly when building a custom wrapper).
|
|
170
|
+
|
|
171
|
+
### `GridToolbarProps`
|
|
172
|
+
|
|
173
|
+
| Prop | Type | Default | Description |
|
|
174
|
+
| :--- | :--- | :--- | :--- |
|
|
175
|
+
| `columns` | `GridColDef[]` | `[]` | Column definitions β injected automatically when used via `slots`. |
|
|
176
|
+
| `baseColumns` | `GridColDef[]` | β | Pre-pivot columns shown in the Pivot panel instead of synthetic pivot columns. |
|
|
177
|
+
| `aggregationModel` | `GridAggregationModel` | `{}` | Current aggregation configuration. |
|
|
178
|
+
| `onAggregationModelChange` | `(model: GridAggregationModel) => void` | β | Called when the user changes aggregation settings. |
|
|
179
|
+
| `pivotModel` | `GridPivotModel` | β | Current pivot configuration. Presence of this prop renders the Pivot button. |
|
|
180
|
+
| `onPivotModelChange` | `(model: GridPivotModel) => void` | β | Called when the user changes pivot settings. |
|
|
181
|
+
| `filterModel` | `GridFilterModel` | β | Current filter model. Presence of this prop renders the search bar and Filter button. |
|
|
182
|
+
| `onFilterModelChange` | `(model: GridFilterModel) => void` | β | Called when the user changes filters or the quick-search value. |
|
|
183
|
+
| `columnVisibilityModel` | `Record<string, boolean>` | `{}` | Current column visibility map. |
|
|
184
|
+
| `onColumnVisibilityModelChange` | `(model: Record<string, boolean>) => void` | β | Called when the user shows or hides a column. Presence renders the Columns button. |
|
|
185
|
+
| `onColumnReorder` | `(from: string, to: string) => void` | β | Called when the user drags a column in the Columns panel. |
|
|
186
|
+
| `onColumnOrderReset` | `() => void` | β | Called when the user clicks "Reset order" in the Columns panel. |
|
|
187
|
+
| `forceColumnsOpen` | `boolean` | β | Forces the Columns panel open (used internally by the column header context menu). |
|
|
188
|
+
| `onColumnsPanelClose` | `() => void` | β | Called when the Columns panel closes after a `forceColumnsOpen`. |
|
|
189
|
+
| `children` | `ReactNode` | β | Content rendered on the **left** side of the toolbar, before the spacer. |
|
|
190
|
+
| `rightContent` | `ReactNode` | β | Content rendered on the **right** side, after all built-in buttons. |
|
|
191
|
+
| `className` | `string` | β | Additional CSS class on the toolbar root `<div>`. Use for visual theme overrides. |
|
|
192
|
+
| `style` | `CSSProperties` | β | Inline styles on the toolbar root. |
|
|
193
|
+
| `renderColumnsButton` | `(props: ToolbarButtonRenderProps) => ReactNode` | β | Replace the built-in Columns toggle button. The Columns panel still functions normally. |
|
|
194
|
+
| `renderFilterButton` | `(props: ToolbarButtonRenderProps) => ReactNode` | β | Replace the built-in Filters toggle button. The Filter panel still functions normally. |
|
|
195
|
+
| `renderAggregationButton` | `(props: ToolbarButtonRenderProps) => ReactNode` | β | Replace the built-in Summaries toggle button. The Aggregation panel still functions normally. |
|
|
196
|
+
| `renderExportButton` | `() => ReactNode` | β | Inject an Export button after the Aggregation button. No built-in export button exists. |
|
|
197
|
+
| `renderQuickFilter` | `(props: ToolbarQuickFilterRenderProps) => ReactNode` | β | Replace the built-in `GlobalSearch` input with your own component. |
|
|
198
|
+
|
|
199
|
+
### `ToolbarButtonRenderProps`
|
|
200
|
+
|
|
201
|
+
Passed to `renderColumnsButton`, `renderFilterButton`, and `renderAggregationButton`.
|
|
202
|
+
|
|
203
|
+
| Property | Type | Description |
|
|
204
|
+
| :--- | :--- | :--- |
|
|
205
|
+
| `onClick` | `() => void` | Toggle the associated panel open or closed. |
|
|
206
|
+
| `isOpen` | `boolean` | Whether the associated panel is currently open. |
|
|
207
|
+
| `activeCount` | `number` | Active items: hidden columns for Columns, applied filters for Filter, configured aggregations for Summaries. |
|
|
208
|
+
|
|
209
|
+
### `ToolbarQuickFilterRenderProps`
|
|
210
|
+
|
|
211
|
+
Passed to `renderQuickFilter`.
|
|
212
|
+
|
|
213
|
+
| Property | Type | Description |
|
|
214
|
+
| :--- | :--- | :--- |
|
|
215
|
+
| `value` | `string` | Current search string. |
|
|
216
|
+
| `onChange` | `(value: string) => void` | Call with the updated string when the input changes. |
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
167
220
|
## πΉοΈ Imperative API (`GridApi`)
|
|
168
221
|
|
|
169
222
|
Access these methods via the `apiRef` prop.
|
|
@@ -1,40 +1,221 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `GridToolbar`
|
|
2
2
|
|
|
3
|
-
The toolbar is an optional component rendered at the top of the grid. It
|
|
3
|
+
The toolbar is an optional component rendered at the top of the grid. It provides global search, column visibility management, advanced filters, aggregation configuration, and pivot mode β all in one composable component.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Basic usage
|
|
6
6
|
|
|
7
|
-
OpenGridX includes a pre-built `GridToolbar` that bundles common actions.
|
|
8
|
-
|
|
9
|
-
### Usage
|
|
10
7
|
```tsx
|
|
11
8
|
import { DataGrid, GridToolbar } from '@opencorestack/opengridx';
|
|
12
9
|
|
|
13
10
|
<DataGrid
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
rows={rows}
|
|
12
|
+
columns={columns}
|
|
13
|
+
filterModel={filterModel}
|
|
14
|
+
onFilterModelChange={setFilterModel}
|
|
15
|
+
columnVisibilityModel={columnVisibilityModel}
|
|
16
|
+
onColumnVisibilityModelChange={setColumnVisibilityModel}
|
|
17
|
+
aggregationModel={aggregationModel}
|
|
18
|
+
onAggregationModelChange={setAggregationModel}
|
|
19
|
+
slots={{ toolbar: GridToolbar }}
|
|
20
|
+
/>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
`GridToolbar` automatically hides buttons for features whose callbacks are not wired. For example, if you don't pass `onFilterModelChange` the search bar and filter button are not rendered.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## `GridToolbarProps`
|
|
28
|
+
|
|
29
|
+
| Prop | Type | Default | Description |
|
|
30
|
+
|------|------|---------|-------------|
|
|
31
|
+
| `columns` | `GridColDef[]` | `[]` | Column definitions (injected automatically when used via `slots`). |
|
|
32
|
+
| `baseColumns` | `GridColDef[]` | β | Pre-pivot column definitions, used by the Pivot panel to avoid showing synthetic columns. |
|
|
33
|
+
| `aggregationModel` | `GridAggregationModel` | `{}` | Current aggregation configuration. |
|
|
34
|
+
| `onAggregationModelChange` | `(model) => void` | β | Called when the user changes aggregation settings. |
|
|
35
|
+
| `pivotModel` | `GridPivotModel` | β | Current pivot configuration. |
|
|
36
|
+
| `onPivotModelChange` | `(model) => void` | β | Called when the user changes pivot settings. Presence of this prop shows the Pivot button. |
|
|
37
|
+
| `filterModel` | `GridFilterModel` | β | Current filter model. Presence of this prop shows the search bar and Filter button. |
|
|
38
|
+
| `onFilterModelChange` | `(model) => void` | β | Called when the user changes filters or the search query. |
|
|
39
|
+
| `columnVisibilityModel` | `Record<string, boolean>` | `{}` | Current column visibility state. |
|
|
40
|
+
| `onColumnVisibilityModelChange` | `(model) => void` | β | Called when the user shows/hides columns. Presence shows the Columns button. |
|
|
41
|
+
| `onColumnReorder` | `(from, to) => void` | β | Called when the user drags a column in the Columns panel. |
|
|
42
|
+
| `onColumnOrderReset` | `() => void` | β | Called when the user clicks "Reset order" in the Columns panel. |
|
|
43
|
+
| `forceColumnsOpen` | `boolean` | β | When `true`, opens the Columns panel immediately (used internally by the column header menu). |
|
|
44
|
+
| `onColumnsPanelClose` | `() => void` | β | Called when the Columns panel closes after a `forceColumnsOpen`. |
|
|
45
|
+
| `children` | `ReactNode` | β | Content rendered in the **left** side of the toolbar (before the spacer). |
|
|
46
|
+
| `rightContent` | `ReactNode` | β | Content rendered in the **right** side of the toolbar (after all built-in buttons). |
|
|
47
|
+
| `className` | `string` | β | Additional CSS class applied to the toolbar root `<div>`. Use for visual overrides without replacing the component. |
|
|
48
|
+
| `style` | `CSSProperties` | β | Inline style applied to the toolbar root `<div>`. |
|
|
49
|
+
| `renderColumnsButton` | `(props: ToolbarButtonRenderProps) => ReactNode` | β | Replace the built-in Columns button. The Columns panel still opens and closes normally. |
|
|
50
|
+
| `renderFilterButton` | `(props: ToolbarButtonRenderProps) => ReactNode` | β | Replace the built-in Filters button. The Filter panel still opens and closes normally. |
|
|
51
|
+
| `renderAggregationButton` | `(props: ToolbarButtonRenderProps) => ReactNode` | β | Replace the built-in Summaries button. The Aggregation panel still opens and closes normally. |
|
|
52
|
+
| `renderExportButton` | `() => ReactNode` | β | Inject an Export button after the Aggregation button. No built-in export button exists β this is the slot for it. |
|
|
53
|
+
| `renderQuickFilter` | `(props: ToolbarQuickFilterRenderProps) => ReactNode` | β | Replace the built-in quick-filter search input with your own component. |
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Render prop types
|
|
58
|
+
|
|
59
|
+
### `ToolbarButtonRenderProps`
|
|
60
|
+
|
|
61
|
+
Passed to `renderColumnsButton`, `renderFilterButton`, and `renderAggregationButton`.
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
interface ToolbarButtonRenderProps {
|
|
65
|
+
onClick: () => void; // Toggle the associated panel open/closed
|
|
66
|
+
isOpen: boolean; // Whether the panel is currently open
|
|
67
|
+
activeCount: number; // Active items (hidden columns, applied filters, etc.)
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### `ToolbarQuickFilterRenderProps`
|
|
72
|
+
|
|
73
|
+
Passed to `renderQuickFilter`.
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
interface ToolbarQuickFilterRenderProps {
|
|
77
|
+
value: string; // Current search string
|
|
78
|
+
onChange: (value: string) => void; // Call with new string on input change
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Customization patterns
|
|
85
|
+
|
|
86
|
+
### Add content to left or right sides
|
|
87
|
+
|
|
88
|
+
Use `children` (left) and `rightContent` (right) to inject elements without touching the built-in buttons:
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
<DataGrid
|
|
92
|
+
slots={{ toolbar: GridToolbar }}
|
|
93
|
+
slotProps={{
|
|
94
|
+
toolbar: {
|
|
95
|
+
children: <span style={{ fontWeight: 600 }}>My Grid</span>,
|
|
96
|
+
rightContent: (
|
|
97
|
+
<button onClick={handleExport}>Export CSV</button>
|
|
98
|
+
),
|
|
99
|
+
},
|
|
100
|
+
}}
|
|
101
|
+
/>
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Custom search bar
|
|
105
|
+
|
|
106
|
+
Replace only the search input while keeping the rest of the toolbar intact:
|
|
107
|
+
|
|
108
|
+
```tsx
|
|
109
|
+
function MySearchBar({ value, onChange }: ToolbarQuickFilterRenderProps) {
|
|
110
|
+
return (
|
|
111
|
+
<input
|
|
112
|
+
className="my-search"
|
|
113
|
+
value={value}
|
|
114
|
+
onChange={e => onChange(e.target.value)}
|
|
115
|
+
placeholder="Searchβ¦"
|
|
116
|
+
/>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
<DataGrid
|
|
121
|
+
slots={{ toolbar: GridToolbar }}
|
|
122
|
+
slotProps={{
|
|
123
|
+
toolbar: {
|
|
124
|
+
renderQuickFilter: (props) => <MySearchBar {...props} />,
|
|
125
|
+
},
|
|
16
126
|
}}
|
|
17
127
|
/>
|
|
18
128
|
```
|
|
19
129
|
|
|
20
|
-
###
|
|
21
|
-
- **Quick Search**: Search across all visible columns.
|
|
22
|
-
- **Export Menu**: Download data as CSV, Print, or [Advanced Excel](../features/export-guide.md).
|
|
23
|
-
- **Column Visibility**: Toggle which columns are shown via a dropdown [Visibility Panel](column-visibility.md).
|
|
24
|
-
- **Density**: Switch between Compact, Standard, and Comfortable row heights.
|
|
130
|
+
### Custom action buttons (panels still work)
|
|
25
131
|
|
|
26
|
-
|
|
132
|
+
Replace individual trigger buttons while keeping their panels fully functional:
|
|
27
133
|
|
|
28
|
-
|
|
134
|
+
```tsx
|
|
135
|
+
function MyFilterButton({ onClick, isOpen, activeCount }: ToolbarButtonRenderProps) {
|
|
136
|
+
return (
|
|
137
|
+
<button
|
|
138
|
+
className={`my-btn ${isOpen ? 'my-btn--active' : ''}`}
|
|
139
|
+
onClick={onClick}
|
|
140
|
+
>
|
|
141
|
+
Filters {activeCount > 0 && <span className="badge">{activeCount}</span>}
|
|
142
|
+
</button>
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
<DataGrid
|
|
147
|
+
slots={{ toolbar: GridToolbar }}
|
|
148
|
+
slotProps={{
|
|
149
|
+
toolbar: {
|
|
150
|
+
renderFilterButton: (props) => <MyFilterButton {...props} />,
|
|
151
|
+
renderColumnsButton: (props) => <MyColumnsButton {...props} />,
|
|
152
|
+
renderAggregationButton: (props) => <MyAggButton {...props} />,
|
|
153
|
+
},
|
|
154
|
+
}}
|
|
155
|
+
/>
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Add an Export button
|
|
159
|
+
|
|
160
|
+
There is no built-in export button in the toolbar. Use `renderExportButton` to add one:
|
|
29
161
|
|
|
30
162
|
```tsx
|
|
31
|
-
|
|
163
|
+
import { exportToCsv, useGridApiRef } from '@opencorestack/opengridx';
|
|
164
|
+
|
|
165
|
+
const apiRef = useGridApiRef();
|
|
166
|
+
|
|
167
|
+
<DataGrid
|
|
168
|
+
apiRef={apiRef}
|
|
169
|
+
slots={{ toolbar: GridToolbar }}
|
|
170
|
+
slotProps={{
|
|
171
|
+
toolbar: {
|
|
172
|
+
renderExportButton: () => (
|
|
173
|
+
<button onClick={() => exportToCsv(apiRef.current.getAllRows(), columns)}>
|
|
174
|
+
Export CSV
|
|
175
|
+
</button>
|
|
176
|
+
),
|
|
177
|
+
},
|
|
178
|
+
}}
|
|
179
|
+
/>
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Theme override via `className`
|
|
183
|
+
|
|
184
|
+
Style the toolbar to match your brand without replacing the component:
|
|
185
|
+
|
|
186
|
+
```css
|
|
187
|
+
/* your-styles.css */
|
|
188
|
+
.my-toolbar {
|
|
189
|
+
background: linear-gradient(135deg, #1e1b4b, #312e81);
|
|
190
|
+
border-bottom: none;
|
|
191
|
+
border-radius: 8px 8px 0 0;
|
|
192
|
+
padding: 10px 16px;
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
```tsx
|
|
197
|
+
<DataGrid
|
|
198
|
+
slots={{ toolbar: GridToolbar }}
|
|
199
|
+
slotProps={{ toolbar: { className: 'my-toolbar' } }}
|
|
200
|
+
/>
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Fully custom toolbar
|
|
206
|
+
|
|
207
|
+
If the render props don't give you enough control, replace the entire toolbar via `slots.toolbar`:
|
|
208
|
+
|
|
209
|
+
```tsx
|
|
210
|
+
function MyToolbar() {
|
|
32
211
|
return (
|
|
33
|
-
<div className="
|
|
34
|
-
<
|
|
212
|
+
<div className="my-toolbar-root">
|
|
213
|
+
<span>Custom toolbar</span>
|
|
35
214
|
</div>
|
|
36
215
|
);
|
|
37
|
-
}
|
|
216
|
+
}
|
|
38
217
|
|
|
39
218
|
<DataGrid slots={{ toolbar: MyToolbar }} />
|
|
40
219
|
```
|
|
220
|
+
|
|
221
|
+
The custom component receives all `GridToolbarProps` via `slotProps.toolbar`.
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# Toolbar Customization
|
|
2
|
+
|
|
3
|
+
**Available from:** `@opencorestack/opengridx` v1.0.6
|
|
4
|
+
|
|
5
|
+
Replace individual toolbar controls β search bar, column button, filter button, aggregation button β without replacing the entire toolbar. All panels (columns, filters, aggregation) continue to work; only the trigger elements change.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Quick start
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import {
|
|
13
|
+
DataGrid,
|
|
14
|
+
GridToolbar,
|
|
15
|
+
type ToolbarButtonRenderProps,
|
|
16
|
+
type ToolbarQuickFilterRenderProps,
|
|
17
|
+
} from '@opencorestack/opengridx';
|
|
18
|
+
|
|
19
|
+
<DataGrid
|
|
20
|
+
rows={rows}
|
|
21
|
+
columns={columns}
|
|
22
|
+
filterModel={filterModel}
|
|
23
|
+
onFilterModelChange={setFilterModel}
|
|
24
|
+
columnVisibilityModel={columnVisibilityModel}
|
|
25
|
+
onColumnVisibilityModelChange={setColumnVisibilityModel}
|
|
26
|
+
slots={{ toolbar: GridToolbar }}
|
|
27
|
+
slotProps={{
|
|
28
|
+
toolbar: {
|
|
29
|
+
renderQuickFilter: ({ value, onChange }: ToolbarQuickFilterRenderProps) => (
|
|
30
|
+
<input
|
|
31
|
+
className="my-search"
|
|
32
|
+
value={value}
|
|
33
|
+
onChange={e => onChange(e.target.value)}
|
|
34
|
+
placeholder="Searchβ¦"
|
|
35
|
+
/>
|
|
36
|
+
),
|
|
37
|
+
},
|
|
38
|
+
}}
|
|
39
|
+
/>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## New props on `GridToolbarProps`
|
|
45
|
+
|
|
46
|
+
| Prop | Type | Description |
|
|
47
|
+
|------|------|-------------|
|
|
48
|
+
| `renderColumnsButton` | `(props: ToolbarButtonRenderProps) => ReactNode` | Replace the Columns toggle button. The Columns panel still opens and closes normally. |
|
|
49
|
+
| `renderFilterButton` | `(props: ToolbarButtonRenderProps) => ReactNode` | Replace the Filters toggle button. The Filter panel still opens and closes normally. |
|
|
50
|
+
| `renderAggregationButton` | `(props: ToolbarButtonRenderProps) => ReactNode` | Replace the Summaries toggle button. The Aggregation panel still opens and closes normally. |
|
|
51
|
+
| `renderExportButton` | `() => ReactNode` | Insert an Export button after the Aggregation button. No built-in export button exists β this is the slot for it. |
|
|
52
|
+
| `renderQuickFilter` | `(props: ToolbarQuickFilterRenderProps) => ReactNode` | Replace the built-in search input with your own component. |
|
|
53
|
+
| `className` | `string` | Additional CSS class on the toolbar root `<div>` for theme overrides. |
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Render prop types
|
|
58
|
+
|
|
59
|
+
### `ToolbarButtonRenderProps`
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
interface ToolbarButtonRenderProps {
|
|
63
|
+
onClick: () => void; // toggle the panel
|
|
64
|
+
isOpen: boolean; // whether the panel is open
|
|
65
|
+
activeCount: number; // hidden columns / applied filters / active aggregations
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### `ToolbarQuickFilterRenderProps`
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
interface ToolbarQuickFilterRenderProps {
|
|
73
|
+
value: string;
|
|
74
|
+
onChange: (value: string) => void;
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Both types are exported from the package:
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
import type { ToolbarButtonRenderProps, ToolbarQuickFilterRenderProps } from '@opencorestack/opengridx';
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Examples
|
|
87
|
+
|
|
88
|
+
### Custom search bar
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
function MySearchBar({ value, onChange }: ToolbarQuickFilterRenderProps) {
|
|
92
|
+
return (
|
|
93
|
+
<div className="search-wrap">
|
|
94
|
+
<SearchIcon />
|
|
95
|
+
<input
|
|
96
|
+
value={value}
|
|
97
|
+
onChange={e => onChange(e.target.value)}
|
|
98
|
+
placeholder="Searchβ¦"
|
|
99
|
+
/>
|
|
100
|
+
{value && <button onClick={() => onChange('')}>β</button>}
|
|
101
|
+
</div>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
slotProps={{
|
|
106
|
+
toolbar: {
|
|
107
|
+
renderQuickFilter: (props) => <MySearchBar {...props} />,
|
|
108
|
+
},
|
|
109
|
+
}}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Custom filter button with active-count badge
|
|
113
|
+
|
|
114
|
+
```tsx
|
|
115
|
+
function MyFilterBtn({ onClick, isOpen, activeCount }: ToolbarButtonRenderProps) {
|
|
116
|
+
return (
|
|
117
|
+
<button
|
|
118
|
+
className={`btn ${isOpen ? 'btn--active' : ''}`}
|
|
119
|
+
onClick={onClick}
|
|
120
|
+
>
|
|
121
|
+
Filters
|
|
122
|
+
{activeCount > 0 && <span className="badge">{activeCount}</span>}
|
|
123
|
+
</button>
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
slotProps={{
|
|
128
|
+
toolbar: {
|
|
129
|
+
renderFilterButton: (props) => <MyFilterBtn {...props} />,
|
|
130
|
+
},
|
|
131
|
+
}}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Export button wired to `apiRef`
|
|
135
|
+
|
|
136
|
+
```tsx
|
|
137
|
+
import { exportToCsv, useGridApiRef } from '@opencorestack/opengridx';
|
|
138
|
+
|
|
139
|
+
const apiRef = useGridApiRef();
|
|
140
|
+
|
|
141
|
+
<DataGrid
|
|
142
|
+
apiRef={apiRef}
|
|
143
|
+
slots={{ toolbar: GridToolbar }}
|
|
144
|
+
slotProps={{
|
|
145
|
+
toolbar: {
|
|
146
|
+
renderExportButton: () => (
|
|
147
|
+
<button onClick={() => exportToCsv(apiRef.current.getAllRows(), columns, { filename: 'export' })}>
|
|
148
|
+
Export CSV
|
|
149
|
+
</button>
|
|
150
|
+
),
|
|
151
|
+
},
|
|
152
|
+
}}
|
|
153
|
+
/>
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Replacing all buttons at once
|
|
157
|
+
|
|
158
|
+
```tsx
|
|
159
|
+
slotProps={{
|
|
160
|
+
toolbar: {
|
|
161
|
+
renderQuickFilter: (props) => <MySearch {...props} />,
|
|
162
|
+
renderColumnsButton: (props) => <MyColumnsBtn {...props} />,
|
|
163
|
+
renderFilterButton: (props) => <MyFilterBtn {...props} />,
|
|
164
|
+
renderAggregationButton: (props) => <MyAggBtn {...props} />,
|
|
165
|
+
renderExportButton: () => <MyExportBtn />,
|
|
166
|
+
},
|
|
167
|
+
}}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Theme override via `className`
|
|
171
|
+
|
|
172
|
+
```css
|
|
173
|
+
/* your-styles.css */
|
|
174
|
+
.toolbar-dark {
|
|
175
|
+
background: linear-gradient(135deg, #1e1b4b, #312e81);
|
|
176
|
+
border-bottom: none;
|
|
177
|
+
padding: 10px 16px;
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
```tsx
|
|
182
|
+
slotProps={{
|
|
183
|
+
toolbar: { className: 'toolbar-dark' },
|
|
184
|
+
}}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## How panels stay functional
|
|
190
|
+
|
|
191
|
+
When you provide a custom button, the toolbar renders your element as the trigger but keeps its own open/close state. The panel (Columns, Filters, or Aggregation) is positioned relative to the wrapper `<div>` surrounding your custom button, so placement is automatic β you don't need to pass any refs.
|
|
192
|
+
|
|
193
|
+
Panel close behaviour is unchanged: Escape key closes, click-outside closes (except the Filter panel, which requires an explicit Close button to let users type without it dismissing).
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## What is NOT replaced
|
|
198
|
+
|
|
199
|
+
These built-in features are unaffected regardless of which render props you provide:
|
|
200
|
+
|
|
201
|
+
- Column panel content (drag-to-reorder, show/hide toggles)
|
|
202
|
+
- Filter panel content (operators, values, logic operator)
|
|
203
|
+
- Aggregation panel content (per-column function pills)
|
|
204
|
+
- Pivot panel (if `onPivotModelChange` is wired)
|
|
205
|
+
- `children` / `rightContent` slot behaviour
|
|
@@ -513,6 +513,19 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
|
|
|
513
513
|
pageSize: effectivePaginationModel.pageSize,
|
|
514
514
|
});
|
|
515
515
|
|
|
516
|
+
// Merge layout-computed widths (which include flex resolution) with user-resize
|
|
517
|
+
// overrides. The footer and other consumers that receive `columnWidths` only get
|
|
518
|
+
// the resize-override map, which has no entry for flex columns that haven't been
|
|
519
|
+
// manually resized β causing them to fall back to the raw `col.width` prop instead
|
|
520
|
+
// of the actual rendered width.
|
|
521
|
+
const resolvedColumnWidths = useMemo(() => {
|
|
522
|
+
const result: Record<string, number> = {};
|
|
523
|
+
for (const col of [...layout.leftPinnedCols, ...layout.unpinnedColsWithWidth, ...layout.rightPinnedCols]) {
|
|
524
|
+
if (!col.isSpacer) result[col.field] = col.width;
|
|
525
|
+
}
|
|
526
|
+
return { ...result, ...columnWidths };
|
|
527
|
+
}, [layout.leftPinnedCols, layout.unpinnedColsWithWidth, layout.rightPinnedCols, columnWidths]);
|
|
528
|
+
|
|
516
529
|
useEffect(() => {
|
|
517
530
|
gridData.apiRef.current.scrollToIndexes = ({ rowIndex, colIndex }) => {
|
|
518
531
|
const el = viewportRef.current;
|
|
@@ -977,7 +990,7 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
|
|
|
977
990
|
columns={orderedColumns as unknown as GridColDef[]}
|
|
978
991
|
aggregationModel={aggregationModel}
|
|
979
992
|
aggregationResult={aggregationResult}
|
|
980
|
-
columnWidths={
|
|
993
|
+
columnWidths={resolvedColumnWidths}
|
|
981
994
|
rowHeight={rowHeight}
|
|
982
995
|
checkboxSelection={checkboxSelection}
|
|
983
996
|
hasDetailPanel={hasDetailPanel}
|