@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.
- package/.claude/skills/svelte-ui/SKILL.md +118 -0
- package/.claude/skills/themes/SKILL.md +303 -0
- package/CLAUDE.md +248 -0
- package/README.md +180 -42
- package/dist/components/Alert.svelte +119 -0
- package/dist/components/Alert.svelte.d.ts +29 -0
- package/dist/components/Badge/Badge.svelte +142 -69
- package/dist/components/Badge/Badge.svelte.d.ts +26 -6
- package/dist/components/Badge/index.d.ts +1 -1
- package/dist/components/Badge/index.js +1 -1
- package/dist/components/Banner.svelte +133 -0
- package/dist/components/Banner.svelte.d.ts +31 -0
- package/dist/components/Button.svelte +240 -0
- package/dist/components/Button.svelte.d.ts +33 -0
- package/dist/components/ButtonDropdown.svelte +145 -0
- package/dist/components/ButtonDropdown.svelte.d.ts +31 -0
- package/dist/components/Calendar.svelte +259 -0
- package/dist/components/Calendar.svelte.d.ts +27 -0
- package/dist/components/Card.svelte +79 -0
- package/dist/components/Card.svelte.d.ts +17 -0
- package/dist/components/CardBody.svelte +41 -0
- package/dist/components/CardBody.svelte.d.ts +17 -0
- package/dist/components/CardFooter.svelte +51 -0
- package/dist/components/CardFooter.svelte.d.ts +16 -0
- package/dist/components/CardHeader.svelte +51 -0
- package/dist/components/CardHeader.svelte.d.ts +16 -0
- package/dist/components/Checkbox.svelte +131 -0
- package/dist/components/Checkbox.svelte.d.ts +16 -0
- package/dist/components/ConfirmDialog.svelte +103 -0
- package/dist/components/ConfirmDialog.svelte.d.ts +33 -0
- package/dist/components/DataTable.svelte +518 -0
- package/dist/components/DataTable.svelte.d.ts +74 -0
- package/dist/components/DatePicker.svelte +312 -0
- package/dist/components/DatePicker.svelte.d.ts +32 -0
- package/dist/components/DateTimeInput.svelte +93 -0
- package/dist/components/DateTimeInput.svelte.d.ts +20 -0
- package/dist/components/Dialog.svelte +151 -0
- package/dist/components/Dialog.svelte.d.ts +30 -0
- package/dist/components/{EmailInput/EmailInput.svelte → EmailInput.svelte} +17 -8
- package/dist/components/EmailInput.svelte.d.ts +21 -0
- package/dist/components/Input.svelte +369 -0
- package/dist/components/Input.svelte.d.ts +35 -0
- package/dist/components/{List/List.svelte → List.svelte} +194 -133
- package/dist/components/{List/List.svelte.d.ts → List.svelte.d.ts} +9 -1
- package/dist/components/Menu.svelte +117 -0
- package/dist/components/Menu.svelte.d.ts +20 -0
- package/dist/components/NotesEditor.svelte +127 -0
- package/dist/components/NotesEditor.svelte.d.ts +17 -0
- package/dist/components/{NumberInput/NumberInput.svelte → NumberInput.svelte} +146 -105
- package/dist/components/{NumberInput/NumberInput.svelte.d.ts → NumberInput.svelte.d.ts} +11 -4
- package/dist/components/PasswordInput.svelte +52 -0
- package/dist/components/PasswordInput.svelte.d.ts +20 -0
- package/dist/components/Popup.svelte +140 -0
- package/dist/components/Popup.svelte.d.ts +31 -0
- package/dist/components/Query.svelte +284 -0
- package/dist/components/Query.svelte.d.ts +15 -0
- package/dist/components/{Rating/Rating.svelte → Rating.svelte} +19 -10
- package/dist/components/Rating.svelte.d.ts +13 -0
- package/dist/components/{SearchInput/SearchInput.svelte → SearchInput.svelte} +19 -8
- package/dist/components/{SearchInput/SearchInput.svelte.d.ts → SearchInput.svelte.d.ts} +9 -2
- package/dist/components/{Select/Select.svelte → Select.svelte} +48 -76
- package/dist/components/{Select/Select.svelte.d.ts → Select.svelte.d.ts} +11 -1
- package/dist/components/SideBarMenu/SideBarMenu.svelte +724 -0
- package/dist/components/SideBarMenu/SideBarMenu.svelte.d.ts +109 -0
- package/dist/components/SideBarMenu/index.d.ts +2 -0
- package/dist/components/SideBarMenu/index.js +1 -0
- package/dist/components/TabStrip/TabStrip.svelte +384 -0
- package/dist/components/TabStrip/TabStrip.svelte.d.ts +50 -0
- package/dist/components/TabStrip/index.d.ts +3 -0
- package/dist/components/TabStrip/index.js +2 -0
- package/dist/components/{TextArea/TextArea.svelte → TextArea.svelte} +143 -112
- package/dist/components/TextArea.svelte.d.ts +38 -0
- package/dist/components/ThemeSelector.svelte +81 -0
- package/dist/components/ThemeSelector.svelte.d.ts +10 -0
- package/dist/components/TimePicker.svelte +148 -0
- package/dist/components/TimePicker.svelte.d.ts +28 -0
- package/dist/components/TimeRangeInput.svelte +203 -0
- package/dist/components/TimeRangeInput.svelte.d.ts +29 -0
- package/dist/components/TimeSpinner.svelte +202 -0
- package/dist/components/TimeSpinner.svelte.d.ts +26 -0
- package/dist/components/Toast/Toaster.svelte +51 -0
- package/dist/components/Toast/Toaster.svelte.d.ts +12 -0
- package/dist/components/Toast/toast.svelte.d.ts +29 -0
- package/dist/components/Toast/toast.svelte.js +27 -0
- package/dist/components/Toggle.svelte +93 -0
- package/dist/components/Toggle.svelte.d.ts +15 -0
- package/dist/data/dataset.d.ts +42 -0
- package/dist/data/dataset.js +3 -0
- package/dist/data/index.d.ts +3 -0
- package/dist/data/index.js +3 -0
- package/dist/data/query/ast.d.ts +62 -0
- package/dist/data/query/ast.js +12 -0
- package/dist/data/query/index.d.ts +3 -0
- package/dist/data/query/index.js +3 -0
- package/dist/data/query/lexer.d.ts +33 -0
- package/dist/data/query/lexer.js +225 -0
- package/dist/data/query/parser.d.ts +11 -0
- package/dist/data/query/parser.js +252 -0
- package/dist/data/table/grid.svelte.d.ts +57 -0
- package/dist/data/table/grid.svelte.js +139 -0
- package/dist/data/table/index.d.ts +2 -0
- package/dist/data/table/index.js +2 -0
- package/dist/data/table/types.d.ts +79 -0
- package/dist/index.d.ts +49 -22
- package/dist/index.js +46 -21
- package/dist/positioning/anchored.d.ts +61 -0
- package/dist/positioning/anchored.js +122 -0
- package/dist/positioning/tooltip.d.ts +41 -0
- package/dist/positioning/tooltip.js +147 -0
- package/dist/theme.css +205 -0
- package/dist/types/breakpoints.d.ts +24 -0
- package/dist/types/breakpoints.js +13 -0
- package/dist/types/responsive.d.ts +32 -0
- package/dist/types/responsive.js +54 -0
- package/dist/types/sizes.d.ts +10 -3
- package/dist/types/time.d.ts +19 -0
- package/dist/types/time.js +10 -0
- package/dist/types/variants.d.ts +8 -1
- package/dist/types/variants.js +16 -1
- package/docs/components.md +255 -0
- package/docs/examples.md +323 -0
- package/docs/paradigm.md +240 -0
- package/docs/themes.md +170 -0
- package/docs/usage.md +450 -0
- package/package.json +97 -63
- package/dist/components/Button/Button.svelte +0 -172
- package/dist/components/Button/Button.svelte.d.ts +0 -32
- package/dist/components/Button/index.d.ts +0 -1
- package/dist/components/Button/index.js +0 -1
- package/dist/components/Dialog/Dialog.svelte +0 -101
- package/dist/components/Dialog/Dialog.svelte.d.ts +0 -18
- package/dist/components/Dialog/index.d.ts +0 -1
- package/dist/components/Dialog/index.js +0 -1
- package/dist/components/ElementManager/ElementManager.svelte +0 -397
- package/dist/components/ElementManager/ElementManager.svelte.d.ts +0 -43
- package/dist/components/ElementManager/index.d.ts +0 -1
- package/dist/components/ElementManager/index.js +0 -1
- package/dist/components/EmailInput/EmailInput.svelte.d.ts +0 -14
- package/dist/components/EmailInput/index.d.ts +0 -1
- package/dist/components/EmailInput/index.js +0 -1
- package/dist/components/Icon/Icon.svelte +0 -74
- package/dist/components/Icon/Icon.svelte.d.ts +0 -13
- package/dist/components/Icon/index.d.ts +0 -1
- package/dist/components/Icon/index.js +0 -1
- package/dist/components/Input/Input.svelte +0 -268
- package/dist/components/Input/Input.svelte.d.ts +0 -18
- package/dist/components/Input/index.d.ts +0 -1
- package/dist/components/Input/index.js +0 -1
- package/dist/components/List/index.d.ts +0 -1
- package/dist/components/List/index.js +0 -1
- package/dist/components/ListItem/ListItem.svelte +0 -175
- package/dist/components/ListItem/ListItem.svelte.d.ts +0 -24
- package/dist/components/ListItem/index.d.ts +0 -2
- package/dist/components/ListItem/index.js +0 -2
- package/dist/components/ListView/ListView.svelte +0 -463
- package/dist/components/ListView/ListView.svelte.d.ts +0 -37
- package/dist/components/ListView/index.d.ts +0 -2
- package/dist/components/ListView/index.js +0 -2
- package/dist/components/NodeGraph/BaseNode.d.ts +0 -57
- package/dist/components/NodeGraph/BaseNode.js +0 -30
- package/dist/components/NodeGraph/Edge.svelte +0 -60
- package/dist/components/NodeGraph/Edge.svelte.d.ts +0 -16
- package/dist/components/NodeGraph/ExpressionEvaluator.d.ts +0 -82
- package/dist/components/NodeGraph/ExpressionEvaluator.js +0 -152
- package/dist/components/NodeGraph/Node.svelte +0 -100
- package/dist/components/NodeGraph/Node.svelte.d.ts +0 -10
- package/dist/components/NodeGraph/NodeGraph.svelte +0 -52
- package/dist/components/NodeGraph/NodeGraph.svelte.d.ts +0 -14
- package/dist/components/NodeGraph/NodeInstance.svelte.d.ts +0 -80
- package/dist/components/NodeGraph/NodeInstance.svelte.js +0 -241
- package/dist/components/NodeGraph/NodePort.svelte +0 -75
- package/dist/components/NodeGraph/NodePort.svelte.d.ts +0 -11
- package/dist/components/NodeGraph/decorators.d.ts +0 -81
- package/dist/components/NodeGraph/decorators.js +0 -148
- package/dist/components/NodeGraph/index.d.ts +0 -9
- package/dist/components/NodeGraph/index.js +0 -9
- package/dist/components/NodeGraph/types.d.ts +0 -94
- package/dist/components/NodeGraph/types.js +0 -33
- package/dist/components/NotesEditor/NotesEditor.svelte +0 -203
- package/dist/components/NotesEditor/NotesEditor.svelte.d.ts +0 -9
- package/dist/components/NotesEditor/index.d.ts +0 -1
- package/dist/components/NotesEditor/index.js +0 -1
- package/dist/components/NumberInput/index.d.ts +0 -1
- package/dist/components/NumberInput/index.js +0 -1
- package/dist/components/PasswordInput/PasswordInput.svelte +0 -41
- package/dist/components/PasswordInput/PasswordInput.svelte.d.ts +0 -13
- package/dist/components/PasswordInput/index.d.ts +0 -1
- package/dist/components/PasswordInput/index.js +0 -1
- package/dist/components/Popup/index.d.ts +0 -1
- package/dist/components/Popup/index.js +0 -1
- package/dist/components/Rating/Rating.svelte.d.ts +0 -7
- package/dist/components/Rating/index.d.ts +0 -1
- package/dist/components/Rating/index.js +0 -1
- package/dist/components/ScrollView/ScrollView.svelte +0 -285
- package/dist/components/ScrollView/ScrollView.svelte.d.ts +0 -19
- package/dist/components/ScrollView/index.d.ts +0 -1
- package/dist/components/ScrollView/index.js +0 -1
- package/dist/components/SearchInput/index.d.ts +0 -1
- package/dist/components/SearchInput/index.js +0 -1
- package/dist/components/Select/index.d.ts +0 -1
- package/dist/components/Select/index.js +0 -1
- package/dist/components/TextArea/TextArea.svelte.d.ts +0 -19
- package/dist/components/TextArea/index.d.ts +0 -1
- package/dist/components/TextArea/index.js +0 -1
- package/dist/components/ThemeSelector/ThemeSelector.svelte +0 -64
- package/dist/components/ThemeSelector/ThemeSelector.svelte.d.ts +0 -3
- package/dist/components/ThemeSelector/index.d.ts +0 -1
- package/dist/components/ThemeSelector/index.js +0 -1
- package/dist/components/TooltipHandler/TooltipHandler.svelte +0 -593
- package/dist/components/TooltipHandler/TooltipHandler.svelte.d.ts +0 -10
- package/dist/components/TooltipHandler/index.d.ts +0 -1
- package/dist/components/TooltipHandler/index.js +0 -1
- package/dist/styles/sizes.d.ts +0 -78
- package/dist/styles/sizes.js +0 -120
- package/dist/styles/variants.d.ts +0 -106
- package/dist/styles/variants.js +0 -194
- package/dist/types/ManagerTypes.d.ts +0 -42
- /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
|
+
```
|