fix(front): autofocus follows the stacking order of elements
This commit is contained in:
parent
3044a88dbc
commit
ef67b38018
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { ref, computed, useSlots, onMounted } from 'vue'
|
||||
import { ref, computed, useSlots, onMounted, watch, onUnmounted, nextTick } from 'vue'
|
||||
|
||||
import { type ColorProps, type VariantProps, type DefaultProps, type RaisedProps, type PastelProps, color } from '~/composables/color'
|
||||
import { type WidthProps, width } from '~/composables/width'
|
||||
|
@ -65,9 +65,18 @@ const click = async (...args: any[]) => {
|
|||
internalLoader.value = false
|
||||
}
|
||||
}
|
||||
onMounted(() => {
|
||||
if (props.autofocus) button.value.focus()
|
||||
})
|
||||
|
||||
const previouslyFocusedElement = ref()
|
||||
|
||||
onMounted(() => props.autofocus && nextTick(() => {
|
||||
previouslyFocusedElement.value = document.activeElement
|
||||
previouslyFocusedElement.value?.blur()
|
||||
button.value.focus()
|
||||
}))
|
||||
|
||||
onUnmounted(() =>
|
||||
previouslyFocusedElement.value?.focus()
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import onKeyboardShortcut from '~/composables/onKeyboardShortcut'
|
||||
import { type ColorProps, type VariantProps, type DefaultProps, type RaisedProps, type PastelProps, color } from '~/composables/color.ts'
|
||||
|
@ -41,9 +41,17 @@ const { t } = useI18n()
|
|||
|
||||
const input = ref()
|
||||
|
||||
onMounted(() => {
|
||||
if (props.autofocus) input.value.focus()
|
||||
})
|
||||
const previouslyFocusedElement = ref()
|
||||
|
||||
onMounted(() => props.autofocus && nextTick(() => {
|
||||
previouslyFocusedElement.value = document.activeElement
|
||||
previouslyFocusedElement.value?.blur()
|
||||
input.value.focus()
|
||||
}))
|
||||
|
||||
onUnmounted(() =>
|
||||
previouslyFocusedElement.value?.focus()
|
||||
)
|
||||
|
||||
const model = defineModel<string|number>({ required: true })
|
||||
</script>
|
||||
|
|
|
@ -13,7 +13,8 @@ const props = defineProps<{
|
|||
overPopover?: true,
|
||||
destructive?: true,
|
||||
cancel?: string,
|
||||
icon? : string
|
||||
icon?: string,
|
||||
autofocus?: true | 'off'
|
||||
} &(ColorProps | DefaultProps)>()
|
||||
|
||||
const isOpen = defineModel<boolean>({ default: false })
|
||||
|
@ -23,8 +24,11 @@ const previouslyFocusedElement = ref()
|
|||
// Handle focus and inertness of the elements behind the modal
|
||||
watchEffect(() => {
|
||||
if (isOpen.value) {
|
||||
previouslyFocusedElement.value = document.activeElement
|
||||
document.querySelector('#app')?.setAttribute('inert', 'true')
|
||||
nextTick(()=>{
|
||||
previouslyFocusedElement.value = document.activeElement
|
||||
previouslyFocusedElement.value?.blur()
|
||||
document.querySelector('#app')?.setAttribute('inert', 'true')
|
||||
})
|
||||
} else {
|
||||
nextTick(() => previouslyFocusedElement.value?.focus())
|
||||
document.querySelector('#app')?.removeAttribute('inert')
|
||||
|
@ -93,6 +97,7 @@ onKeyboardShortcut('escape', () => { isOpen.value = false })
|
|||
icon="bi-x-lg"
|
||||
ghost
|
||||
align-self="baseline"
|
||||
:autofocus="props.autofocus === undefined ? ($slots.actions || cancel ? undefined : true) : props.autofocus !== 'off'"
|
||||
@click="isOpen = false"
|
||||
/>
|
||||
</Layout>
|
||||
|
|
|
@ -335,6 +335,12 @@ primary
|
|||
|
||||
</Layout>
|
||||
|
||||
## Auto-focus the close button
|
||||
|
||||
If there are no action slots and no cancel button, the close button is auto-focused.
|
||||
|
||||
The `autofocus` prop, when set to `off`, overrides this behavior.
|
||||
|
||||
## Responsivity
|
||||
|
||||
### Designing for small screens
|
||||
|
|
Loading…
Reference in New Issue