Modifier extensions for controlling video/audio behavior and responsive media.
import codes.yousef.summon.modifier.pauseOnScroll
import codes.yousef.summon.modifier.lazyLoad
import codes.yousef.summon.modifier.nativeLazyLoad
import codes.yousef.summon.modifier.aspectRatio
import codes.yousef.summon.modifier.responsiveMedia
Media modifiers provide scroll-based media control, lazy loading, and responsive behavior for media elements.
Marks an element for pause-on-scroll behavior using IntersectionObserver.
fun Modifier.pauseOnScroll(threshold: Float = 0.1f): Modifier
| Parameter | Type | Default | Description | |-----------|------|---------|-------------| | threshold | Float | 0.1f | Visibility threshold (0.0-1.0) at which to trigger |
When the element containing a <video> or <audio> child scrolls out of the viewport, the media will be paused. When it scrolls back into view, playback will resume if it was playing before.
This modifier adds data attributes that JavaScript observes using IntersectionObserver:
data-pause-on-scroll="true"data-pause-on-scroll-threshold="0.1"Box(modifier = Modifier().pauseOnScroll()) {
Video(
src = "hero-video.mp4",
autoplay = true,
muted = true,
loop = true
)
}
// With custom threshold (pause when 30% visible)
Box(modifier = Modifier().pauseOnScroll(threshold = 0.3f)) {
Video(src = "content-video.mp4")
}
The framework automatically initializes IntersectionObserver for elements with data-pause-on-scroll="true". Custom implementation:
document.querySelectorAll('[data-pause-on-scroll="true"]').forEach(el => {
const threshold = parseFloat(el.dataset.pauseOnScrollThreshold) || 0.1;
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
const video = el.querySelector('video');
if (video) {
if (entry.isIntersecting) {
if (video.dataset.wasPlaying === 'true') {
video.play();
}
} else {
video.dataset.wasPlaying = !video.paused;
video.pause();
}
}
});
}, { threshold });
observer.observe(el);
});
Marks an element for lazy loading when near the viewport.
fun Modifier.lazyLoad(rootMargin: String = "200px"): Modifier
| Parameter | Type | Default | Description | |-----------|------|---------|-------------| | rootMargin | String | "200px" | Distance from viewport to trigger loading |
Elements with this modifier will defer loading until they are within the specified distance of the viewport.
Adds data attributes:
data-lazy-load="true"data-lazy-load-margin="200px"// Lazy load images 200px before they enter viewport
Image(
src = "large-image.jpg",
modifier = Modifier().lazyLoad()
)
// Load 500px before viewport
Image(
src = "hero-image.jpg",
modifier = Modifier().lazyLoad(rootMargin = "500px")
)
Enables native browser lazy loading using the loading="lazy" attribute.
fun Modifier.nativeLazyLoad(): Modifier
Uses the browser's native lazy loading support. Simpler than IntersectionObserver-based lazy loading but with less control.
Image(
src = "image.jpg",
modifier = Modifier().nativeLazyLoad()
)
Sets the aspect ratio for responsive media containers.
fun Modifier.aspectRatio(width: Int, height: Int): Modifier
| Parameter | Type | Description | |-----------|------|-------------| | width | Int | Aspect width (e.g., 16) | | height | Int | Aspect height (e.g., 9) |
Uses CSS aspect-ratio property for modern browsers. The element will maintain the specified ratio regardless of its actual content.
// 16:9 widescreen
Video(
src = "video.mp4",
modifier = Modifier().aspectRatio(16, 9)
)
// 4:3 standard
Image(
src = "photo.jpg",
modifier = Modifier().aspectRatio(4, 3)
)
// 1:1 square
Box(modifier = Modifier().aspectRatio(1, 1)) {
// Content
}
Makes media responsive while maintaining aspect ratio.
fun Modifier.responsiveMedia(): Modifier
Applies styles for responsive media that fills its container width while maintaining correct height ratio:
width: 100%height: automax-width: 100%// Responsive video
Video(
src = "video.mp4",
modifier = Modifier().responsiveMedia()
)
// Combine with aspect ratio
Video(
src = "video.mp4",
modifier = Modifier()
.responsiveMedia()
.aspectRatio(16, 9)
)
Media modifiers can be combined with other modifiers:
Box(
modifier = Modifier()
.width("100%")
.maxWidth("800px")
.pauseOnScroll(threshold = 0.5f)
) {
Video(
src = "content.mp4",
autoplay = true,
muted = true,
modifier = Modifier()
.responsiveMedia()
.aspectRatio(16, 9)
.borderRadius("8px")
)
}