@cnamts/synapse 0.0.0-alpha.0

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 (130) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +2 -0
  3. package/dist/design-system-v3.d.ts +246 -0
  4. package/dist/design-system-v3.js +5425 -0
  5. package/dist/design-system-v3.umd.cjs +2 -0
  6. package/dist/style.css +1 -0
  7. package/package.json +104 -0
  8. package/src/assets/tokens.scss +500 -0
  9. package/src/components/Alert/Alert.mdx +36 -0
  10. package/src/components/Alert/Alert.stories.ts +115 -0
  11. package/src/components/Alert/Alert.vue +248 -0
  12. package/src/components/Alert/locales.ts +3 -0
  13. package/src/components/Alert/tests/Alert.spec.ts +105 -0
  14. package/src/components/Alert/tests/__snapshots__/Alert.spec.ts.snap +15 -0
  15. package/src/components/BackBtn/BackBtn.mdx +26 -0
  16. package/src/components/BackBtn/BackBtn.stories.ts +138 -0
  17. package/src/components/BackBtn/BackBtn.vue +60 -0
  18. package/src/components/BackBtn/locales.ts +3 -0
  19. package/src/components/BackBtn/tests/BackBtn.spec.ts +103 -0
  20. package/src/components/BackBtn/tests/__snapshots__/BackBtn.spec.ts.snap +9 -0
  21. package/src/components/BackToTopBtn/BackToTopBtn.mdx +52 -0
  22. package/src/components/BackToTopBtn/BackToTopBtn.stories.ts +188 -0
  23. package/src/components/BackToTopBtn/BackToTopBtn.vue +137 -0
  24. package/src/components/BackToTopBtn/config.ts +12 -0
  25. package/src/components/BackToTopBtn/locales.ts +3 -0
  26. package/src/components/BackToTopBtn/tests/BackToTopBtn.spec.ts +173 -0
  27. package/src/components/BackToTopBtn/tests/__snapshots__/BackToTopBtn.spec.ts.snap +17 -0
  28. package/src/components/Beta/beta.mdx +5 -0
  29. package/src/components/CopyBtn/CopyBtn.mdx +38 -0
  30. package/src/components/CopyBtn/CopyBtn.stories.ts +209 -0
  31. package/src/components/CopyBtn/CopyBtn.vue +103 -0
  32. package/src/components/CopyBtn/config.ts +17 -0
  33. package/src/components/CopyBtn/locales.ts +3 -0
  34. package/src/components/CopyBtn/tests/CopyBtn.spec.ts +99 -0
  35. package/src/components/CopyBtn/tests/__snapshots__/CopyBtn.spec.ts.snap +7 -0
  36. package/src/components/Deprecated/deprecated.mdx +5 -0
  37. package/src/components/DownloadBtn/DownloadBtn.mdx +94 -0
  38. package/src/components/DownloadBtn/DownloadBtn.stories.ts +211 -0
  39. package/src/components/DownloadBtn/DownloadBtn.vue +113 -0
  40. package/src/components/DownloadBtn/config.ts +13 -0
  41. package/src/components/DownloadBtn/tests/DownloadBtn.spec.ts +82 -0
  42. package/src/components/DownloadBtn/tests/__snapshots__/DownloadBtn.spec.ts.snap +17 -0
  43. package/src/components/DownloadBtn/tests/data/filePromise.ts +53 -0
  44. package/src/components/DownloadBtn/tests/data/test.json +0 -0
  45. package/src/components/FranceConnectBtn/FranceConnectBtn.mdx +34 -0
  46. package/src/components/FranceConnectBtn/FranceConnectBtn.stories.ts +92 -0
  47. package/src/components/FranceConnectBtn/FranceConnectBtn.vue +154 -0
  48. package/src/components/FranceConnectBtn/locales.ts +6 -0
  49. package/src/components/FranceConnectBtn/tests/FranceConnectBtn.spec.ts +62 -0
  50. package/src/components/FranceConnectBtn/tests/__snapshots__/FranceConnectBtn.spec.ts.snap +36 -0
  51. package/src/components/LangBtn/LangBtn.mdx +37 -0
  52. package/src/components/LangBtn/LangBtn.stories.ts +147 -0
  53. package/src/components/LangBtn/LangBtn.vue +167 -0
  54. package/src/components/LangBtn/config.ts +17 -0
  55. package/src/components/LangBtn/locales.ts +3 -0
  56. package/src/components/LangBtn/tests/Config.spec.ts +24 -0
  57. package/src/components/LangBtn/tests/LangBtn.spec.ts +283 -0
  58. package/src/components/LangBtn/tests/__snapshots__/LangBtn.spec.ts.snap +11 -0
  59. package/src/components/LangBtn/types.d.ts +7 -0
  60. package/src/components/NotificationBar/NotificationBar.mdx +94 -0
  61. package/src/components/NotificationBar/NotificationBar.stories.ts +366 -0
  62. package/src/components/NotificationBar/NotificationBar.vue +296 -0
  63. package/src/components/NotificationBar/options.ts +15 -0
  64. package/src/components/NotificationBar/tests/NotificationBar.spec.ts +332 -0
  65. package/src/components/NotificationBar/tests/__snapshots__/NotificationBar.spec.ts.snap +7 -0
  66. package/src/components/NotificationBar/types.ts +7 -0
  67. package/src/components/PageContainer/PageContainer.mdx +29 -0
  68. package/src/components/PageContainer/PageContainer.stories.ts +115 -0
  69. package/src/components/PageContainer/PageContainer.vue +68 -0
  70. package/src/components/PageContainer/tests/PageContainer.spec.ts +56 -0
  71. package/src/components/PageContainer/tests/__snapshots__/PageContainer.spec.ts.snap +7 -0
  72. package/src/components/SkipLink/SkipLink.mdx +55 -0
  73. package/src/components/SkipLink/SkipLink.stories.ts +70 -0
  74. package/src/components/SkipLink/SkipLink.vue +79 -0
  75. package/src/components/SkipLink/locales.ts +3 -0
  76. package/src/components/SkipLink/tests/__snapshots__/skipLink.spec.ts.snap +3 -0
  77. package/src/components/SkipLink/tests/skipLink.spec.ts +46 -0
  78. package/src/components/index.ts +8 -0
  79. package/src/composables/useCustomizableOptions.ts +23 -0
  80. package/src/designTokens/bootstrapColors.md +66 -0
  81. package/src/designTokens/cnamColors.md +193 -0
  82. package/src/designTokens/index.ts +15 -0
  83. package/src/designTokens/tokens/bootstrap/bootstrapColors.ts +158 -0
  84. package/src/designTokens/tokens/bootstrap/bootstrapLightTheme.ts +22 -0
  85. package/src/designTokens/tokens/cnam/cnamColors.ts +171 -0
  86. package/src/designTokens/tokens/cnam/cnamContextual.ts +58 -0
  87. package/src/designTokens/tokens/cnam/cnamLightTheme.ts +90 -0
  88. package/src/designTokens/tokens/cnam/cnamSemantic.ts +87 -0
  89. package/src/designTokens/tokens/json/contextual-tokens.json +156 -0
  90. package/src/designTokens/tokens/json/primitives.json +209 -0
  91. package/src/designTokens/tokens/json/semantic.json +120 -0
  92. package/src/designTokens/utils/convertGaps.ts +11 -0
  93. package/src/designTokens/utils/convertSemanticsToken.ts +32 -0
  94. package/src/designTokens/utils/createFlattenTheme.ts +19 -0
  95. package/src/designTokens/utils/index.ts +4 -0
  96. package/src/main.ts +2 -0
  97. package/src/services/NotificationService.ts +27 -0
  98. package/src/stories/Fondamentaux/Accessibilite/Accessibilite.mdx +52 -0
  99. package/src/stories/Fondamentaux/Accessibilite/Accessibilite.stories.ts +36 -0
  100. package/src/stories/Fondamentaux/Accessibilite/AccessibiliteItems.ts +706 -0
  101. package/src/stories/Fondamentaux/Accessibilite/constants/ExpertiseLevelEnum.ts +5 -0
  102. package/src/stories/Fondamentaux/Accessibilite/constants/RGAALevelEnum.ts +4 -0
  103. package/src/stories/Fondamentaux/EcoConception/EcoConception.mdx +24 -0
  104. package/src/stories/Fondamentaux/EcoConception/Econception.stories.ts +30 -0
  105. package/src/stories/Fondamentaux/EcoConception/ecoDesignItems.ts +55 -0
  106. package/src/stories/GuideDuDev/CommentContribuer.mdx +22 -0
  107. package/src/stories/GuideDuDev/components.stories.ts +23 -0
  108. package/src/stories/GuideDuDev/moduleDeNotification.mdx +182 -0
  109. package/src/stories/GuideDuDev/vuetifyOptions.mdx +72 -0
  110. package/src/stories/Guidelines/Colors.mdx +220 -0
  111. package/src/stories/Guidelines/CustomisationEtThemes.mdx +3 -0
  112. package/src/stories/Guidelines/Introduction.mdx +35 -0
  113. package/src/stories/Guidelines/Typo.mdx +53 -0
  114. package/src/stories/Home/Accueil.mdx +7 -0
  115. package/src/stories/Home/PolitiqueDeConfidentialite.mdx +4 -0
  116. package/src/stories/Home/synapse.webp +0 -0
  117. package/src/temp/TestA11y.vue +14 -0
  118. package/src/temp/TestComponent.vue +37 -0
  119. package/src/temp/TestDTComponent.vue +93 -0
  120. package/src/temp/customizableOptions.vue +18 -0
  121. package/src/temp/gridsTests.vue +54 -0
  122. package/src/temp/options.json +5 -0
  123. package/src/types/vuetifyTypes.ts +3 -0
  124. package/src/utils/convertToUnit/index.ts +16 -0
  125. package/src/utils/convertToUnit/test/convertToUnit.spec.ts +32 -0
  126. package/src/utils/functions/copyToClipboard/index.ts +38 -0
  127. package/src/utils/functions/copyToClipboard/tests/copyToClipboard.spec.ts +104 -0
  128. package/src/utils/functions/downloadFile/index.ts +37 -0
  129. package/src/utils/functions/downloadFile/tests/downloadFile.spec.ts +69 -0
  130. package/src/utils/functions/downloadFile/types.ts +1 -0
@@ -0,0 +1,211 @@
1
+ import { fn, userEvent, within } from '@storybook/test'
2
+ import type { Meta, StoryObj } from '@storybook/vue3'
3
+ import axios from 'axios'
4
+ import { VThemeProvider } from 'vuetify/components'
5
+ import DownloadBtn from './DownloadBtn.vue'
6
+ import NotificationBar from '../NotificationBar/NotificationBar.vue'
7
+ import { useNotificationService } from '@/services/NotificationService'
8
+
9
+ const meta = {
10
+ title: 'Components/DownloadBtn',
11
+ component: DownloadBtn,
12
+ parameters: {
13
+ layout: 'fullscreen',
14
+ controls: {
15
+ exclude: ['getFileInfo', 'download', 'state', 'onError', 'onSuccess'],
16
+ },
17
+ },
18
+ argTypes: {
19
+ default: {
20
+ control: { type: 'text' },
21
+ table: {
22
+ category: 'slots',
23
+ },
24
+ },
25
+ filePromise: {
26
+ control: false,
27
+ description: 'Une fonction retournant un valeur de retour de Axios `Promise<AxiosResponse>`. <br>Exemple: `() => axios.get("https://run.mocky.io/v3/63e571d5-1134-4f51-82ac-fa7cc8045124")`',
28
+ table: {
29
+ category: 'props',
30
+ },
31
+ },
32
+ fallbackFilename: {
33
+ control: { type: 'text' },
34
+ description: 'Le nom du fichier téléchargé si celui ci n\'est pas disponible dans la réponse.',
35
+ table: {
36
+ type: {
37
+ summary: 'string',
38
+ },
39
+ },
40
+ },
41
+ vuetifyOptions: {
42
+ control: { type: 'object' },
43
+ description: 'Options pour personnaliser les composants Vuetify utilisés en interne.',
44
+ table: {
45
+ type: {
46
+ summary: 'object',
47
+ detail: `{
48
+ btn: Record<string, any>,
49
+ icon: Record<string, any>,
50
+ }`,
51
+ },
52
+ defaultValue: {
53
+ summary: 'config',
54
+ detail: ` {
55
+ btn: {
56
+ variant: 'outlined',
57
+ color: 'primary',
58
+ class: 'text-wrap',
59
+ minHeight: '36px',
60
+ height: 'auto',
61
+ },
62
+ icon: {
63
+ color: 'primary',
64
+ class: 'mr-3',
65
+ },
66
+ }`,
67
+ },
68
+ category: 'props',
69
+ },
70
+ },
71
+ },
72
+ args: {
73
+ vuetifyOptions: {
74
+ btn: {
75
+ variant: 'outlined',
76
+ color: 'primary',
77
+ class: 'text-wrap',
78
+ minHeight: '36px',
79
+ height: 'auto',
80
+ },
81
+ icon: {
82
+ color: 'primary',
83
+ class: 'mr-3',
84
+ },
85
+ },
86
+ },
87
+ decorators: [() => ({ template: '<div class="pa-4"><story/></div>' })],
88
+ } satisfies Meta<typeof DownloadBtn>
89
+
90
+ export default meta
91
+
92
+ type Story = StoryObj<typeof meta>
93
+
94
+ export const Default: Story = {
95
+ args: {
96
+ filePromise: () => axios.get('https://run.mocky.io/v3/63e571d5-1134-4f51-82ac-fa7cc8045124'),
97
+ default: 'Télécharger',
98
+ onError: fn(),
99
+ onSuccess: fn(),
100
+ },
101
+ }
102
+
103
+ export const Error: Story = {
104
+ name: 'Error',
105
+ args: {
106
+ filePromise: () => axios.get('https://'),
107
+ default: 'Télécharger',
108
+ onError: fn(),
109
+ onSuccess: fn(),
110
+ },
111
+ }
112
+
113
+ export const Loading: Story = {
114
+ name: 'Loading',
115
+ args: {
116
+ filePromise: () => new Promise(() => { setTimeout(() => {}, 100000) }),
117
+ default: 'Télécharger',
118
+ onError: fn(),
119
+ onSuccess: fn(),
120
+ },
121
+ play: async ({ canvasElement }) => {
122
+ const canvas = within(canvasElement)
123
+ const btn = canvas.getByRole('button')
124
+ userEvent.click(btn)
125
+ },
126
+ }
127
+
128
+ export const Dark: Story = {
129
+ name: 'Dark theme',
130
+ render: args => ({
131
+ components: { VThemeProvider, DownloadBtn },
132
+ setup() {
133
+ return { args }
134
+ },
135
+ template: `
136
+ <VThemeProvider theme="dark" with-background class="pa-4">
137
+ <DownloadBtn v-bind="args">{{ args.default }}</DownloadBtn>
138
+ </VThemeProvider>
139
+ `,
140
+ }),
141
+
142
+ args: {
143
+ filePromise: () => axios.get('https://run.mocky.io/v3/63e571d5-1134-4f51-82ac-fa7cc8045124'),
144
+ default: 'Télécharger',
145
+ onError: fn(),
146
+ onSuccess: fn(),
147
+ },
148
+ }
149
+
150
+ export const Notify: Story = {
151
+ args: {
152
+ filePromise: () => axios.get('https://run.mocky.io/v3/63e571d5-1134-4f51-82ac-fa7cc8045124'),
153
+ default: 'Télécharger',
154
+ onError: fn(),
155
+ onSuccess: fn(),
156
+ },
157
+ name: 'Notification',
158
+ render: args => ({
159
+ components: { NotificationBar, DownloadBtn },
160
+ setup() {
161
+ const { addNotification } = useNotificationService()
162
+
163
+ const notify = (message: string, type: 'error' | 'success') => {
164
+ const notification = {
165
+ id: Date.now().toString(),
166
+ message,
167
+ type,
168
+ timeout: -1,
169
+ }
170
+ addNotification(notification)
171
+ }
172
+ return { args, notify }
173
+ },
174
+ template: `
175
+ <div>
176
+ <NotificationBar />
177
+ <div class="d-flex">
178
+ <DownloadBtn
179
+ :file-promise="args.filePromise"
180
+ :btn="{ color: 'primary'}"
181
+ @error="notify('Une error est survenue', 'error')"
182
+ @success="notify('Votre attestation a été téléchargée', 'success')"
183
+ >
184
+ {{ args.default }}
185
+ </DownloadBtn>
186
+ </div>
187
+ </div>
188
+ `,
189
+ }),
190
+ }
191
+
192
+ export const Customization: Story = {
193
+ name: 'Customisation',
194
+ args: {
195
+ filePromise: () => axios.get('https://run.mocky.io/v3/63e571d5-1134-4f51-82ac-fa7cc8045124'),
196
+ default: 'Télécharger',
197
+ onError: fn(),
198
+ onSuccess: fn(),
199
+ vuetifyOptions: {
200
+ btn: {
201
+ variant: 'plain',
202
+ ripple: true,
203
+ color: 'secondary',
204
+ },
205
+ icon: {
206
+ class: 'ml-2 mr-2',
207
+ color: 'secondary',
208
+ },
209
+ },
210
+ },
211
+ }
@@ -0,0 +1,113 @@
1
+ <script setup lang="ts">
2
+ import useCustomizableOptions, { type CustomizableOptions } from '@/composables/useCustomizableOptions'
3
+ import { downloadFile } from '@/utils/functions/downloadFile'
4
+ import { mdiDownload } from '@mdi/js'
5
+ import type { AxiosResponse } from 'axios'
6
+ import deepmerge from 'deepmerge'
7
+ import { computed, ref, useAttrs } from 'vue'
8
+ import { config } from './config'
9
+
10
+ type State = 'idle' | 'loading' | 'success' | 'error'
11
+
12
+ export interface FileInfo {
13
+ name: string
14
+ type: string
15
+ }
16
+
17
+ export interface Props {
18
+ filePromise: () => Promise<AxiosResponse<Blob>>
19
+ fallbackFilename?: string
20
+ }
21
+
22
+ defineOptions({
23
+ inheritAttrs: false,
24
+ })
25
+
26
+ const props = withDefaults(defineProps<Props & CustomizableOptions>(), {
27
+ fallbackFilename: undefined,
28
+ })
29
+ const emits = defineEmits(['error', 'success'])
30
+ const attrs = useAttrs()
31
+ const state = ref<State>('idle')
32
+ const options = useCustomizableOptions(config, props)
33
+ const btnOptions = computed(() => deepmerge(options.value.btn, attrs))
34
+
35
+ /**
36
+ * Get filename and content type from headers
37
+ */
38
+ function getFileInfo(header: Record<string, string>): FileInfo {
39
+ const contentType = header['content-type']
40
+ const contentDispositionHeader = header['content-disposition']
41
+ let fileName: string | undefined
42
+
43
+ fileName = contentDispositionHeader
44
+ ?.split(';')
45
+ ?.find((str: string) => str.includes('filename='))
46
+ ?.split('=')?.[1]
47
+
48
+ if (!fileName) {
49
+ fileName = props.fallbackFilename || 'file'
50
+ }
51
+
52
+ return {
53
+ name: fileName,
54
+ type: contentType,
55
+ }
56
+ }
57
+
58
+ async function download(): Promise<void> {
59
+ state.value = 'loading'
60
+
61
+ try {
62
+ const { data, headers } = await props.filePromise()
63
+ const { name, type } = getFileInfo(headers as Record<string, string>)
64
+ downloadFile(data, name, type)
65
+ }
66
+ catch (error) {
67
+ state.value = 'error'
68
+ emits('error', error)
69
+ return
70
+ }
71
+ state.value = 'success'
72
+ emits('success')
73
+ }
74
+
75
+ defineExpose({
76
+ getFileInfo, download, state,
77
+ })
78
+
79
+ </script>
80
+
81
+ <template>
82
+ <VBtn
83
+ v-bind="btnOptions"
84
+ :loading="state === 'loading'"
85
+ :class="btnOptions.variant === 'outlined' ? 'outlined-style' : ''"
86
+ class="vd-download-btn"
87
+ data-testid="download-btn"
88
+ @click="download"
89
+ >
90
+ <slot name="icon">
91
+ <VIcon v-bind="options.icon">
92
+ {{ mdiDownload }}
93
+ </VIcon>
94
+ </slot>
95
+
96
+ <slot />
97
+ </VBtn>
98
+ </template>
99
+
100
+ <style lang="scss" scoped>
101
+ .vd-download-btn :deep() {
102
+ .v-btn__content {
103
+ flex-wrap: wrap;
104
+ }
105
+ .v-icon {
106
+ flex: none;
107
+ }
108
+ }
109
+
110
+ .outlined-style {
111
+ border: 1px solid currentColor;
112
+ }
113
+ </style>
@@ -0,0 +1,13 @@
1
+ export const config = {
2
+ btn: {
3
+ variant: 'outlined',
4
+ color: 'primary',
5
+ class: 'text-wrap',
6
+ minHeight: '36px',
7
+ height: 'auto',
8
+ },
9
+ icon: {
10
+ color: 'primary',
11
+ class: 'mr-3',
12
+ },
13
+ }
@@ -0,0 +1,82 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
2
+ import { DOMWrapper, mount } from '@vue/test-utils'
3
+
4
+ import {
5
+ filePromise,
6
+ filePromiseError,
7
+ } from './data/filePromise'
8
+ import DownloadBtn from '../DownloadBtn.vue'
9
+ import { vuetify } from '@tests/unit/setup'
10
+ import { downloadFile } from '@/utils/functions/downloadFile'
11
+
12
+ describe('DownloadBtn', () => {
13
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
14
+ let wrapper: any
15
+ let element: DOMWrapper<Element>
16
+ beforeEach(() => {
17
+ wrapper = mount(DownloadBtn, {
18
+ props: {
19
+ filePromise,
20
+ },
21
+ global: {
22
+ plugins: [vuetify],
23
+ },
24
+ })
25
+
26
+ vi.spyOn(wrapper.vm, 'getFileInfo')
27
+ vi.spyOn(wrapper.vm, 'download')
28
+
29
+ element = wrapper.find('[data-testid="download-btn"]')
30
+ global.URL.createObjectURL = vi.fn()
31
+ global.URL.revokeObjectURL = vi.fn()
32
+ })
33
+ afterEach(() => {
34
+ wrapper.unmount()
35
+ vi.restoreAllMocks()
36
+ })
37
+
38
+ it('renders correctly', async () => {
39
+ expect(DownloadBtn).toBeTruthy()
40
+
41
+ expect(element.exists()).toBe(true)
42
+
43
+ expect(wrapper.html()).toMatchSnapshot()
44
+ })
45
+
46
+ it('works correctly', async () => {
47
+ vi.mock('@/utils/functions/downloadFile', () => ({ downloadFile: vi.fn() }))
48
+
49
+ await element.trigger('click')
50
+
51
+ expect(downloadFile).toHaveBeenCalledTimes(1)
52
+ })
53
+
54
+ it('emit error event', async () => {
55
+ await wrapper.setProps({
56
+ filePromise: filePromiseError,
57
+ })
58
+
59
+ expect(wrapper.emitted('error')).toBeFalsy()
60
+ expect(wrapper.vm.state).toBe('idle')
61
+ await element.trigger('click')
62
+ expect(wrapper.vm.state).toBe('error')
63
+ expect(wrapper.emitted('error')).toBeTruthy()
64
+ })
65
+
66
+ it('with slots', async () => {
67
+ const slot = 'Download'
68
+ wrapper = mount(DownloadBtn, {
69
+ props: {
70
+ filePromise,
71
+ },
72
+ slots: {
73
+ default: slot,
74
+ },
75
+ global: {
76
+ plugins: [vuetify],
77
+ },
78
+ })
79
+
80
+ expect(wrapper.html()).toMatchSnapshot()
81
+ })
82
+ })
@@ -0,0 +1,17 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`DownloadBtn > renders correctly 1`] = `
4
+ "<button data-v-e1153e16="" type="button" class="v-btn v-theme--light text-primary v-btn--density-default v-btn--size-default v-btn--variant-outlined text-wrap outlined-style vd-download-btn" style="height: auto; min-height: 36px;" data-testid="download-btn"><span class="v-btn__overlay"></span><span class="v-btn__underlay"></span>
5
+ <!----><span class="v-btn__content" data-no-activator=""><i data-v-e1153e16="" class="M5,20H19V18H5M19,9H15V3H9V9H5L12,16L19,9Z mdi v-icon notranslate v-theme--light v-icon--size-default text-primary mr-3" aria-hidden="true"></i></span>
6
+ <!---->
7
+ <!---->
8
+ </button>"
9
+ `;
10
+
11
+ exports[`DownloadBtn > with slots 1`] = `
12
+ "<button data-v-e1153e16="" type="button" class="v-btn v-theme--light text-primary v-btn--density-default v-btn--size-default v-btn--variant-outlined text-wrap outlined-style vd-download-btn" style="height: auto; min-height: 36px;" data-testid="download-btn"><span class="v-btn__overlay"></span><span class="v-btn__underlay"></span>
13
+ <!----><span class="v-btn__content" data-no-activator=""><i data-v-e1153e16="" class="M5,20H19V18H5M19,9H15V3H9V9H5L12,16L19,9Z mdi v-icon notranslate v-theme--light v-icon--size-default text-primary mr-3" aria-hidden="true"></i>Download</span>
14
+ <!---->
15
+ <!---->
16
+ </button>"
17
+ `;
@@ -0,0 +1,53 @@
1
+ import { type AxiosResponse } from 'axios'
2
+
3
+ /** Returns a promise that returns a file */
4
+ export function filePromise(): Promise<AxiosResponse<Blob>> {
5
+ return new Promise((resolve) => {
6
+ resolve({
7
+ data: new File(['test'], 'attestation.txt', { type: 'text/plain' }),
8
+ status: 200,
9
+ statusText: 'OK',
10
+ headers: {
11
+ 'content-type': 'text/plain',
12
+ 'content-disposition': 'attachment; filename="attestation.txt"',
13
+ },
14
+ config: {
15
+ headers: {
16
+ Accept: 'application/json, text/plain, */*',
17
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- mock Axios headers
18
+ } as any,
19
+ },
20
+ })
21
+ })
22
+ }
23
+
24
+ export function filePromiseError(): Promise<AxiosResponse<Blob>> {
25
+ return new Promise((_, reject) => {
26
+ reject({
27
+ response: {
28
+ data: 'error',
29
+ status: 500,
30
+ statusText: 'Internal Server Error',
31
+ headers: {},
32
+ config: {},
33
+ },
34
+ })
35
+ })
36
+ }
37
+
38
+ export function filePromiseNoHeaders(): Promise<AxiosResponse<Blob>> {
39
+ return new Promise((resolve) => {
40
+ resolve({
41
+ data: new File(['test'], 'attestation.txt', { type: 'text/plain' }),
42
+ status: 200,
43
+ statusText: 'OK',
44
+ headers: {},
45
+ config: {
46
+ headers: {
47
+ Accept: 'application/json, text/plain, */*',
48
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- mock Axios headers
49
+ } as any,
50
+ },
51
+ })
52
+ })
53
+ }
@@ -0,0 +1,34 @@
1
+ import {Controls, Canvas, Meta, Source} from '@storybook/blocks';
2
+
3
+ import * as FranceConnectBtnStories from './FranceConnectBtn.stories';
4
+
5
+ <Meta of={FranceConnectBtnStories} />
6
+
7
+ # FranceConnectBtn
8
+
9
+ Le composant `FranceConnectBtn` est utilisé pour afficher un bouton permettant à l’utilisateur de se connecter à FranceConnect.
10
+
11
+ <Canvas of={FranceConnectBtnStories.Default} />
12
+
13
+ ## API
14
+
15
+ <Controls of={FranceConnectBtnStories.Default} />
16
+
17
+ # Exemple d'utilisation
18
+
19
+ <Source dark code={`
20
+ <script setup lang="ts">
21
+ import FranceConnectBtn from '@/components/FranceConnectBtn/FranceConnectBtn.vue'
22
+ </script>
23
+
24
+ <template>
25
+ <FranceConnectBtn href="/" />
26
+
27
+ <br>
28
+
29
+ <FranceConnectBtn
30
+ href="/"
31
+ is-connect-plus
32
+ />
33
+ </template>
34
+ `} />
@@ -0,0 +1,92 @@
1
+ import type { Meta, StoryObj } from '@storybook/vue3'
2
+ import FranceConnectBtn from './FranceConnectBtn.vue'
3
+
4
+ const meta = {
5
+ title: 'Components/FranceConnectBtn',
6
+ component: FranceConnectBtn,
7
+ parameters: {
8
+ layout: 'fullscreen',
9
+ },
10
+ } satisfies Meta<typeof FranceConnectBtn>
11
+
12
+ export default meta
13
+
14
+ type Story = StoryObj<typeof meta>
15
+
16
+ export const Default: Story = {
17
+ args: {
18
+ href: 'https://app.franceconnect.gouv.fr/',
19
+ isConnectPlus: false,
20
+ dark: false,
21
+ },
22
+ render: (args) => {
23
+ return {
24
+ components: { FranceConnectBtn },
25
+ setup() {
26
+ return { args }
27
+ },
28
+ template: `
29
+ <div class="d-flex flex-wrap align-center pa-4">
30
+ <FranceConnectBtn
31
+ :href="args.href"
32
+ :is-connect-plus="args.isConnectPlus"
33
+ :dark="args.dark"
34
+ />
35
+ </div>
36
+ `,
37
+ }
38
+ },
39
+ }
40
+
41
+ export const FranceConnectPlus: Story = {
42
+ args: {
43
+ href: 'https://app.franceconnect.gouv.fr/',
44
+ isConnectPlus: true,
45
+ dark: false,
46
+ },
47
+ render: (args) => {
48
+ return {
49
+ components: { FranceConnectBtn },
50
+ setup() {
51
+ return { args }
52
+ },
53
+ template: `
54
+ <div class="d-flex flex-wrap align-center pa-4">
55
+ <FranceConnectBtn
56
+ :href="args.href"
57
+ :is-connect-plus="args.isConnectPlus"
58
+ :dark="args.dark"
59
+ />
60
+ </div>
61
+ `,
62
+ }
63
+ },
64
+ }
65
+
66
+ export const DarkTheme: Story = {
67
+ args: {
68
+ href: 'https://app.franceconnect.gouv.fr/',
69
+ isConnectPlus: true,
70
+ dark: true,
71
+ },
72
+ render: (args) => {
73
+ return {
74
+ components: { FranceConnectBtn },
75
+ setup() {
76
+ return { args }
77
+ },
78
+ template: `
79
+ <VThemeProvider
80
+ theme="dark"
81
+ with-background
82
+ class="pa-4"
83
+ >
84
+ <FranceConnectBtn
85
+ :href="args.href"
86
+ :is-connect-plus="args.isConnectPlus"
87
+ :dark="args.dark"
88
+ />
89
+ </VThemeProvider>`,
90
+ }
91
+ },
92
+ }