@expressivecss/expressive 0.7.0 → 0.9.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.
Files changed (122) hide show
  1. package/CHANGELOG.md +1313 -1
  2. package/README.md +76 -30
  3. package/dist/css/expressive.css +4896 -1777
  4. package/dist/css/expressive.css.map +1 -1
  5. package/dist/css/expressive.min.css +1 -1
  6. package/dist/css/expressive.min.css.map +1 -1
  7. package/dist/fonts/LICENSE-material-symbols +93 -0
  8. package/dist/fonts/LICENSE-noto-sans +93 -0
  9. package/dist/fonts/LICENSE-roboto +93 -0
  10. package/dist/fonts/material-symbols-outlined.woff2 +0 -0
  11. package/dist/fonts/material-symbols-rounded.woff2 +0 -0
  12. package/dist/fonts/material-symbols-sharp.woff2 +0 -0
  13. package/dist/fonts/noto-sans-latin-400.woff2 +0 -0
  14. package/dist/fonts/noto-sans-latin-500.woff2 +0 -0
  15. package/dist/fonts/roboto-latin-400.woff2 +0 -0
  16. package/dist/fonts/roboto-latin-500.woff2 +0 -0
  17. package/dist/js/expressive.cjs +1673 -1338
  18. package/dist/js/expressive.cjs.map +4 -4
  19. package/dist/js/expressive.js +1673 -1338
  20. package/dist/js/expressive.js.map +4 -4
  21. package/dist/js/expressive.min.js +13 -13
  22. package/dist/js/expressive.min.js.map +4 -4
  23. package/dist/js/expressive.mjs +1673 -1338
  24. package/dist/js/expressive.mjs.map +4 -4
  25. package/dist/types/behaviors/bottomSheets.d.ts +19 -11
  26. package/dist/types/behaviors/sheetDrag.d.ts +40 -0
  27. package/dist/types/behaviors/sideSheets.d.ts +2 -9
  28. package/dist/types/components/appBar.d.ts +26 -0
  29. package/dist/types/components/autocomplete.d.ts +15 -3
  30. package/dist/types/components/buttonGroup.d.ts +39 -0
  31. package/dist/types/components/buttons.d.ts +5 -1
  32. package/dist/types/components/cards.d.ts +11 -13
  33. package/dist/types/components/carousel.d.ts +87 -53
  34. package/dist/types/components/chips.d.ts +21 -1
  35. package/dist/types/components/expandingCard.d.ts +31 -0
  36. package/dist/types/components/index.d.ts +23 -20
  37. package/dist/types/components/lightbox.d.ts +1 -0
  38. package/dist/types/components/menu.d.ts +11 -1
  39. package/dist/types/components/{sidenav.d.ts → navigationDrawer.d.ts} +16 -16
  40. package/dist/types/components/registry.d.ts +18 -8
  41. package/dist/types/components/slider.d.ts +26 -85
  42. package/dist/types/components/snackbar.d.ts +20 -5
  43. package/dist/types/components/tabs.d.ts +12 -0
  44. package/dist/types/components/timepicker.d.ts +12 -10
  45. package/dist/types/components/tooltip.d.ts +1 -0
  46. package/dist/types/core/utils.d.ts +64 -53
  47. package/dist/types/index.d.ts +8 -9
  48. package/package.json +39 -3
  49. package/src/sass/README.md +61 -11
  50. package/src/sass/abstracts/_breakpoints.scss +17 -19
  51. package/src/sass/abstracts/_mixins.scss +155 -21
  52. package/src/sass/abstracts/_variables.scss +69 -5
  53. package/src/sass/base/_fonts.scss +63 -0
  54. package/src/sass/base/_global.scss +6 -24
  55. package/src/sass/base/_grid.scss +15 -12
  56. package/src/sass/base/_normalize.scss +34 -38
  57. package/src/sass/base/_typography.scss +4 -18
  58. package/src/sass/components/_badges.scss +3 -5
  59. package/src/sass/components/_banners.scss +298 -0
  60. package/src/sass/components/_bottom-app-bar.scss +180 -0
  61. package/src/sass/components/_bottom-sheet.scss +12 -4
  62. package/src/sass/components/_button-groups.scss +358 -0
  63. package/src/sass/components/_buttons.scss +245 -92
  64. package/src/sass/components/_cards.scss +514 -78
  65. package/src/sass/components/_carousel.scss +562 -68
  66. package/src/sass/components/_chips.scss +64 -5
  67. package/src/sass/components/_datepicker.scss +24 -24
  68. package/src/sass/components/_dialog.scss +17 -11
  69. package/src/sass/components/_drag-handle.scss +130 -0
  70. package/src/sass/components/_expanding-card.scss +226 -0
  71. package/src/sass/components/_fab-menu.scss +232 -0
  72. package/src/sass/components/_floating-sheet.scss +86 -0
  73. package/src/sass/components/_icon-buttons.scss +172 -0
  74. package/src/sass/components/_icons-material-design.scss +22 -10
  75. package/src/sass/components/_index.scss +22 -6
  76. package/src/sass/components/_list.scss +16 -13
  77. package/src/sass/components/_loading-indicator.scss +106 -0
  78. package/src/sass/components/_menu.scss +335 -61
  79. package/src/sass/components/_navbar.scss +245 -45
  80. package/src/sass/components/_navigation-bar.scss +22 -11
  81. package/src/sass/components/{_sidenav.scss → _navigation-drawer.scss} +123 -33
  82. package/src/sass/components/_navigation-rail.scss +31 -23
  83. package/src/sass/components/_page-footer.scss +19 -16
  84. package/src/sass/components/_pagination.scss +24 -6
  85. package/src/sass/components/_panes.scss +52 -11
  86. package/src/sass/components/{_preloader.scss → _progress.scss} +11 -3
  87. package/src/sass/components/_scrim.scss +37 -0
  88. package/src/sass/components/_search.scss +259 -0
  89. package/src/sass/components/_segmented-buttons.scss +188 -0
  90. package/src/sass/components/_side-sheet.scss +2 -2
  91. package/src/sass/components/_snackbar.scss +20 -15
  92. package/src/sass/components/_split-button.scss +196 -0
  93. package/src/sass/components/_tabs.scss +7 -8
  94. package/src/sass/components/_timepicker.scss +67 -58
  95. package/src/sass/components/_toolbar.scss +206 -80
  96. package/src/sass/components/_transitions.scss +8 -1
  97. package/src/sass/components/forms/_checkboxes.scss +49 -12
  98. package/src/sass/components/forms/_fieldset.scss +4 -4
  99. package/src/sass/components/forms/_file-input.scss +8 -1
  100. package/src/sass/components/forms/_index.scss +1 -1
  101. package/src/sass/components/forms/_input-fields.scss +50 -44
  102. package/src/sass/components/forms/_radio-buttons.scss +42 -10
  103. package/src/sass/components/forms/_select.scss +38 -1
  104. package/src/sass/components/forms/{_range.scss → _slider.scss} +8 -9
  105. package/src/sass/components/forms/_switches.scss +6 -7
  106. package/src/sass/expressive.scss +5 -0
  107. package/src/sass/tokens/_index.scss +4 -1
  108. package/src/sass/tokens/_reference.scss +70 -61
  109. package/src/sass/tokens/_state.scss +24 -0
  110. package/src/sass/tokens/_theme.scss +6 -3
  111. package/src/sass/tokens/_vibrant.scss +76 -0
  112. package/src/sass/utilities/_colors.scss +14 -1
  113. package/src/sass/utilities/_helpers.scss +5 -5
  114. package/src/sass/utilities/_visibility.scss +48 -26
  115. package/dist/types/behaviors/waves.d.ts +0 -15
  116. package/dist/types/components/parallax.d.ts +0 -16
  117. package/dist/types/components/range.d.ts +0 -43
  118. package/dist/types/core/bounding.d.ts +0 -6
  119. package/dist/types/core/edges.d.ts +0 -6
  120. package/src/sass/components/_parallax.scss +0 -104
  121. package/src/sass/components/_pulse.scss +0 -37
  122. package/src/sass/components/_slider.scss +0 -129
@@ -6,14 +6,24 @@
6
6
  // Headings are the headline, icon-only links/buttons are the leading and
7
7
  // trailing actions, <menu> / <ul> hold text destinations. Helpers are only
8
8
  // for variants the markup cannot express: .center, .medium, .large, .fixed.
9
+ // `.medium` and `.large` are the Expressive flexible bars.
9
10
  // Destinations at the bottom of the screen are nav.navigation-bar, not this.
10
11
  //
11
- // Tokens follow the M3 top-app-bar spec
12
- // (https://m3.material.io/components/app-bars/specs):
13
- // container surface, 64dp small / 112 medium / 152 large
14
- // headline on-surface, title-large (small), headline-small/medium
15
- // icons on-surface-variant, 24dp in a 48dp target, 4dp inset
16
- // on scroll surface-container fill (not elevation) so the bar
12
+ // Tokens follow the M3 Expressive app bar spec
13
+ // (https://m3.material.io/components/app-bars/specs, Material Web v29.0.16):
14
+ // container surface, 64dp small / 112 medium-flexible /
15
+ // 120 large-flexible (136 / 152 with a subtitle)
16
+ // headline on-surface, title-large (small), headline-medium
17
+ // (medium-flexible), display-small (large-flexible)
18
+ // subtitle label-medium / label-large / title-medium in an <hgroup>
19
+ // icons 24dp in a 48dp target, 4dp inset. The spec mutes the
20
+ // trailing ones (on-surface-variant) and leaves the leading
21
+ // one on-surface; both inherit here instead, so a fill +
22
+ // on-* pair on the header stays readable. The two tokens
23
+ // below are the opt-in to the spec colors.
24
+ // medium/large headline 16dp from the inline edges; wrap to two lines
25
+ // on scroll surface-container fill (not elevation - the spec's
26
+ // level2 elevation carries a transparent shadow) so the bar
17
27
  // separates from the body. A color utility on the
18
28
  // header still wins — it sets background-color itself.
19
29
 
@@ -29,12 +39,28 @@
29
39
  initial-value: 0;
30
40
  }
31
41
 
32
- header:has(> nav:not(.navigation-bar, .navigation-rail)) {
42
+ // The bar itself. A top app bar that holds destinations is a <nav>; one that
43
+ // holds only a title and controls - as the docs chrome does - is not
44
+ // navigation and says so with `.bar`, rather than claiming a landmark and
45
+ // then having nothing to put in it. Both look identical.
46
+ // Wrapped in :is() so it stays ONE compound selector. A bare comma-separated
47
+ // list breaks out of its context on interpolation: `header.medium > #{$_bar}`
48
+ // expanded to `header.medium > nav:not(...), .bar`, which styled every .bar on
49
+ // the page as an app bar. Same trap as $_icon in _icons-material-design.
50
+ // :is() also keeps the specificity where nav:not(...) had it.
51
+ $_bar: ":is(nav:not(.tabs, .navigation-bar, .navigation-rail), .bar)";
52
+ $_heading: ":is(h1, h2, h3, h4, h5, h6)";
53
+ $_title: ":is(#{$_heading}, hgroup)";
54
+ $_search: ":is(.search-bar, .searchbar)";
55
+
56
+ header:has(> :is(nav:not(.navigation-bar, .navigation-rail), .bar)) {
33
57
  --md-comp-top-app-bar-container-color: var(--md-sys-color-surface);
34
58
  --md-comp-top-app-bar-scrolled-container-color: var(--md-sys-color-surface-container);
35
59
  --md-comp-top-app-bar-headline-color: var(--md-sys-color-on-surface);
36
- // Inherit so a fill + on-* pair on the header recolors the icons.
37
- // Set this to --md-sys-color-on-surface-variant for the spec mute.
60
+ // Inherit so a fill + on-* pair on the header recolors the icons. The spec
61
+ // splits them - leading on-surface, trailing on-surface-variant - and each
62
+ // token below is the opt-in for its own side. Leading is everything before
63
+ // the headline; trailing is everything after it.
38
64
  --md-comp-top-app-bar-leading-icon-color: inherit;
39
65
  --md-comp-top-app-bar-trailing-icon-color: inherit;
40
66
  --md-comp-top-app-bar-container-height: 64px;
@@ -51,7 +77,7 @@ header:has(> nav:not(.navigation-bar, .navigation-rail)) {
51
77
  border-radius: var(--md-comp-top-app-bar-container-shape);
52
78
  width: 100%;
53
79
 
54
- > nav:not(.tabs, .navigation-bar, .navigation-rail) {
80
+ > #{$_bar} {
55
81
  display: flex;
56
82
  align-items: center;
57
83
  box-sizing: border-box;
@@ -61,7 +87,7 @@ header:has(> nav:not(.navigation-bar, .navigation-rail)) {
61
87
  margin: 0;
62
88
  }
63
89
 
64
- > nav:not(.tabs, .navigation-bar, .navigation-rail) > :is(h1, h2, h3, h4, h5, h6) {
90
+ > #{$_bar} > #{$_title} {
65
91
  flex: 1 1 auto;
66
92
  min-width: 0;
67
93
  margin: 0;
@@ -75,6 +101,12 @@ header:has(> nav:not(.navigation-bar, .navigation-rail)) {
75
101
  text-overflow: ellipsis;
76
102
  white-space: nowrap;
77
103
  color: inherit;
104
+ }
105
+
106
+ > #{$_bar} > #{$_heading},
107
+ > #{$_bar} > hgroup > #{$_heading} {
108
+ margin: 0;
109
+ color: inherit;
78
110
  font-family: var(--md-sys-typescale-title-large-font-family-name);
79
111
  font-size: var(--md-sys-typescale-title-large-font-size);
80
112
  font-weight: var(--md-sys-typescale-title-large-font-weight);
@@ -82,8 +114,31 @@ header:has(> nav:not(.navigation-bar, .navigation-rail)) {
82
114
  letter-spacing: var(--md-sys-typescale-title-large-letter-spacing);
83
115
  }
84
116
 
117
+ > #{$_bar} > hgroup {
118
+ display: flex;
119
+ flex-direction: column;
120
+ justify-content: center;
121
+ gap: 0;
122
+ white-space: normal;
123
+ text-overflow: unset;
124
+ }
125
+
126
+ > #{$_bar} > hgroup > p {
127
+ margin: 0;
128
+ color: inherit;
129
+ font-family: var(--md-sys-typescale-label-medium-font-family-name);
130
+ font-size: var(--md-sys-typescale-label-medium-font-size);
131
+ font-weight: var(--md-sys-typescale-label-medium-font-weight);
132
+ line-height: var(--md-sys-typescale-label-medium-line-height);
133
+ letter-spacing: var(--md-sys-typescale-label-medium-letter-spacing);
134
+ }
135
+
85
136
  // Icon-only actions — 48dp target, 24dp glyph, 4dp from the container edge.
86
- > nav:not(.tabs, .navigation-bar, .navigation-rail) > :is(a, button):not(.button):not(.circle):not(.extra):has(> i:only-child) {
137
+ // $icon, not `i`: the canonical icon is a <span class="material-symbols">, and
138
+ // keying on the element meant every bar written the documented way lost this
139
+ // rule — the leading action fell through to the generic button pill and the
140
+ // trailing ones were picked up by the text-destination rule below.
141
+ > #{$_bar} > :is(a, button):not(.button, .icon-button):not(.circle):not(.extra):has(> #{$icon}:only-child) {
87
142
  display: inline-flex;
88
143
  flex: 0 0 auto;
89
144
  align-items: center;
@@ -105,7 +160,7 @@ header:has(> nav:not(.navigation-bar, .navigation-rail)) {
105
160
  text-decoration: none;
106
161
  @include focus-visible;
107
162
 
108
- > i {
163
+ > #{$icon} {
109
164
  display: block;
110
165
  font-size: var(--md-comp-top-app-bar-leading-icon-size);
111
166
  width: var(--md-comp-top-app-bar-leading-icon-size);
@@ -122,12 +177,20 @@ header:has(> nav:not(.navigation-bar, .navigation-rail)) {
122
177
  }
123
178
  }
124
179
 
180
+ // Trailing actions are the ones that follow the headline - DOM order is the
181
+ // anatomy, here as everywhere else in this file. Without this the trailing
182
+ // token was declared and consumed by nothing, so the documented way to opt
183
+ // into the spec's muted trailing icons did nothing at all.
184
+ > #{$_bar} > :is(#{$_title}, #{$_search}) ~ :is(a, button):not(.button, .icon-button):not(.circle):not(.extra):has(> #{$icon}:only-child) {
185
+ color: var(--md-comp-top-app-bar-trailing-icon-color);
186
+ }
187
+
125
188
  // Text destinations, either loose or grouped in a menu/list.
126
- > nav:not(.tabs, .navigation-bar, .navigation-rail) > a:not(:has(> i:only-child)):not(.button):not(.circle):not(.breadcrumb) {
189
+ > #{$_bar} > a:not(:has(> #{$icon}:only-child)):not(.button, .icon-button):not(.circle):not(.breadcrumb) {
127
190
  @extend %app-bar-destination;
128
191
  }
129
192
 
130
- > nav:not(.tabs, .navigation-bar, .navigation-rail) > :is(menu, ul) {
193
+ > #{$_bar} > :is(menu, ul) {
131
194
  display: flex;
132
195
  align-items: stretch;
133
196
  align-self: stretch;
@@ -151,7 +214,7 @@ header:has(> nav:not(.navigation-bar, .navigation-rail)) {
151
214
  // Breadcrumb trail. Layout only — colors stay on the breadcrumb tokens
152
215
  // (which this header remaps to inherit). Do not treat the crumbs as
153
216
  // destinations.
154
- > nav:not(.tabs, .navigation-bar, .navigation-rail) > ol {
217
+ > #{$_bar} > ol {
155
218
  display: flex;
156
219
  flex-wrap: wrap;
157
220
  align-items: center;
@@ -163,7 +226,7 @@ header:has(> nav:not(.navigation-bar, .navigation-rail)) {
163
226
  padding-inline: 12px;
164
227
  }
165
228
 
166
- > nav:not(.tabs, .navigation-bar, .navigation-rail) > form {
229
+ > #{$_bar} > form {
167
230
  display: flex;
168
231
  flex: 1 1 auto;
169
232
  align-items: center;
@@ -194,6 +257,22 @@ header:has(> nav:not(.navigation-bar, .navigation-rail)) {
194
257
  }
195
258
  }
196
259
  }
260
+
261
+ // Search app bar: the search component sits in the title slot. Icons
262
+ // beside it (siblings of the search) stay outside; icons inside it stay
263
+ // on the search-bar rules. Centered supporting text is the Expressive
264
+ // search-app-bar configuration.
265
+ > #{$_bar} > #{$_search} {
266
+ flex: 1 1 auto;
267
+ width: auto;
268
+ min-width: 0;
269
+ align-self: center;
270
+ margin-block: 4px;
271
+
272
+ input {
273
+ text-align: center;
274
+ }
275
+ }
197
276
  }
198
277
 
199
278
  %app-bar-destination {
@@ -219,12 +298,14 @@ header:has(> nav:not(.navigation-bar, .navigation-rail)) {
219
298
  }
220
299
 
221
300
  // Center-aligned small bar. The headline is taken out of flow so leading and
222
- // trailing actions can sit on the edges without shifting the title.
223
- header.center:has(> nav) > nav:not(.tabs, .navigation-bar, .navigation-rail) {
301
+ // trailing actions can sit on the edges without shifting the title. Medium
302
+ // and large keep the title on the second row and center it there instead.
303
+ header.center:not(.medium, .large):has(> #{$_bar}) > #{$_bar},
304
+ header.center.collapsed:has(> #{$_bar}) > #{$_bar} {
224
305
  position: relative;
225
306
  justify-content: space-between;
226
307
 
227
- > :is(h1, h2, h3, h4, h5, h6) {
308
+ > #{$_title} {
228
309
  position: absolute;
229
310
  left: 50%;
230
311
  transform: translateX(-50%);
@@ -241,53 +322,172 @@ header.center:has(> nav) > nav:not(.tabs, .navigation-bar, .navigation-rail) {
241
322
  // so leading/trailing icons would otherwise pack together at the start.
242
323
  // `space-between` parks the icon row at the top and the title at the
243
324
  // bottom — that's what makes the 112/152 height readable.
244
- header.medium:has(> nav) > nav:not(.tabs, .navigation-bar, .navigation-rail),
245
- header.large:has(> nav) > nav:not(.tabs, .navigation-bar, .navigation-rail) {
325
+ header.medium:has(> #{$_bar}) > #{$_bar},
326
+ header.large:has(> #{$_bar}) > #{$_bar} {
246
327
  flex-wrap: wrap;
247
328
  align-content: space-between;
248
329
  align-items: flex-start;
249
330
  height: auto;
250
- padding-top: 4px;
331
+ // 8dp so the 48dp icon targets are centred in the 64dp top row, the
332
+ // same row the bar collapses to.
333
+ padding-top: 8px;
334
+
335
+ // The top row is 64dp whether or not it holds icons. Without this
336
+ // zero-width spacer a title-only bar has a single flex line and
337
+ // `space-between` pins it to the *top*, so the headline sits where the
338
+ // icons belong instead of on the bottom row.
339
+ &::before {
340
+ content: "";
341
+ flex: 0 0 0;
342
+ height: 48px;
343
+ }
251
344
 
252
- > :is(h1, h2, h3, h4, h5, h6) {
345
+ > #{$_title} {
253
346
  order: 1;
254
- flex: 1 0 100%;
347
+ // Wider than the line, so it always breaks onto its own one - a basis of
348
+ // exactly 100% still fits beside the zero-width spacer above, which put
349
+ // the headline back on the icon row. It shrinks to fit once there.
350
+ flex: 1 1 calc(100% + 1px);
255
351
  white-space: normal;
256
- overflow: visible;
352
+ overflow: hidden;
257
353
  text-overflow: unset;
258
354
  }
259
355
 
260
- > :is(h1, h2, h3, h4, h5, h6) + * {
356
+ > #{$_heading},
357
+ > hgroup > #{$_heading} {
358
+ display: -webkit-box;
359
+ -webkit-box-orient: vertical;
360
+ -webkit-line-clamp: 2;
361
+ line-clamp: 2;
362
+ overflow: hidden;
363
+ white-space: normal;
364
+ }
365
+
366
+ > #{$_title} + * {
261
367
  margin-inline-start: auto;
262
368
  }
263
369
  }
264
370
 
265
- header.medium:has(> nav) > nav:not(.tabs, .navigation-bar, .navigation-rail) {
371
+ header.medium:has(> #{$_bar}) > #{$_bar} {
266
372
  min-height: 112px;
267
- padding-bottom: 16px;
268
-
269
- > :is(h1, h2, h3, h4, h5, h6) {
270
- padding: 4px 12px 0 16px;
271
- font-family: var(--md-sys-typescale-headline-small-font-family-name);
272
- font-size: var(--md-sys-typescale-headline-small-font-size);
273
- font-weight: var(--md-sys-typescale-headline-small-font-weight);
274
- line-height: var(--md-sys-typescale-headline-small-line-height);
275
- letter-spacing: var(--md-sys-typescale-headline-small-letter-spacing);
276
- }
277
- }
373
+ padding-bottom: 20px;
278
374
 
279
- header.large:has(> nav) > nav:not(.tabs, .navigation-bar, .navigation-rail) {
280
- min-height: 152px;
281
- padding-bottom: 28px;
375
+ > #{$_title} {
376
+ padding: 0 12px;
377
+ }
282
378
 
283
- > :is(h1, h2, h3, h4, h5, h6) {
284
- padding: 12px 12px 0 16px;
379
+ > #{$_heading},
380
+ > hgroup > #{$_heading} {
285
381
  font-family: var(--md-sys-typescale-headline-medium-font-family-name);
286
382
  font-size: var(--md-sys-typescale-headline-medium-font-size);
287
383
  font-weight: var(--md-sys-typescale-headline-medium-font-weight);
288
384
  line-height: var(--md-sys-typescale-headline-medium-line-height);
289
385
  letter-spacing: var(--md-sys-typescale-headline-medium-letter-spacing);
290
386
  }
387
+
388
+ > hgroup > p {
389
+ font-family: var(--md-sys-typescale-label-large-font-family-name);
390
+ font-size: var(--md-sys-typescale-label-large-font-size);
391
+ font-weight: var(--md-sys-typescale-label-large-font-weight);
392
+ line-height: var(--md-sys-typescale-label-large-line-height);
393
+ letter-spacing: var(--md-sys-typescale-label-large-letter-spacing);
394
+ }
395
+ }
396
+
397
+ header.medium:has(> #{$_bar} > hgroup > p) > #{$_bar} {
398
+ min-height: 136px;
399
+ }
400
+
401
+ header.large:has(> #{$_bar}) > #{$_bar} {
402
+ min-height: 120px;
403
+ padding-bottom: 20px;
404
+
405
+ > #{$_title} {
406
+ padding: 0 12px;
407
+ }
408
+
409
+ > #{$_heading},
410
+ > hgroup > #{$_heading} {
411
+ font-family: var(--md-sys-typescale-display-small-font-family-name);
412
+ font-size: var(--md-sys-typescale-display-small-font-size);
413
+ font-weight: var(--md-sys-typescale-display-small-font-weight);
414
+ line-height: var(--md-sys-typescale-display-small-line-height);
415
+ letter-spacing: var(--md-sys-typescale-display-small-letter-spacing);
416
+ }
417
+
418
+ > hgroup > p {
419
+ font-family: var(--md-sys-typescale-title-medium-font-family-name);
420
+ font-size: var(--md-sys-typescale-title-medium-font-size);
421
+ font-weight: var(--md-sys-typescale-title-medium-font-weight);
422
+ line-height: var(--md-sys-typescale-title-medium-line-height);
423
+ letter-spacing: var(--md-sys-typescale-title-medium-letter-spacing);
424
+ }
425
+ }
426
+
427
+ header.large:has(> #{$_bar} > hgroup > p) > #{$_bar} {
428
+ min-height: 152px;
429
+ padding-bottom: 28px;
430
+ }
431
+
432
+ header.center.medium:not(.collapsed):has(> #{$_bar}) > #{$_bar} > #{$_title},
433
+ header.center.large:not(.collapsed):has(> #{$_bar}) > #{$_bar} > #{$_title} {
434
+ text-align: center;
435
+ align-items: center;
436
+ }
437
+
438
+ // Collapse the flexible bars into the small 64dp row. AppBar toggles
439
+ // `.collapsed` when the page has scrolled; the class is also legal to set
440
+ // by hand. The two-row layout, the spacer, and the expanded type roles
441
+ // all have to go, or the 64dp height just clips the second row.
442
+ header.medium.collapsed:has(> #{$_bar}) > #{$_bar},
443
+ header.large.collapsed:has(> #{$_bar}) > #{$_bar} {
444
+ flex-wrap: nowrap;
445
+ align-content: center;
446
+ align-items: center;
447
+ min-height: 64px;
448
+ padding-top: 0;
449
+ padding-bottom: 0;
450
+
451
+ &::before {
452
+ display: none;
453
+ }
454
+
455
+ > #{$_title} {
456
+ order: 0;
457
+ flex: 1 1 auto;
458
+ white-space: nowrap;
459
+ overflow: hidden;
460
+ text-overflow: ellipsis;
461
+ }
462
+
463
+ > #{$_title} + * {
464
+ margin-inline-start: 0;
465
+ }
466
+
467
+ > #{$_heading},
468
+ > hgroup > #{$_heading} {
469
+ display: block;
470
+ padding: 0;
471
+ -webkit-line-clamp: unset;
472
+ line-clamp: unset;
473
+ white-space: nowrap;
474
+ overflow: hidden;
475
+ text-overflow: ellipsis;
476
+ font-family: var(--md-sys-typescale-title-large-font-family-name);
477
+ font-size: var(--md-sys-typescale-title-large-font-size);
478
+ font-weight: var(--md-sys-typescale-title-large-font-weight);
479
+ line-height: var(--md-sys-typescale-title-large-line-height);
480
+ letter-spacing: var(--md-sys-typescale-title-large-letter-spacing);
481
+ }
482
+
483
+ > hgroup > p {
484
+ padding: 0;
485
+ font-family: var(--md-sys-typescale-label-medium-font-family-name);
486
+ font-size: var(--md-sys-typescale-label-medium-font-size);
487
+ font-weight: var(--md-sys-typescale-label-medium-font-weight);
488
+ line-height: var(--md-sys-typescale-label-medium-line-height);
489
+ letter-spacing: var(--md-sys-typescale-label-medium-letter-spacing);
490
+ }
291
491
  }
292
492
 
293
493
  // Pin the bar. On scroll, fill with surface-container so it separates
@@ -295,7 +495,7 @@ header.large:has(> nav) > nav:not(.tabs, .navigation-bar, .navigation-rail) {
295
495
  // progress; a utility class on the header sets background-color itself
296
496
  // and is not overwritten. Without animation-timeline the bar stays at
297
497
  // rest (surface), the spec default.
298
- header.fixed:has(> nav:not(.navigation-bar, .navigation-rail)) {
498
+ header.fixed:has(> :is(nav:not(.navigation-bar, .navigation-rail), .bar)) {
299
499
  position: sticky;
300
500
  top: 0;
301
501
  z-index: 997;
@@ -15,7 +15,7 @@
15
15
  // --md-comp-nav-bar-container-color
16
16
  // --md-comp-nav-bar-container-height 64px
17
17
  // --md-comp-nav-bar-icon-size 24px
18
- // --md-comp-nav-bar-indicator-width 56px
18
+ // --md-comp-nav-bar-indicator-width 64px
19
19
  // --md-comp-nav-bar-indicator-height 32px
20
20
  // --md-comp-nav-bar-indicator-shape 16px / 100px horizontal
21
21
  // --md-comp-nav-bar-active-indicator-color secondary-container
@@ -27,7 +27,10 @@
27
27
  --md-comp-nav-bar-container-color: var(--md-sys-color-surface-container);
28
28
  --md-comp-nav-bar-container-height: 64px;
29
29
  --md-comp-nav-bar-icon-size: 24px;
30
- --md-comp-nav-bar-indicator-width: 56px;
30
+ // 64dp, not the rail's 56dp: md.comp.navigation-bar.active-indicator.width
31
+ // is 64 while md.comp.navigation-rail.active-indicator.width is 56. Both were
32
+ // 56 here, which is the rail's value copied onto the bar.
33
+ --md-comp-nav-bar-indicator-width: 64px;
31
34
  --md-comp-nav-bar-indicator-height: 32px;
32
35
  --md-comp-nav-bar-indicator-shape: 16px;
33
36
  --md-comp-nav-bar-active-indicator-color: var(--md-sys-color-secondary-container);
@@ -66,7 +69,7 @@
66
69
  @include typescale("label-medium");
67
70
  @include focus-visible;
68
71
 
69
- > i {
72
+ > #{$icon} {
70
73
  display: flex;
71
74
  flex-shrink: 0;
72
75
  align-items: center;
@@ -80,15 +83,15 @@
80
83
  transition: background-color 0.2s ease-out;
81
84
  }
82
85
 
83
- &:hover:not(.active, [aria-current]) > i {
84
- background-color: color-mix(in oklab, var(--md-sys-color-on-surface) 8%, transparent);
86
+ &:hover:not(.active, [aria-current]) > #{$icon} {
87
+ background-color: color-mix(in oklab, var(--md-sys-color-on-surface) state-opacity("hover"), transparent);
85
88
  }
86
89
 
87
90
  &.active,
88
91
  &[aria-current] {
89
92
  color: var(--md-sys-color-on-surface);
90
93
 
91
- > i {
94
+ > #{$icon} {
92
95
  background-color: var(--md-comp-nav-bar-active-indicator-color);
93
96
  color: var(--md-comp-nav-bar-active-color);
94
97
  --md-icon-fill: 1;
@@ -106,8 +109,12 @@
106
109
  position: absolute;
107
110
  z-index: 1;
108
111
  top: calc(4px + (var(--md-comp-nav-bar-indicator-height) - 24px) / 2);
109
- left: calc(50% + 12px);
112
+ inset-inline-start: calc(50% + 12px);
110
113
  transform: translate(-50%, -50%);
114
+
115
+ &:dir(rtl) {
116
+ transform: translate(50%, -50%);
117
+ }
111
118
  }
112
119
  }
113
120
 
@@ -123,7 +130,7 @@
123
130
  padding: 8px 16px;
124
131
  border-radius: var(--md-comp-nav-bar-indicator-shape);
125
132
 
126
- > i {
133
+ > #{$icon} {
127
134
  width: var(--md-comp-nav-bar-icon-size);
128
135
  height: var(--md-comp-nav-bar-icon-size);
129
136
  border-radius: 0;
@@ -134,12 +141,16 @@
134
141
  left: auto;
135
142
  inset-inline-start: calc(16px + 24px);
136
143
  transform: translate(-50%, -50%);
144
+
145
+ &:dir(rtl) {
146
+ transform: translate(50%, -50%);
147
+ }
137
148
  }
138
149
 
139
150
  &:hover:not(.active, [aria-current]) {
140
- background-color: color-mix(in oklab, var(--md-sys-color-on-surface) 8%, transparent);
151
+ background-color: color-mix(in oklab, var(--md-sys-color-on-surface) state-opacity("hover"), transparent);
141
152
 
142
- > i {
153
+ > #{$icon} {
143
154
  background-color: transparent;
144
155
  }
145
156
  }
@@ -149,7 +160,7 @@
149
160
  background-color: var(--md-comp-nav-bar-active-indicator-color);
150
161
  color: var(--md-comp-nav-bar-active-color);
151
162
 
152
- > i {
163
+ > #{$icon} {
153
164
  background-color: transparent;
154
165
  color: inherit;
155
166
  }