react-hooks-use-modal
Advanced tools
Comparing version 3.2.0 to 3.3.0
@@ -1,9 +0,15 @@ | ||
import { Options as FocusTrapOptions } from 'focus-trap'; | ||
import { Options } from 'focus-trap'; | ||
import React from 'react'; | ||
export interface WrapperProps { | ||
interface ModalProviderProps extends UseModalOptions<{}> { | ||
children?: React.ReactNode; | ||
} | ||
declare const ModalProvider: React.FC<ModalProviderProps>; | ||
interface WrapperProps { | ||
children: React.ReactNode; | ||
} | ||
export interface OverlayProps { | ||
interface OverlayProps { | ||
} | ||
export interface ModalProps<T extends Record<string, unknown>> { | ||
interface ModalProps<T extends Record<string, unknown>> { | ||
title?: React.ReactNode; | ||
@@ -15,6 +21,6 @@ description?: React.ReactNode; | ||
} | ||
export interface UseModalOptions<T extends Record<string, unknown>> { | ||
interface UseModalOptions<T extends Record<string, unknown>> { | ||
initialValue?: boolean; | ||
preventScroll?: boolean; | ||
focusTrapOptions?: FocusTrapOptions; | ||
focusTrapOptions?: Options; | ||
components?: { | ||
@@ -26,3 +32,3 @@ Wrapper?: React.ComponentType<WrapperProps>; | ||
} | ||
export interface ModalWrapperProps<T extends Record<string, unknown>> { | ||
interface ModalWrapperProps<T extends Record<string, unknown>> { | ||
title?: React.ReactNode; | ||
@@ -33,3 +39,3 @@ description?: React.ReactNode; | ||
} | ||
export declare type UseModalResult<T extends Record<string, unknown>> = [ | ||
type UseModalResult<T extends Record<string, unknown>> = [ | ||
ModalWrapper: React.FC<ModalWrapperProps<T>>, | ||
@@ -40,4 +46,5 @@ open: () => void, | ||
]; | ||
export declare type UseModal<T extends Record<string, unknown>> = (elementId?: string, options?: UseModalOptions<T>) => UseModalResult<T>; | ||
export declare const useModal: <T extends Record<string, unknown>>(elementId?: string, options?: UseModalOptions<T> | undefined) => UseModalResult<T>; | ||
export { ModalProvider } from './components/ModalProvider'; | ||
type UseModal<T extends Record<string, unknown>> = (elementId?: string, options?: UseModalOptions<T>) => UseModalResult<T>; | ||
declare const useModal: <T extends Record<string, unknown>>(elementId?: string, options?: UseModalOptions<T> | undefined) => UseModalResult<T>; | ||
export { ModalProps, ModalProvider, ModalWrapperProps, OverlayProps, UseModal, UseModalOptions, UseModalResult, WrapperProps, useModal }; |
@@ -1,1 +0,251 @@ | ||
var e=require("react"),t=require("react-dom"),n=require("body-scroll-lock"),r=require("focus-trap");function l(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var o=l(e),a={position:"fixed",top:0,left:0,bottom:0,right:0,display:"flex",justifyContent:"center",alignItems:"center",zIndex:1e3},i=function(e){return o.default.createElement("div",{style:a},e.children)},c={position:"fixed",top:0,left:0,bottom:0,right:0,backgroundColor:"rgba(0, 0, 0, 0.5)"},u=function(){return o.default.createElement("div",{style:c})},s=function(t){return o.default.createElement(e.Fragment,null,t.children)};function d(){return d=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},d.apply(this,arguments)}var f=function(l){var a=l.children,i=l.isOpen,c=l.close,u=l.elementId,s=void 0===u?"root":u,f=l.title,p=l.description,v=l.preventScroll,m=l.focusTrapOptions,h=l.components,b=l.additionalProps,y=e.useRef(null);return function(t,n,l){e.useEffect(function(){if(n&&null!==t.current){var e=r.createFocusTrap(t.current,d({fallbackFocus:t.current},l));return e.activate(),setTimeout(function(){document.activeElement===t.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(){e.deactivate()}}},[l,n,t])}(y,i,e.useMemo(function(){return d({onDeactivate:c,clickOutsideDeactivates:!0},m)},[c,m])),function(t,r,l){e.useEffect(function(){if(null!==t.current)return l?(r?n.disableBodyScroll(t.current,{reserveScrollBarGap:!0}):n.enableBodyScroll(t.current),function(){n.clearAllBodyScrollLocks()}):void 0},[r,l,t])}(y,i,v),!1===i?null:t.createPortal(o.default.createElement(h.Wrapper,null,o.default.createElement(h.Overlay,null),o.default.createElement("div",{ref:y,role:"dialog","aria-modal":"true",tabIndex:-1,style:{position:"relative"}},o.default.createElement(h.Modal,{title:f,description:p,close:c,additionalProps:b},a))),document.getElementById(s))},p=e.createContext({}),v=["children"],m={initialValue:!1,preventScroll:!1,focusTrapOptions:{},components:{}};exports.ModalProvider=function(e){var t=e.children,n=function(e,t){if(null==e)return{};var n,r,l={},o=Object.keys(e);for(r=0;r<o.length;r++)t.indexOf(n=o[r])>=0||(l[n]=e[n]);return l}(e,v);return o.default.createElement(p.Provider,{value:n},t)},exports.useModal=function(t,n){var r,l,a;void 0===t&&(t="root");var c=e.useContext(p),d=e.useMemo(function(){return Object.assign({},m,c,n)},[c,n]),v=d.preventScroll,h=d.focusTrapOptions,b=d.components,y=e.useState(d.initialValue),O=y[0],g=y[1],E=e.useCallback(function(){g(!0)},[g]),k=e.useCallback(function(){g(!1)},[g]),x=null!=(r=b.Wrapper)?r:i,S=null!=(l=b.Overlay)?l:u,w=null!=(a=b.Modal)?a:s;return[e.useCallback(function(e){return o.default.createElement(f,{isOpen:O,close:k,elementId:t,title:e.title,description:e.description,preventScroll:v,focusTrapOptions:h,components:{Modal:w,Overlay:S,Wrapper:x},additionalProps:e.additionalProps},e.children)},[w,S,x,k,t,h,O,v]),E,k,O]}; | ||
"use strict"; | ||
var __create = Object.create; | ||
var __defProp = Object.defineProperty; | ||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
var __getOwnPropNames = Object.getOwnPropertyNames; | ||
var __getProtoOf = Object.getPrototypeOf; | ||
var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
var __export = (target, all) => { | ||
for (var name in all) | ||
__defProp(target, name, { get: all[name], enumerable: true }); | ||
}; | ||
var __copyProps = (to, from, except, desc) => { | ||
if (from && typeof from === "object" || typeof from === "function") { | ||
for (let key of __getOwnPropNames(from)) | ||
if (!__hasOwnProp.call(to, key) && key !== except) | ||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
} | ||
return to; | ||
}; | ||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( | ||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, | ||
mod | ||
)); | ||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
// src/index.tsx | ||
var src_exports = {}; | ||
__export(src_exports, { | ||
ModalProvider: () => ModalProvider, | ||
useModal: () => useModal | ||
}); | ||
module.exports = __toCommonJS(src_exports); | ||
var import_react7 = __toESM(require("react")); | ||
// src/components/DefaultComponents.tsx | ||
var import_react = __toESM(require("react")); | ||
var wrapperStyle = { | ||
position: "fixed", | ||
top: 0, | ||
left: 0, | ||
bottom: 0, | ||
right: 0, | ||
display: "flex", | ||
justifyContent: "center", | ||
alignItems: "center", | ||
zIndex: 1e3 | ||
}; | ||
var Wrapper = ({ children }) => { | ||
return /* @__PURE__ */ import_react.default.createElement("div", { style: wrapperStyle }, children); | ||
}; | ||
var overlayStyle = { | ||
position: "fixed", | ||
top: 0, | ||
left: 0, | ||
bottom: 0, | ||
right: 0, | ||
backgroundColor: "rgba(0, 0, 0, 0.5)" | ||
}; | ||
var Overlay = () => { | ||
return /* @__PURE__ */ import_react.default.createElement("div", { style: overlayStyle }); | ||
}; | ||
var Modal = ({ | ||
children | ||
}) => { | ||
return /* @__PURE__ */ import_react.default.createElement(import_react.Fragment, null, children); | ||
}; | ||
// src/components/Modal.tsx | ||
var import_react4 = __toESM(require("react")); | ||
var import_react_dom = require("react-dom"); | ||
// src/hooks/useBodyScrollLock.ts | ||
var import_body_scroll_lock = require("body-scroll-lock"); | ||
var import_react2 = require("react"); | ||
var useBodyScrollLock = (ref, isOpen, preventScroll) => { | ||
(0, import_react2.useEffect)(() => { | ||
if (ref.current === null) { | ||
return; | ||
} | ||
if (preventScroll) { | ||
if (isOpen) { | ||
(0, import_body_scroll_lock.disableBodyScroll)(ref.current, { | ||
reserveScrollBarGap: true | ||
}); | ||
} else { | ||
(0, import_body_scroll_lock.enableBodyScroll)(ref.current); | ||
} | ||
return () => { | ||
(0, import_body_scroll_lock.clearAllBodyScrollLocks)(); | ||
}; | ||
} | ||
}, [isOpen, preventScroll, ref]); | ||
}; | ||
// src/hooks/useFocusTrap.tsx | ||
var import_focus_trap = require("focus-trap"); | ||
var import_react3 = require("react"); | ||
var useFocusTrap = (ref, isOpen, focusTrapOptions) => { | ||
(0, import_react3.useEffect)(() => { | ||
if (!isOpen || ref.current === null) { | ||
return; | ||
} | ||
const focusTrap = (0, import_focus_trap.createFocusTrap)(ref.current, { | ||
fallbackFocus: ref.current, | ||
...focusTrapOptions | ||
}); | ||
focusTrap.activate(); | ||
setTimeout(() => { | ||
if (document.activeElement === ref.current) { | ||
console.warn(`[react-hooks-use-modal]: Since there were no focusable elements in the modal, the initial focus was on the containing element. | ||
WAI-ARIA 1.1 states that there should be at least one focusable element in the modal. | ||
https://www.w3.org/TR/wai-aria-1.1/#dialog`); | ||
} | ||
}, 100); | ||
return () => { | ||
focusTrap.deactivate(); | ||
}; | ||
}, [focusTrapOptions, isOpen, ref]); | ||
}; | ||
// src/components/Modal.tsx | ||
var ModalWrapper = ({ | ||
children, | ||
isOpen, | ||
close, | ||
elementId = "root", | ||
title, | ||
description, | ||
preventScroll, | ||
focusTrapOptions, | ||
components, | ||
additionalProps | ||
}) => { | ||
const dialogRef = (0, import_react4.useRef)(null); | ||
const _focusTrapOptions = (0, import_react4.useMemo)( | ||
() => ({ | ||
onDeactivate: close, | ||
clickOutsideDeactivates: true, | ||
...focusTrapOptions | ||
}), | ||
[close, focusTrapOptions] | ||
); | ||
useFocusTrap(dialogRef, isOpen, _focusTrapOptions); | ||
useBodyScrollLock(dialogRef, isOpen, preventScroll); | ||
if (isOpen === false) { | ||
return null; | ||
} | ||
return (0, import_react_dom.createPortal)( | ||
/* @__PURE__ */ import_react4.default.createElement(components.Wrapper, null, /* @__PURE__ */ import_react4.default.createElement(components.Overlay, null), /* @__PURE__ */ import_react4.default.createElement( | ||
"div", | ||
{ | ||
ref: dialogRef, | ||
role: "dialog", | ||
"aria-modal": "true", | ||
tabIndex: -1, | ||
style: { position: "relative" } | ||
}, | ||
/* @__PURE__ */ import_react4.default.createElement( | ||
components.Modal, | ||
{ | ||
title, | ||
description, | ||
close, | ||
additionalProps | ||
}, | ||
children | ||
) | ||
)), | ||
document.getElementById(elementId) | ||
); | ||
}; | ||
// src/hooks/useModalConfig.ts | ||
var import_react5 = require("react"); | ||
var ModalConfigContext = (0, import_react5.createContext)({}); | ||
var useModalConfig = () => { | ||
return (0, import_react5.useContext)(ModalConfigContext); | ||
}; | ||
// src/components/ModalProvider.tsx | ||
var import_react6 = __toESM(require("react")); | ||
var ModalProvider = ({ | ||
children, | ||
...props | ||
}) => { | ||
return /* @__PURE__ */ import_react6.default.createElement(ModalConfigContext.Provider, { value: props }, children); | ||
}; | ||
// src/index.tsx | ||
var defaultOptions = { | ||
initialValue: false, | ||
preventScroll: false, | ||
focusTrapOptions: {}, | ||
components: {} | ||
}; | ||
var useModal = (elementId = "root", options) => { | ||
const modalConfig = useModalConfig(); | ||
const { initialValue, preventScroll, focusTrapOptions, components } = (0, import_react7.useMemo)( | ||
() => Object.assign({}, defaultOptions, modalConfig, options), | ||
[modalConfig, options] | ||
); | ||
const [isOpen, setOpen] = (0, import_react7.useState)(initialValue); | ||
const open = (0, import_react7.useCallback)(() => { | ||
setOpen(true); | ||
}, [setOpen]); | ||
const close = (0, import_react7.useCallback)(() => { | ||
setOpen(false); | ||
}, [setOpen]); | ||
const Wrapper2 = components.Wrapper ?? Wrapper; | ||
const Overlay2 = components.Overlay ?? Overlay; | ||
const Modal2 = components.Modal ?? Modal; | ||
const _ModalWrapper = (0, import_react7.useCallback)( | ||
({ title, description, children, additionalProps }) => { | ||
return /* @__PURE__ */ import_react7.default.createElement( | ||
ModalWrapper, | ||
{ | ||
isOpen, | ||
close, | ||
elementId, | ||
title, | ||
description, | ||
preventScroll, | ||
focusTrapOptions, | ||
components: { | ||
Modal: Modal2, | ||
Overlay: Overlay2, | ||
Wrapper: Wrapper2 | ||
}, | ||
additionalProps | ||
}, | ||
children | ||
); | ||
}, | ||
[ | ||
Modal2, | ||
Overlay2, | ||
Wrapper2, | ||
close, | ||
elementId, | ||
focusTrapOptions, | ||
isOpen, | ||
preventScroll | ||
] | ||
); | ||
return [_ModalWrapper, open, close, isOpen]; | ||
}; | ||
// Annotate the CommonJS export names for ESM import in node: | ||
0 && (module.exports = { | ||
ModalProvider, | ||
useModal | ||
}); |
@@ -16,2 +16,6 @@ module.exports = [ | ||
}, | ||
{ | ||
path: '/future', | ||
title: 'Future useModal example', | ||
}, | ||
]; |
{ | ||
"name": "react-hooks-use-modal", | ||
"version": "3.2.0", | ||
"version": "3.3.0", | ||
"author": "shibe97", | ||
@@ -17,13 +17,24 @@ "description": "A react hook which can open the modal with react-portal", | ||
"main": "dist/index.js", | ||
"module": "dist/index.modern.js", | ||
"module": "dist/index.mjs", | ||
"types": "dist/index.d.ts", | ||
"exports": { | ||
".": { | ||
"import": "./dist/index.mjs", | ||
"require": "./dist/index.js" | ||
}, | ||
"./future": { | ||
"import": "./dist/future/index.mjs", | ||
"require": "./dist/future/index.js" | ||
} | ||
}, | ||
"dependencies": { | ||
"body-scroll-lock": "^3.1.5", | ||
"focus-trap": "^7.0.0" | ||
"body-scroll-lock": "^4.0.0-beta.0", | ||
"focus-trap": "^7.2.0" | ||
}, | ||
"devDependencies": { | ||
"@types/body-scroll-lock": "^3.1.0", | ||
"@types/deepmerge": "^2.2.0", | ||
"@types/react": "^18.0.21", | ||
"@types/react-dom": "^18.0.6", | ||
"css-loader": "^6.7.2", | ||
"esbuild-css-modules-plugin": "^2.6.3", | ||
"eslint": "^8.22.0", | ||
@@ -36,7 +47,8 @@ "eslint-config-prettier": "^8.5.0", | ||
"lint-staged": "^13.0.3", | ||
"microbundle": "^0.13.3", | ||
"prettier": "^2.3.2", | ||
"react": "^18.2.0", | ||
"react-dom": "^18.2.0", | ||
"style-loader": "^3.3.1", | ||
"ts-loader": "^8.2.0", | ||
"tsup": "^6.5.0", | ||
"typescript": "^4.3.5", | ||
@@ -52,6 +64,6 @@ "webpack": "^5.50.0", | ||
"scripts": { | ||
"build": "microbundle --sourcemap false", | ||
"watch": "microbundle --watch", | ||
"start": "webpack-dev-server --mode development", | ||
"lint": "eslint --ext .ts --ext .tsx . --cache", | ||
"build": "tsup", | ||
"watch": "tsup --watch", | ||
"start:demo": "webpack-dev-server --mode development", | ||
"build:demo": "webpack --mode production", | ||
@@ -58,0 +70,0 @@ "deploy:demo": "gh-pages -d examples/dist", |
@@ -195,3 +195,3 @@ # useModal | ||
``` | ||
$ npm install | ||
$ yarn | ||
``` | ||
@@ -202,3 +202,3 @@ | ||
``` | ||
$ npm run build | ||
$ yarn build | ||
``` | ||
@@ -209,21 +209,15 @@ | ||
``` | ||
$ npm run watch | ||
$ yarn watch | ||
``` | ||
### Build examples | ||
### Start demo | ||
``` | ||
$ npm run build:demo | ||
$ yarn start:demo | ||
``` | ||
### Start examples | ||
Then access it on http://localhost:3001/react-hooks-use-modal | ||
``` | ||
$ npm start | ||
``` | ||
http://localhost:3001 | ||
## License | ||
MIT |
@@ -9,5 +9,6 @@ { | ||
"strict": true, | ||
"allowSyntheticDefaultImports": true | ||
"allowSyntheticDefaultImports": true, | ||
"baseUrl": "./" | ||
}, | ||
"include": ["src"] | ||
"include": ["src/**/*", "css-modules.d.ts"] | ||
} |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
36139
985
0
22
15
221
1
+ Addedbody-scroll-lock@4.0.0-beta.0(transitive)
- Removedbody-scroll-lock@3.1.5(transitive)
Updatedfocus-trap@^7.2.0