Skip to content

Commit f7ace54

Browse files
authored
feat(material-experimental/mdc-button): add extended fab (#21585)
* feat(material-experimental/mdc-button): add extended fab * fix(material-experimental/mdc-button): split up fab and mini fab * fix(material-experimental/mdc-button): fix icon styling and add example * fix(material-experimental/mdc-button): add getter/setter for extended property
1 parent f68662c commit f7ace54

File tree

5 files changed

+181
-13
lines changed

5 files changed

+181
-13
lines changed

src/dev-app/mdc-button/mdc-button-demo.html

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ <h4 class="demo-section-header">Anchors</h4>
3737
<a href="//www.google.com" mat-mini-fab>
3838
<mat-icon>check</mat-icon>
3939
</a>
40+
<a href="//www.google.com" mat-fab extended>Search</a>
41+
<a href="//www.google.com" mat-fab extended>
42+
<mat-icon>check</mat-icon>
43+
Search
44+
</a>
4045
</section>
4146
<section>
4247
<a href="//www.google.com" disabled mat-button color="primary">SEARCH</a>
@@ -49,6 +54,11 @@ <h4 class="demo-section-header">Anchors</h4>
4954
<a href="//www.google.com" disabled mat-mini-fab>
5055
<mat-icon>check</mat-icon>
5156
</a>
57+
<a href="//www.google.com" disabled mat-fab extended>Search</a>
58+
<a href="//www.google.com" disabled mat-fab extended>
59+
<mat-icon>check</mat-icon>
60+
Search
61+
</a>
5262
</section>
5363

5464
<h4 class="demo-section-header">Text Buttons [mat-button]</h4>
@@ -145,6 +155,23 @@ <h4 class="demo-section-header">Fab Buttons [mat-fab]</h4>
145155
</button>
146156
</section>
147157

158+
<h4 class="demo-section-header">Extended Fab Buttons</h4>
159+
<section>
160+
<button mat-fab extended>Extended</button>
161+
<button mat-fab extended color="primary">Extended</button>
162+
<button mat-fab extended color="accent">Extended</button>
163+
<button mat-fab extended color="warn">Extended</button>
164+
<button mat-fab extended>
165+
<mat-icon>home</mat-icon>
166+
Extended
167+
</button>
168+
<button mat-fab extended>
169+
<mat-icon>home</mat-icon>
170+
Extended
171+
<mat-icon iconPositionEnd>favorite</mat-icon>
172+
</button>
173+
</section>
174+
148175
<h4 class="demo-section-header"> Mini Fab Buttons [mat-mini-fab]</h4>
149176
<section>
150177
<button mat-mini-fab>

src/material-experimental/mdc-button/button.spec.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,22 @@ describe('MDC-based MatButton', () => {
9494
});
9595
});
9696

97+
describe('button[mat-fab] extended', () => {
98+
it('should be extended', () => {
99+
const fixture = TestBed.createComponent(TestApp);
100+
fixture.detectChanges();
101+
const extendedFabButtonDebugEl = fixture.debugElement.query(By.css('.extended-fab-test'))!;
102+
103+
expect(extendedFabButtonDebugEl.nativeElement.classList.contains('mat-mdc-extended-fab'))
104+
.toBeFalse();
105+
106+
fixture.componentInstance.extended = true;
107+
108+
fixture.detectChanges();
109+
expect(extendedFabButtonDebugEl.nativeElement.classList).toContain('mat-mdc-extended-fab');
110+
});
111+
});
112+
97113
// Regular button tests
98114
describe('button[mat-button]', () => {
99115
it('should handle a click on the button', () => {
@@ -281,6 +297,7 @@ describe('MDC-based MatButton', () => {
281297
Link
282298
</a>
283299
<button mat-fab>Fab Button</button>
300+
<button mat-fab [extended]="extended" class="extended-fab-test">Extended</button>
284301
<button mat-mini-fab>Mini Fab Button</button>
285302
`
286303
})
@@ -290,6 +307,7 @@ class TestApp {
290307
rippleDisabled: boolean = false;
291308
buttonColor: ThemePalette;
292309
tabIndex: number;
310+
extended: boolean = false;
293311

294312
increment() {
295313
this.clickCount++;

src/material-experimental/mdc-button/fab.scss

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
@import '@material/fab/mixins.import';
2+
@import '@material/fab/variables.import';
23
@import '@material/button/variables.import';
34
@import '@material/theme/variables.import';
45
@import '../mdc-helpers/mdc-helpers';
@@ -22,11 +23,31 @@
2223
// <span class="mdc-fab__icon material-icons">favorite</span>
2324
// ```
2425
// However, Angular Material expects a `mat-icon` instead. The following
25-
// will extend the `mdc-fab__icon` styling to the mat icon. Note that
26-
// the extended styles inherently only match icons that nest themselves in
27-
// a parent `mdc-fab`.
26+
// mixin will style the icons appropriately.
2827
.mat-icon {
29-
@extend .mdc-fab__icon;
28+
@include mdc-fab-icon_();
29+
}
30+
}
31+
32+
.mat-mdc-extended-fab {
33+
@include mdc-fab-extended_();
34+
35+
.mat-icon {
36+
@include mdc-fab-extended-icon-padding(
37+
$mdc-fab-extended-icon-padding,
38+
$mdc-fab-extended-label-padding
39+
);
40+
}
41+
42+
// For Extended FAB with text label followed by icon.
43+
// We are checking for the a button class because white this is a FAB it
44+
// uses the same template as button.
45+
.mdc-button__label + .mat-icon {
46+
@include mdc-fab-extended-icon-padding(
47+
$mdc-fab-extended-icon-padding,
48+
$mdc-fab-extended-label-padding,
49+
$is-icon-at-end: true
50+
);
3051
}
3152
}
3253

src/material-experimental/mdc-button/fab.ts

Lines changed: 106 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,34 @@ import {
2727
MatButtonBase
2828
} from './button-base';
2929
import {ThemePalette} from '@angular/material-experimental/mdc-core';
30+
import {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion';
3031

3132
/**
3233
* Material Design floating action button (FAB) component. These buttons represent the primary
3334
* or most common action for users to interact with.
3435
* See https://material.io/components/buttons-floating-action-button/
3536
*
36-
* The `MatFabButton` class has two appearances: normal and mini.
37+
* The `MatFabButton` class has two appearances: normal and extended.
3738
*/
3839
@Component({
39-
selector: `button[mat-fab], button[mat-mini-fab]`,
40+
selector: `button[mat-fab]`,
4041
templateUrl: 'button.html',
4142
styleUrls: ['fab.css'],
42-
inputs: MAT_BUTTON_INPUTS,
43-
host: MAT_BUTTON_HOST,
43+
// TODO: change to MAT_BUTTON_INPUTS/MAT_BUTTON_HOST with spread after ViewEngine is deprecated
44+
inputs: ['disabled', 'disableRipple', 'color', 'extended'],
45+
host: {
46+
'[class.mdc-fab--extended]': 'extended',
47+
'[class.mat-mdc-extended-fab]': 'extended',
48+
'[attr.disabled]': 'disabled || null',
49+
'[class._mat-animation-noopable]': '_animationMode === "NoopAnimations"',
50+
// MDC automatically applies the primary theme color to the button, but we want to support
51+
// an unthemed version. If color is undefined, apply a CSS class that makes it easy to
52+
// select and style this "theme".
53+
'[class.mat-unthemed]': '!color',
54+
// Add a class that applies to all buttons. This makes it easier to target if somebody
55+
// wants to target all Material buttons.
56+
'[class.mat-mdc-button-base]': 'true',
57+
},
4458
exportAs: 'matButton',
4559
encapsulation: ViewEncapsulation.None,
4660
changeDetection: ChangeDetectionStrategy.OnPush,
@@ -49,11 +63,43 @@ export class MatFabButton extends MatButtonBase {
4963
// The FAB by default has its color set to accent.
5064
color = 'accent' as ThemePalette;
5165

66+
private _extended: boolean;
67+
get extended(): boolean { return this._extended; }
68+
set extended(value: boolean) { this._extended = coerceBooleanProperty(value); }
69+
5270
constructor(
5371
elementRef: ElementRef, platform: Platform, ngZone: NgZone,
5472
@Optional() @Inject(ANIMATION_MODULE_TYPE) animationMode?: string) {
5573
super(elementRef, platform, ngZone, animationMode);
5674
}
75+
76+
static ngAcceptInputType_extended: BooleanInput;
77+
}
78+
79+
/**
80+
* Material Design mini floating action button (FAB) component. These buttons represent the primary
81+
* or most common action for users to interact with.
82+
* See https://material.io/components/buttons-floating-action-button/
83+
*/
84+
@Component({
85+
selector: `button[mat-mini-fab]`,
86+
templateUrl: 'button.html',
87+
styleUrls: ['fab.css'],
88+
inputs: MAT_BUTTON_INPUTS,
89+
host: MAT_BUTTON_HOST,
90+
exportAs: 'matButton',
91+
encapsulation: ViewEncapsulation.None,
92+
changeDetection: ChangeDetectionStrategy.OnPush,
93+
})
94+
export class MatMiniFabButton extends MatButtonBase {
95+
// The FAB by default has its color set to accent.
96+
color = 'accent' as ThemePalette;
97+
98+
constructor(
99+
elementRef: ElementRef, platform: Platform, ngZone: NgZone,
100+
@Optional() @Inject(ANIMATION_MODULE_TYPE) animationMode?: string) {
101+
super(elementRef, platform, ngZone, animationMode);
102+
}
57103
}
58104

59105

@@ -62,14 +108,33 @@ export class MatFabButton extends MatButtonBase {
62108
* are used to provide links for the user to navigate across different routes or pages.
63109
* See https://material.io/components/buttons-floating-action-button/
64110
*
65-
* The `MatFabAnchor` class has two appearances: normal and mini.
111+
* The `MatFabAnchor` class has two appearances: normal and extended.
66112
*/
67113
@Component({
68-
selector: `a[mat-fab], a[mat-mini-fab]`,
114+
selector: `a[mat-fab]`,
69115
templateUrl: 'button.html',
70116
styleUrls: ['fab.css'],
71-
inputs: MAT_ANCHOR_INPUTS,
72-
host: MAT_ANCHOR_HOST,
117+
// TODO: change to MAT_ANCHOR_INPUTS/MAT_ANCHOR_HOST with spread after ViewEngine is deprecated
118+
inputs: ['disabled', 'disableRipple', 'color', 'tabIndex', 'extended'],
119+
host: {
120+
'[class.mdc-fab--extended]': 'extended',
121+
'[class.mat-mdc-extended-fab]': 'extended',
122+
'[attr.disabled]': 'disabled || null',
123+
'[class._mat-animation-noopable]': '_animationMode === "NoopAnimations"',
124+
125+
// Note that we ignore the user-specified tabindex when it's disabled for
126+
// consistency with the `mat-button` applied on native buttons where even
127+
// though they have an index, they're not tabbable.
128+
'[attr.tabindex]': 'disabled ? -1 : (tabIndex || 0)',
129+
'[attr.aria-disabled]': 'disabled.toString()',
130+
// MDC automatically applies the primary theme color to the button, but we want to support
131+
// an unthemed version. If color is undefined, apply a CSS class that makes it easy to
132+
// select and style this "theme".
133+
'[class.mat-unthemed]': '!color',
134+
// Add a class that applies to all buttons. This makes it easier to target if somebody
135+
// wants to target all Material buttons.
136+
'[class.mat-mdc-button-base]': 'true',
137+
},
73138
exportAs: 'matButton, matAnchor',
74139
encapsulation: ViewEncapsulation.None,
75140
changeDetection: ChangeDetectionStrategy.OnPush,
@@ -78,9 +143,42 @@ export class MatFabAnchor extends MatAnchor {
78143
// The FAB by default has its color set to accent.
79144
color = 'accent' as ThemePalette;
80145

146+
private _extended: boolean;
147+
get extended(): boolean { return this._extended; }
148+
set extended(value: boolean) { this._extended = coerceBooleanProperty(value); }
149+
150+
81151
constructor(
82152
elementRef: ElementRef, platform: Platform, ngZone: NgZone,
83153
@Optional() @Inject(ANIMATION_MODULE_TYPE) animationMode?: string) {
84154
super(elementRef, platform, ngZone, animationMode);
85155
}
156+
157+
static ngAcceptInputType_extended: BooleanInput;
158+
}
159+
160+
/**
161+
* Material Design mini floating action button (FAB) component for anchor elements. Anchor elements
162+
* are used to provide links for the user to navigate across different routes or pages.
163+
* See https://material.io/components/buttons-floating-action-button/
164+
*/
165+
@Component({
166+
selector: `a[mat-mini-fab]`,
167+
templateUrl: 'button.html',
168+
styleUrls: ['fab.css'],
169+
inputs: MAT_ANCHOR_INPUTS,
170+
host: MAT_ANCHOR_HOST,
171+
exportAs: 'matButton, matAnchor',
172+
encapsulation: ViewEncapsulation.None,
173+
changeDetection: ChangeDetectionStrategy.OnPush,
174+
})
175+
export class MatMiniFabAnchor extends MatAnchor {
176+
// The FAB by default has its color set to accent.
177+
color = 'accent' as ThemePalette;
178+
179+
constructor(
180+
elementRef: ElementRef, platform: Platform, ngZone: NgZone,
181+
@Optional() @Inject(ANIMATION_MODULE_TYPE) animationMode?: string) {
182+
super(elementRef, platform, ngZone, animationMode);
183+
}
86184
}

src/material-experimental/mdc-button/module.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import {NgModule} from '@angular/core';
1010
import {MatCommonModule, MatRippleModule} from '@angular/material-experimental/mdc-core';
1111
import {MatAnchor, MatButton} from './button';
12-
import {MatFabAnchor, MatFabButton} from './fab';
12+
import {MatFabAnchor, MatFabButton, MatMiniFabAnchor, MatMiniFabButton} from './fab';
1313
import {MatIconAnchor, MatIconButton} from './icon-button';
1414

1515
@NgModule({
@@ -19,6 +19,8 @@ import {MatIconAnchor, MatIconButton} from './icon-button';
1919
MatButton,
2020
MatIconAnchor,
2121
MatIconButton,
22+
MatMiniFabAnchor,
23+
MatMiniFabButton,
2224
MatFabAnchor,
2325
MatFabButton,
2426
MatCommonModule,
@@ -27,6 +29,8 @@ import {MatIconAnchor, MatIconButton} from './icon-button';
2729
MatAnchor,
2830
MatButton,
2931
MatIconAnchor,
32+
MatMiniFabAnchor,
33+
MatMiniFabButton,
3034
MatIconButton,
3135
MatFabAnchor,
3236
MatFabButton,

0 commit comments

Comments
 (0)