@spaethtech/svelte-ui 0.16.0 → 0.16.1-dev.76.a0169fa
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/themes/SKILL.md +35 -14
- package/CLAUDE.md +6 -3
- package/dist/components/Avatar/Avatar.svelte +1 -1
- package/dist/components/Avatar/AvatarGroup.svelte +1 -1
- package/dist/components/Button.svelte +1 -1
- package/dist/components/Card.svelte +1 -1
- package/dist/components/CardFooter.svelte +1 -1
- package/dist/components/CardHeader.svelte +1 -1
- package/dist/components/Chip/Chip.svelte +1 -1
- package/dist/components/Combobox/Combobox.svelte +1 -1
- package/dist/components/DataTable.svelte +1 -1
- package/dist/components/DatePicker.svelte +1 -1
- package/dist/components/EmptyState/EmptyState.svelte +1 -1
- package/dist/components/Input.svelte +1 -1
- package/dist/components/List.svelte +2 -2
- package/dist/components/Menu.svelte +2 -2
- package/dist/components/NotesEditor.svelte +1 -1
- package/dist/components/Pagination/Pagination.svelte +1 -1
- package/dist/components/Query.svelte +1 -1
- package/dist/components/SideBarMenu/SideBarMenu.svelte +4 -4
- package/dist/components/Stat/Stat.svelte +1 -1
- package/dist/components/TextArea.svelte +1 -1
- package/dist/components/TimePicker.svelte +1 -1
- package/dist/components/TimeRangeInput.svelte +1 -1
- package/dist/components/TokenInput/TokenInput.svelte +1 -1
- package/dist/theme.css +18 -3
- package/dist/types/variants.d.ts +5 -4
- package/dist/types/variants.js +7 -6
- package/docs/themes.md +13 -8
- package/package.json +1 -1
|
@@ -22,7 +22,7 @@ per-component `--dt-*`/`--card-*` namespaces have all been removed — don't rei
|
|
|
22
22
|
### Palette — `--ui-color-*`
|
|
23
23
|
|
|
24
24
|
```
|
|
25
|
-
--ui-color-background --ui-color-text
|
|
25
|
+
--ui-color-background --ui-color-text --ui-color-neutral
|
|
26
26
|
--ui-color-primary --ui-color-secondary
|
|
27
27
|
--ui-color-success --ui-color-warning
|
|
28
28
|
--ui-color-error --ui-color-info
|
|
@@ -30,14 +30,23 @@ per-component `--dt-*`/`--card-*` namespaces have all been removed — don't rei
|
|
|
30
30
|
|
|
31
31
|
These are the only palette colours a component references. The `variant` axis
|
|
32
32
|
(`types/variants.ts` → `variantToken`) maps each `Variant` to one of these (`danger`→`error`; the two
|
|
33
|
-
non-accent variants `neutral` and `ghost` →
|
|
33
|
+
non-accent variants `neutral` and `ghost` → **`--ui-color-neutral`**). Canonical order:
|
|
34
34
|
`neutral · primary · secondary · success · info · warning · danger · ghost`.
|
|
35
35
|
|
|
36
|
+
**`neutral` is the default/undefined variant** — every sizeable/themeable component defaults to
|
|
37
|
+
`variant="neutral"`, so out of the box the whole library is **monochrome**; a colour appears only when
|
|
38
|
+
you set an explicit `variant`. **`--ui-color-neutral`** is the themeable neutral base: it **defaults to
|
|
39
|
+
`var(--ui-color-text)`** (so it flips opposite `--ui-color-background` per theme, and a border mixed
|
|
40
|
+
toward `transparent` always reads against the background), but a theme can override it **independently
|
|
41
|
+
of body text** to recolour every neutral border/surface at once. Every neutral border/divider — and
|
|
42
|
+
`--ui-border-color` — derives from it, so it's the single knob for "the colour of all neutral borders".
|
|
43
|
+
|
|
36
44
|
- `ghost` — borderless, transparent, hover-tint only (the minimal control). For the box-shaped
|
|
37
45
|
**fields** (Input/Select/TextArea) this also drives the **field background**: `ghost` → transparent,
|
|
38
46
|
every other variant → `--ui-color-background` (so a field reads as a field on any surface).
|
|
39
|
-
- `neutral` — the _uncoloured_ variant (mixes from `--ui-color-
|
|
40
|
-
(Button/Toggle/Banner → black-on-white /
|
|
47
|
+
- `neutral` — the _uncoloured_, **default** variant (mixes from `--ui-color-neutral`, which defaults to
|
|
48
|
+
`--ui-color-text`): **solid** in solid contexts (Button/Toggle/Banner → black-on-white /
|
|
49
|
+
white-on-black), a **tint** in soft/bordered contexts (Badge/Alert/Input/Card frame).
|
|
41
50
|
- (`plain` was removed — it's now `ghost`. Old bordered-`ghost` → `neutral`.)
|
|
42
51
|
|
|
43
52
|
Field **help/error text** uses no new token: the muted `description` row is an inline
|
|
@@ -68,7 +77,7 @@ variant token at shared strengths, so every tinted surface is calculated identic
|
|
|
68
77
|
```
|
|
69
78
|
--ui-tint-soft 12% soft resting fill (Badge fill, Alert `filled`)
|
|
70
79
|
--ui-tint-divider 30% soft internal divider (CardHeader/CardFooter separators; the default
|
|
71
|
-
|
|
80
|
+
NEUTRAL divider is `--ui-border-color`)
|
|
72
81
|
--ui-tint-border 50% bordered surface, REST (Badge/Alert/Banner ring · Card/DataTable/Input/
|
|
73
82
|
TextArea frame · Button outline)
|
|
74
83
|
--ui-tint-border-hover 80% bordered field, HOVER (Input/TextArea/Card/DataTable/Button — the
|
|
@@ -77,14 +86,16 @@ variant token at shared strengths, so every tinted surface is calculated identic
|
|
|
77
86
|
```
|
|
78
87
|
|
|
79
88
|
e.g. `color-mix(in srgb, var(<variant-token>) var(--ui-tint-soft), transparent)`. A `primary` badge is
|
|
80
|
-
primary@these; a `neutral` one is
|
|
81
|
-
whole tint language). **Every bordered surface uses ONE calc** —
|
|
82
|
-
`--ui-tint-border-hover` on hover/focus, from the variant token — with **no
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
`--ui-
|
|
86
|
-
|
|
87
|
-
|
|
89
|
+
primary@these; a `neutral` (default) one is **`--ui-color-neutral`**@these. Theme-independent (a theme
|
|
90
|
+
MAY override them to tune the whole tint language). **Every bordered surface uses ONE calc** —
|
|
91
|
+
`--ui-tint-border` at rest, `--ui-tint-border-hover` on hover/focus, from the variant token — with **no
|
|
92
|
+
`secondary` special case**. A default (neutral) frame is therefore `--ui-color-neutral` @ these; a
|
|
93
|
+
default divider is `--ui-color-neutral` @ `--ui-tint-divider` (= `--ui-border-color`). Internal
|
|
94
|
+
**dividers** use the softer `--ui-tint-divider` (30%) tier, likewise one calc per variant — so a
|
|
95
|
+
divider always reads lighter than the frame at any variant. `--ui-border-color-strong`/`-strong-hover`
|
|
96
|
+
have been **REMOVED** (migrate to `color-mix(in srgb, var(--ui-color-neutral) var(--ui-tint-border),
|
|
97
|
+
transparent)`, hover → `--ui-tint-border-hover`). (Distinct from the interactive tints above, which mix
|
|
98
|
+
from `--ui-accent`.)
|
|
88
99
|
|
|
89
100
|
### The `borderless` prop (border-colour swap, never a border-width change)
|
|
90
101
|
|
|
@@ -107,11 +118,21 @@ NOT take `borderless`.
|
|
|
107
118
|
```
|
|
108
119
|
--ui-border-radius corner radius — ONE fixed value for every rectangular surface; NOT
|
|
109
120
|
scaled by `size`, no -sm/-lg (pills use rounded-full)
|
|
110
|
-
--ui-border-color soft internal divider (row separators, section splits)
|
|
121
|
+
--ui-border-color soft internal divider (row separators, section splits) — NEUTRAL:
|
|
122
|
+
`--ui-color-neutral` @ `--ui-tint-divider` (30%). Repeated per theme
|
|
123
|
+
scope so it re-resolves per theme + survives @theme tree-shaking.
|
|
111
124
|
(--ui-border-color-strong/-strong-hover were REMOVED — use the
|
|
112
125
|
`--ui-tint-border` / `--ui-tint-border-hover` scheme instead)
|
|
126
|
+
--ui-color-neutral the neutral/undefined-variant base colour; defaults to
|
|
127
|
+
`var(--ui-color-text)`. Override to recolour ALL neutral borders +
|
|
128
|
+
surfaces at once, independent of body text + the variant colours.
|
|
113
129
|
```
|
|
114
130
|
|
|
131
|
+
**One hue, two weights.** All *neutral* borders share the `--ui-color-neutral` hue; only the tint
|
|
132
|
+
weight differs by role — **divider** `--ui-tint-divider` (30%, `--ui-border-color`) vs **frame**
|
|
133
|
+
`--ui-tint-border` (50%). A `variant`-set border tints from that variant's token instead (a `secondary`
|
|
134
|
+
Card = cyan border) — that's intended; the neutral default is what's monochrome.
|
|
135
|
+
|
|
115
136
|
### Density / text / icon — the `size` axis
|
|
116
137
|
|
|
117
138
|
```
|
package/CLAUDE.md
CHANGED
|
@@ -160,8 +160,11 @@ with its clear/help actions as `<Button>`. A raw interactive element inside a co
|
|
|
160
160
|
|
|
161
161
|
Two shared **cross-cutting axes** every sizeable/themeable component consumes (mirror each other):
|
|
162
162
|
|
|
163
|
-
- **`variant`** (`types/variants.ts`) — color/style: `primary` `secondary` `danger` `info`
|
|
164
|
-
`
|
|
163
|
+
- **`variant`** (`types/variants.ts`) — color/style: `neutral` `primary` `secondary` `danger` `info`
|
|
164
|
+
`success` `warning` `ghost`. **`neutral` is the default** (undefined variant) — components are
|
|
165
|
+
monochrome out of the box, colour only on an explicit variant. `neutral`/`ghost` mix from
|
|
166
|
+
`--ui-color-neutral` (defaults to `--ui-color-text`, independently themeable). `ghost` =
|
|
167
|
+
borderless/transparent, for dense icon controls.
|
|
165
168
|
- **`size`** (`types/sizes.ts`) — `sm` (24px) · `md` (32px, **default**) · `lg` (40px), tied to
|
|
166
169
|
`--ui-height-sm` / `--ui-height` / `--ui-height-lg` (`--ui-height-touch` 44px is a separate token
|
|
167
170
|
for explicit touch targets, not `lg`). Each component maps `size` to its height/text/padding/icon,
|
|
@@ -226,7 +229,7 @@ interface Props {
|
|
|
226
229
|
size?: Size;
|
|
227
230
|
children?: Snippet;
|
|
228
231
|
}
|
|
229
|
-
let { value = "", variant = "
|
|
232
|
+
let { value = "", variant = "neutral", size = "md", children }: Props = $props();
|
|
230
233
|
```
|
|
231
234
|
|
|
232
235
|
## Known Issues (do not "fix" in code)
|
|
@@ -218,7 +218,7 @@
|
|
|
218
218
|
// (If a header-less / footer-less mode is ever added, flip that edge to `bodyBorder` + round the corner.)
|
|
219
219
|
// `ghost` makes every section transparent (bands AND body) for a bare, see-through table.
|
|
220
220
|
const sectionBorder =
|
|
221
|
-
"color-mix(in srgb, var(--ui-color-
|
|
221
|
+
"color-mix(in srgb, var(--ui-color-neutral) var(--ui-tint-border), transparent)";
|
|
222
222
|
const bandBg = $derived(variant === "ghost" ? "transparent" : "var(--ui-color-surface)");
|
|
223
223
|
const bodyBg = $derived(variant === "ghost" ? "transparent" : "var(--ui-color-background)");
|
|
224
224
|
const bandBorder = $derived(borderless ? bandBg : sectionBorder); // header + footer, all 4 sides
|
|
@@ -216,7 +216,7 @@
|
|
|
216
216
|
|
|
217
217
|
<Popup anchor={anchorEl} bind:open offset={6}>
|
|
218
218
|
<div
|
|
219
|
-
class="rounded-[var(--ui-border-radius)] border {pad} shadow-lg [border-color:color-mix(in_srgb,var(--ui-color-
|
|
219
|
+
class="rounded-[var(--ui-border-radius)] border {pad} shadow-lg [border-color:color-mix(in_srgb,var(--ui-color-neutral)_var(--ui-tint-border),transparent)] [background-color:var(--ui-color-background)] [color:var(--ui-color-text)]"
|
|
220
220
|
style="--accent: {accent}"
|
|
221
221
|
>
|
|
222
222
|
{#if range}
|
|
@@ -502,8 +502,8 @@
|
|
|
502
502
|
<div
|
|
503
503
|
bind:this={listElement}
|
|
504
504
|
class="ui-accent border {disabled
|
|
505
|
-
? '[background-color:color-mix(in_srgb,var(--ui-color-text)_5%,transparent)] [border-color:color-mix(in_srgb,var(--ui-color-
|
|
506
|
-
: '[background-color:var(--ui-color-background)] [border-color:color-mix(in_srgb,var(--ui-color-
|
|
505
|
+
? '[background-color:color-mix(in_srgb,var(--ui-color-text)_5%,transparent)] [border-color:color-mix(in_srgb,var(--ui-color-neutral)_var(--ui-tint-border),transparent)] cursor-not-allowed'
|
|
506
|
+
: '[background-color:var(--ui-color-background)] [border-color:color-mix(in_srgb,var(--ui-color-neutral)_var(--ui-tint-border),transparent)] hover:[border-color:color-mix(in_srgb,var(--ui-color-neutral)_var(--ui-tint-border-hover),transparent)] focus:[border-color:color-mix(in_srgb,var(--ui-color-neutral)_var(--ui-tint-border-hover),transparent)] focus:[outline:2px_solid_color-mix(in_srgb,currentColor_70%,transparent)] focus:[outline-offset:0px]'} rounded-md overflow-y-scroll custom-list {dropdownClass}"
|
|
507
507
|
style="{accentVar} height: {maxHeight()}px; scrollbar-width: none; -ms-overflow-style: none; overscroll-behavior: contain;"
|
|
508
508
|
onscroll={handleScroll}
|
|
509
509
|
onkeydown={handleListKeydown}
|
|
@@ -90,12 +90,12 @@
|
|
|
90
90
|
role="menu"
|
|
91
91
|
tabindex="0"
|
|
92
92
|
{onkeydown}
|
|
93
|
-
class="ui-accent min-w-48 rounded-md border p-1 shadow-lg outline-none [background-color:var(--ui-color-background)] [border-color:color-mix(in_srgb,var(--ui-color-
|
|
93
|
+
class="ui-accent min-w-48 rounded-md border p-1 shadow-lg outline-none [background-color:var(--ui-color-background)] [border-color:color-mix(in_srgb,var(--ui-color-neutral)_var(--ui-tint-border),transparent)]"
|
|
94
94
|
style={accentVar}
|
|
95
95
|
>
|
|
96
96
|
{#each items as item, i (i)}
|
|
97
97
|
{#if isSeparator(item)}
|
|
98
|
-
<li role="separator" class="my-1 h-px [background-color:color-mix(in_srgb,var(--ui-color-
|
|
98
|
+
<li role="separator" class="my-1 h-px [background-color:color-mix(in_srgb,var(--ui-color-neutral)_var(--ui-tint-border),transparent)]"></li>
|
|
99
99
|
{:else}
|
|
100
100
|
<li role="none">
|
|
101
101
|
<button
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
// Band surface + border: variant re-points --ui-accent so --ui-color-surface/hover re-mix from it
|
|
79
79
|
// (the shared .ui-accent mechanism DataTable's footer uses). `ghost` ⇒ transparent band.
|
|
80
80
|
const accentVar = $derived(variant ? `--ui-accent: var(${variantToken[variant]});` : "");
|
|
81
|
-
const sectionBorder = "color-mix(in srgb, var(--ui-color-
|
|
81
|
+
const sectionBorder = "color-mix(in srgb, var(--ui-color-neutral) var(--ui-tint-border), transparent)";
|
|
82
82
|
const bandBg = $derived(variant === "ghost" ? "transparent" : "var(--ui-color-surface)");
|
|
83
83
|
const bandBorder = $derived(borderless ? "transparent" : sectionBorder);
|
|
84
84
|
|
|
@@ -320,8 +320,8 @@
|
|
|
320
320
|
const dockEdge = $derived(dockRight ? "right-0" : "left-0");
|
|
321
321
|
const dockBorder = $derived(
|
|
322
322
|
dockRight
|
|
323
|
-
? "[border-left:
|
|
324
|
-
: "[border-right:
|
|
323
|
+
? "[border-left:1px_solid_var(--ui-border-color)]"
|
|
324
|
+
: "[border-right:1px_solid_var(--ui-border-color)]",
|
|
325
325
|
);
|
|
326
326
|
|
|
327
327
|
// ── Icon-mode hover-expand ──────────────────────────────────────
|
|
@@ -1083,7 +1083,7 @@
|
|
|
1083
1083
|
data-sbm-popout=""
|
|
1084
1084
|
data-open={isOpen}
|
|
1085
1085
|
style="width: max-content;{expandedWidth != null ? ` max-width: ${expandedWidth}px;` : ''} max-height: {maxHeight}; --sbm-accent: {accentVar}; --sbm-lbl: inline; --sbm-affix: inline-flex;{bd.nudge ? ` transform: translateY(${bd.nudge}px);` : ''}"
|
|
1086
|
-
class="overflow-hidden shadow-lg [background-color:var(--ui-color-background)] [color:var(--ui-color-text)] [border-color:color-mix(in_srgb,var(--ui-color-
|
|
1086
|
+
class="overflow-hidden shadow-lg [background-color:var(--ui-color-background)] [color:var(--ui-color-text)] [border-color:color-mix(in_srgb,var(--ui-color-neutral)_var(--ui-tint-border),transparent)] {bd.cls}"
|
|
1087
1087
|
onmouseenter={popoutOnHover ? cancelClose : undefined}
|
|
1088
1088
|
onmouseleave={popoutOnHover ? scheduleClose : undefined}
|
|
1089
1089
|
onwheel={item.popout
|
|
@@ -1136,7 +1136,7 @@
|
|
|
1136
1136
|
data-sbm-burger={uid}
|
|
1137
1137
|
class="fixed top-3 {dockRight
|
|
1138
1138
|
? 'right-3'
|
|
1139
|
-
: 'left-3'} z-[80] w-10 h-10 items-center justify-center cursor-pointer [background-color:var(--ui-color-background)] border [border-color:color-mix(in_srgb,var(--ui-color-
|
|
1139
|
+
: 'left-3'} z-[80] w-10 h-10 items-center justify-center cursor-pointer [background-color:var(--ui-color-background)] border [border-color:color-mix(in_srgb,var(--ui-color-neutral)_var(--ui-tint-border),transparent)] shadow-md [&_svg]:w-5 [&_svg]:h-5"
|
|
1140
1140
|
aria-label={open ? "Close menu" : "Open menu"}
|
|
1141
1141
|
aria-expanded={open}
|
|
1142
1142
|
onclick={() => (open = !open)}
|
|
@@ -124,7 +124,7 @@
|
|
|
124
124
|
|
|
125
125
|
<Popup anchor={anchorEl} bind:open offset={6}>
|
|
126
126
|
<div
|
|
127
|
-
class="rounded-[var(--ui-border-radius)] border {pad} shadow-lg [border-color:color-mix(in_srgb,var(--ui-color-
|
|
127
|
+
class="rounded-[var(--ui-border-radius)] border {pad} shadow-lg [border-color:color-mix(in_srgb,var(--ui-color-neutral)_var(--ui-tint-border),transparent)] [background-color:var(--ui-color-background)] [color:var(--ui-color-text)]"
|
|
128
128
|
style="--accent: {accent}"
|
|
129
129
|
>
|
|
130
130
|
<div class="grid place-items-center py-1">
|
|
@@ -149,7 +149,7 @@
|
|
|
149
149
|
|
|
150
150
|
<Popup anchor={anchorEl} bind:open offset={6}>
|
|
151
151
|
<div
|
|
152
|
-
class="rounded-[var(--ui-border-radius)] border {pad} shadow-lg [border-color:color-mix(in_srgb,var(--ui-color-
|
|
152
|
+
class="rounded-[var(--ui-border-radius)] border {pad} shadow-lg [border-color:color-mix(in_srgb,var(--ui-color-neutral)_var(--ui-tint-border),transparent)] [background-color:var(--ui-color-background)] [color:var(--ui-color-text)]"
|
|
153
153
|
style="--accent: {accent}"
|
|
154
154
|
>
|
|
155
155
|
<div class="flex flex-col gap-2">
|
package/dist/theme.css
CHANGED
|
@@ -67,10 +67,11 @@
|
|
|
67
67
|
* Fixed, NOT scaled by `size`, so different-size controls share a
|
|
68
68
|
* corner. (Pills like Toggle/Badge use rounded-full; the tiny
|
|
69
69
|
* Checkbox box keeps its own small radius — not worth a token.)
|
|
70
|
-
* --ui-border-color soft internal divider (row separators, section splits) —
|
|
71
|
-
*
|
|
70
|
+
* --ui-border-color soft internal divider (row separators, section splits) — the
|
|
71
|
+
* NEUTRAL divider (`--ui-color-neutral` @ `--ui-tint-divider`).
|
|
72
|
+
* Defined in the token scopes below (not here) so it re-resolves per
|
|
73
|
+
* theme and isn't tree-shaken out of @theme. */
|
|
72
74
|
--ui-border-radius: 0.375rem;
|
|
73
|
-
--ui-border-color: color-mix(in srgb, var(--ui-color-secondary) var(--ui-tint-divider), transparent);
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
/* One interactive-surface language, library-wide. A subtle tint of the ACCENT colour, so it lightens on
|
|
@@ -98,6 +99,14 @@
|
|
|
98
99
|
:root {
|
|
99
100
|
/* light default — no theme class + light system */
|
|
100
101
|
--ui-accent: var(--ui-color-text);
|
|
102
|
+
/* Neutral = the undefined-variant / monochrome default colour. Defaults to the TEXT colour (so it
|
|
103
|
+
* flips opposite --ui-color-background per theme — dark text on light, light text on dark — and a
|
|
104
|
+
* border mixed toward `transparent` always reads against the background). Independently themeable:
|
|
105
|
+
* override --ui-color-neutral to recolour EVERY neutral border/divider (and the `neutral` variant)
|
|
106
|
+
* without touching body text or the accent colours. Repeated per theme scope (like --ui-accent) so
|
|
107
|
+
* it re-resolves per theme and survives Tailwind's @theme tree-shaking. */
|
|
108
|
+
--ui-color-neutral: var(--ui-color-text);
|
|
109
|
+
--ui-border-color: color-mix(in srgb, var(--ui-color-neutral) var(--ui-tint-divider), transparent);
|
|
101
110
|
--ui-color-hover: color-mix(in srgb, var(--ui-accent) 4%, transparent);
|
|
102
111
|
--ui-color-surface: color-mix(in srgb, var(--ui-accent) 8%, transparent);
|
|
103
112
|
--ui-color-active: color-mix(in srgb, var(--ui-accent) 12%, transparent);
|
|
@@ -151,6 +160,8 @@ body {
|
|
|
151
160
|
--ui-color-error: #ef4444;
|
|
152
161
|
--ui-color-info: #06b6d4;
|
|
153
162
|
--ui-accent: var(--ui-color-text);
|
|
163
|
+
--ui-color-neutral: var(--ui-color-text);
|
|
164
|
+
--ui-border-color: color-mix(in srgb, var(--ui-color-neutral) var(--ui-tint-divider), transparent);
|
|
154
165
|
--ui-color-hover: color-mix(in srgb, var(--ui-accent) 4%, transparent);
|
|
155
166
|
--ui-color-surface: color-mix(in srgb, var(--ui-accent) 8%, transparent);
|
|
156
167
|
--ui-color-active: color-mix(in srgb, var(--ui-accent) 12%, transparent);
|
|
@@ -169,6 +180,8 @@ body {
|
|
|
169
180
|
--ui-color-info: #0ea5e9;
|
|
170
181
|
/* forced light must re-assert the tint (overrides the dark @media above) */
|
|
171
182
|
--ui-accent: var(--ui-color-text);
|
|
183
|
+
--ui-color-neutral: var(--ui-color-text);
|
|
184
|
+
--ui-border-color: color-mix(in srgb, var(--ui-color-neutral) var(--ui-tint-divider), transparent);
|
|
172
185
|
--ui-color-hover: color-mix(in srgb, var(--ui-accent) 4%, transparent);
|
|
173
186
|
--ui-color-surface: color-mix(in srgb, var(--ui-accent) 8%, transparent);
|
|
174
187
|
--ui-color-active: color-mix(in srgb, var(--ui-accent) 12%, transparent);
|
|
@@ -185,6 +198,8 @@ body {
|
|
|
185
198
|
--ui-color-error: #ef4444;
|
|
186
199
|
--ui-color-info: #06b6d4;
|
|
187
200
|
--ui-accent: var(--ui-color-text);
|
|
201
|
+
--ui-color-neutral: var(--ui-color-text);
|
|
202
|
+
--ui-border-color: color-mix(in srgb, var(--ui-color-neutral) var(--ui-tint-divider), transparent);
|
|
188
203
|
--ui-color-hover: color-mix(in srgb, var(--ui-accent) 4%, transparent);
|
|
189
204
|
--ui-color-surface: color-mix(in srgb, var(--ui-accent) 8%, transparent);
|
|
190
205
|
--ui-color-active: color-mix(in srgb, var(--ui-accent) 12%, transparent);
|
package/dist/types/variants.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export type Variant = "neutral" | "primary" | "secondary" | "success" | "info" | "warning" | "danger" | "ghost";
|
|
2
2
|
/** Variant → semantic colour token, used where a variant needs an ACCENT colour (Toggle track,
|
|
3
3
|
* Checkbox, Card border, DataTable accent…). `danger` maps to `--ui-color-error`. The two non-accent
|
|
4
|
-
* variants — `
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* variants — `neutral` (the undefined-variant / monochrome default) and `ghost` (transparent,
|
|
5
|
+
* hover-tint only) — resolve to `--ui-color-neutral`, which itself defaults to `--ui-color-text` but
|
|
6
|
+
* is independently themeable (see theme.css). So neutral/ghost controls read monochrome, and a theme
|
|
7
|
+
* can recolour every neutral border/surface via one token without moving body text. The interactive
|
|
8
|
+
* tints (hover/surface/active) re-mix off whichever colour this points at. */
|
|
8
9
|
export declare const variantToken: Record<Variant, string>;
|
package/dist/types/variants.js
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
/** Variant → semantic colour token, used where a variant needs an ACCENT colour (Toggle track,
|
|
2
2
|
* Checkbox, Card border, DataTable accent…). `danger` maps to `--ui-color-error`. The two non-accent
|
|
3
|
-
* variants — `
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
3
|
+
* variants — `neutral` (the undefined-variant / monochrome default) and `ghost` (transparent,
|
|
4
|
+
* hover-tint only) — resolve to `--ui-color-neutral`, which itself defaults to `--ui-color-text` but
|
|
5
|
+
* is independently themeable (see theme.css). So neutral/ghost controls read monochrome, and a theme
|
|
6
|
+
* can recolour every neutral border/surface via one token without moving body text. The interactive
|
|
7
|
+
* tints (hover/surface/active) re-mix off whichever colour this points at. */
|
|
7
8
|
export const variantToken = {
|
|
8
|
-
neutral: "--ui-color-
|
|
9
|
+
neutral: "--ui-color-neutral",
|
|
9
10
|
primary: "--ui-color-primary",
|
|
10
11
|
secondary: "--ui-color-secondary",
|
|
11
12
|
success: "--ui-color-success",
|
|
12
13
|
info: "--ui-color-info",
|
|
13
14
|
warning: "--ui-color-warning",
|
|
14
15
|
danger: "--ui-color-error",
|
|
15
|
-
ghost: "--ui-color-
|
|
16
|
+
ghost: "--ui-color-neutral",
|
|
16
17
|
};
|
package/docs/themes.md
CHANGED
|
@@ -53,12 +53,17 @@ theme-independent** (identical in light and dark) — only the accent color flip
|
|
|
53
53
|
## Border & radius — `--ui-border-*`
|
|
54
54
|
|
|
55
55
|
- `--ui-border-radius` — `0.375rem` — corner radius for every surface (Card, Input, DataTable…)
|
|
56
|
-
- `--ui-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
56
|
+
- `--ui-color-neutral` — `var(--ui-color-text)` (default) — the neutral / undefined-variant base
|
|
57
|
+
colour. **Override it to recolour every neutral border + surface at once**, independent of body text
|
|
58
|
+
and the variant colours. All neutral borders derive from this one hue.
|
|
59
|
+
- `--ui-border-color` — `color-mix(in srgb, var(--ui-color-neutral) var(--ui-tint-divider), transparent)`
|
|
60
|
+
— the soft internal **neutral divider** (row separators, section splits). One hue, two weights: a
|
|
61
|
+
**frame** border is the same `--ui-color-neutral` at `--ui-tint-border` (50%) instead of the 30%
|
|
62
|
+
divider tier. A `variant`-set border tints from that variant's token (a `secondary` Card = cyan) —
|
|
63
|
+
only the *neutral* default is monochrome.
|
|
64
|
+
- (`--ui-border-color-strong` / `-strong-hover` were **removed** — use
|
|
65
|
+
`color-mix(in srgb, var(--ui-color-neutral) var(--ui-tint-border), transparent)` for a frame edge,
|
|
66
|
+
`--ui-tint-border-hover` for its hover.)
|
|
62
67
|
|
|
63
68
|
## Sizing — the `size` axis (`sm` / `md` / `lg`)
|
|
64
69
|
|
|
@@ -126,9 +131,9 @@ Components reference these via Tailwind's arbitrary-value syntax:
|
|
|
126
131
|
<!-- Text / background -->
|
|
127
132
|
<div class="text-[var(--ui-color-text)] bg-[var(--ui-color-background)]">...</div>
|
|
128
133
|
|
|
129
|
-
<!-- Border (
|
|
134
|
+
<!-- Border (a neutral frame edge — the 50% tier — + radius) -->
|
|
130
135
|
<div
|
|
131
|
-
class="border [border-color:var(--ui-
|
|
136
|
+
class="border [border-color:color-mix(in_srgb,var(--ui-color-neutral)_var(--ui-tint-border),transparent)] [border-radius:var(--ui-border-radius)]"
|
|
132
137
|
>
|
|
133
138
|
...
|
|
134
139
|
</div>
|