"use client" import * as React from "react" import type { Editor } from "@tiptap/react" // --- Hooks --- import { useIsMobile } from "@/hooks/use-mobile" import { useTiptapEditor } from "@/hooks/use-tiptap-editor" // --- Icons --- import { CornerDownLeftIcon } from "@/components/tiptap-icons/corner-down-left-icon" import { ExternalLinkIcon } from "@/components/tiptap-icons/external-link-icon" import { LinkIcon } from "@/components/tiptap-icons/link-icon" import { TrashIcon } from "@/components/tiptap-icons/trash-icon" // --- Tiptap UI --- import type { UseLinkPopoverConfig } from "@/components/tiptap-ui/link-popover" import { useLinkPopover } from "@/components/tiptap-ui/link-popover" // --- UI Primitives --- import type { ButtonProps } from "@/components/tiptap-ui-primitive/button" import { Button, ButtonGroup } from "@/components/tiptap-ui-primitive/button" import { Popover, PopoverContent, PopoverTrigger, } from "@/components/tiptap-ui-primitive/popover" import { Separator } from "@/components/tiptap-ui-primitive/separator" import { Card, CardBody, CardItemGroup, } from "@/components/tiptap-ui-primitive/card" import { Input, InputGroup } from "@/components/tiptap-ui-primitive/input" export interface LinkMainProps { /** * The URL to set for the link. */ url: string /** * Function to update the URL state. */ setUrl: React.Dispatch> /** * Function to set the link in the editor. */ setLink: () => void /** * Function to remove the link from the editor. */ removeLink: () => void /** * Function to open the link. */ openLink: () => void /** * Whether the link is currently active in the editor. */ isActive: boolean } export interface LinkPopoverProps extends Omit, UseLinkPopoverConfig { /** * Callback for when the popover opens or closes. */ onOpenChange?: (isOpen: boolean) => void /** * Whether to automatically open the popover when a link is active. * @default true */ autoOpenOnLinkActive?: boolean } /** * Link button component for triggering the link popover */ export const LinkButton = React.forwardRef( ({ className, children, ...props }, ref) => { return ( ) } ) LinkButton.displayName = "LinkButton" /** * Main content component for the link popover */ const LinkMain: React.FC = ({ url, setUrl, setLink, removeLink, openLink, isActive, }) => { const isMobile = useIsMobile() const handleKeyDown = (event: React.KeyboardEvent) => { if (event.key === "Enter") { event.preventDefault() setLink() } } return ( setUrl(e.target.value)} onKeyDown={handleKeyDown} autoFocus autoComplete="off" autoCorrect="off" autoCapitalize="off" /> ) } /** * Link content component for standalone use */ export const LinkContent: React.FC<{ editor?: Editor | null }> = ({ editor }) => { const linkPopover = useLinkPopover({ editor, }) return } /** * Link popover component for Tiptap editors. * * For custom popover implementations, use the `useLinkPopover` hook instead. */ export const LinkPopover = React.forwardRef< HTMLButtonElement, LinkPopoverProps >( ( { editor: providedEditor, hideWhenUnavailable = false, onSetLink, onOpenChange, autoOpenOnLinkActive = true, onClick, children, ...buttonProps }, ref ) => { const { editor } = useTiptapEditor(providedEditor) const [isOpen, setIsOpen] = React.useState(false) const { isVisible, canSet, isActive, url, setUrl, setLink, removeLink, openLink, label, Icon, } = useLinkPopover({ editor, hideWhenUnavailable, onSetLink, }) const handleOnOpenChange = React.useCallback( (nextIsOpen: boolean) => { setIsOpen(nextIsOpen) onOpenChange?.(nextIsOpen) }, [onOpenChange] ) const handleSetLink = React.useCallback(() => { setLink() setIsOpen(false) }, [setLink]) const handleClick = React.useCallback( (event: React.MouseEvent) => { onClick?.(event) if (event.defaultPrevented) return setIsOpen(!isOpen) }, [onClick, isOpen] ) React.useEffect(() => { if (autoOpenOnLinkActive && isActive) { setIsOpen(true) } }, [autoOpenOnLinkActive, isActive]) if (!isVisible) { return null } return ( {children ?? } ) } ) LinkPopover.displayName = "LinkPopover" export default LinkPopover