feat: add MultipleChoice and MultipleSelect renderers

This commit is contained in:
LaurensBartelds committed 2026-04-21 21:38:58 +02:00
1 parent b5e53c97e6
commit 535434421a
2 files changed
+80

No files matched your search

@@ -0,0 +1,40 @@
import Tex from '../Tex'
import type { Question } from '../../types'
interface Props {
q: Question
value: string | null | undefined
onChange: (val: string) => void
locked?: boolean
graded?: boolean
}
export default function MultipleChoice({ q, value, onChange, locked, graded }: Props) {
return (
<div className="choices" role="radiogroup">
{(q.choices ?? []).map((c, i) => {
const isSelected = value === c.id
let cls = 'choice'
if (isSelected) cls += ' selected'
if (graded) {
if (c.id === q.answer) cls += ' correct'
else if (isSelected) cls += ' wrong'
}
return (
<button
key={c.id}
className={cls}
onClick={() => !locked && onChange(c.id)}
disabled={locked}
role="radio"
aria-checked={isSelected}
>
<span className="choice-marker" />
<span className="choice-key">{String.fromCharCode(65 + i)}</span>
<Tex>{c.text}</Tex>
</button>
)
})}
</div>
)
}
@@ -0,0 +1,40 @@
import Tex from '../Tex'
import type { Question } from '../../types'
interface Props {
q: Question
value: string[] | null | undefined
onChange: (val: string[]) => void
locked?: boolean
graded?: boolean
}
export default function MultipleSelect({ q, value, onChange, locked, graded }: Props) {
const current = value ?? []
const toggle = (id: string) => {
if (locked) return
onChange(current.includes(id) ? current.filter((v) => v !== id) : [...current, id])
}
const answerSet = new Set((q.answer as string[]) ?? [])
return (
<div className="choices">
{(q.choices ?? []).map((c, i) => {
const isSelected = current.includes(c.id)
let cls = 'choice'
if (isSelected) cls += ' selected'
if (graded) {
if (answerSet.has(c.id)) cls += ' correct'
else if (isSelected) cls += ' wrong'
}
return (
<button key={c.id} className={cls} onClick={() => toggle(c.id)} disabled={locked}>
<span className="choice-marker square" />
<span className="choice-key">{String.fromCharCode(65 + i)}</span>
<Tex>{c.text}</Tex>
</button>
)
})}
</div>
)
}