@cnamts/synapse 0.0.2-alpha → 0.0.4-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 (193) hide show
  1. package/README.md +1 -1
  2. package/dist/design-system-v3.d.ts +712 -27
  3. package/dist/design-system-v3.js +2745 -5384
  4. package/dist/design-system-v3.umd.cjs +10 -2
  5. package/dist/style.css +1 -1
  6. package/package.json +32 -29
  7. package/src/components/Alert/Alert.mdx +1 -1
  8. package/src/components/Alert/Alert.stories.ts +91 -1
  9. package/src/components/Alert/Alert.vue +8 -8
  10. package/src/components/BackBtn/BackBtn.mdx +1 -1
  11. package/src/components/BackBtn/BackBtn.stories.ts +84 -1
  12. package/src/components/BackToTopBtn/BackToTopBtn.mdx +3 -3
  13. package/src/components/BackToTopBtn/BackToTopBtn.stories.ts +172 -11
  14. package/src/components/CollapsibleList/CollapsibleList.mdx +2 -2
  15. package/src/components/CollapsibleList/CollapsibleList.stories.ts +37 -1
  16. package/src/components/CopyBtn/CopyBtn.mdx +1 -1
  17. package/src/components/CopyBtn/CopyBtn.stories.ts +120 -1
  18. package/src/components/CopyBtn/CopyBtn.vue +1 -1
  19. package/src/components/Customs/CustomInputSelect/CustomInputSelect.mdx +6 -8
  20. package/src/components/Customs/CustomInputSelect/CustomInputSelect.stories.ts +270 -4
  21. package/src/components/Customs/CustomInputSelect/CustomInputSelect.vue +80 -53
  22. package/src/components/Customs/CustomInputSelect/config.ts +10 -0
  23. package/src/components/Customs/CustomSelect/CustomSelect.mdx +3 -3
  24. package/src/components/Customs/CustomSelect/CustomSelect.stories.ts +158 -2
  25. package/src/components/Customs/CustomSelect/CustomSelect.vue +25 -6
  26. package/src/components/Customs/CustomTextField/CustomTextField.mdx +44 -0
  27. package/src/components/Customs/CustomTextField/CustomTextField.stories.ts +403 -0
  28. package/src/components/Customs/CustomTextField/CustomTextField.vue +110 -0
  29. package/src/components/Customs/CustomTextField/tests/CustomTextField.spec.ts +93 -0
  30. package/src/components/Customs/CustomTextField/tests/__snapshots__/CustomTextField.spec.ts.snap +59 -0
  31. package/src/components/Customs/CustomTextField/types.d.ts +3 -0
  32. package/src/components/DataList/DataList.mdx +77 -0
  33. package/src/components/DataList/DataList.stories.ts +960 -0
  34. package/src/components/DataList/DataList.vue +140 -0
  35. package/src/components/DataList/DataListLoading/DataListLoading.vue +56 -0
  36. package/src/components/DataList/DataListLoading/tests/DataListLoading.spec.ts +23 -0
  37. package/src/components/DataList/locales.ts +3 -0
  38. package/src/components/DataList/tests/DataList.spec.ts +194 -0
  39. package/src/components/DataList/types.d.ts +23 -0
  40. package/src/components/DataListGroup/DataListGroup.mdx +77 -0
  41. package/src/components/DataListGroup/DataListGroup.stories.ts +987 -0
  42. package/src/components/DataListGroup/DataListGroup.vue +59 -0
  43. package/src/components/DataListGroup/tests/DataListGroup.spec.ts +54 -0
  44. package/src/components/DataListGroup/tests/data/dataListGroupItems.ts +41 -0
  45. package/src/components/DataListGroup/types.d.ts +15 -0
  46. package/src/components/DataListItem/DataListItem.vue +135 -0
  47. package/src/components/DataListItem/config.ts +17 -0
  48. package/src/components/DataListItem/locales.ts +3 -0
  49. package/src/components/DataListItem/tests/DataListItem.spec.ts +156 -0
  50. package/src/components/DataListItem/types.d.ts +23 -0
  51. package/src/components/DownloadBtn/Accessibilite.mdx +14 -0
  52. package/src/components/DownloadBtn/Accessibilite.stories.ts +166 -0
  53. package/src/components/DownloadBtn/AccessibiliteItems.ts +129 -0
  54. package/src/components/DownloadBtn/DownloadBtn.mdx +5 -6
  55. package/src/components/DownloadBtn/DownloadBtn.stories.ts +207 -2
  56. package/src/components/DownloadBtn/constants/ExpertiseLevelEnum.ts +4 -0
  57. package/src/components/FooterBar/FooterBar.mdx +2 -2
  58. package/src/components/FooterBar/FooterBar.stories.ts +1 -1
  59. package/src/components/FranceConnectBtn/FranceConnectBtn.mdx +1 -1
  60. package/src/components/FranceConnectBtn/FranceConnectBtn.stories.ts +58 -1
  61. package/src/components/FranceConnectBtn/FranceConnectBtn.vue +2 -2
  62. package/src/components/HeaderBar/HeaderBar.mdx +256 -0
  63. package/src/components/HeaderBar/HeaderBar.stories.ts +703 -0
  64. package/src/components/HeaderBar/HeaderBar.vue +276 -0
  65. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderBurgerMenu.mdx +433 -0
  66. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderBurgerMenu.stories.ts +1089 -0
  67. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderBurgerMenu.vue +234 -0
  68. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuItem/HeaderMenuItem.mdx +38 -0
  69. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuItem/HeaderMenuItem.stories.ts +89 -0
  70. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuItem/HeaderMenuItem.vue +51 -0
  71. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuItem/tests/HeaderMenuItem.spec.ts +16 -0
  72. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuItem/tests/__snapshots__/HeaderMenuItem.spec.ts.snap +3 -0
  73. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuSection/HeaderMenuSection.mdx +17 -0
  74. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuSection/HeaderMenuSection.stories.ts +121 -0
  75. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuSection/HeaderMenuSection.vue +51 -0
  76. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuSection/tests/HeaderMenuSection.spec.ts +31 -0
  77. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderSubMenu/HeaderSubMenu.mdx +43 -0
  78. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderSubMenu/HeaderSubMenu.stories.ts +261 -0
  79. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderSubMenu/HeaderSubMenu.vue +194 -0
  80. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderSubMenu/tests/HeaderSubMenu.spec.ts +63 -0
  81. package/src/components/HeaderBar/HeaderBurgerMenu/conts.ts +1 -0
  82. package/src/components/HeaderBar/HeaderBurgerMenu/locals.ts +4 -0
  83. package/src/components/HeaderBar/HeaderBurgerMenu/tests/HeaderBurgerMenu.spec.ts +180 -0
  84. package/src/components/HeaderBar/HeaderBurgerMenu/tests/__snapshots__/HeaderBurgerMenu.spec.ts.snap +13 -0
  85. package/src/components/HeaderBar/HeaderBurgerMenu/tests/__snapshots__/HeaderComplexMenu.spec.ts.snap +13 -0
  86. package/src/components/HeaderBar/HeaderBurgerMenu/tests/useHandleSubMenus.spec.ts +158 -0
  87. package/src/components/HeaderBar/HeaderBurgerMenu/useHandleSubMenus.ts +49 -0
  88. package/src/components/HeaderBar/HeaderLogo/HeaderLogo.vue +143 -0
  89. package/src/components/HeaderBar/HeaderLogo/locales.ts +3 -0
  90. package/src/components/HeaderBar/HeaderLogo/logos/Logo-mobile.vue +117 -0
  91. package/src/components/HeaderBar/HeaderLogo/logos/Logo.vue +279 -0
  92. package/src/components/HeaderBar/HeaderLogo/tests/HeaderLogo.spec.ts +119 -0
  93. package/src/components/HeaderBar/HeaderMenuBtn/HeaderMenuBtn.vue +84 -0
  94. package/src/components/HeaderBar/HeaderMenuBtn/locals.ts +4 -0
  95. package/src/components/HeaderBar/HeaderMenuBtn/tests/HeaderMenuBtn.spec.ts +70 -0
  96. package/src/components/HeaderBar/Usages.mdx +85 -0
  97. package/src/components/HeaderBar/consts.scss +6 -0
  98. package/src/components/HeaderBar/consts.ts +2 -0
  99. package/src/components/HeaderBar/locales.ts +3 -0
  100. package/src/components/HeaderBar/tests/HeaderBar.spec.ts +216 -0
  101. package/src/components/HeaderBar/tests/__snapshots__/HeaderBar.spec.ts.snap +45 -0
  102. package/src/components/HeaderBar/tests/useHeaderResponsiveMode.spec.ts +26 -0
  103. package/src/components/HeaderBar/tests/useScrollDirection.spec.ts +34 -0
  104. package/src/components/HeaderBar/useHeaderResponsiveMode.ts +25 -0
  105. package/src/components/HeaderBar/useScrollDirection.ts +26 -0
  106. package/src/components/HeaderLoading/HeaderLoading.mdx +28 -0
  107. package/src/components/HeaderLoading/HeaderLoading.stories.ts +62 -0
  108. package/src/components/HeaderLoading/HeaderLoading.vue +45 -0
  109. package/src/components/HeaderLoading/tests/HeaderLoading.spec.ts +22 -0
  110. package/src/components/HeaderNavigationBar/HeaderNavigationBar.mdx +128 -0
  111. package/src/components/HeaderNavigationBar/HeaderNavigationBar.stories.ts +784 -0
  112. package/src/components/HeaderNavigationBar/HeaderNavigationBar.vue +194 -0
  113. package/src/components/HeaderNavigationBar/HorizontalNavbar/HorizontalNavbar.vue +74 -0
  114. package/src/components/HeaderNavigationBar/HorizontalNavbar/config.ts +18 -0
  115. package/src/components/HeaderNavigationBar/tests/HeaderNavigationBar.spec.ts +127 -0
  116. package/src/components/HeaderNavigationBar/types.ts +7 -0
  117. package/src/components/HeaderToolbar/HeaderToolbar.mdx +31 -0
  118. package/src/components/HeaderToolbar/HeaderToolbar.stories.ts +343 -0
  119. package/src/components/HeaderToolbar/HeaderToolbar.vue +487 -0
  120. package/src/components/HeaderToolbar/tests/HeaderToolbar.spec.ts +196 -0
  121. package/src/components/HeaderToolbar/types.d.ts +20 -0
  122. package/src/components/LangBtn/LangBtn.mdx +1 -1
  123. package/src/components/LangBtn/LangBtn.stories.ts +125 -8
  124. package/src/components/Logo/Logo.mdx +2 -2
  125. package/src/components/Logo/Logo.stories.ts +147 -1
  126. package/src/components/LogoBrandSection/LogoBrandSection.mdx +14 -0
  127. package/src/components/LogoBrandSection/LogoBrandSection.stories.ts +158 -0
  128. package/src/components/LogoBrandSection/LogoBrandSection.vue +312 -0
  129. package/src/components/LogoBrandSection/assets/ameli-pro.svg +1 -0
  130. package/src/components/LogoBrandSection/assets/ameli.svg +1 -0
  131. package/src/components/LogoBrandSection/assets/cnam.svg +1 -0
  132. package/src/components/LogoBrandSection/assets/compte-ameli.svg +1 -0
  133. package/src/components/LogoBrandSection/dividerDimensionsMapping.ts +14 -0
  134. package/src/components/LogoBrandSection/locales.ts +14 -0
  135. package/src/components/LogoBrandSection/secondaryLogoMapping.ts +24 -0
  136. package/src/components/LogoBrandSection/tests/LogoBrandSection.spec.ts +365 -0
  137. package/src/components/LogoBrandSection/tests/__snapshots__/LogoBrandSection.spec.ts.snap +14 -0
  138. package/src/components/LogoBrandSection/types.ts +8 -0
  139. package/src/components/NotificationBar/NotificationBar.mdx +6 -6
  140. package/src/components/NotificationBar/NotificationBar.stories.ts +1 -1
  141. package/src/components/NotificationBar/NotificationBar.vue +7 -9
  142. package/src/components/NotificationBar/tests/NotificationBar.spec.ts +1 -1
  143. package/src/components/PageContainer/PageContainer.mdx +1 -1
  144. package/src/components/PageContainer/PageContainer.stories.ts +86 -1
  145. package/src/components/PageContainer/PageContainer.vue +0 -1
  146. package/src/components/PhoneField/PhoneField.mdx +49 -0
  147. package/src/components/PhoneField/PhoneField.stories.ts +869 -0
  148. package/src/components/PhoneField/PhoneField.vue +230 -0
  149. package/src/components/PhoneField/indicatifs.ts +104 -0
  150. package/src/components/PhoneField/locales.ts +4 -0
  151. package/src/components/PhoneField/tests/PhoneField.spec.ts +179 -0
  152. package/src/components/SkipLink/SkipLink.stories.ts +50 -1
  153. package/src/components/SocialMediaLinks/SocialMediaLinks.mdx +28 -1
  154. package/src/components/SocialMediaLinks/SocialMediaLinks.stories.ts +37 -1
  155. package/src/components/SubHeader/SubHeader.mdx +31 -0
  156. package/src/components/SubHeader/SubHeader.stories.ts +1032 -0
  157. package/src/components/SubHeader/SubHeader.vue +185 -0
  158. package/src/components/SubHeader/config.ts +12 -0
  159. package/src/components/SubHeader/locales.ts +3 -0
  160. package/src/components/SubHeader/tests/SubHeader.spec.ts +144 -0
  161. package/src/components/index.ts +24 -7
  162. package/src/composables/widthable/index.ts +29 -0
  163. package/src/composables/widthable/tests/widthable.spec.ts +52 -0
  164. package/src/designTokens/tokens/cnam/cnamLightTheme.ts +2 -2
  165. package/src/main.ts +1 -0
  166. package/src/modules.d.ts +4 -0
  167. package/src/services/index.ts +1 -0
  168. package/src/stories/Demarrer/Accueil.mdx +10 -0
  169. package/src/stories/Demarrer/Accueil.stories.ts +76 -0
  170. package/src/stories/Demarrer/PolitiqueDeConfidentialite.mdx +9 -0
  171. package/src/stories/Demarrer/PolitiqueDeConfidentialite.stories.ts +20 -0
  172. package/src/stories/Fondamentaux/Accessibilite/Accessibilite.mdx +1 -2
  173. package/src/stories/Fondamentaux/Accessibilite/Accessibilite.stories.ts +1 -1
  174. package/src/stories/Fondamentaux/EcoConception/Econception.stories.ts +1 -1
  175. package/src/stories/GuideDuDev/moduleDeNotification.mdx +52 -48
  176. package/src/stories/GuideDuDev/vuetifyOptions.mdx +31 -28
  177. package/src/stories/Guidelines/CustomisationEtThemes.mdx +1 -1
  178. package/src/utils/functions/throttleDisplayFn/tests/throttleDisplayFn.spec.ts +47 -0
  179. package/src/utils/functions/throttleDisplayFn/throttleDisplayFn.ts +26 -0
  180. package/src/utils/rules/exactLength/index.ts +33 -0
  181. package/src/utils/rules/exactLength/locales.ts +6 -0
  182. package/src/utils/rules/required/index.ts +25 -0
  183. package/src/utils/rules/required/locales.ts +5 -0
  184. package/src/utils/rules/required/ruleMessageHelper.ts +14 -0
  185. package/src/utils/rules/required/tests/index.spec.ts +47 -0
  186. package/src/utils/rules/required/tests/rulesMessageHelper.spec.ts +22 -0
  187. package/src/utils/rules/types.d.ts +15 -0
  188. package/src/components/Beta/beta.mdx +0 -5
  189. package/src/components/Deprecated/deprecated.mdx +0 -5
  190. package/src/stories/Home/Accueil.mdx +0 -7
  191. package/src/stories/Home/PolitiqueDeConfidentialite.mdx +0 -4
  192. package/src/stories/Home/synapse.webp +0 -0
  193. /package/src/components/Logo/{types.d.ts → types.ts} +0 -0
@@ -0,0 +1,487 @@
1
+ <script lang="ts" setup>
2
+ import { ref, type PropType } from 'vue'
3
+ import type { MenuItem, SelectItem } from './types'
4
+ import CustomInputSelect from '../Customs/CustomInputSelect/CustomInputSelect.vue'
5
+
6
+ const props = defineProps({
7
+ leftMenu: {
8
+ type: Array as PropType<MenuItem[]>,
9
+ default: () => [
10
+ {
11
+ title: 'Assuré',
12
+ href: 'https://www.ameli.fr/assure',
13
+ openInNewTab: true,
14
+ },
15
+ {
16
+ title: 'Professionnel de santé',
17
+ },
18
+ {
19
+ title: 'Entreprise',
20
+ href: 'https://www.ameli.fr/entreprise',
21
+ openInNewTab: true,
22
+ },
23
+ ],
24
+ },
25
+ rightMenu: {
26
+ type: Array as PropType<MenuItem[]>,
27
+ default: () => [
28
+ {
29
+ title: 'Qui sommes-nous ?',
30
+ href: 'https://www.assurance-maladie.ameli.fr/qui-sommes-nous',
31
+ openInNewTab: true,
32
+ },
33
+ {
34
+ title: 'Carrières',
35
+ href: 'https://www.assurance-maladie.ameli.fr/carrieres',
36
+ openInNewTab: true,
37
+ },
38
+ {
39
+ title: 'Études et données',
40
+ href: 'https://www.assurance-maladie.ameli.fr/etudes-et-donnees',
41
+ openInNewTab: true,
42
+ },
43
+ {
44
+ title: 'Presse',
45
+ href: 'https://www.assurance-maladie.ameli.fr/presse',
46
+ openInNewTab: true,
47
+ },
48
+ ],
49
+ },
50
+ itemsSelectMenu: {
51
+ type: Array as PropType<SelectItem[]>,
52
+ default: () => [
53
+ {
54
+ text: 'Chirurgien-dentiste',
55
+ value: 'Chirurgien-dentiste',
56
+ href: 'https://www.ameli.fr/chirurgien-dentiste',
57
+ openInNewTab: true,
58
+ },
59
+ {
60
+ text: 'Établissement',
61
+ value: 'Établissement',
62
+ href: 'https://www.ameli.fr/etablissement',
63
+ openInNewTab: true,
64
+ },
65
+ {
66
+ text: 'Exercice coordonné',
67
+ value: 'Exercice coordonné',
68
+ href: 'https://www.ameli.fr/exercice-coordonne',
69
+ openInNewTab: true,
70
+ },
71
+ {
72
+ text: 'Infirmier',
73
+ value: 'Infirmier',
74
+ href: 'https://www.ameli.fr/infirmier',
75
+ openInNewTab: true,
76
+ },
77
+ {
78
+ text: 'Laboratoire d\'analyses médicales',
79
+ value: 'Laboratoire d\'analyses médicales',
80
+ href: 'https://www.ameli.fr/laboratoire-danalyses-medicales',
81
+ openInNewTab: true,
82
+ },
83
+ {
84
+ text: 'Masseur-kinésithérapeute',
85
+ value: 'Masseur-kinésithérapeute',
86
+ href: 'https://www.ameli.fr/masseur-kinesitherapeute',
87
+ openInNewTab: true,
88
+ },
89
+ {
90
+ text: 'Médecin',
91
+ value: 'Médecin',
92
+ href: 'https://www.ameli.fr/medecin',
93
+ openInNewTab: true,
94
+ },
95
+ {
96
+ text: 'Orthophoniste',
97
+ value: 'Orthophoniste',
98
+ href: 'https://www.ameli.fr/orthophoniste',
99
+ openInNewTab: true,
100
+ },
101
+ {
102
+ text: 'Orthoptiste',
103
+ value: 'Orthoptiste',
104
+ href: 'https://www.ameli.fr/orthoptiste',
105
+ openInNewTab: true,
106
+ },
107
+ {
108
+ text: 'Pédicure-podologue',
109
+ value: 'Pédicure-podologue',
110
+ href: 'https://www.ameli.fr/pedicure-podologue',
111
+ openInNewTab: true,
112
+ },
113
+ {
114
+ text: 'Pharmacien',
115
+ value: 'Pharmacien',
116
+ href: 'https://www.ameli.fr/pharmacien',
117
+ openInNewTab: true,
118
+ },
119
+ {
120
+ text: 'Professionnel de la LPP/LATM',
121
+ value: 'Professionnel de la LPP/LATM',
122
+ href: 'https://www.ameli.fr/professionnel-de-la-lpplatm',
123
+ openInNewTab: true,
124
+ },
125
+ {
126
+ text: 'Psychologue',
127
+ value: 'Psychologue',
128
+ href: 'https://www.ameli.fr/psychologue',
129
+ openInNewTab: true,
130
+ },
131
+ {
132
+ text: 'Sage-femme',
133
+ value: 'Sage-femme',
134
+ href: 'https://www.ameli.fr/sage-femme',
135
+ openInNewTab: true,
136
+ },
137
+ {
138
+ text: 'Taxi conventionné',
139
+ value: 'Taxi conventionné',
140
+ href: 'https://www.ameli.fr/taxi-conventionne',
141
+ openInNewTab: true,
142
+ },
143
+ {
144
+ text: 'Transporteur sanitaire',
145
+ value: 'Transporteur sanitaire',
146
+ href: 'https://www.ameli.fr/transporteur-sanitaire',
147
+ openInNewTab: true,
148
+ },
149
+ ],
150
+ },
151
+ ariaLeftMenu: {
152
+ type: String,
153
+ default: 'left-menu',
154
+ },
155
+ ariaRightMenu: {
156
+ type: String,
157
+ default: 'right-menu',
158
+ },
159
+ })
160
+
161
+ const getLinkComponent = (item: MenuItem): string => {
162
+ if (item.href) {
163
+ return 'a'
164
+ }
165
+ else if (item.to) {
166
+ return 'RouterLink'
167
+ }
168
+ else {
169
+ return 'a' // fix doc
170
+ }
171
+ }
172
+
173
+ const showOverlay = ref(false)
174
+ const highlightMenu = ref(false)
175
+ const activeIndex = ref<number | null>(null)
176
+
177
+ const hideOverlay = () => {
178
+ const activeSelected = document.querySelector('.custom-select > span')?.textContent
179
+ if (activeSelected && activeSelected === 'Professionnel de santé') {
180
+ highlightMenu.value = false
181
+ }
182
+ showOverlay.value = false
183
+ }
184
+ const handleLink = (index: number) => {
185
+ if (index === 1) {
186
+ showOverlay.value = !showOverlay.value
187
+ }
188
+ }
189
+ const checkActiveLink = (index: number) => {
190
+ activeIndex.value = index
191
+ if (index !== 1) {
192
+ highlightMenu.value = false
193
+ }
194
+ }
195
+
196
+ const deleteActiveLink = () => {
197
+ activeIndex.value = null
198
+ }
199
+
200
+ defineExpose({
201
+ hideOverlay,
202
+ handleLink,
203
+ checkActiveLink,
204
+ deleteActiveLink,
205
+ activeIndex,
206
+ highlightMenu,
207
+ showOverlay,
208
+ getLinkComponent,
209
+ })
210
+ </script>
211
+
212
+ <template>
213
+ <div class="toolbar">
214
+ <div class="container">
215
+ <slot name="left-menu">
216
+ <button
217
+ v-if="showOverlay"
218
+ aria-label="Close overlay"
219
+ class="overlay"
220
+ @click="hideOverlay"
221
+ @keydown.enter="hideOverlay"
222
+ @keydown.esc="hideOverlay"
223
+ />
224
+ <nav
225
+ id="left-menu"
226
+ :aria-labelledby="props.ariaLeftMenu"
227
+ role="navigation"
228
+ >
229
+ <ul>
230
+ <li
231
+ v-for="(item, index) in props.leftMenu"
232
+ :key="index"
233
+ :class="{ 'active': activeIndex === index, 'highlight': highlightMenu }"
234
+ >
235
+ <component
236
+ :is="getLinkComponent(item as MenuItem)"
237
+ :aria-label="item.title"
238
+ :href="item.href"
239
+ :rel="item.openInNewTab ? 'noopener noreferrer' : undefined"
240
+ :tabindex="0"
241
+ :target="item.openInNewTab ? '_blank' : undefined"
242
+ :title="item.title"
243
+ :to="item.to"
244
+ @click="checkActiveLink(index)"
245
+ @focus="index === 1 && showOverlay ? highlightMenu = true : null"
246
+ @mouseover="index === 1 && showOverlay ? highlightMenu = true : null"
247
+ >
248
+ <span v-if="itemsSelectMenu && index === 1">
249
+ <CustomInputSelect
250
+ :items="itemsSelectMenu as unknown as string[]"
251
+ :label="item.title"
252
+ is-header-toolbar
253
+ @click="handleLink(index)"
254
+ />
255
+ </span>
256
+ <span
257
+ v-else
258
+ class="link"
259
+ >
260
+ {{ item.title }}
261
+ </span>
262
+ </component>
263
+ </li>
264
+ </ul>
265
+ </nav>
266
+ </slot>
267
+ <slot name="right-menu">
268
+ <nav
269
+ id="right-menu"
270
+ :aria-labelledby="props.ariaRightMenu"
271
+ role="navigation"
272
+ >
273
+ <ul>
274
+ <li
275
+ v-for="(item, index) in props.rightMenu"
276
+ :key="index"
277
+ >
278
+ <component
279
+ :is="getLinkComponent(item as MenuItem)"
280
+ :aria-label="item.title"
281
+ :href="item.href"
282
+ :rel="item.openInNewTab ? 'noopener noreferrer' : undefined"
283
+ :tabindex="0"
284
+ :target="item.openInNewTab ? '_blank' : undefined"
285
+ :title="item.title"
286
+ :to="item.to"
287
+ @click="deleteActiveLink()"
288
+ >
289
+ <span class="right-menu-item">{{ item.title }}</span>
290
+ </component>
291
+ </li>
292
+ </ul>
293
+ </nav>
294
+ </slot>
295
+ </div>
296
+ </div>
297
+ </template>
298
+
299
+ <style lang="scss" scoped>
300
+ @use '@/assets/tokens.scss';
301
+ @use '../HeaderBar/consts' as *;
302
+
303
+ .toolbar {
304
+ background: tokens.$blue-lighten-90;
305
+ position: relative;
306
+ display: flex;
307
+ align-items: center;
308
+ justify-content: center;
309
+ z-index: 100;
310
+
311
+ .container {
312
+ width: 100%;
313
+ max-height: 45px;
314
+ max-width: $header-max-width;
315
+ display: flex;
316
+ align-items: center;
317
+ justify-content: space-between;
318
+ @media (max-width: 768px) {
319
+ max-height: 41px;
320
+ }
321
+
322
+ :deep(ul) {
323
+ display: flex;
324
+ align-items: center;
325
+ justify-content: flex-start;
326
+ list-style: none;
327
+ text-decoration: none;
328
+
329
+ li {
330
+ text-align: center;
331
+ }
332
+ }
333
+
334
+ :deep(ul > li > a) {
335
+ display: block;
336
+ color: tokens.$blue-darken-40;
337
+ text-decoration: none;
338
+ padding: 10px 16px;
339
+ cursor: pointer;
340
+
341
+ &:hover {
342
+ text-decoration: underline;
343
+ }
344
+
345
+ @media (max-width: 768px) {
346
+ font-size: 12px;
347
+ }
348
+ }
349
+ }
350
+
351
+ #left-menu {
352
+ ul > li > a {
353
+ font-weight: 700;
354
+ color: tokens.$blue-darken-40;
355
+
356
+ &:hover {
357
+ text-decoration: none;
358
+ }
359
+ }
360
+
361
+ li:first-child {
362
+ min-width: 95px;
363
+ background: transparent;
364
+ @media (max-width: $header-breakpoint) {
365
+ min-width: 82px;
366
+ }
367
+ }
368
+
369
+ li:nth-child(2) {
370
+ min-width: 260px;
371
+ z-index: 2;
372
+ @media (max-width: 768px) {
373
+ min-width: 152px;
374
+ }
375
+ }
376
+
377
+ li:nth-child(3) {
378
+ background: transparent;
379
+ }
380
+
381
+ li:first-child a:hover, li:first-child.active {
382
+ background: tokens.$user-assure;
383
+ }
384
+
385
+ li:nth-child(2) a:hover, .highlight {
386
+ background: tokens.$user-professionnel;
387
+ }
388
+
389
+ li:nth-child(3) a:hover, li:nth-child(3).active {
390
+ background: tokens.$user-entreprise;
391
+ }
392
+ }
393
+
394
+ #right-menu {
395
+ @media (max-width: 1000px) {
396
+ display: none;
397
+ }
398
+ }
399
+
400
+ #right-menu ul {
401
+ white-space: nowrap;
402
+ overflow: hidden;
403
+ }
404
+
405
+ #right-menu ul li {
406
+ display: inline-block;
407
+ }
408
+
409
+ :deep(.v-input) {
410
+ .v-input__details {
411
+ display: none;
412
+ }
413
+
414
+ .v-input__control {
415
+ font-weight: 700;
416
+
417
+ .text-color {
418
+ color: tokens.$blue-darken-60 !important;
419
+ }
420
+
421
+ .v-icon {
422
+ margin-left: 10px;
423
+ }
424
+
425
+ .custom-select {
426
+ display: flex;
427
+ justify-content: space-between;
428
+ width: 100%;
429
+
430
+ span {
431
+ max-width: 260px;
432
+ white-space: nowrap;
433
+ overflow: hidden;
434
+ text-overflow: ellipsis;
435
+ @media (max-width: 768px) {
436
+ max-width: 182px;
437
+ }
438
+ }
439
+ }
440
+
441
+ @media (max-width: 768px) {
442
+ font-size: 12px;
443
+ }
444
+ }
445
+
446
+ .v-list {
447
+ top: 34px !important;
448
+ left: -16px !important;
449
+ text-align: left;
450
+ min-width: 260px;
451
+ max-width: fit-content !important;
452
+ border-radius: 0;
453
+ @media (max-width: 768px) {
454
+ position: fixed;
455
+ top: 38px !important;
456
+ left: 0 !important;
457
+ min-width: 100% !important;
458
+ box-shadow: none !important;
459
+ }
460
+
461
+ .v-list-item--density-default.v-list-item--one-line {
462
+ min-height: 40px;
463
+ }
464
+ }
465
+ }
466
+
467
+ .overlay {
468
+ position: fixed;
469
+ display: block;
470
+ top: 0;
471
+ left: 0;
472
+ width: 100%;
473
+ height: 100%;
474
+ background-color: rgba(3, 16, 37, .5);
475
+ cursor: default;
476
+ backdrop-filter: blur(2px);
477
+ z-index: 1;
478
+ @media (max-width: 768px) {
479
+ display: none;
480
+ }
481
+ }
482
+ }
483
+
484
+ .right-menu-item {
485
+ color: tokens.$blue-darken-60;
486
+ }
487
+ </style>
@@ -0,0 +1,196 @@
1
+ import { mount } from '@vue/test-utils'
2
+ import { expect, describe, it } from 'vitest'
3
+ import HeaderToolbar from '../HeaderToolbar.vue'
4
+ import { vuetify } from '@tests/unit/setup'
5
+
6
+ describe('HeaderToolbar.vue', () => {
7
+ it('renders the component with default props', () => {
8
+ const wrapper = mount(HeaderToolbar, {
9
+ global: {
10
+ plugins: [vuetify],
11
+ },
12
+ props: {
13
+ leftMenu: [
14
+ {
15
+ title: 'Left',
16
+ to: '/',
17
+ ariaLabel: 'Left',
18
+ },
19
+ ],
20
+ rightMenu: [
21
+ {
22
+ title: 'Right',
23
+ to: '/',
24
+ ariaLabel: 'Right',
25
+ },
26
+ ],
27
+ },
28
+ })
29
+ expect(wrapper.exists()).toBe(true)
30
+ expect(wrapper.find('#left-menu').text()).toBe('Left')
31
+ expect(wrapper.find('#right-menu').text()).toBe('Right')
32
+ })
33
+
34
+ it('returns a link component with href', () => {
35
+ const wrapper = mount(HeaderToolbar, {
36
+ global: {
37
+ plugins: [vuetify],
38
+ },
39
+ props: {
40
+ leftMenu: [
41
+ {
42
+ title: 'Left',
43
+ href: '/',
44
+ ariaLabel: 'Left',
45
+ },
46
+ ],
47
+ },
48
+ })
49
+
50
+ expect(wrapper.html()).toContain('href="/"')
51
+ })
52
+
53
+ it('returns a link component with to', () => {
54
+ const wrapper = mount(HeaderToolbar, {
55
+ global: {
56
+ plugins: [vuetify],
57
+ },
58
+ props: {
59
+ leftMenu: [
60
+ {
61
+ title: 'Left',
62
+ to: '/home',
63
+ ariaLabel: 'Left',
64
+ },
65
+ ],
66
+ },
67
+ })
68
+
69
+ expect(wrapper.html()).toContain('to="/home"')
70
+ })
71
+
72
+ it('hides the overlay', async () => {
73
+ const wrapper = mount(HeaderToolbar, {
74
+ global: {
75
+ plugins: [vuetify],
76
+ },
77
+ })
78
+
79
+ await wrapper.vm.hideOverlay()
80
+ expect(wrapper.vm.showOverlay).toBe(false)
81
+ })
82
+
83
+ it('toggles the overlay when handleLink is called', async () => {
84
+ const wrapper = mount(HeaderToolbar, {
85
+ global: {
86
+ plugins: [vuetify],
87
+ },
88
+ })
89
+
90
+ await wrapper.vm.handleLink(1)
91
+ expect(wrapper.vm.showOverlay).toBe(true)
92
+
93
+ await wrapper.vm.handleLink(1)
94
+ expect(wrapper.vm.showOverlay).toBe(false)
95
+ })
96
+
97
+ it('sets the active link correctly', async () => {
98
+ const wrapper = mount(HeaderToolbar, {
99
+ global: {
100
+ plugins: [vuetify],
101
+ },
102
+ })
103
+
104
+ await wrapper.vm.checkActiveLink(1)
105
+ expect(wrapper.vm.activeIndex).toBe(1)
106
+ })
107
+
108
+ it('should set showOverlay to true when handleLink is called', async () => {
109
+ const wrapper = mount(HeaderToolbar, {
110
+ global: {
111
+ plugins: [vuetify],
112
+ },
113
+ })
114
+
115
+ await wrapper.vm.handleLink(1)
116
+ await wrapper.vm.checkActiveLink(1)
117
+
118
+ expect(wrapper.vm.showOverlay).toBe(true)
119
+ expect(wrapper.vm.activeIndex).toBe(1)
120
+ })
121
+
122
+ it('hides the overlay when hideOverlay is called', async () => {
123
+ const wrapper = mount(HeaderToolbar, {
124
+ global: {
125
+ plugins: [vuetify],
126
+ },
127
+ })
128
+
129
+ wrapper.vm.showOverlay = true
130
+ await wrapper.vm.hideOverlay()
131
+ expect(wrapper.vm.showOverlay).toBe(false)
132
+ expect(wrapper.vm.highlightMenu).toBe(false)
133
+ })
134
+
135
+ it('should set showOverlay to false when handleLink is called', async () => {
136
+ const wrapper = mount(HeaderToolbar, {
137
+ global: {
138
+ plugins: [vuetify],
139
+ },
140
+ })
141
+
142
+ await wrapper.vm.handleLink(0)
143
+ await wrapper.vm.checkActiveLink(0)
144
+
145
+ expect(wrapper.vm.showOverlay).toBe(false)
146
+ expect(wrapper.vm.activeIndex).toBe(0)
147
+ })
148
+
149
+ it('should set highlightMenu to false when handleLink is called', async () => {
150
+ const wrapper = mount(HeaderToolbar, {
151
+ global: {
152
+ plugins: [vuetify],
153
+ },
154
+ props: {
155
+ leftMenu: [
156
+ {
157
+ title: 'Left',
158
+ to: '/',
159
+ ariaLabel: 'Left',
160
+ },
161
+ {
162
+ title: 'Professionnel de santé',
163
+ to: '/',
164
+ ariaLabel: 'Professionnel de santé',
165
+ },
166
+ ],
167
+ itemsSelectMenu: [
168
+ { text: 'Option 1', value: '1' },
169
+ { text: 'Option 2', value: '2' },
170
+ ],
171
+ },
172
+ })
173
+
174
+ await wrapper.vm.$nextTick()
175
+
176
+ await wrapper.vm.handleLink(1)
177
+ await wrapper.vm.hideOverlay()
178
+
179
+ expect(wrapper.vm.highlightMenu).toBe(false)
180
+
181
+ const activeSelected = wrapper.find('.custom-select > span')
182
+ expect(activeSelected.text()).toBe('Professionnel de santé')
183
+ })
184
+
185
+ it('should set activeIndex to -1 when deleteActiveLink is called', async () => {
186
+ const wrapper = mount(HeaderToolbar, {
187
+ global: {
188
+ plugins: [vuetify],
189
+ },
190
+ })
191
+
192
+ await wrapper.vm.deleteActiveLink()
193
+
194
+ expect(wrapper.vm.activeIndex).toBe(null)
195
+ })
196
+ })
@@ -0,0 +1,20 @@
1
+ import type { RouteLocationRaw } from 'vue-router'
2
+
3
+ export interface MenuItem {
4
+ title: string
5
+ href?: string
6
+ to?: RouteLocationRaw
7
+ ariaLabel?: string
8
+ openInNewTab?: boolean
9
+ }
10
+
11
+ export interface SelectItem {
12
+ text: string
13
+ value: string
14
+ hidden?: unknown
15
+ to?: RouteLocationRaw
16
+ href?: string
17
+ ariaLabel?: string
18
+ title?: string
19
+ openInNewTab?: boolean
20
+ }
@@ -17,7 +17,7 @@ Le composant `LangBtn` est utilisé pour afficher une alerte à l’utilisateur.
17
17
 
18
18
  <Source dark code={`
19
19
  <script setup lang="ts">
20
- import LangBtn from '@/components/LangBtn/LangBtn.vue'
20
+ import LangBtn from '@cnamts/synapse'
21
21
  import { ref } from 'vue'
22
22
 
23
23
  const value = ref('fr')