mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
302 lines
8.4 KiB
Markdown
302 lines
8.4 KiB
Markdown
# @isa/utils/scroll-position
|
|
|
|
Utility library providing scroll position restoration and scroll-to-top functionality for Angular applications.
|
|
|
|
## Overview
|
|
|
|
The `@isa/utils/scroll-position` library enables automatic scroll position preservation across route navigations and provides a reusable scroll-to-top button component. It stores scroll positions in session storage and restores them when users navigate back to previously visited routes, creating a smoother user experience for applications with long, scrollable content.
|
|
|
|
**Key Features:**
|
|
- **Automatic Scroll Restoration**: Preserve and restore scroll position across route navigation
|
|
- **Session Storage Integration**: Persists scroll positions in session storage for reliability
|
|
- **Route-Level Control**: Enable/disable restoration per route via route data configuration
|
|
- **Scroll-to-Top Button**: Ready-to-use component with accessibility support
|
|
- **Configurable Delays**: Control timing of scroll restoration with optional delays
|
|
|
|
**Type:** Utility library with functions, providers, and components
|
|
|
|
## Installation
|
|
|
|
```typescript
|
|
import {
|
|
provideScrollPositionRestoration,
|
|
injectRestoreScrollPosition,
|
|
storeScrollPosition,
|
|
ScrollTopButtonComponent
|
|
} from '@isa/utils/scroll-position';
|
|
```
|
|
|
|
## API Reference
|
|
|
|
### Providers
|
|
|
|
#### `provideScrollPositionRestoration()`
|
|
|
|
Provides an environment initializer that automatically stores scroll positions during navigation and page unload events.
|
|
|
|
**Returns:** `EnvironmentProviders`
|
|
|
|
**Behavior:**
|
|
- Listens to `NavigationStart` events from the Angular Router
|
|
- Listens to the `beforeunload` window event
|
|
- Only stores scroll position for routes with `scrollPositionRestoration: true` in their route data
|
|
- Stores positions in session storage using the current URL as the key
|
|
|
|
**Usage:**
|
|
|
|
```typescript
|
|
// In app.config.ts
|
|
import { provideScrollPositionRestoration } from '@isa/utils/scroll-position';
|
|
|
|
export const appConfig: ApplicationConfig = {
|
|
providers: [
|
|
provideScrollPositionRestoration(),
|
|
// other providers...
|
|
]
|
|
};
|
|
```
|
|
|
|
### Functions
|
|
|
|
#### `storeScrollPosition()`
|
|
|
|
Stores the current viewport scroll position in session storage using the current router URL as the key.
|
|
|
|
**Returns:** `Promise<void>`
|
|
|
|
**Usage:**
|
|
|
|
```typescript
|
|
import { Component } from '@angular/core';
|
|
import { storeScrollPosition } from '@isa/utils/scroll-position';
|
|
|
|
@Component({
|
|
selector: 'app-product-list',
|
|
// ...
|
|
})
|
|
export class ProductListComponent {
|
|
async onNavigateAway() {
|
|
// Manually store scroll position before navigating
|
|
await storeScrollPosition();
|
|
// navigation logic...
|
|
}
|
|
}
|
|
```
|
|
|
|
#### `injectRestoreScrollPosition()`
|
|
|
|
Returns a function that restores the scroll position from session storage for the current route.
|
|
|
|
**Returns:** `(delay?: number) => Promise<void>` - An async function that accepts an optional delay parameter
|
|
|
|
**Parameters (returned function):**
|
|
- `delay?: number` - Optional delay in milliseconds before restoring scroll position (default: 0)
|
|
|
|
**Behavior:**
|
|
- Retrieves stored scroll position using the current router URL as the key
|
|
- Waits for the specified delay to ensure the DOM is ready
|
|
- Clears the stored position after restoration
|
|
- Does nothing if no position was stored for the current URL
|
|
|
|
**Usage:**
|
|
|
|
```typescript
|
|
import { Component, OnInit } from '@angular/core';
|
|
import { injectRestoreScrollPosition } from '@isa/utils/scroll-position';
|
|
|
|
@Component({
|
|
selector: 'app-product-list',
|
|
// ...
|
|
})
|
|
export class ProductListComponent implements OnInit {
|
|
private restoreScrollPosition = injectRestoreScrollPosition();
|
|
|
|
async ngOnInit() {
|
|
// Restore scroll position after 100ms to ensure content is rendered
|
|
await this.restoreScrollPosition(100);
|
|
}
|
|
}
|
|
```
|
|
|
|
### Components
|
|
|
|
#### `ScrollTopButtonComponent`
|
|
|
|
A standalone component that displays a button to scroll back to the top of the page or a specific scrollable element.
|
|
|
|
**Selector:** `utils-scroll-top-button`
|
|
|
|
**Inputs:**
|
|
- `target: Window | HTMLElement` - The scroll target (default: `window`)
|
|
|
|
**Features:**
|
|
- Automatically shows/hides based on scroll position (shows when scrolled down)
|
|
- Respects user's `prefers-reduced-motion` setting
|
|
- Uses smooth scrolling when motion is not reduced
|
|
- Includes proper accessibility attributes (`aria-label`)
|
|
- E2E testing ready with `data-what` attribute
|
|
|
|
**Styling:**
|
|
- Host class: `utils-scroll-top-button`
|
|
- Uses `ViewEncapsulation.None` for flexible styling
|
|
- Button uses tertiary color and large size from `@isa/ui/buttons`
|
|
|
|
**Usage:**
|
|
|
|
```typescript
|
|
// Basic usage (scrolls window)
|
|
import { ScrollTopButtonComponent } from '@isa/utils/scroll-position';
|
|
|
|
@Component({
|
|
selector: 'app-product-list',
|
|
imports: [ScrollTopButtonComponent],
|
|
template: `
|
|
<div class="content">
|
|
<!-- Your scrollable content -->
|
|
</div>
|
|
<utils-scroll-top-button />
|
|
`
|
|
})
|
|
export class ProductListComponent {}
|
|
```
|
|
|
|
```typescript
|
|
// Custom scroll target (specific element)
|
|
@Component({
|
|
selector: 'app-modal',
|
|
imports: [ScrollTopButtonComponent],
|
|
template: `
|
|
<div #scrollContainer class="modal-content">
|
|
<!-- Long content -->
|
|
</div>
|
|
<utils-scroll-top-button [target]="scrollContainer" />
|
|
`
|
|
})
|
|
export class ModalComponent {
|
|
@ViewChild('scrollContainer') scrollContainer!: ElementRef<HTMLElement>;
|
|
}
|
|
```
|
|
|
|
**Styling Example:**
|
|
|
|
```scss
|
|
// Custom positioning and appearance
|
|
utils-scroll-top-button {
|
|
position: fixed;
|
|
bottom: 2rem;
|
|
right: 2rem;
|
|
z-index: 1000;
|
|
}
|
|
```
|
|
|
|
## Usage Examples
|
|
|
|
### Complete Setup with Automatic Restoration
|
|
|
|
```typescript
|
|
// 1. Configure in app.config.ts
|
|
import { ApplicationConfig } from '@angular/core';
|
|
import { provideScrollPositionRestoration } from '@isa/utils/scroll-position';
|
|
|
|
export const appConfig: ApplicationConfig = {
|
|
providers: [
|
|
provideScrollPositionRestoration(),
|
|
]
|
|
};
|
|
|
|
// 2. Enable in route configuration
|
|
export const routes: Routes = [
|
|
{
|
|
path: 'products',
|
|
component: ProductListComponent,
|
|
data: { scrollPositionRestoration: true }
|
|
}
|
|
];
|
|
|
|
// 3. Restore position in component
|
|
import { Component, OnInit } from '@angular/core';
|
|
import { injectRestoreScrollPosition, ScrollTopButtonComponent } from '@isa/utils/scroll-position';
|
|
|
|
@Component({
|
|
selector: 'app-product-list',
|
|
imports: [ScrollTopButtonComponent],
|
|
template: `
|
|
<div class="product-grid">
|
|
@for (product of products(); track product.id) {
|
|
<app-product-card [product]="product" />
|
|
}
|
|
</div>
|
|
<utils-scroll-top-button />
|
|
`
|
|
})
|
|
export class ProductListComponent implements OnInit {
|
|
private restoreScrollPosition = injectRestoreScrollPosition();
|
|
|
|
async ngOnInit() {
|
|
await this.loadProducts();
|
|
// Restore scroll after content loads
|
|
await this.restoreScrollPosition(100);
|
|
}
|
|
}
|
|
```
|
|
|
|
### Manual Control for Custom Scenarios
|
|
|
|
```typescript
|
|
import { Component } from '@angular/core';
|
|
import { storeScrollPosition, injectRestoreScrollPosition } from '@isa/utils/scroll-position';
|
|
|
|
@Component({
|
|
selector: 'app-custom-navigation',
|
|
// ...
|
|
})
|
|
export class CustomNavigationComponent {
|
|
private restoreScrollPosition = injectRestoreScrollPosition();
|
|
|
|
async onCustomNavigateAway() {
|
|
// Store before custom navigation logic
|
|
await storeScrollPosition();
|
|
this.customNavigationService.navigate();
|
|
}
|
|
|
|
async onCustomNavigateBack() {
|
|
// Restore after returning
|
|
await this.restoreScrollPosition(200);
|
|
}
|
|
}
|
|
```
|
|
|
|
### Route Configuration
|
|
|
|
To enable automatic scroll restoration on specific routes, add the `scrollPositionRestoration` property in route data:
|
|
|
|
```typescript
|
|
export const routes: Routes = [
|
|
{
|
|
path: 'example',
|
|
component: ExampleComponent,
|
|
data: {
|
|
scrollPositionRestoration: true
|
|
}
|
|
}
|
|
];
|
|
```
|
|
|
|
## Dependencies
|
|
|
|
- `@angular/common` - ViewportScroller for scroll operations
|
|
- `@angular/core` - Core Angular functionality (inject, signals, etc.)
|
|
- `@angular/router` - Router integration for navigation events
|
|
- `@isa/core/storage` - Session storage provider for persistence
|
|
- `@isa/ui/buttons` - Icon button component for ScrollTopButtonComponent
|
|
- `@isa/icons` - Icon assets (isaSortByUpMedium)
|
|
- `@ng-icons/core` - Icon system integration
|
|
|
|
## Notes
|
|
|
|
- Scroll positions are stored in **session storage** and cleared after restoration
|
|
- The automatic restoration only applies to routes with `scrollPositionRestoration: true` in their data
|
|
- The scroll-to-top button respects accessibility preferences (`prefers-reduced-motion`)
|
|
- Manual restoration includes a configurable delay to ensure DOM readiness before scrolling
|
|
- The scroll-to-top button automatically shows/hides based on scroll position
|