@getmicdrop/svelte-components 5.3.6 → 5.3.12

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 (132) hide show
  1. package/dist/calendar/AboutShow/AboutShow.svelte +9 -8
  2. package/dist/calendar/AboutShow/AboutShow.svelte.d.ts.map +1 -1
  3. package/dist/calendar/Calendar/MiniMonthCalendar.svelte +13 -12
  4. package/dist/calendar/Calendar/MiniMonthCalendar.svelte.d.ts.map +1 -1
  5. package/dist/calendar/FAQs/FAQs.svelte +6 -5
  6. package/dist/calendar/FAQs/FAQs.svelte.d.ts.map +1 -1
  7. package/dist/calendar/MonthSwitcher/MonthSwitcher.svelte +3 -2
  8. package/dist/calendar/MonthSwitcher/MonthSwitcher.svelte.d.ts.map +1 -1
  9. package/dist/calendar/OrderSummary/OrderSummary.svelte +69 -28
  10. package/dist/calendar/OrderSummary/OrderSummary.svelte.d.ts +2 -0
  11. package/dist/calendar/OrderSummary/OrderSummary.svelte.d.ts.map +1 -1
  12. package/dist/calendar/PublicCard/PublicCard.svelte +7 -9
  13. package/dist/calendar/PublicCard/PublicCard.svelte.d.ts.map +1 -1
  14. package/dist/calendar/ShowCard/ShowCard.svelte +11 -10
  15. package/dist/calendar/ShowCard/ShowCard.svelte.d.ts.map +1 -1
  16. package/dist/calendar/ShowTimeCard/ShowTimeCard.svelte +5 -3
  17. package/dist/calendar/ShowTimeCard/ShowTimeCard.svelte.d.ts.map +1 -1
  18. package/dist/components/Layout/Section.svelte +4 -4
  19. package/dist/components/Layout/Section.svelte.d.ts.map +1 -1
  20. package/dist/index.d.ts +3 -0
  21. package/dist/index.js +9 -0
  22. package/dist/patterns/data/DataTable.svelte +4 -2
  23. package/dist/patterns/data/DataTable.svelte.d.ts.map +1 -1
  24. package/dist/patterns/forms/FormSection.svelte +4 -2
  25. package/dist/patterns/forms/FormSection.svelte.d.ts.map +1 -1
  26. package/dist/patterns/navigation/BottomNav.svelte +4 -3
  27. package/dist/patterns/navigation/BottomNav.svelte.d.ts.map +1 -1
  28. package/dist/patterns/navigation/Header.svelte +11 -10
  29. package/dist/patterns/navigation/Header.svelte.d.ts.map +1 -1
  30. package/dist/patterns/page/PageHeader.svelte +3 -2
  31. package/dist/patterns/page/PageHeader.svelte.d.ts.map +1 -1
  32. package/dist/patterns/page/PageLayout.svelte +2 -1
  33. package/dist/patterns/page/PageLayout.svelte.d.ts.map +1 -1
  34. package/dist/patterns/page/PageLoader.svelte +2 -1
  35. package/dist/patterns/page/PageLoader.svelte.d.ts.map +1 -1
  36. package/dist/patterns/page/SectionHeader.svelte +5 -3
  37. package/dist/patterns/page/SectionHeader.svelte.d.ts.map +1 -1
  38. package/dist/primitives/Accordion/Accordion.svelte +2 -1
  39. package/dist/primitives/Accordion/Accordion.svelte.d.ts.map +1 -1
  40. package/dist/primitives/Accordion/AccordionItem.svelte +6 -5
  41. package/dist/primitives/Accordion/AccordionItem.svelte.d.ts.map +1 -1
  42. package/dist/primitives/BottomSheet/BottomSheet.svelte +2 -1
  43. package/dist/primitives/BottomSheet/BottomSheet.svelte.d.ts.map +1 -1
  44. package/dist/primitives/Breadcrumb/Breadcrumb.svelte +6 -5
  45. package/dist/primitives/Breadcrumb/Breadcrumb.svelte.d.ts.map +1 -1
  46. package/dist/primitives/Button/Button.svelte +27 -10
  47. package/dist/primitives/Button/Button.svelte.d.ts.map +1 -1
  48. package/dist/primitives/Button/ButtonSaveDemo.svelte +2 -1
  49. package/dist/primitives/Button/ButtonSaveDemo.svelte.d.ts.map +1 -1
  50. package/dist/primitives/Card.svelte +1 -1
  51. package/dist/primitives/Checkbox/Checkbox.svelte +8 -8
  52. package/dist/primitives/DarkModeToggle.svelte +43 -44
  53. package/dist/primitives/DarkModeToggle.svelte.d.ts.map +1 -1
  54. package/dist/primitives/Drawer/Drawer.svelte +121 -47
  55. package/dist/primitives/Drawer/Drawer.svelte.d.ts +4 -0
  56. package/dist/primitives/Drawer/Drawer.svelte.d.ts.map +1 -1
  57. package/dist/primitives/Icons/ImageOutline.svelte +19 -0
  58. package/dist/primitives/Icons/ImageOutline.svelte.d.ts +12 -0
  59. package/dist/primitives/Icons/ImageOutline.svelte.d.ts.map +1 -0
  60. package/dist/primitives/Icons/TrashBinOutline.svelte +19 -0
  61. package/dist/primitives/Icons/TrashBinOutline.svelte.d.ts +12 -0
  62. package/dist/primitives/Icons/TrashBinOutline.svelte.d.ts.map +1 -0
  63. package/dist/primitives/Icons/index.d.ts +2 -0
  64. package/dist/primitives/Icons/index.js +2 -0
  65. package/dist/primitives/Input/Input.svelte +41 -80
  66. package/dist/primitives/Input/Input.svelte.d.ts +4 -6
  67. package/dist/primitives/Input/Input.svelte.d.ts.map +1 -1
  68. package/dist/primitives/Input/Select.svelte +66 -13
  69. package/dist/primitives/Input/Select.svelte.d.ts +2 -0
  70. package/dist/primitives/Input/Select.svelte.d.ts.map +1 -1
  71. package/dist/primitives/Input/Textarea.svelte +5 -3
  72. package/dist/primitives/Input/Textarea.svelte.d.ts.map +1 -1
  73. package/dist/primitives/Modal/Modal.svelte +13 -1
  74. package/dist/primitives/Modal/Modal.svelte.d.ts.map +1 -1
  75. package/dist/primitives/Pagination/Pagination.svelte +3 -2
  76. package/dist/primitives/Pagination/Pagination.svelte.d.ts.map +1 -1
  77. package/dist/primitives/Radio/Radio.svelte +7 -7
  78. package/dist/primitives/Tabs/Tabs.svelte +4 -3
  79. package/dist/primitives/Tabs/Tabs.svelte.d.ts.map +1 -1
  80. package/dist/recipes/CropImage/CropImage.svelte +10 -5
  81. package/dist/recipes/CropImage/CropImage.svelte.d.ts.map +1 -1
  82. package/dist/recipes/ImageUploader/ImageUploader.stories.svelte +125 -0
  83. package/dist/recipes/ImageUploader/ImageUploader.stories.svelte.d.ts +28 -0
  84. package/dist/recipes/ImageUploader/ImageUploader.stories.svelte.d.ts.map +1 -0
  85. package/dist/recipes/ImageUploader/ImageUploader.svelte +980 -0
  86. package/dist/recipes/ImageUploader/ImageUploader.svelte.d.ts +62 -0
  87. package/dist/recipes/ImageUploader/ImageUploader.svelte.d.ts.map +1 -0
  88. package/dist/recipes/SuperLogin/SuperLogin.svelte +37 -40
  89. package/dist/recipes/SuperLogin/SuperLogin.svelte.d.ts.map +1 -1
  90. package/dist/recipes/feedback/EmptyState/EmptyState.svelte +3 -2
  91. package/dist/recipes/feedback/EmptyState/EmptyState.svelte.d.ts.map +1 -1
  92. package/dist/recipes/fields/CheckboxField.svelte +3 -2
  93. package/dist/recipes/fields/CheckboxField.svelte.d.ts.map +1 -1
  94. package/dist/recipes/fields/FormField.svelte +12 -4
  95. package/dist/recipes/fields/FormField.svelte.d.ts +3 -1
  96. package/dist/recipes/fields/FormField.svelte.d.ts.map +1 -1
  97. package/dist/recipes/fields/RadioGroup.svelte +13 -4
  98. package/dist/recipes/fields/RadioGroup.svelte.d.ts +4 -1
  99. package/dist/recipes/fields/RadioGroup.svelte.d.ts.map +1 -1
  100. package/dist/recipes/fields/SelectField.svelte +12 -3
  101. package/dist/recipes/fields/SelectField.svelte.d.ts +4 -1
  102. package/dist/recipes/fields/SelectField.svelte.d.ts.map +1 -1
  103. package/dist/recipes/fields/TextareaField.svelte +2 -1
  104. package/dist/recipes/fields/TextareaField.svelte.d.ts.map +1 -1
  105. package/dist/recipes/fields/ToggleField.svelte +3 -2
  106. package/dist/recipes/fields/ToggleField.svelte.d.ts.map +1 -1
  107. package/dist/recipes/inputs/MultiSelect.svelte +9 -8
  108. package/dist/recipes/inputs/MultiSelect.svelte.d.ts.map +1 -1
  109. package/dist/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.svelte +9 -9
  110. package/dist/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.svelte.d.ts.map +1 -1
  111. package/dist/recipes/inputs/Search.svelte +7 -6
  112. package/dist/recipes/inputs/Search.svelte.d.ts.map +1 -1
  113. package/dist/recipes/modals/AlertModal.svelte +3 -2
  114. package/dist/recipes/modals/AlertModal.svelte.d.ts.map +1 -1
  115. package/dist/recipes/modals/ConfirmationModal.svelte +6 -4
  116. package/dist/recipes/modals/ConfirmationModal.svelte.d.ts.map +1 -1
  117. package/dist/recipes/modals/InputModal.svelte +9 -8
  118. package/dist/recipes/modals/InputModal.svelte.d.ts.map +1 -1
  119. package/dist/recipes/modals/ModalStateManager.svelte +4 -3
  120. package/dist/recipes/modals/ModalStateManager.svelte.d.ts.map +1 -1
  121. package/dist/recipes/modals/StatusModal.svelte +5 -4
  122. package/dist/recipes/modals/StatusModal.svelte.d.ts.map +1 -1
  123. package/dist/stories/ButtonAuditReview.svelte +361 -397
  124. package/dist/stories/ButtonAuditReview.svelte.d.ts +24 -4
  125. package/dist/stories/ButtonAuditReview.svelte.d.ts.map +1 -1
  126. package/dist/tokens/index.d.ts +4 -8
  127. package/dist/tokens/index.d.ts.map +1 -1
  128. package/dist/tokens/index.js +4 -8
  129. package/dist/tokens/typography.d.ts +76 -169
  130. package/dist/tokens/typography.d.ts.map +1 -1
  131. package/dist/tokens/typography.js +93 -62
  132. package/package.json +4 -2
@@ -2,11 +2,17 @@
2
2
  /**
3
3
  * Input Component - Flowbite Native
4
4
  * Migrated to Svelte 5 runes
5
+ *
6
+ * NOTE: This component does NOT perform any validation.
7
+ * All validation should be handled externally (e.g., via Zod schemas).
8
+ * Use the `errorText` prop to display validation errors.
9
+ * Use the `color` prop ('red' | 'base') to style the border.
5
10
  */
6
11
  import { slide } from "svelte/transition";
7
12
  import { cubicOut } from "svelte/easing";
8
13
  import { onDestroy } from "svelte";
9
14
  import { EyeOutline, EyeSlashOutline, CloseCircleOutline, ExclamationCircleOutline } from "../Icons";
15
+ import { typography } from "../../tokens/typography";
10
16
 
11
17
  /** @type {{
12
18
  required?: boolean,
@@ -26,6 +32,7 @@
26
32
  size?: 'sm' | 'md' | 'lg',
27
33
  textareaSize?: string,
28
34
  errorText?: string,
35
+ color?: 'base' | 'red',
29
36
  helperText?: string,
30
37
  helperIcon?: string,
31
38
  hintText?: string,
@@ -34,7 +41,7 @@
34
41
  readonly?: boolean,
35
42
  controlled?: boolean,
36
43
  onButtonClick?: ((value: string) => void) | null,
37
- value?: string,
44
+ value?: string | number | null,
38
45
  autocomplete?: string | null,
39
46
  autofocus?: boolean,
40
47
  showPasswordToggle?: boolean,
@@ -43,8 +50,6 @@
43
50
  statusType?: string,
44
51
  buttonDisabled?: boolean,
45
52
  inputmode?: string | null,
46
- showErrors?: boolean,
47
- disableBuiltInValidation?: boolean,
48
53
  instantSearch?: boolean,
49
54
  debounceMs?: number,
50
55
  minSearchChars?: number,
@@ -74,6 +79,7 @@
74
79
  size = "md",
75
80
  textareaSize = "",
76
81
  errorText = "",
82
+ color = "base",
77
83
  helperText = "",
78
84
  helperIcon = "",
79
85
  hintText = "",
@@ -91,8 +97,6 @@
91
97
  statusType = "",
92
98
  buttonDisabled = false,
93
99
  inputmode = null,
94
- showErrors = false,
95
- disableBuiltInValidation = false,
96
100
  instantSearch = false,
97
101
  debounceMs = 250,
98
102
  minSearchChars = 2,
@@ -136,10 +140,11 @@
136
140
  }
137
141
  }
138
142
 
139
- let touched = $state(false);
140
- let displayErrorText = $state("");
141
143
  let isPasswordVisible = $state(false);
142
144
 
145
+ // Error state derived from color prop or errorText
146
+ let hasError = $derived(color === 'red' || Boolean(errorText));
147
+
143
148
  let inputType = $derived(showPasswordToggle && isPasswordVisible ? "text" : type);
144
149
  let shouldAnimate = $derived(animateFocus && !disabled && !readonly);
145
150
 
@@ -157,16 +162,16 @@
157
162
 
158
163
  const handleInput = (event) => {
159
164
  inputValue = event.target.value;
160
- let rawInput = inputValue;
161
165
 
166
+ // Format special input types
162
167
  if (type === "creditCardNumber") {
163
- rawInput = inputValue.replace(/\D/g, "");
168
+ const rawInput = inputValue.replace(/\D/g, "");
164
169
  inputValue = formatCreditCardNumber(rawInput);
165
170
  event.target.value = inputValue;
166
171
  }
167
172
 
168
173
  if (type === "phoneNumber") {
169
- rawInput = inputValue.replace(/\D/g, "");
174
+ const rawInput = inputValue.replace(/\D/g, "");
170
175
  inputValue = formatPhoneNumber(rawInput);
171
176
  event.target.value = inputValue;
172
177
  }
@@ -182,35 +187,6 @@
182
187
  sanitized = sanitized.replace(/[^A-Za-z0-9._]/g, "");
183
188
  inputValue = sanitized;
184
189
  event.target.value = inputValue;
185
- rawInput = sanitized;
186
- }
187
-
188
- if (type === "email") {
189
- if (!isValidEmail(inputValue)) {
190
- displayErrorText = errorText;
191
- } else {
192
- displayErrorText = "";
193
- }
194
- }
195
-
196
- if (type === "password") {
197
- if (!isStrongPassword(inputValue)) {
198
- displayErrorText = "Password must be at least 8 characters long and include uppercase, lowercase, a number, and a special character.";
199
- } else {
200
- displayErrorText = "";
201
- }
202
- }
203
-
204
- if (minlength !== null && rawInput.length < minlength) {
205
- displayErrorText = errorText;
206
- } else {
207
- displayErrorText = "";
208
- }
209
-
210
- if (!disableBuiltInValidation && required && !inputValue.trim()) {
211
- displayErrorText = "This field is required.";
212
- } else if (!disableBuiltInValidation) {
213
- displayErrorText = "";
214
190
  }
215
191
 
216
192
  value = inputValue;
@@ -218,13 +194,15 @@
218
194
  // Call oninputchange callback if provided
219
195
  oninputchange?.(inputValue);
220
196
 
197
+ // Handle instant search
221
198
  if (instantSearch) {
199
+ const inputValueStr = inputValue ?? '';
222
200
  clearTimeout(debounceTimer);
223
- if (inputValue.length === 0) {
201
+ if (inputValueStr.length === 0) {
224
202
  onsearch?.({ query: '' });
225
203
  return;
226
204
  }
227
- if (inputValue.length >= minSearchChars) {
205
+ if (inputValueStr.length >= minSearchChars) {
228
206
  debounceTimer = setTimeout(() => {
229
207
  onsearch?.({ query: inputValue });
230
208
  }, debounceMs);
@@ -260,15 +238,6 @@
260
238
  clearTimeout(debounceTimer);
261
239
  });
262
240
 
263
- const isStrongPassword = (password) => {
264
- const minLength = 8;
265
- const hasUpperCase = /[A-Z]/.test(password);
266
- const hasLowerCase = /[a-z]/.test(password);
267
- const hasNumber = /[0-9]/.test(password);
268
- const hasSpecialChar = /[!@#$%^&*]/.test(password);
269
- return password.length >= minLength && hasUpperCase && hasLowerCase && hasNumber && hasSpecialChar;
270
- };
271
-
272
241
  const formatCreditCardNumber = (value) => {
273
242
  return value.replace(/\D/g, "").replace(/(.{4})/g, "$1 ").trim();
274
243
  };
@@ -283,29 +252,13 @@
283
252
  };
284
253
 
285
254
  const handleBlur = () => {
286
- touched = true;
287
255
  onblur?.();
288
- if (disableBuiltInValidation) return;
289
- if (required && !inputValue.trim()) {
290
- displayErrorText = "This field is required.";
291
- } else if (type === "email" && !isValidEmail(inputValue)) {
292
- displayErrorText = errorText;
293
- } else if (minlength !== null && inputValue.length < minlength) {
294
- displayErrorText = errorText;
295
- } else {
296
- displayErrorText = "";
297
- }
298
256
  };
299
257
 
300
258
  const handleFocus = () => {
301
259
  onfocus?.();
302
260
  };
303
261
 
304
- const isValidEmail = (email) => {
305
- const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
306
- return re.test(String(email).toLowerCase());
307
- };
308
-
309
262
  const getContentFloatClass = () => {
310
263
  switch (contentFloat) {
311
264
  case "center": return "text-center";
@@ -328,23 +281,19 @@
328
281
  onButtonClick(inputValue);
329
282
  }
330
283
  };
331
-
332
- $effect(() => {
333
- displayErrorText = errorText || (touched && !disableBuiltInValidation && (errorText || (required && !inputValue.trim() ? "This field is required." : "")));
334
- });
335
284
  </script>
336
285
 
337
286
  <div class="flex flex-col gap-2 {className}" {...restProps}>
338
287
  {#if label}
339
288
  <div class="flex justify-start items-center gap-1">
340
- <label for={id} class="text-sm font-medium text-gray-900 dark:text-white leading-tight sm:leading-none">
289
+ <label for={id} class={`${typography.label} leading-tight sm:leading-none`}>
341
290
  {label}{#if required}<span class="text-red-500 font-medium text-sm ml-0.5">*</span>{/if}
342
291
  </label>
343
292
  {#if statusText}
344
293
  <span class="text-sm font-medium {statusType === 'success' ? 'text-green-600' : statusType === 'error' ? 'text-red-500' : ''}">({statusText})</span>
345
294
  {/if}
346
295
  {#if optional}
347
- <span class="text-sm text-gray-500 dark:text-gray-400">(optional)</span>
296
+ <span class={typography.smMuted}>(optional)</span>
348
297
  {/if}
349
298
  </div>
350
299
  {/if}
@@ -360,7 +309,7 @@
360
309
  onfocus={handleFocus}
361
310
  {maxlength}
362
311
  {minlength}
363
- class="w-full px-3 py-2 bg-gray-50 dark:bg-gray-700 border rounded-lg text-sm font-medium text-gray-900 dark:text-white placeholder-gray-500 dark:placeholder-gray-400 transition-all focus:outline-none focus:ring-4 focus:ring-blue-300 dark:focus:ring-blue-800 resize-y {displayErrorText ? 'border-red-500' : 'border-gray-300 dark:border-gray-600 hover:border-blue-500 focus:border-blue-500'} {getContentFloatClass()} {getTextareaSizeClass()} {shouldAnimate ? 'focus:scale-[1.01]' : ''}"
312
+ class="{typography.sm} w-full px-3 py-2 bg-gray-50 dark:bg-gray-800 border rounded-lg font-medium placeholder-gray-500 dark:placeholder-gray-400 transition-all focus:outline-none focus:ring-4 focus:ring-blue-300 dark:focus:ring-blue-800 resize-y {hasError ? 'border-red-500' : 'border-gray-300 dark:border-gray-600 hover:border-blue-500 focus:border-blue-500'} {getContentFloatClass()} {getTextareaSizeClass()} {shouldAnimate ? 'focus:scale-[1.01]' : ''}"
364
313
  required={false}
365
314
  {disabled}
366
315
  {readonly}
@@ -368,7 +317,7 @@
368
317
  aria-required={required}
369
318
  ></textarea>
370
319
  {:else if type === "password" && showPasswordToggle}
371
- <div class="flex items-center w-full bg-gray-50 dark:bg-gray-700 border rounded-lg transition-all outline-none focus-within:ring-4 focus-within:ring-blue-300 dark:focus-within:ring-blue-800 {displayErrorText ? 'border-red-500' : 'border-gray-300 dark:border-gray-600 hover:border-blue-500 focus-within:border-blue-500'} {shouldAnimate ? 'focus-within:scale-[1.01]' : ''}">
320
+ <div class="flex items-center w-full bg-gray-50 dark:bg-gray-800 border rounded-lg transition-all outline-none focus-within:ring-4 focus-within:ring-blue-300 dark:focus-within:ring-blue-800 {hasError ? 'border-red-500' : 'border-gray-300 dark:border-gray-600 hover:border-blue-500 focus-within:border-blue-500'} {shouldAnimate ? 'focus-within:scale-[1.01]' : ''}">
372
321
  <input
373
322
  bind:this={inputElement}
374
323
  {id}
@@ -382,7 +331,7 @@
382
331
  onfocus={handleFocus}
383
332
  {maxlength}
384
333
  {minlength}
385
- class="flex-1 w-full {sizeClass} bg-transparent border-none text-gray-900 dark:text-white font-medium text-sm placeholder-gray-500 dark:placeholder-gray-400 focus:outline-none focus:ring-0 {getContentFloatClass()}"
334
+ class="{typography.sm} flex-1 w-full {sizeClass} bg-transparent border-none font-medium placeholder-gray-500 dark:placeholder-gray-400 focus:outline-none focus:ring-0 {getContentFloatClass()}"
386
335
  required={false}
387
336
  {disabled}
388
337
  {readonly}
@@ -426,7 +375,7 @@
426
375
  onkeydown={handleSearchKeyDown}
427
376
  {maxlength}
428
377
  {minlength}
429
- class="w-full {sizeClass} bg-gray-50 dark:bg-gray-700 border rounded-lg font-medium text-gray-900 dark:text-white placeholder-gray-500 dark:placeholder-gray-400 transition-all focus:outline-none focus:ring-4 focus:ring-blue-300 dark:focus:ring-blue-800 {displayErrorText ? 'border-red-500' : 'border-gray-300 dark:border-gray-600 hover:border-blue-500 focus:border-blue-500'} {icon || (showClearButton && inputValue) ? 'pr-10' : ''} {leftIcon ? 'pl-10' : ''} {getContentFloatClass()} {shouldAnimate ? 'focus:scale-[1.01]' : ''} {disabled ? 'opacity-50 cursor-not-allowed' : ''}"
378
+ class="{typography.body} w-full {sizeClass} bg-gray-50 dark:bg-gray-800 border rounded-lg font-medium placeholder-gray-500 dark:placeholder-gray-400 transition-all focus:outline-none focus:ring-4 focus:ring-blue-300 dark:focus:ring-blue-800 {hasError ? 'border-red-500' : 'border-gray-300 dark:border-gray-600 hover:border-blue-500 focus:border-blue-500'} {icon || (showClearButton && inputValue) ? 'pr-10' : ''} {leftIcon ? 'pl-10' : ''} {getContentFloatClass()} {shouldAnimate ? 'focus:scale-[1.01]' : ''} {disabled ? 'opacity-50 cursor-not-allowed' : ''}"
430
379
  required={false}
431
380
  {disabled}
432
381
  {readonly}
@@ -450,7 +399,7 @@
450
399
  type="button"
451
400
  onclick={handleButtonClick}
452
401
  disabled={buttonDisabled}
453
- class="absolute inset-y-0 right-0 gap-1 flex items-center justify-center px-4 text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300 disabled:opacity-50 disabled:cursor-not-allowed {helperText || hintText || displayErrorText ? 'mb-7' : ''}"
402
+ class="absolute inset-y-0 right-0 gap-1 flex items-center justify-center px-4 text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300 disabled:opacity-50 disabled:cursor-not-allowed {helperText || hintText || errorText ? 'mb-7' : ''}"
454
403
  >
455
404
  {#if buttonIcon}
456
405
  <img src={buttonIcon} alt="Button Icon" class="w-5 h-5" />
@@ -466,13 +415,13 @@
466
415
  </div>
467
416
  {/if}
468
417
 
469
- {#if displayErrorText && (touched || showErrors)}
418
+ {#if errorText}
470
419
  <div transition:slide={{ duration: 300, easing: cubicOut }} class="flex items-start gap-1.5 mt-2" role="alert" aria-live="assertive">
471
420
  <ExclamationCircleOutline class="w-4 h-4 shrink-0 text-red-500 mt-0.5" />
472
- <p class="text-sm text-red-500">{displayErrorText}</p>
421
+ <p class={typography.error}>{errorText}</p>
473
422
  </div>
474
423
  {:else if helperText || hintText}
475
- <div class="mt-2 flex items-center text-xs text-gray-500 dark:text-gray-400 opacity-65">
424
+ <div class={`mt-2 flex items-center ${typography.xsMuted} opacity-65`}>
476
425
  {#if helperIcon || hintIcon}
477
426
  <img src={helperIcon || hintIcon} alt="Helper icon" class="w-4 h-4 mr-2" />
478
427
  {/if}
@@ -481,3 +430,15 @@
481
430
  {/if}
482
431
  </div>
483
432
  </div>
433
+
434
+ <style>
435
+ /* Hide number input spinners globally */
436
+ :global(input[type="number"]::-webkit-outer-spin-button),
437
+ :global(input[type="number"]::-webkit-inner-spin-button) {
438
+ -webkit-appearance: none;
439
+ margin: 0;
440
+ }
441
+ :global(input[type="number"]) {
442
+ -moz-appearance: textfield;
443
+ }
444
+ </style>
@@ -20,6 +20,7 @@ type Input = {
20
20
  size?: "sm" | "md" | "lg" | undefined;
21
21
  textareaSize?: string | undefined;
22
22
  errorText?: string | undefined;
23
+ color?: "red" | "base" | undefined;
23
24
  helperText?: string | undefined;
24
25
  helperIcon?: string | undefined;
25
26
  hintText?: string | undefined;
@@ -28,7 +29,7 @@ type Input = {
28
29
  readonly?: boolean | undefined;
29
30
  controlled?: boolean | undefined;
30
31
  onButtonClick?: ((value: string) => void) | null | undefined;
31
- value?: string | undefined;
32
+ value?: string | number | null | undefined;
32
33
  autocomplete?: string | null | undefined;
33
34
  autofocus?: boolean | undefined;
34
35
  showPasswordToggle?: boolean | undefined;
@@ -37,8 +38,6 @@ type Input = {
37
38
  statusType?: string | undefined;
38
39
  buttonDisabled?: boolean | undefined;
39
40
  inputmode?: string | null | undefined;
40
- showErrors?: boolean | undefined;
41
- disableBuiltInValidation?: boolean | undefined;
42
41
  instantSearch?: boolean | undefined;
43
42
  debounceMs?: number | undefined;
44
43
  minSearchChars?: number | undefined;
@@ -71,6 +70,7 @@ declare const Input: import("svelte").Component<{
71
70
  size?: "sm" | "md" | "lg";
72
71
  textareaSize?: string;
73
72
  errorText?: string;
73
+ color?: "base" | "red";
74
74
  helperText?: string;
75
75
  helperIcon?: string;
76
76
  hintText?: string;
@@ -79,7 +79,7 @@ declare const Input: import("svelte").Component<{
79
79
  readonly?: boolean;
80
80
  controlled?: boolean;
81
81
  onButtonClick?: ((value: string) => void) | null;
82
- value?: string;
82
+ value?: string | number | null;
83
83
  autocomplete?: string | null;
84
84
  autofocus?: boolean;
85
85
  showPasswordToggle?: boolean;
@@ -88,8 +88,6 @@ declare const Input: import("svelte").Component<{
88
88
  statusType?: string;
89
89
  buttonDisabled?: boolean;
90
90
  inputmode?: string | null;
91
- showErrors?: boolean;
92
- disableBuiltInValidation?: boolean;
93
91
  instantSearch?: boolean;
94
92
  debounceMs?: number;
95
93
  minSearchChars?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"Input.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/primitives/Input/Input.svelte.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkdA;;eA/Ce,OAAO;eACP,OAAO;eACP,OAAO;WACX,MAAM,GAAG,IAAI;iBACP,MAAM,GAAG,IAAI;iBACb,MAAM,GAAG,IAAI;gBACd,MAAM,GAAG,IAAI;gBACb,MAAM,GAAG,IAAI;WAClB,MAAM;kBACC,MAAM;YACZ,MAAM;SACT,MAAM;WACJ,MAAM;gBACD,MAAM;WACX,IAAI,GAAG,IAAI,GAAG,IAAI;mBACV,MAAM;gBACT,MAAM;iBACL,MAAM;iBACN,MAAM;eACR,MAAM;eACN,MAAM;mBACF,MAAM;eACV,OAAO;iBACL,OAAO;oBACJ,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,IAAI;YACxC,MAAM;mBACC,MAAM,GAAG,IAAI;gBAChB,OAAO;yBACE,OAAO;mBACb,OAAO;iBACT,MAAM;iBACN,MAAM;qBACF,OAAO;gBACZ,MAAM,GAAG,IAAI;iBACZ,OAAO;+BACO,OAAO;oBAClB,OAAO;iBACV,MAAM;qBACF,MAAM;sBACL,OAAO;eACd,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI;cACpC,MAAM,IAAI;aACX,MAAM,IAAI;oBACH,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI;eAC5B,GAAG;gBAGkC"}
1
+ {"version":3,"file":"Input.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/primitives/Input/Input.svelte.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiaA;;eA9Ce,OAAO;eACP,OAAO;eACP,OAAO;WACX,MAAM,GAAG,IAAI;iBACP,MAAM,GAAG,IAAI;iBACb,MAAM,GAAG,IAAI;gBACd,MAAM,GAAG,IAAI;gBACb,MAAM,GAAG,IAAI;WAClB,MAAM;kBACC,MAAM;YACZ,MAAM;SACT,MAAM;WACJ,MAAM;gBACD,MAAM;WACX,IAAI,GAAG,IAAI,GAAG,IAAI;mBACV,MAAM;gBACT,MAAM;YACV,MAAM,GAAG,KAAK;iBACT,MAAM;iBACN,MAAM;eACR,MAAM;eACN,MAAM;mBACF,MAAM;eACV,OAAO;iBACL,OAAO;oBACJ,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,IAAI;YACxC,MAAM,GAAG,MAAM,GAAG,IAAI;mBACf,MAAM,GAAG,IAAI;gBAChB,OAAO;yBACE,OAAO;mBACb,OAAO;iBACT,MAAM;iBACN,MAAM;qBACF,OAAO;gBACZ,MAAM,GAAG,IAAI;oBACT,OAAO;iBACV,MAAM;qBACF,MAAM;sBACL,OAAO;eACd,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI;cACpC,MAAM,IAAI;aACX,MAAM,IAAI;oBACH,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI;eAC5B,GAAG;gBAGkC"}
@@ -1,6 +1,8 @@
1
1
  <script>
2
- import { onMount } from "svelte";
3
- import { ChevronDownOutline, CheckOutline } from "../Icons";
2
+ import { onMount, tick } from "svelte";
3
+ import { ChevronDownOutline } from "../Icons";
4
+ import { portal as portalAction } from "../../utils/portal.js";
5
+ import { typography } from "../../tokens/typography";
4
6
 
5
7
  let {
6
8
  value = $bindable(""),
@@ -13,6 +15,7 @@
13
15
  name = "",
14
16
  id = "",
15
17
  size = "md",
18
+ portal = false,
16
19
  onchange,
17
20
  ...restProps
18
21
  } = $props();
@@ -21,6 +24,7 @@
21
24
  let triggerElement = $state(null);
22
25
  let dropdownElement = $state(null);
23
26
  let focusedIndex = $state(-1);
27
+ let dropdownPosition = $state({ top: 0, left: 0, width: 0 });
24
28
 
25
29
  const instanceId = Math.random().toString(36).substring(2, 9);
26
30
 
@@ -35,12 +39,26 @@
35
39
 
36
40
  let sizeClass = $derived(sizeClasses[size] || sizeClasses.md);
37
41
 
38
- function toggle() {
42
+ function updateDropdownPosition() {
43
+ if (!triggerElement || !portal) return;
44
+ const rect = triggerElement.getBoundingClientRect();
45
+ dropdownPosition = {
46
+ top: rect.bottom + 4,
47
+ left: rect.left,
48
+ width: rect.width
49
+ };
50
+ }
51
+
52
+ async function toggle() {
39
53
  if (disabled) return;
40
54
  isOpen = !isOpen;
41
55
  if (isOpen) {
42
56
  focusedIndex = items.findIndex((item) => item.value === value);
43
57
  window.dispatchEvent(new CustomEvent('select-opened', { detail: { instanceId } }));
58
+ if (portal) {
59
+ await tick();
60
+ updateDropdownPosition();
61
+ }
44
62
  }
45
63
  }
46
64
 
@@ -112,9 +130,20 @@
112
130
  onMount(() => {
113
131
  document.addEventListener("click", handleClickOutside, true);
114
132
  window.addEventListener("select-opened", handleOtherSelectOpened);
133
+
134
+ // Update position on scroll/resize when portal is enabled
135
+ if (portal) {
136
+ window.addEventListener("scroll", updateDropdownPosition, true);
137
+ window.addEventListener("resize", updateDropdownPosition);
138
+ }
139
+
115
140
  return () => {
116
141
  document.removeEventListener("click", handleClickOutside, true);
117
142
  window.removeEventListener("select-opened", handleOtherSelectOpened);
143
+ if (portal) {
144
+ window.removeEventListener("scroll", updateDropdownPosition, true);
145
+ window.removeEventListener("resize", updateDropdownPosition);
146
+ }
118
147
  };
119
148
  });
120
149
  </script>
@@ -122,7 +151,7 @@
122
151
  <div class="w-full flex flex-col gap-2" {...restProps}>
123
152
  {#if label}
124
153
  <div class="flex justify-start items-center gap-1">
125
- <label for={id || name} class="text-sm font-medium text-gray-900 dark:text-white">
154
+ <label for={id || name} class={typography.label}>
126
155
  {label}{#if required}<span class="text-red-500 font-medium text-sm ml-0.5">*</span>{/if}
127
156
  </label>
128
157
  </div>
@@ -134,7 +163,7 @@
134
163
  bind:this={triggerElement}
135
164
  {id}
136
165
  {name}
137
- class="flex items-center justify-between w-full {sizeClass} bg-gray-50 dark:bg-gray-700 border rounded-lg cursor-pointer transition-colors text-left focus:outline-none focus:ring-4 focus:ring-blue-300 dark:focus:ring-blue-800 {error ? 'border-red-500 dark:border-red-500' : 'border-gray-300 dark:border-gray-600 hover:border-blue-500 dark:hover:border-blue-500'} {disabled ? 'opacity-50 cursor-not-allowed' : ''} {!selectedItem ? 'text-gray-500 dark:text-gray-400' : 'text-gray-900 dark:text-white'}"
166
+ class="flex items-center justify-between w-full {sizeClass} bg-gray-50 dark:bg-gray-800 border rounded-lg cursor-pointer transition-colors text-left focus:outline-none focus:ring-4 focus:ring-blue-300 dark:focus:ring-blue-800 {error ? 'border-red-500 dark:border-red-500' : 'border-gray-300 dark:border-gray-600 hover:border-blue-500 dark:hover:border-blue-500'} {disabled ? 'opacity-50 cursor-not-allowed' : ''} {!selectedItem ? `${typography.textMuted}` : `${typography.body}`}"
138
167
  {disabled}
139
168
  aria-haspopup="listbox"
140
169
  aria-expanded={isOpen}
@@ -142,10 +171,10 @@
142
171
  onkeydown={handleKeydown}
143
172
  >
144
173
  <span class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap">{displayText}</span>
145
- <ChevronDownOutline class="w-4 h-4 shrink-0 text-gray-500 dark:text-gray-400 transition-transform duration-200 {isOpen ? 'rotate-180' : ''}" />
174
+ <ChevronDownOutline class="w-4 h-4 shrink-0 {typography.iconMuted} transition-transform duration-200 {isOpen ? 'rotate-180' : ''}" />
146
175
  </button>
147
176
 
148
- {#if isOpen}
177
+ {#if isOpen && !portal}
149
178
  <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
150
179
  <ul
151
180
  bind:this={dropdownElement}
@@ -157,16 +186,13 @@
157
186
  <!-- svelte-ignore a11y_click_events_have_key_events -->
158
187
  <li
159
188
  id="{id || name}-option-{index}"
160
- class="flex items-center justify-between px-4 py-2 cursor-pointer text-sm transition-colors {item.value === value ? 'font-semibold text-gray-900 dark:text-white' : 'text-gray-700 dark:text-gray-300'} {index === focusedIndex ? 'bg-gray-100 dark:bg-gray-600' : 'hover:bg-gray-100 dark:hover:bg-gray-600'}"
189
+ class={`px-4 py-2 cursor-pointer ${typography.sm} transition-colors ${item.value === value ? '' : `${typography.textMuted}`} ${index === focusedIndex ? 'bg-gray-100 dark:bg-gray-600' : 'hover:bg-gray-100 dark:hover:bg-gray-600'}`}
161
190
  role="option"
162
191
  aria-selected={item.value === value}
163
192
  onclick={() => selectItem(item)}
164
193
  onmouseenter={() => (focusedIndex = index)}
165
194
  >
166
- <span class="flex-1">{item.name}</span>
167
- {#if item.value === value}
168
- <CheckOutline class="w-4 h-4 shrink-0 text-blue-600" />
169
- {/if}
195
+ {item.name}
170
196
  </li>
171
197
  {/each}
172
198
  </ul>
@@ -174,6 +200,33 @@
174
200
  </div>
175
201
 
176
202
  {#if error}
177
- <p class="text-sm text-red-500">{error}</p>
203
+ <p class={typography.error}>{error}</p>
178
204
  {/if}
179
205
  </div>
206
+
207
+ {#if isOpen && portal}
208
+ <!-- Portal dropdown - truly moved to document.body to escape overflow containers and transforms -->
209
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
210
+ <ul
211
+ bind:this={dropdownElement}
212
+ use:portalAction
213
+ class="fixed z-[9999] bg-white dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-lg shadow-lg max-h-60 overflow-y-auto py-1"
214
+ style="top: {dropdownPosition.top}px; left: {dropdownPosition.left}px; width: {dropdownPosition.width}px;"
215
+ role="listbox"
216
+ tabindex="-1"
217
+ >
218
+ {#each items as item, index}
219
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
220
+ <li
221
+ id="{id || name}-option-{index}"
222
+ class={`px-4 py-2 cursor-pointer ${typography.sm} transition-colors ${item.value === value ? '' : `${typography.textMuted}`} ${index === focusedIndex ? 'bg-gray-100 dark:bg-gray-600' : 'hover:bg-gray-100 dark:hover:bg-gray-600'}`}
223
+ role="option"
224
+ aria-selected={item.value === value}
225
+ onclick={() => selectItem(item)}
226
+ onmouseenter={() => (focusedIndex = index)}
227
+ >
228
+ {item.name}
229
+ </li>
230
+ {/each}
231
+ </ul>
232
+ {/if}
@@ -14,6 +14,7 @@ declare const Select: import("svelte").Component<{
14
14
  name?: string;
15
15
  id?: string;
16
16
  size?: string;
17
+ portal?: boolean;
17
18
  onchange: any;
18
19
  } & Record<string, any>, {}, "value">;
19
20
  type $$ComponentProps = {
@@ -27,6 +28,7 @@ type $$ComponentProps = {
27
28
  name?: string;
28
29
  id?: string;
29
30
  size?: string;
31
+ portal?: boolean;
30
32
  onchange: any;
31
33
  } & Record<string, any>;
32
34
  //# sourceMappingURL=Select.svelte.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Select.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/primitives/Input/Select.svelte.js"],"names":[],"mappings":";;;;;AAqKA;YA3J6B,MAAM;YAAU,GAAG,EAAE;kBAAgB,MAAM;YAAU,MAAM;eAAa,OAAO;eAAa,OAAO;YAAU,MAAM;WAAS,MAAM;SAAO,MAAM;WAAS,MAAM;cAAY,GAAG;sCA2JrJ;wBA3JlC;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,GAAG,CAAA;CAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC"}
1
+ {"version":3,"file":"Select.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/primitives/Input/Select.svelte.js"],"names":[],"mappings":";;;;;AA8MA;YAhM6B,MAAM;YAAU,GAAG,EAAE;kBAAgB,MAAM;YAAU,MAAM;eAAa,OAAO;eAAa,OAAO;YAAU,MAAM;WAAS,MAAM;SAAO,MAAM;WAAS,MAAM;aAAW,OAAO;cAAY,GAAG;sCAgMvK;wBAhMlC;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,GAAG,CAAA;CAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC"}
@@ -1,4 +1,6 @@
1
1
  <script>
2
+ import { typography } from "../../tokens/typography";
3
+
2
4
  let {
3
5
  value = $bindable(""),
4
6
  placeholder = "",
@@ -43,7 +45,7 @@
43
45
 
44
46
  <div class="flex flex-col gap-2 w-full">
45
47
  {#if label}
46
- <label for={id || name} class="text-sm font-medium text-gray-900 dark:text-white leading-tight">
48
+ <label for={id || name} class={`${typography.label} leading-tight`}>
47
49
  {label}{#if required}<span class="text-red-500 font-medium text-sm ml-0.5">*</span>{/if}
48
50
  </label>
49
51
  {/if}
@@ -57,7 +59,7 @@
57
59
  {readonly}
58
60
  {maxlength}
59
61
  {minlength}
60
- class="w-full p-2.5 bg-gray-50 dark:bg-gray-700 text-gray-900 dark:text-white text-sm leading-normal border rounded-lg resize-y transition-colors focus:outline-none focus:ring-4 focus:ring-blue-300 dark:focus:ring-blue-800 placeholder-gray-500 dark:placeholder-gray-400 {error ? 'border-red-500' : 'border-gray-300 dark:border-gray-600 hover:border-blue-500 focus:border-blue-500'} {disabled ? 'opacity-50 cursor-not-allowed' : ''} {className}"
62
+ class="{typography.sm} w-full p-2.5 bg-gray-50 dark:bg-gray-800 leading-normal border rounded-lg resize-y transition-colors focus:outline-none focus:ring-4 focus:ring-blue-300 dark:focus:ring-blue-800 placeholder-gray-500 dark:placeholder-gray-400 {error ? 'border-red-500' : 'border-gray-300 dark:border-gray-600 hover:border-blue-500 focus:border-blue-500'} {disabled ? 'opacity-50 cursor-not-allowed' : ''} {className}"
61
63
  bind:value
62
64
  oninput={handleInput}
63
65
  onchange={handleChange}
@@ -72,6 +74,6 @@
72
74
  ></textarea>
73
75
 
74
76
  {#if error}
75
- <p class="text-sm text-red-500">{error}</p>
77
+ <p class={typography.error}>{error}</p>
76
78
  {/if}
77
79
  </div>
@@ -1 +1 @@
1
- {"version":3,"file":"Textarea.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/primitives/Input/Textarea.svelte.js"],"names":[],"mappings":";;;;;AA8DA;YA1D6B,MAAM;kBAAgB,MAAM;WAAS,MAAM;eAAa,OAAO;eAAa,OAAO;eAAa,OAAO;SAAO,MAAM;WAAS,MAAM;YAAU,MAAM;YAAU,MAAM;gBAAc,GAAG;gBAAc,GAAG;YAAU,MAAM;aAAW,GAAG;cAAY,GAAG;YAAU,GAAG;aAAW,GAAG;eAAa,GAAG;aAAW,GAAG;gBAAc,GAAG;sCA0DlS;wBA1DpC;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,GAAG,CAAC;IAAC,SAAS,CAAC,EAAE,GAAG,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,GAAG,CAAC;IAAC,QAAQ,EAAE,GAAG,CAAC;IAAC,MAAM,EAAE,GAAG,CAAC;IAAC,OAAO,EAAE,GAAG,CAAC;IAAC,SAAS,EAAE,GAAG,CAAC;IAAC,OAAO,EAAE,GAAG,CAAC;IAAC,UAAU,EAAE,GAAG,CAAA;CAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC"}
1
+ {"version":3,"file":"Textarea.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/primitives/Input/Textarea.svelte.js"],"names":[],"mappings":";;;;;AAkEA;YA1D6B,MAAM;kBAAgB,MAAM;WAAS,MAAM;eAAa,OAAO;eAAa,OAAO;eAAa,OAAO;SAAO,MAAM;WAAS,MAAM;YAAU,MAAM;YAAU,MAAM;gBAAc,GAAG;gBAAc,GAAG;YAAU,MAAM;aAAW,GAAG;cAAY,GAAG;YAAU,GAAG;aAAW,GAAG;eAAa,GAAG;aAAW,GAAG;gBAAc,GAAG;sCA0DlS;wBA1DpC;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,GAAG,CAAC;IAAC,SAAS,CAAC,EAAE,GAAG,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,GAAG,CAAC;IAAC,QAAQ,EAAE,GAAG,CAAC;IAAC,MAAM,EAAE,GAAG,CAAC;IAAC,OAAO,EAAE,GAAG,CAAC;IAAC,SAAS,EAAE,GAAG,CAAC;IAAC,OAAO,EAAE,GAAG,CAAC;IAAC,UAAU,EAAE,GAAG,CAAA;CAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC"}
@@ -99,7 +99,19 @@
99
99
  <!-- svelte-ignore a11y_no_static_element_interactions -->
100
100
  <div
101
101
  class="fixed inset-0 flex bg-black/50 z-50 items-end justify-center md:items-center md:p-4 touch-none overscroll-none"
102
- onclick={persistent ? null : resetModal}
102
+ onmousedown={(e) => {
103
+ // Only track direct clicks on backdrop, not drags that end on backdrop
104
+ if (e.target === e.currentTarget && !persistent) {
105
+ e.currentTarget.dataset.clickStartedOnBackdrop = 'true';
106
+ }
107
+ }}
108
+ onmouseup={(e) => {
109
+ // Only close if both mousedown and mouseup were on the backdrop
110
+ if (e.target === e.currentTarget && e.currentTarget.dataset.clickStartedOnBackdrop === 'true' && !persistent) {
111
+ resetModal();
112
+ }
113
+ delete e.currentTarget.dataset.clickStartedOnBackdrop;
114
+ }}
103
115
  transition:fade={{ duration: 300 }}
104
116
  role="dialog"
105
117
  aria-modal="true"
@@ -1 +1 @@
1
- {"version":3,"file":"Modal.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/primitives/Modal/Modal.svelte.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AA0JA;;WAZW,OAAO;mBACC,OAAO;gBACV,OAAO;WACZ,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ;iBAClC,OAAO;eACT,MAAM,IAAI;aACZ,GAAG;WACL,GAAG;aACD,GAAG;YACJ,MAAM;eAGkC"}
1
+ {"version":3,"file":"Modal.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/primitives/Modal/Modal.svelte.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAqKA;;WAZW,OAAO;mBACC,OAAO;gBACV,OAAO;WACZ,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ;iBAClC,OAAO;eACT,MAAM,IAAI;aACZ,GAAG;WACL,GAAG;aACD,GAAG;YACJ,MAAM;eAGkC"}
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from 'svelte';
3
3
  import { ChevronLeftOutline, ChevronRightOutline } from "../Icons";
4
+ import { typography } from "../../tokens/typography";
4
5
 
5
6
  interface Props {
6
7
  currentPage?: number;
@@ -112,8 +113,8 @@
112
113
 
113
114
  {#if variant === 'table'}
114
115
  <div class="flex flex-col items-center gap-3 sm:flex-row sm:justify-between {className}" {...restProps}>
115
- <span class="text-sm text-gray-700 dark:text-gray-400">
116
- Showing <span class="font-semibold text-gray-900 dark:text-white">{startItem}</span> to <span class="font-semibold text-gray-900 dark:text-white">{endItem}</span> of <span class="font-semibold text-gray-900 dark:text-white">{totalItems}</span> entries
116
+ <span class={`${typography.sm} text-gray-700 dark:text-gray-400`}>
117
+ Showing <span class={`font-semibold ${typography.sm}`}>{startItem}</span> to <span class={`font-semibold ${typography.sm}`}>{endItem}</span> of <span class={`font-semibold ${typography.sm}`}>{totalItems}</span> entries
117
118
  </span>
118
119
  <nav class="inline-flex -space-x-px rtl:space-x-reverse" aria-label="Pagination">
119
120
  {#if effectiveShowPrevNext}
@@ -1 +1 @@
1
- {"version":3,"file":"Pagination.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/primitives/Pagination/Pagination.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAIpC,UAAU,KAAK;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;IAC9B,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC9C,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAmMH,QAAA,MAAM,UAAU,sDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"Pagination.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/primitives/Pagination/Pagination.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAKpC,UAAU,KAAK;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;IAC9B,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC9C,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAoMH,QAAA,MAAM,UAAU,sDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
@@ -35,12 +35,12 @@
35
35
  }
36
36
 
37
37
  const colorClasses = {
38
- blue: 'text-blue-600 focus:ring-blue-500 dark:focus:ring-blue-600',
39
- red: 'text-red-600 focus:ring-red-500 dark:focus:ring-red-600',
40
- green: 'text-green-600 focus:ring-green-500 dark:focus:ring-green-600',
41
- purple: 'text-purple-600 focus:ring-purple-500 dark:focus:ring-purple-600',
42
- orange: 'text-orange-500 focus:ring-orange-500 dark:focus:ring-orange-600',
43
- yellow: 'text-yellow-400 focus:ring-yellow-500 dark:focus:ring-yellow-600'
38
+ blue: 'text-blue-600',
39
+ red: 'text-red-600',
40
+ green: 'text-green-600',
41
+ purple: 'text-purple-600',
42
+ orange: 'text-orange-500',
43
+ yellow: 'text-yellow-400'
44
44
  };
45
45
 
46
46
  let colorClass = $derived(colorClasses[color] || colorClasses.blue);
@@ -57,7 +57,7 @@
57
57
  {disabled}
58
58
  checked={isChecked}
59
59
  onchange={handleChange}
60
- class="w-4 h-4 bg-gray-100 border-gray-300 focus:ring-2 dark:ring-offset-gray-800 dark:bg-gray-700 dark:border-gray-600 {colorClass}"
60
+ class="w-4 h-4 bg-gray-100 border-gray-300 focus:outline-none dark:bg-gray-700 dark:border-gray-600 {colorClass}"
61
61
  />
62
62
  {#if children}
63
63
  <span class="text-sm font-medium text-gray-900 dark:text-gray-300">