@scion/components 21.1.1 → 22.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/scion-components-dimension.mjs +11 -8
- package/fesm2022/scion-components-dimension.mjs.map +1 -1
- package/fesm2022/scion-components-sashbox.mjs +47 -33
- package/fesm2022/scion-components-sashbox.mjs.map +1 -1
- package/fesm2022/scion-components-splitter.mjs +15 -10
- package/fesm2022/scion-components-splitter.mjs.map +1 -1
- package/fesm2022/scion-components-throbber.mjs +23 -22
- package/fesm2022/scion-components-throbber.mjs.map +1 -1
- package/fesm2022/scion-components-viewport.mjs +183 -134
- package/fesm2022/scion-components-viewport.mjs.map +1 -1
- package/package.json +7 -6
- package/types/scion-components-viewport.d.ts +62 -28
- package/viewport/scrollbar/_scrollbar.scss +10 -16
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, DOCUMENT, NgZone, Injectable, input, ElementRef, Renderer2, effect, untracked, Directive, DestroyRef, viewChild,
|
|
3
|
-
import { fromEvent, merge,
|
|
4
|
-
import { debounceTime, startWith, map, distinctUntilChanged,
|
|
2
|
+
import { inject, DOCUMENT, NgZone, Injectable, input, ElementRef, Renderer2, effect, untracked, Directive, DestroyRef, viewChild, computed, signal, Component, output, ChangeDetectionStrategy, ViewEncapsulation } from '@angular/core';
|
|
3
|
+
import { fromEvent, race, tap, merge, finalize, timer, exhaustMap, of, concatWith, mergeWith } from 'rxjs';
|
|
4
|
+
import { debounceTime, startWith, map, distinctUntilChanged, takeUntil, withLatestFrom, switchMap } from 'rxjs/operators';
|
|
5
5
|
import { toSignal, takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
6
|
-
import { subscribeIn
|
|
6
|
+
import { subscribeIn } from '@scion/toolkit/operators';
|
|
7
7
|
import { coerceElement } from '@angular/cdk/coercion';
|
|
8
8
|
import { fromResize$, fromMutation$ } from '@scion/toolkit/observable';
|
|
9
9
|
import { CdkScrollable } from '@angular/cdk/scrolling';
|
|
@@ -77,10 +77,10 @@ class SciNativeScrollbarTrackSizeProvider {
|
|
|
77
77
|
map(() => this.computeTrackSize()), distinctUntilChanged((t1, t2) => t1?.hScrollbarTrackHeight === t2?.hScrollbarTrackHeight && t1?.vScrollbarTrackWidth === t2?.vScrollbarTrackWidth));
|
|
78
78
|
return toSignal(trackSize$, { initialValue: null });
|
|
79
79
|
}
|
|
80
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
81
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
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' });
|
|
82
82
|
}
|
|
83
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
83
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: SciNativeScrollbarTrackSizeProvider, decorators: [{
|
|
84
84
|
type: Injectable,
|
|
85
85
|
args: [{ providedIn: 'root' }]
|
|
86
86
|
}], ctorParameters: () => [] });
|
|
@@ -121,7 +121,7 @@ class SciScrollableDirective {
|
|
|
121
121
|
* Controls whether to display native scrollbars.
|
|
122
122
|
* Has no effect if the native scrollbar sits on top of the content, e.g. in OS X.
|
|
123
123
|
*/
|
|
124
|
-
displayNativeScrollbar = input(false, ...(ngDevMode ?
|
|
124
|
+
displayNativeScrollbar = input(false, { ...(ngDevMode ? { debugName: "displayNativeScrollbar" } : /* istanbul ignore next */ {}), alias: 'sciScrollableDisplayNativeScrollbar' });
|
|
125
125
|
_host = inject((ElementRef)).nativeElement;
|
|
126
126
|
_renderer = inject(Renderer2);
|
|
127
127
|
_nativeScrollbarTrackSizeProvider = inject(SciNativeScrollbarTrackSizeProvider);
|
|
@@ -174,10 +174,10 @@ class SciScrollableDirective {
|
|
|
174
174
|
setStyle(element, style) {
|
|
175
175
|
Object.keys(style).forEach(key => this._renderer.setStyle(element, key, style[key]));
|
|
176
176
|
}
|
|
177
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
178
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "
|
|
177
|
+
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 });
|
|
179
179
|
}
|
|
180
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
180
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: SciScrollableDirective, decorators: [{
|
|
181
181
|
type: Directive,
|
|
182
182
|
args: [{ selector: '[sciScrollable]' }]
|
|
183
183
|
}], ctorParameters: () => [], propDecorators: { displayNativeScrollbar: [{ type: i0.Input, args: [{ isSignal: true, alias: "sciScrollableDisplayNativeScrollbar", required: false }] }] } });
|
|
@@ -195,7 +195,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImpor
|
|
|
195
195
|
* Renders a vertical or horizontal scrollbar.
|
|
196
196
|
*
|
|
197
197
|
* The scrollbar features the following functionality:
|
|
198
|
-
* - allows to move the thumb by mouse
|
|
198
|
+
* - allows to move the thumb by mouse
|
|
199
199
|
* - enlarges the thumb if the mouse pointer is near the thumb
|
|
200
200
|
* - allows paging on mousedown on the scroll track
|
|
201
201
|
*
|
|
@@ -204,7 +204,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImpor
|
|
|
204
204
|
* To customize the default look of SCION components or support different themes, configure the `@scion/components` SCSS module in `styles.scss`.
|
|
205
205
|
* To style a specific `sci-scrollbar` component, the following CSS variables can be set directly on the component.
|
|
206
206
|
*
|
|
207
|
-
* - sci-scrollbar-color: Sets the color of the scrollbar.
|
|
207
|
+
* - --sci-scrollbar-color: Sets the color of the scrollbar.
|
|
208
208
|
*
|
|
209
209
|
* Example:
|
|
210
210
|
*
|
|
@@ -229,95 +229,111 @@ class SciScrollbarComponent {
|
|
|
229
229
|
/**
|
|
230
230
|
* Specifies the direction of the scrollbar. Defaults to a vertical scrollbar.
|
|
231
231
|
*/
|
|
232
|
-
direction = input('vscroll',
|
|
232
|
+
direction = input('vscroll', /* @ts-ignore */
|
|
233
|
+
...(ngDevMode ? [{ debugName: "direction" }] : /* istanbul ignore next */ []));
|
|
233
234
|
/**
|
|
234
|
-
*
|
|
235
|
+
* Specifies the viewport associated with the scrollbar.
|
|
235
236
|
*/
|
|
236
|
-
viewport = input.required(
|
|
237
|
+
viewport = input.required(/* @ts-ignore */
|
|
238
|
+
...(ngDevMode ? [{ debugName: "viewport" }] : /* istanbul ignore next */ []));
|
|
237
239
|
_host = inject(ElementRef).nativeElement;
|
|
238
240
|
_document = inject(DOCUMENT);
|
|
239
241
|
_zone = inject(NgZone);
|
|
240
242
|
_destroyRef = inject(DestroyRef);
|
|
241
243
|
_thumbElement = viewChild.required('thumb_handle');
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
horizontal = computed(() => !this.vertical(),
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
244
|
+
vertical = computed(() => this.direction() === 'vscroll', /* @ts-ignore */
|
|
245
|
+
...(ngDevMode ? [{ debugName: "vertical" }] : /* istanbul ignore next */ []));
|
|
246
|
+
horizontal = computed(() => !this.vertical(), /* @ts-ignore */
|
|
247
|
+
...(ngDevMode ? [{ debugName: "horizontal" }] : /* istanbul ignore next */ []));
|
|
248
|
+
scrolling = signal(false, /* @ts-ignore */
|
|
249
|
+
...(ngDevMode ? [{ debugName: "scrolling" }] : /* istanbul ignore next */ []));
|
|
250
|
+
overflow = signal(false, /* @ts-ignore */
|
|
251
|
+
...(ngDevMode ? [{ debugName: "overflow" }] : /* istanbul ignore next */ []));
|
|
252
|
+
thumbSizeFr = signal(0, /* @ts-ignore */
|
|
253
|
+
...(ngDevMode ? [{ debugName: "thumbSizeFr" }] : /* istanbul ignore next */ []));
|
|
254
|
+
thumbPositionFr = signal(0, /* @ts-ignore */
|
|
255
|
+
...(ngDevMode ? [{ debugName: "thumbPositionFr" }] : /* istanbul ignore next */ []));
|
|
249
256
|
constructor() {
|
|
250
257
|
this.installScrollPositionRenderer();
|
|
251
258
|
}
|
|
252
259
|
/**
|
|
253
|
-
* Computes the scroll position and updates CSS variables to render the scroll position
|
|
260
|
+
* Computes the scroll position and updates CSS variables to render the scroll position.
|
|
254
261
|
*/
|
|
255
262
|
renderScrollPosition() {
|
|
256
263
|
NgZone.assertNotInAngularZone();
|
|
257
|
-
const viewportSize = this.viewportSize;
|
|
258
|
-
const viewportClientSize = this.viewportClientSize;
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
if (thumbPositionFr !== this._thumbPositionFr || thumbSizeFr !== this._thumbSizeFr) {
|
|
263
|
-
this._thumbPositionFr = thumbPositionFr;
|
|
264
|
-
this._thumbSizeFr = thumbSizeFr;
|
|
265
|
-
this.setCssVariable('--ɵsci-scrollbar-thumb-position-fr', thumbPositionFr);
|
|
266
|
-
this.setCssVariable('--ɵsci-scrollbar-thumb-size-fr', thumbSizeFr);
|
|
267
|
-
}
|
|
268
|
-
if (overflow !== this._overflow) {
|
|
269
|
-
this._overflow = overflow;
|
|
270
|
-
overflow ? this._host.classList.add('overflow') : this._host.classList.remove('overflow');
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
onTouchStart(event) {
|
|
274
|
-
event.preventDefault();
|
|
275
|
-
this._lastDragPosition.set(this.vertical() ? event.touches[0].screenY : event.touches[0].screenX);
|
|
264
|
+
const viewportSize = this.viewportSize();
|
|
265
|
+
const viewportClientSize = this.viewportClientSize();
|
|
266
|
+
this.thumbPositionFr.set(this.viewportScrollPosition() / viewportClientSize);
|
|
267
|
+
this.thumbSizeFr.set(viewportSize / viewportClientSize);
|
|
268
|
+
this.overflow.set(viewportClientSize > viewportSize);
|
|
276
269
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
const viewportPanPx = this.toViewportPanPx(scrollbarPanPx);
|
|
282
|
-
this._lastDragPosition.set(newDragPositionPx);
|
|
283
|
-
this.moveViewportClient(viewportPanPx);
|
|
284
|
-
}
|
|
285
|
-
onTouchEnd(event) {
|
|
286
|
-
event.preventDefault();
|
|
287
|
-
this._lastDragPosition.set(null);
|
|
288
|
-
}
|
|
289
|
-
onMouseDown(mousedownEvent) {
|
|
270
|
+
/**
|
|
271
|
+
* Method invoked when clicking on the scrollbar thumb.
|
|
272
|
+
*/
|
|
273
|
+
onThumbMouseDown(mousedownEvent) {
|
|
290
274
|
if (mousedownEvent.button !== 0) {
|
|
291
275
|
return;
|
|
292
276
|
}
|
|
277
|
+
this.scrolling.set(true);
|
|
278
|
+
// Prevent text selection during drag.
|
|
293
279
|
mousedownEvent.preventDefault();
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
const
|
|
297
|
-
|
|
280
|
+
// Memoize offset where thumb was clicked.
|
|
281
|
+
const [thumbStartPosition] = this.thumbPosition();
|
|
282
|
+
const thumbStartOffset = (this.vertical() ? mousedownEvent.pageY : mousedownEvent.pageX) - thumbStartPosition;
|
|
283
|
+
// Stop scrolling when releasing the mouse. Handle the event in the capture phase and stop propagation to not close a potential overlay when releasing the mouse outside the overlay.
|
|
284
|
+
const mouseUp$ = race(fromEvent(this._document, 'mouseup', { capture: true, once: true }), fromEvent(this._document, 'sci-mouseup', { once: true }))
|
|
285
|
+
.pipe(tap(mouseupEvent => mouseupEvent.stopPropagation()));
|
|
286
|
+
// Track pointer until mouse release.
|
|
287
|
+
merge(fromEvent(this._document, 'mousemove'), fromEvent(this._document, 'sci-mousemove'))
|
|
288
|
+
.pipe(subscribeIn(fn => this._zone.runOutsideAngular(fn)), takeUntilDestroyed(this._destroyRef), takeUntil(mouseUp$), finalize(() => this.scrolling.set(false)))
|
|
298
289
|
.subscribe(mousemoveEvent => {
|
|
299
290
|
NgZone.assertNotInAngularZone();
|
|
291
|
+
// Prevent user agent scrolling while during drag.
|
|
300
292
|
mousemoveEvent.preventDefault();
|
|
301
|
-
|
|
302
|
-
const
|
|
303
|
-
|
|
304
|
-
this._lastDragPosition.set(newDragPositionPx);
|
|
305
|
-
this.moveViewportClient(viewportPanPx);
|
|
293
|
+
// Calculate new thumb position.
|
|
294
|
+
const pointerPosition = this.vertical() ? mousemoveEvent.pageY : mousemoveEvent.pageX;
|
|
295
|
+
this.scrollViewport(pointerPosition - thumbStartOffset);
|
|
306
296
|
});
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Method invoked when clicking on the scrollbar track.
|
|
300
|
+
*
|
|
301
|
+
* Scrolls in discrete steps to the pointer, then switches to regular scrolling until releasing the mouse.
|
|
302
|
+
*/
|
|
303
|
+
onScrollTrackMouseDown(event) {
|
|
304
|
+
const mouseMove$ = merge(fromEvent(this._document, 'mousemove'), fromEvent(this._document, 'sci-mousemove'));
|
|
305
|
+
// 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.
|
|
306
|
+
const mouseUp$ = race(fromEvent(this._document, 'mouseup', { capture: true, once: true }), fromEvent(this._document, 'sci-mouseup', { once: true }))
|
|
307
|
+
.pipe(tap(mouseupEvent => mouseupEvent.stopPropagation()));
|
|
308
|
+
// Prevent text selection during drag.
|
|
309
|
+
event.preventDefault();
|
|
310
|
+
this.scrolling.set(true);
|
|
311
|
+
// Scroll in discrete steps to the pointer position, then switch to regular scrolling.
|
|
312
|
+
timer(250, 50)
|
|
313
|
+
.pipe(
|
|
314
|
+
// Track current pointer position.
|
|
315
|
+
withLatestFrom(mouseMove$.pipe(startWith(event)), (_tick, event) => event),
|
|
316
|
+
// Scroll immediately on initial click.
|
|
317
|
+
startWith(event), subscribeIn(fn => this._zone.runOutsideAngular(fn)), exhaustMap(event => {
|
|
318
|
+
const pointerPosition = this.vertical() ? event.pageY : event.pageX;
|
|
319
|
+
const [thumbStartPosition, thumbEndPosition] = this.thumbPosition();
|
|
320
|
+
const thumbSize = thumbEndPosition - thumbStartPosition;
|
|
321
|
+
// Step scroll until the pointer hits the thumb.
|
|
322
|
+
if (!isBetween(pointerPosition, { from: thumbStartPosition - thumbSize, to: thumbEndPosition + thumbSize })) {
|
|
323
|
+
const scrollingDown = pointerPosition > thumbEndPosition;
|
|
324
|
+
return of(scrollingDown ? thumbStartPosition + thumbSize : thumbStartPosition - thumbSize);
|
|
325
|
+
}
|
|
326
|
+
// Switch to "smooth scrolling" following the pointer.
|
|
327
|
+
return of(event)
|
|
328
|
+
.pipe(concatWith(mouseMove$), map(event => (this.vertical() ? event.pageY : event.pageX) - (thumbSize / 2)));
|
|
329
|
+
}),
|
|
330
|
+
// Stop on mouse release.
|
|
331
|
+
takeUntil(mouseUp$), finalize(() => this.scrolling.set(false)))
|
|
332
|
+
.subscribe((thumbPosition) => {
|
|
311
333
|
NgZone.assertNotInAngularZone();
|
|
312
|
-
|
|
313
|
-
mousemoveListener.unsubscribe();
|
|
314
|
-
this._lastDragPosition.set(null);
|
|
334
|
+
this.scrollViewport(thumbPosition);
|
|
315
335
|
});
|
|
316
336
|
}
|
|
317
|
-
onScrollTrackMouseDown(event, direction) {
|
|
318
|
-
const signum = (direction === 'up' ? -1 : 1);
|
|
319
|
-
this.scrollWhileMouseDown(this.toViewportPanPx(signum * this.thumbSize), event);
|
|
320
|
-
}
|
|
321
337
|
/**
|
|
322
338
|
* Renders the current scroll position when the viewport is scrolled.
|
|
323
339
|
*/
|
|
@@ -333,85 +349,101 @@ class SciScrollbarComponent {
|
|
|
333
349
|
});
|
|
334
350
|
}
|
|
335
351
|
/**
|
|
336
|
-
*
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
const scrollRangePx = this.trackSize - this.thumbSize;
|
|
340
|
-
const scrollRatio = scrollbarPanPx / scrollRangePx;
|
|
341
|
-
return scrollRatio * (this.viewportClientSize - this.viewportSize);
|
|
342
|
-
}
|
|
343
|
-
/**
|
|
344
|
-
* Moves the viewport client by the specified numbers of pixels.
|
|
352
|
+
* Moves the scrollbar thumb to the specified position, scrolling the viewport accordingly.
|
|
353
|
+
*
|
|
354
|
+
* The thumb position must be given in page coordinates relative to the top-left corner of the document.
|
|
345
355
|
*/
|
|
346
|
-
|
|
356
|
+
scrollViewport(thumbPosition) {
|
|
357
|
+
const [scrollbarComponentStartPosition] = this.scrollbarComponentPosition();
|
|
358
|
+
const scrollbarBorderWidth = this.vertical() ? this._host.clientTop : this._host.clientLeft;
|
|
359
|
+
const scrollRatio = clamp((thumbPosition - scrollbarComponentStartPosition - scrollbarBorderWidth) / (this.trackSize() - this.thumbSize()), { min: 0, max: 1 });
|
|
360
|
+
const viewportScrollPosition = scrollRatio * (this.viewportClientSize() - this.viewportSize());
|
|
347
361
|
if (this.vertical()) {
|
|
348
|
-
this.viewport().scrollTop
|
|
362
|
+
this.viewport().scrollTop = viewportScrollPosition;
|
|
349
363
|
}
|
|
350
364
|
else {
|
|
351
|
-
this.viewport().scrollLeft
|
|
365
|
+
this.viewport().scrollLeft = viewportScrollPosition;
|
|
352
366
|
}
|
|
353
367
|
}
|
|
354
368
|
/**
|
|
355
|
-
*
|
|
369
|
+
* Returns the position of this component in page coordinates.
|
|
370
|
+
*
|
|
371
|
+
* Returned coordinates are relative to the top-left corner of the document.
|
|
372
|
+
* Depending on the scrollbar orientation, returned coordinates are `[top, bottom]` or `[left, right]`.
|
|
356
373
|
*/
|
|
357
|
-
|
|
358
|
-
|
|
374
|
+
scrollbarComponentPosition() {
|
|
375
|
+
const boundingBox = this._host.getBoundingClientRect();
|
|
376
|
+
return this.vertical() ? [boundingBox.top + window.scrollY, boundingBox.bottom + window.scrollY] : [boundingBox.left + window.scrollX, boundingBox.right + window.scrollX];
|
|
359
377
|
}
|
|
360
378
|
/**
|
|
361
|
-
*
|
|
379
|
+
* Returns the size of the viewport in pixels.
|
|
380
|
+
*
|
|
381
|
+
* The viewport is the container for scrollable content (viewport client), displaying scrollbars if it overflows.
|
|
382
|
+
* Depending on the scrollbar orientation, the returned size is `viewport.clientHeight` or `viewport.clientWidth`.
|
|
362
383
|
*/
|
|
363
|
-
|
|
364
|
-
// The `EventTarget` type of `Event.target` is not yet compatible with `FromEventTarget` used in `fromEvent`.
|
|
365
|
-
// This will be fixed in rxjs version 7.0.0. Refer to https://github.com/ReactiveX/rxjs/commit/5f022d784570684632e6fd5ae247fc259ee34c4b
|
|
366
|
-
// for more details.
|
|
367
|
-
const scrollTrackElement = mousedownEvent.target;
|
|
368
|
-
// scroll continuously every 50ms after an initial delay of 250ms
|
|
369
|
-
timer(250, 50)
|
|
370
|
-
.pipe(
|
|
371
|
-
// continue chain with latest mouse event
|
|
372
|
-
withLatestFrom(merge(of(mousedownEvent), fromEvent(scrollTrackElement, 'mousemove')), (tick, event) => event),
|
|
373
|
-
// start immediately
|
|
374
|
-
startWith(mousedownEvent),
|
|
375
|
-
// stop scrolling if the thumb hits the mouse pointer position
|
|
376
|
-
takeWhile((event) => scrollTrackElement === this._document.elementFromPoint(event.clientX, event.clientY)), debounceTime(10),
|
|
377
|
-
// stop scrolling on mouseout or mouseup
|
|
378
|
-
takeUntil(merge(fromEvent(scrollTrackElement, 'mouseout'), fromEvent(scrollTrackElement, 'mouseup'))))
|
|
379
|
-
.subscribe(() => {
|
|
380
|
-
this.moveViewportClient(viewportScrollPx);
|
|
381
|
-
});
|
|
382
|
-
}
|
|
383
|
-
setCssVariable(key, value) {
|
|
384
|
-
this._host.style.setProperty(key, `${value}`);
|
|
385
|
-
}
|
|
386
|
-
get viewportSize() {
|
|
384
|
+
viewportSize() {
|
|
387
385
|
return this.vertical() ? this.viewport().clientHeight : this.viewport().clientWidth;
|
|
388
386
|
}
|
|
389
|
-
|
|
387
|
+
/**
|
|
388
|
+
* Returns the size of the viewport client in pixels.
|
|
389
|
+
*
|
|
390
|
+
* The viewport client represents scrollable content displayed in the viewport.
|
|
391
|
+
* Depending on the scrollbar orientation, the returned size is `viewport.scrollHeight` or `viewport.scrollWidth`.
|
|
392
|
+
*/
|
|
393
|
+
viewportClientSize() {
|
|
390
394
|
return this.vertical() ? this.viewport().scrollHeight : this.viewport().scrollWidth;
|
|
391
395
|
}
|
|
392
|
-
|
|
396
|
+
/**
|
|
397
|
+
* Returns the viewport's scroll position in pixels.
|
|
398
|
+
*
|
|
399
|
+
* Depending on the scrollbar orientation, the returned position is `viewport.scrollTop` or `viewport.scrollLeft`.
|
|
400
|
+
*/
|
|
401
|
+
viewportScrollPosition() {
|
|
393
402
|
return this.vertical() ? this.viewport().scrollTop : this.viewport().scrollLeft;
|
|
394
403
|
}
|
|
395
|
-
|
|
404
|
+
/**
|
|
405
|
+
* Returns the size of the scrollbar thumb in pixels.
|
|
406
|
+
*
|
|
407
|
+
* The thumb is the handle used to scroll the scrollbar.
|
|
408
|
+
*/
|
|
409
|
+
thumbSize() {
|
|
396
410
|
const thumbElement = this._thumbElement().nativeElement;
|
|
397
|
-
return this.vertical() ? thumbElement.
|
|
411
|
+
return this.vertical() ? thumbElement.offsetHeight : thumbElement.offsetWidth;
|
|
398
412
|
}
|
|
399
|
-
|
|
413
|
+
/**
|
|
414
|
+
* Returns the current thumb position in page coordinates.
|
|
415
|
+
*
|
|
416
|
+
* Returned coordinates are relative to the top-left corner of the document.
|
|
417
|
+
* Depending on the scrollbar orientation, returned coordinates are `[top, bottom]` or `[left, right]`.
|
|
418
|
+
*/
|
|
419
|
+
thumbPosition() {
|
|
420
|
+
const boundingBox = this._thumbElement().nativeElement.getBoundingClientRect();
|
|
421
|
+
return this.vertical() ? [boundingBox.top + window.scrollY, boundingBox.bottom + window.scrollY] : [boundingBox.left + window.scrollX, boundingBox.right + window.scrollX];
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Returns the size of the scrollbar track in pixels.
|
|
425
|
+
*
|
|
426
|
+
* The scrollbar track is the track along which the scrollbar thumb moves.
|
|
427
|
+
*/
|
|
428
|
+
trackSize() {
|
|
400
429
|
return this.vertical() ? this._host.clientHeight : this._host.clientWidth;
|
|
401
430
|
}
|
|
402
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
403
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "
|
|
431
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: SciScrollbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
432
|
+
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"] });
|
|
404
433
|
}
|
|
405
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
434
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: SciScrollbarComponent, decorators: [{
|
|
406
435
|
type: Component,
|
|
407
|
-
args: [{ selector: 'sci-scrollbar',
|
|
436
|
+
args: [{ selector: 'sci-scrollbar', host: {
|
|
408
437
|
'[class.vertical]': 'vertical()',
|
|
409
438
|
'[class.horizontal]': 'horizontal()',
|
|
410
439
|
'[class.scrolling]': 'scrolling()',
|
|
411
|
-
|
|
440
|
+
'[class.overflow]': 'overflow()',
|
|
441
|
+
'[style.--ɵsci-scrollbar-thumb-position-fr]': 'thumbPositionFr()',
|
|
442
|
+
'[style.--ɵsci-scrollbar-thumb-size-fr]': 'thumbSizeFr()',
|
|
443
|
+
}, 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"] }]
|
|
412
444
|
}], 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 }] }] } });
|
|
413
445
|
/**
|
|
414
|
-
* Emits whenever the viewport
|
|
446
|
+
* Emits whenever the viewport is scrolled.
|
|
415
447
|
*/
|
|
416
448
|
function viewportScroll$(viewport) {
|
|
417
449
|
return fromEvent(viewport, 'scroll', { passive: true }).pipe(map(() => undefined));
|
|
@@ -446,7 +478,23 @@ function viewportClientSize$(viewport, options) {
|
|
|
446
478
|
*/
|
|
447
479
|
function children$(element) {
|
|
448
480
|
return fromMutation$(element, { subtree: false, childList: true })
|
|
449
|
-
.pipe(startWith(undefined), map(() => Array.from(element.children)
|
|
481
|
+
.pipe(startWith(undefined), map(() => Array.from(element.children)
|
|
482
|
+
// Map to slotted content if a slot (Shadow DOM).
|
|
483
|
+
.flatMap(child => child instanceof HTMLSlotElement ? child.assignedElements() : child)
|
|
484
|
+
// Filter HTML elements.
|
|
485
|
+
.filter((child) => child instanceof HTMLElement)));
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Returns the value clamped to the inclusive range of min and max.
|
|
489
|
+
*/
|
|
490
|
+
function clamp(value, minmax) {
|
|
491
|
+
return Math.max(minmax.min, Math.min(value, minmax.max));
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Returns whether the value is between the specified range (inclusive).
|
|
495
|
+
*/
|
|
496
|
+
function isBetween(value, range) {
|
|
497
|
+
return value >= range.from && value <= range.to;
|
|
450
498
|
}
|
|
451
499
|
|
|
452
500
|
/*
|
|
@@ -529,7 +577,8 @@ class SciViewportComponent {
|
|
|
529
577
|
/**
|
|
530
578
|
* Controls if to use the native scrollbar or a scrollbar that sits on top of the viewport. Defaults to `on-top`.
|
|
531
579
|
*/
|
|
532
|
-
scrollbarStyle = input('on-top',
|
|
580
|
+
scrollbarStyle = input('on-top', /* @ts-ignore */
|
|
581
|
+
...(ngDevMode ? [{ debugName: "scrollbarStyle" }] : /* istanbul ignore next */ []));
|
|
533
582
|
/**
|
|
534
583
|
* Emits when the viewport is scrolled. The event is emitted outside the Angular zone to avoid unnecessary change detection cycles.
|
|
535
584
|
*/
|
|
@@ -700,18 +749,18 @@ class SciViewportComponent {
|
|
|
700
749
|
});
|
|
701
750
|
});
|
|
702
751
|
}
|
|
703
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
704
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
752
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: SciViewportComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
753
|
+
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: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:1px;right:1px;bottom:1px}:host>sci-scrollbar.horizontal{left:1px;bottom:1px;right:1px}\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 });
|
|
705
754
|
}
|
|
706
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
755
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: SciViewportComponent, decorators: [{
|
|
707
756
|
type: Component,
|
|
708
757
|
args: [{ selector: 'sci-viewport', encapsulation: ViewEncapsulation.ShadowDom, imports: [
|
|
709
758
|
SciScrollableDirective,
|
|
710
759
|
SciScrollbarComponent,
|
|
711
760
|
CdkScrollable,
|
|
712
|
-
], host: {
|
|
761
|
+
], changeDetection: ChangeDetectionStrategy.Eager, host: {
|
|
713
762
|
'(focus)': 'focus()',
|
|
714
|
-
}, 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
|
|
763
|
+
}, template: "<!-- viewport and viewport client -->\n<div #viewport\n class=\"viewport\"\n tabindex=\"-1\"\n sciScrollable [sciScrollableDisplayNativeScrollbar]=\"scrollbarStyle() === 'native'\"\n cdkScrollable>\n <div #viewport_client class=\"viewport-client\" part=\"content\">\n <slot></slot>\n </div>\n</div>\n\n<!-- render emulated scrollbars which sit on-top -->\n@if (scrollbarStyle() === 'on-top' && 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: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:1px;right:1px;bottom:1px}:host>sci-scrollbar.horizontal{left:1px;bottom:1px;right:1px}\n"] }]
|
|
715
764
|
}], 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 }] }] } });
|
|
716
765
|
|
|
717
766
|
/*
|