@loidolt/theme-svelte 0.2.0 → 0.4.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 (92) hide show
  1. package/README.md +21 -0
  2. package/dist/components/Accordion.svelte +100 -0
  3. package/dist/components/Accordion.svelte.d.ts +50 -0
  4. package/dist/components/Alert.svelte +6 -3
  5. package/dist/components/Alert.svelte.d.ts +3 -2
  6. package/dist/components/AlertDialog.svelte +130 -0
  7. package/dist/components/AlertDialog.svelte.d.ts +35 -0
  8. package/dist/components/AppShell.svelte +2 -1
  9. package/dist/components/AppShell.svelte.d.ts +1 -0
  10. package/dist/components/Badge.svelte +9 -2
  11. package/dist/components/Badge.svelte.d.ts +2 -1
  12. package/dist/components/Brand.svelte +29 -15
  13. package/dist/components/Brand.svelte.d.ts +8 -4
  14. package/dist/components/Breadcrumbs.svelte +53 -0
  15. package/dist/components/Breadcrumbs.svelte.d.ts +18 -0
  16. package/dist/components/Button.svelte +43 -21
  17. package/dist/components/Button.svelte.d.ts +9 -4
  18. package/dist/components/Card.svelte +23 -5
  19. package/dist/components/Card.svelte.d.ts +11 -4
  20. package/dist/components/CodeBlock.svelte +55 -0
  21. package/dist/components/CodeBlock.svelte.d.ts +14 -0
  22. package/dist/components/CommentList.svelte +67 -0
  23. package/dist/components/CommentList.svelte.d.ts +53 -0
  24. package/dist/components/Dialog.svelte +25 -3
  25. package/dist/components/Dialog.svelte.d.ts +4 -1
  26. package/dist/components/Drawer.svelte +105 -0
  27. package/dist/components/Drawer.svelte.d.ts +31 -0
  28. package/dist/components/DropdownMenu.svelte +2 -2
  29. package/dist/components/DropdownMenu.svelte.d.ts +1 -1
  30. package/dist/components/EmptyState.svelte +40 -0
  31. package/dist/components/EmptyState.svelte.d.ts +19 -0
  32. package/dist/components/Fieldset.svelte +60 -0
  33. package/dist/components/Fieldset.svelte.d.ts +19 -0
  34. package/dist/components/FileInput.svelte +47 -0
  35. package/dist/components/FileInput.svelte.d.ts +15 -0
  36. package/dist/components/Filmstrip.svelte +72 -0
  37. package/dist/components/Filmstrip.svelte.d.ts +50 -0
  38. package/dist/components/FloatingBar.svelte +43 -0
  39. package/dist/components/FloatingBar.svelte.d.ts +16 -0
  40. package/dist/components/IconButton.svelte +1 -1
  41. package/dist/components/Input.svelte.d.ts +1 -1
  42. package/dist/components/ListRow.svelte +50 -0
  43. package/dist/components/ListRow.svelte.d.ts +18 -0
  44. package/dist/components/Marker.svelte +38 -0
  45. package/dist/components/Marker.svelte.d.ts +14 -0
  46. package/dist/components/NavMenu.svelte +6 -1
  47. package/dist/components/NavMenu.svelte.d.ts +2 -1
  48. package/dist/components/NumberField.svelte +12 -1
  49. package/dist/components/NumberField.svelte.d.ts +1 -1
  50. package/dist/components/Pagination.svelte +86 -0
  51. package/dist/components/Pagination.svelte.d.ts +22 -0
  52. package/dist/components/Popover.svelte +24 -3
  53. package/dist/components/Popover.svelte.d.ts +4 -1
  54. package/dist/components/RadioGroup.svelte.d.ts +2 -2
  55. package/dist/components/RecordStepper.svelte +58 -0
  56. package/dist/components/RecordStepper.svelte.d.ts +18 -0
  57. package/dist/components/SegmentedNav.svelte +53 -0
  58. package/dist/components/SegmentedNav.svelte.d.ts +22 -0
  59. package/dist/components/Select.svelte.d.ts +2 -2
  60. package/dist/components/Stat.svelte +41 -0
  61. package/dist/components/Stat.svelte.d.ts +17 -0
  62. package/dist/components/StatusDot.svelte +27 -0
  63. package/dist/components/StatusDot.svelte.d.ts +12 -0
  64. package/dist/components/SwatchGroup.svelte +69 -0
  65. package/dist/components/SwatchGroup.svelte.d.ts +44 -0
  66. package/dist/components/Switch.svelte +19 -0
  67. package/dist/components/Table.svelte +30 -3
  68. package/dist/components/Table.svelte.d.ts +13 -0
  69. package/dist/components/TableHeader.svelte +72 -0
  70. package/dist/components/TableHeader.svelte.d.ts +24 -0
  71. package/dist/components/Tabs.svelte +23 -5
  72. package/dist/components/Tabs.svelte.d.ts +4 -3
  73. package/dist/components/Textarea.svelte.d.ts +1 -1
  74. package/dist/components/ThemeToggle.svelte +133 -0
  75. package/dist/components/ThemeToggle.svelte.d.ts +20 -0
  76. package/dist/components/Thumbnail.svelte +51 -0
  77. package/dist/components/Thumbnail.svelte.d.ts +19 -0
  78. package/dist/components/ToggleGroup.svelte +107 -0
  79. package/dist/components/ToggleGroup.svelte.d.ts +46 -0
  80. package/dist/components/TooltipProvider.svelte +1 -0
  81. package/dist/components/Workspace.svelte +27 -6
  82. package/dist/components/Workspace.svelte.d.ts +12 -0
  83. package/dist/index.d.ts +29 -2
  84. package/dist/index.js +26 -1
  85. package/dist/media.svelte.d.ts +48 -0
  86. package/dist/media.svelte.js +69 -0
  87. package/dist/theme.svelte.d.ts +86 -0
  88. package/dist/theme.svelte.js +166 -0
  89. package/dist/toaster.svelte.d.ts +2 -0
  90. package/dist/toaster.svelte.js +51 -9
  91. package/dist/types.d.ts +21 -0
  92. package/package.json +10 -8
@@ -0,0 +1,86 @@
1
+ <script lang="ts">
2
+ import { Pagination as PaginationPrimitive } from 'bits-ui';
3
+ import type { HTMLAttributes } from 'svelte/elements';
4
+ import { cx } from '../utils.js';
5
+
6
+ interface Props extends Omit<HTMLAttributes<HTMLElement>, 'children'> {
7
+ /** Total number of items being paged through — not the number of pages. */
8
+ count: number;
9
+ perPage?: number;
10
+ /** 1-based current page. */
11
+ page?: number;
12
+ /** Pages kept either side of the current one before the trail turns into an ellipsis. */
13
+ siblingCount?: number;
14
+ /** Accessible name of the landmark. */
15
+ label?: string;
16
+ previousLabel?: string;
17
+ nextLabel?: string;
18
+ /** Accessible name for a page button, e.g. `(page) => `Page ${page}``. */
19
+ pageLabel?: (page: number) => string;
20
+ onPageChange?: (page: number) => void;
21
+ class?: string;
22
+ ref?: HTMLElement | null;
23
+ }
24
+
25
+ let {
26
+ count,
27
+ perPage = 10,
28
+ page = $bindable(1),
29
+ siblingCount = 1,
30
+ label = 'Pagination',
31
+ previousLabel = 'Previous',
32
+ nextLabel = 'Next',
33
+ pageLabel = (value: number) => `Page ${value}`,
34
+ onPageChange,
35
+ class: className,
36
+ ref = $bindable(null),
37
+ ...rest
38
+ }: Props = $props();
39
+ </script>
40
+
41
+ <!--
42
+ Bits' Root is a `<div>`; the landmark is ours, so the control set is reachable as "Pagination"
43
+ from a rotor without the page having to add one.
44
+ -->
45
+ <nav bind:this={ref} class={cx('ldt-pagination', className)} aria-label={label} {...rest}>
46
+ <PaginationPrimitive.Root
47
+ {count}
48
+ {perPage}
49
+ {siblingCount}
50
+ bind:page
51
+ onPageChange={(next) => onPageChange?.(next)}
52
+ class="ldt-pagination__list"
53
+ >
54
+ {#snippet children({ pages, currentPage })}
55
+ <PaginationPrimitive.PrevButton class="ldt-button ldt-button--quiet ldt-button--sm"
56
+ >{previousLabel}</PaginationPrimitive.PrevButton
57
+ >
58
+ {#each pages as item (item.key)}
59
+ {#if item.type === 'ellipsis'}
60
+ <!-- Presentational: the gap is a rendering device, and "…" read aloud between page
61
+ numbers is noise. The page buttons either side already say where the trail jumps. -->
62
+ <span class="ldt-pagination__ellipsis" aria-hidden="true">…</span>
63
+ {:else}
64
+ <!--
65
+ Rendered through Bits' `child` snippet rather than as a styled primitive: the
66
+ primitive merges its own `aria-label` last and would overwrite `pageLabel`. Spreading
67
+ `props` first leaves its behaviour intact while the naming stays ours.
68
+ -->
69
+ <PaginationPrimitive.Page page={item}>
70
+ {#snippet child({ props })}
71
+ <button
72
+ {...props}
73
+ class="ldt-button ldt-button--quiet ldt-button--sm ldt-pagination__page"
74
+ aria-label={pageLabel(item.value)}
75
+ aria-current={item.value === currentPage ? 'page' : undefined}>{item.value}</button
76
+ >
77
+ {/snippet}
78
+ </PaginationPrimitive.Page>
79
+ {/if}
80
+ {/each}
81
+ <PaginationPrimitive.NextButton class="ldt-button ldt-button--quiet ldt-button--sm"
82
+ >{nextLabel}</PaginationPrimitive.NextButton
83
+ >
84
+ {/snippet}
85
+ </PaginationPrimitive.Root>
86
+ </nav>
@@ -0,0 +1,22 @@
1
+ import type { HTMLAttributes } from 'svelte/elements';
2
+ interface Props extends Omit<HTMLAttributes<HTMLElement>, 'children'> {
3
+ /** Total number of items being paged through — not the number of pages. */
4
+ count: number;
5
+ perPage?: number;
6
+ /** 1-based current page. */
7
+ page?: number;
8
+ /** Pages kept either side of the current one before the trail turns into an ellipsis. */
9
+ siblingCount?: number;
10
+ /** Accessible name of the landmark. */
11
+ label?: string;
12
+ previousLabel?: string;
13
+ nextLabel?: string;
14
+ /** Accessible name for a page button, e.g. `(page) => `Page ${page}``. */
15
+ pageLabel?: (page: number) => string;
16
+ onPageChange?: (page: number) => void;
17
+ class?: string;
18
+ ref?: HTMLElement | null;
19
+ }
20
+ declare const Pagination: import("svelte").Component<Props, {}, "ref" | "page">;
21
+ type Pagination = ReturnType<typeof Pagination>;
22
+ export default Pagination;
@@ -2,7 +2,13 @@
2
2
  import { Popover as PopoverPrimitive } from 'bits-ui';
3
3
  import type { Snippet } from 'svelte';
4
4
  import type { PopoverContentProps } from 'bits-ui';
5
- import type { Alignment, Placement, TriggerChildProps } from '../types.js';
5
+ import type {
6
+ ActionVariant,
7
+ Alignment,
8
+ ControlSize,
9
+ Placement,
10
+ TriggerChildProps,
11
+ } from '../types.js';
6
12
  import { cx } from '../utils.js';
7
13
 
8
14
  type Props = Omit<PopoverContentProps, 'children' | 'class' | 'child'> & {
@@ -10,6 +16,9 @@
10
16
  trigger?: Snippet;
11
17
  /** Full control of the trigger element — receives the props Bits needs on it. */
12
18
  triggerChild?: Snippet<[TriggerChildProps]>;
19
+ /** Button variant for the default trigger (`quiet` unless set). An explicit `triggerClass` wins wholesale. */
20
+ triggerVariant?: ActionVariant;
21
+ triggerSize?: ControlSize;
13
22
  triggerClass?: string;
14
23
  children: Snippet;
15
24
  side?: Placement;
@@ -25,7 +34,9 @@
25
34
  open = $bindable(false),
26
35
  trigger,
27
36
  triggerChild,
28
- triggerClass = 'ldt-button ldt-button--quiet',
37
+ triggerVariant,
38
+ triggerSize,
39
+ triggerClass,
29
40
  children,
30
41
  side = 'bottom',
31
42
  align = 'start',
@@ -35,6 +46,16 @@
35
46
  ref = $bindable(null),
36
47
  ...rest
37
48
  }: Props = $props();
49
+
50
+ // Popover's historical default trigger is the quiet button; an explicit triggerClass wins.
51
+ const triggerClasses = $derived(
52
+ triggerClass ??
53
+ cx(
54
+ 'ldt-button',
55
+ (triggerVariant ?? 'quiet') !== 'default' && `ldt-button--${triggerVariant ?? 'quiet'}`,
56
+ triggerSize && triggerSize !== 'md' && `ldt-button--${triggerSize}`
57
+ )
58
+ );
38
59
  </script>
39
60
 
40
61
  <PopoverPrimitive.Root bind:open {onOpenChange}>
@@ -42,7 +63,7 @@
42
63
  >{#snippet child(childProps)}{@render triggerChild(
43
64
  childProps
44
65
  )}{/snippet}</PopoverPrimitive.Trigger
45
- >{:else if trigger}<PopoverPrimitive.Trigger class={triggerClass}
66
+ >{:else if trigger}<PopoverPrimitive.Trigger class={triggerClasses}
46
67
  >{@render trigger()}</PopoverPrimitive.Trigger
47
68
  >{/if}
48
69
  <PopoverPrimitive.Portal
@@ -1,11 +1,14 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  import type { PopoverContentProps } from 'bits-ui';
3
- import type { Alignment, Placement, TriggerChildProps } from '../types.js';
3
+ import type { ActionVariant, Alignment, ControlSize, Placement, TriggerChildProps } from '../types.js';
4
4
  type Props = Omit<PopoverContentProps, 'children' | 'class' | 'child'> & {
5
5
  open?: boolean;
6
6
  trigger?: Snippet;
7
7
  /** Full control of the trigger element — receives the props Bits needs on it. */
8
8
  triggerChild?: Snippet<[TriggerChildProps]>;
9
+ /** Button variant for the default trigger (`quiet` unless set). An explicit `triggerClass` wins wholesale. */
10
+ triggerVariant?: ActionVariant;
11
+ triggerSize?: ControlSize;
9
12
  triggerClass?: string;
10
13
  children: Snippet;
11
14
  side?: Placement;
@@ -14,7 +14,7 @@ declare function $$render<T extends string = string>(): {
14
14
  ref?: HTMLFieldSetElement | null;
15
15
  };
16
16
  exports: {};
17
- bindings: "ref" | "value";
17
+ bindings: "value" | "ref";
18
18
  slots: {};
19
19
  events: {};
20
20
  };
@@ -22,7 +22,7 @@ declare class __sveltets_Render<T extends string = string> {
22
22
  props(): ReturnType<typeof $$render<T>>['props'];
23
23
  events(): ReturnType<typeof $$render<T>>['events'];
24
24
  slots(): ReturnType<typeof $$render<T>>['slots'];
25
- bindings(): "ref" | "value";
25
+ bindings(): "value" | "ref";
26
26
  exports(): {};
27
27
  }
28
28
  interface $$IsomorphicComponent {
@@ -0,0 +1,58 @@
1
+ <script lang="ts">
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+ import { cx } from '../utils.js';
4
+
5
+ interface Props extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
6
+ /** 0-based position in the set; `format` receives it 1-based. */
7
+ index: number;
8
+ total: number;
9
+ onPrevious?: () => void;
10
+ onNext?: () => void;
11
+ label?: string;
12
+ previousLabel?: string;
13
+ nextLabel?: string;
14
+ format?: (n: number, total: number) => string;
15
+ disabled?: boolean;
16
+ class?: string;
17
+ ref?: HTMLDivElement | null;
18
+ }
19
+
20
+ let {
21
+ index,
22
+ total,
23
+ onPrevious,
24
+ onNext,
25
+ label = 'Records',
26
+ previousLabel = 'Previous',
27
+ nextLabel = 'Next',
28
+ format = (n, t) => `${n} of ${t}`,
29
+ disabled = false,
30
+ class: className,
31
+ ref = $bindable(null),
32
+ ...rest
33
+ }: Props = $props();
34
+ </script>
35
+
36
+ <div
37
+ bind:this={ref}
38
+ class={cx('ldt-record-stepper', className)}
39
+ role="group"
40
+ aria-label={label}
41
+ {...rest}
42
+ >
43
+ <button
44
+ type="button"
45
+ class="ldt-button ldt-button--text ldt-button--sm"
46
+ disabled={disabled || index <= 0}
47
+ onclick={() => onPrevious?.()}>{previousLabel}</button
48
+ >
49
+ <span class="ldt-record-stepper__count ldt-utility-text" aria-live="polite"
50
+ >{format(index + 1, total)}</span
51
+ >
52
+ <button
53
+ type="button"
54
+ class="ldt-button ldt-button--text ldt-button--sm"
55
+ disabled={disabled || index >= total - 1}
56
+ onclick={() => onNext?.()}>{nextLabel}</button
57
+ >
58
+ </div>
@@ -0,0 +1,18 @@
1
+ import type { HTMLAttributes } from 'svelte/elements';
2
+ interface Props extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
3
+ /** 0-based position in the set; `format` receives it 1-based. */
4
+ index: number;
5
+ total: number;
6
+ onPrevious?: () => void;
7
+ onNext?: () => void;
8
+ label?: string;
9
+ previousLabel?: string;
10
+ nextLabel?: string;
11
+ format?: (n: number, total: number) => string;
12
+ disabled?: boolean;
13
+ class?: string;
14
+ ref?: HTMLDivElement | null;
15
+ }
16
+ declare const RecordStepper: import("svelte").Component<Props, {}, "ref">;
17
+ type RecordStepper = ReturnType<typeof RecordStepper>;
18
+ export default RecordStepper;
@@ -0,0 +1,53 @@
1
+ <script lang="ts">
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+ import type { ControlSize } from '../types.js';
4
+ import { cx } from '../utils.js';
5
+
6
+ interface SegmentedNavItem {
7
+ label: string;
8
+ href: string;
9
+ /** Marks the current page (`aria-current="page"`), which is also the pressed style. */
10
+ current?: boolean;
11
+ /** Small trailing annotation, e.g. "latest". */
12
+ hint?: string;
13
+ }
14
+
15
+ interface Props extends Omit<HTMLAttributes<HTMLElement>, 'children'> {
16
+ items: SegmentedNavItem[];
17
+ /** Accessible name of the navigation region. */
18
+ label?: string;
19
+ size?: ControlSize;
20
+ class?: string;
21
+ itemClass?: string;
22
+ ref?: HTMLElement | null;
23
+ }
24
+
25
+ let {
26
+ items,
27
+ label = 'Sections',
28
+ size = 'md',
29
+ class: className,
30
+ itemClass,
31
+ ref = $bindable(null),
32
+ ...rest
33
+ }: Props = $props();
34
+ </script>
35
+
36
+ <!-- ToggleGroup's shape for navigation: options are real links, so open-in-new-tab and the
37
+ rotor both work — an anchor inside a radiogroup would surrender that. -->
38
+ <nav
39
+ bind:this={ref}
40
+ class={cx('ldt-segmented-nav', size !== 'md' && `ldt-toggle-group--${size}`, className)}
41
+ aria-label={label}
42
+ {...rest}
43
+ >
44
+ {#each items as item, index (index)}
45
+ <a
46
+ class={cx('ldt-toggle-group__item', itemClass)}
47
+ href={item.href}
48
+ aria-current={item.current ? 'page' : undefined}
49
+ >
50
+ {item.label}{#if item.hint}<span class="ldt-segmented-nav__hint">{item.hint}</span>{/if}
51
+ </a>
52
+ {/each}
53
+ </nav>
@@ -0,0 +1,22 @@
1
+ import type { HTMLAttributes } from 'svelte/elements';
2
+ import type { ControlSize } from '../types.js';
3
+ interface SegmentedNavItem {
4
+ label: string;
5
+ href: string;
6
+ /** Marks the current page (`aria-current="page"`), which is also the pressed style. */
7
+ current?: boolean;
8
+ /** Small trailing annotation, e.g. "latest". */
9
+ hint?: string;
10
+ }
11
+ interface Props extends Omit<HTMLAttributes<HTMLElement>, 'children'> {
12
+ items: SegmentedNavItem[];
13
+ /** Accessible name of the navigation region. */
14
+ label?: string;
15
+ size?: ControlSize;
16
+ class?: string;
17
+ itemClass?: string;
18
+ ref?: HTMLElement | null;
19
+ }
20
+ declare const SegmentedNav: import("svelte").Component<Props, {}, "ref">;
21
+ type SegmentedNav = ReturnType<typeof SegmentedNav>;
22
+ export default SegmentedNav;
@@ -18,7 +18,7 @@ declare function $$render<T extends string = string>(): {
18
18
  ref?: HTMLSelectElement | null;
19
19
  };
20
20
  exports: {};
21
- bindings: "ref" | "value";
21
+ bindings: "value" | "ref";
22
22
  slots: {};
23
23
  events: {};
24
24
  };
@@ -26,7 +26,7 @@ declare class __sveltets_Render<T extends string = string> {
26
26
  props(): ReturnType<typeof $$render<T>>['props'];
27
27
  events(): ReturnType<typeof $$render<T>>['events'];
28
28
  slots(): ReturnType<typeof $$render<T>>['slots'];
29
- bindings(): "ref" | "value";
29
+ bindings(): "value" | "ref";
30
30
  exports(): {};
31
31
  }
32
32
  interface $$IsomorphicComponent {
@@ -0,0 +1,41 @@
1
+ <script lang="ts">
2
+ import type { HTMLAnchorAttributes, HTMLAttributes } from 'svelte/elements';
3
+ import { cx } from '../utils.js';
4
+
5
+ interface CommonProps {
6
+ label: string;
7
+ value: string | number;
8
+ /** Small accent line above the value, in the eyebrow voice. */
9
+ eyebrow?: string;
10
+ class?: string;
11
+ ref?: HTMLElement | null;
12
+ }
13
+
14
+ type Props = CommonProps &
15
+ (
16
+ | (Omit<HTMLAnchorAttributes, 'class'> & { href: string })
17
+ | (Omit<HTMLAttributes<HTMLElement>, 'class'> & { href?: never })
18
+ );
19
+
20
+ let {
21
+ label,
22
+ value,
23
+ eyebrow,
24
+ href,
25
+ class: className,
26
+ ref = $bindable(null),
27
+ ...rest
28
+ }: Props = $props();
29
+ </script>
30
+
31
+ <svelte:element
32
+ this={href ? 'a' : 'div'}
33
+ bind:this={ref}
34
+ class={cx('ldt-stat', className)}
35
+ {href}
36
+ {...rest}
37
+ >
38
+ {#if eyebrow}<p class="ldt-eyebrow">{eyebrow}</p>{/if}
39
+ <p class="ldt-stat__value">{value}</p>
40
+ <p class="ldt-stat__label">{label}</p>
41
+ </svelte:element>
@@ -0,0 +1,17 @@
1
+ import type { HTMLAnchorAttributes, HTMLAttributes } from 'svelte/elements';
2
+ interface CommonProps {
3
+ label: string;
4
+ value: string | number;
5
+ /** Small accent line above the value, in the eyebrow voice. */
6
+ eyebrow?: string;
7
+ class?: string;
8
+ ref?: HTMLElement | null;
9
+ }
10
+ type Props = CommonProps & ((Omit<HTMLAnchorAttributes, 'class'> & {
11
+ href: string;
12
+ }) | (Omit<HTMLAttributes<HTMLElement>, 'class'> & {
13
+ href?: never;
14
+ }));
15
+ declare const Stat: import("svelte").Component<Props, {}, "ref">;
16
+ type Stat = ReturnType<typeof Stat>;
17
+ export default Stat;
@@ -0,0 +1,27 @@
1
+ <script lang="ts">
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+ import type { BadgeVariant } from '../types.js';
4
+ import { cx } from '../utils.js';
5
+
6
+ interface Props extends HTMLAttributes<HTMLSpanElement> {
7
+ variant?: BadgeVariant;
8
+ /** Accessible name — color alone must never carry the state. */
9
+ label: string;
10
+ class?: string;
11
+ ref?: HTMLSpanElement | null;
12
+ }
13
+
14
+ let {
15
+ variant = 'default',
16
+ label,
17
+ class: className,
18
+ ref = $bindable(null),
19
+ ...rest
20
+ }: Props = $props();
21
+ </script>
22
+
23
+ <span
24
+ bind:this={ref}
25
+ class={cx('ldt-status-dot', variant !== 'default' && `ldt-status-dot--${variant}`, className)}
26
+ {...rest}><span class="ldt-sr-only">{label}</span></span
27
+ >
@@ -0,0 +1,12 @@
1
+ import type { HTMLAttributes } from 'svelte/elements';
2
+ import type { BadgeVariant } from '../types.js';
3
+ interface Props extends HTMLAttributes<HTMLSpanElement> {
4
+ variant?: BadgeVariant;
5
+ /** Accessible name — color alone must never carry the state. */
6
+ label: string;
7
+ class?: string;
8
+ ref?: HTMLSpanElement | null;
9
+ }
10
+ declare const StatusDot: import("svelte").Component<Props, {}, "ref">;
11
+ type StatusDot = ReturnType<typeof StatusDot>;
12
+ export default StatusDot;
@@ -0,0 +1,69 @@
1
+ <script lang="ts" generics="T extends string = string">
2
+ import type { HTMLFieldsetAttributes } from 'svelte/elements';
3
+ import { cx } from '../utils.js';
4
+
5
+ interface SwatchOption<V extends string = string> {
6
+ value: V;
7
+ /** Accessible name of the swatch. Falls back to the color value. */
8
+ label?: string;
9
+ /** Any CSS color. */
10
+ color: string;
11
+ disabled?: boolean;
12
+ }
13
+
14
+ interface Props extends HTMLFieldsetAttributes {
15
+ options: SwatchOption<T>[];
16
+ value?: T;
17
+ onValueChange?: (value: T) => void;
18
+ size?: 'sm' | 'md';
19
+ /** Visible group label, rendered as a `<legend>`. */
20
+ label?: string;
21
+ /** Shared `name` for the radios. Defaults to an SSR-stable generated id. */
22
+ name?: string;
23
+ disabled?: boolean;
24
+ class?: string;
25
+ ref?: HTMLFieldSetElement | null;
26
+ }
27
+
28
+ const generatedName = $props.id();
29
+
30
+ let {
31
+ options,
32
+ value = $bindable(),
33
+ onValueChange,
34
+ size = 'md',
35
+ label,
36
+ name = generatedName,
37
+ disabled = false,
38
+ class: className,
39
+ ref = $bindable(null),
40
+ ...rest
41
+ }: Props = $props();
42
+ </script>
43
+
44
+ <fieldset bind:this={ref} class={cx('ldt-fieldset', className)} {disabled} {...rest}>
45
+ {#if label}<legend class="ldt-legend">{label}</legend>{/if}
46
+ <div class={cx('ldt-swatch-group', size === 'sm' && 'ldt-swatch-group--sm')}>
47
+ {#each options as option (option.value)}
48
+ <label
49
+ class="ldt-swatch-group__swatch"
50
+ style={`--ldt-swatch: ${option.color};`}
51
+ title={option.label ?? option.color}
52
+ >
53
+ <input
54
+ class="ldt-sr-only"
55
+ type="radio"
56
+ {name}
57
+ value={option.value}
58
+ checked={value === option.value}
59
+ disabled={option.disabled}
60
+ onchange={() => {
61
+ value = option.value;
62
+ onValueChange?.(option.value);
63
+ }}
64
+ />
65
+ <span class="ldt-sr-only">{option.label ?? option.color}</span>
66
+ </label>
67
+ {/each}
68
+ </div>
69
+ </fieldset>
@@ -0,0 +1,44 @@
1
+ import type { HTMLFieldsetAttributes } from 'svelte/elements';
2
+ declare function $$render<T extends string = string>(): {
3
+ props: HTMLFieldsetAttributes & {
4
+ options: {
5
+ value: T;
6
+ /** Accessible name of the swatch. Falls back to the color value. */
7
+ label?: string;
8
+ /** Any CSS color. */
9
+ color: string;
10
+ disabled?: boolean;
11
+ }[];
12
+ value?: T;
13
+ onValueChange?: (value: T) => void;
14
+ size?: "sm" | "md";
15
+ /** Visible group label, rendered as a `<legend>`. */
16
+ label?: string;
17
+ /** Shared `name` for the radios. Defaults to an SSR-stable generated id. */
18
+ name?: string;
19
+ disabled?: boolean;
20
+ class?: string;
21
+ ref?: HTMLFieldSetElement | null;
22
+ };
23
+ exports: {};
24
+ bindings: "value" | "ref";
25
+ slots: {};
26
+ events: {};
27
+ };
28
+ declare class __sveltets_Render<T extends string = string> {
29
+ props(): ReturnType<typeof $$render<T>>['props'];
30
+ events(): ReturnType<typeof $$render<T>>['events'];
31
+ slots(): ReturnType<typeof $$render<T>>['slots'];
32
+ bindings(): "value" | "ref";
33
+ exports(): {};
34
+ }
35
+ interface $$IsomorphicComponent {
36
+ new <T extends string = string>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
37
+ $$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
38
+ } & ReturnType<__sveltets_Render<T>['exports']>;
39
+ <T extends string = string>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
40
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
41
+ }
42
+ declare const SwatchGroup: $$IsomorphicComponent;
43
+ type SwatchGroup<T extends string = string> = InstanceType<typeof SwatchGroup<T>>;
44
+ export default SwatchGroup;
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ import { onMount } from 'svelte';
2
3
  import type { Snippet } from 'svelte';
3
4
  import type { HTMLButtonAttributes } from 'svelte/elements';
4
5
  import { cx } from '../utils.js';
@@ -20,6 +21,7 @@
20
21
  checked = $bindable(false),
21
22
  disabled = false,
22
23
  name,
24
+ form,
23
25
  value = 'on',
24
26
  onCheckedChange,
25
27
  onclick,
@@ -29,6 +31,20 @@
29
31
  ...rest
30
32
  }: Props = $props();
31
33
 
34
+ let input = $state<HTMLInputElement | null>(null);
35
+ const initialChecked = checked;
36
+
37
+ onMount(() => {
38
+ const owner = input?.form;
39
+ if (!owner) return;
40
+ const reset = () => {
41
+ checked = initialChecked;
42
+ onCheckedChange?.(checked);
43
+ };
44
+ owner.addEventListener('reset', reset);
45
+ return () => owner.removeEventListener('reset', reset);
46
+ });
47
+
32
48
  function handleClick(event: MouseEvent & { currentTarget: EventTarget & HTMLButtonElement }) {
33
49
  if (disabled) return;
34
50
  checked = !checked;
@@ -43,6 +59,7 @@
43
59
  role="switch"
44
60
  aria-checked={checked}
45
61
  {disabled}
62
+ {form}
46
63
  class={cx('ldt-switch', className)}
47
64
  {...rest}
48
65
  onclick={handleClick}
@@ -51,11 +68,13 @@
51
68
  {#if children}<span>{@render children()}</span>{/if}
52
69
  </button>
53
70
  {#if name}<input
71
+ bind:this={input}
54
72
  type="checkbox"
55
73
  class="ldt-sr-only"
56
74
  tabindex="-1"
57
75
  aria-hidden="true"
58
76
  {name}
77
+ {form}
59
78
  {value}
60
79
  {checked}
61
80
  {disabled}