Skip to content

Commit e838770

Browse files
Merge pull request #1951 from carbon-design-system/fix-hotspot-1897
fix(hotspoteditormodal): make the user hold CTRL key before adding hotspots
2 parents 13370bc + 66bb505 commit e838770

8 files changed

Lines changed: 51 additions & 15 deletions

File tree

packages/react/src/components/HotspotEditorModal/HotspotEditorTooltipTab/HotspotEditorTooltipTab.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ const defaultProps = {
8383
iconDropdownLabelText: 'Select an icon',
8484
iconDropdownTitleText: 'Icon',
8585
infoMessageText:
86-
'Click a position on the image to add a hotspot, or set the X and Y coordinates using dataitems and create hotspots at those positions.',
86+
'Hold the CTRL key and click a position on the image to add a hotspot, or set the X and Y coordinates using dataitems and create hotspots at those positions.',
8787
colorDropdownLabelText: 'Select a color',
8888
colorDropdownTitleText: 'Color',
8989
},

packages/react/src/components/HotspotEditorModal/HotspotEditorTooltipTab/__snapshots__/HotspotEditorTooltipTab.story.storyshot

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ exports[`Storybook Snapshot tests and console checks Storyshots Watson IoT Exper
326326
/>
327327
</svg>
328328
<p>
329-
Click a position on the image to add a hotspot, or set the X and Y coordinates using dataitems and create hotspots at those positions.
329+
Hold the CTRL key and click a position on the image to add a hotspot, or set the X and Y coordinates using dataitems and create hotspots at those positions.
330330
</p>
331331
</div>
332332
</div>

packages/react/src/components/HotspotEditorModal/HotspotTextStyleTab/HotspotTextStyleTab.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ const defaultProps = {
8282
i18n: {
8383
boldLabelText: 'Text Bold',
8484
infoMessageText:
85-
'Select an existing label on the image to edit it or click on an empty region to create one',
85+
'Select an existing label on the image to edit it or hold the CTRL key and click on an empty region to create one',
8686
italicLabelText: 'Text Italic',
8787
underlineLabelText: 'Text Underline',
8888
fontColorLabelText: 'Font color',

packages/react/src/components/HotspotEditorModal/__snapshots__/HotspotEditorModal.story.storyshot

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ exports[`Storybook Snapshot tests and console checks Storyshots Watson IoT Exper
400400
/>
401401
</svg>
402402
<p>
403-
Click a position on the image to add a hotspot, or set the X and Y coordinates using dataitems and create hotspots at those positions.
403+
Hold the CTRL key and click a position on the image to add a hotspot, or set the X and Y coordinates using dataitems and create hotspots at those positions.
404404
</p>
405405
</div>
406406
</div>
@@ -872,7 +872,7 @@ exports[`Storybook Snapshot tests and console checks Storyshots Watson IoT Exper
872872
/>
873873
</svg>
874874
<p>
875-
Click a position on the image to add a hotspot, or set the X and Y coordinates using dataitems and create hotspots at those positions.
875+
Hold the CTRL key and click a position on the image to add a hotspot, or set the X and Y coordinates using dataitems and create hotspots at those positions.
876876
</p>
877877
</div>
878878
</div>
@@ -1808,7 +1808,7 @@ exports[`Storybook Snapshot tests and console checks Storyshots Watson IoT Exper
18081808
/>
18091809
</svg>
18101810
<p>
1811-
Click a position on the image to add a hotspot, or set the X and Y coordinates using dataitems and create hotspots at those positions.
1811+
Hold the CTRL key and click a position on the image to add a hotspot, or set the X and Y coordinates using dataitems and create hotspots at those positions.
18121812
</p>
18131813
</div>
18141814
</div>
@@ -2280,7 +2280,7 @@ exports[`Storybook Snapshot tests and console checks Storyshots Watson IoT Exper
22802280
/>
22812281
</svg>
22822282
<p>
2283-
Click a position on the image to add a hotspot, or set the X and Y coordinates using dataitems and create hotspots at those positions.
2283+
Hold the CTRL key and click a position on the image to add a hotspot, or set the X and Y coordinates using dataitems and create hotspots at those positions.
22842284
</p>
22852285
</div>
22862286
</div>

packages/react/src/components/ImageCard/ImageHotspots.jsx

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,8 @@ const ImageHotspots = ({
411411
selectedHotspots,
412412
displayOption,
413413
}) => {
414+
// Need to keep track of whether the Ctrl key is currently pressed because we want to only add hotspots in that case
415+
const [isCtrlPressed, setIsCtrlPressed] = useState();
414416
// Image needs to be stored in state because we're dragging it around when zoomed in, and we need to keep track of when it loads
415417
const [image, setImage] = useState({});
416418
// Minimap needs to be stored in state because we're dragging it around when zoomed in
@@ -430,6 +432,28 @@ const ImageHotspots = ({
430432

431433
const mergedI18n = useMemo(() => ({ ...defaultProps.i18n, ...i18n }), [i18n]);
432434

435+
const handleCtrlKeyUp = useCallback((event) => {
436+
// Was the control key unpressed
437+
if (event.keyCode === 17) {
438+
setIsCtrlPressed(false);
439+
}
440+
}, []);
441+
const handleCtrlKeyDown = useCallback((event) => {
442+
if (event.ctrlKey) {
443+
setIsCtrlPressed(true);
444+
}
445+
}, []);
446+
447+
// Listen to the control key to add hotspots
448+
useEffect(() => {
449+
window.addEventListener('keydown', handleCtrlKeyDown);
450+
window.addEventListener('keyup', handleCtrlKeyUp);
451+
return () => {
452+
window.removeEventListener('keydown', handleCtrlKeyDown);
453+
window.removeEventListener('keyup', handleCtrlKeyUp);
454+
};
455+
}, [handleCtrlKeyDown, handleCtrlKeyUp]);
456+
433457
useEffect(() => {
434458
setOptions({
435459
hideZoomControls: hideZoomControlsProp,
@@ -472,7 +496,7 @@ const ImageHotspots = ({
472496
};
473497

474498
const imageStyle = {
475-
cursor: isEditable && !dragging ? 'crosshair' : 'auto',
499+
cursor: isEditable && !dragging && isCtrlPressed ? 'crosshair' : 'auto',
476500
position: 'relative',
477501
left: image.offsetX,
478502
top: image.offsetY,
@@ -587,6 +611,14 @@ const ImageHotspots = ({
587611
/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */
588612
return (
589613
<div
614+
onContextMenu={
615+
isEditable
616+
? (event) => {
617+
// if we're in edit mode, prevent the CTRL-click context menu from popping
618+
event.preventDefault();
619+
}
620+
: undefined
621+
}
590622
style={containerStyle}
591623
onMouseOut={() => {
592624
if (dragging) {
@@ -638,7 +670,7 @@ const ImageHotspots = ({
638670
cursor,
639671
setCursor,
640672
isEditable,
641-
callback: onAddHotspotPosition,
673+
callback: event.ctrlKey ? onAddHotspotPosition : undefined,
642674
});
643675
}
644676
}}

packages/react/src/components/ImageCard/ImageHotspots.test.jsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -307,8 +307,9 @@ describe('ImageHotspots', () => {
307307
selectedHotspots={[]}
308308
/>
309309
);
310-
311-
userEvent.click(screen.getByAltText(testImageText));
310+
userEvent.click(screen.getByAltText(testImageText), {
311+
ctrlKey: true,
312+
});
312313
expect(onAddHotspotPosition).not.toHaveBeenCalled();
313314

314315
rerender(
@@ -325,7 +326,9 @@ describe('ImageHotspots', () => {
325326
/>
326327
);
327328

328-
userEvent.click(screen.getByAltText(testImageText));
329+
userEvent.click(screen.getByAltText(testImageText), {
330+
ctrlKey: true,
331+
});
329332
// We aren't more specific about the callback param here due to
330333
// difficulties setting the event.pageX & event.pageY in the test,
331334
// which are needed for getting the position of the click correct.

packages/react/src/components/ImageCard/__snapshots__/ImageHotspots.story.storyshot

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ exports[`Storybook Snapshot tests and console checks Storyshots Watson IoT/Image
2222
>
2323
<div
2424
onBlur={[Function]}
25+
onContextMenu={[Function]}
2526
onMouseOut={[Function]}
2627
style={
2728
Object {
@@ -45,7 +46,7 @@ exports[`Storybook Snapshot tests and console checks Storyshots Watson IoT/Image
4546
src="landscape.jpg"
4647
style={
4748
Object {
48-
"cursor": "crosshair",
49+
"cursor": "auto",
4950
"height": "auto",
5051
"left": undefined,
5152
"objectFit": null,

packages/react/src/utils/__tests__/__snapshots__/publicAPI.test.js.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18456,7 +18456,7 @@ Map {
1845618456
"descriptionTextareaPlaceholderText": "Enter description for the tooltip",
1845718457
"iconDropdownLabelText": "Select an icon",
1845818458
"iconDropdownTitleText": "Icon",
18459-
"infoMessageText": "Click a position on the image to add a hotspot, or set the X and Y coordinates using dataitems and create hotspots at those positions.",
18459+
"infoMessageText": "Hold the CTRL key and click a position on the image to add a hotspot, or set the X and Y coordinates using dataitems and create hotspots at those positions.",
1846018460
"titleInputLabelText": "Title",
1846118461
"titleInputPlaceholderText": "Enter title for the tooltip",
1846218462
},
@@ -18708,7 +18708,7 @@ Map {
1870818708
"fontColorLabelText": "Font color",
1870918709
"fontSizeInvalidText": "Font Size is invalid",
1871018710
"fontSizeLabelText": "Font Size",
18711-
"infoMessageText": "Select an existing label on the image to edit it or click on an empty region to create one",
18711+
"infoMessageText": "Select an existing label on the image to edit it or hold the CTRL key and click on an empty region to create one",
1871218712
"italicLabelText": "Text Italic",
1871318713
"underlineLabelText": "Text Underline",
1871418714
},

0 commit comments

Comments
 (0)