auq-mcp-server 3.2.4 → 3.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/package.json +1 -1
- package/dist/src/tui/components/Footer.js +3 -2
- package/dist/src/tui/components/MultiLineTextInput.js +13 -11
- package/dist/src/tui/components/StepperView.js +34 -15
- package/dist/src/tui/components/__tests__/Footer.test.js +4 -3
- package/dist/src/tui/constants/keybindings.js +2 -1
- package/dist/src/tui-opentui/components/Footer.js +4 -3
- package/dist/src/tui-opentui/components/OptionsList.js +55 -26
- package/dist/src/tui-opentui/components/StepperView.js +32 -15
- package/package.json +1 -1
package/dist/package.json
CHANGED
|
@@ -33,8 +33,8 @@ export const Footer = ({ focusContext, multiSelect, isReviewScreen = false, show
|
|
|
33
33
|
return [
|
|
34
34
|
{ key: KEY_LABELS.NAVIGATE_OPTIONS, action: t("footer.options") },
|
|
35
35
|
{ key: KEY_LABELS.CURSOR, action: t("footer.cursor") },
|
|
36
|
-
{ key: KEY_LABELS.NAVIGATE_QUESTIONS_TAB, action: t("footer.questions") },
|
|
37
36
|
{ key: KEY_LABELS.NEWLINE, action: t("footer.newline") },
|
|
37
|
+
{ key: KEY_LABELS.ADVANCE_INPUT, action: t("footer.next") },
|
|
38
38
|
{ key: KEY_LABELS.REJECT, action: t("footer.reject") },
|
|
39
39
|
];
|
|
40
40
|
}
|
|
@@ -43,7 +43,8 @@ export const Footer = ({ focusContext, multiSelect, isReviewScreen = false, show
|
|
|
43
43
|
return [
|
|
44
44
|
{ key: KEY_LABELS.NAVIGATE_OPTIONS, action: t("footer.options") },
|
|
45
45
|
{ key: KEY_LABELS.CURSOR, action: t("footer.cursor") },
|
|
46
|
-
{ key:
|
|
46
|
+
{ key: KEY_LABELS.NEWLINE, action: t("footer.newline") },
|
|
47
|
+
{ key: KEY_LABELS.ADVANCE_INPUT, action: t("footer.next") },
|
|
47
48
|
{ key: KEY_LABELS.REJECT, action: t("footer.reject") },
|
|
48
49
|
];
|
|
49
50
|
}
|
|
@@ -5,9 +5,9 @@ import { useTheme } from "../ThemeContext.js";
|
|
|
5
5
|
/**
|
|
6
6
|
* Multi-line text input component for Ink with cursor positioning
|
|
7
7
|
* Supports left/right arrow keys for cursor movement
|
|
8
|
-
* Enter for newlines, Tab
|
|
8
|
+
* Enter to submit/advance, Shift+Enter for newlines, Tab also submits
|
|
9
9
|
*/
|
|
10
|
-
export const MultiLineTextInput = ({ isFocused = true, onChange, onSubmit, placeholder = t("input.multiLinePlaceholder"), value, enterSubmits = false, }) => {
|
|
10
|
+
export const MultiLineTextInput = ({ isFocused = true, onChange, onSubmit, placeholder = t("input.multiLinePlaceholder"), value, enterSubmits: _enterSubmits = false, }) => {
|
|
11
11
|
const { theme } = useTheme();
|
|
12
12
|
// Initialize cursor at end of text (using character count for CJK support)
|
|
13
13
|
const [cursorPosition, setCursorPosition] = useState([...value].length);
|
|
@@ -45,18 +45,20 @@ export const MultiLineTextInput = ({ isFocused = true, onChange, onSubmit, place
|
|
|
45
45
|
if (key.tab && key.shift) {
|
|
46
46
|
return;
|
|
47
47
|
}
|
|
48
|
-
// Enter: Submit
|
|
48
|
+
// Enter: Submit/advance; Shift+Enter inserts newline
|
|
49
49
|
if (input === "\r" || input === "\n" || key.return) {
|
|
50
|
-
if (
|
|
51
|
-
|
|
50
|
+
if (key.shift) {
|
|
51
|
+
// Shift+Enter: Insert newline at cursor position
|
|
52
|
+
const chars = [...currentValue];
|
|
53
|
+
const before = chars.slice(0, currentCursor).join("");
|
|
54
|
+
const after = chars.slice(currentCursor).join("");
|
|
55
|
+
const newValue = before + "\n" + after;
|
|
56
|
+
onChange(newValue);
|
|
57
|
+
setCursorPosition(currentCursor + 1);
|
|
52
58
|
return;
|
|
53
59
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const after = chars.slice(currentCursor).join("");
|
|
57
|
-
const newValue = before + "\n" + after;
|
|
58
|
-
onChange(newValue);
|
|
59
|
-
setCursorPosition(currentCursor + 1);
|
|
60
|
+
// Enter (without Shift): Submit/advance
|
|
61
|
+
onSubmit?.();
|
|
60
62
|
return;
|
|
61
63
|
}
|
|
62
64
|
// Left arrow: Move cursor left (accounting for CJK characters)
|
|
@@ -77,24 +77,37 @@ export const StepperView = ({ onComplete, onProgress, hasMultipleSessions, initi
|
|
|
77
77
|
}, [currentQuestionIndex]);
|
|
78
78
|
// Handle option selection (single-select mode)
|
|
79
79
|
const handleSelectOption = (label) => {
|
|
80
|
+
const existing = answers.get(currentQuestionIndex) || {};
|
|
81
|
+
const isDeselecting = existing.selectedOption === label;
|
|
80
82
|
setAnswers((prev) => {
|
|
81
83
|
const newAnswers = new Map(prev);
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
});
|
|
89
|
-
// Clear elaborate mark when selecting a regular option (single-select behavior)
|
|
90
|
-
setElaborateMarks((prev) => {
|
|
91
|
-
if (prev.has(currentQuestionIndex)) {
|
|
92
|
-
const newMarks = new Map(prev);
|
|
93
|
-
newMarks.delete(currentQuestionIndex);
|
|
94
|
-
return newMarks;
|
|
84
|
+
const existingAnswer = newAnswers.get(currentQuestionIndex) || {};
|
|
85
|
+
if (isDeselecting) {
|
|
86
|
+
newAnswers.set(currentQuestionIndex, {
|
|
87
|
+
...existingAnswer,
|
|
88
|
+
selectedOption: undefined,
|
|
89
|
+
});
|
|
95
90
|
}
|
|
96
|
-
|
|
91
|
+
else {
|
|
92
|
+
newAnswers.set(currentQuestionIndex, {
|
|
93
|
+
...existingAnswer,
|
|
94
|
+
selectedOption: label,
|
|
95
|
+
customText: undefined,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
return newAnswers;
|
|
97
99
|
});
|
|
100
|
+
// Clear elaborate mark only when SELECTING (not deselecting)
|
|
101
|
+
if (!isDeselecting) {
|
|
102
|
+
setElaborateMarks((prev) => {
|
|
103
|
+
if (prev.has(currentQuestionIndex)) {
|
|
104
|
+
const newMarks = new Map(prev);
|
|
105
|
+
newMarks.delete(currentQuestionIndex);
|
|
106
|
+
return newMarks;
|
|
107
|
+
}
|
|
108
|
+
return prev;
|
|
109
|
+
});
|
|
110
|
+
}
|
|
98
111
|
};
|
|
99
112
|
const handleToggleOption = (label) => {
|
|
100
113
|
setAnswers((prev) => {
|
|
@@ -125,13 +138,17 @@ export const StepperView = ({ onComplete, onProgress, hasMultipleSessions, initi
|
|
|
125
138
|
}
|
|
126
139
|
};
|
|
127
140
|
// Handle custom answer text
|
|
141
|
+
// Handle custom answer text
|
|
128
142
|
const handleChangeCustomAnswer = (text) => {
|
|
129
143
|
setAnswers((prev) => {
|
|
130
144
|
const newAnswers = new Map(prev);
|
|
131
145
|
const existing = newAnswers.get(currentQuestionIndex) || {};
|
|
146
|
+
const question = sessionRequest.questions[currentQuestionIndex];
|
|
132
147
|
newAnswers.set(currentQuestionIndex, {
|
|
133
148
|
...existing,
|
|
134
149
|
customText: text,
|
|
150
|
+
// Single-choice: clear selectedOption when typing custom text
|
|
151
|
+
...(text.trim().length > 0 && !question?.multiSelect ? { selectedOption: undefined } : {}),
|
|
135
152
|
});
|
|
136
153
|
return newAnswers;
|
|
137
154
|
});
|
|
@@ -331,14 +348,16 @@ export const StepperView = ({ onComplete, onProgress, hasMultipleSessions, initi
|
|
|
331
348
|
return newMarks;
|
|
332
349
|
});
|
|
333
350
|
// In single-select mode, clear selected option when marking elaborate
|
|
351
|
+
// In single-select mode, clear selected option and customText when marking elaborate
|
|
334
352
|
if (isMarking && !currentQuestion.multiSelect) {
|
|
335
353
|
setAnswers((prev) => {
|
|
336
354
|
const existing = prev.get(currentQuestionIndex);
|
|
337
|
-
if (existing?.selectedOption) {
|
|
355
|
+
if (existing?.selectedOption || existing?.customText) {
|
|
338
356
|
const newAnswers = new Map(prev);
|
|
339
357
|
newAnswers.set(currentQuestionIndex, {
|
|
340
358
|
...existing,
|
|
341
359
|
selectedOption: undefined,
|
|
360
|
+
customText: undefined,
|
|
342
361
|
});
|
|
343
362
|
return newAnswers;
|
|
344
363
|
}
|
|
@@ -42,8 +42,8 @@ describe("Footer keybinding labels", () => {
|
|
|
42
42
|
const output = getOutput(instance.lastFrame());
|
|
43
43
|
expect(output).toContain(KEY_LABELS.NAVIGATE_OPTIONS); // "↑↓"
|
|
44
44
|
expect(output).toContain(KEY_LABELS.CURSOR); // "←→"
|
|
45
|
-
expect(output).toContain(KEY_LABELS.
|
|
46
|
-
expect(output).toContain(KEY_LABELS.
|
|
45
|
+
expect(output).toContain(KEY_LABELS.NEWLINE); // "Shift+Enter"
|
|
46
|
+
expect(output).toContain(KEY_LABELS.ADVANCE_INPUT); // "Enter"
|
|
47
47
|
expect(output).toContain(KEY_LABELS.REJECT); // "Esc"
|
|
48
48
|
});
|
|
49
49
|
it("elaborate-input context shows correct keybindings", () => {
|
|
@@ -51,7 +51,8 @@ describe("Footer keybinding labels", () => {
|
|
|
51
51
|
const output = getOutput(instance.lastFrame());
|
|
52
52
|
expect(output).toContain(KEY_LABELS.NAVIGATE_OPTIONS); // "↑↓"
|
|
53
53
|
expect(output).toContain(KEY_LABELS.CURSOR); // "←→"
|
|
54
|
-
expect(output).toContain("Enter
|
|
54
|
+
expect(output).toContain(KEY_LABELS.NEWLINE); // "Shift+Enter"
|
|
55
|
+
expect(output).toContain(KEY_LABELS.ADVANCE_INPUT); // "Enter"
|
|
55
56
|
expect(output).toContain(KEY_LABELS.REJECT); // "Esc"
|
|
56
57
|
});
|
|
57
58
|
it("review screen shows Submit and Back labels", () => {
|
|
@@ -28,13 +28,13 @@ export const Footer = ({ focusContext, multiSelect, isReviewScreen = false, show
|
|
|
28
28
|
{ key: KEY_LABELS.BACK, action: t("footer.back") },
|
|
29
29
|
];
|
|
30
30
|
}
|
|
31
|
-
// Custom input focused
|
|
31
|
+
// Custom input focused (Enter submits)
|
|
32
32
|
if (focusContext === "custom-input") {
|
|
33
33
|
return [
|
|
34
34
|
{ key: KEY_LABELS.NAVIGATE_OPTIONS, action: t("footer.options") },
|
|
35
35
|
{ key: KEY_LABELS.CURSOR, action: t("footer.cursor") },
|
|
36
|
-
{ key: KEY_LABELS.NAVIGATE_QUESTIONS_TAB, action: t("footer.questions") },
|
|
37
36
|
{ key: KEY_LABELS.NEWLINE, action: t("footer.newline") },
|
|
37
|
+
{ key: KEY_LABELS.ADVANCE_INPUT, action: t("footer.next") },
|
|
38
38
|
{ key: KEY_LABELS.REJECT, action: t("footer.reject") },
|
|
39
39
|
];
|
|
40
40
|
}
|
|
@@ -43,7 +43,8 @@ export const Footer = ({ focusContext, multiSelect, isReviewScreen = false, show
|
|
|
43
43
|
return [
|
|
44
44
|
{ key: KEY_LABELS.NAVIGATE_OPTIONS, action: t("footer.options") },
|
|
45
45
|
{ key: KEY_LABELS.CURSOR, action: t("footer.cursor") },
|
|
46
|
-
{ key:
|
|
46
|
+
{ key: KEY_LABELS.NEWLINE, action: t("footer.newline") },
|
|
47
|
+
{ key: KEY_LABELS.ADVANCE_INPUT, action: t("footer.next") },
|
|
47
48
|
{ key: KEY_LABELS.REJECT, action: t("footer.reject") },
|
|
48
49
|
];
|
|
49
50
|
}
|
|
@@ -82,7 +82,7 @@ export const OptionsList = ({ isFocused, onSelect, options, selectedOption, show
|
|
|
82
82
|
setFocusedIndex(newIndex);
|
|
83
83
|
return;
|
|
84
84
|
}
|
|
85
|
-
// When custom input is focused,
|
|
85
|
+
// When custom input is focused, handle all keyboard input here
|
|
86
86
|
if (isCustomInputFocused) {
|
|
87
87
|
if (key.name === "escape") {
|
|
88
88
|
setFocusedIndex(Math.max(0, options.length - 1));
|
|
@@ -90,9 +90,32 @@ export const OptionsList = ({ isFocused, onSelect, options, selectedOption, show
|
|
|
90
90
|
else if (key.name === "tab" && !key.shift) {
|
|
91
91
|
onAdvance?.();
|
|
92
92
|
}
|
|
93
|
+
else if (key.name === "return") {
|
|
94
|
+
if (key.shift) {
|
|
95
|
+
// Shift+Enter: insert newline
|
|
96
|
+
onCustomChange?.(customValue + "\n");
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
// Enter: advance to next question
|
|
100
|
+
onAdvance?.();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
else if (key.name === "backspace" || key.name === "delete") {
|
|
104
|
+
if (customValue.length > 0) {
|
|
105
|
+
onCustomChange?.(customValue.slice(0, -1));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
else if (key.sequence && !key.ctrl && !key.meta && key.name !== "up" && key.name !== "down") {
|
|
109
|
+
const sanitized = key.sequence
|
|
110
|
+
.replace(/\x1b?\[<[\d;]*[Mm]/g, '')
|
|
111
|
+
.replace(/\[?[OI]/g, '');
|
|
112
|
+
if (sanitized.length > 0) {
|
|
113
|
+
onCustomChange?.(customValue + sanitized);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
93
116
|
return;
|
|
94
117
|
}
|
|
95
|
-
// When elaborate input is focused,
|
|
118
|
+
// When elaborate input is focused, handle all keyboard input here
|
|
96
119
|
if (isElaborateFocused) {
|
|
97
120
|
if (key.name === "escape") {
|
|
98
121
|
setFocusedIndex(customInputIndex);
|
|
@@ -100,6 +123,32 @@ export const OptionsList = ({ isFocused, onSelect, options, selectedOption, show
|
|
|
100
123
|
else if (key.name === "tab" && !key.shift) {
|
|
101
124
|
onAdvance?.();
|
|
102
125
|
}
|
|
126
|
+
else if (key.name === "return") {
|
|
127
|
+
if (key.shift) {
|
|
128
|
+
// Shift+Enter: insert newline
|
|
129
|
+
onElaborateTextChange?.(elaborateText + "\n");
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
// Enter: advance to next question
|
|
133
|
+
if (!elaborateText.trim()) {
|
|
134
|
+
onElaborateSelect?.();
|
|
135
|
+
}
|
|
136
|
+
onAdvance?.();
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
else if (key.name === "backspace" || key.name === "delete") {
|
|
140
|
+
if (elaborateText.length > 0) {
|
|
141
|
+
onElaborateTextChange?.(elaborateText.slice(0, -1));
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
else if (key.sequence && !key.ctrl && !key.meta && key.name !== "up" && key.name !== "down") {
|
|
145
|
+
const sanitized = key.sequence
|
|
146
|
+
.replace(/\x1b?\[<[\d;]*[Mm]/g, '')
|
|
147
|
+
.replace(/\[?[OI]/g, '');
|
|
148
|
+
if (sanitized.length > 0) {
|
|
149
|
+
onElaborateTextChange?.(elaborateText + sanitized);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
103
152
|
return;
|
|
104
153
|
}
|
|
105
154
|
// Spacebar: Select/toggle WITHOUT advancing (works for both modes)
|
|
@@ -109,6 +158,8 @@ export const OptionsList = ({ isFocused, onSelect, options, selectedOption, show
|
|
|
109
158
|
onToggle?.(options[focusedIndex].label);
|
|
110
159
|
}
|
|
111
160
|
else {
|
|
161
|
+
// Single-select: toggle (deselect if already selected)
|
|
162
|
+
// Parent handleSelectOption handles the toggle logic
|
|
112
163
|
onSelect(options[focusedIndex].label);
|
|
113
164
|
}
|
|
114
165
|
}
|
|
@@ -203,15 +254,7 @@ export const OptionsList = ({ isFocused, onSelect, options, selectedOption, show
|
|
|
203
254
|
marginTop: 0,
|
|
204
255
|
paddingX: 1,
|
|
205
256
|
paddingY: 0,
|
|
206
|
-
}, children: _jsx("
|
|
207
|
-
// Filter SGR mouse escape sequences that leak through stdin parser
|
|
208
|
-
const sanitized = val
|
|
209
|
-
.replace(/\x1b?\[<[\d;]*[Mm]/g, '')
|
|
210
|
-
.replace(/\[?[OI]/g, '');
|
|
211
|
-
if (sanitized !== val && sanitized.length === 0)
|
|
212
|
-
return;
|
|
213
|
-
onCustomChange?.(sanitized);
|
|
214
|
-
}, onSubmit: () => onAdvance?.() }) })), !isCustomInputFocused && customValue && (_jsx("box", { style: { marginLeft: 2, marginTop: 0 }, children: _jsxs("text", { style: { fg: theme.components.options.hint, attributes: TextAttributes.DIM }, children: [" ", customLines.slice(0, 3).join("\n "), customLines.length > 3 ? "\n \u2026" : ""] }) }))] }) })), showCustomInput && (_jsx("box", { style: { marginTop: 0 }, children: _jsxs("box", { style: { flexDirection: "column" }, children: [(() => {
|
|
257
|
+
}, children: customValue ? (_jsx("text", { style: { fg: theme.components.options.focused }, children: customValue + "▌" })) : (_jsx("text", { style: { fg: theme.components.options.hint, attributes: TextAttributes.DIM }, children: t("input.placeholder") + "▌" })) })), !isCustomInputFocused && customValue && (_jsx("box", { style: { marginLeft: 2, marginTop: 0 }, children: _jsxs("text", { style: { fg: theme.components.options.hint, attributes: TextAttributes.DIM }, children: [" ", customLines.slice(0, 3).join("\n "), customLines.length > 3 ? "\n \u2026" : ""] }) }))] }) })), showCustomInput && (_jsx("box", { style: { marginTop: 0 }, children: _jsxs("box", { style: { flexDirection: "column" }, children: [(() => {
|
|
215
258
|
const rowBg = isElaborateFocused
|
|
216
259
|
? theme.components.options.focusedBg
|
|
217
260
|
: isElaborateMarked
|
|
@@ -240,19 +283,5 @@ export const OptionsList = ({ isFocused, onSelect, options, selectedOption, show
|
|
|
240
283
|
marginTop: 0,
|
|
241
284
|
paddingX: 1,
|
|
242
285
|
paddingY: 0,
|
|
243
|
-
}, children: _jsx("
|
|
244
|
-
// Filter SGR mouse escape sequences that leak through stdin parser
|
|
245
|
-
const sanitized = val
|
|
246
|
-
.replace(/\x1b?\[<[\d;]*[Mm]/g, '')
|
|
247
|
-
.replace(/\[?[OI]/g, '');
|
|
248
|
-
if (sanitized !== val && sanitized.length === 0)
|
|
249
|
-
return;
|
|
250
|
-
onElaborateTextChange?.(sanitized);
|
|
251
|
-
}, onSubmit: () => {
|
|
252
|
-
// Enter submits and advance
|
|
253
|
-
if (!elaborateText.trim()) {
|
|
254
|
-
onElaborateSelect?.();
|
|
255
|
-
}
|
|
256
|
-
onAdvance?.();
|
|
257
|
-
} }) })), !isElaborateFocused && elaborateText && (_jsx("box", { style: { marginLeft: 2, marginTop: 0 }, children: _jsxs("text", { style: { fg: theme.components.options.hint, attributes: TextAttributes.DIM }, children: [" ", elaborateLines.slice(0, 3).join("\n "), elaborateLines.length > 3 ? "\n \u2026" : ""] }) }))] }) }))] }));
|
|
286
|
+
}, children: elaborateText ? (_jsx("text", { style: { fg: theme.components.options.focused }, children: elaborateText + "▌" })) : (_jsx("text", { style: { fg: theme.components.options.hint, attributes: TextAttributes.DIM }, children: t("input.elaboratePlaceholder") + "▌" })) })), !isElaborateFocused && elaborateText && (_jsx("box", { style: { marginLeft: 2, marginTop: 0 }, children: _jsxs("text", { style: { fg: theme.components.options.hint, attributes: TextAttributes.DIM }, children: [" ", elaborateLines.slice(0, 3).join("\n "), elaborateLines.length > 3 ? "\n \u2026" : ""] }) }))] }) }))] }));
|
|
258
287
|
};
|
|
@@ -73,24 +73,37 @@ export const StepperView = ({ onComplete, onProgress, hasMultipleSessions, initi
|
|
|
73
73
|
}, [currentQuestionIndex]);
|
|
74
74
|
// Handle option selection (single-select mode)
|
|
75
75
|
const handleSelectOption = (label) => {
|
|
76
|
+
const existing = answers.get(currentQuestionIndex) || {};
|
|
77
|
+
const isDeselecting = existing.selectedOption === label;
|
|
76
78
|
setAnswers((prev) => {
|
|
77
79
|
const newAnswers = new Map(prev);
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
80
|
+
const existingAnswer = newAnswers.get(currentQuestionIndex) || {};
|
|
81
|
+
if (isDeselecting) {
|
|
82
|
+
newAnswers.set(currentQuestionIndex, {
|
|
83
|
+
...existingAnswer,
|
|
84
|
+
selectedOption: undefined,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
newAnswers.set(currentQuestionIndex, {
|
|
89
|
+
...existingAnswer,
|
|
90
|
+
selectedOption: label,
|
|
91
|
+
customText: undefined,
|
|
92
|
+
});
|
|
91
93
|
}
|
|
92
|
-
return
|
|
94
|
+
return newAnswers;
|
|
93
95
|
});
|
|
96
|
+
// Clear elaborate mark only when SELECTING (not deselecting) a regular option
|
|
97
|
+
if (!isDeselecting) {
|
|
98
|
+
setElaborateMarks((prev) => {
|
|
99
|
+
if (prev.has(currentQuestionIndex)) {
|
|
100
|
+
const newMarks = new Map(prev);
|
|
101
|
+
newMarks.delete(currentQuestionIndex);
|
|
102
|
+
return newMarks;
|
|
103
|
+
}
|
|
104
|
+
return prev;
|
|
105
|
+
});
|
|
106
|
+
}
|
|
94
107
|
};
|
|
95
108
|
const handleToggleOption = (label) => {
|
|
96
109
|
setAnswers((prev) => {
|
|
@@ -123,9 +136,12 @@ export const StepperView = ({ onComplete, onProgress, hasMultipleSessions, initi
|
|
|
123
136
|
setAnswers((prev) => {
|
|
124
137
|
const newAnswers = new Map(prev);
|
|
125
138
|
const existing = newAnswers.get(currentQuestionIndex) || {};
|
|
139
|
+
const question = sessionRequest.questions[currentQuestionIndex];
|
|
126
140
|
newAnswers.set(currentQuestionIndex, {
|
|
127
141
|
...existing,
|
|
128
142
|
customText: text,
|
|
143
|
+
// Single-choice: clear selectedOption when typing custom text
|
|
144
|
+
...(text.trim().length > 0 && !question?.multiSelect ? { selectedOption: undefined } : {}),
|
|
129
145
|
});
|
|
130
146
|
return newAnswers;
|
|
131
147
|
});
|
|
@@ -327,11 +343,12 @@ export const StepperView = ({ onComplete, onProgress, hasMultipleSessions, initi
|
|
|
327
343
|
if (isMarking && !currentQuestion.multiSelect) {
|
|
328
344
|
setAnswers((prev) => {
|
|
329
345
|
const existing = prev.get(currentQuestionIndex);
|
|
330
|
-
if (existing?.selectedOption) {
|
|
346
|
+
if (existing?.selectedOption || existing?.customText) {
|
|
331
347
|
const newAnswers = new Map(prev);
|
|
332
348
|
newAnswers.set(currentQuestionIndex, {
|
|
333
349
|
...existing,
|
|
334
350
|
selectedOption: undefined,
|
|
351
|
+
customText: undefined,
|
|
335
352
|
});
|
|
336
353
|
return newAnswers;
|
|
337
354
|
}
|