import * as React from "react"; import { Input } from "@/components/ui/input"; import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuSeparator, ContextMenuTrigger, } from "@/components/ui/context-menu"; import { Scissors, Copy, Clipboard, Type } from "lucide-react"; export interface InputWithContextProps extends React.InputHTMLAttributes { onValueChange?: (value: string) => void; } const InputWithContext = React.forwardRef(({ className, type, onValueChange, onChange, ...props }, ref) => { const inputRef = React.useRef(null); const [hasSelection, setHasSelection] = React.useState(false); const [canPaste, setCanPaste] = React.useState(false); React.useImperativeHandle(ref, () => inputRef.current as HTMLInputElement); const updateSelectionState = () => { const input = inputRef.current; if (!input) return; const start = input.selectionStart ?? 0; const end = input.selectionEnd ?? 0; setHasSelection(start !== end); }; const checkClipboard = async () => { try { const text = await navigator.clipboard.readText(); setCanPaste(text.length > 0); } catch { setCanPaste(false); } }; const handleCut = async () => { const input = inputRef.current; if (!input) return; const start = input.selectionStart ?? 0; const end = input.selectionEnd ?? 0; const selectedText = input.value.substring(start, end); if (selectedText) { try { await navigator.clipboard.writeText(selectedText); const newValue = input.value.substring(0, start) + input.value.substring(end); input.value = newValue; input.setSelectionRange(start, start); if (onChange) { const event = { target: input, currentTarget: input, } as React.ChangeEvent; onChange(event); } if (onValueChange) { onValueChange(newValue); } input.focus(); } catch (err) { console.error("Failed to cut:", err); } } }; const handleCopy = async () => { const input = inputRef.current; if (!input) return; const start = input.selectionStart ?? 0; const end = input.selectionEnd ?? 0; const selectedText = input.value.substring(start, end); if (selectedText) { try { await navigator.clipboard.writeText(selectedText); input.focus(); } catch (err) { console.error("Failed to copy:", err); } } }; const handlePaste = async () => { const input = inputRef.current; if (!input) return; try { const text = await navigator.clipboard.readText(); const start = input.selectionStart ?? 0; const end = input.selectionEnd ?? 0; const newValue = input.value.substring(0, start) + text + input.value.substring(end); input.value = newValue; const newPosition = start + text.length; input.setSelectionRange(newPosition, newPosition); if (onChange) { const event = { target: input, currentTarget: input, } as React.ChangeEvent; onChange(event); } if (onValueChange) { onValueChange(newValue); } input.focus(); await checkClipboard(); } catch (err) { console.error("Failed to paste:", err); } }; const handleSelectAll = () => { const input = inputRef.current; if (!input) return; input.select(); input.focus(); updateSelectionState(); }; const handleInputChange = (e: React.ChangeEvent) => { if (onChange) { onChange(e); } if (onValueChange) { onValueChange(e.target.value); } }; return ( { if (open) { checkClipboard(); } }}> Cut Ctrl+X Copy Ctrl+C Paste Ctrl+V Select All Ctrl+A ); }); InputWithContext.displayName = "InputWithContext"; export { InputWithContext };