@spaethtech/svelte-ui 0.3.1-dev.6.5d93a69 → 0.3.1-dev.8.7f749c3

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.
package/docs/usage.md ADDED
@@ -0,0 +1,427 @@
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
+ ### Dialog
216
+
217
+ ```svelte
218
+ <script>
219
+ import { Dialog, Button, Input } from "@spaethtech/svelte-ui";
220
+
221
+ let showDialog = $state(false);
222
+ let showDanger = $state(false);
223
+ </script>
224
+
225
+ <!-- Basic confirmation -->
226
+ <Button text="Show Dialog" onclick={() => (showDialog = true)} />
227
+ <Dialog
228
+ bind:isOpen={showDialog}
229
+ title="Confirm Action"
230
+ message="Are you sure you want to proceed?"
231
+ onConfirm={() => console.log("Confirmed")}
232
+ />
233
+
234
+ <!-- Danger variant -->
235
+ <Dialog
236
+ bind:isOpen={showDanger}
237
+ title="Delete Item"
238
+ message="This action cannot be undone!"
239
+ variant="danger"
240
+ confirmText="Delete"
241
+ onConfirm={() => console.log("Deleted")}
242
+ />
243
+
244
+ <!-- Custom content -->
245
+ <Dialog bind:isOpen={showDialog} title="Custom Content">
246
+ <div class="space-y-2">
247
+ <p>This is custom content</p>
248
+ <Input placeholder="Enter value" />
249
+ </div>
250
+ </Dialog>
251
+ ```
252
+
253
+ ### Badge
254
+
255
+ ```svelte
256
+ <script>
257
+ import { Badge } from "@spaethtech/svelte-ui";
258
+ import IconCheck from "~icons/mdi/check";
259
+
260
+ let showBadge = $state(true);
261
+ </script>
262
+
263
+ <!-- Basic badges -->
264
+ <Badge text="New" variant="primary" />
265
+ <Badge text="Beta" variant="warning" size="sm" />
266
+ <Badge text="v1.0.0" variant="success" size="lg" />
267
+
268
+ <!-- Dismissible -->
269
+ {#if showBadge}
270
+ <Badge text="Alert" variant="danger" dismissible on:dismiss={() => (showBadge = false)} />
271
+ {/if}
272
+
273
+ <!-- Custom content -->
274
+ <Badge variant="success">
275
+ <IconCheck />
276
+ <span>Verified</span>
277
+ </Badge>
278
+ ```
279
+
280
+ ### TextArea
281
+
282
+ ```svelte
283
+ <script>
284
+ import { TextArea } from "@spaethtech/svelte-ui";
285
+
286
+ let notes = $state("");
287
+ let code = $state("");
288
+ </script>
289
+
290
+ <!-- Auto-resizing -->
291
+ <TextArea bind:value={notes} placeholder="Enter notes..." minRows={3} maxRows={10} />
292
+
293
+ <!-- Fixed height -->
294
+ <TextArea bind:value={code} minRows={5} maxRows={5} placeholder="Paste code here..." />
295
+
296
+ <!-- Read-only with copy control -->
297
+ <TextArea value="Read-only content" readonly allowCopy />
298
+ ```
299
+
300
+ ### Specialized Inputs
301
+
302
+ ```svelte
303
+ <script>
304
+ import { PasswordInput, EmailInput, SearchInput, NumberInput } from "@spaethtech/svelte-ui";
305
+
306
+ let password = $state("");
307
+ let email = $state("");
308
+ let search = $state("");
309
+ let quantity = $state(1);
310
+ </script>
311
+
312
+ <PasswordInput bind:value={password} placeholder="Enter password" />
313
+ <EmailInput bind:value={email} required placeholder="user@example.com" />
314
+ <SearchInput bind:value={search} placeholder="Search..." />
315
+ <NumberInput bind:value={quantity} min={1} max={100} />
316
+ ```
317
+
318
+ ### Tooltips (use:tooltip action)
319
+
320
+ There is no `Tooltip` component — tooltips are a Svelte action built on the `anchored` engine.
321
+
322
+ ```svelte
323
+ <script>
324
+ import { Button, tooltip } from "@spaethtech/svelte-ui";
325
+ </script>
326
+
327
+ <!-- Button drives the action from its `title` automatically -->
328
+ <Button title="Delete" variant="danger" />
329
+
330
+ <!-- Apply the action directly to any element -->
331
+ <span use:tooltip={{ text: "Any element", side: "top" }}>hover me</span>
332
+
333
+ <!-- Falls back to the element's native title (which it then suppresses) -->
334
+ <a href="/help" title="Get help" use:tooltip>?</a>
335
+ ```
336
+
337
+ ### Popup & Menu
338
+
339
+ ```svelte
340
+ <script>
341
+ import { Popup, Menu, Button } from "@spaethtech/svelte-ui";
342
+ import IconPencil from "~icons/mdi/pencil";
343
+ import IconDelete from "~icons/mdi/delete";
344
+
345
+ let trigger = $state();
346
+ let popupOpen = $state(false);
347
+ let menuOpen = $state(false);
348
+
349
+ const items = [
350
+ { label: "Edit", icon: IconPencil, onclick: () => console.log("edit") },
351
+ { label: "Delete", icon: IconDelete, onclick: () => console.log("delete") },
352
+ ];
353
+ </script>
354
+
355
+ <!-- Popover (arbitrary content) -->
356
+ <Button bind:element={trigger} text="Open" onclick={() => (popupOpen = !popupOpen)} />
357
+ <Popup anchor={trigger} bind:open={popupOpen} side="bottom" align="start">
358
+ <div class="p-3">…your content…</div>
359
+ </Popup>
360
+
361
+ <!-- Action menu -->
362
+ <Button bind:element={trigger} text="Actions" onclick={() => (menuOpen = !menuOpen)} />
363
+ <Menu anchor={trigger} bind:open={menuOpen} {items} align="end" />
364
+ ```
365
+
366
+ ### DataTable & Query (@spaethtech/svelte-ui/data)
367
+
368
+ The data components are driven by the headless layer. Build a grid with `createGrid` and a filter
369
+ bar with `Query` over a `DataSet`.
370
+
371
+ ```svelte
372
+ <script>
373
+ import { DataTable, Query } from "@spaethtech/svelte-ui";
374
+ import { createGrid } from "@spaethtech/svelte-ui/data";
375
+ import IconPencil from "~icons/mdi/pencil";
376
+
377
+ const grid = createGrid({
378
+ columns: [
379
+ { id: "name", label: "Name" },
380
+ { id: "email", label: "Email" },
381
+ { id: "status", label: "Status", sortKey: "status" },
382
+ ],
383
+ fetch: (request) => /* a reactive query returning { rows, total } */ myQuery(request),
384
+ });
385
+ </script>
386
+
387
+ <DataTable
388
+ {grid}
389
+ selectable
390
+ rowActions={(row) => [{ label: "Edit", icon: IconPencil, onclick: () => edit(row) }]}
391
+ />
392
+ ```
393
+
394
+ See the live demo for the full DataTable + Query walkthrough — http://localhost:5173.
395
+
396
+ ## Theme Integration
397
+
398
+ ### Using CSS Variables
399
+
400
+ ```svelte
401
+ <style>
402
+ .custom-component {
403
+ background: var(--ui-color-background);
404
+ color: var(--ui-color-text);
405
+ height: var(--ui-height);
406
+ }
407
+
408
+ .custom-button {
409
+ background: var(--ui-color-primary);
410
+ &:hover {
411
+ background: color-mix(in srgb, var(--ui-color-primary), black 12%);
412
+ }
413
+ }
414
+ /* For neutral surfaces (rows, ghost buttons, section bands) use the shared tints instead:
415
+ var(--ui-color-hover) / var(--ui-color-surface) / var(--ui-color-active). */
416
+ </style>
417
+ ```
418
+
419
+ ### Theme Selector
420
+
421
+ ```svelte
422
+ <script>
423
+ import { ThemeSelector } from "@spaethtech/svelte-ui";
424
+ </script>
425
+
426
+ <ThemeSelector />
427
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spaethtech/svelte-ui",
3
- "version": "0.3.1-dev.6.5d93a69",
3
+ "version": "0.3.1-dev.8.7f749c3",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/spaethtech/svelte-ui.git"
@@ -33,7 +33,11 @@
33
33
  "files": [
34
34
  "dist",
35
35
  "!dist/**/*.test.*",
36
- "!dist/**/*.spec.*"
36
+ "!dist/**/*.spec.*",
37
+ "CLAUDE.md",
38
+ "docs",
39
+ ".claude/skills/themes",
40
+ ".claude/skills/svelte-ui"
37
41
  ],
38
42
  "sideEffects": [
39
43
  "**/*.css"