@cnamts/synapse 1.0.18 → 1.0.19

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 (43) hide show
  1. package/dist/{DateFilter-C0qj2Xp4.js → DateFilter-CeVuSfJ9.js} +1 -1
  2. package/dist/{NumberFilter-DLlqjkwg.js → NumberFilter-C8PAu_sw.js} +1 -1
  3. package/dist/{PeriodFilter-BQCGbydv.js → PeriodFilter-UMUaxx3d.js} +1 -1
  4. package/dist/{SelectFilter-CPnShk0h.js → SelectFilter-CqZl8CYt.js} +1 -1
  5. package/dist/{TextFilter-6N05mkcs.js → TextFilter-D_RhhNOh.js} +1 -1
  6. package/dist/components/Amelipro/AmeliproAutoCompleteField/AmeliproAutoCompleteField.d.ts +2 -2
  7. package/dist/components/Amelipro/AmeliproCaptcha/AmeliproCaptcha.d.ts +1 -1
  8. package/dist/components/Amelipro/AmeliproCard/AmeliproCard.d.ts +1 -1
  9. package/dist/components/Amelipro/AmeliproClickableTile/AmeliproClickableTile.d.ts +1 -1
  10. package/dist/components/Amelipro/AmeliproFilters/types.d.ts +6 -0
  11. package/dist/components/Captcha/Captcha.d.ts +1 -1
  12. package/dist/components/{Customs/Selects/SyBtnSelect/SyBtnSelect.d.ts → SyBtnMenu/SyBtnMenu.d.ts} +2 -17
  13. package/dist/components/UserMenuBtn/UserMenuBtn.d.ts +2 -2
  14. package/dist/components/index.d.ts +21 -21
  15. package/dist/design-system-v3.js +10 -10
  16. package/dist/design-system-v3.umd.cjs +16 -16
  17. package/dist/{main-CY1bof-3.js → main-B39UVv5p.js} +9018 -8993
  18. package/dist/style.css +1 -1
  19. package/package.json +2 -2
  20. package/src/components/Accordion/Accessibilite/AccessibilityGuide.mdx +1 -1
  21. package/src/components/Amelipro/AmeliproFilters/AmeliproFilters.mdx +14 -0
  22. package/src/components/Amelipro/AmeliproFilters/AmeliproFilters.stories.ts +106 -0
  23. package/src/components/Amelipro/AmeliproFilters/AmeliproFilters.vue +218 -0
  24. package/src/components/Amelipro/AmeliproFilters/__tests__/AmeliproFilters.spec.ts +180 -0
  25. package/src/components/Amelipro/AmeliproFilters/types.d.ts +6 -0
  26. package/src/components/Customs/Selects/SelectOverview.mdx +0 -68
  27. package/src/components/DatePicker/CalendarMode/tests/DatePicker.spec.ts +19 -6
  28. package/src/components/{Customs/Selects/SyBtnSelect/SyBtnSelect.mdx → SyBtnMenu/SyBtnMenu.mdx} +8 -9
  29. package/src/components/{Customs/Selects/SyBtnSelect/SyBtnSelect.stories.ts → SyBtnMenu/SyBtnMenu.stories.ts} +80 -78
  30. package/src/components/{Customs/Selects/SyBtnSelect/SyBtnSelect.vue → SyBtnMenu/SyBtnMenu.vue} +84 -24
  31. package/src/components/SyBtnMenu/accessibilite/AccessibilityGuide.mdx +77 -0
  32. package/src/components/{Customs/Selects/SyBtnSelect/tests/SyBtnSelect.spec.ts → SyBtnMenu/tests/SyBtnMenu.spec.ts} +38 -11
  33. package/src/components/UserMenuBtn/UserMenuBtn.vue +3 -3
  34. package/src/components/UserMenuBtn/tests/UserMenuBtn.spec.ts +3 -3
  35. package/src/components/index.ts +21 -21
  36. package/src/composables/date/tests/useDateFormatDayjs.spec.ts +19 -0
  37. package/src/composables/date/useDateFormatDayjs.ts +4 -4
  38. package/src/stories/Accessibilite/Avancement/Avancement.stories.ts +1 -1
  39. package/src/stories/Accessibilite/Vuetify/VuetifyItems.ts +0 -4
  40. package/src/stories/Components/Components.stories.ts +2 -2
  41. package/src/stories/GuideDuDev/PortailAgent.stories.ts +0 -1
  42. package/src/components/Customs/Selects/SyBtnSelect/Accessibilite.mdx +0 -13
  43. package/src/components/Customs/Selects/SyBtnSelect/Accessibilite.stories.ts +0 -25
@@ -1,6 +1,7 @@
1
1
  <script lang="ts" setup>
2
- import { ref, watch, computed, onMounted, useSlots, type PropType } from 'vue'
2
+ import { ref, watch, computed, onMounted, useSlots, type PropType, nextTick } from 'vue'
3
3
  import { useDisplay } from 'vuetify'
4
+ import slugify from 'slugify'
4
5
 
5
6
  type Item = string | Record<string, unknown>
6
7
 
@@ -15,7 +16,7 @@
15
16
  },
16
17
  label: {
17
18
  type: String,
18
- default: 'Sélectionnez une option',
19
+ default: 'Menu utilisateur',
19
20
  },
20
21
  required: {
21
22
  type: Boolean,
@@ -69,10 +70,6 @@
69
70
 
70
71
  const isOpen = ref(false)
71
72
  const selectedItem = ref<Record<string, unknown> | string | null>(props.modelValue as Record<string, unknown> | string | null)
72
- const toggleMenu = () => {
73
- isOpen.value = !isOpen.value
74
- }
75
-
76
73
  const buttonRef = ref<HTMLElement | null>(null)
77
74
  const buttonWidth = ref('')
78
75
 
@@ -101,7 +98,7 @@
101
98
  if (props.hideIcon) {
102
99
  return 'pa-1 pa-sm-2'
103
100
  }
104
- return isMobileVersion.value ? 'pa-0' : 'pa-1 pa-sm-3'
101
+ return isMobileVersion.value ? 'pa-1' : 'pa-1 pa-sm-3'
105
102
  })
106
103
 
107
104
  const hasListContent = computed(() => {
@@ -118,6 +115,27 @@
118
115
 
119
116
  const generatedId = ref(`custom-btn-select-${Math.random().toString(36).substring(7)}`)
120
117
 
118
+ function getSelectedValue() {
119
+ if (!selectedItem.value) return undefined
120
+ if (typeof selectedItem.value === 'string') return selectedItem.value
121
+ return selectedItem.value[props.textKey] as string
122
+ }
123
+
124
+ const menu = ref<InstanceType<typeof import('vuetify/components').VList> | null>(null)
125
+
126
+ watch(isOpen, async (newVal) => {
127
+ if (newVal) {
128
+ await nextTick()
129
+ if (menu.value?.$el) {
130
+ menu.value.$el.querySelector('[role="menuitem"]')?.focus()
131
+ }
132
+ }
133
+ else {
134
+ await nextTick()
135
+ document.getElementById(generatedId.value)!.focus()
136
+ }
137
+ })
138
+
121
139
  defineExpose({
122
140
  isOpen,
123
141
  formattedItems,
@@ -131,7 +149,9 @@
131
149
  class="sy-user-menu-btn-ctn d-inline-block"
132
150
  >
133
151
  <VMenu
134
- :id="generatedId"
152
+ :id="$props.menuId"
153
+ v-model="isOpen"
154
+ class="sy-user-menu"
135
155
  :disabled="!hasListContent"
136
156
  location="bottom end"
137
157
  transition="fade-transition"
@@ -152,17 +172,16 @@
152
172
  ...menuProps,
153
173
  ...props.options['btn'],
154
174
  }"
155
- @click="toggleMenu"
156
175
  >
157
- <div
176
+ <span
158
177
  :class="['text-'+props?.options['btn']?.color]"
159
- class="d-flex align-center"
178
+ class="d-flex align-center ga-2"
160
179
  >
161
180
  <slot name="prepend-icon" />
162
181
  <span class="d-sr-only">{{ props.label }}</span>
163
182
  <span
164
183
  v-if="!isMobileVersion && !iconOnly"
165
- class="d-flex flex-column align-end py-1 mr-2"
184
+ class="d-flex flex-column align-end py-1"
166
185
  >
167
186
  <span
168
187
  :class="`text-${props?.options['btn']?.textColor}`"
@@ -172,7 +191,7 @@
172
191
  </span>
173
192
  <span
174
193
  :class="`text-${props?.options['btn']?.textColor}`"
175
- class="text-grey text-darken-2 text-h7 font-weight-regular"
194
+ class="subtitle text-grey text-darken-2 font-weight-regular"
176
195
  >
177
196
  {{ props.secondaryInfo }}
178
197
  </span>
@@ -185,27 +204,41 @@
185
204
  {{ props.primaryInfo }}
186
205
  </span>
187
206
  <slot name="append-icon" />
188
- </div>
207
+ </span>
189
208
  </VBtn>
190
209
  </template>
191
210
  <slot name="content">
192
211
  <VList
193
212
  v-if="hasListContent"
213
+ ref="menu"
214
+ tag="ul"
215
+ role="menu"
194
216
  v-bind="props.options['list']"
217
+ :aria-labelledby="generatedId"
218
+ :aria-activedescendant="getSelectedValue() ? `item-${slugify(getSelectedValue()!)}` : undefined"
195
219
  >
196
- <VListItem
220
+ <li
197
221
  v-for="(item, index) in formattedItems"
222
+ :id="`item-${slugify(item[props.textKey] as string)}`"
198
223
  :key="index"
199
- :class="`text-${props?.options['list']?.textColor}`"
200
- v-bind="props.options['list']"
201
- :href="item.link"
202
- :to="item.to"
203
- @click="selectItem(item)"
204
224
  >
205
- <VListItemTitle v-bind="props.options['list']">
206
- {{ item[props.textKey] }}
207
- </VListItemTitle>
208
- </VListItem>
225
+ <VListItem
226
+ :class="`text-${props?.options['list']?.textColor}`"
227
+ v-bind="props.options['list']"
228
+ :href="item.link"
229
+ :to="item.to"
230
+ :tabindex="0"
231
+ role="menuitem"
232
+ :aria-current="selectedItem === item ? 'page' : undefined"
233
+ @click="selectItem(item)"
234
+ >
235
+ <VListItemTitle
236
+ class="item-title"
237
+ >
238
+ {{ item[props.textKey] }}
239
+ </VListItemTitle>
240
+ </VListItem>
241
+ </li>
209
242
  <slot />
210
243
  <slot name="footer-list-item" />
211
244
  </VList>
@@ -247,9 +280,36 @@
247
280
  &:focus {
248
281
  background: rgba(tokens.$blue-base, 0.08) !important;
249
282
  }
283
+
284
+ .subtitle {
285
+ font-size: 0.875rem;
286
+ line-height: 1.5;
287
+ }
250
288
  }
251
289
 
252
290
  :deep(.sy-user-menu-btn:focus > .v-btn__overlay) {
253
291
  opacity: 0 !important;
254
292
  }
293
+
294
+ .v-btn:focus-visible {
295
+ outline: 2px solid rgb(var(--v-theme-primary));
296
+ outline-offset: 2px;
297
+
298
+ :deep(.v-btn__overlay) {
299
+ opacity: 0;
300
+ }
301
+
302
+ &::after {
303
+ opacity: 0;
304
+ }
305
+ }
306
+
307
+ :global(.sy-user-menu .v-list-item:focus) {
308
+ outline: 2px solid rgb(var(--v-theme-primary));
309
+ outline-offset: -2px;
310
+ }
311
+
312
+ .item-title {
313
+ white-space: wrap;
314
+ }
255
315
  </style>
@@ -0,0 +1,77 @@
1
+ import { Meta, Primary } from '@storybook/blocks';
2
+ import * as SyBtnMenuStories from '../SyBtnMenu.stories.ts';
3
+ import AccessibilityIcon from '@/common/imgs/accessibility-svgrepo-com.svg';
4
+ import {
5
+ AccessibilityGuideLayout,
6
+ CriteriaSection,
7
+ CriteriaCard,
8
+ DemoSection,
9
+ BestPracticesSection,
10
+ ResourcesSection,
11
+ } from '@/stories/accessibility/AccessibilityGuideLayout.mdx';
12
+
13
+ <Meta of={SyBtnMenuStories} />
14
+
15
+ <AccessibilityGuideLayout
16
+ componentName="SyBtnMenu"
17
+ iconSrc={AccessibilityIcon}
18
+ apgHref="https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/"
19
+ >
20
+ <CriteriaSection>
21
+ <CriteriaCard icon="🔍" title="Structure sémantique">
22
+ <ul>
23
+ <li><strong>Rôles ARIA appropriés</strong> : <code>role="menu"</code> pour la liste (<code>&lt;ul&gt;</code>), <code>role="menuitem"</code> pour chaque option (<code>&lt;li&gt;</code>)</li>
24
+ <li><strong>Attributs ARIA</strong> : <code>aria-haspopup</code>, <code>aria-expanded</code>, <code>aria-controls</code> sur le bouton, <code>aria-activedescendant</code> sur le menu</li>
25
+ <li><strong>Liens sémantiques</strong> : <code>aria-labelledby</code> pour relier le menu au bouton</li>
26
+ </ul>
27
+ </CriteriaCard>
28
+
29
+ <CriteriaCard icon="⌨️" title="Navigation clavier complète">
30
+ <ul>
31
+ <li><strong>Tabulation</strong> : Accès au bouton puis navigation dans le menu</li>
32
+ <li><strong>Touches fléchées</strong> : Navigation verticale dans les options</li>
33
+ <li><strong>Entrée/Espace</strong> : Activation d'une option</li>
34
+ <li><strong>Échappement</strong> : Fermeture du menu et retour au bouton</li>
35
+ </ul>
36
+ </CriteriaCard>
37
+
38
+ <CriteriaCard icon="📱" title="États et retours d'information">
39
+ <ul>
40
+ <li><strong>État d'ouverture</strong> : <code>aria-expanded</code> reflète l'état du menu</li>
41
+ <li><strong>Focus visible</strong> : Indication claire de l'élément focalisé</li>
42
+ <li><strong>Retour visuel</strong> : Styles pour l'état actif/sélectionné</li>
43
+ </ul>
44
+ </CriteriaCard>
45
+
46
+ <CriteriaCard icon="🎨" title="Personnalisation accessible">
47
+ <ul>
48
+ <li><strong>Options de personnalisation</strong> : Couleurs, tailles, et icônes adaptables</li>
49
+ <li><strong>Compatibilité mobile</strong> : Utilisation adaptée sur petits écrans</li>
50
+ </ul>
51
+ </CriteriaCard>
52
+ </CriteriaSection>
53
+
54
+ <DemoSection componentName="SyBtnMenu">
55
+ <Primary />
56
+ </DemoSection>
57
+
58
+ <BestPracticesSection>
59
+ <ul>
60
+ <li>Utilisez un libellé explicite pour le bouton d'ouverture du menu</li>
61
+ <li>Utiliser des libellés explicites pour les options du menu</li>
62
+ <li>Évitez de surcharger le menu avec trop d'options</li>
63
+ </ul>
64
+ </BestPracticesSection>
65
+
66
+ <ResourcesSection>
67
+ <ul>
68
+ <li><a href="https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/" target="_blank" rel="noopener noreferrer">WAI-ARIA Authoring Practices: Menu Button</a></li>
69
+ <li><a href="https://inclusive-components.design/menus-menu-buttons/" target="_blank" rel="noopener noreferrer">Inclusive Components: Menus & Menu Buttons</a></li>
70
+ </ul>
71
+ </ResourcesSection>
72
+
73
+ <div class="mt-8">
74
+ <p>Rapport d’audit manuel : <a href="/audits/SyBtnMenu.xlsx" style={{ color:'#0C41BD' }}>Voir le rapport</a></p>
75
+ <p style={{ color: 'grey', fontSize: '14px', marginTop: '0px' }}>Correctifs associés (<a href="https://github.com/assurance-maladie-digital/design-system-v3/issues/918" target="_blank" style={{color:'#0C41BD'}}>issue #918</a>)</p>
76
+ </div>
77
+ </AccessibilityGuideLayout>
@@ -1,32 +1,38 @@
1
1
  import { describe, it, expect } from 'vitest'
2
2
  import { mount } from '@vue/test-utils'
3
- import SyBtnSelect from '../SyBtnSelect.vue'
3
+ import SyBtnMenu from '../SyBtnMenu.vue'
4
4
 
5
- describe('SyBtnSelect', () => {
5
+ describe('SyBtnMenu', () => {
6
6
  it('renders the component with default props', () => {
7
- const wrapper = mount(SyBtnSelect, {
7
+ const wrapper = mount(SyBtnMenu, {
8
8
  props: {
9
9
  primaryInfo: 'John Doe',
10
10
  },
11
+ attachTo: document.body,
11
12
  })
12
13
 
13
14
  expect(wrapper.exists()).toBe(true)
14
15
  expect(wrapper.text()).toContain('John Doe')
16
+
17
+ wrapper.unmount()
15
18
  })
16
19
 
17
20
  it('shows secondaryInfo if provided', () => {
18
- const wrapper = mount(SyBtnSelect, {
21
+ const wrapper = mount(SyBtnMenu, {
19
22
  props: {
20
23
  primaryInfo: 'John Doe',
21
24
  secondaryInfo: 'Additional Info',
22
25
  },
26
+ attachTo: document.body,
23
27
  })
24
28
 
25
29
  expect(wrapper.text()).toContain('Additional Info')
30
+
31
+ wrapper.unmount()
26
32
  })
27
33
 
28
34
  it('emits "update:modelValue" when an item is selected', async () => {
29
- const wrapper = mount(SyBtnSelect, {
35
+ const wrapper = mount(SyBtnMenu, {
30
36
  props: {
31
37
  modelValue: null,
32
38
  menuItems: [
@@ -35,6 +41,7 @@ describe('SyBtnSelect', () => {
35
41
  ],
36
42
  primaryInfo: 'John Doe',
37
43
  },
44
+ attachTo: document.body,
38
45
  })
39
46
 
40
47
  const button = wrapper.find('.sy-user-menu-btn')
@@ -50,13 +57,16 @@ describe('SyBtnSelect', () => {
50
57
  expect(wrapper.emitted('update:modelValue')![0]).toEqual([
51
58
  { text: 'Option 1', value: 'option1' },
52
59
  ])
60
+
61
+ wrapper.unmount()
53
62
  })
54
63
 
55
64
  it('toggles the menu open and closed', async () => {
56
- const wrapper = mount(SyBtnSelect, {
65
+ const wrapper = mount(SyBtnMenu, {
57
66
  props: {
58
67
  primaryInfo: 'John Doe',
59
68
  },
69
+ attachTo: document.body,
60
70
  })
61
71
 
62
72
  const button = wrapper.find('.sy-user-menu-btn')
@@ -67,14 +77,17 @@ describe('SyBtnSelect', () => {
67
77
 
68
78
  await button.trigger('click')
69
79
  expect(wrapper.vm.isOpen).toBe(false)
80
+
81
+ wrapper.unmount()
70
82
  })
71
83
 
72
84
  it('formats menu items correctly', () => {
73
- const wrapper = mount(SyBtnSelect, {
85
+ const wrapper = mount(SyBtnMenu, {
74
86
  props: {
75
87
  primaryInfo: 'John Doe',
76
88
  menuItems: ['Option 1', 'Option 2'],
77
89
  },
90
+ attachTo: document.body,
78
91
  })
79
92
 
80
93
  const formattedItems = wrapper.vm.formattedItems
@@ -82,59 +95,73 @@ describe('SyBtnSelect', () => {
82
95
  { text: 'Option 1', value: 'Option 1' },
83
96
  { text: 'Option 2', value: 'Option 2' },
84
97
  ])
98
+
99
+ wrapper.unmount()
85
100
  })
86
101
 
87
102
  it('updates selectedItem when modelValue changes', async () => {
88
- const wrapper = mount(SyBtnSelect, {
103
+ const wrapper = mount(SyBtnMenu, {
89
104
  props: {
90
105
  modelValue: 'initial-value',
91
106
  primaryInfo: 'John Doe',
92
107
  },
108
+ attachTo: document.body,
93
109
  })
94
110
 
95
111
  expect(wrapper.vm.selectedItem).toBe('initial-value')
96
112
 
97
113
  await wrapper.setProps({ modelValue: 'new-value' })
98
114
  expect(wrapper.vm.selectedItem).toBe('new-value')
115
+
116
+ wrapper.unmount()
99
117
  })
100
118
 
101
119
  it('renders the primaryInfo in a span when isMobileVersion and hideIcon are true', async () => {
102
- const wrapper = mount(SyBtnSelect, {
120
+ const wrapper = mount(SyBtnMenu, {
103
121
  props: {
104
122
  primaryInfo: 'John Doe',
105
123
  isMobileView: true,
106
124
  hideIcon: true,
107
125
  },
126
+ attachTo: document.body,
108
127
  })
109
128
 
110
129
  const span = wrapper.find('span.font-weight-bold.text-caption')
111
130
 
112
131
  expect(span.text()).toBe('John Doe')
132
+
133
+ wrapper.unmount()
113
134
  })
114
135
 
115
136
  it('does not render the span if isMobileVersion is false', () => {
116
- const wrapper = mount(SyBtnSelect, {
137
+ const wrapper = mount(SyBtnMenu, {
117
138
  props: {
118
139
  primaryInfo: 'John Doe',
119
140
  isMobileView: false,
120
141
  hideIcon: true,
121
142
  },
143
+ attachTo: document.body,
122
144
  })
123
145
 
124
146
  const span = wrapper.find('span.font-weight-bold.text-sm-caption')
125
147
  expect(span.exists()).toBe(false)
148
+
149
+ wrapper.unmount()
126
150
  })
127
151
 
128
152
  it('does not render the span if hideIcon is false', () => {
129
- const wrapper = mount(SyBtnSelect, {
153
+ const wrapper = mount(SyBtnMenu, {
130
154
  props: {
131
155
  primaryInfo: 'John Doe',
132
156
  isMobileView: true,
133
157
  hideIcon: false,
134
158
  },
159
+ attachTo: document.body,
135
160
  })
136
161
 
137
162
  const span = wrapper.find('span.font-weight-bold.text-sm-caption')
138
163
  expect(span.exists()).toBe(false)
164
+
165
+ wrapper.unmount()
139
166
  })
140
167
  })
@@ -1,7 +1,7 @@
1
1
  <script lang="ts" setup>
2
2
  import { computed } from 'vue'
3
3
  import type { RouteLocationRaw } from 'vue-router'
4
- import SyBtnSelect from '@/components/Customs/Selects/SyBtnSelect/SyBtnSelect.vue'
4
+ import SyBtnMenu from '@/components/SyBtnMenu/SyBtnMenu.vue'
5
5
  import { useDisplay } from 'vuetify'
6
6
  import { mdiAccount, mdiLoginVariant } from '@mdi/js'
7
7
  import useCustomizableOptions, { type CustomizableOptions } from '@/composables/useCustomizableOptions'
@@ -43,7 +43,7 @@
43
43
  </script>
44
44
 
45
45
  <template>
46
- <SyBtnSelect
46
+ <SyBtnMenu
47
47
  v-model="modelValue"
48
48
  :hide-icon="hideUserIcon"
49
49
  :icon-only="isMobileView"
@@ -85,7 +85,7 @@
85
85
  </VListItem>
86
86
  </slot>
87
87
  </template>
88
- </SyBtnSelect>
88
+ </SyBtnMenu>
89
89
  </template>
90
90
 
91
91
  <style scoped lang="scss">
@@ -91,9 +91,9 @@ describe('UserMenuBtn', () => {
91
91
  },
92
92
  })
93
93
 
94
- const SyBtnSelect = wrapper.findComponent({ name: 'SyBtnSelect' })
95
- // Utiliser le format camelCase pour l'événement, comme déclaré dans le composant SyBtnSelect
96
- await SyBtnSelect.vm.$emit('update:modelValue', 'test-value')
94
+ const SyBtnMenu = wrapper.findComponent({ name: 'SyBtnMenu' })
95
+ // Utiliser le format camelCase pour l'événement, comme déclaré dans le composant SyBtnMenu
96
+ await SyBtnMenu.vm.$emit('update:modelValue', 'test-value')
97
97
 
98
98
  expect(wrapper.emitted('update:modelValue')).toBeTruthy()
99
99
  expect(wrapper.emitted('update:modelValue')![0]).toEqual(['test-value'])
@@ -4,12 +4,12 @@
4
4
  export { default as FooterBar } from './FooterBar/FooterBar.vue'
5
5
  export { default as HeaderBar } from './HeaderBar/HeaderBar.vue'
6
6
  export { default as HeaderBurgerMenu } from './HeaderBar/HeaderBurgerMenu/HeaderBurgerMenu.vue'
7
- export { default as HeaderLoading } from './HeaderLoading/HeaderLoading.vue'
8
- export { default as HeaderLogo } from './HeaderBar/HeaderLogo/HeaderLogo.vue'
9
- export { default as HeaderMenuBtn } from './HeaderBar/HeaderMenuBtn/HeaderMenuBtn.vue'
10
7
  export { default as HeaderMenuItem } from './HeaderBar/HeaderBurgerMenu/HeaderMenuItem/HeaderMenuItem.vue'
11
8
  export { default as HeaderMenuSection } from './HeaderBar/HeaderBurgerMenu/HeaderMenuSection/HeaderMenuSection.vue'
12
9
  export { default as HeaderSubMenu } from './HeaderBar/HeaderBurgerMenu/HeaderSubMenu/HeaderSubMenu.vue'
10
+ export { default as HeaderLogo } from './HeaderBar/HeaderLogo/HeaderLogo.vue'
11
+ export { default as HeaderMenuBtn } from './HeaderBar/HeaderMenuBtn/HeaderMenuBtn.vue'
12
+ export { default as HeaderLoading } from './HeaderLoading/HeaderLoading.vue'
13
13
  export { default as HeaderToolbar } from './HeaderToolbar/HeaderToolbar.vue'
14
14
  export { default as SubHeader } from './SubHeader/SubHeader.vue'
15
15
 
@@ -23,12 +23,13 @@ export { default as ToolbarContainer } from './ToolbarContainer/ToolbarContainer
23
23
  // Navigation
24
24
  // ===========================
25
25
  export { default as ContextualMenu } from './ContextualMenu/ContextualMenu.vue'
26
+ export { default as SyPagination } from './Customs/SyPagination/SyPagination.vue'
27
+ export { default as SyTabs } from './Customs/SyTabs/SyTabs.vue'
26
28
  export { default as ExternalLinks } from './ExternalLinks/ExternalLinks.vue'
27
29
  export { default as HeaderNavigationBar } from './HeaderNavigationBar/HeaderNavigationBar.vue'
28
30
  export { default as SkipLink } from './SkipLink/SkipLink.vue'
29
31
  export { default as SocialMediaLinks } from './SocialMediaLinks/SocialMediaLinks.vue'
30
- export { default as SyPagination } from './Customs/SyPagination/SyPagination.vue'
31
- export { default as SyTabs } from './Customs/SyTabs/SyTabs.vue'
32
+ export { default as SyBtnMenu } from './SyBtnMenu/SyBtnMenu.vue'
32
33
 
33
34
  // ===========================
34
35
  // Boutons
@@ -45,6 +46,14 @@ export { default as UserMenuBtn } from './UserMenuBtn/UserMenuBtn.vue'
45
46
  // Formulaires
46
47
  // ===========================
47
48
  export { default as DatePicker } from '@/components/DatePicker/CalendarMode/DatePicker.vue'
49
+ export { default as Captcha } from './Captcha/Captcha.vue'
50
+ export { default as SelectBtnField } from './Customs/Selects/SelectBtnField/SelectBtnField.vue'
51
+ export { default as SyInputSelect } from './Customs/Selects/SyInputSelect/SyInputSelect.vue'
52
+ export { default as SySelect } from './Customs/Selects/SySelect/SySelect.vue'
53
+ export { default as SyCheckbox } from './Customs/SyCheckbox/SyCheckbox.vue'
54
+ export { default as SyForm } from './Customs/SyForm/SyForm.vue'
55
+ export { default as SyRadioGroup } from './Customs/SyRadioGroup/SyRadioGroup.vue'
56
+ export { default as SyTextField } from './Customs/SyTextField/SyTextField.vue'
48
57
  export { default as DiacriticPicker } from './DiacriticPicker/DiacriticPicker.vue'
49
58
  export { default as FileUpload } from './FileUpload/FileUpload.vue'
50
59
  export { default as LunarCalendar } from './LunarCalendar/LunarCalendar.vue'
@@ -56,17 +65,8 @@ export { indicatifs } from './PhoneField/indicatifs'
56
65
  export { default as PhoneField } from './PhoneField/PhoneField.vue'
57
66
  export { default as RangeField } from './RangeField/RangeField.vue'
58
67
  export { default as SearchListField } from './SearchListField/SearchListField.vue'
59
- export { default as SelectBtnField } from './Customs/Selects/SelectBtnField/SelectBtnField.vue'
60
- export { default as SyBtnSelect } from './Customs/Selects/SyBtnSelect/SyBtnSelect.vue'
61
- export { default as SyCheckbox } from './Customs/SyCheckbox/SyCheckbox.vue'
62
- export { default as SyInputSelect } from './Customs/Selects/SyInputSelect/SyInputSelect.vue'
63
- export { default as SySelect } from './Customs/Selects/SySelect/SySelect.vue'
64
68
  export { default as SyTextArea } from './SyTextArea/SyTextArea.vue'
65
- export { default as SyTextField } from './Customs/SyTextField/SyTextField.vue'
66
69
  export { default as UploadWorkflow } from './UploadWorkflow/UploadWorkflow.vue'
67
- export { default as Captcha } from './Captcha/Captcha.vue'
68
- export { default as SyForm } from './Customs/SyForm/SyForm.vue'
69
- export { default as SyRadioGroup } from './Customs/SyRadioGroup/SyRadioGroup.vue'
70
70
 
71
71
  // ===========================
72
72
  // Tableaux
@@ -89,6 +89,7 @@ export { default as Accordion } from './Accordion/Accordion.vue'
89
89
  export { default as ChipList } from './ChipList/ChipList.vue'
90
90
  export * from './ChipList/types'
91
91
  export { default as CollapsibleList } from './CollapsibleList/CollapsibleList.vue'
92
+ export { default as SyIcon } from './Customs/SyIcon/SyIcon.vue'
92
93
  export { default as DataList } from './DataList/DataList.vue'
93
94
  export { default as DataListGroup } from './DataListGroup/DataListGroup.vue'
94
95
  export { default as DataListItem } from './DataListItem/DataListItem.vue'
@@ -96,7 +97,6 @@ export { default as FileList } from './FileList/FileList.vue'
96
97
  export { default as FilePreview } from './FilePreview/FilePreview.vue'
97
98
  export { default as Logo } from './Logo/Logo.vue'
98
99
  export { default as LogoBrandSection } from './LogoBrandSection/LogoBrandSection.vue'
99
- export { default as SyIcon } from './Customs/SyIcon/SyIcon.vue'
100
100
 
101
101
  // ===========================
102
102
  // Feedback
@@ -122,8 +122,8 @@ export { default as NotFoundPage } from './NotFoundPage/NotFoundPage.vue'
122
122
  // Amelipro
123
123
  // ===========================
124
124
  export { default as AmeliproAccordion } from './Amelipro/AmeliproAccordion/AmeliproAccordion.vue'
125
- export { default as AmeliproAccordionGroup } from './Amelipro/AmeliproAccordionGroup/AmeliproAccordionGroup.vue'
126
125
  export { default as AmeliproAccordionFrieze } from './Amelipro/AmeliproAccordionFrieze/AmeliproAccordionFrieze.vue'
126
+ export { default as AmeliproAccordionGroup } from './Amelipro/AmeliproAccordionGroup/AmeliproAccordionGroup.vue'
127
127
  export { default as AmeliproAccordionList } from './Amelipro/AmeliproAccordionList/AmeliproAccordionList.vue'
128
128
  export { default as AmeliproAccordionResult } from './Amelipro/AmeliproAccordionResult/AmeliproAccordionResult.vue'
129
129
  export { default as AmeliproAccordionResultList } from './Amelipro/AmeliproAccordionResultList/AmeliproAccordionResultList.vue'
@@ -131,10 +131,10 @@ export { default as AmeliproAutoCompleteField } from './Amelipro/AmeliproAutoCom
131
131
  export { default as AmeliproBadge } from './Amelipro/AmeliproBadge/AmeliproBadge.vue'
132
132
  export { default as AmeliproBreadcrumb } from './Amelipro/AmeliproBreadcrumb/AmeliproBreadcrumb.vue'
133
133
  export { default as AmeliproBtn } from './Amelipro/AmeliproBtn/AmeliproBtn.vue'
134
- export { default as AmeliproCard } from './Amelipro/AmeliproCard/AmeliproCard.vue'
135
134
  export { default as AmeliproCallback } from './Amelipro/AmeliproCallback/AmeliproCallback.vue'
136
- export { default as AmeliproCarousel } from './Amelipro/AmeliproCarousel/AmeliproCarousel.vue'
137
135
  export { default as AmeliproCaptcha } from './Amelipro/AmeliproCaptcha/AmeliproCaptcha.vue'
136
+ export { default as AmeliproCard } from './Amelipro/AmeliproCard/AmeliproCard.vue'
137
+ export { default as AmeliproCarousel } from './Amelipro/AmeliproCarousel/AmeliproCarousel.vue'
138
138
  export { default as AmeliproCheckbox } from './Amelipro/AmeliproCheckbox/AmeliproCheckbox.vue'
139
139
  export { default as AmeliproCheckboxGroup } from './Amelipro/AmeliproCheckboxGroup/AmeliproCheckboxGroup.vue'
140
140
  export { default as AmeliproChips } from './Amelipro/AmeliproChips/AmeliproChips.vue'
@@ -179,8 +179,8 @@ export { default as AmeliproTextField } from './Amelipro/AmeliproTextField/Ameli
179
179
  export { default as AmeliproTileBtn } from './Amelipro/AmeliproTileBtn/AmeliproTileBtn.vue'
180
180
  export { default as AmeliproTooltips } from './Amelipro/AmeliproTooltips/AmeliproTooltips.vue'
181
181
  export { default as AmeliproTransmission } from './Amelipro/AmeliproTransmission/AmeliproTransmission.vue'
182
- export { default as StructureMenu } from './Amelipro/StructureMenu/StructureMenu.vue'
183
182
  export { default as ServiceMenu } from './Amelipro/ServiceMenu/ServiceMenu.vue'
183
+ export { default as StructureMenu } from './Amelipro/StructureMenu/StructureMenu.vue'
184
184
  export { default as UserInformationSummary } from './Amelipro/UserInformationSummary/UserInformationSummary.vue'
185
185
  export { default as UserMenu } from './Amelipro/UserMenu/UserMenu.vue'
186
186
 
@@ -189,10 +189,10 @@ export { default as UserMenu } from './Amelipro/UserMenu/UserMenu.vue'
189
189
  // ===========================
190
190
  export { useDateFormat } from '../composables/date/useDateFormatDayjs'
191
191
  export { useFieldValidation } from '../composables/rules/useFieldValidation'
192
- export { useNotificationService } from '../services/NotificationService'
193
- export { useValidation } from '../composables/validation/useValidation'
194
192
  export type { RuleOptions } from '../composables/rules/useFieldValidation'
195
193
  export { useValidatable } from '../composables/validation/useValidatable'
194
+ export { useValidation } from '../composables/validation/useValidation'
195
+ export { useNotificationService } from '../services/NotificationService'
196
196
 
197
197
  // ===========================
198
198
  // Directives
@@ -0,0 +1,19 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { formatDate, parseDate } from '../useDateFormatDayjs'
3
+
4
+ describe('useDateFormatDayjs', () => {
5
+ describe('parseDate', () => {
6
+ it('keeps the same calendar day when formatting back in a negative timezone (UTC-4)', () => {
7
+ const previousTz = process.env.TZ
8
+ process.env.TZ = 'America/Guadeloupe'
9
+ try {
10
+ const parsed = parseDate('2023-01-15', 'YYYY-MM-DD')
11
+ expect(parsed).toBeInstanceOf(Date)
12
+ expect(formatDate(parsed, 'YYYY-MM-DD')).toBe('2023-01-15')
13
+ }
14
+ finally {
15
+ process.env.TZ = previousTz
16
+ }
17
+ })
18
+ })
19
+ })
@@ -49,10 +49,10 @@ export const parseDate = (dateString: string | Date | null | undefined, format:
49
49
  return null
50
50
  }
51
51
 
52
- // Extraire les composants de la date pour créer une date UTC
53
- // Cela évite les problèmes de décalage de fuseau horaire et garantit
54
- // que les dates au format dd/mm/yyyy sont correctement interprétées
55
- return dayjs.utc()
52
+ // Extraire les composants de la date pour créer une date à minuit en timezone locale.
53
+ // On évite ainsi les décalages jour-1/jour+1 quand on formate la Date en local,
54
+ // notamment dans les fuseaux négatifs (ex: UTC-4).
55
+ return dayjs()
56
56
  .year(parsedDate.year())
57
57
  .month(parsedDate.month())
58
58
  .date(parsedDate.date())
@@ -43,7 +43,7 @@ const ITEMS: AuditItem[] = [
43
43
  { composant: 'PasswordField', status: STATUS.AUDITED },
44
44
  { composant: 'PhoneField', status: STATUS.AUDITED },
45
45
  { composant: 'UserMenuBtn', status: STATUS.NOT_AUDITED },
46
- { composant: 'SyBtnSelect', status: STATUS.NOT_AUDITED },
46
+ { composant: 'SyBtnMenu', status: STATUS.AUDITED },
47
47
  { composant: 'NirField', status: STATUS.IN_PROGRESS },
48
48
  { composant: 'PeriodField', status: STATUS.NOT_AUDITED },
49
49
  { composant: 'RangeField', status: STATUS.NOT_AUDITED },
@@ -87,10 +87,6 @@ export const VuetifyItems = [
87
87
  name: 'SyInputSelect',
88
88
  href: '/?path=/docs/composants-formulaires-selects-syinputselect--docs',
89
89
  },
90
- {
91
- name: 'SyBtnSelect',
92
- href: '/?path=/docs/composants-formulaires-selects-sybtnselect--docs',
93
- },
94
90
  ],
95
91
  },
96
92
  {