From 9e4c0086808016f54d1049f28e52bb7fc9ea0564 Mon Sep 17 00:00:00 2001 From: Xevion Date: Wed, 22 Oct 2025 17:19:29 -0500 Subject: [PATCH] feat: enhance LookupInput with visual badges and flicker-free detection - Add Badge component to display autodetection status with color coding - Show green "Auto" badge when type is detected, red when unknown - Prevent badge flickering during empty-to-non-empty input transitions - Increase lock icon size from 14x14 to 16x16 pixels with blue color - Track input state to manage smooth badge transitions --- src/rdap/components/LookupInput.tsx | 60 +++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 7 deletions(-) diff --git a/src/rdap/components/LookupInput.tsx b/src/rdap/components/LookupInput.tsx index 7399fd1..3828fca 100644 --- a/src/rdap/components/LookupInput.tsx +++ b/src/rdap/components/LookupInput.tsx @@ -1,11 +1,11 @@ import { useForm, Controller } from "react-hook-form"; import type { FunctionComponent } from "react"; -import { useState } from "react"; +import { useState, useEffect } from "react"; import { onPromise, preventDefault } from "@/lib/utils"; import type { SimplifiedTargetType, SubmitProps, TargetType } from "@/rdap/schemas"; import { TargetTypeEnum } from "@/rdap/schemas"; import { MagnifyingGlassIcon, ReloadIcon, LockClosedIcon } from "@radix-ui/react-icons"; -import { TextField, Select, Flex, Checkbox, Text, IconButton } from "@radix-ui/themes"; +import { TextField, Select, Flex, Checkbox, Text, IconButton, Badge } from "@radix-ui/themes"; import type { Maybe } from "true-myth"; import { placeholders } from "@/rdap/constants"; @@ -85,6 +85,17 @@ const LookupInput: FunctionComponent = ({ */ const [selected, setSelected] = useState("auto"); + /** + * Tracks the current input value to determine if the field is empty. + */ + const [inputValue, setInputValue] = useState(""); + + /** + * Tracks whether we're waiting for type detection after transitioning from empty to non-empty input. + * Prevents badge from flickering during initial input. + */ + const [showingPlaceholder, setShowingPlaceholder] = useState(false); + /** * Retrieves the target type based on the provided value. * @param value - The value to retrieve the target type for. @@ -102,6 +113,16 @@ const LookupInput: FunctionComponent = ({ return result.success ? result.data : null; } + /** + * Clear the placeholder flag when type detection completes. + * This prevents badge flickering when transitioning from empty to non-empty input. + */ + useEffect(() => { + if (showingPlaceholder) { + setShowingPlaceholder(false); + } + }, [detectedType]); + return (
= ({ {...register("target", { required: true, onChange: () => { + const targetValue = getValues("target"); + const oldIsEmpty = inputValue.trim() === ""; + const newIsEmpty = targetValue.trim() === ""; + + // Transitioning from empty to non-empty - show placeholder until detection completes + if (oldIsEmpty && !newIsEmpty) { + setShowingPlaceholder(true); + } else if (newIsEmpty) { + // Input is now empty - clear placeholder + setShowingPlaceholder(false); + } + + setInputValue(targetValue); if (onChange != undefined) void onChange({ - target: getValues("target"), + target: targetValue, targetType: retrieveTargetType(null), }); }, @@ -177,14 +211,26 @@ const LookupInput: FunctionComponent = ({ }} > {selected == "auto" ? ( - detectedType.isJust ? ( - Auto ({targetShortNames[detectedType.value]}) - ) : ( + showingPlaceholder || inputValue.trim() === "" ? ( objectNames["auto"] + ) : detectedType.isJust ? ( + + Auto + {targetShortNames[detectedType.value]} + + ) : ( + + Auto + Unknown + ) ) : ( - + {objectNames[selected]} )}