React Native、Expo、Web で待機できるモーダル
どこからでも命令的に呼び出すことができるモーダル ライブラリ。モーダルを簡単に制御し、複雑なフローを合理化し、信頼性の高いユーザー エクスペリエンスを作成します。
ひと目でわかる
- これは何?
- ポータルを1つマウントし、magicModal.show() を呼び出すと、Expo、React Native、Web で型付きのクローズ結果を待機できます。
- 誰に向いている?
- Magic Modal は、React Native、Expo、Web 向けに Promise ベースのモーダル API を提供します。README には、ポータル、型付きクローズ結果、プラットフォーム別のインストール手順が記載されています。
- 商用利用できる?
- できます。MIT は寛容なライセンスで、著作権表示とライセンス表示を残せば、使用・改変・販売が可能です。
- 今もメンテナンスされている?
- されています。最後のコミットは 1 日前です。
- 何の言語で書かれている?
- 主に TypeScript です(GitHub の言語統計による)。
回答はプロジェクトの GitHub データ(最終同期:2026年9月14日)と当サイトの分析に基づくもので、法的助言ではありません。
オープンソース詳細解説
任意の非同期フローからモーダルを待機する
Magic Modal は、モーダルダイアログを待機可能な Promise のように振る舞わせる TypeScript ライブラリです。ポータルを1つマウントし、magicModal.show() にコンポーネントと設定を渡して呼び出すと、モーダルが閉じたときに返されたハンドルが解決します。解決結果には、モーダルが送信したデータまたは閉じられた理由が含まれます。README は、これを Expo、React Native、Web の任意の非同期フローからモーダルを開く方法として説明しており、3つすべてで同じ型付き結果契約を使用します。
ポータルがモーダルスタックを所有する
ライブラリのアーキテクチャは MagicModalPortal を中心としており、これがモーダルスタックを所有します。magicModal.show() を呼び出すたびに、そのスタックに新しいエントリがプッシュされ、待機可能なハンドルが返されます。ハンドルはそれ自体が Promise であり、そのエントリの modalID、update 関数、hide 関数も保持します。README は、ハンドル上の promise エイリアスが非推奨であると述べており、const { promise } = magicModal.show(...) と書くこともできますが、ハンドル自体が Promise です。各スタックエントリは独自のコンポーネント、設定、ID、Promise を保持するため、2回目の show() 呼び出しは現在のモーダルの上に開くことができ、結果が混ざることはありません。
インストールはプラットフォームによって異なる
パッケージはネイティブとブラウザのランタイムに別々のエントリを提供するため、インストールコマンドは異なります。Expo Web の場合、README には pnpm add magic-modal に続けて npx expo install react-native-gesture-handler react-native-reanimated react-native-worklets react-dom react-native-web @expo/metro-runtime とあります。Expo iOS と Android は同じ最初のコマンドを使用しますが、Web 依存関係を react-native-screens に置き換えます。Next.js のようなブラウザのみの React アプリでは、インストールは pnpm add magic-modal だけで完了します。Web エントリには React Native 依存関係がゼロであるため、バンドラーエイリアスやジェスチャー・アニメーションのピアは不要です。README はまた、素の React Native ユーザーに別のインストールガイドを案内しています。
環境ごとのポータルのマウント
Expo とネイティブ React Native では、README の例のように GestureHandlerRootView の内側に MagicModalPortal をマウントします。ポータルはアプリコンテンツの横に配置されます。Expo Router の場合、同じ構造をルートの app/_layout.tsx に置きます。ブラウザアプリケーションでは、Client Component 内にポータルをマウントするだけで、他には何も必要ありません。ブラウザバンドルには Gesture Handler が含まれないため、GestureHandlerRootView はありません。README は、正確なシェルについては Next.js ガイドを、実行可能な App Router コンシューマーの例については examples/next-web を参照しています。
型付き結果とクローズ理由
API は、期待するデータに対してジェネリックです。show<T>() でモーダルを開き、モーダルコンテンツ内で useMagicModal<T>() を使って hide(data) を呼び出します。Promise は HideReturn<T> に解決され、理由と、理由が MagicModalHideReason.INTENTIONAL_HIDE の場合にはデータが含まれます。その他の理由には、背景の押下、完了したスワイプ、Android の戻るや Web の Escape などのシステムによる破棄、hideAll() が含まれます。TypeScript は結果を絞り込むため、理由を確認した後にのみ data にアクセスできます。README には、呼び出し側がブール値のような結果を待って処理する確認モーダルの例があり、ブラウザエントリは React Native コンポーネントではなく DOM 要素をレンダリングしますが、同じ結果契約を使用すると述べています。
FAQ が明確にすること
FAQ はいくつかの一般的な質問に答えています。複数のモーダルを開くことができます。各 show() が独立したエントリを作成するためです。モーダルに ScrollView を含めることはできますが、swipeDirection: undefined を渡してスワイプによる破棄を無効にする必要があります。ライブラリはスナップポイントやネストされたスクロールを実装していません。コンポーネントの外部からモーダルを閉じるには、show() が返す modalID を保持し、magicModal.hide(undefined, { modalID }) を呼び出します。iOS でネイティブピッカーの下にレンダリングするには、一時的に magicModal.disableFullWindowOverlay() を呼び出し、finally ブロックで復元します。README はまた、貢献者リストと貢献ガイドへのリンクも提供しています。
ライセンスと貢献
Magic Modal は MIT ライセンスでリリースされており、著作権は Gabriel Taveira(2023)に帰属します。ライセンスは、著作権表示を含めることを条件に、コピーの使用、コピー、変更、結合、公開、配布、サブライセンス、販売を許可します。ソフトウェアは「現状のまま」提供され、いかなる種類の保証もなく、ライセンスはサポート、セキュリティ保証、または本番稼働への適合性については言及していません。README は貢献者リストと貢献ガイドへのリンクを提供しており、リポジトリメタデータには未解決の問題数が表示されていますが、README はリリース頻度やメンテナンスポリシーを指定していません。
編集部の結論
Magic Modal は、React Native、Expo、Web 向けに Promise ベースのモーダル API を提供します。README には、ポータル、型付きクローズ結果、プラットフォーム別のインストール手順が記載されています。プロジェクトは MIT ライセンスで、ドキュメント、例、貢献ガイドへのリンクが含まれています。
コミュニティノート