@cnamts/synapse 1.0.22 → 1.0.23

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 (190) hide show
  1. package/dist/{DateFilter-B5n-ZkLi.js → DateFilter-Dc-gSGwk.js} +1 -1
  2. package/dist/{NumberFilter-CtiZ9uj8.js → NumberFilter-vP38Wp6j.js} +1 -1
  3. package/dist/{PeriodFilter-DzqiMb-b.js → PeriodFilter-Ba1uYUnT.js} +1 -1
  4. package/dist/{SelectFilter-BOYlF7rX.js → SelectFilter-BioGT6Nn.js} +1 -1
  5. package/dist/{TextFilter-BOFRNfcX.js → TextFilter-B84dpnoq.js} +1 -1
  6. package/dist/components/Accordion/Accordion.d.ts +13 -2
  7. package/dist/components/Accordion/composables/useAccordionState.d.ts +2 -1
  8. package/dist/components/Amelipro/AmeliproAutoCompleteField/AmeliproAutoCompleteField.d.ts +7 -7
  9. package/dist/components/Amelipro/AmeliproCheckbox/AmeliproCheckbox.d.ts +1 -1
  10. package/dist/components/Amelipro/AmeliproCustomSelector/AmeliproCustomSelector.d.ts +1 -1
  11. package/dist/components/Amelipro/AmeliproPostalAddressField/AmeliproPostalAddressField.d.ts +1 -1
  12. package/dist/components/Amelipro/AmeliproSelect/AmeliproSelect.d.ts +7 -7
  13. package/dist/components/Amelipro/AmeliproTabs/AmeliproTabs.d.ts +16 -16
  14. package/dist/components/Amelipro/AmeliproTextArea/AmeliproTextArea.d.ts +1 -1
  15. package/dist/components/Amelipro/AmeliproTextField/AmeliproTextField.d.ts +1 -1
  16. package/dist/components/Customs/Selects/SyAutocomplete/SyAutocomplete.d.ts +22 -1
  17. package/dist/components/Customs/Selects/SyAutocomplete/locales.d.ts +5 -0
  18. package/dist/components/Customs/Selects/SyInputSelect/SyInputSelect.d.ts +1 -1
  19. package/dist/components/Customs/Selects/SySelect/SySelect.d.ts +1 -1
  20. package/dist/components/Customs/Selects/SySelect/locales.d.ts +1 -0
  21. package/dist/components/Customs/SyCheckBoxGroup/SyCheckBoxGroup.d.ts +1 -1
  22. package/dist/components/Customs/SyCheckbox/SyCheckbox.d.ts +1 -1
  23. package/dist/components/Customs/SyRadioGroup/SyRadioGroup.d.ts +1 -1
  24. package/dist/components/Customs/SyTextField/SyTextField.d.ts +5 -2
  25. package/dist/components/DatePicker/CalendarMode/DatePicker.d.ts +13 -9
  26. package/dist/components/DatePicker/ComplexDatePicker/ComplexDatePicker.d.ts +7 -5
  27. package/dist/components/DatePicker/DateTextInput/DateTextInput.d.ts +2 -1
  28. package/dist/components/ErrorPage/ErrorPage.d.ts +3 -1
  29. package/dist/components/FileList/UploadItem/UploadItem.d.ts +6 -0
  30. package/dist/components/FileList/UploadItem/locales.d.ts +1 -4
  31. package/dist/components/FileUpload/FileUploadContent.d.ts +2 -0
  32. package/dist/components/FileUpload/validateFiles.d.ts +2 -1
  33. package/dist/components/HeaderBar/HeaderBar.d.ts +2 -1
  34. package/dist/components/HeaderBar/HeaderLogo/HeaderLogo.d.ts +2 -1
  35. package/dist/components/HeaderNavigationBar/HeaderNavigationBar.d.ts +2 -1
  36. package/dist/components/MonthPicker/MonthPicker.d.ts +1939 -0
  37. package/dist/components/MonthPicker/MonthPickerText/MonthPickerInput.d.ts +1899 -0
  38. package/dist/components/MonthPicker/MonthPickerText/useTextField.d.ts +21 -0
  39. package/dist/components/MonthPicker/MonthPickerVisual/MonthPickerVisual.d.ts +21 -0
  40. package/dist/components/MonthPicker/MonthPickerVisual/MonthPickerVisualProps.d.ts +12 -0
  41. package/dist/components/MonthPicker/MonthPickerVisual/MonthSelector.d.ts +11 -0
  42. package/dist/components/MonthPicker/MonthPickerVisual/VisualPickerFooter.d.ts +6 -0
  43. package/dist/components/MonthPicker/MonthPickerVisual/VisualPickerHeader.d.ts +14 -0
  44. package/dist/components/MonthPicker/MonthPickerVisual/YearSelector.d.ts +14 -0
  45. package/dist/components/MonthPicker/MonthPickerVisual/useMonthGrid.d.ts +9 -0
  46. package/dist/components/MonthPicker/MonthPickerVisual/useYearGrid.d.ts +8 -0
  47. package/dist/components/MonthPicker/MonthPickerVisual/utils.d.ts +8 -0
  48. package/dist/components/MonthPicker/locales.d.ts +12 -0
  49. package/dist/components/MonthPicker/useMonthPickerValidation.d.ts +25 -0
  50. package/dist/components/NirField/NirField.d.ts +3 -1
  51. package/dist/components/NotificationBar/Notification/Notification.d.ts +3 -0
  52. package/dist/components/PasswordField/PasswordField.d.ts +1 -1
  53. package/dist/components/PeriodField/PeriodField.d.ts +29 -21
  54. package/dist/components/PhoneField/PhoneField.d.ts +2 -1
  55. package/dist/components/SyBtnMenu/SyBtnMenu.d.ts +1 -1
  56. package/dist/components/SyHeading/SyHeading.a11y.test.d.ts +1 -0
  57. package/dist/components/SyHeading/SyHeading.d.ts +4 -2
  58. package/dist/components/SyHeading/SyHeading.test.d.ts +1 -0
  59. package/dist/components/SyTextArea/SyTextArea.d.ts +1 -1
  60. package/dist/components/Tables/SyServerTable/SyServerTable.d.ts +4 -4
  61. package/dist/components/Tables/SyTable/SyTable.d.ts +4 -4
  62. package/dist/components/Tables/common/SyTablePagination.d.ts +6 -6
  63. package/dist/components/index.d.ts +1 -0
  64. package/dist/design-system-v3.js +102 -99
  65. package/dist/design-system-v3.umd.cjs +126 -126
  66. package/dist/designTokens/tokens/cnam/cnamContextual.d.ts +5 -0
  67. package/dist/{main-CEl4J8_T.js → main-aLKwdMi1.js} +11167 -10522
  68. package/dist/main.d.ts +1 -0
  69. package/dist/style.css +1 -1
  70. package/package.json +10 -4
  71. package/src/assets/apTokens.scss +2 -2
  72. package/src/assets/overrides/_btns.scss +8 -0
  73. package/src/assets/overrides/_forms.scss +9 -0
  74. package/src/assets/overrides/_icons.scss +38 -9
  75. package/src/assets/overrides/_tables.scss +19 -0
  76. package/src/components/Accordion/Accordion.mdx +23 -9
  77. package/src/components/Accordion/Accordion.stories.ts +153 -3
  78. package/src/components/Accordion/Accordion.vue +7 -6
  79. package/src/components/Accordion/composables/__tests__/useAccordionState.spec.ts +40 -12
  80. package/src/components/Accordion/composables/useAccordionState.ts +3 -4
  81. package/src/components/Accordion/tests/accordion.spec.ts +131 -19
  82. package/src/components/Amelipro/AmeliproPagination/AmeliproPagination.mdx +3 -1
  83. package/src/components/Amelipro/AmeliproPagination/AmeliproPagination.stories.ts +8 -0
  84. package/src/components/BackBtn/accessibilite/Accessibility.mdx +62 -10
  85. package/src/components/BackToTopBtn/BackToTopBtn.stories.ts +9 -3
  86. package/src/components/BackToTopBtn/accessibilite/Accessibility.mdx +86 -6
  87. package/src/components/Captcha/tests/Captcha.spec.ts +0 -29
  88. package/src/components/Captcha/tests/__snapshots__/Captcha.spec.ts.snap +2 -110
  89. package/src/components/Customs/Selects/SelectBtnField/accessibilite/Accessibility.mdx +133 -10
  90. package/src/components/Customs/Selects/SyAutocomplete/SyAutocomplete.stories.ts +379 -93
  91. package/src/components/Customs/Selects/SyAutocomplete/SyAutocomplete.vue +144 -83
  92. package/src/components/Customs/Selects/SyAutocomplete/accessibilite/Accessibilite.stories.ts +40 -1
  93. package/src/components/Customs/Selects/SyAutocomplete/accessibilite/Accessibility.mdx +7 -1
  94. package/src/components/Customs/Selects/SyAutocomplete/locales.ts +5 -0
  95. package/src/components/Customs/Selects/SyAutocomplete/tests/SyAutocomplete.a11y.spec.ts +96 -0
  96. package/src/components/Customs/Selects/SyAutocomplete/tests/SyAutocomplete.spec.ts +234 -9
  97. package/src/components/Customs/Selects/SyAutocomplete/utils/ariaManager.ts +13 -3
  98. package/src/components/Customs/Selects/SyAutocomplete/utils/useSelectionLogic.ts +9 -10
  99. package/src/components/Customs/Selects/SySelect/SySelect.vue +46 -3
  100. package/src/components/Customs/Selects/SySelect/locales.ts +1 -0
  101. package/src/components/Customs/SyIcon/SyIcon.vue +1 -1
  102. package/src/components/Customs/SyIcon/tests/SyIcon.a11y.spec.ts +20 -0
  103. package/src/components/Customs/SyIconButton/SyIconButton.mdx +46 -0
  104. package/src/components/Customs/SyIconButton/SyIconButton.stories.ts +184 -0
  105. package/src/components/Customs/SyIconButton/SyIconButton.vue +38 -0
  106. package/src/components/Customs/SyIconButton/accessibilite/Accessibility.mdx +64 -0
  107. package/src/components/Customs/SyIconButton/tests/SyIconButton.a11y.spec.ts +87 -0
  108. package/src/components/Customs/SyIconButton/tests/SyIconButton.spec.ts +152 -0
  109. package/src/components/Customs/SyIconButton/tests/__snapshots__/SyIconButton.spec.ts.snap +61 -0
  110. package/src/components/Customs/SyPagination/SyPagination.vue +5 -5
  111. package/src/components/Customs/SyTextField/SyTextField.vue +20 -2
  112. package/src/components/Customs/SyTextField/accessibilite/Accessibility.mdx +67 -9
  113. package/src/components/Customs/SyTextField/tests/SyTextField.a11y.spec.ts +15 -0
  114. package/src/components/Customs/SyTextField/tests/SyTextField.spec.ts +36 -0
  115. package/src/components/DataList/accessibilite/Accessibility.mdx +79 -11
  116. package/src/components/DataListGroup/accessibilite/Accessibility.mdx +80 -11
  117. package/src/components/DownloadBtn/tests/DownloadBtn.a11y.spec.ts +25 -0
  118. package/src/components/ErrorPage/ErrorPage.stories.ts +113 -19
  119. package/src/components/ErrorPage/ErrorPage.vue +17 -2
  120. package/src/components/ErrorPage/tests/ErrorPage.a11y.spec.ts +17 -0
  121. package/src/components/ErrorPage/tests/ErrorPage.spec.ts +21 -1
  122. package/src/components/ErrorPage/tests/__snapshots__/ErrorPage.spec.ts.snap +0 -1
  123. package/src/components/ExternalLinks/tests/ExternalLinks.a11y.spec.ts +23 -0
  124. package/src/components/FileList/FileList.stories.ts +51 -1
  125. package/src/components/FileList/UploadItem/UploadItem.vue +13 -6
  126. package/src/components/FileList/UploadItem/locales.ts +3 -12
  127. package/src/components/FileList/accessibilite/Accessibility.mdx +3 -0
  128. package/src/components/FileUpload/FileUpload.vue +2 -1
  129. package/src/components/FileUpload/FileUploadContent.vue +2 -1
  130. package/src/components/FileUpload/tests/FileUpload.spec.ts +47 -0
  131. package/src/components/FileUpload/validateFiles.ts +5 -2
  132. package/src/components/FranceConnectBtn/accessibilite/Accessibility.mdx +62 -9
  133. package/src/components/HeaderBar/HeaderBar.vue +2 -1
  134. package/src/components/HeaderBar/HeaderLogo/HeaderLogo.vue +2 -1
  135. package/src/components/HeaderNavigationBar/HeaderNavigationBar.vue +2 -1
  136. package/src/components/LunarCalendar/accessibilite/Accessibility.mdx +74 -8
  137. package/src/components/LunarCalendar/tests/LunarCalendar.a11y.spec.ts +163 -0
  138. package/src/components/MaintenancePage/MaintenancePage.vue +1 -1
  139. package/src/components/MaintenancePage/tests/MaintenancePage.spec.ts +4 -5
  140. package/src/components/MaintenancePage/tests/__snapshots__/MaintenancePage.spec.ts.snap +0 -1
  141. package/src/components/MonthPicker/MonthPicker.mdx +35 -0
  142. package/src/components/MonthPicker/MonthPicker.stories.ts +527 -0
  143. package/src/components/MonthPicker/MonthPicker.vue +79 -0
  144. package/src/components/MonthPicker/MonthPickerText/MonthPickerInput.vue +89 -0
  145. package/src/components/MonthPicker/MonthPickerText/useTextField.ts +27 -0
  146. package/src/components/MonthPicker/MonthPickerVisual/MonthPickerVisual.vue +154 -0
  147. package/src/components/MonthPicker/MonthPickerVisual/MonthPickerVisualProps.ts +13 -0
  148. package/src/components/MonthPicker/MonthPickerVisual/MonthSelector.vue +137 -0
  149. package/src/components/MonthPicker/MonthPickerVisual/VisualPickerFooter.vue +60 -0
  150. package/src/components/MonthPicker/MonthPickerVisual/VisualPickerHeader.vue +149 -0
  151. package/src/components/MonthPicker/MonthPickerVisual/YearSelector.vue +143 -0
  152. package/src/components/MonthPicker/MonthPickerVisual/useMonthGrid.ts +45 -0
  153. package/src/components/MonthPicker/MonthPickerVisual/useYearGrid.ts +45 -0
  154. package/src/components/MonthPicker/MonthPickerVisual/utils.ts +17 -0
  155. package/src/components/MonthPicker/accessibilite/Accessibility.mdx +59 -0
  156. package/src/components/MonthPicker/locales.ts +12 -0
  157. package/src/components/MonthPicker/tests/MonthPicker.a11y.spec.ts +71 -0
  158. package/src/components/MonthPicker/tests/MonthPicker.spec.ts +1248 -0
  159. package/src/components/MonthPicker/tests/__snapshots__/MonthPicker.spec.ts.snap +2545 -0
  160. package/src/components/MonthPicker/useMonthPickerValidation.ts +30 -0
  161. package/src/components/NirField/NirField.mdx +1 -2
  162. package/src/components/NirField/NirField.stories.ts +66 -6
  163. package/src/components/NotFoundPage/tests/NotFoundPage.spec.ts +2 -3
  164. package/src/components/NotFoundPage/tests/__snapshots__/NotFoundPage.spec.ts.snap +22 -14
  165. package/src/components/NotificationBar/Notification/Notification.vue +3 -1
  166. package/src/components/NotificationBar/NotificationBar.stories.ts +154 -0
  167. package/src/components/NotificationBar/tests/NotificationBar.a11y.spec.ts +26 -0
  168. package/src/components/NotificationBar/tests/NotificationBar.spec.ts +60 -0
  169. package/src/components/RangeField/accessibilite/Accessibility.mdx +79 -11
  170. package/src/components/SkipLink/tests/SkipLink.a11y.spec.ts +23 -0
  171. package/src/components/StatusPage/StatusPage.stories.ts +118 -0
  172. package/src/components/StatusPage/StatusPage.vue +5 -3
  173. package/src/components/StatusPage/tests/StatusPage.a11y.spec.ts +22 -0
  174. package/src/components/StatusPage/tests/StatusPage.spec.ts +22 -0
  175. package/src/components/StatusPage/tests/__snapshots__/StatusPage.spec.ts.snap +22 -14
  176. package/src/components/SubHeader/tests/SubHeader.a11y.spec.ts +20 -0
  177. package/src/components/SyAlert/SyAlert.vue +1 -0
  178. package/src/components/SyAlert/accessibilite/Accessibility.mdx +79 -9
  179. package/src/components/SyAlert/tests/SyAlert.a11y.spec.ts +23 -0
  180. package/src/components/SyHeading/SyHeading.a11y.test.ts +149 -0
  181. package/src/components/SyHeading/SyHeading.test.ts +115 -0
  182. package/src/components/SyHeading/SyHeading.vue +5 -3
  183. package/src/components/SyTextArea/accessibilite/Accessibility.mdx +80 -8
  184. package/src/components/SyTextArea/tests/SyTextArea.a11y.spec.ts +151 -0
  185. package/src/components/ToolbarContainer/tests/ToolbarContainer.a11y.spec.ts +126 -0
  186. package/src/components/UploadWorkflow/tests/__snapshots__/UploadWorkflow.spec.ts.snap +2 -2
  187. package/src/components/index.ts +1 -0
  188. package/src/composables/useFormFieldErrorHandling.ts +11 -2
  189. package/src/designTokens/tokens/cnam/cnamContextual.ts +6 -1
  190. package/src/main.ts +2 -0
@@ -0,0 +1,527 @@
1
+ import { fn } from '@storybook/test'
2
+ import { nextTick, ref } from 'vue'
3
+ import MonthPicker from './MonthPicker.vue'
4
+ import type { Meta, StoryObj } from '@storybook/vue3'
5
+ import type SyTextField from '../Customs/SyTextField/SyTextField.vue'
6
+ import SyForm from '../Customs/SyForm/SyForm.vue'
7
+
8
+ const meta: Meta<typeof MonthPicker> = {
9
+ title: 'Composants/Formulaires/MonthPicker',
10
+ component: MonthPicker,
11
+ argTypes: {
12
+ 'modelValue': {
13
+ control: 'text',
14
+ description: 'Valeur du sélecteur de mois au format "MM/YYYY".',
15
+ table: {
16
+ type: { summary: 'string' },
17
+ },
18
+ },
19
+ 'locales': {
20
+ description: 'Objet de traduction pour le sélecteur de mois. Par défaut, les traductions françaises sont utilisées.',
21
+ table: {
22
+ type: { summary: 'object' },
23
+ },
24
+ },
25
+ 'minYear': {
26
+ description: 'Année minimale affichée dans le sélecteur visuel. Ne concerne pas la validation.',
27
+ table: {
28
+ type: { summary: 'number' },
29
+ defaultValue: { summary: '1900' },
30
+ category: 'props',
31
+ },
32
+ },
33
+ 'maxYear': {
34
+ description: 'Année maximale affichée dans le sélecteur visuel. Ne concerne pas la validation.',
35
+ table: {
36
+ type: { summary: 'number' },
37
+ defaultValue: { summary: '2100' },
38
+ category: 'props',
39
+ },
40
+ },
41
+ 'yearsOrder': {
42
+ description: 'Ordre d’affichage des années dans le sélecteur visuel. Peut être "asc" pour un ordre croissant ou "desc" pour un ordre décroissant.',
43
+ control: 'select',
44
+ options: ['asc', 'desc'],
45
+ table: {
46
+ type: { summary: '"asc" | "desc"' },
47
+ defaultValue: { summary: '"asc"' },
48
+ category: 'props',
49
+ },
50
+ },
51
+ 'initialView': {
52
+ description: 'Vue initiale affichée lorsque la modale de sélection de mois est ouverte.',
53
+ control: 'select',
54
+ options: ['months', 'years'],
55
+ table: {
56
+ type: { summary: '"months" | "years"' },
57
+ defaultValue: { summary: '"months"' },
58
+ category: 'props',
59
+ },
60
+ },
61
+ 'placeholder': {
62
+ description: 'Texte affiché dans le champ de saisie lorsque aucune valeur n’est sélectionnée.',
63
+ control: 'text',
64
+ table: {
65
+ type: { summary: 'string' },
66
+ category: 'props',
67
+ },
68
+ },
69
+ 'label': {
70
+ description: 'Label du champ de saisie du sélecteur de mois.',
71
+ control: 'text',
72
+ table: {
73
+ type: { summary: 'string' },
74
+ category: 'props',
75
+ },
76
+ },
77
+ 'density': {
78
+ description: 'Densité d’affichage du champ de saisie. Peut être "default", "comfortable" ou "compact".',
79
+ control: 'select',
80
+ options: ['default', 'comfortable', 'compact'],
81
+ table: {
82
+ type: { summary: '"default" | "comfortable" | "compact"' },
83
+ defaultValue: { summary: '"default"' },
84
+ category: 'props',
85
+ },
86
+ },
87
+ 'hint': {
88
+ description: 'Texte d’aide affiché sous le champ de saisie.',
89
+ control: 'text',
90
+ table: {
91
+ type: { summary: 'string' },
92
+ category: 'props',
93
+ },
94
+ },
95
+ 'customRules': {
96
+ description: 'Règles de validation personnalisées pour les erreurs.',
97
+ table: {
98
+ type: { summary: 'ValidationRule[]' },
99
+ category: 'props',
100
+ },
101
+ },
102
+ 'customWarningRules': {
103
+ description: 'Règles de validation personnalisées pour les avertissements.',
104
+ table: {
105
+ type: { summary: 'ValidationRule[]' },
106
+ category: 'props',
107
+ },
108
+ },
109
+ 'customSuccessRules': {
110
+ description: 'Règles de validation personnalisées pour les succès.',
111
+ table: {
112
+ type: { summary: 'ValidationRule[]' },
113
+ category: 'props',
114
+ },
115
+ category: 'validation',
116
+ },
117
+ 'errorMessages': {
118
+ description: 'Messages d’erreur personnalisés à afficher lorsque la validation échoue. Peut être une chaîne de caractères ou un tableau de chaînes.',
119
+ control: 'text',
120
+ table: {
121
+ type: { summary: 'string | string[]' },
122
+ category: 'props',
123
+ },
124
+ },
125
+ 'warningMessages': {
126
+ description: 'Messages d’avertissement personnalisés à afficher lorsque la validation génère un avertissement. Peut être une chaîne de caractères ou un tableau de chaînes.',
127
+ control: 'text',
128
+ table: {
129
+ type: { summary: 'string | string[]' },
130
+ category: 'props',
131
+ },
132
+ },
133
+ 'successMessages': {
134
+ description: 'Messages de succès personnalisés à afficher lorsque la validation réussit. Peut être une chaîne de caractères ou un tableau de chaînes.',
135
+ control: 'text',
136
+ table: {
137
+ type: { summary: 'string | string[]' },
138
+ category: 'props',
139
+ },
140
+ },
141
+ 'hasError': {
142
+ description: 'Indique si le champ est en état d’erreur. Utilisé pour forcer l’affichage des messages d’erreur.',
143
+ control: 'boolean',
144
+ table: {
145
+ type: { summary: 'boolean' },
146
+ category: 'props',
147
+ },
148
+ },
149
+ 'hasWarning': {
150
+ description: 'Indique si le champ est en état d’avertissement. Utilisé pour forcer l’affichage des messages d’avertissement.',
151
+ control: 'boolean',
152
+ table: {
153
+ type: { summary: 'boolean' },
154
+ category: 'props',
155
+ },
156
+ },
157
+ 'hasSuccess': {
158
+ description: 'Indique si le champ est en état de succès. Utilisé pour forcer l’affichage des messages de succès.',
159
+ control: 'boolean',
160
+ table: {
161
+ type: { summary: 'boolean' },
162
+ category: 'props',
163
+ },
164
+ },
165
+ 'showSuccessMessages': {
166
+ description: 'Indique si les messages de succès doivent être affichés.',
167
+ control: 'boolean',
168
+ table: {
169
+ type: { summary: 'boolean' },
170
+ category: 'props',
171
+ },
172
+ },
173
+ 'disabled': {
174
+ description: 'Indique si le champ de saisie est désactivé. Lorsqu’il est désactivé, le sélecteur de mois ne peut pas être ouvert et aucune interaction n’est possible.',
175
+ control: 'boolean',
176
+ table: {
177
+ type: { summary: 'boolean' },
178
+ defaultValue: { summary: 'false' },
179
+ category: 'props',
180
+ },
181
+ },
182
+ 'readonly': {
183
+ description: 'Indique si le champ de saisie est en lecture seule. Lorsqu’il est en lecture seule, le sélecteur de mois peut être ouvert pour afficher la valeur sélectionnée, mais aucune modification n’est possible.',
184
+ control: 'boolean',
185
+ table: {
186
+ type: { summary: 'boolean' },
187
+ defaultValue: { summary: 'false' },
188
+ category: 'props',
189
+ },
190
+ category: 'props',
191
+ },
192
+ 'onUpdate:modelValue': {
193
+ action: 'update:modelValue',
194
+ description: 'Événement émis lorsque le champs de saisie change (quelque soit la valeur renseigné même incomplète ou invalide) ou lorsque un mois ET une année sont sélectionnés dans la modale. La valeur est toujours au format "MM/YYYY".',
195
+ table: {
196
+ type: { summary: 'string' },
197
+ },
198
+ },
199
+ 'onUpdate:open': {
200
+ action: 'update:open',
201
+ description: 'Événement émis lorsque le sélecteur de mois est ouvert ou fermé. Si seulement une année ou un mois est sélectionné, le contenu de ma modale est réinitialisé et aucun événement "update:modelValue" n’est émis.',
202
+ table: {
203
+ type: { summary: 'boolean' },
204
+ },
205
+ },
206
+ },
207
+ parameters: {
208
+ controls: {
209
+ exclude: ['width', 'undefined', 'onUpdate:modelValue', 'onUpdate:open'],
210
+ },
211
+ docs: {
212
+ controls: {
213
+ exclude: ['onUpdate:modelValue', 'onUpdate:open'],
214
+ },
215
+ },
216
+ },
217
+ }
218
+
219
+ export default meta
220
+ type Story = StoryObj<typeof MonthPicker & typeof SyTextField>
221
+
222
+ export const Default: Story = {
223
+ args: {
224
+ 'modelValue': '11/2025',
225
+ 'label': 'Début du projet',
226
+ 'onUpdate:modelValue': fn(),
227
+ 'onUpdate:open': fn(),
228
+ 'width': '400px',
229
+ 'customRules': [{
230
+ type: 'custom',
231
+ options: {
232
+ validate: (value: string) => /^(0[1-9]|1[0-2])\/\d{4}$/.test(value),
233
+ message: 'Le format doit être MM/YYYY. (ex: 12/2026).',
234
+ },
235
+ }],
236
+ },
237
+ parameters: {
238
+ sourceCode: [
239
+ {
240
+ name: 'Template',
241
+ code: `
242
+ <template>
243
+ <MonthPicker
244
+ v-model="selectedMonth"
245
+ label="Début du projet"
246
+ width="400px"
247
+ :custom-rules="rules"
248
+ />
249
+ </template>
250
+ `,
251
+ }, {
252
+ name: 'Script',
253
+ code: `
254
+ <script setup lang="ts">
255
+ import { MonthPicker } from '@cnamts/synapse'
256
+ import { ref } from 'vue'
257
+
258
+ const selectedMonth = ref('11/2025')
259
+
260
+ const rules = [{
261
+ type: 'custom',
262
+ options: {
263
+ validate: (value: string) => /^(0[1-9]|1[0-2])\\/\\d{4}$/.test(value),
264
+ message: 'Le format doit être MM/YYYY (ex: 12/2026).',
265
+ },
266
+ }]
267
+ </script>
268
+ `,
269
+ },
270
+ ],
271
+ },
272
+ }
273
+
274
+ export const MonthValidation: Story = {
275
+ args: {
276
+ 'modelValue': '11/2025',
277
+ 'label': 'Début du projet',
278
+ 'onUpdate:modelValue': fn(),
279
+ 'onUpdate:open': fn(),
280
+ },
281
+ play: async ({ canvasElement }) => {
282
+ const input = canvasElement.querySelector('input') as HTMLInputElement
283
+ const currentDate = new Date()
284
+
285
+ setTimeout(async () => {
286
+ input.focus()
287
+ const futureYear = currentDate.getFullYear() + 6
288
+ input.value = `11/${futureYear}`
289
+ input.dispatchEvent(new Event('input'))
290
+ await nextTick()
291
+ input.dispatchEvent(new Event('blur'))
292
+ }, 100)
293
+ },
294
+ parameters: {
295
+ sourceCode: [
296
+ {
297
+ name: 'Template',
298
+ code: `
299
+ <template>
300
+ <MonthPicker
301
+ v-model="selectedMonth"
302
+ label="Début du projet"
303
+ :custom-rules
304
+ :custom-warning-rules
305
+ />
306
+ </template>
307
+ `,
308
+ }, {
309
+ name: 'Script',
310
+ code: `
311
+ <script setup lang="ts">
312
+ import { MonthPicker } from '@cnamts/synapse'
313
+ import { ref } from 'vue'
314
+
315
+ const selectedMonth = ref('11/2025')
316
+
317
+ const customRules = [
318
+ {
319
+ type: 'required',
320
+ options: {
321
+ message: 'Ce champ est requis.',
322
+ },
323
+ },
324
+ {
325
+ type: 'custom',
326
+ options: {
327
+ validate: (value: string) => {
328
+ const [month] = value.split('/').map(Number)
329
+ if (
330
+ !value ||
331
+ !month ||
332
+ !/^\\d{2}\\/\\d{4}$/.test(value) ||
333
+ month < 1 ||
334
+ month > 12
335
+ ) {
336
+ return false
337
+ }
338
+ return true
339
+ },
340
+ message: 'Format de mois invalide.',
341
+ },
342
+ },
343
+ ]
344
+
345
+ const customWarningRules = [{
346
+ type: 'custom',
347
+ options: {
348
+ validate: (value: string) => {
349
+ const [month, year] = value.split('/').map(Number) as [number, number]
350
+ const currentDate = new Date()
351
+ const currentYear = currentDate.getFullYear()
352
+ const currentMonth = currentDate.getMonth() + 1
353
+ if (year > currentYear + 5 || (year === currentYear + 5 && month > currentMonth)) {
354
+ return false
355
+ }
356
+ return true
357
+ },
358
+ warningMessage: 'La date est plus de 5 ans dans le futur.',
359
+ },
360
+ }]
361
+ </script>
362
+ `,
363
+ },
364
+ ],
365
+ },
366
+ render: args => ({
367
+ components: { MonthPicker },
368
+ setup() {
369
+ const customRules = [
370
+ {
371
+ type: 'required',
372
+ options: {
373
+ message: 'Ce champ est requis.',
374
+ },
375
+ },
376
+ {
377
+ type: 'custom',
378
+ options: {
379
+ validate: (value: string) => {
380
+ const [month] = value.split('/').map(Number)
381
+ if (
382
+ !month
383
+ || !/^\d{2}\/\d{4}$/.test(value)
384
+ || month < 1
385
+ || month > 12
386
+ ) {
387
+ return false
388
+ }
389
+ return true
390
+ },
391
+ message: 'Format de mois invalide.',
392
+ },
393
+ },
394
+ ]
395
+
396
+ const customWarningRules = [{
397
+ type: 'custom',
398
+ options: {
399
+ validate: (value: string) => {
400
+ const [month, year] = value.split('/').map(Number) as [number, number]
401
+ const currentDate = new Date()
402
+ const currentYear = currentDate.getFullYear()
403
+ const currentMonth = currentDate.getMonth() + 1
404
+ if (year > currentYear + 5 || (year === currentYear + 5 && month > currentMonth)) {
405
+ return false
406
+ }
407
+ return true
408
+ },
409
+ warningMessage: 'La date est plus de 5 ans dans le futur.',
410
+ },
411
+ }]
412
+ return { args, customRules, customWarningRules }
413
+ },
414
+ template: `
415
+ <MonthPicker
416
+ v-bind="args"
417
+ :custom-rules="customRules"
418
+ :custom-warning-rules="customWarningRules"
419
+ width="400px"
420
+ />
421
+ `,
422
+ }),
423
+ }
424
+
425
+ export const CustomDisplayedYears: Story = {
426
+ args: {
427
+ 'modelValue': '11/2025',
428
+ 'label': 'Début du projet',
429
+ 'minYear': 2000,
430
+ 'maxYear': 2025,
431
+ 'width': '400px',
432
+ 'onUpdate:modelValue': fn(),
433
+ 'onUpdate:open': fn(),
434
+ },
435
+ parameters: {
436
+ sourceCode: [
437
+ {
438
+ name: 'Template',
439
+ code: `
440
+ <template>
441
+ <MonthPicker
442
+ v-model="selectedMonth"
443
+ label="Début du projet"
444
+ :min-year="2000"
445
+ :max-year="2025"
446
+ />
447
+ </template>
448
+ `,
449
+ }, {
450
+ name: 'Script',
451
+ code: `
452
+ <script setup lang="ts">
453
+ import { MonthPicker } from '@cnamts/synapse'
454
+ import { ref } from 'vue'
455
+
456
+ const selectedMonth = ref('11/2025')
457
+ </script>
458
+ `,
459
+ },
460
+ ],
461
+ },
462
+ }
463
+
464
+ export const Form: Story = {
465
+ args: {
466
+ modelValue: '',
467
+ label: 'Début du projet',
468
+ width: '400px',
469
+ },
470
+ parameters: {
471
+ sourceCode: [
472
+ {
473
+ name: 'Template',
474
+ code: `
475
+ <template>
476
+ <SyForm @submit="handleSubmit">
477
+ <MonthPicker
478
+ v-model="selectedMonth"
479
+ label="Début du projet"
480
+ width="400px"
481
+ :custom-rules="[{ type: 'required', options: { message: 'Ce champ est requis.' } }]"
482
+ />
483
+ <VBtn type="submit" color="primary" class="mt-4">Soumettre</VBtn>
484
+ </SyForm>
485
+ </template>
486
+ `,
487
+ }, {
488
+ name: 'Script',
489
+ code: `
490
+ <script setup lang="ts">
491
+ import { MonthPicker, SyForm } from '@cnamts/synapse'
492
+ import { ref } from 'vue'
493
+
494
+ const selectedMonth = ref('')
495
+
496
+ const handleSubmit = (e: { isValid: boolean }) => {
497
+ alert(e.isValid ? 'Le formulaire est valide.' : 'Le formulaire est invalide.')
498
+ }
499
+ </script>
500
+ `,
501
+ },
502
+ ],
503
+ },
504
+ render: args => ({
505
+ components: { MonthPicker, SyForm },
506
+ setup() {
507
+ const selectedMonth = ref('')
508
+
509
+ const handleSubmit = (e: { isValid: boolean }) => {
510
+ alert(e.isValid ? 'Le formulaire est valide.' : 'Le formulaire est invalide.')
511
+ }
512
+
513
+ return { args, selectedMonth, handleSubmit }
514
+ },
515
+ template: `
516
+ <SyForm @submit="handleSubmit">
517
+ <MonthPicker
518
+ v-bind="args"
519
+ v-model="selectedMonth"
520
+ width="400px"
521
+ :custom-rules="[{ type: 'required', options: { message: 'Ce champ est requis.' } }]"
522
+ />
523
+ <VBtn type="submit" color="primary" class="mt-4">Soumettre</VBtn>
524
+ </SyForm>
525
+ `,
526
+ }),
527
+ }
@@ -0,0 +1,79 @@
1
+ <script lang="ts" setup>
2
+ import { computed, provide, ref, useAttrs, type ComponentPublicInstance } from 'vue'
3
+ import MonthPickerInput from './MonthPickerText/MonthPickerInput.vue'
4
+ import MonthPickerVisual from './MonthPickerVisual/MonthPickerVisual.vue'
5
+ import { watch } from 'vue'
6
+ import { locales as defaultLocales, localesKey } from './locales'
7
+ import { defaultTextFieldProps, useTextField, type TextFieldProps } from './MonthPickerText/useTextField'
8
+ import { defaultMonthPickerVisualProps, type MonthPickerVisualProps } from './MonthPickerVisual/MonthPickerVisualProps'
9
+ import { useMonthPickerValidation, type ValidationProps } from './useMonthPickerValidation'
10
+
11
+ const props = withDefaults(defineProps<{
12
+ modelValue?: string
13
+ locales?: typeof defaultLocales
14
+ disabled?: boolean
15
+ readonly?: boolean
16
+ } & TextFieldProps & ValidationProps & Partial<MonthPickerVisualProps>>(), {
17
+ modelValue: undefined,
18
+ locales: () => defaultLocales,
19
+ hint: 'Format MM/AAAA',
20
+ showSuccessMessages: false,
21
+ ...defaultMonthPickerVisualProps,
22
+ ...defaultTextFieldProps,
23
+ disabled: false,
24
+ readonly: false,
25
+ })
26
+
27
+ provide(localesKey, computed(() => props.locales))
28
+
29
+ const emits = defineEmits<{
30
+ (e: 'update:modelValue', value: string | undefined): void
31
+ (e: 'update:open', value: boolean): void
32
+ }>()
33
+
34
+ const attrs = useAttrs()
35
+ const textInput = ref<ComponentPublicInstance<typeof MonthPickerInput> | null>(null)
36
+ const toggleBtn = computed(() => textInput.value?.toggleBtn)
37
+
38
+ const internalValue = ref<string | undefined>(undefined)
39
+
40
+ watch(
41
+ () => props.modelValue,
42
+ (newValue) => {
43
+ internalValue.value = newValue
44
+ },
45
+ { immediate: true },
46
+ )
47
+
48
+ watch(internalValue, (newValue) => {
49
+ if (!props.readonly && !props.disabled) {
50
+ emits('update:modelValue', newValue)
51
+ }
52
+ })
53
+ </script>
54
+
55
+ <template>
56
+ <div class="month-picker">
57
+ <MonthPickerInput
58
+ ref="textInput"
59
+ v-model="internalValue"
60
+ v-bind="{
61
+ ...attrs,
62
+ ...useTextField(props).value,
63
+ ...useMonthPickerValidation(props).value
64
+ }"
65
+ />
66
+ <MonthPickerVisual
67
+ v-model="internalValue"
68
+ :text-input
69
+ :toggle-btn
70
+ :min-year
71
+ :max-year
72
+ :years-order
73
+ :initial-view
74
+ :disabled
75
+ :readonly
76
+ @update:open="emits('update:open', $event)"
77
+ />
78
+ </div>
79
+ </template>
@@ -0,0 +1,89 @@
1
+ <script setup lang="ts">
2
+ import SyIcon from '@/components/Customs/SyIcon/SyIcon.vue'
3
+ import SyTextField from '@/components/Customs/SyTextField/SyTextField.vue'
4
+ import { mdiCalendar } from '@mdi/js'
5
+ import { vMaska } from 'maska/vue'
6
+ import { nextTick, inject, ref, watch } from 'vue'
7
+ import { locales as defaultLocales, localesKey } from '../locales'
8
+ import type { TextFieldProps } from './useTextField'
9
+ import { useTextField } from './useTextField'
10
+ import { useMonthPickerValidation, type ValidationProps } from '../useMonthPickerValidation'
11
+
12
+ const props = defineProps<{
13
+ modelValue: string | undefined
14
+ } & TextFieldProps & ValidationProps>()
15
+
16
+ const emits = defineEmits<{
17
+ (e: 'update:modelValue', value: string | undefined): void
18
+ }>()
19
+
20
+ const locales = inject<typeof defaultLocales>(localesKey)!
21
+ const input = ref<InstanceType<typeof SyTextField>>()
22
+
23
+ const mask = '##/####'
24
+
25
+ const innerValue = ref<string | undefined>(props.modelValue)
26
+ watch(
27
+ () => props.modelValue,
28
+ async (newValue) => {
29
+ const shouldValidate = newValue !== innerValue.value
30
+ innerValue.value = newValue
31
+ if (shouldValidate) {
32
+ await nextTick()
33
+ input.value?.validateOnSubmit()
34
+ }
35
+ },
36
+ )
37
+
38
+ watch(innerValue, async (newValue) => {
39
+ if (newValue?.length === mask.length) {
40
+ await nextTick()
41
+ input.value?.validateOnSubmit()
42
+ }
43
+
44
+ emits('update:modelValue', newValue)
45
+ })
46
+
47
+ const toggleBtn = ref<HTMLButtonElement | null>(null)
48
+ defineExpose({
49
+ toggleBtn,
50
+ })
51
+ </script>
52
+
53
+ <template>
54
+ <SyTextField
55
+ ref="input"
56
+ v-model="innerValue"
57
+ v-maska="mask"
58
+ v-bind="{
59
+ ...useTextField(props).value,
60
+ ...useMonthPickerValidation(props).value
61
+ }"
62
+ >
63
+ <template #append>
64
+ <button
65
+ ref="toggleBtn"
66
+ type="button"
67
+ class="month-picker-input__toggle-btn"
68
+ :title="locales.btnLabel"
69
+ :aria-label="locales.btnLabel"
70
+ >
71
+ <SyIcon
72
+ :icon="mdiCalendar"
73
+ decorative
74
+ />
75
+ </button>
76
+ </template>
77
+ </SyTextField>
78
+ </template>
79
+
80
+ <style scoped lang="scss">
81
+ .error-field .month-picker-input__toggle-btn :deep(svg) {
82
+ color: rgb(var(--v-theme-error, 179, 63, 46));
83
+ }
84
+
85
+ .warning-field .month-picker-input__toggle-btn :deep(svg) {
86
+ color: rgb(var(--v-theme-warning, 96, 72, 14));
87
+ }
88
+
89
+ </style>