feat: initial commit
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
import {
|
||||
createContext,
|
||||
useCallback,
|
||||
useMemo,
|
||||
useState,
|
||||
type ComponentType,
|
||||
type ReactNode,
|
||||
} from "react";
|
||||
import { idAssert } from "../../util/ts.js";
|
||||
|
||||
export interface PopupManagerContextData {
|
||||
openPopup(popup: ComponentType<{ id: string; onClose: () => void }>): string;
|
||||
openPopup<T>(
|
||||
popup: ComponentType<{ id: string; onClose: () => void } & T>,
|
||||
props: T
|
||||
): string;
|
||||
|
||||
closePopup(id: string): void;
|
||||
}
|
||||
|
||||
export const PopupManagerContext =
|
||||
createContext<PopupManagerContextData | null>(null);
|
||||
PopupManagerContext.displayName = "PopupManagerContext";
|
||||
|
||||
type Popup = {
|
||||
id: string;
|
||||
Component: ComponentType<{ id: string; onClose: () => void }>;
|
||||
props: { id: string; onClose: () => void };
|
||||
};
|
||||
|
||||
export function PopupManager({ children }: { children: ReactNode }) {
|
||||
const [popups, setPopups] = useState<Popup[]>([]);
|
||||
|
||||
const openPopup = useCallback<PopupManagerContextData["openPopup"]>(
|
||||
(
|
||||
Component: ComponentType<{ id: string; onClose: () => void }>,
|
||||
props = {}
|
||||
) => {
|
||||
const id = crypto.randomUUID();
|
||||
Object.assign(props, {
|
||||
id,
|
||||
onClose: () => setPopups((prev) => prev.filter((x) => x.id !== id)),
|
||||
});
|
||||
idAssert<{ id: string; onClose: () => void }>(props);
|
||||
setPopups((prev) => [...prev, { id, Component, props }]);
|
||||
return id;
|
||||
},
|
||||
[]
|
||||
);
|
||||
const closePopup = useCallback((id: string) => {
|
||||
setPopups((prev) => prev.filter((x) => x.id !== id));
|
||||
}, []);
|
||||
const ctx = useMemo<PopupManagerContextData>(
|
||||
() => ({ openPopup, closePopup }),
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<PopupManagerContext value={ctx}>
|
||||
{children}
|
||||
{popups.map((popup) => (
|
||||
<popup.Component key={popup.id} {...popup.props} />
|
||||
))}
|
||||
</PopupManagerContext>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user