@getmicdrop/svelte-components 5.6.1 → 5.7.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 +172 -172
- package/dist/calendar/Calendar/MiniMonthCalendar.svelte +782 -782
- package/dist/calendar/FAQs/FAQs.svelte +75 -75
- package/dist/calendar/MonthSwitcher/MonthSwitcher.svelte +126 -126
- package/dist/calendar/OrderSummary/OrderSummary.svelte +367 -367
- package/dist/calendar/PublicCard/PublicCard.svelte +134 -134
- package/dist/calendar/ShowCard/ShowCard.svelte +157 -157
- package/dist/calendar/ShowTimeCard/ShowTimeCard.svelte +61 -61
- package/dist/components/Heading.svelte +57 -0
- package/dist/components/Heading.svelte.d.ts +12 -0
- package/dist/components/Heading.svelte.d.ts.map +1 -0
- package/dist/components/Layout/AppShell.svelte +104 -104
- package/dist/components/Layout/ContentSection.svelte +80 -80
- package/dist/components/Layout/Grid.svelte +4 -4
- package/dist/components/Layout/Heading.svelte +81 -81
- package/dist/components/Layout/PageContainer.svelte +69 -69
- package/dist/components/Layout/Responsive.svelte +75 -75
- package/dist/components/Layout/Section.svelte +80 -80
- package/dist/components/Layout/ShowOnDesktop.svelte +37 -37
- package/dist/components/Layout/ShowOnMobile.svelte +37 -37
- package/dist/components/Layout/Sidebar.svelte +108 -108
- package/dist/components/Layout/Stack.spec.js +1 -1
- package/dist/components/Layout/Stack.svelte +6 -6
- package/dist/components/Layout/Text.svelte +87 -87
- package/dist/components/Layout/TwoColumn.svelte +108 -108
- package/dist/components/Layout/index.d.ts +11 -0
- package/dist/components/Layout/index.d.ts.map +1 -0
- package/dist/components/Layout/index.js +14 -0
- package/dist/components/Text.svelte +40 -0
- package/dist/components/Text.svelte.d.ts +11 -0
- package/dist/components/Text.svelte.d.ts.map +1 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +12 -0
- package/dist/constants/validation.js +91 -91
- package/dist/constants/validation.spec.js +64 -64
- package/dist/datetime/__tests__/format.test.js +1 -1
- package/dist/datetime/__tests__/parse.test.js +1 -1
- package/dist/datetime/__tests__/timezone.test.js +1 -1
- package/dist/datetime/parse.js +1 -1
- package/dist/forms/createFormStore.svelte.js +0 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +10 -1
- package/dist/patterns/data/DataGrid.svelte +45 -45
- package/dist/patterns/data/DataList.svelte +24 -24
- package/dist/patterns/data/DataTable.svelte +36 -36
- package/dist/patterns/forms/FormActions.spec.js +95 -95
- package/dist/patterns/forms/FormActions.stories.svelte +97 -97
- package/dist/patterns/forms/FormActions.svelte +46 -46
- package/dist/patterns/forms/FormGrid.svelte +33 -33
- package/dist/patterns/forms/FormSection.svelte +32 -32
- package/dist/patterns/forms/FormValidationSummary.stories.svelte +83 -83
- package/dist/patterns/forms/FormValidationSummary.svelte +74 -74
- package/dist/patterns/layout/Sidebar.svelte +39 -39
- package/dist/patterns/navigation/BottomNav.stories.svelte +117 -117
- package/dist/patterns/navigation/BottomNav.svelte +74 -74
- package/dist/patterns/navigation/Header.stories.svelte +77 -77
- package/dist/patterns/navigation/Header.svelte +193 -193
- package/dist/patterns/page/PageHeader.svelte +18 -18
- package/dist/patterns/page/PageLayout.svelte +40 -40
- package/dist/patterns/page/PageLoader.spec.js +57 -57
- package/dist/patterns/page/PageLoader.stories.svelte +137 -137
- package/dist/patterns/page/PageLoader.svelte +24 -24
- package/dist/patterns/page/SectionHeader.svelte +29 -29
- package/dist/presets/badges.js +112 -112
- package/dist/presets/buttons.js +76 -76
- package/dist/presets/index.js +9 -9
- package/dist/primitives/Accordion/Accordion.stories.svelte +75 -75
- package/dist/primitives/Accordion/Accordion.svelte +42 -42
- package/dist/primitives/Accordion/AccordionItem.svelte +95 -95
- package/dist/primitives/Alert/Alert.spec.js +173 -173
- package/dist/primitives/Alert/Alert.stories.svelte +88 -88
- package/dist/primitives/Alert/Alert.svelte +27 -27
- package/dist/primitives/Avatar/Avatar.stories.svelte +94 -94
- package/dist/primitives/Avatar/Avatar.svelte +66 -66
- package/dist/primitives/Badges/Badge.spec.js +144 -144
- package/dist/primitives/Badges/Badge.stories.svelte +86 -86
- package/dist/primitives/Badges/Badge.svelte +79 -79
- package/dist/primitives/BottomSheet/BottomSheet.spec.js +136 -136
- package/dist/primitives/BottomSheet/BottomSheet.stories.svelte +83 -83
- package/dist/primitives/BottomSheet/BottomSheet.svelte +100 -100
- package/dist/primitives/Breadcrumb/Breadcrumb.spec.js +122 -122
- package/dist/primitives/Breadcrumb/Breadcrumb.stories.svelte +23 -23
- package/dist/primitives/Breadcrumb/Breadcrumb.svelte +89 -89
- package/dist/primitives/Button/Button.spec.js +223 -223
- package/dist/primitives/Button/Button.stories.svelte +76 -76
- package/dist/primitives/Button/Button.svelte +270 -270
- package/dist/primitives/Button/ButtonSaveDemo.spec.js +146 -146
- package/dist/primitives/Button/ButtonSaveDemo.svelte +25 -25
- package/dist/primitives/Button/ButtonVariantShowcase.svelte +129 -129
- package/dist/primitives/Card.spec.js +49 -49
- package/dist/primitives/Card.stories.svelte +22 -22
- package/dist/primitives/Card.svelte +28 -28
- package/dist/primitives/Checkbox/Checkbox.stories.svelte +84 -84
- package/dist/primitives/Checkbox/Checkbox.svelte +88 -88
- package/dist/primitives/DarkModeToggle.spec.js +390 -390
- package/dist/primitives/DarkModeToggle.stories.svelte +57 -57
- package/dist/primitives/DarkModeToggle.svelte +136 -136
- package/dist/primitives/Drawer/Drawer.stories.svelte +80 -80
- package/dist/primitives/Drawer/Drawer.svelte +120 -120
- package/dist/primitives/Dropdown/Dropdown.stories.svelte +137 -137
- package/dist/primitives/Dropdown/Dropdown.svelte +14 -14
- package/dist/primitives/Dropdown/DropdownDivider.svelte +9 -9
- package/dist/primitives/Dropdown/DropdownItem.svelte +80 -80
- package/dist/primitives/Helper/Helper.svelte +33 -33
- package/dist/primitives/Icons/ArrowLeft.svelte +8 -8
- package/dist/primitives/Icons/ArrowRight.svelte +8 -8
- package/dist/primitives/Icons/Availability.svelte +14 -14
- package/dist/primitives/Icons/Back.svelte +14 -14
- package/dist/primitives/Icons/CheckCircle.svelte +6 -6
- package/dist/primitives/Icons/CheckCircleOutline.svelte +15 -15
- package/dist/primitives/Icons/ChevronLeft.svelte +4 -4
- package/dist/primitives/Icons/ChevronRight.svelte +4 -4
- package/dist/primitives/Icons/Copy.svelte +15 -15
- package/dist/primitives/Icons/Cross.svelte +5 -5
- package/dist/primitives/Icons/DownArrow.svelte +8 -8
- package/dist/primitives/Icons/ErrorCircle.svelte +6 -6
- package/dist/primitives/Icons/FacebookIcon.svelte +2 -2
- package/dist/primitives/Icons/Home.svelte +15 -15
- package/dist/primitives/Icons/Icon.spec.js +169 -169
- package/dist/primitives/Icons/Icon.stories.svelte +100 -100
- package/dist/primitives/Icons/Icon.svelte +52 -52
- package/dist/primitives/Icons/IconGallery.stories.svelte +235 -235
- package/dist/primitives/Icons/Info.svelte +7 -7
- package/dist/primitives/Icons/InstagramIcon.svelte +4 -4
- package/dist/primitives/Icons/LogoInstagram.svelte +2 -2
- package/dist/primitives/Icons/Message.svelte +15 -15
- package/dist/primitives/Icons/MoonIcon.svelte +5 -5
- package/dist/primitives/Icons/More.svelte +21 -21
- package/dist/primitives/Icons/MoreHori.spec.js +61 -61
- package/dist/primitives/Icons/MoreHori.svelte +22 -22
- package/dist/primitives/Icons/Notification.svelte +14 -14
- package/dist/primitives/Icons/Payment.svelte +14 -14
- package/dist/primitives/Icons/Profile.svelte +21 -21
- package/dist/primitives/Icons/Reload.svelte +29 -29
- package/dist/primitives/Icons/Shows.svelte +21 -21
- package/dist/primitives/Icons/Signout.svelte +21 -21
- package/dist/primitives/Icons/SunIcon.svelte +8 -8
- package/dist/primitives/Icons/TiktokIcon.svelte +2 -2
- package/dist/primitives/Icons/TwitterIcon.svelte +2 -2
- package/dist/primitives/Icons/WarningIcon.spec.js +18 -18
- package/dist/primitives/Icons/WarningIcon.svelte +5 -5
- package/dist/primitives/Input/Input.spec.js +573 -573
- package/dist/primitives/Input/Input.stories.svelte +139 -139
- package/dist/primitives/Input/Select.spec.js +212 -212
- package/dist/primitives/Input/Select.stories.svelte +112 -112
- package/dist/primitives/Input/Select.svelte +128 -128
- package/dist/primitives/Input/Textarea.stories.svelte +137 -137
- package/dist/primitives/Input/Textarea.svelte +35 -35
- package/dist/primitives/Label/Label.svelte +37 -37
- package/dist/primitives/Modal/Modal.spec.js +99 -99
- package/dist/primitives/Modal/Modal.stories.svelte +86 -86
- package/dist/primitives/Pagination/Pagination.stories.svelte +76 -76
- package/dist/primitives/Pagination/Pagination.svelte +261 -261
- package/dist/primitives/Radio/Radio.stories.svelte +80 -80
- package/dist/primitives/Radio/Radio.svelte +67 -67
- package/dist/primitives/Skeleton/CardPlaceholder.svelte +87 -87
- package/dist/primitives/Skeleton/ImagePlaceholder.svelte +59 -59
- package/dist/primitives/Skeleton/ListPlaceholder.svelte +76 -76
- package/dist/primitives/Skeleton/Skeleton.stories.svelte +151 -151
- package/dist/primitives/Skeleton/Skeleton.svelte +26 -26
- package/dist/primitives/Spinner/Spinner.spec.js +71 -71
- package/dist/primitives/Spinner/Spinner.stories.svelte +29 -29
- package/dist/primitives/Spinner/Spinner.svelte +20 -20
- package/dist/primitives/Tabs/TabItem.svelte +49 -49
- package/dist/primitives/Tabs/Tabs.stories.svelte +112 -112
- package/dist/primitives/Tabs/Tabs.svelte +123 -123
- package/dist/primitives/Toggle.spec.js +143 -143
- package/dist/primitives/Toggle.stories.svelte +92 -92
- package/dist/primitives/Tooltip/Tooltip.svelte +83 -83
- package/dist/primitives/Typography/Typography.svelte +53 -53
- package/dist/primitives/ValidationError.spec.js +103 -103
- package/dist/primitives/ValidationError.stories.svelte +69 -69
- package/dist/primitives/ValidationError.svelte +29 -29
- package/dist/primitives/index.js +91 -91
- package/dist/recipes/CropImage/CropImage.spec.js +208 -208
- package/dist/recipes/CropImage/CropImage.stories.svelte +104 -104
- package/dist/recipes/CropImage/CropImage.svelte +238 -238
- package/dist/recipes/ImageUploader/ImageUploader.stories.svelte +125 -125
- package/dist/recipes/ImageUploader/ImageUploader.svelte +804 -804
- package/dist/recipes/Toaster/Toaster.stories.svelte +62 -62
- package/dist/recipes/feedback/EmptyState/EmptyState.svelte +1 -1
- package/dist/recipes/feedback/ErrorDisplay.spec.js +69 -69
- package/dist/recipes/feedback/ErrorDisplay.stories.svelte +101 -101
- package/dist/recipes/feedback/ErrorDisplay.svelte +1 -1
- package/dist/recipes/feedback/StatusIndicator/StatusIndicator.spec.js +133 -133
- package/dist/recipes/feedback/StatusIndicator/StatusIndicator.svelte +157 -157
- package/dist/recipes/fields/CheckboxField.svelte +85 -85
- package/dist/recipes/fields/FormField.svelte +58 -58
- package/dist/recipes/fields/RadioGroup.svelte +95 -95
- package/dist/recipes/fields/SelectField.svelte +80 -80
- package/dist/recipes/fields/TextareaField.svelte +97 -97
- package/dist/recipes/fields/ToggleField.svelte +60 -60
- package/dist/recipes/fields/index.js +7 -7
- package/dist/recipes/inputs/MultiSelect.spec.js +258 -258
- package/dist/recipes/inputs/MultiSelect.stories.svelte +133 -133
- package/dist/recipes/inputs/OTPInput.spec.js +251 -251
- package/dist/recipes/inputs/OTPInput.stories.svelte +162 -162
- package/dist/recipes/inputs/OTPInput.svelte +29 -29
- package/dist/recipes/inputs/PasswordInput.svelte +22 -22
- package/dist/recipes/inputs/PasswordStrengthIndicator/PasswordStrengthIndicator.svelte +117 -117
- package/dist/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.stories.svelte +123 -123
- package/dist/recipes/inputs/Search.svelte +37 -37
- package/dist/recipes/inputs/SelectDropdown.svelte +57 -57
- package/dist/recipes/modals/AlertModal.svelte +130 -130
- package/dist/recipes/modals/ConfirmationModal.spec.js +206 -206
- package/dist/recipes/modals/ConfirmationModal.stories.svelte +119 -119
- package/dist/recipes/modals/ConfirmationModal.svelte +152 -152
- package/dist/recipes/modals/InputModal.svelte +182 -182
- package/dist/recipes/modals/ModalStateManager.spec.js +100 -100
- package/dist/recipes/modals/ModalStateManager.svelte +77 -77
- package/dist/recipes/modals/ModalTestWrapper.svelte +65 -65
- package/dist/recipes/modals/StatusModal.svelte +206 -206
- package/dist/services/EventService.js +75 -75
- package/dist/services/EventService.spec.js +217 -217
- package/dist/services/ShowService.spec.js +345 -345
- package/dist/stores/auth.js +36 -44
- package/dist/stores/auth.spec.js +139 -139
- package/dist/stores/formDataStore.d.ts.map +1 -1
- package/dist/stores/formDataStore.js +0 -8
- package/dist/stores/formSave.d.ts.map +1 -1
- package/dist/stores/formSave.js +0 -8
- package/dist/stores/navigation.d.ts.map +1 -1
- package/dist/stores/navigation.js +0 -8
- package/dist/stores/toaster.js +13 -13
- package/dist/stories/ButtonAuditReview.stories.svelte +14 -14
- package/dist/stories/ButtonAuditReview.svelte +427 -427
- package/dist/stories/PatternsGallery.stories.svelte +19 -19
- package/dist/stories/PatternsGallery.svelte +206 -206
- package/dist/stories/PrimitivesGallery.stories.svelte +19 -19
- package/dist/stories/PrimitivesGallery.svelte +725 -725
- package/dist/stories/RecipesGallery.stories.svelte +19 -19
- package/dist/stories/RecipesGallery.svelte +271 -271
- package/dist/stories/button-audit-manifest.json +11186 -11186
- package/dist/tailwind/preset.cjs +82 -82
- package/dist/telemetry.js +405 -405
- package/dist/telemetry.spec.js +1169 -1169
- package/dist/tokens/tokens.css +87 -87
- package/dist/tokens/typography-base.css +163 -163
- package/dist/utils/apiConfig.spec.js +219 -219
- package/dist/utils/transitions.js +62 -62
- package/dist/utils/utils.js +354 -354
- package/package.json +1 -1
- package/dist/stores/auth.svelte.d.ts +0 -39
- package/dist/stores/auth.svelte.d.ts.map +0 -1
- package/dist/stores/auth.svelte.js +0 -60
- package/dist/stores/formDataStore.svelte.d.ts +0 -47
- package/dist/stores/formDataStore.svelte.d.ts.map +0 -1
- package/dist/stores/formDataStore.svelte.js +0 -84
- package/dist/stores/formSave.svelte.d.ts +0 -33
- package/dist/stores/formSave.svelte.d.ts.map +0 -1
- package/dist/stores/formSave.svelte.js +0 -113
- package/dist/stores/navigation.svelte.d.ts +0 -35
- package/dist/stores/navigation.svelte.d.ts.map +0 -1
- package/dist/stores/navigation.svelte.js +0 -69
|
@@ -54,30 +54,30 @@
|
|
|
54
54
|
let displayText = $derived(selectedItem ? selectedItem.name : placeholder);
|
|
55
55
|
|
|
56
56
|
let sizeClass = $derived(formControlSizes[size] || formControlSizes.md);
|
|
57
|
-
|
|
58
|
-
function updateDropdownPosition() {
|
|
59
|
-
if (!triggerElement || !portal) return;
|
|
60
|
-
const rect = triggerElement.getBoundingClientRect();
|
|
61
|
-
dropdownPosition = {
|
|
62
|
-
top: rect.bottom + 4,
|
|
63
|
-
left: rect.left,
|
|
64
|
-
width: rect.width
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
async function toggle() {
|
|
69
|
-
if (disabled) return;
|
|
70
|
-
isOpen = !isOpen;
|
|
71
|
-
if (isOpen) {
|
|
72
|
-
focusedIndex = items.findIndex((item) => item.value === value);
|
|
73
|
-
window.dispatchEvent(new CustomEvent('select-opened', { detail: { instanceId } }));
|
|
74
|
-
if (portal) {
|
|
75
|
-
await tick();
|
|
76
|
-
updateDropdownPosition();
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
57
|
+
|
|
58
|
+
function updateDropdownPosition() {
|
|
59
|
+
if (!triggerElement || !portal) return;
|
|
60
|
+
const rect = triggerElement.getBoundingClientRect();
|
|
61
|
+
dropdownPosition = {
|
|
62
|
+
top: rect.bottom + 4,
|
|
63
|
+
left: rect.left,
|
|
64
|
+
width: rect.width
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function toggle() {
|
|
69
|
+
if (disabled) return;
|
|
70
|
+
isOpen = !isOpen;
|
|
71
|
+
if (isOpen) {
|
|
72
|
+
focusedIndex = items.findIndex((item) => item.value === value);
|
|
73
|
+
window.dispatchEvent(new CustomEvent('select-opened', { detail: { instanceId } }));
|
|
74
|
+
if (portal) {
|
|
75
|
+
await tick();
|
|
76
|
+
updateDropdownPosition();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
81
|
function handleOtherSelectOpened(event: Event) {
|
|
82
82
|
const customEvent = event as CustomEvent<{ instanceId: string }>;
|
|
83
83
|
if (customEvent.detail.instanceId !== instanceId && isOpen) {
|
|
@@ -143,107 +143,107 @@
|
|
|
143
143
|
close();
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
|
-
|
|
147
|
-
onMount(() => {
|
|
148
|
-
document.addEventListener("click", handleClickOutside, true);
|
|
149
|
-
window.addEventListener("select-opened", handleOtherSelectOpened);
|
|
150
|
-
|
|
151
|
-
// Update position on scroll/resize when portal is enabled
|
|
152
|
-
if (portal) {
|
|
153
|
-
window.addEventListener("scroll", updateDropdownPosition, true);
|
|
154
|
-
window.addEventListener("resize", updateDropdownPosition);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
return () => {
|
|
158
|
-
document.removeEventListener("click", handleClickOutside, true);
|
|
159
|
-
window.removeEventListener("select-opened", handleOtherSelectOpened);
|
|
160
|
-
if (portal) {
|
|
161
|
-
window.removeEventListener("scroll", updateDropdownPosition, true);
|
|
162
|
-
window.removeEventListener("resize", updateDropdownPosition);
|
|
163
|
-
}
|
|
164
|
-
};
|
|
165
|
-
});
|
|
166
|
-
</script>
|
|
167
|
-
|
|
168
|
-
<div class="w-full flex flex-col gap-2" {...restProps}>
|
|
169
|
-
{#if label}
|
|
170
|
-
<div class="flex justify-start items-center gap-1">
|
|
171
|
-
<label for={id || name} class={typography.label}>
|
|
172
|
-
{label}{#if required}<span class="text-red-500 font-medium text-sm ml-0.5">*</span>{/if}
|
|
173
|
-
</label>
|
|
174
|
-
</div>
|
|
175
|
-
{/if}
|
|
176
|
-
|
|
177
|
-
<div class="relative w-full">
|
|
178
|
-
<button
|
|
179
|
-
type="button"
|
|
180
|
-
bind:this={triggerElement}
|
|
181
|
-
{id}
|
|
182
|
-
{name}
|
|
183
|
-
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}`}"
|
|
184
|
-
{disabled}
|
|
185
|
-
aria-haspopup="listbox"
|
|
186
|
-
aria-expanded={isOpen}
|
|
187
|
-
onclick={toggle}
|
|
188
|
-
onkeydown={handleKeydown}
|
|
189
|
-
>
|
|
190
|
-
<span class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap">{displayText}</span>
|
|
191
|
-
<ChevronDownOutline class="w-4 h-4 shrink-0 {typography.iconMuted} transition-transform duration-200 {isOpen ? 'rotate-180' : ''}" />
|
|
192
|
-
</button>
|
|
193
|
-
|
|
194
|
-
{#if isOpen && !portal}
|
|
195
|
-
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
196
|
-
<ul
|
|
197
|
-
bind:this={dropdownElement}
|
|
198
|
-
class="absolute top-full left-0 right-0 z-50 mt-1 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"
|
|
199
|
-
role="listbox"
|
|
200
|
-
tabindex="-1"
|
|
201
|
-
>
|
|
202
|
-
{#each items as item, index}
|
|
203
|
-
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
204
|
-
<li
|
|
205
|
-
id="{id || name}-option-{index}"
|
|
206
|
-
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'}`}
|
|
207
|
-
role="option"
|
|
208
|
-
aria-selected={item.value === value}
|
|
209
|
-
onclick={() => selectItem(item)}
|
|
210
|
-
onmouseenter={() => (focusedIndex = index)}
|
|
211
|
-
>
|
|
212
|
-
{item.name}
|
|
213
|
-
</li>
|
|
214
|
-
{/each}
|
|
215
|
-
</ul>
|
|
216
|
-
{/if}
|
|
217
|
-
</div>
|
|
218
|
-
|
|
219
|
-
{#if error}
|
|
220
|
-
<p class={typography.error}>{error}</p>
|
|
221
|
-
{/if}
|
|
222
|
-
</div>
|
|
223
|
-
|
|
224
|
-
{#if isOpen && portal}
|
|
225
|
-
<!-- Portal dropdown - truly moved to document.body to escape overflow containers and transforms -->
|
|
226
|
-
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
227
|
-
<ul
|
|
228
|
-
bind:this={dropdownElement}
|
|
229
|
-
use:portalAction
|
|
230
|
-
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"
|
|
231
|
-
style="top: {dropdownPosition.top}px; left: {dropdownPosition.left}px; width: {dropdownPosition.width}px;"
|
|
232
|
-
role="listbox"
|
|
233
|
-
tabindex="-1"
|
|
234
|
-
>
|
|
235
|
-
{#each items as item, index}
|
|
236
|
-
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
237
|
-
<li
|
|
238
|
-
id="{id || name}-option-{index}"
|
|
239
|
-
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'}`}
|
|
240
|
-
role="option"
|
|
241
|
-
aria-selected={item.value === value}
|
|
242
|
-
onclick={() => selectItem(item)}
|
|
243
|
-
onmouseenter={() => (focusedIndex = index)}
|
|
244
|
-
>
|
|
245
|
-
{item.name}
|
|
246
|
-
</li>
|
|
247
|
-
{/each}
|
|
248
|
-
</ul>
|
|
249
|
-
{/if}
|
|
146
|
+
|
|
147
|
+
onMount(() => {
|
|
148
|
+
document.addEventListener("click", handleClickOutside, true);
|
|
149
|
+
window.addEventListener("select-opened", handleOtherSelectOpened);
|
|
150
|
+
|
|
151
|
+
// Update position on scroll/resize when portal is enabled
|
|
152
|
+
if (portal) {
|
|
153
|
+
window.addEventListener("scroll", updateDropdownPosition, true);
|
|
154
|
+
window.addEventListener("resize", updateDropdownPosition);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return () => {
|
|
158
|
+
document.removeEventListener("click", handleClickOutside, true);
|
|
159
|
+
window.removeEventListener("select-opened", handleOtherSelectOpened);
|
|
160
|
+
if (portal) {
|
|
161
|
+
window.removeEventListener("scroll", updateDropdownPosition, true);
|
|
162
|
+
window.removeEventListener("resize", updateDropdownPosition);
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
});
|
|
166
|
+
</script>
|
|
167
|
+
|
|
168
|
+
<div class="w-full flex flex-col gap-2" {...restProps}>
|
|
169
|
+
{#if label}
|
|
170
|
+
<div class="flex justify-start items-center gap-1">
|
|
171
|
+
<label for={id || name} class={typography.label}>
|
|
172
|
+
{label}{#if required}<span class="text-red-500 font-medium text-sm ml-0.5">*</span>{/if}
|
|
173
|
+
</label>
|
|
174
|
+
</div>
|
|
175
|
+
{/if}
|
|
176
|
+
|
|
177
|
+
<div class="relative w-full">
|
|
178
|
+
<button
|
|
179
|
+
type="button"
|
|
180
|
+
bind:this={triggerElement}
|
|
181
|
+
{id}
|
|
182
|
+
{name}
|
|
183
|
+
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}`}"
|
|
184
|
+
{disabled}
|
|
185
|
+
aria-haspopup="listbox"
|
|
186
|
+
aria-expanded={isOpen}
|
|
187
|
+
onclick={toggle}
|
|
188
|
+
onkeydown={handleKeydown}
|
|
189
|
+
>
|
|
190
|
+
<span class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap">{displayText}</span>
|
|
191
|
+
<ChevronDownOutline class="w-4 h-4 shrink-0 {typography.iconMuted} transition-transform duration-200 {isOpen ? 'rotate-180' : ''}" />
|
|
192
|
+
</button>
|
|
193
|
+
|
|
194
|
+
{#if isOpen && !portal}
|
|
195
|
+
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
196
|
+
<ul
|
|
197
|
+
bind:this={dropdownElement}
|
|
198
|
+
class="absolute top-full left-0 right-0 z-50 mt-1 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"
|
|
199
|
+
role="listbox"
|
|
200
|
+
tabindex="-1"
|
|
201
|
+
>
|
|
202
|
+
{#each items as item, index}
|
|
203
|
+
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
204
|
+
<li
|
|
205
|
+
id="{id || name}-option-{index}"
|
|
206
|
+
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'}`}
|
|
207
|
+
role="option"
|
|
208
|
+
aria-selected={item.value === value}
|
|
209
|
+
onclick={() => selectItem(item)}
|
|
210
|
+
onmouseenter={() => (focusedIndex = index)}
|
|
211
|
+
>
|
|
212
|
+
{item.name}
|
|
213
|
+
</li>
|
|
214
|
+
{/each}
|
|
215
|
+
</ul>
|
|
216
|
+
{/if}
|
|
217
|
+
</div>
|
|
218
|
+
|
|
219
|
+
{#if error}
|
|
220
|
+
<p class={typography.error}>{error}</p>
|
|
221
|
+
{/if}
|
|
222
|
+
</div>
|
|
223
|
+
|
|
224
|
+
{#if isOpen && portal}
|
|
225
|
+
<!-- Portal dropdown - truly moved to document.body to escape overflow containers and transforms -->
|
|
226
|
+
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
227
|
+
<ul
|
|
228
|
+
bind:this={dropdownElement}
|
|
229
|
+
use:portalAction
|
|
230
|
+
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"
|
|
231
|
+
style="top: {dropdownPosition.top}px; left: {dropdownPosition.left}px; width: {dropdownPosition.width}px;"
|
|
232
|
+
role="listbox"
|
|
233
|
+
tabindex="-1"
|
|
234
|
+
>
|
|
235
|
+
{#each items as item, index}
|
|
236
|
+
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
237
|
+
<li
|
|
238
|
+
id="{id || name}-option-{index}"
|
|
239
|
+
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'}`}
|
|
240
|
+
role="option"
|
|
241
|
+
aria-selected={item.value === value}
|
|
242
|
+
onclick={() => selectItem(item)}
|
|
243
|
+
onmouseenter={() => (focusedIndex = index)}
|
|
244
|
+
>
|
|
245
|
+
{item.name}
|
|
246
|
+
</li>
|
|
247
|
+
{/each}
|
|
248
|
+
</ul>
|
|
249
|
+
{/if}
|
|
@@ -1,137 +1,137 @@
|
|
|
1
|
-
<script module>
|
|
2
|
-
import { defineMeta } from '@storybook/addon-svelte-csf';
|
|
3
|
-
import Textarea from './Textarea.svelte';
|
|
4
|
-
|
|
5
|
-
const { Story } = defineMeta({
|
|
6
|
-
title: 'Primitives/Textarea',
|
|
7
|
-
component: Textarea,
|
|
8
|
-
tags: ['autodocs'],
|
|
9
|
-
argTypes: {
|
|
10
|
-
label: { control: 'text' },
|
|
11
|
-
placeholder: { control: 'text' },
|
|
12
|
-
rows: { control: 'number' },
|
|
13
|
-
disabled: { control: 'boolean' },
|
|
14
|
-
required: { control: 'boolean' },
|
|
15
|
-
maxlength: { control: 'number' },
|
|
16
|
-
errorText: { control: 'text' },
|
|
17
|
-
},
|
|
18
|
-
parameters: {
|
|
19
|
-
docs: {
|
|
20
|
-
description: {
|
|
21
|
-
component: 'Multi-line text input component.',
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
let value = $state('');
|
|
28
|
-
</script>
|
|
29
|
-
|
|
30
|
-
<Story name="Default">
|
|
31
|
-
{#snippet template()}
|
|
32
|
-
<div class="max-w-md">
|
|
33
|
-
<Textarea
|
|
34
|
-
label="Description"
|
|
35
|
-
placeholder="Enter your description..."
|
|
36
|
-
/>
|
|
37
|
-
</div>
|
|
38
|
-
{/snippet}
|
|
39
|
-
</Story>
|
|
40
|
-
|
|
41
|
-
<Story name="With Value">
|
|
42
|
-
{#snippet template()}
|
|
43
|
-
<div class="max-w-md">
|
|
44
|
-
<Textarea
|
|
45
|
-
label="Bio"
|
|
46
|
-
placeholder="Tell us about yourself..."
|
|
47
|
-
bind:value={value}
|
|
48
|
-
/>
|
|
49
|
-
<p class="text-sm text-gray-500 mt-2">{value.length} characters</p>
|
|
50
|
-
</div>
|
|
51
|
-
{/snippet}
|
|
52
|
-
</Story>
|
|
53
|
-
|
|
54
|
-
<Story name="With Max Length">
|
|
55
|
-
{#snippet template()}
|
|
56
|
-
<div class="max-w-md">
|
|
57
|
-
<Textarea
|
|
58
|
-
label="Short Bio"
|
|
59
|
-
placeholder="Keep it brief..."
|
|
60
|
-
maxlength={200}
|
|
61
|
-
helperText="Maximum 200 characters"
|
|
62
|
-
/>
|
|
63
|
-
</div>
|
|
64
|
-
{/snippet}
|
|
65
|
-
</Story>
|
|
66
|
-
|
|
67
|
-
<Story name="With Error">
|
|
68
|
-
{#snippet template()}
|
|
69
|
-
<div class="max-w-md">
|
|
70
|
-
<Textarea
|
|
71
|
-
label="Comments"
|
|
72
|
-
placeholder="Enter your comments..."
|
|
73
|
-
errorText="Please provide at least 10 characters"
|
|
74
|
-
/>
|
|
75
|
-
</div>
|
|
76
|
-
{/snippet}
|
|
77
|
-
</Story>
|
|
78
|
-
|
|
79
|
-
<Story name="Custom Rows">
|
|
80
|
-
{#snippet template()}
|
|
81
|
-
<div class="space-y-6 max-w-md">
|
|
82
|
-
<Textarea
|
|
83
|
-
label="Small (2 rows)"
|
|
84
|
-
placeholder="Two rows..."
|
|
85
|
-
rows={2}
|
|
86
|
-
/>
|
|
87
|
-
<Textarea
|
|
88
|
-
label="Medium (4 rows)"
|
|
89
|
-
placeholder="Four rows..."
|
|
90
|
-
rows={4}
|
|
91
|
-
/>
|
|
92
|
-
<Textarea
|
|
93
|
-
label="Large (8 rows)"
|
|
94
|
-
placeholder="Eight rows..."
|
|
95
|
-
rows={8}
|
|
96
|
-
/>
|
|
97
|
-
</div>
|
|
98
|
-
{/snippet}
|
|
99
|
-
</Story>
|
|
100
|
-
|
|
101
|
-
<Story name="Disabled">
|
|
102
|
-
{#snippet template()}
|
|
103
|
-
<div class="max-w-md">
|
|
104
|
-
<Textarea
|
|
105
|
-
label="Disabled Textarea"
|
|
106
|
-
placeholder="Cannot edit this..."
|
|
107
|
-
disabled
|
|
108
|
-
/>
|
|
109
|
-
</div>
|
|
110
|
-
{/snippet}
|
|
111
|
-
</Story>
|
|
112
|
-
|
|
113
|
-
<Story name="All States">
|
|
114
|
-
{#snippet template()}
|
|
115
|
-
<div class="grid grid-cols-2 gap-6 max-w-2xl">
|
|
116
|
-
<Textarea
|
|
117
|
-
label="Default"
|
|
118
|
-
placeholder="Enter text..."
|
|
119
|
-
/>
|
|
120
|
-
<Textarea
|
|
121
|
-
label="With Error"
|
|
122
|
-
placeholder="Enter text..."
|
|
123
|
-
errorText="This field is required"
|
|
124
|
-
/>
|
|
125
|
-
<Textarea
|
|
126
|
-
label="Disabled"
|
|
127
|
-
placeholder="Cannot edit..."
|
|
128
|
-
disabled
|
|
129
|
-
/>
|
|
130
|
-
<Textarea
|
|
131
|
-
label="With Helper"
|
|
132
|
-
placeholder="Enter text..."
|
|
133
|
-
helperText="Optional additional information"
|
|
134
|
-
/>
|
|
135
|
-
</div>
|
|
136
|
-
{/snippet}
|
|
137
|
-
</Story>
|
|
1
|
+
<script module>
|
|
2
|
+
import { defineMeta } from '@storybook/addon-svelte-csf';
|
|
3
|
+
import Textarea from './Textarea.svelte';
|
|
4
|
+
|
|
5
|
+
const { Story } = defineMeta({
|
|
6
|
+
title: 'Primitives/Textarea',
|
|
7
|
+
component: Textarea,
|
|
8
|
+
tags: ['autodocs'],
|
|
9
|
+
argTypes: {
|
|
10
|
+
label: { control: 'text' },
|
|
11
|
+
placeholder: { control: 'text' },
|
|
12
|
+
rows: { control: 'number' },
|
|
13
|
+
disabled: { control: 'boolean' },
|
|
14
|
+
required: { control: 'boolean' },
|
|
15
|
+
maxlength: { control: 'number' },
|
|
16
|
+
errorText: { control: 'text' },
|
|
17
|
+
},
|
|
18
|
+
parameters: {
|
|
19
|
+
docs: {
|
|
20
|
+
description: {
|
|
21
|
+
component: 'Multi-line text input component.',
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
let value = $state('');
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<Story name="Default">
|
|
31
|
+
{#snippet template()}
|
|
32
|
+
<div class="max-w-md">
|
|
33
|
+
<Textarea
|
|
34
|
+
label="Description"
|
|
35
|
+
placeholder="Enter your description..."
|
|
36
|
+
/>
|
|
37
|
+
</div>
|
|
38
|
+
{/snippet}
|
|
39
|
+
</Story>
|
|
40
|
+
|
|
41
|
+
<Story name="With Value">
|
|
42
|
+
{#snippet template()}
|
|
43
|
+
<div class="max-w-md">
|
|
44
|
+
<Textarea
|
|
45
|
+
label="Bio"
|
|
46
|
+
placeholder="Tell us about yourself..."
|
|
47
|
+
bind:value={value}
|
|
48
|
+
/>
|
|
49
|
+
<p class="text-sm text-gray-500 mt-2">{value.length} characters</p>
|
|
50
|
+
</div>
|
|
51
|
+
{/snippet}
|
|
52
|
+
</Story>
|
|
53
|
+
|
|
54
|
+
<Story name="With Max Length">
|
|
55
|
+
{#snippet template()}
|
|
56
|
+
<div class="max-w-md">
|
|
57
|
+
<Textarea
|
|
58
|
+
label="Short Bio"
|
|
59
|
+
placeholder="Keep it brief..."
|
|
60
|
+
maxlength={200}
|
|
61
|
+
helperText="Maximum 200 characters"
|
|
62
|
+
/>
|
|
63
|
+
</div>
|
|
64
|
+
{/snippet}
|
|
65
|
+
</Story>
|
|
66
|
+
|
|
67
|
+
<Story name="With Error">
|
|
68
|
+
{#snippet template()}
|
|
69
|
+
<div class="max-w-md">
|
|
70
|
+
<Textarea
|
|
71
|
+
label="Comments"
|
|
72
|
+
placeholder="Enter your comments..."
|
|
73
|
+
errorText="Please provide at least 10 characters"
|
|
74
|
+
/>
|
|
75
|
+
</div>
|
|
76
|
+
{/snippet}
|
|
77
|
+
</Story>
|
|
78
|
+
|
|
79
|
+
<Story name="Custom Rows">
|
|
80
|
+
{#snippet template()}
|
|
81
|
+
<div class="space-y-6 max-w-md">
|
|
82
|
+
<Textarea
|
|
83
|
+
label="Small (2 rows)"
|
|
84
|
+
placeholder="Two rows..."
|
|
85
|
+
rows={2}
|
|
86
|
+
/>
|
|
87
|
+
<Textarea
|
|
88
|
+
label="Medium (4 rows)"
|
|
89
|
+
placeholder="Four rows..."
|
|
90
|
+
rows={4}
|
|
91
|
+
/>
|
|
92
|
+
<Textarea
|
|
93
|
+
label="Large (8 rows)"
|
|
94
|
+
placeholder="Eight rows..."
|
|
95
|
+
rows={8}
|
|
96
|
+
/>
|
|
97
|
+
</div>
|
|
98
|
+
{/snippet}
|
|
99
|
+
</Story>
|
|
100
|
+
|
|
101
|
+
<Story name="Disabled">
|
|
102
|
+
{#snippet template()}
|
|
103
|
+
<div class="max-w-md">
|
|
104
|
+
<Textarea
|
|
105
|
+
label="Disabled Textarea"
|
|
106
|
+
placeholder="Cannot edit this..."
|
|
107
|
+
disabled
|
|
108
|
+
/>
|
|
109
|
+
</div>
|
|
110
|
+
{/snippet}
|
|
111
|
+
</Story>
|
|
112
|
+
|
|
113
|
+
<Story name="All States">
|
|
114
|
+
{#snippet template()}
|
|
115
|
+
<div class="grid grid-cols-2 gap-6 max-w-2xl">
|
|
116
|
+
<Textarea
|
|
117
|
+
label="Default"
|
|
118
|
+
placeholder="Enter text..."
|
|
119
|
+
/>
|
|
120
|
+
<Textarea
|
|
121
|
+
label="With Error"
|
|
122
|
+
placeholder="Enter text..."
|
|
123
|
+
errorText="This field is required"
|
|
124
|
+
/>
|
|
125
|
+
<Textarea
|
|
126
|
+
label="Disabled"
|
|
127
|
+
placeholder="Cannot edit..."
|
|
128
|
+
disabled
|
|
129
|
+
/>
|
|
130
|
+
<Textarea
|
|
131
|
+
label="With Helper"
|
|
132
|
+
placeholder="Enter text..."
|
|
133
|
+
helperText="Optional additional information"
|
|
134
|
+
/>
|
|
135
|
+
</div>
|
|
136
|
+
{/snippet}
|
|
137
|
+
</Story>
|
|
@@ -68,38 +68,38 @@
|
|
|
68
68
|
onfocus?.(event);
|
|
69
69
|
}
|
|
70
70
|
</script>
|
|
71
|
-
|
|
72
|
-
<div class="flex flex-col gap-2 w-full">
|
|
73
|
-
{#if label}
|
|
74
|
-
<label for={id || name} class={`${typography.label} leading-tight`}>
|
|
75
|
-
{label}{#if required}<span class="text-red-500 font-medium text-sm ml-0.5">*</span>{/if}
|
|
76
|
-
</label>
|
|
77
|
-
{/if}
|
|
78
|
-
|
|
79
|
-
<textarea
|
|
80
|
-
{id}
|
|
81
|
-
{name}
|
|
82
|
-
{placeholder}
|
|
83
|
-
{rows}
|
|
84
|
-
{disabled}
|
|
85
|
-
{readonly}
|
|
86
|
-
{maxlength}
|
|
87
|
-
{minlength}
|
|
88
|
-
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}"
|
|
89
|
-
bind:value
|
|
90
|
-
oninput={handleInput}
|
|
91
|
-
onchange={handleChange}
|
|
92
|
-
onblur={handleBlur}
|
|
93
|
-
onfocus={handleFocus}
|
|
94
|
-
{onkeydown}
|
|
95
|
-
{onkeyup}
|
|
96
|
-
{onkeypress}
|
|
97
|
-
aria-required={required}
|
|
98
|
-
aria-invalid={!!error}
|
|
99
|
-
{...restProps}
|
|
100
|
-
></textarea>
|
|
101
|
-
|
|
102
|
-
{#if error}
|
|
103
|
-
<p class={typography.error}>{error}</p>
|
|
104
|
-
{/if}
|
|
105
|
-
</div>
|
|
71
|
+
|
|
72
|
+
<div class="flex flex-col gap-2 w-full">
|
|
73
|
+
{#if label}
|
|
74
|
+
<label for={id || name} class={`${typography.label} leading-tight`}>
|
|
75
|
+
{label}{#if required}<span class="text-red-500 font-medium text-sm ml-0.5">*</span>{/if}
|
|
76
|
+
</label>
|
|
77
|
+
{/if}
|
|
78
|
+
|
|
79
|
+
<textarea
|
|
80
|
+
{id}
|
|
81
|
+
{name}
|
|
82
|
+
{placeholder}
|
|
83
|
+
{rows}
|
|
84
|
+
{disabled}
|
|
85
|
+
{readonly}
|
|
86
|
+
{maxlength}
|
|
87
|
+
{minlength}
|
|
88
|
+
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}"
|
|
89
|
+
bind:value
|
|
90
|
+
oninput={handleInput}
|
|
91
|
+
onchange={handleChange}
|
|
92
|
+
onblur={handleBlur}
|
|
93
|
+
onfocus={handleFocus}
|
|
94
|
+
{onkeydown}
|
|
95
|
+
{onkeyup}
|
|
96
|
+
{onkeypress}
|
|
97
|
+
aria-required={required}
|
|
98
|
+
aria-invalid={!!error}
|
|
99
|
+
{...restProps}
|
|
100
|
+
></textarea>
|
|
101
|
+
|
|
102
|
+
{#if error}
|
|
103
|
+
<p class={typography.error}>{error}</p>
|
|
104
|
+
{/if}
|
|
105
|
+
</div>
|