summaryrefslogtreecommitdiff
path: root/packages/integrations/image/components
diff options
context:
space:
mode:
Diffstat (limited to 'packages/integrations/image/components')
-rw-r--r--packages/integrations/image/components/Image.astro112
-rw-r--r--packages/integrations/image/components/Picture.astro39
-rw-r--r--packages/integrations/image/components/index.js1
3 files changed, 49 insertions, 103 deletions
diff --git a/packages/integrations/image/components/Image.astro b/packages/integrations/image/components/Image.astro
index 51d4182a2..326c1bc6c 100644
--- a/packages/integrations/image/components/Image.astro
+++ b/packages/integrations/image/components/Image.astro
@@ -4,7 +4,7 @@ import loader from 'virtual:image-loader';
import { getImage } from '../src/index.js';
import type { ImageAttributes, ImageMetadata, TransformOptions, OutputFormat } from '../src/types.js';
-export interface LocalImageProps extends Omit<TransformOptions, 'src'>, Omit<ImageAttributes, 'src'> {
+export interface LocalImageProps extends Omit<TransformOptions, 'src'>, Omit<ImageAttributes, 'src' | 'width' | 'height'> {
src: ImageMetadata | Promise<{ default: ImageMetadata }>;
}
@@ -17,109 +17,15 @@ export interface RemoteImageProps extends TransformOptions, ImageAttributes {
export type Props = LocalImageProps | RemoteImageProps;
-function isLocalImage(props: Props): props is LocalImageProps {
- // vite-plugin-astro-image resolves ESM imported images
- // to a metadata object
- return typeof props.src !== 'string';
-}
-
-function parseAspectRatio(aspectRatio: TransformOptions['aspectRatio']) {
- if (!aspectRatio) {
- return undefined;
- }
-
- // parse aspect ratio strings, if required (ex: "16:9")
- if (typeof aspectRatio === 'number') {
- aspectRatio = aspectRatio;
- } else {
- const [width, height] = aspectRatio.split(':');
- aspectRatio = parseInt(width) / parseInt(height);
- }
-}
-
-async function resolveProps(props: Props): Promise<TransformOptions> {
- // For remote images, just check the width/height provided
- if (!isLocalImage(props)) {
- return calculateSize(props);
- }
+const { loading = "lazy", decoding = "async", ...props } = Astro.props as Props;
- let { width, height, aspectRatio, format, ...rest } = props;
-
- // if a Promise<ImageMetadata> was provided, unwrap it first
- const { src, ...metadata } = 'then' in props.src ? (await props.src).default : props.src;
-
- if (!width && !height) {
- // neither dimension was provided, use the file metadata
- width = metadata.width;
- height = metadata.height;
- } else if (width) {
- // one dimension was provided, calculate the other
- let ratio = parseAspectRatio(aspectRatio) || metadata.width / metadata.height;
- height = height || width / ratio;
- } else if (height) {
- // one dimension was provided, calculate the other
- let ratio = parseAspectRatio(aspectRatio) || metadata.width / metadata.height;
- width = width || height * ratio;
- }
-
- return {
- ...rest,
- width,
- height,
- aspectRatio,
- src,
- format: format || metadata.format as OutputFormat,
- }
-}
-
-function calculateSize(transform: TransformOptions): TransformOptions {
- // keep width & height as provided
- if (transform.width && transform.height) {
- return transform;
- }
-
- if (!transform.width && !transform.height) {
- throw new Error(`"width" and "height" cannot both be undefined`);
- }
-
- if (!transform.aspectRatio) {
- throw new Error(`"aspectRatio" must be included if only "${transform.width ? "width": "height"}" is provided`)
- }
-
- let aspectRatio: number;
+const attrs = await getImage(loader, props);
+---
- // parse aspect ratio strings, if required (ex: "16:9")
- if (typeof transform.aspectRatio === 'number') {
- aspectRatio = transform.aspectRatio;
- } else {
- const [width, height] = transform.aspectRatio.split(':');
- aspectRatio = parseInt(width) / parseInt(height);
- }
+<img {...attrs} {loading} {decoding} />
- if (transform.width) {
- // only width was provided, calculate height
- return {
- ...transform,
- width: transform.width,
- height: transform.width / aspectRatio
- };
- } else if (transform.height) {
- // only height was provided, calculate width
- return {
- ...transform,
- width: transform.height * aspectRatio,
- height: transform.height
- }
+<style>
+ img {
+ content-visibility: auto;
}
-
- return transform;
-}
-
-const props = Astro.props as Props;
-
-const imageProps = await resolveProps(props);
-
-const attrs = await getImage(loader, imageProps);
----
-
-<img {...attrs} />
+</style>
diff --git a/packages/integrations/image/components/Picture.astro b/packages/integrations/image/components/Picture.astro
new file mode 100644
index 000000000..ed2cfd49e
--- /dev/null
+++ b/packages/integrations/image/components/Picture.astro
@@ -0,0 +1,39 @@
+---
+// @ts-ignore
+import loader from 'virtual:image-loader';
+import { getPicture } from '../src/get-picture.js';
+import type { ImageAttributes, ImageMetadata, OutputFormat, PictureAttributes, TransformOptions } from '../src/types.js';
+
+export interface LocalImageProps extends Omit<PictureAttributes, 'src' | 'width' | 'height'>, Omit<TransformOptions, 'src'>, Omit<ImageAttributes, 'src' | 'width' | 'height'> {
+ src: ImageMetadata | Promise<{ default: ImageMetadata }>;
+ sizes: HTMLImageElement['sizes'];
+ widths: number[];
+ formats?: OutputFormat[];
+}
+
+export interface RemoteImageProps extends Omit<PictureAttributes, 'src' | 'width' | 'height'>, TransformOptions, Omit<ImageAttributes, 'src' | 'width' | 'height'> {
+ src: string;
+ sizes: HTMLImageElement['sizes'];
+ widths: number[];
+ aspectRatio: TransformOptions['aspectRatio'];
+ formats?: OutputFormat[];
+}
+
+export type Props = LocalImageProps | RemoteImageProps;
+
+const { src, sizes, widths, aspectRatio, formats = ['avif', 'webp'], loading = 'lazy', decoding = 'eager', ...attrs } = Astro.props as Props;
+
+const { image, sources } = await getPicture({ loader, src, widths, formats, aspectRatio });
+---
+
+<picture {...attrs}>
+ {sources.map(attrs => (
+ <source {...attrs} {sizes}>))}
+ <img {...image} {loading} {decoding} />
+</picture>
+
+<style>
+ img {
+ content-visibility: auto;
+ }
+</style>
diff --git a/packages/integrations/image/components/index.js b/packages/integrations/image/components/index.js
index fa9809650..be0e10130 100644
--- a/packages/integrations/image/components/index.js
+++ b/packages/integrations/image/components/index.js
@@ -1 +1,2 @@
export { default as Image } from './Image.astro';
+export { default as Picture } from './Picture.astro';