@vegajs/modal-controller
Version:
A flexible modal management system for React applications, featuring ModalContainer, ModalProvider, and ModalController components for advanced and intuitive modal workflows.
245 lines (180 loc) • 7.37 kB
Markdown
# @vegajs/modal-controller
[](https://badge.fury.io/js/%40vegajs%2Fmodal-controller)
- [Introduction](#introduction)
- [ModalContainer](#modalcontainer)
- [Props](#props)
- [Usage](#usage)
- [ModalProvider](#modalprovider)
- [Usage](#usage-1)
- [ModalController](#modalcontroller)
- [API Overview](#api-overview)
- [Methods](#methods)
- [Examples](#examples)
- [Advanced Usage](#advanced-usage)
# Introduction
This documentation is intended to provide a comprehensive guide to the `ModalContainer`, `ModalProvider`, and `ModalController` components. These components form a system for managing modal windows in your application, offering a flexible, extensible, and intuitive API for both simple and advanced modal workflows.
## Installation
Install the package via npm:
```bash
npm install @vegajs/storage
```
# ModalContainer
`ModalContainer` is a wrapper component that is responsible for rendering the currently active modal window on the page. It listens to the `ModalController` to determine which modal to display.
## Props
- **controller**: *(Required)* An instance of `ModalController` that manages the modal windows. This prop determines which modal is currently active and handles its lifecycle.
- **BackdropComponent**: *(Optional)* A component that wraps around the modal content to create a backdrop effect. If not provided, the modal content will be displayed without a backdrop.
## Usage
```typescript jsx
import { modalController, ModalContainer } from '@vegajs/modal-controller';
export const App = () => (
<div>
<ModalContainer controller={modalController} />
<ModalShow />
</div>
);
```
In this example, `ModalContainer` listens to the `modalController` to determine which modal to render. You can also provide a custom `BackdropComponent` for added visual effects.
# ModalProvider
`ModalProvider` is a wrapper component that provides modal management via React context. It works with the `useModal` hook, allowing you to easily manage modals without explicitly passing a controller.
## Usage
```typescript jsx
import { ModalProvider } from '@vegajs/modal-controller';
export const App = () => (
<div>
<ModalProvider>
<ModalShowWithContext />
</ModalProvider>
</div>
);
```
With `ModalProvider`, any nested component can use the `useModal` hook to show or hide modals without direct access to a modal controller instance.
# ModalController
`ModalController` is a class responsible for managing the entire lifecycle of modal windows. It provides a rich set of methods for displaying, hiding, and confirming modals.
## API Overview
The `ModalController` API provides the following core methods:
- `show`: Displays a new modal.
- `onClose`: Closes the current modal.
- `onResolve`: Completes the current modal with a result.
- `subscribe`: Listens for changes to the current modal.
- `closeAll`: Closes all active modals.
## Methods
### `subscribe(listener: Listener<ModalUnit | null>): () => void`
Subscribes to changes in the currently active modal and notifies listeners when the active modal changes.
**Parameters**:
- `listener`: A function that receives the current modal state (`ModalUnit | null`).
**Returns**:
- A function to unsubscribe from the current modal state.
### `show(modal: ModalUnit): EventEmitter<ResolveObject<T>>`
Displays a new modal. If the modal is already in the queue, it will be moved to the top.
**Parameters**:
- `modal`: The modal data to be displayed.
**Returns**:
- An `EventEmitter` that can be used to subscribe to the resolution of the modal.
**Example**:
```typescript
const modal = modalController.show(myModalData);
modal.subscribe(({ status }) => console.log(status));
```
### `onClose(): void`
Closes the currently active modal. If the modal has a confirmation step, it will display the confirmation modal instead.
**Example**:
```typescript
<button onClick={controller.onClose}>Close Modal</button>
```
### `onResolve(status: boolean, data?: T): void`
Completes the current modal by providing the result of its execution. If `status` is `true`, the modal will be closed.
**Parameters**:
- `status`: A boolean indicating whether the modal was successfully completed.
- `data`: Optional data to pass to the subscribers of the modal.
**Example**:
```typescript
<button onClick={() => controller.onResolve(true)}>Confirm</button>
<button onClick={() => controller.onResolve(false)}>Cancel</button>
```
### `closeAll(): void`
Closes all active modals and unsubscribes any listeners.
**Example**:
```typescript
controller.closeAll();
```
## Examples
### Displaying a Basic Modal
Using `modalController`:
```typescript
modalController.show({ id: 'baseModal', component: BaseModal });
```
Using `useModal`:
```typescript jsx
import { useModal } from '@vegajs/modal-controller';
const Component = () => {
const { show } = useModal();
const handleShowModal = () => {
show({ id: 'baseModal', component: BaseModal });
};
return <button onClick={handleShowModal}>Show Modal</button>;
};
```
### Displaying a Modal with Confirmation
```typescript
const handleShowBaseWithConfirm = () => {
modalController
.show({
id: 'baseModalWithConfirm',
component: BaseModal,
confirmComponent: ConfirmModal,
})
.subscribe(({ status }) => {
console.log(`Modal closed with status: ${status}`);
});
};
```
### Displaying a Modal with an Inner Modal
**Base Modal**:
```typescript jsx
const handleShowModalWithInnerModal = () => {
modalController
.show({
id: 'withInnerModal',
component: (props) => {
const handlerShowInner = () => {
modalController
.show({
id: 'innerModal',
component: InnerModal,
})
.subscribe(({ status }) => {
console.log(`Modal closed with status: ${status}`);
});
};
return (
<BaseModal {...props}>
<button onClick={handlerShowInner}>Show Inner Modal</button>
</BaseModal>
);
},
})
.subscribe(({ status }) => {
console.log(`Modal closed with status: ${status}`);
});
};
```
# Advanced Usage
## Nested Modals
You can use the `ModalController` to manage nested modals by calling `show` inside a modal's component. This allows you to create complex workflows, such as step-by-step wizards or confirmation dialogs within modals.
## Handling Modal Completion
Use the `onResolve` method to handle the result of a modal. This can be useful for confirmation dialogs, where the user must either confirm or cancel an action.
**Example**:
```typescript jsx
const handleConfirm = () => {
modalController.show({
id: 'confirmDelete',
component: ConfirmDeleteModal,
}).subscribe(({ status }) => {
if (status) {
// Perform the delete action
}
});
};
```
# Conclusion
The `ModalContainer`, `ModalProvider`, and `ModalController` components provide a powerful system for managing modals in your application. By combining these components, you can create a variety of modal workflows, from simple alerts to complex multi-step wizards. The rich API of `ModalController` allows you to customize and extend modal behaviors to suit your application's needs.