react-modal-port 0.2.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- var e=require("react/jsx-runtime"),t=require("react");function r(){return r=Object.assign?Object.assign.bind():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},r.apply(this,arguments)}var n=t.createContext({stack:[],launchModal:function(){},updateStack:function(){},updateState:function(){}});function o(){return t.useContext(n)}exports.ModalContextProvider=function(o){var a=o.children,c=t.useState([]),u=c[0],l=c[1],s={stack:u,launchModal:function(e,t,r){void 0===r&&(r={});var n=Object.keys(t).reduce(function(e,r){var n=t[r];return e[r]=function(){try{return Promise.resolve(n.apply(void 0,[].slice.call(arguments))).then(function(e){return l(function(e){return e.slice(0,-1)}),e})}catch(e){return Promise.reject(e)}},e},{});l([].concat(u,[{render:e,resolvers:n,props:r,state:{}}]))},updateStack:l,updateState:function(e){var t=[].concat(u);t[u.length-1].state=r({},e),l(t)}};return e.jsx(n.Provider,{value:s,children:a})},exports.ModalPort=function(n){var a=n.onModalLaunch,c=n.onModalClose,u=n.render,l=o().stack,s=t.useMemo(function(){return l.length>0?l[l.length-1]:null},[l]),i=t.useCallback(function(e){e.currentTarget===e.target&&(null==s?void 0:s.resolvers.onBackdropClick)&&s.resolvers.onBackdropClick(e)},[s]);return t.useEffect(function(){s?a&&a():c&&c()},[s,a,c]),s&&e.jsx(u,{onBackdropClick:i,children:s.render(r({},s.resolvers,s.props))})||null},exports.useModal=function(){return o().launchModal},exports.useModalContext=o,exports.useModalState=function(){var e=o(),t=e.stack,r=e.updateState;if(0===t.length)throw new Error("Trying to access modal state while no modal is open");return[t[t.length-1].state,r]};
1
+ var e=require("react/jsx-runtime"),r=require("react");function n(){return n=Object.assign?Object.assign.bind():function(e){for(var r=1;r<arguments.length;r++){var n=arguments[r];for(var t in n)({}).hasOwnProperty.call(n,t)&&(e[t]=n[t])}return e},n.apply(null,arguments)}var t=r.createContext(null);function o(){var e=r.useContext(t);if(!e)throw new Error("useModalContext must be used within a ModalContextProvider");return e}exports.ModalContextProvider=function(o){var u=o.children,a=r.useState([]),l=a[0],c=a[1],s=r.useCallback(function(e,r,n){void 0===n&&(n={});var t=Object.keys(r).reduce(function(e,n){var t=r[n];return e[n]=function(){try{return Promise.resolve(t.apply(void 0,[].slice.call(arguments))).then(function(e){return c(function(e){return e.slice(0,-1)}),e})}catch(e){return Promise.reject(e)}},e},{});c(function(r){return[].concat(r,[{render:e,resolvers:t,props:n,state:{}}])})},[]),i=r.useCallback(function(e){c(function(r){var t=[].concat(r);return t.length>0&&(t[t.length-1]=n({},t[t.length-1],{state:n({},e)})),t})},[]);return e.jsx(t.Provider,{value:{stack:l,launchModal:s,updateStack:c,updateState:i},children:u})},exports.ModalPort=function(t){var u=t.onModalLaunch,a=t.onModalClose,l=t.render,c=o().stack,s=r.useMemo(function(){return c.length>0?c[c.length-1]:null},[c]),i=r.useRef(null),d=r.useCallback(function(e){e.currentTarget===e.target&&null!=s&&s.resolvers.onBackdropClick&&s.resolvers.onBackdropClick(e)},[s]);r.useEffect(function(){var e=i.current;!e&&s?null==u||u():e&&!s&&(null==a||a()),i.current=s},[s,u,a]);var v=null==s?void 0:s.render;return e.jsx(e.Fragment,{children:v&&e.jsx(l,{onBackdropClick:d,children:e.jsx(v,n({},s.resolvers,s.props))})||null})},exports.useModal=function(){return o().launchModal},exports.useModalContext=o,exports.useModalState=function(){var e=o(),r=e.stack,n=e.updateState;return 0===r.length?[null,n]:[r[r.length-1].state,n]};
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/context.tsx","../src/modal-port.tsx"],"sourcesContent":["import { \n createContext, \n useContext, \n useState, \n type SyntheticEvent \n} from 'react';\nimport { \n type ModalStackItem,\n type ModalContextProperties,\n type LaunchModal,\n type LaunchModalResolvers,\n type ModalState,\n type UpdateModalState,\n} from '../types';\n\nexport const ModalContext = createContext<ModalContextProperties>({\n stack: [],\n launchModal: () => {},\n updateStack: () => {},\n updateState: () => {},\n});\n\nexport const ModalContextProvider = ({ children }: Readonly<{ children: React.ReactNode }>) => {\n\n const [ stack, updateStack ] = useState<ModalStackItem[]>([]);\n\n const launchModal: LaunchModal = (render, resolvers, props = {}) => {\n // Wrap resolvers to update the stack\n const wrappedResovers = Object.keys(resolvers).reduce((acc, key) => {\n const resolver = resolvers[key];\n acc[key] = async (...args: any[]) => {\n const result = await resolver(...args);\n // update stack with an array conating all the items in the stack except the last one\n updateStack(currStack => currStack.slice(0, -1));\n return result;\n };\n return acc;\n }, {} as LaunchModalResolvers);\n updateStack([\n ...stack,\n {\n render,\n resolvers: wrappedResovers,\n props,\n state: {},\n },\n ]);\n };\n\n const updateState = (newState: ModalState) => {\n const updatedStack = [\n ...stack,\n ];\n updatedStack[stack.length - 1].state = { ...newState };\n updateStack(updatedStack);\n };\n\n const contextProperties: ModalContextProperties = {\n stack,\n launchModal,\n updateStack,\n updateState,\n };\n\n return <ModalContext.Provider value={contextProperties}>{children}</ModalContext.Provider>;\n\n};\n\n/**\n * Get properties from the modal context\n * @returns {ModalContextProperties} Object with the modal context properties\n */\nexport function useModalContext(): ModalContextProperties {\n return useContext(ModalContext);\n}\n\n/**\n * Short-hand for `useModalContext().launchModal`\n * @returns {LaunchModal} The launchModal function\n */\nexport function useModal(): LaunchModal {\n const { launchModal } = useModalContext();\n return launchModal;\n}\n\n/**\n * Get access to the current modal state and a function to update it\n * @returns {[ ModalState, UpdateModalState ]} A tuple with the current modal state and a function to update it\n */\nexport function useModalState(): [ ModalState, UpdateModalState ] {\n const { stack, updateState } = useModalContext();\n if (stack.length === 0) \n throw new Error('Trying to access modal state while no modal is open');\n const state = stack[stack.length - 1].state;\n return [ state, updateState ];\n}\n","import { \n type ModalPortProps, \n type ModalStackItem \n} from \"../types\";\nimport { useModalContext } from \"./context\";\nimport { \n type SyntheticEvent, \n useCallback, \n useEffect, \n useMemo\n} from \"react\";\n\nconst ModalPort: React.FC<ModalPortProps> = ({\n onModalLaunch,\n onModalClose,\n render: Backdrop\n}) => {\n\n const { stack } = useModalContext();\n const currentModal: ModalStackItem | null = useMemo(\n () => stack.length > 0 ? stack[stack.length - 1] : null,\n [ stack ]\n );\n const onBackdropClick = useCallback((ev: SyntheticEvent) => {\n if (ev.currentTarget !== ev.target) return;\n currentModal?.resolvers.onBackdropClick &&\n currentModal.resolvers.onBackdropClick(ev);\n }, [ currentModal ]);\n\n useEffect(() => {\n if (currentModal) {\n onModalLaunch && onModalLaunch();\n } else {\n onModalClose && onModalClose();\n }\n }, [ currentModal, onModalLaunch, onModalClose ]);\n\n return currentModal && (\n <Backdrop onBackdropClick={onBackdropClick}>\n {currentModal.render({\n ...currentModal.resolvers,\n ...currentModal.props,\n })}\n </Backdrop>\n ) || null;\n};\n\nexport default ModalPort;\n"],"names":["ModalContext","createContext","stack","launchModal","updateStack","updateState","useModalContext","useContext","_ref","children","_useState","useState","contextProperties","render","resolvers","props","wrappedResovers","Object","keys","reduce","acc","key","resolver","Promise","resolve","apply","slice","call","arguments","then","result","currStack","e","reject","concat","state","newState","updatedStack","length","_extends","_jsx","Provider","value","onModalLaunch","onModalClose","Backdrop","currentModal","useMemo","onBackdropClick","useCallback","ev","currentTarget","target","useEffect","_useModalContext2","Error"],"mappings":"8RAeaA,EAAeC,EAAaA,cAAyB,CAChEC,MAAO,GACPC,YAAa,WAAQ,EACrBC,YAAa,WAAQ,EACrBC,YAAa,WAAK,aAqDJC,IACd,OAAOC,EAAAA,WAAWP,EACpB,8BApDoC,SAAHQ,GAAM,IAAAC,EAAQD,EAARC,SAErCC,EAA+BC,EAAAA,SAA2B,IAAlDT,EAAKQ,EAAEN,GAAAA,EAAWM,EAE1B,GA+BME,EAA4C,CAChDV,MAAAA,EACAC,YAjC+B,SAACU,EAAQC,EAAWC,QAAAA,IAAAA,IAAAA,EAAQ,CAAA,GAE3D,IAAMC,EAAkBC,OAAOC,KAAKJ,GAAWK,OAAO,SAACC,EAAKC,GAC1D,IAAMC,EAAWR,EAAUO,GAO3B,OANAD,EAAIC,kBAAgCE,OAAAA,QAAAC,QACbF,EAAQG,WAAA,EAAA,GAAAC,MAAAC,KADKC,aACIC,KAAhCC,SAAAA,GAGN,OADA1B,EAAY,SAAA2B,UAAaA,EAAUL,MAAM,GAAI,EAAE,GACxCI,CAAO,EAChB,CAAC,MAAAE,GAAA,OAAAT,QAAAU,OAAAD,EACD,CAAA,EAAOZ,CACT,EAAG,IACHhB,KAAW8B,OACNhC,EACH,CAAA,CACEW,OAAAA,EACAC,UAAWE,EACXD,MAAAA,EACAoB,MAAO,CAAA,KAGb,EAaE/B,YAAAA,EACAC,YAZkB,SAAC+B,GACnB,IAAMC,EAAY,GAAAH,OACbhC,GAELmC,EAAanC,EAAMoC,OAAS,GAAGH,MAAKI,KAAQH,GAC5ChC,EAAYiC,EACd,GASA,OAAOG,MAACxC,EAAayC,SAAQ,CAACC,MAAO9B,EAAiBH,SAAGA,GAE3D,oBCtD4C,SAA7BD,GACb,IAAAmC,EAAanC,EAAbmC,cACAC,EAAYpC,EAAZoC,aACQC,EAAQrC,EAAhBK,OAGQX,EAAUI,IAAVJ,MACF4C,EAAsCC,EAAOA,QACjD,kBAAM7C,EAAMoC,OAAS,EAAIpC,EAAMA,EAAMoC,OAAS,GAAK,IAAI,EACvD,CAAEpC,IAEE8C,EAAkBC,cAAY,SAACC,GAC/BA,EAAGC,gBAAkBD,EAAGE,SAChB,MAAZN,OAAY,EAAZA,EAAchC,UAAUkC,kBACxBF,EAAahC,UAAUkC,gBAAgBE,EACzC,EAAG,CAAEJ,IAUL,OARAO,EAASA,UAAC,WACJP,EACFH,GAAiBA,IAEjBC,GAAgBA,GAEpB,EAAG,CAAEE,EAAcH,EAAeC,IAE3BE,GACLN,MAACK,EAAQ,CAACG,gBAAiBA,EAAevC,SACvCqC,EAAajC,OAAM0B,EACfO,CAAAA,EAAAA,EAAahC,UACbgC,EAAa/B,WAGjB,IACP,mBDmCgB,WAEd,OADwBT,IAAhBH,WAEV,kDAMgB,WACd,IAAAmD,EAA+BhD,IAAvBJ,EAAKoD,EAALpD,MAAOG,EAAWiD,EAAXjD,YACf,GAAqB,IAAjBH,EAAMoC,OACR,MAAU,IAAAiB,MAAM,uDAElB,MAAO,CADOrD,EAAMA,EAAMoC,OAAS,GAAGH,MACtB9B,EAClB"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/context.tsx","../src/modal-port.tsx"],"sourcesContent":["import { \n createContext, \n useContext, \n useState, \n useCallback,\n type SyntheticEvent \n} from 'react';\nimport { \n type ModalStackItem,\n type ModalContextProperties,\n type LaunchModal,\n type LaunchModalResolvers,\n type ModalState,\n type UpdateModalState,\n ModalProps,\n} from './types';\n\nexport const ModalContext = createContext<ModalContextProperties | null>(null);\n\nexport const ModalContextProvider = ({ children }: Readonly<{ children: React.ReactNode }>) => {\n\n const [ stack, updateStack ] = useState<ModalStackItem<any>[]>([]);\n\n const launchModal = useCallback(<P extends Record<string, any> = Record<string, any>>(\n render: React.FunctionComponent<ModalProps<P>>, \n resolvers: LaunchModalResolvers,\n props: any = {}\n ) => {\n // Wrap resolvers to update the stack\n const wrappedResovers = Object.keys(resolvers).reduce((acc, key) => {\n const resolver = resolvers[key];\n acc[key] = async (...args: any[]) => {\n const result = await resolver(...args);\n // update stack with an array containing all the items in the stack except the last one\n updateStack(currStack => currStack.slice(0, -1));\n return result;\n };\n return acc;\n }, {} as LaunchModalResolvers);\n\n updateStack(prevStack => [\n ...prevStack,\n {\n render,\n resolvers: wrappedResovers,\n props,\n state: {},\n },\n ]);\n }, []);\n\n const updateState = useCallback((newState: ModalState) => {\n updateStack(prevStack => {\n const updatedStack = [...prevStack];\n if (updatedStack.length > 0) {\n updatedStack[updatedStack.length - 1] = {\n ...updatedStack[updatedStack.length - 1],\n state: { ...newState }\n };\n }\n return updatedStack;\n });\n }, []);\n\n const contextProperties: ModalContextProperties = {\n stack,\n launchModal,\n updateStack,\n updateState,\n };\n\n return <ModalContext.Provider value={contextProperties}>{children}</ModalContext.Provider>;\n\n};\n\n/**\n * Get properties from the modal context\n * @returns {ModalContextProperties} Object with the modal context properties\n */\nexport function useModalContext(): ModalContextProperties {\n const context = useContext(ModalContext);\n if (!context) {\n throw new Error('useModalContext must be used within a ModalContextProvider');\n }\n return context;\n}\n\n/**\n * Short-hand for `useModalContext().launchModal`\n * @returns {LaunchModal} The launchModal function\n */\nexport function useModal() {\n const { launchModal } = useModalContext();\n return launchModal;\n}\n\n/**\n * Get access to the current modal state and a function to update it\n * @returns {[ ModalState | null, UpdateModalState ]} A tuple with the current modal state and a function to update it\n */\nexport function useModalState(): [ ModalState | null, UpdateModalState ] {\n const { stack, updateState } = useModalContext();\n if (stack.length === 0) {\n return [null, updateState];\n }\n const state = stack[stack.length - 1].state;\n return [ state, updateState ];\n}\n","import { \n ModalProps,\n type ModalPortProps, \n type ModalStackItem \n} from \"./types\";\nimport { useModalContext } from \"./context\";\nimport { \n type SyntheticEvent, \n useCallback, \n useEffect, \n useMemo,\n useRef,\n type ReactElement\n} from \"react\";\n\nconst ModalPort: React.FC<ModalPortProps> = ({\n onModalLaunch,\n onModalClose,\n render: Backdrop\n}) => {\n\n const { stack } = useModalContext();\n const currentModal: ModalStackItem<ModalProps> | null = useMemo(\n () => stack.length > 0 ? stack[stack.length - 1] : null,\n [ stack ]\n );\n \n const previousModalRef = useRef<ModalStackItem<ModalProps> | null>(null);\n \n const onBackdropClick = useCallback((ev: SyntheticEvent) => {\n if (ev.currentTarget !== ev.target) return;\n if (currentModal?.resolvers.onBackdropClick) {\n currentModal.resolvers.onBackdropClick(ev);\n }\n }, [ currentModal ]);\n\n useEffect(() => {\n const previousModal = previousModalRef.current;\n \n // Modal was launched (went from no modal to having a modal)\n if (!previousModal && currentModal) {\n onModalLaunch?.();\n }\n // Modal was closed (went from having a modal to no modal)\n else if (previousModal && !currentModal) {\n onModalClose?.();\n }\n \n // Update the ref for next time\n previousModalRef.current = currentModal;\n }, [ currentModal, onModalLaunch, onModalClose ]);\n\n const ModalContent = currentModal?.render;\n\n return (\n <>\n {ModalContent && (\n <Backdrop onBackdropClick={onBackdropClick}>\n <ModalContent\n {...currentModal.resolvers}\n {...currentModal.props}\n />\n </Backdrop>\n ) || null}\n </>\n );\n};\n\nexport default ModalPort;\nexport { ModalPort };\n"],"names":["ModalContext","createContext","useModalContext","context","useContext","Error","_ref","children","_useState","useState","stack","updateStack","launchModal","useCallback","render","resolvers","props","wrappedResovers","Object","keys","reduce","acc","key","resolver","Promise","resolve","apply","slice","call","arguments","then","result","currStack","e","reject","prevStack","concat","state","updateState","newState","updatedStack","length","_extends","_jsx","Provider","value","onModalLaunch","onModalClose","Backdrop","currentModal","useMemo","previousModalRef","useRef","onBackdropClick","ev","currentTarget","target","useEffect","previousModal","current","ModalContent","_Fragment","jsx","_useModalContext2"],"mappings":"kRAiBaA,EAAeC,EAAaA,cAAgC,MA8DzD,SAAAC,IACd,IAAMC,EAAUC,EAAUA,WAACJ,GAC3B,IAAKG,EACH,MAAU,IAAAE,MAAM,8DAElB,OAAOF,CACT,8BAlEoC,SAAHG,GAA6D,IAAvDC,EAAQD,EAARC,SAErCC,EAA+BC,EAAQA,SAAwB,IAAvDC,EAAKF,EAAA,GAAEG,EAAWH,EAE1B,GAAMI,EAAcC,EAAAA,YAAY,SAC9BC,EACAC,EACAC,QAAAA,IAAAA,IAAAA,EAAa,IAGb,IAAMC,EAAkBC,OAAOC,KAAKJ,GAAWK,OAAO,SAACC,EAAKC,GAC1D,IAAMC,EAAWR,EAAUO,GAO3B,OANAD,EAAIC,GAAI,WAAA,IAA4B,OAAAE,QAAAC,QACbF,EAAQG,WAAAC,EAAAA,GAAAA,MAAAC,KADKC,aACIC,KAAhCC,SAAAA,GAGN,OADApB,EAAY,SAAAqB,GAAa,OAAAA,EAAUL,MAAM,GAAI,EAAE,GACxCI,CAAO,EAChB,CAAC,MAAAE,UAAAT,QAAAU,OAAAD,EAAA,CAAA,EACMZ,CACT,EAAG,CAAA,GAEHV,EAAY,SAAAwB,GAAS,MAAA,GAAAC,OAChBD,EACH,CAAA,CACErB,OAAAA,EACAC,UAAWE,EACXD,MAAAA,EACAqB,MAAO,CAAA,IAEV,EACH,EAAG,IAEGC,EAAczB,cAAY,SAAC0B,GAC/B5B,EAAY,SAAAwB,GACV,IAAMK,EAAYJ,GAAAA,OAAOD,GAOzB,OANIK,EAAaC,OAAS,IACxBD,EAAaA,EAAaC,OAAS,GAAEC,EAChCF,CAAAA,EAAAA,EAAaA,EAAaC,OAAS,GACtCJ,CAAAA,MAAKK,KAAOH,MAGTC,CACT,EACF,EAAG,IASH,OAAOG,EAAAA,IAAC3C,EAAa4C,SAAQ,CAACC,MAPoB,CAChDnC,MAAAA,EACAE,YAAAA,EACAD,YAAAA,EACA2B,YAAAA,GAGoD/B,SAAGA,GAE3D,oBC1D4C,SAA7BD,GACb,IAAAwC,EAAaxC,EAAbwC,cACAC,EAAYzC,EAAZyC,aACQC,EAAQ1C,EAAhBQ,OAGQJ,EAAUR,IAAVQ,MACFuC,EAAkDC,EAAAA,QACtD,WAAA,OAAMxC,EAAM+B,OAAS,EAAI/B,EAAMA,EAAM+B,OAAS,GAAK,IAAI,EACvD,CAAE/B,IAGEyC,EAAmBC,SAA0C,MAE7DC,EAAkBxC,EAAAA,YAAY,SAACyC,GAC/BA,EAAGC,gBAAkBD,EAAGE,cACxBP,GAAAA,EAAclC,UAAUsC,iBAC1BJ,EAAalC,UAAUsC,gBAAgBC,EAE3C,EAAG,CAAEL,IAELQ,EAAAA,UAAU,WACR,IAAMC,EAAgBP,EAAiBQ,SAGlCD,GAAiBT,EACP,MAAbH,GAAAA,IAGOY,IAAkBT,IACzBF,MAAAA,GAAAA,KAIFI,EAAiBQ,QAAUV,CAC7B,EAAG,CAAEA,EAAcH,EAAeC,IAElC,IAAMa,EAAeX,MAAAA,OAAAA,EAAAA,EAAcnC,OAEnC,OACE6B,EAAAA,IAAAkB,EAAAA,SAAA,CAAAtD,SACGqD,GACCjB,EAAAmB,IAACd,EAAQ,CAACK,gBAAiBA,EAAe9C,SACxCoC,EAACmB,IAAAF,EAAYlB,EACPO,CAAAA,EAAAA,EAAalC,UACbkC,EAAajC,WAGlB,MAGX,8BD2BE,OADwBd,IAAhBU,WAEV,6DAOE,IAAAmD,EAA+B7D,IAAvBQ,EAAKqD,EAALrD,MAAO4B,EAAWyB,EAAXzB,YACf,OAAqB,IAAjB5B,EAAM+B,OACD,CAAC,KAAMH,GAGT,CADO5B,EAAMA,EAAM+B,OAAS,GAAGJ,MACtBC,EAClB"}
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import{jsx as n}from"react/jsx-runtime";import{createContext as r,useState as t,useContext as e,useMemo as o,useCallback as a,useEffect as c}from"react";function u(){return u=Object.assign?Object.assign.bind():function(n){for(var r=1;r<arguments.length;r++){var t=arguments[r];for(var e in t)Object.prototype.hasOwnProperty.call(t,e)&&(n[e]=t[e])}return n},u.apply(this,arguments)}var i=r({stack:[],launchModal:function(){},updateStack:function(){},updateState:function(){}}),l=function(r){var e=r.children,o=t([]),a=o[0],c=o[1],l={stack:a,launchModal:function(n,r,t){void 0===t&&(t={});var e=Object.keys(r).reduce(function(n,t){var e=r[t];return n[t]=function(){try{return Promise.resolve(e.apply(void 0,[].slice.call(arguments))).then(function(n){return c(function(n){return n.slice(0,-1)}),n})}catch(n){return Promise.reject(n)}},n},{});c([].concat(a,[{render:n,resolvers:e,props:t,state:{}}]))},updateStack:c,updateState:function(n){var r=[].concat(a);r[a.length-1].state=u({},n),c(r)}};return n(i.Provider,{value:l,children:e})};function s(){return e(i)}function d(){return s().launchModal}function f(){var n=s(),r=n.stack,t=n.updateState;if(0===r.length)throw new Error("Trying to access modal state while no modal is open");return[r[r.length-1].state,t]}var p=function(r){var t=r.onModalLaunch,e=r.onModalClose,i=r.render,l=s().stack,d=o(function(){return l.length>0?l[l.length-1]:null},[l]),f=a(function(n){n.currentTarget===n.target&&(null==d?void 0:d.resolvers.onBackdropClick)&&d.resolvers.onBackdropClick(n)},[d]);return c(function(){d?t&&t():e&&e()},[d,t,e]),d&&n(i,{onBackdropClick:f,children:d.render(u({},d.resolvers,d.props))})||null};export{l as ModalContextProvider,p as ModalPort,d as useModal,s as useModalContext,f as useModalState};
1
+ import{jsx as r,Fragment as n}from"react/jsx-runtime";import{createContext as t,useState as e,useCallback as o,useContext as l,useMemo as u,useRef as c,useEffect as a}from"react";function i(){return i=Object.assign?Object.assign.bind():function(r){for(var n=1;n<arguments.length;n++){var t=arguments[n];for(var e in t)({}).hasOwnProperty.call(t,e)&&(r[e]=t[e])}return r},i.apply(null,arguments)}var s=t(null),d=function(n){var t=n.children,l=e([]),u=l[0],c=l[1],a=o(function(r,n,t){void 0===t&&(t={});var e=Object.keys(n).reduce(function(r,t){var e=n[t];return r[t]=function(){try{return Promise.resolve(e.apply(void 0,[].slice.call(arguments))).then(function(r){return c(function(r){return r.slice(0,-1)}),r})}catch(r){return Promise.reject(r)}},r},{});c(function(n){return[].concat(n,[{render:r,resolvers:e,props:t,state:{}}])})},[]),d=o(function(r){c(function(n){var t=[].concat(n);return t.length>0&&(t[t.length-1]=i({},t[t.length-1],{state:i({},r)})),t})},[]);return r(s.Provider,{value:{stack:u,launchModal:a,updateStack:c,updateState:d},children:t})};function v(){var r=l(s);if(!r)throw new Error("useModalContext must be used within a ModalContextProvider");return r}function f(){return v().launchModal}function h(){var r=v(),n=r.stack,t=r.updateState;return 0===n.length?[null,t]:[n[n.length-1].state,t]}var p=function(t){var e=t.onModalLaunch,l=t.onModalClose,s=t.render,d=v().stack,f=u(function(){return d.length>0?d[d.length-1]:null},[d]),h=c(null),p=o(function(r){r.currentTarget===r.target&&null!=f&&f.resolvers.onBackdropClick&&f.resolvers.onBackdropClick(r)},[f]);a(function(){var r=h.current;!r&&f?null==e||e():r&&!f&&(null==l||l()),h.current=f},[f,e,l]);var g=null==f?void 0:f.render;return r(n,{children:g&&r(s,{onBackdropClick:p,children:r(g,i({},f.resolvers,f.props))})||null})};export{d as ModalContextProvider,p as ModalPort,f as useModal,v as useModalContext,h as useModalState};
2
2
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../src/context.tsx","../src/modal-port.tsx"],"sourcesContent":["import { \n createContext, \n useContext, \n useState, \n type SyntheticEvent \n} from 'react';\nimport { \n type ModalStackItem,\n type ModalContextProperties,\n type LaunchModal,\n type LaunchModalResolvers,\n type ModalState,\n type UpdateModalState,\n} from '../types';\n\nexport const ModalContext = createContext<ModalContextProperties>({\n stack: [],\n launchModal: () => {},\n updateStack: () => {},\n updateState: () => {},\n});\n\nexport const ModalContextProvider = ({ children }: Readonly<{ children: React.ReactNode }>) => {\n\n const [ stack, updateStack ] = useState<ModalStackItem[]>([]);\n\n const launchModal: LaunchModal = (render, resolvers, props = {}) => {\n // Wrap resolvers to update the stack\n const wrappedResovers = Object.keys(resolvers).reduce((acc, key) => {\n const resolver = resolvers[key];\n acc[key] = async (...args: any[]) => {\n const result = await resolver(...args);\n // update stack with an array conating all the items in the stack except the last one\n updateStack(currStack => currStack.slice(0, -1));\n return result;\n };\n return acc;\n }, {} as LaunchModalResolvers);\n updateStack([\n ...stack,\n {\n render,\n resolvers: wrappedResovers,\n props,\n state: {},\n },\n ]);\n };\n\n const updateState = (newState: ModalState) => {\n const updatedStack = [\n ...stack,\n ];\n updatedStack[stack.length - 1].state = { ...newState };\n updateStack(updatedStack);\n };\n\n const contextProperties: ModalContextProperties = {\n stack,\n launchModal,\n updateStack,\n updateState,\n };\n\n return <ModalContext.Provider value={contextProperties}>{children}</ModalContext.Provider>;\n\n};\n\n/**\n * Get properties from the modal context\n * @returns {ModalContextProperties} Object with the modal context properties\n */\nexport function useModalContext(): ModalContextProperties {\n return useContext(ModalContext);\n}\n\n/**\n * Short-hand for `useModalContext().launchModal`\n * @returns {LaunchModal} The launchModal function\n */\nexport function useModal(): LaunchModal {\n const { launchModal } = useModalContext();\n return launchModal;\n}\n\n/**\n * Get access to the current modal state and a function to update it\n * @returns {[ ModalState, UpdateModalState ]} A tuple with the current modal state and a function to update it\n */\nexport function useModalState(): [ ModalState, UpdateModalState ] {\n const { stack, updateState } = useModalContext();\n if (stack.length === 0) \n throw new Error('Trying to access modal state while no modal is open');\n const state = stack[stack.length - 1].state;\n return [ state, updateState ];\n}\n","import { \n type ModalPortProps, \n type ModalStackItem \n} from \"../types\";\nimport { useModalContext } from \"./context\";\nimport { \n type SyntheticEvent, \n useCallback, \n useEffect, \n useMemo\n} from \"react\";\n\nconst ModalPort: React.FC<ModalPortProps> = ({\n onModalLaunch,\n onModalClose,\n render: Backdrop\n}) => {\n\n const { stack } = useModalContext();\n const currentModal: ModalStackItem | null = useMemo(\n () => stack.length > 0 ? stack[stack.length - 1] : null,\n [ stack ]\n );\n const onBackdropClick = useCallback((ev: SyntheticEvent) => {\n if (ev.currentTarget !== ev.target) return;\n currentModal?.resolvers.onBackdropClick &&\n currentModal.resolvers.onBackdropClick(ev);\n }, [ currentModal ]);\n\n useEffect(() => {\n if (currentModal) {\n onModalLaunch && onModalLaunch();\n } else {\n onModalClose && onModalClose();\n }\n }, [ currentModal, onModalLaunch, onModalClose ]);\n\n return currentModal && (\n <Backdrop onBackdropClick={onBackdropClick}>\n {currentModal.render({\n ...currentModal.resolvers,\n ...currentModal.props,\n })}\n </Backdrop>\n ) || null;\n};\n\nexport default ModalPort;\n"],"names":["ModalContext","createContext","stack","launchModal","updateStack","updateState","ModalContextProvider","_ref","children","_useState","useState","contextProperties","render","resolvers","props","wrappedResovers","Object","keys","reduce","acc","key","resolver","Promise","resolve","apply","slice","call","arguments","then","result","currStack","e","reject","concat","state","newState","updatedStack","length","_extends","_jsx","Provider","value","useModalContext","useContext","useModal","useModalState","_useModalContext2","Error","ModalPort","onModalLaunch","onModalClose","Backdrop","currentModal","useMemo","onBackdropClick","useCallback","ev","currentTarget","target","useEffect"],"mappings":"iYAeaA,EAAeC,EAAsC,CAChEC,MAAO,GACPC,YAAa,WAAQ,EACrBC,YAAa,WAAQ,EACrBC,YAAa,WAAK,IAGPC,EAAuB,SAAHC,GAAM,IAAAC,EAAQD,EAARC,SAErCC,EAA+BC,EAA2B,IAAlDR,EAAKO,EAAEL,GAAAA,EAAWK,EAE1B,GA+BME,EAA4C,CAChDT,MAAAA,EACAC,YAjC+B,SAACS,EAAQC,EAAWC,QAAAA,IAAAA,IAAAA,EAAQ,CAAA,GAE3D,IAAMC,EAAkBC,OAAOC,KAAKJ,GAAWK,OAAO,SAACC,EAAKC,GAC1D,IAAMC,EAAWR,EAAUO,GAO3B,OANAD,EAAIC,kBAAgCE,OAAAA,QAAAC,QACbF,EAAQG,WAAA,EAAA,GAAAC,MAAAC,KADKC,aACIC,KAAhCC,SAAAA,GAGN,OADAzB,EAAY,SAAA0B,UAAaA,EAAUL,MAAM,GAAI,EAAE,GACxCI,CAAO,EAChB,CAAC,MAAAE,GAAA,OAAAT,QAAAU,OAAAD,EACD,CAAA,EAAOZ,CACT,EAAG,IACHf,KAAW6B,OACN/B,EACH,CAAA,CACEU,OAAAA,EACAC,UAAWE,EACXD,MAAAA,EACAoB,MAAO,CAAA,KAGb,EAaE9B,YAAAA,EACAC,YAZkB,SAAC8B,GACnB,IAAMC,EAAY,GAAAH,OACb/B,GAELkC,EAAalC,EAAMmC,OAAS,GAAGH,MAAKI,KAAQH,GAC5C/B,EAAYgC,EACd,GASA,OAAOG,EAACvC,EAAawC,SAAQ,CAACC,MAAO9B,EAAiBH,SAAGA,GAE3D,WAMgBkC,IACd,OAAOC,EAAW3C,EACpB,CAMgB,SAAA4C,IAEd,OADwBF,IAAhBvC,WAEV,CAMgB,SAAA0C,IACd,IAAAC,EAA+BJ,IAAvBxC,EAAK4C,EAAL5C,MAAOG,EAAWyC,EAAXzC,YACf,GAAqB,IAAjBH,EAAMmC,OACR,MAAU,IAAAU,MAAM,uDAElB,MAAO,CADO7C,EAAMA,EAAMmC,OAAS,GAAGH,MACtB7B,EAClB,CCnFM,IAAA2C,EAAsC,SAA7BzC,GACb,IAAA0C,EAAa1C,EAAb0C,cACAC,EAAY3C,EAAZ2C,aACQC,EAAQ5C,EAAhBK,OAGQV,EAAUwC,IAAVxC,MACFkD,EAAsCC,EAC1C,kBAAMnD,EAAMmC,OAAS,EAAInC,EAAMA,EAAMmC,OAAS,GAAK,IAAI,EACvD,CAAEnC,IAEEoD,EAAkBC,EAAY,SAACC,GAC/BA,EAAGC,gBAAkBD,EAAGE,SAChB,MAAZN,OAAY,EAAZA,EAAcvC,UAAUyC,kBACxBF,EAAavC,UAAUyC,gBAAgBE,EACzC,EAAG,CAAEJ,IAUL,OARAO,EAAU,WACJP,EACFH,GAAiBA,IAEjBC,GAAgBA,GAEpB,EAAG,CAAEE,EAAcH,EAAeC,IAE3BE,GACLb,EAACY,EAAQ,CAACG,gBAAiBA,EAAe9C,SACvC4C,EAAaxC,OAAM0B,EACfc,CAAAA,EAAAA,EAAavC,UACbuC,EAAatC,WAGjB,IACP"}
1
+ {"version":3,"file":"index.mjs","sources":["../src/context.tsx","../src/modal-port.tsx"],"sourcesContent":["import { \n createContext, \n useContext, \n useState, \n useCallback,\n type SyntheticEvent \n} from 'react';\nimport { \n type ModalStackItem,\n type ModalContextProperties,\n type LaunchModal,\n type LaunchModalResolvers,\n type ModalState,\n type UpdateModalState,\n ModalProps,\n} from './types';\n\nexport const ModalContext = createContext<ModalContextProperties | null>(null);\n\nexport const ModalContextProvider = ({ children }: Readonly<{ children: React.ReactNode }>) => {\n\n const [ stack, updateStack ] = useState<ModalStackItem<any>[]>([]);\n\n const launchModal = useCallback(<P extends Record<string, any> = Record<string, any>>(\n render: React.FunctionComponent<ModalProps<P>>, \n resolvers: LaunchModalResolvers,\n props: any = {}\n ) => {\n // Wrap resolvers to update the stack\n const wrappedResovers = Object.keys(resolvers).reduce((acc, key) => {\n const resolver = resolvers[key];\n acc[key] = async (...args: any[]) => {\n const result = await resolver(...args);\n // update stack with an array containing all the items in the stack except the last one\n updateStack(currStack => currStack.slice(0, -1));\n return result;\n };\n return acc;\n }, {} as LaunchModalResolvers);\n\n updateStack(prevStack => [\n ...prevStack,\n {\n render,\n resolvers: wrappedResovers,\n props,\n state: {},\n },\n ]);\n }, []);\n\n const updateState = useCallback((newState: ModalState) => {\n updateStack(prevStack => {\n const updatedStack = [...prevStack];\n if (updatedStack.length > 0) {\n updatedStack[updatedStack.length - 1] = {\n ...updatedStack[updatedStack.length - 1],\n state: { ...newState }\n };\n }\n return updatedStack;\n });\n }, []);\n\n const contextProperties: ModalContextProperties = {\n stack,\n launchModal,\n updateStack,\n updateState,\n };\n\n return <ModalContext.Provider value={contextProperties}>{children}</ModalContext.Provider>;\n\n};\n\n/**\n * Get properties from the modal context\n * @returns {ModalContextProperties} Object with the modal context properties\n */\nexport function useModalContext(): ModalContextProperties {\n const context = useContext(ModalContext);\n if (!context) {\n throw new Error('useModalContext must be used within a ModalContextProvider');\n }\n return context;\n}\n\n/**\n * Short-hand for `useModalContext().launchModal`\n * @returns {LaunchModal} The launchModal function\n */\nexport function useModal() {\n const { launchModal } = useModalContext();\n return launchModal;\n}\n\n/**\n * Get access to the current modal state and a function to update it\n * @returns {[ ModalState | null, UpdateModalState ]} A tuple with the current modal state and a function to update it\n */\nexport function useModalState(): [ ModalState | null, UpdateModalState ] {\n const { stack, updateState } = useModalContext();\n if (stack.length === 0) {\n return [null, updateState];\n }\n const state = stack[stack.length - 1].state;\n return [ state, updateState ];\n}\n","import { \n ModalProps,\n type ModalPortProps, \n type ModalStackItem \n} from \"./types\";\nimport { useModalContext } from \"./context\";\nimport { \n type SyntheticEvent, \n useCallback, \n useEffect, \n useMemo,\n useRef,\n type ReactElement\n} from \"react\";\n\nconst ModalPort: React.FC<ModalPortProps> = ({\n onModalLaunch,\n onModalClose,\n render: Backdrop\n}) => {\n\n const { stack } = useModalContext();\n const currentModal: ModalStackItem<ModalProps> | null = useMemo(\n () => stack.length > 0 ? stack[stack.length - 1] : null,\n [ stack ]\n );\n \n const previousModalRef = useRef<ModalStackItem<ModalProps> | null>(null);\n \n const onBackdropClick = useCallback((ev: SyntheticEvent) => {\n if (ev.currentTarget !== ev.target) return;\n if (currentModal?.resolvers.onBackdropClick) {\n currentModal.resolvers.onBackdropClick(ev);\n }\n }, [ currentModal ]);\n\n useEffect(() => {\n const previousModal = previousModalRef.current;\n \n // Modal was launched (went from no modal to having a modal)\n if (!previousModal && currentModal) {\n onModalLaunch?.();\n }\n // Modal was closed (went from having a modal to no modal)\n else if (previousModal && !currentModal) {\n onModalClose?.();\n }\n \n // Update the ref for next time\n previousModalRef.current = currentModal;\n }, [ currentModal, onModalLaunch, onModalClose ]);\n\n const ModalContent = currentModal?.render;\n\n return (\n <>\n {ModalContent && (\n <Backdrop onBackdropClick={onBackdropClick}>\n <ModalContent\n {...currentModal.resolvers}\n {...currentModal.props}\n />\n </Backdrop>\n ) || null}\n </>\n );\n};\n\nexport default ModalPort;\nexport { ModalPort };\n"],"names":["ModalContext","createContext","ModalContextProvider","_ref","children","_useState","useState","stack","updateStack","launchModal","useCallback","render","resolvers","props","wrappedResovers","Object","keys","reduce","acc","key","resolver","Promise","resolve","apply","slice","call","arguments","then","result","currStack","e","reject","prevStack","concat","state","updateState","newState","updatedStack","length","_extends","_jsx","Provider","value","useModalContext","context","useContext","Error","useModal","useModalState","_useModalContext2","ModalPort","onModalLaunch","onModalClose","Backdrop","currentModal","useMemo","previousModalRef","useRef","onBackdropClick","ev","currentTarget","target","useEffect","previousModal","current","ModalContent","_Fragment"],"mappings":"+YAiBaA,EAAeC,EAA6C,MAE5DC,EAAuB,SAAHC,GAA6D,IAAvDC,EAAQD,EAARC,SAErCC,EAA+BC,EAAgC,IAAvDC,EAAKF,EAAA,GAAEG,EAAWH,EAE1B,GAAMI,EAAcC,EAAY,SAC9BC,EACAC,EACAC,QAAAA,IAAAA,IAAAA,EAAa,IAGb,IAAMC,EAAkBC,OAAOC,KAAKJ,GAAWK,OAAO,SAACC,EAAKC,GAC1D,IAAMC,EAAWR,EAAUO,GAO3B,OANAD,EAAIC,GAAI,WAAA,IAA4B,OAAAE,QAAAC,QACbF,EAAQG,WAAAC,EAAAA,GAAAA,MAAAC,KADKC,aACIC,KAAhCC,SAAAA,GAGN,OADApB,EAAY,SAAAqB,GAAa,OAAAA,EAAUL,MAAM,GAAI,EAAE,GACxCI,CAAO,EAChB,CAAC,MAAAE,UAAAT,QAAAU,OAAAD,EAAA,CAAA,EACMZ,CACT,EAAG,CAAA,GAEHV,EAAY,SAAAwB,GAAS,MAAA,GAAAC,OAChBD,EACH,CAAA,CACErB,OAAAA,EACAC,UAAWE,EACXD,MAAAA,EACAqB,MAAO,CAAA,IAEV,EACH,EAAG,IAEGC,EAAczB,EAAY,SAAC0B,GAC/B5B,EAAY,SAAAwB,GACV,IAAMK,EAAYJ,GAAAA,OAAOD,GAOzB,OANIK,EAAaC,OAAS,IACxBD,EAAaA,EAAaC,OAAS,GAAEC,EAChCF,CAAAA,EAAAA,EAAaA,EAAaC,OAAS,GACtCJ,CAAAA,MAAKK,KAAOH,MAGTC,CACT,EACF,EAAG,IASH,OAAOG,EAACxC,EAAayC,SAAQ,CAACC,MAPoB,CAChDnC,MAAAA,EACAE,YAAAA,EACAD,YAAAA,EACA2B,YAAAA,GAGoD/B,SAAGA,GAE3D,EAMgB,SAAAuC,IACd,IAAMC,EAAUC,EAAW7C,GAC3B,IAAK4C,EACH,MAAU,IAAAE,MAAM,8DAElB,OAAOF,CACT,UAMgBG,IAEd,OADwBJ,IAAhBlC,WAEV,UAMgBuC,IACd,IAAAC,EAA+BN,IAAvBpC,EAAK0C,EAAL1C,MAAO4B,EAAWc,EAAXd,YACf,OAAqB,IAAjB5B,EAAM+B,OACD,CAAC,KAAMH,GAGT,CADO5B,EAAMA,EAAM+B,OAAS,GAAGJ,MACtBC,EAClB,CC5FM,IAAAe,EAAsC,SAA7B/C,GACb,IAAAgD,EAAahD,EAAbgD,cACAC,EAAYjD,EAAZiD,aACQC,EAAQlD,EAAhBQ,OAGQJ,EAAUoC,IAAVpC,MACF+C,EAAkDC,EACtD,WAAA,OAAMhD,EAAM+B,OAAS,EAAI/B,EAAMA,EAAM+B,OAAS,GAAK,IAAI,EACvD,CAAE/B,IAGEiD,EAAmBC,EAA0C,MAE7DC,EAAkBhD,EAAY,SAACiD,GAC/BA,EAAGC,gBAAkBD,EAAGE,cACxBP,GAAAA,EAAc1C,UAAU8C,iBAC1BJ,EAAa1C,UAAU8C,gBAAgBC,EAE3C,EAAG,CAAEL,IAELQ,EAAU,WACR,IAAMC,EAAgBP,EAAiBQ,SAGlCD,GAAiBT,EACP,MAAbH,GAAAA,IAGOY,IAAkBT,IACzBF,MAAAA,GAAAA,KAIFI,EAAiBQ,QAAUV,CAC7B,EAAG,CAAEA,EAAcH,EAAeC,IAElC,IAAMa,EAAeX,MAAAA,OAAAA,EAAAA,EAAc3C,OAEnC,OACE6B,EAAA0B,EAAA,CAAA9D,SACG6D,GACCzB,EAACa,EAAQ,CAACK,gBAAiBA,EAAetD,SACxCoC,EAACyB,EAAY1B,EACPe,CAAAA,EAAAA,EAAa1C,UACb0C,EAAazC,WAGlB,MAGX"}
@@ -1,2 +1,2 @@
1
- import{jsx as t}from"react/jsx-runtime";import{createContext as e,useState as r,useContext as n,useMemo as o,useCallback as a,useEffect as c}from"react";function s(){return s=Object.assign?Object.assign.bind():function(t){for(var e=1;e<arguments.length;e++){var r=arguments[e];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(t[n]=r[n])}return t},s.apply(this,arguments)}const l=e({stack:[],launchModal:()=>{},updateStack:()=>{},updateState:()=>{}}),u=({children:e})=>{const[n,o]=r([]);return t(l.Provider,{value:{stack:n,launchModal:(t,e,r={})=>{const a=Object.keys(e).reduce((t,r)=>{const n=e[r];return t[r]=async(...t)=>{const e=await n(...t);return o(t=>t.slice(0,-1)),e},t},{});o([...n,{render:t,resolvers:a,props:r,state:{}}])},updateStack:o,updateState:t=>{const e=[...n];e[n.length-1].state=s({},t),o(e)}},children:e})};function i(){return n(l)}function d(){const{launchModal:t}=i();return t}function p(){const{stack:t,updateState:e}=i();if(0===t.length)throw new Error("Trying to access modal state while no modal is open");return[t[t.length-1].state,e]}const h=({onModalLaunch:e,onModalClose:r,render:n})=>{const{stack:l}=i(),u=o(()=>l.length>0?l[l.length-1]:null,[l]),d=a(t=>{t.currentTarget===t.target&&(null==u?void 0:u.resolvers.onBackdropClick)&&u.resolvers.onBackdropClick(t)},[u]);return c(()=>{u?e&&e():r&&r()},[u,e,r]),u&&t(n,{onBackdropClick:d,children:u.render(s({},u.resolvers,u.props))})||null};export{u as ModalContextProvider,h as ModalPort,d as useModal,i as useModalContext,p as useModalState};
1
+ import{jsx as n,Fragment as t}from"react/jsx-runtime";import{createContext as r,useState as e,useCallback as o,useContext as l,useMemo as c,useRef as s,useEffect as a}from"react";function u(){return u=Object.assign?Object.assign.bind():function(n){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var e in r)({}).hasOwnProperty.call(r,e)&&(n[e]=r[e])}return n},u.apply(null,arguments)}const i=r(null),d=({children:t})=>{const[r,l]=e([]),c=o((n,t,r={})=>{const e=Object.keys(t).reduce((n,r)=>{const e=t[r];return n[r]=async(...n)=>{const t=await e(...n);return l(n=>n.slice(0,-1)),t},n},{});l(t=>[...t,{render:n,resolvers:e,props:r,state:{}}])},[]),s=o(n=>{l(t=>{const r=[...t];return r.length>0&&(r[r.length-1]=u({},r[r.length-1],{state:u({},n)})),r})},[]);return n(i.Provider,{value:{stack:r,launchModal:c,updateStack:l,updateState:s},children:t})};function h(){const n=l(i);if(!n)throw new Error("useModalContext must be used within a ModalContextProvider");return n}function p(){const{launchModal:n}=h();return n}function g(){const{stack:n,updateState:t}=h();return 0===n.length?[null,t]:[n[n.length-1].state,t]}const k=({onModalLaunch:r,onModalClose:e,render:l})=>{const{stack:i}=h(),d=c(()=>i.length>0?i[i.length-1]:null,[i]),p=s(null),g=o(n=>{n.currentTarget===n.target&&null!=d&&d.resolvers.onBackdropClick&&d.resolvers.onBackdropClick(n)},[d]);a(()=>{const n=p.current;!n&&d?null==r||r():n&&!d&&(null==e||e()),p.current=d},[d,r,e]);const k=null==d?void 0:d.render;return n(t,{children:k&&n(l,{onBackdropClick:g,children:n(k,u({},d.resolvers,d.props))})||null})};export{d as ModalContextProvider,k as ModalPort,p as useModal,h as useModalContext,g as useModalState};
2
2
  //# sourceMappingURL=index.modern.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.modern.mjs","sources":["../src/context.tsx","../src/modal-port.tsx"],"sourcesContent":["import { \n createContext, \n useContext, \n useState, \n type SyntheticEvent \n} from 'react';\nimport { \n type ModalStackItem,\n type ModalContextProperties,\n type LaunchModal,\n type LaunchModalResolvers,\n type ModalState,\n type UpdateModalState,\n} from '../types';\n\nexport const ModalContext = createContext<ModalContextProperties>({\n stack: [],\n launchModal: () => {},\n updateStack: () => {},\n updateState: () => {},\n});\n\nexport const ModalContextProvider = ({ children }: Readonly<{ children: React.ReactNode }>) => {\n\n const [ stack, updateStack ] = useState<ModalStackItem[]>([]);\n\n const launchModal: LaunchModal = (render, resolvers, props = {}) => {\n // Wrap resolvers to update the stack\n const wrappedResovers = Object.keys(resolvers).reduce((acc, key) => {\n const resolver = resolvers[key];\n acc[key] = async (...args: any[]) => {\n const result = await resolver(...args);\n // update stack with an array conating all the items in the stack except the last one\n updateStack(currStack => currStack.slice(0, -1));\n return result;\n };\n return acc;\n }, {} as LaunchModalResolvers);\n updateStack([\n ...stack,\n {\n render,\n resolvers: wrappedResovers,\n props,\n state: {},\n },\n ]);\n };\n\n const updateState = (newState: ModalState) => {\n const updatedStack = [\n ...stack,\n ];\n updatedStack[stack.length - 1].state = { ...newState };\n updateStack(updatedStack);\n };\n\n const contextProperties: ModalContextProperties = {\n stack,\n launchModal,\n updateStack,\n updateState,\n };\n\n return <ModalContext.Provider value={contextProperties}>{children}</ModalContext.Provider>;\n\n};\n\n/**\n * Get properties from the modal context\n * @returns {ModalContextProperties} Object with the modal context properties\n */\nexport function useModalContext(): ModalContextProperties {\n return useContext(ModalContext);\n}\n\n/**\n * Short-hand for `useModalContext().launchModal`\n * @returns {LaunchModal} The launchModal function\n */\nexport function useModal(): LaunchModal {\n const { launchModal } = useModalContext();\n return launchModal;\n}\n\n/**\n * Get access to the current modal state and a function to update it\n * @returns {[ ModalState, UpdateModalState ]} A tuple with the current modal state and a function to update it\n */\nexport function useModalState(): [ ModalState, UpdateModalState ] {\n const { stack, updateState } = useModalContext();\n if (stack.length === 0) \n throw new Error('Trying to access modal state while no modal is open');\n const state = stack[stack.length - 1].state;\n return [ state, updateState ];\n}\n","import { \n type ModalPortProps, \n type ModalStackItem \n} from \"../types\";\nimport { useModalContext } from \"./context\";\nimport { \n type SyntheticEvent, \n useCallback, \n useEffect, \n useMemo\n} from \"react\";\n\nconst ModalPort: React.FC<ModalPortProps> = ({\n onModalLaunch,\n onModalClose,\n render: Backdrop\n}) => {\n\n const { stack } = useModalContext();\n const currentModal: ModalStackItem | null = useMemo(\n () => stack.length > 0 ? stack[stack.length - 1] : null,\n [ stack ]\n );\n const onBackdropClick = useCallback((ev: SyntheticEvent) => {\n if (ev.currentTarget !== ev.target) return;\n currentModal?.resolvers.onBackdropClick &&\n currentModal.resolvers.onBackdropClick(ev);\n }, [ currentModal ]);\n\n useEffect(() => {\n if (currentModal) {\n onModalLaunch && onModalLaunch();\n } else {\n onModalClose && onModalClose();\n }\n }, [ currentModal, onModalLaunch, onModalClose ]);\n\n return currentModal && (\n <Backdrop onBackdropClick={onBackdropClick}>\n {currentModal.render({\n ...currentModal.resolvers,\n ...currentModal.props,\n })}\n </Backdrop>\n ) || null;\n};\n\nexport default ModalPort;\n"],"names":["ModalContext","createContext","stack","launchModal","updateStack","updateState","ModalContextProvider","children","useState","_jsx","Provider","value","render","resolvers","props","wrappedResovers","Object","keys","reduce","acc","key","resolver","async","args","result","currStack","slice","state","newState","updatedStack","length","_extends","useModalContext","useContext","useModal","useModalState","Error","ModalPort","onModalLaunch","onModalClose","Backdrop","currentModal","useMemo","onBackdropClick","useCallback","ev","currentTarget","target","useEffect"],"mappings":"mYAeaA,EAAeC,EAAsC,CAChEC,MAAO,GACPC,YAAaA,OACbC,YAAaA,OACbC,YAAaA,SAGFC,EAAuBA,EAAGC,eAErC,MAAQL,EAAOE,GAAgBI,EAA2B,IAwC1D,OAAOC,EAACT,EAAaU,SAAQ,CAACC,MAPoB,CAChDT,QACAC,YAjC+BA,CAACS,EAAQC,EAAWC,EAAQ,CAAA,KAE3D,MAAMC,EAAkBC,OAAOC,KAAKJ,GAAWK,OAAO,CAACC,EAAKC,KAC1D,MAAMC,EAAWR,EAAUO,GAO3B,OANAD,EAAIC,GAAOE,SAAUC,KACnB,MAAMC,QAAeH,KAAYE,GAGjC,OADAnB,EAAYqB,GAAaA,EAAUC,MAAM,GAAI,IACtCF,GAEFL,GACN,CAA0B,GAC7Bf,EAAY,IACPF,EACH,CACEU,SACAC,UAAWE,EACXD,QACAa,MAAO,CAAA,IAGb,EAaEvB,cACAC,YAZmBuB,IACnB,MAAMC,EAAe,IAChB3B,GAEL2B,EAAa3B,EAAM4B,OAAS,GAAGH,MAAKI,EAAA,GAAQH,GAC5CxB,EAAYyB,EAAY,GAU4BtB,SAAGA,GAAQ,WAQnDyB,IACd,OAAOC,EAAWjC,EACpB,UAMgBkC,IACd,MAAM/B,YAAEA,GAAgB6B,IACxB,OAAO7B,CACT,UAMgBgC,IACd,MAAMjC,MAAEA,EAAKG,YAAEA,GAAgB2B,IAC/B,GAAqB,IAAjB9B,EAAM4B,OACR,UAAUM,MAAM,uDAElB,MAAO,CADOlC,EAAMA,EAAM4B,OAAS,GAAGH,MACtBtB,EAClB,CCnFM,MAAAgC,EAAsCA,EAC1CC,gBACAC,eACA3B,OAAQ4B,MAGR,MAAMtC,MAAEA,GAAU8B,IACZS,EAAsCC,EAC1C,IAAMxC,EAAM4B,OAAS,EAAI5B,EAAMA,EAAM4B,OAAS,GAAK,KACnD,CAAE5B,IAEEyC,EAAkBC,EAAaC,IAC/BA,EAAGC,gBAAkBD,EAAGE,SAChB,MAAZN,OAAY,EAAZA,EAAc5B,UAAU8B,kBACxBF,EAAa5B,UAAU8B,gBAAgBE,EACzC,EAAG,CAAEJ,IAUL,OARAO,EAAU,KACJP,EACFH,GAAiBA,IAEjBC,GAAgBA,GAClB,EACC,CAAEE,EAAcH,EAAeC,IAE3BE,GACLhC,EAAC+B,EAAQ,CAACG,gBAAiBA,EAAepC,SACvCkC,EAAa7B,OAAMmB,EAAA,CAAA,EACfU,EAAa5B,UACb4B,EAAa3B,WAGjB"}
1
+ {"version":3,"file":"index.modern.mjs","sources":["../src/context.tsx","../src/modal-port.tsx"],"sourcesContent":["import { \n createContext, \n useContext, \n useState, \n useCallback,\n type SyntheticEvent \n} from 'react';\nimport { \n type ModalStackItem,\n type ModalContextProperties,\n type LaunchModal,\n type LaunchModalResolvers,\n type ModalState,\n type UpdateModalState,\n ModalProps,\n} from './types';\n\nexport const ModalContext = createContext<ModalContextProperties | null>(null);\n\nexport const ModalContextProvider = ({ children }: Readonly<{ children: React.ReactNode }>) => {\n\n const [ stack, updateStack ] = useState<ModalStackItem<any>[]>([]);\n\n const launchModal = useCallback(<P extends Record<string, any> = Record<string, any>>(\n render: React.FunctionComponent<ModalProps<P>>, \n resolvers: LaunchModalResolvers,\n props: any = {}\n ) => {\n // Wrap resolvers to update the stack\n const wrappedResovers = Object.keys(resolvers).reduce((acc, key) => {\n const resolver = resolvers[key];\n acc[key] = async (...args: any[]) => {\n const result = await resolver(...args);\n // update stack with an array containing all the items in the stack except the last one\n updateStack(currStack => currStack.slice(0, -1));\n return result;\n };\n return acc;\n }, {} as LaunchModalResolvers);\n\n updateStack(prevStack => [\n ...prevStack,\n {\n render,\n resolvers: wrappedResovers,\n props,\n state: {},\n },\n ]);\n }, []);\n\n const updateState = useCallback((newState: ModalState) => {\n updateStack(prevStack => {\n const updatedStack = [...prevStack];\n if (updatedStack.length > 0) {\n updatedStack[updatedStack.length - 1] = {\n ...updatedStack[updatedStack.length - 1],\n state: { ...newState }\n };\n }\n return updatedStack;\n });\n }, []);\n\n const contextProperties: ModalContextProperties = {\n stack,\n launchModal,\n updateStack,\n updateState,\n };\n\n return <ModalContext.Provider value={contextProperties}>{children}</ModalContext.Provider>;\n\n};\n\n/**\n * Get properties from the modal context\n * @returns {ModalContextProperties} Object with the modal context properties\n */\nexport function useModalContext(): ModalContextProperties {\n const context = useContext(ModalContext);\n if (!context) {\n throw new Error('useModalContext must be used within a ModalContextProvider');\n }\n return context;\n}\n\n/**\n * Short-hand for `useModalContext().launchModal`\n * @returns {LaunchModal} The launchModal function\n */\nexport function useModal() {\n const { launchModal } = useModalContext();\n return launchModal;\n}\n\n/**\n * Get access to the current modal state and a function to update it\n * @returns {[ ModalState | null, UpdateModalState ]} A tuple with the current modal state and a function to update it\n */\nexport function useModalState(): [ ModalState | null, UpdateModalState ] {\n const { stack, updateState } = useModalContext();\n if (stack.length === 0) {\n return [null, updateState];\n }\n const state = stack[stack.length - 1].state;\n return [ state, updateState ];\n}\n","import { \n ModalProps,\n type ModalPortProps, \n type ModalStackItem \n} from \"./types\";\nimport { useModalContext } from \"./context\";\nimport { \n type SyntheticEvent, \n useCallback, \n useEffect, \n useMemo,\n useRef,\n type ReactElement\n} from \"react\";\n\nconst ModalPort: React.FC<ModalPortProps> = ({\n onModalLaunch,\n onModalClose,\n render: Backdrop\n}) => {\n\n const { stack } = useModalContext();\n const currentModal: ModalStackItem<ModalProps> | null = useMemo(\n () => stack.length > 0 ? stack[stack.length - 1] : null,\n [ stack ]\n );\n \n const previousModalRef = useRef<ModalStackItem<ModalProps> | null>(null);\n \n const onBackdropClick = useCallback((ev: SyntheticEvent) => {\n if (ev.currentTarget !== ev.target) return;\n if (currentModal?.resolvers.onBackdropClick) {\n currentModal.resolvers.onBackdropClick(ev);\n }\n }, [ currentModal ]);\n\n useEffect(() => {\n const previousModal = previousModalRef.current;\n \n // Modal was launched (went from no modal to having a modal)\n if (!previousModal && currentModal) {\n onModalLaunch?.();\n }\n // Modal was closed (went from having a modal to no modal)\n else if (previousModal && !currentModal) {\n onModalClose?.();\n }\n \n // Update the ref for next time\n previousModalRef.current = currentModal;\n }, [ currentModal, onModalLaunch, onModalClose ]);\n\n const ModalContent = currentModal?.render;\n\n return (\n <>\n {ModalContent && (\n <Backdrop onBackdropClick={onBackdropClick}>\n <ModalContent\n {...currentModal.resolvers}\n {...currentModal.props}\n />\n </Backdrop>\n ) || null}\n </>\n );\n};\n\nexport default ModalPort;\nexport { ModalPort };\n"],"names":["ModalContext","createContext","ModalContextProvider","children","stack","updateStack","useState","launchModal","useCallback","render","resolvers","props","wrappedResovers","Object","keys","reduce","acc","key","resolver","async","args","result","currStack","slice","prevStack","state","updateState","newState","updatedStack","length","_extends","_jsx","Provider","value","useModalContext","context","useContext","Error","useModal","useModalState","ModalPort","onModalLaunch","onModalClose","Backdrop","currentModal","useMemo","previousModalRef","useRef","onBackdropClick","ev","currentTarget","target","useEffect","previousModal","current","ModalContent","_Fragment"],"mappings":"iZAiBaA,EAAeC,EAA6C,MAE5DC,EAAuBA,EAAGC,eAErC,MAAQC,EAAOC,GAAgBC,EAAgC,IAEzDC,EAAcC,EAAY,CAC9BC,EACAC,EACAC,EAAa,CAAE,KAGf,MAAMC,EAAkBC,OAAOC,KAAKJ,GAAWK,OAAO,CAACC,EAAKC,KAC1D,MAAMC,EAAWR,EAAUO,GAO3B,OANAD,EAAIC,GAAOE,SAAUC,KACnB,MAAMC,QAAeH,KAAYE,GAGjC,OADAf,EAAYiB,GAAaA,EAAUC,MAAM,GAAI,IACtCF,GAEFL,GACN,CAA0B,GAE7BX,EAAYmB,GAAa,IACpBA,EACH,CACEf,SACAC,UAAWE,EACXD,QACAc,MAAO,CAAA,MAGV,IAEGC,EAAclB,EAAamB,IAC/BtB,EAAYmB,IACV,MAAMI,EAAe,IAAIJ,GAOzB,OANII,EAAaC,OAAS,IACxBD,EAAaA,EAAaC,OAAS,GAAEC,EAChCF,GAAAA,EAAaA,EAAaC,OAAS,GACtCJ,CAAAA,MAAKK,EAAA,CAAA,EAAOH,MAGTC,GACR,EACA,IASH,OAAOG,EAAC/B,EAAagC,SAAQ,CAACC,MAPoB,CAChD7B,QACAG,cACAF,cACAqB,eAGoDvB,SAAGA,GAAQ,EAQnD,SAAA+B,IACd,MAAMC,EAAUC,EAAWpC,GAC3B,IAAKmC,EACH,UAAUE,MAAM,8DAElB,OAAOF,CACT,UAMgBG,IACd,MAAM/B,YAAEA,GAAgB2B,IACxB,OAAO3B,CACT,UAMgBgC,IACd,MAAMnC,MAAEA,EAAKsB,YAAEA,GAAgBQ,IAC/B,OAAqB,IAAjB9B,EAAMyB,OACD,CAAC,KAAMH,GAGT,CADOtB,EAAMA,EAAMyB,OAAS,GAAGJ,MACtBC,EAClB,CC5FM,MAAAc,EAAsCA,EAC1CC,gBACAC,eACAjC,OAAQkC,MAGR,MAAMvC,MAAEA,GAAU8B,IACZU,EAAkDC,EACtD,IAAMzC,EAAMyB,OAAS,EAAIzB,EAAMA,EAAMyB,OAAS,GAAK,KACnD,CAAEzB,IAGE0C,EAAmBC,EAA0C,MAE7DC,EAAkBxC,EAAayC,IAC/BA,EAAGC,gBAAkBD,EAAGE,QACZ,MAAZP,GAAAA,EAAclC,UAAUsC,iBAC1BJ,EAAalC,UAAUsC,gBAAgBC,EACzC,EACC,CAAEL,IAELQ,EAAU,KACR,MAAMC,EAAgBP,EAAiBQ,SAGlCD,GAAiBT,EACP,MAAbH,GAAAA,IAGOY,IAAkBT,IACb,MAAZF,GAAAA,KAIFI,EAAiBQ,QAAUV,CAAAA,EAC1B,CAAEA,EAAcH,EAAeC,IAElC,MAAMa,EAA2B,MAAZX,OAAY,EAAZA,EAAcnC,OAEnC,OACEsB,EAAAyB,EAAA,CAAArD,SACGoD,GACCxB,EAACY,EAAQ,CAACK,gBAAiBA,EAAe7C,SACxC4B,EAACwB,EAAYzB,EAAA,CAAA,EACPc,EAAalC,UACbkC,EAAajC,WAGlB,MAAI"}
package/dist/index.umd.js CHANGED
@@ -1,2 +1,2 @@
1
- !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("react/jsx-runtime"),require("react")):"function"==typeof define&&define.amd?define(["exports","react/jsx-runtime","react"],t):t((e||self).reactModalPort={},e.jsx,e.react)}(this,function(e,t,n){function r(){return r=Object.assign?Object.assign.bind():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},r.apply(this,arguments)}var o=n.createContext({stack:[],launchModal:function(){},updateStack:function(){},updateState:function(){}});function a(){return n.useContext(o)}e.ModalContextProvider=function(e){var a=e.children,c=n.useState([]),u=c[0],i=c[1],l={stack:u,launchModal:function(e,t,n){void 0===n&&(n={});var r=Object.keys(t).reduce(function(e,n){var r=t[n];return e[n]=function(){try{return Promise.resolve(r.apply(void 0,[].slice.call(arguments))).then(function(e){return i(function(e){return e.slice(0,-1)}),e})}catch(e){return Promise.reject(e)}},e},{});i([].concat(u,[{render:e,resolvers:r,props:n,state:{}}]))},updateStack:i,updateState:function(e){var t=[].concat(u);t[u.length-1].state=r({},e),i(t)}};return t.jsx(o.Provider,{value:l,children:a})},e.ModalPort=function(e){var o=e.onModalLaunch,c=e.onModalClose,u=e.render,i=a().stack,l=n.useMemo(function(){return i.length>0?i[i.length-1]:null},[i]),s=n.useCallback(function(e){e.currentTarget===e.target&&(null==l?void 0:l.resolvers.onBackdropClick)&&l.resolvers.onBackdropClick(e)},[l]);return n.useEffect(function(){l?o&&o():c&&c()},[l,o,c]),l&&t.jsx(u,{onBackdropClick:s,children:l.render(r({},l.resolvers,l.props))})||null},e.useModal=function(){return a().launchModal},e.useModalContext=a,e.useModalState=function(){var e=a(),t=e.stack,n=e.updateState;if(0===t.length)throw new Error("Trying to access modal state while no modal is open");return[t[t.length-1].state,n]}});
1
+ !function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("react/jsx-runtime"),require("react")):"function"==typeof define&&define.amd?define(["exports","react/jsx-runtime","react"],n):n((e||self).reactModalPort={},e.jsx,e.react)}(this,function(e,n,t){function r(){return r=Object.assign?Object.assign.bind():function(e){for(var n=1;n<arguments.length;n++){var t=arguments[n];for(var r in t)({}).hasOwnProperty.call(t,r)&&(e[r]=t[r])}return e},r.apply(null,arguments)}var o=t.createContext(null);function u(){var e=t.useContext(o);if(!e)throw new Error("useModalContext must be used within a ModalContextProvider");return e}e.ModalContextProvider=function(e){var u=e.children,a=t.useState([]),l=a[0],c=a[1],i=t.useCallback(function(e,n,t){void 0===t&&(t={});var r=Object.keys(n).reduce(function(e,t){var r=n[t];return e[t]=function(){try{return Promise.resolve(r.apply(void 0,[].slice.call(arguments))).then(function(e){return c(function(e){return e.slice(0,-1)}),e})}catch(e){return Promise.reject(e)}},e},{});c(function(n){return[].concat(n,[{render:e,resolvers:r,props:t,state:{}}])})},[]),s=t.useCallback(function(e){c(function(n){var t=[].concat(n);return t.length>0&&(t[t.length-1]=r({},t[t.length-1],{state:r({},e)})),t})},[]);return n.jsx(o.Provider,{value:{stack:l,launchModal:i,updateStack:c,updateState:s},children:u})},e.ModalPort=function(e){var o=e.onModalLaunch,a=e.onModalClose,l=e.render,c=u().stack,i=t.useMemo(function(){return c.length>0?c[c.length-1]:null},[c]),s=t.useRef(null),d=t.useCallback(function(e){e.currentTarget===e.target&&null!=i&&i.resolvers.onBackdropClick&&i.resolvers.onBackdropClick(e)},[i]);t.useEffect(function(){var e=s.current;!e&&i?null==o||o():e&&!i&&(null==a||a()),s.current=i},[i,o,a]);var f=null==i?void 0:i.render;return n.jsx(n.Fragment,{children:f&&n.jsx(l,{onBackdropClick:d,children:n.jsx(f,r({},i.resolvers,i.props))})||null})},e.useModal=function(){return u().launchModal},e.useModalContext=u,e.useModalState=function(){var e=u(),n=e.stack,t=e.updateState;return 0===n.length?[null,t]:[n[n.length-1].state,t]}});
2
2
  //# sourceMappingURL=index.umd.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.umd.js","sources":["../src/context.tsx","../src/modal-port.tsx"],"sourcesContent":["import { \n createContext, \n useContext, \n useState, \n type SyntheticEvent \n} from 'react';\nimport { \n type ModalStackItem,\n type ModalContextProperties,\n type LaunchModal,\n type LaunchModalResolvers,\n type ModalState,\n type UpdateModalState,\n} from '../types';\n\nexport const ModalContext = createContext<ModalContextProperties>({\n stack: [],\n launchModal: () => {},\n updateStack: () => {},\n updateState: () => {},\n});\n\nexport const ModalContextProvider = ({ children }: Readonly<{ children: React.ReactNode }>) => {\n\n const [ stack, updateStack ] = useState<ModalStackItem[]>([]);\n\n const launchModal: LaunchModal = (render, resolvers, props = {}) => {\n // Wrap resolvers to update the stack\n const wrappedResovers = Object.keys(resolvers).reduce((acc, key) => {\n const resolver = resolvers[key];\n acc[key] = async (...args: any[]) => {\n const result = await resolver(...args);\n // update stack with an array conating all the items in the stack except the last one\n updateStack(currStack => currStack.slice(0, -1));\n return result;\n };\n return acc;\n }, {} as LaunchModalResolvers);\n updateStack([\n ...stack,\n {\n render,\n resolvers: wrappedResovers,\n props,\n state: {},\n },\n ]);\n };\n\n const updateState = (newState: ModalState) => {\n const updatedStack = [\n ...stack,\n ];\n updatedStack[stack.length - 1].state = { ...newState };\n updateStack(updatedStack);\n };\n\n const contextProperties: ModalContextProperties = {\n stack,\n launchModal,\n updateStack,\n updateState,\n };\n\n return <ModalContext.Provider value={contextProperties}>{children}</ModalContext.Provider>;\n\n};\n\n/**\n * Get properties from the modal context\n * @returns {ModalContextProperties} Object with the modal context properties\n */\nexport function useModalContext(): ModalContextProperties {\n return useContext(ModalContext);\n}\n\n/**\n * Short-hand for `useModalContext().launchModal`\n * @returns {LaunchModal} The launchModal function\n */\nexport function useModal(): LaunchModal {\n const { launchModal } = useModalContext();\n return launchModal;\n}\n\n/**\n * Get access to the current modal state and a function to update it\n * @returns {[ ModalState, UpdateModalState ]} A tuple with the current modal state and a function to update it\n */\nexport function useModalState(): [ ModalState, UpdateModalState ] {\n const { stack, updateState } = useModalContext();\n if (stack.length === 0) \n throw new Error('Trying to access modal state while no modal is open');\n const state = stack[stack.length - 1].state;\n return [ state, updateState ];\n}\n","import { \n type ModalPortProps, \n type ModalStackItem \n} from \"../types\";\nimport { useModalContext } from \"./context\";\nimport { \n type SyntheticEvent, \n useCallback, \n useEffect, \n useMemo\n} from \"react\";\n\nconst ModalPort: React.FC<ModalPortProps> = ({\n onModalLaunch,\n onModalClose,\n render: Backdrop\n}) => {\n\n const { stack } = useModalContext();\n const currentModal: ModalStackItem | null = useMemo(\n () => stack.length > 0 ? stack[stack.length - 1] : null,\n [ stack ]\n );\n const onBackdropClick = useCallback((ev: SyntheticEvent) => {\n if (ev.currentTarget !== ev.target) return;\n currentModal?.resolvers.onBackdropClick &&\n currentModal.resolvers.onBackdropClick(ev);\n }, [ currentModal ]);\n\n useEffect(() => {\n if (currentModal) {\n onModalLaunch && onModalLaunch();\n } else {\n onModalClose && onModalClose();\n }\n }, [ currentModal, onModalLaunch, onModalClose ]);\n\n return currentModal && (\n <Backdrop onBackdropClick={onBackdropClick}>\n {currentModal.render({\n ...currentModal.resolvers,\n ...currentModal.props,\n })}\n </Backdrop>\n ) || null;\n};\n\nexport default ModalPort;\n"],"names":["ModalContext","createContext","stack","launchModal","updateStack","updateState","useModalContext","useContext","_ref","children","_useState","useState","contextProperties","render","resolvers","props","wrappedResovers","Object","keys","reduce","acc","key","resolver","Promise","resolve","apply","slice","call","arguments","then","result","currStack","e","reject","concat","state","newState","updatedStack","length","_extends","_jsx","Provider","value","onModalLaunch","onModalClose","Backdrop","currentModal","useMemo","onBackdropClick","useCallback","ev","currentTarget","target","useEffect","_useModalContext2","Error"],"mappings":"4iBAeaA,EAAeC,EAAaA,cAAyB,CAChEC,MAAO,GACPC,YAAa,WAAQ,EACrBC,YAAa,WAAQ,EACrBC,YAAa,WAAK,aAqDJC,IACd,OAAOC,EAAAA,WAAWP,EACpB,wBApDoC,SAAHQ,GAAM,IAAAC,EAAQD,EAARC,SAErCC,EAA+BC,EAAAA,SAA2B,IAAlDT,EAAKQ,EAAEN,GAAAA,EAAWM,EAE1B,GA+BME,EAA4C,CAChDV,MAAAA,EACAC,YAjC+B,SAACU,EAAQC,EAAWC,QAAAA,IAAAA,IAAAA,EAAQ,CAAA,GAE3D,IAAMC,EAAkBC,OAAOC,KAAKJ,GAAWK,OAAO,SAACC,EAAKC,GAC1D,IAAMC,EAAWR,EAAUO,GAO3B,OANAD,EAAIC,kBAAgCE,OAAAA,QAAAC,QACbF,EAAQG,WAAA,EAAA,GAAAC,MAAAC,KADKC,aACIC,KAAhCC,SAAAA,GAGN,OADA1B,EAAY,SAAA2B,UAAaA,EAAUL,MAAM,GAAI,EAAE,GACxCI,CAAO,EAChB,CAAC,MAAAE,GAAA,OAAAT,QAAAU,OAAAD,EACD,CAAA,EAAOZ,CACT,EAAG,IACHhB,KAAW8B,OACNhC,EACH,CAAA,CACEW,OAAAA,EACAC,UAAWE,EACXD,MAAAA,EACAoB,MAAO,CAAA,KAGb,EAaE/B,YAAAA,EACAC,YAZkB,SAAC+B,GACnB,IAAMC,EAAY,GAAAH,OACbhC,GAELmC,EAAanC,EAAMoC,OAAS,GAAGH,MAAKI,KAAQH,GAC5ChC,EAAYiC,EACd,GASA,OAAOG,MAACxC,EAAayC,SAAQ,CAACC,MAAO9B,EAAiBH,SAAGA,GAE3D,cCtD4C,SAA7BD,GACb,IAAAmC,EAAanC,EAAbmC,cACAC,EAAYpC,EAAZoC,aACQC,EAAQrC,EAAhBK,OAGQX,EAAUI,IAAVJ,MACF4C,EAAsCC,EAAOA,QACjD,kBAAM7C,EAAMoC,OAAS,EAAIpC,EAAMA,EAAMoC,OAAS,GAAK,IAAI,EACvD,CAAEpC,IAEE8C,EAAkBC,cAAY,SAACC,GAC/BA,EAAGC,gBAAkBD,EAAGE,SAChB,MAAZN,OAAY,EAAZA,EAAchC,UAAUkC,kBACxBF,EAAahC,UAAUkC,gBAAgBE,EACzC,EAAG,CAAEJ,IAUL,OARAO,EAASA,UAAC,WACJP,EACFH,GAAiBA,IAEjBC,GAAgBA,GAEpB,EAAG,CAAEE,EAAcH,EAAeC,IAE3BE,GACLN,MAACK,EAAQ,CAACG,gBAAiBA,EAAevC,SACvCqC,EAAajC,OAAM0B,EACfO,CAAAA,EAAAA,EAAahC,UACbgC,EAAa/B,WAGjB,IACP,aDmCgB,WAEd,OADwBT,IAAhBH,WAEV,sCAMgB,WACd,IAAAmD,EAA+BhD,IAAvBJ,EAAKoD,EAALpD,MAAOG,EAAWiD,EAAXjD,YACf,GAAqB,IAAjBH,EAAMoC,OACR,MAAU,IAAAiB,MAAM,uDAElB,MAAO,CADOrD,EAAMA,EAAMoC,OAAS,GAAGH,MACtB9B,EAClB"}
1
+ {"version":3,"file":"index.umd.js","sources":["../src/context.tsx","../src/modal-port.tsx"],"sourcesContent":["import { \n createContext, \n useContext, \n useState, \n useCallback,\n type SyntheticEvent \n} from 'react';\nimport { \n type ModalStackItem,\n type ModalContextProperties,\n type LaunchModal,\n type LaunchModalResolvers,\n type ModalState,\n type UpdateModalState,\n ModalProps,\n} from './types';\n\nexport const ModalContext = createContext<ModalContextProperties | null>(null);\n\nexport const ModalContextProvider = ({ children }: Readonly<{ children: React.ReactNode }>) => {\n\n const [ stack, updateStack ] = useState<ModalStackItem<any>[]>([]);\n\n const launchModal = useCallback(<P extends Record<string, any> = Record<string, any>>(\n render: React.FunctionComponent<ModalProps<P>>, \n resolvers: LaunchModalResolvers,\n props: any = {}\n ) => {\n // Wrap resolvers to update the stack\n const wrappedResovers = Object.keys(resolvers).reduce((acc, key) => {\n const resolver = resolvers[key];\n acc[key] = async (...args: any[]) => {\n const result = await resolver(...args);\n // update stack with an array containing all the items in the stack except the last one\n updateStack(currStack => currStack.slice(0, -1));\n return result;\n };\n return acc;\n }, {} as LaunchModalResolvers);\n\n updateStack(prevStack => [\n ...prevStack,\n {\n render,\n resolvers: wrappedResovers,\n props,\n state: {},\n },\n ]);\n }, []);\n\n const updateState = useCallback((newState: ModalState) => {\n updateStack(prevStack => {\n const updatedStack = [...prevStack];\n if (updatedStack.length > 0) {\n updatedStack[updatedStack.length - 1] = {\n ...updatedStack[updatedStack.length - 1],\n state: { ...newState }\n };\n }\n return updatedStack;\n });\n }, []);\n\n const contextProperties: ModalContextProperties = {\n stack,\n launchModal,\n updateStack,\n updateState,\n };\n\n return <ModalContext.Provider value={contextProperties}>{children}</ModalContext.Provider>;\n\n};\n\n/**\n * Get properties from the modal context\n * @returns {ModalContextProperties} Object with the modal context properties\n */\nexport function useModalContext(): ModalContextProperties {\n const context = useContext(ModalContext);\n if (!context) {\n throw new Error('useModalContext must be used within a ModalContextProvider');\n }\n return context;\n}\n\n/**\n * Short-hand for `useModalContext().launchModal`\n * @returns {LaunchModal} The launchModal function\n */\nexport function useModal() {\n const { launchModal } = useModalContext();\n return launchModal;\n}\n\n/**\n * Get access to the current modal state and a function to update it\n * @returns {[ ModalState | null, UpdateModalState ]} A tuple with the current modal state and a function to update it\n */\nexport function useModalState(): [ ModalState | null, UpdateModalState ] {\n const { stack, updateState } = useModalContext();\n if (stack.length === 0) {\n return [null, updateState];\n }\n const state = stack[stack.length - 1].state;\n return [ state, updateState ];\n}\n","import { \n ModalProps,\n type ModalPortProps, \n type ModalStackItem \n} from \"./types\";\nimport { useModalContext } from \"./context\";\nimport { \n type SyntheticEvent, \n useCallback, \n useEffect, \n useMemo,\n useRef,\n type ReactElement\n} from \"react\";\n\nconst ModalPort: React.FC<ModalPortProps> = ({\n onModalLaunch,\n onModalClose,\n render: Backdrop\n}) => {\n\n const { stack } = useModalContext();\n const currentModal: ModalStackItem<ModalProps> | null = useMemo(\n () => stack.length > 0 ? stack[stack.length - 1] : null,\n [ stack ]\n );\n \n const previousModalRef = useRef<ModalStackItem<ModalProps> | null>(null);\n \n const onBackdropClick = useCallback((ev: SyntheticEvent) => {\n if (ev.currentTarget !== ev.target) return;\n if (currentModal?.resolvers.onBackdropClick) {\n currentModal.resolvers.onBackdropClick(ev);\n }\n }, [ currentModal ]);\n\n useEffect(() => {\n const previousModal = previousModalRef.current;\n \n // Modal was launched (went from no modal to having a modal)\n if (!previousModal && currentModal) {\n onModalLaunch?.();\n }\n // Modal was closed (went from having a modal to no modal)\n else if (previousModal && !currentModal) {\n onModalClose?.();\n }\n \n // Update the ref for next time\n previousModalRef.current = currentModal;\n }, [ currentModal, onModalLaunch, onModalClose ]);\n\n const ModalContent = currentModal?.render;\n\n return (\n <>\n {ModalContent && (\n <Backdrop onBackdropClick={onBackdropClick}>\n <ModalContent\n {...currentModal.resolvers}\n {...currentModal.props}\n />\n </Backdrop>\n ) || null}\n </>\n );\n};\n\nexport default ModalPort;\nexport { ModalPort };\n"],"names":["ModalContext","createContext","useModalContext","context","useContext","Error","_ref","children","_useState","useState","stack","updateStack","launchModal","useCallback","render","resolvers","props","wrappedResovers","Object","keys","reduce","acc","key","resolver","Promise","resolve","apply","slice","call","arguments","then","result","currStack","e","reject","prevStack","concat","state","updateState","newState","updatedStack","length","_extends","_jsx","Provider","value","onModalLaunch","onModalClose","Backdrop","currentModal","useMemo","previousModalRef","useRef","onBackdropClick","ev","currentTarget","target","useEffect","previousModal","current","ModalContent","_Fragment","jsx","_useModalContext2"],"mappings":"giBAiBaA,EAAeC,EAAaA,cAAgC,MA8DzD,SAAAC,IACd,IAAMC,EAAUC,EAAUA,WAACJ,GAC3B,IAAKG,EACH,MAAU,IAAAE,MAAM,8DAElB,OAAOF,CACT,wBAlEoC,SAAHG,GAA6D,IAAvDC,EAAQD,EAARC,SAErCC,EAA+BC,EAAQA,SAAwB,IAAvDC,EAAKF,EAAA,GAAEG,EAAWH,EAE1B,GAAMI,EAAcC,EAAAA,YAAY,SAC9BC,EACAC,EACAC,QAAAA,IAAAA,IAAAA,EAAa,IAGb,IAAMC,EAAkBC,OAAOC,KAAKJ,GAAWK,OAAO,SAACC,EAAKC,GAC1D,IAAMC,EAAWR,EAAUO,GAO3B,OANAD,EAAIC,GAAI,WAAA,IAA4B,OAAAE,QAAAC,QACbF,EAAQG,WAAAC,EAAAA,GAAAA,MAAAC,KADKC,aACIC,KAAhCC,SAAAA,GAGN,OADApB,EAAY,SAAAqB,GAAa,OAAAA,EAAUL,MAAM,GAAI,EAAE,GACxCI,CAAO,EAChB,CAAC,MAAAE,UAAAT,QAAAU,OAAAD,EAAA,CAAA,EACMZ,CACT,EAAG,CAAA,GAEHV,EAAY,SAAAwB,GAAS,MAAA,GAAAC,OAChBD,EACH,CAAA,CACErB,OAAAA,EACAC,UAAWE,EACXD,MAAAA,EACAqB,MAAO,CAAA,IAEV,EACH,EAAG,IAEGC,EAAczB,cAAY,SAAC0B,GAC/B5B,EAAY,SAAAwB,GACV,IAAMK,EAAYJ,GAAAA,OAAOD,GAOzB,OANIK,EAAaC,OAAS,IACxBD,EAAaA,EAAaC,OAAS,GAAEC,EAChCF,CAAAA,EAAAA,EAAaA,EAAaC,OAAS,GACtCJ,CAAAA,MAAKK,KAAOH,MAGTC,CACT,EACF,EAAG,IASH,OAAOG,EAAAA,IAAC3C,EAAa4C,SAAQ,CAACC,MAPoB,CAChDnC,MAAAA,EACAE,YAAAA,EACAD,YAAAA,EACA2B,YAAAA,GAGoD/B,SAAGA,GAE3D,cC1D4C,SAA7BD,GACb,IAAAwC,EAAaxC,EAAbwC,cACAC,EAAYzC,EAAZyC,aACQC,EAAQ1C,EAAhBQ,OAGQJ,EAAUR,IAAVQ,MACFuC,EAAkDC,EAAAA,QACtD,WAAA,OAAMxC,EAAM+B,OAAS,EAAI/B,EAAMA,EAAM+B,OAAS,GAAK,IAAI,EACvD,CAAE/B,IAGEyC,EAAmBC,SAA0C,MAE7DC,EAAkBxC,EAAAA,YAAY,SAACyC,GAC/BA,EAAGC,gBAAkBD,EAAGE,cACxBP,GAAAA,EAAclC,UAAUsC,iBAC1BJ,EAAalC,UAAUsC,gBAAgBC,EAE3C,EAAG,CAAEL,IAELQ,EAAAA,UAAU,WACR,IAAMC,EAAgBP,EAAiBQ,SAGlCD,GAAiBT,EACP,MAAbH,GAAAA,IAGOY,IAAkBT,IACzBF,MAAAA,GAAAA,KAIFI,EAAiBQ,QAAUV,CAC7B,EAAG,CAAEA,EAAcH,EAAeC,IAElC,IAAMa,EAAeX,MAAAA,OAAAA,EAAAA,EAAcnC,OAEnC,OACE6B,EAAAA,IAAAkB,EAAAA,SAAA,CAAAtD,SACGqD,GACCjB,EAAAmB,IAACd,EAAQ,CAACK,gBAAiBA,EAAe9C,SACxCoC,EAACmB,IAAAF,EAAYlB,EACPO,CAAAA,EAAAA,EAAalC,UACbkC,EAAajC,WAGlB,MAGX,wBD2BE,OADwBd,IAAhBU,WAEV,iDAOE,IAAAmD,EAA+B7D,IAAvBQ,EAAKqD,EAALrD,MAAO4B,EAAWyB,EAAXzB,YACf,OAAqB,IAAjB5B,EAAM+B,OACD,CAAC,KAAMH,GAGT,CADO5B,EAAMA,EAAM+B,OAAS,GAAGJ,MACtBC,EAClB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-modal-port",
3
- "version": "0.2.3",
3
+ "version": "0.3.0",
4
4
  "description": "Launch modals from any React component.",
5
5
  "type": "module",
6
6
  "source": "src/index.ts",
@@ -25,7 +25,9 @@
25
25
  "build:cjs": "microbundle -o dist/index.cjs --format cjs --globals react/jsx-runtime=jsx",
26
26
  "build:umd": "microbundle -o dist/index.umd.js --format umd --globals react/jsx-runtime=jsx",
27
27
  "prepare": "npm run build",
28
- "test": "echo \"Error: no test specified\" && exit 1"
28
+ "test": "jest",
29
+ "test:watch": "jest --watch",
30
+ "test:coverage": "jest --coverage"
29
31
  },
30
32
  "repository": {
31
33
  "type": "git",
@@ -50,16 +52,23 @@
50
52
  "homepage": "https://github.com/oliverwehn/react-modal-port#readme",
51
53
  "dependencies": {},
52
54
  "devDependencies": {
53
- "react": "^18",
54
- "react-dom": "^18",
55
- "@types/react": "^18",
56
- "@types/react-dom": "^18.2.19",
55
+ "react": "^19.0.0",
56
+ "react-dom": "^19.0.0",
57
+ "@types/react": "^19.0.0",
58
+ "@types/react-dom": "^19.0.0",
59
+ "@types/jest": "^29.5.14",
57
60
  "microbundle": "^0.15.1",
58
- "typescript": "^5.3.3"
61
+ "typescript": "^5.7.2",
62
+ "jest": "^29.7.0",
63
+ "jest-environment-jsdom": "^29.7.0",
64
+ "ts-jest": "^29.2.5",
65
+ "@testing-library/react": "^16.3.0",
66
+ "@testing-library/jest-dom": "^6.6.3",
67
+ "@testing-library/user-event": "^14.5.2"
59
68
  },
60
69
  "peerDependencies": {
61
- "@types/react": "^18",
62
- "react": "^18",
63
- "react-dom": "^18"
70
+ "@types/react": "^19.0.0",
71
+ "react": "^19.0.0",
72
+ "react-dom": "^19.0.0"
64
73
  }
65
74
  }
package/readme.md CHANGED
@@ -5,13 +5,14 @@ This small but neat package allows you to:
5
5
  * Launch modals flexibly from anywhere in your React app.
6
6
  * Have them render at one specific place in your DOM.
7
7
 
8
- **Demo:** https://codepen.io/oliverwehn/pen/YzMyoBr
8
+ **Demo:** https://codepen.io/oliverwehn/pen/YzMyoBr?editors=0010
9
9
 
10
10
  ---
11
11
  - [Installation](#-installation)
12
12
  - [Components](#-components)
13
13
  - [ModalContextProvider](#modalcontextprovider)
14
14
  - [ModalPort](#modalport)
15
+ - [Usage Example](#usage-example)
15
16
  - [Launching Modals](#-launching-modals)
16
17
  - [Stacking Modals And Handling Modal State](#-stacking-modals-and-handling-modal-state)
17
18
  ---
@@ -30,11 +31,13 @@ The `ModalContextProvider` wraps your app to allow your app’s components to la
30
31
 
31
32
  ### ModalPort
32
33
 
33
- The `ModalPort` handles the rendering of your modals. It leaves the *how* you want to render your modals fully up to you. It simply requires a `React.FunctionComponent` to be passed to it via its `render` prop. This component allows you to wrap any rendered modal in, for example, a backdrop component.
34
+ The `ModalPort` defines the outlet in your app through which your modals will be rendered. It requires one prop, `render`, that expects a `React.FunctionComponent`. Any modal you’ll launch will be rendered as the child of the component passed via the prop. Typically, this component will provide a backdrop the modal is rendered on top.
34
35
 
35
- Besides `children` a prop `onBackdropClick` is passed to `render`. It holds, if provided to the modal on launch, the click handler function that should be called if the backdrop is clicked, e.g. to dismiss the modal.
36
+ Besides `children`, a prop `onBackdropClick` is passed to `render`. It holds, if provided to the modal on launch, the click handler function that should be called if the backdrop is clicked, e.g. to dismiss the modal.
36
37
 
38
+ The `ModalPort` accepts two addtional optional props `onModalLauch` and `onModalClose` that both expect a function. The provided functions will be called in the event of a modal being launched or, respectively, a modal being closed.
37
39
 
40
+ ### Usage Example
38
41
  ```tsx
39
42
  import { ModalContextProvider } from 'react-modal-port';
40
43
 
@@ -64,6 +67,10 @@ const RootLayout:React.FC<PropsWithChildren> = ({ children }) => (
64
67
  <ModalContextProvider>
65
68
  <div style="width: 100%; min-height: 100vh;">
66
69
  {children}
70
+ {
71
+ /* The ModalPort defines the place in the app
72
+ * where your modals will be rendered */
73
+ }
67
74
  <ModalPort render={Backdrop} />
68
75
  </div>
69
76
  </ModalContextProvider>
@@ -0,0 +1,20 @@
1
+ import { type ModalContextProperties, type LaunchModalResolvers, type ModalState, type UpdateModalState, ModalProps } from './types';
2
+ export declare const ModalContext: import("react").Context<ModalContextProperties | null>;
3
+ export declare const ModalContextProvider: ({ children }: Readonly<{
4
+ children: React.ReactNode;
5
+ }>) => import("react/jsx-runtime").JSX.Element;
6
+ /**
7
+ * Get properties from the modal context
8
+ * @returns {ModalContextProperties} Object with the modal context properties
9
+ */
10
+ export declare function useModalContext(): ModalContextProperties;
11
+ /**
12
+ * Short-hand for `useModalContext().launchModal`
13
+ * @returns {LaunchModal} The launchModal function
14
+ */
15
+ export declare function useModal(): <P extends Record<string, any> = Record<string, any>>(render: React.FunctionComponent<ModalProps<P>>, resolvers: LaunchModalResolvers, props?: import("./types").LaunchModalProps) => void;
16
+ /**
17
+ * Get access to the current modal state and a function to update it
18
+ * @returns {[ ModalState | null, UpdateModalState ]} A tuple with the current modal state and a function to update it
19
+ */
20
+ export declare function useModalState(): [ModalState | null, UpdateModalState];
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.tsx"],"names":[],"mappings":"AAOA,OAAO,EAEL,KAAK,sBAAsB,EAC3B,KAAK,WAAW,EAEhB,KAAK,UAAU,EACf,KAAK,gBAAgB,EACtB,MAAM,UAAU,CAAC;AAElB,eAAO,MAAM,YAAY,wDAAqD,CAAC;AAE/E,eAAO,MAAM,oBAAoB,GAAI,cAAc,QAAQ,CAAC;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,CAAC,4CAkDzF,CAAC;AAEF;;;GAGG;AACH,wBAAgB,eAAe,IAAI,sBAAsB,CAMxD;AAED;;;GAGG;AACH,wBAAgB,QAAQ,IAAI,WAAW,CAGtC;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,CAAE,UAAU,GAAG,IAAI,EAAE,gBAAgB,CAAE,CAOvE"}
package/types/index.d.ts CHANGED
@@ -1,60 +1,3 @@
1
- /// <reference types="react" />
2
-
3
- import { PropsWithChildren } from "react";
4
-
5
- export type ModalResolver = (...args: any[]) => Promise<void>|void;
6
-
7
-
8
- export type LaunchModalResolvers = {
9
- [key: string]: ModalResolver;
10
- };
11
-
12
- export type LaunchModalProps = {
13
- [key: string]: any;
14
- };
15
-
16
- export type ModalProps = LaunchModalResolvers & LaunchModalProps;
17
-
18
- export type ModalStackItem = {
19
- render: React.FunctionComponent<LaunchModalResolvers>;
20
- resolvers: LaunchModalResolvers;
21
- props: LaunchModalProps;
22
- state: ModalState;
23
- };
24
-
25
- export type LaunchModal = (
26
- render: React.FunctionComponent<ModalProps>,
27
- resolvers: LaunchModalResolvers,
28
- props?: LaunchModalProps,
29
- ) => void;
30
-
31
- export type ModalState = { [key: string]: any };
32
- export type UpdateModalState = (newState: ModalState) => void;
33
-
34
- export type ModalContextProperties = {
35
- stack: ModalStackItem[];
36
- launchModal: LaunchModal;
37
- updateStack: (newStack: ModalStackItem[]) => void;
38
- updateState: (newState: ModalState) => void;
39
- };
40
-
41
- export type ModalPortRenderProps = React.PropsWithChildren & {
42
- onBackdropClick?: (ev: React.SyntheticEvent) => void;
43
- };
44
-
45
- export type ModalPortProps = {
46
- onModalLaunch?: () => void | null;
47
- onModalClose?: () => void | null;
48
- render: React.FC<ModalPortRenderProps>;
49
- };
50
-
51
- declare module 'react-modal-port' {
52
-
53
- const ModalContextProvider: React.FC<PropsWithChildren>;
54
- const useModalContext: () => ModalContextProperties;
55
- const useModal: () => ModalContextProperties['launchModal'];
56
- const useModalState: () => ModalState;
57
- const ModalPort: React.FC<ModalPortProps>;
58
-
59
- }
60
-
1
+ export { ModalContextProvider, useModalContext, useModal, useModalState, } from './context';
2
+ export { ModalPort } from './modal-port';
3
+ export type { ModalResolver, LaunchModalResolvers, LaunchModalProps, ModalProps, ModalStackItem, LaunchModal, ModalState, UpdateModalState, ModalContextProperties, ModalPortRenderProps, ModalPortProps } from './types';
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,QAAQ,EACR,aAAa,GACd,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { type ModalPortProps } from "./types";
2
+ declare const ModalPort: React.FC<ModalPortProps>;
3
+ export default ModalPort;
4
+ export { ModalPort };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modal-port.d.ts","sourceRoot":"","sources":["../src/modal-port.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,cAAc,EAEpB,MAAM,UAAU,CAAC;AAWlB,QAAA,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CA+DvC,CAAC;AAEF,eAAe,SAAS,CAAC;AACzB,OAAO,EAAE,SAAS,EAAE,CAAC"}
@@ -0,0 +1 @@
1
+ import '@testing-library/jest-dom';
@@ -0,0 +1,34 @@
1
+ import { type SyntheticEvent } from "react";
2
+ export type ModalResolver = (...args: any[]) => Promise<void> | void;
3
+ export type LaunchModalResolvers = {
4
+ [key: string]: ModalResolver;
5
+ };
6
+ export type LaunchModalProps = {
7
+ [key: string]: any;
8
+ };
9
+ export type ModalProps<P = Record<string, any>> = P;
10
+ export type ModalStackItem<P extends Record<string, any> = Record<string, any>> = {
11
+ render: React.FunctionComponent<ModalProps<P>>;
12
+ resolvers: LaunchModalResolvers;
13
+ props: LaunchModalProps;
14
+ state: ModalState;
15
+ };
16
+ export type LaunchModal<P extends Record<string, any> = Record<string, any>> = (render: React.FunctionComponent<ModalProps<P>>, resolvers: LaunchModalResolvers, props?: LaunchModalProps) => void;
17
+ export type ModalState = {
18
+ [key: string]: any;
19
+ };
20
+ export type UpdateModalState = (newState: ModalState) => void;
21
+ export type ModalContextProperties = {
22
+ stack: ModalStackItem<any>[];
23
+ launchModal: <P extends Record<string, any> = Record<string, any>>(render: React.FunctionComponent<ModalProps<P>>, resolvers: LaunchModalResolvers, props?: LaunchModalProps) => void;
24
+ updateStack: (newStack: ModalStackItem<any>[]) => void;
25
+ updateState: (newState: ModalState) => void;
26
+ };
27
+ export type ModalPortRenderProps = React.PropsWithChildren & {
28
+ onBackdropClick?: (ev: SyntheticEvent) => void;
29
+ };
30
+ export type ModalPortProps = {
31
+ onModalLaunch?: () => void | null;
32
+ onModalClose?: () => void | null;
33
+ render: React.FC<ModalPortRenderProps>;
34
+ };