-
Notifications
You must be signed in to change notification settings - Fork 942
feat(web): support Enter key to confirm archive and other dialogs #1490
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@moonshot-ai/kimi-code": patch | ||
| --- | ||
|
|
||
| web: Press Enter to confirm in archive and other confirmation dialogs. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,11 +3,19 @@ | |
| Dialog (height auto, right-aligned footer). The single confirmation surface | ||
| for user actions — driven app-wide by useConfirmDialog(). --> | ||
| <script setup lang="ts"> | ||
| import { onBeforeUnmount, ref } from 'vue'; | ||
| import { useI18n } from 'vue-i18n'; | ||
| import Dialog from '../ui/Dialog.vue'; | ||
| import Button from '../ui/Button.vue'; | ||
|
|
||
| withDefaults(defineProps<{ | ||
| const confirmButtonRef = ref<InstanceType<typeof Button> | null>(null); | ||
|
|
||
| function confirmButtonElement(): HTMLElement | null { | ||
| const el = confirmButtonRef.value?.$el; | ||
| return el instanceof HTMLElement ? el : null; | ||
| } | ||
|
|
||
| const props = withDefaults(defineProps<{ | ||
| open: boolean; | ||
| title: string; | ||
| message?: string; | ||
|
|
@@ -32,13 +40,41 @@ function onCancel(): void { | |
| emit('update:open', false); | ||
| emit('cancel'); | ||
| } | ||
|
|
||
| function onKeydown(event: KeyboardEvent): void { | ||
| if (event.key !== 'Enter' || !props.open || props.loading) return; | ||
| // Preserve native Enter semantics for interactive controls (buttons, links, | ||
| // form fields) so tabbing to Cancel / Close and pressing Enter does not | ||
| // accidentally confirm the dialog. Only treat Enter as confirm when focus is | ||
| // on a non-interactive part of the dialog. | ||
| const target = event.target as HTMLElement | null; | ||
| if ( | ||
| target instanceof HTMLButtonElement || | ||
| target instanceof HTMLAnchorElement || | ||
| target instanceof HTMLTextAreaElement || | ||
| target instanceof HTMLSelectElement || | ||
| target instanceof HTMLInputElement | ||
| ) { | ||
| return; | ||
| } | ||
| event.preventDefault(); | ||
| emit('confirm'); | ||
|
Comment on lines
+60
to
+61
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When a confirmation dialog is open, this window-level handler also receives Useful? React with 👍 / 👎. |
||
| } | ||
|
|
||
| if (typeof window !== 'undefined') { | ||
| window.addEventListener('keydown', onKeydown); | ||
| } | ||
| onBeforeUnmount(() => { | ||
| if (typeof window !== 'undefined') window.removeEventListener('keydown', onKeydown); | ||
| }); | ||
| </script> | ||
|
|
||
| <template> | ||
| <Dialog | ||
| :open="open" | ||
| :title="title" | ||
| height="auto" | ||
| :initial-focus="confirmButtonElement" | ||
| @update:open="emit('update:open', $event)" | ||
| @close="onCancel" | ||
| > | ||
|
|
@@ -47,7 +83,12 @@ function onCancel(): void { | |
| <Button variant="secondary" :disabled="loading" @click="onCancel"> | ||
| {{ cancelLabel ?? t('common.cancel') }} | ||
| </Button> | ||
| <Button :variant="variant" :loading="loading" @click="emit('confirm')"> | ||
| <Button | ||
| ref="confirmButtonRef" | ||
| :variant="variant" | ||
| :loading="loading" | ||
| @click="emit('confirm')" | ||
| > | ||
| {{ confirmLabel ?? t('common.confirm') }} | ||
| </Button> | ||
| </template> | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the default archive-confirm flow,
Dialog.vuemoves focus to the first focusable element when opened, and the first focusable in this dialog is the header close button. Because this handler returns for everyHTMLButtonElement, pressing Enter immediately after the modal appears does not run the new confirm shortcut; the browser instead activates the focused close button and cancels/closes the dialog. This makes the advertised keyboard path fail for the main scenario unless the user first moves focus off the close button.Useful? React with 👍 / 👎.