Skip to content

Commit a464828

Browse files
author
Asif Ansari
committed
feat: toolbar render prop slots and className override (v1.0.6)
Add five render props to GridToolbar allowing individual controls to be replaced without rebuilding the entire toolbar. All panels retain their existing open/close logic — only the trigger elements change. New GridToolbarProps: - renderColumnsButton(ToolbarButtonRenderProps) — replace Columns button - renderFilterButton(ToolbarButtonRenderProps) — replace Filters button - renderAggregationButton(ToolbarButtonRenderProps) — replace Summaries button - renderExportButton() — inject an Export button slot - renderQuickFilter(ToolbarQuickFilterRenderProps) — replace search input - className — CSS class on toolbar root ToolbarButtonRenderProps and ToolbarQuickFilterRenderProps are exported from the package for TypeScript consumers. Panel positioning switches to the wrapper div ref when a custom button is provided, so no ref plumbing is required in consumer code. Also includes: - Toolbar Customization demo page (/toolbar-customization) - In-app API docs updated with GridToolbar section - docs/components/toolbar.md rewritten with full prop reference - docs/API_REFERENCE.md GridToolbar section added - docs/features/toolbar-customization.md new standalone guide - README.md toolbar section updated with render prop table - App.css header z-index raised to 990 - AdvancedFilteringDemo minor formatting fixes
1 parent 5a4c81f commit a464828

17 files changed

Lines changed: 1371 additions & 104 deletions

File tree

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,21 @@
55

66
---
77

8+
## [1.0.6] — August 13, 2026 ✨
9+
10+
### Added
11+
- **Toolbar render prop slots**: `GridToolbar` now accepts render props to replace individual toolbar controls without replacing the entire toolbar. All panels (columns, filters, aggregation) continue to open and close normally — only the trigger element is swapped.
12+
- `renderColumnsButton(props)` — replace the Columns icon button
13+
- `renderFilterButton(props)` — replace the Filters icon button; receives `activeCount`
14+
- `renderAggregationButton(props)` — replace the Summaries icon button; receives `activeCount`
15+
- `renderExportButton()` — inject an Export button after the Aggregation button (no built-in exists)
16+
- `renderQuickFilter(props)` — replace the built-in `GlobalSearch` input; receives `value` and `onChange`
17+
- **`GridToolbar.className`**: Accepts an additional CSS class on the toolbar root `<div>` for full visual override without replacing the component.
18+
- **Exported types**: `ToolbarButtonRenderProps` and `ToolbarQuickFilterRenderProps` are now exported from the package for TypeScript consumers.
19+
- **Toolbar Customization demo**: new demo page at `/toolbar-customization` showing a branded dark toolbar and a plain light toolbar, each using all five render props.
20+
21+
---
22+
823
## [1.0.5] — August 12, 2026 🐛
924

1025
### Fixed

README.md

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,11 +339,58 @@ import { DataGrid, GridToolbar } from '@opencorestack/opengridx';
339339
<DataGrid
340340
rows={rows}
341341
columns={columns}
342+
filterModel={filterModel}
343+
onFilterModelChange={setFilterModel}
344+
columnVisibilityModel={columnVisibilityModel}
345+
onColumnVisibilityModelChange={setColumnVisibilityModel}
342346
slots={{ toolbar: GridToolbar }}
343347
/>
344348
```
345349

346-
`GridToolbar` provides global search, column visibility panel, filter panel, and export controls out of the box.
350+
`GridToolbar` provides global search, column visibility management, advanced filters, and aggregation controls. Each feature button is automatically hidden if its callback prop is not provided.
351+
352+
#### Customizing individual toolbar controls
353+
354+
Replace any single control using render props — the panels remain fully functional:
355+
356+
| Prop | What it replaces |
357+
|------|-----------------|
358+
| `renderQuickFilter(props)` | The search input. Receives `{ value, onChange }`. |
359+
| `renderColumnsButton(props)` | The Columns toggle button. Receives `{ onClick, isOpen, activeCount }`. |
360+
| `renderFilterButton(props)` | The Filters toggle button. Receives `{ onClick, isOpen, activeCount }`. |
361+
| `renderAggregationButton(props)` | The Summaries toggle button. Receives `{ onClick, isOpen, activeCount }`. |
362+
| `renderExportButton()` | Inserts an Export button slot (no built-in exists). |
363+
| `className` | CSS class on the toolbar root for theme overrides. |
364+
365+
```tsx
366+
import { GridToolbar, exportToCsv, useGridApiRef,
367+
type ToolbarButtonRenderProps, type ToolbarQuickFilterRenderProps } from '@opencorestack/opengridx';
368+
369+
const apiRef = useGridApiRef();
370+
371+
<DataGrid
372+
apiRef={apiRef}
373+
slots={{ toolbar: GridToolbar }}
374+
slotProps={{
375+
toolbar: {
376+
className: 'my-branded-toolbar',
377+
renderQuickFilter: ({ value, onChange }: ToolbarQuickFilterRenderProps) => (
378+
<input className="my-search" value={value} onChange={e => onChange(e.target.value)} />
379+
),
380+
renderFilterButton: ({ onClick, isOpen, activeCount }: ToolbarButtonRenderProps) => (
381+
<button className={isOpen ? 'active' : ''} onClick={onClick}>
382+
Filters {activeCount > 0 && <span>{activeCount}</span>}
383+
</button>
384+
),
385+
renderExportButton: () => (
386+
<button onClick={() => exportToCsv(apiRef.current.getAllRows(), columns)}>
387+
Export CSV
388+
</button>
389+
),
390+
},
391+
}}
392+
/>
393+
```
347394

348395
### Export Functionality
349396

demo/App.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
padding: 0 24px;
1616
position: sticky;
1717
top: 0;
18-
z-index: 50;
18+
z-index: 990;
1919
}
2020

2121
.app-github-link {

demo/App.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ const RealEstatePortfolioDemo = lazy(() => import('./examples/RealEstatePortfoli
3434
const EmployeeCalendarDemo = lazy(() => import('./examples/EmployeeCalendarDemo/EmployeeCalendarDemo'));
3535
const LoadingStatesDemo = lazy(() => import('./examples/LoadingStatesDemo/LoadingStatesDemo'));
3636
const ToolbarDemo = lazy(() => import('./examples/ToolbarDemo/ToolbarDemo'));
37+
const ToolbarCustomizationDemo = lazy(() => import('./examples/ToolbarCustomizationDemo/ToolbarCustomizationDemo'));
3738
const FilterPanelDemo = lazy(() => import('./examples/FilterPanelDemo/FilterPanelDemo'));
3839
const SlotsDemo = lazy(() => import('./examples/SlotsDemo/SlotsDemo'));
3940
const CRUDTutorial = lazy(() => import('./examples/CRUDTutorial/CRUDTutorial'));
@@ -78,6 +79,7 @@ const examplesConfig = [
7879

7980
// Components
8081
{ path: '/toolbar', name: 'Toolbar', component: ToolbarDemo, category: 'Components' },
82+
{ path: '/toolbar-customization', name: 'Toolbar Customization', component: ToolbarCustomizationDemo, category: 'Components' },
8183
{ path: '/filter-panel', name: 'Filter Panel', component: FilterPanelDemo, category: 'Components' },
8284

8385
// Customization
@@ -135,7 +137,7 @@ export default function App() {
135137
<img src={`${import.meta.env.BASE_URL}logo.png`} alt="OpenGridX Logo" className="app-logo" />
136138
<h2 className="app-title">
137139
OpenGridX
138-
<span className="app-version">v1.0.5</span>
140+
<span className="app-version">v1.0.6</span>
139141
</h2>
140142
</div>
141143

demo/Home.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export default function Home(_props: HomeProps) {
6868
<div className="home-logo-hero">
6969
<img src={`${import.meta.env.BASE_URL}banner.png`} alt="OpenGridX Logo" className="home-banner-image" />
7070
</div>
71-
<span className="home-badge">OpenGridX v1.0.5</span>
71+
<span className="home-badge">OpenGridX v1.0.6</span>
7272
<p className="home-subtitle">
7373
The elite, high-performance DataGrid for modern React.
7474
Built to handle massive data with a premium developer experience.

demo/examples/AdvancedFilteringDemo/AdvancedFilteringDemo.css

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
}
4040

4141
.filtering-export-btn {
42-
color: #4b5563;
42+
color: #fff;
4343
}
4444

4545
.filtering-export-btn--disabled {
@@ -49,7 +49,7 @@
4949
/* Toolbar Export Spinner */
5050
.toolbar-spinner {
5151
animation: ogx-spin 1s linear infinite;
52-
border: 2px solid rgba(0,0,0,0.1);
52+
border: 2px solid rgba(0, 0, 0, 0.1);
5353
border-top: 2px solid #6b7280;
5454
border-radius: 50%;
5555
width: 16px;
@@ -58,5 +58,7 @@
5858
}
5959

6060
@keyframes ogx-spin {
61-
to { transform: rotate(360deg); }
62-
}
61+
to {
62+
transform: rotate(360deg);
63+
}
64+
}

demo/examples/AdvancedFilteringDemo/AdvancedFilteringDemo.tsx

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,25 @@
11

22
import { useState } from 'react';
3-
import { DataGrid, GridToolbar, GridColDef, GridFilterModel, GridTooltip, exportToCsv, exportToExcel, exportToJson, printGrid } from '@opencorestack/opengridx';
3+
import { DataGrid, GridToolbar, GridColDef, GridRowModel, GridFilterModel, GridTooltip, exportToCsv, exportToExcel, exportToJson, printGrid } from '@opencorestack/opengridx';
44
import { DocsLayout } from '../../components/DocsLayout';
55
import './AdvancedFilteringDemo.css';
66

77
import sourceCode from './AdvancedFilteringDemo.tsx?raw';
88

9+
interface Employee extends GridRowModel {
10+
id: number;
11+
firstName: string;
12+
lastName: string;
13+
age: number;
14+
department: string;
15+
salary: number;
16+
active: boolean;
17+
}
18+
919
interface ExportToolbarProps {
1020
apiRef?: any;
11-
fallbackRows: any[];
12-
fallbackColumns: GridColDef[];
21+
fallbackRows: Employee[];
22+
fallbackColumns: GridColDef<Employee>[];
1323
}
1424

1525
function ExportToolbar({ apiRef, fallbackRows, fallbackColumns }: ExportToolbarProps) {
@@ -113,7 +123,7 @@ function ExportToolbar({ apiRef, fallbackRows, fallbackColumns }: ExportToolbarP
113123
);
114124
}
115125

116-
const rows = [
126+
const rows: Employee[] = [
117127
{ id: 1, firstName: 'Jon', lastName: 'Snow', age: 35, department: 'Engineering', salary: 95000, active: true },
118128
{ id: 2, firstName: 'Cersei', lastName: 'Lannister', age: 42, department: 'Management', salary: 140000, active: false },
119129
{ id: 3, firstName: 'Jaime', lastName: 'Lannister', age: 45, department: 'Security', salary: 88000, active: true },
@@ -141,9 +151,9 @@ const rows = [
141151
{ id: 25, firstName: 'Tormund', lastName: 'Giantsbane', age: 38, department: 'Security', salary: 72000, active: true },
142152
];
143153

144-
const columns: GridColDef[] = [
154+
const columns: GridColDef<Employee>[] = [
145155
{ field: 'id', headerName: 'ID', width: 70, type: 'number' },
146-
{ field: 'firstName', headerName: 'First Name', width: 140 },
156+
{ field: 'firstName', headerName: 'First Name', flex: 1, width: 100 },
147157
{ field: 'lastName', headerName: 'Last Name', width: 150 },
148158
{ field: 'age', headerName: 'Age', width: 90, type: 'number' },
149159
{ field: 'department', headerName: 'Department', width: 150 },

0 commit comments

Comments
 (0)