sanity-plugin-hotspot-array 0.0.7 → 0.1.0-v3-studio.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +136 -38
- package/lib/cjs/index.js +403 -0
- package/lib/cjs/index.js.map +1 -0
- package/lib/esm/index.js +395 -0
- package/lib/esm/index.js.map +1 -0
- package/lib/types/index.d.ts +36 -0
- package/lib/types/index.d.ts.map +1 -0
- package/package.json +61 -47
- package/sanity.json +6 -5
- package/src/Feedback.tsx +2 -2
- package/src/ImageHotspotArray.tsx +188 -0
- package/src/Spot.tsx +32 -19
- package/src/index.tsx +42 -0
- package/v2-incompatible.js +11 -0
- package/.babelrc +0 -3
- package/lib/Feedback.js +0 -23
- package/lib/Feedback.js.map +0 -1
- package/lib/HotspotArray.js +0 -189
- package/lib/HotspotArray.js.map +0 -1
- package/lib/Spot.js +0 -180
- package/lib/Spot.js.map +0 -1
- package/lib/useUnsetInputComponent.js +0 -32
- package/lib/useUnsetInputComponent.js.map +0 -1
- package/src/HotspotArray.tsx +0 -177
- package/src/useUnsetInputComponent.ts +0 -17
package/package.json
CHANGED
|
@@ -1,75 +1,89 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sanity-plugin-hotspot-array",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.1.0-v3-studio.1",
|
|
4
4
|
"description": "A configurable Custom Input for Arrays that will add and update items by clicking on an Image",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
"
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"husky": {
|
|
16
|
-
"hooks": {
|
|
17
|
-
"pre-commit": "npm run lint:fix"
|
|
5
|
+
"author": "Simeon Griggs <simeon@sanity.io>",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"main": "./lib/cjs/index.js",
|
|
8
|
+
"source": "./src/index.tsx",
|
|
9
|
+
"module": "./lib/esm/index.js",
|
|
10
|
+
"types": "./lib/types/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"require": "./lib/cjs/index.js",
|
|
14
|
+
"default": "./lib/esm/index.js"
|
|
18
15
|
}
|
|
19
16
|
},
|
|
17
|
+
"files": [
|
|
18
|
+
"src",
|
|
19
|
+
"lib",
|
|
20
|
+
"v2-incompatible.js",
|
|
21
|
+
"sanity.json"
|
|
22
|
+
],
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=14.0.0"
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "parcel build --no-cache",
|
|
28
|
+
"watch": "parcel watch",
|
|
29
|
+
"prepublishOnly": "npm run build",
|
|
30
|
+
"lint": "eslint src/**/*",
|
|
31
|
+
"lint:fix": "eslint . --fix",
|
|
32
|
+
"clean": "rimraf lib",
|
|
33
|
+
"prebuild": "npm run clean && plugin-kit verify-package --silent",
|
|
34
|
+
"link-watch": "plugin-kit link-watch",
|
|
35
|
+
"prepare": "husky install"
|
|
36
|
+
},
|
|
20
37
|
"repository": {
|
|
21
38
|
"type": "git",
|
|
22
|
-
"url": "git
|
|
39
|
+
"url": "git@github.com:sanity-io/sanity-plugin-hotspot-array.git"
|
|
23
40
|
},
|
|
24
41
|
"keywords": [
|
|
25
42
|
"sanity",
|
|
26
43
|
"sanity-plugin"
|
|
27
44
|
],
|
|
28
|
-
"author": "Simeon Griggs <simeon@sanity.io>",
|
|
29
|
-
"license": "MIT",
|
|
30
45
|
"dependencies": {
|
|
31
46
|
"@react-hookz/web": "^14.2.2",
|
|
32
47
|
"@sanity/asset-utils": "^1.2.3",
|
|
33
|
-
"@sanity/
|
|
34
|
-
"@sanity/
|
|
35
|
-
"@sanity/
|
|
36
|
-
"framer-motion": "^6.3.11"
|
|
37
|
-
"husky": "^8.0.1"
|
|
48
|
+
"@sanity/incompatible-plugin": "^1.0.4",
|
|
49
|
+
"@sanity/ui": "^1.0.0-beta.31",
|
|
50
|
+
"@sanity/util": "dev-preview || 3.0.0-dev-preview.22",
|
|
51
|
+
"framer-motion": "^6.3.11"
|
|
38
52
|
},
|
|
39
53
|
"devDependencies": {
|
|
40
|
-
"
|
|
54
|
+
"@commitlint/cli": "^17.1.2",
|
|
55
|
+
"@commitlint/config-conventional": "^17.1.0",
|
|
56
|
+
"@parcel/packager-ts": "^2.6.2",
|
|
57
|
+
"@parcel/transformer-typescript-types": "^2.6.2",
|
|
58
|
+
"@sanity/plugin-kit": "^1.0.2",
|
|
59
|
+
"@sanity/semantic-release-preset": "^2.0.2",
|
|
60
|
+
"@typescript-eslint/eslint-plugin": "^5.41.0",
|
|
61
|
+
"@typescript-eslint/parser": "^5.41.0",
|
|
62
|
+
"eslint": "^8.26.0",
|
|
41
63
|
"eslint-config-prettier": "^8.5.0",
|
|
42
64
|
"eslint-config-sanity": "^6.0.0",
|
|
43
|
-
"eslint-plugin-
|
|
65
|
+
"eslint-plugin-prettier": "^4.2.1",
|
|
66
|
+
"eslint-plugin-react": "^7.31.10",
|
|
67
|
+
"eslint-plugin-react-hooks": "^4.6.0",
|
|
68
|
+
"husky": "^8.0.1",
|
|
69
|
+
"lint-staged": "^13.0.3",
|
|
70
|
+
"parcel": "~2.6.0",
|
|
44
71
|
"pinst": "^2.1.6",
|
|
45
|
-
"prettier": "^2.7.
|
|
46
|
-
"
|
|
72
|
+
"prettier": "^2.7.1",
|
|
73
|
+
"react": "^18.0.0",
|
|
74
|
+
"rimraf": "^3.0.2",
|
|
75
|
+
"sanipack": "^2.1.0",
|
|
76
|
+
"sanity": "dev-preview || 3.0.0-dev-preview.22",
|
|
77
|
+
"typescript": "~4.7.0"
|
|
47
78
|
},
|
|
48
79
|
"peerDependencies": {
|
|
49
80
|
"@sanity/image-url": "1.0.1",
|
|
50
|
-
"@sanity/util": "2.29.5",
|
|
51
81
|
"lodash": "4.17.21",
|
|
52
|
-
"react": "^
|
|
82
|
+
"react": "^18.0.0",
|
|
83
|
+
"sanity": "dev-preview || 3.0.0-dev-preview.22"
|
|
53
84
|
},
|
|
54
85
|
"bugs": {
|
|
55
|
-
"url": "https://github.com/
|
|
56
|
-
},
|
|
57
|
-
"homepage": "https://github.com/SimeonGriggs/sanity-plugin-hotspot-array#readme",
|
|
58
|
-
"prettier": {
|
|
59
|
-
"semi": false,
|
|
60
|
-
"printWidth": 100,
|
|
61
|
-
"bracketSpacing": false,
|
|
62
|
-
"singleQuote": true
|
|
86
|
+
"url": "https://github.com/sanity-io/sanity-plugin-hotspot-array/issues"
|
|
63
87
|
},
|
|
64
|
-
"
|
|
65
|
-
"parser": "sanipack/babel/eslint-parser",
|
|
66
|
-
"extends": [
|
|
67
|
-
"sanity",
|
|
68
|
-
"sanity/react",
|
|
69
|
-
"prettier"
|
|
70
|
-
],
|
|
71
|
-
"ignorePatterns": [
|
|
72
|
-
"lib/**/"
|
|
73
|
-
]
|
|
74
|
-
}
|
|
88
|
+
"homepage": "https://github.com/sanity-io/sanity-plugin-hotspot-array#readme"
|
|
75
89
|
}
|
package/sanity.json
CHANGED
package/src/Feedback.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import React from 'react'
|
|
1
|
+
import React, {ReactNode} from 'react'
|
|
2
2
|
import {Card, Text} from '@sanity/ui'
|
|
3
3
|
|
|
4
|
-
export default function Feedback({children}) {
|
|
4
|
+
export default function Feedback({children}: {children: ReactNode}) {
|
|
5
5
|
return (
|
|
6
6
|
<Card padding={4} radius={2} shadow={1} tone="caution">
|
|
7
7
|
<Text>{children}</Text>
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/* eslint-disable react/display-name */
|
|
2
|
+
|
|
3
|
+
import {getImageDimensions} from '@sanity/asset-utils'
|
|
4
|
+
import {
|
|
5
|
+
ArrayOfObjectsInputProps,
|
|
6
|
+
ImageValue,
|
|
7
|
+
insert,
|
|
8
|
+
ObjectSchemaType,
|
|
9
|
+
PatchEvent,
|
|
10
|
+
set,
|
|
11
|
+
setIfMissing,
|
|
12
|
+
useClient,
|
|
13
|
+
useFormValue,
|
|
14
|
+
} from 'sanity'
|
|
15
|
+
import imageUrlBuilder from '@sanity/image-url'
|
|
16
|
+
import {Card, Flex, Stack} from '@sanity/ui'
|
|
17
|
+
import {randomKey} from '@sanity/util/content'
|
|
18
|
+
import get from 'lodash/get'
|
|
19
|
+
import React, {useCallback, useMemo, useRef, useState} from 'react'
|
|
20
|
+
|
|
21
|
+
import {IUseResizeObserverCallback, useDebouncedCallback, useResizeObserver} from '@react-hookz/web'
|
|
22
|
+
import Feedback from './Feedback'
|
|
23
|
+
import Spot from './Spot'
|
|
24
|
+
import {ImageHotspotOptions} from './index'
|
|
25
|
+
|
|
26
|
+
const imageStyle = {width: `100%`, height: `auto`}
|
|
27
|
+
|
|
28
|
+
const VALID_ROOT_PATHS = ['document', 'parent']
|
|
29
|
+
|
|
30
|
+
export type FnHotspotMove = (key: string, x: number, y: number) => void
|
|
31
|
+
|
|
32
|
+
export type HotspotItem<HotspotFields = {[key: string]: unknown}> = {
|
|
33
|
+
_key: string
|
|
34
|
+
_type: string
|
|
35
|
+
x: number
|
|
36
|
+
y: number
|
|
37
|
+
} & HotspotFields
|
|
38
|
+
|
|
39
|
+
export function ImageHotspotArray(
|
|
40
|
+
props: ArrayOfObjectsInputProps<HotspotItem> & {imageHotspotOptions: ImageHotspotOptions}
|
|
41
|
+
) {
|
|
42
|
+
const {value, onChange, imageHotspotOptions, schemaType, renderPreview} = props
|
|
43
|
+
|
|
44
|
+
const sanityClient = useClient({apiVersion: '2022-01-01'})
|
|
45
|
+
|
|
46
|
+
const imageHotspotPathRoot = useMemo(() => {
|
|
47
|
+
const pathRoot = VALID_ROOT_PATHS.includes(imageHotspotOptions.pathRoot ?? '')
|
|
48
|
+
? imageHotspotOptions.pathRoot
|
|
49
|
+
: 'document'
|
|
50
|
+
return pathRoot === 'document' ? [] : props.path.slice(0, -1)
|
|
51
|
+
}, [imageHotspotOptions.pathRoot, props.path])
|
|
52
|
+
|
|
53
|
+
const rootObject = useFormValue(imageHotspotPathRoot)
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Finding the image from the imageHotspotPathRoot (defaults to document),
|
|
57
|
+
* using the path from the hotspot's `options` field
|
|
58
|
+
*
|
|
59
|
+
* when changes in imageHotspotPathRoot (e.g. document) occur,
|
|
60
|
+
* check if there are any changes to the hotspotImage and update the reference
|
|
61
|
+
*/
|
|
62
|
+
const hotspotImage = useMemo(() => {
|
|
63
|
+
return get(rootObject, imageHotspotOptions.imagePath) as ImageValue | undefined
|
|
64
|
+
}, [rootObject, imageHotspotOptions.imagePath])
|
|
65
|
+
|
|
66
|
+
const displayImage = useMemo(() => {
|
|
67
|
+
const builder = imageUrlBuilder(sanityClient).dataset(sanityClient.config().dataset ?? '')
|
|
68
|
+
const urlFor = (source: ImageValue) => builder.image(source)
|
|
69
|
+
|
|
70
|
+
if (hotspotImage?.asset?._ref) {
|
|
71
|
+
const {aspectRatio} = getImageDimensions(hotspotImage.asset._ref)
|
|
72
|
+
const width = 1200
|
|
73
|
+
const height = Math.round(width / aspectRatio)
|
|
74
|
+
const url = urlFor(hotspotImage).width(width).url()
|
|
75
|
+
|
|
76
|
+
return {width, height, url}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return null
|
|
80
|
+
}, [hotspotImage, sanityClient])
|
|
81
|
+
|
|
82
|
+
const handleHotspotImageClick = useCallback(
|
|
83
|
+
(event: any) => {
|
|
84
|
+
const {nativeEvent} = event
|
|
85
|
+
|
|
86
|
+
// Calculate the x/y percentage of the click position
|
|
87
|
+
const x = Number(((nativeEvent.offsetX * 100) / nativeEvent.srcElement.width).toFixed(2))
|
|
88
|
+
const y = Number(((nativeEvent.offsetY * 100) / nativeEvent.srcElement.height).toFixed(2))
|
|
89
|
+
const description = `New Hotspot at ${x}% x ${y}%`
|
|
90
|
+
|
|
91
|
+
const newRow: HotspotItem = {
|
|
92
|
+
_key: randomKey(12),
|
|
93
|
+
_type: schemaType.of[0].name,
|
|
94
|
+
x,
|
|
95
|
+
y,
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (imageHotspotOptions?.descriptionPath) {
|
|
99
|
+
newRow[imageHotspotOptions.descriptionPath] = description
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
onChange(PatchEvent.from([setIfMissing([]), insert([newRow], 'after', [-1])]))
|
|
103
|
+
},
|
|
104
|
+
[imageHotspotOptions, onChange, schemaType]
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
const handleHotspotMove: FnHotspotMove = useCallback(
|
|
108
|
+
(key, x, y) => {
|
|
109
|
+
onChange(
|
|
110
|
+
PatchEvent.from([
|
|
111
|
+
// Set the `x` value of this array key item
|
|
112
|
+
set(x, [{_key: key}, 'x']),
|
|
113
|
+
// Set the `y` value of this array key item
|
|
114
|
+
set(y, [{_key: key}, 'y']),
|
|
115
|
+
])
|
|
116
|
+
)
|
|
117
|
+
},
|
|
118
|
+
[onChange]
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
const hotspotImageRef = useRef<HTMLImageElement | null>(null)
|
|
122
|
+
|
|
123
|
+
const [imageRect, setImageRect] = useState<DOMRectReadOnly>()
|
|
124
|
+
const updateImageRectCallback = useDebouncedCallback(
|
|
125
|
+
((e) => setImageRect(e.contentRect)) as IUseResizeObserverCallback,
|
|
126
|
+
[setImageRect],
|
|
127
|
+
200
|
|
128
|
+
)
|
|
129
|
+
useResizeObserver(hotspotImageRef, updateImageRectCallback)
|
|
130
|
+
|
|
131
|
+
return (
|
|
132
|
+
<Stack space={[2, 2, 3]}>
|
|
133
|
+
{displayImage?.url ? (
|
|
134
|
+
<div style={{position: `relative`}}>
|
|
135
|
+
{imageRect &&
|
|
136
|
+
(value?.length ?? 0) > 0 &&
|
|
137
|
+
value?.map((spot, index) => (
|
|
138
|
+
<Spot
|
|
139
|
+
index={index}
|
|
140
|
+
key={spot._key}
|
|
141
|
+
value={spot}
|
|
142
|
+
bounds={imageRect}
|
|
143
|
+
update={handleHotspotMove}
|
|
144
|
+
hotspotDescriptionPath={imageHotspotOptions?.descriptionPath}
|
|
145
|
+
tooltip={imageHotspotOptions?.tooltip}
|
|
146
|
+
renderPreview={renderPreview}
|
|
147
|
+
schemaType={schemaType.of[0] as ObjectSchemaType}
|
|
148
|
+
/>
|
|
149
|
+
))}
|
|
150
|
+
|
|
151
|
+
<Card __unstable_checkered shadow={1}>
|
|
152
|
+
<Flex align="center" justify="center">
|
|
153
|
+
<img
|
|
154
|
+
ref={hotspotImageRef}
|
|
155
|
+
src={displayImage.url}
|
|
156
|
+
width={displayImage.width}
|
|
157
|
+
height={displayImage.height}
|
|
158
|
+
alt=""
|
|
159
|
+
style={imageStyle}
|
|
160
|
+
onClick={handleHotspotImageClick}
|
|
161
|
+
/>
|
|
162
|
+
</Flex>
|
|
163
|
+
</Card>
|
|
164
|
+
</div>
|
|
165
|
+
) : (
|
|
166
|
+
<Feedback>
|
|
167
|
+
{imageHotspotOptions.imagePath ? (
|
|
168
|
+
<>
|
|
169
|
+
No Hotspot image found at path <code>{imageHotspotOptions.imagePath}</code>
|
|
170
|
+
</>
|
|
171
|
+
) : (
|
|
172
|
+
<>
|
|
173
|
+
Define a path in this field using to the image field in this document at{' '}
|
|
174
|
+
<code>options.hotspotImagePath</code>
|
|
175
|
+
</>
|
|
176
|
+
)}
|
|
177
|
+
</Feedback>
|
|
178
|
+
)}
|
|
179
|
+
{imageHotspotOptions.pathRoot && !VALID_ROOT_PATHS.includes(imageHotspotOptions.pathRoot) && (
|
|
180
|
+
<Feedback>
|
|
181
|
+
The supplied imageHotspotPathRoot "{imageHotspotOptions.pathRoot}" is not valid, falling
|
|
182
|
+
back to "document". Available values are "{VALID_ROOT_PATHS.join(', ')}".
|
|
183
|
+
</Feedback>
|
|
184
|
+
)}
|
|
185
|
+
{props.renderDefault(props as unknown as ArrayOfObjectsInputProps)}
|
|
186
|
+
</Stack>
|
|
187
|
+
)
|
|
188
|
+
}
|
package/src/Spot.tsx
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
1
2
|
import {Box, Text, Tooltip} from '@sanity/ui'
|
|
2
3
|
import {motion, useMotionValue} from 'framer-motion'
|
|
3
4
|
import get from 'lodash/get'
|
|
4
|
-
import React, {CSSProperties, ReactElement, useEffect} from 'react'
|
|
5
|
-
import {FnHotspotMove,
|
|
5
|
+
import React, {ComponentType, CSSProperties, ReactElement, useEffect} from 'react'
|
|
6
|
+
import {FnHotspotMove, HotspotItem} from './ImageHotspotArray'
|
|
7
|
+
import {ObjectSchemaType, RenderPreviewCallback} from 'sanity'
|
|
6
8
|
|
|
7
9
|
const dragStyle: CSSProperties = {
|
|
8
10
|
width: '1.4rem',
|
|
9
11
|
height: '1.4rem',
|
|
10
12
|
position: 'absolute',
|
|
13
|
+
boxSizing: 'border-box',
|
|
11
14
|
top: 0,
|
|
12
15
|
left: 0,
|
|
13
16
|
margin: '-0.7rem 0 0 -0.7rem',
|
|
@@ -60,39 +63,49 @@ const labelStyleWhileActive: CSSProperties = {
|
|
|
60
63
|
visibility: 'hidden',
|
|
61
64
|
}
|
|
62
65
|
|
|
63
|
-
const round = (num) => Math.round(num * 100) / 100
|
|
66
|
+
const round = (num: number) => Math.round(num * 100) / 100
|
|
64
67
|
|
|
65
|
-
interface
|
|
66
|
-
|
|
68
|
+
export interface HotspotTooltipProps<HotspotFields = {[key: string]: unknown}> {
|
|
69
|
+
value: HotspotItem<HotspotFields>
|
|
70
|
+
schemaType: ObjectSchemaType
|
|
71
|
+
renderPreview: RenderPreviewCallback
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
interface HotspotProps<HotspotFields = {[key: string]: unknown}> {
|
|
75
|
+
value: HotspotItem
|
|
67
76
|
bounds: DOMRectReadOnly
|
|
68
77
|
update: FnHotspotMove
|
|
69
78
|
hotspotDescriptionPath?: string
|
|
70
|
-
tooltip?:
|
|
79
|
+
tooltip?: ComponentType<HotspotTooltipProps<HotspotFields>>
|
|
71
80
|
index: number
|
|
81
|
+
schemaType: ObjectSchemaType
|
|
82
|
+
renderPreview: RenderPreviewCallback
|
|
72
83
|
}
|
|
73
84
|
|
|
74
85
|
export default function Spot({
|
|
75
|
-
|
|
86
|
+
value,
|
|
76
87
|
bounds,
|
|
77
88
|
update,
|
|
78
89
|
hotspotDescriptionPath,
|
|
79
90
|
tooltip,
|
|
80
91
|
index,
|
|
81
|
-
|
|
92
|
+
schemaType,
|
|
93
|
+
renderPreview,
|
|
94
|
+
}: HotspotProps) {
|
|
82
95
|
const [isDragging, setIsDragging] = React.useState(false)
|
|
83
96
|
const [isHovering, setIsHovering] = React.useState(false)
|
|
84
97
|
|
|
85
98
|
// x/y are stored as % but need to be converted to px
|
|
86
|
-
const x = useMotionValue(round(bounds.width * (
|
|
87
|
-
const y = useMotionValue(round(bounds.height * (
|
|
99
|
+
const x = useMotionValue(round(bounds.width * (value.x / 100)))
|
|
100
|
+
const y = useMotionValue(round(bounds.height * (value.y / 100)))
|
|
88
101
|
|
|
89
102
|
/**
|
|
90
103
|
* update x/y if the bounds change when resizing the window
|
|
91
104
|
*/
|
|
92
105
|
useEffect(() => {
|
|
93
|
-
x.set(round(bounds.width * (
|
|
94
|
-
y.set(round(bounds.height * (
|
|
95
|
-
}, [bounds])
|
|
106
|
+
x.set(round(bounds.width * (value.x / 100)))
|
|
107
|
+
y.set(round(bounds.height * (value.y / 100)))
|
|
108
|
+
}, [x, y, value, bounds])
|
|
96
109
|
|
|
97
110
|
const handleDragEnd = React.useCallback(() => {
|
|
98
111
|
setIsDragging(false)
|
|
@@ -109,8 +122,8 @@ export default function Spot({
|
|
|
109
122
|
const safeX = Math.max(0, Math.min(100, newX))
|
|
110
123
|
const safeY = Math.max(0, Math.min(100, newY))
|
|
111
124
|
|
|
112
|
-
update(
|
|
113
|
-
}, [
|
|
125
|
+
update(value._key, safeX, safeY)
|
|
126
|
+
}, [x, y, value, update, bounds])
|
|
114
127
|
const handleDragStart = React.useCallback(() => setIsDragging(true), [])
|
|
115
128
|
|
|
116
129
|
const handleHoverStart = React.useCallback(() => setIsHovering(true), [])
|
|
@@ -122,18 +135,18 @@ export default function Spot({
|
|
|
122
135
|
|
|
123
136
|
return (
|
|
124
137
|
<Tooltip
|
|
125
|
-
key={
|
|
138
|
+
key={value._key}
|
|
126
139
|
disabled={isDragging}
|
|
127
140
|
portal
|
|
128
141
|
content={
|
|
129
142
|
tooltip && typeof tooltip === 'function' ? (
|
|
130
|
-
React.createElement(tooltip, {
|
|
143
|
+
React.createElement(tooltip, {value, renderPreview, schemaType})
|
|
131
144
|
) : (
|
|
132
145
|
<Box padding={2} style={{maxWidth: 200, pointerEvents: `none`}}>
|
|
133
146
|
<Text textOverflow="ellipsis">
|
|
134
147
|
{hotspotDescriptionPath
|
|
135
|
-
? (get(
|
|
136
|
-
: `${
|
|
148
|
+
? (get(value, hotspotDescriptionPath) as string)
|
|
149
|
+
: `${value.x}% x ${value.y}%`}
|
|
137
150
|
</Text>
|
|
138
151
|
</Box>
|
|
139
152
|
)
|
package/src/index.tsx
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import {ImageHotspotArray, type HotspotItem} from './ImageHotspotArray'
|
|
2
|
+
import React, {ComponentType} from 'react'
|
|
3
|
+
import {ArrayOfObjectsInputProps, createPlugin} from 'sanity'
|
|
4
|
+
import {type HotspotTooltipProps} from './Spot'
|
|
5
|
+
|
|
6
|
+
export interface ImageHotspotOptions<HotspotFields = {[key: string]: unknown}> {
|
|
7
|
+
pathRoot?: 'document' | 'parent'
|
|
8
|
+
imagePath: string
|
|
9
|
+
descriptionPath?: string
|
|
10
|
+
tooltip?: ComponentType<HotspotTooltipProps<HotspotFields>>
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
declare module '@sanity/types' {
|
|
14
|
+
export interface ArrayOptions {
|
|
15
|
+
imageHotspot?: ImageHotspotOptions
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export {ImageHotspotArray}
|
|
20
|
+
export type {HotspotTooltipProps, HotspotItem}
|
|
21
|
+
|
|
22
|
+
export const imageHotspotArrayPlugin = createPlugin({
|
|
23
|
+
name: 'image-hotspot-array',
|
|
24
|
+
form: {
|
|
25
|
+
components: {
|
|
26
|
+
input: (props) => {
|
|
27
|
+
if (props.schemaType.jsonType === 'array' && props.schemaType.options?.imageHotspot) {
|
|
28
|
+
const imageHotspotOptions = props.schemaType.options?.imageHotspot
|
|
29
|
+
if (imageHotspotOptions) {
|
|
30
|
+
return (
|
|
31
|
+
<ImageHotspotArray
|
|
32
|
+
{...(props as unknown as ArrayOfObjectsInputProps<HotspotItem>)}
|
|
33
|
+
imageHotspotOptions={imageHotspotOptions}
|
|
34
|
+
/>
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return props.renderDefault(props)
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
})
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const {showIncompatiblePluginDialog} = require('@sanity/incompatible-plugin')
|
|
2
|
+
const {name, version, sanityExchangeUrl} = require('./package.json')
|
|
3
|
+
|
|
4
|
+
export default showIncompatiblePluginDialog({
|
|
5
|
+
name: name,
|
|
6
|
+
versions: {
|
|
7
|
+
v3: version,
|
|
8
|
+
v2: undefined,
|
|
9
|
+
},
|
|
10
|
+
sanityExchangeUrl,
|
|
11
|
+
})
|
package/.babelrc
DELETED
package/lib/Feedback.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = Feedback;
|
|
7
|
-
|
|
8
|
-
var _react = _interopRequireDefault(require("react"));
|
|
9
|
-
|
|
10
|
-
var _ui = require("@sanity/ui");
|
|
11
|
-
|
|
12
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
13
|
-
|
|
14
|
-
function Feedback(_ref) {
|
|
15
|
-
var children = _ref.children;
|
|
16
|
-
return /*#__PURE__*/_react.default.createElement(_ui.Card, {
|
|
17
|
-
padding: 4,
|
|
18
|
-
radius: 2,
|
|
19
|
-
shadow: 1,
|
|
20
|
-
tone: "caution"
|
|
21
|
-
}, /*#__PURE__*/_react.default.createElement(_ui.Text, null, children));
|
|
22
|
-
}
|
|
23
|
-
//# sourceMappingURL=Feedback.js.map
|
package/lib/Feedback.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Feedback.js","names":["Feedback","children"],"sources":["../src/Feedback.tsx"],"sourcesContent":["import React from 'react'\nimport {Card, Text} from '@sanity/ui'\n\nexport default function Feedback({children}) {\n return (\n <Card padding={4} radius={2} shadow={1} tone=\"caution\">\n <Text>{children}</Text>\n </Card>\n )\n}\n"],"mappings":";;;;;;;AAAA;;AACA;;;;AAEe,SAASA,QAAT,OAA8B;EAAA,IAAXC,QAAW,QAAXA,QAAW;EAC3C,oBACE,6BAAC,QAAD;IAAM,OAAO,EAAE,CAAf;IAAkB,MAAM,EAAE,CAA1B;IAA6B,MAAM,EAAE,CAArC;IAAwC,IAAI,EAAC;EAA7C,gBACE,6BAAC,QAAD,QAAOA,QAAP,CADF,CADF;AAKD"}
|