diff --git a/apps/docs/src/examples/components/aspect-ratio/ResponsiveImage.vue b/apps/docs/src/examples/components/aspect-ratio/ResponsiveImage.vue new file mode 100644 index 000000000..afc936b11 --- /dev/null +++ b/apps/docs/src/examples/components/aspect-ratio/ResponsiveImage.vue @@ -0,0 +1,31 @@ + + + diff --git a/apps/docs/src/examples/components/aspect-ratio/basic.vue b/apps/docs/src/examples/components/aspect-ratio/basic.vue new file mode 100644 index 000000000..4a3da3a2c --- /dev/null +++ b/apps/docs/src/examples/components/aspect-ratio/basic.vue @@ -0,0 +1,38 @@ + + + diff --git a/apps/docs/src/examples/components/aspect-ratio/responsive.vue b/apps/docs/src/examples/components/aspect-ratio/responsive.vue new file mode 100644 index 000000000..c839757e3 --- /dev/null +++ b/apps/docs/src/examples/components/aspect-ratio/responsive.vue @@ -0,0 +1,18 @@ + + + diff --git a/apps/docs/src/examples/components/image/BlurUpImage.vue b/apps/docs/src/examples/components/image/BlurUpImage.vue new file mode 100644 index 000000000..348277531 --- /dev/null +++ b/apps/docs/src/examples/components/image/BlurUpImage.vue @@ -0,0 +1,34 @@ + + + diff --git a/apps/docs/src/examples/components/image/PictureImage.vue b/apps/docs/src/examples/components/image/PictureImage.vue new file mode 100644 index 000000000..5d3a8d95e --- /dev/null +++ b/apps/docs/src/examples/components/image/PictureImage.vue @@ -0,0 +1,49 @@ + + + diff --git a/apps/docs/src/examples/components/image/basic.vue b/apps/docs/src/examples/components/image/basic.vue new file mode 100644 index 000000000..48fbd185f --- /dev/null +++ b/apps/docs/src/examples/components/image/basic.vue @@ -0,0 +1,28 @@ + + + diff --git a/apps/docs/src/examples/components/image/observer.vue b/apps/docs/src/examples/components/image/observer.vue new file mode 100644 index 000000000..32f07b7ce --- /dev/null +++ b/apps/docs/src/examples/components/image/observer.vue @@ -0,0 +1,43 @@ + + + diff --git a/apps/docs/src/examples/components/image/picture.vue b/apps/docs/src/examples/components/image/picture.vue new file mode 100644 index 000000000..af346a734 --- /dev/null +++ b/apps/docs/src/examples/components/image/picture.vue @@ -0,0 +1,15 @@ + + + diff --git a/apps/docs/src/examples/composables/use-image/LazyImage.vue b/apps/docs/src/examples/composables/use-image/LazyImage.vue new file mode 100644 index 000000000..68270bb7f --- /dev/null +++ b/apps/docs/src/examples/composables/use-image/LazyImage.vue @@ -0,0 +1,33 @@ + + + diff --git a/apps/docs/src/examples/composables/use-image/RetryableImage.vue b/apps/docs/src/examples/composables/use-image/RetryableImage.vue new file mode 100644 index 000000000..a3eb48a8e --- /dev/null +++ b/apps/docs/src/examples/composables/use-image/RetryableImage.vue @@ -0,0 +1,68 @@ + + + diff --git a/apps/docs/src/examples/composables/use-image/basic.vue b/apps/docs/src/examples/composables/use-image/basic.vue new file mode 100644 index 000000000..5bf054530 --- /dev/null +++ b/apps/docs/src/examples/composables/use-image/basic.vue @@ -0,0 +1,65 @@ + + + diff --git a/apps/docs/src/examples/composables/use-image/lazy.vue b/apps/docs/src/examples/composables/use-image/lazy.vue new file mode 100644 index 000000000..f91f973d1 --- /dev/null +++ b/apps/docs/src/examples/composables/use-image/lazy.vue @@ -0,0 +1,27 @@ + + + diff --git a/apps/docs/src/examples/composables/use-image/retry.vue b/apps/docs/src/examples/composables/use-image/retry.vue new file mode 100644 index 000000000..83b2d5741 --- /dev/null +++ b/apps/docs/src/examples/composables/use-image/retry.vue @@ -0,0 +1,12 @@ + + + diff --git a/apps/docs/src/examples/composables/use-image/useLazyImage.ts b/apps/docs/src/examples/composables/use-image/useLazyImage.ts new file mode 100644 index 000000000..db56645cf --- /dev/null +++ b/apps/docs/src/examples/composables/use-image/useLazyImage.ts @@ -0,0 +1,25 @@ +import { useImage, useIntersectionObserver } from '@vuetify/v0' +import { shallowRef, toValue } from 'vue' + +import type { MaybeRefOrGetter } from 'vue' + +/** + * Combines `useImage` and `useIntersectionObserver` into a single reusable + * composable. The image source is gated by viewport intersection, and the + * returned `target` ref is bound to the element that should be observed. + */ +export function useLazyImage (src: MaybeRefOrGetter, rootMargin = '0px') { + const target = shallowRef() + + const { isIntersecting } = useIntersectionObserver(target, () => {}, { + once: true, + rootMargin, + }) + + const image = useImage({ + src: () => toValue(src), + eager: isIntersecting, + }) + + return { target, ...image } +} diff --git a/apps/docs/src/pages/components/index.md b/apps/docs/src/pages/components/index.md index fe16e97af..d4838bed5 100644 --- a/apps/docs/src/pages/components/index.md +++ b/apps/docs/src/pages/components/index.md @@ -24,6 +24,7 @@ Foundation components for building higher-level abstractions. | Name | Description | | - | - | +| [AspectRatio](/components/primitives/aspect-ratio) | Fixed width-to-height ratio container via CSS `aspect-ratio` | | [Atom](/components/primitives/atom) | Polymorphic element with dynamic `as` prop and renderless mode | | [Portal](/components/primitives/portal) | Teleport wrapper with automatic z-index stacking via useStack | | [Presence](/components/primitives/presence) | Renderless mount lifecycle with lazy mounting and exit animation delay | @@ -77,6 +78,7 @@ Components with meaningful HTML defaults. Render semantic elements by default bu | [Avatar](/components/semantic/avatar) | Image/fallback avatar with priority loading | | [Breadcrumbs](/components/semantic/breadcrumbs) | Navigation breadcrumbs with overflow detection and truncation | | [Carousel](/components/semantic/carousel) | Scroll-snap slide navigation with multi-slide display and drag/swipe | +| [Image](/components/semantic/image) | Image with placeholder, error fallback, and lazy loading | | [Pagination](/components/semantic/pagination) | Page navigation with semantic `