@cnamts/synapse 0.0.15-alpha → 0.0.16-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/CookiesSelection/CookiesSelection.d.ts +26 -26
- package/dist/components/Customs/SyTextField/SyTextField.d.ts +1391 -1
- package/dist/components/DatePicker/DatePicker.d.ts +2810 -16
- package/dist/components/DatePicker/DateTextInput.d.ts +1401 -4
- package/dist/components/LangBtn/LangBtn.d.ts +4 -4
- package/dist/components/NirField/NirField.d.ts +2794 -4
- package/dist/components/PeriodField/PeriodField.d.ts +5636 -48
- package/dist/components/SyAlert/SyAlert.d.ts +72 -1
- package/dist/components/UploadWorkflow/UploadWorkflow.d.ts +26 -26
- package/dist/components/index.d.ts +1 -0
- package/dist/composables/date/useDateFormat.d.ts +2 -2
- package/dist/composables/date/useDateFormatDayjs.d.ts +23 -0
- package/dist/composables/date/useDateInitializationDayjs.d.ts +18 -0
- package/dist/design-system-v3.js +3953 -3728
- package/dist/design-system-v3.umd.cjs +1 -1
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/Customs/SyTextField/Accessibilite.stories.ts +7 -0
- package/src/components/Customs/SyTextField/SyTextField.stories.ts +13 -0
- package/src/components/Customs/SyTextField/SyTextField.vue +82 -17
- package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.vue +795 -0
- package/src/components/DatePicker/DatePicker.stories.ts +432 -1
- package/src/components/DatePicker/DatePicker.vue +66 -24
- package/src/components/DatePicker/DatePickerValidation.stories.ts +9 -1
- package/src/components/DatePicker/DateTextInput.vue +85 -133
- package/src/components/DatePicker/docExamples/DatePickerBidirectionalValidation.vue +282 -0
- package/src/components/DatePicker/tests/DatePicker.spec.ts +33 -32
- package/src/components/DatePicker/tests/DateTextInput.spec.ts +81 -33
- package/src/components/SyAlert/Accessibilite.stories.ts +4 -0
- package/src/components/SyAlert/SyAlert.mdx +3 -7
- package/src/components/SyAlert/SyAlert.stories.ts +19 -12
- package/src/components/SyAlert/SyAlert.vue +88 -51
- package/src/components/SyAlert/tests/SyAlert.spec.ts +20 -2
- package/src/components/SyAlert/tests/__snapshots__/SyAlert.spec.ts.snap +83 -75
- package/src/components/index.ts +1 -0
- package/src/composables/date/useDateFormat.ts +17 -1
- package/src/composables/date/useDateFormatDayjs.ts +84 -0
- package/src/composables/date/useDateInitializationDayjs.ts +133 -0
- package/src/stories/Accessibilite/Avancement/Avancement.mdx +12 -0
- package/src/stories/Accessibilite/Avancement/Avancement.stories.ts +134 -0
- /package/src/components/DatePicker/{DatePickerValidationExamples.vue → docExamples/DatePickerValidationExamples.vue} +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/vue3'
|
|
2
2
|
import DatePicker from './DatePicker.vue'
|
|
3
|
-
import { ref } from 'vue'
|
|
3
|
+
import { ref, watch, computed } from 'vue'
|
|
4
|
+
import { useDateFormat } from '@/composables/date/useDateFormatDayjs'
|
|
4
5
|
|
|
5
6
|
const meta = {
|
|
6
7
|
title: 'Composants/Formulaires/DatePicker',
|
|
@@ -1199,6 +1200,436 @@ export const NoCalendarWithErrorDisabled: Story = {
|
|
|
1199
1200
|
},
|
|
1200
1201
|
}
|
|
1201
1202
|
|
|
1203
|
+
export const WithDayjsFormat: Story = {
|
|
1204
|
+
parameters: {
|
|
1205
|
+
sourceCode: [
|
|
1206
|
+
{
|
|
1207
|
+
name: 'Template',
|
|
1208
|
+
code: `
|
|
1209
|
+
<template>
|
|
1210
|
+
<div>
|
|
1211
|
+
<DatePicker
|
|
1212
|
+
v-model="date"
|
|
1213
|
+
placeholder="Sélectionner une date"
|
|
1214
|
+
format="DD/MM/YYYY"
|
|
1215
|
+
/>
|
|
1216
|
+
<p class="mt-4">Date formatée avec dayjs: {{ formattedDate }}</p>
|
|
1217
|
+
<p>Date parsée avec dayjs: {{ parsedDate ? parsedDate.toLocaleDateString() : 'Aucune date' }}</p>
|
|
1218
|
+
</div>
|
|
1219
|
+
</template>
|
|
1220
|
+
`,
|
|
1221
|
+
},
|
|
1222
|
+
{
|
|
1223
|
+
name: 'Script',
|
|
1224
|
+
code: `
|
|
1225
|
+
<script setup lang="ts">
|
|
1226
|
+
import { ref, watch } from 'vue'
|
|
1227
|
+
import { DatePicker } from '@cnamts/synapse'
|
|
1228
|
+
import { useDateFormat } from '@cnamts/synapse'
|
|
1229
|
+
|
|
1230
|
+
const { parseDate, formatDate } = useDateFormat()
|
|
1231
|
+
|
|
1232
|
+
const date = ref('')
|
|
1233
|
+
const formattedDate = ref('')
|
|
1234
|
+
const parsedDate = ref<Date | null>(null)
|
|
1235
|
+
|
|
1236
|
+
watch(date, (newDate) => {
|
|
1237
|
+
if (newDate) {
|
|
1238
|
+
parsedDate.value = parseDate(newDate, 'DD/MM/YYYY')
|
|
1239
|
+
if (parsedDate.value) {
|
|
1240
|
+
formattedDate.value = formatDate(parsedDate.value, 'YYYY-MM-DD')
|
|
1241
|
+
}
|
|
1242
|
+
} else {
|
|
1243
|
+
formattedDate.value = ''
|
|
1244
|
+
parsedDate.value = null
|
|
1245
|
+
}
|
|
1246
|
+
})
|
|
1247
|
+
</script>
|
|
1248
|
+
`,
|
|
1249
|
+
},
|
|
1250
|
+
],
|
|
1251
|
+
},
|
|
1252
|
+
args: {
|
|
1253
|
+
placeholder: 'Sélectionner une date',
|
|
1254
|
+
format: 'DD/MM/YYYY',
|
|
1255
|
+
isBirthDate: false,
|
|
1256
|
+
showWeekNumber: false,
|
|
1257
|
+
required: false,
|
|
1258
|
+
displayRange: false,
|
|
1259
|
+
displayIcon: true,
|
|
1260
|
+
displayAppendIcon: false,
|
|
1261
|
+
disabled: false,
|
|
1262
|
+
noIcon: false,
|
|
1263
|
+
noCalendar: false,
|
|
1264
|
+
modelValue: '',
|
|
1265
|
+
},
|
|
1266
|
+
render: () => {
|
|
1267
|
+
return {
|
|
1268
|
+
components: { DatePicker },
|
|
1269
|
+
setup() {
|
|
1270
|
+
// Importer le composable useDateFormat depuis useDateFormatDayjs
|
|
1271
|
+
const { parseDate, formatDate } = useDateFormat()
|
|
1272
|
+
|
|
1273
|
+
const date = ref('')
|
|
1274
|
+
const formattedDate = ref('')
|
|
1275
|
+
const parsedDate = ref<Date | null>(null)
|
|
1276
|
+
|
|
1277
|
+
watch(date, (newDate) => {
|
|
1278
|
+
if (newDate) {
|
|
1279
|
+
parsedDate.value = parseDate(newDate, 'DD/MM/YYYY')
|
|
1280
|
+
if (parsedDate.value) {
|
|
1281
|
+
formattedDate.value = formatDate(parsedDate.value, 'YYYY-MM-DD')
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
else {
|
|
1285
|
+
formattedDate.value = ''
|
|
1286
|
+
parsedDate.value = null
|
|
1287
|
+
}
|
|
1288
|
+
})
|
|
1289
|
+
|
|
1290
|
+
return { date, formattedDate, parsedDate }
|
|
1291
|
+
},
|
|
1292
|
+
|
|
1293
|
+
template: `
|
|
1294
|
+
<div class="pa-4">
|
|
1295
|
+
<DatePicker
|
|
1296
|
+
v-model="date"
|
|
1297
|
+
placeholder="Sélectionner une date"
|
|
1298
|
+
format="DD/MM/YYYY"
|
|
1299
|
+
/>
|
|
1300
|
+
<p class="mt-4">Date formatée avec dayjs: {{ formattedDate }}</p>
|
|
1301
|
+
<p>Date parsée avec dayjs: {{ parsedDate ? parsedDate.toLocaleDateString() : 'Aucune date' }}</p>
|
|
1302
|
+
</div>
|
|
1303
|
+
`,
|
|
1304
|
+
}
|
|
1305
|
+
},
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
export const BidirectionalValidation: Story = {
|
|
1309
|
+
parameters: {
|
|
1310
|
+
sourceCode: [
|
|
1311
|
+
{
|
|
1312
|
+
name: 'Template',
|
|
1313
|
+
code: `
|
|
1314
|
+
<template>
|
|
1315
|
+
<div class="date-validation-playground">
|
|
1316
|
+
<h1>Validation bidirectionnelle des dates</h1>
|
|
1317
|
+
<p class="description">
|
|
1318
|
+
Démonstration de la validation bidirectionnelle entre les DatePickers.
|
|
1319
|
+
Les messages d'erreur apparaissent directement dans les composants.
|
|
1320
|
+
</p>
|
|
1321
|
+
<div class="date-range-container">
|
|
1322
|
+
<div class="date-picker-wrapper">
|
|
1323
|
+
<h3>Date de début</h3>
|
|
1324
|
+
<DatePicker
|
|
1325
|
+
ref="startDatePickerRef"
|
|
1326
|
+
v-model="startDate"
|
|
1327
|
+
placeholder="Date de début"
|
|
1328
|
+
:custom-rules="startDateRules"
|
|
1329
|
+
required
|
|
1330
|
+
@update:model-value="validateEndDate"
|
|
1331
|
+
/>
|
|
1332
|
+
</div>
|
|
1333
|
+
<div class="date-picker-wrapper">
|
|
1334
|
+
<h3>Date de fin</h3>
|
|
1335
|
+
<DatePicker
|
|
1336
|
+
ref="endDatePickerRef"
|
|
1337
|
+
v-model="endDate"
|
|
1338
|
+
placeholder="Date de fin"
|
|
1339
|
+
:custom-rules="endDateRules"
|
|
1340
|
+
required
|
|
1341
|
+
@update:model-value="validateStartDate"
|
|
1342
|
+
/>
|
|
1343
|
+
</div>
|
|
1344
|
+
</div>
|
|
1345
|
+
<div class="current-values">
|
|
1346
|
+
<p><strong>Date de début:</strong> {{ startDate || 'Non sélectionnée' }}</p>
|
|
1347
|
+
<p><strong>Date de fin:</strong> {{ endDate || 'Non sélectionnée' }}</p>
|
|
1348
|
+
</div>
|
|
1349
|
+
</div>
|
|
1350
|
+
</template>
|
|
1351
|
+
`,
|
|
1352
|
+
},
|
|
1353
|
+
{
|
|
1354
|
+
name: 'Script',
|
|
1355
|
+
code: `
|
|
1356
|
+
<script lang="ts" setup>
|
|
1357
|
+
import { ref, watch, computed } from 'vue'
|
|
1358
|
+
import DatePicker from '@cnamts/synapse'
|
|
1359
|
+
import { useDateFormat } from '@cnamts/synapse'
|
|
1360
|
+
|
|
1361
|
+
const { parseDate } = useDateFormat()
|
|
1362
|
+
|
|
1363
|
+
// État des dates
|
|
1364
|
+
const startDate = ref<string | null>(null)
|
|
1365
|
+
const endDate = ref<string | null>(null)
|
|
1366
|
+
|
|
1367
|
+
// Références aux composants DatePicker pour accéder à leurs méthodes
|
|
1368
|
+
const startDatePickerRef = ref<InstanceType<typeof DatePicker> | null>(null)
|
|
1369
|
+
const endDatePickerRef = ref<InstanceType<typeof DatePicker> | null>(null)
|
|
1370
|
+
|
|
1371
|
+
// Règle de validation pour vérifier que la date de fin n'est pas avant la date de début
|
|
1372
|
+
const createEndDateValidationRule = () => ({
|
|
1373
|
+
type: 'custom',
|
|
1374
|
+
options: {
|
|
1375
|
+
validate: (value: string) => {
|
|
1376
|
+
// Si pas de valeur pour la date de fin, pas besoin de validation
|
|
1377
|
+
if (!value) return true
|
|
1378
|
+
|
|
1379
|
+
// Si pas de date de début mais une date de fin, afficher l'erreur
|
|
1380
|
+
if (!startDate.value) return 'Veuillez d'abord sélectionner une date de début'
|
|
1381
|
+
|
|
1382
|
+
const start = parseDate(startDate.value, 'DD/MM/YYYY')
|
|
1383
|
+
const end = parseDate(value, 'DD/MM/YYYY')
|
|
1384
|
+
|
|
1385
|
+
if (!start || !end) return true
|
|
1386
|
+
|
|
1387
|
+
return end >= start || 'La date de fin ne peut pas être antérieure à la date de début'
|
|
1388
|
+
},
|
|
1389
|
+
message: 'La date de fin ne peut pas être antérieure à la date de début',
|
|
1390
|
+
},
|
|
1391
|
+
})
|
|
1392
|
+
|
|
1393
|
+
// Règle de validation pour vérifier que la date de début n'est pas après la date de fin
|
|
1394
|
+
const createStartDateValidationRule = () => ({
|
|
1395
|
+
type: 'custom',
|
|
1396
|
+
options: {
|
|
1397
|
+
validate: (value: string) => {
|
|
1398
|
+
// Si pas de valeur pour la date de début ou pas de date de fin, pas besoin de validation
|
|
1399
|
+
if (!value || !endDate.value) return true
|
|
1400
|
+
|
|
1401
|
+
const start = parseDate(value, 'DD/MM/YYYY')
|
|
1402
|
+
const end = parseDate(endDate.value, 'DD/MM/YYYY')
|
|
1403
|
+
|
|
1404
|
+
if (!start || !end) return true
|
|
1405
|
+
|
|
1406
|
+
return start <= end || 'La date de début ne peut pas être postérieure à la date de fin'
|
|
1407
|
+
},
|
|
1408
|
+
message: 'La date de début ne peut pas être postérieure à la date de fin',
|
|
1409
|
+
},
|
|
1410
|
+
})
|
|
1411
|
+
|
|
1412
|
+
// Règles de validation pour la date de début
|
|
1413
|
+
const startDateRules = computed(() => [
|
|
1414
|
+
{
|
|
1415
|
+
type: 'required',
|
|
1416
|
+
options: {
|
|
1417
|
+
message: 'La date de début est requise.',
|
|
1418
|
+
},
|
|
1419
|
+
},
|
|
1420
|
+
createStartDateValidationRule(),
|
|
1421
|
+
])
|
|
1422
|
+
|
|
1423
|
+
// Règles de validation pour la date de fin
|
|
1424
|
+
const endDateRules = computed(() => [
|
|
1425
|
+
{
|
|
1426
|
+
type: 'required',
|
|
1427
|
+
options: {
|
|
1428
|
+
message: 'La date de fin est requise.',
|
|
1429
|
+
},
|
|
1430
|
+
},
|
|
1431
|
+
createEndDateValidationRule(),
|
|
1432
|
+
])
|
|
1433
|
+
|
|
1434
|
+
// Fonction pour forcer la validation de la date de fin quand la date de début change
|
|
1435
|
+
const validateEndDate = () => {
|
|
1436
|
+
if (endDatePickerRef.value && endDate.value) {
|
|
1437
|
+
// On utilise validateOnSubmit pour forcer la validation complète
|
|
1438
|
+
endDatePickerRef.value.validateOnSubmit()
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
// Fonction pour forcer la validation de la date de début quand la date de fin change
|
|
1443
|
+
const validateStartDate = () => {
|
|
1444
|
+
if (startDatePickerRef.value && startDate.value) {
|
|
1445
|
+
// On utilise validateOnSubmit pour forcer la validation complète
|
|
1446
|
+
startDatePickerRef.value.validateOnSubmit()
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
// Watcher pour la date de début qui force la revalidation de la date de fin
|
|
1451
|
+
watch(startDate, () => {
|
|
1452
|
+
// Laisser le temps au système de mettre à jour les valeurs
|
|
1453
|
+
setTimeout(() => {
|
|
1454
|
+
validateEndDate()
|
|
1455
|
+
}, 0)
|
|
1456
|
+
})
|
|
1457
|
+
|
|
1458
|
+
// Watcher pour la date de fin qui force la revalidation de la date de début
|
|
1459
|
+
watch(endDate, () => {
|
|
1460
|
+
// Laisser le temps au système de mettre à jour les valeurs
|
|
1461
|
+
setTimeout(() => {
|
|
1462
|
+
validateStartDate()
|
|
1463
|
+
}, 0)
|
|
1464
|
+
})
|
|
1465
|
+
</script>
|
|
1466
|
+
`,
|
|
1467
|
+
},
|
|
1468
|
+
],
|
|
1469
|
+
},
|
|
1470
|
+
render: () => {
|
|
1471
|
+
return {
|
|
1472
|
+
components: { DatePicker },
|
|
1473
|
+
setup() {
|
|
1474
|
+
// Importer le composable useDateFormat depuis useDateFormatDayjs
|
|
1475
|
+
const { parseDate } = useDateFormat()
|
|
1476
|
+
|
|
1477
|
+
// État des dates
|
|
1478
|
+
const startDate = ref<string | null>(null)
|
|
1479
|
+
const endDate = ref<string | null>(null)
|
|
1480
|
+
|
|
1481
|
+
// Références aux composants DatePicker pour accéder à leurs méthodes
|
|
1482
|
+
const startDatePickerRef = ref<InstanceType<typeof DatePicker> | null>(null)
|
|
1483
|
+
const endDatePickerRef = ref<InstanceType<typeof DatePicker> | null>(null)
|
|
1484
|
+
|
|
1485
|
+
// Règle de validation pour vérifier que la date de fin n'est pas avant la date de début
|
|
1486
|
+
const createEndDateValidationRule = () => ({
|
|
1487
|
+
type: 'custom',
|
|
1488
|
+
options: {
|
|
1489
|
+
validate: (value: string) => {
|
|
1490
|
+
// Si pas de valeur pour la date de fin, pas besoin de validation
|
|
1491
|
+
if (!value) return true
|
|
1492
|
+
|
|
1493
|
+
// Si pas de date de début mais une date de fin, afficher l'erreur
|
|
1494
|
+
if (!startDate.value) return 'Veuillez d\'abord sélectionner une date de début'
|
|
1495
|
+
|
|
1496
|
+
const start = parseDate(startDate.value, 'DD/MM/YYYY')
|
|
1497
|
+
const end = parseDate(value, 'DD/MM/YYYY')
|
|
1498
|
+
|
|
1499
|
+
if (!start || !end) return true
|
|
1500
|
+
|
|
1501
|
+
return end >= start || 'La date de fin ne peut pas être antérieure à la date de début'
|
|
1502
|
+
},
|
|
1503
|
+
message: 'La date de fin ne peut pas être antérieure à la date de début',
|
|
1504
|
+
},
|
|
1505
|
+
})
|
|
1506
|
+
|
|
1507
|
+
// Règle de validation pour vérifier que la date de début n'est pas après la date de fin
|
|
1508
|
+
const createStartDateValidationRule = () => ({
|
|
1509
|
+
type: 'custom',
|
|
1510
|
+
options: {
|
|
1511
|
+
validate: (value: string) => {
|
|
1512
|
+
// Si pas de valeur pour la date de début ou pas de date de fin, pas besoin de validation
|
|
1513
|
+
if (!value || !endDate.value) return true
|
|
1514
|
+
|
|
1515
|
+
const start = parseDate(value, 'DD/MM/YYYY')
|
|
1516
|
+
const end = parseDate(endDate.value, 'DD/MM/YYYY')
|
|
1517
|
+
|
|
1518
|
+
if (!start || !end) return true
|
|
1519
|
+
|
|
1520
|
+
return start <= end || 'La date de début ne peut pas être postérieure à la date de fin'
|
|
1521
|
+
},
|
|
1522
|
+
message: 'La date de début ne peut pas être postérieure à la date de fin',
|
|
1523
|
+
},
|
|
1524
|
+
})
|
|
1525
|
+
|
|
1526
|
+
// Règles de validation pour la date de début
|
|
1527
|
+
const startDateRules = computed(() => [
|
|
1528
|
+
{
|
|
1529
|
+
type: 'required',
|
|
1530
|
+
options: {
|
|
1531
|
+
message: 'La date de début est requise.',
|
|
1532
|
+
},
|
|
1533
|
+
},
|
|
1534
|
+
createStartDateValidationRule(),
|
|
1535
|
+
])
|
|
1536
|
+
|
|
1537
|
+
// Règles de validation pour la date de fin
|
|
1538
|
+
const endDateRules = computed(() => [
|
|
1539
|
+
{
|
|
1540
|
+
type: 'required',
|
|
1541
|
+
options: {
|
|
1542
|
+
message: 'La date de fin est requise.',
|
|
1543
|
+
},
|
|
1544
|
+
},
|
|
1545
|
+
createEndDateValidationRule(),
|
|
1546
|
+
])
|
|
1547
|
+
|
|
1548
|
+
// Fonction pour forcer la validation de la date de fin quand la date de début change
|
|
1549
|
+
const validateEndDate = () => {
|
|
1550
|
+
if (endDatePickerRef.value && endDate.value) {
|
|
1551
|
+
// On utilise validateOnSubmit pour forcer la validation complète
|
|
1552
|
+
endDatePickerRef.value.validateOnSubmit()
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
// Fonction pour forcer la validation de la date de début quand la date de fin change
|
|
1557
|
+
const validateStartDate = () => {
|
|
1558
|
+
if (startDatePickerRef.value && startDate.value) {
|
|
1559
|
+
// On utilise validateOnSubmit pour forcer la validation complète
|
|
1560
|
+
startDatePickerRef.value.validateOnSubmit()
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
// Watcher pour la date de début qui force la revalidation de la date de fin
|
|
1565
|
+
watch(startDate, () => {
|
|
1566
|
+
// Laisser le temps au système de mettre à jour les valeurs
|
|
1567
|
+
setTimeout(() => {
|
|
1568
|
+
validateEndDate()
|
|
1569
|
+
}, 0)
|
|
1570
|
+
})
|
|
1571
|
+
|
|
1572
|
+
// Watcher pour la date de fin qui force la revalidation de la date de début
|
|
1573
|
+
watch(endDate, () => {
|
|
1574
|
+
// Laisser le temps au système de mettre à jour les valeurs
|
|
1575
|
+
setTimeout(() => {
|
|
1576
|
+
validateStartDate()
|
|
1577
|
+
}, 0)
|
|
1578
|
+
})
|
|
1579
|
+
|
|
1580
|
+
return {
|
|
1581
|
+
startDate,
|
|
1582
|
+
endDate,
|
|
1583
|
+
startDatePickerRef,
|
|
1584
|
+
endDatePickerRef,
|
|
1585
|
+
startDateRules,
|
|
1586
|
+
endDateRules,
|
|
1587
|
+
validateEndDate,
|
|
1588
|
+
validateStartDate,
|
|
1589
|
+
}
|
|
1590
|
+
},
|
|
1591
|
+
|
|
1592
|
+
template: `
|
|
1593
|
+
<div class="date-validation-playground">
|
|
1594
|
+
<h1>Validation bidirectionnelle des dates</h1>
|
|
1595
|
+
<p class="description">
|
|
1596
|
+
Démonstration de la validation bidirectionnelle entre les DatePickers.
|
|
1597
|
+
Les messages d'erreur apparaissent directement dans les composants.
|
|
1598
|
+
</p>
|
|
1599
|
+
<div class="date-range-container">
|
|
1600
|
+
<div class="date-picker-wrapper">
|
|
1601
|
+
<h3>Date de début</h3>
|
|
1602
|
+
<DatePicker
|
|
1603
|
+
ref="startDatePickerRef"
|
|
1604
|
+
v-model="startDate"
|
|
1605
|
+
placeholder="Date de début"
|
|
1606
|
+
:custom-rules="startDateRules"
|
|
1607
|
+
required
|
|
1608
|
+
@update:model-value="validateEndDate"
|
|
1609
|
+
/>
|
|
1610
|
+
</div>
|
|
1611
|
+
<div class="date-picker-wrapper">
|
|
1612
|
+
<h3>Date de fin</h3>
|
|
1613
|
+
<DatePicker
|
|
1614
|
+
ref="endDatePickerRef"
|
|
1615
|
+
v-model="endDate"
|
|
1616
|
+
placeholder="Date de fin"
|
|
1617
|
+
:custom-rules="endDateRules"
|
|
1618
|
+
required
|
|
1619
|
+
@update:model-value="validateStartDate"
|
|
1620
|
+
/>
|
|
1621
|
+
</div>
|
|
1622
|
+
</div>
|
|
1623
|
+
<div class="current-values">
|
|
1624
|
+
<p><strong>Date de début:</strong> {{ startDate || 'Non sélectionnée' }}</p>
|
|
1625
|
+
<p><strong>Date de fin:</strong> {{ endDate || 'Non sélectionnée' }}</p>
|
|
1626
|
+
</div>
|
|
1627
|
+
</div>
|
|
1628
|
+
`,
|
|
1629
|
+
}
|
|
1630
|
+
},
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1202
1633
|
export const WithFormSubmission: Story = {
|
|
1203
1634
|
parameters: {
|
|
1204
1635
|
sourceCode: [
|
|
@@ -4,9 +4,14 @@
|
|
|
4
4
|
import DateTextInput from './DateTextInput.vue'
|
|
5
5
|
import { VDatePicker } from 'vuetify/components'
|
|
6
6
|
import { useValidation } from '@/composables/validation/useValidation'
|
|
7
|
-
import { useDateFormat } from '@/composables/date/
|
|
8
|
-
import { useDateInitialization, type DateValue, type DateInput } from '@/composables/date/
|
|
7
|
+
import { useDateFormat } from '@/composables/date/useDateFormatDayjs'
|
|
8
|
+
import { useDateInitialization, type DateValue, type DateInput } from '@/composables/date/useDateInitializationDayjs'
|
|
9
9
|
import { useDatePickerAccessibility } from '@/composables/date/useDatePickerAccessibility'
|
|
10
|
+
import dayjs from 'dayjs'
|
|
11
|
+
import customParseFormat from 'dayjs/plugin/customParseFormat'
|
|
12
|
+
|
|
13
|
+
// Initialiser les plugins dayjs
|
|
14
|
+
dayjs.extend(customParseFormat)
|
|
10
15
|
|
|
11
16
|
const { parseDate, formatDate } = useDateFormat()
|
|
12
17
|
const { initializeSelectedDates } = useDateInitialization()
|
|
@@ -93,7 +98,7 @@
|
|
|
93
98
|
// Variable pour éviter les mises à jour récursives
|
|
94
99
|
const isUpdatingFromInternal = ref(false)
|
|
95
100
|
|
|
96
|
-
//
|
|
101
|
+
// Fonction pour valider les dates
|
|
97
102
|
const validateDates = (forceValidation = false) => {
|
|
98
103
|
if (props.noCalendar) {
|
|
99
104
|
// En mode no-calendar, on délègue la validation au DateTextInput
|
|
@@ -320,6 +325,13 @@
|
|
|
320
325
|
}
|
|
321
326
|
})
|
|
322
327
|
|
|
328
|
+
// Fonction pour mettre à jour displayFormattedDate quand le VDatePicker change
|
|
329
|
+
const updateDisplayFormattedDate = () => {
|
|
330
|
+
if (displayFormattedDateComputed.value) {
|
|
331
|
+
displayFormattedDate.value = displayFormattedDateComputed.value
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
323
335
|
const updateSelectedDates = (input: DateValue) => {
|
|
324
336
|
if (Array.isArray(input)) {
|
|
325
337
|
const dates = input
|
|
@@ -354,11 +366,7 @@
|
|
|
354
366
|
}
|
|
355
367
|
|
|
356
368
|
const todayInString = computed(() => {
|
|
357
|
-
return (
|
|
358
|
-
weekday: 'long',
|
|
359
|
-
month: 'long',
|
|
360
|
-
day: 'numeric',
|
|
361
|
-
})).replace(/\b\w/g, l => l.toUpperCase())
|
|
369
|
+
return dayjs().locale('fr').format('dddd D MMMM').replace(/\b\w/g, l => l.toUpperCase())
|
|
362
370
|
})
|
|
363
371
|
|
|
364
372
|
onMounted(() => {
|
|
@@ -377,7 +385,7 @@
|
|
|
377
385
|
document.removeEventListener('click', handleClickOutside)
|
|
378
386
|
})
|
|
379
387
|
|
|
380
|
-
const dateTextInputRef = ref<null | ComponentPublicInstance<
|
|
388
|
+
const dateTextInputRef = ref<null | ComponentPublicInstance<typeof DateTextInput>>()
|
|
381
389
|
const dateCalendarTextInputRef = ref<null | ComponentPublicInstance<typeof SyTextField>>()
|
|
382
390
|
const datePickerRef = ref<null | ComponentPublicInstance<typeof VDatePicker>>()
|
|
383
391
|
|
|
@@ -391,19 +399,10 @@
|
|
|
391
399
|
return errors.value.length === 0
|
|
392
400
|
}
|
|
393
401
|
|
|
394
|
-
const showDatePicker = () => {
|
|
395
|
-
if (props.disabled || props.readonly) return
|
|
396
|
-
|
|
397
|
-
isDatePickerVisible.value = true
|
|
398
|
-
|
|
399
|
-
// Mettre à jour l'accessibilité après l'ouverture du DatePicker
|
|
400
|
-
nextTick(() => {
|
|
401
|
-
updateAccessibility()
|
|
402
|
-
})
|
|
403
|
-
}
|
|
404
|
-
|
|
405
402
|
const openDatePicker = () => {
|
|
406
|
-
|
|
403
|
+
if (!isDatePickerVisible.value) {
|
|
404
|
+
toggleDatePicker()
|
|
405
|
+
}
|
|
407
406
|
}
|
|
408
407
|
|
|
409
408
|
type ViewMode = 'month' | 'year' | 'months' | undefined
|
|
@@ -411,6 +410,10 @@
|
|
|
411
410
|
// Variable pour suivre le mode d'affichage actuel du DatePicker
|
|
412
411
|
const currentViewMode = ref<ViewMode>(props.isBirthDate ? 'year' : 'month')
|
|
413
412
|
|
|
413
|
+
watch(() => props.isBirthDate, (newValue) => {
|
|
414
|
+
currentViewMode.value = newValue ? 'year' : 'month'
|
|
415
|
+
})
|
|
416
|
+
|
|
414
417
|
// Fonction pour gérer le changement de mode d'affichage
|
|
415
418
|
const handleViewModeUpdate = (newMode: ViewMode) => {
|
|
416
419
|
currentViewMode.value = newMode
|
|
@@ -432,6 +435,11 @@
|
|
|
432
435
|
}
|
|
433
436
|
}
|
|
434
437
|
|
|
438
|
+
const handleInputBlur = () => {
|
|
439
|
+
emit('blur')
|
|
440
|
+
validateDates(true)
|
|
441
|
+
}
|
|
442
|
+
|
|
435
443
|
watch(isDatePickerVisible, async (isVisible) => {
|
|
436
444
|
if (!isVisible && props.isBirthDate) {
|
|
437
445
|
// Réinitialiser le mode d'affichage au type birthdate
|
|
@@ -526,6 +534,36 @@
|
|
|
526
534
|
}
|
|
527
535
|
}, { immediate: true })
|
|
528
536
|
|
|
537
|
+
const toggleDatePicker = () => {
|
|
538
|
+
if (props.disabled || props.readonly) return
|
|
539
|
+
|
|
540
|
+
isDatePickerVisible.value = !isDatePickerVisible.value
|
|
541
|
+
|
|
542
|
+
if (isDatePickerVisible.value) {
|
|
543
|
+
// Mettre à jour l'accessibilité après l'ouverture du DatePicker
|
|
544
|
+
nextTick(() => {
|
|
545
|
+
updateAccessibility()
|
|
546
|
+
})
|
|
547
|
+
}
|
|
548
|
+
else {
|
|
549
|
+
emit('closed')
|
|
550
|
+
validateDates()
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
const openDatePickerOnClick = () => {
|
|
555
|
+
openDatePicker()
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
const openDatePickerOnFocus = () => {
|
|
559
|
+
openDatePicker()
|
|
560
|
+
emit('focus')
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
const openDatePickerOnIconClick = () => {
|
|
564
|
+
toggleDatePicker()
|
|
565
|
+
}
|
|
566
|
+
|
|
529
567
|
defineExpose({
|
|
530
568
|
validateOnSubmit,
|
|
531
569
|
isDatePickerVisible,
|
|
@@ -596,6 +634,7 @@
|
|
|
596
634
|
:warning-messages="warningMessages"
|
|
597
635
|
:success-messages="props.showSuccessMessages ? successMessages : []"
|
|
598
636
|
:disabled="props.disabled"
|
|
637
|
+
:disable-click-button="false"
|
|
599
638
|
:readonly="true"
|
|
600
639
|
:label="props.placeholder"
|
|
601
640
|
:no-icon="props.noIcon"
|
|
@@ -606,10 +645,12 @@
|
|
|
606
645
|
:bg-color="props.bgColor"
|
|
607
646
|
is-clearable
|
|
608
647
|
title="Date Picker"
|
|
609
|
-
@
|
|
648
|
+
@click="openDatePickerOnClick"
|
|
649
|
+
@focus="openDatePickerOnFocus"
|
|
650
|
+
@blur="handleInputBlur"
|
|
610
651
|
@update:model-value="updateSelectedDates"
|
|
611
|
-
@prepend-icon-click="
|
|
612
|
-
@append-icon-click="
|
|
652
|
+
@prepend-icon-click="openDatePickerOnIconClick"
|
|
653
|
+
@append-icon-click="openDatePickerOnIconClick"
|
|
613
654
|
/>
|
|
614
655
|
</template>
|
|
615
656
|
<VDatePicker
|
|
@@ -625,6 +666,7 @@
|
|
|
625
666
|
@update:view-mode="handleViewModeUpdate"
|
|
626
667
|
@update:year="handleYearUpdate"
|
|
627
668
|
@update:month="handleMonthUpdate"
|
|
669
|
+
@update:model-value="updateDisplayFormattedDate"
|
|
628
670
|
>
|
|
629
671
|
<template #title>
|
|
630
672
|
Sélectionnez une date
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type Meta, type StoryFn } from '@storybook/vue3'
|
|
2
|
-
import DatePickerValidationExamples from './DatePickerValidationExamples.vue'
|
|
2
|
+
import DatePickerValidationExamples from './docExamples/DatePickerValidationExamples.vue'
|
|
3
|
+
import DatePickerBidirectionalValidation from './docExamples/DatePickerBidirectionalValidation.vue'
|
|
3
4
|
|
|
4
5
|
export default {
|
|
5
6
|
title: 'Composants/Formulaires/DatePicker/Validation',
|
|
@@ -20,3 +21,10 @@ export const ValidationExamples: StoryFn = () => ({
|
|
|
20
21
|
},
|
|
21
22
|
template: '<DatePickerValidationExamples />',
|
|
22
23
|
})
|
|
24
|
+
|
|
25
|
+
export const BidirectionalValidation: StoryFn = () => ({
|
|
26
|
+
components: {
|
|
27
|
+
DatePickerBidirectionalValidation,
|
|
28
|
+
},
|
|
29
|
+
template: '<DatePickerBidirectionalValidation />',
|
|
30
|
+
})
|