import React, { useCallback, useEffect, useRef } from "react"; import { cls, fieldBackgroundDisabledMixin, fieldBackgroundHoverMixin, fieldBackgroundMixin, InputLabel, TextareaAutosize, TextField } from "@firecms/ui"; export type InputType = T extends string ? "text" : "number"; export function AdvancedTextField({ value, setValue, label, inputType, multiline = false, highlight, disabled, error, size = "large", className }: { inputType: InputType, value: T, setValue: (value: T | null) => void, highlight?: string, label: React.ReactNode, multiline?: boolean, disabled?: boolean, error?: boolean, size?: "smallest" | "small" | "medium" | "large", className?: string, }) { const inputRef = useRef(null); const ref = useRef(null); const [internalValue, setInternalValue] = React.useState(value ? value.toString() : ""); useEffect(() => { setInternalValue(value ? value.toString() : ""); }, [value]); const onScroll = useCallback((e: any) => { if (!ref.current) return; ref.current.scrollTop = e.target.scrollTop; ref.current.scrollLeft = e.target.scrollLeft; }, []); const [focused, setFocused] = React.useState(document.activeElement === inputRef.current); const hasValue = internalValue !== undefined && internalValue !== null && internalValue !== ""; const endsWithHighlight = !!highlight && (value === highlight || String(value).endsWith(highlight)); const originalValue = endsWithHighlight ? String(value).substring(0, String(value).length - highlight.length) : internalValue; const onChange = useCallback((event: React.ChangeEvent) => { const stringValue = event.target.value; if (inputType === "number") { if (stringValue === "-" || stringValue.startsWith(".") || stringValue.endsWith(".")) { setInternalValue(stringValue); } else { const numberValue = stringValue ? parseFloat(stringValue) : undefined; if (numberValue && isNaN(numberValue)) { setValue(null); setInternalValue(""); } else if (numberValue !== undefined && numberValue !== null) { setValue(numberValue as T); setInternalValue(numberValue.toString()); } else { setValue(null); setInternalValue(""); } } } else { setValue(stringValue as T); setInternalValue(stringValue); } }, [inputType, setValue]); const numberInputOnWheelPreventChange = useCallback((e: any) => { e.target.blur() e.stopPropagation() setTimeout(() => { e.target.focus() }, 0) }, []); if (disabled) { return } const additional: any = { onKeyPress: (e: any) => { // if (e.key === "Enter") { // e.preventDefault(); // e.stopPropagation(); // } if (!multiline && e.key === "Enter") { e.preventDefault(); } } } return (
{label && ( {label} )}
{addLineBreaks(originalValue, !endsWithHighlight && multiline)} {endsWithHighlight && {addLineBreaks(highlight, multiline)} }
setFocused(true)} onBlur={() => setFocused(false)} value={internalValue} sizeRef={ref} onChange={onChange} onScroll={onScroll} {...additional}/>
); } function addLineBreaks(value?: string | number, addLastBreak = false) { if (typeof value === "number" || value === undefined) return value; if (typeof value !== "string") { console.error("addLineBreaks: value is not a string", value) return ""; } const lines = value.split("\n"); if (lines.length === 1) return {value ?? " "}; // @ts-ignore return lines.map((p, i) => {p ?? " "} {(lines.length - 1 !== i || addLastBreak) &&
}
); }