@alaarab/ogrid-core 2.1.10 → 2.1.11
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/index.js +144 -13
- package/dist/types/constants/zIndex.d.ts +30 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/types/dataGridTypes.d.ts +7 -0
- package/dist/types/utils/dataGridViewModel.d.ts +75 -1
- package/dist/types/utils/index.d.ts +2 -2
- package/dist/types/utils/validation.d.ts +8 -2
- package/package.json +1 -1
package/dist/esm/index.js
CHANGED
|
@@ -583,20 +583,31 @@ function processClientSideData(data, columns, filters, sortBy, sortDirection) {
|
|
|
583
583
|
if (Number.isNaN(bt)) return 1 * dir;
|
|
584
584
|
return at === bt ? 0 : at > bt ? dir : -dir;
|
|
585
585
|
});
|
|
586
|
-
} else {
|
|
586
|
+
} else if (!compare) {
|
|
587
|
+
const keyCache = /* @__PURE__ */ new Map();
|
|
588
|
+
for (let i = 0; i < sortable.length; i++) {
|
|
589
|
+
const row = sortable[i];
|
|
590
|
+
const v = sortCol ? getCellValue(row, sortCol) : row[sortBy];
|
|
591
|
+
if (v == null) {
|
|
592
|
+
keyCache.set(row, void 0);
|
|
593
|
+
} else if (typeof v === "number") {
|
|
594
|
+
keyCache.set(row, v);
|
|
595
|
+
} else {
|
|
596
|
+
keyCache.set(row, String(v).toLowerCase());
|
|
597
|
+
}
|
|
598
|
+
}
|
|
587
599
|
sortable.sort((a, b) => {
|
|
588
|
-
|
|
589
|
-
const
|
|
590
|
-
|
|
591
|
-
if (av
|
|
592
|
-
if (
|
|
593
|
-
if (bv == null) return 1 * dir;
|
|
600
|
+
const av = keyCache.get(a);
|
|
601
|
+
const bv = keyCache.get(b);
|
|
602
|
+
if (av === void 0 && bv === void 0) return 0;
|
|
603
|
+
if (av === void 0) return -1 * dir;
|
|
604
|
+
if (bv === void 0) return 1 * dir;
|
|
594
605
|
if (typeof av === "number" && typeof bv === "number")
|
|
595
606
|
return av === bv ? 0 : av > bv ? dir : -dir;
|
|
596
|
-
|
|
597
|
-
const bs = String(bv).toLowerCase();
|
|
598
|
-
return as === bs ? 0 : as > bs ? dir : -dir;
|
|
607
|
+
return av === bv ? 0 : av > bv ? dir : -dir;
|
|
599
608
|
});
|
|
609
|
+
} else {
|
|
610
|
+
sortable.sort((a, b) => compare(a, b) * dir);
|
|
600
611
|
}
|
|
601
612
|
return sortable;
|
|
602
613
|
}
|
|
@@ -787,7 +798,83 @@ function getHeaderFilterConfig(col, input) {
|
|
|
787
798
|
}
|
|
788
799
|
return base;
|
|
789
800
|
}
|
|
790
|
-
|
|
801
|
+
var _CellDescriptorCache = class _CellDescriptorCache {
|
|
802
|
+
constructor() {
|
|
803
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
804
|
+
/** Last seen volatile version string. Used to detect when to skip per-cell version checks. */
|
|
805
|
+
this.lastVersion = "";
|
|
806
|
+
}
|
|
807
|
+
/**
|
|
808
|
+
* Compute a version string from the volatile parts of CellRenderDescriptorInput.
|
|
809
|
+
* This string changes whenever any input that affects per-cell output changes.
|
|
810
|
+
* Cheap to compute (simple string concat) — O(1) regardless of grid size.
|
|
811
|
+
*/
|
|
812
|
+
static computeVersion(input) {
|
|
813
|
+
const ec = input.editingCell;
|
|
814
|
+
const ac = input.activeCell;
|
|
815
|
+
const sr = input.selectionRange;
|
|
816
|
+
const cr = input.cutRange;
|
|
817
|
+
const cp = input.copyRange;
|
|
818
|
+
return (ec ? `${String(ec.rowId)}\0${ec.columnId}` : "") + "" + (ac ? `${ac.rowIndex}\0${ac.columnIndex}` : "") + "" + (sr ? `${sr.startRow}\0${sr.startCol}\0${sr.endRow}\0${sr.endCol}` : "") + "" + (cr ? `${cr.startRow}\0${cr.startCol}\0${cr.endRow}\0${cr.endCol}` : "") + "" + (cp ? `${cp.startRow}\0${cp.startCol}\0${cp.endRow}\0${cp.endCol}` : "") + "" + (input.isDragging ? "1" : "0") + "" + (input.editable !== false ? "1" : "0") + "" + (input.onCellValueChanged ? "1" : "0");
|
|
819
|
+
}
|
|
820
|
+
/**
|
|
821
|
+
* Get a cached descriptor or compute a new one.
|
|
822
|
+
*
|
|
823
|
+
* @param rowIndex - Row index in the dataset.
|
|
824
|
+
* @param colIdx - Column index within the visible columns.
|
|
825
|
+
* @param version - Volatile version string (from CellDescriptorCache.computeVersion).
|
|
826
|
+
* @param compute - Factory function called on cache miss.
|
|
827
|
+
* @returns The descriptor (cached or freshly computed).
|
|
828
|
+
*/
|
|
829
|
+
get(rowIndex, colIdx, version, compute) {
|
|
830
|
+
const key = rowIndex * _CellDescriptorCache.MAX_COL_STRIDE + colIdx;
|
|
831
|
+
const entry = this.cache.get(key);
|
|
832
|
+
if (entry !== void 0 && entry.version === version) {
|
|
833
|
+
return entry.descriptor;
|
|
834
|
+
}
|
|
835
|
+
const descriptor = compute();
|
|
836
|
+
this.cache.set(key, { version, descriptor });
|
|
837
|
+
return descriptor;
|
|
838
|
+
}
|
|
839
|
+
/**
|
|
840
|
+
* Update the last-seen version and return it.
|
|
841
|
+
* Call once per render pass to track whether any volatile state changed.
|
|
842
|
+
* If the version is unchanged from last render, the entire render is a no-op for all cells.
|
|
843
|
+
*/
|
|
844
|
+
updateVersion(version) {
|
|
845
|
+
this.lastVersion = version;
|
|
846
|
+
}
|
|
847
|
+
/** The last version string set via updateVersion(). */
|
|
848
|
+
get currentVersion() {
|
|
849
|
+
return this.lastVersion;
|
|
850
|
+
}
|
|
851
|
+
/**
|
|
852
|
+
* Clear all cached entries. Call when the grid's data changes (new items array,
|
|
853
|
+
* different column count, etc.) to prevent stale cell values from being served.
|
|
854
|
+
*/
|
|
855
|
+
clear() {
|
|
856
|
+
this.cache.clear();
|
|
857
|
+
}
|
|
858
|
+
};
|
|
859
|
+
/**
|
|
860
|
+
* Stride used to compute a flat cache key: rowIndex * MAX_COL_STRIDE + colIdx.
|
|
861
|
+
* 1024 supports grids up to 1024 columns, which covers all realistic use cases.
|
|
862
|
+
* Using a power-of-2 stride lets the JS engine optimize the multiplication.
|
|
863
|
+
*/
|
|
864
|
+
_CellDescriptorCache.MAX_COL_STRIDE = 1024;
|
|
865
|
+
var CellDescriptorCache = _CellDescriptorCache;
|
|
866
|
+
function getCellRenderDescriptor(item, col, rowIndex, colIdx, input, cache) {
|
|
867
|
+
if (cache !== void 0) {
|
|
868
|
+
return cache.get(
|
|
869
|
+
rowIndex,
|
|
870
|
+
colIdx,
|
|
871
|
+
cache.currentVersion,
|
|
872
|
+
() => computeCellDescriptor(item, col, rowIndex, colIdx, input)
|
|
873
|
+
);
|
|
874
|
+
}
|
|
875
|
+
return computeCellDescriptor(item, col, rowIndex, colIdx, input);
|
|
876
|
+
}
|
|
877
|
+
function computeCellDescriptor(item, col, rowIndex, colIdx, input) {
|
|
791
878
|
const rowId = input.getRowId(item);
|
|
792
879
|
const globalColIndex = colIdx + input.colOffset;
|
|
793
880
|
const colEditable = isColumnEditable(col, item);
|
|
@@ -1384,6 +1471,7 @@ function validateColumns(columns) {
|
|
|
1384
1471
|
console.warn("[OGrid] columns prop is empty or not an array");
|
|
1385
1472
|
return;
|
|
1386
1473
|
}
|
|
1474
|
+
const isDev = typeof process !== "undefined" && process.env?.NODE_ENV !== "production";
|
|
1387
1475
|
const ids = /* @__PURE__ */ new Set();
|
|
1388
1476
|
for (const col of columns) {
|
|
1389
1477
|
if (!col.columnId) {
|
|
@@ -1393,10 +1481,25 @@ function validateColumns(columns) {
|
|
|
1393
1481
|
console.warn(`[OGrid] Duplicate columnId: "${col.columnId}"`);
|
|
1394
1482
|
}
|
|
1395
1483
|
ids.add(col.columnId);
|
|
1484
|
+
if (isDev && col.editable === true && col.cellEditor == null) {
|
|
1485
|
+
console.warn(
|
|
1486
|
+
`[OGrid] Column "${col.columnId}" has editable=true but no cellEditor defined. Cells will not open an editor on double-click. Set cellEditor to 'text', 'select', 'checkbox', 'date', or a custom component.`
|
|
1487
|
+
);
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
function validateVirtualScrollConfig(config) {
|
|
1492
|
+
if (typeof process !== "undefined" && process.env?.NODE_ENV === "production") return;
|
|
1493
|
+
if (config.enabled !== true) return;
|
|
1494
|
+
if (!config.rowHeight || config.rowHeight <= 0) {
|
|
1495
|
+
console.warn(
|
|
1496
|
+
"[OGrid] virtualScroll.enabled is true but rowHeight is missing or <= 0. Set a positive rowHeight (e.g. virtualScroll: { enabled: true, rowHeight: 36 }) for correct virtual scrolling behavior."
|
|
1497
|
+
);
|
|
1396
1498
|
}
|
|
1397
1499
|
}
|
|
1398
1500
|
function validateRowIds(items, getRowId) {
|
|
1399
1501
|
if (typeof process !== "undefined" && process.env.NODE_ENV === "production") return;
|
|
1502
|
+
if (!getRowId) return;
|
|
1400
1503
|
const ids = /* @__PURE__ */ new Set();
|
|
1401
1504
|
const limit = Math.min(items.length, 100);
|
|
1402
1505
|
for (let i = 0; i < limit; i++) {
|
|
@@ -1422,16 +1525,44 @@ var SIDEBAR_TRANSITION_MS = 300;
|
|
|
1422
1525
|
|
|
1423
1526
|
// src/constants/zIndex.ts
|
|
1424
1527
|
var Z_INDEX = {
|
|
1528
|
+
/** Column resize drag handle */
|
|
1529
|
+
RESIZE_HANDLE: 1,
|
|
1530
|
+
/** Active/editing cell outline */
|
|
1531
|
+
ACTIVE_CELL: 2,
|
|
1532
|
+
/** Fill handle dot */
|
|
1533
|
+
FILL_HANDLE: 3,
|
|
1425
1534
|
/** Selection range overlay (marching ants) */
|
|
1426
1535
|
SELECTION_OVERLAY: 4,
|
|
1536
|
+
/** Row number column */
|
|
1537
|
+
ROW_NUMBER: 5,
|
|
1427
1538
|
/** Clipboard overlay (copy/cut animation) */
|
|
1428
1539
|
CLIPBOARD_OVERLAY: 5,
|
|
1540
|
+
/** Sticky pinned body cells */
|
|
1541
|
+
PINNED: 6,
|
|
1542
|
+
/** Selection checkbox column in body */
|
|
1543
|
+
SELECTION_CELL: 7,
|
|
1544
|
+
/** Sticky thead row */
|
|
1545
|
+
THEAD: 8,
|
|
1546
|
+
/** Pinned header cells (sticky both axes) */
|
|
1547
|
+
PINNED_HEADER: 10,
|
|
1548
|
+
/** Focused header cell */
|
|
1549
|
+
HEADER_FOCUS: 11,
|
|
1550
|
+
/** Checkbox column in sticky header (sticky both axes) */
|
|
1551
|
+
SELECTION_HEADER_PINNED: 12,
|
|
1552
|
+
/** Loading overlay within table */
|
|
1553
|
+
LOADING: 2,
|
|
1554
|
+
/** Column reorder drop indicator */
|
|
1555
|
+
DROP_INDICATOR: 100,
|
|
1429
1556
|
/** Dropdown menus (column chooser, pagination size select) */
|
|
1430
1557
|
DROPDOWN: 1e3,
|
|
1558
|
+
/** Filter popovers */
|
|
1559
|
+
FILTER_POPOVER: 1e3,
|
|
1431
1560
|
/** Modal dialogs */
|
|
1432
1561
|
MODAL: 2e3,
|
|
1562
|
+
/** Fullscreen grid container */
|
|
1563
|
+
FULLSCREEN: 9999,
|
|
1433
1564
|
/** Context menus (right-click grid menu) */
|
|
1434
|
-
CONTEXT_MENU:
|
|
1565
|
+
CONTEXT_MENU: 1e4
|
|
1435
1566
|
};
|
|
1436
1567
|
|
|
1437
|
-
export { AUTOSIZE_EXTRA_PX, AUTOSIZE_MAX_PX, CELL_PADDING, CHECKBOX_COLUMN_WIDTH, COLUMN_HEADER_MENU_ITEMS, DEFAULT_DEBOUNCE_MS, DEFAULT_MIN_COLUMN_WIDTH, GRID_BORDER_RADIUS, GRID_CONTEXT_MENU_ITEMS, MAX_PAGE_BUTTONS, PAGE_SIZE_OPTIONS, PEOPLE_SEARCH_DEBOUNCE_MS, ROW_NUMBER_COLUMN_WIDTH, SIDEBAR_TRANSITION_MS, UndoRedoStack, Z_INDEX, applyCellDeletion, applyCutClear, applyFillValues, applyPastedValues, applyRangeRowSelection, areGridRowPropsEqual, booleanParser, buildCellIndex, buildCsvHeader, buildCsvRows, buildHeaderRows, buildInlineEditorProps, buildPopoverEditorProps, calculateDropTarget, clampSelectionToBounds, computeAggregations, computeArrowNavigation, computeAutoScrollSpeed, computeNextSortState, computeRowSelectionState, computeTabNavigation, computeTotalHeight, computeVisibleRange, currencyParser, dateParser, debounce, deriveFilterOptionsFromData, emailParser, escapeCsvValue, exportToCsv, findCtrlArrowTarget, flattenColumns, formatCellValueForTsv, formatSelectionAsTsv, formatShortcut, getCellRenderDescriptor, getCellValue, getColumnHeaderMenuItems, getContextMenuHandlers, getDataGridStatusBarConfig, getFilterField, getHeaderFilterConfig, getMultiSelectFilterFields, getPaginationViewModel, getPinStateForColumn, getScrollTopForRow, getStatusBarParts, injectGlobalStyles, isColumnEditable, isFilterConfig, isInSelectionRange, isRowInRange, measureColumnContentWidth, measureRange, mergeFilter, normalizeSelectionRange, numberParser, parseTsvClipboard, parseValue, processClientSideData, rangesEqual, reorderColumnArray, resolveCellDisplayContent, resolveCellStyle, toUserLike, triggerCsvDownload, validateColumns, validateRowIds };
|
|
1568
|
+
export { AUTOSIZE_EXTRA_PX, AUTOSIZE_MAX_PX, CELL_PADDING, CHECKBOX_COLUMN_WIDTH, COLUMN_HEADER_MENU_ITEMS, CellDescriptorCache, DEFAULT_DEBOUNCE_MS, DEFAULT_MIN_COLUMN_WIDTH, GRID_BORDER_RADIUS, GRID_CONTEXT_MENU_ITEMS, MAX_PAGE_BUTTONS, PAGE_SIZE_OPTIONS, PEOPLE_SEARCH_DEBOUNCE_MS, ROW_NUMBER_COLUMN_WIDTH, SIDEBAR_TRANSITION_MS, UndoRedoStack, Z_INDEX, applyCellDeletion, applyCutClear, applyFillValues, applyPastedValues, applyRangeRowSelection, areGridRowPropsEqual, booleanParser, buildCellIndex, buildCsvHeader, buildCsvRows, buildHeaderRows, buildInlineEditorProps, buildPopoverEditorProps, calculateDropTarget, clampSelectionToBounds, computeAggregations, computeArrowNavigation, computeAutoScrollSpeed, computeNextSortState, computeRowSelectionState, computeTabNavigation, computeTotalHeight, computeVisibleRange, currencyParser, dateParser, debounce, deriveFilterOptionsFromData, emailParser, escapeCsvValue, exportToCsv, findCtrlArrowTarget, flattenColumns, formatCellValueForTsv, formatSelectionAsTsv, formatShortcut, getCellRenderDescriptor, getCellValue, getColumnHeaderMenuItems, getContextMenuHandlers, getDataGridStatusBarConfig, getFilterField, getHeaderFilterConfig, getMultiSelectFilterFields, getPaginationViewModel, getPinStateForColumn, getScrollTopForRow, getStatusBarParts, injectGlobalStyles, isColumnEditable, isFilterConfig, isInSelectionRange, isRowInRange, measureColumnContentWidth, measureRange, mergeFilter, normalizeSelectionRange, numberParser, parseTsvClipboard, parseValue, processClientSideData, rangesEqual, reorderColumnArray, resolveCellDisplayContent, resolveCellStyle, toUserLike, triggerCsvDownload, validateColumns, validateRowIds, validateVirtualScrollConfig };
|
|
@@ -1,18 +1,47 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Z-index constants for layering OGrid UI elements.
|
|
3
3
|
* Ensures consistent stacking order across all packages.
|
|
4
|
+
* Values mirror --ogrid-z-* CSS custom properties in _ogrid-theme.scss.
|
|
4
5
|
*/
|
|
5
6
|
export declare const Z_INDEX: {
|
|
7
|
+
/** Column resize drag handle */
|
|
8
|
+
readonly RESIZE_HANDLE: 1;
|
|
9
|
+
/** Active/editing cell outline */
|
|
10
|
+
readonly ACTIVE_CELL: 2;
|
|
11
|
+
/** Fill handle dot */
|
|
12
|
+
readonly FILL_HANDLE: 3;
|
|
6
13
|
/** Selection range overlay (marching ants) */
|
|
7
14
|
readonly SELECTION_OVERLAY: 4;
|
|
15
|
+
/** Row number column */
|
|
16
|
+
readonly ROW_NUMBER: 5;
|
|
8
17
|
/** Clipboard overlay (copy/cut animation) */
|
|
9
18
|
readonly CLIPBOARD_OVERLAY: 5;
|
|
19
|
+
/** Sticky pinned body cells */
|
|
20
|
+
readonly PINNED: 6;
|
|
21
|
+
/** Selection checkbox column in body */
|
|
22
|
+
readonly SELECTION_CELL: 7;
|
|
23
|
+
/** Sticky thead row */
|
|
24
|
+
readonly THEAD: 8;
|
|
25
|
+
/** Pinned header cells (sticky both axes) */
|
|
26
|
+
readonly PINNED_HEADER: 10;
|
|
27
|
+
/** Focused header cell */
|
|
28
|
+
readonly HEADER_FOCUS: 11;
|
|
29
|
+
/** Checkbox column in sticky header (sticky both axes) */
|
|
30
|
+
readonly SELECTION_HEADER_PINNED: 12;
|
|
31
|
+
/** Loading overlay within table */
|
|
32
|
+
readonly LOADING: 2;
|
|
33
|
+
/** Column reorder drop indicator */
|
|
34
|
+
readonly DROP_INDICATOR: 100;
|
|
10
35
|
/** Dropdown menus (column chooser, pagination size select) */
|
|
11
36
|
readonly DROPDOWN: 1000;
|
|
37
|
+
/** Filter popovers */
|
|
38
|
+
readonly FILTER_POPOVER: 1000;
|
|
12
39
|
/** Modal dialogs */
|
|
13
40
|
readonly MODAL: 2000;
|
|
41
|
+
/** Fullscreen grid container */
|
|
42
|
+
readonly FULLSCREEN: 9999;
|
|
14
43
|
/** Context menus (right-click grid menu) */
|
|
15
|
-
readonly CONTEXT_MENU:
|
|
44
|
+
readonly CONTEXT_MENU: 10000;
|
|
16
45
|
};
|
|
17
46
|
/** Type helper for z-index keys */
|
|
18
47
|
export type ZIndexKey = keyof typeof Z_INDEX;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -24,7 +24,7 @@ export { getPinStateForColumn, reorderColumnArray, calculateDropTarget, } from '
|
|
|
24
24
|
export type { ColumnPinState, IDropTarget, ICalculateDropTargetParams } from './utils';
|
|
25
25
|
export { computeVisibleRange, computeTotalHeight, getScrollTopForRow, } from './utils';
|
|
26
26
|
export type { IVisibleRange } from './utils';
|
|
27
|
-
export { getHeaderFilterConfig, getCellRenderDescriptor, resolveCellDisplayContent, resolveCellStyle, buildInlineEditorProps, buildPopoverEditorProps, } from './utils';
|
|
27
|
+
export { getHeaderFilterConfig, getCellRenderDescriptor, CellDescriptorCache, resolveCellDisplayContent, resolveCellStyle, buildInlineEditorProps, buildPopoverEditorProps, } from './utils';
|
|
28
28
|
export type { HeaderFilterConfigInput, HeaderFilterConfig, CellRenderDescriptorInput, CellRenderDescriptor, CellRenderMode, } from './utils';
|
|
29
29
|
export { debounce } from './utils';
|
|
30
30
|
export { measureRange, buildCellIndex, injectGlobalStyles } from './utils';
|
|
@@ -38,7 +38,7 @@ export { rangesEqual, clampSelectionToBounds, computeAutoScrollSpeed, applyRange
|
|
|
38
38
|
export { formatCellValueForTsv, formatSelectionAsTsv, parseTsvClipboard, applyPastedValues, applyCutClear, } from './utils';
|
|
39
39
|
export { applyFillValues } from './utils';
|
|
40
40
|
export { UndoRedoStack } from './utils';
|
|
41
|
-
export { validateColumns, validateRowIds } from './utils';
|
|
41
|
+
export { validateColumns, validateRowIds, validateVirtualScrollConfig } from './utils';
|
|
42
42
|
export { CHECKBOX_COLUMN_WIDTH, ROW_NUMBER_COLUMN_WIDTH, DEFAULT_MIN_COLUMN_WIDTH, CELL_PADDING, GRID_BORDER_RADIUS, } from './constants';
|
|
43
43
|
export { DEFAULT_DEBOUNCE_MS, PEOPLE_SEARCH_DEBOUNCE_MS, SIDEBAR_TRANSITION_MS, } from './constants';
|
|
44
44
|
export { Z_INDEX } from './constants';
|
|
@@ -136,6 +136,13 @@ export interface IVirtualScrollConfig {
|
|
|
136
136
|
rowHeight?: number;
|
|
137
137
|
/** Number of extra rows to render above/below the visible area (default: 5). */
|
|
138
138
|
overscan?: number;
|
|
139
|
+
/**
|
|
140
|
+
* Minimum row count before virtual scrolling activates (default: 100).
|
|
141
|
+
* When totalRows < threshold, all rows are rendered without virtualization.
|
|
142
|
+
* Lower values activate virtualization earlier (more memory-efficient for mid-size grids);
|
|
143
|
+
* higher values keep small grids fully rendered (no scroll offset artifacts).
|
|
144
|
+
*/
|
|
145
|
+
threshold?: number;
|
|
139
146
|
}
|
|
140
147
|
/** Configuration for column reordering via drag-and-drop. */
|
|
141
148
|
export interface IColumnReorderConfig {
|
|
@@ -94,11 +94,85 @@ export interface CellRenderDescriptor {
|
|
|
94
94
|
/** Raw value for display (when mode === 'display'). UI uses col.renderCell or col.valueFormatter. */
|
|
95
95
|
displayValue?: unknown;
|
|
96
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* Per-grid cache for cell render descriptors.
|
|
99
|
+
*
|
|
100
|
+
* Problem: A 50-column × 100-row grid calls getCellRenderDescriptor 5,000 times per render.
|
|
101
|
+
* Most cells don't change between renders — only cells in the active row, selection range,
|
|
102
|
+
* or editing row need recomputation. The cache skips recomputation for unchanged cells.
|
|
103
|
+
*
|
|
104
|
+
* Design:
|
|
105
|
+
* - Keyed by (rowIndex * MAX_COL_STRIDE + colIdx) for O(1) flat-array-style access.
|
|
106
|
+
* - Tracks a "volatile version" string derived from all inputs that affect per-cell output.
|
|
107
|
+
* - On version match (cache hit), returns the cached descriptor without recomputing.
|
|
108
|
+
* - On version mismatch (cache miss or first render), recomputes and stores the result.
|
|
109
|
+
*
|
|
110
|
+
* Usage: Create one instance per grid (e.g. useRef in React) and pass to getCellRenderDescriptor.
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* const descriptorCache = useRef(new CellDescriptorCache());
|
|
114
|
+
* // In renderCellContent:
|
|
115
|
+
* getCellRenderDescriptor(item, col, rowIndex, colIdx, input, descriptorCache.current);
|
|
116
|
+
*/
|
|
117
|
+
export declare class CellDescriptorCache {
|
|
118
|
+
/**
|
|
119
|
+
* Stride used to compute a flat cache key: rowIndex * MAX_COL_STRIDE + colIdx.
|
|
120
|
+
* 1024 supports grids up to 1024 columns, which covers all realistic use cases.
|
|
121
|
+
* Using a power-of-2 stride lets the JS engine optimize the multiplication.
|
|
122
|
+
*/
|
|
123
|
+
private static readonly MAX_COL_STRIDE;
|
|
124
|
+
private readonly cache;
|
|
125
|
+
/** Last seen volatile version string. Used to detect when to skip per-cell version checks. */
|
|
126
|
+
private lastVersion;
|
|
127
|
+
/**
|
|
128
|
+
* Compute a version string from the volatile parts of CellRenderDescriptorInput.
|
|
129
|
+
* This string changes whenever any input that affects per-cell output changes.
|
|
130
|
+
* Cheap to compute (simple string concat) — O(1) regardless of grid size.
|
|
131
|
+
*/
|
|
132
|
+
static computeVersion<T>(input: CellRenderDescriptorInput<T>): string;
|
|
133
|
+
/**
|
|
134
|
+
* Get a cached descriptor or compute a new one.
|
|
135
|
+
*
|
|
136
|
+
* @param rowIndex - Row index in the dataset.
|
|
137
|
+
* @param colIdx - Column index within the visible columns.
|
|
138
|
+
* @param version - Volatile version string (from CellDescriptorCache.computeVersion).
|
|
139
|
+
* @param compute - Factory function called on cache miss.
|
|
140
|
+
* @returns The descriptor (cached or freshly computed).
|
|
141
|
+
*/
|
|
142
|
+
get(rowIndex: number, colIdx: number, version: string, compute: () => CellRenderDescriptor): CellRenderDescriptor;
|
|
143
|
+
/**
|
|
144
|
+
* Update the last-seen version and return it.
|
|
145
|
+
* Call once per render pass to track whether any volatile state changed.
|
|
146
|
+
* If the version is unchanged from last render, the entire render is a no-op for all cells.
|
|
147
|
+
*/
|
|
148
|
+
updateVersion(version: string): void;
|
|
149
|
+
/** The last version string set via updateVersion(). */
|
|
150
|
+
get currentVersion(): string;
|
|
151
|
+
/**
|
|
152
|
+
* Clear all cached entries. Call when the grid's data changes (new items array,
|
|
153
|
+
* different column count, etc.) to prevent stale cell values from being served.
|
|
154
|
+
*/
|
|
155
|
+
clear(): void;
|
|
156
|
+
}
|
|
97
157
|
/**
|
|
98
158
|
* Returns a descriptor for rendering a cell. UI uses this to decide editing-inline vs editing-popover vs display
|
|
99
159
|
* and to apply isActive, isInRange, etc. without duplicating the boolean logic.
|
|
160
|
+
*
|
|
161
|
+
* @param item - The row data object.
|
|
162
|
+
* @param col - The column definition.
|
|
163
|
+
* @param rowIndex - Row index in the dataset.
|
|
164
|
+
* @param colIdx - Column index within the visible columns.
|
|
165
|
+
* @param input - Volatile state inputs (editing cell, active cell, selection ranges, etc.).
|
|
166
|
+
* @param cache - Optional descriptor cache. When provided and the volatile state is unchanged,
|
|
167
|
+
* the cached descriptor is returned without recomputation. Pass a `CellDescriptorCache`
|
|
168
|
+
* instance created once per grid (e.g. via `useRef`) and updated each render via
|
|
169
|
+
* `CellDescriptorCache.computeVersion`. This eliminates ~5,000 allocations/render on a
|
|
170
|
+
* 50-col × 100-row grid when selection/editing state hasn't changed for a given cell.
|
|
100
171
|
*/
|
|
101
|
-
export declare function getCellRenderDescriptor<T>(item: T, col: IColumnDef<T>, rowIndex: number, colIdx: number, input: CellRenderDescriptorInput<T
|
|
172
|
+
export declare function getCellRenderDescriptor<T>(item: T, col: IColumnDef<T>, rowIndex: number, colIdx: number, input: CellRenderDescriptorInput<T>, cache?: {
|
|
173
|
+
get(rowIndex: number, colIdx: number, version: string, compute: () => CellRenderDescriptor): CellRenderDescriptor;
|
|
174
|
+
currentVersion: string;
|
|
175
|
+
}): CellRenderDescriptor;
|
|
102
176
|
/**
|
|
103
177
|
* Resolves display content for a cell in display mode.
|
|
104
178
|
* Handles the renderCell -> valueFormatter -> String() fallback chain.
|
|
@@ -21,7 +21,7 @@ export { getPinStateForColumn, reorderColumnArray, calculateDropTarget, } from '
|
|
|
21
21
|
export type { ColumnPinState, IDropTarget, ICalculateDropTargetParams } from './columnReorder';
|
|
22
22
|
export { computeVisibleRange, computeTotalHeight, getScrollTopForRow, } from './virtualScroll';
|
|
23
23
|
export type { IVisibleRange } from './virtualScroll';
|
|
24
|
-
export { getHeaderFilterConfig, getCellRenderDescriptor, resolveCellDisplayContent, resolveCellStyle, buildInlineEditorProps, buildPopoverEditorProps, } from './dataGridViewModel';
|
|
24
|
+
export { getHeaderFilterConfig, getCellRenderDescriptor, CellDescriptorCache, resolveCellDisplayContent, resolveCellStyle, buildInlineEditorProps, buildPopoverEditorProps, } from './dataGridViewModel';
|
|
25
25
|
export type { HeaderFilterConfigInput, HeaderFilterConfig, CellRenderDescriptorInput, CellRenderDescriptor, CellRenderMode, } from './dataGridViewModel';
|
|
26
26
|
export { debounce } from './debounce';
|
|
27
27
|
export { measureRange, buildCellIndex, injectGlobalStyles } from './dom';
|
|
@@ -35,4 +35,4 @@ export { rangesEqual, clampSelectionToBounds, computeAutoScrollSpeed, applyRange
|
|
|
35
35
|
export { formatCellValueForTsv, formatSelectionAsTsv, parseTsvClipboard, applyPastedValues, applyCutClear, } from './clipboardHelpers';
|
|
36
36
|
export { applyFillValues } from './fillHelpers';
|
|
37
37
|
export { UndoRedoStack } from './undoRedoStack';
|
|
38
|
-
export { validateColumns, validateRowIds } from './validation';
|
|
38
|
+
export { validateColumns, validateRowIds, validateVirtualScrollConfig } from './validation';
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import type { IColumnDef } from '../types/columnTypes';
|
|
2
|
-
import type { RowId } from '../types/dataGridTypes';
|
|
2
|
+
import type { RowId, IVirtualScrollConfig } from '../types/dataGridTypes';
|
|
3
3
|
/**
|
|
4
4
|
* Validate column definitions at grid initialization.
|
|
5
5
|
* Called once (not per render). Warns on empty/missing/duplicate columnIds.
|
|
6
|
+
* In development mode, also warns when editable=true but no cellEditor is defined.
|
|
6
7
|
*/
|
|
7
8
|
export declare function validateColumns<T>(columns: IColumnDef<T>[]): void;
|
|
9
|
+
/**
|
|
10
|
+
* Validate virtual scroll configuration.
|
|
11
|
+
* Dev-only warning when enabled=true but rowHeight is missing or <= 0.
|
|
12
|
+
*/
|
|
13
|
+
export declare function validateVirtualScrollConfig(config: IVirtualScrollConfig): void;
|
|
8
14
|
/**
|
|
9
15
|
* Validate that getRowId returns unique, non-null values.
|
|
10
16
|
* Dev-only (skipped in production). Samples the first 100 rows.
|
|
11
17
|
* Called once on first data render via a hasValidated flag in the caller.
|
|
12
18
|
*/
|
|
13
|
-
export declare function validateRowIds<T>(items: T[], getRowId: (item: T) => RowId): void;
|
|
19
|
+
export declare function validateRowIds<T>(items: T[], getRowId: ((item: T) => RowId) | null | undefined): void;
|
package/package.json
CHANGED