@alaarab/ogrid-angular 2.0.9 → 2.0.12
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 +106 -6
- 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 +94 -35
- package/dist/esm/components/sidebar.component.js +58 -55
- package/dist/esm/components/status-bar.component.js +43 -23
- package/dist/esm/index.js +3 -0
- package/dist/esm/services/datagrid-state.service.js +1 -1
- package/dist/esm/services/ogrid.service.js +8 -8
- 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 -1
- 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/dist/types/services/datagrid-state.service.d.ts +1 -1
- package/dist/types/services/ogrid.service.d.ts +2 -1
- package/dist/types/types/dataGridTypes.d.ts +3 -1
- package/package.json +2 -2
|
@@ -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',
|
|
@@ -103,56 +106,56 @@ SideBarComponent = __decorate([
|
|
|
103
106
|
.ogrid-sidebar-tab-strip {
|
|
104
107
|
display: flex; flex-direction: column;
|
|
105
108
|
width: var(--ogrid-sidebar-tab-size, 36px);
|
|
106
|
-
background: var(--ogrid-header-bg,
|
|
109
|
+
background: var(--ogrid-header-bg, rgba(0, 0, 0, 0.04));
|
|
107
110
|
}
|
|
108
|
-
.ogrid-sidebar-tab-strip--left { border-right: 1px solid var(--ogrid-border,
|
|
109
|
-
.ogrid-sidebar-tab-strip--right { border-left: 1px solid var(--ogrid-border,
|
|
111
|
+
.ogrid-sidebar-tab-strip--left { border-right: 1px solid var(--ogrid-border, rgba(0, 0, 0, 0.12)); }
|
|
112
|
+
.ogrid-sidebar-tab-strip--right { border-left: 1px solid var(--ogrid-border, rgba(0, 0, 0, 0.12)); }
|
|
110
113
|
.ogrid-sidebar-tab {
|
|
111
114
|
width: var(--ogrid-sidebar-tab-size, 36px);
|
|
112
115
|
height: var(--ogrid-sidebar-tab-size, 36px);
|
|
113
116
|
border: none; cursor: pointer;
|
|
114
|
-
color: var(--ogrid-fg,
|
|
117
|
+
color: var(--ogrid-fg, rgba(0, 0, 0, 0.87)); font-size: 14px;
|
|
115
118
|
display: flex; align-items: center; justify-content: center;
|
|
116
119
|
background: transparent; font-weight: normal;
|
|
117
120
|
}
|
|
118
|
-
.ogrid-sidebar-tab--active { background: var(--ogrid-bg, #
|
|
121
|
+
.ogrid-sidebar-tab--active { background: var(--ogrid-bg, #ffffff); font-weight: bold; }
|
|
119
122
|
.ogrid-sidebar-panel {
|
|
120
123
|
width: var(--ogrid-sidebar-panel-width, 240px);
|
|
121
124
|
display: flex; flex-direction: column; overflow: hidden;
|
|
122
|
-
background: var(--ogrid-bg, #
|
|
125
|
+
background: var(--ogrid-bg, #ffffff); color: var(--ogrid-fg, rgba(0, 0, 0, 0.87));
|
|
123
126
|
}
|
|
124
|
-
.ogrid-sidebar-panel--left { border-right: 1px solid var(--ogrid-border,
|
|
125
|
-
.ogrid-sidebar-panel--right { border-left: 1px solid var(--ogrid-border,
|
|
127
|
+
.ogrid-sidebar-panel--left { border-right: 1px solid var(--ogrid-border, rgba(0, 0, 0, 0.12)); }
|
|
128
|
+
.ogrid-sidebar-panel--right { border-left: 1px solid var(--ogrid-border, rgba(0, 0, 0, 0.12)); }
|
|
126
129
|
.ogrid-sidebar-panel-header {
|
|
127
130
|
display: flex; justify-content: space-between; align-items: center;
|
|
128
|
-
padding: 8px 12px; border-bottom: 1px solid var(--ogrid-border,
|
|
131
|
+
padding: 8px 12px; border-bottom: 1px solid var(--ogrid-border, rgba(0, 0, 0, 0.12)); font-weight: 600;
|
|
129
132
|
}
|
|
130
133
|
.ogrid-sidebar-panel-close {
|
|
131
134
|
border: none; background: transparent; cursor: pointer;
|
|
132
|
-
font-size: 16px; color: var(--ogrid-fg,
|
|
135
|
+
font-size: 16px; color: var(--ogrid-fg, rgba(0, 0, 0, 0.87));
|
|
133
136
|
}
|
|
134
137
|
.ogrid-sidebar-panel-body { flex: 1; overflow-y: auto; padding: 8px 12px; }
|
|
135
138
|
.ogrid-sidebar-actions { display: flex; gap: 8px; margin-bottom: 8px; }
|
|
136
139
|
.ogrid-sidebar-action-btn {
|
|
137
140
|
flex: 1; cursor: pointer;
|
|
138
|
-
background: var(--ogrid-bg
|
|
139
|
-
border: 1px solid var(--ogrid-border,
|
|
141
|
+
background: var(--ogrid-header-bg, rgba(0, 0, 0, 0.04)); color: var(--ogrid-fg, rgba(0, 0, 0, 0.87));
|
|
142
|
+
border: 1px solid var(--ogrid-border, rgba(0, 0, 0, 0.12)); border-radius: 4px; padding: 4px 8px;
|
|
140
143
|
}
|
|
141
144
|
.ogrid-sidebar-col-label { display: flex; align-items: center; gap: 6px; padding: 2px 0; cursor: pointer; }
|
|
142
|
-
.ogrid-sidebar-empty { color: var(--ogrid-muted,
|
|
145
|
+
.ogrid-sidebar-empty { color: var(--ogrid-fg-muted, rgba(0, 0, 0, 0.5)); font-style: italic; }
|
|
143
146
|
.ogrid-sidebar-filter-group { margin-bottom: 12px; }
|
|
144
147
|
.ogrid-sidebar-filter-label { font-weight: 500; margin-bottom: 4px; font-size: 13px; }
|
|
145
148
|
.ogrid-sidebar-text-input {
|
|
146
149
|
width: 100%; box-sizing: border-box; padding: 4px 6px;
|
|
147
|
-
background: var(--ogrid-bg, #
|
|
148
|
-
border: 1px solid var(--ogrid-border,
|
|
150
|
+
background: var(--ogrid-bg, #ffffff); color: var(--ogrid-fg, rgba(0, 0, 0, 0.87));
|
|
151
|
+
border: 1px solid var(--ogrid-border, rgba(0, 0, 0, 0.12)); border-radius: 4px;
|
|
149
152
|
}
|
|
150
153
|
.ogrid-sidebar-date-row { display: flex; flex-direction: column; gap: 4px; }
|
|
151
154
|
.ogrid-sidebar-date-label { display: flex; align-items: center; gap: 4px; font-size: 12px; }
|
|
152
155
|
.ogrid-sidebar-date-input {
|
|
153
156
|
flex: 1; padding: 2px 4px;
|
|
154
|
-
background: var(--ogrid-bg, #
|
|
155
|
-
border: 1px solid var(--ogrid-border,
|
|
157
|
+
background: var(--ogrid-bg, #ffffff); color: var(--ogrid-fg, rgba(0, 0, 0, 0.87));
|
|
158
|
+
border: 1px solid var(--ogrid-border, rgba(0, 0, 0, 0.12)); border-radius: 4px;
|
|
156
159
|
}
|
|
157
160
|
.ogrid-sidebar-multiselect-list { max-height: 120px; overflow-y: auto; }
|
|
158
161
|
.ogrid-sidebar-multiselect-item {
|
|
@@ -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, $any($event.target).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') {
|
|
@@ -4,41 +4,61 @@ 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 { getStatusBarParts } from '@alaarab/ogrid-core';
|
|
10
10
|
let StatusBarComponent = class StatusBarComponent {
|
|
11
11
|
constructor() {
|
|
12
|
-
this.
|
|
13
|
-
this.
|
|
14
|
-
this.
|
|
15
|
-
this.
|
|
16
|
-
this.
|
|
17
|
-
this.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
};
|
|
12
|
+
this.filteredCount = undefined;
|
|
13
|
+
this.selectedCount = undefined;
|
|
14
|
+
this.selectedCellCount = undefined;
|
|
15
|
+
this.aggregation = undefined;
|
|
16
|
+
this.suppressRowCount = undefined;
|
|
17
|
+
this.classNames = undefined;
|
|
18
|
+
}
|
|
19
|
+
getParts() {
|
|
20
|
+
return getStatusBarParts({
|
|
21
|
+
totalCount: this.totalCount,
|
|
22
|
+
filteredCount: this.filteredCount,
|
|
23
|
+
selectedCount: this.selectedCount,
|
|
24
|
+
selectedCellCount: this.selectedCellCount,
|
|
25
|
+
aggregation: this.aggregation ?? undefined,
|
|
26
|
+
suppressRowCount: this.suppressRowCount,
|
|
27
|
+
});
|
|
29
28
|
}
|
|
30
29
|
};
|
|
30
|
+
__decorate([
|
|
31
|
+
Input({ required: true })
|
|
32
|
+
], StatusBarComponent.prototype, "totalCount", void 0);
|
|
33
|
+
__decorate([
|
|
34
|
+
Input()
|
|
35
|
+
], StatusBarComponent.prototype, "filteredCount", void 0);
|
|
36
|
+
__decorate([
|
|
37
|
+
Input()
|
|
38
|
+
], StatusBarComponent.prototype, "selectedCount", void 0);
|
|
39
|
+
__decorate([
|
|
40
|
+
Input()
|
|
41
|
+
], StatusBarComponent.prototype, "selectedCellCount", void 0);
|
|
42
|
+
__decorate([
|
|
43
|
+
Input()
|
|
44
|
+
], StatusBarComponent.prototype, "aggregation", void 0);
|
|
45
|
+
__decorate([
|
|
46
|
+
Input()
|
|
47
|
+
], StatusBarComponent.prototype, "suppressRowCount", void 0);
|
|
48
|
+
__decorate([
|
|
49
|
+
Input()
|
|
50
|
+
], StatusBarComponent.prototype, "classNames", void 0);
|
|
31
51
|
StatusBarComponent = __decorate([
|
|
32
52
|
Component({
|
|
33
53
|
selector: 'ogrid-status-bar',
|
|
34
54
|
standalone: true,
|
|
35
55
|
imports: [CommonModule],
|
|
36
56
|
template: `
|
|
37
|
-
<div [class]="classNames
|
|
38
|
-
@for (part of
|
|
39
|
-
<span [class]="classNames
|
|
40
|
-
<span [class]="classNames
|
|
41
|
-
<span [class]="classNames
|
|
57
|
+
<div [class]="classNames?.statusBar ?? ''" role="status" aria-live="polite">
|
|
58
|
+
@for (part of getParts(); track part.key) {
|
|
59
|
+
<span [class]="classNames?.statusBarItem ?? ''">
|
|
60
|
+
<span [class]="classNames?.statusBarLabel ?? ''">{{ part.label }}</span>
|
|
61
|
+
<span [class]="classNames?.statusBarValue ?? ''">{{ part.value.toLocaleString() }}</span>
|
|
42
62
|
</span>
|
|
43
63
|
}
|
|
44
64
|
</div>
|
package/dist/esm/index.js
CHANGED
|
@@ -16,4 +16,7 @@ export { SideBarComponent } from './components/sidebar.component';
|
|
|
16
16
|
export { MarchingAntsOverlayComponent } from './components/marching-ants-overlay.component';
|
|
17
17
|
export { EmptyStateComponent } from './components/empty-state.component';
|
|
18
18
|
export { BaseDataGridTableComponent } from './components/base-datagrid-table.component';
|
|
19
|
+
export { BaseColumnHeaderFilterComponent } from './components/base-column-header-filter.component';
|
|
20
|
+
export { BaseColumnChooserComponent } from './components/base-column-chooser.component';
|
|
21
|
+
export { BasePaginationControlsComponent } from './components/base-pagination-controls.component';
|
|
19
22
|
export { getHeaderFilterConfig, getCellRenderDescriptor, resolveCellDisplayContent, resolveCellStyle, createDebouncedSignal, createDebouncedCallback, debounce, createLatestRef, createLatestCallback, } from './utils';
|
|
@@ -1081,7 +1081,7 @@ let DataGridStateService = class DataGridStateService {
|
|
|
1081
1081
|
headerFilterInput: {
|
|
1082
1082
|
sortBy: p?.sortBy,
|
|
1083
1083
|
sortDirection: p?.sortDirection ?? 'asc',
|
|
1084
|
-
onColumnSort: (columnKey) => p?.onColumnSort(columnKey),
|
|
1084
|
+
onColumnSort: (columnKey, direction) => p?.onColumnSort(columnKey, direction),
|
|
1085
1085
|
filters: p?.filters ?? {},
|
|
1086
1086
|
onFilterChange: (key, value) => p?.onFilterChange(key, value),
|
|
1087
1087
|
filterOptions: p?.filterOptions ?? {},
|
|
@@ -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, } from '@alaarab/ogrid-core';
|
|
8
|
+
import { mergeFilter, deriveFilterOptionsFromData, getMultiSelectFilterFields, flattenColumns, processClientSideData, computeNextSortState, } from '@alaarab/ogrid-core';
|
|
9
9
|
const DEFAULT_PAGE_SIZE = 25;
|
|
10
10
|
const EMPTY_LOADING_OPTIONS = {};
|
|
11
11
|
const DEFAULT_PANELS = ['columns', 'filters'];
|
|
@@ -67,6 +67,7 @@ let OGridService = class OGridService {
|
|
|
67
67
|
this.onFirstDataRendered = signal(undefined);
|
|
68
68
|
this.onError = signal(undefined);
|
|
69
69
|
this.columnChooserProp = signal(undefined);
|
|
70
|
+
this.columnReorder = signal(undefined);
|
|
70
71
|
this.virtualScroll = signal(undefined);
|
|
71
72
|
this.ariaLabel = signal(undefined);
|
|
72
73
|
this.ariaLabelledBy = signal(undefined);
|
|
@@ -215,7 +216,7 @@ let OGridService = class OGridService {
|
|
|
215
216
|
getRowId: this.getRowId(),
|
|
216
217
|
sortBy: this.sort().field,
|
|
217
218
|
sortDirection: this.sort().direction,
|
|
218
|
-
onColumnSort: (columnKey) => this.handleSort(columnKey),
|
|
219
|
+
onColumnSort: (columnKey, direction) => this.handleSort(columnKey, direction),
|
|
219
220
|
visibleColumns: this.visibleColumns(),
|
|
220
221
|
columnOrder: this.columnOrder(),
|
|
221
222
|
onColumnOrderChange: this.onColumnOrderChange(),
|
|
@@ -246,6 +247,7 @@ let OGridService = class OGridService {
|
|
|
246
247
|
getUserByEmail: this.dataSource()?.getUserByEmail?.bind(this.dataSource()),
|
|
247
248
|
layoutMode: this.layoutMode(),
|
|
248
249
|
suppressHorizontalScroll: this.suppressHorizontalScroll(),
|
|
250
|
+
columnReorder: this.columnReorder(),
|
|
249
251
|
virtualScroll: this.virtualScroll(),
|
|
250
252
|
'aria-label': this.ariaLabel(),
|
|
251
253
|
'aria-labelledby': this.ariaLabelledBy(),
|
|
@@ -401,12 +403,8 @@ let OGridService = class OGridService {
|
|
|
401
403
|
this.internalVisibleColumnsOverride.set(cols);
|
|
402
404
|
this.onVisibleColumnsChange()?.(cols);
|
|
403
405
|
}
|
|
404
|
-
handleSort(columnKey) {
|
|
405
|
-
|
|
406
|
-
this.setSort({
|
|
407
|
-
field: columnKey,
|
|
408
|
-
direction: sort.field === columnKey && sort.direction === 'asc' ? 'desc' : 'asc',
|
|
409
|
-
});
|
|
406
|
+
handleSort(columnKey, direction) {
|
|
407
|
+
this.setSort(computeNextSortState(this.sort(), columnKey, direction));
|
|
410
408
|
}
|
|
411
409
|
handleFilterChange(key, value) {
|
|
412
410
|
this.setFilters(mergeFilter(this.filters(), key, value));
|
|
@@ -521,6 +519,8 @@ let OGridService = class OGridService {
|
|
|
521
519
|
this.onError.set(props.onError);
|
|
522
520
|
if (props.columnChooser !== undefined)
|
|
523
521
|
this.columnChooserProp.set(props.columnChooser);
|
|
522
|
+
if (props.columnReorder !== undefined)
|
|
523
|
+
this.columnReorder.set(props.columnReorder);
|
|
524
524
|
if (props.virtualScroll !== undefined)
|
|
525
525
|
this.virtualScroll.set(props.virtualScroll);
|
|
526
526
|
if (props.entityLabelPlural !== undefined)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { EventEmitter } from '@angular/core';
|
|
2
|
+
import type { IColumnDefinition } from '../types';
|
|
3
|
+
export interface IColumnChooserProps {
|
|
4
|
+
columns: IColumnDefinition[];
|
|
5
|
+
visibleColumns: Set<string>;
|
|
6
|
+
onVisibilityChange: (columnKey: string, visible: boolean) => void;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Abstract base class containing all shared TypeScript logic for ColumnChooser components.
|
|
10
|
+
* Framework-specific UI packages extend this with their templates and style overrides.
|
|
11
|
+
*
|
|
12
|
+
* Subclasses must:
|
|
13
|
+
* 1. Provide a @Component decorator with template and styles
|
|
14
|
+
* 2. Handle their own click-outside behavior (host binding or effect)
|
|
15
|
+
*/
|
|
16
|
+
export declare abstract class BaseColumnChooserComponent {
|
|
17
|
+
private readonly _columns;
|
|
18
|
+
private readonly _visibleColumns;
|
|
19
|
+
set columns(v: IColumnDefinition[]);
|
|
20
|
+
get columns(): IColumnDefinition[];
|
|
21
|
+
set visibleColumns(v: Set<string>);
|
|
22
|
+
get visibleColumns(): Set<string>;
|
|
23
|
+
visibilityChange: EventEmitter<{
|
|
24
|
+
columnKey: string;
|
|
25
|
+
visible: boolean;
|
|
26
|
+
}>;
|
|
27
|
+
readonly isOpen: import("@angular/core").WritableSignal<boolean>;
|
|
28
|
+
readonly visibleCount: import("@angular/core").Signal<number>;
|
|
29
|
+
readonly totalCount: import("@angular/core").Signal<number>;
|
|
30
|
+
toggle(): void;
|
|
31
|
+
onCheckboxChange(columnKey: string, event: Event): void;
|
|
32
|
+
onToggle(columnKey: string, checked: boolean): void;
|
|
33
|
+
selectAll(): void;
|
|
34
|
+
clearAll(): void;
|
|
35
|
+
onClearAll(): void;
|
|
36
|
+
onSelectAll(): void;
|
|
37
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { ElementRef } from '@angular/core';
|
|
2
|
+
import type { ColumnFilterType, IDateFilterValue, UserLike } from '../types';
|
|
3
|
+
export interface IColumnHeaderFilterProps {
|
|
4
|
+
columnKey: string;
|
|
5
|
+
columnName: string;
|
|
6
|
+
filterType: ColumnFilterType;
|
|
7
|
+
isSorted?: boolean;
|
|
8
|
+
isSortedDescending?: boolean;
|
|
9
|
+
onSort?: () => void;
|
|
10
|
+
selectedValues?: string[];
|
|
11
|
+
onFilterChange?: (values: string[]) => void;
|
|
12
|
+
options?: string[];
|
|
13
|
+
isLoadingOptions?: boolean;
|
|
14
|
+
textValue?: string;
|
|
15
|
+
onTextChange?: (value: string) => void;
|
|
16
|
+
selectedUser?: UserLike;
|
|
17
|
+
onUserChange?: (user: UserLike | undefined) => void;
|
|
18
|
+
peopleSearch?: (query: string) => Promise<UserLike[]>;
|
|
19
|
+
dateValue?: IDateFilterValue;
|
|
20
|
+
onDateChange?: (value: IDateFilterValue | undefined) => void;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Abstract base class containing all shared TypeScript logic for ColumnHeaderFilter components.
|
|
24
|
+
* Framework-specific UI packages extend this with their templates and style overrides.
|
|
25
|
+
*
|
|
26
|
+
* Subclasses must:
|
|
27
|
+
* 1. Provide a @Component decorator with template and styles
|
|
28
|
+
* 2. Implement abstract accessor for headerEl (ViewChild reference)
|
|
29
|
+
*/
|
|
30
|
+
export declare abstract class BaseColumnHeaderFilterComponent {
|
|
31
|
+
columnKey: string;
|
|
32
|
+
columnName: string;
|
|
33
|
+
private readonly _filterType;
|
|
34
|
+
private readonly _selectedValues;
|
|
35
|
+
private readonly _options;
|
|
36
|
+
private readonly _textValue;
|
|
37
|
+
private readonly _selectedUser;
|
|
38
|
+
private readonly _dateValue;
|
|
39
|
+
set filterType(v: ColumnFilterType);
|
|
40
|
+
get filterType(): ColumnFilterType;
|
|
41
|
+
set selectedValues(v: string[] | undefined);
|
|
42
|
+
get selectedValues(): string[] | undefined;
|
|
43
|
+
set options(v: string[] | undefined);
|
|
44
|
+
get options(): string[] | undefined;
|
|
45
|
+
set textValue(v: string);
|
|
46
|
+
get textValue(): string;
|
|
47
|
+
set selectedUser(v: UserLike | undefined);
|
|
48
|
+
get selectedUser(): UserLike | undefined;
|
|
49
|
+
set dateValue(v: IDateFilterValue | undefined);
|
|
50
|
+
get dateValue(): IDateFilterValue | undefined;
|
|
51
|
+
isSorted: boolean;
|
|
52
|
+
isSortedDescending: boolean;
|
|
53
|
+
onSort: (() => void) | undefined;
|
|
54
|
+
onFilterChange: ((values: string[]) => void) | undefined;
|
|
55
|
+
isLoadingOptions: boolean;
|
|
56
|
+
onTextChange: ((value: string) => void) | undefined;
|
|
57
|
+
onUserChange: ((user: UserLike | undefined) => void) | undefined;
|
|
58
|
+
peopleSearch: ((query: string) => Promise<UserLike[]>) | undefined;
|
|
59
|
+
onDateChange: ((value: IDateFilterValue | undefined) => void) | undefined;
|
|
60
|
+
protected abstract getHeaderEl(): ElementRef<HTMLElement> | undefined;
|
|
61
|
+
readonly isFilterOpen: import("@angular/core").WritableSignal<boolean>;
|
|
62
|
+
readonly tempTextValue: import("@angular/core").WritableSignal<string>;
|
|
63
|
+
readonly searchText: import("@angular/core").WritableSignal<string>;
|
|
64
|
+
readonly tempSelected: import("@angular/core").WritableSignal<Set<string>>;
|
|
65
|
+
readonly peopleSearchText: import("@angular/core").WritableSignal<string>;
|
|
66
|
+
readonly peopleSuggestions: import("@angular/core").WritableSignal<UserLike[]>;
|
|
67
|
+
readonly isPeopleLoading: import("@angular/core").WritableSignal<boolean>;
|
|
68
|
+
readonly tempDateFrom: import("@angular/core").WritableSignal<string>;
|
|
69
|
+
readonly tempDateTo: import("@angular/core").WritableSignal<string>;
|
|
70
|
+
readonly popoverTop: import("@angular/core").WritableSignal<number>;
|
|
71
|
+
readonly popoverLeft: import("@angular/core").WritableSignal<number>;
|
|
72
|
+
private peopleDebounceTimer;
|
|
73
|
+
readonly hasActiveFilter: import("@angular/core").Signal<boolean>;
|
|
74
|
+
readonly filteredOptions: import("@angular/core").Signal<string[]>;
|
|
75
|
+
asInputValue(event: Event): string;
|
|
76
|
+
toggleFilter(event: MouseEvent): void;
|
|
77
|
+
onTextKeydown(event: KeyboardEvent): void;
|
|
78
|
+
handleTextApply(): void;
|
|
79
|
+
handleTextClear(): void;
|
|
80
|
+
handleCheckboxChange(option: string, event: Event): void;
|
|
81
|
+
handleSelectAllFiltered(): void;
|
|
82
|
+
handleClearSelection(): void;
|
|
83
|
+
handleApplyMultiSelect(): void;
|
|
84
|
+
onPeopleSearchInput(event: Event): void;
|
|
85
|
+
handleUserSelect(user: UserLike): void;
|
|
86
|
+
handleClearUser(): void;
|
|
87
|
+
handleDateApply(): void;
|
|
88
|
+
handleDateClear(): void;
|
|
89
|
+
onDocumentClick(event: MouseEvent, selectorName: string): void;
|
|
90
|
+
}
|
|
@@ -19,12 +19,16 @@ export declare abstract class BaseDataGridTableComponent<T = unknown> {
|
|
|
19
19
|
readonly virtualScrollService: VirtualScrollService;
|
|
20
20
|
protected lastMouseShift: boolean;
|
|
21
21
|
readonly columnSizingVersion: import("@angular/core").WritableSignal<number>;
|
|
22
|
+
protected readonly wrapperElSignal: import("@angular/core").WritableSignal<HTMLElement | null>;
|
|
23
|
+
protected readonly tableContainerElSignal: import("@angular/core").WritableSignal<HTMLElement | null>;
|
|
22
24
|
/** Return the IOGridDataGridProps from however the subclass receives them */
|
|
23
25
|
protected abstract getProps(): IOGridDataGridProps<T> | undefined;
|
|
24
26
|
/** Return the wrapper element ref */
|
|
25
27
|
protected abstract getWrapperRef(): ElementRef<HTMLElement> | undefined;
|
|
26
28
|
/** Return the table container element ref */
|
|
27
29
|
protected abstract getTableContainerRef(): ElementRef<HTMLElement> | undefined;
|
|
30
|
+
/** Lifecycle hook — populate element signals from @ViewChild refs */
|
|
31
|
+
ngAfterViewInit(): void;
|
|
28
32
|
readonly state: import("@angular/core").Signal<import("../services/datagrid-state.service").DataGridStateResult<T>>;
|
|
29
33
|
readonly tableContainerEl: import("@angular/core").Signal<HTMLElement | null>;
|
|
30
34
|
readonly allItems: import("@angular/core").Signal<T[]>;
|
|
@@ -46,6 +50,8 @@ export declare abstract class BaseDataGridTableComponent<T = unknown> {
|
|
|
46
50
|
readonly currentPage: import("@angular/core").Signal<number>;
|
|
47
51
|
readonly pageSize: import("@angular/core").Signal<number>;
|
|
48
52
|
readonly rowNumberOffset: import("@angular/core").Signal<number>;
|
|
53
|
+
readonly propsVisibleColumns: import("@angular/core").Signal<Set<string> | undefined>;
|
|
54
|
+
readonly propsColumnOrder: import("@angular/core").Signal<string[] | undefined>;
|
|
49
55
|
readonly visibleCols: import("@angular/core").Signal<IColumnDef<T>[]>;
|
|
50
56
|
readonly hasCheckboxCol: import("@angular/core").Signal<boolean>;
|
|
51
57
|
readonly hasRowNumbersCol: import("@angular/core").Signal<boolean>;
|
|
@@ -81,7 +87,7 @@ export declare abstract class BaseDataGridTableComponent<T = unknown> {
|
|
|
81
87
|
readonly headerFilterInput: import("@angular/core").Signal<{
|
|
82
88
|
sortBy?: string;
|
|
83
89
|
sortDirection: "asc" | "desc";
|
|
84
|
-
onColumnSort: (columnKey: string) => void;
|
|
90
|
+
onColumnSort: (columnKey: string, direction?: "asc" | "desc" | null) => void;
|
|
85
91
|
filters: import("@alaarab/ogrid-core").IFilters;
|
|
86
92
|
onFilterChange: (key: string, value: import("@alaarab/ogrid-core").FilterValue | undefined) => void;
|
|
87
93
|
filterOptions: Record<string, string[]>;
|
|
@@ -123,6 +129,10 @@ export declare abstract class BaseDataGridTableComponent<T = unknown> {
|
|
|
123
129
|
minWidth: number;
|
|
124
130
|
width: number;
|
|
125
131
|
}[]>;
|
|
132
|
+
readonly pinningOffsets: import("@angular/core").Signal<{
|
|
133
|
+
leftOffsets: Record<string, number>;
|
|
134
|
+
rightOffsets: Record<string, number>;
|
|
135
|
+
}>;
|
|
126
136
|
/**
|
|
127
137
|
* Initialize base wiring effects. Must be called from subclass constructor
|
|
128
138
|
* (effects need to run inside an injection context).
|
|
@@ -138,6 +148,8 @@ export declare abstract class BaseDataGridTableComponent<T = unknown> {
|
|
|
138
148
|
buildPopoverEditorProps(item: T, col: IColumnDef<T>, descriptor: CellRenderDescriptor): unknown;
|
|
139
149
|
getSelectValues(col: IColumnDef<T>): string[];
|
|
140
150
|
formatDateForInput(value: unknown): string;
|
|
151
|
+
getPinnedLeftOffset(columnId: string): number | null;
|
|
152
|
+
getPinnedRightOffset(columnId: string): number | null;
|
|
141
153
|
onWrapperScroll(event: Event): void;
|
|
142
154
|
setPopoverAnchorEl(el: HTMLElement | null): void;
|
|
143
155
|
setPendingEditorValue(value: unknown): void;
|
|
@@ -173,4 +185,10 @@ export declare abstract class BaseDataGridTableComponent<T = unknown> {
|
|
|
173
185
|
canPinRight: boolean;
|
|
174
186
|
canUnpin: boolean;
|
|
175
187
|
};
|
|
188
|
+
onSortAsc(columnId: string): void;
|
|
189
|
+
onSortDesc(columnId: string): void;
|
|
190
|
+
onClearSort(columnId?: string): void;
|
|
191
|
+
getSortState(columnId: string): 'asc' | 'desc' | null;
|
|
192
|
+
onAutosizeColumn(columnId: string): void;
|
|
193
|
+
onAutosizeAllColumns(): void;
|
|
176
194
|
}
|