Update input field error/warning behavior and time picker handling

This commit is contained in:
2025-12-03 22:38:59 +00:00
parent 41ffce1c23
commit 63d6124ce3
6 changed files with 154 additions and 71 deletions

View File

@@ -50,9 +50,10 @@ const FormNumericInput = React.forwardRef<HTMLInputElement, NumericInputProps>(
className,
...props
}, ref) => {
const [showError, setShowError] = React.useState(false)
const [showWarning, setShowWarning] = React.useState(false)
const [, setShowError] = React.useState(false)
const [, setShowWarning] = React.useState(false)
const [touched, setTouched] = React.useState(false)
const [isFocused, setIsFocused] = React.useState(false)
const containerRef = React.useRef<HTMLDivElement>(null)
// Check if value is invalid (check validity regardless of touch state)
@@ -114,20 +115,25 @@ const FormNumericInput = React.forwardRef<HTMLInputElement, NumericInputProps>(
}
const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {
const val = e.target.value
const inputValue = e.target.value.trim()
setTouched(true)
setIsFocused(false)
setShowError(false)
setShowWarning(false)
if (val === '' && !allowEmpty) {
if (inputValue === '' && !allowEmpty) {
// Update parent with empty value so validation works
onChange('')
return
}
if (val !== '' && !isNaN(Number(val))) {
onChange(formatValue(val))
if (inputValue !== '' && !isNaN(Number(inputValue))) {
onChange(formatValue(inputValue))
}
}
const handleFocus = () => {
setIsFocused(true)
setShowError(hasError)
setShowWarning(hasWarning)
}
@@ -162,7 +168,8 @@ const FormNumericInput = React.forwardRef<HTMLInputElement, NumericInputProps>(
size="icon"
className={cn(
"h-9 w-9 rounded-r-none border-r-0",
hasError && "border-destructive"
hasError && "border-destructive",
hasWarning && !hasError && "border-yellow-500"
)}
onClick={() => updateValue(-1)}
tabIndex={-1}
@@ -181,7 +188,8 @@ const FormNumericInput = React.forwardRef<HTMLInputElement, NumericInputProps>(
"w-20 h-9 z-20",
"rounded-none",
getAlignmentClass(),
hasError && "border-destructive focus-visible:ring-destructive"
hasError && "border-destructive focus-visible:ring-destructive",
hasWarning && !hasError && "border-yellow-500 focus-visible:ring-yellow-500"
)}
{...props}
/>
@@ -192,7 +200,8 @@ const FormNumericInput = React.forwardRef<HTMLInputElement, NumericInputProps>(
className={cn(
"h-9 w-9",
clearButton && allowEmpty ? "rounded-l-none rounded-r-none border-x-0" : "rounded-l-none border-l-0",
hasError && "border-destructive"
hasError && "border-destructive",
hasWarning && !hasError && "border-yellow-500"
)}
onClick={() => updateValue(1)}
tabIndex={-1}
@@ -206,7 +215,8 @@ const FormNumericInput = React.forwardRef<HTMLInputElement, NumericInputProps>(
size="icon"
className={cn(
"h-9 w-9 rounded-l-none",
hasError && "border-destructive"
hasError && "border-destructive",
hasWarning && !hasError && "border-yellow-500"
)}
onClick={() => onChange('')}
tabIndex={-1}
@@ -216,13 +226,13 @@ const FormNumericInput = React.forwardRef<HTMLInputElement, NumericInputProps>(
)}
</div>
{unit && <span className="text-sm text-muted-foreground whitespace-nowrap">{unit}</span>}
{hasError && showError && errorMessage && (
{hasError && isFocused && errorMessage && (
<div className="absolute top-full left-0 mt-1 z-50 w-64 bg-destructive text-destructive-foreground text-xs p-2 rounded-md shadow-lg">
{errorMessage}
</div>
)}
{hasWarning && showWarning && warningMessage && (
<div className="absolute top-full left-0 mt-1 z-50 w-48 bg-yellow-500 text-yellow-950 text-xs p-2 rounded-md shadow-lg">
{hasWarning && isFocused && warningMessage && (
<div className="absolute top-full left-0 mt-1 z-50 w-48 bg-yellow-500 text-white text-xs p-2 rounded-md shadow-lg">
{warningMessage}
</div>
)}