New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

react-hooks-use-modal

Package Overview
Dependencies
Maintainers
1
Versions
18
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-hooks-use-modal - npm Package Compare versions

Comparing version 2.1.0 to 3.0.0

.husky/pre-commit

33

dist/index.d.ts

@@ -0,16 +1,30 @@

import { Options as FocusTrapOptions } from 'focus-trap';
import React from 'react';
export interface WrapperProps {
children: React.ReactNode;
}
export interface OverlayProps {
}
export interface ModalProps {
title?: React.ReactNode;
description?: React.ReactNode;
close: () => void;
children: React.ReactNode;
isOpen: boolean;
onOverlayClick: React.MouseEventHandler<HTMLDivElement>;
elementId: 'root' | string;
}
export interface ModalOptions {
export interface UseModalOptions {
preventScroll?: boolean;
closeOnOverlayClick?: boolean;
focusTrapOptions?: FocusTrapOptions;
components?: {
Wrapper?: React.ComponentType<WrapperProps>;
Overlay?: React.ComponentType<OverlayProps>;
Modal?: React.ComponentType<ModalProps>;
};
}
export declare type UseModal = (elementId: string, options?: ModalOptions) => [
ModalWrapper: React.FC<{
children: React.ReactNode;
}>,
export interface ModalWrapperProps {
title?: React.ReactNode;
description?: React.ReactNode;
children: React.ReactNode;
}
export declare type UseModal = (elementId?: string, options?: UseModalOptions) => [
ModalWrapper: React.FC<ModalWrapperProps>,
open: () => void,

@@ -21,1 +35,2 @@ close: () => void,

export declare const useModal: UseModal;
export { ModalProvider } from './components/ModalProvider';

@@ -1,1 +0,1 @@

var e=require("react"),t=require("react-dom"),l=require("disable-scroll");function n(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var o=n(e),r=n(l),i={position:"fixed",top:0,left:0,bottom:0,right:0,display:"flex",justifyContent:"center",alignItems:"center",zIndex:1e3},a={position:"fixed",top:0,left:0,bottom:0,right:0,backgroundColor:"rgba(0, 0, 0, 0.5)",zIndex:1e5},d={position:"relative",zIndex:100001},c=function(e){var l=e.children,n=e.isOpen,r=e.elementId,c=void 0===r?"root":r;return!1===(void 0!==n&&n)?null:t.createPortal(o.default.createElement("div",{style:i},o.default.createElement("div",{style:a,onClick:e.onOverlayClick}),o.default.createElement("div",{style:d},l)),document.getElementById(c))};exports.useModal=function(t,l){void 0===t&&(t="root"),void 0===l&&(l={});var n=l.preventScroll,i=void 0!==n&&n,a=l.closeOnOverlayClick,d=void 0===a||a,u=e.useState(!1),f=u[0],s=u[1],v=e.useCallback(function(){s(!0),i&&r.default.on()},[s,i]),p=e.useCallback(function(){s(!1),i&&r.default.off()},[s,i]),m=e.useCallback(function(e){e.stopPropagation(),d&&p()},[d,p]);return[e.useCallback(function(e){return o.default.createElement(c,{isOpen:f,onOverlayClick:m,elementId:t},e.children)},[f,p,t]),v,p,f]};
var e=require("deepmerge"),t=require("react"),r=require("react-dom"),n=require("body-scroll-lock"),l=require("focus-trap");function o(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var a=o(e),c=o(t),i={position:"fixed",top:0,left:0,bottom:0,right:0,display:"flex",justifyContent:"center",alignItems:"center",zIndex:1e3},u=function(e){return c.default.createElement("div",{style:i},e.children)},d={position:"fixed",top:0,left:0,bottom:0,right:0,backgroundColor:"rgba(0, 0, 0, 0.5)"},s=function(){return c.default.createElement("div",{style:d})},f=function(e){return c.default.createElement(t.Fragment,null,e.children)};function p(){return p=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e},p.apply(this,arguments)}var v=function(e){var o=e.children,a=e.isOpen,i=e.close,u=e.elementId,d=void 0===u?"root":u,s=e.title,f=e.description,v=e.preventScroll,m=e.focusTrapOptions,h=e.components,b=t.useRef(null);return function(e,r,n){t.useEffect(function(){if(r&&null!==e.current){var t=l.createFocusTrap(e.current,p({fallbackFocus:e.current},n));return t.activate(),setTimeout(function(){document.activeElement===e.current&&console.warn("[react-hooks-use-modal]: Since there were no focusable elements in the modal, the initial focus was on the containing element.\n WAI-ARIA 1.1 states that there should be at least one focusable element in the modal.\n https://www.w3.org/TR/wai-aria-1.1/#dialog")},100),function(){t.deactivate()}}},[n,r,e])}(b,a,p({onDeactivate:i,clickOutsideDeactivates:!0},m)),function(e,r,l){t.useEffect(function(){if(null!==e.current)return l?(r?n.disableBodyScroll(e.current,{reserveScrollBarGap:!0}):n.enableBodyScroll(e.current),function(){n.clearAllBodyScrollLocks()}):void 0},[r,l,e])}(b,a,v),!1===a?null:r.createPortal(c.default.createElement(h.Wrapper,null,c.default.createElement(h.Overlay,null),c.default.createElement("div",{ref:b,role:"dialog","aria-modal":"true",tabIndex:-1,style:{position:"relative"}},c.default.createElement(h.Modal,{title:s,description:f,close:i},o))),document.getElementById(d))},m=t.createContext({}),h=["children"];exports.ModalProvider=function(e){var t=e.children,r=function(e,t){if(null==e)return{};var r,n,l={},o=Object.keys(e);for(n=0;n<o.length;n++)t.indexOf(r=o[n])>=0||(l[r]=e[r]);return l}(e,h);return c.default.createElement(m.Provider,{value:r},t)},exports.useModal=function(e,r){var n,l,o;void 0===e&&(e="root"),void 0===r&&(r={});var i=a.default(t.useContext(m),r),d=i.preventScroll,p=void 0!==d&&d,h=i.focusTrapOptions,b=void 0===h?{}:h,y=i.components,g=void 0===y?{}:y,O=t.useState(!1),E=O[0],k=O[1],x=t.useCallback(function(){k(!0)},[k]),w=t.useCallback(function(){k(!1)},[k]),S=null!=(n=g.Wrapper)?n:u,I=null!=(l=g.Overlay)?l:s,C=null!=(o=g.Modal)?o:f;return[t.useCallback(function(t){return c.default.createElement(v,{isOpen:E,close:w,elementId:e,title:t.title,description:t.description,preventScroll:p,focusTrapOptions:b,components:{Modal:C,Overlay:I,Wrapper:S}},t.children)},[C,I,S,w,e,b,E,p]),x,w,E]};

@@ -1,1 +0,1 @@

import e,{useState as t,useCallback as o}from"react";import{createPortal as n}from"react-dom";import i from"disable-scroll";var r={position:"fixed",top:0,left:0,bottom:0,right:0,display:"flex",justifyContent:"center",alignItems:"center",zIndex:1e3},l={position:"fixed",top:0,left:0,bottom:0,right:0,backgroundColor:"rgba(0, 0, 0, 0.5)",zIndex:1e5},c={position:"relative",zIndex:100001},d=function(t){var o=t.children,i=t.isOpen,d=t.elementId,a=void 0===d?"root":d;return!1===(void 0!==i&&i)?null:n(e.createElement("div",{style:r},e.createElement("div",{style:l,onClick:t.onOverlayClick}),e.createElement("div",{style:c},o)),document.getElementById(a))},a=function(n,r){void 0===n&&(n="root"),void 0===r&&(r={});var l=r.preventScroll,c=void 0!==l&&l,a=r.closeOnOverlayClick,m=void 0===a||a,f=t(!1),v=f[0],p=f[1],s=o(function(){p(!0),c&&i.on()},[p,c]),u=o(function(){p(!1),c&&i.off()},[p,c]),y=o(function(e){e.stopPropagation(),m&&u()},[m,u]);return[o(function(t){return e.createElement(d,{isOpen:v,onOverlayClick:y,elementId:n},t.children)},[v,u,n]),s,u,v]};export{a as useModal};
import e from"deepmerge";import t,{Fragment as n,useEffect as r,useRef as o,createContext as i,useContext as l,useState as c,useCallback as a}from"react";import{createPortal as u}from"react-dom";import{disableBodyScroll as s,enableBodyScroll as d,clearAllBodyScrollLocks as f}from"body-scroll-lock";import{createFocusTrap as p}from"focus-trap";var m={position:"fixed",top:0,left:0,bottom:0,right:0,display:"flex",justifyContent:"center",alignItems:"center",zIndex:1e3},v=function(e){return t.createElement("div",{style:m},e.children)},h={position:"fixed",top:0,left:0,bottom:0,right:0,backgroundColor:"rgba(0, 0, 0, 0.5)"},g=function(){return t.createElement("div",{style:h})},y=function(e){return t.createElement(n,null,e.children)};function O(){return O=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},O.apply(this,arguments)}var b=function(e){var n=e.children,i=e.isOpen,l=e.close,c=e.elementId,a=void 0===c?"root":c,m=e.title,v=e.description,h=e.preventScroll,g=e.focusTrapOptions,y=e.components,b=o(null);return function(e,t,n){r(function(){if(t&&null!==e.current){var r=p(e.current,O({fallbackFocus:e.current},n));return r.activate(),setTimeout(function(){document.activeElement===e.current&&console.warn("[react-hooks-use-modal]: Since there were no focusable elements in the modal, the initial focus was on the containing element.\n WAI-ARIA 1.1 states that there should be at least one focusable element in the modal.\n https://www.w3.org/TR/wai-aria-1.1/#dialog")},100),function(){r.deactivate()}}},[n,t,e])}(b,i,O({onDeactivate:l,clickOutsideDeactivates:!0},g)),function(e,t,n){r(function(){if(null!==e.current)return n?(t?s(e.current,{reserveScrollBarGap:!0}):d(e.current),function(){f()}):void 0},[t,n,e])}(b,i,h),!1===i?null:u(t.createElement(y.Wrapper,null,t.createElement(y.Overlay,null),t.createElement("div",{ref:b,role:"dialog","aria-modal":"true",tabIndex:-1,style:{position:"relative"}},t.createElement(y.Modal,{title:m,description:v,close:l},n))),document.getElementById(a))},E=i({}),w=["children"],I=function(e){var n=e.children,r=function(e,t){if(null==e)return{};var n,r,o={},i=Object.keys(e);for(r=0;r<i.length;r++)t.indexOf(n=i[r])>=0||(o[n]=e[n]);return o}(e,w);return t.createElement(E.Provider,{value:r},n)},x=function(n,r){var o,i,u;void 0===n&&(n="root"),void 0===r&&(r={});var s=e(l(E),r),d=s.preventScroll,f=void 0!==d&&d,p=s.focusTrapOptions,m=void 0===p?{}:p,h=s.components,O=void 0===h?{}:h,w=c(!1),I=w[0],x=w[1],k=a(function(){x(!0)},[x]),S=a(function(){x(!1)},[x]),T=null!=(o=O.Wrapper)?o:v,j=null!=(i=O.Overlay)?i:g,W=null!=(u=O.Modal)?u:y;return[a(function(e){return t.createElement(b,{isOpen:I,close:S,elementId:n,title:e.title,description:e.description,preventScroll:f,focusTrapOptions:m,components:{Modal:W,Overlay:j,Wrapper:T}},e.children)},[W,j,T,S,n,m,I,f]),k,S,I]};export{I as ModalProvider,x as useModal};

@@ -1,1 +0,1 @@

!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("react"),require("react-dom"),require("disable-scroll")):"function"==typeof define&&define.amd?define(["exports","react","react-dom","disable-scroll"],t):t((e||self).reactHooksUseModal={},e.react,e.reactDom,e.disableScroll)}(this,function(e,t,o,l){function n(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var i=n(t),r=n(l),a={position:"fixed",top:0,left:0,bottom:0,right:0,display:"flex",justifyContent:"center",alignItems:"center",zIndex:1e3},d={position:"fixed",top:0,left:0,bottom:0,right:0,backgroundColor:"rgba(0, 0, 0, 0.5)",zIndex:1e5},c={position:"relative",zIndex:100001},u=function(e){var t=e.children,l=e.isOpen,n=e.elementId,r=void 0===n?"root":n;return!1===(void 0!==l&&l)?null:o.createPortal(i.default.createElement("div",{style:a},i.default.createElement("div",{style:d,onClick:e.onOverlayClick}),i.default.createElement("div",{style:c},t)),document.getElementById(r))};e.useModal=function(e,o){void 0===e&&(e="root"),void 0===o&&(o={});var l=o.preventScroll,n=void 0!==l&&l,a=o.closeOnOverlayClick,d=void 0===a||a,c=t.useState(!1),f=c[0],s=c[1],p=t.useCallback(function(){s(!0),n&&r.default.on()},[s,n]),v=t.useCallback(function(){s(!1),n&&r.default.off()},[s,n]),m=t.useCallback(function(e){e.stopPropagation(),d&&v()},[d,v]);return[t.useCallback(function(t){return i.default.createElement(u,{isOpen:f,onOverlayClick:m,elementId:e},t.children)},[f,v,e]),p,v,f]}});
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("deepmerge"),require("react"),require("react-dom"),require("body-scroll-lock"),require("focus-trap")):"function"==typeof define&&define.amd?define(["exports","deepmerge","react","react-dom","body-scroll-lock","focus-trap"],t):t((e||self).reactHooksUseModal={},e.deepmerge,e.react,e.reactDom,e.bodyScrollLock,e.focusTrap)}(this,function(e,t,n,r,o,l){function a(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var c=a(t),i=a(n),u={position:"fixed",top:0,left:0,bottom:0,right:0,display:"flex",justifyContent:"center",alignItems:"center",zIndex:1e3},d=function(e){return i.default.createElement("div",{style:u},e.children)},s={position:"fixed",top:0,left:0,bottom:0,right:0,backgroundColor:"rgba(0, 0, 0, 0.5)"},f=function(){return i.default.createElement("div",{style:s})},p=function(e){return i.default.createElement(n.Fragment,null,e.children)};function m(){return m=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},m.apply(this,arguments)}var v=function(e){var t=e.children,a=e.isOpen,c=e.close,u=e.elementId,d=void 0===u?"root":u,s=e.title,f=e.description,p=e.preventScroll,v=e.focusTrapOptions,h=e.components,b=n.useRef(null);return function(e,t,r){n.useEffect(function(){if(t&&null!==e.current){var n=l.createFocusTrap(e.current,m({fallbackFocus:e.current},r));return n.activate(),setTimeout(function(){document.activeElement===e.current&&console.warn("[react-hooks-use-modal]: Since there were no focusable elements in the modal, the initial focus was on the containing element.\n WAI-ARIA 1.1 states that there should be at least one focusable element in the modal.\n https://www.w3.org/TR/wai-aria-1.1/#dialog")},100),function(){n.deactivate()}}},[r,t,e])}(b,a,m({onDeactivate:c,clickOutsideDeactivates:!0},v)),function(e,t,r){n.useEffect(function(){if(null!==e.current)return r?(t?o.disableBodyScroll(e.current,{reserveScrollBarGap:!0}):o.enableBodyScroll(e.current),function(){o.clearAllBodyScrollLocks()}):void 0},[t,r,e])}(b,a,p),!1===a?null:r.createPortal(i.default.createElement(h.Wrapper,null,i.default.createElement(h.Overlay,null),i.default.createElement("div",{ref:b,role:"dialog","aria-modal":"true",tabIndex:-1,style:{position:"relative"}},i.default.createElement(h.Modal,{title:s,description:f,close:c},t))),document.getElementById(d))},h=n.createContext({}),b=["children"];e.ModalProvider=function(e){var t=e.children,n=function(e,t){if(null==e)return{};var n,r,o={},l=Object.keys(e);for(r=0;r<l.length;r++)t.indexOf(n=l[r])>=0||(o[n]=e[n]);return o}(e,b);return i.default.createElement(h.Provider,{value:n},t)},e.useModal=function(e,t){var r,o,l;void 0===e&&(e="root"),void 0===t&&(t={});var a=c.default(n.useContext(h),t),u=a.preventScroll,s=void 0!==u&&u,m=a.focusTrapOptions,b=void 0===m?{}:m,y=a.components,g=void 0===y?{}:y,O=n.useState(!1),k=O[0],E=O[1],x=n.useCallback(function(){E(!0)},[E]),S=n.useCallback(function(){E(!1)},[E]),w=null!=(r=g.Wrapper)?r:d,T=null!=(o=g.Overlay)?o:f,I=null!=(l=g.Modal)?l:p;return[n.useCallback(function(t){return i.default.createElement(v,{isOpen:k,close:S,elementId:e,title:t.title,description:t.description,preventScroll:s,focusTrapOptions:b,components:{Modal:I,Overlay:T,Wrapper:w}},t.children)},[I,T,w,S,e,b,k,s]),x,S,k]}});
{
"name": "react-hooks-use-modal",
"version": "2.1.0",
"version": "3.0.0",
"author": "shibe97",

@@ -20,9 +20,18 @@ "description": "A react hook which can open the modal with react-portal",

"dependencies": {
"disable-scroll": "^0.6.0"
"body-scroll-lock": "^3.1.5",
"deepmerge": "^4.2.2",
"focus-trap": "^7.0.0"
},
"devDependencies": {
"@types/body-scroll-lock": "^3.1.0",
"@types/deepmerge": "^2.2.0",
"@types/react": "^17.0.16",
"@types/react-dom": "^17.0.9",
"eslint": "^8.22.0",
"eslint-config-prettier": "^8.5.0",
"eslint-config-react-app": "^7.0.1",
"gh-pages": "^2.1.1",
"html-webpack-plugin": "^5.3.2",
"husky": "^8.0.1",
"lint-staged": "^13.0.3",
"microbundle": "^0.13.3",

@@ -35,4 +44,4 @@ "prettier": "^2.3.2",

"webpack": "^5.50.0",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.2"
"webpack-cli": "^4.10.0",
"webpack-dev-server": "^4.10.0"
},

@@ -47,13 +56,23 @@ "peerDependencies": {

"start": "webpack-dev-server --mode development",
"lint": "eslint --ext .ts --ext .tsx . --cache",
"build:demo": "webpack --mode production",
"deploy:demo": "gh-pages -d examples/dist"
"deploy:demo": "gh-pages -d examples/dist",
"lint-staged": "lint-staged",
"prepare": "husky install"
},
"lint-staged": {
"*.{js,jsx,json,css,md}": [
"prettier --write",
"git add"
"*.{ts,tsx}": [
"eslint",
"prettier --write"
]
},
"eslintConfig": {
"extends": "react-app"
"extends": [
"react-app",
"prettier"
],
"ignorePatterns": [
"*.config.js",
"dist"
]
},

@@ -60,0 +79,0 @@ "prettier": {

@@ -15,3 +15,5 @@ # useModal

preventScroll: true,
closeOnOverlayClick: false;
focusTrapOptions: {
clickOutsideDeactivates: false,
},
});

@@ -37,6 +39,8 @@ return (

### [ModalComponent, openFunc, closeFunc, isOpenBool] = useModal(domNode?, { preventScroll?, closeOnOverlayClick? })
### [ModalComponent, openFunc, closeFunc, isOpenBool] = useModal(domNode?, { preventScroll?, focusTrapOptions?, components? })
`ModalComponent`
Type: React.FC<{ title?: React.ReactNode; description?: React.ReactNode, children?: React.ReactNode }>
Modal component that displays children in the screen center.
If you specify `title` and `description`, you must implement custom components with the `components` option's `Modal` property and render in them.

@@ -62,6 +66,116 @@ `openFunc`

`closeOnOverlayClick`
Optional to close modal when click the overlay.
Default value is true.
`focusTrapOptions`
Override the focus-trap options used internally.
For example, to prevent a modal from closing when a non-modal element is clicked, do the following
```jsx
useModal('root', {
focusTrapOptions: {
clickOutsideDeactivates: false,
},
});
```
`components`
Optional.
This is an option to customize the `ModalWrapper` returned by useModal.
Use as follows
```jsx
useModal('root', {
components: {
Modal: ({ title, description, children }) => {
return (
<div
style={{
padding: '60px 100px',
backgroundColor: '#fff',
borderRadius: '10px',
}}
>
{title && <h1>{title}</h1>}
{description && <p>{description}</p>}
{children}
</div>
);
},
Overlay: () => {
return (
<div
style={{
position: 'fixed',
top: 0,
left: 0,
bottom: 0,
right: 0,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
}}
/>
);
},
Wrapper: ({ children }) => {
return (
<div
style={{
position: 'fixed',
top: 0,
left: 0,
bottom: 0,
right: 0,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
zIndex: 1000,
}}
>
{children}
</div>
);
},
},
});
```
Combined with `ModalProvider` (described below), you can specify the default style for all `useModal` in the project.
## Global Settings
The `ModalProvider` component allows you to apply a common default configuration to all `useModal` hooks.
```jsx
<ModalProvider {...options}>
<Component />
</ModalProvider>
```
The following example sets all `useModal` hooks to not scroll outside the modal by default.
```jsx
const Component1 = () => {
const [Modal] = useModal('root');
return (
<Modal>
<h2>Common</h2>
</Modal>
);
};
const Component2 = () => {
const [Modal] = useModal('root', { preventScroll: false }); // override
return (
<Modal>
<h2>Override options</h2>
</Modal>
);
};
const App = () => {
return (
<ModalProvider preventScroll>
<Component1 />
<Component2 />
</ModalProvider>
);
};
```
## Demo

@@ -68,0 +182,0 @@

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