Files
initiative/specs/010-ui-baseline/contracts/ui-components.md

3.0 KiB

UI Component Contracts: UI Baseline

Feature: 010-ui-baseline | Date: 2026-03-05

Layout Contract

The encounter screen follows a single-column layout with three zones:

┌─────────────────────────────────┐
│         EncounterHeader         │
│  Title + Round/Turn status      │
├─────────────────────────────────┤
│         CombatantList           │
│  ┌─ CombatantRow (active) ───┐  │
│  │ Init │ Name │ HP │ Actions│  │
│  └───────────────────────────┘  │
│  ┌─ CombatantRow ────────────┐  │
│  │ Init │ Name │ HP │ Actions│  │
│  └───────────────────────────┘  │
│  ... (scrollable if overflow)   │
│                                 │
│  [EmptyState if no combatants]  │
├─────────────────────────────────┤
│           ActionBar             │
│  [Name input] [Add] [Next Turn] │
└─────────────────────────────────┘

CombatantRow Contract

Props:

  • combatant: Combatant — domain entity
  • isActive: boolean — whether this is the active turn
  • onRename: (id, newName) => void
  • onSetInitiative: (id, value) => void
  • onRemove: (id) => void
  • onSetHp: (id, maxHp) => void
  • onAdjustHp: (id, delta) => void

Visual contract:

  • Row uses consistent column widths across all combatant rows
  • Active row has visually distinct highlight (accent background or left border)
  • Name column truncates with ellipsis at max width
  • Remove action is an icon button (no text label)
  • All inputs use design system styling (no browser defaults)

Interaction contract:

  • Click name → enter inline edit mode
  • Enter/blur in edit mode → commit change
  • Escape in edit mode → cancel
  • Initiative input is always visible (not click-to-edit), direct typing only
  • HP inputs are direct-entry text fields with numeric keyboard (inputmode="numeric")
  • All numeric inputs: no browser spinners, ch-based widths (6ch), tabular numerals, centered text

ActionBar Contract

Props:

  • onAddCombatant: (name: string) => void
  • onAdvanceTurn: () => void

Visual contract:

  • Visually separated from combatant list (spacing, background, or border)
  • Add form: text input + submit button in a row
  • Next Turn: distinct button, visually secondary to Add

Interaction contract:

  • Enter in name input → add combatant + clear input
  • Empty name → no action (button may be disabled or form simply ignores)

EmptyState Contract

Displayed when: encounter.combatants.length === 0

Visual contract:

  • Centered message in the combatant list area
  • Muted/secondary text color
  • Suggests adding a combatant