@alaarab/ogrid-angular 2.0.8 → 2.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/components/base-column-chooser.component.js +78 -0
- package/dist/esm/components/base-column-header-filter.component.js +266 -0
- package/dist/esm/components/base-datagrid-table.component.js +116 -5
- package/dist/esm/components/base-pagination-controls.component.js +72 -0
- package/dist/esm/components/empty-state.component.js +22 -10
- package/dist/esm/components/grid-context-menu.component.js +65 -26
- package/dist/esm/components/marching-ants-overlay.component.js +78 -69
- package/dist/esm/components/ogrid-layout.component.js +32 -18
- package/dist/esm/components/sidebar.component.js +45 -42
- package/dist/esm/components/status-bar.component.js +43 -23
- package/dist/esm/index.js +3 -0
- package/dist/esm/services/ogrid.service.js +14 -4
- package/dist/types/components/base-column-chooser.component.d.ts +37 -0
- package/dist/types/components/base-column-header-filter.component.d.ts +90 -0
- package/dist/types/components/base-datagrid-table.component.d.ts +19 -0
- package/dist/types/components/base-pagination-controls.component.d.ts +34 -0
- package/dist/types/components/empty-state.component.d.ts +5 -4
- package/dist/types/components/grid-context-menu.component.d.ts +16 -16
- package/dist/types/components/marching-ants-overlay.component.d.ts +14 -14
- package/dist/types/components/ogrid-layout.component.d.ts +5 -5
- package/dist/types/components/sidebar.component.d.ts +1 -1
- package/dist/types/components/status-bar.component.d.ts +10 -10
- package/dist/types/index.d.ts +5 -0
- package/package.json +2 -2
|
@@ -4,30 +4,27 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { Component,
|
|
7
|
+
import { Component, Input, Output, EventEmitter, ViewChild, DestroyRef, inject } from '@angular/core';
|
|
8
8
|
import { CommonModule } from '@angular/common';
|
|
9
9
|
import { GRID_CONTEXT_MENU_ITEMS, formatShortcut } from '@alaarab/ogrid-core';
|
|
10
10
|
let GridContextMenuComponent = class GridContextMenuComponent {
|
|
11
11
|
constructor() {
|
|
12
12
|
this.destroyRef = inject(DestroyRef);
|
|
13
|
-
this.
|
|
14
|
-
this.
|
|
15
|
-
this.
|
|
16
|
-
this.
|
|
17
|
-
this.
|
|
18
|
-
this.
|
|
19
|
-
this.
|
|
20
|
-
this.
|
|
21
|
-
this.
|
|
22
|
-
this.
|
|
23
|
-
this.
|
|
24
|
-
this.redoAction = output();
|
|
25
|
-
this.close = output();
|
|
26
|
-
this.menuRef = viewChild('menuRef');
|
|
13
|
+
this.hasSelection = false;
|
|
14
|
+
this.canUndoProp = false;
|
|
15
|
+
this.canRedoProp = false;
|
|
16
|
+
this.classNames = undefined;
|
|
17
|
+
this.copy = new EventEmitter();
|
|
18
|
+
this.cut = new EventEmitter();
|
|
19
|
+
this.paste = new EventEmitter();
|
|
20
|
+
this.selectAll = new EventEmitter();
|
|
21
|
+
this.undoAction = new EventEmitter();
|
|
22
|
+
this.redoAction = new EventEmitter();
|
|
23
|
+
this.close = new EventEmitter();
|
|
27
24
|
this.menuItems = GRID_CONTEXT_MENU_ITEMS;
|
|
28
25
|
this.formatShortcutFn = formatShortcut;
|
|
29
26
|
this.clickOutsideHandler = (e) => {
|
|
30
|
-
const el = this.menuRef
|
|
27
|
+
const el = this.menuRef?.nativeElement;
|
|
31
28
|
if (el && !el.contains(e.target))
|
|
32
29
|
this.close.emit();
|
|
33
30
|
};
|
|
@@ -44,11 +41,11 @@ let GridContextMenuComponent = class GridContextMenuComponent {
|
|
|
44
41
|
});
|
|
45
42
|
}
|
|
46
43
|
isDisabled(item) {
|
|
47
|
-
if (item.disabledWhenNoSelection && !this.hasSelection
|
|
44
|
+
if (item.disabledWhenNoSelection && !this.hasSelection)
|
|
48
45
|
return true;
|
|
49
|
-
if (item.id === 'undo' && !this.canUndoProp
|
|
46
|
+
if (item.id === 'undo' && !this.canUndoProp)
|
|
50
47
|
return true;
|
|
51
|
-
if (item.id === 'redo' && !this.canRedoProp
|
|
48
|
+
if (item.id === 'redo' && !this.canRedoProp)
|
|
52
49
|
return true;
|
|
53
50
|
return false;
|
|
54
51
|
}
|
|
@@ -76,6 +73,48 @@ let GridContextMenuComponent = class GridContextMenuComponent {
|
|
|
76
73
|
this.close.emit();
|
|
77
74
|
}
|
|
78
75
|
};
|
|
76
|
+
__decorate([
|
|
77
|
+
Input({ required: true })
|
|
78
|
+
], GridContextMenuComponent.prototype, "x", void 0);
|
|
79
|
+
__decorate([
|
|
80
|
+
Input({ required: true })
|
|
81
|
+
], GridContextMenuComponent.prototype, "y", void 0);
|
|
82
|
+
__decorate([
|
|
83
|
+
Input()
|
|
84
|
+
], GridContextMenuComponent.prototype, "hasSelection", void 0);
|
|
85
|
+
__decorate([
|
|
86
|
+
Input()
|
|
87
|
+
], GridContextMenuComponent.prototype, "canUndoProp", void 0);
|
|
88
|
+
__decorate([
|
|
89
|
+
Input()
|
|
90
|
+
], GridContextMenuComponent.prototype, "canRedoProp", void 0);
|
|
91
|
+
__decorate([
|
|
92
|
+
Input()
|
|
93
|
+
], GridContextMenuComponent.prototype, "classNames", void 0);
|
|
94
|
+
__decorate([
|
|
95
|
+
Output()
|
|
96
|
+
], GridContextMenuComponent.prototype, "copy", void 0);
|
|
97
|
+
__decorate([
|
|
98
|
+
Output()
|
|
99
|
+
], GridContextMenuComponent.prototype, "cut", void 0);
|
|
100
|
+
__decorate([
|
|
101
|
+
Output()
|
|
102
|
+
], GridContextMenuComponent.prototype, "paste", void 0);
|
|
103
|
+
__decorate([
|
|
104
|
+
Output()
|
|
105
|
+
], GridContextMenuComponent.prototype, "selectAll", void 0);
|
|
106
|
+
__decorate([
|
|
107
|
+
Output()
|
|
108
|
+
], GridContextMenuComponent.prototype, "undoAction", void 0);
|
|
109
|
+
__decorate([
|
|
110
|
+
Output()
|
|
111
|
+
], GridContextMenuComponent.prototype, "redoAction", void 0);
|
|
112
|
+
__decorate([
|
|
113
|
+
Output()
|
|
114
|
+
], GridContextMenuComponent.prototype, "close", void 0);
|
|
115
|
+
__decorate([
|
|
116
|
+
ViewChild('menuRef')
|
|
117
|
+
], GridContextMenuComponent.prototype, "menuRef", void 0);
|
|
79
118
|
GridContextMenuComponent = __decorate([
|
|
80
119
|
Component({
|
|
81
120
|
selector: 'ogrid-context-menu',
|
|
@@ -84,25 +123,25 @@ GridContextMenuComponent = __decorate([
|
|
|
84
123
|
template: `
|
|
85
124
|
<div
|
|
86
125
|
#menuRef
|
|
87
|
-
[class]="classNames
|
|
126
|
+
[class]="classNames?.contextMenu ?? ''"
|
|
88
127
|
role="menu"
|
|
89
|
-
[style.left.px]="x
|
|
90
|
-
[style.top.px]="y
|
|
128
|
+
[style.left.px]="x"
|
|
129
|
+
[style.top.px]="y"
|
|
91
130
|
aria-label="Grid context menu"
|
|
92
131
|
>
|
|
93
132
|
@for (item of menuItems; track item.id) {
|
|
94
133
|
@if (item.dividerBefore) {
|
|
95
|
-
<div [class]="classNames
|
|
134
|
+
<div [class]="classNames?.contextMenuDivider ?? ''"></div>
|
|
96
135
|
}
|
|
97
136
|
<button
|
|
98
137
|
type="button"
|
|
99
|
-
[class]="classNames
|
|
138
|
+
[class]="classNames?.contextMenuItem ?? ''"
|
|
100
139
|
(click)="onItemClick(item.id)"
|
|
101
140
|
[disabled]="isDisabled(item)"
|
|
102
141
|
>
|
|
103
|
-
<span [class]="classNames
|
|
142
|
+
<span [class]="classNames?.contextMenuItemLabel ?? ''">{{ item.label }}</span>
|
|
104
143
|
@if (item.shortcut) {
|
|
105
|
-
<span [class]="classNames
|
|
144
|
+
<span [class]="classNames?.contextMenuItemShortcut ?? ''">
|
|
106
145
|
{{ formatShortcutFn(item.shortcut) }}
|
|
107
146
|
</span>
|
|
108
147
|
}
|
|
@@ -4,81 +4,25 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { Component,
|
|
7
|
+
import { Component, Input, signal, DestroyRef, inject } from '@angular/core';
|
|
8
8
|
import { CommonModule } from '@angular/common';
|
|
9
|
-
|
|
10
|
-
const startGlobalCol = range.startCol + colOffset;
|
|
11
|
-
const endGlobalCol = range.endCol + colOffset;
|
|
12
|
-
const topLeft = container.querySelector(`[data-row-index="${range.startRow}"][data-col-index="${startGlobalCol}"]`);
|
|
13
|
-
const bottomRight = container.querySelector(`[data-row-index="${range.endRow}"][data-col-index="${endGlobalCol}"]`);
|
|
14
|
-
if (!topLeft || !bottomRight)
|
|
15
|
-
return null;
|
|
16
|
-
const cRect = container.getBoundingClientRect();
|
|
17
|
-
const tlRect = topLeft.getBoundingClientRect();
|
|
18
|
-
const brRect = bottomRight.getBoundingClientRect();
|
|
19
|
-
return {
|
|
20
|
-
top: tlRect.top - cRect.top,
|
|
21
|
-
left: tlRect.left - cRect.left,
|
|
22
|
-
width: brRect.right - tlRect.left,
|
|
23
|
-
height: brRect.bottom - tlRect.top,
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
function ensureKeyframes() {
|
|
27
|
-
if (typeof document === 'undefined')
|
|
28
|
-
return;
|
|
29
|
-
if (document.getElementById('ogrid-marching-ants-keyframes'))
|
|
30
|
-
return;
|
|
31
|
-
const style = document.createElement('style');
|
|
32
|
-
style.id = 'ogrid-marching-ants-keyframes';
|
|
33
|
-
style.textContent = '@keyframes ogrid-marching-ants{to{stroke-dashoffset:-8}}';
|
|
34
|
-
document.head.appendChild(style);
|
|
35
|
-
}
|
|
9
|
+
import { measureRange, injectGlobalStyles } from '@alaarab/ogrid-core';
|
|
36
10
|
let MarchingAntsOverlayComponent = class MarchingAntsOverlayComponent {
|
|
37
11
|
constructor() {
|
|
38
12
|
this.destroyRef = inject(DestroyRef);
|
|
39
|
-
this.
|
|
40
|
-
this.
|
|
41
|
-
this.
|
|
42
|
-
this.
|
|
43
|
-
this.
|
|
44
|
-
this.
|
|
13
|
+
this.selectionRange = null;
|
|
14
|
+
this.copyRange = null;
|
|
15
|
+
this.cutRange = null;
|
|
16
|
+
this.colOffset = 0;
|
|
17
|
+
this.columnSizingVersion = 0;
|
|
18
|
+
this.items = [];
|
|
19
|
+
this.visibleColumns = undefined;
|
|
20
|
+
this.columnOrder = undefined;
|
|
45
21
|
this.selRect = signal(null);
|
|
46
22
|
this.clipRect = signal(null);
|
|
47
23
|
this.rafId = 0;
|
|
48
24
|
this.resizeObserver = null;
|
|
49
|
-
|
|
50
|
-
effect(() => {
|
|
51
|
-
const container = this.containerEl();
|
|
52
|
-
const selRange = this.selectionRange();
|
|
53
|
-
const clipRange = this.copyRange() ?? this.cutRange();
|
|
54
|
-
const colOff = this.colOffset();
|
|
55
|
-
void this.columnSizingVersion(); // Track column resize changes
|
|
56
|
-
if (this.resizeObserver) {
|
|
57
|
-
this.resizeObserver.disconnect();
|
|
58
|
-
this.resizeObserver = null;
|
|
59
|
-
}
|
|
60
|
-
if (!selRange && !clipRange) {
|
|
61
|
-
this.selRect.set(null);
|
|
62
|
-
this.clipRect.set(null);
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
const measureAll = () => {
|
|
66
|
-
if (!container) {
|
|
67
|
-
this.selRect.set(null);
|
|
68
|
-
this.clipRect.set(null);
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
this.selRect.set(selRange ? measureRange(container, selRange, colOff) : null);
|
|
72
|
-
this.clipRect.set(clipRange ? measureRange(container, clipRange, colOff) : null);
|
|
73
|
-
};
|
|
74
|
-
if (this.rafId)
|
|
75
|
-
cancelAnimationFrame(this.rafId);
|
|
76
|
-
this.rafId = requestAnimationFrame(measureAll);
|
|
77
|
-
if (container) {
|
|
78
|
-
this.resizeObserver = new ResizeObserver(measureAll);
|
|
79
|
-
this.resizeObserver.observe(container);
|
|
80
|
-
}
|
|
81
|
-
});
|
|
25
|
+
injectGlobalStyles('ogrid-marching-ants-keyframes', '@keyframes ogrid-marching-ants{to{stroke-dashoffset:-8}}');
|
|
82
26
|
this.destroyRef.onDestroy(() => {
|
|
83
27
|
if (this.rafId)
|
|
84
28
|
cancelAnimationFrame(this.rafId);
|
|
@@ -86,9 +30,47 @@ let MarchingAntsOverlayComponent = class MarchingAntsOverlayComponent {
|
|
|
86
30
|
this.resizeObserver.disconnect();
|
|
87
31
|
});
|
|
88
32
|
}
|
|
33
|
+
ngOnChanges(_changes) {
|
|
34
|
+
this.recalculate();
|
|
35
|
+
}
|
|
36
|
+
recalculate() {
|
|
37
|
+
const container = this.containerEl;
|
|
38
|
+
const selRange = this.selectionRange;
|
|
39
|
+
const clipRange = this.copyRange ?? this.cutRange;
|
|
40
|
+
const colOff = this.colOffset;
|
|
41
|
+
void this.columnSizingVersion; // Track column resize changes
|
|
42
|
+
void this.items; // Track data changes (sorting)
|
|
43
|
+
void this.visibleColumns; // Track column visibility changes
|
|
44
|
+
void this.columnOrder; // Track column reordering
|
|
45
|
+
if (this.resizeObserver) {
|
|
46
|
+
this.resizeObserver.disconnect();
|
|
47
|
+
this.resizeObserver = null;
|
|
48
|
+
}
|
|
49
|
+
if (!selRange && !clipRange) {
|
|
50
|
+
this.selRect.set(null);
|
|
51
|
+
this.clipRect.set(null);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const measureAll = () => {
|
|
55
|
+
if (!container) {
|
|
56
|
+
this.selRect.set(null);
|
|
57
|
+
this.clipRect.set(null);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
this.selRect.set(selRange ? measureRange(container, selRange, colOff) : null);
|
|
61
|
+
this.clipRect.set(clipRange ? measureRange(container, clipRange, colOff) : null);
|
|
62
|
+
};
|
|
63
|
+
if (this.rafId)
|
|
64
|
+
cancelAnimationFrame(this.rafId);
|
|
65
|
+
this.rafId = requestAnimationFrame(measureAll);
|
|
66
|
+
if (container) {
|
|
67
|
+
this.resizeObserver = new ResizeObserver(measureAll);
|
|
68
|
+
this.resizeObserver.observe(container);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
89
71
|
clipRangeMatchesSel() {
|
|
90
|
-
const selRange = this.selectionRange
|
|
91
|
-
const clipRange = this.copyRange
|
|
72
|
+
const selRange = this.selectionRange;
|
|
73
|
+
const clipRange = this.copyRange ?? this.cutRange;
|
|
92
74
|
return selRange != null && clipRange != null &&
|
|
93
75
|
selRange.startRow === clipRange.startRow &&
|
|
94
76
|
selRange.startCol === clipRange.startCol &&
|
|
@@ -99,6 +81,33 @@ let MarchingAntsOverlayComponent = class MarchingAntsOverlayComponent {
|
|
|
99
81
|
return Math.max(0, n);
|
|
100
82
|
}
|
|
101
83
|
};
|
|
84
|
+
__decorate([
|
|
85
|
+
Input({ required: true })
|
|
86
|
+
], MarchingAntsOverlayComponent.prototype, "containerEl", void 0);
|
|
87
|
+
__decorate([
|
|
88
|
+
Input()
|
|
89
|
+
], MarchingAntsOverlayComponent.prototype, "selectionRange", void 0);
|
|
90
|
+
__decorate([
|
|
91
|
+
Input()
|
|
92
|
+
], MarchingAntsOverlayComponent.prototype, "copyRange", void 0);
|
|
93
|
+
__decorate([
|
|
94
|
+
Input()
|
|
95
|
+
], MarchingAntsOverlayComponent.prototype, "cutRange", void 0);
|
|
96
|
+
__decorate([
|
|
97
|
+
Input()
|
|
98
|
+
], MarchingAntsOverlayComponent.prototype, "colOffset", void 0);
|
|
99
|
+
__decorate([
|
|
100
|
+
Input()
|
|
101
|
+
], MarchingAntsOverlayComponent.prototype, "columnSizingVersion", void 0);
|
|
102
|
+
__decorate([
|
|
103
|
+
Input()
|
|
104
|
+
], MarchingAntsOverlayComponent.prototype, "items", void 0);
|
|
105
|
+
__decorate([
|
|
106
|
+
Input()
|
|
107
|
+
], MarchingAntsOverlayComponent.prototype, "visibleColumns", void 0);
|
|
108
|
+
__decorate([
|
|
109
|
+
Input()
|
|
110
|
+
], MarchingAntsOverlayComponent.prototype, "columnOrder", void 0);
|
|
102
111
|
MarchingAntsOverlayComponent = __decorate([
|
|
103
112
|
Component({
|
|
104
113
|
selector: 'ogrid-marching-ants-overlay',
|
|
@@ -4,20 +4,34 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { Component,
|
|
7
|
+
import { Component, Input } from '@angular/core';
|
|
8
8
|
import { CommonModule } from '@angular/common';
|
|
9
9
|
import { SideBarComponent } from './sidebar.component';
|
|
10
10
|
import { GRID_BORDER_RADIUS } from '@alaarab/ogrid-core';
|
|
11
11
|
let OGridLayoutComponent = class OGridLayoutComponent {
|
|
12
12
|
constructor() {
|
|
13
|
-
this.
|
|
14
|
-
this.
|
|
15
|
-
this.
|
|
16
|
-
this.
|
|
17
|
-
this.sideBar = input(null);
|
|
13
|
+
this.hasToolbar = false;
|
|
14
|
+
this.hasToolbarBelow = false;
|
|
15
|
+
this.hasPagination = false;
|
|
16
|
+
this.sideBar = null;
|
|
18
17
|
this.borderRadius = GRID_BORDER_RADIUS;
|
|
19
18
|
}
|
|
20
19
|
};
|
|
20
|
+
__decorate([
|
|
21
|
+
Input()
|
|
22
|
+
], OGridLayoutComponent.prototype, "className", void 0);
|
|
23
|
+
__decorate([
|
|
24
|
+
Input()
|
|
25
|
+
], OGridLayoutComponent.prototype, "hasToolbar", void 0);
|
|
26
|
+
__decorate([
|
|
27
|
+
Input()
|
|
28
|
+
], OGridLayoutComponent.prototype, "hasToolbarBelow", void 0);
|
|
29
|
+
__decorate([
|
|
30
|
+
Input()
|
|
31
|
+
], OGridLayoutComponent.prototype, "hasPagination", void 0);
|
|
32
|
+
__decorate([
|
|
33
|
+
Input()
|
|
34
|
+
], OGridLayoutComponent.prototype, "sideBar", void 0);
|
|
21
35
|
OGridLayoutComponent = __decorate([
|
|
22
36
|
Component({
|
|
23
37
|
selector: 'ogrid-layout',
|
|
@@ -44,21 +58,21 @@ OGridLayoutComponent = __decorate([
|
|
|
44
58
|
padding: 6px 12px; background: var(--ogrid-header-bg, #f5f5f5);
|
|
45
59
|
}
|
|
46
60
|
.ogrid-layout-grid-area { width: 100%; min-width: 0; min-height: 0; flex: 1; display: flex; }
|
|
47
|
-
.ogrid-layout-grid-content { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; }
|
|
61
|
+
.ogrid-layout-grid-content { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }
|
|
48
62
|
.ogrid-layout-footer {
|
|
49
63
|
border-top: 1px solid var(--ogrid-border, #e0e0e0);
|
|
50
64
|
background: var(--ogrid-header-bg, #f5f5f5); padding: 6px 12px;
|
|
51
65
|
}
|
|
52
66
|
`],
|
|
53
67
|
template: `
|
|
54
|
-
<div [class]="(className
|
|
68
|
+
<div [class]="(className ?? '') + ' ogrid-layout-root'">
|
|
55
69
|
<div class="ogrid-layout-container" [style.border-radius.px]="borderRadius">
|
|
56
70
|
<!-- Toolbar strip -->
|
|
57
|
-
@if (hasToolbar
|
|
71
|
+
@if (hasToolbar) {
|
|
58
72
|
<div
|
|
59
73
|
class="ogrid-layout-toolbar"
|
|
60
|
-
[class.ogrid-layout-toolbar--has-below]="hasToolbarBelow
|
|
61
|
-
[class.ogrid-layout-toolbar--no-below]="!hasToolbarBelow
|
|
74
|
+
[class.ogrid-layout-toolbar--has-below]="hasToolbarBelow"
|
|
75
|
+
[class.ogrid-layout-toolbar--no-below]="!hasToolbarBelow"
|
|
62
76
|
>
|
|
63
77
|
<div class="ogrid-layout-toolbar-left">
|
|
64
78
|
<ng-content select="[toolbar]"></ng-content>
|
|
@@ -70,23 +84,23 @@ OGridLayoutComponent = __decorate([
|
|
|
70
84
|
}
|
|
71
85
|
|
|
72
86
|
<!-- Secondary toolbar row -->
|
|
73
|
-
@if (hasToolbarBelow
|
|
87
|
+
@if (hasToolbarBelow) {
|
|
74
88
|
<div class="ogrid-layout-toolbar-below">
|
|
75
89
|
<ng-content select="[toolbarBelow]"></ng-content>
|
|
76
90
|
</div>
|
|
77
91
|
}
|
|
78
92
|
|
|
79
93
|
<!-- Grid area -->
|
|
80
|
-
@if (sideBar
|
|
94
|
+
@if (sideBar) {
|
|
81
95
|
<div class="ogrid-layout-grid-area">
|
|
82
|
-
@if (sideBar
|
|
83
|
-
<ogrid-sidebar [sideBarProps]="sideBar
|
|
96
|
+
@if (sideBar?.position === 'left') {
|
|
97
|
+
<ogrid-sidebar [sideBarProps]="sideBar"></ogrid-sidebar>
|
|
84
98
|
}
|
|
85
99
|
<div class="ogrid-layout-grid-content">
|
|
86
100
|
<ng-content></ng-content>
|
|
87
101
|
</div>
|
|
88
|
-
@if (sideBar
|
|
89
|
-
<ogrid-sidebar [sideBarProps]="sideBar
|
|
102
|
+
@if (sideBar?.position !== 'left') {
|
|
103
|
+
<ogrid-sidebar [sideBarProps]="sideBar"></ogrid-sidebar>
|
|
90
104
|
}
|
|
91
105
|
</div>
|
|
92
106
|
} @else {
|
|
@@ -96,7 +110,7 @@ OGridLayoutComponent = __decorate([
|
|
|
96
110
|
}
|
|
97
111
|
|
|
98
112
|
<!-- Footer strip (pagination) -->
|
|
99
|
-
@if (hasPagination
|
|
113
|
+
@if (hasPagination) {
|
|
100
114
|
<div class="ogrid-layout-footer">
|
|
101
115
|
<ng-content select="[pagination]"></ng-content>
|
|
102
116
|
</div>
|
|
@@ -4,31 +4,31 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { Component,
|
|
7
|
+
import { Component, Input } from '@angular/core';
|
|
8
8
|
import { CommonModule } from '@angular/common';
|
|
9
9
|
const PANEL_WIDTH = 240;
|
|
10
10
|
const TAB_WIDTH = 36;
|
|
11
11
|
const PANEL_LABELS = { columns: 'Columns', filters: 'Filters' };
|
|
12
12
|
let SideBarComponent = class SideBarComponent {
|
|
13
13
|
constructor() {
|
|
14
|
-
this.sideBarProps =
|
|
14
|
+
this.sideBarProps = null;
|
|
15
15
|
this.panelLabels = PANEL_LABELS;
|
|
16
16
|
this.tabWidth = TAB_WIDTH;
|
|
17
17
|
this.panelWidth = PANEL_WIDTH;
|
|
18
18
|
}
|
|
19
19
|
onTabClick(panel) {
|
|
20
|
-
const props = this.sideBarProps
|
|
20
|
+
const props = this.sideBarProps;
|
|
21
21
|
if (props)
|
|
22
22
|
props.onPanelChange(props.activePanel === panel ? null : panel);
|
|
23
23
|
}
|
|
24
24
|
allVisible() {
|
|
25
|
-
const props = this.sideBarProps
|
|
25
|
+
const props = this.sideBarProps;
|
|
26
26
|
if (!props)
|
|
27
27
|
return false;
|
|
28
28
|
return props.columns.every((c) => props.visibleColumns.has(c.columnId));
|
|
29
29
|
}
|
|
30
30
|
onSelectAll() {
|
|
31
|
-
const props = this.sideBarProps
|
|
31
|
+
const props = this.sideBarProps;
|
|
32
32
|
if (!props)
|
|
33
33
|
return;
|
|
34
34
|
const next = new Set(props.visibleColumns);
|
|
@@ -36,7 +36,7 @@ let SideBarComponent = class SideBarComponent {
|
|
|
36
36
|
props.onSetVisibleColumns(next);
|
|
37
37
|
}
|
|
38
38
|
onClearAll() {
|
|
39
|
-
const props = this.sideBarProps
|
|
39
|
+
const props = this.sideBarProps;
|
|
40
40
|
if (!props)
|
|
41
41
|
return;
|
|
42
42
|
const next = new Set();
|
|
@@ -47,52 +47,55 @@ let SideBarComponent = class SideBarComponent {
|
|
|
47
47
|
props.onSetVisibleColumns(next);
|
|
48
48
|
}
|
|
49
49
|
onVisibilityChange(columnKey, visible) {
|
|
50
|
-
this.sideBarProps
|
|
50
|
+
this.sideBarProps?.onVisibilityChange(columnKey, visible);
|
|
51
51
|
}
|
|
52
52
|
getTextFilterValue(filterField) {
|
|
53
|
-
const filters = this.sideBarProps
|
|
53
|
+
const filters = this.sideBarProps?.filters;
|
|
54
54
|
const fv = filters?.[filterField];
|
|
55
55
|
return fv?.type === 'text' ? fv.value : '';
|
|
56
56
|
}
|
|
57
57
|
onTextFilterChange(filterField, value) {
|
|
58
|
-
this.sideBarProps
|
|
58
|
+
this.sideBarProps?.onFilterChange(filterField, value ? { type: 'text', value } : undefined);
|
|
59
59
|
}
|
|
60
60
|
getDateFrom(filterField) {
|
|
61
|
-
const fv = this.sideBarProps
|
|
61
|
+
const fv = this.sideBarProps?.filters?.[filterField];
|
|
62
62
|
return fv?.type === 'date' ? (fv.value.from ?? '') : '';
|
|
63
63
|
}
|
|
64
64
|
getDateTo(filterField) {
|
|
65
|
-
const fv = this.sideBarProps
|
|
65
|
+
const fv = this.sideBarProps?.filters?.[filterField];
|
|
66
66
|
return fv?.type === 'date' ? (fv.value.to ?? '') : '';
|
|
67
67
|
}
|
|
68
68
|
onDateFromChange(filterField, value) {
|
|
69
|
-
const fv = this.sideBarProps
|
|
69
|
+
const fv = this.sideBarProps?.filters?.[filterField];
|
|
70
70
|
const existing = fv?.type === 'date' ? fv.value : {};
|
|
71
71
|
const from = value || undefined;
|
|
72
72
|
const to = existing.to;
|
|
73
|
-
this.sideBarProps
|
|
73
|
+
this.sideBarProps?.onFilterChange(filterField, from || to ? { type: 'date', value: { from, to } } : undefined);
|
|
74
74
|
}
|
|
75
75
|
onDateToChange(filterField, value) {
|
|
76
|
-
const fv = this.sideBarProps
|
|
76
|
+
const fv = this.sideBarProps?.filters?.[filterField];
|
|
77
77
|
const existing = fv?.type === 'date' ? fv.value : {};
|
|
78
78
|
const to = value || undefined;
|
|
79
79
|
const from = existing.from;
|
|
80
|
-
this.sideBarProps
|
|
80
|
+
this.sideBarProps?.onFilterChange(filterField, from || to ? { type: 'date', value: { from, to } } : undefined);
|
|
81
81
|
}
|
|
82
82
|
getFilterOptions(filterField) {
|
|
83
|
-
return this.sideBarProps
|
|
83
|
+
return this.sideBarProps?.filterOptions?.[filterField] ?? [];
|
|
84
84
|
}
|
|
85
85
|
isMultiSelectChecked(filterField, opt) {
|
|
86
|
-
const fv = this.sideBarProps
|
|
86
|
+
const fv = this.sideBarProps?.filters?.[filterField];
|
|
87
87
|
return fv?.type === 'multiSelect' ? fv.value.includes(opt) : false;
|
|
88
88
|
}
|
|
89
89
|
onMultiSelectChange(filterField, opt, checked) {
|
|
90
|
-
const fv = this.sideBarProps
|
|
90
|
+
const fv = this.sideBarProps?.filters?.[filterField];
|
|
91
91
|
const current = fv?.type === 'multiSelect' ? fv.value : [];
|
|
92
92
|
const next = checked ? [...current, opt] : current.filter((v) => v !== opt);
|
|
93
|
-
this.sideBarProps
|
|
93
|
+
this.sideBarProps?.onFilterChange(filterField, next.length > 0 ? { type: 'multiSelect', value: next } : undefined);
|
|
94
94
|
}
|
|
95
95
|
};
|
|
96
|
+
__decorate([
|
|
97
|
+
Input()
|
|
98
|
+
], SideBarComponent.prototype, "sideBarProps", void 0);
|
|
96
99
|
SideBarComponent = __decorate([
|
|
97
100
|
Component({
|
|
98
101
|
selector: 'ogrid-sidebar',
|
|
@@ -162,11 +165,11 @@ SideBarComponent = __decorate([
|
|
|
162
165
|
`],
|
|
163
166
|
template: `
|
|
164
167
|
<div class="ogrid-sidebar-root" role="complementary" aria-label="Side bar">
|
|
165
|
-
@if (sideBarProps
|
|
168
|
+
@if (sideBarProps?.position === 'left') {
|
|
166
169
|
<ng-container *ngTemplateOutlet="tabStripTpl"></ng-container>
|
|
167
170
|
<ng-container *ngTemplateOutlet="panelContentTpl"></ng-container>
|
|
168
171
|
}
|
|
169
|
-
@if (sideBarProps
|
|
172
|
+
@if (sideBarProps?.position === 'right') {
|
|
170
173
|
<ng-container *ngTemplateOutlet="panelContentTpl"></ng-container>
|
|
171
174
|
<ng-container *ngTemplateOutlet="tabStripTpl"></ng-container>
|
|
172
175
|
}
|
|
@@ -175,17 +178,17 @@ SideBarComponent = __decorate([
|
|
|
175
178
|
<ng-template #tabStripTpl>
|
|
176
179
|
<div
|
|
177
180
|
class="ogrid-sidebar-tab-strip"
|
|
178
|
-
[class.ogrid-sidebar-tab-strip--left]="sideBarProps
|
|
179
|
-
[class.ogrid-sidebar-tab-strip--right]="sideBarProps
|
|
181
|
+
[class.ogrid-sidebar-tab-strip--left]="sideBarProps?.position === 'left'"
|
|
182
|
+
[class.ogrid-sidebar-tab-strip--right]="sideBarProps?.position === 'right'"
|
|
180
183
|
role="tablist"
|
|
181
184
|
aria-label="Side bar tabs"
|
|
182
185
|
>
|
|
183
|
-
@for (panel of sideBarProps
|
|
186
|
+
@for (panel of sideBarProps?.panels ?? []; track panel) {
|
|
184
187
|
<button
|
|
185
188
|
role="tab"
|
|
186
189
|
class="ogrid-sidebar-tab"
|
|
187
|
-
[class.ogrid-sidebar-tab--active]="sideBarProps
|
|
188
|
-
[attr.aria-selected]="sideBarProps
|
|
190
|
+
[class.ogrid-sidebar-tab--active]="sideBarProps?.activePanel === panel"
|
|
191
|
+
[attr.aria-selected]="sideBarProps?.activePanel === panel"
|
|
189
192
|
[attr.aria-label]="panelLabels[panel]"
|
|
190
193
|
(click)="onTabClick(panel)"
|
|
191
194
|
[title]="panelLabels[panel]"
|
|
@@ -197,36 +200,36 @@ SideBarComponent = __decorate([
|
|
|
197
200
|
</ng-template>
|
|
198
201
|
|
|
199
202
|
<ng-template #panelContentTpl>
|
|
200
|
-
@if (sideBarProps
|
|
203
|
+
@if (sideBarProps?.activePanel) {
|
|
201
204
|
<div
|
|
202
205
|
role="tabpanel"
|
|
203
206
|
class="ogrid-sidebar-panel"
|
|
204
|
-
[class.ogrid-sidebar-panel--left]="sideBarProps
|
|
205
|
-
[class.ogrid-sidebar-panel--right]="sideBarProps
|
|
206
|
-
[attr.aria-label]="panelLabels[sideBarProps
|
|
207
|
+
[class.ogrid-sidebar-panel--left]="sideBarProps?.position === 'left'"
|
|
208
|
+
[class.ogrid-sidebar-panel--right]="sideBarProps?.position === 'right'"
|
|
209
|
+
[attr.aria-label]="panelLabels[sideBarProps!.activePanel!]"
|
|
207
210
|
>
|
|
208
211
|
<div class="ogrid-sidebar-panel-header">
|
|
209
|
-
<span>{{ panelLabels[sideBarProps
|
|
210
|
-
<button (click)="sideBarProps
|
|
212
|
+
<span>{{ panelLabels[sideBarProps!.activePanel!] }}</span>
|
|
213
|
+
<button (click)="sideBarProps?.onPanelChange(null)" class="ogrid-sidebar-panel-close" aria-label="Close panel">×</button>
|
|
211
214
|
</div>
|
|
212
215
|
<div class="ogrid-sidebar-panel-body">
|
|
213
|
-
@if (sideBarProps
|
|
216
|
+
@if (sideBarProps?.activePanel === 'columns') {
|
|
214
217
|
<div class="ogrid-sidebar-actions">
|
|
215
218
|
<button (click)="onSelectAll()" [disabled]="allVisible()" class="ogrid-sidebar-action-btn">Select All</button>
|
|
216
219
|
<button (click)="onClearAll()" class="ogrid-sidebar-action-btn">Clear All</button>
|
|
217
220
|
</div>
|
|
218
|
-
@for (col of sideBarProps
|
|
221
|
+
@for (col of sideBarProps?.columns ?? []; track col.columnId) {
|
|
219
222
|
<label class="ogrid-sidebar-col-label">
|
|
220
|
-
<input type="checkbox" [checked]="sideBarProps
|
|
223
|
+
<input type="checkbox" [checked]="sideBarProps?.visibleColumns?.has(col.columnId)" (change)="onVisibilityChange(col.columnId, ($event.target as HTMLInputElement).checked)" [disabled]="col.required" />
|
|
221
224
|
<span>{{ col.name }}</span>
|
|
222
225
|
</label>
|
|
223
226
|
}
|
|
224
227
|
}
|
|
225
|
-
@if (sideBarProps
|
|
226
|
-
@if ((sideBarProps
|
|
228
|
+
@if (sideBarProps?.activePanel === 'filters') {
|
|
229
|
+
@if ((sideBarProps?.filterableColumns ?? []).length === 0) {
|
|
227
230
|
<div class="ogrid-sidebar-empty">No filterable columns</div>
|
|
228
231
|
}
|
|
229
|
-
@for (col of sideBarProps
|
|
232
|
+
@for (col of sideBarProps?.filterableColumns ?? []; track col.columnId) {
|
|
230
233
|
<div class="ogrid-sidebar-filter-group">
|
|
231
234
|
<div class="ogrid-sidebar-filter-label">{{ col.name }}</div>
|
|
232
235
|
@if (col.filterType === 'text') {
|
|
@@ -234,7 +237,7 @@ SideBarComponent = __decorate([
|
|
|
234
237
|
type="text"
|
|
235
238
|
class="ogrid-sidebar-text-input"
|
|
236
239
|
[value]="getTextFilterValue(col.filterField)"
|
|
237
|
-
(input)="onTextFilterChange(col.filterField,
|
|
240
|
+
(input)="onTextFilterChange(col.filterField, ($event.target as HTMLInputElement).value)"
|
|
238
241
|
[placeholder]="'Filter ' + col.name + '...'"
|
|
239
242
|
[attr.aria-label]="'Filter ' + col.name"
|
|
240
243
|
/>
|
|
@@ -243,11 +246,11 @@ SideBarComponent = __decorate([
|
|
|
243
246
|
<div class="ogrid-sidebar-date-row">
|
|
244
247
|
<label class="ogrid-sidebar-date-label">
|
|
245
248
|
From:
|
|
246
|
-
<input type="date" class="ogrid-sidebar-date-input" [value]="getDateFrom(col.filterField)" (change)="onDateFromChange(col.filterField,
|
|
249
|
+
<input type="date" class="ogrid-sidebar-date-input" [value]="getDateFrom(col.filterField)" (change)="onDateFromChange(col.filterField, ($event.target as HTMLInputElement).value)" [attr.aria-label]="col.name + ' from date'" />
|
|
247
250
|
</label>
|
|
248
251
|
<label class="ogrid-sidebar-date-label">
|
|
249
252
|
To:
|
|
250
|
-
<input type="date" class="ogrid-sidebar-date-input" [value]="getDateTo(col.filterField)" (change)="onDateToChange(col.filterField,
|
|
253
|
+
<input type="date" class="ogrid-sidebar-date-input" [value]="getDateTo(col.filterField)" (change)="onDateToChange(col.filterField, ($event.target as HTMLInputElement).value)" [attr.aria-label]="col.name + ' to date'" />
|
|
251
254
|
</label>
|
|
252
255
|
</div>
|
|
253
256
|
}
|
|
@@ -255,7 +258,7 @@ SideBarComponent = __decorate([
|
|
|
255
258
|
<div class="ogrid-sidebar-multiselect-list" role="group" [attr.aria-label]="col.name + ' options'">
|
|
256
259
|
@for (opt of getFilterOptions(col.filterField); track opt) {
|
|
257
260
|
<label class="ogrid-sidebar-multiselect-item">
|
|
258
|
-
<input type="checkbox" [checked]="isMultiSelectChecked(col.filterField, opt)" (change)="onMultiSelectChange(col.filterField, opt,
|
|
261
|
+
<input type="checkbox" [checked]="isMultiSelectChecked(col.filterField, opt)" (change)="onMultiSelectChange(col.filterField, opt, ($event.target as HTMLInputElement).checked)" />
|
|
259
262
|
<span>{{ opt }}</span>
|
|
260
263
|
</label>
|
|
261
264
|
}
|