@alaarab/ogrid-core 1.3.1 → 1.4.0

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 (46) hide show
  1. package/dist/esm/components/OGridLayout.js +73 -7
  2. package/dist/esm/components/SideBar.js +98 -0
  3. package/dist/esm/hooks/index.js +2 -0
  4. package/dist/esm/hooks/useCellSelection.js +207 -16
  5. package/dist/esm/hooks/useColumnHeaderFilterState.js +25 -3
  6. package/dist/esm/hooks/useColumnResize.js +9 -2
  7. package/dist/esm/hooks/useDataGridState.js +44 -6
  8. package/dist/esm/hooks/useFillHandle.js +91 -10
  9. package/dist/esm/hooks/useKeyboardNavigation.js +56 -4
  10. package/dist/esm/hooks/useOGrid.js +132 -4
  11. package/dist/esm/hooks/useRichSelectState.js +53 -0
  12. package/dist/esm/hooks/useSideBarState.js +34 -0
  13. package/dist/esm/index.js +3 -2
  14. package/dist/esm/types/dataGridTypes.js +9 -2
  15. package/dist/esm/utils/aggregationUtils.js +39 -0
  16. package/dist/esm/utils/columnUtils.js +97 -0
  17. package/dist/esm/utils/dataGridViewModel.js +105 -6
  18. package/dist/esm/utils/index.js +3 -2
  19. package/dist/esm/utils/ogridHelpers.js +4 -2
  20. package/dist/esm/utils/paginationHelpers.js +1 -1
  21. package/dist/esm/utils/statusBarHelpers.js +8 -1
  22. package/dist/esm/utils/valueParsers.js +15 -1
  23. package/dist/types/components/OGridLayout.d.ts +22 -5
  24. package/dist/types/components/SideBar.d.ts +34 -0
  25. package/dist/types/components/StatusBar.d.ts +8 -0
  26. package/dist/types/hooks/index.d.ts +5 -1
  27. package/dist/types/hooks/useCellSelection.d.ts +1 -0
  28. package/dist/types/hooks/useColumnHeaderFilterState.d.ts +9 -1
  29. package/dist/types/hooks/useColumnResize.d.ts +3 -1
  30. package/dist/types/hooks/useDataGridState.d.ts +3 -0
  31. package/dist/types/hooks/useInlineCellEditorState.d.ts +1 -1
  32. package/dist/types/hooks/useOGrid.d.ts +7 -0
  33. package/dist/types/hooks/useRichSelectState.d.ts +17 -0
  34. package/dist/types/hooks/useSideBarState.d.ts +15 -0
  35. package/dist/types/index.d.ts +7 -5
  36. package/dist/types/types/columnTypes.d.ts +26 -2
  37. package/dist/types/types/dataGridTypes.d.ts +56 -6
  38. package/dist/types/types/index.d.ts +2 -2
  39. package/dist/types/utils/aggregationUtils.d.ts +15 -0
  40. package/dist/types/utils/columnUtils.d.ts +16 -1
  41. package/dist/types/utils/dataGridViewModel.d.ts +67 -2
  42. package/dist/types/utils/index.d.ts +5 -3
  43. package/dist/types/utils/ogridHelpers.d.ts +2 -2
  44. package/dist/types/utils/paginationHelpers.d.ts +1 -1
  45. package/dist/types/utils/statusBarHelpers.d.ts +8 -0
  46. package/package.json +1 -1
@@ -0,0 +1,15 @@
1
+ import type { SideBarPanelId, ISideBarDef } from '../types';
2
+ export interface UseSideBarStateParams {
3
+ config: boolean | ISideBarDef | undefined;
4
+ }
5
+ export interface UseSideBarStateResult {
6
+ isEnabled: boolean;
7
+ activePanel: SideBarPanelId | null;
8
+ setActivePanel: (panel: SideBarPanelId | null) => void;
9
+ panels: SideBarPanelId[];
10
+ position: 'left' | 'right';
11
+ isOpen: boolean;
12
+ toggle: (panel: SideBarPanelId) => void;
13
+ close: () => void;
14
+ }
15
+ export declare function useSideBarState(params: UseSideBarStateParams): UseSideBarStateResult;
@@ -1,7 +1,7 @@
1
- export type { ColumnFilterType, IColumnFilterDef, IColumnMeta, IColumnDef, IColumnGroupDef, IColumnDefinition, ICellValueChangedEvent, ICellEditorProps, CellEditorParams, IValueParserParams, UserLike, UserLikeInput, FilterValue, IFilters, IFetchParams, IPageResult, IDataSource, IGridColumnState, IOGridApi, IOGridProps, IOGridDataGridProps, RowSelectionMode, IRowSelectionChangeEvent, StatusBarPanel, IStatusBarProps, IActiveCell, ISelectionRange, } from './types';
1
+ export type { ColumnFilterType, IColumnFilterDef, IColumnMeta, IColumnDef, IColumnGroupDef, IColumnDefinition, ICellValueChangedEvent, ICellEditorProps, CellEditorParams, IValueParserParams, UserLike, UserLikeInput, FilterValue, IFilters, IFetchParams, IPageResult, IDataSource, IGridColumnState, IOGridApi, IOGridProps, IOGridDataGridProps, RowSelectionMode, IRowSelectionChangeEvent, StatusBarPanel, IStatusBarProps, IActiveCell, ISelectionRange, HeaderCell, HeaderRow, SideBarPanelId, ISideBarDef, IDateFilterValue, } from './types';
2
2
  export { toUserLike, toDataGridFilterProps, isInSelectionRange, normalizeSelectionRange } from './types';
3
- export { useFilterOptions, useOGrid, useActiveCell, useCellEditing, useContextMenu, useCellSelection, useClipboard, useRowSelection, useKeyboardNavigation, useUndoRedo, useDebounce, useFillHandle, useDataGridState, useColumnHeaderFilterState, useColumnChooserState, useInlineCellEditorState, useColumnResize, } from './hooks';
4
- export type { UseFilterOptionsResult, UseOGridResult, UseActiveCellResult, UseCellEditingResult, EditingCell, UseContextMenuResult, ContextMenuPosition, UseCellSelectionResult, UseCellSelectionParams, UseClipboardResult, UseClipboardParams, UseRowSelectionResult, UseRowSelectionParams, UseKeyboardNavigationResult, UseKeyboardNavigationParams, UseUndoRedoResult, UseUndoRedoParams, UseFillHandleResult, UseFillHandleParams, UseDataGridStateParams, UseDataGridStateResult, UseColumnHeaderFilterStateParams, UseColumnHeaderFilterStateResult, UseColumnChooserStateParams, UseColumnChooserStateResult, UseInlineCellEditorStateParams, UseInlineCellEditorStateResult, InlineCellEditorType, UseColumnResizeParams, UseColumnResizeResult, } from './hooks';
3
+ export { useFilterOptions, useOGrid, useActiveCell, useCellEditing, useContextMenu, useCellSelection, useClipboard, useRowSelection, useKeyboardNavigation, useUndoRedo, useDebounce, useFillHandle, useDataGridState, useColumnHeaderFilterState, useColumnChooserState, useInlineCellEditorState, useColumnResize, useRichSelectState, useSideBarState, } from './hooks';
4
+ export type { UseFilterOptionsResult, UseOGridResult, ColumnChooserPlacement, UseActiveCellResult, UseCellEditingResult, EditingCell, UseContextMenuResult, ContextMenuPosition, UseCellSelectionResult, UseCellSelectionParams, UseClipboardResult, UseClipboardParams, UseRowSelectionResult, UseRowSelectionParams, UseKeyboardNavigationResult, UseKeyboardNavigationParams, UseUndoRedoResult, UseUndoRedoParams, UseFillHandleResult, UseFillHandleParams, UseDataGridStateParams, UseDataGridStateResult, UseColumnHeaderFilterStateParams, UseColumnHeaderFilterStateResult, UseColumnChooserStateParams, UseColumnChooserStateResult, UseInlineCellEditorStateParams, UseInlineCellEditorStateResult, InlineCellEditorType, UseColumnResizeParams, UseColumnResizeResult, UseRichSelectStateParams, UseRichSelectStateResult, UseSideBarStateParams, UseSideBarStateResult, } from './hooks';
5
5
  export { OGridLayout } from './components/OGridLayout';
6
6
  export type { OGridLayoutProps } from './components/OGridLayout';
7
7
  export { StatusBar } from './components/StatusBar';
@@ -10,5 +10,7 @@ export { GridContextMenu } from './components/GridContextMenu';
10
10
  export type { GridContextMenuProps, GridContextMenuClassNames } from './components/GridContextMenu';
11
11
  export { MarchingAntsOverlay } from './components/MarchingAntsOverlay';
12
12
  export type { MarchingAntsOverlayProps } from './components/MarchingAntsOverlay';
13
- export { escapeCsvValue, buildCsvHeader, buildCsvRows, exportToCsv, triggerCsvDownload, getCellValue, flattenColumns, getFilterField, mergeFilter, deriveFilterOptionsFromData, getMultiSelectFilterFields, getStatusBarParts, getDataGridStatusBarConfig, GRID_CONTEXT_MENU_ITEMS, getContextMenuHandlers, formatShortcut, getPaginationViewModel, PAGE_SIZE_OPTIONS, MAX_PAGE_BUTTONS, getHeaderFilterConfig, getCellRenderDescriptor, parseValue, numberParser, currencyParser, dateParser, emailParser, booleanParser, } from './utils';
14
- export type { CsvColumn, StatusBarPart, StatusBarPartsInput, GridContextMenuItem, GridContextMenuHandlerProps, PaginationViewModel, HeaderFilterConfigInput, HeaderFilterConfig, CellRenderDescriptorInput, CellRenderDescriptor, CellRenderMode, ParseValueResult, } from './utils';
13
+ export { SideBar } from './components/SideBar';
14
+ export type { SideBarProps, SideBarFilterColumn } from './components/SideBar';
15
+ 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, resolveCellDisplayContent, resolveCellStyle, buildInlineEditorProps, buildPopoverEditorProps, getCellInteractionProps, parseValue, numberParser, currencyParser, dateParser, emailParser, booleanParser, computeAggregations, } from './utils';
16
+ export type { CsvColumn, StatusBarPart, StatusBarPartsInput, GridContextMenuItem, GridContextMenuHandlerProps, PaginationViewModel, HeaderFilterConfigInput, HeaderFilterConfig, CellRenderDescriptorInput, CellRenderDescriptor, CellRenderMode, CellInteractionHandlers, ParseValueResult, AggregationResult, } from './utils';
@@ -1,5 +1,10 @@
1
1
  import * as React from 'react';
2
- export type ColumnFilterType = 'none' | 'text' | 'multiSelect' | 'people';
2
+ export type ColumnFilterType = 'none' | 'text' | 'multiSelect' | 'people' | 'date';
3
+ /** Date range filter value (ISO YYYY-MM-DD strings). Both fields optional for open-ended ranges. */
4
+ export interface IDateFilterValue {
5
+ from?: string;
6
+ to?: string;
7
+ }
3
8
  export interface IColumnFilterDef {
4
9
  type: Exclude<ColumnFilterType, 'none'>;
5
10
  filterField?: string;
@@ -10,6 +15,8 @@ export interface IColumnFilterDef {
10
15
  export interface IColumnMeta {
11
16
  columnId: string;
12
17
  name: string;
18
+ /** Column type shorthand. Affects alignment, default editor, filter type, sorting, and display formatting. */
19
+ type?: 'text' | 'numeric' | 'date' | 'boolean';
13
20
  sortable?: boolean;
14
21
  /** Omit for not filterable; set to IColumnFilterDef for filterable. */
15
22
  filterable?: IColumnFilterDef;
@@ -50,7 +57,7 @@ export interface IColumnDef<T = unknown> extends IColumnMeta {
50
57
  /** Whether the cell is editable (per-column or per-row). */
51
58
  editable?: boolean | ((item: T) => boolean);
52
59
  /** Built-in editor type or custom React component. */
53
- cellEditor?: 'text' | 'select' | 'checkbox' | React.ComponentType<ICellEditorProps<T>>;
60
+ cellEditor?: 'text' | 'select' | 'checkbox' | 'richSelect' | 'date' | React.ComponentType<ICellEditorProps<T>>;
54
61
  /** When true, custom cell editor is rendered in a popover/popper instead of inline. */
55
62
  cellEditorPopup?: boolean;
56
63
  /** Params passed to the cell editor (e.g. { values: string[] } for select). */
@@ -78,6 +85,8 @@ export interface ICellEditorProps<T> {
78
85
  /** Params for built-in cell editors (e.g. select: { values: string[] }). Extend for custom editors. */
79
86
  export interface CellEditorParams {
80
87
  values?: unknown[];
88
+ /** Format a value for display in rich select editor. */
89
+ formatValue?: (value: unknown) => string;
81
90
  [key: string]: unknown;
82
91
  }
83
92
  /** Column group for multi-row header (has children, no columnId for data). */
@@ -87,6 +96,21 @@ export interface IColumnGroupDef<T = unknown> {
87
96
  /** Nested groups or leaf columns. */
88
97
  children: (IColumnGroupDef<T> | IColumnDef<T>)[];
89
98
  }
99
+ /** A single cell in a header row (either a group header or a leaf column header). */
100
+ export interface HeaderCell<T = unknown> {
101
+ /** Display text for this header cell. */
102
+ label: string;
103
+ /** Number of leaf columns this cell spans. */
104
+ colSpan: number;
105
+ /** True if this is a group header (not a leaf column). */
106
+ isGroup: boolean;
107
+ /** The leaf column definition (only set when isGroup is false). */
108
+ columnDef?: IColumnDef<T>;
109
+ /** The depth level of this cell in the group tree (0 = top). */
110
+ depth: number;
111
+ }
112
+ /** A single row in the multi-row header. */
113
+ export type HeaderRow<T = unknown> = HeaderCell<T>[];
90
114
  /** Minimal column info for the ColumnChooser (framework-agnostic). */
91
115
  export interface IColumnDefinition {
92
116
  columnId: string;
@@ -1,5 +1,5 @@
1
1
  import type { ReactNode } from 'react';
2
- import type { IColumnDef, IColumnGroupDef, ICellValueChangedEvent } from './columnTypes';
2
+ import type { IColumnDef, IColumnGroupDef, ICellValueChangedEvent, IDateFilterValue } from './columnTypes';
3
3
  /** Row identifier type — grids accept string or number IDs. */
4
4
  export type RowId = string | number;
5
5
  export interface UserLike {
@@ -18,17 +18,18 @@ export type UserLikeInput = {
18
18
  photo?: string;
19
19
  };
20
20
  export declare function toUserLike(u: UserLikeInput | undefined): UserLike | undefined;
21
- /** Single filter value: text (string), multi-select (string[]), or people (UserLike). */
22
- export type FilterValue = string | string[] | UserLike;
21
+ /** Single filter value: text (string), multi-select (string[]), people (UserLike), or date range. */
22
+ export type FilterValue = string | string[] | UserLike | IDateFilterValue;
23
23
  /** Unified filter model: field id -> filter value. Use FilterValue for type-safe access. */
24
24
  export interface IFilters {
25
25
  [field: string]: FilterValue | undefined;
26
26
  }
27
- /** Split IFilters into DataGridTable's multiSelect, text, and people props. */
27
+ /** Split IFilters into DataGridTable's multiSelect, text, people, and date props. */
28
28
  export declare function toDataGridFilterProps(filters: IFilters): {
29
29
  multiSelectFilters: Record<string, string[]>;
30
30
  textFilters: Record<string, string>;
31
31
  peopleFilters: Record<string, UserLike | undefined>;
32
+ dateFilters: Record<string, IDateFilterValue>;
32
33
  };
33
34
  export interface IFetchParams {
34
35
  page: number;
@@ -50,13 +51,19 @@ export interface IDataSource<T> {
50
51
  searchPeople?(query: string): Promise<UserLike[]>;
51
52
  getUserByEmail?(email: string): Promise<UserLike | undefined>;
52
53
  }
53
- /** Column state returned by getColumnState(). Uses string[] for JSON-serializability (e.g. column state persistence). */
54
+ /** Column state returned by getColumnState(). All fields JSON-serializable for persistence (e.g. localStorage). */
54
55
  export interface IGridColumnState {
55
56
  visibleColumns: string[];
56
57
  sort?: {
57
58
  field: string;
58
59
  direction: 'asc' | 'desc';
59
60
  };
61
+ /** Column display order (array of column ids). */
62
+ columnOrder?: string[];
63
+ /** Column widths (column id -> width in pixels). */
64
+ columnWidths?: Record<string, number>;
65
+ /** Active filters. */
66
+ filters?: IFilters;
60
67
  }
61
68
  /** Row selection mode. */
62
69
  export type RowSelectionMode = 'none' | 'single' | 'multiple';
@@ -77,6 +84,14 @@ export interface IStatusBarProps {
77
84
  selectedCount?: number;
78
85
  /** Panels to show (default: all applicable). */
79
86
  panels?: StatusBarPanel[];
87
+ /** Aggregation values for selected numeric cells. */
88
+ aggregation?: {
89
+ sum: number;
90
+ avg: number;
91
+ min: number;
92
+ max: number;
93
+ count: number;
94
+ } | null;
80
95
  }
81
96
  /** Identifies a cell for keyboard navigation. */
82
97
  export interface IActiveCell {
@@ -94,14 +109,27 @@ export interface ISelectionRange {
94
109
  export declare function isInSelectionRange(range: ISelectionRange, row: number, col: number): boolean;
95
110
  /** Normalize range so start ≤ end for both dimensions. */
96
111
  export declare function normalizeSelectionRange(range: ISelectionRange): ISelectionRange;
112
+ /** Available side bar panel identifiers. */
113
+ export type SideBarPanelId = 'columns' | 'filters';
114
+ /** Side bar configuration options. */
115
+ export interface ISideBarDef {
116
+ /** Which panels to show (default: ['columns', 'filters']). */
117
+ panels?: SideBarPanelId[];
118
+ /** Panel to open on mount. */
119
+ defaultPanel?: SideBarPanelId;
120
+ /** Position of the side bar (default: 'right'). */
121
+ position?: 'left' | 'right';
122
+ }
97
123
  /** Imperative grid API exposed via ref. */
98
124
  export interface IOGridApi<T> {
99
125
  /** Set row data (client-side only; no-op when using dataSource). */
100
126
  setRowData: (data: T[]) => void;
101
127
  /** Set loading overlay. */
102
128
  setLoading: (loading: boolean) => void;
103
- /** Get current column state (visible columns, sort). */
129
+ /** Get current column state (visibility, order, widths, sort, filters). */
104
130
  getColumnState: () => IGridColumnState;
131
+ /** Bulk restore column state (visibility, order, widths, sort, filters). All fields optional. */
132
+ applyColumnState: (state: Partial<IGridColumnState>) => void;
105
133
  /** Set filter model (unified IFilters). */
106
134
  setFilterModel: (filters: IFilters) => void;
107
135
  /** Get currently selected row IDs. */
@@ -138,6 +166,8 @@ export interface IOGridProps<T> {
138
166
  onVisibleColumnsChange?: (cols: Set<string>) => void;
139
167
  columnOrder?: string[];
140
168
  onColumnOrderChange?: (order: string[]) => void;
169
+ /** Called when a column is resized by the user. */
170
+ onColumnResized?: (columnId: string, width: number) => void;
141
171
  freezeRows?: number;
142
172
  freezeCols?: number;
143
173
  editable?: boolean;
@@ -162,8 +192,20 @@ export interface IOGridProps<T> {
162
192
  };
163
193
  entityLabelPlural?: string;
164
194
  className?: string;
195
+ /** @deprecated Render your title outside the OGrid component. Will be removed in next major. */
165
196
  title?: ReactNode;
197
+ /** Where the column chooser renders.
198
+ * - `true` or `'toolbar'` (default): column chooser button in the toolbar strip.
199
+ * - `'sidebar'`: column chooser only available via the sidebar columns panel.
200
+ * - `false`: column chooser hidden entirely. */
201
+ columnChooser?: boolean | 'toolbar' | 'sidebar';
166
202
  layoutMode?: 'content' | 'fill';
203
+ /** When true, horizontal scrolling is suppressed (overflow-x hidden). */
204
+ suppressHorizontalScroll?: boolean;
205
+ /** Side bar configuration. `true` shows default panels (columns + filters). Pass ISideBarDef for options. */
206
+ sideBar?: boolean | ISideBarDef;
207
+ /** Page size options shown in the pagination dropdown. Default: [10, 20, 50, 100]. */
208
+ pageSizeOptions?: number[];
167
209
  /** Called when server-side fetchPage fails. */
168
210
  onError?: (error: unknown) => void;
169
211
  'aria-label'?: string;
@@ -181,11 +223,17 @@ export interface IOGridDataGridProps<T> {
181
223
  /** Optional column display order (column ids). When set, visible columns are ordered by this array. */
182
224
  columnOrder?: string[];
183
225
  onColumnOrderChange?: (order: string[]) => void;
226
+ /** Called when a column is resized by the user. */
227
+ onColumnResized?: (columnId: string, width: number) => void;
228
+ /** Initial column width overrides (from restored state). */
229
+ initialColumnWidths?: Record<string, number>;
184
230
  /** Number of rows to freeze (sticky), e.g. 1 = header row. */
185
231
  freezeRows?: number;
186
232
  /** Number of data columns to freeze (sticky left). */
187
233
  freezeCols?: number;
188
234
  layoutMode?: 'content' | 'fill';
235
+ /** When true, horizontal scrolling is suppressed (overflow-x hidden). */
236
+ suppressHorizontalScroll?: boolean;
189
237
  isLoading?: boolean;
190
238
  loadingMessage?: string;
191
239
  editable?: boolean;
@@ -206,6 +254,8 @@ export interface IOGridDataGridProps<T> {
206
254
  onTextFilterChange?: (key: string, value: string) => void;
207
255
  peopleFilters?: Record<string, UserLike | undefined>;
208
256
  onPeopleFilterChange?: (key: string, user: UserLike | undefined) => void;
257
+ dateFilters?: Record<string, IDateFilterValue>;
258
+ onDateFilterChange?: (key: string, value: IDateFilterValue | undefined) => void;
209
259
  filterOptions: Record<string, string[]>;
210
260
  loadingFilterOptions: Record<string, boolean>;
211
261
  peopleSearch?: (query: string) => Promise<UserLike[]>;
@@ -1,3 +1,3 @@
1
- export type { ColumnFilterType, IColumnFilterDef, IColumnMeta, IColumnDef, IColumnGroupDef, IColumnDefinition, ICellValueChangedEvent, ICellEditorProps, CellEditorParams, IValueParserParams, } from './columnTypes';
2
- export type { RowId, UserLike, UserLikeInput, FilterValue, IFilters, IFetchParams, IPageResult, IDataSource, IGridColumnState, IOGridApi, IOGridProps, IOGridDataGridProps, RowSelectionMode, IRowSelectionChangeEvent, StatusBarPanel, IStatusBarProps, IActiveCell, ISelectionRange, } from './dataGridTypes';
1
+ export type { ColumnFilterType, IColumnFilterDef, IColumnMeta, IColumnDef, IColumnGroupDef, IColumnDefinition, ICellValueChangedEvent, ICellEditorProps, CellEditorParams, IValueParserParams, IDateFilterValue, HeaderCell, HeaderRow, } from './columnTypes';
2
+ export type { RowId, UserLike, UserLikeInput, FilterValue, IFilters, IFetchParams, IPageResult, IDataSource, IGridColumnState, IOGridApi, IOGridProps, IOGridDataGridProps, RowSelectionMode, IRowSelectionChangeEvent, StatusBarPanel, IStatusBarProps, IActiveCell, ISelectionRange, SideBarPanelId, ISideBarDef, } from './dataGridTypes';
3
3
  export { toUserLike, toDataGridFilterProps, isInSelectionRange, normalizeSelectionRange } from './dataGridTypes';
@@ -0,0 +1,15 @@
1
+ import type { IColumnDef } from '../types/columnTypes';
2
+ import type { ISelectionRange } from '../types/dataGridTypes';
3
+ export interface AggregationResult {
4
+ sum: number;
5
+ avg: number;
6
+ min: number;
7
+ max: number;
8
+ count: number;
9
+ }
10
+ /**
11
+ * Computes numeric aggregations (sum, avg, min, max, count) for selected cells.
12
+ * Only numeric values are included in sum/avg/min/max. Count includes only numeric cells.
13
+ * Returns null when selection is absent, has fewer than 2 cells, or contains no numeric values.
14
+ */
15
+ export declare function computeAggregations<T>(items: T[], visibleCols: IColumnDef<T>[], selectionRange: ISelectionRange | null): AggregationResult | null;
@@ -1,6 +1,21 @@
1
- import type { IColumnDef, IColumnGroupDef } from '../types/columnTypes';
1
+ import type { IColumnDef, IColumnGroupDef, HeaderRow } from '../types/columnTypes';
2
2
  /**
3
3
  * Flattens a tree of column groups and column definitions into a single array of leaf columns.
4
4
  * Used for body rendering and when the grid accepts grouped columns.
5
5
  */
6
6
  export declare function flattenColumns<T>(columns: (IColumnGroupDef<T> | IColumnDef<T>)[]): IColumnDef<T>[];
7
+ /**
8
+ * Builds an array of header rows from a column tree for multi-row <thead> rendering.
9
+ *
10
+ * - Flat columns (no groups) produce a single row of leaf cells.
11
+ * - Grouped columns produce N rows where N = max nesting depth + 1.
12
+ * - Group cells get colSpan = number of visible leaf descendants.
13
+ * - Leaf cells at a depth shallower than maxDepth are placed at their own depth
14
+ * (the rendering layer can use rowSpan to stretch them down to the bottom row).
15
+ * - If visibleColumns is provided, only visible leaf columns and their ancestors are included.
16
+ *
17
+ * @param columns - The column tree (mix of IColumnDef and IColumnGroupDef)
18
+ * @param visibleColumns - Optional set of visible column ids (filters out hidden leaves + empty groups)
19
+ * @returns Array of HeaderRow, from top (group headers) to bottom (leaf columns)
20
+ */
21
+ export declare function buildHeaderRows<T>(columns: (IColumnGroupDef<T> | IColumnDef<T>)[], visibleColumns?: Set<string>): HeaderRow<T>[];
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * View model helpers for DataGridTable. Core owns the logic; UI packages only render.
3
3
  */
4
- import type { ColumnFilterType } from '../types/columnTypes';
4
+ import type * as React from 'react';
5
+ import type { ColumnFilterType, ICellEditorProps, IDateFilterValue } from '../types/columnTypes';
5
6
  import type { IColumnDef } from '../types/columnTypes';
6
7
  import type { RowId, UserLike } from '../types/dataGridTypes';
7
8
  export interface HeaderFilterConfigInput {
@@ -17,6 +18,8 @@ export interface HeaderFilterConfigInput {
17
18
  loadingFilterOptions: Record<string, boolean>;
18
19
  multiSelectFilters: Record<string, string[]>;
19
20
  onMultiSelectFilterChange: (key: string, values: string[]) => void;
21
+ dateFilters?: Record<string, IDateFilterValue>;
22
+ onDateFilterChange?: (key: string, value: IDateFilterValue | undefined) => void;
20
23
  }
21
24
  /** Props to pass to ColumnHeaderFilter. Matches IColumnHeaderFilterProps. */
22
25
  export interface HeaderFilterConfig {
@@ -35,6 +38,8 @@ export interface HeaderFilterConfig {
35
38
  selectedUser?: UserLike;
36
39
  onUserChange?: (user: UserLike | undefined) => void;
37
40
  peopleSearch?: (query: string) => Promise<UserLike[]>;
41
+ dateValue?: IDateFilterValue;
42
+ onDateChange?: (value: IDateFilterValue | undefined) => void;
38
43
  }
39
44
  /**
40
45
  * Returns ColumnHeaderFilter props from column def and grid filter/sort state.
@@ -79,7 +84,7 @@ export interface CellRenderDescriptorInput<T> {
79
84
  }
80
85
  export interface CellRenderDescriptor {
81
86
  mode: CellRenderMode;
82
- editorType?: 'text' | 'select' | 'checkbox';
87
+ editorType?: 'text' | 'select' | 'checkbox' | 'richSelect' | 'date';
83
88
  value?: unknown;
84
89
  isActive: boolean;
85
90
  isInRange: boolean;
@@ -100,3 +105,63 @@ export interface CellRenderDescriptor {
100
105
  * and to apply isActive, isInRange, etc. without duplicating the boolean logic.
101
106
  */
102
107
  export declare function getCellRenderDescriptor<T>(item: T, col: IColumnDef<T>, rowIndex: number, colIdx: number, input: CellRenderDescriptorInput<T>): CellRenderDescriptor;
108
+ /**
109
+ * Resolves display content for a cell in display mode.
110
+ * Handles the renderCell → valueFormatter → String() fallback chain.
111
+ */
112
+ export declare function resolveCellDisplayContent<T>(col: IColumnDef<T>, item: T, displayValue: unknown): React.ReactNode;
113
+ /**
114
+ * Resolves the cellStyle from a column def, handling both function and static values.
115
+ */
116
+ export declare function resolveCellStyle<T>(col: IColumnDef<T>, item: T): React.CSSProperties | undefined;
117
+ /**
118
+ * Builds props for InlineCellEditor. Shared across all UI packages.
119
+ */
120
+ export declare function buildInlineEditorProps<T>(item: T, col: IColumnDef<T>, descriptor: CellRenderDescriptor, callbacks: {
121
+ commitCellEdit: (item: T, columnId: string, oldValue: unknown, newValue: unknown, rowIndex: number, globalColIndex: number) => void;
122
+ setEditingCell: (cell: null) => void;
123
+ }): {
124
+ value: unknown;
125
+ item: T;
126
+ column: IColumnDef<T>;
127
+ rowIndex: number;
128
+ editorType: "text" | "select" | "checkbox" | "richSelect" | "date";
129
+ onCommit: (newValue: unknown) => void;
130
+ onCancel: () => void;
131
+ };
132
+ /**
133
+ * Builds ICellEditorProps for custom popover editors. Shared across all UI packages.
134
+ */
135
+ export declare function buildPopoverEditorProps<T>(item: T, col: IColumnDef<T>, descriptor: CellRenderDescriptor, pendingEditorValue: unknown, callbacks: {
136
+ setPendingEditorValue: (value: unknown) => void;
137
+ commitCellEdit: (item: T, columnId: string, oldValue: unknown, newValue: unknown, rowIndex: number, globalColIndex: number) => void;
138
+ cancelPopoverEdit: () => void;
139
+ }): ICellEditorProps<T>;
140
+ /**
141
+ * Common interaction props for cell wrapper elements.
142
+ * Includes data attributes, event handlers, and accessibility props.
143
+ * Spread onto the cell wrapper div/Box in each UI package.
144
+ */
145
+ export interface CellInteractionHandlers {
146
+ handleCellMouseDown: (e: React.MouseEvent, rowIndex: number, colIndex: number) => void;
147
+ setActiveCell: (cell: {
148
+ rowIndex: number;
149
+ columnIndex: number;
150
+ }) => void;
151
+ setEditingCell: (cell: {
152
+ rowId: RowId;
153
+ columnId: string;
154
+ } | null) => void;
155
+ handleCellContextMenu: (e: React.MouseEvent) => void;
156
+ }
157
+ export declare function getCellInteractionProps(descriptor: CellRenderDescriptor, columnId: string, handlers: CellInteractionHandlers): {
158
+ role?: "button" | undefined;
159
+ onDoubleClick?: (() => void) | undefined;
160
+ tabIndex: number;
161
+ onMouseDown: (e: React.MouseEvent) => void;
162
+ onClick: () => void;
163
+ onContextMenu: (e: React.MouseEvent) => void;
164
+ 'data-in-range'?: "true" | undefined;
165
+ 'data-row-index': number;
166
+ 'data-col-index': number;
167
+ };
@@ -1,16 +1,18 @@
1
1
  export { escapeCsvValue, buildCsvHeader, buildCsvRows, exportToCsv, triggerCsvDownload, } from './exportToCsv';
2
2
  export { getCellValue } from './cellValue';
3
- export { flattenColumns } from './columnUtils';
3
+ export { flattenColumns, buildHeaderRows } from './columnUtils';
4
4
  export { getFilterField, mergeFilter, deriveFilterOptionsFromData, getMultiSelectFilterFields, } from './ogridHelpers';
5
5
  export { getStatusBarParts } from './statusBarHelpers';
6
6
  export { getDataGridStatusBarConfig } from './dataGridStatusBar';
7
7
  export { getPaginationViewModel, PAGE_SIZE_OPTIONS, MAX_PAGE_BUTTONS, } from './paginationHelpers';
8
8
  export type { PaginationViewModel } from './paginationHelpers';
9
9
  export { GRID_CONTEXT_MENU_ITEMS, getContextMenuHandlers, formatShortcut } from './gridContextMenuHelpers';
10
- export { getHeaderFilterConfig, getCellRenderDescriptor, } from './dataGridViewModel';
11
- export type { HeaderFilterConfigInput, HeaderFilterConfig, CellRenderDescriptorInput, CellRenderDescriptor, CellRenderMode, } from './dataGridViewModel';
10
+ export { getHeaderFilterConfig, getCellRenderDescriptor, resolveCellDisplayContent, resolveCellStyle, buildInlineEditorProps, buildPopoverEditorProps, getCellInteractionProps, } from './dataGridViewModel';
11
+ export type { HeaderFilterConfigInput, HeaderFilterConfig, CellRenderDescriptorInput, CellRenderDescriptor, CellRenderMode, CellInteractionHandlers, } from './dataGridViewModel';
12
12
  export type { CsvColumn } from './exportToCsv';
13
13
  export type { StatusBarPart, StatusBarPartsInput } from './statusBarHelpers';
14
14
  export type { GridContextMenuItem, GridContextMenuHandlerProps } from './gridContextMenuHelpers';
15
15
  export { parseValue, numberParser, currencyParser, dateParser, emailParser, booleanParser, } from './valueParsers';
16
16
  export type { ParseValueResult } from './valueParsers';
17
+ export { computeAggregations } from './aggregationUtils';
18
+ export type { AggregationResult } from './aggregationUtils';
@@ -1,8 +1,8 @@
1
- import type { IColumnDef, UserLike, IFilters } from '../types';
1
+ import type { IColumnDef, IFilters, FilterValue } from '../types';
2
2
  /** Resolve the filter field key for a column (filterField or columnId). */
3
3
  export declare function getFilterField<T>(col: IColumnDef<T>): string;
4
4
  /** Merge a single filter change into a full IFilters object. */
5
- export declare function mergeFilter(prev: IFilters, key: string, value: string | string[] | UserLike | undefined): IFilters;
5
+ export declare function mergeFilter(prev: IFilters, key: string, value: FilterValue | undefined): IFilters;
6
6
  /** Derive filter options for multiSelect columns from client-side data. */
7
7
  export declare function deriveFilterOptionsFromData<T>(items: T[], columns: IColumnDef<T>[]): Record<string, string[]>;
8
8
  /** Get list of filter fields that use multiSelect (for useFilterOptions). */
@@ -2,7 +2,7 @@
2
2
  * Shared pagination view model for Fluent, Material, and Radix PaginationControls.
3
3
  * UI packages use this and render only presentation.
4
4
  */
5
- export declare const PAGE_SIZE_OPTIONS: readonly [10, 20, 50, 100];
5
+ export declare const PAGE_SIZE_OPTIONS: readonly [10, 25, 50, 100];
6
6
  export declare const MAX_PAGE_BUTTONS = 5;
7
7
  export interface PaginationViewModel {
8
8
  totalPages: number;
@@ -11,6 +11,14 @@ export interface StatusBarPartsInput {
11
11
  filteredCount?: number;
12
12
  selectedCount?: number;
13
13
  selectedCellCount?: number;
14
+ /** Aggregation of selected numeric cells. */
15
+ aggregation?: {
16
+ sum: number;
17
+ avg: number;
18
+ min: number;
19
+ max: number;
20
+ count: number;
21
+ } | null;
14
22
  }
15
23
  /**
16
24
  * Returns an array of status bar parts (Rows, Filtered, Selected) for consistent rendering across packages.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alaarab/ogrid-core",
3
- "version": "1.3.1",
3
+ "version": "1.4.0",
4
4
  "description": "OGrid core – framework-agnostic types, hooks, and utilities for OGrid data tables.",
5
5
  "main": "dist/esm/index.js",
6
6
  "module": "dist/esm/index.js",