feat(date) : anneau focus clavier et ouverture clavier sur CalendarField
Couvre toute la famille date (Date, DateRange, DateTime, DateWeek) : - Anneau de focus clavier (clavier-only) ; ouvert, l'anneau entoure champ + calendrier d'un seul tenant (combo) - Entrée / Espace ouvrent/ferment le calendrier (mode non éditable), Échap ferme ; mode éditable inchangé - Anneau sur la croix d'effacement Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -23,10 +23,10 @@
|
|||||||
placeholder="_"
|
placeholder="_"
|
||||||
type="text"
|
type="text"
|
||||||
@click="onFieldClick"
|
@click="onFieldClick"
|
||||||
@focus="onFocus"
|
@focus="onFocus(); onKbdFocus()"
|
||||||
@input="onInput"
|
@input="onInput"
|
||||||
@blur="onBlur"
|
@blur="onBlur(); onKbdBlur()"
|
||||||
@keydown.enter.prevent="onEnter"
|
@keydown="onKeydown"
|
||||||
>
|
>
|
||||||
|
|
||||||
<label
|
<label
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
v-if="showClear"
|
v-if="showClear"
|
||||||
type="button"
|
type="button"
|
||||||
data-test="clear"
|
data-test="clear"
|
||||||
class="text-m-muted hover:text-m-primary"
|
class="m-focus-ring rounded-malio text-m-muted hover:text-m-primary"
|
||||||
aria-label="Effacer la date"
|
aria-label="Effacer la date"
|
||||||
@click.stop="emit('clear')"
|
@click.stop="emit('clear')"
|
||||||
>
|
>
|
||||||
@@ -66,6 +66,7 @@
|
|||||||
data-test="popover"
|
data-test="popover"
|
||||||
role="dialog"
|
role="dialog"
|
||||||
class="absolute left-0 right-0 top-full z-20 box-border w-full rounded-b-md bg-white p-[10px] shadow-[0_4px_4px_0_rgba(0,0,0,0.25)]"
|
class="absolute left-0 right-0 top-full z-20 box-border w-full rounded-b-md bg-white p-[10px] shadow-[0_4px_4px_0_rgba(0,0,0,0.25)]"
|
||||||
|
:class="keyboardFocused ? 'm-combo-ring-bottom' : ''"
|
||||||
>
|
>
|
||||||
<CalendarHeader
|
<CalendarHeader
|
||||||
:view-mode="viewMode"
|
:view-mode="viewMode"
|
||||||
@@ -114,9 +115,12 @@ import CalendarHeader from './CalendarHeader.vue'
|
|||||||
import MonthPicker from './MonthPicker.vue'
|
import MonthPicker from './MonthPicker.vue'
|
||||||
import {useCalendarPopover} from '../composables/useCalendarPopover'
|
import {useCalendarPopover} from '../composables/useCalendarPopover'
|
||||||
import {useCalendarView} from '../composables/useCalendarView'
|
import {useCalendarView} from '../composables/useCalendarView'
|
||||||
|
import {useKbdFocusRing} from '../../shared/useKbdFocusRing'
|
||||||
|
|
||||||
defineOptions({name: 'MalioCalendarField', inheritAttrs: false})
|
defineOptions({name: 'MalioCalendarField', inheritAttrs: false})
|
||||||
|
|
||||||
|
const {keyboardFocused, onFocus: onKbdFocus, onBlur: onKbdBlur} = useKbdFocusRing()
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
displayValue: string
|
displayValue: string
|
||||||
@@ -236,6 +240,33 @@ const onEnter = () => {
|
|||||||
closePopover()
|
closePopover()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onKeydown = (e: KeyboardEvent) => {
|
||||||
|
if (props.disabled || props.readonly) return
|
||||||
|
|
||||||
|
if (e.key === 'Escape') {
|
||||||
|
if (isOpen.value) {
|
||||||
|
e.preventDefault()
|
||||||
|
closePopover()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.editable) {
|
||||||
|
// En mode éditable, Entrée valide la saisie (Espace = caractère normal)
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
e.preventDefault()
|
||||||
|
onEnter()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mode non éditable : Entrée / Espace ouvre ou ferme le calendrier
|
||||||
|
if (e.key === 'Enter' || e.key === ' ') {
|
||||||
|
e.preventDefault()
|
||||||
|
onFieldClick()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
watch(() => props.syncTo, (value) => {
|
watch(() => props.syncTo, (value) => {
|
||||||
if (isOpen.value) syncToIso(value)
|
if (isOpen.value) syncToIso(value)
|
||||||
})
|
})
|
||||||
@@ -262,6 +293,7 @@ const mergedInputClass = computed(() =>
|
|||||||
? 'border-m-success'
|
? 'border-m-success'
|
||||||
: isReadonly.value ? '' : 'focus:border-m-primary',
|
: isReadonly.value ? '' : 'focus:border-m-primary',
|
||||||
(!isReadonly.value && isOpen.value) ? 'border-m-primary !py-[9px] !rounded-b-none' : '',
|
(!isReadonly.value && isOpen.value) ? 'border-m-primary !py-[9px] !rounded-b-none' : '',
|
||||||
|
keyboardFocused.value ? (isOpen.value ? 'm-combo-ring-top' : 'm-focus-ring-kbd') : '',
|
||||||
props.inputClass,
|
props.inputClass,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user