plasma-svelte 0.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.
Files changed (95) hide show
  1. package/README.md +65 -0
  2. package/dist/accordion/Accordion.svelte +28 -0
  3. package/dist/accordion/Accordion.svelte.d.ts +8 -0
  4. package/dist/accordion/AccordionItem.svelte +193 -0
  5. package/dist/accordion/AccordionItem.svelte.d.ts +14 -0
  6. package/dist/avatar/Avatar.svelte +178 -0
  7. package/dist/avatar/Avatar.svelte.d.ts +16 -0
  8. package/dist/badge/Badge.svelte +162 -0
  9. package/dist/badge/Badge.svelte.d.ts +16 -0
  10. package/dist/breadcrumb/Breadcrumb.svelte +59 -0
  11. package/dist/breadcrumb/Breadcrumb.svelte.d.ts +9 -0
  12. package/dist/breadcrumb/BreadcrumbItem.svelte +151 -0
  13. package/dist/breadcrumb/BreadcrumbItem.svelte.d.ts +14 -0
  14. package/dist/button/Button.svelte +274 -0
  15. package/dist/button/Button.svelte.d.ts +22 -0
  16. package/dist/button/ButtonGroup.svelte +98 -0
  17. package/dist/button/ButtonGroup.svelte.d.ts +12 -0
  18. package/dist/card/Card.svelte +191 -0
  19. package/dist/card/Card.svelte.d.ts +18 -0
  20. package/dist/checkbox/Checkbox.svelte +199 -0
  21. package/dist/checkbox/Checkbox.svelte.d.ts +12 -0
  22. package/dist/datepicker/DatePicker.svelte +509 -0
  23. package/dist/datepicker/DatePicker.svelte.d.ts +14 -0
  24. package/dist/divider/Divider.svelte +112 -0
  25. package/dist/divider/Divider.svelte.d.ts +13 -0
  26. package/dist/drawer/Drawer.svelte +330 -0
  27. package/dist/drawer/Drawer.svelte.d.ts +21 -0
  28. package/dist/dropzone/DropZone.svelte +282 -0
  29. package/dist/dropzone/DropZone.svelte.d.ts +17 -0
  30. package/dist/emptystate/EmptyState.svelte +169 -0
  31. package/dist/emptystate/EmptyState.svelte.d.ts +15 -0
  32. package/dist/headerbar/HeaderBar.svelte +210 -0
  33. package/dist/headerbar/HeaderBar.svelte.d.ts +17 -0
  34. package/dist/index.d.ts +44 -0
  35. package/dist/index.js +44 -0
  36. package/dist/input/Input.svelte +227 -0
  37. package/dist/input/Input.svelte.d.ts +14 -0
  38. package/dist/layout/Flex.svelte +110 -0
  39. package/dist/layout/Flex.svelte.d.ts +20 -0
  40. package/dist/layout/Grid.svelte +78 -0
  41. package/dist/layout/Grid.svelte.d.ts +19 -0
  42. package/dist/layout/Space.svelte +64 -0
  43. package/dist/layout/Space.svelte.d.ts +16 -0
  44. package/dist/layout/utils.d.ts +2 -0
  45. package/dist/layout/utils.js +19 -0
  46. package/dist/menu/Menu.svelte +156 -0
  47. package/dist/menu/Menu.svelte.d.ts +14 -0
  48. package/dist/menu/MenuDivider.svelte +19 -0
  49. package/dist/menu/MenuDivider.svelte.d.ts +6 -0
  50. package/dist/menu/MenuItem.svelte +126 -0
  51. package/dist/menu/MenuItem.svelte.d.ts +13 -0
  52. package/dist/message/InlineMessage.svelte +226 -0
  53. package/dist/message/InlineMessage.svelte.d.ts +15 -0
  54. package/dist/modal/ConfirmDialog.svelte +151 -0
  55. package/dist/modal/ConfirmDialog.svelte.d.ts +19 -0
  56. package/dist/modal/Modal.svelte +279 -0
  57. package/dist/modal/Modal.svelte.d.ts +18 -0
  58. package/dist/pagination/Pagination.svelte +258 -0
  59. package/dist/pagination/Pagination.svelte.d.ts +16 -0
  60. package/dist/progress/ProgressBar.svelte +179 -0
  61. package/dist/progress/ProgressBar.svelte.d.ts +15 -0
  62. package/dist/radio/Radio.svelte +161 -0
  63. package/dist/radio/Radio.svelte.d.ts +13 -0
  64. package/dist/searchfield/SearchField.svelte +246 -0
  65. package/dist/searchfield/SearchField.svelte.d.ts +15 -0
  66. package/dist/select/Select.svelte +392 -0
  67. package/dist/select/Select.svelte.d.ts +20 -0
  68. package/dist/sidebar/Sidebar.svelte +78 -0
  69. package/dist/sidebar/Sidebar.svelte.d.ts +11 -0
  70. package/dist/sidebar/SidebarGroup.svelte +51 -0
  71. package/dist/sidebar/SidebarGroup.svelte.d.ts +9 -0
  72. package/dist/sidebar/SidebarItem.svelte +185 -0
  73. package/dist/sidebar/SidebarItem.svelte.d.ts +16 -0
  74. package/dist/slider/Slider.svelte +204 -0
  75. package/dist/slider/Slider.svelte.d.ts +16 -0
  76. package/dist/spinbox/SpinBox.svelte +299 -0
  77. package/dist/spinbox/SpinBox.svelte.d.ts +20 -0
  78. package/dist/spinner/Spinner.svelte +130 -0
  79. package/dist/spinner/Spinner.svelte.d.ts +11 -0
  80. package/dist/style/base.css +178 -0
  81. package/dist/style/index.css +2 -0
  82. package/dist/style/token.css +230 -0
  83. package/dist/switch/Switch.svelte +199 -0
  84. package/dist/switch/Switch.svelte.d.ts +13 -0
  85. package/dist/table/Table.svelte +305 -0
  86. package/dist/table/Table.svelte.d.ts +32 -0
  87. package/dist/tabs/Tabs.svelte +216 -0
  88. package/dist/tabs/Tabs.svelte.d.ts +21 -0
  89. package/dist/textarea/TextArea.svelte +114 -0
  90. package/dist/textarea/TextArea.svelte.d.ts +14 -0
  91. package/dist/timepicker/TimePicker.svelte +452 -0
  92. package/dist/timepicker/TimePicker.svelte.d.ts +16 -0
  93. package/dist/tooltip/Tooltip.svelte +122 -0
  94. package/dist/tooltip/Tooltip.svelte.d.ts +12 -0
  95. package/package.json +66 -0
@@ -0,0 +1,509 @@
1
+ <script lang="ts">
2
+ import type { HTMLAttributes } from "svelte/elements";
3
+
4
+ type DatePickerSize = "sm" | "md" | "lg" | "small" | "medium" | "large";
5
+
6
+ interface Props extends Omit<HTMLAttributes<HTMLDivElement>, "size" | "onchange"> {
7
+ value?: string; // YYYY-MM-DD format
8
+ placeholder?: string;
9
+ min?: string;
10
+ max?: string;
11
+ size?: DatePickerSize;
12
+ disabled?: boolean;
13
+ onchange?: (val: string) => void;
14
+ }
15
+
16
+ let {
17
+ value = $bindable(""),
18
+ placeholder = "Select date...",
19
+ min,
20
+ max,
21
+ size = "md",
22
+ disabled = false,
23
+ onchange,
24
+ class: customClass = "",
25
+ id,
26
+ ...restProps
27
+ }: Props = $props();
28
+
29
+ let isOpen = $state(false);
30
+ let triggerEl = $state<HTMLButtonElement | null>(null);
31
+ let popupEl = $state<HTMLDivElement | null>(null);
32
+ let popupStyle = $state("");
33
+
34
+ // Parse current selected or initial viewing date
35
+ function parseDate(val: string) {
36
+ if (!val) return new Date();
37
+ const parts = val.split("-").map(Number);
38
+ if (parts.length === 3 && !Number.isNaN(parts[0]) && !Number.isNaN(parts[1]) && !Number.isNaN(parts[2])) {
39
+ return new Date(parts[0], parts[1] - 1, parts[2]);
40
+ }
41
+ return new Date();
42
+ }
43
+
44
+ let viewDate = $state(parseDate(value));
45
+
46
+ const resolvedSize = $derived(
47
+ size === "small"
48
+ ? "sm"
49
+ : size === "large"
50
+ ? "lg"
51
+ : size === "medium"
52
+ ? "md"
53
+ : size
54
+ );
55
+
56
+ const months = [
57
+ "January", "February", "March", "April", "May", "June",
58
+ "July", "August", "September", "October", "November", "December"
59
+ ];
60
+ const dayNames = ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"];
61
+
62
+ const currentYear = $derived(viewDate.getFullYear());
63
+ const currentMonth = $derived(viewDate.getMonth());
64
+
65
+ // Generate 42 calendar grid cells (Monday-first)
66
+ const calendarCells = $derived.by(() => {
67
+ const firstDayOfMonth = new Date(currentYear, currentMonth, 1);
68
+ const lastDayOfMonth = new Date(currentYear, currentMonth + 1, 0);
69
+
70
+ let startDayOfWeek = firstDayOfMonth.getDay() - 1;
71
+ if (startDayOfWeek === -1) startDayOfWeek = 6; // Sunday -> 6
72
+
73
+ const daysInMonth = lastDayOfMonth.getDate();
74
+ const prevMonthLastDay = new Date(currentYear, currentMonth, 0).getDate();
75
+
76
+ const cells: { dateStr: string; dayNum: number; isCurrentMonth: boolean; isToday: boolean; isSelected: boolean; isDisabled: boolean }[] = [];
77
+
78
+ const todayStr = new Date().toISOString().split("T")[0];
79
+
80
+ // Previous month filler days
81
+ for (let i = startDayOfWeek - 1; i >= 0; i--) {
82
+ const d = prevMonthLastDay - i;
83
+ const m = currentMonth === 0 ? 12 : currentMonth;
84
+ const y = currentMonth === 0 ? currentYear - 1 : currentYear;
85
+ const dateStr = `${y}-${String(m).padStart(2, "0")}-${String(d).padStart(2, "0")}`;
86
+ cells.push({
87
+ dateStr,
88
+ dayNum: d,
89
+ isCurrentMonth: false,
90
+ isToday: dateStr === todayStr,
91
+ isSelected: dateStr === value,
92
+ isDisabled: !!((min && dateStr < min) || (max && dateStr > max))
93
+ });
94
+ }
95
+
96
+ // Current month days
97
+ for (let d = 1; d <= daysInMonth; d++) {
98
+ const dateStr = `${currentYear}-${String(currentMonth + 1).padStart(2, "0")}-${String(d).padStart(2, "0")}`;
99
+ cells.push({
100
+ dateStr,
101
+ dayNum: d,
102
+ isCurrentMonth: true,
103
+ isToday: dateStr === todayStr,
104
+ isSelected: dateStr === value,
105
+ isDisabled: !!((min && dateStr < min) || (max && dateStr > max))
106
+ });
107
+ }
108
+
109
+ // Next month filler days
110
+ const remaining = 42 - cells.length;
111
+ for (let d = 1; d <= remaining; d++) {
112
+ const m = currentMonth === 11 ? 1 : currentMonth + 2;
113
+ const y = currentMonth === 11 ? currentYear + 1 : currentYear;
114
+ const dateStr = `${y}-${String(m).padStart(2, "0")}-${String(d).padStart(2, "0")}`;
115
+ cells.push({
116
+ dateStr,
117
+ dayNum: d,
118
+ isCurrentMonth: false,
119
+ isToday: dateStr === todayStr,
120
+ isSelected: dateStr === value,
121
+ isDisabled: !!((min && dateStr < min) || (max && dateStr > max))
122
+ });
123
+ }
124
+
125
+ return cells;
126
+ });
127
+
128
+ function prevMonth() {
129
+ viewDate = new Date(currentYear, currentMonth - 1, 1);
130
+ }
131
+
132
+ function nextMonth() {
133
+ viewDate = new Date(currentYear, currentMonth + 1, 1);
134
+ }
135
+
136
+ function goToToday() {
137
+ const today = new Date();
138
+ viewDate = today;
139
+ selectDate(today.toISOString().split("T")[0]);
140
+ }
141
+
142
+ function selectDate(dateStr: string) {
143
+ value = dateStr;
144
+ onchange?.(dateStr);
145
+ popupEl?.hidePopover();
146
+ }
147
+
148
+ function updatePosition() {
149
+ if (!triggerEl) return;
150
+ const rect = triggerEl.getBoundingClientRect();
151
+ popupStyle = `top: ${rect.bottom + 4}px; left: ${rect.left}px;`;
152
+ }
153
+
154
+ function toggleOpen() {
155
+ if (disabled) return;
156
+ if (popupEl?.matches(":popover-open")) {
157
+ popupEl.hidePopover();
158
+ } else {
159
+ if (value) {
160
+ viewDate = parseDate(value);
161
+ }
162
+ updatePosition();
163
+ popupEl?.showPopover();
164
+ }
165
+ }
166
+
167
+ function handleToggle(e: Event) {
168
+ const toggleEvent = e as Event & { newState?: string };
169
+ isOpen = toggleEvent.newState === "open";
170
+ if (isOpen) {
171
+ updatePosition();
172
+ }
173
+ }
174
+ </script>
175
+
176
+ <div
177
+ class="plasma-datepicker-container {customClass}"
178
+ class:plasma-datepicker--disabled={disabled}
179
+ {...restProps}
180
+ >
181
+ <!-- Date Input Button -->
182
+ <button
183
+ {id}
184
+ bind:this={triggerEl}
185
+ type="button"
186
+ class="plasma-datepicker-trigger plasma-datepicker--{resolvedSize}"
187
+ class:plasma-datepicker-trigger--open={isOpen}
188
+ {disabled}
189
+ onclick={toggleOpen}
190
+ aria-haspopup="dialog"
191
+ aria-expanded={isOpen}
192
+ >
193
+ <span class="plasma-datepicker-icon">
194
+ <svg aria-hidden="true" viewBox="0 0 16 16" width="14" height="14" fill="currentColor">
195
+ <path d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5zM1 4v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4H1z" />
196
+ </svg>
197
+ </span>
198
+
199
+ <span class="plasma-datepicker-text" class:plasma-datepicker-placeholder={!value}>
200
+ {value || placeholder}
201
+ </span>
202
+
203
+ <span class="plasma-datepicker-chevron" class:plasma-datepicker-chevron--open={isOpen}>
204
+ <svg aria-hidden="true" viewBox="0 0 16 16" width="10" height="10" fill="currentColor">
205
+ <path d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z" />
206
+ </svg>
207
+ </span>
208
+ </button>
209
+
210
+ <!-- KDE Breeze Calendar Top-Layer Popover -->
211
+ <div
212
+ bind:this={popupEl}
213
+ popover="auto"
214
+ ontoggle={handleToggle}
215
+ class="plasma-calendar-popup"
216
+ style={popupStyle}
217
+ role="dialog"
218
+ aria-label="Calendar"
219
+ >
220
+ <!-- Calendar Header -->
221
+ <div class="plasma-calendar-header">
222
+ <button
223
+ type="button"
224
+ class="plasma-calendar-nav-btn"
225
+ onclick={prevMonth}
226
+ aria-label="Previous month"
227
+ >
228
+
229
+ </button>
230
+
231
+ <span class="plasma-calendar-month-label">
232
+ {months[currentMonth]} {currentYear}
233
+ </span>
234
+
235
+ <button
236
+ type="button"
237
+ class="plasma-calendar-nav-btn"
238
+ onclick={nextMonth}
239
+ aria-label="Next month"
240
+ >
241
+
242
+ </button>
243
+ </div>
244
+
245
+ <!-- Days of Week Header -->
246
+ <div class="plasma-calendar-weekdays">
247
+ {#each dayNames as day}
248
+ <span class="plasma-calendar-weekday">{day}</span>
249
+ {/each}
250
+ </div>
251
+
252
+ <!-- Calendar Grid -->
253
+ <div class="plasma-calendar-grid">
254
+ {#each calendarCells as cell}
255
+ <button
256
+ type="button"
257
+ class="plasma-calendar-day"
258
+ class:plasma-calendar-day--other={!cell.isCurrentMonth}
259
+ class:plasma-calendar-day--today={cell.isToday}
260
+ class:plasma-calendar-day--selected={cell.isSelected}
261
+ disabled={cell.isDisabled}
262
+ onclick={() => selectDate(cell.dateStr)}
263
+ >
264
+ {cell.dayNum}
265
+ </button>
266
+ {/each}
267
+ </div>
268
+
269
+ <!-- Calendar Footer -->
270
+ <div class="plasma-calendar-footer">
271
+ <button
272
+ type="button"
273
+ class="plasma-calendar-today-btn"
274
+ onclick={goToToday}
275
+ >
276
+ Today
277
+ </button>
278
+ </div>
279
+ </div>
280
+ </div>
281
+
282
+ <style>
283
+ .plasma-datepicker-container {
284
+ position: relative;
285
+ display: inline-block;
286
+ width: 100%;
287
+ box-sizing: border-box;
288
+ font-family: var(--plasma-font-sans);
289
+ }
290
+
291
+ /* --------------------------------------------------------------------------
292
+ Trigger Button
293
+ -------------------------------------------------------------------------- */
294
+ .plasma-datepicker-trigger {
295
+ display: flex;
296
+ align-items: center;
297
+ justify-content: space-between;
298
+ width: 100%;
299
+ padding: 0 var(--plasma-space-md);
300
+ background-color: var(--plasma-color-view-bg);
301
+ color: var(--plasma-color-text);
302
+ border: 1px solid var(--plasma-color-border);
303
+ border-radius: var(--plasma-radius-md);
304
+ box-shadow: var(--plasma-shadow-xs);
305
+ cursor: pointer;
306
+ box-sizing: border-box;
307
+ user-select: none;
308
+ transition: var(--plasma-transition-fast);
309
+ }
310
+
311
+ .plasma-datepicker-trigger:hover:not(:disabled):not(.plasma-datepicker-trigger--open) {
312
+ border-color: var(--plasma-color-border-hover);
313
+ }
314
+
315
+ .plasma-datepicker-trigger--open {
316
+ border-color: var(--plasma-color-highlight);
317
+ box-shadow: var(--plasma-shadow-focus);
318
+ }
319
+
320
+ .plasma-datepicker-icon {
321
+ display: inline-flex;
322
+ align-items: center;
323
+ color: var(--plasma-color-text-muted);
324
+ margin-right: var(--plasma-space-sm);
325
+ }
326
+
327
+ .plasma-datepicker-text {
328
+ flex: 1;
329
+ text-align: left;
330
+ overflow: hidden;
331
+ text-overflow: ellipsis;
332
+ white-space: nowrap;
333
+ }
334
+
335
+ .plasma-datepicker-placeholder {
336
+ color: var(--plasma-color-text-muted);
337
+ opacity: 0.75;
338
+ }
339
+
340
+ .plasma-datepicker-chevron {
341
+ display: inline-flex;
342
+ align-items: center;
343
+ color: var(--plasma-color-text-muted);
344
+ transition: transform var(--plasma-duration-fast) var(--plasma-ease-default);
345
+ }
346
+
347
+ .plasma-datepicker-chevron--open {
348
+ transform: rotate(180deg);
349
+ }
350
+
351
+ /* --------------------------------------------------------------------------
352
+ Sizing
353
+ -------------------------------------------------------------------------- */
354
+ .plasma-datepicker--sm {
355
+ height: var(--plasma-control-height-sm);
356
+ font-size: var(--plasma-font-size-xs);
357
+ }
358
+
359
+ .plasma-datepicker--md {
360
+ height: var(--plasma-control-height-md);
361
+ font-size: var(--plasma-font-size-base);
362
+ }
363
+
364
+ .plasma-datepicker--lg {
365
+ height: var(--plasma-control-height-lg);
366
+ font-size: var(--plasma-font-size-md);
367
+ }
368
+
369
+ /* --------------------------------------------------------------------------
370
+ Top-Layer Calendar Popover
371
+ -------------------------------------------------------------------------- */
372
+ .plasma-calendar-popup {
373
+ position: fixed;
374
+ margin: 0;
375
+ inset: unset;
376
+ z-index: 99999;
377
+ width: 280px;
378
+ padding: var(--plasma-space-md);
379
+ background-color: var(--plasma-color-surface);
380
+ color: var(--plasma-color-text);
381
+ font-family: var(--plasma-font-sans);
382
+ border: 1px solid var(--plasma-color-border);
383
+ border-radius: var(--plasma-radius-lg);
384
+ box-shadow: var(--plasma-shadow-lg);
385
+ box-sizing: border-box;
386
+ animation: plasma-popup-fade var(--plasma-duration-fast) var(--plasma-ease-default);
387
+ }
388
+
389
+ @keyframes plasma-popup-fade {
390
+ from { opacity: 0; transform: translateY(-4px); }
391
+ to { opacity: 1; transform: translateY(0); }
392
+ }
393
+
394
+ .plasma-calendar-header {
395
+ display: flex;
396
+ align-items: center;
397
+ justify-content: space-between;
398
+ margin-bottom: var(--plasma-space-sm);
399
+ }
400
+
401
+ .plasma-calendar-month-label {
402
+ font-size: var(--plasma-font-size-base);
403
+ font-weight: var(--plasma-font-weight-bold);
404
+ color: var(--plasma-color-text);
405
+ }
406
+
407
+ .plasma-calendar-nav-btn {
408
+ display: inline-flex;
409
+ align-items: center;
410
+ justify-content: center;
411
+ width: 24px;
412
+ height: 24px;
413
+ border: none;
414
+ border-radius: var(--plasma-radius-sm);
415
+ background: transparent;
416
+ color: var(--plasma-color-text);
417
+ font-size: 16px;
418
+ cursor: pointer;
419
+ transition: var(--plasma-transition-fast);
420
+ }
421
+
422
+ .plasma-calendar-nav-btn:hover {
423
+ background-color: var(--plasma-color-surface-hover);
424
+ color: var(--plasma-color-highlight);
425
+ }
426
+
427
+ .plasma-calendar-weekdays {
428
+ display: grid;
429
+ grid-template-columns: repeat(7, 1fr);
430
+ text-align: center;
431
+ margin-bottom: 4px;
432
+ }
433
+
434
+ .plasma-calendar-weekday {
435
+ font-size: 11px;
436
+ font-weight: var(--plasma-font-weight-bold);
437
+ color: var(--plasma-color-text-muted);
438
+ padding: 2px 0;
439
+ }
440
+
441
+ .plasma-calendar-grid {
442
+ display: grid;
443
+ grid-template-columns: repeat(7, 1fr);
444
+ gap: 2px;
445
+ }
446
+
447
+ .plasma-calendar-day {
448
+ display: inline-flex;
449
+ align-items: center;
450
+ justify-content: center;
451
+ height: 32px;
452
+ border: none;
453
+ border-radius: var(--plasma-radius-sm);
454
+ background: transparent;
455
+ color: var(--plasma-color-text);
456
+ font-size: var(--plasma-font-size-sm);
457
+ cursor: pointer;
458
+ transition: var(--plasma-transition-fast);
459
+ }
460
+
461
+ .plasma-calendar-day:hover:not(:disabled) {
462
+ background-color: var(--plasma-color-surface-hover);
463
+ }
464
+
465
+ .plasma-calendar-day--other {
466
+ color: var(--plasma-color-text-disabled);
467
+ opacity: 0.5;
468
+ }
469
+
470
+ .plasma-calendar-day--today {
471
+ border: 1px solid var(--plasma-color-highlight);
472
+ font-weight: var(--plasma-font-weight-bold);
473
+ }
474
+
475
+ .plasma-calendar-day--selected {
476
+ background-color: var(--plasma-color-highlight) !important;
477
+ color: #ffffff !important;
478
+ font-weight: var(--plasma-font-weight-bold);
479
+ }
480
+
481
+ .plasma-calendar-day:disabled {
482
+ opacity: 0.3;
483
+ cursor: not-allowed;
484
+ }
485
+
486
+ .plasma-calendar-footer {
487
+ display: flex;
488
+ justify-content: center;
489
+ margin-top: var(--plasma-space-sm);
490
+ padding-top: var(--plasma-space-xs);
491
+ border-top: 1px solid var(--plasma-color-border-subtle);
492
+ }
493
+
494
+ .plasma-calendar-today-btn {
495
+ padding: 3px 12px;
496
+ font-size: 12px;
497
+ font-weight: var(--plasma-font-weight-medium);
498
+ border: none;
499
+ border-radius: var(--plasma-radius-sm);
500
+ background: transparent;
501
+ color: var(--plasma-color-highlight);
502
+ cursor: pointer;
503
+ transition: var(--plasma-transition-fast);
504
+ }
505
+
506
+ .plasma-calendar-today-btn:hover {
507
+ background-color: var(--plasma-color-highlight-soft);
508
+ }
509
+ </style>
@@ -0,0 +1,14 @@
1
+ import type { HTMLAttributes } from "svelte/elements";
2
+ type DatePickerSize = "sm" | "md" | "lg" | "small" | "medium" | "large";
3
+ interface Props extends Omit<HTMLAttributes<HTMLDivElement>, "size" | "onchange"> {
4
+ value?: string;
5
+ placeholder?: string;
6
+ min?: string;
7
+ max?: string;
8
+ size?: DatePickerSize;
9
+ disabled?: boolean;
10
+ onchange?: (val: string) => void;
11
+ }
12
+ declare const DatePicker: import("svelte").Component<Props, {}, "value">;
13
+ type DatePicker = ReturnType<typeof DatePicker>;
14
+ export default DatePicker;
@@ -0,0 +1,112 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from "svelte";
3
+ import type { HTMLAttributes } from "svelte/elements";
4
+
5
+ type DividerOrientation = "horizontal" | "vertical";
6
+ type DividerAlign = "left" | "center" | "right";
7
+
8
+ interface Props extends HTMLAttributes<HTMLDivElement> {
9
+ orientation?: DividerOrientation;
10
+ align?: DividerAlign;
11
+ label?: string;
12
+ children?: Snippet;
13
+ }
14
+
15
+ let {
16
+ orientation = "horizontal",
17
+ align = "center",
18
+ label = "",
19
+ children,
20
+ class: customClass = "",
21
+ ...restProps
22
+ }: Props = $props();
23
+ </script>
24
+
25
+ {#if orientation === "vertical"}
26
+ <div
27
+ role="separator"
28
+ aria-orientation="vertical"
29
+ class="plasma-divider plasma-divider--vertical {customClass}"
30
+ {...restProps}
31
+ ></div>
32
+ {:else if label || children}
33
+ <div
34
+ role="separator"
35
+ aria-orientation="horizontal"
36
+ class="plasma-divider-with-label plasma-divider-with-label--{align} {customClass}"
37
+ {...restProps}
38
+ >
39
+ <span class="plasma-divider-line"></span>
40
+ <span class="plasma-divider-text">
41
+ {#if children}
42
+ {@render children()}
43
+ {:else}
44
+ {label}
45
+ {/if}
46
+ </span>
47
+ <span class="plasma-divider-line"></span>
48
+ </div>
49
+ {:else}
50
+ <hr
51
+ class="plasma-divider plasma-divider--horizontal {customClass}"
52
+ {...restProps}
53
+ />
54
+ {/if}
55
+
56
+ <style>
57
+ /* Horizontal Hairline */
58
+ .plasma-divider--horizontal {
59
+ width: 100%;
60
+ height: 1px;
61
+ margin: var(--plasma-space-md) 0;
62
+ padding: 0;
63
+ border: none;
64
+ background-color: var(--plasma-color-border-subtle);
65
+ box-sizing: border-box;
66
+ }
67
+
68
+ /* Vertical Hairline */
69
+ .plasma-divider--vertical {
70
+ display: inline-block;
71
+ width: 1px;
72
+ height: 100%;
73
+ min-height: 1.25em;
74
+ margin: 0 var(--plasma-space-md);
75
+ padding: 0;
76
+ background-color: var(--plasma-color-border-subtle);
77
+ vertical-align: middle;
78
+ box-sizing: border-box;
79
+ }
80
+
81
+ /* Labeled Divider */
82
+ .plasma-divider-with-label {
83
+ display: flex;
84
+ align-items: center;
85
+ width: 100%;
86
+ margin: var(--plasma-space-md) 0;
87
+ font-family: var(--plasma-font-sans);
88
+ font-size: var(--plasma-font-size-xs);
89
+ color: var(--plasma-color-text-muted);
90
+ user-select: none;
91
+ }
92
+
93
+ .plasma-divider-line {
94
+ flex: 1;
95
+ height: 1px;
96
+ background-color: var(--plasma-color-border-subtle);
97
+ }
98
+
99
+ .plasma-divider-text {
100
+ padding: 0 var(--plasma-space-md);
101
+ white-space: nowrap;
102
+ text-transform: uppercase;
103
+ letter-spacing: 0.05em;
104
+ }
105
+
106
+ .plasma-divider-with-label--left .plasma-divider-line:first-child {
107
+ max-width: 24px;
108
+ }
109
+ .plasma-divider-with-label--right .plasma-divider-line:last-child {
110
+ max-width: 24px;
111
+ }
112
+ </style>
@@ -0,0 +1,13 @@
1
+ import type { Snippet } from "svelte";
2
+ import type { HTMLAttributes } from "svelte/elements";
3
+ type DividerOrientation = "horizontal" | "vertical";
4
+ type DividerAlign = "left" | "center" | "right";
5
+ interface Props extends HTMLAttributes<HTMLDivElement> {
6
+ orientation?: DividerOrientation;
7
+ align?: DividerAlign;
8
+ label?: string;
9
+ children?: Snippet;
10
+ }
11
+ declare const Divider: import("svelte").Component<Props, {}, "">;
12
+ type Divider = ReturnType<typeof Divider>;
13
+ export default Divider;