DModal APIを使用してDiscourseでモーダルウィンドウ(ポップアップ/ダイアログ)を表示する

Discourse 3.1.0.beta6 には、まったく新しい <DModal> コンポーネントベースの API が同梱されています。DModalUI キット の一部であり、discourse/ui-kit/d-modal からインポートされます。

:information_source: これは従来のコントローラーベースの API を置き換えます。従来の API は現在非推奨です。旧 API を使用して既存のモーダルがある場合は、こちらのマイグレーションガイドをご覧ください。

モーダルのレンダリング

モーダルは、handlebars テンプレートに <DModal> コンポーネントを含めることでレンダリングされます。適切なテンプレートを持っていない場合は、Using Plugin Outlet Connectors from a Theme or Plugin を確認してください。

シンプルなモーダルは次のようになります:

<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: ここでは、値を設定するための hbs 専用の方法として mut ヘルパー が使用されています。modalIsVisible は、他の標準的な Ember メソッドを使用して設定することもできます。

この例は、次のようなシンプルなモーダルを作成します:

コンポーネントでのラップ

より複雑な要素を導入する前に、新しいモーダルを独自のコンポーネント定義にラップするのが通常は最善です。<DModal> の部分を新しい <MyModal /> コンポーネントの中に移動してみましょう。

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

この .gjs ファイルをクラスベースのコンポーネントにアップグレードすることで、より複雑なロジックや状態を導入できるようになります。

新しいコンポーネントを使用するには、呼び出し元を参照するように更新し、@closeModal 引数を渡すことを確認してください。

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

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

フッターの追加

多くのモーダルには何らかのコールトゥアクションがあります。Discourse では、これらは通常モーダルの下部に配置されます。これを可能にするために、DModal には内部にコンテンツをレンダリングできる複数の「名前付きブロック」があります。ここでは、フッターに2つのボタン(そのうち1つは標準の 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>

hbs 以外のコンテキストからモーダルをレンダリングする

理想的には、<DModal> インスタンスは上記で示した宣言的なテクニックを使用して、Ember テンプレート内からレンダリングされるべきです。それがあなたのユースケースで実行不可能な場合、modal サービスをインジェクションし、modal.show() を呼び出すことで実行できます。

上記の説明に従って、モーダルを独自のコンポーネントにラップしていることを確認してください。次に、コンポーネントクラスの参照を showModal に渡すことでモーダルをトリガーします:

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

// (関連する場所に modal サービスをインジェクションする)

// モーダルを開きたいときにこの呼び出しを追加します。
// `@closeModal` 引数は自動的にコンポーネントに渡されます。
this.modal.show(MyModal);

// 任意で、'`model`' パラメータを渡します。コンポーネントに `@model` として渡されます。
// これはデータや、モーダルが使用するアクション/コールバックを含めることができます。
this.modal.show(MyModal, {
  model: { topic: this.topic, someAction: this.someAction },
});

// `modal.show()` は Promise を返すため、クローズされるのを待つことができます。
// `@closeModal` アクションに渡されたデータで解決されます。
const result = await this.modal.show(MyModal);

より多くのカスタマイズ性!

<DModal> には、名前付きブロックと引数が多数あります。

引数

引数 目的
@closeModal ディスミスの UI が表示されるために必須です。
@title <h1 id="discourse-modal-title"> をレンダリングし、aria-labelledby を配線します。
@subtitle タイトルの下の小さなテキスト。
@flash / @flashType モーダルの上部のインラインアラート (DFlashMessage)。
@hideHeader, @hideFooter 領域全体を非表示にします。
@headerClass, @bodyClass ヘッダー/ボディのラッパーに追加されるクラス。
@dismissable @closeModal が設定されている場合、デフォルトで true です。Esc / バックドロップ クリック / X を無効にします。
@autofocus デフォルトで true です。dTrapTab を通じて最初のフォーカス可能な要素に自動フォーカスします。
@submitOnEnter デフォルトで true です。フォーカスがフォーム / テキストエリア / select-kit にない限り、Enter は .d-modal__footer .btn-primary をクリックします。
@beforeClose async ({ initiatedBy }) => boolean。クローズをキャンセルするには false を返します(例:未保存フォームの確認)。
@hidden キーボード処理を一時停止します。ネストされたモーダルが上にある場合に使用されます。
@tagName "div"(デフォルト)または "form"。ネイティブの submit が機能するようにフォームには "form" を使用します。

ブロック

ブロック 位置 使用タイミング
default / :body メインコンテンツエリア デフォルトのエリア
:aboveHeader ヘッダーの前、最上部 ほとんど必要ありません。タイトルバーの上に配置しなければならないコンテンツ(例:バナー)に使用。
:headerAboveTitle ヘッダー内、タイトル前 存在しますが未使用。ほとんど必要ありません。
:belowModalTitle .d-modal__title 内、<h1> の後 補足的なメタ情報には最適な位置。
:headerBelowTitle ヘッダー内、タイトルブロック後 ヘッダーの一部であるタブ、サブナビ、または検索入力。
:headerPrimaryAction モバイルのみでヘッダーの右側 X クローズボタンをプライマリアクション(例:“保存”)に置き換えます。また、左側に “キャンセル” ボタンを自動レンダリングし、ヘッダーに .--has-primary-action を追加します。
:belowHeader ヘッダーとボディの間 スクロール可能なボディの外にある永続的なサブヘッダーコンテンツ(例:検索)で、スティッキー表示が可能。
:aboveFooter ボディとフッターの間 @hideFooter が設定されている場合は抑制されます。フッターに関連するが外にあるコンテンツに使用。また稀です。
:footer 下部アクションバー プライマリ + セカンダリボタン。ここにある最初の .btn-primary が Enter でトリガーされます。
:belowFooter フッターの後 ほとんど必要ありません。@hideFooter を無視します。ボーダー付きフッターエリアの外にあるステータステキストに有用。

ソース:引数については インタラクティブスタイルガイド、名前付きブロックについては d-modal テンプレート実装 を参照してください。

CSS

.d-modal クラスをアンカーとして使用してコアをオーバーライドし、レガシーの .modal セレクタを避けてください。

利用可能な 4 つの修飾子:

  • .--large最大 を 800px に設定します(デスクトップのみ)
  • .--max最大 を 90vw に設定します(デスクトップのみ)
  • .has-search固定 高さ(80vh)を設定します:結果の長さに基づいて高さが変化することを避けるため、検索/フィルタリングシステムを持つモーダルに意図されています(デスクトップのみ)
  • .--stacked はフッターボタンをスタッキングに設定します(モバイルのみ)

このドキュメントはバージョン管理されています - 変更提案は GitHub でどうぞ。

「いいね!」 17

投稿が新しいトピックに分割されました: head_tagからモーダルを表示できますか