@getmicdrop/svelte-components 5.9.4 → 5.10.0
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/Calendar/MiniMonthCalendar.svelte +3 -3
- package/dist/calendar/MonthSwitcher/MonthSwitcher.svelte +3 -3
- package/dist/calendar/PublicCard/PublicCard.svelte +2 -2
- package/dist/calendar/ShowCard/ShowCard.svelte +1 -1
- package/dist/components/Layout/ContentSection.svelte +1 -1
- package/dist/patterns/forms/FormValidationSummary.svelte +1 -1
- package/dist/patterns/layout/Sidebar.svelte +4 -4
- package/dist/patterns/navigation/Header.svelte +1 -1
- package/dist/patterns/page/PageLayout.svelte +1 -1
- package/dist/primitives/Accordion/AccordionItem.spec.js +2 -2
- package/dist/primitives/Accordion/AccordionItem.svelte +1 -1
- package/dist/primitives/Badges/Badge.svelte +1 -1
- package/dist/primitives/Breadcrumb/Breadcrumb.svelte +11 -2
- package/dist/primitives/Breadcrumb/Breadcrumb.svelte.d.ts.map +1 -1
- package/dist/primitives/Button/Button.svelte +3 -3
- package/dist/primitives/Button/ButtonGroup.svelte +1 -1
- package/dist/primitives/Checkbox/Checkbox.spec.js +2 -2
- package/dist/primitives/Checkbox/Checkbox.svelte +1 -1
- package/dist/primitives/DarkModeToggle.spec.js +1 -1
- package/dist/primitives/Dropdown/Dropdown.svelte +10 -0
- package/dist/primitives/Dropdown/Dropdown.svelte.d.ts.map +1 -1
- package/dist/primitives/Input/Input.svelte +7 -17
- package/dist/primitives/Input/Select.spec.js +6 -0
- package/dist/primitives/Input/Select.svelte +4 -1
- package/dist/primitives/Input/Select.svelte.d.ts.map +1 -1
- package/dist/primitives/Input/Textarea.svelte +1 -1
- package/dist/primitives/Modal/Modal.svelte +1 -1
- package/dist/primitives/Radio/Radio.spec.js +2 -2
- package/dist/primitives/Radio/Radio.svelte +1 -1
- package/dist/primitives/Tabs/Tabs.svelte +1 -1
- package/dist/primitives/Toggle.spec.js +9 -6
- package/dist/primitives/Toggle.svelte +84 -22
- package/dist/primitives/Toggle.svelte.d.ts.map +1 -1
- package/dist/primitives/Tooltip/Tooltip.svelte +1 -1
- package/dist/recipes/CropImage/CropImage.svelte +2 -2
- package/dist/recipes/SuperLogin/SuperLogin.svelte +1 -1
- package/dist/recipes/inputs/MultiSelect.spec.js +6 -0
- package/dist/recipes/inputs/MultiSelect.svelte +5 -3
- package/dist/recipes/inputs/MultiSelect.svelte.d.ts.map +1 -1
- package/dist/recipes/inputs/OTPInput.svelte +1 -1
- package/dist/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.spec.js +6 -0
- package/dist/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.svelte +4 -2
- package/dist/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.svelte.d.ts.map +1 -1
- package/dist/recipes/inputs/Search.svelte +1 -1
- package/dist/recipes/inputs/SelectDropdown.spec.js +6 -0
- package/dist/recipes/inputs/SelectDropdown.svelte +3 -1
- package/dist/recipes/inputs/SelectDropdown.svelte.d.ts.map +1 -1
- package/dist/recipes/modals/InputModal.svelte +1 -1
- package/dist/recipes/modals/ModalTestWrapper.svelte +26 -26
- package/dist/stories/ButtonAuditDashboard.spec.js +1 -1
- package/dist/stories/ButtonAuditDashboard.svelte +25 -25
- package/dist/stories/ButtonGridView.svelte +1 -1
- package/dist/stories/RecipesGallery.svelte +3 -3
- package/dist/tokens/utilities.css +5 -5
- package/package.json +1 -1
|
@@ -644,7 +644,7 @@
|
|
|
644
644
|
|
|
645
645
|
<div class="flex items-center gap-2">
|
|
646
646
|
<button
|
|
647
|
-
class="p-2 flex items-center justify-center border-0 rounded-lg bg-transparent text-gray-500 dark:text-gray-400 cursor-pointer select-none transition-all duration-100 ease-out hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-900 dark:hover:text-white focus:outline-
|
|
647
|
+
class="p-2 flex items-center justify-center border-0 rounded-lg bg-transparent text-gray-500 dark:text-gray-400 cursor-pointer select-none transition-all duration-100 ease-out hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-900 dark:hover:text-white focus:outline-hidden focus-visible:ring-2 focus-visible:ring-blue-600 focus-visible:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed"
|
|
648
648
|
class:scale-90={prevPressed}
|
|
649
649
|
class:bg-gray-100={prevPressed}
|
|
650
650
|
class:dark:bg-gray-700={prevPressed}
|
|
@@ -663,7 +663,7 @@
|
|
|
663
663
|
|
|
664
664
|
{#if showTodayButton}
|
|
665
665
|
<button
|
|
666
|
-
class="text-sm font-medium px-3 py-1 border border-gray-300 dark:border-gray-600 rounded-lg bg-transparent text-gray-900 dark:text-white cursor-pointer select-none transition-transform duration-100 ease-out hover:bg-blue-700 hover:text-white hover:border-blue-700 focus:outline-
|
|
666
|
+
class="text-sm font-medium px-3 py-1 border border-gray-300 dark:border-gray-600 rounded-lg bg-transparent text-gray-900 dark:text-white cursor-pointer select-none transition-transform duration-100 ease-out hover:bg-blue-700 hover:text-white hover:border-blue-700 focus:outline-hidden focus-visible:ring-2 focus-visible:ring-blue-600 focus-visible:ring-offset-2 disabled:opacity-40 disabled:cursor-not-allowed"
|
|
667
667
|
class:scale-95={todayPressed}
|
|
668
668
|
class:bg-blue-700={todayPressed}
|
|
669
669
|
class:text-white={todayPressed}
|
|
@@ -682,7 +682,7 @@
|
|
|
682
682
|
{/if}
|
|
683
683
|
|
|
684
684
|
<button
|
|
685
|
-
class="p-2 flex items-center justify-center border-0 rounded-lg bg-transparent text-gray-500 dark:text-gray-400 cursor-pointer select-none transition-all duration-100 ease-out hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-900 dark:hover:text-white focus:outline-
|
|
685
|
+
class="p-2 flex items-center justify-center border-0 rounded-lg bg-transparent text-gray-500 dark:text-gray-400 cursor-pointer select-none transition-all duration-100 ease-out hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-900 dark:hover:text-white focus:outline-hidden focus-visible:ring-2 focus-visible:ring-blue-600 focus-visible:ring-offset-2"
|
|
686
686
|
class:scale-90={nextPressed}
|
|
687
687
|
class:bg-gray-100={nextPressed}
|
|
688
688
|
class:dark:bg-gray-700={nextPressed}
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
</h2>
|
|
70
70
|
<div class="flex items-center gap-2">
|
|
71
71
|
<button
|
|
72
|
-
class="p-3 -m-1.5 flex items-center justify-center border-0 rounded-full bg-transparent text-gray-500 dark:text-gray-400 cursor-pointer select-none transition-transform duration-100 ease-out hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-900 dark:hover:text-white focus:outline-
|
|
72
|
+
class="p-3 -m-1.5 flex items-center justify-center border-0 rounded-full bg-transparent text-gray-500 dark:text-gray-400 cursor-pointer select-none transition-transform duration-100 ease-out hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-900 dark:hover:text-white focus:outline-hidden focus-visible:ring-2 focus-visible:ring-blue-600 focus-visible:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed"
|
|
73
73
|
class:scale-90={prevPressed}
|
|
74
74
|
class:bg-gray-100={prevPressed}
|
|
75
75
|
class:dark:bg-gray-700={prevPressed}
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
<ChevronLeftOutline class="w-5 h-5" />
|
|
89
89
|
</button>
|
|
90
90
|
<button
|
|
91
|
-
class="{`${typography.label} px-3 py-1 border border-gray-300 dark:border-gray-600 rounded-lg bg-transparent cursor-pointer select-none transition-transform duration-100 ease-out hover:bg-blue-700 hover:text-white hover:border-blue-700 focus:outline-
|
|
91
|
+
class="{`${typography.label} px-3 py-1 border border-gray-300 dark:border-gray-600 rounded-lg bg-transparent cursor-pointer select-none transition-transform duration-100 ease-out hover:bg-blue-700 hover:text-white hover:border-blue-700 focus:outline-hidden focus-visible:ring-2 focus-visible:ring-blue-600 focus-visible:ring-offset-2 disabled:opacity-40 disabled:cursor-not-allowed disabled:text-gray-500 dark:disabled:text-gray-400`}"
|
|
92
92
|
class:scale-95={todayPressed}
|
|
93
93
|
class:bg-blue-700={todayPressed}
|
|
94
94
|
class:text-white={todayPressed}
|
|
@@ -105,7 +105,7 @@
|
|
|
105
105
|
Today
|
|
106
106
|
</button>
|
|
107
107
|
<button
|
|
108
|
-
class="p-3 -m-1.5 flex items-center justify-center border-0 rounded-full bg-transparent text-gray-500 dark:text-gray-400 cursor-pointer select-none transition-transform duration-100 ease-out hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-900 dark:hover:text-white focus:outline-
|
|
108
|
+
class="p-3 -m-1.5 flex items-center justify-center border-0 rounded-full bg-transparent text-gray-500 dark:text-gray-400 cursor-pointer select-none transition-transform duration-100 ease-out hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-900 dark:hover:text-white focus:outline-hidden focus-visible:ring-2 focus-visible:ring-blue-600 focus-visible:ring-offset-2"
|
|
109
109
|
class:scale-90={nextPressed}
|
|
110
110
|
class:bg-gray-100={nextPressed}
|
|
111
111
|
class:dark:bg-gray-700={nextPressed}
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
{#each events as event}
|
|
74
74
|
<!-- svelte-ignore a11y_no_noninteractive_element_to_interactive_role -->
|
|
75
75
|
<article
|
|
76
|
-
class="bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 cursor-pointer overflow-hidden transition-all duration-200 hover:shadow-lg hover:border-gray-300 dark:hover:border-gray-600 focus:outline-
|
|
76
|
+
class="bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 cursor-pointer overflow-hidden transition-all duration-200 hover:shadow-lg hover:border-gray-300 dark:hover:border-gray-600 focus:outline-hidden focus:ring-4 focus:ring-blue-300 dark:focus:ring-blue-800 relative {view === 'col'
|
|
77
77
|
? 'flex flex-col'
|
|
78
78
|
: 'grid grid-cols-[100px_1fr] sm:grid-cols-[160px_1fr] gap-3 sm:gap-4 p-3 sm:p-4'}"
|
|
79
79
|
onclick={() => handleEventClick(event)}
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
<div
|
|
86
86
|
class="bg-gray-100 dark:bg-gray-700 flex items-center justify-center overflow-hidden {view === 'col'
|
|
87
87
|
? 'w-full aspect-[4/3] rounded-t-lg'
|
|
88
|
-
: 'w-24 h-24 sm:w-40 sm:h-32 rounded-lg
|
|
88
|
+
: 'w-24 h-24 sm:w-40 sm:h-32 rounded-lg shrink-0'}"
|
|
89
89
|
>
|
|
90
90
|
<img
|
|
91
91
|
src={event.image || placeholder}
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
{event.name || ''}
|
|
84
84
|
</h2>
|
|
85
85
|
<button
|
|
86
|
-
class="
|
|
86
|
+
class="shrink-0 p-2 rounded-lg transition-colors hover:bg-gray-100 dark:hover:bg-gray-700 relative"
|
|
87
87
|
aria-label="Share event"
|
|
88
88
|
onclick={handleShare}
|
|
89
89
|
>
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
<Button
|
|
61
61
|
variant="link"
|
|
62
62
|
size="sm"
|
|
63
|
-
class="
|
|
63
|
+
class="text-red-600! dark:text-red-500! hover:text-red-900! dark:hover:text-red-400!"
|
|
64
64
|
onclick={() => scrollToField(field.elementId)}
|
|
65
65
|
>
|
|
66
66
|
{field.label}
|
|
@@ -22,17 +22,17 @@
|
|
|
22
22
|
|
|
23
23
|
<div class="flex flex-col lg:flex-row gap-6 {className}">
|
|
24
24
|
{#if sidebarPosition === 'left'}
|
|
25
|
-
<aside class="w-full {widthClasses[sidebarWidth]}
|
|
25
|
+
<aside class="w-full {widthClasses[sidebarWidth]} shrink-0">
|
|
26
26
|
{@render sidebar?.()}
|
|
27
27
|
</aside>
|
|
28
|
-
<main class="w-full {mainWidthClasses[sidebarWidth]}
|
|
28
|
+
<main class="w-full {mainWidthClasses[sidebarWidth]} grow min-w-0">
|
|
29
29
|
{@render children?.()}
|
|
30
30
|
</main>
|
|
31
31
|
{:else}
|
|
32
|
-
<main class="w-full {mainWidthClasses[sidebarWidth]}
|
|
32
|
+
<main class="w-full {mainWidthClasses[sidebarWidth]} grow min-w-0">
|
|
33
33
|
{@render children?.()}
|
|
34
34
|
</main>
|
|
35
|
-
<aside class="w-full {widthClasses[sidebarWidth]}
|
|
35
|
+
<aside class="w-full {widthClasses[sidebarWidth]} shrink-0">
|
|
36
36
|
{@render sidebar?.()}
|
|
37
37
|
</aside>
|
|
38
38
|
{/if}
|
|
@@ -217,7 +217,7 @@
|
|
|
217
217
|
transition:fly={{ y: 300, duration: 300, easing: cubicOut }}
|
|
218
218
|
>
|
|
219
219
|
<div class="flex justify-center pt-3 pb-2">
|
|
220
|
-
<div class="w-10 h-1 bg-gray-300 dark:bg-gray-600 rounded-
|
|
220
|
+
<div class="w-10 h-1 bg-gray-300 dark:bg-gray-600 rounded-xs"></div>
|
|
221
221
|
</div>
|
|
222
222
|
|
|
223
223
|
<div class="px-6 py-4 border-b border-gray-200 dark:border-gray-700">
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
<div class="flex flex-col sm:flex-row sm:items-start sm:justify-between gap-4">
|
|
22
22
|
<Breadcrumb data={breadcrumb} {title} {subtitle} />
|
|
23
23
|
{#if actions}
|
|
24
|
-
<div class="flex items-center gap-3
|
|
24
|
+
<div class="flex items-center gap-3 shrink-0">
|
|
25
25
|
{@render actions()}
|
|
26
26
|
</div>
|
|
27
27
|
{/if}
|
|
@@ -233,10 +233,10 @@ describe('AccordionItem - Accessibility', () => {
|
|
|
233
233
|
});
|
|
234
234
|
});
|
|
235
235
|
|
|
236
|
-
test('button has focus:outline-
|
|
236
|
+
test('button has focus:outline-hidden for custom focus styling', () => {
|
|
237
237
|
const { container } = render(AccordionItemWrapper);
|
|
238
238
|
const button = container.querySelector('button');
|
|
239
|
-
expect(button).toHaveClass('focus:outline-
|
|
239
|
+
expect(button).toHaveClass('focus:outline-hidden');
|
|
240
240
|
});
|
|
241
241
|
|
|
242
242
|
test('button is keyboard accessible', async () => {
|
|
@@ -92,7 +92,7 @@ let variantClasses = $derived(
|
|
|
92
92
|
onclick={(e) => onclick?.(e)}
|
|
93
93
|
>
|
|
94
94
|
{#if showDot}
|
|
95
|
-
<span class="w-1.5 h-1.5 rounded-full bg-current
|
|
95
|
+
<span class="w-1.5 h-1.5 rounded-full bg-current shrink-0"></span>
|
|
96
96
|
{/if}
|
|
97
97
|
{@render leftIcon?.()}
|
|
98
98
|
{@render children?.()}
|
|
@@ -45,11 +45,14 @@
|
|
|
45
45
|
{#if index > 0}
|
|
46
46
|
<ChevronRightOutline class="rtl:rotate-180 w-3 h-3 text-gray-400 mx-1" />
|
|
47
47
|
{/if}
|
|
48
|
-
{#if index === data.length
|
|
49
|
-
|
|
48
|
+
{#if index === 0 && showHomeIcon && data.length === 1}
|
|
49
|
+
<!-- Single item with home icon - show as non-clickable label -->
|
|
50
|
+
<span class="{typography.smMuted} inline-flex items-center font-medium">
|
|
51
|
+
<HomeSolid class="w-3 h-3 me-2.5" />
|
|
50
52
|
{crumb.name}
|
|
51
53
|
</span>
|
|
52
54
|
{:else if index === 0 && showHomeIcon}
|
|
55
|
+
<!-- First item with home icon - clickable link -->
|
|
53
56
|
<a
|
|
54
57
|
href={crumb.href}
|
|
55
58
|
onclick={() => handleClick(crumb)}
|
|
@@ -58,7 +61,13 @@
|
|
|
58
61
|
<HomeSolid class="w-3 h-3 me-2.5" />
|
|
59
62
|
{crumb.name}
|
|
60
63
|
</a>
|
|
64
|
+
{:else if index === data.length - 1}
|
|
65
|
+
<!-- Last item - non-clickable -->
|
|
66
|
+
<span class={`ms-1 ${typography.smMuted} font-medium md:ms-2 max-w-48 truncate`} title={crumb.name}>
|
|
67
|
+
{crumb.name}
|
|
68
|
+
</span>
|
|
61
69
|
{:else}
|
|
70
|
+
<!-- Middle items - clickable links -->
|
|
62
71
|
<a
|
|
63
72
|
href={crumb.href}
|
|
64
73
|
onclick={() => handleClick(crumb)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Breadcrumb.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/primitives/Breadcrumb/Breadcrumb.svelte.ts"],"names":[],"mappings":"AAOE,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,KAAK;IACb,6BAA6B;IAC7B,IAAI,CAAC,EAAE,cAAc,EAAE,CAAC;IACxB,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qCAAqC;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;CAC3C;
|
|
1
|
+
{"version":3,"file":"Breadcrumb.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/primitives/Breadcrumb/Breadcrumb.svelte.ts"],"names":[],"mappings":"AAOE,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,KAAK;IACb,6BAA6B;IAC7B,IAAI,CAAC,EAAE,cAAc,EAAE,CAAC;IACxB,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qCAAqC;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;CAC3C;AA2EH,QAAA,MAAM,UAAU,2CAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
|
|
@@ -118,8 +118,8 @@
|
|
|
118
118
|
// Chart row - for leaderboard/chart list items with progress bars
|
|
119
119
|
"chart-row": "w-full text-left text-gray-900 bg-transparent border-transparent hover:bg-gray-50 dark:text-white dark:hover:bg-gray-800",
|
|
120
120
|
// Landing page hero buttons - prominent CTAs with shadow
|
|
121
|
-
landing: "text-white bg-blue-600 border border-blue-600 hover:bg-blue-700 dark:bg-blue-600 dark:border-blue-600 dark:hover:bg-blue-700 no-underline hover:no-underline shadow
|
|
122
|
-
"landing-secondary": "text-gray-700 bg-white border border-gray-200 hover:border-gray-400 hover:text-gray-900 dark:text-gray-300 dark:bg-gray-800 dark:border-gray-600 dark:hover:border-gray-500 dark:hover:text-gray-100 no-underline hover:no-underline shadow
|
|
121
|
+
landing: "text-white bg-blue-600 border border-blue-600 hover:bg-blue-700 dark:bg-blue-600 dark:border-blue-600 dark:hover:bg-blue-700 no-underline hover:no-underline shadow hover:shadow-md",
|
|
122
|
+
"landing-secondary": "text-gray-700 bg-white border border-gray-200 hover:border-gray-400 hover:text-gray-900 dark:text-gray-300 dark:bg-gray-800 dark:border-gray-600 dark:hover:border-gray-500 dark:hover:text-gray-100 no-underline hover:no-underline shadow hover:shadow-md",
|
|
123
123
|
};
|
|
124
124
|
|
|
125
125
|
// Active state classes for ghost, toggle, menu-item, and nav
|
|
@@ -188,7 +188,7 @@ let sizeClass = $derived((() => {
|
|
|
188
188
|
: "inline-flex items-center justify-center",
|
|
189
189
|
roundedClass,
|
|
190
190
|
"font-medium leading-none",
|
|
191
|
-
"focus:outline-
|
|
191
|
+
"focus:outline-hidden",
|
|
192
192
|
// Apple-style micro-interactions (only when not disabled)
|
|
193
193
|
"transition-all duration-150 ease-out",
|
|
194
194
|
effectiveDisabled ? "" : "active:scale-[0.97] active:opacity-90",
|
|
@@ -140,10 +140,10 @@ describe('Checkbox Input Styling', () => {
|
|
|
140
140
|
expect(input).toHaveClass('dark:border-gray-600');
|
|
141
141
|
});
|
|
142
142
|
|
|
143
|
-
test('has focus:outline-
|
|
143
|
+
test('has focus:outline-hidden', () => {
|
|
144
144
|
const { container } = render(Checkbox);
|
|
145
145
|
const input = container.querySelector('input');
|
|
146
|
-
expect(input).toHaveClass('focus:outline-
|
|
146
|
+
expect(input).toHaveClass('focus:outline-hidden');
|
|
147
147
|
});
|
|
148
148
|
|
|
149
149
|
test('has cursor-pointer when not disabled', () => {
|
|
@@ -112,7 +112,7 @@ describe("DarkModeToggle Component Tests", () => {
|
|
|
112
112
|
test("Button has focus outline removed", () => {
|
|
113
113
|
setupTest();
|
|
114
114
|
const button = screen.getByRole("button");
|
|
115
|
-
expect(button).toHaveClass("focus:outline-
|
|
115
|
+
expect(button).toHaveClass("focus:outline-hidden");
|
|
116
116
|
});
|
|
117
117
|
|
|
118
118
|
test("Button click handler is called on interaction", async () => {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { onMount, onDestroy, tick, setContext } from "svelte";
|
|
3
3
|
import type { Snippet } from "svelte";
|
|
4
|
+
import { bloom } from "../../utils/transitions.js";
|
|
4
5
|
|
|
5
6
|
interface Props {
|
|
6
7
|
open?: boolean;
|
|
@@ -143,6 +144,14 @@
|
|
|
143
144
|
left: "right-full top-0 mr-1",
|
|
144
145
|
right: "left-full top-0 ml-1"
|
|
145
146
|
};
|
|
147
|
+
|
|
148
|
+
// Map placement to transform origin for bloom animation
|
|
149
|
+
const placementOrigins: Record<string, string> = {
|
|
150
|
+
bottom: "top left",
|
|
151
|
+
top: "bottom left",
|
|
152
|
+
left: "top right",
|
|
153
|
+
right: "top left"
|
|
154
|
+
};
|
|
146
155
|
</script>
|
|
147
156
|
|
|
148
157
|
{#if open}
|
|
@@ -151,6 +160,7 @@
|
|
|
151
160
|
class="absolute z-10 bg-white divide-y divide-gray-100 rounded-lg shadow-lg w-44 dark:bg-gray-700 dark:divide-gray-600 {className}"
|
|
152
161
|
role="menu"
|
|
153
162
|
aria-label={ariaLabel}
|
|
163
|
+
transition:bloom={{ origin: placementOrigins[placement] || "top left" }}
|
|
154
164
|
{...restProps}
|
|
155
165
|
>
|
|
156
166
|
<ul bind:this={dropdownRef} class="py-2 text-sm text-gray-700 dark:text-gray-200">
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Dropdown.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/primitives/Dropdown/Dropdown.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"Dropdown.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/primitives/Dropdown/Dropdown.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAIpC,UAAU,KAAK;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AA6JH,QAAA,MAAM,QAAQ,+CAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
|
|
@@ -293,7 +293,7 @@
|
|
|
293
293
|
onfocus={handleFocus}
|
|
294
294
|
{maxlength}
|
|
295
295
|
{minlength}
|
|
296
|
-
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-
|
|
296
|
+
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-hidden focus:ring-4 focus:ring-blue-300 dark:focus:ring-blue-300 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]' : ''}"
|
|
297
297
|
required={false}
|
|
298
298
|
{disabled}
|
|
299
299
|
{readonly}
|
|
@@ -301,7 +301,7 @@
|
|
|
301
301
|
aria-required={required}
|
|
302
302
|
></textarea>
|
|
303
303
|
{:else if type === "password" && showPasswordToggle}
|
|
304
|
-
<div class="flex items-center w-full
|
|
304
|
+
<div class="relative flex items-center w-full">
|
|
305
305
|
<!-- svelte-ignore a11y_autofocus -->
|
|
306
306
|
<input
|
|
307
307
|
bind:this={inputElement}
|
|
@@ -316,7 +316,7 @@
|
|
|
316
316
|
onfocus={handleFocus}
|
|
317
317
|
{maxlength}
|
|
318
318
|
{minlength}
|
|
319
|
-
class="
|
|
319
|
+
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-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'} pr-10 {getContentFloatClass()} {shouldAnimate ? 'focus:scale-[1.01]' : ''} {disabled ? 'opacity-50 cursor-not-allowed' : ''}"
|
|
320
320
|
required={false}
|
|
321
321
|
{disabled}
|
|
322
322
|
{readonly}
|
|
@@ -328,7 +328,7 @@
|
|
|
328
328
|
<button
|
|
329
329
|
type="button"
|
|
330
330
|
onclick={togglePasswordVisibility}
|
|
331
|
-
class="flex items-center justify-center
|
|
331
|
+
class="absolute right-3 inset-y-0 flex items-center justify-center text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 focus:outline-hidden"
|
|
332
332
|
tabindex="-1"
|
|
333
333
|
aria-label={isPasswordVisible ? "Hide password" : "Show password"}
|
|
334
334
|
>
|
|
@@ -361,7 +361,7 @@
|
|
|
361
361
|
onkeydown={handleSearchKeyDown}
|
|
362
362
|
{maxlength}
|
|
363
363
|
{minlength}
|
|
364
|
-
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-
|
|
364
|
+
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-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'} {icon || (showClearButton && inputValue) ? 'pr-10' : ''} {leftIcon ? 'pl-10' : ''} {getContentFloatClass()} {shouldAnimate ? 'focus:scale-[1.01]' : ''} {disabled ? 'opacity-50 cursor-not-allowed' : ''}"
|
|
365
365
|
required={false}
|
|
366
366
|
{disabled}
|
|
367
367
|
{readonly}
|
|
@@ -374,7 +374,7 @@
|
|
|
374
374
|
<button
|
|
375
375
|
type="button"
|
|
376
376
|
onclick={clearInput}
|
|
377
|
-
class="absolute right-
|
|
377
|
+
class="absolute right-3 inset-y-0 flex items-center justify-center text-gray-400 hover:text-gray-600 dark:hover:text-gray-200"
|
|
378
378
|
aria-label="Clear input"
|
|
379
379
|
tabindex="-1"
|
|
380
380
|
>
|
|
@@ -419,15 +419,5 @@
|
|
|
419
419
|
</div>
|
|
420
420
|
|
|
421
421
|
<style>
|
|
422
|
-
/*
|
|
423
|
-
* Override Tailwind v4 preflight which sets input { border: 1px solid currentColor }
|
|
424
|
-
* in @layer base. The base layer's element selector has higher specificity than
|
|
425
|
-
* utility class selectors like border-0 or border-none, so we need scoped overrides.
|
|
426
|
-
*
|
|
427
|
-
* This affects the password input which is wrapped in a container div that provides
|
|
428
|
-
* the visible border - the inner input should have no border.
|
|
429
|
-
*/
|
|
430
|
-
:global(.password-input-inner) {
|
|
431
|
-
border: none !important;
|
|
432
|
-
}
|
|
422
|
+
/* No custom styles needed - password input now uses same structure as email input */
|
|
433
423
|
</style>
|
|
@@ -3,6 +3,12 @@ import userEvent from "@testing-library/user-event";
|
|
|
3
3
|
import { expect, describe, test, vi } from "vitest";
|
|
4
4
|
import Select from "./Select.svelte";
|
|
5
5
|
|
|
6
|
+
// Mock transitions to be instant for testing
|
|
7
|
+
vi.mock('../../utils/transitions.js', () => ({
|
|
8
|
+
bloom: () => ({ duration: 0, delay: 0, css: () => '' }),
|
|
9
|
+
safeSlide: () => ({ duration: 0, delay: 0, css: () => '' }),
|
|
10
|
+
}));
|
|
11
|
+
|
|
6
12
|
const sampleItems = [
|
|
7
13
|
{ name: "Option 1", value: "opt1" },
|
|
8
14
|
{ name: "Option 2", value: "opt2" },
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { portal as portalAction } from "../../utils/portal.js";
|
|
5
5
|
import { typography } from "../../tokens/typography";
|
|
6
6
|
import { formControlSizes } from "../../tokens/sizing";
|
|
7
|
+
import { bloom } from "../../utils/transitions.js";
|
|
7
8
|
|
|
8
9
|
interface SelectItem {
|
|
9
10
|
value: string;
|
|
@@ -180,7 +181,7 @@
|
|
|
180
181
|
bind:this={triggerElement}
|
|
181
182
|
{id}
|
|
182
183
|
{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-
|
|
184
|
+
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-hidden 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
185
|
{disabled}
|
|
185
186
|
aria-haspopup="listbox"
|
|
186
187
|
aria-expanded={isOpen}
|
|
@@ -198,6 +199,7 @@
|
|
|
198
199
|
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
200
|
role="listbox"
|
|
200
201
|
tabindex="-1"
|
|
202
|
+
transition:bloom={{ origin: "top left" }}
|
|
201
203
|
>
|
|
202
204
|
{#each items as item, index}
|
|
203
205
|
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
@@ -231,6 +233,7 @@
|
|
|
231
233
|
style="top: {dropdownPosition.top}px; left: {dropdownPosition.left}px; width: {dropdownPosition.width}px;"
|
|
232
234
|
role="listbox"
|
|
233
235
|
tabindex="-1"
|
|
236
|
+
transition:bloom={{ origin: "top left" }}
|
|
234
237
|
>
|
|
235
238
|
{#each items as item, index}
|
|
236
239
|
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Select.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/primitives/Input/Select.svelte.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Select.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/primitives/Input/Select.svelte.ts"],"names":[],"mappings":"AAWE,UAAU,UAAU;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,KAAK;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,UAAU,CAAA;KAAE,KAAK,IAAI,CAAC;IACjE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAsMH,QAAA,MAAM,MAAM,gDAAwC,CAAC;AACrD,KAAK,MAAM,GAAG,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC;AACxC,eAAe,MAAM,CAAC"}
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
{readonly}
|
|
86
86
|
{maxlength}
|
|
87
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-
|
|
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-hidden 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
89
|
bind:value
|
|
90
90
|
oninput={handleInput}
|
|
91
91
|
onchange={handleChange}
|
|
@@ -127,7 +127,7 @@
|
|
|
127
127
|
>
|
|
128
128
|
<!-- Handle bar -->
|
|
129
129
|
<div class="flex justify-center pt-3 pb-1 shrink-0">
|
|
130
|
-
<div class="w-10 h-1 bg-gray-300 dark:bg-gray-600 rounded-
|
|
130
|
+
<div class="w-10 h-1 bg-gray-300 dark:bg-gray-600 rounded-xs"></div>
|
|
131
131
|
</div>
|
|
132
132
|
|
|
133
133
|
<div class="p-6 pb-[calc(5rem+env(safe-area-inset-bottom,0px))] overflow-y-auto flex-1">
|
|
@@ -134,10 +134,10 @@ describe('Radio Input Styling', () => {
|
|
|
134
134
|
expect(input).toHaveClass('dark:border-gray-600');
|
|
135
135
|
});
|
|
136
136
|
|
|
137
|
-
test('has focus:outline-
|
|
137
|
+
test('has focus:outline-hidden', () => {
|
|
138
138
|
const { container } = render(Radio);
|
|
139
139
|
const input = container.querySelector('input');
|
|
140
|
-
expect(input).toHaveClass('focus:outline-
|
|
140
|
+
expect(input).toHaveClass('focus:outline-hidden');
|
|
141
141
|
});
|
|
142
142
|
});
|
|
143
143
|
|
|
@@ -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:outline-
|
|
60
|
+
class="w-4 h-4 bg-gray-100 border-gray-300 focus:outline-hidden 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">
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
|
|
92
92
|
// Tab button classes by style
|
|
93
93
|
function getTabClasses(isActive: boolean) {
|
|
94
|
-
const base = "inline-flex items-center justify-center whitespace-nowrap transition-colors focus:outline-
|
|
94
|
+
const base = "inline-flex items-center justify-center whitespace-nowrap transition-colors focus:outline-hidden";
|
|
95
95
|
|
|
96
96
|
switch (tabStyle) {
|
|
97
97
|
case 'underline':
|
|
@@ -97,22 +97,25 @@ describe('Toggle Component', () => {
|
|
|
97
97
|
it('has default md size track dimensions', () => {
|
|
98
98
|
const { container } = render(Toggle, { size: 'md' });
|
|
99
99
|
const switchEl = container.querySelector('[role="switch"]');
|
|
100
|
-
|
|
101
|
-
expect(switchEl).toHaveClass('
|
|
100
|
+
// Uses CSS classes instead of Tailwind for Tailwind v4 compatibility
|
|
101
|
+
expect(switchEl).toHaveClass('toggle-track');
|
|
102
|
+
expect(switchEl).toHaveClass('toggle-md');
|
|
102
103
|
});
|
|
103
104
|
|
|
104
105
|
it('has sm size track dimensions', () => {
|
|
105
106
|
const { container } = render(Toggle, { size: 'sm' });
|
|
106
107
|
const switchEl = container.querySelector('[role="switch"]');
|
|
107
|
-
|
|
108
|
-
expect(switchEl).toHaveClass('
|
|
108
|
+
// Uses CSS classes instead of Tailwind for Tailwind v4 compatibility
|
|
109
|
+
expect(switchEl).toHaveClass('toggle-track');
|
|
110
|
+
expect(switchEl).toHaveClass('toggle-sm');
|
|
109
111
|
});
|
|
110
112
|
|
|
111
113
|
it('has lg size track dimensions', () => {
|
|
112
114
|
const { container } = render(Toggle, { size: 'lg' });
|
|
113
115
|
const switchEl = container.querySelector('[role="switch"]');
|
|
114
|
-
|
|
115
|
-
expect(switchEl).toHaveClass('
|
|
116
|
+
// Uses CSS classes instead of Tailwind for Tailwind v4 compatibility
|
|
117
|
+
expect(switchEl).toHaveClass('toggle-track');
|
|
118
|
+
expect(switchEl).toHaveClass('toggle-lg');
|
|
116
119
|
});
|
|
117
120
|
|
|
118
121
|
it('has dark mode classes', () => {
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Toggle Component - Flowbite Native
|
|
4
4
|
* Migrated to Svelte 5 runes
|
|
5
|
+
*
|
|
6
|
+
* Note: Uses CSS style block for pseudo-element styling instead of Tailwind
|
|
7
|
+
* after: classes, because Tailwind v4 doesn't generate after: classes from
|
|
8
|
+
* node_modules when this component is consumed by other apps.
|
|
5
9
|
*/
|
|
6
10
|
|
|
7
11
|
/** @type {{
|
|
@@ -26,27 +30,6 @@
|
|
|
26
30
|
checked = event.target.checked;
|
|
27
31
|
onchange?.({ checked });
|
|
28
32
|
}
|
|
29
|
-
|
|
30
|
-
// Flowbite toggle sizes - thumb uses after: pseudo-element
|
|
31
|
-
const sizes = {
|
|
32
|
-
sm: {
|
|
33
|
-
track: 'w-9 h-5',
|
|
34
|
-
thumb: 'after:h-4 after:w-4 after:top-0.5 after:start-0.5',
|
|
35
|
-
translate: 'peer-checked:after:translate-x-full'
|
|
36
|
-
},
|
|
37
|
-
md: {
|
|
38
|
-
track: 'w-11 h-6',
|
|
39
|
-
thumb: 'after:h-5 after:w-5 after:top-0.5 after:start-0.5',
|
|
40
|
-
translate: 'peer-checked:after:translate-x-full'
|
|
41
|
-
},
|
|
42
|
-
lg: {
|
|
43
|
-
track: 'w-14 h-7',
|
|
44
|
-
thumb: 'after:h-6 after:w-6 after:top-0.5 after:start-0.5',
|
|
45
|
-
translate: 'peer-checked:after:translate-x-full'
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
let sizeConfig = $derived(sizes[size] || sizes.md);
|
|
50
33
|
</script>
|
|
51
34
|
|
|
52
35
|
<label class="inline-flex items-center {disabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer'} {className}" {...restProps}>
|
|
@@ -58,9 +41,10 @@
|
|
|
58
41
|
class="sr-only peer"
|
|
59
42
|
/>
|
|
60
43
|
<div
|
|
61
|
-
class="
|
|
44
|
+
class="toggle-track toggle-{size} relative bg-gray-200 peer-focus:outline-hidden peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:bg-blue-600"
|
|
62
45
|
role="switch"
|
|
63
46
|
aria-checked={checked}
|
|
47
|
+
style="--toggle-translate: {sizeConfig.translatePx}"
|
|
64
48
|
></div>
|
|
65
49
|
{#if children}
|
|
66
50
|
<span class="ms-3 text-sm font-medium text-gray-900 dark:text-gray-300">
|
|
@@ -68,3 +52,81 @@
|
|
|
68
52
|
</span>
|
|
69
53
|
{/if}
|
|
70
54
|
</label>
|
|
55
|
+
|
|
56
|
+
<style>
|
|
57
|
+
/*
|
|
58
|
+
* Toggle track sizes (replaces Tailwind w-* h-* classes)
|
|
59
|
+
* Using CSS instead of Tailwind because these need to work in consuming apps
|
|
60
|
+
*/
|
|
61
|
+
.toggle-sm {
|
|
62
|
+
width: 2.25rem; /* w-9 = 36px */
|
|
63
|
+
height: 1.25rem; /* h-5 = 20px */
|
|
64
|
+
}
|
|
65
|
+
.toggle-md {
|
|
66
|
+
width: 2.75rem; /* w-11 = 44px */
|
|
67
|
+
height: 1.5rem; /* h-6 = 24px */
|
|
68
|
+
}
|
|
69
|
+
.toggle-lg {
|
|
70
|
+
width: 3.5rem; /* w-14 = 56px */
|
|
71
|
+
height: 1.75rem; /* h-7 = 28px */
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/*
|
|
75
|
+
* Toggle thumb (the white circle) - uses ::after pseudo-element
|
|
76
|
+
* Tailwind v4 doesn't generate after: classes from node_modules,
|
|
77
|
+
* so we use explicit CSS here.
|
|
78
|
+
*/
|
|
79
|
+
.toggle-track::after {
|
|
80
|
+
content: '';
|
|
81
|
+
position: absolute;
|
|
82
|
+
background-color: white;
|
|
83
|
+
border: 1px solid #d1d5db; /* gray-300 */
|
|
84
|
+
border-radius: 9999px;
|
|
85
|
+
transition: all 150ms;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* Thumb sizes for each toggle size */
|
|
89
|
+
.toggle-sm::after {
|
|
90
|
+
width: 1rem; /* 16px */
|
|
91
|
+
height: 1rem;
|
|
92
|
+
top: 0.125rem; /* 2px */
|
|
93
|
+
inset-inline-start: 0.125rem;
|
|
94
|
+
}
|
|
95
|
+
.toggle-md::after {
|
|
96
|
+
width: 1.25rem; /* 20px */
|
|
97
|
+
height: 1.25rem;
|
|
98
|
+
top: 0.125rem;
|
|
99
|
+
inset-inline-start: 0.125rem;
|
|
100
|
+
}
|
|
101
|
+
.toggle-lg::after {
|
|
102
|
+
width: 1.5rem; /* 24px */
|
|
103
|
+
height: 1.5rem;
|
|
104
|
+
top: 0.125rem;
|
|
105
|
+
inset-inline-start: 0.125rem;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* Checked state - move thumb to the right */
|
|
109
|
+
:global(input.peer:checked) + .toggle-sm::after {
|
|
110
|
+
transform: translateX(1rem); /* 16px */
|
|
111
|
+
border-color: white;
|
|
112
|
+
}
|
|
113
|
+
:global(input.peer:checked) + .toggle-md::after {
|
|
114
|
+
transform: translateX(1.25rem); /* 20px */
|
|
115
|
+
border-color: white;
|
|
116
|
+
}
|
|
117
|
+
:global(input.peer:checked) + .toggle-lg::after {
|
|
118
|
+
transform: translateX(1.5rem); /* 24px */
|
|
119
|
+
border-color: white;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/* RTL support - translate in opposite direction */
|
|
123
|
+
:global([dir="rtl"]) :global(input.peer:checked) + .toggle-sm::after {
|
|
124
|
+
transform: translateX(-1rem);
|
|
125
|
+
}
|
|
126
|
+
:global([dir="rtl"]) :global(input.peer:checked) + .toggle-md::after {
|
|
127
|
+
transform: translateX(-1.25rem);
|
|
128
|
+
}
|
|
129
|
+
:global([dir="rtl"]) :global(input.peer:checked) + .toggle-lg::after {
|
|
130
|
+
transform: translateX(-1.5rem);
|
|
131
|
+
}
|
|
132
|
+
</style>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toggle.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/primitives/Toggle.svelte.js"],"names":[],"mappings":";;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"Toggle.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/primitives/Toggle.svelte.js"],"names":[],"mappings":";;;;;;;;;;;;;;AA0DA;cAPc,OAAO;eACN,OAAO;WACX,IAAI,GAAG,IAAI,GAAG,IAAI;YACjB,MAAM;eACH,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI;eACtC,OAAO,QAAQ,EAAE,OAAO;kBAEc"}
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
|
|
73
73
|
{#if visible && content}
|
|
74
74
|
<div
|
|
75
|
-
class="absolute z-50 px-3 py-2 text-sm text-white bg-gray-900 rounded-lg shadow
|
|
75
|
+
class="absolute z-50 px-3 py-2 text-sm text-white bg-gray-900 rounded-lg shadow whitespace-nowrap pointer-events-none dark:bg-gray-700 {placementClasses[placement]} {className}"
|
|
76
76
|
transition:fly={{ y: placement === 'top' ? 5 : placement === 'bottom' ? -5 : 0, x: placement === 'left' ? 5 : placement === 'right' ? -5 : 0, duration: 150 }}
|
|
77
77
|
>
|
|
78
78
|
{content}
|
|
@@ -159,7 +159,7 @@
|
|
|
159
159
|
<Button
|
|
160
160
|
variant="outline"
|
|
161
161
|
size="sm"
|
|
162
|
-
class="
|
|
162
|
+
class="rounded-full! w-9! h-9! p-0! shrink-0"
|
|
163
163
|
onclick={() => (zoom = Math.max(1, zoom - 0.2))}
|
|
164
164
|
aria-label="Zoom out"
|
|
165
165
|
>
|
|
@@ -179,7 +179,7 @@
|
|
|
179
179
|
<Button
|
|
180
180
|
variant="outline"
|
|
181
181
|
size="sm"
|
|
182
|
-
class="
|
|
182
|
+
class="rounded-full! w-9! h-9! p-0! shrink-0"
|
|
183
183
|
onclick={() => (zoom = Math.min(3, zoom + 0.2))}
|
|
184
184
|
aria-label="Zoom in"
|
|
185
185
|
>
|
|
@@ -802,7 +802,7 @@
|
|
|
802
802
|
onclick={() => handleAccountSelectInternal(account)}
|
|
803
803
|
>
|
|
804
804
|
<div
|
|
805
|
-
class="h-10 w-10 rounded-md bg-gray-200
|
|
805
|
+
class="h-10 w-10 rounded-md bg-gray-200 shrink-0 overflow-hidden mr-4"
|
|
806
806
|
>
|
|
807
807
|
{#if account.performerProfile?.profileImage}
|
|
808
808
|
<img
|
|
@@ -3,6 +3,12 @@ import userEvent from "@testing-library/user-event";
|
|
|
3
3
|
import { expect, describe, test, vi } from "vitest";
|
|
4
4
|
import MultiSelect from "./MultiSelect.svelte";
|
|
5
5
|
|
|
6
|
+
// Mock transitions to be instant for testing
|
|
7
|
+
vi.mock('../../utils/transitions.js', () => ({
|
|
8
|
+
bloom: () => ({ duration: 0, delay: 0, css: () => '' }),
|
|
9
|
+
safeSlide: () => ({ duration: 0, delay: 0, css: () => '' }),
|
|
10
|
+
}));
|
|
11
|
+
|
|
6
12
|
const sampleItems = [
|
|
7
13
|
{ name: "Option 1", value: "opt1" },
|
|
8
14
|
{ name: "Option 2", value: "opt2" },
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import { CloseOutline, ChevronDownOutline } from "../../primitives/Icons";
|
|
3
3
|
import { typography } from '../../tokens/typography';
|
|
4
|
+
import { bloom } from "../../utils/transitions.js";
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -183,7 +184,7 @@
|
|
|
183
184
|
<div
|
|
184
185
|
bind:this={triggerElement}
|
|
185
186
|
{id}
|
|
186
|
-
class="flex items-center justify-between gap-2 w-full {sizeClass} bg-gray-50 dark:bg-gray-800 border rounded-lg cursor-pointer text-left transition-all focus:outline-
|
|
187
|
+
class="flex items-center justify-between gap-2 w-full {sizeClass} bg-gray-50 dark:bg-gray-800 border rounded-lg cursor-pointer text-left transition-all focus:outline-hidden focus:ring-4 focus:ring-blue-300 dark:focus:ring-blue-800
|
|
187
188
|
{error ? 'border-red-500 dark:border-red-500' : 'border-gray-300 dark:border-gray-600 hover:border-blue-500 dark:hover:border-blue-500 focus:border-blue-500 dark:focus:border-blue-500'}
|
|
188
189
|
{disabled ? 'opacity-50 cursor-not-allowed' : ''}
|
|
189
190
|
{animateFocus ? 'multiselect-animate-focus' : ''}"
|
|
@@ -206,7 +207,7 @@
|
|
|
206
207
|
<span class={`${typography.sm} overflow-hidden text-ellipsis whitespace-nowrap`} style="color-scheme: light dark;">{item.name}</span>
|
|
207
208
|
<button
|
|
208
209
|
type="button"
|
|
209
|
-
class="inline-flex items-center p-0.5 ms-1.5 text-sm text-blue-400 bg-transparent rounded-
|
|
210
|
+
class="inline-flex items-center p-0.5 ms-1.5 text-sm text-blue-400 bg-transparent rounded-xs hover:bg-blue-200 hover:text-blue-900 dark:hover:bg-blue-800 dark:hover:text-blue-300"
|
|
210
211
|
onclick={(e) => removeItem(item, e)}
|
|
211
212
|
aria-label="Remove {item.name}"
|
|
212
213
|
>
|
|
@@ -220,7 +221,7 @@
|
|
|
220
221
|
{/if}
|
|
221
222
|
</div>
|
|
222
223
|
|
|
223
|
-
<div class="flex items-center gap-1
|
|
224
|
+
<div class="flex items-center gap-1 shrink-0">
|
|
224
225
|
{#if hasSelection && !hideClear}
|
|
225
226
|
<button
|
|
226
227
|
type="button"
|
|
@@ -244,6 +245,7 @@
|
|
|
244
245
|
role="listbox"
|
|
245
246
|
tabindex="-1"
|
|
246
247
|
aria-multiselectable="true"
|
|
248
|
+
transition:bloom={{ origin: "top left" }}
|
|
247
249
|
aria-activedescendant={focusedIndex >= 0
|
|
248
250
|
? `${id || name}-option-${focusedIndex}`
|
|
249
251
|
: undefined}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultiSelect.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/recipes/inputs/MultiSelect.svelte.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"MultiSelect.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/recipes/inputs/MultiSelect.svelte.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAwQA;YAhBY,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE;YACnB;;;;cA1OI,MAAM;;;;eACN,MAAM,GAAG,MAAM;OAyOP;kBACN,MAAM;YACZ,MAAM;eACH,OAAO;eACP,OAAO;YACV,MAAM;gBACF,OAAO;qBACF,OAAO;mBACT,OAAO;WACf,MAAM;SACR,MAAM;WACJ,IAAI,GAAG,IAAI,GAAG,IAAI;mBACV,OAAO;eACX,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;QAAC,KAAK,EAAE;;;;kBAvP7C,MAAM;;;;mBACN,MAAM,GAAG,MAAM;WAsP0C,CAAA;KAAE,KAAK,IAAI;gBAE1B;;;;;UAzP1C,MAAM;;;;WACN,MAAM,GAAG,MAAM"}
|
|
@@ -108,7 +108,7 @@
|
|
|
108
108
|
{disabled}
|
|
109
109
|
aria-label="Digit {index + 1} of {length}"
|
|
110
110
|
aria-describedby="otp-instructions"
|
|
111
|
-
class="h-12 w-12 border-2 border-gray-300 bg-gray-50 p-0 text-center text-xl font-semibold leading-none text-gray-900 transition-colors focus:border-blue-500 focus:outline-
|
|
111
|
+
class="h-12 w-12 border-2 border-gray-300 bg-gray-50 p-0 text-center text-xl font-semibold leading-none text-gray-900 transition-colors focus:border-blue-500 focus:outline-hidden focus:ring-blue-500 disabled:cursor-not-allowed disabled:bg-gray-200 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder-gray-400 dark:focus:border-blue-500 dark:focus:ring-blue-500 dark:disabled:bg-gray-600 md:h-14 md:w-14 md:text-2xl rounded-lg"
|
|
112
112
|
oninput={(e) => handleInput(index, e)}
|
|
113
113
|
onkeydown={(e) => handleKeyDown(index, e)}
|
|
114
114
|
onpaste={handlePaste}
|
|
@@ -32,6 +32,12 @@ vi.mock('$lib/config.js', () => ({
|
|
|
32
32
|
PUBLIC_GOOGLE_MAPS_API_KEY: 'test-api-key',
|
|
33
33
|
}));
|
|
34
34
|
|
|
35
|
+
// Mock transitions to be instant for testing
|
|
36
|
+
vi.mock('../../../utils/transitions.js', () => ({
|
|
37
|
+
bloom: () => ({ duration: 0, delay: 0, css: () => '' }),
|
|
38
|
+
safeSlide: () => ({ duration: 0, delay: 0, css: () => '' }),
|
|
39
|
+
}));
|
|
40
|
+
|
|
35
41
|
function setupTest(props = {}) {
|
|
36
42
|
const user = userEvent.setup();
|
|
37
43
|
const result = render(PlaceAutocomplete, { props });
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import * as GMaps from '@googlemaps/js-api-loader';
|
|
4
4
|
import { PUBLIC_GOOGLE_MAPS_API_KEY } from '../../../config.js';
|
|
5
5
|
import { typography } from '../../../tokens/typography';
|
|
6
|
+
import { bloom } from '../../../utils/transitions.js';
|
|
6
7
|
const { Loader } = GMaps;
|
|
7
8
|
/** 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
9
|
|
|
@@ -291,7 +292,7 @@
|
|
|
291
292
|
type="text"
|
|
292
293
|
name="location"
|
|
293
294
|
class="block w-full h-10 pl-10 pr-2.5 py-2.5 bg-gray-50 border border-gray-300 rounded-lg {typography.label}
|
|
294
|
-
focus:ring-blue-500 focus:border-blue-500 focus:outline-
|
|
295
|
+
focus:ring-blue-500 focus:border-blue-500 focus:outline-hidden
|
|
295
296
|
hover:border-blue-500
|
|
296
297
|
disabled:opacity-50 disabled:cursor-not-allowed
|
|
297
298
|
placeholder:text-gray-500
|
|
@@ -318,6 +319,7 @@
|
|
|
318
319
|
class="absolute top-full left-0 right-0 z-50 mt-1 py-1 bg-white border border-gray-200 rounded-lg shadow-lg max-h-60 overflow-y-auto
|
|
319
320
|
dark:bg-gray-800 dark:border-gray-600"
|
|
320
321
|
id="options"
|
|
322
|
+
transition:bloom={{ origin: "top left" }}
|
|
321
323
|
>
|
|
322
324
|
{#each results as place, i}
|
|
323
325
|
<li
|
|
@@ -328,7 +330,7 @@
|
|
|
328
330
|
<button
|
|
329
331
|
type="button"
|
|
330
332
|
class="block w-full text-left px-4 py-3 bg-transparent border-none cursor-pointer {typography.sm}
|
|
331
|
-
focus:outline-
|
|
333
|
+
focus:outline-hidden focus:bg-gray-100 dark:focus:bg-gray-700"
|
|
332
334
|
tabindex={i + 1}
|
|
333
335
|
onclick={() => onPlaceSelected(place.to_place, place.text)}
|
|
334
336
|
>
|
|
@@ -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":"AASA,0CAA0C,CAAE,UAAU,gBAAgB;IAAM,QAAQ,EAAE,MAAM,CAAC;IAAI,SAAS,EAAE,MAAM,CAAC;IAAI,KAAK,EAAE,MAAM,EAAE,CAAC;CAAG;AACzI,sCAAsC,CAAE,UAAU,SAAS;IAAM,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAAI,iBAAiB,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAAI,IAAI,CAAC,EAAE,MAAM,CAAC;IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAAG;AAMrL,UAAU,KAAK;IACb,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,CAAC;IACvC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,IAAI,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;IAC5B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAsTH,QAAA,MAAM,iBAAiB,sDAAwC,CAAC;AAChE,KAAK,iBAAiB,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC9D,eAAe,iBAAiB,CAAC"}
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
{name}
|
|
85
85
|
{placeholder}
|
|
86
86
|
{disabled}
|
|
87
|
-
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-
|
|
87
|
+
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
88
|
bind:value
|
|
89
89
|
oninput={handleInput}
|
|
90
90
|
onchange={handleChange}
|
|
@@ -3,6 +3,12 @@ import userEvent from "@testing-library/user-event";
|
|
|
3
3
|
import { expect, describe, test, vi, beforeEach } from "vitest";
|
|
4
4
|
import SelectDropdown from "./SelectDropdown.svelte";
|
|
5
5
|
|
|
6
|
+
// Mock transitions to be instant for testing
|
|
7
|
+
vi.mock('../../utils/transitions.js', () => ({
|
|
8
|
+
bloom: () => ({ duration: 0, delay: 0, css: () => '' }),
|
|
9
|
+
safeSlide: () => ({ duration: 0, delay: 0, css: () => '' }),
|
|
10
|
+
}));
|
|
11
|
+
|
|
6
12
|
const sampleOptions = [
|
|
7
13
|
{ label: "Option 1", value: "opt1" },
|
|
8
14
|
{ label: "Option 2", value: "opt2" },
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { tick } from "svelte";
|
|
3
3
|
import { ChevronDownOutline } from "../../primitives/Icons";
|
|
4
|
+
import { bloom } from "../../utils/transitions.js";
|
|
4
5
|
|
|
5
6
|
interface SelectOption {
|
|
6
7
|
label: string;
|
|
@@ -129,7 +130,7 @@
|
|
|
129
130
|
<button
|
|
130
131
|
bind:this={triggerRef}
|
|
131
132
|
type="button"
|
|
132
|
-
class="inline-flex items-center justify-between w-full px-4 py-2.5 text-sm font-medium text-gray-900 bg-white border border-gray-300 rounded-lg hover:bg-gray-100 focus:ring-4 focus:outline-
|
|
133
|
+
class="inline-flex items-center justify-between w-full px-4 py-2.5 text-sm font-medium text-gray-900 bg-white border border-gray-300 rounded-lg hover:bg-gray-100 focus:ring-4 focus:outline-hidden focus:ring-blue-300 dark:bg-gray-700 dark:text-white dark:border-gray-600 dark:hover:bg-gray-600 dark:focus:ring-blue-800 {disabled ? 'opacity-50 cursor-not-allowed' : ''}"
|
|
133
134
|
onclick={toggleDropdown}
|
|
134
135
|
aria-haspopup="listbox"
|
|
135
136
|
aria-expanded={isOpen}
|
|
@@ -148,6 +149,7 @@
|
|
|
148
149
|
class="absolute z-10 mt-1 w-full bg-white divide-y divide-gray-100 rounded-lg shadow-lg dark:bg-gray-700 dark:divide-gray-600 max-h-60 overflow-y-auto"
|
|
149
150
|
role="listbox"
|
|
150
151
|
aria-label={placeholder}
|
|
152
|
+
transition:bloom={{ origin: "top left" }}
|
|
151
153
|
>
|
|
152
154
|
<ul class="py-2 text-sm text-gray-700 dark:text-gray-200">
|
|
153
155
|
{#each options as option}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SelectDropdown.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/recipes/inputs/SelectDropdown.svelte.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SelectDropdown.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/recipes/inputs/SelectDropdown.svelte.ts"],"names":[],"mappings":"AAQE,UAAU,YAAY;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,UAAU,KAAK;IACb,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB,QAAQ,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,CAAC;CAC3C;AA8IH,QAAA,MAAM,cAAc,mDAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
|
|
@@ -118,7 +118,7 @@
|
|
|
118
118
|
bind:value={inputValue}
|
|
119
119
|
placeholder={inputPlaceholder}
|
|
120
120
|
rows={inputRows}
|
|
121
|
-
class="w-full px-3 py-2 border {hasError ? 'border-red-500' : 'border-gray-300 dark:border-gray-600'} bg-gray-50 dark:bg-gray-700 {typography.body} rounded-lg focus:outline-
|
|
121
|
+
class="w-full px-3 py-2 border {hasError ? 'border-red-500' : 'border-gray-300 dark:border-gray-600'} bg-gray-50 dark:bg-gray-700 {typography.body} rounded-lg focus:outline-hidden focus:ring-2 focus:ring-blue-500 focus:border-transparent resize-none"
|
|
122
122
|
disabled={disabled || loading}
|
|
123
123
|
></textarea>
|
|
124
124
|
{:else}
|
|
@@ -34,32 +34,32 @@
|
|
|
34
34
|
}: Props = $props();
|
|
35
35
|
</script>
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
{#
|
|
39
|
-
{
|
|
40
|
-
|
|
41
|
-
{
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
{/snippet}
|
|
37
|
+
{#snippet headerContent()}
|
|
38
|
+
{#if header}
|
|
39
|
+
{@render header()}
|
|
40
|
+
{:else}
|
|
41
|
+
{title}
|
|
42
|
+
{/if}
|
|
43
|
+
{/snippet}
|
|
45
44
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
{/if}
|
|
45
|
+
{#snippet bodyContent()}
|
|
46
|
+
{#if body}
|
|
47
|
+
{@render body()}
|
|
48
|
+
{:else}
|
|
49
|
+
{description}
|
|
50
|
+
{#if warningText}
|
|
51
|
+
<br /> {warningText}
|
|
54
52
|
{/if}
|
|
55
|
-
{/
|
|
53
|
+
{/if}
|
|
54
|
+
{/snippet}
|
|
56
55
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
56
|
+
{#snippet footerContent()}
|
|
57
|
+
{#if footer}
|
|
58
|
+
{@render footer()}
|
|
59
|
+
{:else}
|
|
60
|
+
<Button variant="alternative">Cancel</Button>
|
|
61
|
+
<Button variant="default">Confirm</Button>
|
|
62
|
+
{/if}
|
|
63
|
+
{/snippet}
|
|
64
|
+
|
|
65
|
+
<Modal bind:show {oncancel} header={headerContent} body={bodyContent} footer={footerContent} />
|
|
@@ -727,7 +727,7 @@ describe('ButtonAuditDashboard', () => {
|
|
|
727
727
|
|
|
728
728
|
it('should have proper border and shadow styling', () => {
|
|
729
729
|
const { container } = render(ButtonAuditDashboard);
|
|
730
|
-
const header = container.querySelector('.border-b.shadow
|
|
730
|
+
const header = container.querySelector('.border-b.shadow');
|
|
731
731
|
expect(header).toBeInTheDocument();
|
|
732
732
|
});
|
|
733
733
|
});
|
|
@@ -161,7 +161,7 @@
|
|
|
161
161
|
|
|
162
162
|
<div class="min-h-screen bg-gray-50 dark:bg-gray-900 transition-colors">
|
|
163
163
|
<!-- Sticky Header -->
|
|
164
|
-
<div class="sticky top-0 z-50 bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 shadow
|
|
164
|
+
<div class="sticky top-0 z-50 bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 shadow">
|
|
165
165
|
<div class="max-w-7xl mx-auto px-4 py-4">
|
|
166
166
|
<div class="flex flex-wrap items-center justify-between gap-4">
|
|
167
167
|
<div>
|
|
@@ -292,21 +292,21 @@
|
|
|
292
292
|
📂 Open
|
|
293
293
|
</a>
|
|
294
294
|
</div>
|
|
295
|
-
<div class="flex items-center gap-2
|
|
296
|
-
{#if isPreviewable(route.file)}
|
|
297
|
-
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
298
|
-
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
299
|
-
<span
|
|
300
|
-
role="button"
|
|
301
|
-
tabindex="0"
|
|
302
|
-
onclick={(e) => { e.stopPropagation(); openPreview(route.route, route.file); }}
|
|
303
|
-
onkeydown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.stopPropagation(); openPreview(route.route, route.file); }}}
|
|
304
|
-
class="px-2 py-0.5 text-xs rounded bg-green-100 text-green-700 hover:bg-green-200 dark:bg-green-900 dark:text-green-300 dark:hover:bg-green-800 cursor-pointer"
|
|
305
|
-
title="Preview this page"
|
|
306
|
-
>
|
|
307
|
-
👁️ Preview
|
|
308
|
-
</span>
|
|
309
|
-
{/if}
|
|
295
|
+
<div class="flex items-center gap-2 shrink-0 ml-2">
|
|
296
|
+
{#if isPreviewable(route.file)}
|
|
297
|
+
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
298
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
299
|
+
<span
|
|
300
|
+
role="button"
|
|
301
|
+
tabindex="0"
|
|
302
|
+
onclick={(e) => { e.stopPropagation(); openPreview(route.route, route.file); }}
|
|
303
|
+
onkeydown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.stopPropagation(); openPreview(route.route, route.file); }}}
|
|
304
|
+
class="px-2 py-0.5 text-xs rounded bg-green-100 text-green-700 hover:bg-green-200 dark:bg-green-900 dark:text-green-300 dark:hover:bg-green-800 cursor-pointer"
|
|
305
|
+
title="Preview this page"
|
|
306
|
+
>
|
|
307
|
+
👁️ Preview
|
|
308
|
+
</span>
|
|
309
|
+
{/if}
|
|
310
310
|
<span class="text-xs text-gray-500 dark:text-gray-400">
|
|
311
311
|
{routeVisibleButtons.length} buttons
|
|
312
312
|
</span>
|
|
@@ -404,7 +404,7 @@
|
|
|
404
404
|
|
|
405
405
|
<!-- Preview Modal -->
|
|
406
406
|
{#if previewModal.open}
|
|
407
|
-
<div class="fixed inset-0 z-[100] flex items-center justify-center p-4 bg-black/50 backdrop-blur-
|
|
407
|
+
<div class="fixed inset-0 z-[100] flex items-center justify-center p-4 bg-black/50 backdrop-blur-xs">
|
|
408
408
|
<div class="relative w-full max-w-6xl h-[85vh] bg-white dark:bg-gray-800 rounded-xl shadow-2xl overflow-hidden flex flex-col">
|
|
409
409
|
<!-- Modal Header -->
|
|
410
410
|
<div class="flex items-center justify-between px-4 py-3 bg-gray-100 dark:bg-gray-700 border-b border-gray-200 dark:border-gray-600">
|
|
@@ -430,14 +430,14 @@
|
|
|
430
430
|
</div>
|
|
431
431
|
</div>
|
|
432
432
|
|
|
433
|
-
<!-- Iframe Content -->
|
|
434
|
-
<div class="flex-1 relative">
|
|
435
|
-
<iframe
|
|
436
|
-
src={previewModal.url}
|
|
437
|
-
class="absolute inset-0 w-full h-full border-0"
|
|
438
|
-
title="Page preview"
|
|
439
|
-
></iframe>
|
|
440
|
-
</div>
|
|
433
|
+
<!-- Iframe Content -->
|
|
434
|
+
<div class="flex-1 relative">
|
|
435
|
+
<iframe
|
|
436
|
+
src={previewModal.url}
|
|
437
|
+
class="absolute inset-0 w-full h-full border-0"
|
|
438
|
+
title="Page preview"
|
|
439
|
+
></iframe>
|
|
440
|
+
</div>
|
|
441
441
|
|
|
442
442
|
<!-- Modal Footer -->
|
|
443
443
|
<div class="px-4 py-2 bg-gray-50 dark:bg-gray-700/50 border-t border-gray-200 dark:border-gray-600 text-xs text-gray-500 dark:text-gray-400">
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
|
|
75
75
|
<div class="min-h-screen bg-gray-100 dark:bg-gray-900 p-4">
|
|
76
76
|
<!-- Header -->
|
|
77
|
-
<div class="sticky top-0 z-50 bg-white dark:bg-gray-800 rounded-lg shadow
|
|
77
|
+
<div class="sticky top-0 z-50 bg-white dark:bg-gray-800 rounded-lg shadow p-4 mb-4">
|
|
78
78
|
<div class="flex flex-wrap items-center justify-between gap-4">
|
|
79
79
|
<div>
|
|
80
80
|
<h1 class="text-xl font-bold text-gray-900 dark:text-white">Button Grid View</h1>
|
|
@@ -192,7 +192,7 @@
|
|
|
192
192
|
type="text"
|
|
193
193
|
placeholder="John Doe"
|
|
194
194
|
bind:value={formFieldValue}
|
|
195
|
-
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-gray-50 dark:bg-gray-700 focus:outline-
|
|
195
|
+
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-gray-50 dark:bg-gray-700 focus:outline-hidden focus:ring-2 focus:ring-blue-500"
|
|
196
196
|
/>
|
|
197
197
|
{/snippet}
|
|
198
198
|
</FormField>
|
|
@@ -208,7 +208,7 @@
|
|
|
208
208
|
{id}
|
|
209
209
|
type="email"
|
|
210
210
|
placeholder="email@example.com"
|
|
211
|
-
class="w-full px-3 py-2 border {error ? 'border-red-500' : 'border-gray-300 dark:border-gray-600'} rounded-lg bg-gray-50 dark:bg-gray-700 focus:outline-
|
|
211
|
+
class="w-full px-3 py-2 border {error ? 'border-red-500' : 'border-gray-300 dark:border-gray-600'} rounded-lg bg-gray-50 dark:bg-gray-700 focus:outline-hidden focus:ring-2 focus:ring-blue-500"
|
|
212
212
|
/>
|
|
213
213
|
{/snippet}
|
|
214
214
|
</FormField>
|
|
@@ -423,7 +423,7 @@
|
|
|
423
423
|
{id}
|
|
424
424
|
type="email"
|
|
425
425
|
placeholder="email@example.com"
|
|
426
|
-
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-gray-50 dark:bg-gray-700 focus:outline-
|
|
426
|
+
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-gray-50 dark:bg-gray-700 focus:outline-hidden focus:ring-2 focus:ring-blue-500"
|
|
427
427
|
/>
|
|
428
428
|
{/snippet}
|
|
429
429
|
</FormField>
|
|
@@ -173,7 +173,7 @@
|
|
|
173
173
|
|
|
174
174
|
/* Elevated card with shadow */
|
|
175
175
|
.card-elevated {
|
|
176
|
-
@apply bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-lg shadow
|
|
176
|
+
@apply bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-lg shadow;
|
|
177
177
|
}
|
|
178
178
|
|
|
179
179
|
/* Compact card with less padding */
|
|
@@ -258,22 +258,22 @@
|
|
|
258
258
|
|
|
259
259
|
/* Base input styling */
|
|
260
260
|
.input-base {
|
|
261
|
-
@apply w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white placeholder-gray-400 dark:placeholder-gray-500 focus:outline-
|
|
261
|
+
@apply w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white placeholder-gray-400 dark:placeholder-gray-500 focus:outline-hidden focus:ring-2 focus:ring-blue-500 focus:border-transparent;
|
|
262
262
|
}
|
|
263
263
|
|
|
264
264
|
/* Base button styling */
|
|
265
265
|
.btn-base {
|
|
266
|
-
@apply inline-flex items-center justify-center px-4 py-2 text-sm font-medium rounded-lg transition-colors focus:outline-
|
|
266
|
+
@apply inline-flex items-center justify-center px-4 py-2 text-sm font-medium rounded-lg transition-colors focus:outline-hidden focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed;
|
|
267
267
|
}
|
|
268
268
|
|
|
269
269
|
/* Primary button */
|
|
270
270
|
.btn-primary {
|
|
271
|
-
@apply inline-flex items-center justify-center px-4 py-2 text-sm font-medium rounded-lg transition-colors focus:outline-
|
|
271
|
+
@apply inline-flex items-center justify-center px-4 py-2 text-sm font-medium rounded-lg transition-colors focus:outline-hidden focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500;
|
|
272
272
|
}
|
|
273
273
|
|
|
274
274
|
/* Secondary/outline button */
|
|
275
275
|
.btn-secondary {
|
|
276
|
-
@apply inline-flex items-center justify-center px-4 py-2 text-sm font-medium rounded-lg transition-colors focus:outline-
|
|
276
|
+
@apply inline-flex items-center justify-center px-4 py-2 text-sm font-medium rounded-lg transition-colors focus:outline-hidden focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-200 border border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700 focus:ring-gray-500;
|
|
277
277
|
}
|
|
278
278
|
|
|
279
279
|
/* ==========================================================================
|