/** * src/book/components/Quiz.tsx * * Multiple-choice or predict-the-output question with instant feedback. * No server required — answers are evaluated client-side. * * Usage in MDX: * */ interface Props { question: string; options: string[]; /** 0-based index of the correct answer. */ answer: number; /** Optional explanation shown after answering. */ explanation?: string; } import { useState } from 'react'; export default function Quiz({ question, options, answer, explanation }: Props) { const [selected, setSelected] = useState(null); const answered = selected !== null; return ( {/* Header */} Quiz {question} {options.map((opt, i) => { const isCorrect = i === answer; const isSelected = i === selected; let bg = 'var(--bk-chip-bg)'; let color = 'var(--bk-text)'; let borderColor = 'var(--bk-border)'; if (answered) { if (isCorrect) { bg = 'var(--bk-chip-correct-bg)'; color = 'var(--bk-chip-correct-text)'; borderColor = 'var(--bk-chip-correct-text)'; } else if (isSelected) { bg = 'var(--bk-chip-wrong-bg)'; color = 'var(--bk-chip-wrong-text)'; borderColor = 'var(--bk-chip-wrong-text)'; } } return ( !answered && setSelected(i)} disabled={answered} style={{ display: 'flex', alignItems: 'center', gap: '0.6rem', padding: '0.45rem 0.75rem', background: bg, color, border: `1px solid ${borderColor}`, borderRadius: 4, textAlign: 'left', cursor: answered ? 'default' : 'pointer', fontFamily: 'var(--bk-font-prose)', fontSize: '0.88rem', transition: 'background 0.1s, border-color 0.1s', }} > {String.fromCharCode(65 + i)}. {opt} {answered && isCorrect && ✓} {answered && isSelected && !isCorrect && ✗} ); })} {/* Explanation */} {answered && explanation && ( {explanation} )} ); }
{question}
{explanation}