UNPKG

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
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