1 /*
2 * Copyright 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package androidx.compose.material
18
19 import androidx.compose.runtime.Immutable
20 import androidx.compose.runtime.staticCompositionLocalOf
21 import androidx.compose.ui.text.PlatformTextStyle
22 import androidx.compose.ui.text.TextStyle
23 import androidx.compose.ui.text.font.FontFamily
24 import androidx.compose.ui.text.font.FontWeight
25 import androidx.compose.ui.text.style.LineHeightStyle
26 import androidx.compose.ui.unit.sp
27
28 /**
29 * [Material Design type
30 * scale](https://material.io/design/typography/the-type-system.html#type-scale)
31 *
32 * The Material Design type scale includes a range of contrasting styles that support the needs of
33 * your product and its content.
34 *
35 * The type scale is a combination of thirteen styles that are supported by the type system. It
36 * contains reusable categories of text, each with an intended application and meaning.
37 *
38 * 
40 *
41 * @property h1 h1 is the largest headline, reserved for short, important text or numerals. For
42 * headlines, you can choose an expressive font, such as a display, handwritten, or script style.
43 * These unconventional font designs have details and intricacy that help attract the eye.
44 * @property h2 h2 is the second largest headline, reserved for short, important text or numerals.
45 * For headlines, you can choose an expressive font, such as a display, handwritten, or script
46 * style. These unconventional font designs have details and intricacy that help attract the eye.
47 * @property h3 h3 is the third largest headline, reserved for short, important text or numerals.
48 * For headlines, you can choose an expressive font, such as a display, handwritten, or script
49 * style. These unconventional font designs have details and intricacy that help attract the eye.
50 * @property h4 h4 is the fourth largest headline, reserved for short, important text or numerals.
51 * For headlines, you can choose an expressive font, such as a display, handwritten, or script
52 * style. These unconventional font designs have details and intricacy that help attract the eye.
53 * @property h5 h5 is the fifth largest headline, reserved for short, important text or numerals.
54 * For headlines, you can choose an expressive font, such as a display, handwritten, or script
55 * style. These unconventional font designs have details and intricacy that help attract the eye.
56 * @property h6 h6 is the sixth largest headline, reserved for short, important text or numerals.
57 * For headlines, you can choose an expressive font, such as a display, handwritten, or script
58 * style. These unconventional font designs have details and intricacy that help attract the eye.
59 * @property subtitle1 subtitle1 is the largest subtitle, and is typically reserved for
60 * medium-emphasis text that is shorter in length. Serif or sans serif typefaces work well for
61 * subtitles.
62 * @property subtitle2 subtitle2 is the smallest subtitle, and is typically reserved for
63 * medium-emphasis text that is shorter in length. Serif or sans serif typefaces work well for
64 * subtitles.
65 * @property body1 body1 is the largest body, and is typically used for long-form writing as it
66 * works well for small text sizes. For longer sections of text, a serif or sans serif typeface is
67 * recommended.
68 * @property body2 body2 is the smallest body, and is typically used for long-form writing as it
69 * works well for small text sizes. For longer sections of text, a serif or sans serif typeface is
70 * recommended.
71 * @property button button text is a call to action used in different types of buttons (such as
72 * text, outlined and contained buttons) and in tabs, dialogs, and cards. Button text is typically
73 * sans serif, using all caps text.
74 * @property caption caption is one of the smallest font sizes. It is used sparingly to annotate
75 * imagery or to introduce a headline.
76 * @property overline overline is one of the smallest font sizes. It is used sparingly to annotate
77 * imagery or to introduce a headline.
78 */
79 @Immutable
80 class Typography
81 internal constructor(
82 val h1: TextStyle,
83 val h2: TextStyle,
84 val h3: TextStyle,
85 val h4: TextStyle,
86 val h5: TextStyle,
87 val h6: TextStyle,
88 val subtitle1: TextStyle,
89 val subtitle2: TextStyle,
90 val body1: TextStyle,
91 val body2: TextStyle,
92 val button: TextStyle,
93 val caption: TextStyle,
94 val overline: TextStyle
95 ) {
96 /**
97 * Constructor to create a [Typography]. For information on the types of style defined in this
98 * constructor, see the property documentation for [Typography].
99 *
100 * @param defaultFontFamily the default [FontFamily] to be used for [TextStyle]s provided in
101 * this constructor. This default will be used if the [FontFamily] on the [TextStyle] is
102 * `null`.
103 * @param h1 h1 is the largest headline, reserved for short, important text or numerals.
104 * @param h2 h2 is the second largest headline, reserved for short, important text or numerals.
105 * @param h3 h3 is the third largest headline, reserved for short, important text or numerals.
106 * @param h4 h4 is the fourth largest headline, reserved for short, important text or numerals.
107 * @param h5 h5 is the fifth largest headline, reserved for short, important text or numerals.
108 * @param h6 h6 is the sixth largest headline, reserved for short, important text or numerals.
109 * @param subtitle1 subtitle1 is the largest subtitle, and is typically reserved for
110 * medium-emphasis text that is shorter in length.
111 * @param subtitle2 subtitle2 is the smallest subtitle, and is typically reserved for
112 * medium-emphasis text that is shorter in length.
113 * @param body1 body1 is the largest body, and is typically used for long-form writing as it
114 * works well for small text sizes.
115 * @param body2 body2 is the smallest body, and is typically used for long-form writing as it
116 * works well for small text sizes.
117 * @param button button text is a call to action used in different types of buttons (such as
118 * text, outlined and contained buttons) and in tabs, dialogs, and cards.
119 * @param caption caption is one of the smallest font sizes. It is used sparingly to annotate
120 * imagery or to introduce a headline.
121 * @param overline overline is one of the smallest font sizes. It is used sparingly to annotate
122 * imagery or to introduce a headline.
123 */
124 constructor(
125 defaultFontFamily: FontFamily = FontFamily.Default,
126 h1: TextStyle =
127 DefaultTextStyle.copy(
128 fontWeight = FontWeight.Light,
129 fontSize = 96.sp,
130 lineHeight = 112.sp,
131 letterSpacing = (-1.5).sp
132 ),
133 h2: TextStyle =
134 DefaultTextStyle.copy(
135 fontWeight = FontWeight.Light,
136 fontSize = 60.sp,
137 lineHeight = 72.sp,
138 letterSpacing = (-0.5).sp
139 ),
140 h3: TextStyle =
141 DefaultTextStyle.copy(
142 fontWeight = FontWeight.Normal,
143 fontSize = 48.sp,
144 lineHeight = 56.sp,
145 letterSpacing = 0.sp
146 ),
147 h4: TextStyle =
148 DefaultTextStyle.copy(
149 fontWeight = FontWeight.Normal,
150 fontSize = 34.sp,
151 lineHeight = 36.sp,
152 letterSpacing = 0.25.sp
153 ),
154 h5: TextStyle =
155 DefaultTextStyle.copy(
156 fontWeight = FontWeight.Normal,
157 fontSize = 24.sp,
158 lineHeight = 24.sp,
159 letterSpacing = 0.sp
160 ),
161 h6: TextStyle =
162 DefaultTextStyle.copy(
163 fontWeight = FontWeight.Medium,
164 fontSize = 20.sp,
165 lineHeight = 24.sp,
166 letterSpacing = 0.15.sp
167 ),
168 subtitle1: TextStyle =
169 DefaultTextStyle.copy(
170 fontWeight = FontWeight.Normal,
171 fontSize = 16.sp,
172 lineHeight = 24.sp,
173 letterSpacing = 0.15.sp
174 ),
175 subtitle2: TextStyle =
176 DefaultTextStyle.copy(
177 fontWeight = FontWeight.Medium,
178 fontSize = 14.sp,
179 lineHeight = 24.sp,
180 letterSpacing = 0.1.sp
181 ),
182 body1: TextStyle =
183 DefaultTextStyle.copy(
184 fontWeight = FontWeight.Normal,
185 fontSize = 16.sp,
186 lineHeight = 24.sp,
187 letterSpacing = 0.5.sp
188 ),
189 body2: TextStyle =
190 DefaultTextStyle.copy(
191 fontWeight = FontWeight.Normal,
192 fontSize = 14.sp,
193 lineHeight = 20.sp,
194 letterSpacing = 0.25.sp
195 ),
196 button: TextStyle =
197 DefaultTextStyle.copy(
198 fontWeight = FontWeight.Medium,
199 fontSize = 14.sp,
200 lineHeight = 16.sp,
201 letterSpacing = 1.25.sp
202 ),
203 caption: TextStyle =
204 DefaultTextStyle.copy(
205 fontWeight = FontWeight.Normal,
206 fontSize = 12.sp,
207 lineHeight = 16.sp,
208 letterSpacing = 0.4.sp
209 ),
210 overline: TextStyle =
211 DefaultTextStyle.copy(
212 fontWeight = FontWeight.Normal,
213 fontSize = 10.sp,
214 lineHeight = 16.sp,
215 letterSpacing = 1.5.sp
216 )
217 ) : this(
218 h1 = h1.withDefaultFontFamily(defaultFontFamily),
219 h2 = h2.withDefaultFontFamily(defaultFontFamily),
220 h3 = h3.withDefaultFontFamily(defaultFontFamily),
221 h4 = h4.withDefaultFontFamily(defaultFontFamily),
222 h5 = h5.withDefaultFontFamily(defaultFontFamily),
223 h6 = h6.withDefaultFontFamily(defaultFontFamily),
224 subtitle1 = subtitle1.withDefaultFontFamily(defaultFontFamily),
225 subtitle2 = subtitle2.withDefaultFontFamily(defaultFontFamily),
226 body1 = body1.withDefaultFontFamily(defaultFontFamily),
227 body2 = body2.withDefaultFontFamily(defaultFontFamily),
228 button = button.withDefaultFontFamily(defaultFontFamily),
229 caption = caption.withDefaultFontFamily(defaultFontFamily),
230 overline = overline.withDefaultFontFamily(defaultFontFamily)
231 )
232
233 /** Returns a copy of this Typography, optionally overriding some of the values. */
copynull234 fun copy(
235 h1: TextStyle = this.h1,
236 h2: TextStyle = this.h2,
237 h3: TextStyle = this.h3,
238 h4: TextStyle = this.h4,
239 h5: TextStyle = this.h5,
240 h6: TextStyle = this.h6,
241 subtitle1: TextStyle = this.subtitle1,
242 subtitle2: TextStyle = this.subtitle2,
243 body1: TextStyle = this.body1,
244 body2: TextStyle = this.body2,
245 button: TextStyle = this.button,
246 caption: TextStyle = this.caption,
247 overline: TextStyle = this.overline
248 ): Typography =
249 Typography(
250 h1 = h1,
251 h2 = h2,
252 h3 = h3,
253 h4 = h4,
254 h5 = h5,
255 h6 = h6,
256 subtitle1 = subtitle1,
257 subtitle2 = subtitle2,
258 body1 = body1,
259 body2 = body2,
260 button = button,
261 caption = caption,
262 overline = overline
263 )
264
265 override fun equals(other: Any?): Boolean {
266 if (this === other) return true
267 if (other !is Typography) return false
268
269 if (h1 != other.h1) return false
270 if (h2 != other.h2) return false
271 if (h3 != other.h3) return false
272 if (h4 != other.h4) return false
273 if (h5 != other.h5) return false
274 if (h6 != other.h6) return false
275 if (subtitle1 != other.subtitle1) return false
276 if (subtitle2 != other.subtitle2) return false
277 if (body1 != other.body1) return false
278 if (body2 != other.body2) return false
279 if (button != other.button) return false
280 if (caption != other.caption) return false
281 if (overline != other.overline) return false
282
283 return true
284 }
285
hashCodenull286 override fun hashCode(): Int {
287 var result = h1.hashCode()
288 result = 31 * result + h2.hashCode()
289 result = 31 * result + h3.hashCode()
290 result = 31 * result + h4.hashCode()
291 result = 31 * result + h5.hashCode()
292 result = 31 * result + h6.hashCode()
293 result = 31 * result + subtitle1.hashCode()
294 result = 31 * result + subtitle2.hashCode()
295 result = 31 * result + body1.hashCode()
296 result = 31 * result + body2.hashCode()
297 result = 31 * result + button.hashCode()
298 result = 31 * result + caption.hashCode()
299 result = 31 * result + overline.hashCode()
300 return result
301 }
302
toStringnull303 override fun toString(): String {
304 return "Typography(h1=$h1, h2=$h2, h3=$h3, h4=$h4, h5=$h5, h6=$h6, " +
305 "subtitle1=$subtitle1, subtitle2=$subtitle2, body1=$body1, " +
306 "body2=$body2, button=$button, caption=$caption, overline=$overline)"
307 }
308 }
309
310 /**
311 * @return [this] if there is a [FontFamily] defined, otherwise copies [this] with [default] as the
312 * [FontFamily].
313 */
TextStylenull314 private fun TextStyle.withDefaultFontFamily(default: FontFamily): TextStyle {
315 return if (fontFamily != null) this else copy(fontFamily = default)
316 }
317
318 internal val DefaultLineHeightStyle =
319 LineHeightStyle(
320 alignment = LineHeightStyle.Alignment.Center,
321 trim = LineHeightStyle.Trim.None,
322 )
323
324 internal val DefaultTextStyle =
325 TextStyle.Default.copy(
326 platformStyle = defaultPlatformTextStyle(),
327 lineHeightStyle = DefaultLineHeightStyle,
328 )
329
330 /** Returns Default [PlatformTextStyle]. */
defaultPlatformTextStylenull331 internal expect fun defaultPlatformTextStyle(): PlatformTextStyle?
332
333 /**
334 * This CompositionLocal holds on to the current definition of typography for this application as
335 * described by the Material spec. You can read the values in it when creating custom components
336 * that want to use Material types, as well as override the values when you want to re-style a part
337 * of your hierarchy. Material components related to text such as [Button] will use this
338 * CompositionLocal to set values with which to style children text components.
339 *
340 * To access values within this CompositionLocal, use [MaterialTheme.typography].
341 */
342 internal val LocalTypography = staticCompositionLocalOf { Typography() }
343