3.1 KiB
Research: Combatant Row Declutter
Feature: 019-combatant-row-declutter Date: 2026-03-06
R1: Popover Dismissal Pattern
Decision: Use a click-outside listener with ref-based boundary detection, consistent with the existing ConditionPicker component pattern.
Rationale: The codebase already uses this pattern in condition-picker.tsx / condition-tags.tsx where clicking outside the picker closes it. Reusing the same approach maintains consistency and avoids introducing new dependencies (e.g., a popover library). The popover will use useEffect with a document-level click handler that checks if the click target is outside the popover ref.
Alternatives considered:
- Headless UI library (Radix Popover, Floating UI): Adds a dependency for a simple use case. Rejected — the project has no headless UI library and introducing one for a single popover is over-engineering.
- HTML
<dialog>/popoverattribute: Native browser support is good, but thepopoverattribute doesn't provide the positioning control needed (anchored to the HP value). Rejected for insufficient positioning semantics.
R2: Click-to-Edit Pattern for AC
Decision: Reuse the exact same pattern as the existing EditableName component — toggle between static display and input on click, commit on Enter/blur, cancel on Escape.
Rationale: EditableName in combatant-row.tsx already implements this exact interaction pattern. The AC click-to-edit can follow the same state machine (editing boolean, draft state, commit/cancel callbacks). This ensures behavioral consistency across the row.
Alternatives considered:
- Popover (same as HP): AC editing is simpler (just set a value, no damage/heal distinction), so a popover adds unnecessary complexity. Rejected.
- Double-click to edit: Less discoverable than single-click. Rejected — the existing name edit uses single-click.
R3: HP Popover Positioning
Decision: Position the popover directly below (or above if near viewport bottom) the current HP value using simple CSS absolute/relative positioning.
Rationale: The popover only needs to appear near the trigger element. The combatant row is a simple list layout — no complex scrolling containers or overflow clipping that would require a positioning library. Simple CSS positioning (relative parent + absolute child) is sufficient.
Alternatives considered:
- Floating UI / Popper.js: Provides advanced positioning with flip/shift. Overkill for this use case since the encounter list is a straightforward vertical layout. Rejected.
R4: Keyboard Shortcuts in Popover
Decision: Handle Enter (damage) and Shift+Enter (heal) via onKeyDown on the popover's input element. Escape handled at the same level to close the popover.
Rationale: This matches the existing QuickHpInput pattern where Enter applies damage. Adding Shift+Enter for healing is a natural modifier key extension. The input captures all keyboard events, so no global listeners are needed.
Alternatives considered:
- Separate keyboard shortcut system: Unnecessary complexity for two shortcuts scoped to a single input. Rejected.