@nqmcreative/ui 0.2.1 → 0.2.3

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 (175) hide show
  1. package/README.md +7 -5
  2. package/dist/core/index.d.ts +1 -1
  3. package/dist/core/index.js +1 -1
  4. package/dist/core/trigger.d.ts +6 -0
  5. package/dist/core/trigger.js +13 -0
  6. package/dist/styles/matte/Button.svelte +4 -4
  7. package/dist/styles/matte/Card.svelte +3 -3
  8. package/dist/styles/matte/Combobox.svelte +2 -2
  9. package/dist/styles/matte/CommandPalette.svelte +32 -7
  10. package/dist/styles/matte/CommandPalette.svelte.d.ts +5 -0
  11. package/dist/styles/matte/DatePicker.svelte +2 -2
  12. package/dist/styles/matte/Drawer.svelte +2 -2
  13. package/dist/styles/matte/Dropzone.svelte +1 -1
  14. package/dist/styles/matte/FeatureCard.svelte +1 -1
  15. package/dist/styles/matte/Input.svelte +4 -4
  16. package/dist/styles/matte/MenuItem.svelte +1 -1
  17. package/dist/styles/matte/Modal.svelte +3 -3
  18. package/dist/styles/matte/NumberInput.svelte +2 -2
  19. package/dist/styles/matte/PasswordInput.svelte +2 -2
  20. package/dist/styles/matte/PricingCard.svelte +3 -3
  21. package/dist/styles/matte/SegmentedControl.svelte +1 -1
  22. package/dist/styles/matte/Select.svelte +1 -1
  23. package/dist/styles/matte/Sidebar.svelte +75 -26
  24. package/dist/styles/matte/Sidebar.svelte.d.ts +15 -1
  25. package/dist/styles/matte/StatsBand.svelte +1 -1
  26. package/dist/styles/matte/Table.svelte +3 -3
  27. package/dist/styles/matte/Testimonial.svelte +2 -2
  28. package/dist/styles/matte/Textarea.svelte +1 -1
  29. package/dist/styles/matte/index.d.ts +1 -1
  30. package/dist/styles/paper/CommandPalette.svelte +25 -2
  31. package/dist/styles/paper/CommandPalette.svelte.d.ts +5 -0
  32. package/dist/styles/paper/Modal.svelte +9 -1
  33. package/dist/styles/paper/Sidebar.svelte +75 -26
  34. package/dist/styles/paper/Sidebar.svelte.d.ts +15 -1
  35. package/dist/styles/paper/fonts.css +34 -7
  36. package/dist/styles/paper/index.d.ts +1 -1
  37. package/dist/styles/paper/theme.css +11 -8
  38. package/dist/styles/sprout/Accordion.svelte +17 -0
  39. package/dist/styles/sprout/Accordion.svelte.d.ts +8 -0
  40. package/dist/styles/sprout/AccordionItem.svelte +46 -0
  41. package/dist/styles/sprout/AccordionItem.svelte.d.ts +14 -0
  42. package/dist/styles/sprout/Alert.svelte +100 -0
  43. package/dist/styles/sprout/Alert.svelte.d.ts +18 -0
  44. package/dist/styles/sprout/Avatar.svelte +60 -0
  45. package/dist/styles/sprout/Avatar.svelte.d.ts +16 -0
  46. package/dist/styles/sprout/AvatarGroup.svelte +17 -0
  47. package/dist/styles/sprout/AvatarGroup.svelte.d.ts +8 -0
  48. package/dist/styles/sprout/Badge.svelte +58 -0
  49. package/dist/styles/sprout/Badge.svelte.d.ts +16 -0
  50. package/dist/styles/sprout/Breadcrumb.svelte +49 -0
  51. package/dist/styles/sprout/Breadcrumb.svelte.d.ts +14 -0
  52. package/dist/styles/sprout/Button.svelte +105 -0
  53. package/dist/styles/sprout/Button.svelte.d.ts +21 -0
  54. package/dist/styles/sprout/CTASection.svelte +77 -0
  55. package/dist/styles/sprout/CTASection.svelte.d.ts +18 -0
  56. package/dist/styles/sprout/Calendar.svelte +202 -0
  57. package/dist/styles/sprout/Calendar.svelte.d.ts +22 -0
  58. package/dist/styles/sprout/Card.svelte +82 -0
  59. package/dist/styles/sprout/Card.svelte.d.ts +21 -0
  60. package/dist/styles/sprout/Checkbox.svelte +76 -0
  61. package/dist/styles/sprout/Checkbox.svelte.d.ts +15 -0
  62. package/dist/styles/sprout/CheckboxGroup.svelte +112 -0
  63. package/dist/styles/sprout/CheckboxGroup.svelte.d.ts +30 -0
  64. package/dist/styles/sprout/Combobox.svelte +267 -0
  65. package/dist/styles/sprout/Combobox.svelte.d.ts +29 -0
  66. package/dist/styles/sprout/CommandPalette.svelte +233 -0
  67. package/dist/styles/sprout/CommandPalette.svelte.d.ts +37 -0
  68. package/dist/styles/sprout/ConfirmDialog.svelte +97 -0
  69. package/dist/styles/sprout/ConfirmDialog.svelte.d.ts +22 -0
  70. package/dist/styles/sprout/ContextMenu.svelte +89 -0
  71. package/dist/styles/sprout/ContextMenu.svelte.d.ts +15 -0
  72. package/dist/styles/sprout/DatePicker.svelte +193 -0
  73. package/dist/styles/sprout/DatePicker.svelte.d.ts +23 -0
  74. package/dist/styles/sprout/Divider.svelte +30 -0
  75. package/dist/styles/sprout/Divider.svelte.d.ts +10 -0
  76. package/dist/styles/sprout/Drawer.svelte +166 -0
  77. package/dist/styles/sprout/Drawer.svelte.d.ts +20 -0
  78. package/dist/styles/sprout/Dropdown.svelte +95 -0
  79. package/dist/styles/sprout/Dropdown.svelte.d.ts +23 -0
  80. package/dist/styles/sprout/Dropzone.svelte +211 -0
  81. package/dist/styles/sprout/Dropzone.svelte.d.ts +29 -0
  82. package/dist/styles/sprout/EmptyState.svelte +71 -0
  83. package/dist/styles/sprout/EmptyState.svelte.d.ts +18 -0
  84. package/dist/styles/sprout/FeatureCard.svelte +61 -0
  85. package/dist/styles/sprout/FeatureCard.svelte.d.ts +16 -0
  86. package/dist/styles/sprout/FeatureGrid.svelte +62 -0
  87. package/dist/styles/sprout/FeatureGrid.svelte.d.ts +16 -0
  88. package/dist/styles/sprout/Field.svelte +42 -0
  89. package/dist/styles/sprout/Field.svelte.d.ts +16 -0
  90. package/dist/styles/sprout/Footer.svelte +91 -0
  91. package/dist/styles/sprout/Footer.svelte.d.ts +25 -0
  92. package/dist/styles/sprout/HeroSection.svelte +86 -0
  93. package/dist/styles/sprout/HeroSection.svelte.d.ts +21 -0
  94. package/dist/styles/sprout/Input.svelte +61 -0
  95. package/dist/styles/sprout/Input.svelte.d.ts +18 -0
  96. package/dist/styles/sprout/InputGroup.svelte +20 -0
  97. package/dist/styles/sprout/InputGroup.svelte.d.ts +11 -0
  98. package/dist/styles/sprout/Kbd.svelte +18 -0
  99. package/dist/styles/sprout/Kbd.svelte.d.ts +8 -0
  100. package/dist/styles/sprout/Label.svelte +16 -0
  101. package/dist/styles/sprout/Label.svelte.d.ts +9 -0
  102. package/dist/styles/sprout/Link.svelte +44 -0
  103. package/dist/styles/sprout/Link.svelte.d.ts +16 -0
  104. package/dist/styles/sprout/LocaleProvider.svelte +24 -0
  105. package/dist/styles/sprout/LocaleProvider.svelte.d.ts +10 -0
  106. package/dist/styles/sprout/LogoCloud.svelte +61 -0
  107. package/dist/styles/sprout/LogoCloud.svelte.d.ts +19 -0
  108. package/dist/styles/sprout/MenuItem.svelte +64 -0
  109. package/dist/styles/sprout/MenuItem.svelte.d.ts +18 -0
  110. package/dist/styles/sprout/MenuSeparator.svelte +22 -0
  111. package/dist/styles/sprout/MenuSeparator.svelte.d.ts +8 -0
  112. package/dist/styles/sprout/Modal.svelte +127 -0
  113. package/dist/styles/sprout/Modal.svelte.d.ts +21 -0
  114. package/dist/styles/sprout/MultiSelect.svelte +288 -0
  115. package/dist/styles/sprout/MultiSelect.svelte.d.ts +31 -0
  116. package/dist/styles/sprout/Navbar.svelte +201 -0
  117. package/dist/styles/sprout/Navbar.svelte.d.ts +33 -0
  118. package/dist/styles/sprout/NumberInput.svelte +97 -0
  119. package/dist/styles/sprout/NumberInput.svelte.d.ts +15 -0
  120. package/dist/styles/sprout/Pagination.svelte +84 -0
  121. package/dist/styles/sprout/Pagination.svelte.d.ts +15 -0
  122. package/dist/styles/sprout/PasswordInput.svelte +101 -0
  123. package/dist/styles/sprout/PasswordInput.svelte.d.ts +12 -0
  124. package/dist/styles/sprout/Popover.svelte +90 -0
  125. package/dist/styles/sprout/Popover.svelte.d.ts +19 -0
  126. package/dist/styles/sprout/PricingCard.svelte +109 -0
  127. package/dist/styles/sprout/PricingCard.svelte.d.ts +25 -0
  128. package/dist/styles/sprout/Progress.svelte +59 -0
  129. package/dist/styles/sprout/Progress.svelte.d.ts +17 -0
  130. package/dist/styles/sprout/Radio.svelte +56 -0
  131. package/dist/styles/sprout/Radio.svelte.d.ts +15 -0
  132. package/dist/styles/sprout/RadioGroup.svelte +96 -0
  133. package/dist/styles/sprout/RadioGroup.svelte.d.ts +27 -0
  134. package/dist/styles/sprout/SegmentedControl.svelte +89 -0
  135. package/dist/styles/sprout/SegmentedControl.svelte.d.ts +25 -0
  136. package/dist/styles/sprout/Select.svelte +62 -0
  137. package/dist/styles/sprout/Select.svelte.d.ts +20 -0
  138. package/dist/styles/sprout/Sidebar.svelte +255 -0
  139. package/dist/styles/sprout/Sidebar.svelte.d.ts +50 -0
  140. package/dist/styles/sprout/Skeleton.svelte +46 -0
  141. package/dist/styles/sprout/Skeleton.svelte.d.ts +13 -0
  142. package/dist/styles/sprout/Slider.svelte +80 -0
  143. package/dist/styles/sprout/Slider.svelte.d.ts +19 -0
  144. package/dist/styles/sprout/Spinner.svelte +34 -0
  145. package/dist/styles/sprout/Spinner.svelte.d.ts +13 -0
  146. package/dist/styles/sprout/Stat.svelte +51 -0
  147. package/dist/styles/sprout/Stat.svelte.d.ts +16 -0
  148. package/dist/styles/sprout/StatsBand.svelte +64 -0
  149. package/dist/styles/sprout/StatsBand.svelte.d.ts +20 -0
  150. package/dist/styles/sprout/Steps.svelte +143 -0
  151. package/dist/styles/sprout/Steps.svelte.d.ts +24 -0
  152. package/dist/styles/sprout/Switch.svelte +65 -0
  153. package/dist/styles/sprout/Switch.svelte.d.ts +14 -0
  154. package/dist/styles/sprout/Table.svelte +218 -0
  155. package/dist/styles/sprout/Table.svelte.d.ts +66 -0
  156. package/dist/styles/sprout/Tabs.svelte +103 -0
  157. package/dist/styles/sprout/Tabs.svelte.d.ts +23 -0
  158. package/dist/styles/sprout/Testimonial.svelte +65 -0
  159. package/dist/styles/sprout/Testimonial.svelte.d.ts +19 -0
  160. package/dist/styles/sprout/Textarea.svelte +55 -0
  161. package/dist/styles/sprout/Textarea.svelte.d.ts +12 -0
  162. package/dist/styles/sprout/ThemeToggle.svelte +131 -0
  163. package/dist/styles/sprout/ThemeToggle.svelte.d.ts +16 -0
  164. package/dist/styles/sprout/Toaster.svelte +133 -0
  165. package/dist/styles/sprout/Toaster.svelte.d.ts +8 -0
  166. package/dist/styles/sprout/Tooltip.svelte +34 -0
  167. package/dist/styles/sprout/Tooltip.svelte.d.ts +12 -0
  168. package/dist/styles/sprout/fonts.css +77 -0
  169. package/dist/styles/sprout/index.d.ts +109 -0
  170. package/dist/styles/sprout/index.js +83 -0
  171. package/dist/styles/sprout/lift.d.ts +40 -0
  172. package/dist/styles/sprout/lift.js +36 -0
  173. package/dist/styles/sprout/theme.css +255 -0
  174. package/package.json +269 -3
  175. package/registry.json +139 -66
@@ -0,0 +1,100 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import type { HTMLAttributes } from 'svelte/elements';
4
+ import {
5
+ toneBorder,
6
+ toneBorderSoft,
7
+ toneSurface,
8
+ toneText,
9
+ type Tone
10
+ } from '../../core/tones.js';
11
+ import { useLocale } from '../../core/locale.svelte.js';
12
+ import { edge } from './lift.js';
13
+
14
+ export type AlertVariant = 'soft' | 'outline' | 'accent';
15
+
16
+ interface Props extends HTMLAttributes<HTMLDivElement> {
17
+ tone?: Tone;
18
+ variant?: AlertVariant;
19
+ title?: string;
20
+ /** Shows a close button and fires `ondismiss`. */
21
+ dismissible?: boolean;
22
+ ondismiss?: () => void;
23
+ /** Replaces the built-in status glyph. */
24
+ icon?: Snippet;
25
+ children?: Snippet;
26
+ }
27
+
28
+ let {
29
+ tone = 'info',
30
+ variant = 'soft',
31
+ title,
32
+ dismissible = false,
33
+ ondismiss,
34
+ icon,
35
+ class: className = '',
36
+ children,
37
+ ...rest
38
+ }: Props = $props();
39
+
40
+ const t = useLocale();
41
+ let open = $state(true);
42
+
43
+ const variants = $derived({
44
+ soft: `${toneSurface[tone]} border ${toneBorderSoft[tone]}`,
45
+ outline: `bg-bg ${edge} border ${toneBorderSoft[tone]}`,
46
+ accent: `${toneSurface[tone]} border-l-4 ${toneBorder[tone]}`
47
+ });
48
+
49
+ function dismiss() {
50
+ open = false;
51
+ ondismiss?.();
52
+ }
53
+ </script>
54
+
55
+ {#if open}
56
+ <div
57
+ role={tone === 'danger' ? 'alert' : 'status'}
58
+ class="flex items-start gap-3 rounded-[20px] p-4 font-sans {variants[variant]} {className}"
59
+ {...rest}
60
+ >
61
+ <span class="mt-0.5 shrink-0 {toneText[tone]}">
62
+ {#if icon}
63
+ {@render icon()}
64
+ {:else}
65
+ <svg class="size-4" viewBox="0 0 16 16" fill="none" aria-hidden="true">
66
+ <circle cx="8" cy="8" r="6.5" stroke="currentColor" stroke-width="1.5" />
67
+ <path d="M8 4.75v4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" />
68
+ <circle cx="8" cy="11.25" r="0.85" fill="currentColor" />
69
+ </svg>
70
+ {/if}
71
+ </span>
72
+
73
+ <div class="flex min-w-0 flex-1 flex-col gap-1">
74
+ {#if title}
75
+ <p class="text-sm leading-snug font-semibold {toneText[tone]}">{title}</p>
76
+ {/if}
77
+ {#if children}
78
+ <div class="text-[13px] leading-relaxed text-text-secondary">{@render children()}</div>
79
+ {/if}
80
+ </div>
81
+
82
+ {#if dismissible}
83
+ <button
84
+ type="button"
85
+ onclick={dismiss}
86
+ aria-label={t.current.dismiss}
87
+ class="-m-1 shrink-0 rounded p-1 text-text-muted transition-colors duration-150 hover:bg-bg/60 hover:text-text focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-current"
88
+ >
89
+ <svg class="size-3.5" viewBox="0 0 14 14" fill="none" aria-hidden="true">
90
+ <path
91
+ d="m2 2 10 10M12 2 2 12"
92
+ stroke="currentColor"
93
+ stroke-width="1.6"
94
+ stroke-linecap="round"
95
+ />
96
+ </svg>
97
+ </button>
98
+ {/if}
99
+ </div>
100
+ {/if}
@@ -0,0 +1,18 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+ import { type Tone } from '../../core/tones.js';
4
+ export type AlertVariant = 'soft' | 'outline' | 'accent';
5
+ interface Props extends HTMLAttributes<HTMLDivElement> {
6
+ tone?: Tone;
7
+ variant?: AlertVariant;
8
+ title?: string;
9
+ /** Shows a close button and fires `ondismiss`. */
10
+ dismissible?: boolean;
11
+ ondismiss?: () => void;
12
+ /** Replaces the built-in status glyph. */
13
+ icon?: Snippet;
14
+ children?: Snippet;
15
+ }
16
+ declare const Alert: import("svelte").Component<Props, {}, "">;
17
+ type Alert = ReturnType<typeof Alert>;
18
+ export default Alert;
@@ -0,0 +1,60 @@
1
+ <script lang="ts">
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+ import { toneSoft, type Tone } from '../../core/tones.js';
4
+
5
+ export type AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
6
+
7
+ interface Props extends HTMLAttributes<HTMLSpanElement> {
8
+ src?: string;
9
+ alt?: string;
10
+ /** Falls back to the initials of this name when there is no `src`. */
11
+ name?: string;
12
+ size?: AvatarSize;
13
+ tone?: Tone;
14
+ /** Rounded square instead of the default circle. */
15
+ squared?: boolean;
16
+ }
17
+
18
+ let {
19
+ src,
20
+ alt,
21
+ name = '',
22
+ size = 'md',
23
+ tone = 'brand',
24
+ squared = false,
25
+ class: className = '',
26
+ ...rest
27
+ }: Props = $props();
28
+
29
+ const sizes: Record<AvatarSize, string> = {
30
+ xs: 'size-6 text-[10px]',
31
+ sm: 'size-8 text-xs',
32
+ md: 'size-10 text-sm',
33
+ lg: 'size-12 text-base',
34
+ xl: 'size-16 text-lg'
35
+ };
36
+
37
+ const initials = $derived(
38
+ name
39
+ .trim()
40
+ .split(/\s+/)
41
+ .slice(0, 2)
42
+ .map((part) => part[0] ?? '')
43
+ .join('')
44
+ .toUpperCase()
45
+ );
46
+ </script>
47
+
48
+ <span
49
+ class="inline-flex shrink-0 items-center justify-center overflow-hidden font-sans font-semibold select-none
50
+ {squared ? 'rounded-2xl' : 'rounded-full'} {sizes[size]} {src
51
+ ? 'bg-bg-inset'
52
+ : toneSoft[tone]} {className}"
53
+ {...rest}
54
+ >
55
+ {#if src}
56
+ <img {src} alt={alt ?? name} class="size-full object-cover" />
57
+ {:else}
58
+ {initials}
59
+ {/if}
60
+ </span>
@@ -0,0 +1,16 @@
1
+ import type { HTMLAttributes } from 'svelte/elements';
2
+ import { type Tone } from '../../core/tones.js';
3
+ export type AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
4
+ interface Props extends HTMLAttributes<HTMLSpanElement> {
5
+ src?: string;
6
+ alt?: string;
7
+ /** Falls back to the initials of this name when there is no `src`. */
8
+ name?: string;
9
+ size?: AvatarSize;
10
+ tone?: Tone;
11
+ /** Rounded square instead of the default circle. */
12
+ squared?: boolean;
13
+ }
14
+ declare const Avatar: import("svelte").Component<Props, {}, "">;
15
+ type Avatar = ReturnType<typeof Avatar>;
16
+ export default Avatar;
@@ -0,0 +1,17 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import type { HTMLAttributes } from 'svelte/elements';
4
+
5
+ interface Props extends HTMLAttributes<HTMLDivElement> {
6
+ children: Snippet;
7
+ }
8
+
9
+ let { class: className = '', children, ...rest }: Props = $props();
10
+ </script>
11
+
12
+ <div
13
+ class="flex items-center *:-ml-2 *:ring-2 *:ring-bg [&>*:first-child]:ml-0 {className}"
14
+ {...rest}
15
+ >
16
+ {@render children()}
17
+ </div>
@@ -0,0 +1,8 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+ interface Props extends HTMLAttributes<HTMLDivElement> {
4
+ children: Snippet;
5
+ }
6
+ declare const AvatarGroup: import("svelte").Component<Props, {}, "">;
7
+ type AvatarGroup = ReturnType<typeof AvatarGroup>;
8
+ export default AvatarGroup;
@@ -0,0 +1,58 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import type { HTMLAttributes } from 'svelte/elements';
4
+ import {
5
+ toneBorderSoft,
6
+ toneFill,
7
+ toneSoft,
8
+ toneSolid,
9
+ toneText,
10
+ type Tone
11
+ } from '../../core/tones.js';
12
+
13
+ export type BadgeVariant = 'soft' | 'solid' | 'outline';
14
+ export type BadgeSize = 'sm' | 'md';
15
+
16
+ interface Props extends HTMLAttributes<HTMLSpanElement> {
17
+ tone?: Tone;
18
+ variant?: BadgeVariant;
19
+ size?: BadgeSize;
20
+ /** Small filled circle before the label. */
21
+ dot?: boolean;
22
+ children: Snippet;
23
+ }
24
+
25
+ let {
26
+ tone = 'brand',
27
+ variant = 'soft',
28
+ size = 'md',
29
+ dot = false,
30
+ class: className = '',
31
+ children,
32
+ ...rest
33
+ }: Props = $props();
34
+
35
+ const variants: Record<BadgeVariant, string> = $derived({
36
+ soft: toneSoft[tone],
37
+ solid: toneSolid[tone],
38
+ outline: `border ${toneBorderSoft[tone]} ${toneText[tone]} bg-bg`
39
+ });
40
+
41
+ const sizes: Record<BadgeSize, string> = {
42
+ sm: 'px-2.5 py-0.5 text-[11px]',
43
+ md: 'px-3 py-1 text-xs'
44
+ };
45
+ </script>
46
+
47
+ <span
48
+ class="inline-flex items-center gap-1.5 rounded-full font-heading font-medium tracking-[0.04em]
49
+ {variants[variant]} {sizes[size]} {className}"
50
+ {...rest}
51
+ >
52
+ {#if dot}
53
+ <span
54
+ class="size-1.5 shrink-0 rounded-full {variant === 'solid' ? 'bg-current' : toneFill[tone]}"
55
+ ></span>
56
+ {/if}
57
+ {@render children()}
58
+ </span>
@@ -0,0 +1,16 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+ import { type Tone } from '../../core/tones.js';
4
+ export type BadgeVariant = 'soft' | 'solid' | 'outline';
5
+ export type BadgeSize = 'sm' | 'md';
6
+ interface Props extends HTMLAttributes<HTMLSpanElement> {
7
+ tone?: Tone;
8
+ variant?: BadgeVariant;
9
+ size?: BadgeSize;
10
+ /** Small filled circle before the label. */
11
+ dot?: boolean;
12
+ children: Snippet;
13
+ }
14
+ declare const Badge: import("svelte").Component<Props, {}, "">;
15
+ type Badge = ReturnType<typeof Badge>;
16
+ export default Badge;
@@ -0,0 +1,49 @@
1
+ <script lang="ts">
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+ import { toneHoverText, type Tone } from '../../core/tones.js';
4
+ import { useLocale } from '../../core/locale.svelte.js';
5
+
6
+ export interface BreadcrumbItem {
7
+ label: string;
8
+ href?: string;
9
+ }
10
+
11
+ interface Props extends HTMLAttributes<HTMLElement> {
12
+ items: BreadcrumbItem[];
13
+ separator?: string;
14
+ tone?: Tone;
15
+ }
16
+
17
+ let { items, separator = '/', tone = 'brand', class: className = '', ...rest }: Props = $props();
18
+
19
+ const t = useLocale();
20
+ </script>
21
+
22
+ <nav aria-label={t.current.breadcrumb} class="font-sans text-sm {className}" {...rest}>
23
+ <ol class="flex flex-wrap items-center gap-1.5">
24
+ {#each items as item, i (item.label)}
25
+ <li class="flex items-center gap-1.5">
26
+ {#if i > 0}
27
+ <span class="text-hairline-strong select-none" aria-hidden="true">{separator}</span>
28
+ {/if}
29
+ {#if item.href && i < items.length - 1}
30
+ <a
31
+ href={item.href}
32
+ class="rounded px-1 py-0.5 text-text-muted transition-colors duration-150 ease-brand-out hover:bg-bg-inset {toneHoverText[
33
+ tone
34
+ ]}"
35
+ >
36
+ {item.label}
37
+ </a>
38
+ {:else}
39
+ <span
40
+ class="px-1 py-0.5 font-medium text-text"
41
+ aria-current={i === items.length - 1 ? 'page' : undefined}
42
+ >
43
+ {item.label}
44
+ </span>
45
+ {/if}
46
+ </li>
47
+ {/each}
48
+ </ol>
49
+ </nav>
@@ -0,0 +1,14 @@
1
+ import type { HTMLAttributes } from 'svelte/elements';
2
+ import { type Tone } from '../../core/tones.js';
3
+ export interface BreadcrumbItem {
4
+ label: string;
5
+ href?: string;
6
+ }
7
+ interface Props extends HTMLAttributes<HTMLElement> {
8
+ items: BreadcrumbItem[];
9
+ separator?: string;
10
+ tone?: Tone;
11
+ }
12
+ declare const Breadcrumb: import("svelte").Component<Props, {}, "">;
13
+ type Breadcrumb = ReturnType<typeof Breadcrumb>;
14
+ export default Breadcrumb;
@@ -0,0 +1,105 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import type { HTMLButtonAttributes } from 'svelte/elements';
4
+ import Spinner from './Spinner.svelte';
5
+ import {
6
+ focusRing,
7
+ toneBorderSoft,
8
+ toneRing,
9
+ toneSoft,
10
+ toneSoftHover,
11
+ toneSolid,
12
+ toneSolidHover,
13
+ toneText,
14
+ type Tone
15
+ } from '../../core/tones.js';
16
+ import { edge, lift } from './lift.js';
17
+
18
+ export type ButtonVariant = 'solid' | 'soft' | 'outline' | 'ghost' | 'link' | 'primary';
19
+ export type ButtonSize = 'sm' | 'md' | 'lg' | 'xl';
20
+
21
+ interface Props extends HTMLButtonAttributes {
22
+ variant?: ButtonVariant;
23
+ tone?: Tone;
24
+ size?: ButtonSize;
25
+ /** Renders an `<a>` instead of a `<button>`. */
26
+ href?: string;
27
+ target?: string;
28
+ rel?: string;
29
+ loading?: boolean;
30
+ /** Stretch to the container's full width. */
31
+ block?: boolean;
32
+ children: Snippet;
33
+ }
34
+
35
+ let {
36
+ variant = 'solid',
37
+ tone = 'brand',
38
+ size = 'md',
39
+ href,
40
+ loading = false,
41
+ block = false,
42
+ disabled = false,
43
+ type = 'button',
44
+ class: className = '',
45
+ children,
46
+ ...rest
47
+ }: Props = $props();
48
+
49
+ // Fully round, in the heading face, and standing on a solid lip it sinks
50
+ // into when pressed: the three things that make a sprout button read as
51
+ // something to touch rather than something to click. The 3px it travels is
52
+ // exactly what the lip loses, so the top face lands where the shadow was.
53
+ const base =
54
+ 'inline-flex items-center justify-center gap-2 rounded-full border font-heading font-semibold whitespace-nowrap transition-[color,background-color,border-color,box-shadow,transform] duration-150 ease-brand-out active:translate-y-[3px] disabled:opacity-50 disabled:pointer-events-none disabled:active:translate-y-0 aria-disabled:opacity-50 aria-disabled:pointer-events-none';
55
+
56
+ // Roomier than the other styles' — a pill needs horizontal padding to keep its label
57
+ // off the curve, and the extra width suits a touch target.
58
+ const sizes: Record<ButtonSize, string> = {
59
+ sm: 'h-9 px-4 text-[13px]',
60
+ md: 'h-11 px-5 text-sm',
61
+ lg: 'h-12 px-6 text-[15px]',
62
+ xl: 'h-14 px-8 text-base'
63
+ };
64
+
65
+ const variantClass = $derived.by(() => {
66
+ switch (variant) {
67
+ case 'primary':
68
+ case 'solid':
69
+ return `border-transparent ${toneSolid[tone]} ${toneSolidHover[tone]} ${lift[tone]}`;
70
+ case 'soft':
71
+ return `border-transparent ${toneSoft[tone]} ${toneSoftHover[tone]} ${edge}`;
72
+ // Outline keeps its own colours on hover — swapping to a solid fill is
73
+ // matte's move, and it fights sprout's soft surfaces.
74
+ case 'outline':
75
+ return `bg-bg ${edge} ${toneText[tone]} ${toneBorderSoft[tone]} hover:bg-bg-alt`;
76
+ // Nothing raised, so nothing to sink: ghost stays flat on the page.
77
+ case 'ghost':
78
+ return `border-transparent bg-transparent ${toneText[tone]} ${toneSoftHover[tone]} active:translate-y-0`;
79
+ // No pill and no dip: this variant is a sentence, not a target.
80
+ case 'link':
81
+ return `border-transparent ${toneText[tone]} h-auto p-0 text-sm underline-offset-4 hover:underline active:translate-y-0`;
82
+ }
83
+ });
84
+
85
+ const isLink = $derived(variant === 'link');
86
+ const inert = $derived(disabled || loading);
87
+ </script>
88
+
89
+ <svelte:element
90
+ this={href ? 'a' : 'button'}
91
+ {href}
92
+ type={href ? undefined : type}
93
+ disabled={href ? undefined : inert}
94
+ aria-disabled={href && inert ? 'true' : undefined}
95
+ aria-busy={loading ? 'true' : undefined}
96
+ role={href ? 'button' : undefined}
97
+ class="{base} {focusRing} {toneRing[tone]} {variantClass} {isLink ? '' : sizes[size]}
98
+ {block ? 'w-full' : ''} {className}"
99
+ {...rest}
100
+ >
101
+ {#if loading}
102
+ <Spinner size={size === 'sm' ? 'xs' : 'sm'} label="" />
103
+ {/if}
104
+ {@render children()}
105
+ </svelte:element>
@@ -0,0 +1,21 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { HTMLButtonAttributes } from 'svelte/elements';
3
+ import { type Tone } from '../../core/tones.js';
4
+ export type ButtonVariant = 'solid' | 'soft' | 'outline' | 'ghost' | 'link' | 'primary';
5
+ export type ButtonSize = 'sm' | 'md' | 'lg' | 'xl';
6
+ interface Props extends HTMLButtonAttributes {
7
+ variant?: ButtonVariant;
8
+ tone?: Tone;
9
+ size?: ButtonSize;
10
+ /** Renders an `<a>` instead of a `<button>`. */
11
+ href?: string;
12
+ target?: string;
13
+ rel?: string;
14
+ loading?: boolean;
15
+ /** Stretch to the container's full width. */
16
+ block?: boolean;
17
+ children: Snippet;
18
+ }
19
+ declare const Button: import("svelte").Component<Props, {}, "">;
20
+ type Button = ReturnType<typeof Button>;
21
+ export default Button;
@@ -0,0 +1,77 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import type { HTMLAttributes } from 'svelte/elements';
4
+ import { toneBorderSoft, toneSolid, toneSurface, type Tone } from '../../core/tones.js';
5
+ import { edge, soft } from './lift.js';
6
+
7
+ export type CTAVariant = 'tinted' | 'solid' | 'outline';
8
+
9
+ interface Props extends HTMLAttributes<HTMLElement> {
10
+ title: string;
11
+ description?: string;
12
+ tone?: Tone;
13
+ variant?: CTAVariant;
14
+ /** Side by side on wide screens instead of stacked and centred. */
15
+ inline?: boolean;
16
+ /** The buttons. */
17
+ actions?: Snippet;
18
+ children?: Snippet;
19
+ }
20
+
21
+ let {
22
+ title,
23
+ description,
24
+ tone = 'brand',
25
+ variant = 'tinted',
26
+ inline = false,
27
+ actions,
28
+ class: className = '',
29
+ children,
30
+ ...rest
31
+ }: Props = $props();
32
+
33
+ const variants = $derived({
34
+ tinted: `${toneSurface[tone]} border ${toneBorderSoft[tone]}`,
35
+ solid: `${toneSolid[tone]} ${soft}`,
36
+ outline: `bg-bg border ${toneBorderSoft[tone]} ${edge}`
37
+ });
38
+
39
+ const onSolid = $derived(variant === 'solid');
40
+ </script>
41
+
42
+ <section class="w-full px-6 py-16 {className}" {...rest}>
43
+ <div
44
+ class="mx-auto flex w-full max-w-6xl gap-8 rounded-[32px] p-10 sm:p-14 {variants[variant]}
45
+ {inline
46
+ ? 'flex-col lg:flex-row lg:items-center lg:justify-between'
47
+ : 'flex-col items-center text-center'}"
48
+ >
49
+ <div class="flex min-w-0 flex-col gap-3 {inline ? '' : 'items-center'}">
50
+ <h2
51
+ class="max-w-2xl font-heading text-3xl font-semibold tracking-tight text-balance {onSolid
52
+ ? 'text-text-inverse'
53
+ : 'text-text'}"
54
+ >
55
+ {title}
56
+ </h2>
57
+ {#if description}
58
+ <p
59
+ class="max-w-xl font-sans leading-relaxed text-pretty {onSolid
60
+ ? 'text-text-inverse/80'
61
+ : 'text-text-secondary'}"
62
+ >
63
+ {description}
64
+ </p>
65
+ {/if}
66
+ {#if children}
67
+ {@render children()}
68
+ {/if}
69
+ </div>
70
+
71
+ {#if actions}
72
+ <div class="flex shrink-0 flex-wrap items-center gap-3 {inline ? '' : 'justify-center'}">
73
+ {@render actions()}
74
+ </div>
75
+ {/if}
76
+ </div>
77
+ </section>
@@ -0,0 +1,18 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+ import { type Tone } from '../../core/tones.js';
4
+ export type CTAVariant = 'tinted' | 'solid' | 'outline';
5
+ interface Props extends HTMLAttributes<HTMLElement> {
6
+ title: string;
7
+ description?: string;
8
+ tone?: Tone;
9
+ variant?: CTAVariant;
10
+ /** Side by side on wide screens instead of stacked and centred. */
11
+ inline?: boolean;
12
+ /** The buttons. */
13
+ actions?: Snippet;
14
+ children?: Snippet;
15
+ }
16
+ declare const CTASection: import("svelte").Component<Props, {}, "">;
17
+ type CTASection = ReturnType<typeof CTASection>;
18
+ export default CTASection;