@marianmeres/stuic 2.66.0 → 3.0.1

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 (208) hide show
  1. package/README.md +292 -4
  2. package/dist/README.md +41 -18
  3. package/dist/actions/index.d.ts +1 -0
  4. package/dist/actions/index.js +1 -0
  5. package/dist/actions/popover/README.md +19 -0
  6. package/dist/actions/popover/index.css +6 -9
  7. package/dist/actions/popover/popover.svelte.js +2 -2
  8. package/dist/actions/tooltip/README.md +18 -0
  9. package/dist/actions/tooltip/index.css +5 -8
  10. package/dist/actions/tooltip/tooltip.svelte.js +1 -1
  11. package/dist/actions/typeahead.svelte.d.ts +53 -0
  12. package/dist/actions/typeahead.svelte.js +328 -0
  13. package/dist/base.css +17 -0
  14. package/dist/components/AlertConfirmPrompt/AlertConfirmPrompt.svelte +10 -10
  15. package/dist/components/AlertConfirmPrompt/AlertConfirmPrompt.svelte.d.ts +4 -3
  16. package/dist/components/AlertConfirmPrompt/Current.svelte +15 -18
  17. package/dist/components/AlertConfirmPrompt/Current.svelte.d.ts +4 -3
  18. package/dist/components/AlertConfirmPrompt/acp-icons.js +5 -4
  19. package/dist/components/AlertConfirmPrompt/index.css +66 -0
  20. package/dist/components/AssetsPreview/AssetsPreview.svelte +91 -73
  21. package/dist/components/AssetsPreview/index.css +61 -0
  22. package/dist/components/Avatar/Avatar.svelte +31 -18
  23. package/dist/components/Avatar/README.md +166 -0
  24. package/dist/components/Avatar/index.css +130 -0
  25. package/dist/components/Backdrop/Backdrop.svelte +7 -2
  26. package/dist/components/Backdrop/README.md +71 -6
  27. package/dist/components/Backdrop/index.css +31 -0
  28. package/dist/components/Button/Button.svelte +116 -124
  29. package/dist/components/Button/Button.svelte.d.ts +35 -24
  30. package/dist/components/Button/README.md +87 -21
  31. package/dist/components/Button/index.css +475 -9
  32. package/dist/components/Button/index.d.ts +1 -1
  33. package/dist/components/Button/index.js +1 -1
  34. package/dist/components/ButtonGroupRadio/ButtonGroupRadio.svelte +7 -39
  35. package/dist/components/ButtonGroupRadio/ButtonGroupRadio.svelte.d.ts +0 -1
  36. package/dist/components/ButtonGroupRadio/README.md +82 -4
  37. package/dist/components/ButtonGroupRadio/index.css +158 -14
  38. package/dist/components/Collapsible/Collapsible.svelte +7 -7
  39. package/dist/components/Collapsible/Collapsible.svelte.d.ts +2 -2
  40. package/dist/components/Collapsible/README.md +34 -2
  41. package/dist/components/Collapsible/index.css +40 -0
  42. package/dist/components/CommandMenu/CommandMenu.svelte +18 -26
  43. package/dist/components/CommandMenu/CommandMenu.svelte.d.ts +0 -1
  44. package/dist/components/CommandMenu/README.md +39 -0
  45. package/dist/components/CommandMenu/index.css +47 -2
  46. package/dist/components/DismissibleMessage/DismissibleMessage.svelte +53 -51
  47. package/dist/components/DismissibleMessage/DismissibleMessage.svelte.d.ts +6 -6
  48. package/dist/components/DismissibleMessage/README.md +93 -11
  49. package/dist/components/DismissibleMessage/index.css +128 -8
  50. package/dist/components/DismissibleMessage/index.d.ts +1 -1
  51. package/dist/components/DropdownMenu/DropdownMenu.svelte +14 -51
  52. package/dist/components/DropdownMenu/DropdownMenu.svelte.d.ts +6 -7
  53. package/dist/components/DropdownMenu/README.md +132 -0
  54. package/dist/components/DropdownMenu/index.css +258 -52
  55. package/dist/components/Input/FieldAssets.svelte +8 -5
  56. package/dist/components/Input/FieldCheckbox.svelte +7 -44
  57. package/dist/components/Input/FieldFile.svelte +1 -6
  58. package/dist/components/Input/FieldInput.svelte +9 -1
  59. package/dist/components/Input/FieldInput.svelte.d.ts +2 -0
  60. package/dist/components/Input/FieldOptions.svelte +42 -39
  61. package/dist/components/Input/FieldRadios.svelte +7 -16
  62. package/dist/components/Input/FieldSelect.svelte +1 -1
  63. package/dist/components/Input/FieldSwitch.svelte +1 -5
  64. package/dist/components/Input/FieldTextarea.svelte +1 -1
  65. package/dist/components/Input/README.md +194 -0
  66. package/dist/components/Input/_internal/FieldRadioInternal.svelte +2 -40
  67. package/dist/components/Input/_internal/InputWrap.svelte +8 -48
  68. package/dist/components/Input/index.css +524 -116
  69. package/dist/components/KbdShortcut/KbdShortcut.svelte +4 -12
  70. package/dist/components/KbdShortcut/README.md +34 -0
  71. package/dist/components/KbdShortcut/index.css +55 -0
  72. package/dist/components/ListItemButton/ListItemButton.svelte +37 -74
  73. package/dist/components/ListItemButton/ListItemButton.svelte.d.ts +1 -10
  74. package/dist/components/ListItemButton/README.md +100 -45
  75. package/dist/components/ListItemButton/index.css +173 -52
  76. package/dist/components/ListItemButton/index.d.ts +1 -1
  77. package/dist/components/ListItemButton/index.js +1 -1
  78. package/dist/components/Modal/Modal.svelte +1 -8
  79. package/dist/components/Modal/README.md +29 -0
  80. package/dist/components/Modal/index.css +38 -0
  81. package/dist/components/ModalDialog/ModalDialog.svelte +2 -21
  82. package/dist/components/ModalDialog/README.md +35 -0
  83. package/dist/components/ModalDialog/index.css +59 -0
  84. package/dist/components/Nav/Nav.svelte +732 -0
  85. package/dist/components/Nav/Nav.svelte.d.ts +110 -0
  86. package/dist/components/Nav/README.md +334 -0
  87. package/dist/components/Nav/index.css +318 -0
  88. package/dist/components/Nav/index.d.ts +1 -0
  89. package/dist/components/Nav/index.js +1 -0
  90. package/dist/components/Notifications/Notifications.svelte +44 -129
  91. package/dist/components/Notifications/Notifications.svelte.d.ts +9 -18
  92. package/dist/components/Notifications/README.md +186 -70
  93. package/dist/components/Notifications/index.css +212 -15
  94. package/dist/components/Notifications/notifications-stack.svelte.d.ts +4 -0
  95. package/dist/components/Notifications/notifications-stack.svelte.js +8 -0
  96. package/dist/components/Progress/Progress.svelte +4 -2
  97. package/dist/components/Progress/Progress.svelte.d.ts +1 -0
  98. package/dist/components/Progress/README.md +97 -11
  99. package/dist/components/Progress/_internal/Bar.svelte +4 -15
  100. package/dist/components/Progress/_internal/Bar.svelte.d.ts +1 -1
  101. package/dist/components/Progress/_internal/Circle.svelte +30 -2
  102. package/dist/components/Progress/_internal/Circle.svelte.d.ts +1 -0
  103. package/dist/components/Progress/index.css +50 -4
  104. package/dist/components/Skeleton/README.md +152 -0
  105. package/dist/components/Skeleton/Skeleton.svelte +9 -9
  106. package/dist/components/Skeleton/Skeleton.svelte.d.ts +0 -1
  107. package/dist/components/Skeleton/index.css +72 -45
  108. package/dist/components/Spinner/README.md +149 -37
  109. package/dist/components/Spinner/Spinner.svelte +14 -38
  110. package/dist/components/Spinner/Spinner.svelte.d.ts +2 -1
  111. package/dist/components/Spinner/SpinnerCircle.svelte +6 -34
  112. package/dist/components/Spinner/SpinnerCircle.svelte.d.ts +1 -0
  113. package/dist/components/Spinner/SpinnerCircleOscillate.svelte +10 -5
  114. package/dist/components/Spinner/SpinnerUnicode.svelte +3 -1
  115. package/dist/components/Spinner/SpinnerUnicode.svelte.d.ts +1 -0
  116. package/dist/components/Spinner/index.css +104 -0
  117. package/dist/components/Switch/README.md +45 -14
  118. package/dist/components/Switch/Switch.svelte +23 -48
  119. package/dist/components/Switch/Switch.svelte.d.ts +4 -2
  120. package/dist/components/Switch/index.css +121 -4
  121. package/dist/components/Switch/index.d.ts +1 -2
  122. package/dist/components/Switch/index.js +1 -2
  123. package/dist/components/TabbedMenu/README.md +37 -21
  124. package/dist/components/TabbedMenu/TabbedMenu.svelte +5 -46
  125. package/dist/components/TabbedMenu/TabbedMenu.svelte.d.ts +0 -1
  126. package/dist/components/TabbedMenu/index.css +84 -17
  127. package/dist/components/ThemePreview/README.md +289 -0
  128. package/dist/components/ThemePreview/ThemePreview.svelte +394 -0
  129. package/dist/components/ThemePreview/ThemePreview.svelte.d.ts +35 -0
  130. package/dist/components/ThemePreview/index.css +509 -0
  131. package/dist/components/ThemePreview/index.d.ts +1 -0
  132. package/dist/components/ThemePreview/index.js +1 -0
  133. package/dist/components/TwCheck/README.md +32 -13
  134. package/dist/components/TwCheck/TwCheck.svelte +11 -9
  135. package/dist/components/TwCheck/TwCheck.svelte.d.ts +0 -1
  136. package/dist/components/TwCheck/index.css +17 -2
  137. package/dist/components/TypeaheadInput/TypeaheadInput.svelte +20 -188
  138. package/dist/components/TypeaheadInput/TypeaheadInput.svelte.d.ts +4 -2
  139. package/dist/components/X/X.svelte +12 -5
  140. package/dist/components/X/X.svelte.d.ts +1 -0
  141. package/dist/icons/index.d.ts +1 -0
  142. package/dist/icons/index.js +1 -0
  143. package/dist/index.css +46 -26
  144. package/dist/index.d.ts +2 -0
  145. package/dist/index.js +2 -0
  146. package/dist/themes/blue-orange.css +217 -0
  147. package/dist/themes/blue-orange.d.ts +6 -0
  148. package/dist/themes/blue-orange.js +175 -0
  149. package/dist/themes/cyan-red.css +217 -0
  150. package/dist/themes/cyan-red.d.ts +6 -0
  151. package/dist/themes/cyan-red.js +175 -0
  152. package/dist/themes/cyan-slate.css +217 -0
  153. package/dist/themes/cyan-slate.d.ts +6 -0
  154. package/dist/themes/cyan-slate.js +175 -0
  155. package/dist/themes/emerald-pink.css +217 -0
  156. package/dist/themes/emerald-pink.d.ts +6 -0
  157. package/dist/themes/emerald-pink.js +175 -0
  158. package/dist/themes/fuchsia-emerald.css +217 -0
  159. package/dist/themes/fuchsia-emerald.d.ts +6 -0
  160. package/dist/themes/fuchsia-emerald.js +175 -0
  161. package/dist/themes/gray.css +217 -0
  162. package/dist/themes/gray.d.ts +6 -0
  163. package/dist/themes/gray.js +175 -0
  164. package/dist/themes/indigo-amber.css +217 -0
  165. package/dist/themes/indigo-amber.d.ts +6 -0
  166. package/dist/themes/indigo-amber.js +175 -0
  167. package/dist/themes/neutral.css +217 -0
  168. package/dist/themes/neutral.d.ts +6 -0
  169. package/dist/themes/neutral.js +175 -0
  170. package/dist/themes/pink-emerald.css +217 -0
  171. package/dist/themes/pink-emerald.d.ts +6 -0
  172. package/dist/themes/pink-emerald.js +175 -0
  173. package/dist/themes/purple-yellow.css +217 -0
  174. package/dist/themes/purple-yellow.d.ts +6 -0
  175. package/dist/themes/purple-yellow.js +175 -0
  176. package/dist/themes/rainbow.css +217 -0
  177. package/dist/themes/rainbow.d.ts +6 -0
  178. package/dist/themes/rainbow.js +180 -0
  179. package/dist/themes/red-blue.css +217 -0
  180. package/dist/themes/red-blue.d.ts +6 -0
  181. package/dist/themes/red-blue.js +175 -0
  182. package/dist/themes/red-cyan.css +217 -0
  183. package/dist/themes/red-cyan.d.ts +6 -0
  184. package/dist/themes/red-cyan.js +175 -0
  185. package/dist/themes/rose-teal.css +217 -0
  186. package/dist/themes/rose-teal.d.ts +6 -0
  187. package/dist/themes/rose-teal.js +175 -0
  188. package/dist/themes/sky-amber.css +217 -0
  189. package/dist/themes/sky-amber.d.ts +6 -0
  190. package/dist/themes/sky-amber.js +175 -0
  191. package/dist/themes/slate-cyan.css +217 -0
  192. package/dist/themes/slate-cyan.d.ts +6 -0
  193. package/dist/themes/slate-cyan.js +175 -0
  194. package/dist/themes/tailwind-color-pairs.md +31 -0
  195. package/dist/themes/teal-rose.css +217 -0
  196. package/dist/themes/teal-rose.d.ts +6 -0
  197. package/dist/themes/teal-rose.js +175 -0
  198. package/dist/themes/violet-lime.css +217 -0
  199. package/dist/themes/violet-lime.d.ts +6 -0
  200. package/dist/themes/violet-lime.js +175 -0
  201. package/dist/utils/design-tokens.d.ts +43 -0
  202. package/dist/utils/design-tokens.js +127 -0
  203. package/dist/utils/index.d.ts +1 -0
  204. package/dist/utils/index.js +1 -0
  205. package/dist/utils/storage-abstraction.js +1 -1
  206. package/package.json +14 -11
  207. package/dist/components/Switch/SwitchButton.svelte +0 -135
  208. package/dist/components/Switch/SwitchButton.svelte.d.ts +0 -21
@@ -1,22 +1,21 @@
1
1
  # Button
2
2
 
3
- A flexible button component with style variants, sizes, and optional toggle/switch behavior. Can render as a button or anchor tag.
3
+ A flexible button component with semantic intents, visual variants, sizes, and optional toggle/switch behavior. Can render as a button or anchor tag.
4
4
 
5
5
  ## Props
6
6
 
7
7
  | Prop | Type | Default | Description |
8
8
  |------|------|---------|-------------|
9
- | `variant` | `"primary" \| "secondary" \| string` | - | Style variant |
10
- | `size` | `"sm" \| "md" \| "lg" \| string` | - | Button size |
11
- | `muted` | `boolean` | `false` | Reduce text contrast for less emphasis |
12
- | `noshadow` | `boolean` | `false` | Remove shadow effect |
13
- | `noborder` | `boolean` | `false` | Remove border |
9
+ | `intent` | `"primary" \| "accent" \| "destructive" \| "warning" \| "success" \| "info"` | - | Semantic color intent |
10
+ | `variant` | `"solid" \| "outline" \| "ghost" \| "soft" \| "link"` | `"solid"` | Visual variant (how colors are applied) |
11
+ | `size` | `"sm" \| "md" \| "lg" \| "xl"` | `"md"` | Button size |
12
+ | `muted` | `boolean` | `false` | Reduce emphasis (lower opacity) |
13
+ | `raised` | `boolean` | `false` | 3D push effect |
14
14
  | `unstyled` | `boolean` | `false` | Skip all default styling |
15
- | `inverse` | `boolean` | `false` | Transparent bg, styled on hover |
16
15
  | `href` | `string` | - | Render as anchor tag with this URL |
17
16
  | `roleSwitch` | `boolean` | `false` | Enable toggle/switch behavior |
18
17
  | `checked` | `boolean` | `false` | Toggle state when `roleSwitch` is true (bindable) |
19
- | `el` | `Element` | - | Element reference (bindable) |
18
+ | `el` | `HTMLElement` | - | Element reference (bindable) |
20
19
  | `class` | `string` | - | Additional CSS classes |
21
20
 
22
21
  ## Snippet Props
@@ -25,32 +24,45 @@ The `children` snippet receives `{ checked }` when `roleSwitch` is enabled.
25
24
 
26
25
  ## Usage
27
26
 
28
- ### Basic Variants
27
+ ### Intent x Variant
29
28
 
30
29
  ```svelte
31
30
  <script lang="ts">
32
- import { Button } from 'stuic';
31
+ import { Button } from '@marianmeres/stuic';
33
32
  </script>
34
33
 
35
- <Button>Default</Button>
36
- <Button variant="primary">Primary</Button>
37
- <Button variant="secondary">Secondary</Button>
34
+ <!-- Intent determines the color palette -->
35
+ <Button intent="primary">Primary</Button>
36
+ <Button intent="destructive">Destructive</Button>
37
+ <Button intent="success">Success</Button>
38
+
39
+ <!-- Variant determines how colors are applied -->
40
+ <Button intent="primary" variant="solid">Solid</Button>
41
+ <Button intent="primary" variant="outline">Outline</Button>
42
+ <Button intent="primary" variant="ghost">Ghost</Button>
43
+ <Button intent="primary" variant="soft">Soft</Button>
44
+ <Button intent="primary" variant="link">Link</Button>
45
+ ```
46
+
47
+ ### Sizes
48
+
49
+ ```svelte
38
50
  <Button size="sm">Small</Button>
51
+ <Button size="md">Medium</Button>
39
52
  <Button size="lg">Large</Button>
53
+ <Button size="xl">Extra Large</Button>
40
54
  ```
41
55
 
42
- ### Inverse Style (Ghost Button)
56
+ ### 3D Push Effect
43
57
 
44
58
  ```svelte
45
- <Button inverse>
46
- Hover to see background
47
- </Button>
59
+ <Button intent="primary" raised>Push Me</Button>
48
60
  ```
49
61
 
50
62
  ### As Link
51
63
 
52
64
  ```svelte
53
- <Button href="/dashboard">
65
+ <Button href="/dashboard" intent="primary">
54
66
  Go to Dashboard
55
67
  </Button>
56
68
  ```
@@ -59,7 +71,7 @@ The `children` snippet receives `{ checked }` when `roleSwitch` is enabled.
59
71
 
60
72
  ```svelte
61
73
  <script lang="ts">
62
- import { Button } from 'stuic';
74
+ import { Button } from '@marianmeres/stuic';
63
75
 
64
76
  let isActive = $state(false);
65
77
  </script>
@@ -74,10 +86,64 @@ The `children` snippet receives `{ checked }` when `roleSwitch` is enabled.
74
86
  ### Custom Styling
75
87
 
76
88
  ```svelte
89
+ <!-- Using unstyled for full control -->
77
90
  <Button
78
91
  unstyled
79
- class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
92
+ class="bg-gradient-to-red from-purple-500 to-pink-500 text-white px-4 py-2 rounded-lg"
80
93
  >
81
- Fully Custom
94
+ Gradient Button
95
+ </Button>
96
+
97
+ <!-- Override component tokens inline -->
98
+ <Button intent="primary" style="--stuic-button-radius: 9999px;">
99
+ Pill Shape
82
100
  </Button>
83
101
  ```
102
+
103
+ ## CSS Variables
104
+
105
+ ### Component Tokens
106
+
107
+ | Variable | Default | Description |
108
+ |----------|---------|-------------|
109
+ | `--stuic-button-radius` | `--radius-md` | Border radius |
110
+ | `--stuic-button-font-family` | `--font-sans` | Font family |
111
+ | `--stuic-button-font-weight` | `--font-weight-medium` | Font weight |
112
+ | `--stuic-button-transition` | `100ms` | Transition duration |
113
+ | `--stuic-button-ring-width` | `3px` | Focus ring width |
114
+ | `--stuic-button-ring-color` | `--stuic-color-ring` | Focus ring color |
115
+ | `--stuic-button-raised-offset` | `2px` | 3D effect offset |
116
+ | `--stuic-button-raised-color` | `rgb(0 0 0 / 0.8)` | 3D shadow color |
117
+
118
+ ### Size Tokens
119
+
120
+ Each size (sm, md, lg, xl) has corresponding tokens:
121
+ - `--stuic-button-padding-x-{size}`
122
+ - `--stuic-button-padding-y-{size}`
123
+ - `--stuic-button-font-size-{size}`
124
+ - `--stuic-button-min-height-{size}`
125
+
126
+ ### Intent Color Tokens
127
+
128
+ Override these to customize intent colors globally:
129
+
130
+ ```css
131
+ :root {
132
+ --stuic-color-primary: var(--color-blue-600);
133
+ --stuic-color-primary-hover: var(--color-blue-700);
134
+ --stuic-color-primary-active: var(--color-blue-800);
135
+ --stuic-color-primary-foreground: var(--color-white);
136
+ }
137
+ ```
138
+
139
+ Available intents: `primary`, `accent`, `destructive`, `warning`, `success`, `info`
140
+
141
+ ## Data Attributes
142
+
143
+ The component uses data attributes for styling:
144
+ - `data-intent` - The intent value
145
+ - `data-variant` - The variant value
146
+ - `data-size` - The size value
147
+ - `data-muted` - Present when muted
148
+ - `data-raised` - Present when raised
149
+ - `data-checked` - Present when roleSwitch is enabled and checked
@@ -1,14 +1,480 @@
1
+ /* ============================================================================
2
+ BUTTON COMPONENT TOKENS
3
+ Override globally: :root { --stuic-button-radius: 0; }
4
+ Override locally: <Button style="--stuic-button-radius: 9999px;">
5
+ ============================================================================ */
6
+
1
7
  /* prettier-ignore */
2
- @theme inline {
3
- --color-button-bg: var(--color-button-bg, var(--color-neutral-200));
4
- --color-button-bg-dark: var(--color-button-bg-dark, var(--color-neutral-500));
8
+ :root {
9
+ /* Component-level customization tokens */
10
+ --stuic-button-radius: var(--radius-md);
11
+ --stuic-button-font-family: var(--font-sans);
12
+ --stuic-button-font-weight: var(--font-weight-medium);
13
+ --stuic-button-transition: 150ms;
14
+
15
+ /* Focus ring */
16
+ --stuic-button-ring-width: 3px;
17
+ --stuic-button-ring-offset: 0px;
18
+ --stuic-button-ring-color: var(--stuic-color-ring);
19
+
20
+ /* Size: sm (min 44px touch target) */
21
+ --stuic-button-padding-x-sm: 0.75rem;
22
+ --stuic-button-padding-y-sm: 0.5rem;
23
+ --stuic-button-font-size-sm: 0.875rem;
24
+ --stuic-button-min-height-sm: 2.75rem; /* 44px - Apple HIG minimum */
25
+
26
+ /* Size: md (min 44px touch target) */
27
+ --stuic-button-padding-x-md: 1rem;
28
+ --stuic-button-padding-y-md: 0.625rem;
29
+ --stuic-button-font-size-md: 1rem;
30
+ --stuic-button-min-height-md: 2.75rem; /* 44px */
31
+
32
+ /* Size: lg */
33
+ --stuic-button-padding-x-lg: 1.25rem;
34
+ --stuic-button-padding-y-lg: 0.625rem;
35
+ --stuic-button-font-size-lg: 1.125rem;
36
+ --stuic-button-min-height-lg: 3rem;
37
+
38
+ /* Size: xl */
39
+ --stuic-button-padding-x-xl: 1.5rem;
40
+ --stuic-button-padding-y-xl: 0.75rem;
41
+ --stuic-button-font-size-xl: 1.25rem;
42
+ --stuic-button-min-height-xl: 3.5rem;
43
+
44
+ /* Raised (3D push) effect */
45
+ --stuic-button-raised-offset: 2px;
46
+ --stuic-button-raised-color: rgb(0 0 0 / 0.8);
47
+ }
48
+
49
+ @layer components {
50
+ /* ============================================================================
51
+ BASE STYLES
52
+ ============================================================================ */
53
+
54
+ .stuic-button {
55
+ /* Layout */
56
+ display: inline-flex;
57
+ align-items: center;
58
+ justify-content: center;
59
+ gap: 0.5rem;
60
+
61
+ /* Typography */
62
+ font-family: var(--stuic-button-font-family);
63
+ font-weight: var(--stuic-button-font-weight);
64
+ line-height: 1;
65
+ text-align: center;
66
+ text-decoration: none;
67
+ white-space: nowrap;
68
+
69
+ /* Box model */
70
+ border-width: 1px;
71
+ border-style: solid;
72
+ border-radius: var(--stuic-button-radius);
73
+
74
+ /* Interaction */
75
+ cursor: pointer;
76
+ user-select: none;
77
+ -webkit-tap-highlight-color: transparent; /* Remove iOS tap highlight */
78
+ touch-action: manipulation; /* Disable double-tap zoom for faster response */
79
+ transition:
80
+ background var(--stuic-button-transition),
81
+ color var(--stuic-button-transition),
82
+ border-color var(--stuic-button-transition),
83
+ opacity var(--stuic-button-transition);
84
+
85
+ /* Colors - use internal vars set by intent/variant */
86
+ background: var(--_bg);
87
+ color: var(--_text);
88
+ border-color: var(--_border);
89
+ }
90
+
91
+ /* Focus styles */
92
+ .stuic-button:focus-visible {
93
+ outline: var(--stuic-button-ring-width) solid
94
+ var(--_ring, var(--stuic-button-ring-color));
95
+ outline-offset: var(--stuic-button-ring-offset);
96
+ }
97
+
98
+ /* Hover state */
99
+ .stuic-button:hover:not(:disabled) {
100
+ background: var(--_bg-hover);
101
+ color: var(--_text-hover);
102
+ border-color: var(--_border-hover);
103
+ }
104
+
105
+ /* Active state */
106
+ .stuic-button:active:not(:disabled) {
107
+ background: var(--_bg-active);
108
+ color: var(--_text-active);
109
+ border-color: var(--_border-active);
110
+ }
111
+
112
+ /* Disabled state */
113
+ .stuic-button:disabled {
114
+ opacity: 0.5;
115
+ cursor: not-allowed;
116
+ }
117
+
118
+ /* ============================================================================
119
+ SIZE VARIANTS
120
+ ============================================================================ */
121
+
122
+ .stuic-button[data-size="sm"] {
123
+ padding: var(--stuic-button-padding-y-sm) var(--stuic-button-padding-x-sm);
124
+ font-size: var(--stuic-button-font-size-sm);
125
+ min-height: var(--stuic-button-min-height-sm);
126
+ }
127
+
128
+ .stuic-button[data-size="md"] {
129
+ padding: var(--stuic-button-padding-y-md) var(--stuic-button-padding-x-md);
130
+ font-size: var(--stuic-button-font-size-md);
131
+ min-height: var(--stuic-button-min-height-md);
132
+ }
133
+
134
+ .stuic-button[data-size="lg"] {
135
+ padding: var(--stuic-button-padding-y-lg) var(--stuic-button-padding-x-lg);
136
+ font-size: var(--stuic-button-font-size-lg);
137
+ min-height: var(--stuic-button-min-height-lg);
138
+ }
139
+
140
+ .stuic-button[data-size="xl"] {
141
+ padding: var(--stuic-button-padding-y-xl) var(--stuic-button-padding-x-xl);
142
+ font-size: var(--stuic-button-font-size-xl);
143
+ min-height: var(--stuic-button-min-height-xl);
144
+ }
145
+
146
+ /* ============================================================================
147
+ INTENT COLOR MAPPING
148
+ Each intent sets the color palette via internal CSS vars.
149
+ ============================================================================ */
150
+
151
+ /* Default (no intent): neutral gray (no blue undertone) */
152
+ .stuic-button:not([data-intent]) {
153
+ --_color: var(--color-neutral-200);
154
+ --_color-hover: var(--color-neutral-300);
155
+ --_color-active: var(--color-neutral-400);
156
+ --_fg: var(--color-neutral-800);
157
+ --_fg-hover: var(--color-neutral-800);
158
+ --_fg-active: var(--color-neutral-800);
159
+ }
160
+
161
+ .stuic-button[data-intent="primary"] {
162
+ --_color: var(--stuic-color-primary);
163
+ --_color-hover: var(--stuic-color-primary-hover);
164
+ --_color-active: var(--stuic-color-primary-active);
165
+ --_fg: var(--stuic-color-primary-foreground);
166
+ --_fg-hover: var(--stuic-color-primary-foreground-hover);
167
+ --_fg-active: var(--stuic-color-primary-foreground-active);
168
+ }
169
+
170
+ .stuic-button[data-intent="accent"] {
171
+ --_color: var(--stuic-color-accent);
172
+ --_color-hover: var(--stuic-color-accent-hover);
173
+ --_color-active: var(--stuic-color-accent-active);
174
+ --_fg: var(--stuic-color-accent-foreground);
175
+ --_fg-hover: var(--stuic-color-accent-foreground-hover);
176
+ --_fg-active: var(--stuic-color-accent-foreground-active);
177
+ }
178
+
179
+ .stuic-button[data-intent="destructive"] {
180
+ --_color: var(--stuic-color-destructive);
181
+ --_color-hover: var(--stuic-color-destructive-hover);
182
+ --_color-active: var(--stuic-color-destructive-active);
183
+ --_fg: var(--stuic-color-destructive-foreground);
184
+ --_fg-hover: var(--stuic-color-destructive-foreground-hover);
185
+ --_fg-active: var(--stuic-color-destructive-foreground-active);
186
+ }
187
+
188
+ .stuic-button[data-intent="warning"] {
189
+ --_color: var(--stuic-color-warning);
190
+ --_color-hover: var(--stuic-color-warning-hover);
191
+ --_color-active: var(--stuic-color-warning-active);
192
+ --_fg: var(--stuic-color-warning-foreground);
193
+ --_fg-hover: var(--stuic-color-warning-foreground-hover);
194
+ --_fg-active: var(--stuic-color-warning-foreground-active);
195
+ }
196
+
197
+ .stuic-button[data-intent="success"] {
198
+ --_color: var(--stuic-color-success);
199
+ --_color-hover: var(--stuic-color-success-hover);
200
+ --_color-active: var(--stuic-color-success-active);
201
+ --_fg: var(--stuic-color-success-foreground);
202
+ --_fg-hover: var(--stuic-color-success-foreground-hover);
203
+ --_fg-active: var(--stuic-color-success-foreground-active);
204
+ }
205
+
206
+ .stuic-button[data-intent="info"] {
207
+ --_color: var(--stuic-color-info);
208
+ --_color-hover: var(--stuic-color-info-hover);
209
+ --_color-active: var(--stuic-color-info-active);
210
+ --_fg: var(--stuic-color-info-foreground);
211
+ --_fg-hover: var(--stuic-color-info-foreground-hover);
212
+ --_fg-active: var(--stuic-color-info-foreground-active);
213
+ }
214
+
215
+ /* ============================================================================
216
+ VARIANT STYLES
217
+ Each variant determines HOW the color palette is applied.
218
+ ============================================================================ */
219
+
220
+ /* Solid (default): filled background with contrasting text */
221
+ .stuic-button[data-variant="solid"],
222
+ .stuic-button:not([data-variant]) {
223
+ --_bg: var(--_color);
224
+ --_bg-hover: var(--_color-hover);
225
+ --_bg-active: var(--_color-active);
226
+ --_text: var(--_fg);
227
+ --_text-hover: var(--_fg-hover);
228
+ --_text-active: var(--_fg-active);
229
+ --_border: var(--_color);
230
+ --_border-hover: var(--_color-hover);
231
+ --_border-active: var(--_color-active);
232
+ }
233
+
234
+ /* Outline: transparent background with colored border and text */
235
+ .stuic-button[data-variant="outline"] {
236
+ --_bg: transparent;
237
+ --_bg-hover: color-mix(in srgb, var(--_color) 10%, transparent);
238
+ --_bg-active: color-mix(in srgb, var(--_color) 20%, transparent);
239
+ --_text: var(--_color);
240
+ --_text-hover: var(--_color-hover);
241
+ --_text-active: var(--_color-active);
242
+ --_border: var(--_color);
243
+ --_border-hover: var(--_color-hover);
244
+ --_border-active: var(--_color-active);
245
+ }
246
+
247
+ /* Ghost: transparent background, colored text, subtle hover state */
248
+ .stuic-button[data-variant="ghost"] {
249
+ --_bg: transparent;
250
+ --_bg-hover: color-mix(in srgb, var(--_color) 10%, transparent);
251
+ --_bg-active: color-mix(in srgb, var(--_color) 20%, transparent);
252
+ --_text: var(--_color);
253
+ --_text-hover: var(--_color-hover);
254
+ --_text-active: var(--_color-active);
255
+ --_border: transparent;
256
+ --_border-hover: transparent;
257
+ --_border-active: transparent;
258
+ }
259
+
260
+ /* Soft: muted/translucent background tint with colored text */
261
+ .stuic-button[data-variant="soft"] {
262
+ --_bg: color-mix(in srgb, var(--_color) 15%, transparent);
263
+ --_bg-hover: color-mix(in srgb, var(--_color) 25%, transparent);
264
+ --_bg-active: color-mix(in srgb, var(--_color) 35%, transparent);
265
+ --_text: var(--_color);
266
+ --_text-hover: var(--_color-hover);
267
+ --_text-active: var(--_color-active);
268
+ --_border: transparent;
269
+ --_border-hover: transparent;
270
+ --_border-active: transparent;
271
+ }
272
+
273
+ /* Link: appears as inline text link, minimal styling */
274
+ .stuic-button[data-variant="link"] {
275
+ --_bg: transparent;
276
+ --_bg-hover: transparent;
277
+ --_bg-active: transparent;
278
+ --_text: var(--_color);
279
+ --_text-hover: var(--_color-hover);
280
+ --_text-active: var(--_color-active);
281
+ --_border: transparent;
282
+ --_border-hover: transparent;
283
+ --_border-active: transparent;
284
+ text-decoration: underline;
285
+ text-underline-offset: 2px;
286
+ min-height: auto;
287
+ padding: 0;
288
+ position: relative;
289
+ }
290
+
291
+ .stuic-button[data-variant="link"]::before {
292
+ content: "";
293
+ position: absolute;
294
+ inset: -12px -8px; /* expands tap area */
295
+ }
296
+
297
+ /* ============================================================================
298
+ DEFAULT INTENT OVERRIDES
299
+ The default intent uses light surface colors - we need visible borders
300
+ for solid and visible text/borders for other variants.
301
+ ============================================================================ */
302
+
303
+ /* Default solid: add visible border */
304
+ .stuic-button:not([data-intent])[data-variant="solid"],
305
+ .stuic-button:not([data-intent]):not([data-variant]) {
306
+ --_border: var(--color-neutral-400);
307
+ --_border-hover: var(--color-neutral-500);
308
+ --_border-active: var(--color-neutral-500);
309
+ }
310
+
311
+ .stuic-button:not([data-intent])[data-variant="outline"] {
312
+ --_text: var(--color-neutral-800);
313
+ --_text-hover: var(--color-neutral-900);
314
+ --_text-active: var(--color-neutral-900);
315
+ --_border: var(--color-neutral-400);
316
+ --_border-hover: var(--color-neutral-400);
317
+ --_border-active: var(--color-neutral-500);
318
+ --_bg-hover: var(--color-neutral-100);
319
+ --_bg-active: var(--color-neutral-200);
320
+ }
321
+
322
+ .stuic-button:not([data-intent])[data-variant="ghost"] {
323
+ --_text: var(--color-neutral-800);
324
+ --_text-hover: var(--color-neutral-900);
325
+ --_text-active: var(--color-neutral-900);
326
+ --_bg-hover: var(--color-neutral-100);
327
+ --_bg-active: var(--color-neutral-200);
328
+ }
329
+
330
+ .stuic-button:not([data-intent])[data-variant="soft"] {
331
+ --_text: var(--color-neutral-800);
332
+ --_text-hover: var(--color-neutral-900);
333
+ --_text-active: var(--color-neutral-900);
334
+ --_bg: var(--color-neutral-100);
335
+ --_bg-hover: var(--color-neutral-200);
336
+ --_bg-active: var(--color-neutral-300);
337
+ }
338
+
339
+ .stuic-button:not([data-intent])[data-variant="link"] {
340
+ --_text: var(--color-neutral-700);
341
+ --_text-hover: var(--color-neutral-900);
342
+ --_text-active: var(--color-neutral-900);
343
+ }
344
+
345
+ /* ============================================================================
346
+ DEFAULT INTENT DARK MODE OVERRIDES
347
+ ============================================================================ */
348
+
349
+ /* Default (no intent) in dark mode: lighter neutral colors */
350
+ .dark .stuic-button:not([data-intent]) {
351
+ --_color: var(--color-neutral-700);
352
+ --_color-hover: var(--color-neutral-600);
353
+ --_color-active: var(--color-neutral-500);
354
+ --_fg: var(--color-neutral-100);
355
+ --_fg-hover: var(--color-neutral-100);
356
+ --_fg-active: var(--color-neutral-100);
357
+ }
358
+
359
+ /* Default solid in dark mode */
360
+ .dark .stuic-button:not([data-intent])[data-variant="solid"],
361
+ .dark .stuic-button:not([data-intent]):not([data-variant]) {
362
+ --_border: var(--color-neutral-500);
363
+ --_border-hover: var(--color-neutral-400);
364
+ --_border-active: var(--color-neutral-400);
365
+ }
366
+
367
+ /* Default outline in dark mode */
368
+ .dark .stuic-button:not([data-intent])[data-variant="outline"] {
369
+ --_text: var(--color-neutral-200);
370
+ --_text-hover: var(--color-neutral-100);
371
+ --_text-active: var(--color-neutral-100);
372
+ --_border: var(--color-neutral-500);
373
+ --_border-hover: var(--color-neutral-400);
374
+ --_border-active: var(--color-neutral-400);
375
+ --_bg-hover: var(--color-neutral-800);
376
+ --_bg-active: var(--color-neutral-700);
377
+ }
378
+
379
+ /* Default ghost in dark mode */
380
+ .dark .stuic-button:not([data-intent])[data-variant="ghost"] {
381
+ --_text: var(--color-neutral-200);
382
+ --_text-hover: var(--color-neutral-100);
383
+ --_text-active: var(--color-neutral-100);
384
+ --_bg-hover: var(--color-neutral-800);
385
+ --_bg-active: var(--color-neutral-700);
386
+ }
387
+
388
+ /* Default soft in dark mode */
389
+ .dark .stuic-button:not([data-intent])[data-variant="soft"] {
390
+ --_text: var(--color-neutral-200);
391
+ --_text-hover: var(--color-neutral-100);
392
+ --_text-active: var(--color-neutral-100);
393
+ --_bg: var(--color-neutral-800);
394
+ --_bg-hover: var(--color-neutral-700);
395
+ --_bg-active: var(--color-neutral-600);
396
+ }
397
+
398
+ /* Default link in dark mode */
399
+ .dark .stuic-button:not([data-intent])[data-variant="link"] {
400
+ --_text: var(--color-neutral-300);
401
+ --_text-hover: var(--color-neutral-100);
402
+ --_text-active: var(--color-neutral-100);
403
+ }
404
+
405
+ /* ============================================================================
406
+ MUTED MODIFIER
407
+ ============================================================================ */
408
+
409
+ .stuic-button[data-muted="true"] {
410
+ opacity: 0.7;
411
+ }
412
+
413
+ .stuic-button[data-muted="true"]:hover:not(:disabled) {
414
+ opacity: 0.85;
415
+ }
416
+
417
+ /* ============================================================================
418
+ RAISED (3D PUSH) EFFECT
419
+ Override globally: :root { --stuic-button-raised-offset: 4px; }
420
+ Override locally: <Button raised style="--stuic-button-raised-offset: 5px;">
421
+ ============================================================================ */
422
+
423
+ .stuic-button[data-raised] {
424
+ box-shadow: var(--stuic-button-raised-offset) var(--stuic-button-raised-offset) 0 0
425
+ var(--stuic-button-raised-color);
426
+ transition:
427
+ background var(--stuic-button-transition),
428
+ color var(--stuic-button-transition),
429
+ border-color var(--stuic-button-transition),
430
+ opacity var(--stuic-button-transition),
431
+ box-shadow var(--stuic-button-transition),
432
+ transform var(--stuic-button-transition);
433
+ }
434
+
435
+ .stuic-button[data-raised]:active:not(:disabled) {
436
+ box-shadow: none;
437
+ transform: translate(
438
+ var(--stuic-button-raised-offset),
439
+ var(--stuic-button-raised-offset)
440
+ );
441
+ }
442
+
443
+ /* ============================================================================
444
+ ROUNDED FULL
445
+ ============================================================================ */
446
+ .stuic-button[data-rounded-full] {
447
+ --stuic-button-radius: 9999px;
448
+ }
449
+
450
+ /* ============================================================================
451
+ SQUARED (1:1 aspect ratio)
452
+ ============================================================================ */
453
+ .stuic-button[data-aspect1] {
454
+ aspect-ratio: 1;
455
+ }
456
+
457
+ .stuic-button[data-aspect1][data-size="sm"] {
458
+ min-width: var(--stuic-button-min-height-sm);
459
+ min-height: var(--stuic-button-min-height-sm);
460
+ padding: var(--stuic-button-padding-y-sm);
461
+ }
5
462
 
6
- --color-button-text: var(--color-button-text, var(--color-black));
7
- --color-button-text-dark: var(--color-button-text-dark, var(--color-white));
463
+ .stuic-button[data-aspect1][data-size="md"] {
464
+ min-width: var(--stuic-button-min-height-md);
465
+ min-height: var(--stuic-button-min-height-md);
466
+ padding: var(--stuic-button-padding-y-md);
467
+ }
8
468
 
9
- --color-button-border: var(--color-button-border, var(--color-neutral-400));
10
- --color-button-border-dark: var(--color-button-border-dark, var(--color-neutral-600));
469
+ .stuic-button[data-aspect1][data-size="lg"] {
470
+ min-width: var(--stuic-button-min-height-lg);
471
+ min-height: var(--stuic-button-min-height-lg);
472
+ padding: var(--stuic-button-padding-y-lg);
473
+ }
11
474
 
12
- --color-button-border-focus: var(--color-button-border-focus, var(--color-neutral-500));
13
- --color-button-border-focus-dark: var(--color-button-border-focus-dark, var(--color-neutral-500));
475
+ .stuic-button[data-aspect1][data-size="xl"] {
476
+ min-width: var(--stuic-button-min-height-xl);
477
+ min-height: var(--stuic-button-min-height-xl);
478
+ padding: var(--stuic-button-padding-y-xl);
479
+ }
14
480
  }
@@ -1 +1 @@
1
- export { default as Button, type Props as ButtonProps } from "./Button.svelte";
1
+ export { default as Button, type Props as ButtonProps, type ButtonVariant, type ButtonSize, } from "./Button.svelte";
@@ -1 +1 @@
1
- export { default as Button } from "./Button.svelte";
1
+ export { default as Button, } from "./Button.svelte";