Correction tech-steps : sélectionner du texte pour ajouter un ingrédient/ustensile/température ferme le popover en cours #36
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Contexte
Depuis la refonte du popover de correction des tech-steps (#29-#32), une fois
un popover ouvert sur une technique, chaque section Ingrédients/Ustensiles/
Température permet d'ajouter une mention en cliquant "+ Ajouter..." puis en
surlignant le texte correspondant dans la description de l'étape — pensé
explicitement pour ne pas fermer le popover pendant cette sélection (voir
la doc de
TechStepCorrectionPopover.tsx: "the description stays fullyvisible and selectable the whole time, nothing overlays it" / "can ask the
viewer to select a second span of text without closing this popover
first").
En pratique ce n'est pas ce qui se passe : surligner le texte demandé ferme
le popover ouvert et un autre s'ouvre à sa place — comme si le texte
sélectionné devait servir à une toute nouvelle correction de technique, pas à
l'ingrédient/ustensile/température qu'on essayait d'ajouter à la correction
en cours (perdant au passage la technique déjà choisie et tout ce qui avait
déjà été ajouté avant validation).
Cause
TechStepCorrectionPopover.tsxferme le popover au premiermousedownendehors de son propre DOM (même patron "outside-click" que
WeekNavigator'sCalendarPopover) :Le
<p>contenant la description de l'étape (StepDescription.tsx, refcontainerRef) est un frère du popover dans le DOM, pas un de sesdescendants — donc tout
mousedowndedans, y compris celui qui démarre leglisser-sélectionner demandé par le hint "Sélectionnez le texte
correspondant..." (
selectSpanHint), est vu comme "en dehors" et fermeimmédiatement le popover, avant même que le
mouseupqui termine lasélection ne se déclenche.
Séquence exacte :
requestSpan("ingredient")(
TechStepCorrectionPopover.tsx:516-519) →onRequestSpan("ingredient")remonte à
StepDescription, qui metpendingSpanRequest = "ingredient"(branché directement :
onRequestSpan={setPendingSpanRequest},StepDescription.tsx:340).mousedownsur le<p>→handleClickOutsidedu popover (toujoursmonté à cet instant) le voit comme un clic extérieur →
onClose()→closeActiveCorrection()(StepDescription.tsx:140-144) remet tout ànull, y comprispendingSpanRequest→ le popover se démonte.mouseup→handleMouseUps'exécutetoujours (attaché au
<p>, pas au popover) maispendingSpanRequestestdéjà
null(remis à zéro à l'étape 2) → tombe dans la branche par défaut,setActiveCorrection({ range, selectedText, previousTechStepId: null })(
StepDescription.tsx:161-165) → un nouveau popover s'ouvre,traitant le texte sélectionné comme une toute nouvelle proposition de
technique.
Reproduction
/recettes/:id), sur un textecontenant à la fois une technique et un ingrédient/ustensile mentionnés
(ex. "Faire revenir l'oignon dans une poêle").
texte pour en proposer une) → le popover de correction s'ouvre.
(ou Ustensile/Température) — le popover affiche l'invite "Sélectionnez le
texte correspondant dans la description".
tant que nouvelle proposition de technique — la technique choisie à
l'étape 3 et tout ingrédient/ustensile/température déjà ajouté sont
perdus.
Impact
Rend "ajouter un ingrédient/ustensile/température à une correction de
technique" essentiellement inutilisable — c'est le seul moyen prévu de le
faire (le hint de l'interface le demande explicitement), et il casse
systématiquement à chaque tentative, quelle que soit la section
(Ingrédients/Ustensiles/Température, les trois partagent le même mécanisme
awaitingSpanFor/pendingSpanRequest).Pourquoi ça n'est couvert par aucun test existant
TechStepCorrectionPopover.cy.tsx(test composant) simule le retour deonRequestSpanen injectant directement unresolvedMetadataSpanfixe(
Harness), sans jamais faire vivreStepDescription/le vrai DOM desélection — avec ce commentaire explicite dans le fichier :
Or ce scénario e2e n'existe pas : ni
recipes.featurenirecipes.tsnecontiennent le moindre step lié à l'ajout d'un ingrédient/ustensile/
température via sélection. L'intégration réelle "sélectionner du texte dans
StepDescriptionpendant qu'un popoverTechStepCorrectionPopoverestouvert" n'est testée nulle part dans la suite — ce qui explique que la
régression ait pu passer inaperçue lors de la vérification de #29/#30 (suite
verte à 100% par ailleurs, mais sur des chemins qui ne couvrent pas cette
interaction précise).
Pistes de correction
Fix recommandé — exempter le conteneur de la description du "clic
extérieur" du popover, plutôt que fermer sur tout
mousedownhors de sonpropre DOM :
descriptionContainerRef: nouveau prop optionnel —StepDescriptionpassesimplement son
containerRefexistant (déjà utilisé paruseTextSelection), aucune nouvelle ref à créer, juste un fil à tirer d'uncomposant à l'autre.
Vérifié que ça ne casse rien d'autre :
ouvert) : inchangé, ce listener n'existe pas tant qu'aucun popover n'est
monté.
description pendant qu'un popover est ouvert :
StepDescription's propreonClick(StepDescription.tsx:304-320pour une technique) fait déjàsetActiveCorrection(...)explicitement — inchangé, cette exemption nefait que retirer une fermeture concurrente qui arrivait à la même
conclusion par coïncidence.
comme "outside", popover toujours fermé normalement.
Alternative plus simple, moins fidèle à l'intention documentée : ne
fermer sur aucun clic extérieur tant que
awaitingSpanFor !== null(statedéjà existant dans le popover), sans threader de ref supplémentaire — mais
bloque aussi la fermeture pour un clic voulu ailleurs pendant qu'on attend
une sélection (il faudrait alors explicitement cliquer "Annuler" dans la
section pour se débloquer).
Test à ajouter (comble le vrai trou de couverture identifié plus haut) :
écrire le scénario e2e que le commentaire de
TechStepCorrectionPopover.cy.tsxprétend déjà exister (ou corriger ce commentaire si la couverture reste
volontairement au niveau composant) : ouvrir une vraie
StepDescriptionéditable, ouvrir une correction, cliquer "+ Ajouter un ingrédient", puis
simuler une vraie sélection de texte dans la description et vérifier que
le même popover reste ouvert avec le nouvel ingrédient ajouté (pas un
popover vierge pour une nouvelle technique). Simuler une sélection réelle en
Cypress :
.trigger("mousedown")sur le segment de départ, construire unRange/Selectionviacy.window()(document.createRange()+window.getSelection().addRange(...)sur les vrais nœuds texte des segmentsdata-offsetrendus), puis.trigger("mouseup")sur la description — pas unsimple
.click(), qui ne reproduit pas la séquence mousedown-avant-mouseupqui déclenche ce bug. Sans ce test, rien ne garantit que le correctif tienne
dans la durée (même levier que la régression
resourceTypede #32).Hors scope
sélection plutôt que de le garder fixe sous l'étape) — le placement actuel
est un choix assumé documenté dans le composant, non remis en cause ici.
🤖 Filed by Claude Code