summaryrefslogtreecommitdiff
path: root/packages/integrations/image/components/Image.astro
diff options
context:
space:
mode:
authorGravatar Tony Sullivan <tony.f.sullivan@outlook.com> 2022-07-08 21:37:55 +0000
committerGravatar GitHub <noreply@github.com> 2022-07-08 21:37:55 +0000
commit89d76753a0dc50b2967d1fa9d36e34bde2722b83 (patch)
treecfaf7ecf53999c15bb56646dad8c57e013c68450 /packages/integrations/image/components/Image.astro
parentec392589f6d60785e45a49acdb3b9bda29c566df (diff)
downloadastro-89d76753a0dc50b2967d1fa9d36e34bde2722b83.tar.gz
astro-89d76753a0dc50b2967d1fa9d36e34bde2722b83.tar.zst
astro-89d76753a0dc50b2967d1fa9d36e34bde2722b83.zip
Adds a new `<Picture>` component to the image integration (#3866)
* moving all normalization logic out of the Image component * refactor: only require loaders to provide the image src * Adding a `<Picture />` component * fixing types.ts imports * refactor: moving getImage to it's own file * updating component types to use astroHTML.JSX * Revert "updating component types to use astroHTML.JSX" This reverts commit 6e5f578da8d1d3fd262f3cd9add7549f7580af97. * going back to letting loaders add extra HTML attributes * Always use lazy loading and async decoding * Cleaning up the Picture component * Adding test coverage for <Picture> * updating the README * using JSX types for the Image and Picture elements * chore: adding changeset * Update packages/integrations/image/src/get-image.ts Co-authored-by: Nate Moore <natemoo-re@users.noreply.github.com> * allow users to override loading and async on the <img> * renaming config to constants, exporting getPicture() * found the right syntax to import astro-jsx Co-authored-by: Nate Moore <natemoo-re@users.noreply.github.com>
Diffstat (limited to 'packages/integrations/image/components/Image.astro')
-rw-r--r--packages/integrations/image/components/Image.astro112
1 files changed, 9 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>