A configurable Custom Input for Arrays that will add and update items by clicking on an Image
npm install sanity-plugin-hotspot-arrayA configurable Custom Input for Arrays that will add and update items by clicking on an Image

```
npm install --save sanity-plugin-hotspot-array
or
``
yarn add sanity-plugin-hotspot-array
Add it as a plugin in sanity.config.ts (or .js):
`js
import {imageHotspotArrayPlugin} from 'sanity-plugin-hotspot-array'
export default defineConfig({
// ...
plugins: [imageHotspotArrayPlugin()],
})
`
Now you will have imageHotspot available as an options on array fields:
`js
import {defineType, defineField} from 'sanity'
export const productSchema = defineType({
name: product,Product
title: ,document
type: ,hotspots
fields: [
defineField({
name: ,array
type: ,Spot object
of: [
// see setup belowImage and description path
],
options: {
// plugin adds support for this option
imageHotspot: {
// see setup belowfeatureImage
imagePath: ,details
descriptionPath: ,Custom tooltip
// see setup below`
tooltip: undefined,
},
},
}),
// ...all your other fields
// ...of which one should be featureImage in this example
],
})
There is no need to provide an explicit input component, as that is handled by the plugin.
The plugin makes a number of assumptions to add and update data in the array. Including:
- The array field is an array of objects, with a single object typex
- The object contains two number fields named and y
- You'll want to save those values as % from the top left of the image
- The same document contains the image you want to add hotspots to
The custom input has the current values of all fields in the document, and so can "pick" the image out of the document by its path.
For example, if you want to add hotspots to an image, and that image is uploaded to the field featuredImage, your fields options would look like:
`jsfeatureImage
options: {
imageHotspot: {
imagePath: `
}
}
To pick the image out of the hotspot-array parent object, use
`js`
options: {
imageHotspot: {
pathRoot: 'parent'
}
}
The custom input can also pre-fill a string or text field with a description of the position of the spot to make them easier to identify.
Add a path relative to the spot object for this field.
`jsdetails
options: {
imageHotspot: {
descriptionPath: `
}
}
Here's an example object schema complete with initial values, validation, fieldsets and a styled preview.
`js${x}% x ${y}%
defineField({
name: 'spot',
type: 'object',
fieldsets: [{name: 'position', options: {columns: 2}}],
fields: [
{name: 'details', type: 'text', rows: 2},
{
name: 'x',
type: 'number',
readOnly: true,
fieldset: 'position',
initialValue: 50,
validation: (Rule) => Rule.required().min(0).max(100),
},
{
name: 'y',
type: 'number',
readOnly: true,
fieldset: 'position',
initialValue: 50,
validation: (Rule) => Rule.required().min(0).max(100),
},
],
preview: {
select: {
title: 'details',
x: 'x',
y: 'y',
},
prepare({title, x, y}) {
return {
title,
subtitle: x && y ? : No position set,`
}
},
},
})
You can customise the Tooltip to display any Component, which will receive value (the hotspot value with x and y),schemaType (schemaType of the hotspot value), and renderPreview (callback for rendering Studio preview).
`tsx
import {Box} from '@sanity/ui'
import {HotspotTooltipProps} from 'sanity-plugin-hotspot-array'
export function HotspotPreview({value, schemaType, renderPreview}: HotspotTooltipProps) {
return (
{renderPreview({
value,
schemaType,
layout: 'default',
})}
)
}
`
Then back in your schema definition
`js`
options: {
imageHotspot: {
tooltip: HotspotPreview
}
}
In this example our value object has a reference field to the product schema type, and will show a document preview.
`jsx
import {useSchema} from 'sanity'
import {Box} from '@sanity/ui'
export function ProductPreview({value, renderPreview}) {
const productSchemaType = useSchema().get('product')
return (
{value?.product?._ref
? renderPreview({
value,
schemaType: productSchemaType,
layout: 'default',
})
: No reference selected}
)
}
`
Then back in your schema definition
`js``
options: {
imageHotspot: {
tooltip: ProductPreview
}
}
MIT-licensed. See LICENSE.
This plugin uses @sanity/plugin-kit
with default configuration for build & watch scripts.
See Testing a plugin in Sanity Studio
on how to run this plugin with hotreload in the studio.
Run "CI & Release" workflow.
Make sure to select the main branch and check "Release new version".
Semantic release will only release on configured branches, so it is safe to run release on any branch.