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

Discourse 3.1.0.beta6 è dotato di una nuova API basata su componenti <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 disponi già di un template adatto, consulta Using Plugin Outlet Connectors from a Theme or Plugin.

Un modale semplice potrebbe essere simile a questo:

<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: L’helper mut viene utilizzato qui come metodo solo hbs per impostare un valore. È possibile impostare modalIsVisible anche utilizzando qualsiasi altro metodo standard di Ember.

Questo esempio creerà un modale semplice come questo:

Incapsulamento in un componente

Prima di introdurre ulteriore complessità, è generalmente meglio incapsulare il nuovo Modale nella 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 classi 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 invito all’azione (call-to-action). In Discourse, questi tendono a essere posizionati 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 all’interno di un template Ember utilizzando la tecnica dichiarativa dimostrata sopra. Se ciò non è fattibile per il tuo caso d’uso, è possibile farlo 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 di componente a showModal:

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

// (inietta il servizio modal nel punto pertinente)

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

// Opzionalmente, 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);

Maggiore personalizzazione!

<DModal> ha diversi blocchi nominati e argomenti.

Argomenti

Arg Scopo
@closeModal Obbligatorio affinché la UI di chiusura venga visualizzata.
@title Renderizza <h1 id="discourse-modal-title">; collega aria-labelledby.
@subtitle Testo piccolo sotto il titolo.
@flash / @flashType Avviso inline nella parte superiore del modale (DFlashMessage).
@hideHeader, @hideFooter Nasconde intere regioni.
@headerClass, @bodyClass Classe aggiuntiva su header/body wrapper.
@dismissable Default true quando @closeModal è impostato. Disabilita Esc / click sul backdrop / X.
@autofocus Default true. Mette a fuoco automaticamente il primo elemento focalizzabile tramite dTrapTab.
@submitOnEnter Default 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. Restituisci false per annullare la chiusura (es. conferma form sporco).
@hidden Mette in pausa la gestione della tastiera; usato quando un modale annidato è in cima.
@tagName "div" (default) 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 <h1> Posizione eccellente per informazioni meta supplementari.
:headerBelowTitle All’interno dell’header, dopo il blocco del titolo Schede, sub-nav o input di ricerca che fanno 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 è fuori dal corpo scorrevole, quindi display sticky.
:aboveFooter Tra body e footer Soppresso quando @hideFooter è impostato. Usato per contenuto legato al footer ma esterno ad esso. Anche raro.
:footer Barra di azione inferiore Pulsanti primari e 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 fuori dall’area del footer con bordo.

Fonti: lo styleguide interattivo per gli argomenti e l’implementazione del template d-modal per i blocchi nominati.

CSS

Usa le classi .d-modal come ancoraggio per sovrascrivere il core e evita il selettore legacy .modal.

Sono disponibili 4 modificatori:

  • .--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/filtro per evitare variazioni di altezza basate sulla lunghezza dei risultati (solo desktop)
  • .--stacked imposta i pulsanti del footer in impilamento (solo mobile)

Questo documento è sotto controllo di versione - suggerisci modifiche su github.

17 Mi Piace

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