Controlled inline search field that replaces the chat panel header's title area when search is active, debouncing typed input before emitting it to the host for server-side refetching. ## Key Components ### `ChatHeaderSearchField` The primary export. Renders a leading `SearchIcon` alongside a borderless, full-height `` that takes over the header title slot. Manages its own text state locally for snappy typing, then propagates the debounced query (300 ms) via `onSearchChange`. **Collapse lifecycle** — exit animations are coordinated manually: 1. `beginCollapse()` sets `exiting = true`, disabling the input and triggering CSS leave animations. 2. `finishCollapse()` is called on `animationend` of the root element (bubbled child events are ignored). 3. A 240 ms `setTimeout` fallback fires `finishCollapse` when `animationend` never fires (reduced-motion or stripped utilities). **Stale-debounce guard** — when Escape is pressed or the field blurs empty, the cleared term is emitted synchronously and recorded in `lastEmitted`, preventing the still-pending 300 ms debounce from triggering a redundant server round-trip after unmount begins. ### `ChatHeaderSearchFieldProps` | Prop | Type | Default | Description | |---|---|---|---| | `initialValue` | `string` | `''` | Seeds the input on mount | | `onSearchChange` | `(query: string) => void` | — | Receives the debounced search term | | `onCollapse` | `() => void` | — | Called after the leave animation completes | | `autoFocus` | `boolean` | `true` | Focuses the input on mount | | `className` | `string` | — | Appended to the root element | ## Usage Example ```typescript import { ChatHeaderSearchField } from './chat-header-search-field' function ChatPanelHeader() { const [searchOpen, setSearchOpen] = React.useState(false) const [query, setQuery] = React.useState('') return (
{searchOpen ? ( setQuery(term)} onCollapse={() => setSearchOpen(false)} /> ) : (

Chats

)}
) } ```