@getmicdrop/svelte-components 5.3.12 → 5.3.13

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 (248) hide show
  1. package/dist/calendar/AboutShow/AboutShow.svelte +172 -172
  2. package/dist/calendar/Calendar/MiniMonthCalendar.svelte +782 -782
  3. package/dist/calendar/FAQs/FAQs.svelte +75 -75
  4. package/dist/calendar/MonthSwitcher/MonthSwitcher.svelte +126 -126
  5. package/dist/calendar/OrderSummary/OrderSummary.svelte +367 -367
  6. package/dist/calendar/PublicCard/PublicCard.svelte +145 -145
  7. package/dist/calendar/ShowCard/ShowCard.svelte +157 -157
  8. package/dist/calendar/ShowTimeCard/ShowTimeCard.svelte +61 -61
  9. package/dist/components/Layout/Grid.svelte +109 -109
  10. package/dist/components/Layout/Section.svelte +80 -80
  11. package/dist/components/Layout/Sidebar.svelte +108 -108
  12. package/dist/components/Layout/Stack.svelte +90 -90
  13. package/dist/constants/formOptions.js +26 -26
  14. package/dist/constants/validation.js +91 -91
  15. package/dist/constants/validation.spec.js +64 -64
  16. package/dist/datetime/__tests__/format.test.d.ts +2 -0
  17. package/dist/datetime/__tests__/format.test.d.ts.map +1 -0
  18. package/dist/datetime/__tests__/format.test.js +268 -0
  19. package/dist/datetime/__tests__/integration.test.d.ts +2 -0
  20. package/dist/datetime/__tests__/integration.test.d.ts.map +1 -0
  21. package/dist/datetime/__tests__/integration.test.js +243 -0
  22. package/dist/datetime/__tests__/parse.test.d.ts +2 -0
  23. package/dist/datetime/__tests__/parse.test.d.ts.map +1 -0
  24. package/dist/datetime/__tests__/parse.test.js +261 -0
  25. package/dist/datetime/__tests__/timezone.test.d.ts +2 -0
  26. package/dist/datetime/__tests__/timezone.test.d.ts.map +1 -0
  27. package/dist/datetime/__tests__/timezone.test.js +214 -0
  28. package/dist/datetime/constants.d.ts +133 -0
  29. package/dist/datetime/constants.d.ts.map +1 -0
  30. package/dist/datetime/constants.js +112 -0
  31. package/dist/datetime/format.d.ts +158 -0
  32. package/dist/datetime/format.d.ts.map +1 -0
  33. package/dist/datetime/format.js +315 -0
  34. package/dist/datetime/index.d.ts +42 -0
  35. package/dist/datetime/index.d.ts.map +1 -0
  36. package/dist/datetime/index.js +44 -0
  37. package/dist/datetime/parse.d.ts +149 -0
  38. package/dist/datetime/parse.d.ts.map +1 -0
  39. package/dist/datetime/parse.js +276 -0
  40. package/dist/datetime/timezone.d.ts +95 -0
  41. package/dist/datetime/timezone.d.ts.map +1 -0
  42. package/dist/datetime/timezone.js +241 -0
  43. package/dist/datetime/types.d.ts +105 -0
  44. package/dist/datetime/types.d.ts.map +1 -0
  45. package/dist/datetime/types.js +31 -0
  46. package/dist/index.d.ts +10 -0
  47. package/dist/index.js +232 -218
  48. package/dist/patterns/data/DataGrid.svelte +45 -45
  49. package/dist/patterns/data/DataList.svelte +24 -24
  50. package/dist/patterns/data/DataTable.svelte +40 -40
  51. package/dist/patterns/forms/FormActions.spec.js +88 -88
  52. package/dist/patterns/forms/FormActions.stories.svelte +97 -97
  53. package/dist/patterns/forms/FormActions.svelte +46 -46
  54. package/dist/patterns/forms/FormGrid.svelte +33 -33
  55. package/dist/patterns/forms/FormSection.svelte +32 -32
  56. package/dist/patterns/forms/FormValidationSummary.spec.js +203 -203
  57. package/dist/patterns/forms/FormValidationSummary.stories.svelte +97 -97
  58. package/dist/patterns/forms/FormValidationSummary.svelte +67 -67
  59. package/dist/patterns/layout/Grid.svelte +35 -35
  60. package/dist/patterns/layout/Sidebar.svelte +39 -39
  61. package/dist/patterns/layout/Stack.svelte +45 -45
  62. package/dist/patterns/navigation/BottomNav.spec.js +130 -130
  63. package/dist/patterns/navigation/BottomNav.stories.svelte +117 -117
  64. package/dist/patterns/navigation/BottomNav.svelte +54 -54
  65. package/dist/patterns/navigation/Header.spec.js +203 -203
  66. package/dist/patterns/navigation/Header.stories.svelte +77 -77
  67. package/dist/patterns/navigation/Header.svelte +240 -240
  68. package/dist/patterns/page/PageHeader.svelte +36 -36
  69. package/dist/patterns/page/PageLayout.svelte +40 -40
  70. package/dist/patterns/page/PageLoader.spec.js +54 -54
  71. package/dist/patterns/page/PageLoader.stories.svelte +137 -137
  72. package/dist/patterns/page/PageLoader.svelte +41 -41
  73. package/dist/patterns/page/SectionHeader.svelte +41 -41
  74. package/dist/presets/badges.js +112 -112
  75. package/dist/presets/buttons.js +76 -76
  76. package/dist/presets/index.js +9 -9
  77. package/dist/primitives/Accordion/Accordion.stories.svelte +75 -75
  78. package/dist/primitives/Accordion/Accordion.svelte +61 -61
  79. package/dist/primitives/Accordion/AccordionItem.svelte +95 -95
  80. package/dist/primitives/Alert/Alert.spec.js +170 -170
  81. package/dist/primitives/Alert/Alert.stories.svelte +88 -88
  82. package/dist/primitives/Alert/Alert.svelte +65 -65
  83. package/dist/primitives/Avatar/Avatar.stories.svelte +94 -94
  84. package/dist/primitives/Avatar/Avatar.svelte +66 -66
  85. package/dist/primitives/Badges/Badge.spec.js +103 -103
  86. package/dist/primitives/Badges/Badge.stories.svelte +86 -86
  87. package/dist/primitives/Badges/Badge.svelte +142 -142
  88. package/dist/primitives/BottomSheet/BottomSheet.spec.js +127 -127
  89. package/dist/primitives/BottomSheet/BottomSheet.stories.svelte +83 -83
  90. package/dist/primitives/BottomSheet/BottomSheet.svelte +100 -100
  91. package/dist/primitives/Breadcrumb/Breadcrumb.spec.js +120 -120
  92. package/dist/primitives/Breadcrumb/Breadcrumb.stories.svelte +23 -23
  93. package/dist/primitives/Breadcrumb/Breadcrumb.svelte +89 -89
  94. package/dist/primitives/Button/Button.spec.js +211 -211
  95. package/dist/primitives/Button/Button.stories.svelte +76 -76
  96. package/dist/primitives/Button/Button.svelte +301 -301
  97. package/dist/primitives/Button/ButtonSaveDemo.spec.js +48 -48
  98. package/dist/primitives/Button/ButtonSaveDemo.svelte +25 -25
  99. package/dist/primitives/Button/ButtonVariantShowcase.svelte +129 -129
  100. package/dist/primitives/Card.spec.js +49 -49
  101. package/dist/primitives/Card.stories.svelte +22 -22
  102. package/dist/primitives/Card.svelte +28 -28
  103. package/dist/primitives/Checkbox/Checkbox.stories.svelte +84 -84
  104. package/dist/primitives/Checkbox/Checkbox.svelte +88 -88
  105. package/dist/primitives/DarkModeToggle.spec.js +357 -357
  106. package/dist/primitives/DarkModeToggle.stories.svelte +57 -57
  107. package/dist/primitives/DarkModeToggle.svelte +136 -136
  108. package/dist/primitives/Drawer/Drawer.stories.svelte +100 -100
  109. package/dist/primitives/Drawer/Drawer.svelte +214 -214
  110. package/dist/primitives/Dropdown/Dropdown.stories.svelte +137 -137
  111. package/dist/primitives/Dropdown/Dropdown.svelte +148 -148
  112. package/dist/primitives/Dropdown/DropdownItem.svelte +80 -80
  113. package/dist/primitives/Icons/ArrowLeft.svelte +20 -20
  114. package/dist/primitives/Icons/ArrowRight.svelte +20 -20
  115. package/dist/primitives/Icons/Availability.svelte +26 -26
  116. package/dist/primitives/Icons/Back.svelte +26 -26
  117. package/dist/primitives/Icons/CheckCircle.svelte +18 -18
  118. package/dist/primitives/Icons/CheckCircleOutline.svelte +27 -27
  119. package/dist/primitives/Icons/ChevronLeft.svelte +16 -16
  120. package/dist/primitives/Icons/ChevronRight.svelte +16 -16
  121. package/dist/primitives/Icons/Copy.svelte +27 -27
  122. package/dist/primitives/Icons/Cross.svelte +17 -17
  123. package/dist/primitives/Icons/DownArrow.svelte +20 -20
  124. package/dist/primitives/Icons/ErrorCircle.svelte +18 -18
  125. package/dist/primitives/Icons/FacebookIcon.svelte +13 -13
  126. package/dist/primitives/Icons/Home.svelte +27 -27
  127. package/dist/primitives/Icons/Icon.spec.js +175 -175
  128. package/dist/primitives/Icons/Icon.stories.svelte +100 -100
  129. package/dist/primitives/Icons/Icon.svelte +63 -63
  130. package/dist/primitives/Icons/IconGallery.stories.svelte +235 -235
  131. package/dist/primitives/Icons/ImageOutline.svelte +19 -19
  132. package/dist/primitives/Icons/Info.svelte +19 -19
  133. package/dist/primitives/Icons/InstagramIcon.svelte +19 -19
  134. package/dist/primitives/Icons/LogoInstagram.svelte +15 -15
  135. package/dist/primitives/Icons/Message.svelte +27 -27
  136. package/dist/primitives/Icons/MoonIcon.svelte +16 -16
  137. package/dist/primitives/Icons/More.svelte +33 -33
  138. package/dist/primitives/Icons/MoreHori.spec.js +67 -67
  139. package/dist/primitives/Icons/MoreHori.svelte +34 -34
  140. package/dist/primitives/Icons/Notification.svelte +26 -26
  141. package/dist/primitives/Icons/Payment.svelte +26 -26
  142. package/dist/primitives/Icons/Profile.svelte +33 -33
  143. package/dist/primitives/Icons/Reload.svelte +41 -41
  144. package/dist/primitives/Icons/Shows.svelte +33 -33
  145. package/dist/primitives/Icons/Signout.svelte +33 -33
  146. package/dist/primitives/Icons/SunIcon.svelte +19 -19
  147. package/dist/primitives/Icons/TiktokIcon.svelte +13 -13
  148. package/dist/primitives/Icons/TrashBinOutline.svelte +19 -19
  149. package/dist/primitives/Icons/TwitterIcon.svelte +13 -13
  150. package/dist/primitives/Icons/WarningIcon.spec.js +30 -30
  151. package/dist/primitives/Icons/WarningIcon.svelte +24 -24
  152. package/dist/primitives/Input/Input.spec.js +573 -573
  153. package/dist/primitives/Input/Input.stories.svelte +139 -139
  154. package/dist/primitives/Input/Input.svelte +444 -444
  155. package/dist/primitives/Input/Select.spec.js +218 -218
  156. package/dist/primitives/Input/Select.stories.svelte +112 -112
  157. package/dist/primitives/Input/Select.svelte +232 -232
  158. package/dist/primitives/Input/Textarea.stories.svelte +137 -137
  159. package/dist/primitives/Input/Textarea.svelte +79 -79
  160. package/dist/primitives/Label/Label.svelte +37 -37
  161. package/dist/primitives/Modal/Modal.spec.js +95 -95
  162. package/dist/primitives/Modal/Modal.stories.svelte +86 -86
  163. package/dist/primitives/Modal/Modal.svelte +158 -158
  164. package/dist/primitives/Pagination/Pagination.stories.svelte +76 -76
  165. package/dist/primitives/Pagination/Pagination.svelte +261 -261
  166. package/dist/primitives/Radio/Radio.stories.svelte +80 -80
  167. package/dist/primitives/Radio/Radio.svelte +67 -67
  168. package/dist/primitives/Skeleton/CardPlaceholder.svelte +87 -87
  169. package/dist/primitives/Skeleton/ImagePlaceholder.svelte +59 -59
  170. package/dist/primitives/Skeleton/ListPlaceholder.svelte +76 -76
  171. package/dist/primitives/Skeleton/Skeleton.stories.svelte +151 -151
  172. package/dist/primitives/Skeleton/Skeleton.svelte +52 -52
  173. package/dist/primitives/Spinner/Spinner.spec.js +75 -75
  174. package/dist/primitives/Spinner/Spinner.stories.svelte +29 -29
  175. package/dist/primitives/Spinner/Spinner.svelte +57 -57
  176. package/dist/primitives/Tabs/TabItem.svelte +51 -51
  177. package/dist/primitives/Tabs/Tabs.stories.svelte +112 -112
  178. package/dist/primitives/Tabs/Tabs.svelte +128 -128
  179. package/dist/primitives/Toggle.spec.js +127 -127
  180. package/dist/primitives/Toggle.stories.svelte +92 -92
  181. package/dist/primitives/Toggle.svelte +71 -71
  182. package/dist/primitives/Typography/Typography.svelte +53 -53
  183. package/dist/primitives/ValidationError.spec.js +103 -103
  184. package/dist/primitives/ValidationError.stories.svelte +111 -111
  185. package/dist/primitives/ValidationError.svelte +29 -29
  186. package/dist/recipes/CropImage/CropImage.spec.js +216 -216
  187. package/dist/recipes/CropImage/CropImage.stories.svelte +104 -104
  188. package/dist/recipes/CropImage/CropImage.svelte +238 -238
  189. package/dist/recipes/ImageUploader/ImageUploader.stories.svelte +125 -125
  190. package/dist/recipes/ImageUploader/ImageUploader.svelte +980 -980
  191. package/dist/recipes/Toaster/Toaster.stories.svelte +62 -62
  192. package/dist/recipes/feedback/EmptyState/EmptyState.svelte +47 -47
  193. package/dist/recipes/feedback/ErrorDisplay.spec.js +69 -69
  194. package/dist/recipes/feedback/ErrorDisplay.stories.svelte +112 -112
  195. package/dist/recipes/feedback/ErrorDisplay.svelte +38 -38
  196. package/dist/recipes/feedback/StatusIndicator/StatusIndicator.spec.js +129 -129
  197. package/dist/recipes/feedback/StatusIndicator/StatusIndicator.svelte +167 -167
  198. package/dist/recipes/fields/CheckboxField.svelte +85 -85
  199. package/dist/recipes/fields/FormField.svelte +58 -58
  200. package/dist/recipes/fields/RadioGroup.svelte +95 -95
  201. package/dist/recipes/fields/SelectField.svelte +82 -82
  202. package/dist/recipes/fields/TextareaField.svelte +101 -101
  203. package/dist/recipes/fields/ToggleField.svelte +60 -60
  204. package/dist/recipes/fields/index.js +7 -7
  205. package/dist/recipes/inputs/MultiSelect.spec.js +257 -257
  206. package/dist/recipes/inputs/MultiSelect.stories.svelte +133 -133
  207. package/dist/recipes/inputs/MultiSelect.svelte +244 -244
  208. package/dist/recipes/inputs/OTPInput.spec.js +238 -238
  209. package/dist/recipes/inputs/OTPInput.stories.svelte +162 -162
  210. package/dist/recipes/inputs/OTPInput.svelte +102 -102
  211. package/dist/recipes/inputs/PasswordInput.svelte +100 -100
  212. package/dist/recipes/inputs/PasswordStrengthIndicator/PasswordStrengthIndicator.spec.js +173 -173
  213. package/dist/recipes/inputs/PasswordStrengthIndicator/PasswordStrengthIndicator.svelte +108 -108
  214. package/dist/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.spec.js +300 -300
  215. package/dist/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.stories.svelte +165 -165
  216. package/dist/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.svelte +337 -337
  217. package/dist/recipes/inputs/Search.svelte +85 -85
  218. package/dist/recipes/inputs/SelectDropdown.svelte +161 -161
  219. package/dist/recipes/modals/AlertModal.svelte +130 -130
  220. package/dist/recipes/modals/ConfirmationModal.spec.js +191 -191
  221. package/dist/recipes/modals/ConfirmationModal.stories.svelte +119 -119
  222. package/dist/recipes/modals/ConfirmationModal.svelte +152 -152
  223. package/dist/recipes/modals/InputModal.svelte +182 -182
  224. package/dist/recipes/modals/ModalStateManager.spec.js +100 -100
  225. package/dist/recipes/modals/ModalStateManager.svelte +77 -77
  226. package/dist/recipes/modals/ModalTestWrapper.svelte +65 -65
  227. package/dist/recipes/modals/StatusModal.svelte +206 -206
  228. package/dist/services/EventService.js +75 -75
  229. package/dist/services/EventService.spec.js +217 -217
  230. package/dist/services/ShowService.spec.js +342 -342
  231. package/dist/stores/auth.js +93 -6
  232. package/dist/stores/auth.spec.js +310 -2
  233. package/dist/stores/toaster.js +13 -13
  234. package/dist/stories/ButtonAuditReview.stories.svelte +14 -14
  235. package/dist/stories/ButtonAuditReview.svelte +427 -427
  236. package/dist/stories/PatternsGallery.stories.svelte +19 -19
  237. package/dist/stories/PatternsGallery.svelte +388 -388
  238. package/dist/stories/PrimitivesGallery.stories.svelte +19 -19
  239. package/dist/stories/PrimitivesGallery.svelte +752 -752
  240. package/dist/stories/RecipesGallery.stories.svelte +19 -19
  241. package/dist/stories/RecipesGallery.svelte +441 -441
  242. package/dist/stories/button-audit-manifest.json +11186 -11186
  243. package/dist/tailwind/preset.cjs +82 -82
  244. package/dist/telemetry.js +357 -357
  245. package/dist/tokens/tokens.css +87 -87
  246. package/dist/utils/apiConfig.js +49 -49
  247. package/dist/utils/utils.js +9 -1
  248. package/package.json +233 -191
@@ -1,301 +1,301 @@
1
- <script>
2
- /**
3
- * Button Component - Flowbite Native (Pure Tailwind)
4
- * Migrated to Svelte 5 runes
5
- *
6
- * Variants (Flowbite naming):
7
- * - default: Primary blue button
8
- * - alternative: Gray outline button
9
- * - outline: Blue outline button
10
- * - red: Destructive solid button
11
- * - red-outline: Destructive outline button
12
- * - ghost: Text-only button
13
- * - ghost-red: Destructive text button
14
- * - icon: Icon-only button
15
- * - toggle: Toggle/pill button
16
- * - avatar: Avatar/image trigger button (no padding, opacity hover)
17
- * - menu-item: Dropdown/sheet menu item (full width, left-aligned)
18
- * - menu-item-danger: Destructive menu item (red text)
19
- * - card: Selectable card button (bordered, for list selections)
20
- * - sidebar-toggle: Compact pill for sidebar expand/collapse
21
- *
22
- * Sizes (Flowbite native): xs, sm, md, lg, xl
23
- */
24
- import { CheckOutline } from '../Icons';
25
- import { twMerge } from 'tailwind-merge';
26
-
27
- /** @type {{
28
- variant?: string,
29
- size?: string,
30
- disabled?: boolean,
31
- loading?: boolean,
32
- success?: boolean,
33
- successText?: string,
34
- active?: boolean,
35
- href?: string | null,
36
- type?: 'button' | 'submit' | 'reset',
37
- children?: any,
38
- trailing?: any,
39
- class?: string,
40
- onclick?: (e: MouseEvent) => void,
41
- [key: string]: any
42
- }} */
43
- let {
44
- variant = "default",
45
- size = "md",
46
- disabled = false,
47
- loading = false,
48
- success = false,
49
- successText = "",
50
- active = false,
51
- href = null,
52
- type = "button",
53
- children,
54
- trailing,
55
- class: className = "",
56
- onclick,
57
- ...restProps
58
- } = $props();
59
-
60
- // Legacy variant name mapping
61
- const variantMap = {
62
- "blue-solid": "default",
63
- "gray-outline": "alternative",
64
- "blue-outline": "outline",
65
- "red-solid": "red",
66
- "red-text": "ghost-red",
67
- "gray-text": "ghost",
68
- };
69
-
70
- // Resolve legacy names
71
- let resolvedVariant = $derived(variantMap[variant] || variant);
72
- let effectiveDisabled = $derived(disabled || loading || success);
73
-
74
- // Size classes - Flowbite native sizing
75
- const sizeClasses = {
76
- xs: "px-3 py-1.5 text-xs",
77
- sm: "px-3 py-2 text-sm",
78
- md: "px-4 py-2.5 text-sm",
79
- lg: "px-5 py-3 text-sm",
80
- xl: "px-6 py-3.5 text-sm",
81
- "xl-medium": "w-full px-6 py-3.5 text-sm",
82
- full: "w-full px-5 py-3 text-sm",
83
- "full-md-auto": "w-full px-5 py-3 text-sm md:w-auto",
84
- half: "w-1/2 px-4 py-2.5 text-sm",
85
- };
86
-
87
- // Icon variant sizes
88
- const iconSizes = {
89
- xs: "p-1.5",
90
- sm: "p-2",
91
- md: "p-2.5",
92
- lg: "p-3",
93
- };
94
-
95
- // Avatar variant sizes (no padding, just min dimensions)
96
- const avatarSizes = {
97
- sm: "min-w-8 min-h-8",
98
- md: "min-w-10 min-h-10",
99
- lg: "min-w-12 min-h-12",
100
- };
101
-
102
- // Menu item sizes
103
- const menuItemSizes = {
104
- sm: "py-2 px-4 text-sm",
105
- md: "py-3 px-4 text-sm",
106
- lg: "py-4 px-6 text-base",
107
- nav: "py-2 px-3 text-base font-normal",
108
- };
109
-
110
- // Card sizes (larger padding for card-like buttons)
111
- const cardSizes = {
112
- sm: "p-3 text-sm",
113
- md: "p-4 text-sm",
114
- lg: "p-5 text-base",
115
- };
116
-
117
- // Variant classes with all states in Tailwind (no focus rings - design decision)
118
- const variantClasses = {
119
- default: "text-white bg-blue-700 border border-blue-700 hover:bg-blue-800 dark:bg-blue-600 dark:hover:bg-blue-700",
120
- alternative: "text-gray-900 bg-white border border-gray-200 hover:bg-gray-100 hover:text-blue-700 dark:bg-gray-800 dark:text-white dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700",
121
- outline: "text-blue-700 bg-transparent border border-blue-700 hover:text-white hover:bg-blue-800 dark:border-blue-500 dark:text-blue-500 dark:hover:text-white dark:hover:bg-blue-500",
122
- red: "text-white bg-red-700 border border-red-700 hover:bg-red-800 dark:bg-red-600 dark:hover:bg-red-700",
123
- "red-outline": "text-red-700 bg-transparent border border-red-700 hover:text-white hover:bg-red-800 dark:border-red-500 dark:text-red-500 dark:hover:text-white dark:hover:bg-red-600",
124
- ghost: "text-gray-500 bg-transparent border-transparent hover:bg-gray-100 hover:text-gray-900 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white",
125
- "ghost-red": "text-red-700 bg-transparent border-transparent hover:bg-red-100 hover:text-red-900 dark:text-red-500 dark:hover:bg-red-900/50 dark:hover:text-red-400",
126
- link: "text-blue-700 bg-transparent border-transparent hover:underline dark:text-blue-500",
127
- icon: "text-gray-500 bg-transparent border-transparent hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700",
128
- toggle: "text-gray-500 bg-gray-100 border border-gray-200 hover:bg-gray-200 dark:bg-gray-700 dark:text-gray-400 dark:border-gray-600 dark:hover:bg-gray-600",
129
- success: "text-white bg-green-600 border border-green-600",
130
- // Avatar/image trigger - no background, opacity hover
131
- avatar: "bg-transparent border-transparent hover:opacity-80",
132
- // Menu items - full width, left-aligned, for dropdowns/sheets and sidebar nav
133
- "menu-item": "w-full text-left whitespace-nowrap text-gray-900 bg-transparent border-transparent hover:bg-gray-100 dark:text-white dark:hover:bg-gray-600",
134
- // Danger menu item - red text version
135
- "menu-item-danger": "w-full text-left whitespace-nowrap text-red-600 bg-transparent border-transparent hover:bg-red-50 dark:text-red-500 dark:hover:bg-gray-600",
136
- // Selectable card - bordered card-like button for list selections
137
- card: "w-full text-left text-gray-900 bg-white border border-gray-300 hover:bg-gray-50 dark:bg-gray-800 dark:text-white dark:border-gray-600 dark:hover:bg-gray-700",
138
- // Search result item - blue hover for search dropdowns
139
- "search-result": "w-full text-left text-gray-900 bg-transparent border-transparent hover:bg-blue-50 focus:bg-blue-50 dark:text-white dark:hover:bg-blue-900/20 dark:focus:bg-blue-900/20",
140
- // Sidebar toggle - compact pill for sidebar expand/collapse
141
- "sidebar-toggle": "w-6 h-7 text-gray-900 bg-blue-100 border border-blue-200 hover:bg-blue-200 shadow-lg dark:text-white dark:bg-gray-800 dark:border-gray-700 dark:hover:bg-gray-700",
142
- // Bottom navigation item - vertical layout, transparent, for mobile nav bars
143
- nav: "flex-col h-full py-2 text-gray-500 bg-transparent border-transparent hover:text-blue-600 dark:text-gray-400 dark:hover:text-blue-500",
144
- // Calendar day cell - base styling with hover, colors overridden via className
145
- "calendar-day": "border-transparent text-gray-900 dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700",
146
- };
147
-
148
- // Active state classes for ghost, toggle, menu-item, and nav
149
- const activeClasses = {
150
- ghost: "text-blue-700 bg-blue-50 dark:text-white dark:bg-gray-900",
151
- toggle: "text-white bg-blue-600 border-blue-600 hover:bg-blue-700 dark:text-white dark:bg-blue-600 dark:border-blue-600 dark:hover:bg-blue-700",
152
- "menu-item": "bg-blue-50 dark:bg-gray-700",
153
- nav: "text-blue-600 dark:text-blue-500",
154
- };
155
-
156
- // Disabled classes
157
- const disabledClasses = "bg-gray-200 border-gray-200 text-gray-400 cursor-not-allowed dark:bg-gray-700 dark:border-gray-700 dark:text-gray-500";
158
- // Disabled classes for transparent variants (link, ghost) - no background
159
- const disabledTransparentClasses = "text-gray-400 cursor-not-allowed dark:text-gray-500";
160
-
161
- let sizeClass = $derived((() => {
162
- if (resolvedVariant === "icon") return iconSizes[size] || iconSizes.sm;
163
- if (resolvedVariant === "avatar") return avatarSizes[size] || avatarSizes.md;
164
- if (resolvedVariant === "menu-item" || resolvedVariant === "menu-item-danger" || resolvedVariant === "search-result") {
165
- return menuItemSizes[size] || menuItemSizes.md;
166
- }
167
- if (resolvedVariant === "card") return cardSizes[size] || cardSizes.md;
168
- if (resolvedVariant === "link") return "text-sm";
169
- if (resolvedVariant === "sidebar-toggle") return ""; // Fixed dimensions in variant
170
- if (resolvedVariant === "nav") return ""; // Nav has sizing in variant class
171
- return sizeClasses[size] || sizeClasses.md;
172
- })());
173
-
174
- // Variants that should stay transparent when disabled
175
- const transparentVariants = ["link", "ghost", "ghost-red", "icon"];
176
-
177
- let variantClass = $derived((() => {
178
- if (success) return variantClasses.success;
179
- if (disabled && !loading && !success) {
180
- return transparentVariants.includes(resolvedVariant)
181
- ? disabledTransparentClasses
182
- : disabledClasses;
183
- }
184
- if (active && activeClasses[resolvedVariant]) {
185
- // When active, use ONLY active classes (they include all necessary styling)
186
- return activeClasses[resolvedVariant];
187
- }
188
- return variantClasses[resolvedVariant] || variantClasses.default;
189
- })());
190
-
191
- // Menu items, cards, and search results need left alignment, others are centered
192
- let isLeftAligned = $derived(
193
- resolvedVariant === "menu-item" ||
194
- resolvedVariant === "menu-item-danger" ||
195
- resolvedVariant === "card" ||
196
- resolvedVariant === "search-result"
197
- );
198
-
199
- // Use justify-between when there's trailing content (e.g., chevrons in nav items)
200
- let hasTrailing = $derived(typeof trailing === 'function' || trailing);
201
-
202
- let buttonClasses = $derived(twMerge(
203
- "relative",
204
- isLeftAligned
205
- ? (hasTrailing ? "flex items-center justify-between" : "flex items-center justify-start")
206
- : "inline-flex items-center justify-center",
207
- "rounded-lg",
208
- "font-medium leading-none",
209
- "focus:outline-none",
210
- // Apple-style micro-interactions (only when not disabled)
211
- "transition-all duration-150 ease-out",
212
- effectiveDisabled ? "" : "active:scale-[0.97] active:opacity-90",
213
- "select-none",
214
- sizeClass,
215
- variantClass,
216
- effectiveDisabled ? "cursor-not-allowed" : "cursor-pointer",
217
- className
218
- ));
219
- </script>
220
-
221
- {#if href}
222
- <a
223
- {href}
224
- class="{buttonClasses} {loading ? 'loading-pulse' : ''}"
225
- {onclick}
226
- {...restProps}
227
- >
228
- {#if loading}
229
- <span class="shimmer-overlay"></span>
230
- {/if}
231
- <span class="inline-flex items-center gap-1.5" class:invisible={loading || success}>
232
- {#if typeof children === 'function'}{@render children()}{:else if children}{children}{/if}
233
- </span>
234
- {#if typeof trailing === 'function'}{@render trailing()}{:else if trailing}{trailing}{/if}
235
- </a>
236
- {:else}
237
- <button
238
- {type}
239
- class="{buttonClasses} {loading ? 'loading-pulse' : ''}"
240
- disabled={effectiveDisabled}
241
- {onclick}
242
- {...restProps}
243
- >
244
- {#if loading}
245
- <span class="shimmer-overlay"></span>
246
- {/if}
247
- <span class="inline-flex items-center gap-1.5" class:invisible={loading || success}>
248
- {#if typeof children === 'function'}{@render children()}{:else if children}{children}{/if}
249
- </span>
250
- {#if typeof trailing === 'function'}{@render trailing()}{:else if trailing}{trailing}{/if}
251
- {#if success}
252
- <span class="absolute inset-0 flex items-center justify-center gap-2">
253
- <CheckOutline class="w-5 h-5" />
254
- {#if successText}<span class="font-medium">{successText}</span>{/if}
255
- </span>
256
- {/if}
257
- </button>
258
- {/if}
259
-
260
- <style>
261
- .loading-pulse {
262
- animation: pulse-bg 2s ease-in-out infinite;
263
- }
264
-
265
- @keyframes pulse-bg {
266
- 0%, 100% { filter: brightness(1); }
267
- 50% { filter: brightness(1.15); }
268
- }
269
-
270
- .shimmer-overlay {
271
- position: absolute;
272
- inset: 0;
273
- overflow: hidden;
274
- border-radius: inherit;
275
- }
276
-
277
- .shimmer-overlay::after {
278
- content: '';
279
- position: absolute;
280
- top: 0;
281
- left: -100%;
282
- width: 100%;
283
- height: 100%;
284
- background: linear-gradient(
285
- 90deg,
286
- transparent 0%,
287
- rgba(255, 255, 255, 0.2) 50%,
288
- transparent 100%
289
- );
290
- animation: shimmer 1s ease-in-out infinite;
291
- }
292
-
293
- @keyframes shimmer {
294
- 0% {
295
- left: -100%;
296
- }
297
- 100% {
298
- left: 100%;
299
- }
300
- }
301
- </style>
1
+ <script>
2
+ /**
3
+ * Button Component - Flowbite Native (Pure Tailwind)
4
+ * Migrated to Svelte 5 runes
5
+ *
6
+ * Variants (Flowbite naming):
7
+ * - default: Primary blue button
8
+ * - alternative: Gray outline button
9
+ * - outline: Blue outline button
10
+ * - red: Destructive solid button
11
+ * - red-outline: Destructive outline button
12
+ * - ghost: Text-only button
13
+ * - ghost-red: Destructive text button
14
+ * - icon: Icon-only button
15
+ * - toggle: Toggle/pill button
16
+ * - avatar: Avatar/image trigger button (no padding, opacity hover)
17
+ * - menu-item: Dropdown/sheet menu item (full width, left-aligned)
18
+ * - menu-item-danger: Destructive menu item (red text)
19
+ * - card: Selectable card button (bordered, for list selections)
20
+ * - sidebar-toggle: Compact pill for sidebar expand/collapse
21
+ *
22
+ * Sizes (Flowbite native): xs, sm, md, lg, xl
23
+ */
24
+ import { CheckOutline } from '../Icons';
25
+ import { twMerge } from 'tailwind-merge';
26
+
27
+ /** @type {{
28
+ variant?: string,
29
+ size?: string,
30
+ disabled?: boolean,
31
+ loading?: boolean,
32
+ success?: boolean,
33
+ successText?: string,
34
+ active?: boolean,
35
+ href?: string | null,
36
+ type?: 'button' | 'submit' | 'reset',
37
+ children?: any,
38
+ trailing?: any,
39
+ class?: string,
40
+ onclick?: (e: MouseEvent) => void,
41
+ [key: string]: any
42
+ }} */
43
+ let {
44
+ variant = "default",
45
+ size = "md",
46
+ disabled = false,
47
+ loading = false,
48
+ success = false,
49
+ successText = "",
50
+ active = false,
51
+ href = null,
52
+ type = "button",
53
+ children,
54
+ trailing,
55
+ class: className = "",
56
+ onclick,
57
+ ...restProps
58
+ } = $props();
59
+
60
+ // Legacy variant name mapping
61
+ const variantMap = {
62
+ "blue-solid": "default",
63
+ "gray-outline": "alternative",
64
+ "blue-outline": "outline",
65
+ "red-solid": "red",
66
+ "red-text": "ghost-red",
67
+ "gray-text": "ghost",
68
+ };
69
+
70
+ // Resolve legacy names
71
+ let resolvedVariant = $derived(variantMap[variant] || variant);
72
+ let effectiveDisabled = $derived(disabled || loading || success);
73
+
74
+ // Size classes - Flowbite native sizing
75
+ const sizeClasses = {
76
+ xs: "px-3 py-1.5 text-xs",
77
+ sm: "px-3 py-2 text-sm",
78
+ md: "px-4 py-2.5 text-sm",
79
+ lg: "px-5 py-3 text-sm",
80
+ xl: "px-6 py-3.5 text-sm",
81
+ "xl-medium": "w-full px-6 py-3.5 text-sm",
82
+ full: "w-full px-5 py-3 text-sm",
83
+ "full-md-auto": "w-full px-5 py-3 text-sm md:w-auto",
84
+ half: "w-1/2 px-4 py-2.5 text-sm",
85
+ };
86
+
87
+ // Icon variant sizes
88
+ const iconSizes = {
89
+ xs: "p-1.5",
90
+ sm: "p-2",
91
+ md: "p-2.5",
92
+ lg: "p-3",
93
+ };
94
+
95
+ // Avatar variant sizes (no padding, just min dimensions)
96
+ const avatarSizes = {
97
+ sm: "min-w-8 min-h-8",
98
+ md: "min-w-10 min-h-10",
99
+ lg: "min-w-12 min-h-12",
100
+ };
101
+
102
+ // Menu item sizes
103
+ const menuItemSizes = {
104
+ sm: "py-2 px-4 text-sm",
105
+ md: "py-3 px-4 text-sm",
106
+ lg: "py-4 px-6 text-base",
107
+ nav: "py-2 px-3 text-base font-normal",
108
+ };
109
+
110
+ // Card sizes (larger padding for card-like buttons)
111
+ const cardSizes = {
112
+ sm: "p-3 text-sm",
113
+ md: "p-4 text-sm",
114
+ lg: "p-5 text-base",
115
+ };
116
+
117
+ // Variant classes with all states in Tailwind (no focus rings - design decision)
118
+ const variantClasses = {
119
+ default: "text-white bg-blue-700 border border-blue-700 hover:bg-blue-800 dark:bg-blue-600 dark:hover:bg-blue-700",
120
+ alternative: "text-gray-900 bg-white border border-gray-200 hover:bg-gray-100 hover:text-blue-700 dark:bg-gray-800 dark:text-white dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700",
121
+ outline: "text-blue-700 bg-transparent border border-blue-700 hover:text-white hover:bg-blue-800 dark:border-blue-500 dark:text-blue-500 dark:hover:text-white dark:hover:bg-blue-500",
122
+ red: "text-white bg-red-700 border border-red-700 hover:bg-red-800 dark:bg-red-600 dark:hover:bg-red-700",
123
+ "red-outline": "text-red-700 bg-transparent border border-red-700 hover:text-white hover:bg-red-800 dark:border-red-500 dark:text-red-500 dark:hover:text-white dark:hover:bg-red-600",
124
+ ghost: "text-gray-500 bg-transparent border-transparent hover:bg-gray-100 hover:text-gray-900 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white",
125
+ "ghost-red": "text-red-700 bg-transparent border-transparent hover:bg-red-100 hover:text-red-900 dark:text-red-500 dark:hover:bg-red-900/50 dark:hover:text-red-400",
126
+ link: "text-blue-700 bg-transparent border-transparent hover:underline dark:text-blue-500",
127
+ icon: "text-gray-500 bg-transparent border-transparent hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700",
128
+ toggle: "text-gray-500 bg-gray-100 border border-gray-200 hover:bg-gray-200 dark:bg-gray-700 dark:text-gray-400 dark:border-gray-600 dark:hover:bg-gray-600",
129
+ success: "text-white bg-green-600 border border-green-600",
130
+ // Avatar/image trigger - no background, opacity hover
131
+ avatar: "bg-transparent border-transparent hover:opacity-80",
132
+ // Menu items - full width, left-aligned, for dropdowns/sheets and sidebar nav
133
+ "menu-item": "w-full text-left whitespace-nowrap text-gray-900 bg-transparent border-transparent hover:bg-gray-100 dark:text-white dark:hover:bg-gray-600",
134
+ // Danger menu item - red text version
135
+ "menu-item-danger": "w-full text-left whitespace-nowrap text-red-600 bg-transparent border-transparent hover:bg-red-50 dark:text-red-500 dark:hover:bg-gray-600",
136
+ // Selectable card - bordered card-like button for list selections
137
+ card: "w-full text-left text-gray-900 bg-white border border-gray-300 hover:bg-gray-50 dark:bg-gray-800 dark:text-white dark:border-gray-600 dark:hover:bg-gray-700",
138
+ // Search result item - blue hover for search dropdowns
139
+ "search-result": "w-full text-left text-gray-900 bg-transparent border-transparent hover:bg-blue-50 focus:bg-blue-50 dark:text-white dark:hover:bg-blue-900/20 dark:focus:bg-blue-900/20",
140
+ // Sidebar toggle - compact pill for sidebar expand/collapse
141
+ "sidebar-toggle": "w-6 h-7 text-gray-900 bg-blue-100 border border-blue-200 hover:bg-blue-200 shadow-lg dark:text-white dark:bg-gray-800 dark:border-gray-700 dark:hover:bg-gray-700",
142
+ // Bottom navigation item - vertical layout, transparent, for mobile nav bars
143
+ nav: "flex-col h-full py-2 text-gray-500 bg-transparent border-transparent hover:text-blue-600 dark:text-gray-400 dark:hover:text-blue-500",
144
+ // Calendar day cell - base styling with hover, colors overridden via className
145
+ "calendar-day": "border-transparent text-gray-900 dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700",
146
+ };
147
+
148
+ // Active state classes for ghost, toggle, menu-item, and nav
149
+ const activeClasses = {
150
+ ghost: "text-blue-700 bg-blue-50 dark:text-white dark:bg-gray-900",
151
+ toggle: "text-white bg-blue-600 border-blue-600 hover:bg-blue-700 dark:text-white dark:bg-blue-600 dark:border-blue-600 dark:hover:bg-blue-700",
152
+ "menu-item": "bg-blue-50 dark:bg-gray-700",
153
+ nav: "text-blue-600 dark:text-blue-500",
154
+ };
155
+
156
+ // Disabled classes
157
+ const disabledClasses = "bg-gray-200 border-gray-200 text-gray-400 cursor-not-allowed dark:bg-gray-700 dark:border-gray-700 dark:text-gray-500";
158
+ // Disabled classes for transparent variants (link, ghost) - no background
159
+ const disabledTransparentClasses = "text-gray-400 cursor-not-allowed dark:text-gray-500";
160
+
161
+ let sizeClass = $derived((() => {
162
+ if (resolvedVariant === "icon") return iconSizes[size] || iconSizes.sm;
163
+ if (resolvedVariant === "avatar") return avatarSizes[size] || avatarSizes.md;
164
+ if (resolvedVariant === "menu-item" || resolvedVariant === "menu-item-danger" || resolvedVariant === "search-result") {
165
+ return menuItemSizes[size] || menuItemSizes.md;
166
+ }
167
+ if (resolvedVariant === "card") return cardSizes[size] || cardSizes.md;
168
+ if (resolvedVariant === "link") return "text-sm";
169
+ if (resolvedVariant === "sidebar-toggle") return ""; // Fixed dimensions in variant
170
+ if (resolvedVariant === "nav") return ""; // Nav has sizing in variant class
171
+ return sizeClasses[size] || sizeClasses.md;
172
+ })());
173
+
174
+ // Variants that should stay transparent when disabled
175
+ const transparentVariants = ["link", "ghost", "ghost-red", "icon"];
176
+
177
+ let variantClass = $derived((() => {
178
+ if (success) return variantClasses.success;
179
+ if (disabled && !loading && !success) {
180
+ return transparentVariants.includes(resolvedVariant)
181
+ ? disabledTransparentClasses
182
+ : disabledClasses;
183
+ }
184
+ if (active && activeClasses[resolvedVariant]) {
185
+ // When active, use ONLY active classes (they include all necessary styling)
186
+ return activeClasses[resolvedVariant];
187
+ }
188
+ return variantClasses[resolvedVariant] || variantClasses.default;
189
+ })());
190
+
191
+ // Menu items, cards, and search results need left alignment, others are centered
192
+ let isLeftAligned = $derived(
193
+ resolvedVariant === "menu-item" ||
194
+ resolvedVariant === "menu-item-danger" ||
195
+ resolvedVariant === "card" ||
196
+ resolvedVariant === "search-result"
197
+ );
198
+
199
+ // Use justify-between when there's trailing content (e.g., chevrons in nav items)
200
+ let hasTrailing = $derived(typeof trailing === 'function' || trailing);
201
+
202
+ let buttonClasses = $derived(twMerge(
203
+ "relative",
204
+ isLeftAligned
205
+ ? (hasTrailing ? "flex items-center justify-between" : "flex items-center justify-start")
206
+ : "inline-flex items-center justify-center",
207
+ "rounded-lg",
208
+ "font-medium leading-none",
209
+ "focus:outline-none",
210
+ // Apple-style micro-interactions (only when not disabled)
211
+ "transition-all duration-150 ease-out",
212
+ effectiveDisabled ? "" : "active:scale-[0.97] active:opacity-90",
213
+ "select-none",
214
+ sizeClass,
215
+ variantClass,
216
+ effectiveDisabled ? "cursor-not-allowed" : "cursor-pointer",
217
+ className
218
+ ));
219
+ </script>
220
+
221
+ {#if href}
222
+ <a
223
+ {href}
224
+ class="{buttonClasses} {loading ? 'loading-pulse' : ''}"
225
+ {onclick}
226
+ {...restProps}
227
+ >
228
+ {#if loading}
229
+ <span class="shimmer-overlay"></span>
230
+ {/if}
231
+ <span class="inline-flex items-center gap-1.5" class:invisible={loading || success}>
232
+ {#if typeof children === 'function'}{@render children()}{:else if children}{children}{/if}
233
+ </span>
234
+ {#if typeof trailing === 'function'}{@render trailing()}{:else if trailing}{trailing}{/if}
235
+ </a>
236
+ {:else}
237
+ <button
238
+ {type}
239
+ class="{buttonClasses} {loading ? 'loading-pulse' : ''}"
240
+ disabled={effectiveDisabled}
241
+ {onclick}
242
+ {...restProps}
243
+ >
244
+ {#if loading}
245
+ <span class="shimmer-overlay"></span>
246
+ {/if}
247
+ <span class="inline-flex items-center gap-1.5" class:invisible={loading || success}>
248
+ {#if typeof children === 'function'}{@render children()}{:else if children}{children}{/if}
249
+ </span>
250
+ {#if typeof trailing === 'function'}{@render trailing()}{:else if trailing}{trailing}{/if}
251
+ {#if success}
252
+ <span class="absolute inset-0 flex items-center justify-center gap-2">
253
+ <CheckOutline class="w-5 h-5" />
254
+ {#if successText}<span class="font-medium">{successText}</span>{/if}
255
+ </span>
256
+ {/if}
257
+ </button>
258
+ {/if}
259
+
260
+ <style>
261
+ .loading-pulse {
262
+ animation: pulse-bg 2s ease-in-out infinite;
263
+ }
264
+
265
+ @keyframes pulse-bg {
266
+ 0%, 100% { filter: brightness(1); }
267
+ 50% { filter: brightness(1.15); }
268
+ }
269
+
270
+ .shimmer-overlay {
271
+ position: absolute;
272
+ inset: 0;
273
+ overflow: hidden;
274
+ border-radius: inherit;
275
+ }
276
+
277
+ .shimmer-overlay::after {
278
+ content: '';
279
+ position: absolute;
280
+ top: 0;
281
+ left: -100%;
282
+ width: 100%;
283
+ height: 100%;
284
+ background: linear-gradient(
285
+ 90deg,
286
+ transparent 0%,
287
+ rgba(255, 255, 255, 0.2) 50%,
288
+ transparent 100%
289
+ );
290
+ animation: shimmer 1s ease-in-out infinite;
291
+ }
292
+
293
+ @keyframes shimmer {
294
+ 0% {
295
+ left: -100%;
296
+ }
297
+ 100% {
298
+ left: 100%;
299
+ }
300
+ }
301
+ </style>