@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
@@ -5,68 +5,93 @@
5
5
  size?: 'sm' | 'md' | 'lg';
6
6
  /** Accessible name. Ignored when the spinner is `aria-hidden`, e.g. inside a loading Button. */
7
7
  label?: string;
8
+ ref?: HTMLSpanElement | null;
8
9
  };
9
10
 
10
- let { size = 'md', label = 'Loading', class: className, ...rest }: Props = $props();
11
+ let {
12
+ size = 'md',
13
+ label = 'Loading',
14
+ ref = $bindable(null),
15
+ class: className,
16
+ ...rest
17
+ }: Props = $props();
11
18
  </script>
12
19
 
13
- <span {...rest} role="status" aria-label={label} class={['spinner', `spinner--${size}`, className]}
20
+ <span
21
+ {...rest}
22
+ bind:this={ref}
23
+ role="status"
24
+ aria-label={label}
25
+ class={['spinner', `spinner--${size}`, className]}
14
26
  ></span>
15
27
 
16
28
  <style>
17
- @property --spinner-angle {
18
- syntax: '<angle>';
19
- initial-value: 0deg;
20
- inherits: false;
21
- }
29
+ @layer svelte-ui {
30
+ @property --spinner-angle {
31
+ syntax: '<angle>';
32
+ initial-value: 0deg;
33
+ inherits: false;
34
+ }
22
35
 
23
- .spinner {
24
- --spinner-size: 16px;
25
- position: relative;
26
- display: inline-block;
27
- flex-shrink: 0;
28
- width: var(--spinner-size);
29
- height: var(--spinner-size);
30
- }
36
+ .spinner {
37
+ --spinner-size: 16px;
38
+ position: relative;
39
+ display: inline-block;
40
+ flex-shrink: 0;
41
+ width: var(--spinner-size);
42
+ height: var(--spinner-size);
43
+ }
31
44
 
32
- .spinner--sm {
33
- --spinner-size: 14px;
34
- }
45
+ .spinner--sm {
46
+ --spinner-size: 14px;
47
+ }
35
48
 
36
- .spinner--lg {
37
- --spinner-size: 20px;
38
- }
49
+ .spinner--lg {
50
+ --spinner-size: 20px;
51
+ }
39
52
 
40
- .spinner::before,
41
- .spinner::after {
42
- content: '';
43
- position: absolute;
44
- inset: 0;
45
- box-sizing: border-box;
46
- border: calc(var(--spinner-size) / 8) solid currentColor;
47
- border-radius: 30%;
48
- }
53
+ .spinner::before,
54
+ .spinner::after {
55
+ content: '';
56
+ position: absolute;
57
+ inset: 0;
58
+ box-sizing: border-box;
59
+ border: calc(var(--spinner-size) / 8) solid currentColor;
60
+ border-radius: 30%;
61
+ }
49
62
 
50
- /* Track */
51
- .spinner::before {
52
- opacity: 0.2;
53
- }
63
+ /* Track */
64
+ .spinner::before {
65
+ opacity: 0.2;
66
+ }
54
67
 
55
- /* Handle: a conic mask whose head is opaque and whose tail fades out */
56
- .spinner::after {
57
- mask: conic-gradient(from var(--spinner-angle), transparent 0% 60%, #000 100%);
58
- animation: spinner-rotate 1s linear infinite;
59
- }
68
+ /* Handle: a conic mask whose head is opaque and whose tail fades out */
69
+ .spinner::after {
70
+ mask: conic-gradient(from var(--spinner-angle), transparent 0% 60%, #000 100%);
71
+ animation: spinner-rotate 1s linear infinite;
72
+ }
60
73
 
61
- @keyframes spinner-rotate {
62
- to {
63
- --spinner-angle: 360deg;
74
+ @keyframes spinner-rotate {
75
+ to {
76
+ --spinner-angle: 360deg;
77
+ }
64
78
  }
65
- }
66
79
 
67
- @media (prefers-reduced-motion: reduce) {
68
- .spinner::after {
69
- animation-duration: 3s;
80
+ @media (forced-colors: active) {
81
+ .spinner::before {
82
+ opacity: 1;
83
+ border-color: GrayText;
84
+ }
85
+
86
+ .spinner::after {
87
+ border-color: Highlight;
88
+ }
89
+ }
90
+
91
+ @media (prefers-reduced-motion: reduce) {
92
+ .spinner::after {
93
+ animation-duration: 3s;
94
+ }
70
95
  }
71
96
  }
72
97
  </style>
@@ -3,7 +3,8 @@ type Props = Omit<HTMLAttributes<HTMLSpanElement>, 'children'> & {
3
3
  size?: 'sm' | 'md' | 'lg';
4
4
  /** Accessible name. Ignored when the spinner is `aria-hidden`, e.g. inside a loading Button. */
5
5
  label?: string;
6
+ ref?: HTMLSpanElement | null;
6
7
  };
7
- declare const Spinner: import("svelte").Component<Props, {}, "">;
8
+ declare const Spinner: import("svelte").Component<Props, {}, "ref">;
8
9
  type Spinner = ReturnType<typeof Spinner>;
9
10
  export default Spinner;
@@ -1,88 +1,149 @@
1
1
  <script lang="ts">
2
2
  import type { HTMLInputAttributes } from 'svelte/elements';
3
3
 
4
- type Props = Omit<HTMLInputAttributes, 'type' | 'role'>;
4
+ type Props = Omit<HTMLInputAttributes, 'type' | 'role'> & {
5
+ ref?: HTMLInputElement | null;
6
+ };
5
7
 
6
- let { checked = $bindable(false), class: className, ...rest }: Props = $props();
8
+ let {
9
+ checked = $bindable(false),
10
+ ref = $bindable(null),
11
+ class: className,
12
+ ...rest
13
+ }: Props = $props();
7
14
  </script>
8
15
 
9
16
  <span class={['switch', className]}>
10
- <input {...rest} type="checkbox" role="switch" bind:checked />
17
+ <input {...rest} bind:this={ref} type="checkbox" role="switch" bind:checked />
11
18
  <span class="switch-thumb" aria-hidden="true"></span>
12
19
  </span>
13
20
 
14
21
  <style>
15
- .switch {
16
- position: relative;
17
- display: inline-flex;
18
- flex-shrink: 0;
19
- width: 36px;
20
- height: 22px;
21
- }
22
+ @layer svelte-ui {
23
+ .switch {
24
+ position: relative;
25
+ display: inline-flex;
26
+ flex-shrink: 0;
27
+ width: 36px;
28
+ height: 22px;
29
+ }
22
30
 
23
- input {
24
- appearance: none;
25
- box-sizing: border-box;
26
- width: 100%;
27
- height: 100%;
28
- margin: 0;
29
- background-color: var(--color-surface);
30
- border: 1px solid var(--color-border);
31
- border-radius: 9px;
32
- outline: none;
33
- cursor: pointer;
34
- transition:
35
- background-color 200ms ease,
36
- border-color 200ms ease;
37
- }
31
+ input {
32
+ appearance: none;
33
+ box-sizing: border-box;
34
+ width: 100%;
35
+ height: 100%;
36
+ margin: 0;
37
+ background-color: var(--color-surface);
38
+ border: 1px solid var(--color-border);
39
+ border-radius: 9px;
40
+ outline: none;
41
+ cursor: pointer;
42
+ transition:
43
+ background-color 200ms ease,
44
+ border-color 200ms ease;
45
+ }
38
46
 
39
- input:checked {
40
- background-color: var(--color-accent);
41
- border-color: var(--color-accent);
42
- }
47
+ input:checked {
48
+ background-color: var(--color-accent);
49
+ border-color: var(--color-accent);
50
+ }
43
51
 
44
- input:focus-visible {
45
- outline: 2px solid var(--color-accent);
46
- outline-offset: 2px;
47
- }
52
+ input:focus-visible {
53
+ outline: 2px solid var(--color-accent);
54
+ outline-offset: 2px;
55
+ }
48
56
 
49
- input[aria-invalid='true'] {
50
- border-color: var(--color-destructive);
51
- }
57
+ input[aria-invalid='true'] {
58
+ border-color: var(--color-destructive);
59
+ }
52
60
 
53
- input:disabled {
54
- cursor: not-allowed;
55
- opacity: 0.5;
56
- }
61
+ input:disabled {
62
+ cursor: not-allowed;
63
+ opacity: 0.5;
64
+ }
57
65
 
58
- /* Radius is the track's 9px minus the 4px inset, so the corners stay concentric */
59
- .switch-thumb {
60
- position: absolute;
61
- top: 4px;
62
- left: 4px;
63
- width: 14px;
64
- height: 14px;
65
- background-color: var(--color-base);
66
- border-radius: 5px;
67
- pointer-events: none;
68
- transition:
69
- transform 200ms ease,
70
- background-color 200ms ease;
71
- }
66
+ /* Radius is the track's 9px minus the 4px inset, so the corners stay concentric */
67
+ .switch-thumb {
68
+ position: absolute;
69
+ top: 4px;
70
+ left: 4px;
71
+ width: 14px;
72
+ height: 14px;
73
+ background-color: var(--color-base);
74
+ border-radius: 5px;
75
+ pointer-events: none;
76
+ transition:
77
+ transform 200ms ease,
78
+ background-color 200ms ease;
79
+ }
72
80
 
73
- input:checked + .switch-thumb {
74
- background-color: var(--color-accent-foreground);
75
- transform: translateX(14px);
76
- }
81
+ input:checked + .switch-thumb {
82
+ background-color: var(--color-accent-foreground);
83
+ transform: translateX(14px);
84
+ }
77
85
 
78
- input:disabled + .switch-thumb {
79
- opacity: 0.5;
80
- }
86
+ input:disabled + .switch-thumb {
87
+ opacity: 0.5;
88
+ }
81
89
 
82
- @media (prefers-reduced-motion: reduce) {
83
- input,
84
- .switch-thumb {
85
- transition: none;
90
+ @media (pointer: coarse) {
91
+ input {
92
+ position: relative;
93
+ }
94
+
95
+ input::after {
96
+ content: '';
97
+ position: absolute;
98
+ top: 50%;
99
+ left: 50%;
100
+ width: max(100%, 44px);
101
+ height: max(100%, 44px);
102
+ transform: translate(-50%, -50%);
103
+ }
104
+ }
105
+
106
+ @media (forced-colors: active) {
107
+ input {
108
+ border-color: ButtonText;
109
+ }
110
+
111
+ input:checked {
112
+ background-color: Highlight;
113
+ border-color: Highlight;
114
+ }
115
+
116
+ input:disabled {
117
+ border-color: GrayText;
118
+ }
119
+
120
+ input:checked:disabled {
121
+ background-color: GrayText;
122
+ border-color: GrayText;
123
+ }
124
+
125
+ .switch-thumb {
126
+ background-color: ButtonText;
127
+ }
128
+
129
+ input:checked + .switch-thumb {
130
+ background-color: HighlightText;
131
+ }
132
+
133
+ input:disabled + .switch-thumb {
134
+ background-color: GrayText;
135
+ }
136
+
137
+ input:checked:disabled + .switch-thumb {
138
+ background-color: HighlightText;
139
+ }
140
+ }
141
+
142
+ @media (prefers-reduced-motion: reduce) {
143
+ input,
144
+ .switch-thumb {
145
+ transition: none;
146
+ }
86
147
  }
87
148
  }
88
149
  </style>
@@ -1,5 +1,7 @@
1
1
  import type { HTMLInputAttributes } from 'svelte/elements';
2
- type Props = Omit<HTMLInputAttributes, 'type' | 'role'>;
3
- declare const Switch: import("svelte").Component<Props, {}, "checked">;
2
+ type Props = Omit<HTMLInputAttributes, 'type' | 'role'> & {
3
+ ref?: HTMLInputElement | null;
4
+ };
5
+ declare const Switch: import("svelte").Component<Props, {}, "ref" | "checked">;
4
6
  type Switch = ReturnType<typeof Switch>;
5
7
  export default Switch;
@@ -35,7 +35,9 @@
35
35
 
36
36
  <script lang="ts" generics="T">
37
37
  import type { HTMLAttributes } from 'svelte/elements';
38
- import { ArrowDown, ArrowUp, ChevronsUpDown } from '@lucide/svelte';
38
+ import ArrowDown from '../../internal/icons/ArrowDown.svelte';
39
+ import ArrowUp from '../../internal/icons/ArrowUp.svelte';
40
+ import ChevronsUpDown from '../../internal/icons/ChevronsUpDown.svelte';
39
41
  import Checkbox from '../checkbox/Checkbox.svelte';
40
42
 
41
43
  type Props = Omit<HTMLAttributes<HTMLTableElement>, 'children'> & {
@@ -47,6 +49,13 @@
47
49
  selected?: T[];
48
50
  /** Identifies rows across data updates; defaults to the row object itself. */
49
51
  rowId?: (row: T) => unknown;
52
+ /** Locale used to compare strings when sorting. Defaults to the runtime locale. */
53
+ locale?: string;
54
+ /** Accessible names of the selection checkboxes. */
55
+ labels?: { selectAll?: string; selectRow?: string };
56
+ /** Rendered in a full-width row while `data` is empty. */
57
+ empty?: Snippet;
58
+ ref?: HTMLTableElement | null;
50
59
  };
51
60
 
52
61
  let {
@@ -56,10 +65,17 @@
56
65
  selection,
57
66
  selected = $bindable([]),
58
67
  rowId = (row) => row,
68
+ locale,
69
+ labels,
70
+ empty,
71
+ ref = $bindable(null),
59
72
  class: className,
60
73
  ...rest
61
74
  }: Props = $props();
62
75
 
76
+ const selectAllLabel = $derived(labels?.selectAll ?? 'Select all rows');
77
+ const selectRowLabel = $derived(labels?.selectRow ?? 'Select row');
78
+
63
79
  const columnId = (column: TableColumn<T>) => column.id ?? column.key ?? column.header;
64
80
 
65
81
  function sortValue(column: TableColumn<T>, row: T): unknown {
@@ -70,7 +86,7 @@
70
86
  function compare(a: unknown, b: unknown) {
71
87
  if (a instanceof Date && b instanceof Date) return a.getTime() - b.getTime();
72
88
  if (typeof a === 'number' && typeof b === 'number') return a - b;
73
- return String(a).localeCompare(String(b), undefined, { numeric: true });
89
+ return String(a).localeCompare(String(b), locale, { numeric: true });
74
90
  }
75
91
 
76
92
  const rows = $derived.by(() => {
@@ -114,14 +130,14 @@
114
130
  </script>
115
131
 
116
132
  <div class="table-container">
117
- <table {...rest} class={['table', className]}>
133
+ <table {...rest} bind:this={ref} class={['table', className]}>
118
134
  <thead>
119
135
  <tr>
120
136
  {#if selection}
121
137
  <th scope="col" class="table-select">
122
138
  {#if selection === 'multiple'}
123
139
  <Checkbox
124
- aria-label="Select all rows"
140
+ aria-label={selectAllLabel}
125
141
  checked={allSelected}
126
142
  indeterminate={someSelected}
127
143
  onchange={toggleAll}
@@ -165,7 +181,7 @@
165
181
  {#if selection}
166
182
  <td class="table-select">
167
183
  <Checkbox
168
- aria-label="Select row"
184
+ aria-label={selectRowLabel}
169
185
  checked={isSelected}
170
186
  onchange={() => toggleRow(row)}
171
187
  />
@@ -181,96 +197,139 @@
181
197
  </td>
182
198
  {/each}
183
199
  </tr>
200
+ {:else}
201
+ {#if empty}
202
+ <tr>
203
+ <td class="table-empty" colspan={columns.length + (selection ? 1 : 0)}>
204
+ {@render empty()}
205
+ </td>
206
+ </tr>
207
+ {/if}
184
208
  {/each}
185
209
  </tbody>
186
210
  </table>
187
211
  </div>
188
212
 
189
213
  <style>
190
- .table-container {
191
- width: 100%;
192
- overflow-x: auto;
193
- }
214
+ @layer svelte-ui {
215
+ .table-container {
216
+ width: 100%;
217
+ overflow-x: auto;
218
+ }
194
219
 
195
- .table {
196
- width: 100%;
197
- border-collapse: collapse;
198
- font-size: 13px;
199
- color: var(--color-text);
200
- }
220
+ .table {
221
+ width: 100%;
222
+ border-collapse: collapse;
223
+ font-size: 13px;
224
+ color: var(--color-text);
225
+ }
201
226
 
202
- th,
203
- td {
204
- padding: 10px 12px;
205
- white-space: nowrap;
206
- border-bottom: 1px solid var(--color-border);
207
- }
227
+ th,
228
+ td {
229
+ padding: 10px 12px;
230
+ white-space: nowrap;
231
+ border-bottom: 1px solid var(--color-border);
232
+ }
208
233
 
209
- th {
210
- font-weight: 500;
211
- color: var(--color-text-muted);
212
- }
234
+ th {
235
+ font-weight: 500;
236
+ color: var(--color-text-muted);
237
+ }
213
238
 
214
- tbody tr:last-child td {
215
- border-bottom: none;
216
- }
239
+ tbody tr:last-child td {
240
+ border-bottom: none;
241
+ }
217
242
 
218
- tbody tr:hover,
219
- tbody tr[data-selected] {
220
- background-color: var(--color-surface);
221
- }
243
+ tbody tr:hover,
244
+ tbody tr[data-selected] {
245
+ background-color: var(--color-surface);
246
+ }
222
247
 
223
- .table-left {
224
- text-align: left;
225
- }
248
+ .table-left {
249
+ text-align: left;
250
+ }
226
251
 
227
- .table-center {
228
- text-align: center;
229
- }
252
+ .table-center {
253
+ text-align: center;
254
+ }
230
255
 
231
- .table-right {
232
- text-align: right;
233
- }
256
+ .table-right {
257
+ text-align: right;
258
+ }
234
259
 
235
- .table-select {
236
- width: 16px;
237
- padding-right: 0;
238
- line-height: 0;
239
- }
260
+ .table-select {
261
+ width: 16px;
262
+ padding-right: 0;
263
+ line-height: 0;
264
+ }
240
265
 
241
- .table-sort {
242
- display: inline-flex;
243
- align-items: center;
244
- gap: 4px;
245
- margin: -2px -4px;
246
- padding: 2px 4px;
247
- font: inherit;
248
- color: inherit;
249
- background: none;
250
- border: none;
251
- border-radius: 6px;
252
- outline: none;
253
- cursor: pointer;
254
- transition: color 200ms ease;
255
- }
266
+ .table-sort {
267
+ display: inline-flex;
268
+ align-items: center;
269
+ gap: 4px;
270
+ margin: -2px -4px;
271
+ padding: 2px 4px;
272
+ font: inherit;
273
+ color: inherit;
274
+ background: none;
275
+ border: none;
276
+ border-radius: 6px;
277
+ outline: none;
278
+ cursor: pointer;
279
+ transition: color 200ms ease;
280
+ }
256
281
 
257
- .table-sort:hover,
258
- th[aria-sort='ascending'] .table-sort,
259
- th[aria-sort='descending'] .table-sort {
260
- color: var(--color-text);
261
- }
282
+ .table-sort:hover,
283
+ th[aria-sort='ascending'] .table-sort,
284
+ th[aria-sort='descending'] .table-sort {
285
+ color: var(--color-text);
286
+ }
262
287
 
263
- .table-sort:focus-visible {
264
- outline: 2px solid var(--color-accent);
265
- }
288
+ .table-sort:focus-visible {
289
+ outline: 2px solid var(--color-accent);
290
+ }
266
291
 
267
- .table-sort :global(.table-sort-icon) {
268
- width: 14px;
269
- height: 14px;
270
- flex-shrink: 0;
271
- }
292
+ .table-sort :global(.table-sort-icon) {
293
+ width: 14px;
294
+ height: 14px;
295
+ flex-shrink: 0;
296
+ }
297
+
298
+ .table-sort :global(.table-sort-icon--idle) {
299
+ opacity: 0.5;
300
+ }
301
+
302
+ .table-empty {
303
+ text-align: center;
304
+ color: var(--color-text-muted);
305
+ }
306
+
307
+ @media (pointer: coarse) {
308
+ .table-sort {
309
+ min-width: 44px;
310
+ min-height: 44px;
311
+ }
312
+ }
313
+
314
+ @media (forced-colors: active) {
315
+ tbody tr[data-selected] {
316
+ outline: 2px solid Highlight;
317
+ outline-offset: -2px;
318
+ }
319
+
320
+ .table-sort:focus-visible {
321
+ outline-color: Highlight;
322
+ }
323
+
324
+ .table-sort :global(.table-sort-icon--idle) {
325
+ opacity: 1;
326
+ }
327
+ }
272
328
 
273
- .table-sort :global(.table-sort-icon--idle) {
274
- opacity: 0.5;
329
+ @media (prefers-reduced-motion: reduce) {
330
+ .table-sort {
331
+ transition: none;
332
+ }
333
+ }
275
334
  }
276
335
  </style>
@@ -35,9 +35,19 @@ declare function $$render<T>(): {
35
35
  selected?: T[];
36
36
  /** Identifies rows across data updates; defaults to the row object itself. */
37
37
  rowId?: (row: T) => unknown;
38
+ /** Locale used to compare strings when sorting. Defaults to the runtime locale. */
39
+ locale?: string;
40
+ /** Accessible names of the selection checkboxes. */
41
+ labels?: {
42
+ selectAll?: string;
43
+ selectRow?: string;
44
+ };
45
+ /** Rendered in a full-width row while `data` is empty. */
46
+ empty?: Snippet;
47
+ ref?: HTMLTableElement | null;
38
48
  };
39
49
  exports: {};
40
- bindings: "sort" | "selected";
50
+ bindings: "ref" | "sort" | "selected";
41
51
  slots: {};
42
52
  events: {};
43
53
  };
@@ -45,7 +55,7 @@ declare class __sveltets_Render<T> {
45
55
  props(): ReturnType<typeof $$render<T>>['props'];
46
56
  events(): ReturnType<typeof $$render<T>>['events'];
47
57
  slots(): ReturnType<typeof $$render<T>>['slots'];
48
- bindings(): "sort" | "selected";
58
+ bindings(): "ref" | "sort" | "selected";
49
59
  exports(): {};
50
60
  }
51
61
  interface $$IsomorphicComponent {