diff --git a/src/material/radio/radio.md b/src/material/radio/radio.md index 8a999eb056c5..0e978b65093f 100644 --- a/src/material/radio/radio.md +++ b/src/material/radio/radio.md @@ -34,3 +34,13 @@ This internal radio button receives focus and is automatically labelled by the t `` element. Radio button groups should be given a meaningful label via `aria-label` or `aria-labelledby`. + +### Default Color Configuration +The default color for radio buttons can be configured globally using the `MAT_RADIO_DEFAULT_OPTIONS` provider + +``` +providers: [ + provide: MAT_RADIO_DEFAULT_OPTIONS, + useValue: { color: 'accent' }, +] +``` \ No newline at end of file diff --git a/src/material/radio/radio.spec.ts b/src/material/radio/radio.spec.ts index 07c9c04347fa..65f6541115cd 100644 --- a/src/material/radio/radio.spec.ts +++ b/src/material/radio/radio.spec.ts @@ -3,6 +3,8 @@ import {FormControl, FormsModule, NgModel, ReactiveFormsModule} from '@angular/f import {Component, DebugElement, ViewChild} from '@angular/core'; import {By} from '@angular/platform-browser'; import {dispatchFakeEvent} from '@angular/cdk/testing'; + +import {MAT_RADIO_DEFAULT_OPTIONS} from './radio'; import {MatRadioButton, MatRadioChange, MatRadioGroup, MatRadioModule} from './index'; describe('MatRadio', () => { @@ -796,6 +798,43 @@ describe('MatRadio', () => { }); }); +describe('MatRadioDefaultOverrides', () => { + describe('when MAT_RADIO_DEFAULT_OPTIONS overridden', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [MatRadioModule, FormsModule], + declarations: [DefaultRadioButton, RadioButtonWithColorBinding], + providers: [{ + provide: MAT_RADIO_DEFAULT_OPTIONS, + useValue: {color: 'primary'}, + }], + }); + + TestBed.compileComponents(); + })); + it('should override default color in Component', () => { + const fixture: ComponentFixture = + TestBed.createComponent(DefaultRadioButton); + fixture.detectChanges(); + const radioDebugElement: DebugElement = + fixture.debugElement.query(By.directive(MatRadioButton)); + expect( + radioDebugElement.nativeElement.classList + ).toContain('mat-primary'); + }); + it('should not override explicit input bindings', () => { + const fixture: ComponentFixture = + TestBed.createComponent(RadioButtonWithColorBinding); + fixture.detectChanges(); + const radioDebugElement: DebugElement = + fixture.debugElement.query(By.directive(MatRadioButton)); + expect( + radioDebugElement.nativeElement.classList + ).not.toContain('mat-primary'); + expect(radioDebugElement.nativeElement.classList).toContain('mat-warn'); + }); + }); +}); @Component({ template: ` @@ -937,3 +976,13 @@ class TranscludingWrapper {} template: `` }) class RadioButtonWithPredefinedTabindex {} + +@Component({ + template: `` +}) +class DefaultRadioButton {} + +@Component({ + template: `` +}) +class RadioButtonWithColorBinding {} diff --git a/src/material/radio/radio.ts b/src/material/radio/radio.ts index c6d517567727..fc7d93470aeb 100644 --- a/src/material/radio/radio.ts +++ b/src/material/radio/radio.ts @@ -21,6 +21,7 @@ import { EventEmitter, forwardRef, Inject, + InjectionToken, Input, OnDestroy, OnInit, @@ -43,6 +44,22 @@ import { import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations'; +export interface MatRadioDefaultOptions { + color: ThemePalette; +} + +export const MAT_RADIO_DEFAULT_OPTIONS = + new InjectionToken('mat-radio-default-options', { + providedIn: 'root', + factory: MAT_RADIO_DEFAULT_OPTIONS_FACTORY +}); + +export function MAT_RADIO_DEFAULT_OPTIONS_FACTORY(): MatRadioDefaultOptions { + return { + color: 'accent' + }; +} + // Increasing integer for generating unique ids for radio components. let nextUniqueId = 0; @@ -433,7 +450,9 @@ export class MatRadioButton extends _MatRadioButtonMixinBase /** Theme color of the radio button. */ @Input() get color(): ThemePalette { - return this._color || (this.radioGroup && this.radioGroup.color) || 'accent'; + return this._color || + (this.radioGroup && this.radioGroup.color) || + this._providerOverride && this._providerOverride.color || 'accent'; } set color(newValue: ThemePalette) { this._color = newValue; } private _color: ThemePalette; @@ -474,7 +493,9 @@ export class MatRadioButton extends _MatRadioButtonMixinBase private _changeDetector: ChangeDetectorRef, private _focusMonitor: FocusMonitor, private _radioDispatcher: UniqueSelectionDispatcher, - @Optional() @Inject(ANIMATION_MODULE_TYPE) public _animationMode?: string) { + @Optional() @Inject(ANIMATION_MODULE_TYPE) public _animationMode?: string, + @Optional() @Inject(MAT_RADIO_DEFAULT_OPTIONS) + private _providerOverride?: MatRadioDefaultOptions) { super(elementRef); // Assertions. Ideally these should be stripped out by the compiler. diff --git a/tools/public_api_guard/material/radio.d.ts b/tools/public_api_guard/material/radio.d.ts index 38189132e674..5a199f54801b 100644 --- a/tools/public_api_guard/material/radio.d.ts +++ b/tools/public_api_guard/material/radio.d.ts @@ -1,3 +1,7 @@ +export declare const MAT_RADIO_DEFAULT_OPTIONS: InjectionToken; + +export declare function MAT_RADIO_DEFAULT_OPTIONS_FACTORY(): MatRadioDefaultOptions; + export declare const MAT_RADIO_GROUP_CONTROL_VALUE_ACCESSOR: any; export declare class MatRadioButton extends _MatRadioButtonMixinBase implements OnInit, AfterViewInit, OnDestroy, CanDisableRipple, HasTabIndex { @@ -17,7 +21,7 @@ export declare class MatRadioButton extends _MatRadioButtonMixinBase implements radioGroup: MatRadioGroup; required: boolean; value: any; - constructor(radioGroup: MatRadioGroup, elementRef: ElementRef, _changeDetector: ChangeDetectorRef, _focusMonitor: FocusMonitor, _radioDispatcher: UniqueSelectionDispatcher, _animationMode?: string | undefined); + constructor(radioGroup: MatRadioGroup, elementRef: ElementRef, _changeDetector: ChangeDetectorRef, _focusMonitor: FocusMonitor, _radioDispatcher: UniqueSelectionDispatcher, _animationMode?: string | undefined, _providerOverride?: MatRadioDefaultOptions | undefined); _isRippleDisabled(): boolean; _markForCheck(): void; _onInputChange(event: Event): void; @@ -36,6 +40,10 @@ export declare class MatRadioChange { value: any); } +export interface MatRadioDefaultOptions { + color: ThemePalette; +} + export declare class MatRadioGroup implements AfterContentInit, ControlValueAccessor { _controlValueAccessorChangeFn: (value: any) => void; _radios: QueryList;