@cnamts/synapse 0.0.3-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 (185) hide show
  1. package/dist/design-system-v3.d.ts +712 -27
  2. package/dist/design-system-v3.js +2715 -1485
  3. package/dist/design-system-v3.umd.cjs +10 -1
  4. package/dist/style.css +1 -1
  5. package/package.json +5 -2
  6. package/src/components/Alert/Alert.mdx +1 -1
  7. package/src/components/Alert/Alert.stories.ts +91 -1
  8. package/src/components/BackBtn/BackBtn.mdx +1 -1
  9. package/src/components/BackBtn/BackBtn.stories.ts +84 -1
  10. package/src/components/BackToTopBtn/BackToTopBtn.mdx +3 -3
  11. package/src/components/BackToTopBtn/BackToTopBtn.stories.ts +172 -11
  12. package/src/components/CollapsibleList/CollapsibleList.mdx +2 -2
  13. package/src/components/CollapsibleList/CollapsibleList.stories.ts +37 -1
  14. package/src/components/CopyBtn/CopyBtn.mdx +1 -1
  15. package/src/components/CopyBtn/CopyBtn.stories.ts +120 -1
  16. package/src/components/CopyBtn/CopyBtn.vue +1 -1
  17. package/src/components/Customs/CustomInputSelect/CustomInputSelect.mdx +6 -8
  18. package/src/components/Customs/CustomInputSelect/CustomInputSelect.stories.ts +270 -4
  19. package/src/components/Customs/CustomInputSelect/CustomInputSelect.vue +80 -53
  20. package/src/components/Customs/CustomInputSelect/config.ts +10 -0
  21. package/src/components/Customs/CustomSelect/CustomSelect.mdx +3 -3
  22. package/src/components/Customs/CustomSelect/CustomSelect.stories.ts +158 -2
  23. package/src/components/Customs/CustomSelect/CustomSelect.vue +25 -6
  24. package/src/components/Customs/CustomTextField/CustomTextField.mdx +44 -0
  25. package/src/components/Customs/CustomTextField/CustomTextField.stories.ts +403 -0
  26. package/src/components/Customs/CustomTextField/CustomTextField.vue +110 -0
  27. package/src/components/Customs/CustomTextField/tests/CustomTextField.spec.ts +93 -0
  28. package/src/components/Customs/CustomTextField/tests/__snapshots__/CustomTextField.spec.ts.snap +59 -0
  29. package/src/components/Customs/CustomTextField/types.d.ts +3 -0
  30. package/src/components/DataList/DataList.mdx +77 -0
  31. package/src/components/DataList/DataList.stories.ts +960 -0
  32. package/src/components/DataList/DataList.vue +140 -0
  33. package/src/components/DataList/DataListLoading/DataListLoading.vue +56 -0
  34. package/src/components/DataList/DataListLoading/tests/DataListLoading.spec.ts +23 -0
  35. package/src/components/DataList/locales.ts +3 -0
  36. package/src/components/DataList/tests/DataList.spec.ts +194 -0
  37. package/src/components/DataList/types.d.ts +23 -0
  38. package/src/components/DataListGroup/DataListGroup.mdx +77 -0
  39. package/src/components/DataListGroup/DataListGroup.stories.ts +987 -0
  40. package/src/components/DataListGroup/DataListGroup.vue +59 -0
  41. package/src/components/DataListGroup/tests/DataListGroup.spec.ts +54 -0
  42. package/src/components/DataListGroup/tests/data/dataListGroupItems.ts +41 -0
  43. package/src/components/DataListGroup/types.d.ts +15 -0
  44. package/src/components/DataListItem/DataListItem.vue +135 -0
  45. package/src/components/DataListItem/config.ts +17 -0
  46. package/src/components/DataListItem/locales.ts +3 -0
  47. package/src/components/DataListItem/tests/DataListItem.spec.ts +156 -0
  48. package/src/components/DataListItem/types.d.ts +23 -0
  49. package/src/components/DownloadBtn/Accessibilite.mdx +14 -0
  50. package/src/components/DownloadBtn/Accessibilite.stories.ts +166 -0
  51. package/src/components/DownloadBtn/AccessibiliteItems.ts +129 -0
  52. package/src/components/DownloadBtn/DownloadBtn.mdx +5 -6
  53. package/src/components/DownloadBtn/DownloadBtn.stories.ts +207 -2
  54. package/src/components/DownloadBtn/constants/ExpertiseLevelEnum.ts +4 -0
  55. package/src/components/FooterBar/FooterBar.mdx +2 -2
  56. package/src/components/FooterBar/FooterBar.stories.ts +1 -1
  57. package/src/components/FranceConnectBtn/FranceConnectBtn.mdx +1 -1
  58. package/src/components/FranceConnectBtn/FranceConnectBtn.stories.ts +58 -1
  59. package/src/components/HeaderBar/HeaderBar.mdx +164 -45
  60. package/src/components/HeaderBar/HeaderBar.stories.ts +559 -15
  61. package/src/components/HeaderBar/HeaderBar.vue +60 -22
  62. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderBurgerMenu.mdx +433 -0
  63. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderBurgerMenu.stories.ts +1089 -0
  64. package/src/components/HeaderBar/{HeaderComplexMenu/HeaderComplexMenu.vue → HeaderBurgerMenu/HeaderBurgerMenu.vue} +74 -45
  65. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuItem/HeaderMenuItem.mdx +38 -0
  66. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuItem/HeaderMenuItem.stories.ts +89 -0
  67. package/src/components/HeaderBar/{HeaderComplexMenu → HeaderBurgerMenu}/HeaderMenuItem/tests/__snapshots__/HeaderMenuItem.spec.ts.snap +1 -1
  68. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuSection/HeaderMenuSection.mdx +17 -0
  69. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuSection/HeaderMenuSection.stories.ts +121 -0
  70. package/src/components/HeaderBar/{HeaderComplexMenu → HeaderBurgerMenu}/HeaderMenuSection/HeaderMenuSection.vue +2 -2
  71. package/src/components/HeaderBar/{HeaderComplexMenu → HeaderBurgerMenu}/HeaderMenuSection/tests/HeaderMenuSection.spec.ts +1 -3
  72. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderSubMenu/HeaderSubMenu.mdx +43 -0
  73. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderSubMenu/HeaderSubMenu.stories.ts +261 -0
  74. package/src/components/HeaderBar/{HeaderComplexMenu → HeaderBurgerMenu}/HeaderSubMenu/HeaderSubMenu.vue +17 -3
  75. package/src/components/HeaderBar/{HeaderComplexMenu → HeaderBurgerMenu}/HeaderSubMenu/tests/HeaderSubMenu.spec.ts +1 -1
  76. package/src/components/HeaderBar/HeaderBurgerMenu/tests/HeaderBurgerMenu.spec.ts +180 -0
  77. package/src/components/HeaderBar/HeaderBurgerMenu/tests/__snapshots__/HeaderBurgerMenu.spec.ts.snap +13 -0
  78. package/src/components/HeaderBar/HeaderBurgerMenu/tests/__snapshots__/HeaderComplexMenu.spec.ts.snap +13 -0
  79. package/src/components/HeaderBar/HeaderLogo/HeaderLogo.vue +62 -25
  80. package/src/components/HeaderBar/HeaderLogo/tests/HeaderLogo.spec.ts +49 -1
  81. package/src/components/HeaderBar/HeaderMenuBtn/HeaderMenuBtn.vue +19 -23
  82. package/src/components/HeaderBar/HeaderMenuBtn/tests/HeaderMenuBtn.spec.ts +70 -0
  83. package/src/components/HeaderBar/Usages.mdx +85 -0
  84. package/src/components/HeaderBar/consts.scss +0 -1
  85. package/src/components/HeaderBar/tests/HeaderBar.spec.ts +8 -2
  86. package/src/components/HeaderBar/tests/__snapshots__/HeaderBar.spec.ts.snap +5 -10
  87. package/src/components/HeaderLoading/HeaderLoading.mdx +28 -0
  88. package/src/components/HeaderLoading/HeaderLoading.stories.ts +62 -0
  89. package/src/components/HeaderLoading/HeaderLoading.vue +45 -0
  90. package/src/components/HeaderLoading/tests/HeaderLoading.spec.ts +22 -0
  91. package/src/components/HeaderNavigationBar/HeaderNavigationBar.mdx +128 -0
  92. package/src/components/HeaderNavigationBar/HeaderNavigationBar.stories.ts +784 -0
  93. package/src/components/HeaderNavigationBar/HeaderNavigationBar.vue +194 -0
  94. package/src/components/HeaderNavigationBar/HorizontalNavbar/HorizontalNavbar.vue +74 -0
  95. package/src/components/HeaderNavigationBar/HorizontalNavbar/config.ts +18 -0
  96. package/src/components/HeaderNavigationBar/tests/HeaderNavigationBar.spec.ts +127 -0
  97. package/src/components/HeaderNavigationBar/types.ts +7 -0
  98. package/src/components/HeaderToolbar/HeaderToolbar.mdx +31 -0
  99. package/src/components/HeaderToolbar/HeaderToolbar.stories.ts +343 -0
  100. package/src/components/HeaderToolbar/HeaderToolbar.vue +487 -0
  101. package/src/components/HeaderToolbar/tests/HeaderToolbar.spec.ts +196 -0
  102. package/src/components/HeaderToolbar/types.d.ts +20 -0
  103. package/src/components/LangBtn/LangBtn.mdx +1 -1
  104. package/src/components/LangBtn/LangBtn.stories.ts +125 -8
  105. package/src/components/Logo/Logo.mdx +2 -2
  106. package/src/components/Logo/Logo.stories.ts +147 -1
  107. package/src/components/LogoBrandSection/LogoBrandSection.mdx +14 -0
  108. package/src/components/LogoBrandSection/LogoBrandSection.stories.ts +158 -0
  109. package/src/components/LogoBrandSection/LogoBrandSection.vue +312 -0
  110. package/src/components/LogoBrandSection/assets/ameli-pro.svg +1 -0
  111. package/src/components/LogoBrandSection/assets/ameli.svg +1 -0
  112. package/src/components/LogoBrandSection/assets/cnam.svg +1 -0
  113. package/src/components/LogoBrandSection/assets/compte-ameli.svg +1 -0
  114. package/src/components/LogoBrandSection/dividerDimensionsMapping.ts +14 -0
  115. package/src/components/LogoBrandSection/locales.ts +14 -0
  116. package/src/components/LogoBrandSection/secondaryLogoMapping.ts +24 -0
  117. package/src/components/LogoBrandSection/tests/LogoBrandSection.spec.ts +365 -0
  118. package/src/components/LogoBrandSection/tests/__snapshots__/LogoBrandSection.spec.ts.snap +14 -0
  119. package/src/components/LogoBrandSection/types.ts +8 -0
  120. package/src/components/NotificationBar/NotificationBar.mdx +6 -6
  121. package/src/components/NotificationBar/NotificationBar.stories.ts +1 -1
  122. package/src/components/NotificationBar/NotificationBar.vue +2 -2
  123. package/src/components/NotificationBar/tests/NotificationBar.spec.ts +1 -1
  124. package/src/components/PageContainer/PageContainer.mdx +1 -1
  125. package/src/components/PageContainer/PageContainer.stories.ts +86 -1
  126. package/src/components/PhoneField/PhoneField.mdx +49 -0
  127. package/src/components/PhoneField/PhoneField.stories.ts +869 -0
  128. package/src/components/PhoneField/PhoneField.vue +230 -0
  129. package/src/components/PhoneField/indicatifs.ts +104 -0
  130. package/src/components/PhoneField/locales.ts +4 -0
  131. package/src/components/PhoneField/tests/PhoneField.spec.ts +179 -0
  132. package/src/components/SkipLink/SkipLink.stories.ts +50 -1
  133. package/src/components/SocialMediaLinks/SocialMediaLinks.mdx +28 -1
  134. package/src/components/SocialMediaLinks/SocialMediaLinks.stories.ts +37 -1
  135. package/src/components/SubHeader/SubHeader.mdx +31 -0
  136. package/src/components/SubHeader/SubHeader.stories.ts +1032 -0
  137. package/src/components/SubHeader/SubHeader.vue +185 -0
  138. package/src/components/SubHeader/config.ts +12 -0
  139. package/src/components/SubHeader/locales.ts +3 -0
  140. package/src/components/SubHeader/tests/SubHeader.spec.ts +144 -0
  141. package/src/components/index.ts +24 -7
  142. package/src/composables/widthable/index.ts +29 -0
  143. package/src/composables/widthable/tests/widthable.spec.ts +52 -0
  144. package/src/designTokens/tokens/cnam/cnamLightTheme.ts +2 -2
  145. package/src/main.ts +1 -0
  146. package/src/modules.d.ts +4 -0
  147. package/src/services/index.ts +1 -0
  148. package/src/stories/Demarrer/Accueil.mdx +10 -0
  149. package/src/stories/Demarrer/Accueil.stories.ts +76 -0
  150. package/src/stories/Demarrer/PolitiqueDeConfidentialite.mdx +9 -0
  151. package/src/stories/Demarrer/PolitiqueDeConfidentialite.stories.ts +20 -0
  152. package/src/stories/Fondamentaux/Accessibilite/Accessibilite.mdx +1 -2
  153. package/src/stories/Fondamentaux/Accessibilite/Accessibilite.stories.ts +1 -1
  154. package/src/stories/Fondamentaux/EcoConception/Econception.stories.ts +1 -1
  155. package/src/stories/GuideDuDev/moduleDeNotification.mdx +52 -48
  156. package/src/stories/GuideDuDev/vuetifyOptions.mdx +31 -28
  157. package/src/stories/Guidelines/CustomisationEtThemes.mdx +1 -1
  158. package/src/utils/functions/throttleDisplayFn/tests/throttleDisplayFn.spec.ts +47 -0
  159. package/src/utils/functions/throttleDisplayFn/throttleDisplayFn.ts +26 -0
  160. package/src/utils/rules/exactLength/index.ts +33 -0
  161. package/src/utils/rules/exactLength/locales.ts +6 -0
  162. package/src/utils/rules/required/index.ts +25 -0
  163. package/src/utils/rules/required/locales.ts +5 -0
  164. package/src/utils/rules/required/ruleMessageHelper.ts +14 -0
  165. package/src/utils/rules/required/tests/index.spec.ts +47 -0
  166. package/src/utils/rules/required/tests/rulesMessageHelper.spec.ts +22 -0
  167. package/src/utils/rules/types.d.ts +15 -0
  168. package/src/components/Beta/beta.mdx +0 -5
  169. package/src/components/Deprecated/deprecated.mdx +0 -5
  170. package/src/components/HeaderBar/HeaderComplexMenu/HeaderComplexMenu.stories.ts +0 -272
  171. package/src/components/HeaderBar/HeaderComplexMenu/HeaderMenuItem/HeaderMenuItem.stories.ts +0 -49
  172. package/src/components/HeaderBar/HeaderComplexMenu/HeaderMenuSection/HeaderMenuSection.stories.ts +0 -56
  173. package/src/components/HeaderBar/HeaderComplexMenu/HeaderSubMenu/HeaderSubMenu.stories.ts +0 -137
  174. package/src/components/HeaderBar/HeaderComplexMenu/tests/HeaderComplexMenu.spec.ts +0 -129
  175. package/src/components/HeaderBar/HeaderComplexMenu/tests/__snapshots__/HeaderComplexMenu.spec.ts.snap +0 -18
  176. package/src/stories/Home/Accueil.mdx +0 -7
  177. package/src/stories/Home/PolitiqueDeConfidentialite.mdx +0 -4
  178. package/src/stories/Home/synapse.webp +0 -0
  179. /package/src/components/HeaderBar/{HeaderComplexMenu → HeaderBurgerMenu}/HeaderMenuItem/HeaderMenuItem.vue +0 -0
  180. /package/src/components/HeaderBar/{HeaderComplexMenu → HeaderBurgerMenu}/HeaderMenuItem/tests/HeaderMenuItem.spec.ts +0 -0
  181. /package/src/components/HeaderBar/{HeaderComplexMenu → HeaderBurgerMenu}/conts.ts +0 -0
  182. /package/src/components/HeaderBar/{HeaderComplexMenu → HeaderBurgerMenu}/locals.ts +0 -0
  183. /package/src/components/HeaderBar/{HeaderComplexMenu → HeaderBurgerMenu}/tests/useHandleSubMenus.spec.ts +0 -0
  184. /package/src/components/HeaderBar/{HeaderComplexMenu → HeaderBurgerMenu}/useHandleSubMenus.ts +0 -0
  185. /package/src/components/Logo/{types.d.ts → types.ts} +0 -0
@@ -0,0 +1,261 @@
1
+ import type { Meta, StoryObj } from '@storybook/vue3'
2
+ import HeaderBar from '../../HeaderBar.vue'
3
+ import HeaderBurgerMenu from '../HeaderBurgerMenu.vue'
4
+ import HeaderMenuItem from '../HeaderMenuItem/HeaderMenuItem.vue'
5
+ import HeaderMenuSection from '../HeaderMenuSection/HeaderMenuSection.vue'
6
+ import HeaderSubMenu from './HeaderSubMenu.vue'
7
+
8
+ const meta = {
9
+ title: 'Composants/Structure/HeaderBar/HeaderBurgerMenu/HeaderSubMenu',
10
+ component: HeaderSubMenu,
11
+ argTypes: {
12
+ title: {
13
+ control: { type: 'text' },
14
+ description: 'Titre du sous-menu',
15
+ table: {
16
+ type: { summary: '{}' },
17
+ },
18
+ },
19
+ default: {
20
+ control: { type: 'text' },
21
+ description: 'Contenu du sous-menu, construit avec des composants `HeaderMenuSection`',
22
+ table: {
23
+ type: { summary: '{}' },
24
+ },
25
+ },
26
+ },
27
+ parameters: {
28
+ layout: 'fullscreen',
29
+ },
30
+ } satisfies Meta<typeof HeaderSubMenu>
31
+
32
+ export default meta
33
+
34
+ type Story = StoryObj<typeof meta>
35
+
36
+ export const Default: Story = {
37
+ args: {
38
+ title: 'Menu de premier niveau',
39
+ },
40
+ render: (args) => {
41
+ return {
42
+ components: { HeaderMenuItem, HeaderBurgerMenu, HeaderBar, HeaderSubMenu, HeaderMenuSection },
43
+ setup() {
44
+ return { args }
45
+ },
46
+ template: `
47
+ <HeaderBar>
48
+ <template #menu>
49
+ <HeaderBurgerMenu>
50
+ <HeaderMenuSection>
51
+ <HeaderMenuItem>
52
+ <a>Item</a>
53
+ </HeaderMenuItem>
54
+ <HeaderMenuItem>
55
+ <a>Item</a>
56
+ </HeaderMenuItem>
57
+ <headerMenuItem>
58
+ <HeaderSubMenu v-bind="args">
59
+ <template #title>
60
+ {{ args.title }}
61
+ </template>
62
+ <HeaderMenuItem>
63
+ <a>Item</a>
64
+ </HeaderMenuItem>
65
+ </HeaderSubMenu>
66
+ </headerMenuItem>
67
+ <HeaderMenuItem>
68
+ <a>Item</a>
69
+ </HeaderMenuItem>
70
+ </HeaderMenuSection>
71
+ </HeaderBurgerMenu>
72
+ </template>
73
+ </HeaderBar>
74
+ `,
75
+ }
76
+ },
77
+ play: async ({ canvasElement }) => {
78
+ const menuBtn = canvasElement.querySelector('button')
79
+ setTimeout(() => {
80
+ menuBtn!.click()
81
+ }, 1000)
82
+ },
83
+ parameters: {
84
+ sourceCode: [
85
+ {
86
+ name: 'Template',
87
+ code: `
88
+ <HeaderBar>
89
+ <template #menu>
90
+ <HeaderBurgerMenu>
91
+ <HeaderMenuSection>
92
+ <HeaderMenuItem>
93
+ <a>Item</a>
94
+ </HeaderMenuItem>
95
+ <HeaderMenuItem>
96
+ <a>Item</a>
97
+ </HeaderMenuItem>
98
+ <headerMenuItem>
99
+ <HeaderSubMenu>
100
+ <template #title>
101
+ Menu de premier niveau
102
+ </template>
103
+ <HeaderMenuItem>
104
+ <a>Item</a>
105
+ </HeaderMenuItem>
106
+ </HeaderSubMenu>
107
+ </headerMenuItem>
108
+ <HeaderMenuItem>
109
+ <a>Item</a>
110
+ </HeaderMenuItem>
111
+ </HeaderMenuSection>
112
+ </HeaderBurgerMenu>
113
+ </template>
114
+ </HeaderBar>
115
+ `,
116
+ },
117
+ {
118
+ name: 'Script',
119
+ code: `
120
+ <script setup>
121
+ import { HeaderBurgerMenu, HeaderBar, HeaderMenuSection, HeaderMenuItem, HeaderSubMenu } from '@cnamts/synapse'
122
+ </script>
123
+ `,
124
+ },
125
+ ],
126
+ },
127
+ }
128
+
129
+ export const Deep: Story = {
130
+ args: {
131
+ title: 'Menu de deuxième niveau',
132
+ },
133
+ render: (args) => {
134
+ return {
135
+ components: { HeaderMenuItem, HeaderBurgerMenu, HeaderBar, HeaderSubMenu, HeaderMenuSection },
136
+ setup() {
137
+ return { args }
138
+ },
139
+ template: `
140
+ <Template>
141
+ <HeaderBar>
142
+ <template #menu>
143
+ <HeaderBurgerMenu>
144
+ <HeaderMenuSection>
145
+ <HeaderMenuItem>
146
+ <a>Item 1</a>
147
+ </HeaderMenuItem>
148
+ <HeaderMenuItem>
149
+ <a>Item 2</a>
150
+ </HeaderMenuItem>
151
+ <headerMenuItem>
152
+ <HeaderSubMenu>
153
+ <template #title>
154
+ Menu de premier niveau
155
+ </template>
156
+ <HeaderMenuItem>
157
+ <a>Item 2.1</a>
158
+ </HeaderMenuItem>
159
+ <HeaderMenuItem>
160
+ <a>Item 2.2</a>
161
+ </HeaderMenuItem>
162
+ <HeaderMenuItem>
163
+ <HeaderSubMenu v-bind="args">
164
+ <template #title>
165
+ {{ args.title }}
166
+ </template>
167
+ <HeaderMenuItem>
168
+ <a>Item 3.1</a>
169
+ </HeaderMenuItem>
170
+ <HeaderMenuItem>
171
+ <a>Item 3.2</a>
172
+ </HeaderMenuItem>
173
+ </HeaderSubMenu>
174
+ </HeaderMenuItem>
175
+ </HeaderSubMenu>
176
+ </headerMenuItem>
177
+ <HeaderMenuItem>
178
+ <a>Item 3</a>
179
+ </HeaderMenuItem>
180
+ </HeaderMenuSection>
181
+ </HeaderBurgerMenu>
182
+ </template>
183
+ </HeaderBar>
184
+ </Template>
185
+ `,
186
+ }
187
+ },
188
+ play: async ({ canvasElement }) => {
189
+ const menuBtn = canvasElement.querySelector('button')
190
+ await new Promise(resolve => setTimeout(resolve, 1000))
191
+ await menuBtn!.click()
192
+ await new Promise(resolve => setTimeout(resolve, 500))
193
+ const subMenuBtn = document.querySelector<HTMLElement>('.sub-menu-btn')
194
+ await subMenuBtn!.click()
195
+ await new Promise(resolve => setTimeout(resolve, 500))
196
+ const subMenuBtn2 = document.querySelector<HTMLElement>('.sub-menu .sub-menu .sub-menu-btn')
197
+ await subMenuBtn2!.click()
198
+ },
199
+ parameters: {
200
+ sourceCode: [
201
+ {
202
+ name: 'Template',
203
+ code: `
204
+ <Template>
205
+ <HeaderBar>
206
+ <template #menu>
207
+ <HeaderBurgerMenu>
208
+ <HeaderMenuSection>
209
+ <HeaderMenuItem>
210
+ <a>Item 1</a>
211
+ </HeaderMenuItem>
212
+ <HeaderMenuItem>
213
+ <a>Item 2</a>
214
+ </HeaderMenuItem>
215
+ <headerMenuItem>
216
+ <HeaderSubMenu>
217
+ <template #title>
218
+ Menu de premier niveau
219
+ </template>
220
+ <HeaderMenuItem>
221
+ <a>Item 2.1</a>
222
+ </HeaderMenuItem>
223
+ <HeaderMenuItem>
224
+ <a>Item 2.2</a>
225
+ </HeaderMenuItem>
226
+ <HeaderMenuItem>
227
+ <HeaderSubMenu>
228
+ <template #title>
229
+ Menu de deuxième niveau
230
+ </template>
231
+ <HeaderMenuItem>
232
+ <a>Item 3.1</a>
233
+ </HeaderMenuItem>
234
+ <HeaderMenuItem>
235
+ <a>Item 3.2</a>
236
+ </HeaderMenuItem>
237
+ </HeaderSubMenu>
238
+ </HeaderMenuItem>
239
+ </HeaderSubMenu>
240
+ </headerMenuItem>
241
+ <HeaderMenuItem>
242
+ <a>Item 3</a>
243
+ </HeaderMenuItem>
244
+ </HeaderMenuSection>
245
+ </HeaderBurgerMenu>
246
+ </template>
247
+ </HeaderBar>
248
+ </Template>
249
+ `,
250
+ },
251
+ {
252
+ name: 'Script',
253
+ code: `
254
+ <script setup>
255
+ import { HeaderBurgerMenu, HeaderBar, HeaderMenuSection, HeaderMenuItem, HeaderSubMenu } from '@cnamts/synapse'
256
+ </script>
257
+ `,
258
+ },
259
+ ],
260
+ },
261
+ }
@@ -8,8 +8,10 @@
8
8
  const submenuId = useId()
9
9
  const btnId = `${submenuId}-btn`
10
10
 
11
- const registerSubMenu = inject<((r: DeepReadonly<Ref<boolean>>, c: () => void) => void) | undefined>(registerSubMenuKey, undefined)
12
- if (!registerSubMenu) throw new Error('The HeaderSubMenu component must be used inside a HeaderComplexMenu component')
11
+ const registerSubMenu = inject<
12
+ ((r: DeepReadonly<Ref<boolean>>, c: () => void) => void) | undefined
13
+ >(registerSubMenuKey, undefined)
14
+ if (!registerSubMenu) throw new Error('The HeaderSubMenu component must be used inside a HeaderBurgerMenu component')
13
15
  registerSubMenu(menuOpen, () => {
14
16
  menuOpen.value = false
15
17
  })
@@ -114,6 +116,13 @@
114
116
  border-bottom: 1px solid $menu-border-color;
115
117
  color: #000;
116
118
  background-color: transparent;
119
+
120
+ &:hover {
121
+ color: #000;
122
+ > :deep(*) {
123
+ color: #000 !important;
124
+ }
125
+ }
117
126
  }
118
127
 
119
128
  .sub-menu--open > .sub-menu-btn > :deep(.sub-menu-btn__icon) {
@@ -131,17 +140,22 @@
131
140
  background-color: $primary-base;
132
141
  color: $neutral-white;
133
142
  transition: color 0.15s linear, background-color 0.15s linear;
143
+
144
+ > :deep(*) {
145
+ color: $neutral-white !important;
146
+ }
134
147
  }
135
148
 
136
149
  .sub-menu-content-wrapper {
137
150
  position: absolute;
138
151
  top: 0;
152
+ bottom: 0;
139
153
  left: $menu-width;
140
154
  }
141
155
 
142
156
  .sub-menu-content {
143
157
  width: $menu-width + 1px;
144
- height: $menu-height;
158
+ height: 100%;
145
159
  background: #f9f9f9;
146
160
  border-left: 1px solid $menu-border-color;
147
161
  overflow-y: auto;
@@ -58,6 +58,6 @@ describe('HeaderSubMenu', () => {
58
58
  },
59
59
  })
60
60
 
61
- expect(mountWithoutInject).toThrowError('The HeaderSubMenu component must be used inside a HeaderComplexMenu component')
61
+ expect(mountWithoutInject).toThrowError('The HeaderSubMenu component must be used inside a HeaderBurgerMenu component')
62
62
  })
63
63
  })
@@ -0,0 +1,180 @@
1
+ import { vuetify } from '@tests/unit/setup'
2
+ import { mount } from '@vue/test-utils'
3
+ import { describe, expect, it, vi, afterAll } from 'vitest'
4
+ import { registerHeaderMenuKey } from '../../consts'
5
+ import HeaderBurgerMenu from '../HeaderBurgerMenu.vue'
6
+ import { defineComponent, toRef } from 'vue'
7
+
8
+ describe('HeaderBurgerMenu', () => {
9
+ const BtnTestComponent = defineComponent({
10
+ props: {
11
+ modelValue: {
12
+ type: Boolean,
13
+ default: false,
14
+ },
15
+ },
16
+ setup(props) {
17
+ return { open: toRef(props, 'modelValue'), focus: () => {} }
18
+ },
19
+ template: `<button @click="$emit('update:modelValue', !open)">Test</button>`,
20
+ })
21
+
22
+ vi.mock('@/utils/functions/throttleDisplayFn/throttleDisplayFn.ts', () => ({
23
+ default: (fn: (...args: unknown[]) => void) => fn,
24
+ }))
25
+
26
+ afterAll(() => {
27
+ vi.restoreAllMocks()
28
+ document.body.innerHTML = ''
29
+ })
30
+
31
+ it('should render the component', async () => {
32
+ const wrapper = mount(HeaderBurgerMenu, {
33
+ global: {
34
+ plugins: [vuetify],
35
+ provide: {
36
+ [registerHeaderMenuKey]: () => {},
37
+ },
38
+ stubs: {
39
+ teleport: true,
40
+ HeaderMenuBtn: BtnTestComponent,
41
+ },
42
+ },
43
+ slots: {
44
+ default: '<div>Default slot</div>',
45
+ },
46
+ attachTo: document.body,
47
+ })
48
+
49
+ expect(wrapper.find('.overlay').exists()).toBe(false)
50
+ const btn = wrapper.find('button')
51
+ await btn.trigger('click')
52
+ expect(wrapper.find('.overlay').exists()).toBe(true)
53
+ expect(wrapper.find('.overlay').html()).toMatchSnapshot()
54
+
55
+ wrapper.unmount()
56
+ })
57
+
58
+ it('should close the menu when clicking outside', async () => {
59
+ const wrapper = mount(HeaderBurgerMenu, {
60
+ global: {
61
+ plugins: [vuetify],
62
+ provide: {
63
+ [registerHeaderMenuKey]: () => {},
64
+ },
65
+ stubs: {
66
+ teleport: true,
67
+ HeaderMenuBtn: BtnTestComponent,
68
+ },
69
+ },
70
+ slots: {
71
+ default: '<div>Default slot</div>',
72
+ },
73
+ attachTo: document.body,
74
+ })
75
+
76
+ const btn = wrapper.find('button')
77
+
78
+ await btn.trigger('click')
79
+ expect(wrapper.find('.overlay').exists()).toBe(true)
80
+
81
+ await wrapper.find('.overlay').trigger('click')
82
+ expect(wrapper.find('.overlay').exists()).toBe(false)
83
+
84
+ wrapper.unmount()
85
+ })
86
+
87
+ it('should not close the menu when clicking inside', async () => {
88
+ const wrapper = mount(HeaderBurgerMenu, {
89
+ global: {
90
+ plugins: [vuetify],
91
+ provide: {
92
+ [registerHeaderMenuKey]: () => {},
93
+ },
94
+ stubs: {
95
+ teleport: true,
96
+ HeaderMenuBtn: BtnTestComponent,
97
+ },
98
+ },
99
+ slots: {
100
+ default: '<div>Default slot</div>',
101
+ },
102
+ attachTo: document.body,
103
+ })
104
+
105
+ const btn = wrapper.find('button')
106
+ await btn.trigger('click')
107
+ expect(wrapper.find('.overlay').exists()).toBe(true)
108
+
109
+ await wrapper.find('.header-menu').trigger('click')
110
+ expect(wrapper.find('.overlay').exists()).toBe(true)
111
+
112
+ wrapper.unmount()
113
+ })
114
+
115
+ it('should listen to the button to open and close the menu', async () => {
116
+ const wrapper = mount(HeaderBurgerMenu, {
117
+ global: {
118
+ plugins: [vuetify],
119
+ provide: {
120
+ [registerHeaderMenuKey]: () => {},
121
+ },
122
+ stubs: {
123
+ Teleport: true,
124
+ HeaderMenuBtn: BtnTestComponent,
125
+ },
126
+ },
127
+ slots: {
128
+ default: '<div>Default slot</div>',
129
+ },
130
+ attachTo: document.body,
131
+ })
132
+
133
+ const btn = wrapper.find('button')
134
+ await btn.trigger('click')
135
+ expect(wrapper.find('.overlay').exists()).toBe(true)
136
+
137
+ await btn.trigger('click')
138
+ expect(wrapper.find('.overlay').exists()).toBe(false)
139
+
140
+ wrapper.unmount()
141
+ })
142
+
143
+ it('reposition the menu when the size of the window changes', async () => {
144
+ const wrapper = mount(HeaderBurgerMenu, {
145
+ global: {
146
+ plugins: [vuetify],
147
+ provide: {
148
+ [registerHeaderMenuKey]: () => {},
149
+ },
150
+ stubs: {
151
+ Teleport: true,
152
+ HeaderMenuBtn: BtnTestComponent,
153
+ },
154
+ },
155
+ attachTo: document.body,
156
+ })
157
+
158
+ const btn = wrapper.find('button')
159
+ await btn.trigger('click')
160
+ const menuBtnWrapper = wrapper.find('[role="dialog"]>div')
161
+
162
+ vi.spyOn(menuBtnWrapper.element, 'getBoundingClientRect').mockReturnValue(new DOMRect(50, 50, 0, 0))
163
+
164
+ window.dispatchEvent(new Event('resize'))
165
+ await wrapper.vm.$nextTick()
166
+
167
+ let renderStyle = wrapper.find('.menu-wrapper').attributes('style')
168
+ expect(renderStyle).toContain('left: 50px; top: 50px;')
169
+
170
+ vi.spyOn(menuBtnWrapper.element, 'getBoundingClientRect').mockReturnValue(new DOMRect(40, 60, 0, 0))
171
+
172
+ window.dispatchEvent(new Event('resize'))
173
+ await wrapper.vm.$nextTick()
174
+
175
+ renderStyle = wrapper.find('.menu-wrapper').attributes('style')
176
+ expect(renderStyle).toContain('left: 40px; top: 60px;')
177
+
178
+ wrapper.unmount()
179
+ })
180
+ })
@@ -0,0 +1,13 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`HeaderBurgerMenu > should render the component 1`] = `
4
+ "<div data-v-18e6540e="" class="overlay">
5
+ <div data-v-18e6540e="" role="menu" class="menu-wrapper" style="left: 0px; top: 0px; height: calc(100vh - 0px - 48px);"><button data-v-18e6540e="">Test</button>
6
+ <nav data-v-18e6540e="" id="header-menu-wrapper" class="header-menu-wrapper" role="navigation" aria-label="Menu public">
7
+ <div data-v-18e6540e="" class="header-menu">
8
+ <div>Default slot</div>
9
+ </div>
10
+ </nav>
11
+ </div>
12
+ </div>"
13
+ `;
@@ -0,0 +1,13 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`HeaderBurgerMenu > should render the component 1`] = `
4
+ "<div data-v-18e6540e="" class="overlay">
5
+ <div data-v-18e6540e="" role="menu" class="menu-wrapper" style="left: 0px; top: 0px; height: calc(100vh - 0px - 48px);"><button data-v-18e6540e="">Test</button>
6
+ <nav data-v-18e6540e="" id="header-menu-wrapper" class="header-menu-wrapper" role="navigation" aria-label="Menu public">
7
+ <div data-v-18e6540e="" class="header-menu">
8
+ <div>Default slot</div>
9
+ </div>
10
+ </nav>
11
+ </div>
12
+ </div>"
13
+ `;
@@ -1,59 +1,92 @@
1
1
  <script lang="ts" setup>
2
+ import { computed, getCurrentInstance } from 'vue'
3
+ import type { RouteLocationRaw } from 'vue-router'
2
4
  import { useTheme } from 'vuetify'
3
5
  import useHeaderResponsiveMode from '../useHeaderResponsiveMode'
4
6
  import { locales } from './locales'
5
7
  import LogoMobile from './logos/Logo-mobile.vue'
6
8
  import Logo from './logos/Logo.vue'
7
9
 
8
- withDefaults(defineProps<{
10
+ const props = withDefaults(defineProps<{
9
11
  ariaLabel?: string
10
12
  serviceTitle?: string
11
13
  serviceSubtitle?: string
14
+ homeLink?: {
15
+ ariaLabel?: string
16
+ to?: RouteLocationRaw
17
+ href?: string
18
+ }
12
19
  }>(), {
13
20
  ariaLabel: locales.ariaLabel,
14
21
  serviceTitle: undefined,
15
22
  serviceSubtitle: undefined,
23
+ homeLink: () => ({
24
+ href: '/',
25
+ }),
16
26
  })
17
27
 
18
- const slot = defineSlots<{
19
- serviceTitle?(): void
28
+ defineSlots<{
29
+ 'brand-content'?(): void
20
30
  }>()
21
31
 
22
32
  const theme = useTheme()
23
33
  const primary = theme.current.value.colors.primary
24
34
  const { isDesktop } = useHeaderResponsiveMode()
35
+
36
+ const routeType = computed(() => {
37
+ if (props.homeLink?.to) {
38
+ const componentsRegistered = getCurrentInstance()?.appContext?.components
39
+ const hasRouterLink = componentsRegistered && 'RouterLink' in componentsRegistered
40
+ if (hasRouterLink) {
41
+ return 'router-link'
42
+ }
43
+ return 'div'
44
+ }
45
+ if (props.homeLink?.href) {
46
+ return 'a'
47
+ }
48
+ return 'div'
49
+ })
25
50
  </script>
26
51
 
27
52
  <template>
28
- <div class="logo">
53
+ <component
54
+ :is="routeType"
55
+ v-bind="{
56
+ to: 'to' in homeLink ? homeLink?.to : undefined,
57
+ href: 'href' in homeLink ? homeLink?.href : undefined,
58
+ 'aria-label': 'aria-label' in homeLink ? homeLink?.['aria-label'] : undefined,
59
+ }"
60
+ class="logo"
61
+ >
29
62
  <Logo
30
63
  v-if="isDesktop"
31
- :aria-label
64
+ :aria-label="props.ariaLabel"
32
65
  />
33
66
  <LogoMobile
34
67
  v-else
35
- :aria-label
68
+ :aria-label="props.ariaLabel"
36
69
  />
37
70
 
38
- <svg
39
- v-if="slot?.serviceTitle || serviceTitle"
40
- :width="22"
41
- :height="64"
42
- :fill="primary"
43
- role="img"
44
- focusable="false"
45
- aria-hidden="true"
46
- xmlns="http://www.w3.org/2000/svg"
47
- viewBox="0 0 22 64"
48
- class="vd-divider"
49
- >
50
- <path d="M14.3 49.3c-.2 0-.4-.2-.4-.4V14.2c0-.2.2-.4.4-.4.3 0 .5.2.5.4v34.7c0 .2-.2.4-.5.4Z" />
51
- </svg>
52
-
53
71
  <slot
54
- name="serviceTitle"
72
+ name="brand-content"
55
73
  >
56
- <div if="serviceTitle">
74
+ <svg
75
+ v-if="serviceTitle"
76
+ :width="22"
77
+ :height="64"
78
+ :fill="primary"
79
+ role="img"
80
+ focusable="false"
81
+ aria-hidden="true"
82
+ xmlns="http://www.w3.org/2000/svg"
83
+ viewBox="0 0 22 64"
84
+ class="vd-divider"
85
+ >
86
+ <path d="M14.3 49.3c-.2 0-.4-.2-.4-.4V14.2c0-.2.2-.4.4-.4.3 0 .5.2.5.4v34.7c0 .2-.2.4-.5.4Z" />
87
+ </svg>
88
+
89
+ <div v-if="serviceTitle">
57
90
  <div class="service-title">
58
91
  {{ serviceTitle }}
59
92
  </div>
@@ -65,18 +98,22 @@
65
98
  </div>
66
99
  </div>
67
100
  </slot>
68
- </div>
101
+ </component>
69
102
  </template>
70
103
 
71
104
  <style scoped lang="scss">
72
105
  @use '../consts' as *;
106
+ @use '@/assets/tokens.scss' as *;
73
107
 
74
108
  .logo {
75
109
  display: flex;
76
110
  height: 52px;
77
111
  align-items: center;
78
- color: v-bind(primary);
112
+ color: $primary-base;
79
113
  line-height: 1.45;
114
+ font-family: 'Cabin', 'Arial', 'Helvetica', sans-serif;
115
+ text-decoration: none;
116
+ cursor: pointer;
80
117
  }
81
118
 
82
119
  .logo :deep(svg) {