import React, { forwardRef, useEffect, useImperativeHandle, useRef, } from "react"; import { cn } from "~/lib/utils"; export interface TextBoxProps extends Omit, "onChange" | "value"> { value: string; onChange: (value: string) => void; placeholder?: string; wrapperClassName?: string; inputClassName?: string; disabled?: boolean; autoFocus?: boolean; spellCheck?: boolean; } export const TextBox = forwardRef( ( { value, onChange, placeholder, wrapperClassName, inputClassName, disabled = false, autoFocus = false, spellCheck = true, onInput, onBlur, onFocus, ...rest }, ref, ) => { const localRef = useRef(null); useImperativeHandle(ref, () => localRef.current as HTMLDivElement); // Function to handle DOM updates const updateDOM = (newValue: string) => { if (localRef.current) { // Only update if different to avoid selection issues if (localRef.current.textContent !== newValue) { localRef.current.textContent = newValue; // Clear any
elements if the content is empty if ( !newValue && localRef.current.innerHTML.includes("
") ) { localRef.current.innerHTML = ""; } } } }; // Update DOM when value prop changes useEffect(() => { updateDOM(value); }, [value]); useEffect(() => { if (autoFocus && localRef.current) { localRef.current.focus(); } }, [autoFocus]); const handleInput = (event: React.FormEvent) => { const newValue = event.currentTarget.textContent || ""; // Handle the case where the content is empty but contains a
if (!newValue && event.currentTarget.innerHTML.includes("
")) { event.currentTarget.innerHTML = ""; } onChange(newValue); onInput?.(event); }; const handlePaste = (event: React.ClipboardEvent) => { event.preventDefault(); const text = event.clipboardData.getData("text/plain"); // Use document.execCommand to maintain undo stack document.execCommand("insertText", false, text); // Manually trigger input event const inputEvent = new Event("input", { bubbles: true }); event.currentTarget.dispatchEvent(inputEvent); }; return (
localRef.current?.focus()} >
); }, ); TextBox.displayName = "TextBox"; export default TextBox;