51 lines
1.1 KiB
TypeScript
51 lines
1.1 KiB
TypeScript
import type { ComponentType } from 'react';
|
|
import { useCallback, useEffect, useId } from 'react';
|
|
|
|
import { modalStore } from './store';
|
|
|
|
interface ModalControlProps {
|
|
isOpen?: boolean;
|
|
onOpenChange?: (isOpen: boolean) => void;
|
|
}
|
|
|
|
export const useModal = () => {
|
|
const scopeId = useId();
|
|
|
|
useEffect(() => {
|
|
return () => {
|
|
modalStore
|
|
.getSnapshot()
|
|
.filter((m) => m.scopeId === scopeId)
|
|
.forEach((m) => m.resolve());
|
|
modalStore.removeByScope(scopeId);
|
|
};
|
|
}, [scopeId]);
|
|
|
|
const show = useCallback(
|
|
<P extends ModalControlProps>(
|
|
Component: ComponentType<P>,
|
|
props?: Omit<P, keyof ModalControlProps>
|
|
): Promise<void> =>
|
|
new Promise((resolve) => {
|
|
modalStore.addModal({
|
|
id: crypto.randomUUID(),
|
|
scopeId,
|
|
Component,
|
|
props: props ?? {},
|
|
resolve,
|
|
});
|
|
}),
|
|
[scopeId]
|
|
);
|
|
|
|
const hide = useCallback(() => {
|
|
modalStore
|
|
.getSnapshot()
|
|
.filter((m) => m.scopeId === scopeId)
|
|
.forEach((m) => m.resolve());
|
|
modalStore.removeByScope(scopeId);
|
|
}, [scopeId]);
|
|
|
|
return { show, hide };
|
|
};
|