import { useEntitySetContext } from "components/EntitySetProvider"; import { generateKeyBetween } from "fractional-indexing"; import { useEffect, useState } from "react"; import { useEntity, useReplicache } from "src/replicache"; import { useUIState } from "src/useUIState"; import { addLinkBlock } from "src/utils/addLinkBlock"; import { BlockProps, BlockLayout } from "./Block"; import { v7 } from "uuid"; import { useSmoker } from "components/Toast"; import { Separator } from "components/Layout"; import { Input } from "components/Input"; import { focusElement } from "src/utils/focusElement"; import { isUrl } from "src/utils/isURL"; import { elementId } from "src/utils/elementId"; import { focusBlock } from "src/utils/focusBlock"; import { CheckTiny } from "components/Icons/CheckTiny"; import { LinkSmall } from "components/Icons/LinkSmall"; export const ExternalLinkBlock = ( props: BlockProps & { preview?: boolean }, ) => { let { permissions } = useEntitySetContext(); let previewImage = useEntity(props.entityID, "link/preview"); let title = useEntity(props.entityID, "link/title"); let description = useEntity(props.entityID, "link/description"); let url = useEntity(props.entityID, "link/url"); let isSelected = useUIState((s) => s.selectedBlocks.find((b) => b.value === props.entityID), ); useEffect(() => { if (props.preview) return; let input = document.getElementById(elementId.block(props.entityID).input); if (isSelected) { setTimeout(() => { let input = document.getElementById( elementId.block(props.entityID).input, ); focusElement(input as HTMLInputElement | null); }, 20); } else input?.blur(); }, [isSelected, props.entityID, props.preview]); if (url === undefined) { if (!permissions.write) return null; return ( ); } return (
{title?.data.value}
{description?.data.value}
{url?.data.value}
); }; const BlockLinkInput = (props: BlockProps & { preview?: boolean }) => { let isSelected = useUIState((s) => s.selectedBlocks.find((b) => b.value === props.entityID), ); let isLocked = useEntity(props.value, "block/is-locked")?.data.value; let entity_set = useEntitySetContext(); let [linkValue, setLinkValue] = useState(""); let { rep } = useReplicache(); let submit = async () => { let linkEntity = props.entityID; if (!linkEntity) { linkEntity = v7(); await rep?.mutate.addBlock({ permission_set: entity_set.set, factID: v7(), parent: props.parent, type: "card", position: generateKeyBetween(props.position, props.nextPosition), newEntityID: linkEntity, }); } let link = linkValue; if (!linkValue.startsWith("http")) link = `https://${linkValue}`; addLinkBlock(link, linkEntity, rep); let textEntity = v7(); await rep?.mutate.addBlock({ permission_set: entity_set.set, factID: v7(), parent: props.parent, type: "text", position: generateKeyBetween(props.position, props.nextPosition), newEntityID: textEntity, }); focusBlock( { value: textEntity, type: "text", parent: props.parent, }, { type: "start" }, ); }; let smoker = useSmoker(); return (
<> setLinkValue(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); if (!linkValue) return; if (!isUrl(linkValue)) { let rect = e.currentTarget.getBoundingClientRect(); smoker({ alignOnMobile: "left", error: true, text: "invalid url!", position: { x: rect.left, y: rect.top - 8 }, }); return; } submit(); } }} />
); };