@scion/components 22.1.0 → 22.3.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 +75 -5
- package/common/package.json +4 -0
- package/design/_theming.scss +25 -10
- package/design/components/_scion-component-dark-tokens.scss +153 -0
- package/design/components/_scion-component-light-tokens.scss +153 -0
- package/design/icons/_scion-icon-font.scss +50 -0
- package/design/themes/_scion-dark-theme.scss +2 -7
- package/design/themes/_scion-light-theme.scss +3 -8
- package/fesm2022/scion-components-common.mjs +251 -0
- package/fesm2022/scion-components-common.mjs.map +1 -0
- package/fesm2022/scion-components-dimension.mjs +7 -6
- package/fesm2022/scion-components-dimension.mjs.map +1 -1
- package/fesm2022/scion-components-icon.mjs +380 -0
- package/fesm2022/scion-components-icon.mjs.map +1 -0
- package/fesm2022/scion-components-menu.mjs +3271 -0
- package/fesm2022/scion-components-menu.mjs.map +1 -0
- package/fesm2022/scion-components-sashbox.mjs +21 -21
- package/fesm2022/scion-components-sashbox.mjs.map +1 -1
- package/fesm2022/scion-components-splitter.mjs +16 -13
- package/fesm2022/scion-components-splitter.mjs.map +1 -1
- package/fesm2022/scion-components-table.mjs +2265 -0
- package/fesm2022/scion-components-table.mjs.map +1 -0
- package/fesm2022/scion-components-text.mjs +322 -0
- package/fesm2022/scion-components-text.mjs.map +1 -0
- package/fesm2022/scion-components-throbber.mjs +15 -15
- package/fesm2022/scion-components-throbber.mjs.map +1 -1
- package/fesm2022/scion-components-viewport.mjs +142 -125
- package/fesm2022/scion-components-viewport.mjs.map +1 -1
- package/icon/package.json +4 -0
- package/menu/package.json +4 -0
- package/package.json +22 -2
- package/table/package.json +4 -0
- package/text/package.json +4 -0
- package/types/scion-components-common.d.ts +185 -0
- package/types/scion-components-icon.d.ts +146 -0
- package/types/scion-components-menu.d.ts +1922 -0
- package/types/scion-components-sashbox.d.ts +4 -2
- package/types/scion-components-splitter.d.ts +4 -3
- package/types/scion-components-table.d.ts +577 -0
- package/types/scion-components-text.d.ts +131 -0
- package/types/scion-components-viewport.d.ts +32 -39
- package/viewport/scrollbar/_scrollbar.scss +4 -4
- package/design/components/_scion-component-tokens.scss +0 -48
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, DOCUMENT, NgZone, Injectable, input, ElementRef, Renderer2, effect, untracked, Directive, DestroyRef, viewChild,
|
|
3
|
-
import {
|
|
2
|
+
import { inject, DOCUMENT, NgZone, Injectable, input, ElementRef, Renderer2, computed, effect, untracked, Directive, DestroyRef, viewChild, signal, Component, output, ChangeDetectionStrategy, ViewEncapsulation } from '@angular/core';
|
|
3
|
+
import { coerceElement } from '@angular/cdk/coercion';
|
|
4
|
+
import { fromEvent, race, tap, merge, finalize, timer, exhaustMap, of, concatWith, mergeWith, switchMap as switchMap$1, concat, map as map$1 } from 'rxjs';
|
|
4
5
|
import { debounceTime, startWith, map, distinctUntilChanged, takeUntil, withLatestFrom, switchMap } from 'rxjs/operators';
|
|
5
|
-
import { toSignal, takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
6
|
+
import { toSignal, takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
|
|
6
7
|
import { subscribeIn } from '@scion/toolkit/operators';
|
|
7
|
-
import { coerceElement } from '@angular/cdk/coercion';
|
|
8
8
|
import { fromResize$, fromMutation$ } from '@scion/toolkit/observable';
|
|
9
|
+
import { isBetween, clamp } from '@scion/toolkit/util';
|
|
9
10
|
import { CdkScrollable } from '@angular/cdk/scrolling';
|
|
10
11
|
|
|
11
12
|
/*
|
|
12
|
-
* Copyright (c) 2018-
|
|
13
|
+
* Copyright (c) 2018-2026 Swiss Federal Railways
|
|
13
14
|
*
|
|
14
15
|
* This program and the accompanying materials are made
|
|
15
16
|
* available under the terms of the Eclipse Public License 2.0
|
|
@@ -17,25 +18,27 @@ import { CdkScrollable } from '@angular/cdk/scrolling';
|
|
|
17
18
|
*
|
|
18
19
|
* SPDX-License-Identifier: EPL-2.0
|
|
19
20
|
*/
|
|
20
|
-
/**
|
|
21
|
-
|
|
22
|
-
*/
|
|
23
|
-
class SciNativeScrollbarTrackSizeProvider {
|
|
21
|
+
/** @inheritDoc */
|
|
22
|
+
class ɵSciNativeScrollbarTrackSizeProvider {
|
|
24
23
|
_document = inject(DOCUMENT);
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
24
|
+
/** @inheritDoc */
|
|
25
|
+
trackSize = this.computeNativeScrollbarTrackSize();
|
|
26
|
+
computeNativeScrollbarTrackSize() {
|
|
27
|
+
// We compute the size of the native scrollbar track when the browser fires the onresize window event.
|
|
28
|
+
// This event is also fired on page zoom or when displaying a hidden document. Hidden documents do not have
|
|
29
|
+
// a scrollbar track size until being displayed, e.g., after showing hidden iframes.
|
|
30
|
+
const zone = inject(NgZone);
|
|
31
|
+
const trackSize$ = fromEvent(window, 'resize')
|
|
32
|
+
.pipe(subscribeIn(fn => zone.runOutsideAngular(fn)), debounceTime(5), startWith(null), // trigger the initial computation
|
|
33
|
+
map(() => this.calculateTrackSize()), distinctUntilChanged((t1, t2) => t1?.hScrollbarTrackHeight === t2?.hScrollbarTrackHeight && t1?.vScrollbarTrackWidth === t2?.vScrollbarTrackWidth));
|
|
34
|
+
return toSignal(trackSize$, { initialValue: null });
|
|
32
35
|
}
|
|
33
36
|
/**
|
|
34
37
|
* Computes the native scrollbar track size.
|
|
35
38
|
*
|
|
36
39
|
* @returns native track size, or `null` if the native scrollbars sit on top of the content.
|
|
37
40
|
*/
|
|
38
|
-
|
|
41
|
+
calculateTrackSize() {
|
|
39
42
|
// Create temporary viewport and viewport client with native scrollbars to compute the scrolltrack width.
|
|
40
43
|
const viewportDiv = this._document.createElement('div');
|
|
41
44
|
setStyle(viewportDiv, {
|
|
@@ -68,22 +71,12 @@ class SciNativeScrollbarTrackSizeProvider {
|
|
|
68
71
|
}
|
|
69
72
|
return trackSize;
|
|
70
73
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
// This event is also fired on page zoom or when displaying a hidden document. Hidden documents do not have
|
|
74
|
-
// a scrollbar track size until being displayed, e.g., after showing hidden iframes.
|
|
75
|
-
const trackSize$ = fromEvent(window, 'resize')
|
|
76
|
-
.pipe(subscribeIn(fn => this._zone.runOutsideAngular(fn)), debounceTime(5), startWith(null), // trigger the initial computation
|
|
77
|
-
map(() => this.computeTrackSize()), distinctUntilChanged((t1, t2) => t1?.hScrollbarTrackHeight === t2?.hScrollbarTrackHeight && t1?.vScrollbarTrackWidth === t2?.vScrollbarTrackWidth));
|
|
78
|
-
return toSignal(trackSize$, { initialValue: null });
|
|
79
|
-
}
|
|
80
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: SciNativeScrollbarTrackSizeProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
81
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: SciNativeScrollbarTrackSizeProvider, providedIn: 'root' });
|
|
74
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: ɵSciNativeScrollbarTrackSizeProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
75
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: ɵSciNativeScrollbarTrackSizeProvider });
|
|
82
76
|
}
|
|
83
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
84
|
-
type: Injectable
|
|
85
|
-
|
|
86
|
-
}], ctorParameters: () => [] });
|
|
77
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: ɵSciNativeScrollbarTrackSizeProvider, decorators: [{
|
|
78
|
+
type: Injectable
|
|
79
|
+
}] });
|
|
87
80
|
/**
|
|
88
81
|
* Applies the given style(s) to the given element.
|
|
89
82
|
*
|
|
@@ -96,6 +89,27 @@ function setStyle(element, styles) {
|
|
|
96
89
|
Object.entries(styles).forEach(([name, value]) => element.style.setProperty(name, value));
|
|
97
90
|
}
|
|
98
91
|
|
|
92
|
+
/*
|
|
93
|
+
* Copyright (c) 2018-2026 Swiss Federal Railways
|
|
94
|
+
*
|
|
95
|
+
* This program and the accompanying materials are made
|
|
96
|
+
* available under the terms of the Eclipse Public License 2.0
|
|
97
|
+
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
98
|
+
*
|
|
99
|
+
* SPDX-License-Identifier: EPL-2.0
|
|
100
|
+
*/
|
|
101
|
+
/**
|
|
102
|
+
* Provides the native scrollbar tracksize.
|
|
103
|
+
*/
|
|
104
|
+
class SciNativeScrollbarTrackSizeProvider {
|
|
105
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciNativeScrollbarTrackSizeProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
106
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciNativeScrollbarTrackSizeProvider, providedIn: 'root', useClass: ɵSciNativeScrollbarTrackSizeProvider });
|
|
107
|
+
}
|
|
108
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciNativeScrollbarTrackSizeProvider, decorators: [{
|
|
109
|
+
type: Injectable,
|
|
110
|
+
args: [{ providedIn: 'root', useClass: ɵSciNativeScrollbarTrackSizeProvider }]
|
|
111
|
+
}] });
|
|
112
|
+
|
|
99
113
|
/*
|
|
100
114
|
* Copyright (c) 2018-2019 Swiss Federal Railways
|
|
101
115
|
*
|
|
@@ -115,16 +129,37 @@ function setStyle(element, styles) {
|
|
|
115
129
|
* This directive expects its host element to be the only child in document flow in its parent DOM element. It makes the host element
|
|
116
130
|
* fill up the entire space (width and height set to 100%). The parent element must have its CSS `overflow` property set to `hidden`
|
|
117
131
|
* to hide the pushed out native scrollbars.
|
|
132
|
+
*
|
|
133
|
+
* This directive provides the `isNativeScrollbarCropped` signal, which indicates whether native scrollbars are pushed out of the viewport element.
|
|
134
|
+
* In templates, access it via the exported template reference variable `sciScrollable`.
|
|
135
|
+
*
|
|
136
|
+
* ```html
|
|
137
|
+
* <div sciScrollable #sciScrollable="sciScrollable" #viewport>
|
|
138
|
+
* content
|
|
139
|
+
* </div>
|
|
140
|
+
*
|
|
141
|
+
* <!-- Render scrollbars only if native scrollbars are pushed out of the viewport element. -->
|
|
142
|
+
* @if (sciScrollable.isNativeScrollbarCropped()) {
|
|
143
|
+
* <sci-scrollbar [viewport]="viewport" direction="vscroll"/>
|
|
144
|
+
* <sci-scrollbar [viewport]="viewport" direction="hscroll"/>
|
|
145
|
+
* }
|
|
146
|
+
* ```
|
|
118
147
|
*/
|
|
119
148
|
class SciScrollableDirective {
|
|
120
149
|
/**
|
|
121
150
|
* Controls whether to display native scrollbars.
|
|
151
|
+
*
|
|
122
152
|
* Has no effect if the native scrollbar sits on top of the content, e.g. in OS X.
|
|
123
153
|
*/
|
|
124
154
|
displayNativeScrollbar = input(false, { ...(ngDevMode ? { debugName: "displayNativeScrollbar" } : /* istanbul ignore next */ {}), alias: 'sciScrollableDisplayNativeScrollbar' });
|
|
125
155
|
_host = inject((ElementRef)).nativeElement;
|
|
126
156
|
_renderer = inject(Renderer2);
|
|
127
157
|
_nativeScrollbarTrackSizeProvider = inject(SciNativeScrollbarTrackSizeProvider);
|
|
158
|
+
/**
|
|
159
|
+
* Indicates whether native scrollbars are pushed out of the viewport element.
|
|
160
|
+
*/
|
|
161
|
+
isNativeScrollbarCropped = computed(() => !this.displayNativeScrollbar() && this._nativeScrollbarTrackSizeProvider.trackSize() !== null, /* @ts-ignore */
|
|
162
|
+
...(ngDevMode ? [{ debugName: "isNativeScrollbarCropped" }] : /* istanbul ignore next */ []));
|
|
128
163
|
constructor() {
|
|
129
164
|
this.controlDisplayOfNativeScrollbar();
|
|
130
165
|
}
|
|
@@ -133,14 +168,9 @@ class SciScrollableDirective {
|
|
|
133
168
|
*/
|
|
134
169
|
controlDisplayOfNativeScrollbar() {
|
|
135
170
|
effect(() => {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
untracked(() => this.
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
const nativeScrollbarTrackSize = this._nativeScrollbarTrackSizeProvider.trackSize();
|
|
142
|
-
if (nativeScrollbarTrackSize) {
|
|
143
|
-
untracked(() => this.shiftNativeScrollbars(nativeScrollbarTrackSize));
|
|
171
|
+
if (this.isNativeScrollbarCropped()) {
|
|
172
|
+
const trackSize = this._nativeScrollbarTrackSizeProvider.trackSize();
|
|
173
|
+
untracked(() => this.shiftNativeScrollbars(trackSize));
|
|
144
174
|
}
|
|
145
175
|
else {
|
|
146
176
|
untracked(() => this.useNativeScrollbars());
|
|
@@ -162,24 +192,27 @@ class SciScrollableDirective {
|
|
|
162
192
|
/**
|
|
163
193
|
* Shifts the native scrollbars out of the visible viewport area.
|
|
164
194
|
*/
|
|
165
|
-
shiftNativeScrollbars(
|
|
195
|
+
shiftNativeScrollbars(trackSize) {
|
|
166
196
|
this.setStyle(this._host, {
|
|
167
197
|
overflow: 'scroll',
|
|
168
|
-
width: `calc(100% + ${
|
|
169
|
-
height: `calc(100% + ${
|
|
170
|
-
marginRight: `-${
|
|
171
|
-
marginBottom: `-${
|
|
198
|
+
width: `calc(100% + ${trackSize.vScrollbarTrackWidth}px`,
|
|
199
|
+
height: `calc(100% + ${trackSize.hScrollbarTrackHeight}px`,
|
|
200
|
+
marginRight: `-${trackSize.vScrollbarTrackWidth}px`,
|
|
201
|
+
marginBottom: `-${trackSize.hScrollbarTrackHeight}px`,
|
|
172
202
|
});
|
|
173
203
|
}
|
|
174
204
|
setStyle(element, style) {
|
|
175
205
|
Object.keys(style).forEach(key => this._renderer.setStyle(element, key, style[key]));
|
|
176
206
|
}
|
|
177
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
178
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.
|
|
207
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciScrollableDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
208
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.7", type: SciScrollableDirective, isStandalone: true, selector: "[sciScrollable]", inputs: { displayNativeScrollbar: { classPropertyName: "displayNativeScrollbar", publicName: "sciScrollableDisplayNativeScrollbar", isSignal: true, isRequired: false, transformFunction: null } }, exportAs: ["sciScrollable"], ngImport: i0 });
|
|
179
209
|
}
|
|
180
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
210
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciScrollableDirective, decorators: [{
|
|
181
211
|
type: Directive,
|
|
182
|
-
args: [{
|
|
212
|
+
args: [{
|
|
213
|
+
selector: '[sciScrollable]',
|
|
214
|
+
exportAs: 'sciScrollable',
|
|
215
|
+
}]
|
|
183
216
|
}], ctorParameters: () => [], propDecorators: { displayNativeScrollbar: [{ type: i0.Input, args: [{ isSignal: true, alias: "sciScrollableDisplayNativeScrollbar", required: false }] }] } });
|
|
184
217
|
|
|
185
218
|
/*
|
|
@@ -216,16 +249,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
|
|
|
216
249
|
* ```
|
|
217
250
|
*/
|
|
218
251
|
class SciScrollbarComponent {
|
|
219
|
-
/**
|
|
220
|
-
* Timeout for debouncing viewport resize events that trigger the scroll position computation.
|
|
221
|
-
*
|
|
222
|
-
* Debouncing is particularly important in the context of Angular animations, since they continuously
|
|
223
|
-
* trigger resize events. Debouncing prevents the scrollbar from flickering, for example, when the user
|
|
224
|
-
* expands a panel that contains a viewport.
|
|
225
|
-
*
|
|
226
|
-
* @internal
|
|
227
|
-
*/
|
|
228
|
-
static VIEWPORT_RESIZE_DEBOUNCE_TIME = 50;
|
|
229
252
|
/**
|
|
230
253
|
* Specifies the direction of the scrollbar. Defaults to a vertical scrollbar.
|
|
231
254
|
*/
|
|
@@ -240,7 +263,8 @@ class SciScrollbarComponent {
|
|
|
240
263
|
_document = inject(DOCUMENT);
|
|
241
264
|
_zone = inject(NgZone);
|
|
242
265
|
_destroyRef = inject(DestroyRef);
|
|
243
|
-
_thumbElement = viewChild.required('thumb_handle'
|
|
266
|
+
_thumbElement = viewChild.required('thumb_handle', /* @ts-ignore */
|
|
267
|
+
...(ngDevMode ? [{ debugName: "_thumbElement" }] : /* istanbul ignore next */ []));
|
|
244
268
|
vertical = computed(() => this.direction() === 'vscroll', /* @ts-ignore */
|
|
245
269
|
...(ngDevMode ? [{ debugName: "vertical" }] : /* istanbul ignore next */ []));
|
|
246
270
|
horizontal = computed(() => !this.vertical(), /* @ts-ignore */
|
|
@@ -277,9 +301,10 @@ class SciScrollbarComponent {
|
|
|
277
301
|
this.scrolling.set(true);
|
|
278
302
|
// Prevent text selection during drag.
|
|
279
303
|
mousedownEvent.preventDefault();
|
|
304
|
+
// Calculate screen offset to convert screen coordinates into client coordinates, required for `sci-mousemove` events which originate from other documents (iframes).
|
|
305
|
+
const { screenOffsetX, screenOffsetY } = calculateScreenOffset(mousedownEvent);
|
|
280
306
|
// Memoize offset where thumb was clicked.
|
|
281
|
-
const
|
|
282
|
-
const thumbStartOffset = (this.vertical() ? mousedownEvent.pageY : mousedownEvent.pageX) - thumbStartPosition;
|
|
307
|
+
const thumbStartOffset = this.vertical() ? mousedownEvent.offsetY : mousedownEvent.offsetX;
|
|
283
308
|
// Stop scrolling when releasing the mouse. Handle the event in the capture phase and stop propagation to not close a potential overlay when releasing the mouse outside the overlay.
|
|
284
309
|
const mouseUp$ = race(fromEvent(this._document, 'mouseup', { capture: true, once: true }), fromEvent(this._document, 'sci-mouseup', { once: true }))
|
|
285
310
|
.pipe(tap(mouseupEvent => mouseupEvent.stopPropagation()));
|
|
@@ -291,7 +316,7 @@ class SciScrollbarComponent {
|
|
|
291
316
|
// Prevent user agent scrolling while during drag.
|
|
292
317
|
mousemoveEvent.preventDefault();
|
|
293
318
|
// Calculate new thumb position.
|
|
294
|
-
const pointerPosition = this.vertical() ? mousemoveEvent.
|
|
319
|
+
const pointerPosition = this.vertical() ? mousemoveEvent.screenY - screenOffsetY : mousemoveEvent.screenX - screenOffsetX;
|
|
295
320
|
this.scrollViewport(pointerPosition - thumbStartOffset);
|
|
296
321
|
});
|
|
297
322
|
}
|
|
@@ -301,13 +326,15 @@ class SciScrollbarComponent {
|
|
|
301
326
|
* Scrolls in discrete steps to the pointer, then switches to regular scrolling until releasing the mouse.
|
|
302
327
|
*/
|
|
303
328
|
onScrollTrackMouseDown(event) {
|
|
329
|
+
this.scrolling.set(true);
|
|
330
|
+
// Prevent text selection during drag.
|
|
331
|
+
event.preventDefault();
|
|
304
332
|
const mouseMove$ = merge(fromEvent(this._document, 'mousemove'), fromEvent(this._document, 'sci-mousemove'));
|
|
305
|
-
//
|
|
333
|
+
// Handle the event in the capture phase and stop propagation to not close a potential overlay when releasing the mouse outside the overlay.
|
|
306
334
|
const mouseUp$ = race(fromEvent(this._document, 'mouseup', { capture: true, once: true }), fromEvent(this._document, 'sci-mouseup', { once: true }))
|
|
307
335
|
.pipe(tap(mouseupEvent => mouseupEvent.stopPropagation()));
|
|
308
|
-
//
|
|
309
|
-
event
|
|
310
|
-
this.scrolling.set(true);
|
|
336
|
+
// Calculate screen offset to convert screen coordinates into client coordinates, required for `sci-mousemove` events which originate from other documents (iframes).
|
|
337
|
+
const { screenOffsetX, screenOffsetY } = calculateScreenOffset(event);
|
|
311
338
|
// Scroll in discrete steps to the pointer position, then switch to regular scrolling.
|
|
312
339
|
timer(250, 50)
|
|
313
340
|
.pipe(
|
|
@@ -315,7 +342,7 @@ class SciScrollbarComponent {
|
|
|
315
342
|
withLatestFrom(mouseMove$.pipe(startWith(event)), (_tick, event) => event),
|
|
316
343
|
// Scroll immediately on initial click.
|
|
317
344
|
startWith(event), subscribeIn(fn => this._zone.runOutsideAngular(fn)), exhaustMap(event => {
|
|
318
|
-
const pointerPosition = this.vertical() ? event.
|
|
345
|
+
const pointerPosition = this.vertical() ? event.screenY - screenOffsetY : event.screenX - screenOffsetX;
|
|
319
346
|
const [thumbStartPosition, thumbEndPosition] = this.thumbPosition();
|
|
320
347
|
const thumbSize = thumbEndPosition - thumbStartPosition;
|
|
321
348
|
// Step scroll until the pointer hits the thumb.
|
|
@@ -325,7 +352,7 @@ class SciScrollbarComponent {
|
|
|
325
352
|
}
|
|
326
353
|
// Switch to "smooth scrolling" following the pointer.
|
|
327
354
|
return of(event)
|
|
328
|
-
.pipe(concatWith(mouseMove$), map(event => (this.vertical() ? event.
|
|
355
|
+
.pipe(concatWith(mouseMove$), map(event => (this.vertical() ? event.screenY - screenOffsetY : event.screenX - screenOffsetX) - (thumbSize / 2)));
|
|
329
356
|
}),
|
|
330
357
|
// Stop on mouse release.
|
|
331
358
|
takeUntil(mouseUp$), finalize(() => this.scrolling.set(false)))
|
|
@@ -342,8 +369,10 @@ class SciScrollbarComponent {
|
|
|
342
369
|
const viewport = this.viewport();
|
|
343
370
|
untracked(() => {
|
|
344
371
|
const subscription = viewportScroll$(viewport)
|
|
345
|
-
.pipe(mergeWith(viewportSize$(viewport
|
|
346
|
-
.subscribe(() =>
|
|
372
|
+
.pipe(mergeWith(viewportSize$(viewport)), mergeWith(viewportClientSize$(viewport)), subscribeIn(fn => this._zone.runOutsideAngular(fn)))
|
|
373
|
+
.subscribe(() => {
|
|
374
|
+
this.renderScrollPosition();
|
|
375
|
+
});
|
|
347
376
|
onCleanup(() => subscription.unsubscribe());
|
|
348
377
|
});
|
|
349
378
|
});
|
|
@@ -351,7 +380,7 @@ class SciScrollbarComponent {
|
|
|
351
380
|
/**
|
|
352
381
|
* Moves the scrollbar thumb to the specified position, scrolling the viewport accordingly.
|
|
353
382
|
*
|
|
354
|
-
* The thumb position must be given in
|
|
383
|
+
* The thumb position must be given in client coordinates (relative to the top-left corner of the page viewport).
|
|
355
384
|
*/
|
|
356
385
|
scrollViewport(thumbPosition) {
|
|
357
386
|
const [scrollbarComponentStartPosition] = this.scrollbarComponentPosition();
|
|
@@ -366,14 +395,14 @@ class SciScrollbarComponent {
|
|
|
366
395
|
}
|
|
367
396
|
}
|
|
368
397
|
/**
|
|
369
|
-
* Returns the position of this component in
|
|
398
|
+
* Returns the position of this component in client coordinates.
|
|
370
399
|
*
|
|
371
|
-
* Returned coordinates are relative to the top-left corner of the
|
|
400
|
+
* Returned coordinates are relative to the top-left corner of the page viewport.
|
|
372
401
|
* Depending on the scrollbar orientation, returned coordinates are `[top, bottom]` or `[left, right]`.
|
|
373
402
|
*/
|
|
374
403
|
scrollbarComponentPosition() {
|
|
375
404
|
const boundingBox = this._host.getBoundingClientRect();
|
|
376
|
-
return this.vertical() ? [boundingBox.top
|
|
405
|
+
return this.vertical() ? [boundingBox.top, boundingBox.bottom] : [boundingBox.left, boundingBox.right];
|
|
377
406
|
}
|
|
378
407
|
/**
|
|
379
408
|
* Returns the size of the viewport in pixels.
|
|
@@ -411,14 +440,14 @@ class SciScrollbarComponent {
|
|
|
411
440
|
return this.vertical() ? thumbElement.offsetHeight : thumbElement.offsetWidth;
|
|
412
441
|
}
|
|
413
442
|
/**
|
|
414
|
-
* Returns the current thumb position in
|
|
443
|
+
* Returns the current thumb position in client coordinates.
|
|
415
444
|
*
|
|
416
|
-
* Returned coordinates are relative to the top-left corner of the
|
|
445
|
+
* Returned coordinates are relative to the top-left corner of the page viewport.
|
|
417
446
|
* Depending on the scrollbar orientation, returned coordinates are `[top, bottom]` or `[left, right]`.
|
|
418
447
|
*/
|
|
419
448
|
thumbPosition() {
|
|
420
449
|
const boundingBox = this._thumbElement().nativeElement.getBoundingClientRect();
|
|
421
|
-
return this.vertical() ? [boundingBox.top
|
|
450
|
+
return this.vertical() ? [boundingBox.top, boundingBox.bottom] : [boundingBox.left, boundingBox.right];
|
|
422
451
|
}
|
|
423
452
|
/**
|
|
424
453
|
* Returns the size of the scrollbar track in pixels.
|
|
@@ -428,10 +457,10 @@ class SciScrollbarComponent {
|
|
|
428
457
|
trackSize() {
|
|
429
458
|
return this.vertical() ? this._host.clientHeight : this._host.clientWidth;
|
|
430
459
|
}
|
|
431
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
432
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.
|
|
460
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciScrollbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
461
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.7", type: SciScrollbarComponent, isStandalone: true, selector: "sci-scrollbar", inputs: { direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null }, viewport: { classPropertyName: "viewport", publicName: "viewport", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "class.vertical": "vertical()", "class.horizontal": "horizontal()", "class.scrolling": "scrolling()", "class.overflow": "overflow()", "style.--\u0275sci-scrollbar-thumb-position-fr": "thumbPositionFr()", "style.--\u0275sci-scrollbar-thumb-size-fr": "thumbSizeFr()" } }, viewQueries: [{ propertyName: "_thumbElement", first: true, predicate: ["thumb_handle"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- scrolltrack for moving the viewport client upwards (paging) -->\n<div class=\"scrolltrack\" (mousedown)=\"onScrollTrackMouseDown($event)\"></div>\n\n<!-- scrollthumb -->\n<div #thumb_handle\n class=\"thumb-handle\"\n [class.vertical]=\"vertical()\"\n [class.horizontal]=\"horizontal()\"\n (mousedown)=\"onThumbMouseDown($event)\">\n <div class=\"thumb e2e-thumb\"\n [class.vertical]=\"vertical()\"\n [class.horizontal]=\"horizontal()\">\n </div>\n</div>\n\n<!-- scrolltrack for moving the viewport client downwards (paging) -->\n<div class=\"scrolltrack\" (mousedown)=\"onScrollTrackMouseDown($event)\"></div>\n", styles: ["@charset \"UTF-8\";:host{display:flex;box-sizing:border-box;transition-duration:1s;transition-property:opacity;transition-timing-function:ease-out;--\\275sci-scrollbar-thumb-position-fr: 0;--\\275sci-scrollbar-thumb-size-fr: 0}:host.vertical{flex-direction:column;width:8px}:host.horizontal{flex-direction:row;height:8px}:host>div.scrolltrack:first-child{flex-grow:var(--\\275sci-scrollbar-thumb-position-fr)}:host:not(.overflow){display:none}:host:hover>div.thumb-handle>div.thumb,:host.scrolling>div.thumb-handle>div.thumb{background-color:var(--sci-scrollbar-color);opacity:.75}:host:hover>div.thumb-handle>div.thumb.vertical,:host.scrolling>div.thumb-handle>div.thumb.vertical{width:100%}:host:hover>div.thumb-handle>div.thumb.horizontal,:host.scrolling>div.thumb-handle>div.thumb.horizontal{height:100%}:host>div.thumb-handle{display:flex;flex-grow:var(--\\275sci-scrollbar-thumb-size-fr);align-items:center}:host>div.thumb-handle.vertical{flex-direction:column;min-height:20px}:host>div.thumb-handle.horizontal{flex-direction:row;min-width:20px}:host>div.thumb-handle>div.thumb{flex:auto;border-radius:4px;background-color:var(--sci-scrollbar-color);opacity:.4;transition-duration:125ms;transition-property:width,height;transition-timing-function:ease-out}:host>div.thumb-handle>div.thumb.vertical{width:60%}:host>div.thumb-handle>div.thumb.horizontal{height:60%}:host>div.scrolltrack:last-child{flex-grow:calc(1 - (var(--\\275sci-scrollbar-thumb-position-fr) + var(--\\275sci-scrollbar-thumb-size-fr)))}\n"] });
|
|
433
462
|
}
|
|
434
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
463
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciScrollbarComponent, decorators: [{
|
|
435
464
|
type: Component,
|
|
436
465
|
args: [{ selector: 'sci-scrollbar', host: {
|
|
437
466
|
'[class.vertical]': 'vertical()',
|
|
@@ -451,27 +480,18 @@ function viewportScroll$(viewport) {
|
|
|
451
480
|
/**
|
|
452
481
|
* Emits on subscription, and then each time the size of the viewport changes.
|
|
453
482
|
*/
|
|
454
|
-
function viewportSize$(viewport
|
|
455
|
-
return fromResize$(viewport)
|
|
456
|
-
.pipe(
|
|
457
|
-
// Debouncing is particularly important in the context of Angular animations, since they continuously
|
|
458
|
-
// trigger resize events. Debouncing prevents the scrollbar from flickering, for example, when the user
|
|
459
|
-
// expands a panel that contains a viewport.
|
|
460
|
-
debounceTime(options.debounceTime), map(() => undefined));
|
|
483
|
+
function viewportSize$(viewport) {
|
|
484
|
+
return fromResize$(viewport).pipe(map(() => undefined));
|
|
461
485
|
}
|
|
462
486
|
/**
|
|
463
487
|
* Emits on subscription, and then each time the size or style property of the viewport client changes.
|
|
464
488
|
*/
|
|
465
|
-
function viewportClientSize$(viewport
|
|
489
|
+
function viewportClientSize$(viewport) {
|
|
466
490
|
return children$(viewport)
|
|
467
491
|
.pipe(switchMap(children => merge(...children.map(child => merge(fromResize$(child),
|
|
468
492
|
// Observe style mutations since some transformations change the scroll position without necessarily triggering a dimension change,
|
|
469
493
|
// e.g., `scale` or `translate` used by some virtual scroll implementations
|
|
470
|
-
fromMutation$(child, { subtree: false, childList: false, attributeFilter: ['style'] }))))),
|
|
471
|
-
// Debouncing is particularly important in the context of Angular animations, since they continuously
|
|
472
|
-
// trigger resize events. Debouncing prevents the scrollbar from flickering, for example, when the user
|
|
473
|
-
// expands a panel that contains a viewport.
|
|
474
|
-
debounceTime(options.debounceTime), map(() => undefined));
|
|
494
|
+
fromMutation$(child, { subtree: false, childList: false, attributeFilter: ['style'] }))))), map(() => undefined));
|
|
475
495
|
}
|
|
476
496
|
/**
|
|
477
497
|
* Emits the children of the passed element, and then each time child elements are added or removed.
|
|
@@ -485,16 +505,18 @@ function children$(element) {
|
|
|
485
505
|
.filter((child) => child instanceof HTMLElement)));
|
|
486
506
|
}
|
|
487
507
|
/**
|
|
488
|
-
*
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
* Returns whether the value is between the specified range (inclusive).
|
|
508
|
+
* Calculates the distance between the top-left corner of the screen (monitor) and the top-left corner of the page viewport of this document.
|
|
509
|
+
*
|
|
510
|
+
* Use to convert screen coordinates from `sci-mousemove` and `sci-mouseup` events into client coordinates relative to the page viewport of the current document.
|
|
511
|
+
*
|
|
512
|
+
* The `sci-mousemove` and `sci-mouseup` events originate from other documents (iframes) and do not include client coordinates. Even if they did, they would be
|
|
513
|
+
* relative to the source document, not the current one.
|
|
495
514
|
*/
|
|
496
|
-
function
|
|
497
|
-
return
|
|
515
|
+
function calculateScreenOffset(mousedownEvent) {
|
|
516
|
+
return {
|
|
517
|
+
screenOffsetX: mousedownEvent.screenX - mousedownEvent.clientX,
|
|
518
|
+
screenOffsetY: mousedownEvent.screenY - mousedownEvent.clientY,
|
|
519
|
+
};
|
|
498
520
|
}
|
|
499
521
|
|
|
500
522
|
/*
|
|
@@ -584,12 +606,14 @@ class SciViewportComponent {
|
|
|
584
606
|
*/
|
|
585
607
|
scroll = output(); // eslint-disable-line @angular-eslint/no-output-native
|
|
586
608
|
_host = inject(ElementRef).nativeElement;
|
|
587
|
-
_viewport = viewChild.required('viewport'
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
609
|
+
_viewport = viewChild.required('viewport', /* @ts-ignore */
|
|
610
|
+
...(ngDevMode ? [{ debugName: "_viewport" }] : /* istanbul ignore next */ []));
|
|
611
|
+
_viewportClient = viewChild.required('viewport_client', /* @ts-ignore */
|
|
612
|
+
...(ngDevMode ? [{ debugName: "_viewportClient" }] : /* istanbul ignore next */ []));
|
|
613
|
+
/**
|
|
614
|
+
* Indicates whether currently scrolling the viewport.
|
|
615
|
+
*/
|
|
616
|
+
scrolling = this.computeScrolling(this._viewport);
|
|
593
617
|
focus() {
|
|
594
618
|
this.viewportElement.focus();
|
|
595
619
|
}
|
|
@@ -735,24 +759,17 @@ class SciViewportComponent {
|
|
|
735
759
|
return offset;
|
|
736
760
|
}
|
|
737
761
|
/**
|
|
738
|
-
*
|
|
762
|
+
* Computes whether currently scrolling the viewport.
|
|
739
763
|
*/
|
|
740
|
-
|
|
764
|
+
computeScrolling(viewport) {
|
|
741
765
|
const zone = inject(NgZone);
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
untracked(() => {
|
|
745
|
-
const subscription = fromEvent(viewport.nativeElement, 'scroll')
|
|
746
|
-
.pipe(subscribeIn(fn => zone.runOutsideAngular(fn)))
|
|
747
|
-
.subscribe(event => this.scroll.emit(event));
|
|
748
|
-
onCleanup(() => subscription.unsubscribe());
|
|
749
|
-
});
|
|
750
|
-
});
|
|
766
|
+
return toSignal(toObservable(viewport)
|
|
767
|
+
.pipe(switchMap$1(viewport => fromEvent(viewport.nativeElement, 'scroll', { passive: true }).pipe(subscribeIn(fn => zone.runOutsideAngular(fn)))), tap(event => this.scroll.emit(event)), switchMap$1(() => concat(of(true), timer(150).pipe(map$1(() => false))))), { initialValue: false });
|
|
751
768
|
}
|
|
752
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
753
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.
|
|
769
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciViewportComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
770
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: SciViewportComponent, isStandalone: true, selector: "sci-viewport", inputs: { scrollbarStyle: { classPropertyName: "scrollbarStyle", publicName: "scrollbarStyle", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { scroll: "scroll" }, host: { listeners: { "focus": "focus()" } }, viewQueries: [{ propertyName: "_viewport", first: true, predicate: ["viewport"], descendants: true, isSignal: true }, { propertyName: "_viewportClient", first: true, predicate: ["viewport_client"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- viewport and viewport client -->\n<div #viewport\n class=\"viewport\"\n tabindex=\"-1\"\n sciScrollable [sciScrollableDisplayNativeScrollbar]=\"scrollbarStyle() === 'native'\" #sciScrollable=\"sciScrollable\"\n cdkScrollable>\n <div #viewport_client class=\"viewport-client\" part=\"content\">\n <slot></slot>\n </div>\n</div>\n\n<!-- render emulated scrollbars which sit on-top -->\n@if (scrollbarStyle() === 'on-top' && sciScrollable.isNativeScrollbarCropped()) {\n <sci-scrollbar direction=\"vscroll\" [viewport]=\"viewport\"/>\n <sci-scrollbar direction=\"hscroll\" [viewport]=\"viewport\"/>\n}\n", styles: [":host{display:grid;grid-template-columns:100%;grid-template-rows:100%;position:relative;overflow:hidden;outline:none}:host:is(:not(:hover):not(:active),:host(:not(:hover):not(:active))) sci-scrollbar:not(.scrolling){opacity:0}:host>div.viewport{display:grid;position:relative;outline:none;-webkit-overflow-scrolling:touch}:host>div.viewport>div.viewport-client{display:grid}:host>sci-scrollbar{--sci-scrollbar-color: var(--sci-viewport-scrollbar-color);position:absolute}:host>sci-scrollbar.vertical{top:2px;right:1px;bottom:2px}:host>sci-scrollbar.horizontal{left:2px;bottom:1px;right:2px}\n"], dependencies: [{ kind: "directive", type: SciScrollableDirective, selector: "[sciScrollable]", inputs: ["sciScrollableDisplayNativeScrollbar"], exportAs: ["sciScrollable"] }, { kind: "component", type: SciScrollbarComponent, selector: "sci-scrollbar", inputs: ["direction", "viewport"] }, { kind: "directive", type: CdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }], changeDetection: i0.ChangeDetectionStrategy.Eager, encapsulation: i0.ViewEncapsulation.ShadowDom });
|
|
754
771
|
}
|
|
755
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
772
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SciViewportComponent, decorators: [{
|
|
756
773
|
type: Component,
|
|
757
774
|
args: [{ selector: 'sci-viewport', encapsulation: ViewEncapsulation.ShadowDom, imports: [
|
|
758
775
|
SciScrollableDirective,
|
|
@@ -760,8 +777,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
|
|
|
760
777
|
CdkScrollable,
|
|
761
778
|
], changeDetection: ChangeDetectionStrategy.Eager, host: {
|
|
762
779
|
'(focus)': 'focus()',
|
|
763
|
-
}, template: "<!-- viewport and viewport client -->\n<div #viewport\n class=\"viewport\"\n tabindex=\"-1\"\n sciScrollable [sciScrollableDisplayNativeScrollbar]=\"scrollbarStyle() === 'native'\"\n cdkScrollable>\n <div #viewport_client class=\"viewport-client\" part=\"content\">\n <slot></slot>\n </div>\n</div>\n\n<!-- render emulated scrollbars which sit on-top -->\n@if (scrollbarStyle() === 'on-top' &&
|
|
764
|
-
}],
|
|
780
|
+
}, template: "<!-- viewport and viewport client -->\n<div #viewport\n class=\"viewport\"\n tabindex=\"-1\"\n sciScrollable [sciScrollableDisplayNativeScrollbar]=\"scrollbarStyle() === 'native'\" #sciScrollable=\"sciScrollable\"\n cdkScrollable>\n <div #viewport_client class=\"viewport-client\" part=\"content\">\n <slot></slot>\n </div>\n</div>\n\n<!-- render emulated scrollbars which sit on-top -->\n@if (scrollbarStyle() === 'on-top' && sciScrollable.isNativeScrollbarCropped()) {\n <sci-scrollbar direction=\"vscroll\" [viewport]=\"viewport\"/>\n <sci-scrollbar direction=\"hscroll\" [viewport]=\"viewport\"/>\n}\n", styles: [":host{display:grid;grid-template-columns:100%;grid-template-rows:100%;position:relative;overflow:hidden;outline:none}:host:is(:not(:hover):not(:active),:host(:not(:hover):not(:active))) sci-scrollbar:not(.scrolling){opacity:0}:host>div.viewport{display:grid;position:relative;outline:none;-webkit-overflow-scrolling:touch}:host>div.viewport>div.viewport-client{display:grid}:host>sci-scrollbar{--sci-scrollbar-color: var(--sci-viewport-scrollbar-color);position:absolute}:host>sci-scrollbar.vertical{top:2px;right:1px;bottom:2px}:host>sci-scrollbar.horizontal{left:2px;bottom:1px;right:2px}\n"] }]
|
|
781
|
+
}], propDecorators: { scrollbarStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollbarStyle", required: false }] }], scroll: [{ type: i0.Output, args: ["scroll"] }], _viewport: [{ type: i0.ViewChild, args: ['viewport', { isSignal: true }] }], _viewportClient: [{ type: i0.ViewChild, args: ['viewport_client', { isSignal: true }] }] } });
|
|
765
782
|
|
|
766
783
|
/*
|
|
767
784
|
* Copyright (c) 2018-2019 Swiss Federal Railways
|