UNPKG

react-custom-tours

Version:

A library with tips that you can attach to blocks on your sites so that users can more easily understand how to use your site

214 lines (213 loc) 10.1 kB
import { jsxs as g, jsx as s, Fragment as T } from "react/jsx-runtime"; import { useContext as A, useRef as H, useMemo as P, useState as L, useLayoutEffect as S, useEffect as b, createContext as $ } from "react"; import O from "./shared/ui/spinner/index.js"; import { useEscapeListener as D } from "./shared/hooks/useEscapeListener.js"; import { usePropsColors as j } from "./shared/hooks/usePropsColors.js"; import { hasNativeAnchor as z, anchorFallbackStyle as F } from "./shared/utils/anchor.js"; import { createPortal as V } from "react-dom"; import './assets/tips.css';const R = () => A(B), Y = "_wrapper_1ln8w_3", Z = "_dark_1ln8w_17", q = "_block_1ln8w_22", M = { wrapper: Y, dark: Z, block: q }, G = "_wrapper_1daah_1", J = "_header_1daah_42", K = "_leftHeader_1daah_47", Q = "_count_1daah_52", U = "_close_1daah_59", X = "_textWrapper_1daah_75", tt = "_footer_1daah_90", C = { wrapper: G, header: J, leftHeader: K, count: Q, close: U, textWrapper: X, footer: tt }, et = (o) => { const { item: n, itemRect: r, prevItem: c, nextItem: a, countItems: u, itemIdx: t, isLoading: d, onPrev: m, onNext: y, onClose: l } = o, { isHiddenClose: f } = R(), v = `${t + 1} / ${u}`, h = H(null), k = P(() => f ? u - 1 === t : !0, [t, u, f]), x = 10, _ = h.current?.offsetHeight ?? 220, I = h.current?.offsetWidth ?? 320, N = window.innerHeight - r.bottom - x, W = r.top - x, e = N >= _ ? "bottom" : W >= _ ? "top" : "overlap", i = r.left, p = i + (e === "overlap" ? x : 0), w = Math.max(8, Math.min(p, window.innerWidth - 8 - I)), E = { left: Math.round(w - i) }; return n?.maxWidth && (E.maxWidth = Math.min(n.maxWidth, window.innerWidth - 16)), /* @__PURE__ */ g("div", { ref: h, style: E, className: C.wrapper, "data-testid": "tips-tooltip", "data-v": e, children: [ /* @__PURE__ */ g("header", { className: C.header, children: [ /* @__PURE__ */ g("div", { className: C.leftHeader, children: [ /* @__PURE__ */ s("span", { className: C.count, "data-testid": "tooltip-count", title: `Номер подсказки - (${v})`, children: v }), d && /* @__PURE__ */ s(O, {}) ] }), k && /* @__PURE__ */ s( "button", { className: C.close, onClick: l, type: "button", "data-testid": "tooltip-close", title: "Закрыть подсказки", children: /* @__PURE__ */ s("svg", { width: "8", height: "8", viewBox: "0 0 8 8", children: /* @__PURE__ */ s("path", { d: "M7.8228 0.183264C7.76667 0.127012 7.69999 0.0823841 7.62658 0.0519343C7.55318 0.0214845 7.47448 0.00581086 7.39501 0.00581086C7.31554 0.00581086 7.23685 0.0214845 7.16345 0.0519343C7.09004 0.0823841 7.02336 0.127012 6.96722 0.183264L4 3.14442L1.03278 0.177196C0.976598 0.121018 0.909905 0.0764551 0.836505 0.0460517C0.763104 0.0156483 0.684434 5.91933e-10 0.604986 0C0.525539 -5.91934e-10 0.446868 0.0156483 0.373468 0.0460517C0.300068 0.0764551 0.233374 0.121018 0.177196 0.177196C0.121018 0.233374 0.0764551 0.300068 0.0460517 0.373468C0.0156483 0.446868 -5.91933e-10 0.525539 0 0.604986C5.91934e-10 0.684434 0.0156483 0.763104 0.0460517 0.836505C0.0764551 0.909905 0.121018 0.976598 0.177196 1.03278L3.14442 4L0.177196 6.96722C0.121018 7.0234 0.0764551 7.0901 0.0460517 7.1635C0.0156483 7.2369 0 7.31557 0 7.39501C0 7.47446 0.0156483 7.55313 0.0460517 7.62653C0.0764551 7.69993 0.121018 7.76663 0.177196 7.8228C0.233374 7.87898 0.300068 7.92355 0.373468 7.95395C0.446868 7.98435 0.525539 8 0.604986 8C0.684434 8 0.763104 7.98435 0.836505 7.95395C0.909905 7.92355 0.976598 7.87898 1.03278 7.8228L4 4.85558L6.96722 7.8228C7.0234 7.87898 7.0901 7.92355 7.1635 7.95395C7.2369 7.98435 7.31557 8 7.39501 8C7.47446 8 7.55313 7.98435 7.62653 7.95395C7.69993 7.92355 7.76663 7.87898 7.8228 7.8228C7.87898 7.76663 7.92355 7.69993 7.95395 7.62653C7.98435 7.55313 8 7.47446 8 7.39501C8 7.31557 7.98435 7.2369 7.95395 7.1635C7.92355 7.0901 7.87898 7.0234 7.8228 6.96722L4.85558 4L7.8228 1.03278C8.05339 0.802195 8.05339 0.413846 7.8228 0.183264Z" }) }) } ) ] }), /* @__PURE__ */ g("div", { className: C.textWrapper, children: [ n?.title && /* @__PURE__ */ s("h4", { "data-testid": "tooltip-title", title: n.title, children: n.title }), /* @__PURE__ */ s("p", { "data-testid": "tooltip-text", title: n.text, children: n.text }) ] }), /* @__PURE__ */ g("footer", { className: C.footer, children: [ c && /* @__PURE__ */ s( "button", { disabled: !c || d, onClick: m, type: "button", "data-testid": "tooltip-prev", title: "Предыдущая подсказка", children: "Назад" } ), /* @__PURE__ */ g( "button", { disabled: d, title: a ? "Следующая подсказка" : "Закрыть", onClick: a ? y : l, type: "button", "data-testid": "tooltip-next", children: [ a ? "Далее" : "Все понятно", a && /* @__PURE__ */ s("svg", { width: "10", height: "8", viewBox: "0 0 10 8", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ s( "path", { d: "M1.0271 3.63123H8.5271M8.5271 3.63123L5.5271 0.631226M8.5271 3.63123L5.5271 6.63123", stroke: "white", strokeWidth: "1.25", strokeLinecap: "round", strokeLinejoin: "round" } ) }) ] } ) ] }) ] }); }, ot = "--rct-anchor", nt = ({ data: o }) => { const { setIsShow: n, theme: r, escapeToClose: c, highlightPadding: a, customColors: u } = R(), [t, d] = L(o[0]), m = H(null), [y, l] = L(!1), [f, v] = L(() => new DOMRect()), [h] = L(z), k = o[o.indexOf(t) + 1], x = o[o.indexOf(t) - 1], _ = async (e) => { e && (l(!0), await e(), l(!1)); }, I = async () => { await _(t?.onClick?.nextButton), d(k); }, N = async () => { await _(t?.onClick?.prevButton), d(x); }, W = async () => { await _(t?.onClick?.closeButton), n(!1); }; return D(!!c, () => n(!1)), j(m, u, r), S(() => { const e = t?.node; if (!(!e || !h)) return e.style.setProperty("anchor-name", ot), () => { e.style.removeProperty("anchor-name"); }; }, [t, h]), b(() => { const e = t?.node; if (!e) return; const i = e.getBoundingClientRect().height; e.scrollIntoView({ behavior: "smooth", block: i > window.innerHeight - 200 ? "start" : "center", inline: "nearest" }); }, [t]), b(() => { const e = t?.node; if (!e) return; const i = () => { const p = e.getBoundingClientRect(); v( (w) => w.top === p.top && w.left === p.left && w.width === p.width && w.height === p.height ? w : p ); }; return i(), window.addEventListener("scroll", i, !0), window.addEventListener("resize", i), () => { window.removeEventListener("scroll", i, !0), window.removeEventListener("resize", i); }; }, [t]), b(() => { d(o[0]); }, [o]), b(() => { const e = m?.current; if (!e) return; const i = (p) => { p.stopPropagation(); }; return e.addEventListener("mousedown", i), () => { e.removeEventListener("mousedown", i); }; }, []), V( /* @__PURE__ */ s( "div", { className: `${M.wrapper} ${r === "dark" ? M.dark : ""}`, ref: m, "data-testid": "tips-active-layout", children: /* @__PURE__ */ s( "div", { className: M.block, "data-testid": "tips-highlight", style: { // Размер/позицию короба вычисляет CSS через anchor() и anchor-size(). // Сюда отдаём только динамический паддинг подсветки и радиус. "--rct-highlight-padding": `${a || 0}px`, borderRadius: t?.node?.style.borderRadius || void 0, // Фолбэк для движков без anchor(): позиционируем короб на JS из // уже трекаемого activeItemRect, перебивая невалидный CSS anchor(). ...h ? void 0 : F(f, a || 0) }, children: /* @__PURE__ */ s( et, { isLoading: y, itemRect: f, countItems: o.length, itemIdx: o.indexOf(t), item: t, nextItem: k, prevItem: x, onNext: I, onPrev: N, onClose: W } ) } ) } ), document.body ); }, st = "You are trying to show a tour, but the DOM nodes for this tour are not found in the DOM Tree, please check it!", rt = ({ children: o }) => { const { data: n, isShow: r } = R(); return /* @__PURE__ */ g(T, { children: [ /* @__PURE__ */ s(it, { data: n, isShow: r }), o ] }); }, it = ({ isShow: o, data: n }) => { if (!o || !n) return null; const r = n.filter((c) => c?.node).sort((c, a) => c.idx - a.idx); return r.length === 0 ? (console.warn(st), null) : /* @__PURE__ */ s(nt, { data: r }); }, B = $({}), mt = (o) => { const { children: n, tips: r, theme: c, customColors: a, escapeToClose: u, isHiddenClose: t, highlightPadding: d } = o, [m, y] = L(null), [l, f] = L(!1); b(() => { l && y( r.map((h) => ({ ...h, node: document.getElementById(h.nodeId) })) ); }, [r, l]); const v = P( () => ({ data: m, isShow: l, theme: c, escapeToClose: u, customColors: a, isHiddenClose: t, highlightPadding: d, setIsShow: f }), [m, l, c, u, f, a, t, d] ); return /* @__PURE__ */ s(B.Provider, { value: v, children: /* @__PURE__ */ s(rt, { children: n }) }); }; export { mt as T, et as a, nt as b, rt as c, B as d, R as u };