@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.
- package/CHANGELOG.md +1313 -1
- package/README.md +76 -30
- package/dist/css/expressive.css +4896 -1777
- package/dist/css/expressive.css.map +1 -1
- package/dist/css/expressive.min.css +1 -1
- package/dist/css/expressive.min.css.map +1 -1
- package/dist/fonts/LICENSE-material-symbols +93 -0
- package/dist/fonts/LICENSE-noto-sans +93 -0
- package/dist/fonts/LICENSE-roboto +93 -0
- package/dist/fonts/material-symbols-outlined.woff2 +0 -0
- package/dist/fonts/material-symbols-rounded.woff2 +0 -0
- package/dist/fonts/material-symbols-sharp.woff2 +0 -0
- package/dist/fonts/noto-sans-latin-400.woff2 +0 -0
- package/dist/fonts/noto-sans-latin-500.woff2 +0 -0
- package/dist/fonts/roboto-latin-400.woff2 +0 -0
- package/dist/fonts/roboto-latin-500.woff2 +0 -0
- package/dist/js/expressive.cjs +1673 -1338
- package/dist/js/expressive.cjs.map +4 -4
- package/dist/js/expressive.js +1673 -1338
- package/dist/js/expressive.js.map +4 -4
- package/dist/js/expressive.min.js +13 -13
- package/dist/js/expressive.min.js.map +4 -4
- package/dist/js/expressive.mjs +1673 -1338
- package/dist/js/expressive.mjs.map +4 -4
- package/dist/types/behaviors/bottomSheets.d.ts +19 -11
- package/dist/types/behaviors/sheetDrag.d.ts +40 -0
- package/dist/types/behaviors/sideSheets.d.ts +2 -9
- package/dist/types/components/appBar.d.ts +26 -0
- package/dist/types/components/autocomplete.d.ts +15 -3
- package/dist/types/components/buttonGroup.d.ts +39 -0
- package/dist/types/components/buttons.d.ts +5 -1
- package/dist/types/components/cards.d.ts +11 -13
- package/dist/types/components/carousel.d.ts +87 -53
- package/dist/types/components/chips.d.ts +21 -1
- package/dist/types/components/expandingCard.d.ts +31 -0
- package/dist/types/components/index.d.ts +23 -20
- package/dist/types/components/lightbox.d.ts +1 -0
- package/dist/types/components/menu.d.ts +11 -1
- package/dist/types/components/{sidenav.d.ts → navigationDrawer.d.ts} +16 -16
- package/dist/types/components/registry.d.ts +18 -8
- package/dist/types/components/slider.d.ts +26 -85
- package/dist/types/components/snackbar.d.ts +20 -5
- package/dist/types/components/tabs.d.ts +12 -0
- package/dist/types/components/timepicker.d.ts +12 -10
- package/dist/types/components/tooltip.d.ts +1 -0
- package/dist/types/core/utils.d.ts +64 -53
- package/dist/types/index.d.ts +8 -9
- package/package.json +39 -3
- package/src/sass/README.md +61 -11
- package/src/sass/abstracts/_breakpoints.scss +17 -19
- package/src/sass/abstracts/_mixins.scss +155 -21
- package/src/sass/abstracts/_variables.scss +69 -5
- package/src/sass/base/_fonts.scss +63 -0
- package/src/sass/base/_global.scss +6 -24
- package/src/sass/base/_grid.scss +15 -12
- package/src/sass/base/_normalize.scss +34 -38
- package/src/sass/base/_typography.scss +4 -18
- package/src/sass/components/_badges.scss +3 -5
- package/src/sass/components/_banners.scss +298 -0
- package/src/sass/components/_bottom-app-bar.scss +180 -0
- package/src/sass/components/_bottom-sheet.scss +12 -4
- package/src/sass/components/_button-groups.scss +358 -0
- package/src/sass/components/_buttons.scss +245 -92
- package/src/sass/components/_cards.scss +514 -78
- package/src/sass/components/_carousel.scss +562 -68
- package/src/sass/components/_chips.scss +64 -5
- package/src/sass/components/_datepicker.scss +24 -24
- package/src/sass/components/_dialog.scss +17 -11
- package/src/sass/components/_drag-handle.scss +130 -0
- package/src/sass/components/_expanding-card.scss +226 -0
- package/src/sass/components/_fab-menu.scss +232 -0
- package/src/sass/components/_floating-sheet.scss +86 -0
- package/src/sass/components/_icon-buttons.scss +172 -0
- package/src/sass/components/_icons-material-design.scss +22 -10
- package/src/sass/components/_index.scss +22 -6
- package/src/sass/components/_list.scss +16 -13
- package/src/sass/components/_loading-indicator.scss +106 -0
- package/src/sass/components/_menu.scss +335 -61
- package/src/sass/components/_navbar.scss +245 -45
- package/src/sass/components/_navigation-bar.scss +22 -11
- package/src/sass/components/{_sidenav.scss → _navigation-drawer.scss} +123 -33
- package/src/sass/components/_navigation-rail.scss +31 -23
- package/src/sass/components/_page-footer.scss +19 -16
- package/src/sass/components/_pagination.scss +24 -6
- package/src/sass/components/_panes.scss +52 -11
- package/src/sass/components/{_preloader.scss → _progress.scss} +11 -3
- package/src/sass/components/_scrim.scss +37 -0
- package/src/sass/components/_search.scss +259 -0
- package/src/sass/components/_segmented-buttons.scss +188 -0
- package/src/sass/components/_side-sheet.scss +2 -2
- package/src/sass/components/_snackbar.scss +20 -15
- package/src/sass/components/_split-button.scss +196 -0
- package/src/sass/components/_tabs.scss +7 -8
- package/src/sass/components/_timepicker.scss +67 -58
- package/src/sass/components/_toolbar.scss +206 -80
- package/src/sass/components/_transitions.scss +8 -1
- package/src/sass/components/forms/_checkboxes.scss +49 -12
- package/src/sass/components/forms/_fieldset.scss +4 -4
- package/src/sass/components/forms/_file-input.scss +8 -1
- package/src/sass/components/forms/_index.scss +1 -1
- package/src/sass/components/forms/_input-fields.scss +50 -44
- package/src/sass/components/forms/_radio-buttons.scss +42 -10
- package/src/sass/components/forms/_select.scss +38 -1
- package/src/sass/components/forms/{_range.scss → _slider.scss} +8 -9
- package/src/sass/components/forms/_switches.scss +6 -7
- package/src/sass/expressive.scss +5 -0
- package/src/sass/tokens/_index.scss +4 -1
- package/src/sass/tokens/_reference.scss +70 -61
- package/src/sass/tokens/_state.scss +24 -0
- package/src/sass/tokens/_theme.scss +6 -3
- package/src/sass/tokens/_vibrant.scss +76 -0
- package/src/sass/utilities/_colors.scss +14 -1
- package/src/sass/utilities/_helpers.scss +5 -5
- package/src/sass/utilities/_visibility.scss +48 -26
- package/dist/types/behaviors/waves.d.ts +0 -15
- package/dist/types/components/parallax.d.ts +0 -16
- package/dist/types/components/range.d.ts +0 -43
- package/dist/types/core/bounding.d.ts +0 -6
- package/dist/types/core/edges.d.ts +0 -6
- package/src/sass/components/_parallax.scss +0 -104
- package/src/sass/components/_pulse.scss +0 -37
- package/src/sass/components/_slider.scss +0 -129
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
@use "../abstracts" as *;
|
|
2
|
+
|
|
3
|
+
// FAB menu. A FAB that expands into a list of labelled actions and morphs
|
|
4
|
+
// into a close button while it is open. `.fab-menu` is the host; `.active`
|
|
5
|
+
// and `aria-expanded` are the framework's, never the author's.
|
|
6
|
+
//
|
|
7
|
+
// It shares the FloatingActionButton class with the `.fab` speed dial next
|
|
8
|
+
// door and nothing else. The two never collide: `$_fab` is
|
|
9
|
+
// `:is(.fab, .fixed-action-btn)`, and a class selector matches whole class
|
|
10
|
+
// names, so `.fab` does not reach `.fab-menu`. The one name that looks shared
|
|
11
|
+
// is `--md-comp-fab-menu-gap`, which is the speed dial's own gap token and is
|
|
12
|
+
// deliberately not one of the names below.
|
|
13
|
+
//
|
|
14
|
+
// Tokens (M3 md.comp.fab-menu.*, DSP 34.0.21):
|
|
15
|
+
//
|
|
16
|
+
// close-button 56x56, icon 20dp, corner.full, elevation 3, 8dp above list
|
|
17
|
+
// menu-item 56dp tall, icon 24dp, 24dp insets, 8dp icon-label space,
|
|
18
|
+
// 4dp between items, corner.full, elevation 0, title-medium
|
|
19
|
+
//
|
|
20
|
+
// The colour axis is M3's three roles, and each one moves two pairs at once:
|
|
21
|
+
// the list item takes `<role>-container` / `on-<role>-container`, the close
|
|
22
|
+
// button the solid `<role>` / `on-<role>`. That pairing is M3's - the close
|
|
23
|
+
// button is deliberately the louder of the two.
|
|
24
|
+
$_fab-menu-roles: ("primary", "secondary", "tertiary");
|
|
25
|
+
|
|
26
|
+
.fab-menu {
|
|
27
|
+
--md-comp-fab-menu-close-button-container-height: 56px;
|
|
28
|
+
--md-comp-fab-menu-close-button-container-width: 56px;
|
|
29
|
+
--md-comp-fab-menu-close-button-icon-size: 20px;
|
|
30
|
+
--md-comp-fab-menu-close-button-between-space: 8px;
|
|
31
|
+
--md-comp-fab-menu-close-button-container-color: var(--md-sys-color-primary);
|
|
32
|
+
--md-comp-fab-menu-close-button-icon-color: var(--md-sys-color-on-primary);
|
|
33
|
+
--md-comp-fab-menu-menu-item-container-height: 56px;
|
|
34
|
+
--md-comp-fab-menu-menu-item-between-space: 4px;
|
|
35
|
+
--md-comp-fab-menu-menu-item-icon-size: 24px;
|
|
36
|
+
--md-comp-fab-menu-menu-item-icon-label-space: 8px;
|
|
37
|
+
--md-comp-fab-menu-menu-item-leading-space: 24px;
|
|
38
|
+
--md-comp-fab-menu-menu-item-trailing-space: 24px;
|
|
39
|
+
--md-comp-fab-menu-menu-item-container-color: var(
|
|
40
|
+
--md-sys-color-primary-container
|
|
41
|
+
);
|
|
42
|
+
--md-comp-fab-menu-menu-item-label-text-color: var(
|
|
43
|
+
--md-sys-color-on-primary-container
|
|
44
|
+
);
|
|
45
|
+
--md-comp-fab-menu-offset: 16px;
|
|
46
|
+
--md-comp-fab-menu-z: 997;
|
|
47
|
+
--md-comp-fab-menu-duration: 200ms;
|
|
48
|
+
--md-comp-fab-menu-stagger: 40ms;
|
|
49
|
+
--md-comp-fab-menu-easing: cubic-bezier(0.65, 0, 0.35, 1);
|
|
50
|
+
|
|
51
|
+
position: fixed;
|
|
52
|
+
inset-inline-end: var(--md-comp-fab-menu-offset);
|
|
53
|
+
bottom: var(--md-comp-fab-menu-offset);
|
|
54
|
+
z-index: var(--md-comp-fab-menu-z);
|
|
55
|
+
margin: 0;
|
|
56
|
+
|
|
57
|
+
// The trigger is the host's only in-flow child, so the host is exactly its
|
|
58
|
+
// size and the list can hang off `bottom: 100%`. Taking the list out of
|
|
59
|
+
// flow is what keeps a closed menu from reserving its own height.
|
|
60
|
+
> :is(a, button) {
|
|
61
|
+
position: relative;
|
|
62
|
+
z-index: 1;
|
|
63
|
+
|
|
64
|
+
// A second glyph in the trigger is the close button's, and only one of
|
|
65
|
+
// the two is ever in the box. With one glyph the morph is the whole
|
|
66
|
+
// affordance. `inline-block` is restated rather than reverted: the icon's
|
|
67
|
+
// own rule is in this layer too, so `revert-layer` would skip past it to
|
|
68
|
+
// the base default.
|
|
69
|
+
> #{$icon}:nth-child(2) {
|
|
70
|
+
display: none;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
:is(ul, menu) {
|
|
75
|
+
position: absolute;
|
|
76
|
+
inset-inline-end: 0;
|
|
77
|
+
bottom: calc(100% + var(--md-comp-fab-menu-close-button-between-space));
|
|
78
|
+
display: flex;
|
|
79
|
+
flex-direction: column;
|
|
80
|
+
align-items: flex-end;
|
|
81
|
+
gap: var(--md-comp-fab-menu-menu-item-between-space);
|
|
82
|
+
margin: 0;
|
|
83
|
+
padding: 0;
|
|
84
|
+
list-style: none;
|
|
85
|
+
visibility: hidden;
|
|
86
|
+
transition: visibility 0s var(--md-comp-fab-menu-duration);
|
|
87
|
+
|
|
88
|
+
// Opening runs bottom-up, so the item nearest the FAB moves first. Past
|
|
89
|
+
// six the ladder runs out and the rest move together, which is where M3
|
|
90
|
+
// stops recommending actions anyway.
|
|
91
|
+
li:nth-last-child(1) { --i: 0; }
|
|
92
|
+
li:nth-last-child(2) { --i: 1; }
|
|
93
|
+
li:nth-last-child(3) { --i: 2; }
|
|
94
|
+
li:nth-last-child(4) { --i: 3; }
|
|
95
|
+
li:nth-last-child(5) { --i: 4; }
|
|
96
|
+
li:nth-last-child(6) { --i: 5; }
|
|
97
|
+
|
|
98
|
+
> li > :is(a, button) {
|
|
99
|
+
display: inline-flex;
|
|
100
|
+
align-items: center;
|
|
101
|
+
gap: var(--md-comp-fab-menu-menu-item-icon-label-space);
|
|
102
|
+
height: var(--md-comp-fab-menu-menu-item-container-height);
|
|
103
|
+
padding-inline: var(--md-comp-fab-menu-menu-item-leading-space)
|
|
104
|
+
var(--md-comp-fab-menu-menu-item-trailing-space);
|
|
105
|
+
border: none;
|
|
106
|
+
border-radius: 9999px;
|
|
107
|
+
color: var(--md-comp-fab-menu-menu-item-label-text-color);
|
|
108
|
+
background-color: var(--md-comp-fab-menu-menu-item-container-color);
|
|
109
|
+
white-space: nowrap;
|
|
110
|
+
text-decoration: none;
|
|
111
|
+
cursor: pointer;
|
|
112
|
+
appearance: none;
|
|
113
|
+
opacity: 0;
|
|
114
|
+
transform: scale(.8) translateY(1rem);
|
|
115
|
+
transition:
|
|
116
|
+
opacity var(--md-comp-fab-menu-duration) var(--md-comp-fab-menu-easing),
|
|
117
|
+
transform var(--md-comp-fab-menu-duration) var(--md-comp-fab-menu-easing),
|
|
118
|
+
background-color .2s ease-out,
|
|
119
|
+
box-shadow .2s ease-out;
|
|
120
|
+
@include typescale("title-medium");
|
|
121
|
+
@include focus-visible;
|
|
122
|
+
|
|
123
|
+
> #{$icon} {
|
|
124
|
+
font-size: var(--md-comp-fab-menu-menu-item-icon-size);
|
|
125
|
+
width: var(--md-comp-fab-menu-menu-item-icon-size);
|
|
126
|
+
height: var(--md-comp-fab-menu-menu-item-icon-size);
|
|
127
|
+
line-height: var(--md-comp-fab-menu-menu-item-icon-size);
|
|
128
|
+
color: inherit;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Enabled is elevation 0; only the states lift.
|
|
132
|
+
&:hover {
|
|
133
|
+
@include z-depth("4");
|
|
134
|
+
background-color: color-mix(
|
|
135
|
+
in oklab,
|
|
136
|
+
var(--md-comp-fab-menu-menu-item-label-text-color) state-opacity("hover"),
|
|
137
|
+
var(--md-comp-fab-menu-menu-item-container-color)
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
&:active,
|
|
142
|
+
&:focus {
|
|
143
|
+
@include z-depth("3");
|
|
144
|
+
background-color: color-mix(
|
|
145
|
+
in oklab,
|
|
146
|
+
var(--md-comp-fab-menu-menu-item-label-text-color) state-opacity("focus"),
|
|
147
|
+
var(--md-comp-fab-menu-menu-item-container-color)
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
&.active :is(ul, menu) {
|
|
154
|
+
visibility: visible;
|
|
155
|
+
transition-delay: 0s;
|
|
156
|
+
|
|
157
|
+
> li > :is(a, button) {
|
|
158
|
+
opacity: 1;
|
|
159
|
+
transform: none;
|
|
160
|
+
transition-delay: calc(var(--md-comp-fab-menu-stagger) * var(--i, 0));
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Open, the FAB is the close button: the same disc on corner.full, the
|
|
165
|
+
// solid role colour, and a 20dp glyph. Four of those are the FAB's own
|
|
166
|
+
// tokens, so retuning them is the whole morph - `.fab-menu.active` outweighs
|
|
167
|
+
// `:where(.button).extra.circle`, which contributes only `.extra.circle`.
|
|
168
|
+
&.active > :is(a, button) {
|
|
169
|
+
--md-comp-fab-container-height: var(
|
|
170
|
+
--md-comp-fab-menu-close-button-container-height
|
|
171
|
+
);
|
|
172
|
+
--md-comp-fab-container-width: var(
|
|
173
|
+
--md-comp-fab-menu-close-button-container-width
|
|
174
|
+
);
|
|
175
|
+
--md-comp-fab-container-shape: 9999px;
|
|
176
|
+
--md-comp-fab-icon-size: var(--md-comp-fab-menu-close-button-icon-size);
|
|
177
|
+
|
|
178
|
+
color: var(--md-comp-fab-menu-close-button-icon-color);
|
|
179
|
+
background-color: var(--md-comp-fab-menu-close-button-container-color);
|
|
180
|
+
|
|
181
|
+
> #{$icon}:first-child:not(:only-child) {
|
|
182
|
+
display: none;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
> #{$icon}:nth-child(2) {
|
|
186
|
+
display: inline-block;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
&:hover {
|
|
190
|
+
background-color: color-mix(
|
|
191
|
+
in oklab,
|
|
192
|
+
var(--md-comp-fab-menu-close-button-icon-color) state-opacity("hover"),
|
|
193
|
+
var(--md-comp-fab-menu-close-button-container-color)
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
&:active,
|
|
198
|
+
&:focus {
|
|
199
|
+
background-color: color-mix(
|
|
200
|
+
in oklab,
|
|
201
|
+
var(--md-comp-fab-menu-close-button-icon-color) state-opacity("focus"),
|
|
202
|
+
var(--md-comp-fab-menu-close-button-container-color)
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// `.primary-container` is the default and is named anyway, so all three
|
|
208
|
+
// roles are a class a page can be written with.
|
|
209
|
+
@each $role in $_fab-menu-roles {
|
|
210
|
+
&.#{$role}-container {
|
|
211
|
+
--md-comp-fab-menu-menu-item-container-color: var(
|
|
212
|
+
--md-sys-color-#{$role}-container
|
|
213
|
+
);
|
|
214
|
+
--md-comp-fab-menu-menu-item-label-text-color: var(
|
|
215
|
+
--md-sys-color-on-#{$role}-container
|
|
216
|
+
);
|
|
217
|
+
--md-comp-fab-menu-close-button-container-color: var(
|
|
218
|
+
--md-sys-color-#{$role}
|
|
219
|
+
);
|
|
220
|
+
--md-comp-fab-menu-close-button-icon-color: var(
|
|
221
|
+
--md-sys-color-on-#{$role}
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
@media (prefers-reduced-motion: reduce) {
|
|
228
|
+
.fab-menu {
|
|
229
|
+
--md-comp-fab-menu-duration: 0s;
|
|
230
|
+
--md-comp-fab-menu-stagger: 0s;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
@use "../abstracts" as *;
|
|
2
|
+
|
|
3
|
+
// Floating sheets.
|
|
4
|
+
//
|
|
5
|
+
// The third member of M3's sheet family (`md.comp.sheet.floating`). A
|
|
6
|
+
// dialog.floating-sheet is the surface, detached from every window edge
|
|
7
|
+
// instead of docked to one. showModal() is the modal variant (scrim,
|
|
8
|
+
// page inert); show() is the standard variant (no scrim, the page stays
|
|
9
|
+
// interactive and the sheet floats above it).
|
|
10
|
+
//
|
|
11
|
+
// It is a <dialog>, so every dialog slot already applies - heading, body,
|
|
12
|
+
// optional <hr> and extra content, and a last-child form[method=dialog]
|
|
13
|
+
// as the action row. Only the container differs, and the sheet states it
|
|
14
|
+
// by re-pointing the basic-dialog container tokens at its own.
|
|
15
|
+
//
|
|
16
|
+
// The token set is small on purpose: md.comp.sheet.floating publishes
|
|
17
|
+
// exactly three values (DSP 34.0.21) and nothing about placement.
|
|
18
|
+
// container surface-container-low, 28dp corners, elevation 1
|
|
19
|
+
// inset 24dp from every edge; the sheet centres in what is left
|
|
20
|
+
//
|
|
21
|
+
// There are deliberately no edge modifiers. `.bottom` and `.left` /
|
|
22
|
+
// `.right` already select a bottom or side sheet, so a floating sheet
|
|
23
|
+
// that borrowed those names would pick up two sheets' rules at once.
|
|
24
|
+
// Author placement with `inset` / `margin` when a corner is wanted.
|
|
25
|
+
|
|
26
|
+
dialog.floating-sheet {
|
|
27
|
+
--md-comp-floating-sheet-container-color: var(--md-sys-color-surface-container-low);
|
|
28
|
+
--md-comp-floating-sheet-container-shape: 28px;
|
|
29
|
+
--md-comp-floating-sheet-container-max-width: 400px;
|
|
30
|
+
--md-comp-floating-sheet-inset: 24px;
|
|
31
|
+
|
|
32
|
+
// The surface is the dialog's; the sheet only swaps what it owns.
|
|
33
|
+
--md-comp-basic-dialog-container-color: var(--md-comp-floating-sheet-container-color);
|
|
34
|
+
--md-comp-basic-dialog-container-shape: var(--md-comp-floating-sheet-container-shape);
|
|
35
|
+
|
|
36
|
+
box-sizing: border-box;
|
|
37
|
+
position: fixed;
|
|
38
|
+
inset: var(--md-comp-floating-sheet-inset);
|
|
39
|
+
width: min(
|
|
40
|
+
var(--md-comp-floating-sheet-container-max-width),
|
|
41
|
+
calc(100% - 2 * var(--md-comp-floating-sheet-inset))
|
|
42
|
+
);
|
|
43
|
+
min-width: 0;
|
|
44
|
+
max-width: var(--md-comp-floating-sheet-container-max-width);
|
|
45
|
+
// `inset` sets both block edges, and an `auto` height between two fixed
|
|
46
|
+
// edges is *solved*, not shrink-wrapped - the sheet would fill the window
|
|
47
|
+
// whatever it holds. `fit-content` makes all three non-auto, which is the
|
|
48
|
+
// case where auto margins centre instead.
|
|
49
|
+
height: fit-content;
|
|
50
|
+
// A percentage max-height resolves against the containing block, which is
|
|
51
|
+
// the whole viewport - not the box `inset` leaves. At 100% a tall sheet
|
|
52
|
+
// grew to viewport height, went over-constrained, and auto margins split
|
|
53
|
+
// the overflow as -24px top and bottom: the inset disappeared exactly when
|
|
54
|
+
// the sheet was large enough to need it.
|
|
55
|
+
max-height: calc(100% - 2 * var(--md-comp-floating-sheet-inset));
|
|
56
|
+
margin: auto;
|
|
57
|
+
@include z-depth("1");
|
|
58
|
+
opacity: 1;
|
|
59
|
+
scale: 1;
|
|
60
|
+
transition: opacity 200ms ease, scale 200ms ease;
|
|
61
|
+
|
|
62
|
+
// Non-modal `show()` is not in the top layer - sit above page content
|
|
63
|
+
// and below snackbars (z-index 10000).
|
|
64
|
+
&:not(:modal) {
|
|
65
|
+
z-index: 1100;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Standard: no scrim. Modal keeps the basic-dialog backdrop.
|
|
69
|
+
&:not(:modal)::backdrop {
|
|
70
|
+
background: none;
|
|
71
|
+
backdrop-filter: none;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@starting-style {
|
|
76
|
+
dialog.floating-sheet[open] {
|
|
77
|
+
opacity: 0;
|
|
78
|
+
scale: 0.9;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
@media (prefers-reduced-motion: reduce) {
|
|
83
|
+
dialog.floating-sheet {
|
|
84
|
+
transition: none;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
@use "sass:map";
|
|
2
|
+
@use "../abstracts" as *;
|
|
3
|
+
|
|
4
|
+
// Icon buttons.
|
|
5
|
+
//
|
|
6
|
+
// Its own component, not a modifier on the common button: M3 gives it nine
|
|
7
|
+
// token families of its own — md.comp.icon-button.{xsmall…xlarge} for the size
|
|
8
|
+
// ladder and md.comp.icon-button-{standard,filled,tonal,outlined} for the
|
|
9
|
+
// colours — and neither the sizes nor the colours line up with a common
|
|
10
|
+
// button's. `.icon-button` is listed in `$_not-btn` in `_buttons.scss` for
|
|
11
|
+
// exactly that reason, so none of the common-button geometry reaches it.
|
|
12
|
+
//
|
|
13
|
+
// The 40dp `.button.circle` icon button is untouched. It stays what it always
|
|
14
|
+
// was: a common button wearing a round shape.
|
|
15
|
+
//
|
|
16
|
+
// Hosts step aside for it. A component that styles its own child controls
|
|
17
|
+
// already lets a control that styles itself opt out - that is what `.button` is
|
|
18
|
+
// doing in those `:not()` lists - and `.icon-button` is now in every one of
|
|
19
|
+
// them (toolbar, app bar, list row, dialog, snackbar, rail, panes, footer,
|
|
20
|
+
// side sheet). `tests/icon-buttons.test.js` keeps the lists in step; the member
|
|
21
|
+
// goes inside the existing `:not()` argument list, never chained after it, so
|
|
22
|
+
// the host rule stays exactly as specific as it was.
|
|
23
|
+
//
|
|
24
|
+
// The navigation drawer is the deliberate exception. Its `$_row` geometry has
|
|
25
|
+
// no opt-out for `.button` either: every row in a drawer is one shape, and
|
|
26
|
+
// carving an icon button out of that is the drawer's decision to make, not
|
|
27
|
+
// this component's.
|
|
28
|
+
//
|
|
29
|
+
// Anatomy is the HTML — one control, one icon, and the name on the control.
|
|
30
|
+
// The icon is decoration (`aria-hidden`), so `aria-label` is the only name the
|
|
31
|
+
// control has; `semantics.json` enforces both halves of that.
|
|
32
|
+
//
|
|
33
|
+
// Tokens (M3 md.comp.icon-button.*, DSP 34.0.21):
|
|
34
|
+
//
|
|
35
|
+
// size height icon space narrow wide square pressed outline
|
|
36
|
+
// xsmall 32 20 6 4 10 12 8 1
|
|
37
|
+
// small 40 24 8 4 14 12 8 1 <- default
|
|
38
|
+
// medium 56 24 16 12 24 16 12 1
|
|
39
|
+
// large 96 32 32 16 48 28 16 2
|
|
40
|
+
// xlarge 136 40 48 32 72 28 16 3
|
|
41
|
+
//
|
|
42
|
+
// Width is not a token: it is leading + icon + trailing. That is why every
|
|
43
|
+
// size's default width equals its height, and why `.narrow` / `.wide` need
|
|
44
|
+
// nothing but a different inset.
|
|
45
|
+
// Standard is the default style: no container, `on-surface-variant` icon. Every
|
|
46
|
+
// other style is two tokens.
|
|
47
|
+
.icon-button {
|
|
48
|
+
@include icon-button-size("small");
|
|
49
|
+
|
|
50
|
+
--md-comp-icon-button-color: var(--md-sys-color-on-surface-variant);
|
|
51
|
+
--md-comp-icon-button-container-color: transparent;
|
|
52
|
+
--md-comp-icon-button-container-shape: 9999px;
|
|
53
|
+
|
|
54
|
+
box-sizing: border-box;
|
|
55
|
+
display: inline-flex;
|
|
56
|
+
flex: 0 0 auto;
|
|
57
|
+
align-items: center;
|
|
58
|
+
justify-content: center;
|
|
59
|
+
height: var(--md-comp-icon-button-container-height);
|
|
60
|
+
padding-block: 0;
|
|
61
|
+
padding-inline: var(--md-comp-icon-button-leading-space)
|
|
62
|
+
var(--md-comp-icon-button-trailing-space);
|
|
63
|
+
border: none;
|
|
64
|
+
border-radius: var(--md-comp-icon-button-container-shape);
|
|
65
|
+
color: var(--md-comp-icon-button-color);
|
|
66
|
+
background-color: var(--md-comp-icon-button-container-color);
|
|
67
|
+
text-decoration: none;
|
|
68
|
+
cursor: pointer;
|
|
69
|
+
outline: 0;
|
|
70
|
+
user-select: none;
|
|
71
|
+
appearance: none;
|
|
72
|
+
vertical-align: middle;
|
|
73
|
+
-webkit-tap-highlight-color: transparent;
|
|
74
|
+
transition: background-color .2s ease-out, border-radius .2s ease-out;
|
|
75
|
+
|
|
76
|
+
> #{$icon} {
|
|
77
|
+
flex: 0 0 auto;
|
|
78
|
+
font-size: var(--md-comp-icon-button-icon-size);
|
|
79
|
+
width: var(--md-comp-icon-button-icon-size);
|
|
80
|
+
height: var(--md-comp-icon-button-icon-size);
|
|
81
|
+
line-height: var(--md-comp-icon-button-icon-size);
|
|
82
|
+
color: inherit;
|
|
83
|
+
overflow: hidden;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// The state layer is the icon colour mixed into the container, whatever the
|
|
87
|
+
// style set those two to - `transparent` included, which is how a standard
|
|
88
|
+
// icon button gets a translucent tint instead of an opaque one.
|
|
89
|
+
@each $state, $selector in ("hover": "&:hover", "focus": "&:focus", "pressed": "&:active") {
|
|
90
|
+
#{$selector} {
|
|
91
|
+
background-color: color-mix(
|
|
92
|
+
in oklab,
|
|
93
|
+
var(--md-comp-icon-button-color) state-opacity($state),
|
|
94
|
+
var(--md-comp-icon-button-container-color)
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
@include focus-visible;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Styles. Each is the icon colour and the container it sits on; the state
|
|
103
|
+
// layers above follow from those two.
|
|
104
|
+
.icon-button.filled {
|
|
105
|
+
--md-comp-icon-button-color: var(--md-sys-color-on-primary);
|
|
106
|
+
--md-comp-icon-button-container-color: var(--md-sys-color-primary);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.icon-button.tonal {
|
|
110
|
+
--md-comp-icon-button-color: var(--md-sys-color-on-secondary-container);
|
|
111
|
+
--md-comp-icon-button-container-color: var(--md-sys-color-secondary-container);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// The outline is a border rather than an inset box-shadow so it survives
|
|
115
|
+
// forced-colors mode, and the inset gives the width back — otherwise a 3dp
|
|
116
|
+
// xlarge outline makes a round button 6px wider than it is tall.
|
|
117
|
+
.icon-button.outlined {
|
|
118
|
+
border: var(--md-comp-icon-button-outline-width) solid var(--md-sys-color-outline-variant);
|
|
119
|
+
padding-inline: calc(var(--md-comp-icon-button-leading-space) - var(--md-comp-icon-button-outline-width))
|
|
120
|
+
calc(var(--md-comp-icon-button-trailing-space) - var(--md-comp-icon-button-outline-width));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Sizes. Default is small (40dp), which is M3's default icon button.
|
|
124
|
+
@each $name in ("xsmall", "medium", "large", "xlarge") {
|
|
125
|
+
.icon-button.#{$name} {
|
|
126
|
+
@include icon-button-size($name);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Width axis. Narrow and wide only move the inset, so they compose with every
|
|
131
|
+
// size and with the outlined padding above.
|
|
132
|
+
.icon-button.narrow {
|
|
133
|
+
--md-comp-icon-button-leading-space: var(--md-comp-icon-button-narrow-space);
|
|
134
|
+
--md-comp-icon-button-trailing-space: var(--md-comp-icon-button-narrow-space);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.icon-button.wide {
|
|
138
|
+
--md-comp-icon-button-leading-space: var(--md-comp-icon-button-wide-space);
|
|
139
|
+
--md-comp-icon-button-trailing-space: var(--md-comp-icon-button-wide-space);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Shape. Round by default, `.square` for the squared container. The pressed
|
|
143
|
+
// shape is the M3 Expressive corner morph, and it has to be written after
|
|
144
|
+
// `.square`: both are one class plus the root, so a tie is decided by order,
|
|
145
|
+
// and a squared button pressed would otherwise keep its resting corner.
|
|
146
|
+
.icon-button.square {
|
|
147
|
+
--md-comp-icon-button-container-shape: var(--md-comp-icon-button-container-shape-square);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.icon-button:active {
|
|
151
|
+
border-radius: var(--md-comp-icon-button-pressed-container-shape);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Disabled. The icon fades to 38% on-surface; a container that exists fades to
|
|
155
|
+
// 10%. Standard and outlined have none, so theirs stays transparent.
|
|
156
|
+
//
|
|
157
|
+
// `aria-disabled="true"` is in the list because an <a> cannot take `disabled`,
|
|
158
|
+
// and it is the attribute that actually tells a screen reader. Note what CSS
|
|
159
|
+
// cannot do for a link: `pointer-events: none` stops the pointer and nothing
|
|
160
|
+
// else, so a disabled-looking <a href> is still reachable by Tab and still
|
|
161
|
+
// navigates on Enter. Drop the `href` (or the link) rather than painting a
|
|
162
|
+
// control that lies about being inert - the docs page says so too.
|
|
163
|
+
.icon-button:is(:disabled, [disabled], [aria-disabled="true"], .disabled) {
|
|
164
|
+
--md-comp-icon-button-color: color-mix(in oklab, var(--md-sys-color-on-surface) 38%, transparent);
|
|
165
|
+
|
|
166
|
+
pointer-events: none;
|
|
167
|
+
cursor: default;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.icon-button:is(.filled, .tonal):is(:disabled, [disabled], [aria-disabled="true"], .disabled) {
|
|
171
|
+
--md-comp-icon-button-container-color: color-mix(in oklab, var(--md-sys-color-on-surface) 10%, transparent);
|
|
172
|
+
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
@use "../abstracts" as *;
|
|
2
2
|
|
|
3
|
-
// Material Symbols. The
|
|
4
|
-
// rounded, and sharp
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
3
|
+
// Material Symbols. The compiled sheet ships @font-face rules for outlined,
|
|
4
|
+
// rounded, and sharp variable fonts (opsz / wght / FILL / GRAD) plus Roboto
|
|
5
|
+
// and Noto Sans. Browsers only download a family after markup uses it, so
|
|
6
|
+
// rounded and sharp stay cheap until `icon-style` or a family class asks
|
|
7
|
+
// for them. Override $expressive-include-fonts when compiling Sass if the
|
|
8
|
+
// page already loads these families.
|
|
9
9
|
//
|
|
10
10
|
// Style (outlined / rounded / sharp) is the font family, not a variation
|
|
11
11
|
// axis. Switch it with the `icon-style` attribute (same idea as `theme`)
|
|
12
12
|
// or by setting --md-icon-font. Fill, weight, grade, and optical size
|
|
13
13
|
// are axes and inherit as custom properties.
|
|
14
14
|
|
|
15
|
-
:root {
|
|
15
|
+
:root, :host {
|
|
16
16
|
--md-icon-font-outlined: "Material Symbols Outlined";
|
|
17
17
|
--md-icon-font-rounded: "Material Symbols Rounded";
|
|
18
18
|
--md-icon-font-sharp: "Material Symbols Sharp";
|
|
@@ -23,9 +23,12 @@
|
|
|
23
23
|
--md-icon-optical-size: 24;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
[icon-style="outlined"]
|
|
27
|
-
[icon-style="
|
|
28
|
-
[icon-style="
|
|
26
|
+
[icon-style="outlined"],
|
|
27
|
+
:host([icon-style="outlined"]) { --md-icon-font: var(--md-icon-font-outlined); }
|
|
28
|
+
[icon-style="rounded"],
|
|
29
|
+
:host([icon-style="rounded"]) { --md-icon-font: var(--md-icon-font-rounded); }
|
|
30
|
+
[icon-style="sharp"],
|
|
31
|
+
:host([icon-style="sharp"]) { --md-icon-font: var(--md-icon-font-sharp); }
|
|
29
32
|
|
|
30
33
|
$_icon: ".material-symbols, .material-symbols-outlined, .material-symbols-rounded, .material-symbols-sharp, .material-icons";
|
|
31
34
|
|
|
@@ -54,6 +57,15 @@ $_icon: ".material-symbols, .material-symbols-outlined, .material-symbols-rounde
|
|
|
54
57
|
// Nest so each class in $_icon gets the suffix. `#{$_icon}.tiny` would
|
|
55
58
|
// only attach `.tiny` to the last item and leave every other icon
|
|
56
59
|
// matching the bare `.material-symbols` selector — including `.large`.
|
|
60
|
+
// Float helpers, moved off the `i` element selector in base/_global so they
|
|
61
|
+
// survive the canonical <span class="material-symbols"> form.
|
|
62
|
+
&.left {
|
|
63
|
+
float: left;
|
|
64
|
+
margin-left: -8px;
|
|
65
|
+
}
|
|
66
|
+
&.right {
|
|
67
|
+
float: right;
|
|
68
|
+
}
|
|
57
69
|
&.tiny {
|
|
58
70
|
font-size: 1rem;
|
|
59
71
|
--md-icon-optical-size: 20;
|
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
// One line per component. Order is cascade order, so keep related widgets
|
|
2
2
|
// together and append new components at the end unless order matters.
|
|
3
3
|
|
|
4
|
+
// Icons first: it is the base glyph default (font-size, line-height) that a
|
|
5
|
+
// component's own icon rule is meant to override. `$icon` interpolates to an
|
|
6
|
+
// :is() carrying classes, so a component rule ties with the base rule on
|
|
7
|
+
// specificity and the winner is decided by source order alone - with icons
|
|
8
|
+
// loaded 4th, `buttons`, `list` and `badges` silently lost that tie. That is
|
|
9
|
+
// why a button icon rendered as an 18px box around a 24px glyph.
|
|
10
|
+
@forward "icons-material-design";
|
|
4
11
|
@forward "buttons";
|
|
12
|
+
@forward "button-groups";
|
|
13
|
+
@forward "split-button";
|
|
14
|
+
@forward "icon-buttons";
|
|
5
15
|
@forward "list";
|
|
6
16
|
@forward "badges";
|
|
7
|
-
@forward "icons-material-design";
|
|
8
17
|
@forward "navbar";
|
|
9
18
|
@forward "navigation-bar";
|
|
10
19
|
@forward "navigation-rail";
|
|
@@ -16,23 +25,30 @@
|
|
|
16
25
|
@forward "tooltip";
|
|
17
26
|
@forward "menu";
|
|
18
27
|
@forward "dialog";
|
|
28
|
+
@forward "expanding-card";
|
|
19
29
|
@forward "bottom-sheet";
|
|
20
30
|
@forward "side-sheet";
|
|
31
|
+
@forward "floating-sheet";
|
|
21
32
|
@forward "chips";
|
|
22
33
|
@forward "lightbox";
|
|
23
|
-
@forward "parallax";
|
|
24
34
|
@forward "docked-display";
|
|
25
35
|
@forward "page-footer";
|
|
26
36
|
@forward "forms";
|
|
27
37
|
@forward "table_of_contents";
|
|
28
38
|
@forward "scrollspy";
|
|
29
|
-
@forward "
|
|
30
|
-
@forward "
|
|
31
|
-
@forward "slider";
|
|
39
|
+
@forward "navigation-drawer";
|
|
40
|
+
@forward "progress";
|
|
32
41
|
@forward "carousel";
|
|
33
|
-
@forward "pulse";
|
|
34
42
|
@forward "datepicker";
|
|
35
43
|
@forward "timepicker";
|
|
36
44
|
@forward "breadcrumb";
|
|
37
45
|
@forward "pagination";
|
|
38
46
|
@forward "panes";
|
|
47
|
+
@forward "fab-menu";
|
|
48
|
+
@forward "loading-indicator";
|
|
49
|
+
@forward "search";
|
|
50
|
+
@forward "segmented-buttons";
|
|
51
|
+
@forward "banners";
|
|
52
|
+
@forward "drag-handle";
|
|
53
|
+
@forward "bottom-app-bar";
|
|
54
|
+
@forward "scrim";
|