@opencorestack/opengridx 1.0.5 → 1.0.7
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.css +1 -1
- package/dist/opengridx.es.js +2649 -2610
- package/dist/opengridx.es.js.map +1 -1
- package/dist/opengridx.umd.js +11 -11
- 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/ColumnVisibilityPanel/ColumnVisibilityPanel.tsx +0 -2
- package/lib/components/DataGrid/DataGrid.css +36 -0
- package/lib/components/DataGrid/DataGrid.tsx +4 -2
- package/lib/components/DataGrid/GridAggregationFooter.tsx +47 -9
- package/lib/components/DataGrid/GridStandaloneColumnPanel.tsx +3 -1
- package/lib/components/FilterPanel/FilterPanel.tsx +5 -4
- package/lib/components/Header/Header.tsx +4 -3
- package/lib/components/Pagination/Pagination.tsx +4 -3
- package/lib/components/Row/Row.tsx +3 -2
- package/lib/components/Toolbar/GlobalSearch.tsx +0 -2
- package/lib/components/Toolbar/GridToolbar.tsx +159 -71
- package/lib/index.ts +1 -1
- package/package.json +1 -1
|
@@ -6,6 +6,7 @@ import type { GridColDef, GridRowModel, GridColumnOrderChangeParams } from '../.
|
|
|
6
6
|
export interface GridStandaloneColumnPanelProps<R extends GridRowModel> {
|
|
7
7
|
isOpen: boolean;
|
|
8
8
|
containerRef: React.RefObject<HTMLDivElement | null>;
|
|
9
|
+
panelRef?: React.RefObject<HTMLDivElement | null>;
|
|
9
10
|
effectiveColumns: GridColDef<R>[];
|
|
10
11
|
columnVisibilityModel: Record<string, boolean>;
|
|
11
12
|
effectiveColumnOrder: string[];
|
|
@@ -20,6 +21,7 @@ export interface GridStandaloneColumnPanelProps<R extends GridRowModel> {
|
|
|
20
21
|
export function GridStandaloneColumnPanel<R extends GridRowModel>({
|
|
21
22
|
isOpen,
|
|
22
23
|
containerRef,
|
|
24
|
+
panelRef,
|
|
23
25
|
effectiveColumns,
|
|
24
26
|
columnVisibilityModel,
|
|
25
27
|
effectiveColumnOrder,
|
|
@@ -64,7 +66,7 @@ export function GridStandaloneColumnPanel<R extends GridRowModel>({
|
|
|
64
66
|
|
|
65
67
|
return ReactDOM.createPortal(
|
|
66
68
|
<div
|
|
67
|
-
|
|
69
|
+
ref={panelRef}
|
|
68
70
|
style={{
|
|
69
71
|
position: 'fixed',
|
|
70
72
|
top: panelTop,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
1
|
+
import React, { useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
2
2
|
import type {
|
|
3
3
|
GridFilterModel,
|
|
4
4
|
GridFilterItem,
|
|
@@ -25,6 +25,7 @@ const FilterRow: React.FC<{
|
|
|
25
25
|
item: GridFilterItem | undefined;
|
|
26
26
|
onChange: (item: GridFilterItem | null) => void;
|
|
27
27
|
}> = ({ col, item, onChange }) => {
|
|
28
|
+
const filterId = useId();
|
|
28
29
|
const operators = getOperatorsForType(col.type);
|
|
29
30
|
const isActive = !!item;
|
|
30
31
|
const currentOperator = item?.operator ?? operators[0];
|
|
@@ -99,7 +100,7 @@ const FilterRow: React.FC<{
|
|
|
99
100
|
<div className="ogx-filter__controls">
|
|
100
101
|
{ }
|
|
101
102
|
<select
|
|
102
|
-
id={
|
|
103
|
+
id={`${filterId}-op`}
|
|
103
104
|
name={`filter-op-${col.field}`}
|
|
104
105
|
className={`ogx-filter__op-select${isActive ? ' ogx-filter__op-select--active' : ''}`}
|
|
105
106
|
value={String(currentOperator)}
|
|
@@ -114,7 +115,7 @@ const FilterRow: React.FC<{
|
|
|
114
115
|
{ }
|
|
115
116
|
{showValue && isBoolean && (
|
|
116
117
|
<select
|
|
117
|
-
id={
|
|
118
|
+
id={`${filterId}-val`}
|
|
118
119
|
name={`filter-val-${col.field}`}
|
|
119
120
|
className={`ogx-filter__value-input ogx-filter__value-select${isActive ? ' ogx-filter__value-input--active' : ''}`}
|
|
120
121
|
value={String(item?.value ?? 'true')}
|
|
@@ -136,7 +137,7 @@ const FilterRow: React.FC<{
|
|
|
136
137
|
|
|
137
138
|
{showValue && !isBoolean && (
|
|
138
139
|
<input
|
|
139
|
-
id={
|
|
140
|
+
id={`${filterId}-val`}
|
|
140
141
|
name={`filter-val-${col.field}`}
|
|
141
142
|
className={`ogx-filter__value-input${isActive ? ' ogx-filter__value-input--active' : ''}`}
|
|
142
143
|
type="text"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useId } from 'react';
|
|
2
2
|
import { Checkbox } from '../ui/Checkbox';
|
|
3
3
|
import { ColumnResizeHandle } from '../ColumnResizeHandle/ColumnResizeHandle';
|
|
4
4
|
import type { GridColDef, GridRowModel, GridSortDirection, GridColumnPinning, GridAggregationModel, GridColumnGroup, GridColumnGroupingModel } from '../../types';
|
|
@@ -171,6 +171,7 @@ export function Header<R extends GridRowModel = GridRowModel>(props: HeaderProps
|
|
|
171
171
|
onManageColumns,
|
|
172
172
|
} = props;
|
|
173
173
|
|
|
174
|
+
const selectAllId = useId();
|
|
174
175
|
const cellRefs = React.useRef<Record<string, HTMLElement | null>>({});
|
|
175
176
|
const [menuOpenParams, setMenuOpenParams] = React.useState<{ colDef: GridColDef<R>; anchorEl: HTMLElement } | null>(null);
|
|
176
177
|
|
|
@@ -340,8 +341,8 @@ export function Header<R extends GridRowModel = GridRowModel>(props: HeaderProps
|
|
|
340
341
|
}}
|
|
341
342
|
>
|
|
342
343
|
<Checkbox
|
|
343
|
-
id=
|
|
344
|
-
name=
|
|
344
|
+
id={selectAllId}
|
|
345
|
+
name={selectAllId}
|
|
345
346
|
checked={allSelected}
|
|
346
347
|
indeterminate={someSelected}
|
|
347
348
|
onChange={(e) => onSelectAll?.(e.target.checked)}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import React from 'react';
|
|
2
|
+
import React, { useId } from 'react';
|
|
3
3
|
import { Button } from '../ui/Button';
|
|
4
4
|
|
|
5
5
|
export interface PaginationProps {
|
|
@@ -14,6 +14,7 @@ export interface PaginationProps {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export function Pagination(props: PaginationProps) {
|
|
17
|
+
const pageSizeId = useId();
|
|
17
18
|
const {
|
|
18
19
|
page,
|
|
19
20
|
pageSize,
|
|
@@ -61,11 +62,11 @@ export function Pagination(props: PaginationProps) {
|
|
|
61
62
|
<div className="ogx-pagination" role="navigation" aria-label="Pagination">
|
|
62
63
|
{ }
|
|
63
64
|
<div className="ogx-pagination__page-size">
|
|
64
|
-
<label htmlFor=
|
|
65
|
+
<label htmlFor={pageSizeId} className="ogx-pagination__label">
|
|
65
66
|
Rows per page:
|
|
66
67
|
</label>
|
|
67
68
|
<select
|
|
68
|
-
id=
|
|
69
|
+
id={pageSizeId}
|
|
69
70
|
className="ogx-pagination__select"
|
|
70
71
|
value={pageSize}
|
|
71
72
|
onChange={handlePageSizeChange}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import React from 'react';
|
|
2
|
+
import React, { useId } from 'react';
|
|
3
3
|
import { Cell } from '../Cell/Cell';
|
|
4
4
|
import { Checkbox } from '../ui/Checkbox';
|
|
5
5
|
import { ExpandIcon } from '../ui/ExpandIcon';
|
|
@@ -94,6 +94,7 @@ export function Row<R extends GridRowModel = GridRowModel>(props: RowProps<R>) {
|
|
|
94
94
|
rowHeight = 52
|
|
95
95
|
} = props;
|
|
96
96
|
|
|
97
|
+
const checkboxId = useId();
|
|
97
98
|
const expandCellRef = React.useRef<HTMLDivElement>(null);
|
|
98
99
|
const checkboxCellRef = React.useRef<HTMLDivElement>(null);
|
|
99
100
|
|
|
@@ -291,7 +292,7 @@ export function Row<R extends GridRowModel = GridRowModel>(props: RowProps<R>) {
|
|
|
291
292
|
}}
|
|
292
293
|
>
|
|
293
294
|
<Checkbox
|
|
294
|
-
id={
|
|
295
|
+
id={checkboxId}
|
|
295
296
|
name={`ogx-select-row-${row.id}`}
|
|
296
297
|
checked={isSelected}
|
|
297
298
|
onChange={handleCheckboxChange}
|
|
@@ -146,8 +146,6 @@ export function GlobalSearch({ value = '', onChange, placeholder = 'Search...',
|
|
|
146
146
|
</div>
|
|
147
147
|
<input
|
|
148
148
|
ref={inputRef}
|
|
149
|
-
id="ogx-global-search-input"
|
|
150
|
-
name="ogx-global-search"
|
|
151
149
|
className="ogx-global-search__input"
|
|
152
150
|
value={localValue}
|
|
153
151
|
onChange={(e) => setLocalValue(e.target.value)}
|
|
@@ -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}
|
|
@@ -604,11 +684,9 @@ export function GridToolbar({
|
|
|
604
684
|
<GridTooltip title="Pivot">
|
|
605
685
|
<button
|
|
606
686
|
ref={pivotButtonRef}
|
|
607
|
-
id="ogx-pivot-btn"
|
|
608
687
|
className={`ogx-toolbar__icon-btn${pivotOpen ? ' ogx-toolbar__icon-btn--active' : ''}`}
|
|
609
688
|
aria-label="Configure pivot"
|
|
610
689
|
aria-expanded={pivotOpen}
|
|
611
|
-
aria-controls="ogx-pivot-panel"
|
|
612
690
|
onClick={() => {
|
|
613
691
|
setPivotOpen(!pivotOpen);
|
|
614
692
|
setAggOpen(false);
|
|
@@ -636,32 +714,39 @@ export function GridToolbar({
|
|
|
636
714
|
)}
|
|
637
715
|
|
|
638
716
|
{/* 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
|
-
|
|
717
|
+
<div ref={aggWrapperRef} className="ogx-toolbar__dropdown-wrapper" style={{ marginRight: 4 }}>
|
|
718
|
+
{renderAggregationButton
|
|
719
|
+
? renderAggregationButton({
|
|
720
|
+
onClick: () => { setAggOpen(o => !o); setPivotOpen(false); setColsOpen(false); setFilterOpen(false); },
|
|
721
|
+
isOpen: aggOpen,
|
|
722
|
+
activeCount,
|
|
723
|
+
})
|
|
724
|
+
: (
|
|
725
|
+
<GridTooltip title="Summaries">
|
|
726
|
+
<button
|
|
727
|
+
ref={aggButtonRef}
|
|
728
|
+
className={`ogx-toolbar__icon-btn${aggOpen ? ' ogx-toolbar__icon-btn--active' : ''}`}
|
|
729
|
+
aria-label="Configure summaries"
|
|
730
|
+
aria-expanded={aggOpen}
|
|
731
|
+
onClick={() => {
|
|
732
|
+
setAggOpen(!aggOpen);
|
|
733
|
+
setPivotOpen(false);
|
|
734
|
+
setColsOpen(false);
|
|
735
|
+
setFilterOpen(false);
|
|
736
|
+
}}
|
|
737
|
+
>
|
|
738
|
+
<SigmaIcon />
|
|
739
|
+
{activeCount > 0 && (
|
|
740
|
+
<span className="ogx-toolbar__dot" aria-label={`${activeCount} active summaries`} />
|
|
741
|
+
)}
|
|
742
|
+
</button>
|
|
743
|
+
</GridTooltip>
|
|
744
|
+
)
|
|
745
|
+
}
|
|
661
746
|
|
|
662
747
|
{aggOpen && (
|
|
663
748
|
<AggregationPanel
|
|
664
|
-
anchorRef={aggButtonRef}
|
|
749
|
+
anchorRef={renderAggregationButton ? aggWrapperRef : aggButtonRef}
|
|
665
750
|
aggregationModel={aggregationModel}
|
|
666
751
|
aggregableColumns={aggregableColumns}
|
|
667
752
|
onFunctionChange={handleFunctionChange}
|
|
@@ -672,6 +757,9 @@ export function GridToolbar({
|
|
|
672
757
|
)}
|
|
673
758
|
</div>
|
|
674
759
|
|
|
760
|
+
{/* Export button slot */}
|
|
761
|
+
{renderExportButton && renderExportButton()}
|
|
762
|
+
|
|
675
763
|
{rightContent}
|
|
676
764
|
</div>
|
|
677
765
|
</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.7",
|
|
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",
|