feat(date) : mode editable dans CalendarField (saisie clavier)

This commit is contained in:
2026-06-09 11:50:50 +02:00
parent 36940139b9
commit d01875750c
@@ -6,14 +6,15 @@
>
<input
:id="inputId"
v-maska="maskaOptions"
:name="name"
data-test="date-input"
readonly
:readonly="inputReadonly"
autocomplete="off"
:class="mergedInputClass"
:required="required"
:disabled="disabled"
:value="displayValue"
:value="editable ? draft : displayValue"
:aria-invalid="!!error"
:aria-describedby="describedBy"
:aria-expanded="isOpen"
@@ -22,6 +23,10 @@
placeholder="_"
type="text"
@click="onFieldClick"
@focus="onFocus"
@input="onInput"
@blur="onBlur"
@keydown.enter.prevent="onEnter"
>
<label
@@ -102,6 +107,8 @@
import {computed, ref, useAttrs, useId, watch} from 'vue'
import {Icon} from '@iconify/vue'
import {twMerge} from 'tailwind-merge'
import {vMaska} from 'maska/vue'
import type {MaskInputOptions} from 'maska'
import MalioRequiredMark from '../../shared/RequiredMark.vue'
import CalendarHeader from './CalendarHeader.vue'
import MonthPicker from './MonthPicker.vue'
@@ -125,6 +132,7 @@ const props = withDefaults(
error?: string
success?: string
clearable?: boolean
editable?: boolean
inputClass?: string
labelClass?: string
groupClass?: string
@@ -142,6 +150,7 @@ const props = withDefaults(
error: '',
success: '',
clearable: true,
editable: false,
inputClass: '',
labelClass: '',
groupClass: '',
@@ -149,19 +158,32 @@ const props = withDefaults(
},
)
const emit = defineEmits<{(e: 'clear' | 'close'): void}>()
const emit = defineEmits<{
(e: 'clear' | 'close'): void
(e: 'commit', value: string): void
}>()
const attrs = useAttrs()
const generatedId = useId()
const root = ref<HTMLElement | null>(null)
const draft = ref(props.displayValue)
const maskaOptions = computed<MaskInputOptions>(() => ({mask: props.editable ? '##/##/####' : undefined}))
const inputReadonly = computed(() => !props.editable || props.readonly || props.disabled)
watch(() => props.displayValue, (value) => {
draft.value = value
})
const {isOpen, viewMode, open, close: closePopover, toggleView} = useCalendarPopover(root)
const {currentMonth, currentYear, goToPrev, goToNext, selectMonth, syncToIso} = useCalendarView(viewMode)
const inputId = computed(() => props.id?.toString() || `malio-date-${generatedId}`)
const hasError = computed(() => !!props.error)
const hasSuccess = computed(() => !!props.success && !hasError.value)
const isFilled = computed(() => props.displayValue.length > 0)
const isFilled = computed(() =>
(props.editable ? draft.value.length : props.displayValue.length) > 0,
)
const isReadonly = computed(() => props.readonly && !props.disabled)
const showClear = computed(() =>
props.clearable && isFilled.value && !props.disabled && !props.readonly,
@@ -176,6 +198,13 @@ watch(isOpen, (value) => {
const onFieldClick = () => {
if (props.disabled || props.readonly) return
if (props.editable) {
if (!isOpen.value) {
syncToIso(props.syncTo)
open()
}
return
}
if (isOpen.value) {
closePopover()
return
@@ -184,6 +213,29 @@ const onFieldClick = () => {
open()
}
const onFocus = () => {
if (props.disabled || props.readonly || !props.editable) return
if (!isOpen.value) {
syncToIso(props.syncTo)
open()
}
}
const onInput = (event: Event) => {
draft.value = (event.target as HTMLInputElement).value
}
const onBlur = () => {
if (!props.editable) return
emit('commit', draft.value)
}
const onEnter = () => {
if (!props.editable) return
emit('commit', draft.value)
closePopover()
}
watch(() => props.syncTo, (value) => {
if (isOpen.value) syncToIso(value)
})