@expressivecss/expressive 0.3.0 → 0.5.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 (96) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/README.md +4 -9
  3. package/dist/css/expressive.css +3183 -2150
  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 +1254 -1567
  8. package/dist/js/expressive.cjs.map +4 -4
  9. package/dist/js/expressive.js +1254 -1567
  10. package/dist/js/expressive.js.map +4 -4
  11. package/dist/js/expressive.min.js +12 -22
  12. package/dist/js/expressive.min.js.map +4 -4
  13. package/dist/js/expressive.mjs +1254 -1568
  14. package/dist/js/expressive.mjs.map +4 -4
  15. package/dist/types/behaviors/bottomSheets.d.ts +18 -0
  16. package/dist/types/behaviors/sideSheets.d.ts +18 -0
  17. package/dist/types/components/autocomplete.d.ts +13 -20
  18. package/dist/types/components/buttons.d.ts +2 -2
  19. package/dist/types/components/cards.d.ts +3 -6
  20. package/dist/types/components/carousel.d.ts +3 -3
  21. package/dist/types/components/characterCounter.d.ts +3 -5
  22. package/dist/types/components/chips.d.ts +2 -2
  23. package/dist/types/components/datepicker.d.ts +2 -8
  24. package/dist/types/components/index.d.ts +3 -6
  25. package/dist/types/components/lightbox.d.ts +2 -2
  26. package/dist/types/components/{dropdown.d.ts → menu.d.ts} +48 -38
  27. package/dist/types/components/navigationRail.d.ts +53 -0
  28. package/dist/types/components/parallax.d.ts +2 -8
  29. package/dist/types/components/range.d.ts +5 -2
  30. package/dist/types/components/registry.d.ts +7 -19
  31. package/dist/types/components/scrollspy.d.ts +26 -50
  32. package/dist/types/components/select.d.ts +28 -14
  33. package/dist/types/components/sidenav.d.ts +40 -55
  34. package/dist/types/components/slider.d.ts +2 -2
  35. package/dist/types/components/{toasts.d.ts → snackbar.d.ts} +28 -25
  36. package/dist/types/components/tabs.d.ts +2 -2
  37. package/dist/types/components/timepicker.d.ts +2 -4
  38. package/dist/types/components/tooltip.d.ts +2 -2
  39. package/dist/types/core/component.d.ts +4 -4
  40. package/dist/types/index.d.ts +3 -1
  41. package/package.json +4 -3
  42. package/src/sass/README.md +13 -15
  43. package/src/sass/abstracts/_breakpoints.scss +14 -19
  44. package/src/sass/abstracts/_mixins.scss +3 -3
  45. package/src/sass/abstracts/_variables.scss +27 -23
  46. package/src/sass/base/_global.scss +1 -1
  47. package/src/sass/base/_grid.scss +64 -133
  48. package/src/sass/base/_index.scss +1 -1
  49. package/src/sass/components/_badges.scss +76 -61
  50. package/src/sass/components/_bottom-sheet.scss +137 -0
  51. package/src/sass/components/_buttons.scss +22 -54
  52. package/src/sass/components/_cards.scss +54 -127
  53. package/src/sass/components/_carousel.scss +4 -6
  54. package/src/sass/components/_chips.scss +6 -5
  55. package/src/sass/components/_datepicker.scss +1 -15
  56. package/src/sass/components/_dialog.scss +268 -0
  57. package/src/sass/components/_index.scss +9 -7
  58. package/src/sass/components/_list.scss +253 -0
  59. package/src/sass/components/_menu.scss +341 -0
  60. package/src/sass/components/_navbar.scss +68 -117
  61. package/src/sass/components/_navigation-bar.scss +165 -0
  62. package/src/sass/components/_navigation-rail.scss +308 -0
  63. package/src/sass/components/_page-footer.scss +138 -15
  64. package/src/sass/components/_parallax.scss +7 -28
  65. package/src/sass/components/_preloader.scss +145 -300
  66. package/src/sass/components/_scrollspy.scss +18 -0
  67. package/src/sass/components/_side-sheet.scss +193 -0
  68. package/src/sass/components/_sidenav.scss +281 -146
  69. package/src/sass/components/{_toast.scss → _snackbar.scss} +43 -43
  70. package/src/sass/components/_table_of_contents.scss +30 -14
  71. package/src/sass/components/_tabs.scss +43 -50
  72. package/src/sass/components/_toolbar.scss +93 -27
  73. package/src/sass/components/_tooltip.scss +5 -10
  74. package/src/sass/components/_transitions.scss +0 -5
  75. package/src/sass/components/forms/_fieldset.scss +1 -1
  76. package/src/sass/components/forms/_index.scss +0 -5
  77. package/src/sass/components/forms/_input-fields.scss +52 -55
  78. package/src/sass/components/forms/_range.scss +423 -98
  79. package/src/sass/components/forms/_select.scss +177 -60
  80. package/src/sass/components/forms/_switches.scss +21 -8
  81. package/src/sass/tokens/_reference.scss +37 -13
  82. package/src/sass/tokens/_theme.scss +5 -13
  83. package/src/sass/utilities/_colors.scss +16 -74
  84. package/src/sass/utilities/_helpers.scss +1 -3
  85. package/src/sass/utilities/_typescale.scss +0 -5
  86. package/src/sass/utilities/_visibility.scss +10 -2
  87. package/dist/types/components/collapsible.d.ts +0 -96
  88. package/dist/types/components/modal.d.ts +0 -45
  89. package/dist/types/components/pushpin.d.ts +0 -51
  90. package/dist/types/components/tapTarget.d.ts +0 -57
  91. package/src/sass/components/_collapsible.scss +0 -181
  92. package/src/sass/components/_collection.scss +0 -198
  93. package/src/sass/components/_dropdown.scss +0 -129
  94. package/src/sass/components/_modal.scss +0 -208
  95. package/src/sass/components/_pushpin.scss +0 -11
  96. package/src/sass/components/_tapTarget.scss +0 -191
@@ -1,129 +1,284 @@
1
1
  @use "../abstracts" as *;
2
2
 
3
- .sidenav {
4
- --sidenav-width: 300px;
5
- --sidenav-font-size: 14px;
6
- --sidenav-padding: 16px;
7
- --sidenav-item-height: 48px;
8
- --sidenav-line-height: var(--sidenav-item-height);
3
+ // Navigation drawer.
4
+ //
5
+ // Overlay is a modal <dialog> (JS wraps a <ul class="sidenav"> in
6
+ // dialog.sidenav-overlay, or the author writes <dialog class="sidenav">).
7
+ // showModal() puts it on the top layer; ::backdrop is the scrim; Escape
8
+ // and a scrim tap close it. Drag writes --md-comp-nav-drawer-shift;
9
+ // this file does the slide.
10
+ //
11
+ // Nested sections are native <details>/<summary>. Same `name` is an
12
+ // accordion. The summary is a destination row with an expand_more
13
+ // chevron; there is no Collapsible plugin.
14
+ //
15
+ // .sidenav-fixed is a breakpoint, not a JS open(): at `large` the host
16
+ // is display: contents so the list is a docked sidebar. Below that it
17
+ // is the same overlay drawer as any other sidenav.
18
+ //
19
+ // Tokens:
20
+ // --md-comp-nav-drawer-width 300px
21
+ // --md-comp-nav-drawer-item-height 48px
22
+ // --md-comp-nav-drawer-duration 250ms
23
+ // --md-comp-nav-drawer-easing
24
+ // --md-comp-nav-drawer-shift 0px (JS, px from fully open)
25
+ // --md-comp-nav-drawer-open 1 (JS, 0–1 scrim opacity)
26
+ // --md-comp-nav-drawer-font-size 14px
27
+ // --md-comp-nav-drawer-padding 16px
28
+ // --md-comp-nav-drawer-line-height item height
9
29
 
10
- position: fixed;
11
- width: var(--sidenav-width);
12
- left: 0;
13
- top: 0;
30
+ :root {
31
+ --md-comp-nav-drawer-width: 300px;
32
+ }
33
+
34
+ dialog.sidenav-overlay,
35
+ dialog.sidenav {
36
+ --md-comp-nav-drawer-item-height: 48px;
37
+ --md-comp-nav-drawer-duration: 250ms;
38
+ --md-comp-nav-drawer-easing: ease;
39
+ --md-comp-nav-drawer-shift: 0px;
40
+ --md-comp-nav-drawer-open: 1;
41
+ --md-comp-nav-drawer-font-size: 14px;
42
+ --md-comp-nav-drawer-padding: 16px;
43
+ --md-comp-nav-drawer-line-height: var(--md-comp-nav-drawer-item-height);
44
+
45
+ box-sizing: border-box;
46
+ width: var(--md-comp-nav-drawer-width);
47
+ min-width: 0;
48
+ max-width: none;
49
+ max-height: none;
50
+ height: 100dvh;
14
51
  margin: 0;
15
- transform: translateX(-100%);
16
- height: 100vh;
17
52
  padding: 0;
18
- z-index: 999;
19
- overflow-y: auto;
20
- will-change: transform;
21
- backface-visibility: hidden;
22
- transform: translateX(-105%);
23
- user-select: none;
24
-
25
- color: var(--md-sys-color-on-secondary-container);
26
- background-color: var(--md-sys-color-surface);
53
+ border: none;
54
+ border-radius: 0;
55
+ inset: 0 auto 0 0;
56
+ overflow: hidden;
57
+ color: var(--md-sys-color-on-surface);
58
+ background-color: var(--md-sys-color-surface-container-low);
59
+ outline: none;
27
60
  @include z-depth("1");
28
61
 
29
- // Right Align
62
+ transform: translateX(calc(-100% + var(--md-comp-nav-drawer-shift)));
63
+ transition:
64
+ transform var(--md-comp-nav-drawer-duration) var(--md-comp-nav-drawer-easing),
65
+ display var(--md-comp-nav-drawer-duration) allow-discrete,
66
+ overlay var(--md-comp-nav-drawer-duration) allow-discrete;
67
+
68
+ &:modal {
69
+ display: flex;
70
+ flex-direction: column;
71
+ transform: translateX(var(--md-comp-nav-drawer-shift));
72
+ }
73
+
30
74
  &.right-aligned {
31
- right: 0;
32
- transform: translateX(105%);
33
- left: auto;
75
+ inset: 0 0 0 auto;
76
+ transform: translateX(calc(100% - var(--md-comp-nav-drawer-shift)));
77
+
78
+ &:modal {
79
+ transform: translateX(calc(-1 * var(--md-comp-nav-drawer-shift)));
80
+ }
81
+ }
82
+
83
+ &.dragging {
84
+ transition: none;
85
+ }
86
+
87
+ &::backdrop {
88
+ background-color: color-mix(in oklab, var(--md-sys-color-scrim) 32%, transparent);
89
+ opacity: var(--md-comp-nav-drawer-open, 1);
90
+ backdrop-filter: none;
91
+ transition:
92
+ opacity var(--md-comp-nav-drawer-duration) var(--md-comp-nav-drawer-easing),
93
+ display var(--md-comp-nav-drawer-duration) allow-discrete,
94
+ overlay var(--md-comp-nav-drawer-duration) allow-discrete;
95
+ }
96
+ }
97
+
98
+ @starting-style {
99
+ :is(dialog.sidenav-overlay, dialog.sidenav):modal {
100
+ transform: translateX(-100%);
101
+ }
102
+
103
+ :is(dialog.sidenav-overlay, dialog.sidenav).right-aligned:modal {
34
104
  transform: translateX(100%);
35
105
  }
36
106
 
37
- .collapsible {
38
- margin: 0;
107
+ :is(dialog.sidenav-overlay, dialog.sidenav):modal::backdrop {
108
+ opacity: 0;
39
109
  }
110
+ }
40
111
 
41
- /* Hover only on top row */
42
- /*a:hover {
43
- //color: red;
44
- //background-color: var(--md-sys-color-on-secondary-container);
45
- //md.sys.color.on-secondary-container
46
- }*/
47
- a:focus {
48
- background-color: rgba(0, 0, 0, 0.12);
112
+ @media (prefers-reduced-motion: reduce) {
113
+ dialog.sidenav-overlay,
114
+ dialog.sidenav {
115
+ transition: none;
116
+
117
+ &::backdrop {
118
+ transition: none;
119
+ }
49
120
  }
121
+ }
50
122
 
51
- li.active > a:not(.collapsible-header):not(.btn):not(.btn-large):not(.btn-small):not(.btn-flat):not(.btn-large):not(.btn-floating) {
52
- //color: var(--md-sys-color-on-secondary-container); //var(--md-sys-color-on-secondary-container);
53
- //background-color: var(--md-sys-color-secondary-container);
54
- background-color: color-mix(in oklab, var(--md-sys-color-secondary) 10%, transparent);
123
+ // Docked sidebar: the host must not be a box, or it would steal the
124
+ // list's position:fixed. Closed, so it is not :modal and does not
125
+ // lock the page.
126
+ @include bp-up("large") {
127
+ dialog.sidenav-overlay:has(> .sidenav-fixed):not(:modal) {
128
+ display: contents;
55
129
  }
130
+ }
131
+
132
+ .sidenav {
133
+ --md-comp-nav-drawer-item-height: 48px;
134
+ --md-comp-nav-drawer-font-size: 14px;
135
+ --md-comp-nav-drawer-padding: 16px;
136
+ --md-comp-nav-drawer-line-height: var(--md-comp-nav-drawer-item-height);
137
+
138
+ box-sizing: border-box;
139
+ position: fixed;
140
+ width: var(--md-comp-nav-drawer-width);
141
+ inset: 0 auto 0 0;
142
+ margin: 0;
143
+ padding: 0;
144
+ height: 100dvh;
145
+ z-index: 999;
146
+ overflow-y: auto;
147
+ overscroll-behavior: contain;
148
+ user-select: none;
149
+ color: var(--md-sys-color-on-surface);
150
+ background-color: var(--md-sys-color-surface-container-low);
151
+ transform: translateX(-100%);
152
+ @include z-depth("1");
56
153
 
57
- .collapsible-body > ul { padding-left: 10px; }
154
+ &.right-aligned {
155
+ inset: 0 0 0 auto;
156
+ transform: translateX(100%);
157
+ }
58
158
 
59
- li {
159
+ li {
60
160
  list-style: none;
61
161
  display: grid;
62
162
  align-content: center;
63
163
  }
64
- li > a {
65
- /* https://stackoverflow.com/questions/5848090/full-width-hover-background-for-nested-lists */
66
- //padding-left: calc(100% + var(--sidenav-padding));
67
- //margin-left: -100%;
68
- margin: 0 12px;
69
- padding: 0 var(--sidenav-padding);
70
- //padding-left: var(--sidenav-padding);
71
- // Truncate too long text
72
- /*
73
- min-width: 0;
74
- white-space: nowrap;
75
- overflow: hidden;
76
- text-overflow: ellipsis;
77
- */
164
+
165
+ li.active > a:not(.button, .circle, .extra) {
166
+ background-color: var(--md-sys-color-secondary-container);
167
+ color: var(--md-sys-color-on-secondary-container);
168
+ }
169
+
170
+ :is(li > a, summary) {
78
171
  display: flex;
79
- height: var(--sidenav-item-height);
80
- font-size: var(--sidenav-font-size);
81
- font-weight: 500;
82
172
  align-items: center;
173
+ margin: 0 12px;
174
+ padding: 0 var(--md-comp-nav-drawer-padding);
175
+ height: var(--md-comp-nav-drawer-item-height);
83
176
  overflow: hidden;
84
177
  border-radius: 100px;
178
+ font-size: var(--md-comp-nav-drawer-font-size);
179
+ font-weight: 500;
85
180
 
86
- &:not(.btn):not(.button):not(.btn-flat):not(.btn-large):not(.btn-floating) {
87
- color: var(--md-sys-color-on-secondary-container);
88
- &:hover {
89
- //color: var(--md-sys-color-on-secondary-container);
90
- //md.sys.color.on-secondary-container
91
- background-color: color-mix(in oklab, var(--md-sys-color-on-surface) 8%, transparent);
92
- }
181
+ > :is(
182
+ .material-symbols,
183
+ .material-symbols-outlined,
184
+ .material-symbols-rounded,
185
+ .material-symbols-sharp,
186
+ .material-icons
187
+ ) {
188
+ display: inline-flex;
189
+ flex-shrink: 0;
190
+ margin-right: 12px;
93
191
  }
192
+ }
94
193
 
95
- &.btn, &.button, &.btn-large, &.btn-flat, &.btn-floating {
96
- margin: 10px 15px;
194
+ li > a:not(.button, .circle, .extra),
195
+ summary {
196
+ color: var(--md-sys-color-on-surface-variant);
197
+
198
+ &:hover {
199
+ background-color: color-mix(in oklab, var(--md-sys-color-on-surface) 8%, transparent);
97
200
  }
98
201
 
99
- /* TODO: Use special class in future like "mw-icon" */
100
- & > :is(.material-symbols, .material-symbols-outlined, .material-symbols-rounded, .material-symbols-sharp, .material-icons) {
101
- display: inline-flex;
102
- vertical-align: middle;
103
- margin-right: 12px;
202
+ @include focus-visible;
203
+ }
204
+
205
+ li > a.button,
206
+ li > a.circle,
207
+ li > a.extra {
208
+ margin: 10px 15px;
209
+ }
210
+
211
+ summary {
212
+ box-sizing: border-box;
213
+ border: 0;
214
+ background: transparent;
215
+ font: inherit;
216
+ text-align: start;
217
+ list-style: none;
218
+ cursor: pointer;
219
+ appearance: none;
220
+
221
+ &::-webkit-details-marker {
222
+ display: none;
223
+ }
224
+
225
+ &::marker {
226
+ content: none;
104
227
  }
228
+
229
+ &::after {
230
+ content: "expand_more";
231
+ flex-shrink: 0;
232
+ margin-inline-start: auto;
233
+ font-family: var(--md-icon-font);
234
+ font-size: 24px;
235
+ font-style: normal;
236
+ font-variation-settings:
237
+ "FILL" var(--md-icon-fill),
238
+ "wght" var(--md-icon-weight),
239
+ "GRAD" var(--md-icon-grade),
240
+ "opsz" var(--md-icon-optical-size);
241
+ line-height: 1;
242
+ -webkit-font-smoothing: antialiased;
243
+ transition: transform var(--md-comp-nav-drawer-duration, 250ms)
244
+ var(--md-comp-nav-drawer-easing, ease);
245
+ }
246
+ }
247
+
248
+ details {
249
+ margin: 0;
250
+ }
251
+
252
+ details[open] > summary::after {
253
+ transform: rotate(180deg);
254
+ }
255
+
256
+ details > ul {
257
+ margin: 0;
258
+ padding: 0;
259
+ padding-inline-start: 10px;
260
+ list-style: none;
105
261
  }
106
262
 
107
263
  .divider {
108
- margin: calc(var(--sidenav-padding) * 0.5) 0 0 0;
264
+ margin: calc(var(--md-comp-nav-drawer-padding) * 0.5) 0 0;
109
265
  }
110
266
 
111
267
  .subheader {
112
268
  cursor: initial;
113
269
  pointer-events: none;
114
- color: red;
115
- font-size: var(--sidenav-font-size);
270
+ color: var(--md-sys-color-on-surface-variant);
271
+ font-size: var(--md-comp-nav-drawer-font-size);
116
272
  font-weight: 500;
117
- line-height: var(--sidenav-line-height);
273
+ line-height: var(--md-comp-nav-drawer-line-height);
118
274
  }
119
275
 
120
- // Remove this? is very custom
121
276
  .user-view {
122
277
  position: relative;
123
- padding: calc(var(--sidenav-padding) * 2) calc(var(--sidenav-padding) * 2) 0;
124
- margin-bottom: calc(var(--sidenav-padding) * 0.5);
278
+ padding: calc(var(--md-comp-nav-drawer-padding) * 2) calc(var(--md-comp-nav-drawer-padding) * 2) 0;
279
+ margin-bottom: calc(var(--md-comp-nav-drawer-padding) * 0.5);
125
280
 
126
- & > a {
281
+ > a {
127
282
  height: auto;
128
283
  padding: 0;
129
284
 
@@ -135,14 +290,13 @@
135
290
  .background {
136
291
  overflow: hidden;
137
292
  position: absolute;
138
- top: 0;
139
- right: 0;
140
- bottom: 0;
141
- left: 0;
293
+ inset: 0;
142
294
  z-index: -1;
143
295
  }
144
296
 
145
- .circle, .name, .email {
297
+ .circle,
298
+ .name,
299
+ .email {
146
300
  display: block;
147
301
  }
148
302
 
@@ -153,8 +307,8 @@
153
307
 
154
308
  .name,
155
309
  .email {
156
- font-size: var(--sidenav-font-size);
157
- line-height: calc(var(--sidenav-line-height) * 0.5);
310
+ font-size: var(--md-comp-nav-drawer-font-size);
311
+ line-height: calc(var(--md-comp-nav-drawer-line-height) * 0.5);
158
312
  }
159
313
 
160
314
  .name {
@@ -169,83 +323,64 @@
169
323
  }
170
324
  }
171
325
 
172
- // Touch interaction
173
- .drag-target {
326
+ // Overlay only: the dialog is the panel, so the list fills it. When the
327
+ // host is `display: contents` (a docked .sidenav-fixed) this must not
328
+ // apply — static positioning would drop the list into the header flow
329
+ // and it would read as part of the app bar.
330
+ dialog.sidenav-overlay:modal > .sidenav {
331
+ position: static;
332
+ inset: auto;
333
+ width: 100%;
174
334
  height: 100%;
175
- position: fixed;
176
- top: 0;
177
- left: 0;
178
- z-index: 998;
179
-
180
- &.right-aligned {
181
- right: 0;
182
- }
335
+ transform: none;
336
+ box-shadow: none;
337
+ background-color: transparent;
338
+ z-index: auto;
183
339
  }
184
340
 
185
- // Fixed Sidenav shown
186
341
  .sidenav.sidenav-fixed {
187
- left: 0;
188
- transform: translateX(0);
189
- position: fixed;
342
+ transform: none;
190
343
 
191
344
  &.right-aligned {
192
- right: 0;
193
- left: auto;
345
+ transform: none;
194
346
  }
195
347
  }
196
348
 
197
- // Fixed Sidenav hide on smaller
198
349
  @include bp-down("large") {
199
- .sidenav {
200
- &.sidenav-fixed {
201
- transform: translateX(-105%);
350
+ // Uninitialized / no-js: keep a fixed drawer off-canvas. Once JS wraps
351
+ // it, the host's display:none hides the closed drawer and this must
352
+ // not also hide the list inside an open dialog.
353
+ .sidenav.sidenav-fixed {
354
+ transform: translateX(-100%);
202
355
 
203
- &.right-aligned {
204
- transform: translateX(105%);
205
- }
206
- }
207
- > a {
208
- padding: 0 var(--sidenav-padding);
209
- }
210
- .user-view {
211
- padding: var(--sidenav-padding) var(--sidenav-padding) 0;
356
+ &.right-aligned {
357
+ transform: translateX(100%);
212
358
  }
213
359
  }
214
- }
215
360
 
216
- .sidenav .collapsible-body,
217
- .sidenav details::details-content {
218
- padding: 0;
361
+ .sidenav .user-view {
362
+ padding: var(--md-comp-nav-drawer-padding) var(--md-comp-nav-drawer-padding) 0;
363
+ }
219
364
  }
220
365
 
221
- .sidenav-overlay {
366
+ .drag-target {
222
367
  position: fixed;
223
- top: 0;
224
- left: 0;
225
- right: 0;
226
- opacity: 0;
227
- height: 120vh;
228
- background-color: rgba(0, 0, 0, .5);
229
- z-index: 997;
230
- display: none;
231
- }
368
+ inset: 0 auto 0 0;
369
+ width: var(--md-comp-nav-drawer-drag-width, 10px);
370
+ height: 100%;
371
+ z-index: 998;
372
+ touch-action: pan-y;
232
373
 
233
- // Sidenav collapsible styling (Taken from Collapsible.scss)
234
- .sidenav,
235
- .sidenav.sidenav-fixed {
236
- .collapsible {
237
- overflow: visible;
238
- border: none;
239
- border-radius: 0;
240
- background: transparent;
241
- box-shadow: none;
242
- }
243
- .collapsible-header,
244
- summary {
245
- border: none;
374
+ &.right-aligned {
375
+ inset: 0 0 0 auto;
246
376
  }
247
- .collapsible-body,
248
- details::details-content {
249
- border: none;
377
+ }
378
+
379
+ @include bp-up("large") {
380
+ .drag-target[data-fixed] {
381
+ display: none;
382
+ pointer-events: none;
250
383
  }
251
384
  }
385
+
386
+
@@ -1,11 +1,11 @@
1
1
  @use "../abstracts" as *;
2
2
 
3
- // Snackbars (toasts).
3
+ // Snackbars.
4
4
  //
5
- // Anatomy is the HTML. A .snackbar / .toast is the container. A <p> (or
6
- // <span>, or loose text) is the supporting text. A trailing <button> is
7
- // the action; a .circle button is the optional close. An optional leading
8
- // <i> is an icon. .toast-action stays as an alias on the action control.
5
+ // Anatomy is the HTML. A .snackbar is the container. A <p> (or <span>,
6
+ // or loose text) is the supporting text. A trailing <button> is the
7
+ // action; a .circle button is the optional close. An optional leading
8
+ // <i> is an icon.
9
9
  //
10
10
  // Tokens follow https://m3.material.io/components/snackbar/specs
11
11
  // container inverse-surface, 4dp corners, elevation 3, min 48dp
@@ -13,15 +13,18 @@
13
13
  // text body-medium / inverse-on-surface, two lines max
14
14
  // action label-large / inverse-primary text button
15
15
  // close 24dp icon, inverse-on-surface
16
- // inset 8dp compact, 24dp from start+bottom on larger screens
16
+ // inset 8dp compact, 24dp from the bottom on larger screens
17
+ // placement bottom of the UI; centered from the small breakpoint
17
18
  //
18
- // The constructor always adds both .toast and .snackbar. A static
19
- // .snackbar is in-flow (docs previews). .active pins it to the viewport.
20
- // There is no AutoInit and no toast() helper.
19
+ // Snackbars must not interrupt browsing: the container is pointer-events
20
+ // none except on the bar, and the live region is polite. One at a time
21
+ // is a JS concern. The constructor adds .snackbar. A static .snackbar
22
+ // is in-flow (docs previews). .active pins it to the viewport. There
23
+ // is no AutoInit.
21
24
 
22
- $_bar: ":is(.toast, .snackbar)";
25
+ $_bar: ".snackbar";
23
26
 
24
- #toast-container {
27
+ #snackbar-container {
25
28
  --md-comp-snackbar-container-margin-leading: 8px;
26
29
  --md-comp-snackbar-container-margin-trailing: 8px;
27
30
  --md-comp-snackbar-container-margin-bottom: 8px;
@@ -34,10 +37,11 @@ $_bar: ":is(.toast, .snackbar)";
34
37
  position: fixed;
35
38
  z-index: 10000;
36
39
  inset: auto var(--md-comp-snackbar-container-margin-trailing)
37
- var(--md-comp-snackbar-container-margin-bottom)
40
+ max(var(--md-comp-snackbar-container-margin-bottom), env(safe-area-inset-bottom, 0px))
38
41
  var(--md-comp-snackbar-container-margin-leading);
39
42
  width: auto;
40
43
  max-width: calc(100% - var(--md-comp-snackbar-container-margin-leading) - var(--md-comp-snackbar-container-margin-trailing));
44
+ // The page stays browsable — only the bar itself receives pointer events.
41
45
  pointer-events: none;
42
46
 
43
47
  > * {
@@ -49,26 +53,20 @@ $_bar: ":is(.toast, .snackbar)";
49
53
  --md-comp-snackbar-container-margin-trailing: 24px;
50
54
  --md-comp-snackbar-container-margin-bottom: 24px;
51
55
  --md-comp-snackbar-container-margin-top: 24px;
52
- align-items: flex-start;
56
+ align-items: center;
57
+ left: 50%;
58
+ right: auto;
53
59
  width: max-content;
54
60
  min-width: min(344px, calc(100% - 48px));
55
61
  max-width: min(672px, calc(100% - 48px));
62
+ transform: translateX(-50%);
56
63
  }
57
64
 
58
- // Position helpers on the container, or on a child via :has().
65
+ // Opt-in: M3 places snackbars at the bottom. `.top` is the exception.
59
66
  &:has(> .top),
60
67
  &.top {
61
- inset: var(--md-comp-snackbar-container-margin-top)
62
- var(--md-comp-snackbar-container-margin-trailing)
63
- auto
64
- var(--md-comp-snackbar-container-margin-leading);
65
- }
66
-
67
- &:has(> .center),
68
- &.center {
69
- left: 50%;
70
- right: auto;
71
- transform: translateX(-50%);
68
+ inset-block-start: var(--md-comp-snackbar-container-margin-top);
69
+ inset-block-end: auto;
72
70
  }
73
71
  }
74
72
 
@@ -128,7 +126,7 @@ $_bar: ":is(.toast, .snackbar)";
128
126
  }
129
127
 
130
128
  // Inline links in the supporting text use the action color.
131
- a:not(.button, .toast-action) {
129
+ a:not(.button) {
132
130
  color: var(--md-comp-snackbar-action-label-text-color);
133
131
  }
134
132
 
@@ -147,8 +145,8 @@ $_bar: ":is(.toast, .snackbar)";
147
145
  }
148
146
 
149
147
  // Text action — inverse-primary, not the filled common-button default.
150
- > :is(button, a.button, a.toast-action, .toast-action):not(.circle),
151
- > nav > :is(button, a.button, a.toast-action, .toast-action):not(.circle) {
148
+ > :is(button, a.button):not(.circle),
149
+ > nav > :is(button, a.button):not(.circle) {
152
150
  flex: 0 0 auto;
153
151
  height: 40px;
154
152
  min-width: 48px;
@@ -216,45 +214,47 @@ $_bar: ":is(.toast, .snackbar)";
216
214
  }
217
215
  }
218
216
 
219
- // Stacked in-flow previews. JS toasts use the container gap instead.
217
+ // Stacked in-flow previews. JS-created snackbars use the container gap instead.
220
218
  #{$_bar} + #{$_bar} {
221
219
  margin-top: 8px;
222
220
  }
223
221
 
224
- // JS enter animation starts the bar 35px below its rest position.
225
- #toast-container #{$_bar} {
222
+ #snackbar-container #{$_bar} {
226
223
  position: relative;
227
- top: 35px;
228
224
  margin-top: 0;
229
225
  }
230
226
 
231
227
  // Static overlay. In-flow without this (docs previews). Not AutoInit —
232
228
  // add and remove the class yourself, or use the constructor for timing.
229
+ // Default: bottom of the UI, centered from the small breakpoint.
233
230
  #{$_bar}.active {
234
231
  position: fixed;
235
232
  z-index: 10000;
236
- inset: auto auto 16px 16px;
233
+ left: 50%;
234
+ right: auto;
235
+ bottom: 24px;
237
236
  top: auto;
237
+ transform: translateX(-50%);
238
238
  width: max-content;
239
- max-width: min(672px, calc(100% - 32px));
239
+ max-width: min(672px, calc(100% - 48px));
240
240
 
241
241
  @include bp-down("small") {
242
- inset: auto 8px 8px 8px;
242
+ left: 8px;
243
+ right: 8px;
244
+ bottom: max(8px, env(safe-area-inset-bottom, 0px));
245
+ transform: none;
243
246
  width: auto;
244
247
  max-width: none;
245
248
  }
246
249
 
247
250
  &.top {
248
- inset: 16px auto auto 16px;
251
+ top: 24px;
252
+ bottom: auto;
249
253
 
250
254
  @include bp-down("small") {
251
- inset: 8px 8px auto 8px;
255
+ top: 8px;
256
+ left: 8px;
257
+ right: 8px;
252
258
  }
253
259
  }
254
-
255
- &.center {
256
- left: 50%;
257
- right: auto;
258
- transform: translateX(-50%);
259
- }
260
260
  }