@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,180 @@
1
+ <template>
2
+ <div :class="containerClasses">
3
+ <div :class="inputWrapperClasses">
4
+ <f-icon
5
+ v-if="iconPosition === 'inside' && !buttonMode"
6
+ name="search"
7
+ :size="iconSize"
8
+ :class="insideIconClasses"
9
+ />
10
+ <input
11
+ ref="input"
12
+ :class="inputClasses"
13
+ type="text"
14
+ :value="value"
15
+ :placeholder="placeholder"
16
+ :disabled="disabled"
17
+ @input="handleInput"
18
+ @keydown.enter="handleSubmit"
19
+ @focus="$emit('focus', $event)"
20
+ @blur="$emit('blur', $event)"
21
+ />
22
+ </div>
23
+ <f-button
24
+ v-if="buttonMode"
25
+ :size="size"
26
+ :disabled="disabled"
27
+ type="button"
28
+ @click="handleSubmit"
29
+ >
30
+ {{ buttonLabel }}
31
+ </f-button>
32
+ <button
33
+ v-else-if="iconPosition === 'outside'"
34
+ :class="iconButtonClasses"
35
+ :disabled="disabled"
36
+ type="button"
37
+ @click="handleSubmit"
38
+ >
39
+ <f-icon name="search" :size="iconSize" />
40
+ <span class="sr-only">{{ buttonLabel }}</span>
41
+ </button>
42
+ </div>
43
+ </template>
44
+
45
+ <script>
46
+ import FIcon from '../../atoms/FIcon/FIcon.vue';
47
+ import FButton from '../../atoms/FButton/FButton.vue';
48
+
49
+ export default {
50
+ name: 'FSearchBar',
51
+ components: {
52
+ FIcon,
53
+ FButton
54
+ },
55
+ props: {
56
+ value: {
57
+ type: [String, Number],
58
+ default: ''
59
+ },
60
+ placeholder: {
61
+ type: String,
62
+ default: 'Rechercher...'
63
+ },
64
+ size: {
65
+ type: String,
66
+ default: 'medium',
67
+ validator: (value) => ['small', 'medium', 'large'].includes(value)
68
+ },
69
+ iconPosition: {
70
+ type: String,
71
+ default: 'inside',
72
+ validator: (value) => ['inside', 'outside'].includes(value)
73
+ },
74
+ buttonMode: {
75
+ type: Boolean,
76
+ default: false
77
+ },
78
+ buttonLabel: {
79
+ type: String,
80
+ default: 'Rechercher'
81
+ },
82
+ disabled: {
83
+ type: Boolean,
84
+ default: false
85
+ }
86
+ },
87
+ computed: {
88
+ containerClasses() {
89
+ return 'flex items-center gap-2';
90
+ },
91
+ inputWrapperClasses() {
92
+ return 'relative flex-1';
93
+ },
94
+ inputClasses() {
95
+ const baseClasses =
96
+ 'block w-full font-sans border rounded transition-all duration-200 box-border focus:outline-none focus:ring-2 border-neutral-300 focus:border-primary-500 focus:ring-primary-500/20';
97
+
98
+ const sizeClasses = {
99
+ small: 'py-1.5 px-2.5 text-xs',
100
+ medium: 'py-2.5 px-3.5 text-sm',
101
+ large: 'py-3.5 px-4.5 text-base'
102
+ };
103
+
104
+ const paddingLeftClasses = {
105
+ small: 'pl-8',
106
+ medium: 'pl-10',
107
+ large: 'pl-12'
108
+ };
109
+
110
+ const disabledClasses = this.disabled
111
+ ? 'bg-neutral-100 cursor-not-allowed opacity-70'
112
+ : '';
113
+
114
+ const hasInsideIcon = this.iconPosition === 'inside' && !this.buttonMode;
115
+
116
+ return [
117
+ baseClasses,
118
+ sizeClasses[this.size],
119
+ hasInsideIcon ? paddingLeftClasses[this.size] : '',
120
+ disabledClasses
121
+ ]
122
+ .filter(Boolean)
123
+ .join(' ');
124
+ },
125
+ iconButtonClasses() {
126
+ const baseClasses =
127
+ 'inline-flex items-center justify-center rounded transition-all duration-200 text-neutral-500 hover:text-primary-500 hover:bg-primary-50 focus:outline-none focus:ring-2 focus:ring-primary-500/20';
128
+
129
+ const sizeClasses = {
130
+ small: 'p-1.5',
131
+ medium: 'p-2.5',
132
+ large: 'p-3.5'
133
+ };
134
+
135
+ const disabledClasses = this.disabled
136
+ ? 'opacity-50 cursor-not-allowed'
137
+ : 'cursor-pointer';
138
+
139
+ return [baseClasses, sizeClasses[this.size], disabledClasses]
140
+ .filter(Boolean)
141
+ .join(' ');
142
+ },
143
+ iconSize() {
144
+ const sizeMap = {
145
+ small: 'sm',
146
+ medium: 'md',
147
+ large: 'lg'
148
+ };
149
+ return sizeMap[this.size];
150
+ },
151
+ insideIconClasses() {
152
+ const baseClasses =
153
+ 'absolute top-1/2 -translate-y-1/2 text-neutral-400 pointer-events-none';
154
+
155
+ const leftPositionClasses = {
156
+ small: 'left-2.5',
157
+ medium: 'left-3',
158
+ large: 'left-4'
159
+ };
160
+
161
+ return [baseClasses, leftPositionClasses[this.size]]
162
+ .filter(Boolean)
163
+ .join(' ');
164
+ }
165
+ },
166
+ methods: {
167
+ handleInput(event) {
168
+ this.$emit('input', event.target.value);
169
+ },
170
+ handleSubmit() {
171
+ if (!this.disabled) {
172
+ this.$emit('search', this.value);
173
+ }
174
+ },
175
+ focus() {
176
+ this.$refs.input.focus();
177
+ }
178
+ }
179
+ };
180
+ </script>
@@ -0,0 +1,333 @@
1
+ import FSelect from './FSelect.vue';
2
+
3
+ export default {
4
+ title: 'Molecules/FSelect',
5
+ component: FSelect,
6
+ tags: ['autodocs'],
7
+ argTypes: {
8
+ value: {
9
+ control: 'object',
10
+ description: 'Valeur sélectionnée (v-model)'
11
+ },
12
+ options: {
13
+ control: 'object',
14
+ description: 'Liste des options'
15
+ },
16
+ optionKey: {
17
+ control: 'text',
18
+ description: 'Clé pour identifier une option (si options sont des objets)'
19
+ },
20
+ optionLabel: {
21
+ control: 'text',
22
+ description: "Clé pour le label d'une option (si options sont des objets)"
23
+ },
24
+ optionDisabled: {
25
+ control: 'text',
26
+ description: 'Clé pour désactiver une option (si options sont des objets)'
27
+ },
28
+ placeholder: {
29
+ control: 'text',
30
+ description: "Texte affiché quand aucune valeur n'est sélectionnée"
31
+ },
32
+ size: {
33
+ control: { type: 'select' },
34
+ options: ['small', 'medium', 'large'],
35
+ description: 'Taille du composant'
36
+ },
37
+ multiple: {
38
+ control: 'boolean',
39
+ description: 'Activer la sélection multiple'
40
+ },
41
+ searchable: {
42
+ control: 'boolean',
43
+ description: 'Activer le champ de recherche'
44
+ },
45
+ searchPlaceholder: {
46
+ control: 'text',
47
+ description: 'Placeholder du champ de recherche'
48
+ },
49
+ emptyText: {
50
+ control: 'text',
51
+ description:
52
+ 'Texte affiché quand aucune option ne correspond à la recherche'
53
+ },
54
+ loading: {
55
+ control: 'boolean',
56
+ description: 'État de chargement (pour options asynchrones)'
57
+ },
58
+ loadingText: {
59
+ control: 'text',
60
+ description: 'Texte affiché pendant le chargement'
61
+ },
62
+ disabled: {
63
+ control: 'boolean',
64
+ description: 'État désactivé'
65
+ },
66
+ error: {
67
+ control: 'boolean',
68
+ description: "État d'erreur"
69
+ },
70
+ labelId: {
71
+ control: 'text',
72
+ description: 'ID du label associé (pour accessibilité)'
73
+ }
74
+ }
75
+ };
76
+
77
+ const simpleOptions = [
78
+ 'Option 1',
79
+ 'Option 2',
80
+ 'Option 3',
81
+ 'Option 4',
82
+ 'Option 5'
83
+ ];
84
+
85
+ const objectOptions = [
86
+ { value: 1, label: 'Paris' },
87
+ { value: 2, label: 'Lyon' },
88
+ { value: 3, label: 'Marseille' },
89
+ { value: 4, label: 'Toulouse' },
90
+ { value: 5, label: 'Nice' }
91
+ ];
92
+
93
+ const Template = (args, { argTypes }) => ({
94
+ components: { FSelect },
95
+ props: Object.keys(argTypes),
96
+ data() {
97
+ return {
98
+ selectedValue: args.value || null
99
+ };
100
+ },
101
+ template: '<FSelect v-bind="$props" v-model="selectedValue" />'
102
+ });
103
+
104
+ export const Default = Template.bind({});
105
+ Default.args = {
106
+ options: simpleOptions,
107
+ placeholder: 'Sélectionner une option...'
108
+ };
109
+
110
+ export const WithValue = Template.bind({});
111
+ WithValue.args = {
112
+ options: simpleOptions,
113
+ value: 'Option 2'
114
+ };
115
+
116
+ export const ObjectOptions = Template.bind({});
117
+ ObjectOptions.args = {
118
+ options: objectOptions,
119
+ placeholder: 'Choisir une ville...'
120
+ };
121
+
122
+ export const Searchable = Template.bind({});
123
+ Searchable.args = {
124
+ options: objectOptions,
125
+ searchable: true,
126
+ placeholder: 'Rechercher une ville...'
127
+ };
128
+
129
+ export const Multiple = Template.bind({});
130
+ Multiple.args = {
131
+ options: objectOptions,
132
+ multiple: true,
133
+ value: [],
134
+ placeholder: 'Sélectionner plusieurs villes...'
135
+ };
136
+
137
+ export const SearchableMultiple = Template.bind({});
138
+ SearchableMultiple.args = {
139
+ options: objectOptions,
140
+ multiple: true,
141
+ searchable: true,
142
+ value: [],
143
+ placeholder: 'Rechercher et sélectionner...'
144
+ };
145
+
146
+ export const Sizes = () => ({
147
+ components: { FSelect },
148
+ data() {
149
+ return {
150
+ options: simpleOptions,
151
+ small: null,
152
+ medium: null,
153
+ large: null
154
+ };
155
+ },
156
+ template: `
157
+ <div class="flex flex-col gap-4">
158
+ <FSelect v-model="small" :options="options" size="small" placeholder="Petit" />
159
+ <FSelect v-model="medium" :options="options" size="medium" placeholder="Moyen" />
160
+ <FSelect v-model="large" :options="options" size="large" placeholder="Grand" />
161
+ </div>
162
+ `
163
+ });
164
+
165
+ export const Disabled = Template.bind({});
166
+ Disabled.args = {
167
+ options: simpleOptions,
168
+ disabled: true,
169
+ placeholder: 'Sélection désactivée'
170
+ };
171
+
172
+ export const WithError = Template.bind({});
173
+ WithError.args = {
174
+ options: simpleOptions,
175
+ error: true,
176
+ placeholder: 'Champ avec erreur'
177
+ };
178
+
179
+ export const Loading = Template.bind({});
180
+ Loading.args = {
181
+ options: [],
182
+ loading: true,
183
+ loadingText: 'Chargement des options...'
184
+ };
185
+
186
+ export const AsyncOptions = () => ({
187
+ components: { FSelect },
188
+ data() {
189
+ return {
190
+ selectedValue: null,
191
+ options: [],
192
+ loading: false
193
+ };
194
+ },
195
+ mounted() {
196
+ this.loadOptions();
197
+ },
198
+ methods: {
199
+ loadOptions() {
200
+ this.loading = true;
201
+ // Simuler un appel API
202
+ setTimeout(() => {
203
+ this.options = [
204
+ { value: 1, label: 'Option asynchrone 1' },
205
+ { value: 2, label: 'Option asynchrone 2' },
206
+ { value: 3, label: 'Option asynchrone 3' },
207
+ { value: 4, label: 'Option asynchrone 4' },
208
+ { value: 5, label: 'Option asynchrone 5' }
209
+ ];
210
+ this.loading = false;
211
+ }, 2000);
212
+ }
213
+ },
214
+ template: `
215
+ <FSelect
216
+ v-model="selectedValue"
217
+ :options="options"
218
+ :loading="loading"
219
+ searchable
220
+ placeholder="Options chargées depuis une API..."
221
+ loading-text="Chargement des options..."
222
+ />
223
+ `
224
+ });
225
+
226
+ export const DisabledOptions = () => ({
227
+ components: { FSelect },
228
+ data() {
229
+ return {
230
+ selectedValue: null,
231
+ options: [
232
+ { value: 1, label: 'Option active 1', disabled: false },
233
+ { value: 2, label: 'Option désactivée', disabled: true },
234
+ { value: 3, label: 'Option active 2', disabled: false },
235
+ { value: 4, label: 'Option désactivée 2', disabled: true },
236
+ { value: 5, label: 'Option active 3', disabled: false }
237
+ ]
238
+ };
239
+ },
240
+ template: `
241
+ <FSelect
242
+ v-model="selectedValue"
243
+ :options="options"
244
+ placeholder="Certaines options sont désactivées..."
245
+ />
246
+ `
247
+ });
248
+
249
+ export const LargeList = () => ({
250
+ components: { FSelect },
251
+ data() {
252
+ return {
253
+ selectedValue: null,
254
+ options: Array.from({ length: 100 }, (_, i) => ({
255
+ value: i + 1,
256
+ label: `Option ${i + 1}`
257
+ }))
258
+ };
259
+ },
260
+ template: `
261
+ <FSelect
262
+ v-model="selectedValue"
263
+ :options="options"
264
+ searchable
265
+ placeholder="Liste avec 100 options..."
266
+ />
267
+ `
268
+ });
269
+
270
+ export const CustomFilter = () => ({
271
+ components: { FSelect },
272
+ data() {
273
+ return {
274
+ selectedValue: null,
275
+ options: [
276
+ { value: 1, label: 'JavaScript', category: 'Frontend' },
277
+ { value: 2, label: 'Python', category: 'Backend' },
278
+ { value: 3, label: 'Vue.js', category: 'Frontend' },
279
+ { value: 4, label: 'Node.js', category: 'Backend' },
280
+ { value: 5, label: 'React', category: 'Frontend' }
281
+ ]
282
+ };
283
+ },
284
+ methods: {
285
+ customFilter(query, options) {
286
+ const lowerQuery = query.toLowerCase();
287
+ return options.filter((option) => {
288
+ const labelMatch = option.label.toLowerCase().includes(lowerQuery);
289
+ const categoryMatch = option.category
290
+ .toLowerCase()
291
+ .includes(lowerQuery);
292
+ return labelMatch || categoryMatch;
293
+ });
294
+ }
295
+ },
296
+ template: `
297
+ <FSelect
298
+ v-model="selectedValue"
299
+ :options="options"
300
+ :filter-method="customFilter"
301
+ searchable
302
+ placeholder="Rechercher par nom ou catégorie..."
303
+ />
304
+ `
305
+ });
306
+
307
+ export const States = () => ({
308
+ components: { FSelect },
309
+ data() {
310
+ return {
311
+ options: simpleOptions,
312
+ normal: null,
313
+ disabled: null,
314
+ error: null
315
+ };
316
+ },
317
+ template: `
318
+ <div class="flex flex-col gap-4">
319
+ <div>
320
+ <label class="block text-sm font-medium mb-1">Normal</label>
321
+ <FSelect v-model="normal" :options="options" placeholder="État normal" />
322
+ </div>
323
+ <div>
324
+ <label class="block text-sm font-medium mb-1">Désactivé</label>
325
+ <FSelect v-model="disabled" :options="options" disabled placeholder="État désactivé" />
326
+ </div>
327
+ <div>
328
+ <label class="block text-sm font-medium mb-1">Erreur</label>
329
+ <FSelect v-model="error" :options="options" error placeholder="État erreur" />
330
+ </div>
331
+ </div>
332
+ `
333
+ });