@elogroup-sereduc/portal-aluno-tour 1.0.3 → 1.0.4
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/README.md +6 -1
- package/dist/components/Tour.d.ts.map +1 -1
- package/dist/components/Tour.js +76 -18
- package/package.json +3 -2
- package/src/components/Tour.tsx +98 -39
- package/tailwind.config.js +8 -0
package/README.md
CHANGED
|
@@ -8,6 +8,12 @@ Componente de tour guiado customizado usando HeroUI para o Portal do Aluno.
|
|
|
8
8
|
npm install @elogroup-sereduc/portal-aluno-tour
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
+
## Configuração do Tailwind
|
|
12
|
+
|
|
13
|
+
Este pacote usa `@elogroup-sereduc/portal-aluno-tailwind-config` com o prefixo `portal-tour:`.
|
|
14
|
+
|
|
15
|
+
Certifique-se de que o Tailwind está configurado para processar as classes deste pacote. O pacote inclui um `tailwind.config.js` que estende a configuração compartilhada.
|
|
16
|
+
|
|
11
17
|
## Uso
|
|
12
18
|
|
|
13
19
|
```tsx
|
|
@@ -77,4 +83,3 @@ function MyComponent() {
|
|
|
77
83
|
- `showBullets?: boolean` - Mostrar bullets de navegação
|
|
78
84
|
- `exitOnOverlayClick?: boolean` - Permitir fechar clicando no overlay
|
|
79
85
|
- `exitOnEsc?: boolean` - Permitir fechar com ESC
|
|
80
|
-
|
|
@@ -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,kDAqcX"}
|
package/dist/components/Tour.js
CHANGED
|
@@ -19,30 +19,86 @@ export function Tour({ enabled, steps, initialStep = 0, options = {}, onExit, on
|
|
|
19
19
|
const rect = element.getBoundingClientRect();
|
|
20
20
|
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
|
21
21
|
const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
|
|
22
|
+
const viewportWidth = window.innerWidth;
|
|
23
|
+
const viewportHeight = window.innerHeight;
|
|
24
|
+
// Tamanho estimado da tooltip (ajuste conforme necessário)
|
|
25
|
+
const tooltipWidth = 384; // max-w-sm = 384px
|
|
26
|
+
const tooltipHeight = 200; // altura estimada
|
|
27
|
+
const spacing = 16; // espaçamento entre elemento e tooltip
|
|
22
28
|
let top = 0;
|
|
23
29
|
let left = 0;
|
|
30
|
+
let finalPosition = position;
|
|
31
|
+
// Calcula posição base
|
|
24
32
|
switch (position) {
|
|
25
33
|
case "top":
|
|
26
|
-
top = rect.top + scrollTop -
|
|
34
|
+
top = rect.top + scrollTop - spacing;
|
|
27
35
|
left = rect.left + scrollLeft + rect.width / 2;
|
|
28
36
|
break;
|
|
29
37
|
case "bottom":
|
|
30
|
-
top = rect.bottom + scrollTop +
|
|
38
|
+
top = rect.bottom + scrollTop + spacing;
|
|
31
39
|
left = rect.left + scrollLeft + rect.width / 2;
|
|
32
40
|
break;
|
|
33
41
|
case "left":
|
|
34
42
|
top = rect.top + scrollTop + rect.height / 2;
|
|
35
|
-
left = rect.left + scrollLeft -
|
|
43
|
+
left = rect.left + scrollLeft - spacing;
|
|
36
44
|
break;
|
|
37
45
|
case "right":
|
|
38
46
|
top = rect.top + scrollTop + rect.height / 2;
|
|
39
|
-
left = rect.right + scrollLeft +
|
|
47
|
+
left = rect.right + scrollLeft + spacing;
|
|
40
48
|
break;
|
|
41
49
|
default:
|
|
42
|
-
top = rect.bottom + scrollTop +
|
|
50
|
+
top = rect.bottom + scrollTop + spacing;
|
|
43
51
|
left = rect.left + scrollLeft + rect.width / 2;
|
|
52
|
+
finalPosition = "bottom";
|
|
44
53
|
}
|
|
45
|
-
|
|
54
|
+
// Ajusta posição se a tooltip sair da viewport
|
|
55
|
+
if (finalPosition === "bottom" || finalPosition === "top") {
|
|
56
|
+
// Ajusta horizontalmente
|
|
57
|
+
if (left - tooltipWidth / 2 < scrollLeft) {
|
|
58
|
+
left = scrollLeft + tooltipWidth / 2 + 16;
|
|
59
|
+
}
|
|
60
|
+
else if (left + tooltipWidth / 2 > scrollLeft + viewportWidth) {
|
|
61
|
+
left = scrollLeft + viewportWidth - tooltipWidth / 2 - 16;
|
|
62
|
+
}
|
|
63
|
+
// Se não couber embaixo, tenta em cima
|
|
64
|
+
if (finalPosition === "bottom" && top + tooltipHeight > scrollTop + viewportHeight) {
|
|
65
|
+
if (rect.top - tooltipHeight > scrollTop) {
|
|
66
|
+
top = rect.top + scrollTop - tooltipHeight - spacing;
|
|
67
|
+
finalPosition = "top";
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// Se não couber em cima, tenta embaixo
|
|
71
|
+
else if (finalPosition === "top" && top - tooltipHeight < scrollTop) {
|
|
72
|
+
if (rect.bottom + tooltipHeight < scrollTop + viewportHeight) {
|
|
73
|
+
top = rect.bottom + scrollTop + spacing;
|
|
74
|
+
finalPosition = "bottom";
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else if (finalPosition === "left" || finalPosition === "right") {
|
|
79
|
+
// Ajusta verticalmente
|
|
80
|
+
if (top - tooltipHeight / 2 < scrollTop) {
|
|
81
|
+
top = scrollTop + tooltipHeight / 2 + 16;
|
|
82
|
+
}
|
|
83
|
+
else if (top + tooltipHeight / 2 > scrollTop + viewportHeight) {
|
|
84
|
+
top = scrollTop + viewportHeight - tooltipHeight / 2 - 16;
|
|
85
|
+
}
|
|
86
|
+
// Se não couber à esquerda, tenta à direita
|
|
87
|
+
if (finalPosition === "left" && left - tooltipWidth < scrollLeft) {
|
|
88
|
+
if (rect.right + tooltipWidth < scrollLeft + viewportWidth) {
|
|
89
|
+
left = rect.right + scrollLeft + spacing;
|
|
90
|
+
finalPosition = "right";
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Se não couber à direita, tenta à esquerda
|
|
94
|
+
else if (finalPosition === "right" && left + tooltipWidth > scrollLeft + viewportWidth) {
|
|
95
|
+
if (rect.left - tooltipWidth > scrollLeft) {
|
|
96
|
+
left = rect.left + scrollLeft - spacing;
|
|
97
|
+
finalPosition = "left";
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return { top, left, position: finalPosition };
|
|
46
102
|
}, []);
|
|
47
103
|
// Configura o tour quando steps ou options mudam
|
|
48
104
|
const configureTour = useCallback(() => {
|
|
@@ -79,7 +135,7 @@ export function Tour({ enabled, steps, initialStep = 0, options = {}, onExit, on
|
|
|
79
135
|
element.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
80
136
|
// Calcula posição da tooltip após um pequeno delay para garantir que o scroll terminou
|
|
81
137
|
setTimeout(() => {
|
|
82
|
-
const position = calculateTooltipPosition(element, step.position);
|
|
138
|
+
const position = calculateTooltipPosition(element, step.position || "bottom");
|
|
83
139
|
setTooltipPosition(position);
|
|
84
140
|
}, 300);
|
|
85
141
|
}, [isVisible, currentStep, steps, calculateTooltipPosition]);
|
|
@@ -191,35 +247,37 @@ export function Tour({ enabled, steps, initialStep = 0, options = {}, onExit, on
|
|
|
191
247
|
backgroundColor: "rgba(0, 0, 0, 0.6)",
|
|
192
248
|
zIndex: 9998,
|
|
193
249
|
pointerEvents: exitOnOverlayClick ? "auto" : "none",
|
|
194
|
-
} }), tooltipPosition && currentStepData && highlightedElement && (_jsxs("div", { ref: tooltipRef, className: "max-w-sm", style: {
|
|
250
|
+
} }), tooltipPosition && currentStepData && highlightedElement && (_jsxs("div", { ref: tooltipRef, className: "portal-tour:max-w-sm", style: {
|
|
195
251
|
position: "fixed",
|
|
196
|
-
top:
|
|
197
|
-
|
|
198
|
-
|
|
252
|
+
top: tooltipPosition.position === "bottom" || tooltipPosition.position === "left" || tooltipPosition.position === "right"
|
|
253
|
+
? `${tooltipPosition.top}px`
|
|
254
|
+
: undefined,
|
|
255
|
+
bottom: tooltipPosition.position === "top" ? `${window.innerHeight - tooltipPosition.top}px` : undefined,
|
|
256
|
+
left: tooltipPosition.position === "left" || tooltipPosition.position === "right"
|
|
199
257
|
? `${tooltipPosition.left}px`
|
|
200
258
|
: `${tooltipPosition.left}px`,
|
|
201
|
-
transform:
|
|
259
|
+
transform: tooltipPosition.position === "left" || tooltipPosition.position === "right"
|
|
202
260
|
? "translate(0, -50%)"
|
|
203
261
|
: "translate(-50%, 0)",
|
|
204
262
|
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
|
|
206
|
-
? "bg-brand-primary w-6"
|
|
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 })] })] })] }),
|
|
263
|
+
}, children: [_jsxs("div", { className: "portal-tour:bg-white portal-tour:rounded-lg portal-tour:shadow-xl portal-tour:p-6 portal-tour:relative", children: [_jsx("button", { onClick: handleExit, className: "portal-tour:absolute portal-tour:top-2 portal-tour:right-2 portal-tour:p-1 portal-tour:rounded-full portal-tour:hover:bg-gray-100 portal-tour:transition-colors portal-tour:z-10", "aria-label": "Fechar tour", children: _jsx(HiXMark, { className: "portal-tour:w-5 portal-tour:h-5 portal-tour:text-gray-500" }) }), currentStepData.title && (_jsx("h3", { className: "portal-tour:text-lg portal-tour:font-semibold portal-tour:text-gray-900 portal-tour:mb-2 portal-tour:pr-6", children: currentStepData.title })), _jsx("p", { className: "portal-tour:text-gray-700 portal-tour:mb-4", children: currentStepData.intro }), showProgress && (_jsxs("div", { className: "portal-tour:mb-4", children: [_jsx("div", { className: "portal-tour:w-full portal-tour:bg-gray-200 portal-tour:rounded-full portal-tour:h-2", children: _jsx("div", { className: "portal-tour:bg-brand-primary portal-tour:h-2 portal-tour:rounded-full portal-tour:transition-all portal-tour:duration-300", style: { width: `${progress}%` } }) }), _jsxs("p", { className: "portal-tour:text-xs portal-tour:text-gray-500 portal-tour:mt-1 portal-tour:text-center", children: [currentStep + 1, " de ", steps.length] })] })), showBullets && (_jsx("div", { className: "portal-tour:flex portal-tour:justify-center portal-tour:gap-1 portal-tour:mb-4", children: steps.map((_, index) => (_jsx("button", { onClick: () => setCurrentStep(index), className: `portal-tour:w-2 portal-tour:h-2 portal-tour:rounded-full portal-tour:transition-all ${index === currentStep
|
|
264
|
+
? "portal-tour:bg-brand-primary portal-tour:w-6"
|
|
265
|
+
: "portal-tour:bg-gray-300 portal-tour:hover:bg-gray-400"}`, "aria-label": `Ir para passo ${index + 1}` }, index))) })), _jsxs("div", { className: "portal-tour:flex portal-tour:justify-between portal-tour:items-center portal-tour:gap-2", children: [_jsx("div", { className: "portal-tour:flex portal-tour:gap-2", children: !isFirstStep && (_jsx(Button, { variant: "bordered", onPress: handlePrev, startContent: _jsx(HiChevronLeft, { className: "portal-tour:w-4 portal-tour:h-4" }), children: prevLabel })) }), _jsxs("div", { className: "portal-tour:flex portal-tour:gap-2", children: [_jsx(Button, { variant: "light", onPress: handleSkip, children: skipLabel }), _jsx(Button, { color: "primary", onPress: isLastStep ? handleComplete : handleNext, endContent: !isLastStep ? _jsx(HiChevronRight, { className: "portal-tour:w-4 portal-tour:h-4" }) : undefined, children: isLastStep ? doneLabel : nextLabel })] })] })] }), tooltipPosition.position === "bottom" && (_jsx("div", { className: "portal-tour:absolute portal-tour:w-0 portal-tour:h-0 portal-tour:border-8 portal-tour:border-transparent", style: {
|
|
208
266
|
top: "-16px",
|
|
209
267
|
left: "50%",
|
|
210
268
|
transform: "translateX(-50%)",
|
|
211
269
|
borderColor: "transparent transparent white transparent",
|
|
212
|
-
} })),
|
|
270
|
+
} })), tooltipPosition.position === "top" && (_jsx("div", { className: "portal-tour:absolute portal-tour:w-0 portal-tour:h-0 portal-tour:border-8 portal-tour:border-transparent", style: {
|
|
213
271
|
bottom: "-16px",
|
|
214
272
|
left: "50%",
|
|
215
273
|
transform: "translateX(-50%)",
|
|
216
274
|
borderColor: "white transparent transparent transparent",
|
|
217
|
-
} })),
|
|
275
|
+
} })), tooltipPosition.position === "right" && (_jsx("div", { className: "portal-tour:absolute portal-tour:w-0 portal-tour:h-0 portal-tour:border-8 portal-tour:border-transparent", style: {
|
|
218
276
|
left: "-16px",
|
|
219
277
|
top: "50%",
|
|
220
278
|
transform: "translateY(-50%)",
|
|
221
279
|
borderColor: "transparent white transparent transparent",
|
|
222
|
-
} })),
|
|
280
|
+
} })), tooltipPosition.position === "left" && (_jsx("div", { className: "portal-tour:absolute portal-tour:w-0 portal-tour:h-0 portal-tour:border-8 portal-tour:border-transparent", style: {
|
|
223
281
|
right: "-16px",
|
|
224
282
|
top: "50%",
|
|
225
283
|
transform: "translateY(-50%)",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elogroup-sereduc/portal-aluno-tour",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
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",
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
"react-dom": "^18.0.0",
|
|
14
14
|
"@heroui/button": "^2.0.0",
|
|
15
15
|
"@heroui/system": "^2.0.0",
|
|
16
|
-
"react-icons": "^5.0.0"
|
|
16
|
+
"react-icons": "^5.0.0",
|
|
17
|
+
"@elogroup-sereduc/portal-aluno-tailwind-config": "^1.0.0"
|
|
17
18
|
},
|
|
18
19
|
"devDependencies": {
|
|
19
20
|
"@types/react": "^18.0.0",
|
package/src/components/Tour.tsx
CHANGED
|
@@ -17,7 +17,7 @@ export function Tour({
|
|
|
17
17
|
const [currentStep, setCurrentStep] = useState(initialStep);
|
|
18
18
|
const [isVisible, setIsVisible] = useState(false);
|
|
19
19
|
const [highlightedElement, setHighlightedElement] = useState<HTMLElement | null>(null);
|
|
20
|
-
const [tooltipPosition, setTooltipPosition] = useState<{ top: number; left: number } | null>(null);
|
|
20
|
+
const [tooltipPosition, setTooltipPosition] = useState<{ top: number; left: number; position: string } | null>(null);
|
|
21
21
|
const overlayRef = useRef<HTMLDivElement>(null);
|
|
22
22
|
const tooltipRef = useRef<HTMLDivElement>(null);
|
|
23
23
|
const isConfiguredRef = useRef(false);
|
|
@@ -38,33 +38,90 @@ export function Tour({
|
|
|
38
38
|
const rect = element.getBoundingClientRect();
|
|
39
39
|
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
|
40
40
|
const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
|
|
41
|
+
const viewportWidth = window.innerWidth;
|
|
42
|
+
const viewportHeight = window.innerHeight;
|
|
43
|
+
|
|
44
|
+
// Tamanho estimado da tooltip (ajuste conforme necessário)
|
|
45
|
+
const tooltipWidth = 384; // max-w-sm = 384px
|
|
46
|
+
const tooltipHeight = 200; // altura estimada
|
|
47
|
+
const spacing = 16; // espaçamento entre elemento e tooltip
|
|
41
48
|
|
|
42
49
|
let top = 0;
|
|
43
50
|
let left = 0;
|
|
51
|
+
let finalPosition = position;
|
|
44
52
|
|
|
53
|
+
// Calcula posição base
|
|
45
54
|
switch (position) {
|
|
46
55
|
case "top":
|
|
47
|
-
top = rect.top + scrollTop -
|
|
56
|
+
top = rect.top + scrollTop - spacing;
|
|
48
57
|
left = rect.left + scrollLeft + rect.width / 2;
|
|
49
58
|
break;
|
|
50
59
|
case "bottom":
|
|
51
|
-
top = rect.bottom + scrollTop +
|
|
60
|
+
top = rect.bottom + scrollTop + spacing;
|
|
52
61
|
left = rect.left + scrollLeft + rect.width / 2;
|
|
53
62
|
break;
|
|
54
63
|
case "left":
|
|
55
64
|
top = rect.top + scrollTop + rect.height / 2;
|
|
56
|
-
left = rect.left + scrollLeft -
|
|
65
|
+
left = rect.left + scrollLeft - spacing;
|
|
57
66
|
break;
|
|
58
67
|
case "right":
|
|
59
68
|
top = rect.top + scrollTop + rect.height / 2;
|
|
60
|
-
left = rect.right + scrollLeft +
|
|
69
|
+
left = rect.right + scrollLeft + spacing;
|
|
61
70
|
break;
|
|
62
71
|
default:
|
|
63
|
-
top = rect.bottom + scrollTop +
|
|
72
|
+
top = rect.bottom + scrollTop + spacing;
|
|
64
73
|
left = rect.left + scrollLeft + rect.width / 2;
|
|
74
|
+
finalPosition = "bottom";
|
|
65
75
|
}
|
|
66
76
|
|
|
67
|
-
|
|
77
|
+
// Ajusta posição se a tooltip sair da viewport
|
|
78
|
+
if (finalPosition === "bottom" || finalPosition === "top") {
|
|
79
|
+
// Ajusta horizontalmente
|
|
80
|
+
if (left - tooltipWidth / 2 < scrollLeft) {
|
|
81
|
+
left = scrollLeft + tooltipWidth / 2 + 16;
|
|
82
|
+
} else if (left + tooltipWidth / 2 > scrollLeft + viewportWidth) {
|
|
83
|
+
left = scrollLeft + viewportWidth - tooltipWidth / 2 - 16;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Se não couber embaixo, tenta em cima
|
|
87
|
+
if (finalPosition === "bottom" && top + tooltipHeight > scrollTop + viewportHeight) {
|
|
88
|
+
if (rect.top - tooltipHeight > scrollTop) {
|
|
89
|
+
top = rect.top + scrollTop - tooltipHeight - spacing;
|
|
90
|
+
finalPosition = "top";
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Se não couber em cima, tenta embaixo
|
|
94
|
+
else if (finalPosition === "top" && top - tooltipHeight < scrollTop) {
|
|
95
|
+
if (rect.bottom + tooltipHeight < scrollTop + viewportHeight) {
|
|
96
|
+
top = rect.bottom + scrollTop + spacing;
|
|
97
|
+
finalPosition = "bottom";
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
} else if (finalPosition === "left" || finalPosition === "right") {
|
|
101
|
+
// Ajusta verticalmente
|
|
102
|
+
if (top - tooltipHeight / 2 < scrollTop) {
|
|
103
|
+
top = scrollTop + tooltipHeight / 2 + 16;
|
|
104
|
+
} else if (top + tooltipHeight / 2 > scrollTop + viewportHeight) {
|
|
105
|
+
top = scrollTop + viewportHeight - tooltipHeight / 2 - 16;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Se não couber à esquerda, tenta à direita
|
|
109
|
+
if (finalPosition === "left" && left - tooltipWidth < scrollLeft) {
|
|
110
|
+
if (rect.right + tooltipWidth < scrollLeft + viewportWidth) {
|
|
111
|
+
left = rect.right + scrollLeft + spacing;
|
|
112
|
+
finalPosition = "right";
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// Se não couber à direita, tenta à esquerda
|
|
116
|
+
else if (finalPosition === "right" && left + tooltipWidth > scrollLeft + viewportWidth) {
|
|
117
|
+
if (rect.left - tooltipWidth > scrollLeft) {
|
|
118
|
+
left = rect.left + scrollLeft - spacing;
|
|
119
|
+
finalPosition = "left";
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return { top, left, position: finalPosition };
|
|
68
125
|
}, []);
|
|
69
126
|
|
|
70
127
|
// Configura o tour quando steps ou options mudam
|
|
@@ -108,7 +165,7 @@ export function Tour({
|
|
|
108
165
|
|
|
109
166
|
// Calcula posição da tooltip após um pequeno delay para garantir que o scroll terminou
|
|
110
167
|
setTimeout(() => {
|
|
111
|
-
const position = calculateTooltipPosition(element, step.position);
|
|
168
|
+
const position = calculateTooltipPosition(element, step.position || "bottom");
|
|
112
169
|
setTooltipPosition(position);
|
|
113
170
|
}, 300);
|
|
114
171
|
}, [isVisible, currentStep, steps, calculateTooltipPosition]);
|
|
@@ -249,51 +306,53 @@ export function Tour({
|
|
|
249
306
|
{tooltipPosition && currentStepData && highlightedElement && (
|
|
250
307
|
<div
|
|
251
308
|
ref={tooltipRef}
|
|
252
|
-
className="max-w-sm"
|
|
309
|
+
className="portal-tour:max-w-sm"
|
|
253
310
|
style={{
|
|
254
311
|
position: "fixed",
|
|
255
|
-
top:
|
|
256
|
-
|
|
257
|
-
|
|
312
|
+
top: tooltipPosition.position === "bottom" || tooltipPosition.position === "left" || tooltipPosition.position === "right"
|
|
313
|
+
? `${tooltipPosition.top}px`
|
|
314
|
+
: undefined,
|
|
315
|
+
bottom: tooltipPosition.position === "top" ? `${window.innerHeight - tooltipPosition.top}px` : undefined,
|
|
316
|
+
left: tooltipPosition.position === "left" || tooltipPosition.position === "right"
|
|
258
317
|
? `${tooltipPosition.left}px`
|
|
259
318
|
: `${tooltipPosition.left}px`,
|
|
260
319
|
transform:
|
|
261
|
-
|
|
320
|
+
tooltipPosition.position === "left" || tooltipPosition.position === "right"
|
|
262
321
|
? "translate(0, -50%)"
|
|
263
322
|
: "translate(-50%, 0)",
|
|
264
323
|
zIndex: 10001,
|
|
265
324
|
}}
|
|
266
325
|
>
|
|
267
|
-
<div className="bg-white rounded-lg shadow-xl p-6 relative">
|
|
326
|
+
<div className="portal-tour:bg-white portal-tour:rounded-lg portal-tour:shadow-xl portal-tour:p-6 portal-tour:relative">
|
|
268
327
|
{/* Botão fechar */}
|
|
269
328
|
<button
|
|
270
329
|
onClick={handleExit}
|
|
271
|
-
className="absolute top-2 right-2 p-1 rounded-full hover:bg-gray-100 transition-colors z-10"
|
|
330
|
+
className="portal-tour:absolute portal-tour:top-2 portal-tour:right-2 portal-tour:p-1 portal-tour:rounded-full portal-tour:hover:bg-gray-100 portal-tour:transition-colors portal-tour:z-10"
|
|
272
331
|
aria-label="Fechar tour"
|
|
273
332
|
>
|
|
274
|
-
<HiXMark className="w-5 h-5 text-gray-500" />
|
|
333
|
+
<HiXMark className="portal-tour:w-5 portal-tour:h-5 portal-tour:text-gray-500" />
|
|
275
334
|
</button>
|
|
276
335
|
|
|
277
336
|
{/* Título (se fornecido) */}
|
|
278
337
|
{currentStepData.title && (
|
|
279
|
-
<h3 className="text-lg font-semibold text-gray-900 mb-2 pr-6">
|
|
338
|
+
<h3 className="portal-tour:text-lg portal-tour:font-semibold portal-tour:text-gray-900 portal-tour:mb-2 portal-tour:pr-6">
|
|
280
339
|
{currentStepData.title}
|
|
281
340
|
</h3>
|
|
282
341
|
)}
|
|
283
342
|
|
|
284
343
|
{/* Conteúdo */}
|
|
285
|
-
<p className="text-gray-700 mb-4">{currentStepData.intro}</p>
|
|
344
|
+
<p className="portal-tour:text-gray-700 portal-tour:mb-4">{currentStepData.intro}</p>
|
|
286
345
|
|
|
287
346
|
{/* Progresso */}
|
|
288
347
|
{showProgress && (
|
|
289
|
-
<div className="mb-4">
|
|
290
|
-
<div className="w-full bg-gray-200 rounded-full h-2">
|
|
348
|
+
<div className="portal-tour:mb-4">
|
|
349
|
+
<div className="portal-tour:w-full portal-tour:bg-gray-200 portal-tour:rounded-full portal-tour:h-2">
|
|
291
350
|
<div
|
|
292
|
-
className="bg-brand-primary h-2 rounded-full transition-all duration-300"
|
|
351
|
+
className="portal-tour:bg-brand-primary portal-tour:h-2 portal-tour:rounded-full portal-tour:transition-all portal-tour:duration-300"
|
|
293
352
|
style={{ width: `${progress}%` }}
|
|
294
353
|
/>
|
|
295
354
|
</div>
|
|
296
|
-
<p className="text-xs text-gray-500 mt-1 text-center">
|
|
355
|
+
<p className="portal-tour:text-xs portal-tour:text-gray-500 portal-tour:mt-1 portal-tour:text-center">
|
|
297
356
|
{currentStep + 1} de {steps.length}
|
|
298
357
|
</p>
|
|
299
358
|
</div>
|
|
@@ -301,15 +360,15 @@ export function Tour({
|
|
|
301
360
|
|
|
302
361
|
{/* Bullets */}
|
|
303
362
|
{showBullets && (
|
|
304
|
-
<div className="flex justify-center gap-1 mb-4">
|
|
363
|
+
<div className="portal-tour:flex portal-tour:justify-center portal-tour:gap-1 portal-tour:mb-4">
|
|
305
364
|
{steps.map((_, index) => (
|
|
306
365
|
<button
|
|
307
366
|
key={index}
|
|
308
367
|
onClick={() => setCurrentStep(index)}
|
|
309
|
-
className={`w-2 h-2 rounded-full transition-all ${
|
|
368
|
+
className={`portal-tour:w-2 portal-tour:h-2 portal-tour:rounded-full portal-tour:transition-all ${
|
|
310
369
|
index === currentStep
|
|
311
|
-
? "bg-brand-primary w-6"
|
|
312
|
-
: "bg-gray-300 hover:bg-gray-400"
|
|
370
|
+
? "portal-tour:bg-brand-primary portal-tour:w-6"
|
|
371
|
+
: "portal-tour:bg-gray-300 portal-tour:hover:bg-gray-400"
|
|
313
372
|
}`}
|
|
314
373
|
aria-label={`Ir para passo ${index + 1}`}
|
|
315
374
|
/>
|
|
@@ -318,27 +377,27 @@ export function Tour({
|
|
|
318
377
|
)}
|
|
319
378
|
|
|
320
379
|
{/* Botões de navegação */}
|
|
321
|
-
<div className="flex justify-between items-center gap-2">
|
|
322
|
-
<div className="flex gap-2">
|
|
380
|
+
<div className="portal-tour:flex portal-tour:justify-between portal-tour:items-center portal-tour:gap-2">
|
|
381
|
+
<div className="portal-tour:flex portal-tour:gap-2">
|
|
323
382
|
{!isFirstStep && (
|
|
324
383
|
<Button
|
|
325
384
|
variant="bordered"
|
|
326
385
|
onPress={handlePrev}
|
|
327
|
-
startContent={<HiChevronLeft className="w-4 h-4" />}
|
|
386
|
+
startContent={<HiChevronLeft className="portal-tour:w-4 portal-tour:h-4" />}
|
|
328
387
|
>
|
|
329
388
|
{prevLabel}
|
|
330
389
|
</Button>
|
|
331
390
|
)}
|
|
332
391
|
</div>
|
|
333
392
|
|
|
334
|
-
<div className="flex gap-2">
|
|
393
|
+
<div className="portal-tour:flex portal-tour:gap-2">
|
|
335
394
|
<Button variant="light" onPress={handleSkip}>
|
|
336
395
|
{skipLabel}
|
|
337
396
|
</Button>
|
|
338
397
|
<Button
|
|
339
398
|
color="primary"
|
|
340
399
|
onPress={isLastStep ? handleComplete : handleNext}
|
|
341
|
-
endContent={!isLastStep ? <HiChevronRight className="w-4 h-4" /> : undefined}
|
|
400
|
+
endContent={!isLastStep ? <HiChevronRight className="portal-tour:w-4 portal-tour:h-4" /> : undefined}
|
|
342
401
|
>
|
|
343
402
|
{isLastStep ? doneLabel : nextLabel}
|
|
344
403
|
</Button>
|
|
@@ -347,9 +406,9 @@ export function Tour({
|
|
|
347
406
|
</div>
|
|
348
407
|
|
|
349
408
|
{/* Seta indicadora */}
|
|
350
|
-
{
|
|
409
|
+
{tooltipPosition.position === "bottom" && (
|
|
351
410
|
<div
|
|
352
|
-
className="absolute w-0 h-0 border-8 border-transparent"
|
|
411
|
+
className="portal-tour:absolute portal-tour:w-0 portal-tour:h-0 portal-tour:border-8 portal-tour:border-transparent"
|
|
353
412
|
style={{
|
|
354
413
|
top: "-16px",
|
|
355
414
|
left: "50%",
|
|
@@ -358,9 +417,9 @@ export function Tour({
|
|
|
358
417
|
}}
|
|
359
418
|
/>
|
|
360
419
|
)}
|
|
361
|
-
{
|
|
420
|
+
{tooltipPosition.position === "top" && (
|
|
362
421
|
<div
|
|
363
|
-
className="absolute w-0 h-0 border-8 border-transparent"
|
|
422
|
+
className="portal-tour:absolute portal-tour:w-0 portal-tour:h-0 portal-tour:border-8 portal-tour:border-transparent"
|
|
364
423
|
style={{
|
|
365
424
|
bottom: "-16px",
|
|
366
425
|
left: "50%",
|
|
@@ -369,9 +428,9 @@ export function Tour({
|
|
|
369
428
|
}}
|
|
370
429
|
/>
|
|
371
430
|
)}
|
|
372
|
-
{
|
|
431
|
+
{tooltipPosition.position === "right" && (
|
|
373
432
|
<div
|
|
374
|
-
className="absolute w-0 h-0 border-8 border-transparent"
|
|
433
|
+
className="portal-tour:absolute portal-tour:w-0 portal-tour:h-0 portal-tour:border-8 portal-tour:border-transparent"
|
|
375
434
|
style={{
|
|
376
435
|
left: "-16px",
|
|
377
436
|
top: "50%",
|
|
@@ -380,9 +439,9 @@ export function Tour({
|
|
|
380
439
|
}}
|
|
381
440
|
/>
|
|
382
441
|
)}
|
|
383
|
-
{
|
|
442
|
+
{tooltipPosition.position === "left" && (
|
|
384
443
|
<div
|
|
385
|
-
className="absolute w-0 h-0 border-8 border-transparent"
|
|
444
|
+
className="portal-tour:absolute portal-tour:w-0 portal-tour:h-0 portal-tour:border-8 portal-tour:border-transparent"
|
|
386
445
|
style={{
|
|
387
446
|
right: "-16px",
|
|
388
447
|
top: "50%",
|