@cnamts/synapse 0.0.11-alpha → 0.0.12-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.
Files changed (108) hide show
  1. package/dist/design-system-v3.js +3878 -3189
  2. package/dist/design-system-v3.umd.cjs +1 -1
  3. package/dist/src/components/Amelipro/types/languages.d.ts +6 -0
  4. package/dist/src/components/Amelipro/types/types.d.ts +65 -0
  5. package/dist/src/components/CookieBanner/CookieBanner.d.ts +1 -1
  6. package/dist/src/components/Customs/SyInputSelect/SyInputSelect.d.ts +2 -0
  7. package/dist/src/components/Customs/SyTextField/SyTextField.d.ts +29 -23
  8. package/dist/src/components/Customs/SyTextField/types.d.ts +1 -0
  9. package/dist/src/components/DatePicker/DatePicker.d.ts +70 -59
  10. package/dist/src/components/DatePicker/DateTextInput.d.ts +67 -56
  11. package/dist/src/components/ErrorPage/ErrorPage.d.ts +1 -1
  12. package/dist/src/components/FileList/FileList.d.ts +1 -0
  13. package/dist/src/components/FileList/UploadItem/UploadItem.d.ts +1 -1
  14. package/dist/src/components/FilterSideBar/FilterSideBar.d.ts +31 -0
  15. package/dist/src/components/FilterSideBar/locales.d.ts +7 -0
  16. package/dist/src/components/FilterSideBar/tests/FilterSideBar.spec.d.ts +1 -0
  17. package/dist/src/components/LangBtn/LangBtn.d.ts +2 -2
  18. package/dist/src/components/NirField/NirField.d.ts +940 -0
  19. package/dist/src/components/NotificationBar/NotificationBar.d.ts +1 -1
  20. package/dist/src/components/PasswordField/PasswordField.d.ts +40 -8
  21. package/dist/src/components/PeriodField/PeriodField.d.ts +142 -120
  22. package/dist/src/components/PhoneField/PhoneField.d.ts +11 -2
  23. package/dist/src/components/RatingPicker/EmotionPicker/EmotionPicker.d.ts +1 -1
  24. package/dist/src/components/RatingPicker/NumberPicker/NumberPicker.d.ts +1 -1
  25. package/dist/src/components/RatingPicker/StarsPicker/StarsPicker.d.ts +1 -1
  26. package/dist/src/components/UploadWorkflow/config.d.ts +29 -0
  27. package/dist/src/components/UploadWorkflow/locales.d.ts +7 -0
  28. package/dist/src/components/UploadWorkflow/tests/UploadWorkflow.spec.d.ts +1 -0
  29. package/dist/src/components/UploadWorkflow/types.d.ts +19 -0
  30. package/dist/src/components/UploadWorkflow/useFileList.d.ts +10 -0
  31. package/dist/src/components/UploadWorkflow/useFileUploadJourney.d.ts +9 -0
  32. package/dist/src/components/index.d.ts +2 -0
  33. package/dist/src/composables/rules/useFieldValidation.d.ts +1 -0
  34. package/dist/src/composables/validation/tests/useValidation.spec.d.ts +1 -0
  35. package/dist/src/composables/validation/useValidation.d.ts +39 -0
  36. package/dist/src/designTokens/index.d.ts +3 -1
  37. package/dist/src/vuetifyConfig.d.ts +81 -0
  38. package/dist/style.css +1 -1
  39. package/package.json +1 -1
  40. package/src/assets/_elevations.scss +89 -0
  41. package/src/assets/_fonts.scss +6 -0
  42. package/src/assets/_radius.scss +86 -0
  43. package/src/assets/_spacers.scss +149 -0
  44. package/src/assets/settings.scss +7 -3
  45. package/src/assets/tokens.scss +32 -29
  46. package/src/components/Amelipro/types/languages.d.ts +6 -0
  47. package/src/components/Amelipro/types/types.d.ts +65 -0
  48. package/src/components/Customs/SyInputSelect/SyInputSelect.stories.ts +65 -0
  49. package/src/components/Customs/SyInputSelect/SyInputSelect.vue +13 -3
  50. package/src/components/Customs/SySelect/SySelect.stories.ts +88 -5
  51. package/src/components/Customs/SySelect/SySelect.vue +36 -10
  52. package/src/components/Customs/SySelect/tests/SySelect.spec.ts +135 -2
  53. package/src/components/Customs/SyTextField/SyTextField.stories.ts +576 -85
  54. package/src/components/Customs/SyTextField/SyTextField.vue +132 -104
  55. package/src/components/Customs/SyTextField/tests/SyTextField.spec.ts +190 -38
  56. package/src/components/Customs/SyTextField/types.d.ts +1 -0
  57. package/src/components/DatePicker/DatePicker.vue +405 -137
  58. package/src/components/DatePicker/DateTextInput.vue +15 -0
  59. package/src/components/DatePicker/tests/DatePicker.spec.ts +8 -15
  60. package/src/components/FileList/FileList.vue +2 -1
  61. package/src/components/FileList/UploadItem/UploadItem.vue +10 -0
  62. package/src/components/FileUpload/FileUpload.stories.ts +84 -0
  63. package/src/components/FileUpload/FileUpload.vue +1 -0
  64. package/src/components/FileUpload/tests/FileUpload.spec.ts +4 -4
  65. package/src/components/FilterInline/FilterInline.mdx +180 -34
  66. package/src/components/FilterInline/FilterInline.stories.ts +363 -6
  67. package/src/components/FilterSideBar/FilterSideBar.mdx +237 -0
  68. package/src/components/FilterSideBar/FilterSideBar.stories.ts +798 -0
  69. package/src/components/FilterSideBar/FilterSideBar.vue +193 -0
  70. package/src/components/FilterSideBar/locales.ts +8 -0
  71. package/src/components/FilterSideBar/tests/FilterSideBar.spec.ts +305 -0
  72. package/src/components/FilterSideBar/tests/__snapshots__/FilterSideBar.spec.ts.snap +39 -0
  73. package/src/components/HeaderBar/Usages.mdx +1 -1
  74. package/src/components/NirField/NirField.stories.ts +573 -29
  75. package/src/components/NirField/NirField.vue +397 -359
  76. package/src/components/NirField/tests/NirField.spec.ts +88 -52
  77. package/src/components/NirField/tests//342/200/257dataset/342/200/257.md +12 -0
  78. package/src/components/NotificationBar/Accessibilite.stories.ts +4 -0
  79. package/src/components/NotificationBar/NotificationBar.stories.ts +18 -13
  80. package/src/components/PasswordField/PasswordField.mdx +129 -47
  81. package/src/components/PasswordField/PasswordField.stories.ts +924 -120
  82. package/src/components/PasswordField/PasswordField.vue +209 -99
  83. package/src/components/PasswordField/tests/PasswordField.spec.ts +138 -9
  84. package/src/components/PeriodField/PeriodField.vue +55 -54
  85. package/src/components/PhoneField/PhoneField.stories.ts +69 -0
  86. package/src/components/PhoneField/PhoneField.vue +3 -0
  87. package/src/components/PhoneField/indicatifs.ts +1 -1
  88. package/src/components/UploadWorkflow/UploadWorkflow.mdx +75 -0
  89. package/src/components/UploadWorkflow/UploadWorkflow.stories.ts +943 -0
  90. package/src/components/UploadWorkflow/UploadWorkflow.vue +230 -0
  91. package/src/components/UploadWorkflow/config.ts +29 -0
  92. package/src/components/UploadWorkflow/locales.ts +8 -0
  93. package/src/components/UploadWorkflow/tests/UploadWorkflow.spec.ts +257 -0
  94. package/src/components/UploadWorkflow/tests/__snapshots__/UploadWorkflow.spec.ts.snap +54 -0
  95. package/src/components/UploadWorkflow/types.ts +21 -0
  96. package/src/components/UploadWorkflow/useFileList.ts +84 -0
  97. package/src/components/UploadWorkflow/useFileUploadJourney.ts +18 -0
  98. package/src/components/index.ts +2 -0
  99. package/src/composables/rules/useFieldValidation.ts +5 -2
  100. package/src/composables/validation/tests/useValidation.spec.ts +154 -0
  101. package/src/composables/validation/useValidation.ts +165 -0
  102. package/src/designTokens/index.ts +4 -0
  103. package/src/stories/Demarrer/Accueil.mdx +1 -1
  104. package/src/stories/DesignTokens/ThemePA.mdx +4 -30
  105. package/src/stories/GuideDuDev/UtiliserLesRules.mdx +319 -76
  106. package/src/stories/GuideDuDev/moduleDeNotification.mdx +1 -1
  107. package/src/vuetifyConfig.ts +61 -0
  108. package/src/composables/useFilterable/__snapshots__/useFilterable.spec.ts.snap +0 -3
@@ -1,8 +1,9 @@
1
1
  import type { Meta, StoryObj } from '@storybook/vue3'
2
2
  import SyTextField from '@/components/Customs/SyTextField/SyTextField.vue'
3
3
  import { VIcon } from 'vuetify/components'
4
- import { ref } from 'vue'
4
+ import { ref, watch } from 'vue'
5
5
  import { mdiAccountBox } from '@mdi/js'
6
+ import { VBtn } from 'vuetify/components'
6
7
 
7
8
  const meta = {
8
9
  title: 'Composants/Formulaires/SyTextField',
@@ -14,7 +15,7 @@ const meta = {
14
15
  ],
15
16
  parameters: {
16
17
  layout: 'fullscreen',
17
- controls: { exclude: ['modelValue', 'appendInnerIconColor'] },
18
+ controls: { exclude: ['modelValue', 'appendInnerIconColor', 'errorMessages', 'warningMessages', 'successMessages'] },
18
19
  docs: {
19
20
  description: {
20
21
  component: `SyTextField`,
@@ -22,55 +23,292 @@ const meta = {
22
23
  },
23
24
  },
24
25
  argTypes: {
25
- modelValue: { control: 'text' },
26
- label: { control: 'text' },
27
- prependIcon: {
26
+ 'modelValue': { control: 'text' },
27
+ 'label': {
28
+ description: 'Texte affiché comme label du champ',
29
+ control: 'text',
30
+ },
31
+ 'prependIcon': {
28
32
  control: 'select',
29
33
  options: ['info', 'success', 'warning', 'error', 'close'],
30
34
  },
31
- appendIcon: {
35
+ 'appendIcon': {
32
36
  control: 'select',
33
37
  options: ['info', 'success', 'warning', 'error', 'close'],
34
38
  },
35
- prependInnerIcon: {
39
+ 'prependInnerIcon': {
36
40
  control: 'select',
37
41
  options: ['info', 'success', 'warning', 'error', 'close'],
38
42
  },
39
- appendInnerIcon: {
43
+ 'appendInnerIcon': {
40
44
  control: 'select',
41
45
  options: ['info', 'success', 'warning', 'error', 'close'],
42
46
  },
43
- variantStyle: {
47
+ 'variantStyle': {
44
48
  control: 'select',
45
49
  options: ['outlined', 'plain', 'underlined', 'filled', 'solo', 'solo-inverted', 'solo-filled'],
46
50
  },
47
- color: {
51
+ 'color': {
48
52
  control: 'select',
49
53
  options: ['primary', 'secondary', 'success', 'error', 'warning'],
50
54
  description: 'Couleur du champ',
51
55
  },
52
- density: {
56
+ 'density': {
53
57
  control: 'select',
54
58
  options: ['default', 'comfortable', 'compact'],
55
59
  description: 'Densité du champ',
56
60
  },
57
- direction: {
58
- control: 'select',
59
- options: ['horizontal', 'vertical'],
60
- description: 'Direction d\'affichage',
61
- },
62
- customRules: {
61
+ 'customRules': {
63
62
  description: 'Règles de validation personnalisées',
64
63
  control: 'object',
65
64
  },
66
- customWarningRules: {
65
+ 'customWarningRules': {
67
66
  description: 'Règles d\'avertissement personnalisées',
68
67
  control: 'object',
69
68
  },
70
- showSuccessMessages: {
69
+ 'showSuccessMessages': {
71
70
  description: 'Afficher les messages de succès',
72
71
  control: 'boolean',
73
72
  },
73
+ 'isValidateOnBlur': {
74
+ description: 'Vérifie la validité lors de la perte de focus',
75
+ control: 'boolean',
76
+ default: true,
77
+ },
78
+ 'isActive': {
79
+ description: 'Force l\'état actif du champ (label flottant et styles visuels)',
80
+ control: 'boolean',
81
+ default: false,
82
+ },
83
+ 'isClearable': {
84
+ description: 'Affiche un bouton pour effacer le contenu du champ',
85
+ control: 'boolean',
86
+ default: false,
87
+ },
88
+ 'prependTooltip': {
89
+ description: 'Si le texte du prepend tooltip est renseigné alors l\'icône du tooltip s\'affiche',
90
+ control: 'text',
91
+ },
92
+ 'appendTooltip': {
93
+ description: 'Si le texte du append tooltip est renseigné alors l\'icône du tooltip s\'affiche',
94
+ control: 'text',
95
+ },
96
+ 'tooltipLocation': {
97
+ description: 'Position des tooltips',
98
+ control: 'select',
99
+ options: ['top', 'bottom', 'start', 'end'],
100
+ default: 'top',
101
+ },
102
+ 'required': {
103
+ description: 'Indique si le champ est obligatoire',
104
+ control: 'boolean',
105
+ default: false,
106
+ },
107
+ 'displayAsterisk': {
108
+ description: 'Affiche un astérisque à côté du label',
109
+ control: 'boolean',
110
+ default: false,
111
+ },
112
+ 'isDisabled': {
113
+ description: 'Désactive le champ',
114
+ control: 'boolean',
115
+ default: false,
116
+ },
117
+ 'isReadOnly': {
118
+ description: 'Rend le champ en lecture seule',
119
+ control: 'boolean',
120
+ default: false,
121
+ },
122
+ 'baseColor': {
123
+ description: 'Couleur de base du champ (par défaut hérite de color)',
124
+ control: 'text',
125
+ },
126
+ 'bgColor': {
127
+ description: 'Couleur de fond du champ',
128
+ control: 'text',
129
+ },
130
+ 'centerAffix': {
131
+ description: 'Centre verticalement les éléments ajoutés avant/après le champ',
132
+ control: 'boolean',
133
+ },
134
+ 'counter': {
135
+ description: 'Affiche un compteur de caractères',
136
+ control: 'boolean',
137
+ },
138
+ 'counterValue': {
139
+ description: 'Fonction personnalisée pour calculer la valeur du compteur',
140
+ control: 'object',
141
+ },
142
+ 'direction': {
143
+ description: 'Direction du champ (horizontal ou vertical)',
144
+ control: 'select',
145
+ options: ['horizontal', 'vertical'],
146
+ },
147
+ 'isDirty': {
148
+ description: 'Indique si le champ a été modifié',
149
+ control: 'boolean',
150
+ },
151
+ 'isFlat': {
152
+ description: 'Supprime l\'élévation du champ',
153
+ control: 'boolean',
154
+ },
155
+ 'isFocused': {
156
+ description: 'Force l\'état focus du champ',
157
+ control: 'boolean',
158
+ },
159
+ 'areDetailsHidden': {
160
+ description: 'Masque la section des détails (messages d\'erreur, compteur)',
161
+ control: 'boolean',
162
+ },
163
+ 'areSpinButtonsHidden': {
164
+ description: 'Masque les boutons d\'incrémentation pour les champs numériques',
165
+ control: 'boolean',
166
+ },
167
+ 'hint': {
168
+ description: 'Texte d\'aide affiché sous le champ',
169
+ control: 'text',
170
+ },
171
+ 'loading': {
172
+ description: 'Affiche un indicateur de chargement',
173
+ control: 'boolean',
174
+ },
175
+ 'maxErrors': {
176
+ description: 'Nombre maximum de messages d\'erreur à afficher',
177
+ control: { type: 'text' },
178
+ },
179
+ 'maxWidth': {
180
+ description: 'Largeur maximale du champ',
181
+ control: { type: 'text' },
182
+ },
183
+ 'minWidth': {
184
+ description: 'Largeur minimale du champ',
185
+ control: { type: 'text' },
186
+ },
187
+ 'name': {
188
+ description: 'Nom du champ pour les formulaires',
189
+ control: 'text',
190
+ },
191
+ 'displayPersistentClear': {
192
+ description: 'Affiche toujours le bouton de réinitialisation',
193
+ control: 'boolean',
194
+ default: false,
195
+ },
196
+ 'displayPersistentCounter': {
197
+ description: 'Affiche toujours le compteur',
198
+ control: 'boolean',
199
+ default: false,
200
+ },
201
+ 'displayPersistentHint': {
202
+ description: 'Affiche toujours le texte d\'aide',
203
+ control: 'boolean',
204
+ default: false,
205
+ },
206
+ 'displayPersistentPlaceholder': {
207
+ description: 'Garde le placeholder visible même avec une valeur',
208
+ control: 'boolean',
209
+ default: false,
210
+ },
211
+ 'placeholder': {
212
+ description: 'Texte affiché quand le champ est vide',
213
+ control: 'text',
214
+ },
215
+ 'prefix': {
216
+ description: 'Texte affiché avant la valeur: prefix="€" : affichera "€" avant la valeur saisie',
217
+ control: 'text',
218
+ },
219
+ 'isReversed': {
220
+ description: 'Inverse l\'ordre des éléments',
221
+ control: 'boolean',
222
+ default: false,
223
+ },
224
+ 'role': {
225
+ description: 'Rôle ARIA du champ',
226
+ control: 'text',
227
+ },
228
+ 'rounded': {
229
+ description: 'Arrondit les coins du champ',
230
+ control: { type: 'text' },
231
+ },
232
+ 'isOnSingleLine': {
233
+ description: 'Force l\'affichage sur une seule ligne',
234
+ control: 'boolean',
235
+ default: false,
236
+ },
237
+ 'suffix': {
238
+ description: 'Texte affiché après la valeur',
239
+ control: 'text',
240
+ },
241
+ 'theme': {
242
+ description: 'Thème à appliquer au champ',
243
+ control: 'text',
244
+ },
245
+ 'isTiled': {
246
+ description: 'Applique un style tuile',
247
+ control: 'boolean',
248
+ default: false,
249
+ },
250
+ 'type': {
251
+ description: 'Type du champ de saisie',
252
+ control: 'select',
253
+ options: ['text', 'number', 'password', 'email', 'tel', 'url', 'search'],
254
+ default: 'text',
255
+ },
256
+ 'width': {
257
+ description: 'Largeur du champ',
258
+ control: { type: 'text' },
259
+ },
260
+ 'validation': {
261
+ description: 'Valide le champ avec la valeur donnée',
262
+ type: '(value: string | number | null) => void',
263
+ },
264
+ 'validateOnSubmit': {
265
+ description: 'Valide le champ lors de la soumission du formulaire',
266
+ type: '() => void',
267
+ },
268
+ 'checkErrorOnBlur': {
269
+ description: 'Vérifie les erreurs lors de la perte de focus',
270
+ type: '() => void',
271
+ },
272
+ 'append': {
273
+ description: 'Slot pour ajouter du contenu à droite du champ',
274
+ control: false,
275
+ table: {
276
+ type: { summary: 'VNode' },
277
+ category: 'slots',
278
+ },
279
+ },
280
+ 'prepend': {
281
+ description: 'Slot pour ajouter du contenu à gauche du champ',
282
+ control: false,
283
+ table: {
284
+ type: { summary: 'VNode' },
285
+ category: 'slots',
286
+ },
287
+ },
288
+ 'append-inner': {
289
+ description: 'Slot pour ajouter du contenu à droite dans le champ',
290
+ control: false,
291
+ table: {
292
+ type: { summary: 'VNode' },
293
+ category: 'slots',
294
+ },
295
+ },
296
+ 'prepend-inner': {
297
+ description: 'Slot pour ajouter du contenu à gauche dans le champ',
298
+ control: false,
299
+ table: {
300
+ type: { summary: 'VNode' },
301
+ category: 'slots',
302
+ },
303
+ },
304
+ 'details': {
305
+ description: 'Slot pour personnaliser la section des détails (messages d\'erreur, compteur)',
306
+ control: false,
307
+ table: {
308
+ type: { summary: 'VNode' },
309
+ category: 'slots',
310
+ },
311
+ },
74
312
  },
75
313
  } as Meta<typeof SyTextField>
76
314
 
@@ -110,7 +348,10 @@ export const Default: Story = {
110
348
  return {
111
349
  components: { SyTextField, VIcon },
112
350
  setup() {
113
- const value = ref('')
351
+ const value = ref(args.modelValue)
352
+ watch(() => args.modelValue, (newValue) => {
353
+ value.value = newValue
354
+ })
114
355
  return { args, value }
115
356
  },
116
357
  template: `
@@ -123,50 +364,82 @@ export const Default: Story = {
123
364
  }
124
365
 
125
366
  export const Required: Story = {
367
+ args: {
368
+ ...Default.args,
369
+ required: true,
370
+ },
126
371
  parameters: {
372
+ docs: {
373
+ description: {
374
+ story: `
375
+ ### Champ requis sans astérisque
376
+
377
+ Cette story montre un champ requis sans astérisque.
378
+ Pour afficher l'astérisque sur un champ requis, il faut activer la prop \`displayAsterisk\`.`,
379
+ },
380
+ },
127
381
  sourceCode: [
128
382
  {
129
383
  name: 'Template',
130
- code: `
131
- <template>
132
- <SyTextField
133
- v-model="value"
134
- required
135
- />
136
- </template>
137
- `,
384
+ code: `<template>
385
+ <SyTextField
386
+ v-model="value"
387
+ required
388
+ label="Champ requis sans astérisque"
389
+ />
390
+ </template>`,
138
391
  },
139
392
  {
140
393
  name: 'Script',
141
- code: `
142
- <script setup lang="ts">
143
- import { SyTextField } from '@cnamts/synapse'
144
- </script>
145
- `,
394
+ code: `<script setup lang="ts">
395
+ import { SyTextField } from '@cnamts/synapse'
396
+ import { ref } from 'vue'
397
+
398
+ const value = ref('')
399
+ </script>`,
146
400
  },
147
401
  ],
148
402
  },
403
+ }
404
+
405
+ export const RequiredWithAsterisk: Story = {
149
406
  args: {
150
- showDivider: false,
151
- variantStyle: 'outlined',
152
- color: 'primary',
153
- isClearable: true,
154
- label: 'Label',
407
+ ...Default.args,
155
408
  required: true,
156
- modelValue: '',
409
+ displayAsterisk: true,
157
410
  },
158
- render: (args) => {
159
- return {
160
- components: { SyTextField, VIcon },
161
- setup() {
162
- return { args }
411
+ parameters: {
412
+ docs: {
413
+ description: {
414
+ story: `
415
+ ### Champ requis avec astérisque
416
+
417
+ Cette story montre un champ requis avec astérisque.
418
+ L'astérisque ne peut être affiché que sur un champ requis, en activant la prop \`displayAsterisk\`.`,
163
419
  },
164
- template: `
165
- <div class="d-flex flex-wrap align-center">
166
- <SyTextField v-bind="args" />
167
- </div>
168
- `,
169
- }
420
+ },
421
+ sourceCode: [
422
+ {
423
+ name: 'Template',
424
+ code: `<template>
425
+ <SyTextField
426
+ v-model="value"
427
+ required
428
+ display-asterisk
429
+ label="Champ requis avec astérisque"
430
+ />
431
+ </template>`,
432
+ },
433
+ {
434
+ name: 'Script',
435
+ code: `<script setup lang="ts">
436
+ import { SyTextField } from '@cnamts/synapse'
437
+ import { ref } from 'vue'
438
+
439
+ const value = ref('')
440
+ </script>`,
441
+ },
442
+ ],
170
443
  },
171
444
  }
172
445
 
@@ -207,15 +480,15 @@ export const SlotPrepend: Story = {
207
480
  return {
208
481
  components: { SyTextField, VIcon },
209
482
  setup() {
210
- return { args }
483
+ const value = ref(args.modelValue)
484
+ watch(() => args.modelValue, (newValue) => {
485
+ value.value = newValue
486
+ })
487
+ return { args, value }
211
488
  },
212
489
  template: `
213
490
  <div class="d-flex flex-wrap align-center">
214
- <SyTextField
215
- v-bind="args"
216
- :label="args.label"
217
- :prepend-icon="args.prependIcon"
218
- />
491
+ <SyTextField v-bind="args" v-model="value" />
219
492
  </div>
220
493
  `,
221
494
  }
@@ -259,14 +532,15 @@ export const SlotAppend: Story = {
259
532
  return {
260
533
  components: { SyTextField, VIcon },
261
534
  setup() {
262
- return { args }
535
+ const value = ref(args.modelValue)
536
+ watch(() => args.modelValue, (newValue) => {
537
+ value.value = newValue
538
+ })
539
+ return { args, value }
263
540
  },
264
541
  template: `
265
542
  <div class="d-flex flex-wrap align-center">
266
- <SyTextField
267
- v-bind="args"
268
- :append-icon="args.appendIcon"
269
- />
543
+ <SyTextField v-bind="args" v-model="value" />
270
544
  </div>
271
545
  `,
272
546
  }
@@ -310,14 +584,15 @@ export const SlotPrependInner: Story = {
310
584
  return {
311
585
  components: { SyTextField, VIcon },
312
586
  setup() {
313
- return { args }
587
+ const value = ref(args.modelValue)
588
+ watch(() => args.modelValue, (newValue) => {
589
+ value.value = newValue
590
+ })
591
+ return { args, value }
314
592
  },
315
593
  template: `
316
594
  <div class="d-flex flex-wrap align-center">
317
- <SyTextField
318
- v-bind="args"
319
- :prepend-inner-icon="args.prependInnerIcon"
320
- />
595
+ <SyTextField v-bind="args" v-model="value" />
321
596
  </div>
322
597
  `,
323
598
  }
@@ -362,15 +637,15 @@ export const SlotPrependInnerDivider: Story = {
362
637
  return {
363
638
  components: { SyTextField, VIcon },
364
639
  setup() {
365
- return { args }
640
+ const value = ref(args.modelValue)
641
+ watch(() => args.modelValue, (newValue) => {
642
+ value.value = newValue
643
+ })
644
+ return { args, value }
366
645
  },
367
646
  template: `
368
647
  <div class="d-flex flex-wrap align-center">
369
- <SyTextField
370
- v-bind="args"
371
- :prepend-inner-icon="args.prependInnerIcon"
372
- :show-divider="args.showDivider"
373
- />
648
+ <SyTextField v-bind="args" v-model="value" />
374
649
  </div>
375
650
  `,
376
651
  }
@@ -414,14 +689,15 @@ export const SlotAppendInner: Story = {
414
689
  return {
415
690
  components: { SyTextField, VIcon },
416
691
  setup() {
417
- return { args }
692
+ const value = ref(args.modelValue)
693
+ watch(() => args.modelValue, (newValue) => {
694
+ value.value = newValue
695
+ })
696
+ return { args, value }
418
697
  },
419
698
  template: `
420
699
  <div class="d-flex flex-wrap align-center">
421
- <SyTextField
422
- v-bind="args"
423
- :append-inner-icon="args.appendInnerIcon"
424
- />
700
+ <SyTextField v-bind="args" v-model="value" />
425
701
  </div>
426
702
  `,
427
703
  }
@@ -470,15 +746,17 @@ export const SlotCustomIcon: Story = {
470
746
  return {
471
747
  components: { SyTextField, VIcon },
472
748
  setup() {
749
+ const value = ref(args.modelValue)
750
+ watch(() => args.modelValue, (newValue) => {
751
+ value.value = newValue
752
+ })
473
753
  const iconName = ref(mdiAccountBox)
474
754
 
475
- return { args, iconName }
755
+ return { args, value, iconName }
476
756
  },
477
757
  template: `
478
758
  <div class="d-flex flex-wrap align-center">
479
- <SyTextField
480
- v-bind="args"
481
- >
759
+ <SyTextField v-bind="args" v-model="value">
482
760
  <template #append-inner>
483
761
  <VIcon>
484
762
  {{ iconName }}
@@ -574,10 +852,10 @@ Cette story montre l'utilisation combinée des règles standard et d'avertisseme
574
852
  required
575
853
  :customWarningRules="[
576
854
  {
577
- type: 'maxLength',
855
+ type: 'minLength',
578
856
  options: {
579
857
  length: 10,
580
- message: 'Le texte commence à être un peu long'
858
+ message: 'Le texte doit comporter plus de 10 caracteres'
581
859
  }
582
860
  }
583
861
  ]"
@@ -600,10 +878,10 @@ Cette story montre l'utilisation combinée des règles standard et d'avertisseme
600
878
  required
601
879
  :customWarningRules="[
602
880
  {
603
- type: 'maxLength',
881
+ type: 'minLength',
604
882
  options: {
605
883
  length: 10,
606
- message: 'Le texte comporte plus de 10 caracteres'
884
+ message: 'Le texte doit comporter plus de 10 caracteres'
607
885
  }
608
886
  }
609
887
  ]"
@@ -739,6 +1017,169 @@ Cette story montre l'utilisation de la règle \`matchPattern\` pour valider un f
739
1017
  }),
740
1018
  }
741
1019
 
1020
+ export const WithTooltips: Story = {
1021
+ args: {
1022
+ modelValue: '',
1023
+ label: 'Champ avec tooltips',
1024
+ prependTooltip: 'Information à gauche du champ',
1025
+ appendTooltip: 'Information à droite du champ',
1026
+ tooltipLocation: 'top',
1027
+ },
1028
+ render: args => ({
1029
+ components: { SyTextField },
1030
+ setup() {
1031
+ const value = ref(args.modelValue)
1032
+ return { args, value }
1033
+ },
1034
+ template: `
1035
+ <div>
1036
+ <p class="mb-4">
1037
+ Des icônes d'information avec tooltips sont affichées de chaque côté du champ.
1038
+ Survolez-les pour voir les messages d'aide qui apparaissent en haut grâce à la prop tooltipLocation="top".
1039
+ </p>
1040
+ <SyTextField
1041
+ v-model="value"
1042
+ v-bind="args"
1043
+ />
1044
+ </div>
1045
+ `,
1046
+ }),
1047
+ parameters: {
1048
+ docs: {
1049
+ description: {
1050
+ story: 'Exemple de champ avec des tooltips d\'information. Les icônes d\'information apparaissent automatiquement lorsque les props prependTooltip et/ou appendTooltip sont renseignées. La position des tooltips peut être contrôlée avec la prop tooltipLocation.',
1051
+ },
1052
+ },
1053
+ sourceCode: [
1054
+ {
1055
+ name: 'Template',
1056
+ code: `
1057
+ <template>
1058
+ <SyTextField
1059
+ v-model="value"
1060
+ label="Champ avec tooltips"
1061
+ prependTooltip="Information à gauche du champ"
1062
+ appendTooltip="Information à droite du champ"
1063
+ tooltipLocation="top"
1064
+ />
1065
+ </template>
1066
+ `,
1067
+ },
1068
+ ],
1069
+ },
1070
+ }
1071
+
1072
+ /**
1073
+ * Story avec validation désactivée au blur
1074
+ */
1075
+ export const ValidateOnBlur: Story = {
1076
+ args: {
1077
+ modelValue: '',
1078
+ label: 'Champ texte',
1079
+ required: true,
1080
+ isValidateOnBlur: true,
1081
+ customRules: [
1082
+ {
1083
+ type: 'custom',
1084
+ options: {
1085
+ message: 'Le champ doit contenir au moins 3 caractères',
1086
+ validate: (value: string) => value.length >= 3,
1087
+ },
1088
+ },
1089
+ ],
1090
+ },
1091
+ render: args => ({
1092
+ components: { SyTextField, VBtn },
1093
+ setup() {
1094
+ const value = ref(args.modelValue)
1095
+ const fieldRef = ref()
1096
+
1097
+ function handleSubmit() {
1098
+ const isValid = fieldRef.value?.validateOnSubmit()
1099
+ alert(isValid ? 'Formulaire valide !' : 'Formulaire invalide, veuillez corriger les erreurs.')
1100
+ }
1101
+
1102
+ return { args, value, fieldRef, handleSubmit }
1103
+ },
1104
+ template: `
1105
+ <form @submit.prevent="handleSubmit">
1106
+ <p class="mb-4">
1107
+ La validation ne se déclenche qu'à la perte de focus ou à la soumission du formulaire.
1108
+ </p>
1109
+ <SyTextField
1110
+ ref="fieldRef"
1111
+ v-model="value"
1112
+ v-bind="args"
1113
+ @update:model-value="args.modelValue = $event"
1114
+ />
1115
+ <div class="mt-4">
1116
+ <VBtn type="submit" color="primary">
1117
+ Valider
1118
+ </VBtn>
1119
+ </div>
1120
+ </form>
1121
+ `,
1122
+ }),
1123
+ parameters: {
1124
+ docs: {
1125
+ description: {
1126
+ story: 'Exemple de champ avec validation désactivée au blur. La validation ne se déclenche que lors de la soumission du formulaire.',
1127
+ },
1128
+ },
1129
+ sourceCode: [
1130
+ {
1131
+ name: 'Template',
1132
+ code: `
1133
+ <template>
1134
+ <form @submit.prevent="handleSubmit">
1135
+ <SyTextField
1136
+ ref="fieldRef"
1137
+ v-model="value"
1138
+ label="Champ texte"
1139
+ required
1140
+ :is-validate-on-blur="true"
1141
+ :custom-rules="[
1142
+ {
1143
+ type: 'custom',
1144
+ options: {
1145
+ message: 'Le champ doit contenir au moins 3 caractères',
1146
+ validate: value => value.length >= 3
1147
+ }
1148
+ }
1149
+ ]"
1150
+ />
1151
+ <button type="submit">
1152
+ Valider
1153
+ </button>
1154
+ </form>
1155
+ </template>
1156
+ `,
1157
+ },
1158
+ {
1159
+ name: 'Script',
1160
+ code: `
1161
+ <script setup lang="ts">
1162
+ import { ref } from 'vue'
1163
+ import { SyTextField } from '@cnamts/synapse'
1164
+
1165
+ const value = ref('')
1166
+ const fieldRef = ref()
1167
+
1168
+ function handleSubmit() {
1169
+ const isValid = fieldRef.value?.validateOnSubmit()
1170
+ if (!isValid) {
1171
+ // Gérer l'erreur
1172
+ return
1173
+ }
1174
+ // Continuer avec la soumission
1175
+ }
1176
+ </script>
1177
+ `,
1178
+ },
1179
+ ],
1180
+ },
1181
+ }
1182
+
742
1183
  export const FormValidation: Story = {
743
1184
  render: args => ({
744
1185
  components: { SyTextField },
@@ -868,3 +1309,53 @@ export const FormValidation: Story = {
868
1309
  `,
869
1310
  }),
870
1311
  }
1312
+
1313
+ export const WithPrefixAndSuffix: Story = {
1314
+ args: {
1315
+ modelValue: '42',
1316
+ label: 'Montant',
1317
+ prefix: '€',
1318
+ suffix: 'TTC',
1319
+ },
1320
+ render: args => ({
1321
+ components: { SyTextField },
1322
+ setup() {
1323
+ const value = ref(args.modelValue)
1324
+ return { args, value }
1325
+ },
1326
+ template: `
1327
+ <div>
1328
+ <p class="mb-4">
1329
+ Utilisation des props prefix et suffix pour ajouter des unités ou des informations complémentaires
1330
+ directement dans le champ.
1331
+ </p>
1332
+ <SyTextField
1333
+ v-model="value"
1334
+ v-bind="args"
1335
+ />
1336
+ </div>
1337
+ `,
1338
+ }),
1339
+ parameters: {
1340
+ docs: {
1341
+ description: {
1342
+ story: 'Exemple d\'utilisation des props prefix et suffix pour ajouter des informations complémentaires directement dans le champ de saisie.',
1343
+ },
1344
+ },
1345
+ sourceCode: [
1346
+ {
1347
+ name: 'Template',
1348
+ code: `
1349
+ <template>
1350
+ <SyTextField
1351
+ v-model="value"
1352
+ label="Montant"
1353
+ prefix="€"
1354
+ suffix="TTC"
1355
+ />
1356
+ </template>
1357
+ `,
1358
+ },
1359
+ ],
1360
+ },
1361
+ }