Public Access
feat: add MultipleChoice and MultipleSelect renderers
This commit is contained in:
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>
|
||||
)
|
||||
}
|
||||
Reference in new issue
Block a user