Skip to content

Commit bfc1286

Browse files
crisbetovivian-hu-zz
authored andcommitted
feat(badge): allow badge to be disabled (#13196)
Adds the `matBadgeDisabled` input that allows for a badge to be styled as if it was disabled. This allows it to blend in when it's attached to an element that is also disabled. Fixes #13191.
1 parent 0886cef commit bfc1286

File tree

4 files changed

+52
-4
lines changed

4 files changed

+52
-4
lines changed

src/demo-app/badge/badge-demo.html

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,14 @@ <h3>Buttons</h3>
4848
<mat-icon color="primary">home</mat-icon>
4949
</button>
5050

51+
<button mat-raised-button [matBadge]="badgeContent" matBadgeDisabled>
52+
<mat-icon color="primary">home</mat-icon>
53+
</button>
54+
55+
<button disabled mat-raised-button [matBadge]="badgeContent" matBadgeDisabled>
56+
<mat-icon color="primary">home</mat-icon>
57+
</button>
58+
5159
<button mat-raised-button matBadge="22" matBadgePosition="below before">
5260
<mat-icon color="primary">home</mat-icon>
5361
</button>

src/lib/badge/_badge-theme.scss

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ $mat-badge-large-size: $mat-badge-default-size + 6;
9696
$accent: map-get($theme, accent);
9797
$warn: map-get($theme, warn);
9898
$primary: map-get($theme, primary);
99+
$background: map-get($theme, background);
100+
$foreground: map-get($theme, foreground);
99101

100102
.mat-badge-content {
101103
color: mat-color($primary, default-contrast);
@@ -126,6 +128,20 @@ $mat-badge-large-size: $mat-badge-default-size + 6;
126128
}
127129
}
128130

131+
.mat-badge-disabled {
132+
.mat-badge-content {
133+
// The disabled color usually has some kind of opacity, but because the badge is overlayed
134+
// on top of something else, it won't look good if it's opaque. We convert it into a solid
135+
// color by taking the opacity from the rgba value and using the value to determine the
136+
// percentage of the background to put into foreground when mixing the colors together.
137+
$app-background: mat-color($background, 'background');
138+
$badge-color: mat-color($foreground, disabled-button);
139+
$badge-opacity: opacity($badge-color);
140+
background: mix($app-background, rgba($badge-color, 1), (1 - $badge-opacity) * 100%);
141+
color: mat-color($foreground, disabled-text);
142+
}
143+
}
144+
129145
.mat-badge-content {
130146
position: absolute;
131147
text-align: center;

src/lib/badge/badge.spec.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,17 @@ describe('MatBadge', () => {
154154
expect(encapsulationAttr).toBeTruthy();
155155
});
156156

157+
it('should toggle a class depending on the badge disabled state', () => {
158+
const element: HTMLElement = badgeDebugElement.nativeElement;
159+
160+
expect(element.classList).not.toContain('mat-badge-disabled');
161+
162+
testComponent.badgeDisabled = true;
163+
fixture.detectChanges();
164+
165+
expect(element.classList).toContain('mat-badge-disabled');
166+
});
167+
157168
});
158169

159170
/** Test component that contains a MatBadge. */
@@ -168,7 +179,8 @@ describe('MatBadge', () => {
168179
[matBadgeHidden]="badgeHidden"
169180
[matBadgeSize]="badgeSize"
170181
[matBadgeOverlap]="badgeOverlap"
171-
[matBadgeDescription]="badgeDescription">
182+
[matBadgeDescription]="badgeDescription"
183+
[matBadgeDisabled]="badgeDisabled">
172184
home
173185
</span>
174186
`
@@ -181,4 +193,5 @@ class BadgeTestApp {
181193
badgeSize = 'medium';
182194
badgeOverlap = false;
183195
badgeDescription: string;
196+
badgeDisabled = false;
184197
}

src/lib/badge/badge.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,25 @@ import {
1919
Optional,
2020
Renderer2,
2121
} from '@angular/core';
22-
import {ThemePalette} from '@angular/material/core';
22+
import {ThemePalette, mixinDisabled, CanDisableCtor, CanDisable} from '@angular/material/core';
2323

2424

2525
let nextId = 0;
2626

27+
// Boilerplate for applying mixins to MatBadge.
28+
/** @docs-private */
29+
export class MatBadgeBase {}
30+
31+
export const _MatBadgeMixinBase:
32+
CanDisableCtor & typeof MatBadgeBase = mixinDisabled(MatBadgeBase);
33+
2734
export type MatBadgePosition = 'above after' | 'above before' | 'below before' | 'below after';
2835
export type MatBadgeSize = 'small' | 'medium' | 'large';
2936

3037
/** Directive to display a text badge. */
3138
@Directive({
3239
selector: '[matBadge]',
40+
inputs: ['disabled: matBadgeDisabled'],
3341
host: {
3442
'class': 'mat-badge',
3543
'[class.mat-badge-overlap]': 'overlap',
@@ -41,9 +49,10 @@ export type MatBadgeSize = 'small' | 'medium' | 'large';
4149
'[class.mat-badge-medium]': 'size === "medium"',
4250
'[class.mat-badge-large]': 'size === "large"',
4351
'[class.mat-badge-hidden]': 'hidden || !_hasContent',
52+
'[class.mat-badge-disabled]': 'disabled',
4453
},
4554
})
46-
export class MatBadge implements OnDestroy {
55+
export class MatBadge extends _MatBadgeMixinBase implements OnDestroy, CanDisable {
4756
/** Whether the badge has any content. */
4857
_hasContent = false;
4958

@@ -113,7 +122,9 @@ export class MatBadge implements OnDestroy {
113122
private _elementRef: ElementRef<HTMLElement>,
114123
private _ariaDescriber: AriaDescriber,
115124
/** @breaking-change 8.0.0 Make _renderer a required param and remove _document. */
116-
private _renderer?: Renderer2) {}
125+
private _renderer?: Renderer2) {
126+
super();
127+
}
117128

118129
/** Whether the badge is above the host or not */
119130
isAbove(): boolean {

0 commit comments

Comments
 (0)