@opencorestack/opengridx 1.0.5 → 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 +15 -0
- package/README.md +48 -1
- package/dist/index.d.ts +46 -1
- package/dist/opengridx.es.js +1616 -1591
- 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/Toolbar/GridToolbar.tsx +161 -69
- package/lib/index.ts +1 -1
- package/package.json +1 -1
|
@@ -7,6 +7,24 @@ import { ColumnVisibilityPanel } from '../ColumnVisibilityPanel/ColumnVisibility
|
|
|
7
7
|
import { FilterPanel } from '../FilterPanel/FilterPanel';
|
|
8
8
|
import { GridTooltip } from '../Tooltip/Tooltip';
|
|
9
9
|
|
|
10
|
+
/** Props passed to a custom toolbar button renderer. */
|
|
11
|
+
export interface ToolbarButtonRenderProps {
|
|
12
|
+
/** Call this to toggle the associated panel open/closed. */
|
|
13
|
+
onClick: () => void;
|
|
14
|
+
/** Whether the associated panel is currently open. */
|
|
15
|
+
isOpen: boolean;
|
|
16
|
+
/** Number of active items (filters applied, aggregations configured, etc.). */
|
|
17
|
+
activeCount: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Props passed to a custom quick-filter renderer. */
|
|
21
|
+
export interface ToolbarQuickFilterRenderProps {
|
|
22
|
+
/** Current search string. */
|
|
23
|
+
value: string;
|
|
24
|
+
/** Call with the new search string when the input changes. */
|
|
25
|
+
onChange: (value: string) => void;
|
|
26
|
+
}
|
|
27
|
+
|
|
10
28
|
export interface GridToolbarProps {
|
|
11
29
|
columns?: GridColDef[];
|
|
12
30
|
/** Original user-defined columns (before pivot transformation).
|
|
@@ -29,6 +47,33 @@ export interface GridToolbarProps {
|
|
|
29
47
|
children?: React.ReactNode;
|
|
30
48
|
rightContent?: React.ReactNode;
|
|
31
49
|
style?: React.CSSProperties;
|
|
50
|
+
/**
|
|
51
|
+
* Replace the built-in Columns button. The columns panel still opens and
|
|
52
|
+
* closes normally — only the trigger element is replaced.
|
|
53
|
+
*/
|
|
54
|
+
renderColumnsButton?: (props: ToolbarButtonRenderProps) => React.ReactNode;
|
|
55
|
+
/**
|
|
56
|
+
* Replace the built-in Filters button. The filter panel still opens and
|
|
57
|
+
* closes normally — only the trigger element is replaced.
|
|
58
|
+
*/
|
|
59
|
+
renderFilterButton?: (props: ToolbarButtonRenderProps) => React.ReactNode;
|
|
60
|
+
/**
|
|
61
|
+
* Replace the built-in Aggregation/Summaries button. The aggregation panel
|
|
62
|
+
* still opens and closes normally — only the trigger element is replaced.
|
|
63
|
+
*/
|
|
64
|
+
renderAggregationButton?: (props: ToolbarButtonRenderProps) => React.ReactNode;
|
|
65
|
+
/**
|
|
66
|
+
* Render an Export button. There is no built-in export button — this slot
|
|
67
|
+
* inserts your element after the Aggregation button in the toolbar action row.
|
|
68
|
+
*/
|
|
69
|
+
renderExportButton?: () => React.ReactNode;
|
|
70
|
+
/**
|
|
71
|
+
* Replace the built-in quick-filter search bar. Receives the current search
|
|
72
|
+
* value and an onChange handler; connect them to your own input element.
|
|
73
|
+
*/
|
|
74
|
+
renderQuickFilter?: (props: ToolbarQuickFilterRenderProps) => React.ReactNode;
|
|
75
|
+
/** Additional CSS class applied to the toolbar root element. */
|
|
76
|
+
className?: string;
|
|
32
77
|
}
|
|
33
78
|
|
|
34
79
|
const AGGREGATION_FUNCTIONS = ['none', 'sum', 'avg', 'count', 'min', 'max'] as const;
|
|
@@ -78,7 +123,7 @@ function AggregationPanel({
|
|
|
78
123
|
onClose,
|
|
79
124
|
activeCount,
|
|
80
125
|
}: {
|
|
81
|
-
anchorRef: React.RefObject<
|
|
126
|
+
anchorRef: React.RefObject<HTMLElement | null>;
|
|
82
127
|
aggregationModel: GridAggregationModel;
|
|
83
128
|
aggregableColumns: GridColDef[];
|
|
84
129
|
onFunctionChange: (field: string, fn: string) => void;
|
|
@@ -205,7 +250,7 @@ function ColumnsPanelWrapper({
|
|
|
205
250
|
onColumnOrderReset,
|
|
206
251
|
onClose
|
|
207
252
|
}: {
|
|
208
|
-
anchorRef: React.RefObject<
|
|
253
|
+
anchorRef: React.RefObject<HTMLElement | null>;
|
|
209
254
|
columns: GridColDef[];
|
|
210
255
|
visibleColumns: Set<string>;
|
|
211
256
|
onVisibilityChange: (field: string, isVisible: boolean) => void;
|
|
@@ -286,7 +331,7 @@ function FilterPanelWrapper({
|
|
|
286
331
|
onFilterModelChange,
|
|
287
332
|
onClose
|
|
288
333
|
}: {
|
|
289
|
-
anchorRef: React.RefObject<
|
|
334
|
+
anchorRef: React.RefObject<HTMLElement | null>;
|
|
290
335
|
columns: GridColDef[];
|
|
291
336
|
filterModel: GridFilterModel;
|
|
292
337
|
onFilterModelChange: (model: GridFilterModel) => void;
|
|
@@ -413,6 +458,12 @@ export function GridToolbar({
|
|
|
413
458
|
children,
|
|
414
459
|
rightContent,
|
|
415
460
|
style,
|
|
461
|
+
renderColumnsButton,
|
|
462
|
+
renderFilterButton,
|
|
463
|
+
renderAggregationButton,
|
|
464
|
+
renderExportButton,
|
|
465
|
+
renderQuickFilter,
|
|
466
|
+
className,
|
|
416
467
|
}: GridToolbarProps) {
|
|
417
468
|
const [aggOpen, setAggOpen] = useState(false);
|
|
418
469
|
const [pivotOpen, setPivotOpen] = useState(false);
|
|
@@ -433,6 +484,12 @@ export function GridToolbar({
|
|
|
433
484
|
const colsButtonRef = useRef<HTMLButtonElement>(null);
|
|
434
485
|
const filterButtonRef = useRef<HTMLButtonElement>(null);
|
|
435
486
|
|
|
487
|
+
// Wrapper div refs — used as panel anchors when a custom button renderer
|
|
488
|
+
// is provided (the custom element doesn't expose a ref to us).
|
|
489
|
+
const colsWrapperRef = useRef<HTMLDivElement>(null);
|
|
490
|
+
const filterWrapperRef = useRef<HTMLDivElement>(null);
|
|
491
|
+
const aggWrapperRef = useRef<HTMLDivElement>(null);
|
|
492
|
+
|
|
436
493
|
const currentPivotModel = pivotModel ?? EMPTY_PIVOT;
|
|
437
494
|
const pivotActive = currentPivotModel.rowFields.length > 0
|
|
438
495
|
|| currentPivotModel.columnFields.length > 0
|
|
@@ -512,7 +569,7 @@ export function GridToolbar({
|
|
|
512
569
|
}, [columns, columnVisibilityModel, onColumnVisibilityModelChange]);
|
|
513
570
|
|
|
514
571
|
return (
|
|
515
|
-
<div className=
|
|
572
|
+
<div className={['ogx-toolbar', className].filter(Boolean).join(' ')} role="toolbar" aria-label="Grid toolbar" style={style}>
|
|
516
573
|
{/* Left slot — custom content */}
|
|
517
574
|
{children && <div className="ogx-toolbar__left">{children}</div>}
|
|
518
575
|
|
|
@@ -523,35 +580,49 @@ export function GridToolbar({
|
|
|
523
580
|
<div className="ogx-toolbar__actions">
|
|
524
581
|
{onFilterModelChange && (
|
|
525
582
|
<div className="ogx-toolbar__dropdown-wrapper" style={{ marginRight: 4 }}>
|
|
526
|
-
|
|
527
|
-
value
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
583
|
+
{renderQuickFilter
|
|
584
|
+
? renderQuickFilter({ value: searchValue, onChange: handleSearchChange })
|
|
585
|
+
: (
|
|
586
|
+
<GlobalSearch
|
|
587
|
+
value={searchValue}
|
|
588
|
+
onChange={handleSearchChange}
|
|
589
|
+
placeholder="Search..."
|
|
590
|
+
/>
|
|
591
|
+
)
|
|
592
|
+
}
|
|
531
593
|
</div>
|
|
532
594
|
)}
|
|
533
595
|
|
|
534
596
|
{/* Columns Button */}
|
|
535
597
|
{onColumnVisibilityModelChange && (
|
|
536
|
-
<div className="ogx-toolbar__dropdown-wrapper" style={{ marginRight: 4 }}>
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
598
|
+
<div ref={colsWrapperRef} className="ogx-toolbar__dropdown-wrapper" style={{ marginRight: 4 }}>
|
|
599
|
+
{renderColumnsButton
|
|
600
|
+
? renderColumnsButton({
|
|
601
|
+
onClick: () => { setColsOpen(o => !o); setAggOpen(false); setPivotOpen(false); setFilterOpen(false); },
|
|
602
|
+
isOpen: colsOpen,
|
|
603
|
+
activeCount: columns.length - visibleColumns.size,
|
|
604
|
+
})
|
|
605
|
+
: (
|
|
606
|
+
<GridTooltip title="Columns">
|
|
607
|
+
<button
|
|
608
|
+
ref={colsButtonRef}
|
|
609
|
+
className={`ogx-toolbar__icon-btn${colsOpen ? ' ogx-toolbar__icon-btn--active' : ''}`}
|
|
610
|
+
aria-label="Manage columns"
|
|
611
|
+
onClick={() => {
|
|
612
|
+
setColsOpen(!colsOpen);
|
|
613
|
+
setAggOpen(false);
|
|
614
|
+
setPivotOpen(false);
|
|
615
|
+
setFilterOpen(false);
|
|
616
|
+
}}
|
|
617
|
+
>
|
|
618
|
+
<ViewColumnIcon />
|
|
619
|
+
</button>
|
|
620
|
+
</GridTooltip>
|
|
621
|
+
)
|
|
622
|
+
}
|
|
552
623
|
{colsOpen && (
|
|
553
624
|
<ColumnsPanelWrapper
|
|
554
|
-
anchorRef={colsButtonRef}
|
|
625
|
+
anchorRef={renderColumnsButton ? colsWrapperRef : colsButtonRef}
|
|
555
626
|
columns={columns}
|
|
556
627
|
visibleColumns={visibleColumns}
|
|
557
628
|
onVisibilityChange={handleVisibilityChange}
|
|
@@ -567,28 +638,37 @@ export function GridToolbar({
|
|
|
567
638
|
|
|
568
639
|
{/* Filters Button */}
|
|
569
640
|
{onFilterModelChange && (
|
|
570
|
-
<div className="ogx-toolbar__dropdown-wrapper" style={{ marginRight: 4 }}>
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
641
|
+
<div ref={filterWrapperRef} className="ogx-toolbar__dropdown-wrapper" style={{ marginRight: 4 }}>
|
|
642
|
+
{renderFilterButton
|
|
643
|
+
? renderFilterButton({
|
|
644
|
+
onClick: () => { setFilterOpen(o => !o); setAggOpen(false); setPivotOpen(false); setColsOpen(false); },
|
|
645
|
+
isOpen: filterOpen,
|
|
646
|
+
activeCount: activeFilterCount,
|
|
647
|
+
})
|
|
648
|
+
: (
|
|
649
|
+
<GridTooltip title="Filters">
|
|
650
|
+
<button
|
|
651
|
+
ref={filterButtonRef}
|
|
652
|
+
className={`ogx-toolbar__icon-btn${filterOpen ? ' ogx-toolbar__icon-btn--active' : ''}`}
|
|
653
|
+
aria-label="Advanced filters"
|
|
654
|
+
onClick={() => {
|
|
655
|
+
setFilterOpen(!filterOpen);
|
|
656
|
+
setAggOpen(false);
|
|
657
|
+
setPivotOpen(false);
|
|
658
|
+
setColsOpen(false);
|
|
659
|
+
}}
|
|
660
|
+
>
|
|
661
|
+
<FilterIcon />
|
|
662
|
+
{activeFilterCount > 0 && (
|
|
663
|
+
<span className="ogx-toolbar__dot" aria-label="Filters active" />
|
|
664
|
+
)}
|
|
665
|
+
</button>
|
|
666
|
+
</GridTooltip>
|
|
667
|
+
)
|
|
668
|
+
}
|
|
589
669
|
{filterOpen && (
|
|
590
670
|
<FilterPanelWrapper
|
|
591
|
-
anchorRef={filterButtonRef}
|
|
671
|
+
anchorRef={renderFilterButton ? filterWrapperRef : filterButtonRef}
|
|
592
672
|
columns={columns}
|
|
593
673
|
filterModel={filterModel || { items: [] }}
|
|
594
674
|
onFilterModelChange={onFilterModelChange}
|
|
@@ -636,32 +716,41 @@ export function GridToolbar({
|
|
|
636
716
|
)}
|
|
637
717
|
|
|
638
718
|
{/* Summaries button */}
|
|
639
|
-
<div className="ogx-toolbar__dropdown-wrapper" style={{ marginRight: 4 }}>
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
719
|
+
<div ref={aggWrapperRef} className="ogx-toolbar__dropdown-wrapper" style={{ marginRight: 4 }}>
|
|
720
|
+
{renderAggregationButton
|
|
721
|
+
? renderAggregationButton({
|
|
722
|
+
onClick: () => { setAggOpen(o => !o); setPivotOpen(false); setColsOpen(false); setFilterOpen(false); },
|
|
723
|
+
isOpen: aggOpen,
|
|
724
|
+
activeCount,
|
|
725
|
+
})
|
|
726
|
+
: (
|
|
727
|
+
<GridTooltip title="Summaries">
|
|
728
|
+
<button
|
|
729
|
+
ref={aggButtonRef}
|
|
730
|
+
id="ogx-aggregation-btn"
|
|
731
|
+
className={`ogx-toolbar__icon-btn${aggOpen ? ' ogx-toolbar__icon-btn--active' : ''}`}
|
|
732
|
+
aria-label="Configure summaries"
|
|
733
|
+
aria-expanded={aggOpen}
|
|
734
|
+
aria-controls="ogx-aggregation-panel"
|
|
735
|
+
onClick={() => {
|
|
736
|
+
setAggOpen(!aggOpen);
|
|
737
|
+
setPivotOpen(false);
|
|
738
|
+
setColsOpen(false);
|
|
739
|
+
setFilterOpen(false);
|
|
740
|
+
}}
|
|
741
|
+
>
|
|
742
|
+
<SigmaIcon />
|
|
743
|
+
{activeCount > 0 && (
|
|
744
|
+
<span className="ogx-toolbar__dot" aria-label={`${activeCount} active summaries`} />
|
|
745
|
+
)}
|
|
746
|
+
</button>
|
|
747
|
+
</GridTooltip>
|
|
748
|
+
)
|
|
749
|
+
}
|
|
661
750
|
|
|
662
751
|
{aggOpen && (
|
|
663
752
|
<AggregationPanel
|
|
664
|
-
anchorRef={aggButtonRef}
|
|
753
|
+
anchorRef={renderAggregationButton ? aggWrapperRef : aggButtonRef}
|
|
665
754
|
aggregationModel={aggregationModel}
|
|
666
755
|
aggregableColumns={aggregableColumns}
|
|
667
756
|
onFunctionChange={handleFunctionChange}
|
|
@@ -672,6 +761,9 @@ export function GridToolbar({
|
|
|
672
761
|
)}
|
|
673
762
|
</div>
|
|
674
763
|
|
|
764
|
+
{/* Export button slot */}
|
|
765
|
+
{renderExportButton && renderExportButton()}
|
|
766
|
+
|
|
675
767
|
{rightContent}
|
|
676
768
|
</div>
|
|
677
769
|
</div>
|
package/lib/index.ts
CHANGED
|
@@ -9,7 +9,7 @@ export { Header } from './components/Header/Header';
|
|
|
9
9
|
export { Skeleton } from './components/Skeleton/Skeleton';
|
|
10
10
|
export { FilterPanel } from './components/FilterPanel';
|
|
11
11
|
export { GridToolbar } from './components/Toolbar/GridToolbar';
|
|
12
|
-
export type { GridToolbarProps } from './components/Toolbar/GridToolbar';
|
|
12
|
+
export type { GridToolbarProps, ToolbarButtonRenderProps, ToolbarQuickFilterRenderProps } from './components/Toolbar/GridToolbar';
|
|
13
13
|
export { GridTooltip } from './components/Tooltip/Tooltip';
|
|
14
14
|
|
|
15
15
|
export { useGridApiRef } from './hooks/core/useGridApiRef';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opencorestack/opengridx",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "OpenGridX: High-performance React data infrastructure. Unlock advanced Row Grouping, Excel Export, and Column Pinning without the usual \"Pro\" gatekeeping. Built for speed, scale, and complete architectural freedom. Fully open, virtualization-ready, and feature-complete.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/opengridx.umd.js",
|