v-tutorial 0.0.0-stage → 1.0.0

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
@@ -1,3 +1,340 @@
1
- # Temporary Holding Version
1
+ <div align="center">
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ # 🎯 v-tutorial
4
+
5
+ **100% Interactive, Mobile-First (Bootstrap-Style) & Headless-Ready Guided Tours for Vue 3**
6
+
7
+ [![NPM Version](https://img.shields.io/npm/v/v-tutorial?color=42b883&label=npm)](https://www.npmjs.com/package/v-tutorial)
8
+ [![Vue 3](https://img.shields.io/badge/Vue-3.x-42b883?logo=vue.js)](https://vuejs.org/)
9
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Strict-3178c6?logo=typescript)](https://www.typescriptlang.org/)
10
+ [![Zero Dependencies](https://img.shields.io/badge/Dependencies-Zero-success)](#)
11
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
12
+
13
+ 🌎 **English** | 🇧🇷 **[Leia em Português (Portuguese Version)](./README.pt-BR.md)**
14
+
15
+ </div>
16
+
17
+ ---
18
+
19
+ ## 📋 Table of Contents
20
+
21
+ 1. [Why `v-tutorial`? (+ Comparison Table)](#1-why-v-tutorial)
22
+ 2. [Modular Architecture](#2-modular-architecture)
23
+ 3. [Installation & Quick Setup](#3-installation--quick-setup)
24
+ 4. [Step Modes (`info`, `wait-click`, `optional-click`)](#4-step-modes-info-wait-click-optional-click)
25
+ 5. [Bootstrap-Style Mobile-First Responsiveness (`xs` to `xxl`)](#5-bootstrap-style-mobile-first-responsiveness-xs-to-xxl)
26
+ 6. [Declarative Usage (`<TutorialProvider>` + `<VTutorialStep>`)](#6-declarative-usage-tutorialprovider--vtutorialstep)
27
+ 7. [Connecting Remote Components (`registerAction` & `v-tutorial`)](#7-connecting-remote-components-registeraction--v-tutorial)
28
+ 8. [Styling, Dark Mode & CSS Variables](#8-styling-dark-mode--css-variables)
29
+ 9. [Headless UI Mode & Scoped Slots](#9-headless-ui-mode--scoped-slots)
30
+ 10. [Complete API Reference](#10-complete-api-reference)
31
+
32
+ ---
33
+
34
+ ## 1. Why `v-tutorial`?
35
+
36
+ Most guided tour libraries (`Driver.js`, `Shepherd.js`, `Intro.js`) were built for static websites or passive `"Next -> Next -> Finish"` reading flows. When used inside modern **Vue 3 SPAs** with dynamic routes, `Teleport` modals, and distinct Mobile/Desktop DOM trees, they break `z-index` stacking contexts, cover mandatory buttons on mobile screens, and fail when a user clicks **"Previous"**.
37
+
38
+ | Feature | `v-tutorial` | Driver.js | Shepherd.js | Intro.js |
39
+ | :--- | :---: | :---: | :---: | :---: |
40
+ | **4-Shield Real Click (`wait-click`)** *(No `z-index` hacks)* | ✅ | ❌ | ❌ | ❌ |
41
+ | **Bootstrap-Style Mobile-First Breakpoints (`xs`..`xxl`)** | ✅ | ❌ | ❌ | ❌ |
42
+ | **Anti-Collision Mobile Sheets (`bottom-sheet` / `top-sheet`)** | ✅ | ❌ | ❌ | ❌ |
43
+ | **Declarative Vue Router Rollback (`route` / `rollback-route`)** | ✅ | ❌ | ❌ | ❌ |
44
+ | **Remote Component State Rollback (`registerAction`)** | ✅ | ❌ | ❌ | ❌ |
45
+ | **Declarative `<VTutorialStep>` Template API + Slots** | ✅ | ❌ | ❌ | ❌ |
46
+ | **Headless UI Mode (`:unstyled="true"` + 8 Scoped Slots)** | ✅ | ❌ | ⚠️ Partial | ❌ |
47
+ | **External Dependencies** | **0** | 0 | Floating UI | 0 |
48
+
49
+ ### Core Highlights
50
+
51
+ * 🛡️ **4-Shield Click Architecture (`wait-click`):** Instead of cloning DOM nodes or hacking `z-index`, `v-tutorial` surrounds the target element with 4 invisible click shields. The rest of the screen is blocked while **your real button remains 100% interactive** in its native DOM context.
52
+ * 📱 **Bootstrap-Style Mobile-First Cascade (`xs` -> `sm` -> `md` -> `lg` -> `xl` -> `xxl`):** Define base props for mobile (`xs`) and override `target`, `placement`, `enterActions`, or `disabled` at any breakpoint (`md`, `lg`, etc.). Rules cascade upward automatically just like Bootstrap's grid.
53
+ * 🧲 **Anti-Collision Mobile Sheets (`bottom-sheet` & `top-sheet`):** On mobile viewports, floating cards automatically dock as a clean bottom or top sheet. If a sheet would overlap the highlighted button, the anti-collision engine automatically flips it to the opposite free side.
54
+ * ⏪ **Declarative State & Route Rollback:** If Step 2 opens a sidebar, Step 3 navigates to `/report`, and the user clicks **"Previous"**, `v-tutorial` automatically rolls back the route and UI state (`rollback-route`, `:rollback-actions`).
55
+ * ⚡ **0% Idle CPU Tracking:** Uses `ResizeObserver` + short `requestAnimationFrame` bursts only during CSS transitions (`transitionrun`), dropping to 0% CPU usage once the layout settles.
56
+
57
+ ---
58
+
59
+ ## 2. Modular Architecture
60
+
61
+ The library is split into focused, single-responsibility modules inside `src/`:
62
+
63
+ | File | Responsibility |
64
+ | :--- | :--- |
65
+ | `types.ts` | TypeScript interfaces for steps, responsive breakpoints, action maps, and contexts. |
66
+ | `responsive.ts` | Bootstrap 5 breakpoint detection (`xs` to `xxl`) and Mobile-First property cascading. |
67
+ | `domResolver.ts` | Visible DOM element resolution, multi-target bounding box calculation, and smooth auto-scrolling. |
68
+ | `positioning.ts` | Card & caret arrow coordinate math, auto-flipping, and mobile sheet anti-collision engine. |
69
+ | `useTutorial.ts` | Reactive state machine, step queue, registered actions, and global click capture. |
70
+ | `TutorialProvider.vue` | Root visual/Headless provider rendering shields, spotlight ring, arrow, and card slots. |
71
+ | `TutorialStep.vue` | Declarative `<VTutorialStep>` component with slot teleportation and reactive prop syncing. |
72
+
73
+ ---
74
+
75
+ ## 3. Installation & Quick Setup
76
+
77
+ Install the package via NPM, PNPM, or Yarn:
78
+
79
+ ```bash
80
+ npm install v-tutorial
81
+ ```
82
+
83
+ Register `TutorialPlugin` and import the stylesheet in your `main.ts`:
84
+
85
+ ```ts
86
+ // main.ts
87
+ import { createApp } from 'vue'
88
+ import App from './App.vue'
89
+ import router from './router'
90
+ import { TutorialPlugin } from 'v-tutorial'
91
+ import 'v-tutorial/style.css'
92
+
93
+ const app = createApp(App)
94
+
95
+ app.use(router)
96
+ app.use(TutorialPlugin, {
97
+ storageKey: 'my-app-tutorial-completed',
98
+ autoScroll: true,
99
+ scrollBehavior: 'smooth',
100
+ spotlightPadding: 6,
101
+ cardWidth: 370,
102
+ showArrow: true,
103
+ mobileSheetOnAuto: true,
104
+ router, // Optional: Enables declarative route="" and rollback-route="" on steps
105
+ })
106
+
107
+ app.mount('#app')
108
+ ```
109
+
110
+ ---
111
+
112
+ ## 4. Step Modes (`info`, `wait-click`, `optional-click`)
113
+
114
+ | Mode | "Next" Button | Clicking Target Element | Best Use Case |
115
+ | :--- | :---: | :---: | :--- |
116
+ | `'info'` *(default)* | **Visible** | Optional (does not auto-advance) | Welcome screens, general explanations, or panel overviews. |
117
+ | `'wait-click'` | **Hidden** *(shows "Waiting click...")* | **Required to advance** | Hands-on training where the user **must click the real button** (e.g., opening a menu or system). |
118
+ | `'optional-click'` | **Visible** | **Also advances the step** | When the user can either test the button (e.g., pin a favorite) or click "Next" to skip. |
119
+
120
+ ---
121
+
122
+ ## 5. Bootstrap-Style Mobile-First Responsiveness (`xs` to `xxl`)
123
+
124
+ Just like Bootstrap 5, `v-tutorial` is **Mobile-First**. Base props on `<VTutorialStep>` apply from `xs` (`0px`) upward, and any breakpoint override cascades to larger screens until overridden again:
125
+
126
+ | Breakpoint | Default Min-Width | Shorthand Props |
127
+ | :--- | :---: | :--- |
128
+ | `xs` *(base)* | `0px` | `target`, `placement` |
129
+ | `sm` | `576px` | `target-sm`, `placement-sm` |
130
+ | `md` | `768px` | `target-md`, `placement-md` |
131
+ | `lg` | `992px` | `target-lg`, `placement-lg` |
132
+ | `xl` | `1200px` | `target-xl`, `placement-xl` |
133
+ | `xxl` | `1400px` | `target-xxl`, `placement-xxl` |
134
+
135
+ ### 5.1. Using Shorthand Responsive Props (`target-md`, `placement-md`)
136
+ If your app renders `.mobile-system-link` on phones (`xs`/`sm`) and `.desktop-system-link` on desktops (`md` and up):
137
+
138
+ ```vue
139
+ <VTutorialStep
140
+ id="select-system"
141
+ target=".mobile-system-link"
142
+ target-md=".desktop-system-link"
143
+ placement="bottom-sheet"
144
+ placement-md="right"
145
+ title="Open a System"
146
+ mode="wait-click"
147
+ >
148
+ <p class="mb-0">Click on the highlighted system to open it.</p>
149
+ </VTutorialStep>
150
+ ```
151
+
152
+ ### 5.2. Mobile-Only or Desktop-Only Steps (`disabled: true` per Breakpoint)
153
+ Want a step that teaches mobile users how to pull open the mobile drawer (`.mobile-drawer-tab`), but automatically skips itself on desktop (`md` and up)? Use the `:breakpoints` prop:
154
+
155
+ ```vue
156
+ <!-- Runs on xs and sm (< 768px), automatically skipped on md, lg, xl, xxl (>= 768px) -->
157
+ <VTutorialStep
158
+ id="open-mobile-drawer"
159
+ target=".mobile-drawer-tab"
160
+ placement="bottom-sheet"
161
+ title="Mobile Menu Tab"
162
+ mode="wait-click"
163
+ :breakpoints="{
164
+ md: { disabled: true }
165
+ }"
166
+ >
167
+ <p class="mb-0">Tap the side pull-tab to open the mobile menu.</p>
168
+ </VTutorialStep>
169
+ ```
170
+
171
+ ---
172
+
173
+ ## 6. Declarative Usage (`<TutorialProvider>` + `<VTutorialStep>`)
174
+
175
+ Build complete multi-route interactive onboarding flows directly in your template:
176
+
177
+ ```vue
178
+ <template>
179
+ <TutorialProvider :auto-start="true">
180
+ <VTutorialStep
181
+ id="welcome"
182
+ title="Welcome!"
183
+ mode="info"
184
+ placement="center"
185
+ route="/"
186
+ :enter-actions="{ closeThemeModal: true, closeUserMenu: true, setSidebarExpanded: false }"
187
+ >
188
+ <p class="mb-0">This training is <strong>100% interactive</strong>.</p>
189
+ </VTutorialStep>
190
+
191
+ <VTutorialStep
192
+ id="click-report"
193
+ target=".report-link"
194
+ placement="bottom-sheet"
195
+ placement-md="right"
196
+ title="Report an Issue"
197
+ mode="wait-click"
198
+ rollback-route="/"
199
+ :enter-actions="{ setSidebarExpanded: true, openUserMenu: true }"
200
+ :rollback-actions="{ setSidebarExpanded: true, openUserMenu: true }"
201
+ >
202
+ <p class="mb-0">Click on <strong>"Report issue or suggestion"</strong>.</p>
203
+ </VTutorialStep>
204
+ </TutorialProvider>
205
+ </template>
206
+ ```
207
+
208
+ ---
209
+
210
+ ## 7. Connecting Remote Components (`registerAction` & `v-tutorial`)
211
+
212
+ ### 7.1. Exposing Component State (`registerAction`)
213
+ Any component can register actions that steps can trigger via `enterActions`, `rollbackActions`, or `leaveActions`:
214
+
215
+ ```ts
216
+ // Inside UserInfo.vue
217
+ import { useTutorial } from 'v-tutorial'
218
+
219
+ const { registerAction } = useTutorial()
220
+
221
+ registerAction('openUserMenu', () => {
222
+ if (isMobile.value) {
223
+ isOpen.value = true
224
+ } else {
225
+ isDesktopModalOpen.value = true
226
+ }
227
+ })
228
+
229
+ registerAction('closeUserMenu', () => {
230
+ isOpen.value = false
231
+ isDesktopModalOpen.value = false
232
+ })
233
+ ```
234
+
235
+ ### 7.2. Restarting the Tutorial from a Settings Modal
236
+ Call `restartTutorial()` from any component to clear the completion flag in `localStorage` and immediately launch Step 1:
237
+
238
+ ```ts
239
+ import { useTutorial } from 'v-tutorial'
240
+
241
+ const { restartTutorial } = useTutorial()
242
+
243
+ async function handleRestartClick() {
244
+ closeSettingsModal()
245
+ await restartTutorial()
246
+ }
247
+ ```
248
+
249
+ ---
250
+
251
+ ## 8. Styling, Dark Mode & CSS Variables
252
+
253
+ `v-tutorial` inherits **Tabler / Bootstrap** variables (`--tblr-primary`, `--tblr-bg-surface`) automatically and adapts to Dark Mode (`[data-bs-theme="dark"]` or `.dark`). Override `--v-tutorial-*` variables to customize:
254
+
255
+ ```css
256
+ :root {
257
+ --v-tutorial-primary: #10b981;
258
+ --v-tutorial-bg: #ffffff;
259
+ --v-tutorial-bg-secondary: #f8fafc;
260
+ --v-tutorial-text: #0f172a;
261
+ --v-tutorial-muted: #64748b;
262
+ --v-tutorial-border: rgba(15, 23, 42, 0.12);
263
+ --v-tutorial-danger: #ef4444;
264
+ --v-tutorial-backdrop: rgba(10, 14, 23, 0.72);
265
+ --v-tutorial-radius: 16px;
266
+ --v-tutorial-z-index: 10040;
267
+ }
268
+ ```
269
+
270
+ ---
271
+
272
+ ## 9. Headless UI Mode & Scoped Slots
273
+
274
+ Set `:unstyled="true"` or override any Scoped Slot on `<TutorialProvider>` (`#card`, `#header`, `#body`, `#hint`, `#progress`, `#footer`, `#exit-button`, `#spotlight`):
275
+
276
+ ```vue
277
+ <TutorialProvider>
278
+ <template #card="{ step, stepIndex, totalSteps, activeBreakpoint, nextStep, prevStep, endTutorial }">
279
+ <div class="custom-card p-4">
280
+ <small>Breakpoint: {{ activeBreakpoint }} | Step {{ stepIndex + 1 }}/{{ totalSteps }}</small>
281
+ <h4>{{ step?.title }}</h4>
282
+ <div v-html="step?.content"></div>
283
+ <button v-if="stepIndex > 0" @click="prevStep">Back</button>
284
+ <button v-if="step?.mode !== 'wait-click'" @click="nextStep">Next</button>
285
+ <button @click="endTutorial(true)">Skip</button>
286
+ </div>
287
+ </template>
288
+ </TutorialProvider>
289
+ ```
290
+
291
+ ---
292
+
293
+ ## 10. Complete API Reference
294
+
295
+ ### `<VTutorialStep>` Props / `TutorialStep` Properties
296
+
297
+ | Property | Type | Default | Description |
298
+ | :--- | :--- | :---: | :--- |
299
+ | `id` | `string` | Auto-generated | Unique step identifier. |
300
+ | `target` | `string \| string[]` | `undefined` | Base (`xs`) selector, `v-tutorial` ID, or array of selectors. |
301
+ | `targetSm`..`targetXxl` | `string \| string[]` | `undefined` | Mobile-First target overrides for `sm`, `md`, `lg`, `xl`, `xxl`. |
302
+ | `placement` | `'auto' \| 'top' \| 'bottom' \| 'left' \| 'right' \| 'center' \| 'bottom-sheet' \| 'top-sheet'` | `'auto'` | Base (`xs`) card placement with automatic collision prevention. |
303
+ | `placementSm`..`placementXxl` | `TutorialPlacement` | `undefined` | Mobile-First placement overrides for `sm`, `md`, `lg`, `xl`, `xxl`. |
304
+ | `breakpoints` | `Partial<Record<TutorialBreakpointName, TutorialStepResponsiveOverride>>` | `undefined` | Full Mobile-First override object per breakpoint (`disabled`, `enterActions`, `title`, etc.). |
305
+ | `disabled` | `boolean` | `false` | Skips this step when `true` in the active breakpoint. |
306
+ | `title` | `string` | **Required** | Step header title. |
307
+ | `mode` | `'info' \| 'wait-click' \| 'optional-click'` | `'info'` | Step interaction behavior. |
308
+ | `hintText` | `string` | `undefined` | Text shown in the pulsing interactive banner. |
309
+ | `route` | `string` | `undefined` | Navigates to this route before entering the step. |
310
+ | `rollbackRoute` | `string` | `undefined` | Navigates to this route when returning via "Previous". |
311
+ | `enterActions` | `Record<string, any> \| string[]` | `undefined` | Registered actions executed when entering the step. |
312
+ | `rollbackActions` | `Record<string, any> \| string[]` | `undefined` | Registered actions executed when returning via "Previous". |
313
+ | `leaveActions` | `Record<string, any> \| string[]` | `undefined` | Registered actions executed when leaving the step. |
314
+ | `afterClickDelay` | `number` | `280` | Delay in `ms` after clicking the target before advancing. |
315
+ | `preventNativeClick` | `boolean` | `false` | Blocks the native click handler of the target during the tour. |
316
+
317
+ ### `useTutorial()` Return Values
318
+
319
+ | Property / Method | Type | Description |
320
+ | :--- | :--- | :--- |
321
+ | `isActive` | `Ref<boolean>` | Whether the tutorial is currently running. |
322
+ | `activeBreakpoint` | `ComputedRef<'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'xxl'>` | Current Bootstrap-style breakpoint name. |
323
+ | `isMobileViewport` | `ComputedRef<boolean>` | `true` when viewport width is below `md` (`< 768px`). |
324
+ | `currentStep` | `ComputedRef<TutorialStep \| null>` | Active step resolved for the current breakpoint. |
325
+ | `currentStepIndex` | `Ref<number>` | 0-based index of the active step. |
326
+ | `totalSteps` | `ComputedRef<number>` | Total enabled steps for the current breakpoint. |
327
+ | `progress` | `ComputedRef<number>` | Completion percentage (`0` to `100`). |
328
+ | `startTutorial(steps?, force?)` | `Promise<void>` | Starts the tour (`force = true` ignores `localStorage`). |
329
+ | `restartTutorial()` | `Promise<void>` | Clears `localStorage` flag and restarts from Step 1. |
330
+ | `nextStep()` / `prevStep()` | `Promise<void>` | Navigates forward or backward (with automatic rollback). |
331
+ | `goToStep(indexOrId)` | `Promise<void>` | Jumps directly to a specific step index or `id`. |
332
+ | `endTutorial(markCompleted?)` | `void` | Closes the tutorial immediately. |
333
+ | `registerAction(name, fn)` | `void` | Registers a named action callable by any step. |
334
+ | `onFinish` / `onStop` / `onStepChange` | `(cb) => () => void` | Lifecycle event listeners (auto-disposed on component unmount). |
335
+
336
+ ---
337
+
338
+ ## 📄 License
339
+
340
+ Distributed under the **MIT License**. Created by [Márlon Bento Azevedo](https://github.com/marlon-bento).
@@ -0,0 +1,341 @@
1
+ <div align="center">
2
+
3
+ # 🎯 v-tutorial
4
+
5
+ **Tours Guiados e Treinamento 100% Interativo, Mobile-First (Estilo Bootstrap) e Headless-Ready para Vue 3**
6
+
7
+ [![NPM Version](https://img.shields.io/npm/v/v-tutorial?color=42b883&label=npm)](https://www.npmjs.com/package/v-tutorial)
8
+ [![Vue 3](https://img.shields.io/badge/Vue-3.x-42b883?logo=vue.js)](https://vuejs.org/)
9
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Strict-3178c6?logo=typescript)](https://www.typescriptlang.org/)
10
+ [![Zero Dependencies](https://img.shields.io/badge/Dependências-Zero-success)](#)
11
+ [![License: MIT](https://img.shields.io/badge/Licença-MIT-blue.svg)](https://opensource.org/licenses/MIT)
12
+
13
+ 🇧🇷 **Português** | 🌎 **[Read in English (English Version)](./README.md)**
14
+
15
+ </div>
16
+
17
+ ---
18
+
19
+ ## 📋 Sumário
20
+
21
+ 1. [Por que usar o `v-tutorial`? (+ Tabela Comparativa)](#1-por-que-usar-o-v-tutorial)
22
+ 2. [Arquitetura Modular](#2-arquitetura-modular)
23
+ 3. [Instalação e Configuração Rápida](#3-instalação-e-configuração-rápida)
24
+ 4. [Modos de Passo (`info`, `wait-click`, `optional-click`)](#4-modos-de-passo-info-wait-click-optional-click)
25
+ 5. [Responsividade Mobile-First Estilo Bootstrap (`xs` até `xxl`)](#5-responsividade-mobile-first-estilo-bootstrap-xs-até-xxl)
26
+ 6. [Uso Declarativo (`<TutorialProvider>` + `<VTutorialStep>`)](#6-uso-declarativo-tutorialprovider--vtutorialstep)
27
+ 7. [Conectando Componentes Distintos (`registerAction` e `v-tutorial`)](#7-conectando-componentes-distintos-registeraction-e-v-tutorial)
28
+ 8. [Customização Visual, Dark Mode e Variáveis CSS](#8-customização-visual-dark-mode-e-variáveis-css)
29
+ 9. [Modo Headless UI e Scoped Slots](#9-modo-headless-ui-e-scoped-slots)
30
+ 10. [Referência Completa da API](#10-referência-completa-da-api)
31
+
32
+ ---
33
+
34
+ ## 1. Por que usar o `v-tutorial`?
35
+
36
+ A maioria das bibliotecas de tour (`Driver.js`, `Shepherd.js`, `Intro.js`) foi pensada para sites estáticos ou fluxos passivos de leitura (`"Próximo -> Próximo -> Concluir"`). Quando colocadas dentro de uma **SPA moderna em Vue 3** com rotas dinâmicas, modais via `Teleport` e árvores DOM diferentes para Mobile e Desktop, elas quebram o `z-index` da aplicação, cobrem botões obrigatórios no celular e falham quando o usuário clica em **"Anterior"**.
37
+
38
+ | Recurso | `v-tutorial` | Driver.js | Shepherd.js | Intro.js |
39
+ | :--- | :---: | :---: | :---: | :---: |
40
+ | **Clique Real com 4 Escudos (`wait-click`)** *(Sem hack de `z-index`)* | ✅ | ❌ | ❌ | ❌ |
41
+ | **Breakpoints Mobile-First Estilo Bootstrap (`xs`..`xxl`)** | ✅ | ❌ | ❌ | ❌ |
42
+ | **Gavetas Mobile Anti-Colisão (`bottom-sheet` / `top-sheet`)** | ✅ | ❌ | ❌ | ❌ |
43
+ | **Rollback Declarativo de Rotas (`route` / `rollback-route`)** | ✅ | ❌ | ❌ | ❌ |
44
+ | **Rollback de Estado entre Componentes (`registerAction`)** | ✅ | ❌ | ❌ | ❌ |
45
+ | **API Declarativa `<VTutorialStep>` no Template + Slots** | ✅ | ❌ | ❌ | ❌ |
46
+ | **Modo Headless UI (`:unstyled="true"` + 8 Scoped Slots)** | ✅ | ❌ | ⚠️ Parcial | ❌ |
47
+ | **Dependências Externas** | **0** | 0 | Floating UI | 0 |
48
+
49
+ ### Principais Diferenciais
50
+
51
+ * 🛡️ **Arquitetura de 4 Escudos de Clique (`wait-click`):** Em vez de clonar nós do DOM ou forçar `z-index`, o `v-tutorial` posiciona 4 escudos invisíveis ao redor do elemento destacado. O restante da tela fica bloqueado, mas **o botão real do seu sistema permanece 100% clicável** no lugar original.
52
+ * 📱 **Cascata Mobile-First Estilo Bootstrap (`xs` -> `sm` -> `md` -> `lg` -> `xl` -> `xxl`):** Defina o comportamento base para celular (`xs`) e sobrescreva `target`, `placement`, `enterActions` ou `disabled` a partir de qualquer breakpoint (`md`, `lg`, etc.). As regras cascateiam para telas maiores exatamente como no Bootstrap.
53
+ * 🧲 **Gavetas Mobile com Sistema Anti-Colisão (`bottom-sheet` e `top-sheet`):** Em telas móveis, o card ancora como uma gaveta inferior ou superior. Se o motor detectar que o card cobriria o botão destacado, ele inverte automaticamente a posição para o lado livre.
54
+ * ⏪ **Rollback Declarativo de Rotas e Estados:** Se o Passo 2 abre o menu lateral, o Passo 3 navega para `/report` e o usuário clica em **"Anterior"**, o `v-tutorial` desfaz a rota e o estado visual automaticamente (`rollback-route`, `:rollback-actions`).
55
+ * ⚡ **0% de CPU em Repouso:** Utiliza `ResizeObserver` combinado com janelas curtas de `requestAnimationFrame` apenas durante transições CSS (`transitionrun`), desligando o loop assim que a tela estabiliza.
56
+
57
+ ---
58
+
59
+ ## 2. Arquitetura Modular
60
+
61
+ O motor interno em `src/` é dividido em módulos independentes com responsabilidade única:
62
+
63
+ | Arquivo | Responsabilidade |
64
+ | :--- | :--- |
65
+ | `types.ts` | Contratos TypeScript de passos, breakpoints responsivos, mapas de ações e contextos. |
66
+ | `responsive.ts` | Detecção dos breakpoints do Bootstrap 5 (`xs` até `xxl`) e herança em cascata Mobile-First. |
67
+ | `domResolver.ts` | Busca de elementos visíveis no DOM, cálculo de `DOMRect` agrupado e auto-scroll suave. |
68
+ | `positioning.ts` | Matemática geométrica do card e da seta (`arrowStyle`), auto-flip e sistema anti-colisão mobile. |
69
+ | `useTutorial.ts` | Máquina de estados reativa, fila de passos, ações registradas e captura global de clique. |
70
+ | `TutorialProvider.vue` | Provedor visual/Headless que renderiza os escudos, anel de spotlight, seta e Scoped Slots. |
71
+ | `TutorialStep.vue` | Componente declarativo `<VTutorialStep>` com teleporte de slot e sincronização reativa. |
72
+
73
+ ---
74
+
75
+ ## 3. Instalação e Configuração Rápida
76
+
77
+ Instale o pacote via NPM, PNPM ou Yarn:
78
+
79
+ ```bash
80
+ npm install v-tutorial
81
+ ```
82
+
83
+ No arquivo `main.ts`, registre o `TutorialPlugin` e importe o CSS da biblioteca:
84
+
85
+ ```ts
86
+ // main.ts
87
+ import { createApp } from 'vue'
88
+ import App from './App.vue'
89
+ import router from './router'
90
+ import { TutorialPlugin } from 'v-tutorial'
91
+ import 'v-tutorial/style.css'
92
+
93
+ const app = createApp(App)
94
+
95
+ app.use(router)
96
+ app.use(TutorialPlugin, {
97
+ storageKey: 'meu-app-tutorial-concluido',
98
+ autoScroll: true,
99
+ scrollBehavior: 'smooth',
100
+ spotlightPadding: 6,
101
+ cardWidth: 370,
102
+ showArrow: true,
103
+ mobileSheetOnAuto: true,
104
+ router, // Opcional: Habilita o funcionamento automático de route="" e rollback-route="" nos passos
105
+ })
106
+
107
+ app.mount('#app')
108
+ ```
109
+
110
+ ---
111
+
112
+ ## 4. Modos de Passo (`info`, `wait-click`, `optional-click`)
113
+
114
+ | Modo | Botão "Próximo" | Clique no Elemento Alvo | Caso de Uso Ideal |
115
+ | :--- | :---: | :---: | :--- |
116
+ | `'info'` *(padrão)* | **Visível** | Opcional (não avança sozinho) | Telas de boas-vindas, explicações gerais ou visão de painéis. |
117
+ | `'wait-click'` | **Oculto** *(exibe "Aguardando clique...")* | **Obrigatório para avançar** | Treinamento prático onde o usuário **precisa clicar no botão real** (ex: abrir menu, abrir sistema). |
118
+ | `'optional-click'` | **Visível** | **Também avança o passo** | Quando o usuário pode testar o clique no botão (ex: fixar favorito) ou clicar em "Próximo". |
119
+
120
+ ---
121
+
122
+ ## 5. Responsividade Mobile-First Estilo Bootstrap (`xs` até `xxl`)
123
+
124
+ Assim como no Bootstrap 5, o `v-tutorial` segue a filosofia **Mobile-First**. As propriedades base definidas no `<VTutorialStep>` valem a partir de `xs` (`0px`) para cima, e qualquer propriedade definida em um breakpoint maior herda para os seguintes até ser sobrescrita:
125
+
126
+ | Breakpoint | Largura Mínima Padrão | Props de Atalho Direto |
127
+ | :--- | :---: | :--- |
128
+ | `xs` *(base)* | `0px` | `target`, `placement` |
129
+ | `sm` | `576px` | `target-sm`, `placement-sm` |
130
+ | `md` | `768px` | `target-md`, `placement-md` |
131
+ | `lg` | `992px` | `target-lg`, `placement-lg` |
132
+ | `xl` | `1200px` | `target-xl`, `placement-xl` |
133
+ | `xxl` | `1400px` | `target-xxl`, `placement-xxl` |
134
+
135
+ ### 5.1. Usando Atalhos Diretos nas Props (`target-md`, `placement-md`)
136
+ Se no celular (`xs` e `sm`) o item do menu usa a classe `.mobile-system-link` e no computador (`md` em diante) usa `.sistema-item-row a.button`:
137
+
138
+ ```vue
139
+ <VTutorialStep
140
+ id="selecionar-sistema"
141
+ target=".mobile-system-link"
142
+ target-md=".sistema-item-row a.button"
143
+ placement="bottom-sheet"
144
+ placement-md="right"
145
+ title="Abra um Sistema Técnico"
146
+ mode="wait-click"
147
+ >
148
+ <p class="mb-0">Clique no primeiro sistema destacado para abri-lo.</p>
149
+ </VTutorialStep>
150
+ ```
151
+
152
+ ### 5.2. Passos Exclusivos de Mobile ou Desktop (`disabled: true` por Breakpoint)
153
+ Quer criar um passo que ensina o usuário do celular a abrir a aba deslizante `.super-slim-slider`, mas que seja pulado automaticamente em telas `md` (`>= 768px`)? Basta usar `:breakpoints`:
154
+
155
+ ```vue
156
+ <!-- Executa em xs e sm (< 768px) e é desabilitado automaticamente em md, lg, xl e xxl (>= 768px) -->
157
+ <VTutorialStep
158
+ id="abrir-gaveta-mobile"
159
+ target=".super-slim-slider"
160
+ placement="bottom-sheet"
161
+ title="Menu Lateral no Celular"
162
+ mode="wait-click"
163
+ :breakpoints="{
164
+ md: { disabled: true }
165
+ }"
166
+ >
167
+ <p class="mb-0">Toque na aba destacada para abrir a lista de sistemas.</p>
168
+ </VTutorialStep>
169
+ ```
170
+
171
+ ---
172
+
173
+ ## 6. Uso Declarativo (`<TutorialProvider>` + `<VTutorialStep>`)
174
+
175
+ Para manter a arquitetura limpa, deixe o componente `.vue` focado na declaração dos passos e isole os mapas de ações em um composable dedicado:
176
+
177
+ ```vue
178
+ <template>
179
+ <TutorialProvider>
180
+ <VTutorialStep
181
+ id="boas-vindas"
182
+ title="Bem-vindo!"
183
+ mode="info"
184
+ placement="center"
185
+ route="/"
186
+ :enter-actions="acoesBoasVindasBase"
187
+ :breakpoints="acoesBoasVindasDesktop"
188
+ >
189
+ <p class="mb-0">Este tutorial é <strong>100% interativo</strong>.</p>
190
+ </VTutorialStep>
191
+
192
+ <VTutorialStep
193
+ id="clicar-reportar"
194
+ target=".report-link"
195
+ placement="bottom-sheet"
196
+ placement-md="right"
197
+ title="Reportar Erro ou Sugestão"
198
+ mode="wait-click"
199
+ rollback-route="/"
200
+ :enter-actions="acoesAbrirMenuUsuario"
201
+ :rollback-actions="acoesAbrirMenuUsuario"
202
+ >
203
+ <p class="mb-0">Clique na opção <strong>"Reportar erro ou sugestão"</strong>.</p>
204
+ </VTutorialStep>
205
+ </TutorialProvider>
206
+ </template>
207
+ ```
208
+
209
+ ---
210
+
211
+ ## 7. Conectando Componentes Distintos (`registerAction` e `v-tutorial`)
212
+
213
+ ### 7.1. Expondo Ações de Estado (`registerAction`)
214
+ Qualquer componente pode registrar ações globais que os passos acionam via `enterActions`, `rollbackActions` ou `leaveActions`:
215
+
216
+ ```ts
217
+ // Dentro de UserInfo.vue
218
+ import { useTutorial } from 'v-tutorial'
219
+
220
+ const { registerAction } = useTutorial()
221
+
222
+ registerAction('openUserMenu', () => {
223
+ if (isMobile.value) {
224
+ isOpen.value = true
225
+ } else {
226
+ isDesktopModalOpen.value = true
227
+ }
228
+ })
229
+
230
+ registerAction('closeUserMenu', () => {
231
+ isOpen.value = false
232
+ isDesktopModalOpen.value = false
233
+ })
234
+ ```
235
+
236
+ ### 7.2. Botão de Reiniciar Tutorial no Modal de Configurações
237
+ Chame `restartTutorial()` de qualquer lugar para limpar o `localStorage` e reiniciar o treinamento imediatamente a partir do Passo 1:
238
+
239
+ ```ts
240
+ import { useTutorial } from 'v-tutorial'
241
+
242
+ const { restartTutorial } = useTutorial()
243
+
244
+ async function reiniciarTreinamentoSistema() {
245
+ emit('fecharModal')
246
+ await restartTutorial()
247
+ }
248
+ ```
249
+
250
+ ---
251
+
252
+ ## 8. Customização Visual, Dark Mode e Variáveis CSS
253
+
254
+ O `v-tutorial` herda variáveis do **Tabler / Bootstrap** (`--tblr-primary`, `--tblr-bg-surface`) automaticamente e adapta-se ao modo escuro (`[data-bs-theme="dark"]` ou `.dark`). Para customizar em qualquer projeto:
255
+
256
+ ```css
257
+ :root {
258
+ --v-tutorial-primary: #10b981;
259
+ --v-tutorial-bg: #ffffff;
260
+ --v-tutorial-bg-secondary: #f8fafc;
261
+ --v-tutorial-text: #0f172a;
262
+ --v-tutorial-muted: #64748b;
263
+ --v-tutorial-border: rgba(15, 23, 42, 0.12);
264
+ --v-tutorial-danger: #ef4444;
265
+ --v-tutorial-backdrop: rgba(10, 14, 23, 0.72);
266
+ --v-tutorial-radius: 16px;
267
+ --v-tutorial-z-index: 10040;
268
+ }
269
+ ```
270
+
271
+ ---
272
+
273
+ ## 9. Modo Headless UI e Scoped Slots
274
+
275
+ Ative `:unstyled="true"` ou substitua qualquer Scoped Slot no `<TutorialProvider>` (`#card`, `#header`, `#body`, `#hint`, `#progress`, `#footer`, `#exit-button`, `#spotlight`):
276
+
277
+ ```vue
278
+ <TutorialProvider>
279
+ <template #card="{ step, stepIndex, totalSteps, activeBreakpoint, nextStep, prevStep, endTutorial }">
280
+ <div class="meu-card-customizado p-4">
281
+ <small>Breakpoint: {{ activeBreakpoint }} | Passo {{ stepIndex + 1 }}/{{ totalSteps }}</small>
282
+ <h4>{{ step?.title }}</h4>
283
+ <div v-html="step?.content"></div>
284
+ <button v-if="stepIndex > 0" @click="prevStep">Anterior</button>
285
+ <button v-if="step?.mode !== 'wait-click'" @click="nextStep">Próximo</button>
286
+ <button @click="endTutorial(true)">Pular</button>
287
+ </div>
288
+ </template>
289
+ </TutorialProvider>
290
+ ```
291
+
292
+ ---
293
+
294
+ ## 10. Referência Completa da API
295
+
296
+ ### Props de `<VTutorialStep>` / Interface `TutorialStep`
297
+
298
+ | Propriedade | Tipo | Padrão | Descrição |
299
+ | :--- | :--- | :---: | :--- |
300
+ | `id` | `string` | Auto-gerado | Identificador único do passo. |
301
+ | `target` | `string \| string[]` | `undefined` | Seletor CSS base (`xs`), ID do `v-tutorial` ou array de seletores. |
302
+ | `targetSm`..`targetXxl` | `string \| string[]` | `undefined` | Sobrescrita Mobile-First do alvo para `sm`, `md`, `lg`, `xl`, `xxl`. |
303
+ | `placement` | `'auto' \| 'top' \| 'bottom' \| 'left' \| 'right' \| 'center' \| 'bottom-sheet' \| 'top-sheet'` | `'auto'` | Posicionamento base (`xs`) com prevenção automática de colisão. |
304
+ | `placementSm`..`placementXxl` | `TutorialPlacement` | `undefined` | Sobrescrita Mobile-First do posicionamento para `sm`, `md`, `lg`, `xl`, `xxl`. |
305
+ | `breakpoints` | `Partial<Record<TutorialBreakpointName, TutorialStepResponsiveOverride>>` | `undefined` | Objeto completo de sobrescrita Mobile-First por breakpoint (`disabled`, `enterActions`, `title`, etc.). |
306
+ | `disabled` | `boolean` | `false` | Ignora/pula o passo automaticamente se for `true` no breakpoint ativo. |
307
+ | `title` | `string` | **Obrigatório** | Título exibido no cabeçalho do card. |
308
+ | `mode` | `'info' \| 'wait-click' \| 'optional-click'` | `'info'` | Define o comportamento de avanço do passo. |
309
+ | `hintText` | `string` | `undefined` | Frase exibida na faixa pulsante de ação interativa. |
310
+ | `route` | `string` | `undefined` | Navega automaticamente para esta rota ao entrar no passo. |
311
+ | `rollbackRoute` | `string` | `undefined` | Rota para a qual retorna ao clicar em "Anterior". |
312
+ | `enterActions` | `Record<string, any> \| string[]` | `undefined` | Mapa de ações registradas executadas ao entrar no passo. |
313
+ | `rollbackActions` | `Record<string, any> \| string[]` | `undefined` | Mapa de ações registradas executadas ao voltar ("Anterior") para o passo. |
314
+ | `leaveActions` | `Record<string, any> \| string[]` | `undefined` | Mapa de ações registradas executadas ao sair do passo. |
315
+ | `afterClickDelay` | `number` | `280` | Tempo em `ms` após o clique no elemento antes de avançar. |
316
+ | `preventNativeClick` | `boolean` | `false` | Bloqueia a ação original do botão clicado durante o tutorial. |
317
+
318
+ ### Retorno do Composable `useTutorial()`
319
+
320
+ | Propriedade / Método | Tipo | Descrição |
321
+ | :--- | :--- | :--- |
322
+ | `isActive` | `Ref<boolean>` | Indica se o tutorial está ativo no momento. |
323
+ | `activeBreakpoint` | `ComputedRef<'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'xxl'>` | Nome do breakpoint Bootstrap ativo na janela atual. |
324
+ | `isMobileViewport` | `ComputedRef<boolean>` | `true` quando a largura da janela é menor que `md` (`< 768px`). |
325
+ | `currentStep` | `ComputedRef<TutorialStep \| null>` | Objeto do passo atual já resolvido para o breakpoint ativo. |
326
+ | `currentStepIndex` | `Ref<number>` | Índice numérico (base 0) do passo atual. |
327
+ | `totalSteps` | `ComputedRef<number>` | Quantidade total de passos habilitados no breakpoint atual. |
328
+ | `progress` | `ComputedRef<number>` | Porcentagem de conclusão (`0` a `100`). |
329
+ | `startTutorial(steps?, force?)` | `Promise<void>` | Inicia o tutorial (`force = true` ignora o `localStorage`). |
330
+ | `restartTutorial()` | `Promise<void>` | Limpa a flag do `localStorage` e reinicia imediatamente do Passo 1. |
331
+ | `nextStep()` / `prevStep()` | `Promise<void>` | Avança ou retorna um passo (acionando o rollback automaticamente). |
332
+ | `goToStep(indexOrId)` | `Promise<void>` | Pula diretamente para um passo pelo índice ou pelo `id`. |
333
+ | `endTutorial(markCompleted?)` | `void` | Fecha o tutorial imediatamente. |
334
+ | `registerAction(name, fn)` | `void` | Registra uma função nomeada que pode ser chamada pelos passos. |
335
+ | `onFinish` / `onStop` / `onStepChange` | `(cb) => () => void` | Listeners de ciclo de vida (limpos automaticamente no `onUnmounted`). |
336
+
337
+ ---
338
+
339
+ ## 📄 Licença
340
+
341
+ Distribuído sob a **Licença MIT**. Desenvolvido por [Márlon Bento Azevedo](https://github.com/marlon-bento).