@getmicdrop/svelte-components 5.10.0 → 5.10.3

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 (233) 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 +146 -146
  7. package/dist/calendar/ShowCard/ShowCard.svelte +157 -157
  8. package/dist/calendar/ShowTimeCard/ShowTimeCard.svelte +61 -61
  9. package/dist/components/Heading.svelte +60 -60
  10. package/dist/components/Layout/AppShell.svelte +104 -104
  11. package/dist/components/Layout/ContentSection.svelte +80 -80
  12. package/dist/components/Layout/Grid.svelte +4 -4
  13. package/dist/components/Layout/Heading.svelte +81 -81
  14. package/dist/components/Layout/PageContainer.svelte +69 -69
  15. package/dist/components/Layout/Responsive.svelte +75 -75
  16. package/dist/components/Layout/Section.svelte +80 -80
  17. package/dist/components/Layout/ShowOnDesktop.svelte +37 -37
  18. package/dist/components/Layout/ShowOnMobile.svelte +37 -37
  19. package/dist/components/Layout/Sidebar.svelte +108 -108
  20. package/dist/components/Layout/Stack.spec.js +1 -1
  21. package/dist/components/Layout/Stack.svelte +6 -6
  22. package/dist/components/Layout/Text.svelte +87 -87
  23. package/dist/components/Layout/TwoColumn.svelte +108 -108
  24. package/dist/components/Text.svelte +53 -53
  25. package/dist/constants/validation.js +91 -91
  26. package/dist/constants/validation.spec.js +64 -64
  27. package/dist/datetime/__tests__/format.test.js +1 -1
  28. package/dist/datetime/__tests__/parse.test.js +1 -1
  29. package/dist/datetime/__tests__/timezone.test.js +1 -1
  30. package/dist/datetime/parse.js +1 -1
  31. package/dist/forms/createFormStore.svelte.js +1 -0
  32. package/dist/index.js +51 -51
  33. package/dist/patterns/data/DataGrid.svelte +45 -45
  34. package/dist/patterns/data/DataList.svelte +24 -24
  35. package/dist/patterns/data/DataTable.svelte +36 -36
  36. package/dist/patterns/forms/FormActions.spec.js +95 -95
  37. package/dist/patterns/forms/FormActions.stories.svelte +97 -97
  38. package/dist/patterns/forms/FormActions.svelte +46 -46
  39. package/dist/patterns/forms/FormGrid.svelte +33 -33
  40. package/dist/patterns/forms/FormSection.svelte +32 -32
  41. package/dist/patterns/forms/FormValidationSummary.stories.svelte +83 -83
  42. package/dist/patterns/forms/FormValidationSummary.svelte +74 -74
  43. package/dist/patterns/layout/Sidebar.svelte +39 -39
  44. package/dist/patterns/layout/index.js +29 -29
  45. package/dist/patterns/navigation/BottomNav.stories.svelte +117 -117
  46. package/dist/patterns/navigation/BottomNav.svelte +74 -74
  47. package/dist/patterns/navigation/Header.stories.svelte +77 -77
  48. package/dist/patterns/navigation/Header.svelte +255 -255
  49. package/dist/patterns/page/PageHeader.svelte +18 -18
  50. package/dist/patterns/page/PageLayout.svelte +40 -40
  51. package/dist/patterns/page/PageLoader.spec.js +57 -57
  52. package/dist/patterns/page/PageLoader.stories.svelte +137 -137
  53. package/dist/patterns/page/PageLoader.svelte +24 -24
  54. package/dist/patterns/page/SectionHeader.svelte +29 -29
  55. package/dist/presets/badges.js +112 -112
  56. package/dist/presets/buttons.js +76 -76
  57. package/dist/presets/index.js +9 -9
  58. package/dist/primitives/Accordion/Accordion.stories.svelte +75 -75
  59. package/dist/primitives/Accordion/Accordion.svelte +42 -42
  60. package/dist/primitives/Accordion/AccordionItem.svelte +95 -95
  61. package/dist/primitives/Alert/Alert.spec.js +173 -173
  62. package/dist/primitives/Alert/Alert.stories.svelte +88 -88
  63. package/dist/primitives/Alert/Alert.svelte +27 -27
  64. package/dist/primitives/Avatar/Avatar.stories.svelte +94 -94
  65. package/dist/primitives/Avatar/Avatar.svelte +66 -66
  66. package/dist/primitives/Badges/Badge.spec.js +144 -144
  67. package/dist/primitives/Badges/Badge.stories.svelte +86 -86
  68. package/dist/primitives/Badges/Badge.svelte +99 -99
  69. package/dist/primitives/BottomSheet/BottomSheet.spec.js +136 -136
  70. package/dist/primitives/BottomSheet/BottomSheet.stories.svelte +83 -83
  71. package/dist/primitives/BottomSheet/BottomSheet.svelte +100 -100
  72. package/dist/primitives/Breadcrumb/Breadcrumb.spec.js +122 -122
  73. package/dist/primitives/Breadcrumb/Breadcrumb.stories.svelte +23 -23
  74. package/dist/primitives/Breadcrumb/Breadcrumb.svelte +98 -98
  75. package/dist/primitives/Button/Button.spec.js +223 -223
  76. package/dist/primitives/Button/Button.stories.svelte +76 -76
  77. package/dist/primitives/Button/Button.svelte +283 -283
  78. package/dist/primitives/Button/ButtonGroup.svelte +50 -50
  79. package/dist/primitives/Button/ButtonSaveDemo.spec.js +146 -146
  80. package/dist/primitives/Button/ButtonSaveDemo.svelte +25 -25
  81. package/dist/primitives/Button/ButtonVariantShowcase.svelte +129 -129
  82. package/dist/primitives/Card.spec.js +49 -49
  83. package/dist/primitives/Card.stories.svelte +22 -22
  84. package/dist/primitives/Card.svelte +28 -28
  85. package/dist/primitives/Checkbox/Checkbox.stories.svelte +84 -84
  86. package/dist/primitives/Checkbox/Checkbox.svelte +88 -88
  87. package/dist/primitives/DarkModeToggle.spec.js +390 -390
  88. package/dist/primitives/DarkModeToggle.stories.svelte +57 -57
  89. package/dist/primitives/DarkModeToggle.svelte +136 -136
  90. package/dist/primitives/Drawer/Drawer.stories.svelte +80 -80
  91. package/dist/primitives/Drawer/Drawer.svelte +120 -120
  92. package/dist/primitives/Dropdown/Dropdown.stories.svelte +137 -137
  93. package/dist/primitives/Dropdown/Dropdown.svelte +170 -170
  94. package/dist/primitives/Dropdown/DropdownDivider.svelte +9 -9
  95. package/dist/primitives/Dropdown/DropdownItem.svelte +80 -80
  96. package/dist/primitives/Helper/Helper.svelte +33 -33
  97. package/dist/primitives/Icons/ArrowLeft.svelte +8 -8
  98. package/dist/primitives/Icons/ArrowRight.svelte +8 -8
  99. package/dist/primitives/Icons/Availability.svelte +14 -14
  100. package/dist/primitives/Icons/Back.svelte +14 -14
  101. package/dist/primitives/Icons/CheckCircle.svelte +6 -6
  102. package/dist/primitives/Icons/CheckCircleOutline.svelte +15 -15
  103. package/dist/primitives/Icons/ChevronLeft.svelte +4 -4
  104. package/dist/primitives/Icons/ChevronRight.svelte +4 -4
  105. package/dist/primitives/Icons/Copy.svelte +15 -15
  106. package/dist/primitives/Icons/Cross.svelte +5 -5
  107. package/dist/primitives/Icons/DownArrow.svelte +8 -8
  108. package/dist/primitives/Icons/ErrorCircle.svelte +6 -6
  109. package/dist/primitives/Icons/FacebookIcon.svelte +2 -2
  110. package/dist/primitives/Icons/Home.svelte +15 -15
  111. package/dist/primitives/Icons/Icon.spec.js +169 -169
  112. package/dist/primitives/Icons/Icon.stories.svelte +100 -100
  113. package/dist/primitives/Icons/Icon.svelte +52 -52
  114. package/dist/primitives/Icons/IconGallery.stories.svelte +235 -235
  115. package/dist/primitives/Icons/Info.svelte +7 -7
  116. package/dist/primitives/Icons/InstagramIcon.svelte +4 -4
  117. package/dist/primitives/Icons/LogoInstagram.svelte +2 -2
  118. package/dist/primitives/Icons/Message.svelte +15 -15
  119. package/dist/primitives/Icons/MoonIcon.svelte +5 -5
  120. package/dist/primitives/Icons/More.svelte +21 -21
  121. package/dist/primitives/Icons/MoreHori.spec.js +61 -61
  122. package/dist/primitives/Icons/MoreHori.svelte +22 -22
  123. package/dist/primitives/Icons/Notification.svelte +14 -14
  124. package/dist/primitives/Icons/Payment.svelte +14 -14
  125. package/dist/primitives/Icons/Profile.svelte +21 -21
  126. package/dist/primitives/Icons/Reload.svelte +29 -29
  127. package/dist/primitives/Icons/Shows.svelte +21 -21
  128. package/dist/primitives/Icons/Signout.svelte +21 -21
  129. package/dist/primitives/Icons/SunIcon.svelte +8 -8
  130. package/dist/primitives/Icons/TiktokIcon.svelte +2 -2
  131. package/dist/primitives/Icons/TwitterIcon.svelte +2 -2
  132. package/dist/primitives/Icons/WarningIcon.spec.js +18 -18
  133. package/dist/primitives/Icons/WarningIcon.svelte +5 -5
  134. package/dist/primitives/Input/Input.spec.js +573 -573
  135. package/dist/primitives/Input/Input.stories.svelte +139 -139
  136. package/dist/primitives/Input/Input.svelte +423 -423
  137. package/dist/primitives/Input/Select.spec.js +218 -218
  138. package/dist/primitives/Input/Select.stories.svelte +112 -112
  139. package/dist/primitives/Input/Select.svelte +252 -252
  140. package/dist/primitives/Input/Textarea.stories.svelte +137 -137
  141. package/dist/primitives/Input/Textarea.svelte +105 -105
  142. package/dist/primitives/Label/Label.svelte +37 -37
  143. package/dist/primitives/Modal/Modal.spec.js +99 -99
  144. package/dist/primitives/Modal/Modal.stories.svelte +86 -86
  145. package/dist/primitives/Modal/Modal.svelte +157 -157
  146. package/dist/primitives/Pagination/Pagination.stories.svelte +76 -76
  147. package/dist/primitives/Pagination/Pagination.svelte +261 -261
  148. package/dist/primitives/Radio/Radio.stories.svelte +80 -80
  149. package/dist/primitives/Radio/Radio.svelte +67 -67
  150. package/dist/primitives/Skeleton/CardPlaceholder.svelte +87 -87
  151. package/dist/primitives/Skeleton/ImagePlaceholder.svelte +59 -59
  152. package/dist/primitives/Skeleton/ListPlaceholder.svelte +76 -76
  153. package/dist/primitives/Skeleton/Skeleton.stories.svelte +151 -151
  154. package/dist/primitives/Skeleton/Skeleton.svelte +26 -26
  155. package/dist/primitives/Spinner/Spinner.spec.js +71 -71
  156. package/dist/primitives/Spinner/Spinner.stories.svelte +29 -29
  157. package/dist/primitives/Spinner/Spinner.svelte +20 -20
  158. package/dist/primitives/Tabs/TabItem.svelte +49 -49
  159. package/dist/primitives/Tabs/Tabs.stories.svelte +112 -112
  160. package/dist/primitives/Tabs/Tabs.svelte +137 -137
  161. package/dist/primitives/Toggle.spec.js +146 -146
  162. package/dist/primitives/Toggle.stories.svelte +92 -92
  163. package/dist/primitives/Toggle.svelte +131 -132
  164. package/dist/primitives/Tooltip/Tooltip.svelte +83 -83
  165. package/dist/primitives/Typography/Typography.svelte +53 -53
  166. package/dist/primitives/ValidationError.spec.js +103 -103
  167. package/dist/primitives/ValidationError.stories.svelte +69 -69
  168. package/dist/primitives/ValidationError.svelte +29 -29
  169. package/dist/primitives/index.js +92 -92
  170. package/dist/recipes/CropImage/CropImage.spec.js +208 -208
  171. package/dist/recipes/CropImage/CropImage.stories.svelte +104 -104
  172. package/dist/recipes/CropImage/CropImage.svelte +219 -219
  173. package/dist/recipes/ImageUploader/ImageUploader.stories.svelte +125 -125
  174. package/dist/recipes/ImageUploader/ImageUploader.svelte +970 -970
  175. package/dist/recipes/Toaster/Toaster.stories.svelte +62 -62
  176. package/dist/recipes/feedback/EmptyState/EmptyState.svelte +1 -1
  177. package/dist/recipes/feedback/ErrorDisplay.spec.js +69 -69
  178. package/dist/recipes/feedback/ErrorDisplay.stories.svelte +101 -101
  179. package/dist/recipes/feedback/ErrorDisplay.svelte +1 -1
  180. package/dist/recipes/feedback/StatusIndicator/StatusIndicator.spec.js +133 -133
  181. package/dist/recipes/feedback/StatusIndicator/StatusIndicator.svelte +157 -157
  182. package/dist/recipes/fields/CheckboxField.svelte +85 -85
  183. package/dist/recipes/fields/FormField.svelte +58 -58
  184. package/dist/recipes/fields/RadioGroup.svelte +95 -95
  185. package/dist/recipes/fields/SelectField.svelte +80 -80
  186. package/dist/recipes/fields/TextareaField.svelte +97 -97
  187. package/dist/recipes/fields/ToggleField.svelte +60 -60
  188. package/dist/recipes/fields/index.js +7 -7
  189. package/dist/recipes/inputs/MultiSelect.spec.js +260 -260
  190. package/dist/recipes/inputs/MultiSelect.stories.svelte +133 -133
  191. package/dist/recipes/inputs/MultiSelect.svelte +283 -283
  192. package/dist/recipes/inputs/OTPInput.spec.js +251 -251
  193. package/dist/recipes/inputs/OTPInput.stories.svelte +162 -162
  194. package/dist/recipes/inputs/OTPInput.svelte +117 -117
  195. package/dist/recipes/inputs/PasswordInput.svelte +22 -22
  196. package/dist/recipes/inputs/PasswordStrengthIndicator/PasswordStrengthIndicator.svelte +131 -117
  197. package/dist/recipes/inputs/PasswordStrengthIndicator/PasswordStrengthIndicator.svelte.d.ts.map +1 -1
  198. package/dist/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.stories.svelte +123 -123
  199. package/dist/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.svelte +344 -344
  200. package/dist/recipes/inputs/Search.svelte +102 -102
  201. package/dist/recipes/inputs/SelectDropdown.svelte +171 -171
  202. package/dist/recipes/modals/AlertModal.svelte +130 -130
  203. package/dist/recipes/modals/ConfirmationModal.spec.js +206 -206
  204. package/dist/recipes/modals/ConfirmationModal.stories.svelte +119 -119
  205. package/dist/recipes/modals/ConfirmationModal.svelte +152 -152
  206. package/dist/recipes/modals/InputModal.svelte +182 -182
  207. package/dist/recipes/modals/ModalStateManager.spec.js +100 -100
  208. package/dist/recipes/modals/ModalStateManager.svelte +77 -77
  209. package/dist/recipes/modals/ModalTestWrapper.svelte +65 -65
  210. package/dist/recipes/modals/StatusModal.svelte +206 -206
  211. package/dist/services/EventService.js +75 -75
  212. package/dist/services/EventService.spec.js +217 -217
  213. package/dist/services/ShowService.spec.js +345 -345
  214. package/dist/stores/toaster.js +13 -13
  215. package/dist/stories/ButtonAuditReview.stories.svelte +14 -14
  216. package/dist/stories/ButtonAuditReview.svelte +427 -427
  217. package/dist/stories/PatternsGallery.stories.svelte +19 -19
  218. package/dist/stories/PatternsGallery.svelte +206 -206
  219. package/dist/stories/PrimitivesGallery.stories.svelte +19 -19
  220. package/dist/stories/PrimitivesGallery.svelte +752 -752
  221. package/dist/stories/RecipesGallery.stories.svelte +19 -19
  222. package/dist/stories/RecipesGallery.svelte +471 -471
  223. package/dist/stories/button-audit-manifest.json +11186 -11186
  224. package/dist/tailwind/preset.cjs +82 -82
  225. package/dist/telemetry.js +405 -405
  226. package/dist/telemetry.spec.js +1169 -1169
  227. package/dist/tokens/tokens.css +87 -87
  228. package/dist/tokens/typography-base.css +163 -163
  229. package/dist/tokens/utilities.css +353 -353
  230. package/dist/utils/apiConfig.spec.js +219 -219
  231. package/dist/utils/transitions.js +4 -4
  232. package/dist/utils/utils.js +693 -693
  233. package/package.json +297 -297
@@ -1,170 +1,170 @@
1
- <script lang="ts">
2
- import { onMount, onDestroy, tick, setContext } from "svelte";
3
- import type { Snippet } from "svelte";
4
- import { bloom } from "../../utils/transitions.js";
5
-
6
- interface Props {
7
- open?: boolean;
8
- activeUrl?: string;
9
- placement?: string;
10
- class?: string;
11
- ariaLabel?: string;
12
- onclose?: () => void;
13
- children?: Snippet;
14
- [key: string]: unknown;
15
- }
16
-
17
- let {
18
- open = $bindable(false),
19
- activeUrl = "",
20
- placement = "bottom",
21
- class: className = "",
22
- ariaLabel = "Menu",
23
- onclose,
24
- children,
25
- ...restProps
26
- }: Props = $props();
27
-
28
- let dropdownRef: HTMLUListElement | null = $state(null);
29
- let containerRef: HTMLDivElement | null = $state(null);
30
- let focusedIndex = $state(-1);
31
- let menuItems: HTMLElement[] = $state([]);
32
-
33
- async function updateMenuItems() {
34
- await tick();
35
- if (dropdownRef) {
36
- menuItems = Array.from(dropdownRef.querySelectorAll<HTMLElement>('[role="menuitem"]:not([disabled])'));
37
- }
38
- }
39
-
40
- function focusItem(index: number) {
41
- if (menuItems.length === 0) return;
42
- if (index < 0) index = menuItems.length - 1;
43
- if (index >= menuItems.length) index = 0;
44
- focusedIndex = index;
45
- menuItems[focusedIndex]?.focus();
46
- }
47
-
48
- function getTriggerElement(): Element | null {
49
- const parent = containerRef?.parentElement;
50
- if (parent) {
51
- const siblings = Array.from(parent.children);
52
- const containerIndex = containerRef ? siblings.indexOf(containerRef) : -1;
53
- if (containerIndex > 0) {
54
- return siblings[containerIndex - 1];
55
- }
56
- }
57
- return null;
58
- }
59
-
60
- function handleClickOutside(event: MouseEvent) {
61
- if (!open) return;
62
-
63
- if (dropdownRef && dropdownRef.contains(event.target as Node)) {
64
- return;
65
- }
66
-
67
- const trigger = getTriggerElement();
68
- if (trigger && trigger.contains(event.target as Node)) {
69
- return;
70
- }
71
-
72
- open = false;
73
- onclose?.();
74
- }
75
-
76
- function handleKeydown(event: KeyboardEvent) {
77
- if (!open) return;
78
-
79
- const trigger = getTriggerElement();
80
- if (!dropdownRef?.contains(event.target as Node) && !trigger?.contains(event.target as Node)) {
81
- return;
82
- }
83
-
84
- switch (event.key) {
85
- case "Escape":
86
- open = false;
87
- (trigger as HTMLElement | null)?.focus();
88
- event.preventDefault();
89
- onclose?.();
90
- break;
91
- case "ArrowDown":
92
- focusItem(focusedIndex + 1);
93
- event.preventDefault();
94
- break;
95
- case "ArrowUp":
96
- focusItem(focusedIndex - 1);
97
- event.preventDefault();
98
- break;
99
- case "Home":
100
- focusItem(0);
101
- event.preventDefault();
102
- break;
103
- case "End":
104
- focusItem(menuItems.length - 1);
105
- event.preventDefault();
106
- break;
107
- case "Tab":
108
- open = false;
109
- onclose?.();
110
- break;
111
- }
112
- }
113
-
114
- $effect(() => {
115
- if (open) {
116
- focusedIndex = -1;
117
- updateMenuItems();
118
- }
119
- });
120
-
121
- onMount(() => {
122
- document.addEventListener("mousedown", handleClickOutside, true);
123
- document.addEventListener("keydown", handleKeydown);
124
- });
125
-
126
- onDestroy(() => {
127
- if (typeof document !== "undefined") {
128
- document.removeEventListener("mousedown", handleClickOutside, true);
129
- document.removeEventListener("keydown", handleKeydown);
130
- }
131
- });
132
-
133
- setContext("dropdown", {
134
- get activeUrl() { return activeUrl; },
135
- close: () => {
136
- open = false;
137
- onclose?.();
138
- }
139
- });
140
-
141
- const placementClasses: Record<string, string> = {
142
- bottom: "top-full left-0 mt-1",
143
- top: "bottom-full left-0 mb-1",
144
- left: "right-full top-0 mr-1",
145
- right: "left-full top-0 ml-1"
146
- };
147
-
148
- // Map placement to transform origin for bloom animation
149
- const placementOrigins: Record<string, string> = {
150
- bottom: "top left",
151
- top: "bottom left",
152
- left: "top right",
153
- right: "top left"
154
- };
155
- </script>
156
-
157
- {#if open}
158
- <div
159
- bind:this={containerRef}
160
- class="absolute z-10 bg-white divide-y divide-gray-100 rounded-lg shadow-lg w-44 dark:bg-gray-700 dark:divide-gray-600 {className}"
161
- role="menu"
162
- aria-label={ariaLabel}
163
- transition:bloom={{ origin: placementOrigins[placement] || "top left" }}
164
- {...restProps}
165
- >
166
- <ul bind:this={dropdownRef} class="py-2 text-sm text-gray-700 dark:text-gray-200">
167
- {#if typeof children === 'function'}{@render children()}{:else if children}{children}{/if}
168
- </ul>
169
- </div>
170
- {/if}
1
+ <script lang="ts">
2
+ import { onMount, onDestroy, tick, setContext } from "svelte";
3
+ import type { Snippet } from "svelte";
4
+ import { bloom } from "../../utils/transitions.js";
5
+
6
+ interface Props {
7
+ open?: boolean;
8
+ activeUrl?: string;
9
+ placement?: string;
10
+ class?: string;
11
+ ariaLabel?: string;
12
+ onclose?: () => void;
13
+ children?: Snippet;
14
+ [key: string]: unknown;
15
+ }
16
+
17
+ let {
18
+ open = $bindable(false),
19
+ activeUrl = "",
20
+ placement = "bottom",
21
+ class: className = "",
22
+ ariaLabel = "Menu",
23
+ onclose,
24
+ children,
25
+ ...restProps
26
+ }: Props = $props();
27
+
28
+ let dropdownRef: HTMLUListElement | null = $state(null);
29
+ let containerRef: HTMLDivElement | null = $state(null);
30
+ let focusedIndex = $state(-1);
31
+ let menuItems: HTMLElement[] = $state([]);
32
+
33
+ async function updateMenuItems() {
34
+ await tick();
35
+ if (dropdownRef) {
36
+ menuItems = Array.from(dropdownRef.querySelectorAll<HTMLElement>('[role="menuitem"]:not([disabled])'));
37
+ }
38
+ }
39
+
40
+ function focusItem(index: number) {
41
+ if (menuItems.length === 0) return;
42
+ if (index < 0) index = menuItems.length - 1;
43
+ if (index >= menuItems.length) index = 0;
44
+ focusedIndex = index;
45
+ menuItems[focusedIndex]?.focus();
46
+ }
47
+
48
+ function getTriggerElement(): Element | null {
49
+ const parent = containerRef?.parentElement;
50
+ if (parent) {
51
+ const siblings = Array.from(parent.children);
52
+ const containerIndex = containerRef ? siblings.indexOf(containerRef) : -1;
53
+ if (containerIndex > 0) {
54
+ return siblings[containerIndex - 1];
55
+ }
56
+ }
57
+ return null;
58
+ }
59
+
60
+ function handleClickOutside(event: MouseEvent) {
61
+ if (!open) return;
62
+
63
+ if (dropdownRef && dropdownRef.contains(event.target as Node)) {
64
+ return;
65
+ }
66
+
67
+ const trigger = getTriggerElement();
68
+ if (trigger && trigger.contains(event.target as Node)) {
69
+ return;
70
+ }
71
+
72
+ open = false;
73
+ onclose?.();
74
+ }
75
+
76
+ function handleKeydown(event: KeyboardEvent) {
77
+ if (!open) return;
78
+
79
+ const trigger = getTriggerElement();
80
+ if (!dropdownRef?.contains(event.target as Node) && !trigger?.contains(event.target as Node)) {
81
+ return;
82
+ }
83
+
84
+ switch (event.key) {
85
+ case "Escape":
86
+ open = false;
87
+ (trigger as HTMLElement | null)?.focus();
88
+ event.preventDefault();
89
+ onclose?.();
90
+ break;
91
+ case "ArrowDown":
92
+ focusItem(focusedIndex + 1);
93
+ event.preventDefault();
94
+ break;
95
+ case "ArrowUp":
96
+ focusItem(focusedIndex - 1);
97
+ event.preventDefault();
98
+ break;
99
+ case "Home":
100
+ focusItem(0);
101
+ event.preventDefault();
102
+ break;
103
+ case "End":
104
+ focusItem(menuItems.length - 1);
105
+ event.preventDefault();
106
+ break;
107
+ case "Tab":
108
+ open = false;
109
+ onclose?.();
110
+ break;
111
+ }
112
+ }
113
+
114
+ $effect(() => {
115
+ if (open) {
116
+ focusedIndex = -1;
117
+ updateMenuItems();
118
+ }
119
+ });
120
+
121
+ onMount(() => {
122
+ document.addEventListener("mousedown", handleClickOutside, true);
123
+ document.addEventListener("keydown", handleKeydown);
124
+ });
125
+
126
+ onDestroy(() => {
127
+ if (typeof document !== "undefined") {
128
+ document.removeEventListener("mousedown", handleClickOutside, true);
129
+ document.removeEventListener("keydown", handleKeydown);
130
+ }
131
+ });
132
+
133
+ setContext("dropdown", {
134
+ get activeUrl() { return activeUrl; },
135
+ close: () => {
136
+ open = false;
137
+ onclose?.();
138
+ }
139
+ });
140
+
141
+ const placementClasses: Record<string, string> = {
142
+ bottom: "top-full left-0 mt-1",
143
+ top: "bottom-full left-0 mb-1",
144
+ left: "right-full top-0 mr-1",
145
+ right: "left-full top-0 ml-1"
146
+ };
147
+
148
+ // Map placement to transform origin for bloom animation
149
+ const placementOrigins: Record<string, string> = {
150
+ bottom: "top left",
151
+ top: "bottom left",
152
+ left: "top right",
153
+ right: "top left"
154
+ };
155
+ </script>
156
+
157
+ {#if open}
158
+ <div
159
+ bind:this={containerRef}
160
+ class="absolute z-10 bg-white divide-y divide-gray-100 rounded-lg shadow-lg w-44 dark:bg-gray-700 dark:divide-gray-600 {className}"
161
+ role="menu"
162
+ aria-label={ariaLabel}
163
+ transition:bloom={{ origin: placementOrigins[placement] || "top left" }}
164
+ {...restProps}
165
+ >
166
+ <ul bind:this={dropdownRef} class="py-2 text-sm text-gray-700 dark:text-gray-200">
167
+ {#if typeof children === 'function'}{@render children()}{:else if children}{children}{/if}
168
+ </ul>
169
+ </div>
170
+ {/if}
@@ -1,9 +1,9 @@
1
- <script lang="ts">
2
- interface Props {
3
- class?: string;
4
- }
5
-
6
- let { class: className = '' }: Props = $props();
7
- </script>
8
-
9
- <li class="my-1 border-t border-gray-200 dark:border-gray-600 {className}" role="separator" aria-hidden="true"></li>
1
+ <script lang="ts">
2
+ interface Props {
3
+ class?: string;
4
+ }
5
+
6
+ let { class: className = '' }: Props = $props();
7
+ </script>
8
+
9
+ <li class="my-1 border-t border-gray-200 dark:border-gray-600 {className}" role="separator" aria-hidden="true"></li>
@@ -1,80 +1,80 @@
1
- <script lang="ts">
2
- import { getContext } from "svelte";
3
- import type { Snippet } from 'svelte';
4
-
5
- interface Props {
6
- /** Optional href to make the item a link */
7
- href?: string;
8
- /** Whether the item is disabled */
9
- disabled?: boolean;
10
- /** Additional CSS classes */
11
- class?: string;
12
- /** Click handler callback (replaces dispatch('click')) */
13
- onclick?: (event: MouseEvent | KeyboardEvent) => void;
14
- /** Child content */
15
- children?: Snippet;
16
- }
17
-
18
- let {
19
- href = undefined,
20
- disabled = false,
21
- class: className = '',
22
- onclick,
23
- children
24
- }: Props = $props();
25
-
26
- const context = getContext<{ activeUrl?: string; close?: () => void }>("dropdown");
27
-
28
- let isActive = $derived(context?.activeUrl && href && context.activeUrl === href);
29
-
30
- function handleClick(event: MouseEvent | KeyboardEvent) {
31
- if (disabled) {
32
- event.preventDefault();
33
- return;
34
- }
35
- onclick?.(event);
36
- if (!href && context?.close) {
37
- context.close();
38
- }
39
- }
40
-
41
- function handleKeydown(event: KeyboardEvent) {
42
- if (event.key === "Enter" || event.key === " ") {
43
- handleClick(event);
44
- }
45
- }
46
-
47
- const baseClasses = "block w-full text-left px-4 py-2 text-sm hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white";
48
- const activeClasses = "bg-blue-50 text-blue-700 dark:bg-gray-600 dark:text-white";
49
- const disabledClasses = "opacity-50 cursor-not-allowed";
50
- const defaultClasses = "text-gray-700 dark:text-gray-200";
51
- </script>
52
-
53
- {#if href}
54
- <li>
55
- <a
56
- {href}
57
- class="{baseClasses} {isActive ? activeClasses : defaultClasses} {disabled ? disabledClasses : 'cursor-pointer'} {className}"
58
- role="menuitem"
59
- tabindex={disabled ? -1 : 0}
60
- onclick={handleClick}
61
- onkeydown={handleKeydown}
62
- >
63
- {@render children?.()}
64
- </a>
65
- </li>
66
- {:else}
67
- <li>
68
- <button
69
- type="button"
70
- class="{baseClasses} {defaultClasses} {disabled ? disabledClasses : 'cursor-pointer'} {className}"
71
- role="menuitem"
72
- tabindex={disabled ? -1 : 0}
73
- {disabled}
74
- onclick={handleClick}
75
- onkeydown={handleKeydown}
76
- >
77
- {@render children?.()}
78
- </button>
79
- </li>
80
- {/if}
1
+ <script lang="ts">
2
+ import { getContext } from "svelte";
3
+ import type { Snippet } from 'svelte';
4
+
5
+ interface Props {
6
+ /** Optional href to make the item a link */
7
+ href?: string;
8
+ /** Whether the item is disabled */
9
+ disabled?: boolean;
10
+ /** Additional CSS classes */
11
+ class?: string;
12
+ /** Click handler callback (replaces dispatch('click')) */
13
+ onclick?: (event: MouseEvent | KeyboardEvent) => void;
14
+ /** Child content */
15
+ children?: Snippet;
16
+ }
17
+
18
+ let {
19
+ href = undefined,
20
+ disabled = false,
21
+ class: className = '',
22
+ onclick,
23
+ children
24
+ }: Props = $props();
25
+
26
+ const context = getContext<{ activeUrl?: string; close?: () => void }>("dropdown");
27
+
28
+ let isActive = $derived(context?.activeUrl && href && context.activeUrl === href);
29
+
30
+ function handleClick(event: MouseEvent | KeyboardEvent) {
31
+ if (disabled) {
32
+ event.preventDefault();
33
+ return;
34
+ }
35
+ onclick?.(event);
36
+ if (!href && context?.close) {
37
+ context.close();
38
+ }
39
+ }
40
+
41
+ function handleKeydown(event: KeyboardEvent) {
42
+ if (event.key === "Enter" || event.key === " ") {
43
+ handleClick(event);
44
+ }
45
+ }
46
+
47
+ const baseClasses = "block w-full text-left px-4 py-2 text-sm hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white";
48
+ const activeClasses = "bg-blue-50 text-blue-700 dark:bg-gray-600 dark:text-white";
49
+ const disabledClasses = "opacity-50 cursor-not-allowed";
50
+ const defaultClasses = "text-gray-700 dark:text-gray-200";
51
+ </script>
52
+
53
+ {#if href}
54
+ <li>
55
+ <a
56
+ {href}
57
+ class="{baseClasses} {isActive ? activeClasses : defaultClasses} {disabled ? disabledClasses : 'cursor-pointer'} {className}"
58
+ role="menuitem"
59
+ tabindex={disabled ? -1 : 0}
60
+ onclick={handleClick}
61
+ onkeydown={handleKeydown}
62
+ >
63
+ {@render children?.()}
64
+ </a>
65
+ </li>
66
+ {:else}
67
+ <li>
68
+ <button
69
+ type="button"
70
+ class="{baseClasses} {defaultClasses} {disabled ? disabledClasses : 'cursor-pointer'} {className}"
71
+ role="menuitem"
72
+ tabindex={disabled ? -1 : 0}
73
+ {disabled}
74
+ onclick={handleClick}
75
+ onkeydown={handleKeydown}
76
+ >
77
+ {@render children?.()}
78
+ </button>
79
+ </li>
80
+ {/if}
@@ -1,33 +1,33 @@
1
- <script lang="ts">
2
- /**
3
- * Helper Component - Form helper/hint text
4
- *
5
- * Displays helper text below form inputs with color variants
6
- */
7
- import type { Snippet } from 'svelte';
8
-
9
- interface Props {
10
- /** Color variant */
11
- color?: 'default' | 'red' | 'green';
12
- /** Additional CSS classes */
13
- class?: string;
14
- /** Child content */
15
- children?: Snippet;
16
- }
17
-
18
- let {
19
- color = 'default',
20
- class: className = '',
21
- children
22
- }: Props = $props();
23
-
24
- const colorClasses: Record<string, string> = {
25
- default: 'text-gray-500 dark:text-gray-400',
26
- red: 'text-red-600 dark:text-red-500',
27
- green: 'text-green-600 dark:text-green-500'
28
- };
29
- </script>
30
-
31
- <p class="mt-1 text-sm {colorClasses[color]} {className}">
32
- {#if children}{@render children()}{/if}
33
- </p>
1
+ <script lang="ts">
2
+ /**
3
+ * Helper Component - Form helper/hint text
4
+ *
5
+ * Displays helper text below form inputs with color variants
6
+ */
7
+ import type { Snippet } from 'svelte';
8
+
9
+ interface Props {
10
+ /** Color variant */
11
+ color?: 'default' | 'red' | 'green';
12
+ /** Additional CSS classes */
13
+ class?: string;
14
+ /** Child content */
15
+ children?: Snippet;
16
+ }
17
+
18
+ let {
19
+ color = 'default',
20
+ class: className = '',
21
+ children
22
+ }: Props = $props();
23
+
24
+ const colorClasses: Record<string, string> = {
25
+ default: 'text-gray-500 dark:text-gray-400',
26
+ red: 'text-red-600 dark:text-red-500',
27
+ green: 'text-green-600 dark:text-green-500'
28
+ };
29
+ </script>
30
+
31
+ <p class="mt-1 text-sm {colorClasses[color]} {className}">
32
+ {#if children}{@render children()}{/if}
33
+ </p>
@@ -11,11 +11,11 @@
11
11
  fill="none"
12
12
  xmlns="http://www.w3.org/2000/svg"
13
13
  >
14
- <path
15
- d="M10.5 12C10.5 12 6.50001 9.05407 6.5 8C6.49999 6.94587 10.5 4 10.5 4"
16
- stroke={color}
17
- stroke-width="1.5"
18
- stroke-linecap="round"
19
- stroke-linejoin="round"
20
- />
21
- </svg>
14
+ <path
15
+ d="M10.5 12C10.5 12 6.50001 9.05407 6.5 8C6.49999 6.94587 10.5 4 10.5 4"
16
+ stroke={color}
17
+ stroke-width="1.5"
18
+ stroke-linecap="round"
19
+ stroke-linejoin="round"
20
+ />
21
+ </svg>
@@ -11,11 +11,11 @@
11
11
  fill="none"
12
12
  xmlns="http://www.w3.org/2000/svg"
13
13
  >
14
- <path
15
- d="M9 18L15 12L9 6"
16
- stroke={color}
17
- stroke-width="2"
18
- stroke-linecap="round"
19
- stroke-linejoin="round"
20
- />
21
- </svg>
14
+ <path
15
+ d="M9 18L15 12L9 6"
16
+ stroke={color}
17
+ stroke-width="2"
18
+ stroke-linecap="round"
19
+ stroke-linejoin="round"
20
+ />
21
+ </svg>
@@ -11,18 +11,18 @@
11
11
  fill="none"
12
12
  xmlns="http://www.w3.org/2000/svg"
13
13
  >
14
- <path
15
- d="M10.0003 18.8327C14.6027 18.8327 18.3337 15.1017 18.3337 10.4993C18.3337 5.89698 14.6027 2.16602 10.0003 2.16602C5.39795 2.16602 1.66699 5.89698 1.66699 10.4993C1.66699 15.1017 5.39795 18.8327 10.0003 18.8327Z"
16
- stroke={color}
17
- stroke-width="1.66667"
18
- stroke-linecap="round"
19
- stroke-linejoin="round"
20
- />
21
- <path
22
- d="M10 5.5V10.5L13.3333 12.1667"
23
- stroke={color}
24
- stroke-width="1.66667"
25
- stroke-linecap="round"
26
- stroke-linejoin="round"
27
- />
14
+ <path
15
+ d="M10.0003 18.8327C14.6027 18.8327 18.3337 15.1017 18.3337 10.4993C18.3337 5.89698 14.6027 2.16602 10.0003 2.16602C5.39795 2.16602 1.66699 5.89698 1.66699 10.4993C1.66699 15.1017 5.39795 18.8327 10.0003 18.8327Z"
16
+ stroke={color}
17
+ stroke-width="1.66667"
18
+ stroke-linecap="round"
19
+ stroke-linejoin="round"
20
+ />
21
+ <path
22
+ d="M10 5.5V10.5L13.3333 12.1667"
23
+ stroke={color}
24
+ stroke-width="1.66667"
25
+ stroke-linecap="round"
26
+ stroke-linejoin="round"
27
+ />
28
28
  </svg>