diff options
author | 2022-07-19 19:21:58 +0000 | |
---|---|---|
committer | 2022-07-19 19:21:58 +0000 | |
commit | d73c04a9e58c7d320cdb4f34604de76b30199778 (patch) | |
tree | 163afe91847b0bf45b4191a308ec4a13fd28cf11 | |
parent | b37d7078a009869bf482912397a073dca490d3da (diff) | |
download | astro-d73c04a9e58c7d320cdb4f34604de76b30199778.tar.gz astro-d73c04a9e58c7d320cdb4f34604de76b30199778.tar.zst astro-d73c04a9e58c7d320cdb4f34604de76b30199778.zip |
<Picture> component should pass all unknown attributes to the <img> element (#3961)
* <Picture /> should pass all unrecognized props down to the <img> element
* chore: add changeset
* Adding test coverage for custom <img> attributes
* chore: adding a README note for passing attributes to the picture's img
* Revert "<Picture /> should pass all unrecognized props down to the <img> element"
This reverts commit ce3e33930f825ed91bc18c38caa205713212c1b9.
* Picture should pass alt text to the img
6 files changed, 38 insertions, 19 deletions
diff --git a/.changeset/chatty-bikes-sin.md b/.changeset/chatty-bikes-sin.md new file mode 100644 index 000000000..99d999bda --- /dev/null +++ b/.changeset/chatty-bikes-sin.md @@ -0,0 +1,5 @@ +--- +'@astrojs/image': patch +--- + +Updates the <Picture /> component to pass the `alt` attribute down to the <img> element diff --git a/packages/integrations/image/README.md b/packages/integrations/image/README.md index ee9fdf3c9..fef238891 100644 --- a/packages/integrations/image/README.md +++ b/packages/integrations/image/README.md @@ -188,13 +188,13 @@ const imageUrl = 'https://www.google.com/images/branding/googlelogo/2x/googlelog --- // Local image with multiple sizes -<Picture src={hero} widths={[200, 400, 800]} sizes="(max-width: 800px) 100vw, 800px" /> +<Picture src={hero} widths={[200, 400, 800]} sizes="(max-width: 800px) 100vw, 800px" alt="My hero image" /> // Remote image (aspect ratio is required) -<Picture src={imageUrl} widths={[200, 400, 800]} aspectRatio="4:3" sizes="(max-width: 800px) 100vw, 800px" /> +<Picture src={imageUrl} widths={[200, 400, 800]} aspectRatio="4:3" sizes="(max-width: 800px) 100vw, 800px" alt="My hero image" /> // Inlined imports are supported -<Picture src={import("../assets/hero.png")} widths={[200, 400, 800]} sizes="(max-width: 800px) 100vw, 800px" /> +<Picture src={import("../assets/hero.png")} widths={[200, 400, 800]} sizes="(max-width: 800px) 100vw, 800px" alt="My hero image" /> ``` </details> diff --git a/packages/integrations/image/components/Picture.astro b/packages/integrations/image/components/Picture.astro index fb1f1e2bd..bff6aad89 100644 --- a/packages/integrations/image/components/Picture.astro +++ b/packages/integrations/image/components/Picture.astro @@ -4,15 +4,17 @@ 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'> { +export interface LocalImageProps extends Omit<PictureAttributes, 'src' | 'width' | 'height'>, Omit<TransformOptions, 'src'>, Pick<ImageAttributes, 'loading' | 'decoding'> { src: ImageMetadata | Promise<{ default: ImageMetadata }>; + alt?: string; sizes: HTMLImageElement['sizes']; widths: number[]; formats?: OutputFormat[]; } -export interface RemoteImageProps extends Omit<PictureAttributes, 'src' | 'width' | 'height'>, TransformOptions, Omit<ImageAttributes, 'src' | 'width' | 'height'> { +export interface RemoteImageProps extends Omit<PictureAttributes, 'src' | 'width' | 'height'>, TransformOptions, Pick<ImageAttributes, 'loading' | 'decoding'> { src: string; + alt?: string; sizes: HTMLImageElement['sizes']; widths: number[]; aspectRatio: TransformOptions['aspectRatio']; @@ -21,7 +23,7 @@ export interface RemoteImageProps extends Omit<PictureAttributes, 'src' | 'width export type Props = LocalImageProps | RemoteImageProps; -const { src, sizes, widths, aspectRatio, formats = ['avif', 'webp'], loading = 'lazy', decoding = 'async', ...attrs } = Astro.props as Props; +const { src, alt, sizes, widths, aspectRatio, formats = ['avif', 'webp'], loading = 'lazy', decoding = 'async', ...attrs } = Astro.props as Props; const { image, sources } = await getPicture({ loader, src, widths, formats, aspectRatio }); --- @@ -29,7 +31,7 @@ const { image, sources } = await getPicture({ loader, src, widths, formats, aspe <picture {...attrs}> {sources.map(attrs => ( <source {...attrs} {sizes}>))} - <img {...image} {loading} {decoding} /> + <img {...image} {loading} {decoding} {alt} /> </picture> <style> diff --git a/packages/integrations/image/test/fixtures/basic-picture/src/pages/index.astro b/packages/integrations/image/test/fixtures/basic-picture/src/pages/index.astro index e3e0ade30..f51760e79 100644 --- a/packages/integrations/image/test/fixtures/basic-picture/src/pages/index.astro +++ b/packages/integrations/image/test/fixtures/basic-picture/src/pages/index.astro @@ -8,10 +8,10 @@ import { Picture } from '@astrojs/image'; <!-- Head Stuff --> </head> <body> - <Picture id="social-jpg" src={socialJpg} sizes="(min-width: 640px) 50vw, 100vw" widths={[253, 506]} /> + <Picture id="social-jpg" src={socialJpg} sizes="(min-width: 640px) 50vw, 100vw" widths={[253, 506]} alt="Social image" /> <br /> - <Picture id="google" src="https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png" sizes="(min-width: 640px) 50vw, 100vw" widths={[272, 544]} aspectRatio={544/184} /> + <Picture id="google" src="https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png" sizes="(min-width: 640px) 50vw, 100vw" widths={[272, 544]} aspectRatio={544/184} alt="Google logo" /> <br /> - <Picture id='inline' src={import('../assets/social.jpg')} sizes="(min-width: 640px) 50vw, 100vw" widths={[253, 506]} /> + <Picture id='inline' src={import('../assets/social.jpg')} sizes="(min-width: 640px) 50vw, 100vw" widths={[253, 506]} alt="Inline social image" /> </body> </html> diff --git a/packages/integrations/image/test/picture-ssg.test.js b/packages/integrations/image/test/picture-ssg.test.js index 0da1daa1c..d8851dbfa 100644 --- a/packages/integrations/image/test/picture-ssg.test.js +++ b/packages/integrations/image/test/picture-ssg.test.js @@ -45,12 +45,13 @@ describe('SSG pictures', function () { // TODO: better coverage to verify source props }); - it('includes src, width, and height attributes', () => { + it('includes <img> attributes', () => { const image = $('#social-jpg img'); expect(image.attr('src')).to.equal('/_image/assets/social_506x253.jpg'); expect(image.attr('width')).to.equal('506'); expect(image.attr('height')).to.equal('253'); + expect(image.attr('alt')).to.equal('Social image'); }); it('built the optimized image', () => { @@ -72,12 +73,13 @@ describe('SSG pictures', function () { // TODO: better coverage to verify source props }); - it('includes src, width, and height attributes', () => { + it('includes <img> attributes', () => { const image = $('#inline img'); expect(image.attr('src')).to.equal('/_image/assets/social_506x253.jpg'); expect(image.attr('width')).to.equal('506'); expect(image.attr('height')).to.equal('253'); + expect(image.attr('alt')).to.equal('Inline social image'); }); it('built the optimized image', () => { @@ -103,12 +105,13 @@ describe('SSG pictures', function () { // TODO: better coverage to verify source props }); - it('includes src, width, and height attributes', () => { + it('includes <img> attributes', () => { const image = $('#google img'); expect(image.attr('src')).to.equal(`/_image/googlelogo_color_272x92dp-${HASH}_544x184.png`); expect(image.attr('width')).to.equal('544'); expect(image.attr('height')).to.equal('184'); + expect(image.attr('alt')).to.equal('Google logo'); }); it('built the optimized image', () => { @@ -169,7 +172,7 @@ describe('SSG pictures', function () { // TODO: better coverage to verify source props }); - it('includes src, width, and height attributes', () => { + it('includes <img> attributes', () => { const image = $('#social-jpg img'); const src = image.attr('src'); @@ -184,6 +187,7 @@ describe('SSG pictures', function () { expect(searchParams.get('h')).to.equal('253'); // TODO: possible to avoid encoding the full image path? expect(searchParams.get('href').endsWith('/assets/social.jpg')).to.equal(true); + expect(image.attr('alt')).to.equal('Social image'); }); it('returns the optimized image', async () => { @@ -207,7 +211,7 @@ describe('SSG pictures', function () { // TODO: better coverage to verify source props }); - it('includes src, width, and height attributes', () => { + it('includes <img> attributes', () => { const image = $('#inline img'); const src = image.attr('src'); @@ -222,6 +226,7 @@ describe('SSG pictures', function () { expect(searchParams.get('h')).to.equal('253'); // TODO: possible to avoid encoding the full image path? expect(searchParams.get('href').endsWith('/assets/social.jpg')).to.equal(true); + expect(image.attr('alt')).to.equal('Inline social image'); }); it('returns the optimized image', async () => { @@ -245,7 +250,7 @@ describe('SSG pictures', function () { // TODO: better coverage to verify source props }); - it('includes src, width, and height attributes', () => { + it('includes <img> attributes', () => { const image = $('#google img'); const src = image.attr('src'); @@ -261,6 +266,7 @@ describe('SSG pictures', function () { expect(searchParams.get('href')).to.equal( 'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png' ); + expect(image.attr('alt')).to.equal('Google logo'); }); }); }); diff --git a/packages/integrations/image/test/picture-ssr.test.js b/packages/integrations/image/test/picture-ssr.test.js index 5bdc6f04c..4914b7354 100644 --- a/packages/integrations/image/test/picture-ssr.test.js +++ b/packages/integrations/image/test/picture-ssr.test.js @@ -33,7 +33,7 @@ describe('SSR pictures - build', function () { // TODO: better coverage to verify source props }); - it('includes src, width, and height attributes', async () => { + it('includes <img> attributes', async () => { const app = await fixture.loadTestAdapterApp(); const request = new Request('http://example.com/'); @@ -55,6 +55,7 @@ describe('SSR pictures - build', function () { expect(searchParams.get('h')).to.equal('253'); // TODO: possible to avoid encoding the full image path? expect(searchParams.get('href').endsWith('/assets/social.jpg')).to.equal(true); + expect(image.attr('alt')).to.equal('Social image'); }); // TODO: Track down why the fixture.fetch is failing with the test adapter @@ -93,7 +94,7 @@ describe('SSR pictures - build', function () { // TODO: better coverage to verify source props }); - it('includes src, width, and height attributes', async () => { + it('includes <img> attributes', async () => { const app = await fixture.loadTestAdapterApp(); const request = new Request('http://example.com/'); @@ -115,6 +116,7 @@ describe('SSR pictures - build', function () { expect(searchParams.get('h')).to.equal('253'); // TODO: possible to avoid encoding the full image path? expect(searchParams.get('href').endsWith('/assets/social.jpg')).to.equal(true); + expect(image.attr('alt')).to.equal('Inline social image'); }); }); @@ -134,7 +136,7 @@ describe('SSR pictures - build', function () { // TODO: better coverage to verify source props }); - it('includes src, width, and height attributes', async () => { + it('includes <img> attributes', async () => { const app = await fixture.loadTestAdapterApp(); const request = new Request('http://example.com/'); @@ -156,6 +158,7 @@ describe('SSR pictures - build', function () { expect(searchParams.get('h')).to.equal('184'); // TODO: possible to avoid encoding the full image path? expect(searchParams.get('href').endsWith('googlelogo_color_272x92dp.png')).to.equal(true); + expect(image.attr('alt')).to.equal('Google logo'); }); }); }); @@ -207,6 +210,7 @@ describe('SSR images - dev', function () { expect(searchParams.get('h')).to.equal('253'); // TODO: possible to avoid encoding the full image path? expect(searchParams.get('href').endsWith('/assets/social.jpg')).to.equal(true); + expect(image.attr('alt')).to.equal('Social image'); }); it('returns the optimized image', async () => { @@ -245,6 +249,7 @@ describe('SSR images - dev', function () { expect(searchParams.get('h')).to.equal('253'); // TODO: possible to avoid encoding the full image path? expect(searchParams.get('href').endsWith('/assets/social.jpg')).to.equal(true); + expect(image.attr('alt')).to.equal('Inline social image'); }); }); @@ -273,6 +278,7 @@ describe('SSR images - dev', function () { expect(searchParams.get('href')).to.equal( 'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png' ); + expect(image.attr('alt')).to.equal('Google logo'); }); }); }); |