@rio-m3e/styles 0.1.0 → 0.2.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/package.json +1 -1
- package/src/base/shape-morph.css +28 -4
- package/src/base/state-layer.css +2 -1
- package/src/button-group.css +98 -0
- package/src/button.css +27 -7
- package/src/split-button.css +185 -0
- package/src/switch.css +12 -4
package/package.json
CHANGED
package/src/base/shape-morph.css
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Shape morphing, driven by `attachShapeMorph` from `@rio-m3e/core`. A component sets
|
|
3
|
-
* `--rio-shape-morph-target` to the corner radius it wants in each state
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
3
|
+
* `--rio-shape-morph-target` to the corner radius it wants in each state. The primitive reads
|
|
4
|
+
* the targets in px, which needs the registrations below, and springs the inline radii toward
|
|
5
|
+
* them. It marks the element with `data-shape-morph`.
|
|
6
|
+
*
|
|
7
|
+
* Shapes whose sides differ set `--rio-shape-morph-start-target` and `--rio-shape-morph-end-target`
|
|
8
|
+
* (the corners at the start and end of the line, in the writing direction) with any class or
|
|
9
|
+
* attribute selector; otherwise both follow `--rio-shape-morph-target`.
|
|
10
|
+
*
|
|
11
|
+
* The component also draws its corners from the per-side targets, so it still works without
|
|
12
|
+
* JavaScript, and lists both targets in its `transition` as `1ms step-end`, so the springs see
|
|
13
|
+
* them change (see "Primitives" in docs/conventions.md, and button.css).
|
|
7
14
|
*/
|
|
8
15
|
|
|
9
16
|
@property --rio-shape-morph-target {
|
|
@@ -11,3 +18,20 @@
|
|
|
11
18
|
inherits: false;
|
|
12
19
|
initial-value: 0px;
|
|
13
20
|
}
|
|
21
|
+
|
|
22
|
+
@property --rio-shape-morph-start-target {
|
|
23
|
+
syntax: '<length>';
|
|
24
|
+
inherits: false;
|
|
25
|
+
initial-value: 0px;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@property --rio-shape-morph-end-target {
|
|
29
|
+
syntax: '<length>';
|
|
30
|
+
inherits: false;
|
|
31
|
+
initial-value: 0px;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
:where([data-shape-morph]) {
|
|
35
|
+
--rio-shape-morph-start-target: var(--rio-shape-morph-target);
|
|
36
|
+
--rio-shape-morph-end-target: var(--rio-shape-morph-target);
|
|
37
|
+
}
|
package/src/base/state-layer.css
CHANGED
|
@@ -41,7 +41,8 @@
|
|
|
41
41
|
opacity: var(--rio-state-pressed-state-layer-opacity);
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
/* `attachDrag` from `@rio-m3e/core` marks an element with `data-dragging` while it moves. */
|
|
45
|
+
.rio-state-layer[data-dragging]::before {
|
|
45
46
|
opacity: var(--rio-state-dragged-state-layer-opacity);
|
|
46
47
|
}
|
|
47
48
|
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* M3E button group: a row of buttons and icon buttons (`button.css`, `icon-button.css`). The group
|
|
3
|
+
* has no color of its own. It carries `data-variant`, `data-size`, and `data-shape`, which
|
|
4
|
+
* `createButtonGroup` from `@rio-m3e/core` sets; the size and shape reach the buttons through the
|
|
5
|
+
* framework adapter, so these rules read the buttons' own `data-size` and `data-shape`.
|
|
6
|
+
*
|
|
7
|
+
* Values come from Material Web's component tokens (`_md-comp-button-group-standard-*.scss` and
|
|
8
|
+
* `_md-comp-button-group-connected-*.scss`, Material 3 v34.0.21). The pressed button's width
|
|
9
|
+
* change in standard groups is JavaScript (`attachButtonGroup` from `@rio-m3e/core`).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
.rio-button-group {
|
|
13
|
+
/* Standard, small */
|
|
14
|
+
--_between: 12px;
|
|
15
|
+
|
|
16
|
+
display: inline-flex;
|
|
17
|
+
align-items: center;
|
|
18
|
+
gap: var(--_between);
|
|
19
|
+
vertical-align: middle;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* Standard: the space keeps every button's 48px target clear of its neighbors' */
|
|
23
|
+
|
|
24
|
+
.rio-button-group:where([data-size='xsmall']) {
|
|
25
|
+
--_between: 18px;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.rio-button-group:where([data-size='medium'], [data-size='large'], [data-size='xlarge']) {
|
|
29
|
+
--_between: 8px;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/*
|
|
33
|
+
* Connected: 2px apart, and as wide as the space it's given, shared equally by its buttons. The
|
|
34
|
+
* ends of the row keep the group's shape; the facing corners are smaller, tighten when pressed,
|
|
35
|
+
* and open up fully when the button is selected. Each button springs its two sides separately
|
|
36
|
+
* (see base/shape-morph.css).
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
.rio-button-group:where([data-variant='connected']) {
|
|
40
|
+
--_between: 2px;
|
|
41
|
+
|
|
42
|
+
display: flex;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.rio-button-group[data-variant='connected'] > .rio-button {
|
|
46
|
+
/* Small, medium, and extra small */
|
|
47
|
+
--_inner: var(--rio-shape-corner-small);
|
|
48
|
+
--_inner-pressed: var(--rio-shape-corner-extra-small);
|
|
49
|
+
/* Corners that face another button, and corners at the ends of the row */
|
|
50
|
+
--_inner-now: var(--_inner);
|
|
51
|
+
--_outer: var(--_round);
|
|
52
|
+
--_start: var(--_inner-now);
|
|
53
|
+
--_end: var(--_inner-now);
|
|
54
|
+
|
|
55
|
+
flex: 1 1 0;
|
|
56
|
+
/* The corners show these targets (button.css). */
|
|
57
|
+
--rio-shape-morph-start-target: var(--_start);
|
|
58
|
+
--rio-shape-morph-end-target: var(--_end);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.rio-button-group[data-variant='connected'] > .rio-button:where([data-size='large']) {
|
|
62
|
+
--_inner: var(--rio-shape-corner-large);
|
|
63
|
+
--_inner-pressed: var(--rio-shape-corner-medium);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.rio-button-group[data-variant='connected'] > .rio-button:where([data-size='xlarge']) {
|
|
67
|
+
--_inner: var(--rio-shape-corner-large-increased);
|
|
68
|
+
--_inner-pressed: var(--rio-shape-corner-large);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/* A square group's ends use the same radius as its facing corners. */
|
|
72
|
+
.rio-button-group[data-variant='connected'] > .rio-button[data-shape='square'] {
|
|
73
|
+
--_outer: var(--_inner);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.rio-button-group[data-variant='connected'] > .rio-button:first-child {
|
|
77
|
+
--_start: var(--_outer);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.rio-button-group[data-variant='connected'] > .rio-button:last-child {
|
|
81
|
+
--_end: var(--_outer);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.rio-button-group[data-variant='connected'] > .rio-button[data-selected='true'] {
|
|
85
|
+
--_inner-now: var(--_round);
|
|
86
|
+
--_outer: var(--_round);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* After selected, so a pressed selected button still tightens its facing corners */
|
|
90
|
+
.rio-button-group[data-variant='connected'] > .rio-button[data-pressed] {
|
|
91
|
+
--_inner-now: var(--_inner-pressed);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/* Extra small and small icon buttons keep a 48px minimum width, matching their target. */
|
|
95
|
+
.rio-button-group[data-variant='connected']
|
|
96
|
+
> .rio-icon-button:where([data-size='xsmall'], [data-size='small']) {
|
|
97
|
+
min-inline-size: 48px;
|
|
98
|
+
}
|
package/src/button.css
CHANGED
|
@@ -42,9 +42,19 @@
|
|
|
42
42
|
block-size: var(--_height);
|
|
43
43
|
padding-inline: var(--_padding);
|
|
44
44
|
border: var(--_outline-width) solid var(--_outline);
|
|
45
|
-
/*
|
|
45
|
+
/*
|
|
46
|
+
* The shape-morph primitive springs the inline radii toward these targets. The corners show the
|
|
47
|
+
* targets, not `--_radius`: when the state changes, a target holds its old value until the
|
|
48
|
+
* spring takes over (see `transition` below), so the new shape doesn't flash first. Button
|
|
49
|
+
* groups and split buttons set the per-side targets.
|
|
50
|
+
*/
|
|
46
51
|
--rio-shape-morph-target: var(--_radius);
|
|
47
|
-
|
|
52
|
+
--rio-shape-morph-start-target: var(--rio-shape-morph-target);
|
|
53
|
+
--rio-shape-morph-end-target: var(--rio-shape-morph-target);
|
|
54
|
+
border-start-start-radius: var(--rio-shape-morph-start-target);
|
|
55
|
+
border-end-start-radius: var(--rio-shape-morph-start-target);
|
|
56
|
+
border-start-end-radius: var(--rio-shape-morph-end-target);
|
|
57
|
+
border-end-end-radius: var(--rio-shape-morph-end-target);
|
|
48
58
|
background-color: var(--_container);
|
|
49
59
|
box-shadow: var(--_elevation);
|
|
50
60
|
color: var(--_content);
|
|
@@ -54,11 +64,20 @@
|
|
|
54
64
|
vertical-align: middle;
|
|
55
65
|
cursor: pointer;
|
|
56
66
|
user-select: none;
|
|
57
|
-
/*
|
|
67
|
+
/*
|
|
68
|
+
* No border-radius transition: corners move with the fast-spatial spring (see
|
|
69
|
+
* base/shape-morph.css). The spring targets get an instant transition instead, which is how the
|
|
70
|
+
* spring sees them change (core's spring-property). `--rio-spring-targets` is public: an app
|
|
71
|
+
* that sets its own `transition` on a button keeps the morphing by including it, and
|
|
72
|
+
* stylesheets that spring more targets on a button extend it.
|
|
73
|
+
*/
|
|
74
|
+
--rio-spring-targets:
|
|
75
|
+
--rio-shape-morph-start-target 1ms step-end, --rio-shape-morph-end-target 1ms step-end;
|
|
58
76
|
transition:
|
|
59
77
|
background-color var(--rio-motion-fast-effects),
|
|
60
78
|
color var(--rio-motion-fast-effects),
|
|
61
|
-
box-shadow var(--rio-motion-fast-effects)
|
|
79
|
+
box-shadow var(--rio-motion-fast-effects),
|
|
80
|
+
var(--rio-spring-targets);
|
|
62
81
|
}
|
|
63
82
|
|
|
64
83
|
/* Sizes */
|
|
@@ -189,7 +208,6 @@
|
|
|
189
208
|
|
|
190
209
|
.rio-button[data-pressed] {
|
|
191
210
|
--rio-shape-morph-target: var(--_pressed);
|
|
192
|
-
border-radius: var(--_pressed);
|
|
193
211
|
box-shadow: var(--_elevation);
|
|
194
212
|
}
|
|
195
213
|
|
|
@@ -237,8 +255,10 @@
|
|
|
237
255
|
/* Extra small and small buttons are shorter than the spec's 48px minimum target. */
|
|
238
256
|
.rio-button__touch {
|
|
239
257
|
position: absolute;
|
|
240
|
-
|
|
241
|
-
|
|
258
|
+
/* Physical, like `translate`: a logical start would flip in right-to-left layouts and push the
|
|
259
|
+
target off the button. */
|
|
260
|
+
top: 50%;
|
|
261
|
+
left: 50%;
|
|
242
262
|
inline-size: max(100%, 48px);
|
|
243
263
|
block-size: max(100%, 48px);
|
|
244
264
|
translate: -50% -50%;
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* M3E split button: a leading button and a trailing menu button, 2px apart. Both are buttons
|
|
3
|
+
* (`button.css`), so they keep the button's sizes, colors, elevation, disabled rules, state layer,
|
|
4
|
+
* ripple, and touch target. This file adds what differs: the paddings, the trailing button's
|
|
5
|
+
* width, the corners, and the menu icon. `createSplitButton` from `@rio-m3e/core` sets the
|
|
6
|
+
* attributes, and the buttons carry `data-size`, `data-variant`, and, on the trailing button,
|
|
7
|
+
* `data-open`.
|
|
8
|
+
*
|
|
9
|
+
* Values come from Material Web's component tokens (`_md-comp-split-button-*.scss`, Material 3
|
|
10
|
+
* v34.0.21). The menu icon's offset comes from the spec page's measurements, and its direction
|
|
11
|
+
* (toward the start) from the M3 Design Kit.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
@property --rio-split-button-menu-turn-target {
|
|
15
|
+
syntax: '<angle>';
|
|
16
|
+
inherits: false;
|
|
17
|
+
initial-value: 0deg;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@property --rio-split-button-menu-shift-target {
|
|
21
|
+
syntax: '<length>';
|
|
22
|
+
inherits: false;
|
|
23
|
+
initial-value: 0px;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.rio-split-button {
|
|
27
|
+
display: inline-flex;
|
|
28
|
+
align-items: center;
|
|
29
|
+
gap: 2px;
|
|
30
|
+
vertical-align: middle;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/*
|
|
34
|
+
* Both buttons: the corners at the ends of the split button are round, and the facing ones are
|
|
35
|
+
* small. Hovering, focusing, or pressing a button rounds its facing corners more, and opening the
|
|
36
|
+
* menu rounds the trailing button fully. Each side springs on its own (see base/shape-morph.css).
|
|
37
|
+
*/
|
|
38
|
+
.rio-split-button > .rio-button {
|
|
39
|
+
/* Small */
|
|
40
|
+
--_lead-start: 16px;
|
|
41
|
+
--_lead-end: 12px;
|
|
42
|
+
--_menu-size: 22px;
|
|
43
|
+
--_menu-padding: 13px;
|
|
44
|
+
--_menu-offset: 1px;
|
|
45
|
+
--_inner: var(--rio-shape-corner-extra-small);
|
|
46
|
+
--_inner-active: var(--rio-shape-corner-medium);
|
|
47
|
+
|
|
48
|
+
--_inner-now: var(--_inner);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/*
|
|
52
|
+
* `[data-variant]` is always there; it lifts this above button.css's per-side defaults in any
|
|
53
|
+
* order. The corners show these targets (button.css).
|
|
54
|
+
*/
|
|
55
|
+
.rio-split-button > .rio-button[data-variant] {
|
|
56
|
+
--rio-shape-morph-start-target: var(--_start);
|
|
57
|
+
--rio-shape-morph-end-target: var(--_end);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.rio-split-button > .rio-button:where([data-size='xsmall']) {
|
|
61
|
+
--_lead-start: 12px;
|
|
62
|
+
--_lead-end: 10px;
|
|
63
|
+
--_inner-active: var(--rio-shape-corner-small);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.rio-split-button > .rio-button:where([data-size='medium']) {
|
|
67
|
+
--_lead-start: 24px;
|
|
68
|
+
--_lead-end: 24px;
|
|
69
|
+
--_menu-size: 26px;
|
|
70
|
+
--_menu-padding: 15px;
|
|
71
|
+
--_menu-offset: 2px;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.rio-split-button > .rio-button:where([data-size='large']) {
|
|
75
|
+
--_lead-start: 48px;
|
|
76
|
+
--_lead-end: 48px;
|
|
77
|
+
--_menu-size: 38px;
|
|
78
|
+
--_menu-padding: 29px;
|
|
79
|
+
--_menu-offset: 3px;
|
|
80
|
+
--_inner: var(--rio-shape-corner-small);
|
|
81
|
+
--_inner-active: var(--rio-shape-corner-large-increased);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.rio-split-button > .rio-button:where([data-size='xlarge']) {
|
|
85
|
+
--_lead-start: 64px;
|
|
86
|
+
--_lead-end: 64px;
|
|
87
|
+
--_menu-size: 50px;
|
|
88
|
+
--_menu-padding: 43px;
|
|
89
|
+
--_menu-offset: 6px;
|
|
90
|
+
--_inner: var(--rio-shape-corner-medium);
|
|
91
|
+
--_inner-active: var(--rio-shape-corner-large-increased);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
@media (hover: hover) {
|
|
95
|
+
.rio-split-button > .rio-button:hover {
|
|
96
|
+
--_inner-now: var(--_inner-active);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.rio-split-button > .rio-button:is(:focus-visible, [data-pressed]) {
|
|
101
|
+
--_inner-now: var(--_inner-active);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/*
|
|
105
|
+
* Disabled buttons don't react, so their corners stay put. Being open still shows (that rule comes
|
|
106
|
+
* later): a disabled toggle button keeps its selected shape too.
|
|
107
|
+
*/
|
|
108
|
+
.rio-split-button > .rio-button:is(:disabled, [aria-disabled='true']) {
|
|
109
|
+
--_inner-now: var(--_inner);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* Leading button */
|
|
113
|
+
|
|
114
|
+
.rio-split-button > .rio-split-button__leading {
|
|
115
|
+
--_start: var(--_round);
|
|
116
|
+
--_end: var(--_inner-now);
|
|
117
|
+
|
|
118
|
+
padding-inline: var(--_lead-start) var(--_lead-end);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/* Trailing button: a square, or 48px wide when shorter, with the menu icon in it */
|
|
122
|
+
|
|
123
|
+
.rio-split-button > .rio-split-button__trailing {
|
|
124
|
+
--_start: var(--_inner-now);
|
|
125
|
+
--_end: var(--_round);
|
|
126
|
+
--rio-split-button-menu-shift-target: var(--_menu-offset);
|
|
127
|
+
/* Toward the start: left, or right in right-to-left layouts */
|
|
128
|
+
--_start-sign: -1;
|
|
129
|
+
|
|
130
|
+
inline-size: calc(var(--_menu-size) + 2 * var(--_menu-padding));
|
|
131
|
+
padding: 0;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.rio-split-button > .rio-split-button__trailing:dir(rtl) {
|
|
135
|
+
--_start-sign: 1;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/*
|
|
139
|
+
* Open: fully round, with the icon centered and turned half a circle, its point swinging through
|
|
140
|
+
* the start side, toward the leading button. The color doesn't change; a state layer shows
|
|
141
|
+
* instead, at the pressed opacity.
|
|
142
|
+
*/
|
|
143
|
+
.rio-split-button > .rio-split-button__trailing[data-open] {
|
|
144
|
+
--_inner-now: var(--_round);
|
|
145
|
+
--rio-split-button-menu-turn-target: 180deg;
|
|
146
|
+
--rio-split-button-menu-shift-target: 0px;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.rio-split-button > .rio-split-button__trailing[data-open]:dir(rtl) {
|
|
150
|
+
--rio-split-button-menu-turn-target: -180deg;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.rio-split-button
|
|
154
|
+
> .rio-split-button__trailing[data-open]:not(:disabled, [aria-disabled='true'])::before {
|
|
155
|
+
opacity: var(--rio-state-pressed-state-layer-opacity);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/*
|
|
159
|
+
* The springs in `attachSplitButtonMenuIcon` write `--_menu-turn` and `--_menu-shift` while they
|
|
160
|
+
* move; at rest the targets apply. The targets are registered and don't inherit, so they are
|
|
161
|
+
* passed down through these.
|
|
162
|
+
*/
|
|
163
|
+
.rio-split-button > .rio-split-button__trailing {
|
|
164
|
+
--_menu-turn-rest: var(--rio-split-button-menu-turn-target);
|
|
165
|
+
--_menu-shift-rest: var(--rio-split-button-menu-shift-target);
|
|
166
|
+
/* The button's spring targets (button.css), and the menu icon's. */
|
|
167
|
+
--rio-spring-targets:
|
|
168
|
+
--rio-shape-morph-start-target 1ms step-end, --rio-shape-morph-end-target 1ms step-end,
|
|
169
|
+
--rio-split-button-menu-turn-target 1ms step-end,
|
|
170
|
+
--rio-split-button-menu-shift-target 1ms step-end;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.rio-split-button__menu-icon {
|
|
174
|
+
display: inline-flex;
|
|
175
|
+
flex: none;
|
|
176
|
+
inline-size: var(--_menu-size);
|
|
177
|
+
block-size: var(--_menu-size);
|
|
178
|
+
rotate: var(--_menu-turn, var(--_menu-turn-rest));
|
|
179
|
+
translate: calc(var(--_menu-shift, var(--_menu-shift-rest)) * var(--_start-sign)) 0;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.rio-split-button__menu-icon > :is(svg, img) {
|
|
183
|
+
inline-size: 100%;
|
|
184
|
+
block-size: 100%;
|
|
185
|
+
}
|
package/src/switch.css
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* Values come from Material Web's component tokens (`_md-comp-switch.scss`, Material 3 v34.0.21),
|
|
5
5
|
* which match the spec's measurements table. The handle's center and size are declared as targets
|
|
6
6
|
* for each state; `attachSwitchHandle` from `@rio-m3e/core` springs `--_handle-x` and
|
|
7
|
-
* `--_handle-size` toward them
|
|
7
|
+
* `--_handle-size` toward them, which show the targets at rest. The targets get an instant
|
|
8
|
+
* transition so the springs see them change. Without JavaScript the handle simply jumps.
|
|
8
9
|
*
|
|
9
10
|
* The root carries `data-selected`, plus `data-pressed` (from the ripple), `data-dragging` (from
|
|
10
11
|
* the drag), and `data-icon` when the handle shows an icon. State rules sit inside `:where()` so
|
|
@@ -72,9 +73,14 @@
|
|
|
72
73
|
/* Horizontal drags belong to the handle; vertical ones still scroll the page. */
|
|
73
74
|
touch-action: pan-y;
|
|
74
75
|
-webkit-tap-highlight-color: transparent;
|
|
76
|
+
/* The handle's spring targets get an instant transition, which is how the springs see them
|
|
77
|
+
change (core's spring-property). Public, as on the button (button.css). */
|
|
78
|
+
--rio-spring-targets:
|
|
79
|
+
--rio-switch-handle-x-target 1ms step-end, --rio-switch-handle-size-target 1ms step-end;
|
|
75
80
|
transition:
|
|
76
81
|
background-color var(--rio-motion-fast-effects),
|
|
77
|
-
border-color var(--rio-motion-fast-effects)
|
|
82
|
+
border-color var(--rio-motion-fast-effects),
|
|
83
|
+
var(--rio-spring-targets);
|
|
78
84
|
}
|
|
79
85
|
|
|
80
86
|
/* States */
|
|
@@ -196,8 +202,10 @@
|
|
|
196
202
|
/* The track is 32px tall, below the spec's 48px minimum target. */
|
|
197
203
|
.rio-switch__touch {
|
|
198
204
|
position: absolute;
|
|
199
|
-
|
|
200
|
-
|
|
205
|
+
/* Physical, like `translate`: a logical start would flip in right-to-left layouts and push the
|
|
206
|
+
target off the switch. */
|
|
207
|
+
top: 50%;
|
|
208
|
+
left: 50%;
|
|
201
209
|
inline-size: max(100%, 48px);
|
|
202
210
|
block-size: max(100%, 48px);
|
|
203
211
|
translate: -50% -50%;
|