@@ -113,19 +167,13 @@ export const AskUserQuestionCard: React.FC
= ({ reques
question={active}
name={`askq-${requestId}-${activeIdx}`}
selection={selections[activeIdx]}
+ otherActive={otherActive[activeIdx] ?? false}
+ customText={customTexts[activeIdx] ?? ""}
disabled={busy}
- onToggle={(label) =>
- setSelections((prev) => {
- if (active.multiSelect) {
- const cur = prev[activeIdx];
- const next = new Set(cur instanceof Set ? cur : []);
- if (next.has(label)) next.delete(label);
- else next.add(label);
- return { ...prev, [activeIdx]: next };
- }
- return { ...prev, [activeIdx]: label };
- })
- }
+ onTogglePreset={togglePreset}
+ onToggleOther={toggleOther}
+ onCustomTextChange={(text) => setCustomTexts((prev) => ({ ...prev, [activeIdx]: text }))}
+ onSubmitShortcut={submit}
/>
@@ -146,8 +194,14 @@ interface QuestionPanelProps {
/** Radio-group name; namespaced by requestId + index so cards don't collide. */
name: string;
selection: string | Set
| undefined;
+ otherActive: boolean;
+ customText: string;
disabled: boolean;
- onToggle: (label: string) => void;
+ onTogglePreset: (label: string) => void;
+ onToggleOther: () => void;
+ onCustomTextChange: (text: string) => void;
+ /** Cmd/Ctrl+Enter in the textarea; the parent guards on `canSubmit`. */
+ onSubmitShortcut: () => void;
}
/** The active question's prompt text plus its single- or multi-select option list. */
@@ -155,9 +209,15 @@ const QuestionPanel: React.FC = ({
question,
name,
selection,
+ otherActive,
+ customText,
disabled,
- onToggle,
+ onTogglePreset,
+ onToggleOther,
+ onCustomTextChange,
+ onSubmitShortcut,
}) => {
+ const control = question.multiSelect ? "checkbox" : "radio";
return (
{question.question}
@@ -177,11 +237,11 @@ const QuestionPanel: React.FC
= ({
native checkboxes/radios, which was throwing off alignment. */}
onToggle(opt.label)}
+ onChange={() => onTogglePreset(opt.label)}
className="tw-m-0"
/>
@@ -194,7 +254,44 @@ const QuestionPanel: React.FC = ({
);
})}
+
+ {/* "Other" escape hatch: shares the radio group name so single-select
+ grouping stays native, and reveals a free-form textarea when armed. */}
+
+
+ {otherActive ? (
+
);
};