@scion/components 22.0.0 → 22.2.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.
@@ -1,15 +1,15 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, DOCUMENT, NgZone, Injectable, input, ElementRef, Renderer2, effect, untracked, Directive, DestroyRef, viewChild, signal, computed, Component, output, ChangeDetectionStrategy, ViewEncapsulation } from '@angular/core';
3
- import { fromEvent, merge, mergeWith, timer, of } from 'rxjs';
4
- import { debounceTime, startWith, map, distinctUntilChanged, first, withLatestFrom, takeWhile, takeUntil, switchMap } from 'rxjs/operators';
5
- import { toSignal, takeUntilDestroyed } from '@angular/core/rxjs-interop';
6
- import { subscribeIn, filterArray } from '@scion/toolkit/operators';
2
+ import { inject, DOCUMENT, NgZone, Injectable, input, ElementRef, Renderer2, computed, effect, untracked, Directive, DestroyRef, viewChild, signal, Component, output, ChangeDetectionStrategy, ViewEncapsulation } from '@angular/core';
7
3
  import { coerceElement } from '@angular/cdk/coercion';
4
+ import { fromEvent, race, tap, merge, finalize, timer, exhaustMap, of, concatWith, mergeWith } from 'rxjs';
5
+ import { debounceTime, startWith, map, distinctUntilChanged, takeUntil, withLatestFrom, switchMap } from 'rxjs/operators';
6
+ import { toSignal, takeUntilDestroyed } from '@angular/core/rxjs-interop';
7
+ import { subscribeIn } from '@scion/toolkit/operators';
8
8
  import { fromResize$, fromMutation$ } from '@scion/toolkit/observable';
9
9
  import { CdkScrollable } from '@angular/cdk/scrolling';
10
10
 
11
11
  /*
12
- * Copyright (c) 2018-2024 Swiss Federal Railways
12
+ * Copyright (c) 2018-2026 Swiss Federal Railways
13
13
  *
14
14
  * This program and the accompanying materials are made
15
15
  * available under the terms of the Eclipse Public License 2.0
@@ -17,25 +17,27 @@ import { CdkScrollable } from '@angular/cdk/scrolling';
17
17
  *
18
18
  * SPDX-License-Identifier: EPL-2.0
19
19
  */
20
- /**
21
- * Provides the native scrollbar tracksize.
22
- */
23
- class SciNativeScrollbarTrackSizeProvider {
20
+ /** @inheritDoc */
21
+ class ɵSciNativeScrollbarTrackSizeProvider {
24
22
  _document = inject(DOCUMENT);
25
- _zone = inject(NgZone);
26
- /**
27
- * Provides the track size of the native scrollbar, or `null` if the native scrollbars sit on top of the content.
28
- */
29
- trackSize;
30
- constructor() {
31
- this.trackSize = this.createNativeScrollbarTrackSizeSignal();
23
+ /** @inheritDoc */
24
+ trackSize = this.computeNativeScrollbarTrackSize();
25
+ computeNativeScrollbarTrackSize() {
26
+ // We compute the size of the native scrollbar track when the browser fires the onresize window event.
27
+ // This event is also fired on page zoom or when displaying a hidden document. Hidden documents do not have
28
+ // a scrollbar track size until being displayed, e.g., after showing hidden iframes.
29
+ const zone = inject(NgZone);
30
+ const trackSize$ = fromEvent(window, 'resize')
31
+ .pipe(subscribeIn(fn => zone.runOutsideAngular(fn)), debounceTime(5), startWith(null), // trigger the initial computation
32
+ map(() => this.calculateTrackSize()), distinctUntilChanged((t1, t2) => t1?.hScrollbarTrackHeight === t2?.hScrollbarTrackHeight && t1?.vScrollbarTrackWidth === t2?.vScrollbarTrackWidth));
33
+ return toSignal(trackSize$, { initialValue: null });
32
34
  }
33
35
  /**
34
36
  * Computes the native scrollbar track size.
35
37
  *
36
38
  * @returns native track size, or `null` if the native scrollbars sit on top of the content.
37
39
  */
38
- computeTrackSize() {
40
+ calculateTrackSize() {
39
41
  // Create temporary viewport and viewport client with native scrollbars to compute the scrolltrack width.
40
42
  const viewportDiv = this._document.createElement('div');
41
43
  setStyle(viewportDiv, {
@@ -68,22 +70,12 @@ class SciNativeScrollbarTrackSizeProvider {
68
70
  }
69
71
  return trackSize;
70
72
  }
71
- createNativeScrollbarTrackSizeSignal() {
72
- // We compute the size of the native scrollbar track when the browser fires the onresize window event.
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' });
73
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: ɵSciNativeScrollbarTrackSizeProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
74
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: ɵSciNativeScrollbarTrackSizeProvider });
82
75
  }
83
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: SciNativeScrollbarTrackSizeProvider, decorators: [{
84
- type: Injectable,
85
- args: [{ providedIn: 'root' }]
86
- }], ctorParameters: () => [] });
76
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: ɵSciNativeScrollbarTrackSizeProvider, decorators: [{
77
+ type: Injectable
78
+ }] });
87
79
  /**
88
80
  * Applies the given style(s) to the given element.
89
81
  *
@@ -96,6 +88,27 @@ function setStyle(element, styles) {
96
88
  Object.entries(styles).forEach(([name, value]) => element.style.setProperty(name, value));
97
89
  }
98
90
 
91
+ /*
92
+ * Copyright (c) 2018-2026 Swiss Federal Railways
93
+ *
94
+ * This program and the accompanying materials are made
95
+ * available under the terms of the Eclipse Public License 2.0
96
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
97
+ *
98
+ * SPDX-License-Identifier: EPL-2.0
99
+ */
100
+ /**
101
+ * Provides the native scrollbar tracksize.
102
+ */
103
+ class SciNativeScrollbarTrackSizeProvider {
104
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: SciNativeScrollbarTrackSizeProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
105
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: SciNativeScrollbarTrackSizeProvider, providedIn: 'root', useClass: ɵSciNativeScrollbarTrackSizeProvider });
106
+ }
107
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: SciNativeScrollbarTrackSizeProvider, decorators: [{
108
+ type: Injectable,
109
+ args: [{ providedIn: 'root', useClass: ɵSciNativeScrollbarTrackSizeProvider }]
110
+ }] });
111
+
99
112
  /*
100
113
  * Copyright (c) 2018-2019 Swiss Federal Railways
101
114
  *
@@ -115,16 +128,37 @@ function setStyle(element, styles) {
115
128
  * 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
129
  * fill up the entire space (width and height set to 100%). The parent element must have its CSS `overflow` property set to `hidden`
117
130
  * to hide the pushed out native scrollbars.
131
+ *
132
+ * This directive provides the `isNativeScrollbarCropped` signal, which indicates whether native scrollbars are pushed out of the viewport element.
133
+ * In templates, access it via the exported template reference variable `sciScrollable`.
134
+ *
135
+ * ```html
136
+ * <div sciScrollable #sciScrollable="sciScrollable" #viewport>
137
+ * content
138
+ * </div>
139
+ *
140
+ * <!-- Render scrollbars only if native scrollbars are pushed out of the viewport element. -->
141
+ * @if (sciScrollable.isNativeScrollbarCropped()) {
142
+ * <sci-scrollbar [viewport]="viewport" direction="vscroll"/>
143
+ * <sci-scrollbar [viewport]="viewport" direction="hscroll"/>
144
+ * }
145
+ * ```
118
146
  */
119
147
  class SciScrollableDirective {
120
148
  /**
121
149
  * Controls whether to display native scrollbars.
150
+ *
122
151
  * Has no effect if the native scrollbar sits on top of the content, e.g. in OS X.
123
152
  */
124
153
  displayNativeScrollbar = input(false, { ...(ngDevMode ? { debugName: "displayNativeScrollbar" } : /* istanbul ignore next */ {}), alias: 'sciScrollableDisplayNativeScrollbar' });
125
154
  _host = inject((ElementRef)).nativeElement;
126
155
  _renderer = inject(Renderer2);
127
156
  _nativeScrollbarTrackSizeProvider = inject(SciNativeScrollbarTrackSizeProvider);
157
+ /**
158
+ * Indicates whether native scrollbars are pushed out of the viewport element.
159
+ */
160
+ isNativeScrollbarCropped = computed(() => !this.displayNativeScrollbar() && this._nativeScrollbarTrackSizeProvider.trackSize() !== null, /* @ts-ignore */
161
+ ...(ngDevMode ? [{ debugName: "isNativeScrollbarCropped" }] : /* istanbul ignore next */ []));
128
162
  constructor() {
129
163
  this.controlDisplayOfNativeScrollbar();
130
164
  }
@@ -133,14 +167,9 @@ class SciScrollableDirective {
133
167
  */
134
168
  controlDisplayOfNativeScrollbar() {
135
169
  effect(() => {
136
- const displayNativeScrollbar = this.displayNativeScrollbar();
137
- if (displayNativeScrollbar) {
138
- untracked(() => this.useNativeScrollbars());
139
- return;
140
- }
141
- const nativeScrollbarTrackSize = this._nativeScrollbarTrackSizeProvider.trackSize();
142
- if (nativeScrollbarTrackSize) {
143
- untracked(() => this.shiftNativeScrollbars(nativeScrollbarTrackSize));
170
+ if (this.isNativeScrollbarCropped()) {
171
+ const trackSize = this._nativeScrollbarTrackSizeProvider.trackSize();
172
+ untracked(() => this.shiftNativeScrollbars(trackSize));
144
173
  }
145
174
  else {
146
175
  untracked(() => this.useNativeScrollbars());
@@ -162,24 +191,27 @@ class SciScrollableDirective {
162
191
  /**
163
192
  * Shifts the native scrollbars out of the visible viewport area.
164
193
  */
165
- shiftNativeScrollbars(nativeScrollbarTrackSize) {
194
+ shiftNativeScrollbars(trackSize) {
166
195
  this.setStyle(this._host, {
167
196
  overflow: 'scroll',
168
- width: `calc(100% + ${nativeScrollbarTrackSize.vScrollbarTrackWidth}px`,
169
- height: `calc(100% + ${nativeScrollbarTrackSize.hScrollbarTrackHeight}px`,
170
- marginRight: `-${nativeScrollbarTrackSize.vScrollbarTrackWidth}px`,
171
- marginBottom: `-${nativeScrollbarTrackSize.hScrollbarTrackHeight}px`,
197
+ width: `calc(100% + ${trackSize.vScrollbarTrackWidth}px`,
198
+ height: `calc(100% + ${trackSize.hScrollbarTrackHeight}px`,
199
+ marginRight: `-${trackSize.vScrollbarTrackWidth}px`,
200
+ marginBottom: `-${trackSize.hScrollbarTrackHeight}px`,
172
201
  });
173
202
  }
174
203
  setStyle(element, style) {
175
204
  Object.keys(style).forEach(key => this._renderer.setStyle(element, key, style[key]));
176
205
  }
177
206
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: SciScrollableDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
178
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.1", type: SciScrollableDirective, isStandalone: true, selector: "[sciScrollable]", inputs: { displayNativeScrollbar: { classPropertyName: "displayNativeScrollbar", publicName: "sciScrollableDisplayNativeScrollbar", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
207
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.1", type: SciScrollableDirective, isStandalone: true, selector: "[sciScrollable]", inputs: { displayNativeScrollbar: { classPropertyName: "displayNativeScrollbar", publicName: "sciScrollableDisplayNativeScrollbar", isSignal: true, isRequired: false, transformFunction: null } }, exportAs: ["sciScrollable"], ngImport: i0 });
179
208
  }
180
209
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: SciScrollableDirective, decorators: [{
181
210
  type: Directive,
182
- args: [{ selector: '[sciScrollable]' }]
211
+ args: [{
212
+ selector: '[sciScrollable]',
213
+ exportAs: 'sciScrollable',
214
+ }]
183
215
  }], ctorParameters: () => [], propDecorators: { displayNativeScrollbar: [{ type: i0.Input, args: [{ isSignal: true, alias: "sciScrollableDisplayNativeScrollbar", required: false }] }] } });
184
216
 
185
217
  /*
@@ -195,7 +227,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
195
227
  * Renders a vertical or horizontal scrollbar.
196
228
  *
197
229
  * The scrollbar features the following functionality:
198
- * - allows to move the thumb by mouse or touch
230
+ * - allows to move the thumb by mouse
199
231
  * - enlarges the thumb if the mouse pointer is near the thumb
200
232
  * - allows paging on mousedown on the scroll track
201
233
  *
@@ -204,7 +236,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
204
236
  * To customize the default look of SCION components or support different themes, configure the `@scion/components` SCSS module in `styles.scss`.
205
237
  * To style a specific `sci-scrollbar` component, the following CSS variables can be set directly on the component.
206
238
  *
207
- * - sci-scrollbar-color: Sets the color of the scrollbar.
239
+ * - --sci-scrollbar-color: Sets the color of the scrollbar.
208
240
  *
209
241
  * Example:
210
242
  *
@@ -232,7 +264,7 @@ class SciScrollbarComponent {
232
264
  direction = input('vscroll', /* @ts-ignore */
233
265
  ...(ngDevMode ? [{ debugName: "direction" }] : /* istanbul ignore next */ []));
234
266
  /**
235
- * The viewport to provide scrollbars for.
267
+ * Specifies the viewport associated with the scrollbar.
236
268
  */
237
269
  viewport = input.required(/* @ts-ignore */
238
270
  ...(ngDevMode ? [{ debugName: "viewport" }] : /* istanbul ignore next */ []));
@@ -241,89 +273,102 @@ class SciScrollbarComponent {
241
273
  _zone = inject(NgZone);
242
274
  _destroyRef = inject(DestroyRef);
243
275
  _thumbElement = viewChild.required('thumb_handle');
244
- _lastDragPosition = signal(null, /* @ts-ignore */
245
- ...(ngDevMode ? [{ debugName: "_lastDragPosition" }] : /* istanbul ignore next */ []));
246
276
  vertical = computed(() => this.direction() === 'vscroll', /* @ts-ignore */
247
277
  ...(ngDevMode ? [{ debugName: "vertical" }] : /* istanbul ignore next */ []));
248
278
  horizontal = computed(() => !this.vertical(), /* @ts-ignore */
249
279
  ...(ngDevMode ? [{ debugName: "horizontal" }] : /* istanbul ignore next */ []));
250
- scrolling = computed(() => this._lastDragPosition() !== null, /* @ts-ignore */
280
+ scrolling = signal(false, /* @ts-ignore */
251
281
  ...(ngDevMode ? [{ debugName: "scrolling" }] : /* istanbul ignore next */ []));
252
- _overflow = false;
253
- _thumbSizeFr = 0;
254
- _thumbPositionFr = 0;
282
+ overflow = signal(false, /* @ts-ignore */
283
+ ...(ngDevMode ? [{ debugName: "overflow" }] : /* istanbul ignore next */ []));
284
+ thumbSizeFr = signal(0, /* @ts-ignore */
285
+ ...(ngDevMode ? [{ debugName: "thumbSizeFr" }] : /* istanbul ignore next */ []));
286
+ thumbPositionFr = signal(0, /* @ts-ignore */
287
+ ...(ngDevMode ? [{ debugName: "thumbPositionFr" }] : /* istanbul ignore next */ []));
255
288
  constructor() {
256
289
  this.installScrollPositionRenderer();
257
290
  }
258
291
  /**
259
- * Computes the scroll position and updates CSS variables to render the scroll position in the UI.
292
+ * Computes the scroll position and updates CSS variables to render the scroll position.
260
293
  */
261
294
  renderScrollPosition() {
262
295
  NgZone.assertNotInAngularZone();
263
- const viewportSize = this.viewportSize;
264
- const viewportClientSize = this.viewportClientSize;
265
- const thumbPositionFr = this.scrollPosition / viewportClientSize;
266
- const thumbSizeFr = viewportSize / viewportClientSize;
267
- const overflow = viewportClientSize > viewportSize;
268
- if (thumbPositionFr !== this._thumbPositionFr || thumbSizeFr !== this._thumbSizeFr) {
269
- this._thumbPositionFr = thumbPositionFr;
270
- this._thumbSizeFr = thumbSizeFr;
271
- this.setCssVariable('--ɵsci-scrollbar-thumb-position-fr', thumbPositionFr);
272
- this.setCssVariable('--ɵsci-scrollbar-thumb-size-fr', thumbSizeFr);
273
- }
274
- if (overflow !== this._overflow) {
275
- this._overflow = overflow;
276
- overflow ? this._host.classList.add('overflow') : this._host.classList.remove('overflow');
277
- }
296
+ const viewportSize = this.viewportSize();
297
+ const viewportClientSize = this.viewportClientSize();
298
+ this.thumbPositionFr.set(this.viewportScrollPosition() / viewportClientSize);
299
+ this.thumbSizeFr.set(viewportSize / viewportClientSize);
300
+ this.overflow.set(viewportClientSize > viewportSize);
278
301
  }
279
- onTouchStart(event) {
280
- event.preventDefault();
281
- this._lastDragPosition.set(this.vertical() ? event.touches[0].screenY : event.touches[0].screenX);
282
- }
283
- onTouchMove(event) {
284
- event.preventDefault();
285
- const newDragPositionPx = this.vertical() ? event.touches[0].screenY : event.touches[0].screenX;
286
- const scrollbarPanPx = newDragPositionPx - this._lastDragPosition();
287
- const viewportPanPx = this.toViewportPanPx(scrollbarPanPx);
288
- this._lastDragPosition.set(newDragPositionPx);
289
- this.moveViewportClient(viewportPanPx);
290
- }
291
- onTouchEnd(event) {
292
- event.preventDefault();
293
- this._lastDragPosition.set(null);
294
- }
295
- onMouseDown(mousedownEvent) {
302
+ /**
303
+ * Method invoked when clicking on the scrollbar thumb.
304
+ */
305
+ onThumbMouseDown(mousedownEvent) {
296
306
  if (mousedownEvent.button !== 0) {
297
307
  return;
298
308
  }
309
+ this.scrolling.set(true);
310
+ // Prevent text selection during drag.
299
311
  mousedownEvent.preventDefault();
300
- this._lastDragPosition.set(this.vertical() ? mousedownEvent.screenY : mousedownEvent.screenX);
301
- // Listen for 'mousemove' events
302
- const mousemoveListener = merge(fromEvent(this._document, 'mousemove'), fromEvent(this._document, 'sci-mousemove'))
303
- .pipe(subscribeIn(fn => this._zone.runOutsideAngular(fn)), takeUntilDestroyed(this._destroyRef))
312
+ // Calculate screen offset to convert screen coordinates into client coordinates, required for `sci-mousemove` events which originate from other documents (iframes).
313
+ const { screenOffsetX, screenOffsetY } = calculateScreenOffset(mousedownEvent);
314
+ // Memoize offset where thumb was clicked.
315
+ const thumbStartOffset = this.vertical() ? mousedownEvent.offsetY : mousedownEvent.offsetX;
316
+ // 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.
317
+ const mouseUp$ = race(fromEvent(this._document, 'mouseup', { capture: true, once: true }), fromEvent(this._document, 'sci-mouseup', { once: true }))
318
+ .pipe(tap(mouseupEvent => mouseupEvent.stopPropagation()));
319
+ // Track pointer until mouse release.
320
+ merge(fromEvent(this._document, 'mousemove'), fromEvent(this._document, 'sci-mousemove'))
321
+ .pipe(subscribeIn(fn => this._zone.runOutsideAngular(fn)), takeUntilDestroyed(this._destroyRef), takeUntil(mouseUp$), finalize(() => this.scrolling.set(false)))
304
322
  .subscribe(mousemoveEvent => {
305
323
  NgZone.assertNotInAngularZone();
324
+ // Prevent user agent scrolling while during drag.
306
325
  mousemoveEvent.preventDefault();
307
- const newDragPositionPx = this.vertical() ? mousemoveEvent.screenY : mousemoveEvent.screenX;
308
- const scrollbarPanPx = newDragPositionPx - this._lastDragPosition();
309
- const viewportPanPx = this.toViewportPanPx(scrollbarPanPx);
310
- this._lastDragPosition.set(newDragPositionPx);
311
- this.moveViewportClient(viewportPanPx);
326
+ // Calculate new thumb position.
327
+ const pointerPosition = this.vertical() ? mousemoveEvent.screenY - screenOffsetY : mousemoveEvent.screenX - screenOffsetX;
328
+ this.scrollViewport(pointerPosition - thumbStartOffset);
312
329
  });
313
- // Listen for 'mouseup' events; use 'capture phase' and 'stop propagation' to not close overlays
314
- merge(fromEvent(this._document, 'mouseup', { capture: true }), fromEvent(this._document, 'sci-mouseup'))
315
- .pipe(subscribeIn(fn => this._zone.runOutsideAngular(fn)), first(), takeUntilDestroyed(this._destroyRef))
316
- .subscribe(mouseupEvent => {
330
+ }
331
+ /**
332
+ * Method invoked when clicking on the scrollbar track.
333
+ *
334
+ * Scrolls in discrete steps to the pointer, then switches to regular scrolling until releasing the mouse.
335
+ */
336
+ onScrollTrackMouseDown(event) {
337
+ this.scrolling.set(true);
338
+ // Prevent text selection during drag.
339
+ event.preventDefault();
340
+ const mouseMove$ = merge(fromEvent(this._document, 'mousemove'), fromEvent(this._document, 'sci-mousemove'));
341
+ // Handle the event in the capture phase and stop propagation to not close a potential overlay when releasing the mouse outside the overlay.
342
+ const mouseUp$ = race(fromEvent(this._document, 'mouseup', { capture: true, once: true }), fromEvent(this._document, 'sci-mouseup', { once: true }))
343
+ .pipe(tap(mouseupEvent => mouseupEvent.stopPropagation()));
344
+ // Calculate screen offset to convert screen coordinates into client coordinates, required for `sci-mousemove` events which originate from other documents (iframes).
345
+ const { screenOffsetX, screenOffsetY } = calculateScreenOffset(event);
346
+ // Scroll in discrete steps to the pointer position, then switch to regular scrolling.
347
+ timer(250, 50)
348
+ .pipe(
349
+ // Track current pointer position.
350
+ withLatestFrom(mouseMove$.pipe(startWith(event)), (_tick, event) => event),
351
+ // Scroll immediately on initial click.
352
+ startWith(event), subscribeIn(fn => this._zone.runOutsideAngular(fn)), exhaustMap(event => {
353
+ const pointerPosition = this.vertical() ? event.screenY - screenOffsetY : event.screenX - screenOffsetX;
354
+ const [thumbStartPosition, thumbEndPosition] = this.thumbPosition();
355
+ const thumbSize = thumbEndPosition - thumbStartPosition;
356
+ // Step scroll until the pointer hits the thumb.
357
+ if (!isBetween(pointerPosition, { from: thumbStartPosition - thumbSize, to: thumbEndPosition + thumbSize })) {
358
+ const scrollingDown = pointerPosition > thumbEndPosition;
359
+ return of(scrollingDown ? thumbStartPosition + thumbSize : thumbStartPosition - thumbSize);
360
+ }
361
+ // Switch to "smooth scrolling" following the pointer.
362
+ return of(event)
363
+ .pipe(concatWith(mouseMove$), map(event => (this.vertical() ? event.screenY - screenOffsetY : event.screenX - screenOffsetX) - (thumbSize / 2)));
364
+ }),
365
+ // Stop on mouse release.
366
+ takeUntil(mouseUp$), finalize(() => this.scrolling.set(false)))
367
+ .subscribe((thumbPosition) => {
317
368
  NgZone.assertNotInAngularZone();
318
- mouseupEvent.stopPropagation();
319
- mousemoveListener.unsubscribe();
320
- this._lastDragPosition.set(null);
369
+ this.scrollViewport(thumbPosition);
321
370
  });
322
371
  }
323
- onScrollTrackMouseDown(event, direction) {
324
- const signum = (direction === 'up' ? -1 : 1);
325
- this.scrollWhileMouseDown(this.toViewportPanPx(signum * this.thumbSize), event);
326
- }
327
372
  /**
328
373
  * Renders the current scroll position when the viewport is scrolled.
329
374
  */
@@ -339,74 +384,87 @@ class SciScrollbarComponent {
339
384
  });
340
385
  }
341
386
  /**
342
- * Projects the given scrollbar scroll pixels into viewport scroll pixels.
343
- */
344
- toViewportPanPx(scrollbarPanPx) {
345
- const scrollRangePx = this.trackSize - this.thumbSize;
346
- const scrollRatio = scrollbarPanPx / scrollRangePx;
347
- return scrollRatio * (this.viewportClientSize - this.viewportSize);
348
- }
349
- /**
350
- * Moves the viewport client by the specified numbers of pixels.
387
+ * Moves the scrollbar thumb to the specified position, scrolling the viewport accordingly.
388
+ *
389
+ * The thumb position must be given in client coordinates (relative to the top-left corner of the page viewport).
351
390
  */
352
- moveViewportClient(viewportPanPx) {
391
+ scrollViewport(thumbPosition) {
392
+ const [scrollbarComponentStartPosition] = this.scrollbarComponentPosition();
393
+ const scrollbarBorderWidth = this.vertical() ? this._host.clientTop : this._host.clientLeft;
394
+ const scrollRatio = clamp((thumbPosition - scrollbarComponentStartPosition - scrollbarBorderWidth) / (this.trackSize() - this.thumbSize()), { min: 0, max: 1 });
395
+ const viewportScrollPosition = scrollRatio * (this.viewportClientSize() - this.viewportSize());
353
396
  if (this.vertical()) {
354
- this.viewport().scrollTop += viewportPanPx;
397
+ this.viewport().scrollTop = viewportScrollPosition;
355
398
  }
356
399
  else {
357
- this.viewport().scrollLeft += viewportPanPx;
400
+ this.viewport().scrollLeft = viewportScrollPosition;
358
401
  }
359
402
  }
360
403
  /**
361
- * Indicates if the content overflows.
404
+ * Returns the position of this component in client coordinates.
405
+ *
406
+ * Returned coordinates are relative to the top-left corner of the page viewport.
407
+ * Depending on the scrollbar orientation, returned coordinates are `[top, bottom]` or `[left, right]`.
362
408
  */
363
- get overflow() {
364
- return this._overflow;
409
+ scrollbarComponentPosition() {
410
+ const boundingBox = this._host.getBoundingClientRect();
411
+ return this.vertical() ? [boundingBox.top, boundingBox.bottom] : [boundingBox.left, boundingBox.right];
365
412
  }
366
413
  /**
367
- * Scrolls continuously while holding the mouse pressed, or until the mouse leaves the scrolltrack.
414
+ * Returns the size of the viewport in pixels.
415
+ *
416
+ * The viewport is the container for scrollable content (viewport client), displaying scrollbars if it overflows.
417
+ * Depending on the scrollbar orientation, the returned size is `viewport.clientHeight` or `viewport.clientWidth`.
368
418
  */
369
- scrollWhileMouseDown(viewportScrollPx, mousedownEvent) {
370
- // The `EventTarget` type of `Event.target` is not yet compatible with `FromEventTarget` used in `fromEvent`.
371
- // This will be fixed in rxjs version 7.0.0. Refer to https://github.com/ReactiveX/rxjs/commit/5f022d784570684632e6fd5ae247fc259ee34c4b
372
- // for more details.
373
- const scrollTrackElement = mousedownEvent.target;
374
- // scroll continuously every 50ms after an initial delay of 250ms
375
- timer(250, 50)
376
- .pipe(
377
- // continue chain with latest mouse event
378
- withLatestFrom(merge(of(mousedownEvent), fromEvent(scrollTrackElement, 'mousemove')), (tick, event) => event),
379
- // start immediately
380
- startWith(mousedownEvent),
381
- // stop scrolling if the thumb hits the mouse pointer position
382
- takeWhile((event) => scrollTrackElement === this._document.elementFromPoint(event.clientX, event.clientY)), debounceTime(10),
383
- // stop scrolling on mouseout or mouseup
384
- takeUntil(merge(fromEvent(scrollTrackElement, 'mouseout'), fromEvent(scrollTrackElement, 'mouseup'))))
385
- .subscribe(() => {
386
- this.moveViewportClient(viewportScrollPx);
387
- });
388
- }
389
- setCssVariable(key, value) {
390
- this._host.style.setProperty(key, `${value}`);
391
- }
392
- get viewportSize() {
419
+ viewportSize() {
393
420
  return this.vertical() ? this.viewport().clientHeight : this.viewport().clientWidth;
394
421
  }
395
- get viewportClientSize() {
422
+ /**
423
+ * Returns the size of the viewport client in pixels.
424
+ *
425
+ * The viewport client represents scrollable content displayed in the viewport.
426
+ * Depending on the scrollbar orientation, the returned size is `viewport.scrollHeight` or `viewport.scrollWidth`.
427
+ */
428
+ viewportClientSize() {
396
429
  return this.vertical() ? this.viewport().scrollHeight : this.viewport().scrollWidth;
397
430
  }
398
- get scrollPosition() {
431
+ /**
432
+ * Returns the viewport's scroll position in pixels.
433
+ *
434
+ * Depending on the scrollbar orientation, the returned position is `viewport.scrollTop` or `viewport.scrollLeft`.
435
+ */
436
+ viewportScrollPosition() {
399
437
  return this.vertical() ? this.viewport().scrollTop : this.viewport().scrollLeft;
400
438
  }
401
- get thumbSize() {
439
+ /**
440
+ * Returns the size of the scrollbar thumb in pixels.
441
+ *
442
+ * The thumb is the handle used to scroll the scrollbar.
443
+ */
444
+ thumbSize() {
402
445
  const thumbElement = this._thumbElement().nativeElement;
403
- return this.vertical() ? thumbElement.clientHeight : thumbElement.clientWidth;
446
+ return this.vertical() ? thumbElement.offsetHeight : thumbElement.offsetWidth;
404
447
  }
405
- get trackSize() {
448
+ /**
449
+ * Returns the current thumb position in client coordinates.
450
+ *
451
+ * Returned coordinates are relative to the top-left corner of the page viewport.
452
+ * Depending on the scrollbar orientation, returned coordinates are `[top, bottom]` or `[left, right]`.
453
+ */
454
+ thumbPosition() {
455
+ const boundingBox = this._thumbElement().nativeElement.getBoundingClientRect();
456
+ return this.vertical() ? [boundingBox.top, boundingBox.bottom] : [boundingBox.left, boundingBox.right];
457
+ }
458
+ /**
459
+ * Returns the size of the scrollbar track in pixels.
460
+ *
461
+ * The scrollbar track is the track along which the scrollbar thumb moves.
462
+ */
463
+ trackSize() {
406
464
  return this.vertical() ? this._host.clientHeight : this._host.clientWidth;
407
465
  }
408
466
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: SciScrollbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
409
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.0.1", 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()" } }, viewQueries: [{ propertyName: "_thumbElement", first: true, predicate: ["thumb_handle"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- scrolltrack to move the viewport client upwards (paging) -->\n<div class=\"scrolltrack-start\" (mousedown)=\"onScrollTrackMouseDown($event, 'up')\"></div>\n\n<!-- scrollthumb -->\n<div #thumb_handle\n class=\"thumb-handle\"\n [class.vertical]=\"vertical()\"\n [class.horizontal]=\"horizontal()\"\n (mousedown)=\"onMouseDown($event)\"\n (touchstart)=\"onTouchStart($event)\"\n (touchmove)=\"onTouchMove($event)\"\n (touchend)=\"onTouchEnd($event)\"\n (touchcancel)=\"onTouchEnd($event)\">\n <div class=\"thumb\"\n [class.vertical]=\"vertical()\"\n [class.horizontal]=\"horizontal()\">\n </div>\n</div>\n\n<!-- scrolltrack to move the viewport client downwards (paging) -->\n<div class=\"scrolltrack-end\" (mousedown)=\"onScrollTrackMouseDown($event, 'down')\"></div>\n", styles: ["@charset \"UTF-8\";:host{display:flex;border:2px solid transparent;box-sizing:border-box;--\\275sci-scrollbar-thumb-position-fr: 0;--\\275sci-scrollbar-thumb-size-fr: 0}:host.vertical{flex-direction:column}:host.horizontal{flex-direction:row}:host>div.scrolltrack-start{flex-grow:var(--\\275sci-scrollbar-thumb-position-fr)}:host>div.thumb-handle{flex-basis:20px;display:flex;flex-grow:var(--\\275sci-scrollbar-thumb-size-fr);align-items:center}:host>div.thumb-handle.vertical{flex-direction:column}:host>div.thumb-handle.horizontal{flex-direction:row}: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-end{flex-grow:calc(1 - (var(--\\275sci-scrollbar-thumb-position-fr) + var(--\\275sci-scrollbar-thumb-size-fr)))}:host-context(:not(.overflow)){display:none}:host-context(:hover)>div.thumb-handle>div.thumb,:host-context(.scrolling)>div.thumb-handle>div.thumb{background-color:var(--sci-scrollbar-color);opacity:.75}:host-context(:hover)>div.thumb-handle>div.thumb.vertical,:host-context(.scrolling)>div.thumb-handle>div.thumb.vertical{width:100%}:host-context(:hover)>div.thumb-handle>div.thumb.horizontal,:host-context(.scrolling)>div.thumb-handle>div.thumb.horizontal{height:100%}\n"] });
467
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.0.1", 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"] });
410
468
  }
411
469
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: SciScrollbarComponent, decorators: [{
412
470
  type: Component,
@@ -414,10 +472,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
414
472
  '[class.vertical]': 'vertical()',
415
473
  '[class.horizontal]': 'horizontal()',
416
474
  '[class.scrolling]': 'scrolling()',
417
- }, template: "<!-- scrolltrack to move the viewport client upwards (paging) -->\n<div class=\"scrolltrack-start\" (mousedown)=\"onScrollTrackMouseDown($event, 'up')\"></div>\n\n<!-- scrollthumb -->\n<div #thumb_handle\n class=\"thumb-handle\"\n [class.vertical]=\"vertical()\"\n [class.horizontal]=\"horizontal()\"\n (mousedown)=\"onMouseDown($event)\"\n (touchstart)=\"onTouchStart($event)\"\n (touchmove)=\"onTouchMove($event)\"\n (touchend)=\"onTouchEnd($event)\"\n (touchcancel)=\"onTouchEnd($event)\">\n <div class=\"thumb\"\n [class.vertical]=\"vertical()\"\n [class.horizontal]=\"horizontal()\">\n </div>\n</div>\n\n<!-- scrolltrack to move the viewport client downwards (paging) -->\n<div class=\"scrolltrack-end\" (mousedown)=\"onScrollTrackMouseDown($event, 'down')\"></div>\n", styles: ["@charset \"UTF-8\";:host{display:flex;border:2px solid transparent;box-sizing:border-box;--\\275sci-scrollbar-thumb-position-fr: 0;--\\275sci-scrollbar-thumb-size-fr: 0}:host.vertical{flex-direction:column}:host.horizontal{flex-direction:row}:host>div.scrolltrack-start{flex-grow:var(--\\275sci-scrollbar-thumb-position-fr)}:host>div.thumb-handle{flex-basis:20px;display:flex;flex-grow:var(--\\275sci-scrollbar-thumb-size-fr);align-items:center}:host>div.thumb-handle.vertical{flex-direction:column}:host>div.thumb-handle.horizontal{flex-direction:row}: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-end{flex-grow:calc(1 - (var(--\\275sci-scrollbar-thumb-position-fr) + var(--\\275sci-scrollbar-thumb-size-fr)))}:host-context(:not(.overflow)){display:none}:host-context(:hover)>div.thumb-handle>div.thumb,:host-context(.scrolling)>div.thumb-handle>div.thumb{background-color:var(--sci-scrollbar-color);opacity:.75}:host-context(:hover)>div.thumb-handle>div.thumb.vertical,:host-context(.scrolling)>div.thumb-handle>div.thumb.vertical{width:100%}:host-context(:hover)>div.thumb-handle>div.thumb.horizontal,:host-context(.scrolling)>div.thumb-handle>div.thumb.horizontal{height:100%}\n"] }]
475
+ '[class.overflow]': 'overflow()',
476
+ '[style.--ɵsci-scrollbar-thumb-position-fr]': 'thumbPositionFr()',
477
+ '[style.--ɵsci-scrollbar-thumb-size-fr]': 'thumbSizeFr()',
478
+ }, 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"] }]
418
479
  }], ctorParameters: () => [], propDecorators: { direction: [{ type: i0.Input, args: [{ isSignal: true, alias: "direction", required: false }] }], viewport: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewport", required: true }] }], _thumbElement: [{ type: i0.ViewChild, args: ['thumb_handle', { isSignal: true }] }] } });
419
480
  /**
420
- * Emits whenever the viewport scrolls.
481
+ * Emits whenever the viewport is scrolled.
421
482
  */
422
483
  function viewportScroll$(viewport) {
423
484
  return fromEvent(viewport, 'scroll', { passive: true }).pipe(map(() => undefined));
@@ -452,7 +513,37 @@ function viewportClientSize$(viewport, options) {
452
513
  */
453
514
  function children$(element) {
454
515
  return fromMutation$(element, { subtree: false, childList: true })
455
- .pipe(startWith(undefined), map(() => Array.from(element.children)), filterArray((child) => child instanceof HTMLElement));
516
+ .pipe(startWith(undefined), map(() => Array.from(element.children)
517
+ // Map to slotted content if a slot (Shadow DOM).
518
+ .flatMap(child => child instanceof HTMLSlotElement ? child.assignedElements() : child)
519
+ // Filter HTML elements.
520
+ .filter((child) => child instanceof HTMLElement)));
521
+ }
522
+ /**
523
+ * Returns the value clamped to the inclusive range of min and max.
524
+ */
525
+ function clamp(value, minmax) {
526
+ return Math.max(minmax.min, Math.min(value, minmax.max));
527
+ }
528
+ /**
529
+ * Returns whether the value is between the specified range (inclusive).
530
+ */
531
+ function isBetween(value, range) {
532
+ return value >= range.from && value <= range.to;
533
+ }
534
+ /**
535
+ * Calculates the distance between the top-left corner of the screen (monitor) and the top-left corner of the page viewport of this document.
536
+ *
537
+ * Use to convert screen coordinates from `sci-mousemove` and `sci-mouseup` events into client coordinates relative to the page viewport of the current document.
538
+ *
539
+ * 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
540
+ * relative to the source document, not the current one.
541
+ */
542
+ function calculateScreenOffset(mousedownEvent) {
543
+ return {
544
+ screenOffsetX: mousedownEvent.screenX - mousedownEvent.clientX,
545
+ screenOffsetY: mousedownEvent.screenY - mousedownEvent.clientY,
546
+ };
456
547
  }
457
548
 
458
549
  /*
@@ -544,7 +635,6 @@ class SciViewportComponent {
544
635
  _host = inject(ElementRef).nativeElement;
545
636
  _viewport = viewChild.required('viewport');
546
637
  _viewportClient = viewChild.required('viewport_client');
547
- nativeScrollbarTrackSizeProvider = inject(SciNativeScrollbarTrackSizeProvider);
548
638
  constructor() {
549
639
  this.installScrollEmitter();
550
640
  }
@@ -708,7 +798,7 @@ class SciViewportComponent {
708
798
  });
709
799
  }
710
800
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: SciViewportComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
711
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", 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'\"\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' && nativeScrollbarTrackSizeProvider.trackSize() !== null) {\n <sci-scrollbar [direction]=\"'vscroll'\" [viewport]=\"viewport\" class=\"e2e-vertical\"/>\n <sci-scrollbar [direction]=\"'hscroll'\" [viewport]=\"viewport\" class=\"e2e-horizontal\"/>\n}\n", styles: [":host{display:grid;grid-template-columns:100%;grid-template-rows:100%;position:relative;overflow:hidden;outline:none}:host:host-context(: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;transition-duration:1s;transition-property:opacity;transition-timing-function:ease-out}:host>sci-scrollbar.vertical{top:0;right:0;bottom:0;left:unset;width:12px}:host>sci-scrollbar.horizontal{top:unset;right:0;bottom:0;left:0;height:12px}\n"], dependencies: [{ kind: "directive", type: SciScrollableDirective, selector: "[sciScrollable]", inputs: ["sciScrollableDisplayNativeScrollbar"] }, { 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 });
801
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", 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 });
712
802
  }
713
803
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: SciViewportComponent, decorators: [{
714
804
  type: Component,
@@ -718,7 +808,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
718
808
  CdkScrollable,
719
809
  ], changeDetection: ChangeDetectionStrategy.Eager, host: {
720
810
  '(focus)': 'focus()',
721
- }, 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' && nativeScrollbarTrackSizeProvider.trackSize() !== null) {\n <sci-scrollbar [direction]=\"'vscroll'\" [viewport]=\"viewport\" class=\"e2e-vertical\"/>\n <sci-scrollbar [direction]=\"'hscroll'\" [viewport]=\"viewport\" class=\"e2e-horizontal\"/>\n}\n", styles: [":host{display:grid;grid-template-columns:100%;grid-template-rows:100%;position:relative;overflow:hidden;outline:none}:host:host-context(: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;transition-duration:1s;transition-property:opacity;transition-timing-function:ease-out}:host>sci-scrollbar.vertical{top:0;right:0;bottom:0;left:unset;width:12px}:host>sci-scrollbar.horizontal{top:unset;right:0;bottom:0;left:0;height:12px}\n"] }]
811
+ }, 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"] }]
722
812
  }], ctorParameters: () => [], 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 }] }] } });
723
813
 
724
814
  /*
@@ -1 +1 @@
1
- {"version":3,"file":"scion-components-viewport.mjs","sources":["../../../../projects/scion/components/viewport/src/native-scrollbar-track-size-provider.service.ts","../../../../projects/scion/components/viewport/src/scrollable.directive.ts","../../../../projects/scion/components/viewport/src/scrollbar/scrollbar.component.ts","../../../../projects/scion/components/viewport/src/scrollbar/scrollbar.component.html","../../../../projects/scion/components/viewport/src/viewport.component.ts","../../../../projects/scion/components/viewport/src/viewport.component.html","../../../../projects/scion/components/viewport/src/public_api.ts","../../../../projects/scion/components/viewport/src/scion-components-viewport.ts"],"sourcesContent":["/*\n * Copyright (c) 2018-2024 Swiss Federal Railways\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n */\n\nimport {inject, Injectable, NgZone, Signal, DOCUMENT} from '@angular/core';\nimport {fromEvent} from 'rxjs';\nimport {debounceTime, distinctUntilChanged, map, startWith} from 'rxjs/operators';\nimport {toSignal} from '@angular/core/rxjs-interop';\nimport {subscribeIn} from '@scion/toolkit/operators';\n\n/**\n * Provides the native scrollbar tracksize.\n */\n@Injectable({providedIn: 'root'})\nexport class SciNativeScrollbarTrackSizeProvider {\n\n private readonly _document = inject(DOCUMENT);\n private readonly _zone = inject(NgZone);\n\n /**\n * Provides the track size of the native scrollbar, or `null` if the native scrollbars sit on top of the content.\n */\n public trackSize: Signal<NativeScrollbarTrackSize | null>;\n\n constructor() {\n this.trackSize = this.createNativeScrollbarTrackSizeSignal();\n }\n\n /**\n * Computes the native scrollbar track size.\n *\n * @returns native track size, or `null` if the native scrollbars sit on top of the content.\n */\n private computeTrackSize(): NativeScrollbarTrackSize | null {\n // Create temporary viewport and viewport client with native scrollbars to compute the scrolltrack width.\n const viewportDiv = this._document.createElement('div');\n setStyle(viewportDiv, {\n position: 'absolute',\n overflow: 'scroll',\n height: '100px',\n width: '100px',\n border: '0',\n visibility: 'hidden',\n });\n\n const viewportClientDiv = this._document.createElement('div');\n setStyle(viewportClientDiv, {\n height: '100%',\n width: '100%',\n border: '0',\n });\n\n viewportDiv.appendChild(viewportClientDiv);\n this._document.body.appendChild(viewportDiv);\n\n // Do not use client and offset width/height to calculate the size of the scrollbar, as they are rounded, resulting in unwanted spacing when zooming the page.\n const viewportBounds = viewportDiv.getBoundingClientRect();\n const viewportClientBounds = viewportClientDiv.getBoundingClientRect();\n const trackSize: NativeScrollbarTrackSize = {\n hScrollbarTrackHeight: viewportBounds.height - viewportClientBounds.height,\n vScrollbarTrackWidth: viewportBounds.width - viewportClientBounds.width,\n };\n\n // Destroy temporary viewport.\n this._document.body.removeChild(viewportDiv);\n if (trackSize.hScrollbarTrackHeight === 0 && trackSize.vScrollbarTrackWidth === 0) {\n return null;\n }\n\n return trackSize;\n }\n\n private createNativeScrollbarTrackSizeSignal(): Signal<NativeScrollbarTrackSize | null> {\n // We compute the size of the native scrollbar track when the browser fires the onresize window event.\n // This event is also fired on page zoom or when displaying a hidden document. Hidden documents do not have\n // a scrollbar track size until being displayed, e.g., after showing hidden iframes.\n const trackSize$ = fromEvent(window, 'resize')\n .pipe(\n subscribeIn(fn => this._zone.runOutsideAngular(fn)),\n debounceTime(5),\n startWith(null), // trigger the initial computation\n map(() => this.computeTrackSize()),\n distinctUntilChanged((t1, t2) => t1?.hScrollbarTrackHeight === t2?.hScrollbarTrackHeight && t1?.vScrollbarTrackWidth === t2?.vScrollbarTrackWidth),\n );\n return toSignal(trackSize$, {initialValue: null});\n }\n}\n\n/**\n * Applies the given style(s) to the given element.\n *\n * Specify styles to be modified by passing a dictionary containing CSS property names (hyphen case).\n * To remove a style, set its value to `null`.\n *\n * @ignore\n */\nfunction setStyle(element: HTMLElement, styles: {[style: string]: string}): void {\n Object.entries(styles).forEach(([name, value]) => element.style.setProperty(name, value));\n}\n\n/**\n * Represents the native scrollbar track size.\n */\nexport interface NativeScrollbarTrackSize {\n hScrollbarTrackHeight: number;\n vScrollbarTrackWidth: number;\n}\n","/*\n * Copyright (c) 2018-2019 Swiss Federal Railways\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n */\n\nimport {Directive, effect, ElementRef, inject, input, Renderer2, untracked} from '@angular/core';\nimport {NativeScrollbarTrackSize, SciNativeScrollbarTrackSizeProvider} from './native-scrollbar-track-size-provider.service';\nimport {Dictionary} from '@scion/toolkit/util';\n\n/**\n * Makes the host element natively scrollable and hides native scrollbars by default, unless native scrollbars\n * already sit on top of the viewport (e.g. in OS X).\n *\n * Because there is no cross-browser API to hide scrollbars without losing native scroll support, we set 'overflow'\n * to 'scroll' but shift the native scrollbars out of the visible viewport area. The shift offset is computed upfront.\n *\n * This directive expects its host element to be the only child in document flow in its parent DOM element. It makes the host element\n * fill up the entire space (width and height set to 100%). The parent element must have its CSS `overflow` property set to `hidden`\n * to hide the pushed out native scrollbars.\n */\n@Directive({selector: '[sciScrollable]'})\nexport class SciScrollableDirective {\n\n /**\n * Controls whether to display native scrollbars.\n * Has no effect if the native scrollbar sits on top of the content, e.g. in OS X.\n */\n public readonly displayNativeScrollbar = input(false, {alias: 'sciScrollableDisplayNativeScrollbar'});\n\n private readonly _host = inject(ElementRef<HTMLDivElement>).nativeElement as HTMLElement;\n private readonly _renderer = inject(Renderer2);\n private readonly _nativeScrollbarTrackSizeProvider = inject(SciNativeScrollbarTrackSizeProvider);\n\n constructor() {\n this.controlDisplayOfNativeScrollbar();\n }\n\n /**\n * Controls the display of the native scrollbar based on this directive's configuration.\n */\n private controlDisplayOfNativeScrollbar(): void {\n effect(() => {\n const displayNativeScrollbar = this.displayNativeScrollbar();\n if (displayNativeScrollbar) {\n untracked(() => this.useNativeScrollbars());\n return;\n }\n\n const nativeScrollbarTrackSize = this._nativeScrollbarTrackSizeProvider.trackSize();\n if (nativeScrollbarTrackSize) {\n untracked(() => this.shiftNativeScrollbars(nativeScrollbarTrackSize));\n }\n else {\n untracked(() => this.useNativeScrollbars());\n }\n });\n }\n\n /**\n * Uses the native scrollbars when content overflows.\n */\n private useNativeScrollbars(): void {\n this.setStyle(this._host, {\n overflow: 'auto',\n width: '100%',\n height: '100%',\n marginRight: 0,\n marginBottom: 0,\n });\n }\n\n /**\n * Shifts the native scrollbars out of the visible viewport area.\n */\n private shiftNativeScrollbars(nativeScrollbarTrackSize: NativeScrollbarTrackSize): void {\n this.setStyle(this._host, {\n overflow: 'scroll',\n width: `calc(100% + ${nativeScrollbarTrackSize.vScrollbarTrackWidth}px`,\n height: `calc(100% + ${nativeScrollbarTrackSize.hScrollbarTrackHeight}px`,\n marginRight: `-${nativeScrollbarTrackSize.vScrollbarTrackWidth}px`,\n marginBottom: `-${nativeScrollbarTrackSize.hScrollbarTrackHeight}px`,\n });\n }\n\n private setStyle(element: Element, style: Dictionary): void {\n Object.keys(style).forEach(key => this._renderer.setStyle(element, key, style[key]));\n }\n}\n","/*\n * Copyright (c) 2018-2019 Swiss Federal Railways\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n */\n\nimport {Component, computed, DestroyRef, DOCUMENT, effect, ElementRef, inject, input, NgZone, signal, untracked, viewChild} from '@angular/core';\nimport {fromEvent, merge, mergeWith, Observable, of, timer} from 'rxjs';\nimport {debounceTime, first, map, startWith, switchMap, takeUntil, takeWhile, withLatestFrom} from 'rxjs/operators';\nimport {fromMutation$, fromResize$} from '@scion/toolkit/observable';\nimport {filterArray, subscribeIn} from '@scion/toolkit/operators';\nimport {takeUntilDestroyed} from '@angular/core/rxjs-interop';\n\n/**\n * Renders a vertical or horizontal scrollbar.\n *\n * The scrollbar features the following functionality:\n * - allows to move the thumb by mouse or touch\n * - enlarges the thumb if the mouse pointer is near the thumb\n * - allows paging on mousedown on the scroll track\n *\n * ### Styling:\n *\n * To customize the default look of SCION components or support different themes, configure the `@scion/components` SCSS module in `styles.scss`.\n * To style a specific `sci-scrollbar` component, the following CSS variables can be set directly on the component.\n *\n * - sci-scrollbar-color: Sets the color of the scrollbar.\n *\n * Example:\n *\n * ```css\n *\n * sci-scrollbar {\n * --sci-scrollbar-color: blue;\n * }\n * ```\n */\n@Component({\n selector: 'sci-scrollbar',\n templateUrl: './scrollbar.component.html',\n styleUrl: './scrollbar.component.scss',\n host: {\n '[class.vertical]': 'vertical()',\n '[class.horizontal]': 'horizontal()',\n '[class.scrolling]': 'scrolling()',\n },\n})\nexport class SciScrollbarComponent {\n\n /**\n * Timeout for debouncing viewport resize events that trigger the scroll position computation.\n *\n * Debouncing is particularly important in the context of Angular animations, since they continuously\n * trigger resize events. Debouncing prevents the scrollbar from flickering, for example, when the user\n * expands a panel that contains a viewport.\n *\n * @internal\n */\n public static readonly VIEWPORT_RESIZE_DEBOUNCE_TIME = 50;\n\n /**\n * Specifies the direction of the scrollbar. Defaults to a vertical scrollbar.\n */\n public readonly direction = input<'vscroll' | 'hscroll'>('vscroll');\n\n /**\n * The viewport to provide scrollbars for.\n */\n public readonly viewport = input.required<HTMLElement>();\n\n private readonly _host = inject(ElementRef).nativeElement as HTMLElement;\n private readonly _document = inject(DOCUMENT);\n private readonly _zone = inject(NgZone);\n private readonly _destroyRef = inject(DestroyRef);\n private readonly _thumbElement = viewChild.required<ElementRef<HTMLDivElement>>('thumb_handle');\n private readonly _lastDragPosition = signal<number | null>(null);\n\n protected readonly vertical = computed(() => this.direction() === 'vscroll');\n protected readonly horizontal = computed(() => !this.vertical());\n protected readonly scrolling = computed(() => this._lastDragPosition() !== null);\n\n private _overflow = false;\n private _thumbSizeFr = 0;\n private _thumbPositionFr = 0;\n\n constructor() {\n this.installScrollPositionRenderer();\n }\n\n /**\n * Computes the scroll position and updates CSS variables to render the scroll position in the UI.\n */\n private renderScrollPosition(): void {\n NgZone.assertNotInAngularZone();\n const viewportSize = this.viewportSize;\n const viewportClientSize = this.viewportClientSize;\n const thumbPositionFr = this.scrollPosition / viewportClientSize;\n const thumbSizeFr = viewportSize / viewportClientSize;\n const overflow = viewportClientSize > viewportSize;\n\n if (thumbPositionFr !== this._thumbPositionFr || thumbSizeFr !== this._thumbSizeFr) {\n this._thumbPositionFr = thumbPositionFr;\n this._thumbSizeFr = thumbSizeFr;\n this.setCssVariable('--ɵsci-scrollbar-thumb-position-fr', thumbPositionFr);\n this.setCssVariable('--ɵsci-scrollbar-thumb-size-fr', thumbSizeFr);\n }\n\n if (overflow !== this._overflow) {\n this._overflow = overflow;\n overflow ? this._host.classList.add('overflow') : this._host.classList.remove('overflow');\n }\n }\n\n protected onTouchStart(event: TouchEvent): void {\n event.preventDefault();\n this._lastDragPosition.set(this.vertical() ? event.touches[0]!.screenY : event.touches[0]!.screenX);\n }\n\n protected onTouchMove(event: TouchEvent): void {\n event.preventDefault();\n\n const newDragPositionPx = this.vertical() ? event.touches[0]!.screenY : event.touches[0]!.screenX;\n const scrollbarPanPx = newDragPositionPx - this._lastDragPosition()!;\n const viewportPanPx = this.toViewportPanPx(scrollbarPanPx);\n this._lastDragPosition.set(newDragPositionPx);\n this.moveViewportClient(viewportPanPx);\n }\n\n protected onTouchEnd(event: TouchEvent): void {\n event.preventDefault();\n this._lastDragPosition.set(null);\n }\n\n protected onMouseDown(mousedownEvent: MouseEvent): void {\n if (mousedownEvent.button !== 0) {\n return;\n }\n\n mousedownEvent.preventDefault();\n this._lastDragPosition.set(this.vertical() ? mousedownEvent.screenY : mousedownEvent.screenX);\n\n // Listen for 'mousemove' events\n const mousemoveListener = merge(fromEvent<MouseEvent>(this._document, 'mousemove'), fromEvent<MouseEvent>(this._document, 'sci-mousemove'))\n .pipe(\n subscribeIn(fn => this._zone.runOutsideAngular(fn)),\n takeUntilDestroyed(this._destroyRef),\n )\n .subscribe(mousemoveEvent => {\n NgZone.assertNotInAngularZone();\n mousemoveEvent.preventDefault();\n const newDragPositionPx = this.vertical() ? mousemoveEvent.screenY : mousemoveEvent.screenX;\n const scrollbarPanPx = newDragPositionPx - this._lastDragPosition()!;\n const viewportPanPx = this.toViewportPanPx(scrollbarPanPx);\n this._lastDragPosition.set(newDragPositionPx);\n this.moveViewportClient(viewportPanPx);\n });\n\n // Listen for 'mouseup' events; use 'capture phase' and 'stop propagation' to not close overlays\n merge(fromEvent<MouseEvent>(this._document, 'mouseup', {capture: true}), fromEvent<MouseEvent>(this._document, 'sci-mouseup'))\n .pipe(\n subscribeIn(fn => this._zone.runOutsideAngular(fn)),\n first(),\n takeUntilDestroyed(this._destroyRef),\n )\n .subscribe(mouseupEvent => {\n NgZone.assertNotInAngularZone();\n mouseupEvent.stopPropagation();\n mousemoveListener.unsubscribe();\n this._lastDragPosition.set(null);\n });\n }\n\n protected onScrollTrackMouseDown(event: MouseEvent, direction: 'up' | 'down'): void {\n const signum = (direction === 'up' ? -1 : 1);\n this.scrollWhileMouseDown(this.toViewportPanPx(signum * this.thumbSize), event);\n }\n\n /**\n * Renders the current scroll position when the viewport is scrolled.\n */\n private installScrollPositionRenderer(): void {\n effect(onCleanup => {\n const viewport = this.viewport();\n\n untracked(() => {\n const subscription = viewportScroll$(viewport)\n .pipe(\n mergeWith(viewportSize$(viewport, {debounceTime: SciScrollbarComponent.VIEWPORT_RESIZE_DEBOUNCE_TIME})),\n mergeWith(viewportClientSize$(viewport, {debounceTime: SciScrollbarComponent.VIEWPORT_RESIZE_DEBOUNCE_TIME})),\n subscribeIn(fn => this._zone.runOutsideAngular(fn)),\n )\n .subscribe(() => this.renderScrollPosition());\n onCleanup(() => subscription.unsubscribe());\n });\n });\n }\n\n /**\n * Projects the given scrollbar scroll pixels into viewport scroll pixels.\n */\n private toViewportPanPx(scrollbarPanPx: number): number {\n const scrollRangePx = this.trackSize - this.thumbSize;\n const scrollRatio = scrollbarPanPx / scrollRangePx;\n return scrollRatio * (this.viewportClientSize - this.viewportSize);\n }\n\n /**\n * Moves the viewport client by the specified numbers of pixels.\n */\n private moveViewportClient(viewportPanPx: number): void {\n if (this.vertical()) {\n this.viewport().scrollTop += viewportPanPx;\n }\n else {\n this.viewport().scrollLeft += viewportPanPx;\n }\n }\n\n /**\n * Indicates if the content overflows.\n */\n public get overflow(): boolean {\n return this._overflow;\n }\n\n /**\n * Scrolls continuously while holding the mouse pressed, or until the mouse leaves the scrolltrack.\n */\n private scrollWhileMouseDown(viewportScrollPx: number, mousedownEvent: MouseEvent): void {\n // The `EventTarget` type of `Event.target` is not yet compatible with `FromEventTarget` used in `fromEvent`.\n // This will be fixed in rxjs version 7.0.0. Refer to https://github.com/ReactiveX/rxjs/commit/5f022d784570684632e6fd5ae247fc259ee34c4b\n // for more details.\n const scrollTrackElement = mousedownEvent.target as Element;\n\n // scroll continuously every 50ms after an initial delay of 250ms\n timer(250, 50)\n .pipe(\n // continue chain with latest mouse event\n withLatestFrom(merge(of(mousedownEvent), fromEvent<MouseEvent>(scrollTrackElement, 'mousemove')), (tick, event) => event),\n // start immediately\n startWith(mousedownEvent),\n // stop scrolling if the thumb hits the mouse pointer position\n takeWhile((event: MouseEvent) => scrollTrackElement === this._document.elementFromPoint(event.clientX, event.clientY)),\n debounceTime(10),\n // stop scrolling on mouseout or mouseup\n takeUntil(merge(fromEvent(scrollTrackElement, 'mouseout'), fromEvent(scrollTrackElement, 'mouseup'))),\n )\n .subscribe(() => {\n this.moveViewportClient(viewportScrollPx);\n });\n }\n\n private setCssVariable(key: string, value: number): void {\n this._host.style.setProperty(key, `${value}`);\n }\n\n private get viewportSize(): number {\n return this.vertical() ? this.viewport().clientHeight : this.viewport().clientWidth;\n }\n\n private get viewportClientSize(): number {\n return this.vertical() ? this.viewport().scrollHeight : this.viewport().scrollWidth;\n }\n\n private get scrollPosition(): number {\n return this.vertical() ? this.viewport().scrollTop : this.viewport().scrollLeft;\n }\n\n private get thumbSize(): number {\n const thumbElement = this._thumbElement().nativeElement;\n return this.vertical() ? thumbElement.clientHeight : thumbElement.clientWidth;\n }\n\n private get trackSize(): number {\n return this.vertical() ? this._host.clientHeight : this._host.clientWidth;\n }\n}\n\n/**\n * Emits whenever the viewport scrolls.\n */\nfunction viewportScroll$(viewport: HTMLElement): Observable<void> {\n return fromEvent(viewport, 'scroll', {passive: true}).pipe(map(() => undefined));\n}\n\n/**\n * Emits on subscription, and then each time the size of the viewport changes.\n */\nfunction viewportSize$(viewport: HTMLElement, options: {debounceTime: number}): Observable<void> {\n return fromResize$(viewport)\n .pipe(\n // Debouncing is particularly important in the context of Angular animations, since they continuously\n // trigger resize events. Debouncing prevents the scrollbar from flickering, for example, when the user\n // expands a panel that contains a viewport.\n debounceTime(options.debounceTime),\n map(() => undefined),\n );\n}\n\n/**\n * Emits on subscription, and then each time the size or style property of the viewport client changes.\n */\nfunction viewportClientSize$(viewport: HTMLElement, options: {debounceTime: number}): Observable<void> {\n return children$(viewport)\n .pipe(\n switchMap(children => merge(...children.map(child => merge(\n fromResize$(child),\n // Observe style mutations since some transformations change the scroll position without necessarily triggering a dimension change,\n // e.g., `scale` or `translate` used by some virtual scroll implementations\n fromMutation$(child, {subtree: false, childList: false, attributeFilter: ['style']})),\n ))),\n // Debouncing is particularly important in the context of Angular animations, since they continuously\n // trigger resize events. Debouncing prevents the scrollbar from flickering, for example, when the user\n // expands a panel that contains a viewport.\n debounceTime(options.debounceTime),\n map(() => undefined),\n );\n}\n\n/**\n * Emits the children of the passed element, and then each time child elements are added or removed.\n */\nfunction children$(element: HTMLElement): Observable<HTMLElement[]> {\n return fromMutation$(element, {subtree: false, childList: true})\n .pipe(\n startWith(undefined as void),\n map(() => Array.from(element.children)),\n filterArray((child: Element): child is HTMLElement => child instanceof HTMLElement),\n );\n}\n","<!-- scrolltrack to move the viewport client upwards (paging) -->\n<div class=\"scrolltrack-start\" (mousedown)=\"onScrollTrackMouseDown($event, 'up')\"></div>\n\n<!-- scrollthumb -->\n<div #thumb_handle\n class=\"thumb-handle\"\n [class.vertical]=\"vertical()\"\n [class.horizontal]=\"horizontal()\"\n (mousedown)=\"onMouseDown($event)\"\n (touchstart)=\"onTouchStart($event)\"\n (touchmove)=\"onTouchMove($event)\"\n (touchend)=\"onTouchEnd($event)\"\n (touchcancel)=\"onTouchEnd($event)\">\n <div class=\"thumb\"\n [class.vertical]=\"vertical()\"\n [class.horizontal]=\"horizontal()\">\n </div>\n</div>\n\n<!-- scrolltrack to move the viewport client downwards (paging) -->\n<div class=\"scrolltrack-end\" (mousedown)=\"onScrollTrackMouseDown($event, 'down')\"></div>\n","/*\n * Copyright (c) 2018-2019 Swiss Federal Railways\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n */\n\nimport {Component, effect, ElementRef, inject, input, NgZone, output, untracked, viewChild, ViewEncapsulation, ChangeDetectionStrategy} from '@angular/core';\nimport {SciNativeScrollbarTrackSizeProvider} from './native-scrollbar-track-size-provider.service';\nimport {coerceElement} from '@angular/cdk/coercion';\nimport {SciScrollableDirective} from './scrollable.directive';\nimport {SciScrollbarComponent} from './scrollbar/scrollbar.component';\nimport {fromEvent} from 'rxjs';\nimport {subscribeIn} from '@scion/toolkit/operators';\nimport {CdkScrollable} from '@angular/cdk/scrolling';\n\n/**\n * Represents a viewport with slotted content (`<ng-content>`) used as scrollable content. By default, content is added to a CSS grid layout.\n *\n * The viewport component displays scrollbars when its content overflows. Scrollbars are displayed on top of the content, not next to it.\n * The component uses the native scrollbars of the operating system if they are already sitting on top, or falls back and renders scrollbars on top otherwise.\n * The viewport remains natively scrollable with the native scrollbars shifted out of the viewport's visible area. Consequently, the viewport keeps supporting\n * native scrolling features such as touch gestures, scroll speed acceleration, or scrolling near the viewport edges during drag-and-drop operations.\n *\n * ```html\n * <sci-viewport>\n * your content\n * </sci-viewport>\n * ```\n *\n * ## Adding the viewport to a layout\n *\n * Typically, you would add the viewport component to a flexible layout, filling the remaining space vertically and horizontally, such as a flexbox container\n * with the viewport's `flex` CSS property set to either `flex: auto` or `flex: 1 1 0`.\n *\n * The viewport is sized according to its content width and height. It grows to absorb any free space, thus overflowing its content only when encountering\n * a layout constraint. Depending on the layout, different steps may be necessary to prevent the viewport from growing to infinity.\n *\n * - If practical, give the viewport a fixed size or a maximum size.\n * - If you add the viewport to a flexbox layout, make sure that it cannot exceed the available space. Instead, the viewport should fill the remaining space,\n * vertically and horizontally. Be aware that, by default, a flex item does not shrink below its minimum content size. To change this, set the viewport's\n * `flex-basis` to `0` (instead of `auto`), or use the CSS shorthand property `flex: 1 1 0`. The `flex-basis` defines the default size of a flex item before\n * the remaining extra space is distributed. If the viewport does not appear after setting this property, check its parent elements' content sizes.\n * As an alternative to setting `flex: 1 1 0`, change the setting to `flex: auto` and hide the overflow in the parent element, as follows: `overflow: hidden`.\n * Another approach would be to set the minimum height of all parents to `0`, as follows: `min-height: 0`.\n *\n * For the complete documentation on the flex layout and its features, refer to https://developer.mozilla.org/en-US/docs/Web/CSS/flex.\n *\n *\n * ## Layouting the viewport's slotted content\n *\n * By default, the viewport's content is added to a CSS grid container with a single column, filling remaining space vertically and horizontally.\n * Using the `::part(content)` pseudo element selector, you can configure the grid container or apply a different layout, such as a flex or flow layout.\n *\n * #### Example of adding slotted content to a CSS flex container\n * ```css\n * sci-viewport::part(content) {\n * display: flex;\n * flex-direction: column;\n * }\n * ```\n *\n * #### Example of configuring CSS grid container with two columns\n * ```css\n * sci-viewport::part(content) {\n * grid-template-columns: 1fr 1fr;\n * gap: 1em;\n * }\n * ```\n *\n * ## Styling\n *\n * To customize the default look of SCION components or support different themes, configure the `@scion/components` SCSS module in `styles.scss`.\n * To style a specific `sci-viewport` component, the following CSS variables can be set directly on the component.\n *\n * - sci-viewport-scrollbar-color: Sets the color of the scrollbar.\n *\n * ```css\n * sci-viewport {\n * --sci-viewport-scrollbar-color: blue;\n * }\n * ```\n */\n@Component({\n selector: 'sci-viewport',\n templateUrl: './viewport.component.html',\n styleUrl: './viewport.component.scss',\n encapsulation: ViewEncapsulation.ShadowDom,\n imports: [\n SciScrollableDirective,\n SciScrollbarComponent,\n CdkScrollable,\n ],\n // Required for backward compatibility for zone-based applications to support child components with eager change detection.\n changeDetection: ChangeDetectionStrategy.Eager, // eslint-disable-line @angular-eslint/prefer-on-push-component-change-detection\n host: {\n '(focus)': 'focus()',\n },\n})\nexport class SciViewportComponent {\n\n /**\n * Controls if to use the native scrollbar or a scrollbar that sits on top of the viewport. Defaults to `on-top`.\n */\n public readonly scrollbarStyle = input<ScrollbarStyle>('on-top');\n\n /**\n * Emits when the viewport is scrolled. The event is emitted outside the Angular zone to avoid unnecessary change detection cycles.\n */\n public readonly scroll = output<Event>(); // eslint-disable-line @angular-eslint/no-output-native\n\n private readonly _host = inject(ElementRef).nativeElement as HTMLElement;\n private readonly _viewport = viewChild.required<ElementRef<HTMLDivElement>>('viewport');\n private readonly _viewportClient = viewChild.required<ElementRef<HTMLDivElement>>('viewport_client');\n\n protected readonly nativeScrollbarTrackSizeProvider = inject(SciNativeScrollbarTrackSizeProvider);\n\n constructor() {\n this.installScrollEmitter();\n }\n\n public focus(): void { // do not rename to expose the same focus method like `HTMLElement.focus()`.\n this.viewportElement.focus();\n }\n\n /**\n * Returns the number of pixels that the viewport client is scrolled vertically.\n *\n * @see Element.scrollTop\n */\n public get scrollTop(): number {\n return this.viewportElement.scrollTop;\n }\n\n /**\n * Sets the number of pixels that the viewport client is scrolled vertically.\n *\n * @see Element.scrollTop\n */\n public set scrollTop(scrollTop: number) {\n this.viewportElement.scrollTop = scrollTop;\n }\n\n /**\n * Returns the number of pixels that the viewport client is scrolled horizontally.\n *\n * @see Element.scrollLeft\n */\n public get scrollLeft(): number {\n return this.viewportElement.scrollLeft;\n }\n\n /**\n * Sets the number of pixels that the viewport client is scrolled horizontally.\n *\n * @see Element.scrollLeft\n */\n public set scrollLeft(scrollLeft: number) {\n this.viewportElement.scrollLeft = scrollLeft;\n }\n\n /**\n * Returns the height of the viewport client.\n *\n * @see Element.scrollHeight\n */\n public get scrollHeight(): number {\n return this.viewportElement.scrollHeight;\n }\n\n /**\n * Returns the width of the viewport client.\n *\n * @see Element.scrollWidth\n */\n public get scrollWidth(): number {\n return this.viewportElement.scrollWidth;\n }\n\n /**\n * Returns the viewport {HTMLElement}.\n */\n public get viewportElement(): HTMLElement {\n return this._viewport().nativeElement;\n }\n\n /**\n * Returns the viewport client {HTMLElement}.\n */\n public get viewportClientElement(): HTMLElement {\n return this._viewportClient().nativeElement;\n }\n\n /**\n * Checks if the specified element is scrolled into the viewport.\n *\n * @param element - the element to be checked\n * @param fit - control if the element must fully or partially fit into the viewport\n * @return `true` if the element is scrolled into the viewport, or `false` otherwise.\n */\n public isElementInView(element: ElementRef<HTMLElement> | HTMLElement, fit: 'full' | 'partial'): boolean {\n const elTop = this.computeOffset(element, 'top');\n if (elTop === null) {\n return false;\n }\n const elLeft = this.computeOffset(element, 'left');\n if (elLeft === null) {\n return false;\n }\n\n // Consider elements as scrolled into view when there is no viewport overflow.\n // The calculation of whether an element is scrolled into view may be wrong by a few pixels if the viewport contains elements with decimal sizes.\n // This can happen because `offsetLeft` and `offsetTop` operate on an integer (not a decimal), losing precision that can accumulate.\n // To avoid incorrect calculation when there is no viewport overflow, we consider all contained elements as scrolled into the view.\n if (this.viewportElement.scrollWidth <= this.viewportElement.clientWidth && this.viewportElement.scrollHeight <= this.viewportElement.clientHeight) {\n return true;\n }\n\n const elBottom = elTop + coerceElement(element).offsetHeight;\n const elRight = elLeft + coerceElement(element).offsetWidth;\n\n const vpTop = this.viewportElement.scrollTop;\n const vpLeft = this.viewportElement.scrollLeft;\n const vpBottom = vpTop + this.viewportElement.clientHeight;\n const vpRight = vpLeft + this.viewportElement.clientWidth;\n\n if (fit === 'full') {\n return (elTop >= vpTop && elBottom <= vpBottom) && (elLeft >= vpLeft && elRight <= vpRight);\n }\n else {\n return (elBottom >= vpTop && elTop <= vpBottom) && (elRight >= vpLeft && elLeft <= vpRight);\n }\n }\n\n /**\n * Scrolls the specified element into the viewport.\n *\n * @param element - the element to scroll into the viewport\n * @param offset - the gap between the element and the viewport\n */\n public scrollIntoView(element: ElementRef<HTMLElement> | HTMLElement, offset: number = 50): void {\n const top = this.computeOffset(element, 'top');\n if (top === null) {\n return;\n }\n const left = this.computeOffset(element, 'left');\n if (left === null) {\n return;\n }\n\n this.viewportElement.scrollTop = top - offset;\n this.viewportElement.scrollLeft = left - offset;\n }\n\n /**\n * Computes the distance of the element to the viewport's left or top border.\n *\n * @return distance of the element to the viewport's left or top border, or `null` if not contained\n * in the viewport or the element or any ancestor has the `display` property set to `none`.\n */\n public computeOffset(element: ElementRef<HTMLElement> | HTMLElement, border: 'left' | 'top'): number | null {\n let offset = 0;\n let el = coerceElement(element);\n do {\n offset += (border === 'left' ? el.offsetLeft : el.offsetTop);\n const offsetParent = el.offsetParent;\n if (offsetParent === null) {\n // `offsetParent` is `null` in the following situations:\n // - The element or any ancestor has the `display` property set to `none`\n // - The element has the position property set to fixed (Firefox returns <body>).\n // - The element is <body> or <html>.\n // See https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetParent.\n return null;\n }\n if (!(offsetParent instanceof HTMLElement)) {\n return null;\n }\n el = offsetParent;\n } while (el !== this._host);\n\n return offset;\n }\n\n /**\n * Emits when the scroll position changes.\n */\n private installScrollEmitter(): void {\n const zone = inject(NgZone);\n effect(onCleanup => {\n const viewport = this._viewport();\n untracked(() => {\n const subscription = fromEvent(viewport.nativeElement, 'scroll')\n .pipe(subscribeIn(fn => zone.runOutsideAngular(fn)))\n .subscribe(event => this.scroll.emit(event));\n onCleanup(() => subscription.unsubscribe());\n });\n });\n }\n}\n\n/**\n * Represents a scrollbar style.\n */\nexport type ScrollbarStyle = 'native' | 'on-top' | 'hidden';\n","<!-- 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' && nativeScrollbarTrackSizeProvider.trackSize() !== null) {\n <sci-scrollbar [direction]=\"'vscroll'\" [viewport]=\"viewport\" class=\"e2e-vertical\"/>\n <sci-scrollbar [direction]=\"'hscroll'\" [viewport]=\"viewport\" class=\"e2e-horizontal\"/>\n}\n","/*\n * Copyright (c) 2018-2019 Swiss Federal Railways\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n */\n\n/*\n * Secondary entrypoint: '@scion/components/viewport'\n *\n * @see https://github.com/ng-packagr/ng-packagr/blob/master/docs/secondary-entrypoints.md\n */\nexport {SciViewportComponent, type ScrollbarStyle} from './viewport.component';\nexport {SciScrollbarComponent} from './scrollbar/scrollbar.component';\nexport {SciScrollableDirective} from './scrollable.directive';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"scion-components-viewport.mjs","sources":["../../../../projects/scion/components/viewport/src/scrolltrack/ɵnative-scrollbar-track-size-provider.service.ts","../../../../projects/scion/components/viewport/src/scrolltrack/native-scrollbar-track-size-provider.service.ts","../../../../projects/scion/components/viewport/src/scrollable.directive.ts","../../../../projects/scion/components/viewport/src/scrollbar/scrollbar.component.ts","../../../../projects/scion/components/viewport/src/scrollbar/scrollbar.component.html","../../../../projects/scion/components/viewport/src/viewport.component.ts","../../../../projects/scion/components/viewport/src/viewport.component.html","../../../../projects/scion/components/viewport/src/public_api.ts","../../../../projects/scion/components/viewport/src/scion-components-viewport.ts"],"sourcesContent":["/*\n * Copyright (c) 2018-2026 Swiss Federal Railways\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n */\n\nimport {DOCUMENT, inject, Injectable, NgZone, Signal} from '@angular/core';\nimport {fromEvent} from 'rxjs';\nimport {debounceTime, distinctUntilChanged, map, startWith} from 'rxjs/operators';\nimport {toSignal} from '@angular/core/rxjs-interop';\nimport {subscribeIn} from '@scion/toolkit/operators';\nimport {SciNativeScrollbarTrackSize, SciNativeScrollbarTrackSizeProvider} from './native-scrollbar-track-size-provider.service';\n\n/** @inheritDoc */\n@Injectable()\nexport class ɵSciNativeScrollbarTrackSizeProvider implements SciNativeScrollbarTrackSizeProvider {\n\n private readonly _document = inject(DOCUMENT);\n\n /** @inheritDoc */\n public readonly trackSize = this.computeNativeScrollbarTrackSize();\n\n private computeNativeScrollbarTrackSize(): Signal<SciNativeScrollbarTrackSize | null> {\n // We compute the size of the native scrollbar track when the browser fires the onresize window event.\n // This event is also fired on page zoom or when displaying a hidden document. Hidden documents do not have\n // a scrollbar track size until being displayed, e.g., after showing hidden iframes.\n const zone = inject(NgZone);\n const trackSize$ = fromEvent(window, 'resize')\n .pipe(\n subscribeIn(fn => zone.runOutsideAngular(fn)),\n debounceTime(5),\n startWith(null), // trigger the initial computation\n map(() => this.calculateTrackSize()),\n distinctUntilChanged((t1, t2) => t1?.hScrollbarTrackHeight === t2?.hScrollbarTrackHeight && t1?.vScrollbarTrackWidth === t2?.vScrollbarTrackWidth),\n );\n return toSignal(trackSize$, {initialValue: null});\n }\n\n /**\n * Computes the native scrollbar track size.\n *\n * @returns native track size, or `null` if the native scrollbars sit on top of the content.\n */\n private calculateTrackSize(): SciNativeScrollbarTrackSize | null {\n // Create temporary viewport and viewport client with native scrollbars to compute the scrolltrack width.\n const viewportDiv = this._document.createElement('div');\n setStyle(viewportDiv, {\n position: 'absolute',\n overflow: 'scroll',\n height: '100px',\n width: '100px',\n border: '0',\n visibility: 'hidden',\n });\n\n const viewportClientDiv = this._document.createElement('div');\n setStyle(viewportClientDiv, {\n height: '100%',\n width: '100%',\n border: '0',\n });\n\n viewportDiv.appendChild(viewportClientDiv);\n this._document.body.appendChild(viewportDiv);\n\n // Do not use client and offset width/height to calculate the size of the scrollbar, as they are rounded, resulting in unwanted spacing when zooming the page.\n const viewportBounds = viewportDiv.getBoundingClientRect();\n const viewportClientBounds = viewportClientDiv.getBoundingClientRect();\n const trackSize: SciNativeScrollbarTrackSize = {\n hScrollbarTrackHeight: viewportBounds.height - viewportClientBounds.height,\n vScrollbarTrackWidth: viewportBounds.width - viewportClientBounds.width,\n };\n\n // Destroy temporary viewport.\n this._document.body.removeChild(viewportDiv);\n if (trackSize.hScrollbarTrackHeight === 0 && trackSize.vScrollbarTrackWidth === 0) {\n return null;\n }\n\n return trackSize;\n }\n}\n\n/**\n * Applies the given style(s) to the given element.\n *\n * Specify styles to be modified by passing a dictionary containing CSS property names (hyphen case).\n * To remove a style, set its value to `null`.\n *\n * @ignore\n */\nfunction setStyle(element: HTMLElement, styles: {[style: string]: string}): void {\n Object.entries(styles).forEach(([name, value]) => element.style.setProperty(name, value));\n}\n","/*\n * Copyright (c) 2018-2026 Swiss Federal Railways\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n */\n\nimport {Injectable, Signal} from '@angular/core';\nimport {ɵSciNativeScrollbarTrackSizeProvider} from './ɵnative-scrollbar-track-size-provider.service';\n\n/**\n * Provides the native scrollbar tracksize.\n */\n@Injectable({providedIn: 'root', useClass: ɵSciNativeScrollbarTrackSizeProvider})\nexport abstract class SciNativeScrollbarTrackSizeProvider {\n\n /**\n * Provides the track size of the native scrollbar, or `null` if the native scrollbars sit on top of the content.\n */\n public abstract readonly trackSize: Signal<SciNativeScrollbarTrackSize | null>;\n}\n\n/**\n * Represents the native scrollbar track size.\n */\nexport interface SciNativeScrollbarTrackSize {\n hScrollbarTrackHeight: number;\n vScrollbarTrackWidth: number;\n}\n","/*\n * Copyright (c) 2018-2019 Swiss Federal Railways\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n */\n\nimport {computed, Directive, effect, ElementRef, inject, input, Renderer2, untracked} from '@angular/core';\nimport {SciNativeScrollbarTrackSize, SciNativeScrollbarTrackSizeProvider} from './scrolltrack/native-scrollbar-track-size-provider.service';\nimport {Dictionary} from '@scion/toolkit/util';\n\n/**\n * Makes the host element natively scrollable and hides native scrollbars by default, unless native scrollbars\n * already sit on top of the viewport (e.g. in OS X).\n *\n * Because there is no cross-browser API to hide scrollbars without losing native scroll support, we set 'overflow'\n * to 'scroll' but shift the native scrollbars out of the visible viewport area. The shift offset is computed upfront.\n *\n * This directive expects its host element to be the only child in document flow in its parent DOM element. It makes the host element\n * fill up the entire space (width and height set to 100%). The parent element must have its CSS `overflow` property set to `hidden`\n * to hide the pushed out native scrollbars.\n *\n * This directive provides the `isNativeScrollbarCropped` signal, which indicates whether native scrollbars are pushed out of the viewport element.\n * In templates, access it via the exported template reference variable `sciScrollable`.\n *\n * ```html\n * <div sciScrollable #sciScrollable=\"sciScrollable\" #viewport>\n * content\n * </div>\n *\n * <!-- Render scrollbars only if native scrollbars are pushed out of the viewport element. -->\n * @if (sciScrollable.isNativeScrollbarCropped()) {\n * <sci-scrollbar [viewport]=\"viewport\" direction=\"vscroll\"/>\n * <sci-scrollbar [viewport]=\"viewport\" direction=\"hscroll\"/>\n * }\n * ```\n */\n@Directive({\n selector: '[sciScrollable]',\n exportAs: 'sciScrollable',\n})\nexport class SciScrollableDirective {\n\n /**\n * Controls whether to display native scrollbars.\n *\n * Has no effect if the native scrollbar sits on top of the content, e.g. in OS X.\n */\n public readonly displayNativeScrollbar = input(false, {alias: 'sciScrollableDisplayNativeScrollbar'});\n\n private readonly _host = inject(ElementRef<HTMLDivElement>).nativeElement as HTMLElement;\n private readonly _renderer = inject(Renderer2);\n private readonly _nativeScrollbarTrackSizeProvider = inject(SciNativeScrollbarTrackSizeProvider);\n\n /**\n * Indicates whether native scrollbars are pushed out of the viewport element.\n */\n public readonly isNativeScrollbarCropped = computed(() => !this.displayNativeScrollbar() && this._nativeScrollbarTrackSizeProvider.trackSize() !== null);\n\n constructor() {\n this.controlDisplayOfNativeScrollbar();\n }\n\n /**\n * Controls the display of the native scrollbar based on this directive's configuration.\n */\n private controlDisplayOfNativeScrollbar(): void {\n effect(() => {\n if (this.isNativeScrollbarCropped()) {\n const trackSize = this._nativeScrollbarTrackSizeProvider.trackSize()!;\n untracked(() => this.shiftNativeScrollbars(trackSize));\n }\n else {\n untracked(() => this.useNativeScrollbars());\n }\n });\n }\n\n /**\n * Uses the native scrollbars when content overflows.\n */\n private useNativeScrollbars(): void {\n this.setStyle(this._host, {\n overflow: 'auto',\n width: '100%',\n height: '100%',\n marginRight: 0,\n marginBottom: 0,\n });\n }\n\n /**\n * Shifts the native scrollbars out of the visible viewport area.\n */\n private shiftNativeScrollbars(trackSize: SciNativeScrollbarTrackSize): void {\n this.setStyle(this._host, {\n overflow: 'scroll',\n width: `calc(100% + ${trackSize.vScrollbarTrackWidth}px`,\n height: `calc(100% + ${trackSize.hScrollbarTrackHeight}px`,\n marginRight: `-${trackSize.vScrollbarTrackWidth}px`,\n marginBottom: `-${trackSize.hScrollbarTrackHeight}px`,\n });\n }\n\n private setStyle(element: Element, style: Dictionary): void {\n Object.keys(style).forEach(key => this._renderer.setStyle(element, key, style[key]));\n }\n}\n","/*\n * Copyright (c) 2018-2019 Swiss Federal Railways\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n */\n\nimport {Component, computed, DestroyRef, DOCUMENT, effect, ElementRef, inject, input, NgZone, signal, untracked, viewChild} from '@angular/core';\nimport {concatWith, exhaustMap, finalize, fromEvent, merge, mergeWith, Observable, of, race, tap, timer} from 'rxjs';\nimport {debounceTime, map, startWith, switchMap, takeUntil, withLatestFrom} from 'rxjs/operators';\nimport {fromMutation$, fromResize$} from '@scion/toolkit/observable';\nimport {subscribeIn} from '@scion/toolkit/operators';\nimport {takeUntilDestroyed} from '@angular/core/rxjs-interop';\n\n/**\n * Renders a vertical or horizontal scrollbar.\n *\n * The scrollbar features the following functionality:\n * - allows to move the thumb by mouse\n * - enlarges the thumb if the mouse pointer is near the thumb\n * - allows paging on mousedown on the scroll track\n *\n * ### Styling:\n *\n * To customize the default look of SCION components or support different themes, configure the `@scion/components` SCSS module in `styles.scss`.\n * To style a specific `sci-scrollbar` component, the following CSS variables can be set directly on the component.\n *\n * - --sci-scrollbar-color: Sets the color of the scrollbar.\n *\n * Example:\n *\n * ```css\n *\n * sci-scrollbar {\n * --sci-scrollbar-color: blue;\n * }\n * ```\n */\n@Component({\n selector: 'sci-scrollbar',\n templateUrl: './scrollbar.component.html',\n styleUrl: './scrollbar.component.scss',\n host: {\n '[class.vertical]': 'vertical()',\n '[class.horizontal]': 'horizontal()',\n '[class.scrolling]': 'scrolling()',\n '[class.overflow]': 'overflow()',\n '[style.--ɵsci-scrollbar-thumb-position-fr]': 'thumbPositionFr()',\n '[style.--ɵsci-scrollbar-thumb-size-fr]': 'thumbSizeFr()',\n },\n})\nexport class SciScrollbarComponent {\n\n /**\n * Timeout for debouncing viewport resize events that trigger the scroll position computation.\n *\n * Debouncing is particularly important in the context of Angular animations, since they continuously\n * trigger resize events. Debouncing prevents the scrollbar from flickering, for example, when the user\n * expands a panel that contains a viewport.\n *\n * @internal\n */\n public static readonly VIEWPORT_RESIZE_DEBOUNCE_TIME = 50;\n\n /**\n * Specifies the direction of the scrollbar. Defaults to a vertical scrollbar.\n */\n public readonly direction = input<'vscroll' | 'hscroll'>('vscroll');\n\n /**\n * Specifies the viewport associated with the scrollbar.\n */\n public readonly viewport = input.required<HTMLElement>();\n\n private readonly _host = inject(ElementRef).nativeElement as HTMLElement;\n private readonly _document = inject(DOCUMENT);\n private readonly _zone = inject(NgZone);\n private readonly _destroyRef = inject(DestroyRef);\n private readonly _thumbElement = viewChild.required<ElementRef<HTMLDivElement>>('thumb_handle');\n\n protected readonly vertical = computed(() => this.direction() === 'vscroll');\n protected readonly horizontal = computed(() => !this.vertical());\n protected readonly scrolling = signal(false);\n protected readonly overflow = signal(false);\n protected readonly thumbSizeFr = signal(0);\n protected readonly thumbPositionFr = signal(0);\n\n constructor() {\n this.installScrollPositionRenderer();\n }\n\n /**\n * Computes the scroll position and updates CSS variables to render the scroll position.\n */\n private renderScrollPosition(): void {\n NgZone.assertNotInAngularZone();\n const viewportSize = this.viewportSize();\n const viewportClientSize = this.viewportClientSize();\n\n this.thumbPositionFr.set(this.viewportScrollPosition() / viewportClientSize);\n this.thumbSizeFr.set(viewportSize / viewportClientSize);\n this.overflow.set(viewportClientSize > viewportSize);\n }\n\n /**\n * Method invoked when clicking on the scrollbar thumb.\n */\n protected onThumbMouseDown(mousedownEvent: MouseEvent): void {\n if (mousedownEvent.button !== 0) {\n return;\n }\n\n this.scrolling.set(true);\n\n // Prevent text selection during drag.\n mousedownEvent.preventDefault();\n\n // Calculate screen offset to convert screen coordinates into client coordinates, required for `sci-mousemove` events which originate from other documents (iframes).\n const {screenOffsetX, screenOffsetY} = calculateScreenOffset(mousedownEvent);\n\n // Memoize offset where thumb was clicked.\n const thumbStartOffset = this.vertical() ? mousedownEvent.offsetY : mousedownEvent.offsetX;\n\n // 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.\n const mouseUp$ = race(fromEvent<MouseEvent>(this._document, 'mouseup', {capture: true, once: true}), fromEvent<MouseEvent>(this._document, 'sci-mouseup', {once: true}))\n .pipe(tap(mouseupEvent => mouseupEvent.stopPropagation()));\n\n // Track pointer until mouse release.\n merge(fromEvent<MouseEvent>(this._document, 'mousemove'), fromEvent<MouseEvent>(this._document, 'sci-mousemove'))\n .pipe(\n subscribeIn(fn => this._zone.runOutsideAngular(fn)),\n takeUntilDestroyed(this._destroyRef),\n takeUntil(mouseUp$),\n finalize(() => this.scrolling.set(false)),\n )\n .subscribe(mousemoveEvent => {\n NgZone.assertNotInAngularZone();\n\n // Prevent user agent scrolling while during drag.\n mousemoveEvent.preventDefault();\n\n // Calculate new thumb position.\n const pointerPosition = this.vertical() ? mousemoveEvent.screenY - screenOffsetY : mousemoveEvent.screenX - screenOffsetX;\n this.scrollViewport(pointerPosition - thumbStartOffset);\n });\n }\n\n /**\n * Method invoked when clicking on the scrollbar track.\n *\n * Scrolls in discrete steps to the pointer, then switches to regular scrolling until releasing the mouse.\n */\n protected onScrollTrackMouseDown(event: MouseEvent): void {\n this.scrolling.set(true);\n\n // Prevent text selection during drag.\n event.preventDefault();\n\n const mouseMove$ = merge(fromEvent<MouseEvent>(this._document, 'mousemove'), fromEvent<MouseEvent>(this._document, 'sci-mousemove'));\n\n // Handle the event in the capture phase and stop propagation to not close a potential overlay when releasing the mouse outside the overlay.\n const mouseUp$ = race(fromEvent<MouseEvent>(this._document, 'mouseup', {capture: true, once: true}), fromEvent<MouseEvent>(this._document, 'sci-mouseup', {once: true}))\n .pipe(tap(mouseupEvent => mouseupEvent.stopPropagation()));\n\n // Calculate screen offset to convert screen coordinates into client coordinates, required for `sci-mousemove` events which originate from other documents (iframes).\n const {screenOffsetX, screenOffsetY} = calculateScreenOffset(event);\n\n // Scroll in discrete steps to the pointer position, then switch to regular scrolling.\n timer(250, 50)\n .pipe(\n // Track current pointer position.\n withLatestFrom(mouseMove$.pipe(startWith(event)), (_tick, event) => event),\n // Scroll immediately on initial click.\n startWith(event),\n subscribeIn(fn => this._zone.runOutsideAngular(fn)),\n exhaustMap(event => {\n const pointerPosition = this.vertical() ? event.screenY - screenOffsetY : event.screenX - screenOffsetX;\n const [thumbStartPosition, thumbEndPosition] = this.thumbPosition();\n const thumbSize = thumbEndPosition - thumbStartPosition;\n\n // Step scroll until the pointer hits the thumb.\n if (!isBetween(pointerPosition, {from: thumbStartPosition - thumbSize, to: thumbEndPosition + thumbSize})) {\n const scrollingDown = pointerPosition > thumbEndPosition;\n return of(scrollingDown ? thumbStartPosition + thumbSize : thumbStartPosition - thumbSize);\n }\n\n // Switch to \"smooth scrolling\" following the pointer.\n return of(event)\n .pipe(\n concatWith(mouseMove$),\n map(event => (this.vertical() ? event.screenY - screenOffsetY : event.screenX - screenOffsetX) - (thumbSize / 2)),\n );\n }),\n // Stop on mouse release.\n takeUntil(mouseUp$),\n finalize(() => this.scrolling.set(false)),\n )\n .subscribe((thumbPosition: number) => {\n NgZone.assertNotInAngularZone();\n this.scrollViewport(thumbPosition);\n });\n }\n\n /**\n * Renders the current scroll position when the viewport is scrolled.\n */\n private installScrollPositionRenderer(): void {\n effect(onCleanup => {\n const viewport = this.viewport();\n\n untracked(() => {\n const subscription = viewportScroll$(viewport)\n .pipe(\n mergeWith(viewportSize$(viewport, {debounceTime: SciScrollbarComponent.VIEWPORT_RESIZE_DEBOUNCE_TIME})),\n mergeWith(viewportClientSize$(viewport, {debounceTime: SciScrollbarComponent.VIEWPORT_RESIZE_DEBOUNCE_TIME})),\n subscribeIn(fn => this._zone.runOutsideAngular(fn)),\n )\n .subscribe(() => this.renderScrollPosition());\n onCleanup(() => subscription.unsubscribe());\n });\n });\n }\n\n /**\n * Moves the scrollbar thumb to the specified position, scrolling the viewport accordingly.\n *\n * The thumb position must be given in client coordinates (relative to the top-left corner of the page viewport).\n */\n private scrollViewport(thumbPosition: number): void {\n const [scrollbarComponentStartPosition] = this.scrollbarComponentPosition();\n const scrollbarBorderWidth = this.vertical() ? this._host.clientTop : this._host.clientLeft;\n const scrollRatio = clamp((thumbPosition - scrollbarComponentStartPosition - scrollbarBorderWidth) / (this.trackSize() - this.thumbSize()), {min: 0, max: 1});\n const viewportScrollPosition = scrollRatio * (this.viewportClientSize() - this.viewportSize());\n\n if (this.vertical()) {\n this.viewport().scrollTop = viewportScrollPosition;\n }\n else {\n this.viewport().scrollLeft = viewportScrollPosition;\n }\n }\n\n /**\n * Returns the position of this component in client coordinates.\n *\n * Returned coordinates are relative to the top-left corner of the page viewport.\n * Depending on the scrollbar orientation, returned coordinates are `[top, bottom]` or `[left, right]`.\n */\n private scrollbarComponentPosition(): [number, number] {\n const boundingBox = this._host.getBoundingClientRect();\n return this.vertical() ? [boundingBox.top, boundingBox.bottom] : [boundingBox.left, boundingBox.right];\n }\n\n /**\n * Returns the size of the viewport in pixels.\n *\n * The viewport is the container for scrollable content (viewport client), displaying scrollbars if it overflows.\n * Depending on the scrollbar orientation, the returned size is `viewport.clientHeight` or `viewport.clientWidth`.\n */\n private viewportSize(): number {\n return this.vertical() ? this.viewport().clientHeight : this.viewport().clientWidth;\n }\n\n /**\n * Returns the size of the viewport client in pixels.\n *\n * The viewport client represents scrollable content displayed in the viewport.\n * Depending on the scrollbar orientation, the returned size is `viewport.scrollHeight` or `viewport.scrollWidth`.\n */\n private viewportClientSize(): number {\n return this.vertical() ? this.viewport().scrollHeight : this.viewport().scrollWidth;\n }\n\n /**\n * Returns the viewport's scroll position in pixels.\n *\n * Depending on the scrollbar orientation, the returned position is `viewport.scrollTop` or `viewport.scrollLeft`.\n */\n private viewportScrollPosition(): number {\n return this.vertical() ? this.viewport().scrollTop : this.viewport().scrollLeft;\n }\n\n /**\n * Returns the size of the scrollbar thumb in pixels.\n *\n * The thumb is the handle used to scroll the scrollbar.\n */\n private thumbSize(): number {\n const thumbElement = this._thumbElement().nativeElement;\n return this.vertical() ? thumbElement.offsetHeight : thumbElement.offsetWidth;\n }\n\n /**\n * Returns the current thumb position in client coordinates.\n *\n * Returned coordinates are relative to the top-left corner of the page viewport.\n * Depending on the scrollbar orientation, returned coordinates are `[top, bottom]` or `[left, right]`.\n */\n private thumbPosition(): [number, number] {\n const boundingBox = this._thumbElement().nativeElement.getBoundingClientRect();\n return this.vertical() ? [boundingBox.top, boundingBox.bottom] : [boundingBox.left, boundingBox.right];\n }\n\n /**\n * Returns the size of the scrollbar track in pixels.\n *\n * The scrollbar track is the track along which the scrollbar thumb moves.\n */\n private trackSize(): number {\n return this.vertical() ? this._host.clientHeight : this._host.clientWidth;\n }\n}\n\n/**\n * Emits whenever the viewport is scrolled.\n */\nfunction viewportScroll$(viewport: HTMLElement): Observable<void> {\n return fromEvent(viewport, 'scroll', {passive: true}).pipe(map(() => undefined));\n}\n\n/**\n * Emits on subscription, and then each time the size of the viewport changes.\n */\nfunction viewportSize$(viewport: HTMLElement, options: {debounceTime: number}): Observable<void> {\n return fromResize$(viewport)\n .pipe(\n // Debouncing is particularly important in the context of Angular animations, since they continuously\n // trigger resize events. Debouncing prevents the scrollbar from flickering, for example, when the user\n // expands a panel that contains a viewport.\n debounceTime(options.debounceTime),\n map(() => undefined),\n );\n}\n\n/**\n * Emits on subscription, and then each time the size or style property of the viewport client changes.\n */\nfunction viewportClientSize$(viewport: HTMLElement, options: {debounceTime: number}): Observable<void> {\n return children$(viewport)\n .pipe(\n switchMap(children => merge(...children.map(child => merge(\n fromResize$(child),\n // Observe style mutations since some transformations change the scroll position without necessarily triggering a dimension change,\n // e.g., `scale` or `translate` used by some virtual scroll implementations\n fromMutation$(child, {subtree: false, childList: false, attributeFilter: ['style']})),\n ))),\n // Debouncing is particularly important in the context of Angular animations, since they continuously\n // trigger resize events. Debouncing prevents the scrollbar from flickering, for example, when the user\n // expands a panel that contains a viewport.\n debounceTime(options.debounceTime),\n map(() => undefined),\n );\n}\n\n/**\n * Emits the children of the passed element, and then each time child elements are added or removed.\n */\nfunction children$(element: HTMLElement): Observable<HTMLElement[]> {\n return fromMutation$(element, {subtree: false, childList: true})\n .pipe(\n startWith(undefined as void),\n map(() => Array.from(element.children)\n // Map to slotted content if a slot (Shadow DOM).\n .flatMap(child => child instanceof HTMLSlotElement ? child.assignedElements() : child)\n // Filter HTML elements.\n .filter((child: Element): child is HTMLElement => child instanceof HTMLElement)),\n );\n}\n\n/**\n * Returns the value clamped to the inclusive range of min and max.\n */\nfunction clamp(value: number, minmax: {min: number; max: number}): number {\n return Math.max(minmax.min, Math.min(value, minmax.max));\n}\n\n/**\n * Returns whether the value is between the specified range (inclusive).\n */\nfunction isBetween(value: number, range: {from: number; to: number}): boolean {\n return value >= range.from && value <= range.to;\n}\n\n/**\n * Calculates the distance between the top-left corner of the screen (monitor) and the top-left corner of the page viewport of this document.\n *\n * Use to convert screen coordinates from `sci-mousemove` and `sci-mouseup` events into client coordinates relative to the page viewport of the current document.\n *\n * 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\n * relative to the source document, not the current one.\n */\nfunction calculateScreenOffset(mousedownEvent: MouseEvent): {screenOffsetX: number; screenOffsetY: number} {\n return {\n screenOffsetX: mousedownEvent.screenX - mousedownEvent.clientX,\n screenOffsetY: mousedownEvent.screenY - mousedownEvent.clientY,\n };\n}\n","<!-- 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","/*\n * Copyright (c) 2018-2019 Swiss Federal Railways\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n */\n\nimport {ChangeDetectionStrategy, Component, effect, ElementRef, inject, input, NgZone, output, untracked, viewChild, ViewEncapsulation} from '@angular/core';\nimport {coerceElement} from '@angular/cdk/coercion';\nimport {SciScrollableDirective} from './scrollable.directive';\nimport {SciScrollbarComponent} from './scrollbar/scrollbar.component';\nimport {fromEvent} from 'rxjs';\nimport {subscribeIn} from '@scion/toolkit/operators';\nimport {CdkScrollable} from '@angular/cdk/scrolling';\n\n/**\n * Represents a viewport with slotted content (`<ng-content>`) used as scrollable content. By default, content is added to a CSS grid layout.\n *\n * The viewport component displays scrollbars when its content overflows. Scrollbars are displayed on top of the content, not next to it.\n * The component uses the native scrollbars of the operating system if they are already sitting on top, or falls back and renders scrollbars on top otherwise.\n * The viewport remains natively scrollable with the native scrollbars shifted out of the viewport's visible area. Consequently, the viewport keeps supporting\n * native scrolling features such as touch gestures, scroll speed acceleration, or scrolling near the viewport edges during drag-and-drop operations.\n *\n * ```html\n * <sci-viewport>\n * your content\n * </sci-viewport>\n * ```\n *\n * ## Adding the viewport to a layout\n *\n * Typically, you would add the viewport component to a flexible layout, filling the remaining space vertically and horizontally, such as a flexbox container\n * with the viewport's `flex` CSS property set to either `flex: auto` or `flex: 1 1 0`.\n *\n * The viewport is sized according to its content width and height. It grows to absorb any free space, thus overflowing its content only when encountering\n * a layout constraint. Depending on the layout, different steps may be necessary to prevent the viewport from growing to infinity.\n *\n * - If practical, give the viewport a fixed size or a maximum size.\n * - If you add the viewport to a flexbox layout, make sure that it cannot exceed the available space. Instead, the viewport should fill the remaining space,\n * vertically and horizontally. Be aware that, by default, a flex item does not shrink below its minimum content size. To change this, set the viewport's\n * `flex-basis` to `0` (instead of `auto`), or use the CSS shorthand property `flex: 1 1 0`. The `flex-basis` defines the default size of a flex item before\n * the remaining extra space is distributed. If the viewport does not appear after setting this property, check its parent elements' content sizes.\n * As an alternative to setting `flex: 1 1 0`, change the setting to `flex: auto` and hide the overflow in the parent element, as follows: `overflow: hidden`.\n * Another approach would be to set the minimum height of all parents to `0`, as follows: `min-height: 0`.\n *\n * For the complete documentation on the flex layout and its features, refer to https://developer.mozilla.org/en-US/docs/Web/CSS/flex.\n *\n *\n * ## Layouting the viewport's slotted content\n *\n * By default, the viewport's content is added to a CSS grid container with a single column, filling remaining space vertically and horizontally.\n * Using the `::part(content)` pseudo element selector, you can configure the grid container or apply a different layout, such as a flex or flow layout.\n *\n * #### Example of adding slotted content to a CSS flex container\n * ```css\n * sci-viewport::part(content) {\n * display: flex;\n * flex-direction: column;\n * }\n * ```\n *\n * #### Example of configuring CSS grid container with two columns\n * ```css\n * sci-viewport::part(content) {\n * grid-template-columns: 1fr 1fr;\n * gap: 1em;\n * }\n * ```\n *\n * ## Styling\n *\n * To customize the default look of SCION components or support different themes, configure the `@scion/components` SCSS module in `styles.scss`.\n * To style a specific `sci-viewport` component, the following CSS variables can be set directly on the component.\n *\n * - sci-viewport-scrollbar-color: Sets the color of the scrollbar.\n *\n * ```css\n * sci-viewport {\n * --sci-viewport-scrollbar-color: blue;\n * }\n * ```\n */\n@Component({\n selector: 'sci-viewport',\n templateUrl: './viewport.component.html',\n styleUrl: './viewport.component.scss',\n encapsulation: ViewEncapsulation.ShadowDom,\n imports: [\n SciScrollableDirective,\n SciScrollbarComponent,\n CdkScrollable,\n ],\n // Required for backward compatibility for zone-based applications to support child components with eager change detection.\n changeDetection: ChangeDetectionStrategy.Eager, // eslint-disable-line @angular-eslint/prefer-on-push-component-change-detection\n host: {\n '(focus)': 'focus()',\n },\n})\nexport class SciViewportComponent {\n\n /**\n * Controls if to use the native scrollbar or a scrollbar that sits on top of the viewport. Defaults to `on-top`.\n */\n public readonly scrollbarStyle = input<ScrollbarStyle>('on-top');\n\n /**\n * Emits when the viewport is scrolled. The event is emitted outside the Angular zone to avoid unnecessary change detection cycles.\n */\n public readonly scroll = output<Event>(); // eslint-disable-line @angular-eslint/no-output-native\n\n private readonly _host = inject(ElementRef).nativeElement as HTMLElement;\n private readonly _viewport = viewChild.required<ElementRef<HTMLDivElement>>('viewport');\n private readonly _viewportClient = viewChild.required<ElementRef<HTMLDivElement>>('viewport_client');\n\n constructor() {\n this.installScrollEmitter();\n }\n\n public focus(): void { // do not rename to expose the same focus method like `HTMLElement.focus()`.\n this.viewportElement.focus();\n }\n\n /**\n * Returns the number of pixels that the viewport client is scrolled vertically.\n *\n * @see Element.scrollTop\n */\n public get scrollTop(): number {\n return this.viewportElement.scrollTop;\n }\n\n /**\n * Sets the number of pixels that the viewport client is scrolled vertically.\n *\n * @see Element.scrollTop\n */\n public set scrollTop(scrollTop: number) {\n this.viewportElement.scrollTop = scrollTop;\n }\n\n /**\n * Returns the number of pixels that the viewport client is scrolled horizontally.\n *\n * @see Element.scrollLeft\n */\n public get scrollLeft(): number {\n return this.viewportElement.scrollLeft;\n }\n\n /**\n * Sets the number of pixels that the viewport client is scrolled horizontally.\n *\n * @see Element.scrollLeft\n */\n public set scrollLeft(scrollLeft: number) {\n this.viewportElement.scrollLeft = scrollLeft;\n }\n\n /**\n * Returns the height of the viewport client.\n *\n * @see Element.scrollHeight\n */\n public get scrollHeight(): number {\n return this.viewportElement.scrollHeight;\n }\n\n /**\n * Returns the width of the viewport client.\n *\n * @see Element.scrollWidth\n */\n public get scrollWidth(): number {\n return this.viewportElement.scrollWidth;\n }\n\n /**\n * Returns the viewport {HTMLElement}.\n */\n public get viewportElement(): HTMLElement {\n return this._viewport().nativeElement;\n }\n\n /**\n * Returns the viewport client {HTMLElement}.\n */\n public get viewportClientElement(): HTMLElement {\n return this._viewportClient().nativeElement;\n }\n\n /**\n * Checks if the specified element is scrolled into the viewport.\n *\n * @param element - the element to be checked\n * @param fit - control if the element must fully or partially fit into the viewport\n * @return `true` if the element is scrolled into the viewport, or `false` otherwise.\n */\n public isElementInView(element: ElementRef<HTMLElement> | HTMLElement, fit: 'full' | 'partial'): boolean {\n const elTop = this.computeOffset(element, 'top');\n if (elTop === null) {\n return false;\n }\n const elLeft = this.computeOffset(element, 'left');\n if (elLeft === null) {\n return false;\n }\n\n // Consider elements as scrolled into view when there is no viewport overflow.\n // The calculation of whether an element is scrolled into view may be wrong by a few pixels if the viewport contains elements with decimal sizes.\n // This can happen because `offsetLeft` and `offsetTop` operate on an integer (not a decimal), losing precision that can accumulate.\n // To avoid incorrect calculation when there is no viewport overflow, we consider all contained elements as scrolled into the view.\n if (this.viewportElement.scrollWidth <= this.viewportElement.clientWidth && this.viewportElement.scrollHeight <= this.viewportElement.clientHeight) {\n return true;\n }\n\n const elBottom = elTop + coerceElement(element).offsetHeight;\n const elRight = elLeft + coerceElement(element).offsetWidth;\n\n const vpTop = this.viewportElement.scrollTop;\n const vpLeft = this.viewportElement.scrollLeft;\n const vpBottom = vpTop + this.viewportElement.clientHeight;\n const vpRight = vpLeft + this.viewportElement.clientWidth;\n\n if (fit === 'full') {\n return (elTop >= vpTop && elBottom <= vpBottom) && (elLeft >= vpLeft && elRight <= vpRight);\n }\n else {\n return (elBottom >= vpTop && elTop <= vpBottom) && (elRight >= vpLeft && elLeft <= vpRight);\n }\n }\n\n /**\n * Scrolls the specified element into the viewport.\n *\n * @param element - the element to scroll into the viewport\n * @param offset - the gap between the element and the viewport\n */\n public scrollIntoView(element: ElementRef<HTMLElement> | HTMLElement, offset: number = 50): void {\n const top = this.computeOffset(element, 'top');\n if (top === null) {\n return;\n }\n const left = this.computeOffset(element, 'left');\n if (left === null) {\n return;\n }\n\n this.viewportElement.scrollTop = top - offset;\n this.viewportElement.scrollLeft = left - offset;\n }\n\n /**\n * Computes the distance of the element to the viewport's left or top border.\n *\n * @return distance of the element to the viewport's left or top border, or `null` if not contained\n * in the viewport or the element or any ancestor has the `display` property set to `none`.\n */\n public computeOffset(element: ElementRef<HTMLElement> | HTMLElement, border: 'left' | 'top'): number | null {\n let offset = 0;\n let el = coerceElement(element);\n do {\n offset += (border === 'left' ? el.offsetLeft : el.offsetTop);\n const offsetParent = el.offsetParent;\n if (offsetParent === null) {\n // `offsetParent` is `null` in the following situations:\n // - The element or any ancestor has the `display` property set to `none`\n // - The element has the position property set to fixed (Firefox returns <body>).\n // - The element is <body> or <html>.\n // See https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetParent.\n return null;\n }\n if (!(offsetParent instanceof HTMLElement)) {\n return null;\n }\n el = offsetParent;\n } while (el !== this._host);\n\n return offset;\n }\n\n /**\n * Emits when the scroll position changes.\n */\n private installScrollEmitter(): void {\n const zone = inject(NgZone);\n effect(onCleanup => {\n const viewport = this._viewport();\n untracked(() => {\n const subscription = fromEvent(viewport.nativeElement, 'scroll')\n .pipe(subscribeIn(fn => zone.runOutsideAngular(fn)))\n .subscribe(event => this.scroll.emit(event));\n onCleanup(() => subscription.unsubscribe());\n });\n });\n }\n}\n\n/**\n * Represents a scrollbar style.\n */\nexport type ScrollbarStyle = 'native' | 'on-top' | 'hidden';\n","<!-- 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","/*\n * Copyright (c) 2018-2019 Swiss Federal Railways\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n */\n\n/*\n * Secondary entrypoint: '@scion/components/viewport'\n *\n * @see https://github.com/ng-packagr/ng-packagr/blob/master/docs/secondary-entrypoints.md\n */\nexport {SciViewportComponent, type ScrollbarStyle} from './viewport.component';\nexport {SciScrollbarComponent} from './scrollbar/scrollbar.component';\nexport {SciScrollableDirective} from './scrollable.directive';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scion/components",
3
- "version": "22.0.0",
3
+ "version": "22.2.0",
4
4
  "description": "Provides a collection of Angular components and directives primarily for use in SCION libraries such as `@scion/workbench` and `@scion/microfrontend-platform`. This library is not a comprehensive component library as its focus is on SCION requirements.",
5
5
  "license": "EPL-2.0",
6
6
  "private": false,
@@ -1,34 +1,5 @@
1
1
  import * as _angular_core from '@angular/core';
2
- import { Signal, ElementRef } from '@angular/core';
3
-
4
- /**
5
- * Provides the native scrollbar tracksize.
6
- */
7
- declare class SciNativeScrollbarTrackSizeProvider {
8
- private readonly _document;
9
- private readonly _zone;
10
- /**
11
- * Provides the track size of the native scrollbar, or `null` if the native scrollbars sit on top of the content.
12
- */
13
- trackSize: Signal<NativeScrollbarTrackSize | null>;
14
- constructor();
15
- /**
16
- * Computes the native scrollbar track size.
17
- *
18
- * @returns native track size, or `null` if the native scrollbars sit on top of the content.
19
- */
20
- private computeTrackSize;
21
- private createNativeScrollbarTrackSizeSignal;
22
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<SciNativeScrollbarTrackSizeProvider, never>;
23
- static ɵprov: _angular_core.ɵɵInjectableDeclaration<SciNativeScrollbarTrackSizeProvider>;
24
- }
25
- /**
26
- * Represents the native scrollbar track size.
27
- */
28
- interface NativeScrollbarTrackSize {
29
- hScrollbarTrackHeight: number;
30
- vScrollbarTrackWidth: number;
31
- }
2
+ import { ElementRef } from '@angular/core';
32
3
 
33
4
  /**
34
5
  * Represents a viewport with slotted content (`<ng-content>`) used as scrollable content. By default, content is added to a CSS grid layout.
@@ -109,7 +80,6 @@ declare class SciViewportComponent {
109
80
  private readonly _host;
110
81
  private readonly _viewport;
111
82
  private readonly _viewportClient;
112
- protected readonly nativeScrollbarTrackSizeProvider: SciNativeScrollbarTrackSizeProvider;
113
83
  constructor();
114
84
  focus(): void;
115
85
  /**
@@ -194,7 +164,7 @@ type ScrollbarStyle = 'native' | 'on-top' | 'hidden';
194
164
  * Renders a vertical or horizontal scrollbar.
195
165
  *
196
166
  * The scrollbar features the following functionality:
197
- * - allows to move the thumb by mouse or touch
167
+ * - allows to move the thumb by mouse
198
168
  * - enlarges the thumb if the mouse pointer is near the thumb
199
169
  * - allows paging on mousedown on the scroll track
200
170
  *
@@ -203,7 +173,7 @@ type ScrollbarStyle = 'native' | 'on-top' | 'hidden';
203
173
  * To customize the default look of SCION components or support different themes, configure the `@scion/components` SCSS module in `styles.scss`.
204
174
  * To style a specific `sci-scrollbar` component, the following CSS variables can be set directly on the component.
205
175
  *
206
- * - sci-scrollbar-color: Sets the color of the scrollbar.
176
+ * - --sci-scrollbar-color: Sets the color of the scrollbar.
207
177
  *
208
178
  * Example:
209
179
  *
@@ -220,7 +190,7 @@ declare class SciScrollbarComponent {
220
190
  */
221
191
  readonly direction: _angular_core.InputSignal<"vscroll" | "hscroll">;
222
192
  /**
223
- * The viewport to provide scrollbars for.
193
+ * Specifies the viewport associated with the scrollbar.
224
194
  */
225
195
  readonly viewport: _angular_core.InputSignal<HTMLElement>;
226
196
  private readonly _host;
@@ -228,49 +198,83 @@ declare class SciScrollbarComponent {
228
198
  private readonly _zone;
229
199
  private readonly _destroyRef;
230
200
  private readonly _thumbElement;
231
- private readonly _lastDragPosition;
232
201
  protected readonly vertical: _angular_core.Signal<boolean>;
233
202
  protected readonly horizontal: _angular_core.Signal<boolean>;
234
- protected readonly scrolling: _angular_core.Signal<boolean>;
235
- private _overflow;
236
- private _thumbSizeFr;
237
- private _thumbPositionFr;
203
+ protected readonly scrolling: _angular_core.WritableSignal<boolean>;
204
+ protected readonly overflow: _angular_core.WritableSignal<boolean>;
205
+ protected readonly thumbSizeFr: _angular_core.WritableSignal<number>;
206
+ protected readonly thumbPositionFr: _angular_core.WritableSignal<number>;
238
207
  constructor();
239
208
  /**
240
- * Computes the scroll position and updates CSS variables to render the scroll position in the UI.
209
+ * Computes the scroll position and updates CSS variables to render the scroll position.
241
210
  */
242
211
  private renderScrollPosition;
243
- protected onTouchStart(event: TouchEvent): void;
244
- protected onTouchMove(event: TouchEvent): void;
245
- protected onTouchEnd(event: TouchEvent): void;
246
- protected onMouseDown(mousedownEvent: MouseEvent): void;
247
- protected onScrollTrackMouseDown(event: MouseEvent, direction: 'up' | 'down'): void;
212
+ /**
213
+ * Method invoked when clicking on the scrollbar thumb.
214
+ */
215
+ protected onThumbMouseDown(mousedownEvent: MouseEvent): void;
216
+ /**
217
+ * Method invoked when clicking on the scrollbar track.
218
+ *
219
+ * Scrolls in discrete steps to the pointer, then switches to regular scrolling until releasing the mouse.
220
+ */
221
+ protected onScrollTrackMouseDown(event: MouseEvent): void;
248
222
  /**
249
223
  * Renders the current scroll position when the viewport is scrolled.
250
224
  */
251
225
  private installScrollPositionRenderer;
252
226
  /**
253
- * Projects the given scrollbar scroll pixels into viewport scroll pixels.
227
+ * Moves the scrollbar thumb to the specified position, scrolling the viewport accordingly.
228
+ *
229
+ * The thumb position must be given in client coordinates (relative to the top-left corner of the page viewport).
254
230
  */
255
- private toViewportPanPx;
231
+ private scrollViewport;
256
232
  /**
257
- * Moves the viewport client by the specified numbers of pixels.
233
+ * Returns the position of this component in client coordinates.
234
+ *
235
+ * Returned coordinates are relative to the top-left corner of the page viewport.
236
+ * Depending on the scrollbar orientation, returned coordinates are `[top, bottom]` or `[left, right]`.
258
237
  */
259
- private moveViewportClient;
238
+ private scrollbarComponentPosition;
260
239
  /**
261
- * Indicates if the content overflows.
240
+ * Returns the size of the viewport in pixels.
241
+ *
242
+ * The viewport is the container for scrollable content (viewport client), displaying scrollbars if it overflows.
243
+ * Depending on the scrollbar orientation, the returned size is `viewport.clientHeight` or `viewport.clientWidth`.
262
244
  */
263
- get overflow(): boolean;
245
+ private viewportSize;
264
246
  /**
265
- * Scrolls continuously while holding the mouse pressed, or until the mouse leaves the scrolltrack.
247
+ * Returns the size of the viewport client in pixels.
248
+ *
249
+ * The viewport client represents scrollable content displayed in the viewport.
250
+ * Depending on the scrollbar orientation, the returned size is `viewport.scrollHeight` or `viewport.scrollWidth`.
251
+ */
252
+ private viewportClientSize;
253
+ /**
254
+ * Returns the viewport's scroll position in pixels.
255
+ *
256
+ * Depending on the scrollbar orientation, the returned position is `viewport.scrollTop` or `viewport.scrollLeft`.
257
+ */
258
+ private viewportScrollPosition;
259
+ /**
260
+ * Returns the size of the scrollbar thumb in pixels.
261
+ *
262
+ * The thumb is the handle used to scroll the scrollbar.
263
+ */
264
+ private thumbSize;
265
+ /**
266
+ * Returns the current thumb position in client coordinates.
267
+ *
268
+ * Returned coordinates are relative to the top-left corner of the page viewport.
269
+ * Depending on the scrollbar orientation, returned coordinates are `[top, bottom]` or `[left, right]`.
270
+ */
271
+ private thumbPosition;
272
+ /**
273
+ * Returns the size of the scrollbar track in pixels.
274
+ *
275
+ * The scrollbar track is the track along which the scrollbar thumb moves.
266
276
  */
267
- private scrollWhileMouseDown;
268
- private setCssVariable;
269
- private get viewportSize();
270
- private get viewportClientSize();
271
- private get scrollPosition();
272
- private get thumbSize();
273
- private get trackSize();
277
+ private trackSize;
274
278
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<SciScrollbarComponent, never>;
275
279
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<SciScrollbarComponent, "sci-scrollbar", never, { "direction": { "alias": "direction"; "required": false; "isSignal": true; }; "viewport": { "alias": "viewport"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
276
280
  }
@@ -285,16 +289,36 @@ declare class SciScrollbarComponent {
285
289
  * This directive expects its host element to be the only child in document flow in its parent DOM element. It makes the host element
286
290
  * fill up the entire space (width and height set to 100%). The parent element must have its CSS `overflow` property set to `hidden`
287
291
  * to hide the pushed out native scrollbars.
292
+ *
293
+ * This directive provides the `isNativeScrollbarCropped` signal, which indicates whether native scrollbars are pushed out of the viewport element.
294
+ * In templates, access it via the exported template reference variable `sciScrollable`.
295
+ *
296
+ * ```html
297
+ * <div sciScrollable #sciScrollable="sciScrollable" #viewport>
298
+ * content
299
+ * </div>
300
+ *
301
+ * <!-- Render scrollbars only if native scrollbars are pushed out of the viewport element. -->
302
+ * @if (sciScrollable.isNativeScrollbarCropped()) {
303
+ * <sci-scrollbar [viewport]="viewport" direction="vscroll"/>
304
+ * <sci-scrollbar [viewport]="viewport" direction="hscroll"/>
305
+ * }
306
+ * ```
288
307
  */
289
308
  declare class SciScrollableDirective {
290
309
  /**
291
310
  * Controls whether to display native scrollbars.
311
+ *
292
312
  * Has no effect if the native scrollbar sits on top of the content, e.g. in OS X.
293
313
  */
294
314
  readonly displayNativeScrollbar: _angular_core.InputSignal<boolean>;
295
315
  private readonly _host;
296
316
  private readonly _renderer;
297
317
  private readonly _nativeScrollbarTrackSizeProvider;
318
+ /**
319
+ * Indicates whether native scrollbars are pushed out of the viewport element.
320
+ */
321
+ readonly isNativeScrollbarCropped: _angular_core.Signal<boolean>;
298
322
  constructor();
299
323
  /**
300
324
  * Controls the display of the native scrollbar based on this directive's configuration.
@@ -310,7 +334,7 @@ declare class SciScrollableDirective {
310
334
  private shiftNativeScrollbars;
311
335
  private setStyle;
312
336
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<SciScrollableDirective, never>;
313
- static ɵdir: _angular_core.ɵɵDirectiveDeclaration<SciScrollableDirective, "[sciScrollable]", never, { "displayNativeScrollbar": { "alias": "sciScrollableDisplayNativeScrollbar"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
337
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<SciScrollableDirective, "[sciScrollable]", ["sciScrollable"], { "displayNativeScrollbar": { "alias": "sciScrollableDisplayNativeScrollbar"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
314
338
  }
315
339
 
316
340
  export { SciScrollableDirective, SciScrollbarComponent, SciViewportComponent };
@@ -6,27 +6,18 @@
6
6
  * Invoke from within the 'sci-scrollbar' selector.
7
7
  */
8
8
  @mixin position() {
9
- $scrollbar-size: 12px;
10
-
11
9
  position: absolute;
12
- transition-duration: 1s;
13
- transition-property: opacity;
14
- transition-timing-function: ease-out;
15
10
 
16
11
  &.vertical {
17
- top: 0;
18
- right: 0;
19
- bottom: 0;
20
- left: unset;
21
- width: $scrollbar-size;
12
+ top: 2px;
13
+ right: 1px;
14
+ bottom: 2px;
22
15
  }
23
16
 
24
17
  &.horizontal {
25
- top: unset;
26
- right: 0;
27
- bottom: 0;
28
- left: 0;
29
- height: $scrollbar-size;
18
+ left: 2px;
19
+ bottom: 1px;
20
+ right: 2px;
30
21
  }
31
22
  }
32
23
 
@@ -39,7 +30,10 @@
39
30
  * Invoke from within the viewport selector.
40
31
  */
41
32
  @mixin hide-when-inactive() {
42
- &:host-context(:not(:hover):not(:active)) sci-scrollbar:not(.scrolling) { // use :host-context to work with shadow DOM, i.e., to select the shadow host of the shadow DOM
33
+ &:is(
34
+ :not(:hover):not(:active), // Support "regular" host
35
+ :host(:not(:hover):not(:active)) // Support "shadow" host
36
+ ) sci-scrollbar:not(.scrolling) {
43
37
  opacity: 0; // do not use 'display' nor 'visibility' property to fade the scrollbar
44
38
  }
45
39
  }