Uso dell'API DModal per visualizzare finestre modali (alias popup/dialoghi) in Discourse

Discourse 3.1.0.beta6 introduce una nuova API basata su componenti per <DModal>. DModal fa parte del UI kit e viene importato da discourse/ui-kit/d-modal.

:information_source: Questa API sostituisce la vecchia API basata su controller, che è ora deprecata. Se hai modali esistenti che utilizzano le vecchie API, consulta la guida alla migrazione qui.

Rendering di un Modale

I modali vengono renderizzati includendo il componente <DModal> in un template handlebars. Se non hai già un template adatto, consulta Using Plugin Outlet Connectors from a Theme or Plugin.

Un semplice modale apparirebbe così:

<DButton
  @translatedLabel="Show Modal"
  @action={{fn (mut this.modalIsVisible) true}}
/>

{{#if this.modalIsVisible}}
  <DModal @title="My Modal" @closeModal={{fn (mut this.modalIsVisible) false}}>
    Hello world, this is some content in a modal
  </DModal>
{{/if}}

:information_source: Qui viene utilizzato l’helper mut come metodo esclusivo per hbs per impostare un valore. Potresti anche impostare modalIsVisible utilizzando qualsiasi altro metodo standard di Ember.

Questo esempio creerà un semplice Modale simile a questo:

Incapsulamento in un componente

Prima di introdurre ulteriore complessità, è generalmente meglio incapsulare il nuovo Modale in una propria definizione di Componente. Spostiamo la parte <DModal> all’interno di un nuovo componente <MyModal />

// components/my-modal.gjs
<template>
  <DModal @title="My Modal" @closeModal={{@closeModal}}>
    Hello world, this is some content in a modal
  </DModal>
</template>

L’aggiornamento di questo file .gjs a un componente basato su classe ti consentirà di introdurre logiche e stati più complessi.

Per utilizzare il nuovo componente, aggiorna il punto di chiamata per fare riferimento ad esso, assicurandoti di passare un argomento @closeModal.

<DButton
  @translatedLabel="Show Modal"
  @action={{fn (mut this.modalIsVisible) true}}
/>

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

Aggiunta di un footer

Molti modali hanno una sorta di call-to-action. In Discourse, queste tendono a trovarsi nella parte inferiore del modale. Per rendere possibile ciò, DModal dispone di diversi ‘blocchi nominati’ in cui è possibile renderizzare contenuto. Ecco l’esempio aggiornato per includere due pulsanti nel footer, uno dei quali è il nostro standard pulsante DModalCancel

<DModal @title="My Modal" @closeModal={{@closeModal}}>
  <:body>
    Hello world, this is some content in a modal
  </:body>
  <:footer>
    <DButton class="btn-primary" @translatedLabel="Submit" />
    <DModalCancel @close={{@closeModal}} />
  </:footer>
</DModal>

Rendering di un modale da un contesto non-hbs

Idealmente, le istanze di <DModal> dovrebbero essere renderizzate da un template Ember utilizzando la tecnica dichiarativa dimostrata sopra. Se ciò non è fattibile per il tuo caso d’uso, può essere fatto iniettando il servizio modal e chiamando modal.show().

Assicurati di aver incapsulato il tuo modale in un proprio componente come descritto sopra. Quindi, attiva il modale passando un riferimento della tua classe componente a showModal:

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

// (inietta il servizio modal nel punto rilevante)

// Aggiungi questa chiamata ogni volta che vuoi aprire il modale.
// Un argomento `@closeModal` verrà passato automaticamente al tuo componente.
this.modal.show(MyModal);

// Facoltativamente, passa un parametro '`model`'. Viene passato come `@model` al tuo componente.
// Questo può includere dati e anche azioni/callback per il tuo Modale da utilizzare.
this.modal.show(MyModal, {
  model: { topic: this.topic, someAction: this.someAction },
});

// `modal.show()` restituisce una promise, quindi puoi aspettare che venga chiuso
// Si risolverà con i dati passati all'azione `@closeModal`
const result = await this.modal.show(MyModal);

Più personalizzabilità!

<DModal> ha una serie di blocchi nominati e argomenti.

Argomenti

Arg Scopo
@closeModal Obbligatorio affinché l’UI di chiusura venga visualizzata.
@title Renderizza <h1 id="discourse-modal-title">; collega aria-labelledby.
@subtitle Testo piccolo sotto il titolo.
@flash / @flashType Alert inline in alto nel modale (DFlashMessage).
@hideHeader, @hideFooter Nasconde le intere regioni.
@headerClass, @bodyClass Classe aggiuntiva sui wrapper di header/body.
@dismissable Predefinito true quando @closeModal è impostato. Disabilita Esc / clic sullo sfondo / X.
@autofocus Predefinito true. Mette a fuoco automaticamente il primo elemento focalizzabile tramite dTrapTab.
@submitOnEnter Predefinito true. Enter fa clic su .d-modal__footer .btn-primary a meno che il focus non sia in un form / textarea / select-kit.
@beforeClose async ({ initiatedBy }) => boolean. Restituisce false per annullare la chiusura (es. conferma form sporco).
@hidden Sospende la gestione della tastiera; usato quando un modale annidato è in cima.
@tagName "div" (predefinito) o "form". Usa "form" per i form in modo che il submit nativo funzioni.

Blocchi

Block Posizione Quando usarlo
default / :body Area di contenuto principale Area predefinita
:aboveHeader Molto in alto, prima dell’header Raramente necessario; per contenuto che deve trovarsi sopra la barra del titolo (es. un banner).
:headerAboveTitle All’interno dell’header, prima del titolo Presente ma non utilizzato. Raramente necessario.
:belowModalTitle All’interno di .d-modal__title, dopo l’<h1> Posizione eccellente per informazioni meta supplementari.
:headerBelowTitle All’interno dell’header, dopo il blocco titolo Tab, sub-nav o campo di ricerca che fa parte dell’header.
:headerPrimaryAction Lato destro dell’header solo su mobile Sostituisce il pulsante di chiusura X con un’azione primaria (es. “Salva”). Renderizza anche automaticamente un pulsante “Annulla” a sinistra e aggiunge .--has-primary-action all’header.
:belowHeader Tra header e body Contenuto di sub-header persistente (es. ricerca) che è esterno al body scorrevole, per un display sticky.
:aboveFooter Tra body e footer Soppresso quando @hideFooter è impostato. Usa per contenuto legato al footer ma esterno ad esso. Anche raro.
:footer Barra di azione inferiore Pulsanti primari + secondari. Il primo .btn-primary qui è ciò che viene attivato da Enter.
:belowFooter Dopo il footer Raramente necessario; ignora @hideFooter. Utile per testo di stato esterno all’area del footer con bordo.

Fonti: la styleguide interattiva per gli argomenti, e l’implementazione del template d-modal per i blocchi nominati.

CSS

Usa le classi .d-modal come punto di riferimento per sovrascrivere il core ed evita il selettore legacy .modal.

4 modificatori disponibili:

  • .--large imposta la larghezza massima a 800px (solo desktop)
  • .--max imposta la larghezza massima a 90vw (solo desktop)
  • .has-search imposta l’altezza fissa (80vh): destinato a modali con sistema di ricerca/filtri per evitare variazioni di altezza basate sulla lunghezza dei risultati (solo desktop)
  • .--stacked imposta i pulsanti del footer in impilamento (solo mobile)

Questo documento è versionato - suggerisci modifiche su github.

17 Mi Piace

Un post è stato diviso in un nuovo argomento: Posso mostrare una modale da head_tag