@sanity/google-maps-input 4.0.0 → 4.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/README.md CHANGED
@@ -50,9 +50,9 @@ export default defineConfig({
50
50
 
51
51
  Ensure that the key has access to:
52
52
 
53
- - Google Maps JavaScript API
54
- - Google Places API Web Service
55
- - Google Static Maps API
53
+ - Google Maps JavaScript API (for the interactive map)
54
+ - Google Places API Web Service (for the search feature)
55
+ - Google Static Maps API (for previewing a location)
56
56
 
57
57
  And that the key allows web-access from the Studio URL(s) you are using the plugin in.
58
58
 
@@ -70,6 +70,8 @@ MIT-licensed. See LICENSE.
70
70
 
71
71
  ## Develop & test
72
72
 
73
+ Add a Google Maps API key to `.env.local` (see `.env.example` for example format).
74
+
73
75
  This plugin uses [@sanity/plugin-kit](https://github.com/sanity-io/plugin-kit)
74
76
  with default configuration for build & watch scripts.
75
77
 
package/dist/index.cjs ADDED
@@ -0,0 +1,604 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: !0 });
3
+ var jsxRuntime = require("react/jsx-runtime"), react = require("react"), ui = require("@sanity/ui"), icons = require("@sanity/icons"), sanity = require("sanity"), styledComponents = require("styled-components");
4
+ const callbackName = "___sanity_googleMapsApiCallback", authFailureCallbackName = "gm_authFailure";
5
+ let AuthError$1 = class extends Error {
6
+ };
7
+ function _loadGoogleMapsApi(config2) {
8
+ return new Promise((resolve, reject) => {
9
+ window[authFailureCallbackName] = () => {
10
+ reject(new AuthError$1("Authentication error when loading Google Maps API."));
11
+ }, window[callbackName] = () => {
12
+ resolve(window.google.maps);
13
+ };
14
+ const script = document.createElement("script");
15
+ script.onerror = (event, source, lineno, colno, error) => reject(new Error(coeerceError(event, error))), script.src = `https://maps.googleapis.com/maps/api/js?key=${config2.apiKey}&libraries=places&callback=${callbackName}&language=${config2.locale}`, document.getElementsByTagName("head")[0].appendChild(script);
16
+ }).finally(() => {
17
+ delete window[callbackName], delete window[authFailureCallbackName];
18
+ });
19
+ }
20
+ let memo = null;
21
+ function loadGoogleMapsApi(config2) {
22
+ return memo || (memo = _loadGoogleMapsApi(config2), memo.catch(() => {
23
+ memo = null;
24
+ }), memo);
25
+ }
26
+ function coeerceError(event, error) {
27
+ return error ? error.message : typeof event == "string" ? event : isErrorEvent(event) ? event.message : "Failed to load Google Maps API";
28
+ }
29
+ function isErrorEvent(event) {
30
+ return typeof event != "object" || event === null || !("message" in event) ? !1 : typeof event.message == "string";
31
+ }
32
+ function LoadError(props) {
33
+ var _a;
34
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Card, { tone: "critical", radius: 1, children: [
35
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { as: "header", paddingX: 4, paddingTop: 4, paddingBottom: 1, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { as: "h2", weight: "bold", children: "Google Maps failed to load" }) }),
36
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { paddingX: 4, paddingTop: 4, paddingBottom: 1, children: props.isAuthError ? /* @__PURE__ */ jsxRuntime.jsx(AuthError2, {}) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
37
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { as: "h3", children: "Error details:" }),
38
+ /* @__PURE__ */ jsxRuntime.jsx("pre", { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Code, { size: 1, children: "error" in props && ((_a = props.error) == null ? void 0 : _a.message) }) })
39
+ ] }) })
40
+ ] });
41
+ }
42
+ function AuthError2() {
43
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { children: [
44
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: "The error appears to be related to authentication" }),
45
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Common causes include:" }),
46
+ /* @__PURE__ */ jsxRuntime.jsxs("ul", { children: [
47
+ /* @__PURE__ */ jsxRuntime.jsx("li", { children: "Incorrect API key" }),
48
+ /* @__PURE__ */ jsxRuntime.jsx("li", { children: "Referer not allowed" }),
49
+ /* @__PURE__ */ jsxRuntime.jsx("li", { children: "Missing authentication scope" })
50
+ ] }),
51
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Check the browser developer tools for more information." })
52
+ ] });
53
+ }
54
+ const browserLocale = typeof window < "u" && window.navigator.language || "en";
55
+ function useLoadGoogleMapsApi(config2) {
56
+ const locale = config2.defaultLocale || browserLocale || "en-US", [state, setState] = react.useState({ type: "loading" });
57
+ return react.useEffect(() => {
58
+ typeof window > "u" || loadGoogleMapsApi({ locale, apiKey: config2.apiKey }).then(
59
+ (api) => setState({ type: "loaded", api }),
60
+ (err) => setState({
61
+ type: "error",
62
+ error: { type: err instanceof AuthError$1 ? "authError" : "loadError", message: err.message }
63
+ })
64
+ );
65
+ }, [locale, config2.apiKey]), state;
66
+ }
67
+ function GoogleMapsLoadProxy(props) {
68
+ const loadState = useLoadGoogleMapsApi(props.config);
69
+ switch (loadState.type) {
70
+ case "error":
71
+ return /* @__PURE__ */ jsxRuntime.jsx(LoadError, { error: loadState.error, isAuthError: loadState.error.type === "authError" });
72
+ case "loading":
73
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { children: "Loading Google Maps API" });
74
+ case "loaded":
75
+ return props.children(loadState.api);
76
+ default:
77
+ return null;
78
+ }
79
+ }
80
+ let config;
81
+ function getGeoConfig() {
82
+ return config;
83
+ }
84
+ function setGeoConfig(newConfig) {
85
+ config = newConfig;
86
+ }
87
+ const PreviewImage = styledComponents.styled.img`
88
+ width: 100%;
89
+ height: auto;
90
+ vertical-align: top;
91
+ `, DialogInnerContainer = styledComponents.styled.div`
92
+ height: 40rem;
93
+ `, WrapperContainer = styledComponents.styled.div`
94
+ position: absolute;
95
+ right: 10px;
96
+ top: 10px;
97
+ width: 220px;
98
+ `;
99
+ var __defProp$5 = Object.defineProperty, __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: !0, configurable: !0, writable: !0, value }) : obj[key] = value, __publicField$3 = (obj, key, value) => __defNormalProp$5(obj, typeof key != "symbol" ? key + "" : key, value);
100
+ class SearchInput extends react.PureComponent {
101
+ constructor() {
102
+ super(...arguments), __publicField$3(this, "searchInputRef", react.createRef()), __publicField$3(this, "autoComplete"), __publicField$3(this, "handleChange", () => {
103
+ this.autoComplete && (this.props.onChange(this.autoComplete.getPlace()), this.searchInputRef.current && (this.searchInputRef.current.value = ""));
104
+ });
105
+ }
106
+ componentDidMount() {
107
+ const input = this.searchInputRef.current;
108
+ if (!input)
109
+ return;
110
+ const { api, map } = this.props, { Circle, places, event } = api, searchBounds = new Circle({ center: map.getCenter(), radius: 100 }).getBounds();
111
+ this.autoComplete = new places.Autocomplete(input, {
112
+ bounds: searchBounds,
113
+ types: []
114
+ // return all kinds of places
115
+ }), event.addListener(this.autoComplete, "place_changed", this.handleChange);
116
+ }
117
+ render() {
118
+ return /* @__PURE__ */ jsxRuntime.jsx(WrapperContainer, { children: /* @__PURE__ */ jsxRuntime.jsx(
119
+ ui.TextInput,
120
+ {
121
+ name: "place",
122
+ ref: this.searchInputRef,
123
+ placeholder: "Search for place or address",
124
+ padding: 4
125
+ }
126
+ ) });
127
+ }
128
+ }
129
+ function latLngAreEqual(latLng1, latLng2) {
130
+ const lat1 = typeof latLng1.lat == "function" ? latLng1.lat() : latLng1.lat, lng1 = typeof latLng1.lng == "function" ? latLng1.lng() : latLng1.lng, lat2 = typeof latLng2.lat == "function" ? latLng2.lat() : latLng2.lat, lng2 = typeof latLng2.lng == "function" ? latLng2.lng() : latLng2.lng;
131
+ return lat1 === lat2 && lng1 === lng2;
132
+ }
133
+ const MapContainer = styledComponents.styled.div`
134
+ position: absolute;
135
+ top: 0;
136
+ left: 0;
137
+ height: 100%;
138
+ width: 100%;
139
+ box-sizing: border-box;
140
+ `;
141
+ var __defProp$4 = Object.defineProperty, __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: !0, configurable: !0, writable: !0, value }) : obj[key] = value, __publicField$2 = (obj, key, value) => __defNormalProp$4(obj, typeof key != "symbol" ? key + "" : key, value);
142
+ class GoogleMap extends react.PureComponent {
143
+ constructor() {
144
+ super(...arguments), __publicField$2(this, "state", { map: void 0 }), __publicField$2(this, "clickHandler"), __publicField$2(this, "mapRef", react.createRef()), __publicField$2(this, "mapEl", null), __publicField$2(this, "attachClickHandler", () => {
145
+ const map = this.state.map;
146
+ if (!map)
147
+ return;
148
+ const { api, onClick } = this.props, { event } = api;
149
+ this.clickHandler && this.clickHandler.remove(), onClick && (this.clickHandler = event.addListener(map, "click", onClick));
150
+ }), __publicField$2(this, "setMapElement", (element) => {
151
+ if (element && element !== this.mapEl) {
152
+ const map = this.constructMap(element);
153
+ this.setState({ map }, this.attachClickHandler);
154
+ }
155
+ this.mapEl = element;
156
+ });
157
+ }
158
+ componentDidMount() {
159
+ this.attachClickHandler();
160
+ }
161
+ componentDidUpdate(prevProps) {
162
+ const map = this.state.map;
163
+ if (!map)
164
+ return;
165
+ const { onClick, location, bounds } = this.props;
166
+ prevProps.onClick !== onClick && this.attachClickHandler(), latLngAreEqual(prevProps.location, location) || map.panTo(this.getCenter()), bounds && (!prevProps.bounds || !bounds.equals(prevProps.bounds)) && map.fitBounds(bounds);
167
+ }
168
+ componentWillUnmount() {
169
+ this.clickHandler && this.clickHandler.remove();
170
+ }
171
+ getCenter() {
172
+ const { location, api } = this.props;
173
+ return new api.LatLng(location.lat, location.lng);
174
+ }
175
+ constructMap(el) {
176
+ const { defaultZoom, api, mapTypeControl, controlSize, bounds, scrollWheel } = this.props, map = new api.Map(el, {
177
+ zoom: defaultZoom,
178
+ center: this.getCenter(),
179
+ scrollwheel: scrollWheel,
180
+ streetViewControl: !1,
181
+ mapTypeControl,
182
+ controlSize
183
+ });
184
+ return bounds && map.fitBounds(bounds), map;
185
+ }
186
+ render() {
187
+ const { children } = this.props, { map } = this.state;
188
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
189
+ /* @__PURE__ */ jsxRuntime.jsx(MapContainer, { ref: this.setMapElement }),
190
+ children && map ? children(map) : null
191
+ ] });
192
+ }
193
+ }
194
+ __publicField$2(GoogleMap, "defaultProps", {
195
+ defaultZoom: 8,
196
+ scrollWheel: !0
197
+ });
198
+ var __defProp$3 = Object.defineProperty, __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: !0, configurable: !0, writable: !0, value }) : obj[key] = value, __publicField$1 = (obj, key, value) => __defNormalProp$3(obj, typeof key != "symbol" ? key + "" : key, value);
199
+ const markerPath = "M 3.052 3.7 C 1.56 5.293 0.626 7.612 0.663 9.793 C 0.738 14.352 2.793 16.077 6.078 22.351 C 7.263 25.111 8.497 28.032 9.672 32.871 C 9.835 33.584 9.994 34.246 10.069 34.305 C 10.143 34.362 10.301 33.697 10.465 32.983 C 11.639 28.145 12.875 25.226 14.059 22.466 C 17.344 16.192 19.398 14.466 19.474 9.908 C 19.511 7.727 18.574 5.405 17.083 3.814 C 15.379 1.994 12.809 0.649 10.069 0.593 C 7.328 0.536 4.756 1.882 3.052 3.7 Z";
200
+ class Marker extends react.PureComponent {
201
+ constructor() {
202
+ super(...arguments), __publicField$1(this, "marker"), __publicField$1(this, "eventHandlers", {});
203
+ }
204
+ componentDidMount() {
205
+ const { position, api, map, onMove, zIndex, opacity, label, markerRef, color } = this.props, { Marker: GMarker } = api;
206
+ let icon;
207
+ color && (icon = {
208
+ path: markerPath,
209
+ fillOpacity: 1,
210
+ fillColor: color.background,
211
+ strokeColor: color.border,
212
+ strokeWeight: 2,
213
+ anchor: new api.Point(10, 35),
214
+ labelOrigin: new api.Point(10, 11)
215
+ }), this.marker = new GMarker({
216
+ draggable: !!onMove,
217
+ position,
218
+ map,
219
+ zIndex,
220
+ opacity,
221
+ label,
222
+ icon
223
+ }), markerRef && (markerRef.current = this.marker), this.attachMoveHandler(), this.attachClickHandler();
224
+ }
225
+ componentDidUpdate(prevProps) {
226
+ if (!this.marker)
227
+ return;
228
+ const { position, onMove, label, zIndex, opacity, map } = this.props;
229
+ prevProps.onMove !== onMove && this.attachMoveHandler(), latLngAreEqual(prevProps.position, position) || this.marker.setPosition(position), prevProps.label !== label && this.marker.setLabel(label || null), prevProps.zIndex !== zIndex && this.marker.setZIndex(zIndex || null), prevProps.opacity !== opacity && this.marker.setOpacity(opacity || null), prevProps.map !== map && this.marker.setMap(map);
230
+ }
231
+ componentWillUnmount() {
232
+ this.eventHandlers.move && this.eventHandlers.move.remove(), this.marker && this.marker.setMap(null);
233
+ }
234
+ attachMoveHandler() {
235
+ const { api, onMove } = this.props;
236
+ this.eventHandlers.move && this.eventHandlers.move.remove(), this.marker && onMove && (this.eventHandlers.move = api.event.addListener(this.marker, "dragend", onMove));
237
+ }
238
+ attachClickHandler() {
239
+ const { api, onClick } = this.props;
240
+ this.eventHandlers.click && this.eventHandlers.click.remove(), this.marker && onClick && (this.eventHandlers.click = api.event.addListener(this.marker, "click", onClick));
241
+ }
242
+ // eslint-disable-next-line class-methods-use-this
243
+ render() {
244
+ return null;
245
+ }
246
+ }
247
+ var __defProp$2 = Object.defineProperty, __getOwnPropSymbols$1 = Object.getOwnPropertySymbols, __hasOwnProp$1 = Object.prototype.hasOwnProperty, __propIsEnum$1 = Object.prototype.propertyIsEnumerable, __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: !0, configurable: !0, writable: !0, value }) : obj[key] = value, __spreadValues$1 = (a, b) => {
248
+ for (var prop in b || (b = {}))
249
+ __hasOwnProp$1.call(b, prop) && __defNormalProp$2(a, prop, b[prop]);
250
+ if (__getOwnPropSymbols$1)
251
+ for (var prop of __getOwnPropSymbols$1(b))
252
+ __propIsEnum$1.call(b, prop) && __defNormalProp$2(a, prop, b[prop]);
253
+ return a;
254
+ };
255
+ const fallbackLatLng = { lat: 40.7058254, lng: -74.1180863 }, GeopointSelect = ({
256
+ api,
257
+ value,
258
+ onChange,
259
+ defaultLocation = { lng: 10.74609, lat: 59.91273 },
260
+ defaultZoom = 8
261
+ }) => {
262
+ const getCenter2 = react.useCallback(() => __spreadValues$1(__spreadValues$1(__spreadValues$1({}, fallbackLatLng), defaultLocation), value), [value, defaultLocation]), setValue = react.useCallback(
263
+ (geoPoint) => {
264
+ onChange && onChange(geoPoint);
265
+ },
266
+ [onChange]
267
+ ), handlePlaceChanged = react.useCallback(
268
+ (place) => {
269
+ var _a;
270
+ (_a = place.geometry) != null && _a.location && setValue(place.geometry.location);
271
+ },
272
+ [setValue]
273
+ ), handleMarkerDragEnd = react.useCallback(
274
+ (event) => {
275
+ event.latLng && setValue(event.latLng);
276
+ },
277
+ [setValue]
278
+ ), handleMapClick = react.useCallback(
279
+ (event) => {
280
+ event.latLng && setValue(event.latLng);
281
+ },
282
+ [setValue]
283
+ );
284
+ return /* @__PURE__ */ jsxRuntime.jsx(GoogleMap, { api, location: getCenter2(), onClick: handleMapClick, defaultZoom, children: (map) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
285
+ /* @__PURE__ */ jsxRuntime.jsx(SearchInput, { api, map, onChange: handlePlaceChanged }),
286
+ value && /* @__PURE__ */ jsxRuntime.jsx(
287
+ Marker,
288
+ {
289
+ api,
290
+ map,
291
+ position: value,
292
+ onMove: onChange ? handleMarkerDragEnd : void 0
293
+ }
294
+ )
295
+ ] }) });
296
+ }, EMPTY_PATH = [], getStaticImageUrl = (value, apiKey) => {
297
+ const loc = `${value.lat},${value.lng}`;
298
+ return `https://maps.googleapis.com/maps/api/staticmap?${new URLSearchParams({
299
+ key: apiKey,
300
+ center: loc,
301
+ markers: loc,
302
+ zoom: "13",
303
+ scale: "2",
304
+ size: "640x300"
305
+ }).toString()}`;
306
+ };
307
+ function GeopointInput(props) {
308
+ const {
309
+ changed,
310
+ elementProps,
311
+ focused,
312
+ geoConfig: config2,
313
+ onChange,
314
+ onPathFocus,
315
+ path,
316
+ readOnly,
317
+ schemaType,
318
+ value
319
+ } = props, {
320
+ id,
321
+ ref: inputRef,
322
+ onBlur: handleBlur,
323
+ onFocus: handleFocus,
324
+ "aria-describedby": ariaDescribedBy
325
+ } = elementProps, schemaTypeName = schemaType.name, dialogId = react.useId(), dialogRef = react.useRef(null), handleFocusButton = react.useCallback(() => {
326
+ var _a;
327
+ return (_a = inputRef == null ? void 0 : inputRef.current) == null ? void 0 : _a.focus();
328
+ }, [inputRef]), [modalOpen, setModalOpen] = react.useState(!1), handleCloseModal = react.useCallback(() => {
329
+ dialogRef.current && dialogRef.current.blur(), setModalOpen(!1), handleFocusButton();
330
+ }, [setModalOpen, handleFocusButton]), handleToggleModal = react.useCallback(
331
+ () => setModalOpen((currentState) => !currentState),
332
+ [setModalOpen]
333
+ ), handleChange = react.useCallback(
334
+ (latLng) => {
335
+ onChange([
336
+ sanity.setIfMissing({ _type: schemaTypeName }),
337
+ sanity.set(latLng.lat(), ["lat"]),
338
+ sanity.set(latLng.lng(), ["lng"])
339
+ ]);
340
+ },
341
+ [schemaTypeName, onChange]
342
+ ), handleClear = react.useCallback(() => {
343
+ onChange(sanity.unset());
344
+ }, [onChange]);
345
+ return react.useEffect(() => {
346
+ modalOpen && onPathFocus(EMPTY_PATH);
347
+ }, [modalOpen, onPathFocus]), !config2 || !config2.apiKey ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
348
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
349
+ "The ",
350
+ /* @__PURE__ */ jsxRuntime.jsx("a", { href: "https://sanity.io/docs/schema-types/geopoint-type", children: "Geopoint type" }),
351
+ " needs a Google Maps API key with access to:"
352
+ ] }),
353
+ /* @__PURE__ */ jsxRuntime.jsxs("ul", { children: [
354
+ /* @__PURE__ */ jsxRuntime.jsx("li", { children: "Google Maps JavaScript API" }),
355
+ /* @__PURE__ */ jsxRuntime.jsx("li", { children: "Google Places API Web Service" }),
356
+ /* @__PURE__ */ jsxRuntime.jsx("li", { children: "Google Static Maps API" })
357
+ ] }),
358
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Please enter the API key with access to these services in your googleMapsInput plugin config." })
359
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
360
+ value && /* @__PURE__ */ jsxRuntime.jsx(sanity.ChangeIndicator, { path, isChanged: changed, hasFocus: !!focused, children: /* @__PURE__ */ jsxRuntime.jsx(
361
+ PreviewImage,
362
+ {
363
+ src: getStaticImageUrl(value, config2.apiKey),
364
+ alt: "Map location",
365
+ onClick: handleFocusButton,
366
+ onDoubleClick: handleToggleModal
367
+ }
368
+ ) }),
369
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Grid, { columns: value ? 2 : 1, gap: 3, children: [
370
+ /* @__PURE__ */ jsxRuntime.jsx(
371
+ ui.Button,
372
+ {
373
+ "aria-describedby": ariaDescribedBy,
374
+ disabled: readOnly,
375
+ icon: value && icons.EditIcon,
376
+ id,
377
+ mode: "ghost",
378
+ onClick: handleToggleModal,
379
+ onFocus: handleFocus,
380
+ padding: 3,
381
+ ref: inputRef,
382
+ text: value ? "Edit" : "Set location"
383
+ }
384
+ ),
385
+ value && /* @__PURE__ */ jsxRuntime.jsx(
386
+ ui.Button,
387
+ {
388
+ disabled: readOnly,
389
+ icon: icons.TrashIcon,
390
+ mode: "ghost",
391
+ onClick: handleClear,
392
+ padding: 3,
393
+ text: "Remove",
394
+ tone: "critical"
395
+ }
396
+ )
397
+ ] }) }),
398
+ modalOpen && /* @__PURE__ */ jsxRuntime.jsx(
399
+ ui.Dialog,
400
+ {
401
+ header: "Place the marker on the map",
402
+ id: `${dialogId}_dialog`,
403
+ onBlur: handleBlur,
404
+ onClose: handleCloseModal,
405
+ ref: dialogRef,
406
+ width: 1,
407
+ children: /* @__PURE__ */ jsxRuntime.jsx(DialogInnerContainer, { children: /* @__PURE__ */ jsxRuntime.jsx(GoogleMapsLoadProxy, { config: getGeoConfig(), children: (api) => /* @__PURE__ */ jsxRuntime.jsx(
408
+ GeopointSelect,
409
+ {
410
+ api,
411
+ value: value || void 0,
412
+ onChange: readOnly ? void 0 : handleChange,
413
+ defaultLocation: config2.defaultLocation,
414
+ defaultZoom: config2.defaultZoom
415
+ }
416
+ ) }) })
417
+ }
418
+ )
419
+ ] });
420
+ }
421
+ var __defProp$1 = Object.defineProperty, __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: !0, configurable: !0, writable: !0, value }) : obj[key] = value, __publicField = (obj, key, value) => __defNormalProp$1(obj, typeof key != "symbol" ? key + "" : key, value);
422
+ class Arrow extends react.PureComponent {
423
+ constructor() {
424
+ super(...arguments), __publicField(this, "line"), __publicField(this, "eventHandlers", {});
425
+ }
426
+ componentDidMount() {
427
+ const { from, to, api, map, zIndex, onClick, color, arrowRef } = this.props, lineSymbol = {
428
+ path: api.SymbolPath.FORWARD_OPEN_ARROW
429
+ };
430
+ this.line = new api.Polyline({
431
+ map,
432
+ zIndex,
433
+ path: [from, to],
434
+ icons: [{ icon: lineSymbol, offset: "50%" }],
435
+ strokeOpacity: 0.55,
436
+ strokeColor: color ? color.text : "black"
437
+ }), onClick && (this.eventHandlers.click = api.event.addListener(this.line, "click", onClick)), arrowRef && (arrowRef.current = this.line);
438
+ }
439
+ componentDidUpdate(prevProps) {
440
+ if (!this.line)
441
+ return;
442
+ const { from, to, map } = this.props;
443
+ (!latLngAreEqual(prevProps.from, from) || !latLngAreEqual(prevProps.to, to)) && this.line.setPath([from, to]), prevProps.map !== map && this.line.setMap(map);
444
+ }
445
+ componentWillUnmount() {
446
+ this.line && this.line.setMap(null), this.eventHandlers.click && this.eventHandlers.click.remove();
447
+ }
448
+ // eslint-disable-next-line class-methods-use-this
449
+ render() {
450
+ return null;
451
+ }
452
+ }
453
+ function GeopointMove({ diff, api, map, label }) {
454
+ const { fromValue: from, toValue: to } = diff, annotation = diff.isChanged ? diff.annotation : void 0, userColor = sanity.useUserColor(annotation ? annotation.author : null) || void 0, fromRef = react.useRef(), toRef = react.useRef();
455
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
456
+ from && /* @__PURE__ */ jsxRuntime.jsx(
457
+ Marker,
458
+ {
459
+ api,
460
+ map,
461
+ position: from,
462
+ zIndex: 0,
463
+ opacity: 0.55,
464
+ markerRef: fromRef,
465
+ color: userColor
466
+ }
467
+ ),
468
+ from && to && /* @__PURE__ */ jsxRuntime.jsx(Arrow, { api, map, from, to, zIndex: 1, color: userColor }),
469
+ to && /* @__PURE__ */ jsxRuntime.jsx(
470
+ Marker,
471
+ {
472
+ api,
473
+ map,
474
+ position: to,
475
+ zIndex: 2,
476
+ markerRef: toRef,
477
+ label,
478
+ color: userColor
479
+ }
480
+ )
481
+ ] });
482
+ }
483
+ const RootContainer = styledComponents.styled.div`
484
+ position: relative;
485
+ min-height: 200px;
486
+
487
+ &:empty {
488
+ background-color: var(--card-skeleton-color-from);
489
+ display: table;
490
+ width: 100%;
491
+ }
492
+
493
+ &:empty:after {
494
+ content: 'Missing/invalid data';
495
+ display: table-cell;
496
+ vertical-align: middle;
497
+ text-align: center;
498
+ position: relative;
499
+ }
500
+ `, GeopointArrayDiff = ({
501
+ diff,
502
+ schemaType
503
+ }) => /* @__PURE__ */ jsxRuntime.jsx(RootContainer, { children: /* @__PURE__ */ jsxRuntime.jsx(GoogleMapsLoadProxy, { config: getGeoConfig(), children: (api) => /* @__PURE__ */ jsxRuntime.jsx(GeopointDiff$1, { api, diff, schemaType }) }) });
504
+ function GeopointDiff$1({ api, diff }) {
505
+ const fromValue = (diff.fromValue || []).filter(hasCoordinates), toValue = (diff.toValue || []).filter(hasCoordinates);
506
+ if (fromValue.length === 0 && toValue.length === 0)
507
+ return null;
508
+ const bounds = getBounds$1(fromValue, toValue, api);
509
+ return /* @__PURE__ */ jsxRuntime.jsx(
510
+ GoogleMap,
511
+ {
512
+ api,
513
+ location: bounds.getCenter().toJSON(),
514
+ mapTypeControl: !1,
515
+ controlSize: 20,
516
+ bounds,
517
+ children: (map) => /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: diff.items.map(({ toIndex, diff: pointDiff }) => isChangeDiff(pointDiff) ? /* @__PURE__ */ jsxRuntime.jsx(
518
+ GeopointMove,
519
+ {
520
+ api,
521
+ map,
522
+ diff: pointDiff,
523
+ label: `${toIndex}`
524
+ },
525
+ toIndex
526
+ ) : null) })
527
+ }
528
+ );
529
+ }
530
+ function isChangeDiff(diff) {
531
+ return diff.action !== "unchanged" && diff.type === "object";
532
+ }
533
+ function hasCoordinates(point) {
534
+ return typeof point.lat == "number" && typeof point.lng == "number";
535
+ }
536
+ function getBounds$1(fromValue, toValue, api) {
537
+ const bounds = new api.LatLngBounds();
538
+ return [...fromValue || [], ...toValue || []].forEach((point) => bounds.extend(point)), bounds;
539
+ }
540
+ const GeopointFieldDiff = ({
541
+ diff,
542
+ schemaType
543
+ }) => /* @__PURE__ */ jsxRuntime.jsx(RootContainer, { children: /* @__PURE__ */ jsxRuntime.jsx(GoogleMapsLoadProxy, { config: getGeoConfig(), children: (api) => /* @__PURE__ */ jsxRuntime.jsx(GeopointDiff, { api, diff, schemaType }) }) });
544
+ function GeopointDiff({ api, diff }) {
545
+ const { fromValue, toValue } = diff, annotation = sanity.getAnnotationAtPath(diff, ["lat"]) || sanity.getAnnotationAtPath(diff, ["lng"]) || sanity.getAnnotationAtPath(diff, []), center = getCenter(diff, api), bounds = fromValue && toValue ? getBounds(fromValue, toValue, api) : void 0;
546
+ return /* @__PURE__ */ jsxRuntime.jsx(sanity.DiffTooltip, { annotations: annotation ? [annotation] : [], description: getAction(diff), children: /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(
547
+ GoogleMap,
548
+ {
549
+ api,
550
+ location: center,
551
+ mapTypeControl: !1,
552
+ controlSize: 20,
553
+ bounds,
554
+ scrollWheel: !1,
555
+ children: (map) => /* @__PURE__ */ jsxRuntime.jsx(GeopointMove, { api, map, diff })
556
+ }
557
+ ) }) });
558
+ }
559
+ function getBounds(fromValue, toValue, api) {
560
+ return new api.LatLngBounds().extend(fromValue).extend(toValue);
561
+ }
562
+ function getCenter(diff, api) {
563
+ const { fromValue, toValue } = diff;
564
+ if (fromValue && toValue)
565
+ return getBounds(fromValue, toValue, api).getCenter().toJSON();
566
+ if (fromValue)
567
+ return fromValue;
568
+ if (toValue)
569
+ return toValue;
570
+ throw new Error("Neither a from or a to value present");
571
+ }
572
+ function getAction(diff) {
573
+ const { fromValue, toValue } = diff;
574
+ return fromValue && toValue ? "Moved" : fromValue ? "Removed" : toValue ? "Added" : "Unchanged";
575
+ }
576
+ var __defProp = Object.defineProperty, __defProps = Object.defineProperties, __getOwnPropDescs = Object.getOwnPropertyDescriptors, __getOwnPropSymbols = Object.getOwnPropertySymbols, __hasOwnProp = Object.prototype.hasOwnProperty, __propIsEnum = Object.prototype.propertyIsEnumerable, __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: !0, configurable: !0, writable: !0, value }) : obj[key] = value, __spreadValues = (a, b) => {
577
+ for (var prop in b || (b = {}))
578
+ __hasOwnProp.call(b, prop) && __defNormalProp(a, prop, b[prop]);
579
+ if (__getOwnPropSymbols)
580
+ for (var prop of __getOwnPropSymbols(b))
581
+ __propIsEnum.call(b, prop) && __defNormalProp(a, prop, b[prop]);
582
+ return a;
583
+ }, __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
584
+ const googleMapsInput = sanity.definePlugin((config2) => (setGeoConfig(config2), {
585
+ name: "google-maps-input",
586
+ form: {
587
+ components: {
588
+ input(props) {
589
+ return isGeopoint(props.schemaType) ? /* @__PURE__ */ jsxRuntime.jsx(GeopointInput, __spreadProps(__spreadValues({}, props), { geoConfig: config2 })) : props.renderDefault(props);
590
+ }
591
+ }
592
+ }
593
+ }));
594
+ function isGeopoint(schemaType) {
595
+ return isType("geopoint", schemaType);
596
+ }
597
+ function isType(name, schema) {
598
+ return (schema == null ? void 0 : schema.name) === name ? !0 : schema != null && schema.name ? isType(name, schema == null ? void 0 : schema.type) : !1;
599
+ }
600
+ exports.GeopointArrayDiff = GeopointArrayDiff;
601
+ exports.GeopointFieldDiff = GeopointFieldDiff;
602
+ exports.GeopointInput = GeopointInput;
603
+ exports.googleMapsInput = googleMapsInput;
604
+ //# sourceMappingURL=index.cjs.map