@cnamts/synapse 0.0.14-alpha → 0.0.16-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/dist/components/CookiesSelection/CookiesSelection.d.ts +26 -26
  2. package/dist/components/Customs/SyInputSelect/SyInputSelect.d.ts +2 -2
  3. package/dist/components/Customs/SySelect/SySelect.d.ts +24 -12
  4. package/dist/components/Customs/SySelect/locales.d.ts +3 -0
  5. package/dist/components/Customs/SyTextField/SyTextField.d.ts +1393 -3
  6. package/dist/components/DatePicker/DatePicker.d.ts +3532 -22
  7. package/dist/components/DatePicker/DateTextInput.d.ts +1408 -11
  8. package/dist/components/DialogBox/config.d.ts +1 -1
  9. package/dist/components/DownloadBtn/DownloadBtn.d.ts +2 -0
  10. package/dist/components/LangBtn/LangBtn.d.ts +467 -1
  11. package/dist/components/LangBtn/config.d.ts +1 -3
  12. package/dist/components/NirField/NirField.d.ts +2805 -15
  13. package/dist/components/PasswordField/PasswordField.d.ts +2 -2
  14. package/dist/components/PeriodField/PeriodField.d.ts +7345 -325
  15. package/dist/components/PhoneField/PhoneField.d.ts +3 -3
  16. package/dist/components/SelectBtnField/SelectBtnField.d.ts +1 -1
  17. package/dist/components/SkipLink/SkipLink.d.ts +3 -2
  18. package/dist/components/SyAlert/SyAlert.d.ts +72 -1
  19. package/dist/components/UploadWorkflow/UploadWorkflow.d.ts +26 -26
  20. package/dist/components/UserMenuBtn/UserMenuBtn.d.ts +2 -0
  21. package/dist/components/index.d.ts +2 -0
  22. package/dist/composables/date/useDateFormat.d.ts +2 -2
  23. package/dist/composables/date/useDateFormatDayjs.d.ts +23 -0
  24. package/dist/composables/date/useDateInitializationDayjs.d.ts +18 -0
  25. package/dist/design-system-v3.js +4314 -3987
  26. package/dist/design-system-v3.umd.cjs +1 -1
  27. package/dist/style.css +1 -1
  28. package/dist/vuetifyConfig.d.ts +1 -0
  29. package/package.json +1 -1
  30. package/src/components/BackBtn/Accessibilite.stories.ts +4 -0
  31. package/src/components/BackBtn/BackBtn.vue +2 -1
  32. package/src/components/BackToTopBtn/Accessibilite.stories.ts +4 -0
  33. package/src/components/BackToTopBtn/BackToTopBtn.stories.ts +78 -21
  34. package/src/components/BackToTopBtn/BackToTopBtn.vue +15 -0
  35. package/src/components/BackToTopBtn/config.ts +2 -2
  36. package/src/components/BackToTopBtn/tests/__snapshots__/BackToTopBtn.spec.ts.snap +4 -4
  37. package/src/components/CopyBtn/Accessibilite.stories.ts +4 -0
  38. package/src/components/Customs/SyBtnSelect/SyBtnSelect.stories.ts +2 -2
  39. package/src/components/Customs/SyBtnSelect/SyBtnSelect.vue +0 -1
  40. package/src/components/Customs/SyInputSelect/SyInputSelect.stories.ts +3 -3
  41. package/src/components/Customs/SyInputSelect/SyInputSelect.vue +4 -4
  42. package/src/components/Customs/SySelect/SySelect.stories.ts +4 -0
  43. package/src/components/Customs/SySelect/SySelect.vue +75 -10
  44. package/src/components/Customs/SySelect/locales.ts +3 -0
  45. package/src/components/Customs/SySelect/tests/SySelect.spec.ts +24 -2
  46. package/src/components/Customs/SyTextField/Accessibilite.stories.ts +7 -0
  47. package/src/components/Customs/SyTextField/SyTextField.stories.ts +14 -1
  48. package/src/components/Customs/SyTextField/SyTextField.vue +85 -20
  49. package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.vue +795 -0
  50. package/src/components/DatePicker/DatePicker.stories.ts +432 -1
  51. package/src/components/DatePicker/DatePicker.vue +143 -76
  52. package/src/components/DatePicker/DatePickerValidation.mdx +338 -0
  53. package/src/components/DatePicker/DatePickerValidation.stories.ts +30 -0
  54. package/src/components/DatePicker/DateTextInput.vue +87 -135
  55. package/src/components/DatePicker/docExamples/DatePickerBidirectionalValidation.vue +282 -0
  56. package/src/components/DatePicker/docExamples/DatePickerValidationExamples.vue +535 -0
  57. package/src/components/DatePicker/tests/DatePicker.spec.ts +33 -32
  58. package/src/components/DatePicker/tests/DateTextInput.spec.ts +83 -35
  59. package/src/components/DialogBox/DialogBox.stories.ts +5 -2
  60. package/src/components/DialogBox/DialogBox.vue +1 -1
  61. package/src/components/DialogBox/config.ts +1 -1
  62. package/src/components/DownloadBtn/Accessibilite.stories.ts +4 -0
  63. package/src/components/DownloadBtn/DownloadBtn.stories.ts +17 -8
  64. package/src/components/DownloadBtn/DownloadBtn.vue +13 -6
  65. package/src/components/DownloadBtn/tests/__snapshots__/DownloadBtn.spec.ts.snap +0 -2
  66. package/src/components/FranceConnectBtn/Accessibilite.stories.ts +4 -0
  67. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuItem/HeaderMenuItem.vue +3 -0
  68. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderSubMenu/HeaderSubMenu.vue +3 -0
  69. package/src/components/HeaderBar/HeaderBurgerMenu/menu.scss +19 -0
  70. package/src/components/HeaderBar/HeaderMenuBtn/HeaderMenuBtn.vue +12 -2
  71. package/src/components/LangBtn/Accessibilite.stories.ts +4 -0
  72. package/src/components/LangBtn/LangBtn.stories.ts +1 -4
  73. package/src/components/LangBtn/LangBtn.vue +68 -9
  74. package/src/components/LangBtn/config.ts +0 -1
  75. package/src/components/LangBtn/tests/LangBtn.spec.ts +30 -2
  76. package/src/components/PageContainer/Accessibilite.stories.ts +36 -23
  77. package/src/components/PaginatedTable/PaginatedTable.stories.ts +144 -18
  78. package/src/components/PasswordField/PasswordField.stories.ts +6 -6
  79. package/src/components/PasswordField/PasswordField.vue +3 -3
  80. package/src/components/PeriodField/PeriodField.vue +4 -4
  81. package/src/components/PhoneField/PhoneField.stories.ts +216 -24
  82. package/src/components/PhoneField/PhoneField.vue +32 -2
  83. package/src/components/PhoneField/tests/PhoneField.spec.ts +161 -14
  84. package/src/components/RatingPicker/NumberPicker/NumberPicker.vue +2 -1
  85. package/src/components/RatingPicker/RatingPicker.stories.ts +1 -1
  86. package/src/components/SkipLink/Accessibilite.stories.ts +8 -0
  87. package/src/components/SkipLink/SkipLink.vue +11 -9
  88. package/src/components/SkipLink/tests/__snapshots__/skipLink.spec.ts.snap +7 -4
  89. package/src/components/SkipLink/tests/skipLink.spec.ts +120 -6
  90. package/src/components/SyAlert/Accessibilite.stories.ts +4 -0
  91. package/src/components/SyAlert/SyAlert.mdx +3 -7
  92. package/src/components/SyAlert/SyAlert.stories.ts +19 -12
  93. package/src/components/SyAlert/SyAlert.vue +88 -51
  94. package/src/components/SyAlert/tests/SyAlert.spec.ts +20 -2
  95. package/src/components/SyAlert/tests/__snapshots__/SyAlert.spec.ts.snap +83 -75
  96. package/src/components/UserMenuBtn/UserMenuBtn.stories.ts +56 -0
  97. package/src/components/UserMenuBtn/UserMenuBtn.vue +4 -2
  98. package/src/components/UserMenuBtn/tests/UserMenuBtn.spec.ts +41 -0
  99. package/src/components/index.ts +2 -0
  100. package/src/composables/date/useDateFormat.ts +17 -1
  101. package/src/composables/date/useDateFormatDayjs.ts +84 -0
  102. package/src/composables/date/useDateInitializationDayjs.ts +133 -0
  103. package/src/composables/rules/useFieldValidation.ts +26 -3
  104. package/src/stories/Accessibilite/Avancement/Avancement.mdx +12 -0
  105. package/src/stories/Accessibilite/Avancement/Avancement.stories.ts +134 -0
  106. package/src/stories/Accessibilite/KitDePreAudit/Echantillonnage.mdx +1 -1
  107. package/src/stories/GuideDuDev/LesBreackingChanges.mdx +31 -2
  108. package/src/components/LangBtn/tests/Config.spec.ts +0 -24
@@ -38,7 +38,7 @@ describe('DateTextInput.vue', () => {
38
38
  await input.trigger('blur')
39
39
  await wrapper.vm.$nextTick()
40
40
  const textField = wrapper.findComponent(SyTextField)
41
- expect(textField.props('errorMessages')).toContain('Format de date invalide')
41
+ expect(textField.props('errorMessages')).toContain('Format de date invalide (DD/MM/YYYY)')
42
42
  })
43
43
 
44
44
  it('accepts valid date format', async () => {
@@ -116,20 +116,20 @@ describe('DateTextInput.vue', () => {
116
116
  },
117
117
  })
118
118
 
119
- // Force la validation en déclenchant un événement de perte de focus
119
+ // Force validation by triggering a blur event
120
120
  const input = wrapper.find('input')
121
121
  await input.trigger('focus')
122
122
  await input.trigger('blur')
123
123
  await wrapper.vm.$nextTick()
124
- await wrapper.vm.$nextTick() // Double nextTick pour s'assurer que les mises à jour sont terminées
125
- // On peut également forcer la validation manuellement
124
+ await wrapper.vm.$nextTick() // Double nextTick to ensure updates are completed
125
+ // We can also force validation manually
126
126
  await wrapper.vm.validateOnSubmit()
127
127
  await wrapper.vm.$nextTick()
128
128
  const textField = wrapper.findComponent(SyTextField)
129
129
  const warningMessages = textField.props('warningMessages') || []
130
- // Vérifier que le message d'avertissement est bien présent
130
+ // Check that the warning message is present
131
131
  expect(warningMessages.length).toBeGreaterThan(0)
132
- // Le message réel commence par "Attention :"
132
+ // The actual message starts with "Attention:"
133
133
  expect(warningMessages[0]).toContain('Attention :')
134
134
  })
135
135
 
@@ -139,7 +139,7 @@ describe('DateTextInput.vue', () => {
139
139
  await input.trigger('blur')
140
140
  await wrapper.vm.$nextTick()
141
141
  const textField = wrapper.findComponent(SyTextField)
142
- expect(textField.props('errorMessages')).toContain('Format de date invalide')
142
+ expect(textField.props('errorMessages')).toContain('Format de date invalide (DD/MM/YYYY)')
143
143
  })
144
144
 
145
145
  it('formats input while typing', async () => {
@@ -169,7 +169,7 @@ describe('DateTextInput.vue', () => {
169
169
  const input = wrapper.find('input')
170
170
  await input.trigger('blur')
171
171
  await wrapper.vm.$nextTick()
172
- expect(textField.props('errorMessages')).toContain('Format de date invalide')
172
+ expect(textField.props('errorMessages')).toContain('Format de date invalide (DD/MM/YYYY)')
173
173
  })
174
174
 
175
175
  it('formats date during input', async () => {
@@ -180,13 +180,13 @@ describe('DateTextInput.vue', () => {
180
180
  })
181
181
 
182
182
  it('handles date deletion', async () => {
183
- // D'abord on met une date valide
183
+ // First set a valid date
184
184
  const input = wrapper.find('input')
185
185
  await input.setValue('01/01/2025')
186
186
  await input.trigger('blur')
187
187
  await wrapper.vm.$nextTick()
188
188
 
189
- // Puis on la supprime
189
+ // Then delete it
190
190
  await input.setValue('')
191
191
  await input.trigger('input')
192
192
  await input.trigger('blur')
@@ -227,9 +227,9 @@ describe('DateTextInput.vue', () => {
227
227
  })
228
228
 
229
229
  it('handles readonly state', async () => {
230
- await wrapper.setProps({ readOnly: true })
230
+ await wrapper.setProps({ readonly: true })
231
231
  const textField = wrapper.findComponent(SyTextField)
232
- expect(textField.props('readOnly')).toBe(true)
232
+ expect(textField.props('readonly')).toBe(true)
233
233
  })
234
234
 
235
235
  it('emits focus and blur events', async () => {
@@ -266,19 +266,61 @@ describe('DateTextInput.vue', () => {
266
266
  await wrapper.vm.$nextTick()
267
267
  expect(input.element.value).toBe('01/__/____')
268
268
 
269
- // Simuler une position de curseur après le "01"
269
+ // Simulate cursor position after "01"
270
270
  input.element.setSelectionRange(2, 2)
271
271
  await input.trigger('input')
272
272
  await wrapper.vm.$nextTick()
273
273
 
274
- // La position du curseur devrait rester après le "01"
274
+ // The cursor position should remain after "01"
275
275
  expect(input.element.selectionStart).toBe(2)
276
276
  })
277
277
 
278
+ it('handles 2 digits year correctly', async () => {
279
+ const customWrapper = mount(DateTextInput, {
280
+ global: {
281
+ plugins: [vuetify],
282
+ },
283
+ props: {
284
+ modelValue: null,
285
+ format: 'DD/MM/YY',
286
+ dateFormatReturn: 'YYYY-MM-DD',
287
+ },
288
+ })
289
+
290
+ const input = customWrapper.find('input')
291
+ await input.setValue('0')
292
+ expect(input.element.value).toBe('0_/__/__')
293
+
294
+ await input.setValue('01/02/99')
295
+ expect(input.element.value).toBe('01/02/99')
296
+ expect(customWrapper.emitted('update:model-value')?.at(-1)).toEqual(['1999-02-01'])
297
+ })
298
+
299
+ it('handles ISO-8601 date format correctly', async () => {
300
+ const customWrapper = mount(DateTextInput, {
301
+ global: {
302
+ plugins: [vuetify],
303
+ },
304
+ props: {
305
+ modelValue: null,
306
+ format: 'YYYY-MM-DD',
307
+ },
308
+ })
309
+
310
+ const input = customWrapper.find('input')
311
+ await input.setValue('2025-')
312
+ expect(input.element.value).toBe('2025-__-__')
313
+ expect(customWrapper.emitted('update:model-value')).toBeFalsy()
314
+
315
+ await input.setValue('2025-01-01')
316
+ expect(input.element.value).toBe('2025-01-01')
317
+ expect(customWrapper.emitted('update:model-value')?.at(-1)).toEqual(['2025-01-01'])
318
+ })
319
+
278
320
  it('handles paste event with valid date', async () => {
279
321
  const input = wrapper.find('input')
280
322
 
281
- // Créer un événement de collage avec les données
323
+ // Create a paste event with data
282
324
  const clipboardData = {
283
325
  getData: () => '01/01/2025',
284
326
  }
@@ -297,26 +339,26 @@ describe('DateTextInput.vue', () => {
297
339
  await input.trigger('keydown', {
298
340
  key: 'Tab',
299
341
  })
300
- // Vérifier que le composant n'empêche pas la navigation par tab
342
+ // Check that the component doesn't prevent tab navigation
301
343
  expect(wrapper.emitted('update:model-value')).toBeFalsy()
302
344
 
303
- // Tester le comportement avec Ctrl+V (coller)
345
+ // Test behavior with Ctrl+V (paste)
304
346
  await input.trigger('keydown', {
305
347
  key: 'v',
306
348
  ctrlKey: true,
307
349
  })
308
- // Le comportement par défaut devrait être préservé
350
+ // Default behavior should be preserved
309
351
  expect(wrapper.emitted('update:model-value')).toBeFalsy()
310
352
  })
311
353
 
312
354
  it('validates on submit correctly', async () => {
313
355
  const input = wrapper.find('input')
314
356
 
315
- // Cas 1: Champ vide avec required=true
357
+ // Case 1: Empty field with required=true
316
358
  const emptyResult = await wrapper.vm.validateOnSubmit()
317
359
  expect(emptyResult).toBe(false)
318
360
 
319
- // Cas 2: Date valide
361
+ // Case 2: Valid date
320
362
  await input.setValue('01/01/2025')
321
363
  await input.trigger('blur')
322
364
  await wrapper.vm.$nextTick()
@@ -326,23 +368,29 @@ describe('DateTextInput.vue', () => {
326
368
  })
327
369
 
328
370
  it('handles focus and blur methods correctly', async () => {
329
- // Simuler un querySelector global
330
- const originalQuerySelector = document.querySelector
371
+ // Create a mock for the input element
331
372
  const mockInput = { focus: vi.fn(), blur: vi.fn() }
332
373
 
333
- // Remplacer document.querySelector
334
- document.querySelector = vi.fn().mockReturnValue(mockInput)
374
+ // Mock the component's querySelector method
375
+ const mockQuerySelector = vi.fn().mockReturnValue(mockInput)
376
+
377
+ // Replace the element reference and its querySelector method
378
+ wrapper.vm.inputRef = {
379
+ $el: {
380
+ querySelector: mockQuerySelector,
381
+ },
382
+ }
335
383
 
336
- // Appeler les méthodes exposées
384
+ // Call the exposed methods
337
385
  wrapper.vm.focus()
338
386
  wrapper.vm.blur()
339
387
 
340
- // Vérifier que les méthodes ont été appelées
388
+ // Check that querySelector was called with the right selector
389
+ expect(mockQuerySelector).toHaveBeenCalledWith('input:not([type="hidden"])')
390
+
391
+ // Check that the methods were called
341
392
  expect(mockInput.focus).toHaveBeenCalled()
342
393
  expect(mockInput.blur).toHaveBeenCalled()
343
-
344
- // Restaurer document.querySelector
345
- document.querySelector = originalQuerySelector
346
394
  })
347
395
 
348
396
  it('initializes with model value correctly', async () => {
@@ -383,17 +431,17 @@ describe('DateTextInput.vue', () => {
383
431
  it('handles partial date input correctly', async () => {
384
432
  const input = wrapper.find('input')
385
433
 
386
- // Saisir seulement le jour
434
+ // Enter only the day
387
435
  await input.setValue('01')
388
436
  await wrapper.vm.$nextTick()
389
437
  expect(input.element.value).toBe('01/__/____')
390
438
 
391
- // Ajouter le mois
439
+ // Add the month
392
440
  await input.setValue('01/02')
393
441
  await wrapper.vm.$nextTick()
394
442
  expect(input.element.value).toBe('01/02/____')
395
443
 
396
- // Compléter la date
444
+ // Complete the date
397
445
  await input.setValue('01/02/2025')
398
446
  await wrapper.vm.$nextTick()
399
447
  expect(input.element.value).toBe('01/02/2025')
@@ -423,16 +471,16 @@ describe('DateTextInput.vue', () => {
423
471
  await input.trigger('focus')
424
472
  await input.trigger('blur')
425
473
  await customWrapper.vm.$nextTick()
426
- await customWrapper.vm.$nextTick() // Double nextTick pour fiabilité
474
+ await customWrapper.vm.$nextTick() // Double nextTick for reliability
427
475
 
428
- // Force validation manuelle
476
+ // Force manual validation
429
477
  await customWrapper.vm.validateOnSubmit()
430
478
  await customWrapper.vm.$nextTick()
431
479
 
432
480
  const textField = customWrapper.findComponent(SyTextField)
433
481
  const successMessages = textField.props('successMessages') || []
434
482
 
435
- // Vérification assouplie
483
+ // Flexible verification
436
484
  expect(successMessages.length).toBeGreaterThan(0)
437
485
  expect(successMessages[0]).toContain('valide')
438
486
  })
@@ -121,7 +121,7 @@ const meta: Meta<typeof DialogBox> = {
121
121
  height: '32px',
122
122
  class: 'mt-n2 mr-n2 ml-4',
123
123
  },
124
- actionsCtn: {
124
+ cardActions: {
125
125
  class: 'd-flex flex-wrap mt-6',
126
126
  },
127
127
  cancelBtn: {
@@ -139,8 +139,11 @@ const meta: Meta<typeof DialogBox> = {
139
139
  {
140
140
  card?: Record<string, any>,
141
141
  cardTitle?: Record<string, any>,
142
+ spacer?: Record<string, any>,
142
143
  closeBtn?: Record<string, any>,
143
- actionsCtn?: Record<string, any>,
144
+ icon?: Record<string, any>,
145
+ actionsBtn?: Record<string, any>,
146
+ actionsSpacer?: Record<string, any>,
144
147
  cancelBtn?: Record<string, any>,
145
148
  confirmBtn?: Record<string, any>,
146
149
  }
@@ -123,7 +123,7 @@
123
123
 
124
124
  <div
125
125
  v-if="!props.hideActions"
126
- v-bind="options.actionsCtn"
126
+ v-bind="options.cardActions"
127
127
  class="sy-dialog-box-actions-ctn"
128
128
  >
129
129
  <VSpacer v-bind="options.actionsSpacer" />
@@ -12,7 +12,7 @@ export const config = {
12
12
  height: '32px',
13
13
  class: 'mt-n2 mr-n2 ml-4',
14
14
  },
15
- actionsCtn: {
15
+ cardActions: {
16
16
  class: 'd-flex flex-wrap mt-6',
17
17
  },
18
18
  cancelBtn: {
@@ -159,6 +159,10 @@ export const Legende: StoryObj = {
159
159
  </div>
160
160
  </div>
161
161
  </div>
162
+ <div class="mt-4">
163
+ <p>Rapport d’audit manuel : <a href="/audits/DownloadBtn.xlsx" style="color:#0C41BD;">Voir le rapport</a></p>
164
+ <p style="color: grey; font-size: 14px">Correctifs associés (<a href="https://github.com/assurance-maladie-digital/design-system/issues/4007" target="_blank" style="color:#0C41BD;">issue #4007</a>)</p>
165
+ </div>
162
166
  `,
163
167
  }
164
168
  },
@@ -1,7 +1,7 @@
1
1
  import { fn, userEvent, within } from '@storybook/test'
2
2
  import type { Meta, StoryObj } from '@storybook/vue3'
3
3
  import axios from 'axios'
4
- import { VThemeProvider } from 'vuetify/components'
4
+ import { VSheet } from 'vuetify/components'
5
5
  import DownloadBtn from './DownloadBtn.vue'
6
6
  import NotificationBar from '../NotificationBar/NotificationBar.vue'
7
7
  import { useNotificationService } from '@/services/NotificationService'
@@ -22,6 +22,15 @@ const meta = {
22
22
  category: 'slots',
23
23
  },
24
24
  },
25
+ dark: {
26
+ control: 'boolean',
27
+ description: 'Applique le thème sombre.',
28
+ table: {
29
+ type: {
30
+ summary: 'boolean',
31
+ },
32
+ },
33
+ },
25
34
  filePromise: {
26
35
  control: false,
27
36
  description: 'Une fonction retournant une valeur de retour de Axios `Promise<AxiosResponse>`. <br>Exemple: `() => axios.get("https://run.mocky.io/v3/884c25f5-6dc2-4c01-b8d9-26c54042f94f")`',
@@ -231,16 +240,16 @@ export const Dark: Story = {
231
240
  {
232
241
  name: 'Template',
233
242
  code: `<template>
234
- <VThemeProvider theme="dark" with-background class="pa-4">
243
+ <VSheet color="primary" class="pa-4">
235
244
  <DownloadBtn
245
+ dark
236
246
  :file-promise="download"
237
- background-color="black"
238
247
  @error="console.log('error')"
239
248
  @success="console.log('success')"
240
249
  >
241
250
  Télécharger
242
251
  </DownloadBtn>
243
- </VThemeProvider>
252
+ </VSheet>
244
253
  </template>
245
254
  `,
246
255
  },
@@ -259,20 +268,20 @@ export const Dark: Story = {
259
268
  ],
260
269
  },
261
270
  render: args => ({
262
- components: { VThemeProvider, DownloadBtn },
271
+ components: { VSheet, DownloadBtn },
263
272
  setup() {
264
273
  return { args }
265
274
  },
266
275
  template: `
267
- <VThemeProvider theme="dark" with-background class="pa-4">
276
+ <VSheet color="primary" class="pa-4">
268
277
  <DownloadBtn v-bind="args">{{ args.default }}</DownloadBtn>
269
- </VThemeProvider>
278
+ </VSheet>
270
279
  `,
271
280
  }),
272
281
  args: {
282
+ dark: true,
273
283
  filePromise: () => axios.get('https://run.mocky.io/v3/884c25f5-6dc2-4c01-b8d9-26c54042f94f'),
274
284
  default: 'Télécharger',
275
- backgroundColor: 'black',
276
285
  onError: fn(),
277
286
  onSuccess: fn(),
278
287
  },
@@ -19,6 +19,7 @@
19
19
  filePromise: () => Promise<AxiosResponse<Blob>>
20
20
  fallbackFilename?: string
21
21
  backgroundColor?: string
22
+ dark?: boolean
22
23
  locales?: typeof defaultLocales
23
24
  }
24
25
 
@@ -29,13 +30,19 @@
29
30
  const props = withDefaults(defineProps<Props & CustomizableOptions>(), {
30
31
  fallbackFilename: undefined,
31
32
  backgroundColor: 'white',
33
+ dark: false,
32
34
  locales: () => defaultLocales,
33
35
  })
36
+
34
37
  const emits = defineEmits(['error', 'success'])
35
38
  const attrs = useAttrs()
36
39
  const state = ref<State>('idle')
37
40
  const options = useCustomizableOptions(config, props)
38
41
  const btnOptions = computed(() => deepmerge(options.value.btn, attrs))
42
+ const isDark = computed(() => props.dark ?? false)
43
+ const buttonColor = computed(() => isDark.value ? 'white' : options.value.btn.color)
44
+ const buttonBgColor = computed(() => isDark.value ? 'transparent' : props.backgroundColor)
45
+ const iconColor = computed(() => isDark.value ? 'white' : options.value.icon.color)
39
46
 
40
47
  /**
41
48
  * Get filename and content type from headers
@@ -88,12 +95,16 @@
88
95
  v-bind="btnOptions"
89
96
  :loading="state === 'loading'"
90
97
  class="sy-download-btn"
91
- :class="[`bg-${backgroundColor}`, btnOptions.variant === 'outlined' ? 'outlined-style' : '']"
98
+ :color="buttonColor"
99
+ :class="`bg-${buttonBgColor}`"
92
100
  data-testid="download-btn"
93
101
  @click="download"
94
102
  >
95
103
  <slot name="icon">
96
- <VIcon v-bind="options.icon">
104
+ <VIcon
105
+ v-bind="options.icon"
106
+ :color="iconColor"
107
+ >
97
108
  {{ mdiDownload }}
98
109
  </VIcon>
99
110
  </slot>
@@ -141,8 +152,4 @@
141
152
  .sy-download-btn:focus-visible::after {
142
153
  opacity: 1;
143
154
  }
144
-
145
- .outlined-style {
146
- border: 1px solid currentcolor;
147
- }
148
155
  </style>
@@ -4,7 +4,6 @@ exports[`DownloadBtn > renders correctly 1`] = `
4
4
  <button
5
5
  class="
6
6
  bg-white
7
- outlined-style
8
7
  sy-download-btn
9
8
  text-primary
10
9
  text-wrap
@@ -47,7 +46,6 @@ exports[`DownloadBtn > with slots 1`] = `
47
46
  <button
48
47
  class="
49
48
  bg-white
50
- outlined-style
51
49
  sy-download-btn
52
50
  text-primary
53
51
  text-wrap
@@ -187,6 +187,10 @@ export const Legende: StoryObj = {
187
187
  </div>
188
188
  </div>
189
189
  </div>
190
+ <div class="mt-4">
191
+ <p>Rapport d’audit manuel : <a href="/audits/FranceConnectBtn.xlsx" style="color:#0C41BD;">Voir le rapport</a></p>
192
+ <p style="color: grey; font-size: 14px">Correctifs associés (<a href="https://github.com/assurance-maladie-digital/design-system/issues/4005" target="_blank" style="color:#0C41BD;">issue #4005</a>)</p>
193
+ </div>
190
194
  `,
191
195
  }
192
196
  },
@@ -10,6 +10,7 @@
10
10
 
11
11
  <style lang="scss" scoped>
12
12
  @use '@/assets/tokens.scss' as *;
13
+ @use '../menu';
13
14
 
14
15
  .header-menu-item {
15
16
  color: rgb(var(--v-theme-primary));
@@ -37,6 +38,8 @@
37
38
  &::first-letter {
38
39
  text-transform: uppercase;
39
40
  }
41
+
42
+ @include menu.item-focused;
40
43
  }
41
44
  }
42
45
 
@@ -63,6 +63,7 @@
63
63
  <style lang="scss" scoped>
64
64
  @use '@/assets/tokens.scss' as *;
65
65
  @use '../../consts' as *;
66
+ @use '../menu';
66
67
 
67
68
  .sub-menu-btn {
68
69
  display: flex;
@@ -83,6 +84,8 @@
83
84
  }
84
85
  }
85
86
 
87
+ @include menu.item-focused;
88
+
86
89
  &::first-letter {
87
90
  text-transform: uppercase;
88
91
  }
@@ -0,0 +1,19 @@
1
+ @use 'sass:color';
2
+ @use '@/assets/tokens';
3
+
4
+ $red: color.channel(tokens.$primary-base, 'red');
5
+ $green: color.channel(tokens.$primary-base, 'green');
6
+ $blue: color.channel(tokens.$primary-base, 'blue');
7
+ $primary: $red, $green, $blue;
8
+
9
+ @mixin item-focused() {
10
+ border-top: 2px solid transparent;
11
+ border-bottom: 2px solid transparent;
12
+ transition: border-color 0.1s ease;
13
+
14
+ &:focus-visible {
15
+ outline: 0;
16
+ border-top: 2px solid rgb(var(--v-theme-primary, $primary));
17
+ border-bottom: 2px solid rgb(var(--v-theme-primary, $primary));
18
+ }
19
+ }
@@ -48,12 +48,22 @@
48
48
  font-weight: 700;
49
49
  background-color: rgb(var(--v-theme-primary));
50
50
  color: tokens.$neutral-white;
51
- border-bottom: solid 1px tokens.$blue-lighten-80;
52
- transition: color 0.15s 0.1s, background-color 0.15s 0.1s, border-bottom 0.15s 0.1s;
51
+ border: 2px solid transparent;
52
+ border-bottom:
53
+ solid 2px linear-gradient(
54
+ 180deg,
55
+ transparent 0%,
56
+ transparent 50%,
57
+ tokens.$blue-lighten-80 50%,
58
+ tokens.$blue-lighten-80 100%
59
+ );
60
+ transition: color 0.15s 0.1s, background-color 0.15s 0.1s, border 0.15s 0.1s;
53
61
 
54
62
  &:focus-visible {
55
63
  background-color: tokens.$neutral-white;
56
64
  color: rgb(var(--v-theme-primary));
65
+ outline: none;
66
+ border: 2px solid rgb(var(--v-theme-primary));
57
67
  }
58
68
  }
59
69
 
@@ -159,6 +159,10 @@ export const Legende: StoryObj = {
159
159
  </v-btn>
160
160
  Problèmes relevés par Tanaguru
161
161
  </div>
162
+ </div>
163
+ <div class="mt-4">
164
+ <p>Rapport d’audit manuel : <a href="/audits/LangBtn.xlsx" style="color:#0C41BD;">Voir le rapport</a></p>
165
+ <p style="color: grey; font-size: 14px">Correctifs associés (<a href="https://github.com/assurance-maladie-digital/design-system/issues/4009" target="_blank" style="color:#0C41BD;">issue #4009</a>)</p>
162
166
  </div>
163
167
  </div>
164
168
  `,
@@ -13,13 +13,11 @@ const meta: Meta<typeof LangBtn> = {
13
13
  modelValue: { control: 'text' },
14
14
  hideDownArrow: { control: 'boolean' },
15
15
  ariaLabel: { control: 'text' },
16
- // @ts-expect-error Type '"array"' is not assignable to type 'Control | undefined'.
17
- availableLanguages: { control: { type: 'array' } },
16
+ availableLanguages: { control: { type: 'object' } },
18
17
  vuetifyOptions: {
19
18
  control: { type: 'object' },
20
19
  default: () => ({
21
20
  menu: {
22
- offsetY: true,
23
21
  },
24
22
  btn: {
25
23
  color: 'primary',
@@ -73,7 +71,6 @@ export const Default: Story = {
73
71
  availableLanguages: ['fr', 'en', 'es'],
74
72
  vuetifyOptions: {
75
73
  menu: {
76
- offsetY: true,
77
74
  },
78
75
  btn: {
79
76
  color: 'primary',