@alaarab/ogrid-angular 2.1.14 → 2.2.0
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 +148 -11
- package/dist/types/components/base-datagrid-table.component.d.ts +28 -0
- package/dist/types/components/marching-ants-overlay.component.d.ts +1 -0
- package/dist/types/services/ogrid.service.d.ts +9 -0
- package/dist/types/services/virtual-scroll.service.d.ts +9 -1
- package/dist/types/types/dataGridTypes.d.ts +2 -0
- package/package.json +2 -2
package/dist/esm/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { flattenColumns, getMultiSelectFilterFields, deriveFilterOptionsFromData, processClientSideData, validateColumns, validateRowIds, computeNextSortState, mergeFilter, CHECKBOX_COLUMN_WIDTH, DEFAULT_MIN_COLUMN_WIDTH, CELL_PADDING, parseValue, UndoRedoStack, rangesEqual, normalizeSelectionRange, formatSelectionAsTsv, parseTsvClipboard, getCellValue, computeTabNavigation, applyFillValues, computeAggregations, getDataGridStatusBarConfig, computeVisibleRange, computeTotalHeight, getScrollTopForRow, validateVirtualScrollConfig, GRID_BORDER_RADIUS, getStatusBarParts, GRID_CONTEXT_MENU_ITEMS, formatShortcut, injectGlobalStyles, buildHeaderRows, getHeaderFilterConfig, getCellRenderDescriptor, resolveCellDisplayContent, resolveCellStyle, buildPopoverEditorProps, measureColumnContentWidth, getPaginationViewModel, ROW_NUMBER_COLUMN_WIDTH, reorderColumnArray, findCtrlArrowTarget, measureRange } from '@alaarab/ogrid-core';
|
|
1
|
+
import { flattenColumns, getMultiSelectFilterFields, deriveFilterOptionsFromData, processClientSideData, validateColumns, processClientSideDataAsync, validateRowIds, computeNextSortState, mergeFilter, CHECKBOX_COLUMN_WIDTH, DEFAULT_MIN_COLUMN_WIDTH, CELL_PADDING, parseValue, UndoRedoStack, rangesEqual, normalizeSelectionRange, formatSelectionAsTsv, parseTsvClipboard, getCellValue, computeTabNavigation, applyFillValues, computeAggregations, getDataGridStatusBarConfig, computeVisibleRange, computeTotalHeight, computeVisibleColumnRange, getScrollTopForRow, validateVirtualScrollConfig, GRID_BORDER_RADIUS, getStatusBarParts, GRID_CONTEXT_MENU_ITEMS, formatShortcut, injectGlobalStyles, partitionColumnsForVirtualization, buildHeaderRows, getHeaderFilterConfig, getCellRenderDescriptor, resolveCellDisplayContent, resolveCellStyle, buildPopoverEditorProps, measureColumnContentWidth, getPaginationViewModel, ROW_NUMBER_COLUMN_WIDTH, reorderColumnArray, findCtrlArrowTarget, measureRange } from '@alaarab/ogrid-core';
|
|
2
2
|
export * from '@alaarab/ogrid-core';
|
|
3
3
|
export { CELL_PADDING, CHECKBOX_COLUMN_WIDTH, DEFAULT_DEBOUNCE_MS, DEFAULT_MIN_COLUMN_WIDTH, GRID_BORDER_RADIUS, PEOPLE_SEARCH_DEBOUNCE_MS, ROW_NUMBER_COLUMN_WIDTH, SIDEBAR_TRANSITION_MS, Z_INDEX, debounce, getCellRenderDescriptor, getHeaderFilterConfig, isInSelectionRange, normalizeSelectionRange, resolveCellDisplayContent, resolveCellStyle, toUserLike } from '@alaarab/ogrid-core';
|
|
4
4
|
import { Injectable, Input, Component, ChangeDetectionStrategy, ViewEncapsulation, Output, ViewChild, inject, DestroyRef, signal, computed, effect, NgZone, EventEmitter, Injector, EnvironmentInjector, createComponent } from '@angular/core';
|
|
@@ -75,6 +75,7 @@ var OGridService = class {
|
|
|
75
75
|
this.virtualScroll = signal(void 0);
|
|
76
76
|
this.ariaLabel = signal(void 0);
|
|
77
77
|
this.ariaLabelledBy = signal(void 0);
|
|
78
|
+
this.workerSort = signal(false);
|
|
78
79
|
// --- Internal state signals ---
|
|
79
80
|
this.internalData = signal([]);
|
|
80
81
|
this.internalLoading = signal(false);
|
|
@@ -94,6 +95,9 @@ var OGridService = class {
|
|
|
94
95
|
this.filterAbortController = null;
|
|
95
96
|
this.refreshCounter = signal(0);
|
|
96
97
|
this.firstDataRendered = signal(false);
|
|
98
|
+
// Worker sort async state
|
|
99
|
+
this.asyncClientItems = signal(null);
|
|
100
|
+
this.workerSortAbortId = 0;
|
|
97
101
|
// Side bar state
|
|
98
102
|
this.sideBarActivePanel = signal(null);
|
|
99
103
|
// Filter options state
|
|
@@ -134,8 +138,9 @@ var OGridService = class {
|
|
|
134
138
|
if (this.hasServerFilterOptions()) return this.serverFilterOptions();
|
|
135
139
|
return deriveFilterOptionsFromData(this.displayData(), this.columns());
|
|
136
140
|
});
|
|
141
|
+
/** Sync path: used when workerSort is off. */
|
|
137
142
|
this.clientItemsAndTotal = computed(() => {
|
|
138
|
-
if (!this.isClientSide()) return null;
|
|
143
|
+
if (!this.isClientSide() || this.workerSort()) return null;
|
|
139
144
|
const rows = processClientSideData(
|
|
140
145
|
this.displayData(),
|
|
141
146
|
this.columns(),
|
|
@@ -148,12 +153,18 @@ var OGridService = class {
|
|
|
148
153
|
const paged = rows.slice(start, start + this.pageSize());
|
|
149
154
|
return { items: paged, totalCount: total };
|
|
150
155
|
});
|
|
156
|
+
/** Resolved client items — sync or async depending on workerSort. */
|
|
157
|
+
this.resolvedClientItems = computed(() => {
|
|
158
|
+
const syncResult = this.clientItemsAndTotal();
|
|
159
|
+
if (syncResult) return syncResult;
|
|
160
|
+
return this.asyncClientItems();
|
|
161
|
+
});
|
|
151
162
|
this.displayItems = computed(() => {
|
|
152
|
-
const cit = this.
|
|
163
|
+
const cit = this.resolvedClientItems();
|
|
153
164
|
return this.isClientSide() && cit ? cit.items : this.serverItems();
|
|
154
165
|
});
|
|
155
166
|
this.displayTotalCount = computed(() => {
|
|
156
|
-
const cit = this.
|
|
167
|
+
const cit = this.resolvedClientItems();
|
|
157
168
|
return this.isClientSide() && cit ? cit.totalCount : this.serverTotalCount();
|
|
158
169
|
});
|
|
159
170
|
this.hasActiveFilters = computed(() => {
|
|
@@ -323,6 +334,34 @@ var OGridService = class {
|
|
|
323
334
|
validateColumns(cols);
|
|
324
335
|
}
|
|
325
336
|
});
|
|
337
|
+
effect((onCleanup) => {
|
|
338
|
+
if (!this.isClientSide() || !this.workerSort()) return;
|
|
339
|
+
const data = this.displayData();
|
|
340
|
+
const cols = this.columns();
|
|
341
|
+
const filters = this.filters();
|
|
342
|
+
const sortField = this.sort().field;
|
|
343
|
+
const sortDir = this.sort().direction;
|
|
344
|
+
const page = this.page();
|
|
345
|
+
const ps = this.pageSize();
|
|
346
|
+
const abortId = ++this.workerSortAbortId;
|
|
347
|
+
processClientSideDataAsync(data, cols, filters, sortField, sortDir).then((rows) => {
|
|
348
|
+
if (abortId !== this.workerSortAbortId) return;
|
|
349
|
+
const total = rows.length;
|
|
350
|
+
const start = (page - 1) * ps;
|
|
351
|
+
const paged = rows.slice(start, start + ps);
|
|
352
|
+
this.asyncClientItems.set({ items: paged, totalCount: total });
|
|
353
|
+
}).catch(() => {
|
|
354
|
+
if (abortId !== this.workerSortAbortId) return;
|
|
355
|
+
const rows = processClientSideData(data, cols, filters, sortField, sortDir);
|
|
356
|
+
const total = rows.length;
|
|
357
|
+
const start = (page - 1) * ps;
|
|
358
|
+
const paged = rows.slice(start, start + ps);
|
|
359
|
+
this.asyncClientItems.set({ items: paged, totalCount: total });
|
|
360
|
+
});
|
|
361
|
+
onCleanup(() => {
|
|
362
|
+
this.workerSortAbortId++;
|
|
363
|
+
});
|
|
364
|
+
});
|
|
326
365
|
effect((onCleanup) => {
|
|
327
366
|
const ds = this.dataSource();
|
|
328
367
|
if (!this.isServerSide() || !ds) {
|
|
@@ -486,6 +525,13 @@ var OGridService = class {
|
|
|
486
525
|
// --- Configure from props ---
|
|
487
526
|
configure(props) {
|
|
488
527
|
this.columnsProp.set(props.columns);
|
|
528
|
+
if (Object.keys(this.pinnedOverrides()).length === 0) {
|
|
529
|
+
const initial = {};
|
|
530
|
+
for (const col of flattenColumns(props.columns)) {
|
|
531
|
+
if (col.pinned) initial[col.columnId] = col.pinned;
|
|
532
|
+
}
|
|
533
|
+
if (Object.keys(initial).length > 0) this.pinnedOverrides.set(initial);
|
|
534
|
+
}
|
|
489
535
|
this.getRowId.set(props.getRowId);
|
|
490
536
|
if ("data" in props && props.data !== void 0) this.data.set(props.data);
|
|
491
537
|
if ("dataSource" in props && props.dataSource !== void 0) this.dataSource.set(props.dataSource);
|
|
@@ -528,6 +574,7 @@ var OGridService = class {
|
|
|
528
574
|
if (props.columnChooser !== void 0) this.columnChooserProp.set(props.columnChooser);
|
|
529
575
|
if (props.columnReorder !== void 0) this.columnReorder.set(props.columnReorder);
|
|
530
576
|
if (props.virtualScroll !== void 0) this.virtualScroll.set(props.virtualScroll);
|
|
577
|
+
if (props.workerSort !== void 0) this.workerSort.set(props.workerSort);
|
|
531
578
|
if (props.entityLabelPlural !== void 0) this.entityLabelPlural.set(props.entityLabelPlural);
|
|
532
579
|
if (props.className !== void 0) this.className.set(props.className);
|
|
533
580
|
if (props.layoutMode !== void 0) this.layoutMode.set(props.layoutMode);
|
|
@@ -1371,10 +1418,13 @@ var DataGridInteractionHelper = class {
|
|
|
1371
1418
|
const finalRange = this.liveDragRange;
|
|
1372
1419
|
if (finalRange) {
|
|
1373
1420
|
this.setSelectionRange(finalRange);
|
|
1374
|
-
this.
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1421
|
+
const anchor = this.dragStartPos;
|
|
1422
|
+
if (anchor) {
|
|
1423
|
+
this.setActiveCell({
|
|
1424
|
+
rowIndex: anchor.row,
|
|
1425
|
+
columnIndex: anchor.col + colOffset
|
|
1426
|
+
});
|
|
1427
|
+
}
|
|
1378
1428
|
}
|
|
1379
1429
|
}
|
|
1380
1430
|
this.clearDragAttrs(wrapperEl);
|
|
@@ -1530,6 +1580,7 @@ var DataGridStateService = class {
|
|
|
1530
1580
|
const p = this.props();
|
|
1531
1581
|
if (!p || p.items.length === 0) return false;
|
|
1532
1582
|
const selected = this.selectedRowIds();
|
|
1583
|
+
if (selected.size !== p.items.length) return false;
|
|
1533
1584
|
return p.items.every((item) => selected.has(p.getRowId(item)));
|
|
1534
1585
|
});
|
|
1535
1586
|
this.someSelected = computed(() => {
|
|
@@ -2035,7 +2086,7 @@ var DataGridStateService = class {
|
|
|
2035
2086
|
endCol: fillDragEnd.endCol
|
|
2036
2087
|
});
|
|
2037
2088
|
this.setSelectionRange(norm);
|
|
2038
|
-
this.setActiveCell({ rowIndex:
|
|
2089
|
+
this.setActiveCell({ rowIndex: fillStart.startRow, columnIndex: fillStart.startCol + colOff });
|
|
2039
2090
|
if (!p) return;
|
|
2040
2091
|
const items = p.items;
|
|
2041
2092
|
const visibleCols = this.visibleCols();
|
|
@@ -2225,6 +2276,10 @@ var VirtualScrollService = class {
|
|
|
2225
2276
|
this.containerHeight = signal(0);
|
|
2226
2277
|
// --- Internal state ---
|
|
2227
2278
|
this.scrollTop = signal(0);
|
|
2279
|
+
this.scrollLeft = signal(0);
|
|
2280
|
+
// --- Column virtualization inputs ---
|
|
2281
|
+
this.columnWidths = signal([]);
|
|
2282
|
+
this.containerWidth = signal(0);
|
|
2228
2283
|
// Scrollable container reference for programmatic scrolling
|
|
2229
2284
|
this.containerEl = null;
|
|
2230
2285
|
// --- Derived computed signals ---
|
|
@@ -2254,6 +2309,21 @@ var VirtualScrollService = class {
|
|
|
2254
2309
|
});
|
|
2255
2310
|
/** Total scrollable height in pixels. */
|
|
2256
2311
|
this.totalHeight = computed(() => computeTotalHeight(this.totalRows(), this.rowHeight()));
|
|
2312
|
+
// --- Column virtualization ---
|
|
2313
|
+
this.columnsEnabled = computed(() => this.config().columns === true);
|
|
2314
|
+
this.columnOverscan = computed(() => this.config().columnOverscan ?? 2);
|
|
2315
|
+
/** The visible column range with spacer widths, or null when column virtualization is off. */
|
|
2316
|
+
this.columnRange = computed(() => {
|
|
2317
|
+
if (!this.columnsEnabled()) return null;
|
|
2318
|
+
const widths = this.columnWidths();
|
|
2319
|
+
if (widths.length === 0) return null;
|
|
2320
|
+
return computeVisibleColumnRange(
|
|
2321
|
+
this.scrollLeft(),
|
|
2322
|
+
widths,
|
|
2323
|
+
this.containerWidth(),
|
|
2324
|
+
this.columnOverscan()
|
|
2325
|
+
);
|
|
2326
|
+
});
|
|
2257
2327
|
this.destroyRef.onDestroy(() => {
|
|
2258
2328
|
this.containerEl = null;
|
|
2259
2329
|
});
|
|
@@ -2267,10 +2337,12 @@ var VirtualScrollService = class {
|
|
|
2267
2337
|
}
|
|
2268
2338
|
/**
|
|
2269
2339
|
* Call this from the container's scroll event handler.
|
|
2340
|
+
* Tracks both vertical and horizontal scroll positions.
|
|
2270
2341
|
*/
|
|
2271
2342
|
onScroll(event) {
|
|
2272
2343
|
const target = event.target;
|
|
2273
2344
|
this.scrollTop.set(target.scrollTop);
|
|
2345
|
+
this.scrollLeft.set(target.scrollLeft);
|
|
2274
2346
|
}
|
|
2275
2347
|
/**
|
|
2276
2348
|
* Scroll to a specific row index.
|
|
@@ -3105,6 +3177,10 @@ var MarchingAntsOverlayComponent = class {
|
|
|
3105
3177
|
this.resizeObserver.observe(container);
|
|
3106
3178
|
}
|
|
3107
3179
|
}
|
|
3180
|
+
isSingleCellSelection() {
|
|
3181
|
+
const r = this.selectionRange;
|
|
3182
|
+
return r != null && r.startRow === r.endRow && r.startCol === r.endCol;
|
|
3183
|
+
}
|
|
3108
3184
|
clipRangeMatchesSel() {
|
|
3109
3185
|
const selRange = this.selectionRange;
|
|
3110
3186
|
const clipRange = this.copyRange ?? this.cutRange;
|
|
@@ -3152,7 +3228,7 @@ MarchingAntsOverlayComponent = __decorateClass([
|
|
|
3152
3228
|
.ogrid-marching-ants-svg--clip { z-index: 5; }
|
|
3153
3229
|
`],
|
|
3154
3230
|
template: `
|
|
3155
|
-
@if (selRect() && !clipRangeMatchesSel()) {
|
|
3231
|
+
@if (selRect() && !clipRangeMatchesSel() && !isSingleCellSelection()) {
|
|
3156
3232
|
<svg
|
|
3157
3233
|
class="ogrid-marching-ants-svg ogrid-marching-ants-svg--selection"
|
|
3158
3234
|
[style.top.px]="selRect()!.top"
|
|
@@ -3396,6 +3472,53 @@ var BaseDataGridTableComponent = class {
|
|
|
3396
3472
|
if (!this.vsEnabled()) return 0;
|
|
3397
3473
|
return this.vsVisibleRange().startIndex;
|
|
3398
3474
|
});
|
|
3475
|
+
// Column virtualization
|
|
3476
|
+
this.vsColumnsEnabled = computed(() => this.virtualScrollService.columnsEnabled());
|
|
3477
|
+
this.vsColumnRange = computed(() => this.virtualScrollService.columnRange());
|
|
3478
|
+
/** Partitioned columns for column virtualization: pinned-left, virtualized-unpinned, pinned-right, with spacer widths. */
|
|
3479
|
+
this.vsColumnPartition = computed(() => {
|
|
3480
|
+
if (!this.vsColumnsEnabled()) return null;
|
|
3481
|
+
const cols = this.visibleCols();
|
|
3482
|
+
const range = this.vsColumnRange();
|
|
3483
|
+
const props = this.getProps();
|
|
3484
|
+
const pinnedCols = props?.pinnedColumns;
|
|
3485
|
+
return partitionColumnsForVirtualization(cols, range, pinnedCols);
|
|
3486
|
+
});
|
|
3487
|
+
/** Column layouts filtered by column virtualization range (or all if column virt is off). */
|
|
3488
|
+
this.vsColumnLayouts = computed(() => {
|
|
3489
|
+
const allLayouts = this.columnLayouts();
|
|
3490
|
+
const partition = this.vsColumnPartition();
|
|
3491
|
+
if (!partition) return allLayouts;
|
|
3492
|
+
const visibleIds = /* @__PURE__ */ new Set();
|
|
3493
|
+
for (const col of partition.pinnedLeft) visibleIds.add(col.columnId);
|
|
3494
|
+
for (const col of partition.virtualizedUnpinned) visibleIds.add(col.columnId);
|
|
3495
|
+
for (const col of partition.pinnedRight) visibleIds.add(col.columnId);
|
|
3496
|
+
return allLayouts.filter((layout) => visibleIds.has(layout.col.columnId));
|
|
3497
|
+
});
|
|
3498
|
+
/** Visible columns filtered by column virtualization range (or all if column virt is off). */
|
|
3499
|
+
this.vsVisibleCols = computed(() => {
|
|
3500
|
+
const allCols = this.visibleCols();
|
|
3501
|
+
const partition = this.vsColumnPartition();
|
|
3502
|
+
if (!partition) return allCols;
|
|
3503
|
+
const visibleIds = /* @__PURE__ */ new Set();
|
|
3504
|
+
for (const col of partition.pinnedLeft) visibleIds.add(col.columnId);
|
|
3505
|
+
for (const col of partition.virtualizedUnpinned) visibleIds.add(col.columnId);
|
|
3506
|
+
for (const col of partition.pinnedRight) visibleIds.add(col.columnId);
|
|
3507
|
+
return allCols.filter((col) => visibleIds.has(col.columnId));
|
|
3508
|
+
});
|
|
3509
|
+
/** Left spacer width for column virtualization (in pixels). */
|
|
3510
|
+
this.vsLeftSpacerWidth = computed(() => this.vsColumnPartition()?.leftSpacerWidth ?? 0);
|
|
3511
|
+
/** Right spacer width for column virtualization (in pixels). */
|
|
3512
|
+
this.vsRightSpacerWidth = computed(() => this.vsColumnPartition()?.rightSpacerWidth ?? 0);
|
|
3513
|
+
/** Map from columnId to its global index in visibleCols. Used to maintain correct colIdx for cell descriptors during column virtualization. */
|
|
3514
|
+
this.globalColIndexMap = computed(() => {
|
|
3515
|
+
const cols = this.visibleCols();
|
|
3516
|
+
const map = /* @__PURE__ */ new Map();
|
|
3517
|
+
for (let i = 0; i < cols.length; i++) {
|
|
3518
|
+
map.set(cols[i].columnId, i);
|
|
3519
|
+
}
|
|
3520
|
+
return map;
|
|
3521
|
+
});
|
|
3399
3522
|
// Popover editing
|
|
3400
3523
|
this.popoverAnchorEl = computed(() => this.editingState().popoverAnchorEl);
|
|
3401
3524
|
this.pendingEditorValueForPopover = computed(() => this.editingState().pendingEditorValue);
|
|
@@ -3519,6 +3642,10 @@ var BaseDataGridTableComponent = class {
|
|
|
3519
3642
|
this.measuredColumnWidths.set(measured);
|
|
3520
3643
|
}
|
|
3521
3644
|
}
|
|
3645
|
+
/** Get global column index for a column (correct even during column virtualization). */
|
|
3646
|
+
getGlobalColIndex(col) {
|
|
3647
|
+
return this.globalColIndexMap().get(col.columnId) ?? 0;
|
|
3648
|
+
}
|
|
3522
3649
|
/**
|
|
3523
3650
|
* Initialize base wiring effects. Must be called from subclass constructor.
|
|
3524
3651
|
*
|
|
@@ -3569,16 +3696,26 @@ var BaseDataGridTableComponent = class {
|
|
|
3569
3696
|
this.virtualScrollService.updateConfig({
|
|
3570
3697
|
enabled: p.virtualScroll.enabled,
|
|
3571
3698
|
rowHeight: p.virtualScroll.rowHeight,
|
|
3572
|
-
overscan: p.virtualScroll.overscan
|
|
3699
|
+
overscan: p.virtualScroll.overscan,
|
|
3700
|
+
columns: p.virtualScroll.columns,
|
|
3701
|
+
columnOverscan: p.virtualScroll.columnOverscan
|
|
3573
3702
|
});
|
|
3574
3703
|
}
|
|
3575
3704
|
}
|
|
3576
3705
|
});
|
|
3706
|
+
effect(() => {
|
|
3707
|
+
const layouts = this.columnLayouts();
|
|
3708
|
+
const props = this.getProps();
|
|
3709
|
+
const pinnedCols = props?.pinnedColumns ?? {};
|
|
3710
|
+
const unpinnedWidths = layouts.filter((l) => !l.pinnedLeft && !l.pinnedRight && !pinnedCols[l.col.columnId]).map((l) => l.width);
|
|
3711
|
+
this.virtualScrollService.columnWidths.set(unpinnedWidths);
|
|
3712
|
+
});
|
|
3577
3713
|
effect(() => {
|
|
3578
3714
|
const el = this.wrapperElSignal();
|
|
3579
3715
|
if (el) {
|
|
3580
3716
|
this.virtualScrollService.setContainer(el);
|
|
3581
3717
|
this.virtualScrollService.containerHeight.set(el.clientHeight);
|
|
3718
|
+
this.virtualScrollService.containerWidth.set(el.clientWidth);
|
|
3582
3719
|
}
|
|
3583
3720
|
});
|
|
3584
3721
|
}
|
|
@@ -134,6 +134,34 @@ export declare abstract class BaseDataGridTableComponent<T = unknown> {
|
|
|
134
134
|
readonly vsBottomSpacerHeight: import("@angular/core").Signal<number>;
|
|
135
135
|
readonly vsVisibleItems: import("@angular/core").Signal<T[]>;
|
|
136
136
|
readonly vsStartIndex: import("@angular/core").Signal<number>;
|
|
137
|
+
readonly vsColumnsEnabled: import("@angular/core").Signal<boolean>;
|
|
138
|
+
readonly vsColumnRange: import("@angular/core").Signal<import("@alaarab/ogrid-core").IVisibleColumnRange | null>;
|
|
139
|
+
/** Partitioned columns for column virtualization: pinned-left, virtualized-unpinned, pinned-right, with spacer widths. */
|
|
140
|
+
readonly vsColumnPartition: import("@angular/core").Signal<{
|
|
141
|
+
pinnedLeft: import("@alaarab/ogrid-core").IColumnDef<T>[];
|
|
142
|
+
virtualizedUnpinned: import("@alaarab/ogrid-core").IColumnDef<T>[];
|
|
143
|
+
pinnedRight: import("@alaarab/ogrid-core").IColumnDef<T>[];
|
|
144
|
+
leftSpacerWidth: number;
|
|
145
|
+
rightSpacerWidth: number;
|
|
146
|
+
} | null>;
|
|
147
|
+
/** Column layouts filtered by column virtualization range (or all if column virt is off). */
|
|
148
|
+
readonly vsColumnLayouts: import("@angular/core").Signal<{
|
|
149
|
+
col: IColumnDef<T>;
|
|
150
|
+
pinnedLeft: boolean;
|
|
151
|
+
pinnedRight: boolean;
|
|
152
|
+
minWidth: number;
|
|
153
|
+
width: number;
|
|
154
|
+
}[]>;
|
|
155
|
+
/** Visible columns filtered by column virtualization range (or all if column virt is off). */
|
|
156
|
+
readonly vsVisibleCols: import("@angular/core").Signal<IColumnDef<T>[]>;
|
|
157
|
+
/** Left spacer width for column virtualization (in pixels). */
|
|
158
|
+
readonly vsLeftSpacerWidth: import("@angular/core").Signal<number>;
|
|
159
|
+
/** Right spacer width for column virtualization (in pixels). */
|
|
160
|
+
readonly vsRightSpacerWidth: import("@angular/core").Signal<number>;
|
|
161
|
+
/** Map from columnId to its global index in visibleCols. Used to maintain correct colIdx for cell descriptors during column virtualization. */
|
|
162
|
+
readonly globalColIndexMap: import("@angular/core").Signal<Map<string, number>>;
|
|
163
|
+
/** Get global column index for a column (correct even during column virtualization). */
|
|
164
|
+
getGlobalColIndex(col: IColumnDef<T>): number;
|
|
137
165
|
readonly popoverAnchorEl: import("@angular/core").Signal<HTMLElement | null>;
|
|
138
166
|
readonly pendingEditorValueForPopover: import("@angular/core").Signal<unknown>;
|
|
139
167
|
readonly allowOverflowX: import("@angular/core").Signal<boolean>;
|
|
@@ -19,6 +19,7 @@ export declare class MarchingAntsOverlayComponent implements OnChanges {
|
|
|
19
19
|
constructor();
|
|
20
20
|
ngOnChanges(_changes: SimpleChanges): void;
|
|
21
21
|
private recalculate;
|
|
22
|
+
isSingleCellSelection(): boolean;
|
|
22
23
|
clipRangeMatchesSel(): boolean;
|
|
23
24
|
max0(n: number): number;
|
|
24
25
|
}
|
|
@@ -108,6 +108,7 @@ export declare class OGridService<T> {
|
|
|
108
108
|
readonly virtualScroll: import("@angular/core").WritableSignal<IVirtualScrollConfig | undefined>;
|
|
109
109
|
readonly ariaLabel: import("@angular/core").WritableSignal<string | undefined>;
|
|
110
110
|
readonly ariaLabelledBy: import("@angular/core").WritableSignal<string | undefined>;
|
|
111
|
+
readonly workerSort: import("@angular/core").WritableSignal<boolean>;
|
|
111
112
|
private readonly internalData;
|
|
112
113
|
private readonly internalLoading;
|
|
113
114
|
private readonly internalPage;
|
|
@@ -125,6 +126,8 @@ export declare class OGridService<T> {
|
|
|
125
126
|
private filterAbortController;
|
|
126
127
|
private readonly refreshCounter;
|
|
127
128
|
private readonly firstDataRendered;
|
|
129
|
+
private readonly asyncClientItems;
|
|
130
|
+
private workerSortAbortId;
|
|
128
131
|
private readonly sideBarActivePanel;
|
|
129
132
|
private readonly serverFilterOptions;
|
|
130
133
|
private readonly loadingFilterOptions;
|
|
@@ -147,10 +150,16 @@ export declare class OGridService<T> {
|
|
|
147
150
|
readonly multiSelectFilterFields: import("@angular/core").Signal<string[]>;
|
|
148
151
|
readonly hasServerFilterOptions: import("@angular/core").Signal<boolean>;
|
|
149
152
|
readonly clientFilterOptions: import("@angular/core").Signal<Record<string, string[]>>;
|
|
153
|
+
/** Sync path: used when workerSort is off. */
|
|
150
154
|
readonly clientItemsAndTotal: import("@angular/core").Signal<{
|
|
151
155
|
items: T[];
|
|
152
156
|
totalCount: number;
|
|
153
157
|
} | null>;
|
|
158
|
+
/** Resolved client items — sync or async depending on workerSort. */
|
|
159
|
+
readonly resolvedClientItems: import("@angular/core").Signal<{
|
|
160
|
+
items: T[];
|
|
161
|
+
totalCount: number;
|
|
162
|
+
} | null>;
|
|
154
163
|
readonly displayItems: import("@angular/core").Signal<T[]>;
|
|
155
164
|
readonly displayTotalCount: import("@angular/core").Signal<number>;
|
|
156
165
|
readonly hasActiveFilters: import("@angular/core").Signal<boolean>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IVisibleRange, IVirtualScrollConfig } from '@alaarab/ogrid-core';
|
|
1
|
+
import type { IVisibleRange, IVisibleColumnRange, IVirtualScrollConfig } from '@alaarab/ogrid-core';
|
|
2
2
|
/**
|
|
3
3
|
* Manages virtual scrolling state using Angular signals.
|
|
4
4
|
* Port of React's useVirtualScroll hook.
|
|
@@ -13,6 +13,9 @@ export declare class VirtualScrollService {
|
|
|
13
13
|
readonly config: import("@angular/core").WritableSignal<IVirtualScrollConfig>;
|
|
14
14
|
readonly containerHeight: import("@angular/core").WritableSignal<number>;
|
|
15
15
|
readonly scrollTop: import("@angular/core").WritableSignal<number>;
|
|
16
|
+
readonly scrollLeft: import("@angular/core").WritableSignal<number>;
|
|
17
|
+
readonly columnWidths: import("@angular/core").WritableSignal<number[]>;
|
|
18
|
+
readonly containerWidth: import("@angular/core").WritableSignal<number>;
|
|
16
19
|
private containerEl;
|
|
17
20
|
readonly rowHeight: import("@angular/core").Signal<number>;
|
|
18
21
|
readonly overscan: import("@angular/core").Signal<number>;
|
|
@@ -24,6 +27,10 @@ export declare class VirtualScrollService {
|
|
|
24
27
|
readonly visibleRange: import("@angular/core").Signal<IVisibleRange>;
|
|
25
28
|
/** Total scrollable height in pixels. */
|
|
26
29
|
readonly totalHeight: import("@angular/core").Signal<number>;
|
|
30
|
+
readonly columnsEnabled: import("@angular/core").Signal<boolean>;
|
|
31
|
+
readonly columnOverscan: import("@angular/core").Signal<number>;
|
|
32
|
+
/** The visible column range with spacer widths, or null when column virtualization is off. */
|
|
33
|
+
readonly columnRange: import("@angular/core").Signal<IVisibleColumnRange | null>;
|
|
27
34
|
constructor();
|
|
28
35
|
/**
|
|
29
36
|
* Set the scrollable container element.
|
|
@@ -32,6 +39,7 @@ export declare class VirtualScrollService {
|
|
|
32
39
|
setContainer(el: HTMLElement | null): void;
|
|
33
40
|
/**
|
|
34
41
|
* Call this from the container's scroll event handler.
|
|
42
|
+
* Tracks both vertical and horizontal scroll positions.
|
|
35
43
|
*/
|
|
36
44
|
onScroll(event: Event): void;
|
|
37
45
|
/**
|
|
@@ -63,6 +63,8 @@ interface IOGridBaseProps<T> {
|
|
|
63
63
|
sideBar?: boolean | ISideBarDef;
|
|
64
64
|
columnReorder?: boolean;
|
|
65
65
|
virtualScroll?: IVirtualScrollConfig;
|
|
66
|
+
/** Offload sort/filter to a Web Worker for large datasets. Falls back to sync when sort column has a custom compare. */
|
|
67
|
+
workerSort?: boolean;
|
|
66
68
|
/** Fixed row height in pixels. Overrides default row height (36px). */
|
|
67
69
|
rowHeight?: number;
|
|
68
70
|
pageSizeOptions?: number[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alaarab/ogrid-angular",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "OGrid Angular – Angular services, signals, and headless components for OGrid data grids.",
|
|
5
5
|
"main": "dist/esm/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"node": ">=18"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@alaarab/ogrid-core": "2.
|
|
38
|
+
"@alaarab/ogrid-core": "2.2.0"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
41
|
"@angular/core": "^21.0.0",
|