// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates // SPDX-License-Identifier: MIT import { Button } from "../../ui/button"; import { PopoverContent } from "../../ui/popover"; import { cn } from "../../../lib/utils"; import { Popover, PopoverTrigger } from "@radix-ui/react-popover"; import { Check, Trash } from "lucide-react"; import { useEditor } from "novel"; import { useEffect, useRef } from "react"; export function isValidUrl(url: string) { try { new URL(url); return true; } catch (_e) { return false; } } export function getUrlFromString(str: string) { if (isValidUrl(str)) return str; try { if (str.includes(".") && !str.includes(" ")) { return new URL(`https://${str}`).toString(); } } catch (_e) { return null; } } interface LinkSelectorProps { open: boolean; onOpenChange: (open: boolean) => void; } export const LinkSelector = ({ open, onOpenChange }: LinkSelectorProps) => { const inputRef = useRef(null); const { editor } = useEditor(); // Autofocus on input by default useEffect(() => { inputRef.current?.focus(); }); if (!editor) return null; return (
{ const target = e.currentTarget as HTMLFormElement; e.preventDefault(); const input = target[0] as HTMLInputElement; const url = getUrlFromString(input.value); if (url) { editor.chain().focus().setLink({ href: url }).run(); onOpenChange(false); } }} className="flex p-1" > {editor.getAttributes("link").href ? ( ) : ( )}
); };