@spaethtech/svelte-ui 0.1.10 → 0.3.1-dev.10.ff03a8d

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 (218) hide show
  1. package/.claude/skills/svelte-ui/SKILL.md +118 -0
  2. package/.claude/skills/themes/SKILL.md +303 -0
  3. package/CLAUDE.md +248 -0
  4. package/README.md +180 -42
  5. package/dist/components/Alert.svelte +119 -0
  6. package/dist/components/Alert.svelte.d.ts +29 -0
  7. package/dist/components/Badge/Badge.svelte +142 -69
  8. package/dist/components/Badge/Badge.svelte.d.ts +26 -6
  9. package/dist/components/Badge/index.d.ts +1 -1
  10. package/dist/components/Badge/index.js +1 -1
  11. package/dist/components/Banner.svelte +133 -0
  12. package/dist/components/Banner.svelte.d.ts +31 -0
  13. package/dist/components/Button.svelte +240 -0
  14. package/dist/components/Button.svelte.d.ts +33 -0
  15. package/dist/components/ButtonDropdown.svelte +145 -0
  16. package/dist/components/ButtonDropdown.svelte.d.ts +31 -0
  17. package/dist/components/Calendar.svelte +259 -0
  18. package/dist/components/Calendar.svelte.d.ts +27 -0
  19. package/dist/components/Card.svelte +79 -0
  20. package/dist/components/Card.svelte.d.ts +17 -0
  21. package/dist/components/CardBody.svelte +41 -0
  22. package/dist/components/CardBody.svelte.d.ts +17 -0
  23. package/dist/components/CardFooter.svelte +51 -0
  24. package/dist/components/CardFooter.svelte.d.ts +16 -0
  25. package/dist/components/CardHeader.svelte +51 -0
  26. package/dist/components/CardHeader.svelte.d.ts +16 -0
  27. package/dist/components/Checkbox.svelte +131 -0
  28. package/dist/components/Checkbox.svelte.d.ts +16 -0
  29. package/dist/components/ConfirmDialog.svelte +103 -0
  30. package/dist/components/ConfirmDialog.svelte.d.ts +33 -0
  31. package/dist/components/DataTable.svelte +518 -0
  32. package/dist/components/DataTable.svelte.d.ts +74 -0
  33. package/dist/components/DatePicker.svelte +312 -0
  34. package/dist/components/DatePicker.svelte.d.ts +32 -0
  35. package/dist/components/DateTimeInput.svelte +93 -0
  36. package/dist/components/DateTimeInput.svelte.d.ts +20 -0
  37. package/dist/components/Dialog.svelte +151 -0
  38. package/dist/components/Dialog.svelte.d.ts +30 -0
  39. package/dist/components/{EmailInput/EmailInput.svelte → EmailInput.svelte} +17 -8
  40. package/dist/components/EmailInput.svelte.d.ts +21 -0
  41. package/dist/components/Input.svelte +369 -0
  42. package/dist/components/Input.svelte.d.ts +35 -0
  43. package/dist/components/{List/List.svelte → List.svelte} +194 -133
  44. package/dist/components/{List/List.svelte.d.ts → List.svelte.d.ts} +9 -1
  45. package/dist/components/Menu.svelte +117 -0
  46. package/dist/components/Menu.svelte.d.ts +20 -0
  47. package/dist/components/NotesEditor.svelte +127 -0
  48. package/dist/components/NotesEditor.svelte.d.ts +17 -0
  49. package/dist/components/{NumberInput/NumberInput.svelte → NumberInput.svelte} +146 -105
  50. package/dist/components/{NumberInput/NumberInput.svelte.d.ts → NumberInput.svelte.d.ts} +11 -4
  51. package/dist/components/PasswordInput.svelte +52 -0
  52. package/dist/components/PasswordInput.svelte.d.ts +20 -0
  53. package/dist/components/Popup.svelte +140 -0
  54. package/dist/components/Popup.svelte.d.ts +31 -0
  55. package/dist/components/Query.svelte +284 -0
  56. package/dist/components/Query.svelte.d.ts +15 -0
  57. package/dist/components/{Rating/Rating.svelte → Rating.svelte} +19 -10
  58. package/dist/components/Rating.svelte.d.ts +13 -0
  59. package/dist/components/{SearchInput/SearchInput.svelte → SearchInput.svelte} +19 -8
  60. package/dist/components/{SearchInput/SearchInput.svelte.d.ts → SearchInput.svelte.d.ts} +9 -2
  61. package/dist/components/{Select/Select.svelte → Select.svelte} +48 -76
  62. package/dist/components/{Select/Select.svelte.d.ts → Select.svelte.d.ts} +11 -1
  63. package/dist/components/SideBarMenu/SideBarMenu.svelte +724 -0
  64. package/dist/components/SideBarMenu/SideBarMenu.svelte.d.ts +109 -0
  65. package/dist/components/SideBarMenu/index.d.ts +2 -0
  66. package/dist/components/SideBarMenu/index.js +1 -0
  67. package/dist/components/TabStrip/TabStrip.svelte +384 -0
  68. package/dist/components/TabStrip/TabStrip.svelte.d.ts +50 -0
  69. package/dist/components/TabStrip/index.d.ts +3 -0
  70. package/dist/components/TabStrip/index.js +2 -0
  71. package/dist/components/{TextArea/TextArea.svelte → TextArea.svelte} +143 -112
  72. package/dist/components/TextArea.svelte.d.ts +38 -0
  73. package/dist/components/ThemeSelector.svelte +81 -0
  74. package/dist/components/ThemeSelector.svelte.d.ts +10 -0
  75. package/dist/components/TimePicker.svelte +148 -0
  76. package/dist/components/TimePicker.svelte.d.ts +28 -0
  77. package/dist/components/TimeRangeInput.svelte +203 -0
  78. package/dist/components/TimeRangeInput.svelte.d.ts +29 -0
  79. package/dist/components/TimeSpinner.svelte +202 -0
  80. package/dist/components/TimeSpinner.svelte.d.ts +26 -0
  81. package/dist/components/Toast/Toaster.svelte +51 -0
  82. package/dist/components/Toast/Toaster.svelte.d.ts +12 -0
  83. package/dist/components/Toast/toast.svelte.d.ts +29 -0
  84. package/dist/components/Toast/toast.svelte.js +27 -0
  85. package/dist/components/Toggle.svelte +93 -0
  86. package/dist/components/Toggle.svelte.d.ts +15 -0
  87. package/dist/data/dataset.d.ts +42 -0
  88. package/dist/data/dataset.js +3 -0
  89. package/dist/data/index.d.ts +3 -0
  90. package/dist/data/index.js +3 -0
  91. package/dist/data/query/ast.d.ts +62 -0
  92. package/dist/data/query/ast.js +12 -0
  93. package/dist/data/query/index.d.ts +3 -0
  94. package/dist/data/query/index.js +3 -0
  95. package/dist/data/query/lexer.d.ts +33 -0
  96. package/dist/data/query/lexer.js +225 -0
  97. package/dist/data/query/parser.d.ts +11 -0
  98. package/dist/data/query/parser.js +252 -0
  99. package/dist/data/table/grid.svelte.d.ts +57 -0
  100. package/dist/data/table/grid.svelte.js +139 -0
  101. package/dist/data/table/index.d.ts +2 -0
  102. package/dist/data/table/index.js +2 -0
  103. package/dist/data/table/types.d.ts +79 -0
  104. package/dist/index.d.ts +49 -22
  105. package/dist/index.js +46 -21
  106. package/dist/positioning/anchored.d.ts +61 -0
  107. package/dist/positioning/anchored.js +122 -0
  108. package/dist/positioning/tooltip.d.ts +41 -0
  109. package/dist/positioning/tooltip.js +147 -0
  110. package/dist/theme.css +205 -0
  111. package/dist/types/breakpoints.d.ts +24 -0
  112. package/dist/types/breakpoints.js +13 -0
  113. package/dist/types/responsive.d.ts +32 -0
  114. package/dist/types/responsive.js +54 -0
  115. package/dist/types/sizes.d.ts +10 -3
  116. package/dist/types/time.d.ts +19 -0
  117. package/dist/types/time.js +10 -0
  118. package/dist/types/variants.d.ts +8 -1
  119. package/dist/types/variants.js +16 -1
  120. package/docs/components.md +255 -0
  121. package/docs/examples.md +323 -0
  122. package/docs/paradigm.md +240 -0
  123. package/docs/themes.md +170 -0
  124. package/docs/usage.md +450 -0
  125. package/package.json +97 -63
  126. package/dist/components/Button/Button.svelte +0 -172
  127. package/dist/components/Button/Button.svelte.d.ts +0 -32
  128. package/dist/components/Button/index.d.ts +0 -1
  129. package/dist/components/Button/index.js +0 -1
  130. package/dist/components/Dialog/Dialog.svelte +0 -101
  131. package/dist/components/Dialog/Dialog.svelte.d.ts +0 -18
  132. package/dist/components/Dialog/index.d.ts +0 -1
  133. package/dist/components/Dialog/index.js +0 -1
  134. package/dist/components/ElementManager/ElementManager.svelte +0 -397
  135. package/dist/components/ElementManager/ElementManager.svelte.d.ts +0 -43
  136. package/dist/components/ElementManager/index.d.ts +0 -1
  137. package/dist/components/ElementManager/index.js +0 -1
  138. package/dist/components/EmailInput/EmailInput.svelte.d.ts +0 -14
  139. package/dist/components/EmailInput/index.d.ts +0 -1
  140. package/dist/components/EmailInput/index.js +0 -1
  141. package/dist/components/Icon/Icon.svelte +0 -74
  142. package/dist/components/Icon/Icon.svelte.d.ts +0 -13
  143. package/dist/components/Icon/index.d.ts +0 -1
  144. package/dist/components/Icon/index.js +0 -1
  145. package/dist/components/Input/Input.svelte +0 -268
  146. package/dist/components/Input/Input.svelte.d.ts +0 -18
  147. package/dist/components/Input/index.d.ts +0 -1
  148. package/dist/components/Input/index.js +0 -1
  149. package/dist/components/List/index.d.ts +0 -1
  150. package/dist/components/List/index.js +0 -1
  151. package/dist/components/ListItem/ListItem.svelte +0 -175
  152. package/dist/components/ListItem/ListItem.svelte.d.ts +0 -24
  153. package/dist/components/ListItem/index.d.ts +0 -2
  154. package/dist/components/ListItem/index.js +0 -2
  155. package/dist/components/ListView/ListView.svelte +0 -463
  156. package/dist/components/ListView/ListView.svelte.d.ts +0 -37
  157. package/dist/components/ListView/index.d.ts +0 -2
  158. package/dist/components/ListView/index.js +0 -2
  159. package/dist/components/NodeGraph/BaseNode.d.ts +0 -57
  160. package/dist/components/NodeGraph/BaseNode.js +0 -30
  161. package/dist/components/NodeGraph/Edge.svelte +0 -60
  162. package/dist/components/NodeGraph/Edge.svelte.d.ts +0 -16
  163. package/dist/components/NodeGraph/ExpressionEvaluator.d.ts +0 -82
  164. package/dist/components/NodeGraph/ExpressionEvaluator.js +0 -152
  165. package/dist/components/NodeGraph/Node.svelte +0 -100
  166. package/dist/components/NodeGraph/Node.svelte.d.ts +0 -10
  167. package/dist/components/NodeGraph/NodeGraph.svelte +0 -52
  168. package/dist/components/NodeGraph/NodeGraph.svelte.d.ts +0 -14
  169. package/dist/components/NodeGraph/NodeInstance.svelte.d.ts +0 -80
  170. package/dist/components/NodeGraph/NodeInstance.svelte.js +0 -241
  171. package/dist/components/NodeGraph/NodePort.svelte +0 -75
  172. package/dist/components/NodeGraph/NodePort.svelte.d.ts +0 -11
  173. package/dist/components/NodeGraph/decorators.d.ts +0 -81
  174. package/dist/components/NodeGraph/decorators.js +0 -148
  175. package/dist/components/NodeGraph/index.d.ts +0 -9
  176. package/dist/components/NodeGraph/index.js +0 -9
  177. package/dist/components/NodeGraph/types.d.ts +0 -94
  178. package/dist/components/NodeGraph/types.js +0 -33
  179. package/dist/components/NotesEditor/NotesEditor.svelte +0 -203
  180. package/dist/components/NotesEditor/NotesEditor.svelte.d.ts +0 -9
  181. package/dist/components/NotesEditor/index.d.ts +0 -1
  182. package/dist/components/NotesEditor/index.js +0 -1
  183. package/dist/components/NumberInput/index.d.ts +0 -1
  184. package/dist/components/NumberInput/index.js +0 -1
  185. package/dist/components/PasswordInput/PasswordInput.svelte +0 -41
  186. package/dist/components/PasswordInput/PasswordInput.svelte.d.ts +0 -13
  187. package/dist/components/PasswordInput/index.d.ts +0 -1
  188. package/dist/components/PasswordInput/index.js +0 -1
  189. package/dist/components/Popup/index.d.ts +0 -1
  190. package/dist/components/Popup/index.js +0 -1
  191. package/dist/components/Rating/Rating.svelte.d.ts +0 -7
  192. package/dist/components/Rating/index.d.ts +0 -1
  193. package/dist/components/Rating/index.js +0 -1
  194. package/dist/components/ScrollView/ScrollView.svelte +0 -285
  195. package/dist/components/ScrollView/ScrollView.svelte.d.ts +0 -19
  196. package/dist/components/ScrollView/index.d.ts +0 -1
  197. package/dist/components/ScrollView/index.js +0 -1
  198. package/dist/components/SearchInput/index.d.ts +0 -1
  199. package/dist/components/SearchInput/index.js +0 -1
  200. package/dist/components/Select/index.d.ts +0 -1
  201. package/dist/components/Select/index.js +0 -1
  202. package/dist/components/TextArea/TextArea.svelte.d.ts +0 -19
  203. package/dist/components/TextArea/index.d.ts +0 -1
  204. package/dist/components/TextArea/index.js +0 -1
  205. package/dist/components/ThemeSelector/ThemeSelector.svelte +0 -64
  206. package/dist/components/ThemeSelector/ThemeSelector.svelte.d.ts +0 -3
  207. package/dist/components/ThemeSelector/index.d.ts +0 -1
  208. package/dist/components/ThemeSelector/index.js +0 -1
  209. package/dist/components/TooltipHandler/TooltipHandler.svelte +0 -593
  210. package/dist/components/TooltipHandler/TooltipHandler.svelte.d.ts +0 -10
  211. package/dist/components/TooltipHandler/index.d.ts +0 -1
  212. package/dist/components/TooltipHandler/index.js +0 -1
  213. package/dist/styles/sizes.d.ts +0 -78
  214. package/dist/styles/sizes.js +0 -120
  215. package/dist/styles/variants.d.ts +0 -106
  216. package/dist/styles/variants.js +0 -194
  217. package/dist/types/ManagerTypes.d.ts +0 -42
  218. /package/dist/{types/ManagerTypes.js → data/table/types.js} +0 -0
package/docs/themes.md ADDED
@@ -0,0 +1,170 @@
1
+ # CSS Variables Reference
2
+
3
+ This document describes the CSS variables in the svelte-ui theme. The source of truth is
4
+ `src/lib/theme.css` (shipped as `@spaethtech/svelte-ui/theme.css`); this doc mirrors it. Every token is
5
+ **`--ui-*`-prefixed** — there are no unprefixed tokens and no per-component tokens.
6
+
7
+ ## Overview
8
+
9
+ The library themes via CSS custom properties. There are **two themes only — light (default) and
10
+ dark**. Dark follows the system preference automatically (`@media (prefers-color-scheme: dark)`);
11
+ force either with the `.theme-light` / `.theme-dark` classes (see `ThemeSelector`).
12
+
13
+ Consumers import the theme right after Tailwind:
14
+
15
+ ```css
16
+ @import "tailwindcss";
17
+ @import "@spaethtech/svelte-ui/theme.css";
18
+ ```
19
+
20
+ ## Palette — `--ui-color-*`
21
+
22
+ ### Core
23
+
24
+ - `--ui-color-background` — main background for pages and containers
25
+ - `--ui-color-text` — primary text color
26
+
27
+ ### Semantic
28
+
29
+ - `--ui-color-primary` — primary brand color (blue)
30
+ - `--ui-color-secondary` — secondary brand color (cyan)
31
+ - `--ui-color-success` — success state (green)
32
+ - `--ui-color-warning` — warning state (amber)
33
+ - `--ui-color-error` — error/danger state (red) — the `danger` variant maps here
34
+ - `--ui-color-info` — informational state (sky blue)
35
+
36
+ ## Interactive-surface tints — `--ui-accent` + hover / surface / active
37
+
38
+ One shared tint language for every hover, section band, and pressed surface. Three steps of the
39
+ **same** mix, from lightest to strongest:
40
+
41
+ - `--ui-color-hover` — **4%** — row / option / ghost-button hover
42
+ - `--ui-color-surface` — **8%** — header / footer / section bands (a notch darker than hover)
43
+ - `--ui-color-active` — **12%** — pressed / held
44
+
45
+ Each is `color-mix(in srgb, var(--ui-accent) N%, transparent)`. The **percentages are
46
+ theme-independent** (identical in light and dark) — only the accent color flips.
47
+
48
+ - `--ui-accent` — the color the tints mix from. **Defaults to `var(--ui-color-text)`**, so out of
49
+ the box these are neutral grey tints. Point it at a semantic color to tint a surface (this is how
50
+ a component `variant` colors its whole surface). Overriding `--ui-accent` requires the `.ui-accent`
51
+ re-mix class — see [Applying a theme](#theme-application) and the themes skill.
52
+
53
+ ## Border & radius — `--ui-border-*`
54
+
55
+ - `--ui-border-radius` — `0.375rem` — corner radius for every surface (Card, Input, DataTable…)
56
+ - `--ui-border-color` — `color-mix(in srgb, var(--ui-color-secondary) 30%, transparent)` — soft
57
+ internal divider (row separators, section splits)
58
+ - `--ui-border-color-strong` — `var(--ui-color-secondary)` — prominent outer edge (Card frame,
59
+ Input, DataTable outer)
60
+ - `--ui-border-color-strong-hover` — `color-mix(in srgb, var(--ui-color-secondary) 80%, black)` —
61
+ darker edge on hover for interactive controls
62
+
63
+ ## Sizing — the `size` axis (`sm` / `md` / `lg`)
64
+
65
+ ### Control heights
66
+
67
+ - `--ui-height-sm` — `1.5rem` / 24px (`sm`)
68
+ - `--ui-height` — `2rem` / 32px (`md`, **default**)
69
+ - `--ui-height-lg` — `2.5rem` / 40px (`lg`)
70
+ - `--ui-height-touch` — `2.75rem` / 44px — explicit touch target (WCAG/Apple min), **not** the `lg` size
71
+
72
+ ### Text
73
+
74
+ - `--ui-text-sm` — `0.75rem` / 12px · `--ui-text` — `0.875rem` / 14px (default) · `--ui-text-lg` — `1rem` / 16px
75
+
76
+ ### Inline icons
77
+
78
+ - `--ui-icon-sm` — `0.875rem` / 14px · `--ui-icon` — `1rem` / 16px (default) · `--ui-icon-lg` — `1.25rem` / 20px
79
+
80
+ > Per-component **padding / gap** is NOT a token — each component maps the `size` prop to Tailwind
81
+ > class maps (`Record<Size, string>`) internally. (The old `--ui-padding*` and `--ui-border` width
82
+ > tokens were removed.)
83
+
84
+ ## Breakpoints (in `@theme`)
85
+
86
+ Narrow-mobile tiers and an ultrawide tier on top of Tailwind's defaults, so `DataTable` column
87
+ placements can target the full range:
88
+ `4xs` 320px · `3xs` 360px · `2xs` 420px · `xs` 480px · `3xl` 1920px.
89
+
90
+ ## Theme values
91
+
92
+ ### Light (default)
93
+
94
+ ```css
95
+ --ui-color-background: #ffffff;
96
+ --ui-color-text: #111827;
97
+ --ui-color-primary: #1d4ed8;
98
+ --ui-color-secondary: #0891b2;
99
+ --ui-color-success: #059669;
100
+ --ui-color-warning: #d97706;
101
+ --ui-color-error: #dc2626;
102
+ --ui-color-info: #0ea5e9;
103
+ ```
104
+
105
+ ### Dark
106
+
107
+ ```css
108
+ --ui-color-background: #111827;
109
+ --ui-color-text: #f9fafb;
110
+ --ui-color-primary: #2563eb;
111
+ --ui-color-secondary: #06b6d4;
112
+ --ui-color-success: #10b981;
113
+ --ui-color-warning: #f59e0b;
114
+ --ui-color-error: #ef4444;
115
+ --ui-color-info: #06b6d4;
116
+ ```
117
+
118
+ The sizing/text/icon tokens are theme-independent. The interactive tints use the same percentages
119
+ in both themes — only `--ui-color-text` (hence `--ui-accent`) flips.
120
+
121
+ ## Usage in components
122
+
123
+ Components reference these via Tailwind's arbitrary-value syntax:
124
+
125
+ ```svelte
126
+ <!-- Text / background -->
127
+ <div class="text-[var(--ui-color-text)] bg-[var(--ui-color-background)]">...</div>
128
+
129
+ <!-- Border (color + radius tokens) -->
130
+ <div
131
+ class="border [border-color:var(--ui-border-color-strong)] [border-radius:var(--ui-border-radius)]"
132
+ >
133
+ ...
134
+ </div>
135
+
136
+ <!-- Hover / section / pressed surfaces — use the shared tints, not ad-hoc color-mix -->
137
+ <div
138
+ class="[background-color:var(--ui-color-surface)] hover:[background-color:var(--ui-color-hover)]"
139
+ >
140
+ ...
141
+ </div>
142
+ ```
143
+
144
+ For muted text or faint dividers, mix the text color: `color-mix(in srgb, var(--ui-color-text) 60%, transparent)`.
145
+
146
+ ## Theme application
147
+
148
+ Precedence:
149
+
150
+ 1. Forced theme via `.theme-light` / `.theme-dark` — set on **`<html>`** by `ThemeSelector` and by
151
+ the pre-hydration script in `app.html`. A switcher **must** target `<html>` (documentElement),
152
+ never `<body>` — putting it on `<body>` leaves `<html>` on the system path and freezes the
153
+ accent-derived tints to the wrong theme.
154
+ 2. System preference via `@media (prefers-color-scheme: dark)`.
155
+ 3. Default light values.
156
+
157
+ `ThemeSelector` manages switching (Auto / Light / Dark) and persists the choice in `localStorage`
158
+ under `svelte-ui-theme`.
159
+
160
+ **Scoped / inverse surfaces:** because the theme classes are ordinary CSS, apply one to any
161
+ container to re-theme just that subtree — e.g. `class="theme-dark"` on a dark header sitting on a
162
+ light page, so the components inside resolve light-on-dark and stay visible. This works because the
163
+ tint tokens are re-defined per theme scope; see the themes skill.
164
+
165
+ ## Building a custom theme
166
+
167
+ This page documents the token _surface_. For the authoring side — swapping palette/sizing, tinting
168
+ by variant (`--ui-accent` + `.ui-accent`), scoping/inverse surfaces, the custom-property freeze
169
+ rule, the self-reference trap, and bridging to another design system (DaisyUI, shadcn, …) — see the
170
+ themes skill: [`.claude/skills/themes/SKILL.md`](../.claude/skills/themes/SKILL.md).
package/docs/usage.md ADDED
@@ -0,0 +1,450 @@
1
+ # Usage Examples
2
+
3
+ Common usage patterns for svelte-ui components. For the full, live gallery, run the demo and
4
+ browse every component at **http://localhost:5173**.
5
+
6
+ ## Installation
7
+
8
+ Published to npm:
9
+
10
+ ```bash
11
+ npm install @spaethtech/svelte-ui
12
+ ```
13
+
14
+ During active co-development you can instead link a local checkout with a `file:` dependency:
15
+
16
+ ```jsonc
17
+ // package.json
18
+ "dependencies": {
19
+ "@spaethtech/svelte-ui": "file:../svelte-ui"
20
+ }
21
+ ```
22
+
23
+ Peer dependencies:
24
+
25
+ ```bash
26
+ npm install svelte@^5 tailwindcss@^4 unplugin-icons@^23 @iconify-json/mdi@^1
27
+ ```
28
+
29
+ ## Setup
30
+
31
+ **1. Vite — add the icon resolver** (`vite.config.ts`):
32
+
33
+ ```ts
34
+ import Icons from "unplugin-icons/vite";
35
+
36
+ export default defineConfig({
37
+ plugins: [/* sveltekit(), tailwindcss(), */ Icons({ compiler: "svelte" })],
38
+ });
39
+ ```
40
+
41
+ **2. CSS — import Tailwind + the theme and scan the dist** (`app.css`, Tailwind v4):
42
+
43
+ ```css
44
+ @import "tailwindcss";
45
+ @import "@spaethtech/svelte-ui/theme.css";
46
+
47
+ /* Generate the utility classes the components use (path relative to this file). */
48
+ @source "../node_modules/@spaethtech/svelte-ui/dist";
49
+ ```
50
+
51
+ ## Basic Import
52
+
53
+ ```svelte
54
+ <script>
55
+ import { Button, Input, Select } from "@spaethtech/svelte-ui";
56
+ </script>
57
+ ```
58
+
59
+ ## Icons
60
+
61
+ There is **no `Icon` component**. Import an MDI icon component from `~icons/mdi/*` and render it
62
+ into a component's `icon` snippet — the library sizes and colors it:
63
+
64
+ ```svelte
65
+ <script>
66
+ import { Button, Input } from "@spaethtech/svelte-ui";
67
+ import IconHome from "~icons/mdi/home";
68
+ import IconSearch from "~icons/mdi/magnify";
69
+ </script>
70
+
71
+ <Button title="Home">{#snippet icon()}<IconHome />{/snippet}</Button>
72
+
73
+ <Input placeholder="Search…">
74
+ {#snippet icon()}<IconSearch />{/snippet}
75
+ </Input>
76
+ ```
77
+
78
+ ## Component Examples
79
+
80
+ ### Button
81
+
82
+ ```svelte
83
+ <script>
84
+ import { Button } from "@spaethtech/svelte-ui";
85
+ import IconContentSave from "~icons/mdi/content-save";
86
+ import IconPencil from "~icons/mdi/pencil";
87
+ import IconDelete from "~icons/mdi/delete";
88
+ </script>
89
+
90
+ <!-- Text button -->
91
+ <Button text="Click me" variant="primary" onclick={() => alert("Clicked!")} />
92
+
93
+ <!-- Button with icon -->
94
+ <Button text="Save" variant="success">
95
+ {#snippet icon()}<IconContentSave />{/snippet}
96
+ </Button>
97
+
98
+ <!-- Icon-only button (title → themed tooltip + aria-label) -->
99
+ <Button title="Edit" variant="plain" size="sm">
100
+ {#snippet icon()}<IconPencil />{/snippet}
101
+ </Button>
102
+
103
+ <!-- Button as link -->
104
+ <Button href="/home" text="Home" variant="ghost" />
105
+
106
+ <!-- Danger -->
107
+ <Button text="Delete" variant="danger">
108
+ {#snippet icon()}<IconDelete />{/snippet}
109
+ </Button>
110
+ ```
111
+
112
+ ### Input
113
+
114
+ ```svelte
115
+ <script>
116
+ import { Input } from "@spaethtech/svelte-ui";
117
+ import IconAccount from "~icons/mdi/account";
118
+
119
+ let username = $state("");
120
+ let validated = $state("");
121
+ </script>
122
+
123
+ <!-- Basic -->
124
+ <Input bind:value={username} placeholder="Username" />
125
+
126
+ <!-- With a leading icon -->
127
+ <Input bind:value={username} placeholder="Enter username" iconPosition="left">
128
+ {#snippet icon()}<IconAccount />{/snippet}
129
+ </Input>
130
+
131
+ <!-- With validation -->
132
+ <Input
133
+ bind:value={validated}
134
+ validate={(v) => (v.length >= 3 ? true : "Minimum 3 characters")}
135
+ placeholder="Validated input"
136
+ />
137
+
138
+ <!-- Clickable trailing icon -->
139
+ <Input bind:value={username} iconClickable onIconClick={() => console.log("clicked")}>
140
+ {#snippet icon()}<IconAccount />{/snippet}
141
+ </Input>
142
+ ```
143
+
144
+ ### Select
145
+
146
+ ```svelte
147
+ <script>
148
+ import { Select } from "@spaethtech/svelte-ui";
149
+
150
+ let selected = $state("");
151
+ const options = [
152
+ { value: "1", label: "Option 1" },
153
+ { value: "2", label: "Option 2" },
154
+ { value: "3", label: "Option 3" },
155
+ ];
156
+ </script>
157
+
158
+ <!-- Static select -->
159
+ <Select bind:value={selected} {options} placeholder="Choose option" />
160
+
161
+ <!-- API-driven select with search -->
162
+ <Select
163
+ bind:value={selected}
164
+ url="/api/items"
165
+ searchParam="q"
166
+ placeholder="Search items..."
167
+ transform={(data) => data.results.map((r) => ({ value: r.id, label: r.name }))}
168
+ />
169
+
170
+ <!-- Custom item rendering -->
171
+ <Select bind:value={selected} {options}>
172
+ {#snippet itemSnippet(option)}
173
+ <div class="flex items-center gap-2">
174
+ <span class="font-bold">{option.value}</span>
175
+ <span>{option.label}</span>
176
+ </div>
177
+ {/snippet}
178
+ </Select>
179
+ ```
180
+
181
+ ### List
182
+
183
+ ```svelte
184
+ <script>
185
+ import { List } from "@spaethtech/svelte-ui";
186
+
187
+ let selected = $state([]);
188
+ const options = [
189
+ { value: "1", label: "Item 1" },
190
+ { value: "2", label: "Item 2" },
191
+ { value: "3", label: "Item 3" },
192
+ ];
193
+ </script>
194
+
195
+ <!-- Single select -->
196
+ <List bind:value={selected} {options} />
197
+
198
+ <!-- Multi-select with checkboxes -->
199
+ <List bind:value={selected} {options} multiSelect showCheckboxes />
200
+ ```
201
+
202
+ ### Checkbox
203
+
204
+ ```svelte
205
+ <script>
206
+ import { Checkbox } from "@spaethtech/svelte-ui";
207
+ let checked = $state(false);
208
+ </script>
209
+
210
+ <Checkbox bind:checked />
211
+ <Checkbox checked indeterminate />
212
+ <Checkbox disabled />
213
+ ```
214
+
215
+ ### ConfirmDialog
216
+
217
+ The common title + message + Confirm/Cancel modal (composed from a `Card` on the `Dialog` shell).
218
+
219
+ ```svelte
220
+ <script>
221
+ import { ConfirmDialog, Button } from "@spaethtech/svelte-ui";
222
+
223
+ let showConfirm = $state(false);
224
+ let showDanger = $state(false);
225
+ </script>
226
+
227
+ <!-- Basic confirmation -->
228
+ <Button text="Show Dialog" onclick={() => (showConfirm = true)} />
229
+ <ConfirmDialog
230
+ bind:isOpen={showConfirm}
231
+ title="Confirm Action"
232
+ message="Are you sure you want to proceed?"
233
+ onConfirm={() => console.log("Confirmed")}
234
+ />
235
+
236
+ <!-- Danger + must-decide (no backdrop/Escape dismiss) -->
237
+ <ConfirmDialog
238
+ bind:isOpen={showDanger}
239
+ title="Delete Item"
240
+ message="This action cannot be undone!"
241
+ variant="danger"
242
+ confirmText="Delete"
243
+ dismissible={false}
244
+ onConfirm={() => console.log("Deleted")}
245
+ />
246
+ ```
247
+
248
+ ### Dialog (shell)
249
+
250
+ A pure modal shell — you supply the content. Use it for anything beyond the confirm pattern; size it
251
+ with `width` / `height` (any CSS value).
252
+
253
+ ```svelte
254
+ <script>
255
+ import { Dialog, Card, CardHeader, CardFooter, Button, Input } from "@spaethtech/svelte-ui";
256
+
257
+ let open = $state(false);
258
+ </script>
259
+
260
+ <Button text="Open" onclick={() => (open = true)} />
261
+
262
+ <Dialog bind:isOpen={open} width="80vw" height="60vh">
263
+ <Card class="w-full h-full flex flex-col">
264
+ <CardHeader><h3 class="text-lg font-medium">Custom modal</h3></CardHeader>
265
+ <div class="flex-1 overflow-auto space-y-2">
266
+ <p>You own the Card — control its separator, variant, sizing, and body.</p>
267
+ <Input placeholder="Enter value" />
268
+ </div>
269
+ <CardFooter separator={false}>
270
+ <Button text="Close" variant="secondary" onclick={() => (open = false)} />
271
+ </CardFooter>
272
+ </Card>
273
+ </Dialog>
274
+ ```
275
+
276
+ ### Badge
277
+
278
+ ```svelte
279
+ <script>
280
+ import { Badge } from "@spaethtech/svelte-ui";
281
+ import IconCheck from "~icons/mdi/check";
282
+
283
+ let showBadge = $state(true);
284
+ </script>
285
+
286
+ <!-- Basic badges -->
287
+ <Badge text="New" variant="primary" />
288
+ <Badge text="Beta" variant="warning" size="sm" />
289
+ <Badge text="v1.0.0" variant="success" size="lg" />
290
+
291
+ <!-- Dismissible -->
292
+ {#if showBadge}
293
+ <Badge text="Alert" variant="danger" dismissible on:dismiss={() => (showBadge = false)} />
294
+ {/if}
295
+
296
+ <!-- Custom content -->
297
+ <Badge variant="success">
298
+ <IconCheck />
299
+ <span>Verified</span>
300
+ </Badge>
301
+ ```
302
+
303
+ ### TextArea
304
+
305
+ ```svelte
306
+ <script>
307
+ import { TextArea } from "@spaethtech/svelte-ui";
308
+
309
+ let notes = $state("");
310
+ let code = $state("");
311
+ </script>
312
+
313
+ <!-- Auto-resizing -->
314
+ <TextArea bind:value={notes} placeholder="Enter notes..." minRows={3} maxRows={10} />
315
+
316
+ <!-- Fixed height -->
317
+ <TextArea bind:value={code} minRows={5} maxRows={5} placeholder="Paste code here..." />
318
+
319
+ <!-- Read-only with copy control -->
320
+ <TextArea value="Read-only content" readonly allowCopy />
321
+ ```
322
+
323
+ ### Specialized Inputs
324
+
325
+ ```svelte
326
+ <script>
327
+ import { PasswordInput, EmailInput, SearchInput, NumberInput } from "@spaethtech/svelte-ui";
328
+
329
+ let password = $state("");
330
+ let email = $state("");
331
+ let search = $state("");
332
+ let quantity = $state(1);
333
+ </script>
334
+
335
+ <PasswordInput bind:value={password} placeholder="Enter password" />
336
+ <EmailInput bind:value={email} required placeholder="user@example.com" />
337
+ <SearchInput bind:value={search} placeholder="Search..." />
338
+ <NumberInput bind:value={quantity} min={1} max={100} />
339
+ ```
340
+
341
+ ### Tooltips (use:tooltip action)
342
+
343
+ There is no `Tooltip` component — tooltips are a Svelte action built on the `anchored` engine.
344
+
345
+ ```svelte
346
+ <script>
347
+ import { Button, tooltip } from "@spaethtech/svelte-ui";
348
+ </script>
349
+
350
+ <!-- Button drives the action from its `title` automatically -->
351
+ <Button title="Delete" variant="danger" />
352
+
353
+ <!-- Apply the action directly to any element -->
354
+ <span use:tooltip={{ text: "Any element", side: "top" }}>hover me</span>
355
+
356
+ <!-- Falls back to the element's native title (which it then suppresses) -->
357
+ <a href="/help" title="Get help" use:tooltip>?</a>
358
+ ```
359
+
360
+ ### Popup & Menu
361
+
362
+ ```svelte
363
+ <script>
364
+ import { Popup, Menu, Button } from "@spaethtech/svelte-ui";
365
+ import IconPencil from "~icons/mdi/pencil";
366
+ import IconDelete from "~icons/mdi/delete";
367
+
368
+ let trigger = $state();
369
+ let popupOpen = $state(false);
370
+ let menuOpen = $state(false);
371
+
372
+ const items = [
373
+ { label: "Edit", icon: IconPencil, onclick: () => console.log("edit") },
374
+ { label: "Delete", icon: IconDelete, onclick: () => console.log("delete") },
375
+ ];
376
+ </script>
377
+
378
+ <!-- Popover (arbitrary content) -->
379
+ <Button bind:element={trigger} text="Open" onclick={() => (popupOpen = !popupOpen)} />
380
+ <Popup anchor={trigger} bind:open={popupOpen} side="bottom" align="start">
381
+ <div class="p-3">…your content…</div>
382
+ </Popup>
383
+
384
+ <!-- Action menu -->
385
+ <Button bind:element={trigger} text="Actions" onclick={() => (menuOpen = !menuOpen)} />
386
+ <Menu anchor={trigger} bind:open={menuOpen} {items} align="end" />
387
+ ```
388
+
389
+ ### DataTable & Query (@spaethtech/svelte-ui/data)
390
+
391
+ The data components are driven by the headless layer. Build a grid with `createGrid` and a filter
392
+ bar with `Query` over a `DataSet`.
393
+
394
+ ```svelte
395
+ <script>
396
+ import { DataTable, Query } from "@spaethtech/svelte-ui";
397
+ import { createGrid } from "@spaethtech/svelte-ui/data";
398
+ import IconPencil from "~icons/mdi/pencil";
399
+
400
+ const grid = createGrid({
401
+ columns: [
402
+ { id: "name", label: "Name" },
403
+ { id: "email", label: "Email" },
404
+ { id: "status", label: "Status", sortKey: "status" },
405
+ ],
406
+ fetch: (request) => /* a reactive query returning { rows, total } */ myQuery(request),
407
+ });
408
+ </script>
409
+
410
+ <DataTable
411
+ {grid}
412
+ selectable
413
+ rowActions={(row) => [{ label: "Edit", icon: IconPencil, onclick: () => edit(row) }]}
414
+ />
415
+ ```
416
+
417
+ See the live demo for the full DataTable + Query walkthrough — http://localhost:5173.
418
+
419
+ ## Theme Integration
420
+
421
+ ### Using CSS Variables
422
+
423
+ ```svelte
424
+ <style>
425
+ .custom-component {
426
+ background: var(--ui-color-background);
427
+ color: var(--ui-color-text);
428
+ height: var(--ui-height);
429
+ }
430
+
431
+ .custom-button {
432
+ background: var(--ui-color-primary);
433
+ &:hover {
434
+ background: color-mix(in srgb, var(--ui-color-primary), black 12%);
435
+ }
436
+ }
437
+ /* For neutral surfaces (rows, ghost buttons, section bands) use the shared tints instead:
438
+ var(--ui-color-hover) / var(--ui-color-surface) / var(--ui-color-active). */
439
+ </style>
440
+ ```
441
+
442
+ ### Theme Selector
443
+
444
+ ```svelte
445
+ <script>
446
+ import { ThemeSelector } from "@spaethtech/svelte-ui";
447
+ </script>
448
+
449
+ <ThemeSelector />
450
+ ```