Skip to content

Commit 33fa4c6

Browse files
committed
Apply Copilot feedback
1 parent a73d97b commit 33fa4c6

File tree

4 files changed

+39
-18
lines changed

4 files changed

+39
-18
lines changed

README.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -152,17 +152,17 @@ Customization with optional inputs and icon
152152

153153
## 📚 Component API <a name="api"></a>
154154

155-
| Input | Value Typing | Default Value | Description |
156-
| ---------------------- | ----------------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
157-
| **backgroundColor** | string | `#0D58C0` | Background color of the back to top button. Define any `'x'` css property available for `'background-color: x'`. |
158-
| **bottomOffset** | string \| number | `0px` | Offset `px` from bottom of page when scrolled to bottom. For example this can be used to make sure the back to top button never overlaps a footer. |
159-
| **displayAtYPosition** | string \| number | `420px` | The back to top button will not be displayed until the user scrolls to the provided Y (vertical `px`) coordinate on the page. |
160-
| **fontColor** | string | `#FFFFFF` | The font color for the nested content within the back to top button. Define any `'x'` css property available for `'color: x'`. |
161-
| **fontSize** | string | `16px` | The font size for the nested content within the back to top button. Define any `'x'` css property available for `'font-size: x'`. |
162-
| **height** | string | `32px` \| `1rem` | Height of back to top button in string format. |
163-
| **position** | `left` \| `right` | `right` | Position on-screen where the back to top button is displayed. |
164-
| **width** | string | `32px` \| `1rem` | Width of back to top button in string format. |
165-
| **zIndex** | number | `999` | Style the `z-index` for the back to top button as needed for correct layer height adjustment. This can be useful when working with sticky headers. |
155+
| Input | Value Typing | Default Value | Description |
156+
| ---------------------- | ---------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
157+
| **backgroundColor** | string | #0D58C0 | Background color of the back to top button. Define any 'x' css property available for 'background-color: x'. |
158+
| **bottomOffset** | string \| number | 0px | Offset px from bottom of page when scrolled to bottom. For example this can be used to make sure the back to top button never overlaps a footer. |
159+
| **displayAtYPosition** | string \| number | 420px | The back to top button will not be displayed until the user scrolls to the provided Y (vertical px) coordinate on the page. |
160+
| **fontColor** | string | #FFFFFF | The font color for the nested content within the back to top button. Define any 'x' css property available for 'color: x'. |
161+
| **fontSize** | string | 16px | The font size for the nested content within the back to top button. Define any 'x' css property available for 'font-size: x'. |
162+
| **height** | string | 32px \| 1rem | Height of back to top button in string format. |
163+
| **position** | left \| right | right | Position on-screen where the back to top button is displayed. |
164+
| **width** | string | 32px \| 1rem | Width of back to top button in string format. |
165+
| **zIndex** | number | 999 | Style the z-index for the back to top button as needed for correct layer height adjustment. This can be useful when working with sticky headers. |
166166

167167
<p align="right">[ <a href="#index">🔍 Index</a> ]</p>
168168

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
(click)="scrollTop()"
44
[class.fade-in]="fadeState() === 'fading-in'"
55
[class.fade-out]="fadeState() === 'fading-out'"
6-
[class.idle]="fadeState() === 'idle'"
6+
[class.not-rendered]="isButtonNotRendered()"
77
[style.background-color]="backgroundColor()"
88
aria-label="Scroll to top"
99
>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,6 @@ svg.default-content {
6262
top: 0;
6363
}
6464

65-
button.idle {
65+
button.not-rendered {
6666
opacity: 0;
6767
}

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

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ const animationMs = 200;
4040
}
4141
`,
4242
],
43+
imports: [],
44+
standalone: true,
4345
})
4446
export class NgxScrollTopComponent implements OnInit, OnDestroy {
4547
/**
@@ -159,6 +161,10 @@ export class NgxScrollTopComponent implements OnInit, OnDestroy {
159161
/** Timeout reference for fade completion. */
160162
private fadeTimeout?: ReturnType<typeof setTimeout>;
161163

164+
protected isButtonNotRendered = signal(true);
165+
166+
private isDestroyed = false;
167+
162168
private animationFrameId?: number;
163169

164170
@HostBinding('style.bottom') protected styleBottom = this.defaultPadding;
@@ -189,11 +195,14 @@ export class NgxScrollTopComponent implements OnInit, OnDestroy {
189195
}
190196

191197
public ngOnDestroy(): void {
198+
this.isDestroyed = true;
192199
if (this.fadeTimeout) {
193200
clearTimeout(this.fadeTimeout);
201+
this.fadeTimeout = undefined;
194202
}
195203
if (this.animationFrameId) {
196204
cancelAnimationFrame(this.animationFrameId);
205+
this.animationFrameId = undefined;
197206
}
198207
}
199208

@@ -253,25 +262,37 @@ export class NgxScrollTopComponent implements OnInit, OnDestroy {
253262

254263
// Fade in
255264
if (!this.shouldRenderButton() && scrollY > displayAtYPosition) {
265+
// Cancel any pending fade-out
266+
if (this.fadeTimeout) {
267+
clearTimeout(this.fadeTimeout);
268+
this.fadeTimeout = undefined;
269+
}
270+
this.fadeState.set('idle'); // Reset fade state
256271
this.shouldRenderButton.set(true);
257-
this.fadeState.set('idle');
258-
if (this.fadeTimeout) clearTimeout(this.fadeTimeout);
272+
this.isButtonNotRendered.set(true);
259273

260-
// Cancel previous frame if exists
274+
// Cancel previous animation frame if exists
261275
if (this.animationFrameId) {
262276
cancelAnimationFrame(this.animationFrameId);
263277
}
264278

265-
// Schedule fade-in with animation frame
266-
this.animationFrameId = requestAnimationFrame(() => {
279+
// Schedule and track new animation frame
280+
const animationFrameId = requestAnimationFrame(() => {
281+
if (this.isDestroyed) return;
267282
this.fadeState.set('fading-in');
283+
this.isButtonNotRendered.set(false);
284+
this.animationFrameId = undefined;
268285
});
286+
287+
this.animationFrameId = animationFrameId;
269288
}
289+
270290
// Fade out
271291
else if (this.shouldRenderButton() && scrollY <= displayAtYPosition) {
272292
this.fadeState.set('fading-out');
273293
if (this.fadeTimeout) clearTimeout(this.fadeTimeout);
274294
this.fadeTimeout = setTimeout(() => {
295+
if (this.isDestroyed) return;
275296
this.shouldRenderButton.set(false);
276297
this.fadeState.set('idle');
277298
}, this.fadeDuration);

0 commit comments

Comments
 (0)