@alaarab/ogrid-angular 2.0.23 → 2.1.1
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/components/base-column-header-filter.component.js +26 -11
- package/dist/esm/components/base-datagrid-table.component.js +64 -46
- package/dist/esm/components/base-ogrid.component.js +36 -0
- package/dist/esm/components/base-popover-cell-editor.component.js +6 -7
- package/dist/esm/components/empty-state.component.js +2 -2
- package/dist/esm/components/grid-context-menu.component.js +17 -17
- package/dist/esm/components/ogrid-layout.component.js +2 -49
- package/dist/esm/components/sidebar.component.js +2 -6
- package/dist/esm/components/status-bar.component.js +6 -2
- package/dist/esm/index.js +5 -1
- package/dist/esm/services/datagrid-editing.service.js +52 -0
- package/dist/esm/services/datagrid-interaction.service.js +667 -0
- package/dist/esm/services/datagrid-layout.service.js +151 -0
- package/dist/esm/services/datagrid-state.service.js +130 -865
- package/dist/esm/services/ogrid.service.js +61 -26
- package/dist/esm/utils/index.js +1 -1
- package/dist/esm/utils/latestRef.js +0 -5
- package/dist/types/components/base-column-header-filter.component.d.ts +2 -0
- package/dist/types/components/base-datagrid-table.component.d.ts +21 -5
- package/dist/types/components/base-ogrid.component.d.ts +10 -0
- package/dist/types/components/grid-context-menu.component.d.ts +5 -5
- package/dist/types/components/sidebar.component.d.ts +0 -2
- package/dist/types/components/status-bar.component.d.ts +4 -1
- package/dist/types/index.d.ts +5 -1
- package/dist/types/services/datagrid-editing.service.d.ts +31 -0
- package/dist/types/services/datagrid-interaction.service.d.ts +86 -0
- package/dist/types/services/datagrid-layout.service.d.ts +36 -0
- package/dist/types/services/datagrid-state.service.d.ts +20 -39
- package/dist/types/services/ogrid.service.d.ts +8 -3
- package/dist/types/types/dataGridTypes.d.ts +1 -1
- package/dist/types/utils/index.d.ts +1 -1
- package/dist/types/utils/latestRef.d.ts +0 -5
- package/package.json +10 -3
|
@@ -5,7 +5,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
7
|
import { Injectable, signal, computed, effect, DestroyRef, inject } from '@angular/core';
|
|
8
|
-
import { mergeFilter, deriveFilterOptionsFromData, getMultiSelectFilterFields, flattenColumns, processClientSideData, computeNextSortState, } from '@alaarab/ogrid-core';
|
|
8
|
+
import { mergeFilter, deriveFilterOptionsFromData, getMultiSelectFilterFields, flattenColumns, processClientSideData, computeNextSortState, validateColumns, validateRowIds, } from '@alaarab/ogrid-core';
|
|
9
9
|
const DEFAULT_PAGE_SIZE = 25;
|
|
10
10
|
const EMPTY_LOADING_OPTIONS = {};
|
|
11
11
|
const DEFAULT_PANELS = ['columns', 'filters'];
|
|
@@ -86,9 +86,10 @@ let OGridService = class OGridService {
|
|
|
86
86
|
this.serverItems = signal([]);
|
|
87
87
|
this.serverTotalCount = signal(0);
|
|
88
88
|
this.serverLoading = signal(true);
|
|
89
|
-
this.
|
|
89
|
+
this.fetchAbortController = null;
|
|
90
|
+
this.filterAbortController = null;
|
|
90
91
|
this.refreshCounter = signal(0);
|
|
91
|
-
this.firstDataRendered = false;
|
|
92
|
+
this.firstDataRendered = signal(false);
|
|
92
93
|
// Side bar state
|
|
93
94
|
this.sideBarActivePanel = signal(null);
|
|
94
95
|
// Filter options state
|
|
@@ -109,10 +110,12 @@ let OGridService = class OGridService {
|
|
|
109
110
|
});
|
|
110
111
|
this.filters = computed(() => this.controlledFilters() ?? this.internalFilters());
|
|
111
112
|
this.visibleColumns = computed(() => {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
113
|
+
const controlled = this.controlledVisibleColumns();
|
|
114
|
+
if (controlled)
|
|
115
|
+
return controlled;
|
|
116
|
+
const override = this.internalVisibleColumnsOverride();
|
|
117
|
+
if (override)
|
|
118
|
+
return override;
|
|
116
119
|
const cols = this.columns();
|
|
117
120
|
if (cols.length === 0)
|
|
118
121
|
return new Set();
|
|
@@ -196,8 +199,8 @@ let OGridService = class OGridService {
|
|
|
196
199
|
.map((c) => ({
|
|
197
200
|
columnId: c.columnId,
|
|
198
201
|
name: c.name,
|
|
199
|
-
filterField: c.filterable
|
|
200
|
-
filterType: c.filterable
|
|
202
|
+
filterField: c.filterable?.filterField ?? c.columnId,
|
|
203
|
+
filterType: c.filterable?.type,
|
|
201
204
|
})));
|
|
202
205
|
this.sideBarState = computed(() => ({
|
|
203
206
|
isEnabled: this.sideBarEnabled(),
|
|
@@ -217,6 +220,9 @@ let OGridService = class OGridService {
|
|
|
217
220
|
this.handleSelectionChangeFn = (event) => this.handleSelectionChange(event);
|
|
218
221
|
this.handleFilterChangeFn = (key, value) => this.handleFilterChange(key, value);
|
|
219
222
|
this.clearAllFiltersFn = () => this.setFilters({});
|
|
223
|
+
this.setPageFn = (p) => this.setPage(p);
|
|
224
|
+
this.setPageSizeFn = (size) => this.setPageSize(size);
|
|
225
|
+
this.handleVisibilityChangeFn = (columnKey, isVisible) => this.handleVisibilityChange(columnKey, isVisible);
|
|
220
226
|
// --- Data grid props computed ---
|
|
221
227
|
this.dataGridProps = computed(() => ({
|
|
222
228
|
items: this.displayItems(),
|
|
@@ -270,15 +276,15 @@ let OGridService = class OGridService {
|
|
|
270
276
|
page: this.page(),
|
|
271
277
|
pageSize: this.pageSize(),
|
|
272
278
|
displayTotalCount: this.displayTotalCount(),
|
|
273
|
-
setPage:
|
|
274
|
-
setPageSize:
|
|
279
|
+
setPage: this.setPageFn,
|
|
280
|
+
setPageSize: this.setPageSizeFn,
|
|
275
281
|
pageSizeOptions: this.pageSizeOptions(),
|
|
276
282
|
entityLabelPlural: this.entityLabelPlural(),
|
|
277
283
|
}));
|
|
278
284
|
this.columnChooser = computed(() => ({
|
|
279
285
|
columns: this.columnChooserColumns(),
|
|
280
286
|
visibleColumns: this.visibleColumns(),
|
|
281
|
-
onVisibilityChange:
|
|
287
|
+
onVisibilityChange: this.handleVisibilityChangeFn,
|
|
282
288
|
placement: this.columnChooserPlacement(),
|
|
283
289
|
}));
|
|
284
290
|
this.filtersResult = computed(() => ({
|
|
@@ -304,8 +310,17 @@ let OGridService = class OGridService {
|
|
|
304
310
|
filterOptions: this.clientFilterOptions(),
|
|
305
311
|
};
|
|
306
312
|
});
|
|
307
|
-
//
|
|
313
|
+
// Validate columns once (on first non-empty columns signal)
|
|
314
|
+
let columnsValidated = false;
|
|
308
315
|
effect(() => {
|
|
316
|
+
const cols = this.columns();
|
|
317
|
+
if (!columnsValidated && cols.length > 0) {
|
|
318
|
+
columnsValidated = true;
|
|
319
|
+
validateColumns(cols);
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
// Server-side data fetching effect
|
|
323
|
+
effect((onCleanup) => {
|
|
309
324
|
const ds = this.dataSource();
|
|
310
325
|
if (!this.isServerSide() || !ds) {
|
|
311
326
|
if (!this.isServerSide())
|
|
@@ -318,36 +333,46 @@ let OGridService = class OGridService {
|
|
|
318
333
|
const filters = this.filters();
|
|
319
334
|
// Read refreshCounter to trigger re-fetches
|
|
320
335
|
this.refreshCounter();
|
|
321
|
-
const
|
|
336
|
+
const controller = new AbortController();
|
|
337
|
+
this.fetchAbortController = controller;
|
|
322
338
|
this.serverLoading.set(true);
|
|
323
339
|
ds.fetchPage({ page, pageSize, sort: { field: sort.field, direction: sort.direction }, filters })
|
|
324
340
|
.then((res) => {
|
|
325
|
-
if (
|
|
341
|
+
if (controller.signal.aborted)
|
|
326
342
|
return;
|
|
327
343
|
this.serverItems.set(res.items);
|
|
328
344
|
this.serverTotalCount.set(res.totalCount);
|
|
329
345
|
})
|
|
330
346
|
.catch((err) => {
|
|
331
|
-
if (
|
|
347
|
+
if (controller.signal.aborted)
|
|
332
348
|
return;
|
|
333
349
|
this.onError()?.(err);
|
|
334
350
|
this.serverItems.set([]);
|
|
335
351
|
this.serverTotalCount.set(0);
|
|
336
352
|
})
|
|
337
353
|
.finally(() => {
|
|
338
|
-
if (
|
|
354
|
+
if (!controller.signal.aborted)
|
|
339
355
|
this.serverLoading.set(false);
|
|
340
356
|
});
|
|
357
|
+
onCleanup(() => {
|
|
358
|
+
controller.abort();
|
|
359
|
+
});
|
|
341
360
|
});
|
|
342
|
-
// Fire onFirstDataRendered once
|
|
361
|
+
// Fire onFirstDataRendered once; also validate row IDs on first data
|
|
362
|
+
let rowIdsValidated = false;
|
|
343
363
|
effect(() => {
|
|
344
|
-
|
|
345
|
-
|
|
364
|
+
const items = this.displayItems();
|
|
365
|
+
if (!this.firstDataRendered() && items.length > 0) {
|
|
366
|
+
this.firstDataRendered.set(true);
|
|
346
367
|
this.onFirstDataRendered()?.();
|
|
347
368
|
}
|
|
369
|
+
if (!rowIdsValidated && items.length > 0) {
|
|
370
|
+
rowIdsValidated = true;
|
|
371
|
+
validateRowIds(items, this.getRowId());
|
|
372
|
+
}
|
|
348
373
|
});
|
|
349
374
|
// Load server filter options
|
|
350
|
-
effect(() => {
|
|
375
|
+
effect((onCleanup) => {
|
|
351
376
|
const ds = this.dataSource();
|
|
352
377
|
const fields = this.multiSelectFilterFields();
|
|
353
378
|
const fetcher = ds && 'fetchFilterOptions' in ds && typeof ds.fetchFilterOptions === 'function'
|
|
@@ -358,6 +383,8 @@ let OGridService = class OGridService {
|
|
|
358
383
|
this.loadingFilterOptions.set({});
|
|
359
384
|
return;
|
|
360
385
|
}
|
|
386
|
+
const controller = new AbortController();
|
|
387
|
+
this.filterAbortController = controller;
|
|
361
388
|
const loading = {};
|
|
362
389
|
fields.forEach((f) => { loading[f] = true; });
|
|
363
390
|
this.loadingFilterOptions.set(loading);
|
|
@@ -370,9 +397,14 @@ let OGridService = class OGridService {
|
|
|
370
397
|
results[field] = [];
|
|
371
398
|
}
|
|
372
399
|
})).then(() => {
|
|
400
|
+
if (controller.signal.aborted)
|
|
401
|
+
return;
|
|
373
402
|
this.serverFilterOptions.set(results);
|
|
374
403
|
this.loadingFilterOptions.set({});
|
|
375
404
|
});
|
|
405
|
+
onCleanup(() => {
|
|
406
|
+
controller.abort();
|
|
407
|
+
});
|
|
376
408
|
});
|
|
377
409
|
// Initialize sidebar default panel
|
|
378
410
|
effect(() => {
|
|
@@ -381,8 +413,12 @@ let OGridService = class OGridService {
|
|
|
381
413
|
this.sideBarActivePanel.set(parsed.defaultPanel);
|
|
382
414
|
}
|
|
383
415
|
});
|
|
384
|
-
// Cleanup on destroy —
|
|
416
|
+
// Cleanup on destroy — abort in-flight requests and reset callback signals
|
|
385
417
|
this.destroyRef.onDestroy(() => {
|
|
418
|
+
this.fetchAbortController?.abort();
|
|
419
|
+
this.filterAbortController?.abort();
|
|
420
|
+
this.fetchAbortController = null;
|
|
421
|
+
this.filterAbortController = null;
|
|
386
422
|
this.onPageChange.set(undefined);
|
|
387
423
|
this.onPageSizeChange.set(undefined);
|
|
388
424
|
this.onSortChange.set(undefined);
|
|
@@ -576,8 +612,7 @@ let OGridService = class OGridService {
|
|
|
576
612
|
*/
|
|
577
613
|
unpinColumn(columnId) {
|
|
578
614
|
this.pinnedOverrides.update((prev) => {
|
|
579
|
-
const
|
|
580
|
-
delete next[columnId];
|
|
615
|
+
const { [columnId]: _, ...next } = prev;
|
|
581
616
|
return next;
|
|
582
617
|
});
|
|
583
618
|
this.onColumnPinned()?.(columnId, null);
|
|
@@ -641,8 +676,8 @@ let OGridService = class OGridService {
|
|
|
641
676
|
this.setVisibleColumns(new Set(state.visibleColumns));
|
|
642
677
|
if (state.sort)
|
|
643
678
|
this.setSort(state.sort);
|
|
644
|
-
if (state.columnOrder
|
|
645
|
-
this.onColumnOrderChange()(state.columnOrder);
|
|
679
|
+
if (state.columnOrder)
|
|
680
|
+
this.onColumnOrderChange()?.(state.columnOrder);
|
|
646
681
|
if (state.columnWidths)
|
|
647
682
|
this.columnWidthOverrides.set(state.columnWidths);
|
|
648
683
|
if (state.filters)
|
package/dist/esm/utils/index.js
CHANGED
|
@@ -5,4 +5,4 @@ export { getHeaderFilterConfig, getCellRenderDescriptor, resolveCellDisplayConte
|
|
|
5
5
|
// Debounce utilities
|
|
6
6
|
export { createDebouncedSignal, createDebouncedCallback, debounce, } from './debounce';
|
|
7
7
|
// Latest ref utilities
|
|
8
|
-
export {
|
|
8
|
+
export { createLatestCallback, } from './latestRef';
|
|
@@ -39,8 +39,3 @@ export function createLatestCallback(fn) {
|
|
|
39
39
|
return fn()(...args);
|
|
40
40
|
});
|
|
41
41
|
}
|
|
42
|
-
/**
|
|
43
|
-
* Alias for createLatestCallback for consistency with React/Vue naming.
|
|
44
|
-
* @deprecated Use createLatestCallback instead
|
|
45
|
-
*/
|
|
46
|
-
export const createLatestRef = createLatestCallback;
|
|
@@ -86,5 +86,7 @@ export declare abstract class BaseColumnHeaderFilterComponent {
|
|
|
86
86
|
handleClearUser(): void;
|
|
87
87
|
handleDateApply(): void;
|
|
88
88
|
handleDateClear(): void;
|
|
89
|
+
/** Clean up debounce timer on destroy. */
|
|
90
|
+
ngOnDestroy(): void;
|
|
89
91
|
onDocumentClick(event: MouseEvent, selectorName: string): void;
|
|
90
92
|
}
|
|
@@ -20,7 +20,7 @@ export declare abstract class BaseDataGridTableComponent<T = unknown> {
|
|
|
20
20
|
protected lastMouseShift: boolean;
|
|
21
21
|
readonly columnSizingVersion: import("@angular/core").WritableSignal<number>;
|
|
22
22
|
/** Dirty flag — set when column layout changes, cleared after measurement. */
|
|
23
|
-
private measureDirty;
|
|
23
|
+
private readonly measureDirty;
|
|
24
24
|
/** DOM-measured column widths from the last layout pass.
|
|
25
25
|
* Used as a minWidth floor to prevent columns from shrinking
|
|
26
26
|
* when new data loads (e.g. server-side pagination). */
|
|
@@ -41,8 +41,14 @@ export declare abstract class BaseDataGridTableComponent<T = unknown> {
|
|
|
41
41
|
* Only updates the signal when values actually change, to avoid render loops. */
|
|
42
42
|
private measureColumnWidths;
|
|
43
43
|
readonly state: import("@angular/core").Signal<import("../services/datagrid-state.service").DataGridStateResult<T>>;
|
|
44
|
+
protected readonly layoutState: import("@angular/core").Signal<import("../services/datagrid-state.service").DataGridLayoutState<T>>;
|
|
45
|
+
protected readonly rowSelectionState: import("@angular/core").Signal<import("../services/datagrid-state.service").DataGridRowSelectionState>;
|
|
46
|
+
protected readonly editingState: import("@angular/core").Signal<import("../services/datagrid-state.service").DataGridEditingState<T>>;
|
|
47
|
+
protected readonly interactionState: import("@angular/core").Signal<import("../services/datagrid-state.service").DataGridCellInteractionState>;
|
|
48
|
+
protected readonly contextMenuState: import("@angular/core").Signal<import("../services/datagrid-state.service").DataGridContextMenuState>;
|
|
49
|
+
protected readonly viewModelsState: import("@angular/core").Signal<import("../services/datagrid-state.service").DataGridViewModelState<T>>;
|
|
50
|
+
protected readonly pinningState: import("@angular/core").Signal<import("../services/datagrid-state.service").DataGridPinningState>;
|
|
44
51
|
readonly tableContainerEl: import("@angular/core").Signal<HTMLElement | null>;
|
|
45
|
-
readonly allItems: import("@angular/core").Signal<T[]>;
|
|
46
52
|
readonly items: import("@angular/core").Signal<T[]>;
|
|
47
53
|
readonly getRowId: import("@angular/core").Signal<(item: T) => RowId>;
|
|
48
54
|
readonly isLoading: import("@angular/core").Signal<boolean>;
|
|
@@ -55,7 +61,7 @@ export declare abstract class BaseDataGridTableComponent<T = unknown> {
|
|
|
55
61
|
onClearAll: () => void;
|
|
56
62
|
hasActiveFilters: boolean;
|
|
57
63
|
message?: string;
|
|
58
|
-
render?:
|
|
64
|
+
render?: unknown;
|
|
59
65
|
} | undefined>;
|
|
60
66
|
readonly currentPage: import("@angular/core").Signal<number>;
|
|
61
67
|
readonly pageSize: import("@angular/core").Signal<number>;
|
|
@@ -144,8 +150,18 @@ export declare abstract class BaseDataGridTableComponent<T = unknown> {
|
|
|
144
150
|
rightOffsets: Record<string, number>;
|
|
145
151
|
}>;
|
|
146
152
|
/**
|
|
147
|
-
* Initialize base wiring effects. Must be called from subclass constructor
|
|
148
|
-
*
|
|
153
|
+
* Initialize base wiring effects. Must be called from subclass constructor.
|
|
154
|
+
*
|
|
155
|
+
* **Timing:** Angular requires `effect()` to be created inside an injection
|
|
156
|
+
* context (constructor or field initializer). On the first run, signals like
|
|
157
|
+
* `wrapperElSignal()` return `null` because the DOM hasn't been created yet.
|
|
158
|
+
* After `ngAfterViewInit` sets these signals, Angular's signal graph
|
|
159
|
+
* automatically re-runs each effect. The null guards inside each effect body
|
|
160
|
+
* ensure the first (null) run is a safe no-op.
|
|
161
|
+
*
|
|
162
|
+
* Sequence:
|
|
163
|
+
* 1. Constructor → `initBase()` → effects created, first run (signals null → no-ops)
|
|
164
|
+
* 2. `ngAfterViewInit` → `wrapperElSignal.set(el)` → effects re-run with real values
|
|
149
165
|
*/
|
|
150
166
|
protected initBase(): void;
|
|
151
167
|
/** Lookup effective min-width for a column (includes measured width floor) */
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { OGridService } from '../services/ogrid.service';
|
|
2
|
+
import type { IOGridProps } from '../types';
|
|
3
|
+
export declare abstract class BaseOGridComponent<T> {
|
|
4
|
+
private readonly propsSignal;
|
|
5
|
+
readonly ogridService: OGridService<T>;
|
|
6
|
+
set props(value: IOGridProps<T>);
|
|
7
|
+
constructor();
|
|
8
|
+
get showToolbar(): boolean;
|
|
9
|
+
onPageSizeChange(size: number): void;
|
|
10
|
+
}
|
|
@@ -14,13 +14,13 @@ export declare class GridContextMenuComponent {
|
|
|
14
14
|
contextMenuItemShortcut?: string;
|
|
15
15
|
contextMenuDivider?: string;
|
|
16
16
|
} | undefined;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
copyAction: EventEmitter<void>;
|
|
18
|
+
cutAction: EventEmitter<void>;
|
|
19
|
+
pasteAction: EventEmitter<void>;
|
|
20
|
+
selectAllAction: EventEmitter<void>;
|
|
21
21
|
undoAction: EventEmitter<void>;
|
|
22
22
|
redoAction: EventEmitter<void>;
|
|
23
|
-
|
|
23
|
+
closeAction: EventEmitter<void>;
|
|
24
24
|
menuRef?: ElementRef<HTMLDivElement>;
|
|
25
25
|
readonly menuItems: import("@alaarab/ogrid-core").GridContextMenuItem[];
|
|
26
26
|
readonly formatShortcutFn: typeof formatShortcut;
|
|
@@ -23,8 +23,6 @@ export interface SideBarProps {
|
|
|
23
23
|
export declare class SideBarComponent {
|
|
24
24
|
sideBarProps: SideBarProps | null;
|
|
25
25
|
readonly panelLabels: Record<SideBarPanelId, string>;
|
|
26
|
-
readonly tabWidth = 36;
|
|
27
|
-
readonly panelWidth = 240;
|
|
28
26
|
onTabClick(panel: SideBarPanelId): void;
|
|
29
27
|
allVisible(): boolean;
|
|
30
28
|
onSelectAll(): void;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { OnChanges } from '@angular/core';
|
|
2
|
+
export declare class StatusBarComponent implements OnChanges {
|
|
2
3
|
totalCount: number;
|
|
3
4
|
filteredCount: number | undefined;
|
|
4
5
|
selectedCount: number | undefined;
|
|
@@ -17,5 +18,7 @@ export declare class StatusBarComponent {
|
|
|
17
18
|
statusBarLabel?: string;
|
|
18
19
|
statusBarValue?: string;
|
|
19
20
|
} | undefined;
|
|
21
|
+
private cachedParts;
|
|
22
|
+
ngOnChanges(): void;
|
|
20
23
|
getParts(): import("@alaarab/ogrid-core").StatusBarPart[];
|
|
21
24
|
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -8,6 +8,9 @@ export { OGridService } from './services/ogrid.service';
|
|
|
8
8
|
export type { ColumnChooserPlacement, OGridPagination, OGridColumnChooser, OGridFilters, OGridSideBarState, } from './services/ogrid.service';
|
|
9
9
|
export { DataGridStateService } from './services/datagrid-state.service';
|
|
10
10
|
export type { DataGridLayoutState, DataGridRowSelectionState, DataGridEditingState, DataGridCellInteractionState, DataGridContextMenuState, DataGridViewModelState, DataGridPinningState, DataGridStateResult, } from './services/datagrid-state.service';
|
|
11
|
+
export { DataGridLayoutHelper } from './services/datagrid-layout.service';
|
|
12
|
+
export { DataGridEditingHelper } from './services/datagrid-editing.service';
|
|
13
|
+
export { DataGridInteractionHelper } from './services/datagrid-interaction.service';
|
|
11
14
|
export { ColumnReorderService } from './services/column-reorder.service';
|
|
12
15
|
export { VirtualScrollService } from './services/virtual-scroll.service';
|
|
13
16
|
export { OGridLayoutComponent } from './components/ogrid-layout.component';
|
|
@@ -17,6 +20,7 @@ export { SideBarComponent } from './components/sidebar.component';
|
|
|
17
20
|
export type { SideBarProps, SideBarFilterColumn } from './components/sidebar.component';
|
|
18
21
|
export { MarchingAntsOverlayComponent } from './components/marching-ants-overlay.component';
|
|
19
22
|
export { EmptyStateComponent } from './components/empty-state.component';
|
|
23
|
+
export { BaseOGridComponent } from './components/base-ogrid.component';
|
|
20
24
|
export { BaseDataGridTableComponent } from './components/base-datagrid-table.component';
|
|
21
25
|
export { BaseColumnHeaderFilterComponent } from './components/base-column-header-filter.component';
|
|
22
26
|
export type { IColumnHeaderFilterProps } from './components/base-column-header-filter.component';
|
|
@@ -28,4 +32,4 @@ export { INLINE_CELL_EDITOR_TEMPLATE, INLINE_CELL_EDITOR_STYLES } from './compon
|
|
|
28
32
|
export { BasePopoverCellEditorComponent, POPOVER_CELL_EDITOR_TEMPLATE, POPOVER_CELL_EDITOR_OVERLAY_STYLES } from './components/base-popover-cell-editor.component';
|
|
29
33
|
export { OGRID_THEME_VARS_CSS } from './styles/ogrid-theme-vars';
|
|
30
34
|
export type { HeaderFilterConfigInput, HeaderFilterConfig, CellRenderDescriptorInput, CellRenderDescriptor, CellRenderMode, } from './utils';
|
|
31
|
-
export { getHeaderFilterConfig, getCellRenderDescriptor, resolveCellDisplayContent, resolveCellStyle, createDebouncedSignal, createDebouncedCallback, debounce,
|
|
35
|
+
export { getHeaderFilterConfig, getCellRenderDescriptor, resolveCellDisplayContent, resolveCellStyle, createDebouncedSignal, createDebouncedCallback, debounce, createLatestCallback, } from './utils';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { RowId, IActiveCell, ICellValueChangedEvent } from '../types';
|
|
2
|
+
import type { IColumnDef as IAngularColumnDef } from '../types';
|
|
3
|
+
type IColumnDef<T> = IAngularColumnDef<T>;
|
|
4
|
+
/**
|
|
5
|
+
* Manages cell editing state, inline/popover editor, and commit/cancel logic.
|
|
6
|
+
* Extracted from DataGridStateService for modularity.
|
|
7
|
+
*
|
|
8
|
+
* Not @Injectable — instantiated and owned by DataGridStateService.
|
|
9
|
+
*/
|
|
10
|
+
export declare class DataGridEditingHelper<T> {
|
|
11
|
+
readonly editingCellSig: import("@angular/core").WritableSignal<{
|
|
12
|
+
rowId: RowId;
|
|
13
|
+
columnId: string;
|
|
14
|
+
} | null>;
|
|
15
|
+
readonly pendingEditorValueSig: import("@angular/core").WritableSignal<unknown>;
|
|
16
|
+
readonly popoverAnchorElSig: import("@angular/core").WritableSignal<HTMLElement | null>;
|
|
17
|
+
/** Injected dependencies */
|
|
18
|
+
private getVisibleCols;
|
|
19
|
+
private getItems;
|
|
20
|
+
private getWrappedOnCellValueChanged;
|
|
21
|
+
private setActiveCellFn;
|
|
22
|
+
constructor(getVisibleCols: () => IColumnDef<T>[], getItems: () => T[], getWrappedOnCellValueChanged: () => ((event: ICellValueChangedEvent<T>) => void) | undefined, setActiveCellFn: (cell: IActiveCell | null) => void);
|
|
23
|
+
setEditingCell(cell: {
|
|
24
|
+
rowId: RowId;
|
|
25
|
+
columnId: string;
|
|
26
|
+
} | null): void;
|
|
27
|
+
setPendingEditorValue(value: unknown): void;
|
|
28
|
+
commitCellEdit(item: T, columnId: string, oldValue: unknown, newValue: unknown, rowIndex: number, globalColIndex: number): void;
|
|
29
|
+
cancelPopoverEdit(): void;
|
|
30
|
+
}
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { UndoRedoStack } from '@alaarab/ogrid-core';
|
|
2
|
+
import type { RowId, IActiveCell, ISelectionRange, ICellValueChangedEvent } from '../types';
|
|
3
|
+
import type { IColumnDef as IAngularColumnDef } from '../types';
|
|
4
|
+
type IColumnDef<T> = IAngularColumnDef<T>;
|
|
5
|
+
/**
|
|
6
|
+
* Manages cell selection, keyboard navigation, clipboard, fill handle, and undo/redo.
|
|
7
|
+
* Extracted from DataGridStateService for modularity.
|
|
8
|
+
*
|
|
9
|
+
* Not @Injectable — instantiated and owned by DataGridStateService.
|
|
10
|
+
*/
|
|
11
|
+
export declare class DataGridInteractionHelper<T> {
|
|
12
|
+
readonly activeCellSig: import("@angular/core").WritableSignal<IActiveCell | null>;
|
|
13
|
+
readonly selectionRangeSig: import("@angular/core").WritableSignal<ISelectionRange | null>;
|
|
14
|
+
readonly isDraggingSig: import("@angular/core").WritableSignal<boolean>;
|
|
15
|
+
readonly contextMenuPositionSig: import("@angular/core").WritableSignal<{
|
|
16
|
+
x: number;
|
|
17
|
+
y: number;
|
|
18
|
+
} | null>;
|
|
19
|
+
readonly cutRangeSig: import("@angular/core").WritableSignal<ISelectionRange | null>;
|
|
20
|
+
readonly copyRangeSig: import("@angular/core").WritableSignal<ISelectionRange | null>;
|
|
21
|
+
private internalClipboard;
|
|
22
|
+
readonly undoRedoStack: UndoRedoStack<ICellValueChangedEvent<T>>;
|
|
23
|
+
readonly undoLengthSig: import("@angular/core").WritableSignal<number>;
|
|
24
|
+
readonly redoLengthSig: import("@angular/core").WritableSignal<number>;
|
|
25
|
+
readonly canUndo: import("@angular/core").Signal<boolean>;
|
|
26
|
+
readonly canRedo: import("@angular/core").Signal<boolean>;
|
|
27
|
+
readonly hasCellSelection: import("@angular/core").Signal<boolean>;
|
|
28
|
+
fillDragStart: {
|
|
29
|
+
startRow: number;
|
|
30
|
+
startCol: number;
|
|
31
|
+
} | null;
|
|
32
|
+
fillRafId: number;
|
|
33
|
+
fillMoveHandler: ((e: MouseEvent) => void) | null;
|
|
34
|
+
fillUpHandler: (() => void) | null;
|
|
35
|
+
dragStartPos: {
|
|
36
|
+
row: number;
|
|
37
|
+
col: number;
|
|
38
|
+
} | null;
|
|
39
|
+
dragMoved: boolean;
|
|
40
|
+
isDraggingRef: boolean;
|
|
41
|
+
liveDragRange: ISelectionRange | null;
|
|
42
|
+
rafId: number;
|
|
43
|
+
lastMousePos: {
|
|
44
|
+
cx: number;
|
|
45
|
+
cy: number;
|
|
46
|
+
} | null;
|
|
47
|
+
autoScrollInterval: ReturnType<typeof setInterval> | null;
|
|
48
|
+
setActiveCell(cell: IActiveCell | null): void;
|
|
49
|
+
setSelectionRange(range: ISelectionRange | null): void;
|
|
50
|
+
setContextMenuPosition(pos: {
|
|
51
|
+
x: number;
|
|
52
|
+
y: number;
|
|
53
|
+
} | null): void;
|
|
54
|
+
handleCellContextMenu(e: {
|
|
55
|
+
clientX: number;
|
|
56
|
+
clientY: number;
|
|
57
|
+
preventDefault?: () => void;
|
|
58
|
+
}): void;
|
|
59
|
+
closeContextMenu(): void;
|
|
60
|
+
handleCopy(items: T[], visibleCols: IColumnDef<T>[], colOffset: number): void;
|
|
61
|
+
handleCut(items: T[], visibleCols: IColumnDef<T>[], colOffset: number, editable: boolean | undefined, wrappedOnCellValueChanged: ((event: ICellValueChangedEvent<T>) => void) | undefined): void;
|
|
62
|
+
handlePaste(items: T[], visibleCols: IColumnDef<T>[], colOffset: number, editable: boolean | undefined, wrappedOnCellValueChanged: ((event: ICellValueChangedEvent<T>) => void) | undefined): Promise<void>;
|
|
63
|
+
clearClipboardRanges(): void;
|
|
64
|
+
beginBatch(): void;
|
|
65
|
+
endBatch(): void;
|
|
66
|
+
undo(originalOnCellValueChanged: ((event: ICellValueChangedEvent<T>) => void) | undefined): void;
|
|
67
|
+
redo(originalOnCellValueChanged: ((event: ICellValueChangedEvent<T>) => void) | undefined): void;
|
|
68
|
+
handleCellMouseDown(e: MouseEvent, rowIndex: number, globalColIndex: number, colOffset: number, wrapperEl: HTMLElement | null): void;
|
|
69
|
+
handleSelectAllCells(rowCount: number, visibleColCount: number, colOffset: number): void;
|
|
70
|
+
handleFillHandleMouseDown(e: MouseEvent): void;
|
|
71
|
+
handleGridKeyDown(e: KeyboardEvent, items: T[], getRowId: (item: T) => RowId, visibleCols: IColumnDef<T>[], colOffset: number, hasCheckboxCol: boolean, visibleColumnCount: number, editable: boolean | undefined, wrappedOnCellValueChanged: ((event: ICellValueChangedEvent<T>) => void) | undefined, originalOnCellValueChanged: ((event: ICellValueChangedEvent<T>) => void) | undefined, rowSelection: string, selectedRowIds: Set<RowId>, wrapperEl: HTMLElement | null, handleRowCheckboxChange: (rowId: RowId, checked: boolean, rowIndex: number, shiftKey: boolean) => void, editingCell: {
|
|
72
|
+
rowId: RowId;
|
|
73
|
+
columnId: string;
|
|
74
|
+
} | null, setEditingCell: (cell: {
|
|
75
|
+
rowId: RowId;
|
|
76
|
+
columnId: string;
|
|
77
|
+
} | null) => void): void;
|
|
78
|
+
onWindowMouseMove(e: MouseEvent, colOffset: number, wrapperEl: HTMLElement | null): void;
|
|
79
|
+
onWindowMouseUp(colOffset: number, wrapperEl: HTMLElement | null): void;
|
|
80
|
+
resolveRangeFromMouse(cx: number, cy: number, colOffset: number): ISelectionRange | null;
|
|
81
|
+
applyDragAttrs(range: ISelectionRange, colOff: number, wrapper: HTMLElement | null): void;
|
|
82
|
+
clearDragAttrs(wrapper: HTMLElement | null): void;
|
|
83
|
+
getEffectiveRange(colOffset: number): ISelectionRange | null;
|
|
84
|
+
destroy(): void;
|
|
85
|
+
}
|
|
86
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { signal, computed, NgZone } from '@angular/core';
|
|
2
|
+
import type { RowId } from '../types';
|
|
3
|
+
import type { IColumnDef as IAngularColumnDef } from '../types';
|
|
4
|
+
import type { IOGridDataGridProps } from '../types';
|
|
5
|
+
type IColumnDef<T> = IAngularColumnDef<T>;
|
|
6
|
+
/**
|
|
7
|
+
* Manages column layout, visibility, sizing, and container measurement.
|
|
8
|
+
* Extracted from DataGridStateService for modularity.
|
|
9
|
+
*
|
|
10
|
+
* Not @Injectable — instantiated and owned by DataGridStateService.
|
|
11
|
+
*/
|
|
12
|
+
export declare class DataGridLayoutHelper<T> {
|
|
13
|
+
readonly props: ReturnType<typeof signal<IOGridDataGridProps<T> | null>>;
|
|
14
|
+
readonly wrapperEl: ReturnType<typeof signal<HTMLElement | null>>;
|
|
15
|
+
readonly containerWidthSig: import("@angular/core").WritableSignal<number>;
|
|
16
|
+
readonly columnSizingOverridesSig: import("@angular/core").WritableSignal<Record<string, {
|
|
17
|
+
widthPx: number;
|
|
18
|
+
}>>;
|
|
19
|
+
private resizeObserver;
|
|
20
|
+
private readonly initialColumnWidthsSig;
|
|
21
|
+
readonly flatColumnsRaw: ReturnType<typeof computed<IColumnDef<T>[]>>;
|
|
22
|
+
readonly flatColumns: ReturnType<typeof computed<IColumnDef<T>[]>>;
|
|
23
|
+
readonly visibleCols: ReturnType<typeof computed<IColumnDef<T>[]>>;
|
|
24
|
+
readonly visibleColumnCount: ReturnType<typeof computed<number>>;
|
|
25
|
+
readonly hasCheckboxCol: ReturnType<typeof computed<boolean>>;
|
|
26
|
+
readonly hasRowNumbersCol: ReturnType<typeof computed<boolean>>;
|
|
27
|
+
readonly specialColsCount: ReturnType<typeof computed<number>>;
|
|
28
|
+
readonly totalColCount: ReturnType<typeof computed<number>>;
|
|
29
|
+
readonly colOffset: ReturnType<typeof computed<number>>;
|
|
30
|
+
readonly rowIndexByRowId: ReturnType<typeof computed<Map<RowId, number>>>;
|
|
31
|
+
readonly minTableWidth: ReturnType<typeof computed<number>>;
|
|
32
|
+
readonly desiredTableWidth: ReturnType<typeof computed<number>>;
|
|
33
|
+
constructor(props: ReturnType<typeof signal<IOGridDataGridProps<T> | null>>, wrapperEl: ReturnType<typeof signal<HTMLElement | null>>, ngZone: NgZone);
|
|
34
|
+
destroy(): void;
|
|
35
|
+
}
|
|
36
|
+
export {};
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { RowId, IActiveCell, ISelectionRange, IStatusBarProps, IFilters, FilterValue, UserLike, ICellValueChangedEvent } from '../types';
|
|
2
2
|
import type { IColumnDef as IAngularColumnDef } from '../types';
|
|
3
3
|
import type { IOGridDataGridProps } from '../types';
|
|
4
|
+
import { DataGridLayoutHelper } from './datagrid-layout.service';
|
|
5
|
+
import { DataGridEditingHelper } from './datagrid-editing.service';
|
|
6
|
+
import { DataGridInteractionHelper } from './datagrid-interaction.service';
|
|
4
7
|
type IColumnDef<T> = IAngularColumnDef<T>;
|
|
5
8
|
export interface DataGridLayoutState<T> {
|
|
6
9
|
flatColumns: IColumnDef<T>[];
|
|
@@ -50,14 +53,17 @@ export interface DataGridEditingState<T> {
|
|
|
50
53
|
}
|
|
51
54
|
export interface DataGridCellInteractionState {
|
|
52
55
|
activeCell: IActiveCell | null;
|
|
53
|
-
|
|
56
|
+
/** Set active cell. Undefined when cell selection is disabled. */
|
|
57
|
+
setActiveCell?: (cell: IActiveCell | null) => void;
|
|
54
58
|
selectionRange: ISelectionRange | null;
|
|
55
|
-
|
|
59
|
+
/** Set selection range. Undefined when cell selection is disabled. */
|
|
60
|
+
setSelectionRange?: (range: ISelectionRange | null) => void;
|
|
56
61
|
handleCellMouseDown: (e: MouseEvent, rowIndex: number, globalColIndex: number) => void;
|
|
57
62
|
handleSelectAllCells: () => void;
|
|
58
63
|
hasCellSelection: boolean;
|
|
59
64
|
handleGridKeyDown: (e: KeyboardEvent) => void;
|
|
60
|
-
|
|
65
|
+
/** Handle fill handle mouse down. Undefined when cell selection is disabled. */
|
|
66
|
+
handleFillHandleMouseDown?: (e: MouseEvent) => void;
|
|
61
67
|
handleCopy: () => void;
|
|
62
68
|
handleCut: () => void;
|
|
63
69
|
handlePaste: () => Promise<void>;
|
|
@@ -75,7 +81,8 @@ export interface DataGridContextMenuState {
|
|
|
75
81
|
x: number;
|
|
76
82
|
y: number;
|
|
77
83
|
} | null;
|
|
78
|
-
|
|
84
|
+
/** Set menu position. Undefined when cell selection is disabled. */
|
|
85
|
+
setMenuPosition?: (pos: {
|
|
79
86
|
x: number;
|
|
80
87
|
y: number;
|
|
81
88
|
} | null) => void;
|
|
@@ -157,46 +164,24 @@ export declare class DataGridStateService<T> {
|
|
|
157
164
|
private ngZone;
|
|
158
165
|
readonly props: import("@angular/core").WritableSignal<IOGridDataGridProps<T> | null>;
|
|
159
166
|
readonly wrapperEl: import("@angular/core").WritableSignal<HTMLElement | null>;
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
167
|
+
/** Layout helper: column layout, visibility, sizing, container measurement. */
|
|
168
|
+
readonly layoutHelper: DataGridLayoutHelper<T>;
|
|
169
|
+
/** Editing helper: cell editing state, commit/cancel logic. */
|
|
170
|
+
readonly editingHelper: DataGridEditingHelper<T>;
|
|
171
|
+
/** Interaction helper: cell selection, keyboard nav, clipboard, fill handle, undo/redo. */
|
|
172
|
+
readonly interactionHelper: DataGridInteractionHelper<T>;
|
|
166
173
|
private readonly internalSelectedRows;
|
|
167
|
-
private readonly popoverAnchorElSig;
|
|
168
|
-
private readonly containerWidthSig;
|
|
169
|
-
private readonly columnSizingOverridesSig;
|
|
170
|
-
private readonly cutRangeSig;
|
|
171
|
-
private readonly copyRangeSig;
|
|
172
|
-
private internalClipboard;
|
|
173
|
-
private readonly undoRedoStack;
|
|
174
|
-
private readonly undoLengthSig;
|
|
175
|
-
private readonly redoLengthSig;
|
|
176
|
-
private fillDragStart;
|
|
177
|
-
private fillRafId;
|
|
178
|
-
private fillMoveHandler;
|
|
179
|
-
private fillUpHandler;
|
|
180
174
|
private lastClickedRow;
|
|
181
|
-
private dragStartPos;
|
|
182
|
-
private dragMoved;
|
|
183
|
-
private isDraggingRef;
|
|
184
|
-
private liveDragRange;
|
|
185
|
-
private rafId;
|
|
186
|
-
private lastMousePos;
|
|
187
|
-
private autoScrollInterval;
|
|
188
|
-
private resizeObserver;
|
|
189
175
|
private readonly headerMenuIsOpenSig;
|
|
190
176
|
private readonly headerMenuOpenForColumnSig;
|
|
191
177
|
private readonly headerMenuAnchorElementSig;
|
|
192
178
|
private readonly propsResolved;
|
|
193
179
|
readonly cellSelection: import("@angular/core").Signal<boolean>;
|
|
194
180
|
private readonly originalOnCellValueChanged;
|
|
195
|
-
private readonly initialColumnWidthsSig;
|
|
196
181
|
private readonly wrappedOnCellValueChanged;
|
|
197
|
-
readonly flatColumnsRaw: import("@angular/core").Signal<
|
|
198
|
-
readonly flatColumns: import("@angular/core").Signal<
|
|
199
|
-
readonly visibleCols: import("@angular/core").Signal<
|
|
182
|
+
readonly flatColumnsRaw: import("@angular/core").Signal<IAngularColumnDef<T>[]>;
|
|
183
|
+
readonly flatColumns: import("@angular/core").Signal<IAngularColumnDef<T>[]>;
|
|
184
|
+
readonly visibleCols: import("@angular/core").Signal<IAngularColumnDef<T>[]>;
|
|
200
185
|
readonly visibleColumnCount: import("@angular/core").Signal<number>;
|
|
201
186
|
readonly hasCheckboxCol: import("@angular/core").Signal<boolean>;
|
|
202
187
|
readonly hasRowNumbersCol: import("@angular/core").Signal<boolean>;
|
|
@@ -271,12 +256,8 @@ export declare class DataGridStateService<T> {
|
|
|
271
256
|
headerMenuPinRight(): void;
|
|
272
257
|
headerMenuUnpin(): void;
|
|
273
258
|
getState(): DataGridStateResult<T>;
|
|
274
|
-
private getEffectiveRange;
|
|
275
259
|
private onWindowMouseMove;
|
|
276
260
|
private onWindowMouseUp;
|
|
277
|
-
private resolveRangeFromMouse;
|
|
278
|
-
private applyDragAttrs;
|
|
279
|
-
private clearDragAttrs;
|
|
280
261
|
private setupFillHandleDrag;
|
|
281
262
|
}
|
|
282
263
|
export {};
|