@elogroup-sereduc/portal-aluno-tour 1.0.5 → 1.0.7

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.
@@ -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,kDAqcX"}
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,kDA0iBX"}
@@ -15,86 +15,165 @@ export function Tour({ enabled, steps, initialStep = 0, options = {}, onExit, on
15
15
  const isConfiguredRef = useRef(false);
16
16
  const { nextLabel = "Próximo", prevLabel = "Anterior", skipLabel = "Pular", doneLabel = "Concluir", showProgress = true, showBullets = true, exitOnOverlayClick = false, exitOnEsc = true, } = options;
17
17
  // Calcula a posição da tooltip baseado no elemento destacado
18
+ // Usa getBoundingClientRect() que retorna posições relativas à viewport
19
+ // Isso mantém a tooltip sempre visível mesmo durante scroll
18
20
  const calculateTooltipPosition = useCallback((element, position = "bottom") => {
19
21
  const rect = element.getBoundingClientRect();
20
- const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
21
- const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
22
22
  const viewportWidth = window.innerWidth;
23
23
  const viewportHeight = window.innerHeight;
24
- // Tamanho estimado da tooltip (ajuste conforme necessário)
24
+ // Tamanho estimado da tooltip
25
25
  const tooltipWidth = 384; // max-w-sm = 384px
26
- const tooltipHeight = 200; // altura estimada
27
- const spacing = 16; // espaçamento entre elemento e tooltip
26
+ const tooltipHeight = 250; // altura estimada
27
+ const spacing = 8; // espaçamento próximo ao elemento
28
28
  let top = 0;
29
29
  let left = 0;
30
30
  let finalPosition = position;
31
- // Calcula posição base
31
+ // Verifica se o elemento está visível na viewport
32
+ const isElementVisible = rect.top < viewportHeight &&
33
+ rect.bottom > 0 &&
34
+ rect.left < viewportWidth &&
35
+ rect.right > 0;
36
+ // Se o elemento não estiver visível, tenta posicionar próximo à borda mais próxima
37
+ if (!isElementVisible) {
38
+ // Elemento está fora da viewport - posiciona próximo à borda mais próxima
39
+ if (rect.bottom < 0) {
40
+ // Elemento está acima da viewport
41
+ top = 8;
42
+ left = Math.max(tooltipWidth / 2 + 8, Math.min(viewportWidth - tooltipWidth / 2 - 8, rect.left + rect.width / 2));
43
+ finalPosition = "top";
44
+ }
45
+ else if (rect.top > viewportHeight) {
46
+ // Elemento está abaixo da viewport
47
+ top = viewportHeight - tooltipHeight - 8;
48
+ left = Math.max(tooltipWidth / 2 + 8, Math.min(viewportWidth - tooltipWidth / 2 - 8, rect.left + rect.width / 2));
49
+ finalPosition = "bottom";
50
+ }
51
+ else {
52
+ // Elemento está à esquerda ou direita
53
+ top = Math.max(tooltipHeight / 2 + 8, Math.min(viewportHeight - tooltipHeight / 2 - 8, rect.top + rect.height / 2));
54
+ if (rect.right < 0) {
55
+ left = 8;
56
+ finalPosition = "left";
57
+ }
58
+ else {
59
+ left = viewportWidth - tooltipWidth - 8;
60
+ finalPosition = "right";
61
+ }
62
+ }
63
+ return { top, left, position: finalPosition };
64
+ }
65
+ // Elemento está visível - calcula posição normal próxima ao elemento
32
66
  switch (position) {
33
67
  case "top":
34
- top = rect.top + scrollTop - spacing;
35
- left = rect.left + scrollLeft + rect.width / 2;
68
+ top = rect.top - spacing;
69
+ left = rect.left + rect.width / 2;
36
70
  break;
37
71
  case "bottom":
38
- top = rect.bottom + scrollTop + spacing;
39
- left = rect.left + scrollLeft + rect.width / 2;
72
+ top = rect.bottom + spacing;
73
+ left = rect.left + rect.width / 2;
40
74
  break;
41
75
  case "left":
42
- top = rect.top + scrollTop + rect.height / 2;
43
- left = rect.left + scrollLeft - spacing;
76
+ top = rect.top + rect.height / 2;
77
+ left = rect.left - spacing;
44
78
  break;
45
79
  case "right":
46
- top = rect.top + scrollTop + rect.height / 2;
47
- left = rect.right + scrollLeft + spacing;
80
+ top = rect.top + rect.height / 2;
81
+ left = rect.right + spacing;
48
82
  break;
49
83
  default:
50
- top = rect.bottom + scrollTop + spacing;
51
- left = rect.left + scrollLeft + rect.width / 2;
84
+ top = rect.bottom + spacing;
85
+ left = rect.left + rect.width / 2;
52
86
  finalPosition = "bottom";
53
87
  }
54
- // Ajusta posição se a tooltip sair da viewport
88
+ // Ajusta horizontalmente para tooltips top/bottom - mantém próximo ao elemento
55
89
  if (finalPosition === "bottom" || finalPosition === "top") {
56
- // Ajusta horizontalmente
57
- if (left - tooltipWidth / 2 < scrollLeft) {
58
- left = scrollLeft + tooltipWidth / 2 + 16;
90
+ // Centraliza no elemento, mas ajusta apenas se necessário para não sair da tela
91
+ const elementCenterX = rect.left + rect.width / 2;
92
+ const minLeft = tooltipWidth / 2 + 8;
93
+ const maxLeft = viewportWidth - tooltipWidth / 2 - 8;
94
+ // Mantém o mais próximo possível do centro do elemento
95
+ if (elementCenterX < minLeft) {
96
+ left = minLeft;
97
+ }
98
+ else if (elementCenterX > maxLeft) {
99
+ left = maxLeft;
59
100
  }
60
- else if (left + tooltipWidth / 2 > scrollLeft + viewportWidth) {
61
- left = scrollLeft + viewportWidth - tooltipWidth / 2 - 16;
101
+ else {
102
+ left = elementCenterX; // Mantém centralizado no elemento
62
103
  }
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";
104
+ // Verifica espaço vertical e ajusta posição se necessário
105
+ if (finalPosition === "bottom") {
106
+ const spaceBelow = viewportHeight - rect.bottom;
107
+ if (spaceBelow < tooltipHeight + spacing + 8) {
108
+ const spaceAbove = rect.top;
109
+ if (spaceAbove > spaceBelow && spaceAbove > tooltipHeight + spacing + 8) {
110
+ top = rect.top - spacing;
111
+ finalPosition = "top";
112
+ }
113
+ else {
114
+ // Mantém próximo ao elemento mesmo se não couber perfeitamente
115
+ top = rect.bottom + spacing;
116
+ }
68
117
  }
69
118
  }
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";
119
+ else if (finalPosition === "top") {
120
+ const spaceAbove = rect.top;
121
+ if (spaceAbove < tooltipHeight + spacing + 8) {
122
+ const spaceBelow = viewportHeight - rect.bottom;
123
+ if (spaceBelow > spaceAbove && spaceBelow > tooltipHeight + spacing + 8) {
124
+ top = rect.bottom + spacing;
125
+ finalPosition = "bottom";
126
+ }
127
+ else {
128
+ // Mantém próximo ao elemento mesmo se não couber perfeitamente
129
+ top = rect.top - spacing;
130
+ }
75
131
  }
76
132
  }
77
133
  }
134
+ // Ajusta verticalmente para tooltips left/right - mantém próximo ao elemento
78
135
  else if (finalPosition === "left" || finalPosition === "right") {
79
- // Ajusta verticalmente
80
- if (top - tooltipHeight / 2 < scrollTop) {
81
- top = scrollTop + tooltipHeight / 2 + 16;
136
+ // Centraliza no elemento verticalmente
137
+ const elementCenterY = rect.top + rect.height / 2;
138
+ const minTop = tooltipHeight / 2 + 8;
139
+ const maxTop = viewportHeight - tooltipHeight / 2 - 8;
140
+ // Mantém o mais próximo possível do centro do elemento
141
+ if (elementCenterY < minTop) {
142
+ top = minTop;
82
143
  }
83
- else if (top + tooltipHeight / 2 > scrollTop + viewportHeight) {
84
- top = scrollTop + viewportHeight - tooltipHeight / 2 - 16;
144
+ else if (elementCenterY > maxTop) {
145
+ top = maxTop;
85
146
  }
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";
147
+ else {
148
+ top = elementCenterY; // Mantém centralizado no elemento
149
+ }
150
+ // Verifica espaço horizontal e ajusta posição se necessário
151
+ if (finalPosition === "left") {
152
+ const spaceLeft = rect.left;
153
+ if (spaceLeft < tooltipWidth + spacing + 8) {
154
+ const spaceRight = viewportWidth - rect.right;
155
+ if (spaceRight > spaceLeft && spaceRight > tooltipWidth + spacing + 8) {
156
+ left = rect.right + spacing;
157
+ finalPosition = "right";
158
+ }
159
+ else {
160
+ // Mantém próximo ao elemento mesmo se não couber perfeitamente
161
+ left = rect.left - spacing;
162
+ }
91
163
  }
92
164
  }
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";
165
+ else if (finalPosition === "right") {
166
+ const spaceRight = viewportWidth - rect.right;
167
+ if (spaceRight < tooltipWidth + spacing + 8) {
168
+ const spaceLeft = rect.left;
169
+ if (spaceLeft > spaceRight && spaceLeft > tooltipWidth + spacing + 8) {
170
+ left = rect.left - spacing;
171
+ finalPosition = "left";
172
+ }
173
+ else {
174
+ // Mantém próximo ao elemento mesmo se não couber perfeitamente
175
+ left = rect.right + spacing;
176
+ }
98
177
  }
99
178
  }
100
179
  }
@@ -133,11 +212,33 @@ export function Tour({ enabled, steps, initialStep = 0, options = {}, onExit, on
133
212
  setHighlightedElement(element);
134
213
  // Scroll para o elemento
135
214
  element.scrollIntoView({ behavior: "smooth", block: "center" });
136
- // Calcula posição da tooltip após um pequeno delay para garantir que o scroll terminou
137
- setTimeout(() => {
138
- const position = calculateTooltipPosition(element, step.position || "bottom");
139
- setTooltipPosition(position);
140
- }, 300);
215
+ // Função para calcular e atualizar posição
216
+ const updatePosition = () => {
217
+ const updatedRect = element.getBoundingClientRect();
218
+ if (updatedRect.width > 0 && updatedRect.height > 0) {
219
+ const position = calculateTooltipPosition(element, step.position || "bottom");
220
+ setTooltipPosition(position);
221
+ }
222
+ };
223
+ // Calcula posição inicial após um delay para garantir que o scroll terminou
224
+ setTimeout(updatePosition, 400);
225
+ // Adiciona listeners para recalcular posição em tempo real
226
+ const handleScroll = () => {
227
+ // Usa requestAnimationFrame para suavizar a atualização durante scroll
228
+ requestAnimationFrame(updatePosition);
229
+ };
230
+ const handleResize = () => {
231
+ updatePosition();
232
+ };
233
+ // Adiciona listeners em window e document para capturar todos os tipos de scroll
234
+ window.addEventListener("scroll", handleScroll, { passive: true, capture: true });
235
+ window.addEventListener("resize", handleResize, { passive: true });
236
+ document.addEventListener("scroll", handleScroll, { passive: true, capture: true });
237
+ return () => {
238
+ window.removeEventListener("scroll", handleScroll, true);
239
+ window.removeEventListener("resize", handleResize);
240
+ document.removeEventListener("scroll", handleScroll, true);
241
+ };
141
242
  }, [isVisible, currentStep, steps, calculateTooltipPosition]);
142
243
  // Adiciona overlay e highlight ao elemento
143
244
  useEffect(() => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elogroup-sereduc/portal-aluno-tour",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Componente de tour guiado customizado usando HeroUI para o Portal do Aluno",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -34,89 +34,163 @@ export function Tour({
34
34
  } = options;
35
35
 
36
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
37
39
  const calculateTooltipPosition = useCallback((element: HTMLElement, position: string = "bottom") => {
38
40
  const rect = element.getBoundingClientRect();
39
- const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
40
- const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
41
41
  const viewportWidth = window.innerWidth;
42
42
  const viewportHeight = window.innerHeight;
43
43
 
44
- // Tamanho estimado da tooltip (ajuste conforme necessário)
44
+ // Tamanho estimado da tooltip
45
45
  const tooltipWidth = 384; // max-w-sm = 384px
46
- const tooltipHeight = 200; // altura estimada
47
- const spacing = 16; // espaçamento entre elemento e tooltip
46
+ const tooltipHeight = 250; // altura estimada
47
+ const spacing = 8; // espaçamento próximo ao elemento
48
48
 
49
49
  let top = 0;
50
50
  let left = 0;
51
51
  let finalPosition = position;
52
52
 
53
- // Calcula posição base
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
+ // Elemento está visível - calcula posição normal próxima ao elemento
54
88
  switch (position) {
55
89
  case "top":
56
- top = rect.top + scrollTop - spacing;
57
- left = rect.left + scrollLeft + rect.width / 2;
90
+ top = rect.top - spacing;
91
+ left = rect.left + rect.width / 2;
58
92
  break;
59
93
  case "bottom":
60
- top = rect.bottom + scrollTop + spacing;
61
- left = rect.left + scrollLeft + rect.width / 2;
94
+ top = rect.bottom + spacing;
95
+ left = rect.left + rect.width / 2;
62
96
  break;
63
97
  case "left":
64
- top = rect.top + scrollTop + rect.height / 2;
65
- left = rect.left + scrollLeft - spacing;
98
+ top = rect.top + rect.height / 2;
99
+ left = rect.left - spacing;
66
100
  break;
67
101
  case "right":
68
- top = rect.top + scrollTop + rect.height / 2;
69
- left = rect.right + scrollLeft + spacing;
102
+ top = rect.top + rect.height / 2;
103
+ left = rect.right + spacing;
70
104
  break;
71
105
  default:
72
- top = rect.bottom + scrollTop + spacing;
73
- left = rect.left + scrollLeft + rect.width / 2;
106
+ top = rect.bottom + spacing;
107
+ left = rect.left + rect.width / 2;
74
108
  finalPosition = "bottom";
75
109
  }
76
110
 
77
- // Ajusta posição se a tooltip sair da viewport
111
+ // Ajusta horizontalmente para tooltips top/bottom - mantém próximo ao elemento
78
112
  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;
113
+ // Centraliza no elemento, mas ajusta apenas se necessário para não sair da tela
114
+ const elementCenterX = rect.left + rect.width / 2;
115
+ const minLeft = tooltipWidth / 2 + 8;
116
+ const maxLeft = viewportWidth - tooltipWidth / 2 - 8;
117
+
118
+ // Mantém o mais próximo possível do centro do elemento
119
+ if (elementCenterX < minLeft) {
120
+ left = minLeft;
121
+ } else if (elementCenterX > maxLeft) {
122
+ left = maxLeft;
123
+ } else {
124
+ left = elementCenterX; // Mantém centralizado no elemento
84
125
  }
85
126
 
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";
127
+ // Verifica espaço vertical e ajusta posição se necessário
128
+ if (finalPosition === "bottom") {
129
+ const spaceBelow = viewportHeight - rect.bottom;
130
+ if (spaceBelow < tooltipHeight + spacing + 8) {
131
+ const spaceAbove = rect.top;
132
+ if (spaceAbove > spaceBelow && spaceAbove > tooltipHeight + spacing + 8) {
133
+ top = rect.top - spacing;
134
+ finalPosition = "top";
135
+ } else {
136
+ // Mantém próximo ao elemento mesmo se não couber perfeitamente
137
+ top = rect.bottom + spacing;
138
+ }
91
139
  }
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";
140
+ } else if (finalPosition === "top") {
141
+ const spaceAbove = rect.top;
142
+ if (spaceAbove < tooltipHeight + spacing + 8) {
143
+ const spaceBelow = viewportHeight - rect.bottom;
144
+ if (spaceBelow > spaceAbove && spaceBelow > tooltipHeight + spacing + 8) {
145
+ top = rect.bottom + spacing;
146
+ finalPosition = "bottom";
147
+ } else {
148
+ // Mantém próximo ao elemento mesmo se não couber perfeitamente
149
+ top = rect.top - spacing;
150
+ }
98
151
  }
99
152
  }
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;
153
+ }
154
+ // Ajusta verticalmente para tooltips left/right - mantém próximo ao elemento
155
+ else if (finalPosition === "left" || finalPosition === "right") {
156
+ // Centraliza no elemento verticalmente
157
+ const elementCenterY = rect.top + rect.height / 2;
158
+ const minTop = tooltipHeight / 2 + 8;
159
+ const maxTop = viewportHeight - tooltipHeight / 2 - 8;
160
+
161
+ // Mantém o mais próximo possível do centro do elemento
162
+ if (elementCenterY < minTop) {
163
+ top = minTop;
164
+ } else if (elementCenterY > maxTop) {
165
+ top = maxTop;
166
+ } else {
167
+ top = elementCenterY; // Mantém centralizado no elemento
106
168
  }
107
169
 
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";
170
+ // Verifica espaço horizontal e ajusta posição se necessário
171
+ if (finalPosition === "left") {
172
+ const spaceLeft = rect.left;
173
+ if (spaceLeft < tooltipWidth + spacing + 8) {
174
+ const spaceRight = viewportWidth - rect.right;
175
+ if (spaceRight > spaceLeft && spaceRight > tooltipWidth + spacing + 8) {
176
+ left = rect.right + spacing;
177
+ finalPosition = "right";
178
+ } else {
179
+ // Mantém próximo ao elemento mesmo se não couber perfeitamente
180
+ left = rect.left - spacing;
181
+ }
113
182
  }
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";
183
+ } else if (finalPosition === "right") {
184
+ const spaceRight = viewportWidth - rect.right;
185
+ if (spaceRight < tooltipWidth + spacing + 8) {
186
+ const spaceLeft = rect.left;
187
+ if (spaceLeft > spaceRight && spaceLeft > tooltipWidth + spacing + 8) {
188
+ left = rect.left - spacing;
189
+ finalPosition = "left";
190
+ } else {
191
+ // Mantém próximo ao elemento mesmo se não couber perfeitamente
192
+ left = rect.right + spacing;
193
+ }
120
194
  }
121
195
  }
122
196
  }
@@ -163,11 +237,38 @@ export function Tour({
163
237
  // Scroll para o elemento
164
238
  element.scrollIntoView({ behavior: "smooth", block: "center" });
165
239
 
166
- // Calcula posição da tooltip após um pequeno delay para garantir que o scroll terminou
167
- setTimeout(() => {
168
- const position = calculateTooltipPosition(element, step.position || "bottom");
169
- setTooltipPosition(position);
170
- }, 300);
240
+ // Função para calcular e atualizar posição
241
+ const updatePosition = () => {
242
+ const updatedRect = element.getBoundingClientRect();
243
+ if (updatedRect.width > 0 && updatedRect.height > 0) {
244
+ const position = calculateTooltipPosition(element, step.position || "bottom");
245
+ setTooltipPosition(position);
246
+ }
247
+ };
248
+
249
+ // Calcula posição inicial após um delay para garantir que o scroll terminou
250
+ setTimeout(updatePosition, 400);
251
+
252
+ // Adiciona listeners para recalcular posição em tempo real
253
+ const handleScroll = () => {
254
+ // Usa requestAnimationFrame para suavizar a atualização durante scroll
255
+ requestAnimationFrame(updatePosition);
256
+ };
257
+
258
+ const handleResize = () => {
259
+ updatePosition();
260
+ };
261
+
262
+ // Adiciona listeners em window e document para capturar todos os tipos de scroll
263
+ window.addEventListener("scroll", handleScroll, { passive: true, capture: true });
264
+ window.addEventListener("resize", handleResize, { passive: true });
265
+ document.addEventListener("scroll", handleScroll, { passive: true, capture: true });
266
+
267
+ return () => {
268
+ window.removeEventListener("scroll", handleScroll, true);
269
+ window.removeEventListener("resize", handleResize);
270
+ document.removeEventListener("scroll", handleScroll, true);
271
+ };
171
272
  }, [isVisible, currentStep, steps, calculateTooltipPosition]);
172
273
 
173
274
  // Adiciona overlay e highlight ao elemento