@getmicdrop/svelte-components 5.17.4 → 5.18.1
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 -5
- package/dist/calendar/AboutShow/AboutShow.svelte.d.ts +2 -2
- package/dist/calendar/AboutShow/AboutShow.svelte.d.ts.map +1 -1
- package/dist/calendar/Calendar/MiniMonthCalendar.svelte +39 -18
- package/dist/calendar/Calendar/MiniMonthCalendar.svelte.d.ts +4 -0
- package/dist/calendar/Calendar/MiniMonthCalendar.svelte.d.ts.map +1 -1
- package/dist/calendar/FAQs/FAQs.svelte +16 -5
- package/dist/calendar/FAQs/FAQs.svelte.d.ts +6 -4
- package/dist/calendar/FAQs/FAQs.svelte.d.ts.map +1 -1
- package/dist/calendar/MonthSwitcher/MonthSwitcher.svelte +19 -4
- package/dist/calendar/MonthSwitcher/MonthSwitcher.svelte.d.ts +2 -0
- package/dist/calendar/MonthSwitcher/MonthSwitcher.svelte.d.ts.map +1 -1
- package/dist/calendar/OrderSummary/OrderSummary.spec.js +3 -3
- package/dist/calendar/OrderSummary/OrderSummary.svelte +17 -13
- package/dist/calendar/OrderSummary/OrderSummary.svelte.d.ts +4 -2
- package/dist/calendar/OrderSummary/OrderSummary.svelte.d.ts.map +1 -1
- package/dist/calendar/PublicCard/PublicCard.svelte +11 -2
- package/dist/calendar/PublicCard/PublicCard.svelte.d.ts +4 -0
- package/dist/calendar/PublicCard/PublicCard.svelte.d.ts.map +1 -1
- package/dist/calendar/ShowCard/ShowCard.svelte +25 -11
- package/dist/calendar/ShowCard/ShowCard.svelte.d.ts +4 -0
- package/dist/calendar/ShowCard/ShowCard.svelte.d.ts.map +1 -1
- package/dist/calendar/ShowTimeCard/ShowTimeCard.svelte +12 -4
- package/dist/calendar/ShowTimeCard/ShowTimeCard.svelte.d.ts +4 -0
- package/dist/calendar/ShowTimeCard/ShowTimeCard.svelte.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/patterns/chat/ChatBubble.svelte +9 -1
- package/dist/patterns/chat/ChatBubble.svelte.d.ts +6 -4
- package/dist/patterns/chat/ChatBubble.svelte.d.ts.map +1 -1
- package/dist/patterns/chat/ChatInvitationBubble.svelte +10 -1
- package/dist/patterns/chat/ChatInvitationBubble.svelte.d.ts +6 -3
- package/dist/patterns/chat/ChatInvitationBubble.svelte.d.ts.map +1 -1
- package/dist/patterns/chat/ChatInvitationNotice.svelte +10 -1
- package/dist/patterns/chat/ChatInvitationNotice.svelte.d.ts +6 -3
- package/dist/patterns/chat/ChatInvitationNotice.svelte.d.ts.map +1 -1
- package/dist/patterns/forms/FormValidationSummary.svelte +9 -1
- package/dist/patterns/forms/FormValidationSummary.svelte.d.ts +5 -3
- package/dist/patterns/forms/FormValidationSummary.svelte.d.ts.map +1 -1
- package/dist/patterns/navigation/BottomNav.svelte +9 -1
- package/dist/patterns/navigation/BottomNav.svelte.d.ts +10 -9
- package/dist/patterns/navigation/BottomNav.svelte.d.ts.map +1 -1
- package/dist/patterns/navigation/Header.svelte +20 -8
- package/dist/patterns/navigation/Header.svelte.d.ts +17 -9
- package/dist/patterns/navigation/Header.svelte.d.ts.map +1 -1
- package/dist/patterns/page/PageLoader.svelte +12 -3
- package/dist/patterns/page/PageLoader.svelte.d.ts +6 -3
- package/dist/patterns/page/PageLoader.svelte.d.ts.map +1 -1
- package/dist/primitives/Accordion/AccordionItem.svelte +9 -1
- package/dist/primitives/Accordion/AccordionItem.svelte.d.ts +6 -4
- package/dist/primitives/Accordion/AccordionItem.svelte.d.ts.map +1 -1
- package/dist/primitives/Alert/Alert.svelte +10 -2
- package/dist/primitives/Alert/Alert.svelte.d.ts +6 -4
- package/dist/primitives/Alert/Alert.svelte.d.ts.map +1 -1
- package/dist/primitives/Breadcrumb/Breadcrumb.svelte +9 -1
- package/dist/primitives/Breadcrumb/Breadcrumb.svelte.d.ts +13 -9
- package/dist/primitives/Breadcrumb/Breadcrumb.svelte.d.ts.map +1 -1
- package/dist/primitives/DarkModeToggle.svelte +16 -5
- package/dist/primitives/DarkModeToggle.svelte.d.ts +9 -3
- package/dist/primitives/DarkModeToggle.svelte.d.ts.map +1 -1
- package/dist/primitives/Dropdown/Dropdown.svelte +11 -2
- package/dist/primitives/Dropdown/Dropdown.svelte.d.ts +7 -4
- package/dist/primitives/Dropdown/Dropdown.svelte.d.ts.map +1 -1
- package/dist/primitives/Input/Input.svelte +19 -6
- package/dist/primitives/Input/Input.svelte.d.ts.map +1 -1
- package/dist/primitives/NumberInput/NumberInput.svelte +10 -2
- package/dist/primitives/NumberInput/NumberInput.svelte.d.ts.map +1 -1
- package/dist/primitives/Pagination/Pagination.svelte +21 -7
- package/dist/primitives/Pagination/Pagination.svelte.d.ts +14 -6
- package/dist/primitives/Pagination/Pagination.svelte.d.ts.map +1 -1
- package/dist/primitives/Skeleton/CardPlaceholder.svelte +11 -2
- package/dist/primitives/Skeleton/CardPlaceholder.svelte.d.ts +8 -5
- package/dist/primitives/Skeleton/CardPlaceholder.svelte.d.ts.map +1 -1
- package/dist/primitives/Skeleton/ImagePlaceholder.svelte +11 -2
- package/dist/primitives/Skeleton/ImagePlaceholder.svelte.d.ts +8 -5
- package/dist/primitives/Skeleton/ImagePlaceholder.svelte.d.ts.map +1 -1
- package/dist/primitives/Skeleton/ListPlaceholder.svelte +11 -2
- package/dist/primitives/Skeleton/ListPlaceholder.svelte.d.ts +8 -5
- package/dist/primitives/Skeleton/ListPlaceholder.svelte.d.ts.map +1 -1
- package/dist/primitives/Skeleton/Skeleton.svelte +11 -2
- package/dist/primitives/Skeleton/Skeleton.svelte.d.ts +7 -4
- package/dist/primitives/Skeleton/Skeleton.svelte.d.ts.map +1 -1
- package/dist/primitives/Spinner/Spinner.svelte +9 -1
- package/dist/primitives/Spinner/Spinner.svelte.d.ts +6 -4
- package/dist/primitives/Spinner/Spinner.svelte.d.ts.map +1 -1
- package/dist/recipes/ImageUploader/ImageUploader.svelte +5 -3
- package/dist/recipes/ImageUploader/ImageUploader.svelte.d.ts +1 -0
- package/dist/recipes/ImageUploader/ImageUploader.svelte.d.ts.map +1 -1
- package/dist/recipes/SuperLogin/SuperLogin.svelte +25 -23
- package/dist/recipes/SuperLogin/SuperLogin.svelte.d.ts.map +1 -1
- package/dist/recipes/feedback/EmptyState/EmptyState.svelte +12 -3
- package/dist/recipes/feedback/EmptyState/EmptyState.svelte.d.ts +7 -4
- package/dist/recipes/feedback/EmptyState/EmptyState.svelte.d.ts.map +1 -1
- package/dist/recipes/inputs/MultiSelect.svelte +10 -2
- package/dist/recipes/inputs/MultiSelect.svelte.d.ts.map +1 -1
- package/dist/recipes/inputs/OTPInput.svelte +14 -3
- package/dist/recipes/inputs/OTPInput.svelte.d.ts +14 -12
- package/dist/recipes/inputs/OTPInput.svelte.d.ts.map +1 -1
- package/dist/recipes/inputs/PasswordInput.svelte +10 -1
- package/dist/recipes/inputs/PasswordInput.svelte.d.ts +7 -4
- package/dist/recipes/inputs/PasswordInput.svelte.d.ts.map +1 -1
- package/dist/recipes/inputs/PasswordStrengthIndicator/PasswordStrengthIndicator.svelte +21 -10
- package/dist/recipes/inputs/PasswordStrengthIndicator/PasswordStrengthIndicator.svelte.d.ts +8 -3
- package/dist/recipes/inputs/PasswordStrengthIndicator/PasswordStrengthIndicator.svelte.d.ts.map +1 -1
- package/dist/recipes/inputs/PhoneInput.svelte +254 -0
- package/dist/recipes/inputs/PhoneInput.svelte.d.ts +40 -0
- package/dist/recipes/inputs/PhoneInput.svelte.d.ts.map +1 -0
- package/dist/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.svelte +22 -9
- package/dist/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.svelte.d.ts +21 -16
- package/dist/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.svelte.d.ts.map +1 -1
- package/dist/recipes/inputs/Search.svelte +10 -2
- package/dist/recipes/inputs/Search.svelte.d.ts +7 -5
- package/dist/recipes/inputs/Search.svelte.d.ts.map +1 -1
- package/dist/recipes/inputs/index.d.ts +1 -0
- package/dist/recipes/inputs/index.js +1 -0
- package/dist/recipes/inputs/phoneInput/CountrySelector.svelte +240 -0
- package/dist/recipes/inputs/phoneInput/CountrySelector.svelte.d.ts +15 -0
- package/dist/recipes/inputs/phoneInput/CountrySelector.svelte.d.ts.map +1 -0
- package/dist/recipes/inputs/phoneInput/countryData.d.ts +18 -0
- package/dist/recipes/inputs/phoneInput/countryData.d.ts.map +1 -0
- package/dist/recipes/inputs/phoneInput/countryData.js +211 -0
- package/dist/recipes/modals/AlertModal.svelte +11 -2
- package/dist/recipes/modals/AlertModal.svelte.d.ts +4 -2
- package/dist/recipes/modals/AlertModal.svelte.d.ts.map +1 -1
- package/dist/recipes/modals/ConfirmationModal.svelte +8 -1
- package/dist/recipes/modals/ConfirmationModal.svelte.d.ts +2 -0
- package/dist/recipes/modals/ConfirmationModal.svelte.d.ts.map +1 -1
- package/dist/recipes/modals/InputModal.svelte +19 -7
- package/dist/recipes/modals/InputModal.svelte.d.ts +6 -4
- package/dist/recipes/modals/InputModal.svelte.d.ts.map +1 -1
- package/dist/recipes/modals/StatusModal.svelte +14 -4
- package/dist/recipes/modals/StatusModal.svelte.d.ts +4 -2
- package/dist/recipes/modals/StatusModal.svelte.d.ts.map +1 -1
- package/dist/tokens/__tests__/variants.test.js +12 -4
- package/dist/tokens/variants.d.ts +4 -4
- package/dist/tokens/variants.js +4 -4
- package/dist/utils/formatters.d.ts +6 -0
- package/dist/utils/formatters.d.ts.map +1 -1
- package/dist/utils/formatters.js +8 -0
- package/dist/utils/phoneUtils.d.ts +35 -0
- package/dist/utils/phoneUtils.d.ts.map +1 -0
- package/dist/utils/phoneUtils.js +104 -0
- package/dist/utils/utils.js +25 -16
- package/package.json +6 -1
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { onMount } from "svelte";
|
|
3
|
+
import { safeSlide } from "../../utils/transitions.js";
|
|
4
|
+
import { cubicOut } from "svelte/easing";
|
|
5
|
+
import { ExclamationCircleOutline } from "../../primitives/Icons";
|
|
6
|
+
import { typography } from "../../tokens/typography";
|
|
7
|
+
import { formInputSizes } from "../../tokens/sizing";
|
|
8
|
+
import CountrySelector from "./phoneInput/CountrySelector.svelte";
|
|
9
|
+
import { COUNTRIES, getCountry, type Country } from "./phoneInput/countryData";
|
|
10
|
+
import {
|
|
11
|
+
parseStoredPhone,
|
|
12
|
+
formatAsYouType,
|
|
13
|
+
toE164,
|
|
14
|
+
isValidE164,
|
|
15
|
+
} from "../../utils/phoneUtils";
|
|
16
|
+
import type { CountryCode } from "libphonenumber-js/min";
|
|
17
|
+
|
|
18
|
+
const defaultLabels = {
|
|
19
|
+
searchPlaceholder: 'Search...',
|
|
20
|
+
noResults: 'No countries found',
|
|
21
|
+
countrySelector: 'Select country',
|
|
22
|
+
optional: '(optional)',
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
interface Props {
|
|
26
|
+
value?: string;
|
|
27
|
+
label?: string;
|
|
28
|
+
id?: string;
|
|
29
|
+
name?: string;
|
|
30
|
+
placeholder?: string;
|
|
31
|
+
required?: boolean;
|
|
32
|
+
disabled?: boolean;
|
|
33
|
+
optional?: boolean;
|
|
34
|
+
size?: 'sm' | 'md' | 'lg';
|
|
35
|
+
errorText?: string;
|
|
36
|
+
helperText?: string;
|
|
37
|
+
color?: 'base' | 'red';
|
|
38
|
+
controlled?: boolean;
|
|
39
|
+
buttonText?: string | null;
|
|
40
|
+
buttonDisabled?: boolean;
|
|
41
|
+
onButtonClick?: ((value: string) => void) | null;
|
|
42
|
+
defaultCountry?: string;
|
|
43
|
+
labels?: Partial<typeof defaultLabels>;
|
|
44
|
+
onchange?: (detail: { value: string; country: string; isValid: boolean }) => void;
|
|
45
|
+
animateFocus?: boolean;
|
|
46
|
+
statusText?: string;
|
|
47
|
+
statusType?: string;
|
|
48
|
+
[key: string]: unknown;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
let {
|
|
52
|
+
value = $bindable(''),
|
|
53
|
+
label = '',
|
|
54
|
+
id = '',
|
|
55
|
+
name = '',
|
|
56
|
+
placeholder = '',
|
|
57
|
+
required = false,
|
|
58
|
+
disabled = false,
|
|
59
|
+
optional = false,
|
|
60
|
+
size = 'md',
|
|
61
|
+
errorText = '',
|
|
62
|
+
helperText = '',
|
|
63
|
+
color = 'base',
|
|
64
|
+
controlled = false,
|
|
65
|
+
buttonText = null,
|
|
66
|
+
buttonDisabled = false,
|
|
67
|
+
onButtonClick = null,
|
|
68
|
+
defaultCountry = 'US',
|
|
69
|
+
labels: userLabels = {},
|
|
70
|
+
onchange,
|
|
71
|
+
animateFocus = true,
|
|
72
|
+
statusText = '',
|
|
73
|
+
statusType = '',
|
|
74
|
+
...restProps
|
|
75
|
+
}: Props = $props();
|
|
76
|
+
|
|
77
|
+
let labels = $derived({ ...defaultLabels, ...userLabels });
|
|
78
|
+
|
|
79
|
+
// Internal state
|
|
80
|
+
let selectedCountry = $state<Country>(getCountry(defaultCountry) || COUNTRIES.find((c) => c.code === 'US')!);
|
|
81
|
+
let nationalDigits = $state('');
|
|
82
|
+
let displayValue = $state('');
|
|
83
|
+
let inputElement = $state<HTMLInputElement | null>(null);
|
|
84
|
+
let hasInitialized = $state(false);
|
|
85
|
+
|
|
86
|
+
let hasError = $derived(color === 'red' || Boolean(errorText));
|
|
87
|
+
let sizeClass = $derived(formInputSizes[size] || formInputSizes.md);
|
|
88
|
+
let shouldAnimate = $derived(animateFocus && !disabled);
|
|
89
|
+
|
|
90
|
+
// Parse incoming value on mount or when value changes externally
|
|
91
|
+
$effect(() => {
|
|
92
|
+
const currentValue = value;
|
|
93
|
+
if (!hasInitialized || currentValue !== lastEmittedValue) {
|
|
94
|
+
parseIncomingValue(currentValue);
|
|
95
|
+
hasInitialized = true;
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
let lastEmittedValue = '';
|
|
100
|
+
|
|
101
|
+
function parseIncomingValue(incoming: string) {
|
|
102
|
+
if (!incoming) {
|
|
103
|
+
nationalDigits = '';
|
|
104
|
+
displayValue = '';
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const parsed = parseStoredPhone(incoming);
|
|
109
|
+
if (parsed) {
|
|
110
|
+
const country = getCountry(parsed.countryCode);
|
|
111
|
+
if (country) {
|
|
112
|
+
selectedCountry = country;
|
|
113
|
+
}
|
|
114
|
+
nationalDigits = parsed.nationalNumber;
|
|
115
|
+
displayValue = formatAsYouType(parsed.countryCode as CountryCode, parsed.nationalNumber);
|
|
116
|
+
} else {
|
|
117
|
+
// Can't parse — treat as raw digits
|
|
118
|
+
nationalDigits = incoming.replace(/\D/g, '');
|
|
119
|
+
displayValue = nationalDigits;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function handleInput(event: Event) {
|
|
124
|
+
const target = event.target as HTMLInputElement;
|
|
125
|
+
const raw = target.value.replace(/\D/g, '');
|
|
126
|
+
nationalDigits = raw;
|
|
127
|
+
|
|
128
|
+
// Format as-you-type
|
|
129
|
+
const formatted = formatAsYouType(selectedCountry.code as CountryCode, raw);
|
|
130
|
+
displayValue = formatted;
|
|
131
|
+
target.value = formatted;
|
|
132
|
+
|
|
133
|
+
// Compute E.164 and emit
|
|
134
|
+
const e164 = toE164(selectedCountry.code as CountryCode, raw);
|
|
135
|
+
lastEmittedValue = e164;
|
|
136
|
+
value = e164;
|
|
137
|
+
|
|
138
|
+
const valid = e164 ? isValidE164(e164) : false;
|
|
139
|
+
onchange?.({ value: e164, country: selectedCountry.code, isValid: valid });
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function handleCountryChange() {
|
|
143
|
+
// Re-format existing digits for new country
|
|
144
|
+
displayValue = formatAsYouType(selectedCountry.code as CountryCode, nationalDigits);
|
|
145
|
+
|
|
146
|
+
// Recalculate E.164
|
|
147
|
+
const e164 = toE164(selectedCountry.code as CountryCode, nationalDigits);
|
|
148
|
+
lastEmittedValue = e164;
|
|
149
|
+
value = e164;
|
|
150
|
+
|
|
151
|
+
const valid = e164 ? isValidE164(e164) : false;
|
|
152
|
+
onchange?.({ value: e164, country: selectedCountry.code, isValid: valid });
|
|
153
|
+
|
|
154
|
+
// Focus the input after country change
|
|
155
|
+
inputElement?.focus();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Watch for country changes from the selector
|
|
159
|
+
$effect(() => {
|
|
160
|
+
// Trigger on selectedCountry change (read it to create dependency)
|
|
161
|
+
const _code = selectedCountry.code;
|
|
162
|
+
if (hasInitialized && nationalDigits) {
|
|
163
|
+
handleCountryChange();
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
function handleButtonClick() {
|
|
168
|
+
if (typeof onButtonClick === 'function') {
|
|
169
|
+
onButtonClick(value);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function focus() {
|
|
174
|
+
inputElement?.focus();
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export function clear() {
|
|
178
|
+
nationalDigits = '';
|
|
179
|
+
displayValue = '';
|
|
180
|
+
value = '';
|
|
181
|
+
lastEmittedValue = '';
|
|
182
|
+
}
|
|
183
|
+
</script>
|
|
184
|
+
|
|
185
|
+
<div class="flex flex-col gap-2" {...restProps}>
|
|
186
|
+
{#if label}
|
|
187
|
+
<div class="flex justify-start items-center gap-1">
|
|
188
|
+
<label for={id} class={`${typography.label} leading-tight sm:leading-none`}>
|
|
189
|
+
{label}{#if required}<span class="text-red-500 font-medium text-sm ml-0.5">*</span>{/if}
|
|
190
|
+
</label>
|
|
191
|
+
{#if statusText}
|
|
192
|
+
<span class="text-sm font-medium {statusType === 'success' ? 'text-green-600' : statusType === 'error' ? 'text-red-500' : ''}">({statusText})</span>
|
|
193
|
+
{/if}
|
|
194
|
+
{#if optional}
|
|
195
|
+
<span class={typography.smMuted}>{labels.optional}</span>
|
|
196
|
+
{/if}
|
|
197
|
+
</div>
|
|
198
|
+
{/if}
|
|
199
|
+
|
|
200
|
+
<div class="relative w-full">
|
|
201
|
+
<div class="flex items-stretch w-full">
|
|
202
|
+
<CountrySelector
|
|
203
|
+
bind:country={selectedCountry}
|
|
204
|
+
{disabled}
|
|
205
|
+
{size}
|
|
206
|
+
labels={{
|
|
207
|
+
searchPlaceholder: labels.searchPlaceholder,
|
|
208
|
+
noResults: labels.noResults,
|
|
209
|
+
countrySelector: labels.countrySelector,
|
|
210
|
+
}}
|
|
211
|
+
/>
|
|
212
|
+
|
|
213
|
+
<div class="relative flex-1 flex items-center">
|
|
214
|
+
<input
|
|
215
|
+
bind:this={inputElement}
|
|
216
|
+
{id}
|
|
217
|
+
type="tel"
|
|
218
|
+
{name}
|
|
219
|
+
{placeholder}
|
|
220
|
+
value={displayValue}
|
|
221
|
+
oninput={handleInput}
|
|
222
|
+
inputmode="tel"
|
|
223
|
+
autocomplete="tel"
|
|
224
|
+
class="{typography.body} w-full {sizeClass} bg-gray-50 dark:bg-gray-800 border border-l-0 rounded-r-lg font-medium placeholder-gray-500 dark:placeholder-gray-400 transition-all focus:outline-hidden focus:ring-4 focus:ring-blue-300 dark:focus:ring-blue-300 {hasError ? 'border-red-500' : 'border-gray-300 dark:border-gray-600 hover:border-blue-500 focus:border-blue-500'} {controlled && (buttonText) ? 'pr-20' : ''} {shouldAnimate ? 'focus:scale-[1.01]' : ''} {disabled ? 'opacity-50 cursor-not-allowed' : ''}"
|
|
225
|
+
required={false}
|
|
226
|
+
{disabled}
|
|
227
|
+
aria-required={required}
|
|
228
|
+
/>
|
|
229
|
+
|
|
230
|
+
{#if controlled && buttonText}
|
|
231
|
+
<button
|
|
232
|
+
type="button"
|
|
233
|
+
onclick={handleButtonClick}
|
|
234
|
+
disabled={buttonDisabled}
|
|
235
|
+
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 || errorText ? 'mb-7' : ''}"
|
|
236
|
+
>
|
|
237
|
+
<span class="text-sm font-medium">{buttonText}</span>
|
|
238
|
+
</button>
|
|
239
|
+
{/if}
|
|
240
|
+
</div>
|
|
241
|
+
</div>
|
|
242
|
+
|
|
243
|
+
{#if errorText}
|
|
244
|
+
<div transition:safeSlide={{ duration: 300, easing: cubicOut }} class="flex items-start gap-1.5 mt-2" role="alert" aria-live="assertive">
|
|
245
|
+
<ExclamationCircleOutline class="w-4 h-4 shrink-0 text-red-500 mt-0.5" />
|
|
246
|
+
<p class={typography.error}>{errorText}</p>
|
|
247
|
+
</div>
|
|
248
|
+
{:else if helperText}
|
|
249
|
+
<div class={`mt-2 flex items-center ${typography.xsMuted} opacity-65`}>
|
|
250
|
+
<span>{helperText}</span>
|
|
251
|
+
</div>
|
|
252
|
+
{/if}
|
|
253
|
+
</div>
|
|
254
|
+
</div>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
declare const PhoneInput: import("svelte").Component<{
|
|
2
|
+
[key: string]: unknown;
|
|
3
|
+
value?: string;
|
|
4
|
+
label?: string;
|
|
5
|
+
id?: string;
|
|
6
|
+
name?: string;
|
|
7
|
+
placeholder?: string;
|
|
8
|
+
required?: boolean;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
optional?: boolean;
|
|
11
|
+
size?: "sm" | "md" | "lg";
|
|
12
|
+
errorText?: string;
|
|
13
|
+
helperText?: string;
|
|
14
|
+
color?: "base" | "red";
|
|
15
|
+
controlled?: boolean;
|
|
16
|
+
buttonText?: string | null;
|
|
17
|
+
buttonDisabled?: boolean;
|
|
18
|
+
onButtonClick?: ((value: string) => void) | null;
|
|
19
|
+
defaultCountry?: string;
|
|
20
|
+
labels?: Partial<{
|
|
21
|
+
searchPlaceholder: string;
|
|
22
|
+
noResults: string;
|
|
23
|
+
countrySelector: string;
|
|
24
|
+
optional: string;
|
|
25
|
+
}>;
|
|
26
|
+
onchange?: (detail: {
|
|
27
|
+
value: string;
|
|
28
|
+
country: string;
|
|
29
|
+
isValid: boolean;
|
|
30
|
+
}) => void;
|
|
31
|
+
animateFocus?: boolean;
|
|
32
|
+
statusText?: string;
|
|
33
|
+
statusType?: string;
|
|
34
|
+
}, {
|
|
35
|
+
focus: () => void;
|
|
36
|
+
clear: () => void;
|
|
37
|
+
}, "value">;
|
|
38
|
+
type PhoneInput = ReturnType<typeof PhoneInput>;
|
|
39
|
+
export default PhoneInput;
|
|
40
|
+
//# sourceMappingURL=PhoneInput.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PhoneInput.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/recipes/inputs/PhoneInput.svelte.ts"],"names":[],"mappings":"AAuPA,QAAA,MAAM,UAAU;;YAhNJ,MAAM;YACN,MAAM;SACT,MAAM;WACJ,MAAM;kBACC,MAAM;eACT,OAAO;eACP,OAAO;eACP,OAAO;WACX,IAAI,GAAG,IAAI,GAAG,IAAI;gBACb,MAAM;iBACL,MAAM;YACX,MAAM,GAAG,KAAK;iBACT,OAAO;iBACP,MAAM,GAAG,IAAI;qBACT,OAAO;oBACR,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,IAAI;qBAC/B,MAAM;aACd,OAAO;;;;;MAAsB;eAC3B,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI;mBAClE,OAAO;iBACT,MAAM;iBACN,MAAM;;;;WA2LiC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
|
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
import { PUBLIC_GOOGLE_MAPS_API_KEY } from '../../../config.js';
|
|
5
5
|
import { typography } from '../../../tokens/typography';
|
|
6
6
|
import { bloom } from '../../../utils/transitions.js';
|
|
7
|
+
|
|
8
|
+
const defaultLabels = {
|
|
9
|
+
anErrorOccurred: 'An error occurred',
|
|
10
|
+
seeConsoleForDetails: 'see console for details.',
|
|
11
|
+
errorFetchingPlaceDetails: 'error fetching place details',
|
|
12
|
+
errorFetchToken: 'error fetch token',
|
|
13
|
+
errorLoadingGoogleMapsApi: 'Error loading Google Maps API',
|
|
14
|
+
googleMapsApiKeyRequired: 'Google Maps API key is required',
|
|
15
|
+
};
|
|
7
16
|
/** Google Places API address component */ interface AddressComponent { longText: string; shortText: string; types: string[]; } /** Google Places API response data */ interface PlaceData { formattedAddress?: string; addressComponents?: AddressComponent[]; text?: string; [key: string]: unknown; } /** Google Places autocomplete suggestion */ interface AutocompleteSuggestion { placePrediction: { types: string[]; text: { toString(): string }; toPlace(): PlaceObject; }; } /** Google Places place object */ interface PlaceObject { fetchFields(options: { fields: string[] }): Promise<void>; toJSON(): PlaceData; } /** Google Places API interface */ interface PlacesApiInterface { AutocompleteSessionToken: new () => AutocompleteSessionToken; AutocompleteSuggestion: { fetchAutocompleteSuggestions(request: AutocompleteRequest): Promise<{ suggestions: AutocompleteSuggestion[] }>; }; } /** Google Places autocomplete session token */ interface AutocompleteSessionToken {} /** Autocomplete request parameters */ interface AutocompleteRequest { input: string; language: string; region: string; sessionToken: AutocompleteSessionToken | string; } /** Search result item */ interface SearchResult { to_place: PlaceObject; text: string; originalText?: string; }
|
|
8
17
|
|
|
9
18
|
interface Props {
|
|
@@ -18,6 +27,7 @@
|
|
|
18
27
|
mode?: 'full' | 'cityState';
|
|
19
28
|
animateFocus?: boolean;
|
|
20
29
|
disabled?: boolean;
|
|
30
|
+
labels?: Partial<typeof defaultLabels>;
|
|
21
31
|
}
|
|
22
32
|
|
|
23
33
|
let {
|
|
@@ -32,8 +42,11 @@
|
|
|
32
42
|
mode = 'full',
|
|
33
43
|
animateFocus = true,
|
|
34
44
|
disabled = false,
|
|
45
|
+
labels: userLabels = {},
|
|
35
46
|
}: Props = $props();
|
|
36
47
|
|
|
48
|
+
let labels = $derived({ ...defaultLabels, ...userLabels });
|
|
49
|
+
|
|
37
50
|
let shouldAnimate = $derived(animateFocus && !disabled);
|
|
38
51
|
|
|
39
52
|
let inputRef: HTMLInputElement;
|
|
@@ -131,9 +144,9 @@
|
|
|
131
144
|
} catch (e: unknown) {
|
|
132
145
|
const error = e as { name?: string; message?: string };
|
|
133
146
|
onError(
|
|
134
|
-
(error.name ||
|
|
147
|
+
(error.name || labels.anErrorOccurred) +
|
|
135
148
|
' - ' +
|
|
136
|
-
(error.message ||
|
|
149
|
+
(error.message || labels.seeConsoleForDetails)
|
|
137
150
|
);
|
|
138
151
|
}
|
|
139
152
|
};
|
|
@@ -156,9 +169,9 @@
|
|
|
156
169
|
} catch (e: unknown) {
|
|
157
170
|
const error = e as { name?: string; message?: string };
|
|
158
171
|
onError(
|
|
159
|
-
(error.name ||
|
|
172
|
+
(error.name || labels.anErrorOccurred) +
|
|
160
173
|
' - ' +
|
|
161
|
-
(error.message ||
|
|
174
|
+
(error.message || labels.errorFetchingPlaceDetails)
|
|
162
175
|
);
|
|
163
176
|
}
|
|
164
177
|
|
|
@@ -175,9 +188,9 @@
|
|
|
175
188
|
} catch (e: unknown) {
|
|
176
189
|
const error = e as { name?: string; message?: string };
|
|
177
190
|
onError(
|
|
178
|
-
(error.name ||
|
|
191
|
+
(error.name || labels.anErrorOccurred) +
|
|
179
192
|
' - ' +
|
|
180
|
-
(error.message ||
|
|
193
|
+
(error.message || labels.errorFetchToken)
|
|
181
194
|
);
|
|
182
195
|
return req;
|
|
183
196
|
}
|
|
@@ -236,7 +249,7 @@
|
|
|
236
249
|
// Initialize Google Maps API
|
|
237
250
|
const initGoogleMaps = async () => {
|
|
238
251
|
if (!PUBLIC_GOOGLE_MAPS_API_KEY) {
|
|
239
|
-
onError(
|
|
252
|
+
onError(labels.googleMapsApiKeyRequired);
|
|
240
253
|
return;
|
|
241
254
|
}
|
|
242
255
|
|
|
@@ -255,9 +268,9 @@
|
|
|
255
268
|
} catch (e: unknown) {
|
|
256
269
|
const error = e as { name?: string; message?: string };
|
|
257
270
|
onError(
|
|
258
|
-
(error.name ||
|
|
271
|
+
(error.name || labels.anErrorOccurred) +
|
|
259
272
|
' - ' +
|
|
260
|
-
(error.message ||
|
|
273
|
+
(error.message || labels.errorLoadingGoogleMapsApi)
|
|
261
274
|
);
|
|
262
275
|
}
|
|
263
276
|
};
|
|
@@ -1,28 +1,33 @@
|
|
|
1
|
-
|
|
2
|
-
longText: string;
|
|
3
|
-
shortText: string;
|
|
4
|
-
types: string[];
|
|
5
|
-
}
|
|
6
|
-
/** Google Places API response data */ interface PlaceData {
|
|
7
|
-
formattedAddress?: string;
|
|
8
|
-
addressComponents?: AddressComponent[];
|
|
9
|
-
text?: string;
|
|
10
|
-
[key: string]: unknown;
|
|
11
|
-
}
|
|
12
|
-
interface Props {
|
|
1
|
+
declare const PlaceAutocomplete: import("svelte").Component<{
|
|
13
2
|
fetchFields?: string[];
|
|
14
3
|
placeholder?: string;
|
|
15
4
|
language?: string;
|
|
16
5
|
region?: string;
|
|
17
6
|
autocomplete?: string;
|
|
18
7
|
initialValue?: string;
|
|
19
|
-
onResponse?: (data:
|
|
8
|
+
onResponse?: (data: {
|
|
9
|
+
[key: string]: unknown;
|
|
10
|
+
formattedAddress?: string;
|
|
11
|
+
addressComponents?: {
|
|
12
|
+
longText: string;
|
|
13
|
+
shortText: string;
|
|
14
|
+
types: string[];
|
|
15
|
+
}[];
|
|
16
|
+
text?: string;
|
|
17
|
+
}) => void;
|
|
20
18
|
onError?: (error: string) => void;
|
|
21
|
-
mode?:
|
|
19
|
+
mode?: "full" | "cityState";
|
|
22
20
|
animateFocus?: boolean;
|
|
23
21
|
disabled?: boolean;
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
labels?: Partial<{
|
|
23
|
+
anErrorOccurred: string;
|
|
24
|
+
seeConsoleForDetails: string;
|
|
25
|
+
errorFetchingPlaceDetails: string;
|
|
26
|
+
errorFetchToken: string;
|
|
27
|
+
errorLoadingGoogleMapsApi: string;
|
|
28
|
+
googleMapsApiKeyRequired: string;
|
|
29
|
+
}>;
|
|
30
|
+
}, {}, "placeholder">;
|
|
26
31
|
type PlaceAutocomplete = ReturnType<typeof PlaceAutocomplete>;
|
|
27
32
|
export default PlaceAutocomplete;
|
|
28
33
|
//# sourceMappingURL=PlaceAutocomplete.svelte.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlaceAutocomplete.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.svelte.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PlaceAutocomplete.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.svelte.ts"],"names":[],"mappings":"AA8UA,QAAA,MAAM,iBAAiB;kBAnTL,MAAM,EAAE;kBACR,MAAM;eACT,MAAM;aACR,MAAM;mBACA,MAAM;mBACN,MAAM;iBACR,CAAC,IAAI;;2BATkM,MAAM;4BAAyB;sBAArK,MAAM;uBAAgB,MAAM;mBAAY,MAAM,EAAE;WAAuI;eAAY,MAAM;KAS1P,KAAK,IAAI;cAC5B,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI;WAC1B,MAAM,GAAG,WAAW;mBACZ,OAAO;eACX,OAAO;aACT,OAAO;;;;;;;MAAsB;qBAwSqB,CAAC;AAChE,KAAK,iBAAiB,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC9D,eAAe,iBAAiB,CAAC"}
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
import { SearchOutline } from "../../primitives/Icons";
|
|
4
4
|
import { typography } from '../../tokens/typography';
|
|
5
5
|
|
|
6
|
+
const defaultLabels = {
|
|
7
|
+
placeholder: 'Search',
|
|
8
|
+
};
|
|
9
|
+
|
|
6
10
|
interface Props {
|
|
7
11
|
value?: unknown;
|
|
8
12
|
placeholder?: string;
|
|
@@ -18,13 +22,14 @@
|
|
|
18
22
|
onfocus?: (event: FocusEvent) => void;
|
|
19
23
|
onblur?: (event: FocusEvent) => void;
|
|
20
24
|
children?: Snippet;
|
|
25
|
+
labels?: Partial<typeof defaultLabels>;
|
|
21
26
|
[key: string]: unknown;
|
|
22
27
|
}
|
|
23
28
|
|
|
24
29
|
// API compatible with flowbite-svelte Search
|
|
25
30
|
let {
|
|
26
31
|
value = $bindable(""),
|
|
27
|
-
placeholder =
|
|
32
|
+
placeholder = undefined,
|
|
28
33
|
size = "lg",
|
|
29
34
|
disabled = false,
|
|
30
35
|
id = "",
|
|
@@ -37,9 +42,12 @@
|
|
|
37
42
|
onfocus,
|
|
38
43
|
onblur,
|
|
39
44
|
children,
|
|
45
|
+
labels: userLabels = {},
|
|
40
46
|
...restProps
|
|
41
47
|
}: Props = $props();
|
|
42
48
|
|
|
49
|
+
let labels = $derived({ ...defaultLabels, ...userLabels });
|
|
50
|
+
|
|
43
51
|
const sizes = {
|
|
44
52
|
sm: { icon: "w-3.5 h-3.5", input: `h-8 ${typography.xs} pl-8`, wrapper: "h-8" },
|
|
45
53
|
md: { icon: "w-4 h-4", input: `h-10 ${typography.sm} pl-9`, wrapper: "h-10" },
|
|
@@ -82,7 +90,7 @@
|
|
|
82
90
|
type="search"
|
|
83
91
|
{id}
|
|
84
92
|
{name}
|
|
85
|
-
{placeholder}
|
|
93
|
+
placeholder={placeholder ?? labels.placeholder}
|
|
86
94
|
{disabled}
|
|
87
95
|
class="w-full pr-3 bg-gray-50 dark:bg-gray-700 font-medium border border-gray-300 dark:border-gray-600 rounded-lg transition-colors focus:outline-hidden focus:ring-4 focus:ring-blue-300 dark:focus:ring-blue-800 focus:border-blue-500 hover:border-blue-500 placeholder-gray-500 dark:placeholder-gray-400 [&::-webkit-search-cancel-button]:appearance-none {sizeConfig.input} {disabled ? 'opacity-50 cursor-not-allowed' : ''}"
|
|
88
96
|
bind:value
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
|
-
|
|
2
|
+
declare const Search: import("svelte").Component<{
|
|
3
|
+
[key: string]: unknown;
|
|
3
4
|
value?: unknown;
|
|
4
5
|
placeholder?: string;
|
|
5
|
-
size?:
|
|
6
|
+
size?: "sm" | "md" | "lg";
|
|
6
7
|
disabled?: boolean;
|
|
7
8
|
id?: string;
|
|
8
9
|
name?: string;
|
|
@@ -14,9 +15,10 @@ interface Props {
|
|
|
14
15
|
onfocus?: (event: FocusEvent) => void;
|
|
15
16
|
onblur?: (event: FocusEvent) => void;
|
|
16
17
|
children?: Snippet;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
labels?: Partial<{
|
|
19
|
+
placeholder: string;
|
|
20
|
+
}>;
|
|
21
|
+
}, {}, "value">;
|
|
20
22
|
type Search = ReturnType<typeof Search>;
|
|
21
23
|
export default Search;
|
|
22
24
|
//# sourceMappingURL=Search.svelte.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Search.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/recipes/inputs/Search.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"Search.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/recipes/inputs/Search.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAsGtC,QAAA,MAAM,MAAM;;YAxFA,OAAO;kBACD,MAAM;WACb,IAAI,GAAG,IAAI,GAAG,IAAI;eACd,OAAO;SACb,MAAM;WACJ,MAAM;YACL,MAAM;cACJ,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI;eACrB,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI;gBACrB,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI;cAChC,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI;cAC9B,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI;aAC5B,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI;eACzB,OAAO;aACT,OAAO;;MAAsB;eA0EU,CAAC;AACrD,KAAK,MAAM,GAAG,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC;AACxC,eAAe,MAAM,CAAC"}
|
|
@@ -3,5 +3,6 @@ export { default as OTPInput } from "./OTPInput.svelte";
|
|
|
3
3
|
export { default as PasswordInput } from "./PasswordInput.svelte";
|
|
4
4
|
export { default as PasswordStrengthIndicator } from "./PasswordStrengthIndicator/PasswordStrengthIndicator.svelte";
|
|
5
5
|
export { default as PlaceAutocomplete } from "./PlaceAutocomplete/PlaceAutocomplete.svelte";
|
|
6
|
+
export { default as PhoneInput } from "./PhoneInput.svelte";
|
|
6
7
|
export { default as Search } from "./Search.svelte";
|
|
7
8
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -4,4 +4,5 @@ export { default as OTPInput } from './OTPInput.svelte';
|
|
|
4
4
|
export { default as PasswordInput } from './PasswordInput.svelte';
|
|
5
5
|
export { default as PasswordStrengthIndicator } from './PasswordStrengthIndicator/PasswordStrengthIndicator.svelte';
|
|
6
6
|
export { default as PlaceAutocomplete } from './PlaceAutocomplete/PlaceAutocomplete.svelte';
|
|
7
|
+
export { default as PhoneInput } from './PhoneInput.svelte';
|
|
7
8
|
export { default as Search } from './Search.svelte';
|