import { collectChoices, collectFeatures } from '@/lib/rules'; import type { ClassEntry } from '@/lib/schemas'; import { Input, Select } from '@/components/ui/Input'; import { Badge } from '@/components/ui/Codex'; import { SheetSection, type SectionProps } from './common'; /** * Class features + every choice the character must make — 5e (Fighting Style, Pact Boon, * Invocations, Metamagic, Expertise, subclass maneuvers…) and PF2e (class/skill/general/ * ancestry feats, instinct/doctrine/bloodline…) — so no unlock-able option is missed. */ export function ClassFeaturesSection({ c, update }: SectionProps) { // 5e multiclasses via classes[]; pf2e is single-class with its subclass resolved in choices[]. const classes: ClassEntry[] = c.classes.length ? c.classes : c.className ? [{ className: c.className, level: c.level, ...(c.system === 'pf2e' ? { subclass: c.choices.find((ch) => ch.key.endsWith(':subclass'))?.values[0] } : {}) }] : []; const features = collectFeatures(c.system, classes); const choices = collectChoices(c.system, classes); if (features.length === 0 && choices.length === 0) return null; const getVals = (key: string) => c.choices.find((ch) => ch.key === key)?.values ?? []; const setVal = (key: string, idx: number, value: string) => { const cur = [...getVals(key)]; while (cur.length <= idx) cur.push(''); cur[idx] = value; update({ choices: [...c.choices.filter((ch) => ch.key !== key), { key, values: cur }] }); }; const pendingTotal = choices.reduce((n, ch) => n + Math.max(0, ch.count - getVals(ch.key).filter(Boolean).length), 0); return ( {choices.length > 0 && (
Choices {pendingTotal > 0 && {pendingTotal} to choose}
{choices.map((ch) => { const vals = getVals(ch.key); const filled = vals.filter(Boolean).length; return (
{ch.label} {ch.source} {filled < ch.count && choose {ch.count - filled}}
{Array.from({ length: ch.count }).map((_, i) => { const val = vals[i] ?? ''; return ch.options ? ( ) : ( setVal(ch.key, i, e.target.value)} aria-label={`${ch.label} ${i + 1}`} placeholder={`${ch.label} ${i + 1}`} /> ); })}
{ch.hint &&

{ch.hint}

}
); })}
)} {features.length > 0 && (
Features
)}
); }