Skip to content

Commit 35ce605

Browse files
authored
refactor(material/button): simplify FAB structural styles (#29353)
Simplifies the styles of the FAB to make them smaller and easier to maintain.
1 parent 2636512 commit 35ce605

File tree

10 files changed

+221
-142
lines changed

10 files changed

+221
-142
lines changed

src/material/button/_fab-theme.scss

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
@use '@material/fab/fab-theme' as mdc-fab-theme;
2-
@use '@material/fab/fab-small-theme' as mdc-fab-small-theme;
3-
@use '@material/fab/extended-fab-theme' as mdc-extended-fab-theme;
41
@use '../core/style/sass-utils';
52
@use '../core/theming/theming';
63
@use '../core/theming/inspection';
@@ -21,13 +18,13 @@
2118
@include _theme-from-tokens(inspection.get-theme-tokens($theme, base));
2219
}
2320
@else {
24-
// Add default values for tokens not related to color, typography, or density.
2521
@include sass-utils.current-selector-or-root() {
26-
@include mdc-fab-theme.theme(tokens-mdc-fab.get-unthemable-tokens());
27-
@include mdc-fab-small-theme.theme(tokens-mdc-fab-small.get-unthemable-tokens());
28-
@include mdc-extended-fab-theme.theme(
29-
tokens-mdc-extended-fab.get-unthemable-tokens()
30-
);
22+
@include token-utils.create-token-values(
23+
tokens-mdc-fab.$prefix, tokens-mdc-fab.get-unthemable-tokens());
24+
@include token-utils.create-token-values(
25+
tokens-mdc-fab-small.$prefix, tokens-mdc-fab-small.get-unthemable-tokens());
26+
@include token-utils.create-token-values(
27+
tokens-mdc-extended-fab.$prefix, tokens-mdc-extended-fab.get-unthemable-tokens());
3128
}
3229
}
3330
}
@@ -43,7 +40,7 @@
4340
tokens-mat-fab.get-color-tokens($theme)
4441
);
4542

46-
@include mdc-fab-theme.theme($mdc-tokens);
43+
@include token-utils.create-token-values(tokens-mdc-fab.$prefix, $mdc-tokens);
4744
@include token-utils.create-token-values(tokens-mat-fab.$prefix, $mat-tokens);
4845
}
4946

@@ -58,7 +55,7 @@
5855
tokens-mat-fab-small.get-color-tokens($theme)
5956
);
6057

61-
@include mdc-fab-small-theme.theme($mdc-tokens);
58+
@include token-utils.create-token-values(tokens-mdc-fab-small.$prefix, $mdc-tokens);
6259
@include token-utils.create-token-values(tokens-mat-fab-small.$prefix, $mat-tokens);
6360
}
6461

@@ -75,7 +72,8 @@
7572
@include sass-utils.current-selector-or-root() {
7673
@include _fab-variant($theme, null);
7774
@include _fab-small-variant($theme, null);
78-
@include mdc-extended-fab-theme.theme(tokens-mdc-extended-fab.get-color-tokens($theme));
75+
@include token-utils.create-token-values(
76+
tokens-mdc-extended-fab.$prefix, tokens-mdc-extended-fab.get-color-tokens($theme));
7977

8078
.mat-mdc-fab {
8179
&.mat-primary {
@@ -116,7 +114,8 @@
116114
}
117115
@else {
118116
@include sass-utils.current-selector-or-root() {
119-
@include mdc-extended-fab-theme.theme(tokens-mdc-extended-fab.get-typography-tokens($theme));
117+
@include token-utils.create-token-values(tokens-mdc-extended-fab.$prefix,
118+
tokens-mdc-extended-fab.get-typography-tokens($theme));
120119
@include token-utils.create-token-values(tokens-mat-fab.$prefix,
121120
tokens-mat-fab.get-typography-tokens($theme));
122121
@include token-utils.create-token-values(tokens-mat-fab-small.$prefix,
@@ -190,9 +189,10 @@
190189
$mat-fab-tokens: token-utils.get-tokens-for($tokens, tokens-mat-fab.$prefix, $options...);
191190
$mat-fab-small-tokens: token-utils.get-tokens-for($tokens, tokens-mat-fab-small.$prefix,
192191
$options...);
193-
@include mdc-extended-fab-theme.theme($mdc-extended-fab-tokens);
194-
@include mdc-fab-theme.theme($mdc-fab-tokens);
195-
@include mdc-fab-small-theme.theme($mdc-fab-small-tokens);
192+
@include token-utils.create-token-values(tokens-mdc-extended-fab.$prefix,
193+
$mdc-extended-fab-tokens);
194+
@include token-utils.create-token-values(tokens-mdc-fab.$prefix, $mdc-fab-tokens);
195+
@include token-utils.create-token-values(tokens-mdc-fab-small.$prefix, $mdc-fab-small-tokens);
196196
@include token-utils.create-token-values(tokens-mat-fab.$prefix, $mat-fab-tokens);
197197
@include token-utils.create-token-values(tokens-mat-fab-small.$prefix, $mat-fab-small-tokens);
198198
}

src/material/button/button-base.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,11 @@ const HOST_SELECTOR_MDC_CLASS_PAIR: {attribute: string; mdcClasses: string[]}[]
7272
},
7373
{
7474
attribute: 'mat-fab',
75-
mdcClasses: ['mdc-fab', 'mat-mdc-fab'],
75+
mdcClasses: ['mdc-fab', 'mat-mdc-fab-base', 'mat-mdc-fab'],
7676
},
7777
{
7878
attribute: 'mat-mini-fab',
79-
mdcClasses: ['mdc-fab', 'mdc-fab--mini', 'mat-mdc-mini-fab'],
79+
mdcClasses: ['mdc-fab', 'mat-mdc-fab-base', 'mdc-fab--mini', 'mat-mdc-mini-fab'],
8080
},
8181
{
8282
attribute: 'mat-icon-button',

src/material/button/fab.scss

Lines changed: 107 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,70 @@
1-
@use 'sass:map';
2-
@use '@material/fab' as mdc-fab;
3-
@use '@material/fab/extended-fab-theme' as mdc-extended-fab-theme;
4-
@use '@material/fab/fab-theme' as mdc-fab-theme;
5-
@use '@material/fab/fab-small-theme' as mdc-fab-small-theme;
6-
@use '@material/typography/typography' as mdc-typography;
7-
@use '@material/theme/custom-properties' as mdc-custom-properties;
8-
91
@use './button-base';
10-
@use '../core/mdc-helpers/mdc-helpers';
112
@use '../core/tokens/token-utils';
123
@use '../core/style/private' as style-private;
4+
@use '../core/style/vendor-prefixes';
135
@use '../core/focus-indicators/private' as focus-indicators-private;
146
@use '../core/tokens/m2/mdc/extended-fab' as tokens-mdc-extended-fab;
157
@use '../core/tokens/m2/mdc/fab' as tokens-mdc-fab;
168
@use '../core/tokens/m2/mat/fab' as tokens-mat-fab;
179
@use '../core/tokens/m2/mdc/fab-small' as tokens-mdc-fab-small;
1810
@use '../core/tokens/m2/mat/fab-small' as tokens-mat-fab-small;
1911

20-
@include mdc-custom-properties.configure($emit-fallback-values: false, $emit-fallback-vars: false) {
21-
$mdc-fab-token-slots: tokens-mdc-fab.get-token-slots();
22-
$mdc-fab-small-token-slots: tokens-mdc-fab-small.get-token-slots();
23-
$mdc-extended-fab-token-slots: tokens-mdc-extended-fab.get-token-slots();
24-
$exclude-tokens: (
25-
// Exclude the elevation tokens here since we output them manually below.
26-
container-elevation: null,
27-
focus-container-elevation: null,
28-
hover-container-elevation: null,
29-
pressed-container-elevation: null,
30-
container-shadow-color: null,
31-
);
12+
.mat-mdc-fab-base {
13+
@include button-base.mat-private-button-interactive();
14+
@include style-private.private-animation-noop();
15+
@include vendor-prefixes.user-select(none);
16+
position: relative;
17+
display: inline-flex;
18+
align-items: center;
19+
justify-content: center;
20+
box-sizing: border-box;
21+
width: 56px;
22+
height: 56px;
23+
padding: 0;
24+
border: none;
25+
fill: currentColor;
26+
text-decoration: none;
27+
cursor: pointer;
28+
-moz-appearance: none;
29+
-webkit-appearance: none;
30+
overflow: visible;
31+
transition: box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1), opacity 15ms linear 30ms,
32+
transform 270ms 0ms cubic-bezier(0, 0, 0.2, 1);
33+
flex-shrink: 0; // Prevent the button from shrinking since it's always supposed to be a circle.
3234

33-
// Note: it's important to pass the query here, otherwise MDC generates
34-
// some unnecessary typography styles for the extended FAB.
35-
@include mdc-fab.static-styles($query: mdc-helpers.$mdc-base-styles-query);
35+
&::before {
36+
position: absolute;
37+
box-sizing: border-box;
38+
width: 100%;
39+
height: 100%;
40+
top: 0;
41+
left: 0;
42+
border: 1px solid transparent;
43+
border-radius: inherit;
44+
content: '';
45+
pointer-events: none;
46+
}
3647

37-
.mat-mdc-fab {
38-
@include mdc-fab-theme.theme-styles(map.merge($mdc-fab-token-slots, $exclude-tokens));
48+
// MDC used to include this and it seems like a lot of apps depend on it.
49+
&[hidden] {
50+
display: none;
3951
}
4052

41-
.mat-mdc-mini-fab {
42-
@include mdc-fab-small-theme.theme-styles(
43-
map.merge($mdc-fab-small-token-slots, $exclude-tokens));
53+
&::-moz-focus-inner {
54+
padding: 0;
55+
border: 0;
4456
}
4557

46-
.mat-mdc-extended-fab {
47-
// Before tokens MDC included the font smoothing automatically, but with
48-
// tokens it doesn't. We add it since it can cause tiny differences in
49-
// screenshot tests and it generally looks better.
50-
@include mdc-typography.smooth-font();
51-
@include mdc-extended-fab-theme.theme-styles(
52-
map.merge($mdc-extended-fab-token-slots, $exclude-tokens));
58+
&:active, &:focus {
59+
outline: none;
5360
}
54-
}
5561

56-
.mat-mdc-fab, .mat-mdc-mini-fab {
57-
@include button-base.mat-private-button-interactive();
58-
@include style-private.private-animation-noop();
59-
flex-shrink: 0; // Prevent the button from shrinking since it's always supposed to be a circle.
62+
&:hover {
63+
cursor: pointer;
64+
}
6065

61-
// MDC adds some styles to fab and mini-fab that conflict with some of our focus indicator
62-
// styles and don't actually do anything. This undoes those conflicting styles.
63-
&:not(.mdc-ripple-upgraded):focus::before {
64-
background: transparent;
65-
opacity: 1;
66+
& > svg {
67+
width: 100%;
6668
}
6769

6870
// MDC expects the fab icon to contain this HTML content:
@@ -73,7 +75,9 @@
7375
// mixin will style the icons appropriately.
7476
// stylelint-disable-next-line selector-class-pattern
7577
.mat-icon, .material-icons {
76-
@include mdc-fab.icon_();
78+
transition: transform 180ms 90ms cubic-bezier(0, 0, 0.2, 1);
79+
fill: currentColor;
80+
will-change: transform;
7781
}
7882

7983
.mat-mdc-focus-indicator::before {
@@ -93,18 +97,18 @@
9397

9498
@mixin _fab-elevation($mdc-tokens) {
9599
@include token-utils.use-tokens($mdc-tokens...) {
96-
@include button-base.mat-private-button-elevation(container-elevation);
100+
@include token-utils.create-token-slot(box-shadow, container-elevation-shadow);
97101

98102
&:hover {
99-
@include button-base.mat-private-button-elevation(hover-container-elevation);
103+
@include token-utils.create-token-slot(box-shadow, hover-container-elevation-shadow);
100104
}
101105

102106
&:focus {
103-
@include button-base.mat-private-button-elevation(focus-container-elevation);
107+
@include token-utils.create-token-slot(box-shadow, focus-container-elevation-shadow);
104108
}
105109

106110
&:active, &:focus:active {
107-
@include button-base.mat-private-button-elevation(pressed-container-elevation);
111+
@include token-utils.create-token-slot(box-shadow, pressed-container-elevation-shadow);
108112
}
109113
}
110114
}
@@ -113,10 +117,13 @@
113117
@include button-base.mat-private-button-touch-target(true, $mat-tokens...);
114118
@include button-base.mat-private-button-ripple($mat-tokens...);
115119

116-
@include mdc-helpers.disable-mdc-fallback-declarations {
117-
@include token-utils.use-tokens($mat-tokens...) {
118-
@include token-utils.create-token-slot(color, foreground-color, inherit);
119-
}
120+
@include token-utils.use-tokens($mdc-tokens...) {
121+
@include token-utils.create-token-slot(background-color, container-color);
122+
@include token-utils.create-token-slot(border-radius, container-shape);
123+
}
124+
125+
@include token-utils.use-tokens($mat-tokens...) {
126+
@include token-utils.create-token-slot(color, foreground-color, inherit);
120127
}
121128

122129
@include _fab-elevation($mdc-tokens);
@@ -137,15 +144,30 @@
137144
}
138145

139146
.mat-mdc-mini-fab {
147+
width: 40px;
148+
height: 40px;
149+
140150
@include _fab-structure(
141151
(tokens-mdc-fab-small.$prefix, tokens-mdc-fab-small.get-token-slots()),
142152
(tokens-mat-fab-small.$prefix, tokens-mat-fab-small.get-token-slots()),
143153
);
144154
}
145155

146156
.mat-mdc-extended-fab {
147-
@include _fab-elevation((tokens-mdc-extended-fab.$prefix,
148-
tokens-mdc-extended-fab.get-token-slots()));
157+
$mdc-tokens: (tokens-mdc-extended-fab.$prefix, tokens-mdc-extended-fab.get-token-slots());
158+
159+
// Before tokens MDC included the font smoothing automatically, but with
160+
// tokens it doesn't. We add it since it can cause tiny differences in
161+
// screenshot tests and it generally looks better.
162+
@include vendor-prefixes.smooth-font();
163+
border-radius: 24px;
164+
padding-left: 20px;
165+
padding-right: 20px;
166+
width: auto;
167+
max-width: 100%;
168+
line-height: normal;
169+
170+
@include _fab-elevation($mdc-tokens);
149171

150172
@include button-base.mat-private-button-disabled {
151173
// Necessary for interactive disabled buttons.
@@ -154,30 +176,40 @@
154176
}
155177
}
156178

157-
& > .mat-icon,
158-
& > .material-icons { // stylelint-disable-line selector-class-pattern
159-
@include mdc-fab.extended-icon-padding(
160-
mdc-fab.$extended-icon-padding,
161-
mdc-fab.$extended-label-padding
162-
);
179+
@include token-utils.use-tokens($mdc-tokens...) {
180+
@include token-utils.create-token-slot(height, container-height);
181+
@include token-utils.create-token-slot(border-radius, container-shape);
182+
@include token-utils.create-token-slot(font-family, label-text-font);
183+
@include token-utils.create-token-slot(font-size, label-text-size);
184+
@include token-utils.create-token-slot(font-weight, label-text-weight);
185+
@include token-utils.create-token-slot(letter-spacing, label-text-tracking);
186+
}
187+
188+
// stylelint-disable selector-class-pattern
189+
// For Extended FAB with text label followed by icon.
190+
// We are checking for the a button class because white this is a FAB it
191+
// uses the same template as button.
192+
[dir='rtl'] & .mdc-button__label + .mat-icon,
193+
[dir='rtl'] & .mdc-button__label + .material-icons,
194+
> .mat-icon,
195+
> .material-icons {
196+
margin-left: -8px;
197+
margin-right: 12px;
163198
}
164199

200+
.mdc-button__label + .mat-icon,
201+
.mdc-button__label + .material-icons,
202+
[dir='rtl'] & > .mat-icon,
203+
[dir='rtl'] & > .material-icons {
204+
margin-left: 12px;
205+
margin-right: -8px;
206+
}
207+
// stylelint-enable selector-class-pattern
208+
165209
// All FABs are square except the extended ones so we
166210
// need to set the touch target back to full-width.
167211
.mat-mdc-button-touch-target {
168212
width: 100%;
169213
}
170-
171-
// For Extended FAB with text label followed by icon.
172-
// We are checking for the a button class because white this is a FAB it
173-
// uses the same template as button.
174-
// stylelint-disable-next-line selector-class-pattern
175-
.mdc-button__label + .mat-icon, .mdc-button__label + .material-icons {
176-
@include mdc-fab.extended-icon-padding(
177-
mdc-fab.$extended-icon-padding,
178-
mdc-fab.$extended-label-padding,
179-
$is-icon-at-end: true
180-
);
181-
}
182214
}
183215

src/material/core/tokens/m2/mdc/_extended-fab.scss

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
@use '@material/elevation/elevation-theme' as mdc-elevation;
12
@use '../../token-utils';
23
@use '../../../theming/inspection';
34

@@ -38,18 +39,22 @@ $prefix: (mdc, extended-fab);
3839
pressed-ripple-color: null,
3940
pressed-ripple-opacity: null,
4041
pressed-state-layer-color: null,
41-
pressed-state-layer-opacity: null
42+
pressed-state-layer-opacity: null,
43+
container-elevation: null,
44+
focus-container-elevation: null,
45+
hover-container-elevation: null,
46+
pressed-container-elevation: null,
47+
container-shadow-color: null,
4248
);
4349
}
4450

4551
// Tokens that can be configured through Angular Material's color theming API.
4652
@function get-color-tokens($theme) {
4753
@return (
48-
container-elevation: 6,
49-
focus-container-elevation: 8,
50-
hover-container-elevation: 8,
51-
pressed-container-elevation: 12,
52-
container-shadow-color: #000,
54+
container-elevation-shadow: mdc-elevation.elevation-box-shadow(6),
55+
focus-container-elevation-shadow: mdc-elevation.elevation-box-shadow(8),
56+
hover-container-elevation-shadow: mdc-elevation.elevation-box-shadow(8),
57+
pressed-container-elevation-shadow: mdc-elevation.elevation-box-shadow(12),
5358
);
5459
}
5560

0 commit comments

Comments
 (0)