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;
|