Package: @pierre/trees@1.0.0-beta.3 (also reproducible on 1.0.0-beta.4)
Summary
When the inline rename input is active and the user is composing with an IME (Chinese pinyin, Japanese kana, Korean Hangul), pressing Enter to confirm an IME candidate causes the tree to commit the rename immediately, truncating the in-flight composition. The keydown handler does not check event.isComposing / keyCode === 229, which is the standard guard for IME-safe key handlers.
Steps to reproduce
- Mount any
<FileTree> with renaming enabled.
- Activate inline rename on a row (e.g. via
model.startRenaming(path)).
- Switch to a Chinese (pinyin), Japanese, or Korean IME.
- Type a few characters to bring up an IME candidate menu.
- Press
Enter to confirm the highlighted candidate.
Expected
Enter confirms the IME candidate into the input value. The rename input stays open and editable until the user presses Enter again (or blurs) outside of composition.
Actual
Enter both confirms the IME candidate and immediately commits the rename through renameView.commit(). The committed name is whatever the input held mid-composition — often a partial pinyin string instead of the intended CJK characters.
Root cause
In dist/render/FileTreeView.js (≈ line 1110–1118):
if (renameView.isActive()) {
if (event.key === "Escape") renameView.cancel();
else if (event.key === "Enter") renameView.commit(); // no IME guard
else return;
...
event.preventDefault();
event.stopPropagation();
return;
}
By DOM convention, key events fired while an IME is composing have isComposing: true (or keyCode: 229 in older Safari/Edge). Handlers are expected to skip them — VS Code, Monaco, ProseMirror, CodeMirror, and most React/Vue form libraries all follow this pattern.
Because the keydown listener is registered inside the shadow root, downstream consumers cannot easily intercept the event without forking the package or relying on fragile capture-phase tricks across the shadow boundary.
Suggested fix
Guard the rename commit/cancel branch in handleTreeKeyDown:
if (renameView.isActive()) {
// Skip while an IME is composing — Enter / Escape are consumed by the IME.
if (event.isComposing || event.keyCode === 229) return;
if (event.key === "Escape") renameView.cancel();
else if (event.key === "Enter") renameView.commit();
else return;
...
}
Workaround attempted
From the host app we tried:
- React
onKeyDownCapture on the outer container (composed=true events do bubble out of the shadow root)
- Native
addEventListener('keydown', ..., true) on the host element, scoped via composedPath() to input[data-item-rename-input]
- An
imeSessionRef extended one microtask past compositionend to cover the post-composition Enter
The capture-phase intercept fires before pierre's row bubble handler and can suppress the commit, but on some IMEs / browsers the final Enter keydown carries isComposing: false right after compositionend in the same task. Without an upstream fix there's no reliable, IME-agnostic way to prevent the truncation from outside the shadow root.
Bonus suggestion
Consider making the rename <input> uncontrolled during the rename session (only sync to the model on change / commit, not on every input). Controlled inputs occasionally interact badly with IME composition across browsers; keeping the rename input uncontrolled sidesteps the whole class of issues.
Happy to send a PR if helpful.
Environment
- Browser: Chrome 138 on macOS 15
- IME: macOS built-in Pinyin (Simplified)
- React 19.2 host app (the bug also reproduces in vanilla / preact-only setups)
Package:
@pierre/trees@1.0.0-beta.3(also reproducible on1.0.0-beta.4)Summary
When the inline rename input is active and the user is composing with an IME (Chinese pinyin, Japanese kana, Korean Hangul), pressing
Enterto confirm an IME candidate causes the tree to commit the rename immediately, truncating the in-flight composition. The keydown handler does not checkevent.isComposing/keyCode === 229, which is the standard guard for IME-safe key handlers.Steps to reproduce
<FileTree>with renaming enabled.model.startRenaming(path)).Enterto confirm the highlighted candidate.Expected
Enterconfirms the IME candidate into the input value. The rename input stays open and editable until the user pressesEnteragain (or blurs) outside of composition.Actual
Enterboth confirms the IME candidate and immediately commits the rename throughrenameView.commit(). The committed name is whatever the input held mid-composition — often a partial pinyin string instead of the intended CJK characters.Root cause
In
dist/render/FileTreeView.js(≈ line 1110–1118):By DOM convention, key events fired while an IME is composing have
isComposing: true(orkeyCode: 229in older Safari/Edge). Handlers are expected to skip them — VS Code, Monaco, ProseMirror, CodeMirror, and most React/Vue form libraries all follow this pattern.Because the keydown listener is registered inside the shadow root, downstream consumers cannot easily intercept the event without forking the package or relying on fragile capture-phase tricks across the shadow boundary.
Suggested fix
Guard the rename commit/cancel branch in
handleTreeKeyDown:Workaround attempted
From the host app we tried:
onKeyDownCaptureon the outer container (composed=trueevents do bubble out of the shadow root)addEventListener('keydown', ..., true)on the host element, scoped viacomposedPath()toinput[data-item-rename-input]imeSessionRefextended one microtask pastcompositionendto cover the post-composition EnterThe capture-phase intercept fires before pierre's row bubble handler and can suppress the commit, but on some IMEs / browsers the final
Enterkeydown carriesisComposing: falseright aftercompositionendin the same task. Without an upstream fix there's no reliable, IME-agnostic way to prevent the truncation from outside the shadow root.Bonus suggestion
Consider making the rename
<input>uncontrolled during the rename session (only sync to the model onchange/commit, not on everyinput). Controlled inputs occasionally interact badly with IME composition across browsers; keeping the rename input uncontrolled sidesteps the whole class of issues.Happy to send a PR if helpful.
Environment