fix: Consistent keydown handling for EditableText and TagsInput escape key (#8204)

## Summary

This PR improves keyboard event handling consistency and fixes an issue
where pressing Escape in nested input components would unintentionally
close parent modals/dialogs.

## Changes

### Keyboard Event Fixes

**TagsInput Escape Key Handling**
- Added `@keydown.escape.stop` handler to `TagsInputInput.vue` to
prevent Escape from bubbling up and closing parent modals
- The handler blurs the input and exits editing mode without propagating
the event

**EditableText keyup → keydown Migration**
- Changed `@keyup.enter` to `@keydown.enter` and `@keyup.escape` to
`@keydown.escape`
- Using `keydown` is more consistent with how other UI frameworks handle
these events and provides more responsive feedback
- Updated corresponding unit tests to use `keydown` triggers

### Why keydown over keyup?

- `keydown` fires immediately when the key is pressed, providing faster
perceived response
- Better consistency with browser/OS conventions for action triggers
- Prevents default behaviors (like form submission) more reliably when
needed
- Aligns with other keyboard handlers in the codebase

## Testing

- Updated `EditableText.test.ts` to use `keydown` events
- Updated `NodeHeader.test.ts` to use `keydown.enter`
- Manual testing: Escape in TagsInput no longer closes parent modal

## Checklist

- [x] Unit tests updated
- [x] Keyboard event handlers consistent
- [x] No breaking changes to component API

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8204-fix-Consistent-keydown-handling-for-EditableText-and-TagsInput-escape-key-2ef6d73d365081f0ac6bed8bcae57657)
by [Unito](https://www.unito.io)
This commit is contained in:
Alexander Brown
2026-01-21 09:16:13 -08:00
committed by GitHub
parent 9a6ead37cb
commit 7b701ad07b
4 changed files with 16 additions and 10 deletions

View File

@@ -154,7 +154,7 @@ describe('NodeHeader.vue', () => {
// Edit and confirm (EditableText uses blur or enter to emit)
const input = wrapper.get('[data-testid="node-title-input"]')
await input.setValue('My Custom Sampler')
await input.trigger('keyup.enter')
await input.trigger('keydown.enter')
await input.trigger('blur')
// NodeHeader should emit update:title with trimmed value
@@ -169,7 +169,7 @@ describe('NodeHeader.vue', () => {
await wrapper.get('[data-testid="node-header-1"]').trigger('dblclick')
const input = wrapper.get('[data-testid="node-title-input"]')
await input.setValue('Should Not Save')
await input.trigger('keyup.escape')
await input.trigger('keydown.escape')
// Should not emit update:title
expect(wrapper.emitted('update:title')).toBeFalsy()