@alaarab/ogrid-js 2.1.14 → 2.1.15

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 CHANGED
@@ -502,23 +502,39 @@ function processClientSideData(data, columns, filters, sortBy, sortDirection) {
502
502
  const trimmed = val.value.trim();
503
503
  if (trimmed) {
504
504
  const lower = trimmed.toLowerCase();
505
- predicates.push((r) => String(getCellValue(r, col) ?? "").toLowerCase().includes(lower));
505
+ const textCache = /* @__PURE__ */ new Map();
506
+ for (let j = 0; j < data.length; j++) {
507
+ textCache.set(data[j], String(getCellValue(data[j], col) ?? "").toLowerCase());
508
+ }
509
+ predicates.push((r) => (textCache.get(r) ?? "").includes(lower));
506
510
  }
507
511
  break;
508
512
  }
509
513
  case "people": {
510
514
  const email = val.value.email.toLowerCase();
511
- predicates.push((r) => String(getCellValue(r, col) ?? "").toLowerCase() === email);
515
+ const peopleCache = /* @__PURE__ */ new Map();
516
+ for (let j = 0; j < data.length; j++) {
517
+ peopleCache.set(data[j], String(getCellValue(data[j], col) ?? "").toLowerCase());
518
+ }
519
+ predicates.push((r) => (peopleCache.get(r) ?? "") === email);
512
520
  break;
513
521
  }
514
522
  case "date": {
515
523
  const dv = val.value;
516
524
  const fromTs = dv.from ? (/* @__PURE__ */ new Date(dv.from + "T00:00:00")).getTime() : NaN;
517
525
  const toTs = dv.to ? (/* @__PURE__ */ new Date(dv.to + "T23:59:59.999")).getTime() : NaN;
526
+ const dateCache = /* @__PURE__ */ new Map();
527
+ for (let j = 0; j < data.length; j++) {
528
+ const cellVal = getCellValue(data[j], col);
529
+ if (cellVal == null) {
530
+ dateCache.set(data[j], NaN);
531
+ } else {
532
+ const t = new Date(String(cellVal)).getTime();
533
+ dateCache.set(data[j], Number.isNaN(t) ? NaN : t);
534
+ }
535
+ }
518
536
  predicates.push((r) => {
519
- const cellVal = getCellValue(r, col);
520
- if (cellVal == null) return false;
521
- const cellTs = new Date(String(cellVal)).getTime();
537
+ const cellTs = dateCache.get(r) ?? NaN;
522
538
  if (Number.isNaN(cellTs)) return false;
523
539
  if (!Number.isNaN(fromTs) && cellTs < fromTs) return false;
524
540
  if (!Number.isNaN(toTs) && cellTs > toTs) return false;
@@ -1261,7 +1277,7 @@ function computeRowSelectionState(selectedIds, items, getRowId) {
1261
1277
  if (selectedIds.size === 0 || items.length === 0) {
1262
1278
  return { allSelected: false, someSelected: false };
1263
1279
  }
1264
- const allSelected = items.every((item) => selectedIds.has(getRowId(item)));
1280
+ const allSelected = selectedIds.size >= items.length && items.every((item) => selectedIds.has(getRowId(item)));
1265
1281
  const someSelected = !allSelected && selectedIds.size > 0;
1266
1282
  return { allSelected, someSelected };
1267
1283
  }
@@ -1958,6 +1974,17 @@ var GridState = class {
1958
1974
  };
1959
1975
 
1960
1976
  // src/renderer/TableRenderer.ts
1977
+ function rangeBounds(r) {
1978
+ return {
1979
+ minR: Math.min(r.startRow, r.endRow),
1980
+ maxR: Math.max(r.startRow, r.endRow),
1981
+ minC: Math.min(r.startCol, r.endCol),
1982
+ maxC: Math.max(r.startCol, r.endCol)
1983
+ };
1984
+ }
1985
+ function inBounds(b, row, col) {
1986
+ return row >= b.minR && row <= b.maxR && col >= b.minC && col <= b.maxC;
1987
+ }
1961
1988
  var TableRenderer = class {
1962
1989
  constructor(container, state) {
1963
1990
  this.table = null;
@@ -2227,6 +2254,13 @@ var TableRenderer = class {
2227
2254
  const lastSelection = this.lastSelectionRange;
2228
2255
  const lastCopy = this.lastCopyRange;
2229
2256
  const lastCut = this.lastCutRange;
2257
+ const selBounds = selectionRange ? rangeBounds(selectionRange) : null;
2258
+ const lastSelBounds = lastSelection ? rangeBounds(lastSelection) : null;
2259
+ const copyBounds = copyRange ? rangeBounds(copyRange) : null;
2260
+ const lastCopyBounds = lastCopy ? rangeBounds(lastCopy) : null;
2261
+ const cutBounds = cutRange ? rangeBounds(cutRange) : null;
2262
+ const lastCutBounds = lastCut ? rangeBounds(lastCut) : null;
2263
+ const colOffset = this.getColOffset();
2230
2264
  const cells = this.tbody.querySelectorAll("td[data-row-index][data-col-index]");
2231
2265
  for (let i = 0; i < cells.length; i++) {
2232
2266
  const el = cells[i];
@@ -2234,7 +2268,6 @@ var TableRenderer = class {
2234
2268
  if (!coords) continue;
2235
2269
  const rowIndex = coords.rowIndex;
2236
2270
  const globalColIndex = coords.colIndex;
2237
- const colOffset = this.getColOffset();
2238
2271
  const colIndex = globalColIndex - colOffset;
2239
2272
  const wasActive = lastActive && lastActive.rowIndex === rowIndex && lastActive.columnIndex === globalColIndex;
2240
2273
  const isActive = activeCell && activeCell.rowIndex === rowIndex && activeCell.columnIndex === globalColIndex;
@@ -2245,28 +2278,30 @@ var TableRenderer = class {
2245
2278
  el.setAttribute("data-active-cell", "true");
2246
2279
  el.style.outline = "2px solid var(--ogrid-accent, #0078d4)";
2247
2280
  }
2248
- const wasInRange = lastSelection && isInSelectionRange(lastSelection, rowIndex, colIndex);
2249
- const isInRange = selectionRange && isInSelectionRange(selectionRange, rowIndex, colIndex);
2250
- if (wasInRange && !isInRange) {
2281
+ const wasInRange = lastSelBounds && inBounds(lastSelBounds, rowIndex, colIndex);
2282
+ const isInRange = selBounds && inBounds(selBounds, rowIndex, colIndex);
2283
+ const showRange = isInRange && !isActive;
2284
+ const showedRange = wasInRange && !(lastActive && lastActive.rowIndex === rowIndex && lastActive.columnIndex === globalColIndex);
2285
+ if (showedRange && !showRange) {
2251
2286
  el.removeAttribute("data-in-range");
2252
2287
  el.style.backgroundColor = "";
2253
- } else if (isInRange && !wasInRange) {
2288
+ } else if (showRange && !showedRange) {
2254
2289
  el.setAttribute("data-in-range", "true");
2255
2290
  el.style.backgroundColor = "var(--ogrid-range-bg, rgba(33, 115, 70, 0.12))";
2256
2291
  }
2257
- const wasInCopy = lastCopy && isInSelectionRange(lastCopy, rowIndex, colIndex);
2258
- const isInCopy = copyRange && isInSelectionRange(copyRange, rowIndex, colIndex);
2292
+ const wasInCopy = lastCopyBounds && inBounds(lastCopyBounds, rowIndex, colIndex);
2293
+ const isInCopy = copyBounds && inBounds(copyBounds, rowIndex, colIndex);
2259
2294
  if (wasInCopy && !isInCopy) {
2260
- if (!isActive && !(cutRange && isInSelectionRange(cutRange, rowIndex, colIndex))) {
2295
+ if (!isActive && !(cutBounds && inBounds(cutBounds, rowIndex, colIndex))) {
2261
2296
  el.style.outline = "";
2262
2297
  }
2263
2298
  } else if (isInCopy && !wasInCopy) {
2264
2299
  el.style.outline = "1px dashed var(--ogrid-fg-muted, rgba(0, 0, 0, 0.5))";
2265
2300
  }
2266
- const wasInCut = lastCut && isInSelectionRange(lastCut, rowIndex, colIndex);
2267
- const isInCut = cutRange && isInSelectionRange(cutRange, rowIndex, colIndex);
2301
+ const wasInCut = lastCutBounds && inBounds(lastCutBounds, rowIndex, colIndex);
2302
+ const isInCut = cutBounds && inBounds(cutBounds, rowIndex, colIndex);
2268
2303
  if (wasInCut && !isInCut) {
2269
- if (!isActive && !(copyRange && isInSelectionRange(copyRange, rowIndex, colIndex))) {
2304
+ if (!isActive && !(copyBounds && inBounds(copyBounds, rowIndex, colIndex))) {
2270
2305
  el.style.outline = "";
2271
2306
  }
2272
2307
  } else if (isInCut && !wasInCut) {
@@ -3989,6 +4024,7 @@ var VirtualScrollState = class {
3989
4024
  this._totalRows = 0;
3990
4025
  this.rafId = 0;
3991
4026
  this._ro = null;
4027
+ this._resizeRafId = 0;
3992
4028
  this._cachedRange = { startIndex: 0, endIndex: -1, offsetTop: 0, offsetBottom: 0 };
3993
4029
  this._config = config ?? { enabled: false };
3994
4030
  validateVirtualScrollConfig(this._config);
@@ -4052,11 +4088,13 @@ var VirtualScrollState = class {
4052
4088
  this.disconnectObserver();
4053
4089
  if (typeof ResizeObserver !== "undefined") {
4054
4090
  this._ro = new ResizeObserver((entries) => {
4055
- for (const entry of entries) {
4056
- const rect = entry.contentRect;
4057
- this._containerHeight = rect.height;
4091
+ if (entries.length === 0) return;
4092
+ this._containerHeight = entries[0].contentRect.height;
4093
+ if (this._resizeRafId) cancelAnimationFrame(this._resizeRafId);
4094
+ this._resizeRafId = requestAnimationFrame(() => {
4095
+ this._resizeRafId = 0;
4058
4096
  this.recompute();
4059
- }
4097
+ });
4060
4098
  });
4061
4099
  this._ro.observe(el);
4062
4100
  }
@@ -4098,6 +4136,7 @@ var VirtualScrollState = class {
4098
4136
  }
4099
4137
  destroy() {
4100
4138
  if (this.rafId) cancelAnimationFrame(this.rafId);
4139
+ if (this._resizeRafId) cancelAnimationFrame(this._resizeRafId);
4101
4140
  this.disconnectObserver();
4102
4141
  this.emitter.removeAllListeners();
4103
4142
  }
@@ -4744,7 +4783,7 @@ var FillHandleState = class {
4744
4783
  endCol: end.endCol
4745
4784
  });
4746
4785
  this.setSelectionRange(norm);
4747
- this.setActiveCell({ rowIndex: end.endRow, columnIndex: end.endCol + this.params.colOffset });
4786
+ this.setActiveCell({ rowIndex: start.startRow, columnIndex: start.startCol + this.params.colOffset });
4748
4787
  this.applyFillValuesFromCore(norm, start);
4749
4788
  this._isFillDragging = false;
4750
4789
  this.fillDragStart = null;
@@ -4996,7 +5035,8 @@ var MarchingAntsOverlay = class {
4996
5035
  const clipRange = this.copyRange ?? this.cutRange;
4997
5036
  const selRect = this.selectionRange ? measureRange2(this.container, this.selectionRange, this.colOffset) : null;
4998
5037
  const clipRangeMatchesSel = this.selectionRange != null && clipRange != null && rangesEqual(this.selectionRange, clipRange);
4999
- if (selRect && !clipRangeMatchesSel) {
5038
+ const isSingleCell = this.selectionRange != null && this.selectionRange.startRow === this.selectionRange.endRow && this.selectionRange.startCol === this.selectionRange.endCol;
5039
+ if (selRect && !clipRangeMatchesSel && !isSingleCell) {
5000
5040
  if (!this.selSvg) {
5001
5041
  this.selSvg = this.createSvg(4);
5002
5042
  this.container.appendChild(this.selSvg);
@@ -494,10 +494,11 @@
494
494
  padding: 6px 12px;
495
495
  box-sizing: border-box;
496
496
  font-size: 12px;
497
+ line-height: 20px;
497
498
  color: var(--ogrid-muted, #616161);
498
499
  background: var(--ogrid-bg-subtle, #f3f2f1);
499
500
  border-top: 1px solid var(--ogrid-border, #e0e0e0);
500
- min-height: 28px;
501
+ min-height: 33px;
501
502
  }
502
503
 
503
504
  .ogrid-status-part {
@@ -19,6 +19,7 @@ export declare class VirtualScrollState {
19
19
  private _totalRows;
20
20
  private rafId;
21
21
  private _ro;
22
+ private _resizeRafId;
22
23
  private _cachedRange;
23
24
  constructor(config?: IVirtualScrollConfig);
24
25
  /** Whether virtual scrolling is active (enabled + meets the row threshold). */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alaarab/ogrid-js",
3
- "version": "2.1.14",
3
+ "version": "2.1.15",
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.14"
39
+ "@alaarab/ogrid-core": "2.1.15"
40
40
  },
41
41
  "sideEffects": [
42
42
  "**/*.css"