99 lines
2.6 KiB
TypeScript
99 lines
2.6 KiB
TypeScript
import { StepType, TourContext, TourProvider } from "@reactour/tour";
|
|
import clsx from "clsx";
|
|
import { Dispatch, FC, HTMLAttributes, SetStateAction } from "react";
|
|
|
|
import QuestionIcon from "@dndbeyond/fontawesome-cache/svgs/solid/question.svg";
|
|
|
|
import { Button } from "../Button";
|
|
import styles from "./styles.module.css";
|
|
|
|
export interface GuidedTourProps extends HTMLAttributes<HTMLDivElement> {
|
|
afterOpen?: (target: Element | null) => void;
|
|
beforeClose?: (target: Element | null) => void;
|
|
cookieName?: string;
|
|
setStep?: SetStateAction<any>;
|
|
showOnFirstLoad?: boolean;
|
|
steps?: StepType[];
|
|
step?: number;
|
|
}
|
|
|
|
export const GuidedTour: FC<GuidedTourProps> = ({
|
|
afterOpen,
|
|
beforeClose,
|
|
children,
|
|
className,
|
|
cookieName = "ddbGuidedTour",
|
|
setStep,
|
|
showOnFirstLoad,
|
|
step = 0,
|
|
steps = [],
|
|
...props
|
|
}) => {
|
|
const handleBeforeClose = () => {
|
|
const html = document.querySelector("html");
|
|
if (html) html.style.overflowY = "visible";
|
|
if (beforeClose) beforeClose(null);
|
|
};
|
|
|
|
const handleAfterOpen = () => {
|
|
const html = document.querySelector("html");
|
|
if (html) html.style.overflowY = "hidden";
|
|
if (afterOpen) afterOpen(null);
|
|
};
|
|
|
|
const handleLoad = (setIsOpen: Dispatch<SetStateAction<boolean>>) => {
|
|
if (showOnFirstLoad) {
|
|
const viewedTour = localStorage.getItem(cookieName);
|
|
|
|
if (!viewedTour) {
|
|
setIsOpen(true);
|
|
localStorage.setItem(cookieName, "true");
|
|
}
|
|
}
|
|
};
|
|
|
|
const PrevButton = ({ Button, ...props }) => (
|
|
<Button {...props} kind="prev" hideArrow={step === 0} />
|
|
);
|
|
|
|
const NextButton = ({ Button, ...props }) => (
|
|
<Button
|
|
{...props}
|
|
kind="next"
|
|
hideArrow={step === (steps?.length || 0) - 1}
|
|
/>
|
|
);
|
|
|
|
return (
|
|
<div className={clsx([styles.guidedTour, className])} {...props}>
|
|
<TourProvider
|
|
steps={steps}
|
|
currentStep={step}
|
|
setCurrentStep={setStep}
|
|
afterOpen={handleAfterOpen}
|
|
beforeClose={handleBeforeClose}
|
|
showDots={false}
|
|
prevButton={PrevButton}
|
|
nextButton={NextButton}
|
|
>
|
|
<TourContext.Consumer>
|
|
{({ setIsOpen }) => (
|
|
<div onLoad={() => handleLoad(setIsOpen)}>
|
|
{children}
|
|
<Button
|
|
className={styles.tourButton}
|
|
onClick={() => setIsOpen(true)}
|
|
color="info"
|
|
size="small"
|
|
aria-label="Open guided tour"
|
|
>
|
|
<QuestionIcon />
|
|
</Button>
|
|
</div>
|
|
)}
|
|
</TourContext.Consumer>
|
|
</TourProvider>
|
|
</div>
|
|
);
|
|
};
|