next-sanity
next-sanity copied to clipboard
next-sanity/image does not appear to be fully using hotspot
Is your feature request related to a problem? Please describe.
I had originally been using sanity-image which was good. However, after the livestream with Knut and Lee, I wanted to try using next/image with a loader for Sanity images. Digging through this repo I found that there was next-sanity/image. So I went to implement it as pretty much a drop in replacement for sanity-image. However, I noticed that sometimes it used the hotspot and sometimes it didn't
Describe the solution you'd like It would be nice if I didn't have to crop and it could just use the hotspot.
Describe alternatives you've considered
Well as described above, I used sanity-image.
Additional context
An example where I needed to crop in order to get a hotspot
Before cropping my image BUT still have the hotspot
After cropping the image with same hotspot
An example where I didn't need to crop in order to get a hotspot
Image in the network tab
Display in a card element
How I am using the component
// components/image.tsx
import createImageUrlBuilder from '@sanity/image-url'
import { Image as SanityImage, type ImageProps } from 'next-sanity/image'
import { projectId, dataset } from '@/lib/sanity.api'
const imageBuilder = createImageUrlBuilder({
projectId,
dataset,
})
export const urlForImage = (source: Parameters<(typeof imageBuilder)['image']>[0]) =>
imageBuilder.image(source)
export function Image(
props: Omit<ImageProps, 'src' | 'alt'> & {
src: {
_key?: string | null
_type?: 'image' | string
asset: {
_type: 'reference'
_ref: string
}
crop: {
top: number
bottom: number
left: number
right: number
} | null
hotspot: {
x: number
y: number
height: number
width: number
} | null
caption?: string | undefined
}
alt?: string
},
) {
const { src, ...rest } = props
const imageBuilder = urlForImage(props.src)
if (props.width) {
imageBuilder.width(typeof props.width === 'string' ? parseInt(props.width, 10) : props.width)
}
if (props.height) {
imageBuilder.height(
typeof props.height === 'string' ? parseInt(props.height, 10) : props.height,
)
}
return (
<SanityImage
alt={typeof src.caption === 'string' ? src.caption : ''}
{...rest}
src={imageBuilder.url()}
/>
)
}
I guess this technically could have been a bug report as well but 🤷🏼♂️
Any library using @sanity/image-url will be inaccurate so long as they ignore this 3.5 year old issue that I documented extensively and even built an entire interactive playground to demonstrate. Sanity doesn't seem to have any interest in fixing it. That is half the reason for why sanity-image exists and uses its own, leaner, more accurate and reliable URL builder.
@coreyward does sanity-image expose a loader that can be used with next/image? I’m mainly doing some experimenting after the livestream with Lee and Knut.
A loader is just a function that generates the URLs for your image. Since sanity-image exports both buildSrc and buildSrcSet functions that handle the vast majority of the optimizations performed by the library you can use them in a loader to produce more accurate, optimized image URLs.
This said, I don't believe Next provides you any way to pass the the hotspot and crop values to your loader. They don't even let you pass in the height of the image. It's a hyper-constrained, ridiculously convoluted system that treats devs with kid gloves, all for an exorbitant fee.