@noahbaumgartner/svelte-ui 0.0.5 → 0.0.7

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 (214) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +20 -5
  3. package/dist/components/accordion/Accordion.svelte +16 -6
  4. package/dist/components/accordion/Accordion.svelte.d.ts +3 -1
  5. package/dist/components/accordion/AccordionItem.svelte +106 -67
  6. package/dist/components/accordion/AccordionItem.svelte.d.ts +5 -1
  7. package/dist/components/alert-dialog/AlertDialog.svelte +108 -76
  8. package/dist/components/alert-dialog/AlertDialog.svelte.d.ts +5 -2
  9. package/dist/components/avatar/Avatar.svelte +71 -49
  10. package/dist/components/avatar/Avatar.svelte.d.ts +5 -2
  11. package/dist/components/avatar-group/AvatarGroup.svelte +72 -45
  12. package/dist/components/avatar-group/AvatarGroup.svelte.d.ts +5 -1
  13. package/dist/components/badge/Badge.svelte +50 -28
  14. package/dist/components/badge/Badge.svelte.d.ts +6 -4
  15. package/dist/components/breadcrumb/Breadcrumb.svelte +21 -17
  16. package/dist/components/breadcrumb/Breadcrumb.svelte.d.ts +3 -1
  17. package/dist/components/breadcrumb/BreadcrumbEllipsis.svelte +17 -6
  18. package/dist/components/breadcrumb/BreadcrumbEllipsis.svelte.d.ts +5 -2
  19. package/dist/components/breadcrumb/BreadcrumbItem.svelte +75 -36
  20. package/dist/components/breadcrumb/BreadcrumbItem.svelte.d.ts +8 -5
  21. package/dist/components/breadcrumb/BreadcrumbSeparator.svelte +32 -9
  22. package/dist/components/breadcrumb/BreadcrumbSeparator.svelte.d.ts +10 -17
  23. package/dist/components/button/Button.svelte +206 -168
  24. package/dist/components/button/Button.svelte.d.ts +9 -5
  25. package/dist/components/button-group/ButtonGroup.svelte +52 -55
  26. package/dist/components/button-group/ButtonGroup.svelte.d.ts +3 -1
  27. package/dist/components/calendar/Calendar.svelte +232 -144
  28. package/dist/components/calendar/Calendar.svelte.d.ts +19 -2
  29. package/dist/components/calendar/dates.d.ts +4 -1
  30. package/dist/components/calendar/dates.js +8 -2
  31. package/dist/components/card/Card.svelte +48 -32
  32. package/dist/components/card/Card.svelte.d.ts +3 -1
  33. package/dist/components/card/CardAction.svelte +11 -7
  34. package/dist/components/card/CardAction.svelte.d.ts +3 -1
  35. package/dist/components/card/CardContent.svelte +8 -4
  36. package/dist/components/card/CardContent.svelte.d.ts +3 -1
  37. package/dist/components/card/CardDescription.svelte +11 -7
  38. package/dist/components/card/CardDescription.svelte.d.ts +3 -1
  39. package/dist/components/card/CardFooter.svelte +15 -11
  40. package/dist/components/card/CardFooter.svelte.d.ts +3 -1
  41. package/dist/components/card/CardHeader.svelte +15 -11
  42. package/dist/components/card/CardHeader.svelte.d.ts +3 -1
  43. package/dist/components/card/CardTitle.svelte +11 -7
  44. package/dist/components/card/CardTitle.svelte.d.ts +3 -1
  45. package/dist/components/checkbox/Checkbox.svelte +152 -61
  46. package/dist/components/checkbox/Checkbox.svelte.d.ts +5 -2
  47. package/dist/components/color-picker/ColorPicker.svelte +131 -78
  48. package/dist/components/color-picker/ColorPicker.svelte.d.ts +10 -1
  49. package/dist/components/context-menu/ContextMenu.svelte +78 -61
  50. package/dist/components/context-menu/ContextMenu.svelte.d.ts +5 -2
  51. package/dist/components/context-menu/ContextMenuInfo.svelte +91 -0
  52. package/dist/components/context-menu/ContextMenuInfo.svelte.d.ts +19 -0
  53. package/dist/components/context-menu/ContextMenuItem.svelte +102 -57
  54. package/dist/components/context-menu/ContextMenuItem.svelte.d.ts +10 -5
  55. package/dist/components/context-menu/ContextMenuLabel.svelte +28 -0
  56. package/dist/components/context-menu/ContextMenuLabel.svelte.d.ts +10 -0
  57. package/dist/components/context-menu/ContextMenuSeparator.svelte +29 -0
  58. package/dist/components/context-menu/ContextMenuSeparator.svelte.d.ts +8 -0
  59. package/dist/components/dialog/Dialog.svelte +149 -108
  60. package/dist/components/dialog/Dialog.svelte.d.ts +7 -2
  61. package/dist/components/drawer/Drawer.svelte +240 -189
  62. package/dist/components/drawer/Drawer.svelte.d.ts +7 -2
  63. package/dist/components/empty-state/EmptyState.svelte +67 -47
  64. package/dist/components/empty-state/EmptyState.svelte.d.ts +7 -4
  65. package/dist/components/entry/Entry.svelte +53 -42
  66. package/dist/components/entry/Entry.svelte.d.ts +2 -1
  67. package/dist/components/field/Field.svelte +66 -45
  68. package/dist/components/field/Field.svelte.d.ts +2 -1
  69. package/dist/components/field/FieldContent.svelte +11 -8
  70. package/dist/components/field/FieldContent.svelte.d.ts +2 -1
  71. package/dist/components/field/FieldDescription.svelte +18 -15
  72. package/dist/components/field/FieldDescription.svelte.d.ts +2 -1
  73. package/dist/components/field/FieldError.svelte +22 -13
  74. package/dist/components/field/FieldError.svelte.d.ts +2 -1
  75. package/dist/components/field/FieldGroup.svelte +15 -12
  76. package/dist/components/field/FieldGroup.svelte.d.ts +2 -1
  77. package/dist/components/field/FieldLegend.svelte +23 -14
  78. package/dist/components/field/FieldLegend.svelte.d.ts +2 -1
  79. package/dist/components/field/FieldSeparator.svelte +12 -9
  80. package/dist/components/field/FieldSeparator.svelte.d.ts +2 -1
  81. package/dist/components/field/FieldSet.svelte +18 -15
  82. package/dist/components/field/FieldSet.svelte.d.ts +2 -1
  83. package/dist/components/footer/Footer.svelte +63 -47
  84. package/dist/components/footer/Footer.svelte.d.ts +2 -1
  85. package/dist/components/footer/FooterColumn.svelte +17 -14
  86. package/dist/components/footer/FooterColumn.svelte.d.ts +2 -1
  87. package/dist/components/image/Image.svelte +61 -0
  88. package/dist/components/image/Image.svelte.d.ts +18 -0
  89. package/dist/components/input/Input.svelte +307 -208
  90. package/dist/components/input/Input.svelte.d.ts +12 -1
  91. package/dist/components/input-group/InputGroup.svelte +101 -61
  92. package/dist/components/input-group/InputGroup.svelte.d.ts +2 -1
  93. package/dist/components/input-group/InputGroupAddon.svelte +58 -49
  94. package/dist/components/kbd/Kbd.svelte +39 -30
  95. package/dist/components/kbd/Kbd.svelte.d.ts +2 -1
  96. package/dist/components/kbd/KbdGroup.svelte +15 -12
  97. package/dist/components/kbd/KbdGroup.svelte.d.ts +2 -1
  98. package/dist/components/label/Label.svelte +47 -28
  99. package/dist/components/label/Label.svelte.d.ts +2 -1
  100. package/dist/components/link/Link.svelte +71 -17
  101. package/dist/components/link/Link.svelte.d.ts +2 -1
  102. package/dist/components/mesh-gradient/MeshGradient.svelte +33 -22
  103. package/dist/components/mesh-gradient/MeshGradient.svelte.d.ts +2 -3
  104. package/dist/components/navbar/Navbar.svelte +149 -99
  105. package/dist/components/navbar/Navbar.svelte.d.ts +4 -2
  106. package/dist/components/navigation-menu/NavigationMenu.svelte +37 -20
  107. package/dist/components/navigation-menu/NavigationMenu.svelte.d.ts +4 -2
  108. package/dist/components/navigation-menu/NavigationMenuItem.svelte +131 -89
  109. package/dist/components/navigation-menu/NavigationMenuItem.svelte.d.ts +4 -2
  110. package/dist/components/navigation-menu/NavigationMenuLink.svelte +90 -51
  111. package/dist/components/navigation-menu/NavigationMenuLink.svelte.d.ts +7 -5
  112. package/dist/components/number-stepper/NumberStepper.svelte +39 -20
  113. package/dist/components/number-stepper/NumberStepper.svelte.d.ts +6 -1
  114. package/dist/components/popover/Popover.svelte +85 -65
  115. package/dist/components/popover/Popover.svelte.d.ts +5 -2
  116. package/dist/components/preview-card/PreviewCard.svelte +116 -98
  117. package/dist/components/preview-card/PreviewCard.svelte.d.ts +9 -6
  118. package/dist/components/progress/Progress.svelte +61 -38
  119. package/dist/components/progress/Progress.svelte.d.ts +2 -1
  120. package/dist/components/radio-group/RadioGroup.svelte +24 -19
  121. package/dist/components/radio-group/RadioGroup.svelte.d.ts +2 -1
  122. package/dist/components/radio-group/RadioGroupItem.svelte +101 -54
  123. package/dist/components/radio-group/RadioGroupItem.svelte.d.ts +2 -1
  124. package/dist/components/section/Section.svelte +114 -0
  125. package/dist/components/section/Section.svelte.d.ts +22 -0
  126. package/dist/components/select/Select.svelte +216 -133
  127. package/dist/components/select/Select.svelte.d.ts +11 -2
  128. package/dist/components/separator/Separator.svelte +21 -10
  129. package/dist/components/separator/Separator.svelte.d.ts +2 -1
  130. package/dist/components/sidebar/Sidebar.svelte +142 -108
  131. package/dist/components/sidebar/Sidebar.svelte.d.ts +6 -1
  132. package/dist/components/sidebar/SidebarContent.svelte +15 -12
  133. package/dist/components/sidebar/SidebarContent.svelte.d.ts +2 -1
  134. package/dist/components/sidebar/SidebarFooter.svelte +10 -7
  135. package/dist/components/sidebar/SidebarFooter.svelte.d.ts +2 -1
  136. package/dist/components/sidebar/SidebarGroup.svelte +35 -25
  137. package/dist/components/sidebar/SidebarGroup.svelte.d.ts +2 -1
  138. package/dist/components/sidebar/SidebarHeader.svelte +21 -16
  139. package/dist/components/sidebar/SidebarHeader.svelte.d.ts +6 -1
  140. package/dist/components/sidebar/SidebarInset.svelte +11 -8
  141. package/dist/components/sidebar/SidebarInset.svelte.d.ts +2 -1
  142. package/dist/components/sidebar/SidebarMenu.svelte +13 -10
  143. package/dist/components/sidebar/SidebarMenu.svelte.d.ts +2 -1
  144. package/dist/components/sidebar/SidebarMenuItem.svelte +195 -114
  145. package/dist/components/sidebar/SidebarMenuItem.svelte.d.ts +11 -5
  146. package/dist/components/sidebar/SidebarProvider.svelte +18 -9
  147. package/dist/components/sidebar/SidebarProvider.svelte.d.ts +2 -1
  148. package/dist/components/sidebar/SidebarSeparator.svelte +6 -1
  149. package/dist/components/sidebar/SidebarSeparator.svelte.d.ts +6 -17
  150. package/dist/components/sidebar/SidebarTrigger.svelte +17 -5
  151. package/dist/components/sidebar/SidebarTrigger.svelte.d.ts +4 -2
  152. package/dist/components/skeleton/Skeleton.svelte +26 -16
  153. package/dist/components/skeleton/Skeleton.svelte.d.ts +4 -2
  154. package/dist/components/spinner/Spinner.svelte +71 -46
  155. package/dist/components/spinner/Spinner.svelte.d.ts +2 -1
  156. package/dist/components/switch/Switch.svelte +126 -65
  157. package/dist/components/switch/Switch.svelte.d.ts +4 -2
  158. package/dist/components/table/Table.svelte +135 -76
  159. package/dist/components/table/Table.svelte.d.ts +12 -2
  160. package/dist/components/tabs/Tabs.svelte +173 -116
  161. package/dist/components/tabs/Tabs.svelte.d.ts +10 -8
  162. package/dist/components/textarea/Textarea.svelte +76 -42
  163. package/dist/components/textarea/Textarea.svelte.d.ts +4 -1
  164. package/dist/components/time-picker/TimePicker.svelte +214 -85
  165. package/dist/components/time-picker/TimePicker.svelte.d.ts +18 -1
  166. package/dist/components/toaster/Toaster.svelte +132 -70
  167. package/dist/components/toaster/Toaster.svelte.d.ts +18 -2
  168. package/dist/components/toaster/toast.svelte.d.ts +3 -3
  169. package/dist/components/toggle/Toggle.svelte +25 -4
  170. package/dist/components/toggle/Toggle.svelte.d.ts +1 -1
  171. package/dist/components/tooltip/Tooltip.svelte +87 -58
  172. package/dist/components/tooltip/Tooltip.svelte.d.ts +4 -2
  173. package/dist/icon.d.ts +12 -0
  174. package/dist/icon.js +1 -0
  175. package/dist/index.d.ts +6 -0
  176. package/dist/index.js +5 -0
  177. package/dist/internal/icons/ArrowDown.svelte +14 -0
  178. package/dist/internal/icons/ArrowDown.svelte.d.ts +4 -0
  179. package/dist/internal/icons/ArrowUp.svelte +14 -0
  180. package/dist/internal/icons/ArrowUp.svelte.d.ts +4 -0
  181. package/dist/internal/icons/Calendar.svelte +16 -0
  182. package/dist/internal/icons/Calendar.svelte.d.ts +4 -0
  183. package/dist/internal/icons/Check.svelte +8 -0
  184. package/dist/internal/icons/Check.svelte.d.ts +4 -0
  185. package/dist/internal/icons/ChevronDown.svelte +8 -0
  186. package/dist/internal/icons/ChevronDown.svelte.d.ts +4 -0
  187. package/dist/internal/icons/ChevronLeft.svelte +8 -0
  188. package/dist/internal/icons/ChevronLeft.svelte.d.ts +4 -0
  189. package/dist/internal/icons/ChevronRight.svelte +8 -0
  190. package/dist/internal/icons/ChevronRight.svelte.d.ts +4 -0
  191. package/dist/internal/icons/ChevronUp.svelte +8 -0
  192. package/dist/internal/icons/ChevronUp.svelte.d.ts +4 -0
  193. package/dist/internal/icons/ChevronsUpDown.svelte +14 -0
  194. package/dist/internal/icons/ChevronsUpDown.svelte.d.ts +4 -0
  195. package/dist/internal/icons/Clock.svelte +14 -0
  196. package/dist/internal/icons/Clock.svelte.d.ts +4 -0
  197. package/dist/internal/icons/Ellipsis.svelte +15 -0
  198. package/dist/internal/icons/Ellipsis.svelte.d.ts +4 -0
  199. package/dist/internal/icons/Icon.svelte +33 -0
  200. package/dist/internal/icons/Icon.svelte.d.ts +8 -0
  201. package/dist/internal/icons/Minus.svelte +8 -0
  202. package/dist/internal/icons/Minus.svelte.d.ts +4 -0
  203. package/dist/internal/icons/PanelLeft.svelte +14 -0
  204. package/dist/internal/icons/PanelLeft.svelte.d.ts +4 -0
  205. package/dist/internal/icons/Plus.svelte +14 -0
  206. package/dist/internal/icons/Plus.svelte.d.ts +4 -0
  207. package/dist/internal/icons/User.svelte +14 -0
  208. package/dist/internal/icons/User.svelte.d.ts +4 -0
  209. package/dist/internal/icons/X.svelte +14 -0
  210. package/dist/internal/icons/X.svelte.d.ts +4 -0
  211. package/dist/styles/tokens.css +39 -41
  212. package/package.json +5 -10
  213. package/dist/icons.d.ts +0 -2
  214. package/dist/icons.js +0 -4
@@ -1,7 +1,8 @@
1
1
  <script lang="ts">
2
- import { tick } from 'svelte';
2
+ import { tick, type Snippet } from 'svelte';
3
3
  import type { HTMLAttributes } from 'svelte/elements';
4
- import { ChevronLeft, ChevronRight } from '@lucide/svelte';
4
+ import ChevronLeft from '../../internal/icons/ChevronLeft.svelte';
5
+ import ChevronRight from '../../internal/icons/ChevronRight.svelte';
5
6
  import Button from '../button/Button.svelte';
6
7
  import {
7
8
  addDays,
@@ -13,10 +14,22 @@
13
14
  parseMonth,
14
15
  parseWeek,
15
16
  sameDay,
16
- startOfWeek
17
+ startOfWeek,
18
+ weekdayNames
17
19
  } from './dates.js';
18
20
 
19
- type Props = Omit<HTMLAttributes<HTMLDivElement>, 'onselect'> & {
21
+ type Labels = {
22
+ previousMonth: string;
23
+ nextMonth: string;
24
+ previousYear: string;
25
+ nextYear: string;
26
+ /** Hidden header of the week number column in week mode. */
27
+ week: string;
28
+ };
29
+
30
+ type Props = Omit<HTMLAttributes<HTMLDivElement>, 'onselect' | 'children'> & {
31
+ /** The root element. Bindable. */
32
+ ref?: HTMLDivElement | null;
20
33
  /** Picks a day (`YYYY-MM-DD`), an ISO week (`YYYY-Www`) or a month (`YYYY-MM`), matching the input types. */
21
34
  mode?: 'date' | 'week' | 'month';
22
35
  /** Bindable, in the format of the mode. */
@@ -27,15 +40,33 @@
27
40
  max?: string;
28
41
  /** BCP 47 locale for month and weekday names. Defaults to the browser's. */
29
42
  locale?: string;
43
+ /** First day of the week, 0 (Sunday) to 6 (Saturday). Week mode always starts on Monday, like ISO weeks. */
44
+ firstDayOfWeek?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
45
+ /** Texts for the navigation buttons and the week column, e.g. to translate them. */
46
+ labels?: Partial<Labels>;
47
+ /** Replaces the content of a day cell. Not used in month mode. */
48
+ day?: Snippet<[date: Date]>;
30
49
  onselect?: (value: string) => void;
31
50
  };
32
51
 
52
+ const defaultLabels: Labels = {
53
+ previousMonth: 'Previous month',
54
+ nextMonth: 'Next month',
55
+ previousYear: 'Previous year',
56
+ nextYear: 'Next year',
57
+ week: 'Week'
58
+ };
59
+
33
60
  let {
61
+ ref = $bindable(null),
34
62
  mode = 'date',
35
63
  value = $bindable(''),
36
64
  min,
37
65
  max,
38
66
  locale,
67
+ firstDayOfWeek = 1,
68
+ labels,
69
+ day: dayContent,
39
70
  onselect,
40
71
  class: className,
41
72
  ...rest
@@ -43,6 +74,9 @@
43
74
 
44
75
  const today = new Date();
45
76
 
77
+ let text = $derived({ ...defaultLabels, ...labels });
78
+ let firstDay = $derived(mode === 'week' ? 1 : firstDayOfWeek);
79
+
46
80
  function parse(input: string | undefined) {
47
81
  if (mode === 'week') return parseWeek(input);
48
82
  if (mode === 'month') return parseMonth(input);
@@ -73,14 +107,10 @@
73
107
  : new Intl.DateTimeFormat(locale, { month: 'long', year: 'numeric' }).format(focused)
74
108
  );
75
109
 
76
- let weekdays = $derived(
77
- Array.from({ length: 7 }, (_, i) =>
78
- new Intl.DateTimeFormat(locale, { weekday: 'short' }).format(new Date(2024, 0, 1 + i))
79
- )
80
- );
110
+ let weekdays = $derived(weekdayNames(locale, firstDay));
81
111
 
82
112
  let weeks = $derived.by(() => {
83
- const start = startOfWeek(new Date(focused.getFullYear(), focused.getMonth(), 1));
113
+ const start = startOfWeek(new Date(focused.getFullYear(), focused.getMonth(), 1), firstDay);
84
114
  return Array.from({ length: 6 }, (_, w) =>
85
115
  Array.from({ length: 7 }, (_, d) => addDays(start, w * 7 + d))
86
116
  );
@@ -125,11 +155,12 @@
125
155
  ArrowRight: unit(1),
126
156
  ArrowUp: unit(-columns),
127
157
  ArrowDown: unit(columns),
128
- Home: mode === 'month' ? new Date(focused.getFullYear(), 0, 1) : startOfWeek(focused),
158
+ Home:
159
+ mode === 'month' ? new Date(focused.getFullYear(), 0, 1) : startOfWeek(focused, firstDay),
129
160
  End:
130
161
  mode === 'month'
131
162
  ? new Date(focused.getFullYear(), 11, 1)
132
- : addDays(startOfWeek(focused), 6),
163
+ : addDays(startOfWeek(focused, firstDay), 6),
133
164
  PageUp:
134
165
  mode === 'month'
135
166
  ? new Date(focused.getFullYear() - 1, focused.getMonth(), 1)
@@ -147,13 +178,13 @@
147
178
  }
148
179
  </script>
149
180
 
150
- <div {...rest} class={['calendar', `calendar--${mode}`, className]}>
181
+ <div {...rest} bind:this={ref} class={['calendar', `calendar--${mode}`, className]}>
151
182
  <div class="calendar-header">
152
183
  <Button
153
184
  variant="ghost"
154
185
  size="sm"
155
186
  icon={ChevronLeft}
156
- label={mode === 'month' ? 'Previous year' : 'Previous month'}
187
+ label={mode === 'month' ? text.previousYear : text.previousMonth}
157
188
  onclick={() => page(-1)}
158
189
  />
159
190
  <span class="calendar-title" aria-live="polite">{title}</span>
@@ -161,7 +192,7 @@
161
192
  variant="ghost"
162
193
  size="sm"
163
194
  icon={ChevronRight}
164
- label={mode === 'month' ? 'Next year' : 'Next month'}
195
+ label={mode === 'month' ? text.nextYear : text.nextMonth}
165
196
  onclick={() => page(1)}
166
197
  />
167
198
  </div>
@@ -202,7 +233,7 @@
202
233
  <thead>
203
234
  <tr>
204
235
  {#if mode === 'week'}<th class="calendar-weeknumber" scope="col"
205
- ><span class="calendar-hidden">Week</span></th
236
+ ><span class="calendar-hidden">{text.week}</span></th
206
237
  >{/if}
207
238
  {#each weekdays as weekday (weekday)}
208
239
  <th scope="col">{weekday}</th>
@@ -236,7 +267,7 @@
236
267
  disabled={outOfRange(day)}
237
268
  onclick={() => select(day)}
238
269
  >
239
- {day.getDate()}
270
+ {#if dayContent}{@render dayContent(day)}{:else}{day.getDate()}{/if}
240
271
  </button>
241
272
  </td>
242
273
  {/each}
@@ -248,154 +279,211 @@
248
279
  </div>
249
280
 
250
281
  <style>
251
- .calendar {
252
- display: flex;
253
- flex-direction: column;
254
- gap: 8px;
255
- width: fit-content;
256
- font-size: 13px;
257
- color: var(--color-text);
258
- user-select: none;
259
- }
282
+ @layer svelte-ui {
283
+ .calendar {
284
+ display: flex;
285
+ flex-direction: column;
286
+ gap: 8px;
287
+ width: fit-content;
288
+ font-size: 13px;
289
+ color: var(--color-text);
290
+ user-select: none;
291
+ }
260
292
 
261
- .calendar-header {
262
- display: flex;
263
- align-items: center;
264
- justify-content: space-between;
265
- gap: 8px;
266
- }
293
+ .calendar-header {
294
+ display: flex;
295
+ align-items: center;
296
+ justify-content: space-between;
297
+ gap: 8px;
298
+ }
267
299
 
268
- .calendar-title {
269
- font-weight: 600;
270
- text-transform: capitalize;
271
- }
300
+ .calendar-title {
301
+ font-weight: 600;
302
+ text-transform: capitalize;
303
+ }
272
304
 
273
- .calendar-grid {
274
- border-collapse: collapse;
275
- border-spacing: 0;
276
- table-layout: fixed;
277
- }
305
+ .calendar-grid {
306
+ border-collapse: collapse;
307
+ border-spacing: 0;
308
+ table-layout: fixed;
309
+ }
278
310
 
279
- .calendar-grid th {
280
- height: 28px;
281
- padding: 0;
282
- font-size: 12px;
283
- font-weight: 400;
284
- color: var(--color-text-muted);
285
- }
311
+ .calendar-grid th {
312
+ height: 28px;
313
+ padding: 0;
314
+ font-size: 12px;
315
+ font-weight: 400;
316
+ color: var(--color-text-muted);
317
+ }
286
318
 
287
- .calendar-grid td {
288
- width: 32px;
289
- padding: 1px 0;
290
- }
319
+ .calendar-grid td {
320
+ width: 32px;
321
+ padding: 1px 0;
322
+ }
291
323
 
292
- .calendar-weeknumber {
293
- width: 28px;
294
- padding-right: 4px;
295
- font-variant-numeric: tabular-nums;
296
- }
324
+ .calendar-weeknumber {
325
+ width: 28px;
326
+ padding-right: 4px;
327
+ font-variant-numeric: tabular-nums;
328
+ }
297
329
 
298
- .calendar-hidden {
299
- position: absolute;
300
- width: 1px;
301
- height: 1px;
302
- overflow: hidden;
303
- clip-path: inset(50%);
304
- white-space: nowrap;
305
- }
330
+ .calendar-hidden {
331
+ position: absolute;
332
+ width: 1px;
333
+ height: 1px;
334
+ overflow: hidden;
335
+ clip-path: inset(50%);
336
+ white-space: nowrap;
337
+ }
306
338
 
307
- .calendar-months {
308
- display: grid;
309
- grid-template-columns: repeat(3, 1fr);
310
- gap: 4px;
311
- width: 224px;
312
- }
339
+ .calendar-months {
340
+ display: grid;
341
+ grid-template-columns: repeat(3, 1fr);
342
+ gap: 4px;
343
+ width: 224px;
344
+ }
313
345
 
314
- .calendar-cell {
315
- display: flex;
316
- align-items: center;
317
- justify-content: center;
318
- width: 32px;
319
- height: 32px;
320
- padding: 0;
321
- font-family: inherit;
322
- font-size: 13px;
323
- font-variant-numeric: tabular-nums;
324
- color: var(--color-text);
325
- background-color: transparent;
326
- border: none;
327
- border-radius: 8px;
328
- outline: none;
329
- cursor: pointer;
330
- transition:
331
- background-color 200ms ease,
332
- color 200ms ease;
333
- }
346
+ .calendar-cell {
347
+ display: flex;
348
+ align-items: center;
349
+ justify-content: center;
350
+ width: 32px;
351
+ height: 32px;
352
+ padding: 0;
353
+ font-family: inherit;
354
+ font-size: 13px;
355
+ font-variant-numeric: tabular-nums;
356
+ color: var(--color-text);
357
+ background-color: transparent;
358
+ border: none;
359
+ border-radius: 8px;
360
+ outline: none;
361
+ cursor: pointer;
362
+ transition:
363
+ background-color 200ms ease,
364
+ color 200ms ease;
365
+ }
334
366
 
335
- .calendar-months .calendar-cell {
336
- width: 100%;
337
- height: 40px;
338
- text-transform: capitalize;
339
- }
367
+ .calendar-months .calendar-cell {
368
+ width: 100%;
369
+ height: 40px;
370
+ text-transform: capitalize;
371
+ }
340
372
 
341
- .calendar-cell:hover:not(:disabled) {
342
- background-color: var(--color-surface);
343
- }
373
+ .calendar-cell:hover:not(:disabled) {
374
+ background-color: var(--color-surface);
375
+ }
344
376
 
345
- .calendar-cell:focus-visible {
346
- outline: 2px solid var(--color-accent);
347
- outline-offset: -2px;
348
- }
377
+ .calendar-cell:focus-visible {
378
+ outline: 2px solid var(--color-accent);
379
+ outline-offset: -2px;
380
+ }
349
381
 
350
- .calendar-cell--outside {
351
- color: var(--color-text-faint);
352
- }
382
+ .calendar-cell--outside {
383
+ color: var(--color-text-faint);
384
+ }
353
385
 
354
- .calendar-cell--today {
355
- font-weight: 600;
356
- text-decoration: underline;
357
- text-underline-offset: 4px;
358
- }
386
+ .calendar-cell--today {
387
+ font-weight: 600;
388
+ text-decoration: underline;
389
+ text-underline-offset: 4px;
390
+ }
359
391
 
360
- .calendar-cell:disabled {
361
- cursor: not-allowed;
362
- opacity: 0.35;
363
- }
392
+ .calendar-cell:disabled {
393
+ cursor: not-allowed;
394
+ opacity: 0.35;
395
+ }
364
396
 
365
- .calendar-cell--selected,
366
- .calendar-cell--selected:hover:not(:disabled),
367
- .calendar-row--selected .calendar-cell,
368
- .calendar-row--selected .calendar-cell:hover:not(:disabled) {
369
- color: var(--color-accent-foreground);
370
- background-color: var(--color-accent);
371
- }
397
+ .calendar-cell--selected,
398
+ .calendar-cell--selected:hover:not(:disabled),
399
+ .calendar-row--selected .calendar-cell,
400
+ .calendar-row--selected .calendar-cell:hover:not(:disabled) {
401
+ color: var(--color-accent-foreground);
402
+ background-color: var(--color-accent);
403
+ }
372
404
 
373
- .calendar-cell--selected:focus-visible,
374
- .calendar-row--selected .calendar-cell:focus-visible {
375
- outline-color: var(--color-accent-foreground);
376
- }
405
+ .calendar-cell--selected:focus-visible,
406
+ .calendar-row--selected .calendar-cell:focus-visible {
407
+ outline-color: var(--color-accent-foreground);
408
+ }
377
409
 
378
- /* Week mode: a row reads as one pill */
379
- .calendar--week tbody tr:hover .calendar-cell:not(:disabled) {
380
- background-color: var(--color-surface);
381
- }
410
+ /* Week mode: a row reads as one pill */
411
+ .calendar--week tbody tr:hover .calendar-cell:not(:disabled) {
412
+ background-color: var(--color-surface);
413
+ }
382
414
 
383
- .calendar--week tbody tr.calendar-row--selected .calendar-cell {
384
- background-color: var(--color-accent);
385
- }
415
+ .calendar--week tbody tr.calendar-row--selected .calendar-cell {
416
+ background-color: var(--color-accent);
417
+ }
386
418
 
387
- .calendar--week .calendar-cell {
388
- width: 100%;
389
- border-radius: 0;
390
- }
419
+ .calendar--week .calendar-cell {
420
+ width: 100%;
421
+ border-radius: 0;
422
+ }
391
423
 
392
- .calendar--week td:nth-child(2) .calendar-cell {
393
- border-start-start-radius: 8px;
394
- border-end-start-radius: 8px;
395
- }
424
+ .calendar--week td:nth-child(2) .calendar-cell {
425
+ border-start-start-radius: 8px;
426
+ border-end-start-radius: 8px;
427
+ }
428
+
429
+ @media (pointer: coarse) {
430
+ .calendar-grid td {
431
+ width: 44px;
432
+ }
433
+
434
+ .calendar-cell {
435
+ min-width: 44px;
436
+ min-height: 44px;
437
+ }
438
+
439
+ .calendar-months {
440
+ width: 252px;
441
+ }
442
+
443
+ .calendar-months .calendar-cell {
444
+ min-height: 44px;
445
+ }
396
446
 
397
- .calendar--week td:last-child .calendar-cell {
398
- border-start-end-radius: 8px;
399
- border-end-end-radius: 8px;
447
+ .calendar--week .calendar-cell {
448
+ min-width: 0;
449
+ }
450
+ }
451
+
452
+ @media (forced-colors: active) {
453
+ .calendar-cell:disabled {
454
+ color: GrayText;
455
+ opacity: 1;
456
+ }
457
+
458
+ .calendar-cell:focus-visible {
459
+ outline-color: Highlight;
460
+ }
461
+
462
+ .calendar-cell--selected,
463
+ .calendar-cell--selected:hover:not(:disabled),
464
+ .calendar-row--selected .calendar-cell,
465
+ .calendar-row--selected .calendar-cell:hover:not(:disabled),
466
+ .calendar--week tbody tr.calendar-row--selected .calendar-cell {
467
+ forced-color-adjust: none;
468
+ color: HighlightText;
469
+ background-color: Highlight;
470
+ }
471
+
472
+ .calendar-cell--selected:focus-visible,
473
+ .calendar-row--selected .calendar-cell:focus-visible {
474
+ outline-color: CanvasText;
475
+ }
476
+ }
477
+
478
+ @media (prefers-reduced-motion: reduce) {
479
+ .calendar-cell {
480
+ transition: none;
481
+ }
482
+ }
483
+
484
+ .calendar--week td:last-child .calendar-cell {
485
+ border-start-end-radius: 8px;
486
+ border-end-end-radius: 8px;
487
+ }
400
488
  }
401
489
  </style>
@@ -1,5 +1,16 @@
1
+ import { type Snippet } from 'svelte';
1
2
  import type { HTMLAttributes } from 'svelte/elements';
2
- type Props = Omit<HTMLAttributes<HTMLDivElement>, 'onselect'> & {
3
+ type Labels = {
4
+ previousMonth: string;
5
+ nextMonth: string;
6
+ previousYear: string;
7
+ nextYear: string;
8
+ /** Hidden header of the week number column in week mode. */
9
+ week: string;
10
+ };
11
+ type Props = Omit<HTMLAttributes<HTMLDivElement>, 'onselect' | 'children'> & {
12
+ /** The root element. Bindable. */
13
+ ref?: HTMLDivElement | null;
3
14
  /** Picks a day (`YYYY-MM-DD`), an ISO week (`YYYY-Www`) or a month (`YYYY-MM`), matching the input types. */
4
15
  mode?: 'date' | 'week' | 'month';
5
16
  /** Bindable, in the format of the mode. */
@@ -10,8 +21,14 @@ type Props = Omit<HTMLAttributes<HTMLDivElement>, 'onselect'> & {
10
21
  max?: string;
11
22
  /** BCP 47 locale for month and weekday names. Defaults to the browser's. */
12
23
  locale?: string;
24
+ /** First day of the week, 0 (Sunday) to 6 (Saturday). Week mode always starts on Monday, like ISO weeks. */
25
+ firstDayOfWeek?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
26
+ /** Texts for the navigation buttons and the week column, e.g. to translate them. */
27
+ labels?: Partial<Labels>;
28
+ /** Replaces the content of a day cell. Not used in month mode. */
29
+ day?: Snippet<[date: Date]>;
13
30
  onselect?: (value: string) => void;
14
31
  };
15
- declare const Calendar: import("svelte").Component<Props, {}, "value">;
32
+ declare const Calendar: import("svelte").Component<Props, {}, "ref" | "value">;
16
33
  type Calendar = ReturnType<typeof Calendar>;
17
34
  export default Calendar;
@@ -8,5 +8,8 @@ export declare function formatWeek(date: Date): string;
8
8
  export declare function parseWeek(value: string | undefined): Date | undefined;
9
9
  export declare function addDays(date: Date, days: number): Date;
10
10
  export declare function addMonths(date: Date, months: number): Date;
11
- export declare function startOfWeek(date: Date): Date;
11
+ /** `firstDay` is 0 (Sunday) to 6 (Saturday); defaults to Monday. */
12
+ export declare function startOfWeek(date: Date, firstDay?: number): Date;
13
+ /** Short weekday names starting at `firstDay` (0 is Sunday). */
14
+ export declare function weekdayNames(locale: string | undefined, firstDay?: number): string[];
12
15
  export declare function sameDay(a: Date | undefined, b: Date | undefined): boolean;
@@ -40,8 +40,14 @@ export function addMonths(date, months) {
40
40
  result.setDate(Math.min(date.getDate(), lastDay));
41
41
  return result;
42
42
  }
43
- export function startOfWeek(date) {
44
- return addDays(date, -((date.getDay() + 6) % 7));
43
+ /** `firstDay` is 0 (Sunday) to 6 (Saturday); defaults to Monday. */
44
+ export function startOfWeek(date, firstDay = 1) {
45
+ return addDays(date, -((date.getDay() - firstDay + 7) % 7));
46
+ }
47
+ /** Short weekday names starting at `firstDay` (0 is Sunday). */
48
+ export function weekdayNames(locale, firstDay = 1) {
49
+ const formatter = new Intl.DateTimeFormat(locale, { weekday: 'short' });
50
+ return Array.from({ length: 7 }, (_, i) => formatter.format(new Date(2024, 0, 7 + firstDay + i)));
45
51
  }
46
52
  export function sameDay(a, b) {
47
53
  return !!a && !!b && formatDate(a) === formatDate(b);
@@ -3,53 +3,69 @@
3
3
  import type { HTMLAttributes } from 'svelte/elements';
4
4
 
5
5
  type Props = Omit<HTMLAttributes<HTMLDivElement>, 'children'> & {
6
+ /** The root element. Bindable. */
7
+ ref?: HTMLDivElement | null;
6
8
  variant?: 'outline' | 'secondary';
7
9
  /** CardHeader, CardContent and CardFooter; an `<img>` first renders edge to edge. */
8
10
  children: Snippet;
9
11
  };
10
12
 
11
- let { variant = 'outline', class: className, children, ...rest }: Props = $props();
13
+ let {
14
+ ref = $bindable(null),
15
+ variant = 'outline',
16
+ class: className,
17
+ children,
18
+ ...rest
19
+ }: Props = $props();
12
20
  </script>
13
21
 
14
- <div {...rest} class={['card', `card--${variant}`, className]}>
22
+ <div {...rest} bind:this={ref} class={['card', `card--${variant}`, className]}>
15
23
  {@render children()}
16
24
  </div>
17
25
 
18
26
  <style>
19
- .card {
20
- --card-spacing: 14px;
21
- display: flex;
22
- flex-direction: column;
23
- gap: var(--card-spacing);
24
- box-sizing: border-box;
25
- padding-block: var(--card-spacing);
26
- overflow: hidden;
27
- font-size: 13px;
28
- color: var(--color-text);
29
- border-radius: 14px;
30
- }
27
+ @layer svelte-ui {
28
+ .card {
29
+ --card-spacing: 14px;
30
+ display: flex;
31
+ flex-direction: column;
32
+ gap: var(--card-spacing);
33
+ box-sizing: border-box;
34
+ padding-block: var(--card-spacing);
35
+ overflow: hidden;
36
+ font-size: 13px;
37
+ color: var(--color-text);
38
+ border-radius: 14px;
39
+ }
31
40
 
32
- .card--outline {
33
- background-color: var(--color-bg);
34
- border: 1px solid var(--color-border);
35
- }
41
+ .card--outline {
42
+ background-color: var(--color-bg);
43
+ border: 1px solid var(--color-border);
44
+ }
36
45
 
37
- .card--secondary {
38
- background-color: var(--color-surface);
39
- border: 1px solid transparent;
40
- }
46
+ .card--secondary {
47
+ background-color: var(--color-surface);
48
+ border: 1px solid transparent;
49
+ }
41
50
 
42
- .card:has(> :global(img:first-child)) {
43
- padding-top: 0;
44
- }
51
+ .card:has(> :global(img:first-child)) {
52
+ padding-top: 0;
53
+ }
45
54
 
46
- .card:has(> :global(.card-footer)) {
47
- padding-bottom: 0;
48
- }
55
+ .card:has(> :global(.card-footer)) {
56
+ padding-bottom: 0;
57
+ }
58
+
59
+ @media (forced-colors: active) {
60
+ .card--secondary {
61
+ border-color: CanvasText;
62
+ }
63
+ }
49
64
 
50
- .card > :global(img) {
51
- display: block;
52
- width: 100%;
53
- object-fit: cover;
65
+ .card > :global(img) {
66
+ display: block;
67
+ width: 100%;
68
+ object-fit: cover;
69
+ }
54
70
  }
55
71
  </style>
@@ -1,10 +1,12 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  import type { HTMLAttributes } from 'svelte/elements';
3
3
  type Props = Omit<HTMLAttributes<HTMLDivElement>, 'children'> & {
4
+ /** The root element. Bindable. */
5
+ ref?: HTMLDivElement | null;
4
6
  variant?: 'outline' | 'secondary';
5
7
  /** CardHeader, CardContent and CardFooter; an `<img>` first renders edge to edge. */
6
8
  children: Snippet;
7
9
  };
8
- declare const Card: import("svelte").Component<Props, {}, "">;
10
+ declare const Card: import("svelte").Component<Props, {}, "ref">;
9
11
  type Card = ReturnType<typeof Card>;
10
12
  export default Card;