@sneat/datagrid 0.27.19 → 0.27.21
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/README.md +65 -0
- package/fesm2022/sneat-datagrid.mjs +174 -84
- package/fesm2022/sneat-datagrid.mjs.map +1 -1
- package/package.json +1 -1
- package/tsconfig.lib.prod.tsbuildinfo +1 -1
- package/types/sneat-datagrid.d.ts +57 -25
package/README.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# @sneat/datagrid
|
|
2
|
+
|
|
3
|
+
Angular wrapper around [Tabulator](http://tabulator.info) (`sneat-datagrid`),
|
|
4
|
+
used for dense result grids — e.g. DataTug's table/query results page.
|
|
5
|
+
|
|
6
|
+
## Basic usage
|
|
7
|
+
|
|
8
|
+
```html
|
|
9
|
+
<sneat-datagrid
|
|
10
|
+
[columns]="columns"
|
|
11
|
+
[data]="rows"
|
|
12
|
+
layout="fitColumns"
|
|
13
|
+
/>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Cell selection (opt-in)
|
|
17
|
+
|
|
18
|
+
Cell/range selection is off by default so existing consumers are unaffected.
|
|
19
|
+
Set `selectableRange` to enable it, and listen to `cellSelected` for the
|
|
20
|
+
currently active cell (fired on a mouse click, and — once `selectableRange`
|
|
21
|
+
is on — on keyboard arrow-key navigation between cells too):
|
|
22
|
+
|
|
23
|
+
```html
|
|
24
|
+
<sneat-datagrid
|
|
25
|
+
[columns]="columns"
|
|
26
|
+
[data]="rows"
|
|
27
|
+
[selectableRange]="true"
|
|
28
|
+
(cellSelected)="onCellSelected($event)"
|
|
29
|
+
/>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { IDataGridCellSelectedEvent } from '@sneat/datagrid';
|
|
34
|
+
|
|
35
|
+
onCellSelected(event: IDataGridCellSelectedEvent): void {
|
|
36
|
+
// event.column.field — e.g. "CustomerId"
|
|
37
|
+
// event.column.index — the field's position in the `columns` input
|
|
38
|
+
// event.value — the cell's current value
|
|
39
|
+
// event.rowData — the full row's data object
|
|
40
|
+
console.log(event);
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`selectableRange` mirrors Tabulator's own option: `true` for unlimited
|
|
45
|
+
ranges, or a number to cap how many ranges can be selected at once. It is
|
|
46
|
+
mutually exclusive with row selection (`selectable`) — Tabulator disables
|
|
47
|
+
range selection and logs a console warning if both are set.
|
|
48
|
+
|
|
49
|
+
## Column markers
|
|
50
|
+
|
|
51
|
+
`columnMarkers` renders a small, unobtrusive badge in a column's header,
|
|
52
|
+
keyed by field. The grid applies no semantic meaning to these — it only
|
|
53
|
+
renders what the consumer passes (e.g. a semantic-detection layer flagging a
|
|
54
|
+
declared or inferred `CustomerId` column):
|
|
55
|
+
|
|
56
|
+
```html
|
|
57
|
+
<sneat-datagrid
|
|
58
|
+
[columns]="columns"
|
|
59
|
+
[data]="rows"
|
|
60
|
+
[columnMarkers]="{ CustomerId: { label: 'PK', title: 'Primary key', kind: 'declared' } }"
|
|
61
|
+
/>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`kind` is purely presentational (`'declared'` vs `'inferred'` render with a
|
|
65
|
+
slightly different style); it carries no behaviour.
|
|
@@ -1,44 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import {
|
|
3
|
-
import * as i2 from '@angular/forms';
|
|
4
|
-
import { FormsModule } from '@angular/forms';
|
|
5
|
-
import * as i1 from '@angular/router';
|
|
6
|
-
import { RouterModule } from '@angular/router';
|
|
7
|
-
import { IonCardHeader, IonCardTitle, IonCardSubtitle, IonSegment, IonSegmentButton, IonLabel, IonList, IonItem, IonInput, IonBadge, IonText } from '@ionic/angular';
|
|
2
|
+
import { inject, EventEmitter, Input, Output, ViewChild, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
8
3
|
import { ErrorLogger } from '@sneat/core';
|
|
9
|
-
import { Module, Tabulator, InteractionModule, SelectRowModule, MenuModule } from 'tabulator-tables';
|
|
10
|
-
|
|
11
|
-
class CellPopoverComponent {
|
|
12
|
-
constructor() {
|
|
13
|
-
this.tab = 'rec';
|
|
14
|
-
}
|
|
15
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: CellPopoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
16
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: CellPopoverComponent, isStandalone: true, selector: "sneat-datatug-cell-popover", inputs: { column: "column", value: "value", fk: "fk" }, ngImport: i0, template: "<ion-card-header>\n <ion-card-title>Field: {{ column?.name }}</ion-card-title>\n <ion-card-subtitle>Value: {{ value }}</ion-card-subtitle>\n</ion-card-header>\n<h3 class=\"ion-margin\">\n References:\n @if (fk?.refTable) {\n <a routerLink=\"{{ fk?.refTable?.schema }}.{{ fk?.refTable?.name }}\">\n {{ fk?.refTable?.schema }}.{{ fk?.refTable?.name }}\n </a>\n }\n</h3>\n<ion-segment [(ngModel)]=\"tab\">\n <ion-segment-button value=\"rec\">\n <ion-label>Record</ion-label>\n </ion-segment-button>\n <ion-segment-button value=\"cols\">\n <ion-label>Columns</ion-label>\n </ion-segment-button>\n <ion-segment-button value=\"refs\">\n <ion-label>References</ion-label>\n </ion-segment-button>\n</ion-segment>\n\n@switch (tab) {\n @case (\"rec\") {\n <ion-list>\n <ion-item>\n <ion-label>Id</ion-label>\n <ion-input\n type=\"number\"\n style=\"text-align: right\"\n value=\"1\"\n readonly=\"true\"\n />\n </ion-item>\n <ion-item>\n <ion-label>Code</ion-label>\n <ion-input\n type=\"text\"\n style=\"text-align: right\"\n value=\"Something\"\n readonly=\"true\"\n />\n </ion-item>\n </ion-list>\n }\n @case (\"cols\") {\n <ion-list>\n <ion-item>\n <ion-label>Id</ion-label>\n <ion-badge slot=\"end\" color=\"light\">\n <ion-text color=\"medium\">INT</ion-text>\n </ion-badge>\n </ion-item>\n <ion-item>\n <ion-label>Code</ion-label>\n <ion-badge slot=\"end\" color=\"light\">\n <ion-text color=\"medium\">NVARCHAR</ion-text>\n </ion-badge>\n </ion-item>\n </ion-list>\n }\n}\n", dependencies: [{ kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: IonCardHeader, selector: "ion-card-header", inputs: ["color", "mode", "translucent"] }, { kind: "component", type: IonCardTitle, selector: "ion-card-title", inputs: ["color", "mode"] }, { kind: "component", type: IonCardSubtitle, selector: "ion-card-subtitle", inputs: ["color", "mode"] }, { kind: "component", type: IonSegment, selector: "ion-segment", inputs: ["color", "disabled", "mode", "scrollable", "selectOnFocus", "swipeGesture", "value"] }, { kind: "component", type: IonSegmentButton, selector: "ion-segment-button", inputs: ["contentId", "disabled", "layout", "mode", "type", "value"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonInput, selector: "ion-input", inputs: ["accept", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "shape", "size", "spellcheck", "step", "type", "value"] }, { kind: "component", type: IonBadge, selector: "ion-badge", inputs: ["color", "mode"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
17
|
-
}
|
|
18
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: CellPopoverComponent, decorators: [{
|
|
19
|
-
type: Component,
|
|
20
|
-
args: [{ selector: 'sneat-datatug-cell-popover', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
21
|
-
RouterModule,
|
|
22
|
-
FormsModule,
|
|
23
|
-
IonCardHeader,
|
|
24
|
-
IonCardTitle,
|
|
25
|
-
IonCardSubtitle,
|
|
26
|
-
IonSegment,
|
|
27
|
-
IonSegmentButton,
|
|
28
|
-
IonLabel,
|
|
29
|
-
IonList,
|
|
30
|
-
IonItem,
|
|
31
|
-
IonInput,
|
|
32
|
-
IonBadge,
|
|
33
|
-
IonText,
|
|
34
|
-
], template: "<ion-card-header>\n <ion-card-title>Field: {{ column?.name }}</ion-card-title>\n <ion-card-subtitle>Value: {{ value }}</ion-card-subtitle>\n</ion-card-header>\n<h3 class=\"ion-margin\">\n References:\n @if (fk?.refTable) {\n <a routerLink=\"{{ fk?.refTable?.schema }}.{{ fk?.refTable?.name }}\">\n {{ fk?.refTable?.schema }}.{{ fk?.refTable?.name }}\n </a>\n }\n</h3>\n<ion-segment [(ngModel)]=\"tab\">\n <ion-segment-button value=\"rec\">\n <ion-label>Record</ion-label>\n </ion-segment-button>\n <ion-segment-button value=\"cols\">\n <ion-label>Columns</ion-label>\n </ion-segment-button>\n <ion-segment-button value=\"refs\">\n <ion-label>References</ion-label>\n </ion-segment-button>\n</ion-segment>\n\n@switch (tab) {\n @case (\"rec\") {\n <ion-list>\n <ion-item>\n <ion-label>Id</ion-label>\n <ion-input\n type=\"number\"\n style=\"text-align: right\"\n value=\"1\"\n readonly=\"true\"\n />\n </ion-item>\n <ion-item>\n <ion-label>Code</ion-label>\n <ion-input\n type=\"text\"\n style=\"text-align: right\"\n value=\"Something\"\n readonly=\"true\"\n />\n </ion-item>\n </ion-list>\n }\n @case (\"cols\") {\n <ion-list>\n <ion-item>\n <ion-label>Id</ion-label>\n <ion-badge slot=\"end\" color=\"light\">\n <ion-text color=\"medium\">INT</ion-text>\n </ion-badge>\n </ion-item>\n <ion-item>\n <ion-label>Code</ion-label>\n <ion-badge slot=\"end\" color=\"light\">\n <ion-text color=\"medium\">NVARCHAR</ion-text>\n </ion-badge>\n </ion-item>\n </ion-list>\n }\n}\n" }]
|
|
35
|
-
}], propDecorators: { column: [{
|
|
36
|
-
type: Input
|
|
37
|
-
}], value: [{
|
|
38
|
-
type: Input
|
|
39
|
-
}], fk: [{
|
|
40
|
-
type: Input
|
|
41
|
-
}] } });
|
|
4
|
+
import { Module, Tabulator, InteractionModule, SelectRowModule, SelectRangeModule, KeybindingsModule, MenuModule } from 'tabulator-tables';
|
|
42
5
|
|
|
43
6
|
class AdvertModule extends Module {
|
|
44
7
|
static { this.moduleName = 'advert'; }
|
|
@@ -49,6 +12,13 @@ class AdvertModule extends Module {
|
|
|
49
12
|
Tabulator.registerModule([
|
|
50
13
|
InteractionModule,
|
|
51
14
|
SelectRowModule,
|
|
15
|
+
// SelectRange enables opt-in cell/range selection (selectableRange input).
|
|
16
|
+
// KeybindingsModule wires the arrow-key navigation SelectRange relies on;
|
|
17
|
+
// its default bindings are only *active* when we don't disable them via
|
|
18
|
+
// the `keybindings` table option, which we do unless selectableRange is on
|
|
19
|
+
// (see setTabulatorOptions()) so existing consumers see no behaviour change.
|
|
20
|
+
SelectRangeModule,
|
|
21
|
+
KeybindingsModule,
|
|
52
22
|
AdvertModule,
|
|
53
23
|
MenuModule,
|
|
54
24
|
]);
|
|
@@ -94,6 +64,13 @@ class DataGridComponent {
|
|
|
94
64
|
this.columns = [];
|
|
95
65
|
this.rowSelected = new EventEmitter();
|
|
96
66
|
this.rowDeselected = new EventEmitter();
|
|
67
|
+
/**
|
|
68
|
+
* Emitted when a single cell becomes the active selection, either via a
|
|
69
|
+
* mouse click (always, regardless of `selectableRange`) or, once
|
|
70
|
+
* `selectableRange` is enabled, via keyboard arrow-key navigation between
|
|
71
|
+
* cells. Not emitted for multi-cell range drag-selection.
|
|
72
|
+
*/
|
|
73
|
+
this.cellSelected = new EventEmitter();
|
|
97
74
|
}
|
|
98
75
|
ngOnChanges(changes) {
|
|
99
76
|
try {
|
|
@@ -102,6 +79,15 @@ class DataGridComponent {
|
|
|
102
79
|
(changes['rowClick'] && this.rowClick)) {
|
|
103
80
|
this.drawTable();
|
|
104
81
|
}
|
|
82
|
+
else if (changes['columnMarkers'] && this.tabulator && this.columns) {
|
|
83
|
+
// columnMarkers can arrive after the initial draw (e.g. a semantic
|
|
84
|
+
// layer resolving markers asynchronously) — refresh header markers
|
|
85
|
+
// in place without a full data redraw.
|
|
86
|
+
const columnDefinitions = this.buildColumnDefinitions();
|
|
87
|
+
if (columnDefinitions) {
|
|
88
|
+
this.tabulator.setColumns(columnDefinitions);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
105
91
|
}
|
|
106
92
|
catch (ex) {
|
|
107
93
|
this.errorLogger.logError(ex, 'Failed to process ngOnChanges in DataGridComponent');
|
|
@@ -181,8 +167,131 @@ class DataGridComponent {
|
|
|
181
167
|
});
|
|
182
168
|
this.tabulator.on('rowSelected', (row) => this.rowSelected.emit({ row, event: this.clickEvent }));
|
|
183
169
|
this.tabulator.on('rowDeselected', (row) => this.rowDeselected.emit({ row, event: this.clickEvent }));
|
|
170
|
+
// Mouse-click selection: fires regardless of selectableRange.
|
|
171
|
+
this.tabulator.on('cellClick', (_event, cell) => {
|
|
172
|
+
this.emitCellSelected(cell);
|
|
173
|
+
});
|
|
174
|
+
// Keyboard-driven selection: only fires once selectableRange is on —
|
|
175
|
+
// the SelectRange module is inert otherwise. A plain click always
|
|
176
|
+
// creates a *new* range (rangeAdded), so listening to rangeChanged
|
|
177
|
+
// (bounds moved on the *existing* range) picks up arrow-key
|
|
178
|
+
// navigation and single-cell drag adjustments without double-firing
|
|
179
|
+
// alongside the cellClick handler above.
|
|
180
|
+
this.tabulator.on('rangeChanged', (range) => {
|
|
181
|
+
this.handleRangeChanged(range);
|
|
182
|
+
});
|
|
184
183
|
}
|
|
185
184
|
}
|
|
185
|
+
/** column.index is the field's position in the `columns` input array. */
|
|
186
|
+
emitCellSelected(cell) {
|
|
187
|
+
const field = cell.getField();
|
|
188
|
+
this.cellSelected.emit({
|
|
189
|
+
row: cell.getRow(),
|
|
190
|
+
column: {
|
|
191
|
+
field,
|
|
192
|
+
index: this.columns?.findIndex((c) => c.field === field) ?? -1,
|
|
193
|
+
},
|
|
194
|
+
value: cell.getValue(),
|
|
195
|
+
rowData: cell.getData(),
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
handleRangeChanged(range) {
|
|
199
|
+
const bounds = range.getBounds();
|
|
200
|
+
// Only report single-cell selections; multi-cell range drag-selection
|
|
201
|
+
// is visual-only for now (out of scope for this task).
|
|
202
|
+
if (bounds.start.getElement() === bounds.end.getElement()) {
|
|
203
|
+
this.emitCellSelected(bounds.end);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
buildColumnDefinitions() {
|
|
207
|
+
return this.columns?.map((c) => {
|
|
208
|
+
const col = {
|
|
209
|
+
// TODO(help-wanted): Use strongly typed Tabulator col def
|
|
210
|
+
field: c.field,
|
|
211
|
+
title: c.title || c.field || c.title,
|
|
212
|
+
// headerTooltip: () =>
|
|
213
|
+
// `${c.colName || c.title || c.field}: ${c.dbType}`,
|
|
214
|
+
};
|
|
215
|
+
if (c.colName !== 'Id' && c.colName?.endsWith('Id')) {
|
|
216
|
+
col.formatter = 'link';
|
|
217
|
+
col.formatterParams = {
|
|
218
|
+
url: 'test-url',
|
|
219
|
+
};
|
|
220
|
+
col.cellClick = (e, cell) => {
|
|
221
|
+
void cell;
|
|
222
|
+
e.preventDefault();
|
|
223
|
+
e.stopPropagation();
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
if (c.tooltip) {
|
|
227
|
+
col.tooltip = c.tooltip;
|
|
228
|
+
}
|
|
229
|
+
if (c.formatter) {
|
|
230
|
+
col.formatter = c.formatter;
|
|
231
|
+
}
|
|
232
|
+
if (c.hozAlign) {
|
|
233
|
+
col.hozAlign = c.hozAlign;
|
|
234
|
+
}
|
|
235
|
+
if (c.headerHozAlign) {
|
|
236
|
+
col.headerHozAlign = c.headerHozAlign;
|
|
237
|
+
}
|
|
238
|
+
if (c.widthGrow) {
|
|
239
|
+
col.widthGrow = c.widthGrow;
|
|
240
|
+
}
|
|
241
|
+
if (c.widthShrink) {
|
|
242
|
+
col.widthShrink = c.widthShrink;
|
|
243
|
+
}
|
|
244
|
+
if (c.width !== undefined) {
|
|
245
|
+
col.width = c.width;
|
|
246
|
+
}
|
|
247
|
+
const marker = c.field ? this.columnMarkers?.[c.field] : undefined;
|
|
248
|
+
if (marker) {
|
|
249
|
+
col.titleFormatter = this.buildColumnMarkerTitleFormatter(marker);
|
|
250
|
+
}
|
|
251
|
+
// console.log('col:', col);
|
|
252
|
+
return col;
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Renders the column's title text plus an unobtrusive marker badge.
|
|
257
|
+
* Inline styles (rather than a stylesheet) keep this correct regardless
|
|
258
|
+
* of the host app's CSS and Angular's view encapsulation — Tabulator
|
|
259
|
+
* renders headers into plain DOM nodes outside the component's template,
|
|
260
|
+
* which emulated encapsulation would not otherwise scope styles onto.
|
|
261
|
+
*/
|
|
262
|
+
buildColumnMarkerTitleFormatter(marker) {
|
|
263
|
+
return (cell) => {
|
|
264
|
+
const wrapper = document.createElement('span');
|
|
265
|
+
wrapper.style.display = 'inline-flex';
|
|
266
|
+
wrapper.style.alignItems = 'center';
|
|
267
|
+
wrapper.style.gap = '4px';
|
|
268
|
+
const titleSpan = document.createElement('span');
|
|
269
|
+
titleSpan.textContent = String(cell.getValue() ?? '');
|
|
270
|
+
wrapper.appendChild(titleSpan);
|
|
271
|
+
const markerSpan = document.createElement('span');
|
|
272
|
+
markerSpan.textContent = marker.label;
|
|
273
|
+
markerSpan.style.display = 'inline-block';
|
|
274
|
+
markerSpan.style.fontSize = '0.65em';
|
|
275
|
+
markerSpan.style.fontWeight = '600';
|
|
276
|
+
markerSpan.style.lineHeight = '1.4';
|
|
277
|
+
markerSpan.style.padding = '0 4px';
|
|
278
|
+
markerSpan.style.borderRadius = '3px';
|
|
279
|
+
markerSpan.style.opacity = '0.75';
|
|
280
|
+
markerSpan.style.whiteSpace = 'nowrap';
|
|
281
|
+
markerSpan.style.border =
|
|
282
|
+
marker.kind === 'inferred'
|
|
283
|
+
? '1px dashed currentColor'
|
|
284
|
+
: '1px solid currentColor';
|
|
285
|
+
if (marker.kind === 'inferred') {
|
|
286
|
+
markerSpan.style.fontStyle = 'italic';
|
|
287
|
+
}
|
|
288
|
+
if (marker.title) {
|
|
289
|
+
markerSpan.title = marker.title;
|
|
290
|
+
}
|
|
291
|
+
wrapper.appendChild(markerSpan);
|
|
292
|
+
return wrapper;
|
|
293
|
+
};
|
|
294
|
+
}
|
|
186
295
|
setTabulatorOptions() {
|
|
187
296
|
this.tabulatorOptions = {
|
|
188
297
|
// tooltipsHeader: true, // enable header tooltips
|
|
@@ -191,51 +300,26 @@ class DataGridComponent {
|
|
|
191
300
|
selectableRows: this.selectable,
|
|
192
301
|
data: this.data,
|
|
193
302
|
// reactiveData: true, // enable data reactivity
|
|
194
|
-
columns: this.
|
|
195
|
-
const col = {
|
|
196
|
-
// TODO(help-wanted): Use strongly typed Tabulator col def
|
|
197
|
-
field: c.field,
|
|
198
|
-
title: c.title || c.field || c.title,
|
|
199
|
-
// headerTooltip: () =>
|
|
200
|
-
// `${c.colName || c.title || c.field}: ${c.dbType}`,
|
|
201
|
-
};
|
|
202
|
-
if (c.colName !== 'Id' && c.colName?.endsWith('Id')) {
|
|
203
|
-
col.formatter = 'link';
|
|
204
|
-
col.formatterParams = {
|
|
205
|
-
url: 'test-url',
|
|
206
|
-
};
|
|
207
|
-
col.cellClick = (e, cell) => {
|
|
208
|
-
void cell;
|
|
209
|
-
e.preventDefault();
|
|
210
|
-
e.stopPropagation();
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
if (c.tooltip) {
|
|
214
|
-
col.tooltip = c.tooltip;
|
|
215
|
-
}
|
|
216
|
-
if (c.formatter) {
|
|
217
|
-
col.formatter = c.formatter;
|
|
218
|
-
}
|
|
219
|
-
if (c.hozAlign) {
|
|
220
|
-
col.hozAlign = c.hozAlign;
|
|
221
|
-
}
|
|
222
|
-
if (c.headerHozAlign) {
|
|
223
|
-
col.headerHozAlign = c.headerHozAlign;
|
|
224
|
-
}
|
|
225
|
-
if (c.widthGrow) {
|
|
226
|
-
col.widthGrow = c.widthGrow;
|
|
227
|
-
}
|
|
228
|
-
if (c.widthShrink) {
|
|
229
|
-
col.widthShrink = c.widthShrink;
|
|
230
|
-
}
|
|
231
|
-
if (c.width !== undefined) {
|
|
232
|
-
col.width = c.width;
|
|
233
|
-
}
|
|
234
|
-
// console.log('col:', col);
|
|
235
|
-
return col;
|
|
236
|
-
}),
|
|
303
|
+
columns: this.buildColumnDefinitions(),
|
|
237
304
|
layout: this.layout || 'fitColumns',
|
|
238
305
|
};
|
|
306
|
+
if (this.selectableRange) {
|
|
307
|
+
this.tabulatorOptions = {
|
|
308
|
+
...this.tabulatorOptions,
|
|
309
|
+
selectableRange: this.selectableRange,
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
// Registering KeybindingsModule activates its default arrow/page/home
|
|
314
|
+
// keybindings table-wide (they only *do* something in modules that
|
|
315
|
+
// subscribe to them, but scrolling/focus side effects are otherwise
|
|
316
|
+
// observable). Explicitly disabling them keeps existing consumers'
|
|
317
|
+
// behaviour identical unless they opt into selectableRange.
|
|
318
|
+
this.tabulatorOptions = {
|
|
319
|
+
...this.tabulatorOptions,
|
|
320
|
+
keybindings: false,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
239
323
|
if (this.height) {
|
|
240
324
|
this.tabulatorOptions = {
|
|
241
325
|
...this.tabulatorOptions,
|
|
@@ -264,7 +348,7 @@ class DataGridComponent {
|
|
|
264
348
|
}
|
|
265
349
|
}
|
|
266
350
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: DataGridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
267
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.3", type: DataGridComponent, isStandalone: true, selector: "sneat-datagrid", inputs: { layout: "layout", data: "data", columns: "columns", groupBy: "groupBy", height: "height", maxHeight: "maxHeight", rowContextMenu: "rowContextMenu", rowClick: "rowClick", selectable: "selectable" }, outputs: { rowSelected: "rowSelected", rowDeselected: "rowDeselected" }, viewQueries: [{ propertyName: "tabulatorDiv", first: true, predicate: ["tabulatorDiv"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: `
|
|
351
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.3", type: DataGridComponent, isStandalone: true, selector: "sneat-datagrid", inputs: { layout: "layout", data: "data", columns: "columns", groupBy: "groupBy", height: "height", maxHeight: "maxHeight", rowContextMenu: "rowContextMenu", rowClick: "rowClick", selectableRange: "selectableRange", columnMarkers: "columnMarkers", selectable: "selectable" }, outputs: { rowSelected: "rowSelected", rowDeselected: "rowDeselected", cellSelected: "cellSelected" }, viewQueries: [{ propertyName: "tabulatorDiv", first: true, predicate: ["tabulatorDiv"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: `
|
|
268
352
|
<div id="tabulator" #tabulatorDiv></div>
|
|
269
353
|
<p class="ion-margin-start">Rows: {{ data?.length }}</p>
|
|
270
354
|
`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
@@ -303,6 +387,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
|
|
|
303
387
|
type: Output
|
|
304
388
|
}], rowDeselected: [{
|
|
305
389
|
type: Output
|
|
390
|
+
}], selectableRange: [{
|
|
391
|
+
type: Input
|
|
392
|
+
}], columnMarkers: [{
|
|
393
|
+
type: Input
|
|
394
|
+
}], cellSelected: [{
|
|
395
|
+
type: Output
|
|
306
396
|
}], selectable: [{
|
|
307
397
|
type: Input
|
|
308
398
|
}] } });
|
|
@@ -329,5 +419,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
|
|
|
329
419
|
* Generated bundle index. Do not edit.
|
|
330
420
|
*/
|
|
331
421
|
|
|
332
|
-
export {
|
|
422
|
+
export { DataGridComponent };
|
|
333
423
|
//# sourceMappingURL=sneat-datagrid.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sneat-datagrid.mjs","sources":["../../../../libs/datagrid/src/lib/components/cell-popover/cell-popover.component.ts","../../../../libs/datagrid/src/lib/components/cell-popover/cell-popover.component.html","../../../../libs/datagrid/src/lib/components/data-grid/data-grid.component.ts","../../../../libs/datagrid/src/lib/tabulator/tabulator-options.ts","../../../../libs/datagrid/src/sneat-datagrid.ts"],"sourcesContent":["import { Component, Input, ChangeDetectionStrategy } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { RouterModule } from '@angular/router';\nimport {\n IonBadge,\n IonCardHeader,\n IonCardSubtitle,\n IonCardTitle,\n IonInput,\n IonItem,\n IonLabel,\n IonList,\n IonSegment,\n IonSegmentButton,\n IonText,\n} from '@ionic/angular';\n\n// TODO: Local minimal copies to avoid dependency on @sneat/datatug-main and break circular build deps\ninterface IRecordsetColumn {\n name: string;\n title?: string;\n dbType: string; // Using string here to avoid coupling to DbType type from datatug-main\n}\n\ninterface ITableRef {\n name: string;\n schema: string;\n catalog?: string;\n}\n\ninterface IForeignKey {\n name: string;\n columns: string[];\n refTable: ITableRef;\n}\n\n@Component({\n selector: 'sneat-datatug-cell-popover',\n templateUrl: './cell-popover.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n RouterModule,\n FormsModule,\n IonCardHeader,\n IonCardTitle,\n IonCardSubtitle,\n IonSegment,\n IonSegmentButton,\n IonLabel,\n IonList,\n IonItem,\n IonInput,\n IonBadge,\n IonText,\n ],\n})\nexport class CellPopoverComponent {\n // TODO: Skipped for migration because:\n // Your application code writes to the input. This prevents migration.\n @Input() column?: IRecordsetColumn;\n // TODO: Skipped for migration because:\n // Your application code writes to the input. This prevents migration.\n @Input() value: unknown;\n // TODO: Skipped for migration because:\n // Your application code writes to the input. This prevents migration.\n @Input() fk?: IForeignKey;\n\n public tab: 'rec' | 'cols' | 'refs' = 'rec';\n}\n","<ion-card-header>\n <ion-card-title>Field: {{ column?.name }}</ion-card-title>\n <ion-card-subtitle>Value: {{ value }}</ion-card-subtitle>\n</ion-card-header>\n<h3 class=\"ion-margin\">\n References:\n @if (fk?.refTable) {\n <a routerLink=\"{{ fk?.refTable?.schema }}.{{ fk?.refTable?.name }}\">\n {{ fk?.refTable?.schema }}.{{ fk?.refTable?.name }}\n </a>\n }\n</h3>\n<ion-segment [(ngModel)]=\"tab\">\n <ion-segment-button value=\"rec\">\n <ion-label>Record</ion-label>\n </ion-segment-button>\n <ion-segment-button value=\"cols\">\n <ion-label>Columns</ion-label>\n </ion-segment-button>\n <ion-segment-button value=\"refs\">\n <ion-label>References</ion-label>\n </ion-segment-button>\n</ion-segment>\n\n@switch (tab) {\n @case (\"rec\") {\n <ion-list>\n <ion-item>\n <ion-label>Id</ion-label>\n <ion-input\n type=\"number\"\n style=\"text-align: right\"\n value=\"1\"\n readonly=\"true\"\n />\n </ion-item>\n <ion-item>\n <ion-label>Code</ion-label>\n <ion-input\n type=\"text\"\n style=\"text-align: right\"\n value=\"Something\"\n readonly=\"true\"\n />\n </ion-item>\n </ion-list>\n }\n @case (\"cols\") {\n <ion-list>\n <ion-item>\n <ion-label>Id</ion-label>\n <ion-badge slot=\"end\" color=\"light\">\n <ion-text color=\"medium\">INT</ion-text>\n </ion-badge>\n </ion-item>\n <ion-item>\n <ion-label>Code</ion-label>\n <ion-badge slot=\"end\" color=\"light\">\n <ion-text color=\"medium\">NVARCHAR</ion-text>\n </ion-badge>\n </ion-item>\n </ion-list>\n }\n}\n","import {\n AfterViewInit,\n Component,\n ElementRef,\n EventEmitter,\n Input,\n OnChanges,\n Output,\n SimpleChanges,\n ViewChild,\n inject,\n ChangeDetectionStrategy\n} from '@angular/core';\nimport { ErrorLogger, IErrorLogger } from '@sneat/core';\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nimport {\n Tabulator,\n SelectRowModule,\n MenuModule,\n InteractionModule,\n Module,\n RowContextMenuSignature,\n} from 'tabulator-tables';\nimport { IGridColumn } from '@sneat/grid';\nimport { TabulatorColumn, TabulatorOptions } from '../../tabulator';\n\nclass AdvertModule extends Module {\n public static override moduleName = 'advert';\n\n override initialize() {\n return;\n }\n}\n\nTabulator.registerModule([\n InteractionModule,\n SelectRowModule,\n AdvertModule,\n MenuModule,\n]);\n\n\n// export interface IGridDef {\n// \tcolumns: IGridColumn[],\n// \trows?: unknown[],\n// \tgroupBy?: string;\n// }\n//\n// export const getTabulatorCols = (cols: IGridColumn[]): any[] => cols.map(c => {\n// \tconst v = {...c};\n// \tdelete v.dbType;\n// \treturn v;\n// });\n//\n// export interface IGridColumn {\n// \tfield: string;\n// \tcolName?: string;\n// \tdbType: string;\n// \ttitle: string;\n// \ttooltip?: (cell: any) => string;\n// \tformatter?: any;\n// \thozAlign?: 'left' | 'right';\n// \twidthShrink?: number;\n// \twidthGrow?: number;\n// \twidth?: number | string;\n// }\n\n/**\n * This is a wrapper class for the tabulator JS library.\n * For more info see http://tabulator.info\n */\n@Component({\n selector: 'sneat-datagrid',\n template: `\n <div id=\"tabulator\" #tabulatorDiv></div>\n <p class=\"ion-margin-start\">Rows: {{ data?.length }}</p>\n `,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [],\n})\nexport class DataGridComponent implements AfterViewInit, OnChanges {\n private readonly errorLogger = inject<IErrorLogger>(ErrorLogger);\n\n // TODO: Skipped for migration because:\n // Your application code writes to the input. This prevents migration.\n @Input() layout?: 'fitData' | 'fitColumns' = 'fitColumns';\n // TODO: Skipped for migration because:\n // Your application code writes to the input. This prevents migration.\n @Input() data?: unknown[] = [];\n // TODO: Skipped for migration because:\n // Your application code writes to the input. This prevents migration.\n @Input() columns?: IGridColumn[] = [];\n // TODO: Skipped for migration because:\n // Your application code writes to the input. This prevents migration.\n @Input() groupBy?: string;\n // TODO: Skipped for migration because:\n // Your application code writes to the input. This prevents migration.\n @Input() height?: string;\n // TODO: Skipped for migration because:\n // Your application code writes to the input. This prevents migration.\n @Input() maxHeight?: string | number;\n // TODO: Skipped for migration because:\n // Your application code writes to the input. This prevents migration.\n @Input() rowContextMenu?: RowContextMenuSignature;\n @ViewChild('tabulatorDiv', { static: true }) tabulatorDiv?: ElementRef;\n\n // TODO: Skipped for migration because:\n // Your application code writes to the input. This prevents migration.\n @Input() rowClick?: (event: Event, row: unknown) => void;\n\n @Output() readonly rowSelected = new EventEmitter<{\n row: unknown;\n event?: Event;\n }>();\n\n @Output() readonly rowDeselected = new EventEmitter<{\n row: unknown;\n event?: Event;\n }>();\n\n // private tab = document.createElement('div');\n private tabulator?: Tabulator;\n\n // TODO: Skipped for migration because:\n // Your application code writes to the input. This prevents migration.\n @Input() public selectable?: boolean | number | 'highlight';\n\n private tabulatorOptions?: TabulatorOptions;\n private clickEvent?: Event;\n\n ngOnChanges(changes: SimpleChanges): void {\n try {\n if (\n (changes['data'] && this.data && this.columns) ||\n (changes['columns'] && this.columns) ||\n (changes['rowClick'] && this.rowClick)\n ) {\n this.drawTable();\n }\n } catch (ex) {\n this.errorLogger.logError(\n ex,\n 'Failed to process ngOnChanges in DataGridComponent',\n );\n }\n }\n\n // ngOnDestroy(): void {\n // console.log('DataGridComponent.ngOnDestroy()', this.tabulator);\n // try { // TODO: destroy Tabulator\n // \tif (this.tabulator?.element) {\n // \t\t// noinspection TypeScriptValidateJSTypes\n // \t\tthis.tabulator.element.tabulator('destroy');\n // \t}\n // } catch (ex) {\n // \tthis.errorLogger.logError(ex, 'Failed to destroy tabulator');\n // }\n // }\n\n ngAfterViewInit(): void /* Intentionally not ngOnInit */ {\n if (this.tabulator) {\n try {\n this.tabulator.redraw();\n } catch (e) {\n this.errorLogger.logError(e, 'Failed to redraw tabulator', {\n show: false,\n report: false,\n });\n }\n }\n }\n\n private drawTable(): void {\n if (!this.data || !this.columns) {\n console.warn('drawTable()', 'columns:', this.columns, 'data:', this.data);\n return;\n }\n try {\n if (!this.tabulatorDiv) {\n this.errorLogger.logError(new Error('!this.tabulatorDiv'));\n return;\n }\n if (this.tabulatorOptions) {\n this.tabulatorOptions = { ...this.tabulatorOptions, data: this.data };\n this.tabulator\n ?.setData(this.data)\n .catch(this.errorLogger.logErrorHandler('Failed to set data'));\n } else {\n this.createTabulatorGrid();\n }\n // this.tabulatorDiv.nativeElement.appendChild(this.tab);\n // tabulator.redraw();\n } catch (e) {\n this.errorLogger.logError(e, 'Failed to drawTable');\n }\n }\n\n private createTabulatorGrid(): void {\n this.setTabulatorOptions();\n if (!this.tabulator) {\n this.tabulatorOptions = {\n ...this.tabulatorOptions,\n // rowClick: function (e, row) {\n // \tconsole.log('rowClick1', row);\n // },\n // rowSelect: function (row) {\n // \tconsole.log('rowSelect', row);\n // },\n // rowDeselect: function (row) {\n // \tconsole.log('rowDeselect', row);\n // }\n };\n this.tabulator = new Tabulator(\n this.tabulatorDiv?.nativeElement,\n this.tabulatorOptions,\n );\n this.tabulator.on('rowClick', (event: Event, row: unknown) => {\n this.clickEvent = event;\n if (this.rowClick) {\n this.rowClick(event, row);\n }\n });\n this.tabulator.on('rowSelected', (row: unknown) =>\n this.rowSelected.emit({ row, event: this.clickEvent }),\n );\n this.tabulator.on('rowDeselected', (row: unknown) =>\n this.rowDeselected.emit({ row, event: this.clickEvent }),\n );\n }\n }\n\n private setTabulatorOptions(): void {\n this.tabulatorOptions = {\n // tooltipsHeader: true, // enable header tooltips\n // tooltipGenerationMode: 'hover',\n rowContextMenu: this.rowContextMenu,\n selectableRows: this.selectable,\n data: this.data,\n // reactiveData: true, // enable data reactivity\n columns: this.columns?.map((c) => {\n const col: TabulatorColumn = {\n // TODO(help-wanted): Use strongly typed Tabulator col def\n field: c.field,\n title: c.title || c.field || c.title,\n // headerTooltip: () =>\n // \t`${c.colName || c.title || c.field}: ${c.dbType}`,\n };\n if (c.colName !== 'Id' && c.colName?.endsWith('Id')) {\n col.formatter = 'link';\n col.formatterParams = {\n url: 'test-url',\n };\n col.cellClick = (e: Event, cell: unknown) => {\n void cell;\n e.preventDefault();\n e.stopPropagation();\n };\n }\n if (c.tooltip) {\n col.tooltip = c.tooltip;\n }\n if (c.formatter) {\n col.formatter = c.formatter;\n }\n if (c.hozAlign) {\n col.hozAlign = c.hozAlign;\n }\n if (c.headerHozAlign) {\n col.headerHozAlign = c.headerHozAlign;\n }\n if (c.widthGrow) {\n col.widthGrow = c.widthGrow;\n }\n if (c.widthShrink) {\n col.widthShrink = c.widthShrink;\n }\n if (c.width !== undefined) {\n col.width = c.width;\n }\n // console.log('col:', col);\n return col;\n }),\n layout: this.layout || 'fitColumns',\n };\n if (this.height) {\n this.tabulatorOptions = {\n ...this.tabulatorOptions,\n height: this.height,\n };\n }\n if (this.maxHeight) {\n this.tabulatorOptions = {\n ...this.tabulatorOptions,\n maxHeight: this.maxHeight,\n };\n }\n if (this.groupBy) {\n this.tabulatorOptions = {\n ...this.tabulatorOptions,\n groupBy: this.groupBy,\n groupHeader: (value: unknown, count: number) => {\n // value - the value all members of this group share\n // count - the number of rows in this group\n // data - an array of all the row data objects in this group\n // group - the group component for the group\n // console.log('groupHeader', value);\n return `${\n this.groupBy\n }: ${value} <span class=\"ion-margin-start\">(${count} ${\n count === 1 ? 'record' : 'records'\n })</span>`;\n },\n };\n }\n }\n}\n","import { ColumnDefinition, Options } from 'tabulator-tables';\n\nexport type TabulatorColumn = ColumnDefinition;\n\n// export interface TabulatorColumn {\n// \tfield: string;\n// \ttitle?: string;\n// \tformatter?: 'link' | 'progress' | 'html' | 'text' | 'number' | 'money' | 'image' | 'tickCross';\n// \tformatterParams?: unknown;\n// \tcellClick?: (e: Event, cell: unknown) => void;\n// \theaderTooltip?: () => string;\n// \ttooltip?: (cell: unknown) => string;\n// \thozAlign?: 'left' | 'right';\n// \theaderHozAlign?: 'left' | 'right';\n// \twidthShrink?: number;\n// \twidthGrow?: number;\n// \twidth?: number | string;\n// }\n\nexport type TabulatorOptions = Options;\n// export interface TabulatorOptions {\n// \treadonly tooltipsHeader?: boolean;\n// \treadonly tooltipGenerationMode?: 'hover' | 'mouseover';\n// \treadonly reactiveData?: boolean;\n// \treadonly selectable?: boolean | number | 'highlight';\n// \treadonly data?: unknown[];\n// \treadonly layout?: 'fitData' | 'fitColumns';\n// \treadonly columns?: TabulatorColumn[];\n// \treadonly height?: string | number;\n// \treadonly maxHeight?: string | number;\n// \treadonly groupBy?: string;\n// \treadonly groupHeader?: (value: unknown, count: number) => string;\n// \treadonly rowClick?: (event: Event, row: unknown) => void;\n// \treadonly rowSelect?: (row: unknown) => void;\n// \treadonly rowDeselect?: (row: unknown) => void;\n// \treadonly rowContextMenu?: IRowMenu[];\n// }\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sneat-datagrid.mjs","sources":["../../../../libs/datagrid/src/lib/components/data-grid/data-grid.component.ts","../../../../libs/datagrid/src/lib/tabulator/tabulator-options.ts","../../../../libs/datagrid/src/sneat-datagrid.ts"],"sourcesContent":["import {\n AfterViewInit,\n Component,\n ElementRef,\n EventEmitter,\n Input,\n OnChanges,\n Output,\n SimpleChanges,\n ViewChild,\n inject,\n ChangeDetectionStrategy\n} from '@angular/core';\nimport { ErrorLogger, IErrorLogger } from '@sneat/core';\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nimport {\n Tabulator,\n SelectRowModule,\n SelectRangeModule,\n KeybindingsModule,\n MenuModule,\n InteractionModule,\n Module,\n RowContextMenuSignature,\n} from 'tabulator-tables';\nimport type {\n CellComponent,\n Formatter,\n RangeComponent,\n} from 'tabulator-tables';\nimport { IGridColumn } from '@sneat/grid';\nimport { TabulatorColumn, TabulatorOptions } from '../../tabulator';\n\nclass AdvertModule extends Module {\n public static override moduleName = 'advert';\n\n override initialize() {\n return;\n }\n}\n\nTabulator.registerModule([\n InteractionModule,\n SelectRowModule,\n // SelectRange enables opt-in cell/range selection (selectableRange input).\n // KeybindingsModule wires the arrow-key navigation SelectRange relies on;\n // its default bindings are only *active* when we don't disable them via\n // the `keybindings` table option, which we do unless selectableRange is on\n // (see setTabulatorOptions()) so existing consumers see no behaviour change.\n SelectRangeModule,\n KeybindingsModule,\n AdvertModule,\n MenuModule,\n]);\n\n/**\n * A marker rendered unobtrusively in a column's header, e.g. to flag a\n * semantically-recognised field (a declared or inferred `CustomerId`, etc).\n * The grid has no semantic logic of its own — it only renders what the\n * consumer passes here.\n */\nexport interface IDataGridColumnMarker {\n readonly label: string;\n readonly title?: string;\n readonly kind?: 'declared' | 'inferred';\n}\n\n/** Payload emitted by {@link DataGridComponent.cellSelected}. */\nexport interface IDataGridCellSelectedEvent {\n readonly row: unknown;\n readonly column: { readonly field: string; readonly index: number };\n readonly value: unknown;\n readonly rowData: unknown;\n}\n\n// export interface IGridDef {\n// \tcolumns: IGridColumn[],\n// \trows?: unknown[],\n// \tgroupBy?: string;\n// }\n//\n// export const getTabulatorCols = (cols: IGridColumn[]): any[] => cols.map(c => {\n// \tconst v = {...c};\n// \tdelete v.dbType;\n// \treturn v;\n// });\n//\n// export interface IGridColumn {\n// \tfield: string;\n// \tcolName?: string;\n// \tdbType: string;\n// \ttitle: string;\n// \ttooltip?: (cell: any) => string;\n// \tformatter?: any;\n// \thozAlign?: 'left' | 'right';\n// \twidthShrink?: number;\n// \twidthGrow?: number;\n// \twidth?: number | string;\n// }\n\n/**\n * This is a wrapper class for the tabulator JS library.\n * For more info see http://tabulator.info\n */\n@Component({\n selector: 'sneat-datagrid',\n template: `\n <div id=\"tabulator\" #tabulatorDiv></div>\n <p class=\"ion-margin-start\">Rows: {{ data?.length }}</p>\n `,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [],\n})\nexport class DataGridComponent implements AfterViewInit, OnChanges {\n private readonly errorLogger = inject<IErrorLogger>(ErrorLogger);\n\n // TODO: Skipped for migration because:\n // Your application code writes to the input. This prevents migration.\n @Input() layout?: 'fitData' | 'fitColumns' = 'fitColumns';\n // TODO: Skipped for migration because:\n // Your application code writes to the input. This prevents migration.\n @Input() data?: unknown[] = [];\n // TODO: Skipped for migration because:\n // Your application code writes to the input. This prevents migration.\n @Input() columns?: IGridColumn[] = [];\n // TODO: Skipped for migration because:\n // Your application code writes to the input. This prevents migration.\n @Input() groupBy?: string;\n // TODO: Skipped for migration because:\n // Your application code writes to the input. This prevents migration.\n @Input() height?: string;\n // TODO: Skipped for migration because:\n // Your application code writes to the input. This prevents migration.\n @Input() maxHeight?: string | number;\n // TODO: Skipped for migration because:\n // Your application code writes to the input. This prevents migration.\n @Input() rowContextMenu?: RowContextMenuSignature;\n @ViewChild('tabulatorDiv', { static: true }) tabulatorDiv?: ElementRef;\n\n // TODO: Skipped for migration because:\n // Your application code writes to the input. This prevents migration.\n @Input() rowClick?: (event: Event, row: unknown) => void;\n\n @Output() readonly rowSelected = new EventEmitter<{\n row: unknown;\n event?: Event;\n }>();\n\n @Output() readonly rowDeselected = new EventEmitter<{\n row: unknown;\n event?: Event;\n }>();\n\n /**\n * Enables Tabulator's cell/range selection (opt-in; off by default so\n * existing consumers are unaffected). Mirrors Tabulator's own\n * `selectableRange` option: `true` for unlimited ranges, or a number to\n * cap how many ranges can be selected at once. Mutually exclusive with\n * row selection (`selectable`) — Tabulator disables range selection and\n * logs a console warning if both are set.\n */\n @Input() public selectableRange?: boolean | number;\n\n /**\n * Small, unobtrusive markers rendered in column headers, keyed by field.\n * The grid applies no semantic meaning to these — it only renders what\n * the consumer passes (e.g. a semantic-detection layer flagging a\n * `CustomerId` column).\n */\n @Input() public columnMarkers?: Record<string, IDataGridColumnMarker>;\n\n /**\n * Emitted when a single cell becomes the active selection, either via a\n * mouse click (always, regardless of `selectableRange`) or, once\n * `selectableRange` is enabled, via keyboard arrow-key navigation between\n * cells. Not emitted for multi-cell range drag-selection.\n */\n @Output() readonly cellSelected = new EventEmitter<IDataGridCellSelectedEvent>();\n\n // private tab = document.createElement('div');\n private tabulator?: Tabulator;\n\n // TODO: Skipped for migration because:\n // Your application code writes to the input. This prevents migration.\n @Input() public selectable?: boolean | number | 'highlight';\n\n private tabulatorOptions?: TabulatorOptions;\n private clickEvent?: Event;\n\n ngOnChanges(changes: SimpleChanges): void {\n try {\n if (\n (changes['data'] && this.data && this.columns) ||\n (changes['columns'] && this.columns) ||\n (changes['rowClick'] && this.rowClick)\n ) {\n this.drawTable();\n } else if (changes['columnMarkers'] && this.tabulator && this.columns) {\n // columnMarkers can arrive after the initial draw (e.g. a semantic\n // layer resolving markers asynchronously) — refresh header markers\n // in place without a full data redraw.\n const columnDefinitions = this.buildColumnDefinitions();\n if (columnDefinitions) {\n this.tabulator.setColumns(columnDefinitions);\n }\n }\n } catch (ex) {\n this.errorLogger.logError(\n ex,\n 'Failed to process ngOnChanges in DataGridComponent',\n );\n }\n }\n\n // ngOnDestroy(): void {\n // console.log('DataGridComponent.ngOnDestroy()', this.tabulator);\n // try { // TODO: destroy Tabulator\n // \tif (this.tabulator?.element) {\n // \t\t// noinspection TypeScriptValidateJSTypes\n // \t\tthis.tabulator.element.tabulator('destroy');\n // \t}\n // } catch (ex) {\n // \tthis.errorLogger.logError(ex, 'Failed to destroy tabulator');\n // }\n // }\n\n ngAfterViewInit(): void /* Intentionally not ngOnInit */ {\n if (this.tabulator) {\n try {\n this.tabulator.redraw();\n } catch (e) {\n this.errorLogger.logError(e, 'Failed to redraw tabulator', {\n show: false,\n report: false,\n });\n }\n }\n }\n\n private drawTable(): void {\n if (!this.data || !this.columns) {\n console.warn('drawTable()', 'columns:', this.columns, 'data:', this.data);\n return;\n }\n try {\n if (!this.tabulatorDiv) {\n this.errorLogger.logError(new Error('!this.tabulatorDiv'));\n return;\n }\n if (this.tabulatorOptions) {\n this.tabulatorOptions = { ...this.tabulatorOptions, data: this.data };\n this.tabulator\n ?.setData(this.data)\n .catch(this.errorLogger.logErrorHandler('Failed to set data'));\n } else {\n this.createTabulatorGrid();\n }\n // this.tabulatorDiv.nativeElement.appendChild(this.tab);\n // tabulator.redraw();\n } catch (e) {\n this.errorLogger.logError(e, 'Failed to drawTable');\n }\n }\n\n private createTabulatorGrid(): void {\n this.setTabulatorOptions();\n if (!this.tabulator) {\n this.tabulatorOptions = {\n ...this.tabulatorOptions,\n // rowClick: function (e, row) {\n // \tconsole.log('rowClick1', row);\n // },\n // rowSelect: function (row) {\n // \tconsole.log('rowSelect', row);\n // },\n // rowDeselect: function (row) {\n // \tconsole.log('rowDeselect', row);\n // }\n };\n this.tabulator = new Tabulator(\n this.tabulatorDiv?.nativeElement,\n this.tabulatorOptions,\n );\n this.tabulator.on('rowClick', (event: Event, row: unknown) => {\n this.clickEvent = event;\n if (this.rowClick) {\n this.rowClick(event, row);\n }\n });\n this.tabulator.on('rowSelected', (row: unknown) =>\n this.rowSelected.emit({ row, event: this.clickEvent }),\n );\n this.tabulator.on('rowDeselected', (row: unknown) =>\n this.rowDeselected.emit({ row, event: this.clickEvent }),\n );\n // Mouse-click selection: fires regardless of selectableRange.\n this.tabulator.on('cellClick', (_event: UIEvent, cell: CellComponent) => {\n this.emitCellSelected(cell);\n });\n // Keyboard-driven selection: only fires once selectableRange is on —\n // the SelectRange module is inert otherwise. A plain click always\n // creates a *new* range (rangeAdded), so listening to rangeChanged\n // (bounds moved on the *existing* range) picks up arrow-key\n // navigation and single-cell drag adjustments without double-firing\n // alongside the cellClick handler above.\n this.tabulator.on('rangeChanged', (range: RangeComponent) => {\n this.handleRangeChanged(range);\n });\n }\n }\n\n /** column.index is the field's position in the `columns` input array. */\n private emitCellSelected(cell: CellComponent): void {\n const field = cell.getField();\n this.cellSelected.emit({\n row: cell.getRow(),\n column: {\n field,\n index: this.columns?.findIndex((c) => c.field === field) ?? -1,\n },\n value: cell.getValue(),\n rowData: cell.getData(),\n });\n }\n\n private handleRangeChanged(range: RangeComponent): void {\n const bounds = range.getBounds();\n // Only report single-cell selections; multi-cell range drag-selection\n // is visual-only for now (out of scope for this task).\n if (bounds.start.getElement() === bounds.end.getElement()) {\n this.emitCellSelected(bounds.end);\n }\n }\n\n private buildColumnDefinitions(): TabulatorColumn[] | undefined {\n return this.columns?.map((c) => {\n const col: TabulatorColumn = {\n // TODO(help-wanted): Use strongly typed Tabulator col def\n field: c.field,\n title: c.title || c.field || c.title,\n // headerTooltip: () =>\n // \t`${c.colName || c.title || c.field}: ${c.dbType}`,\n };\n if (c.colName !== 'Id' && c.colName?.endsWith('Id')) {\n col.formatter = 'link';\n col.formatterParams = {\n url: 'test-url',\n };\n col.cellClick = (e: Event, cell: unknown) => {\n void cell;\n e.preventDefault();\n e.stopPropagation();\n };\n }\n if (c.tooltip) {\n col.tooltip = c.tooltip;\n }\n if (c.formatter) {\n col.formatter = c.formatter;\n }\n if (c.hozAlign) {\n col.hozAlign = c.hozAlign;\n }\n if (c.headerHozAlign) {\n col.headerHozAlign = c.headerHozAlign;\n }\n if (c.widthGrow) {\n col.widthGrow = c.widthGrow;\n }\n if (c.widthShrink) {\n col.widthShrink = c.widthShrink;\n }\n if (c.width !== undefined) {\n col.width = c.width;\n }\n const marker = c.field ? this.columnMarkers?.[c.field] : undefined;\n if (marker) {\n col.titleFormatter = this.buildColumnMarkerTitleFormatter(marker);\n }\n // console.log('col:', col);\n return col;\n });\n }\n\n /**\n * Renders the column's title text plus an unobtrusive marker badge.\n * Inline styles (rather than a stylesheet) keep this correct regardless\n * of the host app's CSS and Angular's view encapsulation — Tabulator\n * renders headers into plain DOM nodes outside the component's template,\n * which emulated encapsulation would not otherwise scope styles onto.\n */\n private buildColumnMarkerTitleFormatter(\n marker: IDataGridColumnMarker,\n ): Formatter {\n return (cell: CellComponent): HTMLElement => {\n const wrapper = document.createElement('span');\n wrapper.style.display = 'inline-flex';\n wrapper.style.alignItems = 'center';\n wrapper.style.gap = '4px';\n\n const titleSpan = document.createElement('span');\n titleSpan.textContent = String(cell.getValue() ?? '');\n wrapper.appendChild(titleSpan);\n\n const markerSpan = document.createElement('span');\n markerSpan.textContent = marker.label;\n markerSpan.style.display = 'inline-block';\n markerSpan.style.fontSize = '0.65em';\n markerSpan.style.fontWeight = '600';\n markerSpan.style.lineHeight = '1.4';\n markerSpan.style.padding = '0 4px';\n markerSpan.style.borderRadius = '3px';\n markerSpan.style.opacity = '0.75';\n markerSpan.style.whiteSpace = 'nowrap';\n markerSpan.style.border =\n marker.kind === 'inferred'\n ? '1px dashed currentColor'\n : '1px solid currentColor';\n if (marker.kind === 'inferred') {\n markerSpan.style.fontStyle = 'italic';\n }\n if (marker.title) {\n markerSpan.title = marker.title;\n }\n wrapper.appendChild(markerSpan);\n\n return wrapper;\n };\n }\n\n private setTabulatorOptions(): void {\n this.tabulatorOptions = {\n // tooltipsHeader: true, // enable header tooltips\n // tooltipGenerationMode: 'hover',\n rowContextMenu: this.rowContextMenu,\n selectableRows: this.selectable,\n data: this.data,\n // reactiveData: true, // enable data reactivity\n columns: this.buildColumnDefinitions(),\n layout: this.layout || 'fitColumns',\n };\n if (this.selectableRange) {\n this.tabulatorOptions = {\n ...this.tabulatorOptions,\n selectableRange: this.selectableRange,\n };\n } else {\n // Registering KeybindingsModule activates its default arrow/page/home\n // keybindings table-wide (they only *do* something in modules that\n // subscribe to them, but scrolling/focus side effects are otherwise\n // observable). Explicitly disabling them keeps existing consumers'\n // behaviour identical unless they opt into selectableRange.\n this.tabulatorOptions = {\n ...this.tabulatorOptions,\n keybindings: false,\n };\n }\n if (this.height) {\n this.tabulatorOptions = {\n ...this.tabulatorOptions,\n height: this.height,\n };\n }\n if (this.maxHeight) {\n this.tabulatorOptions = {\n ...this.tabulatorOptions,\n maxHeight: this.maxHeight,\n };\n }\n if (this.groupBy) {\n this.tabulatorOptions = {\n ...this.tabulatorOptions,\n groupBy: this.groupBy,\n groupHeader: (value: unknown, count: number) => {\n // value - the value all members of this group share\n // count - the number of rows in this group\n // data - an array of all the row data objects in this group\n // group - the group component for the group\n // console.log('groupHeader', value);\n return `${\n this.groupBy\n }: ${value} <span class=\"ion-margin-start\">(${count} ${\n count === 1 ? 'record' : 'records'\n })</span>`;\n },\n };\n }\n }\n}\n","import { ColumnDefinition, Options } from 'tabulator-tables';\n\nexport type TabulatorColumn = ColumnDefinition;\n\n// export interface TabulatorColumn {\n// \tfield: string;\n// \ttitle?: string;\n// \tformatter?: 'link' | 'progress' | 'html' | 'text' | 'number' | 'money' | 'image' | 'tickCross';\n// \tformatterParams?: unknown;\n// \tcellClick?: (e: Event, cell: unknown) => void;\n// \theaderTooltip?: () => string;\n// \ttooltip?: (cell: unknown) => string;\n// \thozAlign?: 'left' | 'right';\n// \theaderHozAlign?: 'left' | 'right';\n// \twidthShrink?: number;\n// \twidthGrow?: number;\n// \twidth?: number | string;\n// }\n\nexport type TabulatorOptions = Options;\n// export interface TabulatorOptions {\n// \treadonly tooltipsHeader?: boolean;\n// \treadonly tooltipGenerationMode?: 'hover' | 'mouseover';\n// \treadonly reactiveData?: boolean;\n// \treadonly selectable?: boolean | number | 'highlight';\n// \treadonly data?: unknown[];\n// \treadonly layout?: 'fitData' | 'fitColumns';\n// \treadonly columns?: TabulatorColumn[];\n// \treadonly height?: string | number;\n// \treadonly maxHeight?: string | number;\n// \treadonly groupBy?: string;\n// \treadonly groupHeader?: (value: unknown, count: number) => string;\n// \treadonly rowClick?: (event: Event, row: unknown) => void;\n// \treadonly rowSelect?: (row: unknown) => void;\n// \treadonly rowDeselect?: (row: unknown) => void;\n// \treadonly rowContextMenu?: IRowMenu[];\n// }\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|