@cnamts/synapse 1.0.4 → 1.0.6

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.
Files changed (206) hide show
  1. package/dist/DateFilter-BlOpwEVq.js +98 -0
  2. package/dist/NumberFilter-BPUXE4wY.js +121 -0
  3. package/dist/PeriodFilter-B2yx329_.js +112 -0
  4. package/dist/SelectFilter-CedKn1oV.js +136 -0
  5. package/dist/TextFilter-DkhJjRtR.js +114 -0
  6. package/dist/components/Amelipro/AmeliproAccordion/AmeliproAccordion.d.ts +103 -0
  7. package/dist/components/Amelipro/AmeliproAccordion/AmeliproAccordionTemplate/AmeliproAccordionTemplate.d.ts +105 -0
  8. package/dist/components/Amelipro/AmeliproAutoCompleteField/AmeliproAutoCompleteField.d.ts +3 -3
  9. package/dist/components/Amelipro/AmeliproCaptcha/AmeliproCaptcha.d.ts +132 -0
  10. package/dist/components/Amelipro/AmeliproCaptcha/types.d.ts +5 -0
  11. package/dist/components/Amelipro/AmeliproCard/AmeliproCard.d.ts +3 -3
  12. package/dist/components/Amelipro/AmeliproCustomSelector/AmeliproCustomSelector.d.ts +126 -0
  13. package/dist/components/Amelipro/AmeliproCustomSelector/types.d.ts +6 -0
  14. package/dist/components/Amelipro/AmeliproIllustratedDataTile/AmeliproIllustratedDataTile.d.ts +1 -1
  15. package/dist/components/Amelipro/AmeliproMultipleFoldingCard/AmeliproMultipleFoldingCard.d.ts +1 -1
  16. package/dist/components/Amelipro/AmeliproSelect/AmeliproSelect.d.ts +3 -3
  17. package/dist/components/Amelipro/AmeliproTable/AmeliproTable.d.ts +190 -0
  18. package/dist/components/Amelipro/AmeliproTable/types.d.ts +34 -0
  19. package/dist/components/Amelipro/AmeliproTabs/AmeliproTabs.d.ts +3 -3
  20. package/dist/components/Amelipro/AmeliproTextField/AmeliproTextField.d.ts +1 -1
  21. package/dist/components/Amelipro/AmeliproTileBtn/AmeliproTileBtn.d.ts +1 -1
  22. package/dist/components/Amelipro/types.d.ts +6 -0
  23. package/dist/components/CookieBanner/CookieBanner.d.ts +1 -1
  24. package/dist/components/Customs/Selects/SySelect/SySelect.d.ts +11 -2
  25. package/dist/components/Customs/Selects/SySelect/composables/useSySelectKeyboard.d.ts +6 -1
  26. package/dist/components/Customs/SyTextField/SyTextField.d.ts +3 -1
  27. package/dist/components/DataList/DataList.d.ts +9 -0
  28. package/dist/components/DataListGroup/DataListGroup.d.ts +10 -1
  29. package/dist/components/DataListItem/DataListItem.d.ts +1 -1
  30. package/dist/components/DataListItem/config.d.ts +1 -1
  31. package/dist/components/DatePicker/CalendarMode/DatePicker.d.ts +18 -8
  32. package/dist/components/DatePicker/ComplexDatePicker/ComplexDatePicker.d.ts +16 -6
  33. package/dist/components/DatePicker/DateTextInput/DateTextInput.d.ts +6 -1
  34. package/dist/components/DatePicker/composables/useDateInputEditing.d.ts +17 -8
  35. package/dist/components/DatePicker/composables/useKeyboardEvents.d.ts +41 -0
  36. package/dist/components/DatePicker/composables/useManualDateValidation.d.ts +4 -9
  37. package/dist/components/DatePicker/utils/dateFormattingUtils.d.ts +72 -0
  38. package/dist/components/DatePicker/utils/validationUtils.d.ts +38 -0
  39. package/dist/components/HeaderBar/HeaderBurgerMenu/HeaderBurgerMenu.d.ts +9 -3
  40. package/dist/components/HeaderBar/HeaderBurgerMenu/HeaderMenuItem/HeaderMenuItem.d.ts +6 -1
  41. package/dist/components/HeaderBar/HeaderBurgerMenu/HeaderMenuSection/HeaderMenuSection.d.ts +11 -1
  42. package/dist/components/HeaderBar/HeaderBurgerMenu/HeaderSubMenu/HeaderSubMenu.d.ts +11 -1
  43. package/dist/components/HeaderBar/HeaderBurgerMenu/locals.d.ts +2 -0
  44. package/dist/components/HeaderBar/HeaderBurgerMenu/useMenuPosition.d.ts +4 -0
  45. package/dist/components/NirField/NirField.d.ts +14 -4
  46. package/dist/components/PeriodField/PeriodField.d.ts +24 -4
  47. package/dist/components/Tables/common/SyTablePagination.d.ts +10 -0
  48. package/dist/components/index.d.ts +4 -0
  49. package/dist/composables/index.d.ts +1 -0
  50. package/dist/composables/usePagination.d.ts +16 -0
  51. package/dist/design-system-v3.js +165 -160
  52. package/dist/design-system-v3.umd.cjs +120 -138
  53. package/dist/directives/lockFocus.d.ts +17 -0
  54. package/dist/{main-BzyNNvHX.js → main-BXPFSAB4.js} +14664 -13282
  55. package/dist/style.css +1 -0
  56. package/package.json +5 -2
  57. package/src/assets/amelipro/apTheme.scss +149 -0
  58. package/src/assets/amelipro/apTokens.scss +0 -148
  59. package/src/assets/overrides/_btns.scss +15 -0
  60. package/src/assets/overrides/_container.scss +36 -0
  61. package/src/assets/overrides/_forms.scss +7 -0
  62. package/src/assets/{_spacers.scss → overrides/_spacers.scss} +0 -7
  63. package/src/assets/overrides/_tables.scss +18 -0
  64. package/src/assets/overrides/_tooltips.scss +10 -0
  65. package/src/assets/overrides/_typography.scss +196 -0
  66. package/src/assets/settings.scss +11 -51
  67. package/src/assets/themes.scss +10 -0
  68. package/src/assets/tokens.scss +9 -156
  69. package/src/components/Accordion/composables/__tests__/useAccordionGroupCommunication.spec.ts +80 -40
  70. package/src/components/Amelipro/AmeliproAccordion/AmeliproAccordion.mdx +15 -0
  71. package/src/components/Amelipro/AmeliproAccordion/AmeliproAccordion.stories.ts +83 -0
  72. package/src/components/Amelipro/AmeliproAccordion/AmeliproAccordion.vue +86 -0
  73. package/src/components/Amelipro/AmeliproAccordion/AmeliproAccordionTemplate/AmeliproAccordionTemplate.vue +242 -0
  74. package/src/components/Amelipro/AmeliproAccordion/AmeliproAccordionTemplate/__tests__/AmeliproAccordionTemplate.spec.ts +20 -0
  75. package/src/components/Amelipro/AmeliproAccordion/AmeliproAccordionTemplate/__tests__/__snapshots__/AmeliproAccordionTemplate.spec.ts.snap +124 -0
  76. package/src/components/Amelipro/AmeliproAccordion/__tests__/AmeliproAccordion.spec.ts +20 -0
  77. package/src/components/Amelipro/AmeliproAccordion/__tests__/__snapshots__/AmeliproAccordion.spec.ts.snap +124 -0
  78. package/src/components/Amelipro/AmeliproCaptcha/AmeliproCaptcha.mdx +15 -0
  79. package/src/components/Amelipro/AmeliproCaptcha/AmeliproCaptcha.stories.ts +87 -0
  80. package/src/components/Amelipro/AmeliproCaptcha/AmeliproCaptcha.vue +233 -0
  81. package/src/components/Amelipro/AmeliproCaptcha/__tests__/AmeliproCaptcha.spec.ts +24 -0
  82. package/src/components/Amelipro/AmeliproCaptcha/__tests__/__snapshots__/AmeliproCaptcha.spec.ts.snap +384 -0
  83. package/src/components/Amelipro/AmeliproCaptcha/types.d.ts +5 -0
  84. package/src/components/Amelipro/AmeliproCustomSelector/AmeliproCustomSelector.mdx +15 -0
  85. package/src/components/Amelipro/AmeliproCustomSelector/AmeliproCustomSelector.stories.ts +143 -0
  86. package/src/components/Amelipro/AmeliproCustomSelector/AmeliproCustomSelector.vue +351 -0
  87. package/src/components/Amelipro/AmeliproCustomSelector/__tests__/AmeliproCustomSelector.spec.ts +50 -0
  88. package/src/components/Amelipro/AmeliproCustomSelector/__tests__/__snapshots__/AmeliproCustomSelector.spec.ts.snap +186 -0
  89. package/src/components/Amelipro/AmeliproCustomSelector/types.d.ts +6 -0
  90. package/src/components/Amelipro/AmeliproHeader/AmeliproHeaderBar/AmeliproHeaderBrandSection/tests/__snapshots__/AmeliproHeaderBrandSection.spec.ts.snap +1 -1
  91. package/src/components/Amelipro/AmeliproHeader/AmeliproHeaderBar/tests/__snapshots__/AmeliproHeaderBar.spec.ts.snap +1 -1
  92. package/src/components/Amelipro/AmeliproHeader/tests/__snapshots__/AmeliproHeader.spec.ts.snap +1 -708
  93. package/src/components/Amelipro/AmeliproMenu/tests/__snapshots__/AmeliproMenu.spec.ts.snap +1 -1
  94. package/src/components/Amelipro/AmeliproPageLayout/tests/__snapshots__/AmeliproPageLayout.spec.ts.snap +1 -708
  95. package/src/components/Amelipro/AmeliproTable/AmeliproTable.mdx +22 -0
  96. package/src/components/Amelipro/AmeliproTable/AmeliproTable.stories.ts +550 -0
  97. package/src/components/Amelipro/AmeliproTable/AmeliproTable.vue +421 -0
  98. package/src/components/Amelipro/AmeliproTable/__tests__/AmeliproTable.spec.ts +72 -0
  99. package/src/components/Amelipro/AmeliproTable/__tests__/__snapshots__/AmeliproTable.spec.ts.snap +427 -0
  100. package/src/components/Amelipro/AmeliproTable/types.d.ts +34 -0
  101. package/src/components/Amelipro/ServiceMenu/ServiceMenu.vue +12 -1
  102. package/src/components/Amelipro/ServiceMenu/tests/__snapshots__/ServiceMenu.spec.ts.snap +0 -820
  103. package/src/components/Amelipro/types.ts +8 -0
  104. package/src/components/CollapsibleList/CollapsibleList.vue +0 -2
  105. package/src/components/CookieBanner/CookieBanner.vue +1 -3
  106. package/src/components/CopyBtn/CopyBtn.vue +9 -2
  107. package/src/components/CopyBtn/tests/CopyBtn.spec.ts +3 -1
  108. package/src/components/Customs/Selects/SySelect/Accessibilite.mdx +7 -0
  109. package/src/components/Customs/Selects/SySelect/Accessibilite.stories.ts +4 -1
  110. package/src/components/Customs/Selects/SySelect/SySelect.stories.ts +80 -0
  111. package/src/components/Customs/Selects/SySelect/SySelect.vue +280 -34
  112. package/src/components/Customs/Selects/SySelect/composables/tests/useSySelectKeyboard.spec.ts +14 -5
  113. package/src/components/Customs/Selects/SySelect/composables/useSySelectKeyboard.ts +129 -12
  114. package/src/components/Customs/SyIcon/SyIcon.spec.ts +3 -0
  115. package/src/components/Customs/SyTextField/Accessibilite.stories.ts +3 -1
  116. package/src/components/Customs/SyTextField/SyTextField.stories.ts +79 -6
  117. package/src/components/Customs/SyTextField/SyTextField.vue +218 -24
  118. package/src/components/DataList/Accessibilite.stories.ts +4 -0
  119. package/src/components/DataList/DataList.vue +19 -12
  120. package/src/components/DataListGroup/Accessibilite.stories.ts +4 -0
  121. package/src/components/DataListGroup/DataListGroup.vue +32 -15
  122. package/src/components/DataListItem/DataListItem.vue +14 -11
  123. package/src/components/DataListItem/config.ts +1 -1
  124. package/src/components/DataListItem/tests/DataListItem.spec.ts +2 -2
  125. package/src/components/DatePicker/CalendarMode/DatePicker.vue +12 -7
  126. package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.stories.ts +174 -0
  127. package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.vue +27 -5
  128. package/src/components/DatePicker/DatePickerValidationExample/DatePickerValidation.stories.ts +286 -0
  129. package/src/components/DatePicker/DateTextInput/DateRange.stories.ts +1 -1
  130. package/src/components/DatePicker/DateTextInput/DateTextInput.vue +29 -31
  131. package/src/components/DatePicker/composables/tests/useManualDateValidation.spec.ts +11 -3
  132. package/src/components/DatePicker/composables/useDateInputEditing.ts +73 -209
  133. package/src/components/DatePicker/composables/useKeyboardEvents.ts +149 -0
  134. package/src/components/DatePicker/composables/useManualDateValidation.ts +27 -68
  135. package/src/components/DatePicker/utils/dateFormattingUtils.ts +228 -0
  136. package/src/components/DatePicker/utils/validationUtils.ts +90 -0
  137. package/src/components/DialogBox/Accessibilite.stories.ts +4 -0
  138. package/src/components/DialogBox/DialogBox.stories.ts +10 -10
  139. package/src/components/DialogBox/DialogBox.vue +83 -21
  140. package/src/components/DialogBox/tests/__snapshots__/DialogBox.spec.ts.snap +12 -6
  141. package/src/components/FileUpload/tests/FileUpload.spec.ts +3 -0
  142. package/src/components/FooterBar/FooterBar.vue +1 -0
  143. package/src/components/HeaderBar/Accessibilite.stories.ts +4 -0
  144. package/src/components/HeaderBar/HeaderBar.mdx +47 -22
  145. package/src/components/HeaderBar/HeaderBar.stories.ts +54 -13
  146. package/src/components/HeaderBar/HeaderBar.vue +2 -1
  147. package/src/components/HeaderBar/HeaderBurgerMenu/Accessibilite.stories.ts +4 -0
  148. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderBurgerMenu.stories.ts +160 -82
  149. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderBurgerMenu.vue +41 -56
  150. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuItem/HeaderMenuItem.vue +10 -3
  151. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuSection/HeaderMenuSection.vue +41 -18
  152. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuSection/tests/HeaderMenuSection.spec.ts +7 -2
  153. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderSubMenu/HeaderSubMenu.stories.ts +36 -9
  154. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderSubMenu/HeaderSubMenu.vue +41 -9
  155. package/src/components/HeaderBar/HeaderBurgerMenu/locals.ts +2 -0
  156. package/src/components/HeaderBar/HeaderBurgerMenu/tests/HeaderBurgerMenu.spec.ts +1 -1
  157. package/src/components/HeaderBar/HeaderBurgerMenu/tests/__snapshots__/HeaderBurgerMenu.spec.ts.snap +8 -3
  158. package/src/components/HeaderBar/HeaderBurgerMenu/useMenuPosition.ts +50 -0
  159. package/src/components/HeaderBar/HeaderLogo/HeaderLogo.vue +5 -5
  160. package/src/components/HeaderBar/HeaderMenuBtn/HeaderMenuBtn.vue +7 -4
  161. package/src/components/HeaderBar/locales.ts +1 -1
  162. package/src/components/HeaderBar/tests/__snapshots__/HeaderBar.spec.ts.snap +2 -1
  163. package/src/components/HeaderLoading/HeaderLoading.vue +0 -1
  164. package/src/components/HeaderNavigationBar/tests/HeaderNavigationBar.spec.ts +2 -0
  165. package/src/components/LangBtn/LangBtn.vue +0 -3
  166. package/src/components/LogoBrandSection/Accessibilite.stories.ts +4 -1
  167. package/src/components/LogoBrandSection/LogoBrandSection.stories.ts +2 -2
  168. package/src/components/LogoBrandSection/LogoBrandSection.vue +13 -8
  169. package/src/components/LogoBrandSection/locales.ts +1 -1
  170. package/src/components/LogoBrandSection/tests/LogoBrandSection.spec.ts +1 -1
  171. package/src/components/LogoBrandSection/tests/__snapshots__/LogoBrandSection.spec.ts.snap +6 -4
  172. package/src/components/NirField/NirField.vue +5 -5
  173. package/src/components/NirField/tests/NirField.spec.ts +78 -12
  174. package/src/components/Tables/SyServerTable/tests/SyServerTable.spec.ts +104 -6
  175. package/src/components/Tables/common/TableHeader.vue +10 -7
  176. package/src/components/Tables/common/tableAccessibilityUtils.ts +13 -2
  177. package/src/components/Tables/common/useTableAria.ts +17 -1
  178. package/src/components/UserMenuBtn/tests/UserMenuBtn.spec.ts +2 -1
  179. package/src/components/index.ts +4 -0
  180. package/src/composables/date/tests/useDatePickerAccessibility.spec.ts +34 -5
  181. package/src/composables/index.ts +3 -0
  182. package/src/composables/useFilterable/useFilterable.ts +13 -1
  183. package/src/composables/usePagination.ts +103 -0
  184. package/src/directives/lockFocus.ts +48 -0
  185. package/src/main.ts +1 -2
  186. package/src/stories/Accessibilite/Aculturation/SensibilisationAccessibilite.mdx +1 -8
  187. package/src/stories/Accessibilite/{Aculturation/AuditDesignSystem.mdx → AuditDesignSystem.mdx} +1 -1
  188. package/src/stories/Accessibilite/KitDePreAudit/Outils/Tanaguru/FauxPositifs.mdx +102 -0
  189. package/src/stories/Accessibilite/KitDePreAudit/Outils/Tanaguru/FauxPositifs.stories.ts +219 -0
  190. package/src/stories/Accessibilite/KitDePreAudit/Outils/{Tanaguru.mdx → Tanaguru/Utilisation.mdx} +1 -1
  191. package/src/stories/DesignTokens/ColorIntegrationExample.vue +43 -0
  192. package/src/stories/DesignTokens/Colors.mdx +2 -0
  193. package/src/stories/DesignTokens/colors.stories.ts +9 -0
  194. package/src/vuetifyConfig.ts +3 -3
  195. package/dist/DateFilter-yrwJv_2R.js +0 -95
  196. package/dist/NumberFilter-BQXtywZI.js +0 -117
  197. package/dist/PeriodFilter-BYXVSzr5.js +0 -108
  198. package/dist/SelectFilter-CJV_mlN3.js +0 -133
  199. package/dist/TextFilter-DN0ejYIs.js +0 -110
  200. package/dist/design-system-v3.css +0 -1
  201. package/dist/directives/letterSpacing.d.ts +0 -27
  202. package/src/assets/_fonts.scss +0 -6
  203. package/src/assets/_typography.scss +0 -157
  204. package/src/directives/letterSpacing.ts +0 -233
  205. /package/src/assets/{_elevations.scss → overrides/_elevations.scss} +0 -0
  206. /package/src/assets/{_radius.scss → overrides/_radius.scss} +0 -0
@@ -1305,3 +1305,177 @@ export const WithFormSubmission: Story = {
1305
1305
  }
1306
1306
  },
1307
1307
  }
1308
+
1309
+ export const CustomRules: Story = {
1310
+ parameters: {
1311
+ sourceCode: [
1312
+ {
1313
+ name: 'Template',
1314
+ code: `
1315
+ <template>
1316
+ <DatePicker
1317
+ v-model="date"
1318
+ placeholder="Date requise"
1319
+ format="DD/MM/YYYY"
1320
+ required
1321
+ class="mb-4"
1322
+ useCombinedMode
1323
+ :customRules="customRules"
1324
+ />
1325
+ </template>
1326
+ `,
1327
+ },
1328
+ {
1329
+ name: 'Script',
1330
+ code: `
1331
+ <script setup lang="ts">
1332
+ import { DatePicker } from '@cnamts/synapse'
1333
+ import { ref } from 'vue'
1334
+
1335
+ const date = ref('')
1336
+
1337
+ const customRules = [
1338
+ {
1339
+ type: 'notBeforeToday',
1340
+ options: {
1341
+ message: 'La date ne peut pas être antérieure à aujourd'hui',
1342
+ },
1343
+ },
1344
+ ]
1345
+ </script>
1346
+ `,
1347
+ },
1348
+ ],
1349
+ },
1350
+ render: () => {
1351
+ return {
1352
+ components: { DatePicker },
1353
+ setup() {
1354
+ const customRules = [
1355
+ {
1356
+ type: 'notBeforeToday',
1357
+ options: {
1358
+ message: 'La date ne peut pas être antérieure à aujourd\'hui',
1359
+ },
1360
+ },
1361
+ ]
1362
+
1363
+ // Valeur du DatePicker
1364
+ const date = ref(null)
1365
+
1366
+ return { date, customRules }
1367
+ },
1368
+ template: `
1369
+ <div class="d-flex flex-wrap align-center pa-4">
1370
+ <DatePicker
1371
+ v-model="date"
1372
+ :custom-rules="customRules"
1373
+ required
1374
+ use-combined-mode
1375
+ label="Date de rendez-vous"
1376
+ placeholder="JJ/MM/AAAA"
1377
+ />
1378
+ </div>
1379
+ `,
1380
+ }
1381
+ },
1382
+ }
1383
+
1384
+ export const CustomWarningRules: Story = {
1385
+ parameters: {
1386
+ sourceCode: [
1387
+ {
1388
+ name: 'Template',
1389
+ code: `
1390
+ <template>
1391
+ <DatePicker
1392
+ v-model="date"
1393
+ placeholder="Date requise"
1394
+ format="DD/MM/YYYY"
1395
+ required
1396
+ class="mb-4"
1397
+ useCombinedMode
1398
+ :customWarningRules="customWarningRules"
1399
+ />
1400
+ </template>
1401
+ `,
1402
+ },
1403
+ {
1404
+ name: 'Script',
1405
+ code: `
1406
+ <script setup lang="ts">
1407
+ import { DatePicker } from '@cnamts/synapse'
1408
+ import { ref } from 'vue'
1409
+
1410
+ const date = ref('')
1411
+ const customWarningRules = [
1412
+ {
1413
+ type: 'custom',
1414
+ options: {
1415
+ validate: (value: string | Date) => {
1416
+ // check if manual entry
1417
+ if (typeof value === 'string') {
1418
+ return !value.includes('2025')
1419
+ } else {
1420
+ // check if DatePicker selection
1421
+ return !value.getFullYear().toString().includes('2025')
1422
+ }
1423
+ },
1424
+ warningMessage: 'Les dates en 2025 ne sont pas autorisées',
1425
+ successMessage: 'Date hors 2025',
1426
+ fieldIdentifier: 'date',
1427
+ },
1428
+ },
1429
+ ]
1430
+ </script>
1431
+ `,
1432
+ },
1433
+ ],
1434
+ },
1435
+ render: () => {
1436
+ return {
1437
+ components: { DatePicker },
1438
+ setup() {
1439
+ const customWarningRules = [
1440
+ {
1441
+ type: 'custom',
1442
+ options: {
1443
+ validate: (value: string | Date) => {
1444
+ // check typeof value
1445
+ if (typeof value === 'string') {
1446
+ return !value.includes('2025')
1447
+ }
1448
+ else {
1449
+ // check if value is a Date
1450
+ return !value.getFullYear().toString().includes('2025')
1451
+ }
1452
+ },
1453
+ warningMessage: 'Les dates en 2025 ne sont pas autorisées',
1454
+ successMessage: 'Date hors 2025',
1455
+ fieldIdentifier: 'date',
1456
+ isWarning: true,
1457
+ },
1458
+ },
1459
+ ]
1460
+
1461
+ // Valeur du DatePicker
1462
+ const date = ref('')
1463
+
1464
+ return { date, customWarningRules }
1465
+ },
1466
+ template: `
1467
+ <div class="d-flex flex-wrap align-center pa-4">
1468
+ <DatePicker
1469
+ v-model="date"
1470
+ :custom-warning-rules="customWarningRules"
1471
+ required
1472
+ use-combined-mode
1473
+ label="Date de rendez-vous"
1474
+ placeholder="JJ/MM/AAAA"
1475
+ />
1476
+ </div>
1477
+ `,
1478
+ }
1479
+ },
1480
+
1481
+ }
@@ -339,7 +339,27 @@
339
339
  // Assignation des fonctions et variables retournées par le composable
340
340
  // Utiliser une fonction pour wrapper updateSelectedDates afin de maintenir la compatibilité avec le template
341
341
  const updateSelectedDates = (date: Date | null) => {
342
+ // Avant de mettre à jour la date, vérifier qu'elle est valide selon nos règles personnalisées
343
+ if (date !== null) {
344
+ // Appliquer les règles personnalisées directement à la date sélectionnée
345
+ const validationResult = validateField(date, props.customRules, props.customWarningRules)
346
+
347
+ // Si la date est invalide selon nos règles, ne pas mettre à jour et afficher l'erreur
348
+ if (validationResult.hasError) {
349
+ // Mettre à jour les messages d'erreur
350
+ errors.value = validationResult.state.errors
351
+ return // Ne pas continuer la mise à jour
352
+ }
353
+ }
354
+
355
+ // Si la date est valide ou null, on poursuit normalement
342
356
  dateSelectionResult.updateSelectedDates(date)
357
+
358
+ // Forcer une validation immédiate après la mise à jour des dates
359
+ // pour s'assurer que les messages s'affichent
360
+ setTimeout(() => {
361
+ validateDates(true)
362
+ }, 0)
343
363
  }
344
364
  // generateDateRange est maintenant utilisé via le composable useInputHandler
345
365
  // Synchroniser notre référence locale avec celle du composable
@@ -654,7 +674,7 @@
654
674
  }
655
675
 
656
676
  // Si c'est une valeur string (venant du DateTextInput)
657
- const inputElement = dateCalendarTextInputRef.value?.$el?.querySelector('input')
677
+ const inputElement = dateCalendarTextInputRef.value?.$el?.querySelector?.('input')
658
678
  if (!inputElement) return
659
679
 
660
680
  // Mettre à jour la valeur du modèle directement
@@ -756,9 +776,9 @@
756
776
 
757
777
  // set the focus on the date picker
758
778
  await nextTick()
759
- const firstButton = datePickerRef.value?.$el.querySelector('button')
779
+ const firstButton = datePickerRef.value?.$el?.querySelector?.('button')
760
780
  if (firstButton) {
761
- firstButton.focus()
781
+ firstButton.focus({ preventScroll: true })
762
782
  }
763
783
  }
764
784
  else {
@@ -766,9 +786,9 @@
766
786
  // wait for VMenu to finish DOM updates & transition
767
787
  setTimeout(() => {
768
788
  requestAnimationFrame(() => {
769
- const inputElement = dateCalendarTextInputRef.value?.$el?.querySelector('input')
789
+ const inputElement = dateCalendarTextInputRef.value?.$el?.querySelector?.('input')
770
790
  if (inputElement) {
771
- inputElement.focus()
791
+ inputElement.focus({ preventScroll: true })
772
792
  isDatePickerVisible.value = false
773
793
  }
774
794
  })
@@ -1178,6 +1198,8 @@
1178
1198
  :view-mode="currentViewMode"
1179
1199
  :max="maxDate"
1180
1200
  :min="minDate"
1201
+ :custom-rules="props.customRules"
1202
+ :custom-warning-rules="props.customWarningRules"
1181
1203
  :display-holiday-days="props.displayHolidayDays"
1182
1204
  :display-asterisk="props.displayAsterisk"
1183
1205
  @update:model-value="updateDisplayFormattedDate"
@@ -22,9 +22,295 @@ export const ValidationExamples: StoryFn = () => ({
22
22
  template: '<DatePickerValidationExamples />',
23
23
  })
24
24
 
25
+ ValidationExamples.parameters = {
26
+ sourceCode: [
27
+ {
28
+ name: 'Template',
29
+ code: `
30
+ <template>
31
+ <div class="date-picker-validation-examples">
32
+ <h1 class="text-h5 mb-6">
33
+ Exemples de validation du DatePicker
34
+ </h1>
35
+
36
+ <!-- Exemple 1: Validation de base (required) -->
37
+ <section class="mb-10">
38
+ <h2 class="text-h6 mb-3">
39
+ Validation de base (required)
40
+ </h2>
41
+ <div class="mb-2">
42
+ <DatePicker
43
+ v-model="date1"
44
+ placeholder="Date requise"
45
+ required
46
+ />
47
+ </div>
48
+ <v-btn
49
+ size="small"
50
+ color="primary"
51
+ @click="date1 = ''"
52
+ >
53
+ Vider le champ
54
+ </v-btn>
55
+ <v-btn
56
+ size="small"
57
+ class="ml-2"
58
+ @click="date1 = today"
59
+ >
60
+ Remplir le champ
61
+ </v-btn>
62
+ <div class="mt-2">
63
+ Valeur actuelle: {{ date1 }}
64
+ </div>
65
+ </section>
66
+
67
+ <!-- Autres exemples de validation -->
68
+ </div>
69
+ </template>
70
+ `,
71
+ },
72
+ {
73
+ name: 'Script',
74
+ code: `
75
+ <script setup>
76
+ import { ref } from 'vue'
77
+ import DatePicker from '@/components/DatePicker/CalendarMode/DatePicker.vue'
78
+
79
+ // Exemple 1: Validation de base (required)
80
+ const date1 = ref('')
81
+
82
+ // Exemple 2: notWeekend
83
+ const date2 = ref('')
84
+
85
+ // Exemple 3: notAfterToday
86
+ const date3 = ref('')
87
+
88
+ // Exemple 4: notBeforeToday
89
+ const date4 = ref('')
90
+
91
+ // Exemple 5: notBeforeDate
92
+ const date5 = ref('')
93
+
94
+ // Exemple 6: notAfterDate
95
+ const date6 = ref('')
96
+
97
+ // Exemple 7: dateExact
98
+ const date7 = ref('')
99
+
100
+ // Exemple 8: customRules (règle personnalisée)
101
+ const date8 = ref('')
102
+
103
+ // Exemple 9: customWarningRules
104
+ const date9 = ref('')
105
+
106
+ // Exemple 10: Combinaison de plusieurs règles
107
+ const date10 = ref('')
108
+
109
+ const today = new Date().toLocaleDateString('fr-FR', {
110
+ day: '2-digit',
111
+ month: '2-digit',
112
+ year: 'numeric',
113
+ })
114
+ const tomorrow = new Date(Date.now() + 86400000).toLocaleDateString('fr-FR', {
115
+ day: '2-digit',
116
+ month: '2-digit',
117
+ year: 'numeric',
118
+ })
119
+ const yesterday = new Date(Date.now() - 86400000).toLocaleDateString('fr-FR', {
120
+ day: '2-digit',
121
+ month: '2-digit',
122
+ year: 'numeric',
123
+ })
124
+ </script>
125
+ `,
126
+ },
127
+ ],
128
+ }
129
+
25
130
  export const BidirectionalValidation: StoryFn = () => ({
26
131
  components: {
27
132
  DatePickerBidirectionalValidation,
28
133
  },
29
134
  template: '<DatePickerBidirectionalValidation />',
30
135
  })
136
+
137
+ BidirectionalValidation.parameters = {
138
+ sourceCode: [
139
+ {
140
+ name: 'Template',
141
+ code: `
142
+ <template>
143
+ <div class="date-picker-bidirectional-validation">
144
+ <h1 class="text-h5 mb-6">
145
+ Validation bidirectionnelle entre deux DatePickers
146
+ </h1>
147
+
148
+ <div class="text-body-2 mb-4">
149
+ Ce composant démontre la validation bidirectionnelle entre deux DatePickers. Les règles de validation sont appliquées dans les deux sens :
150
+ <ul class="ml-4">
151
+ <li>La date de fin doit être postérieure ou égale à la date de début</li>
152
+ <li>La date de début doit être antérieure ou égale à la date de fin</li>
153
+ <li>Lorsque la date de début change, la validation de la date de fin est mise à jour</li>
154
+ <li>Lorsque la date de fin change, la validation de la date de début est mise à jour</li>
155
+ </ul>
156
+ </div>
157
+
158
+ <div class="date-range-container mb-6">
159
+ <div class="date-picker-wrapper">
160
+ <h3 class="text-subtitle-1 mb-2">
161
+ Date de début
162
+ </h3>
163
+ <DatePicker
164
+ ref="startDatePickerRef"
165
+ v-model="startDate"
166
+ placeholder="Date de début"
167
+ :custom-rules="startDateRules"
168
+ required
169
+ @update:model-value="validateEndDate"
170
+ />
171
+ </div>
172
+ <div class="date-picker-wrapper">
173
+ <h3 class="text-subtitle-1 mb-2">
174
+ Date de fin
175
+ </h3>
176
+ <DatePicker
177
+ ref="endDatePickerRef"
178
+ v-model="endDate"
179
+ placeholder="Date de fin"
180
+ :custom-rules="endDateRules"
181
+ required
182
+ @update:model-value="validateStartDate"
183
+ />
184
+ </div>
185
+ </div>
186
+
187
+ <div class="actions mb-4">
188
+ <v-btn
189
+ size="small"
190
+ color="primary"
191
+ class="mr-2"
192
+ @click="resetDates"
193
+ >
194
+ Réinitialiser
195
+ </v-btn>
196
+
197
+ <v-btn
198
+ size="small"
199
+ color="success"
200
+ class="mr-2"
201
+ @click="setTestDates"
202
+ >
203
+ Dates valides
204
+ </v-btn>
205
+
206
+ <v-btn
207
+ size="small"
208
+ color="error"
209
+ @click="setInvalidDates"
210
+ >
211
+ Dates invalides
212
+ </v-btn>
213
+ </div>
214
+
215
+ <div class="current-values mt-4">
216
+ <p><strong>Date de début :</strong> {{ startDate || 'Non sélectionnée' }}</p>
217
+ <p><strong>Date de fin :</strong> {{ endDate || 'Non sélectionnée' }}</p>
218
+ </div>
219
+ </div>
220
+ </template>
221
+ `,
222
+ },
223
+ {
224
+ name: 'Script',
225
+ code: `
226
+ <script lang="ts" setup>
227
+ import { ref, computed, watch } from 'vue'
228
+ import DatePicker from '@/components/DatePicker/CalendarMode/DatePicker.vue'
229
+ import { useDateFormat } from '@/composables/date/useDateFormat'
230
+
231
+ const { parseDate } = useDateFormat()
232
+
233
+ // État des dates
234
+ const startDate = ref<string | null>(null)
235
+ const endDate = ref<string | null>(null)
236
+
237
+ // Références aux composants CalendarMode pour accéder à leurs méthodes
238
+ const startDatePickerRef = ref<InstanceType<typeof DatePicker> | null>(null)
239
+ const endDatePickerRef = ref<InstanceType<typeof DatePicker> | null>(null)
240
+
241
+ // Règle de validation pour vérifier que la date de fin n'est pas avant la date de début
242
+ const createEndDateValidationRule = () => ({
243
+ type: 'custom',
244
+ options: {
245
+ validate: (value: string) => {
246
+ // Si pas de valeur pour la date de fin, pas besoin de validation
247
+ if (!value) return true
248
+
249
+ // Si pas de date de début mais une date de fin, afficher l'erreur
250
+ if (!startDate.value) return 'Veuillez d'abord sélectionner une date de début'
251
+
252
+ const start = parseDate(startDate.value, 'DD/MM/YYYY')
253
+ const end = parseDate(value, 'DD/MM/YYYY')
254
+
255
+ if (!start || !end) return true
256
+
257
+ return end >= start || 'La date de fin ne peut pas être antérieure à la date de début'
258
+ },
259
+ message: 'La date de fin ne peut pas être antérieure à la date de début',
260
+ },
261
+ }))
262
+
263
+ // Règles de validation et méthodes additionnelles
264
+ // ...
265
+
266
+ // Fonctions pour la démonstration
267
+ const setTestDates = () => {
268
+ // Définir dates valides (aujourd'hui et demain)
269
+ }
270
+
271
+ const setInvalidDates = () => {
272
+ // Définir dates invalides (aujourd'hui et hier)
273
+ }
274
+
275
+ const resetDates = () => {
276
+ startDate.value = null
277
+ endDate.value = null
278
+ }
279
+ </script>
280
+ `,
281
+ },
282
+ {
283
+ name: 'Style',
284
+ code: `
285
+ <style scoped>
286
+ .date-picker-bidirectional-validation {
287
+ padding: 20px;
288
+ max-width: 800px;
289
+ margin: 0 auto;
290
+ }
291
+
292
+ .date-range-container {
293
+ display: flex;
294
+ gap: 20px;
295
+ }
296
+
297
+ .date-picker-wrapper {
298
+ flex: 1;
299
+ }
300
+
301
+ .actions {
302
+ display: flex;
303
+ flex-wrap: wrap;
304
+ gap: 8px;
305
+ }
306
+
307
+ .current-values {
308
+ padding: 15px;
309
+ background-color: #f5f5f5;
310
+ border-radius: 4px;
311
+ }
312
+ </style>
313
+ `,
314
+ },
315
+ ],
316
+ }
@@ -241,7 +241,7 @@ export const WithInitialValue: Story = {
241
241
  'onClosed': fn(),
242
242
  },
243
243
  render(args) {
244
- const dateRange = ref<string | null>('01/06/2025 - 30/06/2025')
244
+ const dateRange = ref<string | [string, string] | null>('01/06/2025 - 30/06/2025')
245
245
  return {
246
246
  components: { DatePicker },
247
247
  setup() {
@@ -3,6 +3,7 @@
3
3
  import { nextTick } from 'vue'
4
4
  import SyTextField from '../../Customs/SyTextField/SyTextField.vue'
5
5
  import { useValidation, type ValidationRule, type ValidationResult } from '@/composables/validation/useValidation'
6
+ import { type CustomRule } from '../utils/validationUtils'
6
7
  import dayjs from 'dayjs'
7
8
  import customParseFormat from 'dayjs/plugin/customParseFormat'
8
9
  import { useDateRangeInput, useDateRangeValidation, useDateFormatValidation, useDateValidation, useDateInputEditing, useManualDateValidation, useDateAutoClamp } from '../composables'
@@ -252,8 +253,8 @@
252
253
  format: props.format,
253
254
  required: props.required,
254
255
  disableErrorHandling: props.disableErrorHandling,
255
- customRules: props.customRules,
256
- customWarningRules: props.customWarningRules,
256
+ customRules: props.customRules as CustomRule[],
257
+ customWarningRules: props.customWarningRules as CustomRule[],
257
258
  hasInteracted,
258
259
  errors,
259
260
  clearValidation,
@@ -477,7 +478,7 @@
477
478
  }
478
479
  }
479
480
 
480
- const input = inputRef.value?.$el.querySelector('input')
481
+ const input = inputRef.value?.$el?.querySelector?.('input')
481
482
  const cursorPos = input?.selectionStart || 0
482
483
 
483
484
  // Utiliser le composable de plage de dates si le mode plage est activé
@@ -545,21 +546,8 @@
545
546
  // Si la plage est complète (deux dates)
546
547
  if (result.isComplete && result.dates[1]) {
547
548
  const [startDate, endDate] = result.dates
548
-
549
549
  // Vérifier si la plage est valide
550
- if (isValidRange(startDate, endDate)) {
551
- // Formater les dates pour le modèle
552
- const returnFormat = props.dateFormatReturn || props.format
553
- const modelValue: [string, string] = [
554
- formatDate(startDate, returnFormat),
555
- formatDate(endDate, returnFormat),
556
- ]
557
-
558
- // Émettre les événements
559
- emit('update:model-value', modelValue)
560
- emit('date-selected', modelValue)
561
- }
562
- else {
550
+ if (!isValidRange(startDate, endDate)) {
563
551
  errors.value.push(DATE_PICKER_MESSAGES.ERROR_END_BEFORE_START)
564
552
  }
565
553
  }
@@ -571,9 +559,6 @@
571
559
 
572
560
  // Émettre l'événement date-selected pour la première date
573
561
  emit('date-selected', formattedDate)
574
-
575
- // Note: Nous n'émettons pas update:model-value avec un tableau contenant null
576
- // car le type DateValue n'accepte que [string, string] pour les plages
577
562
  }
578
563
  }
579
564
  else {
@@ -729,18 +714,35 @@
729
714
  const validation = validateDateFormat(inputValue.value)
730
715
  // check si pas d'erreur des rules
731
716
  const checkRules = validateField(inputValue.value, props.customRules, props.customWarningRules)
732
- if (validation.isValid && !checkRules.hasError) {
717
+ if (validation.isValid && !checkRules.hasError && !props.displayRange) {
733
718
  // Si le format est valide, la date est également valide grâce à notre correction dans useDateFormatValidation
734
719
  const formattedDate = props.dateFormatReturn
735
720
  ? dayjs(inputValue.value, props.format).format(props.dateFormatReturn)
736
721
  : inputValue.value
737
722
  emit('update:model-value', formattedDate)
738
723
  }
724
+ else if (validation.isValid && !checkRules.hasError && props.displayRange) {
725
+ // If the input is a range (contains ' - '), split it into a tuple [string, string]
726
+ if (typeof inputValue.value === 'string' && inputValue.value.includes(' - ')) {
727
+ const parts = inputValue.value.split(' - ')
728
+ if (parts.length === 2) {
729
+ emit('update:model-value', [parts[0], parts[1]])
730
+ }
731
+ else {
732
+ // If we don't have exactly two parts, use original value
733
+ emit('update:model-value', inputValue.value)
734
+ }
735
+ }
736
+ else {
737
+ emit('update:model-value', inputValue.value)
738
+ }
739
+ }
739
740
  else {
741
+ validateRules(inputValue.value)
740
742
  // Si le format n'est pas valide ou si la date est invalide, ajouter le message d'erreur
741
- clearValidation()
742
743
  errors.value.push(validation.message)
743
744
  emit('update:model-value', props.modelValue)
745
+ clearValidation()
744
746
  }
745
747
  }
746
748
 
@@ -828,7 +830,6 @@
828
830
  if (props.displayRange && inputValue.value) {
829
831
  // Utiliser le composable pour analyser la plage de dates
830
832
  const [startDate, endDate] = parseRangeInput(inputValue.value)
831
-
832
833
  // Si nous avons une plage complète (deux dates)
833
834
  if (startDate && endDate) {
834
835
  // Vérifier si la plage est valide (date de fin >= date de début)
@@ -848,11 +849,8 @@
848
849
 
849
850
  // Plage valide, mettre à jour le modèle
850
851
  const returnFormat = props.dateFormatReturn || props.format
851
- const modelValue: [string, string] = [
852
- formatDate(startDate, returnFormat),
853
- formatDate(endDate, returnFormat),
854
- ]
855
- emit('update:model-value', modelValue)
852
+
853
+ emit('update:model-value', [formatDate(startDate, returnFormat), formatDate(endDate, returnFormat)])
856
854
  validateRules(inputValue.value)
857
855
  return
858
856
  }
@@ -958,14 +956,14 @@
958
956
  focus() {
959
957
  // Utiliser un sélecteur plus spécifique pour cibler l'input principal
960
958
  // SyTextField peut contenir plusieurs inputs, donc on cible le premier qui n'est pas caché
961
- const input = inputRef.value?.$el.querySelector('input:not([type="hidden"])')
959
+ const input = inputRef.value?.$el?.querySelector?.('input:not([type="hidden"])')
962
960
  if (input) {
963
- input.focus()
961
+ input.focus({ preventScroll: true })
964
962
  }
965
963
  },
966
964
  blur() {
967
965
  // Utiliser un sélecteur plus spécifique pour cibler l'input principal
968
- const input = inputRef.value?.$el.querySelector('input:not([type="hidden"])')
966
+ const input = inputRef.value?.$el?.querySelector?.('input:not([type="hidden"])')
969
967
  if (input) {
970
968
  input.blur()
971
969
  }