procyon/packages/components/src/Modal/context.tsx
Roman Jaroš 4a283c5982
All checks were successful
forgejo/Procyon/procyon/pipeline/pr-develop This commit looks good
forgejo/Procyon/procyon/pipeline/head This commit looks good
useModal doest register only open and close
2023-11-21 07:36:15 +01:00

94 lines
2.3 KiB
TypeScript

import React, { createContext, FC, ReactNode, useEffect, useMemo, useState } from 'react';
import { omit } from 'ramda';
export type Modal<P> = {
Component?: FC<P>;
id: string;
props?: Partial<P>;
style?: {
overrideMaxWidth?: boolean;
width?: number | string;
};
title?: string | ReactNode;
};
export type ModalId = Modal<any>['id'];
export type ModalContextType = {
close: (modalId: ModalId) => void;
open: <P>(modalId: ModalId, modal?: Partial<Modal<P>>) => void;
opened: ModalId[];
register: <P>(modal: Modal<P>) => void;
registered: Record<ModalId, Modal<any>>;
unregister: (modalId: ModalId) => void;
};
export const ModalContext = createContext<ModalContextType>({
registered: {},
opened: [],
open: () => {},
close: () => {},
register: () => {},
unregister: () => {},
});
export const ModalWrapper: FC<{ children: ReactNode }> = ({ children }) => {
const [registered, setRegistered] = useState<Record<ModalId, Modal<any>>>({});
const [opened, setOpened] = useState<ModalId[]>([]);
const register = function <P>(modal: Modal<P>) {
setRegistered((modals) => ({
...modals,
[modal.id]: {
...modals[modal.id],
...modal,
},
}));
};
const unregister = (modalId: ModalId) => {
setRegistered((modals) => omit([modalId], modals));
};
const open = function <P>(modalId: ModalId, modal: Modal<P> | undefined) {
if (!registered[modalId]) {
register({ ...modal, id: modalId });
}
setOpened((opened) => [...opened, modalId]);
};
const close = (modalId: ModalId) => {
setOpened((opened) => opened.filter((id) => id !== modalId));
};
useEffect(() => {
window.addEventListener('openModal', (e: CustomEventInit<Modal<any>>) => {
if (e.detail) open(e.detail.id, e.detail);
});
window.addEventListener('closeModal', (e: CustomEventInit<ModalId>) => {
if (e.detail) close(e.detail);
});
}, []);
const value = useMemo(
() => ({
registered: registered,
opened,
unregister,
register,
open,
close,
}),
[registered, opened],
);
return <ModalContext.Provider value={value}>{children}</ModalContext.Provider>;
};
export const openModal = (modal: Modal<any>) => {
window.dispatchEvent(new CustomEvent<Modal<any>>('openModal', { detail: modal }));
};
export const closeModal = (modalId: ModalId) => {
window.dispatchEvent(new CustomEvent<ModalId>('closeModal', { detail: modalId }));
};