bref-ui 0.0.4 → 0.0.5
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/dist/base/button/README.md +160 -0
- package/dist/base/button/button.svelte +133 -236
- package/dist/base/button/icon-button.svelte +128 -236
- package/dist/base/theme/theme.svelte +0 -3
- package/dist/internal/demo-theming.svelte +17 -101
- package/package.json +1 -1
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# Button Component Styling Patterns
|
|
2
|
+
|
|
3
|
+
This document describes the CSS architecture and patterns used in the Button component.
|
|
4
|
+
|
|
5
|
+
## CSS Variable Naming Convention
|
|
6
|
+
|
|
7
|
+
### Internal vs External Variables
|
|
8
|
+
|
|
9
|
+
| Prefix | Meaning | Example |
|
|
10
|
+
|--------|---------|---------|
|
|
11
|
+
| `--color-*`, `--spacing`, `--border-radius` | **External/Theme tokens** – global design system variables | `--color-primary`, `--spacing` |
|
|
12
|
+
| `--internal-*` | **Internal/Private** – component-scoped variables, implementation details | `--internal-btn-hover-mix` |
|
|
13
|
+
|
|
14
|
+
The `--internal-` prefix signals that these variables are not part of the public API and should not be overridden by consumers.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Pattern 1: Centralized Interaction Variables
|
|
19
|
+
|
|
20
|
+
All magic numbers for interactions are defined once in the base `button` selector:
|
|
21
|
+
|
|
22
|
+
```css
|
|
23
|
+
button {
|
|
24
|
+
--internal-btn-transition-bg: 0.15s;
|
|
25
|
+
--internal-btn-transition-transform: 0.08s;
|
|
26
|
+
--internal-btn-scale-active: 0.98;
|
|
27
|
+
--internal-btn-disabled-opacity: 0.5;
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Benefits:**
|
|
32
|
+
- Single source of truth for timing/effects
|
|
33
|
+
- Easy to tweak all hover/active states at once
|
|
34
|
+
- Self-documenting variable names
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Pattern 2: Color Mix Percentages as Variables
|
|
39
|
+
|
|
40
|
+
Instead of hardcoding percentages in `color-mix()`, they're stored as variables:
|
|
41
|
+
|
|
42
|
+
```css
|
|
43
|
+
button {
|
|
44
|
+
--internal-btn-hover-mix: 85%;
|
|
45
|
+
--internal-btn-active-mix: 70%;
|
|
46
|
+
--internal-btn-ghost-hover-opacity: 10%;
|
|
47
|
+
--internal-btn-ghost-active-opacity: 25%;
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Usage:**
|
|
52
|
+
```css
|
|
53
|
+
.filled:not(:disabled):hover {
|
|
54
|
+
background-color: color-mix(in oklch, var(--internal-current-color) var(--internal-btn-hover-mix), black);
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Pattern 3: Size Variants via Variable Overrides
|
|
61
|
+
|
|
62
|
+
Instead of repeating `padding`, `font-size`, `border-radius` in each size class, we override internal variables:
|
|
63
|
+
|
|
64
|
+
```css
|
|
65
|
+
/* Defaults set in button {} */
|
|
66
|
+
--internal-btn-padding-y: calc(var(--spacing) * 0.5);
|
|
67
|
+
--internal-btn-padding-x: calc(var(--spacing) * 1);
|
|
68
|
+
--internal-btn-font-size: 1rem;
|
|
69
|
+
--internal-btn-radius: calc(var(--border-radius) * 1.25);
|
|
70
|
+
|
|
71
|
+
/* Size classes only override the variables */
|
|
72
|
+
.x-small {
|
|
73
|
+
--internal-btn-padding-y: calc(var(--spacing) * 0.25);
|
|
74
|
+
--internal-btn-padding-x: calc(var(--spacing) * 0.5);
|
|
75
|
+
--internal-btn-font-size: 0.75rem;
|
|
76
|
+
--internal-btn-radius: calc(var(--border-radius) * 0.75);
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The actual properties are applied once in the base selector:
|
|
81
|
+
```css
|
|
82
|
+
button {
|
|
83
|
+
padding: var(--internal-btn-padding-y) var(--internal-btn-padding-x);
|
|
84
|
+
font-size: var(--internal-btn-font-size);
|
|
85
|
+
border-radius: var(--internal-btn-radius);
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Pattern 4: Dynamic Color Mapping
|
|
92
|
+
|
|
93
|
+
Color classes map theme tokens to "current" internal variables:
|
|
94
|
+
|
|
95
|
+
```css
|
|
96
|
+
.primary {
|
|
97
|
+
--internal-current-color: var(--color-primary);
|
|
98
|
+
--internal-current-color-soft: var(--color-primary-soft);
|
|
99
|
+
--internal-current-contrast: var(--color-primary-contrast);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.danger {
|
|
103
|
+
--internal-current-color: var(--color-danger);
|
|
104
|
+
--internal-current-color-soft: var(--color-danger-soft);
|
|
105
|
+
--internal-current-contrast: var(--color-danger-contrast);
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Variants then use these generic variables:
|
|
110
|
+
|
|
111
|
+
```css
|
|
112
|
+
.filled {
|
|
113
|
+
background-color: var(--internal-current-color);
|
|
114
|
+
color: var(--internal-current-contrast);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.soft {
|
|
118
|
+
background-color: var(--internal-current-color-soft);
|
|
119
|
+
color: var(--internal-current-color);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.ghost {
|
|
123
|
+
background-color: transparent;
|
|
124
|
+
color: var(--internal-current-color);
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**Benefits:**
|
|
129
|
+
- Adding a new color = 1 small block (3 lines)
|
|
130
|
+
- Variants are color-agnostic (DRY)
|
|
131
|
+
- ~270 lines → ~180 lines
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Pattern 5: Consistent Color Spaces
|
|
136
|
+
|
|
137
|
+
| Variant | Color Space | Reason |
|
|
138
|
+
|---------|-------------|--------|
|
|
139
|
+
| `filled`, `soft` | `oklch` | Perceptually uniform darkening with black |
|
|
140
|
+
| `ghost` | `srgb` | Mixing with `transparent` works better in srgb |
|
|
141
|
+
|
|
142
|
+
```css
|
|
143
|
+
/* Filled/Soft: darken with black */
|
|
144
|
+
color-mix(in oklch, var(--internal-current-color) 85%, black)
|
|
145
|
+
|
|
146
|
+
/* Ghost: fade to transparent */
|
|
147
|
+
color-mix(in srgb, var(--internal-current-color-soft) 10%, transparent)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## Summary
|
|
153
|
+
|
|
154
|
+
| Pattern | What It Solves |
|
|
155
|
+
|---------|----------------|
|
|
156
|
+
| Internal prefix (`--internal-*`) | Signals private implementation details |
|
|
157
|
+
| Centralized interaction vars | No scattered magic numbers |
|
|
158
|
+
| Color mix percentages as vars | Adjust hover/active intensity in one place |
|
|
159
|
+
| Size via variable overrides | Sizes don't repeat property declarations |
|
|
160
|
+
| Dynamic color mapping | Variants are color-agnostic; adding colors is trivial |
|
|
@@ -32,6 +32,24 @@
|
|
|
32
32
|
|
|
33
33
|
<style>
|
|
34
34
|
button {
|
|
35
|
+
/* Button interaction variables */
|
|
36
|
+
--internal-btn-transition-bg: 0.15s;
|
|
37
|
+
--internal-btn-transition-transform: 0.08s;
|
|
38
|
+
--internal-btn-scale-active: 0.98;
|
|
39
|
+
--internal-btn-disabled-opacity: 0.5;
|
|
40
|
+
|
|
41
|
+
/* Color mix percentages */
|
|
42
|
+
--internal-btn-hover-mix: 85%;
|
|
43
|
+
--internal-btn-active-mix: 70%;
|
|
44
|
+
--internal-btn-ghost-hover-opacity: 10%;
|
|
45
|
+
--internal-btn-ghost-active-opacity: 25%;
|
|
46
|
+
|
|
47
|
+
/* Size defaults (medium) */
|
|
48
|
+
--internal-btn-padding-y: calc(var(--spacing) * 0.5);
|
|
49
|
+
--internal-btn-padding-x: calc(var(--spacing) * 1);
|
|
50
|
+
--internal-btn-font-size: 1rem;
|
|
51
|
+
--internal-btn-radius: calc(var(--border-radius) * 1.25);
|
|
52
|
+
|
|
35
53
|
display: inline-flex;
|
|
36
54
|
align-items: center;
|
|
37
55
|
justify-content: center;
|
|
@@ -39,10 +57,14 @@
|
|
|
39
57
|
border: none;
|
|
40
58
|
cursor: pointer;
|
|
41
59
|
font-weight: 500;
|
|
60
|
+
padding: var(--internal-btn-padding-y) var(--internal-btn-padding-x);
|
|
61
|
+
font-size: var(--internal-btn-font-size);
|
|
62
|
+
border-radius: var(--internal-btn-radius);
|
|
42
63
|
transition:
|
|
43
|
-
background-color
|
|
44
|
-
transform
|
|
64
|
+
background-color var(--internal-btn-transition-bg) ease,
|
|
65
|
+
transform var(--internal-btn-transition-transform) cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
45
66
|
}
|
|
67
|
+
|
|
46
68
|
span {
|
|
47
69
|
cursor: inherit;
|
|
48
70
|
color: inherit;
|
|
@@ -50,12 +72,12 @@
|
|
|
50
72
|
}
|
|
51
73
|
|
|
52
74
|
button:disabled {
|
|
53
|
-
opacity:
|
|
75
|
+
opacity: var(--internal-btn-disabled-opacity);
|
|
54
76
|
cursor: not-allowed;
|
|
55
77
|
}
|
|
56
78
|
|
|
57
79
|
button:not(:disabled):active {
|
|
58
|
-
transform: scale(
|
|
80
|
+
transform: scale(var(--internal-btn-scale-active));
|
|
59
81
|
}
|
|
60
82
|
|
|
61
83
|
.wide {
|
|
@@ -64,269 +86,144 @@
|
|
|
64
86
|
|
|
65
87
|
/* Sizes */
|
|
66
88
|
.x-small {
|
|
67
|
-
padding:
|
|
68
|
-
|
|
69
|
-
|
|
89
|
+
--internal-btn-padding-y: calc(var(--spacing) * 0.25);
|
|
90
|
+
--internal-btn-padding-x: calc(var(--spacing) * 0.5);
|
|
91
|
+
--internal-btn-font-size: 0.75rem;
|
|
92
|
+
--internal-btn-radius: calc(var(--border-radius) * 0.75);
|
|
70
93
|
}
|
|
94
|
+
|
|
71
95
|
.small {
|
|
72
|
-
padding:
|
|
73
|
-
|
|
74
|
-
|
|
96
|
+
--internal-btn-padding-y: calc(var(--spacing) * 0.375);
|
|
97
|
+
--internal-btn-padding-x: calc(var(--spacing) * 0.75);
|
|
98
|
+
--internal-btn-font-size: 0.875rem;
|
|
99
|
+
--internal-btn-radius: var(--border-radius);
|
|
75
100
|
}
|
|
101
|
+
|
|
76
102
|
.medium {
|
|
77
|
-
padding: 0.
|
|
78
|
-
|
|
79
|
-
|
|
103
|
+
--internal-btn-padding-y: calc(var(--spacing) * 0.5);
|
|
104
|
+
--internal-btn-padding-x: calc(var(--spacing) * 1);
|
|
105
|
+
--internal-btn-font-size: 1rem;
|
|
106
|
+
--internal-btn-radius: calc(var(--border-radius) * 1.25);
|
|
80
107
|
}
|
|
108
|
+
|
|
81
109
|
.large {
|
|
82
|
-
padding: 0.
|
|
83
|
-
|
|
84
|
-
|
|
110
|
+
--internal-btn-padding-y: calc(var(--spacing) * 0.625);
|
|
111
|
+
--internal-btn-padding-x: calc(var(--spacing) * 1.25);
|
|
112
|
+
--internal-btn-font-size: 1.125rem;
|
|
113
|
+
--internal-btn-radius: calc(var(--border-radius) * 1.5);
|
|
85
114
|
}
|
|
115
|
+
|
|
86
116
|
.x-large {
|
|
87
|
-
padding: 0.
|
|
88
|
-
|
|
89
|
-
|
|
117
|
+
--internal-btn-padding-y: calc(var(--spacing) * 0.75);
|
|
118
|
+
--internal-btn-padding-x: calc(var(--spacing) * 1.5);
|
|
119
|
+
--internal-btn-font-size: 1.25rem;
|
|
120
|
+
--internal-btn-radius: calc(var(--border-radius) * 2);
|
|
90
121
|
}
|
|
91
122
|
|
|
92
|
-
/*
|
|
93
|
-
.
|
|
94
|
-
|
|
95
|
-
color: var(--color-primary-
|
|
96
|
-
|
|
97
|
-
.filled.primary:not(:disabled):hover {
|
|
98
|
-
background-color: color-mix(in oklch, var(--color-primary) 85%, var(--hover-mix));
|
|
99
|
-
}
|
|
100
|
-
.filled.primary:not(:disabled):active {
|
|
101
|
-
background-color: color-mix(in oklch, var(--color-primary) 70%, var(--hover-mix));
|
|
102
|
-
}
|
|
103
|
-
.filled.secondary {
|
|
104
|
-
background-color: var(--color-secondary);
|
|
105
|
-
color: var(--color-secondary-contrast);
|
|
106
|
-
}
|
|
107
|
-
.filled.secondary:not(:disabled):hover {
|
|
108
|
-
background-color: color-mix(in oklch, var(--color-secondary) 85%, var(--hover-mix));
|
|
109
|
-
}
|
|
110
|
-
.filled.secondary:not(:disabled):active {
|
|
111
|
-
background-color: color-mix(in oklch, var(--color-secondary) 70%, var(--hover-mix));
|
|
112
|
-
}
|
|
113
|
-
.filled.success {
|
|
114
|
-
background-color: var(--color-success);
|
|
115
|
-
color: var(--color-success-contrast);
|
|
116
|
-
}
|
|
117
|
-
.filled.success:not(:disabled):hover {
|
|
118
|
-
background-color: color-mix(in oklch, var(--color-success) 85%, var(--hover-mix));
|
|
119
|
-
}
|
|
120
|
-
.filled.success:not(:disabled):active {
|
|
121
|
-
background-color: color-mix(in oklch, var(--color-success) 70%, var(--hover-mix));
|
|
122
|
-
}
|
|
123
|
-
.filled.warning {
|
|
124
|
-
background-color: var(--color-warning);
|
|
125
|
-
color: var(--color-warning-contrast);
|
|
126
|
-
}
|
|
127
|
-
.filled.warning:not(:disabled):hover {
|
|
128
|
-
background-color: color-mix(in oklch, var(--color-warning) 85%, var(--hover-mix));
|
|
129
|
-
}
|
|
130
|
-
.filled.warning:not(:disabled):active {
|
|
131
|
-
background-color: color-mix(in oklch, var(--color-warning) 70%, var(--hover-mix));
|
|
123
|
+
/* Color mappings - set current color variables per color class */
|
|
124
|
+
.primary {
|
|
125
|
+
--internal-current-color: var(--color-primary);
|
|
126
|
+
--internal-current-color-soft: var(--color-primary-soft);
|
|
127
|
+
--internal-current-contrast: var(--color-primary-contrast);
|
|
132
128
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
color: var(--color-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
background-color: color-mix(in oklch, var(--color-danger) 85%, var(--hover-mix));
|
|
139
|
-
}
|
|
140
|
-
.filled.danger:not(:disabled):active {
|
|
141
|
-
background-color: color-mix(in oklch, var(--color-danger) 70%, var(--hover-mix));
|
|
129
|
+
|
|
130
|
+
.secondary {
|
|
131
|
+
--internal-current-color: var(--color-secondary);
|
|
132
|
+
--internal-current-color-soft: var(--color-secondary-soft);
|
|
133
|
+
--internal-current-contrast: var(--color-secondary-contrast);
|
|
142
134
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
color: var(--color-
|
|
135
|
+
|
|
136
|
+
.success {
|
|
137
|
+
--internal-current-color: var(--color-success);
|
|
138
|
+
--internal-current-color-soft: var(--color-success-soft);
|
|
139
|
+
--internal-current-contrast: var(--color-success-contrast);
|
|
146
140
|
}
|
|
147
|
-
|
|
148
|
-
|
|
141
|
+
|
|
142
|
+
.warning {
|
|
143
|
+
--internal-current-color: var(--color-warning);
|
|
144
|
+
--internal-current-color-soft: var(--color-warning-soft);
|
|
145
|
+
--internal-current-contrast: var(--color-warning-contrast);
|
|
149
146
|
}
|
|
150
|
-
|
|
151
|
-
|
|
147
|
+
|
|
148
|
+
.danger {
|
|
149
|
+
--internal-current-color: var(--color-danger);
|
|
150
|
+
--internal-current-color-soft: var(--color-danger-soft);
|
|
151
|
+
--internal-current-contrast: var(--color-danger-contrast);
|
|
152
152
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
color: var(--color-
|
|
153
|
+
|
|
154
|
+
.info {
|
|
155
|
+
--internal-current-color: var(--color-info);
|
|
156
|
+
--internal-current-color-soft: var(--color-info-soft);
|
|
157
|
+
--internal-current-contrast: var(--color-info-contrast);
|
|
156
158
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
+
|
|
160
|
+
.foreground {
|
|
161
|
+
--internal-current-color: var(--color-foreground);
|
|
162
|
+
--internal-current-color-soft: var(--color-foreground-soft);
|
|
163
|
+
--internal-current-contrast: var(--color-background);
|
|
159
164
|
}
|
|
160
|
-
|
|
161
|
-
|
|
165
|
+
|
|
166
|
+
.background {
|
|
167
|
+
--internal-current-color: var(--color-background);
|
|
168
|
+
--internal-current-color-soft: var(--color-background-soft);
|
|
169
|
+
--internal-current-contrast: var(--color-foreground);
|
|
162
170
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
171
|
+
|
|
172
|
+
/* Filled variant */
|
|
173
|
+
.filled {
|
|
174
|
+
background-color: var(--internal-current-color);
|
|
175
|
+
color: var(--internal-current-contrast);
|
|
166
176
|
}
|
|
167
|
-
|
|
168
|
-
|
|
177
|
+
|
|
178
|
+
.filled:not(:disabled):hover {
|
|
179
|
+
background-color: color-mix(in oklch, var(--internal-current-color) var(--internal-btn-hover-mix), black);
|
|
169
180
|
}
|
|
170
|
-
|
|
171
|
-
|
|
181
|
+
|
|
182
|
+
.filled:not(:disabled):active {
|
|
183
|
+
background-color: color-mix(in oklch, var(--internal-current-color) var(--internal-btn-active-mix), black);
|
|
172
184
|
}
|
|
173
185
|
|
|
174
186
|
/* Soft variant */
|
|
175
|
-
.soft
|
|
176
|
-
background-color: var(--color-
|
|
177
|
-
color: var(--color
|
|
178
|
-
}
|
|
179
|
-
.soft.primary:not(:disabled):hover {
|
|
180
|
-
background-color: color-mix(in oklch, var(--color-primary-soft) 85%, var(--hover-mix));
|
|
181
|
-
}
|
|
182
|
-
.soft.primary:not(:disabled):active {
|
|
183
|
-
background-color: color-mix(in oklch, var(--color-primary-soft) 70%, var(--hover-mix));
|
|
184
|
-
}
|
|
185
|
-
.soft.secondary {
|
|
186
|
-
background-color: var(--color-secondary-soft);
|
|
187
|
-
color: var(--color-secondary);
|
|
188
|
-
}
|
|
189
|
-
.soft.secondary:not(:disabled):hover {
|
|
190
|
-
background-color: color-mix(in oklch, var(--color-secondary-soft) 85%, var(--hover-mix));
|
|
191
|
-
}
|
|
192
|
-
.soft.secondary:not(:disabled):active {
|
|
193
|
-
background-color: color-mix(in oklch, var(--color-secondary-soft) 70%, var(--hover-mix));
|
|
194
|
-
}
|
|
195
|
-
.soft.success {
|
|
196
|
-
background-color: var(--color-success-soft);
|
|
197
|
-
color: var(--color-success);
|
|
198
|
-
}
|
|
199
|
-
.soft.success:not(:disabled):hover {
|
|
200
|
-
background-color: color-mix(in oklch, var(--color-success-soft) 85%, var(--hover-mix));
|
|
187
|
+
.soft {
|
|
188
|
+
background-color: var(--internal-current-color-soft);
|
|
189
|
+
color: var(--internal-current-color);
|
|
201
190
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
.soft.warning:not(:disabled):hover {
|
|
210
|
-
background-color: color-mix(in oklch, var(--color-warning-soft) 85%, var(--hover-mix));
|
|
211
|
-
}
|
|
212
|
-
.soft.warning:not(:disabled):active {
|
|
213
|
-
background-color: color-mix(in oklch, var(--color-warning-soft) 70%, var(--hover-mix));
|
|
214
|
-
}
|
|
215
|
-
.soft.danger {
|
|
216
|
-
background-color: var(--color-danger-soft);
|
|
217
|
-
color: var(--color-danger);
|
|
218
|
-
}
|
|
219
|
-
.soft.danger:not(:disabled):hover {
|
|
220
|
-
background-color: color-mix(in oklch, var(--color-danger-soft) 85%, var(--hover-mix));
|
|
221
|
-
}
|
|
222
|
-
.soft.danger:not(:disabled):active {
|
|
223
|
-
background-color: color-mix(in oklch, var(--color-danger-soft) 70%, var(--hover-mix));
|
|
224
|
-
}
|
|
225
|
-
.soft.info {
|
|
226
|
-
background-color: var(--color-info-soft);
|
|
227
|
-
color: var(--color-info);
|
|
228
|
-
}
|
|
229
|
-
.soft.info:not(:disabled):hover {
|
|
230
|
-
background-color: color-mix(in oklch, var(--color-info-soft) 85%, var(--hover-mix));
|
|
231
|
-
}
|
|
232
|
-
.soft.info:not(:disabled):active {
|
|
233
|
-
background-color: color-mix(in oklch, var(--color-info-soft) 70%, var(--hover-mix));
|
|
234
|
-
}
|
|
235
|
-
.soft.foreground {
|
|
236
|
-
background-color: var(--color-foreground-soft);
|
|
237
|
-
color: var(--color-foreground);
|
|
238
|
-
}
|
|
239
|
-
.soft.foreground:not(:disabled):hover {
|
|
240
|
-
background-color: color-mix(in oklch, var(--color-foreground-soft) 85%, var(--hover-mix));
|
|
241
|
-
}
|
|
242
|
-
.soft.foreground:not(:disabled):active {
|
|
243
|
-
background-color: color-mix(in oklch, var(--color-foreground-soft) 70%, var(--hover-mix));
|
|
244
|
-
}
|
|
245
|
-
.soft.background {
|
|
246
|
-
background-color: var(--color-background-soft);
|
|
247
|
-
color: var(--color-background);
|
|
248
|
-
}
|
|
249
|
-
.soft.background:not(:disabled):hover {
|
|
250
|
-
background-color: color-mix(in oklch, var(--color-background-soft) 85%, var(--hover-mix));
|
|
191
|
+
|
|
192
|
+
.soft:not(:disabled):hover {
|
|
193
|
+
background-color: color-mix(
|
|
194
|
+
in oklch,
|
|
195
|
+
var(--internal-current-color-soft) var(--internal-btn-hover-mix),
|
|
196
|
+
var(--internal-current-color)
|
|
197
|
+
);
|
|
251
198
|
}
|
|
252
|
-
|
|
253
|
-
|
|
199
|
+
|
|
200
|
+
.soft:not(:disabled):active {
|
|
201
|
+
background-color: color-mix(
|
|
202
|
+
in oklch,
|
|
203
|
+
var(--internal-current-color-soft) var(--internal-btn-active-mix),
|
|
204
|
+
var(--internal-current-color)
|
|
205
|
+
);
|
|
254
206
|
}
|
|
255
207
|
|
|
256
208
|
/* Ghost variant */
|
|
257
209
|
.ghost {
|
|
258
210
|
background-color: transparent;
|
|
211
|
+
color: var(--internal-current-color);
|
|
259
212
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
background-color: var(--color-primary-soft);
|
|
268
|
-
}
|
|
269
|
-
.ghost.secondary {
|
|
270
|
-
color: var(--color-secondary);
|
|
271
|
-
}
|
|
272
|
-
.ghost.secondary:not(:disabled):hover {
|
|
273
|
-
background-color: color-mix(in srgb, var(--color-secondary-soft) 50%, transparent);
|
|
274
|
-
}
|
|
275
|
-
.ghost.secondary:not(:disabled):active {
|
|
276
|
-
background-color: var(--color-secondary-soft);
|
|
277
|
-
}
|
|
278
|
-
.ghost.success {
|
|
279
|
-
color: var(--color-success);
|
|
280
|
-
}
|
|
281
|
-
.ghost.success:not(:disabled):hover {
|
|
282
|
-
background-color: color-mix(in srgb, var(--color-success-soft) 50%, transparent);
|
|
283
|
-
}
|
|
284
|
-
.ghost.success:not(:disabled):active {
|
|
285
|
-
background-color: var(--color-success-soft);
|
|
286
|
-
}
|
|
287
|
-
.ghost.warning {
|
|
288
|
-
color: var(--color-warning);
|
|
289
|
-
}
|
|
290
|
-
.ghost.warning:not(:disabled):hover {
|
|
291
|
-
background-color: color-mix(in srgb, var(--color-warning-soft) 50%, transparent);
|
|
292
|
-
}
|
|
293
|
-
.ghost.warning:not(:disabled):active {
|
|
294
|
-
background-color: var(--color-warning-soft);
|
|
295
|
-
}
|
|
296
|
-
.ghost.danger {
|
|
297
|
-
color: var(--color-danger);
|
|
298
|
-
}
|
|
299
|
-
.ghost.danger:not(:disabled):hover {
|
|
300
|
-
background-color: color-mix(in srgb, var(--color-danger-soft) 50%, transparent);
|
|
301
|
-
}
|
|
302
|
-
.ghost.danger:not(:disabled):active {
|
|
303
|
-
background-color: var(--color-danger-soft);
|
|
304
|
-
}
|
|
305
|
-
.ghost.info {
|
|
306
|
-
color: var(--color-info);
|
|
307
|
-
}
|
|
308
|
-
.ghost.info:not(:disabled):hover {
|
|
309
|
-
background-color: color-mix(in srgb, var(--color-info-soft) 50%, transparent);
|
|
310
|
-
}
|
|
311
|
-
.ghost.info:not(:disabled):active {
|
|
312
|
-
background-color: var(--color-info-soft);
|
|
313
|
-
}
|
|
314
|
-
.ghost.foreground {
|
|
315
|
-
color: var(--color-foreground);
|
|
316
|
-
}
|
|
317
|
-
.ghost.foreground:not(:disabled):hover {
|
|
318
|
-
background-color: color-mix(in srgb, var(--color-foreground-soft) 50%, transparent);
|
|
319
|
-
}
|
|
320
|
-
.ghost.foreground:not(:disabled):active {
|
|
321
|
-
background-color: var(--color-foreground-soft);
|
|
322
|
-
}
|
|
323
|
-
.ghost.background {
|
|
324
|
-
color: var(--color-background);
|
|
325
|
-
}
|
|
326
|
-
.ghost.background:not(:disabled):hover {
|
|
327
|
-
background-color: color-mix(in srgb, var(--color-background-soft) 50%, transparent);
|
|
213
|
+
|
|
214
|
+
.ghost:not(:disabled):hover {
|
|
215
|
+
background-color: color-mix(
|
|
216
|
+
in srgb,
|
|
217
|
+
var(--internal-current-color) var(--internal-btn-ghost-hover-opacity),
|
|
218
|
+
var(--color-background)
|
|
219
|
+
);
|
|
328
220
|
}
|
|
329
|
-
|
|
330
|
-
|
|
221
|
+
|
|
222
|
+
.ghost:not(:disabled):active {
|
|
223
|
+
background-color: color-mix(
|
|
224
|
+
in srgb,
|
|
225
|
+
var(--internal-current-color) var(--internal-btn-ghost-active-opacity),
|
|
226
|
+
var(--color-background)
|
|
227
|
+
);
|
|
331
228
|
}
|
|
332
229
|
</style>
|
|
@@ -23,294 +23,186 @@
|
|
|
23
23
|
|
|
24
24
|
<style>
|
|
25
25
|
button {
|
|
26
|
+
/* Button interaction variables */
|
|
27
|
+
--internal-btn-transition-bg: 0.15s;
|
|
28
|
+
--internal-btn-transition-transform: 0.08s;
|
|
29
|
+
--internal-btn-scale-active: 0.95;
|
|
30
|
+
--internal-btn-disabled-opacity: 0.5;
|
|
31
|
+
|
|
32
|
+
/* Color mix percentages */
|
|
33
|
+
--internal-btn-hover-mix: 85%;
|
|
34
|
+
--internal-btn-active-mix: 70%;
|
|
35
|
+
--internal-btn-ghost-hover-opacity: 10%;
|
|
36
|
+
--internal-btn-ghost-active-opacity: 25%;
|
|
37
|
+
|
|
38
|
+
/* Size defaults (medium) */
|
|
39
|
+
--internal-btn-size: calc(var(--spacing) * 2.5);
|
|
40
|
+
--internal-btn-radius: calc(var(--border-radius) * 1.25);
|
|
41
|
+
|
|
26
42
|
display: inline-flex;
|
|
27
43
|
align-items: center;
|
|
28
44
|
justify-content: center;
|
|
29
45
|
border: none;
|
|
30
46
|
cursor: pointer;
|
|
47
|
+
width: var(--internal-btn-size);
|
|
48
|
+
height: var(--internal-btn-size);
|
|
49
|
+
border-radius: var(--internal-btn-radius);
|
|
31
50
|
transition:
|
|
32
|
-
background-color
|
|
33
|
-
transform
|
|
51
|
+
background-color var(--internal-btn-transition-bg) ease,
|
|
52
|
+
transform var(--internal-btn-transition-transform) cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
34
53
|
}
|
|
35
54
|
|
|
36
55
|
button:disabled {
|
|
37
|
-
opacity:
|
|
56
|
+
opacity: var(--internal-btn-disabled-opacity);
|
|
38
57
|
cursor: not-allowed;
|
|
39
58
|
}
|
|
40
59
|
|
|
41
60
|
button:not(:disabled):active {
|
|
42
|
-
transform: scale(
|
|
61
|
+
transform: scale(var(--internal-btn-scale-active));
|
|
43
62
|
}
|
|
44
63
|
|
|
45
64
|
/* Sizes */
|
|
46
65
|
.x-small {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
border-radius: calc(var(--border-radius) * 0.75);
|
|
66
|
+
--internal-btn-size: calc(var(--spacing) * 1.5);
|
|
67
|
+
--internal-btn-radius: calc(var(--border-radius) * 0.75);
|
|
50
68
|
}
|
|
69
|
+
|
|
51
70
|
.small {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
border-radius: calc(var(--border-radius));
|
|
71
|
+
--internal-btn-size: calc(var(--spacing) * 2);
|
|
72
|
+
--internal-btn-radius: var(--border-radius);
|
|
55
73
|
}
|
|
74
|
+
|
|
56
75
|
.medium {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
border-radius: calc(var(--border-radius) * 1.25);
|
|
76
|
+
--internal-btn-size: calc(var(--spacing) * 2.5);
|
|
77
|
+
--internal-btn-radius: calc(var(--border-radius) * 1.25);
|
|
60
78
|
}
|
|
79
|
+
|
|
61
80
|
.large {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
border-radius: calc(var(--border-radius) * 1.5);
|
|
81
|
+
--internal-btn-size: calc(var(--spacing) * 3);
|
|
82
|
+
--internal-btn-radius: calc(var(--border-radius) * 1.5);
|
|
65
83
|
}
|
|
84
|
+
|
|
66
85
|
.x-large {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
border-radius: calc(var(--border-radius) * 2);
|
|
86
|
+
--internal-btn-size: calc(var(--spacing) * 4);
|
|
87
|
+
--internal-btn-radius: calc(var(--border-radius) * 2);
|
|
70
88
|
}
|
|
71
89
|
|
|
72
90
|
.rounded {
|
|
73
91
|
border-radius: 50%;
|
|
74
92
|
}
|
|
75
93
|
|
|
76
|
-
/*
|
|
77
|
-
.
|
|
78
|
-
|
|
79
|
-
color: var(--color-primary-
|
|
80
|
-
|
|
81
|
-
.filled.primary:not(:disabled):hover {
|
|
82
|
-
background-color: color-mix(in oklch, var(--color-primary) 85%, var(--hover-mix));
|
|
83
|
-
}
|
|
84
|
-
.filled.primary:not(:disabled):active {
|
|
85
|
-
background-color: color-mix(in oklch, var(--color-primary) 70%, var(--hover-mix));
|
|
86
|
-
}
|
|
87
|
-
.filled.secondary {
|
|
88
|
-
background-color: var(--color-secondary);
|
|
89
|
-
color: var(--color-secondary-contrast);
|
|
90
|
-
}
|
|
91
|
-
.filled.secondary:not(:disabled):hover {
|
|
92
|
-
background-color: color-mix(in oklch, var(--color-secondary) 85%, var(--hover-mix));
|
|
93
|
-
}
|
|
94
|
-
.filled.secondary:not(:disabled):active {
|
|
95
|
-
background-color: color-mix(in oklch, var(--color-secondary) 70%, var(--hover-mix));
|
|
96
|
-
}
|
|
97
|
-
.filled.success {
|
|
98
|
-
background-color: var(--color-success);
|
|
99
|
-
color: var(--color-success-contrast);
|
|
100
|
-
}
|
|
101
|
-
.filled.success:not(:disabled):hover {
|
|
102
|
-
background-color: color-mix(in oklch, var(--color-success) 85%, var(--hover-mix));
|
|
103
|
-
}
|
|
104
|
-
.filled.success:not(:disabled):active {
|
|
105
|
-
background-color: color-mix(in oklch, var(--color-success) 70%, var(--hover-mix));
|
|
106
|
-
}
|
|
107
|
-
.filled.warning {
|
|
108
|
-
background-color: var(--color-warning);
|
|
109
|
-
color: var(--color-warning-contrast);
|
|
110
|
-
}
|
|
111
|
-
.filled.warning:not(:disabled):hover {
|
|
112
|
-
background-color: color-mix(in oklch, var(--color-warning) 85%, var(--hover-mix));
|
|
113
|
-
}
|
|
114
|
-
.filled.warning:not(:disabled):active {
|
|
115
|
-
background-color: color-mix(in oklch, var(--color-warning) 70%, var(--hover-mix));
|
|
116
|
-
}
|
|
117
|
-
.filled.danger {
|
|
118
|
-
background-color: var(--color-danger);
|
|
119
|
-
color: var(--color-danger-contrast);
|
|
94
|
+
/* Color mappings - set current color variables per color class */
|
|
95
|
+
.primary {
|
|
96
|
+
--internal-current-color: var(--color-primary);
|
|
97
|
+
--internal-current-color-soft: var(--color-primary-soft);
|
|
98
|
+
--internal-current-contrast: var(--color-primary-contrast);
|
|
120
99
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
100
|
+
|
|
101
|
+
.secondary {
|
|
102
|
+
--internal-current-color: var(--color-secondary);
|
|
103
|
+
--internal-current-color-soft: var(--color-secondary-soft);
|
|
104
|
+
--internal-current-contrast: var(--color-secondary-contrast);
|
|
126
105
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
color: var(--color-
|
|
106
|
+
|
|
107
|
+
.success {
|
|
108
|
+
--internal-current-color: var(--color-success);
|
|
109
|
+
--internal-current-color-soft: var(--color-success-soft);
|
|
110
|
+
--internal-current-contrast: var(--color-success-contrast);
|
|
130
111
|
}
|
|
131
|
-
|
|
132
|
-
|
|
112
|
+
|
|
113
|
+
.warning {
|
|
114
|
+
--internal-current-color: var(--color-warning);
|
|
115
|
+
--internal-current-color-soft: var(--color-warning-soft);
|
|
116
|
+
--internal-current-contrast: var(--color-warning-contrast);
|
|
133
117
|
}
|
|
134
|
-
|
|
135
|
-
|
|
118
|
+
|
|
119
|
+
.danger {
|
|
120
|
+
--internal-current-color: var(--color-danger);
|
|
121
|
+
--internal-current-color-soft: var(--color-danger-soft);
|
|
122
|
+
--internal-current-contrast: var(--color-danger-contrast);
|
|
136
123
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
color: var(--color-
|
|
124
|
+
|
|
125
|
+
.info {
|
|
126
|
+
--internal-current-color: var(--color-info);
|
|
127
|
+
--internal-current-color-soft: var(--color-info-soft);
|
|
128
|
+
--internal-current-contrast: var(--color-info-contrast);
|
|
140
129
|
}
|
|
141
|
-
|
|
142
|
-
|
|
130
|
+
|
|
131
|
+
.foreground {
|
|
132
|
+
--internal-current-color: var(--color-foreground);
|
|
133
|
+
--internal-current-color-soft: var(--color-foreground-soft);
|
|
134
|
+
--internal-current-contrast: var(--color-background);
|
|
143
135
|
}
|
|
144
|
-
|
|
145
|
-
|
|
136
|
+
|
|
137
|
+
.background {
|
|
138
|
+
--internal-current-color: var(--color-background);
|
|
139
|
+
--internal-current-color-soft: var(--color-background-soft);
|
|
140
|
+
--internal-current-contrast: var(--color-foreground);
|
|
146
141
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
142
|
+
|
|
143
|
+
/* Filled variant */
|
|
144
|
+
.filled {
|
|
145
|
+
background-color: var(--internal-current-color);
|
|
146
|
+
color: var(--internal-current-contrast);
|
|
150
147
|
}
|
|
151
|
-
|
|
152
|
-
|
|
148
|
+
|
|
149
|
+
.filled:not(:disabled):hover {
|
|
150
|
+
background-color: color-mix(
|
|
151
|
+
in oklch,
|
|
152
|
+
var(--internal-current-color) var(--internal-btn-hover-mix),
|
|
153
|
+
black
|
|
154
|
+
);
|
|
153
155
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
+
|
|
157
|
+
.filled:not(:disabled):active {
|
|
158
|
+
background-color: color-mix(
|
|
159
|
+
in oklch,
|
|
160
|
+
var(--internal-current-color) var(--internal-btn-active-mix),
|
|
161
|
+
black
|
|
162
|
+
);
|
|
156
163
|
}
|
|
157
164
|
|
|
158
165
|
/* Soft variant */
|
|
159
|
-
.soft
|
|
160
|
-
background-color: var(--color-
|
|
161
|
-
color: var(--color
|
|
162
|
-
}
|
|
163
|
-
.soft.primary:not(:disabled):hover {
|
|
164
|
-
background-color: color-mix(in oklch, var(--color-primary-soft) 85%, var(--hover-mix));
|
|
165
|
-
}
|
|
166
|
-
.soft.primary:not(:disabled):active {
|
|
167
|
-
background-color: color-mix(in oklch, var(--color-primary-soft) 70%, var(--hover-mix));
|
|
168
|
-
}
|
|
169
|
-
.soft.secondary {
|
|
170
|
-
background-color: var(--color-secondary-soft);
|
|
171
|
-
color: var(--color-secondary);
|
|
172
|
-
}
|
|
173
|
-
.soft.secondary:not(:disabled):hover {
|
|
174
|
-
background-color: color-mix(in oklch, var(--color-secondary-soft) 85%, var(--hover-mix));
|
|
175
|
-
}
|
|
176
|
-
.soft.secondary:not(:disabled):active {
|
|
177
|
-
background-color: color-mix(in oklch, var(--color-secondary-soft) 70%, var(--hover-mix));
|
|
178
|
-
}
|
|
179
|
-
.soft.success {
|
|
180
|
-
background-color: var(--color-success-soft);
|
|
181
|
-
color: var(--color-success);
|
|
182
|
-
}
|
|
183
|
-
.soft.success:not(:disabled):hover {
|
|
184
|
-
background-color: color-mix(in oklch, var(--color-success-soft) 85%, var(--hover-mix));
|
|
185
|
-
}
|
|
186
|
-
.soft.success:not(:disabled):active {
|
|
187
|
-
background-color: color-mix(in oklch, var(--color-success-soft) 70%, var(--hover-mix));
|
|
166
|
+
.soft {
|
|
167
|
+
background-color: var(--internal-current-color-soft);
|
|
168
|
+
color: var(--internal-current-color);
|
|
188
169
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
color:
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
.soft.warning:not(:disabled):active {
|
|
197
|
-
background-color: color-mix(in oklch, var(--color-warning-soft) 70%, var(--hover-mix));
|
|
198
|
-
}
|
|
199
|
-
.soft.danger {
|
|
200
|
-
background-color: var(--color-danger-soft);
|
|
201
|
-
color: var(--color-danger);
|
|
202
|
-
}
|
|
203
|
-
.soft.danger:not(:disabled):hover {
|
|
204
|
-
background-color: color-mix(in oklch, var(--color-danger-soft) 85%, var(--hover-mix));
|
|
205
|
-
}
|
|
206
|
-
.soft.danger:not(:disabled):active {
|
|
207
|
-
background-color: color-mix(in oklch, var(--color-danger-soft) 70%, var(--hover-mix));
|
|
208
|
-
}
|
|
209
|
-
.soft.info {
|
|
210
|
-
background-color: var(--color-info-soft);
|
|
211
|
-
color: var(--color-info);
|
|
212
|
-
}
|
|
213
|
-
.soft.info:not(:disabled):hover {
|
|
214
|
-
background-color: color-mix(in oklch, var(--color-info-soft) 85%, var(--hover-mix));
|
|
215
|
-
}
|
|
216
|
-
.soft.info:not(:disabled):active {
|
|
217
|
-
background-color: color-mix(in oklch, var(--color-info-soft) 70%, var(--hover-mix));
|
|
218
|
-
}
|
|
219
|
-
.soft.foreground {
|
|
220
|
-
background-color: var(--color-foreground-soft);
|
|
221
|
-
color: var(--color-foreground);
|
|
222
|
-
}
|
|
223
|
-
.soft.foreground:not(:disabled):hover {
|
|
224
|
-
background-color: color-mix(in oklch, var(--color-foreground-soft) 85%, var(--hover-mix));
|
|
225
|
-
}
|
|
226
|
-
.soft.foreground:not(:disabled):active {
|
|
227
|
-
background-color: color-mix(in oklch, var(--color-foreground-soft) 70%, var(--hover-mix));
|
|
228
|
-
}
|
|
229
|
-
.soft.background {
|
|
230
|
-
background-color: var(--color-background-soft);
|
|
231
|
-
color: var(--color-background);
|
|
232
|
-
}
|
|
233
|
-
.soft.background:not(:disabled):hover {
|
|
234
|
-
background-color: color-mix(in oklch, var(--color-background-soft) 85%, var(--hover-mix));
|
|
170
|
+
|
|
171
|
+
.soft:not(:disabled):hover {
|
|
172
|
+
background-color: color-mix(
|
|
173
|
+
in oklch,
|
|
174
|
+
var(--internal-current-color-soft) var(--internal-btn-hover-mix),
|
|
175
|
+
var(--internal-current-color)
|
|
176
|
+
);
|
|
235
177
|
}
|
|
236
|
-
|
|
237
|
-
|
|
178
|
+
|
|
179
|
+
.soft:not(:disabled):active {
|
|
180
|
+
background-color: color-mix(
|
|
181
|
+
in oklch,
|
|
182
|
+
var(--internal-current-color-soft) var(--internal-btn-active-mix),
|
|
183
|
+
var(--internal-current-color)
|
|
184
|
+
);
|
|
238
185
|
}
|
|
239
186
|
|
|
240
187
|
/* Ghost variant */
|
|
241
188
|
.ghost {
|
|
242
189
|
background-color: transparent;
|
|
190
|
+
color: var(--internal-current-color);
|
|
243
191
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
background-color: var(--color-primary-soft);
|
|
252
|
-
}
|
|
253
|
-
.ghost.secondary {
|
|
254
|
-
color: var(--color-secondary);
|
|
255
|
-
}
|
|
256
|
-
.ghost.secondary:not(:disabled):hover {
|
|
257
|
-
background-color: color-mix(in srgb, var(--color-secondary-soft) 50%, transparent);
|
|
258
|
-
}
|
|
259
|
-
.ghost.secondary:not(:disabled):active {
|
|
260
|
-
background-color: var(--color-secondary-soft);
|
|
261
|
-
}
|
|
262
|
-
.ghost.success {
|
|
263
|
-
color: var(--color-success);
|
|
264
|
-
}
|
|
265
|
-
.ghost.success:not(:disabled):hover {
|
|
266
|
-
background-color: color-mix(in srgb, var(--color-success-soft) 50%, transparent);
|
|
267
|
-
}
|
|
268
|
-
.ghost.success:not(:disabled):active {
|
|
269
|
-
background-color: var(--color-success-soft);
|
|
270
|
-
}
|
|
271
|
-
.ghost.warning {
|
|
272
|
-
color: var(--color-warning);
|
|
273
|
-
}
|
|
274
|
-
.ghost.warning:not(:disabled):hover {
|
|
275
|
-
background-color: color-mix(in srgb, var(--color-warning-soft) 50%, transparent);
|
|
276
|
-
}
|
|
277
|
-
.ghost.warning:not(:disabled):active {
|
|
278
|
-
background-color: var(--color-warning-soft);
|
|
279
|
-
}
|
|
280
|
-
.ghost.danger {
|
|
281
|
-
color: var(--color-danger);
|
|
282
|
-
}
|
|
283
|
-
.ghost.danger:not(:disabled):hover {
|
|
284
|
-
background-color: color-mix(in srgb, var(--color-danger-soft) 50%, transparent);
|
|
285
|
-
}
|
|
286
|
-
.ghost.danger:not(:disabled):active {
|
|
287
|
-
background-color: var(--color-danger-soft);
|
|
288
|
-
}
|
|
289
|
-
.ghost.info {
|
|
290
|
-
color: var(--color-info);
|
|
291
|
-
}
|
|
292
|
-
.ghost.info:not(:disabled):hover {
|
|
293
|
-
background-color: color-mix(in srgb, var(--color-info-soft) 50%, transparent);
|
|
294
|
-
}
|
|
295
|
-
.ghost.info:not(:disabled):active {
|
|
296
|
-
background-color: var(--color-info-soft);
|
|
297
|
-
}
|
|
298
|
-
.ghost.foreground {
|
|
299
|
-
color: var(--color-foreground);
|
|
300
|
-
}
|
|
301
|
-
.ghost.foreground:not(:disabled):hover {
|
|
302
|
-
background-color: color-mix(in srgb, var(--color-foreground-soft) 50%, transparent);
|
|
303
|
-
}
|
|
304
|
-
.ghost.foreground:not(:disabled):active {
|
|
305
|
-
background-color: var(--color-foreground-soft);
|
|
306
|
-
}
|
|
307
|
-
.ghost.background {
|
|
308
|
-
color: var(--color-background);
|
|
309
|
-
}
|
|
310
|
-
.ghost.background:not(:disabled):hover {
|
|
311
|
-
background-color: color-mix(in srgb, var(--color-background-soft) 50%, transparent);
|
|
192
|
+
|
|
193
|
+
.ghost:not(:disabled):hover {
|
|
194
|
+
background-color: color-mix(
|
|
195
|
+
in srgb,
|
|
196
|
+
var(--internal-current-color) var(--internal-btn-ghost-hover-opacity),
|
|
197
|
+
var(--color-background)
|
|
198
|
+
);
|
|
312
199
|
}
|
|
313
|
-
|
|
314
|
-
|
|
200
|
+
|
|
201
|
+
.ghost:not(:disabled):active {
|
|
202
|
+
background-color: color-mix(
|
|
203
|
+
in srgb,
|
|
204
|
+
var(--internal-current-color) var(--internal-btn-ghost-active-opacity),
|
|
205
|
+
var(--color-background)
|
|
206
|
+
);
|
|
315
207
|
}
|
|
316
208
|
</style>
|
|
@@ -37,7 +37,6 @@
|
|
|
37
37
|
:global(:root),
|
|
38
38
|
:global(:root[data-theme='light']) {
|
|
39
39
|
color-scheme: light;
|
|
40
|
-
--hover-mix: var(--color-foreground);
|
|
41
40
|
--color-background: var(--color-light-background);
|
|
42
41
|
--color-background-soft: var(--color-light-background-soft);
|
|
43
42
|
--color-background-saturated: var(--color-light-background-saturated);
|
|
@@ -63,7 +62,6 @@
|
|
|
63
62
|
|
|
64
63
|
:global(:root[data-theme='dark']) {
|
|
65
64
|
color-scheme: dark;
|
|
66
|
-
--hover-mix: var(--color-foreground);
|
|
67
65
|
--color-background: var(--color-dark-background);
|
|
68
66
|
--color-background-soft: var(--color-dark-background-soft);
|
|
69
67
|
--color-background-saturated: var(--color-dark-background-saturated);
|
|
@@ -77,7 +75,6 @@
|
|
|
77
75
|
@media (prefers-color-scheme: dark) {
|
|
78
76
|
:global(:root:not([data-theme='light'])) {
|
|
79
77
|
color-scheme: dark;
|
|
80
|
-
--hover-mix: var(--color-foreground);
|
|
81
78
|
--color-background: var(--color-dark-background);
|
|
82
79
|
--color-background-soft: var(--color-dark-background-soft);
|
|
83
80
|
--color-background-saturated: var(--color-dark-background-saturated);
|
|
@@ -53,15 +53,13 @@
|
|
|
53
53
|
/>`;
|
|
54
54
|
</script>
|
|
55
55
|
|
|
56
|
-
{#snippet colorCard(name: string
|
|
56
|
+
{#snippet colorCard(name: string)}
|
|
57
57
|
<div class="color-card">
|
|
58
58
|
<div class="color-header">{name}</div>
|
|
59
59
|
<div class="color-variants">
|
|
60
60
|
{#each ['base', 'soft', 'saturated', 'contrast'] as variant}
|
|
61
61
|
{@const cssVar = variant === 'base' ? `--color-${name}` : `--color-${name}-${variant}`}
|
|
62
|
-
|
|
63
|
-
variant === 'contrast' ? `--color-${name}` : `--color-${name}-contrast`}
|
|
64
|
-
<div class="color-swatch" style="background: var({cssVar}); color: var({contrastVar})">
|
|
62
|
+
<div class="color-swatch" style:background={`var(${cssVar})`}>
|
|
65
63
|
<span class="swatch-label">{variant}</span>
|
|
66
64
|
</div>
|
|
67
65
|
{/each}
|
|
@@ -70,90 +68,33 @@
|
|
|
70
68
|
{/snippet}
|
|
71
69
|
|
|
72
70
|
<DemoSection title="Theming" id="theming">
|
|
73
|
-
<p class="intro">
|
|
74
|
-
The theme system provides a flexible, token-based approach to styling with automatic light/dark
|
|
75
|
-
mode support.
|
|
76
|
-
</p>
|
|
77
|
-
|
|
78
|
-
<!-- Theme Mode Toggle -->
|
|
79
|
-
|
|
80
71
|
<h3>Theme Mode</h3>
|
|
81
|
-
<p
|
|
72
|
+
<p>
|
|
82
73
|
Toggle between light and dark modes. The system respects <code>prefers-color-scheme</code> by default
|
|
83
74
|
and persists your choice in localStorage.
|
|
84
75
|
</p>
|
|
85
76
|
<Button
|
|
86
77
|
icon={{ name: themeMode === 'dark' ? 'light_mode' : 'dark_mode' }}
|
|
87
|
-
label="Toggle
|
|
78
|
+
label="Toggle {themeMode === 'dark' ? 'light' : 'dark'}"
|
|
88
79
|
onClick={onThemeToggle}
|
|
89
80
|
/>
|
|
90
81
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
Semantic colors that remain consistent across light and dark modes. Each color generates three
|
|
96
|
-
variants: <strong>soft</strong>, <strong>saturated</strong>, and
|
|
97
|
-
<strong>contrast</strong>.
|
|
82
|
+
<h3>Colors</h3>
|
|
83
|
+
<p>
|
|
84
|
+
Semantic palette colors and surface colors. Each generates <strong>soft</strong>,
|
|
85
|
+
<strong>saturated</strong>, and <strong>contrast</strong> variants.
|
|
98
86
|
</p>
|
|
99
87
|
<div class="color-grid">
|
|
100
88
|
{#each paletteColors as [name]}
|
|
101
89
|
{@render colorCard(name)}
|
|
102
90
|
{/each}
|
|
103
|
-
</div>
|
|
104
|
-
|
|
105
|
-
<!-- Surface Colors -->
|
|
106
|
-
|
|
107
|
-
<h3>Surface Colors</h3>
|
|
108
|
-
<p class="description">
|
|
109
|
-
Background and foreground colors that automatically swap between light and dark modes. These
|
|
110
|
-
define the base canvas and text colors.
|
|
111
|
-
</p>
|
|
112
|
-
<div class="color-grid surface-grid">
|
|
113
91
|
{#each surfaceColors as name}
|
|
114
|
-
{@render colorCard(name
|
|
92
|
+
{@render colorCard(name)}
|
|
115
93
|
{/each}
|
|
116
94
|
</div>
|
|
117
95
|
|
|
118
|
-
<!-- Token Generation Logic -->
|
|
119
|
-
|
|
120
|
-
<h3>Token Generation Logic</h3>
|
|
121
|
-
<ul class="bullet-list">
|
|
122
|
-
<li>
|
|
123
|
-
<strong>Soft:</strong> <code>lighten(25%) + desaturate(10%)</code> — A lighter, muted variant ideal
|
|
124
|
-
for backgrounds when using the base as foreground.
|
|
125
|
-
</li>
|
|
126
|
-
<li>
|
|
127
|
-
<strong>Saturated:</strong> <code>darken(15%) + saturate(10%)</code> — A deeper, more intense shade
|
|
128
|
-
for emphasis or active states.
|
|
129
|
-
</li>
|
|
130
|
-
<li>
|
|
131
|
-
<strong>Contrast:</strong> <code>isDark() ? white : black</code> — Automatically picks black or
|
|
132
|
-
white for text/icons ensuring WCAG compliance.
|
|
133
|
-
</li>
|
|
134
|
-
</ul>
|
|
135
|
-
|
|
136
|
-
<!-- Architecture Overview -->
|
|
137
|
-
|
|
138
|
-
<h3>Architecture</h3>
|
|
139
|
-
<ul class="bullet-list">
|
|
140
|
-
<li>
|
|
141
|
-
All tokens are exposed as <code>--color-*</code> custom properties on <code>:root</code>.
|
|
142
|
-
</li>
|
|
143
|
-
<li>
|
|
144
|
-
Surface colors use <code>data-theme</code> attribute with automatic fallback to
|
|
145
|
-
<code>prefers-color-scheme</code>.
|
|
146
|
-
</li>
|
|
147
|
-
<li>User preference is persisted in <code>localStorage</code>.</li>
|
|
148
|
-
<li>
|
|
149
|
-
Hover states are delegated to components using <code>color-mix()</code> for context-aware derivation.
|
|
150
|
-
</li>
|
|
151
|
-
</ul>
|
|
152
|
-
|
|
153
|
-
<!-- Usage -->
|
|
154
|
-
|
|
155
96
|
<h3>Usage</h3>
|
|
156
|
-
<p
|
|
97
|
+
<p>
|
|
157
98
|
Add the Theme component at the root of your app. It generates CSS custom properties and handles
|
|
158
99
|
light/dark mode switching.
|
|
159
100
|
</p>
|
|
@@ -161,13 +102,6 @@
|
|
|
161
102
|
</DemoSection>
|
|
162
103
|
|
|
163
104
|
<style>
|
|
164
|
-
.intro {
|
|
165
|
-
text-align: center;
|
|
166
|
-
font-size: 1.1rem;
|
|
167
|
-
max-width: 40rem;
|
|
168
|
-
opacity: 0.8;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
105
|
h3 {
|
|
172
106
|
font-size: 1.4rem;
|
|
173
107
|
margin-top: 1.5rem;
|
|
@@ -176,7 +110,7 @@
|
|
|
176
110
|
text-align: center;
|
|
177
111
|
}
|
|
178
112
|
|
|
179
|
-
|
|
113
|
+
p {
|
|
180
114
|
text-align: center;
|
|
181
115
|
max-width: 36rem;
|
|
182
116
|
opacity: 0.7;
|
|
@@ -191,7 +125,6 @@
|
|
|
191
125
|
font-size: 0.85em;
|
|
192
126
|
}
|
|
193
127
|
|
|
194
|
-
/* Color Grid */
|
|
195
128
|
.color-grid {
|
|
196
129
|
display: grid;
|
|
197
130
|
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
|
|
@@ -199,10 +132,6 @@
|
|
|
199
132
|
width: 100%;
|
|
200
133
|
}
|
|
201
134
|
|
|
202
|
-
.surface-grid {
|
|
203
|
-
max-width: 320px;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
135
|
.color-card {
|
|
207
136
|
display: flex;
|
|
208
137
|
flex-direction: column;
|
|
@@ -232,26 +161,13 @@
|
|
|
232
161
|
padding: 0.6rem 0.75rem;
|
|
233
162
|
font-size: 0.75rem;
|
|
234
163
|
}
|
|
235
|
-
|
|
164
|
+
|
|
236
165
|
.swatch-label {
|
|
166
|
+
color: var(--color-foreground);
|
|
167
|
+
padding: 0.15rem 0.4rem;
|
|
168
|
+
text-transform: capitalize ;
|
|
169
|
+
background: color-mix(in srgb, var(--color-background) 50%, transparent);
|
|
170
|
+
border-radius: 0.25rem;
|
|
237
171
|
font-weight: 500;
|
|
238
172
|
}
|
|
239
|
-
|
|
240
|
-
/* Bullet Lists */
|
|
241
|
-
.bullet-list {
|
|
242
|
-
list-style: disc;
|
|
243
|
-
padding-left: 1.5rem;
|
|
244
|
-
max-width: 40rem;
|
|
245
|
-
text-align: left;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
.bullet-list li {
|
|
249
|
-
margin-bottom: 0.5rem;
|
|
250
|
-
font-size: 0.9rem;
|
|
251
|
-
line-height: 1.5;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
.bullet-list li:last-child {
|
|
255
|
-
margin-bottom: 0;
|
|
256
|
-
}
|
|
257
173
|
</style>
|