Skip to content

Commit c971625

Browse files
Observe changes to highlighted element and re-new highlighting if needed
1 parent 96bec84 commit c971625

1 file changed

Lines changed: 106 additions & 77 deletions

File tree

src/components/VisualTour/VisualTour.tsx

Lines changed: 106 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -78,93 +78,122 @@ export const VisualTour = ({
7878
const hasPreviousStep = currentStepIndex > 0;
7979
// Configure optional highlighting
8080
let elementToHighlight: HTMLElement | null = null;
81-
if (step.highlightElementQuery) {
82-
const queries: string[] =
83-
typeof step.highlightElementQuery === "string"
84-
? [step.highlightElementQuery]
85-
: step.highlightElementQuery;
86-
queries.forEach((query) => {
87-
if (elementToHighlight == null) {
88-
elementToHighlight = document.querySelector(query);
89-
}
90-
});
91-
}
92-
if (elementToHighlight) {
93-
// Typescript for some reason incorrectly infers the type of elementToHighlight as never
94-
(elementToHighlight as HTMLElement).classList.add(highlightElementClass);
95-
(elementToHighlight as HTMLElement).scrollIntoView({
96-
behavior: "smooth",
97-
block: "center",
98-
});
99-
}
100-
const stepDisplay = (
101-
<Badge tagProps={{ emphasis: "weaker" }} size="large">
102-
{` ${currentStepIndex + 1}/${steps.length} `}
103-
</Badge>
104-
);
105-
const closeButton = <IconButton name="navigation-close" text={closeLabel} onClick={onClose} />;
106-
const titleOptions = (
107-
<>
108-
{stepDisplay}
109-
{closeButton}
110-
</>
111-
);
112-
const actionButtons = [
113-
hasNextStep ? (
114-
<Button
115-
key={"next"}
116-
variant="outlined"
117-
intent={"primary"}
118-
onClick={() => {
119-
setCurrentStepIndex(currentStepIndex + 1);
120-
}}
121-
rightIcon={"navigation-next"}
122-
>
123-
{nextLabel}: {steps[currentStepIndex + 1].title}
124-
</Button>
125-
) : (
126-
<Button
127-
key={"close"}
128-
text={closeLabel}
129-
onClick={onClose}
130-
variant="outlined"
131-
intent={"primary"}
132-
rightIcon={"navigation-close"}
133-
/>
134-
),
135-
hasPreviousStep ? (
136-
<CardActionsAux>
81+
let lastObserver: MutationObserver | null = null;
82+
const setStepComponent = () => {
83+
const stepDisplay = (
84+
<Badge tagProps={{ emphasis: "weaker" }} size="large">
85+
{` ${currentStepIndex + 1}/${steps.length} `}
86+
</Badge>
87+
);
88+
const closeButton = <IconButton name="navigation-close" text={closeLabel} onClick={onClose} />;
89+
const titleOptions = (
90+
<>
91+
{stepDisplay}
92+
{closeButton}
93+
</>
94+
);
95+
const actionButtons = [
96+
hasNextStep ? (
13797
<Button
138-
key={"prev"}
98+
key={"next"}
13999
variant="outlined"
100+
intent={"primary"}
140101
onClick={() => {
141-
setCurrentStepIndex(currentStepIndex - 1);
102+
setCurrentStepIndex(currentStepIndex + 1);
142103
}}
143-
icon={"navigation-previous"}
104+
rightIcon={"navigation-next"}
144105
>
145-
{prevLabel}
106+
{nextLabel}: {steps[currentStepIndex + 1].title}
146107
</Button>
147-
</CardActionsAux>
148-
) : null,
149-
];
150-
// TODO: What to do if an element should have been highlighted, but none was found?
151-
if (elementToHighlight) {
152-
setCurrentStepComponent(
153-
<StepPopover
154-
highlightedElement={elementToHighlight}
155-
titleOption={titleOptions}
156-
actionButtons={actionButtons}
157-
step={step}
158-
/>
159-
);
160-
} else {
161-
setCurrentStepComponent(
162-
<StepModal titleOption={titleOptions} actionButtons={actionButtons} step={step} onClose={onClose} />
163-
);
108+
) : (
109+
<Button
110+
key={"close"}
111+
text={closeLabel}
112+
onClick={onClose}
113+
variant="outlined"
114+
intent={"primary"}
115+
rightIcon={"navigation-close"}
116+
/>
117+
),
118+
hasPreviousStep ? (
119+
<CardActionsAux>
120+
<Button
121+
key={"prev"}
122+
variant="outlined"
123+
onClick={() => {
124+
setCurrentStepIndex(currentStepIndex - 1);
125+
}}
126+
icon={"navigation-previous"}
127+
>
128+
{prevLabel}
129+
</Button>
130+
</CardActionsAux>
131+
) : null,
132+
];
133+
// TODO: What to do if an element should have been highlighted, but none was found?
134+
if (elementToHighlight) {
135+
setCurrentStepComponent(
136+
<StepPopover
137+
highlightedElement={elementToHighlight}
138+
titleOption={titleOptions}
139+
actionButtons={actionButtons}
140+
step={step}
141+
/>
142+
);
143+
} else {
144+
setCurrentStepComponent(
145+
<StepModal titleOption={titleOptions} actionButtons={actionButtons} step={step} onClose={onClose} />
146+
);
147+
}
148+
}
149+
const addElementHighlighting = () => {
150+
if (step.highlightElementQuery) {
151+
const queries: string[] =
152+
typeof step.highlightElementQuery === "string"
153+
? [step.highlightElementQuery]
154+
: step.highlightElementQuery;
155+
queries.forEach((query) => {
156+
if (elementToHighlight == null) {
157+
elementToHighlight = document.querySelector(query);
158+
}
159+
});
160+
} else {
161+
elementToHighlight = null
162+
}
163+
if (elementToHighlight) {
164+
// Typescript for some reason incorrectly infers the type of elementToHighlight as never
165+
(elementToHighlight as HTMLElement).classList.add(highlightElementClass);
166+
(elementToHighlight as HTMLElement).scrollIntoView({
167+
behavior: "smooth",
168+
block: "center",
169+
});
170+
if(lastObserver) {
171+
lastObserver.disconnect()
172+
}
173+
lastObserver = new MutationObserver(function () {
174+
// Re-new element highlighting
175+
if(step.highlightElementQuery) {
176+
if (!document.body.contains(elementToHighlight)) {
177+
// Element has been removed or replaced
178+
elementToHighlight = null;
179+
addElementHighlighting();
180+
} else if(!elementToHighlight?.classList.contains(highlightElementClass)) {
181+
// Only the classes have been removed
182+
elementToHighlight?.classList.add(highlightElementClass);
183+
}
184+
}
185+
});
186+
lastObserver.observe(document.body, {childList: true, subtree: true});
187+
}
188+
setStepComponent()
164189
}
190+
addElementHighlighting()
165191
return () => {
166192
// Remove previous element highlight
167193
document.querySelector(`.${highlightElementClass}`)?.classList.remove(highlightElementClass);
194+
if(lastObserver) {
195+
lastObserver.disconnect()
196+
}
168197
};
169198
}, [currentStepIndex]);
170199

0 commit comments

Comments
 (0)