Add support for listening to events
Browse files- index.html +20 -1
- src/config.ts +1 -1
- src/driver.ts +1 -2
- src/emitter.ts +1 -1
- src/events.ts +1 -1
- src/popover.ts +53 -1
- src/style.css +4 -0
index.html
CHANGED
|
@@ -161,7 +161,7 @@
|
|
| 161 |
<br />
|
| 162 |
<p>You can Attach events to buttons.</p>
|
| 163 |
<div class="buttons">
|
| 164 |
-
<button id="button-config-events">
|
| 165 |
</div>
|
| 166 |
|
| 167 |
<ul>
|
|
@@ -395,6 +395,25 @@ npm install driver.js</pre
|
|
| 395 |
});
|
| 396 |
});
|
| 397 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 398 |
document.getElementById("is-active-btn").addEventListener("click", () => {
|
| 399 |
alert(driver().isActive());
|
| 400 |
});
|
|
|
|
| 161 |
<br />
|
| 162 |
<p>You can Attach events to buttons.</p>
|
| 163 |
<div class="buttons">
|
| 164 |
+
<button id="button-config-events">Button Listeners</button>
|
| 165 |
</div>
|
| 166 |
|
| 167 |
<ul>
|
|
|
|
| 395 |
});
|
| 396 |
});
|
| 397 |
|
| 398 |
+
document.getElementById("button-config-events").addEventListener("click", () => {
|
| 399 |
+
const driverObj = driver({
|
| 400 |
+
onNextClick: () => alert("Next Clicked"),
|
| 401 |
+
onPrevClick: () => alert("Previous Clicked"),
|
| 402 |
+
onCloseClick: () => {
|
| 403 |
+
driverObj.destroy();
|
| 404 |
+
},
|
| 405 |
+
});
|
| 406 |
+
|
| 407 |
+
driverObj.highlight({
|
| 408 |
+
popover: {
|
| 409 |
+
title: "Global Button Listener",
|
| 410 |
+
description: "You can listen to the button clicks globally.",
|
| 411 |
+
showButtons: ["close", "next", "previous"],
|
| 412 |
+
onPrevClick: () => alert("Overriding — Previous Clicked"),
|
| 413 |
+
},
|
| 414 |
+
});
|
| 415 |
+
});
|
| 416 |
+
|
| 417 |
document.getElementById("is-active-btn").addEventListener("click", () => {
|
| 418 |
alert(driver().isActive());
|
| 419 |
});
|
src/config.ts
CHANGED
|
@@ -26,7 +26,7 @@ export type Config = {
|
|
| 26 |
|
| 27 |
// Event based callbacks, called upon events
|
| 28 |
onNextClick?: (element: Element | undefined, step: DriveStep) => void;
|
| 29 |
-
|
| 30 |
onCloseClick?: (element: Element | undefined, step: DriveStep) => void;
|
| 31 |
};
|
| 32 |
|
|
|
|
| 26 |
|
| 27 |
// Event based callbacks, called upon events
|
| 28 |
onNextClick?: (element: Element | undefined, step: DriveStep) => void;
|
| 29 |
+
onPrevClick?: (element: Element | undefined, step: DriveStep) => void;
|
| 30 |
onCloseClick?: (element: Element | undefined, step: DriveStep) => void;
|
| 31 |
};
|
| 32 |
|
src/driver.ts
CHANGED
|
@@ -42,7 +42,7 @@ export function driver(options: Config = {}) {
|
|
| 42 |
initEvents();
|
| 43 |
|
| 44 |
listen("overlayClick", handleClose);
|
| 45 |
-
listen("
|
| 46 |
}
|
| 47 |
|
| 48 |
function destroy() {
|
|
@@ -74,7 +74,6 @@ export function driver(options: Config = {}) {
|
|
| 74 |
},
|
| 75 |
drive: (steps: DriveStep[]) => console.log(steps),
|
| 76 |
highlight: (step: DriveStep) => {
|
| 77 |
-
console.log(step.popover?.showButtons);
|
| 78 |
init();
|
| 79 |
highlight({
|
| 80 |
...step,
|
|
|
|
| 42 |
initEvents();
|
| 43 |
|
| 44 |
listen("overlayClick", handleClose);
|
| 45 |
+
listen("escapePress", handleClose);
|
| 46 |
}
|
| 47 |
|
| 48 |
function destroy() {
|
|
|
|
| 74 |
},
|
| 75 |
drive: (steps: DriveStep[]) => console.log(steps),
|
| 76 |
highlight: (step: DriveStep) => {
|
|
|
|
| 77 |
init();
|
| 78 |
highlight({
|
| 79 |
...step,
|
src/emitter.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
type allowedEvents = "overlayClick" | "
|
| 2 |
|
| 3 |
let registeredListeners: Partial<{ [key in allowedEvents]: () => void }> = {};
|
| 4 |
|
|
|
|
| 1 |
+
type allowedEvents = "overlayClick" | "escapePress" | "nextClick" | "prevClick" | "closeClick";
|
| 2 |
|
| 3 |
let registeredListeners: Partial<{ [key in allowedEvents]: () => void }> = {};
|
| 4 |
|
src/events.ts
CHANGED
|
@@ -13,7 +13,7 @@ export function requireRefresh() {
|
|
| 13 |
|
| 14 |
function onKeyup(e: KeyboardEvent) {
|
| 15 |
if (e.key === "Escape") {
|
| 16 |
-
emit("
|
| 17 |
}
|
| 18 |
}
|
| 19 |
|
|
|
|
| 13 |
|
| 14 |
function onKeyup(e: KeyboardEvent) {
|
| 15 |
if (e.key === "Escape") {
|
| 16 |
+
emit("escapePress");
|
| 17 |
}
|
| 18 |
}
|
| 19 |
|
src/popover.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { bringInView } from "./utils";
|
|
| 2 |
import { getConfig } from "./config";
|
| 3 |
import { getState, setState } from "./state";
|
| 4 |
import { DriveStep } from "./driver";
|
|
|
|
|
|
|
| 5 |
|
| 6 |
export type Side = "top" | "right" | "bottom" | "left" | "over";
|
| 7 |
export type Alignment = "start" | "center" | "end";
|
|
@@ -15,10 +17,16 @@ export type Popover = {
|
|
| 15 |
|
| 16 |
showButtons?: AllowedButtons[];
|
| 17 |
|
|
|
|
| 18 |
doneBtnText?: string;
|
| 19 |
closeBtnText?: string;
|
| 20 |
nextBtnText?: string;
|
| 21 |
prevBtnText?: string;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
};
|
| 23 |
|
| 24 |
export type PopoverDOM = {
|
|
@@ -80,7 +88,6 @@ export function renderPopover(element: Element, step: DriveStep) {
|
|
| 80 |
const showButtonsConfig: AllowedButtons[] =
|
| 81 |
popoverShowButtons !== undefined ? popoverShowButtons : getConfig("showButtons")!;
|
| 82 |
|
| 83 |
-
console.log(popoverShowButtons);
|
| 84 |
if (showButtonsConfig?.length! > 0) {
|
| 85 |
popover.footer.style.display = "flex";
|
| 86 |
|
|
@@ -111,6 +118,51 @@ export function renderPopover(element: Element, step: DriveStep) {
|
|
| 111 |
const popoverArrow = popover.arrow;
|
| 112 |
popoverArrow.className = "driver-popover-arrow";
|
| 113 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 114 |
setState("popover", popover);
|
| 115 |
|
| 116 |
repositionPopover(element, step);
|
|
|
|
| 2 |
import { getConfig } from "./config";
|
| 3 |
import { getState, setState } from "./state";
|
| 4 |
import { DriveStep } from "./driver";
|
| 5 |
+
import { onDriverClick } from "./events";
|
| 6 |
+
import { emit } from "./emitter";
|
| 7 |
|
| 8 |
export type Side = "top" | "right" | "bottom" | "left" | "over";
|
| 9 |
export type Alignment = "start" | "center" | "end";
|
|
|
|
| 17 |
|
| 18 |
showButtons?: AllowedButtons[];
|
| 19 |
|
| 20 |
+
// Button texts
|
| 21 |
doneBtnText?: string;
|
| 22 |
closeBtnText?: string;
|
| 23 |
nextBtnText?: string;
|
| 24 |
prevBtnText?: string;
|
| 25 |
+
|
| 26 |
+
// Button callbacks
|
| 27 |
+
onNextClick?: (element: Element | undefined, step: DriveStep) => void;
|
| 28 |
+
onPrevClick?: (element: Element | undefined, step: DriveStep) => void;
|
| 29 |
+
onCloseClick?: (element: Element | undefined, step: DriveStep) => void;
|
| 30 |
};
|
| 31 |
|
| 32 |
export type PopoverDOM = {
|
|
|
|
| 88 |
const showButtonsConfig: AllowedButtons[] =
|
| 89 |
popoverShowButtons !== undefined ? popoverShowButtons : getConfig("showButtons")!;
|
| 90 |
|
|
|
|
| 91 |
if (showButtonsConfig?.length! > 0) {
|
| 92 |
popover.footer.style.display = "flex";
|
| 93 |
|
|
|
|
| 118 |
const popoverArrow = popover.arrow;
|
| 119 |
popoverArrow.className = "driver-popover-arrow";
|
| 120 |
|
| 121 |
+
// Handles the popover button clicks
|
| 122 |
+
onDriverClick(
|
| 123 |
+
popover.wrapper,
|
| 124 |
+
e => {
|
| 125 |
+
const target = e.target as HTMLElement;
|
| 126 |
+
|
| 127 |
+
const onNextClick = step.popover?.onNextClick || getConfig("onNextClick");
|
| 128 |
+
const onPrevClick = step.popover?.onPrevClick || getConfig("onPrevClick");
|
| 129 |
+
const onCloseClick = step.popover?.onCloseClick || getConfig("onCloseClick");
|
| 130 |
+
|
| 131 |
+
if (target.classList.contains("driver-popover-next-btn")) {
|
| 132 |
+
// If the user has provided a custom callback, call it
|
| 133 |
+
// otherwise, emit the event.
|
| 134 |
+
if (onNextClick) {
|
| 135 |
+
return onNextClick(element, step);
|
| 136 |
+
} else {
|
| 137 |
+
return emit("nextClick");
|
| 138 |
+
}
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
if (target.classList.contains("driver-popover-prev-btn")) {
|
| 142 |
+
if (onPrevClick) {
|
| 143 |
+
return onPrevClick(element, step);
|
| 144 |
+
} else {
|
| 145 |
+
return emit("prevClick");
|
| 146 |
+
}
|
| 147 |
+
}
|
| 148 |
+
|
| 149 |
+
if (target.classList.contains("driver-popover-close-btn")) {
|
| 150 |
+
if (onCloseClick) {
|
| 151 |
+
return onCloseClick(element, step);
|
| 152 |
+
} else {
|
| 153 |
+
return emit("closeClick");
|
| 154 |
+
}
|
| 155 |
+
}
|
| 156 |
+
|
| 157 |
+
return undefined;
|
| 158 |
+
},
|
| 159 |
+
target => {
|
| 160 |
+
// Only prevent the default action if we're clicking on a button
|
| 161 |
+
// This allows us to have links inside the popover title and description
|
| 162 |
+
return !popover?.description.contains(target) && !popover?.title.contains(target);
|
| 163 |
+
}
|
| 164 |
+
);
|
| 165 |
+
|
| 166 |
setState("popover", popover);
|
| 167 |
|
| 168 |
repositionPopover(element, step);
|
src/style.css
CHANGED
|
@@ -97,6 +97,10 @@
|
|
| 97 |
border-radius: 3px;
|
| 98 |
}
|
| 99 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 100 |
.driver-popover-navigation-btns {
|
| 101 |
display: flex;
|
| 102 |
flex-grow: 1;
|
|
|
|
| 97 |
border-radius: 3px;
|
| 98 |
}
|
| 99 |
|
| 100 |
+
.driver-popover-footer button:hover {
|
| 101 |
+
background-color: #f7f7f7;
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
.driver-popover-navigation-btns {
|
| 105 |
display: flex;
|
| 106 |
flex-grow: 1;
|