@cnamts/synapse 0.0.8-alpha → 0.0.9-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 (111) hide show
  1. package/dist/design-system-v3.d.ts +584 -128
  2. package/dist/design-system-v3.js +4176 -2694
  3. package/dist/design-system-v3.umd.cjs +1 -1
  4. package/dist/style.css +1 -1
  5. package/package.json +1 -1
  6. package/src/assets/settings.scss +1 -1
  7. package/src/components/ContextualMenu/Accessibilite.mdx +14 -0
  8. package/src/components/ContextualMenu/Accessibilite.stories.ts +191 -0
  9. package/src/components/ContextualMenu/AccessibiliteItems.ts +89 -0
  10. package/src/components/ContextualMenu/constants/ExpertiseLevelEnum.ts +4 -0
  11. package/src/components/Customs/SySelect/SySelect.stories.ts +7 -7
  12. package/src/components/Customs/SySelect/SySelect.vue +9 -4
  13. package/src/components/Customs/SySelect/tests/SySelect.spec.ts +2 -2
  14. package/src/components/Customs/SyTextField/SyTextField.stories.ts +187 -2
  15. package/src/components/Customs/SyTextField/SyTextField.vue +185 -16
  16. package/src/components/Customs/SyTextField/tests/SyTextField.spec.ts +2 -4
  17. package/src/components/Customs/SyTextField/tests/__snapshots__/SyTextField.spec.ts.snap +18 -16
  18. package/src/components/Customs/SyTextField/types.d.ts +2 -2
  19. package/src/components/DatePicker/DatePicker.mdx +191 -0
  20. package/src/components/DatePicker/DatePicker.stories.ts +787 -0
  21. package/src/components/DatePicker/DatePicker.vue +560 -0
  22. package/src/components/DatePicker/DateTextInput.vue +409 -0
  23. package/src/components/DatePicker/tests/DatePicker.spec.ts +266 -0
  24. package/src/components/DialogBox/DialogBox.stories.ts +1 -1
  25. package/src/components/ExternalLinks/Accessibilite.mdx +14 -0
  26. package/src/components/ExternalLinks/Accessibilite.stories.ts +191 -0
  27. package/src/components/ExternalLinks/AccessibiliteItems.ts +197 -0
  28. package/src/components/ExternalLinks/constants/ExpertiseLevelEnum.ts +4 -0
  29. package/src/components/ExternalLinks/tests/__snapshots__/ExternalLinks.spec.ts.snap +9 -9
  30. package/src/components/FileUpload/FileUpload.mdx +165 -0
  31. package/src/components/FileUpload/FileUpload.stories.ts +429 -0
  32. package/src/components/FileUpload/FileUpload.vue +195 -0
  33. package/src/components/FileUpload/FileUploadContent.vue +109 -0
  34. package/src/components/FileUpload/locales.ts +10 -0
  35. package/src/components/FileUpload/tests/FileUpload.spec.ts +332 -0
  36. package/src/components/FileUpload/tests/__snapshots__/FileUpload.spec.ts.snap +7 -0
  37. package/src/components/FileUpload/useFileDrop.ts +23 -0
  38. package/src/components/FileUpload/validateFiles.ts +39 -0
  39. package/src/components/NirField/NirField.stories.ts +1 -1
  40. package/src/components/NirField/NirField.vue +2 -1
  41. package/src/components/PasswordField/Accessibilite.mdx +14 -0
  42. package/src/components/PasswordField/Accessibilite.stories.ts +191 -0
  43. package/src/components/PasswordField/AccessibiliteItems.ts +184 -0
  44. package/src/components/PasswordField/PasswordField.vue +3 -3
  45. package/src/components/PasswordField/constants/ExpertiseLevelEnum.ts +4 -0
  46. package/src/components/PhoneField/PhoneField.vue +44 -60
  47. package/src/components/PhoneField/tests/PhoneField.spec.ts +0 -15
  48. package/src/components/RangeField/RangeField.mdx +54 -0
  49. package/src/components/RangeField/RangeField.stories.ts +189 -0
  50. package/src/components/RangeField/RangeField.vue +157 -0
  51. package/src/components/RangeField/RangeSlider/RangeSlider.vue +387 -0
  52. package/src/components/RangeField/RangeSlider/Tooltip/Tooltip.vue +64 -0
  53. package/src/components/RangeField/RangeSlider/tests/__snapshots__/rangeSlider.spec.ts.snap +27 -0
  54. package/src/components/RangeField/RangeSlider/tests/rangeSlider.spec.ts +100 -0
  55. package/src/components/RangeField/RangeSlider/tests/useDoubleSlider.spec.ts +246 -0
  56. package/src/components/RangeField/RangeSlider/tests/useMouseSlide.spec.ts +204 -0
  57. package/src/components/RangeField/RangeSlider/tests/useThumb.spec.ts +22 -0
  58. package/src/components/RangeField/RangeSlider/tests/useThumbKeyboard.spec.ts +233 -0
  59. package/src/components/RangeField/RangeSlider/tests/useTooltipsNudge.spec.ts +150 -0
  60. package/src/components/RangeField/RangeSlider/tests/useTrack.spec.ts +314 -0
  61. package/src/components/RangeField/RangeSlider/tests/vAnimateClick.spec.ts +32 -0
  62. package/src/components/RangeField/RangeSlider/types.ts +15 -0
  63. package/src/components/RangeField/RangeSlider/useMouseSlide.ts +109 -0
  64. package/src/components/RangeField/RangeSlider/useRangeSlider.ts +126 -0
  65. package/src/components/RangeField/RangeSlider/useThumb.ts +18 -0
  66. package/src/components/RangeField/RangeSlider/useThumbKeyboard.ts +84 -0
  67. package/src/components/RangeField/RangeSlider/useTooltipsNudge.ts +92 -0
  68. package/src/components/RangeField/RangeSlider/useTrack.ts +116 -0
  69. package/src/components/RangeField/RangeSlider/vAnimateClick.ts +19 -0
  70. package/src/components/RangeField/config.ts +7 -0
  71. package/src/components/RangeField/locales.ts +4 -0
  72. package/src/components/RangeField/tests/RangeField.spec.ts +224 -0
  73. package/src/components/RangeField/tests/__snapshots__/RangeField.spec.ts.snap +379 -0
  74. package/src/components/RatingPicker/EmotionPicker/EmotionPicker.vue +205 -0
  75. package/src/components/RatingPicker/EmotionPicker/locales.ts +3 -0
  76. package/src/components/RatingPicker/EmotionPicker/tests/EmotionPicker.spec.ts +104 -0
  77. package/src/components/RatingPicker/EmotionPicker/tests/__snapshots__/EmotionPicker.spec.ts.snap +66 -0
  78. package/src/components/RatingPicker/NumberPicker/NumberPicker.vue +159 -0
  79. package/src/components/RatingPicker/NumberPicker/locales.ts +4 -0
  80. package/src/components/RatingPicker/NumberPicker/tests/NumberPicker.spec.ts +73 -0
  81. package/src/components/RatingPicker/NumberPicker/tests/__snapshots__/NumberPicker.spec.ts.snap +105 -0
  82. package/src/components/RatingPicker/Rating.ts +45 -0
  83. package/src/components/RatingPicker/RatingPicker.mdx +56 -0
  84. package/src/components/RatingPicker/RatingPicker.stories.ts +515 -0
  85. package/src/components/RatingPicker/RatingPicker.vue +122 -0
  86. package/src/components/RatingPicker/StarsPicker/StarsPicker.vue +116 -0
  87. package/src/components/RatingPicker/StarsPicker/tests/StarsPicker.spec.ts +95 -0
  88. package/src/components/RatingPicker/StarsPicker/tests/__snapshots__/StarsPicker.spec.ts.snap +36 -0
  89. package/src/components/RatingPicker/locales.ts +3 -0
  90. package/src/components/RatingPicker/tests/Rating.spec.ts +104 -0
  91. package/src/components/RatingPicker/tests/RatingPicker.spec.ts +187 -0
  92. package/src/components/RatingPicker/tests/__snapshots__/RatingPicker.spec.ts.snap +108 -0
  93. package/src/components/SearchListField/SearchListField.mdx +74 -0
  94. package/src/components/SearchListField/SearchListField.stories.ts +126 -0
  95. package/src/components/SearchListField/SearchListField.vue +194 -0
  96. package/src/components/SearchListField/locales.ts +5 -0
  97. package/src/components/SearchListField/tests/SearchListField.spec.ts +323 -0
  98. package/src/components/SearchListField/types.d.ts +4 -0
  99. package/src/components/SelectBtnField/SelectBtnField.mdx +50 -0
  100. package/src/components/SelectBtnField/SelectBtnField.stories.ts +763 -0
  101. package/src/components/SelectBtnField/SelectBtnField.vue +283 -0
  102. package/src/components/SelectBtnField/config.ts +11 -0
  103. package/src/components/SelectBtnField/tests/SelectBtnField.spec.ts +327 -0
  104. package/src/components/SelectBtnField/tests/__snapshots__/SelectBtnField.spec.ts.snap +125 -0
  105. package/src/components/SelectBtnField/types.d.ts +11 -0
  106. package/src/components/index.ts +8 -1
  107. package/src/composables/rules/useFieldValidation.ts +172 -44
  108. package/src/designTokens/index.ts +3 -3
  109. package/src/stories/Fondamentaux/CustomisationEtThemes.mdx +52 -2
  110. package/src/utils/calcHumanFileSize/index.ts +12 -0
  111. package/src/utils/calcHumanFileSize/tests/calcHumanFileSize.spec.ts +21 -0
@@ -1,5 +1,5 @@
1
1
  <script lang="ts" setup>
2
- import { computed, ref } from 'vue'
2
+ import { computed, ref, watch } from 'vue'
3
3
  import type { IconType, VariantStyle, ColorType } from './types'
4
4
  import {
5
5
  mdiAlertOutline,
@@ -7,12 +7,12 @@
7
7
  mdiInformationOutline,
8
8
  mdiClose,
9
9
  mdiInformation,
10
+ mdiCalendar,
10
11
  } from '@mdi/js'
11
12
 
12
- // only variantStyle need a default value
13
- /* eslint-disable vue/require-default-prop */
14
13
  const props = withDefaults(
15
14
  defineProps<{
15
+ modelValue?: string | number | null
16
16
  prependIcon?: IconType
17
17
  appendIcon?: IconType
18
18
  prependInnerIcon?: IconType
@@ -23,22 +23,121 @@
23
23
  showDivider?: boolean
24
24
  label?: string
25
25
  required?: boolean
26
- errorMessages?: string[]
26
+ errorMessages?: string[] | null
27
+ isReadOnly?: boolean
28
+ isActive?: boolean
29
+ baseColor?: string
30
+ bgColor?: string
31
+ centerAffix?: boolean
32
+ counter?: string | number | boolean
33
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- This is a generic type
34
+ counterValue?: number | ((value: any) => number)
35
+ density?: 'default' | 'comfortable' | 'compact'
36
+ direction?: 'horizontal' | 'vertical'
37
+ isDirty?: boolean
38
+ isDisabled?: boolean
39
+ isOnError?: boolean
40
+ isFlat?: boolean
41
+ isFocused?: boolean
42
+ areDetailsHidden?: boolean | 'auto'
43
+ areSpinButtonsHidden?: boolean
44
+ hint?: string
45
+ id?: string
46
+ loading?: string | boolean
47
+ maxErrors?: string | number
48
+ maxWidth?: string | number
49
+ messages?: string | string[]
50
+ minWidth?: string | number
51
+ name?: string
52
+ displayPersistentClear?: boolean
53
+ displayPersistentCounter?: boolean
54
+ displayPersistentHint?: boolean
55
+ displayPersistentPlaceholder?: boolean
56
+ placeholder?: string
57
+ prefix?: string
58
+ isReversed?: boolean
59
+ role?: string
60
+ rounded?: string | number | boolean
61
+ isOnSingleLine?: boolean
62
+ suffix?: string
63
+ theme?: string
64
+ isTiled?: boolean
65
+ type?: string
66
+ width?: string | number
67
+ displayAsterisk?: boolean
68
+ noIcon?: boolean
27
69
  }>(),
28
70
  {
29
- variantStyle: 'outlined', // Remplacez par la valeur par défaut souhaitée
71
+ modelValue: undefined,
72
+ prependIcon: undefined,
73
+ appendIcon: undefined,
74
+ appendInnerIcon: undefined,
75
+ prependInnerIcon: undefined,
76
+ variantStyle: 'outlined',
77
+ color: 'primary',
78
+ label: 'custom label',
79
+ errorMessages: null,
80
+ isReadOnly: false,
81
+ isClearable: false,
82
+ isActive: false,
83
+ baseColor: undefined,
84
+ bgColor: undefined,
85
+ centerAffix: undefined,
86
+ counter: false,
87
+ counterValue: undefined,
88
+ density: 'default',
89
+ direction: 'horizontal',
90
+ isDirty: false,
91
+ isDisabled: false,
92
+ isOnError: false,
93
+ isFlat: false,
94
+ isFocused: false,
95
+ areDetailsHidden: false,
96
+ areSpinButtonsHidden: false,
97
+ hint: undefined,
98
+ id: undefined,
99
+ loading: false,
100
+ maxErrors: 2,
101
+ maxWidth: undefined,
102
+ messages: undefined,
103
+ minWidth: undefined,
104
+ name: undefined,
105
+ displayPersistentClear: false,
106
+ displayPersistentCounter: false,
107
+ displayPersistentHint: false,
108
+ displayPersistentPlaceholder: false,
109
+ placeholder: undefined,
110
+ prefix: undefined,
111
+ isReversed: false,
112
+ role: undefined,
113
+ rounded: undefined,
114
+ isOnSingleLine: false,
115
+ suffix: undefined,
116
+ theme: undefined,
117
+ isTiled: false,
118
+ type: 'text',
119
+ width: undefined,
120
+ displayAsterisk: false,
121
+ noIcon: false,
30
122
  },
31
123
  )
32
124
 
33
- const ICONS: Record<IconType, string> = {
125
+ const ICONS: Record<NonNullable<IconType>, string> = {
34
126
  info: mdiInformationOutline,
35
127
  success: mdiCheck,
36
128
  warning: mdiAlertOutline,
37
129
  error: mdiInformation,
38
130
  close: mdiClose,
131
+ calendar: mdiCalendar,
39
132
  }
40
133
 
41
- const model = ref('')
134
+ const model = computed({
135
+ get: () => props.modelValue,
136
+ set: (value) => {
137
+ emit('update:model-value', value)
138
+ },
139
+ })
140
+
42
141
  const isBlurred = ref(false)
43
142
 
44
143
  const hasError = computed(() => {
@@ -50,11 +149,19 @@
50
149
  }
51
150
 
52
151
  const appendInnerIconColor = computed(() => {
53
- return props.appendInnerIcon === 'error' || props.appendInnerIcon === 'success'
152
+ return props.appendInnerIcon === 'error' || props.appendInnerIcon === 'success' || props.appendInnerIcon === 'warning'
54
153
  ? props.appendInnerIcon
55
154
  : 'black'
56
155
  })
57
156
 
157
+ const isShouldDisplayAsterisk = computed(() => {
158
+ return props.displayAsterisk && props.required
159
+ })
160
+
161
+ const labelWithAsterisk = computed(() => {
162
+ return isShouldDisplayAsterisk.value ? `${props.label} *` : props.label
163
+ })
164
+
58
165
  const dividerProps = {
59
166
  thickness: 2,
60
167
  length: '25px',
@@ -62,6 +169,14 @@
62
169
  opacity: '1',
63
170
  }
64
171
 
172
+ const emit = defineEmits(['update:model-value', 'clear', 'prepend-icon-click', 'append-icon-click'])
173
+
174
+ watch(model, (newValue) => {
175
+ if (props.isClearable && newValue === '') {
176
+ emit('clear')
177
+ }
178
+ })
179
+
65
180
  defineExpose({
66
181
  appendInnerIconColor,
67
182
  })
@@ -69,37 +184,90 @@
69
184
 
70
185
  <template>
71
186
  <VTextField
187
+ :id="props.id"
72
188
  v-model="model"
189
+ :active="props.isActive"
73
190
  :aria-label="props.label"
191
+ :base-color="props.baseColor"
192
+ :bg-color="props.bgColor"
193
+ :center-affix="props.centerAffix"
74
194
  :clear-icon="ICONS.close"
75
195
  :clearable="props.isClearable"
76
196
  :color="props.color"
197
+ :counter-value="props.counterValue"
198
+ :density="props.density"
199
+ :direction="props.direction"
200
+ :dirty="props.isDirty"
201
+ :disabled="props.isDisabled"
202
+ :display-asterisk="isShouldDisplayAsterisk"
203
+ :error="props.isOnError"
77
204
  :error-messages="props.errorMessages"
78
- :label="props.label"
205
+ :flat="props.isFlat"
206
+ :focused="props.isFocused"
207
+ :hide-details="props.areDetailsHidden"
208
+ :hide-spin-buttons="props.areSpinButtonsHidden"
209
+ :hint="props.hint"
210
+ :label="labelWithAsterisk"
211
+ :loading="props.loading"
212
+ :max-errors="props.maxErrors"
213
+ :max-width="props.maxWidth"
214
+ :messages="props.messages"
215
+ :min-width="props.minWidth"
216
+ :name="props.name"
217
+ :no-icon="props.noIcon"
218
+ :persistent-clear="props.displayPersistentClear"
219
+ :persistent-counter="props.displayPersistentCounter"
220
+ :persistent-hint="props.displayPersistentHint"
221
+ :persistent-placeholder="displayPersistentPlaceholder"
222
+ :placeholder="props.placeholder"
223
+ :prefix="props.prefix"
224
+ :readonly="props.isReadOnly"
225
+ :reverse="props.isReversed"
226
+ :role="props.role"
227
+ :rounded="props.rounded"
79
228
  :rules="props.required ? ['Le champ est requis.'] : []"
229
+ :single-line="props.isOnSingleLine"
230
+ :suffix="props.suffix"
231
+ :theme="props.theme"
232
+ :tile="props.isTiled"
233
+ :type="props.type"
80
234
  :variant="props.variantStyle"
235
+ :width="props.width"
81
236
  @blur="checkErrorOnBlur"
82
237
  >
83
- <template #prepend>
238
+ <template
239
+ v-if="props.prependIcon && !props.noIcon"
240
+ #prepend
241
+ >
84
242
  <slot name="prepend">
85
243
  <VIcon
86
- v-if="props.prependIcon"
244
+ :aria-label="props.label ? `${props.label} - bouton ${props.prependIcon}` : `Bouton ${props.prependIcon}`"
245
+ :color="appendInnerIconColor"
87
246
  :icon="ICONS[props.prependIcon]"
247
+ role="button"
248
+ @click="$emit('prepend-icon-click')"
88
249
  />
89
250
  </slot>
90
251
  </template>
91
- <template #append>
252
+ <template
253
+ v-if="props.appendIcon && !props.noIcon"
254
+ #append
255
+ >
92
256
  <slot name="append">
93
257
  <VIcon
94
- v-if="props.appendIcon"
258
+ :aria-label="props.label ? `${props.label} - bouton ${props.appendIcon}` : `Bouton ${props.appendIcon}`"
259
+ :color="appendInnerIconColor"
95
260
  :icon="ICONS[props.appendIcon]"
261
+ role="button"
262
+ @click="$emit('append-icon-click')"
96
263
  />
97
264
  </slot>
98
265
  </template>
99
266
  <template #prepend-inner>
100
267
  <slot name="prepend-inner">
101
268
  <VIcon
102
- v-if="props.prependInnerIcon"
269
+ v-if="props.prependInnerIcon && !props.noIcon"
270
+ :aria-label="props.label ? `${props.label} - bouton ${props.prependInnerIcon}` : `Bouton ${props.prependInnerIcon}`"
103
271
  :icon="ICONS[props.prependInnerIcon]"
104
272
  />
105
273
  </slot>
@@ -112,11 +280,12 @@
112
280
  </template>
113
281
  <template #append-inner>
114
282
  <slot name="append-inner">
115
- <VIcon v-if="hasError">
283
+ <VIcon v-if="hasError && !props.appendInnerIcon">
116
284
  {{ mdiInformation }}
117
285
  </VIcon>
118
286
  <VIcon
119
- v-if="props.appendInnerIcon"
287
+ v-if="props.appendInnerIcon && !props.noIcon"
288
+ :aria-label="props.label ? `${props.label} - bouton ${props.appendInnerIcon}` : `Bouton ${props.appendInnerIcon}`"
120
289
  :class="{ 'error-icon': props.appendInnerIcon === 'error' }"
121
290
  :color="appendInnerIconColor"
122
291
  :icon="ICONS[props.appendInnerIcon]"
@@ -33,13 +33,11 @@ describe('SyTextField', () => {
33
33
  append: '<div data-testid="append-slot">Append Slot Content</div>',
34
34
  })
35
35
 
36
- const prependSlot = wrapper.find('[data-testid="prepend-slot"]')
37
- const appendSlot = wrapper.find('[data-testid="append-slot"]')
36
+ const prependSlot = wrapper.find('.v-field--prepended')
37
+ const appendSlot = wrapper.find('.v-field--appended')
38
38
 
39
39
  expect(prependSlot.exists()).toBe(true)
40
- expect(prependSlot.text()).toBe('Prepend Slot Content')
41
40
  expect(appendSlot.exists()).toBe(true)
42
- expect(appendSlot.text()).toBe('Append Slot Content')
43
41
  })
44
42
 
45
43
  it('renders inner slots correctly', () => {
@@ -2,41 +2,43 @@
2
2
 
3
3
  exports[`SyTextField > matches snapshot 1`] = `
4
4
  "<div class="v-input v-input--horizontal v-input--center-affix v-input--density-default v-theme--light v-locale--is-ltr v-text-field">
5
- <div class="v-input__prepend"><i class="M11,9H13V7H11M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M11,17H13V11H11V17Z mdi v-icon notranslate v-theme--light v-icon--size-default" aria-hidden="true"></i>
5
+ <div class="v-input__prepend"><i class="M11,9H13V7H11M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M11,17H13V11H11V17Z mdi v-icon notranslate v-theme--light v-icon--size-default text-error v-icon--clickable" role="button" aria-hidden="false" tabindex="0" aria-label="custom label - bouton info"></i>
6
6
  <!---->
7
7
  </div>
8
8
  <div class="v-input__control">
9
- <div class="v-field v-field--appended v-field--center-affix v-field--prepended v-field--no-label v-field--variant-filled v-theme--light v-locale--is-ltr">
9
+ <div class="v-field v-field--appended v-field--center-affix v-field--prepended v-field--variant-filled v-theme--light v-locale--is-ltr">
10
10
  <div class="v-field__overlay"></div>
11
11
  <div class="v-field__loader">
12
12
  <div class="v-progress-linear v-theme--light v-locale--is-ltr" style="top: 0px; height: 0px; --v-progress-linear-height: 2px;" role="progressbar" aria-hidden="true" aria-valuemin="0" aria-valuemax="100">
13
13
  <!---->
14
- <div class="v-progress-linear__background" style="opacity: NaN;"></div>
15
- <div class="v-progress-linear__buffer" style="opacity: NaN; width: 0%;"></div>
14
+ <div class="v-progress-linear__background bg-primary" style="opacity: NaN;"></div>
15
+ <div class="v-progress-linear__buffer bg-primary" style="opacity: NaN; width: 0%;"></div>
16
16
  <transition-stub name="fade-transition" appear="false" persisted="false" css="true">
17
17
  <div class="v-progress-linear__indeterminate">
18
- <div class="v-progress-linear__indeterminate long"></div>
19
- <div class="v-progress-linear__indeterminate short"></div>
18
+ <div class="v-progress-linear__indeterminate long bg-primary"></div>
19
+ <div class="v-progress-linear__indeterminate short bg-primary"></div>
20
20
  </div>
21
21
  </transition-stub>
22
22
  <!---->
23
23
  </div>
24
24
  </div>
25
25
  <div class="v-field__prepend-inner">
26
- <!----><i class="M12,2L1,21H23M12,6L19.53,19H4.47M11,10V14H13V10M11,16V18H13V16 mdi v-icon notranslate v-theme--light v-icon--size-default" aria-hidden="true"></i>
26
+ <!----><i class="M12,2L1,21H23M12,6L19.53,19H4.47M11,10V14H13V10M11,16V18H13V16 mdi v-icon notranslate v-theme--light v-icon--size-default" aria-hidden="true" aria-label="custom label - bouton warning"></i>
27
27
  <hr class="v-divider v-divider--vertical v-theme--light text-primary mt-4 pa-1" style="height: 25px; border-right-width: 2px; --v-border-opacity: 1;" aria-orientation="vertical" role="separator">
28
28
  </div>
29
- <div class="v-field__field" data-no-activator="">
30
- <!---->
31
- <!---->
32
- <!----><input size="1" type="text" id="input-0" aria-describedby="input-0-messages" class="v-field__input" value="">
29
+ <div class="v-field__field" data-no-activator=""><label class="v-label v-field-label v-field-label--floating" aria-hidden="true" for="input-0">
30
+ <!---->custom label
31
+ </label><label class="v-label v-field-label" for="input-0">
32
+ <!---->custom label
33
+ </label>
34
+ <!----><input size="1" type="text" id="input-0" aria-describedby="input-0-messages" aria-label="custom label" display-asterisk="false" no-icon="false" class="v-field__input">
33
35
  <!---->
34
36
  </div>
35
37
  <transition-stub name="expand-x-transition" appear="false" persisted="false" css="true">
36
- <div class="v-field__clearable" style="display: none;"><i class="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z mdi v-icon notranslate v-theme--light v-icon--size-default v-icon--clickable" role="button" aria-hidden="false" tabindex="0" aria-label="Clear "></i></div>
38
+ <div class="v-field__clearable" style="display: none;"><i class="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z mdi v-icon notranslate v-theme--light v-icon--size-default v-icon--clickable" role="button" aria-hidden="false" tabindex="0" aria-label="Clear custom label"></i></div>
37
39
  </transition-stub>
38
40
  <div class="v-field__append-inner">
39
- <!--v-if--><i class="M13,9H11V7H13M13,17H11V11H13M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z mdi v-icon notranslate v-theme--light v-icon--size-default text-error error-icon" aria-hidden="true"></i>
41
+ <!--v-if--><i class="M13,9H11V7H13M13,17H11V11H13M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z mdi v-icon notranslate v-theme--light v-icon--size-default text-error error-icon" aria-hidden="true" aria-label="custom label - bouton error"></i>
40
42
  <!---->
41
43
  </div>
42
44
  <div class="v-field__outline">
@@ -46,10 +48,10 @@ exports[`SyTextField > matches snapshot 1`] = `
46
48
  </div>
47
49
  </div>
48
50
  <div class="v-input__append">
49
- <!----><i class="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z mdi v-icon notranslate v-theme--light v-icon--size-default" aria-hidden="true"></i>
51
+ <!----><i class="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z mdi v-icon notranslate v-theme--light v-icon--size-default text-error v-icon--clickable" role="button" aria-hidden="false" tabindex="0" aria-label="custom label - bouton success"></i>
50
52
  </div>
51
- <div class="v-input__details">
52
- <transition-group-stub name="slide-y-transition" tag="div" appear="false" persisted="false" css="true" class="v-messages" role="alert" aria-live="polite" id="input-0-messages">
53
+ <div id="input-0-messages" class="v-input__details" role="alert" aria-live="polite">
54
+ <transition-group-stub name="slide-y-transition" tag="div" appear="false" persisted="false" css="true" class="v-messages">
53
55
  <!---->
54
56
  </transition-group-stub>
55
57
  <!---->
@@ -1,3 +1,3 @@
1
- export type IconType = 'info' | 'success' | 'warning' | 'error' | 'close'
2
- export type VariantStyle = 'outlined' | 'filled' | 'solo' | 'solo-inverted' | 'solo-filled'
1
+ export type IconType = 'info' | 'success' | 'warning' | 'error' | 'close' | 'calendar' | undefined
2
+ export type VariantStyle = 'outlined' | 'filled' | 'solo' | 'solo-inverted' | 'solo-filled' | 'underlined'
3
3
  export type ColorType = 'primary' | 'secondary' | 'success' | 'info' | 'warning' | 'error'
@@ -0,0 +1,191 @@
1
+ import {Meta, Canvas, Controls, Source} from '@storybook/blocks';
2
+ import * as DatePickerStories from "./DatePicker.stories.ts";
3
+
4
+ <Meta of={DatePickerStories}/>
5
+
6
+ # DatePicker
7
+
8
+ Le composant `DatePicker` est un champ de saisie de date qui combine un champ de texte et un sélecteur de date. Il permet de saisir une date manuellement ou de la sélectionner via un calendrier, avec support pour les plages de dates.
9
+
10
+ <Canvas story={{height: '550px'}} of={DatePickerStories.Default}/>
11
+
12
+ # API
13
+
14
+ <Controls of={DatePickerStories.Default}/>
15
+
16
+ # Props
17
+
18
+ ## Valeur et contrôle
19
+
20
+ ### modelValue
21
+ - **Type** : `string | string[]`
22
+ - **Description** : La valeur du champ. Pour une plage de dates, utiliser un tableau de deux dates. La valeur doit être fournie dans le même format que celui spécifié dans la prop `format`.
23
+ - **Défaut** : `undefined`
24
+
25
+ ### placeholder
26
+ - **Type** : `string`
27
+ - **Description** : Texte indicatif affiché quand le champ est vide
28
+ - **Défaut** : `'Sélectionner une date'`
29
+
30
+ ### format
31
+ - **Type** : `string`
32
+ - **Description** : Format d'affichage et d'entrée de la date. Supporte les formats suivants :
33
+ - `DD` : jour sur 2 chiffres
34
+ - `MM` : mois sur 2 chiffres
35
+ - `YYYY` : année sur 4 chiffres
36
+ - `YY` : année sur 2 chiffres (assumé comme 20XX)
37
+ Les séparateurs peuvent être `/`, `-` ou `.`
38
+ - **Défaut** : `'DD/MM/YYYY'`
39
+
40
+ ### dateFormatReturn
41
+ - **Type** : `string`
42
+ - **Description** : Format de la date pour la valeur de retour. Utilise les mêmes tokens que la prop `format`. Si non spécifié, utilise le même format que `format`.
43
+ - **Défaut** : `''`
44
+
45
+ <div
46
+ style={{
47
+ border: '2px solid #FF0000',
48
+ padding: '1rem',
49
+ borderRadius: '4px',
50
+ marginBottom: '1rem',
51
+ }}
52
+ >
53
+ <strong>Note importante sur les formats</strong>
54
+ <p>
55
+ Le composant utilise deux formats distincts :
56
+ </p>
57
+ <ol>
58
+ <li>
59
+ <strong>Format d'entrée/affichage</strong><br/>
60
+ Défini par la prop <code>format</code>, il détermine à la fois :
61
+ <ul>
62
+ <li>Le format dans lequel la date doit être fournie au composant</li>
63
+ <li>Comment la date est affichée visuellement dans le champ</li>
64
+ </ul>
65
+ </li>
66
+ <li>
67
+ <strong>Format de retour</strong><br/>
68
+ Défini par la prop <code>dateFormatReturn</code>, il détermine le format de la date émise
69
+ </li>
70
+ </ol>
71
+ <p>
72
+ Par exemple, avec <code>format="DD-MM-YY"</code> et <code>dateFormatReturn="YYYY/MM/DD"</code> :
73
+ </p>
74
+ <ul>
75
+ <li>Vous devez fournir la date au format : <code>24-12-25</code></li>
76
+ <li>Elle sera affichée comme : <code>24-12-25</code></li>
77
+ <li>Elle sera retournée comme : <code>2025/12/24</code></li>
78
+ </ul>
79
+ </div>
80
+
81
+
82
+
83
+ ### required
84
+ - **Type** : `boolean`
85
+ - **Description** : Indique si le champ est obligatoire
86
+ - **Défaut** : `false`
87
+
88
+ ### isDisabled
89
+ - **Type** : `boolean`
90
+ - **Description** : Désactive le champ
91
+ - **Défaut** : `false`
92
+
93
+ ## Configuration du calendrier
94
+
95
+ ### isBirthDate
96
+ - **Type** : `boolean`
97
+ - **Description** : Active le mode date de naissance (commence par la sélection de l'année)
98
+ - **Défaut** : `false`
99
+
100
+ ### isOutlined
101
+ - **Type** : `boolean`
102
+ - **Description** : Active le style de champ de saisie "outlined" (bordure) plutôt que "underlined" (fond)
103
+ - **Défaut** : `true`
104
+
105
+ ### showWeekNumber
106
+ - **Type** : `boolean`
107
+ - **Description** : Affiche les numéros de semaine dans le calendrier
108
+ - **Défaut** : `false`
109
+
110
+ ### displayRange
111
+ - **Type** : `boolean`
112
+ - **Description** : Active la sélection d'une plage de dates
113
+ - **Défaut** : `false`
114
+
115
+ ### noCalendar
116
+ - **Type** : `boolean`
117
+ - **Description** : Désactive l'affichage du calendrier (saisie manuelle uniquement)
118
+ - **Défaut** : `false`
119
+
120
+ ## Apparence
121
+
122
+ ### displayIcon
123
+ - **Type** : `boolean`
124
+ - **Description** : Affiche l'icône de calendrier
125
+ - **Défaut** : `false`
126
+
127
+ ### displayAppendIcon
128
+ - **Type** : `boolean`
129
+ - **Description** : Affiche l'icône à la fin du champ plutôt qu'au début
130
+ - **Défaut** : `false`
131
+
132
+ ### noIcon
133
+ - **Type** : `boolean`
134
+ - **Description** : Masque toutes les icônes
135
+ - **Défaut** : `false`
136
+
137
+ ## Validation
138
+
139
+ ### customRules
140
+ - **Type** : `{ type: string, options: RuleOptions }[]`
141
+ - **Description** : Règles de validation personnalisées
142
+ - **Défaut** : `[]`
143
+
144
+ ### customWarningRules
145
+ - **Type** : `{ type: string, options: RuleOptions }[]`
146
+ - **Description** : Règles d'avertissement personnalisées
147
+ - **Défaut** : `[]`
148
+
149
+ # Exemple d'utilisation
150
+
151
+ <Source
152
+ dark code={`
153
+ <script setup lang="ts">
154
+ import { ref } from 'vue'
155
+ import { DatePicker } from '@cnamts/synapse'
156
+
157
+ const date = ref('')
158
+ </script>
159
+
160
+ <template>
161
+ <DatePicker
162
+ v-model="date"
163
+ placeholder="Sélectionner une date"
164
+ format="DD/MM/YYYY"
165
+ required
166
+ />
167
+ </template>
168
+ `}
169
+ />
170
+
171
+ ## Exemple avec plage de dates
172
+
173
+ <Source
174
+ dark code={`
175
+ <script setup lang="ts">
176
+ import { ref } from 'vue'
177
+ import { DatePicker } from '@cnamts/synapse'
178
+
179
+ const dateRange = ref(['', ''])
180
+ </script>
181
+
182
+ <template>
183
+ <DatePicker
184
+ v-model="dateRange"
185
+ placeholder="Sélectionner une période"
186
+ format="DD/MM/YYYY"
187
+ display-range
188
+ />
189
+ </template>
190
+ `}
191
+ />