@elogroup-sereduc/portal-aluno-tour 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,6 @@
1
+ import { TourProps } from "../types";
2
+ /**
3
+ * Componente de tour guiado customizado usando HeroUI
4
+ */
5
+ export declare function Tour({ enabled, steps, initialStep, options, onExit, onComplete, }: TourProps): import("react/jsx-runtime").JSX.Element | null;
6
+ //# sourceMappingURL=Tour.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tour.d.ts","sourceRoot":"","sources":["../../src/components/Tour.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAY,MAAM,UAAU,CAAC;AAG/C;;GAEG;AACH,wBAAgB,IAAI,CAAC,EACnB,OAAO,EACP,KAAK,EACL,WAAe,EACf,OAAY,EACZ,MAAM,EACN,UAAU,GACX,EAAE,SAAS,kDA4UX"}
@@ -0,0 +1,178 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useEffect, useState, useCallback, useRef } from "react";
3
+ import { Button } from "@heroui/button";
4
+ import { HiXMark, HiChevronLeft, HiChevronRight } from "react-icons/hi2";
5
+ /**
6
+ * Componente de tour guiado customizado usando HeroUI
7
+ */
8
+ export function Tour({ enabled, steps, initialStep = 0, options = {}, onExit, onComplete, }) {
9
+ const [currentStep, setCurrentStep] = useState(initialStep);
10
+ const [highlightedElement, setHighlightedElement] = useState(null);
11
+ const [tooltipPosition, setTooltipPosition] = useState(null);
12
+ const overlayRef = useRef(null);
13
+ const tooltipRef = useRef(null);
14
+ const { nextLabel = "Próximo", prevLabel = "Anterior", skipLabel = "Pular", doneLabel = "Concluir", showProgress = true, showBullets = true, exitOnOverlayClick = false, exitOnEsc = true, } = options;
15
+ // Calcula a posição da tooltip baseado no elemento destacado
16
+ const calculateTooltipPosition = useCallback((element, position = "bottom") => {
17
+ const rect = element.getBoundingClientRect();
18
+ const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
19
+ const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
20
+ let top = 0;
21
+ let left = 0;
22
+ switch (position) {
23
+ case "top":
24
+ top = rect.top + scrollTop - 10;
25
+ left = rect.left + scrollLeft + rect.width / 2;
26
+ break;
27
+ case "bottom":
28
+ top = rect.bottom + scrollTop + 10;
29
+ left = rect.left + scrollLeft + rect.width / 2;
30
+ break;
31
+ case "left":
32
+ top = rect.top + scrollTop + rect.height / 2;
33
+ left = rect.left + scrollLeft - 10;
34
+ break;
35
+ case "right":
36
+ top = rect.top + scrollTop + rect.height / 2;
37
+ left = rect.right + scrollLeft + 10;
38
+ break;
39
+ default:
40
+ top = rect.bottom + scrollTop + 10;
41
+ left = rect.left + scrollLeft + rect.width / 2;
42
+ }
43
+ return { top, left };
44
+ }, []);
45
+ // Destaca o elemento atual
46
+ useEffect(() => {
47
+ if (!enabled || currentStep < 0 || currentStep >= steps.length) {
48
+ setHighlightedElement(null);
49
+ setTooltipPosition(null);
50
+ return;
51
+ }
52
+ const step = steps[currentStep];
53
+ const element = document.querySelector(step.element);
54
+ if (!element) {
55
+ console.warn(`Elemento não encontrado: ${step.element}`);
56
+ return;
57
+ }
58
+ setHighlightedElement(element);
59
+ // Scroll para o elemento
60
+ element.scrollIntoView({ behavior: "smooth", block: "center" });
61
+ // Calcula posição da tooltip após um pequeno delay para garantir que o scroll terminou
62
+ setTimeout(() => {
63
+ const position = calculateTooltipPosition(element, step.position);
64
+ setTooltipPosition(position);
65
+ }, 300);
66
+ }, [enabled, currentStep, steps, calculateTooltipPosition]);
67
+ // Adiciona overlay e highlight ao elemento
68
+ useEffect(() => {
69
+ if (!highlightedElement) {
70
+ // Remove highlights anteriores
71
+ document.querySelectorAll(".tour-highlight").forEach((el) => {
72
+ el.classList.remove("tour-highlight");
73
+ });
74
+ return;
75
+ }
76
+ // Adiciona classe de highlight
77
+ highlightedElement.classList.add("tour-highlight");
78
+ return () => {
79
+ highlightedElement.classList.remove("tour-highlight");
80
+ };
81
+ }, [highlightedElement]);
82
+ // Handler de teclado (ESC)
83
+ useEffect(() => {
84
+ if (!enabled || !exitOnEsc)
85
+ return;
86
+ const handleKeyDown = (e) => {
87
+ if (e.key === "Escape") {
88
+ handleExit();
89
+ }
90
+ else if (e.key === "ArrowRight") {
91
+ handleNext();
92
+ }
93
+ else if (e.key === "ArrowLeft") {
94
+ handlePrev();
95
+ }
96
+ };
97
+ window.addEventListener("keydown", handleKeyDown);
98
+ return () => window.removeEventListener("keydown", handleKeyDown);
99
+ }, [enabled, exitOnEsc, currentStep, steps.length]);
100
+ const handleNext = useCallback(() => {
101
+ if (currentStep < steps.length - 1) {
102
+ setCurrentStep(currentStep + 1);
103
+ }
104
+ else {
105
+ handleComplete();
106
+ }
107
+ }, [currentStep, steps.length]);
108
+ const handlePrev = useCallback(() => {
109
+ if (currentStep > 0) {
110
+ setCurrentStep(currentStep - 1);
111
+ }
112
+ }, [currentStep]);
113
+ const handleSkip = useCallback(() => {
114
+ handleExit();
115
+ }, []);
116
+ const handleComplete = useCallback(() => {
117
+ onComplete?.();
118
+ handleExit();
119
+ }, [onComplete]);
120
+ const handleExit = useCallback(() => {
121
+ setCurrentStep(initialStep);
122
+ setHighlightedElement(null);
123
+ setTooltipPosition(null);
124
+ onExit?.();
125
+ }, [initialStep, onExit]);
126
+ const handleOverlayClick = useCallback((e) => {
127
+ if (exitOnOverlayClick && e.target === overlayRef.current) {
128
+ handleExit();
129
+ }
130
+ }, [exitOnOverlayClick, handleExit]);
131
+ if (!enabled) {
132
+ return null;
133
+ }
134
+ const currentStepData = steps[currentStep];
135
+ const isFirstStep = currentStep === 0;
136
+ const isLastStep = currentStep === steps.length - 1;
137
+ const progress = ((currentStep + 1) / steps.length) * 100;
138
+ return (_jsxs(_Fragment, { children: [_jsx("div", { ref: overlayRef, className: "fixed inset-0 bg-black/60 z-[9998]", onClick: handleOverlayClick, style: { pointerEvents: exitOnOverlayClick ? "auto" : "none" } }), tooltipPosition && currentStepData && highlightedElement && (_jsxs("div", { ref: tooltipRef, className: "fixed z-[9999] max-w-sm", style: {
139
+ top: currentStepData.position === "bottom" ? `${tooltipPosition.top}px` : undefined,
140
+ bottom: currentStepData.position === "top" ? `${window.innerHeight - tooltipPosition.top}px` : undefined,
141
+ left: currentStepData.position === "left" || currentStepData.position === "right"
142
+ ? `${tooltipPosition.left}px`
143
+ : `${tooltipPosition.left}px`,
144
+ transform: currentStepData.position === "left" || currentStepData.position === "right"
145
+ ? "translate(0, -50%)"
146
+ : "translate(-50%, 0)",
147
+ }, children: [_jsxs("div", { className: "bg-white rounded-lg shadow-xl p-6 relative", children: [_jsx("button", { onClick: handleExit, className: "absolute top-2 right-2 p-1 rounded-full hover:bg-gray-100 transition-colors", "aria-label": "Fechar tour", children: _jsx(HiXMark, { className: "w-5 h-5 text-gray-500" }) }), currentStepData.title && (_jsx("h3", { className: "text-lg font-semibold text-gray-900 mb-2 pr-6", children: currentStepData.title })), _jsx("p", { className: "text-gray-700 mb-4", children: currentStepData.intro }), showProgress && (_jsxs("div", { className: "mb-4", children: [_jsx("div", { className: "w-full bg-gray-200 rounded-full h-2", children: _jsx("div", { className: "bg-brand-primary h-2 rounded-full transition-all duration-300", style: { width: `${progress}%` } }) }), _jsxs("p", { className: "text-xs text-gray-500 mt-1 text-center", children: [currentStep + 1, " de ", steps.length] })] })), showBullets && (_jsx("div", { className: "flex justify-center gap-1 mb-4", children: steps.map((_, index) => (_jsx("button", { onClick: () => setCurrentStep(index), className: `w-2 h-2 rounded-full transition-all ${index === currentStep
148
+ ? "bg-brand-primary w-6"
149
+ : "bg-gray-300 hover:bg-gray-400"}`, "aria-label": `Ir para passo ${index + 1}` }, index))) })), _jsxs("div", { className: "flex justify-between items-center gap-2", children: [_jsx("div", { className: "flex gap-2", children: !isFirstStep && (_jsx(Button, { variant: "bordered", onPress: handlePrev, startContent: _jsx(HiChevronLeft, { className: "w-4 h-4" }), children: prevLabel })) }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { variant: "light", onPress: handleSkip, children: skipLabel }), _jsx(Button, { color: "primary", onPress: isLastStep ? handleComplete : handleNext, endContent: !isLastStep ? _jsx(HiChevronRight, { className: "w-4 h-4" }) : undefined, children: isLastStep ? doneLabel : nextLabel })] })] })] }), currentStepData.position === "bottom" && (_jsx("div", { className: "absolute w-0 h-0 border-8 border-transparent", style: {
150
+ top: "-16px",
151
+ left: "50%",
152
+ transform: "translateX(-50%)",
153
+ borderColor: "transparent transparent white transparent",
154
+ } })), currentStepData.position === "top" && (_jsx("div", { className: "absolute w-0 h-0 border-8 border-transparent", style: {
155
+ bottom: "-16px",
156
+ left: "50%",
157
+ transform: "translateX(-50%)",
158
+ borderColor: "white transparent transparent transparent",
159
+ } })), currentStepData.position === "right" && (_jsx("div", { className: "absolute w-0 h-0 border-8 border-transparent", style: {
160
+ left: "-16px",
161
+ top: "50%",
162
+ transform: "translateY(-50%)",
163
+ borderColor: "transparent white transparent transparent",
164
+ } })), currentStepData.position === "left" && (_jsx("div", { className: "absolute w-0 h-0 border-8 border-transparent", style: {
165
+ right: "-16px",
166
+ top: "50%",
167
+ transform: "translateY(-50%)",
168
+ borderColor: "transparent transparent transparent white",
169
+ } }))] })), _jsx("style", { children: `
170
+ .tour-highlight {
171
+ position: relative;
172
+ z-index: 9999 !important;
173
+ outline: 3px solid var(--brand-primary, #0056b0) !important;
174
+ outline-offset: 2px;
175
+ border-radius: 4px;
176
+ }
177
+ ` })] }));
178
+ }
@@ -0,0 +1,3 @@
1
+ export { Tour } from "./components/Tour";
2
+ export type { TourProps, TourStep, TourOptions } from "./types";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export { Tour } from "./components/Tour";
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Tipos para o componente de tour
3
+ */
4
+ export interface TourStep {
5
+ /**
6
+ * Seletor CSS do elemento a ser destacado
7
+ */
8
+ element: string;
9
+ /**
10
+ * Texto explicativo do passo
11
+ */
12
+ intro: string;
13
+ /**
14
+ * Posição da tooltip em relação ao elemento
15
+ * @default "bottom"
16
+ */
17
+ position?: "top" | "bottom" | "left" | "right";
18
+ /**
19
+ * Título do passo (opcional)
20
+ */
21
+ title?: string;
22
+ }
23
+ export interface TourOptions {
24
+ /**
25
+ * Label do botão "Próximo"
26
+ * @default "Próximo"
27
+ */
28
+ nextLabel?: string;
29
+ /**
30
+ * Label do botão "Anterior"
31
+ * @default "Anterior"
32
+ */
33
+ prevLabel?: string;
34
+ /**
35
+ * Label do botão "Pular"
36
+ * @default "Pular"
37
+ */
38
+ skipLabel?: string;
39
+ /**
40
+ * Label do botão "Concluir"
41
+ * @default "Concluir"
42
+ */
43
+ doneLabel?: string;
44
+ /**
45
+ * Mostrar barra de progresso
46
+ * @default true
47
+ */
48
+ showProgress?: boolean;
49
+ /**
50
+ * Mostrar bullets de navegação
51
+ * @default true
52
+ */
53
+ showBullets?: boolean;
54
+ /**
55
+ * Permitir fechar clicando no overlay
56
+ * @default false
57
+ */
58
+ exitOnOverlayClick?: boolean;
59
+ /**
60
+ * Permitir fechar com ESC
61
+ * @default true
62
+ */
63
+ exitOnEsc?: boolean;
64
+ }
65
+ export interface TourProps {
66
+ /**
67
+ * Se o tour está habilitado/ativo
68
+ */
69
+ enabled: boolean;
70
+ /**
71
+ * Array de passos do tour
72
+ */
73
+ steps: TourStep[];
74
+ /**
75
+ * Passo inicial (índice)
76
+ * @default 0
77
+ */
78
+ initialStep?: number;
79
+ /**
80
+ * Opções de configuração do tour
81
+ */
82
+ options?: TourOptions;
83
+ /**
84
+ * Callback quando o tour é encerrado
85
+ */
86
+ onExit?: () => void;
87
+ /**
88
+ * Callback quando o tour é concluído
89
+ */
90
+ onComplete?: () => void;
91
+ }
92
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;IAE/C;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,KAAK,EAAE,QAAQ,EAAE,CAAC;IAElB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,OAAO,CAAC,EAAE,WAAW,CAAC;IAEtB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IAEpB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB"}
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Tipos para o componente de tour
3
+ */
4
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elogroup-sereduc/portal-aluno-tour",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Componente de tour guiado customizado usando HeroUI para o Portal do Aluno",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,7 +1,7 @@
1
1
  import { useEffect, useState, useCallback, useRef } from "react";
2
2
  import { Button } from "@heroui/button";
3
3
  import { TourProps, TourStep } from "../types";
4
- import { HiX, HiChevronLeft, HiChevronRight } from "react-icons/hi2";
4
+ import { HiXMark, HiChevronLeft, HiChevronRight } from "react-icons/hi2";
5
5
 
6
6
  /**
7
7
  * Componente de tour guiado customizado usando HeroUI
@@ -210,7 +210,7 @@ export function Tour({
210
210
  className="absolute top-2 right-2 p-1 rounded-full hover:bg-gray-100 transition-colors"
211
211
  aria-label="Fechar tour"
212
212
  >
213
- <HiX className="w-5 h-5 text-gray-500" />
213
+ <HiXMark className="w-5 h-5 text-gray-500" />
214
214
  </button>
215
215
 
216
216
  {/* Título (se fornecido) */}