ngx-scrolltop
Version:
Lightweight, Material Design inspired button for scroll-to-top of the page. No dependencies. Pure Angular!
166 lines (158 loc) • 22.2 kB
JavaScript
import { DOCUMENT, NgClass, CommonModule } from '@angular/common';
import * as i0 from '@angular/core';
import { signal, inject, Injectable, input, Component, ChangeDetectionStrategy, HostListener, ElementRef, Directive, NgModule } from '@angular/core';
import { polyfill } from 'seamless-scroll-polyfill';
class NgxScrollTopCoreService {
constructor() {
this.scrolledFromTop = signal(false);
this.scrollOffset = signal(0);
this.isBrowser = typeof window !== 'undefined';
this.alreadyActivated = signal(false);
this.document = inject(DOCUMENT);
}
onWindowScroll(mode) {
const position = this.document.documentElement?.scrollTop || this.document.scrollingElement?.scrollTop;
switch (mode) {
case 'classic':
return this.classicMode(position);
case 'smart':
return this.smartMode(position);
}
}
classicMode(position) {
if (this.isBrowser && position > window.innerHeight) {
return true;
}
else {
return false;
}
}
smartMode(position) {
let show = false;
if (position === 0) {
show = false;
this.scrolledFromTop.set(false);
}
if (this.scrolledFromTop() && this.scrollOffset() > position) {
show = true;
}
if (this.isBrowser && position > window.innerHeight * 2) {
this.scrolledFromTop.set(true);
this.scrollOffset.set(position);
}
return show;
}
scrollToTop() {
if (this.isBrowser) {
// Kick off the polyfill for iOS Safari
if (!this.alreadyActivated()) {
polyfill();
this.alreadyActivated.set(true);
}
// Scroll to the top
window.scroll({ top: 0, left: 0, behavior: 'smooth' });
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: NgxScrollTopCoreService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: NgxScrollTopCoreService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: NgxScrollTopCoreService, decorators: [{
type: Injectable
}] });
class NgxScrollTopComponent {
constructor() {
this.backgroundColor = input();
this.symbolColor = input();
this.size = input();
this.position = input('right');
this.theme = input('gray');
this.mode = input('classic');
this.show = signal(false);
this.core = inject(NgxScrollTopCoreService);
}
onWindowScroll() {
const show = this.core.onWindowScroll(this.mode());
// Performance boost. Only update the state if it has changed.
if (this.show() !== show) {
this.show.set(show);
}
}
scrollToTop() {
this.core.scrollToTop();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: NgxScrollTopComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.5", type: NgxScrollTopComponent, isStandalone: true, selector: "ngx-scrolltop", inputs: { backgroundColor: { classPropertyName: "backgroundColor", publicName: "backgroundColor", isSignal: true, isRequired: false, transformFunction: null }, symbolColor: { classPropertyName: "symbolColor", publicName: "symbolColor", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, theme: { classPropertyName: "theme", publicName: "theme", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "window:scroll": "onWindowScroll()" } }, providers: [NgxScrollTopCoreService], ngImport: i0, template: "@if (show()) {\n <button\n type=\"button\"\n role=\"button\"\n aria-label=\"Scroll to top of the page\"\n tabindex=\"0\"\n class=\"scrolltop-button\"\n #scrollTopButton\n (click)=\"scrollToTop()\"\n [ngClass]=\"theme()\"\n [style.left]=\"position() === 'left' ? '20px' : ''\"\n [style.backgroundColor]=\"backgroundColor()\"\n [style.width.px]=\"size()\"\n [style.height.px]=\"size()\">\n <div class=\"symbol-container\">\n <span #ref>\n <ng-content></ng-content>\n </span>\n @if (ref.childNodes.length === 0) {\n <svg \n aria-hidden=\"true\"\n [style.fill]=\"symbolColor()\"\n focusable=\"false\"\n role=\"img\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 448 512\">\n <path\n d=\"M240.971 130.524l194.343 194.343c9.373 9.373 9.373 24.569 0 33.941l-22.667 22.667c-9.357 9.357-24.522 9.375-33.901.04L224 227.495 69.255 381.516c-9.379 9.335-24.544 9.317-33.901-.04l-22.667-22.667c-9.373-9.373-9.373-24.569 0-33.941L207.03 130.525c9.372-9.373 24.568-9.373 33.941-.001z\">\n </path>\n </svg>\n }\n </div>\n </button>\n}", styles: ["button{outline:0;-webkit-user-select:none;user-select:none}.scrolltop-button{position:fixed;display:flex;justify-content:center;align-items:center;border-radius:50%;padding:0;width:40px;height:40px;right:20px;bottom:20px;cursor:pointer;border:none;transition:opacity .1s linear;z-index:10000;box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f}.scrolltop-button:hover{opacity:.92}.scrolltop-button .symbol-container span{font-size:15px}.scrolltop-button .symbol-container span:empty{display:none}.scrolltop-button .symbol-container svg{display:inline-flex;transform:translateY(10%);width:35%;vertical-align:baseline}.scrolltop-button.black{background-color:#000;color:#fff}.scrolltop-button.black .symbol-container,.scrolltop-button.black .symbol-container span{color:#fff}.scrolltop-button.black .symbol-container svg{fill:#fff}.scrolltop-button.white{background-color:#fff;color:#000}.scrolltop-button.white .symbol-container,.scrolltop-button.white .symbol-container span{color:#000}.scrolltop-button.white .symbol-container svg{fill:#000}.scrolltop-button.gray{background-color:#212121;color:#fafafa}.scrolltop-button.gray .symbol-container,.scrolltop-button.gray .symbol-container span{color:#fafafa}.scrolltop-button.gray .symbol-container svg{fill:#fafafa}.scrolltop-button.grey{background-color:#212121;color:#fafafa}.scrolltop-button.grey .symbol-container,.scrolltop-button.grey .symbol-container span{color:#fafafa}.scrolltop-button.grey .symbol-container svg{fill:#fafafa}.scrolltop-button.brown{background-color:#3e2723;color:#efebe9}.scrolltop-button.brown .symbol-container,.scrolltop-button.brown .symbol-container span{color:#efebe9}.scrolltop-button.brown .symbol-container svg{fill:#efebe9}.scrolltop-button.deeporange{background-color:#bf360c;color:#fbe9e7}.scrolltop-button.deeporange .symbol-container,.scrolltop-button.deeporange .symbol-container span{color:#fbe9e7}.scrolltop-button.deeporange .symbol-container svg{fill:#fbe9e7}.scrolltop-button.orange{background-color:#ff6d00;color:#fff3e0}.scrolltop-button.orange .symbol-container,.scrolltop-button.orange .symbol-container span{color:#fff3e0}.scrolltop-button.orange .symbol-container svg{fill:#fff3e0}.scrolltop-button.yellow{background-color:#ffd600;color:#fffde7}.scrolltop-button.yellow .symbol-container,.scrolltop-button.yellow .symbol-container span{color:#fffde7}.scrolltop-button.yellow .symbol-container svg{fill:#fffde7}.scrolltop-button.green{background-color:#1b5e20;color:#e8f5e9}.scrolltop-button.green .symbol-container,.scrolltop-button.green .symbol-container span{color:#e8f5e9}.scrolltop-button.green .symbol-container svg{fill:#e8f5e9}.scrolltop-button.blue{background-color:#2962ff;color:#e3f2fd}.scrolltop-button.blue .symbol-container,.scrolltop-button.blue .symbol-container span{color:#e3f2fd}.scrolltop-button.blue .symbol-container svg{fill:#e3f2fd}.scrolltop-button.purple{background-color:#4a148c;color:#f3e5f5}.scrolltop-button.purple .symbol-container,.scrolltop-button.purple .symbol-container span{color:#f3e5f5}.scrolltop-button.purple .symbol-container svg{fill:#f3e5f5}.scrolltop-button.deeppurple{background-color:#311b92;color:#ede7f6}.scrolltop-button.deeppurple .symbol-container,.scrolltop-button.deeppurple .symbol-container span{color:#ede7f6}.scrolltop-button.deeppurple .symbol-container svg{fill:#ede7f6}.scrolltop-button.pink{background-color:#880e4f;color:#fce4ec}.scrolltop-button.pink .symbol-container,.scrolltop-button.pink .symbol-container span{color:#fce4ec}.scrolltop-button.pink .symbol-container svg{fill:#fce4ec}.scrolltop-button.red{background-color:#b71c1c;color:#ffebee}.scrolltop-button.red .symbol-container,.scrolltop-button.red .symbol-container span{color:#ffebee}.scrolltop-button.red .symbol-container svg{fill:#ffebee}.scrolltop-button.indigo{background-color:#1a237e;color:#e8eaf6}.scrolltop-button.indigo .symbol-container,.scrolltop-button.indigo .symbol-container span{color:#e8eaf6}.scrolltop-button.indigo .symbol-container svg{fill:#e8eaf6}.scrolltop-button.lightblue{background-color:#01579b;color:#e1f5fe}.scrolltop-button.lightblue .symbol-container,.scrolltop-button.lightblue .symbol-container span{color:#e1f5fe}.scrolltop-button.lightblue .symbol-container svg{fill:#e1f5fe}.scrolltop-button.cyan{background-color:#006064;color:#e0f7fa}.scrolltop-button.cyan .symbol-container,.scrolltop-button.cyan .symbol-container span{color:#e0f7fa}.scrolltop-button.cyan .symbol-container svg{fill:#e0f7fa}.scrolltop-button.teal{background-color:#004d40;color:#e0f2f1}.scrolltop-button.teal .symbol-container,.scrolltop-button.teal .symbol-container span{color:#e0f2f1}.scrolltop-button.teal .symbol-container svg{fill:#e0f2f1}.scrolltop-button.lightgreen{background-color:#33691e;color:#f1f8e9}.scrolltop-button.lightgreen .symbol-container,.scrolltop-button.lightgreen .symbol-container span{color:#f1f8e9}.scrolltop-button.lightgreen .symbol-container svg{fill:#f1f8e9}.scrolltop-button.lime{background-color:#827717;color:#f9fbe7}.scrolltop-button.lime .symbol-container,.scrolltop-button.lime .symbol-container span{color:#f9fbe7}.scrolltop-button.lime .symbol-container svg{fill:#f9fbe7}.scrolltop-button.amber{background-color:#ff6f00;color:#fff8e1}.scrolltop-button.amber .symbol-container,.scrolltop-button.amber .symbol-container span{color:#fff8e1}.scrolltop-button.amber .symbol-container svg{fill:#fff8e1}.scrolltop-button.bluegrey{background-color:#263238;color:#eceff1}.scrolltop-button.bluegrey .symbol-container,.scrolltop-button.bluegrey .symbol-container span{color:#eceff1}.scrolltop-button.bluegrey .symbol-container svg{fill:#eceff1}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: NgxScrollTopComponent, decorators: [{
type: Component,
args: [{ selector: 'ngx-scrolltop', imports: [NgClass], providers: [NgxScrollTopCoreService], changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, template: "@if (show()) {\n <button\n type=\"button\"\n role=\"button\"\n aria-label=\"Scroll to top of the page\"\n tabindex=\"0\"\n class=\"scrolltop-button\"\n #scrollTopButton\n (click)=\"scrollToTop()\"\n [ngClass]=\"theme()\"\n [style.left]=\"position() === 'left' ? '20px' : ''\"\n [style.backgroundColor]=\"backgroundColor()\"\n [style.width.px]=\"size()\"\n [style.height.px]=\"size()\">\n <div class=\"symbol-container\">\n <span #ref>\n <ng-content></ng-content>\n </span>\n @if (ref.childNodes.length === 0) {\n <svg \n aria-hidden=\"true\"\n [style.fill]=\"symbolColor()\"\n focusable=\"false\"\n role=\"img\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 448 512\">\n <path\n d=\"M240.971 130.524l194.343 194.343c9.373 9.373 9.373 24.569 0 33.941l-22.667 22.667c-9.357 9.357-24.522 9.375-33.901.04L224 227.495 69.255 381.516c-9.379 9.335-24.544 9.317-33.901-.04l-22.667-22.667c-9.373-9.373-9.373-24.569 0-33.941L207.03 130.525c9.372-9.373 24.568-9.373 33.941-.001z\">\n </path>\n </svg>\n }\n </div>\n </button>\n}", styles: ["button{outline:0;-webkit-user-select:none;user-select:none}.scrolltop-button{position:fixed;display:flex;justify-content:center;align-items:center;border-radius:50%;padding:0;width:40px;height:40px;right:20px;bottom:20px;cursor:pointer;border:none;transition:opacity .1s linear;z-index:10000;box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f}.scrolltop-button:hover{opacity:.92}.scrolltop-button .symbol-container span{font-size:15px}.scrolltop-button .symbol-container span:empty{display:none}.scrolltop-button .symbol-container svg{display:inline-flex;transform:translateY(10%);width:35%;vertical-align:baseline}.scrolltop-button.black{background-color:#000;color:#fff}.scrolltop-button.black .symbol-container,.scrolltop-button.black .symbol-container span{color:#fff}.scrolltop-button.black .symbol-container svg{fill:#fff}.scrolltop-button.white{background-color:#fff;color:#000}.scrolltop-button.white .symbol-container,.scrolltop-button.white .symbol-container span{color:#000}.scrolltop-button.white .symbol-container svg{fill:#000}.scrolltop-button.gray{background-color:#212121;color:#fafafa}.scrolltop-button.gray .symbol-container,.scrolltop-button.gray .symbol-container span{color:#fafafa}.scrolltop-button.gray .symbol-container svg{fill:#fafafa}.scrolltop-button.grey{background-color:#212121;color:#fafafa}.scrolltop-button.grey .symbol-container,.scrolltop-button.grey .symbol-container span{color:#fafafa}.scrolltop-button.grey .symbol-container svg{fill:#fafafa}.scrolltop-button.brown{background-color:#3e2723;color:#efebe9}.scrolltop-button.brown .symbol-container,.scrolltop-button.brown .symbol-container span{color:#efebe9}.scrolltop-button.brown .symbol-container svg{fill:#efebe9}.scrolltop-button.deeporange{background-color:#bf360c;color:#fbe9e7}.scrolltop-button.deeporange .symbol-container,.scrolltop-button.deeporange .symbol-container span{color:#fbe9e7}.scrolltop-button.deeporange .symbol-container svg{fill:#fbe9e7}.scrolltop-button.orange{background-color:#ff6d00;color:#fff3e0}.scrolltop-button.orange .symbol-container,.scrolltop-button.orange .symbol-container span{color:#fff3e0}.scrolltop-button.orange .symbol-container svg{fill:#fff3e0}.scrolltop-button.yellow{background-color:#ffd600;color:#fffde7}.scrolltop-button.yellow .symbol-container,.scrolltop-button.yellow .symbol-container span{color:#fffde7}.scrolltop-button.yellow .symbol-container svg{fill:#fffde7}.scrolltop-button.green{background-color:#1b5e20;color:#e8f5e9}.scrolltop-button.green .symbol-container,.scrolltop-button.green .symbol-container span{color:#e8f5e9}.scrolltop-button.green .symbol-container svg{fill:#e8f5e9}.scrolltop-button.blue{background-color:#2962ff;color:#e3f2fd}.scrolltop-button.blue .symbol-container,.scrolltop-button.blue .symbol-container span{color:#e3f2fd}.scrolltop-button.blue .symbol-container svg{fill:#e3f2fd}.scrolltop-button.purple{background-color:#4a148c;color:#f3e5f5}.scrolltop-button.purple .symbol-container,.scrolltop-button.purple .symbol-container span{color:#f3e5f5}.scrolltop-button.purple .symbol-container svg{fill:#f3e5f5}.scrolltop-button.deeppurple{background-color:#311b92;color:#ede7f6}.scrolltop-button.deeppurple .symbol-container,.scrolltop-button.deeppurple .symbol-container span{color:#ede7f6}.scrolltop-button.deeppurple .symbol-container svg{fill:#ede7f6}.scrolltop-button.pink{background-color:#880e4f;color:#fce4ec}.scrolltop-button.pink .symbol-container,.scrolltop-button.pink .symbol-container span{color:#fce4ec}.scrolltop-button.pink .symbol-container svg{fill:#fce4ec}.scrolltop-button.red{background-color:#b71c1c;color:#ffebee}.scrolltop-button.red .symbol-container,.scrolltop-button.red .symbol-container span{color:#ffebee}.scrolltop-button.red .symbol-container svg{fill:#ffebee}.scrolltop-button.indigo{background-color:#1a237e;color:#e8eaf6}.scrolltop-button.indigo .symbol-container,.scrolltop-button.indigo .symbol-container span{color:#e8eaf6}.scrolltop-button.indigo .symbol-container svg{fill:#e8eaf6}.scrolltop-button.lightblue{background-color:#01579b;color:#e1f5fe}.scrolltop-button.lightblue .symbol-container,.scrolltop-button.lightblue .symbol-container span{color:#e1f5fe}.scrolltop-button.lightblue .symbol-container svg{fill:#e1f5fe}.scrolltop-button.cyan{background-color:#006064;color:#e0f7fa}.scrolltop-button.cyan .symbol-container,.scrolltop-button.cyan .symbol-container span{color:#e0f7fa}.scrolltop-button.cyan .symbol-container svg{fill:#e0f7fa}.scrolltop-button.teal{background-color:#004d40;color:#e0f2f1}.scrolltop-button.teal .symbol-container,.scrolltop-button.teal .symbol-container span{color:#e0f2f1}.scrolltop-button.teal .symbol-container svg{fill:#e0f2f1}.scrolltop-button.lightgreen{background-color:#33691e;color:#f1f8e9}.scrolltop-button.lightgreen .symbol-container,.scrolltop-button.lightgreen .symbol-container span{color:#f1f8e9}.scrolltop-button.lightgreen .symbol-container svg{fill:#f1f8e9}.scrolltop-button.lime{background-color:#827717;color:#f9fbe7}.scrolltop-button.lime .symbol-container,.scrolltop-button.lime .symbol-container span{color:#f9fbe7}.scrolltop-button.lime .symbol-container svg{fill:#f9fbe7}.scrolltop-button.amber{background-color:#ff6f00;color:#fff8e1}.scrolltop-button.amber .symbol-container,.scrolltop-button.amber .symbol-container span{color:#fff8e1}.scrolltop-button.amber .symbol-container svg{fill:#fff8e1}.scrolltop-button.bluegrey{background-color:#263238;color:#eceff1}.scrolltop-button.bluegrey .symbol-container,.scrolltop-button.bluegrey .symbol-container span{color:#eceff1}.scrolltop-button.bluegrey .symbol-container svg{fill:#eceff1}\n"] }]
}], propDecorators: { onWindowScroll: [{
type: HostListener,
args: ['window:scroll']
}] } });
class NgxScrollTopDirective {
constructor() {
this.mode = input('classic', { alias: 'ngxScrollTopMode' });
this.show = signal(false);
this.el = inject(ElementRef);
this.core = inject(NgxScrollTopCoreService);
this.hideElement();
}
onWindowScroll() {
const show = this.core.onWindowScroll(this.mode());
// Performance boost. Only update the DOM when the state changes.
if (this.show() !== show) {
show ? this.showElement() : this.hideElement();
this.show.set(show);
}
}
onClick() {
this.scrollToTop();
}
hideElement() {
this.el.nativeElement.style.display = 'none';
}
showElement() {
this.el.nativeElement.style.display = '';
}
scrollToTop() {
this.core.scrollToTop();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: NgxScrollTopDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.0.5", type: NgxScrollTopDirective, isStandalone: true, selector: "[ngxScrollTop]", inputs: { mode: { classPropertyName: "mode", publicName: "ngxScrollTopMode", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "window:scroll": "onWindowScroll()", "click": "onClick()" } }, providers: [NgxScrollTopCoreService], ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: NgxScrollTopDirective, decorators: [{
type: Directive,
args: [{
selector: '[ngxScrollTop]',
standalone: true,
providers: [NgxScrollTopCoreService],
}]
}], ctorParameters: () => [], propDecorators: { onWindowScroll: [{
type: HostListener,
args: ['window:scroll']
}], onClick: [{
type: HostListener,
args: ['click']
}] } });
class NgxScrollTopModule {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: NgxScrollTopModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.0.5", ngImport: i0, type: NgxScrollTopModule, imports: [CommonModule, NgxScrollTopComponent, NgxScrollTopDirective], exports: [NgxScrollTopComponent, NgxScrollTopDirective] }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: NgxScrollTopModule, providers: [NgxScrollTopCoreService], imports: [CommonModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: NgxScrollTopModule, decorators: [{
type: NgModule,
args: [{
imports: [CommonModule, NgxScrollTopComponent, NgxScrollTopDirective],
providers: [NgxScrollTopCoreService],
exports: [NgxScrollTopComponent, NgxScrollTopDirective],
}]
}] });
/*
* Public API Surface of ngx-scrolltop
*/
/**
* Generated bundle index. Do not edit.
*/
export { NgxScrollTopComponent, NgxScrollTopDirective, NgxScrollTopModule };
//# sourceMappingURL=ngx-scrolltop.mjs.map