@elogroup-sereduc/portal-aluno-tour 1.0.2 → 1.0.3
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.
- package/dist/components/Tour.d.ts.map +1 -1
- package/dist/components/Tour.js +70 -11
- package/package.json +1 -1
- package/src/components/Tour.tsx +62 -28
|
@@ -1 +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,
|
|
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,kDA0YX"}
|
package/dist/components/Tour.js
CHANGED
|
@@ -7,10 +7,12 @@ import { HiXMark, HiChevronLeft, HiChevronRight } from "react-icons/hi2";
|
|
|
7
7
|
*/
|
|
8
8
|
export function Tour({ enabled, steps, initialStep = 0, options = {}, onExit, onComplete, }) {
|
|
9
9
|
const [currentStep, setCurrentStep] = useState(initialStep);
|
|
10
|
+
const [isVisible, setIsVisible] = useState(false);
|
|
10
11
|
const [highlightedElement, setHighlightedElement] = useState(null);
|
|
11
12
|
const [tooltipPosition, setTooltipPosition] = useState(null);
|
|
12
13
|
const overlayRef = useRef(null);
|
|
13
14
|
const tooltipRef = useRef(null);
|
|
15
|
+
const isConfiguredRef = useRef(false);
|
|
14
16
|
const { nextLabel = "Próximo", prevLabel = "Anterior", skipLabel = "Pular", doneLabel = "Concluir", showProgress = true, showBullets = true, exitOnOverlayClick = false, exitOnEsc = true, } = options;
|
|
15
17
|
// Calcula a posição da tooltip baseado no elemento destacado
|
|
16
18
|
const calculateTooltipPosition = useCallback((element, position = "bottom") => {
|
|
@@ -42,9 +44,26 @@ export function Tour({ enabled, steps, initialStep = 0, options = {}, onExit, on
|
|
|
42
44
|
}
|
|
43
45
|
return { top, left };
|
|
44
46
|
}, []);
|
|
47
|
+
// Configura o tour quando steps ou options mudam
|
|
48
|
+
const configureTour = useCallback(() => {
|
|
49
|
+
isConfiguredRef.current = true;
|
|
50
|
+
}, []);
|
|
51
|
+
// Renderiza os steps (mostra/esconde o tour)
|
|
52
|
+
const renderSteps = useCallback(() => {
|
|
53
|
+
if (enabled && steps.length > 0 && !isVisible) {
|
|
54
|
+
setIsVisible(true);
|
|
55
|
+
setCurrentStep(initialStep);
|
|
56
|
+
}
|
|
57
|
+
else if (!enabled && isVisible) {
|
|
58
|
+
setIsVisible(false);
|
|
59
|
+
setCurrentStep(initialStep);
|
|
60
|
+
setHighlightedElement(null);
|
|
61
|
+
setTooltipPosition(null);
|
|
62
|
+
}
|
|
63
|
+
}, [enabled, steps.length, isVisible, initialStep]);
|
|
45
64
|
// Destaca o elemento atual
|
|
46
65
|
useEffect(() => {
|
|
47
|
-
if (!
|
|
66
|
+
if (!isVisible || currentStep < 0 || currentStep >= steps.length) {
|
|
48
67
|
setHighlightedElement(null);
|
|
49
68
|
setTooltipPosition(null);
|
|
50
69
|
return;
|
|
@@ -63,25 +82,40 @@ export function Tour({ enabled, steps, initialStep = 0, options = {}, onExit, on
|
|
|
63
82
|
const position = calculateTooltipPosition(element, step.position);
|
|
64
83
|
setTooltipPosition(position);
|
|
65
84
|
}, 300);
|
|
66
|
-
}, [
|
|
85
|
+
}, [isVisible, currentStep, steps, calculateTooltipPosition]);
|
|
67
86
|
// Adiciona overlay e highlight ao elemento
|
|
68
87
|
useEffect(() => {
|
|
69
88
|
if (!highlightedElement) {
|
|
70
89
|
// Remove highlights anteriores
|
|
71
90
|
document.querySelectorAll(".tour-highlight").forEach((el) => {
|
|
72
91
|
el.classList.remove("tour-highlight");
|
|
92
|
+
el.style.zIndex = "";
|
|
73
93
|
});
|
|
74
94
|
return;
|
|
75
95
|
}
|
|
76
|
-
// Adiciona classe de highlight
|
|
96
|
+
// Adiciona classe de highlight e z-index alto
|
|
77
97
|
highlightedElement.classList.add("tour-highlight");
|
|
98
|
+
const originalZIndex = highlightedElement.style.zIndex;
|
|
99
|
+
highlightedElement.style.zIndex = "10000";
|
|
78
100
|
return () => {
|
|
79
101
|
highlightedElement.classList.remove("tour-highlight");
|
|
102
|
+
highlightedElement.style.zIndex = originalZIndex;
|
|
80
103
|
};
|
|
81
104
|
}, [highlightedElement]);
|
|
82
|
-
//
|
|
105
|
+
// Configura o tour quando necessário
|
|
106
|
+
useEffect(() => {
|
|
107
|
+
if (!isConfiguredRef.current || steps.length > 0) {
|
|
108
|
+
configureTour();
|
|
109
|
+
renderSteps();
|
|
110
|
+
}
|
|
111
|
+
}, [steps, configureTour, renderSteps]);
|
|
112
|
+
// Atualiza quando enabled muda
|
|
83
113
|
useEffect(() => {
|
|
84
|
-
|
|
114
|
+
renderSteps();
|
|
115
|
+
}, [enabled, renderSteps]);
|
|
116
|
+
// Handler de teclado (ESC e setas)
|
|
117
|
+
useEffect(() => {
|
|
118
|
+
if (!isVisible || !exitOnEsc)
|
|
85
119
|
return;
|
|
86
120
|
const handleKeyDown = (e) => {
|
|
87
121
|
if (e.key === "Escape") {
|
|
@@ -96,7 +130,19 @@ export function Tour({ enabled, steps, initialStep = 0, options = {}, onExit, on
|
|
|
96
130
|
};
|
|
97
131
|
window.addEventListener("keydown", handleKeyDown);
|
|
98
132
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
99
|
-
}, [
|
|
133
|
+
}, [isVisible, exitOnEsc, currentStep, steps.length]);
|
|
134
|
+
// Controla overflow do body
|
|
135
|
+
useEffect(() => {
|
|
136
|
+
if (isVisible) {
|
|
137
|
+
document.body.style.overflow = "hidden";
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
document.body.style.overflow = "";
|
|
141
|
+
}
|
|
142
|
+
return () => {
|
|
143
|
+
document.body.style.overflow = "";
|
|
144
|
+
};
|
|
145
|
+
}, [isVisible]);
|
|
100
146
|
const handleNext = useCallback(() => {
|
|
101
147
|
if (currentStep < steps.length - 1) {
|
|
102
148
|
setCurrentStep(currentStep + 1);
|
|
@@ -118,6 +164,7 @@ export function Tour({ enabled, steps, initialStep = 0, options = {}, onExit, on
|
|
|
118
164
|
handleExit();
|
|
119
165
|
}, [onComplete]);
|
|
120
166
|
const handleExit = useCallback(() => {
|
|
167
|
+
setIsVisible(false);
|
|
121
168
|
setCurrentStep(initialStep);
|
|
122
169
|
setHighlightedElement(null);
|
|
123
170
|
setTooltipPosition(null);
|
|
@@ -128,14 +175,24 @@ export function Tour({ enabled, steps, initialStep = 0, options = {}, onExit, on
|
|
|
128
175
|
handleExit();
|
|
129
176
|
}
|
|
130
177
|
}, [exitOnOverlayClick, handleExit]);
|
|
131
|
-
if (!
|
|
178
|
+
if (!isVisible) {
|
|
132
179
|
return null;
|
|
133
180
|
}
|
|
134
181
|
const currentStepData = steps[currentStep];
|
|
135
182
|
const isFirstStep = currentStep === 0;
|
|
136
183
|
const isLastStep = currentStep === steps.length - 1;
|
|
137
184
|
const progress = ((currentStep + 1) / steps.length) * 100;
|
|
138
|
-
return (_jsxs(_Fragment, { children: [_jsx("div", { ref: overlayRef,
|
|
185
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { ref: overlayRef, onClick: handleOverlayClick, style: {
|
|
186
|
+
position: "fixed",
|
|
187
|
+
top: 0,
|
|
188
|
+
left: 0,
|
|
189
|
+
right: 0,
|
|
190
|
+
bottom: 0,
|
|
191
|
+
backgroundColor: "rgba(0, 0, 0, 0.6)",
|
|
192
|
+
zIndex: 9998,
|
|
193
|
+
pointerEvents: exitOnOverlayClick ? "auto" : "none",
|
|
194
|
+
} }), tooltipPosition && currentStepData && highlightedElement && (_jsxs("div", { ref: tooltipRef, className: "max-w-sm", style: {
|
|
195
|
+
position: "fixed",
|
|
139
196
|
top: currentStepData.position === "bottom" ? `${tooltipPosition.top}px` : undefined,
|
|
140
197
|
bottom: currentStepData.position === "top" ? `${window.innerHeight - tooltipPosition.top}px` : undefined,
|
|
141
198
|
left: currentStepData.position === "left" || currentStepData.position === "right"
|
|
@@ -144,7 +201,8 @@ export function Tour({ enabled, steps, initialStep = 0, options = {}, onExit, on
|
|
|
144
201
|
transform: currentStepData.position === "left" || currentStepData.position === "right"
|
|
145
202
|
? "translate(0, -50%)"
|
|
146
203
|
: "translate(-50%, 0)",
|
|
147
|
-
|
|
204
|
+
zIndex: 10001,
|
|
205
|
+
}, 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 z-10", "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
206
|
? "bg-brand-primary w-6"
|
|
149
207
|
: "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
208
|
top: "-16px",
|
|
@@ -168,11 +226,12 @@ export function Tour({ enabled, steps, initialStep = 0, options = {}, onExit, on
|
|
|
168
226
|
borderColor: "transparent transparent transparent white",
|
|
169
227
|
} }))] })), _jsx("style", { children: `
|
|
170
228
|
.tour-highlight {
|
|
171
|
-
position: relative;
|
|
172
|
-
z-index:
|
|
229
|
+
position: relative !important;
|
|
230
|
+
z-index: 10000 !important;
|
|
173
231
|
outline: 3px solid var(--brand-primary, #0056b0) !important;
|
|
174
232
|
outline-offset: 2px;
|
|
175
233
|
border-radius: 4px;
|
|
234
|
+
box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.6) !important;
|
|
176
235
|
}
|
|
177
236
|
` })] }));
|
|
178
237
|
}
|
package/package.json
CHANGED
package/src/components/Tour.tsx
CHANGED
|
@@ -15,10 +15,12 @@ export function Tour({
|
|
|
15
15
|
onComplete,
|
|
16
16
|
}: TourProps) {
|
|
17
17
|
const [currentStep, setCurrentStep] = useState(initialStep);
|
|
18
|
+
const [isVisible, setIsVisible] = useState(false);
|
|
18
19
|
const [highlightedElement, setHighlightedElement] = useState<HTMLElement | null>(null);
|
|
19
20
|
const [tooltipPosition, setTooltipPosition] = useState<{ top: number; left: number } | null>(null);
|
|
20
21
|
const overlayRef = useRef<HTMLDivElement>(null);
|
|
21
22
|
const tooltipRef = useRef<HTMLDivElement>(null);
|
|
23
|
+
const isConfiguredRef = useRef(false);
|
|
22
24
|
|
|
23
25
|
const {
|
|
24
26
|
nextLabel = "Próximo",
|
|
@@ -31,19 +33,6 @@ export function Tour({
|
|
|
31
33
|
exitOnEsc = true,
|
|
32
34
|
} = options;
|
|
33
35
|
|
|
34
|
-
// Garante que o overlay seja renderizado quando enabled for true
|
|
35
|
-
useEffect(() => {
|
|
36
|
-
if (enabled) {
|
|
37
|
-
// Força o body a não ter scroll quando o tour está ativo
|
|
38
|
-
document.body.style.overflow = "hidden";
|
|
39
|
-
} else {
|
|
40
|
-
document.body.style.overflow = "";
|
|
41
|
-
}
|
|
42
|
-
return () => {
|
|
43
|
-
document.body.style.overflow = "";
|
|
44
|
-
};
|
|
45
|
-
}, [enabled]);
|
|
46
|
-
|
|
47
36
|
// Calcula a posição da tooltip baseado no elemento destacado
|
|
48
37
|
const calculateTooltipPosition = useCallback((element: HTMLElement, position: string = "bottom") => {
|
|
49
38
|
const rect = element.getBoundingClientRect();
|
|
@@ -78,9 +67,27 @@ export function Tour({
|
|
|
78
67
|
return { top, left };
|
|
79
68
|
}, []);
|
|
80
69
|
|
|
70
|
+
// Configura o tour quando steps ou options mudam
|
|
71
|
+
const configureTour = useCallback(() => {
|
|
72
|
+
isConfiguredRef.current = true;
|
|
73
|
+
}, []);
|
|
74
|
+
|
|
75
|
+
// Renderiza os steps (mostra/esconde o tour)
|
|
76
|
+
const renderSteps = useCallback(() => {
|
|
77
|
+
if (enabled && steps.length > 0 && !isVisible) {
|
|
78
|
+
setIsVisible(true);
|
|
79
|
+
setCurrentStep(initialStep);
|
|
80
|
+
} else if (!enabled && isVisible) {
|
|
81
|
+
setIsVisible(false);
|
|
82
|
+
setCurrentStep(initialStep);
|
|
83
|
+
setHighlightedElement(null);
|
|
84
|
+
setTooltipPosition(null);
|
|
85
|
+
}
|
|
86
|
+
}, [enabled, steps.length, isVisible, initialStep]);
|
|
87
|
+
|
|
81
88
|
// Destaca o elemento atual
|
|
82
89
|
useEffect(() => {
|
|
83
|
-
if (!
|
|
90
|
+
if (!isVisible || currentStep < 0 || currentStep >= steps.length) {
|
|
84
91
|
setHighlightedElement(null);
|
|
85
92
|
setTooltipPosition(null);
|
|
86
93
|
return;
|
|
@@ -104,7 +111,7 @@ export function Tour({
|
|
|
104
111
|
const position = calculateTooltipPosition(element, step.position);
|
|
105
112
|
setTooltipPosition(position);
|
|
106
113
|
}, 300);
|
|
107
|
-
}, [
|
|
114
|
+
}, [isVisible, currentStep, steps, calculateTooltipPosition]);
|
|
108
115
|
|
|
109
116
|
// Adiciona overlay e highlight ao elemento
|
|
110
117
|
useEffect(() => {
|
|
@@ -112,6 +119,7 @@ export function Tour({
|
|
|
112
119
|
// Remove highlights anteriores
|
|
113
120
|
document.querySelectorAll(".tour-highlight").forEach((el) => {
|
|
114
121
|
el.classList.remove("tour-highlight");
|
|
122
|
+
(el as HTMLElement).style.zIndex = "";
|
|
115
123
|
});
|
|
116
124
|
return;
|
|
117
125
|
}
|
|
@@ -127,9 +135,22 @@ export function Tour({
|
|
|
127
135
|
};
|
|
128
136
|
}, [highlightedElement]);
|
|
129
137
|
|
|
130
|
-
//
|
|
138
|
+
// Configura o tour quando necessário
|
|
131
139
|
useEffect(() => {
|
|
132
|
-
if (!
|
|
140
|
+
if (!isConfiguredRef.current || steps.length > 0) {
|
|
141
|
+
configureTour();
|
|
142
|
+
renderSteps();
|
|
143
|
+
}
|
|
144
|
+
}, [steps, configureTour, renderSteps]);
|
|
145
|
+
|
|
146
|
+
// Atualiza quando enabled muda
|
|
147
|
+
useEffect(() => {
|
|
148
|
+
renderSteps();
|
|
149
|
+
}, [enabled, renderSteps]);
|
|
150
|
+
|
|
151
|
+
// Handler de teclado (ESC e setas)
|
|
152
|
+
useEffect(() => {
|
|
153
|
+
if (!isVisible || !exitOnEsc) return;
|
|
133
154
|
|
|
134
155
|
const handleKeyDown = (e: KeyboardEvent) => {
|
|
135
156
|
if (e.key === "Escape") {
|
|
@@ -143,7 +164,19 @@ export function Tour({
|
|
|
143
164
|
|
|
144
165
|
window.addEventListener("keydown", handleKeyDown);
|
|
145
166
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
146
|
-
}, [
|
|
167
|
+
}, [isVisible, exitOnEsc, currentStep, steps.length]);
|
|
168
|
+
|
|
169
|
+
// Controla overflow do body
|
|
170
|
+
useEffect(() => {
|
|
171
|
+
if (isVisible) {
|
|
172
|
+
document.body.style.overflow = "hidden";
|
|
173
|
+
} else {
|
|
174
|
+
document.body.style.overflow = "";
|
|
175
|
+
}
|
|
176
|
+
return () => {
|
|
177
|
+
document.body.style.overflow = "";
|
|
178
|
+
};
|
|
179
|
+
}, [isVisible]);
|
|
147
180
|
|
|
148
181
|
const handleNext = useCallback(() => {
|
|
149
182
|
if (currentStep < steps.length - 1) {
|
|
@@ -169,6 +202,7 @@ export function Tour({
|
|
|
169
202
|
}, [onComplete]);
|
|
170
203
|
|
|
171
204
|
const handleExit = useCallback(() => {
|
|
205
|
+
setIsVisible(false);
|
|
172
206
|
setCurrentStep(initialStep);
|
|
173
207
|
setHighlightedElement(null);
|
|
174
208
|
setTooltipPosition(null);
|
|
@@ -184,7 +218,7 @@ export function Tour({
|
|
|
184
218
|
[exitOnOverlayClick, handleExit]
|
|
185
219
|
);
|
|
186
220
|
|
|
187
|
-
if (!
|
|
221
|
+
if (!isVisible) {
|
|
188
222
|
return null;
|
|
189
223
|
}
|
|
190
224
|
|
|
@@ -195,11 +229,11 @@ export function Tour({
|
|
|
195
229
|
|
|
196
230
|
return (
|
|
197
231
|
<>
|
|
198
|
-
{/* Overlay escuro
|
|
232
|
+
{/* Overlay escuro */}
|
|
199
233
|
<div
|
|
200
234
|
ref={overlayRef}
|
|
201
235
|
onClick={handleOverlayClick}
|
|
202
|
-
style={{
|
|
236
|
+
style={{
|
|
203
237
|
position: "fixed",
|
|
204
238
|
top: 0,
|
|
205
239
|
left: 0,
|
|
@@ -220,12 +254,13 @@ export function Tour({
|
|
|
220
254
|
position: "fixed",
|
|
221
255
|
top: currentStepData.position === "bottom" ? `${tooltipPosition.top}px` : undefined,
|
|
222
256
|
bottom: currentStepData.position === "top" ? `${window.innerHeight - tooltipPosition.top}px` : undefined,
|
|
223
|
-
left: currentStepData.position === "left" || currentStepData.position === "right"
|
|
224
|
-
? `${tooltipPosition.left}px`
|
|
257
|
+
left: currentStepData.position === "left" || currentStepData.position === "right"
|
|
258
|
+
? `${tooltipPosition.left}px`
|
|
225
259
|
: `${tooltipPosition.left}px`,
|
|
226
|
-
transform:
|
|
227
|
-
|
|
228
|
-
|
|
260
|
+
transform:
|
|
261
|
+
currentStepData.position === "left" || currentStepData.position === "right"
|
|
262
|
+
? "translate(0, -50%)"
|
|
263
|
+
: "translate(-50%, 0)",
|
|
229
264
|
zIndex: 10001,
|
|
230
265
|
}}
|
|
231
266
|
>
|
|
@@ -233,7 +268,7 @@ export function Tour({
|
|
|
233
268
|
{/* Botão fechar */}
|
|
234
269
|
<button
|
|
235
270
|
onClick={handleExit}
|
|
236
|
-
className="absolute top-2 right-2 p-1 rounded-full hover:bg-gray-100 transition-colors"
|
|
271
|
+
className="absolute top-2 right-2 p-1 rounded-full hover:bg-gray-100 transition-colors z-10"
|
|
237
272
|
aria-label="Fechar tour"
|
|
238
273
|
>
|
|
239
274
|
<HiXMark className="w-5 h-5 text-gray-500" />
|
|
@@ -373,4 +408,3 @@ export function Tour({
|
|
|
373
408
|
</>
|
|
374
409
|
);
|
|
375
410
|
}
|
|
376
|
-
|