@globalhive/vuejs-tour
Version:
VueJS Tour is a lightweight, simple and customizable tour plugin. It provides a quick and easy way to guide your users through your application.
346 lines (345 loc) • 13.8 kB
JavaScript
import { defineComponent as be, computed as v, ref as d, reactive as ue, onMounted as Se, onUnmounted as we, watch as Te, nextTick as N, createBlock as ke, openBlock as w, Teleport as $e, createElementVNode as T, normalizeClass as Le, normalizeStyle as xe, createElementBlock as L, createCommentVNode as x, renderSlot as se, toDisplayString as C, withModifiers as U } from "vue";
import { createPopper as Ce } from "nanopop";
import Ae from "jump.js";
const Ee = (e, n, o, t) => (e /= t, o * e * e + n), Be = (e, n, o, t) => (e /= t, -o * e * (e - 2) + n), ie = (e, n, o, t) => (e /= t / 2, e < 1 ? o / 2 * e * e + n : (e--, -o / 2 * (e * (e - 2) - 1) + n)), De = (e, n, o, t) => (e /= t, o * e * e * e + n), je = (e, n, o, t) => (e /= t, e--, o * (e * e * e + 1) + n), Ie = (e, n, o, t) => (e /= t / 2, e < 1 ? o / 2 * e * e * e + n : (e -= 2, o / 2 * (e * e * e + 2) + n)), Oe = (e, n, o, t) => (e /= t, o * e * e * e * e + n), Pe = (e, n, o, t) => (e /= t, e--, -o * (e * e * e * e - 1) + n), _e = (e, n, o, t) => (e /= t / 2, e < 1 ? o / 2 * e * e * e * e + n : (e -= 2, -o / 2 * (e * e * e * e - 2) + n)), Ne = (e, n, o, t) => (e /= t, o * e * e * e * e * e + n), qe = (e, n, o, t) => (e /= t, e--, o * (e * e * e * e * e + 1) + n), Me = (e, n, o, t) => (e /= t / 2, e < 1 ? o / 2 * e * e * e * e * e + n : (e -= 2, o / 2 * (e * e * e * e * e + 2) + n)), Qe = {
easeInQuad: Ee,
easeOutQuad: Be,
easeInOutQuad: ie,
easeInCubic: De,
easeOutCubic: je,
easeInOutCubic: Ie,
easeInQuart: Oe,
easeOutQuart: Pe,
easeInOutQuart: _e,
easeInQuint: Ne,
easeOutQuint: qe,
easeInOutQuint: Me
}, ze = ["data-hidden"], Ve = ["id", "data-hidden"], Re = ["id", "aria-modal", "aria-label", "aria-describedby", "tabindex", "data-hidden"], Fe = {
key: 0,
role: "status",
"aria-live": "polite",
"aria-atomic": "true",
class: "vjt-sr-only"
}, He = ["id"], Ue = ["id", "innerHTML"], Ge = { class: "vjt-actions" }, Ke = ["aria-label"], Je = ["aria-label"], We = ["aria-label"], tt = /* @__PURE__ */ be({
__name: "VTour",
props: {
name: { default: "tour" },
steps: {},
backdrop: { type: Boolean, default: !1 },
autoStart: { type: Boolean, default: !1 },
startDelay: { default: 0 },
highlight: { type: Boolean, default: !1 },
margin: { default: 8 },
buttonLabels: {},
saveToLocalStorage: { default: "never" },
hideSkip: { type: Boolean, default: !1 },
hideArrow: { type: Boolean, default: !1 },
noScroll: { type: Boolean, default: !1 },
resizeTimeout: { default: 250 },
defaultPlacement: { default: "right" },
jumpOptions: {},
enableA11y: { type: Boolean, default: !1 },
keyboardNav: { type: Boolean, default: !0 },
ariaLabel: { default: "Guided tour" },
teleportDelay: { default: 100 },
restartOnPropChange: { type: Boolean, default: !0 }
},
emits: ["onTourStart", "onTourEnd", "onTourStep"],
setup(e, { expose: n, emit: o }) {
const t = e, q = o, k = v(() => t.name ? `vjt-${t.name}` : "vjt-tour"), h = d(), l = d(0), i = d(0), p = d(1), g = v(() => t.steps[l.value]), ce = v(() => t.steps[i.value]), ve = v(() => t.steps[p.value]), G = ue({
currentStep: l,
lastStep: i,
nextStep: p,
getCurrentStep: g,
getLastStep: ce,
getNextStep: ve
}), K = v(
() => l.value === t.steps.length - 1
), J = v(() => K.value ? t.buttonLabels?.done ?? "Done" : t.buttonLabels?.next ?? "Next"), A = d(""), s = d(!1), M = d(!1), de = d("right"), f = d(!1), Q = v(() => t.name ? `vjt-${t.name}` : "vjt"), E = v(() => `${Q.value}-vjt-tooltip`), W = v(() => `${Q.value}-vjt-backdrop`), fe = v(() => `${Q.value}-vjt-arrow`), y = v(
() => t.name ? `${t.name}vjt-highlight` : "vjt-highlight"
), m = d(), X = d();
let B = null;
const Y = {
duration: 500,
offset: -100
}, D = () => localStorage.getItem(k.value) === "true", j = ue({
name: void 0,
stepsRef: null
}), I = async () => {
if (!D()) {
if (s.value) {
const a = t.name !== j.name, r = t.steps !== j.stepsRef;
if (!(a || r))
return;
b(), await N();
}
if (t.saveToLocalStorage === "step") {
const a = localStorage.getItem(k.value);
l.value = parseInt(a || "0", 10), l.value > 0 && (i.value = Math.max(l.value - 1, 0), p.value = l.value + 1);
} else
l.value = 0;
R = setTimeout(async () => {
await _(l.value);
const a = g.value;
if (!a) {
console.warn("No step data available");
return;
}
const r = document.querySelector(
a.target
);
if (!r) {
console.warn(`Tour target element not found: ${a.target}`);
return;
}
if (await new Promise((u) => {
F = setTimeout(u, t.teleportDelay);
}), m.value || (m.value = document.querySelector(
`#${E.value}`
)), X.value || (X.value = document.querySelector(
`#${W.value}`
)), !m.value) {
console.warn("Tooltip element not found in DOM");
return;
}
t.enableA11y && typeof document < "u" && (B = document.activeElement), s.value = !0, f.value = !0, await N();
{
const u = t.highlight || a.highlight, c = t.margin || (u ? 14 : 8);
h.value = Ce(r, m.value, {
position: a.placement || t.defaultPlacement,
margin: c
});
}
await $(), f.value = !1, t.enableA11y && (await N(), m.value?.focus()), j.name = t.name, j.stepsRef = t.steps, q("onTourStart");
}, t.startDelay);
}
}, b = () => {
clearTimeout(R), clearTimeout(F), s.value = !1, M.value = !1, f.value = !1, document.querySelectorAll(`.${y.value}`).forEach((a) => a.classList.remove(y.value)), h.value && (h.value = void 0), t.enableA11y && B && (B.focus(), B = null);
}, pe = (a = !1) => {
b(), l.value = 0, i.value = 0, p.value = 1, localStorage.removeItem(k.value), a && I();
}, O = async () => {
if (await _(p.value), f.value = !0, i.value = l.value, l.value++, l.value > t.steps.length - 1) {
S();
return;
}
p.value = l.value + 1, await $(), f.value = !1;
}, P = async () => {
if (await _(i.value), f.value = !0, l.value = i.value, i.value = Math.max(i.value - 1, 0), l.value < 0) {
S();
return;
}
p.value = l.value + 1, await $(), f.value = !1;
}, S = () => {
b(), t.saveToLocalStorage !== "never" && localStorage.setItem(k.value, "true"), q("onTourEnd");
}, me = async (a) => {
if (a < 0 || a >= t.steps.length) {
console.warn(`Invalid step index: ${a}`);
return;
}
await _(a), f.value = !0, l.value = a, i.value = Math.max(a - 1, 0), p.value = a + 1, await $(), f.value = !1;
}, _ = async (a) => {
const r = t.steps[a];
r?.onBefore && await r.onBefore();
}, ge = (a) => {
!a || !m.value || (m.value.setAttribute("data-arrow", a), de.value = a);
}, Z = () => {
const a = g.value;
if (!a || !h.value) return;
const r = document.querySelector(
a.target
);
if (!r) return;
ee(), te();
const u = h.value.update({
reference: r,
position: a.placement || t.defaultPlacement
});
ge(u || t.defaultPlacement);
}, $ = async () => {
const a = g.value;
if (!a) return;
const r = document.querySelector(
a.target
);
!r || !m.value || !h.value || (!t.noScroll && !a.noScroll && await new Promise((u) => {
const c = {
duration: Y.duration,
offset: Y.offset,
easing: "easeInOutQuad",
a11y: t.enableA11y,
...t.jumpOptions,
...a.jumpOptions
}, H = Qe[c.easing] || ie;
Ae(r, {
duration: c.duration,
offset: c.offset,
easing: H,
a11y: c.a11y,
callback: () => u()
});
}), Z(), t.saveToLocalStorage === "step" && localStorage.setItem(k.value, l.value.toString()), a.onAfter && await a.onAfter(), q("onTourStep", l.value));
}, ee = () => {
document.querySelectorAll(`.${y.value}`).forEach((u) => u.classList.remove(y.value));
const a = g.value;
if (!a || !t.highlight && !a.highlight) {
A.value = "";
return;
}
const r = document.querySelector(
a.target
);
r && (r.classList.add(y.value), A.value = he(`.${y.value}`));
}, te = () => {
const a = g.value, r = t.backdrop || !!a?.backdrop;
M.value = r;
}, z = () => {
D() || s.value && Z();
};
let V, R, F;
const ae = () => {
D() || (clearTimeout(V), z(), V = setTimeout(() => {
z();
}, t.resizeTimeout));
};
function he(a) {
if (typeof document > "u") return "";
const r = document.querySelector(a);
if (!r) return "";
const u = r.getBoundingClientRect();
return `polygon(
0% 0%,
0% 100%,
${u.left}px 100%,
${u.left}px ${u.top}px,
${u.right}px ${u.top}px,
${u.right}px ${u.bottom}px,
${u.left}px ${u.bottom}px,
${u.left}px 100%,
100% 100%,
100% 0%
)`;
}
A.value = "";
const ne = () => {
D() || s.value && z();
}, oe = (a) => {
if (!(!s.value || !t.enableA11y || !t.keyboardNav))
switch (a.key) {
case "Escape":
S(), a.preventDefault();
break;
case "ArrowRight":
case "Enter":
if (a.key === "Enter" && a.target?.tagName === "BUTTON")
return;
O(), a.preventDefault();
break;
case "ArrowLeft":
l.value > 0 && (P(), a.preventDefault());
break;
}
};
return Se(() => {
t.keyboardNav && window.addEventListener("keydown", oe), t.autoStart && I(), window.addEventListener("resize", ae), window.addEventListener("scroll", ne, !0);
}), we(() => {
t.keyboardNav && window.removeEventListener("keydown", oe), window.removeEventListener("resize", ae), window.removeEventListener("scroll", ne, !0), clearTimeout(V), clearTimeout(R), clearTimeout(F), s.value && b();
}), Te(
() => [t.name, t.steps, t.restartOnPropChange],
async ([a, r, u], [c, H]) => {
if (!u || !s.value) return;
const le = a !== c;
if (le || r !== H) {
if (le && c !== void 0) {
const re = c ? `vjt-highlight-${c}` : "vjt-highlight";
document.querySelectorAll(`.${re}`).forEach((ye) => ye.classList.remove(re));
}
b(), await N(), I();
}
}
), n({
startTour: I,
nextStep: O,
lastStep: P,
endTour: S,
stopTour: b,
goToStep: me,
resetTour: pe,
updatePosition: $,
updateHighlight: ee,
updateBackdrop: te
}), (a, r) => (w(), ke($e, { to: "body" }, [
T("div", {
class: Le(["vjt-modal-overlay", { "vjt-tour-active": s.value }]),
"data-hidden": !s.value
}, [
T("div", {
id: W.value,
"data-hidden": !M.value,
style: xe({ "clip-path": A.value })
}, null, 12, Ve),
T("div", {
id: E.value,
ref_key: "_Tooltip",
ref: m,
role: "dialog",
"aria-modal": e.enableA11y ? "true" : void 0,
"aria-label": g.value?.ariaLabel || e.ariaLabel,
"aria-describedby": `${E.value}-content`,
tabindex: e.enableA11y ? "0" : void 0,
"data-hidden": !s.value || f.value
}, [
s.value ? (w(), L("div", {
key: `step-${l.value}`
}, [
e.enableA11y ? (w(), L("div", Fe, " Step " + C(l.value + 1) + " of " + C(t.steps.length), 1)) : x("", !0),
e.hideArrow ? x("", !0) : (w(), L("div", {
key: 1,
id: fe.value
}, null, 8, He)),
se(a.$slots, "content", {
currentStepIndex: l.value,
currentStepData: g.value
}, () => [
T("div", {
id: `${E.value}-content`,
innerHTML: G.getCurrentStep?.content
}, null, 8, Ue)
]),
se(a.$slots, "actions", {
lastStep: P,
nextStep: O,
endTour: S,
getNextLabel: J.value,
props: t,
_CurrentStep: G
}, () => [
T("div", Ge, [
i.value < l.value ? (w(), L("button", {
key: 0,
type: "button",
onClick: U(P, ["prevent"]),
"aria-label": e.enableA11y ? `Go to previous step, step ${l.value} of ${t.steps.length}` : void 0
}, C(t.buttonLabels?.back || "Back"), 9, Ke)) : x("", !0),
t.hideSkip ? x("", !0) : (w(), L("button", {
key: 1,
type: "button",
onClick: U(S, ["prevent"]),
"aria-label": e.enableA11y ? "Skip tour and close" : void 0
}, C(t.buttonLabels?.skip || "Skip"), 9, Je)),
T("button", {
type: "button",
onClick: U(O, ["prevent"]),
"aria-label": e.enableA11y ? K.value ? "Finish tour" : `Go to next step, step ${p.value + 1} of ${t.steps.length}` : void 0
}, C(J.value), 9, We)
])
])
])) : x("", !0)
], 8, Re)
], 10, ze)
]));
}
});
export {
tt as VTour
};
//# sourceMappingURL=vuejs-tour.js.map