@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,192 @@
1
+ <template>
2
+ <span
3
+ :class="iconClasses"
4
+ :style="iconStyle"
5
+ :aria-hidden="ariaHidden"
6
+ :aria-label="ariaLabel"
7
+ role="img"
8
+ >
9
+ <slot>
10
+ <svg
11
+ v-if="iconPath"
12
+ xmlns="http://www.w3.org/2000/svg"
13
+ fill="none"
14
+ viewBox="0 0 24 24"
15
+ stroke="currentColor"
16
+ stroke-width="2"
17
+ :class="svgClasses"
18
+ >
19
+ <path stroke-linecap="round" stroke-linejoin="round" :d="iconPath" />
20
+ </svg>
21
+ <svg
22
+ v-else-if="showPlaceholder"
23
+ xmlns="http://www.w3.org/2000/svg"
24
+ fill="none"
25
+ viewBox="0 0 24 24"
26
+ stroke="currentColor"
27
+ stroke-width="2"
28
+ :class="svgClasses"
29
+ >
30
+ <path
31
+ stroke-linecap="round"
32
+ stroke-linejoin="round"
33
+ d="M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9 5.25h.008v.008H12v-.008z"
34
+ />
35
+ </svg>
36
+ </slot>
37
+ </span>
38
+ </template>
39
+
40
+ <script>
41
+ const ICON_PATHS = {
42
+ // Navigation
43
+ 'chevron-up': 'M4.5 15.75l7.5-7.5 7.5 7.5',
44
+ 'chevron-down': 'M19.5 8.25l-7.5 7.5-7.5-7.5',
45
+ 'chevron-left': 'M15.75 19.5L8.25 12l7.5-7.5',
46
+ 'chevron-right': 'M8.25 4.5l7.5 7.5-7.5 7.5',
47
+ 'arrow-up': 'M4.5 10.5L12 3m0 0l7.5 7.5M12 3v18',
48
+ 'arrow-down': 'M19.5 13.5L12 21m0 0l-7.5-7.5M12 21V3',
49
+ 'arrow-left': 'M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18',
50
+ 'arrow-right': 'M13.5 4.5L21 12m0 0l-7.5 7.5M21 12H3',
51
+
52
+ // Actions
53
+ check: 'M4.5 12.75l6 6 9-13.5',
54
+ x: 'M6 18L18 6M6 6l12 12',
55
+ plus: 'M12 4.5v15m7.5-7.5h-15',
56
+ minus: 'M19.5 12h-15',
57
+ search:
58
+ 'M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z',
59
+ menu: 'M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5',
60
+ close: 'M6 18L18 6M6 6l12 12',
61
+ refresh:
62
+ 'M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99',
63
+ edit: 'M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10',
64
+ trash:
65
+ 'M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0',
66
+ copy: 'M15.75 17.25v3.375c0 .621-.504 1.125-1.125 1.125h-9.75a1.125 1.125 0 01-1.125-1.125V7.875c0-.621.504-1.125 1.125-1.125H6.75a9.06 9.06 0 011.5.124m7.5 10.376h3.375c.621 0 1.125-.504 1.125-1.125V11.25c0-4.46-3.243-8.161-7.5-8.876a9.06 9.06 0 00-1.5-.124H9.375c-.621 0-1.125.504-1.125 1.125v3.5m7.5 10.375H9.375a1.125 1.125 0 01-1.125-1.125v-9.25m12 6.625v-1.875a3.375 3.375 0 00-3.375-3.375h-1.5a1.125 1.125 0 01-1.125-1.125v-1.5a3.375 3.375 0 00-3.375-3.375H9.75',
67
+
68
+ // Status
69
+ info: 'M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z',
70
+ warning:
71
+ 'M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z',
72
+ error:
73
+ 'M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z',
74
+ success: 'M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z',
75
+ question:
76
+ 'M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9 5.25h.008v.008H12v-.008z',
77
+
78
+ // Common UI
79
+ user: 'M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.501 20.118a7.5 7.5 0 0114.998 0A17.933 17.933 0 0112 21.75c-2.676 0-5.216-.584-7.499-1.632z',
80
+ home: 'M2.25 12l8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25',
81
+ cog: 'M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.324.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 6.759 0 010 .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.28c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.02-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932 6.932 0 010-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.087.22-.128.332-.183.582-.495.644-.869l.214-1.281z',
82
+ bell: 'M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0',
83
+ heart:
84
+ 'M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12z',
85
+ star: 'M11.48 3.499a.562.562 0 011.04 0l2.125 5.111a.563.563 0 00.475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 00-.182.557l1.285 5.385a.562.562 0 01-.84.61l-4.725-2.885a.563.563 0 00-.586 0L6.982 20.54a.562.562 0 01-.84-.61l1.285-5.386a.562.562 0 00-.182-.557l-4.204-3.602a.563.563 0 01.321-.988l5.518-.442a.563.563 0 00.475-.345L11.48 3.5z',
86
+ eye: 'M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z M15 12a3 3 0 11-6 0 3 3 0 016 0z',
87
+ 'eye-off':
88
+ 'M3.98 8.223A10.477 10.477 0 001.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.45 10.45 0 0112 4.5c4.756 0 8.773 3.162 10.065 7.498a10.523 10.523 0 01-4.293 5.774M6.228 6.228L3 3m3.228 3.228l3.65 3.65m7.894 7.894L21 21m-3.228-3.228l-3.65-3.65m0 0a3 3 0 10-4.243-4.243m4.242 4.242L9.88 9.88',
89
+ lock: 'M16.5 10.5V6.75a4.5 4.5 0 10-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 002.25-2.25v-6.75a2.25 2.25 0 00-2.25-2.25H6.75a2.25 2.25 0 00-2.25 2.25v6.75a2.25 2.25 0 002.25 2.25z',
90
+ unlock:
91
+ 'M13.5 10.5V6.75a4.5 4.5 0 119 0v3.75M3.75 21.75h10.5a2.25 2.25 0 002.25-2.25v-6.75a2.25 2.25 0 00-2.25-2.25H3.75a2.25 2.25 0 00-2.25 2.25v6.75a2.25 2.25 0 002.25 2.25z',
92
+ mail: 'M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25h-15a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-1.07 1.916l-7.5 4.615a2.25 2.25 0 01-2.36 0L3.32 8.91a2.25 2.25 0 01-1.07-1.916V6.75',
93
+ calendar:
94
+ 'M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 012.25-2.25h13.5A2.25 2.25 0 0121 7.5v11.25m-18 0A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75m-18 0v-7.5A2.25 2.25 0 015.25 9h13.5A2.25 2.25 0 0121 11.25v7.5',
95
+ clock: 'M12 6v6h4.5m4.5 0a9 9 0 11-18 0 9 9 0 0118 0z',
96
+ download:
97
+ 'M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3',
98
+ upload:
99
+ 'M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5m-13.5-9L12 3m0 0l4.5 4.5M12 3v13.5',
100
+ link: 'M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244',
101
+ 'external-link':
102
+ 'M13.5 6H5.25A2.25 2.25 0 003 8.25v10.5A2.25 2.25 0 005.25 21h10.5A2.25 2.25 0 0018 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25',
103
+ folder:
104
+ 'M2.25 12.75V12A2.25 2.25 0 014.5 9.75h15A2.25 2.25 0 0121.75 12v.75m-8.69-6.44l-2.12-2.12a1.5 1.5 0 00-1.061-.44H4.5A2.25 2.25 0 002.25 6v12a2.25 2.25 0 002.25 2.25h15A2.25 2.25 0 0021.75 18V9a2.25 2.25 0 00-2.25-2.25h-5.379a1.5 1.5 0 01-1.06-.44z',
105
+ document:
106
+ 'M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m2.25 0H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z'
107
+ };
108
+
109
+ export default {
110
+ name: 'FIcon',
111
+ props: {
112
+ name: {
113
+ type: String,
114
+ default: ''
115
+ },
116
+ size: {
117
+ type: String,
118
+ default: 'md',
119
+ validator: (value) =>
120
+ ['xs', 'sm', 'md', 'lg', 'xl'].includes(value) ||
121
+ /^\d+(\.\d+)?(px|rem|em|%|vh|vw)?$/.test(value)
122
+ },
123
+ color: {
124
+ type: String,
125
+ default: ''
126
+ },
127
+ decorative: {
128
+ type: Boolean,
129
+ default: true
130
+ },
131
+ label: {
132
+ type: String,
133
+ default: ''
134
+ }
135
+ },
136
+ computed: {
137
+ iconPath() {
138
+ return ICON_PATHS[this.name] || null;
139
+ },
140
+ showPlaceholder() {
141
+ return this.name && !this.iconPath;
142
+ },
143
+ ariaHidden() {
144
+ return this.decorative ? 'true' : undefined;
145
+ },
146
+ ariaLabel() {
147
+ return !this.decorative ? this.label || this.name : undefined;
148
+ },
149
+ sizeClass() {
150
+ const sizeMap = {
151
+ xs: 'w-3 h-3',
152
+ sm: 'w-4 h-4',
153
+ md: 'w-5 h-5',
154
+ lg: 'w-6 h-6',
155
+ xl: 'w-8 h-8'
156
+ };
157
+ return sizeMap[this.size] || '';
158
+ },
159
+ isCustomSize() {
160
+ return !['xs', 'sm', 'md', 'lg', 'xl'].includes(this.size);
161
+ },
162
+ iconClasses() {
163
+ const baseClasses =
164
+ 'inline-flex items-center justify-center flex-shrink-0';
165
+
166
+ return [baseClasses, this.sizeClass].filter(Boolean).join(' ');
167
+ },
168
+ svgClasses() {
169
+ return 'w-full h-full';
170
+ },
171
+ iconStyle() {
172
+ const style = {};
173
+
174
+ if (this.color) {
175
+ style.color = this.color;
176
+ }
177
+
178
+ if (this.isCustomSize) {
179
+ const size = /^\d+(px|rem|em)?$/.test(this.size)
180
+ ? /^\d+$/.test(this.size)
181
+ ? `${this.size}px`
182
+ : this.size
183
+ : this.size;
184
+ style.width = size;
185
+ style.height = size;
186
+ }
187
+
188
+ return Object.keys(style).length > 0 ? style : undefined;
189
+ }
190
+ }
191
+ };
192
+ </script>
@@ -0,0 +1,119 @@
1
+ import FInput from './FInput.vue';
2
+
3
+ export default {
4
+ title: 'Atoms/FInput',
5
+ component: FInput,
6
+ tags: ['autodocs'],
7
+ argTypes: {
8
+ value: {
9
+ control: 'text',
10
+ description: 'Valeur du champ'
11
+ },
12
+ type: {
13
+ control: { type: 'select' },
14
+ options: ['text', 'email', 'password', 'number', 'tel', 'url'],
15
+ description: 'Type du champ'
16
+ },
17
+ placeholder: {
18
+ control: 'text',
19
+ description: 'Texte de placeholder'
20
+ },
21
+ size: {
22
+ control: { type: 'select' },
23
+ options: ['small', 'medium', 'large'],
24
+ description: 'Taille du champ'
25
+ },
26
+ disabled: {
27
+ control: 'boolean',
28
+ description: 'État désactivé'
29
+ },
30
+ readonly: {
31
+ control: 'boolean',
32
+ description: 'Lecture seule'
33
+ },
34
+ error: {
35
+ control: 'boolean',
36
+ description: "État d'erreur"
37
+ }
38
+ }
39
+ };
40
+
41
+ const Template = (args, { argTypes }) => ({
42
+ components: { FInput },
43
+ props: Object.keys(argTypes),
44
+ data() {
45
+ return { inputValue: args.value || '' };
46
+ },
47
+ template: '<FInput v-bind="$props" v-model="inputValue" />'
48
+ });
49
+
50
+ export const Default = Template.bind({});
51
+ Default.args = {
52
+ placeholder: 'Saisissez du texte...'
53
+ };
54
+
55
+ export const WithValue = Template.bind({});
56
+ WithValue.args = {
57
+ value: 'Valeur initiale'
58
+ };
59
+
60
+ export const Types = () => ({
61
+ components: { FInput },
62
+ data() {
63
+ return {
64
+ text: '',
65
+ email: '',
66
+ password: '',
67
+ number: ''
68
+ };
69
+ },
70
+ template: `
71
+ <div class="flex flex-col gap-4">
72
+ <FInput v-model="text" type="text" placeholder="Texte" />
73
+ <FInput v-model="email" type="email" placeholder="Email" />
74
+ <FInput v-model="password" type="password" placeholder="Mot de passe" />
75
+ <FInput v-model="number" type="number" placeholder="Nombre" />
76
+ </div>
77
+ `
78
+ });
79
+
80
+ export const Sizes = () => ({
81
+ components: { FInput },
82
+ template: `
83
+ <div class="flex flex-col gap-4">
84
+ <FInput size="small" placeholder="Petit" />
85
+ <FInput size="medium" placeholder="Moyen" />
86
+ <FInput size="large" placeholder="Grand" />
87
+ </div>
88
+ `
89
+ });
90
+
91
+ export const Disabled = Template.bind({});
92
+ Disabled.args = {
93
+ disabled: true,
94
+ placeholder: 'Champ désactivé'
95
+ };
96
+
97
+ export const Readonly = Template.bind({});
98
+ Readonly.args = {
99
+ readonly: true,
100
+ value: 'Valeur en lecture seule'
101
+ };
102
+
103
+ export const WithError = Template.bind({});
104
+ WithError.args = {
105
+ error: true,
106
+ placeholder: 'Champ avec erreur'
107
+ };
108
+
109
+ export const States = () => ({
110
+ components: { FInput },
111
+ template: `
112
+ <div class="flex flex-col gap-4">
113
+ <FInput placeholder="Normal" />
114
+ <FInput placeholder="Désactivé" disabled />
115
+ <FInput value="Lecture seule" readonly />
116
+ <FInput placeholder="Erreur" error />
117
+ </div>
118
+ `
119
+ });
@@ -0,0 +1,79 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { mount } from '@vue/test-utils';
3
+ import FInput from './FInput.vue';
4
+
5
+ describe('FInput', () => {
6
+ it('renders correctly with default props', () => {
7
+ const wrapper = mount(FInput);
8
+ expect(wrapper.find('input').exists()).toBe(true);
9
+ });
10
+
11
+ it('renders with correct type', () => {
12
+ const types = ['text', 'email', 'password', 'number'];
13
+ types.forEach((type) => {
14
+ const wrapper = mount(FInput, {
15
+ propsData: { type }
16
+ });
17
+ expect(wrapper.find('input').attributes('type')).toBe(type);
18
+ });
19
+ });
20
+
21
+ it('displays placeholder', () => {
22
+ const wrapper = mount(FInput, {
23
+ propsData: { placeholder: 'Enter text...' }
24
+ });
25
+ expect(wrapper.find('input').attributes('placeholder')).toBe(
26
+ 'Enter text...'
27
+ );
28
+ });
29
+
30
+ it('displays value', () => {
31
+ const wrapper = mount(FInput, {
32
+ propsData: { value: 'Test value' }
33
+ });
34
+ expect((wrapper.find('input').element as HTMLInputElement).value).toBe(
35
+ 'Test value'
36
+ );
37
+ });
38
+
39
+ it('emits input event when typing', async () => {
40
+ const wrapper = mount(FInput);
41
+ await wrapper.find('input').setValue('New value');
42
+ expect(wrapper.emitted('input')).toBeTruthy();
43
+ expect(wrapper.emitted('input')![0]).toEqual(['New value']);
44
+ });
45
+
46
+ it('applies correct size classes', () => {
47
+ const sizes = ['small', 'medium', 'large'] as const;
48
+ sizes.forEach((size) => {
49
+ const wrapper = mount(FInput, {
50
+ propsData: { size }
51
+ });
52
+ expect(wrapper.find('input').exists()).toBe(true);
53
+ });
54
+ });
55
+
56
+ it('applies disabled state', () => {
57
+ const wrapper = mount(FInput, {
58
+ propsData: { disabled: true }
59
+ });
60
+ expect(wrapper.find('input').attributes('disabled')).toBeDefined();
61
+ expect(wrapper.find('input').classes()).toContain('cursor-not-allowed');
62
+ });
63
+
64
+ it('applies readonly state', () => {
65
+ const wrapper = mount(FInput, {
66
+ propsData: { readonly: true }
67
+ });
68
+ expect(wrapper.find('input').attributes('readonly')).toBeDefined();
69
+ });
70
+
71
+ it('applies error styles', () => {
72
+ const wrapper = mount(FInput, {
73
+ propsData: { error: true }
74
+ });
75
+ expect(wrapper.find('input').classes().join(' ')).toContain(
76
+ 'border-danger'
77
+ );
78
+ });
79
+ });
@@ -0,0 +1,88 @@
1
+ <template>
2
+ <input
3
+ :class="inputClasses"
4
+ :type="type"
5
+ :value="value"
6
+ :placeholder="placeholder"
7
+ :disabled="disabled"
8
+ :readonly="readonly"
9
+ @input="handleInput"
10
+ @focus="$emit('focus', $event)"
11
+ @blur="$emit('blur', $event)"
12
+ />
13
+ </template>
14
+
15
+ <script>
16
+ export default {
17
+ name: 'FInput',
18
+ props: {
19
+ value: {
20
+ type: [String, Number],
21
+ default: ''
22
+ },
23
+ type: {
24
+ type: String,
25
+ default: 'text'
26
+ },
27
+ placeholder: {
28
+ type: String,
29
+ default: ''
30
+ },
31
+ size: {
32
+ type: String,
33
+ default: 'medium',
34
+ validator: (value) => ['small', 'medium', 'large'].includes(value)
35
+ },
36
+ disabled: {
37
+ type: Boolean,
38
+ default: false
39
+ },
40
+ readonly: {
41
+ type: Boolean,
42
+ default: false
43
+ },
44
+ error: {
45
+ type: Boolean,
46
+ default: false
47
+ }
48
+ },
49
+ computed: {
50
+ inputClasses() {
51
+ const baseClasses =
52
+ 'block w-full font-sans border rounded box-border focus:outline-none focus:ring-2';
53
+
54
+ const transitionClasses =
55
+ 'transition-all duration-[var(--transition-duration-base)] ease-[var(--transition-easing-standard)]';
56
+
57
+ const sizeClasses = {
58
+ small: 'py-1.5 px-2.5 text-xs',
59
+ medium: 'py-2.5 px-3.5 text-sm',
60
+ large: 'py-3.5 px-4.5 text-base'
61
+ };
62
+
63
+ const stateClasses = this.error
64
+ ? 'border-danger-500 focus:border-danger-500 focus:ring-danger-500/20'
65
+ : 'border-neutral-300 focus:border-primary-500 focus:ring-primary-500/20';
66
+
67
+ const disabledClasses = this.disabled
68
+ ? 'bg-neutral-100 cursor-not-allowed opacity-70'
69
+ : '';
70
+
71
+ return [
72
+ baseClasses,
73
+ transitionClasses,
74
+ sizeClasses[this.size],
75
+ stateClasses,
76
+ disabledClasses
77
+ ]
78
+ .filter(Boolean)
79
+ .join(' ');
80
+ }
81
+ },
82
+ methods: {
83
+ handleInput(event) {
84
+ this.$emit('input', event.target.value);
85
+ }
86
+ }
87
+ };
88
+ </script>
@@ -0,0 +1,109 @@
1
+ import FLoader from './FLoader.vue';
2
+
3
+ export default {
4
+ title: 'Atoms/FLoader',
5
+ component: FLoader,
6
+ tags: ['autodocs'],
7
+ argTypes: {
8
+ size: {
9
+ control: { type: 'select' },
10
+ options: ['xs', 'sm', 'md', 'lg', 'xl'],
11
+ description: 'Taille du loader'
12
+ },
13
+ color: {
14
+ control: 'color',
15
+ description: 'Couleur du loader'
16
+ },
17
+ overlay: {
18
+ control: 'boolean',
19
+ description: 'Afficher en overlay plein écran'
20
+ },
21
+ centered: {
22
+ control: 'boolean',
23
+ description: 'Centrer dans le conteneur parent'
24
+ },
25
+ label: {
26
+ control: 'text',
27
+ description: "Label pour l'accessibilité"
28
+ }
29
+ }
30
+ };
31
+
32
+ const Template = (args, { argTypes }) => ({
33
+ components: { FLoader },
34
+ props: Object.keys(argTypes),
35
+ template: '<FLoader v-bind="$props" />'
36
+ });
37
+
38
+ export const Default = Template.bind({});
39
+ Default.args = {};
40
+
41
+ export const Sizes = () => ({
42
+ components: { FLoader },
43
+ template: `
44
+ <div class="flex items-center gap-6">
45
+ <div class="text-center">
46
+ <FLoader size="xs" />
47
+ <p class="text-xs mt-2">xs</p>
48
+ </div>
49
+ <div class="text-center">
50
+ <FLoader size="sm" />
51
+ <p class="text-xs mt-2">sm</p>
52
+ </div>
53
+ <div class="text-center">
54
+ <FLoader size="md" />
55
+ <p class="text-xs mt-2">md</p>
56
+ </div>
57
+ <div class="text-center">
58
+ <FLoader size="lg" />
59
+ <p class="text-xs mt-2">lg</p>
60
+ </div>
61
+ <div class="text-center">
62
+ <FLoader size="xl" />
63
+ <p class="text-xs mt-2">xl</p>
64
+ </div>
65
+ </div>
66
+ `
67
+ });
68
+
69
+ export const Colors = () => ({
70
+ components: { FLoader },
71
+ template: `
72
+ <div class="flex items-center gap-6">
73
+ <FLoader size="lg" />
74
+ <FLoader size="lg" color="#ef4444" />
75
+ <FLoader size="lg" color="#22c55e" />
76
+ <FLoader size="lg" color="#f59e0b" />
77
+ <FLoader size="lg" color="#8b5cf6" />
78
+ </div>
79
+ `
80
+ });
81
+
82
+ export const Centered = () => ({
83
+ components: { FLoader },
84
+ template: `
85
+ <div class="relative h-40 border border-dashed border-neutral-300 rounded-lg">
86
+ <FLoader size="lg" centered />
87
+ </div>
88
+ `
89
+ });
90
+
91
+ export const WithText = () => ({
92
+ components: { FLoader },
93
+ template: `
94
+ <div class="flex items-center gap-2">
95
+ <FLoader size="sm" />
96
+ <span class="text-sm text-neutral-600">Chargement en cours...</span>
97
+ </div>
98
+ `
99
+ });
100
+
101
+ export const InButton = () => ({
102
+ components: { FLoader },
103
+ template: `
104
+ <button class="inline-flex items-center gap-2 px-4 py-2 bg-primary-600 text-white rounded-md opacity-75 cursor-wait">
105
+ <FLoader size="sm" color="white" />
106
+ <span>Envoi...</span>
107
+ </button>
108
+ `
109
+ });
@@ -0,0 +1,66 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { mount } from '@vue/test-utils';
3
+ import FLoader from './FLoader.vue';
4
+
5
+ describe('FLoader', () => {
6
+ it('renders correctly with default props', () => {
7
+ const wrapper = mount(FLoader);
8
+ expect(wrapper.find('[role="status"]').exists()).toBe(true);
9
+ });
10
+
11
+ it('renders SVG spinner', () => {
12
+ const wrapper = mount(FLoader);
13
+ expect(wrapper.find('svg').exists()).toBe(true);
14
+ expect(wrapper.find('svg').classes()).toContain('animate-spin');
15
+ });
16
+
17
+ it('applies correct size classes', () => {
18
+ const sizes = ['xs', 'sm', 'md', 'lg', 'xl'] as const;
19
+
20
+ sizes.forEach((size) => {
21
+ const wrapper = mount(FLoader, {
22
+ propsData: { size }
23
+ });
24
+ expect(wrapper.find('svg').exists()).toBe(true);
25
+ });
26
+ });
27
+
28
+ it('applies custom color', () => {
29
+ const wrapper = mount(FLoader, {
30
+ propsData: { color: 'red' }
31
+ });
32
+ expect(wrapper.find('svg').attributes('style')).toContain('color: red');
33
+ });
34
+
35
+ it('renders overlay when overlay prop is true', () => {
36
+ const wrapper = mount(FLoader, {
37
+ propsData: { overlay: true }
38
+ });
39
+ expect(wrapper.classes()).toContain('fixed');
40
+ expect(wrapper.classes()).toContain('inset-0');
41
+ });
42
+
43
+ it('applies centered class when centered prop is true', () => {
44
+ const wrapper = mount(FLoader, {
45
+ propsData: { centered: true }
46
+ });
47
+ const container = wrapper.find('[role="status"]');
48
+ expect(container.classes()).toContain('absolute');
49
+ });
50
+
51
+ it('has correct aria-label', () => {
52
+ const wrapper = mount(FLoader);
53
+ expect(wrapper.find('[role="status"]').attributes('aria-label')).toBe(
54
+ 'Chargement en cours'
55
+ );
56
+ });
57
+
58
+ it('accepts custom aria-label', () => {
59
+ const wrapper = mount(FLoader, {
60
+ propsData: { label: 'Loading data...' }
61
+ });
62
+ expect(wrapper.find('[role="status"]').attributes('aria-label')).toBe(
63
+ 'Loading data...'
64
+ );
65
+ });
66
+ });