@lerx/promise-modal 0.1.1 → 0.2.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/app/ModalManager.d.ts +0 -1
- package/dist/app/constant.d.ts +0 -1
- package/dist/bootstrap/BootstrapProvider/BootstrapProvider.d.ts +0 -1
- package/dist/bootstrap/BootstrapProvider/helpers/bootstrap.d.ts +0 -1
- package/dist/bootstrap/BootstrapProvider/hooks/useInitialize.d.ts +0 -1
- package/dist/bootstrap/BootstrapProvider/index.d.ts +0 -1
- package/dist/bootstrap/BootstrapProvider/type.d.ts +0 -1
- package/dist/bootstrap/BootstrapProvider/useBootstrap.d.ts +0 -1
- package/dist/bootstrap/index.d.ts +0 -1
- package/dist/components/Anchor/Anchor.d.ts +0 -1
- package/dist/components/Anchor/classNames.emotion.d.ts +0 -1
- package/dist/components/Anchor/index.d.ts +0 -1
- package/dist/components/Background/Background.d.ts +0 -1
- package/dist/components/Background/classNames.emotion.d.ts +0 -1
- package/dist/components/Background/index.d.ts +0 -1
- package/dist/components/FallbackComponents/FallbackContent.d.ts +0 -1
- package/dist/components/FallbackComponents/FallbackFooter.d.ts +0 -1
- package/dist/components/FallbackComponents/FallbackForegroundFrame.d.ts +0 -1
- package/dist/components/FallbackComponents/FallbackSubtitle.d.ts +0 -1
- package/dist/components/FallbackComponents/FallbackTitle.d.ts +0 -1
- package/dist/components/FallbackComponents/classNames.emotion.d.ts +0 -1
- package/dist/components/FallbackComponents/index.d.ts +0 -1
- package/dist/components/Foreground/Foreground.d.ts +0 -1
- package/dist/components/Foreground/classNames.emotion.d.ts +0 -1
- package/dist/components/Foreground/components/AlertInner.d.ts +0 -1
- package/dist/components/Foreground/components/ConfirmInner.d.ts +0 -1
- package/dist/components/Foreground/components/PromptInner.d.ts +0 -1
- package/dist/components/Foreground/components/index.d.ts +0 -1
- package/dist/components/Foreground/index.d.ts +0 -1
- package/dist/components/Presenter/Presenter.d.ts +0 -1
- package/dist/components/Presenter/classNames.emotion.d.ts +0 -1
- package/dist/components/Presenter/index.d.ts +0 -1
- package/dist/core/handle/alert.d.ts +0 -1
- package/dist/core/handle/confirm.d.ts +0 -1
- package/dist/core/handle/index.d.ts +0 -1
- package/dist/core/handle/prompt.d.ts +0 -1
- package/dist/core/index.d.ts +0 -1
- package/dist/core/node/ModalNode/AbstractNode.d.ts +0 -1
- package/dist/core/node/ModalNode/AlertNode.d.ts +0 -1
- package/dist/core/node/ModalNode/ConfirmNode.d.ts +0 -1
- package/dist/core/node/ModalNode/PromptNode.d.ts +0 -1
- package/dist/core/node/ModalNode/index.d.ts +0 -1
- package/dist/core/node/index.d.ts +0 -1
- package/dist/core/node/nodeFactory.d.ts +0 -1
- package/dist/core/node/type.d.ts +0 -1
- package/dist/hooks/useActiveModalCount.d.ts +0 -1
- package/dist/hooks/useDefaultPathname.d.ts +0 -1
- package/dist/hooks/useDestroyAfter.d.ts +0 -1
- package/dist/hooks/useModalAnimation.d.ts +0 -1
- package/dist/hooks/useSubscribeModal.d.ts +0 -1
- package/dist/index.cjs +966 -2
- package/dist/index.d.ts +0 -1
- package/dist/index.mjs +953 -2
- package/dist/providers/ConfigurationContext/ConfigurationContext.d.ts +0 -1
- package/dist/providers/ConfigurationContext/ConfigurationContextProvider.d.ts +4 -1
- package/dist/providers/ConfigurationContext/index.d.ts +0 -1
- package/dist/providers/ConfigurationContext/useConfigurationContext.d.ts +0 -1
- package/dist/providers/ModalManagerContext/ModalManagerContext.d.ts +0 -1
- package/dist/providers/ModalManagerContext/ModalManagerContextProvider.d.ts +0 -1
- package/dist/providers/ModalManagerContext/index.d.ts +0 -1
- package/dist/providers/ModalManagerContext/useModalManagerContext.d.ts +0 -1
- package/dist/providers/UserDefinedContext/UserDefinedContext.d.ts +0 -1
- package/dist/providers/UserDefinedContext/UserDefinedContextProvider.d.ts +2 -2
- package/dist/providers/UserDefinedContext/index.d.ts +0 -1
- package/dist/providers/UserDefinedContext/useUserDefinedContext.d.ts +0 -1
- package/dist/providers/index.d.ts +0 -1
- package/dist/types/alert.d.ts +0 -1
- package/dist/types/background.d.ts +0 -1
- package/dist/types/base.d.ts +0 -1
- package/dist/types/confirm.d.ts +0 -1
- package/dist/types/index.d.ts +0 -1
- package/dist/types/modal.d.ts +0 -1
- package/dist/types/prompt.d.ts +0 -1
- package/package.json +14 -26
- package/dist/app/ModalManager.d.ts.map +0 -1
- package/dist/app/constant.d.ts.map +0 -1
- package/dist/bootstrap/BootstrapProvider/BootstrapProvider.d.ts.map +0 -1
- package/dist/bootstrap/BootstrapProvider/helpers/bootstrap.d.ts.map +0 -1
- package/dist/bootstrap/BootstrapProvider/hooks/useInitialize.d.ts.map +0 -1
- package/dist/bootstrap/BootstrapProvider/index.d.ts.map +0 -1
- package/dist/bootstrap/BootstrapProvider/type.d.ts.map +0 -1
- package/dist/bootstrap/BootstrapProvider/useBootstrap.d.ts.map +0 -1
- package/dist/bootstrap/index.d.ts.map +0 -1
- package/dist/components/Anchor/Anchor.d.ts.map +0 -1
- package/dist/components/Anchor/classNames.emotion.d.ts.map +0 -1
- package/dist/components/Anchor/index.d.ts.map +0 -1
- package/dist/components/Background/Background.d.ts.map +0 -1
- package/dist/components/Background/classNames.emotion.d.ts.map +0 -1
- package/dist/components/Background/index.d.ts.map +0 -1
- package/dist/components/FallbackComponents/FallbackContent.d.ts.map +0 -1
- package/dist/components/FallbackComponents/FallbackFooter.d.ts.map +0 -1
- package/dist/components/FallbackComponents/FallbackForegroundFrame.d.ts.map +0 -1
- package/dist/components/FallbackComponents/FallbackSubtitle.d.ts.map +0 -1
- package/dist/components/FallbackComponents/FallbackTitle.d.ts.map +0 -1
- package/dist/components/FallbackComponents/classNames.emotion.d.ts.map +0 -1
- package/dist/components/FallbackComponents/index.d.ts.map +0 -1
- package/dist/components/Foreground/Foreground.d.ts.map +0 -1
- package/dist/components/Foreground/classNames.emotion.d.ts.map +0 -1
- package/dist/components/Foreground/components/AlertInner.d.ts.map +0 -1
- package/dist/components/Foreground/components/ConfirmInner.d.ts.map +0 -1
- package/dist/components/Foreground/components/PromptInner.d.ts.map +0 -1
- package/dist/components/Foreground/components/index.d.ts.map +0 -1
- package/dist/components/Foreground/index.d.ts.map +0 -1
- package/dist/components/Presenter/Presenter.d.ts.map +0 -1
- package/dist/components/Presenter/classNames.emotion.d.ts.map +0 -1
- package/dist/components/Presenter/index.d.ts.map +0 -1
- package/dist/core/handle/alert.d.ts.map +0 -1
- package/dist/core/handle/confirm.d.ts.map +0 -1
- package/dist/core/handle/index.d.ts.map +0 -1
- package/dist/core/handle/prompt.d.ts.map +0 -1
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/node/ModalNode/AbstractNode.d.ts.map +0 -1
- package/dist/core/node/ModalNode/AlertNode.d.ts.map +0 -1
- package/dist/core/node/ModalNode/ConfirmNode.d.ts.map +0 -1
- package/dist/core/node/ModalNode/PromptNode.d.ts.map +0 -1
- package/dist/core/node/ModalNode/index.d.ts.map +0 -1
- package/dist/core/node/index.d.ts.map +0 -1
- package/dist/core/node/nodeFactory.d.ts.map +0 -1
- package/dist/core/node/type.d.ts.map +0 -1
- package/dist/hooks/useActiveModalCount.d.ts.map +0 -1
- package/dist/hooks/useDefaultPathname.d.ts.map +0 -1
- package/dist/hooks/useDestroyAfter.d.ts.map +0 -1
- package/dist/hooks/useModalAnimation.d.ts.map +0 -1
- package/dist/hooks/useSubscribeModal.d.ts.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/providers/ConfigurationContext/ConfigurationContext.d.ts.map +0 -1
- package/dist/providers/ConfigurationContext/ConfigurationContextProvider.d.ts.map +0 -1
- package/dist/providers/ConfigurationContext/index.d.ts.map +0 -1
- package/dist/providers/ConfigurationContext/useConfigurationContext.d.ts.map +0 -1
- package/dist/providers/ModalManagerContext/ModalManagerContext.d.ts.map +0 -1
- package/dist/providers/ModalManagerContext/ModalManagerContextProvider.d.ts.map +0 -1
- package/dist/providers/ModalManagerContext/index.d.ts.map +0 -1
- package/dist/providers/ModalManagerContext/useModalManagerContext.d.ts.map +0 -1
- package/dist/providers/UserDefinedContext/UserDefinedContext.d.ts.map +0 -1
- package/dist/providers/UserDefinedContext/UserDefinedContextProvider.d.ts.map +0 -1
- package/dist/providers/UserDefinedContext/index.d.ts.map +0 -1
- package/dist/providers/UserDefinedContext/useUserDefinedContext.d.ts.map +0 -1
- package/dist/providers/index.d.ts.map +0 -1
- package/dist/types/alert.d.ts.map +0 -1
- package/dist/types/background.d.ts.map +0 -1
- package/dist/types/base.d.ts.map +0 -1
- package/dist/types/confirm.d.ts.map +0 -1
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/modal.d.ts.map +0 -1
- package/dist/types/prompt.d.ts.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,953 @@
|
|
|
1
|
-
function _EMOTION_STRINGIFIED_CSS_ERROR__$4(){return"You have tried to stringify object returned from `css` function. It isn't supposed to be used directly (e.g. as value of the `className` prop), but rather handed to emotion so it can handle it (e.g. as value of `css` prop)."}function _EMOTION_STRINGIFIED_CSS_ERROR__$3(){return"You have tried to stringify object returned from `css` function. It isn't supposed to be used directly (e.g. as value of the `className` prop), but rather handed to emotion so it can handle it (e.g. as value of `css` prop)."}function _EMOTION_STRINGIFIED_CSS_ERROR__$2(){return"You have tried to stringify object returned from `css` function. It isn't supposed to be used directly (e.g. as value of the `className` prop), but rather handed to emotion so it can handle it (e.g. as value of `css` prop)."}import{jsx as e,jsxs as n}from"react/jsx-runtime";import{createContext as o,memo as t,useRef as r,useState,useMemo as i,useLayoutEffect as a,useCallback as l,useContext as s,forwardRef as c,Fragment as d,useEffect,useImperativeHandle as u}from"react";import{convertMsFromDuration as m}from"@winglet/common-utils/convert";import{useReference as p,useOnMountLayout as C,useHandle as h,useVersion as g,useOnMount as f}from"@winglet/react-utils/hook";import{getRandomString as b,counterFactory as v}from"@winglet/common-utils/lib";import{css as y,cx as k}from"@emotion/css";import{createPortal as O}from"react-dom";import{map as _}from"@winglet/common-utils/array";import{withErrorBoundary as x}from"@winglet/react-utils/hoc";import{isString as I,isFunction as M}from"@winglet/common-utils/filter";import{renderComponent as N}from"@winglet/react-utils/render";import{printError as D}from"@winglet/common-utils/console";class ModalManager{static#e=0;static activate(){return ModalManager.#e?0:ModalManager.#e=1}static#n=null;static anchor(e){if(ModalManager.#n){const e=document.getElementById(ModalManager.#n.id);if(e)return e}const{tag:n="div",prefix:o="promise-modal",root:t=document.body}=e||{},r=document.createElement(n);return r.setAttribute("id",`${o}-${b(36)}`),t.appendChild(r),ModalManager.#n=r,r}static#o=[];static get prerender(){return ModalManager.#o}static#t=e=>ModalManager.#o.push(e);static set openHandler(e){ModalManager.#t=e,ModalManager.#o=[]}static get unanchored(){return!ModalManager.#n}static reset(){ModalManager.#e=0,ModalManager.#n=null,ModalManager.#o=[],ModalManager.#t=e=>ModalManager.#o.push(e)}static open(e){ModalManager.#t(e)}}const alert=({subtype:e,title:n,subtitle:o,content:t,background:r,footer:i,dimmed:a,manualDestroy:l,closeOnBackdropClick:s,ForegroundComponent:c,BackgroundComponent:d})=>new Promise(((u,m)=>{try{ModalManager.open({type:"alert",subtype:e,resolve:()=>u(),title:n,subtitle:o,content:t,background:r,footer:i,dimmed:a,manualDestroy:l,closeOnBackdropClick:s,ForegroundComponent:c,BackgroundComponent:d})}catch(e){m(e)}})),confirm=({subtype:e,title:n,subtitle:o,content:t,background:r,footer:i,dimmed:a,manualDestroy:l,closeOnBackdropClick:s,ForegroundComponent:c,BackgroundComponent:d})=>new Promise(((u,m)=>{try{ModalManager.open({type:"confirm",subtype:e,resolve:e=>u(e??0),title:n,subtitle:o,content:t,background:r,footer:i,dimmed:a,manualDestroy:l,closeOnBackdropClick:s,ForegroundComponent:c,BackgroundComponent:d})}catch(e){m(e)}})),prompt=({defaultValue:e,title:n,subtitle:o,content:t,Input:r,disabled:i,returnOnCancel:a,background:l,footer:s,dimmed:c,manualDestroy:d,closeOnBackdropClick:u,ForegroundComponent:m,BackgroundComponent:p})=>new Promise(((C,h)=>{try{ModalManager.open({type:"prompt",resolve:e=>C(e),title:n,subtitle:o,content:t,Input:r,defaultValue:e,disabled:i,returnOnCancel:a,background:l,footer:s,dimmed:c,manualDestroy:d,closeOnBackdropClick:u,ForegroundComponent:m,BackgroundComponent:p})}catch(e){h(e)}}));class AbstractNode{id;initiator;title;subtitle;background;manualDestroy;closeOnBackdropClick;dimmed;ForegroundComponent;BackgroundComponent;#r;get alive(){return this.#r}#i;get visible(){return this.#i}#a;#l=new Set;constructor({id:e,initiator:n,title:o,subtitle:t,background:r,dimmed:i=1,manualDestroy:a=0,closeOnBackdropClick:l=1,resolve:s,ForegroundComponent:c,BackgroundComponent:d}){this.id=e,this.initiator=n,this.title=o,this.subtitle=t,this.background=r,this.dimmed=i,this.manualDestroy=a,this.closeOnBackdropClick=l,this.ForegroundComponent=c,this.BackgroundComponent=d,this.#r=1,this.#i=1,this.#a=s}subscribe(e){return this.#l.add(e),()=>{this.#l.delete(e)}}publish(){for(const e of this.#l)e()}resolve(e){this.#a(e)}onDestroy(){const e=1==this.#r;this.#r=0,this.manualDestroy&&e&&this.publish()}onShow(){const e=0==this.#i;this.#i=1,e&&this.publish()}onHide(){const e=1==this.#i;this.#i=0,e&&this.publish()}}class AlertNode extends AbstractNode{type;subtype;content;footer;constructor({id:e,initiator:n,type:o,subtype:t,title:r,subtitle:i,content:a,footer:l,background:s,dimmed:c,manualDestroy:d,closeOnBackdropClick:u,resolve:m,ForegroundComponent:p,BackgroundComponent:C}){super({id:e,initiator:n,title:r,subtitle:i,background:s,dimmed:c,manualDestroy:d,closeOnBackdropClick:u,resolve:m,ForegroundComponent:p,BackgroundComponent:C}),this.type=o,this.subtype=t,this.content=a,this.footer=l}onClose(){this.resolve(null)}onConfirm(){this.resolve(null)}}class ConfirmNode extends AbstractNode{type;subtype;content;footer;constructor({id:e,initiator:n,type:o,subtype:t,title:r,subtitle:i,content:a,footer:l,background:s,dimmed:c,manualDestroy:d,closeOnBackdropClick:u,resolve:m,ForegroundComponent:p,BackgroundComponent:C}){super({id:e,initiator:n,title:r,subtitle:i,background:s,dimmed:c,manualDestroy:d,closeOnBackdropClick:u,resolve:m,ForegroundComponent:p,BackgroundComponent:C}),this.type=o,this.subtype=t,this.content=a,this.footer=l}onClose(){this.resolve(0)}onConfirm(){this.resolve(1)}}class PromptNode extends AbstractNode{type;content;defaultValue;Input;disabled;returnOnCancel;footer;#s;constructor({id:e,initiator:n,type:o,title:t,subtitle:r,content:i,defaultValue:a,Input:l,disabled:s,returnOnCancel:c,footer:d,background:u,dimmed:m,manualDestroy:p,closeOnBackdropClick:C,resolve:h,ForegroundComponent:g,BackgroundComponent:f}){super({id:e,initiator:n,title:t,subtitle:r,background:u,dimmed:m,manualDestroy:p,closeOnBackdropClick:C,resolve:h,ForegroundComponent:g,BackgroundComponent:f}),this.type=o,this.content=i,this.Input=l,this.defaultValue=a,this.#s=a,this.disabled=s,this.returnOnCancel=c,this.footer=d}onChange(e){this.#s=e}onConfirm(){this.resolve(this.#s??null)}onClose(){this.returnOnCancel?this.resolve(this.#s??null):this.resolve(null)}}const nodeFactory=e=>{switch(e.type){case"alert":return new AlertNode(e);case"confirm":return new ConfirmNode(e);case"prompt":return new PromptNode(e)}throw new Error(`Unknown modal: ${e.type}`,{modal:e})},S=o({}),E=t((({usePathname:n,children:o})=>{const t=r(new Map),[s,c]=useState([]),d=p(s),{pathname:u}=n(),h=r(u),g=r(0),f=useConfigurationOptions(),b=i((()=>m(f.duration)),[f]);C((()=>{const{manualDestroy:e,closeOnBackdropClick:n}=f;for(const o of ModalManager.prerender){const r=nodeFactory({...o,id:g.current++,initiator:h.current,manualDestroy:void 0!==o.manualDestroy?o.manualDestroy:e,closeOnBackdropClick:void 0!==o.closeOnBackdropClick?o.closeOnBackdropClick:n});t.current.set(r.id,r),c((e=>[...e,r.id]))}return ModalManager.openHandler=o=>{const r=nodeFactory({...o,id:g.current++,initiator:h.current,manualDestroy:void 0!==o.manualDestroy?o.manualDestroy:e,closeOnBackdropClick:void 0!==o.closeOnBackdropClick?o.closeOnBackdropClick:n});t.current.set(r.id,r),c((e=>{const n=[];for(let o=0;o<e.length;o++){const r=e[o];t.current.get(r)?.alive?n.push(r):t.current.delete(r)}return[...n,r.id]}))},()=>{ModalManager.reset()}})),a((()=>{for(const e of d.current){const n=t.current.get(e);n?.alive&&(n.initiator===u?n.onShow():n.onHide())}h.current=u}),[u]);const v=l((e=>t.current.get(e)),[]),y=l((e=>{const n=t.current.get(e);n&&(n.onDestroy(),k.current?.())}),[]),k=r(void 0),O=l((e=>{const n=t.current.get(e);n&&(n.onHide(),k.current?.(),n.manualDestroy||setTimeout((()=>{n.onDestroy()}),b))}),[b]),_=l(((e,n)=>{const o=t.current.get(e);o&&"prompt"===o.type&&o.onChange(n)}),[]),x=l((e=>{const n=t.current.get(e);n&&(n.onConfirm(),O(e))}),[O]),I=l((e=>{const n=t.current.get(e);n&&(n.onClose(),O(e))}),[O]),M=l((e=>({modal:v(e),onConfirm:()=>x(e),onClose:()=>I(e),onChange:n=>_(e,n),onDestroy:()=>y(e)})),[v,x,I,_,y]),N=i((()=>({modalIds:s,getModalNode:v,onChange:_,onConfirm:x,onClose:I,onDestroy:y,getModal:M,setUpdater:e=>{k.current=e}})),[s,M,v,_,x,I,y]);return e(S.Provider,{value:N,children:o})})),useModalManagerContext=()=>s(S),useModal=e=>{const{getModal:n}=useModalManagerContext();return i((()=>n(e)),[e,n])},B=y("production"===process.env.NODE_ENV?{name:"131j9g2",styles:"margin:unset"}:{name:"1w3kbco-fallback",styles:"margin:unset;label:fallback;",toString:_EMOTION_STRINGIFIED_CSS_ERROR__$4}),F=y("production"===process.env.NODE_ENV?{name:"1kuk3a3",styles:"display:flex;flex-direction:column;justify-content:center;align-items:center;background-color:white;padding:20px 80px;gap:10px;border:1px solid black"}:{name:"16dbbea-frame",styles:"display:flex;flex-direction:column;justify-content:center;align-items:center;background-color:white;padding:20px 80px;gap:10px;border:1px solid black;label:frame;",toString:_EMOTION_STRINGIFIED_CSS_ERROR__$4}),FallbackTitle=({children:n})=>e("h2",{className:B,children:n}),FallbackSubtitle=({children:n})=>e("h3",{className:B,children:n}),FallbackContent=({children:n})=>e("div",{className:B,children:n}),FallbackFooter=({confirmLabel:o,hideConfirm:t=0,cancelLabel:r,hideCancel:i=0,disabled:a,onConfirm:l,onCancel:s})=>n("div",{children:[!t&&e("button",{onClick:l,disabled:a,children:o||"Confirm"}),!i&&"function"==typeof s&&e("button",{onClick:s,children:r||"Cancel"})]}),defaultValidate=e=>e?.visible,useActiveModalCount=(e=defaultValidate,n=0)=>{const{modalIds:o,getModalNode:t}=useModalManagerContext();return i((()=>{let n=0;for(const r of o)e(t(r))&&n++;return n}),[t,o,n])},R=c((({id:n,onChangeOrder:o,children:t},r)=>{const a=useActiveModalCount(),[l,s]=i((()=>{const e=a>1;return[e?Math.floor(n/5)%3*100:0,e?n%5*35:0]}),[a,n]);return e("div",{ref:r,className:F,onClick:o,style:{marginBottom:`calc(25vh + ${l}px)`,marginLeft:`${l}px`,transform:`translate(${s}px, ${s}px)`},children:t})})),T=o({}),w=t((({ForegroundComponent:n,BackgroundComponent:o,TitleComponent:r,SubtitleComponent:a,ContentComponent:l,FooterComponent:s,options:c,children:d})=>{const u=i((()=>({BackgroundComponent:o,ForegroundComponent:n||R,TitleComponent:r||FallbackTitle,SubtitleComponent:a||FallbackSubtitle,ContentComponent:t(l||FallbackContent),FooterComponent:t(s||FallbackFooter),options:{duration:"300ms",backdrop:"rgba(0, 0, 0, 0.5)",closeOnBackdropClick:1,manualDestroy:0,...c}})),[n,o,l,s,a,r,c]);return e(T.Provider,{value:u,children:d})})),useConfigurationContext=()=>s(T),useConfigurationOptions=()=>s(T).options,useConfigurationDuration=()=>{const e=useConfigurationOptions();return{duration:e.duration,milliseconds:m(e.duration)}},useConfigurationBackdrop=()=>useConfigurationOptions().backdrop,P=o({}),UserDefinedContextProvider=({context:n,children:o})=>{const t=i((()=>({context:n||{}})),[n]);return e(P.Provider,{value:t,children:o})},useUserDefinedContext=()=>s(P),usePathname=()=>{const[e,n]=useState(window.location.pathname);return a((()=>{let o;const checkPathname=()=>{o&&cancelAnimationFrame(o),e!==window.location.pathname?n(window.location.pathname):o=requestAnimationFrame(checkPathname)};return o=requestAnimationFrame(checkPathname),()=>{o&&cancelAnimationFrame(o)}}),[e]),{pathname:e}},$=y("production"===process.env.NODE_ENV?{name:"u7uu4v",styles:"display:none;position:fixed;inset:0;z-index:-999;pointer-events:none;>*{pointer-events:none;}"}:{name:"coymdj-background",styles:"display:none;position:fixed;inset:0;z-index:-999;pointer-events:none;>*{pointer-events:none;};label:background;",toString:_EMOTION_STRINGIFIED_CSS_ERROR__$3}),j=y("production"===process.env.NODE_ENV?{name:"n07k1x",styles:"pointer-events:all"}:{name:"1hektcs-active",styles:"pointer-events:all;label:active;",toString:_EMOTION_STRINGIFIED_CSS_ERROR__$3}),V=y("production"===process.env.NODE_ENV?{name:"1wnowod",styles:"display:flex;align-items:center;justify-content:center"}:{name:"xppew7-visible",styles:"display:flex;align-items:center;justify-content:center;label:visible;",toString:_EMOTION_STRINGIFIED_CSS_ERROR__$3}),BackgroundFrame=({modalId:n,onChangeOrder:o})=>{const{BackgroundComponent:t}=useConfigurationContext(),{context:r}=useUserDefinedContext(),{modal:a,onClose:s,onChange:c,onConfirm:d,onDestroy:u}=useModal(n),m=l((e=>{a&&a.closeOnBackdropClick&&a.visible&&s(),e.stopPropagation()}),[a,s]),p=i((()=>a?.BackgroundComponent||t),[t,a]);return a?e("div",{className:k($,{[V]:a.manualDestroy?a.alive:a.visible,[j]:a.closeOnBackdropClick&&a.visible}),onClick:m,children:p&&e(p,{id:a.id,type:a.type,alive:a.alive,visible:a.visible,initiator:a.initiator,manualDestroy:a.manualDestroy,closeOnBackdropClick:a.closeOnBackdropClick,background:a.background,onChange:c,onConfirm:d,onClose:s,onDestroy:u,onChangeOrder:o,context:r})}):null},z=y("production"===process.env.NODE_ENV?{name:"12g0hx0",styles:"pointer-events:none;display:none;position:fixed;inset:0;z-index:1"}:{name:"1hcczik-foreground",styles:"pointer-events:none;display:none;position:fixed;inset:0;z-index:1;label:foreground;",toString:_EMOTION_STRINGIFIED_CSS_ERROR__$2}),A=y("production"===process.env.NODE_ENV?{name:"1g95xyq",styles:">*{pointer-events:all;}"}:{name:"123csva-active",styles:">*{pointer-events:all;};label:active;",toString:_EMOTION_STRINGIFIED_CSS_ERROR__$2}),L=y("production"===process.env.NODE_ENV?{name:"1fmljv2",styles:"display:flex!important;justify-content:center;align-items:center"}:{name:"1p4unab-visible",styles:"display:flex!important;justify-content:center;align-items:center;label:visible;",toString:_EMOTION_STRINGIFIED_CSS_ERROR__$2}),G=t((({modal:o,handlers:t})=>{const{title:r,subtitle:a,content:l,footer:s}=i((()=>o),[o]),{context:c}=useUserDefinedContext(),{onConfirm:u}=i((()=>t),[t]),m=h(u),{TitleComponent:p,SubtitleComponent:C,ContentComponent:g,FooterComponent:f}=useConfigurationContext();return n(d,{children:[r&&(I(r)?e(p,{context:c,children:r}):r),a&&(I(a)?e(C,{context:c,children:a}):a),l&&(I(l)?e(g,{context:c,children:l}):N(l,{onConfirm:m})),0!=s&&("function"==typeof s?s({onConfirm:m,context:c}):e(f,{onConfirm:m,confirmLabel:s?.confirm,hideConfirm:s?.hideConfirm,context:c}))]})})),H=t((({modal:o,handlers:t})=>{const{title:r,subtitle:a,content:l,footer:s}=i((()=>o),[o]),{context:c}=useUserDefinedContext(),{onConfirm:u,onClose:m}=i((()=>t),[t]),p=h(u),C=h(m),{TitleComponent:g,SubtitleComponent:f,ContentComponent:b,FooterComponent:v}=useConfigurationContext();return n(d,{children:[r&&(I(r)?e(g,{context:c,children:r}):r),a&&(I(a)?e(f,{context:c,children:a}):a),l&&(I(l)?e(b,{context:c,children:l}):N(l,{onConfirm:p,onCancel:C,context:c})),0!=s&&("function"==typeof s?s({onConfirm:p,onCancel:C,context:c}):e(v,{onConfirm:p,onCancel:C,confirmLabel:s?.confirm,cancelLabel:s?.cancel,hideConfirm:s?.hideConfirm,hideCancel:s?.hideCancel,context:c}))]})})),q=t((({modal:o,handlers:r})=>{const{Input:a,defaultValue:s,disabled:c,title:u,subtitle:m,content:p,footer:C}=i((()=>({...o,Input:t(x(o.Input))})),[o]),{context:g}=useUserDefinedContext(),[f,b]=useState(s),{onChange:v,onClose:y,onConfirm:k}=i((()=>r),[r]),O=h(y),_=h((e=>{const n=M(e)?e(f):e;b(n),v(n)})),D=l((()=>{requestAnimationFrame(k)}),[k]),S=i((()=>f?!!c?.(f):0),[c,f]),{TitleComponent:E,SubtitleComponent:B,ContentComponent:F,FooterComponent:R}=useConfigurationContext();return n(d,{children:[u&&(I(u)?e(E,{context:g,children:u}):u),m&&(I(m)?e(B,{context:g,children:m}):m),p&&(I(p)?e(F,{context:g,children:p}):N(p,{onConfirm:D,onCancel:O,context:g})),a&&e(a,{defaultValue:s,value:f,onChange:_,onConfirm:D,onCancel:O,context:g}),0!=C&&("function"==typeof C?C({value:f,disabled:S,onChange:_,onConfirm:D,onCancel:O,context:g}):e(R,{disabled:S,onConfirm:D,onCancel:O,confirmLabel:C?.confirm,cancelLabel:C?.cancel,hideConfirm:C?.hideConfirm,hideCancel:C?.hideCancel,context:g}))]})})),ForegroundFrame=({modalId:o,onChangeOrder:t})=>{const{ForegroundComponent:r}=useConfigurationContext(),{context:a}=useUserDefinedContext(),{modal:l,onChange:s,onConfirm:c,onClose:d,onDestroy:u}=useModal(o),m=i((()=>l?.ForegroundComponent||r),[r,l]);return l?e("div",{className:k(z,{[L]:l.manualDestroy?l.alive:l.visible,[A]:l.visible}),children:n(m,{id:l.id,type:l.type,alive:l.alive,visible:l.visible,initiator:l.initiator,manualDestroy:l.manualDestroy,closeOnBackdropClick:l.closeOnBackdropClick,background:l.background,onChange:s,onConfirm:c,onClose:d,onDestroy:u,onChangeOrder:t,context:a,children:["alert"===l.type&&e(G,{modal:l,handlers:{onConfirm:c}}),"confirm"===l.type&&e(H,{modal:l,handlers:{onConfirm:c,onClose:d}}),"prompt"===l.type&&e(q,{modal:l,handlers:{onChange:s,onConfirm:c,onClose:d}})]})}):null},useSubscribeModal=e=>{const[n,o]=g();return useEffect((()=>{if(e)return e.subscribe(o)}),[e,o]),n},Y=y("production"===process.env.NODE_ENV?{name:"13dmkf4",styles:"position:fixed;inset:0;pointer-events:none;overflow:hidden"}:{name:"yjeu12-presenter",styles:"position:fixed;inset:0;pointer-events:none;overflow:hidden;label:presenter;",toString:function _EMOTION_STRINGIFIED_CSS_ERROR__$1(){return"You have tried to stringify object returned from `css` function. It isn't supposed to be used directly (e.g. as value of the `className` prop), but rather handed to emotion so it can handle it (e.g. as value of `css` prop)."}}),{increment:U}=v(1),J=t((({modalId:o})=>{const t=r(null),{modal:i}=useModal(o);useSubscribeModal(i);const a=h((()=>{t.current&&(t.current.style.zIndex=`${U()}`)}));return n("div",{ref:t,className:Y,children:[e(BackgroundFrame,{modalId:o,onChangeOrder:a}),e(ForegroundFrame,{modalId:o,onChangeOrder:a})]})})),K=y("production"===process.env.NODE_ENV?{name:"2hpasy",styles:"display:flex;align-items:center;justify-content:center;position:fixed;inset:0;pointer-events:none;z-index:1000;transition:background-color ease-in-out"}:{name:"lhj8co-anchor",styles:"display:flex;align-items:center;justify-content:center;position:fixed;inset:0;pointer-events:none;z-index:1000;transition:background-color ease-in-out;label:anchor;",toString:function _EMOTION_STRINGIFIED_CSS_ERROR__(){return"You have tried to stringify object returned from `css` function. It isn't supposed to be used directly (e.g. as value of the `className` prop), but rather handed to emotion so it can handle it (e.g. as value of `css` prop)."}}),validateDimmable=e=>e?.visible&&e.dimmed,Q=t(x((()=>{const[n,o]=g(),{modalIds:t,setUpdater:r}=useModalManagerContext();useEffect((()=>{r(o)}),[r,o]);const i=useConfigurationOptions(),a=useActiveModalCount(validateDimmable,n);return e("div",{className:K,style:{transitionDuration:i.duration,backgroundColor:a?i.backdrop:"transparent"},children:_(t,(n=>e(J,{modalId:n},n)))})}))),bootstrap=({ForegroundComponent:n,BackgroundComponent:o,TitleComponent:t,SubtitleComponent:r,ContentComponent:i,FooterComponent:a,usePathname:l,options:s,context:c,anchor:d})=>O(e(UserDefinedContextProvider,{context:c,children:e(w,{ForegroundComponent:n,BackgroundComponent:o,TitleComponent:t,SubtitleComponent:r,ContentComponent:i,FooterComponent:a,options:s,children:e(E,{usePathname:l,children:e(Q,{})})})}),d),useInitialize=()=>{const e=r(ModalManager.activate()),n=r(null),[,o]=g(),t=l((t=>{e.current?(n.current=ModalManager.anchor({root:t}),o()):D("ModalProvider is already initialized",["ModalProvider can only be initialized once.","Nesting ModalProvider will be ignored..."],{info:"Something is wrong with the ModalProvider initialization..."})}),[o]);return{anchorRef:n,handleInitialize:t}},W=c((({usePathname:e,ForegroundComponent:o,BackgroundComponent:t,TitleComponent:r,SubtitleComponent:a,ContentComponent:l,FooterComponent:s,options:c,context:m,children:p},C)=>{const h=i((()=>e||usePathname),[e]),{anchorRef:g,handleInitialize:b}=useInitialize();return u(C,(()=>({initialize:b})),[b]),f((()=>(null===C&&b(),()=>{g.current&&g.current.remove()}))),n(d,{children:[p,g.current&&bootstrap({ForegroundComponent:o,BackgroundComponent:t,TitleComponent:r,SubtitleComponent:a,ContentComponent:l,FooterComponent:s,usePathname:h,options:c,context:m,anchor:g.current})]})})),useBootstrap=({usePathname:e,ForegroundComponent:n,BackgroundComponent:o,TitleComponent:t,SubtitleComponent:r,ContentComponent:a,FooterComponent:s,options:c,context:d,mode:u="auto"}={})=>{const m=i((()=>e||usePathname),[e]),{anchorRef:p,handleInitialize:C}=useInitialize();f((()=>("auto"===u&&C(),()=>{p.current&&p.current.remove()})));const h=l((e=>{"manual"===u&&C(e)}),[u,C]);return{portal:p.current&&bootstrap({usePathname:m,ForegroundComponent:n,BackgroundComponent:o,TitleComponent:t,SubtitleComponent:r,ContentComponent:a,FooterComponent:s,options:c,context:d,anchor:p.current}),initialize:h}},useDestroyAfter=(e,n)=>{const{modal:o,onDestroy:t}=useModal(e),i=useSubscribeModal(o),a=r({modal:o,onDestroy:t,milliseconds:I(n)?m(n):n});useEffect((()=>{const{modal:e,onDestroy:n,milliseconds:o}=a.current;if(!e||e.visible||!e.alive)return;const t=setTimeout((()=>{n()}),o);return()=>{t&&clearTimeout(t)}}),[i])},useModalAnimation=(e,n)=>{const o=r(n);o.current=n,a((()=>{if(!o.current)return;let n;return n=e?requestAnimationFrame((()=>o.current.onVisible?.())):requestAnimationFrame((()=>o.current.onHidden?.())),()=>{n&&cancelAnimationFrame(n)}}),[e])};export{W as ModalProvider,alert,confirm,prompt,useActiveModalCount,useDestroyAfter,useBootstrap as useInitializeModal,useModalAnimation,useConfigurationBackdrop as useModalBackdrop,useConfigurationDuration as useModalDuration,useConfigurationOptions as useModalOptions,useSubscribeModal};
|
|
2
|
-
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import { createContext, useContext, useMemo, forwardRef, memo, useRef, useState, useLayoutEffect, useCallback, Fragment, useEffect, useImperativeHandle } from 'react';
|
|
3
|
+
import { convertMsFromDuration } from '@winglet/common-utils/convert';
|
|
4
|
+
import { useReference, useOnMountLayout, useHandle, useVersion, useOnMount } from '@winglet/react-utils/hook';
|
|
5
|
+
import { getRandomString, counterFactory } from '@winglet/common-utils/lib';
|
|
6
|
+
import { css, cx } from '@emotion/css';
|
|
7
|
+
import { createPortal } from 'react-dom';
|
|
8
|
+
import { map } from '@winglet/common-utils/array';
|
|
9
|
+
import { withErrorBoundary } from '@winglet/react-utils/hoc';
|
|
10
|
+
import { isString, isFunction } from '@winglet/common-utils/filter';
|
|
11
|
+
import { renderComponent } from '@winglet/react-utils/render';
|
|
12
|
+
import { printError } from '@winglet/common-utils/console';
|
|
13
|
+
|
|
14
|
+
class ModalManager {
|
|
15
|
+
static #active = false;
|
|
16
|
+
static activate() {
|
|
17
|
+
if (ModalManager.#active)
|
|
18
|
+
return false;
|
|
19
|
+
return (ModalManager.#active = true);
|
|
20
|
+
}
|
|
21
|
+
static #anchor = null;
|
|
22
|
+
static anchor(options) {
|
|
23
|
+
if (ModalManager.#anchor) {
|
|
24
|
+
const anchor = document.getElementById(ModalManager.#anchor.id);
|
|
25
|
+
if (anchor)
|
|
26
|
+
return anchor;
|
|
27
|
+
}
|
|
28
|
+
const { tag = 'div', prefix = 'promise-modal', root = document.body, } = options || {};
|
|
29
|
+
const node = document.createElement(tag);
|
|
30
|
+
node.setAttribute('id', `${prefix}-${getRandomString(36)}`);
|
|
31
|
+
root.appendChild(node);
|
|
32
|
+
ModalManager.#anchor = node;
|
|
33
|
+
return node;
|
|
34
|
+
}
|
|
35
|
+
static #prerenderList = [];
|
|
36
|
+
static get prerender() {
|
|
37
|
+
return ModalManager.#prerenderList;
|
|
38
|
+
}
|
|
39
|
+
static #openHandler = (modal) => ModalManager.#prerenderList.push(modal);
|
|
40
|
+
static set openHandler(handler) {
|
|
41
|
+
ModalManager.#openHandler = handler;
|
|
42
|
+
ModalManager.#prerenderList = [];
|
|
43
|
+
}
|
|
44
|
+
static get unanchored() {
|
|
45
|
+
return !ModalManager.#anchor;
|
|
46
|
+
}
|
|
47
|
+
static reset() {
|
|
48
|
+
ModalManager.#active = false;
|
|
49
|
+
ModalManager.#anchor = null;
|
|
50
|
+
ModalManager.#prerenderList = [];
|
|
51
|
+
ModalManager.#openHandler = (modal) => ModalManager.#prerenderList.push(modal);
|
|
52
|
+
}
|
|
53
|
+
static open(modal) {
|
|
54
|
+
ModalManager.#openHandler(modal);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const alert = ({ subtype, title, subtitle, content, background, footer, dimmed, manualDestroy, closeOnBackdropClick, ForegroundComponent, BackgroundComponent, }) => {
|
|
59
|
+
return new Promise((resolve, reject) => {
|
|
60
|
+
try {
|
|
61
|
+
ModalManager.open({
|
|
62
|
+
type: 'alert',
|
|
63
|
+
subtype,
|
|
64
|
+
resolve: () => resolve(),
|
|
65
|
+
title,
|
|
66
|
+
subtitle,
|
|
67
|
+
content,
|
|
68
|
+
background,
|
|
69
|
+
footer,
|
|
70
|
+
dimmed,
|
|
71
|
+
manualDestroy,
|
|
72
|
+
closeOnBackdropClick,
|
|
73
|
+
ForegroundComponent,
|
|
74
|
+
BackgroundComponent,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
reject(error);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const confirm = ({ subtype, title, subtitle, content, background, footer, dimmed, manualDestroy, closeOnBackdropClick, ForegroundComponent, BackgroundComponent, }) => {
|
|
84
|
+
return new Promise((resolve, reject) => {
|
|
85
|
+
try {
|
|
86
|
+
ModalManager.open({
|
|
87
|
+
type: 'confirm',
|
|
88
|
+
subtype,
|
|
89
|
+
resolve: (result) => resolve(result ?? false),
|
|
90
|
+
title,
|
|
91
|
+
subtitle,
|
|
92
|
+
content,
|
|
93
|
+
background,
|
|
94
|
+
footer,
|
|
95
|
+
dimmed,
|
|
96
|
+
manualDestroy,
|
|
97
|
+
closeOnBackdropClick,
|
|
98
|
+
ForegroundComponent,
|
|
99
|
+
BackgroundComponent,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
reject(error);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const prompt = ({ defaultValue, title, subtitle, content, Input, disabled, returnOnCancel, background, footer, dimmed, manualDestroy, closeOnBackdropClick, ForegroundComponent, BackgroundComponent, }) => {
|
|
109
|
+
return new Promise((resolve, reject) => {
|
|
110
|
+
try {
|
|
111
|
+
ModalManager.open({
|
|
112
|
+
type: 'prompt',
|
|
113
|
+
resolve: (result) => resolve(result),
|
|
114
|
+
title,
|
|
115
|
+
subtitle,
|
|
116
|
+
content,
|
|
117
|
+
Input,
|
|
118
|
+
defaultValue,
|
|
119
|
+
disabled,
|
|
120
|
+
returnOnCancel,
|
|
121
|
+
background,
|
|
122
|
+
footer,
|
|
123
|
+
dimmed,
|
|
124
|
+
manualDestroy,
|
|
125
|
+
closeOnBackdropClick,
|
|
126
|
+
ForegroundComponent,
|
|
127
|
+
BackgroundComponent,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
reject(error);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
class AbstractNode {
|
|
137
|
+
id;
|
|
138
|
+
initiator;
|
|
139
|
+
title;
|
|
140
|
+
subtitle;
|
|
141
|
+
background;
|
|
142
|
+
manualDestroy;
|
|
143
|
+
closeOnBackdropClick;
|
|
144
|
+
dimmed;
|
|
145
|
+
ForegroundComponent;
|
|
146
|
+
BackgroundComponent;
|
|
147
|
+
#alive;
|
|
148
|
+
get alive() {
|
|
149
|
+
return this.#alive;
|
|
150
|
+
}
|
|
151
|
+
#visible;
|
|
152
|
+
get visible() {
|
|
153
|
+
return this.#visible;
|
|
154
|
+
}
|
|
155
|
+
#resolve;
|
|
156
|
+
#listeners = new Set();
|
|
157
|
+
constructor({ id, initiator, title, subtitle, background, dimmed = true, manualDestroy = false, closeOnBackdropClick = true, resolve, ForegroundComponent, BackgroundComponent, }) {
|
|
158
|
+
this.id = id;
|
|
159
|
+
this.initiator = initiator;
|
|
160
|
+
this.title = title;
|
|
161
|
+
this.subtitle = subtitle;
|
|
162
|
+
this.background = background;
|
|
163
|
+
this.dimmed = dimmed;
|
|
164
|
+
this.manualDestroy = manualDestroy;
|
|
165
|
+
this.closeOnBackdropClick = closeOnBackdropClick;
|
|
166
|
+
this.ForegroundComponent = ForegroundComponent;
|
|
167
|
+
this.BackgroundComponent = BackgroundComponent;
|
|
168
|
+
this.#alive = true;
|
|
169
|
+
this.#visible = true;
|
|
170
|
+
this.#resolve = resolve;
|
|
171
|
+
}
|
|
172
|
+
subscribe(listener) {
|
|
173
|
+
this.#listeners.add(listener);
|
|
174
|
+
return () => {
|
|
175
|
+
this.#listeners.delete(listener);
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
publish() {
|
|
179
|
+
for (const listener of this.#listeners)
|
|
180
|
+
listener();
|
|
181
|
+
}
|
|
182
|
+
resolve(result) {
|
|
183
|
+
this.#resolve(result);
|
|
184
|
+
}
|
|
185
|
+
onDestroy() {
|
|
186
|
+
const needPublish = this.#alive === true;
|
|
187
|
+
this.#alive = false;
|
|
188
|
+
if (this.manualDestroy && needPublish)
|
|
189
|
+
this.publish();
|
|
190
|
+
}
|
|
191
|
+
onShow() {
|
|
192
|
+
const needPublish = this.#visible === false;
|
|
193
|
+
this.#visible = true;
|
|
194
|
+
if (needPublish)
|
|
195
|
+
this.publish();
|
|
196
|
+
}
|
|
197
|
+
onHide() {
|
|
198
|
+
const needPublish = this.#visible === true;
|
|
199
|
+
this.#visible = false;
|
|
200
|
+
if (needPublish)
|
|
201
|
+
this.publish();
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
class AlertNode extends AbstractNode {
|
|
206
|
+
type;
|
|
207
|
+
subtype;
|
|
208
|
+
content;
|
|
209
|
+
footer;
|
|
210
|
+
constructor({ id, initiator, type, subtype, title, subtitle, content, footer, background, dimmed, manualDestroy, closeOnBackdropClick, resolve, ForegroundComponent, BackgroundComponent, }) {
|
|
211
|
+
super({
|
|
212
|
+
id,
|
|
213
|
+
initiator,
|
|
214
|
+
title,
|
|
215
|
+
subtitle,
|
|
216
|
+
background,
|
|
217
|
+
dimmed,
|
|
218
|
+
manualDestroy,
|
|
219
|
+
closeOnBackdropClick,
|
|
220
|
+
resolve,
|
|
221
|
+
ForegroundComponent,
|
|
222
|
+
BackgroundComponent,
|
|
223
|
+
});
|
|
224
|
+
this.type = type;
|
|
225
|
+
this.subtype = subtype;
|
|
226
|
+
this.content = content;
|
|
227
|
+
this.footer = footer;
|
|
228
|
+
}
|
|
229
|
+
onClose() {
|
|
230
|
+
this.resolve(null);
|
|
231
|
+
}
|
|
232
|
+
onConfirm() {
|
|
233
|
+
this.resolve(null);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
class ConfirmNode extends AbstractNode {
|
|
238
|
+
type;
|
|
239
|
+
subtype;
|
|
240
|
+
content;
|
|
241
|
+
footer;
|
|
242
|
+
constructor({ id, initiator, type, subtype, title, subtitle, content, footer, background, dimmed, manualDestroy, closeOnBackdropClick, resolve, ForegroundComponent, BackgroundComponent, }) {
|
|
243
|
+
super({
|
|
244
|
+
id,
|
|
245
|
+
initiator,
|
|
246
|
+
title,
|
|
247
|
+
subtitle,
|
|
248
|
+
background,
|
|
249
|
+
dimmed,
|
|
250
|
+
manualDestroy,
|
|
251
|
+
closeOnBackdropClick,
|
|
252
|
+
resolve,
|
|
253
|
+
ForegroundComponent,
|
|
254
|
+
BackgroundComponent,
|
|
255
|
+
});
|
|
256
|
+
this.type = type;
|
|
257
|
+
this.subtype = subtype;
|
|
258
|
+
this.content = content;
|
|
259
|
+
this.footer = footer;
|
|
260
|
+
}
|
|
261
|
+
onClose() {
|
|
262
|
+
this.resolve(false);
|
|
263
|
+
}
|
|
264
|
+
onConfirm() {
|
|
265
|
+
this.resolve(true);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
class PromptNode extends AbstractNode {
|
|
270
|
+
type;
|
|
271
|
+
content;
|
|
272
|
+
defaultValue;
|
|
273
|
+
Input;
|
|
274
|
+
disabled;
|
|
275
|
+
returnOnCancel;
|
|
276
|
+
footer;
|
|
277
|
+
#value;
|
|
278
|
+
constructor({ id, initiator, type, title, subtitle, content, defaultValue, Input, disabled, returnOnCancel, footer, background, dimmed, manualDestroy, closeOnBackdropClick, resolve, ForegroundComponent, BackgroundComponent, }) {
|
|
279
|
+
super({
|
|
280
|
+
id,
|
|
281
|
+
initiator,
|
|
282
|
+
title,
|
|
283
|
+
subtitle,
|
|
284
|
+
background,
|
|
285
|
+
dimmed,
|
|
286
|
+
manualDestroy,
|
|
287
|
+
closeOnBackdropClick,
|
|
288
|
+
resolve,
|
|
289
|
+
ForegroundComponent,
|
|
290
|
+
BackgroundComponent,
|
|
291
|
+
});
|
|
292
|
+
this.type = type;
|
|
293
|
+
this.content = content;
|
|
294
|
+
this.Input = Input;
|
|
295
|
+
this.defaultValue = defaultValue;
|
|
296
|
+
this.#value = defaultValue;
|
|
297
|
+
this.disabled = disabled;
|
|
298
|
+
this.returnOnCancel = returnOnCancel;
|
|
299
|
+
this.footer = footer;
|
|
300
|
+
}
|
|
301
|
+
onChange(value) {
|
|
302
|
+
this.#value = value;
|
|
303
|
+
}
|
|
304
|
+
onConfirm() {
|
|
305
|
+
this.resolve(this.#value ?? null);
|
|
306
|
+
}
|
|
307
|
+
onClose() {
|
|
308
|
+
if (this.returnOnCancel)
|
|
309
|
+
this.resolve(this.#value ?? null);
|
|
310
|
+
else
|
|
311
|
+
this.resolve(null);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const nodeFactory = (modal) => {
|
|
316
|
+
switch (modal.type) {
|
|
317
|
+
case 'alert':
|
|
318
|
+
return new AlertNode(modal);
|
|
319
|
+
case 'confirm':
|
|
320
|
+
return new ConfirmNode(modal);
|
|
321
|
+
case 'prompt':
|
|
322
|
+
return new PromptNode(modal);
|
|
323
|
+
}
|
|
324
|
+
throw new Error(`Unknown modal: ${modal.type}`, { modal });
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
const DEFAULT_ANIMATION_DURATION = '300ms';
|
|
328
|
+
const DEFAULT_BACKDROP_COLOR = 'rgba(0, 0, 0, 0.5)';
|
|
329
|
+
|
|
330
|
+
const fallback = css `
|
|
331
|
+
margin: unset;
|
|
332
|
+
`;
|
|
333
|
+
const frame = css `
|
|
334
|
+
display: flex;
|
|
335
|
+
flex-direction: column;
|
|
336
|
+
justify-content: center;
|
|
337
|
+
align-items: center;
|
|
338
|
+
background-color: white;
|
|
339
|
+
padding: 20px 80px;
|
|
340
|
+
gap: 10px;
|
|
341
|
+
border: 1px solid black;
|
|
342
|
+
`;
|
|
343
|
+
|
|
344
|
+
const FallbackTitle = ({ children }) => {
|
|
345
|
+
return jsx("h2", { className: fallback, children: children });
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
const FallbackSubtitle = ({ children }) => {
|
|
349
|
+
return jsx("h3", { className: fallback, children: children });
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
const FallbackContent = ({ children }) => {
|
|
353
|
+
return jsx("div", { className: fallback, children: children });
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
const FallbackFooter = ({ confirmLabel, hideConfirm = false, cancelLabel, hideCancel = false, disabled, onConfirm, onCancel, }) => {
|
|
357
|
+
return (jsxs("div", { children: [!hideConfirm && (jsx("button", { onClick: onConfirm, disabled: disabled, children: confirmLabel || 'Confirm' })), !hideCancel && typeof onCancel === 'function' && (jsx("button", { onClick: onCancel, children: cancelLabel || 'Cancel' }))] }));
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
const ModalManagerContext = createContext({});
|
|
361
|
+
|
|
362
|
+
const useModalManagerContext = () => useContext(ModalManagerContext);
|
|
363
|
+
const useModal = (id) => {
|
|
364
|
+
const { getModal } = useModalManagerContext();
|
|
365
|
+
return useMemo(() => getModal(id), [id, getModal]);
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
const defaultValidate = (modal) => modal?.visible;
|
|
369
|
+
const useActiveModalCount = (validate = defaultValidate, refreshKey = 0) => {
|
|
370
|
+
const { modalIds, getModalNode } = useModalManagerContext();
|
|
371
|
+
return useMemo(() => {
|
|
372
|
+
let count = 0;
|
|
373
|
+
for (const id of modalIds) {
|
|
374
|
+
if (validate(getModalNode(id)))
|
|
375
|
+
count++;
|
|
376
|
+
}
|
|
377
|
+
return count;
|
|
378
|
+
}, [getModalNode, modalIds, refreshKey]);
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
const MAX_MODAL_COUNT = 5;
|
|
382
|
+
const MAX_MODAL_LEVEL = 3;
|
|
383
|
+
const FallbackForegroundFrame = forwardRef(({ id, onChangeOrder, children }, ref) => {
|
|
384
|
+
const activeCount = useActiveModalCount();
|
|
385
|
+
const [level, offset] = useMemo(() => {
|
|
386
|
+
const stacked = activeCount > 1;
|
|
387
|
+
const level = stacked
|
|
388
|
+
? (Math.floor(id / MAX_MODAL_COUNT) % MAX_MODAL_LEVEL) * 100
|
|
389
|
+
: 0;
|
|
390
|
+
const offset = stacked ? (id % MAX_MODAL_COUNT) * 35 : 0;
|
|
391
|
+
return [level, offset];
|
|
392
|
+
}, [activeCount, id]);
|
|
393
|
+
return (jsx("div", { ref: ref, className: frame, onClick: onChangeOrder, style: {
|
|
394
|
+
marginBottom: `calc(25vh + ${level}px)`,
|
|
395
|
+
marginLeft: `${level}px`,
|
|
396
|
+
transform: `translate(${offset}px, ${offset}px)`,
|
|
397
|
+
}, children: children }));
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
const ConfigurationContext = createContext({});
|
|
401
|
+
|
|
402
|
+
const ConfigurationContextProvider = memo(({ ForegroundComponent, BackgroundComponent, TitleComponent, SubtitleComponent, ContentComponent, FooterComponent, options, children, }) => {
|
|
403
|
+
const value = useMemo(() => ({
|
|
404
|
+
BackgroundComponent,
|
|
405
|
+
ForegroundComponent: ForegroundComponent || FallbackForegroundFrame,
|
|
406
|
+
TitleComponent: TitleComponent || FallbackTitle,
|
|
407
|
+
SubtitleComponent: SubtitleComponent || FallbackSubtitle,
|
|
408
|
+
ContentComponent: memo(ContentComponent || FallbackContent),
|
|
409
|
+
FooterComponent: memo(FooterComponent || FallbackFooter),
|
|
410
|
+
options: {
|
|
411
|
+
duration: DEFAULT_ANIMATION_DURATION,
|
|
412
|
+
backdrop: DEFAULT_BACKDROP_COLOR,
|
|
413
|
+
closeOnBackdropClick: true,
|
|
414
|
+
manualDestroy: false,
|
|
415
|
+
...options,
|
|
416
|
+
},
|
|
417
|
+
}), [
|
|
418
|
+
ForegroundComponent,
|
|
419
|
+
BackgroundComponent,
|
|
420
|
+
ContentComponent,
|
|
421
|
+
FooterComponent,
|
|
422
|
+
SubtitleComponent,
|
|
423
|
+
TitleComponent,
|
|
424
|
+
options,
|
|
425
|
+
]);
|
|
426
|
+
return (jsx(ConfigurationContext.Provider, { value: value, children: children }));
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
const useConfigurationContext = () => useContext(ConfigurationContext);
|
|
430
|
+
const useConfigurationOptions = () => {
|
|
431
|
+
const context = useContext(ConfigurationContext);
|
|
432
|
+
return context.options;
|
|
433
|
+
};
|
|
434
|
+
const useConfigurationDuration = () => {
|
|
435
|
+
const context = useConfigurationOptions();
|
|
436
|
+
return {
|
|
437
|
+
duration: context.duration,
|
|
438
|
+
milliseconds: convertMsFromDuration(context.duration),
|
|
439
|
+
};
|
|
440
|
+
};
|
|
441
|
+
const useConfigurationBackdrop = () => {
|
|
442
|
+
const context = useConfigurationOptions();
|
|
443
|
+
return context.backdrop;
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
const ModalManagerContextProvider = memo(({ usePathname, children, }) => {
|
|
447
|
+
const modalDictionary = useRef(new Map());
|
|
448
|
+
const [modalIds, setModalIds] = useState([]);
|
|
449
|
+
const modalIdsRef = useReference(modalIds);
|
|
450
|
+
const { pathname } = usePathname();
|
|
451
|
+
const initiator = useRef(pathname);
|
|
452
|
+
const modalIdSequence = useRef(0);
|
|
453
|
+
const options = useConfigurationOptions();
|
|
454
|
+
const duration = useMemo(() => convertMsFromDuration(options.duration), [options]);
|
|
455
|
+
useOnMountLayout(() => {
|
|
456
|
+
const { manualDestroy, closeOnBackdropClick } = options;
|
|
457
|
+
for (const data of ModalManager.prerender) {
|
|
458
|
+
const modal = nodeFactory({
|
|
459
|
+
...data,
|
|
460
|
+
id: modalIdSequence.current++,
|
|
461
|
+
initiator: initiator.current,
|
|
462
|
+
manualDestroy: data.manualDestroy !== undefined
|
|
463
|
+
? data.manualDestroy
|
|
464
|
+
: manualDestroy,
|
|
465
|
+
closeOnBackdropClick: data.closeOnBackdropClick !== undefined
|
|
466
|
+
? data.closeOnBackdropClick
|
|
467
|
+
: closeOnBackdropClick,
|
|
468
|
+
});
|
|
469
|
+
modalDictionary.current.set(modal.id, modal);
|
|
470
|
+
setModalIds((ids) => [...ids, modal.id]);
|
|
471
|
+
}
|
|
472
|
+
ModalManager.openHandler = (data) => {
|
|
473
|
+
const modal = nodeFactory({
|
|
474
|
+
...data,
|
|
475
|
+
id: modalIdSequence.current++,
|
|
476
|
+
initiator: initiator.current,
|
|
477
|
+
manualDestroy: data.manualDestroy !== undefined
|
|
478
|
+
? data.manualDestroy
|
|
479
|
+
: manualDestroy,
|
|
480
|
+
closeOnBackdropClick: data.closeOnBackdropClick !== undefined
|
|
481
|
+
? data.closeOnBackdropClick
|
|
482
|
+
: closeOnBackdropClick,
|
|
483
|
+
});
|
|
484
|
+
modalDictionary.current.set(modal.id, modal);
|
|
485
|
+
setModalIds((ids) => {
|
|
486
|
+
const aliveIds = [];
|
|
487
|
+
for (let index = 0; index < ids.length; index++) {
|
|
488
|
+
const id = ids[index];
|
|
489
|
+
const destroyed = !modalDictionary.current.get(id)?.alive;
|
|
490
|
+
if (destroyed)
|
|
491
|
+
modalDictionary.current.delete(id);
|
|
492
|
+
else
|
|
493
|
+
aliveIds.push(id);
|
|
494
|
+
}
|
|
495
|
+
return [...aliveIds, modal.id];
|
|
496
|
+
});
|
|
497
|
+
};
|
|
498
|
+
return () => {
|
|
499
|
+
ModalManager.reset();
|
|
500
|
+
};
|
|
501
|
+
});
|
|
502
|
+
useLayoutEffect(() => {
|
|
503
|
+
for (const id of modalIdsRef.current) {
|
|
504
|
+
const modal = modalDictionary.current.get(id);
|
|
505
|
+
if (!modal?.alive)
|
|
506
|
+
continue;
|
|
507
|
+
if (modal.initiator === pathname)
|
|
508
|
+
modal.onShow();
|
|
509
|
+
else
|
|
510
|
+
modal.onHide();
|
|
511
|
+
}
|
|
512
|
+
initiator.current = pathname;
|
|
513
|
+
}, [pathname]);
|
|
514
|
+
const getModalNode = useCallback((modalId) => {
|
|
515
|
+
return modalDictionary.current.get(modalId);
|
|
516
|
+
}, []);
|
|
517
|
+
const onDestroy = useCallback((modalId) => {
|
|
518
|
+
const modal = modalDictionary.current.get(modalId);
|
|
519
|
+
if (!modal)
|
|
520
|
+
return;
|
|
521
|
+
modal.onDestroy();
|
|
522
|
+
updaterRef.current?.();
|
|
523
|
+
}, []);
|
|
524
|
+
const updaterRef = useRef(undefined);
|
|
525
|
+
const hideModal = useCallback((modalId) => {
|
|
526
|
+
const modal = modalDictionary.current.get(modalId);
|
|
527
|
+
if (!modal)
|
|
528
|
+
return;
|
|
529
|
+
modal.onHide();
|
|
530
|
+
updaterRef.current?.();
|
|
531
|
+
if (!modal.manualDestroy)
|
|
532
|
+
setTimeout(() => {
|
|
533
|
+
modal.onDestroy();
|
|
534
|
+
}, duration);
|
|
535
|
+
}, [duration]);
|
|
536
|
+
const onChange = useCallback((modalId, value) => {
|
|
537
|
+
const modal = modalDictionary.current.get(modalId);
|
|
538
|
+
if (!modal)
|
|
539
|
+
return;
|
|
540
|
+
if (modal.type === 'prompt')
|
|
541
|
+
modal.onChange(value);
|
|
542
|
+
}, []);
|
|
543
|
+
const onConfirm = useCallback((modalId) => {
|
|
544
|
+
const modal = modalDictionary.current.get(modalId);
|
|
545
|
+
if (!modal)
|
|
546
|
+
return;
|
|
547
|
+
modal.onConfirm();
|
|
548
|
+
hideModal(modalId);
|
|
549
|
+
}, [hideModal]);
|
|
550
|
+
const onClose = useCallback((modalId) => {
|
|
551
|
+
const modal = modalDictionary.current.get(modalId);
|
|
552
|
+
if (!modal)
|
|
553
|
+
return;
|
|
554
|
+
modal.onClose();
|
|
555
|
+
hideModal(modalId);
|
|
556
|
+
}, [hideModal]);
|
|
557
|
+
const getModal = useCallback((modalId) => ({
|
|
558
|
+
modal: getModalNode(modalId),
|
|
559
|
+
onConfirm: () => onConfirm(modalId),
|
|
560
|
+
onClose: () => onClose(modalId),
|
|
561
|
+
onChange: (value) => onChange(modalId, value),
|
|
562
|
+
onDestroy: () => onDestroy(modalId),
|
|
563
|
+
}), [getModalNode, onConfirm, onClose, onChange, onDestroy]);
|
|
564
|
+
const value = useMemo(() => {
|
|
565
|
+
return {
|
|
566
|
+
modalIds,
|
|
567
|
+
getModalNode,
|
|
568
|
+
onChange,
|
|
569
|
+
onConfirm,
|
|
570
|
+
onClose,
|
|
571
|
+
onDestroy,
|
|
572
|
+
getModal,
|
|
573
|
+
setUpdater: (updater) => {
|
|
574
|
+
updaterRef.current = updater;
|
|
575
|
+
},
|
|
576
|
+
};
|
|
577
|
+
}, [
|
|
578
|
+
modalIds,
|
|
579
|
+
getModal,
|
|
580
|
+
getModalNode,
|
|
581
|
+
onChange,
|
|
582
|
+
onConfirm,
|
|
583
|
+
onClose,
|
|
584
|
+
onDestroy,
|
|
585
|
+
]);
|
|
586
|
+
return (jsx(ModalManagerContext.Provider, { value: value, children: children }));
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
const UserDefinedContext = createContext({});
|
|
590
|
+
|
|
591
|
+
const UserDefinedContextProvider = ({ context, children, }) => {
|
|
592
|
+
const contextValue = useMemo(() => ({ context: context || {} }), [context]);
|
|
593
|
+
return (jsx(UserDefinedContext.Provider, { value: contextValue, children: children }));
|
|
594
|
+
};
|
|
595
|
+
|
|
596
|
+
const useUserDefinedContext = () => {
|
|
597
|
+
return useContext(UserDefinedContext);
|
|
598
|
+
};
|
|
599
|
+
|
|
600
|
+
const usePathname = () => {
|
|
601
|
+
const [pathname, setPathname] = useState(window.location.pathname);
|
|
602
|
+
useLayoutEffect(() => {
|
|
603
|
+
let requestId;
|
|
604
|
+
const checkPathname = () => {
|
|
605
|
+
if (requestId)
|
|
606
|
+
cancelAnimationFrame(requestId);
|
|
607
|
+
if (pathname !== window.location.pathname) {
|
|
608
|
+
setPathname(window.location.pathname);
|
|
609
|
+
}
|
|
610
|
+
else {
|
|
611
|
+
requestId = requestAnimationFrame(checkPathname);
|
|
612
|
+
}
|
|
613
|
+
};
|
|
614
|
+
requestId = requestAnimationFrame(checkPathname);
|
|
615
|
+
return () => {
|
|
616
|
+
if (requestId)
|
|
617
|
+
cancelAnimationFrame(requestId);
|
|
618
|
+
};
|
|
619
|
+
}, [pathname]);
|
|
620
|
+
return { pathname };
|
|
621
|
+
};
|
|
622
|
+
|
|
623
|
+
const background = css `
|
|
624
|
+
display: none;
|
|
625
|
+
position: fixed;
|
|
626
|
+
inset: 0;
|
|
627
|
+
z-index: -999;
|
|
628
|
+
pointer-events: none;
|
|
629
|
+
> * {
|
|
630
|
+
pointer-events: none;
|
|
631
|
+
}
|
|
632
|
+
`;
|
|
633
|
+
const active$1 = css `
|
|
634
|
+
pointer-events: all;
|
|
635
|
+
`;
|
|
636
|
+
const visible$1 = css `
|
|
637
|
+
display: flex;
|
|
638
|
+
align-items: center;
|
|
639
|
+
justify-content: center;
|
|
640
|
+
`;
|
|
641
|
+
|
|
642
|
+
const BackgroundFrame = ({ modalId, onChangeOrder, }) => {
|
|
643
|
+
const { BackgroundComponent } = useConfigurationContext();
|
|
644
|
+
const { context: userDefinedContext } = useUserDefinedContext();
|
|
645
|
+
const { modal, onClose, onChange, onConfirm, onDestroy } = useModal(modalId);
|
|
646
|
+
const handleClose = useCallback((event) => {
|
|
647
|
+
if (modal && modal.closeOnBackdropClick && modal.visible)
|
|
648
|
+
onClose();
|
|
649
|
+
event.stopPropagation();
|
|
650
|
+
}, [modal, onClose]);
|
|
651
|
+
const Background = useMemo(() => modal?.BackgroundComponent || BackgroundComponent, [BackgroundComponent, modal]);
|
|
652
|
+
if (!modal)
|
|
653
|
+
return null;
|
|
654
|
+
return (jsx("div", { className: cx(background, {
|
|
655
|
+
[visible$1]: modal.manualDestroy ? modal.alive : modal.visible,
|
|
656
|
+
[active$1]: modal.closeOnBackdropClick && modal.visible,
|
|
657
|
+
}), onClick: handleClose, children: Background && (jsx(Background, { id: modal.id, type: modal.type, alive: modal.alive, visible: modal.visible, initiator: modal.initiator, manualDestroy: modal.manualDestroy, closeOnBackdropClick: modal.closeOnBackdropClick, background: modal.background, onChange: onChange, onConfirm: onConfirm, onClose: onClose, onDestroy: onDestroy, onChangeOrder: onChangeOrder, context: userDefinedContext })) }));
|
|
658
|
+
};
|
|
659
|
+
|
|
660
|
+
const foreground = css `
|
|
661
|
+
pointer-events: none;
|
|
662
|
+
display: none;
|
|
663
|
+
position: fixed;
|
|
664
|
+
inset: 0;
|
|
665
|
+
z-index: 1;
|
|
666
|
+
`;
|
|
667
|
+
const active = css `
|
|
668
|
+
> * {
|
|
669
|
+
pointer-events: all;
|
|
670
|
+
}
|
|
671
|
+
`;
|
|
672
|
+
const visible = css `
|
|
673
|
+
display: flex !important;
|
|
674
|
+
justify-content: center;
|
|
675
|
+
align-items: center;
|
|
676
|
+
`;
|
|
677
|
+
|
|
678
|
+
const AlertInner = memo(({ modal, handlers }) => {
|
|
679
|
+
const { title, subtitle, content, footer } = useMemo(() => modal, [modal]);
|
|
680
|
+
const { context: userDefinedContext } = useUserDefinedContext();
|
|
681
|
+
const { onConfirm } = useMemo(() => handlers, [handlers]);
|
|
682
|
+
const handleConfirm = useHandle(onConfirm);
|
|
683
|
+
const { TitleComponent, SubtitleComponent, ContentComponent, FooterComponent, } = useConfigurationContext();
|
|
684
|
+
return (jsxs(Fragment, { children: [title &&
|
|
685
|
+
(isString(title) ? (jsx(TitleComponent, { context: userDefinedContext, children: title })) : (title)), subtitle &&
|
|
686
|
+
(isString(subtitle) ? (jsx(SubtitleComponent, { context: userDefinedContext, children: subtitle })) : (subtitle)), content &&
|
|
687
|
+
(isString(content) ? (jsx(ContentComponent, { context: userDefinedContext, children: content })) : (renderComponent(content, {
|
|
688
|
+
onConfirm: handleConfirm,
|
|
689
|
+
}))), footer !== false &&
|
|
690
|
+
(typeof footer === 'function' ? (footer({
|
|
691
|
+
onConfirm: handleConfirm,
|
|
692
|
+
context: userDefinedContext,
|
|
693
|
+
})) : (jsx(FooterComponent, { onConfirm: handleConfirm, confirmLabel: footer?.confirm, hideConfirm: footer?.hideConfirm, context: userDefinedContext })))] }));
|
|
694
|
+
});
|
|
695
|
+
|
|
696
|
+
const ConfirmInner = memo(({ modal, handlers }) => {
|
|
697
|
+
const { title, subtitle, content, footer } = useMemo(() => modal, [modal]);
|
|
698
|
+
const { context: userDefinedContext } = useUserDefinedContext();
|
|
699
|
+
const { onConfirm, onClose } = useMemo(() => handlers, [handlers]);
|
|
700
|
+
const handleConfirm = useHandle(onConfirm);
|
|
701
|
+
const handleClose = useHandle(onClose);
|
|
702
|
+
const { TitleComponent, SubtitleComponent, ContentComponent, FooterComponent, } = useConfigurationContext();
|
|
703
|
+
return (jsxs(Fragment, { children: [title &&
|
|
704
|
+
(isString(title) ? (jsx(TitleComponent, { context: userDefinedContext, children: title })) : (title)), subtitle &&
|
|
705
|
+
(isString(subtitle) ? (jsx(SubtitleComponent, { context: userDefinedContext, children: subtitle })) : (subtitle)), content &&
|
|
706
|
+
(isString(content) ? (jsx(ContentComponent, { context: userDefinedContext, children: content })) : (renderComponent(content, {
|
|
707
|
+
onConfirm: handleConfirm,
|
|
708
|
+
onCancel: handleClose,
|
|
709
|
+
context: userDefinedContext,
|
|
710
|
+
}))), footer !== false &&
|
|
711
|
+
(typeof footer === 'function' ? (footer({
|
|
712
|
+
onConfirm: handleConfirm,
|
|
713
|
+
onCancel: handleClose,
|
|
714
|
+
context: userDefinedContext,
|
|
715
|
+
})) : (jsx(FooterComponent, { onConfirm: handleConfirm, onCancel: handleClose, confirmLabel: footer?.confirm, cancelLabel: footer?.cancel, hideConfirm: footer?.hideConfirm, hideCancel: footer?.hideCancel, context: userDefinedContext })))] }));
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
const PromptInner = memo(({ modal, handlers }) => {
|
|
719
|
+
const { Input, defaultValue, disabled: checkDisabled, title, subtitle, content, footer, } = useMemo(() => ({
|
|
720
|
+
...modal,
|
|
721
|
+
Input: memo(withErrorBoundary(modal.Input)),
|
|
722
|
+
}), [modal]);
|
|
723
|
+
const { context: userDefinedContext } = useUserDefinedContext();
|
|
724
|
+
const [value, setValue] = useState(defaultValue);
|
|
725
|
+
const { onChange, onClose, onConfirm } = useMemo(() => handlers, [handlers]);
|
|
726
|
+
const handleClose = useHandle(onClose);
|
|
727
|
+
const handleChange = useHandle((inputValue) => {
|
|
728
|
+
const input = isFunction(inputValue) ? inputValue(value) : inputValue;
|
|
729
|
+
setValue(input);
|
|
730
|
+
onChange(input);
|
|
731
|
+
});
|
|
732
|
+
const handleConfirm = useCallback(() => {
|
|
733
|
+
requestAnimationFrame(onConfirm);
|
|
734
|
+
}, [onConfirm]);
|
|
735
|
+
const disabled = useMemo(() => (value ? !!checkDisabled?.(value) : false), [checkDisabled, value]);
|
|
736
|
+
const { TitleComponent, SubtitleComponent, ContentComponent, FooterComponent, } = useConfigurationContext();
|
|
737
|
+
return (jsxs(Fragment, { children: [title &&
|
|
738
|
+
(isString(title) ? (jsx(TitleComponent, { context: userDefinedContext, children: title })) : (title)), subtitle &&
|
|
739
|
+
(isString(subtitle) ? (jsx(SubtitleComponent, { context: userDefinedContext, children: subtitle })) : (subtitle)), content &&
|
|
740
|
+
(isString(content) ? (jsx(ContentComponent, { context: userDefinedContext, children: content })) : (renderComponent(content, {
|
|
741
|
+
onConfirm: handleConfirm,
|
|
742
|
+
onCancel: handleClose,
|
|
743
|
+
context: userDefinedContext,
|
|
744
|
+
}))), Input && (jsx(Input, { defaultValue: defaultValue, value: value, onChange: handleChange, onConfirm: handleConfirm, onCancel: handleClose, context: userDefinedContext })), footer !== false &&
|
|
745
|
+
(typeof footer === 'function' ? (footer({
|
|
746
|
+
value,
|
|
747
|
+
disabled,
|
|
748
|
+
onChange: handleChange,
|
|
749
|
+
onConfirm: handleConfirm,
|
|
750
|
+
onCancel: handleClose,
|
|
751
|
+
context: userDefinedContext,
|
|
752
|
+
})) : (jsx(FooterComponent, { disabled: disabled, onConfirm: handleConfirm, onCancel: handleClose, confirmLabel: footer?.confirm, cancelLabel: footer?.cancel, hideConfirm: footer?.hideConfirm, hideCancel: footer?.hideCancel, context: userDefinedContext })))] }));
|
|
753
|
+
});
|
|
754
|
+
|
|
755
|
+
const ForegroundFrame = ({ modalId, onChangeOrder, }) => {
|
|
756
|
+
const { ForegroundComponent } = useConfigurationContext();
|
|
757
|
+
const { context: userDefinedContext } = useUserDefinedContext();
|
|
758
|
+
const { modal, onChange, onConfirm, onClose, onDestroy } = useModal(modalId);
|
|
759
|
+
const Foreground = useMemo(() => modal?.ForegroundComponent || ForegroundComponent, [ForegroundComponent, modal]);
|
|
760
|
+
if (!modal)
|
|
761
|
+
return null;
|
|
762
|
+
return (jsx("div", { className: cx(foreground, {
|
|
763
|
+
[visible]: modal.manualDestroy ? modal.alive : modal.visible,
|
|
764
|
+
[active]: modal.visible,
|
|
765
|
+
}), children: jsxs(Foreground, { id: modal.id, type: modal.type, alive: modal.alive, visible: modal.visible, initiator: modal.initiator, manualDestroy: modal.manualDestroy, closeOnBackdropClick: modal.closeOnBackdropClick, background: modal.background, onChange: onChange, onConfirm: onConfirm, onClose: onClose, onDestroy: onDestroy, onChangeOrder: onChangeOrder, context: userDefinedContext, children: [modal.type === 'alert' && (jsx(AlertInner, { modal: modal, handlers: { onConfirm } })), modal.type === 'confirm' && (jsx(ConfirmInner, { modal: modal, handlers: { onConfirm, onClose } })), modal.type === 'prompt' && (jsx(PromptInner, { modal: modal, handlers: { onChange, onConfirm, onClose } }))] }) }));
|
|
766
|
+
};
|
|
767
|
+
|
|
768
|
+
const useSubscribeModal = (modal) => {
|
|
769
|
+
const [version, update] = useVersion();
|
|
770
|
+
useEffect(() => {
|
|
771
|
+
if (!modal)
|
|
772
|
+
return;
|
|
773
|
+
const unsubscribe = modal.subscribe(update);
|
|
774
|
+
return unsubscribe;
|
|
775
|
+
}, [modal, update]);
|
|
776
|
+
return version;
|
|
777
|
+
};
|
|
778
|
+
|
|
779
|
+
const presenter = css `
|
|
780
|
+
position: fixed;
|
|
781
|
+
inset: 0;
|
|
782
|
+
pointer-events: none;
|
|
783
|
+
overflow: hidden;
|
|
784
|
+
`;
|
|
785
|
+
|
|
786
|
+
const { increment } = counterFactory(1);
|
|
787
|
+
const Presenter = memo(({ modalId }) => {
|
|
788
|
+
const ref = useRef(null);
|
|
789
|
+
const { modal } = useModal(modalId);
|
|
790
|
+
useSubscribeModal(modal);
|
|
791
|
+
const handleChangeOrder = useHandle(() => {
|
|
792
|
+
if (ref.current) {
|
|
793
|
+
ref.current.style.zIndex = `${increment()}`;
|
|
794
|
+
}
|
|
795
|
+
});
|
|
796
|
+
return (jsxs("div", { ref: ref, className: presenter, children: [jsx(BackgroundFrame, { modalId: modalId, onChangeOrder: handleChangeOrder }), jsx(ForegroundFrame, { modalId: modalId, onChangeOrder: handleChangeOrder })] }));
|
|
797
|
+
});
|
|
798
|
+
|
|
799
|
+
const anchor = css `
|
|
800
|
+
display: flex;
|
|
801
|
+
align-items: center;
|
|
802
|
+
justify-content: center;
|
|
803
|
+
position: fixed;
|
|
804
|
+
inset: 0;
|
|
805
|
+
pointer-events: none;
|
|
806
|
+
z-index: 1000;
|
|
807
|
+
transition: background-color ease-in-out;
|
|
808
|
+
`;
|
|
809
|
+
|
|
810
|
+
const AnchorInner = () => {
|
|
811
|
+
const [version, update] = useVersion();
|
|
812
|
+
const { modalIds, setUpdater } = useModalManagerContext();
|
|
813
|
+
useEffect(() => {
|
|
814
|
+
setUpdater(update);
|
|
815
|
+
}, [setUpdater, update]);
|
|
816
|
+
const options = useConfigurationOptions();
|
|
817
|
+
const dimmed = useActiveModalCount(validateDimmable, version);
|
|
818
|
+
return (jsx("div", { className: anchor, style: {
|
|
819
|
+
transitionDuration: options.duration,
|
|
820
|
+
backgroundColor: dimmed ? options.backdrop : 'transparent',
|
|
821
|
+
}, children: map(modalIds, (id) => (jsx(Presenter, { modalId: id }, id))) }));
|
|
822
|
+
};
|
|
823
|
+
const validateDimmable = (modal) => modal?.visible && modal.dimmed;
|
|
824
|
+
const Anchor = memo(withErrorBoundary(AnchorInner));
|
|
825
|
+
|
|
826
|
+
const bootstrap = ({ ForegroundComponent, BackgroundComponent, TitleComponent, SubtitleComponent, ContentComponent, FooterComponent, usePathname, options, context, anchor, }) => createPortal(jsx(UserDefinedContextProvider, { context: context, children: jsx(ConfigurationContextProvider, { ForegroundComponent: ForegroundComponent, BackgroundComponent: BackgroundComponent, TitleComponent: TitleComponent, SubtitleComponent: SubtitleComponent, ContentComponent: ContentComponent, FooterComponent: FooterComponent, options: options, children: jsx(ModalManagerContextProvider, { usePathname: usePathname, children: jsx(Anchor, {}) }) }) }), anchor);
|
|
827
|
+
|
|
828
|
+
const useInitialize = () => {
|
|
829
|
+
const permitted = useRef(ModalManager.activate());
|
|
830
|
+
const anchorRef = useRef(null);
|
|
831
|
+
const [, update] = useVersion();
|
|
832
|
+
const handleInitialize = useCallback((root) => {
|
|
833
|
+
if (permitted.current) {
|
|
834
|
+
anchorRef.current = ModalManager.anchor({ root });
|
|
835
|
+
update();
|
|
836
|
+
}
|
|
837
|
+
else
|
|
838
|
+
printError('ModalProvider is already initialized', [
|
|
839
|
+
'ModalProvider can only be initialized once.',
|
|
840
|
+
'Nesting ModalProvider will be ignored...',
|
|
841
|
+
], {
|
|
842
|
+
info: 'Something is wrong with the ModalProvider initialization...',
|
|
843
|
+
});
|
|
844
|
+
}, [update]);
|
|
845
|
+
return {
|
|
846
|
+
anchorRef,
|
|
847
|
+
handleInitialize,
|
|
848
|
+
};
|
|
849
|
+
};
|
|
850
|
+
|
|
851
|
+
const BootstrapProvider = forwardRef(({ usePathname: useExternalPathname, ForegroundComponent, BackgroundComponent, TitleComponent, SubtitleComponent, ContentComponent, FooterComponent, options, context, children, }, handleRef) => {
|
|
852
|
+
const usePathname$1 = useMemo(() => useExternalPathname || usePathname, [useExternalPathname]);
|
|
853
|
+
const { anchorRef, handleInitialize } = useInitialize();
|
|
854
|
+
useImperativeHandle(handleRef, () => ({
|
|
855
|
+
initialize: handleInitialize,
|
|
856
|
+
}), [handleInitialize]);
|
|
857
|
+
useOnMount(() => {
|
|
858
|
+
if (handleRef === null)
|
|
859
|
+
handleInitialize();
|
|
860
|
+
return () => {
|
|
861
|
+
if (anchorRef.current)
|
|
862
|
+
anchorRef.current.remove();
|
|
863
|
+
};
|
|
864
|
+
});
|
|
865
|
+
return (jsxs(Fragment, { children: [children, anchorRef.current &&
|
|
866
|
+
bootstrap({
|
|
867
|
+
ForegroundComponent,
|
|
868
|
+
BackgroundComponent,
|
|
869
|
+
TitleComponent,
|
|
870
|
+
SubtitleComponent,
|
|
871
|
+
ContentComponent,
|
|
872
|
+
FooterComponent,
|
|
873
|
+
usePathname: usePathname$1,
|
|
874
|
+
options,
|
|
875
|
+
context,
|
|
876
|
+
anchor: anchorRef.current,
|
|
877
|
+
})] }));
|
|
878
|
+
});
|
|
879
|
+
|
|
880
|
+
const useBootstrap = ({ usePathname: useExternalPathname, ForegroundComponent, BackgroundComponent, TitleComponent, SubtitleComponent, ContentComponent, FooterComponent, options, context, mode = 'auto', } = {}) => {
|
|
881
|
+
const usePathname$1 = useMemo(() => useExternalPathname || usePathname, [useExternalPathname]);
|
|
882
|
+
const { anchorRef, handleInitialize } = useInitialize();
|
|
883
|
+
useOnMount(() => {
|
|
884
|
+
if (mode === 'auto')
|
|
885
|
+
handleInitialize();
|
|
886
|
+
return () => {
|
|
887
|
+
if (anchorRef.current)
|
|
888
|
+
anchorRef.current.remove();
|
|
889
|
+
};
|
|
890
|
+
});
|
|
891
|
+
const initialize = useCallback((element) => {
|
|
892
|
+
if (mode === 'manual')
|
|
893
|
+
handleInitialize(element);
|
|
894
|
+
}, [mode, handleInitialize]);
|
|
895
|
+
const portal = anchorRef.current &&
|
|
896
|
+
bootstrap({
|
|
897
|
+
usePathname: usePathname$1,
|
|
898
|
+
ForegroundComponent,
|
|
899
|
+
BackgroundComponent,
|
|
900
|
+
TitleComponent,
|
|
901
|
+
SubtitleComponent,
|
|
902
|
+
ContentComponent,
|
|
903
|
+
FooterComponent,
|
|
904
|
+
options,
|
|
905
|
+
context,
|
|
906
|
+
anchor: anchorRef.current,
|
|
907
|
+
});
|
|
908
|
+
return { portal, initialize };
|
|
909
|
+
};
|
|
910
|
+
|
|
911
|
+
const useDestroyAfter = (modalId, duration) => {
|
|
912
|
+
const { modal, onDestroy } = useModal(modalId);
|
|
913
|
+
const tick = useSubscribeModal(modal);
|
|
914
|
+
const reference = useRef({
|
|
915
|
+
modal,
|
|
916
|
+
onDestroy,
|
|
917
|
+
milliseconds: isString(duration)
|
|
918
|
+
? convertMsFromDuration(duration)
|
|
919
|
+
: duration,
|
|
920
|
+
});
|
|
921
|
+
useEffect(() => {
|
|
922
|
+
const { modal, onDestroy, milliseconds } = reference.current;
|
|
923
|
+
if (!modal || modal.visible || !modal.alive)
|
|
924
|
+
return;
|
|
925
|
+
const timer = setTimeout(() => {
|
|
926
|
+
onDestroy();
|
|
927
|
+
}, milliseconds);
|
|
928
|
+
return () => {
|
|
929
|
+
if (timer)
|
|
930
|
+
clearTimeout(timer);
|
|
931
|
+
};
|
|
932
|
+
}, [tick]);
|
|
933
|
+
};
|
|
934
|
+
|
|
935
|
+
const useModalAnimation = (visible, handler) => {
|
|
936
|
+
const handlerRef = useRef(handler);
|
|
937
|
+
handlerRef.current = handler;
|
|
938
|
+
useLayoutEffect(() => {
|
|
939
|
+
if (!handlerRef.current)
|
|
940
|
+
return;
|
|
941
|
+
let frame;
|
|
942
|
+
if (visible)
|
|
943
|
+
frame = requestAnimationFrame(() => handlerRef.current.onVisible?.());
|
|
944
|
+
else
|
|
945
|
+
frame = requestAnimationFrame(() => handlerRef.current.onHidden?.());
|
|
946
|
+
return () => {
|
|
947
|
+
if (frame)
|
|
948
|
+
cancelAnimationFrame(frame);
|
|
949
|
+
};
|
|
950
|
+
}, [visible]);
|
|
951
|
+
};
|
|
952
|
+
|
|
953
|
+
export { BootstrapProvider as ModalProvider, alert, confirm, prompt, useActiveModalCount, useDestroyAfter, useBootstrap as useInitializeModal, useModalAnimation, useConfigurationBackdrop as useModalBackdrop, useConfigurationDuration as useModalDuration, useConfigurationOptions as useModalOptions, useSubscribeModal };
|