1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 | @use 'sass:math';
|
27 | @use 'sass:list';
|
28 | @use 'sass:map';
|
29 | @use 'sass:string';
|
30 | @use '@material/feature-targeting/feature-targeting';
|
31 | @use '@material/theme/custom-properties';
|
32 | @use '@material/theme/keys';
|
33 | @use '@material/theme/theme';
|
34 |
|
35 |
|
36 |
|
37 | @function set-styles_($base-styles, $scale-styles, $override-styles) {
|
38 | $options: (
|
39 | custom-property-prefix: typography,
|
40 | );
|
41 |
|
42 | $base-styles: keys.set-values($base-styles, $options: $options);
|
43 |
|
44 | @each $style, $style-props in $scale-styles {
|
45 | @each $base-key in map.keys($base-styles) {
|
46 |
|
47 | $unused: keys.add-link(keys.combine($style, $base-key), $base-key);
|
48 | }
|
49 |
|
50 |
|
51 | $style-props: map.merge($base-styles, $style-props);
|
52 |
|
53 |
|
54 | $style-props: map.merge($style-props, map.get($override-styles, $style));
|
55 |
|
56 |
|
57 | @each $property, $value in $style-props {
|
58 | $unused: keys.set-value(
|
59 | keys.combine($style, $property),
|
60 | $value,
|
61 | $options: $options
|
62 | );
|
63 | }
|
64 |
|
65 |
|
66 | $scale-styles: map.merge($scale-styles, (#{$style}: $style-props));
|
67 | }
|
68 |
|
69 | @return $scale-styles;
|
70 | }
|
71 |
|
72 | @function get-letter-spacing_($tracking, $font-size) {
|
73 | @return math.div($tracking, $font-size * 16) * 1em;
|
74 | }
|
75 |
|
76 | @function px-to-rem($px) {
|
77 | @if custom-properties.is-custom-prop($px) {
|
78 | @return custom-properties.set-fallback(
|
79 | $px,
|
80 | _px-to-rem(custom-properties.get-fallback($px))
|
81 | );
|
82 | }
|
83 | @return _px-to-rem($px);
|
84 | }
|
85 |
|
86 | @function _px-to-rem($px) {
|
87 | @if $px == null {
|
88 | @return null;
|
89 | }
|
90 | @return math.div($px, 16px) * 1rem;
|
91 | }
|
92 |
|
93 | $font-family: string.unquote('Roboto, sans-serif') !default;
|
94 |
|
95 |
|
96 | $styles-headline1: () !default;
|
97 | $styles-headline2: () !default;
|
98 | $styles-headline3: () !default;
|
99 | $styles-headline4: () !default;
|
100 | $styles-headline5: () !default;
|
101 | $styles-headline6: () !default;
|
102 | $styles-subtitle1: () !default;
|
103 | $styles-subtitle2: () !default;
|
104 | $styles-body1: () !default;
|
105 | $styles-body2: () !default;
|
106 | $styles-caption: () !default;
|
107 | $styles-button: () !default;
|
108 | $styles-overline: () !default;
|
109 |
|
110 |
|
111 |
|
112 | $base: (
|
113 | font-family: $font-family,
|
114 | ) !default;
|
115 |
|
116 | $font-weight-values: (
|
117 | thin: 100,
|
118 | light: 300,
|
119 | regular: 400,
|
120 | medium: 500,
|
121 | bold: 700,
|
122 | black: 900,
|
123 | ) !default;
|
124 |
|
125 |
|
126 |
|
127 | $styles: set-styles_(
|
128 | $base,
|
129 | (
|
130 | headline1: (
|
131 | font-size: px-to-rem(96px),
|
132 | line-height: px-to-rem(96px),
|
133 | font-weight: map.get($font-weight-values, light),
|
134 | letter-spacing: get-letter-spacing_(-1.5, 6),
|
135 | text-decoration: inherit,
|
136 | text-transform: inherit,
|
137 | ),
|
138 | headline2: (
|
139 | font-size: px-to-rem(60px),
|
140 | line-height: px-to-rem(60px),
|
141 | font-weight: map.get($font-weight-values, light),
|
142 | letter-spacing: get-letter-spacing_(-0.5, 3.75),
|
143 | text-decoration: inherit,
|
144 | text-transform: inherit,
|
145 | ),
|
146 | headline3: (
|
147 | font-size: px-to-rem(48px),
|
148 | line-height: px-to-rem(50px),
|
149 | font-weight: map.get($font-weight-values, regular),
|
150 | letter-spacing: normal,
|
151 | text-decoration: inherit,
|
152 | text-transform: inherit,
|
153 | ),
|
154 | headline4: (
|
155 | font-size: px-to-rem(34px),
|
156 | line-height: px-to-rem(40px),
|
157 | font-weight: map.get($font-weight-values, regular),
|
158 | letter-spacing: get-letter-spacing_(0.25, 2.125),
|
159 | text-decoration: inherit,
|
160 | text-transform: inherit,
|
161 | ),
|
162 | headline5: (
|
163 | font-size: px-to-rem(24px),
|
164 | line-height: px-to-rem(32px),
|
165 | font-weight: map.get($font-weight-values, regular),
|
166 | letter-spacing: normal,
|
167 | text-decoration: inherit,
|
168 | text-transform: inherit,
|
169 | ),
|
170 | headline6: (
|
171 | font-size: px-to-rem(20px),
|
172 | line-height: px-to-rem(32px),
|
173 | font-weight: map.get($font-weight-values, medium),
|
174 | letter-spacing: get-letter-spacing_(0.25, 1.25),
|
175 | text-decoration: inherit,
|
176 | text-transform: inherit,
|
177 | ),
|
178 | subtitle1: (
|
179 | font-size: px-to-rem(16px),
|
180 | line-height: px-to-rem(28px),
|
181 | font-weight: map.get($font-weight-values, regular),
|
182 | letter-spacing: get-letter-spacing_(0.15, 1),
|
183 | text-decoration: inherit,
|
184 | text-transform: inherit,
|
185 | ),
|
186 | subtitle2: (
|
187 | font-size: px-to-rem(14px),
|
188 | line-height: px-to-rem(22px),
|
189 | font-weight: map.get($font-weight-values, medium),
|
190 | letter-spacing: get-letter-spacing_(0.1, 0.875),
|
191 | text-decoration: inherit,
|
192 | text-transform: inherit,
|
193 | ),
|
194 | body1: (
|
195 | font-size: px-to-rem(16px),
|
196 | line-height: px-to-rem(24px),
|
197 | font-weight: map.get($font-weight-values, regular),
|
198 | letter-spacing: get-letter-spacing_(0.5, 1),
|
199 | text-decoration: inherit,
|
200 | text-transform: inherit,
|
201 | ),
|
202 | body2: (
|
203 | font-size: px-to-rem(14px),
|
204 | line-height: px-to-rem(20px),
|
205 | font-weight: map.get($font-weight-values, regular),
|
206 | letter-spacing: get-letter-spacing_(0.25, 0.875),
|
207 | text-decoration: inherit,
|
208 | text-transform: inherit,
|
209 | ),
|
210 | caption: (
|
211 | font-size: px-to-rem(12px),
|
212 | line-height: px-to-rem(20px),
|
213 | font-weight: map.get($font-weight-values, regular),
|
214 | letter-spacing: get-letter-spacing_(0.4, 0.75),
|
215 | text-decoration: inherit,
|
216 | text-transform: inherit,
|
217 | ),
|
218 | button: (
|
219 | font-size: px-to-rem(14px),
|
220 | line-height: px-to-rem(36px),
|
221 | font-weight: map.get($font-weight-values, medium),
|
222 | letter-spacing: get-letter-spacing_(1.25, 0.875),
|
223 | text-decoration: none,
|
224 | text-transform: uppercase,
|
225 | ),
|
226 | overline: (
|
227 | font-size: px-to-rem(12px),
|
228 | line-height: px-to-rem(32px),
|
229 | font-weight: map.get($font-weight-values, medium),
|
230 | letter-spacing: get-letter-spacing_(2, 0.75),
|
231 | text-decoration: none,
|
232 | text-transform: uppercase,
|
233 | ),
|
234 | ),
|
235 | (
|
236 | headline1: $styles-headline1,
|
237 | headline2: $styles-headline2,
|
238 | headline3: $styles-headline3,
|
239 | headline4: $styles-headline4,
|
240 | headline5: $styles-headline5,
|
241 | headline6: $styles-headline6,
|
242 | subtitle1: $styles-subtitle1,
|
243 | subtitle2: $styles-subtitle2,
|
244 | body1: $styles-body1,
|
245 | body2: $styles-body2,
|
246 | caption: $styles-caption,
|
247 | button: $styles-button,
|
248 | overline: $styles-overline,
|
249 | )
|
250 | ) !default;
|
251 |
|
252 |
|
253 |
|
254 | $_styles-copy: $styles;
|
255 |
|
256 | @function is-typography-style($style) {
|
257 | @return map.has-key($styles, $style);
|
258 | }
|
259 |
|
260 | @function get-typography-styles() {
|
261 | @return map.keys($styles);
|
262 | }
|
263 |
|
264 | @mixin core-styles($query: feature-targeting.all()) {
|
265 | .mdc-typography {
|
266 | @include base($query: $query);
|
267 | }
|
268 |
|
269 | @each $style in get-typography-styles() {
|
270 | .mdc-typography--#{$style} {
|
271 | @include typography($style, $query: $query);
|
272 | }
|
273 | }
|
274 | }
|
275 |
|
276 | @mixin base($query: feature-targeting.all()) {
|
277 | $feat-typography: feature-targeting.create-target($query, typography);
|
278 |
|
279 | @include smooth-font($query: $query);
|
280 | @include feature-targeting.targets($feat-typography) {
|
281 | @include theme.property(font-family, font-family);
|
282 | }
|
283 | }
|
284 |
|
285 | @mixin typography($style, $query: feature-targeting.all(), $exclude-props: ()) {
|
286 | $feat-typography: feature-targeting.create-target($query, typography);
|
287 |
|
288 | @if not is-typography-style($style) {
|
289 | @error "Invalid style specified! #{$style} doesn't exist. Choose one of #{get-typography-styles()}";
|
290 | }
|
291 |
|
292 | @include smooth-font($query: $query);
|
293 | @include feature-targeting.targets($feat-typography) {
|
294 | @each $key in keys.get-keys($style) {
|
295 |
|
296 |
|
297 |
|
298 | $property: string.slice($key, string.index($key, '-') + 1);
|
299 | @if list.index($exclude-props, $property) == null {
|
300 | $current-global-value: map.get($styles, $style, $property);
|
301 | $configured-global-value: map.get($_styles-copy, $style, $property);
|
302 | @if $current-global-value != $configured-global-value {
|
303 |
|
304 |
|
305 | @if $current-global-value {
|
306 |
|
307 | $custom-prop: keys.create-custom-property($key);
|
308 | $custom-prop: custom-properties.set-fallback(
|
309 | $custom-prop,
|
310 | $current-global-value
|
311 | );
|
312 | @include theme.property($property, $custom-prop);
|
313 | }
|
314 | } @else {
|
315 |
|
316 |
|
317 | @include theme.property($property, $key);
|
318 | }
|
319 | }
|
320 | }
|
321 | }
|
322 | }
|
323 |
|
324 |
|
325 | @mixin smooth-font($query: feature-targeting.all()) {
|
326 | $feat-typography: feature-targeting.create-target($query, typography);
|
327 |
|
328 | @include feature-targeting.targets($feat-typography) {
|
329 | -moz-osx-font-smoothing: grayscale;
|
330 | -webkit-font-smoothing: antialiased;
|
331 | }
|
332 | }
|
333 |
|
334 |
|
335 | @mixin overflow-ellipsis($query: feature-targeting.all()) {
|
336 | $feat-structure: feature-targeting.create-target($query, structure);
|
337 |
|
338 | @include feature-targeting.targets($feat-structure) {
|
339 | text-overflow: ellipsis;
|
340 | white-space: nowrap;
|
341 | overflow: hidden;
|
342 | }
|
343 | }
|
344 |
|
345 |
|
346 |
|
347 |
|
348 |
|
349 |
|
350 |
|
351 |
|
352 |
|
353 |
|
354 |
|
355 |
|
356 |
|
357 | @mixin baseline(
|
358 | $top: 0,
|
359 | $bottom: 0,
|
360 | $display: block,
|
361 | $query: feature-targeting.all()
|
362 | ) {
|
363 | $validDisplayTypes: (flex, inline-flex, block, inline-block);
|
364 |
|
365 | @if list.index($validDisplayTypes, $display) == null {
|
366 | @error "mdc-typography: invalid display specified! #{$display} must be one of #{$validDisplayTypes}";
|
367 | }
|
368 |
|
369 | $isFlexbox: $display == 'flex' or $display == 'inline-flex';
|
370 | $feat-structure: feature-targeting.create-target($query, structure);
|
371 |
|
372 | @include feature-targeting.targets($feat-structure) {
|
373 | display: $display;
|
374 |
|
375 | @if $isFlexbox {
|
376 | align-items: baseline;
|
377 | }
|
378 | }
|
379 |
|
380 | @if $top > 0 {
|
381 | @include baseline-top($top, $query: $query);
|
382 | }
|
383 |
|
384 | @if $bottom > 0 {
|
385 | @if $isFlexbox {
|
386 | @error "mdc-typography: invalid baseline with display type. #{$display} cannot specifiy $bottom. Add a separate child element with its own $bottom.";
|
387 | }
|
388 |
|
389 | @include baseline-bottom($bottom, $query: $query);
|
390 | }
|
391 | }
|
392 |
|
393 |
|
394 |
|
395 |
|
396 |
|
397 |
|
398 |
|
399 |
|
400 |
|
401 |
|
402 |
|
403 |
|
404 |
|
405 |
|
406 |
|
407 |
|
408 |
|
409 |
|
410 |
|
411 |
|
412 |
|
413 | @mixin text-baseline(
|
414 | $top: 0,
|
415 | $bottom: 0,
|
416 | $display: block,
|
417 | $lineHeight: normal,
|
418 | $query: feature-targeting.all()
|
419 | ) {
|
420 | $validDisplayTypes: (block, inline-block);
|
421 |
|
422 | @if list.index($validDisplayTypes, $display) == null {
|
423 | @error "mdc-typography: invalid display specified! #{$display} must be one of #{$validDisplayTypes}";
|
424 | }
|
425 |
|
426 | $feat-structure: feature-targeting.create-target($query, structure);
|
427 |
|
428 | @include baseline(
|
429 | $display: $display,
|
430 | $top: $top,
|
431 | $bottom: $bottom,
|
432 | $query: $query
|
433 | );
|
434 | @include feature-targeting.targets($feat-structure) {
|
435 | @if $top > 0 {
|
436 | margin-top: 0;
|
437 |
|
438 | line-height: #{$lineHeight};
|
439 | }
|
440 |
|
441 | @if $bottom > 0 {
|
442 | margin-bottom: -1 * $bottom;
|
443 | }
|
444 | }
|
445 | }
|
446 |
|
447 |
|
448 |
|
449 |
|
450 |
|
451 |
|
452 | @mixin baseline-top($distance, $query: feature-targeting.all()) {
|
453 | $feat-structure: feature-targeting.create-target($query, structure);
|
454 |
|
455 | &::before {
|
456 | @include feature-targeting.targets($feat-structure) {
|
457 | @include baseline-strut_($distance);
|
458 |
|
459 | vertical-align: 0;
|
460 | }
|
461 | }
|
462 | }
|
463 |
|
464 |
|
465 |
|
466 |
|
467 |
|
468 |
|
469 | @mixin baseline-bottom($distance, $query: feature-targeting.all()) {
|
470 | $feat-structure: feature-targeting.create-target($query, structure);
|
471 |
|
472 | &::after {
|
473 | @include feature-targeting.targets($feat-structure) {
|
474 | @include baseline-strut_($distance);
|
475 |
|
476 | vertical-align: -1 * $distance;
|
477 | }
|
478 | }
|
479 | }
|
480 |
|
481 |
|
482 |
|
483 |
|
484 |
|
485 | @mixin zero-width-prefix($query: feature-targeting.all()) {
|
486 | $feat-structure: feature-targeting.create-target($query, structure);
|
487 |
|
488 | &::before {
|
489 | @include feature-targeting.targets($feat-structure) {
|
490 | content: '\200b';
|
491 | }
|
492 | }
|
493 | }
|
494 |
|
495 | @mixin baseline-strut_($distance) {
|
496 | display: inline-block;
|
497 | width: 0;
|
498 | height: $distance;
|
499 | content: '';
|
500 | }
|
501 |
|
502 | @function get-font($typography) {
|
503 | @return map.get($styles, $typography, font-family);
|
504 | }
|
505 |
|
506 | @function get-line-height($typography) {
|
507 | @return map.get($styles, $typography, line-height);
|
508 | }
|
509 |
|
510 | @function get-size($typography) {
|
511 | @return map.get($styles, $typography, font-size);
|
512 | }
|
513 |
|
514 | @function get-weight($typography) {
|
515 | @return map.get($styles, $typography, font-weight);
|
516 | }
|
517 |
|
518 | @function get-tracking($typography) {
|
519 | @return map.get($styles, $typography, letter-spacing);
|
520 | }
|
521 |
|
522 | $_typography-theme: (
|
523 | font: null,
|
524 | line-height: null,
|
525 | size: null,
|
526 | weight: null,
|
527 | tracking: null,
|
528 | );
|
529 |
|
530 | @mixin theme-styles($theme) {
|
531 | @include theme.validate-theme-keys($_typography-theme, $theme);
|
532 |
|
533 | @include theme.property(font-family, map.get($theme, font));
|
534 | @include theme.property(line-height, map.get($theme, line-height));
|
535 | @include theme.property(font-size, map.get($theme, size));
|
536 | @include theme.property(font-weight, map.get($theme, weight));
|
537 | @include theme.property(letter-spacing, map.get($theme, tracking));
|
538 | }
|