Skip to content

Commit db64a50

Browse files
authored
fix: Fix custom answer in the question prompt not working (#923)
1 parent 3adfc31 commit db64a50

File tree

3 files changed

+123
-63
lines changed

3 files changed

+123
-63
lines changed

apps/twig/src/renderer/components/action-selector/ActionSelector.tsx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
11
import { Box, Flex, Text } from "@radix-ui/themes";
22
import { compactHomePath } from "@utils/path";
33
import { useCallback, useEffect, useRef } from "react";
4-
import { isOtherOption } from "./constants";
54
import { OptionRow } from "./OptionRow";
65
import { StepTabs } from "./StepTabs";
7-
import type { ActionSelectorProps, SelectorOption } from "./types";
6+
import type { ActionSelectorProps } from "./types";
87
import { useActionSelectorState } from "./useActionSelectorState";
98

10-
function needsCustomInput(option: SelectorOption): boolean {
11-
return option.customInput === true || isOtherOption(option.id);
12-
}
13-
149
export function ActionSelector({
1510
title,
1611
pendingAction,
@@ -199,7 +194,15 @@ export function ActionSelector({
199194
ref={containerRef}
200195
tabIndex={0}
201196
p="3"
202-
onClick={() => containerRef.current?.focus()}
197+
onClick={(e) => {
198+
if (
199+
e.target instanceof HTMLElement &&
200+
e.target.closest("[contenteditable]")
201+
) {
202+
return;
203+
}
204+
containerRef.current?.focus();
205+
}}
203206
style={{
204207
outline: "none",
205208
border: "1px solid var(--blue-11)",
@@ -233,10 +236,7 @@ export function ActionSelector({
233236
<Flex direction="column" gap="1">
234237
{allOptions.map((option, index) => {
235238
const isSelected = selectedIndex === index;
236-
const hasCustomContent =
237-
needsCustomInput(option) && customInput.trim() !== "";
238-
const isChecked =
239-
checkedOptions.has(option.id) || hasCustomContent;
239+
const isChecked = checkedOptions.has(option.id);
240240

241241
return (
242242
<OptionRow
Lines changed: 53 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Text } from "@radix-ui/themes";
1+
import { Box, Text } from "@radix-ui/themes";
22
import { useCallback, useEffect } from "react";
33

44
interface InlineEditableTextProps {
@@ -24,7 +24,7 @@ export function InlineEditableText({
2424
}: InlineEditableTextProps) {
2525
useEffect(() => {
2626
if (inputRef.current) {
27-
inputRef.current.textContent = value || placeholder;
27+
inputRef.current.textContent = value || "";
2828
inputRef.current.focus();
2929
if (value) {
3030
const range = document.createRange();
@@ -35,23 +35,14 @@ export function InlineEditableText({
3535
sel?.addRange(range);
3636
}
3737
}
38-
}, [inputRef, placeholder, value]);
38+
}, [inputRef, value]);
3939

4040
const handleInput = useCallback(
4141
(e: React.FormEvent<HTMLSpanElement>) => {
4242
const text = e.currentTarget.textContent ?? "";
4343
onChange(text);
44-
if (!text && inputRef.current) {
45-
inputRef.current.textContent = placeholder;
46-
const range = document.createRange();
47-
range.setStart(inputRef.current, 0);
48-
range.collapse(true);
49-
const sel = window.getSelection();
50-
sel?.removeAllRanges();
51-
sel?.addRange(range);
52-
}
5344
},
54-
[onChange, placeholder, inputRef],
45+
[onChange],
5546
);
5647

5748
const handleKeyDown = useCallback(
@@ -68,45 +59,60 @@ export function InlineEditableText({
6859
} else if (e.key === "Enter" && !e.shiftKey) {
6960
e.preventDefault();
7061
onSubmit();
71-
} else if (!value && e.key.length === 1 && !e.ctrlKey && !e.metaKey) {
72-
e.preventDefault();
73-
e.currentTarget.textContent = e.key;
74-
onChange(e.key);
75-
const range = document.createRange();
76-
range.selectNodeContents(e.currentTarget);
77-
range.collapse(false);
78-
const sel = window.getSelection();
79-
sel?.removeAllRanges();
80-
sel?.addRange(range);
8162
}
8263
},
83-
[value, onChange, onNavigateUp, onNavigateDown, onEscape, onSubmit],
64+
[onNavigateUp, onNavigateDown, onEscape, onSubmit],
8465
);
8566

8667
return (
87-
<Text
88-
asChild
89-
size="1"
90-
weight="medium"
91-
className={value ? "text-gray-12" : "text-gray-10"}
68+
<Box
69+
style={{
70+
display: "inline-grid",
71+
minWidth: "200px",
72+
}}
9273
>
93-
{/* biome-ignore lint/a11y/useSemanticElements: contentEditable span needed for inline editing UX */}
94-
<span
95-
ref={inputRef}
96-
role="textbox"
97-
tabIndex={0}
98-
contentEditable
99-
suppressContentEditableWarning
100-
onInput={handleInput}
101-
onKeyDown={handleKeyDown}
102-
style={{
103-
outline: "none",
104-
minWidth: "200px",
105-
display: "inline-block",
106-
whiteSpace: "pre-wrap",
107-
wordBreak: "break-word",
108-
}}
109-
/>
110-
</Text>
74+
{!value && (
75+
<Text
76+
size="1"
77+
weight="medium"
78+
className="text-gray-10"
79+
style={{
80+
gridRow: 1,
81+
gridColumn: 1,
82+
pointerEvents: "none",
83+
userSelect: "none",
84+
whiteSpace: "pre-wrap",
85+
wordBreak: "break-word",
86+
}}
87+
>
88+
{placeholder}
89+
</Text>
90+
)}
91+
<Text
92+
asChild
93+
size="1"
94+
weight="medium"
95+
className={value ? "text-gray-12" : ""}
96+
>
97+
{/* biome-ignore lint/a11y/useSemanticElements: contentEditable span needed for inline editing UX */}
98+
<span
99+
ref={inputRef}
100+
role="textbox"
101+
tabIndex={0}
102+
contentEditable
103+
suppressContentEditableWarning
104+
onClick={(e) => e.stopPropagation()}
105+
onInput={handleInput}
106+
onKeyDown={handleKeyDown}
107+
style={{
108+
gridRow: 1,
109+
gridColumn: 1,
110+
outline: "none",
111+
whiteSpace: "pre-wrap",
112+
wordBreak: "break-word",
113+
}}
114+
/>
115+
</Text>
116+
</Box>
111117
);
112118
}

apps/twig/src/renderer/components/action-selector/useActionSelectorState.ts

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -310,31 +310,85 @@ export function useActionSelectorState({
310310
containerRef.current?.focus();
311311
}, []);
312312

313+
const handleCustomInputChange = useCallback(
314+
(value: string) => {
315+
setCustomInput(value);
316+
if (
317+
value.trim() &&
318+
showSubmitButton &&
319+
selectedOption &&
320+
needsCustomInput(selectedOption)
321+
) {
322+
setCheckedOptions((prev) => {
323+
if (prev.has(selectedOption.id)) return prev;
324+
const next = new Set(prev);
325+
next.add(selectedOption.id);
326+
return next;
327+
});
328+
}
329+
},
330+
[showSubmitButton, selectedOption],
331+
);
332+
333+
const ensureChecked = useCallback((optionId: string) => {
334+
setCheckedOptions((prev) => {
335+
if (prev.has(optionId)) return prev;
336+
const next = new Set(prev);
337+
next.add(optionId);
338+
return next;
339+
});
340+
}, []);
341+
313342
const handleInlineSubmit = useCallback(() => {
314343
if (!selectedOption) return;
315344
if (showSubmitButton) {
316-
toggleCheck(selectedOption.id);
345+
ensureChecked(selectedOption.id);
346+
containerRef.current?.focus();
347+
moveDown();
317348
} else if (customInput.trim()) {
318349
onSelect(selectedOption.id, customInput.trim());
319350
}
320-
}, [showSubmitButton, toggleCheck, selectedOption, customInput, onSelect]);
351+
}, [
352+
showSubmitButton,
353+
ensureChecked,
354+
selectedOption,
355+
customInput,
356+
onSelect,
357+
moveDown,
358+
]);
321359

322360
const handleNavigateUp = useCallback(() => {
361+
if (
362+
selectedOption &&
363+
needsCustomInput(selectedOption) &&
364+
customInput.trim() &&
365+
showSubmitButton
366+
) {
367+
ensureChecked(selectedOption.id);
368+
}
323369
containerRef.current?.focus();
324370
moveUp();
325-
}, [moveUp]);
371+
}, [moveUp, selectedOption, customInput, showSubmitButton, ensureChecked]);
326372

327373
const handleNavigateDown = useCallback(() => {
374+
if (
375+
selectedOption &&
376+
needsCustomInput(selectedOption) &&
377+
customInput.trim() &&
378+
showSubmitButton
379+
) {
380+
ensureChecked(selectedOption.id);
381+
}
328382
containerRef.current?.focus();
329383
moveDown();
330-
}, [moveDown]);
384+
}, [moveDown, selectedOption, customInput, showSubmitButton, ensureChecked]);
331385

332386
return {
333387
selectedIndex,
334388
setSelectedIndex,
335389
checkedOptions,
336390
customInput,
337-
setCustomInput,
391+
setCustomInput: handleCustomInputChange,
338392
isEditing,
339393
activeStep,
340394
stepAnswers,

0 commit comments

Comments
 (0)