UNPKG

@gajendra-naphade/react-web-guide

Version:

React Web Guide: A customizable, interactive tour component for React apps.

466 lines (465 loc) 18.8 kB
import { jsx as e, jsxs as l, Fragment as dt } from "react/jsx-runtime"; import { useState as f, useEffect as K, useRef as xt } from "react"; const kt = ({ x: t, CursorMessageGap: n, y: r, isOffScreen: d, Theme: w, name: k = "Guide", color: b = "#ff6b6b", message: m, isVisible: y = !0, onClick: R, showNext: W = !1, cursorImage: $ = null, messageBoxStyle: D = {}, cursorStyle: L = {}, nextButtonText: C, nextButtonContinueText: S, nextButtonClassName: P, nextButtonStyle: j = {}, messageClass: O, CustomCursorClass: A = "" }) => { const [c, V] = f({ left: !1, top: !1 }), [p, z] = f(!1); if (K(() => { const X = window.innerWidth - t - 24, s = t - 24, H = window.innerHeight - r - 24, a = r - 24, N = X < 192 && s > 192, Y = H < 100 && a > 100; V({ left: N, top: Y }); }, [t, r]), !y) return null; const I = [ `${O} ${w == "Light" ? "bg-[#ffffff2d] text-gray-900" : "bg-[#0a0b1b] text-white"} z-[999999999999999999999999999999] absolute px-2 md:!px-3 py-2 rounded-lg text-[10px] md:!text-xs font-medium 2xl:!text-sm backdrop-blur-md shadow-lg border-[0.2px] w-24 md:!w-48`, c.left ? "right-14" : "left-8", c.top && !c.left ? "bottom-2 left-6" : "top-6", "transition-all duration-500 ease-in-out" ].join(" "), G = (v) => { v.stopPropagation(), z(!0); }, T = (v) => { v.stopPropagation(), z(!1); }; return /* @__PURE__ */ e( "div", { className: "fixed react-web-guide pointer-events-none z-[999999999999999999999999999999]", style: { left: p ? `${window.innerWidth - 60}px` : `${t}px`, top: p ? "50%" : `${r}px`, transition: "all 0.5s ease-out", ...L }, children: /* @__PURE__ */ l("div", { className: "relative z-[999999999999999999999999999999999]", children: [ $ ? /* @__PURE__ */ e( "img", { src: $, alt: "Custom cursor", className: ` ${A} w-6 h-6 drop-shadow-lg ${c.top ? "-translate-y-5" : ""} z-[99999999999999999]`, style: { filter: "drop-shadow(0 2px 4px rgba(0,0,0,0.2))" } } ) : /* @__PURE__ */ e( "svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", className: `drop-shadow-lg ${c.top ? "-translate-y-5" : ""} z-[99999999999999999]`, style: { filter: "drop-shadow(0 2px 4px rgba(0,0,0,0.2))" }, children: /* @__PURE__ */ e( "path", { d: "M5.65376 12.3673H5.46026L5.31717 12.4976L0.500002 16.8829L0.500002 1.19841L11.7841 12.3673H5.65376Z", fill: b, stroke: "white", strokeWidth: "2" } ) } ), /* @__PURE__ */ e( "div", { className: `absolute ${c.top ? "bottom-1 -left-4" : "top-6 -left-4"} px-2 py-[1px] rounded-full text-[10px] max-w-[65px] truncate text-white font-medium whitespace-nowrap shadow-md`, style: { backgroundColor: b }, children: k } ), m && /* @__PURE__ */ l(dt, { children: [ /* @__PURE__ */ l( "div", { className: I, style: { ...D, opacity: p ? 0 : 1, transform: p ? "translateX(100px)" : "translateX(0)", marginLeft: c.left ? "0" : `${n}px` }, children: [ /* @__PURE__ */ e( "button", { onClick: G, title: "Pause the tour", className: ` ${w === "Light" ? "bg-[#ffffff6c]" : "bg-[#6b6b6b6c] "} pointer-events-auto absolute -top-6 -right-6 border backdrop-blur-md rounded-full p-[6px] shadow-md hover:shadow-lg transition-all duration-200 hover:scale-110`, children: /* @__PURE__ */ l("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "red", stroke: "white", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", class: "lucide lucide-heart-crack", "aria-hidden": "true", children: [ /* @__PURE__ */ e("path", { d: "M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z" }), /* @__PURE__ */ e("path", { d: "m12 13-1-1 2-2-3-3 2-2" }) ] }) } ), /* @__PURE__ */ e("div", { className: "mb-2", children: m }), W && !p && /* @__PURE__ */ e( "button", { title: d ? S : C, onClick: R, className: `${P} ${w === "Light" ? "text-white bg-black/90" : "bg-white/90 text-black"} !pointer-events-auto !z-[99999999999999999999] backdrop-blur-sm rounded-md border px-3 py-[1px] rounded-full text-[10px] flex items-center justify-center font-medium hover:shadow-lg transition-all duration-200 transform hover:scale-105 active:scale-95`, style: j, children: d ? S : C } ) ] } ), p && /* @__PURE__ */ e( "div", { className: "absolute", style: { left: c.left ? "auto" : "calc(100% - 0.4rem)", right: c.left ? "calc(100% - 3rem)" : "auto", top: "50%", transform: "translateY(-50%)" }, children: /* @__PURE__ */ e( "button", { onClick: T, title: "Continue the tour", className: ` ${w === "Light" ? "bg-[#ffffff6c]" : "bg-[#6b6b6b6c] "} pointer-events-auto backdrop-blur-md border rounded-full p-[6px] shadow-md hover:shadow-lg transition-all duration-200 hover:scale-110`, children: /* @__PURE__ */ e("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "red", stroke: "white", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", class: "lucide lucide-heart", "aria-hidden": "true", children: /* @__PURE__ */ e("path", { d: "M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z" }) }) } ) } ) ] }) ] }) } ); }, lt = ({ isVisible: t, onClose: n, theme: r }) => t ? /* @__PURE__ */ e( "div", { className: "react-web-guide absolute w-36 bottom-full mb-2 left-1/2 transform -translate-x-1/2 animate-bounce-subtle z-[99999999999999999]", children: /* @__PURE__ */ l( "div", { className: `relative ${r === "Dark" ? "bg-black/90 text-white" : "bg-white/90 text-black"} px-3 py-2 rounded-lg shadow-lg backdrop-blur-sm tooltip-enter tooltip-enter-active`, children: [ /* @__PURE__ */ e( "button", { onClick: n, className: `absolute -top-2 -right-2 ${r === "Dark" ? "bg-black/90 text-white" : "bg-white/90 text-black"} backdrop-blur-sm rounded-full p-1 shadow-md hover:shadow-lg transition-all duration-200 hover:scale-110`, children: /* @__PURE__ */ l("svg", { xmlns: "http://www.w3.org/2000/svg", width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [ /* @__PURE__ */ e("path", { d: "M18 6 6 18" }), /* @__PURE__ */ e("path", { d: "m6 6 12 12" }) ] }) } ), /* @__PURE__ */ e("div", { className: "text-sm font-medium text-center flex items-center gap-2", children: /* @__PURE__ */ e("span", { children: "Start your web tour here!" }) }), /* @__PURE__ */ e("div", { className: `absolute bottom-0 right-2 transform translate-y-1/2 rotate-45 w-2 h-2 ${r === "Dark" ? "bg-black/90" : "bg-white/90"}` }) ] } ) } ) : null, ct = (t) => { if (!t || t === document.body) return window; const { overflow: n, overflowY: r, overflowX: d, height: w } = window.getComputedStyle(t), k = t.scrollHeight > t.clientHeight || t.scrollWidth > t.clientWidth, b = ["auto", "scroll"].some( (y) => [n, r, d].includes(y) ), m = t.classList.contains("h-screen") || w === "100vh" || w === "100%" || t.style.height === "100vh" || t.style.height === "100%"; return (b || m) && k ? t : ct(t.parentElement); }, at = (t, n = window) => { if (!t) return !1; const r = t.getBoundingClientRect(); if (n === window) return r.top >= -100 && r.bottom <= window.innerHeight + 100 && r.left >= -100 && r.right <= window.innerWidth + 100; { const d = n.getBoundingClientRect(); return r.top >= d.top - 100 && r.bottom <= d.bottom + 100 && r.left >= d.left - 100 && r.right <= d.right + 100; } }, $t = ({ steps: t = [], Theme: n = "Light", onComplete: r, startButtonText: d = "Start Tour", skipButtonText: w = "Skip Tour", minimizedStartText: k = "Start", minimizedSkipText: b = "Skip", showProgress: m = !0, Minimized: y = !0, showTooltip: R = !0, buttonPosition: W = { bottom: "1.5rem", right: "1.5rem", left: "auto", top: "auto" }, expandedButtonClassName: $ = ` ${n === "Dark" ? "text-white bg-black/90" : "bg-white/90 text-black"} border px-4 py-2 rounded-full shadow-lg hover:shadow-xl transition-all duration-300 hover:scale-105`, minimizedButtonClassName: D = ` ${n === "Dark" ? "text-white bg-black/90" : "bg-white/90 text-black"} border px-2 py-2 rounded-full shadow-lg hover:shadow-xl transition-all duration-300 hover:scale-105`, buttonStyle: L = {}, CloseButtonText: C = /* @__PURE__ */ l("svg", { xmlns: "http://www.w3.org/2000/svg", width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "lucide lucide-x", "aria-hidden": "true", children: [ /* @__PURE__ */ e("path", { d: "M18 6 6 18" }), /* @__PURE__ */ e("path", { d: "m6 6 12 12" }) ] }), ExpandButtonText: S = /* @__PURE__ */ l("svg", { xmlns: "http://www.w3.org/2000/svg", width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "lucide lucide-maximize2 lucide-maximize-2", "aria-hidden": "true", children: [ /* @__PURE__ */ e("path", { d: "M15 3h6v6" }), /* @__PURE__ */ e("path", { d: "m21 3-7 7" }), /* @__PURE__ */ e("path", { d: "m3 21 7-7" }), /* @__PURE__ */ e("path", { d: "M9 21H3v-6" }) ] }), minimizedButtonStyle: P = { width: "3rem", height: "3rem", fontSize: "0.875rem" }, closeButtonClassName: j = `${n === "Dark" ? "text-white bg-black/90" : "bg-white/90 text-black"} -translate-y-4 -translate-x-1 rounded-full p-1 shadow-md hover:shadow-lg transition-all duration-200 hover:scale-110`, expandButtonClassName: O = `${n === "Dark" ? "text-white bg-black/90" : "bg-white/90 text-black"} -translate-y-4 -translate-x-1 rounded-full p-1 shadow-md hover:shadow-lg transition-all duration-200 hover:scale-110`, closeButtonStyle: A = {}, expandButtonStyle: c = {}, cursorImage: V = null, messageBoxStyle: p = {}, cursorStyle: z = {}, nextButtonText: I = "Next", nextButtonContinueText: G = "Continue", nextButtonClassName: T, nextButtonStyle: v = {}, messageClass: J, // New prop to specify scrollable container selector or element scrollContainer: x = null, CustomCursorClass: X }) => { var rt, it, st, nt; const [s, H] = f(0), [a, N] = f(!1), [Y, Q] = f(y), [U, ht] = f({ x: 0, y: 0 }), [E, _] = f(!1), [ut, Z] = f(!0), [tt, q] = f(R), [ft, wt] = f(null), B = xt(null); K(() => { var i; if (!a || !((i = t[s]) != null && i.ref.current)) return; let o; if (x) typeof x == "string" ? o = document.querySelector(x) : o = x; else if (o = ct(t[s].ref.current), o === window) { const h = [ ".scrollDiv", // Your specific class '[class*="h-screen"]', '[class*="overflow"]', ".scroll-smooth", "main", "#app", "#root" ]; for (const g of h) { const u = document.querySelector(g); if (u && u.scrollHeight > u.clientHeight) { o = u; break; } } } wt(o), B.current = o; }, [a, s, x]); const M = () => { if (!a || s >= t.length) return; const o = t[s]; if (o.ref.current) { const i = o.ref.current.getBoundingClientRect(), h = i.left + (o.offsetX || i.width / 2), g = i.top + (o.offsetY || i.height / 2); ht({ x: h, y: g }); const u = B.current || window, vt = at(o.ref.current, u); _(!vt); } }, gt = (o, i) => { if (o) if (i === window) o.scrollIntoView({ behavior: "smooth", block: "center", inline: "nearest" }); else if (i && i.scrollTo) { const h = i.getBoundingClientRect(), g = o.getBoundingClientRect(), u = i.scrollTop + g.top - h.top - i.clientHeight / 2 + g.height / 2; i.scrollTo({ top: u, behavior: "smooth" }); } else o.scrollIntoView({ behavior: "smooth", block: "center", inline: "nearest" }); }, et = () => { var o; if (s < t.length - 1) { const i = (o = t[s + 1]) == null ? void 0 : o.ref.current, h = B.current || window; i && !at(i, h) ? (Z(!1), gt(i, h), setTimeout(() => { _(!1), Z(!0), F(); }, 800)) : F(); } else F(); }; K(() => { if (!a) return; M(); const o = B.current, i = () => M(), h = () => M(), g = (u) => { u.key === "ArrowRight" && et(); }; return window.addEventListener("scroll", i, { passive: !0 }), window.addEventListener("resize", h), window.addEventListener("keydown", g), o && o !== window && o.addEventListener("scroll", i, { passive: !0 }), () => { window.removeEventListener("scroll", i), window.removeEventListener("resize", h), window.removeEventListener("keydown", g), o && o !== window && o.removeEventListener("scroll", i); }; }, [a, s, ft]); const F = () => { s < t.length - 1 ? H(s + 1) : (N(!1), r == null || r()); }, pt = () => { N(!0), H(0), Z(!0), setTimeout(M, 500); }, ot = () => { a ? (N(!1), r == null || r()) : (pt(), q(!1)); }, bt = (o) => { o.stopPropagation(), Q(!0); }, mt = (o) => { o.stopPropagation(), Q(!1); }; return /* @__PURE__ */ l("div", { className: "react-web-guide", children: [ /* @__PURE__ */ e( "div", { className: "fixed z-[999999999999999999999999999999999]", style: W, children: Y ? /* @__PURE__ */ l("div", { className: "relative", children: [ /* @__PURE__ */ e( lt, { isVisible: tt && !a, onClose: () => q(!1), theme: n } ), /* @__PURE__ */ e( "button", { onClick: ot, className: `${D} transition-all duration-500`, style: { ...P, ...L }, children: a ? b : k } ), /* @__PURE__ */ e( "button", { onClick: mt, className: `${O} transition-all p-1 duration-500`, style: c, children: S } ) ] }) : /* @__PURE__ */ l("div", { className: "relative z-[99999999999999999]", children: [ /* @__PURE__ */ e( lt, { isVisible: tt && !a, onClose: () => q(!1), theme: n } ), /* @__PURE__ */ e( "button", { onClick: ot, className: `${$} transition-all duration-500`, style: L, children: a ? w : d } ), /* @__PURE__ */ e( "button", { onClick: bt, className: `${j} transition-all p-1 duration-500`, style: A, children: C } ) ] }) } ), a && /* @__PURE__ */ l(dt, { children: [ /* @__PURE__ */ e( kt, { x: E ? window.innerWidth / 2 : U.x, y: E ? window.innerHeight / 2 : U.y, Theme: n, name: ((rt = t[s]) == null ? void 0 : rt.name) || "Guide", color: ((it = t[s]) == null ? void 0 : it.color) || "#ff6b6b", message: E ? "Hey the tour is incomplete!" : (st = t[s]) == null ? void 0 : st.message, isVisible: ut, onClick: et, showNext: !0, isOffScreen: E, cursorImage: V, messageBoxStyle: p, cursorStyle: z, nextButtonText: I, nextButtonContinueText: G, nextButtonClassName: T, nextButtonStyle: v, messageClass: J, CursorMessageGap: ((nt = t[s]) == null ? void 0 : nt.CursorMessageGap) || 0, CustomCursorClass: X } ), m && /* @__PURE__ */ l("div", { className: `fixed top-4 right-4 z-[999999999] ${n == "Dark" ? "bg-[#202020]" : "bg-white/90"} backdrop-blur-sm border rounded-full px-4 py-2 shadow-lg`, children: [ /* @__PURE__ */ l("div", { className: `text-sm font-medium ${n == "Dark" ? "text-white" : "text-gray-700"} `, children: [ /* @__PURE__ */ l("span", { className: "hidden sm:!block text-center", children: [ "Step ", s + 1, " of ", t.length ] }), /* @__PURE__ */ l("span", { className: "sm:hidden", children: [ s + 1, "/", t.length ] }) ] }), /* @__PURE__ */ e("div", { className: "w-full h-1 bg-gray-200 rounded-full mt-1", children: /* @__PURE__ */ e( "div", { className: "h-full bg-gradient-to-r from-purple-500 to-blue-500 rounded-full transition-all duration-500", style: { width: `${(s + 1) / t.length * 100}%` } } ) }) ] }) ] }) ] }); }; export { kt as TourCursor, $t as default }; //# sourceMappingURL=index.js.map