1 | @use 'sass:map';
|
---|
2 | @use 'typography-utils';
|
---|
3 | @use '../theming/theming';
|
---|
4 |
|
---|
5 | /// Defines a typography level from the Material Design spec.
|
---|
6 | /// @param {String} $font-size The font-size for this level.
|
---|
7 | /// @param {String | Number} $line-height The line-height for this level.
|
---|
8 | /// @param {String | Number} $font-weight The font-weight for this level.
|
---|
9 | /// @param {String} $font-family The font-family for this level.
|
---|
10 | /// @param {String} $letter-spacing The letter-spacing for this level.
|
---|
11 | /// @returns {Map} A map representing the definition of this typpographic level.
|
---|
12 | @function define-typography-level(
|
---|
13 | $font-size,
|
---|
14 | $line-height: $font-size,
|
---|
15 | $font-weight: 400,
|
---|
16 | $font-family: null,
|
---|
17 | $letter-spacing: normal) {
|
---|
18 |
|
---|
19 | @return (
|
---|
20 | font-size: $font-size,
|
---|
21 | line-height: $line-height,
|
---|
22 | font-weight: $font-weight,
|
---|
23 | font-family: $font-family,
|
---|
24 | letter-spacing: $letter-spacing
|
---|
25 | );
|
---|
26 | }
|
---|
27 |
|
---|
28 | /// Defines a collection of typography levels to configure typography for an application.
|
---|
29 | /// Any level not specified defaults to the values defined in the Material Design specification:
|
---|
30 | /// https://material.io/guidelines/style/typography.html.
|
---|
31 | ///
|
---|
32 | /// Note that the Material Design specification does not describe explicit letter-spacing values.
|
---|
33 | /// The values here come from reverse engineering the Material Design examples.
|
---|
34 | /// @param {String} $font-family Default font-family for levels that don't specify font-family.
|
---|
35 | /// @param {Map} $display-4 Configuration for the "display-4" typographic level.
|
---|
36 | /// @param {Map} $display-3 Configuration for the "display-3" typographic level.
|
---|
37 | /// @param {Map} $display-2 Configuration for the "display-2" typographic level.
|
---|
38 | /// @param {Map} $display-1 Configuration for the "display-1" typographic level.
|
---|
39 | /// @param {Map} $headline Configuration for the "headline" typographic level.
|
---|
40 | /// @param {Map} $title Configuration for the "title" typographic level.
|
---|
41 | /// @param {Map} $subheading-2 Configuration for the "subheading-2" typographic level.
|
---|
42 | /// @param {Map} $subheading-1 Configuration for the "subheading-1" typographic level.
|
---|
43 | /// @param {Map} $body-2 Configuration for the "body-2" typographic level.
|
---|
44 | /// @param {Map} $body-1 Configuration for the "body-1" typographic level.
|
---|
45 | /// @param {Map} $caption Configuration for the "caption" typographic level.
|
---|
46 | /// @param {Map} $button Configuration for the "button" typographic level.
|
---|
47 | /// @param {Map} $input Configuration for the "input" typographic level.
|
---|
48 | /// @returns {Map} A typography config for the application.
|
---|
49 | @function define-typography-config(
|
---|
50 | $font-family: 'Roboto, "Helvetica Neue", sans-serif',
|
---|
51 | $display-4: define-typography-level(112px, 112px, 300, $letter-spacing: -0.05em),
|
---|
52 | $display-3: define-typography-level(56px, 56px, 400, $letter-spacing: -0.02em),
|
---|
53 | $display-2: define-typography-level(45px, 48px, 400, $letter-spacing: -0.005em),
|
---|
54 | $display-1: define-typography-level(34px, 40px, 400),
|
---|
55 | $headline: define-typography-level(24px, 32px, 400),
|
---|
56 | $title: define-typography-level(20px, 32px, 500),
|
---|
57 | $subheading-2: define-typography-level(16px, 28px, 400),
|
---|
58 | $subheading-1: define-typography-level(15px, 24px, 400),
|
---|
59 | $body-2: define-typography-level(14px, 24px, 500),
|
---|
60 | $body-1: define-typography-level(14px, 20px, 400),
|
---|
61 | $caption: define-typography-level(12px, 20px, 400),
|
---|
62 | $button: define-typography-level(14px, 14px, 500),
|
---|
63 | // Line-height must be unit-less fraction of the font-size.
|
---|
64 | $input: define-typography-level(inherit, 1.125, 400)
|
---|
65 | ) {
|
---|
66 |
|
---|
67 | // Declare an initial map with all of the levels.
|
---|
68 | $config: (
|
---|
69 | display-4: $display-4,
|
---|
70 | display-3: $display-3,
|
---|
71 | display-2: $display-2,
|
---|
72 | display-1: $display-1,
|
---|
73 | headline: $headline,
|
---|
74 | title: $title,
|
---|
75 | subheading-2: $subheading-2,
|
---|
76 | subheading-1: $subheading-1,
|
---|
77 | body-2: $body-2,
|
---|
78 | body-1: $body-1,
|
---|
79 | caption: $caption,
|
---|
80 | button: $button,
|
---|
81 | input: $input,
|
---|
82 | );
|
---|
83 |
|
---|
84 | // Loop through the levels and set the `font-family` of the ones that don't have one to the base.
|
---|
85 | // Note that Sass can't modify maps in place, which means that we need to merge and re-assign.
|
---|
86 | @each $key, $level in $config {
|
---|
87 | @if map.get($level, font-family) == null {
|
---|
88 | $new-level: map.merge($level, (font-family: $font-family));
|
---|
89 | $config: map.merge($config, ($key: $new-level));
|
---|
90 | }
|
---|
91 | }
|
---|
92 |
|
---|
93 | // Add the base font family to the config.
|
---|
94 | @return map.merge($config, (font-family: $font-family));
|
---|
95 | }
|
---|
96 |
|
---|
97 | // Whether a config is for the Material Design 2018 typography system.
|
---|
98 | @function private-typography-is-2018-config($config) {
|
---|
99 | @return map.get($config, headline-1) != null;
|
---|
100 | }
|
---|
101 |
|
---|
102 | // Whether a config is for the Material Design 2014 typography system.
|
---|
103 | @function private-typography-is-2014-config($config) {
|
---|
104 | @return map.get($config, headline) != null;
|
---|
105 | }
|
---|
106 |
|
---|
107 | // Given a config for either the 2014 or 2018 Material Design typography system,
|
---|
108 | // produces a normalized typography config for the 2014 Material Design typography system.
|
---|
109 | // 2014 - https://material.io/archive/guidelines/style/typography.html#typography-styles
|
---|
110 | // 2018 - https://material.io/design/typography/the-type-system.html#type-scale
|
---|
111 | //
|
---|
112 | // Components using this function should be migrated to normalize to the 2018 style config instead.
|
---|
113 | // New components should not use this function.
|
---|
114 | @function private-typography-to-2014-config($config) {
|
---|
115 | @if $config == null {
|
---|
116 | @return null;
|
---|
117 | }
|
---|
118 | @if not private-typography-is-2014-config($config) {
|
---|
119 | $args: (
|
---|
120 | display-4: map.get($config, headline-1),
|
---|
121 | display-3: map.get($config, headline-2),
|
---|
122 | display-2: map.get($config, headline-3),
|
---|
123 | display-1: map.get($config, headline-4),
|
---|
124 | headline: map.get($config, headline-5),
|
---|
125 | title: map.get($config, headline-6),
|
---|
126 | subheading-2: map.get($config, subtitle-1),
|
---|
127 | subheading-1: map.get($config, subtitle-2),
|
---|
128 | body-2: map.get($config, body-1),
|
---|
129 | body-1: map.get($config, body-2),
|
---|
130 | button: map.get($config, button),
|
---|
131 | caption: map.get($config, caption),
|
---|
132 | );
|
---|
133 | $non-null-args: ();
|
---|
134 | @each $key, $value in $args {
|
---|
135 | @if $value != null {
|
---|
136 | $non-null-args: map.merge($non-null-args, ($key: $value));
|
---|
137 | }
|
---|
138 | }
|
---|
139 | @return define-typography-config($non-null-args...);
|
---|
140 | }
|
---|
141 | @return $config;
|
---|
142 | }
|
---|
143 |
|
---|
144 | // Given a config for either the 2014 or 2018 Material Design typography system,
|
---|
145 | // produces a normalized typography config for the 2018 Material Design typography system.
|
---|
146 | // 2014 - https://material.io/archive/guidelines/style/typography.html#typography-styles
|
---|
147 | // 2018 - https://material.io/design/typography/the-type-system.html#type-scale
|
---|
148 | @function private-typography-to-2018-config($config) {
|
---|
149 | @if $config == null {
|
---|
150 | @return null;
|
---|
151 | }
|
---|
152 | @if not private-typography-is-2018-config($config) {
|
---|
153 | @return (
|
---|
154 | headline-1: map.get($config, display-4),
|
---|
155 | headline-2: map.get($config, display-3),
|
---|
156 | headline-3: map.get($config, display-2),
|
---|
157 | headline-4: map.get($config, display-1),
|
---|
158 | headline-5: map.get($config, headline),
|
---|
159 | headline-6: map.get($config, title),
|
---|
160 | subtitle-1: map.get($config, subheading-2),
|
---|
161 |
|
---|
162 | // These mappings are odd, but body-2 in the 2014 system actually looks closer to subtitle-2
|
---|
163 | // in the 2018 system, and subeading-1 in the 2014 system looks more like body-1 in the 2018
|
---|
164 | // system.
|
---|
165 | subtitle-2: map.get($config, body-2),
|
---|
166 | body-1: map.get($config, subheading-1),
|
---|
167 |
|
---|
168 | body-2: map.get($config, body-1),
|
---|
169 | button: map.get($config, button),
|
---|
170 | caption: map.get($config, caption),
|
---|
171 | overline: if(map.get($config, overline), map.get($config, overline),
|
---|
172 | define-typography-level(12px, 32px, 500)
|
---|
173 | )
|
---|
174 | );
|
---|
175 | }
|
---|
176 | @return $config;
|
---|
177 | }
|
---|
178 |
|
---|
179 | // stylelint-disable material/theme-mixin-api
|
---|
180 |
|
---|
181 | /// Emits baseline typographic styles based on a given config.
|
---|
182 | /// @param {Map} $config-or-theme A typography config for an entire theme.
|
---|
183 | /// @param {String} $selector Ancestor selector under which native elements, such as h1, will
|
---|
184 | /// be styled.
|
---|
185 | @mixin typography-hierarchy($config-or-theme, $selector: '.mat-typography') {
|
---|
186 | $config: private-typography-to-2014-config(theming.get-typography-config($config-or-theme));
|
---|
187 |
|
---|
188 | .mat-h1, .mat-headline, #{$selector} h1 {
|
---|
189 | @include typography-utils.typography-level($config, headline);
|
---|
190 | margin: 0 0 16px;
|
---|
191 | }
|
---|
192 |
|
---|
193 | .mat-h2, .mat-title, #{$selector} h2 {
|
---|
194 | @include typography-utils.typography-level($config, title);
|
---|
195 | margin: 0 0 16px;
|
---|
196 | }
|
---|
197 |
|
---|
198 | .mat-h3, .mat-subheading-2, #{$selector} h3 {
|
---|
199 | @include typography-utils.typography-level($config, subheading-2);
|
---|
200 | margin: 0 0 16px;
|
---|
201 | }
|
---|
202 |
|
---|
203 | .mat-h4, .mat-subheading-1, #{$selector} h4 {
|
---|
204 | @include typography-utils.typography-level($config, subheading-1);
|
---|
205 | margin: 0 0 16px;
|
---|
206 | }
|
---|
207 |
|
---|
208 | // Note: the spec doesn't have anything that would correspond to h5 and h6, but we add these for
|
---|
209 | // consistency. The font sizes come from the Chrome user agent styles which have h5 at 0.83em
|
---|
210 | // and h6 at 0.67em.
|
---|
211 | .mat-h5, #{$selector} h5 {
|
---|
212 | @include typography-utils.font-shorthand(
|
---|
213 | // calc is used here to support css variables
|
---|
214 | calc(#{typography-utils.font-size($config, body-1)} * 0.83),
|
---|
215 | typography-utils.font-weight($config, body-1),
|
---|
216 | typography-utils.line-height($config, body-1),
|
---|
217 | typography-utils.font-family($config, body-1)
|
---|
218 | );
|
---|
219 |
|
---|
220 | margin: 0 0 12px;
|
---|
221 | }
|
---|
222 |
|
---|
223 | .mat-h6, #{$selector} h6 {
|
---|
224 | @include typography-utils.font-shorthand(
|
---|
225 | // calc is used here to support css variables
|
---|
226 | calc(#{typography-utils.font-size($config, body-1)} * 0.67),
|
---|
227 | typography-utils.font-weight($config, body-1),
|
---|
228 | typography-utils.line-height($config, body-1),
|
---|
229 | typography-utils.font-family($config, body-1)
|
---|
230 | );
|
---|
231 |
|
---|
232 | margin: 0 0 12px;
|
---|
233 | }
|
---|
234 |
|
---|
235 | .mat-body-strong, .mat-body-2 {
|
---|
236 | @include typography-utils.typography-level($config, body-2);
|
---|
237 | }
|
---|
238 |
|
---|
239 | .mat-body, .mat-body-1, #{$selector} {
|
---|
240 | @include typography-utils.typography-level($config, body-1);
|
---|
241 |
|
---|
242 | p {
|
---|
243 | margin: 0 0 12px;
|
---|
244 | }
|
---|
245 | }
|
---|
246 |
|
---|
247 | .mat-small, .mat-caption {
|
---|
248 | @include typography-utils.typography-level($config, caption);
|
---|
249 | }
|
---|
250 |
|
---|
251 | .mat-display-4, #{$selector} .mat-display-4 {
|
---|
252 | @include typography-utils.typography-level($config, display-4);
|
---|
253 | margin: 0 0 56px;
|
---|
254 | }
|
---|
255 |
|
---|
256 | .mat-display-3, #{$selector} .mat-display-3 {
|
---|
257 | @include typography-utils.typography-level($config, display-3);
|
---|
258 | margin: 0 0 64px;
|
---|
259 | }
|
---|
260 |
|
---|
261 | .mat-display-2, #{$selector} .mat-display-2 {
|
---|
262 | @include typography-utils.typography-level($config, display-2);
|
---|
263 | margin: 0 0 64px;
|
---|
264 | }
|
---|
265 |
|
---|
266 | .mat-display-1, #{$selector} .mat-display-1 {
|
---|
267 | @include typography-utils.typography-level($config, display-1);
|
---|
268 | margin: 0 0 64px;
|
---|
269 | }
|
---|
270 | }
|
---|
271 |
|
---|
272 | // stylelint-enable material/theme-mixin-api
|
---|