@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
@@ -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,12 @@
111
116
  });
112
117
  </script>
113
118
 
114
- <header class="navbar" bind:offsetHeight={height}>
119
+ <header
120
+ {...rest}
121
+ bind:this={ref}
122
+ class={['navbar', open && 'navbar--open', className]}
123
+ bind:offsetHeight={height}
124
+ >
115
125
  <div class="navbar-bar">
116
126
  <div class="navbar-start">
117
127
  {#if logo}{@render logo()}{/if}
@@ -144,123 +154,163 @@
144
154
  </header>
145
155
 
146
156
  <style>
147
- .navbar {
148
- position: sticky;
149
- top: 0;
150
- z-index: 50;
151
- background-color: var(--color-bg);
152
- user-select: none;
153
- }
157
+ @layer svelte-ui {
158
+ .navbar {
159
+ position: sticky;
160
+ top: 0;
161
+ z-index: 50;
162
+ background-color: color-mix(in srgb, var(--color-bg) 80%, transparent);
163
+ -webkit-backdrop-filter: blur(12px);
164
+ backdrop-filter: blur(12px);
165
+ user-select: none;
166
+ }
154
167
 
155
- .navbar-bar {
156
- display: flex;
157
- align-items: center;
158
- justify-content: space-between;
159
- gap: 16px;
160
- padding: 14px 16px;
161
- }
168
+ /* An open menu is opaque, so no page content shows through the bar */
169
+ .navbar--open {
170
+ background-color: var(--color-bg);
171
+ -webkit-backdrop-filter: none;
172
+ backdrop-filter: none;
173
+ }
162
174
 
163
- .navbar-start {
164
- display: flex;
165
- align-items: center;
166
- gap: 40px;
167
- min-width: 0;
168
- }
175
+ /* Without a blurred backdrop, translucent text-on-content would be hard to read */
176
+ @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
177
+ .navbar {
178
+ background-color: var(--color-bg);
179
+ }
180
+ }
169
181
 
170
- .navbar-end {
171
- display: flex;
172
- align-items: center;
173
- gap: 6px;
174
- }
182
+ @media (prefers-reduced-transparency: reduce) {
183
+ .navbar {
184
+ background-color: var(--color-bg);
185
+ -webkit-backdrop-filter: none;
186
+ backdrop-filter: none;
187
+ }
188
+ }
175
189
 
176
- .navbar-desktop {
177
- display: none;
178
- }
190
+ .navbar-bar {
191
+ display: flex;
192
+ align-items: center;
193
+ justify-content: space-between;
194
+ gap: 16px;
195
+ padding: 14px var(--navbar-gutter, 16px);
196
+ }
179
197
 
180
- .navbar-trigger {
181
- display: flex;
182
- }
198
+ .navbar-start {
199
+ display: flex;
200
+ align-items: center;
201
+ gap: 40px;
202
+ min-width: 0;
203
+ }
183
204
 
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
- }
205
+ .navbar-end {
206
+ display: flex;
207
+ align-items: center;
208
+ gap: 6px;
209
+ }
195
210
 
196
- .navbar-panel :global(.navigation-menu) {
197
- padding: 40px 16px 32px;
198
- }
211
+ .navbar-desktop {
212
+ display: none;
213
+ }
199
214
 
200
- .navbar-panel :global(.navigation-menu-list) {
201
- gap: 0;
202
- }
215
+ .navbar-trigger {
216
+ display: flex;
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
+ /* Mobile menu: full-height, left-aligned rows below the bar */
220
+ .navbar-panel {
221
+ position: absolute;
222
+ top: 100%;
223
+ left: 0;
224
+ right: 0;
225
+ box-sizing: border-box;
226
+ overflow-y: auto;
227
+ overscroll-behavior: contain;
228
+ background-color: var(--color-bg);
229
+ }
215
230
 
216
- .navbar-panel :global(:is(.navigation-menu-trigger, .navigation-menu-link):focus-visible) {
217
- outline: none;
218
- background-color: var(--color-surface);
219
- }
231
+ .navbar-panel :global(.navigation-menu) {
232
+ padding: 72px var(--navbar-gutter, 16px) 32px;
233
+ }
220
234
 
221
- .navbar-panel :global(.navigation-menu-chevron) {
222
- width: 20px;
223
- height: 20px;
224
- color: var(--color-text-muted);
225
- }
235
+ .navbar-panel :global(.navigation-menu-list) {
236
+ gap: 0;
237
+ }
226
238
 
227
- .navbar-panel :global(.navigation-menu-sub) {
228
- gap: 0;
229
- margin: 0 -10px;
230
- padding-bottom: 8px;
231
- }
239
+ .navbar-panel :global(.navigation-menu-trigger) {
240
+ gap: 8px;
241
+ padding-block: 10px;
242
+ font-size: 22px;
243
+ font-weight: 600;
244
+ line-height: 1.2;
245
+ }
232
246
 
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
- }
247
+ .navbar-panel :global(.navigation-menu-chevron) {
248
+ width: 20px;
249
+ height: 20px;
250
+ color: var(--color-text-muted);
251
+ }
238
252
 
239
- .navbar-panel :global(.navigation-menu-link-title) {
240
- font-weight: 400;
241
- }
253
+ .navbar-panel :global(.navigation-menu-sub) {
254
+ gap: 0;
255
+ margin: 0;
256
+ padding-bottom: 8px;
257
+ }
242
258
 
243
- .navbar-panel :global(.navigation-menu-link--active) {
244
- background-color: transparent;
245
- color: var(--color-text);
246
- }
259
+ /* Sub-items are plain rows that show only their title */
260
+ .navbar-panel :global(.navigation-menu-link) {
261
+ padding: 8px 0;
262
+ border-radius: 0;
263
+ background-color: transparent;
264
+ font-size: 17px;
265
+ color: var(--color-text-secondary);
266
+ }
247
267
 
248
- .navbar-panel :global(.navigation-menu-link--active .navigation-menu-link-title) {
249
- font-weight: 500;
250
- }
268
+ .navbar-panel :global(.navigation-menu-link:focus-visible) {
269
+ outline-offset: 2px;
270
+ }
251
271
 
252
- .navbar-panel :global(:is(.navigation-menu-link-icon, .navigation-menu-link-description)) {
253
- display: none;
254
- }
272
+ .navbar-panel :global(.navigation-menu-link-title) {
273
+ font-weight: 400;
274
+ }
255
275
 
256
- @media (min-width: 640px) {
257
- .navbar-desktop {
258
- display: flex;
276
+ .navbar-panel :global(.navigation-menu-link--active) {
277
+ color: var(--color-text);
259
278
  }
260
279
 
261
- .navbar-trigger,
262
- .navbar-panel {
280
+ .navbar-panel :global(.navigation-menu-link--active .navigation-menu-link-title) {
281
+ font-weight: 500;
282
+ }
283
+
284
+ .navbar-panel :global(:is(.navigation-menu-link-icon, .navigation-menu-link-description)) {
263
285
  display: none;
264
286
  }
287
+
288
+ @media (min-width: 640px) {
289
+ .navbar-desktop {
290
+ display: flex;
291
+ }
292
+
293
+ .navbar-trigger,
294
+ .navbar-panel {
295
+ display: none;
296
+ }
297
+ }
298
+
299
+ @media (forced-colors: active) {
300
+ .navbar {
301
+ -webkit-backdrop-filter: none;
302
+ backdrop-filter: none;
303
+ }
304
+
305
+ .navbar-panel :global(.navigation-menu-link--active) {
306
+ text-decoration: underline;
307
+ }
308
+ }
309
+
310
+ @media (pointer: coarse) {
311
+ .navbar-panel :global(.navigation-menu-trigger) {
312
+ min-height: 0;
313
+ }
314
+ }
265
315
  }
266
316
  </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;