UNPKG

7.06 kBSCSSView Raw
1//
2// Copyright 2021 Google Inc.
3//
4// Permission is hereby granted, free of charge, to any person obtaining a copy
5// of this software and associated documentation files (the "Software"), to deal
6// in the Software without restriction, including without limitation the rights
7// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8// copies of the Software, and to permit persons to whom the Software is
9// furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20// THE SOFTWARE.
21//
22
23// stylelint-disable selector-class-pattern --
24// Selector '.mdc-*' should only be used in this project.
25
26@use '@material/animation/animation';
27@use '@material/elevation/elevation';
28@use '@material/ripple/ripple';
29@use '@material/rtl/rtl';
30@use '@material/theme/gss';
31
32$animation-duration: 75ms;
33$icon-exit-duration: 0.4 * $animation-duration;
34$icon-enter-duration: $animation-duration - $icon-exit-duration;
35$ripple-target: '.mdc-switch__ripple';
36
37@mixin static-styles() {
38 @include static-styles-without-ripple();
39
40 .mdc-switch {
41 @include ripple.common; // COPYBARA_COMMENT_THIS_LINE
42 @include ripple.surface($ripple-target: $ripple-target);
43 @include ripple.radius-unbounded($ripple-target: $ripple-target);
44 }
45}
46
47@mixin static-styles-without-ripple() {
48 @include elevation.overlay-common; // COPYBARA_COMMENT_THIS_LINE
49
50 .mdc-switch {
51 @include root;
52
53 &:disabled {
54 @include disabled;
55 }
56 }
57
58 .mdc-switch__track {
59 @include track;
60 @include track-off;
61
62 .mdc-switch--selected & {
63 @include track-on;
64 }
65 }
66
67 .mdc-switch__handle-track {
68 @include handle-track;
69 @include handle-track-off;
70
71 .mdc-switch--selected & {
72 @include handle-track-on;
73 }
74 }
75
76 .mdc-switch__handle {
77 @include handle;
78 }
79
80 .mdc-switch__shadow {
81 @include shadow;
82 }
83
84 .mdc-elevation-overlay {
85 @include overlay;
86 }
87
88 .mdc-switch__ripple {
89 @include ripple;
90
91 .mdc-switch:disabled & {
92 @include ripple-disabled;
93 }
94 }
95
96 .mdc-switch__icons {
97 @include icons;
98 }
99
100 .mdc-switch__icon {
101 @include icon;
102 @include icon-hidden;
103 }
104
105 .mdc-switch--selected .mdc-switch__icon--on,
106 .mdc-switch--unselected .mdc-switch__icon--off {
107 @include icon-visible;
108 }
109}
110
111@mixin root() {
112 align-items: center;
113 background: none;
114 border: none;
115 cursor: pointer;
116 display: inline-flex;
117 flex-shrink: 0; // Stop from collapsing in flex containers
118 margin: 0;
119 outline: none;
120 overflow: visible;
121 padding: 0;
122 position: relative;
123}
124
125@mixin disabled() {
126 cursor: default;
127 pointer-events: none;
128}
129
130@mixin track() {
131 overflow: hidden;
132 position: relative;
133 width: 100%;
134
135 &::before,
136 &::after {
137 border: 1px solid transparent; // high contrast mode
138 border-radius: inherit;
139 box-sizing: border-box;
140 content: '';
141 height: 100%;
142 @include gss.annotate($noflip: true);
143 left: 0;
144 position: absolute;
145 width: 100%;
146 }
147}
148
149@mixin track-on() {
150 &::before {
151 transition: animation.exit-temporary(transform, $animation-duration);
152 transform: translateX(100%);
153 @include rtl.rtl {
154 transform: translateX(-100%);
155 }
156 }
157
158 &::after {
159 transition: animation.enter(transform, $animation-duration);
160 transform: translateX(0);
161 }
162}
163
164@mixin track-off() {
165 &::before {
166 transition: animation.enter(transform, $animation-duration);
167 transform: translateX(0);
168 }
169
170 &::after {
171 transition: animation.exit-temporary(transform, $animation-duration);
172 transform: translateX(-100%);
173 @include rtl.rtl {
174 transform: translateX(100%);
175 }
176 }
177}
178
179@mixin handle-track() {
180 height: 100%;
181 // The handle track is used to move the handle across the width of the switch
182 // and may overflow the bounds of the component. It should not be used for
183 // pointer events.
184 pointer-events: none;
185 position: absolute;
186 top: 0; // Needed for IE11
187 transition: animation.standard(transform, $animation-duration);
188 // IE11 needs explicit left/right
189 @include rtl.reflexive(left, 0, right, auto);
190}
191
192@mixin handle-track-on() {
193 transform: translateX(100%);
194
195 @include rtl.rtl {
196 transform: translateX(-100%);
197 }
198}
199
200@mixin handle-track-off() {
201 transform: translateX(0);
202}
203
204@mixin handle() {
205 display: flex;
206 pointer-events: auto;
207 position: absolute;
208 top: 50%;
209 transform: translateY(-50%);
210 // IE11 needs explicit left/right
211 @include rtl.reflexive(left, 0, right, auto);
212
213 &::before,
214 &::after {
215 border: 1px solid transparent; // high contrast mode
216 border-radius: inherit;
217 box-sizing: border-box;
218 content: '';
219 width: 100%;
220 height: 100%;
221 @include gss.annotate($noflip: true);
222 left: 0;
223 position: absolute;
224 top: 0; // IE11 fix
225 transition: animation.standard(background-color, $animation-duration),
226 animation.standard(border-color, $animation-duration);
227 // Move the handle background colors beneath the shadow overlay color,
228 // rather than move the overlay on top of the handle with a positive
229 // z-index, which would require moving all other content on top of the
230 // overlay with an even greater z-index.
231 z-index: -1;
232 }
233}
234
235@mixin shadow() {
236 border-radius: inherit;
237 bottom: 0;
238 @include gss.annotate($noflip: true);
239 left: 0;
240 position: absolute;
241 @include gss.annotate($noflip: true);
242 right: 0;
243 top: 0;
244}
245
246@mixin overlay() {
247 bottom: 0;
248 @include gss.annotate($noflip: true);
249 left: 0;
250 @include gss.annotate($noflip: true);
251 right: 0;
252 top: 0;
253}
254
255@mixin ripple() {
256 @include gss.annotate($noflip: true);
257 left: 50%;
258 position: absolute;
259 top: 50%;
260 transform: translate(-50%, -50%);
261 // Move ripple beneath shadow overlay and handle background colors (see
262 // handle() mixin for explanation).
263 z-index: -1;
264}
265
266@mixin ripple-disabled {
267 display: none;
268}
269
270@mixin icons() {
271 height: 100%;
272 position: relative;
273 width: 100%;
274 z-index: 1;
275}
276
277@mixin icon() {
278 bottom: 0;
279 @include gss.annotate($noflip: true);
280 left: 0;
281 // IE11 needs top/right/bottom/left + margin instead of translate(-50%, -50%)
282 // because of SVG centering issues
283 margin: auto;
284 position: absolute;
285 @include gss.annotate($noflip: true);
286 right: 0;
287 top: 0;
288}
289
290@mixin icon-hidden() {
291 opacity: 0;
292 transition: animation.exit-permanent(opacity, $icon-exit-duration);
293}
294
295@mixin icon-visible() {
296 opacity: 1;
297 transition: animation.enter(
298 opacity,
299 $icon-enter-duration,
300 $delay: $icon-exit-duration
301 );
302}