@sanity/image-url
Version:
Tools to generate image urls from Sanity content
133 lines (115 loc) • 3.25 kB
text/typescript
import type {
SanityAsset,
SanityImageObject,
SanityImageSource,
SanityImageWithAssetStub,
SanityReference,
} from './types'
const isRef = (src: SanityImageSource): src is SanityReference => {
const source = src as SanityReference
return source ? typeof source._ref === 'string' : false
}
const isAsset = (src: SanityImageSource): src is SanityAsset => {
const source = src as SanityAsset
return source ? typeof source._id === 'string' : false
}
const isAssetStub = (src: SanityImageSource): src is SanityImageWithAssetStub => {
const source = src as SanityImageWithAssetStub
return source && source.asset ? typeof source.asset.url === 'string' : false
}
// Detect in-progress uploads (has upload key but no complete asset reference)
export const isInProgressUpload = (src: SanityImageSource): boolean => {
if (typeof src === 'object' && src !== null) {
const obj = src as any
// Check if it has an upload key (indicating in-progress upload)
return obj._upload && (!obj.asset || !obj.asset._ref)
}
return false
}
/**
* @internal
* Convert an asset-id, asset or image to an image record suitable for processing
*/
export function parseSource(source?: SanityImageSource) {
if (!source) {
return null
}
let image: SanityImageObject
if (typeof source === 'string' && isUrl(source)) {
// Someone passed an existing image url?
image = {
asset: {_ref: urlToId(source)},
}
} else if (typeof source === 'string') {
// Just an asset id
image = {
asset: {_ref: source},
}
} else if (isRef(source)) {
// We just got passed an asset directly
image = {
asset: source,
}
} else if (isAsset(source)) {
// If we were passed an image asset document
image = {
asset: {
_ref: source._id || '',
},
}
} else if (isAssetStub(source)) {
// If we were passed a partial asset (`url`, but no `_id`)
image = {
asset: {
_ref: urlToId(source.asset.url),
},
}
} else if (typeof source.asset === 'object') {
// Probably an actual image with materialized asset
image = {...source}
} else {
// We got something that does not look like an image, or it is an image
// that currently isn't sporting an asset.
return null
}
const img = source as SanityImageObject
if (img.crop) {
image.crop = img.crop
}
if (img.hotspot) {
image.hotspot = img.hotspot
}
return applyDefaults(image)
}
function isUrl(url: string) {
return /^https?:\/\//.test(`${url}`)
}
function urlToId(url: string) {
const parts = url.split('/').slice(-1)
return `image-${parts[0]}`.replace(/\.([a-z]+)$/, '-$1')
}
// Mock crop and hotspot if image lacks it
function applyDefaults(image: SanityImageObject) {
if (image.crop && image.hotspot) {
return image as Required<SanityImageObject>
}
// We need to pad in default values for crop or hotspot
const result = {...image}
if (!result.crop) {
result.crop = {
left: 0,
top: 0,
bottom: 0,
right: 0,
}
}
if (!result.hotspot) {
result.hotspot = {
x: 0.5,
y: 0.5,
height: 1.0,
width: 1.0,
}
}
return result as Required<SanityImageObject>
}