@ornery/ui-grid-vanilla 0.1.7 → 0.1.8

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/demo/index.html CHANGED
@@ -52,6 +52,105 @@
52
52
  min-height: 640px;
53
53
  }
54
54
 
55
+ .grid-demo-shell {
56
+ display: grid;
57
+ gap: 1rem;
58
+ }
59
+
60
+ .grid-demo-header {
61
+ display: grid;
62
+ gap: 1rem;
63
+ }
64
+
65
+ .grid-demo-eyebrow {
66
+ margin: 0 0 0.35rem;
67
+ font-size: 0.75rem;
68
+ letter-spacing: 0.12em;
69
+ text-transform: uppercase;
70
+ color: #2a9d8f;
71
+ }
72
+
73
+ .grid-demo-header h2,
74
+ .grid-demo-header p,
75
+ .grid-demo-toolbar p {
76
+ margin: 0;
77
+ }
78
+
79
+ .grid-demo-actions {
80
+ display: flex;
81
+ flex-wrap: wrap;
82
+ gap: 0.75rem;
83
+ align-items: center;
84
+ }
85
+
86
+ .grid-demo-button {
87
+ border: 1px solid rgba(20, 33, 61, 0.12);
88
+ border-radius: 999px;
89
+ background: linear-gradient(135deg, #143a52, #1b5f7a);
90
+ color: #f7f3eb;
91
+ padding: 0.75rem 1.2rem;
92
+ cursor: pointer;
93
+ font: inherit;
94
+ font-weight: 700;
95
+ box-shadow: 0 12px 24px rgba(20, 33, 61, 0.12);
96
+ }
97
+
98
+ .grid-demo-button-secondary {
99
+ background: rgba(255, 255, 255, 0.9);
100
+ color: #14213d;
101
+ box-shadow: none;
102
+ }
103
+
104
+ .grid-demo-stats,
105
+ .grid-demo-metrics article,
106
+ .grid-demo-toolbar {
107
+ border: 1px solid rgba(20, 33, 61, 0.12);
108
+ border-radius: 1rem;
109
+ background: rgba(255, 255, 255, 0.82);
110
+ }
111
+
112
+ .grid-demo-stats {
113
+ display: grid;
114
+ min-width: 7rem;
115
+ padding: 0.8rem 1rem;
116
+ }
117
+
118
+ .grid-demo-stats span {
119
+ font-size: 1.9rem;
120
+ font-weight: 800;
121
+ line-height: 1;
122
+ }
123
+
124
+ .grid-demo-stats small,
125
+ .grid-demo-metrics span,
126
+ .grid-demo-toolbar,
127
+ .grid-demo-header p {
128
+ color: color-mix(in srgb, #14213d 72%, #2a9d8f 28%);
129
+ }
130
+
131
+ .grid-demo-metrics {
132
+ display: grid;
133
+ gap: 0.85rem;
134
+ grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
135
+ }
136
+
137
+ .grid-demo-metrics article {
138
+ display: grid;
139
+ gap: 0.2rem;
140
+ padding: 0.9rem 1rem;
141
+ }
142
+
143
+ .grid-demo-metrics strong {
144
+ font-size: 1.45rem;
145
+ line-height: 1.1;
146
+ }
147
+
148
+ .grid-demo-toolbar {
149
+ display: grid;
150
+ gap: 0.4rem;
151
+ padding: 0.9rem 1rem;
152
+ }
153
+
55
154
  .shell {
56
155
  --ui-grid-surface: rgba(255, 255, 255, 0.88);
57
156
  --ui-grid-header-background: #143a52;
@@ -72,7 +171,52 @@
72
171
  It is the baseline integration target for future Rust-framework wrappers.
73
172
  </p>
74
173
  </section>
75
- <section id="app"></section>
174
+ <section class="grid-demo-shell">
175
+ <header class="grid-demo-header">
176
+ <div>
177
+ <p class="grid-demo-eyebrow">Vanilla package demo</p>
178
+ <h2>UI Grid Vanilla Demo</h2>
179
+ <p>
180
+ Familiar <code>gridOptions</code> and <code>onRegisterApi</code>, rebuilt as a
181
+ framework-neutral custom element with the Rust-backed pipeline, grouping, sorting,
182
+ filtering, and virtualization.
183
+ </p>
184
+ </div>
185
+ <div class="grid-demo-actions">
186
+ <button id="benchmark-button" type="button" class="grid-demo-button">Benchmark</button>
187
+ <button id="export-button" type="button" class="grid-demo-button grid-demo-button-secondary">Export CSV</button>
188
+ <div class="grid-demo-stats">
189
+ <span id="visible-rows-value">0</span>
190
+ <small>visible rows</small>
191
+ </div>
192
+ </div>
193
+ </header>
194
+
195
+ <section class="grid-demo-metrics" aria-label="Vanilla grid metrics">
196
+ <article>
197
+ <strong>On</strong>
198
+ <span>virtualization</span>
199
+ </article>
200
+ <article>
201
+ <strong>1</strong>
202
+ <span>group columns</span>
203
+ </article>
204
+ <article>
205
+ <strong id="benchmark-avg-value">—</strong>
206
+ <span>benchmark avg</span>
207
+ </article>
208
+ </section>
209
+
210
+ <div class="grid-demo-toolbar">
211
+ <div><strong id="visible-rows-inline">0</strong> of <span id="total-rows-value">0</span> rows</div>
212
+ <p>
213
+ <code>gridOptions</code> compatibility layer: sorting, filtering, grouping, templating,
214
+ and virtualized rendering.
215
+ </p>
216
+ </div>
217
+
218
+ <section id="app"></section>
219
+ </section>
76
220
  </main>
77
221
  <script type="module" src="./main.ts"></script>
78
222
  </body>
package/demo/main.ts CHANGED
@@ -1,12 +1,13 @@
1
1
  import { mountVanillaUiGrid } from '../src/index';
2
- import type { GridOptions } from '../src/index';
2
+ import type { GridOptions, UiGridApi } from '../src/index';
3
+ import type { GridBenchmarkResult } from '@ornery/ui-grid-core';
3
4
  import * as uiGridRustWebModule from '../../../dist/ui-grid-wasm-web/ui_grid_wasm.js';
4
5
 
5
6
  const statuses = ['Active', 'Expansion', 'Enterprise', 'Pilot'] as const;
6
7
  const companies = ['Northwind', 'Blue Harbor', 'Forge Group', 'Larkspur', 'Atlas'] as const;
7
8
  const owners = ['Casey Tran', 'Jordan Silva', 'Priya Rao', 'Evan Brooks', 'Mina Patel'] as const;
8
9
 
9
- function createDemoData(count = 5000) {
10
+ function createDemoData(count = 100_000) {
10
11
  return Array.from({ length: count }, (_, i) => ({
11
12
  id: `row-${i + 1}`,
12
13
  name: `Customer ${i + 1}`,
@@ -30,6 +31,19 @@ const options: GridOptions = {
30
31
  enableVirtualization: true,
31
32
  virtualizationThreshold: 25,
32
33
  grouping: { groupBy: ['status'] },
34
+ benchmark: { iterations: 40 },
35
+ onRegisterApi: (api) => {
36
+ gridApi = api as UiGridApi;
37
+ syncVisibleRows();
38
+ unsubscribeVisibleRows?.();
39
+ unsubscribeBenchmark?.();
40
+ unsubscribeVisibleRows = gridApi.core.on.rowsVisibleChanged((rows) => {
41
+ updateVisibleRows(rows.length);
42
+ });
43
+ unsubscribeBenchmark = gridApi.core.on.benchmarkComplete((result) => {
44
+ updateBenchmark(result as GridBenchmarkResult);
45
+ });
46
+ },
33
47
  columnDefs: [
34
48
  { name: 'name', displayName: 'Customer', width: 'minmax(14rem, 1.2fr)' },
35
49
  { name: 'company', width: 'minmax(12rem, 1fr)' },
@@ -57,11 +71,48 @@ const options: GridOptions = {
57
71
  };
58
72
 
59
73
  const mountPoint = document.getElementById('app');
74
+ const visibleRowsValue = document.getElementById('visible-rows-value');
75
+ const visibleRowsInline = document.getElementById('visible-rows-inline');
76
+ const totalRowsValue = document.getElementById('total-rows-value');
77
+ const benchmarkAvgValue = document.getElementById('benchmark-avg-value');
78
+ const benchmarkButton = document.getElementById('benchmark-button') as HTMLButtonElement | null;
79
+ const exportButton = document.getElementById('export-button') as HTMLButtonElement | null;
80
+
81
+ let gridApi: UiGridApi | null = null;
82
+ let unsubscribeVisibleRows: (() => void) | null = null;
83
+ let unsubscribeBenchmark: (() => void) | null = null;
84
+
85
+ function updateVisibleRows(count: number) {
86
+ if (visibleRowsValue) visibleRowsValue.textContent = String(count);
87
+ if (visibleRowsInline) visibleRowsInline.textContent = String(count);
88
+ }
89
+
90
+ function updateBenchmark(result: GridBenchmarkResult | null) {
91
+ if (benchmarkAvgValue) {
92
+ benchmarkAvgValue.textContent = result?.averageMs?.toFixed(2) ?? '—';
93
+ }
94
+ }
95
+
96
+ function syncVisibleRows() {
97
+ updateVisibleRows(gridApi?.core.getVisibleRows().length ?? 0);
98
+ }
60
99
 
61
100
  if (!mountPoint) {
62
101
  throw new Error('Expected vanilla demo mount point');
63
102
  }
64
103
 
104
+ if (totalRowsValue) {
105
+ totalRowsValue.textContent = String(options.data.length);
106
+ }
107
+
108
+ benchmarkButton?.addEventListener('click', () => {
109
+ gridApi?.core.benchmark();
110
+ });
111
+
112
+ exportButton?.addEventListener('click', () => {
113
+ gridApi?.core.exportCsv();
114
+ });
115
+
65
116
  void mountVanillaUiGrid(mountPoint, options, uiGridRustWebModule).catch((error) => {
66
117
  console.error(error);
67
118
  mountPoint.textContent = error instanceof Error ? error.message : String(error);
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { GridOptions, GridLabels, GridColumnDef, PipelineResult, SortState, PinnedColumnState, GridCellPosition, UiGridApi, DisplayItem, SortDirection, PinDirection, GridRow, GridRecord, GroupItem, BuildGridPipelineContext } from '@ornery/ui-grid-core';
1
+ import { GridOptions, GridLabels, GridColumnDef, PipelineResult, SortState, PinnedColumnState, GridCellPosition, UiGridApi, GridRecord, DisplayItem, SortDirection, PinDirection, GridRow, GroupItem, BuildGridPipelineContext } from '@ornery/ui-grid-core';
2
2
  export { GridOptions, UiGridApi } from '@ornery/ui-grid-core';
3
3
 
4
4
  interface GridSaveState {
@@ -53,6 +53,12 @@ declare class VanillaGridController {
53
53
  readonly gridApi: UiGridApi;
54
54
  constructor(options: GridOptions);
55
55
  setOptions(options: GridOptions): void;
56
+ /**
57
+ * Fast-path: swap only the row data and rebuild the pipeline without
58
+ * touching column state. Emits the new snapshot. The element uses this to
59
+ * patch cell content in-place without rebuilding the full shadow DOM.
60
+ */
61
+ refreshData(data: readonly GridRecord[]): void;
56
62
  subscribe(subscriber: GridControllerSubscriber): () => void;
57
63
  getSnapshot(): GridControllerSnapshot;
58
64
  getDisplayItems(): DisplayItem[];
@@ -136,6 +142,12 @@ type VanillaUiGridElement = HTMLElement & {
136
142
  options: GridOptions;
137
143
  getState(): GridSaveState | null;
138
144
  setState(state: Partial<GridSaveState>): void;
145
+ /**
146
+ * Fast-path data update: patches only visible cell content in the existing
147
+ * shadow DOM. Does NOT rebuild the scroll container or header, so scrolling
148
+ * remains completely smooth while data ticks in the background.
149
+ */
150
+ setData(rows: GridRecord[]): void;
139
151
  };
140
152
  type UiGridControlIconKey = 'sortNone' | 'sortAsc' | 'sortDesc' | 'group' | 'groupExpanded' | 'groupCollapsed' | 'treeExpanded' | 'treeCollapsed' | 'expandExpanded' | 'expandCollapsed' | 'pin' | 'pinLeft' | 'pinRight' | 'paginationPrev' | 'paginationNext';
141
153
  interface UiGridIconDefinition {
@@ -148,6 +160,8 @@ declare class UiGridStandaloneElement extends HTMLElement {
148
160
  private snapshot;
149
161
  private unsubscribe;
150
162
  private activeOptions;
163
+ private attributeOptions;
164
+ private attributeSyncScheduled;
151
165
  private iconOverrides;
152
166
  private templateObserver;
153
167
  private openPinMenuColumn;
@@ -162,12 +176,104 @@ declare class UiGridStandaloneElement extends HTMLElement {
162
176
  private measuredFilterStickyHeight;
163
177
  private stickyHeightRelayoutQueued;
164
178
  private benchmarkAverage;
179
+ private skipNextRender;
180
+ private dataFrame;
181
+ static get observedAttributes(): string[];
165
182
  get options(): GridOptions;
166
183
  set options(value: GridOptions);
184
+ attributeChangedCallback(_name: string, _oldValue: string | null, _newValue: string | null): void;
185
+ private syncAttributesToOptions;
186
+ private parseBooleanAttribute;
187
+ private parseNumberAttribute;
188
+ private parseJsonAttribute;
167
189
  get controlIcons(): UiGridIconOverrides;
168
190
  set controlIcons(value: UiGridIconOverrides);
191
+ get gridId(): string;
192
+ set gridId(value: string);
193
+ get title(): string;
194
+ set title(value: string);
195
+ get rowHeight(): number;
196
+ set rowHeight(value: number);
197
+ get headerRowHeight(): number;
198
+ set headerRowHeight(value: number);
199
+ get viewportHeight(): number;
200
+ set viewportHeight(value: number);
201
+ get paginationPageSize(): number;
202
+ set paginationPageSize(value: number);
203
+ get paginationCurrentPage(): number;
204
+ set paginationCurrentPage(value: number);
205
+ get totalItems(): number | undefined;
206
+ set totalItems(value: number | undefined);
207
+ get virtualizationThreshold(): number;
208
+ set virtualizationThreshold(value: number);
209
+ get treeChildrenField(): string;
210
+ set treeChildrenField(value: string);
211
+ get treeIndent(): number;
212
+ set treeIndent(value: number);
213
+ get expandableRowHeight(): number;
214
+ set expandableRowHeight(value: number);
215
+ get expandableRowHeaderWidth(): number;
216
+ set expandableRowHeaderWidth(value: number);
217
+ get emptyMessage(): string;
218
+ set emptyMessage(value: string);
219
+ get infiniteScrollRowsFromEnd(): number;
220
+ set infiniteScrollRowsFromEnd(value: number);
221
+ get columnDefs(): readonly GridColumnDef[];
222
+ set columnDefs(value: readonly GridColumnDef[]);
223
+ get data(): readonly GridRecord[];
224
+ set data(value: readonly GridRecord[]);
225
+ get enableSorting(): boolean;
226
+ set enableSorting(value: boolean);
227
+ get enableFiltering(): boolean;
228
+ set enableFiltering(value: boolean);
229
+ get enableGrouping(): boolean;
230
+ set enableGrouping(value: boolean);
231
+ get enablePinning(): boolean;
232
+ set enablePinning(value: boolean);
233
+ get enableColumnMoving(): boolean;
234
+ set enableColumnMoving(value: boolean);
235
+ get enableCellEdit(): boolean;
236
+ set enableCellEdit(value: boolean);
237
+ get enableCellEditOnFocus(): boolean;
238
+ set enableCellEditOnFocus(value: boolean);
239
+ get enablePagination(): boolean;
240
+ set enablePagination(value: boolean);
241
+ get enablePaginationControls(): boolean;
242
+ set enablePaginationControls(value: boolean);
243
+ get useExternalPagination(): boolean;
244
+ set useExternalPagination(value: boolean);
245
+ get enableExpandable(): boolean;
246
+ set enableExpandable(value: boolean);
247
+ get enableTreeView(): boolean;
248
+ set enableTreeView(value: boolean);
249
+ get showTreeExpandNoChildren(): boolean;
250
+ set showTreeExpandNoChildren(value: boolean);
251
+ get treeRowHeaderAlwaysVisible(): boolean;
252
+ set treeRowHeaderAlwaysVisible(value: boolean);
253
+ get enableAutoResize(): boolean;
254
+ set enableAutoResize(value: boolean);
255
+ get enableVirtualization(): boolean;
256
+ set enableVirtualization(value: boolean);
257
+ get infiniteScrollUp(): boolean;
258
+ set infiniteScrollUp(value: boolean);
259
+ get infiniteScrollDown(): boolean;
260
+ set infiniteScrollDown(value: boolean);
261
+ get grouping(): unknown;
262
+ set grouping(value: unknown);
263
+ get paginationPageSizes(): number[] | null | undefined;
264
+ set paginationPageSizes(value: number[] | null | undefined);
169
265
  getState(): GridSaveState | null;
170
266
  setState(state: Partial<GridSaveState>): void;
267
+ /**
268
+ * Fast-path: update only row data without rebuilding the shadow DOM.
269
+ * The pipeline is updated synchronously; DOM patching is deferred to the
270
+ * next animation frame so it never interrupts an in-progress scroll paint.
271
+ * If multiple ticks arrive before the frame fires, only the latest wins.
272
+ * If a scroll-triggered full render fires first, the frame is cancelled
273
+ * (the fresh innerHTML already reflects the latest data).
274
+ */
275
+ setData(rows: GridRecord[]): void;
276
+ private patchCells;
171
277
  connectedCallback(): void;
172
278
  disconnectedCallback(): void;
173
279
  private ensureShadowRoot;
@@ -175,6 +281,13 @@ declare class UiGridStandaloneElement extends HTMLElement {
175
281
  private observeTemplateSlots;
176
282
  private buildEffectiveOptions;
177
283
  private bindEvents;
284
+ /**
285
+ * Targeted update for virtual scroll: replaces only the rendered rows inside
286
+ * the existing `.grid-virtual-body` without touching the scroll container.
287
+ * This preserves momentum/inertia scrolling because the `.grid-table` element
288
+ * is never destroyed.
289
+ */
290
+ private renderVirtualBody;
178
291
  private render;
179
292
  private renderHeaderCell;
180
293
  private renderFilterCell;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { GridOptions, GridLabels, GridColumnDef, PipelineResult, SortState, PinnedColumnState, GridCellPosition, UiGridApi, DisplayItem, SortDirection, PinDirection, GridRow, GridRecord, GroupItem, BuildGridPipelineContext } from '@ornery/ui-grid-core';
1
+ import { GridOptions, GridLabels, GridColumnDef, PipelineResult, SortState, PinnedColumnState, GridCellPosition, UiGridApi, GridRecord, DisplayItem, SortDirection, PinDirection, GridRow, GroupItem, BuildGridPipelineContext } from '@ornery/ui-grid-core';
2
2
  export { GridOptions, UiGridApi } from '@ornery/ui-grid-core';
3
3
 
4
4
  interface GridSaveState {
@@ -53,6 +53,12 @@ declare class VanillaGridController {
53
53
  readonly gridApi: UiGridApi;
54
54
  constructor(options: GridOptions);
55
55
  setOptions(options: GridOptions): void;
56
+ /**
57
+ * Fast-path: swap only the row data and rebuild the pipeline without
58
+ * touching column state. Emits the new snapshot. The element uses this to
59
+ * patch cell content in-place without rebuilding the full shadow DOM.
60
+ */
61
+ refreshData(data: readonly GridRecord[]): void;
56
62
  subscribe(subscriber: GridControllerSubscriber): () => void;
57
63
  getSnapshot(): GridControllerSnapshot;
58
64
  getDisplayItems(): DisplayItem[];
@@ -136,6 +142,12 @@ type VanillaUiGridElement = HTMLElement & {
136
142
  options: GridOptions;
137
143
  getState(): GridSaveState | null;
138
144
  setState(state: Partial<GridSaveState>): void;
145
+ /**
146
+ * Fast-path data update: patches only visible cell content in the existing
147
+ * shadow DOM. Does NOT rebuild the scroll container or header, so scrolling
148
+ * remains completely smooth while data ticks in the background.
149
+ */
150
+ setData(rows: GridRecord[]): void;
139
151
  };
140
152
  type UiGridControlIconKey = 'sortNone' | 'sortAsc' | 'sortDesc' | 'group' | 'groupExpanded' | 'groupCollapsed' | 'treeExpanded' | 'treeCollapsed' | 'expandExpanded' | 'expandCollapsed' | 'pin' | 'pinLeft' | 'pinRight' | 'paginationPrev' | 'paginationNext';
141
153
  interface UiGridIconDefinition {
@@ -148,6 +160,8 @@ declare class UiGridStandaloneElement extends HTMLElement {
148
160
  private snapshot;
149
161
  private unsubscribe;
150
162
  private activeOptions;
163
+ private attributeOptions;
164
+ private attributeSyncScheduled;
151
165
  private iconOverrides;
152
166
  private templateObserver;
153
167
  private openPinMenuColumn;
@@ -162,12 +176,104 @@ declare class UiGridStandaloneElement extends HTMLElement {
162
176
  private measuredFilterStickyHeight;
163
177
  private stickyHeightRelayoutQueued;
164
178
  private benchmarkAverage;
179
+ private skipNextRender;
180
+ private dataFrame;
181
+ static get observedAttributes(): string[];
165
182
  get options(): GridOptions;
166
183
  set options(value: GridOptions);
184
+ attributeChangedCallback(_name: string, _oldValue: string | null, _newValue: string | null): void;
185
+ private syncAttributesToOptions;
186
+ private parseBooleanAttribute;
187
+ private parseNumberAttribute;
188
+ private parseJsonAttribute;
167
189
  get controlIcons(): UiGridIconOverrides;
168
190
  set controlIcons(value: UiGridIconOverrides);
191
+ get gridId(): string;
192
+ set gridId(value: string);
193
+ get title(): string;
194
+ set title(value: string);
195
+ get rowHeight(): number;
196
+ set rowHeight(value: number);
197
+ get headerRowHeight(): number;
198
+ set headerRowHeight(value: number);
199
+ get viewportHeight(): number;
200
+ set viewportHeight(value: number);
201
+ get paginationPageSize(): number;
202
+ set paginationPageSize(value: number);
203
+ get paginationCurrentPage(): number;
204
+ set paginationCurrentPage(value: number);
205
+ get totalItems(): number | undefined;
206
+ set totalItems(value: number | undefined);
207
+ get virtualizationThreshold(): number;
208
+ set virtualizationThreshold(value: number);
209
+ get treeChildrenField(): string;
210
+ set treeChildrenField(value: string);
211
+ get treeIndent(): number;
212
+ set treeIndent(value: number);
213
+ get expandableRowHeight(): number;
214
+ set expandableRowHeight(value: number);
215
+ get expandableRowHeaderWidth(): number;
216
+ set expandableRowHeaderWidth(value: number);
217
+ get emptyMessage(): string;
218
+ set emptyMessage(value: string);
219
+ get infiniteScrollRowsFromEnd(): number;
220
+ set infiniteScrollRowsFromEnd(value: number);
221
+ get columnDefs(): readonly GridColumnDef[];
222
+ set columnDefs(value: readonly GridColumnDef[]);
223
+ get data(): readonly GridRecord[];
224
+ set data(value: readonly GridRecord[]);
225
+ get enableSorting(): boolean;
226
+ set enableSorting(value: boolean);
227
+ get enableFiltering(): boolean;
228
+ set enableFiltering(value: boolean);
229
+ get enableGrouping(): boolean;
230
+ set enableGrouping(value: boolean);
231
+ get enablePinning(): boolean;
232
+ set enablePinning(value: boolean);
233
+ get enableColumnMoving(): boolean;
234
+ set enableColumnMoving(value: boolean);
235
+ get enableCellEdit(): boolean;
236
+ set enableCellEdit(value: boolean);
237
+ get enableCellEditOnFocus(): boolean;
238
+ set enableCellEditOnFocus(value: boolean);
239
+ get enablePagination(): boolean;
240
+ set enablePagination(value: boolean);
241
+ get enablePaginationControls(): boolean;
242
+ set enablePaginationControls(value: boolean);
243
+ get useExternalPagination(): boolean;
244
+ set useExternalPagination(value: boolean);
245
+ get enableExpandable(): boolean;
246
+ set enableExpandable(value: boolean);
247
+ get enableTreeView(): boolean;
248
+ set enableTreeView(value: boolean);
249
+ get showTreeExpandNoChildren(): boolean;
250
+ set showTreeExpandNoChildren(value: boolean);
251
+ get treeRowHeaderAlwaysVisible(): boolean;
252
+ set treeRowHeaderAlwaysVisible(value: boolean);
253
+ get enableAutoResize(): boolean;
254
+ set enableAutoResize(value: boolean);
255
+ get enableVirtualization(): boolean;
256
+ set enableVirtualization(value: boolean);
257
+ get infiniteScrollUp(): boolean;
258
+ set infiniteScrollUp(value: boolean);
259
+ get infiniteScrollDown(): boolean;
260
+ set infiniteScrollDown(value: boolean);
261
+ get grouping(): unknown;
262
+ set grouping(value: unknown);
263
+ get paginationPageSizes(): number[] | null | undefined;
264
+ set paginationPageSizes(value: number[] | null | undefined);
169
265
  getState(): GridSaveState | null;
170
266
  setState(state: Partial<GridSaveState>): void;
267
+ /**
268
+ * Fast-path: update only row data without rebuilding the shadow DOM.
269
+ * The pipeline is updated synchronously; DOM patching is deferred to the
270
+ * next animation frame so it never interrupts an in-progress scroll paint.
271
+ * If multiple ticks arrive before the frame fires, only the latest wins.
272
+ * If a scroll-triggered full render fires first, the frame is cancelled
273
+ * (the fresh innerHTML already reflects the latest data).
274
+ */
275
+ setData(rows: GridRecord[]): void;
276
+ private patchCells;
171
277
  connectedCallback(): void;
172
278
  disconnectedCallback(): void;
173
279
  private ensureShadowRoot;
@@ -175,6 +281,13 @@ declare class UiGridStandaloneElement extends HTMLElement {
175
281
  private observeTemplateSlots;
176
282
  private buildEffectiveOptions;
177
283
  private bindEvents;
284
+ /**
285
+ * Targeted update for virtual scroll: replaces only the rendered rows inside
286
+ * the existing `.grid-virtual-body` without touching the scroll container.
287
+ * This preserves momentum/inertia scrolling because the `.grid-table` element
288
+ * is never destroyed.
289
+ */
290
+ private renderVirtualBody;
178
291
  private render;
179
292
  private renderHeaderCell;
180
293
  private renderFilterCell;