sanity-plugin-hotspot-array 0.0.8 → 0.0.10

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2021 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
@@ -30,7 +30,8 @@ export default {
30
30
  // see `Spot object` setup below
31
31
  ],
32
32
  options: {
33
- // see `Image and description path` setup below
33
+ // see `Image and description paths` setup below
34
+ imageHotspotPathRoot: `document`,
34
35
  hotspotImagePath: `featureImage`,
35
36
  hotspotDescriptionPath: `details`,
36
37
  // see `Custom tooltip` setup below
@@ -51,9 +52,9 @@ The plugin makes a number of assumptions to add and update data in the array. In
51
52
 
52
53
  ### Image and description paths
53
54
 
54
- 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.
55
+ 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.
55
56
 
56
- 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:
57
+ 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:
57
58
 
58
59
  ```js
59
60
  options: {
@@ -61,6 +62,17 @@ options: {
61
62
  }
62
63
  ```
63
64
 
65
+ 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`.
66
+
67
+ In this case, if the image is uploaded to the parent object field of `featuredImage`, your fields `options` would look like:
68
+
69
+ ```js
70
+ options: {
71
+ imageHotspotPathRoot: `parent`,
72
+ hotspotImagePath: `featureImage`
73
+ }
74
+ ```
75
+
64
76
  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.
65
77
 
66
78
  ```js
@@ -152,5 +164,5 @@ options: {
152
164
 
153
165
  ## License
154
166
 
155
- MIT © Simeon Griggs
167
+ MIT ©
156
168
  See LICENSE
package/lib/Feedback.js CHANGED
@@ -4,13 +4,9 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = Feedback;
7
-
8
7
  var _react = _interopRequireDefault(require("react"));
9
-
10
8
  var _ui = require("@sanity/ui");
11
-
12
9
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
-
14
10
  function Feedback(_ref) {
15
11
  var children = _ref.children;
16
12
  return /*#__PURE__*/_react.default.createElement(_ui.Card, {
@@ -1 +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;;;;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"}
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"}
@@ -4,76 +4,50 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
-
8
7
  var _client = _interopRequireDefault(require("part:@sanity/base/client"));
9
-
10
8
  var _formBuilder = require("part:@sanity/form-builder");
11
-
12
9
  var _assetUtils = require("@sanity/asset-utils");
13
-
14
- var _FormBuilderInput = require("@sanity/form-builder/lib/FormBuilderInput");
15
-
16
10
  var _PatchEvent = require("@sanity/form-builder/PatchEvent");
17
-
18
11
  var _imageUrl = _interopRequireDefault(require("@sanity/image-url"));
19
-
20
12
  var _ui = require("@sanity/ui");
21
-
22
13
  var _content = require("@sanity/util/content");
23
-
24
14
  var _get = _interopRequireDefault(require("lodash/get"));
25
-
26
15
  var _react = _interopRequireWildcard(require("react"));
27
-
28
16
  var _web = require("@react-hookz/web");
29
-
30
17
  var _Feedback = _interopRequireDefault(require("./Feedback"));
31
-
32
18
  var _Spot = _interopRequireDefault(require("./Spot"));
33
-
34
19
  var _useUnsetInputComponent = require("./useUnsetInputComponent");
35
-
20
+ var _NestedFormBuilder = require("./NestedFormBuilder");
36
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); }
37
-
38
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; }
39
-
40
23
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
41
-
42
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); }
43
-
44
25
  function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
45
-
46
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."); }
47
-
48
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); }
49
-
50
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; }
51
-
52
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; }
53
-
54
30
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
55
-
56
31
  var imageStyle = {
57
32
  width: "100%",
58
33
  height: "auto"
59
34
  };
60
35
  var VALID_ROOT_PATHS = ['document', 'parent'];
61
-
62
36
  var HotspotArray = /*#__PURE__*/_react.default.forwardRef((props, ref) => {
63
37
  var _type$options, _type$options2, _type$options3;
64
-
38
+ console.log(props);
65
39
  var type = props.type,
66
- value = props.value,
67
- onChange = props.onChange,
68
- document = props.document;
69
-
40
+ value = props.value,
41
+ onChange = props.onChange,
42
+ document = props.document;
70
43
  var _ref = type !== null && type !== void 0 ? type : {},
71
- options = _ref.options; // Attempt prevention of infinite loop in <FormBuilderInput />
72
- // Re-renders can still occur if this Component is used again in a nested field
73
-
44
+ options = _ref.options;
74
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
75
48
  var typeWithoutInputComponent = (0, _useUnsetInputComponent.useUnsetInputComponent)(type, type === null || type === void 0 ? void 0 : type.inputComponent);
76
49
  var imageHotspotPathRoot = VALID_ROOT_PATHS.includes(options === null || options === void 0 ? void 0 : options.imageHotspotPathRoot) ? props[options.imageHotspotPathRoot] : document;
50
+
77
51
  /**
78
52
  * Finding the image from the imageHotspotPathRoot (defaults to document),
79
53
  * using the path from the hotspot's `options` field
@@ -81,22 +55,16 @@ var HotspotArray = /*#__PURE__*/_react.default.forwardRef((props, ref) => {
81
55
  * when changes in imageHotspotPathRoot (e.g. document) occur,
82
56
  * check if there are any changes to the hotspotImage and update the reference
83
57
  */
84
-
85
58
  var hotspotImage = _react.default.useMemo(() => {
86
59
  return (0, _get.default)(imageHotspotPathRoot, options === null || options === void 0 ? void 0 : options.hotspotImagePath);
87
60
  }, [imageHotspotPathRoot]);
88
-
89
61
  var displayImage = _react.default.useMemo(() => {
90
62
  var _hotspotImage$asset;
91
-
92
63
  var builder = (0, _imageUrl.default)(_client.default).dataset(_client.default.config().dataset);
93
-
94
64
  var urlFor = source => builder.image(source);
95
-
96
65
  if (hotspotImage !== null && hotspotImage !== void 0 && (_hotspotImage$asset = hotspotImage.asset) !== null && _hotspotImage$asset !== void 0 && _hotspotImage$asset._ref) {
97
66
  var _getImageDimensions = (0, _assetUtils.getImageDimensions)(hotspotImage.asset._ref),
98
- aspectRatio = _getImageDimensions.aspectRatio;
99
-
67
+ aspectRatio = _getImageDimensions.aspectRatio;
100
68
  var width = 1200;
101
69
  var height = Math.round(width / aspectRatio);
102
70
  var url = urlFor(hotspotImage).width(width).url();
@@ -106,13 +74,12 @@ var HotspotArray = /*#__PURE__*/_react.default.forwardRef((props, ref) => {
106
74
  url
107
75
  };
108
76
  }
109
-
110
77
  return null;
111
78
  }, [hotspotImage]);
112
-
113
79
  var handleHotspotImageClick = _react.default.useCallback(event => {
114
- var nativeEvent = event.nativeEvent; // Calculate the x/y percentage of the click position
80
+ var nativeEvent = event.nativeEvent;
115
81
 
82
+ // Calculate the x/y percentage of the click position
116
83
  var x = Number((nativeEvent.offsetX * 100 / nativeEvent.srcElement.width).toFixed(2));
117
84
  var y = Number((nativeEvent.offsetY * 100 / nativeEvent.srcElement.height).toFixed(2));
118
85
  var description = "New Hotspot at ".concat(x, "% x ").concat(y, "%");
@@ -122,31 +89,27 @@ var HotspotArray = /*#__PURE__*/_react.default.forwardRef((props, ref) => {
122
89
  x,
123
90
  y
124
91
  };
125
-
126
92
  if (options !== null && options !== void 0 && options.hotspotDescriptionPath) {
127
93
  newRow[options.hotspotDescriptionPath] = description;
128
94
  }
129
-
130
95
  onChange(_PatchEvent.PatchEvent.from((0, _PatchEvent.setIfMissing)([]), (0, _PatchEvent.insert)([newRow], 'after', [-1])));
131
96
  }, []);
132
-
133
97
  var handleHotspotMove = _react.default.useCallback((key, x, y) => {
134
- onChange(_PatchEvent.PatchEvent.from( // Set the `x` value of this array key item
98
+ onChange(_PatchEvent.PatchEvent.from(
99
+ // Set the `x` value of this array key item
135
100
  (0, _PatchEvent.set)(x, [{
136
101
  _key: key
137
- }, 'x']), // Set the `y` value of this array key item
102
+ }, 'x']),
103
+ // Set the `y` value of this array key item
138
104
  (0, _PatchEvent.set)(y, [{
139
105
  _key: key
140
106
  }, 'y'])));
141
107
  }, [value]);
142
-
143
108
  var hotspotImageRef = _react.default.useRef(null);
144
-
145
109
  var _useState = (0, _react.useState)(),
146
- _useState2 = _slicedToArray(_useState, 2),
147
- imageRect = _useState2[0],
148
- setImageRect = _useState2[1];
149
-
110
+ _useState2 = _slicedToArray(_useState, 2),
111
+ imageRect = _useState2[0],
112
+ setImageRect = _useState2[1];
150
113
  var updateImageRectCallback = (0, _web.useDebouncedCallback)(e => setImageRect(e.contentRect), [setImageRect], 200);
151
114
  (0, _web.useResizeObserver)(hotspotImageRef, updateImageRectCallback);
152
115
  return /*#__PURE__*/_react.default.createElement(_ui.Stack, {
@@ -177,13 +140,11 @@ var HotspotArray = /*#__PURE__*/_react.default.forwardRef((props, ref) => {
177
140
  alt: "",
178
141
  style: imageStyle,
179
142
  onClick: handleHotspotImageClick
180
- })))) : /*#__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(_FormBuilderInput.FormBuilderInput, _extends({}, props, {
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, {
181
144
  type: typeWithoutInputComponent,
182
145
  ref: ref
183
146
  })));
184
147
  });
185
-
186
- var _default = (0, _formBuilder.withDocument)(HotspotArray);
187
-
148
+ var _default = (0, _formBuilder.withParent)((0, _formBuilder.withDocument)(HotspotArray));
188
149
  exports.default = _default;
189
150
  //# sourceMappingURL=HotspotArray.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"HotspotArray.js","names":["imageStyle","width","height","VALID_ROOT_PATHS","HotspotArray","React","forwardRef","props","ref","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","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} from 'part:@sanity/form-builder'\n\nimport {getImageDimensions} from '@sanity/asset-utils'\nimport {FormBuilderInput} from '@sanity/form-builder/lib/FormBuilderInput'\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'\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 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 <FormBuilderInput {...props} type={typeWithoutInputComponent} ref={ref} />\n </Stack>\n )\n})\n\nexport default withDocument(HotspotArray)\n"],"mappings":"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"}
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"}
package/lib/Spot.js CHANGED
@@ -4,39 +4,22 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = Spot;
7
-
8
7
  var _ui = require("@sanity/ui");
9
-
10
8
  var _framerMotion = require("framer-motion");
11
-
12
9
  var _get = _interopRequireDefault(require("lodash/get"));
13
-
14
10
  var _react = _interopRequireWildcard(require("react"));
15
-
16
11
  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); }
17
-
18
12
  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; }
19
-
20
13
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
21
-
22
14
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
23
-
24
15
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
25
-
26
16
  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
27
-
28
17
  function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
29
-
30
18
  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."); }
31
-
32
19
  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); }
33
-
34
20
  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; }
35
-
36
21
  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; }
37
-
38
22
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
39
-
40
23
  var dragStyle = {
41
24
  width: '1.4rem',
42
25
  height: '1.4rem',
@@ -87,63 +70,56 @@ var labelStyle = {
87
70
  var labelStyleWhileActive = {
88
71
  visibility: 'hidden'
89
72
  };
90
-
91
73
  var round = num => Math.round(num * 100) / 100;
92
-
93
74
  function Spot(_ref) {
94
75
  var spot = _ref.spot,
95
- bounds = _ref.bounds,
96
- update = _ref.update,
97
- hotspotDescriptionPath = _ref.hotspotDescriptionPath,
98
- tooltip = _ref.tooltip,
99
- index = _ref.index;
100
-
76
+ bounds = _ref.bounds,
77
+ update = _ref.update,
78
+ hotspotDescriptionPath = _ref.hotspotDescriptionPath,
79
+ tooltip = _ref.tooltip,
80
+ index = _ref.index;
101
81
  var _React$useState = _react.default.useState(false),
102
- _React$useState2 = _slicedToArray(_React$useState, 2),
103
- isDragging = _React$useState2[0],
104
- setIsDragging = _React$useState2[1];
105
-
82
+ _React$useState2 = _slicedToArray(_React$useState, 2),
83
+ isDragging = _React$useState2[0],
84
+ setIsDragging = _React$useState2[1];
106
85
  var _React$useState3 = _react.default.useState(false),
107
- _React$useState4 = _slicedToArray(_React$useState3, 2),
108
- isHovering = _React$useState4[0],
109
- setIsHovering = _React$useState4[1]; // x/y are stored as % but need to be converted to px
110
-
86
+ _React$useState4 = _slicedToArray(_React$useState3, 2),
87
+ isHovering = _React$useState4[0],
88
+ setIsHovering = _React$useState4[1];
111
89
 
90
+ // x/y are stored as % but need to be converted to px
112
91
  var x = (0, _framerMotion.useMotionValue)(round(bounds.width * (spot.x / 100)));
113
92
  var y = (0, _framerMotion.useMotionValue)(round(bounds.height * (spot.y / 100)));
93
+
114
94
  /**
115
95
  * update x/y if the bounds change when resizing the window
116
96
  */
117
-
118
97
  (0, _react.useEffect)(() => {
119
98
  x.set(round(bounds.width * (spot.x / 100)));
120
99
  y.set(round(bounds.height * (spot.y / 100)));
121
100
  }, [bounds]);
122
-
123
101
  var handleDragEnd = _react.default.useCallback(() => {
124
- setIsDragging(false); // get current values for x/y in px
102
+ setIsDragging(false);
125
103
 
104
+ // get current values for x/y in px
126
105
  var currentX = x.get();
127
- var currentY = y.get(); // Which we need to convert back to `%` to patch the document
106
+ var currentY = y.get();
128
107
 
108
+ // Which we need to convert back to `%` to patch the document
129
109
  var newX = round(currentX * 100 / bounds.width);
130
- var newY = round(currentY * 100 / bounds.height); // Don't go below 0 or above 100
110
+ var newY = round(currentY * 100 / bounds.height);
131
111
 
112
+ // Don't go below 0 or above 100
132
113
  var safeX = Math.max(0, Math.min(100, newX));
133
114
  var safeY = Math.max(0, Math.min(100, newY));
134
115
  update(spot._key, safeX, safeY);
135
116
  }, [spot]);
136
-
137
117
  var handleDragStart = _react.default.useCallback(() => setIsDragging(true), []);
138
-
139
118
  var handleHoverStart = _react.default.useCallback(() => setIsHovering(true), []);
140
-
141
119
  var handleHoverEnd = _react.default.useCallback(() => setIsHovering(false), []);
142
-
143
120
  if (!x || !y) {
144
121
  return null;
145
122
  }
146
-
147
123
  return /*#__PURE__*/_react.default.createElement(_ui.Tooltip, {
148
124
  key: spot._key,
149
125
  disabled: isDragging,
package/lib/Spot.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Spot.js","names":["dragStyle","width","height","position","boxSizing","top","left","margin","cursor","display","justifyContent","alignItems","borderRadius","background","color","dragStyleWhileDrag","border","dragStyleWhileHover","dotStyle","visibility","pointerEvents","dotStyleWhileActive","labelStyle","fontSize","fontWeight","lineHeight","labelStyleWhileActive","round","num","Math","Spot","spot","bounds","update","hotspotDescriptionPath","tooltip","index","React","useState","isDragging","setIsDragging","isHovering","setIsHovering","x","useMotionValue","y","useEffect","set","handleDragEnd","useCallback","currentX","get","currentY","newX","newY","safeX","max","min","safeY","_key","handleDragStart","handleHoverStart","handleHoverEnd","createElement","maxWidth"],"sources":["../src/Spot.tsx"],"sourcesContent":["import {Box, Text, Tooltip} from '@sanity/ui'\nimport {motion, useMotionValue} from 'framer-motion'\nimport get from 'lodash/get'\nimport React, {CSSProperties, ReactElement, useEffect} from 'react'\nimport {FnHotspotMove, TSpot} from './HotspotArray'\n\nconst dragStyle: CSSProperties = {\n width: '1.4rem',\n height: '1.4rem',\n position: 'absolute',\n boxSizing: 'border-box',\n top: 0,\n left: 0,\n margin: '-0.7rem 0 0 -0.7rem',\n cursor: 'pointer',\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n borderRadius: '50%',\n background: '#000',\n color: 'white',\n}\n\nconst dragStyleWhileDrag: CSSProperties = {\n background: 'rgba(0, 0, 0, 0.1)',\n border: '1px solid #fff',\n cursor: 'none',\n}\n\nconst dragStyleWhileHover: CSSProperties = {\n background: 'rgba(0, 0, 0, 0.1)',\n border: '1px solid #fff',\n}\n\nconst dotStyle: CSSProperties = {\n position: 'absolute',\n left: '50%',\n top: '50%',\n height: '0.2rem',\n width: '0.2rem',\n margin: '-0.1rem 0 0 -0.1rem',\n background: '#fff',\n visibility: 'hidden',\n borderRadius: '50%',\n // make sure pointer events only run on the parent\n pointerEvents: 'none',\n}\n\nconst dotStyleWhileActive: CSSProperties = {\n visibility: 'visible',\n}\n\nconst labelStyle: CSSProperties = {\n color: 'white',\n fontSize: '0.7rem',\n fontWeight: 600,\n lineHeight: '1',\n}\n\nconst labelStyleWhileActive: CSSProperties = {\n visibility: 'hidden',\n}\n\nconst round = (num) => Math.round(num * 100) / 100\n\ninterface IHotspot {\n spot: TSpot\n bounds: DOMRectReadOnly\n update: FnHotspotMove\n hotspotDescriptionPath?: string\n tooltip?: ReactElement\n index: number\n}\n\nexport default function Spot({\n spot,\n bounds,\n update,\n hotspotDescriptionPath,\n tooltip,\n index,\n}: IHotspot) {\n const [isDragging, setIsDragging] = React.useState(false)\n const [isHovering, setIsHovering] = React.useState(false)\n\n // x/y are stored as % but need to be converted to px\n const x = useMotionValue(round(bounds.width * (spot.x / 100)))\n const y = useMotionValue(round(bounds.height * (spot.y / 100)))\n\n /**\n * update x/y if the bounds change when resizing the window\n */\n useEffect(() => {\n x.set(round(bounds.width * (spot.x / 100)))\n y.set(round(bounds.height * (spot.y / 100)))\n }, [bounds])\n\n const handleDragEnd = React.useCallback(() => {\n setIsDragging(false)\n\n // get current values for x/y in px\n const currentX = x.get()\n const currentY = y.get()\n\n // Which we need to convert back to `%` to patch the document\n const newX = round((currentX * 100) / bounds.width)\n const newY = round((currentY * 100) / bounds.height)\n\n // Don't go below 0 or above 100\n const safeX = Math.max(0, Math.min(100, newX))\n const safeY = Math.max(0, Math.min(100, newY))\n\n update(spot._key, safeX, safeY)\n }, [spot])\n const handleDragStart = React.useCallback(() => setIsDragging(true), [])\n\n const handleHoverStart = React.useCallback(() => setIsHovering(true), [])\n const handleHoverEnd = React.useCallback(() => setIsHovering(false), [])\n\n if (!x || !y) {\n return null\n }\n\n return (\n <Tooltip\n key={spot._key}\n disabled={isDragging}\n portal\n content={\n tooltip && typeof tooltip === 'function' ? (\n React.createElement(tooltip, {spot})\n ) : (\n <Box padding={2} style={{maxWidth: 200, pointerEvents: `none`}}>\n <Text textOverflow=\"ellipsis\">\n {hotspotDescriptionPath\n ? (get(spot, hotspotDescriptionPath) as string)\n : `${spot.x}% x ${spot.y}%`}\n </Text>\n </Box>\n )\n }\n >\n <motion.div\n drag\n dragConstraints={bounds}\n dragElastic={0}\n dragMomentum={false}\n onDragEnd={handleDragEnd}\n onDragStart={handleDragStart}\n onHoverStart={handleHoverStart}\n onHoverEnd={handleHoverEnd}\n style={{\n ...dragStyle,\n x,\n y,\n ...(isDragging && {...dragStyleWhileDrag}),\n ...(isHovering && {...dragStyleWhileHover}),\n }}\n >\n {/* Dot */}\n <Box\n style={{\n ...dotStyle,\n ...((isDragging || isHovering) && {...dotStyleWhileActive}),\n }}\n />\n {/* Label */}\n <div\n style={{\n ...labelStyle,\n ...((isDragging || isHovering) && {...labelStyleWhileActive}),\n }}\n >\n {index + 1}\n </div>\n </motion.div>\n </Tooltip>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"Spot.js","names":["dragStyle","width","height","position","boxSizing","top","left","margin","cursor","display","justifyContent","alignItems","borderRadius","background","color","dragStyleWhileDrag","border","dragStyleWhileHover","dotStyle","visibility","pointerEvents","dotStyleWhileActive","labelStyle","fontSize","fontWeight","lineHeight","labelStyleWhileActive","round","num","Math","Spot","spot","bounds","update","hotspotDescriptionPath","tooltip","index","React","useState","isDragging","setIsDragging","isHovering","setIsHovering","x","useMotionValue","y","useEffect","set","handleDragEnd","useCallback","currentX","get","currentY","newX","newY","safeX","max","min","safeY","_key","handleDragStart","handleHoverStart","handleHoverEnd","createElement","maxWidth"],"sources":["../src/Spot.tsx"],"sourcesContent":["import {Box, Text, Tooltip} from '@sanity/ui'\nimport {motion, useMotionValue} from 'framer-motion'\nimport get from 'lodash/get'\nimport React, {CSSProperties, ReactElement, useEffect} from 'react'\nimport {FnHotspotMove, TSpot} from './HotspotArray'\n\nconst dragStyle: CSSProperties = {\n width: '1.4rem',\n height: '1.4rem',\n position: 'absolute',\n boxSizing: 'border-box',\n top: 0,\n left: 0,\n margin: '-0.7rem 0 0 -0.7rem',\n cursor: 'pointer',\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n borderRadius: '50%',\n background: '#000',\n color: 'white',\n}\n\nconst dragStyleWhileDrag: CSSProperties = {\n background: 'rgba(0, 0, 0, 0.1)',\n border: '1px solid #fff',\n cursor: 'none',\n}\n\nconst dragStyleWhileHover: CSSProperties = {\n background: 'rgba(0, 0, 0, 0.1)',\n border: '1px solid #fff',\n}\n\nconst dotStyle: CSSProperties = {\n position: 'absolute',\n left: '50%',\n top: '50%',\n height: '0.2rem',\n width: '0.2rem',\n margin: '-0.1rem 0 0 -0.1rem',\n background: '#fff',\n visibility: 'hidden',\n borderRadius: '50%',\n // make sure pointer events only run on the parent\n pointerEvents: 'none',\n}\n\nconst dotStyleWhileActive: CSSProperties = {\n visibility: 'visible',\n}\n\nconst labelStyle: CSSProperties = {\n color: 'white',\n fontSize: '0.7rem',\n fontWeight: 600,\n lineHeight: '1',\n}\n\nconst labelStyleWhileActive: CSSProperties = {\n visibility: 'hidden',\n}\n\nconst round = (num) => Math.round(num * 100) / 100\n\ninterface IHotspot {\n spot: TSpot\n bounds: DOMRectReadOnly\n update: FnHotspotMove\n hotspotDescriptionPath?: string\n tooltip?: ReactElement\n index: number\n}\n\nexport default function Spot({\n spot,\n bounds,\n update,\n hotspotDescriptionPath,\n tooltip,\n index,\n}: IHotspot) {\n const [isDragging, setIsDragging] = React.useState(false)\n const [isHovering, setIsHovering] = React.useState(false)\n\n // x/y are stored as % but need to be converted to px\n const x = useMotionValue(round(bounds.width * (spot.x / 100)))\n const y = useMotionValue(round(bounds.height * (spot.y / 100)))\n\n /**\n * update x/y if the bounds change when resizing the window\n */\n useEffect(() => {\n x.set(round(bounds.width * (spot.x / 100)))\n y.set(round(bounds.height * (spot.y / 100)))\n }, [bounds])\n\n const handleDragEnd = React.useCallback(() => {\n setIsDragging(false)\n\n // get current values for x/y in px\n const currentX = x.get()\n const currentY = y.get()\n\n // Which we need to convert back to `%` to patch the document\n const newX = round((currentX * 100) / bounds.width)\n const newY = round((currentY * 100) / bounds.height)\n\n // Don't go below 0 or above 100\n const safeX = Math.max(0, Math.min(100, newX))\n const safeY = Math.max(0, Math.min(100, newY))\n\n update(spot._key, safeX, safeY)\n }, [spot])\n const handleDragStart = React.useCallback(() => setIsDragging(true), [])\n\n const handleHoverStart = React.useCallback(() => setIsHovering(true), [])\n const handleHoverEnd = React.useCallback(() => setIsHovering(false), [])\n\n if (!x || !y) {\n return null\n }\n\n return (\n <Tooltip\n key={spot._key}\n disabled={isDragging}\n portal\n content={\n tooltip && typeof tooltip === 'function' ? (\n React.createElement(tooltip, {spot})\n ) : (\n <Box padding={2} style={{maxWidth: 200, pointerEvents: `none`}}>\n <Text textOverflow=\"ellipsis\">\n {hotspotDescriptionPath\n ? (get(spot, hotspotDescriptionPath) as string)\n : `${spot.x}% x ${spot.y}%`}\n </Text>\n </Box>\n )\n }\n >\n <motion.div\n drag\n dragConstraints={bounds}\n dragElastic={0}\n dragMomentum={false}\n onDragEnd={handleDragEnd}\n onDragStart={handleDragStart}\n onHoverStart={handleHoverStart}\n onHoverEnd={handleHoverEnd}\n style={{\n ...dragStyle,\n x,\n y,\n ...(isDragging && {...dragStyleWhileDrag}),\n ...(isHovering && {...dragStyleWhileHover}),\n }}\n >\n {/* Dot */}\n <Box\n style={{\n ...dotStyle,\n ...((isDragging || isHovering) && {...dotStyleWhileActive}),\n }}\n />\n {/* Label */}\n <div\n style={{\n ...labelStyle,\n ...((isDragging || isHovering) && {...labelStyleWhileActive}),\n }}\n >\n {index + 1}\n </div>\n </motion.div>\n </Tooltip>\n )\n}\n"],"mappings":"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"}
@@ -4,26 +4,18 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.useUnsetInputComponent = useUnsetInputComponent;
7
-
8
7
  var _react = _interopRequireDefault(require("react"));
9
-
10
8
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
-
12
9
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
13
-
14
10
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
15
-
16
11
  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
17
-
18
12
  function useUnsetInputComponent(type, component) {
19
13
  return _react.default.useMemo(() => unsetInputComponent(type, component), [type, component]);
20
14
  }
21
-
22
15
  function unsetInputComponent(type, component) {
23
16
  var t = _objectSpread(_objectSpread({}, type), {}, {
24
17
  inputComponent: type.inputComponent === component ? undefined : type.inputComponent
25
18
  });
26
-
27
19
  var typeOfType = t.type ? unsetInputComponent(t.type, component) : undefined;
28
20
  return _objectSpread(_objectSpread({}, t), {}, {
29
21
  type: typeOfType
@@ -1 +1 @@
1
- {"version":3,"file":"useUnsetInputComponent.js","names":["useUnsetInputComponent","type","component","React","useMemo","unsetInputComponent","t","inputComponent","undefined","typeOfType"],"sources":["../src/useUnsetInputComponent.ts"],"sourcesContent":["import React from 'react'\n\nexport function useUnsetInputComponent(type, component) {\n return React.useMemo(() => unsetInputComponent(type, component), [type, component])\n}\n\nfunction unsetInputComponent(type, component) {\n const t = {\n ...type,\n inputComponent: type.inputComponent === component ? undefined : type.inputComponent,\n }\n const typeOfType = t.type ? unsetInputComponent(t.type, component) : undefined\n return {\n ...t,\n type: typeOfType,\n }\n}\n"],"mappings":";;;;;;;AAAA;;;;;;;;;;AAEO,SAASA,sBAAT,CAAgCC,IAAhC,EAAsCC,SAAtC,EAAiD;EACtD,OAAOC,cAAA,CAAMC,OAAN,CAAc,MAAMC,mBAAmB,CAACJ,IAAD,EAAOC,SAAP,CAAvC,EAA0D,CAACD,IAAD,EAAOC,SAAP,CAA1D,CAAP;AACD;;AAED,SAASG,mBAAT,CAA6BJ,IAA7B,EAAmCC,SAAnC,EAA8C;EAC5C,IAAMI,CAAC,mCACFL,IADE;IAELM,cAAc,EAAEN,IAAI,CAACM,cAAL,KAAwBL,SAAxB,GAAoCM,SAApC,GAAgDP,IAAI,CAACM;EAFhE,EAAP;;EAIA,IAAME,UAAU,GAAGH,CAAC,CAACL,IAAF,GAASI,mBAAmB,CAACC,CAAC,CAACL,IAAH,EAASC,SAAT,CAA5B,GAAkDM,SAArE;EACA,uCACKF,CADL;IAEEL,IAAI,EAAEQ;EAFR;AAID"}
1
+ {"version":3,"file":"useUnsetInputComponent.js","names":["useUnsetInputComponent","type","component","React","useMemo","unsetInputComponent","t","inputComponent","undefined","typeOfType"],"sources":["../src/useUnsetInputComponent.ts"],"sourcesContent":["import React from 'react'\n\nexport function useUnsetInputComponent(type, component) {\n return React.useMemo(() => unsetInputComponent(type, component), [type, component])\n}\n\nfunction unsetInputComponent(type, component) {\n const t = {\n ...type,\n inputComponent: type.inputComponent === component ? undefined : type.inputComponent,\n }\n const typeOfType = t.type ? unsetInputComponent(t.type, component) : undefined\n return {\n ...t,\n type: typeOfType,\n }\n}\n"],"mappings":";;;;;;AAAA;AAAyB;AAAA;AAAA;AAAA;AAElB,SAASA,sBAAsB,CAACC,IAAI,EAAEC,SAAS,EAAE;EACtD,OAAOC,cAAK,CAACC,OAAO,CAAC,MAAMC,mBAAmB,CAACJ,IAAI,EAAEC,SAAS,CAAC,EAAE,CAACD,IAAI,EAAEC,SAAS,CAAC,CAAC;AACrF;AAEA,SAASG,mBAAmB,CAACJ,IAAI,EAAEC,SAAS,EAAE;EAC5C,IAAMI,CAAC,mCACFL,IAAI;IACPM,cAAc,EAAEN,IAAI,CAACM,cAAc,KAAKL,SAAS,GAAGM,SAAS,GAAGP,IAAI,CAACM;EAAc,EACpF;EACD,IAAME,UAAU,GAAGH,CAAC,CAACL,IAAI,GAAGI,mBAAmB,CAACC,CAAC,CAACL,IAAI,EAAEC,SAAS,CAAC,GAAGM,SAAS;EAC9E,uCACKF,CAAC;IACJL,IAAI,EAAEQ;EAAU;AAEpB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sanity-plugin-hotspot-array",
3
- "version": "0.0.8",
3
+ "version": "0.0.10",
4
4
  "description": "A configurable Custom Input for Arrays that will add and update items by clicking on an Image",
5
5
  "main": "lib/HotspotArray.js",
6
6
  "scripts": {
@@ -19,20 +19,20 @@
19
19
  },
20
20
  "repository": {
21
21
  "type": "git",
22
- "url": "git+ssh://git@github.com/SimeonGriggs/sanity-plugin-hotspot-array.git"
22
+ "url": "git+ssh://git@github.com/sanity-io/sanity-plugin-hotspot-array.git"
23
23
  },
24
24
  "keywords": [
25
25
  "sanity",
26
26
  "sanity-plugin"
27
27
  ],
28
- "author": "Simeon Griggs <simeon@sanity.io>",
28
+ "author": "Sanity.io <hello@sanity.io>",
29
29
  "license": "MIT",
30
30
  "dependencies": {
31
31
  "@react-hookz/web": "^14.2.2",
32
- "@sanity/asset-utils": "^1.2.3",
33
- "@sanity/base": "^2.30.1",
34
- "@sanity/form-builder": "^2.30.1",
35
- "@sanity/ui": "^0.37.12",
32
+ "@sanity/asset-utils": "^1.3.0",
33
+ "@sanity/base": "^2.35.0",
34
+ "@sanity/form-builder": "^2.35.0",
35
+ "@sanity/ui": "^0.37.22",
36
36
  "framer-motion": "^6.3.11",
37
37
  "husky": "^8.0.1"
38
38
  },
@@ -46,15 +46,16 @@
46
46
  "sanipack": "^2.1.0"
47
47
  },
48
48
  "peerDependencies": {
49
- "@sanity/image-url": "1.0.1",
50
- "@sanity/util": "2.29.5",
49
+ "@sanity/image-url": "^1.0.1",
50
+ "@sanity/util": "^2.35.0",
51
51
  "lodash": "4.17.21",
52
- "react": "^17.0.2"
52
+ "react": "^17",
53
+ "react-dom": "^17"
53
54
  },
54
55
  "bugs": {
55
- "url": "https://github.com/SimeonGriggs/sanity-plugin-hotspot-array/issues"
56
+ "url": "https://github.com/sanity-io/sanity-plugin-hotspot-array/issues"
56
57
  },
57
- "homepage": "https://github.com/SimeonGriggs/sanity-plugin-hotspot-array#readme",
58
+ "homepage": "https://github.com/sanity-io/sanity-plugin-hotspot-array#readme",
58
59
  "prettier": {
59
60
  "semi": false,
60
61
  "printWidth": 100,
@@ -3,10 +3,9 @@
3
3
  // @ts-ignore
4
4
  import sanityClient from 'part:@sanity/base/client'
5
5
  // @ts-ignore
6
- import {withDocument} from 'part:@sanity/form-builder'
6
+ import {withDocument, withParent} from 'part:@sanity/form-builder'
7
7
 
8
8
  import {getImageDimensions} from '@sanity/asset-utils'
9
- import {FormBuilderInput} from '@sanity/form-builder/lib/FormBuilderInput'
10
9
  import {insert, PatchEvent, set, setIfMissing} from '@sanity/form-builder/PatchEvent'
11
10
  import imageUrlBuilder from '@sanity/image-url'
12
11
  import {Card, Flex, Stack} from '@sanity/ui'
@@ -18,6 +17,7 @@ import {IUseResizeObserverCallback, useDebouncedCallback, useResizeObserver} fro
18
17
  import Feedback from './Feedback'
19
18
  import Spot from './Spot'
20
19
  import {useUnsetInputComponent} from './useUnsetInputComponent'
20
+ import { NestedFormBuilder } from './NestedFormBuilder'
21
21
 
22
22
  const imageStyle = {width: `100%`, height: `auto`}
23
23
 
@@ -33,6 +33,7 @@ export type TSpot = {
33
33
  } & {[key: string]: unknown}
34
34
 
35
35
  const HotspotArray = React.forwardRef((props: any, ref) => {
36
+ console.log(props);
36
37
  const {type, value, onChange, document} = props
37
38
  const {options} = type ?? {}
38
39
 
@@ -169,9 +170,9 @@ const HotspotArray = React.forwardRef((props: any, ref) => {
169
170
  falling back to "document". Available values are "{VALID_ROOT_PATHS.join(', ')}".
170
171
  </Feedback>
171
172
  )}
172
- <FormBuilderInput {...props} type={typeWithoutInputComponent} ref={ref} />
173
+ <NestedFormBuilder {...props} type={typeWithoutInputComponent} ref={ref} />
173
174
  </Stack>
174
175
  )
175
176
  })
176
177
 
177
- export default withDocument(HotspotArray)
178
+ export default withParent(withDocument(HotspotArray))
@@ -0,0 +1,44 @@
1
+ import React from 'react';
2
+ import { FormBuilderInput } from '@sanity/form-builder/lib/FormBuilderInput';
3
+
4
+ /**
5
+ * Nesting FormBuilderInput components results in inconsistent focus & tab-index behaviour.
6
+ *
7
+ * FormBuilderInputs requests focus if props.focusPath matches the input.focusPath
8
+ * when mounted and when props change. If multiple components "handle" the same focus path,
9
+ * there is a race-condition on which component will receive the focus, often resulting
10
+ * in seemingly random scrollbehaviour.
11
+ *
12
+ * This is a workaround, reusing as much of FormBuilderInput as possible.
13
+ *
14
+ * Use FormBuilderInput when you need to render a field obtained from a SchemaType (type.fields or type.fieldset[].field).
15
+ *
16
+ * Use NestedFormBuilder for decorator components that are used as inputComponent or in input-resolver.ts.
17
+ *
18
+ * Decorator components are components that just want to modify a type, add some markup or so on,
19
+ * then delegate back to Sanity to obtain an actual input implementation.
20
+ *
21
+ * FormBuilderInput should only be used as the outermost component when resolving
22
+ * inputs recursively.
23
+ */
24
+
25
+ export class NestedFormBuilder extends FormBuilderInput {
26
+ componentDidMount() {
27
+ // do nothing - prevent focus-bug when nesting FormBuilderInput
28
+ }
29
+
30
+ // eslint-disable-next-line camelcase
31
+ UNSAFE_componentWillReceiveProps() {
32
+ // do nothing - prevent focus-bug when nesting FormBuilderInput
33
+ }
34
+
35
+ componentDidUpdate() {
36
+ // do nothing - prevent focus-bug when nesting FormBuilderInput
37
+ }
38
+
39
+ render(): JSX.Element {
40
+ const { type } = this.props;
41
+ const InputComponent = this.resolveInputComponent(type);
42
+ return <InputComponent {...this.props} ref={this.setInput} />;
43
+ }
44
+ }