@elogroup-sereduc/portal-aluno-tour 1.1.1 → 1.1.2

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/postcss.config.js DELETED
@@ -1,6 +0,0 @@
1
- export default {
2
- plugins: {
3
- "@tailwindcss/postcss": {},
4
- },
5
- };
6
-
@@ -1,638 +0,0 @@
1
- import { useEffect, useState, useCallback, useRef } from "react";
2
- import { Button } from "@heroui/button";
3
- import { TourProps, TourStep } from "../types";
4
- import { HiXMark, HiChevronLeft, HiChevronRight } from "react-icons/hi2";
5
-
6
- /**
7
- * Componente de tour guiado customizado usando HeroUI
8
- */
9
- export function Tour({
10
- enabled,
11
- steps,
12
- initialStep = 0,
13
- options = {},
14
- onExit,
15
- onComplete,
16
- }: TourProps) {
17
- const [currentStep, setCurrentStep] = useState(initialStep);
18
- const [isVisible, setIsVisible] = useState(false);
19
- const [highlightedElement, setHighlightedElement] = useState<HTMLElement | null>(null);
20
- const [tooltipPosition, setTooltipPosition] = useState<{ top: number; left: number; position: string } | null>(null);
21
- const overlayRef = useRef<HTMLDivElement>(null);
22
- const tooltipRef = useRef<HTMLDivElement>(null);
23
- const isConfiguredRef = useRef(false);
24
-
25
- const {
26
- nextLabel = "Próximo",
27
- prevLabel = "Anterior",
28
- skipLabel = "Pular",
29
- doneLabel = "Concluir",
30
- showProgress = true,
31
- showBullets = true,
32
- exitOnOverlayClick = false,
33
- exitOnEsc = true,
34
- } = options;
35
-
36
- // Calcula a posição da tooltip baseado no elemento destacado
37
- // Usa getBoundingClientRect() que retorna posições relativas à viewport
38
- // Isso mantém a tooltip sempre visível mesmo durante scroll
39
- const calculateTooltipPosition = useCallback((element: HTMLElement, position: string | undefined = "auto") => {
40
- const rect = element.getBoundingClientRect();
41
- const viewportWidth = window.innerWidth;
42
- const viewportHeight = window.innerHeight;
43
-
44
- // Tamanho estimado da tooltip
45
- const tooltipWidth = 384; // max-w-sm = 384px
46
- const tooltipHeight = 250; // altura estimada
47
- const spacing = 8; // espaçamento próximo ao elemento
48
-
49
- let top = 0;
50
- let left = 0;
51
- let finalPosition = position;
52
-
53
- // Verifica se o elemento está visível na viewport
54
- const isElementVisible =
55
- rect.top < viewportHeight &&
56
- rect.bottom > 0 &&
57
- rect.left < viewportWidth &&
58
- rect.right > 0;
59
-
60
- // Se o elemento não estiver visível, tenta posicionar próximo à borda mais próxima
61
- if (!isElementVisible) {
62
- // Elemento está fora da viewport - posiciona próximo à borda mais próxima
63
- if (rect.bottom < 0) {
64
- // Elemento está acima da viewport
65
- top = 8;
66
- left = Math.max(tooltipWidth / 2 + 8, Math.min(viewportWidth - tooltipWidth / 2 - 8, rect.left + rect.width / 2));
67
- finalPosition = "top";
68
- } else if (rect.top > viewportHeight) {
69
- // Elemento está abaixo da viewport
70
- top = viewportHeight - tooltipHeight - 8;
71
- left = Math.max(tooltipWidth / 2 + 8, Math.min(viewportWidth - tooltipWidth / 2 - 8, rect.left + rect.width / 2));
72
- finalPosition = "bottom";
73
- } else {
74
- // Elemento está à esquerda ou direita
75
- top = Math.max(tooltipHeight / 2 + 8, Math.min(viewportHeight - tooltipHeight / 2 - 8, rect.top + rect.height / 2));
76
- if (rect.right < 0) {
77
- left = 8;
78
- finalPosition = "left";
79
- } else {
80
- left = viewportWidth - tooltipWidth - 8;
81
- finalPosition = "right";
82
- }
83
- }
84
- return { top, left, position: finalPosition };
85
- }
86
-
87
- // Calcula espaço disponível em todas as direções
88
- const spaceAbove = rect.top;
89
- const spaceBelow = viewportHeight - rect.bottom;
90
- const spaceLeft = rect.left;
91
- const spaceRight = viewportWidth - rect.right;
92
-
93
- // Determina a melhor posição baseado no espaço disponível
94
- let bestPosition: "top" | "bottom" | "left" | "right";
95
-
96
- // Se position for "auto" ou não especificado, calcula automaticamente a melhor posição
97
- if (!position || position === "auto") {
98
- // Escolhe automaticamente a direção com mais espaço disponível
99
- const maxSpace = Math.max(spaceAbove, spaceBelow, spaceLeft, spaceRight);
100
- if (maxSpace === spaceAbove) bestPosition = "top";
101
- else if (maxSpace === spaceBelow) bestPosition = "bottom";
102
- else if (maxSpace === spaceLeft) bestPosition = "left";
103
- else bestPosition = "right";
104
- } else {
105
- // Posição específica foi fornecida - tenta usar ela primeiro
106
- // Verifica se a posição especificada tem espaço suficiente
107
- const hasEnoughSpace =
108
- (position === "top" && spaceAbove >= tooltipHeight + spacing + 8) ||
109
- (position === "bottom" && spaceBelow >= tooltipHeight + spacing + 8) ||
110
- (position === "left" && spaceLeft >= tooltipWidth + spacing + 8) ||
111
- (position === "right" && spaceRight >= tooltipWidth + spacing + 8);
112
-
113
- if (hasEnoughSpace) {
114
- // Tem espaço suficiente, usa a posição especificada
115
- bestPosition = position as "top" | "bottom" | "left" | "right";
116
- } else {
117
- // Não tem espaço suficiente na posição especificada, escolhe a melhor alternativa
118
- // Para posições verticais (top/bottom), compara entre elas
119
- if (position === "top" || position === "bottom") {
120
- bestPosition = spaceAbove > spaceBelow ? "top" : "bottom";
121
- }
122
- // Para posições horizontais (left/right), compara entre elas
123
- else if (position === "left" || position === "right") {
124
- bestPosition = spaceLeft > spaceRight ? "left" : "right";
125
- }
126
- // Fallback: escolhe a direção com mais espaço
127
- else {
128
- const maxSpace = Math.max(spaceAbove, spaceBelow, spaceLeft, spaceRight);
129
- if (maxSpace === spaceAbove) bestPosition = "top";
130
- else if (maxSpace === spaceBelow) bestPosition = "bottom";
131
- else if (maxSpace === spaceLeft) bestPosition = "left";
132
- else bestPosition = "right";
133
- }
134
- }
135
- }
136
-
137
- // Calcula posição base na melhor direção escolhida
138
- switch (bestPosition) {
139
- case "top":
140
- top = rect.top - spacing;
141
- left = rect.left + rect.width / 2;
142
- break;
143
- case "bottom":
144
- top = rect.bottom + spacing;
145
- left = rect.left + rect.width / 2;
146
- break;
147
- case "left":
148
- top = rect.top + rect.height / 2;
149
- // Para left, a tooltip fica à esquerda do elemento
150
- // left é onde a tooltip termina (borda direita), então subtrai a largura
151
- left = rect.left - tooltipWidth - spacing;
152
- break;
153
- case "right":
154
- top = rect.top + rect.height / 2;
155
- left = rect.right + spacing;
156
- break;
157
- default:
158
- top = rect.bottom + spacing;
159
- left = rect.left + rect.width / 2;
160
- bestPosition = "bottom";
161
- }
162
-
163
- finalPosition = bestPosition;
164
-
165
- // Ajusta horizontalmente para tooltips top/bottom - mantém próximo ao elemento
166
- if (finalPosition === "bottom" || finalPosition === "top") {
167
- // Centraliza no elemento, mas ajusta apenas se necessário para não sair da tela
168
- const elementCenterX = rect.left + rect.width / 2;
169
- const minLeft = tooltipWidth / 2 + 8;
170
- const maxLeft = viewportWidth - tooltipWidth / 2 - 8;
171
-
172
- // Mantém o mais próximo possível do centro do elemento
173
- if (elementCenterX < minLeft) {
174
- left = minLeft;
175
- } else if (elementCenterX > maxLeft) {
176
- left = maxLeft;
177
- } else {
178
- left = elementCenterX; // Mantém centralizado no elemento
179
- }
180
-
181
- // Verifica espaço vertical e ajusta posição se necessário
182
- if (finalPosition === "bottom") {
183
- const spaceBelow = viewportHeight - rect.bottom;
184
- if (spaceBelow < tooltipHeight + spacing + 8) {
185
- const spaceAbove = rect.top;
186
- if (spaceAbove > spaceBelow && spaceAbove > tooltipHeight + spacing + 8) {
187
- top = rect.top - spacing;
188
- finalPosition = "top";
189
- } else {
190
- // Mantém próximo ao elemento mesmo se não couber perfeitamente
191
- top = rect.bottom + spacing;
192
- }
193
- }
194
- } else if (finalPosition === "top") {
195
- const spaceAbove = rect.top;
196
- if (spaceAbove < tooltipHeight + spacing + 8) {
197
- const spaceBelow = viewportHeight - rect.bottom;
198
- if (spaceBelow > spaceAbove && spaceBelow > tooltipHeight + spacing + 8) {
199
- top = rect.bottom + spacing;
200
- finalPosition = "bottom";
201
- } else {
202
- // Mantém próximo ao elemento mesmo se não couber perfeitamente
203
- top = rect.top - spacing;
204
- }
205
- }
206
- }
207
- }
208
- // Ajusta verticalmente para tooltips left/right - mantém próximo ao elemento
209
- else if (finalPosition === "left" || finalPosition === "right") {
210
- // Centraliza no elemento verticalmente
211
- const elementCenterY = rect.top + rect.height / 2;
212
- const minTop = tooltipHeight / 2 + 8;
213
- const maxTop = viewportHeight - tooltipHeight / 2 - 8;
214
-
215
- // Mantém o mais próximo possível do centro do elemento
216
- if (elementCenterY < minTop) {
217
- top = minTop;
218
- } else if (elementCenterY > maxTop) {
219
- top = maxTop;
220
- } else {
221
- top = elementCenterY; // Mantém centralizado no elemento
222
- }
223
-
224
- // Verifica espaço horizontal e ajusta posição se necessário
225
- if (finalPosition === "left") {
226
- const spaceLeft = rect.left;
227
- if (spaceLeft < tooltipWidth + spacing + 8) {
228
- const spaceRight = viewportWidth - rect.right;
229
- if (spaceRight > spaceLeft && spaceRight > tooltipWidth + spacing + 8) {
230
- // Muda para direita se houver mais espaço
231
- left = rect.right + spacing;
232
- finalPosition = "right";
233
- } else {
234
- // Mantém à esquerda, mas ajusta para ficar visível
235
- left = Math.max(8, rect.left - tooltipWidth - spacing);
236
- }
237
- }
238
- // Se tem espaço suficiente, o left já foi calculado corretamente no switch acima
239
- } else if (finalPosition === "right") {
240
- const spaceRight = viewportWidth - rect.right;
241
- if (spaceRight < tooltipWidth + spacing + 8) {
242
- const spaceLeft = rect.left;
243
- if (spaceLeft > spaceRight && spaceLeft > tooltipWidth + spacing + 8) {
244
- // Muda para esquerda se houver mais espaço
245
- left = rect.left - tooltipWidth - spacing;
246
- finalPosition = "left";
247
- } else {
248
- // Mantém à direita, mas ajusta para ficar visível
249
- left = Math.min(viewportWidth - tooltipWidth - 8, rect.right + spacing);
250
- }
251
- }
252
- // Se tem espaço suficiente, o left já foi calculado corretamente no switch acima
253
- }
254
- }
255
-
256
- return { top, left, position: finalPosition };
257
- }, []);
258
-
259
- // Configura o tour quando steps ou options mudam
260
- const configureTour = useCallback(() => {
261
- isConfiguredRef.current = true;
262
- }, []);
263
-
264
- // Renderiza os steps (mostra/esconde o tour)
265
- const renderSteps = useCallback(() => {
266
- if (enabled && steps.length > 0 && !isVisible) {
267
- setIsVisible(true);
268
- setCurrentStep(initialStep);
269
- } else if (!enabled && isVisible) {
270
- setIsVisible(false);
271
- setCurrentStep(initialStep);
272
- setHighlightedElement(null);
273
- setTooltipPosition(null);
274
- }
275
- }, [enabled, steps.length, isVisible, initialStep]);
276
-
277
- // Função auxiliar para buscar elemento por seletor CSS ou data-onboard
278
- const findElement = useCallback((selector: string): HTMLElement | null => {
279
- // Se o seletor começa com caracteres de seletor CSS (. # [ etc), usa diretamente
280
- if (/^[.#\[:>+\s~]/.test(selector)) {
281
- return document.querySelector(selector) as HTMLElement;
282
- }
283
- // Caso contrário, assume que é um valor de data-onboard
284
- return document.querySelector(`[data-onboard="${selector}"]`) as HTMLElement;
285
- }, []);
286
-
287
- // Destaca o elemento atual
288
- useEffect(() => {
289
- if (!isVisible || currentStep < 0 || currentStep >= steps.length) {
290
- setHighlightedElement(null);
291
- setTooltipPosition(null);
292
- return;
293
- }
294
-
295
- const step = steps[currentStep];
296
- const element = findElement(step.element);
297
-
298
- if (!element) {
299
- console.warn(`Elemento não encontrado: ${step.element}. Tentando buscar [data-onboard="${step.element}"]`);
300
- return;
301
- }
302
-
303
- setHighlightedElement(element);
304
-
305
- // Scroll para o elemento
306
- element.scrollIntoView({ behavior: "smooth", block: "center" });
307
-
308
- // Função para calcular e atualizar posição
309
- const updatePosition = () => {
310
- const updatedRect = element.getBoundingClientRect();
311
- if (updatedRect.width > 0 && updatedRect.height > 0) {
312
- // Usa "auto" como default se position não for especificado
313
- const position = calculateTooltipPosition(element, step.position || "auto");
314
- setTooltipPosition(position);
315
- }
316
- };
317
-
318
- // Calcula posição inicial após um delay para garantir que o scroll terminou
319
- setTimeout(updatePosition, 400);
320
-
321
- // Adiciona listeners para recalcular posição em tempo real
322
- const handleScroll = () => {
323
- // Usa requestAnimationFrame para suavizar a atualização durante scroll
324
- requestAnimationFrame(updatePosition);
325
- };
326
-
327
- const handleResize = () => {
328
- updatePosition();
329
- };
330
-
331
- // Adiciona listeners em window e document para capturar todos os tipos de scroll
332
- window.addEventListener("scroll", handleScroll, { passive: true, capture: true });
333
- window.addEventListener("resize", handleResize, { passive: true });
334
- document.addEventListener("scroll", handleScroll, { passive: true, capture: true });
335
-
336
- return () => {
337
- window.removeEventListener("scroll", handleScroll, true);
338
- window.removeEventListener("resize", handleResize);
339
- document.removeEventListener("scroll", handleScroll, true);
340
- };
341
- }, [isVisible, currentStep, steps, calculateTooltipPosition, findElement]);
342
-
343
- // Adiciona overlay e highlight ao elemento
344
- useEffect(() => {
345
- if (!highlightedElement) {
346
- // Remove highlights anteriores
347
- document.querySelectorAll(".tour-highlight").forEach((el) => {
348
- el.classList.remove("tour-highlight");
349
- (el as HTMLElement).style.zIndex = "";
350
- });
351
- return;
352
- }
353
-
354
- // Adiciona classe de highlight e z-index alto
355
- highlightedElement.classList.add("tour-highlight");
356
- const originalZIndex = highlightedElement.style.zIndex;
357
- highlightedElement.style.zIndex = "10000";
358
-
359
- return () => {
360
- highlightedElement.classList.remove("tour-highlight");
361
- highlightedElement.style.zIndex = originalZIndex;
362
- };
363
- }, [highlightedElement]);
364
-
365
- // Configura o tour quando necessário
366
- useEffect(() => {
367
- if (!isConfiguredRef.current || steps.length > 0) {
368
- configureTour();
369
- renderSteps();
370
- }
371
- }, [steps, configureTour, renderSteps]);
372
-
373
- // Atualiza quando enabled muda
374
- useEffect(() => {
375
- renderSteps();
376
- }, [enabled, renderSteps]);
377
-
378
- // Handler de teclado (ESC e setas)
379
- useEffect(() => {
380
- if (!isVisible || !exitOnEsc) return;
381
-
382
- const handleKeyDown = (e: KeyboardEvent) => {
383
- if (e.key === "Escape") {
384
- handleExit();
385
- } else if (e.key === "ArrowRight") {
386
- handleNext();
387
- } else if (e.key === "ArrowLeft") {
388
- handlePrev();
389
- }
390
- };
391
-
392
- window.addEventListener("keydown", handleKeyDown);
393
- return () => window.removeEventListener("keydown", handleKeyDown);
394
- }, [isVisible, exitOnEsc, currentStep, steps.length]);
395
-
396
- // Controla overflow do body
397
- useEffect(() => {
398
- if (isVisible) {
399
- document.body.style.overflow = "hidden";
400
- } else {
401
- document.body.style.overflow = "";
402
- }
403
- return () => {
404
- document.body.style.overflow = "";
405
- };
406
- }, [isVisible]);
407
-
408
- const handleNext = useCallback(() => {
409
- if (currentStep < steps.length - 1) {
410
- setCurrentStep(currentStep + 1);
411
- } else {
412
- handleComplete();
413
- }
414
- }, [currentStep, steps.length]);
415
-
416
- const handlePrev = useCallback(() => {
417
- if (currentStep > 0) {
418
- setCurrentStep(currentStep - 1);
419
- }
420
- }, [currentStep]);
421
-
422
- const handleSkip = useCallback(() => {
423
- handleExit();
424
- }, []);
425
-
426
- const handleComplete = useCallback(() => {
427
- onComplete?.();
428
- handleExit();
429
- }, [onComplete]);
430
-
431
- const handleExit = useCallback(() => {
432
- setIsVisible(false);
433
- setCurrentStep(initialStep);
434
- setHighlightedElement(null);
435
- setTooltipPosition(null);
436
- onExit?.();
437
- }, [initialStep, onExit]);
438
-
439
- const handleOverlayClick = useCallback(
440
- (e: React.MouseEvent<HTMLDivElement>) => {
441
- if (exitOnOverlayClick && e.target === overlayRef.current) {
442
- handleExit();
443
- }
444
- },
445
- [exitOnOverlayClick, handleExit]
446
- );
447
-
448
- if (!isVisible) {
449
- return null;
450
- }
451
-
452
- const currentStepData = steps[currentStep];
453
- const isFirstStep = currentStep === 0;
454
- const isLastStep = currentStep === steps.length - 1;
455
- const progress = ((currentStep + 1) / steps.length) * 100;
456
-
457
- return (
458
- <>
459
- {/* Overlay escuro */}
460
- <div
461
- ref={overlayRef}
462
- onClick={handleOverlayClick}
463
- style={{
464
- position: "fixed",
465
- top: 0,
466
- left: 0,
467
- right: 0,
468
- bottom: 0,
469
- backgroundColor: "rgba(0, 0, 0, 0.6)",
470
- zIndex: 9998,
471
- pointerEvents: exitOnOverlayClick ? "auto" : "none",
472
- }}
473
- />
474
-
475
- {/* Tooltip */}
476
- {tooltipPosition && currentStepData && highlightedElement && (
477
- <div
478
- ref={tooltipRef}
479
- className="tour:max-w-sm"
480
- style={{
481
- position: "fixed",
482
- top: tooltipPosition.position === "bottom" || tooltipPosition.position === "left" || tooltipPosition.position === "right"
483
- ? `${tooltipPosition.top}px`
484
- : undefined,
485
- bottom: tooltipPosition.position === "top" ? `${window.innerHeight - tooltipPosition.top}px` : undefined,
486
- left: tooltipPosition.position === "left" || tooltipPosition.position === "right"
487
- ? `${tooltipPosition.left}px`
488
- : `${tooltipPosition.left}px`,
489
- transform:
490
- tooltipPosition.position === "left" || tooltipPosition.position === "right"
491
- ? "translate(0, -50%)"
492
- : "translate(-50%, 0)",
493
- zIndex: 10001,
494
- }}
495
- >
496
- <div className="tour:bg-white tour:rounded-lg tour:shadow-xl tour:p-6 tour:relative">
497
- {/* Botão fechar */}
498
- <button
499
- onClick={handleExit}
500
- className="tour:absolute tour:top-2 tour:right-2 tour:p-1 tour:rounded-full tour:hover:bg-gray-100 tour:transition-colors tour:z-10"
501
- aria-label="Fechar tour"
502
- >
503
- <HiXMark className="tour:w-5 tour:h-5 tour:text-gray-500" />
504
- </button>
505
-
506
- {/* Título (se fornecido) */}
507
- {currentStepData.title && (
508
- <h3 className="tour:text-lg tour:font-semibold tour:text-gray-900 tour:mb-2 tour:pr-6">
509
- {currentStepData.title}
510
- </h3>
511
- )}
512
-
513
- {/* Conteúdo */}
514
- <p className="tour:text-gray-700 tour:mb-4">{currentStepData.intro}</p>
515
-
516
- {/* Progresso */}
517
- {showProgress && (
518
- <div className="tour:mb-4">
519
- <div className="tour:w-full tour:bg-gray-200 tour:rounded-full tour:h-2">
520
- <div
521
- className="tour:bg-brand-primary tour:h-2 tour:rounded-full tour:transition-all tour:duration-300"
522
- style={{ width: `${progress}%` }}
523
- />
524
- </div>
525
- <p className="tour:text-xs tour:text-gray-500 tour:mt-1 tour:text-center">
526
- {currentStep + 1} de {steps.length}
527
- </p>
528
- </div>
529
- )}
530
-
531
- {/* Bullets */}
532
- {showBullets && (
533
- <div className="tour:flex tour:justify-center tour:gap-1 tour:mb-4">
534
- {steps.map((_, index) => (
535
- <button
536
- key={index}
537
- onClick={() => setCurrentStep(index)}
538
- className={`tour:w-2 tour:h-2 tour:rounded-full tour:transition-all ${index === currentStep
539
- ? "tour:bg-brand-primary tour:w-6"
540
- : "tour:bg-gray-300 tour:hover:bg-gray-400"
541
- }`}
542
- aria-label={`Ir para passo ${index + 1}`}
543
- />
544
- ))}
545
- </div>
546
- )}
547
-
548
- {/* Botões de navegação */}
549
- <div className="tour:flex tour:justify-between tour:items-center tour:gap-2">
550
- <div className="tour:flex tour:gap-2">
551
- {!isFirstStep && (
552
- <Button
553
- variant="bordered"
554
- onPress={handlePrev}
555
- startContent={<HiChevronLeft className="tour:w-4 tour:h-4" />}
556
- >
557
- {prevLabel}
558
- </Button>
559
- )}
560
- </div>
561
-
562
- <div className="tour:flex tour:gap-2">
563
- <Button variant="light" onPress={handleSkip}>
564
- {skipLabel}
565
- </Button>
566
- <Button
567
- color="primary"
568
- onPress={isLastStep ? handleComplete : handleNext}
569
- endContent={!isLastStep ? <HiChevronRight className="tour:w-4 tour:h-4" /> : undefined}
570
- >
571
- {isLastStep ? doneLabel : nextLabel}
572
- </Button>
573
- </div>
574
- </div>
575
- </div>
576
-
577
- {/* Seta indicadora */}
578
- {tooltipPosition.position === "bottom" && (
579
- <div
580
- className="tour:absolute tour:w-0 tour:h-0 tour:border-8 tour:border-transparent"
581
- style={{
582
- top: "-16px",
583
- left: "50%",
584
- transform: "translateX(-50%)",
585
- borderColor: "transparent transparent white transparent",
586
- }}
587
- />
588
- )}
589
- {tooltipPosition.position === "top" && (
590
- <div
591
- className="tour:absolute tour:w-0 tour:h-0 tour:border-8 tour:border-transparent"
592
- style={{
593
- bottom: "-16px",
594
- left: "50%",
595
- transform: "translateX(-50%)",
596
- borderColor: "white transparent transparent transparent",
597
- }}
598
- />
599
- )}
600
- {tooltipPosition.position === "right" && (
601
- <div
602
- className="tour:absolute tour:w-0 tour:h-0 tour:border-8 tour:border-transparent"
603
- style={{
604
- left: "-16px",
605
- top: "50%",
606
- transform: "translateY(-50%)",
607
- borderColor: "transparent white transparent transparent",
608
- }}
609
- />
610
- )}
611
- {tooltipPosition.position === "left" && (
612
- <div
613
- className="tour:absolute tour:w-0 tour:h-0 tour:border-8 tour:border-transparent"
614
- style={{
615
- right: "-16px",
616
- top: "50%",
617
- transform: "translateY(-50%)",
618
- borderColor: "transparent transparent transparent white",
619
- }}
620
- />
621
- )}
622
- </div>
623
- )}
624
-
625
- {/* Estilos inline para highlight */}
626
- <style>{`
627
- .tour-highlight {
628
- position: relative !important;
629
- z-index: 10000 !important;
630
- outline: 3px solid var(--brand-primary, #0056b0) !important;
631
- outline-offset: 2px;
632
- border-radius: 4px;
633
- box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.6) !important;
634
- }
635
- `}</style>
636
- </>
637
- );
638
- }
@@ -1,3 +0,0 @@
1
- @import "tailwindcss";
2
- @config "../../tailwind.config.js";
3
-