Le système de modal dynamique permet de définir la taille d'une modale via des attributs DOM dans les vues, sans nécessiter de logique côté serveur. Cette fonctionnalité s'applique uniquement à la modale principale (main-modal).
Le système utilise un contrôleur Stimulus (dynamic_modal_controller) qui écoute les événements de chargement Turbo Frame et applique dynamiquement les classes CSS de dimensionnement au conteneur de la modale.
- Contrôleur Stimulus:
app/javascript/controllers/dynamic_modal_controller.js - Partial de modal:
app/views/shared/_modal.html.erb - Événements:
turbo:frame-loadsur le turbo-framemain-modal-content
Vous pouvez utiliser des tailles prédéfinies via l'attribut data-modal-size sur le premier élément enfant du turbo-frame:
<turbo-frame id="main-modal-content">
<div data-modal-size="small">
<!-- contenu de la modale -->
</div>
</turbo-frame>Important: L'attribut data-modal-size doit être placé sur le premier élément enfant du turbo-frame, pas sur le turbo-frame lui-même. Cela permet à Turbo de charger le contenu sans perdre l'attribut.
| Taille | Classes CSS | Usage recommandé |
|---|---|---|
small |
fr-col-12 fr-col-md-6 fr-col-lg-4 |
Confirmations simples, alertes |
medium |
fr-col-12 fr-col-md-8 fr-col-lg-6 |
Taille par défaut |
large |
fr-col-12 fr-col-md-10 fr-col-lg-8 |
Formulaires avec plusieurs champs |
full |
fr-col-12 |
Contenu nécessitant toute la largeur |
Pour un contrôle plus précis, utilisez l'attribut data-modal-size-classes sur le premier élément enfant:
<turbo-frame id="main-modal-content">
<div data-modal-size-classes="fr-col-12 fr-col-md-9 fr-col-lg-7">
<!-- contenu de la modale -->
</div>
</turbo-frame><turbo-frame id="main-modal-content">
<div data-modal-size="large">
<%= form_with(model: @denial_of_authorization, ...) do |f| %>
<div class="fr-modal__content">
<h1 class="fr-modal__title">Refuser la demande</h1>
<%= f.dsfr_text_area :reason %>
</div>
<div class="fr-modal__footer">
<!-- boutons -->
</div>
<% end %>
</div>
</turbo-frame><turbo-frame id="main-modal-content">
<div>
<div class="fr-modal__content">
<h1 class="fr-modal__title">Confirmer l'action</h1>
<p>Êtes-vous sûr de vouloir continuer ?</p>
</div>
<div class="fr-modal__footer">
<!-- boutons -->
</div>
</div>
</turbo-frame><turbo-frame id="main-modal-content">
<div data-modal-size-classes="fr-col-12">
<div class="fr-modal__content">
<h1 class="fr-modal__title">Vue complète</h1>
<!-- contenu large -->
</div>
</div>
</turbo-frame>L'ordre de priorité pour déterminer la taille de la modale est:
data-modal-size-classes(classes personnalisées)data-modal-size(taille prédéfinie)- Taille par défaut (
fr-col-12 fr-col-md-8 fr-col-lg-6)
Les vues existantes sans attributs de taille continuent de fonctionner avec la taille par défaut. Aucune modification n'est nécessaire pour maintenir le comportement actuel.
Lorsque vous naviguez entre différents contenus de modale, la taille s'adapte automatiquement en fonction des attributs du nouveau contenu.
- Cette fonctionnalité s'applique uniquement à la modale principale (
main-modal) - Les autres modales (via
:extra_modal) conservent leur comportement standard - Le contrôleur est simple et ne fait pas de validation des valeurs fournies
Le contrôleur utilise deux mécanismes pour détecter les changements:
- Événement Turbo:
turbo:frame-loadsur le turbo-frame - MutationObserver: Observe les changements DOM dans le turbo-frame
connect() {
this.contentTarget.addEventListener('turbo:frame-load', this.applySizeClasses.bind(this))
this.observer = new MutationObserver(() => {
this.applySizeClasses()
})
this.observer.observe(this.contentTarget, {
childList: true,
subtree: true
})
this.applySizeClasses()
}Le contrôleur:
- Lit les attributs du premier élément enfant du turbo-frame (priorité 1)
- Si absent, cherche sur le turbo-frame lui-même (priorité 2)
- Détermine les classes CSS à appliquer selon l'ordre de priorité:
data-modal-size-classes(classes personnalisées)data-modal-size(taille prédéfinie)- Classes par défaut
- Remplace les classes
fr-col-*du conteneur par les nouvelles classes
Le contrôleur complet est disponible dans app/javascript/controllers/dynamic_modal_controller.js.