# UI Contracts: Bestiary Search & Stat Block Display **Branch**: `021-bestiary-statblock` | **Date**: 2026-03-06 ## Component Contracts ### BestiarySearch **Purpose**: Search input with autocomplete dropdown for creature selection. **Props**: - `onSelectCreature: (creature: Creature) => void` — Called when user selects a creature from results - `onClose: () => void` — Called when search is dismissed (Escape, click outside) **Behavior**: - Opens focused on the search input - Filters creatures by case-insensitive substring match on name - Minimum 2 characters before showing results - Maximum 10 results shown at a time - Keyboard navigation: ArrowUp/ArrowDown to navigate, Enter to select, Escape to close - Shows "No creatures found" for zero-match queries - Shows source tag next to creature name (e.g., "Goblin (MM 2024)") ### StatBlock **Purpose**: Renders a complete creature stat block. **Props**: - `creature: Creature` — The creature data to display **Sections rendered** (in order, omitted if data absent): 1. Header: name, size, type, alignment 2. Stats bar: AC, HP (average + formula), Speed 3. Ability scores: STR/DEX/CON/INT/WIS/CHA with modifiers 4. Properties: Saving Throws, Skills, Damage Vulnerabilities, Damage Resistances, Damage Immunities, Condition Immunities, Senses, Languages, CR + Proficiency Bonus 5. Traits 6. Spellcasting (rendered as a separate section after traits) 7. Actions 8. Bonus Actions 9. Reactions 10. Legendary Actions (with preamble text) ### StatBlockPanel **Purpose**: Responsive wrapper — side panel on desktop, drawer on mobile. **Props**: - `creature: Creature | null` — Currently displayed creature (null = closed) - `onClose: () => void` — Close the panel/drawer **Behavior**: - Desktop (>= 1024px): Renders as a right-side panel, tracker shifts left - Mobile (< 1024px): Renders as a slide-over drawer from right with backdrop - Close button always visible - Panel scrolls independently of the main content ### ActionBar (modified) **Extended Props**: - `onAddCombatant: (name: string) => void` — Existing: add plain combatant - `onAddFromBestiary: (creature: Creature) => void` — New: add creature with stat pre-fill - `suggestions: Creature[]` — Matching creatures for current name input - `onSearchChange: (query: string) => void` — Notify parent of input changes for suggestion filtering **New Elements**: - Magnifying glass icon button next to input → opens dedicated BestiarySearch - Autocomplete suggestion list below input when typing (>= 2 chars and matches exist) ## Hook Contracts ### useBestiary **Purpose**: Provides creature search and lookup from the bundled bestiary. **Returns**: - `search: (query: string) => Creature[]` — Filter creatures by name substring - `getCreature: (id: CreatureId) => Creature | undefined` — Look up creature by ID - `allCreatures: Creature[]` — Full list (for potential future use) **Behavior**: - Loads and normalizes bestiary data once on initialization (lazy, memoized) - Search is synchronous (in-memory filter) - Returns results sorted alphabetically by name ### useEncounter (extended) **Extended return**: - `addFromBestiary: (creature: Creature) => void` — New: adds combatant with auto-numbered name, pre-filled HP/AC, and creatureId link **Auto-numbering behavior**: - Checks existing combatant names for conflicts with the creature's base name - If no conflict: uses creature name as-is - If one existing match: renames existing to "Name 1", new one becomes "Name 2" - If N existing matches: new one becomes "Name N+1" - Names remain editable after auto-numbering ## Layout Contract ### App (modified) **Desktop layout (>= 1024px, stat block open)**: ``` +--------------------------------------------------+ | Header | +-------------------------+------------------------+ | Tracker (flex-1) | Stat Block (~400px) | | - Turn Navigation | - Scrollable | | - Combatant List | - Close button | | - Action Bar | | +-------------------------+------------------------+ ``` **Desktop layout (stat block closed)**: ``` +--------------------------------------------------+ | Header | | Tracker (max-w-2xl, centered) | | - Turn Navigation | | - Combatant List | | - Action Bar | +--------------------------------------------------+ ``` **Mobile layout (< 1024px, stat block open)**: ``` +--------------------------------------------------+ | Header | | Tracker (full width) | | - Turn Navigation | | - Combatant List | | - Action Bar | | | | +----------------------------------------------+ | | | Drawer (slide from right, 85% width) | | | | - Close button | | | | - Stat Block (scrollable) | | | +----------------------------------------------+ | | | Backdrop (click to close) | | +--------------------------------------------------+ ```