Skip to content

Commit bd7009e

Browse files
authored
fix(copilot): commands (#2811)
1 parent 4f04b1e commit bd7009e

File tree

3 files changed

+166
-333
lines changed

3 files changed

+166
-333
lines changed

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/components/mention-menu/mention-menu.tsx

Lines changed: 40 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -26,26 +26,14 @@ function formatTimestamp(iso: string): string {
2626
}
2727
}
2828

29-
/**
30-
* Common text styling for loading and empty states
31-
*/
3229
const STATE_TEXT_CLASSES = 'px-[8px] py-[8px] text-[12px] text-[var(--text-muted)]'
3330

34-
/**
35-
* Loading state component for mention folders
36-
*/
3731
const LoadingState = () => <div className={STATE_TEXT_CLASSES}>Loading...</div>
3832

39-
/**
40-
* Empty state component for mention folders
41-
*/
4233
const EmptyState = ({ message }: { message: string }) => (
4334
<div className={STATE_TEXT_CLASSES}>{message}</div>
4435
)
4536

46-
/**
47-
* Aggregated item type for filtered results
48-
*/
4937
interface AggregatedItem {
5038
id: string
5139
label: string
@@ -78,14 +66,6 @@ interface MentionMenuProps {
7866
}
7967
}
8068

81-
/**
82-
* MentionMenu component for mention menu dropdown.
83-
* Handles rendering of mention options, submenus, and aggregated search results.
84-
* Manages keyboard navigation and selection of mentions.
85-
*
86-
* @param props - Component props
87-
* @returns Rendered mention menu
88-
*/
8969
export function MentionMenu({
9070
mentionMenu,
9171
mentionData,
@@ -100,6 +80,7 @@ export function MentionMenu({
10080
submenuActiveIndex,
10181
mentionActiveIndex,
10282
openSubmenuFor,
83+
setOpenSubmenuFor,
10384
} = mentionMenu
10485

10586
const {
@@ -308,72 +289,55 @@ export function MentionMenu({
308289
'Docs', // 7
309290
] as const
310291

311-
// Get active folder based on navigation when not in submenu and no query
312292
const isInFolderNavigationMode = !openSubmenuFor && !showAggregatedView
313293

314-
// Compute caret viewport position via mirror technique for precise anchoring
315294
const textareaEl = mentionMenu.textareaRef.current
316295
if (!textareaEl) return null
317296

318-
const getCaretViewport = (textarea: HTMLTextAreaElement, caretPosition: number, text: string) => {
319-
const textareaRect = textarea.getBoundingClientRect()
320-
const style = window.getComputedStyle(textarea)
321-
322-
const mirrorDiv = document.createElement('div')
323-
mirrorDiv.style.position = 'absolute'
324-
mirrorDiv.style.visibility = 'hidden'
325-
mirrorDiv.style.whiteSpace = 'pre-wrap'
326-
mirrorDiv.style.wordWrap = 'break-word'
327-
mirrorDiv.style.font = style.font
328-
mirrorDiv.style.padding = style.padding
329-
mirrorDiv.style.border = style.border
330-
mirrorDiv.style.width = style.width
331-
mirrorDiv.style.lineHeight = style.lineHeight
332-
mirrorDiv.style.boxSizing = style.boxSizing
333-
mirrorDiv.style.letterSpacing = style.letterSpacing
334-
mirrorDiv.style.textTransform = style.textTransform
335-
mirrorDiv.style.textIndent = style.textIndent
336-
mirrorDiv.style.textAlign = style.textAlign
337-
338-
mirrorDiv.textContent = text.substring(0, caretPosition)
339-
340-
const caretMarker = document.createElement('span')
341-
caretMarker.style.display = 'inline-block'
342-
caretMarker.style.width = '0px'
343-
caretMarker.style.padding = '0'
344-
caretMarker.style.border = '0'
345-
mirrorDiv.appendChild(caretMarker)
346-
347-
document.body.appendChild(mirrorDiv)
348-
const markerRect = caretMarker.getBoundingClientRect()
349-
const mirrorRect = mirrorDiv.getBoundingClientRect()
350-
document.body.removeChild(mirrorDiv)
351-
352-
const leftOffset = markerRect.left - mirrorRect.left - textarea.scrollLeft
353-
const topOffset = markerRect.top - mirrorRect.top - textarea.scrollTop
354-
355-
return {
356-
left: textareaRect.left + leftOffset,
357-
top: textareaRect.top + topOffset,
358-
}
359-
}
360-
361297
const caretPos = getCaretPos()
362-
const caretViewport = getCaretViewport(textareaEl, caretPos, message)
298+
const textareaRect = textareaEl.getBoundingClientRect()
299+
const style = window.getComputedStyle(textareaEl)
300+
301+
const mirrorDiv = document.createElement('div')
302+
mirrorDiv.style.position = 'absolute'
303+
mirrorDiv.style.visibility = 'hidden'
304+
mirrorDiv.style.whiteSpace = 'pre-wrap'
305+
mirrorDiv.style.wordWrap = 'break-word'
306+
mirrorDiv.style.font = style.font
307+
mirrorDiv.style.padding = style.padding
308+
mirrorDiv.style.border = style.border
309+
mirrorDiv.style.width = style.width
310+
mirrorDiv.style.lineHeight = style.lineHeight
311+
mirrorDiv.style.boxSizing = style.boxSizing
312+
mirrorDiv.style.letterSpacing = style.letterSpacing
313+
mirrorDiv.style.textTransform = style.textTransform
314+
mirrorDiv.style.textIndent = style.textIndent
315+
mirrorDiv.style.textAlign = style.textAlign
316+
mirrorDiv.textContent = message.substring(0, caretPos)
317+
318+
const caretMarker = document.createElement('span')
319+
caretMarker.style.display = 'inline-block'
320+
caretMarker.style.width = '0px'
321+
caretMarker.style.padding = '0'
322+
caretMarker.style.border = '0'
323+
mirrorDiv.appendChild(caretMarker)
324+
325+
document.body.appendChild(mirrorDiv)
326+
const markerRect = caretMarker.getBoundingClientRect()
327+
const mirrorRect = mirrorDiv.getBoundingClientRect()
328+
document.body.removeChild(mirrorDiv)
329+
330+
const caretViewport = {
331+
left: textareaRect.left + (markerRect.left - mirrorRect.left) - textareaEl.scrollLeft,
332+
top: textareaRect.top + (markerRect.top - mirrorRect.top) - textareaEl.scrollTop,
333+
}
363334

364-
// Decide preferred side based on available space
365335
const margin = 8
366-
const spaceAbove = caretViewport.top - margin
367336
const spaceBelow = window.innerHeight - caretViewport.top - margin
368-
const side: 'top' | 'bottom' = spaceBelow >= spaceAbove ? 'bottom' : 'top'
337+
const side: 'top' | 'bottom' = spaceBelow >= caretViewport.top - margin ? 'bottom' : 'top'
369338

370339
return (
371-
<Popover
372-
open={open}
373-
onOpenChange={() => {
374-
/* controlled by mentionMenu */
375-
}}
376-
>
340+
<Popover open={open} onOpenChange={() => {}}>
377341
<PopoverAnchor asChild>
378342
<div
379343
style={{
@@ -399,7 +363,7 @@ export function MentionMenu({
399363
onOpenAutoFocus={(e) => e.preventDefault()}
400364
onCloseAutoFocus={(e) => e.preventDefault()}
401365
>
402-
<PopoverBackButton />
366+
<PopoverBackButton onClick={() => setOpenSubmenuFor(null)} />
403367
<PopoverScrollArea ref={menuListRef} className='space-y-[2px]'>
404368
{openSubmenuFor ? (
405369
// Submenu view - showing contents of a specific folder

0 commit comments

Comments
 (0)