@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.
- package/dist/calendar/AboutShow/AboutShow.svelte +9 -8
- package/dist/calendar/AboutShow/AboutShow.svelte.d.ts.map +1 -1
- package/dist/calendar/Calendar/MiniMonthCalendar.svelte +13 -12
- package/dist/calendar/Calendar/MiniMonthCalendar.svelte.d.ts.map +1 -1
- package/dist/calendar/FAQs/FAQs.svelte +6 -5
- package/dist/calendar/FAQs/FAQs.svelte.d.ts.map +1 -1
- package/dist/calendar/MonthSwitcher/MonthSwitcher.svelte +3 -2
- package/dist/calendar/MonthSwitcher/MonthSwitcher.svelte.d.ts.map +1 -1
- package/dist/calendar/OrderSummary/OrderSummary.svelte +69 -28
- package/dist/calendar/OrderSummary/OrderSummary.svelte.d.ts +2 -0
- package/dist/calendar/OrderSummary/OrderSummary.svelte.d.ts.map +1 -1
- package/dist/calendar/PublicCard/PublicCard.svelte +7 -9
- package/dist/calendar/PublicCard/PublicCard.svelte.d.ts.map +1 -1
- package/dist/calendar/ShowCard/ShowCard.svelte +11 -10
- package/dist/calendar/ShowCard/ShowCard.svelte.d.ts.map +1 -1
- package/dist/calendar/ShowTimeCard/ShowTimeCard.svelte +5 -3
- package/dist/calendar/ShowTimeCard/ShowTimeCard.svelte.d.ts.map +1 -1
- package/dist/components/Layout/Section.svelte +4 -4
- package/dist/components/Layout/Section.svelte.d.ts.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +9 -0
- package/dist/patterns/data/DataTable.svelte +4 -2
- package/dist/patterns/data/DataTable.svelte.d.ts.map +1 -1
- package/dist/patterns/forms/FormSection.svelte +4 -2
- package/dist/patterns/forms/FormSection.svelte.d.ts.map +1 -1
- package/dist/patterns/navigation/BottomNav.svelte +4 -3
- package/dist/patterns/navigation/BottomNav.svelte.d.ts.map +1 -1
- package/dist/patterns/navigation/Header.svelte +11 -10
- package/dist/patterns/navigation/Header.svelte.d.ts.map +1 -1
- package/dist/patterns/page/PageHeader.svelte +3 -2
- package/dist/patterns/page/PageHeader.svelte.d.ts.map +1 -1
- package/dist/patterns/page/PageLayout.svelte +2 -1
- package/dist/patterns/page/PageLayout.svelte.d.ts.map +1 -1
- package/dist/patterns/page/PageLoader.svelte +2 -1
- package/dist/patterns/page/PageLoader.svelte.d.ts.map +1 -1
- package/dist/patterns/page/SectionHeader.svelte +5 -3
- package/dist/patterns/page/SectionHeader.svelte.d.ts.map +1 -1
- package/dist/primitives/Accordion/Accordion.svelte +2 -1
- package/dist/primitives/Accordion/Accordion.svelte.d.ts.map +1 -1
- package/dist/primitives/Accordion/AccordionItem.svelte +6 -5
- package/dist/primitives/Accordion/AccordionItem.svelte.d.ts.map +1 -1
- package/dist/primitives/BottomSheet/BottomSheet.svelte +2 -1
- package/dist/primitives/BottomSheet/BottomSheet.svelte.d.ts.map +1 -1
- package/dist/primitives/Breadcrumb/Breadcrumb.svelte +6 -5
- package/dist/primitives/Breadcrumb/Breadcrumb.svelte.d.ts.map +1 -1
- package/dist/primitives/Button/Button.svelte +27 -10
- package/dist/primitives/Button/Button.svelte.d.ts.map +1 -1
- package/dist/primitives/Button/ButtonSaveDemo.svelte +2 -1
- package/dist/primitives/Button/ButtonSaveDemo.svelte.d.ts.map +1 -1
- package/dist/primitives/Card.svelte +1 -1
- package/dist/primitives/Checkbox/Checkbox.svelte +8 -8
- package/dist/primitives/DarkModeToggle.svelte +43 -44
- package/dist/primitives/DarkModeToggle.svelte.d.ts.map +1 -1
- package/dist/primitives/Drawer/Drawer.svelte +121 -47
- package/dist/primitives/Drawer/Drawer.svelte.d.ts +4 -0
- package/dist/primitives/Drawer/Drawer.svelte.d.ts.map +1 -1
- package/dist/primitives/Icons/ImageOutline.svelte +19 -0
- package/dist/primitives/Icons/ImageOutline.svelte.d.ts +12 -0
- package/dist/primitives/Icons/ImageOutline.svelte.d.ts.map +1 -0
- package/dist/primitives/Icons/TrashBinOutline.svelte +19 -0
- package/dist/primitives/Icons/TrashBinOutline.svelte.d.ts +12 -0
- package/dist/primitives/Icons/TrashBinOutline.svelte.d.ts.map +1 -0
- package/dist/primitives/Icons/index.d.ts +2 -0
- package/dist/primitives/Icons/index.js +2 -0
- package/dist/primitives/Input/Input.svelte +41 -80
- package/dist/primitives/Input/Input.svelte.d.ts +4 -6
- package/dist/primitives/Input/Input.svelte.d.ts.map +1 -1
- package/dist/primitives/Input/Select.svelte +66 -13
- package/dist/primitives/Input/Select.svelte.d.ts +2 -0
- package/dist/primitives/Input/Select.svelte.d.ts.map +1 -1
- package/dist/primitives/Input/Textarea.svelte +5 -3
- package/dist/primitives/Input/Textarea.svelte.d.ts.map +1 -1
- package/dist/primitives/Modal/Modal.svelte +13 -1
- package/dist/primitives/Modal/Modal.svelte.d.ts.map +1 -1
- package/dist/primitives/Pagination/Pagination.svelte +3 -2
- package/dist/primitives/Pagination/Pagination.svelte.d.ts.map +1 -1
- package/dist/primitives/Radio/Radio.svelte +7 -7
- package/dist/primitives/Tabs/Tabs.svelte +4 -3
- package/dist/primitives/Tabs/Tabs.svelte.d.ts.map +1 -1
- package/dist/recipes/CropImage/CropImage.svelte +10 -5
- package/dist/recipes/CropImage/CropImage.svelte.d.ts.map +1 -1
- package/dist/recipes/ImageUploader/ImageUploader.stories.svelte +125 -0
- package/dist/recipes/ImageUploader/ImageUploader.stories.svelte.d.ts +28 -0
- package/dist/recipes/ImageUploader/ImageUploader.stories.svelte.d.ts.map +1 -0
- package/dist/recipes/ImageUploader/ImageUploader.svelte +980 -0
- package/dist/recipes/ImageUploader/ImageUploader.svelte.d.ts +62 -0
- package/dist/recipes/ImageUploader/ImageUploader.svelte.d.ts.map +1 -0
- package/dist/recipes/SuperLogin/SuperLogin.svelte +37 -40
- package/dist/recipes/SuperLogin/SuperLogin.svelte.d.ts.map +1 -1
- package/dist/recipes/feedback/EmptyState/EmptyState.svelte +3 -2
- package/dist/recipes/feedback/EmptyState/EmptyState.svelte.d.ts.map +1 -1
- package/dist/recipes/fields/CheckboxField.svelte +3 -2
- package/dist/recipes/fields/CheckboxField.svelte.d.ts.map +1 -1
- package/dist/recipes/fields/FormField.svelte +12 -4
- package/dist/recipes/fields/FormField.svelte.d.ts +3 -1
- package/dist/recipes/fields/FormField.svelte.d.ts.map +1 -1
- package/dist/recipes/fields/RadioGroup.svelte +13 -4
- package/dist/recipes/fields/RadioGroup.svelte.d.ts +4 -1
- package/dist/recipes/fields/RadioGroup.svelte.d.ts.map +1 -1
- package/dist/recipes/fields/SelectField.svelte +12 -3
- package/dist/recipes/fields/SelectField.svelte.d.ts +4 -1
- package/dist/recipes/fields/SelectField.svelte.d.ts.map +1 -1
- package/dist/recipes/fields/TextareaField.svelte +2 -1
- package/dist/recipes/fields/TextareaField.svelte.d.ts.map +1 -1
- package/dist/recipes/fields/ToggleField.svelte +3 -2
- package/dist/recipes/fields/ToggleField.svelte.d.ts.map +1 -1
- package/dist/recipes/inputs/MultiSelect.svelte +9 -8
- package/dist/recipes/inputs/MultiSelect.svelte.d.ts.map +1 -1
- package/dist/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.svelte +9 -9
- package/dist/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.svelte.d.ts.map +1 -1
- package/dist/recipes/inputs/Search.svelte +7 -6
- package/dist/recipes/inputs/Search.svelte.d.ts.map +1 -1
- package/dist/recipes/modals/AlertModal.svelte +3 -2
- package/dist/recipes/modals/AlertModal.svelte.d.ts.map +1 -1
- package/dist/recipes/modals/ConfirmationModal.svelte +6 -4
- package/dist/recipes/modals/ConfirmationModal.svelte.d.ts.map +1 -1
- package/dist/recipes/modals/InputModal.svelte +9 -8
- package/dist/recipes/modals/InputModal.svelte.d.ts.map +1 -1
- package/dist/recipes/modals/ModalStateManager.svelte +4 -3
- package/dist/recipes/modals/ModalStateManager.svelte.d.ts.map +1 -1
- package/dist/recipes/modals/StatusModal.svelte +5 -4
- package/dist/recipes/modals/StatusModal.svelte.d.ts.map +1 -1
- package/dist/stories/ButtonAuditReview.svelte +361 -397
- package/dist/stories/ButtonAuditReview.svelte.d.ts +24 -4
- package/dist/stories/ButtonAuditReview.svelte.d.ts.map +1 -1
- package/dist/tokens/index.d.ts +4 -8
- package/dist/tokens/index.d.ts.map +1 -1
- package/dist/tokens/index.js +4 -8
- package/dist/tokens/typography.d.ts +76 -169
- package/dist/tokens/typography.d.ts.map +1 -1
- package/dist/tokens/typography.js +93 -62
- 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 (
|
|
201
|
+
if (inputValueStr.length === 0) {
|
|
224
202
|
onsearch?.({ query: '' });
|
|
225
203
|
return;
|
|
226
204
|
}
|
|
227
|
-
if (
|
|
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=
|
|
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=
|
|
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-
|
|
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-
|
|
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
|
|
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-
|
|
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 ||
|
|
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
|
|
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=
|
|
421
|
+
<p class={typography.error}>{errorText}</p>
|
|
473
422
|
</div>
|
|
474
423
|
{:else if helperText || hintText}
|
|
475
|
-
<div class=
|
|
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":"
|
|
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
|
|
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
|
|
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=
|
|
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-
|
|
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
|
|
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=
|
|
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
|
-
|
|
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=
|
|
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":";;;;;
|
|
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=
|
|
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-
|
|
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=
|
|
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":";;;;;
|
|
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
|
-
|
|
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":";;;;;;;;;;;;;;;;;
|
|
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=
|
|
116
|
-
Showing <span class=
|
|
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;
|
|
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
|
|
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
|
|
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:
|
|
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">
|