Démarrer
Installer les deux paquets, lancer une première visite, puis brancher le provider sur une vraie application.
guide accompagne un nouvel utilisateur dans une interface, une étape à la fois. La logique tient dans un paquet, le rendu Material UI dans un second.
Deux paquets, et pourquoi
npm install @apollovisionlabs/guide-core @apollovisionlabs/guide-mui @mui/material @emotion/react @emotion/styled
@apollovisionlabs/guide-core contient la machine à états, la résolution des
cibles, la correspondance de routes, la persistance et les primitives
d’accessibilité. Il n’affiche rien et ne dépend que de React.
@apollovisionlabs/guide-mui est un rendu de ce moteur : un projecteur qui assombrit
la page et une bulle d’étape, en Material UI. Sa seule dépendance de production est
le core.
Si vous dessinez votre propre bulle, installez le core seul et lisez l’étape
courante avec useGuideStep(). Tout ce qui suit suppose la couche Material UI,
qui est le chemin le plus court vers une visite qui tourne.
Le plus petit exemple qui fonctionne
import { GuideProvider, useTour, type Tour } from '@apollovisionlabs/guide-core';
import { GuideTour } from '@apollovisionlabs/guide-mui';
const welcomeTour: Tour = {
id: 'welcome',
steps: [
{
target: 'nav.projects',
title: 'Vos projets sont ici',
body: 'Tout ce que vous créez est rangé dans un projet.',
placement: 'bottom',
},
],
};
function StartButton() {
const tour = useTour('welcome');
return <button onClick={() => tour.start()}>Lancer la visite</button>;
}
export function App() {
return (
<GuideProvider tours={[welcomeTour]}>
<nav>
<a href="/projects" data-guide="nav.projects">
Projets
</a>
</nav>
<StartButton />
<GuideTour />
</GuideProvider>
);
}
GuideProvider porte l’état, GuideTour l’affiche. Les deux lisent le thème
Material UI : gardez-les à l’intérieur de votre ThemeProvider si vous en avez un.
Déclarez la visite au niveau du module, comme ci-dessus. Un objet visite reconstruit
dans un corps de composant est un objet neuf à chaque rendu, et le délai de cible
absente s’appuie sur l’identité des objets étape : recréez-les à chaque rendu et ce
minuteur n’atteint jamais son échéance. Le symptôme est une visite bloquée
indéfiniment sur une étape, avec onMissingTarget qui semble ignoré. Si une visite
doit vraiment être construite à l’exécution, construisez-la une fois dans un
useMemo aux dépendances stables.
Comment une étape trouve sa cible
target est une clé logique, pas un sélecteur CSS. Le moteur cherche
[data-guide="<clé>"] : c’est l’élément mis en avant qui déclare sa participation.
<button data-guide="projects.create">Nouveau projet</button>
Un sélecteur CSS lierait la visite à un balisage qui change pour des raisons
étrangères : une classe renommée par une refonte graphique, un conteneur ajouté par
un remaniement de mise en page, un nom de classe généré par une bibliothèque de
style. Un attribut data-guide est un contrat, visible dans le source de l’élément,
qu’un relecteur voit qu’il est sur le point de casser.
Donnez un espace de noms aux clés, du type nav.projects ou projects.create.
Elles apparaissent dans les événements step:show et target:missing, donc dans
vos journaux.
L’élément n’a pas besoin d’exister tout de suite. Le moteur observe le DOM avec un
MutationObserver pendant targetTimeoutMs (5000 ms par défaut), puis applique la
politique de cible absente décrite dans
Visites.
Brancher une vraie application
Cinq props transforment l’exemple minimal en quelque chose de livrable.
import { useLocation, useNavigate } from 'react-router';
import { useTranslation } from 'react-i18next';
import { GuideProvider, createBrowserStorage } from '@apollovisionlabs/guide-core';
import { GuideTour } from '@apollovisionlabs/guide-mui';
import { productTour } from './tours';
const storage = createBrowserStorage('my-app');
export function App() {
const navigate = useNavigate();
const location = useLocation();
const { t } = useTranslation();
return (
<GuideProvider
tours={[productTour]}
navigate={(path) => navigate(path)}
location={location.pathname}
storage={storage}
translate={(key) => t(key)}
onEvent={(event) => console.info('[guide]', event)}
>
<AppRoutes />
<GuideTour />
</GuideProvider>
);
}
navigate est appelée quand une étape vit sur une autre page. location est le
chemin courant : c’est ainsi que le moteur sait s’il y est déjà. Sans location,
toutes les étapes sont considérées comme étant sur la bonne page et plus rien ne
navigue.
storage conserve la progression. Deux implémentations sont fournies :
createMemoryStorage() pour les tests, createBrowserStorage(namespace) pour
localStorage. Aucune ne parle à un serveur, et les paquets ne font aucun appel
réseau. Sur un poste partagé, localStorage appartient au profil du navigateur et
non à la personne connectée : la visite terminée par la première la supprime pour
la seconde. Quand plusieurs comptes se partagent une machine, implémentez
GuideStorage contre votre propre API.
translate résout titleKey et bodyKey. Elle prend une clé et rend une chaîne,
ce qui tient en une ligne avec n’importe quelle bibliothèque de traduction. Une clé
sans translate affiche la clé brute plutôt que de planter : c’est le symptôme à
reconnaître. Les libellés des boutons de la bulle sont séparés et se remplacent par
labels sur GuideTour :
<GuideTour
labels={{
next: t('common.next'),
previous: t('common.back'),
finish: t('common.finish'),
close: t('common.close'),
}}
/>
close est aussi le nom accessible du bouton de fermeture : le traduire n’est pas
cosmétique. Checklist et ChecklistLauncher acceptent leurs propres labels de
la même façon, décrits dans Checklist.
onEvent reçoit tous les GuideEvent : tour:start, tour:complete,
tour:stop, step:show et target:missing. La bibliothèque n’envoie rien nulle
part ; ce que vous enregistrez et le consentement que cela demande relèvent de
votre application.
Versions requises
React 19 pour le core. React 19, Material UI 7 ou 9 et Emotion 11 pour la couche
Material UI. Les deux paquets portent une directive 'use client' sur chaque
fichier émis : les importer ne casse pas un build serveur. GuideProvider utilise
malgré tout état et contexte, donc le composant qui le rend est un composant client.
GuideTour rend null tant qu’il n’est pas monté dans le navigateur, ce qui garde
la visite hors du HTML rendu côté serveur.