From 9a0c834a7a7756dfe3fc56dd78832f6308b6d17d Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 14 Dec 2025 03:05:44 +0000 Subject: [PATCH] feat(ui): add clear button to URL input - Adds a conditional 'X' button to `UrlInput` when text is present - Implements `useRef` to auto-focus input after clearing - Ensures accessibility with `aria-label` and keyboard support - Updates `components/url-input.tsx` to include `X` icon from lucide-react --- .Jules/palette.md | 3 +++ components/url-input.tsx | 23 +++++++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 .Jules/palette.md diff --git a/.Jules/palette.md b/.Jules/palette.md new file mode 100644 index 0000000..309e21a --- /dev/null +++ b/.Jules/palette.md @@ -0,0 +1,3 @@ +## 2024-05-23 - Clear Actions in Inputs +**Learning:** Users often paste incorrect URLs and need a quick way to reset the input field. A dedicated "Clear" button (X) is a standard pattern that improves speed and reduces friction compared to selecting all text and deleting. +**Action:** When implementing input fields that are the primary action of a page (like a search bar or URL input), always consider adding a "Clear" button that appears when content is present. Ensure it is accessible (focusable, labelled) and returns focus to the input after clicking. diff --git a/components/url-input.tsx b/components/url-input.tsx index 616b6d1..fcf6a4f 100644 --- a/components/url-input.tsx +++ b/components/url-input.tsx @@ -1,7 +1,7 @@ "use client"; -import { useState, useEffect } from "react"; -import { Loader2, ArrowUp, Link, Sparkles } from "lucide-react"; +import { useState, useEffect, useRef } from "react"; +import { Loader2, ArrowUp, Link, Sparkles, X } from "lucide-react"; import { extractVideoId } from "@/lib/utils"; import { cn } from "@/lib/utils"; import { Button } from "@/components/ui/button"; @@ -31,6 +31,7 @@ export function UrlInput({ const [error, setError] = useState(""); const [isFocused, setIsFocused] = useState(false); const [isValidUrl, setIsValidUrl] = useState(false); + const inputRef = useRef(null); const forceSmartMode = isGrokProviderOnClient(); const showModeSelector = !forceSmartMode && typeof onModeChange === "function"; @@ -50,6 +51,13 @@ export function UrlInput({ setIsValidUrl(!!videoId); }, [url]); + const handleClear = () => { + setUrl(""); + setIsValidUrl(false); + setError(""); + inputRef.current?.focus(); + }; + const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); setError(""); @@ -84,6 +92,7 @@ export function UrlInput({ setUrl(e.target.value)} @@ -96,6 +105,16 @@ export function UrlInput({ className="flex-1 border-0 bg-transparent text-[14px] text-[#989999] placeholder:text-[#989999] focus:outline-none" disabled={isLoading} /> + {url && !isLoading && ( + + )} {/* Bottom row: Mode selector (left) and actions (right) */}