From 19abfcaad0a95445403766e1f6402779f80bb063 Mon Sep 17 00:00:00 2001 From: Tim Fischbach Date: Thu, 8 Aug 2024 11:51:14 +0200 Subject: [PATCH] Place scroll arrows outside of hotspots element REDMINE-20673 --- .../contentElements/hotspots/Hotspots-spec.js | 54 ++-- .../src/contentElements/hotspots/Area.js | 5 +- .../contentElements/hotspots/Area.module.css | 4 + .../src/contentElements/hotspots/Hotspots.js | 254 +++++++++++------- .../hotspots/Hotspots.module.css | 53 +++- .../contentElements/hotspots/ScrollButton.js | 2 +- .../hotspots/ScrollButton.module.css | 7 +- .../src/contentElements/hotspots/Scroller.js | 20 +- .../hotspots/Scroller.module.css | 18 +- .../src/contentElements/hotspots/Tooltip.js | 7 +- .../hotspots/Tooltip.module.css | 2 +- .../src/contentElements/hotspots/frontend.js | 3 +- .../hotspots/useIntersectionObserver.js | 4 + 13 files changed, 261 insertions(+), 172 deletions(-) diff --git a/entry_types/scrolled/package/spec/contentElements/hotspots/Hotspots-spec.js b/entry_types/scrolled/package/spec/contentElements/hotspots/Hotspots-spec.js index b41b8c652..d31b7b120 100644 --- a/entry_types/scrolled/package/spec/contentElements/hotspots/Hotspots-spec.js +++ b/entry_types/scrolled/package/spec/contentElements/hotspots/Hotspots-spec.js @@ -388,11 +388,13 @@ describe('Hotspots', () => { const user = userEvent.setup(); observeResizeMock.mockContentRect = {width: 200, height: 100}; - const {container, simulateScrollPosition} = renderInContentElement( + const {container, simulateScrollPosition, getByText} = renderInContentElement( , {seed} ); simulateScrollPosition('near viewport'); - await user.click(container.querySelector(`.${areaStyles.clip}`)); + await user.click(clickableArea(container)); + + getByText('Some title') const {queryByText, getByRole} = within(container.querySelector(`.${tooltipStyles.box}`)); expect(queryByText('Some title')).not.toBeNull(); @@ -433,7 +435,7 @@ describe('Hotspots', () => { , {seed} ); simulateScrollPosition('near viewport'); - await user.click(container.querySelector(`.${areaStyles.clip}`)) + await user.click(clickableArea(container)) expect(queryByRole('link')).toBeNull(); }); @@ -468,7 +470,7 @@ describe('Hotspots', () => { , {seed} ); simulateScrollPosition('near viewport'); - await user.click(container.querySelector(`.${areaStyles.clip}`)) + await user.click(clickableArea(container)) expect(container.querySelector(`.${tooltipStyles.box}`)).not.toHaveClass(tooltipStyles.minWidth); }); @@ -503,7 +505,7 @@ describe('Hotspots', () => { , {seed} ); simulateScrollPosition('near viewport'); - await user.click(container.querySelector(`.${areaStyles.clip}`)) + await user.click(clickableArea(container)) expect(container.querySelector(`.${tooltipStyles.box}`)).toHaveClass(tooltipStyles.minWidth); }); @@ -535,7 +537,7 @@ describe('Hotspots', () => { , {seed} ); simulateScrollPosition('near viewport'); - await user.click(container.querySelector(`.${areaStyles.clip}`)) + await user.click(clickableArea(container)) expect(container.querySelector(`.${tooltipStyles.box}`)).toHaveClass(tooltipStyles['maxWidth-narrow']); }); @@ -570,7 +572,7 @@ describe('Hotspots', () => { , {seed} ); simulateScrollPosition('near viewport'); - await user.click(container.querySelector(`.${areaStyles.clip}`)) + await user.click(clickableArea(container)) expect(container.querySelector(`.${tooltipStyles.box}`)).toHaveClass(tooltipStyles['maxWidth-veryNarrow']); }); @@ -602,7 +604,7 @@ describe('Hotspots', () => { , {seed} ); simulateScrollPosition('near viewport'); - await user.click(container.querySelector(`.${areaStyles.clip}`)) + await user.click(clickableArea(container)) expect(container.querySelector(`.${tooltipStyles.box}`)).toHaveClass(tooltipStyles['align-center']); }); @@ -861,7 +863,7 @@ describe('Hotspots', () => { expect(queryByText('Some title')).toBeNull(); - await user.hover(container.querySelector(`.${areaStyles.clip}`)); + await user.hover(clickableArea(container)); expect(queryByText('Some title')).not.toBeNull(); }); @@ -902,8 +904,8 @@ describe('Hotspots', () => { ); simulateScrollPosition('near viewport'); - await user.click(container.querySelectorAll(`.${areaStyles.clip}`)[0]); - await user.hover(container.querySelectorAll(`.${areaStyles.clip}`)[1]); + await user.click(clickableAreas(container)[0]); + await user.hover(clickableAreas(container)[1]); expect(queryByText('Area 1')).not.toBeNull(); }); @@ -934,7 +936,7 @@ describe('Hotspots', () => { , {seed} ); - await user.click(container.querySelector(`.${areaStyles.clip}`)); + await user.click(clickableArea(container)); await user.click(document.body); expect(container.querySelector(`.${tooltipStyles.box}`)).toBeNull(); @@ -968,7 +970,7 @@ describe('Hotspots', () => { ); simulateScrollPosition('near viewport'); - await user.click(container.querySelector(`.${areaStyles.clip}`)); + await user.click(clickableArea(container)); await user.click(getByText('Some title')); expect(container.querySelector(`.${tooltipStyles.box}`)).not.toBeNull(); @@ -1002,9 +1004,9 @@ describe('Hotspots', () => { ); simulateScrollPosition('near viewport'); - await user.hover(container.querySelector(`.${areaStyles.clip}`)); + await user.hover(clickableArea(container)); await user.click(getByText('Some title')); - await user.unhover(container.querySelector(`.${areaStyles.clip}`)); + await user.unhover(clickableArea(container)); expect(container.querySelector(`.${tooltipStyles.box}`)).not.toBeNull(); }); @@ -1164,7 +1166,7 @@ describe('Hotspots', () => { expect(container.querySelector(`.${areaStyles.area}`)).not.toHaveClass(imageAreaStyles.activeImageVisible); - await user.click(container.querySelector(`.${areaStyles.clip}`)); + await user.click(clickableArea(container)); expect(container.querySelector(`.${areaStyles.area}`)).toHaveClass(imageAreaStyles.activeImageVisible); }); @@ -1193,7 +1195,7 @@ describe('Hotspots', () => { , {seed} ); - await user.click(container.querySelector(`.${areaStyles.clip}`)); + await user.click(clickableArea(container)); expect(container.querySelectorAll(`.${indicatorStyles.indicator}`)[0]).not.toHaveClass(indicatorStyles.hidden); expect(container.querySelectorAll(`.${indicatorStyles.indicator}`)[1]).not.toHaveClass(indicatorStyles.hidden); @@ -1227,11 +1229,11 @@ describe('Hotspots', () => { expect(container.querySelector(`.${areaStyles.area}`)).not.toHaveClass(imageAreaStyles.activeImageVisible); - await user.hover(container.querySelector(`.${areaStyles.clip}`)); + await user.hover(clickableArea(container)); expect(container.querySelector(`.${areaStyles.area}`)).toHaveClass(imageAreaStyles.activeImageVisible); - await user.unhover(container.querySelector(`.${areaStyles.clip}`)); + await user.unhover(clickableArea(container)); expect(container.querySelector(`.${areaStyles.area}`)).not.toHaveClass(imageAreaStyles.activeImageVisible); }); @@ -1383,7 +1385,7 @@ describe('Hotspots', () => { editorState: {isEditable: true, isSelected: true, setTransientState} } ); - await user.click(container.querySelector(`.${areaStyles.clip}`)); + await user.click(clickableArea(container)); expect(setTransientState).toHaveBeenCalledWith({activeAreaId: 1}) }); @@ -1983,7 +1985,7 @@ describe('Hotspots', () => { const scroller = container.querySelector(`.${scrollerStyles.scroller}`); scroller.scrollTo = jest.fn(); simulateScrollPosition('near viewport'); - await user.click(container.querySelector(`.${areaStyles.clip}`)); + await user.click(clickableArea(container)); expect(scroller.scrollTo).toHaveBeenCalled(); expect(container.querySelector(`.${tooltipStyles.box}`)).toBeNull(); @@ -2085,7 +2087,7 @@ describe('Hotspots', () => { , {seed} ); - await user.hover(container.querySelector(`.${areaStyles.clip}`)); + await user.hover(clickableArea(container)); expect(container.querySelector(`.${areaStyles.area}`)).not.toHaveClass(imageAreaStyles.activeImageVisible); }); @@ -2161,3 +2163,11 @@ describe('Hotspots', () => { }); }); }); + +function clickableArea(container) { + return clickableAreas(container)[0]; +} + +function clickableAreas(container) { + return container.querySelectorAll(`div:not(.${imageAreaStyles.area}) > .${areaStyles.clip}`); +} diff --git a/entry_types/scrolled/package/src/contentElements/hotspots/Area.js b/entry_types/scrolled/package/src/contentElements/hotspots/Area.js index 82a59e42d..49ef7ce72 100644 --- a/entry_types/scrolled/package/src/contentElements/hotspots/Area.js +++ b/entry_types/scrolled/package/src/contentElements/hotspots/Area.js @@ -6,7 +6,7 @@ import {paletteColor} from 'pageflow-scrolled/frontend'; import styles from './Area.module.css'; export function Area({ - area, portraitMode, + area, portraitMode, noPointerEvents, highlighted, outlined, className, children, onMouseEnter, onMouseLeave, onClick @@ -16,7 +16,8 @@ export function Area({ return (
+ {[styles.highlighted]: highlighted, + [styles.noPointerEvents]: noPointerEvents})}>
children @@ -138,109 +141,154 @@ export function HotspotsImage({ } }); + function renderScrollButtons() { + if (!panZoomEnabled) { + return null; + } + + return ( + <> +
+ activateArea(activeIndex - 1)} /> +
+
+ = areas.length} + onClick={() => activateArea(activeIndex + 1)}/> +
+ + ); + } + + function renderVisibleAreas() { + return areas.map((area, index) => + + ); + } + + function renderClickableAreas() { + return areas.map((area, index) => + = 0} + onMouseEnter={() => setHoveredIndex(index)} + onMouseLeave={() => setHoveredIndex(-1)} + onClick={() => { + if (!isEditable || isSelected) { + activateArea(index) + } + }} /> + ); + } + + function renderIndicators() { + return areas.map((area, index) => +