@elogroup-sereduc/portal-aluno-tour 1.0.6 → 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,kDAkeX"}
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,50 +15,83 @@ 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
- // Recalcula o rect após possíveis mudanças de scroll
20
21
  const rect = element.getBoundingClientRect();
21
- const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
22
- const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
23
22
  const viewportWidth = window.innerWidth;
24
23
  const viewportHeight = window.innerHeight;
25
24
  // Tamanho estimado da tooltip
26
25
  const tooltipWidth = 384; // max-w-sm = 384px
27
- const tooltipHeight = 250; // altura estimada com conteúdo
28
- const spacing = 8; // espaçamento menor para ficar mais próximo
26
+ const tooltipHeight = 250; // altura estimada
27
+ const spacing = 8; // espaçamento próximo ao elemento
29
28
  let top = 0;
30
29
  let left = 0;
31
30
  let finalPosition = position;
32
- // Calcula posição base - sempre próxima ao elemento
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
33
66
  switch (position) {
34
67
  case "top":
35
- top = rect.top + scrollTop - spacing;
36
- left = rect.left + scrollLeft + rect.width / 2;
68
+ top = rect.top - spacing;
69
+ left = rect.left + rect.width / 2;
37
70
  break;
38
71
  case "bottom":
39
- top = rect.bottom + scrollTop + spacing;
40
- left = rect.left + scrollLeft + rect.width / 2;
72
+ top = rect.bottom + spacing;
73
+ left = rect.left + rect.width / 2;
41
74
  break;
42
75
  case "left":
43
- top = rect.top + scrollTop + rect.height / 2;
44
- left = rect.left + scrollLeft - spacing;
76
+ top = rect.top + rect.height / 2;
77
+ left = rect.left - spacing;
45
78
  break;
46
79
  case "right":
47
- top = rect.top + scrollTop + rect.height / 2;
48
- left = rect.right + scrollLeft + spacing;
80
+ top = rect.top + rect.height / 2;
81
+ left = rect.right + spacing;
49
82
  break;
50
83
  default:
51
- top = rect.bottom + scrollTop + spacing;
52
- left = rect.left + scrollLeft + rect.width / 2;
84
+ top = rect.bottom + spacing;
85
+ left = rect.left + rect.width / 2;
53
86
  finalPosition = "bottom";
54
87
  }
55
- // Ajusta posição apenas se necessário para não sair da viewport
56
- // Mas mantém o mais próximo possível do elemento
88
+ // Ajusta horizontalmente para tooltips top/bottom - mantém próximo ao elemento
57
89
  if (finalPosition === "bottom" || finalPosition === "top") {
58
- // Ajusta horizontalmente apenas se necessário, mantendo próximo ao centro do elemento
59
- const elementCenterX = rect.left + scrollLeft + rect.width / 2;
60
- const minLeft = scrollLeft + tooltipWidth / 2 + 8;
61
- const maxLeft = scrollLeft + viewportWidth - tooltipWidth / 2 - 8;
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
62
95
  if (elementCenterX < minLeft) {
63
96
  left = minLeft;
64
97
  }
@@ -68,31 +101,43 @@ export function Tour({ enabled, steps, initialStep = 0, options = {}, onExit, on
68
101
  else {
69
102
  left = elementCenterX; // Mantém centralizado no elemento
70
103
  }
71
- // Verifica se precisa mudar de posição vertical
104
+ // Verifica espaço vertical e ajusta posição se necessário
72
105
  if (finalPosition === "bottom") {
73
- const spaceBelow = viewportHeight - (rect.bottom - scrollTop);
74
- const spaceAbove = rect.top - scrollTop;
75
- if (spaceBelow < tooltipHeight + spacing && spaceAbove > spaceBelow) {
76
- // Muda para cima se houver mais espaço
77
- top = rect.top + scrollTop - spacing;
78
- finalPosition = "top";
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
+ }
79
117
  }
80
118
  }
81
119
  else if (finalPosition === "top") {
82
- const spaceAbove = rect.top - scrollTop;
83
- const spaceBelow = viewportHeight - (rect.bottom - scrollTop);
84
- if (spaceAbove < tooltipHeight + spacing && spaceBelow > spaceAbove) {
85
- // Muda para baixo se houver mais espaço
86
- top = rect.bottom + scrollTop + spacing;
87
- finalPosition = "bottom";
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
+ }
88
131
  }
89
132
  }
90
133
  }
134
+ // Ajusta verticalmente para tooltips left/right - mantém próximo ao elemento
91
135
  else if (finalPosition === "left" || finalPosition === "right") {
92
- // Ajusta verticalmente apenas se necessário
93
- const elementCenterY = rect.top + scrollTop + rect.height / 2;
94
- const minTop = scrollTop + tooltipHeight / 2 + 8;
95
- const maxTop = scrollTop + viewportHeight - tooltipHeight / 2 - 8;
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
96
141
  if (elementCenterY < minTop) {
97
142
  top = minTop;
98
143
  }
@@ -102,21 +147,33 @@ export function Tour({ enabled, steps, initialStep = 0, options = {}, onExit, on
102
147
  else {
103
148
  top = elementCenterY; // Mantém centralizado no elemento
104
149
  }
105
- // Verifica se precisa mudar de posição horizontal
150
+ // Verifica espaço horizontal e ajusta posição se necessário
106
151
  if (finalPosition === "left") {
107
- const spaceLeft = rect.left - scrollLeft;
108
- const spaceRight = viewportWidth - (rect.right - scrollLeft);
109
- if (spaceLeft < tooltipWidth + spacing && spaceRight > spaceLeft) {
110
- left = rect.right + scrollLeft + spacing;
111
- finalPosition = "right";
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
+ }
112
163
  }
113
164
  }
114
165
  else if (finalPosition === "right") {
115
- const spaceRight = viewportWidth - (rect.right - scrollLeft);
116
- const spaceLeft = rect.left - scrollLeft;
117
- if (spaceRight < tooltipWidth + spacing && spaceLeft > spaceRight) {
118
- left = rect.left + scrollLeft - spacing;
119
- finalPosition = "left";
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
+ }
120
177
  }
121
178
  }
122
179
  }
@@ -155,16 +212,33 @@ export function Tour({ enabled, steps, initialStep = 0, options = {}, onExit, on
155
212
  setHighlightedElement(element);
156
213
  // Scroll para o elemento
157
214
  element.scrollIntoView({ behavior: "smooth", block: "center" });
158
- // Calcula posição da tooltip após um delay para garantir que o scroll terminou
159
- // Usa um delay maior para garantir que o scroll terminou completamente
160
- setTimeout(() => {
161
- // Recalcula o rect após o scroll
215
+ // Função para calcular e atualizar posição
216
+ const updatePosition = () => {
162
217
  const updatedRect = element.getBoundingClientRect();
163
218
  if (updatedRect.width > 0 && updatedRect.height > 0) {
164
219
  const position = calculateTooltipPosition(element, step.position || "bottom");
165
220
  setTooltipPosition(position);
166
221
  }
167
- }, 400);
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
+ };
168
242
  }, [isVisible, currentStep, steps, calculateTooltipPosition]);
169
243
  // Adiciona overlay e highlight ao elemento
170
244
  useEffect(() => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elogroup-sereduc/portal-aluno-tour",
3
- "version": "1.0.6",
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,55 +34,88 @@ 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
- // Recalcula o rect após possíveis mudanças de scroll
39
40
  const rect = element.getBoundingClientRect();
40
- const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
41
- const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
42
41
  const viewportWidth = window.innerWidth;
43
42
  const viewportHeight = window.innerHeight;
44
43
 
45
44
  // Tamanho estimado da tooltip
46
45
  const tooltipWidth = 384; // max-w-sm = 384px
47
- const tooltipHeight = 250; // altura estimada com conteúdo
48
- const spacing = 8; // espaçamento menor para ficar mais próximo
46
+ const tooltipHeight = 250; // altura estimada
47
+ const spacing = 8; // espaçamento próximo ao elemento
49
48
 
50
49
  let top = 0;
51
50
  let left = 0;
52
51
  let finalPosition = position;
53
52
 
54
- // Calcula posição base - sempre próxima ao elemento
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
55
88
  switch (position) {
56
89
  case "top":
57
- top = rect.top + scrollTop - spacing;
58
- left = rect.left + scrollLeft + rect.width / 2;
90
+ top = rect.top - spacing;
91
+ left = rect.left + rect.width / 2;
59
92
  break;
60
93
  case "bottom":
61
- top = rect.bottom + scrollTop + spacing;
62
- left = rect.left + scrollLeft + rect.width / 2;
94
+ top = rect.bottom + spacing;
95
+ left = rect.left + rect.width / 2;
63
96
  break;
64
97
  case "left":
65
- top = rect.top + scrollTop + rect.height / 2;
66
- left = rect.left + scrollLeft - spacing;
98
+ top = rect.top + rect.height / 2;
99
+ left = rect.left - spacing;
67
100
  break;
68
101
  case "right":
69
- top = rect.top + scrollTop + rect.height / 2;
70
- left = rect.right + scrollLeft + spacing;
102
+ top = rect.top + rect.height / 2;
103
+ left = rect.right + spacing;
71
104
  break;
72
105
  default:
73
- top = rect.bottom + scrollTop + spacing;
74
- left = rect.left + scrollLeft + rect.width / 2;
106
+ top = rect.bottom + spacing;
107
+ left = rect.left + rect.width / 2;
75
108
  finalPosition = "bottom";
76
109
  }
77
110
 
78
- // Ajusta posição apenas se necessário para não sair da viewport
79
- // Mas mantém o mais próximo possível do elemento
111
+ // Ajusta horizontalmente para tooltips top/bottom - mantém próximo ao elemento
80
112
  if (finalPosition === "bottom" || finalPosition === "top") {
81
- // Ajusta horizontalmente apenas se necessário, mantendo próximo ao centro do elemento
82
- const elementCenterX = rect.left + scrollLeft + rect.width / 2;
83
- const minLeft = scrollLeft + tooltipWidth / 2 + 8;
84
- const maxLeft = scrollLeft + viewportWidth - tooltipWidth / 2 - 8;
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;
85
117
 
118
+ // Mantém o mais próximo possível do centro do elemento
86
119
  if (elementCenterX < minLeft) {
87
120
  left = minLeft;
88
121
  } else if (elementCenterX > maxLeft) {
@@ -91,32 +124,41 @@ export function Tour({
91
124
  left = elementCenterX; // Mantém centralizado no elemento
92
125
  }
93
126
 
94
- // Verifica se precisa mudar de posição vertical
127
+ // Verifica espaço vertical e ajusta posição se necessário
95
128
  if (finalPosition === "bottom") {
96
- const spaceBelow = viewportHeight - (rect.bottom - scrollTop);
97
- const spaceAbove = rect.top - scrollTop;
98
-
99
- if (spaceBelow < tooltipHeight + spacing && spaceAbove > spaceBelow) {
100
- // Muda para cima se houver mais espaço
101
- top = rect.top + scrollTop - spacing;
102
- finalPosition = "top";
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
+ }
103
139
  }
104
140
  } else if (finalPosition === "top") {
105
- const spaceAbove = rect.top - scrollTop;
106
- const spaceBelow = viewportHeight - (rect.bottom - scrollTop);
107
-
108
- if (spaceAbove < tooltipHeight + spacing && spaceBelow > spaceAbove) {
109
- // Muda para baixo se houver mais espaço
110
- top = rect.bottom + scrollTop + spacing;
111
- finalPosition = "bottom";
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
+ }
112
151
  }
113
152
  }
114
- } else if (finalPosition === "left" || finalPosition === "right") {
115
- // Ajusta verticalmente apenas se necessário
116
- const elementCenterY = rect.top + scrollTop + rect.height / 2;
117
- const minTop = scrollTop + tooltipHeight / 2 + 8;
118
- const maxTop = scrollTop + viewportHeight - tooltipHeight / 2 - 8;
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;
119
160
 
161
+ // Mantém o mais próximo possível do centro do elemento
120
162
  if (elementCenterY < minTop) {
121
163
  top = minTop;
122
164
  } else if (elementCenterY > maxTop) {
@@ -125,22 +167,30 @@ export function Tour({
125
167
  top = elementCenterY; // Mantém centralizado no elemento
126
168
  }
127
169
 
128
- // Verifica se precisa mudar de posição horizontal
170
+ // Verifica espaço horizontal e ajusta posição se necessário
129
171
  if (finalPosition === "left") {
130
- const spaceLeft = rect.left - scrollLeft;
131
- const spaceRight = viewportWidth - (rect.right - scrollLeft);
132
-
133
- if (spaceLeft < tooltipWidth + spacing && spaceRight > spaceLeft) {
134
- left = rect.right + scrollLeft + spacing;
135
- finalPosition = "right";
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
+ }
136
182
  }
137
183
  } else if (finalPosition === "right") {
138
- const spaceRight = viewportWidth - (rect.right - scrollLeft);
139
- const spaceLeft = rect.left - scrollLeft;
140
-
141
- if (spaceRight < tooltipWidth + spacing && spaceLeft > spaceRight) {
142
- left = rect.left + scrollLeft - spacing;
143
- finalPosition = "left";
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
+ }
144
194
  }
145
195
  }
146
196
  }
@@ -187,16 +237,38 @@ export function Tour({
187
237
  // Scroll para o elemento
188
238
  element.scrollIntoView({ behavior: "smooth", block: "center" });
189
239
 
190
- // Calcula posição da tooltip após um delay para garantir que o scroll terminou
191
- // Usa um delay maior para garantir que o scroll terminou completamente
192
- setTimeout(() => {
193
- // Recalcula o rect após o scroll
240
+ // Função para calcular e atualizar posição
241
+ const updatePosition = () => {
194
242
  const updatedRect = element.getBoundingClientRect();
195
243
  if (updatedRect.width > 0 && updatedRect.height > 0) {
196
244
  const position = calculateTooltipPosition(element, step.position || "bottom");
197
245
  setTooltipPosition(position);
198
246
  }
199
- }, 400);
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
+ };
200
272
  }, [isVisible, currentStep, steps, calculateTooltipPosition]);
201
273
 
202
274
  // Adiciona overlay e highlight ao elemento