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">
|
<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 ColorProps, type VariantProps, type DefaultProps, type RaisedProps, type PastelProps, color } from '~/composables/color'
|
||||||
import { type WidthProps, width } from '~/composables/width'
|
import { type WidthProps, width } from '~/composables/width'
|
||||||
|
@ -65,9 +65,18 @@ const click = async (...args: any[]) => {
|
||||||
internalLoader.value = false
|
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onMounted, ref } from 'vue'
|
import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import onKeyboardShortcut from '~/composables/onKeyboardShortcut'
|
import onKeyboardShortcut from '~/composables/onKeyboardShortcut'
|
||||||
import { type ColorProps, type VariantProps, type DefaultProps, type RaisedProps, type PastelProps, color } from '~/composables/color.ts'
|
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()
|
const input = ref()
|
||||||
|
|
||||||
onMounted(() => {
|
const previouslyFocusedElement = ref()
|
||||||
if (props.autofocus) input.value.focus()
|
|
||||||
})
|
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 })
|
const model = defineModel<string|number>({ required: true })
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -13,7 +13,8 @@ const props = defineProps<{
|
||||||
overPopover?: true,
|
overPopover?: true,
|
||||||
destructive?: true,
|
destructive?: true,
|
||||||
cancel?: string,
|
cancel?: string,
|
||||||
icon? : string
|
icon?: string,
|
||||||
|
autofocus?: true | 'off'
|
||||||
} &(ColorProps | DefaultProps)>()
|
} &(ColorProps | DefaultProps)>()
|
||||||
|
|
||||||
const isOpen = defineModel<boolean>({ default: false })
|
const isOpen = defineModel<boolean>({ default: false })
|
||||||
|
@ -23,8 +24,11 @@ const previouslyFocusedElement = ref()
|
||||||
// Handle focus and inertness of the elements behind the modal
|
// Handle focus and inertness of the elements behind the modal
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
if (isOpen.value) {
|
if (isOpen.value) {
|
||||||
previouslyFocusedElement.value = document.activeElement
|
nextTick(()=>{
|
||||||
document.querySelector('#app')?.setAttribute('inert', 'true')
|
previouslyFocusedElement.value = document.activeElement
|
||||||
|
previouslyFocusedElement.value?.blur()
|
||||||
|
document.querySelector('#app')?.setAttribute('inert', 'true')
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
nextTick(() => previouslyFocusedElement.value?.focus())
|
nextTick(() => previouslyFocusedElement.value?.focus())
|
||||||
document.querySelector('#app')?.removeAttribute('inert')
|
document.querySelector('#app')?.removeAttribute('inert')
|
||||||
|
@ -93,6 +97,7 @@ onKeyboardShortcut('escape', () => { isOpen.value = false })
|
||||||
icon="bi-x-lg"
|
icon="bi-x-lg"
|
||||||
ghost
|
ghost
|
||||||
align-self="baseline"
|
align-self="baseline"
|
||||||
|
:autofocus="props.autofocus === undefined ? ($slots.actions || cancel ? undefined : true) : props.autofocus !== 'off'"
|
||||||
@click="isOpen = false"
|
@click="isOpen = false"
|
||||||
/>
|
/>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
|
@ -335,6 +335,12 @@ primary
|
||||||
|
|
||||||
</Layout>
|
</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
|
## Responsivity
|
||||||
|
|
||||||
### Designing for small screens
|
### Designing for small screens
|
||||||
|
|
Loading…
Reference in New Issue