@devzwo/ngx-magic-scroll 1.0.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +133 -0
- package/README.md +1 -1
- package/ai/usage.md +97 -0
- package/docs/concepts/anchors.md +129 -0
- package/docs/concepts/data-readiness-and-restoration.md +102 -0
- package/docs/concepts/position-preservation.md +149 -0
- package/docs/concepts/url-state-and-navigation.md +118 -0
- package/docs/getting-started.md +144 -0
- package/docs/migrations/v0.0.1-rc.1-to-0.0.1-rc.2.md +177 -0
- package/docs/migrations/v0.0.1-rc.2-to-1.0.0.md +176 -0
- package/docs/migrations/v1.0-to-v1.1.md +145 -0
- package/docs/recipes/material-drawer.md +99 -0
- package/docs/recipes/ngrx-signal-store.md +132 -0
- package/docs/recipes/paginated-lists.md +206 -0
- package/docs/recipes/return-to-list.md +110 -0
- package/docs/recipes/rx-resource.md +87 -0
- package/docs/recipes/scroll-to-anchor.md +148 -0
- package/docs/recipes/sticky-master-detail.md +138 -0
- package/docs/recipes/tanstack-query.md +96 -0
- package/fesm2022/devzwo-ngx-magic-scroll.mjs +309 -19
- package/fesm2022/devzwo-ngx-magic-scroll.mjs.map +1 -1
- package/package.json +1 -1
- package/types/devzwo-ngx-magic-scroll.d.ts +118 -8
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## Release v1.1.1 (2026-10-18)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- Bundle offline Markdown documentation (`ai/usage.md`, `getting-started.md`, concepts, recipes, migrations, changelog) directly in the npm distribution package.
|
|
8
|
+
- Provide machine-readable AI Agent Guide (`ai/usage.md`) and dynamic `llms.txt` ecosystem index for AI coding assistants.
|
|
9
|
+
- Add version-specific migration guides covering `v0.0.1-rc.1 -> v0.0.1-rc.2`, `v0.0.1-rc.2 -> v1.0.0`, and `v1.0.x -> v1.1.0` with verified Angular 22 before/after code transformations.
|
|
10
|
+
- Export raw Markdown documentation endpoints (`.md`) across all documentation routes.
|
|
11
|
+
- Add automated validation scripts for package archive structure, Markdown link resolution, version consistency, and Angular `ngc` recipe/migration snippet compilation.
|
|
12
|
+
|
|
13
|
+
### Bug Fixes & Behavioral Changes
|
|
14
|
+
|
|
15
|
+
- Fix duplicate H1 headings rendered on documentation pages in Starlight.
|
|
16
|
+
|
|
17
|
+
### Deprecations
|
|
18
|
+
|
|
19
|
+
- None.
|
|
20
|
+
|
|
21
|
+
### Breaking Changes
|
|
22
|
+
|
|
23
|
+
- None.
|
|
24
|
+
|
|
25
|
+
## Release v1.1.0 (2026-10-18)
|
|
26
|
+
|
|
27
|
+
### Features
|
|
28
|
+
|
|
29
|
+
- Add opt-in `preserveOnLayoutChange` configuration option to maintain section-relative scroll positions during asynchronous layout reflows (e.g., accordions, lazy images, form expansions).
|
|
30
|
+
- Preserve section-relative pixel displacement (`displacement`) across automatic layout corrections and data updates to keep the reader's exact reading position intact.
|
|
31
|
+
- Add accessible focus management (`focus: true`) to `scrollTo()` with temporary `tabindex="-1"` handling and completion coordination for smooth scrolling.
|
|
32
|
+
- Optimize layout reflow tracking using region-scoped `ResizeObserver` and `requestAnimationFrame` coalescing to prevent layout thrashing.
|
|
33
|
+
- Guard against scroll interruptions by deferring layout preservation during active smooth scrolling and skipping redundant sub-pixel (`< 1px`) scroll adjustments.
|
|
34
|
+
- Update demo application with layout preservation controls, accordion examples, accessible navigation toggles, and refreshed architecture documentation.
|
|
35
|
+
|
|
36
|
+
### Bug Fixes & Behavioral Changes
|
|
37
|
+
|
|
38
|
+
- None.
|
|
39
|
+
|
|
40
|
+
### Deprecations
|
|
41
|
+
|
|
42
|
+
- None.
|
|
43
|
+
|
|
44
|
+
### Breaking Changes
|
|
45
|
+
|
|
46
|
+
- None.
|
|
47
|
+
|
|
48
|
+
### Migration Guide
|
|
49
|
+
|
|
50
|
+
- See [Migration Guide: v1.0 to v1.1](./docs/migrations/v1.0-to-v1.1.md) for upgrade instructions and before/after code examples.
|
|
51
|
+
|
|
52
|
+
## Release v1.0.0
|
|
53
|
+
|
|
54
|
+
### Features
|
|
55
|
+
|
|
56
|
+
- Handle subsequent Angular router fragment navigations automatically after initial page load without requiring consumer coordination.
|
|
57
|
+
- Queue pending scroll targets and retry navigation via `MutationObserver` until asynchronous data and matching DOM elements are rendered.
|
|
58
|
+
- Tag scroll-spy navigation origins to distinguish internal fragment updates from external navigation and prevent navigation loops.
|
|
59
|
+
- Support browser history navigation (back/forward popstate) with scroll position restoration while preserving custom router history state.
|
|
60
|
+
- Support multiple anchor prefixes via `anchorPrefixes` array configuration.
|
|
61
|
+
- Add strict explicit anchor selection mode (`explicitOnly`) to restrict anchor resolution exclusively to `[scrollAnchor]` directives.
|
|
62
|
+
- Add parameter help tooltips and interactive anchor strategy toggles to the demo application.
|
|
63
|
+
- Integrate Mermaid architecture and lifecycle flow diagrams into the documentation.
|
|
64
|
+
- Add mascot branding in demo header and update favicons across docs and demo app.
|
|
65
|
+
- Expand test matrix and Playwright configuration with dedicated per-browser test suites.
|
|
66
|
+
|
|
67
|
+
### Bug Fixes & Behavioral Changes
|
|
68
|
+
|
|
69
|
+
- None.
|
|
70
|
+
|
|
71
|
+
### Deprecations
|
|
72
|
+
|
|
73
|
+
- None.
|
|
74
|
+
|
|
75
|
+
### Breaking Changes
|
|
76
|
+
|
|
77
|
+
- None.
|
|
78
|
+
|
|
79
|
+
### Migration Guide
|
|
80
|
+
|
|
81
|
+
- See [Migration Guide: v0.0.1-rc.2 to v1.0.0](./docs/migrations/v0.0.1-rc.2-to-1.0.0.md) for upgrade instructions and before/after code examples.
|
|
82
|
+
|
|
83
|
+
## Pre-Release v0.0.1-rc.2
|
|
84
|
+
|
|
85
|
+
### Features
|
|
86
|
+
|
|
87
|
+
- Track visible live sections in real time so position preservation during asynchronous data updates or resizing targets the current reading position.
|
|
88
|
+
- Keep the currently read section active in the scroll-spy until the next section begins, prioritizing fully contained sections within the reading area.
|
|
89
|
+
- Add `bottomOffset` and `activationThreshold` configuration options for granular control over active reading boundaries and trigger lines.
|
|
90
|
+
- Add active zone overlay in demo application to visualize active boundaries and exclusion zones.
|
|
91
|
+
|
|
92
|
+
### Bug Fixes & Behavioral Changes
|
|
93
|
+
|
|
94
|
+
- Cancel pending initial scroll restoration on user interaction (wheel, touch, navigation keys) prior to data readiness, while ignoring inputs in editable elements.
|
|
95
|
+
- Ensure programmatic `scrollTo()` continues to work as expected after user interruption.
|
|
96
|
+
- Improve server-side rendering (SSR) resilience when `ResizeObserver` or `defaultView` is not available.
|
|
97
|
+
|
|
98
|
+
### Deprecations
|
|
99
|
+
|
|
100
|
+
- None.
|
|
101
|
+
|
|
102
|
+
### Breaking Changes
|
|
103
|
+
|
|
104
|
+
- None.
|
|
105
|
+
|
|
106
|
+
### Migration Guide
|
|
107
|
+
|
|
108
|
+
- See [Migration Guide: v0.0.1-rc.1 to v0.0.1-rc.2](./docs/migrations/v0.0.1-rc.1-to-0.0.1-rc.2.md) for upgrade instructions and before/after code examples.
|
|
109
|
+
|
|
110
|
+
## Pre-Release v0.0.1-rc.1
|
|
111
|
+
|
|
112
|
+
The first public release preview. The public API is under review.
|
|
113
|
+
|
|
114
|
+
### Features
|
|
115
|
+
|
|
116
|
+
- Anchor scrolling through `magicScroll`, with automatic scroll-container detection, configurable offsets and header measurement.
|
|
117
|
+
- URL synchronization and initial scroll-position restoration.
|
|
118
|
+
- Scroll-position preservation when data or container dimensions change.
|
|
119
|
+
- Inheritable defaults through `provideMagicScroll`, with overrides per region or action and separate behavior for restoration and user interaction.
|
|
120
|
+
- Support for signals, plain input data, Angular resources and provider-neutral data sources.
|
|
121
|
+
- Optional anchor markers, explicit IDs through `scrollAnchor` and independent scoping for nested scroll regions.
|
|
122
|
+
|
|
123
|
+
### Bug Fixes & Behavioral Changes
|
|
124
|
+
|
|
125
|
+
- None.
|
|
126
|
+
|
|
127
|
+
### Deprecations
|
|
128
|
+
|
|
129
|
+
- None.
|
|
130
|
+
|
|
131
|
+
### Breaking Changes
|
|
132
|
+
|
|
133
|
+
- None.
|
package/README.md
CHANGED
|
@@ -121,7 +121,7 @@ Four routed examples demonstrate document synchronization, asynchronous navigati
|
|
|
121
121
|
|
|
122
122
|
`pnpm test:ci` enforces 100% statements, branches, functions and lines per library implementation file. The existing 25 E2E scenarios remain unchanged after the migration to the facade and pass in Chromium, Firefox and WebKit (75 runs).
|
|
123
123
|
|
|
124
|
-
[Documentation and API](https://devzwo.github.io/ngx-magic-scroll/) · [Source and issues](https://github.com/devZWO/ngx-magic-scroll)
|
|
124
|
+
[Documentation and API](https://devzwo.github.io/ngx-magic-scroll/) · [AI Agent Guide](ai/usage.md) · [llms.txt Index](https://devzwo.github.io/ngx-magic-scroll/llms.txt) · [Changelog](CHANGELOG.md) · [Source and issues](https://github.com/devZWO/ngx-magic-scroll)
|
|
125
125
|
|
|
126
126
|
MIT, copyright 2026 devZWO GmbH.
|
|
127
127
|
|
package/ai/usage.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: AI Agent Integration Guide
|
|
3
|
+
description: Concise reference and integration rules for AI coding assistants using @devzwo/ngx-magic-scroll.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
This guide provides compact, high-density reference instructions for AI agents and automated code generators integrating or upgrading `@devzwo/ngx-magic-scroll`.
|
|
7
|
+
|
|
8
|
+
## Package Metadata & Prerequisites
|
|
9
|
+
|
|
10
|
+
- **Package**: `@devzwo/ngx-magic-scroll`
|
|
11
|
+
- **Framework Support**: Angular `^22.2.0`, RxJS `^7.8.0`
|
|
12
|
+
- **Prerequisites**: Angular Router enabled (`provideRouter(...)` in `app.config.ts`) for fragment synchronization and history restoration.
|
|
13
|
+
- **Conventions**: Angular standalone components (do not set `standalone: true` in `@Component`), signal inputs/outputs, and native control flow (`@if`, `@for`).
|
|
14
|
+
|
|
15
|
+
## Minimal Integration Example
|
|
16
|
+
|
|
17
|
+
<!-- recipe-check: ai-usage-minimal.ts -->
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { Component } from '@angular/core';
|
|
21
|
+
import {
|
|
22
|
+
MagicScrollDirective,
|
|
23
|
+
ScrollAnchorDirective,
|
|
24
|
+
provideMagicScroll,
|
|
25
|
+
} from '@devzwo/ngx-magic-scroll';
|
|
26
|
+
|
|
27
|
+
@Component({
|
|
28
|
+
selector: 'app-agent-doc-sample',
|
|
29
|
+
imports: [MagicScrollDirective, ScrollAnchorDirective],
|
|
30
|
+
providers: [provideMagicScroll()],
|
|
31
|
+
template: `
|
|
32
|
+
<nav aria-label="Page Sections">
|
|
33
|
+
<button (click)="scroll.scrollTo('intro')">Intro</button>
|
|
34
|
+
<button (click)="scroll.scrollTo('details', { focus: true })">Details</button>
|
|
35
|
+
</nav>
|
|
36
|
+
|
|
37
|
+
<main magicScroll #scroll="magicScroll">
|
|
38
|
+
<section id="intro">
|
|
39
|
+
<h2>Introduction</h2>
|
|
40
|
+
</section>
|
|
41
|
+
<section id="details" scrollAnchor>
|
|
42
|
+
<h2>Details</h2>
|
|
43
|
+
</section>
|
|
44
|
+
</main>
|
|
45
|
+
`,
|
|
46
|
+
})
|
|
47
|
+
export class AgentDocSampleComponent {}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Recipe Decision Guide
|
|
51
|
+
|
|
52
|
+
Select the appropriate recipe and configuration based on application requirements:
|
|
53
|
+
|
|
54
|
+
| Requirement / Scenario | Recommended Recipe | Key Configuration / API |
|
|
55
|
+
| :-------------------------------- | :---------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------- |
|
|
56
|
+
| **Static Navigation & Spy** | [Anchor Navigation](../docs/recipes/scroll-to-anchor.md) | `[magicScroll]`, `#scroll="magicScroll"`, `scroll.activeAnchor()`, `scroll.scrollTo(id, { focus: true })` |
|
|
57
|
+
| **Async Data (Angular Resource)** | [rxResource Integration](../docs/recipes/rx-resource.md) | `[scrollSource]="resource"`, `[scrollAnchor]="item.id"` |
|
|
58
|
+
| **Async Data (Signal State)** | [NgRx Signal Store](../docs/recipes/ngrx-signal-store.md) / [TanStack Query](../docs/recipes/tanstack-query.md) | `[scrollSource]="store.items"` or `[scrollSource]="query.data"` |
|
|
59
|
+
| **Appended / Paginated Lists** | [Paginated Lists](../docs/recipes/paginated-lists.md) | `[scrollSource]="items()"`, automatic top-anchor retention during append |
|
|
60
|
+
| **Cross-Route Return** | [Return to List](../docs/recipes/return-to-list.md) | Browser history popstate auto-restoration |
|
|
61
|
+
| **Sticky Header / Layout Offset** | [Sticky Master-Detail](../docs/recipes/sticky-master-detail.md) | `[headerOffset]="measuredHeight()"` or `[topOffset]="64"` |
|
|
62
|
+
| **Drawer / Nested Container** | [Material Drawer](../docs/recipes/material-drawer.md) | `[magicScroll]` directly on the scrolling overflow container |
|
|
63
|
+
| **Dynamic Reflow / Accordion** | [Position Preservation](../docs/concepts/position-preservation.md) | `provideMagicScroll({ preserveOnLayoutChange: true })` |
|
|
64
|
+
|
|
65
|
+
## Core Integration Rules & Common Pitfalls
|
|
66
|
+
|
|
67
|
+
### 1. `scrollSource` Reactivity
|
|
68
|
+
|
|
69
|
+
- **Rule**: Pass live reactive signals or resource references to `[scrollSource]`, never evaluated static values in non-reactive contexts.
|
|
70
|
+
- **Pitfall**: Passing `[scrollSource]="resource.value()"` creates a static snapshot if not evaluated inside a reactive signal context; pass `[scrollSource]="resource"` directly when using `ResourceRef` or `rxResource`.
|
|
71
|
+
- **Readiness**: `undefined` indicates loading. Position restoration and fragment navigation wait until data resolves to a defined value (array, object, or `null`).
|
|
72
|
+
|
|
73
|
+
### 2. Anchor Scoping & ID Uniqueness
|
|
74
|
+
|
|
75
|
+
- **Containment**: Every anchor element belongs strictly to its closest parent `[magicScroll]` region. A parent scroll instance cannot scroll to anchors inside a nested scroll region.
|
|
76
|
+
- **Stability**: Anchor `id` attributes must be globally unique across the document and remain stable between renders.
|
|
77
|
+
- **Selective Anchors**: Use `[anchorPrefixes]="['section-']"` or `explicitOnly: true` with `[scrollAnchor]` to avoid treating arbitrary DOM IDs as scroll anchors.
|
|
78
|
+
|
|
79
|
+
### 3. Accessible Focus Transfer
|
|
80
|
+
|
|
81
|
+
- When triggering navigation from button clicks or shortcuts, pass `{ focus: true }` to `scrollTo(id, { focus: true })`.
|
|
82
|
+
- Non-focusable elements automatically receive temporary `tabindex="-1"`, cleaned up on blur or directive destruction.
|
|
83
|
+
- Smooth scrolling coordinates focus transfer on scroll completion (`scrollend`).
|
|
84
|
+
|
|
85
|
+
### 4. Layout Preservation During Reflows
|
|
86
|
+
|
|
87
|
+
- Enable `preserveOnLayoutChange: true` to prevent content jumps when accordions toggle, images load, or forms expand above the user's viewport.
|
|
88
|
+
- The library tracks section-relative displacement to preserve the exact reading position without layout thrashing.
|
|
89
|
+
|
|
90
|
+
## Upgrade & Migration Workflow
|
|
91
|
+
|
|
92
|
+
When updating `@devzwo/ngx-magic-scroll` in an existing project:
|
|
93
|
+
|
|
94
|
+
1. **Verify Installed Version**: Inspect `package.json` for `@devzwo/ngx-magic-scroll`.
|
|
95
|
+
2. **Review Changelog**: Check [Changelog](../CHANGELOG.md) for breaking changes, new features, and deprecation notices.
|
|
96
|
+
3. **Check Version Migration Guides**: Consult [Migration Guides](../docs/migrations/v1.0-to-v1.1.md) for step-by-step code transformations and before/after snippets.
|
|
97
|
+
4. **Run Project Validation**: Verify template compilation and unit tests with `ng build` / `pnpm test`.
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Scroll regions and anchor identity
|
|
3
|
+
description: Understand anchor selection, region ownership and the container that actually scrolls.
|
|
4
|
+
sidebar:
|
|
5
|
+
order: 1
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
An anchor identifies a section of content independently of its pixel position. A scroll region defines which anchors `magicScroll` manages; the scroll container determines which viewport moves. Keeping these three roles separate helps you design layouts that remain navigable as content changes.
|
|
9
|
+
|
|
10
|
+
## Stable IDs identify content
|
|
11
|
+
|
|
12
|
+
The URL fragment `#project-12` refers to the element with ID `project-12`. On restoration, the library finds that element's current position. Inserting content above it can change its coordinates without changing what the link means.
|
|
13
|
+
|
|
14
|
+
Use IDs derived from the identity of your content, such as a project ID. An array index is unsuitable when sorting, filtering or inserting items can make it refer to a different item. IDs must be unique across the entire document, including across separate regions.
|
|
15
|
+
|
|
16
|
+
Restoration returns to an anchor's position with the configured top offset. It does not remember the exact pixel distance the user had scrolled into that section.
|
|
17
|
+
|
|
18
|
+
## Configuring activation boundaries and scroll offsets
|
|
19
|
+
|
|
20
|
+
`magicScroll` computes both scroll alignment and active section detection using layout and offset configuration:
|
|
21
|
+
|
|
22
|
+
- **`headerOffset`**: Static spacing in pixels (e.g. `headerOffset: 24`), adding visual breathing room above section headings.
|
|
23
|
+
- **`headerSelector`**: CSS selector for a fixed or sticky navigation bar (e.g. `headerSelector: '.app-header'`). Its dynamically measured height is automatically added to the boundary offset so obscured elements do not trigger activation or get covered during scroll restoration.
|
|
24
|
+
- **`bottomOffset`**: Static bottom spacing in pixels (e.g. `bottomOffset: 40`), accounting for sticky footers, floating action bars, or aesthetic margins.
|
|
25
|
+
- **`activationThreshold`**: Relative focal trigger threshold from `0.0` (top boundary) to `1.0` (bottom boundary), defining the trigger line (`topBoundary + (bottomBoundary - topBoundary) * activationThreshold`) where sections transition to active status.
|
|
26
|
+
|
|
27
|
+
Active section detection evaluates elements within the visible reading area between the effective top boundary (`containerTop + headerHeight + headerOffset`) and bottom boundary (`(containerBottom | viewportHeight) - bottomOffset`), prioritizing fully visible sections before falling back to reading-position tracking for tall content relative to the configured `activationThreshold`.
|
|
28
|
+
|
|
29
|
+
```mermaid
|
|
30
|
+
flowchart TB
|
|
31
|
+
subgraph Viewport ["Scroll Viewport / Container"]
|
|
32
|
+
direction TB
|
|
33
|
+
TopZone["<b>Top Exclusion Area</b><br/><i>[0 .. topBoundary]</i><br/>Sticky Header (headerSelector) + headerOffset"]
|
|
34
|
+
ReadingZone["<b>Active Reading Band</b><br/><i>[topBoundary .. bottomBoundary]</i><br/>Full containment evaluation area"]
|
|
35
|
+
TriggerLine["<b>─── Dynamic Trigger Line ───</b><br/><i>topBoundary + (ReadingBand * activationThreshold)</i>"]
|
|
36
|
+
BottomZone["<b>Bottom Exclusion Area</b><br/><i>[bottomBoundary .. containerBottom]</i><br/>Sticky Footer / Padding (bottomOffset)"]
|
|
37
|
+
|
|
38
|
+
TopZone --- ReadingZone
|
|
39
|
+
ReadingZone --- TriggerLine
|
|
40
|
+
TriggerLine --- BottomZone
|
|
41
|
+
end
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
You can configure offsets globally in application providers or locally per scroll region:
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
// Global configuration
|
|
48
|
+
provideMagicScroll({
|
|
49
|
+
headerSelector: '.app-header',
|
|
50
|
+
headerOffset: 24,
|
|
51
|
+
bottomOffset: 48,
|
|
52
|
+
activationThreshold: 0.3,
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
```html
|
|
57
|
+
<!-- Per-region override -->
|
|
58
|
+
<div magicScroll [scrollOptions]="{ headerOffset: 16, bottomOffset: 32, activationThreshold: 0.5 }">
|
|
59
|
+
...
|
|
60
|
+
</div>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## A region selects its anchors
|
|
64
|
+
|
|
65
|
+
By default (`anchorSelection: 'all'`), all descendant elements with non-empty IDs participate. This includes IDs on headings or form controls, so a region can contain more anchors than your section navigation exposes.
|
|
66
|
+
|
|
67
|
+
Use `anchorPrefixes` to restrict automatic selection, and `scrollAnchor` to explicitly include an element even when its ID does not match the prefix:
|
|
68
|
+
|
|
69
|
+
```html
|
|
70
|
+
<div magicScroll [scrollOptions]="{ anchorPrefixes: ['project-', 'milestone-'] }">
|
|
71
|
+
<section id="overview" scrollAnchor>Overview...</section>
|
|
72
|
+
<section id="project-planning">
|
|
73
|
+
<h2 id="planning-heading">Planning</h2>
|
|
74
|
+
</section>
|
|
75
|
+
<section id="milestone-alpha">Alpha release...</section>
|
|
76
|
+
<section [scrollAnchor]="'project-delivery'">Delivery...</section>
|
|
77
|
+
</div>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The anchors here are `overview`, `project-planning`, `milestone-alpha` and `project-delivery`. The heading's ID (`planning-heading`) is excluded because it matches neither prefix. The bound marker `[scrollAnchor]` also assigns the element's ID; import `ScrollAnchorDirective` when using either marker form.
|
|
81
|
+
|
|
82
|
+
### Multiple prefixes and strict explicit selection
|
|
83
|
+
|
|
84
|
+
`magicScroll` provides versatile selection strategies:
|
|
85
|
+
|
|
86
|
+
- **`anchorPrefixes`**: Specify an array of prefixes (e.g. `['project-', 'milestone-']`). Any descendant element whose ID begins with any of these prefixes participates, along with explicit `scrollAnchor` elements. Passing an empty array `anchorPrefixes: []` disables all prefix matching, allowing only explicit `scrollAnchor` markers to participate.
|
|
87
|
+
- **`anchorSelection: 'explicit'`**: Enables strict explicit-only mode. In this mode, **only** elements explicitly marked with `scrollAnchor` or `[scrollAnchor]` participate in scroll-spy, initial restoration and `scrollTo()`. All other IDs—including auto-generated IDs from component libraries such as Angular Material (`mat-input-*`, `cdk-describedby-*`) or nested form controls—are strictly ignored, even if they match configured prefixes.
|
|
88
|
+
- **`anchorSelection: 'all'` (default)**: Descendant elements matching any configured `anchorPrefixes` (or all descendant IDs if no prefix is set) as well as explicit `scrollAnchor` markers participate.
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
// Example: Strict explicit selection across the application
|
|
92
|
+
provideMagicScroll({
|
|
93
|
+
anchorSelection: 'explicit',
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
```html
|
|
98
|
+
<!-- Per-region override supporting multiple prefixes -->
|
|
99
|
+
<div magicScroll [scrollOptions]="{ anchorPrefixes: ['doc-', 'appendix-'] }">...</div>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The same selection applies to scroll-spy tracking, initial restoration and `scrollTo()`. An element can exist in the DOM and still be unavailable to this region because it is excluded by the selection rules. Setting `anchorPrefixes: ['']` on a region clears an inherited prefix and includes all its descendant IDs again.
|
|
103
|
+
|
|
104
|
+
## Each anchor belongs to its closest region
|
|
105
|
+
|
|
106
|
+
With nested `magicScroll` regions, each anchor belongs to the closest region containing it. The outer region excludes anchors inside the inner region, even if their IDs match its prefix or have explicit markers.
|
|
107
|
+
|
|
108
|
+
For example, an outer article can manage its section headings while an inner list manages its items. Calling the outer region's `scrollTo()` with an inner item ID returns `false`. Call the directive instance that owns the target instead.
|
|
109
|
+
|
|
110
|
+
Region ownership separates target selection. It does not create independent URL state: a route has one fragment, and regions connected to that route share it. Plan which region should control shareable navigation when multiple regions are active.
|
|
111
|
+
|
|
112
|
+
## The region and scroll container can be different elements
|
|
113
|
+
|
|
114
|
+
`magicScroll` chooses the container from the layout:
|
|
115
|
+
|
|
116
|
+
1. The region host itself, if its computed vertical overflow is `auto` or `scroll`.
|
|
117
|
+
2. Otherwise, the closest ancestor with either overflow value.
|
|
118
|
+
3. Otherwise, the document.
|
|
119
|
+
|
|
120
|
+
CSS supplies the height constraints and overflow that make that container scroll. Adding `magicScroll` alone does not create a scrolling viewport.
|
|
121
|
+
|
|
122
|
+
A detail region can therefore scroll with the document while a companion sidebar scrolls independently. If the sidebar sits outside the region, its IDs do not become detail anchors. Conversely, placing the region inside a constrained drawer makes the drawer content the scroll container.
|
|
123
|
+
|
|
124
|
+
## Related documentation
|
|
125
|
+
|
|
126
|
+
- [URL state and navigation](./url-state-and-navigation.md) explains how selected anchors become URL state.
|
|
127
|
+
- [Anchor navigation](../recipes/scroll-to-anchor.md) implements prefix selection, markers and navigation highlighting.
|
|
128
|
+
- [Angular Material Drawer](../recipes/material-drawer.md) shows a constrained scroll container.
|
|
129
|
+
- [MagicScrollDirective](https://devzwo.github.io/ngx-magic-scroll/api/classes/magicscrolldirective/) and [ScrollAnchorDirective](https://devzwo.github.io/ngx-magic-scroll/api/classes/scrollanchordirective/) document the directive APIs.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Data readiness and restoration
|
|
3
|
+
description: Understand when initial restoration runs and what your application must render first.
|
|
4
|
+
sidebar:
|
|
5
|
+
order: 3
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Initial restoration needs both an anchor identifier and a rendered target. `scrollSource` coordinates restoration with your application's data state. It observes readiness; your application loads the data and renders the elements that the fragment identifies.
|
|
9
|
+
|
|
10
|
+
## The initial restoration sequence
|
|
11
|
+
|
|
12
|
+
A region follows this sequence:
|
|
13
|
+
|
|
14
|
+
1. Capture the route fragment when the directive is created.
|
|
15
|
+
2. Wait for its source to be ready, if a source is supplied.
|
|
16
|
+
3. After rendering, attempt to scroll to the captured anchor.
|
|
17
|
+
4. Finish initial restoration, whether or not the target was found.
|
|
18
|
+
|
|
19
|
+
Without `scrollSource`, the first rendered DOM is considered ready. This suits static content and data already available from a router resolver.
|
|
20
|
+
|
|
21
|
+
For asynchronous content, bind the signal or resource that governs the rendered anchors. Pass a signal itself to `scrollSource`, and read its value where you render the collection. This lets readiness track the same data that produces the targets.
|
|
22
|
+
|
|
23
|
+
## Readiness is a data contract
|
|
24
|
+
|
|
25
|
+
| Source state | Initial restoration |
|
|
26
|
+
| ------------------------------------------------------------ | ------------------------------ |
|
|
27
|
+
| No `scrollSource` supplied | Attempt after the first render |
|
|
28
|
+
| Plain value or signal yielding `null` or `undefined` | Wait |
|
|
29
|
+
| Plain value or signal yielding `[]`, `0`, `false` or `''` | Ready |
|
|
30
|
+
| Resource or neutral source reporting `isLoading()` as `true` | Wait |
|
|
31
|
+
| Non-loading resource with an available, non-null value | Ready |
|
|
32
|
+
| Non-loading neutral source with non-null `data()` | Ready |
|
|
33
|
+
|
|
34
|
+
Angular resources expose `isLoading()`, `hasValue()` and `value()`. A resource with no value, including an error state without a value, cannot trigger restoration. The application owns loading indicators, error presentation and retries.
|
|
35
|
+
|
|
36
|
+
Readiness does not inspect whether the requested anchor exists. An empty collection is ready even though it contains no item anchors. Likewise, data can be ready while a separate conditional view still hides the target. Expose a source that reflects all prerequisites for rendering the intended content.
|
|
37
|
+
|
|
38
|
+
For signal forms, use the field's value signal, such as `form().value`, rather than the field tree itself. Source-specific adapters and types are covered by the recipes and API below.
|
|
39
|
+
|
|
40
|
+
## The first ready render is decisive
|
|
41
|
+
|
|
42
|
+
Initial restoration is attempted once per directive instance. If the fragment is absent or its target is missing or ineligible at the first ready render, the attempt does not scroll or rewrite the URL. It is not automatically retried as initial restoration when that target appears later.
|
|
43
|
+
|
|
44
|
+
### Intervening user interaction cancels restoration
|
|
45
|
+
|
|
46
|
+
If the user interacts with the page or scroll container before data readiness arrives—such as scrolling via mouse wheel, touch gestures, or navigation keys (`ArrowUp`, `ArrowDown`, `PageUp`, `PageDown`, `Space`, `Home`, `End`)—the pending initial restoration is cancelled. This prevents delayed data loading from abruptly overriding the user's conscious navigation.
|
|
47
|
+
|
|
48
|
+
Typing inside editable form controls (`input`, `textarea`, `select`, or `contenteditable` elements) is safely ignored and does not cancel restoration. Subsequent explicit navigation using `scrollTo()` continues to function normally without restriction.
|
|
49
|
+
|
|
50
|
+
```mermaid
|
|
51
|
+
graph TD
|
|
52
|
+
subgraph User & Browser Events
|
|
53
|
+
UserScroll[User Wheel / Touch / Keyboard]
|
|
54
|
+
BrowserScroll[Scroll Event]
|
|
55
|
+
DataUpdate[Data Ready / Resize Event]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
subgraph MagicScrollDirective
|
|
59
|
+
IntentDetector{User Intent?}
|
|
60
|
+
LiveTracker[RAF Live Section Calculator]
|
|
61
|
+
DebounceTimer[Debounce Timer]
|
|
62
|
+
PreserveHandler[preserve Realignment]
|
|
63
|
+
InitialRestore[Initial Restoration]
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
subgraph State
|
|
67
|
+
LiveAnchor[liveAnchor Signal]
|
|
68
|
+
URLFragment[URL Route Fragment]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
UserScroll -->|Intervention| IntentDetector
|
|
72
|
+
IntentDetector -->|Cancel pending| InitialRestore
|
|
73
|
+
BrowserScroll --> LiveTracker
|
|
74
|
+
LiveTracker --> LiveAnchor
|
|
75
|
+
LiveTracker --> DebounceTimer
|
|
76
|
+
DebounceTimer --> URLFragment
|
|
77
|
+
DataUpdate --> PreserveHandler
|
|
78
|
+
LiveAnchor -->|Source of Truth| PreserveHandler
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Later ready source changes can still trigger position preservation using the current active section. That is a separate behavior, described in [Position preservation and layout changes](./position-preservation.md), and should not be used as a strategy for loading a missing initial target.
|
|
82
|
+
|
|
83
|
+
An explicit `scrollTo()` call also requires an existing target. It does not wait for `scrollSource` to become ready.
|
|
84
|
+
|
|
85
|
+
## Restore application state before declaring readiness
|
|
86
|
+
|
|
87
|
+
Consider `/projects?count=16#project-12`:
|
|
88
|
+
|
|
89
|
+
- The fragment identifies project 12.
|
|
90
|
+
- The query parameter tells the application to load the first 16 items.
|
|
91
|
+
- The source becomes ready after that required range is available.
|
|
92
|
+
- The rendered region can then restore project 12.
|
|
93
|
+
|
|
94
|
+
If only the first eight items are exposed as ready, the initial attempt cannot find project 12. The library does not fetch additional pages, restore filters or materialize virtualized items.
|
|
95
|
+
|
|
96
|
+
Restore the relevant filters, ordering and data range in your application before readiness. If an item was deleted or filtered out, choose an application fallback rather than expecting automatic target discovery.
|
|
97
|
+
|
|
98
|
+
## Related documentation
|
|
99
|
+
|
|
100
|
+
- [Paginated lists](../recipes/paginated-lists.md) restores the loaded range before the anchor.
|
|
101
|
+
- [Angular rxResource](../recipes/rx-resource.md), [NgRx Signal Store](../recipes/ngrx-signal-store.md) and [TanStack Query](../recipes/tanstack-query.md) connect different data owners.
|
|
102
|
+
- [ScrollSource](https://devzwo.github.io/ngx-magic-scroll/api/type-aliases/scrollsource/), [ScrollResource](https://devzwo.github.io/ngx-magic-scroll/api/interfaces/scrollresource/) and [ScrollDataSource](https://devzwo.github.io/ngx-magic-scroll/api/interfaces/scrolldatasource/) define supported source contracts.
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Position preservation and layout changes
|
|
3
|
+
description: Understand how later data updates, resizing and header changes preserve section-relative reading positions.
|
|
4
|
+
sidebar:
|
|
5
|
+
order: 4
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
After initial restoration, content and layout can shift dynamically due to asynchronous data insertions, container resizing, or sticky header height changes. `ngx-magic-scroll` implements an **anchor-relative pixel displacement policy** that preserves the active section's pixel displacement, preventing disruptive jumps back to section headings during automatic reflows.
|
|
9
|
+
|
|
10
|
+
## Different causes have different policies
|
|
11
|
+
|
|
12
|
+
| Cause | Target | Displacement policy | Default behavior |
|
|
13
|
+
| ---------------------------------------------- | ---------------------------- | -------------------------------------------------------- | --------------------------------------------------------------- |
|
|
14
|
+
| Initial ready render | Fragment from URL snapshot | Aligned to heading (`displacement = 0`) | Restore once, instantly (unless user cancelled via interaction) |
|
|
15
|
+
| Explicit `scrollTo()` | Requested anchor | Aligned to heading (`displacement = 0`) | Scroll smoothly |
|
|
16
|
+
| External router fragment change | Route destination anchor | Aligned to heading (`displacement = 0`) | Restore instantly |
|
|
17
|
+
| Later ready source change | Current live visible section | Preserves saved pixel displacement (`savedDisplacement`) | Correct instantly without resetting to section top |
|
|
18
|
+
| Window resize or measured header-height change | Current live visible section | Preserves saved pixel displacement (`savedDisplacement`) | Realign instantly to maintain section pixel offset |
|
|
19
|
+
| Region content reflow (layout expansion/image) | Current live visible section | Preserves saved pixel displacement (`savedDisplacement`) | Opt-in (`preserveOnLayoutChange: true`); coalesced via rAF |
|
|
20
|
+
|
|
21
|
+
The distinction between initial URL fragments, live visible sections, and intentional user navigation ensures seamless reading continuity. When reading halfway through a 1200px card, layout reflows preserve the section's relative pixel position rather than resetting to the card header.
|
|
22
|
+
|
|
23
|
+
### Live section tracking vs URL debouncing
|
|
24
|
+
|
|
25
|
+
While scrolling, the active visible section geometry and anchor-relative pixel displacement are captured in real time, whereas updates to the browser's URL router are debounced by `debounceTime` (default 500ms) to avoid cluttering browser history during continuous motion. When automatic realignment or data updates occur during this debounce interval, `ngx-magic-scroll` preserves the real-time visible section and displacement rather than falling back to a stale URL anchor.
|
|
26
|
+
|
|
27
|
+
```mermaid
|
|
28
|
+
sequenceDiagram
|
|
29
|
+
autonumber
|
|
30
|
+
actor User
|
|
31
|
+
participant Viewport as Scroll Container
|
|
32
|
+
participant Directive as MagicScrollDirective
|
|
33
|
+
participant Provider as NearestAnchorProvider
|
|
34
|
+
participant Service as ScrollService
|
|
35
|
+
|
|
36
|
+
Note over User,Directive: User scrolls into long section
|
|
37
|
+
User->>Viewport: Scroll to midpoint of long card
|
|
38
|
+
Viewport->>Directive: onScroll event
|
|
39
|
+
Directive->>Provider: calculateNearestAnchor()
|
|
40
|
+
Provider-->>Directive: liveAnchor ('card-1')
|
|
41
|
+
Directive->>Directive: Capture savedDisplacement = anchorRect.top - topBoundary
|
|
42
|
+
|
|
43
|
+
Note over Viewport,Directive: Automatic layout reflow occurs
|
|
44
|
+
alt Data prepended / Container resize / Header resize
|
|
45
|
+
Viewport->>Directive: Data update / ResizeObserver trigger
|
|
46
|
+
Directive->>Directive: preserve() called
|
|
47
|
+
Directive->>Directive: Compute delta = (currentAnchorRect.top - topBoundary) - savedDisplacement
|
|
48
|
+
Directive->>Service: Adjust scrollable.scrollTop by delta (clamped to bounds)
|
|
49
|
+
Service->>Viewport: scrollable.scrollTo(targetScrollTop, instant)
|
|
50
|
+
Note over User,Viewport: Section displacement preserved!
|
|
51
|
+
end
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Section-relative displacement mechanics
|
|
55
|
+
|
|
56
|
+
### 1. Displacement capture during user scrolling
|
|
57
|
+
|
|
58
|
+
As the user scrolls through the container, `onScroll` computes the reading boundary and measures the active section's top offset:
|
|
59
|
+
|
|
60
|
+
```text
|
|
61
|
+
topBoundary = containerTop + measuredHeaderHeight + headerOffset
|
|
62
|
+
savedDisplacement = activeAnchorElement.getBoundingClientRect().top - topBoundary
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
For example, when reading 400px deep into a card, `savedDisplacement` is `-400px`.
|
|
66
|
+
|
|
67
|
+
### 2. Delta calculation and native scroll anchoring compatibility
|
|
68
|
+
|
|
69
|
+
When automatic reflow occurs (e.g. items prepended above the section, or sticky header expanded):
|
|
70
|
+
|
|
71
|
+
```text
|
|
72
|
+
currentDisplacement = currentAnchorElement.getBoundingClientRect().top - topBoundary
|
|
73
|
+
delta = currentDisplacement - savedDisplacement
|
|
74
|
+
targetScrollTop = clamp(currentScrollTop + delta, 0, maxScrollTop)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
- **Without browser scroll anchoring:** If content is inserted above the section, `currentDisplacement` changes by the height of the prepended items. `delta` equals the shift and `scrollTop` is adjusted instantly, keeping the section visually locked under the reader's view.
|
|
78
|
+
- **With native browser scroll anchoring (`overflow-anchor: auto`):** If the browser has already compensated `scrollTop` for inserted content, `currentDisplacement` remains equal to `savedDisplacement`. `delta` computes to `0`, inherently preventing double-compensation without browser-sniffing heuristics.
|
|
79
|
+
- **Intra-section limitation:** Anchor-relative displacement preserves the active section anchor's pixel offset relative to the reading boundary (`savedDisplacement`). It does not track intra-section elements or percentage progress through a section. Consequently, when text wraps or content changes _inside_ the active section itself, the exact paragraph or sentence being read may still move; retaining a specific paragraph across internal changes requires finer-grained child anchors.
|
|
80
|
+
|
|
81
|
+
### 3. Reset policy for deliberate navigation
|
|
82
|
+
|
|
83
|
+
Explicit programmatic calls (`scrollTo('card-2')`) and external router fragment navigations reset `savedDisplacement` to `0`. Intentional navigation always aligns the destination section's heading cleanly to the configured top offset.
|
|
84
|
+
|
|
85
|
+
### 4. Deterministic element removal handling
|
|
86
|
+
|
|
87
|
+
If the active section element is removed from the DOM during a data change or layout update, `preserve()` gracefully skips realignment and maintains the current viewport position without arbitrary jumps.
|
|
88
|
+
|
|
89
|
+
## Region content reflow with preserveOnLayoutChange
|
|
90
|
+
|
|
91
|
+
In dynamic web applications, presentation-level elements within a scroll region frequently change dimensions without any updates to the fetched data source (`scrollSource`). Common examples include:
|
|
92
|
+
|
|
93
|
+
- Expanding an accordion or detail disclosure panel above the reader's active section.
|
|
94
|
+
- Asynchronous image loads settling to their natural height without pre-set aspect ratios.
|
|
95
|
+
- Conditional validation messages or interactive preview cards appearing dynamically.
|
|
96
|
+
|
|
97
|
+
When `preserveOnLayoutChange: true` is enabled, `MagicScrollDirective` attaches a region-scoped `ResizeObserver` to the host element. Layout shifts are coalesced per animation frame (`requestAnimationFrame`) to eliminate layout thrashing and feedback loops.
|
|
98
|
+
|
|
99
|
+
```mermaid
|
|
100
|
+
graph TD
|
|
101
|
+
A[Region Content Reflow / Image Loaded / Accordion Expanded] -->|ResizeObserver Callback| B{preserveOnLayoutChange Enabled?}
|
|
102
|
+
B -->|No| C[Ignore Reflow]
|
|
103
|
+
B -->|Yes| D{Initialized & Not Interrupted?}
|
|
104
|
+
D -->|No / User Scrolling| E[Suppress Realignment]
|
|
105
|
+
D -->|Yes| F{rAF Already Queued?}
|
|
106
|
+
F -->|Yes| G[Coalesce into Existing Frame]
|
|
107
|
+
F -->|No| H[Queue requestAnimationFrame]
|
|
108
|
+
H --> I[Execute preserve()]
|
|
109
|
+
I --> J[Calculate Delta against liveAnchor & savedDisplacement]
|
|
110
|
+
J --> K{Delta === 0 or Anchored by Browser?}
|
|
111
|
+
K -->|Yes| L[No-op: Native overflow-anchor already compensated]
|
|
112
|
+
K -->|No| M[Scrollable.scrollTo: Adjust scrollTop instantly]
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Supported scenarios vs unsupported modifications
|
|
116
|
+
|
|
117
|
+
- **Supported (Dimension Changes)**: Any internal DOM expansion or contraction that changes box dimensions (such as toggling accordions, inserting child cards, or loading images) alters the region's layout and triggers instant, seamless realignment.
|
|
118
|
+
- **Unsupported (Position-Only Shifts)**: Pure CSS coordinate changes (such as `transform: translateY(...)` or CSS `top` transitions) that do not alter the box geometry or layout dimensions of elements in the DOM cannot be observed by `ResizeObserver`.
|
|
119
|
+
- **User Gesture Priority**: If the reader is actively scrolling via touch gestures, wheel events, or navigation keys, automated layout realignments yield immediately to user navigation.
|
|
120
|
+
|
|
121
|
+
## Header measurement defines the top offset
|
|
122
|
+
|
|
123
|
+
The effective top offset boundary is:
|
|
124
|
+
|
|
125
|
+
```text
|
|
126
|
+
measured header height + headerOffset
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
With no configured or matching header, the measured height is zero and `headerOffset` supplies the entire offset. With a header, it adds a gap below that header. Use a `headerSelector` that uniquely identifies the intended element; its height is measured and observed automatically via `ResizeObserver`.
|
|
130
|
+
|
|
131
|
+
`offset()` exposes the sum, and `headerHeight()` exposes the measurement alone. A sticky companion panel can use the same sum for its CSS `top` so navigation and scroll alignment share one boundary.
|
|
132
|
+
|
|
133
|
+
A per-call `topOffset` replaces the entire effective offset for that action. It is not an additional gap. Viewport boundary clamping ensures scroll targets are bounded within `[0, scrollHeight - clientHeight]`.
|
|
134
|
+
|
|
135
|
+
## Choose a policy for your layout
|
|
136
|
+
|
|
137
|
+
Use `restoreOnDataChange: false` when data updates should let the viewport move naturally without anchor preservation. Use `preserveOnResize: false` when automatic realignment during resizing or header changes is unwanted. Disabling layout corrections still leaves the measured header height and effective offset available.
|
|
138
|
+
|
|
139
|
+
Initial restoration and explicit interactions have separate behavior defaults: `behavior.restoration` is `instant`, and `behavior.interaction` is `smooth`. Automatic data and layout corrections remain instant.
|
|
140
|
+
|
|
141
|
+
Provider defaults are inherited through Angular's injector hierarchy. Region `scrollOptions` override those defaults, and supported per-call options override the region for one `scrollTo()` action.
|
|
142
|
+
|
|
143
|
+
## Related documentation
|
|
144
|
+
|
|
145
|
+
- [Data readiness and restoration](./data-readiness-and-restoration.md) explains initial restoration, user cancellation, and the event lifecycle diagram.
|
|
146
|
+
- [Sticky master–detail](../recipes/sticky-master-detail.md) shares the measured offset with a sticky sidebar.
|
|
147
|
+
- [Paginated lists](../recipes/paginated-lists.md) shows data updates and optional correction disabling.
|
|
148
|
+
- [MagicScrollOptions](https://devzwo.github.io/ngx-magic-scroll/api/interfaces/magicscrolloptions/) documents configuration defaults and visibility rules.
|
|
149
|
+
- [MagicScrollToOptions](https://devzwo.github.io/ngx-magic-scroll/api/type-aliases/magicscrolltooptions/) documents per-action overrides.
|