UNPKG

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