UNPKG

@customizer/modal-x

Version:

Modal-X = **This Vue Plugin provides a simple and flexible way to create modals for your web applications using a file-based approach. Easily define modal content in separate files, allowing for better organization and maintainability with minimal effort.

179 lines (158 loc) 4.27 kB
import { reactive, shallowRef, watch, defineAsyncComponent, getCurrentInstance, nextTick, h, ref, } from "vue"; import ModalParent from '../ModalParent.vue' import { defineStore } from "pinia"; import Spinner from "../Spinner.vue"; export const useModal = defineStore("modal", () => { let modals = reactive([]); const fetchedModals = shallowRef([]); const spinners = shallowRef([]); const globalSpinner = shallowRef(); // this will be set by ModalParent Since i can get access of the opened modal name to be set for the options const modalName = ref('') const options = ref([]); function setOptions(opts = { closeonEsc: true, closeOnOverlayClick: true }) { if(!modalName.value) return options.value[modalName.value] = opts } function openModal(modalToOpen, data, cb) { modals.forEach((modal) => { modal.active = false; }); try { data = JSON.parse(JSON.stringify(data)); modals.unshift({ modalToOpen, data, cb, active: true }); } catch (err) { modals.unshift({ modalToOpen, data, cb, active: true }); } } function closeModal(response, sendResponse = true) { let modal = modals.shift(); modals.length && (modals[0].active = true); if (![undefined, null].includes(response)) modal.cb && modal.cb(response); } function getModal(name) { return modals.find((modal) => modal.modalToOpen == name); } async function loadModal(modal, name, render = true) { if ( fetchedModals.value.find((mod) => [name, modal.__name?.match(/.*\/(.+)\.mdl\.vue$/)?.[1]].includes(mod.id) ) ) return; let com; if (render) { com = await modal.__asyncLoader(); } else { com = modal; } name ||= modal.__name?.match(/.*\/(.+)\.mdl\.vue$/)?.[1] fetchedModals.value = [ { id: name || "", modal: h(ModalParent, { name }, () => { return h(com, { data: getModal(name)?.data }) }), }, ...fetchedModals.value, ]; } async function loadSpinners(modal, name, group) { if ( spinners.value.find((mod) => { return [name, modal.__name?.match(/.*\/(.+)\.s\.vue$/)?.[1]?.split('.')?.[0]].includes( mod.id ); }) ) return; const com = await modal.__asyncLoader(); spinners.value = [ { id: name || modal.__name?.match(/.*\/(.+)\.s\.vue$/)?.[1] || "", modal: com, group }, ...spinners.value, ]; } async function loadGlobalSpinner(modal, name) { const com = await modal.__asyncLoader(); globalSpinner.value = { id: name || modal.__name?.match(/.*\/(.+)\.g\.vue$/)?.[1] || "", modal: com, }; } function fetchModal(name) { if ( fetchedModals.value.find( (modal) => modal.id == `${name}.mdl` || modal.id == name ) ) return; const asyncModules = import.meta.glob([ `/**/*(.)*.amdl.vue`, "!./node_modules", ]); let mods = { ...asyncModules }; let group const modalPath = Object.keys(mods).find( (module) => { const file = module.match(/.*\/(.+)\.amdl\.vue$/)?.[1].split(".") const fileName = file?.[0] if(fileName == name) { group = file?.[1] } return fileName == name } ); if (!modalPath) return console.log( `%cno modal found with name [${name}]`, "font-size: 14px; color: red;" ); const spinnerModal = spinners.value.find((m) => m.id == name || (group && m?.group == group))?.modal; let modal = defineAsyncComponent({ loader: () => mods[modalPath](), loadingComponent: spinnerModal || globalSpinner.value?.modal || Spinner, delay: 0, }); loadModal(modal, name, false); } watch(modals, (modals) => { if (modals?.[0]) fetchModal(modals?.[0]?.modalToOpen); }); //watch(options, () => { // console.log(options.value) //}, {immediate: true, deep: true}) return { modals, loadSpinners, spinners, fetchedModals, openModal, closeModal, getModal, loadModal, loadGlobalSpinner, setOptions, options, modalName }; });