@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
package/README.md CHANGED
@@ -1,8 +1,296 @@
1
1
  # @marianmeres/stuic
2
2
 
3
- *S*velte *T*ailwind _UI_ *C*omponents.
3
+ **S**velte **T**ailwind **UI** **C**omponents
4
4
 
5
- OPINIONATED, UNSTABLE AND IN PROGRESS...
5
+ An opinionated Svelte 5 component library built with Tailwind CSS v4. Featuring a centralized design token system for consistent theming across all components.
6
6
 
7
- Ongoing effort to build reusable Svelte UI primitives as I need them, inspired by many
8
- other libs -- cherry-picked, combined, adjusted and tweaked to my personal preference and needs.
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @marianmeres/stuic
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```svelte
16
+ <script>
17
+ import { Button, Modal } from "@marianmeres/stuic";
18
+
19
+ let modal;
20
+ </script>
21
+
22
+ <Button onclick={() => modal.open()}>Open Modal</Button>
23
+
24
+ <Modal bind:this={modal}>
25
+ <p>Hello from Modal!</p>
26
+ </Modal>
27
+ ```
28
+
29
+ ## Theming System
30
+
31
+ STUIC uses a 3-layer CSS variable token system that enables both global theming and per-component customization.
32
+
33
+ ### Architecture
34
+
35
+ ```
36
+ Layer 1: Global Semantic Tokens (--stuic-accent, --stuic-surface, etc.)
37
+ ↓ (used as fallback defaults)
38
+ Layer 2: Component Tokens (--stuic-button-bg, --stuic-input-accent, etc.)
39
+ ↓ (Tailwind utility class references)
40
+ Layer 3: Instance Overrides (inline styles, class props)
41
+ ```
42
+
43
+ ### Global Theming
44
+
45
+ Override global tokens in your app's CSS to change the entire library's appearance:
46
+
47
+ ```css
48
+ /* app.css */
49
+ :root {
50
+ /* Change the accent color globally */
51
+ --stuic-accent: #6366f1; /* Indigo brand color */
52
+ --stuic-accent-hover: #4f46e5;
53
+ --stuic-accent-active: #4338ca;
54
+ }
55
+
56
+ .dark {
57
+ --stuic-accent: #818cf8;
58
+ --stuic-accent-hover: #a5b4fc;
59
+ }
60
+ ```
61
+
62
+ ### Per-Component Customization
63
+
64
+ Override specific component tokens:
65
+
66
+ ```css
67
+ :root {
68
+ /* Only change switches to green */
69
+ --stuic-switch-accent: #10b981;
70
+
71
+ /* Custom button colors */
72
+ --stuic-button-bg: #f3f4f6;
73
+ --stuic-button-bg-hover: #e5e7eb;
74
+ }
75
+ ```
76
+
77
+ ### Instance Overrides
78
+
79
+ Use class props or inline styles for one-off customizations:
80
+
81
+ ```svelte
82
+ <Button class="bg-purple-500 hover:bg-purple-600 text-white">
83
+ Custom Button
84
+ </Button>
85
+
86
+ <div style="--stuic-list-item-button-bg-hover: var(--color-blue-500);">
87
+ <ListItemButton>Blue hover</ListItemButton>
88
+ </div>
89
+ ```
90
+
91
+ ## Global Design Tokens
92
+
93
+ All tokens are defined in `src/lib/theme.css`. See the full reference below.
94
+
95
+ ### Accent Colors
96
+
97
+ | Token | Light Mode | Dark Mode | Description |
98
+ |-------|------------|-----------|-------------|
99
+ | `--stuic-accent` | `sky-600` | `sky-400` | Primary accent for interactive elements |
100
+ | `--stuic-accent-hover` | `sky-700` | `sky-300` | Accent hover state |
101
+ | `--stuic-accent-active` | `sky-800` | `sky-200` | Accent active/pressed state |
102
+ | `--stuic-accent-destructive` | `red-600` | `red-400` | Destructive/error accent |
103
+ | `--stuic-accent-destructive-hover` | `red-700` | `red-300` | Destructive hover state |
104
+
105
+ ### Surface Colors
106
+
107
+ | Token | Light Mode | Dark Mode | Description |
108
+ |-------|------------|-----------|-------------|
109
+ | `--stuic-surface` | `white` | `neutral-900` | Base page background |
110
+ | `--stuic-surface-elevated` | `white` | `neutral-800` | Cards, modals, popovers |
111
+ | `--stuic-surface-sunken` | `neutral-100` | `neutral-700` | Input backgrounds, wells |
112
+ | `--stuic-surface-overlay` | `neutral-800` | `neutral-950` | Backdrops, tooltips |
113
+ | `--stuic-surface-interactive` | `neutral-200` | `neutral-600` | Buttons, list items |
114
+ | `--stuic-surface-interactive-hover` | `neutral-500` | `neutral-200` | Interactive hover |
115
+ | `--stuic-surface-interactive-active` | `neutral-600` | `neutral-100` | Interactive active |
116
+
117
+ ### Text Colors
118
+
119
+ | Token | Light Mode | Dark Mode | Description |
120
+ |-------|------------|-----------|-------------|
121
+ | `--stuic-text` | `black` | `neutral-100` | Primary text |
122
+ | `--stuic-text-muted` | `neutral-600` | `neutral-400` | Secondary/muted text |
123
+ | `--stuic-text-inverse` | `white` | `neutral-900` | Text on dark backgrounds |
124
+ | `--stuic-text-placeholder` | `neutral-400` | `neutral-500` | Placeholder text |
125
+ | `--stuic-text-on-accent` | `white` | `neutral-950` | Text on accent backgrounds |
126
+ | `--stuic-text-destructive` | `red-600` | `red-400` | Error/destructive text |
127
+
128
+ ### Border Colors
129
+
130
+ | Token | Light Mode | Dark Mode | Description |
131
+ |-------|------------|-----------|-------------|
132
+ | `--stuic-border` | `neutral-300` | `neutral-600` | Default border |
133
+ | `--stuic-border-strong` | `neutral-400` | `neutral-500` | Emphasized border |
134
+ | `--stuic-border-subtle` | `neutral-200` | `neutral-700` | Subtle/light border |
135
+ | `--stuic-border-focus` | `sky-500` | `sky-400` | Focus ring border |
136
+ | `--stuic-border-error` | `red-500` | `red-400` | Error state border |
137
+
138
+ ### Other Tokens
139
+
140
+ | Token | Default | Description |
141
+ |-------|---------|-------------|
142
+ | `--stuic-ring` | `sky-500` / `sky-400` | Focus ring color |
143
+ | `--stuic-ring-offset` | `2px` | Focus ring offset |
144
+ | `--stuic-ring-width` | `2px` | Focus ring width |
145
+ | `--stuic-radius-sm` | `--radius-sm` | Small border radius |
146
+ | `--stuic-radius` | `--radius-md` | Default border radius |
147
+ | `--stuic-radius-lg` | `--radius-lg` | Large border radius |
148
+ | `--stuic-radius-full` | `9999px` | Fully rounded |
149
+ | `--stuic-transition-fast` | `100ms` | Fast transitions |
150
+ | `--stuic-transition-normal` | `150ms` | Normal transitions |
151
+ | `--stuic-transition-slow` | `300ms` | Slow transitions |
152
+
153
+ ## Component Tokens
154
+
155
+ Each component defines its own tokens that reference global tokens as defaults:
156
+
157
+ | Component | Token Prefix | Key Tokens |
158
+ |-----------|--------------|------------|
159
+ | Button | `--stuic-button-*` | `bg`, `text`, `border`, `border-focus` |
160
+ | Switch | `--stuic-switch-*` | `accent` |
161
+ | Input | `--stuic-input-*` | `accent`, `accent-error` |
162
+ | Progress | `--stuic-progress-*` | `bg`, `accent` |
163
+ | ListItemButton | `--stuic-list-item-button-*` | `bg`, `text`, `border`, `bg-hover`, `text-hover`, etc. |
164
+ | ButtonGroupRadio | `--stuic-button-group-*` | `bg`, `text`, `border`, `accent`, `bg-active`, `text-active` |
165
+ | TabbedMenu | `--stuic-tabbed-menu-*` | `tab-bg`, `tab-text`, `tab-bg-active`, `tab-text-active`, `border` |
166
+ | DismissibleMessage | `--stuic-dismissible-message-*` | `bg`, `text`, `border` |
167
+ | Notifications | `--stuic-notification-*` | `bg`, `text`, `border` |
168
+ | Tooltip | `--stuic-tooltip-*` | `bg`, `text` |
169
+ | Popover | `--stuic-popover-*` | `bg`, `text`, `border` |
170
+ | Skeleton | `--stuic-skeleton-*` | `bg`, `bg-highlight`, `duration` |
171
+
172
+ ## CSS Variable Naming Convention
173
+
174
+ **STRICT REQUIREMENT**: All CSS variables follow this pattern:
175
+
176
+ ```
177
+ --stuic-{component}-{element?}-{property}-{state?}
178
+ ```
179
+
180
+ - **Full component names** (no abbreviations): `list-item-button` not `lib`
181
+ - **State at end**: `--stuic-button-bg-hover` not `--stuic-button-hover-bg`
182
+ - **No `-dark` suffix**: Dark mode defined in `.dark {}` selector
183
+ - **Properties**: `bg`, `text`, `border`, `ring`, `shadow`, `accent`
184
+ - **States**: `hover`, `active`, `focus`, `disabled`, `error`
185
+
186
+ ### Examples
187
+
188
+ ```css
189
+ /* Correct */
190
+ --stuic-button-bg
191
+ --stuic-button-bg-hover
192
+ --stuic-list-item-button-text-active
193
+ --stuic-input-accent-error
194
+
195
+ /* Incorrect */
196
+ --stuic-btn-bg /* abbreviated component name */
197
+ --stuic-button-hover-bg /* state not at end */
198
+ --stuic-button-bg-dark /* -dark suffix */
199
+ --color-lib-hover-bg /* old naming convention */
200
+ ```
201
+
202
+ ## Customization Approaches
203
+
204
+ ### 1. CSS Variables (Recommended)
205
+
206
+ Set variables in your CSS for theming:
207
+
208
+ ```css
209
+ :root {
210
+ --stuic-accent: #6366f1;
211
+ }
212
+ ```
213
+
214
+ ### 2. Class Props
215
+
216
+ Pass Tailwind classes directly to components:
217
+
218
+ ```svelte
219
+ <Button class="bg-linear-to-r from-purple-500 to-pink-500">
220
+ Gradient Button
221
+ </Button>
222
+ ```
223
+
224
+ ### 3. Unstyled Mode
225
+
226
+ Use `unstyled` prop to remove all default styling:
227
+
228
+ ```svelte
229
+ <Button unstyled class="my-custom-button-class">
230
+ Fully Custom
231
+ </Button>
232
+ ```
233
+
234
+ ## Components
235
+
236
+ See `src/lib/README.md` for the full component list and API documentation.
237
+
238
+ ### Layout & Overlays
239
+ - AppShell, Backdrop, Modal, ModalDialog, Drawer
240
+
241
+ ### Forms & Inputs
242
+ - FieldInput, FieldTextarea, FieldSelect, FieldCheckbox, FieldRadios, FieldFile, FieldAssets, FieldOptions, FieldKeyValues, FieldSwitch, Fieldset
243
+
244
+ ### Buttons & Controls
245
+ - Button, ButtonGroupRadio, Switch, ListItemButton, X
246
+
247
+ ### Feedback & Notifications
248
+ - Notifications, AlertConfirmPrompt, DismissibleMessage, Progress, Spinner, Skeleton
249
+
250
+ ### Navigation & Menus
251
+ - CommandMenu, DropdownMenu, TabbedMenu, TypeaheadInput, KbdShortcut
252
+
253
+ ### Utilities
254
+ - ColorScheme, Thc, SlidingPanels, HoverExpandableWidth, AnimatedElipsis
255
+
256
+ ## Actions
257
+
258
+ ```svelte
259
+ <input use:autogrow use:validate={{ required: true }} />
260
+ <button use:tooltip aria-label="Tooltip text">Hover me</button>
261
+ <div use:popover={{ content: 'Popover content' }}>Anchor</div>
262
+ ```
263
+
264
+ - `autogrow` - Auto-expand textarea height
265
+ - `validate` - Form validation with custom validators
266
+ - `focusTrap` - Trap focus within element
267
+ - `tooltip` - Tooltip from aria-label
268
+ - `popover` - Anchored popover
269
+ - `fileDropzone` - Drag-and-drop file upload
270
+ - `highlightDragover` - Visual feedback for drag operations
271
+
272
+ ## TypeScript
273
+
274
+ All components export their Props types:
275
+
276
+ ```ts
277
+ import type { ButtonProps, ModalProps, ListItemButtonProps } from "@marianmeres/stuic";
278
+ ```
279
+
280
+ ## Requirements
281
+
282
+ - Svelte 5 (runes mode)
283
+ - Tailwind CSS v4
284
+ - Modern browser with CSS custom properties support
285
+
286
+ ## Breaking Changes in v2
287
+
288
+ - All CSS variables renamed from `--color-*` to `--stuic-*` prefix
289
+ - ListItemButton variables renamed from `--color-lib-*` to `--stuic-list-item-button-*`
290
+ - State naming changed from `--*-hover-bg` to `--*-bg-hover` (state at end)
291
+ - Removed `-dark` suffix from variables (use `.dark {}` selector instead)
292
+ - Legacy variable names preserved as aliases for backwards compatibility
293
+
294
+ ## License
295
+
296
+ MIT
package/dist/README.md CHANGED
@@ -53,6 +53,7 @@ npm install @marianmeres/stuic
53
53
  - **Button** - Styled button with variants (primary, secondary, ghost)
54
54
  - **ButtonGroupRadio** - Radio-style button group
55
55
  - **Switch** - Toggle switch component
56
+ - **ListItemButton** - Versatile button for list contexts (dropdowns, menus)
56
57
  - **X** - Close/dismiss button icon
57
58
 
58
59
  ### Feedback & Notifications
@@ -62,10 +63,13 @@ npm install @marianmeres/stuic
62
63
  - **DismissibleMessage** - Closable message banner
63
64
  - **Progress** - Progress bar indicator
64
65
  - **Spinner** - Loading spinner animation
66
+ - **Skeleton** - Loading placeholder with shimmer animation
65
67
 
66
- ### Navigation & Interaction
68
+ ### Navigation & Menus
67
69
 
68
70
  - **CommandMenu** - Keyboard-driven command palette
71
+ - **DropdownMenu** - Anchored dropdown menu with keyboard navigation
72
+ - **TabbedMenu** - Tab-based navigation component
69
73
  - **TypeaheadInput** - Autocomplete text input
70
74
  - **KbdShortcut** - Keyboard shortcut display
71
75
 
@@ -76,17 +80,22 @@ npm install @marianmeres/stuic
76
80
  - **SlidingPanels** - Animated panel transitions
77
81
  - **HoverExpandableWidth** - Expand content on hover
78
82
  - **AnimatedElipsis** - Animated loading dots
83
+ - **Collapsible** - Expandable/collapsible content sections
84
+ - **AssetsPreview** - Preview uploaded files/images
85
+ - **Circle** - Circular container/badge component
79
86
 
80
87
  ## Actions (use:action)
81
88
 
82
89
  ```svelte
83
90
  <input use:autogrow use:validate={{ required: true }} />
91
+ <button use:tooltip aria-label="Tooltip text">Hover me</button>
84
92
  ```
85
93
 
86
94
  - **autogrow** - Auto-expand textarea height
87
95
  - **validate** - Form validation with custom validators
88
96
  - **focusTrap** - Trap focus within element
89
- - **tooltip** - Tooltip from aria-label
97
+ - **tooltip** - Tooltip from aria-label (CSS anchor positioning)
98
+ - **popover** - Anchored popover (CSS anchor positioning)
90
99
  - **fileDropzone** - Drag-and-drop file upload
91
100
  - **highlightDragover** - Visual feedback for drag operations
92
101
 
@@ -104,30 +113,44 @@ import { debounce, throttle, twMerge, localStorageState } from "@marianmeres/stu
104
113
  - **getId** - Generate unique IDs
105
114
  - **EventEmitter** - Typed event emitter
106
115
 
107
- ## Theming
108
-
109
- Components use CSS custom properties for theming. Override in your CSS:
110
-
111
- ```css
112
- :root {
113
- --color-button-bg: theme("colors.blue.500");
114
- --color-button-text: white;
115
- --color-input-accent: theme("colors.blue.500");
116
- /* ... */
117
- }
118
- ```
119
-
120
- See `src/lib/theme.css` for all available custom properties.
121
-
122
116
  ## TypeScript
123
117
 
124
118
  All components export their Props types:
125
119
 
126
120
  ```ts
127
- import type { ButtonProps, ModalProps } from "@marianmeres/stuic";
121
+ import type { ButtonProps, ModalProps, ListItemButtonProps } from "@marianmeres/stuic";
128
122
 
129
123
  const buttonConfig: Partial<ButtonProps> = {
130
124
  variant: "primary",
131
125
  size: "lg",
132
126
  };
133
127
  ```
128
+
129
+ ## Component Token Reference
130
+
131
+ Each component with customizable styling defines CSS custom properties:
132
+
133
+ | Component | Prefix | Key Properties |
134
+ |-----------|--------|----------------|
135
+ | Button | `--stuic-button-*` | `bg`, `text`, `border`, `border-focus` |
136
+ | Switch | `--stuic-switch-*` | `accent` |
137
+ | Input | `--stuic-input-*` | `accent`, `accent-error` |
138
+ | Progress | `--stuic-progress-*` | `bg`, `accent` |
139
+ | Skeleton | `--stuic-skeleton-*` | `bg`, `bg-highlight`, `duration` |
140
+ | ListItemButton | `--stuic-list-item-button-*` | `bg`, `text`, `border`, plus `-hover`, `-active`, `-focus` states |
141
+ | ButtonGroupRadio | `--stuic-button-group-*` | `bg`, `text`, `border`, `accent`, `bg-active`, `text-active` |
142
+ | TabbedMenu | `--stuic-tabbed-menu-*` | `tab-bg`, `tab-text`, `tab-bg-active`, `tab-text-active`, `border` |
143
+ | DismissibleMessage | `--stuic-dismissible-message-*` | `bg`, `text`, `border` |
144
+ | Notifications | `--stuic-notification-*` | `bg`, `text`, `border` |
145
+ | Tooltip | `--stuic-tooltip-*` | `bg`, `text` |
146
+ | Popover | `--stuic-popover-*` | `bg`, `text`, `border` |
147
+
148
+ ### CSS Variable Naming Convention
149
+
150
+ **Pattern:** `--stuic-{component}-{element?}-{property}-{state?}`
151
+
152
+ - Full component names (no abbreviations)
153
+ - State at end: `--stuic-button-bg-hover`
154
+ - No `-dark` suffix (use `.dark {}` selector)
155
+
156
+ See `AGENTS.md` for complete development guidelines.
@@ -8,4 +8,5 @@ export * from "./popover/popover.svelte.js";
8
8
  export * from "./resizable-width.svelte.js";
9
9
  export * from "./tooltip/tooltip.svelte.js";
10
10
  export * from "./trim.svelte.js";
11
+ export * from "./typeahead.svelte.js";
11
12
  export * from "./validate.svelte.js";
@@ -8,4 +8,5 @@ export * from "./popover/popover.svelte.js";
8
8
  export * from "./resizable-width.svelte.js";
9
9
  export * from "./tooltip/tooltip.svelte.js";
10
10
  export * from "./trim.svelte.js";
11
+ export * from "./typeahead.svelte.js";
11
12
  export * from "./validate.svelte.js";
@@ -137,6 +137,25 @@ if (isPopoverSupported()) {
137
137
  }
138
138
  ```
139
139
 
140
+ ## CSS Variables
141
+
142
+ | Variable | Default | Description |
143
+ |----------|---------|-------------|
144
+ | `--stuic-popover-bg` | `--stuic-surface-elevated` | Popover background |
145
+ | `--stuic-popover-text` | `--stuic-text` | Popover text color |
146
+ | `--stuic-popover-border` | `--stuic-border-subtle` | Popover border color |
147
+
148
+ ### Example Override
149
+
150
+ ```css
151
+ :root {
152
+ --stuic-popover-bg: var(--color-slate-50);
153
+ --stuic-popover-border: var(--color-slate-300);
154
+ }
155
+ ```
156
+
157
+ **Note:** Popover CSS variables may not work with inline style props because popovers are created outside the anchor's DOM tree. Set them in your global CSS.
158
+
140
159
  ## Notes
141
160
 
142
161
  - Uses CSS Anchor Positioning API when available
@@ -1,12 +1,9 @@
1
- /* prettier-ignore */
2
- @theme inline {
3
- /* style props will not work as with regular components, because popovers are created outside of the anchor dom tree */
4
- --color-popover-bg: var(--color-popover-bg, var(--color-white));
5
- --color-popover-bg-dark: var(--color-popover-bg-dark, var(--color-neutral-800));
6
- --color-popover-text: var(--color-popover-text, var(--color-neutral-900));
7
- --color-popover-text-dark: var(--color-popover-text-dark, var(--color-neutral-100));
8
- --color-popover-border: var(--color-popover-border, var(--color-neutral-200));
9
- --color-popover-border-dark: var(--color-popover-border-dark, var(--color-neutral-700));
1
+ /* Popover component tokens */
2
+ /* Note: style props will not work as with regular components, because popovers are created outside of the anchor DOM tree */
3
+ :root {
4
+ --stuic-popover-bg: var(--stuic-color-surface);
5
+ --stuic-popover-text: var(--stuic-color-foreground);
6
+ --stuic-popover-border: var(--stuic-color-border);
10
7
  }
11
8
 
12
9
  /* Base popover styles */
@@ -107,9 +107,9 @@ const POSITION_MAP = {
107
107
  right: "right",
108
108
  };
109
109
  const _classPopover = `
110
- bg-popover-bg dark:bg-popover-bg-dark text-popover-text dark:text-popover-text-dark
110
+ bg-(--stuic-popover-bg) text-(--stuic-popover-text)
111
111
  shadow-lg rounded-md
112
- border border-popover-border dark:border-popover-border-dark
112
+ border border-(--stuic-popover-border)
113
113
  z-50
114
114
  `;
115
115
  const _classBackdrop = `
@@ -127,6 +127,24 @@ if (isTooltipSupported()) {
127
127
  - ARIA attributes are automatically managed (`aria-describedby`, `aria-expanded`)
128
128
  - Maximum width is 16rem (256px) by default
129
129
 
130
+ ## CSS Variables
131
+
132
+ | Variable | Default | Description |
133
+ |----------|---------|-------------|
134
+ | `--stuic-tooltip-bg` | `--stuic-surface-overlay` | Tooltip background |
135
+ | `--stuic-tooltip-text` | `--stuic-text-inverse` | Tooltip text color |
136
+
137
+ ### Example Override
138
+
139
+ ```css
140
+ :root {
141
+ --stuic-tooltip-bg: var(--color-indigo-900);
142
+ --stuic-tooltip-text: var(--color-indigo-100);
143
+ }
144
+ ```
145
+
146
+ **Note:** Tooltip CSS variables may not work with inline style props because tooltips are created outside the anchor's DOM tree. Set them in your global CSS.
147
+
130
148
  ## Browser Support
131
149
 
132
150
  Check [Can I Use - CSS Anchor Positioning](https://caniuse.com/css-anchor-positioning) for current browser support. As of 2025, supported in Chrome 125+ and Edge 125+.
@@ -1,11 +1,8 @@
1
- /* prettier-ignore */
2
- @theme inline {
3
- /* style props will not work as with regular components, because tooltips are created outside of the anchor dom tree */
4
- --color-tooltip-bg: var(--color-tooltip-bg, var(--color-neutral-800));
5
- --color-tooltip-bg-dark: var(--color-tooltip-bg-dark, var(--color-neutral-300));
6
- --color-tooltip-text: var(--color-tooltip-text, var(--color-white));
7
- --color-tooltip-text-dark: var(--color-tooltip-text-dark, var(--color-black));
8
-
1
+ /* Tooltip component tokens */
2
+ /* Note: style props will not work as with regular components, because tooltips are created outside of the anchor DOM tree */
3
+ :root {
4
+ --stuic-tooltip-bg: var(--color-black);
5
+ --stuic-tooltip-text: var(--color-white);
9
6
  }
10
7
 
11
8
  .stuic-tooltip {
@@ -28,7 +28,7 @@ export function isTooltipSupported() {
28
28
  CSS.supports("position-try-fallbacks", "top"));
29
29
  }
30
30
  const _classTooltip = `
31
- bg-tooltip-bg dark:bg-tooltip-bg-dark text-tooltip-text dark:text-tooltip-text-dark
31
+ bg-(--stuic-tooltip-bg) text-(--stuic-tooltip-text)
32
32
  text-sm tracking-tight rounded my-1
33
33
  px-2.5 py-1.5
34
34
  max-w-64
@@ -0,0 +1,53 @@
1
+ import type { Item } from "@marianmeres/item-collection";
2
+ /**
3
+ * Configuration options for the typeahead action.
4
+ */
5
+ export interface TypeaheadOptions<T extends Item = Item> {
6
+ /** Whether the typeahead functionality is enabled (default: true) */
7
+ enabled?: boolean;
8
+ /** Async function to fetch options based on the current query (required when enabled) */
9
+ getOptions?: (query: string, current: T[]) => Promise<T[]>;
10
+ /** Custom function to render the label for an item */
11
+ renderOptionLabel?: (item: T) => string;
12
+ /** Property name to use as item ID (default: "id") */
13
+ itemIdPropName?: string;
14
+ /** Debounce delay in milliseconds (default: 150) */
15
+ debounceMs?: number;
16
+ /** Callback when value is submitted (Enter, Tab, blur) */
17
+ onSubmit?: (value: string) => void;
18
+ /** Callback when Backspace is pressed at cursor position 0 */
19
+ onDeleteRequest?: () => void;
20
+ /** Callback when fetching state changes */
21
+ onFetchingChange?: (isFetching: boolean) => void;
22
+ /** Disable showing all options when arrow keys pressed on empty input */
23
+ noListAllOnEmptyQ?: boolean;
24
+ /** Hint text appended to the visible suggestion (default: " [tab]") */
25
+ appendHint?: string;
26
+ /** CSS class for the ghost input element */
27
+ classGhost?: string;
28
+ /** Callback that provides a reset function to clear ghost text programmatically */
29
+ onResetGhost?: (resetFn: () => void) => void;
30
+ }
31
+ /**
32
+ * A Svelte action that adds typeahead/autocomplete functionality to an input element.
33
+ *
34
+ * Creates a "ghost input" behind the main input to show suggestions. Supports keyboard
35
+ * navigation with ArrowUp/Down, accepts suggestions with Tab/Enter/ArrowRight, and
36
+ * handles accent-insensitive matching.
37
+ *
38
+ * @param el - The input element to add typeahead to
39
+ * @param fn - Function returning configuration options
40
+ *
41
+ * @example
42
+ * ```svelte
43
+ * <input
44
+ * bind:value
45
+ * use:typeahead={() => ({
46
+ * getOptions: async (q) => fetchSuggestions(q),
47
+ * renderOptionLabel: (item) => item.name,
48
+ * onSubmit: (v) => console.log('Selected:', v),
49
+ * })}
50
+ * />
51
+ * ```
52
+ */
53
+ export declare function typeahead<T extends Item = Item>(el: HTMLInputElement, fn?: () => TypeaheadOptions<T>): void;