@gajendra-naphade/react-web-guide
Version:
React Web Guide: A customizable, interactive tour component for React apps.
466 lines (465 loc) • 18.8 kB
JavaScript
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