Bug Hunt Feedback
The response panel that pairs with a BugHunt code panel. Three slots stack vertically — a wrong-line hint while the learner is still hunting, a celebration line once every bug has been flagged, and a long-form explanation card once the surrounding flow is done.
Purely presentational: the surrounding shell owns the state machine and code panel; this primitive consumes a thin set of status props and animates the three slots in and out.
Preview
Line 3 looks fine — the assignment is correct. Try a line that touches the loop guard.
Customize
Phase
Options
Installation
npx shadcn@latest add https://craftbits.dev/r/bug-hunt-feedback.jsonUsage
import { BugHuntFeedback } from "@craft-bits/core";
<BugHuntFeedback
phase="find"
selectedLine={3}
wrongLineCount={1}
remainingBugs={1}
wrongLineHint="Try a line that touches the loop guard."
/>Once the hunt is fully done, drop into the explanation phase:
<BugHuntFeedback
phase="done"
remainingBugs={0}
foundCount={2}
explanation="The loop guard reads one past the end — change <= to <."
/>wrongLineHint accepts three shapes — a static string, an array indexed by wrongLineCount, or a function called with the tapped line:
// Array — escalates per miss; clamps to the last entry
<BugHuntFeedback
phase="find"
wrongLineCount={2}
wrongLineHint={["Look at the loop.", "It is the comparison operator."]}
/>
// Function — receives the tapped line
<BugHuntFeedback
phase="find"
selectedLine={4}
wrongLineHint={(line) => "Line " + line + " is not the bug — check earlier."}
/>Anatomy
- Wrong-line hint — small warning-tinted text. Only renders while
phase === "find", after at least one miss, and on a line that is not already infoundLines. - Celebration — checkmark plus a headline ("Bug found!" / "All bugs found!"), shown once
remainingBugsis0and the phase has advanced tocompleteordone. - Explanation card — accent-railed prose. Renders only on
phase === "done"and whenexplanationis non-empty; passsuppressExplanationto hide it even ondone.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
phase | 'find' | 'complete' | 'done' | — | Drives which slots render. |
wrongLineHint | string | string[] | (line) => string | — | Hint shown after a miss. |
selectedLine | number | null | null | 1-indexed line most recently selected. |
wrongLineCount | number | 0 | Total wrong-line taps so far. Indexes into wrongLineHint. |
remainingBugs | number | 0 | Bugs still to find. 0 reveals the celebration. |
foundCount | number | 0 | Bugs found so far. Tunes the headline (singular vs plural). |
foundLines | ReadonlySet<number> | — | Lines already confirmed as bugs. Suppresses the hint when selectedLine matches. |
suppressExplanation | boolean | false | Force the explanation hidden even on done. |
explanation | ReactNode | — | Long-form explanation revealed on done. |
accentColor | string | var(--cb-accent) | Left-rail color for the explanation card. |
celebrationLabel | ReactNode | tone-derived | Override the celebration headline. |
className | string | — | Merged onto the root via cn(). |
Accessibility
- Each of the three slots renders inside a
role="status"region witharia-live="polite"so screen-reader users hear new feedback as it appears without being interrupted. - All animation is opacity + small translate only; reduced-motion users see the same content without the spring.
- Color is never the only channel — every slot has its own text label.
Credits
- Extracted from:
AlgoFlashcards(src/lessons/primitives/BugHunt/BugHuntFeedback.tsx). Stripped theuseBugHuntContextcoupling and the source's mixed-responsibility branching (the same component decided celebration vs explanation by readingfixOptions.length). Re-shaped around an explicitphaseplus thin status props so the panel works outside the original BugHunt shell. InlineSPRING.snappy/SPRING.bouncy/SPRING.smoothand hardcodedtext-warning/text-success/text-muted-foregroundclasses were swapped forSPRINGS.*and thecb-*semantic tokens.