Add tour functionality

This commit is contained in:
Kamran Ahmed
2023-06-18 03:14:07 +01:00
parent 28ba7df565
commit 6aa2828e21
5 changed files with 172 additions and 42 deletions
+87 -22
View File
@@ -183,6 +183,7 @@
<button id="next-prev-button">Next Previous Buttons</button>
<button id="close-button">Close Buttons</button>
<button id="button-texts">Button Texts</button>
<button id="disabled-buttons">Disabled Buttons</button>
<button id="button-config-events">Button Listeners</button>
</div>
@@ -193,6 +194,12 @@
<button id="popover-hook">Popover Hook</button>
</div>
<h2>Tour Feature</h2>
<p>Examples below show the tour usage of driver.js.</p>
<div class="buttons">
<button id="basic-tour">Basic Tour</button>
</div>
<ul>
<li>Written in TypeScript</li>
<li>Lightweight — only 5kb gzipped</li>
@@ -324,6 +331,51 @@ npm install driver.js</pre
<script type="module">
import { driver } from "./src/driver.ts";
document.getElementById("basic-tour").addEventListener("click", () => {
const driverObj = driver({
steps: [
{
element: ".page-header",
popover: {
title: "New and Improved Driver.js",
description:
"Driver.js has been written from the ground up. The new version is more powerful, has less surprises, more customizable and tons of new features.",
side: "bottom",
align: "start",
},
},
{
element: ".page-header h1",
popover: {
title: "No Stacking Issues",
description:
"Unlike the older version, new version doesn't work with z-indexes so no more positional issues.",
side: "left",
align: "start",
},
},
{
element: ".page-header sup",
popover: {
title: "Improved Hooks",
description:
"Unlike the older version, new version doesn't work with z-indexes so no more positional issues.",
side: "bottom",
align: "start",
},
},
{
popover: {
title: "No Element",
description: "You can now have popovers without elements as well",
},
},
],
});
driverObj.drive();
});
document.getElementById("no-buttons").addEventListener("click", () => {
const driverObj = driver({});
@@ -426,37 +478,50 @@ npm install driver.js</pre
document.getElementById("popover-hook").addEventListener("click", () => {
const driverObj = driver({
onPopoverRendered: (popover) => {
popover.title.innerText = 'Modified Parent';
}
onPopoverRendered: popover => {
popover.title.innerText = "Modified Parent";
},
});
driverObj.highlight({
element: '.page-header',
element: ".page-header",
popover: {
title: 'Page Title',
description: 'Body of the popover',
side: 'bottom',
align: 'start',
onPopoverRendered: (popover) => {
popover.title.innerText = 'Modified';
}
}
})
title: "Page Title",
description: "Body of the popover",
side: "bottom",
align: "start",
onPopoverRendered: popover => {
popover.title.innerText = "Modified";
},
},
});
});
document.getElementById("custom-classes").addEventListener("click", () => {
const driverObj = driver({
popoverClass: "custom-driver-popover"
})
popoverClass: "custom-driver-popover",
});
driverObj.highlight({
popover: {
popoverClass: "custom-driver-popover",
title: "Custom Classes",
description: "Popover and buttons have custom classes",
showButtons: ["close", "next", "previous"]
}
})
showButtons: ["close", "next", "previous"],
},
});
});
document.getElementById("disabled-buttons").addEventListener("click", () => {
const driverObj = driver();
driverObj.highlight({
element: "#disabled-buttons",
popover: {
title: "Disable Buttons",
description: "You can selectively disable buttons as well",
showButtons: ["next", "previous", "close"],
disableButtons: ["next", "previous"],
},
});
});
document.getElementById("button-config-events").addEventListener("click", () => {
@@ -623,19 +688,19 @@ npm install driver.js</pre
const driverObj = driver({
animate: true,
onDeselected: (element, step) => {
const elementText = element?.textContent?.slice(0, 10) || ' - N/A -';
const elementText = element?.textContent?.slice(0, 10) || " - N/A -";
console.log(`Deselected: ${elementText}\n${JSON.stringify(step)}`);
},
onHighlightStarted: (element, step) => {
const elementText = element?.textContent?.slice(0, 10) || ' - N/A -';
const elementText = element?.textContent?.slice(0, 10) || " - N/A -";
console.log(`Highlight Started: ${elementText}\n${JSON.stringify(step)}`);
},
onHighlighted: (element, step) => {
const elementText = element?.textContent?.slice(0, 10) || ' - N/A -';
const elementText = element?.textContent?.slice(0, 10) || " - N/A -";
console.log(`Highlighted: ${elementText}\n${JSON.stringify(step)}`);
},
onDestroyed: (element, step) => {
const elementText = element?.textContent?.slice(0, 10) || ' - N/A -';
const elementText = element?.textContent?.slice(0, 10) || " - N/A -";
console.log(`Destroyed: ${elementText}\n${JSON.stringify(step)}`);
},
});
+5
View File
@@ -2,6 +2,8 @@ import { DriveStep } from "./driver";
import {AllowedButtons, PopoverDOM} from "./popover";
export type Config = {
steps?: DriveStep[];
animate?: boolean;
backdropColor?: string;
smoothScroll?: boolean;
@@ -15,11 +17,13 @@ export type Config = {
popoverClass?: string;
popoverOffset?: number;
showButtons?: AllowedButtons[];
disableButtons?: AllowedButtons[];
// Button texts
nextBtnText?: string;
prevBtnText?: string;
closeBtnText?: string;
doneBtnText?: string;
// Called after the popover is rendered
onPopoverRendered?: (popover: PopoverDOM) => void;
@@ -49,6 +53,7 @@ export function configure(config: Config = {}) {
stageRadius: 5,
popoverOffset: 10,
showButtons: ["next", "previous", "close"],
disableButtons: [],
backdropColor: "#000",
...config,
};
+48 -2
View File
@@ -1,4 +1,4 @@
import { destroyPopover, Popover } from "./popover";
import { AllowedButtons, destroyPopover, Popover } from "./popover";
import { destroyStage } from "./stage";
import { destroyEvents, initEvents, requireRefresh } from "./events";
import { Config, configure, getConfig } from "./config";
@@ -38,6 +38,49 @@ export function driver(options: Config = {}) {
listen("escapePress", handleClose);
}
function drive(stepIndex: number = 0) {
const steps = getConfig("steps");
if (!steps) {
console.error("No steps to drive through");
destroy();
return;
}
if (!steps[stepIndex]) {
console.warn(`Step not found at index: ${stepIndex}`);
destroy();
}
const currentStep = steps[stepIndex];
const hasNextStep = steps[stepIndex + 1];
const hasPreviousStep = steps[stepIndex - 1];
const doneBtnText = currentStep.popover?.doneBtnText || getConfig("doneBtnText") || "Done";
highlight({
...currentStep,
popover: {
showButtons: ["next", "previous", "close"],
nextBtnText: !hasNextStep ? doneBtnText : undefined,
disableButtons: [...(!hasPreviousStep ? ["previous" as AllowedButtons] : [])],
onNextClick: () => {
if (!hasNextStep) {
destroy();
} else {
drive(stepIndex + 1);
}
},
onPrevClick: () => {
drive(stepIndex - 1);
},
onCloseClick: () => {
destroy();
},
...(currentStep?.popover || {}),
},
});
}
function destroy() {
const activeElement = getState("activeElement");
const activeStep = getState("activeStep");
@@ -72,7 +115,10 @@ export function driver(options: Config = {}) {
refresh: () => {
requireRefresh();
},
drive: (steps: DriveStep[]) => console.log(steps),
drive: (stepIndex: number = 0) => {
init();
drive(stepIndex);
},
highlight: (step: DriveStep) => {
init();
highlight({
+27 -18
View File
@@ -11,11 +11,12 @@ export type AllowedButtons = "next" | "previous" | "close";
export type Popover = {
title?: string;
description: string;
description?: string;
side?: Side;
align?: Alignment;
showButtons?: AllowedButtons[];
disableButtons?: AllowedButtons[];
popoverClass?: string;
@@ -57,15 +58,19 @@ export function hidePopover() {
export function renderPopover(element: Element, step: DriveStep) {
let popover = getState("popover");
if (!popover) {
popover = createPopover();
document.body.appendChild(popover.wrapper);
if (popover) {
document.body.removeChild(popover.wrapper);
}
popover = createPopover();
document.body.appendChild(popover.wrapper);
const {
title,
description,
showButtons: popoverShowButtons = undefined,
showButtons,
disableButtons,
// doneBtnText = 'Done',
closeBtnText = getConfig("closeBtnText") || "Close",
nextBtnText = getConfig("nextBtnText") || "Next &rarr;",
@@ -90,27 +95,31 @@ export function renderPopover(element: Element, step: DriveStep) {
popover.description.style.display = "none";
}
const showButtonsConfig: AllowedButtons[] =
popoverShowButtons !== undefined ? popoverShowButtons : getConfig("showButtons")!;
const showButtonsConfig: AllowedButtons[] = showButtons || getConfig("showButtons")!;
if (showButtonsConfig?.length! > 0) {
popover.footer.style.display = "flex";
if (!showButtonsConfig.includes("next")) {
popover.nextButton.style.display = "none";
}
if (!showButtonsConfig.includes("previous")) {
popover.previousButton.style.display = "none";
}
if (!showButtonsConfig.includes("close")) {
popover.closeButton.style.display = "none";
}
popover.nextButton.style.display = showButtonsConfig.includes("next") ? 'block' : 'none';
popover.previousButton.style.display = showButtonsConfig.includes("previous") ? 'block' : 'none';
popover.closeButton.style.display = showButtonsConfig.includes("close") ? 'block' : 'none';
} else {
popover.footer.style.display = "none";
}
const disabledButtonsConfig: AllowedButtons[] = disableButtons || getConfig('disableButtons')! || [];
if (disabledButtonsConfig?.includes('next')) {
popover.nextButton.classList.add("driver-popover-btn-disabled")
}
if (disabledButtonsConfig?.includes('previous')) {
popover.previousButton.classList.add("driver-popover-btn-disabled")
}
if (disabledButtonsConfig?.includes('close')) {
popover.closeButton.classList.add("driver-popover-btn-disabled")
}
// Reset the popover position
const popoverWrapper = popover.wrapper;
popoverWrapper.style.display = "block";
+5
View File
@@ -97,6 +97,11 @@
border-radius: 3px;
}
.driver-popover-footer .driver-popover-btn-disabled {
opacity: 0.5;
pointer-events: none;
}
/* Disable the scrolling of parent element if it has an active element*/
:not(body):has(> .driver-active-element) {
overflow: hidden !important;