### 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;
}
```