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) =>
+
= 0 && activeIndex !== index}
+ outerRef={setIndicatorRef(index)}
+ portraitMode={portraitMode} />
+ );
+ }
+
+ function renderTooltips() {
+ return areas.map((area, index) =>
+ setHoveredIndex(index)}
+ onMouseLeave={() => setHoveredIndex(-1)}
+ onClick={() => setActiveIndex(index)}
+ onDismiss={() => activateArea(-1)} />
+ );
+ }
+
+ function renderFullscreenToggle() {
+ if (!displayFullscreenToggle) {
+ return null;
+ }
+
+ return (
+
+ );
+ }
+
return (
-
-
- activateArea(index - 1)}>
-
- {children(
-
-
-
-
- {areas.map((area, index) =>
-
setHoveredIndex(index)}
- onMouseLeave={() => setHoveredIndex(-1)}
- onClick={() => {
- if (!isEditable || isSelected) {
- activateArea(index)
- }
- }} />
- )}
+
+ {renderScrollButtons()}
+
+
+ activateArea(index - 1)}>
+
+ {children(
+
+
+
+
+ {renderVisibleAreas()}
+
+
+
+ {renderClickableAreas()}
+
+
+ {renderIndicators()}
- {areas.map((area, index) =>
- = 0 && activeIndex !== index}
- outerRef={setIndicatorRef(index)}
- portraitMode={portraitMode} />
- )}
- {panZoomEnabled &&
- activateArea(index)}
- containerRect={containerRect}>
-
- {areas.map((area, index) =>
-
setHoveredIndex(index)}
- onMouseLeave={() => setHoveredIndex(-1)}
- onClick={() => {
- if (!isEditable || isSelected) {
- activateArea(index)
- }
- }} />
- )}
-
- }
-
- {displayFullscreenToggle &&
- }
-
-
- )}
- } />
- {areas.map((area, index) =>
- setHoveredIndex(index)}
- onMouseLeave={() => setHoveredIndex(-1)}
- onClick={() => setActiveIndex(index)}
- onDismiss={() => activateArea(-1)} />
- )}
-
-
-
-
+ {renderFullscreenToggle()}
+
+
+ )}
+
} />
+ {renderTooltips()}
+
} />
+
+
+
+
+
);
}
diff --git a/entry_types/scrolled/package/src/contentElements/hotspots/Hotspots.module.css b/entry_types/scrolled/package/src/contentElements/hotspots/Hotspots.module.css
index da81b6200..fda419895 100644
--- a/entry_types/scrolled/package/src/contentElements/hotspots/Hotspots.module.css
+++ b/entry_types/scrolled/package/src/contentElements/hotspots/Hotspots.module.css
@@ -1,20 +1,51 @@
-.compositeItem {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
+.outer {
+ display: grid;
+ grid-template-columns: [left-start center-start] 1fr
+ [left-end] 84%
+ [right-start] 1fr
+ [right-end center-end];
+ justify-content: center;
height: 100%;
+}
+
+.customMargin {
+ grid-template-columns: [left-start] var(--content-margin)
+ [left-end center-start] minmax(0, var(--content-max-width))
+ [right-start center-end] var(--content-margin)
+ [right-end];
+ --hotspots-scroll-button-height: 100%;
+}
+
+.left,
+.right {
+ grid-row: 1;
+ z-index: 2;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ overflow: hidden;
pointer-events: none;
}
+.left {
+ grid-column: left-start / left-end;
+}
+
+.right {
+ grid-column: right-start / right-end;
+}
+
.center {
+ grid-column: center-start / center-end;
+ grid-row: 1;
display: flex;
flex-direction: column;
justify-content: center;
height: 100%;
}
-.outer {
+.tooltipsWrapper {
position: relative;
}
@@ -27,7 +58,6 @@
grid-auto-columns: 100%;
grid-auto-rows: 100%;
height: 100%;
- isolation: isolate;
}
.stack > div {
@@ -44,3 +74,12 @@
.wrapper > img {
height: 100%;
}
+
+.compositeItem {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ pointer-events: none;
+}
diff --git a/entry_types/scrolled/package/src/contentElements/hotspots/ScrollButton.js b/entry_types/scrolled/package/src/contentElements/hotspots/ScrollButton.js
index 770102c0e..cd16af579 100644
--- a/entry_types/scrolled/package/src/contentElements/hotspots/ScrollButton.js
+++ b/entry_types/scrolled/package/src/contentElements/hotspots/ScrollButton.js
@@ -4,7 +4,7 @@ import {ThemeIcon, useI18n} from 'pageflow-scrolled/frontend';
import styles from './ScrollButton.module.css';
-const size = 60;
+const size = 40;
export function ScrollButton({direction, disabled, onClick}) {
const {t} = useI18n();
diff --git a/entry_types/scrolled/package/src/contentElements/hotspots/ScrollButton.module.css b/entry_types/scrolled/package/src/contentElements/hotspots/ScrollButton.module.css
index 3b473ba59..17889f866 100644
--- a/entry_types/scrolled/package/src/contentElements/hotspots/ScrollButton.module.css
+++ b/entry_types/scrolled/package/src/contentElements/hotspots/ScrollButton.module.css
@@ -1,10 +1,11 @@
.button {
- height: 100%;
- padding: 0;
+ height: var(--hotspots-scroll-button-height);
+ padding: 1rem;
background-color: transparent;
border: 0;
color: #fff;
transition: opacity 0.2s linear, visibility 0.2s;
+ pointer-events: auto;
}
.left {
@@ -28,7 +29,7 @@
}
.button:not(.disabled):hover svg,
-.button:not(.disabled):focus svg {
+.button:not(.disabled):active svg {
transform: scale(1.2);
}
diff --git a/entry_types/scrolled/package/src/contentElements/hotspots/Scroller.js b/entry_types/scrolled/package/src/contentElements/hotspots/Scroller.js
index a9a1d72c3..d364fd270 100644
--- a/entry_types/scrolled/package/src/contentElements/hotspots/Scroller.js
+++ b/entry_types/scrolled/package/src/contentElements/hotspots/Scroller.js
@@ -1,26 +1,16 @@
import React from 'react';
-import {ScrollButton} from './ScrollButton';
-
import styles from './Scroller.module.css';
export const Scroller = React.forwardRef(function Scroller(
- {areas, activeIndex, onScrollButtonClick, setStepRef, containerRect, children}, ref
+ {areas, disabled, setStepRef, containerRect, children}, ref
) {
+ if (disabled) {
+ return children;
+ }
+
return (
<>
-
- onScrollButtonClick(activeIndex - 1)} />
-
-
- onScrollButtonClick(
- activeIndex >= areas.length - 1 ? -1 : activeIndex + 1
- )}/>
-
{Array.from({length: areas.length + 2}, (_, index) =>
diff --git a/entry_types/scrolled/package/src/contentElements/hotspots/Scroller.module.css b/entry_types/scrolled/package/src/contentElements/hotspots/Scroller.module.css
index e098e03c2..4ee1f793b 100644
--- a/entry_types/scrolled/package/src/contentElements/hotspots/Scroller.module.css
+++ b/entry_types/scrolled/package/src/contentElements/hotspots/Scroller.module.css
@@ -4,10 +4,9 @@
display: grid;
grid-auto-columns: 100%;
grid-auto-flow: column;
+ grid-template-rows: 0px 100%;
scroll-snap-type: x mandatory;
scrollbar-width: none;
- z-index: 1;
- grid-template-rows: 0px 100%;
}
.scroller::-webkit-scrollbar {
@@ -18,6 +17,7 @@
position: sticky;
top: 0;
left: 0;
+ width: 100%;
grid-column: 1;
grid-row: 1;
}
@@ -27,17 +27,3 @@
scroll-snap-stop: always;
grid-row: 2;
}
-
-.leftButton,
-.rightButton {
- z-index: 2;
-}
-
-
-.leftButton {
- justify-self: start;
-}
-
-.rightButton {
- justify-self: end;
-}
diff --git a/entry_types/scrolled/package/src/contentElements/hotspots/Tooltip.js b/entry_types/scrolled/package/src/contentElements/hotspots/Tooltip.js
index ecdff1d20..532745923 100644
--- a/entry_types/scrolled/package/src/contentElements/hotspots/Tooltip.js
+++ b/entry_types/scrolled/package/src/contentElements/hotspots/Tooltip.js
@@ -43,6 +43,7 @@ export function Tooltip({
area,
contentElementId, portraitMode, configuration, visible, active,
panZoomEnabled, imageFile, containerRect, keepInViewport, floatingStrategy,
+ wrapperRef,
onMouseEnter, onMouseLeave, onClick, onDismiss,
}) {
const {t: translateWithEntryLocale} = useI18n();
@@ -80,7 +81,11 @@ export function Tooltip({
placement: position === 'above' ? 'top' : 'bottom',
middleware: [
offset(referenceType === 'area' ? 7 : 20),
- shift({crossAxis: keepInViewport, padding: {left: 16, right: 16}}),
+ shift({
+ crossAxis: keepInViewport,
+ padding: {left: -5, right: -5},
+ boundary: wrapperRef.current,
+ }),
keepInViewport && flip(),
arrow({
element: arrowRef,
diff --git a/entry_types/scrolled/package/src/contentElements/hotspots/Tooltip.module.css b/entry_types/scrolled/package/src/contentElements/hotspots/Tooltip.module.css
index 23abe7862..4e1a1e454 100644
--- a/entry_types/scrolled/package/src/contentElements/hotspots/Tooltip.module.css
+++ b/entry_types/scrolled/package/src/contentElements/hotspots/Tooltip.module.css
@@ -31,7 +31,7 @@
padding: 0.75rem;
border-radius: 5px;
--max-width: 400px;
- max-width: min(100% - 2rem, var(--max-width));
+ max-width: min(100% - 16% + 10px, var(--max-width));
}
.light {
diff --git a/entry_types/scrolled/package/src/contentElements/hotspots/frontend.js b/entry_types/scrolled/package/src/contentElements/hotspots/frontend.js
index 9704113e6..7f3f51b8f 100644
--- a/entry_types/scrolled/package/src/contentElements/hotspots/frontend.js
+++ b/entry_types/scrolled/package/src/contentElements/hotspots/frontend.js
@@ -3,5 +3,6 @@ import {Hotspots} from './Hotspots';
frontend.contentElementTypes.register('hotspots', {
component: Hotspots,
- lifecycle: true
+ lifecycle: true,
+ customMargin: true
});
diff --git a/entry_types/scrolled/package/src/contentElements/hotspots/useIntersectionObserver.js b/entry_types/scrolled/package/src/contentElements/hotspots/useIntersectionObserver.js
index cf5f0dc22..d513c94a9 100644
--- a/entry_types/scrolled/package/src/contentElements/hotspots/useIntersectionObserver.js
+++ b/entry_types/scrolled/package/src/contentElements/hotspots/useIntersectionObserver.js
@@ -14,6 +14,10 @@ export function useIntersectionObserver({threshold, onVisibleIndexChange, enable
(entries) => {
const containerElement = containerRef.current;
+ if (!containerElement) {
+ return;
+ }
+
let found = false;
entries.forEach((entry) => {