Add tour control using keyboard keys
Browse files- index.html +14 -0
- src/driver.ts +32 -0
- src/emitter.ts +8 -1
- src/events.ts +4 -0
- src/state.ts +2 -0
index.html
CHANGED
|
@@ -370,6 +370,20 @@ npm install driver.js</pre
|
|
| 370 |
description: "You can now have popovers without elements as well",
|
| 371 |
},
|
| 372 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 373 |
],
|
| 374 |
});
|
| 375 |
|
|
|
|
| 370 |
description: "You can now have popovers without elements as well",
|
| 371 |
},
|
| 372 |
},
|
| 373 |
+
{
|
| 374 |
+
element: "#scrollable-area",
|
| 375 |
+
popover: {
|
| 376 |
+
title: "Scrollable Areas",
|
| 377 |
+
description: "There are no issues with scrollable element tours as well."
|
| 378 |
+
}
|
| 379 |
+
},
|
| 380 |
+
{
|
| 381 |
+
element: "#third-scroll-paragraph",
|
| 382 |
+
popover: {
|
| 383 |
+
title: "Nested Scrolls",
|
| 384 |
+
description: "Even the nested scrollable elements work now."
|
| 385 |
+
}
|
| 386 |
+
}
|
| 387 |
],
|
| 388 |
});
|
| 389 |
|
src/driver.ts
CHANGED
|
@@ -24,6 +24,34 @@ export function driver(options: Config = {}) {
|
|
| 24 |
destroy();
|
| 25 |
}
|
| 26 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
function init() {
|
| 28 |
if (getState("isInitialized")) {
|
| 29 |
return;
|
|
@@ -36,6 +64,8 @@ export function driver(options: Config = {}) {
|
|
| 36 |
|
| 37 |
listen("overlayClick", handleClose);
|
| 38 |
listen("escapePress", handleClose);
|
|
|
|
|
|
|
| 39 |
}
|
| 40 |
|
| 41 |
function drive(stepIndex: number = 0) {
|
|
@@ -51,6 +81,8 @@ export function driver(options: Config = {}) {
|
|
| 51 |
destroy();
|
| 52 |
}
|
| 53 |
|
|
|
|
|
|
|
| 54 |
const currentStep = steps[stepIndex];
|
| 55 |
const hasNextStep = steps[stepIndex + 1];
|
| 56 |
const hasPreviousStep = steps[stepIndex - 1];
|
|
|
|
| 24 |
destroy();
|
| 25 |
}
|
| 26 |
|
| 27 |
+
function handleArrowLeft() {
|
| 28 |
+
const steps = getConfig("steps") || [];
|
| 29 |
+
const currentStepIndex = getState("currentStepIndex");
|
| 30 |
+
if (typeof currentStepIndex === "undefined") {
|
| 31 |
+
return;
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
const previousStepIndex = currentStepIndex - 1;
|
| 35 |
+
if (steps[previousStepIndex]) {
|
| 36 |
+
drive(previousStepIndex);
|
| 37 |
+
}
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
function handleArrowRight() {
|
| 41 |
+
const steps = getConfig("steps") || [];
|
| 42 |
+
const currentStepIndex = getState("currentStepIndex");
|
| 43 |
+
if (typeof currentStepIndex === "undefined") {
|
| 44 |
+
return;
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
const nextStepIndex = currentStepIndex + 1;
|
| 48 |
+
if (steps[nextStepIndex]) {
|
| 49 |
+
drive(nextStepIndex);
|
| 50 |
+
} else {
|
| 51 |
+
destroy();
|
| 52 |
+
}
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
function init() {
|
| 56 |
if (getState("isInitialized")) {
|
| 57 |
return;
|
|
|
|
| 64 |
|
| 65 |
listen("overlayClick", handleClose);
|
| 66 |
listen("escapePress", handleClose);
|
| 67 |
+
listen("arrowLeftPress", handleArrowLeft);
|
| 68 |
+
listen("arrowRightPress", handleArrowRight);
|
| 69 |
}
|
| 70 |
|
| 71 |
function drive(stepIndex: number = 0) {
|
|
|
|
| 81 |
destroy();
|
| 82 |
}
|
| 83 |
|
| 84 |
+
setState("currentStepIndex", stepIndex);
|
| 85 |
+
|
| 86 |
const currentStep = steps[stepIndex];
|
| 87 |
const hasNextStep = steps[stepIndex + 1];
|
| 88 |
const hasPreviousStep = steps[stepIndex - 1];
|
src/emitter.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
| 1 |
-
type allowedEvents =
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
|
| 3 |
let registeredListeners: Partial<{ [key in allowedEvents]: () => void }> = {};
|
| 4 |
|
|
|
|
| 1 |
+
type allowedEvents =
|
| 2 |
+
| "overlayClick"
|
| 3 |
+
| "escapePress"
|
| 4 |
+
| "nextClick"
|
| 5 |
+
| "prevClick"
|
| 6 |
+
| "closeClick"
|
| 7 |
+
| "arrowRightPress"
|
| 8 |
+
| "arrowLeftPress";
|
| 9 |
|
| 10 |
let registeredListeners: Partial<{ [key in allowedEvents]: () => void }> = {};
|
| 11 |
|
src/events.ts
CHANGED
|
@@ -20,6 +20,10 @@ function onKeyup(e: KeyboardEvent) {
|
|
| 20 |
|
| 21 |
if (e.key === "Escape") {
|
| 22 |
emit("escapePress");
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
}
|
| 24 |
}
|
| 25 |
|
|
|
|
| 20 |
|
| 21 |
if (e.key === "Escape") {
|
| 22 |
emit("escapePress");
|
| 23 |
+
} else if (e.key === "ArrowRight") {
|
| 24 |
+
emit("arrowRightPress");
|
| 25 |
+
} else if (e.key === "ArrowLeft") {
|
| 26 |
+
emit("arrowLeftPress");
|
| 27 |
}
|
| 28 |
}
|
| 29 |
|
src/state.ts
CHANGED
|
@@ -5,6 +5,8 @@ import { DriveStep } from "./driver";
|
|
| 5 |
export type State = {
|
| 6 |
// Whether driver is initialized or not
|
| 7 |
isInitialized?: boolean;
|
|
|
|
|
|
|
| 8 |
|
| 9 |
// Used to bounce the resize event
|
| 10 |
resizeTimeout?: number;
|
|
|
|
| 5 |
export type State = {
|
| 6 |
// Whether driver is initialized or not
|
| 7 |
isInitialized?: boolean;
|
| 8 |
+
// Index of the currently active step in driver tour
|
| 9 |
+
currentStepIndex?: number;
|
| 10 |
|
| 11 |
// Used to bounce the resize event
|
| 12 |
resizeTimeout?: number;
|