sanity-plugin-hotspot-array 0.1.0-v3-studio.2 → 0.1.0

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/.babelrc ADDED
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "sanipack/babel"
3
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "extends": "@sanity/semantic-release-preset",
3
+ "branches": ["main", {"name": "studio-v2", "channel": "studio-v2", "range": "0.1.x"}]
4
+ }
package/CHANGELOG.md ADDED
@@ -0,0 +1,16 @@
1
+ <!-- markdownlint-disable --><!-- textlint-disable -->
2
+
3
+ # 📓 Changelog
4
+
5
+ All notable changes to this project will be documented in this file. See
6
+ [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
7
+
8
+ ## [0.1.0](https://github.com/sanity-io/sanity-plugin-hotspot-array/compare/v0.0.10...v0.1.0) (2022-11-22)
9
+
10
+ ### Features
11
+
12
+ - make semantic-release happy (not really a feat) ([a70d25c](https://github.com/sanity-io/sanity-plugin-hotspot-array/commit/a70d25c0df2b03350ed8e94954e7a41c94aacb8f))
13
+
14
+ ### Bug Fixes
15
+
16
+ - **ci:** publish using semantic-release ([4b67704](https://github.com/sanity-io/sanity-plugin-hotspot-array/commit/4b67704e5ce0216a0faaf1a3377d8052b2b866b1))
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2022 Simeon Griggs
3
+ Copyright (c) 2022 Sanity.io
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,12 +1,7 @@
1
1
  # sanity-plugin-hotspot-array
2
2
 
3
- > > **NOTE**
4
- >
5
- > This is the **Sanity Studio v3 version** of sanity-plugin-hotspot-array.
6
- >
7
- > For the v2 version, please refer to the [v2-branch](https://github.com/sanity-io/sanity-plugin-hotspot-array).
8
-
9
- ## What is it?
3
+ > This is a **Sanity Studio v2** plugin.
4
+ > For the v3 version, please refer to the [v3-branch](https://github.com/sanity-io/sanity-plugin-hotspot-array).
10
5
 
11
6
  A configurable Custom Input for Arrays that will add and update items by clicking on an Image
12
7
 
@@ -14,106 +9,85 @@ A configurable Custom Input for Arrays that will add and update items by clickin
14
9
 
15
10
  ## Installation
16
11
 
12
+ ```sh
13
+ yarn add sanity-plugin-hotspot-array@studio-v2
17
14
  ```
18
- npm install --save sanity-plugin-hotspot-array@studio-v3
19
- ```
20
-
21
- or
22
15
 
16
+ Next, add `"hotspot-array"` to `sanity.json` plugins array:
17
+ ```json
18
+ "plugins": [
19
+ "hotspot-array"
20
+ ]
23
21
  ```
24
- yarn add sanity-plugin-hotspot-array@studio-v3
25
- ```
26
-
27
22
 
28
- ## Usage
23
+ ## Setup
29
24
 
30
- Add it as a plugin in sanity.config.ts (or .js):
25
+ Import the `HotspotArray` component from this package, into your schema. And insert it as the `inputComponent` of an `array` field.
31
26
 
32
27
  ```js
33
- import { imageHotspotArray } from "sanity-plugin-hotspot-array";
34
-
35
- export default defineConfig({
36
- // ...
37
- plugins: [
38
- imageHotspotArray(),
39
- ]
40
- })
41
- ```
42
-
43
- Now you will have `imageHotspot` available as an options on `array` fields:
28
+ import HotspotArray from 'sanity-plugin-hotspot-array'
44
29
 
45
- ```js
46
- import {defineType, defineField} from 'sanity'
47
-
48
- export const productSchema = defineType({
30
+ export default {
49
31
  name: `product`,
50
32
  title: `Product`,
51
33
  type: `document`,
52
34
  fields: [
53
- defineField({
35
+ {
54
36
  name: `hotspots`,
55
37
  type: `array`,
38
+ inputComponent: HotspotArray,
56
39
  of: [
57
40
  // see `Spot object` setup below
58
41
  ],
59
42
  options: {
60
- // plugin adds support for this option
61
- imageHotspot: {
62
- // see `Image and description path` setup below
63
- imagePath: `featureImage`,
64
- descriptionPath: `details`,
65
- // see `Custom tooltip` setup below
66
- tooltip: undefined,
67
- }
43
+ // see `Image and description paths` setup below
44
+ imageHotspotPathRoot: `document`,
45
+ hotspotImagePath: `featureImage`,
46
+ hotspotDescriptionPath: `details`,
47
+ // see `Custom tooltip` setup below
48
+ hotspotTooltip: undefined,
68
49
  },
69
- }),
50
+ },
70
51
  // ...all your other fields
71
- // ...of which one should be featureImage in this example
72
52
  ],
73
- })
53
+ }
74
54
  ```
75
- There is no need to provide an explicit input component, as that is handled by the plugin.
76
55
 
77
56
  The plugin makes a number of assumptions to add and update data in the array. Including:
78
57
 
79
- - The `array` field is an array of objects, with a single object type
58
+ - The `array` field is an array of objects
80
59
  - The object contains two number fields named `x` and `y`
81
60
  - You'll want to save those values as % from the top left of the image
82
61
  - The same document contains the image you want to add hotspots to
83
62
 
84
- ### Image path
63
+ ### Image and description paths
85
64
 
86
- 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.
65
+ The custom input has the current values of all fields in the document by default, and so can "pick" the image out of the document by its path.
87
66
 
88
- 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:
67
+ For example, if you want to add hotspots to an image, and that image is uploaded to the document field of `featuredImage`, your fields `options` would look like:
89
68
 
90
69
  ```js
91
70
  options: {
92
- imageHotspot: {
93
- imagePath: `featureImage`
94
- }
71
+ hotspotImagePath: `featureImage`
95
72
  }
96
73
  ```
97
74
 
98
- To pick the image out of the hotspot-array parent object, use
75
+ Alternatively, you may supply 'parent' to the `imageHotspotPathRoot` option to pick from the parent object instead. Using 'parent' as `imageHotspotPathRoot` in favor of the default 'document' may be required, e.g. if your schema of hotspots array is defined as a child of another array, and therefore you can not reference dynamically the correct field in a 'document' specified by `hotspotImagePath`.
76
+
77
+ In this case, if the image is uploaded to the parent object field of `featuredImage`, your fields `options` would look like:
78
+
99
79
  ```js
100
80
  options: {
101
- imageHotspot: {
102
- pathRoot: 'parent'
103
- }
81
+ imageHotspotPathRoot: `parent`,
82
+ hotspotImagePath: `featureImage`
104
83
  }
105
84
  ```
106
85
 
107
- ### Description path
108
-
109
- 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.
110
- Add a path **relative to the spot object** for this field.
86
+ 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.
111
87
 
112
88
  ```js
113
89
  options: {
114
- imageHotspot: {
115
- descriptionPath: `details`
116
- }
90
+ hotspotDescriptionPath: `details`
117
91
  }
118
92
  ```
119
93
 
@@ -122,7 +96,7 @@ options: {
122
96
  Here's an example object schema complete with initial values, validation, fieldsets and a styled preview.
123
97
 
124
98
  ```js
125
- defineField({
99
+ {
126
100
  name: 'spot',
127
101
  type: 'object',
128
102
  fieldsets: [{name: 'position', options: {columns: 2}}],
@@ -158,66 +132,28 @@ defineField({
158
132
  }
159
133
  },
160
134
  },
161
- })
135
+ }
162
136
  ```
163
137
 
164
138
  ## Custom tooltip
165
139
 
166
- You can customise the Tooltip to display any Component, which will receive `value` (the hotspot value with x and y),
167
- `schemaType` (schemaType of the hotspot value), and `renderPreview` (callback for rendering Studio preview).
168
-
169
- ### Example 1 - use default hotspot preview
140
+ You can customise the Tooltip to display any Component, it will accept a single prop `spot` which contains the values of the object.
170
141
 
171
- ```tsx
172
- import { Box } from "@sanity/ui";
173
- import { HotspotTooltipProps } from "sanity-plugin-hotspot-array";
174
-
175
- export function HotspotPreview({
176
- value,
177
- schemaType,
178
- renderPreview,
179
- }: HotspotTooltipProps) {
180
- return (
181
- <Box padding={2} style={{ minWidth: 200 }}>
182
- {renderPreview({
183
- value,
184
- schemaType,
185
- layout: "default",
186
- })}
187
- </Box>
188
- );
189
- }
190
- ```
191
-
192
- Then back in your schema definition
142
+ In this example our `spot` object has a `reference` field to the `product` schema type, and will show a Document Preview.
193
143
 
194
144
  ```js
195
- options: {
196
- imageHotspot: {
197
- tooltip: HotspotPreview
198
- }
199
- }
200
- ```
201
-
202
- ### Example 2 - reference value in hotspot
203
- In this example our `value` object has a `reference` field to the `product` schema type, and will show a document preview.
204
-
205
- ```jsx
206
- import {useSchema }from 'sanity'
145
+ // Setup a custom tooltip component
146
+ import Preview from 'part:@sanity/base/preview'
147
+ import schema from 'part:@sanity/base/schema'
207
148
  import {Box} from '@sanity/ui'
208
149
 
209
- export function ProductPreview({value, renderPreview}) {
210
- const productSchemaType = useSchema().get('product')
150
+ export default function ProductPreview({spot}) {
211
151
  return (
212
152
  <Box padding={2} style={{minWidth: 200}}>
213
- {value?.product?._ref ? (
214
- renderPreview({
215
- value,
216
- schemaType: productSchemaType,
217
- layout: "default"
218
- })
153
+ {spot?.product?._ref ? (
154
+ <Preview value={{_id: spot.product._ref}} type={schema.get(`product`)} />
219
155
  ) : (
220
- `No reference selected`
156
+ `No Reference Selected`
221
157
  )}
222
158
  </Box>
223
159
  )
@@ -227,28 +163,16 @@ export function ProductPreview({value, renderPreview}) {
227
163
  Then back in your schema definition
228
164
 
229
165
  ```js
166
+ import HotspotArray from 'sanity-plugin-hotspot-array'
167
+ import ProductPreview from '../../components/ProductPreview'
168
+
230
169
  options: {
231
- imageHotspot: {
232
- tooltip: ProductPreview
233
- }
234
- }
170
+ hotspotImagePath: `hotspotImage`,
171
+ hotspotTooltip: ProductPreview,
172
+ },
235
173
  ```
236
174
 
237
175
  ## License
238
176
 
239
- MIT-licensed. See LICENSE.
240
-
241
- ## Develop & test
242
-
243
- This plugin uses [@sanity/plugin-kit](https://github.com/sanity-io/plugin-kit)
244
- with default configuration for build & watch scripts.
245
-
246
- See [Testing a plugin in Sanity Studio](https://github.com/sanity-io/plugin-kit#testing-a-plugin-in-sanity-studio)
247
- on how to run this plugin with hotreload in the studio.
248
-
249
- ### Release new version
250
-
251
- Run ["CI & Release" workflow](https://github.com/sanity-io/sanity-plugin-hotspot-array/actions/workflows/main.yml).
252
- Make sure to select the main branch and check "Release new version".
253
-
254
- Semantic release will only release on configured branches, so it is safe to run release on any branch.
177
+ MIT ©
178
+ See LICENSE
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = Feedback;
7
+ var _react = _interopRequireDefault(require("react"));
8
+ var _ui = require("@sanity/ui");
9
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
10
+ function Feedback(_ref) {
11
+ var children = _ref.children;
12
+ return /*#__PURE__*/_react.default.createElement(_ui.Card, {
13
+ padding: 4,
14
+ radius: 2,
15
+ shadow: 1,
16
+ tone: "caution"
17
+ }, /*#__PURE__*/_react.default.createElement(_ui.Text, null, children));
18
+ }
19
+ //# sourceMappingURL=Feedback.js.map
@@ -0,0 +1 @@
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;AAAqC;AAEtB,SAASA,QAAQ,OAAa;EAAA,IAAXC,QAAQ,QAARA,QAAQ;EACxC,oBACE,6BAAC,QAAI;IAAC,OAAO,EAAE,CAAE;IAAC,MAAM,EAAE,CAAE;IAAC,MAAM,EAAE,CAAE;IAAC,IAAI,EAAC;EAAS,gBACpD,6BAAC,QAAI,QAAEA,QAAQ,CAAQ,CAClB;AAEX"}
@@ -0,0 +1,150 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _client = _interopRequireDefault(require("part:@sanity/base/client"));
8
+ var _formBuilder = require("part:@sanity/form-builder");
9
+ var _assetUtils = require("@sanity/asset-utils");
10
+ var _PatchEvent = require("@sanity/form-builder/PatchEvent");
11
+ var _imageUrl = _interopRequireDefault(require("@sanity/image-url"));
12
+ var _ui = require("@sanity/ui");
13
+ var _content = require("@sanity/util/content");
14
+ var _get = _interopRequireDefault(require("lodash/get"));
15
+ var _react = _interopRequireWildcard(require("react"));
16
+ var _web = require("@react-hookz/web");
17
+ var _Feedback = _interopRequireDefault(require("./Feedback"));
18
+ var _Spot = _interopRequireDefault(require("./Spot"));
19
+ var _useUnsetInputComponent = require("./useUnsetInputComponent");
20
+ var _NestedFormBuilder = require("./NestedFormBuilder");
21
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
22
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
23
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
24
+ function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
25
+ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
26
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
27
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
28
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
29
+ function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
30
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
31
+ var imageStyle = {
32
+ width: "100%",
33
+ height: "auto"
34
+ };
35
+ var VALID_ROOT_PATHS = ['document', 'parent'];
36
+ var HotspotArray = /*#__PURE__*/_react.default.forwardRef((props, ref) => {
37
+ var _type$options, _type$options2, _type$options3;
38
+ console.log(props);
39
+ var type = props.type,
40
+ value = props.value,
41
+ onChange = props.onChange,
42
+ document = props.document;
43
+ var _ref = type !== null && type !== void 0 ? type : {},
44
+ options = _ref.options;
45
+
46
+ // Attempt prevention of infinite loop in <FormBuilderInput />
47
+ // Re-renders can still occur if this Component is used again in a nested field
48
+ var typeWithoutInputComponent = (0, _useUnsetInputComponent.useUnsetInputComponent)(type, type === null || type === void 0 ? void 0 : type.inputComponent);
49
+ var imageHotspotPathRoot = VALID_ROOT_PATHS.includes(options === null || options === void 0 ? void 0 : options.imageHotspotPathRoot) ? props[options.imageHotspotPathRoot] : document;
50
+
51
+ /**
52
+ * Finding the image from the imageHotspotPathRoot (defaults to document),
53
+ * using the path from the hotspot's `options` field
54
+ *
55
+ * when changes in imageHotspotPathRoot (e.g. document) occur,
56
+ * check if there are any changes to the hotspotImage and update the reference
57
+ */
58
+ var hotspotImage = _react.default.useMemo(() => {
59
+ return (0, _get.default)(imageHotspotPathRoot, options === null || options === void 0 ? void 0 : options.hotspotImagePath);
60
+ }, [imageHotspotPathRoot]);
61
+ var displayImage = _react.default.useMemo(() => {
62
+ var _hotspotImage$asset;
63
+ var builder = (0, _imageUrl.default)(_client.default).dataset(_client.default.config().dataset);
64
+ var urlFor = source => builder.image(source);
65
+ if (hotspotImage !== null && hotspotImage !== void 0 && (_hotspotImage$asset = hotspotImage.asset) !== null && _hotspotImage$asset !== void 0 && _hotspotImage$asset._ref) {
66
+ var _getImageDimensions = (0, _assetUtils.getImageDimensions)(hotspotImage.asset._ref),
67
+ aspectRatio = _getImageDimensions.aspectRatio;
68
+ var width = 1200;
69
+ var height = Math.round(width / aspectRatio);
70
+ var url = urlFor(hotspotImage).width(width).url();
71
+ return {
72
+ width,
73
+ height,
74
+ url
75
+ };
76
+ }
77
+ return null;
78
+ }, [hotspotImage]);
79
+ var handleHotspotImageClick = _react.default.useCallback(event => {
80
+ var nativeEvent = event.nativeEvent;
81
+
82
+ // Calculate the x/y percentage of the click position
83
+ var x = Number((nativeEvent.offsetX * 100 / nativeEvent.srcElement.width).toFixed(2));
84
+ var y = Number((nativeEvent.offsetY * 100 / nativeEvent.srcElement.height).toFixed(2));
85
+ var description = "New Hotspot at ".concat(x, "% x ").concat(y, "%");
86
+ var newRow = {
87
+ _key: (0, _content.randomKey)(12),
88
+ _type: "spot",
89
+ x,
90
+ y
91
+ };
92
+ if (options !== null && options !== void 0 && options.hotspotDescriptionPath) {
93
+ newRow[options.hotspotDescriptionPath] = description;
94
+ }
95
+ onChange(_PatchEvent.PatchEvent.from((0, _PatchEvent.setIfMissing)([]), (0, _PatchEvent.insert)([newRow], 'after', [-1])));
96
+ }, []);
97
+ var handleHotspotMove = _react.default.useCallback((key, x, y) => {
98
+ onChange(_PatchEvent.PatchEvent.from(
99
+ // Set the `x` value of this array key item
100
+ (0, _PatchEvent.set)(x, [{
101
+ _key: key
102
+ }, 'x']),
103
+ // Set the `y` value of this array key item
104
+ (0, _PatchEvent.set)(y, [{
105
+ _key: key
106
+ }, 'y'])));
107
+ }, [value]);
108
+ var hotspotImageRef = _react.default.useRef(null);
109
+ var _useState = (0, _react.useState)(),
110
+ _useState2 = _slicedToArray(_useState, 2),
111
+ imageRect = _useState2[0],
112
+ setImageRect = _useState2[1];
113
+ var updateImageRectCallback = (0, _web.useDebouncedCallback)(e => setImageRect(e.contentRect), [setImageRect], 200);
114
+ (0, _web.useResizeObserver)(hotspotImageRef, updateImageRectCallback);
115
+ return /*#__PURE__*/_react.default.createElement(_ui.Stack, {
116
+ space: [2, 2, 3]
117
+ }, displayImage !== null && displayImage !== void 0 && displayImage.url ? /*#__PURE__*/_react.default.createElement("div", {
118
+ style: {
119
+ position: "relative"
120
+ }
121
+ }, imageRect && (value === null || value === void 0 ? void 0 : value.length) > 0 && value.map((spot, index) => /*#__PURE__*/_react.default.createElement(_Spot.default, {
122
+ index: index,
123
+ key: spot._key,
124
+ spot: spot,
125
+ bounds: imageRect,
126
+ update: handleHotspotMove,
127
+ hotspotDescriptionPath: options === null || options === void 0 ? void 0 : options.hotspotDescriptionPath,
128
+ tooltip: options === null || options === void 0 ? void 0 : options.hotspotTooltip
129
+ })), /*#__PURE__*/_react.default.createElement(_ui.Card, {
130
+ __unstable_checkered: true,
131
+ shadow: 1
132
+ }, /*#__PURE__*/_react.default.createElement(_ui.Flex, {
133
+ align: "center",
134
+ justify: "center"
135
+ }, /*#__PURE__*/_react.default.createElement("img", {
136
+ ref: hotspotImageRef,
137
+ src: displayImage.url,
138
+ width: displayImage.width,
139
+ height: displayImage.height,
140
+ alt: "",
141
+ style: imageStyle,
142
+ onClick: handleHotspotImageClick
143
+ })))) : /*#__PURE__*/_react.default.createElement(_Feedback.default, null, type !== null && type !== void 0 && (_type$options = type.options) !== null && _type$options !== void 0 && _type$options.hotspotImagePath ? /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, "No Hotspot image found at path ", /*#__PURE__*/_react.default.createElement("code", null, type === null || type === void 0 ? void 0 : (_type$options2 = type.options) === null || _type$options2 === void 0 ? void 0 : _type$options2.hotspotImagePath)) : /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, "Define a path in this field using to the image field in this document at", ' ', /*#__PURE__*/_react.default.createElement("code", null, "options.hotspotImagePath"))), (type === null || type === void 0 ? void 0 : (_type$options3 = type.options) === null || _type$options3 === void 0 ? void 0 : _type$options3.imageHotspotPathRoot) && !VALID_ROOT_PATHS.includes(type.options.imageHotspotPathRoot) && /*#__PURE__*/_react.default.createElement(_Feedback.default, null, "The supplied imageHotspotPathRoot \"", type.options.imageHotspotPathRoot, "\" is not valid, falling back to \"document\". Available values are \"", VALID_ROOT_PATHS.join(', '), "\"."), /*#__PURE__*/_react.default.createElement(_NestedFormBuilder.NestedFormBuilder, _extends({}, props, {
144
+ type: typeWithoutInputComponent,
145
+ ref: ref
146
+ })));
147
+ });
148
+ var _default = (0, _formBuilder.withParent)((0, _formBuilder.withDocument)(HotspotArray));
149
+ exports.default = _default;
150
+ //# sourceMappingURL=HotspotArray.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HotspotArray.js","names":["imageStyle","width","height","VALID_ROOT_PATHS","HotspotArray","React","forwardRef","props","ref","console","log","type","value","onChange","document","options","typeWithoutInputComponent","useUnsetInputComponent","inputComponent","imageHotspotPathRoot","includes","hotspotImage","useMemo","get","hotspotImagePath","displayImage","builder","imageUrlBuilder","sanityClient","dataset","config","urlFor","source","image","asset","_ref","getImageDimensions","aspectRatio","Math","round","url","handleHotspotImageClick","useCallback","event","nativeEvent","x","Number","offsetX","srcElement","toFixed","y","offsetY","description","newRow","_key","randomKey","_type","hotspotDescriptionPath","PatchEvent","from","setIfMissing","insert","handleHotspotMove","key","set","hotspotImageRef","useRef","useState","imageRect","setImageRect","updateImageRectCallback","useDebouncedCallback","e","contentRect","useResizeObserver","position","length","map","spot","index","hotspotTooltip","join","withParent","withDocument"],"sources":["../src/HotspotArray.tsx"],"sourcesContent":["/* eslint-disable react/display-name */\n\n// @ts-ignore\nimport sanityClient from 'part:@sanity/base/client'\n// @ts-ignore\nimport {withDocument, withParent} from 'part:@sanity/form-builder'\n\nimport {getImageDimensions} from '@sanity/asset-utils'\nimport {insert, PatchEvent, set, setIfMissing} from '@sanity/form-builder/PatchEvent'\nimport imageUrlBuilder from '@sanity/image-url'\nimport {Card, Flex, Stack} from '@sanity/ui'\nimport {randomKey} from '@sanity/util/content'\nimport get from 'lodash/get'\nimport React, {useState} from 'react'\n\nimport {IUseResizeObserverCallback, useDebouncedCallback, useResizeObserver} from '@react-hookz/web'\nimport Feedback from './Feedback'\nimport Spot from './Spot'\nimport {useUnsetInputComponent} from './useUnsetInputComponent'\nimport { NestedFormBuilder } from './NestedFormBuilder'\n\nconst imageStyle = {width: `100%`, height: `auto`}\n\nconst VALID_ROOT_PATHS = ['document', 'parent']\n\nexport type FnHotspotMove = (key: string, x: number, y: number) => void\n\nexport type TSpot = {\n _key: string\n _type: `spot`\n x: number\n y: number\n} & {[key: string]: unknown}\n\nconst HotspotArray = React.forwardRef((props: any, ref) => {\n console.log(props);\n const {type, value, onChange, document} = props\n const {options} = type ?? {}\n\n // Attempt prevention of infinite loop in <FormBuilderInput />\n // Re-renders can still occur if this Component is used again in a nested field\n const typeWithoutInputComponent = useUnsetInputComponent(type, type?.inputComponent)\n const imageHotspotPathRoot = VALID_ROOT_PATHS.includes(options?.imageHotspotPathRoot)\n ? props[options.imageHotspotPathRoot]\n : document\n\n /**\n * Finding the image from the imageHotspotPathRoot (defaults to document),\n * using the path from the hotspot's `options` field\n *\n * when changes in imageHotspotPathRoot (e.g. document) occur,\n * check if there are any changes to the hotspotImage and update the reference\n */\n const hotspotImage = React.useMemo(() => {\n return get(imageHotspotPathRoot, options?.hotspotImagePath)\n }, [imageHotspotPathRoot])\n\n const displayImage = React.useMemo(() => {\n const builder = imageUrlBuilder(sanityClient).dataset(sanityClient.config().dataset)\n const urlFor = (source) => builder.image(source)\n\n if (hotspotImage?.asset?._ref) {\n const {aspectRatio} = getImageDimensions(hotspotImage.asset._ref)\n const width = 1200\n const height = Math.round(width / aspectRatio)\n const url = urlFor(hotspotImage).width(width).url()\n\n return {width, height, url}\n }\n\n return null\n }, [hotspotImage])\n\n const handleHotspotImageClick = React.useCallback((event) => {\n const {nativeEvent} = event\n\n // Calculate the x/y percentage of the click position\n const x = Number(((nativeEvent.offsetX * 100) / nativeEvent.srcElement.width).toFixed(2))\n const y = Number(((nativeEvent.offsetY * 100) / nativeEvent.srcElement.height).toFixed(2))\n const description = `New Hotspot at ${x}% x ${y}%`\n\n const newRow: TSpot = {\n _key: randomKey(12),\n _type: `spot`,\n x,\n y,\n }\n\n if (options?.hotspotDescriptionPath) {\n newRow[options.hotspotDescriptionPath] = description\n }\n\n onChange(PatchEvent.from(setIfMissing([]), insert([newRow], 'after', [-1])))\n }, [])\n\n const handleHotspotMove: FnHotspotMove = React.useCallback(\n (key, x, y) => {\n onChange(\n PatchEvent.from(\n // Set the `x` value of this array key item\n set(x, [{_key: key}, 'x']),\n // Set the `y` value of this array key item\n set(y, [{_key: key}, 'y'])\n )\n )\n },\n [value]\n )\n\n const hotspotImageRef = React.useRef<HTMLImageElement | null>(null)\n\n const [imageRect, setImageRect] = useState<DOMRectReadOnly>()\n const updateImageRectCallback = useDebouncedCallback(\n ((e) => setImageRect(e.contentRect)) as IUseResizeObserverCallback,\n [setImageRect],\n 200\n )\n useResizeObserver(hotspotImageRef, updateImageRectCallback)\n\n return (\n <Stack space={[2, 2, 3]}>\n {displayImage?.url ? (\n <div style={{position: `relative`}}>\n {imageRect &&\n value?.length > 0 &&\n value.map((spot, index) => (\n <Spot\n index={index}\n key={spot._key}\n spot={spot}\n bounds={imageRect}\n update={handleHotspotMove}\n hotspotDescriptionPath={options?.hotspotDescriptionPath}\n tooltip={options?.hotspotTooltip}\n />\n ))}\n\n <Card __unstable_checkered shadow={1}>\n <Flex align=\"center\" justify=\"center\">\n <img\n ref={hotspotImageRef}\n src={displayImage.url}\n width={displayImage.width}\n height={displayImage.height}\n alt=\"\"\n style={imageStyle}\n onClick={handleHotspotImageClick}\n />\n </Flex>\n </Card>\n </div>\n ) : (\n <Feedback>\n {type?.options?.hotspotImagePath ? (\n <>\n No Hotspot image found at path <code>{type?.options?.hotspotImagePath}</code>\n </>\n ) : (\n <>\n Define a path in this field using to the image field in this document at{' '}\n <code>options.hotspotImagePath</code>\n </>\n )}\n </Feedback>\n )}\n {type?.options?.imageHotspotPathRoot &&\n !VALID_ROOT_PATHS.includes(type.options.imageHotspotPathRoot) && (\n <Feedback>\n The supplied imageHotspotPathRoot \"{type.options.imageHotspotPathRoot}\" is not valid,\n falling back to \"document\". Available values are \"{VALID_ROOT_PATHS.join(', ')}\".\n </Feedback>\n )}\n <NestedFormBuilder {...props} type={typeWithoutInputComponent} ref={ref} />\n </Stack>\n )\n})\n\nexport default withParent(withDocument(HotspotArray))\n"],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.NestedFormBuilder = void 0;
7
+ var _react = _interopRequireDefault(require("react"));
8
+ var _FormBuilderInput = require("@sanity/form-builder/lib/FormBuilderInput");
9
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
10
+ function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
11
+ /**
12
+ * Nesting FormBuilderInput components results in inconsistent focus & tab-index behaviour.
13
+ *
14
+ * FormBuilderInputs requests focus if props.focusPath matches the input.focusPath
15
+ * when mounted and when props change. If multiple components "handle" the same focus path,
16
+ * there is a race-condition on which component will receive the focus, often resulting
17
+ * in seemingly random scrollbehaviour.
18
+ *
19
+ * This is a workaround, reusing as much of FormBuilderInput as possible.
20
+ *
21
+ * Use FormBuilderInput when you need to render a field obtained from a SchemaType (type.fields or type.fieldset[].field).
22
+ *
23
+ * Use NestedFormBuilder for decorator components that are used as inputComponent or in input-resolver.ts.
24
+ *
25
+ * Decorator components are components that just want to modify a type, add some markup or so on,
26
+ * then delegate back to Sanity to obtain an actual input implementation.
27
+ *
28
+ * FormBuilderInput should only be used as the outermost component when resolving
29
+ * inputs recursively.
30
+ */
31
+
32
+ class NestedFormBuilder extends _FormBuilderInput.FormBuilderInput {
33
+ componentDidMount() {
34
+ // do nothing - prevent focus-bug when nesting FormBuilderInput
35
+ }
36
+
37
+ // eslint-disable-next-line camelcase
38
+ UNSAFE_componentWillReceiveProps() {
39
+ // do nothing - prevent focus-bug when nesting FormBuilderInput
40
+ }
41
+ componentDidUpdate() {
42
+ // do nothing - prevent focus-bug when nesting FormBuilderInput
43
+ }
44
+ render() {
45
+ var type = this.props.type;
46
+ var InputComponent = this.resolveInputComponent(type);
47
+ return /*#__PURE__*/_react.default.createElement(InputComponent, _extends({}, this.props, {
48
+ ref: this.setInput
49
+ }));
50
+ }
51
+ }
52
+ exports.NestedFormBuilder = NestedFormBuilder;
53
+ //# sourceMappingURL=NestedFormBuilder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NestedFormBuilder.js","names":["NestedFormBuilder","FormBuilderInput","componentDidMount","UNSAFE_componentWillReceiveProps","componentDidUpdate","render","type","props","InputComponent","resolveInputComponent","setInput"],"sources":["../src/NestedFormBuilder.tsx"],"sourcesContent":["import React from 'react';\nimport { FormBuilderInput } from '@sanity/form-builder/lib/FormBuilderInput';\n\n/**\n * Nesting FormBuilderInput components results in inconsistent focus & tab-index behaviour.\n *\n * FormBuilderInputs requests focus if props.focusPath matches the input.focusPath\n * when mounted and when props change. If multiple components \"handle\" the same focus path,\n * there is a race-condition on which component will receive the focus, often resulting\n * in seemingly random scrollbehaviour.\n *\n * This is a workaround, reusing as much of FormBuilderInput as possible.\n *\n * Use FormBuilderInput when you need to render a field obtained from a SchemaType (type.fields or type.fieldset[].field).\n *\n * Use NestedFormBuilder for decorator components that are used as inputComponent or in input-resolver.ts.\n *\n * Decorator components are components that just want to modify a type, add some markup or so on,\n * then delegate back to Sanity to obtain an actual input implementation.\n *\n * FormBuilderInput should only be used as the outermost component when resolving\n * inputs recursively.\n */\n\nexport class NestedFormBuilder extends FormBuilderInput {\n componentDidMount() {\n // do nothing - prevent focus-bug when nesting FormBuilderInput\n }\n \n // eslint-disable-next-line camelcase\n UNSAFE_componentWillReceiveProps() {\n // do nothing - prevent focus-bug when nesting FormBuilderInput\n }\n \n componentDidUpdate() {\n // do nothing - prevent focus-bug when nesting FormBuilderInput\n }\n \n render(): JSX.Element {\n const { type } = this.props;\n const InputComponent = this.resolveInputComponent(type);\n return <InputComponent {...this.props} ref={this.setInput} />;\n }\n }"],"mappings":";;;;;;AAAA;AACA;AAA6E;AAAA;AAE7E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEO,MAAMA,iBAAiB,SAASC,kCAAgB,CAAC;EACpDC,iBAAiB,GAAG;IAClB;EACF;;EAEA;EACAC,gCAAgC,GAAG;IACjC;EACF;EAEAC,kBAAkB,GAAG;IACnB;EACF;EAEAC,MAAM,GAAgB;IACpB,IAAQC,IAAI,GAAK,IAAI,CAACC,KAAK,CAAnBD,IAAI;IACZ,IAAME,cAAc,GAAG,IAAI,CAACC,qBAAqB,CAACH,IAAI,CAAC;IACvD,oBAAO,6BAAC,cAAc,eAAK,IAAI,CAACC,KAAK;MAAE,GAAG,EAAE,IAAI,CAACG;IAAS,GAAG;EAC/D;AACF;AAAC"}