@alaarab/ogrid-js 2.0.9 → 2.0.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/OGrid.js CHANGED
@@ -50,6 +50,7 @@ export class OGrid {
50
50
  this.contextMenu = null;
51
51
  this.events = new EventEmitter();
52
52
  this.unsubscribes = [];
53
+ this.layoutVersion = 0; // Incremented when items, columns, sizing, or order change
53
54
  this.options = options;
54
55
  this.state = new GridState(options);
55
56
  this.api = this.state.getApi();
@@ -384,7 +385,7 @@ export class OGrid {
384
385
  });
385
386
  this.renderer.update();
386
387
  // Update marching ants overlay
387
- this.marchingAnts?.update(this.selectionState.selectionRange, this.clipboardState.copyRange, this.clipboardState.cutRange);
388
+ this.marchingAnts?.update(this.selectionState.selectionRange, this.clipboardState.copyRange, this.clipboardState.cutRange, this.layoutVersion);
388
389
  }
389
390
  updateDragAttributes() {
390
391
  const wrapper = this.renderer.getWrapperElement();
@@ -658,6 +659,8 @@ export class OGrid {
658
659
  }
659
660
  }
660
661
  renderAll() {
662
+ // Increment layout version to trigger marching ants re-measurement
663
+ this.layoutVersion++;
661
664
  const colOffset = this.rowSelectionState ? 1 : 0;
662
665
  // Update header filter state with current filters and options
663
666
  this.headerFilterState.setFilters(this.state.filters);
@@ -1,31 +1,18 @@
1
- /** Inject the @keyframes rule once into <head> (deduplicates across multiple instances). */
2
- function ensureKeyframes() {
3
- if (typeof document === 'undefined')
4
- return;
5
- if (document.getElementById('ogrid-marching-ants-keyframes'))
6
- return;
7
- const style = document.createElement('style');
8
- style.id = 'ogrid-marching-ants-keyframes';
9
- style.textContent =
10
- '@keyframes ogrid-marching-ants{to{stroke-dashoffset:-8}}';
11
- document.head.appendChild(style);
12
- }
13
- /** Measure the bounding rect of a range within a container. */
1
+ import { injectGlobalStyles, measureRange as measureRangeCore } from '@alaarab/ogrid-core';
2
+ /**
3
+ * Measure the bounding rect of a range within a container, with scroll offsets.
4
+ * This variant adds scroll offsets for the JS implementation's scrollable container.
5
+ */
14
6
  function measureRange(container, range, colOffset) {
15
- const startGlobalCol = range.startCol + colOffset;
16
- const endGlobalCol = range.endCol + colOffset;
17
- const topLeft = container.querySelector(`[data-row-index="${range.startRow}"][data-col-index="${startGlobalCol}"]`);
18
- const bottomRight = container.querySelector(`[data-row-index="${range.endRow}"][data-col-index="${endGlobalCol}"]`);
19
- if (!topLeft || !bottomRight)
7
+ const rect = measureRangeCore(container, range, colOffset);
8
+ if (!rect)
20
9
  return null;
21
- const cRect = container.getBoundingClientRect();
22
- const tlRect = topLeft.getBoundingClientRect();
23
- const brRect = bottomRight.getBoundingClientRect();
10
+ // Add scroll offsets for JS implementation's scrollable container
24
11
  return {
25
- top: tlRect.top - cRect.top + container.scrollTop,
26
- left: tlRect.left - cRect.left + container.scrollLeft,
27
- width: brRect.right - tlRect.left,
28
- height: brRect.bottom - tlRect.top,
12
+ top: rect.top + container.scrollTop,
13
+ left: rect.left + container.scrollLeft,
14
+ width: rect.width,
15
+ height: rect.height,
29
16
  };
30
17
  }
31
18
  function rangesEqual(a, b) {
@@ -51,18 +38,25 @@ export class MarchingAntsOverlay {
51
38
  this.copyRange = null;
52
39
  this.cutRange = null;
53
40
  this.rafHandle = 0;
41
+ this.layoutVersion = 0; // Tracks layout changes to force re-measurement
54
42
  this.container = container;
55
43
  this.colOffset = colOffset;
56
- ensureKeyframes();
44
+ injectGlobalStyles('ogrid-marching-ants-keyframes', '@keyframes ogrid-marching-ants{to{stroke-dashoffset:-8}}');
57
45
  // The container must be positioned for absolute SVGs
58
46
  const pos = getComputedStyle(container).position;
59
47
  if (pos === 'static' || pos === '') {
60
48
  container.style.position = 'relative';
61
49
  }
62
50
  }
63
- update(selectionRange, copyRange, cutRange) {
64
- // Skip if nothing changed
65
- if (rangesEqual(this.selectionRange, selectionRange) &&
51
+ update(selectionRange, copyRange, cutRange, layoutVersion) {
52
+ // Track layout changes separately from range changes
53
+ const layoutChanged = layoutVersion !== undefined && layoutVersion !== this.layoutVersion;
54
+ if (layoutChanged && layoutVersion !== undefined) {
55
+ this.layoutVersion = layoutVersion;
56
+ }
57
+ // Skip if nothing changed (ranges or layout)
58
+ if (!layoutChanged &&
59
+ rangesEqual(this.selectionRange, selectionRange) &&
66
60
  rangesEqual(this.copyRange, copyRange) &&
67
61
  rangesEqual(this.cutRange, cutRange)) {
68
62
  return;
@@ -35,6 +35,7 @@ export declare class OGrid<T> {
35
35
  private paginationContainer;
36
36
  private statusBarContainer;
37
37
  private options;
38
+ private layoutVersion;
38
39
  /** The imperative grid API (extends React's IOGridApi with JS-specific methods). */
39
40
  readonly api: IJsOGridApi<T>;
40
41
  constructor(container: HTMLElement, options: OGridOptions<T>);
@@ -1,4 +1,4 @@
1
- import type { ISelectionRange } from '@alaarab/ogrid-core';
1
+ import { type ISelectionRange } from '@alaarab/ogrid-core';
2
2
  /**
3
3
  * MarchingAntsOverlay — renders SVG overlays on top of the grid:
4
4
  * 1. Selection range: solid green border
@@ -15,8 +15,9 @@ export declare class MarchingAntsOverlay {
15
15
  private copyRange;
16
16
  private cutRange;
17
17
  private rafHandle;
18
+ private layoutVersion;
18
19
  constructor(container: HTMLElement, colOffset?: number);
19
- update(selectionRange: ISelectionRange | null, copyRange: ISelectionRange | null, cutRange: ISelectionRange | null): void;
20
+ update(selectionRange: ISelectionRange | null, copyRange: ISelectionRange | null, cutRange: ISelectionRange | null, layoutVersion?: number): void;
20
21
  private render;
21
22
  private createSvg;
22
23
  private positionSvg;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alaarab/ogrid-js",
3
- "version": "2.0.9",
3
+ "version": "2.0.11",
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.0.9"
39
+ "@alaarab/ogrid-core": "2.0.11"
40
40
  },
41
41
  "sideEffects": false,
42
42
  "publishConfig": {