@pyreweb/fabric 1.2.6

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 (210) hide show
  1. package/README.md +119 -0
  2. package/dist/fabric.cjs.js +18109 -0
  3. package/dist/fabric.css +2180 -0
  4. package/dist/fabric.esm.js +18062 -0
  5. package/dist/fabric.min.js +18112 -0
  6. package/dist/types/components/atoms/FAvatar/FAvatar.test.d.ts +1 -0
  7. package/dist/types/components/atoms/FBadge/FBadge.test.d.ts +1 -0
  8. package/dist/types/components/atoms/FButton/FButton.test.d.ts +1 -0
  9. package/dist/types/components/atoms/FCheckbox/FCheckbox.test.d.ts +1 -0
  10. package/dist/types/components/atoms/FDivider/FDivider.test.d.ts +1 -0
  11. package/dist/types/components/atoms/FIcon/FIcon.test.d.ts +1 -0
  12. package/dist/types/components/atoms/FInput/FInput.test.d.ts +1 -0
  13. package/dist/types/components/atoms/FLoader/FLoader.test.d.ts +1 -0
  14. package/dist/types/components/atoms/FRadio/FRadio.test.d.ts +1 -0
  15. package/dist/types/components/atoms/FTextarea/FTextarea.test.d.ts +1 -0
  16. package/dist/types/components/atoms/FToggle/FToggle.test.d.ts +1 -0
  17. package/dist/types/components/atoms/FTypography/FTypography.test.d.ts +1 -0
  18. package/dist/types/components/atoms/index.d.ts +13 -0
  19. package/dist/types/components/molecules/FAccordionItem/FAccordionItem.test.d.ts +1 -0
  20. package/dist/types/components/molecules/FAlert/FAlert.test.d.ts +1 -0
  21. package/dist/types/components/molecules/FBreadcrumb/FBreadcrumb.test.d.ts +1 -0
  22. package/dist/types/components/molecules/FButtonGroup/FButtonGroup.test.d.ts +1 -0
  23. package/dist/types/components/molecules/FCard/FCard.test.d.ts +1 -0
  24. package/dist/types/components/molecules/FDatePicker/FDatePicker.test.d.ts +1 -0
  25. package/dist/types/components/molecules/FEmptyState/FEmptyState.test.d.ts +1 -0
  26. package/dist/types/components/molecules/FFilePreview/FFilePreview.test.d.ts +1 -0
  27. package/dist/types/components/molecules/FFormField/FFormField.test.d.ts +1 -0
  28. package/dist/types/components/molecules/FListItem/FListItem.test.d.ts +1 -0
  29. package/dist/types/components/molecules/FPagination/FPagination.test.d.ts +1 -0
  30. package/dist/types/components/molecules/FSearchBar/FSearchBar.test.d.ts +1 -0
  31. package/dist/types/components/molecules/FSelect/FSelect.test.d.ts +1 -0
  32. package/dist/types/components/molecules/FStatCard/FStatCard.test.d.ts +1 -0
  33. package/dist/types/components/molecules/FTabs/FTabs.test.d.ts +1 -0
  34. package/dist/types/components/molecules/FToast/FToast.test.d.ts +1 -0
  35. package/dist/types/components/molecules/index.d.ts +18 -0
  36. package/dist/types/components/organisms/FActivityFeed/FActivityFeed.test.d.ts +1 -0
  37. package/dist/types/components/organisms/FDataTable/FDataTable.test.d.ts +1 -0
  38. package/dist/types/components/organisms/FDrawer/FDrawer.test.d.ts +1 -0
  39. package/dist/types/components/organisms/FFileUpload/FFileUpload.test.d.ts +1 -0
  40. package/dist/types/components/organisms/FFilterSidebar/FFilterSidebar.test.d.ts +1 -0
  41. package/dist/types/components/organisms/FForm/FForm.test.d.ts +1 -0
  42. package/dist/types/components/organisms/FModal/FModal.test.d.ts +1 -0
  43. package/dist/types/components/organisms/FNavigationSidebar/FNavigationSidebar.test.d.ts +1 -0
  44. package/dist/types/components/organisms/FOnboardingStepper/FOnboardingStepper.test.d.ts +1 -0
  45. package/dist/types/components/organisms/FOnboardingStepper/FStepperProgress.test.d.ts +1 -0
  46. package/dist/types/components/organisms/FPageHeader/FPageHeader.test.d.ts +1 -0
  47. package/dist/types/components/organisms/FProfileSection/FProfileSection.test.d.ts +1 -0
  48. package/dist/types/components/organisms/FToastProvider/FToastProvider.test.d.ts +1 -0
  49. package/dist/types/components/organisms/FUserMenu/FUserMenu.test.d.ts +1 -0
  50. package/dist/types/components/organisms/index.d.ts +14 -0
  51. package/dist/types/components/utils/FThemeProvider.test.d.ts +1 -0
  52. package/dist/types/components/utils/index.d.ts +2 -0
  53. package/dist/types/components.d.ts +602 -0
  54. package/dist/types/composables/index.d.ts +12 -0
  55. package/dist/types/composables/useDataTableState.d.ts +106 -0
  56. package/dist/types/composables/useDataTableState.test.d.ts +1 -0
  57. package/dist/types/composables/useFormValidation.d.ts +49 -0
  58. package/dist/types/composables/useFormValidation.test.d.ts +1 -0
  59. package/dist/types/composables/useSidebarState.d.ts +65 -0
  60. package/dist/types/composables/useSidebarState.test.d.ts +1 -0
  61. package/dist/types/index.d.ts +19 -0
  62. package/dist/types/types.d.ts +529 -0
  63. package/package.json +100 -0
  64. package/src/components/atoms/FAvatar/FAvatar.stories.js +100 -0
  65. package/src/components/atoms/FAvatar/FAvatar.test.ts +95 -0
  66. package/src/components/atoms/FAvatar/FAvatar.vue +190 -0
  67. package/src/components/atoms/FBadge/FBadge.stories.js +129 -0
  68. package/src/components/atoms/FBadge/FBadge.test.ts +93 -0
  69. package/src/components/atoms/FBadge/FBadge.vue +103 -0
  70. package/src/components/atoms/FButton/FButton.stories.js +122 -0
  71. package/src/components/atoms/FButton/FButton.test.ts +98 -0
  72. package/src/components/atoms/FButton/FButton.vue +147 -0
  73. package/src/components/atoms/FCheckbox/FCheckbox.stories.js +96 -0
  74. package/src/components/atoms/FCheckbox/FCheckbox.test.ts +64 -0
  75. package/src/components/atoms/FCheckbox/FCheckbox.vue +76 -0
  76. package/src/components/atoms/FDivider/FDivider.stories.js +104 -0
  77. package/src/components/atoms/FDivider/FDivider.test.ts +80 -0
  78. package/src/components/atoms/FDivider/FDivider.vue +117 -0
  79. package/src/components/atoms/FIcon/FIcon.stories.js +189 -0
  80. package/src/components/atoms/FIcon/FIcon.test.ts +99 -0
  81. package/src/components/atoms/FIcon/FIcon.vue +192 -0
  82. package/src/components/atoms/FInput/FInput.stories.js +119 -0
  83. package/src/components/atoms/FInput/FInput.test.ts +79 -0
  84. package/src/components/atoms/FInput/FInput.vue +88 -0
  85. package/src/components/atoms/FLoader/FLoader.stories.js +109 -0
  86. package/src/components/atoms/FLoader/FLoader.test.ts +66 -0
  87. package/src/components/atoms/FLoader/FLoader.vue +97 -0
  88. package/src/components/atoms/FRadio/FRadio.stories.js +105 -0
  89. package/src/components/atoms/FRadio/FRadio.test.ts +75 -0
  90. package/src/components/atoms/FRadio/FRadio.vue +119 -0
  91. package/src/components/atoms/FTextarea/FTextarea.stories.js +126 -0
  92. package/src/components/atoms/FTextarea/FTextarea.test.ts +94 -0
  93. package/src/components/atoms/FTextarea/FTextarea.vue +156 -0
  94. package/src/components/atoms/FToggle/FToggle.stories.js +108 -0
  95. package/src/components/atoms/FToggle/FToggle.test.ts +96 -0
  96. package/src/components/atoms/FToggle/FToggle.vue +123 -0
  97. package/src/components/atoms/FTypography/FTypography.stories.js +127 -0
  98. package/src/components/atoms/FTypography/FTypography.test.ts +93 -0
  99. package/src/components/atoms/FTypography/FTypography.vue +78 -0
  100. package/src/components/atoms/index.ts +27 -0
  101. package/src/components/molecules/FAccordionItem/FAccordionItem.stories.js +71 -0
  102. package/src/components/molecules/FAccordionItem/FAccordionItem.test.ts +61 -0
  103. package/src/components/molecules/FAccordionItem/FAccordionItem.vue +105 -0
  104. package/src/components/molecules/FAlert/FAlert.stories.js +87 -0
  105. package/src/components/molecules/FAlert/FAlert.test.ts +59 -0
  106. package/src/components/molecules/FAlert/FAlert.vue +108 -0
  107. package/src/components/molecules/FBreadcrumb/FBreadcrumb.stories.js +90 -0
  108. package/src/components/molecules/FBreadcrumb/FBreadcrumb.test.ts +76 -0
  109. package/src/components/molecules/FBreadcrumb/FBreadcrumb.vue +117 -0
  110. package/src/components/molecules/FButtonGroup/FButtonGroup.stories.js +82 -0
  111. package/src/components/molecules/FButtonGroup/FButtonGroup.test.ts +44 -0
  112. package/src/components/molecules/FButtonGroup/FButtonGroup.vue +31 -0
  113. package/src/components/molecules/FCard/FCard.stories.js +136 -0
  114. package/src/components/molecules/FCard/FCard.test.ts +87 -0
  115. package/src/components/molecules/FCard/FCard.vue +75 -0
  116. package/src/components/molecules/FDatePicker/FDatePicker.stories.js +305 -0
  117. package/src/components/molecules/FDatePicker/FDatePicker.test.ts +282 -0
  118. package/src/components/molecules/FDatePicker/FDatePicker.vue +750 -0
  119. package/src/components/molecules/FEmptyState/FEmptyState.stories.js +98 -0
  120. package/src/components/molecules/FEmptyState/FEmptyState.test.ts +82 -0
  121. package/src/components/molecules/FEmptyState/FEmptyState.vue +89 -0
  122. package/src/components/molecules/FFilePreview/FFilePreview.stories.js +130 -0
  123. package/src/components/molecules/FFilePreview/FFilePreview.test.ts +70 -0
  124. package/src/components/molecules/FFilePreview/FFilePreview.vue +125 -0
  125. package/src/components/molecules/FFormField/FFormField.stories.js +149 -0
  126. package/src/components/molecules/FFormField/FFormField.test.ts +85 -0
  127. package/src/components/molecules/FFormField/FFormField.vue +107 -0
  128. package/src/components/molecules/FListItem/FListItem.stories.js +158 -0
  129. package/src/components/molecules/FListItem/FListItem.test.ts +93 -0
  130. package/src/components/molecules/FListItem/FListItem.vue +113 -0
  131. package/src/components/molecules/FPagination/FPagination.stories.js +132 -0
  132. package/src/components/molecules/FPagination/FPagination.test.ts +79 -0
  133. package/src/components/molecules/FPagination/FPagination.vue +206 -0
  134. package/src/components/molecules/FSearchBar/FSearchBar.stories.js +129 -0
  135. package/src/components/molecules/FSearchBar/FSearchBar.test.ts +81 -0
  136. package/src/components/molecules/FSearchBar/FSearchBar.vue +180 -0
  137. package/src/components/molecules/FSelect/FSelect.stories.js +333 -0
  138. package/src/components/molecules/FSelect/FSelect.test.ts +478 -0
  139. package/src/components/molecules/FSelect/FSelect.vue +551 -0
  140. package/src/components/molecules/FStatCard/FStatCard.stories.js +144 -0
  141. package/src/components/molecules/FStatCard/FStatCard.test.ts +78 -0
  142. package/src/components/molecules/FStatCard/FStatCard.vue +106 -0
  143. package/src/components/molecules/FTabs/FTab.vue +63 -0
  144. package/src/components/molecules/FTabs/FTabs.stories.js +277 -0
  145. package/src/components/molecules/FTabs/FTabs.test.ts +264 -0
  146. package/src/components/molecules/FTabs/FTabs.vue +273 -0
  147. package/src/components/molecules/FToast/FToast.stories.js +150 -0
  148. package/src/components/molecules/FToast/FToast.test.ts +157 -0
  149. package/src/components/molecules/FToast/FToast.vue +283 -0
  150. package/src/components/molecules/index.ts +37 -0
  151. package/src/components/organisms/FActivityFeed/FActivityFeed.stories.js +217 -0
  152. package/src/components/organisms/FActivityFeed/FActivityFeed.test.ts +134 -0
  153. package/src/components/organisms/FActivityFeed/FActivityFeed.vue +589 -0
  154. package/src/components/organisms/FDataTable/FDataTable.stories.js +370 -0
  155. package/src/components/organisms/FDataTable/FDataTable.test.ts +248 -0
  156. package/src/components/organisms/FDataTable/FDataTable.vue +808 -0
  157. package/src/components/organisms/FDrawer/FDrawer.stories.js +296 -0
  158. package/src/components/organisms/FDrawer/FDrawer.test.ts +142 -0
  159. package/src/components/organisms/FDrawer/FDrawer.vue +303 -0
  160. package/src/components/organisms/FFileUpload/FFileUpload.stories.js +162 -0
  161. package/src/components/organisms/FFileUpload/FFileUpload.test.ts +103 -0
  162. package/src/components/organisms/FFileUpload/FFileUpload.vue +616 -0
  163. package/src/components/organisms/FFilterSidebar/FFilterSidebar.stories.js +161 -0
  164. package/src/components/organisms/FFilterSidebar/FFilterSidebar.test.ts +92 -0
  165. package/src/components/organisms/FFilterSidebar/FFilterSidebar.vue +458 -0
  166. package/src/components/organisms/FForm/FForm.stories.js +270 -0
  167. package/src/components/organisms/FForm/FForm.test.ts +63 -0
  168. package/src/components/organisms/FForm/FForm.vue +19 -0
  169. package/src/components/organisms/FModal/FModal.stories.js +227 -0
  170. package/src/components/organisms/FModal/FModal.test.ts +181 -0
  171. package/src/components/organisms/FModal/FModal.vue +319 -0
  172. package/src/components/organisms/FNavigationSidebar/FNavigationSidebar.stories.js +176 -0
  173. package/src/components/organisms/FNavigationSidebar/FNavigationSidebar.test.ts +95 -0
  174. package/src/components/organisms/FNavigationSidebar/FNavigationSidebar.vue +577 -0
  175. package/src/components/organisms/FOnboardingStepper/FOnboardingStepper.stories.js +197 -0
  176. package/src/components/organisms/FOnboardingStepper/FOnboardingStepper.test.ts +114 -0
  177. package/src/components/organisms/FOnboardingStepper/FOnboardingStepper.vue +212 -0
  178. package/src/components/organisms/FOnboardingStepper/FStepperProgress.stories.js +122 -0
  179. package/src/components/organisms/FOnboardingStepper/FStepperProgress.test.ts +130 -0
  180. package/src/components/organisms/FOnboardingStepper/FStepperProgress.vue +146 -0
  181. package/src/components/organisms/FPageHeader/FPageHeader.stories.js +142 -0
  182. package/src/components/organisms/FPageHeader/FPageHeader.test.ts +83 -0
  183. package/src/components/organisms/FPageHeader/FPageHeader.vue +241 -0
  184. package/src/components/organisms/FProfileSection/FProfileSection.stories.js +190 -0
  185. package/src/components/organisms/FProfileSection/FProfileSection.test.ts +85 -0
  186. package/src/components/organisms/FProfileSection/FProfileSection.vue +562 -0
  187. package/src/components/organisms/FToastProvider/FToastProvider.stories.js +290 -0
  188. package/src/components/organisms/FToastProvider/FToastProvider.test.ts +215 -0
  189. package/src/components/organisms/FToastProvider/FToastProvider.vue +214 -0
  190. package/src/components/organisms/FUserMenu/FUserMenu.stories.js +170 -0
  191. package/src/components/organisms/FUserMenu/FUserMenu.test.ts +102 -0
  192. package/src/components/organisms/FUserMenu/FUserMenu.vue +407 -0
  193. package/src/components/organisms/index.ts +29 -0
  194. package/src/components/utils/FThemeProvider.stories.js +236 -0
  195. package/src/components/utils/FThemeProvider.test.ts +244 -0
  196. package/src/components/utils/FThemeProvider.vue +191 -0
  197. package/src/components/utils/index.ts +3 -0
  198. package/src/components.d.ts +602 -0
  199. package/src/composables/README.md +233 -0
  200. package/src/composables/index.ts +25 -0
  201. package/src/composables/useDataTableState.test.ts +378 -0
  202. package/src/composables/useDataTableState.ts +361 -0
  203. package/src/composables/useFormValidation.test.ts +198 -0
  204. package/src/composables/useFormValidation.ts +178 -0
  205. package/src/composables/useSidebarState.test.ts +307 -0
  206. package/src/composables/useSidebarState.ts +201 -0
  207. package/src/env.d.ts +14 -0
  208. package/src/index.ts +167 -0
  209. package/src/styles/tailwind.css +173 -0
  210. package/src/types.ts +740 -0
@@ -0,0 +1,296 @@
1
+ import FDrawer from './FDrawer.vue';
2
+ import FButton from '../../atoms/FButton/FButton.vue';
3
+ import FFormField from '../../molecules/FFormField/FFormField.vue';
4
+
5
+ export default {
6
+ title: 'Organisms/FDrawer',
7
+ component: FDrawer,
8
+ tags: ['autodocs'],
9
+ argTypes: {
10
+ value: {
11
+ control: 'boolean',
12
+ description: 'État ouvert/fermé'
13
+ },
14
+ title: {
15
+ control: 'text',
16
+ description: 'Titre du tiroir'
17
+ },
18
+ subtitle: {
19
+ control: 'text',
20
+ description: 'Sous-titre'
21
+ },
22
+ position: {
23
+ control: { type: 'select' },
24
+ options: ['left', 'right', 'top', 'bottom'],
25
+ description: 'Position du tiroir'
26
+ },
27
+ size: {
28
+ control: { type: 'select' },
29
+ options: ['small', 'medium', 'large'],
30
+ description: 'Taille du tiroir'
31
+ },
32
+ closable: {
33
+ control: 'boolean',
34
+ description: 'Afficher le bouton de fermeture'
35
+ },
36
+ closeOnOverlay: {
37
+ control: 'boolean',
38
+ description: "Fermer au clic sur l'overlay"
39
+ },
40
+ closeOnEscape: {
41
+ control: 'boolean',
42
+ description: 'Fermer avec la touche Échap'
43
+ },
44
+ bordered: {
45
+ control: 'boolean',
46
+ description: 'Afficher une bordure'
47
+ }
48
+ }
49
+ };
50
+
51
+ export const Default = () => ({
52
+ components: { FDrawer, FButton },
53
+ data() {
54
+ return { isOpen: false };
55
+ },
56
+ template: `
57
+ <div>
58
+ <FButton @click="isOpen = true">Ouvrir le tiroir</FButton>
59
+ <FDrawer v-model="isOpen" title="Titre du tiroir">
60
+ <template #body>
61
+ <p>Contenu du tiroir latéral.</p>
62
+ </template>
63
+ <template #actions>
64
+ <FButton variant="outline" @click="isOpen = false">Annuler</FButton>
65
+ <FButton variant="primary" @click="isOpen = false">Confirmer</FButton>
66
+ </template>
67
+ </FDrawer>
68
+ </div>
69
+ `
70
+ });
71
+
72
+ export const WithSubtitle = () => ({
73
+ components: { FDrawer, FButton },
74
+ data() {
75
+ return { isOpen: false };
76
+ },
77
+ template: `
78
+ <div>
79
+ <FButton @click="isOpen = true">Ouvrir</FButton>
80
+ <FDrawer v-model="isOpen" title="Paramètres" subtitle="Configuration du profil">
81
+ <template #body>
82
+ <p>Modifiez vos paramètres de profil ici.</p>
83
+ </template>
84
+ <template #actions>
85
+ <FButton variant="outline" @click="isOpen = false">Annuler</FButton>
86
+ <FButton variant="primary" @click="isOpen = false">Sauvegarder</FButton>
87
+ </template>
88
+ </FDrawer>
89
+ </div>
90
+ `
91
+ });
92
+
93
+ export const Positions = () => ({
94
+ components: { FDrawer, FButton },
95
+ data() {
96
+ return {
97
+ leftOpen: false,
98
+ rightOpen: false,
99
+ topOpen: false,
100
+ bottomOpen: false
101
+ };
102
+ },
103
+ template: `
104
+ <div class="flex gap-2">
105
+ <FButton @click="leftOpen = true">Gauche</FButton>
106
+ <FButton @click="rightOpen = true">Droite</FButton>
107
+ <FButton @click="topOpen = true">Haut</FButton>
108
+ <FButton @click="bottomOpen = true">Bas</FButton>
109
+
110
+ <FDrawer v-model="leftOpen" title="Tiroir gauche" position="left">
111
+ <template #body><p>Contenu du tiroir gauche.</p></template>
112
+ </FDrawer>
113
+ <FDrawer v-model="rightOpen" title="Tiroir droit" position="right">
114
+ <template #body><p>Contenu du tiroir droit.</p></template>
115
+ </FDrawer>
116
+ <FDrawer v-model="topOpen" title="Tiroir haut" position="top">
117
+ <template #body><p>Contenu du tiroir haut.</p></template>
118
+ </FDrawer>
119
+ <FDrawer v-model="bottomOpen" title="Tiroir bas" position="bottom">
120
+ <template #body><p>Contenu du tiroir bas.</p></template>
121
+ </FDrawer>
122
+ </div>
123
+ `
124
+ });
125
+
126
+ export const Sizes = () => ({
127
+ components: { FDrawer, FButton },
128
+ data() {
129
+ return {
130
+ smallOpen: false,
131
+ mediumOpen: false,
132
+ largeOpen: false
133
+ };
134
+ },
135
+ template: `
136
+ <div class="flex gap-2">
137
+ <FButton @click="smallOpen = true">Petit</FButton>
138
+ <FButton @click="mediumOpen = true">Moyen</FButton>
139
+ <FButton @click="largeOpen = true">Grand</FButton>
140
+
141
+ <FDrawer v-model="smallOpen" title="Petit tiroir" size="small">
142
+ <template #body><p>Tiroir de petite taille.</p></template>
143
+ </FDrawer>
144
+ <FDrawer v-model="mediumOpen" title="Tiroir moyen" size="medium">
145
+ <template #body><p>Taille par défaut.</p></template>
146
+ </FDrawer>
147
+ <FDrawer v-model="largeOpen" title="Grand tiroir" size="large">
148
+ <template #body><p>Tiroir de grande taille.</p></template>
149
+ </FDrawer>
150
+ </div>
151
+ `
152
+ });
153
+
154
+ export const NotClosable = () => ({
155
+ components: { FDrawer, FButton },
156
+ data() {
157
+ return { isOpen: false };
158
+ },
159
+ template: `
160
+ <div>
161
+ <FButton @click="isOpen = true">Ouvrir (non fermable)</FButton>
162
+ <FDrawer
163
+ v-model="isOpen"
164
+ title="Action obligatoire"
165
+ :closable="false"
166
+ :closeOnOverlay="false"
167
+ :closeOnEscape="false"
168
+ >
169
+ <template #body>
170
+ <p>Vous devez confirmer cette action avant de continuer.</p>
171
+ </template>
172
+ <template #actions>
173
+ <FButton variant="primary" @click="isOpen = false">J'ai compris</FButton>
174
+ </template>
175
+ </FDrawer>
176
+ </div>
177
+ `
178
+ });
179
+
180
+ export const WithForm = () => ({
181
+ components: { FDrawer, FButton, FFormField },
182
+ data() {
183
+ return {
184
+ isOpen: false,
185
+ form: {
186
+ name: '',
187
+ email: '',
188
+ phone: ''
189
+ }
190
+ };
191
+ },
192
+ methods: {
193
+ handleSubmit() {
194
+ alert(
195
+ `Nom: ${this.form.name}, Email: ${this.form.email}, Téléphone: ${this.form.phone}`
196
+ );
197
+ this.isOpen = false;
198
+ }
199
+ },
200
+ template: `
201
+ <div>
202
+ <FButton @click="isOpen = true">Ajouter un contact</FButton>
203
+ <FDrawer v-model="isOpen" title="Nouveau contact" subtitle="Remplissez les informations">
204
+ <template #body>
205
+ <div class="flex flex-col gap-4">
206
+ <FFormField v-model="form.name" label="Nom complet" required />
207
+ <FFormField v-model="form.email" label="Email" type="email" required />
208
+ <FFormField v-model="form.phone" label="Téléphone" type="tel" />
209
+ </div>
210
+ </template>
211
+ <template #actions>
212
+ <FButton variant="outline" @click="isOpen = false">Annuler</FButton>
213
+ <FButton variant="primary" @click="handleSubmit">Ajouter</FButton>
214
+ </template>
215
+ </FDrawer>
216
+ </div>
217
+ `
218
+ });
219
+
220
+ export const FilterPanel = () => ({
221
+ components: { FDrawer, FButton, FFormField },
222
+ data() {
223
+ return {
224
+ isOpen: false,
225
+ filters: {
226
+ search: '',
227
+ category: '',
228
+ minPrice: '',
229
+ maxPrice: ''
230
+ }
231
+ };
232
+ },
233
+ methods: {
234
+ applyFilters() {
235
+ alert('Filtres appliqués !');
236
+ this.isOpen = false;
237
+ },
238
+ resetFilters() {
239
+ this.filters = {
240
+ search: '',
241
+ category: '',
242
+ minPrice: '',
243
+ maxPrice: ''
244
+ };
245
+ }
246
+ },
247
+ template: `
248
+ <div>
249
+ <FButton @click="isOpen = true">Filtres</FButton>
250
+ <FDrawer v-model="isOpen" title="Filtres" subtitle="Affinez votre recherche" position="left">
251
+ <template #body>
252
+ <div class="flex flex-col gap-4">
253
+ <FFormField v-model="filters.search" label="Recherche" placeholder="Rechercher..." />
254
+ <FFormField v-model="filters.category" label="Catégorie" placeholder="Sélectionner..." />
255
+ <div class="grid grid-cols-2 gap-2">
256
+ <FFormField v-model="filters.minPrice" label="Prix min" type="number" />
257
+ <FFormField v-model="filters.maxPrice" label="Prix max" type="number" />
258
+ </div>
259
+ </div>
260
+ </template>
261
+ <template #actions>
262
+ <FButton variant="ghost" @click="resetFilters">Réinitialiser</FButton>
263
+ <FButton variant="primary" @click="applyFilters">Appliquer</FButton>
264
+ </template>
265
+ </FDrawer>
266
+ </div>
267
+ `
268
+ });
269
+
270
+ export const CustomHeader = () => ({
271
+ components: { FDrawer, FButton },
272
+ data() {
273
+ return { isOpen: false };
274
+ },
275
+ template: `
276
+ <div>
277
+ <FButton @click="isOpen = true">Ouvrir</FButton>
278
+ <FDrawer v-model="isOpen">
279
+ <template #header>
280
+ <div class="flex items-center gap-3">
281
+ <div class="w-10 h-10 rounded-full bg-primary-100 flex items-center justify-center">
282
+ <span class="text-primary-600 font-bold text-xl">📋</span>
283
+ </div>
284
+ <div>
285
+ <h3 class="font-semibold">En-tête personnalisé</h3>
286
+ <p class="text-sm text-neutral-500">Avec icône et mise en forme</p>
287
+ </div>
288
+ </div>
289
+ </template>
290
+ <template #body>
291
+ <p>Contenu du tiroir avec un en-tête personnalisé.</p>
292
+ </template>
293
+ </FDrawer>
294
+ </div>
295
+ `
296
+ });
@@ -0,0 +1,142 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { mount } from '@vue/test-utils';
3
+ import FDrawer from './FDrawer.vue';
4
+
5
+ describe('FDrawer', () => {
6
+ it('renders correctly when open', () => {
7
+ const wrapper = mount(FDrawer, {
8
+ propsData: { value: true, title: 'Test Drawer' }
9
+ });
10
+ expect(wrapper.find('[role="dialog"]').exists()).toBe(true);
11
+ });
12
+
13
+ it('does not render when closed', () => {
14
+ const wrapper = mount(FDrawer, {
15
+ propsData: { value: false }
16
+ });
17
+ expect(wrapper.find('[role="dialog"]').exists()).toBe(false);
18
+ });
19
+
20
+ it('displays title', () => {
21
+ const wrapper = mount(FDrawer, {
22
+ propsData: { value: true, title: 'Drawer Title' }
23
+ });
24
+ expect(wrapper.text()).toContain('Drawer Title');
25
+ });
26
+
27
+ it('displays subtitle', () => {
28
+ const wrapper = mount(FDrawer, {
29
+ propsData: { value: true, title: 'Title', subtitle: 'Subtitle' }
30
+ });
31
+ expect(wrapper.text()).toContain('Subtitle');
32
+ });
33
+
34
+ it('renders body slot', () => {
35
+ const wrapper = mount(FDrawer, {
36
+ propsData: { value: true },
37
+ slots: { body: '<p>Body content</p>' }
38
+ });
39
+ expect(wrapper.html()).toContain('Body content');
40
+ });
41
+
42
+ it('renders actions slot', () => {
43
+ const wrapper = mount(FDrawer, {
44
+ propsData: { value: true },
45
+ slots: { actions: '<button>Action</button>' }
46
+ });
47
+ expect(wrapper.html()).toContain('Action');
48
+ });
49
+
50
+ it('shows close button by default', () => {
51
+ const wrapper = mount(FDrawer, {
52
+ propsData: { value: true }
53
+ });
54
+ expect(wrapper.findComponent({ name: 'FButton' }).exists()).toBe(true);
55
+ });
56
+
57
+ it('hides close button when closable is false', () => {
58
+ const wrapper = mount(FDrawer, {
59
+ propsData: { value: true, closable: false }
60
+ });
61
+ expect(wrapper.findAllComponents({ name: 'FButton' }).length).toBe(0);
62
+ });
63
+
64
+ it('emits close when close button is clicked', async () => {
65
+ const wrapper = mount(FDrawer, {
66
+ propsData: { value: true }
67
+ });
68
+ await wrapper.findComponent({ name: 'FButton' }).trigger('click');
69
+ expect(wrapper.emitted('close')).toBeTruthy();
70
+ });
71
+
72
+ it('emits input false when close button is clicked', async () => {
73
+ const wrapper = mount(FDrawer, {
74
+ propsData: { value: true }
75
+ });
76
+ await wrapper.findComponent({ name: 'FButton' }).trigger('click');
77
+ expect(wrapper.emitted('input')).toBeTruthy();
78
+ });
79
+
80
+ it('closes on overlay click when closeOnOverlay is true', async () => {
81
+ const wrapper = mount(FDrawer, {
82
+ propsData: { value: true, closeOnOverlay: true }
83
+ });
84
+ await wrapper.find('.bg-black').trigger('click');
85
+ expect(wrapper.emitted('close')).toBeTruthy();
86
+ });
87
+
88
+ it('does not close on overlay click when closeOnOverlay is false', async () => {
89
+ const wrapper = mount(FDrawer, {
90
+ propsData: { value: true, closeOnOverlay: false }
91
+ });
92
+ await wrapper.find('.bg-black').trigger('click');
93
+ expect(wrapper.emitted('close')).toBeFalsy();
94
+ });
95
+
96
+ it('applies correct size classes', () => {
97
+ const sizes = ['small', 'medium', 'large'] as const;
98
+ sizes.forEach((size) => {
99
+ const wrapper = mount(FDrawer, {
100
+ propsData: { value: true, size }
101
+ });
102
+ expect(wrapper.find('[role="dialog"]').exists()).toBe(true);
103
+ });
104
+ });
105
+
106
+ it('applies correct position classes for left', () => {
107
+ const wrapper = mount(FDrawer, {
108
+ propsData: { value: true, position: 'left' }
109
+ });
110
+ expect(wrapper.find('[role="dialog"]').classes()).toContain('w-80');
111
+ });
112
+
113
+ it('applies correct position classes for right', () => {
114
+ const wrapper = mount(FDrawer, {
115
+ propsData: { value: true, position: 'right' }
116
+ });
117
+ expect(wrapper.find('[role="dialog"]').classes()).toContain('w-80');
118
+ });
119
+
120
+ it('applies correct position classes for top', () => {
121
+ const wrapper = mount(FDrawer, {
122
+ propsData: { value: true, position: 'top' }
123
+ });
124
+ expect(wrapper.find('[role="dialog"]').classes()).toContain('h-80');
125
+ });
126
+
127
+ it('applies correct position classes for bottom', () => {
128
+ const wrapper = mount(FDrawer, {
129
+ propsData: { value: true, position: 'bottom' }
130
+ });
131
+ expect(wrapper.find('[role="dialog"]').classes()).toContain('h-80');
132
+ });
133
+
134
+ it('applies border when bordered is true', () => {
135
+ const wrapper = mount(FDrawer, {
136
+ propsData: { value: true, bordered: true }
137
+ });
138
+ expect(wrapper.find('[role="dialog"]').classes().join(' ')).toContain(
139
+ 'border'
140
+ );
141
+ });
142
+ });