fix: fall back when initial-focus target is not focusable yet
Task detail opens with taskDetailBusy=true, so the close button is disabled at the moment focusIntoPanel runs; focusing it silently failed and left focus on body (Esc then never reached the sheet). Skip targets that are disabled/hidden/inert without relying on layout metrics (keeps jsdom tests valid), falling back to first focusable or the panel itself.
This commit is contained in:
@@ -1879,7 +1879,7 @@ onUnmounted(() => {
|
|||||||
</main>
|
</main>
|
||||||
<div v-if="selectedTask || habitDetailOpen || calendarDetailOpen" class="pane-resizer pane-resizer--detail" role="separator" :aria-label="detailSeparatorLabel" aria-orientation="vertical" aria-valuemin="300" :aria-valuemax="detailMaxWidth" :aria-valuenow="detailWidth" tabindex="0" @pointerdown="startPaneResize('detail',$event)" @lostpointercapture="handlePaneLostPointerCapture" @keydown="resizePaneWithKeyboard('detail',$event)" />
|
<div v-if="selectedTask || habitDetailOpen || calendarDetailOpen" class="pane-resizer pane-resizer--detail" role="separator" :aria-label="detailSeparatorLabel" aria-orientation="vertical" aria-valuemin="300" :aria-valuemax="detailMaxWidth" :aria-valuenow="detailWidth" tabindex="0" @pointerdown="startPaneResize('detail',$event)" @lostpointercapture="handlePaneLostPointerCapture" @keydown="resizePaneWithKeyboard('detail',$event)" />
|
||||||
|
|
||||||
<AppSheet v-if="selectedTask" :open="true" :modal="compactLayout" variant="detail" panel-class="detail" title-id="task-detail-title" initial-focus="button[aria-label='关闭详情']" :close-on-scrim="compactLayout" :busy="taskDetailBusy" @close="closeTaskDetail" @submit.prevent="saveSelectedTaskChanges">
|
<AppSheet v-if="selectedTask" :open="true" :modal="compactLayout" variant="detail" panel-class="detail" title-id="task-detail-title" initial-focus=".detail-head button" :close-on-scrim="compactLayout" :busy="taskDetailBusy" @close="closeTaskDetail" @submit.prevent="saveSelectedTaskChanges">
|
||||||
<div class="detail-head"><span id="task-detail-title">任务详情</span><button class="icon" type="button" :disabled="taskDetailBusy" aria-label="关闭详情" @click="closeTaskDetail"><X/></button></div>
|
<div class="detail-head"><span id="task-detail-title">任务详情</span><button class="icon" type="button" :disabled="taskDetailBusy" aria-label="关闭详情" @click="closeTaskDetail"><X/></button></div>
|
||||||
<fieldset class="detail-form" :disabled="taskDetailBusy">
|
<fieldset class="detail-form" :disabled="taskDetailBusy">
|
||||||
<div class="detail-title"><button class="task-check detail-task-check" type="button" :aria-label="selectedTask.completed ? `重新打开${selectedTask.title}` : `完成${selectedTask.title}`" :aria-pressed="selectedTask.completed" @click="toggle(selectedTask)"><span class="task-check-mark" :class="`p${selectedTask.priority}`"><Check v-if="selectedTask.completed" /></span></button><textarea v-model="selectedTask.title" rows="2" aria-label="任务标题"/></div>
|
<div class="detail-title"><button class="task-check detail-task-check" type="button" :aria-label="selectedTask.completed ? `重新打开${selectedTask.title}` : `完成${selectedTask.title}`" :aria-pressed="selectedTask.completed" @click="toggle(selectedTask)"><span class="task-check-mark" :class="`p${selectedTask.priority}`"><Check v-if="selectedTask.completed" /></span></button><textarea v-model="selectedTask.title" rows="2" aria-label="任务标题"/></div>
|
||||||
|
|||||||
@@ -57,7 +57,11 @@ function keydown(event: KeyboardEvent) {
|
|||||||
function focusIntoPanel() {
|
function focusIntoPanel() {
|
||||||
if (!panel.value?.contains(document.activeElement)) {
|
if (!panel.value?.contains(document.activeElement)) {
|
||||||
const target = props.initialFocus ? panel.value?.querySelector<HTMLElement>(props.initialFocus) : null
|
const target = props.initialFocus ? panel.value?.querySelector<HTMLElement>(props.initialFocus) : null
|
||||||
;(target ?? focusables()[0] ?? panel.value)?.focus()
|
const usable = !!target && !target.matches(':disabled')
|
||||||
|
&& !target.closest('[hidden],[aria-hidden="true"],[inert]')
|
||||||
|
&& (() => { const s = window.getComputedStyle(target); return s.display !== 'none' && s.visibility !== 'hidden' })()
|
||||||
|
const el = usable ? target : (focusables()[0] ?? panel.value)
|
||||||
|
el?.focus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function activate() {
|
async function activate() {
|
||||||
|
|||||||
Reference in New Issue
Block a user