Conversation
851e1e4 to
7043001
Compare
1573ee3 to
a117d59
Compare
commit: |
|
This looks really cool! |
a117d59 to
1830fbd
Compare
1830fbd to
c08486c
Compare
|
Love it! |
c08486c to
26f6459
Compare
|
@benjamincanac what about this one? I know this implementation is a challenge, but maybe we can get a very basic but functional initial version. It's a very interesting component to have integrated into Nuxt. I'll probably need some help finalizing it with a code review. |
|
Overlay effect [NEW] Registrazione.schermo.2026-02-14.alle.11.19.14.movI think it's stable now @benjamincanac |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds a new Tour feature: a runtime Tour.vue component with TypeScript types and theme styles, localized strings for many locales, utilities for locale fallback, and examples/docs/playground pages demonstrating usage (basic, custom labels, loop, modal, overlay). Exposes the Tour export in runtime types and theme index, updates theme with tour styles, and adds tests for the Tour component. Several documentation and example Vue SFCs plus a new docs page and a playground route were added. Minor navigation update includes adding a "tour" entry. Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Note
Due to the large number of review comments, Critical severity comments were prioritized as inline comments.
🤖 Fix all issues with AI agents
In `@src/runtime/locale/sv.ts`:
- Around line 130-135: The tour strings in the locale files (e.g., the tour
object in sv.ts with keys next, previous, finish, close) are still in English;
update the values for tour.next, tour.previous, tour.finish and tour.close in
sv.ts (and replicate fixes across the other non-English locale files) to their
correct Swedish translations (or pull verified translations from your i18n
source/translator). Ensure you update the tour object in each locale file (not
just carousel.dots), run i18n validation/tests, and commit the translated
strings so the UI displays localized tour controls.
🟠 Major comments (26)
src/runtime/locale/kk.ts-130-135 (1)
130-135:⚠️ Potential issue | 🟠 MajorTour labels are not translated across 58 locales.
The
tourlabels in this and nearly all non-English locale files remain in English. Onlyen.tsanden_gb.tscorrectly have English; all other 58 locale files need translations fornext,previous,finish, andclose.Affected locales include: kk, sk, ru, th, and 54 others (ar, bg, bn, ca, cs, de, es, fr, ja, ko, pt, zh_cn, etc.).
Translate the tour labels before merging, or defer the entire tour feature to a separate localization pass.
src/runtime/locale/bg.ts-130-135 (1)
130-135:⚠️ Potential issue | 🟠 MajorTour strings are not translated to Bulgarian.
Same issue as the other locale files — English placeholders instead of Bulgarian translations. Compare with
carousel.next: 'Напред'.Suggested translations (verify with a native speaker)
tour: { - next: 'Next', - previous: 'Previous', - finish: 'Finish', - close: 'Skip' + next: 'Напред', + previous: 'Назад', + finish: 'Завърши', + close: 'Пропусни' }src/runtime/locale/it.ts-130-135 (1)
130-135:⚠️ Potential issue | 🟠 MajorTour strings are not translated to Italian.
English placeholders instead of Italian. Compare with
carousel.next: 'Successiva'.Suggested translations (verify with a native speaker)
tour: { - next: 'Next', - previous: 'Previous', - finish: 'Finish', - close: 'Skip' + next: 'Avanti', + previous: 'Indietro', + finish: 'Fine', + close: 'Salta' }src/runtime/locale/tr.ts-130-135 (1)
130-135:⚠️ Potential issue | 🟠 MajorTour strings are not translated to Turkish.
All four values are English placeholders. Compare with the rest of this file (e.g.,
carousel.next: 'Sonraki',carousel.prev: 'Önceki'). These should be translated to Turkish.Suggested translations (verify with a native speaker)
tour: { - next: 'Next', - previous: 'Previous', - finish: 'Finish', - close: 'Skip' + next: 'Sonraki', + previous: 'Önceki', + finish: 'Bitir', + close: 'Atla' }src/runtime/locale/mn.ts-130-135 (1)
130-135:⚠️ Potential issue | 🟠 MajorTour strings are not translated to Mongolian.
English placeholders instead of Mongolian. Compare with
carousel.next: 'Дараах'.Suggested translations (verify with a native speaker)
tour: { - next: 'Next', - previous: 'Previous', - finish: 'Finish', - close: 'Skip' + next: 'Дараах', + previous: 'Өмнөх', + finish: 'Дуусгах', + close: 'Алгасах' }src/runtime/locale/he.ts-131-135 (1)
131-135:⚠️ Potential issue | 🟠 MajorTour strings are not translated to Hebrew.
English placeholders instead of Hebrew. Compare with
carousel.next: 'הבא'.Suggested translations (verify with a native speaker)
tour: { - next: 'Next', - previous: 'Previous', - finish: 'Finish', - close: 'Skip' + next: 'הבא', + previous: 'הקודם', + finish: 'סיום', + close: 'דלג' }src/runtime/locale/lo.ts-130-134 (1)
130-134:⚠️ Potential issue | 🟠 MajorTour strings are not translated to Lao and across nearly all non-English locales.
The
tourobject in this file contains English placeholders instead of Lao translations, while all other messages are properly localized in Lao (ລາວ). This is a systemic issue affecting 58 non-English locale files in the repository—only the Belarusian locale has translated tour strings.Proposed fix for Lao:
Translate tour strings
tour: { - next: 'Next', - previous: 'Previous', - finish: 'Finish', - close: 'Skip' + next: 'ຕໍ່ໄປ', + previous: 'ກ່ອນໜ້າ', + finish: 'ສຳເລັດ', + close: 'ຂ້າມ' }Use the carousel translations already in this file (
ຕໍ່ໄປfor "next" andກ່ອນໜ້າfor "previous") for consistency.src/runtime/locale/zh_tw.ts-130-134 (1)
130-134:⚠️ Potential issue | 🟠 MajorTranslate tour strings in all affected locale files.
The
tourobject in zh_tw.ts (lines 130-134) and 6 other locale files (pt, ar, uk, ko, ug_cn, hu, lb) contains only English text, while every other section in these files is properly localized. This breaks i18n for the tour feature and leaves non-English users with untranslated UI elements.Proposed fix for zh_tw.ts
tour: { - next: 'Next', - previous: 'Previous', - finish: 'Finish', - close: 'Skip' + next: '下一步', + previous: '上一步', + finish: '完成', + close: '跳過' }src/runtime/locale/hy.ts-130-134 (1)
130-134:⚠️ Potential issue | 🟠 MajorTour labels are not translated into Armenian.
All four
tourvalues are English placeholders. Every other section in this file uses Armenian translations. These should be localized to match (e.g.,next: 'Հաջորդ',previous: 'Նախորդ',finish: 'Ավdelays',close: 'Բաdelays').src/runtime/locale/zh_cn.ts-130-134 (1)
130-134:⚠️ Potential issue | 🟠 MajorTour labels are not translated into Simplified Chinese.
All four values are English placeholders. Every other section uses Chinese translations. These should be localized, e.g.:
Suggested translations
tour: { - next: 'Next', - previous: 'Previous', - finish: 'Finish', - close: 'Skip' + next: '下一步', + previous: '上一步', + finish: '完成', + close: '跳过' }src/runtime/locale/pt_br.ts-130-134 (1)
130-134:⚠️ Potential issue | 🟠 MajorTour labels are not translated into Brazilian Portuguese.
All four values are English. Based on existing patterns (e.g.,
carousel.next: 'Próximo',carousel.prev: 'Anterior',modal.close: 'Fechar'), these should be localized, e.g.:Suggested translations
tour: { - next: 'Next', - previous: 'Previous', - finish: 'Finish', - close: 'Skip' + next: 'Próximo', + previous: 'Anterior', + finish: 'Concluir', + close: 'Pular' }src/runtime/locale/sq.ts-130-134 (1)
130-134:⚠️ Potential issue | 🟠 MajorTour labels are not translated into Albanian.
All four values are English placeholders. Every other section in this file uses Albanian translations. These should be localized, e.g.:
Suggested translations
tour: { - next: 'Next', - previous: 'Previous', - finish: 'Finish', - close: 'Skip' + next: 'Tjetri', + previous: 'Para', + finish: 'Përfundo', + close: 'Kalo' }src/runtime/locale/eu.ts-130-134 (1)
130-134:⚠️ Potential issue | 🟠 MajorTour labels are not translated into Basque.
All four values are English. Based on existing patterns (e.g.,
carousel.next: 'Hurrengoa',carousel.prev: 'Aurretikoa',modal.close: 'Itxi'), these should be localized, e.g.:Suggested translations
tour: { - next: 'Next', - previous: 'Previous', - finish: 'Finish', - close: 'Skip' + next: 'Hurrengoa', + previous: 'Aurretikoa', + finish: 'Amaitu', + close: 'Saltatu' }src/runtime/locale/fi.ts-130-134 (1)
130-134:⚠️ Potential issue | 🟠 MajorTour labels are not translated into Finnish.
All four values are English. Based on existing patterns (e.g.,
carousel.next: 'Seuraava',carousel.prev: 'Edellinen',modal.close: 'Sulje'), these should be localized, e.g.:Suggested translations
tour: { - next: 'Next', - previous: 'Previous', - finish: 'Finish', - close: 'Skip' + next: 'Seuraava', + previous: 'Edellinen', + finish: 'Valmis', + close: 'Ohita' }src/runtime/locale/ckb.ts-131-135 (1)
131-135:⚠️ Potential issue | 🟠 MajorTour labels are not translated into Central Kurdish.
All four values are English. Every other section uses Kurdish script. Based on existing patterns (e.g.,
carousel.next: 'دواتر',carousel.prev: 'پێشتر',modal.close: 'داخستن'), these should be localized, e.g.:Suggested translations
tour: { - next: 'Next', - previous: 'Previous', - finish: 'Finish', - close: 'Skip' + next: 'دواتر', + previous: 'پێشتر', + finish: 'تەواوکردن', + close: 'بازدان' }src/runtime/locale/nl.ts-130-134 (1)
130-134:⚠️ Potential issue | 🟠 MajorTour labels are not translated into Dutch.
All four values are English. Based on existing patterns in this file (e.g.,
carousel.next: 'Volgende',carousel.prev: 'Vorige',modal.close: 'Sluiten'), these should be something like:Suggested translations
tour: { - next: 'Next', - previous: 'Previous', - finish: 'Finish', - close: 'Skip' + next: 'Volgende', + previous: 'Vorige', + finish: 'Voltooien', + close: 'Overslaan' }src/runtime/locale/de_ch.ts-130-134 (1)
130-134:⚠️ Potential issue | 🟠 MajorTour labels are not translated into Swiss German.
These should use Swiss German strings (e.g.,
next: 'Weiter',previous: 'Zurück',finish: 'Fertig',close: 'Überspringen'), consistent with existing patterns likecarousel.next: 'Weiter'.src/runtime/locale/ms.ts-130-134 (1)
130-134:⚠️ Potential issue | 🟠 MajorTour labels are not translated into Malay.
These should use Malay strings (e.g.,
next: 'Seterusnya',previous: 'Sebelum',finish: 'Selesai',close: 'Langkau'), consistent with existing patterns likecarousel.next: 'Seterusnya'.src/runtime/locale/lt.ts-130-134 (1)
130-134:⚠️ Potential issue | 🟠 MajorTour labels are not translated into Lithuanian.
These should use Lithuanian strings (e.g.,
next: 'Pirmyn',previous: 'Atgal',finish: 'Baigti',close: 'Praleisti'), consistent with existing patterns likecarousel.next: 'Pirmyn'.src/runtime/locale/ka.ts-132-136 (1)
132-136:⚠️ Potential issue | 🟠 MajorTour labels are not translated into Georgian.
All other sections in this locale file use proper Georgian translations, but the
tourkeys are left as English placeholders. These should be translated to Georgian (e.g.,next: 'შემდეგი',previous: 'წინა',finish: 'დასრულება',close: 'გამოტოვება'), consistent with how similar terms are translated elsewhere in this file (e.g.,carousel.nextis'შემდეგი').src/runtime/locale/ky.ts-130-134 (1)
130-134:⚠️ Potential issue | 🟠 MajorTour labels are not translated into Kyrgyz.
These should use Kyrgyz strings (e.g.,
next: 'Кийинки',previous: 'Алдыңкы',finish: 'Аяктоо',close: 'Өткөрүп жиберүү'), consistent with existing patterns likecarousel.next: 'Кийинки'.src/runtime/locale/ro.ts-130-134 (1)
130-134:⚠️ Potential issue | 🟠 MajorTour labels are not translated into Romanian.
Same issue as the other locale files — these should use Romanian strings (e.g.,
next: 'Următor',previous: 'Anterior',finish: 'Finalizare',close: 'Omite'), consistent with existing patterns likecarousel.next: 'Următor'.src/runtime/locale/uz.ts-130-134 (1)
130-134:⚠️ Potential issue | 🟠 MajorTour labels are not translated into Uzbek.
These should use Uzbek strings (e.g.,
next: 'Oldinga',previous: 'Ortga',finish: 'Tugatish',close: 'O'tkazib yuborish'), consistent with existing patterns likecarousel.next: 'Oldinga'.This issue affects all non-English locale files in the repository—59 files have untranslated English tour strings despite having translations for other UI components. Consider addressing them all in a single pass.
src/runtime/components/Tour.vue-296-304 (1)
296-304:⚠️ Potential issue | 🟠 MajorHaving a custom
nextLabelon the last step silently enables looping.Line 299:
if (props.loop || currentStep.value?.nextLabel)restarts the tour when the last step has anextLabel. A user might setnextLabel: "Let's Go!"purely for label customization without intending the tour to loop. This couples label text to navigation behavior, which is surprising.Proposed fix — decouple label from loop behavior
- // If loop is enabled OR if there's a custom nextLabel on the last step, restart the tour - if (props.loop || currentStep.value?.nextLabel) { + if (props.loop) { currentIndex.value = 0 emits('next', currentIndex.value) nextTick(updateHighlight) return }The button label logic in the template (lines 435-437) already handles displaying the correct label when
nextLabelis set, so removing it from the loop condition won't break the label display.src/runtime/components/Tour.vue-199-214 (1)
199-214:⚠️ Potential issue | 🟠 Major
dismissibleprop is effectively ignored whenmodalistrue(the default).With defaults
modal: trueanddismissible: true, the computedshouldPreventDismissalevaluates to!true || true = true, so Escape and click-outside are always blocked. A user who setsdismissible: true(or relies on the default) would expect the tour to be closeable via Escape, but it won't be. Thedismissibleprop becomes a no-op unlessmodalis also set tofalse.If the intent is that
dismissiblecontrols close-on-escape/click-outside independently ofmodal, the condition should use AND:Proposed fix
-// When modal is true, we should also prevent dismissal to ensure proper behavior -const shouldPreventDismissal = computed(() => !dismissible.value || props.modal) +// Prevent dismissal only when explicitly disabled +const shouldPreventDismissal = computed(() => !dismissible.value)If the intent is that modal mode should always block outside interaction (but still allow Escape), consider splitting the event prevention so Escape is governed by
dismissiblealone:Alternative: split escape vs. outside-click
const contentEvents = computed(() => { - if (shouldPreventDismissal.value) { - const events = ['pointerDownOutside', 'interactOutside', 'escapeKeyDown'] - - return events.reduce((acc, curr) => { - acc[curr] = (e: Event) => { - e.preventDefault() - } - return acc - }, {} as Record<typeof events[number], (e: Event) => void>) + const events: Record<string, (e: Event) => void> = {} + if (props.modal || !dismissible.value) { + events.pointerDownOutside = (e: Event) => e.preventDefault() + events.interactOutside = (e: Event) => e.preventDefault() + } + if (!dismissible.value) { + events.escapeKeyDown = (e: Event) => e.preventDefault() } - - return {} + return events })src/runtime/locale/gl.ts-130-134 (1)
130-134:⚠️ Potential issue | 🟠 MajorTour strings are untranslated across 60 locale files.
The issue in
src/runtime/locale/gl.ts(lines 130–134) is part of a systemic problem: nearly every non-English locale file contains English tour strings instead of localized translations.In gl.ts specifically, other keys are properly translated to Galician (e.g.,
carousel.next→ "Seguinte",carousel.prev→ "Anterior"), confirming that tour strings were overlooked.Proposed Galician translations for gl.ts
tour: { - next: 'Next', - previous: 'Previous', - finish: 'Finish', - close: 'Skip' + next: 'Seguinte', + previous: 'Anterior', + finish: 'Finalizar', + close: 'Saltar' }All 60 affected locale files (ar, az, bg, bn, ca, ckb, cs, da, de, de_ch, el, en_gb, es, et, eu, fa_ir, fi, fr, gl, he, hi, hr, hu, hy, id, it, ja, ka, kk, km, ko, ky, lb, lo, lt, mn, ms, nb_no, nl, pl, pt, pt_br, ro, ru, sk, sl, sq, sv, th, tj, tr, ug_cn, uk, ur, uz, vi, zh_cn, zh_tw) require translation of the tour keys.
🟡 Minor comments (15)
src/runtime/locale/vi.ts-130-135 (1)
130-135:⚠️ Potential issue | 🟡 MinorTour strings are not translated — English placeholders in all non-English locales.
The
tourvalues here are English ("Next", "Previous", "Finish", "Skip") while every other string in this file is properly translated to Vietnamese. The same issue affects all non-English locale files in this PR:da.ts,es.ts,ca.ts,et.ts,az.ts,km.ts, and likely others not included for review.For Vietnamese, these should be something like:
Suggested translations (verify with a native speaker)
tour: { - next: 'Next', - previous: 'Previous', - finish: 'Finish', - close: 'Skip' + next: 'Tiếp theo', + previous: 'Trước', + finish: 'Hoàn thành', + close: 'Bỏ qua' }Please translate the tour strings for every locale file, not just this one.
src/runtime/locale/id.ts-131-135 (1)
131-135:⚠️ Potential issue | 🟡 MinorTour strings are not translated into Indonesian.
Suggested:
next: 'Berikutnya',previous: 'Sebelumnya',finish: 'Selesai',close: 'Lewati'— consistent with existing carousel labels in this file.src/runtime/locale/sl.ts-131-135 (1)
131-135:⚠️ Potential issue | 🟡 MinorTour strings are not translated into Slovenian.
Suggested:
next: 'Naprej',previous: 'Nazaj',finish: 'Končaj',close: 'Preskoči'— aligning with existing carousel labels.src/runtime/locale/tj.ts-131-135 (1)
131-135:⚠️ Potential issue | 🟡 MinorTour strings are not translated into Tajik.
Suggested:
next: 'Баъдӣ',previous: 'Қаблӣ',finish: 'Анҷом',close: 'Гузаштан'— aligning with existing carousel labels.src/runtime/locale/cs.ts-131-135 (1)
131-135:⚠️ Potential issue | 🟡 MinorTour strings are not translated into Czech.
Suggested:
next: 'Další',previous: 'Předchozí',finish: 'Dokončit',close: 'Přeskočit'— consistent with existing carousel labels.src/runtime/locale/ur.ts-131-135 (1)
131-135:⚠️ Potential issue | 🟡 MinorTour strings are not translated into Urdu.
All four tour labels are English placeholders while every other key in this locale uses Urdu script. These should be translated (e.g.,
next: 'اگلا',previous: 'پچھلا',finish: 'ختم',close: 'چھوڑیں').src/runtime/locale/nb_no.ts-131-135 (1)
131-135:⚠️ Potential issue | 🟡 MinorTour strings are not translated into Norwegian Bokmål.
This locale already has equivalent terms (e.g.,
carousel.next: 'Neste',carousel.prev: 'Forrige'). Consider reusing the same vocabulary:next: 'Neste',previous: 'Forrige',finish: 'Fullfør',close: 'Hopp over'.src/runtime/locale/hi.ts-131-135 (1)
131-135:⚠️ Potential issue | 🟡 MinorTour strings are not translated into Hindi.
Same issue as other locale files — all four labels are English placeholders. These should be in Hindi (e.g.,
next: 'अगला',previous: 'पिछला',finish: 'समाप्त',close: 'छोड़ें').playgrounds/nuxt/app/pages/components/tour.vue-40-42 (1)
40-42:⚠️ Potential issue | 🟡 MinorInconsistent language: "Avvia tour" is Italian; the rest of the page is English.
Suggested fix
- Avvia tour + Start toursrc/runtime/locale/hr.ts-130-134 (1)
130-134:⚠️ Potential issue | 🟡 MinorTour labels are not translated to Croatian.
Same issue as other locale files — English placeholders instead of Croatian translations.
🌐 Suggested Croatian translations
tour: { - next: 'Next', - previous: 'Previous', - finish: 'Finish', - close: 'Skip' + next: 'Sljedeći', + previous: 'Prethodni', + finish: 'Završi', + close: 'Preskoči' }src/runtime/locale/el.ts-130-134 (1)
130-134:⚠️ Potential issue | 🟡 MinorTour labels are not translated to Greek.
Same pattern — English placeholders instead of Greek translations.
🌐 Suggested Greek translations
tour: { - next: 'Next', - previous: 'Previous', - finish: 'Finish', - close: 'Skip' + next: 'Επόμενο', + previous: 'Προηγούμενο', + finish: 'Τέλος', + close: 'Παράλειψη' }src/runtime/locale/fa_ir.ts-130-135 (1)
130-135:⚠️ Potential issue | 🟡 MinorTour labels are not translated to Persian.
All other strings in this locale are properly translated to فارسی, but the
tourblock contains English values. This should use Persian translations, e.g.:🌐 Suggested Persian translations
tour: { - next: 'Next', - previous: 'Previous', - finish: 'Finish', - close: 'Skip' + next: 'بعدی', + previous: 'قبلی', + finish: 'پایان', + close: 'رد شدن' }src/runtime/locale/fr.ts-130-134 (1)
130-134:⚠️ Potential issue | 🟡 MinorTour labels are not translated to French.
The tour block contains English strings that should be translated. This issue affects 59 out of 61 locale files in the repository. The French translations should be:
🌐 Suggested French translations
tour: { - next: 'Next', - previous: 'Previous', - finish: 'Finish', - close: 'Skip' + next: 'Suivant', + previous: 'Précédent', + finish: 'Terminer', + close: 'Passer' }Please translate the tour strings in all affected locale files.
src/runtime/components/Tour.vue-270-272 (1)
270-272:⚠️ Potential issue | 🟡 MinorMisleading comment: Tailwind's
outline-offset-2is 2px, not 8px.The comment states "outline-offset-2 in Tailwind equals 8px (0.5rem)" — Tailwind's
outline-offset-2utility generatesoutline-offset: 2px. The class for 8px would beoutline-offset-8. If 8px is the correct value for the visual effect, update the comment to reference the right class.src/runtime/utils/locale.ts-21-32 (1)
21-32:⚠️ Potential issue | 🟡 MinorType annotation on
propis incorrect —get()returnsundefinedwhen not found.Line 22 declares
let prop: stringbut assigns the result ofget(locale, \messages.${path}`, undefined), which returnsundefinedwhen the path is not found. Line 25 confirms this withprop === undefinedcheck. The type should bestring | undefined`.Additionally, the
prop === pathcheck on line 25 is unnecessary. Since the default in line 22 isundefined(notpath),prop === pathwould only match if the translation value itself equals the path key, which is extremely unlikely. This appears to be dead code or overly defensive logic that should be removed.Suggested fix
- let prop: string = get(locale, `messages.${path}`, undefined) + let prop: string | undefined = get(locale, `messages.${path}`, undefined) // If translation not found and it's not the fallback path itself, try fallback locale - if (prop === undefined || prop === path) { + if (prop === undefined) {
🧹 Nitpick comments (7)
src/runtime/locale/en_gb.ts (1)
8-16: The explicittourblock is redundant.
en.tsalready includes an identicaltourobject. Since...en.messagesspreads all ofen.ts's messages (includingtour), the explicit override adds unnecessary maintenance burden—ifen.tstour labels change, this file will silently shadow them.Simplify to:
- messages: { - ...en.messages, - tour: { - next: 'Next', - previous: 'Previous', - finish: 'Finish', - close: 'Skip' - } - } + messages: en.messagestest/components/Tour.spec.ts (1)
8-52: Good test coverage for rendering and props/slots.The parameterized snapshot tests provide solid baseline coverage. Consider adding interaction tests (clicking next/previous, verifying step transitions, testing the close/dismiss behavior) in a follow-up to ensure navigation logic works end-to-end.
src/runtime/utils/locale.ts (1)
40-52: Fallback locale computed once — stale iflocaleref changes from'en'to another code.Line 45 evaluates
unref(locale).codeat context creation time to decide whether English fallback is needed. Iflocaleis aRefthat later changes (e.g.,'en'→'fr'), thisfallbackconstant won't update.In practice this is mitigated because
translate()(line 26) re-derives the fallback internally, so translations still resolve correctly. However, having fallback logic in two places (here and intranslate) is redundant and could diverge. Consider computing the fallback solely insidetranslateand removing it frombuildLocaleContext:Simplification suggestion
-export function buildLocaleContext<M>(locale: MaybeRef<Locale<M>>, fallbackLocale?: Locale<M>): LocaleContext<M> { +export function buildLocaleContext<M>(locale: MaybeRef<Locale<M>>): LocaleContext<M> { const lang = computed(() => unref(locale).name) const code = computed(() => unref(locale).code) const dir = computed(() => unref(locale).dir) const localeRef = isRef(locale) ? locale : ref(locale) as Ref<Locale<M>> - const fallback = fallbackLocale || (unref(locale).code !== 'en' ? en as Locale<M> : undefined) return { lang, code, dir, locale: localeRef, - t: buildTranslator(locale, fallback) + t: buildTranslator(locale) } }This way
translateremains the single source of fallback logic and reactivity is preserved.src/runtime/components/Tour.vue (4)
232-256:resolveTargethas a redundant function check and a potentially confusing double-lookup for plain strings.Two issues:
Dead code on line 251:
toValue(target)on line 233 already invokes functions, so thetypeof value === 'function'branch can never be reached for the declaredTourTargettype.String resolution (lines 239-248): Passing a bare string like
"my-element"first queriesdocument.querySelector("my-element"), which matches a<my-element>custom-element tag—likely not the user's intent. If no match, it retries with#my-element. Consider reversing the priority or documenting this behavior.Suggested simplification
function resolveTarget(target?: TourTarget) { const value = toValue(target) as TourTarget if (!value || typeof window === 'undefined') { return undefined } if (typeof value === 'string') { - const direct = document.querySelector(value) as ReferenceElement | null - - if (direct) { - return direct - } - - const selector = value.startsWith('#') || value.startsWith('.') ? value : `#${value}` - - return document.querySelector(selector) as ReferenceElement | null + // If the string is already a selector (starts with # or .), use it directly. + // Otherwise, treat it as an ID. + const selector = value.startsWith('#') || value.startsWith('.') ? value : `#${value}` + return document.querySelector(selector) as ReferenceElement | null } - if (typeof value === 'function') { - return value() ?? undefined - } - return value ?? undefined }
418-428: Redundant:disabled— button is only rendered whenhasPrevis true.Line 419 uses
v-if="hasPrev"so the button is never rendered whenhasPrevis false, making:disabled="!hasPrev"on line 423 always evaluate tofalse.Cleanup
<UButton v-if="hasPrev" size="xs" color="neutral" variant="ghost" - :disabled="!hasPrev" :class="ui.prev({ class: currentStep?.ui?.prev })" `@click`="prev" >
348-368: Hardcoded z-index values nearMAX_INTmay collide with other libraries.Lines 352, 364, 375 use
2147483645,2147483646, and2147483647. While layering overlay < highlight < content is correct, consider making these configurable (e.g., via azIndexprop or theme token) so users can adjust them when integrating with third-party components that also use extreme z-index values.
330-332: Highlight position won't update when a scrollable ancestor (notwindow) scrolls.
useEventListeneron lines 330-331 only listens to thewindowscroll event. If the target element is inside a scrollable container (e.g., an overflow div), the highlight will drift out of sync. This is a known limitation in many tour libraries, but worth noting. A future improvement could find the nearest scrollable ancestor of the target and listen on that as well.
There was a problem hiding this comment.
Actionable comments posted: 8
🤖 Fix all issues with AI agents
In `@src/runtime/locale/et.ts`:
- Around line 130-134: The tour.close translation "Jäta vahele" is inconsistent
with other close keys (e.g., alert.close, modal.close, toast.close) which use
"Sulge"; either change tour.close to "Sulge" to match the intended
"close/dismiss" semantics or, if it truly means "skip", rename the key to
tour.skip (and update all type definitions/usages) so the meaning is explicit;
update the translation and any references to tour.close in code or i18n types
accordingly (look for the tour object and keys named close/skip).
In `@src/runtime/locale/eu.ts`:
- Around line 130-135: tour.previous uses "Aurrekoa" while carousel.prev uses
the variant "Aurretikoa", and tour.close uses "Saltatu" whereas other close keys
use "Itxi"; update for consistency by choosing the standard form "Aurrekoa" for
the carousel.prev entry (or change tour.previous to match if that was intended)
and change tour.close to "Itxi" if the intent is a literal "close" action;
locate the keys named tour.previous, carousel.prev and any other close keys
(e.g., close) in this locale file and make the string values consistent.
In `@src/runtime/locale/he.ts`:
- Around line 131-136: The tour translation uses "דלג" for the close action
which means "skip" and is inconsistent with other close labels; update the tour
object so its close property uses the same word as other components (change
tour.close from 'דלג' to 'סגור') to ensure consistent messaging across alert,
banner, modal, slideover, and toast.
In `@src/runtime/locale/hi.ts`:
- Around line 130-135: The translation for the locale object key tour.close is
inconsistent: replace the string 'छोड़ें' with 'बंद करें' to match other close
translations (e.g., alert.close, modal.close, toast.close, slideover.close) so
the tour.close semantic aligns with "close/dismiss"; if the intent was "skip"
instead, rename the key from close to skip and provide an appropriate 'छोड़ें'
translation for tour.skip to preserve clarity.
In `@src/runtime/locale/tr.ts`:
- Around line 130-135: The translation for tour.close is inconsistent: change
the value or the key so intent matches other translations; either rename the key
tour.close to tour.skip (and set its value to "Atla") if the button is meant to
"Skip" the tour, or keep the key tour.close and change its value from "Atla" to
"Kapat" to match other close keys like alert.close, banner.close, modal.close,
slideover.close, and toast.close; update any code references that use the
tour.close key if you rename it to tour.skip.
In `@src/runtime/locale/ug_cn.ts`:
- Around line 131-136: tour.close currently uses 'ئاتلاش' (skip) while other
close keys (alert.close, banner.close, modal.close, toast.close) use 'تاقاش';
replace the value of the tour.close property from 'ئاتلاش' to 'تاقاش' to make it
consistent, or if the intent is to offer a "skip" action, add a comment near the
tour object documenting that tour.close intentionally means "skip" and leave the
value as-is; locate the tour object and update the tour.close string
accordingly.
In `@src/runtime/locale/vi.ts`:
- Around line 130-135: tour.close is translated as "Bỏ qua" (Skip) but other
close keys use "Đóng"; update the translation for the tour object (tour.next,
tour.previous, tour.finish, tour.close) so that tour.close uses "Đóng" instead
of "Bỏ qua" to match the close semantics used by other components (unless the
tour action is intentionally a "skip", in which case leave as-is and add a
clarifying comment).
In `@src/runtime/locale/zh_tw.ts`:
- Around line 130-135: The translation for tour.close ('略過') is inconsistent
with other close keys; if the intent is to perform a generic "close" action,
change the value of tour.close to '關閉' to match other keys (update any
tests/usage if necessary), otherwise if the action is truly "skip tour" rename
the key tour.close to tour.skip and update every usage/site referencing
tour.close to tour.skip to keep semantics clear and consistent (search for
usages of "tour.close" to update callers).
🧹 Nitpick comments (1)
src/runtime/locale/th.ts (1)
130-135: Tour translations look good; minor note onclosewording consistency.
tour.closeis translated as "ข้าม" (skip), while every other component'sclosekey (alert, banner, modal, slideover, toast) uses "ปิด" (close). If the intent is "skip the tour," this is a reasonable UX choice, but it diverges from the key's semantic name and the rest of the file. Consider whether "ปิด" would be more consistent, or if "ข้าม" is the deliberate choice here.
| tour: { | ||
| next: 'Hurrengoa', | ||
| previous: 'Aurrekoa', | ||
| finish: 'Amaitu', | ||
| close: 'Saltatu' | ||
| } |
There was a problem hiding this comment.
Minor inconsistency: tour.previous vs carousel.prev use different Basque words for "previous".
tour.previous is "Aurrekoa" (line 132) while carousel.prev is "Aurretikoa" (line 29). Both convey "previous" but differ in form. Consider aligning them — "Aurrekoa" is the more standard form, so the carousel entry may be the one to update in a follow-up.
Also, tour.close is "Saltatu" (Skip) whereas every other close key in this file uses "Itxi" (Close). If this is intentional (i.e., the tour close action semantically means "skip"), this is fine — just confirming it's a deliberate choice.
🤖 Prompt for AI Agents
In `@src/runtime/locale/eu.ts` around lines 130 - 135, tour.previous uses
"Aurrekoa" while carousel.prev uses the variant "Aurretikoa", and tour.close
uses "Saltatu" whereas other close keys use "Itxi"; update for consistency by
choosing the standard form "Aurrekoa" for the carousel.prev entry (or change
tour.previous to match if that was intended) and change tour.close to "Itxi" if
the intent is a literal "close" action; locate the keys named tour.previous,
carousel.prev and any other close keys (e.g., close) in this locale file and
make the string values consistent.
|
I can't check the deploy error @benjamincanac , can you help me to understand the error? I'm trying to deploy the repo inside my personal Vercel but I don't have the correct build command to use. |
|
@solidusite It only misses the cover image for this new component, we'll add them with @HugoRCD once I find time to review this. |
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (6)
src/runtime/locale/hi.ts (1)
130-135: LGTM — prior inconsistency resolved.
close: 'बंद करें'now aligns with every otherclosekey in the file (alert, banner, modal, slideover, toast).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/runtime/locale/hi.ts` around lines 130 - 135, The 'tour' object now uses the 'close' key with value 'बंद करें', matching other components; no code change needed—just confirm the 'tour' object (tour) contains keys next, previous, finish, and close with the updated close value and commit as-is.src/runtime/locale/he.ts (1)
131-136: LGTM — prior inconsistency resolved.
close: 'סגור'now aligns with every otherclosekey in the file (alert, banner, modal, slideover, toast).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/runtime/locale/he.ts` around lines 131 - 136, The tour translation already updates the 'close' key to 'סגור', resolving the prior inconsistency; no code change is required—verify the 'tour' object in src/runtime/locale/he.ts contains next/previous/finish/close with close: 'סגור' to match other components' 'close' keys (alert, banner, modal, slideover, toast).src/runtime/locale/ug_cn.ts (1)
131-136: LGTM — prior inconsistency resolved.
close: 'تاقاش'now aligns with every otherclosekey in the file (alert, banner, commandPalette, modal, slideover, toast).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/runtime/locale/ug_cn.ts` around lines 131 - 136, The tour object's close label is inconsistent with other components; update the tour.close property in the tour object to 'تاقاش' (matching alert, banner, commandPalette, modal, slideover, toast) and remove any duplicate or conflicting 'close' entries for tour if present so there is a single consistent definition (inspect the tour object and the 'close' key to locate and fix).src/runtime/locale/et.ts (1)
130-135: LGTM – priortour.closeinconsistency ('Jäta vahele' → 'Sulge') is resolved.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/runtime/locale/et.ts` around lines 130 - 135, The translation inconsistency for the tour object has been resolved: ensure the property tour.close in src/runtime/locale/et.ts uses 'Sulge' (replacing the prior 'Jäta vahele'), confirm tour.next/previous/finish remain correct, and mark the change approved—no further code changes required.src/runtime/locale/zh_tw.ts (1)
130-135: LGTM – priortour.closeinconsistency ('略過' → '關閉') is resolved.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/runtime/locale/zh_tw.ts` around lines 130 - 135, The previous inconsistency in the localization key tour.close has been corrected from '略過' to '關閉'; no code changes required—confirm that the tour object (keys: next, previous, finish, close) in zh_tw.ts uses the finalized translations ('下一步','上一步','完成','關閉') and proceed to approve/merge.src/runtime/locale/sv.ts (1)
130-135: LGTM – prior untranslated-string issue is resolved.All four keys are now proper Swedish and consistent with the rest of the locale (
Stängfor close,Nästa/Föregåendemirroring the carousel).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/runtime/locale/sv.ts` around lines 130 - 135, The translations in the 'tour' object (keys next, previous, finish, close) in src/runtime/locale/sv.ts are correct and consistent with the locale, so no code changes are required — approve the change as-is and ensure the 'tour' object remains: next: 'Nästa', previous: 'Föregående', finish: 'Slutför', close: 'Stäng'.
🧹 Nitpick comments (5)
src/runtime/components/Tour.vue (5)
282-306:updateHighlightis scheduled twice pernext()/prev()call.Both
next()(line 286) andprev()(line 304) explicitly callnextTick(updateHighlight). Thewatch(currentIndex, ...)on line 323 independently schedules the same call whenevercurrentIndexchanges. MutatingcurrentIndex.valueinsidenext()/prev()triggers the watcher, so twonextTick(updateHighlight)calls are enqueued per navigation.♻️ Suggested simplification
Remove the redundant explicit calls inside the navigation functions and rely solely on the watcher:
function next() { if (hasNext.value) { currentIndex.value += 1 emits('next', currentIndex.value) - nextTick(updateHighlight) return } if (props.loop) { currentIndex.value = 0 emits('next', currentIndex.value) - nextTick(updateHighlight) return } finish() } function prev() { if (hasPrev.value) { currentIndex.value -= 1 emits('prev', currentIndex.value) - nextTick(updateHighlight) } }Also applies to: 323-323
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/runtime/components/Tour.vue` around lines 282 - 306, The navigation functions next() and prev() are redundantly scheduling updateHighlight via nextTick() while the watcher on currentIndex already enqueues nextTick(updateHighlight) when currentIndex.value changes; remove the explicit nextTick(updateHighlight) calls from next() and prev() (leave the currentIndex.value mutations, emits('next'/'prev', ...) and loop/finish logic intact) so updateHighlight is only scheduled by the watch(currentIndex, ...) handler.
335-337:<span ref="fallbackRef">is missing adata-slotattribute.Per coding guidelines, all template elements in Vue components must carry a
data-slotattribute.♻️ Suggested fix
- <span ref="fallbackRef" aria-hidden="true" /> + <span ref="fallbackRef" data-slot="trigger" aria-hidden="true" />As per coding guidelines: "Add
data-slot="name"attributes on all template elements in Vue components."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/runtime/components/Tour.vue` around lines 335 - 337, The <span ref="fallbackRef" /> used inside Popover.Trigger in the Tour.vue template is missing the required data-slot attribute; update that element (the span with ref="fallbackRef" inside Popover.Trigger) to include a descriptive data-slot value (e.g., data-slot="fallback" or another appropriate slot name per the component semantics) so it complies with the coding guideline requiring data-slot on all template elements.
96-101:finish()conflates tour dismissal with tour completion — add a separateclose/cancelemit.The close button (line 397,
@click="finish") and the last-step Next button both callfinish(), which emits the same'finish'event. Consumers have no way to distinguish between "user completed all steps" and "user dismissed mid-tour." This limits analytics and conditional post-tour flows.♻️ Suggested approach
Add a
closeevent toTourEmitsand call it exclusively from the close button:export interface TourEmits extends PopoverRootEmits { 'update:step': [number] 'next': [number] 'prev': [number] 'finish': [] + 'close': [] }function finish() { open.value = false emits('finish') } +function close() { + open.value = false + emits('close') +}- `@click`="finish" + `@click`="close"Also applies to: 308-311, 388-398
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/runtime/components/Tour.vue` around lines 96 - 101, The Tour currently uses finish() for both dismissal and completion, which prevents consumers from distinguishing the two; add a separate 'close' emit to the TourEmits interface and wherever the close button handler is wired (the close button that currently calls finish, and any related handlers around the close/dismiss UI at the regions noted), change that handler to emit 'close' instead of calling finish(), leaving finish() reserved for true tour completion (e.g., the last-step Next button); update any emits declarations/usages (TourEmits, the component emits definition, and any methods or places that call finish() for dismissal) and tests/consumers accordingly so dismissal emits 'close' and completion emits 'finish'.
217-218:eslint-disablecomment masks a naming conflict between theuiprop anduicomputed ref.Rename the computed to avoid the collision and remove the suppression comment:
♻️ Suggested rename
-// eslint-disable-next-line vue/no-dupe-keys -const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.tour || {}) })({})) +const uiConfig = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.tour || {}) })({}))Then replace all
ui.xxx(...)calls in the template withuiConfig.xxx(...).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/runtime/components/Tour.vue` around lines 217 - 218, The computed ref named ui conflicts with the existing ui prop and the eslint-disable masks it; rename the computed from ui to uiConfig (update the declaration: const uiConfig = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.tour || {}) })({}))) remove the eslint-disable comment, and update all template and script usages that call ui.xxx(...) to use uiConfig.xxx(...) instead so references point to the new computed ref.
347-360: Hardcodedrgba(0, 0, 0, 0.5)for the spotlight overlay is not customizable.When a target element is resolved, the overlay effect is produced via an inline
boxShadow. This color is hardcoded and cannot be adjusted through props or the theme, unlike the full-page overlay div (lines 340-345) which usesui.overlay(...).♻️ Suggested approach
Expose an
overlayColorprop (or CSS variable) and thread it through the inline style:+ /** + * The backdrop color for the spotlight overlay effect. + * `@defaultValue` 'rgba(0, 0, 0, 0.5)' + */ + overlayColor?: string- ...(showOverlay ? { boxShadow: '0 0 0 9999px rgba(0, 0, 0, 0.5)' } : {}) + ...(showOverlay ? { boxShadow: `0 0 0 9999px ${props.overlayColor ?? 'rgba(0, 0, 0, 0.5)'}` } : {})🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/runtime/components/Tour.vue` around lines 347 - 360, The inline spotlight uses a hardcoded boxShadow color; add a configurable overlay color (e.g., prop overlayColor with a default like 'rgba(0, 0, 0, 0.5)' or read from a CSS variable) and use it when composing the inline style for the highlight element: update the component props to include overlayColor, and change the conditional that builds boxShadow in the element that references highlightRect/showOverlay to use that prop (instead of the literal 'rgba(0, 0, 0, 0.5)'); keep the existing ui.highlight/uiProp?.highlight/currentStep?.ui usage intact so theming still applies.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/runtime/components/Tour.vue`:
- Around line 424-429: The ternary logic in the UButton rendering (using
hasNext, props.loop, currentStep?.nextLabel) wrongly prioritizes nextLabel over
finishLabel; change it so the decision is based only on whether there is a next
step or loop is enabled: if (hasNext || props.loop) render
(currentStep?.nextLabel || t('tour.next')), otherwise render
(currentStep?.finishLabel || t('tour.finish')). Update the expression around
currentStep?.nextLabel/currentStep?.finishLabel in the UButton (the same place
where hasNext and props.loop are checked) to implement this clear two-branch
conditional.
- Around line 231-249: The resolveTarget function is incorrectly auto-prefixing
plain strings with '#' which turns class names and complex selectors into
invalid ID selectors; remove the prefixing logic in resolveTarget so that when
typeof value === 'string' you treat value as a full CSS selector and pass it
straight to document.querySelector(value), and update the JSDoc for
TourStep.target to state that string values are interpreted as raw CSS selectors
(so callers must include '#' for IDs and '.' for classes or use other valid
selector syntax).
In `@src/runtime/locale/tj.ts`:
- Around line 128-129: The change to toast.close introduces a mismatch with
other Tajik "close" labels; revert toast.close back to 'Бастан' so it matches
alert.close, commandPalette.close, modal.close and slideover.close (or
alternatively, as a follow-up, change all of those keys to 'Пӯшидан' for a
unified term). Update the toast.close entry in the locale (the toast.close key)
to 'Бастан' to restore consistency with the other close-action strings.
---
Duplicate comments:
In `@src/runtime/locale/et.ts`:
- Around line 130-135: The translation inconsistency for the tour object has
been resolved: ensure the property tour.close in src/runtime/locale/et.ts uses
'Sulge' (replacing the prior 'Jäta vahele'), confirm tour.next/previous/finish
remain correct, and mark the change approved—no further code changes required.
In `@src/runtime/locale/he.ts`:
- Around line 131-136: The tour translation already updates the 'close' key to
'סגור', resolving the prior inconsistency; no code change is required—verify the
'tour' object in src/runtime/locale/he.ts contains next/previous/finish/close
with close: 'סגור' to match other components' 'close' keys (alert, banner,
modal, slideover, toast).
In `@src/runtime/locale/hi.ts`:
- Around line 130-135: The 'tour' object now uses the 'close' key with value
'बंद करें', matching other components; no code change needed—just confirm the
'tour' object (tour) contains keys next, previous, finish, and close with the
updated close value and commit as-is.
In `@src/runtime/locale/sv.ts`:
- Around line 130-135: The translations in the 'tour' object (keys next,
previous, finish, close) in src/runtime/locale/sv.ts are correct and consistent
with the locale, so no code changes are required — approve the change as-is and
ensure the 'tour' object remains: next: 'Nästa', previous: 'Föregående', finish:
'Slutför', close: 'Stäng'.
In `@src/runtime/locale/ug_cn.ts`:
- Around line 131-136: The tour object's close label is inconsistent with other
components; update the tour.close property in the tour object to 'تاقاش'
(matching alert, banner, commandPalette, modal, slideover, toast) and remove any
duplicate or conflicting 'close' entries for tour if present so there is a
single consistent definition (inspect the tour object and the 'close' key to
locate and fix).
In `@src/runtime/locale/zh_tw.ts`:
- Around line 130-135: The previous inconsistency in the localization key
tour.close has been corrected from '略過' to '關閉'; no code changes
required—confirm that the tour object (keys: next, previous, finish, close) in
zh_tw.ts uses the finalized translations ('下一步','上一步','完成','關閉') and proceed to
approve/merge.
---
Nitpick comments:
In `@src/runtime/components/Tour.vue`:
- Around line 282-306: The navigation functions next() and prev() are
redundantly scheduling updateHighlight via nextTick() while the watcher on
currentIndex already enqueues nextTick(updateHighlight) when currentIndex.value
changes; remove the explicit nextTick(updateHighlight) calls from next() and
prev() (leave the currentIndex.value mutations, emits('next'/'prev', ...) and
loop/finish logic intact) so updateHighlight is only scheduled by the
watch(currentIndex, ...) handler.
- Around line 335-337: The <span ref="fallbackRef" /> used inside
Popover.Trigger in the Tour.vue template is missing the required data-slot
attribute; update that element (the span with ref="fallbackRef" inside
Popover.Trigger) to include a descriptive data-slot value (e.g.,
data-slot="fallback" or another appropriate slot name per the component
semantics) so it complies with the coding guideline requiring data-slot on all
template elements.
- Around line 96-101: The Tour currently uses finish() for both dismissal and
completion, which prevents consumers from distinguishing the two; add a separate
'close' emit to the TourEmits interface and wherever the close button handler is
wired (the close button that currently calls finish, and any related handlers
around the close/dismiss UI at the regions noted), change that handler to emit
'close' instead of calling finish(), leaving finish() reserved for true tour
completion (e.g., the last-step Next button); update any emits
declarations/usages (TourEmits, the component emits definition, and any methods
or places that call finish() for dismissal) and tests/consumers accordingly so
dismissal emits 'close' and completion emits 'finish'.
- Around line 217-218: The computed ref named ui conflicts with the existing ui
prop and the eslint-disable masks it; rename the computed from ui to uiConfig
(update the declaration: const uiConfig = computed(() => tv({ extend: tv(theme),
...(appConfig.ui?.tour || {}) })({}))) remove the eslint-disable comment, and
update all template and script usages that call ui.xxx(...) to use
uiConfig.xxx(...) instead so references point to the new computed ref.
- Around line 347-360: The inline spotlight uses a hardcoded boxShadow color;
add a configurable overlay color (e.g., prop overlayColor with a default like
'rgba(0, 0, 0, 0.5)' or read from a CSS variable) and use it when composing the
inline style for the highlight element: update the component props to include
overlayColor, and change the conditional that builds boxShadow in the element
that references highlightRect/showOverlay to use that prop (instead of the
literal 'rgba(0, 0, 0, 0.5)'); keep the existing
ui.highlight/uiProp?.highlight/currentStep?.ui usage intact so theming still
applies.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
test/components/__snapshots__/Tour-vue.spec.ts.snapis excluded by!**/*.snaptest/components/__snapshots__/Tour.spec.ts.snapis excluded by!**/*.snap
📒 Files selected for processing (64)
playgrounds/nuxt/app/pages/components/tour.vuesrc/runtime/components/Tour.vuesrc/runtime/locale/ar.tssrc/runtime/locale/az.tssrc/runtime/locale/be.tssrc/runtime/locale/bg.tssrc/runtime/locale/bn.tssrc/runtime/locale/ca.tssrc/runtime/locale/ckb.tssrc/runtime/locale/cs.tssrc/runtime/locale/da.tssrc/runtime/locale/de.tssrc/runtime/locale/de_ch.tssrc/runtime/locale/el.tssrc/runtime/locale/en.tssrc/runtime/locale/es.tssrc/runtime/locale/et.tssrc/runtime/locale/eu.tssrc/runtime/locale/fa_ir.tssrc/runtime/locale/fi.tssrc/runtime/locale/fr.tssrc/runtime/locale/gl.tssrc/runtime/locale/he.tssrc/runtime/locale/hi.tssrc/runtime/locale/hr.tssrc/runtime/locale/hu.tssrc/runtime/locale/hy.tssrc/runtime/locale/id.tssrc/runtime/locale/it.tssrc/runtime/locale/ja.tssrc/runtime/locale/ka.tssrc/runtime/locale/kk.tssrc/runtime/locale/km.tssrc/runtime/locale/ko.tssrc/runtime/locale/ky.tssrc/runtime/locale/lb.tssrc/runtime/locale/lo.tssrc/runtime/locale/lt.tssrc/runtime/locale/mn.tssrc/runtime/locale/ms.tssrc/runtime/locale/nb_no.tssrc/runtime/locale/nl.tssrc/runtime/locale/pl.tssrc/runtime/locale/pt.tssrc/runtime/locale/pt_br.tssrc/runtime/locale/ro.tssrc/runtime/locale/ru.tssrc/runtime/locale/sk.tssrc/runtime/locale/sl.tssrc/runtime/locale/sq.tssrc/runtime/locale/sv.tssrc/runtime/locale/th.tssrc/runtime/locale/tj.tssrc/runtime/locale/tr.tssrc/runtime/locale/ug_cn.tssrc/runtime/locale/uk.tssrc/runtime/locale/ur.tssrc/runtime/locale/uz.tssrc/runtime/locale/vi.tssrc/runtime/locale/zh_cn.tssrc/runtime/locale/zh_tw.tssrc/runtime/types/index.tssrc/runtime/utils/locale.tstest/components/Tour.spec.ts
🚧 Files skipped from review as they are similar to previous changes (33)
- src/runtime/locale/ru.ts
- src/runtime/locale/ms.ts
- src/runtime/locale/sq.ts
- src/runtime/locale/nl.ts
- src/runtime/locale/nb_no.ts
- src/runtime/locale/hu.ts
- src/runtime/locale/pl.ts
- src/runtime/locale/fi.ts
- src/runtime/locale/de_ch.ts
- src/runtime/locale/ky.ts
- src/runtime/locale/ro.ts
- src/runtime/locale/gl.ts
- src/runtime/locale/uz.ts
- src/runtime/locale/bg.ts
- src/runtime/locale/ko.ts
- src/runtime/locale/id.ts
- src/runtime/locale/hr.ts
- src/runtime/locale/lt.ts
- src/runtime/locale/bn.ts
- src/runtime/locale/sk.ts
- src/runtime/locale/be.ts
- src/runtime/locale/en.ts
- src/runtime/locale/az.ts
- src/runtime/locale/ckb.ts
- playgrounds/nuxt/app/pages/components/tour.vue
- src/runtime/locale/ar.ts
- src/runtime/locale/it.ts
- src/runtime/locale/ur.ts
- src/runtime/locale/lb.ts
- src/runtime/locale/kk.ts
- src/runtime/locale/pt.ts
- src/runtime/locale/ka.ts
- src/runtime/locale/eu.ts
| function resolveTarget(target?: TourTarget): ReferenceElement | null | undefined { | ||
| if (!target || typeof window === 'undefined') { | ||
| return undefined | ||
| } | ||
|
|
||
| const value = typeof target === 'function' ? target() : target | ||
|
|
||
| if (!value) { | ||
| return undefined | ||
| } | ||
|
|
||
| if (typeof value === 'string') { | ||
| const selector = value.startsWith('#') || value.startsWith('.') ? value : `#${value}` | ||
|
|
||
| return document.querySelector(selector) as ReferenceElement | null | ||
| } | ||
|
|
||
| return value | ||
| } |
There was a problem hiding this comment.
resolveTarget silently auto-prefixes plain strings with #, turning class names into broken ID selectors.
A caller passing "my-class" (intending .my-class) gets document.querySelector("#my-class") instead. Complex selectors like "div > .foo" or "[data-id='bar']" are also mishandled by the prefix logic.
🐛 Suggested fix
- const selector = value.startsWith('#') || value.startsWith('.') ? value : `#${value}`
+ const selector = value.startsWith('#') || value.startsWith('.') || value.startsWith('[') ? value : `#${value}`Additionally, consider documenting in TourStep.target's JSDoc that bare strings without a # or . prefix are treated as IDs.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| function resolveTarget(target?: TourTarget): ReferenceElement | null | undefined { | |
| if (!target || typeof window === 'undefined') { | |
| return undefined | |
| } | |
| const value = typeof target === 'function' ? target() : target | |
| if (!value) { | |
| return undefined | |
| } | |
| if (typeof value === 'string') { | |
| const selector = value.startsWith('#') || value.startsWith('.') ? value : `#${value}` | |
| return document.querySelector(selector) as ReferenceElement | null | |
| } | |
| return value | |
| } | |
| function resolveTarget(target?: TourTarget): ReferenceElement | null | undefined { | |
| if (!target || typeof window === 'undefined') { | |
| return undefined | |
| } | |
| const value = typeof target === 'function' ? target() : target | |
| if (!value) { | |
| return undefined | |
| } | |
| if (typeof value === 'string') { | |
| const selector = value.startsWith('#') || value.startsWith('.') || value.startsWith('[') ? value : `#${value}` | |
| return document.querySelector(selector) as ReferenceElement | null | |
| } | |
| return value | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/runtime/components/Tour.vue` around lines 231 - 249, The resolveTarget
function is incorrectly auto-prefixing plain strings with '#' which turns class
names and complex selectors into invalid ID selectors; remove the prefixing
logic in resolveTarget so that when typeof value === 'string' you treat value as
a full CSS selector and pass it straight to document.querySelector(value), and
update the JSDoc for TourStep.target to state that string values are interpreted
as raw CSS selectors (so callers must include '#' for IDs and '.' for classes or
use other valid selector syntax).
| @click="next" | ||
| > | ||
| {{ hasNext || props.loop || currentStep?.nextLabel | ||
| ? (currentStep?.nextLabel || t('tour.next')) | ||
| : (currentStep?.finishLabel || t('tour.finish')) }} | ||
| </UButton> |
There was a problem hiding this comment.
currentStep?.nextLabel in the condition silently swallows finishLabel on the last step.
The current guard hasNext || props.loop || currentStep?.nextLabel means:
- When
loopistrue, the button always showsnextLabel || 'Next'—finishLabelis always ignored. - When on the last step (no
hasNext, noloop) butnextLabelis set, the button showsnextLabelinstead offinishLabel || 'Finish'.
Callers who set both nextLabel and finishLabel on the same step will find finishLabel has no effect.
🐛 Suggested fix
- {{ hasNext || props.loop || currentStep?.nextLabel
- ? (currentStep?.nextLabel || t('tour.next'))
- : (currentStep?.finishLabel || t('tour.finish')) }}
+ {{ hasNext || props.loop
+ ? (currentStep?.nextLabel || t('tour.next'))
+ : (currentStep?.finishLabel || t('tour.finish')) }}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| @click="next" | |
| > | |
| {{ hasNext || props.loop || currentStep?.nextLabel | |
| ? (currentStep?.nextLabel || t('tour.next')) | |
| : (currentStep?.finishLabel || t('tour.finish')) }} | |
| </UButton> | |
| `@click`="next" | |
| > | |
| {{ hasNext || props.loop | |
| ? (currentStep?.nextLabel || t('tour.next')) | |
| : (currentStep?.finishLabel || t('tour.finish')) }} | |
| </UButton> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/runtime/components/Tour.vue` around lines 424 - 429, The ternary logic in
the UButton rendering (using hasNext, props.loop, currentStep?.nextLabel)
wrongly prioritizes nextLabel over finishLabel; change it so the decision is
based only on whether there is a next step or loop is enabled: if (hasNext ||
props.loop) render (currentStep?.nextLabel || t('tour.next')), otherwise render
(currentStep?.finishLabel || t('tour.finish')). Update the expression around
currentStep?.nextLabel/currentStep?.finishLabel in the UButton (the same place
where hasNext and props.loop are checked) to implement this clear two-branch
conditional.
| close: 'Пӯшидан' | ||
| }, |
There was a problem hiding this comment.
toast.close change widens an existing inconsistency in Tajik "close" translations.
The Tajik locale already had two different words for "close" across components. Changing toast.close from 'Бастан' to 'Пӯшидан' to align with the new tour.close deepens that inconsistency rather than resolving it — alert.close, commandPalette.close, modal.close, and slideover.close still use 'Бастан'.
Consider either reverting toast.close to 'Бастан' to keep it consistent with the other close-action strings, or as a follow-up, aligning all close labels to a single word.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/runtime/locale/tj.ts` around lines 128 - 129, The change to toast.close
introduces a mismatch with other Tajik "close" labels; revert toast.close back
to 'Бастан' so it matches alert.close, commandPalette.close, modal.close and
slideover.close (or alternatively, as a follow-up, change all of those keys to
'Пӯшидан' for a unified term). Update the toast.close entry in the locale (the
toast.close key) to 'Бастан' to restore consistency with the other close-action
strings.
…, and modal support
Add an `overlay` option that darkens the rest of the page while keeping the highlighted target element and the tour popover visible. Uses an inline box-shadow spread on the highlight div for steps with a target, and a fullscreen fallback div for steps without one. The prop can be set globally or overridden per-step. - Add `overlay` slot to theme for the fullscreen fallback - Add `overlay` prop to TourStep and TourProps - Set z-index on Popover.Content when overlay is active so it renders above the shadow (reka-ui propagates it to the wrapper) - Add overlay example, docs section, playground toggle, and Tour entry in the playground navigation - Add missing `tour` key to Belarusian locale Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Translate next, previous, finish and close labels for the Tour component across all 57 non-English locale files. Translations follow each locale's existing conventions (e.g. reusing carousel.next/prev terms where applicable). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Refactor the inline styles of the popover content in Tour component snapshots to ensure consistent rendering. This change improves the clarity and maintainability of the snapshot tests by standardizing the style attributes across different test cases.
de565f7 to
9369ac3
Compare
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/content/docs/2.components/tour.md`:
- Around line 21-25: The docs currently list only selector strings and ref
functions for the step `target`, but the component's public type TourTarget also
accepts a direct ReferenceElement (an HTMLElement); update the text in the tour
documentation to include this third option and show an example like "a direct
HTMLElement (e.g., document.getElementById('foo') or a ReferenceElement)".
Mention TourTarget and the `target` property so readers can map the docs to the
component API.
In `@playgrounds/nuxt/app/pages/components/tour.vue`:
- Around line 40-41: The "Start tour" button currently only sets open = true and
doesn't reset the tour index, so reopenings resume the previous step; update the
click handler (or create a small method like startTour) to set step = 0 before
setting open = true (referencing the reactive vars step and open in this
component) so the demo always starts from step 0 when started again.
In `@src/runtime/components/Tour.vue`:
- Around line 186-190: The code currently uses fallbackRef (hidden <span>) as
the resolved target for `reference`, causing `updateHighlight()` to compute a
tiny `highlightRect` and spotlight the placeholder; change the logic so
`resolveTarget(target)` can return undefined and `reference` only falls back to
`fallbackRef` for popover positioning (not for the highlight). Specifically, in
the places around `currentStep.value?.target` / `resolveTarget(target)` (and the
other affected blocks at the indicated ranges), stop passing the hidden fallback
into the routine that computes `highlightRect`—leave `highlightRect` unset/null
when `resolveTarget` returns no real element, and only use `fallbackRef` when
computing popover position. Ensure `updateHighlight()` checks for a real
resolved element before computing/setting `highlightRect`.
- Around line 276-280: The tour currently only recomputes highlight geometry
(e.g., in goTo and the other step-change handlers) which can leave the target
off-screen; add an opt-in prop (e.g., autoScrollToTarget: boolean) and when
resolving the target element in goTo, next/prev/finish handlers, call
element.scrollIntoView({ block: "nearest", inline: "nearest", behavior: "smooth"
}) or a polyfilled scrollIntoViewIfNeeded before invoking updateHighlight
(ensure the scroll completes or await a small nextTick if needed), gated by the
new prop so scrolling is optional; update the handlers (goTo, the step
navigation functions referenced around those ranges) to perform the
scroll-to-target step prior to calling updateHighlight.
- Around line 242-245: The selector resolution currently calls
document.querySelector(selector) which will throw on invalid CSS selectors; wrap
that call in a try/catch inside the method that converts a string target to an
element (the block that checks typeof value === 'string' and builds const
selector) and on catch return null so the tour degrades to the no-target path
instead of crashing; keep the existing logic of normalizing '#' prefix and only
handle the error around document.querySelector to log/debug if desired and
return null.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 4a65c35f-c5e8-47fc-ba85-870d505d12f2
📒 Files selected for processing (9)
docs/app/components/content/examples/tour/TourBasicExample.vuedocs/app/components/content/examples/tour/TourCustomLabelsExample.vuedocs/app/components/content/examples/tour/TourLoopExample.vuedocs/app/components/content/examples/tour/TourModalExample.vuedocs/app/components/content/examples/tour/TourOverlayExample.vuedocs/content/docs/2.components/tour.mdplaygrounds/nuxt/app/composables/useNavigation.tsplaygrounds/nuxt/app/pages/components/tour.vuesrc/runtime/components/Tour.vue
🚧 Files skipped from review as they are similar to previous changes (4)
- docs/app/components/content/examples/tour/TourOverlayExample.vue
- docs/app/components/content/examples/tour/TourCustomLabelsExample.vue
- docs/app/components/content/examples/tour/TourLoopExample.vue
- docs/app/components/content/examples/tour/TourModalExample.vue
| <UButton @click="open = true"> | ||
| Start Tour | ||
| </UButton> |
There was a problem hiding this comment.
Restart the example tour from the first step.
This button only reopens the tour. If a reader closes it on step 2 or 3, “Start Tour” resumes there instead of showing the full example again.
💡 Proposed fix
- <UButton `@click`="open = true">
+ <UButton `@click`="step = 0; open = true">📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <UButton @click="open = true"> | |
| Start Tour | |
| </UButton> | |
| <UButton `@click`="step = 0; open = true"> | |
| Start Tour | |
| </UButton> |
| Each step in the tour requires a `target` property that can be: | ||
| - A string ID selector (e.g., `'#my-element'`) | ||
| - A CSS class selector (e.g., `'.my-class'`) | ||
| - A ref function that returns an HTMLElement (e.g., `() => myRef.value`) | ||
|
|
There was a problem hiding this comment.
Document direct element targets too.
TourTarget also accepts a ReferenceElement directly, but this list only mentions selector strings and functions. The docs should cover that input so the public API matches the component. Based on learnings, "Update documentation if applicable when making changes to components".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/content/docs/2.components/tour.md` around lines 21 - 25, The docs
currently list only selector strings and ref functions for the step `target`,
but the component's public type TourTarget also accepts a direct
ReferenceElement (an HTMLElement); update the text in the tour documentation to
include this third option and show an example like "a direct HTMLElement (e.g.,
document.getElementById('foo') or a ReferenceElement)". Mention TourTarget and
the `target` property so readers can map the docs to the component API.
| <UButton icon="i-lucide-wand-2" color="primary" variant="soft" @click="open = true"> | ||
| Start tour |
There was a problem hiding this comment.
Reset the demo to step 0 when starting again.
Clicking “Start tour” after finishing or closing mid-flow reopens the tour on the previous step because step is never reset.
💡 Proposed fix
- <UButton icon="i-lucide-wand-2" color="primary" variant="soft" `@click`="open = true">
+ <UButton icon="i-lucide-wand-2" color="primary" variant="soft" `@click`="step = 0; open = true">📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <UButton icon="i-lucide-wand-2" color="primary" variant="soft" @click="open = true"> | |
| Start tour | |
| <UButton icon="i-lucide-wand-2" color="primary" variant="soft" `@click`="step = 0; open = true"> | |
| Start tour |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@playgrounds/nuxt/app/pages/components/tour.vue` around lines 40 - 41, The
"Start tour" button currently only sets open = true and doesn't reset the tour
index, so reopenings resume the previous step; update the click handler (or
create a small method like startTour) to set step = 0 before setting open = true
(referencing the reactive vars step and open in this component) so the demo
always starts from step 0 when started again.
| const target = currentStep.value?.target | ||
| const resolved = resolveTarget(target) | ||
|
|
||
| return resolved ?? fallbackRef.value ?? undefined | ||
| }) |
There was a problem hiding this comment.
Don't build the spotlight from fallbackRef.
When a step target does not resolve, reference falls back to the hidden <span>, so updateHighlight() still produces a tiny rect and the overlay spotlights that placeholder instead of showing the fullscreen fallback overlay. Keep the fallback only for popover positioning, and leave highlightRect unset when there is no real target.
Also applies to: 255-273, 341-358
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/runtime/components/Tour.vue` around lines 186 - 190, The code currently
uses fallbackRef (hidden <span>) as the resolved target for `reference`, causing
`updateHighlight()` to compute a tiny `highlightRect` and spotlight the
placeholder; change the logic so `resolveTarget(target)` can return undefined
and `reference` only falls back to `fallbackRef` for popover positioning (not
for the highlight). Specifically, in the places around
`currentStep.value?.target` / `resolveTarget(target)` (and the other affected
blocks at the indicated ranges), stop passing the hidden fallback into the
routine that computes `highlightRect`—leave `highlightRect` unset/null when
`resolveTarget` returns no real element, and only use `fallbackRef` when
computing popover position. Ensure `updateHighlight()` checks for a real
resolved element before computing/setting `highlightRect`.
| if (typeof value === 'string') { | ||
| const selector = value.startsWith('#') || value.startsWith('.') ? value : `#${value}` | ||
|
|
||
| return document.querySelector(selector) as ReferenceElement | null |
There was a problem hiding this comment.
Catch malformed selector strings here.
document.querySelector() throws on invalid CSS selectors, and target is caller-provided data. A single bad step will crash the tour instead of degrading to the no-target path.
🐛 Proposed fix
if (typeof value === 'string') {
const selector = value.startsWith('#') || value.startsWith('.') ? value : `#${value}`
-
- return document.querySelector(selector) as ReferenceElement | null
+ try {
+ return document.querySelector(selector) as ReferenceElement | null
+ } catch {
+ return null
+ }
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (typeof value === 'string') { | |
| const selector = value.startsWith('#') || value.startsWith('.') ? value : `#${value}` | |
| return document.querySelector(selector) as ReferenceElement | null | |
| if (typeof value === 'string') { | |
| const selector = value.startsWith('#') || value.startsWith('.') ? value : `#${value}` | |
| try { | |
| return document.querySelector(selector) as ReferenceElement | null | |
| } catch { | |
| return null | |
| } | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/runtime/components/Tour.vue` around lines 242 - 245, The selector
resolution currently calls document.querySelector(selector) which will throw on
invalid CSS selectors; wrap that call in a try/catch inside the method that
converts a string target to an element (the block that checks typeof value ===
'string' and builds const selector) and on catch return null so the tour
degrades to the no-target path instead of crashing; keep the existing logic of
normalizing '#' prefix and only handle the error around document.querySelector
to log/debug if desired and return null.
| function goTo(index: number) { | ||
| currentIndex.value = index | ||
| open.value = true | ||
| nextTick(updateHighlight) | ||
| } |
There was a problem hiding this comment.
Step transitions need to bring the target into view.
These code paths only recompute geometry. If the next target is below the fold or inside a scrollable container, the popover/highlight can open completely off-screen, which breaks the tour flow. Scroll the resolved target into view before updateHighlight() runs, ideally behind an opt-in prop.
Also applies to: 282-294, 300-304, 313-323
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/runtime/components/Tour.vue` around lines 276 - 280, The tour currently
only recomputes highlight geometry (e.g., in goTo and the other step-change
handlers) which can leave the target off-screen; add an opt-in prop (e.g.,
autoScrollToTarget: boolean) and when resolving the target element in goTo,
next/prev/finish handlers, call element.scrollIntoView({ block: "nearest",
inline: "nearest", behavior: "smooth" }) or a polyfilled scrollIntoViewIfNeeded
before invoking updateHighlight (ensure the scroll completes or await a small
nextTick if needed), gated by the new prop so scrolling is optional; update the
handlers (goTo, the step navigation functions referenced around those ranges) to
perform the scroll-to-target step prior to calling updateHighlight.
🔗 Linked issue
Resolves #4874
❓ Type of change
📚 Description
The Tour component provides a guided tour experience that highlights specific elements and displays step-by-step instructions. Each tour consists of multiple steps, where each step can target an element by ID selector, CSS class selector, or a ref function. The component automatically highlights target elements with a customizable border and shadow effect, positioning the tour content (popover) relative to each target.
Key features include navigation controls (next, previous, finish) with customizable labels per step, a loop option to automatically restart the tour, and modal mode to block interaction with outside elements for better accessibility. Steps can be configured with custom content positioning, dismissible behavior, and optional arrows. The tour supports custom slots for complete UI customization and includes built-in accessibility features with proper ARIA labels and screen reader support.
Registrazione.schermo.2025-12-29.alle.22.22.09.mov
Overlay effect [NEW]
Registrazione.schermo.2026-02-14.alle.11.19.14.mov
TODO
📝 Checklist