zabi-components 7.0.1 → 8.0.0

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 (174) hide show
  1. package/README.md +46 -3
  2. package/THEMING.md +255 -15
  3. package/dist/atoms/ActionPanel.svelte +12 -7
  4. package/dist/atoms/ActionPanel.svelte.d.ts +2 -0
  5. package/dist/atoms/Badge.svelte +93 -56
  6. package/dist/atoms/Badge.svelte.d.ts +15 -3
  7. package/dist/atoms/Button.svelte +49 -49
  8. package/dist/atoms/Button.svelte.d.ts +3 -0
  9. package/dist/atoms/Card.svelte +31 -28
  10. package/dist/atoms/Card.svelte.d.ts +5 -2
  11. package/dist/atoms/CardContent.svelte +10 -2
  12. package/dist/atoms/CardContent.svelte.d.ts +2 -0
  13. package/dist/atoms/CardFooter.svelte +10 -2
  14. package/dist/atoms/CardFooter.svelte.d.ts +2 -0
  15. package/dist/atoms/CardHeader.svelte +10 -2
  16. package/dist/atoms/CardHeader.svelte.d.ts +2 -0
  17. package/dist/atoms/Checkbox.svelte +4 -0
  18. package/dist/atoms/Checkbox.svelte.d.ts +2 -0
  19. package/dist/atoms/CodeBlock.svelte +15 -7
  20. package/dist/atoms/CodeBlock.svelte.d.ts +9 -3
  21. package/dist/atoms/ColorPicker.svelte +19 -9
  22. package/dist/atoms/ColorPicker.svelte.d.ts +3 -1
  23. package/dist/atoms/Container.svelte +2 -3
  24. package/dist/atoms/Divider.svelte +4 -4
  25. package/dist/atoms/FeatureCard.svelte +4 -3
  26. package/dist/atoms/Heading.svelte +56 -27
  27. package/dist/atoms/Heading.svelte.d.ts +17 -4
  28. package/dist/atoms/IconButton.svelte +30 -37
  29. package/dist/atoms/Input.svelte +26 -34
  30. package/dist/atoms/List.svelte +10 -2
  31. package/dist/atoms/List.svelte.d.ts +2 -0
  32. package/dist/atoms/ListItem.svelte +2 -2
  33. package/dist/atoms/ListItemLeading.svelte +4 -2
  34. package/dist/atoms/ListItemLeading.svelte.d.ts +1 -1
  35. package/dist/atoms/OptimizedImage.svelte +11 -2
  36. package/dist/atoms/OptimizedImage.svelte.d.ts +2 -0
  37. package/dist/atoms/Progress.svelte +4 -1
  38. package/dist/atoms/Progress.svelte.d.ts +2 -0
  39. package/dist/atoms/Radio.svelte +4 -0
  40. package/dist/atoms/Radio.svelte.d.ts +2 -0
  41. package/dist/atoms/Select.svelte +65 -67
  42. package/dist/atoms/Select.svelte.d.ts +4 -0
  43. package/dist/atoms/SelectionControl.svelte +5 -1
  44. package/dist/atoms/SelectionControl.svelte.d.ts +2 -0
  45. package/dist/atoms/Skeleton.svelte +5 -3
  46. package/dist/atoms/Table.svelte +2 -1
  47. package/dist/atoms/Text.svelte +34 -5
  48. package/dist/atoms/Text.svelte.d.ts +7 -1
  49. package/dist/atoms/Textarea.svelte +7 -6
  50. package/dist/atoms/ThemeToggle.svelte +17 -14
  51. package/dist/atoms/ThemeToggle.svelte.d.ts +2 -0
  52. package/dist/atoms/Toast.svelte +10 -8
  53. package/dist/atoms/Toggle.svelte +21 -13
  54. package/dist/atoms/Toggle.svelte.d.ts +7 -0
  55. package/dist/atoms/Tooltip.svelte +89 -57
  56. package/dist/atoms/Tooltip.svelte.d.ts +15 -0
  57. package/dist/components/index.d.ts +3 -1
  58. package/dist/components/index.d.ts.map +1 -1
  59. package/dist/components/organisms/index.d.ts +1 -0
  60. package/dist/components/organisms/index.d.ts.map +1 -1
  61. package/dist/components/util/cn.d.ts +8 -0
  62. package/dist/components/util/cn.d.ts.map +1 -0
  63. package/dist/components/util/ssr-safe.d.ts +4 -4
  64. package/dist/components/util/ssr-safe.d.ts.map +1 -1
  65. package/dist/index.d.ts +3 -1
  66. package/dist/index.js +3 -6
  67. package/dist/molecules/Alert.svelte +43 -64
  68. package/dist/molecules/Alert.svelte.d.ts +7 -1
  69. package/dist/molecules/ComponentDemo.svelte +10 -2
  70. package/dist/molecules/ComponentDemo.svelte.d.ts +2 -0
  71. package/dist/molecules/ContactForm.svelte +12 -2
  72. package/dist/molecules/ContactForm.svelte.d.ts +2 -0
  73. package/dist/molecules/Dropdown.svelte +40 -11
  74. package/dist/molecules/Dropdown.svelte.d.ts +4 -0
  75. package/dist/molecules/EmptyState.svelte +2 -1
  76. package/dist/molecules/Form.svelte +25 -14
  77. package/dist/molecules/Form.svelte.d.ts +13 -5
  78. package/dist/molecules/FormField.svelte +2 -1
  79. package/dist/molecules/Header.svelte +13 -3
  80. package/dist/molecules/Header.svelte.d.ts +2 -0
  81. package/dist/molecules/ImageUpload.svelte +54 -15
  82. package/dist/molecules/ImageUpload.svelte.d.ts +16 -5
  83. package/dist/molecules/Modal.svelte +110 -31
  84. package/dist/molecules/Modal.svelte.d.ts +9 -6
  85. package/dist/molecules/NavigationMenu.svelte +15 -3
  86. package/dist/molecules/NavigationMenu.svelte.d.ts +4 -0
  87. package/dist/molecules/NavigationMenuContent.svelte +36 -38
  88. package/dist/molecules/NavigationMenuContent.svelte.d.ts +2 -0
  89. package/dist/molecules/NavigationMenuItem.svelte +10 -2
  90. package/dist/molecules/NavigationMenuItem.svelte.d.ts +2 -0
  91. package/dist/molecules/NavigationMenuLink.svelte +10 -2
  92. package/dist/molecules/NavigationMenuLink.svelte.d.ts +2 -0
  93. package/dist/molecules/NavigationMenuList.svelte +10 -2
  94. package/dist/molecules/NavigationMenuList.svelte.d.ts +2 -0
  95. package/dist/molecules/NavigationMenuTrigger.svelte +16 -3
  96. package/dist/molecules/NavigationMenuTrigger.svelte.d.ts +2 -0
  97. package/dist/molecules/Page.svelte +8 -2
  98. package/dist/molecules/Page.svelte.d.ts +2 -0
  99. package/dist/molecules/PropsTable.svelte +6 -3
  100. package/dist/molecules/PropsTable.svelte.d.ts +2 -0
  101. package/dist/molecules/RadioGroup.svelte +5 -1
  102. package/dist/molecules/RadioGroup.svelte.d.ts +2 -0
  103. package/dist/molecules/Section.svelte +12 -4
  104. package/dist/molecules/Section.svelte.d.ts +3 -1
  105. package/dist/molecules/SidebarBrandHeader.svelte +13 -4
  106. package/dist/molecules/SidebarBrandHeader.svelte.d.ts +2 -0
  107. package/dist/molecules/SidebarFooter.svelte +12 -4
  108. package/dist/molecules/SidebarFooter.svelte.d.ts +2 -0
  109. package/dist/molecules/SidebarNavSection.svelte +12 -4
  110. package/dist/molecules/SidebarNavSection.svelte.d.ts +2 -0
  111. package/dist/molecules/SlideUp.svelte +85 -21
  112. package/dist/molecules/SlideUp.svelte.d.ts +5 -4
  113. package/dist/molecules/Tabs.svelte +25 -19
  114. package/dist/molecules/Tabs.svelte.d.ts +8 -4
  115. package/dist/molecules/Toaster.svelte +3 -2
  116. package/dist/molecules/ToasterToast.svelte +41 -10
  117. package/dist/molecules/ToasterToast.svelte.d.ts +2 -0
  118. package/dist/organisms/SidebarAccountPanel.svelte +4 -0
  119. package/dist/organisms/SidebarAccountPanel.svelte.d.ts +2 -0
  120. package/dist/organisms/SidebarNavigation.svelte +102 -59
  121. package/dist/organisms/SidebarNavigation.svelte.d.ts +2 -0
  122. package/dist/organisms/SidebarPanel.svelte +19 -11
  123. package/dist/organisms/SidebarPanel.svelte.d.ts +2 -0
  124. package/dist/organisms/SidebarShell.svelte +112 -0
  125. package/dist/organisms/SidebarShell.svelte.d.ts +52 -0
  126. package/dist/organisms/TopNavbar.svelte +88 -17
  127. package/dist/organisms/TopNavbar.svelte.d.ts +2 -0
  128. package/dist/organisms/index.d.ts +1 -0
  129. package/dist/organisms/index.js +1 -0
  130. package/dist/routes/lib/variant-utils.d.ts +26 -0
  131. package/dist/routes/lib/{variant-utils.ts → variant-utils.js} +15 -46
  132. package/dist/types/events.js +1 -0
  133. package/dist/types/index.js +3 -0
  134. package/dist/util/cn.d.ts +7 -0
  135. package/dist/util/cn.js +48 -0
  136. package/dist/util/ssr-safe.d.ts +4 -4
  137. package/dist/zabi-components-colors.css +3 -437
  138. package/dist/zabi-components-theme-dark-only.css +223 -103
  139. package/dist/zabi-components-theme-dark.css +223 -103
  140. package/dist/zabi-components-theme-only.css +347 -107
  141. package/dist/zabi-components-theme.css +347 -107
  142. package/dist/zabi-components.css +953 -843
  143. package/docs/lucide-icons.md +3 -1
  144. package/package.json +20 -25
  145. package/dist/lib/layout-width-tokens.d.ts +0 -17
  146. package/dist/lib/layout-width-tokens.d.ts.map +0 -1
  147. package/dist/lib/showcase/component-docs/Button.d.ts +0 -3
  148. package/dist/lib/showcase/component-docs/Button.d.ts.map +0 -1
  149. package/dist/lib/showcase/component-docs/Input.d.ts +0 -3
  150. package/dist/lib/showcase/component-docs/Input.d.ts.map +0 -1
  151. package/dist/lib/showcase/component-docs/List.d.ts +0 -3
  152. package/dist/lib/showcase/component-docs/List.d.ts.map +0 -1
  153. package/dist/lib/showcase/component-docs/Modal.d.ts +0 -3
  154. package/dist/lib/showcase/component-docs/Modal.d.ts.map +0 -1
  155. package/dist/lib/showcase/component-docs/Radio.d.ts +0 -3
  156. package/dist/lib/showcase/component-docs/Radio.d.ts.map +0 -1
  157. package/dist/lib/showcase/component-docs/SidebarNavigation.d.ts +0 -3
  158. package/dist/lib/showcase/component-docs/SidebarNavigation.d.ts.map +0 -1
  159. package/dist/lib/showcase/component-docs/Skeleton.d.ts +0 -3
  160. package/dist/lib/showcase/component-docs/Skeleton.d.ts.map +0 -1
  161. package/dist/lib/showcase/component-docs/_shared.d.ts +0 -12
  162. package/dist/lib/showcase/component-docs/_shared.d.ts.map +0 -1
  163. package/dist/lib/showcase/component-docs/index.d.ts +0 -4
  164. package/dist/lib/showcase/component-docs/index.d.ts.map +0 -1
  165. package/dist/lib/showcase/components-catalog.d.ts +0 -3
  166. package/dist/lib/showcase/components-catalog.d.ts.map +0 -1
  167. package/dist/lib/showcase/components-showcase-constants.d.ts +0 -89
  168. package/dist/lib/showcase/components-showcase-constants.d.ts.map +0 -1
  169. package/dist/lib/showcase/docs-sidebar-helpers.d.ts +0 -15
  170. package/dist/lib/showcase/docs-sidebar-helpers.d.ts.map +0 -1
  171. package/dist/routes/lib/focus-utils.d.ts +0 -12
  172. package/dist/routes/lib/focus-utils.ts +0 -110
  173. package/dist/routes/lib/ssr-safe.ts +0 -58
  174. package/scripts/fix-lucide-svelte-icon-dts.js +0 -35
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from "svelte";
3
3
  import { getContext } from "svelte";
4
+ import { cn } from "../util/cn.js";
4
5
  import {
5
6
  NAVIGATION_MENU_CONTEXT_KEY,
6
7
  type NavigationMenuContextValue,
@@ -8,17 +9,24 @@
8
9
 
9
10
  interface Props {
10
11
  value?: string;
12
+ class?: string;
13
+ /** @deprecated use `class`. */
11
14
  className?: string;
12
15
  children?: Snippet;
13
16
  }
14
17
 
15
18
  let {
16
19
  value = "",
17
- className = "",
20
+ class: classAttr = "",
21
+ className: legacyClass = "",
18
22
  children,
19
23
  ...restProps
20
24
  }: Props = $props();
21
25
 
26
+ /** `class` is the public prop; `className` is a deprecated alias.
27
+ * Both are merged here so existing call sites keep working. */
28
+ const className = $derived(cn(`${classAttr} ${legacyClass}`));
29
+
22
30
  const context = getContext<NavigationMenuContextValue>(
23
31
  NAVIGATION_MENU_CONTEXT_KEY,
24
32
  );
@@ -27,7 +35,7 @@
27
35
  </script>
28
36
 
29
37
  <li
30
- class="relative {className}"
38
+ class={cn("relative", className)}
31
39
  role="none"
32
40
  data-navigation-menu-item
33
41
  data-active={isActive}
@@ -1,6 +1,8 @@
1
1
  import type { Snippet } from "svelte";
2
2
  interface Props {
3
3
  value?: string;
4
+ class?: string;
5
+ /** @deprecated use `class`. */
4
6
  className?: string;
5
7
  children?: Snippet;
6
8
  }
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from "svelte";
3
3
  import { getContext } from "svelte";
4
+ import { cn } from "../util/cn.js";
4
5
  import {
5
6
  NAVIGATION_MENU_CONTEXT_KEY,
6
7
  type NavigationMenuContextValue,
@@ -9,6 +10,8 @@
9
10
  interface Props {
10
11
  href?: string;
11
12
  asChild?: boolean;
13
+ class?: string;
14
+ /** @deprecated use `class`. */
12
15
  className?: string;
13
16
  children?: Snippet;
14
17
  }
@@ -16,11 +19,16 @@
16
19
  let {
17
20
  href = "#",
18
21
  asChild = false,
19
- className = "",
22
+ class: classAttr = "",
23
+ className: legacyClass = "",
20
24
  children,
21
25
  ...restProps
22
26
  }: Props = $props();
23
27
 
28
+ /** `class` is the public prop; `className` is a deprecated alias.
29
+ * Both are merged here so existing call sites keep working. */
30
+ const className = $derived(cn(`${classAttr} ${legacyClass}`));
31
+
24
32
  const context = getContext<NavigationMenuContextValue>(
25
33
  NAVIGATION_MENU_CONTEXT_KEY,
26
34
  );
@@ -30,7 +38,7 @@
30
38
  }
31
39
 
32
40
  const linkClasses =
33
- "focus-ring focus-ring--nav block cursor-pointer rounded-md px-4 py-2 text-sm text-nav-menu-item no-underline transition-colors duration-150 outline-none hover:bg-nav-menu-hover hover:text-nav-menu-item-hover {className}";
41
+ "focus-ring focus-ring--nav block cursor-pointer rounded-control px-4 py-2 text-sm text-nav-menu-item no-underline transition-colors duration-150 outline-none hover:bg-nav-menu-hover hover:text-nav-menu-item-hover {className}";
34
42
  </script>
35
43
 
36
44
  {#if asChild}
@@ -2,6 +2,8 @@ import type { Snippet } from "svelte";
2
2
  interface Props {
3
3
  href?: string;
4
4
  asChild?: boolean;
5
+ class?: string;
6
+ /** @deprecated use `class`. */
5
7
  className?: string;
6
8
  children?: Snippet;
7
9
  }
@@ -1,20 +1,28 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from "svelte";
3
+ import { cn } from "../util/cn.js";
3
4
 
4
5
  interface Props {
6
+ class?: string;
7
+ /** @deprecated use `class`. */
5
8
  className?: string;
6
9
  children?: Snippet;
7
10
  }
8
11
 
9
12
  let {
10
- className = "",
13
+ class: classAttr = "",
14
+ className: legacyClass = "",
11
15
  children,
12
16
  ...restProps
13
17
  }: Props = $props();
18
+
19
+ /** `class` is the public prop; `className` is a deprecated alias.
20
+ * Both are merged here so existing call sites keep working. */
21
+ const className = $derived(cn(`${classAttr} ${legacyClass}`));
14
22
  </script>
15
23
 
16
24
  <ul
17
- class="flex flex-row items-center gap-1 list-none m-0 p-0 {className}"
25
+ class={cn("flex flex-row items-center gap-1 list-none m-0 p-0", className)}
18
26
  role="menubar"
19
27
  aria-orientation="horizontal"
20
28
  data-navigation-menu-list
@@ -1,5 +1,7 @@
1
1
  import type { Snippet } from "svelte";
2
2
  interface Props {
3
+ class?: string;
4
+ /** @deprecated use `class`. */
3
5
  className?: string;
4
6
  children?: Snippet;
5
7
  }
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from "svelte";
3
3
  import { getContext } from "svelte";
4
+ import { cn } from "../util/cn.js";
4
5
  import {
5
6
  NAVIGATION_MENU_CONTEXT_KEY,
6
7
  navigationMenuPanelId,
@@ -9,17 +10,24 @@
9
10
 
10
11
  interface Props {
11
12
  value?: string;
13
+ class?: string;
14
+ /** @deprecated use `class`. */
12
15
  className?: string;
13
16
  children?: Snippet;
14
17
  }
15
18
 
16
19
  let {
17
20
  value = "",
18
- className = "",
21
+ class: classAttr = "",
22
+ className: legacyClass = "",
19
23
  children,
20
24
  ...restProps
21
25
  }: Props = $props();
22
26
 
27
+ /** `class` is the public prop; `className` is a deprecated alias.
28
+ * Both are merged here so existing call sites keep working. */
29
+ const className = $derived(cn(`${classAttr} ${legacyClass}`));
30
+
23
31
  const context = getContext<NavigationMenuContextValue>(
24
32
  NAVIGATION_MENU_CONTEXT_KEY,
25
33
  );
@@ -58,10 +66,15 @@
58
66
 
59
67
  <button
60
68
  type="button"
61
- class="focus-ring focus-ring--nav inline-flex cursor-pointer items-center justify-center gap-2 rounded-lg bg-transparent px-4 py-2 text-sm font-medium text-nav-menu-item transition-colors duration-150 outline-none hover:bg-nav-menu-hover hover:text-nav-menu-item-hover data-[active=true]:bg-nav-menu-active data-[active=true]:text-nav-menu-item-active {className}"
69
+ class={cn(
70
+ "focus-ring focus-ring--nav inline-flex cursor-pointer items-center justify-center gap-2 rounded-control bg-transparent px-4 py-2 text-sm font-medium transition-colors duration-150 outline-none",
71
+ isActive
72
+ ? "bg-nav-menu-active text-nav-menu-item-active"
73
+ : "text-nav-menu-item hover:bg-nav-menu-hover hover:text-nav-menu-item-hover",
74
+ className,
75
+ )}
62
76
  aria-expanded={isActive ? 'true' : 'false'}
63
77
  aria-controls={panelId || undefined}
64
- aria-haspopup="true"
65
78
  onclick={handleClick}
66
79
  onkeydown={handleKeydown}
67
80
  data-navigation-menu-trigger
@@ -1,6 +1,8 @@
1
1
  import type { Snippet } from "svelte";
2
2
  interface Props {
3
3
  value?: string;
4
+ class?: string;
5
+ /** @deprecated use `class`. */
4
6
  className?: string;
5
7
  children?: Snippet;
6
8
  }
@@ -1,15 +1,21 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from "svelte";
3
+ import { cn } from "../util/cn.js";
3
4
 
4
5
  interface Props {
5
6
  children?: Snippet;
7
+ class?: string;
8
+ /** @deprecated use `class`. */
6
9
  className?: string;
7
10
  }
8
11
 
9
- let { children, className = "" }: Props = $props();
12
+ let { children, class: classAttr = "", className: legacyClass = "" }: Props = $props();
13
+
14
+ /** `class` is the public prop; `className` is a deprecated alias. */
15
+ const className = $derived(cn(`${classAttr} ${legacyClass}`));
10
16
  </script>
11
17
 
12
- <div class="mx-auto w-full space-y-10 {className}">
18
+ <div class={cn("mx-auto w-full space-y-10", className)}>
13
19
  {#if children}
14
20
  {@render children()}
15
21
  {/if}
@@ -1,6 +1,8 @@
1
1
  import type { Snippet } from "svelte";
2
2
  interface Props {
3
3
  children?: Snippet;
4
+ class?: string;
5
+ /** @deprecated use `class`. */
4
6
  className?: string;
5
7
  }
6
8
  declare const Page: import("svelte").Component<Props, {}, "">;
@@ -1,17 +1,20 @@
1
1
  <script lang="ts">
2
2
  import type { ComponentProp } from "../types/page.types";
3
3
  import Table from "../atoms/Table.svelte";
4
+ import { cn } from "../util/cn.js";
4
5
 
5
6
  interface Props {
7
+ /** Extra classes for the host element. */
8
+ class?: string;
6
9
  props: ComponentProp[];
7
10
  caption?: string;
8
11
  }
9
12
 
10
- let { props, caption = "Props / API" }: Props = $props();
13
+ let { class: className = "", props, caption = "Props / API" }: Props = $props();
11
14
  </script>
12
15
 
13
16
  {#if props.length === 0}
14
- <div class="rounded-lg border border-border bg-base-50 px-4 py-4 text-sm text-description">
17
+ <div class={cn("rounded-control border border-border bg-base-50 px-4 py-4 text-sm text-description", className)}>
15
18
  No documented props.
16
19
  </div>
17
20
  {:else}
@@ -37,7 +40,7 @@
37
40
  </thead>
38
41
  <tbody>
39
42
  {#each props as prop}
40
- <tr class="hover:bg-base-50/70">
43
+ <tr class="hover:bg-surface-hover">
41
44
  <td class="border-b border-border px-4 py-3 font-mono text-body">
42
45
  {prop.name}
43
46
  </td>
@@ -1,5 +1,7 @@
1
1
  import type { ComponentProp } from "../types/page.types";
2
2
  interface Props {
3
+ /** Extra classes for the host element. */
4
+ class?: string;
3
5
  props: ComponentProp[];
4
6
  caption?: string;
5
7
  }
@@ -7,6 +7,7 @@
7
7
  } from "../atoms/selection-control.styles";
8
8
  import { generateId } from "../util/ssr-safe.js";
9
9
  import { SvelteMap } from "svelte/reactivity";
10
+ import { cn } from "../util/cn.js";
10
11
 
11
12
  export type RadioGroupOption = {
12
13
  value: string;
@@ -16,6 +17,8 @@
16
17
  };
17
18
 
18
19
  interface Props {
20
+ /** Extra classes for the host element. */
21
+ class?: string;
19
22
  options: RadioGroupOption[];
20
23
  /** Selected value; `bind:value`. Use `undefined` for no selection. */
21
24
  value?: string | undefined;
@@ -28,6 +31,7 @@
28
31
  }
29
32
 
30
33
  let {
34
+ class: className = "",
31
35
  options,
32
36
  defaultValue,
33
37
  value = $bindable(defaultValue),
@@ -150,7 +154,7 @@
150
154
  </script>
151
155
 
152
156
  <fieldset
153
- class="space-y-3"
157
+ class={cn("space-y-3", className)}
154
158
  aria-disabled={disabled ? "true" : undefined}
155
159
  onkeydown={handleKeydown}
156
160
  {...restProps}
@@ -5,6 +5,8 @@ export type RadioGroupOption = {
5
5
  description?: string;
6
6
  };
7
7
  interface Props {
8
+ /** Extra classes for the host element. */
9
+ class?: string;
8
10
  options: RadioGroupOption[];
9
11
  /** Selected value; `bind:value`. Use `undefined` for no selection. */
10
12
  value?: string | undefined;
@@ -2,17 +2,20 @@
2
2
  import type { Snippet } from "svelte";
3
3
  import type { SizeVariant } from "../types/variants.js";
4
4
  import Heading from "../atoms/Heading.svelte";
5
+ import { cn } from "../util/cn.js";
5
6
 
6
7
  interface Props {
7
8
  title?: string;
8
9
  description?: string;
9
10
  /** Title heading level (1–6). */
10
- headingLevel?: number;
11
+ headingLevel?: 1 | 2 | 3 | 4 | 5 | 6;
11
12
  size?: SizeVariant;
12
13
  maxWidth?: "sm" | "md" | "lg" | "xl" | "2xl" | "full" | "none";
13
14
  background?: "default" | "muted" | "accent" | "transparent";
14
15
  padding?: "none" | "sm" | "md" | "lg" | "xl";
15
16
  centered?: boolean;
17
+ class?: string;
18
+ /** @deprecated use `class`. */
16
19
  className?: string;
17
20
  children?: Snippet;
18
21
  }
@@ -26,11 +29,16 @@
26
29
  background = "default",
27
30
  padding = "lg",
28
31
  centered = false,
29
- className = "",
32
+ class: classAttr = "",
33
+ className: legacyClass = "",
30
34
  children,
31
35
  ...restProps
32
36
  }: Props = $props();
33
37
 
38
+ /** `class` is the public prop; `className` is a deprecated alias.
39
+ * Both are merged here so existing call sites keep working. */
40
+ const className = $derived(cn(`${classAttr} ${legacyClass}`));
41
+
34
42
  const sizeClasses = $derived.by(() => {
35
43
  switch (size) {
36
44
  case "sm":
@@ -97,13 +105,13 @@
97
105
  const base = "w-full";
98
106
  const maxWidthClass = maxWidthClasses;
99
107
  const centeredClass = centered ? "mx-auto" : "";
100
- return `${base} ${maxWidthClass} ${centeredClass}`.trim();
108
+ return cn(`${base} ${maxWidthClass} ${centeredClass}`);
101
109
  });
102
110
 
103
111
  const contentClasses = $derived.by(() => {
104
112
  const base = "px-4 sm:px-6 lg:px-8";
105
113
  const centeredClass = centered ? "text-center" : "";
106
- return `${base} ${centeredClass}`.trim();
114
+ return cn(`${base} ${centeredClass}`);
107
115
  });
108
116
  </script>
109
117
 
@@ -4,12 +4,14 @@ interface Props {
4
4
  title?: string;
5
5
  description?: string;
6
6
  /** Title heading level (1–6). */
7
- headingLevel?: number;
7
+ headingLevel?: 1 | 2 | 3 | 4 | 5 | 6;
8
8
  size?: SizeVariant;
9
9
  maxWidth?: "sm" | "md" | "lg" | "xl" | "2xl" | "full" | "none";
10
10
  background?: "default" | "muted" | "accent" | "transparent";
11
11
  padding?: "none" | "sm" | "md" | "lg" | "xl";
12
12
  centered?: boolean;
13
+ class?: string;
14
+ /** @deprecated use `class`. */
13
15
  className?: string;
14
16
  children?: Snippet;
15
17
  }
@@ -1,9 +1,13 @@
1
1
  <script lang="ts">
2
+ import { cn } from "../util/cn.js";
3
+
2
4
  interface Props {
3
5
  collapsed?: boolean;
4
6
  brandName?: string;
5
7
  logoSrc?: string;
6
8
  logoAlt?: string;
9
+ class?: string;
10
+ /** @deprecated use `class`. */
7
11
  className?: string;
8
12
  }
9
13
 
@@ -12,9 +16,14 @@
12
16
  brandName = "",
13
17
  logoSrc = "",
14
18
  logoAlt = "",
15
- className = "",
19
+ class: classAttr = "",
20
+ className: legacyClass = "",
16
21
  }: Props = $props();
17
22
 
23
+ /** `class` is the public prop; `className` is a deprecated alias.
24
+ * Both are merged here so existing call sites keep working. */
25
+ const className = $derived(`${classAttr} ${legacyClass}`.trim());
26
+
18
27
  const trimmedName = $derived(brandName.trim());
19
28
  const monogram = $derived(
20
29
  trimmedName
@@ -35,11 +44,11 @@
35
44
 
36
45
  {#if showLogo || trimmedName}
37
46
  <div
38
- class={`flex w-full min-w-0 items-center gap-2.5 ${className}`.trim()}
47
+ class={cn("flex w-full min-w-0 items-center gap-3", className)}
39
48
  >
40
49
  {#if showLogo}
41
50
  <span
42
- class="flex size-9 shrink-0 items-center justify-center overflow-hidden rounded-xl bg-background ring-1 ring-border"
51
+ class="flex size-9 shrink-0 items-center justify-center overflow-hidden rounded-container bg-background ring-1 ring-border"
43
52
  >
44
53
  <img
45
54
  src={logoSrc}
@@ -51,7 +60,7 @@
51
60
  </span>
52
61
  {:else if showMonogram}
53
62
  <span
54
- class="flex size-9 shrink-0 items-center justify-center rounded-xl bg-action-primary-subtle text-xs font-bold text-headline ring-1 ring-border"
63
+ class="flex size-9 shrink-0 items-center justify-center rounded-container bg-action-primary-subtle text-xs font-bold text-headline ring-1 ring-border"
55
64
  aria-hidden="true"
56
65
  >
57
66
  {monogram}
@@ -3,6 +3,8 @@ interface Props {
3
3
  brandName?: string;
4
4
  logoSrc?: string;
5
5
  logoAlt?: string;
6
+ class?: string;
7
+ /** @deprecated use `class`. */
6
8
  className?: string;
7
9
  }
8
10
  declare const SidebarBrandHeader: import("svelte").Component<Props, {}, "">;
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from "svelte";
3
3
  import { fixedSidebarFlyout } from "../util/fixed-sidebar-flyout.js";
4
+ import { cn } from "../util/cn.js";
4
5
 
5
6
  interface Props {
6
7
  collapsed?: boolean;
@@ -15,6 +16,8 @@
15
16
  isLightMode?: boolean;
16
17
  onLogout?: () => void;
17
18
  onThemeToggle?: (nextIsLightMode: boolean) => void;
19
+ class?: string;
20
+ /** @deprecated use `class`. */
18
21
  className?: string;
19
22
  profilePanelOpen?: boolean;
20
23
  profilePanelControlsId?: string;
@@ -35,18 +38,23 @@
35
38
  isLightMode = $bindable(false),
36
39
  onLogout,
37
40
  onThemeToggle,
38
- className = "",
41
+ class: classAttr = "",
42
+ className: legacyClass = "",
39
43
  profilePanelOpen = false,
40
44
  profilePanelControlsId = "",
41
45
  onProfileClick,
42
46
  profilePanel,
43
47
  }: Props = $props();
44
48
 
49
+ /** `class` is the public prop; `className` is a deprecated alias.
50
+ * Both are merged here so existing call sites keep working. */
51
+ const className = $derived(cn(`${classAttr} ${legacyClass}`));
52
+
45
53
  const showFooter = $derived(showProfile || showLogout || showThemeToggle);
46
54
  const showPanelLauncher = $derived(showProfile);
47
55
 
48
56
  const avatarClasses =
49
- "size-10 rounded-xl bg-action-primary text-action-primary flex items-center justify-center text-sm font-semibold shrink-0 ring-1 ring-border-focus";
57
+ "size-10 rounded-container bg-action-primary text-action-primary flex items-center justify-center text-sm font-semibold shrink-0 ring-1 ring-border-focus";
50
58
 
51
59
  function getTextToneClass(isMuted = false): string {
52
60
  return isMuted ? "text-description" : "text-headline";
@@ -60,14 +68,14 @@
60
68
  {#if showFooter}
61
69
  <div class="w-full shrink-0" data-sidebar-flyout-root>
62
70
  <footer
63
- class={`flex w-full shrink-0 flex-col gap-2.5 border-t border-border pt-3 pb-1 ${className}`.trim()}
71
+ class={cn(`flex w-full shrink-0 flex-col gap-3 border-t border-border pt-3 pb-1 ${className}`)}
64
72
  aria-label="Account and settings"
65
73
  >
66
74
  {#if showPanelLauncher}
67
75
  <button
68
76
  type="button"
69
77
  data-sidebar-flyout-anchor="profile"
70
- class="w-full cursor-pointer rounded-xl px-2 py-2 outline-none transition-colors hover:bg-nav-menu-hover hover:text-nav-menu-item-hover hover:ring-1 hover:ring-border/60 active:bg-base-200 focus-ring focus-ring--nav"
78
+ class="w-full cursor-pointer rounded-container px-2 py-2 outline-none transition-colors hover:bg-nav-menu-hover hover:text-nav-menu-item-hover hover:ring-1 hover:ring-border/60 active:bg-surface-active focus-ring focus-ring--nav"
71
79
  aria-haspopup="dialog"
72
80
  aria-expanded={profilePanelOpen}
73
81
  aria-controls={profilePanelControlsId.trim()
@@ -12,6 +12,8 @@ interface Props {
12
12
  isLightMode?: boolean;
13
13
  onLogout?: () => void;
14
14
  onThemeToggle?: (nextIsLightMode: boolean) => void;
15
+ class?: string;
16
+ /** @deprecated use `class`. */
15
17
  className?: string;
16
18
  profilePanelOpen?: boolean;
17
19
  profilePanelControlsId?: string;
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from "svelte";
3
+ import { cn } from "../util/cn.js";
3
4
 
4
5
  interface Props {
5
6
  title?: string;
@@ -8,6 +9,8 @@
8
9
  /** `aria-label` on the `<ul>` (required when title is hidden in collapsed mode). */
9
10
  listAriaLabel: string;
10
11
  collapsed?: boolean;
12
+ class?: string;
13
+ /** @deprecated use `class`. */
11
14
  className?: string;
12
15
  children: Snippet;
13
16
  }
@@ -17,10 +20,15 @@
17
20
  sectionKey = "",
18
21
  listAriaLabel,
19
22
  collapsed = false,
20
- className = "",
23
+ class: classAttr = "",
24
+ className: legacyClass = "",
21
25
  children,
22
26
  }: Props = $props();
23
27
 
28
+ /** `class` is the public prop; `className` is a deprecated alias.
29
+ * Both are merged here so existing call sites keep working. */
30
+ const className = $derived(cn(`${classAttr} ${legacyClass}`));
31
+
24
32
  const trimmedTitle = $derived(title.trim());
25
33
  const headingId = $derived(
26
34
  trimmedTitle
@@ -30,17 +38,17 @@
30
38
  const showHeading = $derived(Boolean(trimmedTitle) && !collapsed);
31
39
  </script>
32
40
 
33
- <div class={`flex w-full flex-col gap-1.5 ${className}`.trim()}>
41
+ <div class={cn(`flex w-full flex-col gap-2 ${className}`)}>
34
42
  {#if showHeading && headingId}
35
43
  <h2
36
- class="px-0 text-[10px] font-semibold uppercase tracking-[0.12em] text-description"
44
+ class="px-0 text-xs font-semibold uppercase tracking-wider text-description"
37
45
  id={headingId}
38
46
  >
39
47
  {trimmedTitle}
40
48
  </h2>
41
49
  {/if}
42
50
  <ul
43
- class="flex w-full flex-col gap-0.5 px-0"
51
+ class="flex w-full flex-col gap-1 px-0"
44
52
  aria-labelledby={showHeading && headingId ? headingId : undefined}
45
53
  aria-label={showHeading ? undefined : listAriaLabel}
46
54
  >
@@ -6,6 +6,8 @@ interface Props {
6
6
  /** `aria-label` on the `<ul>` (required when title is hidden in collapsed mode). */
7
7
  listAriaLabel: string;
8
8
  collapsed?: boolean;
9
+ class?: string;
10
+ /** @deprecated use `class`. */
9
11
  className?: string;
10
12
  children: Snippet;
11
13
  }