@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.
Files changed (33) hide show
  1. package/dist/esm/components/BaseInlineCellEditor.js +2 -2
  2. package/dist/esm/components/CellErrorBoundary.js +1 -1
  3. package/dist/esm/components/ColumnChooserProps.js +6 -0
  4. package/dist/esm/components/ColumnHeaderFilterContent.js +35 -0
  5. package/dist/esm/components/ColumnHeaderFilterRenderers.js +67 -0
  6. package/dist/esm/components/MarchingAntsOverlay.js +25 -44
  7. package/dist/esm/components/PaginationControlsProps.js +6 -0
  8. package/dist/esm/constants/domHelpers.js +16 -0
  9. package/dist/esm/hooks/index.js +2 -0
  10. package/dist/esm/hooks/useColumnHeaderMenuState.js +52 -2
  11. package/dist/esm/hooks/useColumnResize.js +29 -0
  12. package/dist/esm/hooks/useDataGridState.js +77 -10
  13. package/dist/esm/hooks/useDataGridTableOrchestration.js +200 -0
  14. package/dist/esm/hooks/useDebounce.js +1 -1
  15. package/dist/esm/hooks/useOGrid.js +3 -6
  16. package/dist/esm/hooks/usePaginationControls.js +19 -0
  17. package/dist/esm/index.js +6 -1
  18. package/dist/esm/utils/index.js +1 -1
  19. package/dist/types/components/ColumnChooserProps.d.ts +12 -0
  20. package/dist/types/components/ColumnHeaderFilterContent.d.ts +62 -0
  21. package/dist/types/components/ColumnHeaderFilterRenderers.d.ts +71 -0
  22. package/dist/types/components/MarchingAntsOverlay.d.ts +11 -1
  23. package/dist/types/components/PaginationControlsProps.d.ts +15 -0
  24. package/dist/types/constants/domHelpers.d.ts +17 -0
  25. package/dist/types/hooks/index.d.ts +5 -1
  26. package/dist/types/hooks/useColumnHeaderMenuState.d.ts +23 -1
  27. package/dist/types/hooks/useDataGridState.d.ts +10 -6
  28. package/dist/types/hooks/useDataGridTableOrchestration.d.ts +131 -0
  29. package/dist/types/hooks/usePaginationControls.d.ts +20 -0
  30. package/dist/types/index.d.ts +9 -2
  31. package/dist/types/types/dataGridTypes.d.ts +1 -1
  32. package/dist/types/utils/index.d.ts +1 -1
  33. 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';
@@ -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 left/right/unpin actions).
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
- computeLeftOffsets: (visibleCols: {
132
- columnId: string;
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. */