@elogroup-sereduc/portal-aluno-tour 1.0.4 → 1.0.6

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 CHANGED
@@ -10,9 +10,23 @@ npm install @elogroup-sereduc/portal-aluno-tour
10
10
 
11
11
  ## Configuração do Tailwind
12
12
 
13
- Este pacote usa `@elogroup-sereduc/portal-aluno-tailwind-config` com o prefixo `portal-tour:`.
13
+ Este pacote usa `@elogroup-sereduc/portal-aluno-tailwind-config` com o prefixo `tour:`.
14
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.
15
+ O CSS do Tailwind é gerado automaticamente durante o build e está disponível em `dist/tour.css`.
16
+
17
+ ### Importar o CSS
18
+
19
+ Você precisa importar o CSS do pacote no seu projeto:
20
+
21
+ ```tsx
22
+ import "@elogroup-sereduc/portal-aluno-tour/dist/tour.css";
23
+ ```
24
+
25
+ Ou no seu arquivo CSS principal:
26
+
27
+ ```css
28
+ @import "@elogroup-sereduc/portal-aluno-tour/dist/tour.css";
29
+ ```
16
30
 
17
31
  ## Uso
18
32
 
@@ -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,kDAkeX"}
@@ -16,19 +16,20 @@ export function Tour({ enabled, steps, initialStep = 0, options = {}, onExit, on
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
18
  const calculateTooltipPosition = useCallback((element, position = "bottom") => {
19
+ // Recalcula o rect após possíveis mudanças de scroll
19
20
  const rect = element.getBoundingClientRect();
20
21
  const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
21
22
  const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
22
23
  const viewportWidth = window.innerWidth;
23
24
  const viewportHeight = window.innerHeight;
24
- // Tamanho estimado da tooltip (ajuste conforme necessário)
25
+ // Tamanho estimado da tooltip
25
26
  const tooltipWidth = 384; // max-w-sm = 384px
26
- const tooltipHeight = 200; // altura estimada
27
- const spacing = 16; // espaçamento entre elemento e tooltip
27
+ const tooltipHeight = 250; // altura estimada com conteúdo
28
+ const spacing = 8; // espaçamento menor para ficar mais próximo
28
29
  let top = 0;
29
30
  let left = 0;
30
31
  let finalPosition = position;
31
- // Calcula posição base
32
+ // Calcula posição base - sempre próxima ao elemento
32
33
  switch (position) {
33
34
  case "top":
34
35
  top = rect.top + scrollTop - spacing;
@@ -51,48 +52,69 @@ export function Tour({ enabled, steps, initialStep = 0, options = {}, onExit, on
51
52
  left = rect.left + scrollLeft + rect.width / 2;
52
53
  finalPosition = "bottom";
53
54
  }
54
- // Ajusta posição se a tooltip sair da viewport
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
55
57
  if (finalPosition === "bottom" || finalPosition === "top") {
56
- // Ajusta horizontalmente
57
- if (left - tooltipWidth / 2 < scrollLeft) {
58
- left = scrollLeft + tooltipWidth / 2 + 16;
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;
62
+ if (elementCenterX < minLeft) {
63
+ left = minLeft;
59
64
  }
60
- else if (left + tooltipWidth / 2 > scrollLeft + viewportWidth) {
61
- left = scrollLeft + viewportWidth - tooltipWidth / 2 - 16;
65
+ else if (elementCenterX > maxLeft) {
66
+ left = maxLeft;
62
67
  }
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;
68
+ else {
69
+ left = elementCenterX; // Mantém centralizado no elemento
70
+ }
71
+ // Verifica se precisa mudar de posição vertical
72
+ 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;
67
78
  finalPosition = "top";
68
79
  }
69
80
  }
70
- // Se não couber em cima, tenta embaixo
71
- else if (finalPosition === "top" && top - tooltipHeight < scrollTop) {
72
- if (rect.bottom + tooltipHeight < scrollTop + viewportHeight) {
81
+ 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
73
86
  top = rect.bottom + scrollTop + spacing;
74
87
  finalPosition = "bottom";
75
88
  }
76
89
  }
77
90
  }
78
91
  else if (finalPosition === "left" || finalPosition === "right") {
79
- // Ajusta verticalmente
80
- if (top - tooltipHeight / 2 < scrollTop) {
81
- top = scrollTop + tooltipHeight / 2 + 16;
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;
96
+ if (elementCenterY < minTop) {
97
+ top = minTop;
98
+ }
99
+ else if (elementCenterY > maxTop) {
100
+ top = maxTop;
82
101
  }
83
- else if (top + tooltipHeight / 2 > scrollTop + viewportHeight) {
84
- top = scrollTop + viewportHeight - tooltipHeight / 2 - 16;
102
+ else {
103
+ top = elementCenterY; // Mantém centralizado no elemento
85
104
  }
86
- // Se não couber à esquerda, tenta à direita
87
- if (finalPosition === "left" && left - tooltipWidth < scrollLeft) {
88
- if (rect.right + tooltipWidth < scrollLeft + viewportWidth) {
105
+ // Verifica se precisa mudar de posição horizontal
106
+ if (finalPosition === "left") {
107
+ const spaceLeft = rect.left - scrollLeft;
108
+ const spaceRight = viewportWidth - (rect.right - scrollLeft);
109
+ if (spaceLeft < tooltipWidth + spacing && spaceRight > spaceLeft) {
89
110
  left = rect.right + scrollLeft + spacing;
90
111
  finalPosition = "right";
91
112
  }
92
113
  }
93
- // Se não couber à direita, tenta à esquerda
94
- else if (finalPosition === "right" && left + tooltipWidth > scrollLeft + viewportWidth) {
95
- if (rect.left - tooltipWidth > scrollLeft) {
114
+ else if (finalPosition === "right") {
115
+ const spaceRight = viewportWidth - (rect.right - scrollLeft);
116
+ const spaceLeft = rect.left - scrollLeft;
117
+ if (spaceRight < tooltipWidth + spacing && spaceLeft > spaceRight) {
96
118
  left = rect.left + scrollLeft - spacing;
97
119
  finalPosition = "left";
98
120
  }
@@ -133,11 +155,16 @@ export function Tour({ enabled, steps, initialStep = 0, options = {}, onExit, on
133
155
  setHighlightedElement(element);
134
156
  // Scroll para o elemento
135
157
  element.scrollIntoView({ behavior: "smooth", block: "center" });
136
- // Calcula posição da tooltip após um pequeno delay para garantir que o scroll terminou
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
137
160
  setTimeout(() => {
138
- const position = calculateTooltipPosition(element, step.position || "bottom");
139
- setTooltipPosition(position);
140
- }, 300);
161
+ // Recalcula o rect após o scroll
162
+ const updatedRect = element.getBoundingClientRect();
163
+ if (updatedRect.width > 0 && updatedRect.height > 0) {
164
+ const position = calculateTooltipPosition(element, step.position || "bottom");
165
+ setTooltipPosition(position);
166
+ }
167
+ }, 400);
141
168
  }, [isVisible, currentStep, steps, calculateTooltipPosition]);
142
169
  // Adiciona overlay e highlight ao elemento
143
170
  useEffect(() => {
@@ -247,7 +274,7 @@ export function Tour({ enabled, steps, initialStep = 0, options = {}, onExit, on
247
274
  backgroundColor: "rgba(0, 0, 0, 0.6)",
248
275
  zIndex: 9998,
249
276
  pointerEvents: exitOnOverlayClick ? "auto" : "none",
250
- } }), tooltipPosition && currentStepData && highlightedElement && (_jsxs("div", { ref: tooltipRef, className: "portal-tour:max-w-sm", style: {
277
+ } }), tooltipPosition && currentStepData && highlightedElement && (_jsxs("div", { ref: tooltipRef, className: "tour:max-w-sm", style: {
251
278
  position: "fixed",
252
279
  top: tooltipPosition.position === "bottom" || tooltipPosition.position === "left" || tooltipPosition.position === "right"
253
280
  ? `${tooltipPosition.top}px`
@@ -260,24 +287,24 @@ export function Tour({ enabled, steps, initialStep = 0, options = {}, onExit, on
260
287
  ? "translate(0, -50%)"
261
288
  : "translate(-50%, 0)",
262
289
  zIndex: 10001,
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: {
290
+ }, children: [_jsxs("div", { className: "tour:bg-white tour:rounded-lg tour:shadow-xl tour:p-6 tour:relative", children: [_jsx("button", { onClick: handleExit, 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", "aria-label": "Fechar tour", children: _jsx(HiXMark, { className: "tour:w-5 tour:h-5 tour:text-gray-500" }) }), currentStepData.title && (_jsx("h3", { className: "tour:text-lg tour:font-semibold tour:text-gray-900 tour:mb-2 tour:pr-6", children: currentStepData.title })), _jsx("p", { className: "tour:text-gray-700 tour:mb-4", children: currentStepData.intro }), showProgress && (_jsxs("div", { className: "tour:mb-4", children: [_jsx("div", { className: "tour:w-full tour:bg-gray-200 tour:rounded-full tour:h-2", children: _jsx("div", { className: "tour:bg-brand-primary tour:h-2 tour:rounded-full tour:transition-all tour:duration-300", style: { width: `${progress}%` } }) }), _jsxs("p", { className: "tour:text-xs tour:text-gray-500 tour:mt-1 tour:text-center", children: [currentStep + 1, " de ", steps.length] })] })), showBullets && (_jsx("div", { className: "tour:flex tour:justify-center tour:gap-1 tour:mb-4", children: steps.map((_, index) => (_jsx("button", { onClick: () => setCurrentStep(index), className: `tour:w-2 tour:h-2 tour:rounded-full tour:transition-all ${index === currentStep
291
+ ? "tour:bg-brand-primary tour:w-6"
292
+ : "tour:bg-gray-300 tour:hover:bg-gray-400"}`, "aria-label": `Ir para passo ${index + 1}` }, index))) })), _jsxs("div", { className: "tour:flex tour:justify-between tour:items-center tour:gap-2", children: [_jsx("div", { className: "tour:flex tour:gap-2", children: !isFirstStep && (_jsx(Button, { variant: "bordered", onPress: handlePrev, startContent: _jsx(HiChevronLeft, { className: "tour:w-4 tour:h-4" }), children: prevLabel })) }), _jsxs("div", { className: "tour:flex 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: "tour:w-4 tour:h-4" }) : undefined, children: isLastStep ? doneLabel : nextLabel })] })] })] }), tooltipPosition.position === "bottom" && (_jsx("div", { className: "tour:absolute tour:w-0 tour:h-0 tour:border-8 tour:border-transparent", style: {
266
293
  top: "-16px",
267
294
  left: "50%",
268
295
  transform: "translateX(-50%)",
269
296
  borderColor: "transparent transparent white transparent",
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: {
297
+ } })), tooltipPosition.position === "top" && (_jsx("div", { className: "tour:absolute tour:w-0 tour:h-0 tour:border-8 tour:border-transparent", style: {
271
298
  bottom: "-16px",
272
299
  left: "50%",
273
300
  transform: "translateX(-50%)",
274
301
  borderColor: "white transparent transparent transparent",
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: {
302
+ } })), tooltipPosition.position === "right" && (_jsx("div", { className: "tour:absolute tour:w-0 tour:h-0 tour:border-8 tour:border-transparent", style: {
276
303
  left: "-16px",
277
304
  top: "50%",
278
305
  transform: "translateY(-50%)",
279
306
  borderColor: "transparent white transparent transparent",
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: {
307
+ } })), tooltipPosition.position === "left" && (_jsx("div", { className: "tour:absolute tour:w-0 tour:h-0 tour:border-8 tour:border-transparent", style: {
281
308
  right: "-16px",
282
309
  top: "50%",
283
310
  transform: "translateY(-50%)",
package/dist/tour.css ADDED
@@ -0,0 +1,566 @@
1
+ /*! tailwindcss v4.1.17 | MIT License | https://tailwindcss.com */
2
+ @layer properties;
3
+ @layer theme, base, components, utilities;
4
+ @layer theme {
5
+ :root, :host {
6
+ --tour-color-gray-100: oklch(96.7% 0.003 264.542);
7
+ --tour-color-gray-200: oklch(92.8% 0.006 264.531);
8
+ --tour-color-gray-300: oklch(87.2% 0.01 258.338);
9
+ --tour-color-gray-400: oklch(70.7% 0.022 261.325);
10
+ --tour-color-gray-500: oklch(55.1% 0.027 264.364);
11
+ --tour-color-gray-700: oklch(37.3% 0.034 259.733);
12
+ --tour-color-gray-900: oklch(21% 0.034 264.665);
13
+ --tour-color-white: #fff;
14
+ --tour-spacing: 0.25rem;
15
+ --tour-container-sm: 24rem;
16
+ --tour-text-xs: 0.75rem;
17
+ --tour-text-xs--line-height: calc(1 / 0.75);
18
+ --tour-text-lg: 1.125rem;
19
+ --tour-text-lg--line-height: calc(1.75 / 1.125);
20
+ --tour-font-weight-semibold: 600;
21
+ --tour-radius-lg: 0.5rem;
22
+ }
23
+ }
24
+ @layer base {
25
+ *, ::after, ::before, ::backdrop, ::file-selector-button {
26
+ box-sizing: border-box;
27
+ margin: 0;
28
+ padding: 0;
29
+ border: 0 solid;
30
+ }
31
+ html, :host {
32
+ line-height: 1.5;
33
+ -webkit-text-size-adjust: 100%;
34
+ tab-size: 4;
35
+ font-family: var(--font-sans, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"), Inter, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, sans-serif;
36
+ font-feature-settings: normal;
37
+ font-variation-settings: normal;
38
+ -webkit-tap-highlight-color: transparent;
39
+ }
40
+ hr {
41
+ height: 0;
42
+ color: inherit;
43
+ border-top-width: 1px;
44
+ }
45
+ abbr:where([title]) {
46
+ -webkit-text-decoration: underline dotted;
47
+ text-decoration: underline dotted;
48
+ }
49
+ h1, h2, h3, h4, h5, h6 {
50
+ font-size: inherit;
51
+ font-weight: inherit;
52
+ }
53
+ a {
54
+ color: inherit;
55
+ -webkit-text-decoration: inherit;
56
+ text-decoration: inherit;
57
+ }
58
+ b, strong {
59
+ font-weight: bolder;
60
+ }
61
+ code, kbd, samp, pre {
62
+ font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace), Fira Code, Fira Mono, Courier New, monospace;
63
+ font-feature-settings: normal;
64
+ font-variation-settings: normal;
65
+ font-size: 1em;
66
+ }
67
+ small {
68
+ font-size: 80%;
69
+ }
70
+ sub, sup {
71
+ font-size: 75%;
72
+ line-height: 0;
73
+ position: relative;
74
+ vertical-align: baseline;
75
+ }
76
+ sub {
77
+ bottom: -0.25em;
78
+ }
79
+ sup {
80
+ top: -0.5em;
81
+ }
82
+ table {
83
+ text-indent: 0;
84
+ border-color: inherit;
85
+ border-collapse: collapse;
86
+ }
87
+ :-moz-focusring {
88
+ outline: auto;
89
+ }
90
+ progress {
91
+ vertical-align: baseline;
92
+ }
93
+ summary {
94
+ display: list-item;
95
+ }
96
+ ol, ul, menu {
97
+ list-style: none;
98
+ }
99
+ img, svg, video, canvas, audio, iframe, embed, object {
100
+ display: block;
101
+ vertical-align: middle;
102
+ }
103
+ img, video {
104
+ max-width: 100%;
105
+ height: auto;
106
+ }
107
+ button, input, select, optgroup, textarea, ::file-selector-button {
108
+ font: inherit;
109
+ font-feature-settings: inherit;
110
+ font-variation-settings: inherit;
111
+ letter-spacing: inherit;
112
+ color: inherit;
113
+ border-radius: 0;
114
+ background-color: transparent;
115
+ opacity: 1;
116
+ }
117
+ :where(select:is([multiple], [size])) optgroup {
118
+ font-weight: bolder;
119
+ }
120
+ :where(select:is([multiple], [size])) optgroup option {
121
+ padding-inline-start: 20px;
122
+ }
123
+ ::file-selector-button {
124
+ margin-inline-end: 4px;
125
+ }
126
+ ::placeholder {
127
+ opacity: 1;
128
+ }
129
+ @supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) {
130
+ ::placeholder {
131
+ color: currentcolor;
132
+ @supports (color: color-mix(in lab, red, red)) {
133
+ color: color-mix(in oklab, currentcolor 50%, transparent);
134
+ }
135
+ }
136
+ }
137
+ textarea {
138
+ resize: vertical;
139
+ }
140
+ ::-webkit-search-decoration {
141
+ -webkit-appearance: none;
142
+ }
143
+ ::-webkit-date-and-time-value {
144
+ min-height: 1lh;
145
+ text-align: inherit;
146
+ }
147
+ ::-webkit-datetime-edit {
148
+ display: inline-flex;
149
+ }
150
+ ::-webkit-datetime-edit-fields-wrapper {
151
+ padding: 0;
152
+ }
153
+ ::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field {
154
+ padding-block: 0;
155
+ }
156
+ ::-webkit-calendar-picker-indicator {
157
+ line-height: 1;
158
+ }
159
+ :-moz-ui-invalid {
160
+ box-shadow: none;
161
+ }
162
+ button, input:where([type="button"], [type="reset"], [type="submit"]), ::file-selector-button {
163
+ appearance: button;
164
+ }
165
+ ::-webkit-inner-spin-button, ::-webkit-outer-spin-button {
166
+ height: auto;
167
+ }
168
+ [hidden]:where(:not([hidden="until-found"])) {
169
+ display: none !important;
170
+ }
171
+ }
172
+ @layer utilities {
173
+ .tour\:absolute {
174
+ position: absolute;
175
+ }
176
+ .tour\:relative {
177
+ position: relative;
178
+ }
179
+ .tour\:top-2 {
180
+ top: calc(var(--tour-spacing) * 2);
181
+ }
182
+ .tour\:right-2 {
183
+ right: calc(var(--tour-spacing) * 2);
184
+ }
185
+ .tour\:z-10 {
186
+ z-index: 10;
187
+ }
188
+ .tour\:mt-1 {
189
+ margin-top: calc(var(--tour-spacing) * 1);
190
+ }
191
+ .tour\:mb-2 {
192
+ margin-bottom: calc(var(--tour-spacing) * 2);
193
+ }
194
+ .tour\:mb-4 {
195
+ margin-bottom: calc(var(--tour-spacing) * 4);
196
+ }
197
+ .tour\:flex {
198
+ display: flex;
199
+ }
200
+ .tour\:h-0 {
201
+ height: calc(var(--tour-spacing) * 0);
202
+ }
203
+ .tour\:h-2 {
204
+ height: calc(var(--tour-spacing) * 2);
205
+ }
206
+ .tour\:h-4 {
207
+ height: calc(var(--tour-spacing) * 4);
208
+ }
209
+ .tour\:h-5 {
210
+ height: calc(var(--tour-spacing) * 5);
211
+ }
212
+ .tour\:w-0 {
213
+ width: calc(var(--tour-spacing) * 0);
214
+ }
215
+ .tour\:w-2 {
216
+ width: calc(var(--tour-spacing) * 2);
217
+ }
218
+ .tour\:w-4 {
219
+ width: calc(var(--tour-spacing) * 4);
220
+ }
221
+ .tour\:w-5 {
222
+ width: calc(var(--tour-spacing) * 5);
223
+ }
224
+ .tour\:w-6 {
225
+ width: calc(var(--tour-spacing) * 6);
226
+ }
227
+ .tour\:w-full {
228
+ width: 100%;
229
+ }
230
+ .tour\:max-w-sm {
231
+ max-width: var(--tour-container-sm);
232
+ }
233
+ .tour\:items-center {
234
+ align-items: center;
235
+ }
236
+ .tour\:justify-between {
237
+ justify-content: space-between;
238
+ }
239
+ .tour\:justify-center {
240
+ justify-content: center;
241
+ }
242
+ .tour\:gap-1 {
243
+ gap: calc(var(--tour-spacing) * 1);
244
+ }
245
+ .tour\:gap-2 {
246
+ gap: calc(var(--tour-spacing) * 2);
247
+ }
248
+ .tour\:rounded-full {
249
+ border-radius: calc(infinity * 1px);
250
+ }
251
+ .tour\:rounded-lg {
252
+ border-radius: var(--tour-radius-lg);
253
+ }
254
+ .tour\:border-8 {
255
+ border-style: var(--tw-border-style);
256
+ border-width: 8px;
257
+ }
258
+ .tour\:border-transparent {
259
+ border-color: transparent;
260
+ }
261
+ .tour\:bg-brand-primary {
262
+ background-color: var(--brand-primary);
263
+ }
264
+ .tour\:bg-gray-200 {
265
+ background-color: var(--tour-color-gray-200);
266
+ }
267
+ .tour\:bg-gray-300 {
268
+ background-color: var(--tour-color-gray-300);
269
+ }
270
+ .tour\:bg-white {
271
+ background-color: var(--tour-color-white);
272
+ }
273
+ .tour\:p-1 {
274
+ padding: calc(var(--tour-spacing) * 1);
275
+ }
276
+ .tour\:p-6 {
277
+ padding: calc(var(--tour-spacing) * 6);
278
+ }
279
+ .tour\:pr-6 {
280
+ padding-right: calc(var(--tour-spacing) * 6);
281
+ }
282
+ .tour\:text-center {
283
+ text-align: center;
284
+ }
285
+ .tour\:text-lg {
286
+ font-size: var(--tour-text-lg);
287
+ line-height: var(--tw-leading, var(--tour-text-lg--line-height));
288
+ }
289
+ .tour\:text-xs {
290
+ font-size: var(--tour-text-xs);
291
+ line-height: var(--tw-leading, var(--tour-text-xs--line-height));
292
+ }
293
+ .tour\:font-semibold {
294
+ --tw-font-weight: var(--tour-font-weight-semibold);
295
+ font-weight: var(--tour-font-weight-semibold);
296
+ }
297
+ .tour\:text-gray-500 {
298
+ color: var(--tour-color-gray-500);
299
+ }
300
+ .tour\:text-gray-700 {
301
+ color: var(--tour-color-gray-700);
302
+ }
303
+ .tour\:text-gray-900 {
304
+ color: var(--tour-color-gray-900);
305
+ }
306
+ .tour\:shadow-xl {
307
+ --tw-shadow: 0 20px 25px -5px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 8px 10px -6px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
308
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
309
+ }
310
+ .tour\:transition-all {
311
+ transition-property: all;
312
+ transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
313
+ transition-duration: var(--tw-duration, var(--default-transition-duration));
314
+ }
315
+ .tour\:transition-colors {
316
+ transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to;
317
+ transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
318
+ transition-duration: var(--tw-duration, var(--default-transition-duration));
319
+ }
320
+ .tour\:duration-300 {
321
+ --tw-duration: 300ms;
322
+ transition-duration: 300ms;
323
+ }
324
+ .tour\:hover\:bg-gray-100 {
325
+ &:hover {
326
+ @media (hover: hover) {
327
+ background-color: var(--tour-color-gray-100);
328
+ }
329
+ }
330
+ }
331
+ .tour\:hover\:bg-gray-400 {
332
+ &:hover {
333
+ @media (hover: hover) {
334
+ background-color: var(--tour-color-gray-400);
335
+ }
336
+ }
337
+ }
338
+ }
339
+ @layer base {
340
+ :root, [data-theme] {
341
+ color: hsl(var(--heroui-foreground));
342
+ background-color: hsl(var(--heroui-background));
343
+ }
344
+ }
345
+ @layer base {
346
+ :root, [data-theme=light] {
347
+ color-scheme: light;
348
+ --heroui-background: 0 0% 100%;
349
+ --heroui-foreground-50: 0 0% 98.04%;
350
+ --heroui-foreground-100: 240 4.76% 95.88%;
351
+ --heroui-foreground-200: 240 5.88% 90%;
352
+ --heroui-foreground-300: 240 4.88% 83.92%;
353
+ --heroui-foreground-400: 240 5.03% 64.9%;
354
+ --heroui-foreground-500: 240 3.83% 46.08%;
355
+ --heroui-foreground-600: 240 5.2% 33.92%;
356
+ --heroui-foreground-700: 240 5.26% 26.08%;
357
+ --heroui-foreground-800: 240 3.7% 15.88%;
358
+ --heroui-foreground-900: 240 5.88% 10%;
359
+ --heroui-foreground: 201.81999999999994 24.44% 8.82%;
360
+ --heroui-divider: 0 0% 6.67%;
361
+ --heroui-focus: 212.01999999999998 100% 46.67%;
362
+ --heroui-overlay: 0 0% 0%;
363
+ --heroui-content1: 0 0% 100%;
364
+ --heroui-content1-foreground: 201.81999999999994 24.44% 8.82%;
365
+ --heroui-content2: 240 4.76% 95.88%;
366
+ --heroui-content2-foreground: 240 3.7% 15.88%;
367
+ --heroui-content3: 240 5.88% 90%;
368
+ --heroui-content3-foreground: 240 5.26% 26.08%;
369
+ --heroui-content4: 240 4.88% 83.92%;
370
+ --heroui-content4-foreground: 240 5.2% 33.92%;
371
+ --heroui-default-50: 0 0% 98.04%;
372
+ --heroui-default-100: 240 4.76% 95.88%;
373
+ --heroui-default-200: 240 5.88% 90%;
374
+ --heroui-default-300: 240 4.88% 83.92%;
375
+ --heroui-default-400: 240 5.03% 64.9%;
376
+ --heroui-default-500: 240 3.83% 46.08%;
377
+ --heroui-default-600: 240 5.2% 33.92%;
378
+ --heroui-default-700: 240 5.26% 26.08%;
379
+ --heroui-default-800: 240 3.7% 15.88%;
380
+ --heroui-default-900: 240 5.88% 10%;
381
+ --heroui-default-foreground: 0 0% 0%;
382
+ --heroui-default: 240 4.88% 83.92%;
383
+ --heroui-primary-50: 212.5 92.31% 94.9%;
384
+ --heroui-primary-100: 211.84000000000003 92.45% 89.61%;
385
+ --heroui-primary-200: 211.84000000000003 92.45% 79.22%;
386
+ --heroui-primary-300: 212.24 92.45% 68.82%;
387
+ --heroui-primary-400: 212.14 92.45% 58.43%;
388
+ --heroui-primary-500: 212.01999999999998 100% 46.67%;
389
+ --heroui-primary-600: 212.14 100% 38.43%;
390
+ --heroui-primary-700: 212.24 100% 28.82%;
391
+ --heroui-primary-800: 211.84000000000003 100% 19.22%;
392
+ --heroui-primary-900: 211.84000000000003 100% 9.61%;
393
+ --heroui-primary-foreground: 0 0% 100%;
394
+ --heroui-primary: 212.01999999999998 100% 46.67%;
395
+ --heroui-secondary-50: 270 61.54% 94.9%;
396
+ --heroui-secondary-100: 270 59.26% 89.41%;
397
+ --heroui-secondary-200: 270 59.26% 78.82%;
398
+ --heroui-secondary-300: 270 59.26% 68.24%;
399
+ --heroui-secondary-400: 270 59.26% 57.65%;
400
+ --heroui-secondary-500: 270 66.67% 47.06%;
401
+ --heroui-secondary-600: 270 66.67% 37.65%;
402
+ --heroui-secondary-700: 270 66.67% 28.24%;
403
+ --heroui-secondary-800: 270 66.67% 18.82%;
404
+ --heroui-secondary-900: 270 66.67% 9.41%;
405
+ --heroui-secondary-foreground: 0 0% 100%;
406
+ --heroui-secondary: 270 66.67% 47.06%;
407
+ --heroui-success-50: 146.66999999999996 64.29% 94.51%;
408
+ --heroui-success-100: 145.71000000000004 61.4% 88.82%;
409
+ --heroui-success-200: 146.2 61.74% 77.45%;
410
+ --heroui-success-300: 145.78999999999996 62.57% 66.47%;
411
+ --heroui-success-400: 146.01 62.45% 55.1%;
412
+ --heroui-success-500: 145.96000000000004 79.46% 43.92%;
413
+ --heroui-success-600: 146.01 79.89% 35.1%;
414
+ --heroui-success-700: 145.78999999999996 79.26% 26.47%;
415
+ --heroui-success-800: 146.2 79.78% 17.45%;
416
+ --heroui-success-900: 145.71000000000004 77.78% 8.82%;
417
+ --heroui-success-foreground: 0 0% 0%;
418
+ --heroui-success: 145.96000000000004 79.46% 43.92%;
419
+ --heroui-warning-50: 54.55000000000001 91.67% 95.29%;
420
+ --heroui-warning-100: 37.139999999999986 91.3% 90.98%;
421
+ --heroui-warning-200: 37.139999999999986 91.3% 81.96%;
422
+ --heroui-warning-300: 36.95999999999998 91.24% 73.14%;
423
+ --heroui-warning-400: 37.00999999999999 91.26% 64.12%;
424
+ --heroui-warning-500: 37.02999999999997 91.27% 55.1%;
425
+ --heroui-warning-600: 37.00999999999999 74.22% 44.12%;
426
+ --heroui-warning-700: 36.95999999999998 73.96% 33.14%;
427
+ --heroui-warning-800: 37.139999999999986 75% 21.96%;
428
+ --heroui-warning-900: 37.139999999999986 75% 10.98%;
429
+ --heroui-warning-foreground: 0 0% 0%;
430
+ --heroui-warning: 37.02999999999997 91.27% 55.1%;
431
+ --heroui-danger-50: 339.13 92% 95.1%;
432
+ --heroui-danger-100: 340 91.84% 90.39%;
433
+ --heroui-danger-200: 339.3299999999999 90% 80.39%;
434
+ --heroui-danger-300: 339.11 90.6% 70.78%;
435
+ --heroui-danger-400: 339 90% 60.78%;
436
+ --heroui-danger-500: 339.20000000000005 90.36% 51.18%;
437
+ --heroui-danger-600: 339 86.54% 40.78%;
438
+ --heroui-danger-700: 339.11 85.99% 30.78%;
439
+ --heroui-danger-800: 339.3299999999999 86.54% 20.39%;
440
+ --heroui-danger-900: 340 84.91% 10.39%;
441
+ --heroui-danger-foreground: 0 0% 100%;
442
+ --heroui-danger: 339.20000000000005 90.36% 51.18%;
443
+ --heroui-divider-weight: 1px;
444
+ --heroui-disabled-opacity: .5;
445
+ --heroui-font-size-tiny: 0.75rem;
446
+ --heroui-font-size-small: 0.875rem;
447
+ --heroui-font-size-medium: 1rem;
448
+ --heroui-font-size-large: 1.125rem;
449
+ --heroui-line-height-tiny: 1rem;
450
+ --heroui-line-height-small: 1.25rem;
451
+ --heroui-line-height-medium: 1.5rem;
452
+ --heroui-line-height-large: 1.75rem;
453
+ --heroui-radius-small: 8px;
454
+ --heroui-radius-medium: 12px;
455
+ --heroui-radius-large: 14px;
456
+ --heroui-border-width-small: 1px;
457
+ --heroui-border-width-medium: 2px;
458
+ --heroui-border-width-large: 3px;
459
+ --heroui-box-shadow-small: 0px 0px 5px 0px rgb(0 0 0 / 0.02), 0px 2px 10px 0px rgb(0 0 0 / 0.06), 0px 0px 1px 0px rgb(0 0 0 / 0.3);
460
+ --heroui-box-shadow-medium: 0px 0px 15px 0px rgb(0 0 0 / 0.03), 0px 2px 30px 0px rgb(0 0 0 / 0.08), 0px 0px 1px 0px rgb(0 0 0 / 0.3);
461
+ --heroui-box-shadow-large: 0px 0px 30px 0px rgb(0 0 0 / 0.04), 0px 30px 60px 0px rgb(0 0 0 / 0.12), 0px 0px 1px 0px rgb(0 0 0 / 0.3);
462
+ --heroui-hover-opacity: .8;
463
+ }
464
+ }
465
+ @property --tw-border-style {
466
+ syntax: "*";
467
+ inherits: false;
468
+ initial-value: solid;
469
+ }
470
+ @property --tw-font-weight {
471
+ syntax: "*";
472
+ inherits: false;
473
+ }
474
+ @property --tw-shadow {
475
+ syntax: "*";
476
+ inherits: false;
477
+ initial-value: 0 0 #0000;
478
+ }
479
+ @property --tw-shadow-color {
480
+ syntax: "*";
481
+ inherits: false;
482
+ }
483
+ @property --tw-shadow-alpha {
484
+ syntax: "<percentage>";
485
+ inherits: false;
486
+ initial-value: 100%;
487
+ }
488
+ @property --tw-inset-shadow {
489
+ syntax: "*";
490
+ inherits: false;
491
+ initial-value: 0 0 #0000;
492
+ }
493
+ @property --tw-inset-shadow-color {
494
+ syntax: "*";
495
+ inherits: false;
496
+ }
497
+ @property --tw-inset-shadow-alpha {
498
+ syntax: "<percentage>";
499
+ inherits: false;
500
+ initial-value: 100%;
501
+ }
502
+ @property --tw-ring-color {
503
+ syntax: "*";
504
+ inherits: false;
505
+ }
506
+ @property --tw-ring-shadow {
507
+ syntax: "*";
508
+ inherits: false;
509
+ initial-value: 0 0 #0000;
510
+ }
511
+ @property --tw-inset-ring-color {
512
+ syntax: "*";
513
+ inherits: false;
514
+ }
515
+ @property --tw-inset-ring-shadow {
516
+ syntax: "*";
517
+ inherits: false;
518
+ initial-value: 0 0 #0000;
519
+ }
520
+ @property --tw-ring-inset {
521
+ syntax: "*";
522
+ inherits: false;
523
+ }
524
+ @property --tw-ring-offset-width {
525
+ syntax: "<length>";
526
+ inherits: false;
527
+ initial-value: 0px;
528
+ }
529
+ @property --tw-ring-offset-color {
530
+ syntax: "*";
531
+ inherits: false;
532
+ initial-value: #fff;
533
+ }
534
+ @property --tw-ring-offset-shadow {
535
+ syntax: "*";
536
+ inherits: false;
537
+ initial-value: 0 0 #0000;
538
+ }
539
+ @property --tw-duration {
540
+ syntax: "*";
541
+ inherits: false;
542
+ }
543
+ @layer properties {
544
+ @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
545
+ *, ::before, ::after, ::backdrop {
546
+ --tw-border-style: solid;
547
+ --tw-font-weight: initial;
548
+ --tw-shadow: 0 0 #0000;
549
+ --tw-shadow-color: initial;
550
+ --tw-shadow-alpha: 100%;
551
+ --tw-inset-shadow: 0 0 #0000;
552
+ --tw-inset-shadow-color: initial;
553
+ --tw-inset-shadow-alpha: 100%;
554
+ --tw-ring-color: initial;
555
+ --tw-ring-shadow: 0 0 #0000;
556
+ --tw-inset-ring-color: initial;
557
+ --tw-inset-ring-shadow: 0 0 #0000;
558
+ --tw-ring-inset: initial;
559
+ --tw-ring-offset-width: 0px;
560
+ --tw-ring-offset-color: #fff;
561
+ --tw-ring-offset-shadow: 0 0 #0000;
562
+ --tw-duration: initial;
563
+ }
564
+ }
565
+ }
566
+
package/package.json CHANGED
@@ -1,11 +1,14 @@
1
1
  {
2
2
  "name": "@elogroup-sereduc/portal-aluno-tour",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "Componente de tour guiado customizado usando HeroUI para o Portal do Aluno",
5
+ "type": "module",
5
6
  "main": "dist/index.js",
6
7
  "types": "dist/index.d.ts",
8
+ "style": "dist/tour.css",
7
9
  "scripts": {
8
- "build": "tsc",
10
+ "build": "tsc && npm run build:css",
11
+ "build:css": "postcss src/styles/tour.css -o dist/tour.css",
9
12
  "dev": "tsc --watch"
10
13
  },
11
14
  "peerDependencies": {
@@ -19,7 +22,11 @@
19
22
  "devDependencies": {
20
23
  "@types/react": "^18.0.0",
21
24
  "@types/react-dom": "^18.0.0",
22
- "typescript": "^5.0.0"
25
+ "typescript": "^5.0.0",
26
+ "postcss": "^8.0.0",
27
+ "postcss-cli": "^10.0.0",
28
+ "@tailwindcss/postcss": "^4.1.0",
29
+ "tailwindcss": "^4.1.0"
23
30
  },
24
31
  "keywords": [
25
32
  "tour",
@@ -0,0 +1,6 @@
1
+ export default {
2
+ plugins: {
3
+ "@tailwindcss/postcss": {},
4
+ },
5
+ };
6
+
@@ -35,22 +35,23 @@ export function Tour({
35
35
 
36
36
  // Calcula a posição da tooltip baseado no elemento destacado
37
37
  const calculateTooltipPosition = useCallback((element: HTMLElement, position: string = "bottom") => {
38
+ // Recalcula o rect após possíveis mudanças de scroll
38
39
  const rect = element.getBoundingClientRect();
39
40
  const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
40
41
  const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
41
42
  const viewportWidth = window.innerWidth;
42
43
  const viewportHeight = window.innerHeight;
43
44
 
44
- // Tamanho estimado da tooltip (ajuste conforme necessário)
45
+ // Tamanho estimado da tooltip
45
46
  const tooltipWidth = 384; // max-w-sm = 384px
46
- const tooltipHeight = 200; // altura estimada
47
- const spacing = 16; // espaçamento entre elemento e tooltip
47
+ const tooltipHeight = 250; // altura estimada com conteúdo
48
+ const spacing = 8; // espaçamento menor para ficar mais próximo
48
49
 
49
50
  let top = 0;
50
51
  let left = 0;
51
52
  let finalPosition = position;
52
53
 
53
- // Calcula posição base
54
+ // Calcula posição base - sempre próxima ao elemento
54
55
  switch (position) {
55
56
  case "top":
56
57
  top = rect.top + scrollTop - spacing;
@@ -74,47 +75,70 @@ export function Tour({
74
75
  finalPosition = "bottom";
75
76
  }
76
77
 
77
- // Ajusta posição se a tooltip sair da viewport
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
78
80
  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;
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;
85
+
86
+ if (elementCenterX < minLeft) {
87
+ left = minLeft;
88
+ } else if (elementCenterX > maxLeft) {
89
+ left = maxLeft;
90
+ } else {
91
+ left = elementCenterX; // Mantém centralizado no elemento
84
92
  }
85
93
 
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;
94
+ // Verifica se precisa mudar de posição vertical
95
+ 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;
90
102
  finalPosition = "top";
91
103
  }
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) {
104
+ } 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
96
110
  top = rect.bottom + scrollTop + spacing;
97
111
  finalPosition = "bottom";
98
112
  }
99
113
  }
100
114
  } 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;
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;
119
+
120
+ if (elementCenterY < minTop) {
121
+ top = minTop;
122
+ } else if (elementCenterY > maxTop) {
123
+ top = maxTop;
124
+ } else {
125
+ top = elementCenterY; // Mantém centralizado no elemento
106
126
  }
107
127
 
108
- // Se não couber à esquerda, tenta à direita
109
- if (finalPosition === "left" && left - tooltipWidth < scrollLeft) {
110
- if (rect.right + tooltipWidth < scrollLeft + viewportWidth) {
128
+ // Verifica se precisa mudar de posição horizontal
129
+ if (finalPosition === "left") {
130
+ const spaceLeft = rect.left - scrollLeft;
131
+ const spaceRight = viewportWidth - (rect.right - scrollLeft);
132
+
133
+ if (spaceLeft < tooltipWidth + spacing && spaceRight > spaceLeft) {
111
134
  left = rect.right + scrollLeft + spacing;
112
135
  finalPosition = "right";
113
136
  }
114
- }
115
- // Se não couber à direita, tenta à esquerda
116
- else if (finalPosition === "right" && left + tooltipWidth > scrollLeft + viewportWidth) {
117
- if (rect.left - tooltipWidth > scrollLeft) {
137
+ } 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) {
118
142
  left = rect.left + scrollLeft - spacing;
119
143
  finalPosition = "left";
120
144
  }
@@ -163,11 +187,16 @@ export function Tour({
163
187
  // Scroll para o elemento
164
188
  element.scrollIntoView({ behavior: "smooth", block: "center" });
165
189
 
166
- // Calcula posição da tooltip após um pequeno delay para garantir que o scroll terminou
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
167
192
  setTimeout(() => {
168
- const position = calculateTooltipPosition(element, step.position || "bottom");
169
- setTooltipPosition(position);
170
- }, 300);
193
+ // Recalcula o rect após o scroll
194
+ const updatedRect = element.getBoundingClientRect();
195
+ if (updatedRect.width > 0 && updatedRect.height > 0) {
196
+ const position = calculateTooltipPosition(element, step.position || "bottom");
197
+ setTooltipPosition(position);
198
+ }
199
+ }, 400);
171
200
  }, [isVisible, currentStep, steps, calculateTooltipPosition]);
172
201
 
173
202
  // Adiciona overlay e highlight ao elemento
@@ -306,7 +335,7 @@ export function Tour({
306
335
  {tooltipPosition && currentStepData && highlightedElement && (
307
336
  <div
308
337
  ref={tooltipRef}
309
- className="portal-tour:max-w-sm"
338
+ className="tour:max-w-sm"
310
339
  style={{
311
340
  position: "fixed",
312
341
  top: tooltipPosition.position === "bottom" || tooltipPosition.position === "left" || tooltipPosition.position === "right"
@@ -323,36 +352,36 @@ export function Tour({
323
352
  zIndex: 10001,
324
353
  }}
325
354
  >
326
- <div className="portal-tour:bg-white portal-tour:rounded-lg portal-tour:shadow-xl portal-tour:p-6 portal-tour:relative">
355
+ <div className="tour:bg-white tour:rounded-lg tour:shadow-xl tour:p-6 tour:relative">
327
356
  {/* Botão fechar */}
328
357
  <button
329
358
  onClick={handleExit}
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"
359
+ 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"
331
360
  aria-label="Fechar tour"
332
361
  >
333
- <HiXMark className="portal-tour:w-5 portal-tour:h-5 portal-tour:text-gray-500" />
362
+ <HiXMark className="tour:w-5 tour:h-5 tour:text-gray-500" />
334
363
  </button>
335
364
 
336
365
  {/* Título (se fornecido) */}
337
366
  {currentStepData.title && (
338
- <h3 className="portal-tour:text-lg portal-tour:font-semibold portal-tour:text-gray-900 portal-tour:mb-2 portal-tour:pr-6">
367
+ <h3 className="tour:text-lg tour:font-semibold tour:text-gray-900 tour:mb-2 tour:pr-6">
339
368
  {currentStepData.title}
340
369
  </h3>
341
370
  )}
342
371
 
343
372
  {/* Conteúdo */}
344
- <p className="portal-tour:text-gray-700 portal-tour:mb-4">{currentStepData.intro}</p>
373
+ <p className="tour:text-gray-700 tour:mb-4">{currentStepData.intro}</p>
345
374
 
346
375
  {/* Progresso */}
347
376
  {showProgress && (
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">
377
+ <div className="tour:mb-4">
378
+ <div className="tour:w-full tour:bg-gray-200 tour:rounded-full tour:h-2">
350
379
  <div
351
- className="portal-tour:bg-brand-primary portal-tour:h-2 portal-tour:rounded-full portal-tour:transition-all portal-tour:duration-300"
380
+ className="tour:bg-brand-primary tour:h-2 tour:rounded-full tour:transition-all tour:duration-300"
352
381
  style={{ width: `${progress}%` }}
353
382
  />
354
383
  </div>
355
- <p className="portal-tour:text-xs portal-tour:text-gray-500 portal-tour:mt-1 portal-tour:text-center">
384
+ <p className="tour:text-xs tour:text-gray-500 tour:mt-1 tour:text-center">
356
385
  {currentStep + 1} de {steps.length}
357
386
  </p>
358
387
  </div>
@@ -360,15 +389,15 @@ export function Tour({
360
389
 
361
390
  {/* Bullets */}
362
391
  {showBullets && (
363
- <div className="portal-tour:flex portal-tour:justify-center portal-tour:gap-1 portal-tour:mb-4">
392
+ <div className="tour:flex tour:justify-center tour:gap-1 tour:mb-4">
364
393
  {steps.map((_, index) => (
365
394
  <button
366
395
  key={index}
367
396
  onClick={() => setCurrentStep(index)}
368
- className={`portal-tour:w-2 portal-tour:h-2 portal-tour:rounded-full portal-tour:transition-all ${
397
+ className={`tour:w-2 tour:h-2 tour:rounded-full tour:transition-all ${
369
398
  index === currentStep
370
- ? "portal-tour:bg-brand-primary portal-tour:w-6"
371
- : "portal-tour:bg-gray-300 portal-tour:hover:bg-gray-400"
399
+ ? "tour:bg-brand-primary tour:w-6"
400
+ : "tour:bg-gray-300 tour:hover:bg-gray-400"
372
401
  }`}
373
402
  aria-label={`Ir para passo ${index + 1}`}
374
403
  />
@@ -377,27 +406,27 @@ export function Tour({
377
406
  )}
378
407
 
379
408
  {/* Botões de navegação */}
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">
409
+ <div className="tour:flex tour:justify-between tour:items-center tour:gap-2">
410
+ <div className="tour:flex tour:gap-2">
382
411
  {!isFirstStep && (
383
412
  <Button
384
413
  variant="bordered"
385
414
  onPress={handlePrev}
386
- startContent={<HiChevronLeft className="portal-tour:w-4 portal-tour:h-4" />}
415
+ startContent={<HiChevronLeft className="tour:w-4 tour:h-4" />}
387
416
  >
388
417
  {prevLabel}
389
418
  </Button>
390
419
  )}
391
420
  </div>
392
421
 
393
- <div className="portal-tour:flex portal-tour:gap-2">
422
+ <div className="tour:flex tour:gap-2">
394
423
  <Button variant="light" onPress={handleSkip}>
395
424
  {skipLabel}
396
425
  </Button>
397
426
  <Button
398
427
  color="primary"
399
428
  onPress={isLastStep ? handleComplete : handleNext}
400
- endContent={!isLastStep ? <HiChevronRight className="portal-tour:w-4 portal-tour:h-4" /> : undefined}
429
+ endContent={!isLastStep ? <HiChevronRight className="tour:w-4 tour:h-4" /> : undefined}
401
430
  >
402
431
  {isLastStep ? doneLabel : nextLabel}
403
432
  </Button>
@@ -408,7 +437,7 @@ export function Tour({
408
437
  {/* Seta indicadora */}
409
438
  {tooltipPosition.position === "bottom" && (
410
439
  <div
411
- className="portal-tour:absolute portal-tour:w-0 portal-tour:h-0 portal-tour:border-8 portal-tour:border-transparent"
440
+ className="tour:absolute tour:w-0 tour:h-0 tour:border-8 tour:border-transparent"
412
441
  style={{
413
442
  top: "-16px",
414
443
  left: "50%",
@@ -419,7 +448,7 @@ export function Tour({
419
448
  )}
420
449
  {tooltipPosition.position === "top" && (
421
450
  <div
422
- className="portal-tour:absolute portal-tour:w-0 portal-tour:h-0 portal-tour:border-8 portal-tour:border-transparent"
451
+ className="tour:absolute tour:w-0 tour:h-0 tour:border-8 tour:border-transparent"
423
452
  style={{
424
453
  bottom: "-16px",
425
454
  left: "50%",
@@ -430,7 +459,7 @@ export function Tour({
430
459
  )}
431
460
  {tooltipPosition.position === "right" && (
432
461
  <div
433
- className="portal-tour:absolute portal-tour:w-0 portal-tour:h-0 portal-tour:border-8 portal-tour:border-transparent"
462
+ className="tour:absolute tour:w-0 tour:h-0 tour:border-8 tour:border-transparent"
434
463
  style={{
435
464
  left: "-16px",
436
465
  top: "50%",
@@ -441,7 +470,7 @@ export function Tour({
441
470
  )}
442
471
  {tooltipPosition.position === "left" && (
443
472
  <div
444
- className="portal-tour:absolute portal-tour:w-0 portal-tour:h-0 portal-tour:border-8 portal-tour:border-transparent"
473
+ className="tour:absolute tour:w-0 tour:h-0 tour:border-8 tour:border-transparent"
445
474
  style={{
446
475
  right: "-16px",
447
476
  top: "50%",
@@ -0,0 +1,3 @@
1
+ @import "tailwindcss";
2
+ @config "../../tailwind.config.js";
3
+
@@ -3,6 +3,9 @@ const shared = require("@elogroup-sereduc/portal-aluno-tailwind-config");
3
3
 
4
4
  module.exports = {
5
5
  ...shared,
6
- prefix: "portal-tour",
6
+ prefix: "tour",
7
+ content: [
8
+ "./src/**/*.{js,ts,jsx,tsx}",
9
+ ],
7
10
  };
8
11