@alaarab/ogrid-js 2.1.10 → 2.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/index.js +189 -21
- package/dist/styles/ogrid.css +55 -31
- package/dist/types/state/FillHandleState.d.ts +2 -0
- package/dist/types/state/KeyboardNavState.d.ts +4 -0
- package/dist/types/state/VirtualScrollState.d.ts +1 -1
- package/dist/types/types/gridTypes.d.ts +2 -0
- package/package.json +2 -2
package/dist/esm/index.js
CHANGED
|
@@ -561,20 +561,31 @@ function processClientSideData(data, columns, filters, sortBy, sortDirection) {
|
|
|
561
561
|
if (Number.isNaN(bt)) return 1 * dir;
|
|
562
562
|
return at === bt ? 0 : at > bt ? dir : -dir;
|
|
563
563
|
});
|
|
564
|
-
} else {
|
|
564
|
+
} else if (!compare) {
|
|
565
|
+
const keyCache = /* @__PURE__ */ new Map();
|
|
566
|
+
for (let i = 0; i < sortable.length; i++) {
|
|
567
|
+
const row = sortable[i];
|
|
568
|
+
const v = sortCol ? getCellValue(row, sortCol) : row[sortBy];
|
|
569
|
+
if (v == null) {
|
|
570
|
+
keyCache.set(row, void 0);
|
|
571
|
+
} else if (typeof v === "number") {
|
|
572
|
+
keyCache.set(row, v);
|
|
573
|
+
} else {
|
|
574
|
+
keyCache.set(row, String(v).toLowerCase());
|
|
575
|
+
}
|
|
576
|
+
}
|
|
565
577
|
sortable.sort((a, b) => {
|
|
566
|
-
|
|
567
|
-
const
|
|
568
|
-
|
|
569
|
-
if (av
|
|
570
|
-
if (
|
|
571
|
-
if (bv == null) return 1 * dir;
|
|
578
|
+
const av = keyCache.get(a);
|
|
579
|
+
const bv = keyCache.get(b);
|
|
580
|
+
if (av === void 0 && bv === void 0) return 0;
|
|
581
|
+
if (av === void 0) return -1 * dir;
|
|
582
|
+
if (bv === void 0) return 1 * dir;
|
|
572
583
|
if (typeof av === "number" && typeof bv === "number")
|
|
573
584
|
return av === bv ? 0 : av > bv ? dir : -dir;
|
|
574
|
-
|
|
575
|
-
const bs = String(bv).toLowerCase();
|
|
576
|
-
return as === bs ? 0 : as > bs ? dir : -dir;
|
|
585
|
+
return av === bv ? 0 : av > bv ? dir : -dir;
|
|
577
586
|
});
|
|
587
|
+
} else {
|
|
588
|
+
sortable.sort((a, b) => compare(a, b) * dir);
|
|
578
589
|
}
|
|
579
590
|
return sortable;
|
|
580
591
|
}
|
|
@@ -757,7 +768,77 @@ function getHeaderFilterConfig(col, input) {
|
|
|
757
768
|
}
|
|
758
769
|
return base;
|
|
759
770
|
}
|
|
760
|
-
|
|
771
|
+
var _CellDescriptorCache = class _CellDescriptorCache2 {
|
|
772
|
+
constructor() {
|
|
773
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
774
|
+
this.lastVersion = "";
|
|
775
|
+
}
|
|
776
|
+
/**
|
|
777
|
+
* Compute a version string from the volatile parts of CellRenderDescriptorInput.
|
|
778
|
+
* This string changes whenever any input that affects per-cell output changes.
|
|
779
|
+
* Cheap to compute (simple string concat) — O(1) regardless of grid size.
|
|
780
|
+
*/
|
|
781
|
+
static computeVersion(input) {
|
|
782
|
+
const ec = input.editingCell;
|
|
783
|
+
const ac = input.activeCell;
|
|
784
|
+
const sr = input.selectionRange;
|
|
785
|
+
const cr = input.cutRange;
|
|
786
|
+
const cp = input.copyRange;
|
|
787
|
+
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");
|
|
788
|
+
}
|
|
789
|
+
/**
|
|
790
|
+
* Get a cached descriptor or compute a new one.
|
|
791
|
+
*
|
|
792
|
+
* @param rowIndex - Row index in the dataset.
|
|
793
|
+
* @param colIdx - Column index within the visible columns.
|
|
794
|
+
* @param version - Volatile version string (from CellDescriptorCache.computeVersion).
|
|
795
|
+
* @param compute - Factory function called on cache miss.
|
|
796
|
+
* @returns The descriptor (cached or freshly computed).
|
|
797
|
+
*/
|
|
798
|
+
get(rowIndex, colIdx, version, compute) {
|
|
799
|
+
const key = rowIndex * _CellDescriptorCache2.MAX_COL_STRIDE + colIdx;
|
|
800
|
+
const entry = this.cache.get(key);
|
|
801
|
+
if (entry !== void 0 && entry.version === version) {
|
|
802
|
+
return entry.descriptor;
|
|
803
|
+
}
|
|
804
|
+
const descriptor = compute();
|
|
805
|
+
this.cache.set(key, { version, descriptor });
|
|
806
|
+
return descriptor;
|
|
807
|
+
}
|
|
808
|
+
/**
|
|
809
|
+
* Update the last-seen version and return it.
|
|
810
|
+
* Call once per render pass to track whether any volatile state changed.
|
|
811
|
+
* If the version is unchanged from last render, the entire render is a no-op for all cells.
|
|
812
|
+
*/
|
|
813
|
+
updateVersion(version) {
|
|
814
|
+
this.lastVersion = version;
|
|
815
|
+
}
|
|
816
|
+
/** The last version string set via updateVersion(). */
|
|
817
|
+
get currentVersion() {
|
|
818
|
+
return this.lastVersion;
|
|
819
|
+
}
|
|
820
|
+
/**
|
|
821
|
+
* Clear all cached entries. Call when the grid's data changes (new items array,
|
|
822
|
+
* different column count, etc.) to prevent stale cell values from being served.
|
|
823
|
+
*/
|
|
824
|
+
clear() {
|
|
825
|
+
this.cache.clear();
|
|
826
|
+
}
|
|
827
|
+
};
|
|
828
|
+
_CellDescriptorCache.MAX_COL_STRIDE = 1024;
|
|
829
|
+
var CellDescriptorCache = _CellDescriptorCache;
|
|
830
|
+
function getCellRenderDescriptor(item, col, rowIndex, colIdx, input, cache) {
|
|
831
|
+
if (cache !== void 0) {
|
|
832
|
+
return cache.get(
|
|
833
|
+
rowIndex,
|
|
834
|
+
colIdx,
|
|
835
|
+
cache.currentVersion,
|
|
836
|
+
() => computeCellDescriptor(item, col, rowIndex, colIdx, input)
|
|
837
|
+
);
|
|
838
|
+
}
|
|
839
|
+
return computeCellDescriptor(item, col, rowIndex, colIdx, input);
|
|
840
|
+
}
|
|
841
|
+
function computeCellDescriptor(item, col, rowIndex, colIdx, input) {
|
|
761
842
|
const rowId = input.getRowId(item);
|
|
762
843
|
const globalColIndex = colIdx + input.colOffset;
|
|
763
844
|
const colEditable = isColumnEditable(col, item);
|
|
@@ -1332,6 +1413,7 @@ function validateColumns(columns) {
|
|
|
1332
1413
|
console.warn("[OGrid] columns prop is empty or not an array");
|
|
1333
1414
|
return;
|
|
1334
1415
|
}
|
|
1416
|
+
const isDev = typeof process !== "undefined" && process.env?.NODE_ENV !== "production";
|
|
1335
1417
|
const ids = /* @__PURE__ */ new Set();
|
|
1336
1418
|
for (const col of columns) {
|
|
1337
1419
|
if (!col.columnId) {
|
|
@@ -1341,10 +1423,25 @@ function validateColumns(columns) {
|
|
|
1341
1423
|
console.warn(`[OGrid] Duplicate columnId: "${col.columnId}"`);
|
|
1342
1424
|
}
|
|
1343
1425
|
ids.add(col.columnId);
|
|
1426
|
+
if (isDev && col.editable === true && col.cellEditor == null) {
|
|
1427
|
+
console.warn(
|
|
1428
|
+
`[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.`
|
|
1429
|
+
);
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
function validateVirtualScrollConfig(config) {
|
|
1434
|
+
if (typeof process !== "undefined" && process.env?.NODE_ENV === "production") return;
|
|
1435
|
+
if (config.enabled !== true) return;
|
|
1436
|
+
if (!config.rowHeight || config.rowHeight <= 0) {
|
|
1437
|
+
console.warn(
|
|
1438
|
+
"[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."
|
|
1439
|
+
);
|
|
1344
1440
|
}
|
|
1345
1441
|
}
|
|
1346
1442
|
function validateRowIds(items, getRowId) {
|
|
1347
1443
|
if (typeof process !== "undefined" && process.env.NODE_ENV === "production") return;
|
|
1444
|
+
if (!getRowId) return;
|
|
1348
1445
|
const ids = /* @__PURE__ */ new Set();
|
|
1349
1446
|
const limit = Math.min(items.length, 100);
|
|
1350
1447
|
for (let i = 0; i < limit; i++) {
|
|
@@ -1366,16 +1463,44 @@ var DEFAULT_DEBOUNCE_MS = 300;
|
|
|
1366
1463
|
var PEOPLE_SEARCH_DEBOUNCE_MS = DEFAULT_DEBOUNCE_MS;
|
|
1367
1464
|
var SIDEBAR_TRANSITION_MS = 300;
|
|
1368
1465
|
var Z_INDEX = {
|
|
1466
|
+
/** Column resize drag handle */
|
|
1467
|
+
RESIZE_HANDLE: 1,
|
|
1468
|
+
/** Active/editing cell outline */
|
|
1469
|
+
ACTIVE_CELL: 2,
|
|
1470
|
+
/** Fill handle dot */
|
|
1471
|
+
FILL_HANDLE: 3,
|
|
1369
1472
|
/** Selection range overlay (marching ants) */
|
|
1370
1473
|
SELECTION_OVERLAY: 4,
|
|
1474
|
+
/** Row number column */
|
|
1475
|
+
ROW_NUMBER: 5,
|
|
1371
1476
|
/** Clipboard overlay (copy/cut animation) */
|
|
1372
1477
|
CLIPBOARD_OVERLAY: 5,
|
|
1478
|
+
/** Sticky pinned body cells */
|
|
1479
|
+
PINNED: 6,
|
|
1480
|
+
/** Selection checkbox column in body */
|
|
1481
|
+
SELECTION_CELL: 7,
|
|
1482
|
+
/** Sticky thead row */
|
|
1483
|
+
THEAD: 8,
|
|
1484
|
+
/** Pinned header cells (sticky both axes) */
|
|
1485
|
+
PINNED_HEADER: 10,
|
|
1486
|
+
/** Focused header cell */
|
|
1487
|
+
HEADER_FOCUS: 11,
|
|
1488
|
+
/** Checkbox column in sticky header (sticky both axes) */
|
|
1489
|
+
SELECTION_HEADER_PINNED: 12,
|
|
1490
|
+
/** Loading overlay within table */
|
|
1491
|
+
LOADING: 2,
|
|
1492
|
+
/** Column reorder drop indicator */
|
|
1493
|
+
DROP_INDICATOR: 100,
|
|
1373
1494
|
/** Dropdown menus (column chooser, pagination size select) */
|
|
1374
1495
|
DROPDOWN: 1e3,
|
|
1496
|
+
/** Filter popovers */
|
|
1497
|
+
FILTER_POPOVER: 1e3,
|
|
1375
1498
|
/** Modal dialogs */
|
|
1376
1499
|
MODAL: 2e3,
|
|
1500
|
+
/** Fullscreen grid container */
|
|
1501
|
+
FULLSCREEN: 9999,
|
|
1377
1502
|
/** Context menus (right-click grid menu) */
|
|
1378
|
-
CONTEXT_MENU:
|
|
1503
|
+
CONTEXT_MENU: 1e4
|
|
1379
1504
|
};
|
|
1380
1505
|
|
|
1381
1506
|
// src/utils/getCellCoordinates.ts
|
|
@@ -1908,18 +2033,18 @@ var TableRenderer = class {
|
|
|
1908
2033
|
this.container.innerHTML = "";
|
|
1909
2034
|
const wrapper = document.createElement("div");
|
|
1910
2035
|
wrapper.className = "ogrid-wrapper";
|
|
1911
|
-
wrapper.setAttribute("role", "
|
|
2036
|
+
wrapper.setAttribute("role", "region");
|
|
1912
2037
|
wrapper.setAttribute("tabindex", "0");
|
|
1913
2038
|
wrapper.style.position = "relative";
|
|
1914
2039
|
if (this.state.rowHeight) {
|
|
1915
2040
|
wrapper.style.setProperty("--ogrid-row-height", `${this.state.rowHeight}px`);
|
|
1916
2041
|
}
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
}
|
|
2042
|
+
const label = this.state.ariaLabel ?? "Data grid";
|
|
2043
|
+
wrapper.setAttribute("aria-label", label);
|
|
1920
2044
|
this.wrapperEl = wrapper;
|
|
1921
2045
|
this.table = document.createElement("table");
|
|
1922
2046
|
this.table.className = "ogrid-table";
|
|
2047
|
+
this.table.setAttribute("role", "grid");
|
|
1923
2048
|
this.thead = document.createElement("thead");
|
|
1924
2049
|
if (this.state.stickyHeader) {
|
|
1925
2050
|
this.thead.classList.add("ogrid-sticky-header");
|
|
@@ -2174,6 +2299,11 @@ var TableRenderer = class {
|
|
|
2174
2299
|
}
|
|
2175
2300
|
if (!cell.isGroup && cell.columnDef) {
|
|
2176
2301
|
th.setAttribute("data-column-id", cell.columnDef.columnId);
|
|
2302
|
+
th.setAttribute("scope", "col");
|
|
2303
|
+
const groupSort = this.state.sort;
|
|
2304
|
+
if (groupSort?.field === cell.columnDef.columnId) {
|
|
2305
|
+
th.setAttribute("aria-sort", groupSort.direction === "asc" ? "ascending" : "descending");
|
|
2306
|
+
}
|
|
2177
2307
|
this.applyPinningStyles(th, cell.columnDef.columnId, true);
|
|
2178
2308
|
}
|
|
2179
2309
|
tr.appendChild(th);
|
|
@@ -2202,6 +2332,11 @@ var TableRenderer = class {
|
|
|
2202
2332
|
const th = document.createElement("th");
|
|
2203
2333
|
th.className = "ogrid-header-cell";
|
|
2204
2334
|
th.setAttribute("data-column-id", col.columnId);
|
|
2335
|
+
th.setAttribute("scope", "col");
|
|
2336
|
+
const sort = this.state.sort;
|
|
2337
|
+
if (sort?.field === col.columnId) {
|
|
2338
|
+
th.setAttribute("aria-sort", sort.direction === "asc" ? "ascending" : "descending");
|
|
2339
|
+
}
|
|
2205
2340
|
const textSpan = document.createElement("span");
|
|
2206
2341
|
textSpan.textContent = col.name;
|
|
2207
2342
|
th.appendChild(textSpan);
|
|
@@ -2232,6 +2367,8 @@ var TableRenderer = class {
|
|
|
2232
2367
|
const filterBtn = document.createElement("button");
|
|
2233
2368
|
filterBtn.className = "ogrid-filter-icon";
|
|
2234
2369
|
filterBtn.setAttribute("aria-label", `Filter ${col.name}`);
|
|
2370
|
+
filterBtn.setAttribute("aria-expanded", "false");
|
|
2371
|
+
filterBtn.setAttribute("aria-haspopup", "dialog");
|
|
2235
2372
|
filterBtn.style.border = "none";
|
|
2236
2373
|
filterBtn.style.background = "transparent";
|
|
2237
2374
|
filterBtn.style.cursor = "pointer";
|
|
@@ -2322,6 +2459,7 @@ var TableRenderer = class {
|
|
|
2322
2459
|
const isRowSelected = this.interactionState?.selectedRowIds?.has(rowId) === true;
|
|
2323
2460
|
if (isRowSelected) {
|
|
2324
2461
|
tr.setAttribute("data-row-selected", "true");
|
|
2462
|
+
tr.setAttribute("aria-selected", "true");
|
|
2325
2463
|
}
|
|
2326
2464
|
if (hasCheckbox) {
|
|
2327
2465
|
const td = document.createElement("td");
|
|
@@ -3755,6 +3893,7 @@ var ColumnPinningState = class {
|
|
|
3755
3893
|
// src/state/VirtualScrollState.ts
|
|
3756
3894
|
var DEFAULT_ROW_HEIGHT = 36;
|
|
3757
3895
|
var DEFAULT_OVERSCAN = 5;
|
|
3896
|
+
var DEFAULT_PASSTHROUGH_THRESHOLD = 100;
|
|
3758
3897
|
var VirtualScrollState = class {
|
|
3759
3898
|
constructor(config) {
|
|
3760
3899
|
this.emitter = new EventEmitter();
|
|
@@ -3765,10 +3904,12 @@ var VirtualScrollState = class {
|
|
|
3765
3904
|
this._ro = null;
|
|
3766
3905
|
this._cachedRange = { startIndex: 0, endIndex: -1, offsetTop: 0, offsetBottom: 0 };
|
|
3767
3906
|
this._config = config ?? { enabled: false };
|
|
3907
|
+
validateVirtualScrollConfig(this._config);
|
|
3768
3908
|
}
|
|
3769
|
-
/** Whether virtual scrolling is active. */
|
|
3909
|
+
/** Whether virtual scrolling is active (enabled + meets the row threshold). */
|
|
3770
3910
|
get enabled() {
|
|
3771
|
-
|
|
3911
|
+
const threshold = this._config.threshold ?? DEFAULT_PASSTHROUGH_THRESHOLD;
|
|
3912
|
+
return this._config.enabled === true && this._totalRows >= threshold;
|
|
3772
3913
|
}
|
|
3773
3914
|
get config() {
|
|
3774
3915
|
return this._config;
|
|
@@ -3809,6 +3950,7 @@ var VirtualScrollState = class {
|
|
|
3809
3950
|
}
|
|
3810
3951
|
/** Update the virtual scroll configuration. */
|
|
3811
3952
|
updateConfig(config) {
|
|
3953
|
+
validateVirtualScrollConfig(config);
|
|
3812
3954
|
this._config = config;
|
|
3813
3955
|
this.recompute();
|
|
3814
3956
|
this.emitter.emit("configChanged", { config });
|
|
@@ -3982,7 +4124,11 @@ var KeyboardNavState = class {
|
|
|
3982
4124
|
constructor(params, getActiveCell, getSelectionRange, setActiveCell, setSelectionRange) {
|
|
3983
4125
|
this.wrapperRef = null;
|
|
3984
4126
|
this.handleKeyDown = (e) => {
|
|
3985
|
-
const { items, visibleCols, colOffset, editable, onCellValueChanged, onCopy, onCut, onPaste, onUndo, onRedo, onContextMenu, onStartEdit, getRowId, clearClipboardRanges } = this.params;
|
|
4127
|
+
const { items, visibleCols, colOffset, editable, onCellValueChanged, onCopy, onCut, onPaste, onUndo, onRedo, onContextMenu, onStartEdit, getRowId, clearClipboardRanges, onKeyDown, onFillDown } = this.params;
|
|
4128
|
+
if (onKeyDown) {
|
|
4129
|
+
onKeyDown(e);
|
|
4130
|
+
if (e.defaultPrevented) return;
|
|
4131
|
+
}
|
|
3986
4132
|
const activeCell = this.getActiveCell();
|
|
3987
4133
|
const selectionRange = this.getSelectionRange();
|
|
3988
4134
|
const maxRowIndex = items.length - 1;
|
|
@@ -4022,6 +4168,14 @@ var KeyboardNavState = class {
|
|
|
4022
4168
|
void onPaste?.();
|
|
4023
4169
|
}
|
|
4024
4170
|
break;
|
|
4171
|
+
case "d":
|
|
4172
|
+
if (e.ctrlKey || e.metaKey) {
|
|
4173
|
+
if (editable !== false && onFillDown) {
|
|
4174
|
+
e.preventDefault();
|
|
4175
|
+
onFillDown();
|
|
4176
|
+
}
|
|
4177
|
+
}
|
|
4178
|
+
break;
|
|
4025
4179
|
case "ArrowDown":
|
|
4026
4180
|
case "ArrowUp":
|
|
4027
4181
|
case "ArrowRight":
|
|
@@ -4433,6 +4587,13 @@ var FillHandleState = class {
|
|
|
4433
4587
|
updateParams(params) {
|
|
4434
4588
|
this.params = params;
|
|
4435
4589
|
}
|
|
4590
|
+
/** Fill the current selection down from the top row (keyboard Ctrl+D). No-op if no selection or editable=false. */
|
|
4591
|
+
fillDown() {
|
|
4592
|
+
const range = this.getSelectionRange();
|
|
4593
|
+
if (!range || this.params.editable === false || !this.params.onCellValueChanged) return;
|
|
4594
|
+
const norm = normalizeSelectionRange(range);
|
|
4595
|
+
this.applyFillValuesFromCore(norm, { startRow: norm.startRow, startCol: norm.startCol });
|
|
4596
|
+
}
|
|
4436
4597
|
/** Called when the fill handle square is mousedown'd. */
|
|
4437
4598
|
startFillDrag(e) {
|
|
4438
4599
|
e.preventDefault();
|
|
@@ -5706,7 +5867,9 @@ var OGridRendering = class {
|
|
|
5706
5867
|
onRedo: () => undoRedoState?.redo(),
|
|
5707
5868
|
onContextMenu: (x, y) => this.ctx.showContextMenu(x, y),
|
|
5708
5869
|
onStartEdit: (rowId, columnId) => this.ctx.startCellEdit(rowId, columnId),
|
|
5709
|
-
clearClipboardRanges: () => clipboardState?.clearClipboardRanges()
|
|
5870
|
+
clearClipboardRanges: () => clipboardState?.clearClipboardRanges(),
|
|
5871
|
+
onKeyDown: options.onKeyDown,
|
|
5872
|
+
onFillDown: fillHandleState ? () => fillHandleState.fillDown() : void 0
|
|
5710
5873
|
});
|
|
5711
5874
|
clipboardState.updateParams({
|
|
5712
5875
|
items,
|
|
@@ -5738,6 +5901,11 @@ var OGridRendering = class {
|
|
|
5738
5901
|
renderHeaderFilterPopover() {
|
|
5739
5902
|
const { headerFilterState, headerFilterComponent, filterConfigs } = this.ctx;
|
|
5740
5903
|
const openId = headerFilterState.openColumnId;
|
|
5904
|
+
const allBtns = this.ctx.tableContainer.querySelectorAll(".ogrid-filter-icon[aria-haspopup]");
|
|
5905
|
+
for (const btn of allBtns) {
|
|
5906
|
+
const colId = btn.closest("th[data-column-id]")?.getAttribute("data-column-id");
|
|
5907
|
+
btn.setAttribute("aria-expanded", colId === openId ? "true" : "false");
|
|
5908
|
+
}
|
|
5741
5909
|
if (!openId) {
|
|
5742
5910
|
headerFilterComponent.cleanup();
|
|
5743
5911
|
return;
|
|
@@ -6372,4 +6540,4 @@ var OGrid = class {
|
|
|
6372
6540
|
}
|
|
6373
6541
|
};
|
|
6374
6542
|
|
|
6375
|
-
export { AUTOSIZE_EXTRA_PX, AUTOSIZE_MAX_PX, CELL_PADDING, CHECKBOX_COLUMN_WIDTH, COLUMN_HEADER_MENU_ITEMS, ClipboardState, ColumnChooser, ColumnPinningState, ColumnReorderState, ColumnResizeState, ContextMenu, DEFAULT_DEBOUNCE_MS, DEFAULT_MIN_COLUMN_WIDTH, EventEmitter, FillHandleState, GRID_BORDER_RADIUS, GRID_CONTEXT_MENU_ITEMS, GridState, HeaderFilter, HeaderFilterState, InlineCellEditor, KeyboardNavState, MAX_PAGE_BUTTONS, MarchingAntsOverlay, OGrid, OGridEventWiring, OGridRendering, PAGE_SIZE_OPTIONS, PEOPLE_SEARCH_DEBOUNCE_MS, PaginationControls, ROW_NUMBER_COLUMN_WIDTH, RowSelectionState, SIDEBAR_TRANSITION_MS, SelectionState, SideBar, SideBarState, StatusBar, TableLayoutState, TableRenderer, UndoRedoStack, UndoRedoState, VirtualScrollState, 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 };
|
|
6543
|
+
export { AUTOSIZE_EXTRA_PX, AUTOSIZE_MAX_PX, CELL_PADDING, CHECKBOX_COLUMN_WIDTH, COLUMN_HEADER_MENU_ITEMS, CellDescriptorCache, ClipboardState, ColumnChooser, ColumnPinningState, ColumnReorderState, ColumnResizeState, ContextMenu, DEFAULT_DEBOUNCE_MS, DEFAULT_MIN_COLUMN_WIDTH, EventEmitter, FillHandleState, GRID_BORDER_RADIUS, GRID_CONTEXT_MENU_ITEMS, GridState, HeaderFilter, HeaderFilterState, InlineCellEditor, KeyboardNavState, MAX_PAGE_BUTTONS, MarchingAntsOverlay, OGrid, OGridEventWiring, OGridRendering, PAGE_SIZE_OPTIONS, PEOPLE_SEARCH_DEBOUNCE_MS, PaginationControls, ROW_NUMBER_COLUMN_WIDTH, RowSelectionState, SIDEBAR_TRANSITION_MS, SelectionState, SideBar, SideBarState, StatusBar, TableLayoutState, TableRenderer, UndoRedoStack, UndoRedoState, VirtualScrollState, 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 };
|
package/dist/styles/ogrid.css
CHANGED
|
@@ -6,6 +6,13 @@
|
|
|
6
6
|
|
|
7
7
|
/* ── Light Theme (default) — :where() for zero specificity ── */
|
|
8
8
|
:where(:root) {
|
|
9
|
+
/* Cell padding — override for row density:
|
|
10
|
+
--ogrid-cell-padding : shorthand (default 6px 10px)
|
|
11
|
+
--ogrid-cell-padding-vertical : vertical only (default 6px)
|
|
12
|
+
--ogrid-cell-padding-horizontal: horizontal only (default 10px) */
|
|
13
|
+
--ogrid-cell-padding: 6px 10px;
|
|
14
|
+
--ogrid-cell-padding-vertical: 6px;
|
|
15
|
+
--ogrid-cell-padding-horizontal: 10px;
|
|
9
16
|
--ogrid-bg: #ffffff;
|
|
10
17
|
--ogrid-fg: rgba(0, 0, 0, 0.87);
|
|
11
18
|
--ogrid-fg-secondary: rgba(0, 0, 0, 0.6);
|
|
@@ -132,7 +139,7 @@
|
|
|
132
139
|
.ogrid-container.ogrid-fullscreen {
|
|
133
140
|
position: fixed;
|
|
134
141
|
inset: 0;
|
|
135
|
-
z-index: 9999;
|
|
142
|
+
z-index: var(--ogrid-z-fullscreen, 9999);
|
|
136
143
|
border-radius: 0;
|
|
137
144
|
border: none;
|
|
138
145
|
}
|
|
@@ -224,7 +231,7 @@
|
|
|
224
231
|
|
|
225
232
|
.ogrid-table thead {
|
|
226
233
|
background: var(--ogrid-bg-subtle, #f3f2f1);
|
|
227
|
-
z-index: 8;
|
|
234
|
+
z-index: var(--ogrid-z-thead, 8);
|
|
228
235
|
}
|
|
229
236
|
|
|
230
237
|
.ogrid-table thead.ogrid-sticky-header {
|
|
@@ -270,7 +277,7 @@
|
|
|
270
277
|
width: 8px;
|
|
271
278
|
cursor: col-resize;
|
|
272
279
|
user-select: none;
|
|
273
|
-
z-index: 1;
|
|
280
|
+
z-index: var(--ogrid-z-resize-handle, 1);
|
|
274
281
|
}
|
|
275
282
|
|
|
276
283
|
.ogrid-resize-handle::after {
|
|
@@ -316,7 +323,7 @@
|
|
|
316
323
|
/* ── Body Rows ── */
|
|
317
324
|
|
|
318
325
|
.ogrid-table tbody td {
|
|
319
|
-
padding: 6px 10px;
|
|
326
|
+
padding: var(--ogrid-cell-padding, 6px 10px);
|
|
320
327
|
background: var(--ogrid-bg, #ffffff);
|
|
321
328
|
border-bottom: 1px solid var(--ogrid-border, #e8e8e8);
|
|
322
329
|
position: relative;
|
|
@@ -345,12 +352,15 @@
|
|
|
345
352
|
background: var(--ogrid-bg-selected-hover, #dae8f8);
|
|
346
353
|
}
|
|
347
354
|
|
|
348
|
-
.ogrid-checkbox-header,
|
|
349
|
-
.ogrid-
|
|
355
|
+
/* Element-type selector (th.ogrid-checkbox-header, td.ogrid-checkbox-cell) has specificity
|
|
356
|
+
0,1,1 which beats the generic .ogrid-table tbody td (0,1,2) — wait, 0,1,1 < 0,1,2.
|
|
357
|
+
Qualify with .ogrid-table to reach 0,2,1, beating the base td padding rule (0,1,2). */
|
|
358
|
+
.ogrid-table th.ogrid-checkbox-header,
|
|
359
|
+
.ogrid-table td.ogrid-checkbox-cell {
|
|
350
360
|
width: 48px;
|
|
351
361
|
min-width: 48px;
|
|
352
362
|
max-width: 48px;
|
|
353
|
-
padding: 4px
|
|
363
|
+
padding: 4px;
|
|
354
364
|
text-align: center;
|
|
355
365
|
}
|
|
356
366
|
|
|
@@ -367,20 +377,22 @@
|
|
|
367
377
|
.ogrid-cell[data-active-cell='true'] {
|
|
368
378
|
outline: 2px solid var(--ogrid-selection, #217346);
|
|
369
379
|
outline-offset: -1px;
|
|
370
|
-
z-index: 2;
|
|
380
|
+
z-index: var(--ogrid-z-active-cell, 2);
|
|
371
381
|
position: relative;
|
|
372
382
|
}
|
|
373
383
|
|
|
374
|
-
.ogrid-
|
|
375
|
-
|
|
384
|
+
/* Cell range/drag highlights: qualify with .ogrid-container to reach specificity 0,3,0,
|
|
385
|
+
beating row-hover rules (.ogrid-table tbody tr:hover td = 0,2,3). */
|
|
386
|
+
.ogrid-container .ogrid-cell[data-in-range='true'] {
|
|
387
|
+
background: var(--ogrid-bg-range, rgba(33, 115, 70, 0.12));
|
|
376
388
|
}
|
|
377
389
|
|
|
378
|
-
[data-drag-range] {
|
|
379
|
-
background: var(--ogrid-bg-range, rgba(33, 115, 70, 0.12))
|
|
390
|
+
.ogrid-container [data-drag-range] {
|
|
391
|
+
background: var(--ogrid-bg-range, rgba(33, 115, 70, 0.12));
|
|
380
392
|
}
|
|
381
393
|
|
|
382
|
-
[data-drag-anchor] {
|
|
383
|
-
background: var(--ogrid-bg, #fff)
|
|
394
|
+
.ogrid-container [data-drag-anchor] {
|
|
395
|
+
background: var(--ogrid-bg, #fff);
|
|
384
396
|
}
|
|
385
397
|
|
|
386
398
|
/* ── Fill Handle ── */
|
|
@@ -396,7 +408,7 @@
|
|
|
396
408
|
border-radius: 1px;
|
|
397
409
|
cursor: crosshair;
|
|
398
410
|
pointer-events: auto;
|
|
399
|
-
z-index: 3;
|
|
411
|
+
z-index: var(--ogrid-z-fill-handle, 3);
|
|
400
412
|
}
|
|
401
413
|
|
|
402
414
|
/* ── Pinned Columns ── */
|
|
@@ -404,7 +416,7 @@
|
|
|
404
416
|
.ogrid-table th[data-pinned='left'],
|
|
405
417
|
.ogrid-table td[data-pinned='left'] {
|
|
406
418
|
position: sticky;
|
|
407
|
-
z-index: 6;
|
|
419
|
+
z-index: var(--ogrid-z-pinned, 6);
|
|
408
420
|
background: var(--ogrid-bg, #fff);
|
|
409
421
|
will-change: transform;
|
|
410
422
|
border-right: 1px solid var(--ogrid-border, rgba(0, 0, 0, 0.12));
|
|
@@ -413,13 +425,13 @@
|
|
|
413
425
|
|
|
414
426
|
.ogrid-table thead th[data-pinned='left'] {
|
|
415
427
|
background: var(--ogrid-bg-subtle, #f3f2f1);
|
|
416
|
-
z-index:
|
|
428
|
+
z-index: var(--ogrid-z-pinned-header, 10);
|
|
417
429
|
}
|
|
418
430
|
|
|
419
431
|
.ogrid-table th[data-pinned='right'],
|
|
420
432
|
.ogrid-table td[data-pinned='right'] {
|
|
421
433
|
position: sticky;
|
|
422
|
-
z-index: 6;
|
|
434
|
+
z-index: var(--ogrid-z-pinned, 6);
|
|
423
435
|
background: var(--ogrid-bg, #fff);
|
|
424
436
|
will-change: transform;
|
|
425
437
|
border-left: 1px solid var(--ogrid-border, rgba(0, 0, 0, 0.12));
|
|
@@ -428,7 +440,7 @@
|
|
|
428
440
|
|
|
429
441
|
.ogrid-table thead th[data-pinned='right'] {
|
|
430
442
|
background: var(--ogrid-bg-subtle, #f3f2f1);
|
|
431
|
-
z-index:
|
|
443
|
+
z-index: var(--ogrid-z-pinned-header, 10);
|
|
432
444
|
}
|
|
433
445
|
|
|
434
446
|
/* ── Empty State ── */
|
|
@@ -445,7 +457,7 @@
|
|
|
445
457
|
.ogrid-loading-overlay {
|
|
446
458
|
position: absolute;
|
|
447
459
|
inset: 0;
|
|
448
|
-
z-index: 100;
|
|
460
|
+
z-index: var(--ogrid-z-drop-indicator, 100);
|
|
449
461
|
display: flex;
|
|
450
462
|
align-items: center;
|
|
451
463
|
justify-content: center;
|
|
@@ -589,10 +601,20 @@
|
|
|
589
601
|
cursor: not-allowed;
|
|
590
602
|
}
|
|
591
603
|
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
604
|
+
/* Active pagination button: compound selector (0,2,0) beats base (0,1,0).
|
|
605
|
+
The :hover rule (.ogrid-pagination-btn:hover:not(:disabled), 0,3,0) still wins on hover,
|
|
606
|
+
but that is the correct UX — hovered active page shows hover style. */
|
|
607
|
+
.ogrid-pagination-btn.ogrid-pagination-active {
|
|
608
|
+
background: var(--ogrid-primary, #217346);
|
|
609
|
+
border-color: var(--ogrid-primary, #217346);
|
|
610
|
+
color: var(--ogrid-primary-fg, #fff);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
/* Keep active state even when hovered */
|
|
614
|
+
.ogrid-pagination-btn.ogrid-pagination-active:hover:not(:disabled) {
|
|
615
|
+
background: var(--ogrid-primary, #217346);
|
|
616
|
+
border-color: var(--ogrid-primary, #217346);
|
|
617
|
+
color: var(--ogrid-primary-fg, #fff);
|
|
596
618
|
}
|
|
597
619
|
|
|
598
620
|
.ogrid-pagination-ellipsis {
|
|
@@ -797,7 +819,7 @@
|
|
|
797
819
|
|
|
798
820
|
.ogrid-header-filter-popover {
|
|
799
821
|
position: fixed;
|
|
800
|
-
z-index: 1000;
|
|
822
|
+
z-index: var(--ogrid-z-filter-popover, 1000);
|
|
801
823
|
min-width: 280px;
|
|
802
824
|
max-width: 320px;
|
|
803
825
|
background: var(--ogrid-bg, #fff);
|
|
@@ -909,7 +931,7 @@
|
|
|
909
931
|
|
|
910
932
|
.ogrid-context-menu {
|
|
911
933
|
position: fixed;
|
|
912
|
-
z-index: 10000;
|
|
934
|
+
z-index: var(--ogrid-z-context-menu, 10000);
|
|
913
935
|
min-width: 160px;
|
|
914
936
|
padding: 4px 0;
|
|
915
937
|
background: var(--ogrid-bg, #fff);
|
|
@@ -952,7 +974,7 @@
|
|
|
952
974
|
|
|
953
975
|
.ogrid-cell-editor {
|
|
954
976
|
position: absolute;
|
|
955
|
-
z-index:
|
|
977
|
+
z-index: var(--ogrid-z-filter-popover, 1000);
|
|
956
978
|
background: var(--ogrid-bg, #fff);
|
|
957
979
|
border: 2px solid var(--ogrid-selection, #217346);
|
|
958
980
|
border-radius: 0;
|
|
@@ -982,7 +1004,7 @@
|
|
|
982
1004
|
width: 3px;
|
|
983
1005
|
background: var(--ogrid-primary, #217346);
|
|
984
1006
|
pointer-events: none;
|
|
985
|
-
z-index: 100;
|
|
1007
|
+
z-index: var(--ogrid-z-drop-indicator, 100);
|
|
986
1008
|
transition: left 0.05s;
|
|
987
1009
|
}
|
|
988
1010
|
|
|
@@ -996,9 +1018,11 @@
|
|
|
996
1018
|
|
|
997
1019
|
/* ── Virtual Scrolling ── */
|
|
998
1020
|
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1021
|
+
/* Virtual spacer: element+class selector (0,1,1) beats plain td rules (0,0,1).
|
|
1022
|
+
But .ogrid-table tbody td (0,1,2) has higher specificity so we qualify with the table. */
|
|
1023
|
+
.ogrid-table .ogrid-virtual-spacer td {
|
|
1024
|
+
padding: 0;
|
|
1025
|
+
border: none;
|
|
1002
1026
|
line-height: 0;
|
|
1003
1027
|
}
|
|
1004
1028
|
|
|
@@ -38,6 +38,8 @@ export declare class FillHandleState<T> {
|
|
|
38
38
|
get fillRange(): ISelectionRange | null;
|
|
39
39
|
setWrapperRef(ref: HTMLElement | null): void;
|
|
40
40
|
updateParams(params: FillHandleParams<T>): void;
|
|
41
|
+
/** Fill the current selection down from the top row (keyboard Ctrl+D). No-op if no selection or editable=false. */
|
|
42
|
+
fillDown(): void;
|
|
41
43
|
/** Called when the fill handle square is mousedown'd. */
|
|
42
44
|
startFillDrag(e: MouseEvent): void;
|
|
43
45
|
private onMouseMove;
|
|
@@ -14,6 +14,10 @@ export interface KeyboardNavParams<T> {
|
|
|
14
14
|
onContextMenu?: (x: number, y: number) => void;
|
|
15
15
|
onStartEdit?: (rowId: RowId, columnId: string) => void;
|
|
16
16
|
clearClipboardRanges?: () => void;
|
|
17
|
+
/** Custom keydown handler. Called before grid default. preventDefault() suppresses grid handling. */
|
|
18
|
+
onKeyDown?: (event: KeyboardEvent) => void;
|
|
19
|
+
/** Fill-down callback (Ctrl+D). Provided by FillHandleState. */
|
|
20
|
+
onFillDown?: () => void;
|
|
17
21
|
}
|
|
18
22
|
export declare class KeyboardNavState<T> {
|
|
19
23
|
private params;
|
|
@@ -21,7 +21,7 @@ export declare class VirtualScrollState {
|
|
|
21
21
|
private _ro;
|
|
22
22
|
private _cachedRange;
|
|
23
23
|
constructor(config?: IVirtualScrollConfig);
|
|
24
|
-
/** Whether virtual scrolling is active. */
|
|
24
|
+
/** Whether virtual scrolling is active (enabled + meets the row threshold). */
|
|
25
25
|
get enabled(): boolean;
|
|
26
26
|
get config(): IVirtualScrollConfig;
|
|
27
27
|
get containerHeight(): number;
|
|
@@ -122,6 +122,8 @@ export interface OGridOptions<T> {
|
|
|
122
122
|
columnChooser?: boolean | 'toolbar' | 'sidebar';
|
|
123
123
|
/** Secondary toolbar row rendered below the primary toolbar. */
|
|
124
124
|
toolbarBelow?: HTMLElement | null;
|
|
125
|
+
/** Custom keydown handler. Called before grid's built-in handling. Call event.preventDefault() to suppress grid default. */
|
|
126
|
+
onKeyDown?: (event: KeyboardEvent) => void;
|
|
125
127
|
}
|
|
126
128
|
/** Events emitted by the OGrid instance. */
|
|
127
129
|
export interface OGridEvents<T> extends Record<string, unknown> {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alaarab/ogrid-js",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.12",
|
|
4
4
|
"description": "OGrid vanilla JS – framework-free data grid with sorting, filtering, pagination, and spreadsheet-style editing.",
|
|
5
5
|
"main": "dist/esm/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"node": ">=18"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@alaarab/ogrid-core": "2.1.
|
|
39
|
+
"@alaarab/ogrid-core": "2.1.12"
|
|
40
40
|
},
|
|
41
41
|
"sideEffects": [
|
|
42
42
|
"**/*.css"
|