parent
37da3742a0
commit
82a687c8c8
@ -0,0 +1,76 @@
|
||||
import { useCallback, useContext, useMemo } from "react";
|
||||
import { useDidUpdate } from "rooks";
|
||||
import { log } from "../../utilites/logger";
|
||||
import { ModalContext } from "./provider";
|
||||
|
||||
export function useShowModal() {
|
||||
const {
|
||||
control: { push },
|
||||
} = useContext(ModalContext);
|
||||
|
||||
return useCallback(
|
||||
<T,>(key: string, payload?: T) => {
|
||||
log("info", `modal ${key} sending payload`, payload);
|
||||
|
||||
push({ key, payload });
|
||||
},
|
||||
[push]
|
||||
);
|
||||
}
|
||||
|
||||
export function useCloseModal() {
|
||||
const {
|
||||
control: { pop },
|
||||
} = useContext(ModalContext);
|
||||
return pop;
|
||||
}
|
||||
|
||||
export function useCloseModalUntil() {
|
||||
const {
|
||||
control: { pop, peek },
|
||||
} = useContext(ModalContext);
|
||||
return useCallback(
|
||||
(key: string) => {
|
||||
let modal = peek();
|
||||
while (modal) {
|
||||
if (modal.key === key) {
|
||||
break;
|
||||
} else {
|
||||
modal = pop();
|
||||
}
|
||||
}
|
||||
},
|
||||
[pop, peek]
|
||||
);
|
||||
}
|
||||
|
||||
export function useIsModalShow(key: string) {
|
||||
const {
|
||||
control: { peek },
|
||||
} = useContext(ModalContext);
|
||||
const modal = peek();
|
||||
return key === modal?.key;
|
||||
}
|
||||
|
||||
export function useOnModalShow(callback: () => void, key: string) {
|
||||
const isShow = useIsModalShow(key);
|
||||
useDidUpdate(() => {
|
||||
if (isShow) {
|
||||
callback();
|
||||
}
|
||||
}, [isShow]);
|
||||
}
|
||||
|
||||
export function usePayload<T>(key: string): T | null {
|
||||
const {
|
||||
control: { peek },
|
||||
} = useContext(ModalContext);
|
||||
return useMemo(() => {
|
||||
const modal = peek();
|
||||
if (modal && modal.key === key) {
|
||||
return modal.payload as T;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}, [key, peek]);
|
||||
}
|
@ -1,7 +1,8 @@
|
||||
export * from "./BaseModal";
|
||||
export * from "./HistoryModal";
|
||||
export * from "./hooks";
|
||||
export { default as ItemEditorModal } from "./ItemEditorModal";
|
||||
export { default as MovieUploadModal } from "./MovieUploadModal";
|
||||
export * from "./provider";
|
||||
export { default as ModalProvider } from "./provider";
|
||||
export { default as SeriesUploadModal } from "./SeriesUploadModal";
|
||||
export { default as SubtitleToolModal } from "./SubtitleToolModal";
|
||||
|
@ -1,100 +1,48 @@
|
||||
import React, {
|
||||
Dispatch,
|
||||
FunctionComponent,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from "react";
|
||||
import { log } from "../../utilites/logger";
|
||||
import React, { FunctionComponent, useMemo } from "react";
|
||||
import { useStackState } from "rooks";
|
||||
|
||||
const ModalContext = React.createContext<[string[], Dispatch<string[]>]>([
|
||||
[],
|
||||
(s) => {},
|
||||
]);
|
||||
|
||||
const PayloadContext = React.createContext<[any[], Dispatch<any[]>]>([
|
||||
[],
|
||||
(p) => {},
|
||||
]);
|
||||
|
||||
// TODO: Performance
|
||||
export function useShowModal() {
|
||||
const [keys, setKeys] = useContext(ModalContext);
|
||||
const [payloads, setPayloads] = useContext(PayloadContext);
|
||||
return useCallback(
|
||||
<T,>(key: string, payload?: T) => {
|
||||
log("info", `modal ${key} sending payload`, payload);
|
||||
|
||||
setKeys([...keys, key]);
|
||||
setPayloads([...payloads, payload ?? null]);
|
||||
},
|
||||
[keys, payloads, setKeys, setPayloads]
|
||||
);
|
||||
}
|
||||
|
||||
export function useCloseModal() {
|
||||
const [keys, setKeys] = useContext(ModalContext);
|
||||
const [payloads, setPayloads] = useContext(PayloadContext);
|
||||
return useCallback(() => {
|
||||
const newKey = [...keys];
|
||||
newKey.pop();
|
||||
const newPayload = [...payloads];
|
||||
newPayload.pop();
|
||||
setKeys(newKey);
|
||||
setPayloads(newPayload);
|
||||
}, [keys, payloads, setKeys, setPayloads]);
|
||||
interface Modal {
|
||||
key: string;
|
||||
payload: any;
|
||||
}
|
||||
|
||||
export function useCloseModalUntil(key: string) {
|
||||
const [keys, setKeys] = useContext(ModalContext);
|
||||
const [payloads, setPayloads] = useContext(PayloadContext);
|
||||
return useCallback(() => {
|
||||
const idx = keys.findIndex((v) => v === key);
|
||||
if (idx !== -1) {
|
||||
const newKey = keys.slice(0, idx + 1);
|
||||
const newPayload = payloads.slice(0, idx + 1);
|
||||
setKeys(newKey);
|
||||
setPayloads(newPayload);
|
||||
} else {
|
||||
log("error", "Cannot close modal, key is unavailable");
|
||||
}
|
||||
}, [keys, payloads, setKeys, setPayloads, key]);
|
||||
interface ModalControl {
|
||||
push: (modal: Modal) => void;
|
||||
peek: () => Modal | undefined;
|
||||
pop: () => Modal | undefined;
|
||||
}
|
||||
|
||||
export function useIsModalShow(key: string) {
|
||||
const keys = useContext(ModalContext)[0];
|
||||
return key === keys[keys.length - 1];
|
||||
interface ModalContextType {
|
||||
modals: Modal[];
|
||||
control: ModalControl;
|
||||
}
|
||||
|
||||
export function useOnModalShow(key: string, show: () => void) {
|
||||
const isShow = useIsModalShow(key);
|
||||
useEffect(() => {
|
||||
if (isShow) {
|
||||
show();
|
||||
}
|
||||
}, [isShow, show]);
|
||||
}
|
||||
export const ModalContext = React.createContext<ModalContextType>({
|
||||
modals: [],
|
||||
control: {
|
||||
push: () => {
|
||||
throw new Error("Unimplemented");
|
||||
},
|
||||
pop: () => {
|
||||
throw new Error("Unimplemented");
|
||||
},
|
||||
peek: () => {
|
||||
throw new Error("Unimplemented");
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export function usePayload<T>(key: string): T | null {
|
||||
const payloads = useContext(PayloadContext)[0];
|
||||
const keys = useContext(ModalContext)[0];
|
||||
return useMemo(() => {
|
||||
const idx = keys.findIndex((v) => v === key);
|
||||
return idx !== -1 ? payloads[idx] : null;
|
||||
}, [keys, payloads, key]);
|
||||
}
|
||||
const ModalProvider: FunctionComponent = ({ children }) => {
|
||||
const [stack, { push, pop, peek }] = useStackState([]);
|
||||
|
||||
export const ModalProvider: FunctionComponent = ({ children }) => {
|
||||
const [key, setKey] = useState<string[]>([]);
|
||||
const [payload, setPayload] = useState<any[]>([]);
|
||||
const context = useMemo<ModalContextType>(
|
||||
() => ({ modals: stack, control: { push, pop, peek } }),
|
||||
[stack, push, pop, peek]
|
||||
);
|
||||
|
||||
return (
|
||||
<ModalContext.Provider value={[key, setKey]}>
|
||||
<PayloadContext.Provider value={[payload, setPayload]}>
|
||||
{children}
|
||||
</PayloadContext.Provider>
|
||||
</ModalContext.Provider>
|
||||
<ModalContext.Provider value={context}>{children}</ModalContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default ModalProvider;
|
||||
|
Loading…
Reference in new issue