@maltjoy/mcp-server 0.4.0 → 0.6.0-beta.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/LICENSE +21 -0
- package/README.md +30 -3
- package/dist/doc/VJoyAdminBanner/guideline.md +284 -0
- package/dist/doc/VJoyAvailability/guideline.md +352 -0
- package/dist/doc/VJoyAvatar/guideline.md +192 -0
- package/dist/doc/VJoyAvatarsList/guideline.md +328 -0
- package/dist/doc/VJoyBadge/guideline.md +169 -0
- package/dist/doc/VJoyBadgeLevel/guideline.md +166 -0
- package/dist/doc/VJoyBlockSkeleton/guideline.md +150 -0
- package/dist/doc/VJoyBottomSheet/guideline.md +345 -0
- package/dist/doc/VJoyBottomSheetTrigger/guideline.md +156 -0
- package/dist/doc/VJoyButton/guideline.md +371 -0
- package/dist/doc/VJoyButton/metadata.json +0 -16
- package/dist/doc/VJoyButtonCard/guideline.md +384 -0
- package/dist/doc/VJoyCheckbox/guideline.md +317 -0
- package/dist/doc/VJoyCheckboxCard/guideline.md +381 -0
- package/dist/doc/VJoyCheckboxGroup/guideline.md +363 -0
- package/dist/doc/VJoyCheckboxGroup/metadata.json +7 -7
- package/dist/doc/VJoyCollapse/guideline.md +362 -0
- package/dist/doc/VJoyCollapseItem/guideline.md +394 -0
- package/dist/doc/VJoyCompanyAvatar/guideline.md +162 -0
- package/dist/doc/VJoyDialog/guideline.md +425 -0
- package/dist/doc/VJoyDialogTrigger/guideline.md +186 -0
- package/dist/doc/VJoyDot/guideline.md +177 -0
- package/dist/doc/VJoyDrawer/guideline.md +392 -0
- package/dist/doc/VJoyDrawerTrigger/guideline.md +145 -0
- package/dist/doc/VJoyDropdown/guideline.md +393 -0
- package/dist/doc/VJoyDropdown/metadata.json +6 -6
- package/dist/doc/VJoyDropdownList/guideline.md +396 -0
- package/dist/doc/VJoyDropdownList/metadata.json +7 -7
- package/dist/doc/VJoyDropzone/guideline.md +390 -0
- package/dist/doc/VJoyDropzone/metadata.json +36 -1
- package/dist/doc/VJoyFilterBar/guideline.md +419 -0
- package/dist/doc/VJoyFilterBarButton/guideline.md +359 -0
- package/dist/doc/VJoyFloatingActionsBar/guideline.md +372 -0
- package/dist/doc/VJoyFormError/guideline.md +325 -0
- package/dist/doc/VJoyFormError/metadata.json +0 -14
- package/dist/doc/VJoyFormFieldSkeleton/guideline.md +159 -0
- package/dist/doc/VJoyFormGroup/guideline.md +285 -0
- package/dist/doc/VJoyFunnel/guideline.md +349 -0
- package/dist/doc/VJoyFunnelFooter/guideline.md +178 -0
- package/dist/doc/VJoyFunnelHeader/guideline.md +204 -0
- package/dist/doc/VJoyHighlight/guideline.md +169 -0
- package/dist/doc/VJoyIcon/JoyIcon.types.ts +1 -1
- package/dist/doc/VJoyIcon/guideline.md +168 -0
- package/dist/doc/VJoyIcon/metadata.json +0 -1
- package/dist/doc/VJoyIconButton/guideline.md +169 -0
- package/dist/doc/VJoyIconButton/metadata.json +1 -1
- package/dist/doc/VJoyIndicator/guideline.md +168 -0
- package/dist/doc/VJoyIndicators/guideline.md +183 -0
- package/dist/doc/VJoyInput/JoyInput.types.ts +1 -6
- package/dist/doc/VJoyInput/guideline.md +401 -0
- package/dist/doc/VJoyInput/metadata.json +5 -14
- package/dist/doc/VJoyInputDigit/guideline.md +381 -0
- package/dist/doc/VJoyInputNumber/guideline.md +414 -0
- package/dist/doc/VJoyInputNumber/metadata.json +22 -17
- package/dist/doc/VJoyInputPassword/guideline.md +379 -0
- package/dist/doc/VJoyInputPassword/metadata.json +0 -14
- package/dist/doc/VJoyLabel/guideline.md +200 -0
- package/dist/doc/VJoyLink/guideline.md +360 -0
- package/dist/doc/VJoyListItem/guideline.md +335 -0
- package/dist/doc/VJoyMenu/guideline.md +304 -0
- package/dist/doc/VJoyMenu/metadata.json +21 -21
- package/dist/doc/VJoyMenuItem/guideline.md +352 -0
- package/dist/doc/VJoyPagination/guideline.md +355 -0
- package/dist/doc/VJoyPanel/guideline.md +238 -0
- package/dist/doc/VJoyPanelSection/guideline.md +160 -0
- package/dist/doc/VJoyPasswordRequirement/guideline.md +336 -0
- package/dist/doc/VJoyPasswordRequirement/metadata.json +1 -1
- package/dist/doc/VJoyProductTour/JoyProductTour.types.ts +0 -1
- package/dist/doc/VJoyProductTour/guideline.md +455 -0
- package/dist/doc/VJoyProductTour/metadata.json +1 -1
- package/dist/doc/VJoyProductTourTrigger/guideline.md +167 -0
- package/dist/doc/VJoyProgressBar/guideline.md +348 -0
- package/dist/doc/VJoyRadio/guideline.md +346 -0
- package/dist/doc/VJoyRadioGroup/guideline.md +331 -0
- package/dist/doc/VJoyRatingStars/guideline.md +306 -0
- package/dist/doc/VJoyScreenLoader/guideline.md +172 -0
- package/dist/doc/VJoySelect/guideline.md +396 -0
- package/dist/doc/VJoySelectableItem/guideline.md +351 -0
- package/dist/doc/VJoySelectableItemGroup/guideline.md +370 -0
- package/dist/doc/VJoySeparator/guideline.md +161 -0
- package/dist/doc/VJoySnackbar/guideline.md +402 -0
- package/dist/doc/VJoySpinner/guideline.md +168 -0
- package/dist/doc/VJoyStep/guideline.md +182 -0
- package/dist/doc/VJoyStepper/guideline.md +390 -0
- package/dist/doc/VJoyTab/guideline.md +298 -0
- package/dist/doc/VJoyTabs/guideline.md +353 -0
- package/dist/doc/VJoyTag/guideline.md +226 -0
- package/dist/doc/VJoyTagsInput/guideline.md +387 -0
- package/dist/doc/VJoyTagsList/guideline.md +311 -0
- package/dist/doc/VJoyTagsList/metadata.json +27 -27
- package/dist/doc/VJoyTemplate/guideline.md +366 -0
- package/dist/doc/VJoyText/guideline.md +175 -0
- package/dist/doc/VJoyText/metadata.json +1 -1
- package/dist/doc/VJoyTextarea/guideline.md +378 -0
- package/dist/doc/VJoyTitleBrand/guideline.md +155 -0
- package/dist/doc/VJoyToggle/guideline.md +327 -0
- package/dist/doc/VJoyTooltip/guideline.md +322 -0
- package/dist/doc/VJoyUserCard/guideline.md +268 -0
- package/dist/doc/VJoyUserCard/metadata.json +3 -17
- package/dist/doc/VJoyWalkthrough/guideline.md +351 -0
- package/dist/doc/VJoyWalkthroughTrigger/guideline.md +171 -0
- package/dist/doc/VJoyWrapper/guideline.md +173 -0
- package/dist/doc/css-classes.json +1 -15
- package/dist/doc/design-tokens.json +1 -0
- package/dist/doc/index.json +20 -30
- package/dist/index.js +22 -2
- package/dist/index.js.map +1 -1
- package/dist/tools/get-component-guideline.d.ts +30 -0
- package/dist/tools/get-component-guideline.d.ts.map +1 -0
- package/dist/tools/get-component-guideline.js +51 -0
- package/dist/tools/get-component-guideline.js.map +1 -0
- package/dist/tools/get-documentation-page.d.ts +22 -0
- package/dist/tools/get-documentation-page.d.ts.map +1 -0
- package/dist/tools/get-documentation-page.js +21 -0
- package/dist/tools/get-documentation-page.js.map +1 -0
- package/dist/tools/list-documentation-pages.d.ts +22 -0
- package/dist/tools/list-documentation-pages.d.ts.map +1 -0
- package/dist/tools/list-documentation-pages.js +17 -0
- package/dist/tools/list-documentation-pages.js.map +1 -0
- package/dist/tools/search-documentation.d.ts +41 -0
- package/dist/tools/search-documentation.d.ts.map +1 -0
- package/dist/tools/search-documentation.js +25 -0
- package/dist/tools/search-documentation.js.map +1 -0
- package/dist/zeroheight-parser.d.ts +27 -0
- package/dist/zeroheight-parser.d.ts.map +1 -0
- package/dist/zeroheight-parser.js +77 -0
- package/dist/zeroheight-parser.js.map +1 -0
- package/package.json +10 -10
- package/dist/doc/VJoyMultiCheckbox/metadata.json +0 -332
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: VJoyProductTour
|
|
3
|
+
status: draft
|
|
4
|
+
language: en
|
|
5
|
+
dsds: JoyProductTour.dsds.json
|
|
6
|
+
dsdsVersion: "0.15.2"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Product tour
|
|
10
|
+
|
|
11
|
+
Use **`VJoyProductTour`** when you need a coachmark anchored to a page element — spotlight a control, explain a new feature, and offer dismiss or next-step actions without leaving the current view.
|
|
12
|
+
|
|
13
|
+
It teleports to `body`, positions itself with Floating UI around a `spotlightSelector` target, dims the page with an optional overlay, and exposes imperative `show()` / `hide()` methods. Pair with **`VJoyProductTourTrigger`** to open tours from buttons or to chain multi-step flows.
|
|
14
|
+
|
|
15
|
+
| | |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| **Code** | `VJoyProductTour`, `VJoyProductTourTrigger` from `@maltjoy/core-vue` |
|
|
18
|
+
| **Design** | [ZeroHeight — Product tour](https://zeroheight.com/6bf479565/p/68fc9a-product-tour) |
|
|
19
|
+
| **Storybook** | [VJoyProductTour docs](https://doc.malt.tech/joy-storybook/?path=/docs/components-overlays-vjoyproducttour--docs) |
|
|
20
|
+
| **DSDS (machine)** | [`JoyProductTour.dsds.json`](./JoyProductTour.dsds.json) |
|
|
21
|
+
| **Live API** | `joy_get_component_info("VJoyProductTour")` |
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## When to use this component
|
|
26
|
+
|
|
27
|
+
Use a product tour when you want to **draw attention to a specific UI element** and give short, contextual guidance — for example announcing a new toolbar action, explaining a first-time workflow step, or walking someone through a recently shipped feature.
|
|
28
|
+
|
|
29
|
+
The spotlight keeps the target visible while the card floats nearby. Footer CTAs support skip/dismiss and advancing to the next coachmark in a sequence (`step` / `steps` counter when `steps > 1`).
|
|
30
|
+
|
|
31
|
+
### When not to use this component
|
|
32
|
+
|
|
33
|
+
| Need | Use instead |
|
|
34
|
+
| --- | --- |
|
|
35
|
+
| Full-page onboarding with illustrations and a persistent walkthrough shell | `VJoyWalkthrough` |
|
|
36
|
+
| Blocking decision, form, or confirmation | `VJoyDialog` |
|
|
37
|
+
| Brief hover/focus hint on a single control | `VJoyTooltip` |
|
|
38
|
+
| Transient feedback after an action | `pushVJoySnackbar` |
|
|
39
|
+
| Custom coachmark / popover with ad-hoc CSS | Still use `VJoyProductTour` + Joy tokens — don't reinvent overlay chrome |
|
|
40
|
+
|
|
41
|
+
> **SSR (Nuxt):** wrap `VJoyProductTour` in `<ClientOnly>` so positioning and spotlight math run only in the browser. Storybook documents this constraint.
|
|
42
|
+
|
|
43
|
+
> **Not in the Vue API:** legacy Stencil `dismissed-by` (`all` \| `not-backdrop`) is **not** on `VJoyProductTour`. Backdrop click always dismisses when the overlay is enabled. Do not emit `dismissed-by`.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## How it works
|
|
48
|
+
|
|
49
|
+
`VJoyProductTour` is a thin wrapper that **teleports** `VJoyProductTourInner` to `body`, forwards slots, and registers the instance in a shared store so only one tour is open at a time. Calling `show()` on a new instance hides any previously open tour.
|
|
50
|
+
|
|
51
|
+
### Anatomy
|
|
52
|
+
|
|
53
|
+
| Part | Required? | What it is |
|
|
54
|
+
| --- | --- | --- |
|
|
55
|
+
| Teleport host | Yes | Renders the inner tour at `body` to escape stacking contexts |
|
|
56
|
+
| Overlay | No* | Full-viewport dimmer (`joy-product-tour__overlay`); backdrop click dismisses — *skipped when `disableOverlay` is true |
|
|
57
|
+
| Spotlight | Yes* | Highlight frame around the target element — *only when `show()` finds a matching `spotlightSelector` node in `document` |
|
|
58
|
+
| Card (`joy-product-tour`) | Yes | White panel with elevation, padding, and max width |
|
|
59
|
+
| Arrow | Yes | Rotated square positioned by Floating UI middleware |
|
|
60
|
+
| Banner (`product-tour-banner`) | No | Full-width image strip above the title |
|
|
61
|
+
| Preheader (`product-tour-preheader`) | No | Short meta row (e.g. `VJoyTag`); shares row with close control |
|
|
62
|
+
| Close button | No* | Top-right `VJoyIconButton` when `closeButton` is true — *default true |
|
|
63
|
+
| Header (`product-tour-header`) | Yes (content) | Tour title |
|
|
64
|
+
| Icon | No | Optional leading `VJoyIcon` beside title + body |
|
|
65
|
+
| Content (`product-tour-content`) | Yes (content) | Main explanatory copy |
|
|
66
|
+
| Footer | No* | Shown only when `product-tour-dismiss` and/or `product-tour-next` is provided |
|
|
67
|
+
| Dismiss CTA (`product-tour-dismiss`) | No | Left footer action; click bubbles to `hide()` |
|
|
68
|
+
| Step counter | No | `step/steps` text when `steps > 1` and footer is visible |
|
|
69
|
+
| Next CTA (`product-tour-next`) | No | Primary advance action — **does not** auto-hide; wire `hide()` or chain another tour |
|
|
70
|
+
|
|
71
|
+
### Default values
|
|
72
|
+
|
|
73
|
+
- `position` defaults to **`bottom`**
|
|
74
|
+
- `open` defaults to **`false`** (set `true` to open on mount)
|
|
75
|
+
- `steps` defaults to **`1`**
|
|
76
|
+
- `step` defaults to **`1`**
|
|
77
|
+
- `maxWidth` defaults to **`500`** (px; sets `--product-tour-width`)
|
|
78
|
+
- `disableOverlay` defaults to **`false`**
|
|
79
|
+
- `spotlightPadding` defaults to **`8`** (px around the highlighted element)
|
|
80
|
+
- `closeButton` defaults to **`true`**
|
|
81
|
+
- `spotlightSelector` is **required** — must be a valid `querySelector` string resolving to a single element
|
|
82
|
+
|
|
83
|
+
Props, events, slots, and exposed methods: use Joy MCP (`joy_get_component_info`, `joy_get_component_types`) or Storybook — this page focuses on **when** and **how**, not a full API dump.
|
|
84
|
+
|
|
85
|
+
### Open / close lifecycle
|
|
86
|
+
|
|
87
|
+
1. **Open** — set `open` or call `show()` on the component ref. `show()` only succeeds when `document.querySelector(spotlightSelector)` exists inside `document.body`. The store hides any other open tour, creates overlay + spotlight, and positions the card.
|
|
88
|
+
2. **Dismiss** — close icon, `product-tour-dismiss` click (bubbling), or overlay click (when overlay is enabled). All call inner `hide()` and emit `product-tour:hide`.
|
|
89
|
+
3. **Advance** — `product-tour-next` is manual: hide the current tour and open the next instance (often via `VJoyProductTourTrigger` pointing at another `VJoyProductTour` ref).
|
|
90
|
+
4. **Programmatic hide** — `hide()` on the wrapper clears the store and closes UI. Pass `{ fireHideEvent: true }` to emit `product-tour:hide` from the wrapper when the inner tour already hid without bubbling the event.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Variants
|
|
95
|
+
|
|
96
|
+
`VJoyProductTour` has **no color or emphasis variant**. Choose **`position`** by where there is room around the highlighted element — Floating UI may **flip** to `bottom`, `top`, `left`, or `right` when the preferred side lacks space.
|
|
97
|
+
|
|
98
|
+
### `bottom` (default)
|
|
99
|
+
|
|
100
|
+
Use when the target sits in the upper half of the viewport or when content should read below the control.
|
|
101
|
+
|
|
102
|
+
Avoid when the target is near the bottom edge — prefer `top`.
|
|
103
|
+
|
|
104
|
+
### `top`
|
|
105
|
+
|
|
106
|
+
Use when the target sits low on the page and the card should open upward.
|
|
107
|
+
|
|
108
|
+
Avoid when the target is under a fixed header that would collide with the card.
|
|
109
|
+
|
|
110
|
+
### `left` / `right`
|
|
111
|
+
|
|
112
|
+
Use when vertical placement is tight and horizontal space is available beside the target.
|
|
113
|
+
|
|
114
|
+
Avoid when the target is flush against the viewport edge on that side.
|
|
115
|
+
|
|
116
|
+
### Overlay modes
|
|
117
|
+
|
|
118
|
+
| Mode | Use when |
|
|
119
|
+
| --- | --- |
|
|
120
|
+
| Default overlay (`disableOverlay: false`) | Standard coachmarks — block interaction with the rest of the page |
|
|
121
|
+
| No overlay (`disableOverlay: true`) | The highlighted element (or a parent stacking context) must stay interactive; the page remains fully clickable |
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Sizes
|
|
126
|
+
|
|
127
|
+
`VJoyProductTour` has **no `size` prop**. Typography and spacing come from Joy tokens inside the component (`primary-650` header, `primary-300` body, `--joy-core-spacing-*`).
|
|
128
|
+
|
|
129
|
+
| Control | Use when |
|
|
130
|
+
| --- | --- |
|
|
131
|
+
| Default `maxWidth` (500) | Most in-product coachmarks |
|
|
132
|
+
| Custom `maxWidth` | Narrow side panels or wide banners that need more horizontal room |
|
|
133
|
+
| `spotlightPadding` | Extra breathing room around irregular targets (icons, avatars) |
|
|
134
|
+
|
|
135
|
+
**Don't** hardcode card width, shadow, or radius on `.joy-product-tour` in product CSS. Use `maxWidth` and Joy tokens.
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## States
|
|
140
|
+
|
|
141
|
+
| State | What the user sees / can do |
|
|
142
|
+
| --- | --- |
|
|
143
|
+
| Closed (default) | Inner wrapper hidden (`v-show`); no overlay or spotlight |
|
|
144
|
+
| Opening | Overlay + spotlight mount; card fades in; target `z-index` elevated |
|
|
145
|
+
| Open | Card anchored to target; overlay blocks background clicks (unless disabled) |
|
|
146
|
+
| Dismissing | Overlay/spotlight removed; target inline styles cleared; `product-tour:hide` fires |
|
|
147
|
+
| Multi-step | Footer shows `step/steps` when `steps > 1` and footer slots exist |
|
|
148
|
+
| No footer CTAs | No footer row — user relies on close icon and/or overlay dismiss |
|
|
149
|
+
| `open` on mount | Tour registers in the store and shows immediately (client only) |
|
|
150
|
+
| Missing target | `show()` is a no-op when the selector matches nothing |
|
|
151
|
+
|
|
152
|
+
Only one tour instance is active globally — opening another tour hides the previous one.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Best practices
|
|
157
|
+
|
|
158
|
+
Rules use RFC 2119 strength (**MUST** / **SHOULD** / **MUST NOT** / **SHOULD NOT**).
|
|
159
|
+
|
|
160
|
+
### When to show a tour
|
|
161
|
+
|
|
162
|
+
- **SHOULD** use product tours for **feature discovery** and **one-off education**, not for essential instructions the user cannot complete without.
|
|
163
|
+
- **SHOULD** keep each step focused on **one target element** and one idea.
|
|
164
|
+
- **SHOULD** let users dismiss at any time (close icon, dismiss CTA, or overlay).
|
|
165
|
+
- **MUST NOT** stack multiple unrelated coachmarks without a clear step counter and next action.
|
|
166
|
+
|
|
167
|
+
### Implementation
|
|
168
|
+
|
|
169
|
+
- **MUST** provide a stable `spotlightSelector` that resolves to exactly one element in the DOM before calling `show()`.
|
|
170
|
+
- **MUST** use only documented props and enums from MCP / `JoyProductTour.types.ts`.
|
|
171
|
+
- **MUST** teleport via the component (default) — don't nest the tour inside overflow/stacking contexts.
|
|
172
|
+
- **MUST** wrap usage in `<ClientOnly>` on SSR apps (Nuxt).
|
|
173
|
+
- **MUST NOT** invent props (`variant`, `size`, `dismissed-by`, …).
|
|
174
|
+
- **MUST NOT** override `.joy-product-tour` chrome (background, shadow, radius, z-index) in app CSS.
|
|
175
|
+
- **SHOULD** declare the tour as a `ref<InstanceType<typeof VJoyProductTour>>()` when using triggers or imperative APIs.
|
|
176
|
+
- **SHOULD** use `disableOverlay` only when a parent stacking context prevents correct dimming — document why for reviewers.
|
|
177
|
+
|
|
178
|
+
### Footer and chaining
|
|
179
|
+
|
|
180
|
+
- **MUST** wire `hide()` yourself on `product-tour-next` when advancing — the slot does not auto-close.
|
|
181
|
+
- **SHOULD** use `VJoyProductTourTrigger` inside `product-tour-next` to open the next tour ref.
|
|
182
|
+
- **SHOULD** provide `product-tour-dismiss` for skip / not-now paths in multi-step flows.
|
|
183
|
+
- **SHOULD** set `steps` and `step` when the footer is visible and the flow has more than one coachmark.
|
|
184
|
+
- **MUST NOT** show a step counter without footer CTAs — the counter only renders when a footer exists.
|
|
185
|
+
|
|
186
|
+
### Interaction
|
|
187
|
+
|
|
188
|
+
- **SHOULD** call `show()` after the target element is mounted (e.g. `onMounted`, route settled, data loaded).
|
|
189
|
+
- **SHOULD** listen to `product-tour:hide` to persist "seen" state and avoid re-showing dismissed tours.
|
|
190
|
+
- **SHOULD** use `hide({ fireHideEvent: true })` only when coordinating wrapper-level analytics without double emission.
|
|
191
|
+
|
|
192
|
+
### Do / don't
|
|
193
|
+
|
|
194
|
+
| Do | Don't |
|
|
195
|
+
| --- | --- |
|
|
196
|
+
| `ClientOnly` in Nuxt | Render tours during SSR |
|
|
197
|
+
| Unique, stable CSS selectors | Fragile selectors (`:nth-child` on dynamic lists) |
|
|
198
|
+
| `VJoyProductTourTrigger` for next step | Manual DOM queries to open the next card |
|
|
199
|
+
| `disableOverlay` for stacking edge cases | Disable overlay by default to "simplify" |
|
|
200
|
+
| `VJoyButton` in footer slots | Raw `<button>` with custom Joy-like CSS |
|
|
201
|
+
| One idea per coachmark | Long paragraphs that belong in help docs |
|
|
202
|
+
| Persist dismiss state | Re-open the same tour every visit |
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Content
|
|
207
|
+
|
|
208
|
+
Product tours are promotional and educational — copy can be slightly more joyful than neutral form labels, but each step must still be scannable.
|
|
209
|
+
|
|
210
|
+
### Title formula
|
|
211
|
+
|
|
212
|
+
**Short benefit or feature name** — state what the user can now do, not internal codenames:
|
|
213
|
+
|
|
214
|
+
- ✅ Share projects with your team
|
|
215
|
+
- ✅ Filter by availability
|
|
216
|
+
- ✅ New: AI job suggestions
|
|
217
|
+
|
|
218
|
+
### Body copy
|
|
219
|
+
|
|
220
|
+
- **SHOULD** keep body text to **1–3 short sentences**; link to help center for depth.
|
|
221
|
+
- **SHOULD** describe the **action** the user can take on the highlighted control.
|
|
222
|
+
- **MUST NOT** hide critical compliance or pricing information only inside a tour.
|
|
223
|
+
|
|
224
|
+
### Footer CTA rules
|
|
225
|
+
|
|
226
|
+
Follow `VJoyButton` content rules. Tour-specific expectations:
|
|
227
|
+
|
|
228
|
+
| Strength | Rule |
|
|
229
|
+
| --- | --- |
|
|
230
|
+
| **MUST** | Dismiss CTA is neutral — ✅ `Not now`, `Skip`, `Maybe later` |
|
|
231
|
+
| **MUST** | Primary next CTA names the outcome — ✅ `Got it`, `Show me`, `Next: filters` |
|
|
232
|
+
| **MUST NOT** | Generic first/last-step CTAs — ❌ `OK`, `Continue` alone on step 1 or the final step |
|
|
233
|
+
| **MUST NOT** | Guilt-trip dismiss — ❌ `No thanks`, `I don't care` |
|
|
234
|
+
| **SHOULD** | Match title wording in the primary CTA when advancing |
|
|
235
|
+
| **SHOULD** | Use `VJoyTag` in `product-tour-preheader` for `New`, `Beta`, etc. |
|
|
236
|
+
| **SHOULD** | Joyful tone on tours — still one clear primary action per step |
|
|
237
|
+
|
|
238
|
+
### Patterns
|
|
239
|
+
|
|
240
|
+
**Single coachmark** — Title + one sentence; optional `Got it` in `product-tour-next` or rely on close + overlay dismiss. Footer optional.
|
|
241
|
+
|
|
242
|
+
**Multi-step chain** — One `VJoyProductTour` per target; set `step` / `steps`; `product-tour-dismiss` = skip tour; `product-tour-next` + `VJoyProductTourTrigger` opens the next ref. Hide current tour before or when opening the next.
|
|
243
|
+
|
|
244
|
+
**Feature launch** — Optional `product-tour-banner` image; `icon` (e.g. `sparkles`) when it reinforces "new"; keep image `max-width: 100%` (default deep styles handle block images).
|
|
245
|
+
|
|
246
|
+
**Localized apps** — Translate all slot content. The built-in close `label` is `"Close"` (English) on `VJoyIconButton` — override via `closeButton={false}` and provide your own control if locale ≠ English.
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## Accessibility
|
|
251
|
+
|
|
252
|
+
Behaviors (what must happen), not slogans.
|
|
253
|
+
|
|
254
|
+
| Behavior | Expectation |
|
|
255
|
+
| --- | --- |
|
|
256
|
+
| Role | Card wrapper uses `role="tooltip"` — treat copy as descriptive context for the highlighted control |
|
|
257
|
+
| Name | Title from `product-tour-header`; body from `product-tour-content` |
|
|
258
|
+
| Close control | `VJoyIconButton` with `label="Close"` when `closeButton` is true |
|
|
259
|
+
| Keyboard | Footer CTAs are real `VJoyButton` / native buttons — must be keyboard activatable |
|
|
260
|
+
| Focus | Ensure the highlighted target remains reachable; don't trap focus inside the card unless product UX explicitly requires it |
|
|
261
|
+
| Overlay | Backdrop click dismisses — provide an equivalent keyboard dismiss path via close or dismiss CTA |
|
|
262
|
+
| Motion | Spotlight fade-in uses `--joy-transition-duration-default`; respect `prefers-reduced-motion` at app level if required |
|
|
263
|
+
| Single tour | Global store prevents multiple simultaneous coachmarks reducing cognitive load |
|
|
264
|
+
|
|
265
|
+
Target: **WCAG 2.2 AA** where the product requires it.
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## Examples
|
|
270
|
+
|
|
271
|
+
```vue
|
|
272
|
+
<script setup lang="ts">
|
|
273
|
+
import { onMounted, ref } from 'vue'
|
|
274
|
+
import {
|
|
275
|
+
VJoyProductTour,
|
|
276
|
+
VJoyProductTourTrigger,
|
|
277
|
+
VJoyButton,
|
|
278
|
+
VJoyTag,
|
|
279
|
+
} from '@maltjoy/core-vue'
|
|
280
|
+
|
|
281
|
+
const stepOne = ref<InstanceType<typeof VJoyProductTour>>()
|
|
282
|
+
const stepTwo = ref<InstanceType<typeof VJoyProductTour>>()
|
|
283
|
+
|
|
284
|
+
onMounted(() => {
|
|
285
|
+
// Optional: auto-open first step when target exists
|
|
286
|
+
stepOne.value?.show()
|
|
287
|
+
})
|
|
288
|
+
|
|
289
|
+
function onTourHide() {
|
|
290
|
+
// Persist "seen" in storage / API
|
|
291
|
+
}
|
|
292
|
+
</script>
|
|
293
|
+
|
|
294
|
+
<template>
|
|
295
|
+
<!-- Target on the page -->
|
|
296
|
+
<button type="button" class="highlight-filters">Filters</button>
|
|
297
|
+
|
|
298
|
+
<!-- Step 1 of 2 -->
|
|
299
|
+
<ClientOnly>
|
|
300
|
+
<VJoyProductTour
|
|
301
|
+
ref="stepOne"
|
|
302
|
+
spotlight-selector=".highlight-filters"
|
|
303
|
+
:step="1"
|
|
304
|
+
:steps="2"
|
|
305
|
+
position="right"
|
|
306
|
+
icon="sparkles"
|
|
307
|
+
@product-tour:hide="onTourHide"
|
|
308
|
+
>
|
|
309
|
+
<template #product-tour-preheader>
|
|
310
|
+
<VJoyTag label="New" variant="special" size="xsmall" />
|
|
311
|
+
</template>
|
|
312
|
+
<template #product-tour-header>Find freelancers faster</template>
|
|
313
|
+
<template #product-tour-content>
|
|
314
|
+
Use filters to narrow results by skills, rate, and availability.
|
|
315
|
+
</template>
|
|
316
|
+
<template #product-tour-dismiss>
|
|
317
|
+
<VJoyButton variant="ghost" size="small" label="Not now" />
|
|
318
|
+
</template>
|
|
319
|
+
<template #product-tour-next>
|
|
320
|
+
<VJoyProductTourTrigger :product-tour="stepTwo">
|
|
321
|
+
<VJoyButton
|
|
322
|
+
variant="main"
|
|
323
|
+
size="small"
|
|
324
|
+
label="Next: shortlist"
|
|
325
|
+
@click="stepOne?.hide()"
|
|
326
|
+
/>
|
|
327
|
+
</VJoyProductTourTrigger>
|
|
328
|
+
</template>
|
|
329
|
+
</VJoyProductTour>
|
|
330
|
+
|
|
331
|
+
<!-- Step 2 -->
|
|
332
|
+
<VJoyProductTour
|
|
333
|
+
ref="stepTwo"
|
|
334
|
+
spotlight-selector=".highlight-shortlist"
|
|
335
|
+
:step="2"
|
|
336
|
+
:steps="2"
|
|
337
|
+
position="bottom"
|
|
338
|
+
>
|
|
339
|
+
<template #product-tour-header>Save your favorites</template>
|
|
340
|
+
<template #product-tour-content>
|
|
341
|
+
Add profiles to your shortlist to compare and contact later.
|
|
342
|
+
</template>
|
|
343
|
+
<template #product-tour-next>
|
|
344
|
+
<VJoyButton
|
|
345
|
+
variant="main"
|
|
346
|
+
size="small"
|
|
347
|
+
label="Got it"
|
|
348
|
+
@click="stepTwo?.hide()"
|
|
349
|
+
/>
|
|
350
|
+
</template>
|
|
351
|
+
</VJoyProductTour>
|
|
352
|
+
</ClientOnly>
|
|
353
|
+
</template>
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
In Nuxt (or apps with auto-import), omit imports if components are already global. Keep `<ClientOnly>` around teleported tours.
|
|
357
|
+
|
|
358
|
+
---
|
|
359
|
+
|
|
360
|
+
## Related
|
|
361
|
+
|
|
362
|
+
| Component | Use when |
|
|
363
|
+
| --- | --- |
|
|
364
|
+
| `VJoyProductTourTrigger` | Declarative activator that calls `show()` on a tour ref |
|
|
365
|
+
| `VJoyWalkthrough` | Full onboarding modal with progress, not element anchoring |
|
|
366
|
+
| `VJoyDialog` | Blocking decisions or forms |
|
|
367
|
+
| `VJoyTooltip` | Lightweight hover/focus hints |
|
|
368
|
+
| `VJoyButton` | Footer dismiss / next CTAs |
|
|
369
|
+
| `VJoyIconButton` | Built-in close control |
|
|
370
|
+
| `VJoyTag` | Preheader badges (`New`, `Beta`) |
|
|
371
|
+
| `VJoyIcon` | Optional leading icon in content |
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
## For agents
|
|
376
|
+
|
|
377
|
+
Optional for readers; **required** for vibe-coding quality. Maps to `agentDocumentBlocks` in [`JoyProductTour.dsds.json`](./JoyProductTour.dsds.json).
|
|
378
|
+
|
|
379
|
+
### Pick the right component
|
|
380
|
+
|
|
381
|
+
| If the intent is… | Emit… | Do not emit… |
|
|
382
|
+
| --- | --- | --- |
|
|
383
|
+
| Coachmark on a specific DOM element | `VJoyProductTour` | `VJoyDialog` centered on screen |
|
|
384
|
+
| Full onboarding walkthrough shell | `VJoyWalkthrough` | `VJoyProductTour` without a target |
|
|
385
|
+
| Hover hint on one control | `VJoyTooltip` | `VJoyProductTour` |
|
|
386
|
+
| Open tour from a button | `VJoyProductTour` + `VJoyProductTourTrigger` | `@click` that toggles custom popover CSS |
|
|
387
|
+
| Multi-step anchored tour | Multiple `VJoyProductTour` refs + triggers | One tour with changing `spotlightSelector` without hide/show |
|
|
388
|
+
| Nuxt / SSR app | `<ClientOnly>` + `VJoyProductTour` | Bare tour in server-rendered template |
|
|
389
|
+
|
|
390
|
+
### Hard rules
|
|
391
|
+
|
|
392
|
+
1. **MUST** call `joy_get_component_info("VJoyProductTour")` and/or `joy_get_component_types("VJoyProductTour")` (or read `JoyProductTour.types.ts`) before generating props.
|
|
393
|
+
2. **MUST** set `spotlight-selector` (required) to a valid CSS selector string.
|
|
394
|
+
3. **MUST** wrap tours in `<ClientOnly>` when the app uses SSR (Nuxt).
|
|
395
|
+
4. **MUST** call `hide()` on the current tour when advancing via `product-tour-next`.
|
|
396
|
+
5. **MUST NOT** invent props (`variant`, `size`, `dismissed-by`, …).
|
|
397
|
+
6. **MUST NOT** override `.joy-product-tour` / `.joy-product-tour__overlay` z-index, shadow, or background in app CSS.
|
|
398
|
+
7. **SHOULD** use `ref<InstanceType<typeof VJoyProductTour>>()` for imperative `show()` / `hide()`.
|
|
399
|
+
8. **SHOULD** provide `product-tour-dismiss` and/or close button for dismiss paths.
|
|
400
|
+
9. **SHOULD** set `step` and `steps` when footer CTAs exist and the flow has multiple coachmarks.
|
|
401
|
+
|
|
402
|
+
### Valid enums (from `JoyProductTour.types.ts`)
|
|
403
|
+
|
|
404
|
+
| Prop | Values |
|
|
405
|
+
| --- | --- |
|
|
406
|
+
| `position` | `left`, `right`, `top`, `bottom` |
|
|
407
|
+
| `icon` | Any `TJoyIconsNames` value (see Joy Icon docs / MCP) |
|
|
408
|
+
| `closeButton` | `true`, `false` |
|
|
409
|
+
| `open` | `true`, `false` |
|
|
410
|
+
| `disableOverlay` | `true`, `false` |
|
|
411
|
+
| `spotlightSelector` | Non-empty CSS selector string (required) |
|
|
412
|
+
| `maxWidth`, `spotlightPadding`, `step`, `steps` | Numbers |
|
|
413
|
+
|
|
414
|
+
### Slot checklist
|
|
415
|
+
|
|
416
|
+
- [ ] `product-tour-header` — title present
|
|
417
|
+
- [ ] `product-tour-content` — main copy present
|
|
418
|
+
- [ ] `product-tour-preheader` — only for tags / short meta
|
|
419
|
+
- [ ] `product-tour-banner` — only when an image adds context
|
|
420
|
+
- [ ] `product-tour-dismiss` — skip / not-now in multi-step flows
|
|
421
|
+
- [ ] `product-tour-next` — primary advance (+ manual `hide()` or chained trigger)
|
|
422
|
+
|
|
423
|
+
### Generation checklist
|
|
424
|
+
|
|
425
|
+
- [ ] Correct component (`VJoyProductTour` or named alternative)
|
|
426
|
+
- [ ] Props / enums from MCP or types only
|
|
427
|
+
- [ ] `spotlight-selector` targets an element that exists before `show()`
|
|
428
|
+
- [ ] `<ClientOnly>` when SSR
|
|
429
|
+
- [ ] No invented props / no custom tour chrome CSS
|
|
430
|
+
- [ ] Dismiss path defined (close, dismiss slot, and/or overlay)
|
|
431
|
+
- [ ] `product-tour-next` wires `hide()` when chaining
|
|
432
|
+
- [ ] Footer CTAs use `VJoyButton` with outcome-based labels
|
|
433
|
+
- [ ] `step` / `steps` set when `steps > 1` and footer is used
|
|
434
|
+
- [ ] `product-tour:hide` handled to persist seen state
|
|
435
|
+
|
|
436
|
+
---
|
|
437
|
+
|
|
438
|
+
## DSDS mapping
|
|
439
|
+
|
|
440
|
+
This Markdown mirrors [`JoyProductTour.dsds.json`](./JoyProductTour.dsds.json) (DSDS **0.15.2**).
|
|
441
|
+
|
|
442
|
+
| Section here | DSDS block |
|
|
443
|
+
| --- | --- |
|
|
444
|
+
| When to use / not | `use-cases` |
|
|
445
|
+
| Anatomy | `anatomy` |
|
|
446
|
+
| Variants (position / overlay) | `variants` |
|
|
447
|
+
| Sizes (`maxWidth`, padding) | `variants` / `design-specifications` |
|
|
448
|
+
| States | `states` |
|
|
449
|
+
| Best practices / content rules | `guidelines` (+ `content`) |
|
|
450
|
+
| Accessibility | `accessibility` |
|
|
451
|
+
| Examples | `sections` |
|
|
452
|
+
| For agents | `agentDocumentBlocks` |
|
|
453
|
+
| Props detail | `api` in JSON + Joy MCP |
|
|
454
|
+
| Imports | `imports` in JSON |
|
|
455
|
+
| Token sizing | `design-specifications` in JSON (`--product-tour-width`, z-index tokens) |
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: VJoyProductTourTrigger
|
|
3
|
+
status: draft
|
|
4
|
+
language: en
|
|
5
|
+
dsds: JoyProductTourTrigger.dsds.json
|
|
6
|
+
dsdsVersion: "0.15.2"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Product tour trigger
|
|
10
|
+
|
|
11
|
+
Use **`VJoyProductTourTrigger`** when a control in the page should open a linked **`VJoyProductTour`** — for example a “Show me around” button or a “Next” action inside a tour step.
|
|
12
|
+
|
|
13
|
+
The trigger renders whatever you place in its default slot (usually `VJoyButton`), emits `click`, then calls `show()` on the `productTour` ref. Same composition pattern as `VJoyDialogTrigger` and `VJoyDrawerTrigger`.
|
|
14
|
+
|
|
15
|
+
| | |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| **Code** | `VJoyProductTourTrigger` from `@maltjoy/core-vue` |
|
|
18
|
+
| **Design** | [Figma — Joy Core Design System](https://www.figma.com/design/jfndp2QBJGS9yeuWbeGuvD/) |
|
|
19
|
+
| **Storybook** | [VJoyProductTour docs](https://doc.malt.tech/joy-storybook/?path=/docs/components-overlays-vjoyproducttour--docs) (subcomponent) |
|
|
20
|
+
| **DSDS (machine)** | [`JoyProductTourTrigger.dsds.json`](./JoyProductTourTrigger.dsds.json) |
|
|
21
|
+
| **Live API** | `joy_get_component_info("VJoyProductTourTrigger")` |
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## When to use this component
|
|
26
|
+
|
|
27
|
+
Use this trigger when opening a product tour should stay **declative** — wrap the activator, pass the tour’s template ref, and let the component wire the click handler.
|
|
28
|
+
|
|
29
|
+
Typical jobs: a page-level “Start tour” button, or a “Next” CTA inside `product-tour-next` that opens the following `VJoyProductTour` instance.
|
|
30
|
+
|
|
31
|
+
Declare `VJoyProductTour` with `ref` and pass that ref to `:product-tour`. The trigger uses a computed ref so `show()` runs once the tour component is mounted, even if the ref is briefly `undefined` during setup.
|
|
32
|
+
|
|
33
|
+
### When not to use this component
|
|
34
|
+
|
|
35
|
+
| Need | Use instead |
|
|
36
|
+
| --- | --- |
|
|
37
|
+
| Open the tour from code (route guard, timer, feature flag) | `productTourRef.show()` on the `VJoyProductTour` ref |
|
|
38
|
+
| Configure tour content, spotlight, or steps | `VJoyProductTour` props and slots — not the trigger |
|
|
39
|
+
| Collapsible in-page walkthrough with built-in chrome | `VJoyWalkthrough` (+ its trigger) |
|
|
40
|
+
| Short hover hint on one control | `VJoyTooltip` |
|
|
41
|
+
| Legacy Stencil `product-tour` string ID / `step` / `target` attrs | Vue API: component **ref** via `:product-tour` — those attrs are not on `VJoyProductTourTrigger` |
|
|
42
|
+
| Custom click wrapper with ad-hoc markup | Still use `VJoyProductTourTrigger` + Joy trigger components |
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## How it works
|
|
47
|
+
|
|
48
|
+
### Anatomy
|
|
49
|
+
|
|
50
|
+
| Part | Required? | What it is |
|
|
51
|
+
| --- | --- | --- |
|
|
52
|
+
| Trigger host | Yes | Renders each root vnode from the default slot and listens for `click` |
|
|
53
|
+
| Default slot | Yes | The activator UI — most often `VJoyButton` |
|
|
54
|
+
| `productTour` prop | No* | Template ref to `VJoyProductTour`; when set, `show()` is called after `click` |
|
|
55
|
+
|
|
56
|
+
\*Omitting or leaving `productTour` unset still emits `click` without throwing; the tour simply does not open.
|
|
57
|
+
|
|
58
|
+
### Default values
|
|
59
|
+
|
|
60
|
+
- `productTour` defaults to **`undefined`** (no tour opened until a ref is passed)
|
|
61
|
+
- No `variant`, `size`, or styling props — appearance comes entirely from the default slot
|
|
62
|
+
|
|
63
|
+
Props and events: use Joy MCP or Storybook — this page focuses on **when** and **how**, not a full API dump.
|
|
64
|
+
|
|
65
|
+
### Click flow
|
|
66
|
+
|
|
67
|
+
1. User activates the slotted control.
|
|
68
|
+
2. `VJoyProductTourTrigger` emits **`click`**.
|
|
69
|
+
3. If `productTour` resolves to a mounted instance, it calls **`show()`** on that ref (which registers the tour in the product-tour store and displays the overlay).
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Best practices
|
|
74
|
+
|
|
75
|
+
Rules use RFC 2119 strength (**MUST** / **SHOULD** / **MUST NOT** / **SHOULD NOT**).
|
|
76
|
+
|
|
77
|
+
### Implementation
|
|
78
|
+
|
|
79
|
+
- **MUST** declare `VJoyProductTour` with a template `ref` and pass it to `:product-tour`.
|
|
80
|
+
- **MUST** use only documented props from MCP / component types (`productTour` only).
|
|
81
|
+
- **MUST NOT** invent legacy Stencil props (`step`, `target`, string `product-tour` id).
|
|
82
|
+
- **SHOULD** put a `VJoyButton` (or other focusable control) in the default slot — the trigger adds no chrome of its own.
|
|
83
|
+
- **SHOULD** wrap `VJoyProductTour` usage in **`ClientOnly`** in SSR apps (Nuxt) to avoid positioning issues — see `VJoyProductTour` Storybook notes.
|
|
84
|
+
- **MAY** listen to `@click` for analytics or side effects before the tour opens.
|
|
85
|
+
|
|
86
|
+
### Do / don’t
|
|
87
|
+
|
|
88
|
+
| Do | Don’t |
|
|
89
|
+
| --- | --- |
|
|
90
|
+
| `ref` on `VJoyProductTour` + `:product-tour="tourRef"` | String tour id from the old Stencil API |
|
|
91
|
+
| `VJoyButton` in the default slot | Expect the trigger to ship its own button styles |
|
|
92
|
+
| `productTourRef.show()` when opening imperatively | Empty wrapper when a plain `@click` on your button is enough |
|
|
93
|
+
| Nest a trigger in `product-tour-next` for chained tours | Use for non-tour overlays (`VJoyDialog`, `VJoyDrawer`) |
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Accessibility
|
|
98
|
+
|
|
99
|
+
Behaviors (what must happen), not slogans.
|
|
100
|
+
|
|
101
|
+
| Behavior | Expectation |
|
|
102
|
+
| --- | --- |
|
|
103
|
+
| Role | No role on the wrapper — the slotted control defines semantics (`button`, `a`, …) |
|
|
104
|
+
| Name | **MUST** give the slot trigger an accessible name (`label` on `VJoyButton`, visible text, or `aria-label`) |
|
|
105
|
+
| Keyboard | **MUST** use a keyboard-activatable slotted control; native `<button>` or `VJoyButton` is preferred |
|
|
106
|
+
| Focus | Opening the tour does not move focus by itself — ensure tour content manages focus when shown (`VJoyProductTour`) |
|
|
107
|
+
| Click-only divs | **MUST NOT** use non-interactive elements as the sole activator without keyboard support |
|
|
108
|
+
|
|
109
|
+
Target: **WCAG 2.2 AA** where the product requires it.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Examples
|
|
114
|
+
|
|
115
|
+
```vue
|
|
116
|
+
<script setup lang="ts">
|
|
117
|
+
import { ref } from 'vue'
|
|
118
|
+
import { VJoyProductTour, VJoyProductTourTrigger, VJoyButton } from '@maltjoy/core-vue'
|
|
119
|
+
|
|
120
|
+
const productTour = ref<InstanceType<typeof VJoyProductTour>>()
|
|
121
|
+
const productTour2 = ref<InstanceType<typeof VJoyProductTour>>()
|
|
122
|
+
</script>
|
|
123
|
+
|
|
124
|
+
<template>
|
|
125
|
+
<VJoyProductTourTrigger :product-tour="productTour">
|
|
126
|
+
<VJoyButton label="Show product tour" variant="main" />
|
|
127
|
+
</VJoyProductTourTrigger>
|
|
128
|
+
|
|
129
|
+
<VJoyProductTour
|
|
130
|
+
ref="productTour"
|
|
131
|
+
spotlight-selector=".highlight-target"
|
|
132
|
+
:step="1"
|
|
133
|
+
:steps="2"
|
|
134
|
+
>
|
|
135
|
+
<template #product-tour-header>New feature</template>
|
|
136
|
+
<template #product-tour-content>Short explanation of what changed.</template>
|
|
137
|
+
<template #product-tour-next>
|
|
138
|
+
<VJoyProductTourTrigger :product-tour="productTour2">
|
|
139
|
+
<VJoyButton label="Next" variant="main" size="small" />
|
|
140
|
+
</VJoyProductTourTrigger>
|
|
141
|
+
</template>
|
|
142
|
+
</VJoyProductTour>
|
|
143
|
+
|
|
144
|
+
<VJoyProductTour ref="productTour2" spotlight-selector=".other-target" :step="2" :steps="2">
|
|
145
|
+
<template #product-tour-header>Step two</template>
|
|
146
|
+
<template #product-tour-content>Continue the tour here.</template>
|
|
147
|
+
</VJoyProductTour>
|
|
148
|
+
|
|
149
|
+
<span class="highlight-target">Feature to highlight</span>
|
|
150
|
+
</template>
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
In Nuxt (or apps with auto-import), omit the import if components are already global. Wrap `VJoyProductTour` in `<ClientOnly>` when using SSR.
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Related
|
|
158
|
+
|
|
159
|
+
| Component | Use when |
|
|
160
|
+
| --- | --- |
|
|
161
|
+
| `VJoyProductTour` | Spotlight overlay, steps, banner, and dismiss/next slots |
|
|
162
|
+
| `VJoyDialogTrigger` | Same ref-based trigger pattern for dialogs |
|
|
163
|
+
| `VJoyDrawerTrigger` | Same pattern for drawers |
|
|
164
|
+
| `VJoyBottomSheetTrigger` | Same pattern for bottom sheets |
|
|
165
|
+
| `VJoyWalkthrough` | Collapsible guided tour with built-in trigger chrome |
|
|
166
|
+
| `VJoyButton` | Default activator inside the trigger slot |
|
|
167
|
+
| `VJoyTooltip` | Brief contextual help — not a product tour |
|