Skip to content

Commit 8289d23

Browse files
Add prev button; fix class names; Refactor to support popover
1 parent 6a29db2 commit 8289d23

2 files changed

Lines changed: 109 additions & 26 deletions

File tree

src/components/VisualTour/VisualTour.tsx

Lines changed: 103 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@ export interface VisualTourProps {
1515
onClose: () => void;
1616
/** Label of the button to close the tour. */
1717
closeLabel?: string;
18-
/** The label for the next button. */
18+
/** The label for the 'next' button. */
1919
nextLabel?: string;
20+
/** The label for the 'previous' button. */
21+
prevLabel?: string;
2022
}
2123

2224
interface VisualTourStep {
@@ -38,6 +40,7 @@ export const VisualTour = ({
3840
onClose,
3941
closeLabel = "Close",
4042
nextLabel = "Next",
43+
prevLabel = "Back",
4144
}: VisualTourProps) => {
4245
const [currentStepIndex, setCurrentStepIndex] = React.useState<number>(0);
4346
const [currentStepComponent, setCurrentStepComponent] = React.useState<React.JSX.Element | null>(null);
@@ -51,45 +54,121 @@ export const VisualTour = ({
5154
return;
5255
}
5356
const hasNextStep = currentStepIndex + 1 < steps.length;
57+
const hasPreviousStep = currentStepIndex > 0;
5458
// Configure optional highlighting
5559
const element = document.querySelector(containerElementQuery);
60+
let elementToHighlight: Element | null = null;
5661
if (element) {
5762
// Remove previous element highlight
5863
element.classList.remove(containerHighlightClass);
5964
document.querySelector(`.${highlightElementClass}`)?.classList.remove(highlightElementClass);
6065
if (step.highlightElementQuery) {
61-
const elementToHighlight = document.querySelector(step.highlightElementQuery);
66+
elementToHighlight = document.querySelector(step.highlightElementQuery);
6267
if (elementToHighlight) {
6368
element.classList.add(containerHighlightClass);
6469
elementToHighlight.classList.add(highlightElementClass);
6570
}
6671
}
6772
}
68-
setCurrentStepComponent(
69-
<SimpleDialog
70-
title={step.title + ` ${currentStepIndex + 1} / ${steps.length}`}
71-
isOpen={true}
72-
preventSimpleClosing={true}
73-
onClose={onClose}
74-
actions={[
75-
<Button onClick={onClose}>{closeLabel}</Button>,
76-
hasNextStep ? (
77-
<Button
78-
onClick={() => {
79-
setCurrentStepIndex(currentStepIndex + 1);
80-
}}
81-
>
82-
{nextLabel}: {steps[currentStepIndex + 1].title}
83-
</Button>
84-
) : null,
85-
]}
86-
>
87-
{typeof step.content === "string" ? step.content : step.content()}
88-
</SimpleDialog>
89-
);
73+
const titleSuffix = ` ${currentStepIndex + 1} / ${steps.length}`;
74+
const navigationButtons = [
75+
<Button onClick={onClose}>{closeLabel}</Button>,
76+
hasNextStep ? (
77+
<Button
78+
onClick={() => {
79+
setCurrentStepIndex(currentStepIndex + 1);
80+
}}
81+
>
82+
{nextLabel}: {steps[currentStepIndex + 1].title}
83+
</Button>
84+
) : null,
85+
hasPreviousStep ? (
86+
<Button
87+
onClick={() => {
88+
setCurrentStepIndex(currentStepIndex - 1);
89+
}}
90+
>
91+
{prevLabel}: {steps[currentStepIndex - 1].title}
92+
</Button>
93+
) : null,
94+
];
95+
// TODO: What to do if an element should have been highlighted, but none was found?
96+
if (elementToHighlight) {
97+
setCurrentStepComponent(
98+
<StepPopover
99+
highlightedElement={elementToHighlight}
100+
titleSuffix={titleSuffix}
101+
navigationButtons={navigationButtons}
102+
step={step}
103+
onClose={onClose}
104+
/>
105+
);
106+
} else {
107+
setCurrentStepComponent(
108+
<StepModal
109+
titleSuffix={titleSuffix}
110+
navigationButtons={navigationButtons}
111+
step={step}
112+
onClose={onClose}
113+
/>
114+
);
115+
}
90116
}, [currentStepIndex]);
91117

92118
return currentStepComponent;
93119
};
94120

121+
interface StepModalProps {
122+
step: VisualTourStep;
123+
// Current step starting with 1
124+
titleSuffix: string;
125+
// Close the visual tour
126+
onClose: () => void;
127+
// The navigation buttons
128+
navigationButtons: (React.JSX.Element | null)[];
129+
}
130+
131+
/** Modal that is displayed for a step. */
132+
const StepModal = ({ step, titleSuffix, onClose, navigationButtons }: StepModalProps) => {
133+
return (
134+
<SimpleDialog
135+
title={`${step.title} ${titleSuffix}`}
136+
isOpen={true}
137+
preventSimpleClosing={true}
138+
onClose={onClose}
139+
actions={navigationButtons}
140+
>
141+
{typeof step.content === "string" ? step.content : step.content()}
142+
</SimpleDialog>
143+
);
144+
};
145+
146+
interface StepPopoverProps {
147+
highlightedElement: Element;
148+
step: VisualTourStep;
149+
// Current step starting with 1
150+
titleSuffix: string;
151+
// Close the visual tour
152+
onClose: () => void;
153+
// The navigation buttons
154+
navigationButtons: (React.JSX.Element | null)[];
155+
}
156+
157+
/** Popover that is displayed and points at the highlighted element. */
158+
const StepPopover = ({ highlightedElement, step, titleSuffix, onClose, navigationButtons }: StepPopoverProps) => {
159+
// TODO: Show popover on highlighted element
160+
return (
161+
<SimpleDialog
162+
title={`${step.title} ${titleSuffix}`}
163+
isOpen={true}
164+
preventSimpleClosing={true}
165+
onClose={onClose}
166+
actions={navigationButtons}
167+
>
168+
{typeof step.content === "string" ? step.content : step.content()}
169+
{highlightedElement.tagName}
170+
</SimpleDialog>
171+
);
172+
};
173+
95174
export default VisualTour;
Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
.eccapp-visual-tour__container {
2-
:not(.eccapp-visual-tour__highlighted-element) {
1+
.#{$eccgui}-visual-tour__container {
2+
:not(.#{$eccgui}-visual-tour__highlighted-element) {
33
z-index: 0;
44
opacity: $eccgui-opacity-disabled;
55
filter: grayscale(1);
66
}
7+
8+
.#{$eccgui}-visual-tour__highlighted-element {
9+
background-color: orange;
10+
}
711
}

0 commit comments

Comments
 (0)