mirror of
https://github.com/nexu-io/open-design.git
synced 2026-05-31 19:04:39 +07:00
fix: preserve cursor position when inserting async references
Capture mention state snapshot before async operations (applyProjectSkill, applyById) to prevent cursor position issues. Previously, the mention state could be invalidated during async operations, causing the cursor to land in the wrong position after inserting skills or plugins. Changes: - Add optional mentionSnapshot parameter to replaceMentionWithText() - Capture mention state before async calls in insertSkillMention() - Capture mention state before async calls in insertPluginMention() - Use captured snapshot instead of potentially stale mention state This ensures the cursor position is calculated from the original mention context, not from state that may have changed during re-renders triggered by async operations. Fixes #3195
This commit is contained in:
parent
e8c179d3a6
commit
191f04ac4a
1 changed files with 12 additions and 3 deletions
|
|
@ -1331,7 +1331,14 @@ export const ChatComposer = forwardRef<ChatComposerHandle, Props>(
|
|||
const prevEntries = pluginInsertedTokensRef.current;
|
||||
const prevActiveId = activePluginIdRef.current;
|
||||
|
||||
const result = replaceMentionWithText(`${inlineMentionToken(record.title)} `);
|
||||
// Capture mention state before async operation to prevent cursor
|
||||
// position issues if state changes during apply.
|
||||
const mentionSnapshot = mention;
|
||||
|
||||
const result = replaceMentionWithText(
|
||||
`${inlineMentionToken(record.title)} `,
|
||||
mentionSnapshot,
|
||||
);
|
||||
if (!result) return;
|
||||
// Capture the post-insert draft *snapshot* — the value the
|
||||
// composer is in immediately after our optimistic write.
|
||||
|
|
@ -1468,10 +1475,12 @@ export const ChatComposer = forwardRef<ChatComposerHandle, Props>(
|
|||
|
||||
function replaceMentionWithText(
|
||||
text: string,
|
||||
mentionSnapshot?: typeof mention,
|
||||
): { insertStart: number } | null {
|
||||
if (!mention) return null;
|
||||
const activeMention = mentionSnapshot ?? mention;
|
||||
if (!activeMention) return null;
|
||||
const ta = textareaRef.current;
|
||||
const cursor = mention.cursor;
|
||||
const cursor = activeMention.cursor;
|
||||
const before = draft.slice(0, cursor);
|
||||
const after = draft.slice(cursor);
|
||||
const replaced = before.replace(/(^|\s)@([^\s@]*)$/, `$1${text}`);
|
||||
|
|
|
|||
Loading…
Reference in a new issue