Skip to content

Commit adff575

Browse files
committed
handle paste and some formatting in textarea
1 parent 5687d72 commit adff575

File tree

2 files changed

+35
-10
lines changed

2 files changed

+35
-10
lines changed

web/src/components/common/MentionTextarea.tsx

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export const MentionTextarea = forwardRef<HTMLDivElement, MentionTextareaProps>(
2929

3030
// Rotating placeholder
3131
const [placeholderIndex, setPlaceholderIndex] = useState(0)
32-
const placeholders = ['Ask Anything!', 'Tip: Use @ to mention tables or models']
32+
const placeholders = ['Ask anything!', 'Tip: Use @ to mention any tables or models']
3333

3434
useEffect(() => {
3535
const interval = setInterval(() => {
@@ -91,19 +91,23 @@ export const MentionTextarea = forwardRef<HTMLDivElement, MentionTextareaProps>(
9191
const getCursorPosition = useCallback(() => {
9292
const sel = window.getSelection()
9393
if (!sel?.rangeCount || !editableRef.current) return 0
94-
94+
9595
const range = sel.getRangeAt(0).cloneRange()
9696
range.selectNodeContents(editableRef.current)
9797
range.setEnd(sel.getRangeAt(0).startContainer, sel.getRangeAt(0).startOffset)
98-
return range.toString().length
98+
99+
// Create a temporary div to get innerText (consistent with getTextContent)
100+
const tempDiv = document.createElement('div')
101+
tempDiv.appendChild(range.cloneContents())
102+
return (tempDiv.innerText || tempDiv.textContent || '').length
99103
}, [])
100104

101105
// Update content with highlighted mentions
102106
const updateContent = useCallback((text: string) => {
103107
if (!editableRef.current) return
104108

105109
// If text is empty, clear innerHTML to show placeholder
106-
if (!text.trim()) {
110+
if (text.length === 0) {
107111
editableRef.current.innerHTML = ''
108112
return
109113
}
@@ -140,11 +144,29 @@ export const MentionTextarea = forwardRef<HTMLDivElement, MentionTextareaProps>(
140144
editableRef.current.innerHTML = html
141145
}, [mentionItems])
142146

147+
// Handle paste events for immediate formatting
148+
const handlePaste = useCallback((_e: React.ClipboardEvent<HTMLDivElement>) => {
149+
// Let the paste happen first, then immediately format
150+
setTimeout(() => {
151+
const newValue = getTextContent()
152+
const cursorPosition = getCursorPosition()
153+
154+
// Call original onChange
155+
if (onChange) {
156+
onChange({ target: { value: newValue } })
157+
}
158+
159+
// Immediately update content for paste
160+
updateContent(newValue)
161+
setCursorPosition(cursorPosition)
162+
}, 0)
163+
}, [getTextContent, getCursorPosition, onChange, updateContent, setCursorPosition])
164+
143165
// Handle input changes
144-
const handleInput = useCallback((e: React.FormEvent<HTMLDivElement>) => {
166+
const handleInput = useCallback((_e: React.FormEvent<HTMLDivElement>) => {
145167
const newValue = getTextContent()
146168
const cursorPosition = getCursorPosition()
147-
169+
148170
// Call original onChange
149171
if (onChange) {
150172
onChange({ target: { value: newValue } })
@@ -258,14 +280,14 @@ export const MentionTextarea = forwardRef<HTMLDivElement, MentionTextareaProps>(
258280

259281
// Call original onKeyDown
260282
if (onKeyDown) {
261-
onKeyDown(e)
283+
onKeyDown(e as unknown as React.KeyboardEvent<HTMLTextAreaElement>)
262284
}
263285
}, [showDropdown, filteredItems, selectedIndex, handleMentionSelect, onKeyDown])
264286

265287
// Update content when value prop changes (only if not focused)
266288
useEffect(() => {
267289
if (value !== undefined && editableRef.current && document.activeElement !== editableRef.current) {
268-
updateContent(value)
290+
updateContent(String(value))
269291
}
270292
}, [value, updateContent])
271293

@@ -308,6 +330,7 @@ export const MentionTextarea = forwardRef<HTMLDivElement, MentionTextareaProps>(
308330
suppressContentEditableWarning
309331
onInput={handleInput}
310332
onKeyDown={handleKeyDown}
333+
onPaste={handlePaste}
311334
minH="48px"
312335
maxHeight={300}
313336
overflow="auto"

web/src/components/common/TaskUI.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,7 @@ const TaskUI = forwardRef<HTMLTextAreaElement>((_props, ref) => {
656656
</HStack>
657657
</Box>
658658
<HStack justifyContent="space-between" fontSize="sm" gap={1} width={"100%"}>
659-
<Tooltip
659+
{/* <Tooltip
660660
hasArrow
661661
placement='right'
662662
borderRadius={5}
@@ -687,14 +687,15 @@ const TaskUI = forwardRef<HTMLTextAreaElement>((_props, ref) => {
687687
</HStack>
688688
</VStack>
689689
</Box>
690-
</Tooltip>
690+
</Tooltip> */}
691691
<Tooltip
692692
hasArrow
693693
placement='top'
694694
borderRadius={5}
695695
label={`Personal memory is ${useMemory ? 'enabled' : 'disabled'}`}
696696
>
697697
<Box
698+
flex={1}
698699
bg="minusxBW.200"
699700
px={2}
700701
py={1}
@@ -727,6 +728,7 @@ const TaskUI = forwardRef<HTMLTextAreaElement>((_props, ref) => {
727728
>
728729
<Box
729730
bg="minusxBW.200"
731+
flex={1}
730732
px={2}
731733
py={1}
732734
borderRadius="md"

0 commit comments

Comments
 (0)