Utiliser l'API DModal pour afficher des fenêtres modales (alias popups/dialogues) dans Discourse

Discourse 3.1.0.beta6 intègre une toute nouvelle API basée sur les composants <DModal>.

:information_source: Cette nouvelle API remplace l’ancienne API basée sur les contrôleurs, qui est désormais obsolète. Si vous utilisez encore des modales avec l’ancienne API, consultez le guide de migration ici.

Affichage d’une modale

Les modales sont affichées en incluant le composant <DModal> dans un modèle Handlebars. Si vous ne disposez pas encore d’un modèle approprié, consultez Using Plugin Outlet Connectors from a Theme or Plugin.

Une modale simple ressemblerait à ceci :

<DButton
  @translatedLabel="Afficher la modale"
  @action={{fn (mut this.modalIsVisible) true}}
/>

{{#if this.modalIsVisible}}
  <DModal @title="Ma modale" @closeModal={{fn (mut this.modalIsVisible) false}}>
    Bonjour le monde, voici du contenu dans une modale
  </DModal>
{{/if}}

:information_source: L’helper mut est utilisé ici comme une méthode spécifique à hbs pour définir une valeur. Vous pouvez également définir modalIsVisible en utilisant n’importe quelle autre méthode standard d’Ember.

Cet exemple créera une modale simple comme celle-ci :

Encapsulation dans un composant

Avant d’introduire plus de complexité, il est généralement préférable d’encapsuler votre nouvelle modale dans sa propre définition de composant. Déplaçons le contenu de <DModal> dans un nouveau composant <MyModal />.

// components/my-modal.gjs
<template>
  <DModal @title="Ma modale" @closeModal={{@closeModal}}>
    Bonjour le monde, voici du contenu dans une modale
  </DModal>
</template>

Mettre à jour ce fichier .gjs vers un composant basé sur une classe vous permettra d’introduire une logique et un état plus complexes.

Pour utiliser le nouveau composant, mettez à jour l’appel pour le référencer, en veillant à transmettre un argument @closeModal.

<DButton
  @translatedLabel="Afficher la modale"
  @action={{fn (mut this.modalIsVisible) true}}
/>

{{#if this.modalIsVisible}}
  <MyModal @closeModal={{fn (mut this.modalIsVisible) false}} />
{{/if}}

Ajout d’un pied de page

De nombreuses modales comportent une sorte d’appel à l’action. Dans Discourse, celles-ci sont généralement situées en bas de la modale. Pour rendre cela possible, DModal dispose de plusieurs « blocs nommés » dans lesquels du contenu peut être rendu. Voici l’exemple mis à jour pour inclure deux boutons dans le pied de page, dont l’un est notre bouton standard DModalCancel.

<DModal @title="Ma modale" @closeModal={{@closeModal}}>
  <:body>
    Bonjour le monde, voici du contenu dans une modale
  </:body>
  <:footer>
    <DButton class="btn-primary" @translatedLabel="Soumettre" />
    <DModalCancel @close={{@closeModal}} />
  </:footer>
</DModal>

Affichage d’une modale depuis un contexte non hbs

Idéalement, les instances de <DModal> doivent être affichées depuis un modèle Ember en utilisant la technique déclarative démontrée ci-dessus. Si cela n’est pas réalisable pour votre cas d’utilisation, cela peut être fait en injectant le service modal et en appelant modal.show().

Assurez-vous d’avoir encapsulé votre modale dans son propre composant comme décrit ci-dessus. Ensuite, déclenchez la modale en passant une référence de votre classe de composant à showModal :

import MyModal from "discourse/components/my-modal";

// (injectez le service modal à l'endroit approprié)

// Ajoutez cet appel chaque fois que vous souhaitez ouvrir la modale.
// Un argument `@closeModal` sera automatiquement transmis à votre composant.
this.modal.show(MyModal);

// Optionnellement, passez un paramètre `model`. Transmis sous forme de `@model` à votre composant.
// Cela peut inclure des données, ainsi que des actions/rappels pour votre modale à utiliser.
this.modal.show(MyModal, {
  model: { topic: this.topic, someAction: this.someAction },
});

// `modal.show()` retourne une promesse, vous pouvez donc attendre sa fermeture.
// Elle sera résolue avec les données transmises à l'action `@closeModal`.
const result = await this.modal.show(MyModal);

Plus de personnalisation !

<DModal> dispose de plusieurs blocs nommés et arguments.

Arguments

Argument Objectif
@closeModal Requis pour que l’interface de fermeture apparaisse.
@title Affiche <h1 id="discourse-modal-title"> ; lie aria-labelledby.
@subtitle Petit texte sous le titre.
@flash / @flashType Alerte en ligne en haut de la modale (DFlashMessage).
@hideHeader, @hideFooter Cache les régions entières.
@headerClass, @bodyClass Classes supplémentaires sur les wrappers du header/body.
@dismissable Par défaut true lorsque @closeModal est défini. Désactive Échap / clic sur le fond / X.
@autofocus Par défaut true. Met automatiquement le focus sur le premier élément focusable via dTrapTab.
@submitOnEnter Par défaut true. La touche Entrée clique sur .d-modal__footer .btn-primary sauf si le focus est dans un formulaire / textarea / select-kit.
@beforeClose async ({ initiatedBy }) => boolean. Retournez false pour annuler la fermeture (par exemple, confirmation de formulaire modifié).
@hidden Met en pause la gestion du clavier ; utilisé lorsqu’une modale imbriquée est au premier plan.
@tagName "div" (par défaut) ou "form". Utilisez "form" pour les formulaires afin que la soumission native fonctionne.

Blocs

Bloc Position Quand l’utiliser
default / :body Zone de contenu principale Zone par défaut
:aboveHeader Tout en haut, avant l’en-tête Rarement nécessaire ; pour le contenu qui doit se situer au-dessus de la barre de titre (par exemple, une bannière).
:headerAboveTitle Dans l’en-tête, avant le titre Présent mais inutilisé. Rarement nécessaire.
:belowModalTitle Dans .d-modal__title, après le <h1> Excellente position pour des métadonnées supplémentaires.
:headerBelowTitle Dans l’en-tête, après le bloc titre Onglets, sous-navigation ou champ de recherche faisant partie de l’en-tête.
:headerPrimaryAction Côté droit de l’en-tête uniquement sur mobile Remplace le bouton de fermeture X par une action principale (par exemple, « Enregistrer »). Affiche également automatiquement un bouton « Annuler » à gauche et ajoute .--has-primary-action à l’en-tête.
:belowHeader Entre l’en-tête et le corps Contenu de sous-en-tête persistant (par exemple, recherche) qui se trouve en dehors du corps défilant, pour un affichage fixe.
:aboveFooter Entre le corps et le pied de page Supprimé lorsque @hideFooter est défini. À utiliser pour le contenu lié au pied de page mais en dehors de celui-ci. Également rare.
:footer Barre d’action en bas Boutons principaux et secondaires. Le premier .btn-primary ici est celui que la touche Entrée déclenche.
:belowFooter Après le pied de page Rarement nécessaire ; ignore @hideFooter. Utile pour le texte de statut en dehors de la zone bordée du pied de page.

Sources : le guide de style interactif pour les arguments, et l’implémentation du modèle d-modal pour les blocs nommés.

CSS

Utilisez les classes .d-modal comme ancre pour remplacer le noyau, et évitez le sélecteur hérité .modal.

4 modificateurs disponibles :

  • .--large définit la largeur maximale à 800px (uniquement sur bureau)
  • .--max définit la largeur maximale à 90vw (uniquement sur bureau)
  • .has-search définit la hauteur fixe (80vh) : destiné aux modales avec un système de recherche/filtre pour éviter un changement de hauteur basé sur la longueur des résultats (uniquement sur bureau)
  • .--stacked définit les boutons du pied de page en empilement (uniquement sur mobile)

Ce document est versionné — proposez des modifications sur GitHub.

17 « J'aime »

Une publication a été divisée en un nouveau sujet : Puis-je afficher une modale depuis head_tag