@expressivecss/expressive 0.7.0-rc.0 → 0.8.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 (105) hide show
  1. package/CHANGELOG.md +1311 -1
  2. package/README.md +14 -11
  3. package/dist/css/expressive.css +4215 -1668
  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/js/expressive.cjs +1231 -1253
  8. package/dist/js/expressive.cjs.map +4 -4
  9. package/dist/js/expressive.js +1231 -1253
  10. package/dist/js/expressive.js.map +4 -4
  11. package/dist/js/expressive.min.js +12 -12
  12. package/dist/js/expressive.min.js.map +4 -4
  13. package/dist/js/expressive.mjs +1231 -1253
  14. package/dist/js/expressive.mjs.map +4 -4
  15. package/dist/types/behaviors/bottomSheets.d.ts +19 -11
  16. package/dist/types/behaviors/sheetDrag.d.ts +40 -0
  17. package/dist/types/behaviors/sideSheets.d.ts +2 -9
  18. package/dist/types/components/autocomplete.d.ts +15 -3
  19. package/dist/types/components/buttons.d.ts +5 -1
  20. package/dist/types/components/carousel.d.ts +87 -53
  21. package/dist/types/components/chips.d.ts +21 -1
  22. package/dist/types/components/expandingCard.d.ts +31 -0
  23. package/dist/types/components/index.d.ts +21 -20
  24. package/dist/types/components/lightbox.d.ts +1 -0
  25. package/dist/types/components/menu.d.ts +7 -1
  26. package/dist/types/components/{sidenav.d.ts → navigationDrawer.d.ts} +16 -16
  27. package/dist/types/components/registry.d.ts +8 -8
  28. package/dist/types/components/slider.d.ts +26 -85
  29. package/dist/types/components/snackbar.d.ts +20 -5
  30. package/dist/types/components/tabs.d.ts +12 -0
  31. package/dist/types/components/timepicker.d.ts +12 -9
  32. package/dist/types/core/utils.d.ts +64 -53
  33. package/dist/types/index.d.ts +8 -9
  34. package/package.json +15 -1
  35. package/src/sass/README.md +61 -11
  36. package/src/sass/abstracts/_breakpoints.scss +17 -19
  37. package/src/sass/abstracts/_mixins.scss +103 -21
  38. package/src/sass/abstracts/_variables.scss +50 -5
  39. package/src/sass/base/_global.scss +6 -24
  40. package/src/sass/base/_grid.scss +15 -12
  41. package/src/sass/base/_normalize.scss +34 -38
  42. package/src/sass/base/_typography.scss +4 -18
  43. package/src/sass/components/_badges.scss +2 -3
  44. package/src/sass/components/_banners.scss +298 -0
  45. package/src/sass/components/_bottom-app-bar.scss +180 -0
  46. package/src/sass/components/_bottom-sheet.scss +12 -4
  47. package/src/sass/components/_button-groups.scss +186 -0
  48. package/src/sass/components/_buttons.scss +245 -92
  49. package/src/sass/components/_cards.scss +494 -73
  50. package/src/sass/components/_carousel.scss +562 -68
  51. package/src/sass/components/_chips.scss +64 -5
  52. package/src/sass/components/_datepicker.scss +24 -24
  53. package/src/sass/components/_dialog.scss +17 -11
  54. package/src/sass/components/_drag-handle.scss +130 -0
  55. package/src/sass/components/_expanding-card.scss +260 -0
  56. package/src/sass/components/_fab-menu.scss +232 -0
  57. package/src/sass/components/_floating-sheet.scss +86 -0
  58. package/src/sass/components/_icon-buttons.scss +194 -0
  59. package/src/sass/components/_icons-material-design.scss +16 -4
  60. package/src/sass/components/_index.scss +22 -6
  61. package/src/sass/components/_list.scss +16 -13
  62. package/src/sass/components/_loading-indicator.scss +106 -0
  63. package/src/sass/components/_menu.scss +335 -61
  64. package/src/sass/components/_navbar.scss +71 -24
  65. package/src/sass/components/_navigation-bar.scss +13 -10
  66. package/src/sass/components/{_sidenav.scss → _navigation-drawer.scss} +123 -33
  67. package/src/sass/components/_navigation-rail.scss +22 -22
  68. package/src/sass/components/_page-footer.scss +19 -16
  69. package/src/sass/components/_pagination.scss +24 -6
  70. package/src/sass/components/_panes.scss +52 -11
  71. package/src/sass/components/{_preloader.scss → _progress.scss} +11 -3
  72. package/src/sass/components/_scrim.scss +37 -0
  73. package/src/sass/components/_search.scss +259 -0
  74. package/src/sass/components/_segmented-buttons.scss +188 -0
  75. package/src/sass/components/_side-sheet.scss +2 -2
  76. package/src/sass/components/_snackbar.scss +20 -15
  77. package/src/sass/components/_split-button.scss +196 -0
  78. package/src/sass/components/_tabs.scss +7 -8
  79. package/src/sass/components/_timepicker.scss +67 -58
  80. package/src/sass/components/_toolbar.scss +206 -80
  81. package/src/sass/components/forms/_checkboxes.scss +49 -12
  82. package/src/sass/components/forms/_fieldset.scss +4 -4
  83. package/src/sass/components/forms/_file-input.scss +8 -1
  84. package/src/sass/components/forms/_index.scss +1 -1
  85. package/src/sass/components/forms/_input-fields.scss +50 -44
  86. package/src/sass/components/forms/_radio-buttons.scss +42 -10
  87. package/src/sass/components/forms/_select.scss +0 -1
  88. package/src/sass/components/forms/{_range.scss → _slider.scss} +8 -9
  89. package/src/sass/components/forms/_switches.scss +6 -7
  90. package/src/sass/tokens/_index.scss +4 -1
  91. package/src/sass/tokens/_reference.scss +70 -61
  92. package/src/sass/tokens/_state.scss +24 -0
  93. package/src/sass/tokens/_theme.scss +6 -3
  94. package/src/sass/tokens/_vibrant.scss +76 -0
  95. package/src/sass/utilities/_colors.scss +14 -1
  96. package/src/sass/utilities/_helpers.scss +5 -5
  97. package/src/sass/utilities/_visibility.scss +48 -26
  98. package/dist/types/behaviors/waves.d.ts +0 -15
  99. package/dist/types/components/parallax.d.ts +0 -16
  100. package/dist/types/components/range.d.ts +0 -43
  101. package/dist/types/core/bounding.d.ts +0 -6
  102. package/dist/types/core/edges.d.ts +0 -6
  103. package/src/sass/components/_parallax.scss +0 -104
  104. package/src/sass/components/_pulse.scss +0 -37
  105. package/src/sass/components/_slider.scss +0 -129
@@ -24,7 +24,7 @@
24
24
  //
25
25
  // Nest descendants inside this block.
26
26
 
27
- :root {
27
+ :root, :host {
28
28
  --md-comp-nav-rail-collapsed-width: 96px;
29
29
  --md-comp-nav-rail-expanded-width: 280px;
30
30
  }
@@ -59,7 +59,7 @@
59
59
  padding var(--md-comp-nav-rail-duration) ease;
60
60
 
61
61
  // Menu toggle.
62
- > button:not(.button):first-child {
62
+ > button:not(.button, .icon-button):first-child {
63
63
  display: flex;
64
64
  flex: 0 0 auto;
65
65
  align-items: center;
@@ -76,14 +76,14 @@
76
76
  appearance: none;
77
77
  @include focus-visible;
78
78
 
79
- > i {
79
+ > #{$icon} {
80
80
  font-size: var(--md-comp-nav-rail-icon-size);
81
81
  width: var(--md-comp-nav-rail-icon-size);
82
82
  height: var(--md-comp-nav-rail-icon-size);
83
83
  }
84
84
 
85
85
  &:hover {
86
- background-color: color-mix(in oklab, var(--md-sys-color-on-surface) 8%, transparent);
86
+ background-color: color-mix(in oklab, var(--md-sys-color-on-surface) state-opacity("hover"), transparent);
87
87
  }
88
88
  }
89
89
 
@@ -105,7 +105,7 @@
105
105
  background-color: var(--md-sys-color-primary-container);
106
106
  text-decoration: none;
107
107
 
108
- > :not(i) {
108
+ > :not(#{$icon}) {
109
109
  position: absolute;
110
110
  width: 1px;
111
111
  height: 1px;
@@ -115,8 +115,8 @@
115
115
  }
116
116
 
117
117
  // Destinations.
118
- > a:not(.button),
119
- > button:not(.button):not(:first-child) {
118
+ > a:not(.button, .icon-button),
119
+ > button:not(.button, .icon-button):not(:first-child) {
120
120
  position: relative;
121
121
  display: flex;
122
122
  flex: 0 0 auto;
@@ -138,7 +138,7 @@
138
138
  @include typescale("label-medium");
139
139
  @include focus-visible;
140
140
 
141
- > i {
141
+ > #{$icon} {
142
142
  display: flex;
143
143
  flex-shrink: 0;
144
144
  align-items: center;
@@ -152,15 +152,15 @@
152
152
  transition: background-color var(--md-comp-nav-rail-duration) ease;
153
153
  }
154
154
 
155
- &:hover:not(.active, [aria-current]) > i {
156
- background-color: color-mix(in oklab, var(--md-sys-color-on-surface) 8%, transparent);
155
+ &:hover:not(.active, [aria-current]) > #{$icon} {
156
+ background-color: color-mix(in oklab, var(--md-sys-color-on-surface) state-opacity("hover"), transparent);
157
157
  }
158
158
 
159
159
  &.active,
160
160
  &[aria-current] {
161
161
  color: var(--md-sys-color-on-surface);
162
162
 
163
- > i {
163
+ > #{$icon} {
164
164
  background-color: var(--md-comp-nav-rail-active-indicator-color);
165
165
  color: var(--md-comp-nav-rail-active-color);
166
166
  --md-icon-fill: 1;
@@ -197,7 +197,7 @@
197
197
  min-width: 220px;
198
198
  padding-inline: 16px;
199
199
 
200
- > button:not(.button):first-child {
200
+ > button:not(.button, .icon-button):first-child {
201
201
  justify-content: flex-start;
202
202
  width: auto;
203
203
  padding-inline: 16px;
@@ -210,7 +210,7 @@
210
210
  color: var(--md-sys-color-on-primary-container);
211
211
  background-color: var(--md-sys-color-primary-container);
212
212
 
213
- > :not(i) {
213
+ > :not(#{$icon}) {
214
214
  position: static;
215
215
  width: auto;
216
216
  height: auto;
@@ -220,8 +220,8 @@
220
220
  }
221
221
  }
222
222
 
223
- > a:not(.button),
224
- > button:not(.button):not(:first-child) {
223
+ > a:not(.button, .icon-button),
224
+ > button:not(.button, .icon-button):not(:first-child) {
225
225
  flex-direction: row;
226
226
  justify-content: flex-start;
227
227
  gap: 12px;
@@ -230,16 +230,16 @@
230
230
  border-radius: var(--md-comp-nav-rail-indicator-shape);
231
231
  text-align: start;
232
232
 
233
- > i {
233
+ > #{$icon} {
234
234
  width: var(--md-comp-nav-rail-icon-size);
235
235
  height: var(--md-comp-nav-rail-icon-size);
236
236
  border-radius: 0;
237
237
  }
238
238
 
239
239
  &:hover:not(.active, [aria-current]) {
240
- background-color: color-mix(in oklab, var(--md-sys-color-on-surface) 8%, transparent);
240
+ background-color: color-mix(in oklab, var(--md-sys-color-on-surface) state-opacity("hover"), transparent);
241
241
 
242
- > i {
242
+ > #{$icon} {
243
243
  background-color: transparent;
244
244
  }
245
245
  }
@@ -249,7 +249,7 @@
249
249
  background-color: var(--md-comp-nav-rail-active-indicator-color);
250
250
  color: var(--md-comp-nav-rail-active-color);
251
251
 
252
- > i {
252
+ > #{$icon} {
253
253
  background-color: transparent;
254
254
  color: inherit;
255
255
  }
@@ -278,12 +278,12 @@
278
278
  content: "";
279
279
  position: fixed;
280
280
  inset: 0;
281
- background-color: color-mix(in oklab, var(--md-sys-color-scrim) 32%, transparent);
281
+ background-color: var(--md-comp-scrim-color);
282
282
  z-index: -1;
283
283
  }
284
284
  }
285
285
 
286
- @include bp-down("small") {
286
+ @include bp-down("medium") {
287
287
  &.expanded:not(.modal) {
288
288
  position: fixed;
289
289
  inset: 0 auto 0 0;
@@ -294,7 +294,7 @@
294
294
  content: "";
295
295
  position: fixed;
296
296
  inset: 0;
297
- background-color: color-mix(in oklab, var(--md-sys-color-scrim) 32%, transparent);
297
+ background-color: var(--md-comp-scrim-color);
298
298
  z-index: -1;
299
299
  }
300
300
  }
@@ -3,7 +3,8 @@
3
3
  // Site footer.
4
4
  //
5
5
  // Anatomy is the HTML. A <footer> is the landmark. A heading is a column
6
- // title. A <nav> (or ul) is a link list. The last child <small> is the
6
+ // title. A <nav> (or ul) is a link list; a column with no links is a
7
+ // <section>. The last child <small> is the
7
8
  // legal bar. A footer whose only child is nav.navigation-bar is the
8
9
  // navigation bar, not this component.
9
10
  //
@@ -32,10 +33,9 @@ footer:not(:has(> .navigation-bar:only-child)) {
32
33
  margin: 0 0 8px;
33
34
  color: var(--md-sys-color-on-surface-variant);
34
35
  @include typescale("body-medium");
35
- font-family: $font-stack;
36
36
  }
37
37
 
38
- a:not(.button, .circle, .extra) {
38
+ a:not(.button, .icon-button, .circle, .extra) {
39
39
  color: var(--md-sys-color-primary);
40
40
  text-decoration: none;
41
41
  @include focus-visible;
@@ -45,7 +45,6 @@ footer:not(:has(> .navigation-bar:only-child)) {
45
45
  margin: 0 0 8px;
46
46
  color: var(--md-sys-color-on-surface);
47
47
  @include typescale("title-small");
48
- font-family: $font-stack;
49
48
  }
50
49
 
51
50
  ul {
@@ -69,19 +68,19 @@ footer:not(:has(> nav:only-child)):not(:has(> .container)) {
69
68
  gap: var(--md-comp-footer-gap);
70
69
  grid-template-columns: 1fr;
71
70
 
72
- @include bp-up("small") {
71
+ @include bp-up("medium") {
73
72
  grid-template-columns: repeat(2, 1fr);
74
73
  }
75
74
 
76
- @include bp-up("large") {
75
+ @include bp-up("expanded") {
77
76
  grid-template-columns: repeat(4, 1fr);
78
77
  }
79
78
 
80
- @include bp-up("xlarge") {
79
+ @include bp-up("large") {
81
80
  grid-template-columns: repeat(5, 1fr);
82
81
  }
83
82
 
84
- @include bp-up("xxlarge") {
83
+ @include bp-up("extra-large") {
85
84
  grid-template-columns: repeat(6, 1fr);
86
85
  }
87
86
  }
@@ -91,7 +90,9 @@ footer:not(:has(> nav:only-child)) > .row {
91
90
  grid-column: 1 / -1;
92
91
  }
93
92
 
94
- footer:not(:has(> nav:only-child)) nav {
93
+ // A column with no links is a <section>, not a <nav> - see rule 4. Both are
94
+ // columns to look at.
95
+ footer:not(:has(> nav:only-child)) :is(nav, section) {
95
96
  display: flex;
96
97
  flex-direction: column;
97
98
  align-items: flex-start;
@@ -99,8 +100,8 @@ footer:not(:has(> nav:only-child)) nav {
99
100
  min-width: 0;
100
101
  }
101
102
 
102
- footer:not(:has(> nav:only-child)) nav > a:not(.button, .circle, .extra),
103
- footer:not(:has(> nav:only-child)) ul a:not(.button, .circle, .extra) {
103
+ footer:not(:has(> nav:only-child)) nav > a:not(.button, .icon-button, .circle, .extra),
104
+ footer:not(:has(> nav:only-child)) ul a:not(.button, .icon-button, .circle, .extra) {
104
105
  display: inline-flex;
105
106
  align-items: center;
106
107
  box-sizing: border-box;
@@ -109,14 +110,17 @@ footer:not(:has(> nav:only-child)) ul a:not(.button, .circle, .extra) {
109
110
  margin-inline-start: -12px;
110
111
  border-radius: 2rem;
111
112
  @include typescale("label-large");
112
- font-family: $font-stack;
113
113
 
114
114
  &:hover {
115
- background-color: color-mix(in oklab, var(--md-sys-color-on-surface) 8%, transparent);
115
+ background-color: color-mix(in oklab, var(--md-sys-color-on-surface) state-opacity("hover"), transparent);
116
116
  }
117
117
  }
118
118
 
119
- footer:not(:has(> nav:only-child)) > small:last-child {
119
+ // The legal bar. `.container` is a supported columns wrapper - the rule above
120
+ // already accounts for it - so the bar has to be found through it too, or a
121
+ // footer written the documented way gets an unstyled copyright row.
122
+ footer:not(:has(> nav:only-child)) > small:last-child,
123
+ footer:not(:has(> nav:only-child)) > .container > small:last-child {
120
124
  display: flex;
121
125
  flex-wrap: wrap;
122
126
  align-items: center;
@@ -130,9 +134,8 @@ footer:not(:has(> nav:only-child)) > small:last-child {
130
134
  border-top: 1px solid var(--md-sys-color-outline-variant);
131
135
  color: var(--md-sys-color-on-surface-variant);
132
136
  @include typescale("body-small");
133
- font-family: $font-stack;
134
137
 
135
- a:not(.button) {
138
+ a:not(.button, .icon-button) {
136
139
  color: var(--md-sys-color-primary);
137
140
  }
138
141
  }
@@ -4,7 +4,9 @@
4
4
  // <ol> (or <ul>) of page links. The current page is aria-current="page".
5
5
  // A bare <ul class="pagination"> stays as an alias.
6
6
  //
7
- // .active / .disabled / .prev / .next / .pages still work.
7
+ // .active / .disabled / .pages still work. .prev / .next are accepted but
8
+ // inert - nothing matches them. They used to drive a 10%/80% split, which
9
+ // .nowrap replaced with scrolling.
8
10
  // .nowrap (or the old li.pages nest) scrolls a long run instead of wrapping.
9
11
  //
10
12
  // Tokens (defaults match the original compact pager):
@@ -86,14 +88,22 @@
86
88
  @include focus-visible;
87
89
 
88
90
  &:hover {
89
- background-color: color-mix(in oklab, var(--md-sys-color-on-surface) 8%, transparent);
91
+ background-color: color-mix(in oklab, var(--md-sys-color-on-surface) state-opacity("hover"), transparent);
90
92
  }
91
93
 
92
- &:has(> span) {
94
+ // The pressed layer is the only feedback a touch tap gets: hover never
95
+ // fires there and the tap highlight is suppressed above.
96
+ &:active {
97
+ background-color: color-mix(in oklab, var(--md-sys-color-on-surface) state-opacity("pressed"), transparent);
98
+ }
99
+
100
+ // "Does this control carry a text label?" - the icon is a <span>, so a
101
+ // bare `span` here answers yes for every icon-only prev/next button.
102
+ &:has(> #{$icon-label}) {
93
103
  width: auto;
94
104
  }
95
105
 
96
- > i {
106
+ > #{$icon} {
97
107
  font-size: var(--md-comp-pagination-icon-size);
98
108
  width: var(--md-comp-pagination-icon-size);
99
109
  height: var(--md-comp-pagination-icon-size);
@@ -110,7 +120,15 @@
110
120
  &:hover {
111
121
  background-color: color-mix(
112
122
  in oklab,
113
- var(--md-comp-pagination-selected-on-color) 8%,
123
+ var(--md-comp-pagination-selected-on-color) state-opacity("hover"),
124
+ var(--md-comp-pagination-selected-color)
125
+ );
126
+ }
127
+
128
+ &:active {
129
+ background-color: color-mix(
130
+ in oklab,
131
+ var(--md-comp-pagination-selected-on-color) state-opacity("pressed"),
114
132
  var(--md-comp-pagination-selected-color)
115
133
  );
116
134
  }
@@ -124,7 +142,7 @@
124
142
  cursor: default;
125
143
  }
126
144
 
127
- li > span {
145
+ li > #{$icon-label} {
128
146
  box-sizing: border-box;
129
147
  display: inline-flex;
130
148
  align-items: center;
@@ -7,7 +7,7 @@
7
7
  //
8
8
  // Canonical Layouts:
9
9
  // 1. List-Detail (.list-detail, .panes.list-detail):
10
- // - Compact (< 840px / < 601px): Single pane visible at a time.
10
+ // - Compact and Medium (< 840px): Single pane visible at a time.
11
11
  // - Expanded (>= 840px): 360dp list pane + 1fr detail pane.
12
12
  // 2. Supporting Pane (.supporting-pane-layout, .panes.supporting):
13
13
  // - 1fr primary pane + 360-400dp supporting pane (on trailing or leading side).
@@ -20,6 +20,7 @@
20
20
  // with surface-container-low and a 24dp gap.
21
21
  //
22
22
  // Tokens follow https://m3.material.io/foundations/adaptive-design/canonical-layouts
23
+ // --md-comp-pane-margin 16px Compact / 24px Medium+
23
24
  // --md-comp-pane-gap 24px
24
25
  // --md-comp-pane-divider-color outline-variant
25
26
  // --md-comp-pane-container-color surface
@@ -51,10 +52,25 @@
51
52
  background-color: var(--md-comp-pane-container-color);
52
53
  color: var(--md-sys-color-on-surface);
53
54
 
54
- // Default (Single-Pane on compact screens < 840px / < 601px)
55
+ // Default: single pane on Compact and Medium windows (< 840px).
55
56
  grid-template-columns: 1fr;
56
57
  gap: 0;
57
58
 
59
+ // M3 layout margins are the inline space between content and the window
60
+ // edges. Keep the full-height pane model and inset layouts below Large.
61
+ @include bp-down("medium") {
62
+ --md-comp-pane-margin: 16px;
63
+ width: calc(100% - (2 * var(--md-comp-pane-margin)));
64
+ margin-inline: var(--md-comp-pane-margin);
65
+ }
66
+
67
+ @include bp-between("medium", "expanded") {
68
+ --md-comp-pane-margin: 24px;
69
+ width: calc(100% - (2 * var(--md-comp-pane-margin)));
70
+ margin-inline: var(--md-comp-pane-margin);
71
+ gap: var(--md-comp-pane-gap);
72
+ }
73
+
58
74
  // Panes in compact mode: list/primary visible by default, detail/supporting hidden
59
75
  // unless marked .active
60
76
  > :is(.pane, .list-pane, .primary-pane, .detail-pane, .supporting-pane) {
@@ -75,7 +91,7 @@
75
91
  }
76
92
 
77
93
  // Expanded Viewports: Dual-pane side-by-side (via container query or breakpoint)
78
- @media (width >= 840px) {
94
+ @include bp-up("expanded") {
79
95
  grid-template-columns: var(--md-comp-pane-list-width) 1fr;
80
96
  gap: 0;
81
97
 
@@ -92,6 +108,29 @@
92
108
  display: flex !important;
93
109
  }
94
110
  }
111
+
112
+ // This follows both two-pane rules so their base gap cannot cancel the M3
113
+ // Expanded spacer when the viewport and container queries both match.
114
+ @include bp-between("expanded", "large") {
115
+ --md-comp-pane-margin: 24px;
116
+ width: calc(100% - (2 * var(--md-comp-pane-margin)));
117
+ margin-inline: var(--md-comp-pane-margin);
118
+ gap: var(--md-comp-pane-gap);
119
+ }
120
+
121
+ @include bp-between("large", "extra-large") {
122
+ --md-comp-pane-margin: 24px;
123
+ width: calc(100% - (2 * var(--md-comp-pane-margin)));
124
+ margin-inline: var(--md-comp-pane-margin);
125
+ gap: var(--md-comp-pane-gap);
126
+ }
127
+
128
+ @include bp-up("extra-large") {
129
+ --md-comp-pane-margin: 24px;
130
+ width: calc(100% - (2 * var(--md-comp-pane-margin)));
131
+ margin-inline: var(--md-comp-pane-margin);
132
+ gap: var(--md-comp-pane-gap);
133
+ }
95
134
  }
96
135
 
97
136
  // ---------------------------------------------------------------------------
@@ -101,7 +140,7 @@
101
140
  // 1. Supporting Pane Layout
102
141
  .supporting-pane-layout,
103
142
  .panes.supporting {
104
- @media (width >= 840px) {
143
+ @include bp-up("expanded") {
105
144
  grid-template-columns: 1fr var(--md-comp-pane-supporting-width);
106
145
  }
107
146
 
@@ -112,7 +151,7 @@
112
151
  // Leading supporting pane (.start / .left)
113
152
  &.start,
114
153
  &.left {
115
- @media (width >= 840px) {
154
+ @include bp-up("expanded") {
116
155
  grid-template-columns: var(--md-comp-pane-supporting-width) 1fr;
117
156
  }
118
157
 
@@ -125,7 +164,7 @@
125
164
  // 2. Equal / Proportional Pane Layout
126
165
  .panes.equal,
127
166
  .pane-layout.equal {
128
- @media (width >= 840px) {
167
+ @include bp-up("expanded") {
129
168
  grid-template-columns: 1fr 1fr;
130
169
  }
131
170
 
@@ -137,7 +176,7 @@
137
176
  // 3. Three-Pane Layout (List + Primary Focus + Supporting)
138
177
  .panes.three-pane,
139
178
  .pane-layout.three-pane {
140
- @media (width >= 1200px) {
179
+ @include bp-up("large") {
141
180
  grid-template-columns: var(--md-comp-pane-list-width) 1fr var(--md-comp-pane-supporting-width);
142
181
  }
143
182
 
@@ -181,7 +220,7 @@
181
220
  // ---------------------------------------------------------------------------
182
221
  :is(.panes, .pane-layout, .list-detail, .supporting-pane-layout):not(.separated, .floating) {
183
222
  > :is(.pane, .list-pane, .primary-pane, .detail-pane, .supporting-pane):not(:last-child) {
184
- @media (width >= 840px) {
223
+ @include bp-up("expanded") {
185
224
  border-inline-end: 1px solid var(--md-comp-pane-divider-color);
186
225
  }
187
226
 
@@ -231,7 +270,9 @@
231
270
  text-overflow: ellipsis;
232
271
  }
233
272
 
234
- > :is(button, a.button):has(> i:only-child) {
273
+ // See _dialog: `:only-child` cannot see a text-node label, so `.button`
274
+ // is the opt-out for an icon action that also carries one.
275
+ > :is(button:not(.button, .icon-button), a.button):has(> #{$icon}:only-child) {
235
276
  flex: 0 0 48px;
236
277
  box-sizing: border-box;
237
278
  width: 48px;
@@ -244,7 +285,7 @@
244
285
  color: var(--md-sys-color-on-surface-variant);
245
286
  box-shadow: none;
246
287
 
247
- > i {
288
+ > #{$icon} {
248
289
  font-size: 24px;
249
290
  width: 24px;
250
291
  height: 24px;
@@ -252,7 +293,7 @@
252
293
  }
253
294
 
254
295
  &:hover {
255
- background-color: color-mix(in oklab, var(--md-sys-color-on-surface) 8%, transparent);
296
+ background-color: color-mix(in oklab, var(--md-sys-color-on-surface) state-opacity("hover"), transparent);
256
297
  }
257
298
 
258
299
  &:focus-visible {
@@ -17,6 +17,9 @@
17
17
  // --md-comp-progress-circular-size 48px
18
18
  // --md-comp-progress-circular-thickness 4px
19
19
 
20
+ // M3 names this component "Progress indicators", linear and circular. The
21
+ // class is `.progress`; `.preloader` is the Materialize name for the circular
22
+ // one and stays as an alias, as does `.progress.circular`.
20
23
  .progress,
21
24
  .preloader {
22
25
  --md-comp-progress-track: var(--md-sys-color-secondary-container);
@@ -78,8 +81,11 @@ progress.progress {
78
81
  transition: width 0.3s linear;
79
82
  }
80
83
 
81
- // Bare div.progress with a value token, no child.
82
- .progress:not(:is(progress)):not(:has(> .determinate, > .indeterminate)) {
84
+ // Bare div.progress with a value token, no child. :not(.circular) because a
85
+ // `<span class="progress circular">` is not a <progress>, has no determinate
86
+ // child, and so matched this too - drawing a linear fill on top of the conic
87
+ // circular indicator.
88
+ .progress:not(:is(progress)):not(.circular):not(:has(> .determinate, > .indeterminate)) {
83
89
  &::after {
84
90
  content: "";
85
91
  position: absolute;
@@ -133,7 +139,9 @@ progress.progress:indeterminate {
133
139
  // Circular — one element
134
140
  // ---------------------------------------------------------------------------
135
141
 
136
- .preloader {
142
+ // The circular indicator. `.progress.circular` is the M3-aligned name;
143
+ // `.preloader` is the Materialize one and still works.
144
+ :is(.preloader, .progress.circular) {
137
145
  box-sizing: border-box;
138
146
  display: inline-block;
139
147
  width: var(--md-comp-progress-circular-size);
@@ -0,0 +1,37 @@
1
+ @use "../abstracts" as *;
2
+
3
+ // Scrim (M3 Expressive). A foundation, not a component: there is no markup an
4
+ // author writes to get one. It is the wash a modal surface puts behind itself
5
+ // to dim what it covers, and this is the one place its value is decided -
6
+ // dialogs, both sheets, the navigation drawer and the modal navigation rail
7
+ // all consume the same custom property - the sheets through the
8
+ // `dialog::backdrop` rule they already share, so they declare nothing.
9
+ //
10
+ // https://m3.material.io/styles/color/roles - the `scrim` role, at 32%.
11
+ //
12
+ // Blur is deliberately not part of it. Only the basic dialog frosts what is
13
+ // behind it (`--md-comp-basic-dialog-scrim-blur`); the drawer and the rail
14
+ // slide over the page and would smear it.
15
+ //
16
+ // Declared on :root rather than per surface because four of the five consumers
17
+ // paint into `::backdrop`, which has no box of its own to hang a token on -
18
+ // only the rail uses a `::before`. `::backdrop` inherits from the element it
19
+ // belongs to, so setting this on one `<dialog>` still dims only that one.
20
+ //
21
+ // Resolving the mix here narrows one thing, deliberately: `--md-sys-color-scrim`
22
+ // is substituted at :root, so overriding *that* on a subtree no longer reaches a
23
+ // scrim below it. Override it at the root to move every scrim, or set
24
+ // `--md-comp-scrim-color` on a surface to move one. A scrim is painted by a
25
+ // top-layer or fixed box covering the viewport, so it has no meaningful subtree
26
+ // to be rethemed by in the first place.
27
+
28
+ // `:host` alongside `:root` for the reason tokens/_theme.scss and
29
+ // tokens/_state.scss carry it: a sheet loaded inside a shadow root cannot reach
30
+ // its own host with `:root`, and the token would be undefined there - taking
31
+ // `background-color` down with it, so the surface would show no scrim at all.
32
+ // The rules this replaced read `--md-sys-color-scrim`, which is declared on
33
+ // both, so :root alone would have narrowed what already worked.
34
+ :root,
35
+ :host {
36
+ --md-comp-scrim-color: color-mix(in oklab, var(--md-sys-color-scrim) 32%, transparent);
37
+ }