mirror of
https://github.com/binaricat/Netcatty.git
synced 2026-09-24 15:49:09 +00:00
69df81613b
* fix(#2745): automated Cursor CLI fix * fix(sftp): reset IME composing guard when filter bar closes If the filter input unmounts mid-composition (filter bar toggled closed), compositionend never fires, leaving filterComposingRef stuck at true and blocking every later onSetFilter commit. Clear the guard when the bar hides. Also drop the now-unused startTransition prop from the toolbar (its only use was the removed deferred filter path). Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(sftp): resync filter draft to committed filter when bar closes Resetting only the composing guard left filterDraft diverged from pane.filter when the bar closed mid-composition, so reopening showed stale uncommitted text. Resync the draft to pane.filter on close. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(sftp): clear IME composing guard in commitFilterValue Centralize the guard reset so every commit/clear path (composition end, Escape, inline clear button, close button) finalizes the IME session. The inline clear previously left filterComposingRef stuck true, blocking later onChange commits and letting a delayed compositionend undo the clear. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(sftp): honor external filter change over stale draft on composition end If navigation (e.g. follow-terminal-CWD) clears pane.filter mid-composition, onCompositionEnd previously re-committed the stale composed draft, overwriting the navigation-clear invariant. Capture pane.filter at composition start and adopt any external change on end instead of committing the stale draft. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(sftp): supersede IME composition when navigation clears filter Navigation can clear pane.filter mid-CJK composition. Adopt that external clear into the draft while composing, arm a supersede latch so the common post-compositionend onChange cannot re-commit the stale draft, and reset composing/supersede state when the filter bar unmounts or a commit path runs. * fix(sftp): supersede IME filter draft when path navigates When the committed filter was already empty before composition, directory navigation sets filter to "" again so pane.filter does not change. Track path at composition start and supersede the draft when the path changes so compositionend cannot re-commit stale IME text. * fix: address Codex review on PR #2746 * fix(sftp): clear IME supersede latch if no post-change arrives After compositionend arms the supersede latch, schedule a macrotask fallback clear so ordinary keystrokes work when the browser never fires the post-composition onChange that would clear it. * fix: use ASCII punctuation in PR comments and tests Replace em dashes with ASCII hyphens in comments/tests. Keep the guarded setTimeout supersede-latch clear from the prior IME fix. --------- Co-authored-by: netcatty-bot <308658023+netcatty-bot@users.noreply.github.com> Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> Co-authored-by: bincxz <16399091+binaricat@users.noreply.github.com>
73 lines
2.8 KiB
TypeScript
73 lines
2.8 KiB
TypeScript
/**
|
|
* Pure helpers for controlled text inputs that must not fight CJK IME composition.
|
|
*
|
|
* Deferred parent updates (e.g. startTransition) against `value={external}` reset
|
|
* the DOM mid-composition and break Windows IMEs (candidate dismiss / pinyin echo).
|
|
*/
|
|
|
|
export function shouldCommitImeControlledChange(input: {
|
|
isComposingSession: boolean;
|
|
nativeEventIsComposing?: boolean;
|
|
/**
|
|
* When true, the open (or just-ended) composition was discarded by an external
|
|
* value change (e.g. navigation cleared the filter). Suppress commits so a
|
|
* post-compositionend `onChange` cannot reassert the stale composed draft.
|
|
*/
|
|
compositionExternallySuperseded?: boolean;
|
|
}): boolean {
|
|
if (input.compositionExternallySuperseded) return false;
|
|
return !input.isComposingSession && input.nativeEventIsComposing !== true;
|
|
}
|
|
|
|
export function shouldAdoptExternalImeControlledValue(input: {
|
|
isComposingSession: boolean;
|
|
draftValue: string;
|
|
externalValue: string;
|
|
/**
|
|
* Committed external value captured at compositionstart. When provided during
|
|
* an open composition, an external change relative to this baseline (e.g.
|
|
* different-directory navigation setting filter to "") supersedes the draft
|
|
* so compositionend cannot re-commit stale text over the navigation clear.
|
|
*/
|
|
valueAtComposeStart?: string;
|
|
}): boolean {
|
|
if (input.draftValue === input.externalValue) return false;
|
|
if (!input.isComposingSession) return true;
|
|
// Mid-composition: only adopt when parent moved away from the compose-start
|
|
// baseline. Without a baseline, never fight the IME for self-driven drafts.
|
|
if (input.valueAtComposeStart !== undefined) {
|
|
return input.externalValue !== input.valueAtComposeStart;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Resolve an input event when a composition may have been externally superseded
|
|
* (navigation clear mid-IME). Browsers often re-fire the composed text via
|
|
* `onChange` with `isComposing=false` immediately after `compositionend`; that
|
|
* follow-up must not reassert the stale draft.
|
|
*
|
|
* - While still composing after supersede: keep ignoring event values (draft stays
|
|
* on the external value) and keep the latch armed.
|
|
* - Once composition has fully ended: ignore that one post-composition change and
|
|
* clear the latch so subsequent ordinary typing commits normally.
|
|
*/
|
|
export function resolveSupersededImeInputEvent(input: {
|
|
compositionExternallySuperseded: boolean;
|
|
isComposingSession: boolean;
|
|
nativeEventIsComposing?: boolean;
|
|
}): {
|
|
ignoreEventValue: boolean;
|
|
clearSupersedeLatch: boolean;
|
|
} {
|
|
if (!input.compositionExternallySuperseded) {
|
|
return { ignoreEventValue: false, clearSupersedeLatch: false };
|
|
}
|
|
const compositionFullyEnded =
|
|
!input.isComposingSession && input.nativeEventIsComposing !== true;
|
|
return {
|
|
ignoreEventValue: true,
|
|
clearSupersedeLatch: compositionFullyEnded,
|
|
};
|
|
}
|