### Start Example App Packager Source: https://github.com/gstj/react-native-magic-modal/blob/main/CONTRIBUTING.md Starts the Metro server for the example application. Changes in library code are reflected without a rebuild. ```sh pnpm run example start ``` -------------------------------- ### Setup Project Dependencies Source: https://github.com/gstj/react-native-magic-modal/blob/main/CONTRIBUTING.md Installs all project dependencies and pods, setting up the development environment. ```sh pnpm run bootstrap ``` -------------------------------- ### Run Example App on Web Source: https://github.com/gstj/react-native-magic-modal/blob/main/CONTRIBUTING.md Builds and runs the example application on a web browser. ```sh pnpm run example web ``` -------------------------------- ### Run Example App on iOS Source: https://github.com/gstj/react-native-magic-modal/blob/main/CONTRIBUTING.md Builds and runs the example application on an iOS simulator or device. ```sh pnpm run example ios ``` -------------------------------- ### Install Project Dependencies Source: https://github.com/gstj/react-native-magic-modal/blob/main/CONTRIBUTING.md Run this command in the root directory to install all required dependencies for each package. ```sh pnpm run ``` -------------------------------- ### Install React Native Magic Modal Source: https://github.com/gstj/react-native-magic-modal/blob/main/README.md Install the react-native-magic-modal package using yarn. ```bash yarn add react-native-magic-modal ``` -------------------------------- ### Run Example App on Android Source: https://github.com/gstj/react-native-magic-modal/blob/main/CONTRIBUTING.md Builds and runs the example application on an Android device or emulator. ```sh pnpm run example android ``` -------------------------------- ### Basic Setup for React Native Magic Modal Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/quick-reference.md Integrate MagicModalPortal and GestureHandlerRootView into your application's root component for basic setup. ```typescript import { MagicModalPortal } from "react-native-magic-modal"; import { GestureHandlerRootView } from "react-native-gesture-handler"; export default function App() { return ( ); } ``` -------------------------------- ### Install Peer Dependencies Source: https://github.com/gstj/react-native-magic-modal/blob/main/README.md Install react-native-reanimated and react-native-gesture-handler as peer dependencies. These are required for the library to function correctly. ```bash yarn add react-native-reanimated yarn add react-native-gesture-handler ``` -------------------------------- ### Example Modal Stack Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/Hiding-Modals.md Demonstrates how multiple modals are stacked, with only the topmost modal being interactive. This illustrates the order in which modals are displayed. ```typescript const modal1 = magicModal.show(() => ); // Shown const modal2 = magicModal.show(() => ); // On top of Modal1 const modal3 = magicModal.show(() => ); // On top of Modal2 // Stack (bottom to top): Modal1 -> Modal2 -> Modal3 // Only Modal3 responds to gestures ``` -------------------------------- ### Install magic-eslint-config Source: https://github.com/gstj/react-native-magic-modal/blob/main/packages/eslint-config/README.md Add the magic-eslint-config package as a development dependency to your project using your preferred package manager. ```bash pnpm add -D @magic/eslint-config ``` ```bash yarn add -D @magic/eslint-config ``` ```bash npm install --save-dev @magic/eslint-config ``` -------------------------------- ### Example: Hiding Modal from Outside with Timeout Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/Hiding-Modals.md This example demonstrates hiding a modal after a delay using its `modalID`. Ensure you capture the `modalID` when initially displaying the modal. ```typescript // Show modal and get ID const { modalID } = magicModal.show(() => ); // Later, from a different component setTimeout(() => { magicModal.hide({ closed: "by timeout" }, { modalID }); }, 5000); ``` -------------------------------- ### Conceptual Usage Example Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/MagicModalProvider.md Illustrates the internal pattern of MagicModalProvider, how a hide function is created, and how it's used with a modal component via the useMagicModal hook. ```typescript // This is what happens internally: // 1. MagicModalPortal stores a hideCallback let hideCallback: (value: unknown) => void = () => {}; const promise = new Promise((resolve) => { hideCallback = resolve; }); // 2. Create the hideFunction for this modal const hideFunction = (props) => { hideCallback({ reason: MagicModalHideReason.INTENTIONAL_HIDE, data: props }); }; // 3. Wrap modal with MagicModalProvider // 4. Inside YourModalComponent, use the hook const { hide } = useMagicModal(); // 5. Call hide to close and return data hide({ /* data */ }); ``` -------------------------------- ### Type-Safe Modal Return Example Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/overview.md Demonstrates how to use TypeScript generics for type-safe retrieval of modal return data. The promise returned by `magicModal.show` resolves with a reason and data, which are type-checked against the provided generic type. ```typescript interface ModalReturnType { success: boolean; message: string; } const result = await magicModal .show(() => ) .promise; if (result.reason === "INTENTIONAL_HIDE") { console.log(result.data.success); // ✓ Type-safe console.log(result.data.message); // ✓ Type-safe } ``` -------------------------------- ### Complex Modal Flow Example Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/magicModal.md Demonstrates a multi-step modal flow where one modal's result determines the next modal shown. Use this for sequential user input or confirmation processes. Ensure `GestureHandlerRootView` is used at the root of your app for gesture handling. ```typescript import React from "react"; import { View, Text, Pressable, GestureHandlerRootView } from "react-native"; import { magicModal, MagicModalPortal, useMagicModal, MagicModalHideReason, } from "react-native-magic-modal"; interface ConfirmReturn { confirmed: boolean; } const ConfirmModal = () => { const { hide } = useMagicModal(); return ( Proceed? hide({ confirmed: true })}> Yes hide({ confirmed: false })}> No ); }; const ResultModal = ({ message }: { message: string }) => { const { hide } = useMagicModal(); return ( {message} hide(undefined)}> Close ); }; const MainScreen = () => { const handleFlow = async () => { const confirmResult = await magicModal .show(() => ) .promise; if (confirmResult.reason !== MagicModalHideReason.INTENTIONAL_HIDE) { return; // User didn't press a button } if (confirmResult.data.confirmed) { await magicModal .show(() => ) .promise; } else { await magicModal .show(() => ) .promise; } }; return ( Start Flow ); }; export default MainScreen; ``` -------------------------------- ### Basic Modal with Return Type Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/useMagicModal.md Example of a modal component that uses useMagicModal to return data upon closing. The caller can then access this data. ```typescript import React from "react"; import { View, Text, Pressable } from "react-native"; import { useMagicModal } from "react-native-magic-modal"; type ConfirmModalReturn = { confirmed: boolean; }; const ConfirmModal = () => { const { hide } = useMagicModal(); return ( Are you sure? hide({ confirmed: true })}> Yes hide({ confirmed: false })}> No ); }; // Usage import { magicModal } from "react-native-magic-modal"; const handleConfirm = async () => { const result = await magicModal.show(() => ).promise; if (result.reason === "INTENTIONAL_HIDE" && result.data.confirmed) { console.log("User confirmed"); } }; ``` -------------------------------- ### Simple Modal Close Action Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/README.md Provides a basic example of how to close a modal using the `hide` function from the `useMagicModal` hook. This is useful for simple dismiss actions. ```typescript const { hide } = useMagicModal(); return hide(undefined)}>Close; ``` -------------------------------- ### Basic Modal with Return Type Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/useMagicModal.md Example of using the useMagicModal hook in a modal component to return a boolean confirmation value. ```typescript import React from "react"; import { View, Text, Pressable } from "react-native"; import { useMagicModal } from "react-native-magic-modal"; type ConfirmModalReturn = { confirmed: boolean; }; const ConfirmModal = () => { const { hide } = useMagicModal(); return ( Are you sure? hide({ confirmed: true })}> Yes hide({ confirmed: false })}> No ); }; // Usage in caller component: // import { magicModal } from "react-native-magic-modal"; // const handleConfirm = async () => { // const result = await magicModal.show(() => ).promise; // if (result.reason === "INTENTIONAL_HIDE" && result.data.confirmed) { // console.log("User confirmed"); // } // }; ``` -------------------------------- ### Ensure MagicModalPortal is in the component tree Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/quick-reference.md When encountering a 'MagicModalPortal not found' error, verify that the MagicModalPortal component is rendered at the root of your application's component tree. The 'Wrong' example shows it missing, while the 'Correct' example includes it alongside the app navigator. ```typescript // ❌ Wrong: Portal not in tree export default function App() { return ; } // ✓ Correct: Portal in root export default function App() { return ( <> ); } ``` -------------------------------- ### Modal Without Return Data Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/useMagicModal.md Example of a simple modal that closes without returning any specific data. The type parameter for useMagicModal is omitted, defaulting to void. ```typescript import React from "react"; import { View, Text, Pressable } from "react-native"; import { useMagicModal } from "react-native-magic-modal"; const SimpleModal = () => { // No type parameter - defaults to void const { hide } = useMagicModal(); return ( Hello! hide(undefined)}> Close ); }; ``` -------------------------------- ### Show Modal with Custom Configuration Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/README.md Demonstrates how to display a modal with specific configuration options such as swipe direction, animation timing, and backdrop color. Use this for advanced customization of modal behavior. ```typescript magicModal.show( () => , { swipeDirection: "up", animationInTiming: 400, backdropColor: "rgba(0, 0, 0, 0.9)", // ... more options } ); ``` -------------------------------- ### Preferred Modal Flow with Confirmation Source: https://github.com/gstj/react-native-magic-modal/blob/main/README.md Demonstrates a typical modal interaction flow, including showing a confirmation modal and then a response modal based on user input. Ensure GestureHandlerRootView is set up. ```javascript import React from "react"; import { View, Text, TouchableOpacity } from "react-native"; import { MagicModalPortal, magicModal, useMagicModal, MagicModalHideReason } from "react-native-magic-modal"; import { GestureHandlerRootView } from "react-native-gesture-handler"; type ConfirmationModalReturn = { success: boolean; }; const ConfirmationModal = () => { const { hide } = useMagicModal(); return ( hide({ success: true }) }> Click here to confirm ); }; const ResponseModal = ({ text }) => { const { hide } = useMagicModal(); return ( {text} hide() }> Close ); }; const handleConfirmationFlow = async () => { // You can call `show` with or without props, depending on the requirements of the modal. const result = await magicModal.show(() => ).promise; // Hide could potentially be a backdrop press, a back button press, or a swipe gesture. if (result.reason !== MagicModalHideReason.INTENTIONAL_HIDE) { // User cancelled the flow return; } if (result.data.success) { return magicModal.show(() => ).promise; } return magicModal.show(() => ).promise; }; export const MainScreen = () => { return ( Start the modal flow! ); }; ``` -------------------------------- ### Modal Hide Resolution with Automatic Dismissal Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/types.md Example of the resolved value when a modal is hidden automatically, such as by pressing the backdrop or swiping. ```typescript { reason: MagicModalHideReason.BACKDROP_PRESS } ``` -------------------------------- ### Showing a Modal with magicModal.show Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/overview.md Illustrates the data flow when a modal is displayed using the `magicModal.show` function. A promise is returned to the caller. ```javascript magicModal.show(Component, config?) ↓ MagicModalPortal state updated with new modal ↓ MagicModalProvider wraps Component with hide context ↓ MagicModal renders Component with animations and gestures ↓ Promise returned to caller ``` -------------------------------- ### Slow, Springy Modal Animation Configuration Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/Animations.md Configures a modal with a slow (600ms) and springy entrance animation using FadeIn.springify, and a 'down' swipe direction for drawing user attention. ```typescript import { FadeIn } from "react-native-reanimated"; magicModal.show( () => , { animationInTiming: 600, entering: FadeIn.springify().damping(0.6), swipeDirection: "down", } ); ``` -------------------------------- ### Multi-Step Modal Flow Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/README.md Shows how to chain multiple modals together to create a step-by-step user flow. This pattern is ideal for wizards or complex forms where users progress through distinct stages. ```typescript const step1 = await magicModal.show(() => ).promise; if (step1.reason !== "INTENTIONAL_HIDE") return; const step2 = await magicModal.show(() => ).promise; if (step2.reason !== "INTENTIONAL_HIDE") return; // Process steps ``` -------------------------------- ### Override Modal Configuration Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/configuration.md Demonstrates how to override default configuration options when showing a modal. This includes setting swipe direction, animation timing, backdrop color, and handling backdrop presses. ```typescript import { magicModal } from "react-native-magic-modal"; // Override multiple options magicModal.show( () => , { swipeDirection: "up", animationInTiming: 400, backdropColor: "rgba(0, 0, 0, 0.8)", onBackdropPress: ({ hide }) => { // Custom logic before hiding console.log("Backdrop pressed"); hide({ /* data */ }); } } ); ``` -------------------------------- ### Import magicModal Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/magicModal.md Import the magicModal singleton object from the library. ```typescript import { magicModal } from "react-native-magic-modal"; ``` -------------------------------- ### Implementing Sequential Multi-Step Modal Flows Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/quick-reference.md Chain multiple modals together to create sequential user flows. Await the `promise` of each `magicModal.show` call to ensure the previous modal is completed before proceeding to the next. ```typescript const step1 = await magicModal .show<{ selected: string }>(() => ) .promise; if (step1.reason !== "INTENTIONAL_HIDE") return; const step2 = await magicModal .show<{ confirmed: boolean }>(() => ) .promise; if (step2.reason !== "INTENTIONAL_HIDE") return; console.log("Flow complete"); ``` -------------------------------- ### Modal Hide Resolution with Intentional Dismissal and Data Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/types.md Example of the resolved value when a modal is intentionally hidden using the `hide(data)` function, including the provided data. ```typescript { reason: MagicModalHideReason.INTENTIONAL_HIDE, data: T } ``` -------------------------------- ### Clear modals between tests Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/quick-reference.md In your test setup, use `beforeEach` to call `magicModal.hideAll()`. This ensures a clean state for each test, preventing modal-related side effects from previous tests. ```typescript import { magicModal } from "react-native-magic-modal"; beforeEach(() => { magicModal.hideAll(); }); test("my modal flow", async () => { const result = await magicModal .show(() => ) .promise; expect(result.reason).toBe("INTENTIONAL_HIDE"); }); ``` -------------------------------- ### Basic Usage in eslint.config.js Source: https://github.com/gstj/react-native-magic-modal/blob/main/packages/eslint-config/README.md Import and spread the base configuration in your ESLint configuration file to apply the shared rules. ```javascript import baseConfig from "magic-eslint-config/base"; export default [...baseConfig]; ``` -------------------------------- ### Show Basic Modal Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/magicModal.md Use magicModal.show to display a simple modal component. The returned promise resolves when the modal is hidden. ```typescript import { magicModal } from "react-native-magic-modal"; const SimpleModal = () => ( Hello! ); const { promise, modalID } = magicModal.show(() => ); // Wait for modal to close const result = await promise; console.log(result.reason); // BACKDROP_PRESS, SWIPE_COMPLETE, etc. ``` -------------------------------- ### Global MagicModal API Usage Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/README.md The global `magicModal` object provides functions to show, hide, and manage modals. Use `show` to display a modal and get its ID and a promise for its result. Use `hide` to close a specific modal or `hideAll` to close all active modals. ```typescript import { magicModal } from "react-native-magic-modal"; // Show a modal const { modalID, promise } = magicModal.show(Component, config); // Hide a specific modal magicModal.hide(data, { modalID }); // Hide all modals magicModal.hideAll(); // Control full window overlay (iOS) magicModal.enableFullWindowOverlay(); magicModal.disableFullWindowOverlay(); ``` -------------------------------- ### Modal with Return Data and Confirmation Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/README.md Illustrates how to pass data back from a modal upon closing and how to await the result of a modal presentation. Use this pattern when a modal needs to return a specific value, like a confirmation status. ```typescript interface Result { confirmed: boolean; } const { hide } = useMagicModal(); return hide({ confirmed: true })}>Confirm; const result = await magicModal.show(() => ).promise; ``` -------------------------------- ### Fast Modal Animation Configuration Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/Animations.md Configures a modal with fast in and out animations (150ms duration) and a 'up' swipe direction for quick UI feedback. ```typescript magicModal.show( () => , { animationInTiming: 150, animationOutTiming: 150, swipeDirection: "up", } ); ``` -------------------------------- ### Showing Multiple Modals Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/MagicModalPortal.md Demonstrates how to show multiple modals using the magicModal API. Modals are stacked and closed in reverse order of their opening. ```typescript import { magicModal } from "react-native-magic-modal"; // Show first modal const firstModal = magicModal.show(() => ); // Show second modal on top const secondModal = magicModal.show(() => ); // Close in reverse order await secondModal.promise; // Second modal closes await firstModal.promise; // First modal closes ``` -------------------------------- ### enableFullWindowOverlay() Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/magicModal.md Enables the full window overlay behavior on iOS, ensuring modals appear above native modal screens. This is the default behavior. ```APIDOC ## enableFullWindowOverlay() ### Description Enables the full window overlay on iOS, making modals appear above native modal screens. This is the default behavior and has no effect on Android or Web. ### Method ``` void ``` ### Parameters None ### Returns `void` ### Behavior **iOS:** Modals render in a `FullWindowOverlay`, appearing above native modal screens. **Android, Web:** No effect. ### Usage ```typescript import { magicModal } from "react-native-magic-modal"; // Assuming overlay was disabled earlier magicModal.enableFullWindowOverlay(); // Subsequent modals will appear above native screens await magicModal.show(() => ).promise; ``` ### Use Case Use when you need modals to appear above native screens like UIImagePickerController, UIDocumentPickerViewController, or native permission dialogs. ``` -------------------------------- ### Run Unit Tests Source: https://github.com/gstj/react-native-magic-modal/blob/main/CONTRIBUTING.md Executes the unit tests for the project using Jest. ```sh pnpm run test ``` -------------------------------- ### magicModal.show() Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/magicModal.md Pushes a modal onto the stack and displays it. It returns a promise that resolves when the modal is hidden and a unique modal ID. ```APIDOC ## magicModal.show() ### Description Pushes a modal onto the stack and displays it. It returns a promise that resolves when the modal is hidden and a unique modal ID. ### Signature ```typescript show( newComponent: ModalChildren, newConfig?: NewConfigProps ): { promise: Promise>, modalID: string; } ``` ### Parameters #### Parameters | Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | newComponent | ModalChildren | Yes | — | A React functional component (or function returning one) that renders the modal content | | newConfig | NewConfigProps | No | undefined | Partial configuration object to override defaults from `defaultConfig` | ### Type Parameter - `T` – The type of data the modal will return when hidden via `hide(data)` ### Return Value ```typescript { promise: Promise>, modalID: string; } ``` | Property | Type | Description | |----------|------|-------------| | promise | Promise> | Resolves when the modal is hidden, with the reason and optional data | | modalID | string | Unique identifier for this modal instance; used with `magicModal.hide(data, { modalID })` | ### Throws - **Error** if `MagicModalPortal` is not mounted in the component tree: ``` "MagicModalPortal not found. Please wrap your component with MagicModalPortal." ``` ### Usage **Basic modal:** ```typescript import { magicModal } from "react-native-magic-modal"; const SimpleModal = () => ( Hello! ); const { promise, modalID } = magicModal.show(() => ); // Wait for modal to close const result = await promise; console.log(result.reason); // BACKDROP_PRESS, SWIPE_COMPLETE, etc. ``` **Modal with return type:** ```typescript type MessageReturn = { message: string }; const TextModal = () => { const { hide } = useMagicModal(); return ( hide({ message: "Hello!" })}> Tap me ); }; const result = await magicModal.show(() => ).promise; if (result.reason === "INTENTIONAL_HIDE") { console.log(result.data.message); // "Hello!" } ``` **Override configuration:** ```typescript magicModal.show( () => , { swipeDirection: "up", animationInTiming: 500, backdropColor: "rgba(0, 0, 0, 0.9)", onBackdropPress: ({ hide }) => { console.log("Backdrop tapped"); hide({}); }, } ); ``` **Complex flow:** ```typescript const handleComplexFlow = async () => { const step1 = await magicModal.show(() => ).promise; if (step1.reason !== "INTENTIONAL_HIDE" || !step1.data) return; const step2 = await magicModal.show(() => ).promise; if (step2.reason !== "INTENTIONAL_HIDE") return; console.log("Flow complete:", step2.data); }; ``` #### Modals Stack Modals are added to a stack. When showing multiple modals, they layer on top of each other: ```typescript const first = magicModal.show(() => ); const second = magicModal.show(() => ); const third = magicModal.show(() => ); // Third modal is on top, closes first await third.promise; // Second modal is now on top await second.promise; // First modal closes last await first.promise; ``` ``` -------------------------------- ### NewConfigProps Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/types.md Represents a partial configuration for a modal, allowing for overriding default `ModalProps`. Any subset of `ModalProps` can be provided. ```APIDOC ## NewConfigProps ### Description Partial modal configuration, used to override defaults. ### Type Definition ```typescript type NewConfigProps = Partial; ``` ### Usage Any combination of `ModalProps` fields may be provided; unspecified fields use defaults. **Used by:** `magicModal.show(component, newConfig)` second parameter ``` -------------------------------- ### Publish to npm Source: https://github.com/gstj/react-native-magic-modal/blob/main/CONTRIBUTING.md Publishes new versions of the package to npm using release-it. This command handles version bumping, tagging, and release creation. ```sh pnpm run release ``` -------------------------------- ### Show and Hide Multiple Modals Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/magicModal.md Demonstrates how to display multiple modals sequentially and then hide them all at once using `magicModal.hideAll()`. This is useful for clearing the modal stack, such as during testing or navigation. ```typescript import { magicModal } from "react-native-magic-modal"; // Show multiple modals magicModal.show(() => ); magicModal.show(() => ); magicModal.show(() => ); // Hide all at once magicModal.hideAll(); ``` -------------------------------- ### No Animation Configuration Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/Animations.md Configures a modal to appear and disappear instantly by setting both in and out animation timings to 0 and disabling entering/exiting animations. ```typescript import { Layout } from "react-native-reanimated"; magicModal.show( () => , { animationInTiming: 0, animationOutTiming: 0, entering: undefined, exiting: undefined, } ); ``` -------------------------------- ### Exported API from index.ts Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/overview.md This snippet shows the main exports from the library's entry point, including components, types, and utility functions. ```typescript export { MagicModalPortal } from "./components/MagicModalPortal/MagicModalPortal"; export { MagicModalHideReason, type HideReturn, type NewConfigProps, type ModalChildren, type Direction, type ModalProps, } from "./constants/types"; export { magicModal } from "./utils/magicModalHandler"; export { useMagicModal } from "./components/MagicModalProvider"; ``` -------------------------------- ### EnableFullWindowOverlayFunction Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/types.md Enables the full window overlay behavior, primarily for iOS, making modals appear above native modal screens. This is the default behavior. ```APIDOC ## EnableFullWindowOverlayFunction ### Description Enables the full window overlay behavior, primarily for iOS, making modals appear above native modal screens. This is the default behavior. ### Method `enableFullWindowOverlay` ### Parameters None ### Request Example ```javascript magicModal.enableFullWindowOverlay() ``` ### Response None ``` -------------------------------- ### Verify TypeScript and ESLint Source: https://github.com/gstj/react-native-magic-modal/blob/main/CONTRIBUTING.md Runs TypeScript for type checking and ESLint for code linting to ensure code quality. ```sh pnpm run typescript pnpm run lint ``` -------------------------------- ### Custom Backdrop Press Handler Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/MagicModal.md Illustrates how to implement a custom handler for backdrop presses. This allows for custom logic, such as showing a confirmation dialog, before deciding whether to hide the modal. ```typescript // Example: custom backdrop press logic magicModal.show( () => , { onBackdropPress: ({ hide }) => { console.log("Backdrop tapped"); // Don't close immediately; show confirmation showConfirmation().then((confirmed) => { if (confirmed) hide({}); }); }, } ); ``` -------------------------------- ### Mock Modal Portal and magicModal API for testing Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/quick-reference.md For testing, mock the `react-native-magic-modal` module. This allows you to control the behavior of `magicModal.show`, `hide`, and `hideAll`, and to render a null component for `MagicModalPortal` to avoid interfering with your test environment. ```javascript // jest.config.js or test setup jest.mock("react-native-magic-modal", () => ({ MagicModalPortal: () => null, magicModal: { show: jest.fn(() => ({ promise: Promise.resolve({ reason: "INTENTIONAL_HIDE", data: {}, }), modalID: "test-modal", })), hide: jest.fn(), hideAll: jest.fn(), enableFullWindowOverlay: jest.fn(), disableFullWindowOverlay: jest.fn(), }, useMagicModal: () => ({ hide: jest.fn(), }), })); ``` -------------------------------- ### Define Complete Modal Configuration Properties Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/types.md Defines all possible properties for configuring a modal's behavior, appearance, and animations. This includes timing, backdrop settings, press handlers, and swipe gestures. ```typescript type ModalProps = { animationInTiming: number; animationOutTiming: number; hideBackdrop: boolean; backdropColor: string; onBackButtonPress: (({ hide }: { hide: HookHideFunction }) => void) | undefined; onBackdropPress: (({ hide }: { hide: HookHideFunction }) => void) | undefined; style: Record; dampingFactor: number; swipeDirection: Direction | undefined; swipeVelocityThreshold: number; } & Pick, "entering" | "exiting">; ``` -------------------------------- ### EnableFullWindowOverlayFunction Type Definition Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/types.md Defines the signature for enabling the full window overlay on iOS. This function is a no-op on non-iOS platforms. ```typescript type EnableFullWindowOverlayFunction = () => void; ``` -------------------------------- ### Handle Modal Promise Resolution with Switch Statement Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/magicModal.md Demonstrates how to use a switch statement to handle the different `reason` values when a modal's promise resolves. This allows for specific actions based on how the modal was closed (e.g., backdrop press, intentional hide, global hide). ```typescript const result = await magicModal.show(() => ).promise; switch (result.reason) { case "BACKDROP_PRESS": console.log("User tapped backdrop"); break; case "SWIPE_COMPLETE": console.log("User swiped to dismiss"); break; case "BACK_BUTTON_PRESS": console.log("User pressed back button (Android)"); break; case "INTENTIONAL_HIDE": console.log("Modal was explicitly hidden with data:", result.data); break; case "GLOBAL_HIDE_ALL": console.log("All modals were hidden via hideAll()"); break; } ``` -------------------------------- ### Show Modal with Configuration Override Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/magicModal.md Override default modal configurations like swipe direction, timing, and backdrop color when showing a modal. ```typescript magicModal.show( () => , { swipeDirection: "up", animationInTiming: 500, backdropColor: "rgba(0, 0, 0, 0.9)", onBackdropPress: ({ hide }) => { console.log("Backdrop tapped"); hide({}); }, } ); ``` -------------------------------- ### Memoized Context Value Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/MagicModalProvider.md Demonstrates the memoization of the context value within MagicModalProvider to optimize performance. ```typescript const value = useMemo(() => ({ hide }), [hide]); return ( {children} ); ``` -------------------------------- ### Applying Default Animations with Custom Timing Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/Animations.md Illustrates how the MagicModal component applies default entry and exit animations based on swipe direction and custom timing configurations. ```typescript entering={ !isSwipeComplete ? (config.entering ?? defaultAnimationInMap[ config.swipeDirection ?? defaultDirection ].duration(config.animationInTiming)) : undefined } exiting={ !isSwipeComplete ? (config.exiting ?? defaultAnimationOutMap[ config.swipeDirection ?? defaultDirection ].duration(config.animationOutTiming)) : undefined } ``` -------------------------------- ### Integrate MagicModalPortal and GestureHandlerRootView Source: https://github.com/gstj/react-native-magic-modal/blob/main/README.md Add MagicModalPortal to your application's root structure and ensure GestureHandlerRootView is present. This is essential for modal rendering and gesture handling. ```javascript import { MagicModalPortal } from "react-native-magic-modal"; import { GestureHandlerRootView } from "react-native-gesture-handler"; export default function App() { return ( {/** After your app component hierarchy **/ ); } ``` -------------------------------- ### Showing a Simple Modal Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/quick-reference.md Use `magicModal.show` to display a simple modal. The modal can be closed using the `hide` function provided by `useMagicModal`. ```typescript import { magicModal, useMagicModal } from "react-native-magic-modal"; const SimpleModal = () => { const { hide } = useMagicModal(); return ( hide(undefined)}> Close ); }; magicModal.show(() => ); ``` -------------------------------- ### Create toast-like notifications Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/quick-reference.md Implement toast-like notifications by creating a modal component that automatically hides itself after a set duration using `setTimeout`. Configure the modal with a transparent backdrop and appropriate animation timings for a seamless experience. ```typescript const Toast = ({ message }: { message: string }) => { const { hide } = useMagicModal(); useEffect(() => { const timer = setTimeout(() => hide(undefined), 2000); return () => clearTimeout(timer); }, [hide]); return ( {message} ); }; magicModal.show( () => , { swipeDirection: "up", backdropColor: "transparent", animationInTiming: 300, } ); ``` -------------------------------- ### GlobalShowFunction Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/types.md Imperatively shows a new modal. It accepts a React component for the modal content and optional configuration. It returns a promise that resolves when the modal is hidden, along with a unique modal ID. ```APIDOC ## GlobalShowFunction ### Description Imperatively shows a new modal. It accepts a React component for the modal content and optional configuration. It returns a promise that resolves when the modal is hidden, along with a unique modal ID. ### Method `show` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **newComponent** (ModalChildren) - Required - A React functional component that renders the modal content - **newConfig** (NewConfigProps) - Optional - Partial configuration to override defaults ### Request Example ```javascript magicModal.show(MyModalComponent, { animation: 'fade' }) ``` ### Response #### Success Response (200) - **promise** (Promise>) - Resolves when the modal is hidden, with the reason and optional data - **modalID** (string) - Unique identifier for this modal instance #### Response Example ```json { "promise": "", "modalID": "unique-modal-id-123" } ``` ``` -------------------------------- ### Showing Multiple Modals Sequentially Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/quick-reference.md Display multiple modals that stack on top of each other. Each `magicModal.show` call returns a promise that resolves when its corresponding modal is closed. The modals close in a LIFO (Last-In, First-Out) order. ```typescript const modal1 = magicModal.show(() => ); const modal2 = magicModal.show(() => ); const modal3 = magicModal.show(() => ); // They stack on top of each other // Modal3 is on top and closes first await modal3.promise; // Modal3 closes await modal2.promise; // Modal2 closes await modal1.promise; // Modal1 closes ``` -------------------------------- ### Showing a Modal with Data Return Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/quick-reference.md Display a modal that returns data upon closing. Use generics with `useMagicModal` and `magicModal.show` to define and retrieve the return type. The `promise` property on the result allows awaiting the modal's closure. ```typescript interface ModalResult { confirmed: boolean; } const ConfirmModal = () => { const { hide } = useMagicModal(); return ( <> hide({ confirmed: true })}> Yes hide({ confirmed: false })}> No ); }; const result = await magicModal.show(() => ).promise; if (result.reason === "INTENTIONAL_HIDE" && result.data.confirmed) { // Handle confirmation } ``` -------------------------------- ### Basic App Usage Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/MagicModalPortal.md Place MagicModalPortal near the root of your application, typically after your main app content and within GestureHandlerRootView. ```typescript import React from "react"; import { View, GestureHandlerRootView } from "react-native-gesture-handler"; import { MagicModalPortal } from "react-native-magic-modal"; export default function App() { return ( {/* Portal should be on top */} ); } ``` -------------------------------- ### Custom Enter/Exit Animations Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/MagicModal.md Demonstrates how to provide custom entering and exiting animations for a modal using `react-native-reanimated` components. Use this when default animations do not meet your design requirements. ```typescript import { FadeIn, SlideInDown } from "react-native-reanimated"; magicModal.show( () => , { entering: FadeIn.duration(400).delay(100), exiting: SlideInDown.duration(300), } ); ``` -------------------------------- ### Import MagicModalPortal Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/MagicModalPortal.md Import the MagicModalPortal component from the react-native-magic-modal library. ```typescript import { MagicModalPortal } from "react-native-magic-modal"; ``` -------------------------------- ### Advanced Custom Animation Chains with Reanimated Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/Animations.md Demonstrates creating complex custom animations by chaining multiple react-native-reanimated animation configurations, including springify and easing. ```typescript import { FadeIn, SlideInDown, ZoomIn, } from "react-native-reanimated"; magicModal.show( () => , { entering: FadeIn.duration(200) .springify() .damping(0.8) .mass(1.2), exiting: SlideOutUp.duration(300) .easing(Easing.inOut(Easing.ease)), } ); ``` -------------------------------- ### Backdrop Opacity Interpolation Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/Animations.md Shows how the modal backdrop's opacity is interpolated based on swipe progress during a gesture, creating a smooth fade effect. ```typescript opacity: interpolate( translationValue, [rangeMap[swipeDirection], 0], [0, 1], Extrapolation.CLAMP, ); ``` -------------------------------- ### Import useMagicModal Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/useMagicModal.md Import the useMagicModal hook from the react-native-magic-modal library. ```typescript import { useMagicModal } from "react-native-magic-modal"; ``` -------------------------------- ### Swipe-to-Dismiss Spring Animation Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/Animations.md Explains the use of `withSpring` for animating the modal off-screen during a completed swipe-to-dismiss gesture, utilizing velocity and overshoot clamping. ```typescript withSpring( rangeMap[config.swipeDirection ?? defaultDirection], { velocity: event.velocityX, overshootClamping: true } ) ``` -------------------------------- ### Backdrop Opacity Interpolation Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/Animations.md Interpolates backdrop opacity in real-time during swipe gestures. The opacity ranges from 1 at the initial position to 0 at the final position, with smooth transitions in between. ```typescript interpolate( translationValue, [rangeMap[swipeDirection], 0], // Input range [0, 1], // Output range Extrapolation.CLAMP // Clamping ) ``` -------------------------------- ### Custom Animations with Delays and Sequences Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/Animations.md Illustrates how to add delays to custom entry animations and apply different durations for entry and exit animations using react-native-reanimated. ```typescript import { FadeIn, FadeOut, Easing } from "react-native-reanimated"; magicModal.show( () => , { entering: FadeIn.duration(300).delay(100), exiting: FadeOut.duration(200), } ); ``` -------------------------------- ### Enable Full Window Overlay Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/magicModal.md Enables the full window overlay behavior on iOS, causing modals to render above native modal screens. This is the default behavior and is useful when integrating with native components like image or document pickers. ```typescript import { magicModal } from "react-native-magic-modal"; // Assuming overlay was disabled earlier magicModal.enableFullWindowOverlay(); // Subsequent modals will appear above native screens await magicModal.show(() => ).promise; ``` -------------------------------- ### Error Handling Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/useMagicModal.md Illustrates the error that occurs when useMagicModal is used outside of a MagicModalProvider context. ```typescript // This will throw an error: // "MagicModalPortal not found. Please wrap your component with MagicModalPortal." // import { useMagicModal } from "react-native-magic-modal"; // const BadComponent = () => { // const { hide } = useMagicModal(); // ❌ Not inside a modal // }; ``` -------------------------------- ### Define Swipe and Animation Directions Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/types.md Specifies the possible directions for modal animations and swipe gestures. These include 'up', 'down', 'left', and 'right'. ```typescript type Direction = "up" | "down" | "left" | "right"; ``` -------------------------------- ### Show Modal with Return Type Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/api-reference/magicModal.md Define a return type for the modal and use it to pass data back when the modal is hidden intentionally. ```typescript type MessageReturn = { message: string }; const TextModal = () => { const { hide } = useMagicModal(); return ( hide({ message: "Hello!" })}> Tap me ); }; const result = await magicModal.show(() => ).promise; if (result.reason === "INTENTIONAL_HIDE") { console.log(result.data.message); // "Hello!" } ``` -------------------------------- ### Control Full Window Overlay on iOS Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/configuration.md Manage the `FullWindowOverlay` behavior on iOS globally. Disable it to ensure modals do not appear above certain native screens, or re-enable it as needed. ```typescript // Disable for current and subsequent modals magicModal.disableFullWindowOverlay(); await magicModal.show(() => ).promise; // Re-enable magicModal.enableFullWindowOverlay(); ``` -------------------------------- ### Implementing Conditional Multi-Step Modal Flows Source: https://github.com/gstj/react-native-magic-modal/blob/main/_autodocs/quick-reference.md Create branching logic within modal flows based on user actions or data. Use a `switch` statement on the result of a modal's promise to determine the next modal to display. ```typescript const result = await magicModal .show<{ action: "edit" | "delete" }>(() => ) .promise; switch (result.data?.action) { case "edit": await magicModal.show(() => ).promise; break; case "delete": await magicModal.show(() => ).promise; break; } ```