fix: Date + DateTime new emit update rawValue (#75)
Release / release (push) Successful in 1m8s
Release / release (push) Successful in 1m8s
| Numéro du ticket | Titre du ticket | |------------------|-----------------| | | | ## Description de la PR ## Modification du .env ## Check list - [ ] Pas de régression - [ ] TU/TI/TF rédigée - [ ] TU/TI/TF OK - [ ] CHANGELOG modifié --------- Co-authored-by: admin malio <malio@yuno.malio.fr> Co-authored-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr> Co-authored-by: matthieu <matthieu@yuno.malio.fr> Reviewed-on: #75 Co-authored-by: tristan <tristan@yuno.malio.fr> Co-committed-by: tristan <tristan@yuno.malio.fr>
This commit was merged in pull request #75.
This commit is contained in:
@@ -54,6 +54,7 @@ Liste des évolutions de la librairie Malio layer UI
|
|||||||
* [#MUI-43] MalioDateTime : saisie clavier `JJ/MM/AAAA HH:MM` optionnelle (prop `editable`, masque maska, `invalidMessage`) + même event `update:valid` que MalioDate (mêmes règles, émis dès le montage). Nouveau parseur `parseDisplayToIsoDateTime`.
|
* [#MUI-43] MalioDateTime : saisie clavier `JJ/MM/AAAA HH:MM` optionnelle (prop `editable`, masque maska, `invalidMessage`) + même event `update:valid` que MalioDate (mêmes règles, émis dès le montage). Nouveau parseur `parseDisplayToIsoDateTime`.
|
||||||
* [#MUI-43] Famille Date editable (MalioDate, MalioDateTime) : gabarit fantôme progressif — le format (`JJ/MM/AAAA` / `JJ/MM/AAAA HH:MM`) s'affiche en gris et se remplit au fil de la saisie (tapé en noir, reste en gris) ; séparateurs (`/`, espace, `:`) posés automatiquement dès qu'un groupe est complet (maska `eager`). CalendarField : prop `placeholderTemplate` (le masque maska en est dérivé), remplace l'ancienne mécanique de masque codé en dur.
|
* [#MUI-43] Famille Date editable (MalioDate, MalioDateTime) : gabarit fantôme progressif — le format (`JJ/MM/AAAA` / `JJ/MM/AAAA HH:MM`) s'affiche en gris et se remplit au fil de la saisie (tapé en noir, reste en gris) ; séparateurs (`/`, espace, `:`) posés automatiquement dès qu'un groupe est complet (maska `eager`). CalendarField : prop `placeholderTemplate` (le masque maska en est dérivé), remplace l'ancienne mécanique de masque codé en dur.
|
||||||
* [#MUI-43] CalendarField : la croix d'effacement réinitialise désormais la saisie clavier même après une date invalide (le `v-model` restant `null`, le champ se vidait pas).
|
* [#MUI-43] CalendarField : la croix d'effacement réinitialise désormais la saisie clavier même après une date invalide (le `v-model` restant `null`, le champ se vidait pas).
|
||||||
|
* [#MUI-44] MalioDate / MalioDateTime : event `update:rawValue` (string) exposant la saisie brute sur un canal séparé pour la validation back-autoritative — saisie invalide (non parsable ou hors `min`/`max`) → texte trimmé tel que tapé, saisie valide/vide + clear + sélection au calendrier → `''`. `modelValue` reste `string` ISO `| null` (la saisie invalide n'y transite jamais) ; le parent construit son payload via `valid ? modelValue : rawValue`.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
* DataTable : libellés de pagination en français — `Préc.` / `Suiv.` (étaient `Prev` / `Next`) ; aria-labels déjà en français inchangés.
|
* DataTable : libellés de pagination en français — `Préc.` / `Suiv.` (étaient `Prev` / `Next`) ; aria-labels déjà en français inchangés.
|
||||||
|
|||||||
+9
-3
@@ -509,6 +509,8 @@ Avec `editable`, l'utilisateur peut aussi taper la date au clavier. La valeur n'
|
|||||||
|
|
||||||
L'event `update:valid` remonte l'état de validité de la saisie au parent (`true` = vide ou date valide dans les bornes ; `false` = saisie malformée ou hors `min`/`max`). Il est émis **dès le montage** (état d'un champ pré-rempli connu sans interaction) puis à chaque transition. Il permet d'agréger la validité des champs date dans la gate de submit d'un formulaire — une saisie invalide n'émettant pas `modelValue`, c'est le seul signal disponible côté parent. La validité ne couvre **pas** l'obligation `required` (un champ vide reste valide), qui reste à la charge du parent.
|
L'event `update:valid` remonte l'état de validité de la saisie au parent (`true` = vide ou date valide dans les bornes ; `false` = saisie malformée ou hors `min`/`max`). Il est émis **dès le montage** (état d'un champ pré-rempli connu sans interaction) puis à chaque transition. Il permet d'agréger la validité des champs date dans la gate de submit d'un formulaire — une saisie invalide n'émettant pas `modelValue`, c'est le seul signal disponible côté parent. La validité ne couvre **pas** l'obligation `required` (un champ vide reste valide), qui reste à la charge du parent.
|
||||||
|
|
||||||
|
L'event `update:rawValue` expose la **saisie brute** sur un canal séparé, pour les formulaires en validation back-autoritative (le serveur tranche le format et renvoie un `422`). Il est émis à chaque commit : saisie invalide (non parsable ou hors `min`/`max`) → la chaîne trimmée telle que tapée (ex. `"32/13/2026"`) ; saisie valide ou vide, clear, sélection au calendrier → `''`. Le parent construit alors son payload via `valid ? modelValue : rawValue`. La saisie invalide **ne transite jamais** par `modelValue` (qui reste `string` ISO `| null` pour l'affichage et le round-trip) ; `valid` dit *qu'il y a* une erreur, `rawValue` dit *quoi* envoyer.
|
||||||
|
|
||||||
| Prop | Type | Défaut | Description |
|
| Prop | Type | Défaut | Description |
|
||||||
|------|------|--------|-------------|
|
|------|------|--------|-------------|
|
||||||
| `modelValue` | `string \| null` | `undefined` | Date ISO `"YYYY-MM-DD"` (v-model) |
|
| `modelValue` | `string \| null` | `undefined` | Date ISO `"YYYY-MM-DD"` (v-model) |
|
||||||
@@ -530,7 +532,7 @@ L'event `update:valid` remonte l'état de validité de la saisie au parent (`tru
|
|||||||
| `reserveMessageSpace` | `boolean` | `true` | Réserve l'espace de la ligne message sous le champ (min-h) même sans message. `false` = la ligne ne prend de place que s'il y a un hint/error/success. |
|
| `reserveMessageSpace` | `boolean` | `true` | Réserve l'espace de la ligne message sous le champ (min-h) même sans message. `false` = la ligne ne prend de place que s'il y a un hint/error/success. |
|
||||||
| `inputClass` / `labelClass` / `groupClass` | `string` | `''` | Override des classes |
|
| `inputClass` / `labelClass` / `groupClass` | `string` | `''` | Override des classes |
|
||||||
|
|
||||||
**Events :** `update:modelValue(value: string | null)`, `update:valid(value: boolean)`
|
**Events :** `update:modelValue(value: string | null)`, `update:valid(value: boolean)`, `update:rawValue(value: string)`
|
||||||
|
|
||||||
**Clavier :** `Entrée` / `Espace` ouvrent le calendrier, `Échap` ferme. Anneau de focus clavier (combo champ + calendrier à l'ouverture). La croix d'effacement est focusable. _(Comportement partagé par DateRange, DateTime, DateWeek via le shell CalendarField.)_
|
**Clavier :** `Entrée` / `Espace` ouvrent le calendrier, `Échap` ferme. Anneau de focus clavier (combo champ + calendrier à l'ouverture). La croix d'effacement est focusable. _(Comportement partagé par DateRange, DateTime, DateWeek via le shell CalendarField.)_
|
||||||
|
|
||||||
@@ -540,6 +542,9 @@ L'event `update:valid` remonte l'état de validité de la saisie au parent (`tru
|
|||||||
<MalioDate v-model="rdv" label="Rendez-vous" :min="todayIso" :max="maxIso" />
|
<MalioDate v-model="rdv" label="Rendez-vous" :min="todayIso" :max="maxIso" />
|
||||||
<MalioDate v-model="date" label="Date de naissance" editable />
|
<MalioDate v-model="date" label="Date de naissance" editable />
|
||||||
<MalioDate v-model="date" label="Date de naissance" editable @update:valid="dateValide = $event" />
|
<MalioDate v-model="date" label="Date de naissance" editable @update:valid="dateValide = $event" />
|
||||||
|
<!-- Validation back-autoritative : on envoie la saisie brute si invalide -->
|
||||||
|
<MalioDate v-model="date" editable @update:valid="valide = $event" @update:rawValue="brut = $event" />
|
||||||
|
<!-- payload : valide ? date : brut -->
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -694,16 +699,17 @@ La valeur est une chaîne **ISO naïve sans fuseau** au format `"YYYY-MM-DDTHH:M
|
|||||||
| `reserveMessageSpace` | `boolean` | `true` | Réserve l'espace de la ligne message sous le champ (min-h) même sans message. `false` = la ligne ne prend de place que s'il y a un hint/error/success. |
|
| `reserveMessageSpace` | `boolean` | `true` | Réserve l'espace de la ligne message sous le champ (min-h) même sans message. `false` = la ligne ne prend de place que s'il y a un hint/error/success. |
|
||||||
| `inputClass` / `labelClass` / `groupClass` | `string` | `''` | Override des classes |
|
| `inputClass` / `labelClass` / `groupClass` | `string` | `''` | Override des classes |
|
||||||
|
|
||||||
**Events :** `update:modelValue(value: string | null)`, `update:valid(value: boolean)`
|
**Events :** `update:modelValue(value: string | null)`, `update:valid(value: boolean)`, `update:rawValue(value: string)`
|
||||||
|
|
||||||
Flux : cliquer un jour fixe la date (heure par défaut `00:00`), régler l'heure met à jour l'heure ; le popover se ferme au clic extérieur. La valeur est émise en direct à chaque interaction.
|
Flux : cliquer un jour fixe la date (heure par défaut `00:00`), régler l'heure met à jour l'heure ; le popover se ferme au clic extérieur. La valeur est émise en direct à chaque interaction.
|
||||||
|
|
||||||
Avec `editable`, l'utilisateur peut aussi taper `JJ/MM/AAAA HH:MM` au clavier. La valeur n'est émise qu'au blur (ou sur Entrée) si elle est valide et dans les bornes ; sinon le texte est conservé et le champ passe en erreur (`invalidMessage`). Un **gabarit fantôme** affiche le format en gris et se remplit au fil de la saisie (cf. MalioDate). L'event `update:valid` (booléen) — émis **dès le montage** puis à chaque transition — remonte l'état de validité au parent (`false` = saisie malformée ou hors `min`/`max`, qui n'émet pas `modelValue`), pour bloquer un submit. La validité ne couvre **pas** `required` (champ vide = valide), comme sur `MalioDate`.
|
Avec `editable`, l'utilisateur peut aussi taper `JJ/MM/AAAA HH:MM` au clavier. La valeur n'est émise qu'au blur (ou sur Entrée) si elle est valide et dans les bornes ; sinon le texte est conservé et le champ passe en erreur (`invalidMessage`). Un **gabarit fantôme** affiche le format en gris et se remplit au fil de la saisie (cf. MalioDate). L'event `update:valid` (booléen) — émis **dès le montage** puis à chaque transition — remonte l'état de validité au parent (`false` = saisie malformée ou hors `min`/`max`, qui n'émet pas `modelValue`), pour bloquer un submit. La validité ne couvre **pas** `required` (champ vide = valide), comme sur `MalioDate`. L'event `update:rawValue` expose la saisie brute pour la validation back-autoritative (mêmes règles que `MalioDate` : texte trimmé sur saisie invalide, `''` sinon — clear et sélection au calendrier compris).
|
||||||
|
|
||||||
```vue
|
```vue
|
||||||
<MalioDateTime v-model="rdv" label="Date et heure du rendez-vous" />
|
<MalioDateTime v-model="rdv" label="Date et heure du rendez-vous" />
|
||||||
<!-- rdv === "2026-05-20T14:30:00" -->
|
<!-- rdv === "2026-05-20T14:30:00" -->
|
||||||
<MalioDateTime v-model="rdv" label="Rendez-vous" editable @update:valid="rdvValide = $event" />
|
<MalioDateTime v-model="rdv" label="Rendez-vous" editable @update:valid="rdvValide = $event" />
|
||||||
|
<MalioDateTime v-model="rdv" editable @update:valid="valide = $event" @update:rawValue="brut = $event" />
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -471,4 +471,58 @@ describe('MalioDate', () => {
|
|||||||
expect(wrapper.emitted('update:valid')?.at(-1)).toEqual([true])
|
expect(wrapper.emitted('update:valid')?.at(-1)).toEqual([true])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('saisie brute (update:rawValue)', () => {
|
||||||
|
it('émet le texte brut trimmé sur saisie malformée, sans émettre modelValue', async () => {
|
||||||
|
const wrapper = mountDate({editable: true})
|
||||||
|
const input = wrapper.get('[data-test="date-input"]')
|
||||||
|
await input.setValue('32/13/2026')
|
||||||
|
await input.trigger('blur')
|
||||||
|
expect(wrapper.emitted('update:rawValue')?.at(-1)).toEqual(['32/13/2026'])
|
||||||
|
expect(wrapper.emitted('update:modelValue')).toBeUndefined()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('émet le texte brut trimmé sur saisie hors min/max', async () => {
|
||||||
|
const wrapper = mountDate({editable: true, min: '2026-05-10', max: '2026-05-20'})
|
||||||
|
const input = wrapper.get('[data-test="date-input"]')
|
||||||
|
await input.setValue('25/12/2026')
|
||||||
|
await input.trigger('blur')
|
||||||
|
expect(wrapper.emitted('update:rawValue')?.at(-1)).toEqual(['25/12/2026'])
|
||||||
|
expect(wrapper.emitted('update:modelValue')).toBeUndefined()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('émet rawValue vide et l\'ISO sur saisie clavier valide', async () => {
|
||||||
|
const wrapper = mountDate({editable: true})
|
||||||
|
const input = wrapper.get('[data-test="date-input"]')
|
||||||
|
await input.setValue('19/05/2026')
|
||||||
|
await input.trigger('blur')
|
||||||
|
expect(wrapper.emitted('update:rawValue')?.at(-1)).toEqual([''])
|
||||||
|
expect(wrapper.emitted('update:modelValue')?.at(-1)).toEqual(['2026-05-19'])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('émet rawValue vide sur saisie vidée au blur', async () => {
|
||||||
|
const wrapper = mountDate({editable: true, modelValue: '2026-05-19'})
|
||||||
|
const input = wrapper.get('[data-test="date-input"]')
|
||||||
|
await input.setValue('')
|
||||||
|
await input.trigger('blur')
|
||||||
|
expect(wrapper.emitted('update:rawValue')?.at(-1)).toEqual([''])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('émet rawValue vide sur clear', async () => {
|
||||||
|
const wrapper = mountDate({modelValue: '2026-05-19'})
|
||||||
|
await wrapper.get('[data-test="clear"]').trigger('click')
|
||||||
|
expect(wrapper.emitted('update:rawValue')?.at(-1)).toEqual([''])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('émet rawValue vide quand on sélectionne une date au calendrier', async () => {
|
||||||
|
const wrapper = mountDate({editable: true})
|
||||||
|
const input = wrapper.get('[data-test="date-input"]')
|
||||||
|
await input.setValue('32/13/2026')
|
||||||
|
await input.trigger('blur')
|
||||||
|
expect(wrapper.emitted('update:rawValue')?.at(-1)).toEqual(['32/13/2026'])
|
||||||
|
await input.trigger('focus')
|
||||||
|
await wrapper.get('[data-test="day"][data-iso="2026-05-19"]').trigger('click')
|
||||||
|
expect(wrapper.emitted('update:rawValue')?.at(-1)).toEqual([''])
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -90,6 +90,10 @@ const props = withDefaults(
|
|||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'update:modelValue', value: string | null): void
|
(e: 'update:modelValue', value: string | null): void
|
||||||
(e: 'update:valid', value: boolean): void
|
(e: 'update:valid', value: boolean): void
|
||||||
|
// Canal séparé pour la saisie invalide (validation back-autoritative) : texte brut
|
||||||
|
// tel que tapé sur saisie non parsable/hors plage, '' sinon. Ne JAMAIS transiter
|
||||||
|
// par modelValue, qui doit rester ISO|null pour l'affichage et le round-trip.
|
||||||
|
(e: 'update:rawValue', value: string): void
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const displayValue = computed(() => formatIsoToDisplay(props.modelValue ?? null))
|
const displayValue = computed(() => formatIsoToDisplay(props.modelValue ?? null))
|
||||||
@@ -108,25 +112,30 @@ const onCommit = (text: string) => {
|
|||||||
const trimmed = text.trim()
|
const trimmed = text.trim()
|
||||||
if (trimmed === '') {
|
if (trimmed === '') {
|
||||||
setError('')
|
setError('')
|
||||||
|
emit('update:rawValue', '')
|
||||||
emit('update:modelValue', null)
|
emit('update:modelValue', null)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const iso = parseDisplayToIso(trimmed)
|
const iso = parseDisplayToIso(trimmed)
|
||||||
if (iso && isDateInRange(iso, props.min, props.max)) {
|
if (iso && isDateInRange(iso, props.min, props.max)) {
|
||||||
setError('')
|
setError('')
|
||||||
|
emit('update:rawValue', '')
|
||||||
emit('update:modelValue', iso)
|
emit('update:modelValue', iso)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
setError(props.invalidMessage)
|
setError(props.invalidMessage)
|
||||||
|
emit('update:rawValue', trimmed)
|
||||||
}
|
}
|
||||||
|
|
||||||
const onClear = () => {
|
const onClear = () => {
|
||||||
setError('')
|
setError('')
|
||||||
|
emit('update:rawValue', '')
|
||||||
emit('update:modelValue', null)
|
emit('update:modelValue', null)
|
||||||
}
|
}
|
||||||
|
|
||||||
const onSelect = (iso: string, close: () => void) => {
|
const onSelect = (iso: string, close: () => void) => {
|
||||||
setError('')
|
setError('')
|
||||||
|
emit('update:rawValue', '')
|
||||||
emit('update:modelValue', iso)
|
emit('update:modelValue', iso)
|
||||||
close()
|
close()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -283,4 +283,58 @@ describe('MalioDateTime', () => {
|
|||||||
expect(wrapper.emitted('update:valid')?.at(-1)).toEqual([true])
|
expect(wrapper.emitted('update:valid')?.at(-1)).toEqual([true])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('saisie brute (update:rawValue)', () => {
|
||||||
|
it('émet le texte brut trimmé sur saisie malformée, sans émettre modelValue', async () => {
|
||||||
|
const wrapper = mountDateTime({editable: true})
|
||||||
|
const input = wrapper.get('[data-test="date-input"]')
|
||||||
|
await input.setValue('32/13/2026 14:30')
|
||||||
|
await input.trigger('blur')
|
||||||
|
expect(wrapper.emitted('update:rawValue')?.at(-1)).toEqual(['32/13/2026 14:30'])
|
||||||
|
expect(wrapper.emitted('update:modelValue')).toBeUndefined()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('émet le texte brut trimmé sur saisie hors min/max', async () => {
|
||||||
|
const wrapper = mountDateTime({editable: true, min: '2026-05-10T00:00:00', max: '2026-05-20T00:00:00'})
|
||||||
|
const input = wrapper.get('[data-test="date-input"]')
|
||||||
|
await input.setValue('25/12/2026 10:00')
|
||||||
|
await input.trigger('blur')
|
||||||
|
expect(wrapper.emitted('update:rawValue')?.at(-1)).toEqual(['25/12/2026 10:00'])
|
||||||
|
expect(wrapper.emitted('update:modelValue')).toBeUndefined()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('émet rawValue vide et l\'ISO sur saisie clavier valide', async () => {
|
||||||
|
const wrapper = mountDateTime({editable: true})
|
||||||
|
const input = wrapper.get('[data-test="date-input"]')
|
||||||
|
await input.setValue('20/05/2026 14:30')
|
||||||
|
await input.trigger('blur')
|
||||||
|
expect(wrapper.emitted('update:rawValue')?.at(-1)).toEqual([''])
|
||||||
|
expect(wrapper.emitted('update:modelValue')?.at(-1)).toEqual(['2026-05-20T14:30:00'])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('émet rawValue vide sur saisie vidée au blur', async () => {
|
||||||
|
const wrapper = mountDateTime({editable: true, modelValue: '2026-05-20T14:30:00'})
|
||||||
|
const input = wrapper.get('[data-test="date-input"]')
|
||||||
|
await input.setValue('')
|
||||||
|
await input.trigger('blur')
|
||||||
|
expect(wrapper.emitted('update:rawValue')?.at(-1)).toEqual([''])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('émet rawValue vide sur clear', async () => {
|
||||||
|
const wrapper = mountDateTime({modelValue: '2026-05-20T14:30:00'})
|
||||||
|
await wrapper.get('[data-test="clear"]').trigger('click')
|
||||||
|
expect(wrapper.emitted('update:rawValue')?.at(-1)).toEqual([''])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('émet rawValue vide quand on sélectionne une date au calendrier', async () => {
|
||||||
|
const wrapper = mountDateTime({editable: true})
|
||||||
|
const input = wrapper.get('[data-test="date-input"]')
|
||||||
|
await input.setValue('32/13/2026 14:30')
|
||||||
|
await input.trigger('blur')
|
||||||
|
expect(wrapper.emitted('update:rawValue')?.at(-1)).toEqual(['32/13/2026 14:30'])
|
||||||
|
await input.trigger('focus')
|
||||||
|
await wrapper.get('[data-test="day"][data-iso="2026-05-19"]').trigger('click')
|
||||||
|
expect(wrapper.emitted('update:rawValue')?.at(-1)).toEqual([''])
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -103,6 +103,10 @@ const props = withDefaults(
|
|||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'update:modelValue', value: string | null): void
|
(e: 'update:modelValue', value: string | null): void
|
||||||
(e: 'update:valid', value: boolean): void
|
(e: 'update:valid', value: boolean): void
|
||||||
|
// Canal séparé pour la saisie invalide (validation back-autoritative) : texte brut
|
||||||
|
// tel que tapé sur saisie non parsable/hors plage, '' sinon. Ne JAMAIS transiter
|
||||||
|
// par modelValue, qui doit rester ISO|null pour l'affichage et le round-trip.
|
||||||
|
(e: 'update:rawValue', value: string): void
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
// pendingTime : heure réglée avant qu'un jour ne soit choisi (sinon on ne peut pas émettre).
|
// pendingTime : heure réglée avant qu'un jour ne soit choisi (sinon on ne peut pas émettre).
|
||||||
@@ -129,6 +133,7 @@ function onSelectDay(iso: string) {
|
|||||||
const now = new Date()
|
const now = new Date()
|
||||||
const time = parts.value.time || pendingTime.value || formatTime(now.getHours(), now.getMinutes())
|
const time = parts.value.time || pendingTime.value || formatTime(now.getHours(), now.getMinutes())
|
||||||
setError('')
|
setError('')
|
||||||
|
emit('update:rawValue', '')
|
||||||
emit('update:modelValue', composeDateTime(iso, time))
|
emit('update:modelValue', composeDateTime(iso, time))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,6 +141,7 @@ function onTimeChange(value: string | null) {
|
|||||||
if (!value) return
|
if (!value) return
|
||||||
if (datePart.value) {
|
if (datePart.value) {
|
||||||
setError('')
|
setError('')
|
||||||
|
emit('update:rawValue', '')
|
||||||
emit('update:modelValue', composeDateTime(datePart.value, value))
|
emit('update:modelValue', composeDateTime(datePart.value, value))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -147,21 +153,25 @@ function onCommit(text: string) {
|
|||||||
const trimmed = text.trim()
|
const trimmed = text.trim()
|
||||||
if (trimmed === '') {
|
if (trimmed === '') {
|
||||||
setError('')
|
setError('')
|
||||||
|
emit('update:rawValue', '')
|
||||||
emit('update:modelValue', null)
|
emit('update:modelValue', null)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const iso = parseDisplayToIsoDateTime(trimmed)
|
const iso = parseDisplayToIsoDateTime(trimmed)
|
||||||
if (iso && isDateInRange(iso, props.min, props.max)) {
|
if (iso && isDateInRange(iso, props.min, props.max)) {
|
||||||
setError('')
|
setError('')
|
||||||
|
emit('update:rawValue', '')
|
||||||
emit('update:modelValue', iso)
|
emit('update:modelValue', iso)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
setError(props.invalidMessage)
|
setError(props.invalidMessage)
|
||||||
|
emit('update:rawValue', trimmed)
|
||||||
}
|
}
|
||||||
|
|
||||||
function onClear() {
|
function onClear() {
|
||||||
setError('')
|
setError('')
|
||||||
pendingTime.value = ''
|
pendingTime.value = ''
|
||||||
|
emit('update:rawValue', '')
|
||||||
emit('update:modelValue', null)
|
emit('update:modelValue', null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user