Skip to content

Commit 5f6a99c

Browse files
authored
Merge pull request #2329 from tf/excursions-improvements
Excursions improvements
2 parents 2fdfee3 + 9679cd9 commit 5f6a99c

File tree

5 files changed

+127
-18
lines changed

5 files changed

+127
-18
lines changed

entry_types/scrolled/package/spec/contentElements/hotspots/Hotspots/tooltipDisplay-spec.js

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,18 @@ import tooltipStyles from 'contentElements/hotspots/Tooltip.module.css';
88
import {renderInContentElement} from 'pageflow-scrolled/testHelpers';
99
import {asyncHandlingOf} from 'support/asyncHandlingOf'
1010
import '@testing-library/jest-dom/extend-expect'
11+
import {act, waitFor} from '@testing-library/react';
1112
import userEvent from '@testing-library/user-event';
1213
import 'support/fakeResizeObserver';
1314

1415
jest.mock('contentElements/hotspots/TooltipPortal');
1516
jest.mock('contentElements/hotspots/useTooltipTransitionStyles');
1617

1718
describe('Hotspots', () => {
19+
afterEach(() => {
20+
jest.useRealTimers();
21+
});
22+
1823
it('shows tooltip on area hover', async () => {
1924
const seed = {
2025
imageFileUrlTemplates: {large: ':id_partition/image.webp'},
@@ -226,6 +231,85 @@ describe('Hotspots', () => {
226231

227232
expect(container.querySelector(`.${tooltipStyles.box}`)).toBeNull();
228233
});
234+
235+
it('hides tooltip when storyline enters background', async () => {
236+
const seed = {
237+
imageFileUrlTemplates: {large: ':id_partition/image.webp'},
238+
imageFiles: [{id: 1, permaId: 100}]
239+
};
240+
const configuration = {
241+
image: 100,
242+
areas: [
243+
{
244+
id: 1,
245+
outline: [[10, 20], [10, 30], [40, 30], [40, 20]],
246+
indicatorPosition: [20, 25],
247+
}
248+
],
249+
tooltipTexts: {
250+
1: {
251+
title: [{type: 'heading', children: [{text: 'Some title'}]}],
252+
}
253+
}
254+
};
255+
256+
const user = userEvent.setup();
257+
const {container, simulateScrollPosition, simulateStorylineMode} = renderInContentElement(
258+
<Hotspots configuration={configuration} />, {seed}
259+
);
260+
simulateScrollPosition('near viewport');
261+
262+
await user.hover(clickableArea(container));
263+
expect(container.querySelector(`.${tooltipStyles.box}`)).not.toBeNull();
264+
265+
simulateStorylineMode('background');
266+
267+
await waitFor(() =>
268+
expect(container.querySelector(`.${tooltipStyles.box}`)).toBeNull()
269+
);
270+
});
271+
272+
it('shows tooltip again after delay when storyline becomes active', async () => {
273+
jest.useFakeTimers();
274+
const seed = {
275+
imageFileUrlTemplates: {large: ':id_partition/image.webp'},
276+
imageFiles: [{id: 1, permaId: 100}]
277+
};
278+
const configuration = {
279+
image: 100,
280+
areas: [
281+
{
282+
id: 1,
283+
outline: [[10, 20], [10, 30], [40, 30], [40, 20]],
284+
indicatorPosition: [20, 25],
285+
}
286+
],
287+
tooltipTexts: {
288+
1: {
289+
title: [{type: 'heading', children: [{text: 'Some title'}]}],
290+
}
291+
}
292+
};
293+
294+
const user = userEvent.setup({advanceTimers: jest.advanceTimersByTime});
295+
const {container, simulateScrollPosition, simulateStorylineMode} = renderInContentElement(
296+
<Hotspots configuration={configuration} />, {seed}
297+
);
298+
simulateScrollPosition('near viewport');
299+
300+
await user.hover(clickableArea(container));
301+
simulateStorylineMode('background');
302+
await waitFor(() =>
303+
expect(container.querySelector(`.${tooltipStyles.box}`)).toBeNull()
304+
);
305+
306+
simulateStorylineMode('active');
307+
expect(container.querySelector(`.${tooltipStyles.box}`)).toBeNull();
308+
309+
act(() => jest.advanceTimersByTime(200));
310+
311+
expect(container.querySelector(`.${tooltipStyles.box}`)).not.toBeNull();
312+
});
229313
});
230314

231315
function clickableArea(container) {

entry_types/scrolled/package/src/contentElements/hotspots/Tooltip.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@ import {
2222
useContentElementEditorState,
2323
useContentElementConfigurationUpdate,
2424
useDarkBackground,
25+
useDelayedBoolean,
2526
useFileWithInlineRights,
2627
useFloatingPortalRoot,
2728
useI18n,
29+
useStorylineActivity,
2830
utils,
2931
LinkButton
3032
} from 'pageflow-scrolled/frontend';
@@ -53,6 +55,9 @@ export function Tooltip({
5355
const updateConfiguration = useContentElementConfigurationUpdate();
5456
const {isEditable} = useContentElementEditorState();
5557

58+
const storylineMode = useStorylineActivity();
59+
const inBackground = useDelayedBoolean(storylineMode !== 'active', {fromTrueToFalse: 200});
60+
5661
const darkBackground = useDarkBackground();
5762
const light = configuration.invertTooltips ? !darkBackground : darkBackground;
5863

@@ -75,7 +80,7 @@ export function Tooltip({
7580

7681
const arrowRef = useRef();
7782
const {refs, floatingStyles, context} = useFloating({
78-
open: containerRect.width > 0 && visible,
83+
open: containerRect.width > 0 && visible && !inBackground,
7984
onOpenChange: open => !open && onDismiss(),
8085
strategy: floatingStrategy || 'absolute',
8186
placement: position === 'above' ? 'top' : 'bottom',

entry_types/scrolled/package/src/frontend/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ export {usePortraitOrientation} from './usePortraitOrientation';
101101
export {useScrollPosition} from './useScrollPosition';
102102
export {usePhonePlatform} from './usePhonePlatform';
103103
export {useIsomorphicLayoutEffect} from './useIsomorphicLayoutEffect';
104+
export {MainStorylineActivity, useStorylineActivity} from './storylineActivity';
105+
export {useDelayedBoolean} from './useDelayedBoolean';
104106

105107
export {EditableTable} from './EditableTable';
106108
export {EditableText} from './EditableText';

entry_types/scrolled/package/src/testHelpers/renderInContentElement.js

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, {useContext} from 'react';
1+
import React, {useContext, useEffect, useState} from 'react';
22
import {DndProvider} from 'react-dnd';
33
import {HTML5Backend} from 'react-dnd-html5-backend';
44
import BackboneEvents from 'backbone-events-standalone';
@@ -9,6 +9,7 @@ import {
99
ContentElementEditorCommandEmitterContext,
1010
ContentElementEditorStateContext,
1111
ContentElementLifecycleContext,
12+
MainStorylineActivity,
1213
PhonePlatformContext
1314
} from 'pageflow-scrolled/frontend';
1415

@@ -19,8 +20,9 @@ import {renderInEntryWithScrollPositionLifecycle} from './scrollPositionLifecycl
1920
/**
2021
* Provide context as if component was rendered inside of a content element.
2122
*
22-
* Returns two additionals functions to control content element scroll
23-
* lifecycle and editor commands: `simulateScrollPosition` and `triggerEditorCommand`.
23+
* Returns additional functions to control content element scroll
24+
* lifecycle, editor commands, and storyline mode: `simulateScrollPosition`,
25+
* `triggerEditorCommand`, and `simulateStorylineMode`.
2426
*
2527
* @param {Function} callback - React component or function returning a React component.
2628
* @param {Object} [options] - Supports all options supported by {@link `renderInEntry`}.
@@ -30,12 +32,13 @@ import {renderInEntryWithScrollPositionLifecycle} from './scrollPositionLifecycl
3032
*
3133
* @example
3234
*
33-
* const {getByRole, simulateScrollPosition, triggerEditorCommand} =
35+
* const {getByRole, simulateScrollPosition, triggerEditorCommand, simulateStorylineMode} =
3436
* renderInContentElement(<MyContentElement />, {
3537
* seed: {...}
3638
* });
3739
* simulateScrollPosition('near viewport');
3840
* triggerEditorCommand({type: 'HIGHLIGHT'});
41+
* simulateStorylineMode('background');
3942
*/
4043
export function renderInContentElement(ui, {editorState,
4144
phonePlatform = false,
@@ -44,24 +47,33 @@ export function renderInContentElement(ui, {editorState,
4447
seed,
4548
...options} = {}) {
4649
const emitter = Object.assign({}, BackboneEvents);
50+
const storylineEmitter = Object.assign({}, BackboneEvents);
4751

4852
function Wrapper({children}) {
4953
const defaultEditorState = useContext(ContentElementEditorStateContext);
54+
const [storylineMode, setStorylineMode] = useState('active');
55+
56+
useEffect(() => {
57+
storylineEmitter.on('storylineMode', setStorylineMode);
58+
return () => storylineEmitter.off('storylineMode', setStorylineMode);
59+
}, []);
5060

5161
return (
52-
<PhonePlatformContext.Provider value={phonePlatform}>
53-
<DndProvider backend={HTML5Backend}>
54-
<ContentElementAttributesProvider id={42}>
55-
<ContentElementEditorCommandEmitterContext.Provider
56-
value={emitter}>
57-
<ContentElementEditorStateContext.Provider
58-
value={{...defaultEditorState, ...editorState}}>
59-
{OriginalWrapper ? <OriginalWrapper children={children} /> : children}
60-
</ContentElementEditorStateContext.Provider>
61-
</ContentElementEditorCommandEmitterContext.Provider>
62-
</ContentElementAttributesProvider>
63-
</DndProvider>
64-
</PhonePlatformContext.Provider>
62+
<MainStorylineActivity activeExcursion={storylineMode !== 'active' ? {id: 1} : null}>
63+
<PhonePlatformContext.Provider value={phonePlatform}>
64+
<DndProvider backend={HTML5Backend}>
65+
<ContentElementAttributesProvider id={42}>
66+
<ContentElementEditorCommandEmitterContext.Provider
67+
value={emitter}>
68+
<ContentElementEditorStateContext.Provider
69+
value={{...defaultEditorState, ...editorState}}>
70+
{OriginalWrapper ? <OriginalWrapper children={children} /> : children}
71+
</ContentElementEditorStateContext.Provider>
72+
</ContentElementEditorCommandEmitterContext.Provider>
73+
</ContentElementAttributesProvider>
74+
</DndProvider>
75+
</PhonePlatformContext.Provider>
76+
</MainStorylineActivity>
6577
);
6678
}
6779

@@ -83,6 +95,11 @@ export function renderInContentElement(ui, {editorState,
8395
act(() => {
8496
emitter.trigger(`command:42`, command)
8597
})
98+
},
99+
simulateStorylineMode(mode) {
100+
act(() => {
101+
storylineEmitter.trigger('storylineMode', mode)
102+
});
86103
}
87104
};
88105
}

entry_types/scrolled/package/src/widgets/excursionSheet/ExcursionSheet.module.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
box-shadow: 0 0 20px 5px rgb(0 0 0 / 0.5);
3939
position: relative;
4040
overflow: clip;
41+
clip-path: inset(0);
4142
}
4243

4344
@media (prefers-reduced-motion: no-preference) {

0 commit comments

Comments
 (0)