feat(select): allow disabling ripples for options (#5967)

* Adds a binding that allows developers to disable ripples for every option in a select.
This commit is contained in:
Paul Gschwendtner
2017-07-28 16:56:11 +02:00
committed by Andrew Seguin
parent 82535039a2
commit 34ec068741
4 changed files with 46 additions and 22 deletions
+6 -7
View File
@@ -9,18 +9,18 @@ describe('MdOption component', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [MdOptionModule],
declarations: [OptionWithDisableRipple]
declarations: [OptionWithDisable]
}).compileComponents();
}));
describe('ripples', () => {
let fixture: ComponentFixture<OptionWithDisableRipple>;
let fixture: ComponentFixture<OptionWithDisable>;
let optionDebugElement: DebugElement;
let optionNativeElement: HTMLElement;
let optionInstance: MdOption;
beforeEach(() => {
fixture = TestBed.createComponent(OptionWithDisableRipple);
fixture = TestBed.createComponent(OptionWithDisable);
fixture.detectChanges();
optionDebugElement = fixture.debugElement.query(By.directive(MdOption));
@@ -58,7 +58,7 @@ describe('MdOption component', () => {
expect(optionNativeElement.querySelectorAll('.mat-ripple-element').length)
.toBe(0, 'Expected no ripples to show up initially');
fixture.componentInstance.disableRipple = true;
optionInstance.disableRipple = true;
fixture.detectChanges();
dispatchFakeEvent(optionNativeElement, 'mousedown');
@@ -73,9 +73,8 @@ describe('MdOption component', () => {
});
@Component({
template: `<md-option [disableRipple]="disableRipple" [disabled]="disabled"></md-option>`
template: `<md-option [disabled]="disabled"></md-option>`
})
export class OptionWithDisableRipple {
disableRipple: boolean;
export class OptionWithDisable {
disabled: boolean;
}
+10 -13
View File
@@ -22,7 +22,6 @@ import {ENTER, SPACE} from '../keyboard/keycodes';
import {coerceBooleanProperty} from '@angular/cdk/coercion';
import {MATERIAL_COMPATIBILITY_MODE} from '../../core/compatibility/compatibility';
import {MdOptgroup} from './optgroup';
import {CanDisableRipple, mixinDisableRipple} from '../common-behaviors/disable-ripple';
/**
* Option IDs need to be unique across components, so this counter exists outside of
@@ -35,19 +34,12 @@ export class MdOptionSelectionChange {
constructor(public source: MdOption, public isUserInput = false) { }
}
// Boilerplate for applying mixins to MdOption.
/** @docs-private */
export class MdOptionBase {}
export const _MdOptionMixinBase = mixinDisableRipple(MdOptionBase);
/**
* Single option inside of a `<md-select>` element.
*/
@Component({
moduleId: module.id,
selector: 'md-option, mat-option',
inputs: ['disableRipple'],
host: {
'role': 'option',
'[attr.tabindex]': '_getTabIndex()',
@@ -66,10 +58,11 @@ export const _MdOptionMixinBase = mixinDisableRipple(MdOptionBase);
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MdOption extends _MdOptionMixinBase implements CanDisableRipple {
export class MdOption {
private _selected: boolean = false;
private _active: boolean = false;
private _multiple: boolean = false;
private _disableRipple: boolean = false;
/** Whether the option is disabled. */
private _disabled: boolean = false;
@@ -99,6 +92,13 @@ export class MdOption extends _MdOptionMixinBase implements CanDisableRipple {
get disabled() { return (this.group && this.group.disabled) || this._disabled; }
set disabled(value: any) { this._disabled = coerceBooleanProperty(value); }
/** Whether ripples for the option are disabled. */
get disableRipple() { return this._disableRipple; }
set disableRipple(value: boolean) {
this._disableRipple = value;
this._changeDetectorRef.markForCheck();
}
/** Event emitted when the option is selected or deselected. */
@Output() onSelectionChange = new EventEmitter<MdOptionSelectionChange>();
@@ -106,10 +106,7 @@ export class MdOption extends _MdOptionMixinBase implements CanDisableRipple {
private _element: ElementRef,
private _changeDetectorRef: ChangeDetectorRef,
@Optional() public readonly group: MdOptgroup,
@Optional() @Inject(MATERIAL_COMPATIBILITY_MODE) public _isCompatibilityMode: boolean
) {
super();
}
@Optional() @Inject(MATERIAL_COMPATIBILITY_MODE) public _isCompatibilityMode: boolean) {}
/**
* Whether or not the option is currently active and ready to be selected.
+14 -2
View File
@@ -308,6 +308,18 @@ describe('MdSelect', () => {
expect(event.defaultPrevented).toBe(true);
});
it('should update disableRipple properly on each option', () => {
const options = fixture.componentInstance.options.toArray();
expect(options.every(option => option.disableRipple === false))
.toBeTruthy('Expected all options to have disableRipple set to false initially.');
fixture.componentInstance.disableRipple = true;
fixture.detectChanges();
expect(options.every(option => option.disableRipple === true))
.toBeTruthy('Expected all options to have disableRipple set to true.');
});
});
describe('selection logic', () => {
@@ -924,7 +936,6 @@ describe('MdSelect', () => {
});
});
}));
});
describe('misc forms', () => {
@@ -2660,7 +2671,7 @@ describe('MdSelect', () => {
<div [style.height.px]="heightAbove"></div>
<md-select placeholder="Food" [formControl]="control" [required]="isRequired"
[tabIndex]="tabIndexOverride" [aria-label]="ariaLabel" [aria-labelledby]="ariaLabelledby"
[panelClass]="panelClass">
[panelClass]="panelClass" [disableRipple]="disableRipple">
<md-option *ngFor="let food of foods" [value]="food.value" [disabled]="food.disabled">
{{ food.viewValue }}
</md-option>
@@ -2687,6 +2698,7 @@ class BasicSelect {
ariaLabel: string;
ariaLabelledby: string;
panelClass = ['custom-one', 'custom-two'];
disableRipple: boolean;
@ViewChild(MdSelect) select: MdSelect;
@ViewChildren(MdOption) options: QueryList<MdOption>;
+16
View File
@@ -344,6 +344,15 @@ export class MdSelect extends _MdSelectMixinBase implements AfterContentInit, On
}
private _value: any;
/** Whether ripples for all options in the select are disabled. */
@Input()
get disableRipple(): boolean { return this._disableRipple; }
set disableRipple(value: boolean) {
this._disableRipple = coerceBooleanProperty(value);
this._setOptionDisableRipple();
}
private _disableRipple: boolean = false;
/** Aria label of the select. If not specified, the placeholder will be used as label. */
@Input('aria-label') ariaLabel: string = '';
@@ -719,6 +728,7 @@ export class MdSelect extends _MdSelectMixinBase implements AfterContentInit, On
this._listenToOptions();
this._setOptionIds();
this._setOptionMultiple();
this._setOptionDisableRipple();
}
/** Listens to user-generated selection events on each option. */
@@ -815,6 +825,12 @@ export class MdSelect extends _MdSelectMixinBase implements AfterContentInit, On
}
}
/** Sets the `disableRipple` property on each option. */
private _setOptionDisableRipple() {
if (this.options) {
this.options.forEach(option => option.disableRipple = this.disableRipple);
}
}
/**
* Must set the width of the selected option's value programmatically
* because it is absolutely positioned and otherwise will not clip