Hotspots
Un marqueur sur un élément qui ouvre une courte explication et peut lancer une visite, ce qui le retire pour de bon, et quand il ne dessine plus rien du tout.
Un hotspot est un petit marqueur épinglé sur un élément, en dehors de toute visite. Cliquer dessus
ouvre une bulle avec un titre, un texte, et, en option, un bouton qui lance une visite. Ouvrir la
bulle marque le hotspot comme vu, pour de bon : un hotspot vu ne dessine plus aucun marqueur, ni
sur cette page ni à la visite suivante, jusqu’à ce que reset() soit appelé.
Hotspot et ResolvedHotspot
interface Hotspot {
id: string;
target: string;
title?: string;
titleKey?: string;
body?: string;
bodyKey?: string;
tourId?: string;
placement?: 'top' | 'bottom' | 'left' | 'right';
}
target: la clé logique portée par l’attributdata-guidede l’élément, comparée de la même façon que letargetd’une étape de visite.title/body: du texte littéral.titleKey/bodyKeypassent par la proptranslatedu provider, exactement comme une étape de visite.tourId: la visite lancée quand le bouton « Show me » de la bulle est cliqué. Omettez-le et la bulle n’affiche qu’un bouton Fermer.placement: remplace le placement par défaut de la bulle, pour ce hotspot uniquement.
Deux hotspots partageant un id font échouer HotspotProvider au rendu, immédiatement, tout comme
un identifiant de visite dupliqué.
useHotspots() renvoie chaque hotspot résolu en ResolvedHotspot, avec son texte déjà traduit et
son état vu attaché :
interface ResolvedHotspot {
id: string;
target: string;
title: string;
body: string;
seen: boolean;
tourId?: string;
placement?: 'top' | 'bottom' | 'left' | 'right';
}
HotspotProvider et useHotspots
import {
HotspotProvider,
createBrowserStorage,
type Hotspot,
} from '@apollovisionlabs/guide-core';
import { Hotspots } from '@apollovisionlabs/guide-mui';
const storage = createBrowserStorage('my-app');
const hotspots: Hotspot[] = [
{ id: 'share', target: 'project.share', title: 'Share a project', tourId: 'sharing' },
];
export function App() {
return (
<HotspotProvider hotspots={hotspots} storage={storage}>
<AppRoutes />
<Hotspots />
</HotspotProvider>
);
}
| Prop | Type | Défaut | Description |
|---|---|---|---|
hotspots |
Hotspot[] |
aucun | Les hotspots disponibles dans cet arbre. Les identifiants doivent être uniques. |
children |
ReactNode |
aucun | Votre application. |
storage |
GuideStorage |
aucun | Persiste les hotspots déjà ouverts, sous la seule clé hotspots:seen. Voir Persistance. |
translate |
(key: string) => string |
aucun | Résout titleKey / bodyKey. |
onEvent |
(event: GuideEvent) => void |
aucun | Appelé pour hotspot:show et hotspot:open. Voir « Événements » ci-dessous. |
useHotspots() renvoie :
interface UseHotspotsResult {
hotspots: ResolvedHotspot[];
restored: boolean;
open: (hotspotId: string) => void;
startTour: (hotspotId: string) => void;
reset: () => void;
notifyShown: (hotspotId: string) => void;
}
hotspots: tous les hotspots, vus et non vus, chacun avec son propreseen. Un rendu a besoin aussi de ceux déjà vus, pour garder un marqueur monté pendant que sa propre bulle se ferme ; filtrer sur les non vus tient en une ligne au point d’appel si c’est tout ce qu’il vous faut.restored: si la lecture initiale depuis le stockage s’est stabilisée.trueimmédiatement quand aucune propstoragen’a été fournie, puisqu’il n’y a alors rien à attendre, ettrueune fois que la lecture se résout ou échoue dans les autres cas, y compris une lecture en échec. Un rendu devrait attendre cette valeur avant de dessiner le moindre marqueur, sinon un hotspot déjà vu en stockage peut clignoter à l’écran une fois avant que la restauration n’arrive.open(hotspotId): marque le hotspot comme vu et émethotspot:open. Le rappeler sur un hotspot déjà vu ne fait plus rien. Écrit un avertissement dans la console et ne fait rien pour un identifiant qui ne désigne aucun hotspot.startTour(hotspotId): lance letourIddu hotspot sur leGuideProviderle plus proche. Ne fait rien si le hotspot n’a pas detourId. Avertit une fois si l’arbre n’a pas deGuideProvider, et avertit une fois si la visite échoue à démarrer.reset(): efface tous les hotspots vus d’un coup, ramenant tous les marqueurs. Il n’existe pas d’annulation par hotspot.notifyShown(hotspotId): appelé par un rendu une fois qu’un marqueur est effectivement dessiné à l’écran. Déclenchehotspot:show, et est dédupliqué par hotspot et par montage, si bien qu’un défilement qui remesure la cible n’annonce pas une seconde impression.Hotspotsl’appelle déjà pour vous ; ne l’écrivez vous-même que si vous dessinez vos propres marqueurs par-dessususeHotspots.
Ouvrir retire un hotspot, pour de bon
open(hotspotId), que le marqueur fourni appelle quand on clique dessus, est la seule chose qui
passe seen à true. Une fois qu’il a tourné pour un hotspot, le seen de ce
ResolvedHotspot vaut true partout où useHotspots() est lu, et, avec storage configuré, le
reste après rechargement, car il est écrit sous hotspots:seen. Le composant Hotspots ne
dessine rien pour un hotspot vu. Le seul retour en arrière est reset(), et il emporte tous les
hotspots avec lui : il n’y a pas de moyen de faire redevenir non vu un seul hotspot.
Le composant MUI Hotspots
import { Hotspots } from '@apollovisionlabs/guide-mui';
<Hotspots labels={{ startTour: 'Show me', close: 'Close' }} placement="bottom" />;
| Prop | Type | Défaut | Description |
|---|---|---|---|
labels |
Partial<HotspotLabels> |
voir ci-dessous | Le nom accessible du marqueur et le texte des boutons de la bulle. |
placement |
'top' | 'bottom' | 'left' | 'right' |
'bottom' |
Placement par défaut de la bulle ; le placement propre au hotspot l’emporte. |
zIndex |
number |
theme.zIndex.drawer + 1 |
Niveau d’empilement du marqueur ; la bulle se place un niveau au-dessus. Voir « Limites » ci-dessous pour les cas où cela compte. |
HotspotLabels.marker est une fonction
interface HotspotLabels {
marker: (title: string) => string;
startTour: string;
close: string;
}
Défauts : marker: (title) => \Show what is new: ${title}`, startTour: ‘Show me’, close: ‘Close’`.
marker construit le nom accessible du bouton marqueur, et c’est une fonction plutôt qu’un
gabarit de chaîne parce que la place du titre dans la phrase n’est pas la même d’une langue à
l’autre : une traduction peut avoir besoin de mettre le titre en premier, de l’entourer
autrement, ou de laisser tomber la formule d’introduction. startTour et close sont de simples
chaînes, comme le reste des labels de GuideTour et Checklist.
Événements
| Événement | Charge utile | Quand |
|---|---|---|
hotspot:show |
{ hotspotId } |
Le marqueur d’un hotspot est effectivement dessiné à l’écran. Émis une fois par hotspot et par montage. |
hotspot:open |
{ hotspotId } |
La bulle du hotspot s’ouvre, ce qui le marque aussi comme vu. Pas réémis pour une bulle déjà ouverte ; un second clic sur un marqueur ouvert se contente de la fermer. |
Les hotspots s’effacent devant une visite en cours
Tant qu’une visite est running ou paused, Hotspots ne dessine aucun marqueur, pas seulement
ceux qui entrent en collision avec la cible de l’étape en cours. Un marqueur est
position: fixed sur le coin supérieur droit de sa cible, donc quand une étape de visite pointe
sur ce même élément, le marqueur peut intercepter le clic censé faire avancer une étape
advanceOn: 'click', rester à pulser inutilement par-dessus le spot d’une étape non interactive,
ou garder le focus clavier au-dessus de l’étape qu’une visite vient tout juste de lancer depuis sa
propre bulle. Plutôt que de résoudre chacune de ces collisions au cas par cas, aucun marqueur de
hotspot ne se dessine tant qu’une visite est en cours.
paused compte comme en cours : une visite en pause attend sa cible, elle n’est pas terminée.
C’est une mise en sourdine, pas un retrait. Rien ici ne touche seen, donc les marqueurs
reviennent exactement comme avant, non vus compris, dès que la visite s’arrête ou se termine, et
hotspot:show se redéclenche pour eux puisque sa déduplication se fait par montage, pas
globalement.
Limites
- Un hotspot dans une boîte de dialogue modale est couvert. Le
zIndexpar défaut du marqueur esttheme.zIndex.drawer + 1, choisi pour se placer au-dessus d’une barre d’application ou d’un tiroir, où se trouve souvent la cible d’un hotspot, et en dessous du spot d’une visite en cours, àtheme.zIndex.modal. Une boîte de dialogue se rend elle aussi au-dessus du niveau du tiroir, donc un hotspot dont la cible vit à l’intérieur d’une boîte de dialogue est couvert par elle, sauf à releverzIndexau-dessus. - Avec
storageconfiguré, aucun marqueur ne se dessine tant que la lecture initiale ne s’est pas stabilisée.Hotspotsattendrestoredavant de dessiner quoi que ce soit, donc avec un stockage lent le premier rendu n’affiche aucun marqueur, et ils apparaissent une fois la lecture résolue. - Une visite en pause sur une cible qui ne se monte jamais met tous les hotspots en sourdine
aussi longtemps qu’elle reste en pause. Sous la politique de cible absente
wait, une visite en pause ne dessine déjà rien elle-même ; les hotspots s’effaçant devant elle aussi, la page peut se retrouver sans aucune affordance visible,Échaprestant la seule sortie.
Pour aller plus loin
- Visites guidées pour
tourId, les politiques de cible absente, et ce que signifiepaused. - Persistance pour
GuideStorageet le comportement de fusion à la restauration. - Migrer vers 0.3.0 pour ce qui a changé avec l’arrivée des hotspots.
- Référence de l’API pour tous les symboles exportés.