refactor(ui): unify confirm-dropdown Enter behavior via useAcceptOnEnter
CI / lint (push) Successful in 2s
CI / backend-lint-and-test (push) Successful in 27s
CI / frontend-build (push) Successful in 1m44s
CI / integration (push) Successful in 3m8s

Operator-flagged (again) on the tag-merge picker: Enter on the dropdown re-opens
it instead of accepting the selection. I'd already patched this twice (fandom
picker + fandom set dialog) with copy-pasted capture-phase handlers, so DRY it.

New composable useAcceptOnEnter(accept): tracks the menu state and, on a
capture-phase Enter, lets Vuetify pick when the menu is open but calls accept()
(and blocks the re-open) when it's closed. Applied to every confirm-style picker:
- TagsView merge-into picker (the reported one)
- AliasPickerDialog
- PostSeriesMenu add-to-existing
- FandomPicker + FandomSetDialog (refactored off their bespoke handlers)

One behavior, one place to change it.
This commit is contained in:
2026-06-08 08:59:55 -04:00
parent f2fbe2ae6e
commit 408fcd488a
6 changed files with 71 additions and 33 deletions
@@ -82,6 +82,7 @@
<script setup>
import { nextTick, onMounted, ref } from 'vue'
import { useTagStore } from '../../stores/tags.js'
import { useAcceptOnEnter } from '../../composables/useAcceptOnEnter.js'
const props = defineProps({ tag: { type: Object, required: true } })
const emit = defineEmits(['updated', 'cancel'])
@@ -93,10 +94,15 @@ const newName = ref('')
const busy = ref(false)
const error = ref(null)
const collision = ref(null)
const menuOpen = ref(false)
const fandomRef = ref(null)
const newNameRef = ref(null)
// Enter on the closed dropdown Saves the changed fandom instead of re-opening it.
const { menuOpen, onEnter: onSearchEnter } = useAcceptOnEnter(() => {
if (busy.value) return
if (selectedId.value !== (props.tag.fandom_id ?? null)) onSave()
})
// Always refresh on open so the list reflects fandoms created elsewhere (#712).
onMounted(() => store.loadFandoms())
@@ -131,20 +137,6 @@ async function onCreate() {
}
}
// Enter on the search field — bound in the CAPTURE phase so it runs BEFORE
// Vuetify's own handler (which opens the menu on Enter). Menu open → let Vuetify
// pick the highlighted item. Menu closed with a changed selection → Save and stop
// the event so Vuetify never (re)opens the dropdown (the bug this fixes).
function onSearchEnter(e) {
if (menuOpen.value) return
if (busy.value) return
if (selectedId.value !== (props.tag.fandom_id ?? null)) {
e.preventDefault()
e.stopPropagation()
onSave()
}
}
// Tab from the search field goes to the "new fandom" text field (operator-
// specified). Shift+Tab keeps normal reverse traversal.
function onSearchTab(e) {