@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.
- package/README.md +119 -0
- package/dist/fabric.cjs.js +18109 -0
- package/dist/fabric.css +2180 -0
- package/dist/fabric.esm.js +18062 -0
- package/dist/fabric.min.js +18112 -0
- package/dist/types/components/atoms/FAvatar/FAvatar.test.d.ts +1 -0
- package/dist/types/components/atoms/FBadge/FBadge.test.d.ts +1 -0
- package/dist/types/components/atoms/FButton/FButton.test.d.ts +1 -0
- package/dist/types/components/atoms/FCheckbox/FCheckbox.test.d.ts +1 -0
- package/dist/types/components/atoms/FDivider/FDivider.test.d.ts +1 -0
- package/dist/types/components/atoms/FIcon/FIcon.test.d.ts +1 -0
- package/dist/types/components/atoms/FInput/FInput.test.d.ts +1 -0
- package/dist/types/components/atoms/FLoader/FLoader.test.d.ts +1 -0
- package/dist/types/components/atoms/FRadio/FRadio.test.d.ts +1 -0
- package/dist/types/components/atoms/FTextarea/FTextarea.test.d.ts +1 -0
- package/dist/types/components/atoms/FToggle/FToggle.test.d.ts +1 -0
- package/dist/types/components/atoms/FTypography/FTypography.test.d.ts +1 -0
- package/dist/types/components/atoms/index.d.ts +13 -0
- package/dist/types/components/molecules/FAccordionItem/FAccordionItem.test.d.ts +1 -0
- package/dist/types/components/molecules/FAlert/FAlert.test.d.ts +1 -0
- package/dist/types/components/molecules/FBreadcrumb/FBreadcrumb.test.d.ts +1 -0
- package/dist/types/components/molecules/FButtonGroup/FButtonGroup.test.d.ts +1 -0
- package/dist/types/components/molecules/FCard/FCard.test.d.ts +1 -0
- package/dist/types/components/molecules/FDatePicker/FDatePicker.test.d.ts +1 -0
- package/dist/types/components/molecules/FEmptyState/FEmptyState.test.d.ts +1 -0
- package/dist/types/components/molecules/FFilePreview/FFilePreview.test.d.ts +1 -0
- package/dist/types/components/molecules/FFormField/FFormField.test.d.ts +1 -0
- package/dist/types/components/molecules/FListItem/FListItem.test.d.ts +1 -0
- package/dist/types/components/molecules/FPagination/FPagination.test.d.ts +1 -0
- package/dist/types/components/molecules/FSearchBar/FSearchBar.test.d.ts +1 -0
- package/dist/types/components/molecules/FSelect/FSelect.test.d.ts +1 -0
- package/dist/types/components/molecules/FStatCard/FStatCard.test.d.ts +1 -0
- package/dist/types/components/molecules/FTabs/FTabs.test.d.ts +1 -0
- package/dist/types/components/molecules/FToast/FToast.test.d.ts +1 -0
- package/dist/types/components/molecules/index.d.ts +18 -0
- package/dist/types/components/organisms/FActivityFeed/FActivityFeed.test.d.ts +1 -0
- package/dist/types/components/organisms/FDataTable/FDataTable.test.d.ts +1 -0
- package/dist/types/components/organisms/FDrawer/FDrawer.test.d.ts +1 -0
- package/dist/types/components/organisms/FFileUpload/FFileUpload.test.d.ts +1 -0
- package/dist/types/components/organisms/FFilterSidebar/FFilterSidebar.test.d.ts +1 -0
- package/dist/types/components/organisms/FForm/FForm.test.d.ts +1 -0
- package/dist/types/components/organisms/FModal/FModal.test.d.ts +1 -0
- package/dist/types/components/organisms/FNavigationSidebar/FNavigationSidebar.test.d.ts +1 -0
- package/dist/types/components/organisms/FOnboardingStepper/FOnboardingStepper.test.d.ts +1 -0
- package/dist/types/components/organisms/FOnboardingStepper/FStepperProgress.test.d.ts +1 -0
- package/dist/types/components/organisms/FPageHeader/FPageHeader.test.d.ts +1 -0
- package/dist/types/components/organisms/FProfileSection/FProfileSection.test.d.ts +1 -0
- package/dist/types/components/organisms/FToastProvider/FToastProvider.test.d.ts +1 -0
- package/dist/types/components/organisms/FUserMenu/FUserMenu.test.d.ts +1 -0
- package/dist/types/components/organisms/index.d.ts +14 -0
- package/dist/types/components/utils/FThemeProvider.test.d.ts +1 -0
- package/dist/types/components/utils/index.d.ts +2 -0
- package/dist/types/components.d.ts +602 -0
- package/dist/types/composables/index.d.ts +12 -0
- package/dist/types/composables/useDataTableState.d.ts +106 -0
- package/dist/types/composables/useDataTableState.test.d.ts +1 -0
- package/dist/types/composables/useFormValidation.d.ts +49 -0
- package/dist/types/composables/useFormValidation.test.d.ts +1 -0
- package/dist/types/composables/useSidebarState.d.ts +65 -0
- package/dist/types/composables/useSidebarState.test.d.ts +1 -0
- package/dist/types/index.d.ts +19 -0
- package/dist/types/types.d.ts +529 -0
- package/package.json +100 -0
- package/src/components/atoms/FAvatar/FAvatar.stories.js +100 -0
- package/src/components/atoms/FAvatar/FAvatar.test.ts +95 -0
- package/src/components/atoms/FAvatar/FAvatar.vue +190 -0
- package/src/components/atoms/FBadge/FBadge.stories.js +129 -0
- package/src/components/atoms/FBadge/FBadge.test.ts +93 -0
- package/src/components/atoms/FBadge/FBadge.vue +103 -0
- package/src/components/atoms/FButton/FButton.stories.js +122 -0
- package/src/components/atoms/FButton/FButton.test.ts +98 -0
- package/src/components/atoms/FButton/FButton.vue +147 -0
- package/src/components/atoms/FCheckbox/FCheckbox.stories.js +96 -0
- package/src/components/atoms/FCheckbox/FCheckbox.test.ts +64 -0
- package/src/components/atoms/FCheckbox/FCheckbox.vue +76 -0
- package/src/components/atoms/FDivider/FDivider.stories.js +104 -0
- package/src/components/atoms/FDivider/FDivider.test.ts +80 -0
- package/src/components/atoms/FDivider/FDivider.vue +117 -0
- package/src/components/atoms/FIcon/FIcon.stories.js +189 -0
- package/src/components/atoms/FIcon/FIcon.test.ts +99 -0
- package/src/components/atoms/FIcon/FIcon.vue +192 -0
- package/src/components/atoms/FInput/FInput.stories.js +119 -0
- package/src/components/atoms/FInput/FInput.test.ts +79 -0
- package/src/components/atoms/FInput/FInput.vue +88 -0
- package/src/components/atoms/FLoader/FLoader.stories.js +109 -0
- package/src/components/atoms/FLoader/FLoader.test.ts +66 -0
- package/src/components/atoms/FLoader/FLoader.vue +97 -0
- package/src/components/atoms/FRadio/FRadio.stories.js +105 -0
- package/src/components/atoms/FRadio/FRadio.test.ts +75 -0
- package/src/components/atoms/FRadio/FRadio.vue +119 -0
- package/src/components/atoms/FTextarea/FTextarea.stories.js +126 -0
- package/src/components/atoms/FTextarea/FTextarea.test.ts +94 -0
- package/src/components/atoms/FTextarea/FTextarea.vue +156 -0
- package/src/components/atoms/FToggle/FToggle.stories.js +108 -0
- package/src/components/atoms/FToggle/FToggle.test.ts +96 -0
- package/src/components/atoms/FToggle/FToggle.vue +123 -0
- package/src/components/atoms/FTypography/FTypography.stories.js +127 -0
- package/src/components/atoms/FTypography/FTypography.test.ts +93 -0
- package/src/components/atoms/FTypography/FTypography.vue +78 -0
- package/src/components/atoms/index.ts +27 -0
- package/src/components/molecules/FAccordionItem/FAccordionItem.stories.js +71 -0
- package/src/components/molecules/FAccordionItem/FAccordionItem.test.ts +61 -0
- package/src/components/molecules/FAccordionItem/FAccordionItem.vue +105 -0
- package/src/components/molecules/FAlert/FAlert.stories.js +87 -0
- package/src/components/molecules/FAlert/FAlert.test.ts +59 -0
- package/src/components/molecules/FAlert/FAlert.vue +108 -0
- package/src/components/molecules/FBreadcrumb/FBreadcrumb.stories.js +90 -0
- package/src/components/molecules/FBreadcrumb/FBreadcrumb.test.ts +76 -0
- package/src/components/molecules/FBreadcrumb/FBreadcrumb.vue +117 -0
- package/src/components/molecules/FButtonGroup/FButtonGroup.stories.js +82 -0
- package/src/components/molecules/FButtonGroup/FButtonGroup.test.ts +44 -0
- package/src/components/molecules/FButtonGroup/FButtonGroup.vue +31 -0
- package/src/components/molecules/FCard/FCard.stories.js +136 -0
- package/src/components/molecules/FCard/FCard.test.ts +87 -0
- package/src/components/molecules/FCard/FCard.vue +75 -0
- package/src/components/molecules/FDatePicker/FDatePicker.stories.js +305 -0
- package/src/components/molecules/FDatePicker/FDatePicker.test.ts +282 -0
- package/src/components/molecules/FDatePicker/FDatePicker.vue +750 -0
- package/src/components/molecules/FEmptyState/FEmptyState.stories.js +98 -0
- package/src/components/molecules/FEmptyState/FEmptyState.test.ts +82 -0
- package/src/components/molecules/FEmptyState/FEmptyState.vue +89 -0
- package/src/components/molecules/FFilePreview/FFilePreview.stories.js +130 -0
- package/src/components/molecules/FFilePreview/FFilePreview.test.ts +70 -0
- package/src/components/molecules/FFilePreview/FFilePreview.vue +125 -0
- package/src/components/molecules/FFormField/FFormField.stories.js +149 -0
- package/src/components/molecules/FFormField/FFormField.test.ts +85 -0
- package/src/components/molecules/FFormField/FFormField.vue +107 -0
- package/src/components/molecules/FListItem/FListItem.stories.js +158 -0
- package/src/components/molecules/FListItem/FListItem.test.ts +93 -0
- package/src/components/molecules/FListItem/FListItem.vue +113 -0
- package/src/components/molecules/FPagination/FPagination.stories.js +132 -0
- package/src/components/molecules/FPagination/FPagination.test.ts +79 -0
- package/src/components/molecules/FPagination/FPagination.vue +206 -0
- package/src/components/molecules/FSearchBar/FSearchBar.stories.js +129 -0
- package/src/components/molecules/FSearchBar/FSearchBar.test.ts +81 -0
- package/src/components/molecules/FSearchBar/FSearchBar.vue +180 -0
- package/src/components/molecules/FSelect/FSelect.stories.js +333 -0
- package/src/components/molecules/FSelect/FSelect.test.ts +478 -0
- package/src/components/molecules/FSelect/FSelect.vue +551 -0
- package/src/components/molecules/FStatCard/FStatCard.stories.js +144 -0
- package/src/components/molecules/FStatCard/FStatCard.test.ts +78 -0
- package/src/components/molecules/FStatCard/FStatCard.vue +106 -0
- package/src/components/molecules/FTabs/FTab.vue +63 -0
- package/src/components/molecules/FTabs/FTabs.stories.js +277 -0
- package/src/components/molecules/FTabs/FTabs.test.ts +264 -0
- package/src/components/molecules/FTabs/FTabs.vue +273 -0
- package/src/components/molecules/FToast/FToast.stories.js +150 -0
- package/src/components/molecules/FToast/FToast.test.ts +157 -0
- package/src/components/molecules/FToast/FToast.vue +283 -0
- package/src/components/molecules/index.ts +37 -0
- package/src/components/organisms/FActivityFeed/FActivityFeed.stories.js +217 -0
- package/src/components/organisms/FActivityFeed/FActivityFeed.test.ts +134 -0
- package/src/components/organisms/FActivityFeed/FActivityFeed.vue +589 -0
- package/src/components/organisms/FDataTable/FDataTable.stories.js +370 -0
- package/src/components/organisms/FDataTable/FDataTable.test.ts +248 -0
- package/src/components/organisms/FDataTable/FDataTable.vue +808 -0
- package/src/components/organisms/FDrawer/FDrawer.stories.js +296 -0
- package/src/components/organisms/FDrawer/FDrawer.test.ts +142 -0
- package/src/components/organisms/FDrawer/FDrawer.vue +303 -0
- package/src/components/organisms/FFileUpload/FFileUpload.stories.js +162 -0
- package/src/components/organisms/FFileUpload/FFileUpload.test.ts +103 -0
- package/src/components/organisms/FFileUpload/FFileUpload.vue +616 -0
- package/src/components/organisms/FFilterSidebar/FFilterSidebar.stories.js +161 -0
- package/src/components/organisms/FFilterSidebar/FFilterSidebar.test.ts +92 -0
- package/src/components/organisms/FFilterSidebar/FFilterSidebar.vue +458 -0
- package/src/components/organisms/FForm/FForm.stories.js +270 -0
- package/src/components/organisms/FForm/FForm.test.ts +63 -0
- package/src/components/organisms/FForm/FForm.vue +19 -0
- package/src/components/organisms/FModal/FModal.stories.js +227 -0
- package/src/components/organisms/FModal/FModal.test.ts +181 -0
- package/src/components/organisms/FModal/FModal.vue +319 -0
- package/src/components/organisms/FNavigationSidebar/FNavigationSidebar.stories.js +176 -0
- package/src/components/organisms/FNavigationSidebar/FNavigationSidebar.test.ts +95 -0
- package/src/components/organisms/FNavigationSidebar/FNavigationSidebar.vue +577 -0
- package/src/components/organisms/FOnboardingStepper/FOnboardingStepper.stories.js +197 -0
- package/src/components/organisms/FOnboardingStepper/FOnboardingStepper.test.ts +114 -0
- package/src/components/organisms/FOnboardingStepper/FOnboardingStepper.vue +212 -0
- package/src/components/organisms/FOnboardingStepper/FStepperProgress.stories.js +122 -0
- package/src/components/organisms/FOnboardingStepper/FStepperProgress.test.ts +130 -0
- package/src/components/organisms/FOnboardingStepper/FStepperProgress.vue +146 -0
- package/src/components/organisms/FPageHeader/FPageHeader.stories.js +142 -0
- package/src/components/organisms/FPageHeader/FPageHeader.test.ts +83 -0
- package/src/components/organisms/FPageHeader/FPageHeader.vue +241 -0
- package/src/components/organisms/FProfileSection/FProfileSection.stories.js +190 -0
- package/src/components/organisms/FProfileSection/FProfileSection.test.ts +85 -0
- package/src/components/organisms/FProfileSection/FProfileSection.vue +562 -0
- package/src/components/organisms/FToastProvider/FToastProvider.stories.js +290 -0
- package/src/components/organisms/FToastProvider/FToastProvider.test.ts +215 -0
- package/src/components/organisms/FToastProvider/FToastProvider.vue +214 -0
- package/src/components/organisms/FUserMenu/FUserMenu.stories.js +170 -0
- package/src/components/organisms/FUserMenu/FUserMenu.test.ts +102 -0
- package/src/components/organisms/FUserMenu/FUserMenu.vue +407 -0
- package/src/components/organisms/index.ts +29 -0
- package/src/components/utils/FThemeProvider.stories.js +236 -0
- package/src/components/utils/FThemeProvider.test.ts +244 -0
- package/src/components/utils/FThemeProvider.vue +191 -0
- package/src/components/utils/index.ts +3 -0
- package/src/components.d.ts +602 -0
- package/src/composables/README.md +233 -0
- package/src/composables/index.ts +25 -0
- package/src/composables/useDataTableState.test.ts +378 -0
- package/src/composables/useDataTableState.ts +361 -0
- package/src/composables/useFormValidation.test.ts +198 -0
- package/src/composables/useFormValidation.ts +178 -0
- package/src/composables/useSidebarState.test.ts +307 -0
- package/src/composables/useSidebarState.ts +201 -0
- package/src/env.d.ts +14 -0
- package/src/index.ts +167 -0
- package/src/styles/tailwind.css +173 -0
- 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
|
+
});
|