@scion/components 22.4.0 → 22.6.0
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/_index.scss +32 -88
- package/fesm2022/scion-components-common.mjs +179 -5
- package/fesm2022/scion-components-common.mjs.map +1 -1
- package/fesm2022/scion-components-dimension.mjs +3 -3
- package/fesm2022/scion-components-dimension.mjs.map +1 -1
- package/fesm2022/scion-components-icon.mjs +134 -98
- package/fesm2022/scion-components-icon.mjs.map +1 -1
- package/fesm2022/scion-components-menu.mjs +61 -60
- package/fesm2022/scion-components-menu.mjs.map +1 -1
- package/fesm2022/scion-components-sashbox.mjs +1 -1
- package/fesm2022/scion-components-sashbox.mjs.map +1 -1
- package/fesm2022/scion-components-splitter.mjs +2 -2
- package/fesm2022/scion-components-splitter.mjs.map +1 -1
- package/fesm2022/scion-components-table.mjs +584 -182
- package/fesm2022/scion-components-table.mjs.map +1 -1
- package/fesm2022/scion-components-text.mjs +83 -40
- package/fesm2022/scion-components-text.mjs.map +1 -1
- package/fesm2022/scion-components-throbber.mjs +1 -1
- package/fesm2022/scion-components-throbber.mjs.map +1 -1
- package/fesm2022/scion-components-viewport.mjs +31 -18
- package/fesm2022/scion-components-viewport.mjs.map +1 -1
- package/package.json +2 -2
- package/types/scion-components-common.d.ts +125 -4
- package/types/scion-components-icon.d.ts +42 -15
- package/types/scion-components-menu.d.ts +7 -2
- package/types/scion-components-sashbox.d.ts +1 -1
- package/types/scion-components-splitter.d.ts +1 -1
- package/types/scion-components-table.d.ts +772 -69
- package/types/scion-components-text.d.ts +6 -5
- package/types/scion-components-throbber.d.ts +1 -1
- package/types/scion-components-viewport.d.ts +20 -11
- package/viewport/scrollbar/_scrollbar.scss +12 -0
- package/design/icons/_scion-icon-font.scss +0 -50
|
@@ -1,23 +1,117 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { computed, signal, InjectionToken, makeEnvironmentProviders,
|
|
3
|
-
import
|
|
2
|
+
import { computed, inject, Injector, DEFAULT_CURRENCY_CODE, untracked, signal, InjectionToken, makeEnvironmentProviders, DestroyRef, runInInjectionContext, onIdle, Injectable, linkedSignal, isSignal, NgZone, effect, resource, assertNotInReactiveContext, assertInInjectionContext, Pipe, input, Component, output, viewChild, Directive, afterNextRender, ElementRef, debounced, viewChildren, ViewEncapsulation } from '@angular/core';
|
|
3
|
+
import * as i1 from '@scion/components/common';
|
|
4
|
+
import { coerceSignal, SCI_LOCALE, ɵSingleActiveInjectorFactory as _SingleActiveInjectorFactory, toLazyObservable, ɵcreateDestroyableInjector as _createDestroyableInjector, SciComponentOutletDirective, SciTooltipOnOverflowDirective, TOOLTIP_ON_OVERFLOW_DIRECTIVE_ADDITIONAL_TEXT, TOOLTIP_ON_OVERFLOW_DIRECTIVE_SOURCE_ELEMENT, SciAttributesDirective } from '@scion/components/common';
|
|
5
|
+
import { formatDate, DATE_PIPE_DEFAULT_OPTIONS, NgTemplateOutlet } from '@angular/common';
|
|
6
|
+
import { text, SciTextPipe } from '@scion/components/text';
|
|
4
7
|
import { toObservable, rxResource, takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
5
|
-
import { Objects, clamp, runSafe, Observables
|
|
6
|
-
import {
|
|
8
|
+
import { Objects, Arrays, clamp, runSafe, Observables } from '@scion/toolkit/util';
|
|
9
|
+
import { LatestTaskExecutor } from '@scion/toolkit/common';
|
|
10
|
+
import { fromEvent, switchMap, concat, of, timer, firstValueFrom, defaultIfEmpty, throwError, combineLatestWith, tap, skip } from 'rxjs';
|
|
7
11
|
import { map, startWith, first } from 'rxjs/operators';
|
|
8
12
|
import { subscribeIn } from '@scion/toolkit/operators';
|
|
9
13
|
import { SciScrollbarComponent } from '@scion/components/viewport';
|
|
10
14
|
import { dimension } from '@scion/components/dimension';
|
|
11
|
-
import { NgTemplateOutlet } from '@angular/common';
|
|
12
15
|
import { SciIconComponent } from '@scion/components/icon';
|
|
13
16
|
import { SciToolbarComponent, contributeMenu, ɵSciMenuService as _SciMenuService } from '@scion/components/menu';
|
|
14
17
|
import { UUID } from '@scion/toolkit/uuid';
|
|
15
18
|
import { SciSplitterComponent } from '@scion/components/splitter';
|
|
16
|
-
import { text, SciTextPipe } from '@scion/components/text';
|
|
17
19
|
import { SciThrobberComponent } from '@scion/components/throbber';
|
|
18
|
-
import * as
|
|
20
|
+
import * as i2 from '@angular/forms';
|
|
19
21
|
import { FormsModule } from '@angular/forms';
|
|
20
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Creates a {@link SciDateValue} from the given date-like input.
|
|
25
|
+
*
|
|
26
|
+
* Calling this function is expensive due to date parsing and formatting.
|
|
27
|
+
*/
|
|
28
|
+
function coerceDateValue(dateLike, options) {
|
|
29
|
+
const { format, locale, timezone } = options;
|
|
30
|
+
switch (typeof dateLike) {
|
|
31
|
+
case 'string': {
|
|
32
|
+
const isoString = ensureIso8601DatePrefix(dateLike);
|
|
33
|
+
return {
|
|
34
|
+
isoString,
|
|
35
|
+
millis: new Date(isoString).getTime(),
|
|
36
|
+
formatted: formatDate(isoString, format, locale, timezone),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
case 'number': {
|
|
40
|
+
const millis = dateLike;
|
|
41
|
+
const isoString = new Date(millis).toISOString();
|
|
42
|
+
return {
|
|
43
|
+
isoString,
|
|
44
|
+
millis,
|
|
45
|
+
formatted: formatDate(isoString, format, locale, timezone),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
case 'object': {
|
|
49
|
+
const date = dateLike;
|
|
50
|
+
const isoString = date.toISOString();
|
|
51
|
+
return {
|
|
52
|
+
isoString,
|
|
53
|
+
millis: date.getTime(),
|
|
54
|
+
formatted: formatDate(isoString, format, locale, timezone),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
case 'undefined': {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Prepends '1970-01-01' if the date prefix is missing, as required by {@link formatDate}.
|
|
64
|
+
*
|
|
65
|
+
* Uses fast ASCII character code checks (`-`, `T`, `t`) to avoid string allocation.
|
|
66
|
+
*/
|
|
67
|
+
function ensureIso8601DatePrefix(isoDate) {
|
|
68
|
+
// Check if iso string already starts with a full year date (YYYY-MM-DD)
|
|
69
|
+
if (isoDate.charCodeAt(4) === 45) { // '-'
|
|
70
|
+
return isoDate;
|
|
71
|
+
}
|
|
72
|
+
// Prepend epoch, adding 'T' separator if missing.
|
|
73
|
+
switch (isoDate.charCodeAt(0)) {
|
|
74
|
+
case 84: // 'T'
|
|
75
|
+
case 116: // 't'
|
|
76
|
+
return '1970-01-01' + isoDate;
|
|
77
|
+
default:
|
|
78
|
+
return '1970-01-01T' + isoDate;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/*
|
|
83
|
+
* Copyright (c) 2018-2026 Swiss Federal Railways
|
|
84
|
+
*
|
|
85
|
+
* This program and the accompanying materials are made
|
|
86
|
+
* available under the terms of the Eclipse Public License 2.0
|
|
87
|
+
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
88
|
+
*
|
|
89
|
+
* SPDX-License-Identifier: EPL-2.0
|
|
90
|
+
*/
|
|
91
|
+
/**
|
|
92
|
+
* Creates a {@link SciEnumValue} from the given enum-like input.
|
|
93
|
+
*/
|
|
94
|
+
function coerceEnumValue(enumLike, options) {
|
|
95
|
+
const value = coerceSignal(enumLike, { coerceUndefined: true });
|
|
96
|
+
const enumeration = coerceSignal(options.enumeration);
|
|
97
|
+
const enumEntry = computed(() => value() !== undefined ? enumeration().find(entry => entry.value === value()) : undefined, /* @ts-ignore */
|
|
98
|
+
...(ngDevMode ? [{ debugName: "enumEntry" }] : /* istanbul ignore next */ []));
|
|
99
|
+
const label = text(computed(() => enumEntry()?.label), { injector: options.injector ?? inject(Injector) });
|
|
100
|
+
const tooltip = text(computed(() => enumEntry()?.tooltip), { injector: options.injector ?? inject(Injector) });
|
|
101
|
+
return computed(() => {
|
|
102
|
+
if (!enumEntry()) {
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
value: enumEntry().value,
|
|
107
|
+
label: label(),
|
|
108
|
+
icon: enumEntry().icon,
|
|
109
|
+
// Use tooltip if provided, or fall back to label, but only if it is not configured for display.
|
|
110
|
+
tooltip: tooltip() ?? (tooltip() === null || options.format.label ? undefined : label()),
|
|
111
|
+
};
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
21
115
|
/*
|
|
22
116
|
* Copyright (c) 2018-2026 Swiss Federal Railways
|
|
23
117
|
*
|
|
@@ -41,7 +135,7 @@ class ɵSciTableColumnFactory {
|
|
|
41
135
|
this.columns.push({
|
|
42
136
|
...column,
|
|
43
137
|
type: 'string',
|
|
44
|
-
value: descriptor.value,
|
|
138
|
+
value: item => text(descriptor.value(item)),
|
|
45
139
|
sortable: computed(() => this._table.sortable() && !!sortable),
|
|
46
140
|
filterable: computed(() => this._table.filterable() && !!filterable),
|
|
47
141
|
compare: typeof sortable === 'object' ? sortable.comparator : (a, b) => a.value.localeCompare(b.value),
|
|
@@ -52,28 +146,95 @@ class ɵSciTableColumnFactory {
|
|
|
52
146
|
addNumberColumn(descriptorLike, value) {
|
|
53
147
|
const descriptor = coerceColumnDescriptor(descriptorLike, value);
|
|
54
148
|
const column = this.mapToColumn(descriptor);
|
|
149
|
+
const locale = coerceSignal(descriptor.locale ?? inject(SCI_LOCALE));
|
|
150
|
+
const currency = inject(DEFAULT_CURRENCY_CODE, { optional: true }) ?? 'USD';
|
|
55
151
|
this.columns.push({
|
|
56
152
|
...column,
|
|
57
153
|
type: 'number',
|
|
58
|
-
value: descriptor.value,
|
|
154
|
+
value: item => coerceSignal(descriptor.value(item), { coerceUndefined: true }),
|
|
59
155
|
sortable: computed(() => this._table.sortable() && (descriptor.sortable ?? true)),
|
|
60
156
|
filterable: computed(() => this._table.filterable() && (descriptor.filterable ?? true)),
|
|
61
157
|
compare: (a, b) => a.value - b.value,
|
|
62
158
|
matches: (text, context) => context.value === text,
|
|
159
|
+
format: computed(() => new Intl.NumberFormat(locale(), { currency, ...descriptor.format })),
|
|
63
160
|
});
|
|
64
161
|
return this;
|
|
65
162
|
}
|
|
66
163
|
addBooleanColumn(descriptorLike, value) {
|
|
164
|
+
const descriptor = coerceColumnDescriptor(descriptorLike, value);
|
|
165
|
+
this.addEnumColumn({
|
|
166
|
+
...descriptor,
|
|
167
|
+
value: item => coerceSignal(descriptor.value(item), { coerceUndefined: true }),
|
|
168
|
+
values: [
|
|
169
|
+
{ value: true, icon: 'scion:true', label: '%scion:components:yes.value', tooltip: null },
|
|
170
|
+
{ value: false, icon: 'scion:false', label: '%scion:components:no.value', tooltip: null },
|
|
171
|
+
],
|
|
172
|
+
format: { icon: true },
|
|
173
|
+
filterable: descriptor.filterable === false ? false : 'single',
|
|
174
|
+
referenceType: 'boolean',
|
|
175
|
+
});
|
|
176
|
+
return this;
|
|
177
|
+
}
|
|
178
|
+
addDateColumn(descriptorLike, value) {
|
|
67
179
|
const descriptor = coerceColumnDescriptor(descriptorLike, value);
|
|
68
180
|
const column = this.mapToColumn(descriptor);
|
|
181
|
+
const defaults = inject(DATE_PIPE_DEFAULT_OPTIONS, { optional: true });
|
|
182
|
+
const locale = coerceSignal(descriptor.locale ?? inject(SCI_LOCALE));
|
|
183
|
+
const format = descriptor.format ?? defaults?.dateFormat ?? 'mediumDate';
|
|
184
|
+
const timezone = descriptor.timezone ?? defaults?.timezone;
|
|
69
185
|
this.columns.push({
|
|
70
186
|
...column,
|
|
71
|
-
type: '
|
|
72
|
-
value:
|
|
187
|
+
type: 'date',
|
|
188
|
+
value: item => {
|
|
189
|
+
const dateLike = coerceSignal(descriptor.value(item), { coerceUndefined: true });
|
|
190
|
+
return computed(() => coerceDateValue(dateLike(), { locale: locale(), format, timezone }));
|
|
191
|
+
},
|
|
73
192
|
sortable: computed(() => this._table.sortable() && (descriptor.sortable ?? true)),
|
|
74
193
|
filterable: computed(() => this._table.filterable() && (descriptor.filterable ?? true)),
|
|
75
|
-
compare: (a, b) => a.value
|
|
76
|
-
matches: (text, context) => context.value
|
|
194
|
+
compare: (a, b) => a.value.millis - b.value.millis,
|
|
195
|
+
matches: (text, context) => context.value.formatted.toLowerCase().includes(text.toLowerCase()),
|
|
196
|
+
});
|
|
197
|
+
return this;
|
|
198
|
+
}
|
|
199
|
+
addEnumColumn(descriptor) {
|
|
200
|
+
const column = this.mapToColumn(descriptor);
|
|
201
|
+
const enumeration = coerceSignal(descriptor.values);
|
|
202
|
+
const positionByEnumValue = computed(() => enumeration().reduce((acc, entry, index) => acc.set(entry.value, index), new Map()), /* @ts-ignore */
|
|
203
|
+
...(ngDevMode ? [{ debugName: "positionByEnumValue" }] : /* istanbul ignore next */ []));
|
|
204
|
+
const format = descriptor.format
|
|
205
|
+
? { icon: descriptor.format.icon ?? false, label: descriptor.format.label ?? false, filter: { icon: descriptor.format.filter?.icon ?? false } } // eslint-disable-line @stylistic/operator-linebreak
|
|
206
|
+
: { icon: false, label: true, filter: { icon: true } }; // eslint-disable-line @stylistic/operator-linebreak
|
|
207
|
+
this.columns.push({
|
|
208
|
+
...column,
|
|
209
|
+
type: 'enum',
|
|
210
|
+
referenceType: descriptor.referenceType,
|
|
211
|
+
value: item => coerceEnumValue(descriptor.value(item), { enumeration, format }),
|
|
212
|
+
sortable: computed(() => this._table.sortable() && (descriptor.sortable ?? true)),
|
|
213
|
+
filterable: computed(() => this._table.filterable() && (descriptor.filterable ?? 'multi')),
|
|
214
|
+
enumeration,
|
|
215
|
+
compare: (a, b) => untracked(() => (positionByEnumValue().get(a.value.value) ?? 0) - (positionByEnumValue().get(b.value.value) ?? 0)),
|
|
216
|
+
matches: (filter, context) => {
|
|
217
|
+
if (typeof filter === 'string') { // table filter
|
|
218
|
+
return context.value.label.toLowerCase().includes(filter.toLowerCase());
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
return filter.includes(context.value.value); // column filter
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
format,
|
|
225
|
+
});
|
|
226
|
+
return this;
|
|
227
|
+
}
|
|
228
|
+
addIconColumn(descriptor) {
|
|
229
|
+
const resizable = typeof descriptor.header === 'string' || !!descriptor.header?.label?.length;
|
|
230
|
+
this.addEnumColumn({
|
|
231
|
+
...descriptor,
|
|
232
|
+
value: item => coerceSignal(descriptor.value(item), { coerceUndefined: true }),
|
|
233
|
+
format: { icon: true, filter: { icon: true } },
|
|
234
|
+
resizable: descriptor.resizable ?? resizable,
|
|
235
|
+
width: descriptor.width ?? (resizable ? undefined : 'max-content'), // adapt width to intrinsic size
|
|
236
|
+
minWidth: descriptor.minWidth ?? (resizable ? undefined : 32),
|
|
237
|
+
referenceType: 'icon',
|
|
77
238
|
});
|
|
78
239
|
return this;
|
|
79
240
|
}
|
|
@@ -94,7 +255,7 @@ class ɵSciTableColumnFactory {
|
|
|
94
255
|
sortable: computed(() => this._table.sortable() && !!descriptor.sortable),
|
|
95
256
|
filterable: computed(() => this._table.filterable() && !!descriptor.filterable),
|
|
96
257
|
compare: typeof descriptor.sortable === 'object' ? descriptor.sortable.comparator : () => 0,
|
|
97
|
-
matches: typeof descriptor.filterable === 'object' ? descriptor.filterable.matcher : () =>
|
|
258
|
+
matches: typeof descriptor.filterable === 'object' ? descriptor.filterable.matcher : () => false,
|
|
98
259
|
padding: descriptor.padding ?? true,
|
|
99
260
|
});
|
|
100
261
|
return this;
|
|
@@ -116,7 +277,7 @@ class ɵSciTableColumnFactory {
|
|
|
116
277
|
sortable: computed(() => this._table.sortable() && !!descriptor.sortable),
|
|
117
278
|
filterable: computed(() => this._table.filterable() && !!descriptor.filterable),
|
|
118
279
|
compare: typeof descriptor.sortable === 'object' ? descriptor.sortable.comparator : () => 0,
|
|
119
|
-
matches: typeof descriptor.filterable === 'object' ? descriptor.filterable.matcher : () =>
|
|
280
|
+
matches: typeof descriptor.filterable === 'object' ? descriptor.filterable.matcher : () => false,
|
|
120
281
|
padding: descriptor.padding ?? true,
|
|
121
282
|
});
|
|
122
283
|
return this;
|
|
@@ -140,7 +301,16 @@ class ɵSciTableColumnFactory {
|
|
|
140
301
|
}
|
|
141
302
|
return {
|
|
142
303
|
name: name,
|
|
143
|
-
header:
|
|
304
|
+
header: untracked(() => {
|
|
305
|
+
if (typeof descriptor.header === 'string') {
|
|
306
|
+
return { label: text(descriptor.header), icon: undefined, tooltip: undefined };
|
|
307
|
+
}
|
|
308
|
+
return {
|
|
309
|
+
label: descriptor.header?.label !== undefined ? text(descriptor.header.label) : undefined,
|
|
310
|
+
icon: descriptor.header?.icon,
|
|
311
|
+
tooltip: descriptor.header?.tooltip !== undefined ? text(descriptor.header.tooltip) : undefined,
|
|
312
|
+
};
|
|
313
|
+
}),
|
|
144
314
|
resizable: computed(() => this._table.resizable() && (descriptor.resizable ?? true)),
|
|
145
315
|
width: computed(() => {
|
|
146
316
|
const userSettings = this._table.userSettings().columns?.find(column => column.name === name);
|
|
@@ -154,14 +324,13 @@ class ɵSciTableColumnFactory {
|
|
|
154
324
|
}
|
|
155
325
|
}
|
|
156
326
|
function coerceColumnDescriptor(argument1, argument2) {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
return { header: argument1, value: argument2 };
|
|
160
|
-
case 'function':
|
|
161
|
-
return { value: argument1 };
|
|
162
|
-
default:
|
|
163
|
-
return argument1;
|
|
327
|
+
if (argument2 === undefined) {
|
|
328
|
+
return typeof argument1 === 'function' ? { value: argument1 } : argument1;
|
|
164
329
|
}
|
|
330
|
+
return {
|
|
331
|
+
header: argument1,
|
|
332
|
+
value: argument2,
|
|
333
|
+
};
|
|
165
334
|
}
|
|
166
335
|
|
|
167
336
|
/*
|
|
@@ -207,6 +376,71 @@ function provideTableStorage(storage) {
|
|
|
207
376
|
]);
|
|
208
377
|
}
|
|
209
378
|
|
|
379
|
+
/** @inheritDoc */
|
|
380
|
+
class ɵSciTableCellValuePreloader {
|
|
381
|
+
_executor = new LatestTaskExecutor();
|
|
382
|
+
_queue = new Array(); // PERF: Do not change to signal to avoid array re-allocation on enqueue (expensive); queue size is tracked via a separate signal.
|
|
383
|
+
_queueSize = signal(0, /* @ts-ignore */
|
|
384
|
+
...(ngDevMode ? [{ debugName: "_queueSize" }] : /* istanbul ignore next */ []));
|
|
385
|
+
_injector = inject(Injector);
|
|
386
|
+
/** @inheritDoc */
|
|
387
|
+
loading = computed(() => this._queueSize() > 0, /* @ts-ignore */
|
|
388
|
+
...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
|
|
389
|
+
constructor() {
|
|
390
|
+
inject(DestroyRef).onDestroy(() => {
|
|
391
|
+
this._executor.destroy();
|
|
392
|
+
this._queue.length = 0;
|
|
393
|
+
this._queueSize.set(0);
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
/** @inheritDoc */
|
|
397
|
+
queue(cellValueFn) {
|
|
398
|
+
this._queue.push(cellValueFn);
|
|
399
|
+
this._queueSize.update(size => size + 1);
|
|
400
|
+
this._executor.submit(() => this.whenIdle().then(() => this.preloadQueuedBatch(PRELOAD_BATCH_SIZE)));
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Preloads the next batch of queued cell values, FIFO, then, if the queue is not empty, schedules the next batch.
|
|
404
|
+
*/
|
|
405
|
+
async preloadQueuedBatch(batchSize) {
|
|
406
|
+
this._queue.splice(0, batchSize).forEach(fn => fn());
|
|
407
|
+
this._queueSize.set(this._queue.length);
|
|
408
|
+
// Preload next batch when idle again.
|
|
409
|
+
if (this._queue.length) {
|
|
410
|
+
this._executor.submit(() => this.whenIdle().then(() => this.preloadQueuedBatch(PRELOAD_BATCH_SIZE)));
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Resolves when the browser becomes idle.
|
|
415
|
+
*
|
|
416
|
+
* @see onIdle
|
|
417
|
+
*/
|
|
418
|
+
whenIdle() {
|
|
419
|
+
return runInInjectionContext(this._injector, onIdle);
|
|
420
|
+
}
|
|
421
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: ɵSciTableCellValuePreloader, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
422
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: ɵSciTableCellValuePreloader });
|
|
423
|
+
}
|
|
424
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: ɵSciTableCellValuePreloader, decorators: [{
|
|
425
|
+
type: Injectable
|
|
426
|
+
}], ctorParameters: () => [] });
|
|
427
|
+
const PRELOAD_BATCH_SIZE = 50_000;
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Preloads cell values in the background when the browser is idle. This prevents lag with large datasets, in particular
|
|
431
|
+
* for expensive computations like formatting dates and generating ISO 8601 strings, providing faster sort and filter performance.
|
|
432
|
+
*
|
|
433
|
+
* If a cell's value is requested before background preloading finishes, it is computed synchronously.
|
|
434
|
+
*/
|
|
435
|
+
class SciTableCellValuePreloader {
|
|
436
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciTableCellValuePreloader, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
437
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciTableCellValuePreloader, providedIn: 'root', useClass: ɵSciTableCellValuePreloader });
|
|
438
|
+
}
|
|
439
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciTableCellValuePreloader, decorators: [{
|
|
440
|
+
type: Injectable,
|
|
441
|
+
args: [{ providedIn: 'root', useClass: ɵSciTableCellValuePreloader }]
|
|
442
|
+
}] });
|
|
443
|
+
|
|
210
444
|
/*
|
|
211
445
|
* Copyright (c) 2018-2026 Swiss Federal Railways
|
|
212
446
|
*
|
|
@@ -245,13 +479,23 @@ class Dataset {
|
|
|
245
479
|
count = computed(() => this._dataview().length, /* @ts-ignore */
|
|
246
480
|
...(ngDevMode ? [{ debugName: "count" }] : /* istanbul ignore next */ []));
|
|
247
481
|
constructor(data, columns) {
|
|
248
|
-
const
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
482
|
+
const tableCellValuePreloader = inject(SciTableCellValuePreloader);
|
|
483
|
+
// Create a factory to instantiate a new injector per dataset run, releasing resources allocated in column value functions.
|
|
484
|
+
const injectorFactory = new _SingleActiveInjectorFactory();
|
|
485
|
+
const dataset = computed(() => {
|
|
486
|
+
const injector = injectorFactory.create();
|
|
487
|
+
return data().map(item => ({
|
|
488
|
+
item,
|
|
489
|
+
cells: columns().reduce((cells, column) => untracked(() => {
|
|
490
|
+
// PERF: Cell values are computed lazily (on idle or first use) to defer expensive computations like date formatting.
|
|
491
|
+
const tableCellValue = 'value' in column ? new eSciTableCellValue(tableCellValuePreloader, () => runInInjectionContext(injector, () => column.value(item)())) : undefined;
|
|
492
|
+
return cells.set(column.name, {
|
|
493
|
+
column: column,
|
|
494
|
+
value: () => tableCellValue?.value(),
|
|
495
|
+
});
|
|
496
|
+
}), new Map()),
|
|
497
|
+
}));
|
|
498
|
+
}, /* @ts-ignore */
|
|
255
499
|
...(ngDevMode ? [{ debugName: "dataset" }] : /* istanbul ignore next */ []));
|
|
256
500
|
// Memoize filtered/sorted view; recomputes only when dataset or criteria change, not when scrolling through the view, as sorting is an expensive operation.
|
|
257
501
|
this._dataview = computed(() => {
|
|
@@ -261,8 +505,9 @@ class Dataset {
|
|
|
261
505
|
const sortCriteria = this.sortCriteria();
|
|
262
506
|
// PERF: Do not track signals inside `Array.sort` to avoid Angular signal tracking overhead as the comparator runs repeatedly, degrading performance otherwise.
|
|
263
507
|
return untracked(() => rows
|
|
264
|
-
.filter(row => matchesRow(row, columnFilters) && matchesGlobalFilter(row, tableFilter
|
|
265
|
-
.sort((a, b) => compareRows(a, b, sortCriteria))
|
|
508
|
+
.filter(row => matchesRow(row, columnFilters, { coerceEnumValueToArray: true }) && matchesGlobalFilter(row, tableFilter, { coerceEnumValueToArray: false }))
|
|
509
|
+
.sort((a, b) => compareRows(a, b, sortCriteria))
|
|
510
|
+
.map(row => row.item));
|
|
266
511
|
}, /* @ts-ignore */
|
|
267
512
|
...(ngDevMode ? [{ debugName: "_dataview" }] : /* istanbul ignore next */ []));
|
|
268
513
|
}
|
|
@@ -270,22 +515,22 @@ class Dataset {
|
|
|
270
515
|
* Returns a slice of the filtered and sorted data within the given range (start inclusive, end exclusive).
|
|
271
516
|
*/
|
|
272
517
|
slice(start, end) {
|
|
273
|
-
return computed(() => this._dataview().slice(start, end)
|
|
518
|
+
return computed(() => this._dataview().slice(start, end));
|
|
274
519
|
}
|
|
275
520
|
}
|
|
276
521
|
/**
|
|
277
522
|
* Tests whether a row matches the given global filter.
|
|
278
523
|
*/
|
|
279
|
-
function matchesGlobalFilter(row, filter) {
|
|
524
|
+
function matchesGlobalFilter(row, filter, options) {
|
|
280
525
|
if (!filter?.trim()) {
|
|
281
526
|
return true;
|
|
282
527
|
}
|
|
283
528
|
for (const cell of row.cells.values()) {
|
|
284
|
-
const text =
|
|
529
|
+
const text = cell.column.type === 'number' ? toNumber(filter) : filter;
|
|
285
530
|
if (text === undefined) {
|
|
286
531
|
continue;
|
|
287
532
|
}
|
|
288
|
-
if (matchesRow(row, [{ text, columnName: cell.column.name }])) {
|
|
533
|
+
if (matchesRow(row, [{ text, columnName: cell.column.name }], options)) {
|
|
289
534
|
return true;
|
|
290
535
|
}
|
|
291
536
|
}
|
|
@@ -294,13 +539,17 @@ function matchesGlobalFilter(row, filter) {
|
|
|
294
539
|
/**
|
|
295
540
|
* Tests whether a row matches the given column filters.
|
|
296
541
|
*/
|
|
297
|
-
function matchesRow(row, columnFilters) {
|
|
542
|
+
function matchesRow(row, columnFilters, options) {
|
|
298
543
|
if (!columnFilters.length) {
|
|
299
544
|
return true;
|
|
300
545
|
}
|
|
301
546
|
for (const columnFilter of columnFilters) {
|
|
302
547
|
const cell = row.cells.get(columnFilter.columnName);
|
|
303
|
-
if (
|
|
548
|
+
if ('value' in cell.column && cell.value() === undefined) { // Component and template columns have no value.
|
|
549
|
+
return false;
|
|
550
|
+
}
|
|
551
|
+
const filter = cell.column.type === 'enum' && options.coerceEnumValueToArray ? Arrays.coerce(columnFilter.text) : columnFilter.text;
|
|
552
|
+
if (!cell.column.matches(filter, { item: row.item, value: cell.value() })) {
|
|
304
553
|
return false;
|
|
305
554
|
}
|
|
306
555
|
}
|
|
@@ -316,10 +565,22 @@ function compareRows(row1, row2, sortCriteria) {
|
|
|
316
565
|
for (const criterion of sortCriteria) {
|
|
317
566
|
const cell1 = row1.cells.get(criterion.columnName);
|
|
318
567
|
const cell2 = row2.cells.get(criterion.columnName);
|
|
319
|
-
const
|
|
568
|
+
const value1 = cell1.value();
|
|
569
|
+
const value2 = cell2.value();
|
|
570
|
+
// Always place `undefined` values at the end, independent of the sort direction. Note that component and template columns have no value.
|
|
571
|
+
if (value1 === undefined && value2 !== undefined) {
|
|
572
|
+
return 1;
|
|
573
|
+
}
|
|
574
|
+
if (value2 === undefined && value1 !== undefined) {
|
|
575
|
+
return -1;
|
|
576
|
+
}
|
|
577
|
+
// Prevent calling comparator for value columns where both values are undefined. Note that component and template columns have no value.
|
|
578
|
+
if (value1 === undefined && value2 === undefined && 'value' in cell1.column) {
|
|
579
|
+
return 0;
|
|
580
|
+
}
|
|
581
|
+
const comparison = cell1.column.compare({ item: row1.item, value: value1 }, { item: row2.item, value: value2 });
|
|
320
582
|
if (comparison !== 0) {
|
|
321
|
-
|
|
322
|
-
return signum * comparison;
|
|
583
|
+
return criterion.direction === 'asc' ? comparison : -comparison;
|
|
323
584
|
}
|
|
324
585
|
}
|
|
325
586
|
return 0;
|
|
@@ -342,26 +603,28 @@ function markAsArrayDatasource(loader) {
|
|
|
342
603
|
*/
|
|
343
604
|
const ARRAY_DATASOURCE_MARKER = Symbol('ARRAY_DATASOURCE_HINT');
|
|
344
605
|
/**
|
|
345
|
-
*
|
|
606
|
+
* Converts the given string to a number, or `undefined` if it cannot be parsed.
|
|
346
607
|
*/
|
|
347
|
-
function
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
608
|
+
function toNumber(numberLike) {
|
|
609
|
+
const number = Number.parseFloat(numberLike);
|
|
610
|
+
return !Number.isNaN(number) ? number : undefined;
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* Provides lazy loading for the cell's value, preloading it when idle for better sort/filter performance.
|
|
614
|
+
*
|
|
615
|
+
* The value is computed at most once, whether it gets preloaded during idle time or requested synchronously via {@link value()}.
|
|
616
|
+
*/
|
|
617
|
+
class eSciTableCellValue {
|
|
618
|
+
_valueFn;
|
|
619
|
+
_value;
|
|
620
|
+
constructor(preloader, _valueFn) {
|
|
621
|
+
this._valueFn = _valueFn;
|
|
622
|
+
preloader.queue(() => {
|
|
623
|
+
this._value ??= this._valueFn();
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
value() {
|
|
627
|
+
return this._value ??= untracked(() => this._valueFn());
|
|
365
628
|
}
|
|
366
629
|
}
|
|
367
630
|
|
|
@@ -441,32 +704,57 @@ class SciTableCache {
|
|
|
441
704
|
*
|
|
442
705
|
* SPDX-License-Identifier: EPL-2.0
|
|
443
706
|
*/
|
|
707
|
+
/**
|
|
708
|
+
* Provides row bindings to tables in the scope of the injector providing the bindings.
|
|
709
|
+
*
|
|
710
|
+
* Multiple providers can be registered. Providers at different injector tree levels form a hierarchy.
|
|
711
|
+
*/
|
|
444
712
|
function provideTableRowBinding(bindings) {
|
|
445
|
-
return
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
713
|
+
return [
|
|
714
|
+
{
|
|
715
|
+
provide: SCI_TABLE_ROW_BINDING,
|
|
716
|
+
useValue: bindings,
|
|
717
|
+
multi: true,
|
|
718
|
+
},
|
|
719
|
+
{
|
|
720
|
+
provide: SCI_TABLE_ROW_BINDINGS,
|
|
721
|
+
useFactory: () => {
|
|
722
|
+
return [
|
|
723
|
+
// Collect bindings registered in parent injectors.
|
|
724
|
+
...inject(SCI_TABLE_ROW_BINDINGS, { skipSelf: true, optional: true }) ?? [],
|
|
725
|
+
// Collect bindings registered in this injector.
|
|
726
|
+
...inject(SCI_TABLE_ROW_BINDING),
|
|
727
|
+
];
|
|
728
|
+
},
|
|
729
|
+
},
|
|
730
|
+
];
|
|
450
731
|
}
|
|
451
732
|
class ɵSciTableRowBindingFactory {
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
733
|
+
icons = new Array();
|
|
734
|
+
parts = new Array();
|
|
735
|
+
attributes = new Array();
|
|
736
|
+
classes = new Array();
|
|
737
|
+
addIconBinding(icon) {
|
|
738
|
+
if (icon) {
|
|
739
|
+
this.icons.push(icon);
|
|
458
740
|
}
|
|
459
741
|
return this;
|
|
460
742
|
}
|
|
461
|
-
|
|
743
|
+
addPartBinding(name) {
|
|
462
744
|
if (name) {
|
|
463
|
-
this.
|
|
745
|
+
this.parts.push(name);
|
|
464
746
|
}
|
|
465
747
|
return this;
|
|
466
748
|
}
|
|
467
|
-
|
|
749
|
+
addAttributeBinding(name, value) {
|
|
750
|
+
if (value !== undefined) {
|
|
751
|
+
this.attributes.push([name, value]);
|
|
752
|
+
}
|
|
753
|
+
return this;
|
|
754
|
+
}
|
|
755
|
+
addClassBinding(name) {
|
|
468
756
|
if (name) {
|
|
469
|
-
this.
|
|
757
|
+
this.classes.push(name);
|
|
470
758
|
}
|
|
471
759
|
return this;
|
|
472
760
|
}
|
|
@@ -479,12 +767,20 @@ function coerceTableRowBindings(bindingsFn, item, index) {
|
|
|
479
767
|
}, /* @ts-ignore */
|
|
480
768
|
...(ngDevMode ? [{ debugName: "factory" }] : /* istanbul ignore next */ []));
|
|
481
769
|
return {
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
770
|
+
icons: computed(() => factory().icons, { equal: Objects.isEqual }),
|
|
771
|
+
parts: computed(() => factory().parts, { equal: Objects.isEqual }),
|
|
772
|
+
attributes: computed(() => Object.fromEntries(factory().attributes), { equal: Objects.isEqual }),
|
|
773
|
+
classes: computed(() => factory().classes, { equal: Objects.isEqual }),
|
|
485
774
|
};
|
|
486
775
|
}
|
|
776
|
+
/**
|
|
777
|
+
* Multi-DI token for registering a {@link SciTableRowBindingFactory}.
|
|
778
|
+
*/
|
|
487
779
|
const SCI_TABLE_ROW_BINDING = new InjectionToken('SCI_TABLE_ROW_BINDING');
|
|
780
|
+
/**
|
|
781
|
+
* DI token to inject {@link SciTableRowBindingFactory} functions provided in the current and parent injectors.
|
|
782
|
+
*/
|
|
783
|
+
const SCI_TABLE_ROW_BINDINGS = new InjectionToken('SCI_TABLE_ROW_BINDINGS');
|
|
488
784
|
|
|
489
785
|
/*
|
|
490
786
|
* Copyright (c) 2018-2026 Swiss Federal Railways
|
|
@@ -530,6 +826,7 @@ class ɵSciTable {
|
|
|
530
826
|
computation: (columns, previous) => previous?.value.filter(criteria => columns.some(column => column.name === criteria.columnName)) ?? [],
|
|
531
827
|
equal: Objects.isEqual });
|
|
532
828
|
_cache = new SciTableCache();
|
|
829
|
+
_tableCellValuePreloader = inject(SciTableCellValuePreloader);
|
|
533
830
|
_tableFilter = signal(null, /* @ts-ignore */
|
|
534
831
|
...(ngDevMode ? [{ debugName: "_tableFilter" }] : /* istanbul ignore next */ []));
|
|
535
832
|
_selectedItems = signal(new Map(), /* @ts-ignore */
|
|
@@ -546,7 +843,8 @@ class ɵSciTable {
|
|
|
546
843
|
computation: () => -1 });
|
|
547
844
|
criteria = computed(() => ({ sort: this.sortCriteria(), filter: this.filterCriteria(), tableFilter: this._tableFilter() }), /* @ts-ignore */
|
|
548
845
|
...(ngDevMode ? [{ debugName: "criteria" }] : /* istanbul ignore next */ []));
|
|
549
|
-
loading = this._cache.loading
|
|
846
|
+
loading = computed(() => this._cache.loading() || this._tableCellValuePreloader.loading(), /* @ts-ignore */
|
|
847
|
+
...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
|
|
550
848
|
error = this._cache.error;
|
|
551
849
|
activeRow;
|
|
552
850
|
hoveredRow = computed(() => this.rowsByIndex().get(this.hoveredIndex()), /* @ts-ignore */
|
|
@@ -585,7 +883,7 @@ class ɵSciTable {
|
|
|
585
883
|
this.rowActions = descriptor.rowActions;
|
|
586
884
|
this._rowBindings = [
|
|
587
885
|
...descriptor.rowBindings ? [descriptor.rowBindings] : [],
|
|
588
|
-
...inject(
|
|
886
|
+
...inject(SCI_TABLE_ROW_BINDINGS, { optional: true }) ?? [],
|
|
589
887
|
];
|
|
590
888
|
this._trackBy = descriptor.trackBy;
|
|
591
889
|
this._dataLoaderFn = isSignal(descriptor.ɵdatasource) ? arrayDatasource(descriptor.ɵdatasource, this.columns) : descriptor.ɵdatasource;
|
|
@@ -604,17 +902,13 @@ class ɵSciTable {
|
|
|
604
902
|
this.tableViewRef.set(undefined);
|
|
605
903
|
}
|
|
606
904
|
computeColumns(descriptor) {
|
|
607
|
-
// Create
|
|
608
|
-
|
|
609
|
-
return computed(() => {
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
return
|
|
613
|
-
|
|
614
|
-
descriptor.columns(tableColumnFactory);
|
|
615
|
-
return tableColumnFactory.columns;
|
|
616
|
-
});
|
|
617
|
-
});
|
|
905
|
+
// Create a factory to instantiate a new injector per column factory execution, releasing resources allocated in the previous execution.
|
|
906
|
+
const injectorFactory = new _SingleActiveInjectorFactory();
|
|
907
|
+
return computed(() => runInInjectionContext(injectorFactory.create(), () => {
|
|
908
|
+
const tableColumnFactory = new ɵSciTableColumnFactory(this);
|
|
909
|
+
descriptor.columns(tableColumnFactory);
|
|
910
|
+
return tableColumnFactory.columns;
|
|
911
|
+
}));
|
|
618
912
|
}
|
|
619
913
|
/**
|
|
620
914
|
* Computes the rows currently visible in the viewport (+buffer).
|
|
@@ -734,7 +1028,7 @@ class ɵSciTable {
|
|
|
734
1028
|
cancel: () => this._cache.deleteIfLoading(cacheKey),
|
|
735
1029
|
};
|
|
736
1030
|
}
|
|
737
|
-
const cacheEntryInjector =
|
|
1031
|
+
const cacheEntryInjector = _createDestroyableInjector({ parent: this._injector });
|
|
738
1032
|
const cacheEntry = {
|
|
739
1033
|
rows: runInInjectionContext(cacheEntryInjector, () => {
|
|
740
1034
|
// Fetch data.
|
|
@@ -747,32 +1041,23 @@ class ɵSciTable {
|
|
|
747
1041
|
tableFilter,
|
|
748
1042
|
columnFilters,
|
|
749
1043
|
})), error => throwError(() => error));
|
|
1044
|
+
const columns$ = toObservable(this.columns);
|
|
1045
|
+
const injectorFactory = new _SingleActiveInjectorFactory();
|
|
750
1046
|
// Create a resource to track loading and error states.
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
// Synchronize total row count based on resource state.
|
|
760
|
-
effect(() => {
|
|
761
|
-
switch (rows.status()) {
|
|
762
|
-
case 'resolved': {
|
|
763
|
-
// Update count only after rows resolve to prevent premature scroll invalidation.
|
|
764
|
-
this.totalCount.set(tableResponse.value()?.totalCount);
|
|
765
|
-
break;
|
|
766
|
-
}
|
|
767
|
-
case 'error': {
|
|
768
|
-
console.error(rows.error().cause);
|
|
1047
|
+
return rxResource({
|
|
1048
|
+
stream: () => tableResponse$.pipe(combineLatestWith(columns$), map(([response, columns]) => ({
|
|
1049
|
+
rows: runInInjectionContext(injectorFactory.create(), () => this.mapItemsToRow(response.items, columns, pageStart)),
|
|
1050
|
+
totalCount: response.totalCount,
|
|
1051
|
+
})), tap({
|
|
1052
|
+
next: ({ totalCount }) => this.totalCount.set(totalCount),
|
|
1053
|
+
error: error => {
|
|
1054
|
+
console.error(error);
|
|
769
1055
|
// Reset count to scroll to the top so the user sees the error.
|
|
770
1056
|
this.totalCount.set(0);
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
1057
|
+
},
|
|
1058
|
+
}), map(({ rows }) => rows)),
|
|
1059
|
+
defaultValue: [],
|
|
774
1060
|
});
|
|
775
|
-
return rows;
|
|
776
1061
|
}),
|
|
777
1062
|
dispose: () => cacheEntryInjector.destroy(),
|
|
778
1063
|
start: pageStart,
|
|
@@ -820,12 +1105,9 @@ class ɵSciTable {
|
|
|
820
1105
|
if (!column) {
|
|
821
1106
|
throw Error(`[NullColumnError] Column '${options.columnName}' not found in table '${this.name()}'.`);
|
|
822
1107
|
}
|
|
823
|
-
this.filterCriteria.update(
|
|
824
|
-
const
|
|
825
|
-
|
|
826
|
-
return otherFilterCriteria;
|
|
827
|
-
}
|
|
828
|
-
return otherFilterCriteria.concat({ columnName: column.name, text });
|
|
1108
|
+
this.filterCriteria.update(filterCriteria => {
|
|
1109
|
+
const newFilterCriteria = filterCriteria.filter(filterCriterion => filterCriterion.columnName !== options.columnName);
|
|
1110
|
+
return text === null ? newFilterCriteria : newFilterCriteria.concat({ columnName: column.name, text });
|
|
829
1111
|
});
|
|
830
1112
|
}
|
|
831
1113
|
updateSelectedItems(updateFn) {
|
|
@@ -899,7 +1181,7 @@ class ɵSciTable {
|
|
|
899
1181
|
hovered: computed(() => this.hoveredRow()?.index === index),
|
|
900
1182
|
bindings: coerceTableRowBindings(this._rowBindings, item, pageStart + i),
|
|
901
1183
|
cells: columns.map(column => ({
|
|
902
|
-
value:
|
|
1184
|
+
value: 'value' in column ? column.value(item) : undefined,
|
|
903
1185
|
component: column.type === 'component' ? column.component(item) : undefined,
|
|
904
1186
|
template: column.type === 'template' ? column.template(item) : undefined,
|
|
905
1187
|
type: column.type,
|
|
@@ -1455,6 +1737,30 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
1455
1737
|
type: Injectable
|
|
1456
1738
|
}] });
|
|
1457
1739
|
|
|
1740
|
+
/*
|
|
1741
|
+
* Copyright (c) 2018-2026 Swiss Federal Railways
|
|
1742
|
+
*
|
|
1743
|
+
* This program and the accompanying materials are made
|
|
1744
|
+
* available under the terms of the Eclipse Public License 2.0
|
|
1745
|
+
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
1746
|
+
*
|
|
1747
|
+
* SPDX-License-Identifier: EPL-2.0
|
|
1748
|
+
*/
|
|
1749
|
+
/**
|
|
1750
|
+
* Formats a given number based on the provided {@link Intl.NumberFormat}.
|
|
1751
|
+
*/
|
|
1752
|
+
class SciNumberPipe {
|
|
1753
|
+
transform(number, format) {
|
|
1754
|
+
return number !== undefined ? format.format(number) : undefined;
|
|
1755
|
+
}
|
|
1756
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciNumberPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
1757
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.7", ngImport: i0, type: SciNumberPipe, isStandalone: true, name: "sciNumber" });
|
|
1758
|
+
}
|
|
1759
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciNumberPipe, decorators: [{
|
|
1760
|
+
type: Pipe,
|
|
1761
|
+
args: [{ name: 'sciNumber' }]
|
|
1762
|
+
}] });
|
|
1763
|
+
|
|
1458
1764
|
/*
|
|
1459
1765
|
* Copyright (c) 2018-2026 Swiss Federal Railways
|
|
1460
1766
|
*
|
|
@@ -1472,6 +1778,7 @@ class SciTableCellComponent {
|
|
|
1472
1778
|
template = this.computeTemplate();
|
|
1473
1779
|
templateContext = this.computeTemplateContext();
|
|
1474
1780
|
partAttribute = this.computePartAttribute();
|
|
1781
|
+
value = this.computeValueAttribute();
|
|
1475
1782
|
computeTemplate() {
|
|
1476
1783
|
return computed(() => {
|
|
1477
1784
|
const cell = this.cell();
|
|
@@ -1499,27 +1806,60 @@ class SciTableCellComponent {
|
|
|
1499
1806
|
}
|
|
1500
1807
|
computePartAttribute() {
|
|
1501
1808
|
return computed(() => {
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1809
|
+
const cell = this.cell();
|
|
1810
|
+
const referenceType = cell.type === 'enum' ? cell.column.referenceType : undefined;
|
|
1811
|
+
return Arrays.distinct([
|
|
1812
|
+
// Enable column styling based on column type. For enum columns, resolves to the reference type, if any, i.e., boolean or icon.
|
|
1813
|
+
`column:${referenceType ?? cell.column.type}`,
|
|
1814
|
+
// Enable column styling based on column name.
|
|
1815
|
+
cell.column.name,
|
|
1816
|
+
// Enable row styling based on selection state.
|
|
1817
|
+
this.row().selected() ? 'row:selected' : 'row:not:selected',
|
|
1818
|
+
// Enable row styling based on active state.
|
|
1819
|
+
this.row().active() ? 'row:active' : 'row:not:active',
|
|
1820
|
+
// Enable row styling based on row bindings.
|
|
1821
|
+
...Arrays.coerce(this.row().bindings?.parts()),
|
|
1822
|
+
]).join(' ');
|
|
1823
|
+
});
|
|
1824
|
+
}
|
|
1825
|
+
computeValueAttribute() {
|
|
1826
|
+
return computed(() => {
|
|
1827
|
+
const cell = this.cell();
|
|
1828
|
+
const value = (() => {
|
|
1829
|
+
switch (cell.type) {
|
|
1830
|
+
case 'string':
|
|
1831
|
+
case 'number':
|
|
1832
|
+
return cell.value();
|
|
1833
|
+
case 'enum':
|
|
1834
|
+
return cell.value()?.value;
|
|
1835
|
+
case 'date':
|
|
1836
|
+
return cell.value()?.isoString;
|
|
1837
|
+
default:
|
|
1838
|
+
return undefined;
|
|
1839
|
+
}
|
|
1840
|
+
})();
|
|
1841
|
+
return value !== undefined ? `${value}` : undefined;
|
|
1506
1842
|
});
|
|
1507
1843
|
}
|
|
1508
1844
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciTableCellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1509
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: SciTableCellComponent, isStandalone: true, selector: "sci-table-cell", inputs: { cell: { classPropertyName: "cell", publicName: "cell", isSignal: true, isRequired: true, transformFunction: null }, row: { classPropertyName: "row", publicName: "row", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "attr.data-type": "cell().column.type", "attr.data-column": "cell().column.name", "attr.data-padding": "!cell().column.padding ? false : null", "attr.part": "
|
|
1845
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: SciTableCellComponent, isStandalone: true, selector: "sci-table-cell", inputs: { cell: { classPropertyName: "cell", publicName: "cell", isSignal: true, isRequired: true, transformFunction: null }, row: { classPropertyName: "row", publicName: "row", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "attr.data-type": "cell().column.type", "attr.data-column": "cell().column.name", "attr.data-value": "value()", "attr.data-padding": "!cell().column.padding ? false : null", "attr.part": "partAttribute()" } }, hostDirectives: [{ directive: i1.SciTooltipOnOverflowDirective }], ngImport: i0, template: "@let cell = this.cell();\n\n@switch (cell.type) {\n @case ('template') {\n <ng-template *ngTemplateOutlet=\"template(); context: templateContext()\"/>\n }\n @case ('component') {\n <ng-container *sciComponentOutlet=\"cell.component\"/>\n }\n @case ('date') {\n {{cell.value()?.formatted}}\n }\n @case ('number') {\n {{cell.value() | sciNumber:cell.column.format()}}\n }\n @case ('enum') {\n @let value = cell.value();\n @if (value !== undefined) {\n @if (cell.column.format.icon && value.icon !== undefined) {\n <sci-icon [attr.title]=\"value.tooltip\">{{value.icon}}</sci-icon>\n }\n @if (cell.column.format.label) {\n <span>{{value.label}}</span>\n }\n }\n }\n @default {\n {{cell.value()}}\n }\n}\n", styles: ["@charset \"UTF-8\";:host{display:inline-grid;position:relative;border-inline:var(--\\275sci-table-cell-padding-inline) solid transparent;align-items:center;overflow:hidden}:host:is([data-type=string],[data-type=number],[data-type=date],[data-type=enum]){display:inline;white-space:nowrap;text-overflow:ellipsis;line-height:var(--\\275sci-table-row-height)}:host[data-type=number]{text-align:end}:host:is([data-type=number],[data-type=date]){font-variant-numeric:tabular-nums}:host[data-padding=false]{border-inline:none;align-items:stretch}:host>sci-icon:not(:last-child){margin-right:.75em}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: SciIconComponent, selector: "sci-icon" }, { kind: "directive", type: SciComponentOutletDirective, selector: "ng-template[sciComponentOutlet]", inputs: ["sciComponentOutlet"] }, { kind: "pipe", type: SciNumberPipe, name: "sciNumber" }] });
|
|
1510
1846
|
}
|
|
1511
1847
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciTableCellComponent, decorators: [{
|
|
1512
1848
|
type: Component,
|
|
1513
1849
|
args: [{ selector: 'sci-table-cell', host: {
|
|
1514
1850
|
'[attr.data-type]': 'cell().column.type',
|
|
1515
1851
|
'[attr.data-column]': 'cell().column.name',
|
|
1852
|
+
'[attr.data-value]': 'value()',
|
|
1516
1853
|
'[attr.data-padding]': '!cell().column.padding ? false : null',
|
|
1517
|
-
'[attr.part]': '
|
|
1854
|
+
'[attr.part]': 'partAttribute()',
|
|
1518
1855
|
}, imports: [
|
|
1519
1856
|
NgTemplateOutlet,
|
|
1520
1857
|
SciIconComponent,
|
|
1521
1858
|
SciComponentOutletDirective,
|
|
1522
|
-
|
|
1859
|
+
SciNumberPipe,
|
|
1860
|
+
], hostDirectives: [
|
|
1861
|
+
SciTooltipOnOverflowDirective,
|
|
1862
|
+
], template: "@let cell = this.cell();\n\n@switch (cell.type) {\n @case ('template') {\n <ng-template *ngTemplateOutlet=\"template(); context: templateContext()\"/>\n }\n @case ('component') {\n <ng-container *sciComponentOutlet=\"cell.component\"/>\n }\n @case ('date') {\n {{cell.value()?.formatted}}\n }\n @case ('number') {\n {{cell.value() | sciNumber:cell.column.format()}}\n }\n @case ('enum') {\n @let value = cell.value();\n @if (value !== undefined) {\n @if (cell.column.format.icon && value.icon !== undefined) {\n <sci-icon [attr.title]=\"value.tooltip\">{{value.icon}}</sci-icon>\n }\n @if (cell.column.format.label) {\n <span>{{value.label}}</span>\n }\n }\n }\n @default {\n {{cell.value()}}\n }\n}\n", styles: ["@charset \"UTF-8\";:host{display:inline-grid;position:relative;border-inline:var(--\\275sci-table-cell-padding-inline) solid transparent;align-items:center;overflow:hidden}:host:is([data-type=string],[data-type=number],[data-type=date],[data-type=enum]){display:inline;white-space:nowrap;text-overflow:ellipsis;line-height:var(--\\275sci-table-row-height)}:host[data-type=number]{text-align:end}:host:is([data-type=number],[data-type=date]){font-variant-numeric:tabular-nums}:host[data-padding=false]{border-inline:none;align-items:stretch}:host>sci-icon:not(:last-child){margin-right:.75em}\n"] }]
|
|
1523
1863
|
}], propDecorators: { cell: [{ type: i0.Input, args: [{ isSignal: true, alias: "cell", required: true }] }], row: [{ type: i0.Input, args: [{ isSignal: true, alias: "row", required: true }] }] } });
|
|
1524
1864
|
|
|
1525
1865
|
/*
|
|
@@ -1572,30 +1912,29 @@ class SciTableRowComponent {
|
|
|
1572
1912
|
}
|
|
1573
1913
|
contributeRowActions() {
|
|
1574
1914
|
contributeMenu(this.rowActionsToolbarName, toolbar => {
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
rowActionsFactoryFn(toolbar, this.row().item, this.row().index);
|
|
1915
|
+
if (!this.row().loading) {
|
|
1916
|
+
this.table().rowActions?.(toolbar, this.row().item, this.row().index);
|
|
1578
1917
|
}
|
|
1579
1918
|
});
|
|
1580
1919
|
}
|
|
1581
1920
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciTableRowComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1582
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: SciTableRowComponent, isStandalone: true, selector: "sci-table-row", inputs: { row: { classPropertyName: "row", publicName: "row", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { primaryAction: "primaryAction" }, host: { listeners: { "click": "onRowClick($event)", "dblclick": "onRowDblClick($event)", "mouseenter": "onRowMouseEnter()", "mouseleave": "onRowMouseLeave($event)" }, properties: { "attr.data-active": "row().active() ? '' : null", "attr.data-selected": "row().selected() ? '' : null", "attr.data-hovered": "row().hovered() ? '' : null"
|
|
1921
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: SciTableRowComponent, isStandalone: true, selector: "sci-table-row", inputs: { row: { classPropertyName: "row", publicName: "row", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { primaryAction: "primaryAction" }, host: { listeners: { "click": "onRowClick($event)", "dblclick": "onRowDblClick($event)", "mouseenter": "onRowMouseEnter()", "mouseleave": "onRowMouseLeave($event)" }, properties: { "attr.data-active": "row().active() ? '' : null", "attr.data-selected": "row().selected() ? '' : null", "attr.data-hovered": "row().hovered() ? '' : null" } }, viewQueries: [{ propertyName: "rowActionToolbar", first: true, predicate: SciToolbarComponent, descendants: true, isSignal: true }], ngImport: i0, template: "@let row = this.row();\n\n<!-- Row Icons -->\n@if (row.cells?.length) {\n @for (icon of row.bindings?.icons(); track $index) {\n <sci-icon>{{icon}}</sci-icon>\n }\n}\n\n<!-- Table Cells -->\n@for (cell of row.cells; track cell.column.name) {\n <sci-table-cell [cell]=\"cell\" [row]=\"row\"/>\n} @empty {\n @for (column of table().columns(); track column.name) {\n <div class=\"skeleton e2e-skeleton\" [attr.data-column]=\"column.name\"></div>\n }\n}\n\n<!--Row Actions -->\n@let hasRowActions = !!table().rowActions;\n@let isRowHovered = table().hoveredRow() === row;\n@let isRowActionMenuOpen = rowActionToolbar()?.menuOpen();\n\n@if (hasRowActions && (isRowHovered || isRowActionMenuOpen)) {\n <sci-toolbar [name]=\"rowActionsToolbarName\" (click)=\"onActionToolbarClick($event)\" class=\"row-actions\"/>\n}\n", styles: ["@charset \"UTF-8\";:host{display:inline-grid;grid-template-columns:subgrid;grid-auto-rows:var(--sci-table-row-height);align-items:stretch;-webkit-user-select:none;user-select:none;border-bottom:var(--\\275sci-table-border-size) solid var(--sci-table-gridline-color)}:host[data-hovered]{background-color:var(--sci-table-row-background-color-hover)}:host[data-selected]{background-color:var(--sci-table-row-background-color-selected);--\\275sci-table-row-selected: true}:host[data-hovered]:not([data-selected]){border-radius:var(--sci-table-row-border-radius)}:host:is(:first-child,:not([data-selected])+sci-table-row)[data-selected]{border-top-left-radius:var(--sci-table-row-border-radius);border-top-right-radius:var(--sci-table-row-border-radius)}:host[data-selected]:not(:has(+sci-table-row[data-selected])){border-bottom-left-radius:var(--sci-table-row-border-radius);border-bottom-right-radius:var(--sci-table-row-border-radius)}@container (style(--\\275sci-table-scrolling: true)) or (style(--\\275sci-table-resizing: true)){:host{pointer-events:none}}:host:has(>div.skeleton){pointer-events:none;align-items:center}:host:has(>div.skeleton)>div.skeleton{display:inline-block;position:relative;overflow:hidden;border-radius:var(--sci-corner-small);background-color:var(--sci-color-skeleton-subtle);opacity:0;animation-name:visiblity;animation-duration:.5s;animation-timing-function:ease-in;animation-fill-mode:forwards}:host:has(>div.skeleton)>div.skeleton:after{position:absolute;inset:0;transform:translate(-100%);background-image:linear-gradient(to right,transparent 0,color-mix(in srgb,light-dark(var(--sci-static-color-white),var(--sci-static-color-black)) 30%,transparent) 50%,transparent);animation:shimmer 2s infinite;content:\"\"}@keyframes shimmer{to{transform:translate(100%)}}@keyframes visiblity{to{opacity:1}}:host:has(>div.skeleton)>div.skeleton{height:1em;margin-inline:var(--\\275sci-table-cell-padding-inline)}:host>sci-icon:has(~sci-table-cell:first-of-type){grid-column:1;grid-row:1;align-self:center;--sci-icon-size: 1em;margin-left:calc(var(--\\275sci-table-cell-padding-inline) + (sibling-index() - 1) * 1.5em);width:auto;max-width:var(--sci-icon-size)}:host>sci-icon:has(~sci-table-cell:first-of-type)+sci-table-cell{grid-column:1;grid-row:1;border-left:calc(var(--\\275sci-table-cell-padding-inline) + (sibling-index() - 1) * 1.5em) solid transparent}:host>sci-toolbar.row-actions{position:sticky;right:0;transform:translate(calc(-1 * var(--\\275sci-table-cell-padding-inline)));justify-self:end;align-self:center;border-radius:var(--sci-corner);padding:1px;background-color:var(--\\275sci-table-row-action-background-color);z-index:2;--sci-toolbar-item-background-color-hover: color-mix(in srgb, var(--\\275sci-table-row-action-background-color) 85%, light-dark(var(--sci-static-color-black), var(--sci-static-color-white)));--sci-toolbar-item-background-color-active: color-mix(in srgb, var(--\\275sci-table-row-action-background-color) 75%, light-dark(var(--sci-static-color-black), var(--sci-static-color-white)))}@container not style(--\\275sci-table-row-selected: true){:host>sci-toolbar.row-actions{--\\275sci-table-row-action-background-color: var(--sci-table-row-action-background-color)}}@container style(--\\275sci-table-row-selected: true){:host>sci-toolbar.row-actions{--\\275sci-table-row-action-background-color: var(--sci-table-row-action-background-color-selected)}}:host>sci-toolbar.row-actions:empty{display:none}\n"], dependencies: [{ kind: "component", type: SciTableCellComponent, selector: "sci-table-cell", inputs: ["cell", "row"] }, { kind: "component", type: SciToolbarComponent, selector: "sci-toolbar", inputs: ["name", "orientation", "context", "acceleratorTarget", "popoverViewContainerRef"] }, { kind: "component", type: SciIconComponent, selector: "sci-icon" }] });
|
|
1583
1922
|
}
|
|
1584
1923
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciTableRowComponent, decorators: [{
|
|
1585
1924
|
type: Component,
|
|
1586
1925
|
args: [{ selector: 'sci-table-row', imports: [
|
|
1587
1926
|
SciTableCellComponent,
|
|
1588
1927
|
SciToolbarComponent,
|
|
1928
|
+
SciIconComponent,
|
|
1589
1929
|
], host: {
|
|
1590
1930
|
'[attr.data-active]': `row().active() ? '' : null`,
|
|
1591
1931
|
'[attr.data-selected]': `row().selected() ? '' : null`,
|
|
1592
1932
|
'[attr.data-hovered]': `row().hovered() ? '' : null`,
|
|
1593
|
-
'[class]': 'row().bindings?.cssClass?.()',
|
|
1594
1933
|
'(click)': 'onRowClick($event)',
|
|
1595
1934
|
'(dblclick)': 'onRowDblClick($event)',
|
|
1596
1935
|
'(mouseenter)': 'onRowMouseEnter()',
|
|
1597
1936
|
'(mouseleave)': 'onRowMouseLeave($event)',
|
|
1598
|
-
}, template: "@let row = this.row();\n@for (cell of row.cells; track cell.column.name) {\n <sci-table-cell [cell]=\"cell\" [row]=\"row\"/>\n} @empty {\n @for (column of table().columns(); track column.name) {\n <div class=\"skeleton e2e-skeleton\" [attr.data-column]=\"column.name\"></div>\n }\n}\n\n@let hasRowActions = !!table().rowActions;\n@let isRowHovered = table().hoveredRow() === row;\n@let isRowActionMenuOpen = rowActionToolbar()?.menuOpen();\n\n@if (hasRowActions && (isRowHovered || isRowActionMenuOpen)) {\n
|
|
1937
|
+
}, template: "@let row = this.row();\n\n<!-- Row Icons -->\n@if (row.cells?.length) {\n @for (icon of row.bindings?.icons(); track $index) {\n <sci-icon>{{icon}}</sci-icon>\n }\n}\n\n<!-- Table Cells -->\n@for (cell of row.cells; track cell.column.name) {\n <sci-table-cell [cell]=\"cell\" [row]=\"row\"/>\n} @empty {\n @for (column of table().columns(); track column.name) {\n <div class=\"skeleton e2e-skeleton\" [attr.data-column]=\"column.name\"></div>\n }\n}\n\n<!--Row Actions -->\n@let hasRowActions = !!table().rowActions;\n@let isRowHovered = table().hoveredRow() === row;\n@let isRowActionMenuOpen = rowActionToolbar()?.menuOpen();\n\n@if (hasRowActions && (isRowHovered || isRowActionMenuOpen)) {\n <sci-toolbar [name]=\"rowActionsToolbarName\" (click)=\"onActionToolbarClick($event)\" class=\"row-actions\"/>\n}\n", styles: ["@charset \"UTF-8\";:host{display:inline-grid;grid-template-columns:subgrid;grid-auto-rows:var(--sci-table-row-height);align-items:stretch;-webkit-user-select:none;user-select:none;border-bottom:var(--\\275sci-table-border-size) solid var(--sci-table-gridline-color)}:host[data-hovered]{background-color:var(--sci-table-row-background-color-hover)}:host[data-selected]{background-color:var(--sci-table-row-background-color-selected);--\\275sci-table-row-selected: true}:host[data-hovered]:not([data-selected]){border-radius:var(--sci-table-row-border-radius)}:host:is(:first-child,:not([data-selected])+sci-table-row)[data-selected]{border-top-left-radius:var(--sci-table-row-border-radius);border-top-right-radius:var(--sci-table-row-border-radius)}:host[data-selected]:not(:has(+sci-table-row[data-selected])){border-bottom-left-radius:var(--sci-table-row-border-radius);border-bottom-right-radius:var(--sci-table-row-border-radius)}@container (style(--\\275sci-table-scrolling: true)) or (style(--\\275sci-table-resizing: true)){:host{pointer-events:none}}:host:has(>div.skeleton){pointer-events:none;align-items:center}:host:has(>div.skeleton)>div.skeleton{display:inline-block;position:relative;overflow:hidden;border-radius:var(--sci-corner-small);background-color:var(--sci-color-skeleton-subtle);opacity:0;animation-name:visiblity;animation-duration:.5s;animation-timing-function:ease-in;animation-fill-mode:forwards}:host:has(>div.skeleton)>div.skeleton:after{position:absolute;inset:0;transform:translate(-100%);background-image:linear-gradient(to right,transparent 0,color-mix(in srgb,light-dark(var(--sci-static-color-white),var(--sci-static-color-black)) 30%,transparent) 50%,transparent);animation:shimmer 2s infinite;content:\"\"}@keyframes shimmer{to{transform:translate(100%)}}@keyframes visiblity{to{opacity:1}}:host:has(>div.skeleton)>div.skeleton{height:1em;margin-inline:var(--\\275sci-table-cell-padding-inline)}:host>sci-icon:has(~sci-table-cell:first-of-type){grid-column:1;grid-row:1;align-self:center;--sci-icon-size: 1em;margin-left:calc(var(--\\275sci-table-cell-padding-inline) + (sibling-index() - 1) * 1.5em);width:auto;max-width:var(--sci-icon-size)}:host>sci-icon:has(~sci-table-cell:first-of-type)+sci-table-cell{grid-column:1;grid-row:1;border-left:calc(var(--\\275sci-table-cell-padding-inline) + (sibling-index() - 1) * 1.5em) solid transparent}:host>sci-toolbar.row-actions{position:sticky;right:0;transform:translate(calc(-1 * var(--\\275sci-table-cell-padding-inline)));justify-self:end;align-self:center;border-radius:var(--sci-corner);padding:1px;background-color:var(--\\275sci-table-row-action-background-color);z-index:2;--sci-toolbar-item-background-color-hover: color-mix(in srgb, var(--\\275sci-table-row-action-background-color) 85%, light-dark(var(--sci-static-color-black), var(--sci-static-color-white)));--sci-toolbar-item-background-color-active: color-mix(in srgb, var(--\\275sci-table-row-action-background-color) 75%, light-dark(var(--sci-static-color-black), var(--sci-static-color-white)))}@container not style(--\\275sci-table-row-selected: true){:host>sci-toolbar.row-actions{--\\275sci-table-row-action-background-color: var(--sci-table-row-action-background-color)}}@container style(--\\275sci-table-row-selected: true){:host>sci-toolbar.row-actions{--\\275sci-table-row-action-background-color: var(--sci-table-row-action-background-color-selected)}}:host>sci-toolbar.row-actions:empty{display:none}\n"] }]
|
|
1599
1938
|
}], ctorParameters: () => [], propDecorators: { row: [{ type: i0.Input, args: [{ isSignal: true, alias: "row", required: true }] }], primaryAction: [{ type: i0.Output, args: ["primaryAction"] }], rowActionToolbar: [{ type: i0.ViewChild, args: [i0.forwardRef(() => SciToolbarComponent), { isSignal: true }] }] } });
|
|
1600
1939
|
|
|
1601
1940
|
/*
|
|
@@ -1883,14 +2222,14 @@ class SciTableColumnsComponent {
|
|
|
1883
2222
|
}
|
|
1884
2223
|
}
|
|
1885
2224
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciTableColumnsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1886
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: SciTableColumnsComponent, isStandalone: true, selector: "sci-table-columns", inputs: { rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<!-- Render
|
|
2225
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: SciTableColumnsComponent, isStandalone: true, selector: "sci-table-columns", inputs: { rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<!-- Render splitters, also for non-resizable columns, as non-interactive column header dividers. -->\n@for (column of table().columns(); track column.name; let i = $index) {\n <sci-splitter orientation=\"vertical\"\n [class.resizing]=\"column.resizing()\"\n [attr.data-column]=\"column.name\"\n [attr.data-non-interactive]=\"!column.resizable() ? '' : null\"\n [style.grid-column]=\"i + 1\"\n (start)=\"onResizeStart(column)\"\n (move)=\"onResize(column, $event)\"\n (end)=\"onResizeEnd()\"\n (reset)=\"onPack(column)\"\n (mouseenter)=\"onMouseEnter()\"\n (mouseleave)=\"onMouseLeave()\"/>\n}\n\n<!-- Render an invisible synthetic column per column to read current widths and set minimum widths. -->\n@for (column of table().columns(); track column.name; let i = $index) {\n <sci-table-column [column]=\"column\" [style.grid-column]=\"i + 1\"/>\n}\n", styles: ["@charset \"UTF-8\";:host{display:grid;grid-template-columns:subgrid;overflow-x:clip;pointer-events:none}@container (style(--sci-table-header-column-divider: visible)) and (style(--\\275sci-table-header-visible: true)){:host{--\\275sci-table-header-column-divider-visible: true}}:host:has(>sci-splitter:hover){--\\275sci-column-splitter-hover: true}:host>sci-splitter,:host>sci-table-column{grid-row:1}:host>sci-splitter{--sci-splitter-size: var(--\\275sci-table-border-size);--sci-splitter-size-hover: var(--\\275sci-table-border-size);--sci-splitter-cross-axis-size: 0;--sci-splitter-background-color: var(--\\275sci-table-border-color);justify-self:end}:host>sci-splitter:where(:not([data-non-interactive])){pointer-events:auto}@container style(--\\275sci-table-header-column-divider-visible: true){:host>sci-splitter{--sci-splitter-cross-axis-start: .5em;--sci-splitter-cross-axis-size: calc(var(--\\275sci-table-header-height) - 2 * var(--sci-splitter-cross-axis-start))}@container style(--\\275sci-table-viewport-client-width >= --\\275sci-table-viewport-width){:host>sci-splitter:last-of-type:not(.resizing):not(:hover){--sci-splitter-cross-axis-size: 0}}}:host>sci-splitter:is(:hover,.resizing){--sci-splitter-background-color: rgb(from var(--\\275sci-table-border-color) r g b / .5);--sci-splitter-cross-axis-start: .5em;--sci-splitter-cross-axis-size: auto;--sci-splitter-cross-axis-end: 0}@container not style(--\\275sci-table-header-column-divider-visible: true){:host>sci-splitter:is(:hover,.resizing){--sci-splitter-cross-axis-start: 0}}@container style(--\\275sci-table-resizing: true){:host>sci-splitter:not(.resizing){pointer-events:none}}@container (style(--\\275sci-table-scrolling: true)) and (not style(--\\275sci-table-resizing: true)) and (not style(--\\275sci-column-splitter-hover: true)){:host>sci-splitter{pointer-events:none}}:host>sci-table-column{height:0}\n"], dependencies: [{ kind: "component", type: SciSplitterComponent, selector: "sci-splitter", inputs: ["orientation"], outputs: ["start", "move", "end", "reset"] }, { kind: "component", type: SciTableColumnComponent, selector: "sci-table-column", inputs: ["column"] }] });
|
|
1887
2226
|
}
|
|
1888
2227
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciTableColumnsComponent, decorators: [{
|
|
1889
2228
|
type: Component,
|
|
1890
2229
|
args: [{ selector: 'sci-table-columns', imports: [
|
|
1891
2230
|
SciSplitterComponent,
|
|
1892
2231
|
SciTableColumnComponent,
|
|
1893
|
-
], template: "<!-- Render
|
|
2232
|
+
], template: "<!-- Render splitters, also for non-resizable columns, as non-interactive column header dividers. -->\n@for (column of table().columns(); track column.name; let i = $index) {\n <sci-splitter orientation=\"vertical\"\n [class.resizing]=\"column.resizing()\"\n [attr.data-column]=\"column.name\"\n [attr.data-non-interactive]=\"!column.resizable() ? '' : null\"\n [style.grid-column]=\"i + 1\"\n (start)=\"onResizeStart(column)\"\n (move)=\"onResize(column, $event)\"\n (end)=\"onResizeEnd()\"\n (reset)=\"onPack(column)\"\n (mouseenter)=\"onMouseEnter()\"\n (mouseleave)=\"onMouseLeave()\"/>\n}\n\n<!-- Render an invisible synthetic column per column to read current widths and set minimum widths. -->\n@for (column of table().columns(); track column.name; let i = $index) {\n <sci-table-column [column]=\"column\" [style.grid-column]=\"i + 1\"/>\n}\n", styles: ["@charset \"UTF-8\";:host{display:grid;grid-template-columns:subgrid;overflow-x:clip;pointer-events:none}@container (style(--sci-table-header-column-divider: visible)) and (style(--\\275sci-table-header-visible: true)){:host{--\\275sci-table-header-column-divider-visible: true}}:host:has(>sci-splitter:hover){--\\275sci-column-splitter-hover: true}:host>sci-splitter,:host>sci-table-column{grid-row:1}:host>sci-splitter{--sci-splitter-size: var(--\\275sci-table-border-size);--sci-splitter-size-hover: var(--\\275sci-table-border-size);--sci-splitter-cross-axis-size: 0;--sci-splitter-background-color: var(--\\275sci-table-border-color);justify-self:end}:host>sci-splitter:where(:not([data-non-interactive])){pointer-events:auto}@container style(--\\275sci-table-header-column-divider-visible: true){:host>sci-splitter{--sci-splitter-cross-axis-start: .5em;--sci-splitter-cross-axis-size: calc(var(--\\275sci-table-header-height) - 2 * var(--sci-splitter-cross-axis-start))}@container style(--\\275sci-table-viewport-client-width >= --\\275sci-table-viewport-width){:host>sci-splitter:last-of-type:not(.resizing):not(:hover){--sci-splitter-cross-axis-size: 0}}}:host>sci-splitter:is(:hover,.resizing){--sci-splitter-background-color: rgb(from var(--\\275sci-table-border-color) r g b / .5);--sci-splitter-cross-axis-start: .5em;--sci-splitter-cross-axis-size: auto;--sci-splitter-cross-axis-end: 0}@container not style(--\\275sci-table-header-column-divider-visible: true){:host>sci-splitter:is(:hover,.resizing){--sci-splitter-cross-axis-start: 0}}@container style(--\\275sci-table-resizing: true){:host>sci-splitter:not(.resizing){pointer-events:none}}@container (style(--\\275sci-table-scrolling: true)) and (not style(--\\275sci-table-resizing: true)) and (not style(--\\275sci-column-splitter-hover: true)){:host>sci-splitter{pointer-events:none}}:host>sci-table-column{height:0}\n"] }]
|
|
1894
2233
|
}], propDecorators: { rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: true }] }] } });
|
|
1895
2234
|
|
|
1896
2235
|
/*
|
|
@@ -2006,15 +2345,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2006
2345
|
class SciColumnHeaderComponent {
|
|
2007
2346
|
column = input.required(/* @ts-ignore */
|
|
2008
2347
|
...(ngDevMode ? [{ debugName: "column" }] : /* istanbul ignore next */ []));
|
|
2348
|
+
labelElement = viewChild('label', /* @ts-ignore */
|
|
2349
|
+
...(ngDevMode ? [{ debugName: "labelElement" }] : /* istanbul ignore next */ [])); // public visibility required to be accessible in `configureTooltip` function
|
|
2009
2350
|
table = inject(ɵSCI_TABLE);
|
|
2010
|
-
header = text(computed(() => this.column().header()));
|
|
2011
2351
|
sortDirection = computed(() => this.table().sortCriteria().find(criteria => criteria.columnName === this.column().name)?.direction, /* @ts-ignore */
|
|
2012
2352
|
...(ngDevMode ? [{ debugName: "sortDirection" }] : /* istanbul ignore next */ []));
|
|
2013
2353
|
onSort(event) {
|
|
2014
2354
|
this.table().sort(this.column().name, event.ctrlKey || event.metaKey);
|
|
2015
2355
|
}
|
|
2016
2356
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciColumnHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2017
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: SciColumnHeaderComponent, isStandalone: true, selector: "sci-column-header", inputs: { column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "attr.data-column": "column().name"
|
|
2357
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: SciColumnHeaderComponent, isStandalone: true, selector: "sci-column-header", inputs: { column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "attr.data-column": "column().name" } }, providers: [
|
|
2358
|
+
configureTooltip$1(),
|
|
2359
|
+
], viewQueries: [{ propertyName: "labelElement", first: true, predicate: ["label"], descendants: true, isSignal: true }], hostDirectives: [{ directive: i1.SciTooltipOnOverflowDirective }], ngImport: i0, template: "@if (column().sortable()) {\n <button class=\"sort e2e-sort\"\n [attr.data-sort-direction]=\"sortDirection()\"\n (click)=\"onSort($event)\">\n <!-- Header -->\n <ng-container *ngTemplateOutlet=\"header_template\"/>\n\n <!-- Sort Indicator -->\n @switch (sortDirection()) {\n @case ('asc') {\n <sci-icon>scion:sort_ascending</sci-icon>\n }\n @case ('desc') {\n <sci-icon>scion:sort_descending</sci-icon>\n }\n @default {\n <sci-icon class=\"no-sort\">scion:sort_indicator</sci-icon>\n }\n }\n </button>\n} @else {\n <ng-container *ngTemplateOutlet=\"header_template\"/>\n}\n\n<ng-template #header_template>\n @if (column().header.icon) {\n <sci-icon class=\"icon e2e-icon\">{{column().header.icon}}</sci-icon>\n }\n\n @if (column().header.label) {\n <span [class.wrap]=\"table().wrapHeader()\" class=\"label\" #label>\n {{column().header.label!()}}\n </span>\n }\n</ng-template>\n", styles: ["@charset \"UTF-8\";:host{display:grid;align-items:center;gap:.25em}:host:not(:has(button.sort)){padding-inline:var(--\\275sci-table-cell-padding-inline)}:host:is(:focus-visible,:hover){--\\275sci-table-column-header-hover: true}:host:has(>sci-icon.icon):has(>span.label){grid-template-columns:auto 1fr}:host>button.sort{all:unset;display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:.25em;padding-inline:var(--\\275sci-table-cell-padding-inline);cursor:var(--sci-table-header-cursor);align-self:stretch}:host>button.sort:has(>sci-icon.icon):has(>span.label){grid-template-columns:auto minmax(0,1fr) auto}@container not style(--\\275sci-table-column-header-hover: true){:host>button.sort>sci-icon.no-sort{visibility:hidden}}@container style(--\\275sci-table-column-header-hover: true){:host>button.sort{background-color:var(--sci-table-header-background-color-hover)}}:host span.label{display:inline;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--sci-table-header-text-color);font-family:var(--sci-table-header-font-family),sans-serif;font-weight:var(--sci-table-header-font-weight);font-size:var(--sci-table-header-font-size);padding-block:.25em}:host span.label.wrap{white-space:wrap}\n"], dependencies: [{ kind: "component", type: SciIconComponent, selector: "sci-icon" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
|
|
2018
2360
|
}
|
|
2019
2361
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciColumnHeaderComponent, decorators: [{
|
|
2020
2362
|
type: Component,
|
|
@@ -2023,9 +2365,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2023
2365
|
NgTemplateOutlet,
|
|
2024
2366
|
], host: {
|
|
2025
2367
|
'[attr.data-column]': 'column().name',
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2368
|
+
}, hostDirectives: [
|
|
2369
|
+
SciTooltipOnOverflowDirective,
|
|
2370
|
+
], providers: [
|
|
2371
|
+
configureTooltip$1(),
|
|
2372
|
+
], template: "@if (column().sortable()) {\n <button class=\"sort e2e-sort\"\n [attr.data-sort-direction]=\"sortDirection()\"\n (click)=\"onSort($event)\">\n <!-- Header -->\n <ng-container *ngTemplateOutlet=\"header_template\"/>\n\n <!-- Sort Indicator -->\n @switch (sortDirection()) {\n @case ('asc') {\n <sci-icon>scion:sort_ascending</sci-icon>\n }\n @case ('desc') {\n <sci-icon>scion:sort_descending</sci-icon>\n }\n @default {\n <sci-icon class=\"no-sort\">scion:sort_indicator</sci-icon>\n }\n }\n </button>\n} @else {\n <ng-container *ngTemplateOutlet=\"header_template\"/>\n}\n\n<ng-template #header_template>\n @if (column().header.icon) {\n <sci-icon class=\"icon e2e-icon\">{{column().header.icon}}</sci-icon>\n }\n\n @if (column().header.label) {\n <span [class.wrap]=\"table().wrapHeader()\" class=\"label\" #label>\n {{column().header.label!()}}\n </span>\n }\n</ng-template>\n", styles: ["@charset \"UTF-8\";:host{display:grid;align-items:center;gap:.25em}:host:not(:has(button.sort)){padding-inline:var(--\\275sci-table-cell-padding-inline)}:host:is(:focus-visible,:hover){--\\275sci-table-column-header-hover: true}:host:has(>sci-icon.icon):has(>span.label){grid-template-columns:auto 1fr}:host>button.sort{all:unset;display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:.25em;padding-inline:var(--\\275sci-table-cell-padding-inline);cursor:var(--sci-table-header-cursor);align-self:stretch}:host>button.sort:has(>sci-icon.icon):has(>span.label){grid-template-columns:auto minmax(0,1fr) auto}@container not style(--\\275sci-table-column-header-hover: true){:host>button.sort>sci-icon.no-sort{visibility:hidden}}@container style(--\\275sci-table-column-header-hover: true){:host>button.sort{background-color:var(--sci-table-header-background-color-hover)}}:host span.label{display:inline;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--sci-table-header-text-color);font-family:var(--sci-table-header-font-family),sans-serif;font-weight:var(--sci-table-header-font-weight);font-size:var(--sci-table-header-font-size);padding-block:.25em}:host span.label.wrap{white-space:wrap}\n"] }]
|
|
2373
|
+
}], propDecorators: { column: [{ type: i0.Input, args: [{ isSignal: true, alias: "column", required: true }] }], labelElement: [{ type: i0.ViewChild, args: ['label', { isSignal: true }] }] } });
|
|
2374
|
+
function configureTooltip$1() {
|
|
2375
|
+
return [
|
|
2376
|
+
{
|
|
2377
|
+
provide: TOOLTIP_ON_OVERFLOW_DIRECTIVE_ADDITIONAL_TEXT,
|
|
2378
|
+
useFactory: () => {
|
|
2379
|
+
const host = inject(SciColumnHeaderComponent);
|
|
2380
|
+
return computed(() => host.column().header.tooltip?.());
|
|
2381
|
+
},
|
|
2382
|
+
},
|
|
2383
|
+
{
|
|
2384
|
+
provide: TOOLTIP_ON_OVERFLOW_DIRECTIVE_SOURCE_ELEMENT,
|
|
2385
|
+
useFactory: () => inject(SciColumnHeaderComponent).labelElement,
|
|
2386
|
+
},
|
|
2387
|
+
];
|
|
2388
|
+
}
|
|
2029
2389
|
|
|
2030
2390
|
/*
|
|
2031
2391
|
* Copyright (c) 2018-2026 Swiss Federal Railways
|
|
@@ -2036,22 +2396,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2036
2396
|
*
|
|
2037
2397
|
* SPDX-License-Identifier: EPL-2.0
|
|
2038
2398
|
*/
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2399
|
+
/**
|
|
2400
|
+
* Creates a comma-separated string with localized labels of the given enum values.
|
|
2401
|
+
*/
|
|
2402
|
+
class SciEnumLabelPipe {
|
|
2403
|
+
_injector = inject(Injector);
|
|
2404
|
+
transform(values, enumeration) {
|
|
2405
|
+
return computed(() => Arrays.coerce(values)
|
|
2406
|
+
.map(value => enumeration.find(entry => entry.value === value)?.label)
|
|
2407
|
+
.map(label => untracked(() => text(label, { injector: this._injector }))())
|
|
2408
|
+
.filter(Boolean)
|
|
2409
|
+
.join(', ') || undefined);
|
|
2410
|
+
}
|
|
2411
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciEnumLabelPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
2412
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.7", ngImport: i0, type: SciEnumLabelPipe, isStandalone: true, name: "sciEnumLabel" });
|
|
2051
2413
|
}
|
|
2052
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type:
|
|
2414
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciEnumLabelPipe, decorators: [{
|
|
2053
2415
|
type: Pipe,
|
|
2054
|
-
args: [{ name: '
|
|
2416
|
+
args: [{ name: 'sciEnumLabel' }]
|
|
2055
2417
|
}] });
|
|
2056
2418
|
|
|
2057
2419
|
/*
|
|
@@ -2066,33 +2428,36 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2066
2428
|
class SciColumnFilterComponent {
|
|
2067
2429
|
column = input.required(/* @ts-ignore */
|
|
2068
2430
|
...(ngDevMode ? [{ debugName: "column" }] : /* istanbul ignore next */ []));
|
|
2431
|
+
inputElement = viewChild('input', /* @ts-ignore */
|
|
2432
|
+
...(ngDevMode ? [{ debugName: "inputElement" }] : /* istanbul ignore next */ [])); // public visibility required to be accessible in `configureTooltip` function
|
|
2069
2433
|
filter = signal(null, /* @ts-ignore */
|
|
2070
2434
|
...(ngDevMode ? [{ debugName: "filter" }] : /* istanbul ignore next */ []));
|
|
2071
|
-
|
|
2072
|
-
...(ngDevMode ? [{ debugName: "input" }] : /* istanbul ignore next */ []));
|
|
2435
|
+
dimension = dimension(inject(ElementRef));
|
|
2073
2436
|
_table = inject(ɵSCI_TABLE);
|
|
2074
2437
|
_menuService = inject(_SciMenuService);
|
|
2075
2438
|
_injector = inject(Injector);
|
|
2076
2439
|
_host = inject(ElementRef).nativeElement;
|
|
2077
|
-
|
|
2440
|
+
menu;
|
|
2078
2441
|
constructor() {
|
|
2079
2442
|
this.bindToModel();
|
|
2080
2443
|
}
|
|
2081
2444
|
onFilterClick() {
|
|
2082
|
-
if (this.column().type === '
|
|
2083
|
-
this.
|
|
2445
|
+
if (this.column().type === 'enum') {
|
|
2446
|
+
this.toggleEnumChooser();
|
|
2447
|
+
}
|
|
2448
|
+
else {
|
|
2449
|
+
this.inputElement().nativeElement.focus();
|
|
2084
2450
|
}
|
|
2085
|
-
this.input().nativeElement.focus();
|
|
2086
2451
|
}
|
|
2087
2452
|
onReset(event) {
|
|
2088
2453
|
this.filter.set(null);
|
|
2089
|
-
this.
|
|
2454
|
+
this.inputElement().nativeElement.focus();
|
|
2090
2455
|
event.stopPropagation(); // prevent opening menu
|
|
2091
2456
|
}
|
|
2092
2457
|
bindToModel() {
|
|
2093
2458
|
const filterDebounced = debounced(computed(() => trim(this.filter())), async (value) => {
|
|
2094
|
-
// Debounce only if not empty.
|
|
2095
|
-
if (value !== null &&
|
|
2459
|
+
// Debounce only if not empty and not an enum.
|
|
2460
|
+
if (value !== null && this.column().type !== 'enum') {
|
|
2096
2461
|
await firstValueFrom(timer(200));
|
|
2097
2462
|
}
|
|
2098
2463
|
});
|
|
@@ -2105,56 +2470,93 @@ class SciColumnFilterComponent {
|
|
|
2105
2470
|
});
|
|
2106
2471
|
});
|
|
2107
2472
|
}
|
|
2108
|
-
|
|
2473
|
+
toggleEnumChooser() {
|
|
2109
2474
|
// Close menu if already opened.
|
|
2110
|
-
if (this.
|
|
2111
|
-
this.
|
|
2475
|
+
if (this.menu) {
|
|
2476
|
+
this.menu.close();
|
|
2112
2477
|
return;
|
|
2113
2478
|
}
|
|
2114
|
-
const
|
|
2479
|
+
const column = this.column();
|
|
2480
|
+
const injector = _createDestroyableInjector({ parent: this._injector });
|
|
2115
2481
|
runInInjectionContext(injector, () => {
|
|
2482
|
+
const menuId = `menu:column-filter-${UUID.randomUUID()}`;
|
|
2116
2483
|
// Contribute menu items.
|
|
2117
|
-
contributeMenu(
|
|
2118
|
-
|
|
2119
|
-
.
|
|
2484
|
+
contributeMenu(menuId, menu => {
|
|
2485
|
+
const multi = column.filterable() === 'multi';
|
|
2486
|
+
column.enumeration().forEach(entry => menu.addMenuItem({
|
|
2487
|
+
label: entry.label,
|
|
2488
|
+
checked: multi ? computed(() => this.filter()?.includes(entry.value) ?? false) : undefined,
|
|
2489
|
+
icon: column.format.filter.icon ? entry.icon : undefined,
|
|
2490
|
+
attributes: { 'data-option': `${entry.value}` },
|
|
2491
|
+
onSelect: () => this.filter.update(filter => {
|
|
2492
|
+
if (multi) {
|
|
2493
|
+
const values = new Set(filter ?? []);
|
|
2494
|
+
values.has(entry.value) ? values.delete(entry.value) : values.add(entry.value);
|
|
2495
|
+
return values.size ? Array.from(values) : null;
|
|
2496
|
+
}
|
|
2497
|
+
else {
|
|
2498
|
+
return entry.value;
|
|
2499
|
+
}
|
|
2500
|
+
}),
|
|
2501
|
+
}));
|
|
2502
|
+
});
|
|
2120
2503
|
// Open menu.
|
|
2121
|
-
this.
|
|
2504
|
+
this.menu = this._menuService.open(menuId, {
|
|
2122
2505
|
anchor: this._host,
|
|
2123
2506
|
minWidth: `${this._host.offsetWidth}px`,
|
|
2507
|
+
maxHeight: '300px',
|
|
2508
|
+
cssClass: 'e2e-filter',
|
|
2509
|
+
filter: column.enumeration().length >= 8 ? { focus: true } : false,
|
|
2510
|
+
maxWidth: `max(300px, ${this._host.offsetWidth}px)`, // overflow long enumeration labels
|
|
2124
2511
|
offset: { y: -1 },
|
|
2125
2512
|
});
|
|
2126
2513
|
// Close menu when start resizing a column. By default, closes the menu only on mouse up.
|
|
2127
2514
|
toObservable(this._table().resizing)
|
|
2128
2515
|
.pipe(skip(1))
|
|
2129
|
-
.subscribe(() => this.
|
|
2130
|
-
this.
|
|
2516
|
+
.subscribe(() => this.menu?.close());
|
|
2517
|
+
this.menu.onClose(() => {
|
|
2131
2518
|
injector.destroy();
|
|
2132
2519
|
// Restore focus manually as it is not restored automatically since opening the popover inside Shadow DOM.
|
|
2133
2520
|
// TODO [menu] Consider restore focus manually in Menu API due to restriction in shadow DOM.
|
|
2134
|
-
this.
|
|
2135
|
-
this.
|
|
2521
|
+
this.inputElement().nativeElement.focus();
|
|
2522
|
+
this.menu = undefined;
|
|
2136
2523
|
});
|
|
2137
2524
|
});
|
|
2138
2525
|
}
|
|
2139
2526
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciColumnFilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2140
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: SciColumnFilterComponent, isStandalone: true, selector: "sci-column-filter", inputs: { column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null } }, host: { listeners: { "click": "column().filterable() && onFilterClick()" }, properties: { "attr.data-column": "column().name", "attr.data-disabled": "!column().filterable() ? '' : null"
|
|
2527
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: SciColumnFilterComponent, isStandalone: true, selector: "sci-column-filter", inputs: { column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null } }, host: { listeners: { "click": "column().filterable() && onFilterClick()" }, properties: { "attr.data-column": "column().name", "attr.data-disabled": "!column().filterable() ? '' : null", "class.collapsed": "dimension().clientWidth < 50" } }, providers: [
|
|
2528
|
+
configureTooltip(),
|
|
2529
|
+
], viewQueries: [{ propertyName: "inputElement", first: true, predicate: ["input"], descendants: true, isSignal: true }], hostDirectives: [{ directive: i1.SciTooltipOnOverflowDirective }], ngImport: i0, template: "@let column = this.column();\n@if (column.filterable()) {\n @let active = filter() !== null && filter() !== '';\n\n <sci-icon class=\"filter e2e-filter\" [class.active]=\"active\">scion:filter</sci-icon>\n\n @switch (column.type) {\n @case ('number') {\n <input [(ngModel)]=\"filter\" type=\"number\" #input/>\n }\n @case ('enum') {\n <input [ngModel]=\"(filter() | sciEnumLabel:column.enumeration())()\" type=\"button\" #input>\n <sci-icon class=\"chevron\">{{menu ? 'scion:chevron_up' : 'scion:chevron_down'}}</sci-icon>\n }\n @default {\n <input [(ngModel)]=\"filter\" type=\"text\" #input/>\n }\n }\n\n @if (active) {\n <button class=\"clear e2e-clear\" (click)=\"onReset($event)\" [attr.title]=\"('%scion:components:clear.tooltip' | sciText)()\">\n <sci-icon>scion:clear</sci-icon>\n </button>\n }\n}\n", styles: ["@charset \"UTF-8\";:host{display:flex;gap:.25em;align-items:center;padding-inline:var(--\\275sci-table-cell-padding-inline);border-bottom:var(--\\275sci-table-border-size) solid transparent;margin-bottom:-1px;transition:border-bottom-color ease-in-out .15s,color ease-in-out .15s}:host:focus-within:not(:disabled):not(:has(input:disabled)){border-bottom-color:var(--sci-color-accent)}:host>sci-icon.filter.active{color:var(--sci-color-accent)}:host:has(input[type=button]){cursor:var(--sci-button-cursor)}:host:has(input[type=button]):has(button.clear)>sci-icon.chevron{display:none}:host.collapsed{gap:0}:host>input{all:unset;flex:auto;align-self:stretch;width:0;min-width:0;color:var(--sci-color-text);appearance:auto;box-sizing:border-box}:host>input[type=number]::-webkit-outer-spin-button,:host>input[type=number]::-webkit-inner-spin-button{appearance:none;margin:0}:host>input[type=button]{white-space:nowrap;text-overflow:ellipsis}:host>button.clear{all:unset;display:inline-grid;place-content:center;place-items:center;padding:.25em;border-radius:var(--sci-button-border-radius);-webkit-user-select:none;user-select:none;overflow:hidden;cursor:var(--sci-button-cursor);--sci-icon-size: var(--sci-button-icon-size)}:host>button.clear:hover:where(:not(:disabled)){background-color:var(--sci-button-background-color-hover)}:host>button.clear:active:where(:not(:disabled)){background-color:var(--sci-button-background-color-active)}:host>button.clear:focus:not(:focus-visible){outline:none}:host>button.clear:focus-visible{outline:var(--sci-button-outline-width) solid var(--sci-color-accent)}:host>button.clear:disabled{color:var(--sci-button-text-color-disabled)}:host>button.clear{padding:1px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NumberValueAccessor, selector: "input[type=number]:not([ngNoCva])[formControlName],input[type=number]:not([ngNoCva])[formControl],input[type=number]:not([ngNoCva])[ngModel]" }, { 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: SciIconComponent, selector: "sci-icon" }, { kind: "pipe", type: SciEnumLabelPipe, name: "sciEnumLabel" }, { kind: "pipe", type: SciTextPipe, name: "sciText" }] });
|
|
2141
2530
|
}
|
|
2142
2531
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciColumnFilterComponent, decorators: [{
|
|
2143
2532
|
type: Component,
|
|
2144
2533
|
args: [{ selector: 'sci-column-filter', imports: [
|
|
2145
2534
|
FormsModule,
|
|
2146
2535
|
SciIconComponent,
|
|
2536
|
+
SciEnumLabelPipe,
|
|
2147
2537
|
SciTextPipe,
|
|
2148
|
-
|
|
2538
|
+
], hostDirectives: [
|
|
2539
|
+
SciTooltipOnOverflowDirective,
|
|
2149
2540
|
], host: {
|
|
2150
2541
|
'[attr.data-column]': 'column().name',
|
|
2151
2542
|
'[attr.data-disabled]': `!column().filterable() ? '' : null`,
|
|
2543
|
+
'[class.collapsed]': 'dimension().clientWidth < 50',
|
|
2152
2544
|
'(click)': 'column().filterable() && onFilterClick()',
|
|
2153
|
-
},
|
|
2154
|
-
|
|
2545
|
+
}, providers: [
|
|
2546
|
+
configureTooltip(),
|
|
2547
|
+
], template: "@let column = this.column();\n@if (column.filterable()) {\n @let active = filter() !== null && filter() !== '';\n\n <sci-icon class=\"filter e2e-filter\" [class.active]=\"active\">scion:filter</sci-icon>\n\n @switch (column.type) {\n @case ('number') {\n <input [(ngModel)]=\"filter\" type=\"number\" #input/>\n }\n @case ('enum') {\n <input [ngModel]=\"(filter() | sciEnumLabel:column.enumeration())()\" type=\"button\" #input>\n <sci-icon class=\"chevron\">{{menu ? 'scion:chevron_up' : 'scion:chevron_down'}}</sci-icon>\n }\n @default {\n <input [(ngModel)]=\"filter\" type=\"text\" #input/>\n }\n }\n\n @if (active) {\n <button class=\"clear e2e-clear\" (click)=\"onReset($event)\" [attr.title]=\"('%scion:components:clear.tooltip' | sciText)()\">\n <sci-icon>scion:clear</sci-icon>\n </button>\n }\n}\n", styles: ["@charset \"UTF-8\";:host{display:flex;gap:.25em;align-items:center;padding-inline:var(--\\275sci-table-cell-padding-inline);border-bottom:var(--\\275sci-table-border-size) solid transparent;margin-bottom:-1px;transition:border-bottom-color ease-in-out .15s,color ease-in-out .15s}:host:focus-within:not(:disabled):not(:has(input:disabled)){border-bottom-color:var(--sci-color-accent)}:host>sci-icon.filter.active{color:var(--sci-color-accent)}:host:has(input[type=button]){cursor:var(--sci-button-cursor)}:host:has(input[type=button]):has(button.clear)>sci-icon.chevron{display:none}:host.collapsed{gap:0}:host>input{all:unset;flex:auto;align-self:stretch;width:0;min-width:0;color:var(--sci-color-text);appearance:auto;box-sizing:border-box}:host>input[type=number]::-webkit-outer-spin-button,:host>input[type=number]::-webkit-inner-spin-button{appearance:none;margin:0}:host>input[type=button]{white-space:nowrap;text-overflow:ellipsis}:host>button.clear{all:unset;display:inline-grid;place-content:center;place-items:center;padding:.25em;border-radius:var(--sci-button-border-radius);-webkit-user-select:none;user-select:none;overflow:hidden;cursor:var(--sci-button-cursor);--sci-icon-size: var(--sci-button-icon-size)}:host>button.clear:hover:where(:not(:disabled)){background-color:var(--sci-button-background-color-hover)}:host>button.clear:active:where(:not(:disabled)){background-color:var(--sci-button-background-color-active)}:host>button.clear:focus:not(:focus-visible){outline:none}:host>button.clear:focus-visible{outline:var(--sci-button-outline-width) solid var(--sci-color-accent)}:host>button.clear:disabled{color:var(--sci-button-text-color-disabled)}:host>button.clear{padding:1px}\n"] }]
|
|
2548
|
+
}], ctorParameters: () => [], propDecorators: { column: [{ type: i0.Input, args: [{ isSignal: true, alias: "column", required: true }] }], inputElement: [{ type: i0.ViewChild, args: ['input', { isSignal: true }] }] } });
|
|
2155
2549
|
function trim(value) {
|
|
2156
2550
|
return typeof value === 'string' ? value.trim() || null : value;
|
|
2157
2551
|
}
|
|
2552
|
+
function configureTooltip() {
|
|
2553
|
+
return [
|
|
2554
|
+
{
|
|
2555
|
+
provide: TOOLTIP_ON_OVERFLOW_DIRECTIVE_SOURCE_ELEMENT,
|
|
2556
|
+
useFactory: () => inject(SciColumnFilterComponent).inputElement,
|
|
2557
|
+
},
|
|
2558
|
+
];
|
|
2559
|
+
}
|
|
2158
2560
|
|
|
2159
2561
|
/*
|
|
2160
2562
|
* Copyright (c) 2018-2026 Swiss Federal Railways
|
|
@@ -2286,7 +2688,7 @@ class SciTableComponent {
|
|
|
2286
2688
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: SciTableComponent, isStandalone: true, selector: "sci-table", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, table: { classPropertyName: "table", publicName: "table", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { primaryAction: "primaryAction" }, host: { properties: { "attr.name": "name()", "style.--\u0275sci-table-scrolling": "table().scrolling() ? `true` : null", "style.--\u0275sci-table-resizing": "table().resizing() ? `true` : null" } }, providers: [
|
|
2287
2689
|
provideSciTable(),
|
|
2288
2690
|
SciTableSelectionService,
|
|
2289
|
-
], viewQueries: [{ propertyName: "_viewport", first: true, predicate: SciTableViewportComponent, descendants: true, read: ElementRef, isSignal: true }, { propertyName: "_viewportClient", first: true, predicate: SciTableGridComponent, descendants: true, read: ElementRef, isSignal: true }, { propertyName: "_tableHeader", first: true, predicate: SciTableHeaderComponent, descendants: true, read: ElementRef, isSignal: true }, { propertyName: "_tableBody", first: true, predicate: SciTableBodyComponent, descendants: true, read: ElementRef, isSignal: true }, { propertyName: "_itemSizeSyntheticElement", first: true, predicate: ["item_size_synthetic_element"], descendants: true, isSignal: true }, { propertyName: "_cellPaddingSyntheticElement", first: true, predicate: ["cell_padding_synthetic_element"], descendants: true, isSignal: true }, { propertyName: "rows", predicate: SciTableRowComponent, descendants: true, isSignal: true }], ngImport: i0, template: "@let table = this.table();\n\n<sci-table-viewport #viewport>\n <sci-table-grid>\n <!-- Table header -->\n @if (table.showHeader() || table.filterable()) {\n <sci-table-header/>\n }\n\n <!-- Table body -->\n <sci-table-body sciTableKeyboardNavigator>\n @if (!table.error()) {\n <!-- Track index to reuse the table row elements -->\n @for (row of table.rows(); track $index) {\n <sci-table-row [row]=\"row\"
|
|
2691
|
+
], viewQueries: [{ propertyName: "_viewport", first: true, predicate: SciTableViewportComponent, descendants: true, read: ElementRef, isSignal: true }, { propertyName: "_viewportClient", first: true, predicate: SciTableGridComponent, descendants: true, read: ElementRef, isSignal: true }, { propertyName: "_tableHeader", first: true, predicate: SciTableHeaderComponent, descendants: true, read: ElementRef, isSignal: true }, { propertyName: "_tableBody", first: true, predicate: SciTableBodyComponent, descendants: true, read: ElementRef, isSignal: true }, { propertyName: "_itemSizeSyntheticElement", first: true, predicate: ["item_size_synthetic_element"], descendants: true, isSignal: true }, { propertyName: "_cellPaddingSyntheticElement", first: true, predicate: ["cell_padding_synthetic_element"], descendants: true, isSignal: true }, { propertyName: "rows", predicate: SciTableRowComponent, descendants: true, isSignal: true }], ngImport: i0, template: "@let table = this.table();\n\n<!-- TODO [#384] Replace with sci-viewport -->\n<sci-table-viewport #viewport>\n <sci-table-grid>\n <!-- Table header -->\n @if (table.showHeader() || table.filterable()) {\n <sci-table-header/>\n }\n\n <!-- Table body -->\n <sci-table-body sciTableKeyboardNavigator>\n @if (!table.error()) {\n <!-- Track index to reuse the table row elements -->\n @for (row of table.rows(); track $index) {\n <sci-table-row [row]=\"row\" [sciAttributes]=\"row.bindings?.attributes()\" [class]=\"row.bindings?.classes?.()\" (primaryAction)=\"onRowPrimaryAction($event)\"/>\n } @empty {\n <span class=\"message e2e-no-data\">{{('%scion:components:no_items.message' | sciText)()}}</span>\n }\n } @else {\n <span class=\"message e2e-datasource\">\n {{('%scion:components:datasource_error.message' | sciText)()}}\n\n <button (click)=\"onRetry()\" class=\"action e2e-datasource-retry\">\n <sci-icon>scion:reload</sci-icon>\n <span>{{('%scion:components:retry.action' | sciText)()}}</span>\n </button>\n </span>\n }\n\n <!-- Render active row outline separately to preserve row border-radius within block selection. -->\n @if (table.activeRow()) {\n <div class=\"active-row-outline e2e-active-row-outline\"></div>\n }\n </sci-table-body>\n\n <!-- Render column splitters. -->\n <sci-table-columns [rows]=\"rows()\"/>\n </sci-table-grid>\n</sci-table-viewport>\n\n<!-- Scrollbars -->\n<sci-scrollbar direction=\"hscroll\" [viewport]=\"viewport.host\"/>\n<sci-scrollbar direction=\"vscroll\" [viewport]=\"viewport.host\"/>\n\n@if (table.loading()) {\n <sci-throbber type=\"spinner\" class=\"loading-indicator e2e-loading-indicator\"/>\n}\n\n<!-- Synthetic element to compute the absolute pixel value of the `--sci-table-row-height`, relative to the table's font size if em-based. -->\n<div class=\"synthetic item-size\" #item_size_synthetic_element></div>\n\n<!-- Synthetic element to compute the absolute pixel value of the `--sci-table-cell-padding-inline`, relative to the table's font size if em-based. -->\n<div class=\"synthetic cell-padding\" #cell_padding_synthetic_element></div>\n", styles: ["@charset \"UTF-8\";:host{display:block;overflow:hidden;--\\275sci-table-border-size: 1px;--\\275sci-table-border-color: var(--sci-color-border)}:host>sci-table-viewport{display:block;position:relative;height:100%;overflow:auto;scrollbar-width:none;isolation:isolate;box-sizing:border-box;anchor-name:--sci-table-viewport}:host>sci-table-viewport:is(:not(:hover),:has(sci-table-header:hover))~sci-scrollbar{opacity:0}:host>sci-table-viewport:has(sci-table-header){--\\275sci-table-header-visible: true}:host>sci-table-viewport:has(sci-table-header>sci-column-header){--\\275sci-column-header-visible: true}:host>sci-table-viewport:has(~sci-scrollbar.scrolling){--\\275sci-table-scrolling: true}:host>sci-table-viewport>sci-table-grid{display:grid;grid-template-columns:var(--\\275sci-table-columns, repeat(auto-fit, 100px)) 0;grid-auto-rows:min-content;grid-template-rows:min-content 1fr;width:min-content;min-width:100%;min-height:100%}@container not style(--\\275sci-table-header-visible: true){:host>sci-table-viewport>sci-table-grid{grid-template-rows:1fr}}:host>sci-table-viewport>sci-table-grid>sci-table-header{z-index:1;grid-row:1;grid-column:1/-1;position:sticky;top:0}:host>sci-table-viewport>sci-table-grid>sci-table-body{anchor-name:--sci-table-body;grid-row:2}@container not style(--\\275sci-table-header-visible: true){:host>sci-table-viewport>sci-table-grid>sci-table-body{grid-row:1}}:host>sci-table-viewport>sci-table-grid>sci-table-body{display:grid;grid-template-columns:subgrid;grid-column:1/-1;grid-auto-rows:var(--sci-table-row-height);outline:none;padding-top:var(--\\275sci-table-virtual-scroll-offset-top);padding-bottom:var(--\\275sci-table-virtual-scroll-offset-bottom)}:host>sci-table-viewport>sci-table-grid>sci-table-body>sci-table-row{grid-column:1/-1}:host>sci-table-viewport>sci-table-grid>sci-table-body>sci-table-row[data-active]{anchor-name:--sci-table-active-row}:host>sci-table-viewport>sci-table-grid>sci-table-body>div.active-row-outline{position:absolute;top:anchor(--sci-table-active-row top);right:anchor(--sci-table-active-row right);bottom:anchor(--sci-table-active-row bottom);left:anchor(--sci-table-active-row left);border:var(--sci-table-row-outline-width) var(--sci-table-row-outline-style) var(--sci-table-row-outline-color);border-radius:var(--sci-table-row-border-radius);pointer-events:none}:host>sci-table-viewport>sci-table-grid>sci-table-body:not(:has(sci-table-row[data-active]))>div.active-row-outline{display:none}:host>sci-table-viewport>sci-table-grid>sci-table-body>span.message{grid-column:1/-1;grid-row:auto/span 2;justify-self:center;align-self:center;display:flex;flex-direction:column;align-items:center;gap:1em;-webkit-user-select:none;user-select:none;white-space:nowrap;color:var(--sci-color-text-subtle)}:host>sci-table-viewport>sci-table-grid>sci-table-body>span.message:has(button.action){grid-row:auto/span 4}:host>sci-table-viewport>sci-table-grid>sci-table-body>span.message>button.action{all:unset;display:inline-grid;place-content:center;place-items:center;padding:.25em;border-radius:var(--sci-button-border-radius);-webkit-user-select:none;user-select:none;overflow:hidden;cursor:var(--sci-button-cursor);--sci-icon-size: var(--sci-button-icon-size)}:host>sci-table-viewport>sci-table-grid>sci-table-body>span.message>button.action:hover:where(:not(:disabled)){background-color:var(--sci-button-background-color-hover)}:host>sci-table-viewport>sci-table-grid>sci-table-body>span.message>button.action:active:where(:not(:disabled)){background-color:var(--sci-button-background-color-active)}:host>sci-table-viewport>sci-table-grid>sci-table-body>span.message>button.action:focus:not(:focus-visible){outline:none}:host>sci-table-viewport>sci-table-grid>sci-table-body>span.message>button.action:focus-visible{outline:var(--sci-button-outline-width) solid var(--sci-color-accent)}:host>sci-table-viewport>sci-table-grid>sci-table-body>span.message>button.action:disabled{color:var(--sci-button-text-color-disabled)}:host>sci-table-viewport>sci-table-grid>sci-table-body>span.message>button.action{display:flex;gap:.5em;border:1px solid var(--sci-color-border);padding:.35em 1em}@container style(--\\275sci-table-viewport-client-width > --\\275sci-table-viewport-width){:host>sci-table-viewport>sci-table-grid>sci-table-body>span.message{position:sticky;left:50%;right:50%;width:0}}:host>sci-table-viewport>sci-table-grid>sci-table-body:has(>span.message){z-index:2}:host>sci-table-viewport>sci-table-grid>sci-table-columns{grid-area:1/1/-1/-1;z-index:1;position:sticky;top:0;max-height:var(--\\275sci-table-viewport-height)}:host>sci-scrollbar{position:absolute}:host>sci-scrollbar[direction=vscroll]{top:calc(anchor(--sci-table-body top) + 2px);right:calc(anchor(--sci-table-viewport right) + 2px);bottom:calc(anchor(--sci-table-viewport bottom) + 2px)}:host>sci-scrollbar[direction=hscroll]{left:calc(anchor(--sci-table-viewport left) + 2px);bottom:calc(anchor(--sci-table-viewport bottom) + 1px);right:calc(anchor(--sci-table-viewport right) + 2px)}@container style(--\\275sci-table-resizing: true){:host>sci-scrollbar{pointer-events:none}}:host>sci-throbber.loading-indicator{--sci-throbber-size: 16px;position:absolute;top:calc(anchor(--sci-table-viewport top) + .5em);right:calc(anchor(--sci-table-viewport right) + .5em)}:host>div.synthetic{position:absolute;pointer-events:none;visibility:hidden}:host>div.synthetic.item-size{height:var(--sci-table-row-height)}:host>div.synthetic.cell-padding{width:var(--sci-table-cell-padding-inline)}\n"], dependencies: [{ kind: "component", type: SciTableViewportComponent, selector: "sci-table-viewport" }, { kind: "component", type: SciTableHeaderComponent, selector: "sci-table-header" }, { kind: "component", type: SciTableGridComponent, selector: "sci-table-grid" }, { kind: "component", type: SciTableBodyComponent, selector: "sci-table-body" }, { kind: "component", type: SciTableRowComponent, selector: "sci-table-row", inputs: ["row"], outputs: ["primaryAction"] }, { kind: "component", type: SciTableColumnsComponent, selector: "sci-table-columns", inputs: ["rows"] }, { kind: "directive", type: SciTableKeyboardNavigatorDirective, selector: "[sciTableKeyboardNavigator]" }, { kind: "directive", type: SciAttributesDirective, selector: "[sciAttributes]", inputs: ["sciAttributes"] }, { kind: "component", type: SciScrollbarComponent, selector: "sci-scrollbar", inputs: ["direction", "viewport"] }, { kind: "component", type: SciThrobberComponent, selector: "sci-throbber", inputs: ["type"] }, { kind: "component", type: SciIconComponent, selector: "sci-icon" }, { kind: "pipe", type: SciTextPipe, name: "sciText" }], encapsulation: i0.ViewEncapsulation.ShadowDom });
|
|
2290
2692
|
}
|
|
2291
2693
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciTableComponent, decorators: [{
|
|
2292
2694
|
type: Component,
|
|
@@ -2310,7 +2712,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2310
2712
|
], providers: [
|
|
2311
2713
|
provideSciTable(),
|
|
2312
2714
|
SciTableSelectionService,
|
|
2313
|
-
], template: "@let table = this.table();\n\n<sci-table-viewport #viewport>\n <sci-table-grid>\n <!-- Table header -->\n @if (table.showHeader() || table.filterable()) {\n <sci-table-header/>\n }\n\n <!-- Table body -->\n <sci-table-body sciTableKeyboardNavigator>\n @if (!table.error()) {\n <!-- Track index to reuse the table row elements -->\n @for (row of table.rows(); track $index) {\n <sci-table-row [row]=\"row\"
|
|
2715
|
+
], template: "@let table = this.table();\n\n<!-- TODO [#384] Replace with sci-viewport -->\n<sci-table-viewport #viewport>\n <sci-table-grid>\n <!-- Table header -->\n @if (table.showHeader() || table.filterable()) {\n <sci-table-header/>\n }\n\n <!-- Table body -->\n <sci-table-body sciTableKeyboardNavigator>\n @if (!table.error()) {\n <!-- Track index to reuse the table row elements -->\n @for (row of table.rows(); track $index) {\n <sci-table-row [row]=\"row\" [sciAttributes]=\"row.bindings?.attributes()\" [class]=\"row.bindings?.classes?.()\" (primaryAction)=\"onRowPrimaryAction($event)\"/>\n } @empty {\n <span class=\"message e2e-no-data\">{{('%scion:components:no_items.message' | sciText)()}}</span>\n }\n } @else {\n <span class=\"message e2e-datasource\">\n {{('%scion:components:datasource_error.message' | sciText)()}}\n\n <button (click)=\"onRetry()\" class=\"action e2e-datasource-retry\">\n <sci-icon>scion:reload</sci-icon>\n <span>{{('%scion:components:retry.action' | sciText)()}}</span>\n </button>\n </span>\n }\n\n <!-- Render active row outline separately to preserve row border-radius within block selection. -->\n @if (table.activeRow()) {\n <div class=\"active-row-outline e2e-active-row-outline\"></div>\n }\n </sci-table-body>\n\n <!-- Render column splitters. -->\n <sci-table-columns [rows]=\"rows()\"/>\n </sci-table-grid>\n</sci-table-viewport>\n\n<!-- Scrollbars -->\n<sci-scrollbar direction=\"hscroll\" [viewport]=\"viewport.host\"/>\n<sci-scrollbar direction=\"vscroll\" [viewport]=\"viewport.host\"/>\n\n@if (table.loading()) {\n <sci-throbber type=\"spinner\" class=\"loading-indicator e2e-loading-indicator\"/>\n}\n\n<!-- Synthetic element to compute the absolute pixel value of the `--sci-table-row-height`, relative to the table's font size if em-based. -->\n<div class=\"synthetic item-size\" #item_size_synthetic_element></div>\n\n<!-- Synthetic element to compute the absolute pixel value of the `--sci-table-cell-padding-inline`, relative to the table's font size if em-based. -->\n<div class=\"synthetic cell-padding\" #cell_padding_synthetic_element></div>\n", styles: ["@charset \"UTF-8\";:host{display:block;overflow:hidden;--\\275sci-table-border-size: 1px;--\\275sci-table-border-color: var(--sci-color-border)}:host>sci-table-viewport{display:block;position:relative;height:100%;overflow:auto;scrollbar-width:none;isolation:isolate;box-sizing:border-box;anchor-name:--sci-table-viewport}:host>sci-table-viewport:is(:not(:hover),:has(sci-table-header:hover))~sci-scrollbar{opacity:0}:host>sci-table-viewport:has(sci-table-header){--\\275sci-table-header-visible: true}:host>sci-table-viewport:has(sci-table-header>sci-column-header){--\\275sci-column-header-visible: true}:host>sci-table-viewport:has(~sci-scrollbar.scrolling){--\\275sci-table-scrolling: true}:host>sci-table-viewport>sci-table-grid{display:grid;grid-template-columns:var(--\\275sci-table-columns, repeat(auto-fit, 100px)) 0;grid-auto-rows:min-content;grid-template-rows:min-content 1fr;width:min-content;min-width:100%;min-height:100%}@container not style(--\\275sci-table-header-visible: true){:host>sci-table-viewport>sci-table-grid{grid-template-rows:1fr}}:host>sci-table-viewport>sci-table-grid>sci-table-header{z-index:1;grid-row:1;grid-column:1/-1;position:sticky;top:0}:host>sci-table-viewport>sci-table-grid>sci-table-body{anchor-name:--sci-table-body;grid-row:2}@container not style(--\\275sci-table-header-visible: true){:host>sci-table-viewport>sci-table-grid>sci-table-body{grid-row:1}}:host>sci-table-viewport>sci-table-grid>sci-table-body{display:grid;grid-template-columns:subgrid;grid-column:1/-1;grid-auto-rows:var(--sci-table-row-height);outline:none;padding-top:var(--\\275sci-table-virtual-scroll-offset-top);padding-bottom:var(--\\275sci-table-virtual-scroll-offset-bottom)}:host>sci-table-viewport>sci-table-grid>sci-table-body>sci-table-row{grid-column:1/-1}:host>sci-table-viewport>sci-table-grid>sci-table-body>sci-table-row[data-active]{anchor-name:--sci-table-active-row}:host>sci-table-viewport>sci-table-grid>sci-table-body>div.active-row-outline{position:absolute;top:anchor(--sci-table-active-row top);right:anchor(--sci-table-active-row right);bottom:anchor(--sci-table-active-row bottom);left:anchor(--sci-table-active-row left);border:var(--sci-table-row-outline-width) var(--sci-table-row-outline-style) var(--sci-table-row-outline-color);border-radius:var(--sci-table-row-border-radius);pointer-events:none}:host>sci-table-viewport>sci-table-grid>sci-table-body:not(:has(sci-table-row[data-active]))>div.active-row-outline{display:none}:host>sci-table-viewport>sci-table-grid>sci-table-body>span.message{grid-column:1/-1;grid-row:auto/span 2;justify-self:center;align-self:center;display:flex;flex-direction:column;align-items:center;gap:1em;-webkit-user-select:none;user-select:none;white-space:nowrap;color:var(--sci-color-text-subtle)}:host>sci-table-viewport>sci-table-grid>sci-table-body>span.message:has(button.action){grid-row:auto/span 4}:host>sci-table-viewport>sci-table-grid>sci-table-body>span.message>button.action{all:unset;display:inline-grid;place-content:center;place-items:center;padding:.25em;border-radius:var(--sci-button-border-radius);-webkit-user-select:none;user-select:none;overflow:hidden;cursor:var(--sci-button-cursor);--sci-icon-size: var(--sci-button-icon-size)}:host>sci-table-viewport>sci-table-grid>sci-table-body>span.message>button.action:hover:where(:not(:disabled)){background-color:var(--sci-button-background-color-hover)}:host>sci-table-viewport>sci-table-grid>sci-table-body>span.message>button.action:active:where(:not(:disabled)){background-color:var(--sci-button-background-color-active)}:host>sci-table-viewport>sci-table-grid>sci-table-body>span.message>button.action:focus:not(:focus-visible){outline:none}:host>sci-table-viewport>sci-table-grid>sci-table-body>span.message>button.action:focus-visible{outline:var(--sci-button-outline-width) solid var(--sci-color-accent)}:host>sci-table-viewport>sci-table-grid>sci-table-body>span.message>button.action:disabled{color:var(--sci-button-text-color-disabled)}:host>sci-table-viewport>sci-table-grid>sci-table-body>span.message>button.action{display:flex;gap:.5em;border:1px solid var(--sci-color-border);padding:.35em 1em}@container style(--\\275sci-table-viewport-client-width > --\\275sci-table-viewport-width){:host>sci-table-viewport>sci-table-grid>sci-table-body>span.message{position:sticky;left:50%;right:50%;width:0}}:host>sci-table-viewport>sci-table-grid>sci-table-body:has(>span.message){z-index:2}:host>sci-table-viewport>sci-table-grid>sci-table-columns{grid-area:1/1/-1/-1;z-index:1;position:sticky;top:0;max-height:var(--\\275sci-table-viewport-height)}:host>sci-scrollbar{position:absolute}:host>sci-scrollbar[direction=vscroll]{top:calc(anchor(--sci-table-body top) + 2px);right:calc(anchor(--sci-table-viewport right) + 2px);bottom:calc(anchor(--sci-table-viewport bottom) + 2px)}:host>sci-scrollbar[direction=hscroll]{left:calc(anchor(--sci-table-viewport left) + 2px);bottom:calc(anchor(--sci-table-viewport bottom) + 1px);right:calc(anchor(--sci-table-viewport right) + 2px)}@container style(--\\275sci-table-resizing: true){:host>sci-scrollbar{pointer-events:none}}:host>sci-throbber.loading-indicator{--sci-throbber-size: 16px;position:absolute;top:calc(anchor(--sci-table-viewport top) + .5em);right:calc(anchor(--sci-table-viewport right) + .5em)}:host>div.synthetic{position:absolute;pointer-events:none;visibility:hidden}:host>div.synthetic.item-size{height:var(--sci-table-row-height)}:host>div.synthetic.cell-padding{width:var(--sci-table-cell-padding-inline)}\n"] }]
|
|
2314
2716
|
}], ctorParameters: () => [], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: true }] }], table: [{ type: i0.Input, args: [{ isSignal: true, alias: "table", required: true }] }], primaryAction: [{ type: i0.Output, args: ["primaryAction"] }], _viewport: [{ type: i0.ViewChild, args: [i0.forwardRef(() => SciTableViewportComponent), { ...{ read: ElementRef }, isSignal: true }] }], _viewportClient: [{ type: i0.ViewChild, args: [i0.forwardRef(() => SciTableGridComponent), { ...{ read: ElementRef }, isSignal: true }] }], _tableHeader: [{ type: i0.ViewChild, args: [i0.forwardRef(() => SciTableHeaderComponent), { ...{ read: ElementRef }, isSignal: true }] }], _tableBody: [{ type: i0.ViewChild, args: [i0.forwardRef(() => SciTableBodyComponent), { ...{ read: ElementRef }, isSignal: true }] }], _itemSizeSyntheticElement: [{ type: i0.ViewChild, args: ['item_size_synthetic_element', { isSignal: true }] }], _cellPaddingSyntheticElement: [{ type: i0.ViewChild, args: ['cell_padding_synthetic_element', { isSignal: true }] }], rows: [{ type: i0.ViewChildren, args: [i0.forwardRef(() => SciTableRowComponent), { isSignal: true }] }] } });
|
|
2315
2717
|
function provideSciTable() {
|
|
2316
2718
|
return {
|