svelte-comp 1.3.5 → 1.3.6
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/LICENSE.md +21 -21
- package/README.md +101 -101
- package/dist/App.svelte +1046 -1046
- package/dist/Container.svelte +59 -59
- package/dist/app.css +234 -234
- package/dist/app.d.ts +10 -10
- package/dist/lib/Accordion.svelte +155 -155
- package/dist/lib/Badge.svelte +44 -44
- package/dist/lib/Button.svelte +185 -185
- package/dist/lib/Calendar.svelte +384 -384
- package/dist/lib/Card.svelte +103 -103
- package/dist/lib/Carousel.svelte +293 -293
- package/dist/lib/CheckBox.svelte +210 -210
- package/dist/lib/CodeView.svelte +308 -308
- package/dist/lib/ColorPicker.svelte +159 -159
- package/dist/lib/ContextMenu.svelte +328 -328
- package/dist/lib/DatePicker.svelte +246 -246
- package/dist/lib/Dialog.svelte +233 -233
- package/dist/lib/Field.svelte +299 -299
- package/dist/lib/FilePicker.svelte +295 -295
- package/dist/lib/Form.svelte +438 -438
- package/dist/lib/Hamburger.svelte +217 -217
- package/dist/lib/InstallPWA.svelte +94 -94
- package/dist/lib/Menu.svelte +623 -623
- package/dist/lib/NoticeBase.svelte +140 -140
- package/dist/lib/PaginatedCard.svelte +73 -73
- package/dist/lib/Pagination.svelte +119 -119
- package/dist/lib/PrimaryColorSelect.svelte +111 -111
- package/dist/lib/ProgressBar.svelte +141 -141
- package/dist/lib/ProgressCircle.svelte +190 -190
- package/dist/lib/Radio.svelte +189 -189
- package/dist/lib/SearchInput.svelte +104 -104
- package/dist/lib/Select.svelte +524 -524
- package/dist/lib/Slider.svelte +253 -253
- package/dist/lib/Splitter.svelte +159 -159
- package/dist/lib/Switch.svelte +168 -168
- package/dist/lib/Table.svelte +299 -299
- package/dist/lib/Tabs.svelte +213 -213
- package/dist/lib/ThemeToggle.svelte +128 -128
- package/dist/lib/TimePicker.svelte +312 -312
- package/dist/lib/TimePickerNew.svelte +634 -634
- package/dist/lib/Toast.svelte +123 -123
- package/dist/lib/Tooltip.svelte +110 -110
- package/dist/lib/Topbar.svelte +112 -112
- package/dist/styles.css +234 -234
- package/package.json +52 -52
|
@@ -1,246 +1,246 @@
|
|
|
1
|
-
<!-- src/lib/DatePicker.svelte -->
|
|
2
|
-
<script lang="ts">
|
|
3
|
-
/**
|
|
4
|
-
* @component DatePicker
|
|
5
|
-
* @description Button-driven date selector that formats the chosen value and supports min/max limits.
|
|
6
|
-
*
|
|
7
|
-
* @prop value {string | null} - Selected date value (ISO `YYYY-MM-DD`)
|
|
8
|
-
* @default null
|
|
9
|
-
*
|
|
10
|
-
* @prop min {string} - Minimum selectable date (ISO `YYYY-MM-DD`)
|
|
11
|
-
*
|
|
12
|
-
* @prop max {string} - Maximum selectable date (ISO `YYYY-MM-DD`)
|
|
13
|
-
*
|
|
14
|
-
* @prop label {string} - Label text displayed above the picker
|
|
15
|
-
*
|
|
16
|
-
* @prop placeholder {string} - Placeholder shown when no date is selected
|
|
17
|
-
*
|
|
18
|
-
* @prop locale {string} - Locale used for formatting
|
|
19
|
-
*
|
|
20
|
-
* @prop formatOptions {Intl.DateTimeFormatOptions} - Custom date formatting options
|
|
21
|
-
*
|
|
22
|
-
* @prop disabled {boolean} - Disables all interactions
|
|
23
|
-
* @default false
|
|
24
|
-
*
|
|
25
|
-
* @prop clearable {boolean} - Shows a clear button to reset the value
|
|
26
|
-
* @default true
|
|
27
|
-
*
|
|
28
|
-
* @prop onChange {(value: string | null) => void} - Fired when the date changes
|
|
29
|
-
*
|
|
30
|
-
* @prop class {string} - Additional classes for the wrapper element
|
|
31
|
-
* @default ""
|
|
32
|
-
*
|
|
33
|
-
* @note Wraps a hidden `<input type="date">` so native date-pickers, keyboard, and validation work automatically.
|
|
34
|
-
* @note `showPicker()` is used when available for a consistent trigger; fallback is focus + click.
|
|
35
|
-
* @note Formatter uses `Intl.DateTimeFormat` (with `locale`/`formatOptions`) and gracefully falls back to `toLocaleDateString()`.
|
|
36
|
-
* @note `clearable` resets the underlying input value and dispatches `onChange(null)`.
|
|
37
|
-
* @note Preview card includes `aria-live="polite"` to announce updated dates.
|
|
38
|
-
*/
|
|
39
|
-
import type { HTMLAttributes } from "svelte/elements";
|
|
40
|
-
import Button from "./Button.svelte";
|
|
41
|
-
import Calendar from "./Calendar.svelte";
|
|
42
|
-
import { cx, formatDate, uid } from "../utils";
|
|
43
|
-
import { getComponentText, getLangContext, getLangKey } from "./lang-context";
|
|
44
|
-
|
|
45
|
-
type Props = HTMLAttributes<HTMLDivElement> & {
|
|
46
|
-
value?: string | null;
|
|
47
|
-
min?: string;
|
|
48
|
-
max?: string;
|
|
49
|
-
label?: string;
|
|
50
|
-
placeholder?: string;
|
|
51
|
-
locale?: string;
|
|
52
|
-
formatOptions?: Intl.DateTimeFormatOptions;
|
|
53
|
-
disabled?: boolean;
|
|
54
|
-
clearable?: boolean;
|
|
55
|
-
onChange?: (value: string | null) => void;
|
|
56
|
-
class?: string;
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
let {
|
|
60
|
-
value = $bindable<string | null>(null),
|
|
61
|
-
min = "1926-01-01",
|
|
62
|
-
max,
|
|
63
|
-
label,
|
|
64
|
-
placeholder,
|
|
65
|
-
locale,
|
|
66
|
-
formatOptions,
|
|
67
|
-
disabled = false,
|
|
68
|
-
clearable = true,
|
|
69
|
-
onChange,
|
|
70
|
-
class: externalClass = "",
|
|
71
|
-
...rest
|
|
72
|
-
}: Props = $props();
|
|
73
|
-
|
|
74
|
-
const langCtx = getLangContext();
|
|
75
|
-
const langKey = $derived(getLangKey(langCtx));
|
|
76
|
-
const L = $derived(getComponentText("datePicker", langKey));
|
|
77
|
-
|
|
78
|
-
const labelFinal = $derived(label ?? L.text);
|
|
79
|
-
const placeholderFinal = $derived(placeholder ?? L.placeholder);
|
|
80
|
-
|
|
81
|
-
const base = "inline-block w-full";
|
|
82
|
-
const pickerClass = $derived(cx(base, externalClass));
|
|
83
|
-
|
|
84
|
-
const hasValue = $derived(Boolean(value));
|
|
85
|
-
const formattedValue = $derived(formatDate(value, locale, formatOptions));
|
|
86
|
-
|
|
87
|
-
let open = $state(false);
|
|
88
|
-
const panelId = uid("calendar-");
|
|
89
|
-
const panelSize = 240;
|
|
90
|
-
|
|
91
|
-
let triggerEl = $state<HTMLDivElement | null>(null);
|
|
92
|
-
let panelEl = $state<HTMLDivElement | null>(null);
|
|
93
|
-
let panelTop = $state(0);
|
|
94
|
-
let panelLeft = $state(0);
|
|
95
|
-
|
|
96
|
-
const panelStyle = $derived(
|
|
97
|
-
`position:fixed; top:${panelTop}px; left:${panelLeft}px; width:${panelSize}px; height:${panelSize}px;`
|
|
98
|
-
);
|
|
99
|
-
|
|
100
|
-
function togglePanel() {
|
|
101
|
-
if (disabled) return;
|
|
102
|
-
open = !open;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function handleSelect(nextValue: string | null) {
|
|
106
|
-
value = nextValue;
|
|
107
|
-
onChange?.(nextValue);
|
|
108
|
-
open = false;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function clearSelection() {
|
|
112
|
-
if (!clearable) return;
|
|
113
|
-
value = null;
|
|
114
|
-
onChange?.(null);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
$effect(() => {
|
|
118
|
-
const currentTrigger = triggerEl;
|
|
119
|
-
const currentPanel = panelEl;
|
|
120
|
-
if (!open || !currentTrigger) return;
|
|
121
|
-
|
|
122
|
-
const updatePosition = () => {
|
|
123
|
-
const triggerRect = currentTrigger.getBoundingClientRect();
|
|
124
|
-
const panelHeight =
|
|
125
|
-
currentPanel?.getBoundingClientRect().height ?? 0;
|
|
126
|
-
const spaceBelow = window.innerHeight - triggerRect.bottom;
|
|
127
|
-
const spaceAbove = triggerRect.top;
|
|
128
|
-
const shouldFlip = spaceBelow < panelHeight && spaceAbove > spaceBelow;
|
|
129
|
-
|
|
130
|
-
panelTop = shouldFlip
|
|
131
|
-
? Math.max(0, triggerRect.top - panelHeight - 8)
|
|
132
|
-
: triggerRect.bottom + 8;
|
|
133
|
-
|
|
134
|
-
const viewportLeft = window.scrollX;
|
|
135
|
-
const viewportRight = window.scrollX + window.innerWidth;
|
|
136
|
-
const targetLeft = triggerRect.left + window.scrollX;
|
|
137
|
-
const maxLeft = viewportRight - panelSize;
|
|
138
|
-
panelLeft = Math.max(viewportLeft, Math.min(targetLeft, maxLeft));
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
const onKeyDown = (event: KeyboardEvent) => {
|
|
142
|
-
if (event.key === "Escape") {
|
|
143
|
-
event.preventDefault();
|
|
144
|
-
open = false;
|
|
145
|
-
}
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
const onClickOutside = (event: MouseEvent) => {
|
|
149
|
-
if (
|
|
150
|
-
currentTrigger &&
|
|
151
|
-
currentPanel &&
|
|
152
|
-
!currentTrigger.contains(event.target as Node) &&
|
|
153
|
-
!currentPanel.contains(event.target as Node)
|
|
154
|
-
) {
|
|
155
|
-
open = false;
|
|
156
|
-
}
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
queueMicrotask(updatePosition);
|
|
160
|
-
window.addEventListener("scroll", updatePosition, true);
|
|
161
|
-
window.addEventListener("resize", updatePosition);
|
|
162
|
-
window.addEventListener("keydown", onKeyDown);
|
|
163
|
-
document.addEventListener("mousedown", onClickOutside);
|
|
164
|
-
|
|
165
|
-
return () => {
|
|
166
|
-
window.removeEventListener("scroll", updatePosition, true);
|
|
167
|
-
window.removeEventListener("resize", updatePosition);
|
|
168
|
-
window.removeEventListener("keydown", onKeyDown);
|
|
169
|
-
document.removeEventListener("mousedown", onClickOutside);
|
|
170
|
-
};
|
|
171
|
-
});
|
|
172
|
-
</script>
|
|
173
|
-
|
|
174
|
-
<div class={pickerClass} {...rest}>
|
|
175
|
-
<div class="text-md font-medium mb-2 [color:var(--color-text-default)]">
|
|
176
|
-
{labelFinal}:
|
|
177
|
-
</div>
|
|
178
|
-
<div class="inline-flex flex-wrap items-center gap-x-3 gap-y-2">
|
|
179
|
-
<div bind:this={triggerEl}>
|
|
180
|
-
<Button
|
|
181
|
-
onClick={togglePanel}
|
|
182
|
-
{disabled}
|
|
183
|
-
sz="xs"
|
|
184
|
-
aria-expanded={open}
|
|
185
|
-
aria-controls={open ? panelId : undefined}
|
|
186
|
-
>
|
|
187
|
-
{L.date}
|
|
188
|
-
</Button>
|
|
189
|
-
</div>
|
|
190
|
-
|
|
191
|
-
{#if clearable}
|
|
192
|
-
<Button
|
|
193
|
-
onClick={clearSelection}
|
|
194
|
-
variant="danger"
|
|
195
|
-
disabled={!hasValue || disabled}
|
|
196
|
-
sz="xs"
|
|
197
|
-
>
|
|
198
|
-
{L.clear}
|
|
199
|
-
</Button>
|
|
200
|
-
{/if}
|
|
201
|
-
|
|
202
|
-
{#if open}
|
|
203
|
-
<div
|
|
204
|
-
role="presentation"
|
|
205
|
-
tabindex="-1"
|
|
206
|
-
class="fixed inset-0 z-[var(--z-overlay)]"
|
|
207
|
-
></div>
|
|
208
|
-
|
|
209
|
-
<div
|
|
210
|
-
bind:this={panelEl}
|
|
211
|
-
id={panelId}
|
|
212
|
-
role="dialog"
|
|
213
|
-
aria-label={labelFinal}
|
|
214
|
-
class="z-[var(--z-modal)] p-3 border border-[var(--border-color-default)] rounded-[var(--radius-md)] bg-[var(--color-bg-surface)] shadow-[0_2px_6px_var(--shadow-color)]"
|
|
215
|
-
style={panelStyle}
|
|
216
|
-
>
|
|
217
|
-
<Calendar
|
|
218
|
-
value={value}
|
|
219
|
-
{min}
|
|
220
|
-
{max}
|
|
221
|
-
{locale}
|
|
222
|
-
onChange={handleSelect}
|
|
223
|
-
showOutsideDays
|
|
224
|
-
class="w-full h-full"
|
|
225
|
-
/>
|
|
226
|
-
</div>
|
|
227
|
-
{/if}
|
|
228
|
-
</div>
|
|
229
|
-
|
|
230
|
-
<div
|
|
231
|
-
class="mt-3 p-4 bg-[var(--color-bg-surface)] text-center"
|
|
232
|
-
aria-live="polite"
|
|
233
|
-
>
|
|
234
|
-
<p class="text-xs uppercase tracking-wide [color:var(--color-text-muted)]">
|
|
235
|
-
{L.selectedDate}
|
|
236
|
-
</p>
|
|
237
|
-
|
|
238
|
-
<p class="text-sm font-semibold mt-1 [color:var(--color-text-default)]">
|
|
239
|
-
{#if hasValue}
|
|
240
|
-
{formattedValue}
|
|
241
|
-
{:else}
|
|
242
|
-
{placeholderFinal}
|
|
243
|
-
{/if}
|
|
244
|
-
</p>
|
|
245
|
-
</div>
|
|
246
|
-
</div>
|
|
1
|
+
<!-- src/lib/DatePicker.svelte -->
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
/**
|
|
4
|
+
* @component DatePicker
|
|
5
|
+
* @description Button-driven date selector that formats the chosen value and supports min/max limits.
|
|
6
|
+
*
|
|
7
|
+
* @prop value {string | null} - Selected date value (ISO `YYYY-MM-DD`)
|
|
8
|
+
* @default null
|
|
9
|
+
*
|
|
10
|
+
* @prop min {string} - Minimum selectable date (ISO `YYYY-MM-DD`)
|
|
11
|
+
*
|
|
12
|
+
* @prop max {string} - Maximum selectable date (ISO `YYYY-MM-DD`)
|
|
13
|
+
*
|
|
14
|
+
* @prop label {string} - Label text displayed above the picker
|
|
15
|
+
*
|
|
16
|
+
* @prop placeholder {string} - Placeholder shown when no date is selected
|
|
17
|
+
*
|
|
18
|
+
* @prop locale {string} - Locale used for formatting
|
|
19
|
+
*
|
|
20
|
+
* @prop formatOptions {Intl.DateTimeFormatOptions} - Custom date formatting options
|
|
21
|
+
*
|
|
22
|
+
* @prop disabled {boolean} - Disables all interactions
|
|
23
|
+
* @default false
|
|
24
|
+
*
|
|
25
|
+
* @prop clearable {boolean} - Shows a clear button to reset the value
|
|
26
|
+
* @default true
|
|
27
|
+
*
|
|
28
|
+
* @prop onChange {(value: string | null) => void} - Fired when the date changes
|
|
29
|
+
*
|
|
30
|
+
* @prop class {string} - Additional classes for the wrapper element
|
|
31
|
+
* @default ""
|
|
32
|
+
*
|
|
33
|
+
* @note Wraps a hidden `<input type="date">` so native date-pickers, keyboard, and validation work automatically.
|
|
34
|
+
* @note `showPicker()` is used when available for a consistent trigger; fallback is focus + click.
|
|
35
|
+
* @note Formatter uses `Intl.DateTimeFormat` (with `locale`/`formatOptions`) and gracefully falls back to `toLocaleDateString()`.
|
|
36
|
+
* @note `clearable` resets the underlying input value and dispatches `onChange(null)`.
|
|
37
|
+
* @note Preview card includes `aria-live="polite"` to announce updated dates.
|
|
38
|
+
*/
|
|
39
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
40
|
+
import Button from "./Button.svelte";
|
|
41
|
+
import Calendar from "./Calendar.svelte";
|
|
42
|
+
import { cx, formatDate, uid } from "../utils";
|
|
43
|
+
import { getComponentText, getLangContext, getLangKey } from "./lang-context";
|
|
44
|
+
|
|
45
|
+
type Props = HTMLAttributes<HTMLDivElement> & {
|
|
46
|
+
value?: string | null;
|
|
47
|
+
min?: string;
|
|
48
|
+
max?: string;
|
|
49
|
+
label?: string;
|
|
50
|
+
placeholder?: string;
|
|
51
|
+
locale?: string;
|
|
52
|
+
formatOptions?: Intl.DateTimeFormatOptions;
|
|
53
|
+
disabled?: boolean;
|
|
54
|
+
clearable?: boolean;
|
|
55
|
+
onChange?: (value: string | null) => void;
|
|
56
|
+
class?: string;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
let {
|
|
60
|
+
value = $bindable<string | null>(null),
|
|
61
|
+
min = "1926-01-01",
|
|
62
|
+
max,
|
|
63
|
+
label,
|
|
64
|
+
placeholder,
|
|
65
|
+
locale,
|
|
66
|
+
formatOptions,
|
|
67
|
+
disabled = false,
|
|
68
|
+
clearable = true,
|
|
69
|
+
onChange,
|
|
70
|
+
class: externalClass = "",
|
|
71
|
+
...rest
|
|
72
|
+
}: Props = $props();
|
|
73
|
+
|
|
74
|
+
const langCtx = getLangContext();
|
|
75
|
+
const langKey = $derived(getLangKey(langCtx));
|
|
76
|
+
const L = $derived(getComponentText("datePicker", langKey));
|
|
77
|
+
|
|
78
|
+
const labelFinal = $derived(label ?? L.text);
|
|
79
|
+
const placeholderFinal = $derived(placeholder ?? L.placeholder);
|
|
80
|
+
|
|
81
|
+
const base = "inline-block w-full";
|
|
82
|
+
const pickerClass = $derived(cx(base, externalClass));
|
|
83
|
+
|
|
84
|
+
const hasValue = $derived(Boolean(value));
|
|
85
|
+
const formattedValue = $derived(formatDate(value, locale, formatOptions));
|
|
86
|
+
|
|
87
|
+
let open = $state(false);
|
|
88
|
+
const panelId = uid("calendar-");
|
|
89
|
+
const panelSize = 240;
|
|
90
|
+
|
|
91
|
+
let triggerEl = $state<HTMLDivElement | null>(null);
|
|
92
|
+
let panelEl = $state<HTMLDivElement | null>(null);
|
|
93
|
+
let panelTop = $state(0);
|
|
94
|
+
let panelLeft = $state(0);
|
|
95
|
+
|
|
96
|
+
const panelStyle = $derived(
|
|
97
|
+
`position:fixed; top:${panelTop}px; left:${panelLeft}px; width:${panelSize}px; height:${panelSize}px;`
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
function togglePanel() {
|
|
101
|
+
if (disabled) return;
|
|
102
|
+
open = !open;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function handleSelect(nextValue: string | null) {
|
|
106
|
+
value = nextValue;
|
|
107
|
+
onChange?.(nextValue);
|
|
108
|
+
open = false;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function clearSelection() {
|
|
112
|
+
if (!clearable) return;
|
|
113
|
+
value = null;
|
|
114
|
+
onChange?.(null);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
$effect(() => {
|
|
118
|
+
const currentTrigger = triggerEl;
|
|
119
|
+
const currentPanel = panelEl;
|
|
120
|
+
if (!open || !currentTrigger) return;
|
|
121
|
+
|
|
122
|
+
const updatePosition = () => {
|
|
123
|
+
const triggerRect = currentTrigger.getBoundingClientRect();
|
|
124
|
+
const panelHeight =
|
|
125
|
+
currentPanel?.getBoundingClientRect().height ?? 0;
|
|
126
|
+
const spaceBelow = window.innerHeight - triggerRect.bottom;
|
|
127
|
+
const spaceAbove = triggerRect.top;
|
|
128
|
+
const shouldFlip = spaceBelow < panelHeight && spaceAbove > spaceBelow;
|
|
129
|
+
|
|
130
|
+
panelTop = shouldFlip
|
|
131
|
+
? Math.max(0, triggerRect.top - panelHeight - 8)
|
|
132
|
+
: triggerRect.bottom + 8;
|
|
133
|
+
|
|
134
|
+
const viewportLeft = window.scrollX;
|
|
135
|
+
const viewportRight = window.scrollX + window.innerWidth;
|
|
136
|
+
const targetLeft = triggerRect.left + window.scrollX;
|
|
137
|
+
const maxLeft = viewportRight - panelSize;
|
|
138
|
+
panelLeft = Math.max(viewportLeft, Math.min(targetLeft, maxLeft));
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const onKeyDown = (event: KeyboardEvent) => {
|
|
142
|
+
if (event.key === "Escape") {
|
|
143
|
+
event.preventDefault();
|
|
144
|
+
open = false;
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const onClickOutside = (event: MouseEvent) => {
|
|
149
|
+
if (
|
|
150
|
+
currentTrigger &&
|
|
151
|
+
currentPanel &&
|
|
152
|
+
!currentTrigger.contains(event.target as Node) &&
|
|
153
|
+
!currentPanel.contains(event.target as Node)
|
|
154
|
+
) {
|
|
155
|
+
open = false;
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
queueMicrotask(updatePosition);
|
|
160
|
+
window.addEventListener("scroll", updatePosition, true);
|
|
161
|
+
window.addEventListener("resize", updatePosition);
|
|
162
|
+
window.addEventListener("keydown", onKeyDown);
|
|
163
|
+
document.addEventListener("mousedown", onClickOutside);
|
|
164
|
+
|
|
165
|
+
return () => {
|
|
166
|
+
window.removeEventListener("scroll", updatePosition, true);
|
|
167
|
+
window.removeEventListener("resize", updatePosition);
|
|
168
|
+
window.removeEventListener("keydown", onKeyDown);
|
|
169
|
+
document.removeEventListener("mousedown", onClickOutside);
|
|
170
|
+
};
|
|
171
|
+
});
|
|
172
|
+
</script>
|
|
173
|
+
|
|
174
|
+
<div class={pickerClass} {...rest}>
|
|
175
|
+
<div class="text-md font-medium mb-2 [color:var(--color-text-default)]">
|
|
176
|
+
{labelFinal}:
|
|
177
|
+
</div>
|
|
178
|
+
<div class="inline-flex flex-wrap items-center gap-x-3 gap-y-2">
|
|
179
|
+
<div bind:this={triggerEl}>
|
|
180
|
+
<Button
|
|
181
|
+
onClick={togglePanel}
|
|
182
|
+
{disabled}
|
|
183
|
+
sz="xs"
|
|
184
|
+
aria-expanded={open}
|
|
185
|
+
aria-controls={open ? panelId : undefined}
|
|
186
|
+
>
|
|
187
|
+
{L.date}
|
|
188
|
+
</Button>
|
|
189
|
+
</div>
|
|
190
|
+
|
|
191
|
+
{#if clearable}
|
|
192
|
+
<Button
|
|
193
|
+
onClick={clearSelection}
|
|
194
|
+
variant="danger"
|
|
195
|
+
disabled={!hasValue || disabled}
|
|
196
|
+
sz="xs"
|
|
197
|
+
>
|
|
198
|
+
{L.clear}
|
|
199
|
+
</Button>
|
|
200
|
+
{/if}
|
|
201
|
+
|
|
202
|
+
{#if open}
|
|
203
|
+
<div
|
|
204
|
+
role="presentation"
|
|
205
|
+
tabindex="-1"
|
|
206
|
+
class="fixed inset-0 z-[var(--z-overlay)]"
|
|
207
|
+
></div>
|
|
208
|
+
|
|
209
|
+
<div
|
|
210
|
+
bind:this={panelEl}
|
|
211
|
+
id={panelId}
|
|
212
|
+
role="dialog"
|
|
213
|
+
aria-label={labelFinal}
|
|
214
|
+
class="z-[var(--z-modal)] p-3 border border-[var(--border-color-default)] rounded-[var(--radius-md)] bg-[var(--color-bg-surface)] shadow-[0_2px_6px_var(--shadow-color)]"
|
|
215
|
+
style={panelStyle}
|
|
216
|
+
>
|
|
217
|
+
<Calendar
|
|
218
|
+
value={value}
|
|
219
|
+
{min}
|
|
220
|
+
{max}
|
|
221
|
+
{locale}
|
|
222
|
+
onChange={handleSelect}
|
|
223
|
+
showOutsideDays
|
|
224
|
+
class="w-full h-full"
|
|
225
|
+
/>
|
|
226
|
+
</div>
|
|
227
|
+
{/if}
|
|
228
|
+
</div>
|
|
229
|
+
|
|
230
|
+
<div
|
|
231
|
+
class="mt-3 p-4 bg-[var(--color-bg-surface)] text-center"
|
|
232
|
+
aria-live="polite"
|
|
233
|
+
>
|
|
234
|
+
<p class="text-xs uppercase tracking-wide [color:var(--color-text-muted)]">
|
|
235
|
+
{L.selectedDate}
|
|
236
|
+
</p>
|
|
237
|
+
|
|
238
|
+
<p class="text-sm font-semibold mt-1 [color:var(--color-text-default)]">
|
|
239
|
+
{#if hasValue}
|
|
240
|
+
{formattedValue}
|
|
241
|
+
{:else}
|
|
242
|
+
{placeholderFinal}
|
|
243
|
+
{/if}
|
|
244
|
+
</p>
|
|
245
|
+
</div>
|
|
246
|
+
</div>
|