import ConfirmModal from '$lib/modals/ConfirmModal.svelte'; import { mount, unmount, type Component, type ComponentProps } from 'svelte'; type OnCloseData = T extends { onClose: (data?: infer R) => void } ? R | undefined : T extends { onClose: (data: infer R) => void } ? R : never; type ExtendsEmptyObject = keyof T extends never ? never : T; type StripValueIfOptional = T extends undefined ? undefined : T; // if the modal does not expect any props, makes the props param optional but also allows passing `{}` and `undefined` type OptionalParamIfEmpty = ExtendsEmptyObject extends never ? [] | [Record | undefined] : [T]; class ModalManager { show(Component: Component, ...props: OptionalParamIfEmpty>) { return this.open(Component, ...props).onClose; } open>( Component: Component, ...props: OptionalParamIfEmpty> ) { let modal: object = {}; let onClose: (...args: [StripValueIfOptional]) => Promise; const deferred = new Promise>((resolve) => { onClose = async (...args: [StripValueIfOptional]) => { await unmount(modal); resolve(args?.[0]); }; modal = mount(Component, { target: document.body, props: { ...((props?.[0] ?? {}) as T), onClose, }, }); }); return { onClose: deferred, close: (...args: [StripValueIfOptional]) => onClose(args[0]), }; } showDialog(options: Omit, 'onClose'>) { return this.show(ConfirmModal, options); } } export const modalManager = new ModalManager();