Skip to content

feat(radio): support theme color on mat-radio-group #15741

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/dev-app/radio/radio-demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ <h1>Color Example</h1>
<mat-radio-button name="group2" color="warn">Warn</mat-radio-button>
</section>

<h1>Group Color Example</h1>
<section class="demo-section">
<mat-radio-group color="warn">
<mat-radio-button name="group3" value="1">Option 1</mat-radio-button>
<mat-radio-button name="group3" value="2">Option 2</mat-radio-button>
<mat-radio-button name="group3" value="3">Option 3</mat-radio-button>
<mat-radio-button name="group3" value="4" color="primary">Option with color override</mat-radio-button>
</mat-radio-group>
</section>

<h1>Dynamic Example</h1>
<section class="demo-section">
<div>
Expand Down
23 changes: 23 additions & 0 deletions src/material/radio/radio.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,25 @@ describe('MatRadio', () => {
expect(radioNativeElements.every(radioEl => radioEl.classList.contains('mat-accent')))
.toBe(true, 'Expected every radio element to fallback to accent color if value is falsy.');
});

it('should be able to inherit the color from the radio group', () => {
groupInstance.color = 'warn';
fixture.detectChanges();

expect(radioNativeElements.every(radioEl => radioEl.classList.contains('mat-warn')))
.toBe(true, 'Expected every radio element to have the warn color.');
});

it('should have the individual button color take precedence over the group color', () => {
radioInstances[1].color = 'primary';
groupInstance.color = 'warn';
fixture.detectChanges();

expect(radioNativeElements[0].classList).toContain('mat-warn');
expect(radioNativeElements[1].classList).toContain('mat-primary');
expect(radioNativeElements[2].classList).toContain('mat-warn');
});

});

describe('group with ngModel', () => {
Expand Down Expand Up @@ -702,6 +721,10 @@ describe('MatRadio', () => {
expect(radio.hasAttribute('name')).toBe(false);
});

it('should default the radio color to `accent`', () => {
expect(seasonRadioInstances.every(radio => radio.color === 'accent')).toBe(true);
});

});

describe('with tabindex', () => {
Expand Down
28 changes: 20 additions & 8 deletions src/material/radio/radio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,13 @@ import {
} from '@angular/core';
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
import {
CanColor,
CanColorCtor,
CanDisableRipple,
CanDisableRippleCtor,
HasTabIndex,
HasTabIndexCtor,
mixinColor,
mixinDisableRipple,
mixinTabIndex,
ThemePalette,
} from '@angular/material/core';
import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations';

Expand Down Expand Up @@ -122,6 +120,9 @@ export class MatRadioGroup implements AfterContentInit, ControlValueAccessor {
@ContentChildren(forwardRef(() => MatRadioButton), { descendants: true })
_radios: QueryList<MatRadioButton>;

/** Theme color for all of the radio buttons in the group. */
@Input() color: ThemePalette;

/** Name of the radio button group. All radio buttons inside this group will use this name. */
@Input()
get name(): string { return this._name; }
Expand Down Expand Up @@ -302,9 +303,9 @@ class MatRadioButtonBase {
}
// As per Material design specifications the selection control radio should use the accent color
// palette by default. https://material.io/guidelines/components/selection-controls.html
const _MatRadioButtonMixinBase: CanColorCtor & CanDisableRippleCtor & HasTabIndexCtor &
typeof MatRadioButtonBase =
mixinColor(mixinDisableRipple(mixinTabIndex(MatRadioButtonBase)), 'accent');
const _MatRadioButtonMixinBase:
CanDisableRippleCtor & HasTabIndexCtor & typeof MatRadioButtonBase =
mixinDisableRipple(mixinTabIndex(MatRadioButtonBase));

/**
* A Material design radio-button. Typically placed inside of `<mat-radio-group>` elements.
Expand All @@ -314,14 +315,17 @@ const _MatRadioButtonMixinBase: CanColorCtor & CanDisableRippleCtor & HasTabInde
selector: 'mat-radio-button',
templateUrl: 'radio.html',
styleUrls: ['radio.css'],
inputs: ['color', 'disableRipple', 'tabIndex'],
inputs: ['disableRipple', 'tabIndex'],
encapsulation: ViewEncapsulation.None,
exportAs: 'matRadioButton',
host: {
'class': 'mat-radio-button',
'[class.mat-radio-checked]': 'checked',
'[class.mat-radio-disabled]': 'disabled',
'[class._mat-animation-noopable]': '_animationMode === "NoopAnimations"',
'[class.mat-primary]': 'color === "primary"',
'[class.mat-accent]': 'color === "accent"',
'[class.mat-warn]': 'color === "warn"',
// Needs to be -1 so the `focus` event still fires.
'[attr.tabindex]': '-1',
'[attr.id]': 'id',
Expand All @@ -333,7 +337,7 @@ const _MatRadioButtonMixinBase: CanColorCtor & CanDisableRippleCtor & HasTabInde
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MatRadioButton extends _MatRadioButtonMixinBase
implements OnInit, AfterViewInit, OnDestroy, CanColor, CanDisableRipple, HasTabIndex {
implements OnInit, AfterViewInit, OnDestroy, CanDisableRipple, HasTabIndex {

private _uniqueId: string = `mat-radio-${++nextUniqueId}`;

Expand Down Expand Up @@ -426,6 +430,14 @@ export class MatRadioButton extends _MatRadioButtonMixinBase
this._required = coerceBooleanProperty(value);
}

/** Theme color of the radio button. */
@Input()
get color(): ThemePalette {
return this._color || (this.radioGroup && this.radioGroup.color) || 'accent';
}
set color(newValue: ThemePalette) { this._color = newValue; }
private _color: ThemePalette;

/**
* Event emitted when the checked state of this radio button changes.
* Change events are only emitted when the value changes due to user interaction with
Expand Down
4 changes: 3 additions & 1 deletion tools/public_api_guard/material/radio.d.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
export declare const MAT_RADIO_GROUP_CONTROL_VALUE_ACCESSOR: any;

export declare class MatRadioButton extends _MatRadioButtonMixinBase implements OnInit, AfterViewInit, OnDestroy, CanColor, CanDisableRipple, HasTabIndex {
export declare class MatRadioButton extends _MatRadioButtonMixinBase implements OnInit, AfterViewInit, OnDestroy, CanDisableRipple, HasTabIndex {
_animationMode?: string | undefined;
_inputElement: ElementRef<HTMLInputElement>;
ariaDescribedby: string;
ariaLabel: string;
ariaLabelledby: string;
readonly change: EventEmitter<MatRadioChange>;
checked: boolean;
color: ThemePalette;
disabled: boolean;
id: string;
readonly inputId: string;
Expand Down Expand Up @@ -39,6 +40,7 @@ export declare class MatRadioGroup implements AfterContentInit, ControlValueAcce
_controlValueAccessorChangeFn: (value: any) => void;
_radios: QueryList<MatRadioButton>;
readonly change: EventEmitter<MatRadioChange>;
color: ThemePalette;
disabled: boolean;
labelPosition: 'before' | 'after';
name: string;
Expand Down