import { TextField } from "./TextField"; import type { AppProps, AppState, UIAppState } from "../types"; import DialogActionButton from "./DialogActionButton"; import { getSelectedElements } from "../scene"; import { defaultGetElementLinkFromSelection, getLinkIdAndTypeFromSelection, } from "../element/elementLink"; import { mutateElement } from "../element/mutateElement"; import { useCallback, useEffect, useState } from "react"; import { t } from "../i18n"; import type { ElementsMap, ExcalidrawElement } from "../element/types"; import { ToolButton } from "./ToolButton"; import { TrashIcon } from "./icons"; import { KEYS } from "../keys"; import "./ElementLinkDialog.scss"; import { normalizeLink } from "../data/url"; const ElementLinkDialog = ({ sourceElementId, onClose, elementsMap, appState, generateLinkForSelection = defaultGetElementLinkFromSelection, }: { sourceElementId: ExcalidrawElement["id"]; elementsMap: ElementsMap; appState: UIAppState; onClose?: () => void; generateLinkForSelection: AppProps["generateLinkForSelection"]; }) => { const originalLink = elementsMap.get(sourceElementId)?.link ?? null; const [nextLink, setNextLink] = useState(originalLink); const [linkEdited, setLinkEdited] = useState(false); useEffect(() => { const selectedElements = getSelectedElements(elementsMap, appState); let nextLink = originalLink; if (selectedElements.length > 0 && generateLinkForSelection) { const idAndType = getLinkIdAndTypeFromSelection( selectedElements, appState as AppState, ); if (idAndType) { nextLink = normalizeLink( generateLinkForSelection(idAndType.id, idAndType.type), ); } } setNextLink(nextLink); }, [ elementsMap, appState, appState.selectedElementIds, originalLink, generateLinkForSelection, ]); const handleConfirm = useCallback(() => { if (nextLink && nextLink !== elementsMap.get(sourceElementId)?.link) { const elementToLink = elementsMap.get(sourceElementId); elementToLink && mutateElement(elementToLink, { link: nextLink, }); } if (!nextLink && linkEdited && sourceElementId) { const elementToLink = elementsMap.get(sourceElementId); elementToLink && mutateElement(elementToLink, { link: null, }); } onClose?.(); }, [sourceElementId, nextLink, elementsMap, linkEdited, onClose]); useEffect(() => { const handleKeyDown = (event: KeyboardEvent) => { if ( appState.openDialog?.name === "elementLinkSelector" && event.key === KEYS.ENTER ) { handleConfirm(); } if ( appState.openDialog?.name === "elementLinkSelector" && event.key === KEYS.ESCAPE ) { onClose?.(); } }; window.addEventListener("keydown", handleKeyDown); return () => { window.removeEventListener("keydown", handleKeyDown); }; }, [appState, onClose, handleConfirm]); return (

{t("elementLink.title")}

{t("elementLink.desc")}

{ if (!linkEdited) { setLinkEdited(true); } setNextLink(value); }} onKeyDown={(event) => { if (event.key === KEYS.ENTER) { handleConfirm(); } }} className="ElementLinkDialog__input-field" selectOnRender /> {originalLink && nextLink && ( { // removes the link from the input // but doesn't update the element // when confirmed, will remove the link from the element setNextLink(null); setLinkEdited(true); }} className="ElementLinkDialog__remove" icon={TrashIcon} /> )}
{ onClose?.(); }} style={{ marginRight: 10, }} />
); }; export default ElementLinkDialog;