Skip to content

Commit

Permalink
Update next/future/image to support only width or only height (#…
Browse files Browse the repository at this point in the history
…40278)

This PR allows you to resize a statically imported image using only `width` or only `height`. For example:

```jsx
import img from './img.jpg'
<Image src={img} width="200" />
```

Previously, you had to specify both or else the image aspect ratio would not be preserved.
  • Loading branch information
styfle committed Sep 6, 2022
1 parent 71ad0dd commit d53e2f2
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 18 deletions.
33 changes: 21 additions & 12 deletions packages/next/client/future/image.tsx
Expand Up @@ -548,6 +548,8 @@ export default function Image({
}

let staticSrc = ''
let widthInt = getInt(width)
let heightInt = getInt(height)
let blurWidth: number | undefined
let blurHeight: number | undefined
if (isStaticImport(src)) {
Expand All @@ -560,23 +562,31 @@ export default function Image({
)}`
)
}
blurWidth = staticImageData.blurWidth
blurHeight = staticImageData.blurHeight
blurDataURL = blurDataURL || staticImageData.blurDataURL
staticSrc = staticImageData.src

// Ignore width and height (come from the bundler) when "fill" is used
if (!fill) {
height = height || staticImageData.height
width = width || staticImageData.width
}
if (!staticImageData.height || !staticImageData.width) {
throw new Error(
`An object should only be passed to the image component src parameter if it comes from a static image import. It must include height and width. Received ${JSON.stringify(
staticImageData
)}`
)
}

blurWidth = staticImageData.blurWidth
blurHeight = staticImageData.blurHeight
blurDataURL = blurDataURL || staticImageData.blurDataURL
staticSrc = staticImageData.src

if (!fill) {
if (!widthInt && !heightInt) {
widthInt = staticImageData.width
heightInt = staticImageData.height
} else if (widthInt && !heightInt) {
const ratio = widthInt / staticImageData.width
heightInt = Math.round(staticImageData.height * ratio)
} else if (!widthInt && heightInt) {
const ratio = heightInt / staticImageData.height
widthInt = Math.round(staticImageData.width * ratio)
}
}
}
src = typeof src === 'string' ? src : staticSrc

Expand All @@ -593,8 +603,7 @@ export default function Image({

const [blurComplete, setBlurComplete] = useState(false)
const [showAltText, setShowAltText] = useState(false)
let widthInt = getInt(width)
let heightInt = getInt(height)

const qualityInt = getInt(quality)

if (process.env.NODE_ENV !== 'production') {
Expand Down
10 changes: 9 additions & 1 deletion test/integration/image-future/base-path/pages/static-img.js
Expand Up @@ -10,6 +10,7 @@ import testSVG from '../public/test.svg'
import testGIF from '../public/test.gif'
import testBMP from '../public/test.bmp'
import testICO from '../public/test.ico'
import widePNG from '../public/wide.png'

import TallImage from '../components/TallImage'

Expand All @@ -19,7 +20,14 @@ const Page = () => {
<h1 id="page-header">Static Image</h1>
<Image id="basic-static" src={testImg} placeholder="blur" />
<TallImage />
<Image id="defined-size-static" src={testPNG} height="150" width="150" />
<Image
id="defined-width-and-height"
src={testPNG}
height="150"
width="150"
/>
<Image id="defined-height-only" src={widePNG} height="350" />
<Image id="defined-width-only" src={widePNG} width="400" />
<Image id="require-static" src={require('../public/foo/test-rect.jpg')} />
<Image
id="basic-non-static"
Expand Down
14 changes: 12 additions & 2 deletions test/integration/image-future/base-path/test/static.test.js
Expand Up @@ -69,11 +69,21 @@ const runTests = (isDev) => {
expect(img.attr('width')).toBe('400')
expect(img.attr('height')).toBe('300')
})
it('Should allow provided width and height to override intrinsic', async () => {
const img = $('#defined-size-static')
it('should use width and height prop to override import', async () => {
const img = $('#defined-width-and-height')
expect(img.attr('width')).toBe('150')
expect(img.attr('height')).toBe('150')
})
it('should use height prop to adjust both width and height', async () => {
const img = $('#defined-height-only')
expect(img.attr('width')).toBe('600')
expect(img.attr('height')).toBe('350')
})
it('should use width prop to adjust both width and height', async () => {
const img = $('#defined-width-only')
expect(img.attr('width')).toBe('400')
expect(img.attr('height')).toBe('233')
})

it('Should add a blur placeholder a statically imported jpg', async () => {
const style = $('#basic-static').attr('style')
Expand Down
10 changes: 9 additions & 1 deletion test/integration/image-future/default/pages/static-img.js
Expand Up @@ -10,6 +10,7 @@ import testSVG from '../public/test.svg'
import testGIF from '../public/test.gif'
import testBMP from '../public/test.bmp'
import testICO from '../public/test.ico'
import widePNG from '../public/wide.png'

import TallImage from '../components/TallImage'

Expand All @@ -19,7 +20,14 @@ const Page = () => {
<h1 id="page-header">Static Image</h1>
<Image id="basic-static" src={testImg} placeholder="blur" />
<TallImage />
<Image id="defined-size-static" src={testPNG} height="150" width="150" />
<Image
id="defined-width-and-height"
src={testPNG}
height="150"
width="150"
/>
<Image id="defined-height-only" src={widePNG} height="350" />
<Image id="defined-width-only" src={widePNG} width="400" />
<Image id="require-static" src={require('../public/foo/test-rect.jpg')} />
<Image
id="basic-non-static"
Expand Down
14 changes: 12 additions & 2 deletions test/integration/image-future/default/test/static.test.ts
Expand Up @@ -74,11 +74,21 @@ const runTests = (isDev) => {
expect(img.attr('width')).toBe('400')
expect(img.attr('height')).toBe('300')
})
it('Should allow provided width and height to override intrinsic', async () => {
const img = $('#defined-size-static')
it('should use width and height prop to override import', async () => {
const img = $('#defined-width-and-height')
expect(img.attr('width')).toBe('150')
expect(img.attr('height')).toBe('150')
})
it('should use height prop to adjust both width and height', async () => {
const img = $('#defined-height-only')
expect(img.attr('width')).toBe('600')
expect(img.attr('height')).toBe('350')
})
it('should use width prop to adjust both width and height', async () => {
const img = $('#defined-width-only')
expect(img.attr('width')).toBe('400')
expect(img.attr('height')).toBe('233')
})

it('Should add a blur placeholder a statically imported jpg', async () => {
const style = $('#basic-static').attr('style')
Expand Down

0 comments on commit d53e2f2

Please sign in to comment.