File size: 3,079 Bytes
aa3b624 66a740c 9db3a38 82a88c5 aa3b624 4c98241 aa3b624 edd7dca aa3b624 edd7dca aa3b624 edd7dca aa3b624 75e70b4 aa3b624 66a740c 9db3a38 aa3b624 4c98241 aa3b624 66a740c aa3b624 8480986 9db3a38 4c98241 aa3b624 4c98241 aa3b624 82a88c5 9db3a38 82a88c5 aa3b624 4c98241 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 |
import { DriveStep } from "./driver";
import { refreshStage, trackActiveElement, transitionStage } from "./stage";
import { getConfig } from "./config";
import { repositionPopover, renderPopover, hidePopover } from "./popover";
import { bringInView } from "./utils";
let previousHighlight: Element | undefined;
let activeHighlight: Element | undefined;
let currentTransitionCallback: undefined | (() => void);
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 (!elemObj) {
elemObj = mountDummyElement();
}
previousHighlight = activeHighlight;
activeHighlight = elemObj;
transferHighlight(previousHighlight || elemObj, elemObj);
}
export function refreshActiveHighlight() {
if (!activeHighlight) {
return;
}
trackActiveElement(activeHighlight);
refreshStage();
repositionPopover(activeHighlight);
}
function transferHighlight(from: Element, to: Element) {
const duration = 400;
const start = Date.now();
// 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 hasDelayedPopover = !from || from !== to;
hidePopover();
const animate = () => {
// This makes sure that the repeated calls to transferHighlight
// don't interfere with each other. Only the last call will be
// executed.
if (currentTransitionCallback !== animate) {
return;
}
const elapsed = Date.now() - start;
if (getConfig("animate") && elapsed < duration) {
transitionStage(elapsed, duration, from, to);
} else {
trackActiveElement(to);
if (hasDelayedPopover) {
renderPopover(to);
}
currentTransitionCallback = undefined;
}
window.requestAnimationFrame(animate);
};
currentTransitionCallback = animate;
window.requestAnimationFrame(animate);
bringInView(to);
if (!hasDelayedPopover) {
renderPopover(to);
}
from.classList.remove("driver-active-element");
to.classList.add("driver-active-element");
}
export function destroyHighlight() {
activeHighlight = undefined;
currentTransitionCallback = undefined;
previousHighlight = undefined;
activeHighlight = undefined;
document.getElementById("driver-dummy-element")?.remove();
document.querySelectorAll(".driver-active-element").forEach(element => {
element.classList.remove("driver-active-element");
});
}
|