Files
NetMesh/domain/imeControlledInput.ts
zhaolei 3c72efcb7f
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
[Init] Initial commit - NetMesh terminal manager
2026-09-13 18:24:01 +08:00

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,
};
}