@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,104 @@
1
+ import FDivider from './FDivider.vue';
2
+
3
+ export default {
4
+ title: 'Atoms/FDivider',
5
+ component: FDivider,
6
+ tags: ['autodocs'],
7
+ argTypes: {
8
+ orientation: {
9
+ control: { type: 'select' },
10
+ options: ['horizontal', 'vertical'],
11
+ description: 'Orientation du séparateur'
12
+ },
13
+ align: {
14
+ control: { type: 'select' },
15
+ options: ['left', 'center', 'right'],
16
+ description: 'Alignement du texte'
17
+ },
18
+ margin: {
19
+ control: { type: 'select' },
20
+ options: ['none', 'sm', 'md', 'lg'],
21
+ description: 'Marge autour du séparateur'
22
+ },
23
+ thickness: {
24
+ control: { type: 'select' },
25
+ options: ['thin', 'medium', 'thick'],
26
+ description: 'Épaisseur de la ligne'
27
+ }
28
+ }
29
+ };
30
+
31
+ const Template = (args, { argTypes }) => ({
32
+ components: { FDivider },
33
+ props: Object.keys(argTypes),
34
+ template: '<FDivider v-bind="$props" />'
35
+ });
36
+
37
+ export const Default = Template.bind({});
38
+ Default.args = {};
39
+
40
+ export const WithText = () => ({
41
+ components: { FDivider },
42
+ template: '<FDivider>OU</FDivider>'
43
+ });
44
+
45
+ export const Alignments = () => ({
46
+ components: { FDivider },
47
+ template: `
48
+ <div class="flex flex-col gap-4">
49
+ <FDivider align="left">Gauche</FDivider>
50
+ <FDivider align="center">Centre</FDivider>
51
+ <FDivider align="right">Droite</FDivider>
52
+ </div>
53
+ `
54
+ });
55
+
56
+ export const Thickness = () => ({
57
+ components: { FDivider },
58
+ template: `
59
+ <div class="flex flex-col gap-4">
60
+ <p class="text-sm text-neutral-500">Fin</p>
61
+ <FDivider thickness="thin" />
62
+ <p class="text-sm text-neutral-500">Moyen</p>
63
+ <FDivider thickness="medium" />
64
+ <p class="text-sm text-neutral-500">Épais</p>
65
+ <FDivider thickness="thick" />
66
+ </div>
67
+ `
68
+ });
69
+
70
+ export const Margins = () => ({
71
+ components: { FDivider },
72
+ template: `
73
+ <div class="flex flex-col">
74
+ <p class="text-sm">Contenu au-dessus</p>
75
+ <FDivider margin="none">Sans marge</FDivider>
76
+ <FDivider margin="sm">Petite marge</FDivider>
77
+ <FDivider margin="md">Marge moyenne</FDivider>
78
+ <FDivider margin="lg">Grande marge</FDivider>
79
+ <p class="text-sm">Contenu en dessous</p>
80
+ </div>
81
+ `
82
+ });
83
+
84
+ export const Vertical = () => ({
85
+ components: { FDivider },
86
+ template: `
87
+ <div class="flex items-center h-20">
88
+ <span>Gauche</span>
89
+ <FDivider orientation="vertical" margin="md" />
90
+ <span>Droite</span>
91
+ </div>
92
+ `
93
+ });
94
+
95
+ export const VerticalWithText = () => ({
96
+ components: { FDivider },
97
+ template: `
98
+ <div class="flex items-center h-32">
99
+ <span>Gauche</span>
100
+ <FDivider orientation="vertical" margin="md">OU</FDivider>
101
+ <span>Droite</span>
102
+ </div>
103
+ `
104
+ });
@@ -0,0 +1,80 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { mount } from '@vue/test-utils';
3
+ import FDivider from './FDivider.vue';
4
+
5
+ describe('FDivider', () => {
6
+ it('renders correctly with default props', () => {
7
+ const wrapper = mount(FDivider);
8
+ expect(wrapper.find('[role="separator"]').exists()).toBe(true);
9
+ });
10
+
11
+ it('renders horizontal by default', () => {
12
+ const wrapper = mount(FDivider);
13
+ expect(wrapper.attributes('aria-orientation')).toBe('horizontal');
14
+ });
15
+
16
+ it('renders vertical when specified', () => {
17
+ const wrapper = mount(FDivider, {
18
+ propsData: { orientation: 'vertical' }
19
+ });
20
+ expect(wrapper.attributes('aria-orientation')).toBe('vertical');
21
+ });
22
+
23
+ it('displays content in slot', () => {
24
+ const wrapper = mount(FDivider, {
25
+ slots: {
26
+ default: 'OR'
27
+ }
28
+ });
29
+ expect(wrapper.text()).toContain('OR');
30
+ });
31
+
32
+ it('renders full line when no content', () => {
33
+ const wrapper = mount(FDivider);
34
+ // Should have one full-width line element
35
+ const spans = wrapper.findAll('span');
36
+ expect(spans.length).toBe(1);
37
+ });
38
+
39
+ it('renders two line segments when content is present', () => {
40
+ const wrapper = mount(FDivider, {
41
+ slots: {
42
+ default: 'Text'
43
+ }
44
+ });
45
+ // Should have start line, text, and end line
46
+ const spans = wrapper.findAll('span');
47
+ expect(spans.length).toBe(3);
48
+ });
49
+
50
+ it('applies correct alignment classes', () => {
51
+ const alignments = ['left', 'center', 'right'] as const;
52
+ alignments.forEach((align) => {
53
+ const wrapper = mount(FDivider, {
54
+ propsData: { align },
55
+ slots: { default: 'Text' }
56
+ });
57
+ expect(wrapper.exists()).toBe(true);
58
+ });
59
+ });
60
+
61
+ it('applies margin classes based on margin prop', () => {
62
+ const margins = ['none', 'sm', 'md', 'lg'] as const;
63
+ margins.forEach((margin) => {
64
+ const wrapper = mount(FDivider, {
65
+ propsData: { margin }
66
+ });
67
+ expect(wrapper.exists()).toBe(true);
68
+ });
69
+ });
70
+
71
+ it('applies thickness classes', () => {
72
+ const thicknesses = ['thin', 'medium', 'thick'] as const;
73
+ thicknesses.forEach((thickness) => {
74
+ const wrapper = mount(FDivider, {
75
+ propsData: { thickness }
76
+ });
77
+ expect(wrapper.exists()).toBe(true);
78
+ });
79
+ });
80
+ });
@@ -0,0 +1,117 @@
1
+ <template>
2
+ <div
3
+ role="separator"
4
+ :aria-orientation="orientation"
5
+ :class="containerClasses"
6
+ >
7
+ <template v-if="hasContent">
8
+ <span :class="lineClasses('start')"></span>
9
+ <span :class="textClasses">
10
+ <slot />
11
+ </span>
12
+ <span :class="lineClasses('end')"></span>
13
+ </template>
14
+ <span v-else :class="lineClasses('full')"></span>
15
+ </div>
16
+ </template>
17
+
18
+ <script>
19
+ export default {
20
+ name: 'FDivider',
21
+ props: {
22
+ orientation: {
23
+ type: String,
24
+ default: 'horizontal',
25
+ validator: (v) => ['horizontal', 'vertical'].includes(v)
26
+ },
27
+ align: {
28
+ type: String,
29
+ default: 'center',
30
+ validator: (v) => ['left', 'center', 'right'].includes(v)
31
+ },
32
+ color: {
33
+ type: String,
34
+ default: 'gray-300'
35
+ },
36
+ textColor: {
37
+ type: String,
38
+ default: 'gray-500'
39
+ },
40
+ textSize: {
41
+ type: String,
42
+ default: 'sm'
43
+ },
44
+ margin: {
45
+ type: String,
46
+ default: 'md',
47
+ validator: (v) => ['none', 'sm', 'md', 'lg'].includes(v)
48
+ },
49
+ thickness: {
50
+ type: String,
51
+ default: 'thin',
52
+ validator: (v) => ['thin', 'medium', 'thick'].includes(v)
53
+ }
54
+ },
55
+ computed: {
56
+ hasContent() {
57
+ return !!this.$slots.default;
58
+ },
59
+ isVertical() {
60
+ return this.orientation === 'vertical';
61
+ },
62
+ containerClasses() {
63
+ const margins = {
64
+ none: '',
65
+ sm: this.isVertical ? 'mx-2' : 'my-2',
66
+ md: this.isVertical ? 'mx-4' : 'my-4',
67
+ lg: this.isVertical ? 'mx-6' : 'my-6'
68
+ };
69
+
70
+ return [
71
+ 'flex items-center',
72
+ this.isVertical ? 'flex-col h-full' : 'flex-row w-full',
73
+ margins[this.margin]
74
+ ];
75
+ },
76
+ baseLineClasses() {
77
+ const thicknessMap = {
78
+ thin: 'px',
79
+ medium: '0.5',
80
+ thick: '1'
81
+ };
82
+ const size = thicknessMap[this.thickness];
83
+
84
+ return [`bg-${this.color}`, this.isVertical ? `w-${size}` : `h-${size}`];
85
+ },
86
+ textClasses() {
87
+ return [
88
+ 'font-sans',
89
+ `text-${this.textSize}`,
90
+ `text-${this.textColor}`,
91
+ this.isVertical ? 'py-2' : 'px-3'
92
+ ];
93
+ }
94
+ },
95
+ methods: {
96
+ lineClasses(position) {
97
+ if (position === 'full') {
98
+ return [this.isVertical ? 'h-full' : 'w-full', ...this.baseLineClasses];
99
+ }
100
+
101
+ const offset = this.isVertical ? 'h-4' : 'w-4';
102
+ const grow = 'flex-1';
103
+ const fixed = `flex-none ${offset}`;
104
+
105
+ let sizing = grow;
106
+
107
+ if (this.align === 'left') {
108
+ sizing = position === 'start' ? fixed : grow;
109
+ } else if (this.align === 'right') {
110
+ sizing = position === 'start' ? grow : fixed;
111
+ }
112
+
113
+ return [sizing, ...this.baseLineClasses];
114
+ }
115
+ }
116
+ };
117
+ </script>
@@ -0,0 +1,189 @@
1
+ import FIcon from './FIcon.vue';
2
+
3
+ export default {
4
+ title: 'Atoms/FIcon',
5
+ component: FIcon,
6
+ tags: ['autodocs'],
7
+ argTypes: {
8
+ name: {
9
+ control: 'text',
10
+ description: "Nom de l'icône"
11
+ },
12
+ size: {
13
+ control: { type: 'select' },
14
+ options: ['xs', 'sm', 'md', 'lg', 'xl'],
15
+ description: "Taille de l'icône"
16
+ },
17
+ color: {
18
+ control: 'color',
19
+ description: "Couleur de l'icône"
20
+ },
21
+ decorative: {
22
+ control: 'boolean',
23
+ description: "Icône décorative (masquée aux lecteurs d'écran)"
24
+ },
25
+ label: {
26
+ control: 'text',
27
+ description: "Label pour l'accessibilité"
28
+ }
29
+ }
30
+ };
31
+
32
+ const Template = (args, { argTypes }) => ({
33
+ components: { FIcon },
34
+ props: Object.keys(argTypes),
35
+ template: '<FIcon v-bind="$props" />'
36
+ });
37
+
38
+ export const Default = Template.bind({});
39
+ Default.args = {
40
+ name: 'check'
41
+ };
42
+
43
+ export const Sizes = () => ({
44
+ components: { FIcon },
45
+ template: `
46
+ <div class="flex items-center gap-4">
47
+ <FIcon name="star" size="xs" />
48
+ <FIcon name="star" size="sm" />
49
+ <FIcon name="star" size="md" />
50
+ <FIcon name="star" size="lg" />
51
+ <FIcon name="star" size="xl" />
52
+ </div>
53
+ `
54
+ });
55
+
56
+ export const Colors = () => ({
57
+ components: { FIcon },
58
+ template: `
59
+ <div class="flex items-center gap-4">
60
+ <FIcon name="heart" size="lg" color="#ef4444" />
61
+ <FIcon name="star" size="lg" color="#f59e0b" />
62
+ <FIcon name="check" size="lg" color="#22c55e" />
63
+ <FIcon name="info" size="lg" color="#3b82f6" />
64
+ </div>
65
+ `
66
+ });
67
+
68
+ export const NavigationIcons = () => ({
69
+ components: { FIcon },
70
+ template: `
71
+ <div class="flex items-center gap-4">
72
+ <FIcon name="chevron-up" size="md" />
73
+ <FIcon name="chevron-down" size="md" />
74
+ <FIcon name="chevron-left" size="md" />
75
+ <FIcon name="chevron-right" size="md" />
76
+ <FIcon name="arrow-up" size="md" />
77
+ <FIcon name="arrow-down" size="md" />
78
+ <FIcon name="arrow-left" size="md" />
79
+ <FIcon name="arrow-right" size="md" />
80
+ </div>
81
+ `
82
+ });
83
+
84
+ export const ActionIcons = () => ({
85
+ components: { FIcon },
86
+ template: `
87
+ <div class="flex items-center gap-4">
88
+ <FIcon name="check" size="md" />
89
+ <FIcon name="x" size="md" />
90
+ <FIcon name="plus" size="md" />
91
+ <FIcon name="minus" size="md" />
92
+ <FIcon name="search" size="md" />
93
+ <FIcon name="edit" size="md" />
94
+ <FIcon name="trash" size="md" />
95
+ <FIcon name="copy" size="md" />
96
+ </div>
97
+ `
98
+ });
99
+
100
+ export const StatusIcons = () => ({
101
+ components: { FIcon },
102
+ template: `
103
+ <div class="flex items-center gap-4">
104
+ <FIcon name="info" size="md" color="#3b82f6" />
105
+ <FIcon name="warning" size="md" color="#f59e0b" />
106
+ <FIcon name="error" size="md" color="#ef4444" />
107
+ <FIcon name="success" size="md" color="#22c55e" />
108
+ <FIcon name="question" size="md" color="#6b7280" />
109
+ </div>
110
+ `
111
+ });
112
+
113
+ export const CommonUIIcons = () => ({
114
+ components: { FIcon },
115
+ template: `
116
+ <div class="flex items-center gap-4">
117
+ <FIcon name="user" size="md" />
118
+ <FIcon name="home" size="md" />
119
+ <FIcon name="cog" size="md" />
120
+ <FIcon name="bell" size="md" />
121
+ <FIcon name="mail" size="md" />
122
+ <FIcon name="calendar" size="md" />
123
+ <FIcon name="clock" size="md" />
124
+ <FIcon name="folder" size="md" />
125
+ <FIcon name="document" size="md" />
126
+ </div>
127
+ `
128
+ });
129
+
130
+ export const AllIcons = () => ({
131
+ components: { FIcon },
132
+ template: `
133
+ <div class="grid grid-cols-8 gap-4">
134
+ <div v-for="icon in icons" :key="icon" class="flex flex-col items-center gap-2 p-2">
135
+ <FIcon :name="icon" size="md" />
136
+ <span class="text-xs text-neutral-500">{{ icon }}</span>
137
+ </div>
138
+ </div>
139
+ `,
140
+ data() {
141
+ return {
142
+ icons: [
143
+ 'chevron-up',
144
+ 'chevron-down',
145
+ 'chevron-left',
146
+ 'chevron-right',
147
+ 'arrow-up',
148
+ 'arrow-down',
149
+ 'arrow-left',
150
+ 'arrow-right',
151
+ 'check',
152
+ 'x',
153
+ 'plus',
154
+ 'minus',
155
+ 'search',
156
+ 'menu',
157
+ 'close',
158
+ 'refresh',
159
+ 'edit',
160
+ 'trash',
161
+ 'copy',
162
+ 'info',
163
+ 'warning',
164
+ 'error',
165
+ 'success',
166
+ 'question',
167
+ 'user',
168
+ 'home',
169
+ 'cog',
170
+ 'bell',
171
+ 'heart',
172
+ 'star',
173
+ 'eye',
174
+ 'eye-off',
175
+ 'lock',
176
+ 'unlock',
177
+ 'mail',
178
+ 'calendar',
179
+ 'clock',
180
+ 'download',
181
+ 'upload',
182
+ 'link',
183
+ 'external-link',
184
+ 'folder',
185
+ 'document'
186
+ ]
187
+ };
188
+ }
189
+ });
@@ -0,0 +1,99 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { mount } from '@vue/test-utils';
3
+ import FIcon from './FIcon.vue';
4
+
5
+ describe('FIcon', () => {
6
+ it('renders correctly with default props', () => {
7
+ const wrapper = mount(FIcon);
8
+ expect(wrapper.find('span').exists()).toBe(true);
9
+ });
10
+
11
+ it('renders SVG for known icon names', () => {
12
+ const wrapper = mount(FIcon, {
13
+ propsData: { name: 'check' }
14
+ });
15
+ expect(wrapper.find('svg').exists()).toBe(true);
16
+ });
17
+
18
+ it('renders placeholder for unknown icon names', () => {
19
+ const wrapper = mount(FIcon, {
20
+ propsData: { name: 'unknown-icon-xyz' }
21
+ });
22
+ expect(wrapper.find('svg').exists()).toBe(true);
23
+ });
24
+
25
+ it('applies correct size classes', () => {
26
+ const sizes = ['xs', 'sm', 'md', 'lg', 'xl'] as const;
27
+
28
+ sizes.forEach((size) => {
29
+ const wrapper = mount(FIcon, {
30
+ propsData: { name: 'check', size }
31
+ });
32
+ expect(wrapper.exists()).toBe(true);
33
+ });
34
+ });
35
+
36
+ it('applies custom color', () => {
37
+ const wrapper = mount(FIcon, {
38
+ propsData: { name: 'check', color: 'red' }
39
+ });
40
+ const style = wrapper.attributes('style');
41
+ expect(style).toContain('color');
42
+ });
43
+
44
+ it('is decorative by default (aria-hidden)', () => {
45
+ const wrapper = mount(FIcon, {
46
+ propsData: { name: 'check' }
47
+ });
48
+ expect(wrapper.attributes('aria-hidden')).toBe('true');
49
+ });
50
+
51
+ it('shows aria-label when not decorative', () => {
52
+ const wrapper = mount(FIcon, {
53
+ propsData: { name: 'check', decorative: false, label: 'Checkmark' }
54
+ });
55
+ expect(wrapper.attributes('aria-label')).toBe('Checkmark');
56
+ });
57
+
58
+ it('renders slot content instead of default icon', () => {
59
+ const wrapper = mount(FIcon, {
60
+ slots: {
61
+ default: '<svg data-test="custom"></svg>'
62
+ }
63
+ });
64
+ expect(wrapper.find('[data-test="custom"]').exists()).toBe(true);
65
+ });
66
+
67
+ it('renders navigation icons correctly', () => {
68
+ const navIcons = [
69
+ 'chevron-up',
70
+ 'chevron-down',
71
+ 'chevron-left',
72
+ 'chevron-right'
73
+ ];
74
+ navIcons.forEach((name) => {
75
+ const wrapper = mount(FIcon, {
76
+ propsData: { name }
77
+ });
78
+ expect(wrapper.find('svg').exists()).toBe(true);
79
+ });
80
+ });
81
+
82
+ it('renders action icons correctly', () => {
83
+ const actionIcons = [
84
+ 'check',
85
+ 'x',
86
+ 'plus',
87
+ 'minus',
88
+ 'search',
89
+ 'edit',
90
+ 'trash'
91
+ ];
92
+ actionIcons.forEach((name) => {
93
+ const wrapper = mount(FIcon, {
94
+ propsData: { name }
95
+ });
96
+ expect(wrapper.find('svg').exists()).toBe(true);
97
+ });
98
+ });
99
+ });