@makolabs/ripple 2.5.9 → 3.0.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/README.md +403 -497
- package/dist/adapters/storage/S3Adapter.d.ts +49 -1
- package/dist/adapters/storage/S3Adapter.js +38 -1
- package/dist/adapters/storage/types.d.ts +20 -0
- package/dist/ai/AIChatInterface.svelte +2 -1
- package/dist/ai/AIChatInterface.svelte.d.ts +2 -1
- package/dist/ai/CodeRenderer.svelte +7 -2
- package/dist/ai/CodeRenderer.svelte.d.ts +2 -1
- package/dist/ai/ComposeDropdown.svelte +1 -1
- package/dist/ai/MessageBox.svelte +3 -3
- package/dist/ai/MessageBox.svelte.d.ts +3 -2
- package/dist/ai/ThinkingDisplay.svelte +4 -3
- package/dist/ai/ThinkingDisplay.svelte.d.ts +2 -1
- package/dist/ai/ai-types.d.ts +55 -1
- package/dist/button/Button.svelte +5 -5
- package/dist/button/button-types.d.ts +49 -4
- package/dist/button/button.d.ts +9 -9
- package/dist/button/button.js +6 -6
- package/dist/charts/Chart.svelte +8 -16
- package/dist/charts/chart-types.d.ts +78 -1
- package/dist/drawer/Drawer.svelte +6 -26
- package/dist/drawer/drawer-types.d.ts +33 -12
- package/dist/drawer/drawer.d.ts +3 -3
- package/dist/drawer/drawer.js +1 -1
- package/dist/elements/accordion/Accordion.svelte +6 -17
- package/dist/elements/accordion/accordion-types.d.ts +53 -6
- package/dist/elements/alert/Alert.svelte +3 -0
- package/dist/elements/badge/Badge.svelte +1 -1
- package/dist/elements/badge/badge-types.d.ts +22 -0
- package/dist/elements/badge/badge.d.ts +3 -3
- package/dist/elements/badge/badge.js +1 -1
- package/dist/elements/combobox/ComboBox.svelte +244 -0
- package/dist/elements/combobox/ComboBox.svelte.d.ts +4 -0
- package/dist/elements/combobox/combobox-types.d.ts +41 -0
- package/dist/elements/combobox/combobox-types.js +1 -0
- package/dist/elements/context-menu/ContextMenu.svelte +137 -0
- package/dist/elements/context-menu/ContextMenu.svelte.d.ts +4 -0
- package/dist/elements/context-menu/context-menu-types.d.ts +40 -0
- package/dist/elements/context-menu/context-menu-types.js +1 -0
- package/dist/elements/dropdown/Dropdown.svelte +1 -1
- package/dist/elements/dropdown/Select.svelte +4 -1
- package/dist/elements/dropdown/dropdown-types.d.ts +114 -0
- package/dist/elements/dropdown/dropdown.d.ts +3 -3
- package/dist/elements/dropdown/dropdown.js +2 -2
- package/dist/elements/dropdown/select.d.ts +3 -108
- package/dist/elements/dropdown/select.js +38 -47
- package/dist/elements/empty-state/EmptyState.svelte +1 -1
- package/dist/elements/empty-state/empty-state-types.d.ts +32 -1
- package/dist/elements/empty-state/empty-state.d.ts +3 -3
- package/dist/elements/empty-state/empty-state.js +2 -2
- package/dist/elements/file-upload/FileUpload.svelte +5 -0
- package/dist/elements/file-upload/file-upload-types.d.ts +59 -0
- package/dist/elements/pagination/Pagination.svelte +53 -21
- package/dist/elements/pagination/Pagination.svelte.d.ts +33 -5
- package/dist/elements/popover/Popover.svelte +254 -0
- package/dist/elements/popover/Popover.svelte.d.ts +4 -0
- package/dist/elements/popover/index.d.ts +2 -0
- package/dist/elements/popover/index.js +1 -0
- package/dist/elements/popover/popover-types.d.ts +60 -0
- package/dist/elements/popover/popover-types.js +1 -0
- package/dist/elements/progress/Progress.svelte +32 -7
- package/dist/elements/progress/progress-types.d.ts +48 -1
- package/dist/elements/skeleton/Skeleton.svelte +56 -0
- package/dist/elements/skeleton/Skeleton.svelte.d.ts +4 -0
- package/dist/elements/skeleton/index.d.ts +2 -0
- package/dist/elements/skeleton/index.js +1 -0
- package/dist/elements/skeleton/skeleton-types.d.ts +50 -0
- package/dist/elements/skeleton/skeleton-types.js +1 -0
- package/dist/elements/spinner/Spinner.svelte +1 -1
- package/dist/elements/spinner/spinner-types.d.ts +20 -0
- package/dist/elements/spinner/spinner.d.ts +3 -3
- package/dist/elements/spinner/spinner.js +2 -2
- package/dist/elements/tooltip/Tooltip.svelte +108 -11
- package/dist/elements/tooltip/tooltip-types.d.ts +49 -1
- package/dist/file-browser/FileBrowser.svelte +21 -12
- package/dist/filters/CompactFilters.svelte +221 -33
- package/dist/filters/CompactFilters.svelte.d.ts +1 -1
- package/dist/filters/FilterBar.svelte +184 -0
- package/dist/filters/FilterBar.svelte.d.ts +4 -0
- package/dist/filters/FilterPopover.svelte +346 -0
- package/dist/filters/FilterPopover.svelte.d.ts +4 -0
- package/dist/filters/date-presets.d.ts +15 -0
- package/dist/filters/date-presets.js +107 -0
- package/dist/filters/filter-types.d.ts +69 -3
- package/dist/filters/index.d.ts +5 -0
- package/dist/filters/index.js +4 -0
- package/dist/filters/sync-filters-to-url.svelte.d.ts +37 -0
- package/dist/filters/sync-filters-to-url.svelte.js +114 -0
- package/dist/forms/Checkbox.svelte +24 -9
- package/dist/forms/DateRange.svelte +23 -6
- package/dist/forms/Input.svelte +19 -19
- package/dist/forms/MarketSelector.svelte +9 -4
- package/dist/forms/NumberInput.svelte +14 -18
- package/dist/forms/RadioGroup.svelte +127 -0
- package/dist/forms/RadioGroup.svelte.d.ts +4 -0
- package/dist/forms/SegmentedControl.svelte +11 -4
- package/dist/forms/Slider.svelte +72 -3
- package/dist/forms/Tags.svelte +44 -14
- package/dist/forms/Textarea.svelte +121 -0
- package/dist/forms/Textarea.svelte.d.ts +4 -0
- package/dist/forms/Toggle.svelte +30 -22
- package/dist/forms/calendar/Calendar.svelte +315 -0
- package/dist/forms/calendar/Calendar.svelte.d.ts +4 -0
- package/dist/forms/calendar/calendar-types.d.ts +54 -0
- package/dist/forms/calendar/calendar-types.js +1 -0
- package/dist/forms/calendar/index.d.ts +2 -0
- package/dist/forms/calendar/index.js +1 -0
- package/dist/forms/date-picker/DatePicker.svelte +141 -0
- package/dist/forms/date-picker/DatePicker.svelte.d.ts +4 -0
- package/dist/forms/date-picker/date-picker-types.d.ts +29 -0
- package/dist/forms/date-picker/date-picker-types.js +1 -0
- package/dist/forms/form-size.d.ts +37 -0
- package/dist/forms/form-size.js +67 -0
- package/dist/forms/form-types.d.ts +430 -6
- package/dist/forms/market/market-selector-types.d.ts +52 -1
- package/dist/forms/segmented-control.d.ts +5 -2
- package/dist/forms/segmented-control.js +25 -13
- package/dist/forms/slider.d.ts +3 -3
- package/dist/forms/slider.js +37 -30
- package/dist/funcs/user-management.remote.js +1 -1
- package/dist/header/Breadcrumbs.svelte +4 -20
- package/dist/header/PageHeader.svelte +6 -14
- package/dist/header/breadcrumbs.d.ts +3 -11
- package/dist/header/breadcrumbs.js +10 -5
- package/dist/header/header-types.d.ts +62 -11
- package/dist/index.d.ts +35 -9
- package/dist/index.js +24 -4
- package/dist/layout/activity-list/ActivityList.svelte +13 -7
- package/dist/layout/activity-list/activity-list-types.d.ts +46 -7
- package/dist/layout/card/Card.svelte +12 -15
- package/dist/layout/card/MetricCard.svelte +50 -32
- package/dist/layout/card/card-types.d.ts +114 -4
- package/dist/layout/navbar/navbar-types.d.ts +48 -0
- package/dist/layout/navbar/navbar.d.ts +3 -3
- package/dist/layout/navbar/navbar.js +2 -2
- package/dist/layout/sidebar/Sidebar.svelte +87 -11
- package/dist/layout/sidebar/sidebar-types.d.ts +60 -1
- package/dist/layout/stepper/Stepper.svelte +288 -0
- package/dist/layout/stepper/Stepper.svelte.d.ts +4 -0
- package/dist/layout/stepper/stepper-types.d.ts +80 -0
- package/dist/layout/stepper/stepper-types.js +1 -0
- package/dist/layout/table/Table.svelte +91 -85
- package/dist/layout/table/table-types.d.ts +148 -24
- package/dist/layout/table/table.d.ts +3 -3
- package/dist/layout/table/table.js +2 -2
- package/dist/layout/tabs/Tab.svelte +6 -2
- package/dist/layout/tabs/Tab.svelte.d.ts +4 -1
- package/dist/layout/tabs/TabGroup.svelte +9 -2
- package/dist/layout/tabs/tabs-types.d.ts +63 -0
- package/dist/layout/tabs/tabs.d.ts +3 -3
- package/dist/layout/tabs/tabs.js +12 -6
- package/dist/modal/ConfirmDialog.svelte +65 -0
- package/dist/modal/ConfirmDialog.svelte.d.ts +4 -0
- package/dist/modal/Modal.svelte +6 -26
- package/dist/modal/confirm-dialog-types.d.ts +39 -0
- package/dist/modal/confirm-dialog-types.js +1 -0
- package/dist/modal/modal-types.d.ts +51 -12
- package/dist/modal/modal.d.ts +3 -3
- package/dist/modal/modal.js +3 -3
- package/dist/pipeline/Pipeline.svelte +8 -3
- package/dist/pipeline/pipeline-types.d.ts +55 -3
- package/dist/pipeline/pipeline.d.ts +18 -3
- package/dist/pipeline/pipeline.js +7 -2
- package/dist/server/s3.d.ts +35 -3
- package/dist/sonner/Toaster.svelte +29 -0
- package/dist/sonner/Toaster.svelte.d.ts +4 -0
- package/dist/sonner/index.d.ts +21 -0
- package/dist/sonner/index.js +20 -0
- package/dist/user-management/UserManagement.svelte +22 -16
- package/dist/user-management/UserModal.svelte +10 -7
- package/dist/user-management/UserTable.svelte +16 -17
- package/dist/user-management/UserViewModal.svelte +11 -11
- package/dist/user-management/user-management-types.d.ts +118 -31
- package/dist/variants.d.ts +1 -1
- package/dist/variants.js +1 -1
- package/package.json +7 -4
- package/dist/config/ai.d.ts +0 -13
- package/dist/config/ai.js +0 -44
- package/dist/elements/empty-state/EmptyStateTestWrapper.svelte +0 -25
- package/dist/elements/empty-state/EmptyStateTestWrapper.svelte.d.ts +0 -8
- package/dist/elements/tooltip/TooltipTestWrapper.svelte +0 -14
- package/dist/elements/tooltip/TooltipTestWrapper.svelte.d.ts +0 -7
- package/dist/helper/deprecation.d.ts +0 -14
- package/dist/helper/deprecation.js +0 -24
- package/dist/modal/ModalFooterTestWrapper.svelte +0 -17
- package/dist/modal/ModalFooterTestWrapper.svelte.d.ts +0 -8
package/dist/forms/Slider.svelte
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { buildTestId } from '../helper/testid.js';
|
|
5
5
|
import { slider } from './slider.js';
|
|
6
6
|
import { Size } from '../variants.js';
|
|
7
|
-
import type { SliderProps } from '../index.js';
|
|
7
|
+
import type { SliderProps, SliderTick } from '../index.js';
|
|
8
8
|
|
|
9
9
|
interface EnumOption {
|
|
10
10
|
value: string | number;
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
label,
|
|
21
21
|
mode = 'single' as SliderMode,
|
|
22
22
|
disabled = false,
|
|
23
|
-
size = Size.
|
|
23
|
+
size = Size.MD,
|
|
24
24
|
errors = [],
|
|
25
25
|
class: className = '',
|
|
26
26
|
min = 0,
|
|
@@ -38,9 +38,45 @@
|
|
|
38
38
|
maximumFractionDigits: 1,
|
|
39
39
|
minimumFractionDigits: 0
|
|
40
40
|
},
|
|
41
|
+
tickInterval,
|
|
42
|
+
ticks,
|
|
41
43
|
testId
|
|
42
44
|
}: SliderProps = $props();
|
|
43
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Resolved tick list for single/range modes. Explicit `ticks` wins;
|
|
48
|
+
* otherwise generated from `tickInterval`. Empty for enum mode.
|
|
49
|
+
*/
|
|
50
|
+
const resolvedTicks = $derived.by<SliderTick[]>(() => {
|
|
51
|
+
if (mode === 'enum') return [];
|
|
52
|
+
if (ticks && ticks.length > 0) {
|
|
53
|
+
return ticks
|
|
54
|
+
.map((t) => (typeof t === 'number' ? { value: t } : t))
|
|
55
|
+
.filter((t) => t.value >= min && t.value <= max);
|
|
56
|
+
}
|
|
57
|
+
if (tickInterval && tickInterval > 0) {
|
|
58
|
+
const out: SliderTick[] = [];
|
|
59
|
+
for (let v = min; v <= max; v += tickInterval) {
|
|
60
|
+
out.push({ value: v });
|
|
61
|
+
}
|
|
62
|
+
// Include max if rounding left it out
|
|
63
|
+
if (out[out.length - 1]?.value !== max) out.push({ value: max });
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
return [];
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
function getTickPosition(tickValue: number): string {
|
|
70
|
+
return `${((tickValue - min) / (max - min)) * 100}%`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function isTickInRange(tickValue: number): boolean {
|
|
74
|
+
if (mode === 'range') return tickValue >= valueStart && tickValue <= valueEnd;
|
|
75
|
+
if (mode === 'single' && typeof value === 'number')
|
|
76
|
+
return tickValue >= min && tickValue <= value;
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
|
|
44
80
|
$effect(() => {
|
|
45
81
|
if (mode === 'enum' && options.length > 0 && value === min) {
|
|
46
82
|
value = options[0].value;
|
|
@@ -63,7 +99,17 @@
|
|
|
63
99
|
})
|
|
64
100
|
);
|
|
65
101
|
|
|
66
|
-
const
|
|
102
|
+
const hasTickLabels = $derived(resolvedTicks.some((t) => t.label !== undefined));
|
|
103
|
+
const baseClass = $derived(
|
|
104
|
+
cn(
|
|
105
|
+
base(),
|
|
106
|
+
{
|
|
107
|
+
'mb-12': mode === 'enum' || hasTickLabels,
|
|
108
|
+
'mb-6': !hasTickLabels && resolvedTicks.length > 0 && mode !== 'enum'
|
|
109
|
+
},
|
|
110
|
+
className
|
|
111
|
+
)
|
|
112
|
+
);
|
|
67
113
|
const trackClass = $derived(cn(track()));
|
|
68
114
|
const rangeClass = $derived(cn(range()));
|
|
69
115
|
const thumbClass = $derived(cn(thumb()));
|
|
@@ -274,6 +320,29 @@
|
|
|
274
320
|
aria-label={label}
|
|
275
321
|
onclick={handleTrackClick}
|
|
276
322
|
>
|
|
323
|
+
{#each resolvedTicks as tick (tick.value)}
|
|
324
|
+
<div
|
|
325
|
+
class={cn(
|
|
326
|
+
'absolute top-1/2 h-2 w-px -translate-x-1/2 -translate-y-1/2',
|
|
327
|
+
isTickInRange(tick.value) ? 'bg-primary-400' : 'bg-default-300'
|
|
328
|
+
)}
|
|
329
|
+
style="left: {getTickPosition(tick.value)}"
|
|
330
|
+
aria-hidden="true"
|
|
331
|
+
></div>
|
|
332
|
+
{#if tick.label !== undefined}
|
|
333
|
+
<div
|
|
334
|
+
class={cn(
|
|
335
|
+
markClass,
|
|
336
|
+
'text-default-500 pointer-events-none top-4 text-[10px] whitespace-nowrap'
|
|
337
|
+
)}
|
|
338
|
+
style="left: {getTickPosition(tick.value)}"
|
|
339
|
+
aria-hidden="true"
|
|
340
|
+
>
|
|
341
|
+
{tick.label}
|
|
342
|
+
</div>
|
|
343
|
+
{/if}
|
|
344
|
+
{/each}
|
|
345
|
+
|
|
277
346
|
{#if mode === 'range'}
|
|
278
347
|
<div class={rangeClass} style="width: {getRangeWidth()}; left: {getRangeLeft()}"></div>
|
|
279
348
|
<div
|
package/dist/forms/Tags.svelte
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
import Badge from '../elements/badge/Badge.svelte';
|
|
3
3
|
import { Size } from '../variants.js';
|
|
4
4
|
import { cn } from '../helper/cls.js';
|
|
5
|
+
import { formSizeTokens } from './form-size.js';
|
|
6
|
+
import { fade } from 'svelte/transition';
|
|
7
|
+
import { flip } from 'svelte/animate';
|
|
8
|
+
import { quintOut } from 'svelte/easing';
|
|
5
9
|
import type { TagsProps } from '../index.js';
|
|
6
10
|
|
|
7
11
|
let {
|
|
@@ -10,7 +14,7 @@
|
|
|
10
14
|
label,
|
|
11
15
|
errors,
|
|
12
16
|
placeholder = 'Type and press enter to add tags...',
|
|
13
|
-
size = Size.
|
|
17
|
+
size = Size.MD,
|
|
14
18
|
class: className = '',
|
|
15
19
|
suggestions = [],
|
|
16
20
|
onaddtag: onAddTag,
|
|
@@ -31,6 +35,25 @@
|
|
|
31
35
|
showSuggestions ? suggestions.filter(isUnselected).filter(matchesInput).slice(0, 5) : []
|
|
32
36
|
);
|
|
33
37
|
|
|
38
|
+
const tokens = $derived(formSizeTokens[size]);
|
|
39
|
+
|
|
40
|
+
// Chip size shifted one tier down from the Tags container so chip
|
|
41
|
+
// text matches the container text (e.g. Tags `md` uses `text-xs`, so
|
|
42
|
+
// Badge `sm` — which is also `text-xs` — lines up, instead of Badge
|
|
43
|
+
// `md` which jumps to `text-sm`).
|
|
44
|
+
const chipSize = $derived(
|
|
45
|
+
(
|
|
46
|
+
{
|
|
47
|
+
[Size.XS]: Size.XS,
|
|
48
|
+
[Size.SM]: Size.XS,
|
|
49
|
+
[Size.MD]: Size.SM,
|
|
50
|
+
[Size.LG]: Size.MD,
|
|
51
|
+
[Size.XL]: Size.LG,
|
|
52
|
+
[Size.XXL]: Size.LG
|
|
53
|
+
} as const
|
|
54
|
+
)[size]
|
|
55
|
+
);
|
|
56
|
+
|
|
34
57
|
function handleKeydown(event: KeyboardEvent) {
|
|
35
58
|
if (event.key === 'Enter') {
|
|
36
59
|
event.preventDefault();
|
|
@@ -105,12 +128,14 @@
|
|
|
105
128
|
|
|
106
129
|
const containerClass = $derived(
|
|
107
130
|
cn(
|
|
108
|
-
'relative flex flex-wrap gap-2
|
|
131
|
+
'relative flex flex-wrap gap-2 border bg-white',
|
|
132
|
+
tokens.radius,
|
|
133
|
+
tokens.shadow,
|
|
134
|
+
tokens.padX,
|
|
135
|
+
tokens.padY,
|
|
109
136
|
'border-default-300 focus-within:border-primary-500 focus-within:ring-2 focus-within:ring-primary-500 focus-within:ring-offset-2',
|
|
110
|
-
|
|
111
|
-
'border-danger-300 focus-within:border-danger-500 focus-within:ring-danger-500'
|
|
112
|
-
errors?.length
|
|
113
|
-
},
|
|
137
|
+
errors?.length &&
|
|
138
|
+
'border-danger-300 focus-within:border-danger-500 focus-within:ring-danger-500',
|
|
114
139
|
className
|
|
115
140
|
)
|
|
116
141
|
);
|
|
@@ -135,9 +160,15 @@
|
|
|
135
160
|
{/if}
|
|
136
161
|
<div class={containerClass} onfocusout={handleFocusOut}>
|
|
137
162
|
{#each value as tag (tag)}
|
|
138
|
-
<
|
|
139
|
-
|
|
140
|
-
|
|
163
|
+
<div
|
|
164
|
+
class="inline-flex"
|
|
165
|
+
transition:fade={{ duration: 250, easing: quintOut }}
|
|
166
|
+
animate:flip={{ duration: 300, easing: quintOut }}
|
|
167
|
+
>
|
|
168
|
+
<Badge size={chipSize} color="info" onclose={() => handleTagRemoval(tag)} class="shadow-xs">
|
|
169
|
+
{tag}
|
|
170
|
+
</Badge>
|
|
171
|
+
</div>
|
|
141
172
|
{/each}
|
|
142
173
|
<input
|
|
143
174
|
bind:this={inputRef}
|
|
@@ -145,11 +176,10 @@
|
|
|
145
176
|
{name}
|
|
146
177
|
id={name}
|
|
147
178
|
{placeholder}
|
|
148
|
-
class={cn(
|
|
149
|
-
'text-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
})}
|
|
179
|
+
class={cn(
|
|
180
|
+
'placeholder:text-default-400 min-w-[120px] flex-1 bg-transparent outline-none',
|
|
181
|
+
tokens.text
|
|
182
|
+
)}
|
|
153
183
|
type="text"
|
|
154
184
|
autocomplete="off"
|
|
155
185
|
onkeydown={handleKeydown}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn } from '../helper/cls.js';
|
|
3
|
+
import { buildTestId } from '../helper/testid.js';
|
|
4
|
+
import { Size } from '../variants.js';
|
|
5
|
+
import { formSizeTokens } from './form-size.js';
|
|
6
|
+
import type { TextareaProps } from '../index.js';
|
|
7
|
+
|
|
8
|
+
let {
|
|
9
|
+
name,
|
|
10
|
+
id = name,
|
|
11
|
+
label,
|
|
12
|
+
placeholder,
|
|
13
|
+
value = $bindable(''),
|
|
14
|
+
disabled = false,
|
|
15
|
+
readonly = false,
|
|
16
|
+
rows = 3,
|
|
17
|
+
autoGrow = false,
|
|
18
|
+
maxRows = 10,
|
|
19
|
+
maxLength,
|
|
20
|
+
showCount = false,
|
|
21
|
+
size = Size.MD,
|
|
22
|
+
errors = [],
|
|
23
|
+
class: className = '',
|
|
24
|
+
oninput,
|
|
25
|
+
onblur,
|
|
26
|
+
testId
|
|
27
|
+
}: TextareaProps = $props();
|
|
28
|
+
|
|
29
|
+
let el = $state<HTMLTextAreaElement | undefined>();
|
|
30
|
+
|
|
31
|
+
const tokens = $derived(formSizeTokens[size]);
|
|
32
|
+
const hasErrors = $derived(errors.length > 0);
|
|
33
|
+
|
|
34
|
+
const textareaClasses = $derived(
|
|
35
|
+
cn(
|
|
36
|
+
'w-full border bg-white transition-colors',
|
|
37
|
+
'placeholder:text-default-400',
|
|
38
|
+
'focus-within:outline-none focus-within:ring-2 focus-within:ring-offset-2',
|
|
39
|
+
tokens.radius,
|
|
40
|
+
tokens.shadow,
|
|
41
|
+
tokens.padX,
|
|
42
|
+
tokens.padY,
|
|
43
|
+
tokens.text,
|
|
44
|
+
hasErrors
|
|
45
|
+
? 'border-danger-300 focus-within:border-danger-500 focus-within:ring-danger-500'
|
|
46
|
+
: 'border-default-300 focus-within:border-primary-500 focus-within:ring-primary-500',
|
|
47
|
+
disabled && 'opacity-50 cursor-not-allowed',
|
|
48
|
+
autoGrow ? 'resize-none overflow-hidden' : 'resize-y',
|
|
49
|
+
className
|
|
50
|
+
)
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* When autoGrow is on, measure scrollHeight and clamp to maxRows.
|
|
55
|
+
* Runs after value changes so the textarea expands/shrinks with content.
|
|
56
|
+
*/
|
|
57
|
+
function resize() {
|
|
58
|
+
if (!autoGrow || !el) return;
|
|
59
|
+
el.style.height = 'auto';
|
|
60
|
+
const lineHeight = parseFloat(getComputedStyle(el).lineHeight || '20');
|
|
61
|
+
const padding =
|
|
62
|
+
parseFloat(getComputedStyle(el).paddingTop) + parseFloat(getComputedStyle(el).paddingBottom);
|
|
63
|
+
const maxHeight = lineHeight * maxRows + padding;
|
|
64
|
+
el.style.height = `${Math.min(el.scrollHeight, maxHeight)}px`;
|
|
65
|
+
el.style.overflowY = el.scrollHeight > maxHeight ? 'auto' : 'hidden';
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
$effect(() => {
|
|
69
|
+
void value;
|
|
70
|
+
resize();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
function handleInput(e: Event) {
|
|
74
|
+
const v = (e.currentTarget as HTMLTextAreaElement).value;
|
|
75
|
+
value = v;
|
|
76
|
+
oninput?.(v);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function handleBlur(e: FocusEvent) {
|
|
80
|
+
onblur?.((e.currentTarget as HTMLTextAreaElement).value);
|
|
81
|
+
}
|
|
82
|
+
</script>
|
|
83
|
+
|
|
84
|
+
<div class="w-full" data-testid={buildTestId('textarea', 'wrapper', testId)}>
|
|
85
|
+
{#if label}
|
|
86
|
+
<label for={id} class="text-default-700 mb-1 block text-sm font-medium">
|
|
87
|
+
{label}
|
|
88
|
+
</label>
|
|
89
|
+
{/if}
|
|
90
|
+
<textarea
|
|
91
|
+
bind:this={el}
|
|
92
|
+
{id}
|
|
93
|
+
{name}
|
|
94
|
+
{placeholder}
|
|
95
|
+
{disabled}
|
|
96
|
+
{readonly}
|
|
97
|
+
{rows}
|
|
98
|
+
maxlength={maxLength}
|
|
99
|
+
class={textareaClasses}
|
|
100
|
+
aria-invalid={hasErrors}
|
|
101
|
+
aria-describedby={hasErrors ? `${name}-error` : undefined}
|
|
102
|
+
data-testid={buildTestId('textarea', undefined, testId)}
|
|
103
|
+
{value}
|
|
104
|
+
oninput={handleInput}
|
|
105
|
+
onblur={handleBlur}
|
|
106
|
+
></textarea>
|
|
107
|
+
|
|
108
|
+
{#if showCount && maxLength !== undefined}
|
|
109
|
+
<div class="text-default-400 mt-1 text-right text-xs">
|
|
110
|
+
{value?.length ?? 0} / {maxLength}
|
|
111
|
+
</div>
|
|
112
|
+
{/if}
|
|
113
|
+
|
|
114
|
+
{#if hasErrors}
|
|
115
|
+
<ul id="{name}-error" class="mt-1 space-y-0.5" role="alert">
|
|
116
|
+
{#each errors as error (error)}
|
|
117
|
+
<li class="text-danger-600 text-xs">{error}</li>
|
|
118
|
+
{/each}
|
|
119
|
+
</ul>
|
|
120
|
+
{/if}
|
|
121
|
+
</div>
|
package/dist/forms/Toggle.svelte
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { cn } from '../helper/cls.js';
|
|
3
3
|
import { Color, Size } from '../variants.js';
|
|
4
4
|
import { buildTestId } from '../helper/testid.js';
|
|
5
|
+
import { formSizeTokens } from './form-size.js';
|
|
5
6
|
import type { ToggleProps, VariantColors, VariantSizes } from '../index.js';
|
|
6
7
|
|
|
7
8
|
let {
|
|
@@ -10,18 +11,18 @@
|
|
|
10
11
|
label,
|
|
11
12
|
disabled = false,
|
|
12
13
|
class: className = '',
|
|
13
|
-
size = Size.
|
|
14
|
+
size = Size.MD,
|
|
14
15
|
color = Color.PRIMARY,
|
|
15
16
|
value = $bindable(false),
|
|
16
17
|
errors = [],
|
|
17
18
|
offColor = 'bg-default-200',
|
|
18
|
-
|
|
19
|
+
activeColor,
|
|
19
20
|
testId,
|
|
20
21
|
...restProps
|
|
21
22
|
}: ToggleProps = $props();
|
|
22
23
|
|
|
23
|
-
const
|
|
24
|
-
|
|
24
|
+
const resolvedActiveColor = $derived(
|
|
25
|
+
activeColor ||
|
|
25
26
|
(
|
|
26
27
|
{
|
|
27
28
|
[Color.DEFAULT]: 'bg-default-800',
|
|
@@ -35,13 +36,19 @@
|
|
|
35
36
|
)[color]
|
|
36
37
|
);
|
|
37
38
|
|
|
39
|
+
const tokens = $derived(formSizeTokens[size]);
|
|
40
|
+
|
|
41
|
+
// Track + thumb + on-state offset ladder. Chosen to roughly match the
|
|
42
|
+
// height of an Input at the same `size` (20/24/28/36/44px) so a row
|
|
43
|
+
// with a Toggle and an Input reads evenly. 2xl aliases xl — form
|
|
44
|
+
// controls cap at xl.
|
|
38
45
|
const toggleSize = $derived(
|
|
39
46
|
(
|
|
40
47
|
{
|
|
41
|
-
[Size.XS]: 'w-
|
|
42
|
-
[Size.SM]: 'w-
|
|
43
|
-
[Size.
|
|
44
|
-
[Size.LG]: 'w-
|
|
48
|
+
[Size.XS]: 'w-6 h-3',
|
|
49
|
+
[Size.SM]: 'w-7 h-3.5',
|
|
50
|
+
[Size.MD]: 'w-8 h-4',
|
|
51
|
+
[Size.LG]: 'w-10 h-5',
|
|
45
52
|
[Size.XL]: 'w-12 h-6',
|
|
46
53
|
[Size.XXL]: 'w-12 h-6'
|
|
47
54
|
} satisfies Record<VariantSizes, string>
|
|
@@ -51,10 +58,10 @@
|
|
|
51
58
|
const thumbSize = $derived(
|
|
52
59
|
(
|
|
53
60
|
{
|
|
54
|
-
[Size.XS]: 'h-
|
|
55
|
-
[Size.SM]: 'h-
|
|
56
|
-
[Size.
|
|
57
|
-
[Size.LG]: 'h-
|
|
61
|
+
[Size.XS]: 'h-2 w-2',
|
|
62
|
+
[Size.SM]: 'h-2.5 w-2.5',
|
|
63
|
+
[Size.MD]: 'h-3 w-3',
|
|
64
|
+
[Size.LG]: 'h-4 w-4',
|
|
58
65
|
[Size.XL]: 'h-5 w-5',
|
|
59
66
|
[Size.XXL]: 'h-5 w-5'
|
|
60
67
|
} satisfies Record<VariantSizes, string>
|
|
@@ -64,10 +71,10 @@
|
|
|
64
71
|
const thumbPosition = $derived(
|
|
65
72
|
(
|
|
66
73
|
{
|
|
67
|
-
[Size.XS]: value ? 'translate-x-
|
|
68
|
-
[Size.SM]: value ? 'translate-x-
|
|
69
|
-
[Size.
|
|
70
|
-
[Size.LG]: value ? 'translate-x-
|
|
74
|
+
[Size.XS]: value ? 'translate-x-3' : 'translate-x-0.5',
|
|
75
|
+
[Size.SM]: value ? 'translate-x-3.5' : 'translate-x-0.5',
|
|
76
|
+
[Size.MD]: value ? 'translate-x-4' : 'translate-x-0.5',
|
|
77
|
+
[Size.LG]: value ? 'translate-x-5' : 'translate-x-0.5',
|
|
71
78
|
[Size.XL]: value ? 'translate-x-6' : 'translate-x-0.5',
|
|
72
79
|
[Size.XXL]: value ? 'translate-x-6' : 'translate-x-0.5'
|
|
73
80
|
} satisfies Record<VariantSizes, string>
|
|
@@ -92,7 +99,7 @@
|
|
|
92
99
|
cn(
|
|
93
100
|
'relative inline-flex items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2',
|
|
94
101
|
toggleSize,
|
|
95
|
-
value ?
|
|
102
|
+
value ? resolvedActiveColor : offColor,
|
|
96
103
|
{
|
|
97
104
|
'opacity-50 cursor-not-allowed': disabled,
|
|
98
105
|
'cursor-pointer': !disabled,
|
|
@@ -112,11 +119,12 @@
|
|
|
112
119
|
);
|
|
113
120
|
|
|
114
121
|
const labelClasses = $derived(
|
|
115
|
-
cn(
|
|
116
|
-
'
|
|
117
|
-
|
|
118
|
-
'
|
|
119
|
-
|
|
122
|
+
cn(
|
|
123
|
+
'font-medium',
|
|
124
|
+
tokens.text,
|
|
125
|
+
errors.length ? 'text-danger-600' : 'text-default-700',
|
|
126
|
+
disabled && 'opacity-50'
|
|
127
|
+
)
|
|
120
128
|
);
|
|
121
129
|
|
|
122
130
|
function handleKeyDown(event: KeyboardEvent) {
|