@alaarab/ogrid-angular 2.0.6 → 2.0.7
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-datagrid-table.component.js +5 -6
- package/dist/esm/components/marching-ants-overlay.component.js +1 -1
- package/dist/esm/services/datagrid-state.service.js +80 -1
- package/dist/esm/services/ogrid.service.js +5 -1
- package/dist/types/components/base-datagrid-table.component.d.ts +2 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/services/datagrid-state.service.d.ts +37 -0
- package/dist/types/services/ogrid.service.d.ts +1 -0
- package/dist/types/types/dataGridTypes.d.ts +2 -0
- package/package.json +2 -2
|
@@ -63,6 +63,8 @@ export class BaseDataGridTableComponent {
|
|
|
63
63
|
this.showEmptyInGrid = computed(() => this.state().viewModels.showEmptyInGrid);
|
|
64
64
|
this.headerFilterInput = computed(() => this.state().viewModels.headerFilterInput);
|
|
65
65
|
this.cellDescriptorInput = computed(() => this.state().viewModels.cellDescriptorInput);
|
|
66
|
+
// Pinning state
|
|
67
|
+
this.pinnedColumnsMap = computed(() => this.state().pinning.pinnedColumns);
|
|
66
68
|
this.allowOverflowX = computed(() => {
|
|
67
69
|
const p = this.getProps();
|
|
68
70
|
if (p?.suppressHorizontalScroll)
|
|
@@ -287,16 +289,13 @@ export class BaseDataGridTableComponent {
|
|
|
287
289
|
}
|
|
288
290
|
// --- Column pinning methods ---
|
|
289
291
|
onPinColumn(columnId, side) {
|
|
290
|
-
|
|
291
|
-
props?.onColumnPinned?.(columnId, side);
|
|
292
|
+
this.state().pinning.pinColumn(columnId, side);
|
|
292
293
|
}
|
|
293
294
|
onUnpinColumn(columnId) {
|
|
294
|
-
|
|
295
|
-
props?.onColumnPinned?.(columnId, null);
|
|
295
|
+
this.state().pinning.unpinColumn(columnId);
|
|
296
296
|
}
|
|
297
297
|
isPinned(columnId) {
|
|
298
|
-
|
|
299
|
-
return props?.pinnedColumns?.[columnId];
|
|
298
|
+
return this.state().pinning.isPinned(columnId);
|
|
300
299
|
}
|
|
301
300
|
getPinState(columnId) {
|
|
302
301
|
const pinned = this.isPinned(columnId);
|
|
@@ -52,7 +52,7 @@ let MarchingAntsOverlayComponent = class MarchingAntsOverlayComponent {
|
|
|
52
52
|
const selRange = this.selectionRange();
|
|
53
53
|
const clipRange = this.copyRange() ?? this.cutRange();
|
|
54
54
|
const colOff = this.colOffset();
|
|
55
|
-
|
|
55
|
+
void this.columnSizingVersion(); // Track column resize changes
|
|
56
56
|
if (this.resizeObserver) {
|
|
57
57
|
this.resizeObserver.disconnect();
|
|
58
58
|
this.resizeObserver = null;
|
|
@@ -53,6 +53,10 @@ let DataGridStateService = class DataGridStateService {
|
|
|
53
53
|
this.autoScrollInterval = null;
|
|
54
54
|
// ResizeObserver
|
|
55
55
|
this.resizeObserver = null;
|
|
56
|
+
// Header menu state (for column pinning UI)
|
|
57
|
+
this.headerMenuIsOpenSig = signal(false);
|
|
58
|
+
this.headerMenuOpenForColumnSig = signal(null);
|
|
59
|
+
this.headerMenuAnchorElementSig = signal(null);
|
|
56
60
|
// --- Derived computed ---
|
|
57
61
|
this.propsResolved = computed(() => this.props());
|
|
58
62
|
this.cellSelection = computed(() => {
|
|
@@ -949,6 +953,59 @@ let DataGridStateService = class DataGridStateService {
|
|
|
949
953
|
this.fillDragStart = { startRow: range.startRow, startCol: range.startCol };
|
|
950
954
|
this.setupFillHandleDrag();
|
|
951
955
|
}
|
|
956
|
+
// --- Column pinning ---
|
|
957
|
+
pinColumn(columnId, side) {
|
|
958
|
+
const props = this.props();
|
|
959
|
+
props?.onColumnPinned?.(columnId, side);
|
|
960
|
+
}
|
|
961
|
+
unpinColumn(columnId) {
|
|
962
|
+
const props = this.props();
|
|
963
|
+
props?.onColumnPinned?.(columnId, null);
|
|
964
|
+
}
|
|
965
|
+
isPinned(columnId) {
|
|
966
|
+
const props = this.props();
|
|
967
|
+
return props?.pinnedColumns?.[columnId];
|
|
968
|
+
}
|
|
969
|
+
getPinState(columnId) {
|
|
970
|
+
const pinned = this.isPinned(columnId);
|
|
971
|
+
return {
|
|
972
|
+
canPinLeft: pinned !== 'left',
|
|
973
|
+
canPinRight: pinned !== 'right',
|
|
974
|
+
canUnpin: !!pinned,
|
|
975
|
+
};
|
|
976
|
+
}
|
|
977
|
+
// --- Header menu ---
|
|
978
|
+
openHeaderMenu(columnId, anchorEl) {
|
|
979
|
+
this.headerMenuOpenForColumnSig.set(columnId);
|
|
980
|
+
this.headerMenuAnchorElementSig.set(anchorEl);
|
|
981
|
+
this.headerMenuIsOpenSig.set(true);
|
|
982
|
+
}
|
|
983
|
+
closeHeaderMenu() {
|
|
984
|
+
this.headerMenuIsOpenSig.set(false);
|
|
985
|
+
this.headerMenuOpenForColumnSig.set(null);
|
|
986
|
+
this.headerMenuAnchorElementSig.set(null);
|
|
987
|
+
}
|
|
988
|
+
headerMenuPinLeft() {
|
|
989
|
+
const col = this.headerMenuOpenForColumnSig();
|
|
990
|
+
if (col && this.isPinned(col) !== 'left') {
|
|
991
|
+
this.pinColumn(col, 'left');
|
|
992
|
+
this.closeHeaderMenu();
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
headerMenuPinRight() {
|
|
996
|
+
const col = this.headerMenuOpenForColumnSig();
|
|
997
|
+
if (col && this.isPinned(col) !== 'right') {
|
|
998
|
+
this.pinColumn(col, 'right');
|
|
999
|
+
this.closeHeaderMenu();
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
headerMenuUnpin() {
|
|
1003
|
+
const col = this.headerMenuOpenForColumnSig();
|
|
1004
|
+
if (col && this.isPinned(col)) {
|
|
1005
|
+
this.unpinColumn(col);
|
|
1006
|
+
this.closeHeaderMenu();
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
952
1009
|
// --- Get state result ---
|
|
953
1010
|
getState() {
|
|
954
1011
|
const p = this.props();
|
|
@@ -1048,7 +1105,29 @@ let DataGridStateService = class DataGridStateService {
|
|
|
1048
1105
|
showEmptyInGrid: this.showEmptyInGrid(),
|
|
1049
1106
|
onCellError: p?.onCellError,
|
|
1050
1107
|
};
|
|
1051
|
-
|
|
1108
|
+
// --- Pinning ---
|
|
1109
|
+
const openForColumn = this.headerMenuOpenForColumnSig();
|
|
1110
|
+
const currentPinState = openForColumn ? (p?.pinnedColumns?.[openForColumn]) : undefined;
|
|
1111
|
+
const pinning = {
|
|
1112
|
+
pinnedColumns: p?.pinnedColumns ?? {},
|
|
1113
|
+
pinColumn: (columnId, side) => this.pinColumn(columnId, side),
|
|
1114
|
+
unpinColumn: (columnId) => this.unpinColumn(columnId),
|
|
1115
|
+
isPinned: (columnId) => this.isPinned(columnId),
|
|
1116
|
+
headerMenu: {
|
|
1117
|
+
isOpen: this.headerMenuIsOpenSig(),
|
|
1118
|
+
openForColumn,
|
|
1119
|
+
anchorElement: this.headerMenuAnchorElementSig(),
|
|
1120
|
+
open: (columnId, anchorEl) => this.openHeaderMenu(columnId, anchorEl),
|
|
1121
|
+
close: () => this.closeHeaderMenu(),
|
|
1122
|
+
handlePinLeft: () => this.headerMenuPinLeft(),
|
|
1123
|
+
handlePinRight: () => this.headerMenuPinRight(),
|
|
1124
|
+
handleUnpin: () => this.headerMenuUnpin(),
|
|
1125
|
+
canPinLeft: currentPinState !== 'left',
|
|
1126
|
+
canPinRight: currentPinState !== 'right',
|
|
1127
|
+
canUnpin: !!currentPinState,
|
|
1128
|
+
},
|
|
1129
|
+
};
|
|
1130
|
+
return { layout, rowSelection, editing, interaction, contextMenu, viewModels, pinning };
|
|
1052
1131
|
}
|
|
1053
1132
|
// --- Private helpers ---
|
|
1054
1133
|
getEffectiveRange() {
|
|
@@ -52,6 +52,7 @@ let OGridService = class OGridService {
|
|
|
52
52
|
this.suppressHorizontalScroll = signal(undefined);
|
|
53
53
|
this.editable = signal(undefined);
|
|
54
54
|
this.cellSelection = signal(undefined);
|
|
55
|
+
this.density = signal('normal');
|
|
55
56
|
this.onCellValueChanged = signal(undefined);
|
|
56
57
|
this.onUndo = signal(undefined);
|
|
57
58
|
this.onRedo = signal(undefined);
|
|
@@ -225,6 +226,7 @@ let OGridService = class OGridService {
|
|
|
225
226
|
freezeCols: this.freezeCols(),
|
|
226
227
|
editable: this.editable(),
|
|
227
228
|
cellSelection: this.cellSelection(),
|
|
229
|
+
density: this.density(),
|
|
228
230
|
onCellValueChanged: this.onCellValueChanged(),
|
|
229
231
|
onUndo: this.onUndo(),
|
|
230
232
|
onRedo: this.onRedo(),
|
|
@@ -428,7 +430,7 @@ let OGridService = class OGridService {
|
|
|
428
430
|
handleColumnPinned(columnId, pinned) {
|
|
429
431
|
this.pinnedOverrides.update((prev) => {
|
|
430
432
|
if (pinned === null) {
|
|
431
|
-
const { [columnId]:
|
|
433
|
+
const { [columnId]: _removed, ...rest } = prev;
|
|
432
434
|
return rest;
|
|
433
435
|
}
|
|
434
436
|
return { ...prev, [columnId]: pinned };
|
|
@@ -487,6 +489,8 @@ let OGridService = class OGridService {
|
|
|
487
489
|
this.editable.set(props.editable);
|
|
488
490
|
if (props.cellSelection !== undefined)
|
|
489
491
|
this.cellSelection.set(props.cellSelection);
|
|
492
|
+
if (props.density !== undefined)
|
|
493
|
+
this.density.set(props.density);
|
|
490
494
|
if (props.onCellValueChanged)
|
|
491
495
|
this.onCellValueChanged.set(props.onCellValueChanged);
|
|
492
496
|
if (props.onUndo)
|
|
@@ -13,7 +13,7 @@ import type { HeaderFilterConfig, CellRenderDescriptor } from '../utils';
|
|
|
13
13
|
* 2. Call `initBase()` in the constructor (effects require injection context)
|
|
14
14
|
* 3. Implement abstract accessors for propsInput, wrapperRef, and tableContainerRef
|
|
15
15
|
*/
|
|
16
|
-
export declare abstract class BaseDataGridTableComponent<T =
|
|
16
|
+
export declare abstract class BaseDataGridTableComponent<T = unknown> {
|
|
17
17
|
readonly stateService: DataGridStateService<T>;
|
|
18
18
|
readonly columnReorderService: ColumnReorderService<T>;
|
|
19
19
|
readonly virtualScrollService: VirtualScrollService;
|
|
@@ -103,6 +103,7 @@ export declare abstract class BaseDataGridTableComponent<T = any> {
|
|
|
103
103
|
onCellValueChanged?: ((event: import("@alaarab/ogrid-core").ICellValueChangedEvent<T>) => void) | undefined;
|
|
104
104
|
isDragging: boolean;
|
|
105
105
|
}>;
|
|
106
|
+
readonly pinnedColumnsMap: import("@angular/core").Signal<Record<string, "left" | "right">>;
|
|
106
107
|
readonly allowOverflowX: import("@angular/core").Signal<boolean>;
|
|
107
108
|
readonly selectionCellCount: import("@angular/core").Signal<number | undefined>;
|
|
108
109
|
readonly headerRows: import("@angular/core").Signal<import("@alaarab/ogrid-core").HeaderRow<T>[]>;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export { toUserLike, isInSelectionRange, normalizeSelectionRange } from './types
|
|
|
6
6
|
export { OGridService } from './services/ogrid.service';
|
|
7
7
|
export type { ColumnChooserPlacement, OGridPagination, OGridColumnChooser, OGridFilters, OGridSideBarState, } from './services/ogrid.service';
|
|
8
8
|
export { DataGridStateService } from './services/datagrid-state.service';
|
|
9
|
-
export type { DataGridLayoutState, DataGridRowSelectionState, DataGridEditingState, DataGridCellInteractionState, DataGridContextMenuState, DataGridViewModelState, DataGridStateResult, } from './services/datagrid-state.service';
|
|
9
|
+
export type { DataGridLayoutState, DataGridRowSelectionState, DataGridEditingState, DataGridCellInteractionState, DataGridContextMenuState, DataGridViewModelState, DataGridPinningState, DataGridStateResult, } from './services/datagrid-state.service';
|
|
10
10
|
export { ColumnReorderService } from './services/column-reorder.service';
|
|
11
11
|
export { VirtualScrollService } from './services/virtual-scroll.service';
|
|
12
12
|
export type { IVirtualScrollConfig } from './services/virtual-scroll.service';
|
|
@@ -115,6 +115,26 @@ export interface DataGridViewModelState<T> {
|
|
|
115
115
|
showEmptyInGrid: boolean;
|
|
116
116
|
onCellError?: (error: Error) => void;
|
|
117
117
|
}
|
|
118
|
+
/** Column pinning state and column header menu. */
|
|
119
|
+
export interface DataGridPinningState {
|
|
120
|
+
pinnedColumns: Record<string, 'left' | 'right'>;
|
|
121
|
+
pinColumn: (columnId: string, side: 'left' | 'right') => void;
|
|
122
|
+
unpinColumn: (columnId: string) => void;
|
|
123
|
+
isPinned: (columnId: string) => 'left' | 'right' | undefined;
|
|
124
|
+
headerMenu: {
|
|
125
|
+
isOpen: boolean;
|
|
126
|
+
openForColumn: string | null;
|
|
127
|
+
anchorElement: HTMLElement | null;
|
|
128
|
+
open: (columnId: string, anchorEl: HTMLElement) => void;
|
|
129
|
+
close: () => void;
|
|
130
|
+
handlePinLeft: () => void;
|
|
131
|
+
handlePinRight: () => void;
|
|
132
|
+
handleUnpin: () => void;
|
|
133
|
+
canPinLeft: boolean;
|
|
134
|
+
canPinRight: boolean;
|
|
135
|
+
canUnpin: boolean;
|
|
136
|
+
};
|
|
137
|
+
}
|
|
118
138
|
export interface DataGridStateResult<T> {
|
|
119
139
|
layout: DataGridLayoutState<T>;
|
|
120
140
|
rowSelection: DataGridRowSelectionState;
|
|
@@ -122,6 +142,7 @@ export interface DataGridStateResult<T> {
|
|
|
122
142
|
interaction: DataGridCellInteractionState;
|
|
123
143
|
contextMenu: DataGridContextMenuState;
|
|
124
144
|
viewModels: DataGridViewModelState<T>;
|
|
145
|
+
pinning: DataGridPinningState;
|
|
125
146
|
}
|
|
126
147
|
/**
|
|
127
148
|
* Single orchestration service for DataGridTable. Takes grid props,
|
|
@@ -161,6 +182,9 @@ export declare class DataGridStateService<T> {
|
|
|
161
182
|
private lastMousePos;
|
|
162
183
|
private autoScrollInterval;
|
|
163
184
|
private resizeObserver;
|
|
185
|
+
private readonly headerMenuIsOpenSig;
|
|
186
|
+
private readonly headerMenuOpenForColumnSig;
|
|
187
|
+
private readonly headerMenuAnchorElementSig;
|
|
164
188
|
private readonly propsResolved;
|
|
165
189
|
readonly cellSelection: import("@angular/core").Signal<boolean>;
|
|
166
190
|
private readonly wrappedOnCellValueChanged;
|
|
@@ -227,6 +251,19 @@ export declare class DataGridStateService<T> {
|
|
|
227
251
|
redo(): void;
|
|
228
252
|
handleGridKeyDown(e: KeyboardEvent): void;
|
|
229
253
|
handleFillHandleMouseDown(e: MouseEvent): void;
|
|
254
|
+
pinColumn(columnId: string, side: 'left' | 'right'): void;
|
|
255
|
+
unpinColumn(columnId: string): void;
|
|
256
|
+
isPinned(columnId: string): 'left' | 'right' | undefined;
|
|
257
|
+
getPinState(columnId: string): {
|
|
258
|
+
canPinLeft: boolean;
|
|
259
|
+
canPinRight: boolean;
|
|
260
|
+
canUnpin: boolean;
|
|
261
|
+
};
|
|
262
|
+
openHeaderMenu(columnId: string, anchorEl: HTMLElement): void;
|
|
263
|
+
closeHeaderMenu(): void;
|
|
264
|
+
headerMenuPinLeft(): void;
|
|
265
|
+
headerMenuPinRight(): void;
|
|
266
|
+
headerMenuUnpin(): void;
|
|
230
267
|
getState(): DataGridStateResult<T>;
|
|
231
268
|
private getEffectiveRange;
|
|
232
269
|
private onWindowMouseMove;
|
|
@@ -86,6 +86,7 @@ export declare class OGridService<T> {
|
|
|
86
86
|
readonly suppressHorizontalScroll: import("@angular/core").WritableSignal<boolean | undefined>;
|
|
87
87
|
readonly editable: import("@angular/core").WritableSignal<boolean | undefined>;
|
|
88
88
|
readonly cellSelection: import("@angular/core").WritableSignal<boolean | undefined>;
|
|
89
|
+
readonly density: import("@angular/core").WritableSignal<"compact" | "normal" | "comfortable">;
|
|
89
90
|
readonly onCellValueChanged: import("@angular/core").WritableSignal<((event: ICellValueChangedEvent<T>) => void) | undefined>;
|
|
90
91
|
readonly onUndo: import("@angular/core").WritableSignal<(() => void) | undefined>;
|
|
91
92
|
readonly onRedo: import("@angular/core").WritableSignal<(() => void) | undefined>;
|
|
@@ -32,6 +32,7 @@ interface IOGridBaseProps<T> {
|
|
|
32
32
|
freezeCols?: number;
|
|
33
33
|
editable?: boolean;
|
|
34
34
|
cellSelection?: boolean;
|
|
35
|
+
density?: 'compact' | 'normal' | 'comfortable';
|
|
35
36
|
onCellValueChanged?: (event: ICellValueChangedEvent<T>) => void;
|
|
36
37
|
onUndo?: () => void;
|
|
37
38
|
onRedo?: () => void;
|
|
@@ -99,6 +100,7 @@ export interface IOGridDataGridProps<T> {
|
|
|
99
100
|
loadingMessage?: string;
|
|
100
101
|
editable?: boolean;
|
|
101
102
|
cellSelection?: boolean;
|
|
103
|
+
density?: 'compact' | 'normal' | 'comfortable';
|
|
102
104
|
onCellValueChanged?: (event: ICellValueChangedEvent<T>) => void;
|
|
103
105
|
onUndo?: () => void;
|
|
104
106
|
onRedo?: () => void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alaarab/ogrid-angular",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.7",
|
|
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",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"files": ["dist", "README.md", "LICENSE"],
|
|
23
23
|
"engines": { "node": ">=18" },
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@alaarab/ogrid-core": "2.0.
|
|
25
|
+
"@alaarab/ogrid-core": "2.0.7"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"@angular/core": "^21.0.0",
|