Skip to content

fix(user-input): stop @mention/skill menu from reopening after dismiss#5464

Merged
waleedlatif1 merged 3 commits into
stagingfrom
fix-mention-menu-click-away
Jul 7, 2026
Merged

fix(user-input): stop @mention/skill menu from reopening after dismiss#5464
waleedlatif1 merged 3 commits into
stagingfrom
fix-mention-menu-click-away

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • Fixes a bug where the @mention (and /skill) autocomplete menu couldn't be dismissed — clicking away or pressing Escape closed it, but the very next click/selection change reopened it because the caret was still inside the unfinished @token
  • Adds a one-shot "dismissed" marker per token, set only on a real outside-click/Escape dismiss, cleared the instant the user types again
  • Shared fix in use-prompt-editor.ts covers every consumer: home chat input, scheduled-task modal, task-details modal

Type of Change

  • Bug fix

Testing

Added use-prompt-editor.test.tsx (4 tests) that mounts the real hook and reproduces the exact scenario — confirmed it fails on the pre-fix code and passes after. Also ran full typecheck/lint.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

- Fixes a bug where the @mention (and /skill) autocomplete menu couldn't
  be dismissed: clicking away or pressing Escape closed it, but the very
  next click/selection change reopened it because the caret was still
  inside the unfinished @token
- Adds a one-shot "dismissed" marker per token, set only on a real
  outside-click/Escape dismiss, cleared the instant the user types again
- Shared fix in use-prompt-editor.ts covers every consumer: home chat
  input, scheduled-task modal, task-details modal
@vercel

vercel Bot commented Jul 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Jul 7, 2026 3:21am

Request Review

@cursor

cursor Bot commented Jul 7, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Localized prompt-editor UX logic with new regression tests; no API, auth, or data-path changes.

Overview
Fixes @mention and /skill autocomplete menus popping back open right after the user dismisses them (outside click or Escape) when the caret is still inside the unfinished @ or / token.

use-prompt-editor now records a one-shot dismissed token start on Radix-driven closes (handlePlusMenuClose / handleSkillsMenuClose) and syncMentionState / syncSlashState skip reopening for that exact token on the next selection sync. Typing, clearing, picks, and toolbar slash insert clear the marker so continued typing or a new mention still opens the menu.

Adds use-prompt-editor.test.tsx with jsdom hook tests for dismiss-without-reopen, reopen after more typing, a different @ mention, and slash toolbar after dismiss.

Reviewed by Cursor Bugbot for commit 5e55525. Configure here.

@greptile-apps

greptile-apps Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a menu-persistence bug in the prompt editor where dismissing an @mention or /skill autocomplete menu (via outside-click or Escape) caused it to reopen immediately because the caret remained inside the unfinished token, triggering syncMentionState/syncSlashState on the next selection-change event.

  • Adds two one-shot refs (dismissedMentionStartRef, dismissedSlashStartRef) that record the token's start offset when the user explicitly dismisses the menu, and suppress the reopen in syncMentionState/syncSlashState until the user types again or the token becomes invalid.
  • Clears the dismissed refs consistently in all "typing resumed" paths: handleInputChange, insertSlashTrigger, and the word-boundary !isOpenable branch of both sync functions.
  • Adds four focused unit tests that mount the real hook against a jsdom textarea and cover the core dismiss, reopen-on-keystroke, and new-token scenarios.

Confidence Score: 5/5

Safe to merge — the change is isolated to two ref variables in one hook, all existing reset paths are updated, and the fix is verified by new tests.

The dismissed-position refs are read-only inside syncMentionState/syncSlashState and written only in the dismiss handlers and typing-resumed paths. Every code path that previously nulled mentionRangeRef/slashRangeRef now also nulls the new dismissed refs, so there is no stale-suppression risk. Position-based identity correctly identifies the same token across selection-change events, and any in-place text mutation goes through handleInputChange which clears the refs immediately.

No files require special attention.

Important Files Changed

Filename Overview
apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/prompt-editor/use-prompt-editor.ts Adds two one-shot dismissed-position refs that suppress syncMentionState/syncSlashState from reopening a menu on selection-change after an explicit user dismissal; refs are cleared on any subsequent keystroke or token-boundary change, and in all existing reset paths.
apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/prompt-editor/use-prompt-editor.test.tsx New test file mounting the real hook in a jsdom root; covers four behavioral scenarios for mention-menu dismissal and one for the toolbar slash trigger, following the established test pattern in the codebase.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant User
    participant Textarea
    participant handleInputChange
    participant handlePlusMenuClose
    participant handleSelectAdjust
    participant syncMentionState
    participant PlusMenu

    User->>Textarea: "types "@f""
    Textarea->>handleInputChange: input event
    handleInputChange->>syncMentionState: clears dismissed ref, then syncs
    syncMentionState->>PlusMenu: open()

    User->>handlePlusMenuClose: Escape / outside click
    handlePlusMenuClose->>handlePlusMenuClose: "dismissedMentionStartRef = 0"
    handlePlusMenuClose->>handlePlusMenuClose: "mentionRangeRef = null"

    User->>Textarea: "clicks back into token (caret=2)"
    Textarea->>handleSelectAdjust: selectionchange
    handleSelectAdjust->>syncMentionState: "active.start(0) === dismissed(0) SUPPRESS"
    syncMentionState-->>PlusMenu: not reopened

    User->>Textarea: types more
    Textarea->>handleInputChange: "clears dismissedMentionStartRef = null"
    handleInputChange->>syncMentionState: suppression lifted
    syncMentionState->>PlusMenu: open()
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant User
    participant Textarea
    participant handleInputChange
    participant handlePlusMenuClose
    participant handleSelectAdjust
    participant syncMentionState
    participant PlusMenu

    User->>Textarea: "types "@f""
    Textarea->>handleInputChange: input event
    handleInputChange->>syncMentionState: clears dismissed ref, then syncs
    syncMentionState->>PlusMenu: open()

    User->>handlePlusMenuClose: Escape / outside click
    handlePlusMenuClose->>handlePlusMenuClose: "dismissedMentionStartRef = 0"
    handlePlusMenuClose->>handlePlusMenuClose: "mentionRangeRef = null"

    User->>Textarea: "clicks back into token (caret=2)"
    Textarea->>handleSelectAdjust: selectionchange
    handleSelectAdjust->>syncMentionState: "active.start(0) === dismissed(0) SUPPRESS"
    syncMentionState-->>PlusMenu: not reopened

    User->>Textarea: types more
    Textarea->>handleInputChange: "clears dismissedMentionStartRef = null"
    handleInputChange->>syncMentionState: suppression lifted
    syncMentionState->>PlusMenu: open()
Loading

Reviews (3): Last reviewed commit: "fix(user-input): clear slash dismissal m..." | Re-trigger Greptile

…smiss fix

Trims the inline // explanations added in the previous commit down to
the two declaration-level doc comments that carry real information —
matching the repo's no-inline-comments convention.
…gger

Cursor Bugbot review: insertSlashTrigger (the toolbar Slash button) called
syncSlashState without clearing dismissedSlashStartRef, so a stale dismissal
could suppress the skills menu on an explicit user action when the new
token's start offset coincided with the previously dismissed one. An
explicit trigger click must always open the menu, so it now clears the
marker first like every other insertion path.
@waleedlatif1 waleedlatif1 merged commit cad44b9 into staging Jul 7, 2026
4 checks passed
@waleedlatif1 waleedlatif1 deleted the fix-mention-menu-click-away branch July 7, 2026 03:22
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 5e55525. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant