rune-scroller 2.1.1 → 2.2.2
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/README.md +61 -256
- package/dist/dom-utils.d.ts +1 -0
- package/dist/dom-utils.js +19 -4
- package/dist/index.js +3 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
# ⚡ Rune Scroller
|
|
2
|
-
|
|
3
|
-
**📚 Complete API Reference** — Detailed documentation for all features and options.
|
|
4
|
-
|
|
5
|
-
---
|
|
1
|
+
# ⚡ Rune Scroller
|
|
6
2
|
|
|
7
3
|
<div align="center">
|
|
8
4
|
<img src="./logo.png" alt="Rune Scroller Logo" width="200" />
|
|
@@ -26,16 +22,13 @@
|
|
|
26
22
|
|
|
27
23
|
## ✨ Features
|
|
28
24
|
|
|
29
|
-
- **
|
|
25
|
+
- **5.7KB gzipped** (JS+CSS) - Minimal overhead
|
|
30
26
|
- **Zero dependencies** - Pure Svelte 5 + IntersectionObserver
|
|
31
|
-
- **14 animations** - Fade, Zoom, Flip, Slide, Bounce
|
|
32
|
-
- **
|
|
27
|
+
- **14 animations** - Fade, Zoom, Flip, Slide, Bounce
|
|
28
|
+
- **TypeScript support** - Full type definitions
|
|
33
29
|
- **SSR-ready** - SvelteKit compatible
|
|
34
30
|
- **GPU-accelerated** - Pure CSS transforms
|
|
35
31
|
- **Accessible** - Respects `prefers-reduced-motion`
|
|
36
|
-
- **v2.0.0 New** - `onVisible` callback, ResizeObserver support, animation validation, sentinel customization
|
|
37
|
-
- **✨ Latest** - `useIntersection` migrated to Svelte 5 `$effect` rune for better lifecycle management
|
|
38
|
-
- **🚀 Bundle optimized** - CSS with custom properties, production build minification
|
|
39
32
|
|
|
40
33
|
---
|
|
41
34
|
|
|
@@ -43,47 +36,15 @@
|
|
|
43
36
|
|
|
44
37
|
```bash
|
|
45
38
|
npm install rune-scroller
|
|
46
|
-
# or
|
|
47
|
-
pnpm add rune-scroller
|
|
48
|
-
# or
|
|
49
|
-
yarn add rune-scroller
|
|
50
39
|
```
|
|
51
40
|
|
|
52
41
|
---
|
|
53
42
|
|
|
54
43
|
## 🚀 Quick Start
|
|
55
44
|
|
|
56
|
-
### Step 1: Import CSS (required)
|
|
57
|
-
|
|
58
|
-
**⚠️ Important:** You must import the CSS file once in your app.
|
|
59
|
-
|
|
60
|
-
**Option A - In your root layout (recommended for SvelteKit):**
|
|
61
|
-
|
|
62
|
-
```svelte
|
|
63
|
-
<!-- src/routes/+layout.svelte -->
|
|
64
|
-
<script>
|
|
65
|
-
import 'rune-scroller/animations.css';
|
|
66
|
-
let { children } = $props();
|
|
67
|
-
</script>
|
|
68
|
-
|
|
69
|
-
{@render children()}
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
**Option B - In each component that uses animations:**
|
|
73
|
-
|
|
74
|
-
```svelte
|
|
75
|
-
<script>
|
|
76
|
-
import runeScroller from 'rune-scroller';
|
|
77
|
-
import 'rune-scroller/animations.css';
|
|
78
|
-
</script>
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
### Step 2: Use the animations
|
|
82
|
-
|
|
83
45
|
```svelte
|
|
84
46
|
<script>
|
|
85
47
|
import runeScroller from 'rune-scroller';
|
|
86
|
-
// CSS already imported in layout or above
|
|
87
48
|
</script>
|
|
88
49
|
|
|
89
50
|
<!-- Simple animation -->
|
|
@@ -107,6 +68,7 @@ yarn add rune-scroller
|
|
|
107
68
|
## 🎨 Available Animations
|
|
108
69
|
|
|
109
70
|
### Fade (5)
|
|
71
|
+
|
|
110
72
|
- `fade-in` - Simple opacity fade
|
|
111
73
|
- `fade-in-up` - Fade + move up 300px
|
|
112
74
|
- `fade-in-down` - Fade + move down 300px
|
|
@@ -114,6 +76,7 @@ yarn add rune-scroller
|
|
|
114
76
|
- `fade-in-right` - Fade + move from left 300px
|
|
115
77
|
|
|
116
78
|
### Zoom (5)
|
|
79
|
+
|
|
117
80
|
- `zoom-in` - Scale from 0.3 to 1
|
|
118
81
|
- `zoom-out` - Scale from 2 to 1
|
|
119
82
|
- `zoom-in-up` - Zoom (0.5→1) + move up 300px
|
|
@@ -121,6 +84,7 @@ yarn add rune-scroller
|
|
|
121
84
|
- `zoom-in-right` - Zoom (0.5→1) + move from left 300px
|
|
122
85
|
|
|
123
86
|
### Others (4)
|
|
87
|
+
|
|
124
88
|
- `flip` - 3D flip on Y-axis
|
|
125
89
|
- `flip-x` - 3D flip on X-axis
|
|
126
90
|
- `slide-rotate` - Slide + rotate 10°
|
|
@@ -132,114 +96,45 @@ yarn add rune-scroller
|
|
|
132
96
|
|
|
133
97
|
```typescript
|
|
134
98
|
interface RuneScrollerOptions {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
99
|
+
animation?: AnimationType // Animation name (default: 'fade-in')
|
|
100
|
+
duration?: number // Duration in ms (default: 800)
|
|
101
|
+
repeat?: boolean // Repeat on scroll (default: false)
|
|
102
|
+
debug?: boolean // Show sentinel as visible line (default: false)
|
|
103
|
+
offset?: number // Sentinel offset in px (default: 0, negative = earlier)
|
|
104
|
+
onVisible?: (element: HTMLElement) => void // Callback when visible
|
|
105
|
+
sentinelColor?: string // Debug sentinel color (e.g. '#ff6b6b')
|
|
106
|
+
sentinelId?: string // Custom sentinel ID
|
|
143
107
|
}
|
|
144
108
|
```
|
|
145
109
|
|
|
146
|
-
### Option Details
|
|
147
|
-
|
|
148
|
-
- **`animation`** - Type of animation to play. Choose from 14 built-in animations listed above. Invalid animations automatically fallback to 'fade-in' with a console warning.
|
|
149
|
-
- **`duration`** - How long the animation lasts in milliseconds (default: 800ms).
|
|
150
|
-
- **`repeat`** - If `true`, animation plays every time sentinel enters viewport. If `false`, plays only once.
|
|
151
|
-
- **`debug`** - If `true`, displays the sentinel element as a visible line below your element. Useful for seeing exactly when animations trigger. Default color is cyan (#00e0ff), customize with `sentinelColor`.
|
|
152
|
-
- **`offset`** - Offset of the sentinel in pixels. Positive values move sentinel down (delays animation), negative values move it up (triggers earlier). Useful for large elements where you want animation to trigger before the entire element is visible.
|
|
153
|
-
- **`onVisible`** *(v2.0.0+)* - Callback function triggered when the animation becomes visible. Receives the animated element as parameter. Useful for analytics, lazy loading, or triggering custom effects.
|
|
154
|
-
- **`sentinelColor`** *(v2.0.0+)* - Customize the debug sentinel color (e.g., '#ff6b6b' for red). Only visible when `debug: true`. Useful for distinguishing multiple sentinels on the same page.
|
|
155
|
-
- **`sentinelId`** *(v2.0.0+)* - Set a custom ID for the sentinel element. If not provided, an auto-ID is generated (`sentinel-1`, `sentinel-2`, etc.). Useful for identifying sentinels in DevTools and tracking which element owns which sentinel.
|
|
156
|
-
|
|
157
110
|
### Examples
|
|
158
111
|
|
|
159
112
|
```svelte
|
|
160
113
|
<!-- Basic -->
|
|
161
|
-
<div use:runeScroller={{ animation: 'zoom-in' }}>
|
|
162
|
-
Content
|
|
163
|
-
</div>
|
|
114
|
+
<div use:runeScroller={{ animation: 'zoom-in' }}>Content</div>
|
|
164
115
|
|
|
165
116
|
<!-- Custom duration -->
|
|
166
|
-
<div use:runeScroller={{ animation: 'fade-in-up', duration: 1000 }}>
|
|
167
|
-
Fast animation
|
|
168
|
-
</div>
|
|
117
|
+
<div use:runeScroller={{ animation: 'fade-in-up', duration: 1000 }}>Fast</div>
|
|
169
118
|
|
|
170
119
|
<!-- Repeat mode -->
|
|
171
|
-
<div use:runeScroller={{ animation: 'bounce-in', repeat: true }}>
|
|
172
|
-
Repeats every time you scroll
|
|
173
|
-
</div>
|
|
174
|
-
|
|
175
|
-
<!-- Debug mode - shows cyan line marking sentinel position -->
|
|
176
|
-
<div use:runeScroller={{ animation: 'fade-in', debug: true }}>
|
|
177
|
-
The cyan line below this shows when animation will trigger
|
|
178
|
-
</div>
|
|
179
|
-
|
|
180
|
-
<!-- Multiple options -->
|
|
181
|
-
<div use:runeScroller={{
|
|
182
|
-
animation: 'fade-in-up',
|
|
183
|
-
duration: 1200,
|
|
184
|
-
repeat: true,
|
|
185
|
-
debug: true
|
|
186
|
-
}}>
|
|
187
|
-
Full featured example
|
|
188
|
-
</div>
|
|
120
|
+
<div use:runeScroller={{ animation: 'bounce-in', repeat: true }}>Repeats</div>
|
|
189
121
|
|
|
190
|
-
<!--
|
|
191
|
-
<div use:runeScroller={{
|
|
192
|
-
animation: 'fade-in-up',
|
|
193
|
-
offset: -200 // Trigger 200px before element bottom
|
|
194
|
-
}}>
|
|
195
|
-
Large content that needs early triggering
|
|
196
|
-
</div>
|
|
122
|
+
<!-- Debug mode -->
|
|
123
|
+
<div use:runeScroller={{ animation: 'fade-in', debug: true }}>Debug</div>
|
|
197
124
|
|
|
198
|
-
<!--
|
|
199
|
-
<div use:runeScroller={{
|
|
200
|
-
|
|
201
|
-
offset: 300 // Trigger 300px after element bottom
|
|
202
|
-
}}>
|
|
203
|
-
Content with delayed animation
|
|
125
|
+
<!-- Trigger earlier with negative offset -->
|
|
126
|
+
<div use:runeScroller={{ animation: 'fade-in-up', offset: -200 }}>
|
|
127
|
+
Triggers 200px before element bottom
|
|
204
128
|
</div>
|
|
205
129
|
|
|
206
|
-
<!--
|
|
130
|
+
<!-- onVisible callback for analytics -->
|
|
207
131
|
<div use:runeScroller={{
|
|
208
132
|
animation: 'fade-in-up',
|
|
209
133
|
onVisible: (el) => {
|
|
210
|
-
|
|
211
|
-
// Track analytics, load images, trigger API calls, etc.
|
|
212
|
-
window.gtag?.('event', 'animation_visible', { element: el.id });
|
|
134
|
+
window.gtag?.('event', 'section_viewed', { id: el.id });
|
|
213
135
|
}
|
|
214
136
|
}}>
|
|
215
|
-
Tracked
|
|
216
|
-
</div>
|
|
217
|
-
|
|
218
|
-
<!-- v2.0.0: Custom sentinel color for debugging -->
|
|
219
|
-
<div use:runeScroller={{
|
|
220
|
-
animation: 'fade-in',
|
|
221
|
-
debug: true,
|
|
222
|
-
sentinelColor: '#ff6b6b' // Red instead of default cyan
|
|
223
|
-
}}>
|
|
224
|
-
Red debug sentinel
|
|
225
|
-
</div>
|
|
226
|
-
|
|
227
|
-
<!-- v2.0.0: Custom sentinel ID for identification -->
|
|
228
|
-
<div use:runeScroller={{
|
|
229
|
-
animation: 'zoom-in',
|
|
230
|
-
sentinelId: 'hero-zoom',
|
|
231
|
-
debug: true
|
|
232
|
-
}}>
|
|
233
|
-
Identified sentinel (shows "hero-zoom" in debug mode)
|
|
234
|
-
</div>
|
|
235
|
-
|
|
236
|
-
<!-- v2.0.0: Auto-ID (sentinel-1, sentinel-2, etc) -->
|
|
237
|
-
<div use:runeScroller={{
|
|
238
|
-
animation: 'fade-in-up',
|
|
239
|
-
debug: true
|
|
240
|
-
// sentinelId omitted → auto generates "sentinel-1", "sentinel-2", etc
|
|
241
|
-
}}>
|
|
242
|
-
Auto-identified sentinel
|
|
137
|
+
Tracked section
|
|
243
138
|
</div>
|
|
244
139
|
```
|
|
245
140
|
|
|
@@ -247,58 +142,36 @@ interface RuneScrollerOptions {
|
|
|
247
142
|
|
|
248
143
|
## 🎯 How It Works
|
|
249
144
|
|
|
250
|
-
|
|
145
|
+
**Sentinel-based triggering:**
|
|
251
146
|
|
|
252
|
-
1.
|
|
253
|
-
2. When
|
|
254
|
-
3.
|
|
255
|
-
4.
|
|
256
|
-
5.
|
|
257
|
-
6. *(v2.0.0)* Sentinel automatically repositions on element resize via ResizeObserver
|
|
147
|
+
1. Invisible 1px sentinel created below your element
|
|
148
|
+
2. When sentinel enters viewport, animation triggers
|
|
149
|
+
3. Uses native IntersectionObserver for performance
|
|
150
|
+
4. Pure CSS animations (GPU-accelerated)
|
|
151
|
+
5. ResizeObserver auto-repositions sentinel
|
|
258
152
|
|
|
259
153
|
**Why sentinels?**
|
|
154
|
+
|
|
260
155
|
- Accurate timing across all screen sizes
|
|
261
156
|
- No complex offset calculations
|
|
262
|
-
-
|
|
263
|
-
- Sentinel stays fixed while element animates (no observer confusion with transforms)
|
|
264
|
-
|
|
265
|
-
**Automatic ResizeObserver** *(v2.0.0+)*
|
|
266
|
-
- Sentinel repositions automatically when element resizes
|
|
267
|
-
- Works with responsive layouts and dynamic content
|
|
268
|
-
- No configuration needed—it just works
|
|
157
|
+
- Works with animated elements (transforms don't affect observer)
|
|
269
158
|
|
|
270
159
|
---
|
|
271
160
|
|
|
272
161
|
## 🌐 SSR Compatibility
|
|
273
162
|
|
|
274
|
-
Works seamlessly with SvelteKit
|
|
163
|
+
Works seamlessly with SvelteKit:
|
|
275
164
|
|
|
276
165
|
```svelte
|
|
277
166
|
<!-- src/routes/+layout.svelte -->
|
|
278
167
|
<script>
|
|
279
|
-
import 'rune-scroller
|
|
168
|
+
import runeScroller from 'rune-scroller';
|
|
280
169
|
let { children } = $props();
|
|
281
170
|
</script>
|
|
282
171
|
|
|
283
172
|
{@render children()}
|
|
284
173
|
```
|
|
285
174
|
|
|
286
|
-
Then use animations anywhere in your app:
|
|
287
|
-
|
|
288
|
-
```svelte
|
|
289
|
-
<!-- src/routes/+page.svelte -->
|
|
290
|
-
<script>
|
|
291
|
-
import runeScroller from 'rune-scroller';
|
|
292
|
-
</script>
|
|
293
|
-
|
|
294
|
-
<!-- No special handling needed -->
|
|
295
|
-
<div use:runeScroller={{ animation: 'fade-in-up' }}>
|
|
296
|
-
Works in SvelteKit SSR!
|
|
297
|
-
</div>
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
The library checks for browser environment and gracefully handles server-side rendering.
|
|
301
|
-
|
|
302
175
|
---
|
|
303
176
|
|
|
304
177
|
## ♿ Accessibility
|
|
@@ -306,73 +179,32 @@ The library checks for browser environment and gracefully handles server-side re
|
|
|
306
179
|
Respects `prefers-reduced-motion`:
|
|
307
180
|
|
|
308
181
|
```css
|
|
309
|
-
/* In animations.css */
|
|
310
182
|
@media (prefers-reduced-motion: reduce) {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
183
|
+
.scroll-animate {
|
|
184
|
+
animation: none !important;
|
|
185
|
+
opacity: 1 !important;
|
|
186
|
+
transform: none !important;
|
|
187
|
+
}
|
|
316
188
|
}
|
|
317
189
|
```
|
|
318
190
|
|
|
319
|
-
Users who prefer reduced motion will see content without animations.
|
|
320
|
-
|
|
321
191
|
---
|
|
322
192
|
|
|
323
193
|
## 📚 API Reference
|
|
324
|
-
### Public API
|
|
325
|
-
|
|
326
|
-
Rune Scroller exports a **single action-based API** (no components):
|
|
327
|
-
|
|
328
|
-
1. **`runeScroller`** (default) - Sentinel-based, simple, powerful
|
|
329
|
-
|
|
330
|
-
**Why actions instead of components?**
|
|
331
|
-
- Actions are lightweight directives
|
|
332
|
-
- No DOM wrapper overhead
|
|
333
|
-
- Better performance
|
|
334
|
-
- More flexible
|
|
335
|
-
|
|
336
|
-
### Main Export
|
|
337
194
|
|
|
338
195
|
```typescript
|
|
339
196
|
// Default export
|
|
340
|
-
import runeScroller from
|
|
197
|
+
import runeScroller from "rune-scroller"
|
|
341
198
|
|
|
342
199
|
// Named exports
|
|
343
200
|
import {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
} from
|
|
201
|
+
useIntersection, // Composable
|
|
202
|
+
useIntersectionOnce, // Composable
|
|
203
|
+
calculateRootMargin, // Utility
|
|
204
|
+
} from "rune-scroller"
|
|
348
205
|
|
|
349
206
|
// Types
|
|
350
|
-
import type {
|
|
351
|
-
AnimationType,
|
|
352
|
-
RuneScrollerOptions,
|
|
353
|
-
IntersectionOptions,
|
|
354
|
-
UseIntersectionReturn
|
|
355
|
-
} from 'rune-scroller';
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
### TypeScript Types
|
|
359
|
-
|
|
360
|
-
```typescript
|
|
361
|
-
type AnimationType =
|
|
362
|
-
| 'fade-in' | 'fade-in-up' | 'fade-in-down' | 'fade-in-left' | 'fade-in-right'
|
|
363
|
-
| 'zoom-in' | 'zoom-out' | 'zoom-in-up' | 'zoom-in-left' | 'zoom-in-right'
|
|
364
|
-
| 'flip' | 'flip-x' | 'slide-rotate' | 'bounce-in';
|
|
365
|
-
|
|
366
|
-
interface RuneScrollerOptions {
|
|
367
|
-
animation?: AnimationType;
|
|
368
|
-
duration?: number;
|
|
369
|
-
repeat?: boolean;
|
|
370
|
-
debug?: boolean;
|
|
371
|
-
offset?: number;
|
|
372
|
-
onVisible?: (element: HTMLElement) => void; // v2.0.0+
|
|
373
|
-
sentinelColor?: string; // v2.0.0+
|
|
374
|
-
sentinelId?: string; // v2.0.0+
|
|
375
|
-
}
|
|
207
|
+
import type { AnimationType, RuneScrollerOptions } from "rune-scroller"
|
|
376
208
|
```
|
|
377
209
|
|
|
378
210
|
---
|
|
@@ -384,46 +216,33 @@ interface RuneScrollerOptions {
|
|
|
384
216
|
```svelte
|
|
385
217
|
<script>
|
|
386
218
|
import runeScroller from 'rune-scroller';
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
const items = [
|
|
390
|
-
{ title: 'Feature 1', description: 'Description 1' },
|
|
391
|
-
{ title: 'Feature 2', description: 'Description 2' },
|
|
392
|
-
{ title: 'Feature 3', description: 'Description 3' }
|
|
393
|
-
];
|
|
219
|
+
const items = ['Item 1', 'Item 2', 'Item 3'];
|
|
394
220
|
</script>
|
|
395
221
|
|
|
396
|
-
|
|
397
|
-
{
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
</div>
|
|
222
|
+
{#each items as item, i}
|
|
223
|
+
<div use:runeScroller={{
|
|
224
|
+
animation: 'fade-in-up',
|
|
225
|
+
duration: 800,
|
|
226
|
+
style: `--delay: ${i * 100}ms`
|
|
227
|
+
}}>
|
|
228
|
+
{item}
|
|
229
|
+
</div>
|
|
230
|
+
{/each}
|
|
404
231
|
```
|
|
405
232
|
|
|
406
233
|
### Hero Section
|
|
407
234
|
|
|
408
235
|
```svelte
|
|
409
|
-
<
|
|
410
|
-
|
|
411
|
-
</
|
|
412
|
-
|
|
413
|
-
<div use:runeScroller={{ animation: 'fade-in-up', duration: 1200 }}>
|
|
414
|
-
<p>Engaging content</p>
|
|
415
|
-
</div>
|
|
416
|
-
|
|
417
|
-
<div use:runeScroller={{ animation: 'zoom-in', duration: 1000 }}>
|
|
418
|
-
<button>Get Started</button>
|
|
419
|
-
</div>
|
|
236
|
+
<h1 use:runeScroller={{ animation: 'fade-in-down', duration: 1000 }}>Welcome</h1>
|
|
237
|
+
<p use:runeScroller={{ animation: 'fade-in-up', duration: 1200 }}>Subtitle</p>
|
|
238
|
+
<button use:runeScroller={{ animation: 'zoom-in', duration: 800 }}>Get Started</button>
|
|
420
239
|
```
|
|
421
240
|
|
|
422
241
|
---
|
|
423
242
|
|
|
424
243
|
## 🔗 Links
|
|
425
244
|
|
|
426
|
-
- **npm
|
|
245
|
+
- **npm**: [rune-scroller](https://www.npmjs.com/package/rune-scroller)
|
|
427
246
|
- **GitHub**: [lelabdev/rune-scroller](https://github.com/lelabdev/rune-scroller)
|
|
428
247
|
- **Changelog**: [CHANGELOG.md](https://github.com/lelabdev/rune-scroller/blob/main/lib/CHANGELOG.md)
|
|
429
248
|
|
|
@@ -435,18 +254,4 @@ MIT © [ludoloops](https://github.com/ludoloops)
|
|
|
435
254
|
|
|
436
255
|
---
|
|
437
256
|
|
|
438
|
-
## 🤝 Contributing
|
|
439
|
-
|
|
440
|
-
Contributions welcome! Please open an issue or PR on GitHub.
|
|
441
|
-
|
|
442
|
-
```bash
|
|
443
|
-
# Development
|
|
444
|
-
bun install
|
|
445
|
-
bun run dev
|
|
446
|
-
bun test
|
|
447
|
-
bun run build
|
|
448
|
-
```
|
|
449
|
-
|
|
450
|
-
---
|
|
451
|
-
|
|
452
257
|
Made with ❤️ by [LeLab.dev](https://lelab.dev)
|
package/dist/dom-utils.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ export function createSentinel(element: HTMLElement, debug?: boolean, offset?: n
|
|
|
24
24
|
};
|
|
25
25
|
/**
|
|
26
26
|
* Check if CSS animations are loaded and warn if not (dev only)
|
|
27
|
+
* Uses cache to avoid expensive getComputedStyle() on every element creation
|
|
27
28
|
* @returns {boolean} True if CSS appears to be loaded
|
|
28
29
|
*/
|
|
29
30
|
export function checkAndWarnIfCSSNotLoaded(): boolean;
|
package/dist/dom-utils.js
CHANGED
|
@@ -4,6 +4,13 @@
|
|
|
4
4
|
*/
|
|
5
5
|
let sentinelCounter = 0;
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Cache to check CSS only once per page load
|
|
9
|
+
* Avoids expensive getComputedStyle() calls
|
|
10
|
+
* @type {boolean | null}
|
|
11
|
+
*/
|
|
12
|
+
let cssCheckResult = null;
|
|
13
|
+
|
|
7
14
|
/**
|
|
8
15
|
* @param {HTMLElement} element
|
|
9
16
|
* @param {number} [duration]
|
|
@@ -38,7 +45,7 @@ export function createSentinel(element, debug = false, offset = 0, sentinelColor
|
|
|
38
45
|
const sentinel = document.createElement('div');
|
|
39
46
|
// Use offsetHeight instead of getBoundingClientRect for accurate dimensions
|
|
40
47
|
// getBoundingClientRect returns transformed dimensions (affected by scale, etc)
|
|
41
|
-
// offsetHeight returns
|
|
48
|
+
// offsetHeight returns actual element height independent of CSS transforms
|
|
42
49
|
const elementHeight = element.offsetHeight;
|
|
43
50
|
const sentinelTop = elementHeight + offset;
|
|
44
51
|
|
|
@@ -48,7 +55,7 @@ export function createSentinel(element, debug = false, offset = 0, sentinelColor
|
|
|
48
55
|
sentinelId = `sentinel-${sentinelCounter}`;
|
|
49
56
|
}
|
|
50
57
|
|
|
51
|
-
// Always set
|
|
58
|
+
// Always set to data-sentinel-id attribute
|
|
52
59
|
sentinel.setAttribute('data-sentinel-id', sentinelId);
|
|
53
60
|
|
|
54
61
|
if (debug) {
|
|
@@ -71,11 +78,15 @@ export function createSentinel(element, debug = false, offset = 0, sentinelColor
|
|
|
71
78
|
|
|
72
79
|
/**
|
|
73
80
|
* Check if CSS animations are loaded and warn if not (dev only)
|
|
81
|
+
* Uses cache to avoid expensive getComputedStyle() on every element creation
|
|
74
82
|
* @returns {boolean} True if CSS appears to be loaded
|
|
75
83
|
*/
|
|
76
84
|
export function checkAndWarnIfCSSNotLoaded() {
|
|
77
|
-
if (typeof document === 'undefined') return;
|
|
78
|
-
if (process.env.NODE_ENV === 'production') return;
|
|
85
|
+
if (typeof document === 'undefined') return false;
|
|
86
|
+
if (process.env.NODE_ENV === 'production') return true;
|
|
87
|
+
|
|
88
|
+
// Return cached result if already checked (avoids expensive reflows)
|
|
89
|
+
if (cssCheckResult !== null) return cssCheckResult;
|
|
79
90
|
|
|
80
91
|
// Try to detect if animations.css is loaded by checking for animation classes
|
|
81
92
|
const test = document.createElement('div');
|
|
@@ -94,4 +105,8 @@ export function checkAndWarnIfCSSNotLoaded() {
|
|
|
94
105
|
'Documentation: https://github.com/lelabdev/rune-scroller#installation'
|
|
95
106
|
);
|
|
96
107
|
}
|
|
108
|
+
|
|
109
|
+
// Cache the result for future calls
|
|
110
|
+
cssCheckResult = hasAnimation;
|
|
111
|
+
return hasAnimation;
|
|
97
112
|
}
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rune-scroller",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "Lightweight, high-performance scroll animations for Svelte 5.
|
|
3
|
+
"version": "2.2.2",
|
|
4
|
+
"description": "Lightweight, high-performance scroll animations for Svelte 5. 14KB gzipped, zero dependencies.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"license": "MIT",
|