interface Controller { /** * * @return 結果 */ start: (projects: string[], links: string[]) => Promise< "success" | "cancel" | "failed" >; close: () => void; } const App = ({ getController }: AppProps) => { const [after, setAfter] = useState(""); const [before, setBefore] = useState(""); const [projects, setProjects] = useState([]); const [onEnd, setOnEnd] = useState<(result: Result) => void>(() => {}); const linksDiff = useMemo(() => { const lines = after.split("\n"); // 空文字の場合は、変更なしとみなす return links.map((link, i) => ({ before: link, after: lines[i]?.trim?.() || link })); }, [links, after]); const replace = useCallback(async () => { setReplacing(true); await replaceLinks(linksDiff, projects); setReplacing(false); setOpen(false); onEnd("success"); }, [linksDiff, projects, onEnd]); const handleInput = useCallback((e) => setAfter(e.currentTarget.value), []); const startReplace = useCallback((projects: string[], links: string[]) => { setProject(projects); setBefore(links.join("\n")); setOpen(true); return new Promise((resolve) => setOnEnd(resolve)); }, []); useEffect(() => getController({ start: startReplace, close: () => setOpen(false), }), [getController]); return ( <>