@alaarab/ogrid-core 2.0.1 → 2.0.3
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/utils/columnReorder.js +102 -0
- package/dist/esm/utils/index.js +2 -0
- package/dist/esm/utils/virtualScroll.js +46 -0
- package/dist/types/types/dataGridTypes.d.ts +22 -0
- package/dist/types/types/index.d.ts +1 -1
- package/dist/types/utils/columnReorder.d.ts +40 -0
- package/dist/types/utils/index.d.ts +4 -0
- package/dist/types/utils/virtualScroll.d.ts +36 -0
- package/package.json +1 -1
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Determine which pin zone a column belongs to.
|
|
3
|
+
*/
|
|
4
|
+
export function getPinStateForColumn(columnId, pinnedColumns) {
|
|
5
|
+
if (!pinnedColumns)
|
|
6
|
+
return 'unpinned';
|
|
7
|
+
if (pinnedColumns.left?.includes(columnId))
|
|
8
|
+
return 'left';
|
|
9
|
+
if (pinnedColumns.right?.includes(columnId))
|
|
10
|
+
return 'right';
|
|
11
|
+
return 'unpinned';
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Remove `columnId` from `order` and insert it at `targetIndex`.
|
|
15
|
+
* Returns a new array (does not mutate the input).
|
|
16
|
+
*/
|
|
17
|
+
export function reorderColumnArray(order, columnId, targetIndex) {
|
|
18
|
+
const filtered = order.filter(id => id !== columnId);
|
|
19
|
+
const clampedIndex = Math.max(0, Math.min(targetIndex, filtered.length));
|
|
20
|
+
const result = [...filtered];
|
|
21
|
+
result.splice(clampedIndex, 0, columnId);
|
|
22
|
+
return result;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Calculate the drop target for a dragged column based on mouse position.
|
|
26
|
+
*
|
|
27
|
+
* Iterates visible column header elements (queried via `[data-column-id]`),
|
|
28
|
+
* finds the midpoint of each header cell, and determines insertion side.
|
|
29
|
+
* Respects pinning zones: a left-pinned column can only drop among left-pinned, etc.
|
|
30
|
+
*
|
|
31
|
+
* @param mouseX - Current mouse X position (client coordinates)
|
|
32
|
+
* @param columnOrder - Current column display order (array of column ids)
|
|
33
|
+
* @param draggedColumnId - The column being dragged
|
|
34
|
+
* @param draggedPinState - Pin state of the dragged column
|
|
35
|
+
* @param tableElement - The table (or grid container) DOM element to query headers from
|
|
36
|
+
* @param pinnedColumns - Pinned column configuration
|
|
37
|
+
* @returns Drop target with insertion index and indicator X, or null if no valid target.
|
|
38
|
+
*/
|
|
39
|
+
export function calculateDropTarget(mouseX, columnOrder, draggedColumnId, draggedPinState, tableElement, pinnedColumns) {
|
|
40
|
+
const headerCells = tableElement.querySelectorAll('[data-column-id]');
|
|
41
|
+
if (headerCells.length === 0)
|
|
42
|
+
return null;
|
|
43
|
+
// Build ordered list of header rects for columns in the same pin zone
|
|
44
|
+
const targets = [];
|
|
45
|
+
headerCells.forEach(cell => {
|
|
46
|
+
const colId = cell.getAttribute('data-column-id');
|
|
47
|
+
if (!colId)
|
|
48
|
+
return;
|
|
49
|
+
const pinState = getPinStateForColumn(colId, pinnedColumns);
|
|
50
|
+
if (pinState !== draggedPinState)
|
|
51
|
+
return;
|
|
52
|
+
const rect = cell.getBoundingClientRect();
|
|
53
|
+
const orderIndex = columnOrder.indexOf(colId);
|
|
54
|
+
if (orderIndex === -1)
|
|
55
|
+
return;
|
|
56
|
+
targets.push({
|
|
57
|
+
columnId: colId,
|
|
58
|
+
left: rect.left,
|
|
59
|
+
right: rect.right,
|
|
60
|
+
midX: rect.left + rect.width / 2,
|
|
61
|
+
orderIndex,
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
if (targets.length === 0)
|
|
65
|
+
return null;
|
|
66
|
+
// Sort by visual position (left edge)
|
|
67
|
+
targets.sort((a, b) => a.left - b.left);
|
|
68
|
+
// Find where mouse falls relative to column midpoints
|
|
69
|
+
let targetIndex;
|
|
70
|
+
let indicatorX;
|
|
71
|
+
if (mouseX <= targets[0].midX) {
|
|
72
|
+
// Before the first target
|
|
73
|
+
targetIndex = targets[0].orderIndex;
|
|
74
|
+
indicatorX = targets[0].left;
|
|
75
|
+
}
|
|
76
|
+
else if (mouseX >= targets[targets.length - 1].midX) {
|
|
77
|
+
// After the last target
|
|
78
|
+
const last = targets[targets.length - 1];
|
|
79
|
+
targetIndex = last.orderIndex + 1;
|
|
80
|
+
indicatorX = last.right;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
// Between two targets — find the boundary
|
|
84
|
+
let matchIndex = -1;
|
|
85
|
+
for (let i = 0; i < targets.length - 1; i++) {
|
|
86
|
+
if (mouseX >= targets[i].midX && mouseX < targets[i + 1].midX) {
|
|
87
|
+
matchIndex = i;
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (matchIndex === -1)
|
|
92
|
+
return null;
|
|
93
|
+
targetIndex = targets[matchIndex].orderIndex + 1;
|
|
94
|
+
indicatorX = targets[matchIndex].right;
|
|
95
|
+
}
|
|
96
|
+
// Check if this is a no-op (dropping at same position)
|
|
97
|
+
const currentIndex = columnOrder.indexOf(draggedColumnId);
|
|
98
|
+
if (currentIndex === targetIndex || currentIndex + 1 === targetIndex) {
|
|
99
|
+
return { targetIndex, indicatorX: null };
|
|
100
|
+
}
|
|
101
|
+
return { targetIndex, indicatorX };
|
|
102
|
+
}
|
package/dist/esm/utils/index.js
CHANGED
|
@@ -10,3 +10,5 @@ export { parseValue, numberParser, currencyParser, dateParser, emailParser, bool
|
|
|
10
10
|
export { computeAggregations } from './aggregationUtils';
|
|
11
11
|
export { processClientSideData } from './clientSideData';
|
|
12
12
|
export { areGridRowPropsEqual, isRowInRange } from './gridRowComparator';
|
|
13
|
+
export { getPinStateForColumn, reorderColumnArray, calculateDropTarget, } from './columnReorder';
|
|
14
|
+
export { computeVisibleRange, computeTotalHeight, getScrollTopForRow, } from './virtualScroll';
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compute the range of rows that should be rendered for a given scroll position.
|
|
3
|
+
*
|
|
4
|
+
* @param scrollTop - Current vertical scroll offset (px)
|
|
5
|
+
* @param rowHeight - Fixed height of each row (px)
|
|
6
|
+
* @param containerHeight - Visible height of the scroll container (px)
|
|
7
|
+
* @param totalRows - Total number of rows in the dataset
|
|
8
|
+
* @param overscan - Number of extra rows to render above and below the visible area (default: 5)
|
|
9
|
+
* @returns The visible range with start/end indices and top/bottom spacer offsets
|
|
10
|
+
*/
|
|
11
|
+
export function computeVisibleRange(scrollTop, rowHeight, containerHeight, totalRows, overscan = 5) {
|
|
12
|
+
if (totalRows === 0 || rowHeight <= 0 || containerHeight <= 0) {
|
|
13
|
+
return { startIndex: 0, endIndex: -1, offsetTop: 0, offsetBottom: 0 };
|
|
14
|
+
}
|
|
15
|
+
const startIndex = Math.max(0, Math.floor(scrollTop / rowHeight) - overscan);
|
|
16
|
+
const endIndex = Math.min(totalRows - 1, Math.ceil((scrollTop + containerHeight) / rowHeight) + overscan);
|
|
17
|
+
const offsetTop = startIndex * rowHeight;
|
|
18
|
+
const offsetBottom = Math.max(0, (totalRows - endIndex - 1) * rowHeight);
|
|
19
|
+
return { startIndex, endIndex, offsetTop, offsetBottom };
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Compute the total scrollable height for all rows.
|
|
23
|
+
*/
|
|
24
|
+
export function computeTotalHeight(totalRows, rowHeight) {
|
|
25
|
+
return totalRows * rowHeight;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Compute the scrollTop value needed to bring a specific row into view.
|
|
29
|
+
*
|
|
30
|
+
* @param rowIndex - The row to scroll to
|
|
31
|
+
* @param rowHeight - Fixed height of each row (px)
|
|
32
|
+
* @param containerHeight - Visible height of the scroll container (px)
|
|
33
|
+
* @param align - Where to position the row: 'start' (top), 'center', or 'end' (bottom). Default: 'start'.
|
|
34
|
+
* @returns The scrollTop value to set on the container
|
|
35
|
+
*/
|
|
36
|
+
export function getScrollTopForRow(rowIndex, rowHeight, containerHeight, align = 'start') {
|
|
37
|
+
const rowTop = rowIndex * rowHeight;
|
|
38
|
+
switch (align) {
|
|
39
|
+
case 'start':
|
|
40
|
+
return rowTop;
|
|
41
|
+
case 'center':
|
|
42
|
+
return Math.max(0, rowTop - (containerHeight - rowHeight) / 2);
|
|
43
|
+
case 'end':
|
|
44
|
+
return Math.max(0, rowTop - containerHeight + rowHeight);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -128,6 +128,20 @@ export interface ISideBarDef {
|
|
|
128
128
|
/** Position of the side bar (default: 'right'). */
|
|
129
129
|
position?: 'left' | 'right';
|
|
130
130
|
}
|
|
131
|
+
/** Configuration for virtual scrolling. */
|
|
132
|
+
export interface IVirtualScrollConfig {
|
|
133
|
+
/** Enable virtual scrolling (default: false). */
|
|
134
|
+
enabled?: boolean;
|
|
135
|
+
/** Fixed row height in pixels (required when enabled). */
|
|
136
|
+
rowHeight?: number;
|
|
137
|
+
/** Number of extra rows to render above/below the visible area (default: 5). */
|
|
138
|
+
overscan?: number;
|
|
139
|
+
}
|
|
140
|
+
/** Configuration for column reordering via drag-and-drop. */
|
|
141
|
+
export interface IColumnReorderConfig {
|
|
142
|
+
/** Enable column reordering (default: false). */
|
|
143
|
+
enabled?: boolean;
|
|
144
|
+
}
|
|
131
145
|
/** Imperative grid API exposed via ref. */
|
|
132
146
|
export interface IOGridApi<T> {
|
|
133
147
|
/** Set row data (client-side only; no-op when using dataSource). */
|
|
@@ -160,4 +174,12 @@ export interface IOGridApi<T> {
|
|
|
160
174
|
getDisplayedRows: () => T[];
|
|
161
175
|
/** Re-trigger a data fetch (server-side only; no-op for client-side). */
|
|
162
176
|
refreshData: () => void;
|
|
177
|
+
/** Scroll to a specific row by index (virtual scrolling). */
|
|
178
|
+
scrollToRow: (index: number, options?: {
|
|
179
|
+
align?: 'start' | 'center' | 'end';
|
|
180
|
+
}) => void;
|
|
181
|
+
/** Get the current column display order (array of column ids). */
|
|
182
|
+
getColumnOrder: () => string[];
|
|
183
|
+
/** Set the column display order. */
|
|
184
|
+
setColumnOrder: (order: string[]) => void;
|
|
163
185
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export type { ColumnFilterType, IDateFilterValue, IColumnFilterDef, IColumnMeta, IValueParserParams, IColumnDef, ICellValueChangedEvent, ICellEditorProps, CellEditorParams, IColumnGroupDef, HeaderCell, HeaderRow, IColumnDefinition, } from './columnTypes';
|
|
2
|
-
export type { RowId, UserLike, UserLikeInput, FilterValue, IFilters, IFetchParams, IPageResult, IDataSource, IGridColumnState, RowSelectionMode, IRowSelectionChangeEvent, StatusBarPanel, IStatusBarProps, IActiveCell, ISelectionRange, SideBarPanelId, ISideBarDef, IOGridApi, } from './dataGridTypes';
|
|
2
|
+
export type { RowId, UserLike, UserLikeInput, FilterValue, IFilters, IFetchParams, IPageResult, IDataSource, IGridColumnState, RowSelectionMode, IRowSelectionChangeEvent, StatusBarPanel, IStatusBarProps, IActiveCell, ISelectionRange, SideBarPanelId, ISideBarDef, IVirtualScrollConfig, IColumnReorderConfig, IOGridApi, } from './dataGridTypes';
|
|
3
3
|
export { toUserLike, isInSelectionRange, normalizeSelectionRange, } from './dataGridTypes';
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/** Column pinning state for reorder zone constraints. */
|
|
2
|
+
export type ColumnPinState = 'left' | 'right' | 'unpinned';
|
|
3
|
+
/** Result of computing a drop target during column drag. */
|
|
4
|
+
export interface IDropTarget {
|
|
5
|
+
/** The index in the column order array where the dragged column should be inserted. */
|
|
6
|
+
targetIndex: number;
|
|
7
|
+
/** X position (px) for the visual drop indicator, or null if dropping at the same position (no-op). */
|
|
8
|
+
indicatorX: number | null;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Determine which pin zone a column belongs to.
|
|
12
|
+
*/
|
|
13
|
+
export declare function getPinStateForColumn(columnId: string, pinnedColumns?: {
|
|
14
|
+
left?: string[];
|
|
15
|
+
right?: string[];
|
|
16
|
+
}): ColumnPinState;
|
|
17
|
+
/**
|
|
18
|
+
* Remove `columnId` from `order` and insert it at `targetIndex`.
|
|
19
|
+
* Returns a new array (does not mutate the input).
|
|
20
|
+
*/
|
|
21
|
+
export declare function reorderColumnArray(order: string[], columnId: string, targetIndex: number): string[];
|
|
22
|
+
/**
|
|
23
|
+
* Calculate the drop target for a dragged column based on mouse position.
|
|
24
|
+
*
|
|
25
|
+
* Iterates visible column header elements (queried via `[data-column-id]`),
|
|
26
|
+
* finds the midpoint of each header cell, and determines insertion side.
|
|
27
|
+
* Respects pinning zones: a left-pinned column can only drop among left-pinned, etc.
|
|
28
|
+
*
|
|
29
|
+
* @param mouseX - Current mouse X position (client coordinates)
|
|
30
|
+
* @param columnOrder - Current column display order (array of column ids)
|
|
31
|
+
* @param draggedColumnId - The column being dragged
|
|
32
|
+
* @param draggedPinState - Pin state of the dragged column
|
|
33
|
+
* @param tableElement - The table (or grid container) DOM element to query headers from
|
|
34
|
+
* @param pinnedColumns - Pinned column configuration
|
|
35
|
+
* @returns Drop target with insertion index and indicator X, or null if no valid target.
|
|
36
|
+
*/
|
|
37
|
+
export declare function calculateDropTarget(mouseX: number, columnOrder: string[], draggedColumnId: string, draggedPinState: ColumnPinState, tableElement: Element, pinnedColumns?: {
|
|
38
|
+
left?: string[];
|
|
39
|
+
right?: string[];
|
|
40
|
+
}): IDropTarget | null;
|
|
@@ -17,3 +17,7 @@ export type { AggregationResult } from './aggregationUtils';
|
|
|
17
17
|
export { processClientSideData } from './clientSideData';
|
|
18
18
|
export { areGridRowPropsEqual, isRowInRange } from './gridRowComparator';
|
|
19
19
|
export type { GridRowComparatorProps } from './gridRowComparator';
|
|
20
|
+
export { getPinStateForColumn, reorderColumnArray, calculateDropTarget, } from './columnReorder';
|
|
21
|
+
export type { ColumnPinState, IDropTarget } from './columnReorder';
|
|
22
|
+
export { computeVisibleRange, computeTotalHeight, getScrollTopForRow, } from './virtualScroll';
|
|
23
|
+
export type { IVisibleRange } from './virtualScroll';
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** The visible row range and spacer offsets for virtual scrolling. */
|
|
2
|
+
export interface IVisibleRange {
|
|
3
|
+
/** First visible row index (inclusive, accounting for overscan). */
|
|
4
|
+
startIndex: number;
|
|
5
|
+
/** Last visible row index (inclusive, accounting for overscan). */
|
|
6
|
+
endIndex: number;
|
|
7
|
+
/** Pixel height of the top spacer (to push visible rows into correct scroll position). */
|
|
8
|
+
offsetTop: number;
|
|
9
|
+
/** Pixel height of the bottom spacer (to maintain correct scroll height). */
|
|
10
|
+
offsetBottom: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Compute the range of rows that should be rendered for a given scroll position.
|
|
14
|
+
*
|
|
15
|
+
* @param scrollTop - Current vertical scroll offset (px)
|
|
16
|
+
* @param rowHeight - Fixed height of each row (px)
|
|
17
|
+
* @param containerHeight - Visible height of the scroll container (px)
|
|
18
|
+
* @param totalRows - Total number of rows in the dataset
|
|
19
|
+
* @param overscan - Number of extra rows to render above and below the visible area (default: 5)
|
|
20
|
+
* @returns The visible range with start/end indices and top/bottom spacer offsets
|
|
21
|
+
*/
|
|
22
|
+
export declare function computeVisibleRange(scrollTop: number, rowHeight: number, containerHeight: number, totalRows: number, overscan?: number): IVisibleRange;
|
|
23
|
+
/**
|
|
24
|
+
* Compute the total scrollable height for all rows.
|
|
25
|
+
*/
|
|
26
|
+
export declare function computeTotalHeight(totalRows: number, rowHeight: number): number;
|
|
27
|
+
/**
|
|
28
|
+
* Compute the scrollTop value needed to bring a specific row into view.
|
|
29
|
+
*
|
|
30
|
+
* @param rowIndex - The row to scroll to
|
|
31
|
+
* @param rowHeight - Fixed height of each row (px)
|
|
32
|
+
* @param containerHeight - Visible height of the scroll container (px)
|
|
33
|
+
* @param align - Where to position the row: 'start' (top), 'center', or 'end' (bottom). Default: 'start'.
|
|
34
|
+
* @returns The scrollTop value to set on the container
|
|
35
|
+
*/
|
|
36
|
+
export declare function getScrollTopForRow(rowIndex: number, rowHeight: number, containerHeight: number, align?: 'start' | 'center' | 'end'): number;
|
package/package.json
CHANGED