@noahbaumgartner/svelte-ui 0.0.5 → 0.0.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.
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 +137 -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
@@ -4,7 +4,8 @@ type Props = Omit<HTMLAnchorAttributes, 'children'> & {
4
4
  /** External (http) links open in a new tab. */
5
5
  href: string;
6
6
  children: Snippet;
7
+ ref?: HTMLAnchorElement | null;
7
8
  };
8
- declare const Link: import("svelte").Component<Props, {}, "">;
9
+ declare const Link: import("svelte").Component<Props, {}, "ref">;
9
10
  type Link = ReturnType<typeof Link>;
10
11
  export default Link;
@@ -6,11 +6,10 @@
6
6
  colors: string[];
7
7
  /** Same seed gives the same layout; defaults to the joined colours. */
8
8
  seed?: string;
9
- /** Film grain overlay. */
10
- grain?: boolean;
9
+ ref?: HTMLDivElement | null;
11
10
  };
12
11
 
13
- let { colors, seed = '', grain = true, class: className, ...rest }: Props = $props();
12
+ let { colors, seed = '', class: className, ref = $bindable(null), ...rest }: Props = $props();
14
13
 
15
14
  function hashSeed(str: string) {
16
15
  let h = 0;
@@ -44,7 +43,8 @@
44
43
 
45
44
  <div
46
45
  {...rest}
47
- class={['mesh-gradient', grain && 'mesh-gradient--grain', className]}
46
+ bind:this={ref}
47
+ class={['mesh-gradient', className]}
48
48
  style:background-color={colors[0]}
49
49
  aria-hidden="true"
50
50
  >
@@ -62,25 +62,36 @@
62
62
  </div>
63
63
 
64
64
  <style>
65
- .mesh-gradient {
66
- position: relative;
67
- overflow: hidden;
68
- }
65
+ @layer svelte-ui {
66
+ /* Fills whatever it is placed in; size, shape and radius come from the container. */
67
+ .mesh-gradient {
68
+ position: relative;
69
+ width: 100%;
70
+ height: 100%;
71
+ overflow: hidden;
72
+ }
69
73
 
70
- .mesh-gradient-blob {
71
- position: absolute;
72
- border-radius: 50%;
73
- transform: translate(-50%, -50%);
74
- }
74
+ .mesh-gradient-blob {
75
+ position: absolute;
76
+ border-radius: 50%;
77
+ transform: translate(-50%, -50%);
78
+ }
75
79
 
76
- .mesh-gradient--grain::after {
77
- content: '';
78
- position: absolute;
79
- inset: 0;
80
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
81
- background-size: 160px 160px;
82
- opacity: 0.55;
83
- mix-blend-mode: overlay;
84
- pointer-events: none;
80
+ .mesh-gradient::after {
81
+ content: '';
82
+ position: absolute;
83
+ inset: 0;
84
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
85
+ background-size: 160px 160px;
86
+ opacity: 0.55;
87
+ mix-blend-mode: overlay;
88
+ pointer-events: none;
89
+ }
90
+
91
+ @media (forced-colors: active) {
92
+ .mesh-gradient {
93
+ forced-color-adjust: none;
94
+ }
95
+ }
85
96
  }
86
97
  </style>
@@ -4,9 +4,8 @@ type Props = Omit<HTMLAttributes<HTMLDivElement>, 'children'> & {
4
4
  colors: string[];
5
5
  /** Same seed gives the same layout; defaults to the joined colours. */
6
6
  seed?: string;
7
- /** Film grain overlay. */
8
- grain?: boolean;
7
+ ref?: HTMLDivElement | null;
9
8
  };
10
- declare const MeshGradient: import("svelte").Component<Props, {}, "">;
9
+ declare const MeshGradient: import("svelte").Component<Props, {}, "ref">;
11
10
  type MeshGradient = ReturnType<typeof MeshGradient>;
12
11
  export default MeshGradient;
@@ -8,13 +8,14 @@
8
8
 
9
9
  <script lang="ts">
10
10
  import type { Snippet } from 'svelte';
11
+ import type { HTMLAttributes } from 'svelte/elements';
11
12
  import type { Attachment } from 'svelte/attachments';
12
13
  import { prefersReducedMotion } from 'svelte/motion';
13
14
  import { cubicOut } from 'svelte/easing';
14
15
  import type { TransitionConfig } from 'svelte/transition';
15
16
  import NavigationMenu from '../navigation-menu/NavigationMenu.svelte';
16
17
 
17
- type Props = {
18
+ type Props = Omit<HTMLAttributes<HTMLElement>, 'children'> & {
18
19
  /** Whether the mobile menu is open. Bindable. */
19
20
  open?: boolean;
20
21
  /** Accessible name of the navigation landmark. */
@@ -30,6 +31,7 @@
30
31
  trigger: Snippet<[NavbarTriggerProps, boolean]>;
31
32
  /** `NavigationMenuItem`s, shown inline on desktop and stacked in the mobile menu. */
32
33
  children: Snippet;
34
+ ref?: HTMLElement | null;
33
35
  };
34
36
 
35
37
  let {
@@ -38,7 +40,10 @@
38
40
  logo,
39
41
  actions,
40
42
  trigger,
41
- children
43
+ children,
44
+ class: className,
45
+ ref = $bindable(null),
46
+ ...rest
42
47
  }: Props = $props();
43
48
 
44
49
  const id = $props.id();
@@ -111,7 +116,7 @@
111
116
  });
112
117
  </script>
113
118
 
114
- <header class="navbar" bind:offsetHeight={height}>
119
+ <header {...rest} bind:this={ref} class={['navbar', className]} bind:offsetHeight={height}>
115
120
  <div class="navbar-bar">
116
121
  <div class="navbar-start">
117
122
  {#if logo}{@render logo()}{/if}
@@ -144,123 +149,156 @@
144
149
  </header>
145
150
 
146
151
  <style>
147
- .navbar {
148
- position: sticky;
149
- top: 0;
150
- z-index: 50;
151
- background-color: var(--color-bg);
152
- user-select: none;
153
- }
152
+ @layer svelte-ui {
153
+ .navbar {
154
+ position: sticky;
155
+ top: 0;
156
+ z-index: 50;
157
+ background-color: color-mix(in srgb, var(--color-bg) 80%, transparent);
158
+ -webkit-backdrop-filter: blur(12px);
159
+ backdrop-filter: blur(12px);
160
+ user-select: none;
161
+ }
154
162
 
155
- .navbar-bar {
156
- display: flex;
157
- align-items: center;
158
- justify-content: space-between;
159
- gap: 16px;
160
- padding: 14px 16px;
161
- }
163
+ /* Without a blurred backdrop, translucent text-on-content would be hard to read */
164
+ @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
165
+ .navbar {
166
+ background-color: var(--color-bg);
167
+ }
168
+ }
162
169
 
163
- .navbar-start {
164
- display: flex;
165
- align-items: center;
166
- gap: 40px;
167
- min-width: 0;
168
- }
170
+ @media (prefers-reduced-transparency: reduce) {
171
+ .navbar {
172
+ background-color: var(--color-bg);
173
+ -webkit-backdrop-filter: none;
174
+ backdrop-filter: none;
175
+ }
176
+ }
169
177
 
170
- .navbar-end {
171
- display: flex;
172
- align-items: center;
173
- gap: 6px;
174
- }
178
+ .navbar-bar {
179
+ display: flex;
180
+ align-items: center;
181
+ justify-content: space-between;
182
+ gap: 16px;
183
+ padding: 14px var(--navbar-gutter, 16px);
184
+ }
175
185
 
176
- .navbar-desktop {
177
- display: none;
178
- }
186
+ .navbar-start {
187
+ display: flex;
188
+ align-items: center;
189
+ gap: 40px;
190
+ min-width: 0;
191
+ }
179
192
 
180
- .navbar-trigger {
181
- display: flex;
182
- }
193
+ .navbar-end {
194
+ display: flex;
195
+ align-items: center;
196
+ gap: 6px;
197
+ }
183
198
 
184
- /* Mobile menu: full-height, left-aligned rows below the bar */
185
- .navbar-panel {
186
- position: absolute;
187
- top: 100%;
188
- left: 0;
189
- right: 0;
190
- box-sizing: border-box;
191
- overflow-y: auto;
192
- overscroll-behavior: contain;
193
- background-color: var(--color-bg);
194
- }
199
+ .navbar-desktop {
200
+ display: none;
201
+ }
195
202
 
196
- .navbar-panel :global(.navigation-menu) {
197
- padding: 40px 16px 32px;
198
- }
203
+ .navbar-trigger {
204
+ display: flex;
205
+ }
199
206
 
200
- .navbar-panel :global(.navigation-menu-list) {
201
- gap: 0;
202
- }
207
+ /* Mobile menu: full-height, left-aligned rows below the bar */
208
+ .navbar-panel {
209
+ position: absolute;
210
+ top: 100%;
211
+ left: 0;
212
+ right: 0;
213
+ box-sizing: border-box;
214
+ overflow-y: auto;
215
+ overscroll-behavior: contain;
216
+ background-color: var(--color-bg);
217
+ }
203
218
 
204
- /* Rows are padded into the gutter so the focus background has room; the text stays aligned */
205
- .navbar-panel :global(.navigation-menu-trigger) {
206
- box-sizing: content-box;
207
- gap: 8px;
208
- margin-inline: -10px;
209
- padding: 10px;
210
- border-radius: 10px;
211
- font-size: 22px;
212
- font-weight: 600;
213
- line-height: 1.2;
214
- }
219
+ .navbar-panel :global(.navigation-menu) {
220
+ padding: 32px var(--navbar-gutter, 16px);
221
+ }
215
222
 
216
- .navbar-panel :global(:is(.navigation-menu-trigger, .navigation-menu-link):focus-visible) {
217
- outline: none;
218
- background-color: var(--color-surface);
219
- }
223
+ .navbar-panel :global(.navigation-menu-list) {
224
+ gap: 0;
225
+ }
220
226
 
221
- .navbar-panel :global(.navigation-menu-chevron) {
222
- width: 20px;
223
- height: 20px;
224
- color: var(--color-text-muted);
225
- }
227
+ .navbar-panel :global(.navigation-menu-trigger) {
228
+ gap: 8px;
229
+ padding-block: 10px;
230
+ font-size: 22px;
231
+ font-weight: 600;
232
+ line-height: 1.2;
233
+ }
226
234
 
227
- .navbar-panel :global(.navigation-menu-sub) {
228
- gap: 0;
229
- margin: 0 -10px;
230
- padding-bottom: 8px;
231
- }
235
+ .navbar-panel :global(.navigation-menu-chevron) {
236
+ width: 20px;
237
+ height: 20px;
238
+ color: var(--color-text-muted);
239
+ }
232
240
 
233
- /* Sub-items show only their title */
234
- .navbar-panel :global(.navigation-menu-link) {
235
- font-size: 17px;
236
- color: var(--color-text-secondary);
237
- }
241
+ .navbar-panel :global(.navigation-menu-sub) {
242
+ gap: 0;
243
+ margin: 0;
244
+ padding-bottom: 8px;
245
+ }
238
246
 
239
- .navbar-panel :global(.navigation-menu-link-title) {
240
- font-weight: 400;
241
- }
247
+ /* Sub-items are plain rows that show only their title */
248
+ .navbar-panel :global(.navigation-menu-link) {
249
+ padding: 8px 0;
250
+ border-radius: 0;
251
+ background-color: transparent;
252
+ font-size: 17px;
253
+ color: var(--color-text-secondary);
254
+ }
242
255
 
243
- .navbar-panel :global(.navigation-menu-link--active) {
244
- background-color: transparent;
245
- color: var(--color-text);
246
- }
256
+ .navbar-panel :global(.navigation-menu-link:focus-visible) {
257
+ outline-offset: 2px;
258
+ }
247
259
 
248
- .navbar-panel :global(.navigation-menu-link--active .navigation-menu-link-title) {
249
- font-weight: 500;
250
- }
260
+ .navbar-panel :global(.navigation-menu-link-title) {
261
+ font-weight: 400;
262
+ }
251
263
 
252
- .navbar-panel :global(:is(.navigation-menu-link-icon, .navigation-menu-link-description)) {
253
- display: none;
254
- }
264
+ .navbar-panel :global(.navigation-menu-link--active) {
265
+ color: var(--color-text);
266
+ }
255
267
 
256
- @media (min-width: 640px) {
257
- .navbar-desktop {
258
- display: flex;
268
+ .navbar-panel :global(.navigation-menu-link--active .navigation-menu-link-title) {
269
+ font-weight: 500;
259
270
  }
260
271
 
261
- .navbar-trigger,
262
- .navbar-panel {
272
+ .navbar-panel :global(:is(.navigation-menu-link-icon, .navigation-menu-link-description)) {
263
273
  display: none;
264
274
  }
275
+
276
+ @media (min-width: 640px) {
277
+ .navbar-desktop {
278
+ display: flex;
279
+ }
280
+
281
+ .navbar-trigger,
282
+ .navbar-panel {
283
+ display: none;
284
+ }
285
+ }
286
+
287
+ @media (forced-colors: active) {
288
+ .navbar {
289
+ -webkit-backdrop-filter: none;
290
+ backdrop-filter: none;
291
+ }
292
+
293
+ .navbar-panel :global(.navigation-menu-link--active) {
294
+ text-decoration: underline;
295
+ }
296
+ }
297
+
298
+ @media (pointer: coarse) {
299
+ .navbar-panel :global(.navigation-menu-trigger) {
300
+ min-height: 0;
301
+ }
302
+ }
265
303
  }
266
304
  </style>
@@ -4,7 +4,8 @@ export type NavbarTriggerProps = {
4
4
  'aria-controls': string;
5
5
  };
6
6
  import type { Snippet } from 'svelte';
7
- type Props = {
7
+ import type { HTMLAttributes } from 'svelte/elements';
8
+ type Props = Omit<HTMLAttributes<HTMLElement>, 'children'> & {
8
9
  /** Whether the mobile menu is open. Bindable. */
9
10
  open?: boolean;
10
11
  /** Accessible name of the navigation landmark. */
@@ -20,7 +21,8 @@ type Props = {
20
21
  trigger: Snippet<[NavbarTriggerProps, boolean]>;
21
22
  /** `NavigationMenuItem`s, shown inline on desktop and stacked in the mobile menu. */
22
23
  children: Snippet;
24
+ ref?: HTMLElement | null;
23
25
  };
24
- declare const Navbar: import("svelte").Component<Props, {}, "open">;
26
+ declare const Navbar: import("svelte").Component<Props, {}, "ref" | "open">;
25
27
  type Navbar = ReturnType<typeof Navbar>;
26
28
  export default Navbar;
@@ -1,17 +1,26 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from 'svelte';
3
+ import type { HTMLAttributes } from 'svelte/elements';
3
4
  import { setNavigationMenuContext } from './context.js';
4
5
 
5
- type Props = {
6
+ type Props = Omit<HTMLAttributes<HTMLElement>, 'children'> & {
6
7
  /** Accessible name of the navigation landmark. */
7
8
  label?: string;
8
9
  /** `vertical` stacks the items and expands submenus in place, e.g. in a mobile menu. */
9
10
  orientation?: 'horizontal' | 'vertical';
10
11
  /** `NavigationMenuItem`s. */
11
12
  children: Snippet;
13
+ ref?: HTMLElement | null;
12
14
  };
13
15
 
14
- let { label = 'Main', orientation = 'horizontal', children }: Props = $props();
16
+ let {
17
+ label = 'Main',
18
+ orientation = 'horizontal',
19
+ class: className,
20
+ children,
21
+ ref = $bindable(null),
22
+ ...rest
23
+ }: Props = $props();
15
24
 
16
25
  const openDelay = 200;
17
26
  const closeDelay = 200;
@@ -62,8 +71,14 @@
62
71
  </script>
63
72
 
64
73
  <nav
74
+ {...rest}
75
+ bind:this={ref}
65
76
  aria-label={label}
66
- class={['navigation-menu', { 'navigation-menu--vertical': orientation === 'vertical' }]}
77
+ class={[
78
+ 'navigation-menu',
79
+ { 'navigation-menu--vertical': orientation === 'vertical' },
80
+ className
81
+ ]}
67
82
  >
68
83
  <!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
69
84
  <ul class="navigation-menu-list" onkeydown={handleKeydown}>
@@ -72,24 +87,26 @@
72
87
  </nav>
73
88
 
74
89
  <style>
75
- .navigation-menu {
76
- display: flex;
77
- user-select: none;
78
- }
90
+ @layer svelte-ui {
91
+ .navigation-menu {
92
+ display: flex;
93
+ user-select: none;
94
+ }
79
95
 
80
- .navigation-menu-list {
81
- display: flex;
82
- align-items: center;
83
- gap: 24px;
84
- margin: 0;
85
- padding: 0;
86
- list-style: none;
87
- }
96
+ .navigation-menu-list {
97
+ display: flex;
98
+ align-items: center;
99
+ gap: 24px;
100
+ margin: 0;
101
+ padding: 0;
102
+ list-style: none;
103
+ }
88
104
 
89
- .navigation-menu--vertical .navigation-menu-list {
90
- flex-direction: column;
91
- align-items: stretch;
92
- gap: 4px;
93
- width: 100%;
105
+ .navigation-menu--vertical .navigation-menu-list {
106
+ flex-direction: column;
107
+ align-items: stretch;
108
+ gap: 4px;
109
+ width: 100%;
110
+ }
94
111
  }
95
112
  </style>
@@ -1,12 +1,14 @@
1
1
  import type { Snippet } from 'svelte';
2
- type Props = {
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+ type Props = Omit<HTMLAttributes<HTMLElement>, 'children'> & {
3
4
  /** Accessible name of the navigation landmark. */
4
5
  label?: string;
5
6
  /** `vertical` stacks the items and expands submenus in place, e.g. in a mobile menu. */
6
7
  orientation?: 'horizontal' | 'vertical';
7
8
  /** `NavigationMenuItem`s. */
8
9
  children: Snippet;
10
+ ref?: HTMLElement | null;
9
11
  };
10
- declare const NavigationMenu: import("svelte").Component<Props, {}, "">;
12
+ declare const NavigationMenu: import("svelte").Component<Props, {}, "ref">;
11
13
  type NavigationMenu = ReturnType<typeof NavigationMenu>;
12
14
  export default NavigationMenu;