@makolabs/ripple 2.5.8 → 3.0.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/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 +247 -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 -3
- package/dist/elements/dropdown/select.js +2 -2
- 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 +234 -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/DateRange.svelte +4 -2
- package/dist/forms/Input.svelte +2 -2
- package/dist/forms/MarketSelector.svelte +8 -3
- package/dist/forms/NumberInput.svelte +4 -4
- package/dist/forms/RadioGroup.svelte +123 -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 +14 -5
- package/dist/forms/Textarea.svelte +126 -0
- package/dist/forms/Textarea.svelte.d.ts +4 -0
- package/dist/forms/Toggle.svelte +8 -8
- package/dist/forms/calendar/Calendar.svelte +218 -0
- package/dist/forms/calendar/Calendar.svelte.d.ts +4 -0
- package/dist/forms/calendar/calendar-types.d.ts +46 -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 +144 -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-types.d.ts +425 -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 +16 -5
- package/dist/forms/slider.d.ts +3 -3
- package/dist/forms/slider.js +2 -2
- package/dist/funcs/user-management.remote.d.ts +1 -1
- package/dist/funcs/user-management.remote.js +2 -2
- 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/Toggle.svelte
CHANGED
|
@@ -10,18 +10,18 @@
|
|
|
10
10
|
label,
|
|
11
11
|
disabled = false,
|
|
12
12
|
class: className = '',
|
|
13
|
-
size = Size.
|
|
13
|
+
size = Size.MD,
|
|
14
14
|
color = Color.PRIMARY,
|
|
15
15
|
value = $bindable(false),
|
|
16
16
|
errors = [],
|
|
17
17
|
offColor = 'bg-default-200',
|
|
18
|
-
|
|
18
|
+
activeColor,
|
|
19
19
|
testId,
|
|
20
20
|
...restProps
|
|
21
21
|
}: ToggleProps = $props();
|
|
22
22
|
|
|
23
|
-
const
|
|
24
|
-
|
|
23
|
+
const resolvedActiveColor = $derived(
|
|
24
|
+
activeColor ||
|
|
25
25
|
(
|
|
26
26
|
{
|
|
27
27
|
[Color.DEFAULT]: 'bg-default-800',
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
{
|
|
41
41
|
[Size.XS]: 'w-8 h-4',
|
|
42
42
|
[Size.SM]: 'w-8 h-4',
|
|
43
|
-
[Size.
|
|
43
|
+
[Size.MD]: 'w-10 h-5',
|
|
44
44
|
[Size.LG]: 'w-12 h-6',
|
|
45
45
|
[Size.XL]: 'w-12 h-6',
|
|
46
46
|
[Size.XXL]: 'w-12 h-6'
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
{
|
|
54
54
|
[Size.XS]: 'h-3 w-3',
|
|
55
55
|
[Size.SM]: 'h-3 w-3',
|
|
56
|
-
[Size.
|
|
56
|
+
[Size.MD]: 'h-4 w-4',
|
|
57
57
|
[Size.LG]: 'h-5 w-5',
|
|
58
58
|
[Size.XL]: 'h-5 w-5',
|
|
59
59
|
[Size.XXL]: 'h-5 w-5'
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
{
|
|
67
67
|
[Size.XS]: value ? 'translate-x-4' : 'translate-x-0.5',
|
|
68
68
|
[Size.SM]: value ? 'translate-x-4' : 'translate-x-0.5',
|
|
69
|
-
[Size.
|
|
69
|
+
[Size.MD]: value ? 'translate-x-5' : 'translate-x-0.5',
|
|
70
70
|
[Size.LG]: value ? 'translate-x-6' : 'translate-x-0.5',
|
|
71
71
|
[Size.XL]: value ? 'translate-x-6' : 'translate-x-0.5',
|
|
72
72
|
[Size.XXL]: value ? 'translate-x-6' : 'translate-x-0.5'
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
cn(
|
|
93
93
|
'relative inline-flex items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2',
|
|
94
94
|
toggleSize,
|
|
95
|
-
value ?
|
|
95
|
+
value ? resolvedActiveColor : offColor,
|
|
96
96
|
{
|
|
97
97
|
'opacity-50 cursor-not-allowed': disabled,
|
|
98
98
|
'cursor-pointer': !disabled,
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn } from '../../helper/cls.js';
|
|
3
|
+
import { buildTestId } from '../../helper/testid.js';
|
|
4
|
+
import type { CalendarProps } from './calendar-types.js';
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
mode = 'single',
|
|
8
|
+
value = $bindable<Date | null>(null),
|
|
9
|
+
valueStart = $bindable<Date | null>(null),
|
|
10
|
+
valueEnd = $bindable<Date | null>(null),
|
|
11
|
+
minDate,
|
|
12
|
+
maxDate,
|
|
13
|
+
initialMonth,
|
|
14
|
+
weekStartsOn = 1,
|
|
15
|
+
hideHeader = false,
|
|
16
|
+
disabled = false,
|
|
17
|
+
class: className = '',
|
|
18
|
+
onselect,
|
|
19
|
+
testId
|
|
20
|
+
}: CalendarProps = $props();
|
|
21
|
+
|
|
22
|
+
const anchor = $derived(initialMonth ?? value ?? valueStart ?? new Date());
|
|
23
|
+
|
|
24
|
+
let viewYear = $state(anchor.getFullYear());
|
|
25
|
+
let viewMonth = $state(anchor.getMonth());
|
|
26
|
+
|
|
27
|
+
function sameDay(a: Date | null | undefined, b: Date | null | undefined): boolean {
|
|
28
|
+
if (!a || !b) return false;
|
|
29
|
+
return (
|
|
30
|
+
a.getFullYear() === b.getFullYear() &&
|
|
31
|
+
a.getMonth() === b.getMonth() &&
|
|
32
|
+
a.getDate() === b.getDate()
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function atStartOfDay(d: Date): Date {
|
|
37
|
+
// Pure function over plain Date — no reactivity needed.
|
|
38
|
+
// eslint-disable-next-line svelte/prefer-svelte-reactivity
|
|
39
|
+
const x = new Date(d);
|
|
40
|
+
x.setHours(0, 0, 0, 0);
|
|
41
|
+
return x;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function isOutOfBounds(date: Date): boolean {
|
|
45
|
+
if (minDate && date < atStartOfDay(minDate)) return true;
|
|
46
|
+
if (maxDate && date > atStartOfDay(maxDate)) return true;
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function isInRange(date: Date): boolean {
|
|
51
|
+
if (mode !== 'range' || !valueStart) return false;
|
|
52
|
+
if (!valueEnd) return sameDay(date, valueStart);
|
|
53
|
+
return date >= atStartOfDay(valueStart) && date <= atStartOfDay(valueEnd);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function isRangeEdge(date: Date): boolean {
|
|
57
|
+
if (mode !== 'range') return false;
|
|
58
|
+
return sameDay(date, valueStart) || sameDay(date, valueEnd);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const today = $derived(atStartOfDay(new Date()));
|
|
62
|
+
|
|
63
|
+
const dayHeaders = $derived(() => {
|
|
64
|
+
const all = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
|
65
|
+
return weekStartsOn === 1 ? [...all.slice(1), all[0]] : all;
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
type Cell = {
|
|
69
|
+
date: Date;
|
|
70
|
+
inMonth: boolean;
|
|
71
|
+
disabled: boolean;
|
|
72
|
+
isToday: boolean;
|
|
73
|
+
isSelected: boolean;
|
|
74
|
+
isRangeEdge: boolean;
|
|
75
|
+
isInRange: boolean;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const cells = $derived.by<Cell[]>(() => {
|
|
79
|
+
const first = new Date(viewYear, viewMonth, 1);
|
|
80
|
+
const offset = (first.getDay() - weekStartsOn + 7) % 7;
|
|
81
|
+
const start = new Date(viewYear, viewMonth, 1 - offset);
|
|
82
|
+
const out: Cell[] = [];
|
|
83
|
+
for (let i = 0; i < 42; i++) {
|
|
84
|
+
const d = new Date(start.getFullYear(), start.getMonth(), start.getDate() + i);
|
|
85
|
+
out.push({
|
|
86
|
+
date: d,
|
|
87
|
+
inMonth: d.getMonth() === viewMonth,
|
|
88
|
+
disabled: disabled || isOutOfBounds(d),
|
|
89
|
+
isToday: sameDay(d, today),
|
|
90
|
+
isSelected: mode === 'single' ? sameDay(d, value ?? undefined) : isRangeEdge(d),
|
|
91
|
+
isRangeEdge: isRangeEdge(d),
|
|
92
|
+
isInRange: isInRange(d)
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
return out;
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const monthLabel = $derived(
|
|
99
|
+
new Date(viewYear, viewMonth, 1).toLocaleDateString(undefined, {
|
|
100
|
+
month: 'long',
|
|
101
|
+
year: 'numeric'
|
|
102
|
+
})
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
function prevMonth() {
|
|
106
|
+
if (viewMonth === 0) {
|
|
107
|
+
viewMonth = 11;
|
|
108
|
+
viewYear -= 1;
|
|
109
|
+
} else {
|
|
110
|
+
viewMonth -= 1;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function nextMonth() {
|
|
115
|
+
if (viewMonth === 11) {
|
|
116
|
+
viewMonth = 0;
|
|
117
|
+
viewYear += 1;
|
|
118
|
+
} else {
|
|
119
|
+
viewMonth += 1;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function pick(date: Date, cellDisabled: boolean) {
|
|
124
|
+
if (cellDisabled) return;
|
|
125
|
+
if (mode === 'single') {
|
|
126
|
+
value = date;
|
|
127
|
+
onselect?.(date);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
// range
|
|
131
|
+
if (!valueStart || (valueStart && valueEnd)) {
|
|
132
|
+
valueStart = date;
|
|
133
|
+
valueEnd = null;
|
|
134
|
+
onselect?.({ from: date, to: null });
|
|
135
|
+
} else {
|
|
136
|
+
if (date < valueStart) {
|
|
137
|
+
valueEnd = valueStart;
|
|
138
|
+
valueStart = date;
|
|
139
|
+
} else {
|
|
140
|
+
valueEnd = date;
|
|
141
|
+
}
|
|
142
|
+
onselect?.({ from: valueStart, to: valueEnd });
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
</script>
|
|
146
|
+
|
|
147
|
+
<div
|
|
148
|
+
class={cn(
|
|
149
|
+
'border-default-200 inline-block w-64 rounded-lg border bg-white p-3 shadow-xs select-none',
|
|
150
|
+
className
|
|
151
|
+
)}
|
|
152
|
+
data-testid={buildTestId('calendar', undefined, testId)}
|
|
153
|
+
>
|
|
154
|
+
{#if !hideHeader}
|
|
155
|
+
<div class="mb-2 flex items-center justify-between">
|
|
156
|
+
<button
|
|
157
|
+
type="button"
|
|
158
|
+
onclick={prevMonth}
|
|
159
|
+
class="text-default-500 hover:bg-default-100 hover:text-default-800 flex size-7 cursor-pointer items-center justify-center rounded"
|
|
160
|
+
aria-label="Previous month"
|
|
161
|
+
{disabled}
|
|
162
|
+
>
|
|
163
|
+
<svg class="size-4" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
164
|
+
<path
|
|
165
|
+
fill-rule="evenodd"
|
|
166
|
+
d="M12.78 5.22a.75.75 0 0 1 0 1.06L9.06 10l3.72 3.72a.75.75 0 1 1-1.06 1.06l-4.25-4.25a.75.75 0 0 1 0-1.06l4.25-4.25a.75.75 0 0 1 1.06 0z"
|
|
167
|
+
clip-rule="evenodd"
|
|
168
|
+
/>
|
|
169
|
+
</svg>
|
|
170
|
+
</button>
|
|
171
|
+
<span class="text-default-800 text-sm font-semibold">{monthLabel}</span>
|
|
172
|
+
<button
|
|
173
|
+
type="button"
|
|
174
|
+
onclick={nextMonth}
|
|
175
|
+
class="text-default-500 hover:bg-default-100 hover:text-default-800 flex size-7 cursor-pointer items-center justify-center rounded"
|
|
176
|
+
aria-label="Next month"
|
|
177
|
+
{disabled}
|
|
178
|
+
>
|
|
179
|
+
<svg class="size-4" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
180
|
+
<path
|
|
181
|
+
fill-rule="evenodd"
|
|
182
|
+
d="M7.22 14.78a.75.75 0 0 1 0-1.06L10.94 10 7.22 6.28a.75.75 0 0 1 1.06-1.06l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 0 1-1.06 0z"
|
|
183
|
+
clip-rule="evenodd"
|
|
184
|
+
/>
|
|
185
|
+
</svg>
|
|
186
|
+
</button>
|
|
187
|
+
</div>
|
|
188
|
+
{/if}
|
|
189
|
+
|
|
190
|
+
<div class="text-default-400 mb-1 grid grid-cols-7 gap-0.5 text-center text-[10px] font-medium">
|
|
191
|
+
{#each dayHeaders() as d (d)}
|
|
192
|
+
<div>{d}</div>
|
|
193
|
+
{/each}
|
|
194
|
+
</div>
|
|
195
|
+
|
|
196
|
+
<div class="grid grid-cols-7 gap-0.5" role="grid">
|
|
197
|
+
{#each cells as cell (cell.date.toISOString())}
|
|
198
|
+
<button
|
|
199
|
+
type="button"
|
|
200
|
+
onclick={() => pick(cell.date, cell.disabled)}
|
|
201
|
+
disabled={cell.disabled}
|
|
202
|
+
aria-pressed={cell.isSelected}
|
|
203
|
+
aria-label={cell.date.toLocaleDateString()}
|
|
204
|
+
class={cn(
|
|
205
|
+
'relative flex size-8 items-center justify-center rounded text-xs transition-colors',
|
|
206
|
+
!cell.inMonth && 'text-default-300',
|
|
207
|
+
cell.inMonth && !cell.disabled && 'text-default-700 hover:bg-default-100 cursor-pointer',
|
|
208
|
+
cell.disabled && 'text-default-200 cursor-not-allowed',
|
|
209
|
+
cell.isToday && !cell.isSelected && 'ring-default-300 font-semibold ring-1',
|
|
210
|
+
cell.isInRange && !cell.isRangeEdge && 'bg-primary-50 text-primary-700 rounded-none',
|
|
211
|
+
cell.isSelected && 'bg-primary-500 hover:bg-primary-600 text-white'
|
|
212
|
+
)}
|
|
213
|
+
>
|
|
214
|
+
{cell.date.getDate()}
|
|
215
|
+
</button>
|
|
216
|
+
{/each}
|
|
217
|
+
</div>
|
|
218
|
+
</div>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { ClassValue } from 'tailwind-variants';
|
|
2
|
+
/**
|
|
3
|
+
* Calendar selection mode.
|
|
4
|
+
* - `'single'`: one date. Bind to `value`.
|
|
5
|
+
* - `'range'`: two dates. Bind to `valueStart` and `valueEnd`.
|
|
6
|
+
*/
|
|
7
|
+
export type CalendarMode = 'single' | 'range';
|
|
8
|
+
export type CalendarProps = {
|
|
9
|
+
/** Selection mode. @default 'single' */
|
|
10
|
+
mode?: CalendarMode;
|
|
11
|
+
/** Selected date (single mode). Bindable. */
|
|
12
|
+
value?: Date | null;
|
|
13
|
+
/** Range start (range mode). Bindable. */
|
|
14
|
+
valueStart?: Date | null;
|
|
15
|
+
/** Range end (range mode). Bindable. */
|
|
16
|
+
valueEnd?: Date | null;
|
|
17
|
+
/** Earliest selectable date (inclusive). */
|
|
18
|
+
minDate?: Date;
|
|
19
|
+
/** Latest selectable date (inclusive). */
|
|
20
|
+
maxDate?: Date;
|
|
21
|
+
/**
|
|
22
|
+
* Which month to display initially. Defaults to the month of the current
|
|
23
|
+
* selection, or today if nothing is selected.
|
|
24
|
+
*/
|
|
25
|
+
initialMonth?: Date;
|
|
26
|
+
/**
|
|
27
|
+
* Day the week starts on. `0` = Sunday, `1` = Monday. @default 1
|
|
28
|
+
*/
|
|
29
|
+
weekStartsOn?: 0 | 1;
|
|
30
|
+
/** Hide the month/year header and navigation buttons. @default false */
|
|
31
|
+
hideHeader?: boolean;
|
|
32
|
+
/** Disable all interaction. */
|
|
33
|
+
disabled?: boolean;
|
|
34
|
+
/** Wrapper class. */
|
|
35
|
+
class?: ClassValue;
|
|
36
|
+
/**
|
|
37
|
+
* Fires when the user picks a date. For single mode receives one Date;
|
|
38
|
+
* for range mode receives `{ from, to }` — `to` is `null` until the
|
|
39
|
+
* second click completes the range.
|
|
40
|
+
*/
|
|
41
|
+
onselect?: (selection: Date | {
|
|
42
|
+
from: Date | null;
|
|
43
|
+
to: Date | null;
|
|
44
|
+
}) => void;
|
|
45
|
+
testId?: string;
|
|
46
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Calendar } from './Calendar.svelte';
|
|
@@ -0,0 +1,144 @@
|
|
|
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 Popover from '../../elements/popover/Popover.svelte';
|
|
6
|
+
import Calendar from '../calendar/Calendar.svelte';
|
|
7
|
+
import type { DatePickerProps } from './date-picker-types.js';
|
|
8
|
+
|
|
9
|
+
let {
|
|
10
|
+
name,
|
|
11
|
+
id = name,
|
|
12
|
+
label,
|
|
13
|
+
placeholder = 'Select date',
|
|
14
|
+
value = $bindable<Date | null>(null),
|
|
15
|
+
minDate,
|
|
16
|
+
maxDate,
|
|
17
|
+
format = 'yyyy-MM-dd',
|
|
18
|
+
clearable = true,
|
|
19
|
+
disabled = false,
|
|
20
|
+
readonly = false,
|
|
21
|
+
required = false,
|
|
22
|
+
size = Size.MD,
|
|
23
|
+
errors = [],
|
|
24
|
+
class: className = '',
|
|
25
|
+
onchange,
|
|
26
|
+
testId
|
|
27
|
+
}: DatePickerProps = $props();
|
|
28
|
+
|
|
29
|
+
let open = $state(false);
|
|
30
|
+
|
|
31
|
+
function formatDate(d: Date): string {
|
|
32
|
+
const yyyy = String(d.getFullYear());
|
|
33
|
+
const MM = String(d.getMonth() + 1).padStart(2, '0');
|
|
34
|
+
const dd = String(d.getDate()).padStart(2, '0');
|
|
35
|
+
return format.replace('yyyy', yyyy).replace('MM', MM).replace('dd', dd);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const display = $derived(value ? formatDate(value) : '');
|
|
39
|
+
const hasErrors = $derived(errors.length > 0);
|
|
40
|
+
|
|
41
|
+
const sizeClass = $derived(
|
|
42
|
+
{
|
|
43
|
+
[Size.XS]: 'h-7 text-xs',
|
|
44
|
+
[Size.SM]: 'h-8 text-sm',
|
|
45
|
+
[Size.MD]: 'h-10 text-sm',
|
|
46
|
+
[Size.LG]: 'h-12 text-base',
|
|
47
|
+
[Size.XL]: 'h-14 text-lg',
|
|
48
|
+
[Size.XXL]: 'h-16 text-lg'
|
|
49
|
+
}[size]
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
function clear(e: MouseEvent) {
|
|
53
|
+
e.stopPropagation();
|
|
54
|
+
value = null;
|
|
55
|
+
onchange?.(null);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function handleSelect(date: Date) {
|
|
59
|
+
value = date;
|
|
60
|
+
open = false;
|
|
61
|
+
onchange?.(date);
|
|
62
|
+
}
|
|
63
|
+
</script>
|
|
64
|
+
|
|
65
|
+
<div class={cn('w-full', className)} data-testid={buildTestId('date-picker', 'wrapper', testId)}>
|
|
66
|
+
{#if label}
|
|
67
|
+
<label for={id} class="text-default-700 mb-1 block text-sm font-medium">
|
|
68
|
+
{label}
|
|
69
|
+
{#if required}<span class="text-danger-500" aria-hidden="true">*</span>{/if}
|
|
70
|
+
</label>
|
|
71
|
+
{/if}
|
|
72
|
+
|
|
73
|
+
<!-- Hidden input carries the ISO value for native form posts. -->
|
|
74
|
+
<input type="hidden" {name} value={value ? value.toISOString() : ''} {required} />
|
|
75
|
+
|
|
76
|
+
<Popover trigger="manual" bind:open placement="bottom" {disabled}>
|
|
77
|
+
<button
|
|
78
|
+
{id}
|
|
79
|
+
type="button"
|
|
80
|
+
{disabled}
|
|
81
|
+
onclick={() => (open = !open)}
|
|
82
|
+
aria-haspopup="dialog"
|
|
83
|
+
aria-expanded={open}
|
|
84
|
+
aria-invalid={hasErrors}
|
|
85
|
+
class={cn(
|
|
86
|
+
'flex w-full items-center justify-between gap-2 rounded-lg border bg-white px-3 transition-colors',
|
|
87
|
+
'focus-within:ring-2 focus-within:ring-offset-2 focus-within:outline-none',
|
|
88
|
+
sizeClass,
|
|
89
|
+
hasErrors
|
|
90
|
+
? 'border-danger-300 focus-within:border-danger-500 focus-within:ring-danger-500'
|
|
91
|
+
: 'border-default-300 focus-within:border-primary-500 focus-within:ring-primary-500',
|
|
92
|
+
disabled && 'cursor-not-allowed opacity-50',
|
|
93
|
+
!disabled && 'cursor-pointer'
|
|
94
|
+
)}
|
|
95
|
+
data-testid={buildTestId('date-picker', undefined, testId)}
|
|
96
|
+
>
|
|
97
|
+
<span class={cn('flex-1 text-left', !display && 'text-default-400')}>
|
|
98
|
+
{display || placeholder}
|
|
99
|
+
</span>
|
|
100
|
+
{#if clearable && value && !disabled && !readonly}
|
|
101
|
+
<button
|
|
102
|
+
type="button"
|
|
103
|
+
onclick={clear}
|
|
104
|
+
aria-label="Clear date"
|
|
105
|
+
class="text-default-400 hover:text-default-700 flex size-5 items-center justify-center rounded"
|
|
106
|
+
>
|
|
107
|
+
<svg class="size-3" viewBox="0 0 12 12" fill="none" aria-hidden="true">
|
|
108
|
+
<path
|
|
109
|
+
d="M3 3l6 6M9 3l-6 6"
|
|
110
|
+
stroke="currentColor"
|
|
111
|
+
stroke-width="1.5"
|
|
112
|
+
stroke-linecap="round"
|
|
113
|
+
/>
|
|
114
|
+
</svg>
|
|
115
|
+
</button>
|
|
116
|
+
{:else}
|
|
117
|
+
<svg
|
|
118
|
+
class="text-default-400 size-4"
|
|
119
|
+
viewBox="0 0 20 20"
|
|
120
|
+
fill="currentColor"
|
|
121
|
+
aria-hidden="true"
|
|
122
|
+
>
|
|
123
|
+
<path
|
|
124
|
+
fill-rule="evenodd"
|
|
125
|
+
d="M5.75 2a.75.75 0 0 1 .75.75V4h7V2.75a.75.75 0 0 1 1.5 0V4h.25A2.75 2.75 0 0 1 18 6.75v8.5A2.75 2.75 0 0 1 15.25 18H4.75A2.75 2.75 0 0 1 2 15.25v-8.5A2.75 2.75 0 0 1 4.75 4H5V2.75A.75.75 0 0 1 5.75 2zM4.75 5.5c-.69 0-1.25.56-1.25 1.25V8h13V6.75c0-.69-.56-1.25-1.25-1.25H4.75zM16.5 9.5h-13v5.75c0 .69.56 1.25 1.25 1.25h10.5c.69 0 1.25-.56 1.25-1.25V9.5z"
|
|
126
|
+
clip-rule="evenodd"
|
|
127
|
+
/>
|
|
128
|
+
</svg>
|
|
129
|
+
{/if}
|
|
130
|
+
</button>
|
|
131
|
+
|
|
132
|
+
{#snippet content()}
|
|
133
|
+
<Calendar {value} {minDate} {maxDate} onselect={(d) => handleSelect(d as Date)} />
|
|
134
|
+
{/snippet}
|
|
135
|
+
</Popover>
|
|
136
|
+
|
|
137
|
+
{#if hasErrors}
|
|
138
|
+
<ul class="mt-1 space-y-0.5" role="alert">
|
|
139
|
+
{#each errors as error (error)}
|
|
140
|
+
<li class="text-danger-600 text-xs">{error}</li>
|
|
141
|
+
{/each}
|
|
142
|
+
</ul>
|
|
143
|
+
{/if}
|
|
144
|
+
</div>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ClassValue } from 'tailwind-variants';
|
|
2
|
+
import type { VariantSizes } from '../../index.js';
|
|
3
|
+
/** Very small subset of common date-format tokens supported by DatePicker. */
|
|
4
|
+
export type DateFormatToken = 'yyyy' | 'MM' | 'dd';
|
|
5
|
+
export type DatePickerProps = {
|
|
6
|
+
name: string;
|
|
7
|
+
id?: string;
|
|
8
|
+
label?: string;
|
|
9
|
+
placeholder?: string;
|
|
10
|
+
/** Bindable selected date. Null when cleared. */
|
|
11
|
+
value?: Date | null;
|
|
12
|
+
minDate?: Date;
|
|
13
|
+
maxDate?: Date;
|
|
14
|
+
/**
|
|
15
|
+
* Display format for the input. Supports `yyyy`, `MM`, `dd` tokens
|
|
16
|
+
* and any literal separator (`-`, `/`, `.`, etc.). @default 'yyyy-MM-dd'
|
|
17
|
+
*/
|
|
18
|
+
format?: string;
|
|
19
|
+
/** Allow clearing the selection with a × button. @default true */
|
|
20
|
+
clearable?: boolean;
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
readonly?: boolean;
|
|
23
|
+
required?: boolean;
|
|
24
|
+
size?: VariantSizes;
|
|
25
|
+
errors?: string[];
|
|
26
|
+
class?: ClassValue;
|
|
27
|
+
onchange?: (date: Date | null) => void;
|
|
28
|
+
testId?: string;
|
|
29
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|