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

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