app-studio 0.7.1 → 0.7.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.
@@ -1,19 +1,51 @@
1
1
  import React from 'react';
2
2
  import { ComponentStory } from '@storybook/react';
3
3
  import { View } from '../src/index';
4
- declare const FillTextDemo: React.FC;
5
- declare const _default: import("@storybook/types").ComponentAnnotations<import("@storybook/react/dist/types-0fc72a6d").R, {
6
- children?: React.ReactNode;
7
- }>;
4
+ declare const _default: import("@storybook/types").ComponentAnnotations<import("@storybook/react/dist/types-0fc72a6d").R, import("../src").ElementProps & React.RefAttributes<HTMLElement> & import("../src").ViewProps>;
8
5
  export default _default;
9
- export declare const FillTextScrollStory: ComponentStory<typeof FillTextDemo>;
6
+ /**
7
+ * Demonstrates the useScrollAnimation hook with various configurations.
8
+ * This hook uses IntersectionObserver to track element visibility and progress.
9
+ */
10
+ export declare const UseScrollAnimationHook: ComponentStory<typeof View>;
11
+ /**
12
+ * Demonstrates the useScroll hook for tracking scroll position and progress.
13
+ */
14
+ export declare const UseScrollHook: ComponentStory<typeof View>;
15
+ /**
16
+ * Demonstrates the useScrollDirection hook.
17
+ */
18
+ export declare const UseScrollDirectionHook: ComponentStory<typeof View>;
19
+ /**
20
+ * Demonstrates the useSmoothScroll hook for programmatic smooth scrolling.
21
+ */
22
+ export declare const UseSmoothScrollHook: ComponentStory<typeof View>;
10
23
  /**
11
24
  * CSS View Timeline Animations - Pure CSS, no JavaScript state!
12
- * These animations now work by default with animate prop (animateOn="Both" is default).
13
25
  */
14
- export declare const ViewTimelineAnimations: ComponentStory<typeof View>;
26
+ export declare const CSSViewTimelineAnimations: ComponentStory<typeof View>;
15
27
  /**
16
28
  * Entry + Exit animations combined
17
29
  */
18
30
  export declare const EntryExitAnimations: ComponentStory<typeof View>;
19
- export declare const AnimatedComponent: React.FC;
31
+ /**
32
+ * Scroll-driven text fill animation
33
+ */
34
+ export declare const ScrollDrivenTextFill: ComponentStory<typeof View>;
35
+ /**
36
+ * FillText Examples - Using App-Studio's Theming System
37
+ *
38
+ * This story demonstrates FillText scroll animations integrated with App-Studio's
39
+ * color system. Colors use CSS variables for theme-awareness:
40
+ *
41
+ * - Palette colors: var(--color-blue-500), var(--color-emerald-500)
42
+ * - Alpha transparency: color-mix(in srgb, var(--color-blue-500) 20%, transparent)
43
+ * - Background colors: color.slate.900, color.emerald.950, etc.
44
+ *
45
+ * See docs/Theming.md for the complete color reference.
46
+ */
47
+ export declare const FillTextExamples: ComponentStory<typeof View>;
48
+ /**
49
+ * All scroll-driven animation presets
50
+ */
51
+ export declare const ScrollDrivenAnimationPresets: ComponentStory<typeof View>;
package/docs/Animation.md CHANGED
@@ -189,6 +189,294 @@ These animations are linked to the scroll position associated with a timeline (u
189
189
  <View animate={Animation.fadeInScroll()} />
190
190
  ```
191
191
 
192
+ ### Custom Scroll Timeline with `animate.timeline`
193
+
194
+ For fine-grained control over scroll-driven animations, use the `animate` prop with `timeline` and `keyframes`:
195
+
196
+ ```jsx
197
+ import { View, Vertical, Text } from 'app-studio';
198
+
199
+ function ScrollProgressBar() {
200
+ return (
201
+ <Vertical gap={20} padding={20} height="100vh">
202
+ <Text fontSize={24} fontWeight="bold">
203
+ Scroll Timeline Animation
204
+ </Text>
205
+ <Text>Scroll down to see the progress bar animate.</Text>
206
+
207
+ {/* Scroll container */}
208
+ <View
209
+ height={300}
210
+ overflow="auto"
211
+ border="1px solid #ccc"
212
+ padding={20}
213
+ position="relative"
214
+ >
215
+ {/* Progress Bar - sticks to top of container */}
216
+ <View
217
+ position="sticky"
218
+ top={0}
219
+ width="100%"
220
+ height={8}
221
+ backgroundColor="#ddd"
222
+ zIndex={10}
223
+ >
224
+ {/* Animated progress fill */}
225
+ <View
226
+ height="100%"
227
+ backgroundColor="color.blue.500"
228
+ width="0%"
229
+ animate={{
230
+ timeline: 'scroll()',
231
+ keyframes: {
232
+ from: { width: '0%' },
233
+ to: { width: '100%' },
234
+ },
235
+ }}
236
+ />
237
+ </View>
238
+
239
+ {/* Scrollable content */}
240
+ <Vertical gap={50} paddingVertical={50}>
241
+ {[1, 2, 3, 4, 5].map((i) => (
242
+ <View key={i} padding={20} backgroundColor="#f5f5f5" borderRadius={8}>
243
+ Item {i}
244
+ </View>
245
+ ))}
246
+ </Vertical>
247
+ </View>
248
+ </Vertical>
249
+ );
250
+ }
251
+ ```
252
+
253
+ **Timeline Options:**
254
+
255
+ | Timeline | Description |
256
+ |----------|-------------|
257
+ | `scroll()` | Links animation to the nearest scrollable ancestor's scroll progress |
258
+ | `scroll(root)` | Links to the root (viewport) scroll progress |
259
+ | `view()` | Links to element's visibility in the viewport (entry/exit) |
260
+
261
+ **Keyframe Properties:**
262
+
263
+ You can animate any CSS property between `from` and `to` states, or use percentage keyframes for more control:
264
+
265
+ ```jsx
266
+ animate={{
267
+ timeline: 'scroll()',
268
+ keyframes: {
269
+ '0%': { opacity: 0, transform: 'translateY(20px)' },
270
+ '50%': { opacity: 1, transform: 'translateY(0)' },
271
+ '100%': { opacity: 0.5, transform: 'translateY(-10px)' },
272
+ },
273
+ }}
274
+ ```
275
+
276
+ See the [ScrollTimeline Story](../stories/ScrollTimeline.stories.tsx) for a complete example.
277
+
278
+ ### FillText Scroll Animation with Theming
279
+
280
+ The `fillTextScroll()` animation creates a text reveal effect that fills as the user scrolls. It integrates with App-Studio's theming system using CSS variables.
281
+
282
+ #### Basic Usage
283
+
284
+ ```jsx
285
+ import { View, Animation } from 'app-studio';
286
+
287
+ <View
288
+ as="span"
289
+ fontSize={48}
290
+ fontWeight="bold"
291
+ color="color.gray.500"
292
+ backgroundClip="text"
293
+ animate={Animation.fillTextScroll({
294
+ duration: '1s',
295
+ timingFunction: 'linear',
296
+ timeline: '--section',
297
+ range: 'entry 100% cover 55%',
298
+ })}
299
+ >
300
+ Text that fills as you scroll
301
+ </View>
302
+ ```
303
+
304
+ #### Theme-Aware FillText with CSS Variables
305
+
306
+ For full theme integration, use CSS variables from the theming system. This ensures colors adapt to light/dark mode:
307
+
308
+ ```jsx
309
+ import { View, Text } from 'app-studio';
310
+ import { Animation } from 'app-studio';
311
+
312
+ function ThemedFillText({ children, color = 'blue' }) {
313
+ // Map palette names to CSS variables
314
+ const colors = {
315
+ blue: {
316
+ fill: 'var(--color-blue-500)',
317
+ accent: 'var(--color-blue-400)',
318
+ base: 'color-mix(in srgb, var(--color-blue-500) 15%, transparent)',
319
+ underline: 'color-mix(in srgb, var(--color-blue-500) 20%, transparent)',
320
+ },
321
+ emerald: {
322
+ fill: 'var(--color-emerald-500)',
323
+ accent: 'var(--color-emerald-400)',
324
+ base: 'color-mix(in srgb, var(--color-emerald-500) 12%, transparent)',
325
+ underline: 'color-mix(in srgb, var(--color-emerald-500) 20%, transparent)',
326
+ },
327
+ violet: {
328
+ fill: 'var(--color-violet-500)',
329
+ accent: 'var(--color-violet-400)',
330
+ base: 'color-mix(in srgb, var(--color-violet-500) 10%, transparent)',
331
+ underline: 'color-mix(in srgb, var(--color-violet-500) 20%, transparent)',
332
+ },
333
+ };
334
+
335
+ const { fill, accent, base, underline } = colors[color] || colors.blue;
336
+
337
+ return (
338
+ <View
339
+ as="span"
340
+ fontSize={48}
341
+ fontWeight="bold"
342
+ css={`
343
+ color: ${base};
344
+ --fill-color: ${fill};
345
+ --accent: ${accent};
346
+ --underline-color: ${underline};
347
+ --underline-block-width: 200vmax;
348
+ --underline-width: 100%;
349
+ `}
350
+ backgroundImage={`
351
+ linear-gradient(90deg, transparent calc(100% - 1ch), var(--accent) calc(100% - 1ch)),
352
+ linear-gradient(90deg, var(--fill-color), var(--fill-color)),
353
+ linear-gradient(90deg, var(--underline-color), var(--underline-color))`}
354
+ backgroundSize={`
355
+ var(--underline-block-width) var(--underline-width),
356
+ var(--underline-block-width) var(--underline-width),
357
+ 100% var(--underline-width)`}
358
+ backgroundRepeat="no-repeat"
359
+ backgroundPositionX="0"
360
+ backgroundPositionY="100%"
361
+ backgroundClip="text"
362
+ animate={Animation.fillTextScroll({
363
+ duration: '1s',
364
+ timingFunction: 'linear',
365
+ })}
366
+ >
367
+ {children}
368
+ </View>
369
+ );
370
+ }
371
+
372
+ // Usage with different color palettes
373
+ <ThemedFillText color="blue">Blue themed text</ThemedFillText>
374
+ <ThemedFillText color="emerald">Emerald themed text</ThemedFillText>
375
+ <ThemedFillText color="violet">Violet themed text</ThemedFillText>
376
+ ```
377
+
378
+ #### Using Color Palettes
379
+
380
+ All App-Studio color palettes work with FillText. Reference them via CSS variables:
381
+
382
+ | Palette | Fill Variable | Accent Variable |
383
+ |---------|--------------|-----------------|
384
+ | Blue | `var(--color-blue-500)` | `var(--color-blue-400)` |
385
+ | Emerald | `var(--color-emerald-500)` | `var(--color-emerald-400)` |
386
+ | Violet | `var(--color-violet-500)` | `var(--color-violet-400)` |
387
+ | Amber | `var(--color-amber-500)` | `var(--color-amber-400)` |
388
+ | Rose | `var(--color-rose-500)` | `var(--color-rose-400)` |
389
+ | Cyan | `var(--color-cyan-500)` | `var(--color-cyan-400)` |
390
+ | Gray (light bg) | `var(--color-gray-800)` | `var(--color-gray-900)` |
391
+
392
+ #### Alpha Transparency with `color-mix()`
393
+
394
+ For semi-transparent colors that remain theme-aware, use `color-mix()`:
395
+
396
+ ```jsx
397
+ // 15% opacity blue
398
+ baseColor="color-mix(in srgb, var(--color-blue-500) 15%, transparent)"
399
+
400
+ // 20% opacity emerald
401
+ underlineColor="color-mix(in srgb, var(--color-emerald-500) 20%, transparent)"
402
+
403
+ // 70% opacity white
404
+ fillColor="color-mix(in srgb, var(--color-white) 70%, transparent)"
405
+ ```
406
+
407
+ #### Complete Section Example
408
+
409
+ Here's a complete FillText section with view-timeline:
410
+
411
+ ```jsx
412
+ function FillTextSection() {
413
+ return (
414
+ <View
415
+ css={`
416
+ @supports (animation-timeline: scroll()) {
417
+ @media (prefers-reduced-motion: no-preference) {
418
+ view-timeline-name: --hero-section;
419
+ }
420
+ }
421
+ `}
422
+ backgroundColor="color.slate.900"
423
+ >
424
+ <View height="50vh" />
425
+ <View as="main" height="200vh">
426
+ <View
427
+ as="section"
428
+ position="sticky"
429
+ top="0"
430
+ height="100vh"
431
+ display="grid"
432
+ placeItems="center"
433
+ >
434
+ <View padding="5ch" textAlign="center" maxWidth={1200}>
435
+ <View
436
+ as="span"
437
+ fontSize={56}
438
+ fontWeight="bold"
439
+ css={`
440
+ color: color-mix(in srgb, var(--color-blue-500) 15%, transparent);
441
+ --fill-color: var(--color-blue-500);
442
+ --accent: var(--color-blue-400);
443
+ --underline-color: color-mix(in srgb, var(--color-blue-500) 20%, transparent);
444
+ --underline-block-width: 200vmax;
445
+ --underline-width: 100%;
446
+ `}
447
+ backgroundImage={`
448
+ linear-gradient(90deg, transparent calc(100% - 1ch), var(--accent) calc(100% - 1ch)),
449
+ linear-gradient(90deg, var(--fill-color), var(--fill-color)),
450
+ linear-gradient(90deg, var(--underline-color), var(--underline-color))`}
451
+ backgroundSize={`
452
+ var(--underline-block-width) var(--underline-width),
453
+ var(--underline-block-width) var(--underline-width),
454
+ 100% var(--underline-width)`}
455
+ backgroundRepeat="no-repeat"
456
+ backgroundPositionX="0"
457
+ backgroundPositionY="100%"
458
+ backgroundClip="text"
459
+ animate={Animation.fillTextScroll({
460
+ duration: '1s',
461
+ timingFunction: 'linear',
462
+ timeline: '--hero-section',
463
+ range: 'entry 100% cover 55%, cover 50% exit 0%',
464
+ })}
465
+ >
466
+ Build beautiful scroll-driven animations with pure CSS.
467
+ </View>
468
+ </View>
469
+ </View>
470
+ </View>
471
+ </View>
472
+ );
473
+ }
474
+ ```
475
+
476
+ See [docs/Theming.md](./Theming.md) for the complete color palette reference.
477
+
478
+ See the [FillText Examples Story](../stories/ScrollAnimation.stories.tsx) for interactive demos with all color themes.
479
+
192
480
  ## 7. Event-Based Animations
193
481
 
194
482
  You can trigger animations on interactions like hover, click, or focus using the `on` prop or underscore props (`_hover`, `_active`).
package/docs/Hooks.md CHANGED
@@ -2,11 +2,19 @@
2
2
 
3
3
  App-Studio provides a comprehensive set of React hooks to help you build interactive and responsive applications. This guide covers all the available hooks and their usage.
4
4
 
5
+ ## Iframe Support
6
+
7
+ Many hooks in App-Studio support working inside iframes for micro-frontend architectures, preview environments, and embedded widgets.
8
+
9
+ **Supported hooks:** `useScroll`, `useScrollAnimation`, `useScrollDirection`, `useSmoothScroll`, `useClickOutside`, plus `ResponsiveProvider` and `WindowSizeProvider`.
10
+
11
+ See the dedicated [Iframe Support Guide](./IframeSupport.md) for complete documentation and examples.
12
+
5
13
  ## Scroll Hooks
6
14
 
7
15
  ### useScroll
8
16
 
9
- A hook that tracks scroll position and progress for a container or window.
17
+ A hook that tracks scroll position and progress for a container or window. Supports tracking scroll inside iframes.
10
18
 
11
19
  ```tsx
12
20
  import { useScroll } from 'app-studio';
@@ -27,17 +35,57 @@ function MyComponent() {
27
35
  }
28
36
  ```
29
37
 
38
+ #### Tracking Scroll Inside an Iframe
39
+
40
+ When you pass an `HTMLIFrameElement` reference to the `container` option, `useScroll` automatically detects the iframe context and tracks scroll within the iframe's window:
41
+
42
+ ```tsx
43
+ import { useScroll } from 'app-studio';
44
+
45
+ function IframeScrollTracker() {
46
+ const iframeRef = useRef<HTMLIFrameElement>(null);
47
+
48
+ // Pass the iframe ref - useScroll will track the iframe's scroll position
49
+ const scrollPosition = useScroll({
50
+ container: iframeRef,
51
+ throttleMs: 50
52
+ });
53
+
54
+ return (
55
+ <div>
56
+ <p>Iframe Scroll Y: {Math.round(scrollPosition.y)}px</p>
57
+ <p>Iframe Scroll Progress: {Math.round(scrollPosition.yProgress * 100)}%</p>
58
+ <iframe
59
+ ref={iframeRef}
60
+ src="/your-iframe-content"
61
+ style={{ width: '100%', height: '400px' }}
62
+ />
63
+ </div>
64
+ );
65
+ }
66
+ ```
67
+
30
68
  **Options:**
31
69
 
32
- - `container`: Reference to the scrollable container (optional, defaults to window)
33
- - `target`: Reference to the target element (optional)
34
- - `offset`: X and Y offset values (optional, defaults to [0, 0])
35
- - `throttleMs`: Throttle interval in milliseconds (optional, defaults to 100)
36
- - `disabled`: Whether to disable the hook (optional, defaults to false)
70
+ | Option | Type | Default | Description |
71
+ |--------|------|---------|-------------|
72
+ | `container` | `RefObject<HTMLElement>` | window | Reference to the scrollable container. If an `HTMLIFrameElement` is passed, tracks the iframe's content scroll. |
73
+ | `offset` | `[number, number]` | `[0, 0]` | X and Y offset values to add to scroll position |
74
+ | `throttleMs` | `number` | `100` | Throttle interval in milliseconds for performance |
75
+ | `disabled` | `boolean` | `false` | Whether to disable scroll tracking |
76
+
77
+ **Returns:** `ScrollPosition`
78
+
79
+ | Property | Type | Description |
80
+ |----------|------|-------------|
81
+ | `x` | `number` | Horizontal scroll position in pixels |
82
+ | `y` | `number` | Vertical scroll position in pixels |
83
+ | `xProgress` | `number` | Horizontal scroll progress (0 to 1) |
84
+ | `yProgress` | `number` | Vertical scroll progress (0 to 1) |
37
85
 
38
86
  ### useScrollDirection
39
87
 
40
- A hook that detects scroll direction.
88
+ A hook that detects scroll direction. Supports tracking direction inside iframes via the `targetWindow` parameter.
41
89
 
42
90
  ```tsx
43
91
  import { useScrollDirection } from 'app-studio';
@@ -53,13 +101,35 @@ function ScrollDirectionComponent() {
53
101
  }
54
102
  ```
55
103
 
104
+ #### With Iframe Support
105
+
106
+ ```tsx
107
+ import { useScrollDirection } from 'app-studio';
108
+
109
+ function IframeScrollDirection({ iframeWindow }: { iframeWindow: Window }) {
110
+ // Track scroll direction inside an iframe
111
+ const scrollDirection = useScrollDirection(5, iframeWindow);
112
+
113
+ return (
114
+ <div>
115
+ Iframe scroll direction: {scrollDirection}
116
+ </div>
117
+ );
118
+ }
119
+ ```
120
+
56
121
  **Parameters:**
57
122
 
58
- - `threshold`: Minimum scroll distance in pixels before direction change is detected (optional, defaults to 0)
123
+ | Parameter | Type | Default | Description |
124
+ |-----------|------|---------|-------------|
125
+ | `threshold` | `number` | `5` | Minimum scroll distance in pixels before direction change is detected |
126
+ | `targetWindow` | `Window` | `window` | Target window to track (use `iframe.contentWindow` for iframe support) |
127
+
128
+ **Returns:** `'up' | 'down'`
59
129
 
60
130
  ### useSmoothScroll
61
131
 
62
- A hook that provides smooth scrolling functionality to elements.
132
+ A hook that provides smooth scrolling functionality to elements. Supports scrolling inside iframes via the `targetWindow` parameter.
63
133
 
64
134
  ```tsx
65
135
  import { useSmoothScroll } from 'app-studio';
@@ -79,9 +149,42 @@ function SmoothScrollComponent() {
79
149
  }
80
150
  ```
81
151
 
152
+ #### With Iframe Support
153
+
154
+ ```tsx
155
+ import { useSmoothScroll } from 'app-studio';
156
+
157
+ function IframeSmoothScroll({ iframeWindow }: { iframeWindow: Window }) {
158
+ // Smooth scroll inside an iframe
159
+ const scrollTo = useSmoothScroll(iframeWindow);
160
+ const targetRef = useRef<HTMLDivElement>(null);
161
+
162
+ return (
163
+ <>
164
+ <button onClick={() => scrollTo(targetRef.current, 80)}>
165
+ Scroll to Section in Iframe
166
+ </button>
167
+ <div ref={targetRef}>Target Section</div>
168
+ </>
169
+ );
170
+ }
171
+ ```
172
+
173
+ **Parameters:**
174
+
175
+ | Parameter | Type | Default | Description |
176
+ |-----------|------|---------|-------------|
177
+ | `targetWindow` | `Window` | `window` | Target window to scroll (use `iframe.contentWindow` for iframe support) |
178
+
179
+ **Returns:** `(element: HTMLElement | null, offset?: number) => void`
180
+
181
+ The returned function accepts:
182
+ - `element`: The element to scroll to
183
+ - `offset`: Optional offset from the top in pixels (default: 0)
184
+
82
185
  ### useScrollAnimation
83
186
 
84
- A hook for creating scroll-linked animations using Intersection Observer.
187
+ A hook for creating scroll-linked animations using Intersection Observer. Supports automatic iframe detection and explicit `targetWindow` for cross-window observation.
85
188
 
86
189
  ```tsx
87
190
  import { useScrollAnimation } from 'app-studio';
@@ -101,6 +204,98 @@ function ScrollAnimationComponent() {
101
204
  }
102
205
  ```
103
206
 
207
+ #### With Multiple Thresholds
208
+
209
+ Use an array of thresholds to get granular progress updates:
210
+
211
+ ```tsx
212
+ import { useScrollAnimation } from 'app-studio';
213
+
214
+ function AnimatedSection({ index }: { index: number }) {
215
+ const sectionRef = useRef<HTMLDivElement>(null);
216
+
217
+ const { isInView, progress } = useScrollAnimation(sectionRef, {
218
+ threshold: [0, 0.25, 0.5, 0.75, 1], // Fire at each 25% visibility
219
+ });
220
+
221
+ return (
222
+ <div
223
+ ref={sectionRef}
224
+ style={{
225
+ opacity: 0.3 + progress * 0.7,
226
+ transform: `scale(${0.85 + progress * 0.15})`,
227
+ transition: 'opacity 0.4s, transform 0.4s',
228
+ }}
229
+ >
230
+ <span>{isInView ? '✓ In View' : '○ Out of View'}</span>
231
+ <span>Progress: {(progress * 100).toFixed(0)}%</span>
232
+ </div>
233
+ );
234
+ }
235
+ ```
236
+
237
+ #### With Iframe Support
238
+
239
+ The hook automatically detects when elements are inside an iframe and uses the correct `IntersectionObserver`. You can also explicitly pass `targetWindow`:
240
+
241
+ ```tsx
242
+ import { useScrollAnimation } from 'app-studio';
243
+
244
+ function IframeAnimatedSection({ targetWindow }: { targetWindow?: Window }) {
245
+ const sectionRef = useRef<HTMLDivElement>(null);
246
+
247
+ // Auto-detect iframe context or use explicit targetWindow
248
+ const { isInView, progress } = useScrollAnimation(sectionRef, {
249
+ threshold: [0, 0.25, 0.5, 0.75, 1],
250
+ targetWindow, // Optional: explicitly set the iframe's window
251
+ });
252
+
253
+ return (
254
+ <div
255
+ ref={sectionRef}
256
+ style={{
257
+ opacity: 0.3 + progress * 0.7,
258
+ background: isInView ? '#e8f5e9' : '#f5f5f5',
259
+ }}
260
+ >
261
+ Progress: {(progress * 100).toFixed(0)}%
262
+ </div>
263
+ );
264
+ }
265
+ ```
266
+
267
+ #### With Callback
268
+
269
+ Use the `onIntersectionChange` callback for custom logic:
270
+
271
+ ```tsx
272
+ const { isInView, progress } = useScrollAnimation(ref, {
273
+ threshold: 0.5,
274
+ onIntersectionChange: (isIntersecting, ratio) => {
275
+ if (isIntersecting) {
276
+ analytics.track('section_viewed', { visibility: ratio });
277
+ }
278
+ },
279
+ });
280
+ ```
281
+
282
+ **Options:**
283
+
284
+ | Option | Type | Default | Description |
285
+ |--------|------|---------|-------------|
286
+ | `threshold` | `number \| number[]` | `0` | Visibility threshold(s) to trigger updates (0-1) |
287
+ | `rootMargin` | `string` | `'0px'` | Margin around the root for intersection calculation |
288
+ | `root` | `Element \| null` | `null` | Custom root element for intersection |
289
+ | `targetWindow` | `Window \| null` | auto-detected | Target window for iframe support. Auto-detects from element's `ownerDocument` if not specified. |
290
+ | `onIntersectionChange` | `(isIntersecting: boolean, ratio: number) => void` | - | Callback fired on intersection changes |
291
+
292
+ **Returns:**
293
+
294
+ | Property | Type | Description |
295
+ |----------|------|-------------|
296
+ | `isInView` | `boolean` | Whether the element is currently in view |
297
+ | `progress` | `number` | Intersection ratio (0 to 1) based on threshold |
298
+
104
299
  ### useInfiniteScroll
105
300
 
106
301
  A hook for implementing infinite scroll functionality.