@alaarab/ogrid-react 2.0.9 → 2.0.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/dist/esm/components/BaseInlineCellEditor.js +2 -2
- package/dist/esm/components/CellErrorBoundary.js +1 -1
- package/dist/esm/components/ColumnChooserProps.js +6 -0
- package/dist/esm/components/ColumnHeaderFilterContent.js +35 -0
- package/dist/esm/components/ColumnHeaderFilterRenderers.js +67 -0
- package/dist/esm/components/MarchingAntsOverlay.js +25 -44
- package/dist/esm/components/PaginationControlsProps.js +6 -0
- package/dist/esm/constants/domHelpers.js +16 -0
- package/dist/esm/hooks/index.js +2 -0
- package/dist/esm/hooks/useColumnHeaderMenuState.js +52 -2
- package/dist/esm/hooks/useColumnResize.js +29 -0
- package/dist/esm/hooks/useDataGridState.js +77 -10
- package/dist/esm/hooks/useDataGridTableOrchestration.js +200 -0
- package/dist/esm/hooks/useDebounce.js +1 -1
- package/dist/esm/hooks/useOGrid.js +3 -6
- package/dist/esm/hooks/usePaginationControls.js +19 -0
- package/dist/esm/index.js +6 -1
- package/dist/esm/utils/index.js +1 -1
- package/dist/types/components/ColumnChooserProps.d.ts +12 -0
- package/dist/types/components/ColumnHeaderFilterContent.d.ts +62 -0
- package/dist/types/components/ColumnHeaderFilterRenderers.d.ts +71 -0
- package/dist/types/components/MarchingAntsOverlay.d.ts +11 -1
- package/dist/types/components/PaginationControlsProps.d.ts +15 -0
- package/dist/types/constants/domHelpers.d.ts +17 -0
- package/dist/types/hooks/index.d.ts +5 -1
- package/dist/types/hooks/useColumnHeaderMenuState.d.ts +23 -1
- package/dist/types/hooks/useDataGridState.d.ts +10 -6
- package/dist/types/hooks/useDataGridTableOrchestration.d.ts +131 -0
- package/dist/types/hooks/usePaginationControls.d.ts +20 -0
- package/dist/types/index.d.ts +9 -2
- package/dist/types/types/dataGridTypes.d.ts +1 -1
- package/dist/types/utils/index.d.ts +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { useCallback, useRef, useMemo } from 'react';
|
|
2
|
+
import { useDataGridState } from './useDataGridState';
|
|
3
|
+
import { useColumnResize } from './useColumnResize';
|
|
4
|
+
import { useColumnReorder } from './useColumnReorder';
|
|
5
|
+
import { useVirtualScroll } from './useVirtualScroll';
|
|
6
|
+
import { useLatestRef } from './useLatestRef';
|
|
7
|
+
import { buildHeaderRows } from '../utils';
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// Hook
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
/**
|
|
12
|
+
* Shared orchestration hook for DataGridTable.
|
|
13
|
+
*
|
|
14
|
+
* Encapsulates all state management and computation that is identical across
|
|
15
|
+
* Radix, Fluent, and Material DataGridTable implementations. Each UI package
|
|
16
|
+
* calls this hook, then renders its own framework-specific JSX using the
|
|
17
|
+
* returned values.
|
|
18
|
+
*/
|
|
19
|
+
export function useDataGridTableOrchestration(params) {
|
|
20
|
+
const { props } = params;
|
|
21
|
+
// ── Refs ────────────────────────────────────────────────────────────────
|
|
22
|
+
const wrapperRef = useRef(null);
|
|
23
|
+
const tableContainerRef = useRef(null);
|
|
24
|
+
const lastMouseShiftRef = useRef(false);
|
|
25
|
+
// ── Core state ──────────────────────────────────────────────────────────
|
|
26
|
+
const state = useDataGridState({ props, wrapperRef });
|
|
27
|
+
const { layout, rowSelection: rowSel, editing, interaction, contextMenu: ctxMenu, viewModels, pinning } = state;
|
|
28
|
+
const { visibleCols: visibleColsTyped, totalColCount, hasCheckboxCol, hasRowNumbersCol, colOffset, containerWidth, minTableWidth, desiredTableWidth, columnSizingOverrides, setColumnSizingOverrides, } = layout;
|
|
29
|
+
const visibleCols = visibleColsTyped;
|
|
30
|
+
const { selectedRowIds, updateSelection, handleRowCheckboxChange, handleSelectAll, allSelected, someSelected } = rowSel;
|
|
31
|
+
const { editingCell, setEditingCell, pendingEditorValue, setPendingEditorValue, commitCellEdit, cancelPopoverEdit, popoverAnchorEl, setPopoverAnchorEl } = editing;
|
|
32
|
+
const { setActiveCell, handleCellMouseDown, selectionRange, hasCellSelection, handleGridKeyDown, handleFillHandleMouseDown, handleCopy, handleCut, handlePaste, cutRange, copyRange, canUndo, canRedo, onUndo, onRedo, isDragging } = interaction;
|
|
33
|
+
const { menuPosition, handleCellContextMenu, closeContextMenu } = ctxMenu;
|
|
34
|
+
const { headerFilterInput, cellDescriptorInput, statusBarConfig, showEmptyInGrid, onCellError } = viewModels;
|
|
35
|
+
const { headerMenu } = pinning;
|
|
36
|
+
const handlePasteVoid = useCallback(() => { void handlePaste(); }, [handlePaste]);
|
|
37
|
+
// ── Props destructuring ─────────────────────────────────────────────────
|
|
38
|
+
const { items, columns, getRowId, emptyState, layoutMode = 'fill', rowSelection = 'none', freezeRows, freezeCols, suppressHorizontalScroll, isLoading = false, loadingMessage = 'Loading\u2026', 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, visibleColumns, columnOrder, onColumnOrderChange, columnReorder, virtualScroll, density = 'normal', pinnedColumns, currentPage = 1, pageSize: propPageSize = 25, } = props;
|
|
39
|
+
// ── Derived values ──────────────────────────────────────────────────────
|
|
40
|
+
const rowNumberOffset = hasRowNumbersCol ? (currentPage - 1) * propPageSize : 0;
|
|
41
|
+
const headerRows = useMemo(() => buildHeaderRows(columns, visibleColumns), [columns, visibleColumns]);
|
|
42
|
+
const allowOverflowX = !suppressHorizontalScroll && containerWidth > 0 && (minTableWidth > containerWidth || desiredTableWidth > containerWidth);
|
|
43
|
+
const fitToContent = layoutMode === 'content';
|
|
44
|
+
// ── Column resize ──────────────────────────────────────────────────────
|
|
45
|
+
const { handleResizeStart, getColumnWidth } = useColumnResize({
|
|
46
|
+
columnSizingOverrides,
|
|
47
|
+
setColumnSizingOverrides,
|
|
48
|
+
});
|
|
49
|
+
// ── Column reorder ─────────────────────────────────────────────────────
|
|
50
|
+
const { isDragging: isReorderDragging, dropIndicatorX, handleHeaderMouseDown } = useColumnReorder({
|
|
51
|
+
columns: visibleCols,
|
|
52
|
+
columnOrder,
|
|
53
|
+
onColumnOrderChange,
|
|
54
|
+
enabled: columnReorder === true,
|
|
55
|
+
pinnedColumns,
|
|
56
|
+
wrapperRef,
|
|
57
|
+
});
|
|
58
|
+
// ── Virtual scroll ─────────────────────────────────────────────────────
|
|
59
|
+
const virtualScrollEnabled = virtualScroll?.enabled === true;
|
|
60
|
+
const virtualRowHeight = virtualScroll?.rowHeight ?? 36;
|
|
61
|
+
const { visibleRange } = useVirtualScroll({
|
|
62
|
+
totalRows: items.length,
|
|
63
|
+
rowHeight: virtualRowHeight,
|
|
64
|
+
enabled: virtualScrollEnabled,
|
|
65
|
+
overscan: virtualScroll?.overscan,
|
|
66
|
+
containerRef: wrapperRef,
|
|
67
|
+
});
|
|
68
|
+
// ── Memoized callback groups ───────────────────────────────────────────
|
|
69
|
+
const editCallbacks = useMemo(() => ({ commitCellEdit, setEditingCell, setPendingEditorValue, cancelPopoverEdit }), [commitCellEdit, setEditingCell, setPendingEditorValue, cancelPopoverEdit]);
|
|
70
|
+
const interactionHandlers = useMemo(() => ({ handleCellMouseDown, setActiveCell, setEditingCell, handleCellContextMenu }), [handleCellMouseDown, setActiveCell, setEditingCell, handleCellContextMenu]);
|
|
71
|
+
// ── Stable refs for volatile state ─────────────────────────────────────
|
|
72
|
+
const cellDescriptorInputRef = useLatestRef(cellDescriptorInput);
|
|
73
|
+
const pendingEditorValueRef = useLatestRef(pendingEditorValue);
|
|
74
|
+
const popoverAnchorElRef = useLatestRef(popoverAnchorEl);
|
|
75
|
+
const selectedRowIdsRef = useLatestRef(selectedRowIds);
|
|
76
|
+
// ── Stable row-click handler ───────────────────────────────────────────
|
|
77
|
+
const handleSingleRowClick = useCallback((e) => {
|
|
78
|
+
if (rowSelection !== 'single')
|
|
79
|
+
return;
|
|
80
|
+
const rowId = e.currentTarget.dataset.rowId;
|
|
81
|
+
if (!rowId)
|
|
82
|
+
return;
|
|
83
|
+
const ids = selectedRowIdsRef.current;
|
|
84
|
+
updateSelection(ids.has(rowId) ? new Set() : new Set([rowId]));
|
|
85
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- selectedRowIdsRef is a stable ref
|
|
86
|
+
}, [rowSelection, updateSelection]);
|
|
87
|
+
// ── Return ─────────────────────────────────────────────────────────────
|
|
88
|
+
return {
|
|
89
|
+
// Refs
|
|
90
|
+
wrapperRef,
|
|
91
|
+
tableContainerRef,
|
|
92
|
+
lastMouseShiftRef,
|
|
93
|
+
// Full state sub-objects
|
|
94
|
+
state,
|
|
95
|
+
layout,
|
|
96
|
+
rowSel,
|
|
97
|
+
editing,
|
|
98
|
+
interaction,
|
|
99
|
+
ctxMenu,
|
|
100
|
+
viewModels,
|
|
101
|
+
pinning,
|
|
102
|
+
// Column resize
|
|
103
|
+
handleResizeStart,
|
|
104
|
+
getColumnWidth,
|
|
105
|
+
// Column reorder
|
|
106
|
+
isReorderDragging,
|
|
107
|
+
dropIndicatorX,
|
|
108
|
+
handleHeaderMouseDown,
|
|
109
|
+
// Virtual scroll
|
|
110
|
+
virtualScrollEnabled,
|
|
111
|
+
virtualRowHeight,
|
|
112
|
+
visibleRange,
|
|
113
|
+
// Derived from props
|
|
114
|
+
items,
|
|
115
|
+
columns,
|
|
116
|
+
getRowId,
|
|
117
|
+
emptyState,
|
|
118
|
+
layoutMode,
|
|
119
|
+
rowSelection,
|
|
120
|
+
freezeRows,
|
|
121
|
+
freezeCols,
|
|
122
|
+
suppressHorizontalScroll,
|
|
123
|
+
isLoading,
|
|
124
|
+
loadingMessage,
|
|
125
|
+
ariaLabel,
|
|
126
|
+
ariaLabelledBy,
|
|
127
|
+
visibleColumns,
|
|
128
|
+
columnOrder,
|
|
129
|
+
columnReorder,
|
|
130
|
+
density,
|
|
131
|
+
pinnedColumns,
|
|
132
|
+
currentPage,
|
|
133
|
+
propPageSize,
|
|
134
|
+
// Computed values
|
|
135
|
+
rowNumberOffset,
|
|
136
|
+
headerRows,
|
|
137
|
+
allowOverflowX,
|
|
138
|
+
fitToContent,
|
|
139
|
+
// Memoized callback groups
|
|
140
|
+
editCallbacks,
|
|
141
|
+
interactionHandlers,
|
|
142
|
+
// Stable refs for volatile state
|
|
143
|
+
cellDescriptorInputRef,
|
|
144
|
+
pendingEditorValueRef,
|
|
145
|
+
popoverAnchorElRef,
|
|
146
|
+
selectedRowIdsRef,
|
|
147
|
+
// Convenience handlers
|
|
148
|
+
handleSingleRowClick,
|
|
149
|
+
handlePasteVoid,
|
|
150
|
+
// Layout-derived references
|
|
151
|
+
visibleCols,
|
|
152
|
+
totalColCount,
|
|
153
|
+
hasCheckboxCol,
|
|
154
|
+
hasRowNumbersCol,
|
|
155
|
+
colOffset,
|
|
156
|
+
containerWidth,
|
|
157
|
+
minTableWidth,
|
|
158
|
+
desiredTableWidth,
|
|
159
|
+
columnSizingOverrides,
|
|
160
|
+
setColumnSizingOverrides,
|
|
161
|
+
// Row selection shortcuts
|
|
162
|
+
selectedRowIds,
|
|
163
|
+
updateSelection,
|
|
164
|
+
handleRowCheckboxChange,
|
|
165
|
+
handleSelectAll,
|
|
166
|
+
allSelected,
|
|
167
|
+
someSelected,
|
|
168
|
+
// Editing shortcuts
|
|
169
|
+
editingCell,
|
|
170
|
+
setPopoverAnchorEl,
|
|
171
|
+
cancelPopoverEdit,
|
|
172
|
+
// Interaction shortcuts
|
|
173
|
+
setActiveCell,
|
|
174
|
+
selectionRange,
|
|
175
|
+
hasCellSelection,
|
|
176
|
+
handleGridKeyDown,
|
|
177
|
+
handleFillHandleMouseDown,
|
|
178
|
+
handleCopy,
|
|
179
|
+
handleCut,
|
|
180
|
+
cutRange,
|
|
181
|
+
copyRange,
|
|
182
|
+
canUndo,
|
|
183
|
+
canRedo,
|
|
184
|
+
onUndo,
|
|
185
|
+
onRedo,
|
|
186
|
+
isDragging,
|
|
187
|
+
// Context menu shortcuts
|
|
188
|
+
menuPosition,
|
|
189
|
+
handleCellContextMenu,
|
|
190
|
+
closeContextMenu,
|
|
191
|
+
// ViewModel shortcuts
|
|
192
|
+
headerFilterInput,
|
|
193
|
+
cellDescriptorInput,
|
|
194
|
+
statusBarConfig,
|
|
195
|
+
showEmptyInGrid,
|
|
196
|
+
onCellError,
|
|
197
|
+
// Pinning shortcuts
|
|
198
|
+
headerMenu,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
@@ -17,7 +17,7 @@ export function useDebounce(value, delayMs) {
|
|
|
17
17
|
* Each new call resets the timer.
|
|
18
18
|
*/
|
|
19
19
|
export function useDebouncedCallback(fn, delayMs) {
|
|
20
|
-
const timeoutRef = useRef();
|
|
20
|
+
const timeoutRef = useRef(undefined);
|
|
21
21
|
const fnRef = useRef(fn);
|
|
22
22
|
fnRef.current = fn;
|
|
23
23
|
const debounced = useCallback(((...args) => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useMemo, useCallback, useState, useEffect, useRef, useImperativeHandle, } from 'react';
|
|
2
|
-
import { mergeFilter, deriveFilterOptionsFromData, getMultiSelectFilterFields, flattenColumns, processClientSideData, } from '../utils';
|
|
2
|
+
import { mergeFilter, deriveFilterOptionsFromData, getMultiSelectFilterFields, flattenColumns, processClientSideData, computeNextSortState, } from '../utils';
|
|
3
3
|
import { useFilterOptions } from './useFilterOptions';
|
|
4
4
|
import { useSideBarState } from './useSideBarState';
|
|
5
5
|
const DEFAULT_PAGE_SIZE = 25;
|
|
@@ -72,11 +72,8 @@ export function useOGrid(props, ref) {
|
|
|
72
72
|
setInternalVisibleColumns(cols);
|
|
73
73
|
onVisibleColumnsChange?.(cols);
|
|
74
74
|
}, [controlledVisibleColumns, onVisibleColumnsChange]);
|
|
75
|
-
const handleSort = useCallback((columnKey) => {
|
|
76
|
-
setSort(
|
|
77
|
-
field: columnKey,
|
|
78
|
-
direction: sort.field === columnKey && sort.direction === 'asc' ? 'desc' : 'asc',
|
|
79
|
-
});
|
|
75
|
+
const handleSort = useCallback((columnKey, direction) => {
|
|
76
|
+
setSort(computeNextSortState(sort, columnKey, direction));
|
|
80
77
|
}, [sort, setSort]);
|
|
81
78
|
/** Single filter change handler — wraps discriminated FilterValue into mergeFilter. */
|
|
82
79
|
const handleFilterChange = useCallback((key, value) => {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useMemo, useCallback } from 'react';
|
|
2
|
+
import { getPaginationViewModel } from '../utils';
|
|
3
|
+
/**
|
|
4
|
+
* Shared pagination controls logic for React UI packages.
|
|
5
|
+
* Computes pagination view model and provides standardized handlers.
|
|
6
|
+
*/
|
|
7
|
+
export function usePaginationControls(props) {
|
|
8
|
+
const { currentPage, pageSize, totalCount, onPageSizeChange, pageSizeOptions, entityLabelPlural } = props;
|
|
9
|
+
const labelPlural = entityLabelPlural ?? 'items';
|
|
10
|
+
const vm = useMemo(() => getPaginationViewModel(currentPage, pageSize, totalCount, pageSizeOptions ? { pageSizeOptions } : undefined), [currentPage, pageSize, totalCount, pageSizeOptions]);
|
|
11
|
+
const handlePageSizeChange = useCallback((value) => {
|
|
12
|
+
onPageSizeChange(value);
|
|
13
|
+
}, [onPageSizeChange]);
|
|
14
|
+
return {
|
|
15
|
+
labelPlural,
|
|
16
|
+
vm,
|
|
17
|
+
handlePageSizeChange,
|
|
18
|
+
};
|
|
19
|
+
}
|
package/dist/esm/index.js
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
export { CHECKBOX_COLUMN_WIDTH, ROW_NUMBER_COLUMN_WIDTH, DEFAULT_MIN_COLUMN_WIDTH, CELL_PADDING, GRID_BORDER_RADIUS, } from '@alaarab/ogrid-core';
|
|
3
3
|
export { toUserLike, isInSelectionRange, normalizeSelectionRange } from './types';
|
|
4
4
|
// Hooks
|
|
5
|
-
export { useFilterOptions, useOGrid, useActiveCell, useCellEditing, useContextMenu, useCellSelection, useClipboard, useRowSelection, useKeyboardNavigation, useUndoRedo, useDebounce, useFillHandle, useDataGridState, useColumnHeaderFilterState, useTextFilterState, useMultiSelectFilterState, usePeopleFilterState, useDateFilterState, useColumnChooserState, useInlineCellEditorState, useColumnResize, useRichSelectState, useSideBarState, useTableLayout, useColumnReorder, useVirtualScroll, useLatestRef, } from './hooks';
|
|
5
|
+
export { useFilterOptions, useOGrid, useActiveCell, useCellEditing, useContextMenu, useCellSelection, useClipboard, useRowSelection, useKeyboardNavigation, useUndoRedo, useDebounce, useFillHandle, useDataGridState, useColumnHeaderFilterState, useTextFilterState, useMultiSelectFilterState, usePeopleFilterState, useDateFilterState, useColumnChooserState, useInlineCellEditorState, useColumnResize, useRichSelectState, useSideBarState, useTableLayout, useColumnReorder, useVirtualScroll, useLatestRef, usePaginationControls, useDataGridTableOrchestration, } from './hooks';
|
|
6
|
+
// Constants
|
|
7
|
+
export { GRID_ROOT_STYLE, CURSOR_CELL_STYLE, POPOVER_ANCHOR_STYLE, PREVENT_DEFAULT, NOOP, STOP_PROPAGATION, } from './constants/domHelpers';
|
|
6
8
|
// Components
|
|
7
9
|
export { OGridLayout } from './components/OGridLayout';
|
|
8
10
|
export { StatusBar } from './components/StatusBar';
|
|
@@ -12,5 +14,8 @@ export { MarchingAntsOverlay } from './components/MarchingAntsOverlay';
|
|
|
12
14
|
export { SideBar } from './components/SideBar';
|
|
13
15
|
export { CellErrorBoundary } from './components/CellErrorBoundary';
|
|
14
16
|
export { EmptyState } from './components/EmptyState';
|
|
17
|
+
export { DateFilterContent, getColumnHeaderFilterStateParams, getDateFilterContentProps, } from './components/ColumnHeaderFilterContent';
|
|
15
18
|
// Utilities
|
|
16
19
|
export { escapeCsvValue, buildCsvHeader, buildCsvRows, exportToCsv, triggerCsvDownload, getCellValue, flattenColumns, buildHeaderRows, getFilterField, mergeFilter, deriveFilterOptionsFromData, getMultiSelectFilterFields, getStatusBarParts, getDataGridStatusBarConfig, GRID_CONTEXT_MENU_ITEMS, getContextMenuHandlers, formatShortcut, getPaginationViewModel, PAGE_SIZE_OPTIONS, MAX_PAGE_BUTTONS, getHeaderFilterConfig, getCellRenderDescriptor, isRowInRange, resolveCellDisplayContent, resolveCellStyle, buildInlineEditorProps, buildPopoverEditorProps, getCellInteractionProps, parseValue, numberParser, currencyParser, dateParser, emailParser, booleanParser, computeAggregations, processClientSideData, areGridRowPropsEqual, } from './utils';
|
|
20
|
+
// Shared component props & renderers (for UI packages to consume)
|
|
21
|
+
export { renderFilterContent } from './components/ColumnHeaderFilterRenderers';
|
package/dist/esm/utils/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Shared utilities re-exported from core
|
|
2
|
-
export { escapeCsvValue, buildCsvHeader, buildCsvRows, exportToCsv, triggerCsvDownload, getCellValue, flattenColumns, buildHeaderRows, getFilterField, mergeFilter, deriveFilterOptionsFromData, getMultiSelectFilterFields, getStatusBarParts, getDataGridStatusBarConfig, getPaginationViewModel, PAGE_SIZE_OPTIONS, MAX_PAGE_BUTTONS, GRID_CONTEXT_MENU_ITEMS, getContextMenuHandlers, formatShortcut, parseValue, numberParser, currencyParser, dateParser, emailParser, booleanParser, computeAggregations, processClientSideData, } from '@alaarab/ogrid-core';
|
|
2
|
+
export { escapeCsvValue, buildCsvHeader, buildCsvRows, exportToCsv, triggerCsvDownload, getCellValue, flattenColumns, buildHeaderRows, getFilterField, mergeFilter, deriveFilterOptionsFromData, getMultiSelectFilterFields, getStatusBarParts, getDataGridStatusBarConfig, getPaginationViewModel, PAGE_SIZE_OPTIONS, MAX_PAGE_BUTTONS, GRID_CONTEXT_MENU_ITEMS, getContextMenuHandlers, formatShortcut, parseValue, numberParser, currencyParser, dateParser, emailParser, booleanParser, computeAggregations, processClientSideData, computeNextSortState, measureColumnContentWidth, AUTOSIZE_EXTRA_PX, AUTOSIZE_MAX_PX, } from '@alaarab/ogrid-core';
|
|
3
3
|
// View model utilities (re-exported from core + React-specific getCellInteractionProps)
|
|
4
4
|
export { getHeaderFilterConfig, getCellRenderDescriptor, resolveCellDisplayContent, resolveCellStyle, buildInlineEditorProps, buildPopoverEditorProps, getCellInteractionProps, } from './dataGridViewModel';
|
|
5
5
|
export { areGridRowPropsEqual, isRowInRange } from './gridRowComparator';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared props interface for ColumnChooser across all React UI packages.
|
|
3
|
+
* Each UI package renders its own framework-specific trigger, popover, and checkboxes
|
|
4
|
+
* but shares this common prop shape.
|
|
5
|
+
*/
|
|
6
|
+
import type { IColumnDefinition } from '../types/columnTypes';
|
|
7
|
+
export interface IColumnChooserProps {
|
|
8
|
+
columns: IColumnDefinition[];
|
|
9
|
+
visibleColumns: Set<string>;
|
|
10
|
+
onVisibilityChange: (columnKey: string, visible: boolean) => void;
|
|
11
|
+
className?: string;
|
|
12
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared filter content rendering for ColumnHeaderFilter across all React UI packages.
|
|
3
|
+
* Each UI package provides its own popover wrapper + trigger; this component renders
|
|
4
|
+
* the inner filter content (text, multiselect, people, date) given the shared state
|
|
5
|
+
* from useColumnHeaderFilterState.
|
|
6
|
+
*/
|
|
7
|
+
import * as React from 'react';
|
|
8
|
+
import type { ColumnFilterType, IDateFilterValue } from '../types/columnTypes';
|
|
9
|
+
import type { UserLike } from '../types/dataGridTypes';
|
|
10
|
+
import type { UseColumnHeaderFilterStateResult } from '../hooks/useColumnHeaderFilterState';
|
|
11
|
+
export interface IColumnHeaderFilterProps {
|
|
12
|
+
columnKey: string;
|
|
13
|
+
columnName: string;
|
|
14
|
+
filterType: ColumnFilterType;
|
|
15
|
+
isSorted?: boolean;
|
|
16
|
+
isSortedDescending?: boolean;
|
|
17
|
+
onSort?: () => void;
|
|
18
|
+
selectedValues?: string[];
|
|
19
|
+
onFilterChange?: (values: string[]) => void;
|
|
20
|
+
options?: string[];
|
|
21
|
+
isLoadingOptions?: boolean;
|
|
22
|
+
textValue?: string;
|
|
23
|
+
onTextChange?: (value: string) => void;
|
|
24
|
+
selectedUser?: UserLike;
|
|
25
|
+
onUserChange?: (user: UserLike | undefined) => void;
|
|
26
|
+
peopleSearch?: (query: string) => Promise<UserLike[]>;
|
|
27
|
+
dateValue?: IDateFilterValue;
|
|
28
|
+
onDateChange?: (value: IDateFilterValue | undefined) => void;
|
|
29
|
+
}
|
|
30
|
+
export interface DateFilterContentProps {
|
|
31
|
+
tempDateFrom: string;
|
|
32
|
+
setTempDateFrom: (v: string) => void;
|
|
33
|
+
tempDateTo: string;
|
|
34
|
+
setTempDateTo: (v: string) => void;
|
|
35
|
+
onApply: () => void;
|
|
36
|
+
onClear: () => void;
|
|
37
|
+
classNames?: DateFilterClassNames;
|
|
38
|
+
}
|
|
39
|
+
export interface DateFilterClassNames {
|
|
40
|
+
popoverActions?: string;
|
|
41
|
+
clearButton?: string;
|
|
42
|
+
applyButton?: string;
|
|
43
|
+
}
|
|
44
|
+
export declare const DateFilterContent: React.FC<DateFilterContentProps>;
|
|
45
|
+
export declare function getColumnHeaderFilterStateParams(props: IColumnHeaderFilterProps): {
|
|
46
|
+
filterType: ColumnFilterType;
|
|
47
|
+
isSorted: boolean;
|
|
48
|
+
isSortedDescending: boolean;
|
|
49
|
+
onSort: (() => void) | undefined;
|
|
50
|
+
selectedValues: string[] | undefined;
|
|
51
|
+
onFilterChange: ((values: string[]) => void) | undefined;
|
|
52
|
+
options: string[] | undefined;
|
|
53
|
+
isLoadingOptions: boolean;
|
|
54
|
+
textValue: string;
|
|
55
|
+
onTextChange: ((value: string) => void) | undefined;
|
|
56
|
+
selectedUser: UserLike | undefined;
|
|
57
|
+
onUserChange: ((user: UserLike | undefined) => void) | undefined;
|
|
58
|
+
peopleSearch: ((query: string) => Promise<UserLike[]>) | undefined;
|
|
59
|
+
dateValue: IDateFilterValue | undefined;
|
|
60
|
+
onDateChange: ((value: IDateFilterValue | undefined) => void) | undefined;
|
|
61
|
+
};
|
|
62
|
+
export declare function getDateFilterContentProps(state: UseColumnHeaderFilterStateResult, classNames?: DateFilterClassNames): DateFilterContentProps;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared filter content dispatching for ColumnHeaderFilter across all React UI packages.
|
|
3
|
+
*
|
|
4
|
+
* Each UI package provides framework-specific sub-filter components (TextFilterPopover,
|
|
5
|
+
* MultiSelectFilterPopover, PeopleFilterPopover, date content). This utility dispatches
|
|
6
|
+
* to the correct renderer based on filterType, eliminating the duplicated if/switch chain
|
|
7
|
+
* that was previously in each UI package's ColumnHeaderFilter component.
|
|
8
|
+
*/
|
|
9
|
+
import type * as React from 'react';
|
|
10
|
+
import type { ColumnFilterType } from '../types/columnTypes';
|
|
11
|
+
import type { UserLike } from '../types/dataGridTypes';
|
|
12
|
+
import type { UseColumnHeaderFilterStateResult } from '../hooks/useColumnHeaderFilterState';
|
|
13
|
+
/**
|
|
14
|
+
* Framework-specific renderers for each filter type.
|
|
15
|
+
* Each UI package maps its own sub-filter components to these slots.
|
|
16
|
+
*/
|
|
17
|
+
export interface FilterContentRenderers {
|
|
18
|
+
renderMultiSelect: (props: MultiSelectRendererProps) => React.ReactNode;
|
|
19
|
+
renderText: (props: TextRendererProps) => React.ReactNode;
|
|
20
|
+
renderPeople: (props: PeopleRendererProps) => React.ReactNode;
|
|
21
|
+
renderDate: (props: DateRendererProps) => React.ReactNode;
|
|
22
|
+
}
|
|
23
|
+
export interface MultiSelectRendererProps {
|
|
24
|
+
searchText: string;
|
|
25
|
+
onSearchChange: (value: string) => void;
|
|
26
|
+
options: string[];
|
|
27
|
+
filteredOptions: string[];
|
|
28
|
+
selected: Set<string>;
|
|
29
|
+
onOptionToggle: (option: string, checked: boolean) => void;
|
|
30
|
+
onSelectAll: () => void;
|
|
31
|
+
onClearSelection: () => void;
|
|
32
|
+
onApply: () => void;
|
|
33
|
+
isLoading: boolean;
|
|
34
|
+
}
|
|
35
|
+
export interface TextRendererProps {
|
|
36
|
+
value: string;
|
|
37
|
+
onValueChange: (value: string) => void;
|
|
38
|
+
onApply: () => void;
|
|
39
|
+
onClear: () => void;
|
|
40
|
+
}
|
|
41
|
+
export interface PeopleRendererProps {
|
|
42
|
+
selectedUser: UserLike | undefined;
|
|
43
|
+
searchText: string;
|
|
44
|
+
onSearchChange: (value: string) => void;
|
|
45
|
+
suggestions: UserLike[];
|
|
46
|
+
isLoading: boolean;
|
|
47
|
+
onUserSelect: (user: UserLike) => void;
|
|
48
|
+
onClearUser: () => void;
|
|
49
|
+
inputRef: React.RefObject<HTMLInputElement | null>;
|
|
50
|
+
}
|
|
51
|
+
export interface DateRendererProps {
|
|
52
|
+
tempDateFrom: string;
|
|
53
|
+
setTempDateFrom: (v: string) => void;
|
|
54
|
+
tempDateTo: string;
|
|
55
|
+
setTempDateTo: (v: string) => void;
|
|
56
|
+
onApply: () => void;
|
|
57
|
+
onClear: () => void;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Dispatches to the appropriate filter content renderer based on filterType.
|
|
61
|
+
* Eliminates the duplicated if/switch chain in each UI package's ColumnHeaderFilter.
|
|
62
|
+
*
|
|
63
|
+
* @param filterType - The column's filter type
|
|
64
|
+
* @param state - The result from useColumnHeaderFilterState
|
|
65
|
+
* @param options - The filter options array (for multiSelect)
|
|
66
|
+
* @param isLoadingOptions - Whether options are loading
|
|
67
|
+
* @param selectedUser - The currently selected user (for people filter)
|
|
68
|
+
* @param renderers - Framework-specific renderer functions
|
|
69
|
+
* @returns The rendered filter content, or null for unsupported filter types
|
|
70
|
+
*/
|
|
71
|
+
export declare function renderFilterContent(filterType: ColumnFilterType, state: UseColumnHeaderFilterStateResult, options: string[], isLoadingOptions: boolean, selectedUser: UserLike | undefined, renderers: FilterContentRenderers): React.ReactNode;
|
|
@@ -11,5 +11,15 @@ export interface MarchingAntsOverlayProps {
|
|
|
11
11
|
cutRange: ISelectionRange | null;
|
|
12
12
|
/** Column offset — 1 when checkbox column is present, else 0 */
|
|
13
13
|
colOffset: number;
|
|
14
|
+
/** Items array — triggers re-measurement when data changes (e.g., sorting) */
|
|
15
|
+
items: readonly unknown[];
|
|
16
|
+
/** Visible columns — triggers re-measurement when columns are hidden/shown */
|
|
17
|
+
visibleColumns: Set<string> | undefined;
|
|
18
|
+
/** Column sizing overrides — triggers re-measurement when columns are resized */
|
|
19
|
+
columnSizingOverrides: Record<string, {
|
|
20
|
+
widthPx: number;
|
|
21
|
+
}>;
|
|
22
|
+
/** Column order — triggers re-measurement when columns are reordered */
|
|
23
|
+
columnOrder: readonly string[] | undefined;
|
|
14
24
|
}
|
|
15
|
-
export declare function MarchingAntsOverlay({ containerRef, selectionRange, copyRange, cutRange, colOffset, }: MarchingAntsOverlayProps): React.ReactElement | null;
|
|
25
|
+
export declare function MarchingAntsOverlay({ containerRef, selectionRange, copyRange, cutRange, colOffset, items, visibleColumns, columnSizingOverrides, columnOrder, }: MarchingAntsOverlayProps): React.ReactElement | null;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared props interface for PaginationControls across all React UI packages.
|
|
3
|
+
* Each UI package renders its own framework-specific buttons, selects, and layout
|
|
4
|
+
* but shares this common prop shape.
|
|
5
|
+
*/
|
|
6
|
+
export interface IPaginationControlsProps {
|
|
7
|
+
currentPage: number;
|
|
8
|
+
pageSize: number;
|
|
9
|
+
totalCount: number;
|
|
10
|
+
onPageChange: (page: number) => void;
|
|
11
|
+
onPageSizeChange: (pageSize: number) => void;
|
|
12
|
+
pageSizeOptions?: number[];
|
|
13
|
+
entityLabelPlural?: string;
|
|
14
|
+
className?: string;
|
|
15
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type * as React from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Module-scope stable constants shared across all React UI DataGridTable implementations.
|
|
4
|
+
* Avoid per-render allocations by keeping these at module scope.
|
|
5
|
+
*/
|
|
6
|
+
/** Root container style for the DataGridTable (flex column layout). */
|
|
7
|
+
export declare const GRID_ROOT_STYLE: React.CSSProperties;
|
|
8
|
+
/** Applied to cells that support editing — shows the cell cursor. */
|
|
9
|
+
export declare const CURSOR_CELL_STYLE: React.CSSProperties;
|
|
10
|
+
/** Minimum size for popover anchor elements. */
|
|
11
|
+
export declare const POPOVER_ANCHOR_STYLE: React.CSSProperties;
|
|
12
|
+
/** Prevents the default browser action for mouse events. */
|
|
13
|
+
export declare const PREVENT_DEFAULT: (e: React.MouseEvent) => void;
|
|
14
|
+
/** No-operation function. */
|
|
15
|
+
export declare const NOOP: () => void;
|
|
16
|
+
/** Stops event propagation (e.g. click on checkbox inside a row). */
|
|
17
|
+
export declare const STOP_PROPAGATION: (e: React.MouseEvent) => void;
|
|
@@ -22,7 +22,7 @@ export { useDebounce } from './useDebounce';
|
|
|
22
22
|
export { useFillHandle } from './useFillHandle';
|
|
23
23
|
export type { UseFillHandleResult, UseFillHandleParams } from './useFillHandle';
|
|
24
24
|
export { useDataGridState } from './useDataGridState';
|
|
25
|
-
export type { UseDataGridStateParams, UseDataGridStateResult, DataGridLayoutState, DataGridRowSelectionState, DataGridEditingState, DataGridCellInteractionState, DataGridContextMenuState, DataGridViewModelState, } from './useDataGridState';
|
|
25
|
+
export type { UseDataGridStateParams, UseDataGridStateResult, DataGridLayoutState, DataGridRowSelectionState, DataGridEditingState, DataGridCellInteractionState, DataGridContextMenuState, DataGridViewModelState, DataGridPinningState, } from './useDataGridState';
|
|
26
26
|
export { useColumnHeaderFilterState } from './useColumnHeaderFilterState';
|
|
27
27
|
export type { UseColumnHeaderFilterStateParams, UseColumnHeaderFilterStateResult, } from './useColumnHeaderFilterState';
|
|
28
28
|
export { useTextFilterState } from './useTextFilterState';
|
|
@@ -54,3 +54,7 @@ export type { UseColumnReorderParams, UseColumnReorderResult, } from './useColum
|
|
|
54
54
|
export { useVirtualScroll } from './useVirtualScroll';
|
|
55
55
|
export type { IVirtualScrollConfig, UseVirtualScrollParams, UseVirtualScrollResult, } from './useVirtualScroll';
|
|
56
56
|
export { useLatestRef } from './useLatestRef';
|
|
57
|
+
export { usePaginationControls } from './usePaginationControls';
|
|
58
|
+
export type { UsePaginationControlsProps, UsePaginationControlsResult, } from './usePaginationControls';
|
|
59
|
+
export { useDataGridTableOrchestration } from './useDataGridTableOrchestration';
|
|
60
|
+
export type { UseDataGridTableOrchestrationParams, UseDataGridTableOrchestrationResult, } from './useDataGridTableOrchestration';
|
|
@@ -2,6 +2,20 @@ export interface UseColumnHeaderMenuStateParams {
|
|
|
2
2
|
pinnedColumns: Record<string, 'left' | 'right'>;
|
|
3
3
|
onPinColumn: (columnId: string, side: 'left' | 'right') => void;
|
|
4
4
|
onUnpinColumn: (columnId: string) => void;
|
|
5
|
+
sortBy?: string;
|
|
6
|
+
sortDirection: 'asc' | 'desc';
|
|
7
|
+
onColumnSort: (columnKey: string, direction?: 'asc' | 'desc' | null) => void;
|
|
8
|
+
onColumnResized?: (columnId: string, width: number) => void;
|
|
9
|
+
onAutosizeColumn?: (columnId: string, width: number) => void;
|
|
10
|
+
columns: Array<{
|
|
11
|
+
columnId: string;
|
|
12
|
+
width?: number;
|
|
13
|
+
minWidth?: number;
|
|
14
|
+
sortable?: boolean;
|
|
15
|
+
resizable?: boolean;
|
|
16
|
+
}>;
|
|
17
|
+
data: unknown[];
|
|
18
|
+
getRowId: (item: unknown) => string | number;
|
|
5
19
|
}
|
|
6
20
|
export interface UseColumnHeaderMenuStateResult {
|
|
7
21
|
isOpen: boolean;
|
|
@@ -12,12 +26,20 @@ export interface UseColumnHeaderMenuStateResult {
|
|
|
12
26
|
handlePinLeft: () => void;
|
|
13
27
|
handlePinRight: () => void;
|
|
14
28
|
handleUnpin: () => void;
|
|
29
|
+
handleSortAsc: () => void;
|
|
30
|
+
handleSortDesc: () => void;
|
|
31
|
+
handleClearSort: () => void;
|
|
32
|
+
handleAutosizeThis: () => void;
|
|
33
|
+
handleAutosizeAll: () => void;
|
|
15
34
|
canPinLeft: boolean;
|
|
16
35
|
canPinRight: boolean;
|
|
17
36
|
canUnpin: boolean;
|
|
37
|
+
currentSort: 'asc' | 'desc' | null;
|
|
38
|
+
isSortable: boolean;
|
|
39
|
+
isResizable: boolean;
|
|
18
40
|
}
|
|
19
41
|
/**
|
|
20
|
-
* Manages state for the column header menu (pin
|
|
42
|
+
* Manages state for the column header menu (pin, sort, autosize actions).
|
|
21
43
|
* Tracks which column's menu is open, anchor element, and action handlers.
|
|
22
44
|
*/
|
|
23
45
|
export declare function useColumnHeaderMenuState(params: UseColumnHeaderMenuStateParams): UseColumnHeaderMenuStateResult;
|
|
@@ -128,12 +128,8 @@ export interface DataGridPinningState {
|
|
|
128
128
|
pinColumn: (columnId: string, side: 'left' | 'right') => void;
|
|
129
129
|
unpinColumn: (columnId: string) => void;
|
|
130
130
|
isPinned: (columnId: string) => 'left' | 'right' | undefined;
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}[], columnWidths: Record<string, number>, defaultWidth: number, hasCheckboxColumn: boolean, checkboxColumnWidth: number) => Record<string, number>;
|
|
134
|
-
computeRightOffsets: (visibleCols: {
|
|
135
|
-
columnId: string;
|
|
136
|
-
}[], columnWidths: Record<string, number>, defaultWidth: number) => Record<string, number>;
|
|
131
|
+
leftOffsets: Record<string, number>;
|
|
132
|
+
rightOffsets: Record<string, number>;
|
|
137
133
|
headerMenu: {
|
|
138
134
|
isOpen: boolean;
|
|
139
135
|
openForColumn: string | null;
|
|
@@ -143,9 +139,17 @@ export interface DataGridPinningState {
|
|
|
143
139
|
handlePinLeft: () => void;
|
|
144
140
|
handlePinRight: () => void;
|
|
145
141
|
handleUnpin: () => void;
|
|
142
|
+
handleSortAsc: () => void;
|
|
143
|
+
handleSortDesc: () => void;
|
|
144
|
+
handleClearSort: () => void;
|
|
145
|
+
handleAutosizeThis: () => void;
|
|
146
|
+
handleAutosizeAll: () => void;
|
|
146
147
|
canPinLeft: boolean;
|
|
147
148
|
canPinRight: boolean;
|
|
148
149
|
canUnpin: boolean;
|
|
150
|
+
currentSort: 'asc' | 'desc' | null;
|
|
151
|
+
isSortable: boolean;
|
|
152
|
+
isResizable: boolean;
|
|
149
153
|
};
|
|
150
154
|
}
|
|
151
155
|
/** Grouped result from useDataGridState. */
|