File size: 4,513 Bytes
aa3b624 66a740c 9db3a38 82a88c5 9bde4cc aa3b624 edd7dca aa3b624 edd7dca aa3b624 836d49f aa3b624 edd7dca aa3b624 70d8f15 aa3b624 836d49f 9a5b24f aa3b624 9a5b24f aa3b624 70d8f15 aa3b624 66a740c 70d8f15 836d49f 9db3a38 70d8f15 ef09b80 836d49f 34b7e3b ef09b80 d656141 eb375ea d656141 ef09b80 eb375ea ef09b80 34b7e3b 3b225cb 9db3a38 aa3b624 9bde4cc 4c98241 9bde4cc aa3b624 3b225cb 70d8f15 3b225cb aa3b624 66a740c 70d8f15 aa3b624 70d8f15 8480986 eb375ea ef09b80 9bde4cc ef09b80 aa3b624 9bde4cc aa3b624 70d8f15 836d49f 70d8f15 9db3a38 82a88c5 70d8f15 aa3b624 edd7dca aa3b624 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
import { DriveStep } from "./driver";
import { refreshStage, trackActiveElement, transitionStage } from "./stage";
import { getConfig } from "./config";
import { repositionPopover, renderPopover, hidePopover } from "./popover";
import { bringInView } from "./utils";
import { getState, setState } from "./state";
function mountDummyElement(): Element {
const existingDummy = document.getElementById("driver-dummy-element");
if (existingDummy) {
return existingDummy;
}
let element = document.createElement("div");
element.id = "driver-dummy-element";
element.style.width = "0";
element.style.height = "0";
element.style.pointerEvents = "none";
element.style.opacity = "0";
element.style.position = "fixed";
element.style.top = "50%";
element.style.left = "50%";
document.body.appendChild(element);
return element;
}
export function highlight(step: DriveStep) {
const { element } = step;
let elemObj = typeof element === "string" ? document.querySelector(element) : element;
// If the element is not found, we mount a 1px div
// at the center of the screen to highlight and show
// the popover on top of that. This is to show a
// modal-like highlight.
if (!elemObj) {
elemObj = mountDummyElement();
}
transferHighlight(elemObj, step);
}
export function refreshActiveHighlight() {
const activeHighlight = getState("activeElement");
const activeStep = getState("activeStep")!;
if (!activeHighlight) {
return;
}
trackActiveElement(activeHighlight);
refreshStage();
repositionPopover(activeHighlight, activeStep);
}
function transferHighlight(toElement: Element, toStep: DriveStep) {
const duration = 400;
const start = Date.now();
const fromStep = getState("activeStep");
const fromElement = getState("activeElement") || toElement;
// If it's the first time we're highlighting an element, we show
// the popover immediately. Otherwise, we wait for the animation
// to finish before showing the popover.
const isFirstHighlight = !fromElement || fromElement === toElement;
const isToDummyElement = toElement.id === "driver-dummy-element";
const isFromDummyElement = fromElement.id === "driver-dummy-element";
const isAnimatedTour = getConfig("animate");
const highlightStartedHook = getConfig("onHighlightStarted");
const highlightedHook = getConfig("onHighlighted");
const deselectedHook = getConfig("onDeselected");
if (!isFirstHighlight && deselectedHook) {
deselectedHook(isFromDummyElement ? undefined : fromElement, fromStep!);
}
if (highlightStartedHook) {
highlightStartedHook(isToDummyElement ? undefined : toElement, toStep);
}
const hasDelayedPopover = !isFirstHighlight && isAnimatedTour;
let isPopoverRendered = false;
hidePopover();
const animate = () => {
const transitionCallback = getState("transitionCallback");
// This makes sure that the repeated calls to transferHighlight
// don't interfere with each other. Only the last call will be
// executed.
if (transitionCallback !== animate) {
return;
}
const elapsed = Date.now() - start;
const timeRemaining = duration - elapsed;
const isHalfwayThrough = timeRemaining <= duration / 2;
if (toStep.popover && isHalfwayThrough && !isPopoverRendered && hasDelayedPopover) {
renderPopover(toElement, toStep);
isPopoverRendered = true;
}
if (getConfig("animate") && elapsed < duration) {
transitionStage(elapsed, duration, fromElement, toElement);
} else {
trackActiveElement(toElement);
if (highlightedHook) {
highlightedHook(isToDummyElement ? undefined : toElement, toStep);
}
setState("transitionCallback", undefined);
setState("previousStep", fromStep);
setState("previousElement", fromElement);
setState("activeStep", toStep);
setState("activeElement", toElement);
}
window.requestAnimationFrame(animate);
};
setState("transitionCallback", animate);
window.requestAnimationFrame(animate);
bringInView(toElement);
if (!hasDelayedPopover && toStep.popover) {
renderPopover(toElement, toStep);
}
fromElement.classList.remove("driver-active-element");
toElement.classList.add("driver-active-element");
}
export function destroyHighlight() {
document.getElementById("driver-dummy-element")?.remove();
document.querySelectorAll(".driver-active-element").forEach(element => {
element.classList.remove("driver-active-element");
});
}
|