Skip to content

Commit

Permalink
feat(core): support using native scrollbar
Browse files Browse the repository at this point in the history
  • Loading branch information
splincode committed Oct 8, 2024
1 parent e051888 commit 960d64b
Show file tree
Hide file tree
Showing 13 changed files with 152 additions and 56 deletions.
32 changes: 22 additions & 10 deletions projects/core/components/root/root.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ import {tuiWatch, tuiZonefreeScheduler} from '@taiga-ui/cdk/observables';
import {TUI_IS_MOBILE} from '@taiga-ui/cdk/tokens';
import {TuiAlerts} from '@taiga-ui/core/components/alert';
import {TUI_DIALOGS, TuiDialogs} from '@taiga-ui/core/components/dialog';
import {TuiScrollControls} from '@taiga-ui/core/components/scrollbar';
import {
TUI_SCROLLBAR_OPTIONS,
TuiScrollControls,
} from '@taiga-ui/core/components/scrollbar';
import {TuiDropdowns} from '@taiga-ui/core/directives';
import {TuiHints} from '@taiga-ui/core/directives/hint';
import {TuiBreakpointService} from '@taiga-ui/core/services';
Expand Down Expand Up @@ -57,22 +60,31 @@ export class TuiRoot {
{initialValue: false},
);

protected readonly scrollbars = inject(TUI_IS_MOBILE)
? signal(false)
: toSignal(
inject<Observable<readonly unknown[]>>(TUI_DIALOGS).pipe(
map(({length}) => !length),
debounceTime(0, tuiZonefreeScheduler()),
),
{initialValue: false},
);
protected readonly nativeScrollbar = inject(TUI_SCROLLBAR_OPTIONS).mode === 'native';

protected readonly scrollbars =
this.nativeScrollbar || inject(TUI_IS_MOBILE)
? signal(false)
: toSignal(
inject<Observable<readonly unknown[]>>(TUI_DIALOGS).pipe(
map(({length}) => !length),
debounceTime(0, tuiZonefreeScheduler()),
),
{initialValue: false},
);

constructor() {
inject(DOCUMENT).documentElement.setAttribute(
'data-tui-theme',
inject(TUI_THEME).toLowerCase(),
);

if (!this.nativeScrollbar) {
inject(DOCUMENT).defaultView?.document.documentElement.classList.add(
'tui-zero-scrollbar',
);
}

ngDevMode &&
console.assert(
!!inject<unknown[]>(EVENT_MANAGER_PLUGINS).find(
Expand Down
1 change: 0 additions & 1 deletion projects/core/components/root/root.style.less
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
}
}

html[data-tui-theme],
.tui-zero-scrollbar {
.scrollbar-hidden();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {tuiToAnimationOptions} from '@taiga-ui/core/utils';
import {distinctUntilChanged, map, startWith, throttleTime} from 'rxjs';

import {TuiScrollbarDirective} from './scrollbar.directive';
import {TUI_SCROLLBAR_OPTIONS} from './scrollbar.options';

@Component({
standalone: true,
Expand All @@ -21,7 +22,9 @@ import {TuiScrollbarDirective} from './scrollbar.directive';
export class TuiScrollControls {
private readonly scrollRef = inject(TUI_SCROLL_REF).nativeElement;

protected readonly nativeScrollbar = inject(TUI_SCROLLBAR_OPTIONS).mode === 'native';
protected readonly options = tuiToAnimationOptions(inject(TUI_ANIMATIONS_SPEED));

protected readonly refresh$ = inject(WA_ANIMATION_FRAME).pipe(
throttleTime(300, tuiZonefreeScheduler()),
map(() => this.scrollbars),
Expand Down
51 changes: 27 additions & 24 deletions projects/core/components/scrollbar/scroll-controls.template.html
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
<ng-container *ngIf="refresh$ | async as bars">
<div
*ngIf="bars[0]"
class="t-bar t-bar_vertical"
[@tuiFadeIn]="options"
[class.t-bar_has-horizontal]="bars[1]"
(mousedown.capture.prevent)="(0)"
>
<ng-container *ngIf="nativeScrollbar; else custom" />
<ng-template #custom>
<ng-container *ngIf="refresh$ | async as bars">
<div
tuiScrollbar="vertical"
class="t-thumb"
></div>
</div>
<div
*ngIf="bars[1]"
class="t-bar t-bar_horizontal"
[@tuiFadeIn]="options"
[class.t-bar_has-vertical]="bars[0]"
(mousedown.capture.prevent)="(0)"
>
*ngIf="bars[0]"
class="t-bar t-bar_vertical"
[@tuiFadeIn]="options"
[class.t-bar_has-horizontal]="bars[1]"
(mousedown.capture.prevent)="(0)"
>
<div
tuiScrollbar="vertical"
class="t-thumb"
></div>
</div>
<div
tuiScrollbar="horizontal"
class="t-thumb"
></div>
</div>
</ng-container>
*ngIf="bars[1]"
class="t-bar t-bar_horizontal"
[@tuiFadeIn]="options"
[class.t-bar_has-vertical]="bars[0]"
(mousedown.capture.prevent)="(0)"
>
<div
tuiScrollbar="horizontal"
class="t-thumb"
></div>
</div>
</ng-container>
</ng-template>
9 changes: 6 additions & 3 deletions projects/core/components/scrollbar/scrollbar.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const TUI_SCROLLABLE = 'tui-scrollable';
},
],
host: {
'[class._native-hidden]': '!isIOS || hidden',
'[class._native-hidden]': 'options.mode !== "native" && (!isIOS || hidden)',
[`(${TUI_SCROLLABLE}.stop)`]: 'scrollRef = $event.detail',
[`(${TUI_SCROLL_INTO_VIEW}.stop)`]: 'scrollIntoView($event.detail)',
},
Expand All @@ -50,11 +50,14 @@ export class TuiScrollbar {
protected readonly isIOS = inject(TUI_IS_IOS);
protected readonly browserScrollRef = new ElementRef(this.el);

/**
* @deprecated: use tuiScrollbarOptionsProvider({ mode: 'hidden' })
*/
@Input()
public hidden = false;
public hidden = this.options.mode === 'hidden';

protected get delegated(): boolean {
return this.scrollRef !== this.el;
return this.scrollRef !== this.el || this.options.mode === 'native';
}

protected get scrollRef(): HTMLElement {
Expand Down
18 changes: 4 additions & 14 deletions projects/core/components/scrollbar/scrollbar.options.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,12 @@
import type {Provider} from '@angular/core';
import {tuiCreateToken, tuiProvideOptions} from '@taiga-ui/cdk/utils/miscellaneous';
import {tuiCreateOptions} from '@taiga-ui/cdk/utils/di';

export interface TuiScrollbarOptions {
mode: 'always' | 'hover';
mode: 'always' | 'hidden' | 'hover' | 'native';
}

export const TUI_DEFAULT_SCROLLBAR_OPTIONS: TuiScrollbarOptions = {
mode: 'always',
};

export const TUI_SCROLLBAR_OPTIONS = tuiCreateToken(TUI_DEFAULT_SCROLLBAR_OPTIONS);

export function tuiScrollbarOptionsProvider(
options: Partial<TuiScrollbarOptions>,
): Provider {
return tuiProvideOptions(
TUI_SCROLLBAR_OPTIONS,
options,
TUI_DEFAULT_SCROLLBAR_OPTIONS,
);
}
export const [TUI_SCROLLBAR_OPTIONS, tuiScrollbarOptionsProvider] =
tuiCreateOptions<TuiScrollbarOptions>(TUI_DEFAULT_SCROLLBAR_OPTIONS);
2 changes: 1 addition & 1 deletion projects/core/components/scrollbar/scrollbar.template.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<tui-scroll-controls
*ngIf="!hidden && !isIOS"
*ngIf="!hidden && !isIOS && options.mode !== 'native'"
class="t-bars"
[class.t-hover-mode]="options.mode === 'hover'"
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
appendOnly
itemSize="50"
tuiScrollable
class="example-viewport tui-zero-scrollbar"
class="example-viewport"
[class.tui-zero-scrollbar]="!nativeScrollbar"
>
<div
*cdkVirtualFor="let item of items"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import {
CdkVirtualForOf,
CdkVirtualScrollViewport,
} from '@angular/cdk/scrolling';
import {Component} from '@angular/core';
import {Component, inject} from '@angular/core';
import {changeDetection} from '@demo/emulate/change-detection';
import {encapsulation} from '@demo/emulate/encapsulation';
import {TuiScrollable, TuiScrollbar} from '@taiga-ui/core';
import {TUI_SCROLLBAR_OPTIONS, TuiScrollable, TuiScrollbar} from '@taiga-ui/core';

@Component({
standalone: true,
Expand All @@ -23,6 +23,8 @@ import {TuiScrollable, TuiScrollbar} from '@taiga-ui/core';
changeDetection,
})
export default class Example {
protected readonly nativeScrollbar = inject(TUI_SCROLLBAR_OPTIONS).mode === 'native';

protected items = Array.from({length: 10000}).map((_, i) => `Item #${i}`);

protected add(): void {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<tui-scrollbar class="box">
<div class="content">
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deleniti dignissimos, doloremque. Aperiam
assumenda atque aut blanditiis corporis, eum, facilis harum laudantium magni necessitatibus nobis quas
repudiandae sint ut voluptatem! Optio.
</p>
<p>
Accusamus aperiam assumenda aut consectetur, corporis delectus, dolor eaque eius est hic impedit labore
possimus provident quas rem, rerum sequi sint tempora tempore ut? Debitis esse neque odio odit provident?
</p>
<p>
Cum eum illo, ipsa iure nostrum ut voluptates? Autem blanditiis corporis debitis deserunt ex expedita
facilis fuga, illum iusto magnam praesentium provident recusandae repudiandae, totam, voluptatem. Minima
numquam sapiente sunt.
</p>
<p>
Beatae consectetur cupiditate dignissimos ducimus eos excepturi labore pariatur placeat quia similique.
Architecto aspernatur cumque debitis distinctio esse, facere fugit harum ipsum libero minus neque numquam
omnis quidem, tempora, ut!
</p>
<p>
Mollitia, perspiciatis sunt! Architecto aspernatur assumenda beatae, blanditiis commodi consequuntur debitis
et id, laboriosam maxime molestiae neque nihil officiis omnis, quam quos sint veritatis voluptate? Alias
deserunt distinctio modi perferendis?
</p>
<p>
Ab aspernatur aut cumque cupiditate deleniti, dolorem ducimus eligendi eos facere harum hic ipsam ipsum iste
itaque modi nam necessitatibus nostrum nulla omnis quae repellat, sapiente sit tempore. Ipsam, quidem!
</p>
<p>
Ab debitis deleniti distinctio est ex facere magni nemo numquam placeat quia, quibusdam sequi! Aliquid at
consectetur culpa ea enim facilis, harum hic, inventore iste possimus praesentium quas tempora voluptates.
</p>
<p>
Aliquam eligendi ipsam modi nemo numquam obcaecati officia, quidem unde? Accusantium amet, animi deleniti
dolorum ea earum eos, expedita ipsa minima modi, pariatur perspiciatis porro quibusdam quo repellat tempore
voluptates!
</p>
<p>
Ab assumenda fugiat magni natus officiis perferendis ratione rem repellendus tenetur. At commodi laudantium
modi, natus nobis nulla odio odit sed sint tempora tenetur voluptas? At odio praesentium quas ut!
</p>
<p>
Atque aut consectetur consequuntur debitis eius facere ipsa ipsam maiores minima minus mollitia qui quos
repudiandae sapiente, soluta? Ad, amet dolore doloribus ducimus eos exercitationem molestiae quisquam soluta
ullam voluptate.
</p>
</div>
</tui-scrollbar>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.box {
inline-size: 16rem;
block-size: 16rem;
border: 1px solid;
}

.content {
padding: 0 0.6875rem;
}

p {
white-space: nowrap;
}
19 changes: 19 additions & 0 deletions projects/demo/src/modules/components/scrollbar/examples/8/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {Component} from '@angular/core';
import {changeDetection} from '@demo/emulate/change-detection';
import {encapsulation} from '@demo/emulate/encapsulation';
import {TuiScrollbar, tuiScrollbarOptionsProvider} from '@taiga-ui/core';

@Component({
standalone: true,
imports: [TuiScrollbar],
templateUrl: './index.html',
styleUrls: ['./index.less'],
encapsulation,
changeDetection,
providers: [
tuiScrollbarOptionsProvider({
mode: 'native',
}),
],
})
export default class Example {}
1 change: 1 addition & 0 deletions projects/demo/src/modules/components/scrollbar/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ export default class Page {
'Light scrollbar',
'Virtual scroll',
'Show scroll bars on hover',
'Native scrollbar',
];
}

0 comments on commit 960d64b

Please sign in to comment.