UNPKG

react-snappy-modal

Version:

Flexible and easy-to-use modal library for React, supporting customizable dialogs with promise-based interactions.

1 lines 10.1 kB
{"version":3,"sources":["../src/SnappyModal.tsx","../src/context/useSnappyModalState.tsx","../src/context/SnappyModalContext.tsx","../src/index.ts"],"sourcesContent":["import React from \"react\";\nimport ReactDOM from \"react-dom/client\";\nimport \"./SnappyModal.css\";\nimport { SnappyModalExternalStore } from \"./context/useSnappyModalState\";\n\nconst currentComponents: ModalProgress[] = [];\nexport class SnappyModal {\n static isShow() {\n return currentComponents.length > 0;\n }\n\n static getCurrentComponent(layer: number) {\n return currentComponents.find(c => c.options.layer === layer);\n }\n\n static removeModalProcess(layer: number) {\n const index = currentComponents.findIndex(c => c.options.layer === layer);\n if (index === -1) return;\n currentComponents.splice(index, 1);\n SnappyModalExternalStore.emitChange();\n }\n\n static getModalProcess() {\n return currentComponents;\n }\n\n static close(value?: any, layer = 0) {\n const currentComponent = this.getCurrentComponent(layer);\n currentComponent?.resolve(value);\n this.removeModalProcess(layer);\n }\n\n static throw(thrower?: any, layer = 0) {\n const currentComponent = this.getCurrentComponent(layer);\n currentComponent?.throw(thrower);\n this.removeModalProcess(layer);\n currentComponent?.throw(thrower);\n }\n\n static show(\n component: React.ReactElement,\n options?: SnappyModalOptions,\n ): Promise<any> {\n const dialogOptions = {\n ...defaultDialogOptions,\n ...options,\n };\n\n return new Promise((resolve, reject) => {\n currentComponents.push({\n component: () => <React.Fragment>{component}</React.Fragment>,\n options: dialogOptions,\n resolve: (value: any) => {\n resolve(value);\n SnappyModalExternalStore.emitChange();\n },\n throw: (thrower: any) => {\n reject(thrower);\n SnappyModalExternalStore.emitChange();\n },\n });\n currentComponents.sort((a, b) => a.options.layer - b.options.layer);\n SnappyModalExternalStore.emitChange();\n });\n }\n}\n\nexport interface ModalProgress {\n component: React.FC<any>;\n options: SnappyModalOptions;\n resolve: (value?: any) => void;\n throw: (thrower?: any) => void;\n}\n\nconst defaultDialogOptions: SnappyModalOptions = {\n allowOutsideClick: true,\n allowScroll: false,\n backdrop: true,\n position: \"center\",\n layer: 0,\n};\n\ntype SnappyModalPosition =\n | \"top-left\"\n | \"top-center\"\n | \"top-right\"\n | \"center-left\"\n | \"center\"\n | \"center-right\"\n | \"bottom-left\"\n | \"bottom-center\"\n | \"bottom-right\";\n\nexport type SnappyModalOptions = {\n allowOutsideClick?: boolean;\n allowScroll?: boolean;\n backdrop?: boolean | string;\n position?: SnappyModalPosition;\n zIndex?: number;\n layer?: number;\n};\n","import { ModalProgress, SnappyModal } from \"../SnappyModal\";\nimport { useSyncExternalStore } from \"react\";\n\nlet snappyModalListeners = [];\nlet snappyModalState: {\n isShow: boolean;\n modalProgress: ModalProgress[];\n} = {\n isShow: false,\n modalProgress: [],\n};\n\nfunction emitChange() {\n for (const listener of snappyModalListeners) {\n listener();\n }\n}\n\nexport const SnappyModalExternalStore = {\n emitChange: () => {\n snappyModalState = {\n isShow: SnappyModal.isShow(),\n modalProgress: [...SnappyModal.getModalProcess()],\n };\n emitChange();\n },\n subscribe(listener: () => unknown) {\n snappyModalListeners = [...snappyModalListeners, listener];\n return () => {\n snappyModalListeners = snappyModalListeners.filter(l => l !== listener);\n };\n },\n getSnappyModalState() {\n return snappyModalState;\n },\n};\n\nexport const useSnappyModalState = () => {\n return useSyncExternalStore(\n SnappyModalExternalStore.subscribe,\n SnappyModalExternalStore.getSnappyModalState,\n );\n};\n","import { createContext, useEffect, useMemo } from \"react\";\nimport { useSnappyModalState } from \"./useSnappyModalState\";\nimport { SnappyModal, SnappyModalOptions } from \"../SnappyModal\";\n\nconst SnappyModalContext = createContext({});\n\nexport const SnappyModalProvider = ({ children }) => {\n const snappyModal = useSnappyModalState();\n\n useEffect(() => {\n if (!snappyModal.isShow) return;\n\n const htmlElement = document.getElementsByTagName(\"html\")[0];\n const pageX = window.scrollX;\n const pageY = window.scrollY;\n htmlElement.style.top = `-${pageY}px`;\n htmlElement.style.left = `-${pageX}px`;\n htmlElement.classList.add(\"not-scroll\");\n\n return () => {\n htmlElement.style.top = \"\";\n htmlElement.style.left = \"\";\n htmlElement.classList.remove(\"not-scroll\");\n window.scrollTo({\n left: pageX,\n top: pageY,\n });\n };\n }, [snappyModal.isShow]);\n\n const modalRendered = useMemo(() => {\n const { modalProgress } = snappyModal;\n return modalProgress.map(modal => (\n <div key={modal.options.layer} {...assignModalOptions(modal.options)}>\n <div\n className={`snappy-modal-content`}\n onClick={e => e.stopPropagation()}\n >\n <modal.component />\n </div>\n </div>\n ));\n }, [snappyModal.modalProgress]);\n\n return (\n <SnappyModalContext.Provider value={{}}>\n {children}\n {modalRendered}\n </SnappyModalContext.Provider>\n );\n};\n\nexport function assignModalOptions(options: SnappyModalOptions) {\n const domOptions = {\n classList: [\"snappy-modal-area\"],\n styleProperty: {},\n onClick: e => {},\n };\n if (options.backdrop) {\n domOptions.classList.push(\"backdrop\");\n if (typeof options.backdrop === \"string\") {\n domOptions.styleProperty[\"--snappy-modal-backdrop\"] = options.backdrop;\n }\n }\n if (options.position) {\n domOptions.styleProperty[\"--snappy-modal-content-position\"] =\n options.position;\n }\n if (options?.allowOutsideClick) {\n domOptions.onClick = e => {\n e.stopPropagation();\n e.preventDefault();\n SnappyModal.close(undefined, options.layer);\n };\n }\n if (options.zIndex !== undefined) {\n domOptions.styleProperty[\"--snappy-modal-z-index\"] =\n options.zIndex.toString();\n }\n return {\n className: domOptions.classList.join(\" \"),\n style: domOptions.styleProperty,\n onClick: domOptions.onClick,\n };\n}\n","import { SnappyModal } from \"./SnappyModal\";\nexport * from \"./context\";\n\nexport default SnappyModal;\n"],"mappings":"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","names":["jsx"]}