@leftium/nimble.css 0.1.0 → 0.3.0
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/README.md +152 -55
- package/dist/nimble-base.css +24 -141
- package/dist/nimble-base.min.css +1 -1
- package/dist/nimble-core.css +867 -0
- package/dist/nimble-core.min.css +1 -0
- package/dist/nimble-meter.css +45 -0
- package/dist/nimble-meter.min.css +1 -0
- package/dist/nimble-progress.css +71 -0
- package/dist/nimble-progress.min.css +1 -0
- package/dist/nimble-reset.css +2 -1
- package/dist/nimble-reset.min.css +1 -1
- package/dist/nimble-select.css +46 -0
- package/dist/nimble-select.min.css +1 -0
- package/dist/nimble.css +446 -38
- package/dist/nimble.min.css +1 -1
- package/package.json +10 -2
- package/src/_article.scss +65 -0
- package/src/_buttons.scss +104 -6
- package/src/_colors.scss +20 -19
- package/src/_details.scss +66 -2
- package/src/_dialog.scss +7 -1
- package/src/_document.scss +13 -2
- package/src/_forms.scss +142 -3
- package/src/_links.scss +2 -2
- package/src/_media.scss +1 -1
- package/src/_meter.scss +72 -0
- package/src/_progress.scss +88 -0
- package/src/_reset.scss +3 -1
- package/src/_select.scss +67 -0
- package/src/_typography.scss +13 -13
- package/src/nimble-base.scss +1 -2
- package/src/nimble-core.scss +31 -0
- package/src/nimble-meter.scss +8 -0
- package/src/nimble-progress.scss +8 -0
- package/src/nimble-select.scss +8 -0
- package/src/nimble.scss +7 -1
package/src/_forms.scss
CHANGED
|
@@ -9,23 +9,26 @@
|
|
|
9
9
|
|
|
10
10
|
// ----- Text inputs, select, textarea -----
|
|
11
11
|
|
|
12
|
-
:where(input:not([type="checkbox"], [type="radio"], [type="range"], [type="file"], [type="color"]),
|
|
12
|
+
:where(input:not([type="checkbox"], [type="radio"], [type="range"], [type="file"], [type="color"], [type="submit"], [type="button"], [type="reset"]),
|
|
13
13
|
select, textarea) {
|
|
14
14
|
--_input-bg: color-mix(in oklch, var(#{$prefix}surface-1), var(#{$prefix}surface-2) 20%);
|
|
15
15
|
|
|
16
16
|
padding: 0.5em 0.75em;
|
|
17
|
+
min-height: calc(1em * 1.5 + 1em + 2px); // line-height + vertical padding + border
|
|
17
18
|
background-color: var(--_input-bg);
|
|
18
19
|
border: 1px solid var(#{$prefix}border);
|
|
19
20
|
border-radius: var(#{$prefix}radius);
|
|
20
|
-
color: var(#{$prefix}text
|
|
21
|
+
color: var(#{$prefix}text);
|
|
21
22
|
font: inherit;
|
|
23
|
+
font-size: 1rem; // >=16px prevents iOS Safari auto-zoom on focus
|
|
22
24
|
transition: border-color 0.2s, box-shadow 0.2s;
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
// Make text inputs and select full-width by default (PicoCSS pattern)
|
|
26
|
-
:where(input:not([type="checkbox"], [type="radio"], [type="range"], [type="file"], [type="color"], [type="submit"], [type="button"], [type="reset"]),
|
|
28
|
+
:where(input:not([type="checkbox"], [type="radio"], [type="range"], [type="file"], [type="color"], [type="submit"], [type="button"], [type="reset"], [type="date"], [type="month"], [type="week"], [type="time"], [type="datetime-local"]),
|
|
27
29
|
select, textarea) {
|
|
28
30
|
width: 100%;
|
|
31
|
+
margin-bottom: var(#{$prefix}spacing);
|
|
29
32
|
}
|
|
30
33
|
|
|
31
34
|
// ----- Focus -----
|
|
@@ -36,6 +39,16 @@
|
|
|
36
39
|
outline: none;
|
|
37
40
|
}
|
|
38
41
|
|
|
42
|
+
// When a validation message <small> immediately follows an input,
|
|
43
|
+
// pull it up tight against the field and let it carry the spacing instead.
|
|
44
|
+
:where(input, select, textarea) + :where(small) {
|
|
45
|
+
display: block;
|
|
46
|
+
margin-top: calc(var(#{$prefix}spacing) * -0.75); // pull up under the input
|
|
47
|
+
margin-bottom: var(#{$prefix}spacing);
|
|
48
|
+
font-size: 0.875em;
|
|
49
|
+
color: color-mix(in oklch, var(#{$prefix}text), transparent 40%);
|
|
50
|
+
}
|
|
51
|
+
|
|
39
52
|
// ----- Validation states (aria-invalid) -----
|
|
40
53
|
|
|
41
54
|
:where(input, select, textarea)[aria-invalid="false"] {
|
|
@@ -46,6 +59,15 @@
|
|
|
46
59
|
border-color: var(#{$prefix}invalid);
|
|
47
60
|
}
|
|
48
61
|
|
|
62
|
+
// Color validation messages to match the field state
|
|
63
|
+
:where(input, select, textarea)[aria-invalid="false"] + :where(small) {
|
|
64
|
+
color: var(#{$prefix}valid);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
:where(input, select, textarea)[aria-invalid="true"] + :where(small) {
|
|
68
|
+
color: var(#{$prefix}invalid);
|
|
69
|
+
}
|
|
70
|
+
|
|
49
71
|
// ----- Labels -----
|
|
50
72
|
|
|
51
73
|
:where(label) {
|
|
@@ -57,12 +79,20 @@
|
|
|
57
79
|
font-weight: 600;
|
|
58
80
|
}
|
|
59
81
|
|
|
82
|
+
// file and range are short/inline controls — increase the label gap to match
|
|
83
|
+
// the visual weight of the spacing above and beside them.
|
|
84
|
+
:where(label:has(+ [type="file"], + [type="range"])) {
|
|
85
|
+
margin-bottom: 0.5em;
|
|
86
|
+
}
|
|
87
|
+
|
|
60
88
|
// ----- Fieldset -----
|
|
61
89
|
|
|
62
90
|
:where(fieldset) {
|
|
63
91
|
border: 1px solid var(#{$prefix}border);
|
|
64
92
|
border-radius: var(#{$prefix}radius);
|
|
65
93
|
padding: var(#{$prefix}spacing);
|
|
94
|
+
min-width: 0; // Override UA min-content default — prevents overflow on narrow viewports
|
|
95
|
+
max-width: 100%;
|
|
66
96
|
}
|
|
67
97
|
|
|
68
98
|
:where(legend) {
|
|
@@ -75,6 +105,29 @@
|
|
|
75
105
|
|
|
76
106
|
:where([type="checkbox"], [type="radio"]) {
|
|
77
107
|
accent-color: var(#{$prefix}primary);
|
|
108
|
+
width: 1.125em;
|
|
109
|
+
height: 1.125em;
|
|
110
|
+
margin: 0; // Remove browser default margin so flex labels align flush left
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
:where(label:has([type="checkbox"], [type="radio"])) {
|
|
114
|
+
display: flex;
|
|
115
|
+
align-items: center;
|
|
116
|
+
gap: 0.35em;
|
|
117
|
+
margin-bottom: 0.5em;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Last checkbox/radio label in a group drops its bottom margin
|
|
121
|
+
// so the parent element controls spacing to the next sibling.
|
|
122
|
+
:where(label:has([type="checkbox"], [type="radio"]):last-child) {
|
|
123
|
+
margin-bottom: 0;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// ----- Search (pill shape) -----
|
|
127
|
+
|
|
128
|
+
:where([type="search"]) {
|
|
129
|
+
border-radius: 5rem;
|
|
130
|
+
padding-inline: 1.25em;
|
|
78
131
|
}
|
|
79
132
|
|
|
80
133
|
// ----- Range -----
|
|
@@ -82,12 +135,77 @@
|
|
|
82
135
|
:where([type="range"]) {
|
|
83
136
|
accent-color: var(#{$prefix}primary);
|
|
84
137
|
width: 100%;
|
|
138
|
+
margin-bottom: var(#{$prefix}spacing);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ----- Datalist-connected inputs -----
|
|
142
|
+
// Keep natural width so the dropdown arrow stays near the text,
|
|
143
|
+
// similar to date/time inputs preserving native widget UX.
|
|
144
|
+
|
|
145
|
+
:where(input[list]) {
|
|
146
|
+
width: auto;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// ----- File -----
|
|
150
|
+
|
|
151
|
+
:where([type="file"]) {
|
|
152
|
+
color: var(#{$prefix}text);
|
|
153
|
+
font: inherit;
|
|
154
|
+
cursor: pointer;
|
|
155
|
+
max-width: 100%; // Prevent native file input from overflowing container (iOS Safari)
|
|
156
|
+
margin-bottom: var(#{$prefix}spacing);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
:where([type="file"])::file-selector-button {
|
|
160
|
+
padding: 0.5em 1em;
|
|
161
|
+
margin-right: 0.75em;
|
|
162
|
+
margin-inline-end: 0.75em;
|
|
163
|
+
background-color: var(#{$prefix}primary);
|
|
164
|
+
color: var(#{$prefix}primary-contrast);
|
|
165
|
+
border: 1px solid var(#{$prefix}primary);
|
|
166
|
+
border-radius: var(#{$prefix}radius);
|
|
167
|
+
font: inherit;
|
|
168
|
+
cursor: pointer;
|
|
169
|
+
transition: background-color 0.2s, border-color 0.2s;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
:where([type="file"])::file-selector-button:hover {
|
|
173
|
+
background-color: var(#{$prefix}primary-hover);
|
|
174
|
+
border-color: var(#{$prefix}primary-hover);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// ----- Date/time inputs -----
|
|
178
|
+
// Natural width so picker icon stays near content (excluded from full-width rule above).
|
|
179
|
+
// appearance: none is applied outside @layer (see below) to fix iOS Safari sizing.
|
|
180
|
+
:where([type="date"], [type="month"], [type="week"], [type="time"], [type="datetime-local"]) {
|
|
181
|
+
min-width: 10em; // Prevent collapse when empty (e.g. time with no value)
|
|
182
|
+
margin-bottom: var(#{$prefix}spacing);
|
|
85
183
|
}
|
|
86
184
|
|
|
87
185
|
// ----- Color -----
|
|
88
186
|
|
|
89
187
|
:where([type="color"]) {
|
|
188
|
+
--_color-size: calc(1em * 1.5 + 1em + 2px); // Match text input height
|
|
189
|
+
margin-bottom: var(#{$prefix}spacing);
|
|
190
|
+
|
|
191
|
+
--_color-pad: 0.25em;
|
|
192
|
+
|
|
193
|
+
height: var(--_color-size);
|
|
194
|
+
width: calc((var(--_color-size) - 2 * var(--_color-pad)) * 1.618 + 2 * var(--_color-pad)); // Golden ratio inner swatch
|
|
195
|
+
padding: var(--_color-pad);
|
|
196
|
+
background-color: color-mix(in oklch, var(#{$prefix}surface-1), var(#{$prefix}surface-2) 20%);
|
|
197
|
+
border: 1px solid var(#{$prefix}border);
|
|
198
|
+
border-radius: var(#{$prefix}radius);
|
|
90
199
|
cursor: pointer;
|
|
200
|
+
|
|
201
|
+
&::-webkit-color-swatch-wrapper {
|
|
202
|
+
padding: 0;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
&::-webkit-color-swatch {
|
|
206
|
+
border: none;
|
|
207
|
+
border-radius: calc(var(#{$prefix}radius) * 0.5);
|
|
208
|
+
}
|
|
91
209
|
}
|
|
92
210
|
|
|
93
211
|
// ----- Switch (checkbox with role="switch") -----
|
|
@@ -95,6 +213,12 @@
|
|
|
95
213
|
@if $enable-switch {
|
|
96
214
|
// Minimal switch styling — relies on native checkbox with role="switch"
|
|
97
215
|
// Browsers with :has() support get enhanced label alignment
|
|
216
|
+
:where(label:has([type="checkbox"][role="switch"])) {
|
|
217
|
+
display: flex;
|
|
218
|
+
align-items: center;
|
|
219
|
+
gap: 0.5em;
|
|
220
|
+
}
|
|
221
|
+
|
|
98
222
|
:where([type="checkbox"][role="switch"]) {
|
|
99
223
|
appearance: none;
|
|
100
224
|
width: 2.5em;
|
|
@@ -103,6 +227,8 @@
|
|
|
103
227
|
background-color: var(#{$prefix}border);
|
|
104
228
|
position: relative;
|
|
105
229
|
cursor: pointer;
|
|
230
|
+
flex-shrink: 0;
|
|
231
|
+
margin: 0; // Remove browser default margin so flex labels align flush left
|
|
106
232
|
transition: background-color 0.2s;
|
|
107
233
|
}
|
|
108
234
|
|
|
@@ -128,3 +254,16 @@
|
|
|
128
254
|
}
|
|
129
255
|
|
|
130
256
|
}
|
|
257
|
+
|
|
258
|
+
// iOS Safari ignores author box-model styles on native date/time inputs.
|
|
259
|
+
// appearance: none unlocks sizing control while preserving the native picker
|
|
260
|
+
// (only the decorative icon is removed on iOS; Chrome/desktop keeps its icons).
|
|
261
|
+
// Placed outside @layer with real selectors to beat UA specificity.
|
|
262
|
+
[type="date"],
|
|
263
|
+
[type="month"],
|
|
264
|
+
[type="week"],
|
|
265
|
+
[type="time"],
|
|
266
|
+
[type="datetime-local"] {
|
|
267
|
+
-webkit-appearance: none;
|
|
268
|
+
appearance: none;
|
|
269
|
+
}
|
package/src/_links.scss
CHANGED
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
:where(a:not([role="button"])):visited {
|
|
20
|
-
color: #{string.unquote('color-mix(in oklch, var(#{$prefix}primary) 40%, oklch(0.
|
|
21
|
-
text-decoration-color: #{string.unquote('color-mix(in oklch, var(#{$prefix}primary) 40%, oklch(0.
|
|
20
|
+
color: #{string.unquote('color-mix(in oklch, var(#{$prefix}primary) 40%, oklch(0.38 0.15 310))')};
|
|
21
|
+
text-decoration-color: #{string.unquote('color-mix(in oklch, var(#{$prefix}primary) 40%, oklch(0.38 0.15 310) 30%)')};
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
:where(a:not([role="button"])):hover {
|
package/src/_media.scss
CHANGED
package/src/_meter.scss
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// ==========================================================================
|
|
2
|
+
// nimble.css — Meter
|
|
3
|
+
// Optional: styled <meter> with cross-browser semantic state colors
|
|
4
|
+
// ==========================================================================
|
|
5
|
+
|
|
6
|
+
@use 'config' as *;
|
|
7
|
+
|
|
8
|
+
@layer nimble.base {
|
|
9
|
+
|
|
10
|
+
// Same treatment as progress: appearance: none + pseudo-element rebuild.
|
|
11
|
+
// Meter has three semantic states (optimum / suboptimum / sub-sub-optimum)
|
|
12
|
+
// which we map to --nc-valid (green), --nc-primary (default), --nc-invalid (red).
|
|
13
|
+
|
|
14
|
+
:where(meter) {
|
|
15
|
+
-webkit-appearance: none;
|
|
16
|
+
-moz-appearance: none;
|
|
17
|
+
appearance: none;
|
|
18
|
+
width: 100%;
|
|
19
|
+
height: 0.5rem;
|
|
20
|
+
overflow: hidden;
|
|
21
|
+
border: 0;
|
|
22
|
+
border-radius: var(#{$prefix}radius);
|
|
23
|
+
background-color: var(#{$prefix}surface-3);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// WebKit: track (outer bar)
|
|
27
|
+
:where(meter)::-webkit-meter-inner-element {
|
|
28
|
+
// Wrapper element — reset grid layout that some UAs impose
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
:where(meter)::-webkit-meter-bar {
|
|
32
|
+
border-radius: var(#{$prefix}radius);
|
|
33
|
+
background-color: var(#{$prefix}surface-3);
|
|
34
|
+
border: 0;
|
|
35
|
+
height: 0.5rem;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// WebKit: value bars for each semantic state
|
|
39
|
+
:where(meter)::-webkit-meter-optimum-value {
|
|
40
|
+
background-color: var(#{$prefix}valid);
|
|
41
|
+
border-radius: var(#{$prefix}radius);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
:where(meter)::-webkit-meter-suboptimum-value {
|
|
45
|
+
background-color: var(#{$prefix}primary);
|
|
46
|
+
border-radius: var(#{$prefix}radius);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
:where(meter)::-webkit-meter-even-less-good-value {
|
|
50
|
+
background-color: var(#{$prefix}invalid);
|
|
51
|
+
border-radius: var(#{$prefix}radius);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Firefox: single bar pseudo-element + pseudo-classes for state
|
|
55
|
+
:where(meter)::-moz-meter-bar {
|
|
56
|
+
background-color: var(#{$prefix}primary);
|
|
57
|
+
border-radius: var(#{$prefix}radius);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
:where(meter):-moz-meter-optimum::-moz-meter-bar {
|
|
61
|
+
background-color: var(#{$prefix}valid);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
:where(meter):-moz-meter-sub-optimum::-moz-meter-bar {
|
|
65
|
+
background-color: var(#{$prefix}primary);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
:where(meter):-moz-meter-sub-sub-optimum::-moz-meter-bar {
|
|
69
|
+
background-color: var(#{$prefix}invalid);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// ==========================================================================
|
|
2
|
+
// nimble.css — Progress (add-on)
|
|
3
|
+
// Standalone <progress> styling for use with nimble-base.
|
|
4
|
+
// Not needed with nimble.css (progress is already included). Use with nimble-core.css.
|
|
5
|
+
// ==========================================================================
|
|
6
|
+
|
|
7
|
+
@use 'config' as *;
|
|
8
|
+
|
|
9
|
+
@layer nimble.base {
|
|
10
|
+
|
|
11
|
+
:where(progress) {
|
|
12
|
+
-webkit-appearance: none;
|
|
13
|
+
appearance: none;
|
|
14
|
+
position: relative;
|
|
15
|
+
width: 100%;
|
|
16
|
+
height: 0.5rem;
|
|
17
|
+
overflow: hidden;
|
|
18
|
+
border: 0;
|
|
19
|
+
border-radius: var(#{$prefix}radius);
|
|
20
|
+
background-color: var(#{$prefix}surface-3);
|
|
21
|
+
color: var(#{$prefix}primary); // Firefox uses color for the bar
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
:where(progress)::-webkit-progress-bar {
|
|
25
|
+
border-radius: var(#{$prefix}radius);
|
|
26
|
+
background-color: var(#{$prefix}surface-3);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
:where(progress)::-webkit-progress-value {
|
|
30
|
+
background-color: var(#{$prefix}primary);
|
|
31
|
+
border-radius: var(#{$prefix}radius);
|
|
32
|
+
transition: inline-size 0.3s ease;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
:where(progress)::-moz-progress-bar {
|
|
36
|
+
background-color: var(#{$prefix}primary);
|
|
37
|
+
border-radius: var(#{$prefix}radius);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Indeterminate: evenly-spaced blue bands travel continuously rightward.
|
|
41
|
+
// Gradient is 200% wide with two identical 10%-wide bands at 15% and 65%.
|
|
42
|
+
// They're 50% apart — exactly one visible width (100/200 = 50% of gradient).
|
|
43
|
+
// Animating position by -200% = one full gradient width → seamless loop.
|
|
44
|
+
:where(progress):not([value]) {
|
|
45
|
+
--nc-progress-track:
|
|
46
|
+
linear-gradient(to right,
|
|
47
|
+
var(#{$prefix}surface-3) 0%,
|
|
48
|
+
var(#{$prefix}primary) 25%,
|
|
49
|
+
var(#{$prefix}primary) 25%,
|
|
50
|
+
var(#{$prefix}surface-3) 50%,
|
|
51
|
+
var(#{$prefix}surface-3) 50%,
|
|
52
|
+
var(#{$prefix}primary) 75%,
|
|
53
|
+
var(#{$prefix}primary) 75%,
|
|
54
|
+
var(#{$prefix}surface-3) 100%);
|
|
55
|
+
--nc-progress-track-size: 200% 100%;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
59
|
+
@supports selector(progress::after) {
|
|
60
|
+
:where(progress):not([value])::after {
|
|
61
|
+
content: "";
|
|
62
|
+
position: absolute;
|
|
63
|
+
inset: 0;
|
|
64
|
+
background: var(--nc-progress-track);
|
|
65
|
+
background-size: var(--nc-progress-track-size);
|
|
66
|
+
animation: nc-progress-indeterminate 12s linear infinite;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
:where(progress):not([value])::-webkit-progress-bar {
|
|
71
|
+
background: var(--nc-progress-track);
|
|
72
|
+
background-size: var(--nc-progress-track-size);
|
|
73
|
+
animation: nc-progress-indeterminate 12s linear infinite;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
:where(progress):not([value])::-moz-progress-bar {
|
|
77
|
+
background: var(--nc-progress-track);
|
|
78
|
+
background-size: var(--nc-progress-track-size);
|
|
79
|
+
animation: nc-progress-indeterminate 12s linear infinite;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@keyframes nc-progress-indeterminate {
|
|
84
|
+
from { background-position: 0% 0%; }
|
|
85
|
+
to { background-position: -200% 0%; }
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
}
|
package/src/_reset.scss
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
// --- Document ---
|
|
12
12
|
|
|
13
|
-
:where(
|
|
13
|
+
:where(*:not(progress)),
|
|
14
14
|
:where(*::before),
|
|
15
15
|
:where(*::after) {
|
|
16
16
|
box-sizing: border-box;
|
|
@@ -156,6 +156,7 @@
|
|
|
156
156
|
// Remove delay from tapping on clickable elements
|
|
157
157
|
:where(a, area, button, input, label, select, summary, textarea, [tabindex]) {
|
|
158
158
|
touch-action: manipulation;
|
|
159
|
+
-webkit-tap-highlight-color: transparent;
|
|
159
160
|
}
|
|
160
161
|
|
|
161
162
|
// Change the cursor for busy elements
|
|
@@ -181,3 +182,4 @@
|
|
|
181
182
|
}
|
|
182
183
|
|
|
183
184
|
}
|
|
185
|
+
|
package/src/_select.scss
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// ==========================================================================
|
|
2
|
+
// nimble.css — Customizable Select
|
|
3
|
+
// Optional: styled <select> using appearance: base-select (progressive enhancement)
|
|
4
|
+
// Falls back to classic <select> in unsupported browsers
|
|
5
|
+
// ==========================================================================
|
|
6
|
+
|
|
7
|
+
@use 'config' as *;
|
|
8
|
+
|
|
9
|
+
@layer nimble.base {
|
|
10
|
+
|
|
11
|
+
@supports (appearance: base-select) {
|
|
12
|
+
:where(select),
|
|
13
|
+
:where(select)::picker(select) {
|
|
14
|
+
appearance: base-select;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Picker icon (chevron)
|
|
18
|
+
:where(select)::picker-icon {
|
|
19
|
+
content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='10' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2 2l6 6 6-6'/%3E%3C/svg%3E");
|
|
20
|
+
transition: rotate 0.4s;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
:where(select):open::picker-icon {
|
|
24
|
+
rotate: 180deg;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Drop-down picker
|
|
28
|
+
:where(select)::picker(select) {
|
|
29
|
+
position-area: block-end;
|
|
30
|
+
position-try-order: normal;
|
|
31
|
+
position-try-fallbacks: flip-block;
|
|
32
|
+
border: 1px solid var(#{$prefix}border);
|
|
33
|
+
border-radius: var(#{$prefix}radius);
|
|
34
|
+
background-color: var(#{$prefix}surface-1);
|
|
35
|
+
padding: 0.25em;
|
|
36
|
+
// Fade in/out animation
|
|
37
|
+
opacity: 0;
|
|
38
|
+
transition: opacity 0.2s, overlay 0.2s allow-discrete, display 0.2s allow-discrete;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
:where(select):open::picker(select) {
|
|
42
|
+
opacity: 1;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@starting-style {
|
|
46
|
+
:where(select):open::picker(select) {
|
|
47
|
+
opacity: 0;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Options inside the picker
|
|
52
|
+
:where(select) option {
|
|
53
|
+
padding: 0.5em 0.75em;
|
|
54
|
+
border-radius: var(#{$prefix}radius);
|
|
55
|
+
transition: background-color 0.15s;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
:where(select) option:hover {
|
|
59
|
+
background-color: var(#{$prefix}surface-2);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
:where(select) option:checked {
|
|
63
|
+
font-weight: 600;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
}
|
package/src/_typography.scss
CHANGED
|
@@ -7,15 +7,18 @@
|
|
|
7
7
|
@use 'sass:string';
|
|
8
8
|
@use 'config' as *;
|
|
9
9
|
|
|
10
|
-
// Heading scale: size
|
|
10
|
+
// Heading scale: size, line-height, and top margin
|
|
11
|
+
// h1 has no top margin (page title / first heading).
|
|
12
|
+
// h2–h6 always carry top margin so they breathe above any preceding content,
|
|
13
|
+
// regardless of DOM nesting (first-child of section, etc.).
|
|
11
14
|
// Spec §8.3
|
|
12
15
|
$_heading-scale: (
|
|
13
|
-
h1: (size: 2rem, lh: 1.1),
|
|
14
|
-
h2: (size: 1.75rem, lh: 1.15),
|
|
15
|
-
h3: (size: 1.5rem, lh: 1.2),
|
|
16
|
-
h4: (size: 1.25rem, lh: 1.3),
|
|
17
|
-
h5: (size: 1.125rem, lh: 1.4),
|
|
18
|
-
h6: (size: 1rem, lh: 1.5),
|
|
16
|
+
h1: (size: 2rem, lh: 1.1, mt: 0),
|
|
17
|
+
h2: (size: 1.75rem, lh: 1.15, mt: 2rem),
|
|
18
|
+
h3: (size: 1.5rem, lh: 1.2, mt: 1.5rem),
|
|
19
|
+
h4: (size: 1.25rem, lh: 1.3, mt: 1.5rem),
|
|
20
|
+
h5: (size: 1.125rem, lh: 1.4, mt: 1.5rem),
|
|
21
|
+
h6: (size: 1rem, lh: 1.5, mt: 1.5rem),
|
|
19
22
|
);
|
|
20
23
|
|
|
21
24
|
// Phone breakpoint heading overrides
|
|
@@ -34,7 +37,7 @@ $_heading-phone: (
|
|
|
34
37
|
#{$tag} {
|
|
35
38
|
font-size: map.get($vals, size);
|
|
36
39
|
line-height: map.get($vals, lh);
|
|
37
|
-
margin-top:
|
|
40
|
+
margin-top: map.get($vals, mt);
|
|
38
41
|
margin-bottom: var(#{$prefix}spacing);
|
|
39
42
|
font-weight: 700;
|
|
40
43
|
text-wrap: balance;
|
|
@@ -59,10 +62,7 @@ $_heading-phone: (
|
|
|
59
62
|
margin-bottom: var(#{$prefix}spacing);
|
|
60
63
|
}
|
|
61
64
|
|
|
62
|
-
|
|
63
|
-
:where(p, ul, ol, dl, blockquote, pre, table, figure, form) + :is(h1, h2, h3, h4, h5, h6) {
|
|
64
|
-
margin-top: calc(var(#{$prefix}spacing) * 2);
|
|
65
|
-
}
|
|
65
|
+
|
|
66
66
|
|
|
67
67
|
// ----- Lists -----
|
|
68
68
|
|
|
@@ -103,7 +103,7 @@ $_heading-phone: (
|
|
|
103
103
|
:where(blockquote) cite {
|
|
104
104
|
font-style: normal;
|
|
105
105
|
font-size: 0.9em;
|
|
106
|
-
color: var(#{$prefix}text
|
|
106
|
+
color: color-mix(in oklch, var(#{$prefix}text), transparent 40%);
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
// ----- Horizontal Rule -----
|
package/src/nimble-base.scss
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
// ==========================================================================
|
|
2
2
|
// nimble.css — Base Sub-bundle
|
|
3
|
-
//
|
|
3
|
+
// Colors + document + typography (no reset — use nimble-reset for that)
|
|
4
4
|
// ==========================================================================
|
|
5
5
|
|
|
6
6
|
@use 'config' as *;
|
|
7
7
|
@use 'layers-base';
|
|
8
|
-
@use 'reset';
|
|
9
8
|
@use 'colors';
|
|
10
9
|
@use 'document';
|
|
11
10
|
@use 'typography';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// ==========================================================================
|
|
2
|
+
// nimble.css — Core Entry Point
|
|
3
|
+
// Everything except progress, meter, and select add-ons
|
|
4
|
+
// ==========================================================================
|
|
5
|
+
|
|
6
|
+
@use 'config' as *;
|
|
7
|
+
|
|
8
|
+
// Layer order declaration — emitted first in CSS output.
|
|
9
|
+
// Lower layers lose to higher layers in cascade.
|
|
10
|
+
@use 'layers';
|
|
11
|
+
|
|
12
|
+
// Phase 2: Core
|
|
13
|
+
@use 'reset';
|
|
14
|
+
@use 'colors';
|
|
15
|
+
@use 'document';
|
|
16
|
+
@use 'typography';
|
|
17
|
+
|
|
18
|
+
// Phase 3: Elements
|
|
19
|
+
@use 'links';
|
|
20
|
+
@use 'buttons';
|
|
21
|
+
@use 'forms';
|
|
22
|
+
@use 'tables';
|
|
23
|
+
@use 'code';
|
|
24
|
+
@use 'media';
|
|
25
|
+
@use 'article';
|
|
26
|
+
@use 'details';
|
|
27
|
+
@use 'dialog';
|
|
28
|
+
@use 'print';
|
|
29
|
+
|
|
30
|
+
// Phase 4: Utilities
|
|
31
|
+
@use 'utilities';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// ==========================================================================
|
|
2
|
+
// nimble.css — Meter Sub-bundle
|
|
3
|
+
// Add to nimble.css for styled <meter> elements
|
|
4
|
+
// ==========================================================================
|
|
5
|
+
|
|
6
|
+
@use 'config' as *;
|
|
7
|
+
@use 'layers-base';
|
|
8
|
+
@use 'meter';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// ==========================================================================
|
|
2
|
+
// nimble.css — Progress Sub-bundle
|
|
3
|
+
// Add to nimble.css for styled <progress> elements
|
|
4
|
+
// ==========================================================================
|
|
5
|
+
|
|
6
|
+
@use 'config' as *;
|
|
7
|
+
@use 'layers-base';
|
|
8
|
+
@use 'progress';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// ==========================================================================
|
|
2
|
+
// nimble.css — Customizable Select Sub-bundle
|
|
3
|
+
// Add to nimble.css for styled <select> using appearance: base-select
|
|
4
|
+
// ==========================================================================
|
|
5
|
+
|
|
6
|
+
@use 'config' as *;
|
|
7
|
+
@use 'layers-base';
|
|
8
|
+
@use 'select';
|
package/src/nimble.scss
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// ==========================================================================
|
|
2
2
|
// nimble.css — Entry Point
|
|
3
|
-
//
|
|
3
|
+
// Everything: core + progress, meter, and select
|
|
4
4
|
// ==========================================================================
|
|
5
5
|
|
|
6
6
|
@use 'config' as *;
|
|
@@ -22,9 +22,15 @@
|
|
|
22
22
|
@use 'tables';
|
|
23
23
|
@use 'code';
|
|
24
24
|
@use 'media';
|
|
25
|
+
@use 'article';
|
|
25
26
|
@use 'details';
|
|
26
27
|
@use 'dialog';
|
|
27
28
|
@use 'print';
|
|
28
29
|
|
|
30
|
+
// Phase 3: Optional extras
|
|
31
|
+
@use 'progress';
|
|
32
|
+
@use 'meter';
|
|
33
|
+
@use 'select';
|
|
34
|
+
|
|
29
35
|
// Phase 4: Utilities
|
|
30
36
|
@use 'utilities';
|