carbon-addons-iot-react 5.8.0 → 5.8.2

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.
@@ -315,6 +315,7 @@ var HotspotEditorModal = function HotspotEditorModal(_ref) {
315
315
  switchCurrentType = _useHotspotEditorStat.switchCurrentType,
316
316
  updateHotspotDataSource = _useHotspotEditorStat.updateHotspotDataSource,
317
317
  updateHotspotTooltip = _useHotspotEditorStat.updateHotspotTooltip,
318
+ updateHotspotPosition = _useHotspotEditorStat.updateHotspotPosition,
318
319
  updateTextHotspotStyle = _useHotspotEditorStat.updateTextHotspotStyle,
319
320
  updateTextHotspotContent = _useHotspotEditorStat.updateTextHotspotContent,
320
321
  updateDynamicHotspotSourceX = _useHotspotEditorStat.updateDynamicHotspotSourceX,
@@ -380,6 +381,8 @@ var HotspotEditorModal = function HotspotEditorModal(_ref) {
380
381
  }
381
382
  var hotspotsWithoutExampleValues = filteredHotspots.map(function (hotspot) {
382
383
  return update(hotspot, {
384
+ $unset: ['id'],
385
+ // Remove the internal id added for drag tracking
383
386
  content: {
384
387
  $unset: ['values']
385
388
  }
@@ -629,6 +632,7 @@ var HotspotEditorModal = function HotspotEditorModal(_ref) {
629
632
  hotspotDefaults: hotspotDefaults
630
633
  });
631
634
  },
635
+ onUpdateHotspotPosition: updateHotspotPosition,
632
636
  onSelectHotspot: setSelectedHotspot,
633
637
  selectedHotspots: getSelectedHotspotsList(selectedHotspot, hotspots),
634
638
  src: cardConfig.content.src,
@@ -49,6 +49,7 @@ var hotspotActionTypes = {
49
49
  hotspotDataSourceChange: 'HOTSPOT_DATA_SOURCE_CHANGE',
50
50
  hotspotDataSourceSettingsChange: 'HOTSPOT_DATA_SOURCE_SETTINGS_CHANGE',
51
51
  hotspotTooltipChange: 'HOTSPOT_TOOLTIP_CHANGE',
52
+ hotspotPositionChange: 'HOTSPOT_POSITION_CHANGE',
52
53
  hotspotSelect: 'HOTSPOT_SELECT',
53
54
  hotspotsAdd: 'HOTSPOTS_ADD',
54
55
  textHotspotStyleChange: 'TEXT_HOTSPOT_STYLE_CHANGE',
@@ -151,10 +152,32 @@ function hotspotEditorReducer(state, _ref2) {
151
152
  };
152
153
  return getHotspotUpdate(state, _mergeSpec);
153
154
  }
155
+ // HOTSPOT POSITION CHANGE
156
+ case hotspotActionTypes.hotspotPositionChange:
157
+ {
158
+ var isPositionAvailable = !state.hotspots.find(function (hotspot) {
159
+ return isHotspotMatch(hotspot, payload.position);
160
+ });
161
+ if (isPositionAvailable) {
162
+ // Find the updated hotspot in the new hotspots array to maintain selection
163
+ var updatedSelectedHotspot = payload.newHotspots.find(function (hotspot) {
164
+ return isHotspotMatch(hotspot, payload.position);
165
+ });
166
+ return update(state, {
167
+ hotspots: {
168
+ $set: payload.newHotspots
169
+ },
170
+ selectedHotspot: {
171
+ $set: updatedSelectedHotspot
172
+ }
173
+ });
174
+ }
175
+ return state;
176
+ }
154
177
  // HOTSPOTS ADD
155
178
  case hotspotActionTypes.hotspotsAdd:
156
179
  {
157
- var isPositionAvailable = !state.hotspots.find(function (hotspot) {
180
+ var _isPositionAvailable = !state.hotspots.find(function (hotspot) {
158
181
  return isHotspotMatch(hotspot, payload.position);
159
182
  });
160
183
  var defaultContent = state.currentType === hotspotTypes.TEXT ? {
@@ -165,7 +188,7 @@ function hotspotEditorReducer(state, _ref2) {
165
188
  content: defaultContent,
166
189
  type: createableType
167
190
  });
168
- return isPositionAvailable ? update(state, {
191
+ return _isPositionAvailable ? update(state, {
169
192
  selectedHotspot: {
170
193
  $set: newHotspot
171
194
  },
@@ -193,7 +216,7 @@ function hotspotEditorReducer(state, _ref2) {
193
216
  $set: hotspot
194
217
  },
195
218
  currentType: {
196
- $set: (_hotspot$type = hotspot.type) !== null && _hotspot$type !== void 0 ? _hotspot$type : defaultTypeWhenMissing
219
+ $set: (_hotspot$type = hotspot === null || hotspot === void 0 ? void 0 : hotspot.type) !== null && _hotspot$type !== void 0 ? _hotspot$type : defaultTypeWhenMissing
197
220
  }
198
221
  });
199
222
  }
@@ -392,6 +415,12 @@ function useHotspotEditorState() {
392
415
  payload: hotspotContent
393
416
  });
394
417
  };
418
+ var updateHotspotPosition = function updateHotspotPosition(hotspotPosition) {
419
+ return dispatch({
420
+ type: hotspotActionTypes.hotspotPositionChange,
421
+ payload: hotspotPosition
422
+ });
423
+ };
395
424
 
396
425
  /** Updates the properties of the text hotspot, passes a payload like {color: 'blue'} */
397
426
  var updateTextHotspotStyle = function updateTextHotspotStyle(textHotspotStyle) {
@@ -479,6 +508,7 @@ function useHotspotEditorState() {
479
508
  switchCurrentType: switchCurrentType,
480
509
  updateHotspotDataSource: updateHotspotDataSource,
481
510
  updateHotspotTooltip: updateHotspotTooltip,
511
+ updateHotspotPosition: updateHotspotPosition,
482
512
  updateTextHotspotStyle: updateTextHotspotStyle,
483
513
  updateTextHotspotContent: updateTextHotspotContent,
484
514
  updateDynamicHotspotSourceX: updateDynamicHotspotSourceX,
@@ -174,7 +174,7 @@ var HotspotContent = function HotspotContent(_ref) {
174
174
  }, typeof value === 'number' ? formatNumberWithPrecision(value, !isNil(precision) ? precision : Math.abs(value) < 1 ? value === 0 ? 0 : 3 // for small decimals give 3 spots
175
175
  : 1,
176
176
  // otherwise 1 spot if precision isn't set
177
- locale) : value, unit && value !== '--' && /*#__PURE__*/React__default.createElement("span", {
177
+ locale) : typeof value === 'boolean' ? String(value) : value, unit && value !== '--' && /*#__PURE__*/React__default.createElement("span", {
178
178
  className: "".concat(iotPrefix, "--hotspot-content-unit")
179
179
  }, unit))));
180
180
  }));
@@ -16,7 +16,7 @@ import 'core-js/modules/es.object.keys.js';
16
16
  import 'core-js/modules/es.object.to-string.js';
17
17
  import 'core-js/modules/web.dom-collections.for-each.js';
18
18
  import 'core-js/modules/web.dom-collections.iterator.js';
19
- import React__default, { useState, useMemo, useCallback, useEffect } from 'react';
19
+ import React__default, { useState, useRef, useMemo, useEffect, useCallback } from 'react';
20
20
  import PropTypes from 'prop-types';
21
21
  import { InlineLoading } from '@carbon/react';
22
22
  import warning from 'warning';
@@ -75,6 +75,10 @@ var propTypes = {
75
75
  * Emits position obj {x, y} of hotspot to be added.
76
76
  */
77
77
  onAddHotspotPosition: PropTypes.func,
78
+ /** Callback when a hotspot is dragged to new position in isEditable mode
79
+ * Emits new hotspots and updated position obj {x, y} of hotspot.
80
+ */
81
+ onUpdateHotspotPosition: PropTypes.func,
78
82
  /** Callback when a hotspot is clicked in isEditable mode, emits position obj {x, y} */
79
83
  onSelectHotspot: PropTypes.func,
80
84
  /**
@@ -115,6 +119,7 @@ var defaultProps = {
115
119
  isHotspotDataLoading: false,
116
120
  isEditable: false,
117
121
  onAddHotspotPosition: function onAddHotspotPosition() {},
122
+ onUpdateHotspotPosition: function onUpdateHotspotPosition() {},
118
123
  onSelectHotspot: function onSelectHotspot() {},
119
124
  onHotspotContentChanged: function onHotspotContentChanged() {},
120
125
  background: '#eee',
@@ -233,6 +238,7 @@ var calculateHotspotContainerLayout = function calculateHotspotContainerLayout(_
233
238
  var width;
234
239
  var height;
235
240
  var top;
241
+ var left;
236
242
 
237
243
  // CONTAIN
238
244
  if (objectFit === 'contain') {
@@ -240,32 +246,38 @@ var calculateHotspotContainerLayout = function calculateHotspotContainerLayout(_
240
246
  width = imageWidth;
241
247
  height = imageWidth / imageRatio;
242
248
  top = imageScale > 1 ? imageOffsetY : imageObjectFitOffsetY;
249
+ left = imageScale > 1 ? 0 : (containerWidth - imageWidth) / 2;
243
250
  } else if (imageOrientation === 'portrait') {
244
251
  width = imageHeight / imageRatio;
245
252
  height = imageHeight;
246
253
  top = imageOffsetY;
254
+ left = (containerWidth - width) / 2;
247
255
  }
248
256
  // FILL
249
257
  } else if (objectFit === 'fill') {
250
258
  width = imageScale > 1 ? imageWidth : containerWidth;
251
259
  height = imageScale > 1 ? imageHeight : containerHeight;
252
260
  top = imageOffsetY;
261
+ left = 0;
253
262
  // NO OBJECT FIT
254
263
  } else if (!objectFit) {
255
264
  if (imageOrientation === 'landscape') {
256
265
  width = imageWidth;
257
266
  height = imageWidth / imageRatio;
258
267
  top = imageOffsetY;
268
+ left = 0;
259
269
  } else if (imageOrientation === 'portrait') {
260
270
  width = imageHeight / imageRatio;
261
271
  height = imageHeight;
262
272
  top = imageOffsetY;
273
+ left = (containerWidth - width) / 2;
263
274
  }
264
275
  }
265
276
  return {
266
277
  width: width,
267
278
  height: height,
268
- top: top
279
+ top: top,
280
+ left: left
269
281
  };
270
282
  };
271
283
  var calculateObjectFitOffset = function calculateObjectFitOffset(_ref5) {
@@ -510,6 +522,7 @@ var ImageHotspots = function ImageHotspots(_ref9) {
510
522
  isEditable = _ref9.isEditable,
511
523
  isHotspotDataLoading = _ref9.isHotspotDataLoading,
512
524
  onAddHotspotPosition = _ref9.onAddHotspotPosition,
525
+ onUpdateHotspotPosition = _ref9.onUpdateHotspotPosition,
513
526
  onSelectHotspot = _ref9.onSelectHotspot,
514
527
  onHotspotContentChanged = _ref9.onHotspotContentChanged,
515
528
  zoomMax = _ref9.zoomMax,
@@ -554,9 +567,52 @@ var ImageHotspots = function ImageHotspots(_ref9) {
554
567
  _useState12 = _slicedToArray(_useState11, 2),
555
568
  options = _useState12[0],
556
569
  setOptions = _useState12[1];
570
+ // Tracks if a hotspot is being dragged and which one.
571
+ var _useState13 = useState(null),
572
+ _useState14 = _slicedToArray(_useState13, 2),
573
+ draggingHotspotId = _useState14[0],
574
+ setDraggingHotspotId = _useState14[1];
575
+
576
+ // Ref for outer container
577
+ var containerRef = useRef(null);
578
+ var dragStateRef = useRef({
579
+ // Flag to indicate if a drag is active
580
+ isDragging: false,
581
+ // Stores the starting mouse position of a drag
582
+ dragStartPosition: {
583
+ x: 0,
584
+ y: 0
585
+ },
586
+ // Tracks the current position during a drag
587
+ currentDargPosition: null,
588
+ // Stores layout of image and container
589
+ layout: {
590
+ rect: null,
591
+ hotspotLayout: null
592
+ },
593
+ // Tracks Scheduled Animation Frames
594
+ frame: null
595
+ });
596
+
597
+ // Minimum pixel movement before a drag is initiated
598
+ var DRAG_THRESHOLD = 5;
557
599
  var mergedI18n = useMemo(function () {
558
600
  return _objectSpread(_objectSpread({}, defaultProps.i18n), i18n);
559
601
  }, [i18n]);
602
+ var hotspotsWithId = useMemo(function () {
603
+ return hotspots.map(function (hotspot, index) {
604
+ return _objectSpread(_objectSpread({}, hotspot), {}, {
605
+ id: "".concat(hotspot.x, "-").concat(hotspot.y, "-").concat(index)
606
+ });
607
+ });
608
+ }, [hotspots]);
609
+ var _useState15 = useState(hotspotsWithId),
610
+ _useState16 = _slicedToArray(_useState15, 2),
611
+ editableHotspots = _useState16[0],
612
+ setEditableHotspots = _useState16[1];
613
+ useEffect(function () {
614
+ setEditableHotspots(hotspotsWithId);
615
+ }, [hotspotsWithId]);
560
616
  var handleCtrlKeyUp = useCallback(function (event) {
561
617
  // Was the control key unpressed
562
618
  if (event.key === keyboardKeys.CONTROL) {
@@ -628,6 +684,11 @@ var ImageHotspots = function ImageHotspots(_ref9) {
628
684
  objectFit: displayOption
629
685
  };
630
686
  var onHotspotClicked = useCallback(function (evt, position) {
687
+ // prevent click behavior after drag
688
+ if (dragStateRef.current.isDragging) {
689
+ return;
690
+ }
691
+
631
692
  // It is possible to receive two events here, one Mouse event and one Pointer event.
632
693
  // When used in the ImageHotspots component the Pointer event can somehow be from a
633
694
  // previously clicked hotspot. See https://github.com/carbon-design-system/carbon-addons-iot-react/issues/1803
@@ -636,6 +697,108 @@ var ImageHotspots = function ImageHotspots(_ref9) {
636
697
  onSelectHotspot(position);
637
698
  }
638
699
  }, [onSelectHotspot, isEditable]);
700
+ var handleMouseDownHotspot = useCallback(function (e, id1) {
701
+ var hotspot = editableHotspots.find(function (h) {
702
+ return h.id === id1;
703
+ });
704
+ if (!isEditable || (hotspot === null || hotspot === void 0 ? void 0 : hotspot.type) === 'dynamic') {
705
+ return;
706
+ }
707
+ e.stopPropagation();
708
+ setDraggingHotspotId(id1);
709
+ dragStateRef.current.isDragging = true;
710
+ dragStateRef.current.dragStartPosition = {
711
+ x: e.clientX,
712
+ y: e.clientY
713
+ };
714
+
715
+ // Calculate layout once at drag start
716
+ if (containerRef.current) {
717
+ var rect = containerRef.current.getBoundingClientRect();
718
+ var hotspotLayout = calculateHotspotContainerLayout(image, container, displayOption);
719
+ dragStateRef.current.layout = {
720
+ rect: rect,
721
+ hotspotLayout: hotspotLayout
722
+ };
723
+ }
724
+ }, [container, displayOption, image, isEditable, editableHotspots]);
725
+ var handleMouseMoveHotspot = useCallback(function (e) {
726
+ if (draggingHotspotId !== null && containerRef.current) {
727
+ var _dragStateRef$current = dragStateRef.current,
728
+ isDragging = _dragStateRef$current.isDragging,
729
+ dragStartPosition = _dragStateRef$current.dragStartPosition,
730
+ layout = _dragStateRef$current.layout;
731
+ var dx = e.clientX - dragStartPosition.x;
732
+ var dy = e.clientY - dragStartPosition.y;
733
+ var distance = Math.sqrt(dx * dx + dy * dy);
734
+ if (distance > DRAG_THRESHOLD && isDragging) {
735
+ var rect = layout.rect,
736
+ hotspotLayout = layout.hotspotLayout;
737
+ var x = (e.clientX - rect.left - hotspotLayout.left) / hotspotLayout.width * 100;
738
+ var y = (e.clientY - rect.top - hotspotLayout.top) / hotspotLayout.height * 100;
739
+ // Clamp within image boundaries
740
+ x = Math.max(0, Math.min(100, x));
741
+ y = Math.max(0, Math.min(100, y));
742
+ dragStateRef.current.currentDargPosition = {
743
+ x: x,
744
+ y: y
745
+ };
746
+
747
+ // throttle with requestAnimationFrame
748
+ if (dragStateRef.current.frame === null) {
749
+ dragStateRef.current.frame = requestAnimationFrame(function () {
750
+ setEditableHotspots(function (prev) {
751
+ return prev.map(function (item) {
752
+ return item.id === draggingHotspotId ? _objectSpread(_objectSpread({}, item), {}, {
753
+ x: dragStateRef.current.currentDargPosition.x,
754
+ y: dragStateRef.current.currentDargPosition.y
755
+ }) : item;
756
+ });
757
+ });
758
+ dragStateRef.current.frame = null;
759
+ });
760
+ }
761
+ }
762
+ }
763
+ }, [draggingHotspotId]);
764
+ var handleMouseUpHotspot = useCallback(function (e) {
765
+ if (draggingHotspotId !== null && dragStateRef.current.isDragging) {
766
+ e.stopPropagation();
767
+ var _ref10 = dragStateRef.current.currentDargPosition || {},
768
+ x = _ref10.x,
769
+ y = _ref10.y;
770
+ onUpdateHotspotPosition({
771
+ newHotspots: editableHotspots,
772
+ position: {
773
+ x: x,
774
+ y: y
775
+ }
776
+ });
777
+ setDraggingHotspotId(null);
778
+ dragStateRef.current.currentDargPosition = null;
779
+ dragStateRef.current.isDragging = false;
780
+ }
781
+ }, [editableHotspots, draggingHotspotId, onUpdateHotspotPosition]);
782
+ useEffect(function () {
783
+ var dragState = dragStateRef.current;
784
+ return function () {
785
+ if (dragState.frame !== null) {
786
+ cancelAnimationFrame(dragState.frame);
787
+ }
788
+ };
789
+ }, []);
790
+
791
+ // Listens to mouse movement for dragging hotspot
792
+ useEffect(function () {
793
+ if (!isEditable) return undefined;
794
+ var containerElement = containerRef.current;
795
+ containerElement.addEventListener('mousemove', handleMouseMoveHotspot);
796
+ containerElement.addEventListener('mouseup', handleMouseUpHotspot);
797
+ return function () {
798
+ containerElement.removeEventListener('mousemove', handleMouseMoveHotspot);
799
+ containerElement.removeEventListener('mouseup', handleMouseUpHotspot);
800
+ };
801
+ }, [draggingHotspotId, handleMouseMoveHotspot, handleMouseUpHotspot, isEditable]);
639
802
  var getIconRenderFunction = useCallback(function () {
640
803
  return renderIconByName || (Array.isArray(icons) ? function (name, props) {
641
804
  var _icons$find;
@@ -654,7 +817,7 @@ var ImageHotspots = function ImageHotspots(_ref9) {
654
817
 
655
818
  // Performance improvement
656
819
  var cachedHotspots = useMemo(function () {
657
- return hotspots.map(function (hotspot, index) {
820
+ return editableHotspots.map(function (hotspot, index) {
658
821
  var _hotspot$content;
659
822
  var x = hotspot.x,
660
823
  y = hotspot.y;
@@ -664,10 +827,10 @@ var ImageHotspots = function ImageHotspots(_ref9) {
664
827
  // Determine whether the icon needs to be dynamically overridden by a threshold
665
828
  var matchingAttributeThresholds = [];
666
829
  if ((_hotspot$content = hotspot.content) !== null && _hotspot$content !== void 0 && _hotspot$content.attributes) {
667
- hotspot.content.attributes.forEach(function (_ref10) {
830
+ hotspot.content.attributes.forEach(function (_ref11) {
668
831
  var _hotspot$content2;
669
- var thresholds = _ref10.thresholds,
670
- dataSourceId = _ref10.dataSourceId;
832
+ var thresholds = _ref11.thresholds,
833
+ dataSourceId = _ref11.dataSourceId;
671
834
  if (!isEmpty(thresholds) && !isEmpty((_hotspot$content2 = hotspot.content) === null || _hotspot$content2 === void 0 ? void 0 : _hotspot$content2.values)) {
672
835
  var _hotspot$content3;
673
836
  var attributeThresholds = findMatchingThresholds(thresholds.map(function (threshold) {
@@ -693,10 +856,13 @@ var ImageHotspots = function ImageHotspots(_ref9) {
693
856
  key: "".concat(x, "-").concat(y, "-").concat(index),
694
857
  renderIconByName: getIconRenderFunction(),
695
858
  isSelected: hotspotIsSelected,
696
- onClick: onHotspotClicked
859
+ onClick: onHotspotClicked,
860
+ onMouseDown: function onMouseDown(e) {
861
+ return handleMouseDownHotspot(e, hotspot.id);
862
+ }
697
863
  }));
698
864
  });
699
- }, [hotspots, selectedHotspots, locale, getIconRenderFunction, isEditable, onHotspotContentChanged, mergedI18n, onHotspotClicked]);
865
+ }, [editableHotspots, selectedHotspots, locale, getIconRenderFunction, isEditable, onHotspotContentChanged, mergedI18n, onHotspotClicked, handleMouseDownHotspot]);
700
866
  var hotspotsStyle = {
701
867
  position: 'absolute',
702
868
  left: image.offsetX,
@@ -739,7 +905,8 @@ var ImageHotspots = function ImageHotspots(_ref9) {
739
905
  // If we leave the container, stop detecting the drag
740
906
  stopDrag(cursor, setCursor);
741
907
  }
742
- }
908
+ },
909
+ ref: containerRef
743
910
  }, src ? /*#__PURE__*/React__default.createElement("img", {
744
911
  id: id,
745
912
  className: "".concat(iotPrefix, "--image-card-img"),
@@ -966,6 +1133,17 @@ ImageHotspots.__docgenInfo = {
966
1133
  },
967
1134
  "required": false
968
1135
  },
1136
+ "onUpdateHotspotPosition": {
1137
+ "defaultValue": {
1138
+ "value": "() => {}",
1139
+ "computed": false
1140
+ },
1141
+ "description": "Callback when a hotspot is dragged to new position in isEditable mode\nEmits new hotspots and updated position obj {x, y} of hotspot.",
1142
+ "type": {
1143
+ "name": "func"
1144
+ },
1145
+ "required": false
1146
+ },
969
1147
  "onSelectHotspot": {
970
1148
  "defaultValue": {
971
1149
  "value": "() => {}",
@@ -332,6 +332,7 @@ var HotspotEditorModal = function HotspotEditorModal(_ref) {
332
332
  switchCurrentType = _useHotspotEditorStat.switchCurrentType,
333
333
  updateHotspotDataSource = _useHotspotEditorStat.updateHotspotDataSource,
334
334
  updateHotspotTooltip = _useHotspotEditorStat.updateHotspotTooltip,
335
+ updateHotspotPosition = _useHotspotEditorStat.updateHotspotPosition,
335
336
  updateTextHotspotStyle = _useHotspotEditorStat.updateTextHotspotStyle,
336
337
  updateTextHotspotContent = _useHotspotEditorStat.updateTextHotspotContent,
337
338
  updateDynamicHotspotSourceX = _useHotspotEditorStat.updateDynamicHotspotSourceX,
@@ -397,6 +398,8 @@ var HotspotEditorModal = function HotspotEditorModal(_ref) {
397
398
  }
398
399
  var hotspotsWithoutExampleValues = filteredHotspots.map(function (hotspot) {
399
400
  return update__default.default(hotspot, {
401
+ $unset: ['id'],
402
+ // Remove the internal id added for drag tracking
400
403
  content: {
401
404
  $unset: ['values']
402
405
  }
@@ -646,6 +649,7 @@ var HotspotEditorModal = function HotspotEditorModal(_ref) {
646
649
  hotspotDefaults: hotspotDefaults
647
650
  });
648
651
  },
652
+ onUpdateHotspotPosition: updateHotspotPosition,
649
653
  onSelectHotspot: setSelectedHotspot,
650
654
  selectedHotspots: getSelectedHotspotsList(selectedHotspot, hotspots),
651
655
  src: cardConfig.content.src,
@@ -77,6 +77,7 @@ var hotspotActionTypes = {
77
77
  hotspotDataSourceChange: 'HOTSPOT_DATA_SOURCE_CHANGE',
78
78
  hotspotDataSourceSettingsChange: 'HOTSPOT_DATA_SOURCE_SETTINGS_CHANGE',
79
79
  hotspotTooltipChange: 'HOTSPOT_TOOLTIP_CHANGE',
80
+ hotspotPositionChange: 'HOTSPOT_POSITION_CHANGE',
80
81
  hotspotSelect: 'HOTSPOT_SELECT',
81
82
  hotspotsAdd: 'HOTSPOTS_ADD',
82
83
  textHotspotStyleChange: 'TEXT_HOTSPOT_STYLE_CHANGE',
@@ -179,10 +180,32 @@ function hotspotEditorReducer(state, _ref2) {
179
180
  };
180
181
  return getHotspotUpdate(state, _mergeSpec);
181
182
  }
183
+ // HOTSPOT POSITION CHANGE
184
+ case hotspotActionTypes.hotspotPositionChange:
185
+ {
186
+ var isPositionAvailable = !state.hotspots.find(function (hotspot) {
187
+ return isHotspotMatch(hotspot, payload.position);
188
+ });
189
+ if (isPositionAvailable) {
190
+ // Find the updated hotspot in the new hotspots array to maintain selection
191
+ var updatedSelectedHotspot = payload.newHotspots.find(function (hotspot) {
192
+ return isHotspotMatch(hotspot, payload.position);
193
+ });
194
+ return update__default.default(state, {
195
+ hotspots: {
196
+ $set: payload.newHotspots
197
+ },
198
+ selectedHotspot: {
199
+ $set: updatedSelectedHotspot
200
+ }
201
+ });
202
+ }
203
+ return state;
204
+ }
182
205
  // HOTSPOTS ADD
183
206
  case hotspotActionTypes.hotspotsAdd:
184
207
  {
185
- var isPositionAvailable = !state.hotspots.find(function (hotspot) {
208
+ var _isPositionAvailable = !state.hotspots.find(function (hotspot) {
186
209
  return isHotspotMatch(hotspot, payload.position);
187
210
  });
188
211
  var defaultContent = state.currentType === hotspotTypes.TEXT ? {
@@ -193,7 +216,7 @@ function hotspotEditorReducer(state, _ref2) {
193
216
  content: defaultContent,
194
217
  type: createableType
195
218
  });
196
- return isPositionAvailable ? update__default.default(state, {
219
+ return _isPositionAvailable ? update__default.default(state, {
197
220
  selectedHotspot: {
198
221
  $set: newHotspot
199
222
  },
@@ -221,7 +244,7 @@ function hotspotEditorReducer(state, _ref2) {
221
244
  $set: hotspot
222
245
  },
223
246
  currentType: {
224
- $set: (_hotspot$type = hotspot.type) !== null && _hotspot$type !== void 0 ? _hotspot$type : defaultTypeWhenMissing
247
+ $set: (_hotspot$type = hotspot === null || hotspot === void 0 ? void 0 : hotspot.type) !== null && _hotspot$type !== void 0 ? _hotspot$type : defaultTypeWhenMissing
225
248
  }
226
249
  });
227
250
  }
@@ -420,6 +443,12 @@ function useHotspotEditorState() {
420
443
  payload: hotspotContent
421
444
  });
422
445
  };
446
+ var updateHotspotPosition = function updateHotspotPosition(hotspotPosition) {
447
+ return dispatch({
448
+ type: hotspotActionTypes.hotspotPositionChange,
449
+ payload: hotspotPosition
450
+ });
451
+ };
423
452
 
424
453
  /** Updates the properties of the text hotspot, passes a payload like {color: 'blue'} */
425
454
  var updateTextHotspotStyle = function updateTextHotspotStyle(textHotspotStyle) {
@@ -507,6 +536,7 @@ function useHotspotEditorState() {
507
536
  switchCurrentType: switchCurrentType,
508
537
  updateHotspotDataSource: updateHotspotDataSource,
509
538
  updateHotspotTooltip: updateHotspotTooltip,
539
+ updateHotspotPosition: updateHotspotPosition,
510
540
  updateTextHotspotStyle: updateTextHotspotStyle,
511
541
  updateTextHotspotContent: updateTextHotspotContent,
512
542
  updateDynamicHotspotSourceX: updateDynamicHotspotSourceX,
@@ -182,7 +182,7 @@ var HotspotContent = function HotspotContent(_ref) {
182
182
  }, typeof value === 'number' ? cardUtilityFunctions.formatNumberWithPrecision(value, !isNil(precision) ? precision : Math.abs(value) < 1 ? value === 0 ? 0 : 3 // for small decimals give 3 spots
183
183
  : 1,
184
184
  // otherwise 1 spot if precision isn't set
185
- locale) : value, unit && value !== '--' && /*#__PURE__*/React__default.default.createElement("span", {
185
+ locale) : typeof value === 'boolean' ? String(value) : value, unit && value !== '--' && /*#__PURE__*/React__default.default.createElement("span", {
186
186
  className: "".concat(iotPrefix, "--hotspot-content-unit")
187
187
  }, unit))));
188
188
  }));