@svelte-put/modal
Version:
109 lines (108 loc) • 3.29 kB
JavaScript
/* eslint-disable @typescript-eslint/ban-types */
/* eslint-disable @typescript-eslint/no-explicit-any */
import { createEventDispatcher } from 'svelte';
import { writable } from 'svelte/store';
/**
* Create a svelte store for handling modal
* @example
*
* ```typescript
* import { createModalStore } from '@svelte-put/modal';
* const store = createModalStore();
* ```
* @returns {ModalStore} extended svelte {@link ModalStore}
*/
export function createModalStore() {
const { subscribe, set } = writable([]);
let modals = [];
const resolveMap = {};
const resolveCallbacks = {};
const push = function (input) {
let _resolve;
let resolved = false;
const promise = new Promise((resolve) => {
_resolve = (value) => {
resolved = true;
resolve(value);
};
});
let id = (crypto && crypto.randomUUID && crypto.randomUUID()) ?? `modal-indexed-${modals.length}`;
let props;
let component;
if (typeof input === 'function') {
component = input;
props = {};
}
else {
id = input.id ?? id;
props = input.props ?? {};
component = input.component;
}
const pushed = {
id,
props,
component,
resolve: () => promise,
resolved,
};
modals.push(pushed);
resolveMap[pushed.id] = _resolve;
set([...modals]);
return pushed;
};
const pop = function (pushed, resolved) {
let popped;
if (pushed?.id) {
modals = modals.filter((modal) => {
if (modal.id === pushed.id) {
popped = modal;
return false;
}
return true;
});
set(modals);
}
else {
popped = modals.pop();
set([...modals]);
}
if (popped) {
const rResolved = {
trigger: 'pop',
...(resolved ?? {}),
};
resolveMap[popped.id]?.(rResolved);
resolveMap[popped.id] = undefined;
resolveCallbacks[popped.id]?.forEach((callback) => callback(rResolved));
resolveCallbacks[popped.id] = undefined;
}
return popped;
};
const onPop = function (modalId, callback) {
if (!resolveCallbacks[modalId]) {
resolveCallbacks[modalId] = [callback];
}
else if (!resolveCallbacks[modalId]?.includes(callback)) {
resolveCallbacks[modalId]?.push(callback);
}
return () => {
if (resolveCallbacks[modalId]) {
resolveCallbacks[modalId] = resolveCallbacks[modalId]?.filter((cb) => cb !== callback);
}
};
};
return {
subscribe,
push,
pop,
onPop,
};
}
/**
*Helper that wraps svelte `createEventDispatcher` for creating typesafe
*event dispatcher from the `$$Events` type. See {@link ExtendedModalEvents}
* @returns {ReturnType<typeof createEventDispatcher>} svelte event dispatcher
*/
export function createModalEventDispatcher() {
return createEventDispatcher();
}