Skip to content
This repository has been archived by the owner on Jun 21, 2023. It is now read-only.

Commit

Permalink
Add naturalWidth/naturalHeight to onLoadingComplete() callback (ver…
Browse files Browse the repository at this point in the history
  • Loading branch information
styfle authored Aug 2, 2021
1 parent fdf44a2 commit eed3d8e
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 15 deletions.
5 changes: 5 additions & 0 deletions docs/api-reference/next/image.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,11 @@ The image position when using `layout="fill"`.

A callback function that is invoked once the image is completely loaded and the [placeholder](#placeholder) has been removed.

The `onLoadingComplete` function accepts one parameter, an object with the following properties:

- [`naturalWidth`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/naturalWidth)
- [`naturalHeight`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/naturalHeight)

### loading

> **Attention**: This property is only meant for advanced usage. Switching an
Expand Down
14 changes: 11 additions & 3 deletions packages/next/client/image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ type LayoutValue = typeof VALID_LAYOUT_VALUES[number]

type PlaceholderValue = 'blur' | 'empty'

type OnLoadingComplete = (result: {
naturalWidth: number
naturalHeight: number
}) => void

type ImgElementStyle = NonNullable<JSX.IntrinsicElements['img']['style']>

interface StaticImageData {
Expand Down Expand Up @@ -103,7 +108,7 @@ export type ImageProps = Omit<
unoptimized?: boolean
objectFit?: ImgElementStyle['objectFit']
objectPosition?: ImgElementStyle['objectPosition']
onLoadingComplete?: () => void
onLoadingComplete?: OnLoadingComplete
}

const {
Expand Down Expand Up @@ -249,7 +254,7 @@ function handleLoading(
img: HTMLImageElement | null,
src: string,
placeholder: PlaceholderValue,
onLoadingComplete?: () => void
onLoadingComplete?: OnLoadingComplete
) {
if (!img) {
return
Expand All @@ -265,7 +270,10 @@ function handleLoading(
}
loadedImageURLs.add(src)
if (onLoadingComplete) {
onLoadingComplete()
const { naturalWidth, naturalHeight } = img
// Pass back read-only primitive values but not the
// underlying DOM element because it could be misused.
onLoadingComplete({ naturalWidth, naturalHeight })
}
})
}
Expand Down
2 changes: 1 addition & 1 deletion test/integration/image-component/base-path/public/test.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,53 @@ import Image from 'next/image'
const Page = () => (
<div>
<h1>On Loading Complete Test</h1>
<ImageWithMessage id="1" src="/test.jpg" />
<ImageWithMessage
id="1"
src="/test.jpg"
layout="intrinsic"
width="128"
height="128"
/>
<ImageWithMessage
id="2"
src={require('../public/test.png')}
placeholder="blur"
layout="fixed"
/>
<ImageWithMessage
id="3"
src="/test.svg"
layout="responsive"
width="1200"
height="1200"
/>
<div style={{ position: 'relative', width: '64px', height: '64px' }}>
<ImageWithMessage
id="4"
src="/test.ico"
layout="fill"
objectFit="contain"
/>
</div>
<div id="footer" />
</div>
)

function ImageWithMessage({ id, src }) {
function ImageWithMessage({ id, ...props }) {
const [msg, setMsg] = useState('[LOADING]')
return (
<>
<Image
id={`img${id}`}
src={src}
width="400"
height="400"
onLoadingComplete={() => setMsg(`loaded img${id}`)}
onLoadingComplete={({ naturalWidth, naturalHeight }) =>
setMsg(
`loaded img${id} with dimensions ${naturalWidth}x${naturalHeight}`
)
}
{...props}
/>
<p id={`msg${id}`}>{msg}</p>
<hr />
</>
)
}
Expand Down
2 changes: 1 addition & 1 deletion test/integration/image-component/default/public/test.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 20 additions & 3 deletions test/integration/image-component/default/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,22 +188,39 @@ function runTests(mode) {
try {
browser = await webdriver(appPort, '/on-loading-complete')

await browser.eval(`document.getElementById("footer").scrollIntoView()`)

await check(
() => browser.eval(`document.getElementById("img1").src`),
/test(.*)jpg/
)

await check(
() => browser.eval(`document.getElementById("img2").src`),
/test(.*).png/
)
await check(
() => browser.eval(`document.getElementById("img3").src`),
/test(.*)svg/
)
await check(
() => browser.eval(`document.getElementById("img4").src`),
/test(.*)ico/
)
await check(
() => browser.eval(`document.getElementById("msg1").textContent`),
'loaded img1'
'loaded img1 with dimensions 128x128'
)
await check(
() => browser.eval(`document.getElementById("msg2").textContent`),
'loaded img2'
'loaded img2 with dimensions 400x400'
)
await check(
() => browser.eval(`document.getElementById("msg3").textContent`),
'loaded img3 with dimensions 266x266'
)
await check(
() => browser.eval(`document.getElementById("msg4").textContent`),
'loaded img4 with dimensions 21x21'
)
} finally {
if (browser) {
Expand Down
2 changes: 1 addition & 1 deletion test/integration/image-optimizer/app/public/test.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit eed3d8e

Please sign in to comment.