@cnamts/synapse 0.0.7-alpha → 0.0.9-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 (198) hide show
  1. package/dist/design-system-v3.d.ts +785 -372
  2. package/dist/design-system-v3.js +4993 -3357
  3. package/dist/design-system-v3.umd.cjs +1 -10
  4. package/dist/style.css +1 -1
  5. package/package.json +10 -2
  6. package/src/assets/settings.scss +2 -2
  7. package/src/assets/tokens.scss +107 -112
  8. package/src/components/BackBtn/BackBtn.vue +4 -4
  9. package/src/components/BackToTopBtn/BackToTopBtn.vue +1 -0
  10. package/src/components/CollapsibleList/CollapsibleList.mdx +1 -1
  11. package/src/components/CollapsibleList/CollapsibleList.vue +43 -44
  12. package/src/components/ContextualMenu/Accessibilite.mdx +14 -0
  13. package/src/components/ContextualMenu/Accessibilite.stories.ts +191 -0
  14. package/src/components/ContextualMenu/AccessibiliteItems.ts +89 -0
  15. package/src/components/ContextualMenu/ContextualMenu.mdx +118 -0
  16. package/src/components/ContextualMenu/ContextualMenu.stories.ts +430 -0
  17. package/src/components/ContextualMenu/ContextualMenu.vue +101 -0
  18. package/src/components/ContextualMenu/constants/ExpertiseLevelEnum.ts +4 -0
  19. package/src/components/ContextualMenu/tests/ContextualMenu.spec.ts +115 -0
  20. package/src/components/ContextualMenu/tests/__snapshots__/ContextualMenu.spec.ts.snap +10 -0
  21. package/src/components/ContextualMenu/types.ts +5 -0
  22. package/src/components/CookieBanner/CookieBanner.stories.ts +1 -2
  23. package/src/components/CookieBanner/CookieBanner.vue +13 -10
  24. package/src/components/CookieBanner/tests/__snapshots__/CookieBanner.spec.ts.snap +17 -15
  25. package/src/components/CookiesSelection/CookiesInformation/CookiesInformation.vue +6 -1
  26. package/src/components/CookiesSelection/CookiesInformation/locales.ts +1 -0
  27. package/src/components/CookiesSelection/CookiesTable/CookiesTable.vue +1 -0
  28. package/src/components/CookiesSelection/tests/__snapshots__/CookiesSelection.spec.ts.snap +17 -15
  29. package/src/components/CopyBtn/CopyBtn.vue +7 -7
  30. package/src/components/Customs/SyBtnSelect/SyBtnSelect.vue +26 -26
  31. package/src/components/Customs/SyInputSelect/SyInputSelect.vue +24 -24
  32. package/src/components/Customs/SySelect/SySelect.stories.ts +7 -7
  33. package/src/components/Customs/SySelect/SySelect.vue +36 -30
  34. package/src/components/Customs/SySelect/tests/SySelect.spec.ts +2 -2
  35. package/src/components/Customs/SyTextField/SyTextField.stories.ts +187 -2
  36. package/src/components/Customs/SyTextField/SyTextField.vue +185 -16
  37. package/src/components/Customs/SyTextField/tests/SyTextField.spec.ts +2 -4
  38. package/src/components/Customs/SyTextField/tests/__snapshots__/SyTextField.spec.ts.snap +18 -16
  39. package/src/components/Customs/SyTextField/types.d.ts +2 -2
  40. package/src/components/DataList/DataList.stories.ts +3 -2
  41. package/src/components/DataList/DataList.vue +1 -1
  42. package/src/components/DataListGroup/DataListGroup.stories.ts +3 -2
  43. package/src/components/DataListItem/DataListItem.vue +12 -12
  44. package/src/components/DatePicker/DatePicker.mdx +191 -0
  45. package/src/components/DatePicker/DatePicker.stories.ts +787 -0
  46. package/src/components/DatePicker/DatePicker.vue +560 -0
  47. package/src/components/DatePicker/DateTextInput.vue +409 -0
  48. package/src/components/DatePicker/tests/DatePicker.spec.ts +266 -0
  49. package/src/components/DialogBox/DialogBox.mdx +28 -2
  50. package/src/components/DialogBox/DialogBox.stories.ts +2 -2
  51. package/src/components/DialogBox/DialogBox.vue +3 -2
  52. package/src/components/DownloadBtn/DownloadBtn.vue +2 -1
  53. package/src/components/ExternalLinks/Accessibilite.mdx +14 -0
  54. package/src/components/ExternalLinks/Accessibilite.stories.ts +191 -0
  55. package/src/components/ExternalLinks/AccessibiliteItems.ts +197 -0
  56. package/src/components/ExternalLinks/ExternalLinks.mdx +86 -0
  57. package/src/components/ExternalLinks/ExternalLinks.stories.ts +553 -0
  58. package/src/components/ExternalLinks/ExternalLinks.vue +200 -0
  59. package/src/components/ExternalLinks/config.ts +34 -0
  60. package/src/components/ExternalLinks/constants/ExpertiseLevelEnum.ts +4 -0
  61. package/src/components/ExternalLinks/locales.ts +4 -0
  62. package/src/components/ExternalLinks/tests/ExternalLinks.spec.ts +154 -0
  63. package/src/components/ExternalLinks/tests/__snapshots__/ExternalLinks.spec.ts.snap +159 -0
  64. package/src/components/FileUpload/FileUpload.mdx +165 -0
  65. package/src/components/FileUpload/FileUpload.stories.ts +429 -0
  66. package/src/components/FileUpload/FileUpload.vue +195 -0
  67. package/src/components/FileUpload/FileUploadContent.vue +109 -0
  68. package/src/components/FileUpload/locales.ts +10 -0
  69. package/src/components/FileUpload/tests/FileUpload.spec.ts +332 -0
  70. package/src/components/FileUpload/tests/__snapshots__/FileUpload.spec.ts.snap +7 -0
  71. package/src/components/FileUpload/useFileDrop.ts +23 -0
  72. package/src/components/FileUpload/validateFiles.ts +39 -0
  73. package/src/components/FooterBar/FooterBar.vue +105 -80
  74. package/src/components/FranceConnectBtn/FranceConnectBtn.vue +14 -13
  75. package/src/components/HeaderBar/HeaderBar.vue +3 -3
  76. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderBurgerMenu.vue +11 -7
  77. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuItem/HeaderMenuItem.vue +5 -5
  78. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuSection/HeaderMenuSection.vue +2 -2
  79. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderSubMenu/HeaderSubMenu.vue +10 -8
  80. package/src/components/HeaderBar/HeaderLogo/HeaderLogo.vue +2 -2
  81. package/src/components/HeaderBar/HeaderLogo/logos/Logo-mobile.vue +2 -1
  82. package/src/components/HeaderBar/HeaderLogo/logos/Logo.vue +2 -1
  83. package/src/components/HeaderBar/HeaderMenuBtn/HeaderMenuBtn.vue +10 -10
  84. package/src/components/HeaderBar/consts.scss +1 -1
  85. package/src/components/HeaderLoading/HeaderLoading.vue +12 -11
  86. package/src/components/HeaderNavigationBar/HeaderNavigationBar.vue +2 -1
  87. package/src/components/HeaderNavigationBar/HorizontalNavbar/HorizontalNavbar.vue +9 -9
  88. package/src/components/HeaderToolbar/HeaderToolbar.vue +215 -202
  89. package/src/components/LangBtn/LangBtn.vue +8 -6
  90. package/src/components/LogoBrandSection/LogoBrandSection.stories.ts +2 -2
  91. package/src/components/NirField/NirField.stories.ts +8 -8
  92. package/src/components/NirField/NirField.vue +46 -48
  93. package/src/components/NotFoundPage/NotFoundPage.stories.ts +33 -2
  94. package/src/components/NotFoundPage/NotFoundPage.vue +17 -0
  95. package/src/components/NotificationBar/NotificationBar.mdx +5 -5
  96. package/src/components/NotificationBar/NotificationBar.stories.ts +410 -314
  97. package/src/components/NotificationBar/NotificationBar.vue +43 -41
  98. package/src/components/PageContainer/PageContainer.vue +4 -4
  99. package/src/components/PasswordField/Accessibilite.mdx +14 -0
  100. package/src/components/PasswordField/Accessibilite.stories.ts +191 -0
  101. package/src/components/PasswordField/AccessibiliteItems.ts +184 -0
  102. package/src/components/PasswordField/PasswordField.mdx +70 -0
  103. package/src/components/PasswordField/PasswordField.stories.ts +213 -0
  104. package/src/components/PasswordField/PasswordField.vue +189 -0
  105. package/src/components/PasswordField/config.ts +11 -0
  106. package/src/components/PasswordField/constants/ExpertiseLevelEnum.ts +4 -0
  107. package/src/components/PasswordField/locales.ts +4 -0
  108. package/src/components/PasswordField/tests/PasswordField.spec.ts +96 -0
  109. package/src/components/PhoneField/PhoneField.mdx +0 -2
  110. package/src/components/PhoneField/PhoneField.stories.ts +10 -50
  111. package/src/components/PhoneField/PhoneField.vue +77 -93
  112. package/src/components/PhoneField/tests/PhoneField.spec.ts +0 -15
  113. package/src/components/RangeField/RangeField.mdx +54 -0
  114. package/src/components/RangeField/RangeField.stories.ts +189 -0
  115. package/src/components/RangeField/RangeField.vue +157 -0
  116. package/src/components/RangeField/RangeSlider/RangeSlider.vue +387 -0
  117. package/src/components/RangeField/RangeSlider/Tooltip/Tooltip.vue +64 -0
  118. package/src/components/RangeField/RangeSlider/tests/__snapshots__/rangeSlider.spec.ts.snap +27 -0
  119. package/src/components/RangeField/RangeSlider/tests/rangeSlider.spec.ts +100 -0
  120. package/src/components/RangeField/RangeSlider/tests/useDoubleSlider.spec.ts +246 -0
  121. package/src/components/RangeField/RangeSlider/tests/useMouseSlide.spec.ts +204 -0
  122. package/src/components/RangeField/RangeSlider/tests/useThumb.spec.ts +22 -0
  123. package/src/components/RangeField/RangeSlider/tests/useThumbKeyboard.spec.ts +233 -0
  124. package/src/components/RangeField/RangeSlider/tests/useTooltipsNudge.spec.ts +150 -0
  125. package/src/components/RangeField/RangeSlider/tests/useTrack.spec.ts +314 -0
  126. package/src/components/RangeField/RangeSlider/tests/vAnimateClick.spec.ts +32 -0
  127. package/src/components/RangeField/RangeSlider/types.ts +15 -0
  128. package/src/components/RangeField/RangeSlider/useMouseSlide.ts +109 -0
  129. package/src/components/RangeField/RangeSlider/useRangeSlider.ts +126 -0
  130. package/src/components/RangeField/RangeSlider/useThumb.ts +18 -0
  131. package/src/components/RangeField/RangeSlider/useThumbKeyboard.ts +84 -0
  132. package/src/components/RangeField/RangeSlider/useTooltipsNudge.ts +92 -0
  133. package/src/components/RangeField/RangeSlider/useTrack.ts +116 -0
  134. package/src/components/RangeField/RangeSlider/vAnimateClick.ts +19 -0
  135. package/src/components/RangeField/config.ts +7 -0
  136. package/src/components/RangeField/locales.ts +4 -0
  137. package/src/components/RangeField/tests/RangeField.spec.ts +224 -0
  138. package/src/components/RangeField/tests/__snapshots__/RangeField.spec.ts.snap +379 -0
  139. package/src/components/RatingPicker/EmotionPicker/EmotionPicker.vue +205 -0
  140. package/src/components/RatingPicker/EmotionPicker/locales.ts +3 -0
  141. package/src/components/RatingPicker/EmotionPicker/tests/EmotionPicker.spec.ts +104 -0
  142. package/src/components/RatingPicker/EmotionPicker/tests/__snapshots__/EmotionPicker.spec.ts.snap +66 -0
  143. package/src/components/RatingPicker/NumberPicker/NumberPicker.vue +159 -0
  144. package/src/components/RatingPicker/NumberPicker/locales.ts +4 -0
  145. package/src/components/RatingPicker/NumberPicker/tests/NumberPicker.spec.ts +73 -0
  146. package/src/components/RatingPicker/NumberPicker/tests/__snapshots__/NumberPicker.spec.ts.snap +105 -0
  147. package/src/components/RatingPicker/Rating.ts +45 -0
  148. package/src/components/RatingPicker/RatingPicker.mdx +56 -0
  149. package/src/components/RatingPicker/RatingPicker.stories.ts +515 -0
  150. package/src/components/RatingPicker/RatingPicker.vue +122 -0
  151. package/src/components/RatingPicker/StarsPicker/StarsPicker.vue +116 -0
  152. package/src/components/RatingPicker/StarsPicker/tests/StarsPicker.spec.ts +95 -0
  153. package/src/components/RatingPicker/StarsPicker/tests/__snapshots__/StarsPicker.spec.ts.snap +36 -0
  154. package/src/components/RatingPicker/locales.ts +3 -0
  155. package/src/components/RatingPicker/tests/Rating.spec.ts +104 -0
  156. package/src/components/RatingPicker/tests/RatingPicker.spec.ts +187 -0
  157. package/src/components/RatingPicker/tests/__snapshots__/RatingPicker.spec.ts.snap +108 -0
  158. package/src/components/SearchListField/SearchListField.mdx +74 -0
  159. package/src/components/SearchListField/SearchListField.stories.ts +126 -0
  160. package/src/components/SearchListField/SearchListField.vue +194 -0
  161. package/src/components/SearchListField/locales.ts +5 -0
  162. package/src/components/SearchListField/tests/SearchListField.spec.ts +323 -0
  163. package/src/components/SearchListField/types.d.ts +4 -0
  164. package/src/components/SelectBtnField/SelectBtnField.mdx +50 -0
  165. package/src/components/SelectBtnField/SelectBtnField.stories.ts +763 -0
  166. package/src/components/SelectBtnField/SelectBtnField.vue +283 -0
  167. package/src/components/SelectBtnField/config.ts +11 -0
  168. package/src/components/SelectBtnField/tests/SelectBtnField.spec.ts +327 -0
  169. package/src/components/SelectBtnField/tests/__snapshots__/SelectBtnField.spec.ts.snap +125 -0
  170. package/src/components/SelectBtnField/types.d.ts +11 -0
  171. package/src/components/SkipLink/SkipLink.vue +10 -10
  172. package/src/components/SocialMediaLinks/SocialMediaLinks.vue +28 -26
  173. package/src/components/SubHeader/SubHeader.vue +32 -31
  174. package/src/components/SyAlert/SyAlert.vue +12 -12
  175. package/src/components/UserMenuBtn/UserMenuBtn.vue +1 -1
  176. package/src/components/UserMenuBtn/config.ts +1 -1
  177. package/src/components/index.ts +17 -7
  178. package/src/composables/rules/useFieldValidation.ts +172 -44
  179. package/src/designTokens/index.ts +6 -4
  180. package/src/designTokens/{bootstrapColors.md → paColors.md} +1 -1
  181. package/src/designTokens/tokens/cnam/cnamLightTheme.ts +2 -0
  182. package/src/designTokens/tokens/pa/paColors.ts +171 -0
  183. package/src/designTokens/tokens/pa/paContextual.ts +58 -0
  184. package/src/designTokens/tokens/pa/paDarkTheme.ts +5 -0
  185. package/src/designTokens/tokens/pa/paLightTheme.ts +123 -0
  186. package/src/designTokens/tokens/pa/paSemantic.ts +87 -0
  187. package/src/stories/Fondamentaux/CustomisationEtThemes.mdx +52 -2
  188. package/src/stories/GuideDuDev/CreerUneIssue.mdx +64 -0
  189. package/src/stories/GuideDuDev/{CommentUtiliserLesRules.mdx → UtiliserLesRules.mdx} +2 -2
  190. package/src/stories/GuideDuDev/components.stories.ts +9 -7
  191. package/src/stories/Guidelines/Vuetify/Vuetify.stories.ts +163 -88
  192. package/src/stories/Guidelines/Vuetify/VuetifyItems.ts +250 -23
  193. package/src/temp/TestDTComponent.vue +5 -6
  194. package/src/utils/calcHumanFileSize/index.ts +12 -0
  195. package/src/utils/calcHumanFileSize/tests/calcHumanFileSize.spec.ts +21 -0
  196. package/src/designTokens/tokens/bootstrap/bootstrapColors.ts +0 -158
  197. package/src/designTokens/tokens/bootstrap/bootstrapLightTheme.ts +0 -22
  198. package/src/stories/GuideDuDev/CommentContribuer.mdx +0 -22
@@ -0,0 +1,165 @@
1
+ import {Controls, Canvas, Meta, Source} from '@storybook/blocks';
2
+
3
+ import * as FileUploadStories from './FileUpload.stories.ts';
4
+
5
+ <Meta of={FileUploadStories} />
6
+
7
+ # FileUpload
8
+
9
+ Le composant `FileUpload` est un champ d'upload de fichier par glisser-déposer ou par sélection de fichier.
10
+
11
+ <Canvas of={FileUploadStories.Default} />
12
+
13
+ # API
14
+
15
+ <Controls of={FileUploadStories.Default} />
16
+
17
+ ## Gérer l'envoi des fichiers
18
+
19
+ Vous pouvez envoyer les fichiers sur un serveur en un objet FormData.
20
+
21
+ <Source dark language="typescript" code={`
22
+ <script setup lang="ts">
23
+ import { FileUpload } from '@cnamts/synapse'
24
+ import { ref } from 'vue'
25
+
26
+ const files = ref<File[]>([])
27
+
28
+ function upload() {
29
+ const formData = new FormData()
30
+ files.value.forEach((file: File) => {
31
+ formData.append(file.name, file)
32
+ })
33
+
34
+ fetch('http://localhost:3000/upload', {
35
+ method: 'POST',
36
+ body: formData,
37
+ })
38
+ }
39
+
40
+ </script>
41
+
42
+ <template>
43
+ <main class="pa-12">
44
+ {{ files?.map(file => file.name).join(', ') }}
45
+
46
+ <br>
47
+ <FileUpload
48
+ v-model="files"
49
+ :multiple="true"
50
+ @error="console.log"
51
+ />
52
+
53
+ <VBtn
54
+ @click="upload"
55
+ >
56
+ submit
57
+ </VBtn>
58
+ </main>
59
+ </template>
60
+ `} />
61
+
62
+ Même exemple avec axios :
63
+
64
+ <Source dark language="typescript" code={`
65
+ <script setup lang="ts">
66
+ import { FileUpload } from '@cnamts/synapse'
67
+ import { ref } from 'vue'
68
+ import axios from 'axios'
69
+
70
+ const files = ref<File[]>([])
71
+
72
+ function upload() {
73
+ const formData = new FormData()
74
+ files.value.forEach((file: File) => {
75
+ formData.append(file.name, file)
76
+ })
77
+
78
+ axios.post('http://localhost:3000/upload', formData, {
79
+ headers: {
80
+ 'Content-Type': 'multipart/form-data',
81
+ },
82
+ })
83
+ }
84
+
85
+ </script>
86
+
87
+ <template>
88
+ <main class="pa-12">
89
+ {{ files?.map(file => file.name).join(', ') }}
90
+
91
+ <br>
92
+ <FileUpload
93
+ v-model="files"
94
+ :multiple="true"
95
+ @error="console.log"
96
+ />
97
+
98
+ <VBtn
99
+ @click="upload"
100
+ >
101
+ submit
102
+ </VBtn>
103
+
104
+ </main>
105
+ </template>
106
+ `} />
107
+
108
+ ## Coté backend
109
+
110
+ Voici un exemple de code pour gérer l'upload de fichier en Node.js avec Express,
111
+ ce code est destiné à des fins de tests uniquement.
112
+
113
+ <Source dark language="javascript" code={`
114
+ import express from "express";
115
+ import fileUpload from "express-fileupload";
116
+ import cors from "cors";
117
+ import { join } from "path";
118
+ import { existsSync, mkdirSync } from "fs";
119
+
120
+ const app = express();
121
+
122
+ app.use(fileUpload());
123
+ app.use(cors({ origin: true, credentials: true }));
124
+
125
+ const uploadDir = join(import.meta.dirname, "uploads");
126
+
127
+ if (!existsSync(uploadDir)) {
128
+ mkdirSync(uploadDir);
129
+ }
130
+
131
+ app.post("/upload", async function (req, res) {
132
+ if (!req.files || Object.keys(req.files).length === 0) {
133
+ return res.status(400).send("No files were uploaded.");
134
+ }
135
+
136
+ let errors = [];
137
+
138
+ const uploadPromises = Object.keys(req.files).map(async (fileKey) => {
139
+ const file = req.files[fileKey];
140
+ const filePath = join(uploadDir, file.name);
141
+
142
+ try {
143
+ await file.mv(filePath);
144
+ } catch (err) {
145
+ errors.push(err);
146
+ }
147
+ });
148
+
149
+ try {
150
+ await Promise.all(uploadPromises);
151
+
152
+ if (errors.length > 0) {
153
+ return res.status(500).send(errors.join(", "));
154
+ }
155
+ res.send("Files uploaded!");
156
+ } catch (err) {
157
+ res.status(500).send("An error occurred during file upload.");
158
+ }
159
+ });
160
+
161
+ app.listen(3000, function () {
162
+ console.log("App is listening on port 3000");
163
+ });
164
+
165
+ `} />
@@ -0,0 +1,429 @@
1
+ import { fn } from '@storybook/test'
2
+ import FileUpload from './FileUpload.vue'
3
+ import type { Meta, StoryObj } from '@storybook/vue3'
4
+
5
+ import NotificationBar from '@/components/NotificationBar/NotificationBar.vue'
6
+ import { useNotificationService } from '@/services/NotificationService'
7
+ import { mdiCloudUpload } from '@mdi/js'
8
+ import { VIcon } from 'vuetify/components'
9
+
10
+ const meta = {
11
+ title: 'Composants/Formulaires/FileUpload',
12
+ component: FileUpload,
13
+ argTypes: {
14
+ 'modelValue': {
15
+ description: 'La/Les fichiers de l\'utilisateur',
16
+ control: 'file',
17
+ table: {
18
+ type: {
19
+ summary: 'File[]',
20
+ },
21
+ disable: false,
22
+ category: 'props',
23
+ },
24
+ },
25
+ 'disabled': {
26
+ description: 'Désactive le champ',
27
+ control: 'boolean',
28
+ table: {
29
+ type: {
30
+ summary: 'boolean',
31
+ },
32
+ },
33
+ defaultValue: false,
34
+ },
35
+ 'multiple': {
36
+ description: 'Autorise l\'envoi de plusieurs fichiers',
37
+ control: 'boolean',
38
+ table: {
39
+ type: {
40
+ summary: 'boolean',
41
+ },
42
+ },
43
+ defaultValue: false,
44
+ },
45
+ 'fileSizeMax': {
46
+ description: 'Taille maximale des fichiers en octets',
47
+ control: 'number',
48
+ table: {
49
+ type: {
50
+ summary: 'number',
51
+ },
52
+ },
53
+ defaultValue: 10485760,
54
+ },
55
+ 'fileSizeUnits': {
56
+ description: 'Unité de taille des fichiers',
57
+ control: 'object',
58
+ table: {
59
+ type: {
60
+ summary: 'string[]',
61
+ },
62
+ defaultValue: {
63
+ summary: '[\'o\', \'Ko\', \'Mo\', \'Go\', \'To\']',
64
+ },
65
+ },
66
+ },
67
+ 'allowedExtensions': {
68
+ description: 'Extensions de fichiers autorisées, un tableau vide autorise toutes les extensions',
69
+ control: 'object',
70
+ table: {
71
+ type: {
72
+ summary: 'string[]',
73
+ },
74
+
75
+ defaultValue: {
76
+ summary: '[\'pdf\', \'jpg\', \'jpeg\', \'png\']',
77
+ },
78
+ },
79
+ },
80
+ 'maxWidth': {
81
+ description: 'Largeur maximale du composant',
82
+ control: 'text',
83
+ table: {
84
+ type: {
85
+ summary: 'number | string',
86
+ },
87
+ category: 'props',
88
+ },
89
+ },
90
+ 'minWidth': {
91
+ description: 'Largeur minimale du composant',
92
+ control: 'text',
93
+ table: {
94
+ type: {
95
+ summary: 'number | string',
96
+ },
97
+ category: 'props',
98
+ },
99
+ },
100
+ 'width': {
101
+ description: 'Largeur du composant',
102
+ control: 'text',
103
+ table: {
104
+ type: {
105
+ summary: 'number | string',
106
+ },
107
+ category: 'props',
108
+ },
109
+ },
110
+ 'onUpdate:modelValue': {
111
+ description: 'Événement émis lorsqu\'un fichier est ajouté ou supprimé',
112
+ table: {
113
+ type: {
114
+ summary: 'File[]',
115
+ },
116
+ category: 'events',
117
+ },
118
+ },
119
+ 'onError': {
120
+ description: 'Événement émis lorsqu\'une erreur de validation survient',
121
+ table: {
122
+ type: {
123
+ summary: 'string[]',
124
+ },
125
+ category: 'events',
126
+ },
127
+ },
128
+ 'default': {
129
+ description: 'Intérieur de champ',
130
+ control: 'text',
131
+ table: {
132
+ category: 'slots',
133
+ type: {
134
+ summary: undefined,
135
+ },
136
+ },
137
+ },
138
+ 'icon': {
139
+ description: 'Icône supérieur',
140
+ control: 'text',
141
+ table: {
142
+ category: 'slots',
143
+ type: {
144
+ summary: undefined,
145
+ },
146
+ },
147
+ },
148
+ 'action-text': {
149
+ description: 'Texte de l\'appel à l\'action',
150
+ control: 'text',
151
+ table: {
152
+ category: 'slots',
153
+ type: {
154
+ summary: undefined,
155
+ },
156
+ },
157
+ },
158
+ 'or': {
159
+ description: 'Texte de séparation entre le cta et le bouton',
160
+ control: 'text',
161
+ table: {
162
+ category: 'slots',
163
+ type: {
164
+ summary: undefined,
165
+ },
166
+ },
167
+ },
168
+ 'button-text': {
169
+ description: 'Texte du bouton',
170
+ control: 'text',
171
+ table: {
172
+ category: 'slots',
173
+ type: {
174
+ summary: undefined,
175
+ },
176
+ },
177
+ },
178
+ 'locales': {
179
+ description: 'Traductions',
180
+ control: false,
181
+ table: {
182
+ category: 'props',
183
+ type: {
184
+ summary: undefined,
185
+ },
186
+ defaultValue: {
187
+ summary: `Locales`,
188
+ detail: `{
189
+ or: 'Ou',
190
+ chooseFile: (multiple: boolean) => multiple ? 'Choisir des fichiers' : 'Choisir un fichier',
191
+ infoText: (max: string, ext: string[]): string =>
192
+ \`Taille max. : \${max}. \${ext.length === 1 ? 'Format accepté' : 'Formats acceptés'} : \${ext.join(', ')}\`,
193
+ fileSizeUnits: ['o', 'Ko', 'Mo', 'Go', 'To'],
194
+ dropFilesHere: (multiple: boolean): string => (!multiple ? 'Déposer votre fichier ici' : 'Déposer vos fichiers ici'),
195
+ errorSize: (fileName: string, max: string): string => \`Le fichier \${fileName} est trop volumineux. Taille max. : \${max}\`,
196
+ errorExtension: (fileName: string, ext: string[]): string => \`Le fichier \${fileName} a une extension invalide. Extensions acceptées : \${ext.join(', ')}\`,
197
+ }`,
198
+ },
199
+ },
200
+ },
201
+ },
202
+ parameters: {
203
+ controls: {
204
+ exclude: ['error', 'update:modelValue', 'slotName'],
205
+ },
206
+ docs: {
207
+ controls: {
208
+ sort: 'requiredFirst',
209
+ },
210
+ },
211
+ },
212
+ } satisfies Meta<typeof FileUpload>
213
+
214
+ export default meta
215
+
216
+ type Story = StoryObj<typeof meta>
217
+
218
+ export const Default: Story = {
219
+ args: {
220
+ 'modelValue': [],
221
+ 'multiple': false,
222
+ 'onUpdate:modelValue': fn(),
223
+ 'onError': fn(),
224
+ },
225
+ render: args => ({
226
+ components: { FileUpload },
227
+ setup() {
228
+ return { args }
229
+ },
230
+ template: `<div>
231
+ <FileUpload
232
+ v-model="args.modelValue"
233
+ v-bind="args"
234
+ />
235
+ <ul class="ma-2">
236
+ <li v-for="file in args.modelValue" :key="file.name">{{ file.name }}</li>
237
+ </ul>
238
+ </div>`,
239
+ }),
240
+ parameters: {
241
+ sourceCode: [
242
+ {
243
+ name: 'Template',
244
+ code: `
245
+ <template>
246
+ <FileUpload
247
+ v-model="modelValue"
248
+ />
249
+ <ul class="ma-2">
250
+ <li v-for="file in modelValue" :key="file.name">{{ file.name }}</li>
251
+ </ul>
252
+ </template>
253
+ `,
254
+ },
255
+ {
256
+ name: 'Script',
257
+ code: `
258
+ <script setup lang="ts">
259
+ import { FileUpload } from '@cnamts/synapse'
260
+ import { ref } from 'vue'
261
+
262
+ const modelValue = ref([])
263
+
264
+ </script>
265
+ `,
266
+ },
267
+ ],
268
+ },
269
+ }
270
+
271
+ export const MultipleFiles: Story = {
272
+ args: {
273
+ 'modelValue': [],
274
+ 'multiple': true,
275
+ 'onUpdate:modelValue': fn(),
276
+ 'onError': fn(),
277
+ },
278
+ render: args => ({
279
+ components: { FileUpload, NotificationBar },
280
+ setup() {
281
+ const { addNotification } = useNotificationService()
282
+ const sendError = (e: string[]) => {
283
+ addNotification({
284
+ id: Date.now().toString(),
285
+ message: e.join(', '),
286
+ type: 'error',
287
+ timeout: -1,
288
+ })
289
+ }
290
+ return { args, sendError }
291
+ },
292
+ template: `<div>
293
+ <NotificationBar />
294
+ <FileUpload
295
+ v-model="args.modelValue"
296
+ v-bind="args"
297
+ />
298
+ <ul class="ma-2">
299
+ <li v-for="file in args.modelValue" :key="file.name">{{ file.name }}</li>
300
+ </ul>
301
+ </div>`,
302
+ }),
303
+ parameters: {
304
+ sourceCode: [
305
+ {
306
+ name: 'Template',
307
+ code: `
308
+ <template>
309
+ <div>
310
+ <FileUpload
311
+ v-model="files"
312
+ :multiple="true"
313
+ />
314
+ <ul class="ma-2">
315
+ <li v-for="file in files" :key="file.name">{{ file.name }}</li>
316
+ </ul>
317
+ <NotificationBar />
318
+ </div>
319
+ </template>
320
+ `,
321
+ },
322
+ {
323
+ name: 'Script',
324
+ code: `
325
+ <script setup lang="ts">
326
+ import { FileUpload, NotificationBar, useNotificationService } from '@cnamts/synapse'
327
+ import { ref } from 'vue'
328
+
329
+ const files = ref([])
330
+
331
+ const { addNotification } = useNotificationService()
332
+ const sendError = (e: string[]) => {
333
+ addNotification({
334
+ id: Date.now().toString(),
335
+ message: e.join(', '),
336
+ type: 'error',
337
+ timeout: -1,
338
+ })
339
+ }
340
+
341
+ </script>
342
+ `,
343
+ },
344
+ ],
345
+ },
346
+ }
347
+
348
+ export const Customization: Story = {
349
+ args: {
350
+ 'modelValue': [],
351
+ 'onUpdate:modelValue': fn(),
352
+ 'onError': fn(),
353
+ 'width': '50%',
354
+ 'minWidth': '300px',
355
+ 'maxWidth': '600px',
356
+ },
357
+ render: args => ({
358
+ components: { FileUpload, VIcon },
359
+ setup() {
360
+ return { args, uploadIcon: mdiCloudUpload }
361
+ },
362
+ template: `<div>
363
+ <FileUpload
364
+ v-model="args.modelValue"
365
+ v-bind="args"
366
+ class="bg-accent elevation-3 px-4 py-3 border-0 rounded-0"
367
+ >
368
+ <span class="d-flex align-center white--text">
369
+ <VIcon
370
+ size="25"
371
+ color="white"
372
+ class="mr-4"
373
+ >
374
+ {{ uploadIcon }}
375
+ </VIcon>
376
+
377
+ Sélectionner un fichier
378
+ </span>
379
+ </FileUpload>
380
+ <ul class="ma-2">
381
+ <li v-for="file in args.modelValue" :key="file.name">{{ file.name }}</li>
382
+ </ul>
383
+ </div>`,
384
+ }),
385
+ parameters: {
386
+ sourceCode: [
387
+ {
388
+ name: 'Template',
389
+ code: `
390
+ <template>
391
+ <div>
392
+ <FileUpload
393
+ v-model="files"
394
+ width="50%"
395
+ min-width="300px"
396
+ max-width="600px"
397
+ class="bg-accent elevation-3 px-4 py-3 border-0 rounded-0"
398
+ >
399
+ <span>
400
+ <v-icon size="25" color="white" class="mr-4">
401
+ {{ uploadIcon }}
402
+ </v-icon>
403
+ Sélectionner un fichier
404
+ </span>
405
+ </FileUpload>
406
+ <ul class="ma-2">
407
+ <li v-for="file in files" :key="file.name">{{ file.name }}</li>
408
+ </ul>
409
+ </div>
410
+ </template>
411
+ `,
412
+ },
413
+ {
414
+ name: 'Script',
415
+ code: `
416
+ <script setup lang="ts">
417
+ import { FileUpload, VIcon } from '@cnamts/synapse'
418
+ import { mdiCloudUpload } from '@mdi/js'
419
+ import { ref } from 'vue'
420
+
421
+ const files = ref([])
422
+
423
+ const uploadIcon = mdiCloudUpload
424
+ </script>
425
+ `,
426
+ },
427
+ ],
428
+ },
429
+ }