DModal-API zum Rendern von Modalen (auch Popups/Dialoge genannt) in Discourse

Discourse 3.1.0.beta6 wird mit einer brandneuen, komponentenbasierten <DModal>-API ausgeliefert. DModal ist Teil des UI-Kit und wird aus discourse/ui-kit/d-modal importiert.

:information_source: Dies ersetzt die alte, controllerbasierte API, die nun veraltet ist. Wenn du bestehende Modals mit den alten APIs verwendest, findest du den Migrationsleitfaden hier.

Ein Modal rendern

Modals werden gerendert, indem die <DModal>-Komponente in eine Handlebars-Vorlage eingebunden wird. Falls du noch keine geeignete Vorlage hast, schau dir Using Plugin Outlet Connectors from a Theme or Plugin an.

Ein einfaches Modal könnte so aussehen:

<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: Der mut-Helper wird hier als hbs-spezifische Methode verwendet, um einen Wert zu setzen. Du könntest modalIsVisible auch mit jeder anderen Standard-Ember-Methode setzen.

Dieses Beispiel erstellt ein einfaches Modal wie dieses:

In einer Komponente kapseln

Bevor weitere Komplexität eingeführt wird, ist es in der Regel am besten, das neue Modal in seiner eigenen Komponenten-Definition zu kapseln. Verschieben wir also das <DModal>-Gerüst in eine neue <MyModal />-Komponente.

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

Das Aufrüsten dieser .gjs-Datei zu einer klassenbasierten Komponente ermöglicht es dir, komplexere Logik und Zustände einzuführen.

Um die neue Komponente zu nutzen, aktualisiere die Aufrufstelle, um sie zu referenzieren, und achte darauf, ein @closeModal-Argument zu übergeben.

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

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

Ein Footer hinzufügen

Viele Modals haben eine Art Call-to-Action. In Discourse befinden sich diese tendenziell am unteren Rand des Modals. Um dies zu ermöglichen, verfügt DModal über eine Reihe von ‘benannten Blöcken’ (named blocks), in die Inhalte gerendert werden können. Hier ist das Beispiel aktualisiert, um zwei Buttons im Footer zu enthalten, wobei einer unser Standard-DModalCancel-Button ist.

<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>

Ein Modal aus einem Nicht-hbs-Kontext rendern

Idealerweise sollten <DModal>-Instanzen innerhalb einer Ember-Vorlage mit der oben demonstrierten deklarativen Technik gerendert werden. Falls dies für deinen Anwendungsfall nicht machbar ist, kann dies durch das Einspritzen des modal-Services und den Aufruf von modal.show() erledigt werden.

Stelle sicher, dass du dein Modal wie oben beschrieben in seiner eigenen Komponente gekapselt hast. Dann löst du das Modal aus, indem du eine Referenz auf deine Komponentenklasse an showModal übergibst:

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

// (den modal-Service an der entsprechenden Stelle injizieren)

// Füge diesen Aufruf hinzu, wann immer du das Modal öffnen möchtest.
// Ein `@closeModal`-Argument wird deiner Komponente automatisch übergeben.
this.modal.show(MyModal);

// Optional: Übergib einen '`model`'-Parameter. Wird als `@model` an deine Komponente übergeben.
// Dies kann Daten sowie Aktionen/Callbacks enthalten, die dein Modal verwenden soll.
this.modal.show(MyModal, {
  model: { topic: this.topic, someAction: this.someAction },
});

// `modal.show()` gibt ein Promise zurück, sodass du darauf warten kannst, dass es geschlossen wird.
// Es wird mit den Daten aufgelöst, die an die `@closeModal`-Aktion übergeben wurden.
const result = await this.modal.show(MyModal);

Mehr Anpassungsmöglichkeiten!

<DModal> verfügt über eine Reihe von benannten Blöcken und Argumenten.

Argumente

Arg Zweck
@closeModal Erforderlich, damit überhaupt eine UI zum Schließen angezeigt wird.
@title Rendert <h1 id="discourse-modal-title">; verdrahtet aria-labelledby.
@subtitle Kleiner Text unter dem Titel.
@flash / @flashType Inline-Warnung oben im Modal (DFlashMessage).
@hideHeader, @hideFooter Versteckt ganze Bereiche.
@headerClass, @bodyClass Zusätzliche Klasse auf den Header/Body-Wrapper.
@dismissable Standardmäßig true, wenn @closeModal gesetzt ist. Deaktiviert Esc / Klick auf Hintergrund / X.
@autofocus Standardmäßig true. Fokussiert automatisch das erste fokussierbare Element über dTrapTab.
@submitOnEnter Standardmäßig true. Enter klickt .d-modal__footer .btn-primary, es sei denn, der Fokus liegt in einem Formular / Textarea / Select-Kit.
@beforeClose async ({ initiatedBy }) => boolean. Gib false zurück, um das Schließen abzubrechen (z. B. Bestätigung bei ungespeicherten Änderungen).
@hidden Pausiert die Tastaturverarbeitung; wird verwendet, wenn ein verschachteltes Modal darüber liegt.
@tagName "div" (Standard) oder "form". Verwende "form" für Formulare, damit die native Submit-Funktion funktioniert.

Blöcke

Block Position Wann verwenden
default / :body Hauptinhaltsbereich Standardbereich
:aboveHeader Ganz oben, vor dem Header Selten benötigt; für Inhalte, die über der Titelleiste sitzen müssen (z. B. ein Banner).
:headerAboveTitle Im Header, vor dem Titel Vorhanden, aber ungenutzt. Selten benötigt.
:belowModalTitle In .d-modal__title, nach dem <h1> Hervorragende Position für ergänzende Metainformationen.
:headerBelowTitle Im Header, nach dem Titelblock Tabs, Sub-Navigation oder Suchfeld, die Teil des Headers sind.
:headerPrimaryAction Rechte Seite des Headers nur auf Mobilgeräten Ersetzt den X-Schließen-Button durch eine primäre Aktion (z. B. “Speichern”). Rendert auch automatisch einen “Abbrechen”-Button links und fügt .--has-primary-action zum Header hinzu.
:belowHeader Zwischen Header und Body Persistenter Sub-Header-Inhalt (z. B. Suche), der außerhalb des scrollbaren Body liegt, für eine Sticky-Anzeige.
:aboveFooter Zwischen Body und Footer Unterdrückt, wenn @hideFooter gesetzt ist. Für Inhalte verwenden, die mit dem Footer zusammenhängen, aber außerhalb liegen. Ebenfalls selten.
:footer Untere Aktionsleiste Primäre + sekundäre Buttons. Der erste .btn-primary hier ist der, den Enter auslöst.
:belowFooter Nach dem Footer Selten benötigt; ignoriert @hideFooter. Nützlich für Status-Text außerhalb des gerahmten Footer-Bereichs.

Quellen: der interaktive Styleguide für Argumente und die d-modal-Template-Implementierung für benannte Blöcke.

CSS

Verwende die .d-modal-Klassen als Anker, um Core zu überschreiben, und vermeide den Legacy-.modal-Selektor.

4 Modifikatoren verfügbar:

  • .--large setzt die maximale Breite auf 800px (nur Desktop)
  • .--max setzt die maximale Breite auf 90vw (nur Desktop)
  • .has-search setzt eine feste Höhe (80vh): für Modals mit Such-/Filtersystem gedacht, um Höhenänderungen basierend auf der Ergebnislänge zu vermeiden (nur Desktop)
  • .--stacked setzt die Footer-Buttons auf gestapelte Ansicht (nur Mobilgeräte)

Dieses Dokument wird versioniert verwaltet - Vorschläge für Änderungen auf GitHub.

17 „Gefällt mir“

Ein Beitrag wurde in ein neues Thema aufgeteilt: Kann ich ein Modal aus head_tag anzeigen