@spaethtech/svelte-ui 0.20.1-dev.99.8654270 → 0.21.1-dev.108.1b2415e

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 (96) hide show
  1. package/dist/components/Alert.svelte +15 -6
  2. package/dist/components/Alert.svelte.d.ts +4 -1
  3. package/dist/components/Avatar/Avatar.svelte +4 -2
  4. package/dist/components/Avatar/Avatar.svelte.d.ts +2 -1
  5. package/dist/components/Avatar/AvatarGroup.svelte +4 -1
  6. package/dist/components/Avatar/AvatarGroup.svelte.d.ts +2 -1
  7. package/dist/components/Badge/Badge.svelte +34 -7
  8. package/dist/components/Badge/Badge.svelte.d.ts +10 -1
  9. package/dist/components/Banner.svelte +4 -1
  10. package/dist/components/Banner.svelte.d.ts +2 -1
  11. package/dist/components/Breadcrumbs/Breadcrumbs.svelte +4 -2
  12. package/dist/components/Breadcrumbs/Breadcrumbs.svelte.d.ts +2 -1
  13. package/dist/components/CardFooter.svelte +12 -1
  14. package/dist/components/CardFooter.svelte.d.ts +3 -0
  15. package/dist/components/Carousel/Carousel.svelte +4 -1
  16. package/dist/components/Carousel/Carousel.svelte.d.ts +2 -1
  17. package/dist/components/Chip/Chip.svelte +4 -1
  18. package/dist/components/Chip/Chip.svelte.d.ts +2 -1
  19. package/dist/components/Combobox/Combobox.svelte +4 -1
  20. package/dist/components/Combobox/Combobox.svelte.d.ts +2 -1
  21. package/dist/components/CommandPalette/CommandPalette.svelte +4 -2
  22. package/dist/components/CommandPalette/CommandPalette.svelte.d.ts +2 -1
  23. package/dist/components/ConfirmDialog.svelte +4 -1
  24. package/dist/components/ConfirmDialog.svelte.d.ts +2 -1
  25. package/dist/components/ContextMenu/ContextMenu.svelte +4 -2
  26. package/dist/components/ContextMenu/ContextMenu.svelte.d.ts +2 -1
  27. package/dist/components/DataTable.svelte +4 -1
  28. package/dist/components/DataTable.svelte.d.ts +2 -1
  29. package/dist/components/DatePicker.svelte +4 -2
  30. package/dist/components/DatePicker.svelte.d.ts +2 -1
  31. package/dist/components/Divider/Divider.svelte +6 -3
  32. package/dist/components/Divider/Divider.svelte.d.ts +2 -1
  33. package/dist/components/Drawer/Drawer.svelte +4 -1
  34. package/dist/components/Drawer/Drawer.svelte.d.ts +2 -1
  35. package/dist/components/EmailInput.svelte +2 -1
  36. package/dist/components/EmailInput.svelte.d.ts +2 -1
  37. package/dist/components/EmptyState/EmptyState.svelte +4 -2
  38. package/dist/components/EmptyState/EmptyState.svelte.d.ts +2 -1
  39. package/dist/components/FileUpload/FileUpload.svelte +4 -2
  40. package/dist/components/FileUpload/FileUpload.svelte.d.ts +2 -1
  41. package/dist/components/Grid.svelte +4 -2
  42. package/dist/components/Grid.svelte.d.ts +2 -1
  43. package/dist/components/Kbd/Kbd.svelte +5 -3
  44. package/dist/components/Kbd/Kbd.svelte.d.ts +2 -1
  45. package/dist/components/List.svelte +4 -2
  46. package/dist/components/List.svelte.d.ts +2 -1
  47. package/dist/components/Menu.svelte +4 -1
  48. package/dist/components/Menu.svelte.d.ts +2 -1
  49. package/dist/components/NumberInput.svelte +2 -1
  50. package/dist/components/NumberInput.svelte.d.ts +2 -1
  51. package/dist/components/Pagination/Pagination.svelte +4 -1
  52. package/dist/components/Pagination/Pagination.svelte.d.ts +2 -1
  53. package/dist/components/PasswordInput.svelte +2 -1
  54. package/dist/components/PasswordInput.svelte.d.ts +2 -1
  55. package/dist/components/Popup.svelte +8 -1
  56. package/dist/components/Popup.svelte.d.ts +2 -1
  57. package/dist/components/Progress/Progress.svelte +4 -2
  58. package/dist/components/Progress/Progress.svelte.d.ts +2 -1
  59. package/dist/components/Query.svelte +4 -2
  60. package/dist/components/Query.svelte.d.ts +2 -1
  61. package/dist/components/ScrollArea/ScrollArea.svelte +5 -2
  62. package/dist/components/ScrollArea/ScrollArea.svelte.d.ts +2 -1
  63. package/dist/components/SearchInput.svelte +2 -1
  64. package/dist/components/SearchInput.svelte.d.ts +2 -1
  65. package/dist/components/Select.svelte +3 -1
  66. package/dist/components/Select.svelte.d.ts +3 -1
  67. package/dist/components/SideBarMenu/SideBarMenu.svelte +7 -1
  68. package/dist/components/SideBarMenu/SideBarMenu.svelte.d.ts +2 -1
  69. package/dist/components/Skeleton/Skeleton.svelte +7 -2
  70. package/dist/components/Skeleton/Skeleton.svelte.d.ts +2 -1
  71. package/dist/components/Slider/Slider.svelte +4 -2
  72. package/dist/components/Slider/Slider.svelte.d.ts +2 -1
  73. package/dist/components/Spinner/Spinner.svelte +4 -1
  74. package/dist/components/Spinner/Spinner.svelte.d.ts +2 -1
  75. package/dist/components/Splitter/Splitter.svelte +4 -1
  76. package/dist/components/Splitter/Splitter.svelte.d.ts +2 -1
  77. package/dist/components/Stat/Stat.svelte +4 -2
  78. package/dist/components/Stat/Stat.svelte.d.ts +2 -1
  79. package/dist/components/Stepper/Stepper.svelte +4 -1
  80. package/dist/components/Stepper/Stepper.svelte.d.ts +2 -1
  81. package/dist/components/ThemeSelector.svelte +10 -2
  82. package/dist/components/ThemeSelector.svelte.d.ts +2 -1
  83. package/dist/components/ThemeToggle.svelte +10 -1
  84. package/dist/components/ThemeToggle.svelte.d.ts +2 -1
  85. package/dist/components/TimeRangeInput.svelte +5 -1
  86. package/dist/components/TimeRangeInput.svelte.d.ts +3 -1
  87. package/dist/components/Timeline/Timeline.svelte +4 -2
  88. package/dist/components/Timeline/Timeline.svelte.d.ts +2 -1
  89. package/dist/components/TokenInput/TokenInput.svelte +6 -1
  90. package/dist/components/TokenInput/TokenInput.svelte.d.ts +2 -1
  91. package/dist/components/Tree/Tree.svelte +11 -2
  92. package/dist/components/Tree/Tree.svelte.d.ts +2 -1
  93. package/dist/components/field-chrome.d.ts +22 -0
  94. package/dist/components/field-chrome.js +1 -0
  95. package/docs/components.md +27 -1
  96. package/package.json +1 -1
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from "svelte";
3
+ import type { HTMLAttributes } from "svelte/elements";
3
4
  import type { Size } from "../types/sizes.js";
4
5
  import { responsiveClasses, type Responsive } from "../types/responsive.js";
5
6
 
@@ -10,10 +11,12 @@
10
11
  */
11
12
  type AlertVariant =
12
13
  "neutral" | "primary" | "secondary" | "success" | "info" | "warning" | "danger" | "ghost";
13
- interface Props {
14
+ interface Props extends Omit<HTMLAttributes<HTMLDivElement>, "class" | "style"> {
14
15
  variant?: AlertVariant;
15
16
  size?: Responsive<Size>;
16
17
  text?: string;
18
+ /** Optional bold heading rendered above the body (`text`/`children`). Icon top-aligns when set. */
19
+ title?: string;
17
20
  /** Faint tinted background in addition to the bordered + coloured text. */
18
21
  filled?: boolean;
19
22
  /** Drop the visible frame while keeping the 1px box: border colour = the alert's own background
@@ -31,12 +34,14 @@
31
34
  variant = "info",
32
35
  size = "md",
33
36
  text = "",
37
+ title,
34
38
  filled = false,
35
39
  borderless = false,
36
40
  icon,
37
41
  iconPosition = "left",
38
42
  class: cls = "",
39
43
  children,
44
+ ...rest
40
45
  }: Props = $props();
41
46
 
42
47
  // Variant → semantic token (danger maps to the renamed --ui-color-error).
@@ -86,13 +91,14 @@
86
91
  ` color: ${textColor};` +
87
92
  (filled ? ` background-color: ${bgColor};` : ""),
88
93
  );
89
- const has = $derived(!!children || !!text);
94
+ const has = $derived(!!children || !!text || !!title);
90
95
  </script>
91
96
 
92
97
  {#if has}
93
98
  <div
94
99
  role="alert"
95
- class="flex items-center [border-radius:var(--ui-border-radius)] border {responsiveClasses(
100
+ {...rest}
101
+ class="flex {title ? 'items-start' : 'items-center'} [border-radius:var(--ui-border-radius)] border {responsiveClasses(
96
102
  size,
97
103
  sizeClass,
98
104
  )} {cls}"
@@ -104,9 +110,12 @@
104
110
  >{@render icon()}</span
105
111
  >
106
112
  {/if}
107
- <span class="min-w-0"
108
- >{#if children}{@render children()}{:else}{text}{/if}</span
109
- >
113
+ <div class="flex min-w-0 flex-col">
114
+ {#if title}<span class="font-semibold">{title}</span>{/if}
115
+ <span class="min-w-0"
116
+ >{#if children}{@render children()}{:else}{text}{/if}</span
117
+ >
118
+ </div>
110
119
  {#if icon && iconPosition === "right"}
111
120
  <span
112
121
  class="ml-auto inline-flex shrink-0 [&_svg]:fill-current {responsiveClasses(
@@ -1,4 +1,5 @@
1
1
  import type { Snippet } from "svelte";
2
+ import type { HTMLAttributes } from "svelte/elements";
2
3
  import type { Size } from "../types/sizes.js";
3
4
  import { type Responsive } from "../types/responsive.js";
4
5
  /**
@@ -7,10 +8,12 @@ import { type Responsive } from "../types/responsive.js";
7
8
  * hand-rolled `[color:var(--ui-color-error)]` divs. Renders nothing when empty (drop-in for `{#if err}`).
8
9
  */
9
10
  type AlertVariant = "neutral" | "primary" | "secondary" | "success" | "info" | "warning" | "danger" | "ghost";
10
- interface Props {
11
+ interface Props extends Omit<HTMLAttributes<HTMLDivElement>, "class" | "style"> {
11
12
  variant?: AlertVariant;
12
13
  size?: Responsive<Size>;
13
14
  text?: string;
15
+ /** Optional bold heading rendered above the body (`text`/`children`). Icon top-aligns when set. */
16
+ title?: string;
14
17
  /** Faint tinted background in addition to the bordered + coloured text. */
15
18
  filled?: boolean;
16
19
  /** Drop the visible frame while keeping the 1px box: border colour = the alert's own background
@@ -12,6 +12,7 @@
12
12
 
13
13
  <script lang="ts">
14
14
  import type { Snippet } from "svelte";
15
+ import type { HTMLAttributes } from "svelte/elements";
15
16
  import type { Variant } from "../../types/variants.js";
16
17
  import { variantToken } from "../../types/variants.js";
17
18
  import type { Size } from "../../types/sizes.js";
@@ -28,6 +29,7 @@
28
29
  shape = "circle",
29
30
  status,
30
31
  class: cls = "",
32
+ ...rest
31
33
  }: {
32
34
  src?: string;
33
35
  name?: string;
@@ -38,7 +40,7 @@
38
40
  shape?: AvatarShape;
39
41
  status?: AvatarStatus;
40
42
  class?: string;
41
- } = $props();
43
+ } & Omit<HTMLAttributes<HTMLSpanElement>, "class"> = $props();
42
44
 
43
45
  let imgFailed = $state(false);
44
46
  // Reset the failed flag whenever the source changes.
@@ -80,7 +82,7 @@
80
82
  const shapeClass = $derived(shape === "circle" ? "rounded-full" : "rounded-[var(--ui-border-radius)]");
81
83
  </script>
82
84
 
83
- <span class="relative inline-flex shrink-0 {cls}">
85
+ <span class="relative inline-flex shrink-0 {cls}" {...rest}>
84
86
  <span
85
87
  class="ui-avatar inline-flex items-center justify-center overflow-hidden font-medium select-none {shapeClass} {responsiveClasses(
86
88
  size,
@@ -1,6 +1,7 @@
1
1
  export type AvatarShape = "circle" | "square";
2
2
  export type AvatarStatus = "online" | "offline" | "busy" | "away";
3
3
  import type { Snippet } from "svelte";
4
+ import type { HTMLAttributes } from "svelte/elements";
4
5
  import type { Variant } from "../../types/variants.js";
5
6
  import type { Size } from "../../types/sizes.js";
6
7
  import { type Responsive } from "../../types/responsive.js";
@@ -14,7 +15,7 @@ type $$ComponentProps = {
14
15
  shape?: AvatarShape;
15
16
  status?: AvatarStatus;
16
17
  class?: string;
17
- };
18
+ } & Omit<HTMLAttributes<HTMLSpanElement>, "class">;
18
19
  declare const Avatar: import("svelte").Component<$$ComponentProps, {}, "">;
19
20
  type Avatar = ReturnType<typeof Avatar>;
20
21
  export default Avatar;
@@ -21,6 +21,7 @@
21
21
 
22
22
  <script lang="ts">
23
23
  import Avatar from "./Avatar.svelte";
24
+ import type { HTMLAttributes } from "svelte/elements";
24
25
  import { variantToken } from "../../types/variants.js";
25
26
  import type { Size } from "../../types/sizes.js";
26
27
  import { responsiveClasses, type Responsive } from "../../types/responsive.js";
@@ -33,6 +34,7 @@
33
34
  variant = "neutral",
34
35
  class: cls = "",
35
36
  children,
37
+ ...rest
36
38
  }: {
37
39
  items?: AvatarItem[];
38
40
  max?: number;
@@ -41,7 +43,7 @@
41
43
  variant?: Variant;
42
44
  class?: string;
43
45
  children?: Snippet;
44
- } = $props();
46
+ } & Omit<HTMLAttributes<HTMLDivElement>, "class"> = $props();
45
47
 
46
48
  const shown = $derived(
47
49
  items ? (max != null && items.length > max ? items.slice(0, max) : items) : [],
@@ -61,6 +63,7 @@
61
63
  avatars stay visually separated. -->
62
64
  <div
63
65
  class="flex items-center [&_.ui-avatar]:border-2 [&_.ui-avatar]:[border-color:var(--ui-color-background)] [&>*:not(:first-child)]:-ml-2 {cls}"
66
+ {...rest}
64
67
  >
65
68
  {#if items}
66
69
  {#each shown as it, i (i)}
@@ -8,6 +8,7 @@ export type AvatarItem = {
8
8
  variant?: Variant;
9
9
  icon?: Snippet;
10
10
  };
11
+ import type { HTMLAttributes } from "svelte/elements";
11
12
  import type { Size } from "../../types/sizes.js";
12
13
  import { type Responsive } from "../../types/responsive.js";
13
14
  type $$ComponentProps = {
@@ -18,7 +19,7 @@ type $$ComponentProps = {
18
19
  variant?: Variant;
19
20
  class?: string;
20
21
  children?: Snippet;
21
- };
22
+ } & Omit<HTMLAttributes<HTMLDivElement>, "class">;
22
23
  declare const AvatarGroup: import("svelte").Component<$$ComponentProps, {}, "">;
23
24
  type AvatarGroup = ReturnType<typeof AvatarGroup>;
24
25
  export default AvatarGroup;
@@ -2,6 +2,7 @@
2
2
  import { uiI18n } from "../../i18n.js";
3
3
  const i18n = uiI18n();
4
4
  import type { Snippet } from "svelte";
5
+ import type { HTMLAttributes } from "svelte/elements";
5
6
  import Close from "~icons/mdi/close";
6
7
  import type { Size } from "../../types/sizes.js";
7
8
  import { responsiveClasses, type Responsive } from "../../types/responsive.js";
@@ -27,10 +28,21 @@
27
28
  | "danger"
28
29
  | "ghost";
29
30
 
30
- interface Props {
31
+ // Spreads leftover HTML attributes (`class`, `data-*`, `aria-*`, `title`, `id`, event handlers, …)
32
+ // onto the chip's root element. `style` is OMITTED — the chip computes its own themed `style`
33
+ // (fill/border/text `color-mix`); a passthrough would clobber it. Use `class` for overrides.
34
+ interface Props extends Omit<HTMLAttributes<HTMLElement>, "style"> {
31
35
  text?: string;
32
36
  variant?: BadgeVariant;
33
37
  size?: Responsive<Size>;
38
+ /** Arbitrary fill colour — any CSS colour (e.g. a DB-stored `#rrggbb` for data-driven statuses).
39
+ * Overrides `variant` for colour: when set, `variant` is ignored for the fill/border/text
40
+ * (size/radius/`borderless` still apply). Pair with `textColor` for contrast. This is the
41
+ * supported alternative to a `style` override (which the chip owns). */
42
+ color?: string;
43
+ /** Text (and icon) colour paired with `color`. Only used when `color` is set; default
44
+ * `var(--ui-color-text)`. */
45
+ textColor?: string;
34
46
  dismissible?: boolean;
35
47
  rounded?: boolean;
36
48
  /** Hide the border WITHOUT changing the box: the border stays 1px (so height/width are
@@ -49,12 +61,16 @@
49
61
  text = "",
50
62
  variant = "default",
51
63
  size = "md",
64
+ color,
65
+ textColor,
52
66
  dismissible = false,
53
67
  rounded = true,
54
68
  borderless = true,
55
69
  href,
56
70
  ondismiss,
57
71
  children,
72
+ class: cls = "",
73
+ ...rest
58
74
  }: Props = $props();
59
75
 
60
76
  // Every variant maps to a library-wide colour token — no Tailwind
@@ -101,16 +117,26 @@
101
117
  ? "color-mix(in srgb, var(--ui-color-text) 20%, transparent)"
102
118
  : `color-mix(in srgb, var(${token}) var(--ui-tint-border), transparent)`,
103
119
  );
104
- const textColor = $derived(
120
+ const variantText = $derived(
105
121
  variant === "ghost"
106
122
  ? "color-mix(in srgb, var(--ui-color-text) 65%, transparent)"
107
123
  : `color-mix(in srgb, var(${token}) var(--ui-tint-strong), var(--ui-color-text))`,
108
124
  );
109
- const style = $derived(
110
- `background-color: ${bgColor};` +
111
- ` border-color: ${borderless ? bgColor : standardBorder};` +
112
- ` color: ${textColor};`,
125
+ // An explicit `color` overrides the variant entirely: fill = color; ring = color (borderless) or
126
+ // color mixed toward the text at the shared hover-border strength (keeps the ring on the tint
127
+ // scale); text = `textColor` or the theme text colour. Otherwise the variant tokens drive it.
128
+ const fill = $derived(color ?? bgColor);
129
+ const ring = $derived(
130
+ color
131
+ ? borderless
132
+ ? color
133
+ : `color-mix(in srgb, ${color} var(--ui-tint-border-hover), var(--ui-color-text))`
134
+ : borderless
135
+ ? bgColor
136
+ : standardBorder,
113
137
  );
138
+ const fg = $derived(color ? (textColor ?? "var(--ui-color-text)") : variantText);
139
+ const style = $derived(`background-color: ${fill}; border-color: ${ring}; color: ${fg};`);
114
140
 
115
141
  function handleDismiss() {
116
142
  ondismiss?.();
@@ -128,12 +154,13 @@
128
154
  {#if hasContent}
129
155
  <svelte:element
130
156
  this={href ? "a" : "span"}
157
+ {...rest}
131
158
  {href}
132
159
  class="inline-flex items-center gap-1 border no-underline select-none {href
133
160
  ? 'cursor-pointer hover:brightness-95'
134
161
  : 'cursor-default'} {responsiveClasses(size, sizeClass)} {rounded
135
162
  ? 'rounded-full'
136
- : 'rounded'} transition-[filter,background-color,border-color] duration-150"
163
+ : 'rounded'} transition-[filter,background-color,border-color] duration-150 {cls}"
137
164
  {style}
138
165
  >
139
166
  <span class="truncate">
@@ -1,4 +1,5 @@
1
1
  import type { Snippet } from "svelte";
2
+ import type { HTMLAttributes } from "svelte/elements";
2
3
  import type { Size } from "../../types/sizes.js";
3
4
  import { type Responsive } from "../../types/responsive.js";
4
5
  /**
@@ -12,10 +13,18 @@ import { type Responsive } from "../../types/responsive.js";
12
13
  * text stays high-contrast against the background.
13
14
  */
14
15
  type BadgeVariant = "neutral" | "default" | "primary" | "secondary" | "success" | "info" | "warning" | "danger" | "ghost";
15
- interface Props {
16
+ interface Props extends Omit<HTMLAttributes<HTMLElement>, "style"> {
16
17
  text?: string;
17
18
  variant?: BadgeVariant;
18
19
  size?: Responsive<Size>;
20
+ /** Arbitrary fill colour — any CSS colour (e.g. a DB-stored `#rrggbb` for data-driven statuses).
21
+ * Overrides `variant` for colour: when set, `variant` is ignored for the fill/border/text
22
+ * (size/radius/`borderless` still apply). Pair with `textColor` for contrast. This is the
23
+ * supported alternative to a `style` override (which the chip owns). */
24
+ color?: string;
25
+ /** Text (and icon) colour paired with `color`. Only used when `color` is set; default
26
+ * `var(--ui-color-text)`. */
27
+ textColor?: string;
19
28
  dismissible?: boolean;
20
29
  rounded?: boolean;
21
30
  /** Hide the border WITHOUT changing the box: the border stays 1px (so height/width are
@@ -2,6 +2,7 @@
2
2
  import { uiI18n } from "../i18n.js";
3
3
  const i18n = uiI18n();
4
4
  import type { Snippet } from "svelte";
5
+ import type { HTMLAttributes } from "svelte/elements";
5
6
  import type { Size } from "../types/sizes.js";
6
7
  import { responsiveClasses, type Responsive } from "../types/responsive.js";
7
8
  import IconClose from "~icons/mdi/close";
@@ -14,7 +15,7 @@
14
15
  */
15
16
  type BannerVariant =
16
17
  "neutral" | "primary" | "secondary" | "success" | "info" | "warning" | "danger" | "ghost";
17
- interface Props {
18
+ interface Props extends Omit<HTMLAttributes<HTMLDivElement>, "class" | "style"> {
18
19
  variant?: BannerVariant;
19
20
  size?: Responsive<Size>;
20
21
  text?: string;
@@ -43,6 +44,7 @@
43
44
  onClose,
44
45
  class: cls = "",
45
46
  children,
47
+ ...rest
46
48
  }: Props = $props();
47
49
 
48
50
  // Variant → semantic token (danger maps to --ui-color-error).
@@ -104,6 +106,7 @@
104
106
  {#if open}
105
107
  <div
106
108
  role="status"
109
+ {...rest}
107
110
  class="flex w-full items-center border [border-radius:var(--ui-border-radius)] [&_svg]:fill-current {responsiveClasses(
108
111
  size,
109
112
  sizeClass,
@@ -1,4 +1,5 @@
1
1
  import type { Snippet } from "svelte";
2
+ import type { HTMLAttributes } from "svelte/elements";
2
3
  import type { Size } from "../types/sizes.js";
3
4
  import { type Responsive } from "../types/responsive.js";
4
5
  /**
@@ -8,7 +9,7 @@ import { type Responsive } from "../types/responsive.js";
8
9
  * inline field/form status, use <Alert> instead. Honours the shared Size axis (scalar OR responsive).
9
10
  */
10
11
  type BannerVariant = "neutral" | "primary" | "secondary" | "success" | "info" | "warning" | "danger" | "ghost";
11
- interface Props {
12
+ interface Props extends Omit<HTMLAttributes<HTMLDivElement>, "class" | "style"> {
12
13
  variant?: BannerVariant;
13
14
  size?: Responsive<Size>;
14
15
  text?: string;
@@ -19,6 +19,7 @@
19
19
  <script lang="ts">
20
20
  import { uiI18n } from "../../i18n.js";
21
21
  const i18n = uiI18n();
22
+ import type { HTMLAttributes } from "svelte/elements";
22
23
  import Button from "../Button.svelte";
23
24
  import Menu from "../Menu.svelte";
24
25
  import type { MenuItem } from "../../data/table/types.js";
@@ -33,13 +34,14 @@
33
34
  maxItems,
34
35
  size = "md",
35
36
  class: cls = "",
37
+ ...rest
36
38
  }: {
37
39
  items: BreadcrumbItem[];
38
40
  separator?: Snippet | string;
39
41
  maxItems?: number;
40
42
  size?: Responsive<Size>;
41
43
  class?: string;
42
- } = $props();
44
+ } & Omit<HTMLAttributes<HTMLElement>, "class"> = $props();
43
45
 
44
46
  type Node =
45
47
  | { kind: "crumb"; item: BreadcrumbItem; last: boolean }
@@ -73,7 +75,7 @@
73
75
  }
74
76
  </script>
75
77
 
76
- <nav aria-label={i18n.messages.breadcrumb} class={cls}>
78
+ <nav aria-label={i18n.messages.breadcrumb} class={cls} {...rest}>
77
79
  <ol
78
80
  class="flex flex-wrap items-center gap-1 [color:color-mix(in_srgb,var(--ui-color-text)_60%,transparent)]"
79
81
  >
@@ -5,6 +5,7 @@ export type BreadcrumbItem = {
5
5
  onclick?: () => void;
6
6
  icon?: Snippet;
7
7
  };
8
+ import type { HTMLAttributes } from "svelte/elements";
8
9
  import type { Size } from "../../types/sizes.js";
9
10
  import { type Responsive } from "../../types/responsive.js";
10
11
  type $$ComponentProps = {
@@ -13,7 +14,7 @@ type $$ComponentProps = {
13
14
  maxItems?: number;
14
15
  size?: Responsive<Size>;
15
16
  class?: string;
16
- };
17
+ } & Omit<HTMLAttributes<HTMLElement>, "class">;
17
18
  declare const Breadcrumbs: import("svelte").Component<$$ComponentProps, {}, "">;
18
19
  type Breadcrumbs = ReturnType<typeof Breadcrumbs>;
19
20
  export default Breadcrumbs;
@@ -17,6 +17,7 @@
17
17
  variant = "neutral",
18
18
  size = "md",
19
19
  separator = true,
20
+ align = "right",
20
21
  class: cls = "",
21
22
  children,
22
23
  ...rest
@@ -25,10 +26,20 @@
25
26
  size?: Responsive<Size>;
26
27
  /** Show the top separator (default true). */
27
28
  separator?: boolean;
29
+ /** Horizontal placement of the footer content (action buttons). Default `"right"` — footers
30
+ * right-align actions. Convenience over `class`; a `class` justify-* still overrides (applied last). */
31
+ align?: "left" | "center" | "right" | "between";
28
32
  class?: string;
29
33
  children?: Snippet;
30
34
  } & Omit<HTMLAttributes<HTMLDivElement>, "class"> = $props();
31
35
 
36
+ const justifyClass: Record<NonNullable<typeof align>, string> = {
37
+ left: "justify-start",
38
+ center: "justify-center",
39
+ right: "justify-end",
40
+ between: "justify-between",
41
+ };
42
+
32
43
  // The body→footer gap (`pad`) is ALWAYS applied, so `separator={false}` still leaves breathing room
33
44
  // above the footer (just no line). `separator={true}` adds the line + a matching margin above it
34
45
  // (`sepGap`), giving the margin → line → pad rhythm.
@@ -44,7 +55,7 @@
44
55
  </script>
45
56
 
46
57
  <div
47
- class="flex items-center justify-end gap-3 {responsiveClasses(size, pad)} {separator
58
+ class="flex items-center {justifyClass[align]} gap-3 {responsiveClasses(size, pad)} {separator
48
59
  ? 'border-t ' + responsiveClasses(size, sepGap)
49
60
  : ''} {cls}"
50
61
  style={separator ? `border-color: ${sepColor}` : ""}
@@ -8,6 +8,9 @@ type $$ComponentProps = {
8
8
  size?: Responsive<Size>;
9
9
  /** Show the top separator (default true). */
10
10
  separator?: boolean;
11
+ /** Horizontal placement of the footer content (action buttons). Default `"right"` — footers
12
+ * right-align actions. Convenience over `class`; a `class` justify-* still overrides (applied last). */
13
+ align?: "left" | "center" | "right" | "between";
11
14
  class?: string;
12
15
  children?: Snippet;
13
16
  } & Omit<HTMLAttributes<HTMLDivElement>, "class">;
@@ -17,6 +17,7 @@
17
17
  import IconNext from "~icons/mdi/chevron-right";
18
18
  import type { Variant } from "../../types/variants.js";
19
19
  import { variantToken } from "../../types/variants.js";
20
+ import type { HTMLAttributes } from "svelte/elements";
20
21
 
21
22
  let {
22
23
  items,
@@ -29,6 +30,7 @@
29
30
  variant = "primary",
30
31
  ariaLabel = "Carousel",
31
32
  class: cls = "",
33
+ ...rest
32
34
  }: {
33
35
  items: T[];
34
36
  slide: Snippet<[T, number]>;
@@ -41,7 +43,7 @@
41
43
  variant?: Variant;
42
44
  ariaLabel?: string;
43
45
  class?: string;
44
- } = $props();
46
+ } & Omit<HTMLAttributes<HTMLDivElement>, "class"> = $props();
45
47
 
46
48
  const n = $derived(items.length);
47
49
  const token = $derived(variantToken[variant]);
@@ -77,6 +79,7 @@
77
79
 
78
80
  <!-- svelte-ignore a11y_no_noninteractive_element_interactions a11y_no_noninteractive_tabindex (focusable carousel region for keyboard nav) -->
79
81
  <div
82
+ {...rest}
80
83
  role="region"
81
84
  aria-roledescription="carousel"
82
85
  aria-label={ariaLabel}
@@ -1,5 +1,6 @@
1
1
  import type { Snippet } from "svelte";
2
2
  import type { Variant } from "../../types/variants.js";
3
+ import type { HTMLAttributes } from "svelte/elements";
3
4
  declare function $$render<T>(): {
4
5
  props: {
5
6
  items: T[];
@@ -13,7 +14,7 @@ declare function $$render<T>(): {
13
14
  variant?: Variant;
14
15
  ariaLabel?: string;
15
16
  class?: string;
16
- };
17
+ } & Omit<HTMLAttributes<HTMLDivElement>, "class">;
17
18
  exports: {};
18
19
  bindings: "index";
19
20
  slots: {};
@@ -10,6 +10,7 @@
10
10
  -->
11
11
  <script lang="ts">
12
12
  import type { Snippet } from "svelte";
13
+ import type { HTMLAttributes } from "svelte/elements";
13
14
  import IconClose from "~icons/mdi/close";
14
15
  import type { Variant } from "../../types/variants.js";
15
16
  import { variantToken } from "../../types/variants.js";
@@ -30,6 +31,7 @@
30
31
  rounded = true,
31
32
  class: cls = "",
32
33
  children,
34
+ ...rest
33
35
  }: {
34
36
  text?: string;
35
37
  icon?: Snippet;
@@ -44,7 +46,7 @@
44
46
  rounded?: boolean;
45
47
  class?: string;
46
48
  children?: Snippet;
47
- } = $props();
49
+ } & Omit<HTMLAttributes<HTMLElement>, "class" | "style"> = $props();
48
50
 
49
51
  const interactive = $derived(!!onclick || !!href);
50
52
  const isButton = $derived(!!onclick && !href); // role=button (href navigates instead)
@@ -107,6 +109,7 @@
107
109
 
108
110
  <svelte:element
109
111
  this={href ? "a" : "span"}
112
+ {...rest}
110
113
  {href}
111
114
  role={isButton ? "button" : undefined}
112
115
  tabindex={isButton ? (disabled ? -1 : 0) : undefined}
@@ -1,4 +1,5 @@
1
1
  import type { Snippet } from "svelte";
2
+ import type { HTMLAttributes } from "svelte/elements";
2
3
  import type { Variant } from "../../types/variants.js";
3
4
  import type { Size } from "../../types/sizes.js";
4
5
  import { type Responsive } from "../../types/responsive.js";
@@ -16,7 +17,7 @@ type $$ComponentProps = {
16
17
  rounded?: boolean;
17
18
  class?: string;
18
19
  children?: Snippet;
19
- };
20
+ } & Omit<HTMLAttributes<HTMLElement>, "class" | "style">;
20
21
  declare const Chip: import("svelte").Component<$$ComponentProps, {}, "">;
21
22
  type Chip = ReturnType<typeof Chip>;
22
23
  export default Chip;
@@ -7,6 +7,7 @@
7
7
  -->
8
8
  <script lang="ts">
9
9
  import type { Snippet } from "svelte";
10
+ import type { HTMLAttributes } from "svelte/elements";
10
11
  import Input from "../Input.svelte";
11
12
  import Popup from "../Popup.svelte";
12
13
  import IconChevronDown from "~icons/mdi/chevron-down";
@@ -35,6 +36,7 @@
35
36
  id,
36
37
  required = false,
37
38
  class: cls = "",
39
+ ...rest
38
40
  }: {
39
41
  value?: string;
40
42
  options?: string[];
@@ -55,7 +57,7 @@
55
57
  id?: string;
56
58
  required?: boolean;
57
59
  class?: string;
58
- } = $props();
60
+ } & Omit<HTMLAttributes<HTMLInputElement>, "class"> = $props();
59
61
 
60
62
  const baseId = $props.id();
61
63
  const listId = `${baseId}-listbox`;
@@ -155,6 +157,7 @@
155
157
  </script>
156
158
 
157
159
  <Input
160
+ {...rest}
158
161
  bind:value
159
162
  bind:element={inputEl}
160
163
  bind:fieldElement={fieldEl}
@@ -1,4 +1,5 @@
1
1
  import type { Snippet } from "svelte";
2
+ import type { HTMLAttributes } from "svelte/elements";
2
3
  import type { Variant } from "../../types/variants.js";
3
4
  import type { Size } from "../../types/sizes.js";
4
5
  import { type Responsive } from "../../types/responsive.js";
@@ -22,7 +23,7 @@ type $$ComponentProps = {
22
23
  id?: string;
23
24
  required?: boolean;
24
25
  class?: string;
25
- };
26
+ } & Omit<HTMLAttributes<HTMLInputElement>, "class">;
26
27
  declare const Combobox: import("svelte").Component<$$ComponentProps, {}, "value">;
27
28
  type Combobox = ReturnType<typeof Combobox>;
28
29
  export default Combobox;
@@ -22,6 +22,7 @@
22
22
  <script lang="ts">
23
23
  import { uiI18n } from "../../i18n.js";
24
24
  const i18n = uiI18n();
25
+ import type { HTMLAttributes } from "svelte/elements";
25
26
  import Input from "../Input.svelte";
26
27
  import Kbd from "../Kbd/Kbd.svelte";
27
28
  import IconSearch from "~icons/mdi/magnify";
@@ -33,6 +34,7 @@
33
34
  placeholder = "Type a command or search…",
34
35
  empty = "No matching commands",
35
36
  onopen,
37
+ ...rest
36
38
  }: {
37
39
  open?: boolean;
38
40
  commands: Command[];
@@ -41,7 +43,7 @@
41
43
  placeholder?: string;
42
44
  empty?: string;
43
45
  onopen?: () => void;
44
- } = $props();
46
+ } & Omit<HTMLAttributes<HTMLDivElement>, "class"> = $props();
45
47
 
46
48
  let query = $state("");
47
49
  let highlight = $state(0);
@@ -139,7 +141,7 @@
139
141
 
140
142
  {#if open}
141
143
  <!-- svelte-ignore a11y_click_events_have_key_events a11y_no_static_element_interactions -->
142
- <div use:portal class="fixed inset-0 z-[9999] flex justify-center bg-black/40 p-4 pt-[12vh]" role="presentation"
144
+ <div use:portal {...rest} class="fixed inset-0 z-[9999] flex justify-center bg-black/40 p-4 pt-[12vh]" role="presentation"
143
145
  onclick={(e) => { if (e.target === e.currentTarget) open = false; }}>
144
146
  <div
145
147
  class="h-max w-full max-w-xl overflow-hidden rounded-[var(--ui-border-radius)] border shadow-2xl [background-color:var(--ui-color-background)] [border-color:var(--ui-border-color)]"
@@ -9,6 +9,7 @@ export type Command = {
9
9
  disabled?: boolean;
10
10
  onrun: () => void;
11
11
  };
12
+ import type { HTMLAttributes } from "svelte/elements";
12
13
  type $$ComponentProps = {
13
14
  open?: boolean;
14
15
  commands: Command[];
@@ -17,7 +18,7 @@ type $$ComponentProps = {
17
18
  placeholder?: string;
18
19
  empty?: string;
19
20
  onopen?: () => void;
20
- };
21
+ } & Omit<HTMLAttributes<HTMLDivElement>, "class">;
21
22
  declare const CommandPalette: import("svelte").Component<$$ComponentProps, {}, "open">;
22
23
  type CommandPalette = ReturnType<typeof CommandPalette>;
23
24
  export default CommandPalette;