Skip to content

Commit 07d89f6

Browse files
committed
Apply final styles and inputs
1 parent fab0b86 commit 07d89f6

File tree

6 files changed

+196
-30
lines changed

6 files changed

+196
-30
lines changed

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@proangular/ngx-scroll-top",
3-
"version": "1.0.1",
3+
"version": "1.0.2",
44
"description": "Configurable, lightweight back to top button for Angular projects.",
55
"author": "Pro Angular <webmaster@proangular.com>",
66
"homepage": "https://www.proangular.com",
@@ -25,7 +25,8 @@
2525
"peerDependencies": {
2626
"@angular/animations": ">=12 <15",
2727
"@angular/common": ">=12 <15",
28-
"@angular/core": ">=12 <15"
28+
"@angular/core": ">=12 <15",
29+
"@angular/platform-browser": ">=12 <15"
2930
},
3031
"devDependencies": {
3132
"@angular-devkit/build-angular": "^14.1.0",
@@ -38,7 +39,6 @@
3839
"@angular/compiler": "^14.1.0",
3940
"@angular/compiler-cli": "^14.1.0",
4041
"@angular/forms": "^14.1.0",
41-
"@angular/platform-browser": "^14.1.0",
4242
"@angular/platform-browser-dynamic": "^14.1.0",
4343
"@angular/router": "^14.1.0",
4444
"@types/jasmine": "~4.0.0",

src/app/app.component.ts

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,41 @@ import { Component } from '@angular/core';
22

33
@Component({
44
selector: 'ngx-app',
5-
template: `<p>Init</p>`,
5+
template: `
6+
<header></header>
7+
<section>
8+
<p *ngFor="let number of Array(88)">
9+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
10+
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minimssy
11+
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip expir
12+
ea commodo consequat. Duis aute irure dolor in reprehenderit in esselpa
13+
voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteury
14+
sint occaecat cupidatat non proident, sunt in culpa qui officia luretzo
15+
deserunt mollit anim id est laborum.
16+
</p>
17+
</section>
18+
<footer #footer></footer>
19+
<ngx-scroll-top
20+
backgroundColor="#000"
21+
[bottomOffset]="footer.offsetHeight"
22+
></ngx-scroll-top>
23+
`,
24+
styles: [
25+
`
26+
header {
27+
background-color: #1775d1;
28+
height: 80px;
29+
}
30+
section {
31+
padding: 1rem;
32+
}
33+
footer {
34+
background-color: #1775d1;
35+
height: 420px;
36+
}
37+
`,
38+
],
639
})
7-
export class AppComponent {}
40+
export class AppComponent {
41+
public readonly Array = Array;
42+
}

src/app/public/ngx-scroll-top.component.ts

Lines changed: 148 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,38 @@
11
import { animate, style, transition, trigger } from '@angular/animations';
2-
import { Component, HostBinding, HostListener, Input } from '@angular/core';
3-
4-
const w = window;
2+
import {
3+
Component,
4+
HostBinding,
5+
HostListener,
6+
Input,
7+
OnInit,
8+
} from '@angular/core';
59

610
@Component({
711
selector: 'ngx-scroll-top',
812
template: `
9-
<button *ngIf="!isHidden" (click)="scrollTop()" [@easeInOutAnimation]>
10-
Up
13+
<button
14+
*ngIf="!isHidden"
15+
(click)="scrollTop()"
16+
[style.background-color]="backgroundColor"
17+
[@easeInOutAnimation]
18+
>
19+
<div #content>
20+
<ng-content></ng-content>
21+
</div>
22+
<svg
23+
*ngIf="!content?.innerHTML?.length"
24+
xmlns="http://www.w3.org/2000/svg"
25+
viewBox="0 0 24 24"
26+
fill="currentColor"
27+
aria-hidden="true"
28+
focusable="false"
29+
>
30+
<desc>
31+
https://fonts.gstatic.com/s/i/materialicons/expand_less/v12/24px.svg
32+
</desc>
33+
<path d="M0 0h24v24H0z" fill="none" />
34+
<path d="M12 8l-6 6 1.41 1.41L12 10.83l4.59 4.58L18 14z" />
35+
</svg>
1136
</button>
1237
`,
1338
animations: [
@@ -26,31 +51,115 @@ const w = window;
2651
`
2752
:host {
2853
position: fixed;
29-
right: 2rem;
30-
width: 25px;
3154
transition: all 0.1s ease-in-out;
32-
z-index: 9999;
55+
}
56+
button {
57+
display: inline-block;
58+
position: relative;
59+
transition: all 0.1s ease-in-out;
60+
color: white;
61+
box-shadow: 0px 3px 5px -1px rgba(0, 0, 0, 0.2),
62+
0px 6px 10px 0px rgba(0, 0, 0, 0.14),
63+
0px 1px 18px 0px rgba(0, 0, 0, 0.12);
64+
user-select: none;
65+
cursor: pointer;
66+
outline: none;
67+
border: none;
68+
box-sizing: border-box;
69+
white-space: nowrap;
70+
text-decoration: none;
71+
vertical-align: baseline;
72+
text-align: center;
73+
margin: 0;
74+
/** line-height: 36px; */
75+
border-radius: 50%;
76+
padding: 0;
77+
flex-shrink: 0;
78+
}
79+
button,
80+
button > svg {
81+
width: 100%;
82+
height: 100%;
3383
}
3484
`,
3585
],
3686
})
37-
export class NgxScrollTopComponent {
38-
private readonly styleBottomDefault = '32px';
39-
public isHidden = true;
40-
87+
export class NgxScrollTopComponent implements OnInit {
4188
/**
42-
* Offset button from bottom of page dynamically by setting this value.
89+
* Background color of the back to top button (hex string).
90+
*
91+
* Default: `#1775d1` (blue)
92+
*/
93+
@Input() public backgroundColor = '#1775d1';
94+
/**
95+
* Offset `px` from bottom of page when scrolled to bottom. For example this
96+
* can be used to make sure the back to top button never overlaps a footer.
97+
*
98+
* Default: `0px`
99+
*
100+
* Example: `250px` or `250` because my footer is 250px in height
43101
*/
44102
@Input() public bottomOffset: string | number = '0px';
103+
/**
104+
* The back to top button will not be displayed until the user scrolls to the
105+
* provided Y (vertical `px`) coordinate on the page.
106+
*
107+
* Default: `420px`
108+
*
109+
* Example: `100px` or `100`
110+
*/
45111
@Input() public displayAtYPosition: string | number = '420px';
112+
/**
113+
* Position on-screen where the back to top button is displayed.
114+
*
115+
* Default: `right`
116+
*/
117+
@Input() public position: 'left' | 'right' = 'right';
118+
/**
119+
* Height of back to top button in string px format.
120+
*
121+
* Default: `25px`
122+
*/
123+
@Input() @HostBinding('style.height') public styleHeight = '40px';
124+
/**
125+
* Width of back to top button in string px format.
126+
*
127+
* Default: `25px`
128+
*/
129+
@Input() @HostBinding('style.width') public styleWidth = '40px';
130+
/**
131+
* Style the `z-index` for the back to top button as needed for correct layer
132+
* height adjustment. This can be useful when working with sticky headers.
133+
*
134+
* Default: `999`
135+
*/
136+
@Input() @HostBinding('style.z-index') public styleZIndex = 999;
46137

47-
@HostBinding('style.bottom') public styleBottom = this.styleBottomDefault;
48-
@HostBinding('style.height') public styleHeight = '25px';
138+
public isHidden = true;
139+
private readonly defaultPadding = '16px';
140+
141+
@HostBinding('style.bottom') public styleBottom = this.defaultPadding;
142+
@HostBinding('style.left') public styleLeft = 'unset';
143+
@HostBinding('style.right') public styleRight = this.defaultPadding;
49144
@HostListener('window:scroll', []) public onWindowScroll(): void {
50145
this.updateIsHidden();
51146
this.updatePosition();
52147
}
53148

149+
public ngOnInit(): void {
150+
switch (this.position) {
151+
case 'left':
152+
this.styleRight = 'unset';
153+
this.styleLeft = this.defaultPadding;
154+
break;
155+
case 'right':
156+
default:
157+
this.styleRight = this.defaultPadding;
158+
this.styleLeft = 'unset';
159+
break;
160+
}
161+
}
162+
54163
public scrollTop(): void {
55164
w.scroll({
56165
top: 0,
@@ -61,8 +170,7 @@ export class NgxScrollTopComponent {
61170

62171
private updatePosition(): void {
63172
const useDefaultPosition = (): void => {
64-
// Use the default position.
65-
this.styleBottom = this.styleBottomDefault;
173+
this.styleBottom = this.defaultPadding;
66174
};
67175

68176
if (this.isHidden) {
@@ -74,13 +182,16 @@ export class NgxScrollTopComponent {
74182
const { document, scrollY } = w;
75183
const { documentElement: docEl } = document;
76184
const bottomY = docEl.scrollHeight - docEl.clientHeight;
77-
const bottomOffset = parseInt(this.bottomOffset.toString(), 10);
185+
const bottomOffset = parsePxStringToInt(this.bottomOffset);
78186
const distanceFromBottom = bottomY - scrollY;
79-
const height = parseInt(this.styleHeight, 10);
187+
const halfHeight = parsePxStringToInt(this.styleHeight) / 2;
188+
const defaultPadding = parsePxStringToInt(this.defaultPadding);
80189

81-
if (distanceFromBottom + (height - height / 2) < bottomOffset) {
190+
if (distanceFromBottom + (halfHeight - defaultPadding) < bottomOffset) {
82191
// Scroll up button exceeded bottom offset, update position.
83-
this.styleBottom = `${bottomOffset - distanceFromBottom + height}px`;
192+
this.styleBottom = `${
193+
bottomOffset - distanceFromBottom + defaultPadding
194+
}px`;
84195
} else {
85196
useDefaultPosition();
86197
}
@@ -95,10 +206,24 @@ export class NgxScrollTopComponent {
95206

96207
private updateIsHidden(): void {
97208
const { scrollY } = w;
98-
if (this.isHidden && scrollY > this.displayAtYPosition) {
209+
const displayAtYPosition = parsePxStringToInt(this.displayAtYPosition);
210+
211+
if (this.isHidden && scrollY > displayAtYPosition) {
99212
this.isHidden = false;
100-
} else if (!this.isHidden && scrollY <= this.displayAtYPosition) {
213+
} else if (!this.isHidden && scrollY <= displayAtYPosition) {
101214
this.isHidden = true;
102215
}
103216
}
104217
}
218+
219+
const w = window;
220+
221+
function parsePxStringToInt(value: string | number): number {
222+
try {
223+
return parseInt(value.toString(), 10);
224+
} catch (error: unknown) {
225+
throw new Error(
226+
`Failed to parse value "${value}" with error: ${String(error)}`,
227+
);
228+
}
229+
}

src/app/public/ngx-scroll-top.module.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { CommonModule } from '@angular/common';
22
import { NgModule } from '@angular/core';
33
import { NgxScrollTopComponent } from './ngx-scroll-top.component';
4+
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
45

56
@NgModule({
67
declarations: [NgxScrollTopComponent],
7-
imports: [CommonModule],
8+
imports: [BrowserAnimationsModule, CommonModule],
89
exports: [NgxScrollTopComponent],
910
providers: [],
1011
})

src/styles.scss

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
11
/* You can add global styles to this file, and also import other style files */
2+
3+
body {
4+
padding: 0;
5+
margin: 0;
6+
}

0 commit comments

Comments
 (0)