'use client'; import type { ReactElement } from 'react'; import type { GameView } from '@/game/engine'; import type { TruthFact } from '@/game/truthtrance'; import { TRUTH_FACT_MAX_DEPTH, TRUTH_FACT_MAX_NODES, TRUTH_FACT_MAX_TERMS, truthFactExpressionError, truthFactExpressionSize, } from '@/game/truth-fact-expression'; import { TruthFactFields } from './mixed-shipment-fields'; import { Button } from './ui/button'; const newFact = (): TruthFact => ({ kind: 'hand', name: 'Shield' }); /** Controlled structure editor. Leaf controls retain their existing validators. */ export function TruthFactExpressionFields({ value, game, target, disabled, onChange }: { value: TruthFact; game: GameView; target: string; disabled: boolean; onChange: (fact: TruthFact) => void; }) { const size = truthFactExpressionSize(value); const commit = (next: TruthFact) => { if (!disabled && !truthFactExpressionError(next)) onChange(next); }; const render = ( node: TruthFact, path: string, replace: (next: TruthFact) => TruthFact, remove?: () => TruthFact, ): ReactElement => { const group = node.kind === 'and' || node.kind === 'or'; const allowed = (next: TruthFact) => !disabled && !truthFactExpressionError(replace(next)); const change = (next: TruthFact) => commit(replace(next)); const wrap = (kind: 'and' | 'or'): TruthFact => ({ kind, terms: [node, newFact()] }); return
{group ? `Group ${path} · ${node.kind.toUpperCase()}` : `Current fact ${path}`} {group ? <> {node.terms.map((term, index) => render( term, `${path}.${index + 1}`, next => replace({ ...node, terms: node.terms.map((old, i) => i === index ? next : old) }), () => { const terms = node.terms.filter((_, i) => i !== index); return replace(terms.length === 1 ? terms[0] : { ...node, terms }); }, ))}
: }
{remove && }
; }; return
Current-fact expression

AND requires all conditions; OR requires at least one. The player gives one aggregate answer for the whole expression. No makes the whole expression false, not necessarily every condition.

Current facts are evaluated when the player answers. They create no promise to keep cards, spice or forces afterward.

App limits: {TRUTH_FACT_MAX_TERMS} terms per group, {TRUTH_FACT_MAX_NODES} total clauses including groups, and {TRUTH_FACT_MAX_DEPTH} levels of grouping. These are input limits, not additional printed rules.

{size.nodes} / {TRUTH_FACT_MAX_NODES} total clauses · {size.depth} / {TRUTH_FACT_MAX_DEPTH} levels of grouping

{render(value, '1', next => next)}
; }