Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

react-modal-global

Package Overview
Dependencies
Maintainers
1
Versions
84
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-modal-global - npm Package Compare versions

Comparing version 0.9.33 to 1.0.0

115

dist/index.d.ts

@@ -1,4 +0,5 @@

import { ReactElement, Component, ReactNode } from 'react';
import { ReactElement, Component, ReactNode, ComponentLifecycle } from 'react';
import { HasRequiredKeys } from 'type-fest';
declare type ModalComponent<P = unknown> = (props: P) => ReactElement;
type ModalComponent<P = unknown> = (props: P) => ReactElement;
interface ModalParams {

@@ -35,16 +36,94 @@ /**

}
/**
* Gets either a tuple with required or optional parameters depending on whether `P` has any required keys.
*
* Can be used in function argument to make `params` optional if `P` has only optional keys.
*
* @example
* function open<P>(component: ModalComponent<P>, ...[modalParams]: ModalWindowParams<P>) {}
*
* const OkComponent = () => <div />
* open(OkComponent, { id: 1 }) // OK
* open(OkComponent) // OK
*
* const FailComponent = (props: { required: boolean }) => <div />
* open(FailComponent, { required: true }) // OK
* open(FailComponent) // Error: missing required property `required`
*/
type ModalWindowParams<P = unknown> = HasRequiredKeys<NonNullable<P>> extends true ? [Partial<ModalParams> & P] : [(Partial<ModalParams> & P)?];
declare class Modal {
static open<P>(component: ModalComponent<P>, ...[modalParams]: keyof P extends never ? [Partial<ModalParams>?] : [Partial<ModalParams> & P]): ModalWindow<P> & PromiseLike<void>;
static replace<P>(component: ModalComponent<P>, ...[params]: keyof P extends never ? [Partial<ModalParams>?] : [Partial<ModalParams> & P]): ModalWindow<P> & PromiseLike<void>;
private static add;
private static remove;
private static fork;
static closeAll(): void;
/**
* Controller for opening and closing modal windows.
*
* Can be used with `ModalContainer` or with custom implementation.
*/
declare class ModalController {
/**
* Opens a modal window. Infers props from the component.
*
* - If the same modal window is already in the queue, it will be ignored.
* - If the modal window is weak, it will be unmounted after closing.
* - If the modal window is forked, it will be opened over all other modals.
* - If the modal window is closable (be default `true`), it will be closed by clicking on the overlay.
* - If the modal window is not closable, it will be closed only by calling internal `close` method.
*
* @param component Modal component.
* @param params Modal params.
* @returns Modal window and `PromiseLike`.
*
* @example
* const modal = modalController.open(MyModal, { id: 1 })
* modal.closable // `true` by default
*
* modal.then(() => console.log("Modal was closed"))
* modal.close()
*/
open<P>(component: ModalComponent<P>, ...[modalParams]: ModalWindowParams<P>): ModalWindow<P> & PromiseLike<void>;
/**
* Replaces the last modal window in the queue with a new one.
*
* If the queue is empty, it will be added to the queue.
*/
replace<P>(component: ModalComponent<P>, ...[params]: ModalWindowParams<P>): ModalWindow<P> & PromiseLike<void>;
/**
* Adds a modal window to the queue.
*/
private add;
/**
* Removes a modal window from the queue.
*/
private remove;
/**
* Forks a modal window and adds it to a forked queue.
*
* It means that the modal will be open over all other modals.
*/
private fork;
/**
* Closes all modals by its component (including forked) starting from the last one.
*/
closeByComponent<P>(component: ModalComponent<P>): void;
/**
* Closes all modals by its id (including forked) starting from the last one.
*/
closeById(id: ModalParams["id"]): void;
/**
* Closes all modals (including forked).
*/
closeAll(): void;
}
declare const Modal: ModalController;
interface ModalContainerProps {
/**
* Template for modal window.
*/
template?: (props: {
children: ReactNode;
}) => ReactElement;
/**
* Modal container class name. It will be used as a base for modifiers (will replace defaulted `"modal"`).
*
* @default "modal"
*/
className?: string;

@@ -57,2 +136,7 @@ }

}
/**
* Modal container component. Renders modal windows.
*
* Can be used multiple times to render modals in different places.
*/
declare class ModalContainer extends Component<ModalContainerProps, ModalContainerState> {

@@ -67,4 +151,13 @@ state: ModalContainerState;

declare function useModalContext(): ModalWindow<unknown>;
/**
* Used inside a modal component to access the modal context (`ModalWindow`).
*
* Accepts a generic type that is used to infer the props of the modal component.
* It has 3 overloads:
* 1. `useModalContext<ModalComponent>()` - infers the props from the class component type.
* 2. `useModalContext<typeof ModalComponent>()` - infers the props from the function component type.
* 3. `useModalContext<unknown>()` - infers any type besides the above.
*/
declare function useModalContext<T>(): ModalWindow<T extends ComponentLifecycle<infer P, unknown> | ((props: infer P) => ReactNode) ? P : T>;
export { Modal, ModalContainer, useModalContext };
export { Modal, ModalContainer, ModalController, useModalContext };

30

dist/index.ts

@@ -1,14 +0,16 @@

'use strict';Object.defineProperty(exports,"__esModule",{value:!0});var jsxRuntime=require("react/jsx-runtime"),react=require("react"),extendStatics=function(d,b){extendStatics=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(a,c){a.__proto__=c}||function(a,c){for(var e in c)Object.prototype.hasOwnProperty.call(c,e)&&(a[e]=c[e])};return extendStatics(d,b)};
function __extends(d,b){function a(){this.constructor=d}if("function"!==typeof b&&null!==b)throw new TypeError("Class extends value "+String(b)+" is not a constructor or null");extendStatics(d,b);d.prototype=null===b?Object.create(b):(a.prototype=b.prototype,new a)}var __assign=function(){__assign=Object.assign||function(d){for(var b,a=1,c=arguments.length;a<c;a++){b=arguments[a];for(var e in b)Object.prototype.hasOwnProperty.call(b,e)&&(d[e]=b[e])}return d};return __assign.apply(this,arguments)};
function __read(d,b){var a="function"===typeof Symbol&&d[Symbol.iterator];if(!a)return d;d=a.call(d);var c,e=[];try{for(;(void 0===b||0<b--)&&!(c=d.next()).done;)e.push(c.value)}catch(g){var f={error:g}}finally{try{c&&!c.done&&(a=d["return"])&&a.call(d)}finally{if(f)throw f.error;}}return e}function __spreadArray(d,b,a){if(a||2===arguments.length)for(var c=0,e=b.length,f;c<e;c++)!f&&c in b||(f||(f=Array.prototype.slice.call(b,0,c)),f[c]=b[c]);return d.concat(f||Array.prototype.slice.call(b))}
var modalContext=react.createContext(null);function classWithModifiers(d){for(var b=[],a=1;a<arguments.length;a++)b[a-1]=arguments[a];b=b.filter(Boolean);if(!b.length)return d;b=b.map(function(c){return d+"--"+c});return d+" "+b.join(" ")}var getCircularReplacer=function(){var d=new WeakSet;return function(b,a){if("object"===typeof a&&null!==a){if(d.has(a))return;d.add(a)}return a}};function serialize(d){return null==d?String(d):JSON.stringify(d,getCircularReplacer())}
function stopPropagation(d){return function(b){var a=b.target;b=b.currentTarget;a instanceof Element&&b instanceof Element&&a!==b||(null===d||void 0===d?void 0:d())}}
var containers=new Set,ModalContainer=function(d){function b(){var a=null!==d&&d.apply(this,arguments)||this;a.state={active:!1,queue:[],forkedQueue:[]};return a}__extends(b,d);Object.defineProperty(b.prototype,"className",{get:function(){return this.props.className||"modal"},enumerable:!1,configurable:!0});b.prototype.componentDidMount=function(){containers.add(this)};b.prototype.componentWillUnmount=function(){containers.delete(this)};b.prototype.render=function(){var a,c,e=this.state,f=e.active;
e=e.queue;e=e[e.length-1];var g=(null===(a=null===e||void 0===e?void 0:e.params)||void 0===a?0:a.closable)?stopPropagation(e.close):void 0;a=this.props.template||react.Fragment;return jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx("div",__assign({className:classWithModifiers(this.className,f&&"active"),"aria-modal":!0,"aria-hidden":!f},{children:jsxRuntime.jsx("div",__assign({className:this.className+"__container",onClick:g},{children:jsxRuntime.jsx(modalContext.Provider,__assign({value:e||
null},{children:jsxRuntime.jsx(a,{children:(null===e||void 0===e?void 0:e.component)&&react.createElement(e.component,__assign({},e.params,{key:null===(c=null===e||void 0===e?void 0:e.params)||void 0===c?void 0:c.id}))})}))}))})),this.renderForks()]})};b.prototype.renderForks=function(){var a=this;return this.state.forkedQueue.map(function(c){var e;return jsxRuntime.jsx("div",__assign({className:classWithModifiers(a.className,"active"),"aria-modal":!0},{children:jsxRuntime.jsx("div",__assign({className:a.className+
"__container",onClick:(null===(e=c.params)||void 0===e?0:e.closable)?stopPropagation(c.close):void 0},{children:jsxRuntime.jsx(modalContext.Provider,__assign({value:c},{children:jsxRuntime.jsx(c.component,__assign({},c.params))}))}))}),c.params.id)})};return b}(react.Component),DEFAULT_STATE={active:!1,queue:[],forkedQueue:[]},DEFAULT_PARAMS={id:0,closable:!0,weak:!1,fork:!1};
function dispatch(d){var b=__spreadArray([],__read(containers),!1).at(-1);null==b?console.warn("ModalError: no containers were mounted."):b.setState(d)}
var Modal=function(){function d(){}d.open=function(b){for(var a=[],c=1;c<arguments.length;c++)a[c-1]=arguments[c];a=__read(a,1)[0];a=__assign(__assign({},DEFAULT_PARAMS),a);var e={component:b,params:a,close:function(){f();d.remove(e)}},f=function(){},g=new Promise(function(h){return f=h});d.add(e);return __assign(__assign({},e),{then:function(h,k){return g.then(h,k)}})};d.replace=function(b){for(var a=[],c=1;c<arguments.length;c++)a[c-1]=arguments[c];a=__read(a,1)[0];dispatch(function(e){return __assign(__assign({},
e),{queue:e.queue.slice(0,-1)})});return d.open(b,a)};d.add=function(b){b.params.fork?this.fork(b):dispatch(function(a){var c;return(null===(c=b.params)||void 0===c||!c.weak)&&0<a.queue.length&&(c=a.queue[a.queue.length-1],serialize(c.params)===serialize(b.params)&&c.component===b.component)?__assign(__assign({},a),{active:!0,queue:[b]}):!1===a.active&&1===a.queue.length?__assign(__assign({},a),{active:!0,queue:[b]}):__assign(__assign({},a),{active:!0,queue:__spreadArray(__spreadArray([],__read(a.queue),
!1),[b],!1)})})};d.remove=function(b){b.params.fork?dispatch(function(a){var c=a.forkedQueue.filter(function(e){return e!==b});return __assign(__assign({},a),{forkedQueue:c})}):dispatch(function(a){var c=a.queue.filter(function(f){return f!==b}),e=0===c.length;return!b.params.weak&&e?__assign(__assign({},a),{active:!1}):__assign(__assign({},a),{queue:c,active:!e})})};d.fork=function(b){dispatch(function(a){return __assign(__assign({},a),{forkedQueue:__spreadArray(__spreadArray([],__read(a.forkedQueue),
!1),[b],!1)})})};d.closeAll=function(){dispatch(function(b){b.queue.forEach(function(a){return a.close()});return DEFAULT_STATE})};return d}();function useModalContext(){var d=react.useContext(modalContext);if(!d)throw Error("ModalError: Out of Modal context");return d}exports.Modal=Modal;exports.ModalContainer=ModalContainer;exports.useModalContext=useModalContext
'use strict';Object.defineProperty(exports,"__esModule",{value:!0});var jsxRuntime=require("react/jsx-runtime"),react=require("react"),extendStatics=function(e,b){extendStatics=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(a,c){a.__proto__=c}||function(a,c){for(var d in c)Object.prototype.hasOwnProperty.call(c,d)&&(a[d]=c[d])};return extendStatics(e,b)};
function __extends(e,b){function a(){this.constructor=e}if("function"!==typeof b&&null!==b)throw new TypeError("Class extends value "+String(b)+" is not a constructor or null");extendStatics(e,b);e.prototype=null===b?Object.create(b):(a.prototype=b.prototype,new a)}var __assign=function(){__assign=Object.assign||function(e){for(var b,a=1,c=arguments.length;a<c;a++){b=arguments[a];for(var d in b)Object.prototype.hasOwnProperty.call(b,d)&&(e[d]=b[d])}return e};return __assign.apply(this,arguments)};
function __read(e,b){var a="function"===typeof Symbol&&e[Symbol.iterator];if(!a)return e;e=a.call(e);var c,d=[];try{for(;(void 0===b||0<b--)&&!(c=e.next()).done;)d.push(c.value)}catch(g){var f={error:g}}finally{try{c&&!c.done&&(a=e["return"])&&a.call(e)}finally{if(f)throw f.error;}}return d}function __spreadArray(e,b,a){if(a||2===arguments.length)for(var c=0,d=b.length,f;c<d;c++)!f&&c in b||(f||(f=Array.prototype.slice.call(b,0,c)),f[c]=b[c]);return e.concat(f||Array.prototype.slice.call(b))}
var modalContext=react.createContext(null);function classWithModifiers(e){for(var b=[],a=1;a<arguments.length;a++)b[a-1]=arguments[a];b=b.filter(Boolean);if(!b.length)return e;b=b.map(function(c){return e+"--"+c});return e+" "+b.join(" ")}var getCircularReplacer=function(){var e=new WeakSet;return function(b,a){if("object"===typeof a&&null!==a){if(e.has(a))return;e.add(a)}return a}};function serialize(e){return null==e?String(e):JSON.stringify(e,getCircularReplacer())}
function stopPropagation(e){return function(b){var a=b.target;b=b.currentTarget;a instanceof Element&&b instanceof Element&&a!==b||(null===e||void 0===e?void 0:e())}}
var containers=new Set,ModalContainer=function(e){function b(){var a=null!==e&&e.apply(this,arguments)||this;a.state={active:!1,queue:[],forkedQueue:[]};return a}__extends(b,e);Object.defineProperty(b.prototype,"className",{get:function(){return this.props.className||"modal"},enumerable:!1,configurable:!0});b.prototype.componentDidMount=function(){containers.add(this)};b.prototype.componentWillUnmount=function(){containers.delete(this)};b.prototype.render=function(){var a,c,d=this.state,f=d.active;
d=d.queue;d=d[d.length-1];var g=(null===(a=null===d||void 0===d?void 0:d.params)||void 0===a?0:a.closable)?stopPropagation(d.close):void 0;a=this.props.template||react.Fragment;return jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx("div",__assign({className:classWithModifiers(this.className,f&&"active"),"aria-modal":!0,"aria-hidden":!f},{children:jsxRuntime.jsx("div",__assign({className:this.className+"__container",onClick:g},{children:jsxRuntime.jsx(modalContext.Provider,__assign({value:d||
null},{children:jsxRuntime.jsx(a,{children:(null===d||void 0===d?void 0:d.component)&&react.createElement(d.component,__assign({},d.params,{key:null===(c=null===d||void 0===d?void 0:d.params)||void 0===c?void 0:c.id}))})}))}))})),this.renderForks()]})};b.prototype.renderForks=function(){var a=this;return this.state.forkedQueue.map(function(c){var d;return jsxRuntime.jsx("div",__assign({className:classWithModifiers(a.className,"active"),"aria-modal":!0},{children:jsxRuntime.jsx("div",__assign({className:a.className+
"__container",onClick:(null===(d=c.params)||void 0===d?0:d.closable)?stopPropagation(c.close):void 0},{children:jsxRuntime.jsx(modalContext.Provider,__assign({value:c},{children:jsxRuntime.jsx(c.component,__assign({},c.params))}))}))}),c.params.id)})};return b}(react.Component),DEFAULT_STATE={active:!1,queue:[],forkedQueue:[]},DEFAULT_PARAMS={id:0,closable:!0,weak:!1,fork:!1};
function dispatch(e){var b=__spreadArray([],__read(containers),!1).at(-1);null==b?console.warn("ModalError: no containers were mounted."):b.setState(e)}
var ModalController=function(){function e(){}e.prototype.open=function(b){for(var a=this,c=[],d=1;d<arguments.length;d++)c[d-1]=arguments[d];c=__read(c,1)[0];var f=function(){},g=new Promise(function(h){return f=h});c=__assign(__assign({},DEFAULT_PARAMS),c);var k={component:b,params:c,close:function(){a.remove(k);f()}};this.add(k);return __assign(__assign({},k),{then:function(h,l){return g.then(h,l)}})};e.prototype.replace=function(b){for(var a=[],c=1;c<arguments.length;c++)a[c-1]=arguments[c];a=
__read(a,1)[0];dispatch(function(d){return __assign(__assign({},d),{queue:d.queue.slice(0,-1)})});return this.open(b,a)};e.prototype.add=function(b){b.params.fork?this.fork(b):dispatch(function(a){var c;if((null===(c=b.params)||void 0===c||!c.weak)&&0<a.queue.length){var d=a.queue[a.queue.length-1];c=serialize(b.params)===serialize(d.params);d=b.component===d.component;if(c&&d)return __assign(__assign({},a),{active:!0})}return __assign(__assign({},a),{active:!0,queue:__spreadArray(__spreadArray([],
__read(a.queue),!1),[b],!1)})})};e.prototype.remove=function(b){b.params.fork?dispatch(function(a){var c=a.forkedQueue.filter(function(d){return d!==b});return __assign(__assign({},a),{forkedQueue:c})}):dispatch(function(a){var c=a.queue.filter(function(f){return f!==b}),d=0===c.length;return d&&!b.params.weak?__assign(__assign({},a),{active:!1}):__assign(__assign({},a),{queue:c,active:!d})})};e.prototype.fork=function(b){dispatch(function(a){return __assign(__assign({},a),{forkedQueue:__spreadArray(__spreadArray([],
__read(a.forkedQueue),!1),[b],!1)})})};e.prototype.closeByComponent=function(b){dispatch(function(a){var c=__spreadArray([],__read(a.queue.filter(function(f){return f.component===b})),!1),d=__spreadArray([],__read(a.forkedQueue.filter(function(f){return f.component===b})),!1);c.reverse().forEach(function(f){return f.close()});d.reverse().forEach(function(f){return f.close()});return a})};e.prototype.closeById=function(b){dispatch(function(a){var c=a.queue.filter(function(f){return f.params.id===b}),
d=a.forkedQueue.filter(function(f){return f.params.id===b});c.forEach(function(f){return f.close()});d.forEach(function(f){return f.close()});return a})};e.prototype.closeAll=function(){dispatch(function(b){b.queue.forEach(function(a){return a.close()});return DEFAULT_STATE})};return e}(),Modal=new ModalController;function useModalContext(){var e=react.useContext(modalContext);if(!e)throw Error("ModalError: useModalContext must be used within a modalContext");return e}exports.Modal=Modal;
exports.ModalContainer=ModalContainer;exports.ModalController=ModalController;exports.useModalContext=useModalContext
{
"name": "react-modal-global",
"version": "0.9.33",
"version": "1.0.0",
"description": "React Modal but Global",

@@ -11,4 +11,4 @@ "main": "dist/index.ts",

],
"dependencies": {
"react": "^18.2.0"
"peerDependencies": {
"react": "18.x"
},

@@ -18,2 +18,5 @@ "devDependencies": {

"@rollup/plugin-typescript": "^8.3.3",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@types/jest": "^29.4.0",
"@types/react": "^18.0.15",

@@ -29,2 +32,3 @@ "eslint": "^8.6.0",

"tslib": "^2.4.0",
"type-fest": "^3.5.5",
"typescript": "4.7.4"

@@ -37,3 +41,4 @@ },

"help": "ncc",
"test": "",
"test": "react-scripts test",
"test:coverage": "react-scripts test --coverage *",
"post-fix": "eslint out --fix"

@@ -57,3 +62,8 @@ },

},
"homepage": "https://github.com/FrameMuse/react-modal-global#readme"
"homepage": "https://github.com/FrameMuse/react-modal-global#readme",
"jest": {
"testMatch": [
"**/?(*.)+(spec|test).ts?(x)"
]
}
}
# React Modal Global
Needs feedback, please contribute in GitHub Issues or leave your message on [my discord server](https://discord.gg/DCUWrRhvnt).
[![codecov](https://codecov.io/gh/FrameMuse/react-modal-global/branch/main/graph/badge.svg?token=1FRUN6AQDA)](https://codecov.io/gh/FrameMuse/react-modal-global)
[![npm version](https://badge.fury.io/js/react-modal-global.svg)](https://badge.fury.io/js/react-modal-global)
[![npm downloads](https://img.shields.io/npm/dm/react-modal-global.svg)](https://www.npmjs.com/package/react-modal-global)
[![GitHub license](https://img.shields.io/github/license/FrameMuse/react-modal-global)]()
## Introduction
[![GitHub stars](https://img.shields.io/github/stars/FrameMuse/react-modal-global)]()
[![GitHub contributors](https://img.shields.io/github/contributors/FrameMuse/react-modal-global)]()
[![GitHub last commit](https://img.shields.io/github/last-commit/FrameMuse/react-modal-global)]()
This is a package that provides modal dialogs which does similar to [`react-modal`](https://www.npmjs.com/package/react-modal) except that it is accessed from _anywhere_.
## Presentation
## Features
React modal dialogs which is similar to [`react-modal`](https://www.npmjs.com/package/react-modal) but it may be called from `useEffect`, that's why it is **global** ^_^
## Contribute
Needs feedback, please contribute in GitHub Issues or leave your message to [my discord server](https://discord.gg/DCUWrRhvnt).
## Navigation
- [React Modal Global](#react-modal-global)
- [Presentation](#presentation)
- [Contribute](#contribute)
- [Navigation](#navigation)
- [Advantages](#advantages)
- [Major advantages](#major-advantages)
- [Minor advantages](#minor-advantages)
- [Usage](#usage)
- [Add container](#add-container)
- [Show `ModalContainer` usage example](#show-modalcontainer-usage-example)
- [Create new Modal component](#create-new-modal-component)
- [Plain component](#plain-component)
- [Using `modal context`](#using-modal-context)
- [Modal component usage](#modal-component-usage)
- [Modal Template](#modal-template)
- [Modal layouts](#modal-layouts)
- [If using several containers](#if-using-several-containers)
- [Layout concept](#layout-concept)
- [Description](#description)
- [Aria](#aria)
- [Modal controller](#modal-controller)
- [`Open`](#open)
- [`Close`](#close)
- [`CloseByComponent`](#closebycomponent)
- [`CloseById`](#closebyid)
- [Modal options](#modal-options)
## Advantages
### Major advantages
- Allows to use modals in `useEffect` hook without creating a new component for each one by passing `props` to `open` method.
- Allows opening modals without wrapping them in components and controlling their state.
- Allows to use modals in non-component context (e.g. in `useEffect` hook).
- Allows to reuse modals in different places without creating a new component for each one by passing `props` to `open` method.
- Allows to use various modal types (Dialog, Popup, Drawer) by creating your own layout for each one (advised naming is `[Type][Name]` => `DrawerLayout`).
- Allows customizing modal controls by extending `ModalController` class and creating your own layouts.
- Allows to use several containers at different depths of your app (e.g. to vary templates).
- Allows forking modals and creating "layer depth" (_in development_).
### Minor advantages
- Globalization - opened from anywhere (even from non-component context)
- Multicontainers - for e.g. templates
- Context - the data passed when openning can be accessed in the component via `useModalContext` hook
- Stacking/Nesting
- Forking
- Data preservation
- `open` method returns `Promise`
-
- Context - data that passed in `open` method can be accessed in the component using `useModalContext` hook
- Stacking/Nesting (as a container option).
- Data preservation (after closing last modal, the data will be preserved and if same modal will be request to open, it will _restore_ previous modal but with `weak: true` it will not happen)
- `open` method is `PromiseLike` (`thenable`) - you can use `await` or `then` to wait for modal closing
- The package uses only react as a peer dependency
- The package uses only react as a dependency.
## Usage
#### The main idea
Usage may seem a bit complicated but it's actually very simple, please, be patient and read all the thing through.
There is a `ModalContainer` which is a container for modal components (it usually appears in `#root` element) and modal components will appear there as you open them.
### Add container
<details>
<summary>Show `ModalContainer` usage example</summary>
`ModalContainer` is a container for modal components (it usually appears in the root of your app) and modal components will appear there as you open them.
#### Show `ModalContainer` usage example
```tsx

@@ -46,9 +98,2 @@ import React from "react"

</details>
There are other features upon this idea.
## Usage
Usage may seem a bit complicated, please, be patient and read all the thing throughout.
### Create new Modal component

@@ -79,4 +124,4 @@

<p>Content text</p>
<button type="button" onClick={() => modal.close()}>My custom button to close modal</button>
<button type="button" onClick={modal.close}>close</button>
</>

@@ -114,14 +159,2 @@ )

### Modal options
You can use options when opening a modal.
Available options
| Option | Description |
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id` | Specifies id of a modal (default: `Date.now()`). In react it's used as a `key`. May be used to find and close specific modal or else. |
| `closable` | Specifies if a modal closing is controlled itself |
| `weak` | By default, a last closed modal will not be removed and if same modal will be request to open, it will _restore_ previous modal but with `weak: true` it will not happen. |
| `fork` | Creates a new layer for a single modal |
### Modal Template

@@ -135,3 +168,2 @@

### Modal layouts

@@ -141,3 +173,3 @@

[See example here](./examples/PopupLayout)
[![Edit react-modal-global](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/react-modal-global-examples-47yoil)

@@ -186,1 +218,64 @@ To create your first `Popup` modal try this

```
## Layout concept
### Description
Layout is a component that wraps modal component and allows to customize modal look and controls (close button, header, footer, etc.).
Layouts are used to create various modal types (Dialog, Popup, Drawer) and to customize modal controls.
For example, you can create your own `PopupLayout` to use it in your `Popup` modals.
[See example here](./examples/PopupLayout)
### Aria
Layouts should not have `aria-modal` attribute and `role="dialog"` because they are already set in `ModalContainer` component.
You should manually add `aria-labelledby` and `aria-describedby` attributes to your layout.
## Modal controller
### `Open`
`Modal.open` is a method that opens a modal. See [usage](#modal-component-usage) for example. See [options](#modal-options) for more details.
```tsx
Modal.open(ModalComponent, { /* options */ })
```
### `Close`
There is no `Modal.close` method because it's hard to know what exactly window to close, instead you can close a modal from inside of a modal component using `useModalContext` hook.
Or using `Modal.closeBy` methods.
#### `CloseByComponent`
`Modal.closeByComponent` is a method that closes a modal by its component. It will close all modals that use this component.
```tsx
Modal.closeByComponent(ModalComponent)
```
#### `CloseById`
`Modal.closeById` is a method that closes a modal by its id. It will close all modals that have this id.
```tsx
Modal.closeById("insane-id")
```
### Modal options
You can use options when opening a modal with `Modal.open()`.
Available options
| Option | Description |
| ---------- | ---------- |
| `id` | Specifies id of a modal. In react it's used as a `key`. May be used to find and close specific modal or else. |
| `closable` | Specifies if a modal closing is controllable internally. If `false`, it's supposed to mean that user should do a **specific** action to close. |
| `weak` | By default, a last closed modal will not be removed if the same modal will be requested to open. It will _restore_ previous modal but with `weak: true` it will not happen. |

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc