@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.
- package/CHANGELOG.md +1311 -1
- package/README.md +14 -11
- package/dist/css/expressive.css +4215 -1668
- 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/js/expressive.cjs +1231 -1253
- package/dist/js/expressive.cjs.map +4 -4
- package/dist/js/expressive.js +1231 -1253
- package/dist/js/expressive.js.map +4 -4
- package/dist/js/expressive.min.js +12 -12
- package/dist/js/expressive.min.js.map +4 -4
- package/dist/js/expressive.mjs +1231 -1253
- 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/autocomplete.d.ts +15 -3
- package/dist/types/components/buttons.d.ts +5 -1
- 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 +21 -20
- package/dist/types/components/lightbox.d.ts +1 -0
- package/dist/types/components/menu.d.ts +7 -1
- package/dist/types/components/{sidenav.d.ts → navigationDrawer.d.ts} +16 -16
- package/dist/types/components/registry.d.ts +8 -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 -9
- package/dist/types/core/utils.d.ts +64 -53
- package/dist/types/index.d.ts +8 -9
- package/package.json +15 -1
- package/src/sass/README.md +61 -11
- package/src/sass/abstracts/_breakpoints.scss +17 -19
- package/src/sass/abstracts/_mixins.scss +103 -21
- package/src/sass/abstracts/_variables.scss +50 -5
- 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 +2 -3
- 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 +186 -0
- package/src/sass/components/_buttons.scss +245 -92
- package/src/sass/components/_cards.scss +494 -73
- 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 +260 -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 +194 -0
- package/src/sass/components/_icons-material-design.scss +16 -4
- 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 +71 -24
- package/src/sass/components/_navigation-bar.scss +13 -10
- package/src/sass/components/{_sidenav.scss → _navigation-drawer.scss} +123 -33
- package/src/sass/components/_navigation-rail.scss +22 -22
- 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/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 +0 -1
- package/src/sass/components/forms/{_range.scss → _slider.scss} +8 -9
- package/src/sass/components/forms/_switches.scss +6 -7
- 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,194 @@
|
|
|
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
|
+
$_sizes: (
|
|
46
|
+
"xsmall": (height: 32px, icon: 20px, space: 6px, narrow: 4px, wide: 10px, square: 12px, pressed: 8px, outline: 1px),
|
|
47
|
+
"small": (height: 40px, icon: 24px, space: 8px, narrow: 4px, wide: 14px, square: 12px, pressed: 8px, outline: 1px),
|
|
48
|
+
"medium": (height: 56px, icon: 24px, space: 16px, narrow: 12px, wide: 24px, square: 16px, pressed: 12px, outline: 1px),
|
|
49
|
+
"large": (height: 96px, icon: 32px, space: 32px, narrow: 16px, wide: 48px, square: 28px, pressed: 16px, outline: 2px),
|
|
50
|
+
"xlarge": (height: 136px, icon: 40px, space: 48px, narrow: 32px, wide: 72px, square: 28px, pressed: 16px, outline: 3px),
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
@mixin _size($name) {
|
|
54
|
+
$s: map.get($_sizes, $name);
|
|
55
|
+
|
|
56
|
+
--md-comp-icon-button-container-height: #{map.get($s, height)};
|
|
57
|
+
--md-comp-icon-button-icon-size: #{map.get($s, icon)};
|
|
58
|
+
--md-comp-icon-button-leading-space: #{map.get($s, space)};
|
|
59
|
+
--md-comp-icon-button-trailing-space: #{map.get($s, space)};
|
|
60
|
+
--md-comp-icon-button-narrow-space: #{map.get($s, narrow)};
|
|
61
|
+
--md-comp-icon-button-wide-space: #{map.get($s, wide)};
|
|
62
|
+
--md-comp-icon-button-container-shape-square: #{map.get($s, square)};
|
|
63
|
+
--md-comp-icon-button-pressed-container-shape: #{map.get($s, pressed)};
|
|
64
|
+
--md-comp-icon-button-outline-width: #{map.get($s, outline)};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Standard is the default style: no container, `on-surface-variant` icon. Every
|
|
68
|
+
// other style is two tokens.
|
|
69
|
+
.icon-button {
|
|
70
|
+
@include _size("small");
|
|
71
|
+
|
|
72
|
+
--md-comp-icon-button-color: var(--md-sys-color-on-surface-variant);
|
|
73
|
+
--md-comp-icon-button-container-color: transparent;
|
|
74
|
+
--md-comp-icon-button-container-shape: 9999px;
|
|
75
|
+
|
|
76
|
+
box-sizing: border-box;
|
|
77
|
+
display: inline-flex;
|
|
78
|
+
flex: 0 0 auto;
|
|
79
|
+
align-items: center;
|
|
80
|
+
justify-content: center;
|
|
81
|
+
height: var(--md-comp-icon-button-container-height);
|
|
82
|
+
padding-block: 0;
|
|
83
|
+
padding-inline: var(--md-comp-icon-button-leading-space)
|
|
84
|
+
var(--md-comp-icon-button-trailing-space);
|
|
85
|
+
border: none;
|
|
86
|
+
border-radius: var(--md-comp-icon-button-container-shape);
|
|
87
|
+
color: var(--md-comp-icon-button-color);
|
|
88
|
+
background-color: var(--md-comp-icon-button-container-color);
|
|
89
|
+
text-decoration: none;
|
|
90
|
+
cursor: pointer;
|
|
91
|
+
outline: 0;
|
|
92
|
+
user-select: none;
|
|
93
|
+
appearance: none;
|
|
94
|
+
vertical-align: middle;
|
|
95
|
+
-webkit-tap-highlight-color: transparent;
|
|
96
|
+
transition: background-color .2s ease-out, border-radius .2s ease-out;
|
|
97
|
+
|
|
98
|
+
> #{$icon} {
|
|
99
|
+
flex: 0 0 auto;
|
|
100
|
+
font-size: var(--md-comp-icon-button-icon-size);
|
|
101
|
+
width: var(--md-comp-icon-button-icon-size);
|
|
102
|
+
height: var(--md-comp-icon-button-icon-size);
|
|
103
|
+
line-height: var(--md-comp-icon-button-icon-size);
|
|
104
|
+
color: inherit;
|
|
105
|
+
overflow: hidden;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// The state layer is the icon colour mixed into the container, whatever the
|
|
109
|
+
// style set those two to - `transparent` included, which is how a standard
|
|
110
|
+
// icon button gets a translucent tint instead of an opaque one.
|
|
111
|
+
@each $state, $selector in ("hover": "&:hover", "focus": "&:focus", "pressed": "&:active") {
|
|
112
|
+
#{$selector} {
|
|
113
|
+
background-color: color-mix(
|
|
114
|
+
in oklab,
|
|
115
|
+
var(--md-comp-icon-button-color) state-opacity($state),
|
|
116
|
+
var(--md-comp-icon-button-container-color)
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
@include focus-visible;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Styles. Each is the icon colour and the container it sits on; the state
|
|
125
|
+
// layers above follow from those two.
|
|
126
|
+
.icon-button.filled {
|
|
127
|
+
--md-comp-icon-button-color: var(--md-sys-color-on-primary);
|
|
128
|
+
--md-comp-icon-button-container-color: var(--md-sys-color-primary);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.icon-button.tonal {
|
|
132
|
+
--md-comp-icon-button-color: var(--md-sys-color-on-secondary-container);
|
|
133
|
+
--md-comp-icon-button-container-color: var(--md-sys-color-secondary-container);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// The outline is a border rather than an inset box-shadow so it survives
|
|
137
|
+
// forced-colors mode, and the inset gives the width back — otherwise a 3dp
|
|
138
|
+
// xlarge outline makes a round button 6px wider than it is tall.
|
|
139
|
+
.icon-button.outlined {
|
|
140
|
+
border: var(--md-comp-icon-button-outline-width) solid var(--md-sys-color-outline-variant);
|
|
141
|
+
padding-inline: calc(var(--md-comp-icon-button-leading-space) - var(--md-comp-icon-button-outline-width))
|
|
142
|
+
calc(var(--md-comp-icon-button-trailing-space) - var(--md-comp-icon-button-outline-width));
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Sizes. Default is small (40dp), which is M3's default icon button.
|
|
146
|
+
@each $name in ("xsmall", "medium", "large", "xlarge") {
|
|
147
|
+
.icon-button.#{$name} {
|
|
148
|
+
@include _size($name);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Width axis. Narrow and wide only move the inset, so they compose with every
|
|
153
|
+
// size and with the outlined padding above.
|
|
154
|
+
.icon-button.narrow {
|
|
155
|
+
--md-comp-icon-button-leading-space: var(--md-comp-icon-button-narrow-space);
|
|
156
|
+
--md-comp-icon-button-trailing-space: var(--md-comp-icon-button-narrow-space);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.icon-button.wide {
|
|
160
|
+
--md-comp-icon-button-leading-space: var(--md-comp-icon-button-wide-space);
|
|
161
|
+
--md-comp-icon-button-trailing-space: var(--md-comp-icon-button-wide-space);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Shape. Round by default, `.square` for the squared container. The pressed
|
|
165
|
+
// shape is the M3 Expressive corner morph, and it has to be written after
|
|
166
|
+
// `.square`: both are one class plus the root, so a tie is decided by order,
|
|
167
|
+
// and a squared button pressed would otherwise keep its resting corner.
|
|
168
|
+
.icon-button.square {
|
|
169
|
+
--md-comp-icon-button-container-shape: var(--md-comp-icon-button-container-shape-square);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.icon-button:active {
|
|
173
|
+
border-radius: var(--md-comp-icon-button-pressed-container-shape);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Disabled. The icon fades to 38% on-surface; a container that exists fades to
|
|
177
|
+
// 10%. Standard and outlined have none, so theirs stays transparent.
|
|
178
|
+
//
|
|
179
|
+
// `aria-disabled="true"` is in the list because an <a> cannot take `disabled`,
|
|
180
|
+
// and it is the attribute that actually tells a screen reader. Note what CSS
|
|
181
|
+
// cannot do for a link: `pointer-events: none` stops the pointer and nothing
|
|
182
|
+
// else, so a disabled-looking <a href> is still reachable by Tab and still
|
|
183
|
+
// navigates on Enter. Drop the `href` (or the link) rather than painting a
|
|
184
|
+
// control that lies about being inert - the docs page says so too.
|
|
185
|
+
.icon-button:is(:disabled, [disabled], [aria-disabled="true"], .disabled) {
|
|
186
|
+
--md-comp-icon-button-color: color-mix(in oklab, var(--md-sys-color-on-surface) 38%, transparent);
|
|
187
|
+
|
|
188
|
+
pointer-events: none;
|
|
189
|
+
cursor: default;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.icon-button:is(.filled, .tonal):is(:disabled, [disabled], [aria-disabled="true"], .disabled) {
|
|
193
|
+
--md-comp-icon-button-container-color: color-mix(in oklab, var(--md-sys-color-on-surface) 10%, transparent);
|
|
194
|
+
}
|
|
@@ -12,7 +12,7 @@
|
|
|
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";
|
|
@@ -67,14 +67,14 @@
|
|
|
67
67
|
padding: 8px var(--md-comp-list-item-padding);
|
|
68
68
|
@include typescale("body-large");
|
|
69
69
|
|
|
70
|
-
> :is(
|
|
70
|
+
> :is(#{$icon}, img, input):first-child {
|
|
71
71
|
grid-column: 1;
|
|
72
72
|
grid-row: 1 / -1;
|
|
73
73
|
align-self: center;
|
|
74
74
|
flex-shrink: 0;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
>
|
|
77
|
+
> #{$icon}:first-child:not(.circle) {
|
|
78
78
|
font-size: var(--md-comp-list-leading-icon-size);
|
|
79
79
|
width: var(--md-comp-list-leading-icon-size);
|
|
80
80
|
height: var(--md-comp-list-leading-icon-size);
|
|
@@ -88,14 +88,14 @@
|
|
|
88
88
|
border-radius: 8px;
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
> :is(img,
|
|
91
|
+
> :is(img, #{$icon}).circle {
|
|
92
92
|
width: var(--md-comp-list-avatar-size);
|
|
93
93
|
height: var(--md-comp-list-avatar-size);
|
|
94
94
|
border-radius: 50%;
|
|
95
95
|
object-fit: cover;
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
>
|
|
98
|
+
> #{$icon}.circle {
|
|
99
99
|
display: inline-flex;
|
|
100
100
|
align-items: center;
|
|
101
101
|
justify-content: center;
|
|
@@ -105,8 +105,11 @@
|
|
|
105
105
|
color: var(--md-sys-color-on-primary-container);
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
+
// $icon-label, not a bare `span`: the canonical icon is a <span> too, so
|
|
109
|
+
// this rule used to pull the leading icon out of column 1 and into the
|
|
110
|
+
// text column - the icon rules above went dead and this one over-matched.
|
|
108
111
|
> div:not(.meta),
|
|
109
|
-
>
|
|
112
|
+
> #{$icon-label} {
|
|
110
113
|
grid-column: 2;
|
|
111
114
|
min-width: 0;
|
|
112
115
|
}
|
|
@@ -120,14 +123,14 @@
|
|
|
120
123
|
@include typescale("body-medium");
|
|
121
124
|
}
|
|
122
125
|
|
|
123
|
-
> :is(
|
|
126
|
+
> :is(#{$icon}, kbd, button, time, .meta, .badge, .button, a):last-child:not(:first-child) {
|
|
124
127
|
grid-column: 3;
|
|
125
128
|
grid-row: 1 / -1;
|
|
126
129
|
justify-self: end;
|
|
127
130
|
align-self: center;
|
|
128
131
|
}
|
|
129
132
|
|
|
130
|
-
>
|
|
133
|
+
> #{$icon}:last-child:not(:first-child) {
|
|
131
134
|
font-size: var(--md-comp-list-trailing-icon-size);
|
|
132
135
|
width: var(--md-comp-list-trailing-icon-size);
|
|
133
136
|
height: var(--md-comp-list-trailing-icon-size);
|
|
@@ -146,8 +149,8 @@
|
|
|
146
149
|
padding: 0;
|
|
147
150
|
}
|
|
148
151
|
|
|
149
|
-
> button:last-child:not(:first-child):not(.button),
|
|
150
|
-
> a:last-child:not(:first-child):not(.button):has(>
|
|
152
|
+
> button:last-child:not(:first-child):not(.button, .icon-button),
|
|
153
|
+
> a:last-child:not(:first-child):not(.button, .icon-button):has(> #{$icon}:only-child) {
|
|
151
154
|
display: inline-flex;
|
|
152
155
|
align-items: center;
|
|
153
156
|
justify-content: center;
|
|
@@ -181,7 +184,7 @@
|
|
|
181
184
|
> li:not(.active):not([aria-selected="true"]):not([aria-current]):not(:has(> [aria-current])):not(:has([aria-selected="true"])):not(:has(:checked)):hover {
|
|
182
185
|
background-color: color-mix(
|
|
183
186
|
in oklab,
|
|
184
|
-
var(--md-sys-color-on-surface)
|
|
187
|
+
var(--md-sys-color-on-surface) state-opacity("hover"),
|
|
185
188
|
var(--md-comp-list-item-container-color)
|
|
186
189
|
);
|
|
187
190
|
}
|
|
@@ -195,7 +198,7 @@
|
|
|
195
198
|
background-color: var(--md-comp-list-selected-container-color);
|
|
196
199
|
color: var(--md-comp-list-selected-color);
|
|
197
200
|
|
|
198
|
-
|
|
201
|
+
#{$icon},
|
|
199
202
|
p,
|
|
200
203
|
kbd,
|
|
201
204
|
time,
|
|
@@ -203,8 +206,8 @@
|
|
|
203
206
|
color: inherit;
|
|
204
207
|
}
|
|
205
208
|
|
|
206
|
-
>
|
|
207
|
-
> :is(a, label):only-child >
|
|
209
|
+
> #{$icon}:first-child,
|
|
210
|
+
> :is(a, label):only-child > #{$icon}:first-child {
|
|
208
211
|
--md-icon-fill: 1;
|
|
209
212
|
}
|
|
210
213
|
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
@use "sass:list";
|
|
2
|
+
@use "sass:math";
|
|
3
|
+
@use "../abstracts" as *;
|
|
4
|
+
|
|
5
|
+
// Loading indicator. M3 Expressive's indicator for short waits (under ~5s):
|
|
6
|
+
// a shape that morphs while it rotates. One element, CSS-only.
|
|
7
|
+
//
|
|
8
|
+
// <span class="loading-indicator" role="status" aria-label="Loading">
|
|
9
|
+
// <span class="loading-indicator contained" role="status" aria-label="Loading">
|
|
10
|
+
//
|
|
11
|
+
// It supersedes the indeterminate *circular* case of `.progress` — see the
|
|
12
|
+
// docs page. `.progress` keeps every determinate case and both linear bars.
|
|
13
|
+
//
|
|
14
|
+
// Tokens (M3 md.comp.loading-indicator.*):
|
|
15
|
+
// --md-comp-loading-indicator-active-indicator-size 38px
|
|
16
|
+
// --md-comp-loading-indicator-container-size 48px
|
|
17
|
+
// --md-comp-loading-indicator-active-indicator-color primary
|
|
18
|
+
// --md-comp-loading-indicator-container-color transparent
|
|
19
|
+
//
|
|
20
|
+
// `--md-comp-loading-indicator-duration` is ours, not M3's - the spec states
|
|
21
|
+
// the motion, not a duration token.
|
|
22
|
+
|
|
23
|
+
// The morph shapes. M3 cycles seven named shapes (soft burst, four cookies, a
|
|
24
|
+
// pentagon, a pill); these are four cookies plus a circle, which is the part
|
|
25
|
+
// of the vocabulary one formula can generate. M3 draws each shape as a rounded
|
|
26
|
+
// polygon and interpolates vertex by vertex; `clip-path` interpolates the same
|
|
27
|
+
// way, but only between polygons with the same vertex count. So every shape
|
|
28
|
+
// here is 24 points on a polar curve
|
|
29
|
+
// `r = 50% * (1 - depth * (1 - cos(petals * a)) / 2)`: depth 0 is a circle,
|
|
30
|
+
// and 24 divides 4, 6, 8 and 12 so every cusp lands on a vertex.
|
|
31
|
+
// Corners are unrounded — a 24-gon reads as the shape, not as a polygon. The
|
|
32
|
+
// docs call these cookies, which is M3's word for them; `depth: 0` is the
|
|
33
|
+
// circle the cycle opens on, so the function is named for the curve instead.
|
|
34
|
+
$_points: 24;
|
|
35
|
+
|
|
36
|
+
// Two decimals is 0.005% of a 38px box - a fiftieth of a pixel. Full float
|
|
37
|
+
// precision costs ~2KB across the five shapes and buys nothing visible.
|
|
38
|
+
@function _pct($v) {
|
|
39
|
+
@return math.div(math.round($v * 100), 100);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@function _petal-shape($petals, $depth) {
|
|
43
|
+
$pts: ();
|
|
44
|
+
@for $i from 0 through $_points - 1 {
|
|
45
|
+
$a: math.div($i * 2 * math.$pi, $_points);
|
|
46
|
+
$r: 50% * (1 - math.div($depth * (1 - math.cos($petals * $a)), 2));
|
|
47
|
+
$pts: list.append($pts, _pct(50% + $r * math.cos($a)) _pct(50% + $r * math.sin($a)), comma);
|
|
48
|
+
}
|
|
49
|
+
@return polygon($pts);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.loading-indicator {
|
|
53
|
+
--md-comp-loading-indicator-active-indicator-size: 38px;
|
|
54
|
+
--md-comp-loading-indicator-container-size: 48px;
|
|
55
|
+
--md-comp-loading-indicator-active-indicator-color: var(--md-sys-color-primary);
|
|
56
|
+
--md-comp-loading-indicator-container-color: transparent;
|
|
57
|
+
--md-comp-loading-indicator-duration: 3000ms;
|
|
58
|
+
|
|
59
|
+
box-sizing: border-box;
|
|
60
|
+
display: inline-flex;
|
|
61
|
+
align-items: center;
|
|
62
|
+
justify-content: center;
|
|
63
|
+
width: var(--md-comp-loading-indicator-container-size);
|
|
64
|
+
height: var(--md-comp-loading-indicator-container-size);
|
|
65
|
+
border-radius: 50%;
|
|
66
|
+
background-color: var(--md-comp-loading-indicator-container-color);
|
|
67
|
+
vertical-align: middle;
|
|
68
|
+
|
|
69
|
+
&::before {
|
|
70
|
+
content: "";
|
|
71
|
+
display: block;
|
|
72
|
+
width: var(--md-comp-loading-indicator-active-indicator-size);
|
|
73
|
+
height: var(--md-comp-loading-indicator-active-indicator-size);
|
|
74
|
+
background-color: var(--md-comp-loading-indicator-active-indicator-color);
|
|
75
|
+
clip-path: _petal-shape(0, 0);
|
|
76
|
+
animation:
|
|
77
|
+
loading-indicator-morph var(--md-comp-loading-indicator-duration) ease-in-out infinite,
|
|
78
|
+
loading-indicator-spin var(--md-comp-loading-indicator-duration) linear infinite;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Contained. M3 pairs the container with `on-secondary-container` for the
|
|
82
|
+
// indicator, not `primary` — the container is the louder surface.
|
|
83
|
+
&.contained {
|
|
84
|
+
--md-comp-loading-indicator-container-color: var(--md-sys-color-secondary-container);
|
|
85
|
+
--md-comp-loading-indicator-active-indicator-color: var(--md-sys-color-on-secondary-container);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
@keyframes loading-indicator-morph {
|
|
90
|
+
0%,
|
|
91
|
+
100% { clip-path: _petal-shape(0, 0); }
|
|
92
|
+
20% { clip-path: _petal-shape(4, 0.32); }
|
|
93
|
+
40% { clip-path: _petal-shape(6, 0.26); }
|
|
94
|
+
60% { clip-path: _petal-shape(8, 0.2); }
|
|
95
|
+
80% { clip-path: _petal-shape(12, 0.14); }
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
@keyframes loading-indicator-spin {
|
|
99
|
+
to { transform: rotate(1turn); }
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
@media (prefers-reduced-motion: reduce) {
|
|
103
|
+
.loading-indicator::before {
|
|
104
|
+
animation: none;
|
|
105
|
+
}
|
|
106
|
+
}
|