Skip to content

Commit 1fa3e24

Browse files
authored
Merge branch 'master' into fix-cdk-stepper-coerceNumberProperty
2 parents 0981b66 + 88601fa commit 1fa3e24

File tree

17 files changed

+238
-30
lines changed

17 files changed

+238
-30
lines changed

.circleci/config.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,13 @@ jobs:
152152
e2e_tests:
153153
<<: *job_defaults
154154
resource_class: xlarge
155+
environment:
156+
GCP_DECRYPT_TOKEN: *gcp_decrypt_token
155157
steps:
156158
- *checkout_code
157159
- *restore_cache
160+
- *copy_bazel_config
161+
- *setup_bazel_remote_execution
158162

159163
- run: bazel test e2e/...
160164

@@ -299,11 +303,14 @@ jobs:
299303
publish_snapshots:
300304
<<: *job_defaults
301305
resource_class: xlarge
306+
environment:
307+
GCP_DECRYPT_TOKEN: *gcp_decrypt_token
302308
steps:
303309
- *checkout_code
304310
- *restore_cache
305-
- *yarn_install
306311
- *attach_release_output
312+
- *copy_bazel_config
313+
- *setup_bazel_remote_execution
307314

308315
# CircleCI has a config setting to enforce SSH for all github connections.
309316
# This is not compatible with our mechanism of using a Personal Access Token

.github/CODEOWNERS

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,62 @@
197197
/.circleci/** @jelbourn
198198
/scripts/** @devversion @jelbourn
199199
/test/** @devversion @jelbourn
200-
/tools/** @devversion @jelbourn
200+
/tools/**/!(*.d.ts) @devversion @jelbourn
201+
202+
# Public API golden files
203+
/tools/public_api_guard/cdk/a11y.d.ts @jelbourn @devversion
204+
/tools/public_api_guard/cdk/accordion.d.ts @josephperrott
205+
/tools/public_api_guard/cdk/bidi.d.ts @jelbourn
206+
/tools/public_api_guard/cdk/cdk.d.ts @jelbourn
207+
/tools/public_api_guard/cdk/coercion.d.ts @jelbourn
208+
/tools/public_api_guard/cdk/collections.d.ts @jelbourn @crisbeto @andrewseguin
209+
/tools/public_api_guard/cdk/drag-drop.d.ts @crisbeto
210+
/tools/public_api_guard/cdk/keycodes.d.ts @jelbourn
211+
/tools/public_api_guard/cdk/layout.d.ts @josephperrott
212+
/tools/public_api_guard/cdk/observers.d.ts @jelbourn @crisbeto
213+
/tools/public_api_guard/cdk/overlay.d.ts @jelbourn @crisbeto
214+
/tools/public_api_guard/cdk/platform.d.ts @jelbourn @devversion
215+
/tools/public_api_guard/cdk/scrolling.d.ts @andrewseguin @crisbeto
216+
/tools/public_api_guard/cdk/stepper.d.ts @mmalerba
217+
/tools/public_api_guard/cdk/table.d.ts @andrewseguin
218+
/tools/public_api_guard/cdk/text-field.d.ts @mmalerba
219+
/tools/public_api_guard/cdk/tree.d.ts @jelbourn @andrewseguin
220+
/tools/public_api_guard/lib/autocomplete.d.ts @crisbeto
221+
/tools/public_api_guard/lib/badge.d.ts @jelbourn
222+
/tools/public_api_guard/lib/bottom-sheet.d.ts @jelbourn @crisbeto
223+
/tools/public_api_guard/lib/button-toggle.d.ts @jelbourn
224+
/tools/public_api_guard/lib/button.d.ts @jelbourn @josephperrott
225+
/tools/public_api_guard/lib/card.d.ts @jelbourn
226+
/tools/public_api_guard/lib/checkbox.d.ts @jelbourn @devversion @josephperrott
227+
/tools/public_api_guard/lib/chips.d.ts @jelbourn
228+
/tools/public_api_guard/lib/core.d.ts @jelbourn
229+
/tools/public_api_guard/lib/datepicker.d.ts @mmalerba
230+
/tools/public_api_guard/lib/dialog.d.ts @jelbourn @crisbeto
231+
/tools/public_api_guard/lib/divider.d.ts @jelbourn @crisbeto
232+
/tools/public_api_guard/lib/expansion.d.ts @josephperrott @jelbourn
233+
/tools/public_api_guard/lib/form-field.d.ts @mmalerba
234+
/tools/public_api_guard/lib/grid-list.d.ts @jelbourn
235+
/tools/public_api_guard/lib/icon.d.ts @jelbourn
236+
/tools/public_api_guard/lib/input.d.ts @mmalerba
237+
/tools/public_api_guard/lib/list.d.ts @jelbourn @crisbeto @devversion
238+
/tools/public_api_guard/lib/menu.d.ts @crisbeto
239+
/tools/public_api_guard/lib/paginator.d.ts @andrewseguin
240+
/tools/public_api_guard/lib/progress-bar.d.ts @jelbourn @crisbeto @josephperrott
241+
/tools/public_api_guard/lib/progress-spinner.d.ts @jelbourn @crisbeto @josephperrott
242+
/tools/public_api_guard/lib/radio.d.ts @jelbourn @devversion
243+
/tools/public_api_guard/lib/select.d.ts @crisbeto
244+
/tools/public_api_guard/lib/sidenav.d.ts @mmalerba
245+
/tools/public_api_guard/lib/slide-toggle.d.ts @devversion
246+
/tools/public_api_guard/lib/slider.d.ts @mmalerba
247+
/tools/public_api_guard/lib/snack-bar.d.ts @jelbourn @crisbeto @josephperrott
248+
/tools/public_api_guard/lib/sort.d.ts @andrewseguin
249+
/tools/public_api_guard/lib/stepper.d.ts @mmalerba
250+
/tools/public_api_guard/lib/table.d.ts @andrewseguin
251+
/tools/public_api_guard/lib/tabs.d.ts @andrewseguin
252+
/tools/public_api_guard/lib/toolbar.d.ts @devversion
253+
/tools/public_api_guard/lib/tooltip.d.ts @andrewseguin
254+
/tools/public_api_guard/lib/tree.d.ts @jelbourn @andrewseguin
255+
/tools/public_api_guard/lib/lib.d.ts @jelbourn
201256

202257
# Misc
203258
/* @jelbourn

src/cdk/drag-drop/directives/drag.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,8 @@ describe('CdkDrag', () => {
606606
dragElement.style.transform = 'scale(2)';
607607

608608
dragElementViaMouse(fixture, dragElement, 50, 100);
609-
expect(dragElement.style.transform).toBe('scale(2) translate3d(50px, 100px, 0px)');
609+
610+
expect(dragElement.style.transform).toBe('translate3d(50px, 100px, 0px) scale(2)');
610611

611612
fixture.componentInstance.dragInstance.reset();
612613
expect(dragElement.style.transform).toBe('scale(2)');

src/cdk/scrolling/scrollable.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,15 @@ export class CdkScrollable implements OnInit, OnDestroy {
9595

9696
// Rewrite the bottom offset as a top offset.
9797
if (options.bottom != null) {
98-
options.top = el.scrollHeight - el.clientHeight - options.bottom;
98+
(options as _Without<_Bottom> & _Top).top =
99+
el.scrollHeight - el.clientHeight - options.bottom;
99100
}
100101

101102
// Rewrite the right offset as a left offset.
102103
if (isRtl && getRtlScrollAxisType() != RtlScrollAxisType.NORMAL) {
103104
if (options.left != null) {
104-
options.right = el.scrollWidth - el.clientWidth - options.left;
105+
(options as _Without<_Left> & _Right).right =
106+
el.scrollWidth - el.clientWidth - options.left;
105107
}
106108

107109
if (getRtlScrollAxisType() == RtlScrollAxisType.INVERTED) {
@@ -111,7 +113,8 @@ export class CdkScrollable implements OnInit, OnDestroy {
111113
}
112114
} else {
113115
if (options.right != null) {
114-
options.left = el.scrollWidth - el.clientWidth - options.right;
116+
(options as _Without<_Right> & _Left).left =
117+
el.scrollWidth - el.clientWidth - options.right;
115118
}
116119
}
117120

src/lib/list/list.spec.ts

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
import {async, TestBed} from '@angular/core/testing';
1+
import {async, TestBed, fakeAsync, tick} from '@angular/core/testing';
22
import {Component, QueryList, ViewChildren} from '@angular/core';
3+
import {defaultRippleAnimationConfig} from '@angular/material/core';
4+
import {dispatchMouseEvent} from '@angular/cdk/testing';
35
import {By} from '@angular/platform-browser';
46
import {MatListItem, MatListModule} from './index';
57

6-
78
describe('MatList', () => {
9+
// Default ripple durations used for testing.
10+
const {enterDuration, exitDuration} = defaultRippleAnimationConfig;
811

912
beforeEach(async(() => {
1013
TestBed.configureTestingModule({
@@ -207,6 +210,62 @@ describe('MatList', () => {
207210
expect(items.every(item => item._isRippleDisabled())).toBe(true);
208211
});
209212

213+
it('should disable item ripples when list ripples are disabled via the input in nav list',
214+
fakeAsync(() => {
215+
const fixture = TestBed.createComponent(NavListWithOneAnchorItem);
216+
fixture.detectChanges();
217+
218+
const rippleTarget = fixture.nativeElement.querySelector('.mat-list-item-content');
219+
220+
dispatchMouseEvent(rippleTarget, 'mousedown');
221+
dispatchMouseEvent(rippleTarget, 'mouseup');
222+
223+
expect(rippleTarget.querySelectorAll('.mat-ripple-element').length)
224+
.toBe(1, 'Expected ripples to be enabled by default.');
225+
226+
// Wait for the ripples to go away.
227+
tick(enterDuration + exitDuration);
228+
expect(rippleTarget.querySelectorAll('.mat-ripple-element').length)
229+
.toBe(0, 'Expected ripples to go away.');
230+
231+
fixture.componentInstance.disableListRipple = true;
232+
fixture.detectChanges();
233+
234+
dispatchMouseEvent(rippleTarget, 'mousedown');
235+
dispatchMouseEvent(rippleTarget, 'mouseup');
236+
237+
expect(rippleTarget.querySelectorAll('.mat-ripple-element').length)
238+
.toBe(0, 'Expected no ripples after list ripples are disabled.');
239+
}));
240+
241+
it('should disable item ripples when list ripples are disabled via the input in an action list',
242+
fakeAsync(() => {
243+
const fixture = TestBed.createComponent(ActionListWithoutType);
244+
fixture.detectChanges();
245+
246+
const rippleTarget = fixture.nativeElement.querySelector('.mat-list-item-content');
247+
248+
dispatchMouseEvent(rippleTarget, 'mousedown');
249+
dispatchMouseEvent(rippleTarget, 'mouseup');
250+
251+
expect(rippleTarget.querySelectorAll('.mat-ripple-element').length)
252+
.toBe(1, 'Expected ripples to be enabled by default.');
253+
254+
// Wait for the ripples to go away.
255+
tick(enterDuration + exitDuration);
256+
expect(rippleTarget.querySelectorAll('.mat-ripple-element').length)
257+
.toBe(0, 'Expected ripples to go away.');
258+
259+
fixture.componentInstance.disableListRipple = true;
260+
fixture.detectChanges();
261+
262+
dispatchMouseEvent(rippleTarget, 'mousedown');
263+
dispatchMouseEvent(rippleTarget, 'mouseup');
264+
265+
expect(rippleTarget.querySelectorAll('.mat-ripple-element').length)
266+
.toBe(0, 'Expected no ripples after list ripples are disabled.');
267+
}));
268+
210269
});
211270

212271

src/lib/list/list.ts

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ import {
1717
Optional,
1818
QueryList,
1919
ViewEncapsulation,
20+
OnChanges,
21+
OnDestroy,
22+
ChangeDetectorRef,
2023
} from '@angular/core';
2124
import {
2225
CanDisableRipple,
@@ -25,6 +28,8 @@ import {
2528
setLines,
2629
mixinDisableRipple,
2730
} from '@angular/material/core';
31+
import {Subject} from 'rxjs';
32+
import {takeUntil} from 'rxjs/operators';
2833

2934
// Boilerplate for applying mixins to MatList.
3035
/** @docs-private */
@@ -52,7 +57,19 @@ export const _MatListItemMixinBase: CanDisableRippleCtor & typeof MatListItemBas
5257
encapsulation: ViewEncapsulation.None,
5358
changeDetection: ChangeDetectionStrategy.OnPush,
5459
})
55-
export class MatNavList extends _MatListMixinBase implements CanDisableRipple {}
60+
export class MatNavList extends _MatListMixinBase implements CanDisableRipple, OnChanges,
61+
OnDestroy {
62+
/** Emits when the state of the list changes. */
63+
_stateChanges = new Subject<void>();
64+
65+
ngOnChanges() {
66+
this._stateChanges.next();
67+
}
68+
69+
ngOnDestroy() {
70+
this._stateChanges.complete();
71+
}
72+
}
5673

5774
@Component({
5875
moduleId: module.id,
@@ -67,7 +84,10 @@ export class MatNavList extends _MatListMixinBase implements CanDisableRipple {}
6784
encapsulation: ViewEncapsulation.None,
6885
changeDetection: ChangeDetectionStrategy.OnPush,
6986
})
70-
export class MatList extends _MatListMixinBase implements CanDisableRipple {
87+
export class MatList extends _MatListMixinBase implements CanDisableRipple, OnChanges, OnDestroy {
88+
/** Emits when the state of the list changes. */
89+
_stateChanges = new Subject<void>();
90+
7191
/**
7292
* @deprecated _elementRef parameter to be made required.
7393
* @breaking-change 8.0.0
@@ -94,6 +114,14 @@ export class MatList extends _MatListMixinBase implements CanDisableRipple {
94114

95115
return null;
96116
}
117+
118+
ngOnChanges() {
119+
this._stateChanges.next();
120+
}
121+
122+
ngOnDestroy() {
123+
this._stateChanges.complete();
124+
}
97125
}
98126

99127
/**
@@ -143,17 +171,20 @@ export class MatListSubheaderCssMatStyler {}
143171
changeDetection: ChangeDetectionStrategy.OnPush,
144172
})
145173
export class MatListItem extends _MatListItemMixinBase implements AfterContentInit,
146-
CanDisableRipple {
174+
CanDisableRipple, OnDestroy {
147175
private _isInteractiveList: boolean = false;
148176
private _list?: MatNavList | MatList;
177+
private _destroyed = new Subject<void>();
149178

150179
@ContentChildren(MatLine) _lines: QueryList<MatLine>;
151180
@ContentChild(MatListAvatarCssMatStyler) _avatar: MatListAvatarCssMatStyler;
152181
@ContentChild(MatListIconCssMatStyler) _icon: MatListIconCssMatStyler;
153182

154183
constructor(private _element: ElementRef<HTMLElement>,
155184
@Optional() navList?: MatNavList,
156-
@Optional() list?: MatList) {
185+
@Optional() list?: MatList,
186+
// @breaking-change 8.0.0 `_changeDetectorRef` to be made into a required parameter.
187+
_changeDetectorRef?: ChangeDetectorRef) {
157188
super();
158189
this._isInteractiveList = !!(navList || (list && list._getListType() === 'action-list'));
159190
this._list = navList || list;
@@ -165,12 +196,26 @@ export class MatListItem extends _MatListItemMixinBase implements AfterContentIn
165196
if (element.nodeName.toLowerCase() === 'button' && !element.hasAttribute('type')) {
166197
element.setAttribute('type', 'button');
167198
}
199+
200+
// @breaking-change 8.0.0 Remove null check for _changeDetectorRef.
201+
if (this._list && _changeDetectorRef) {
202+
// React to changes in the state of the parent list since
203+
// some of the item's properties depend on it (e.g. `disableRipple`).
204+
this._list._stateChanges.pipe(takeUntil(this._destroyed)).subscribe(() => {
205+
_changeDetectorRef.markForCheck();
206+
});
207+
}
168208
}
169209

170210
ngAfterContentInit() {
171211
setLines(this._lines, this._element);
172212
}
173213

214+
ngOnDestroy() {
215+
this._destroyed.next();
216+
this._destroyed.complete();
217+
}
218+
174219
/** Whether this list item should show a ripple effect when clicked. */
175220
_isRippleDisabled() {
176221
return !this._isInteractiveList || this.disableRipple ||

src/lib/list/selection-list.spec.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -982,6 +982,21 @@ describe('MatSelectionList with forms', () => {
982982
.toBe(true, 'Expected every list option to be unselected.');
983983
});
984984

985+
it('should deselect option whose value no longer matches', () => {
986+
const option = listOptions[1];
987+
988+
fixture.componentInstance.formControl.setValue(['opt2']);
989+
fixture.detectChanges();
990+
991+
expect(option.selected).toBe(true, 'Expected option to be selected.');
992+
993+
option.value = 'something-different';
994+
fixture.detectChanges();
995+
996+
expect(option.selected).toBe(false, 'Expected option not to be selected.');
997+
expect(fixture.componentInstance.formControl.value).toEqual([]);
998+
});
999+
9851000
it('should mark options as selected when the value is set before they are initialized', () => {
9861001
fixture.destroy();
9871002
fixture = TestBed.createComponent(SelectionListWithFormControl);

src/lib/list/selection-list.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,16 @@ export class MatListOption extends _MatListOptionMixinBase
120120
@Input() checkboxPosition: 'before' | 'after' = 'after';
121121

122122
/** Value of the option */
123-
@Input() value: any;
123+
@Input()
124+
get value(): any { return this._value; }
125+
set value(newValue: any) {
126+
if (this.selected && newValue !== this.value) {
127+
this.selected = false;
128+
}
129+
130+
this._value = newValue;
131+
}
132+
private _value: any;
124133

125134
/** Whether the option is disabled. */
126135
@Input()
@@ -272,7 +281,7 @@ export class MatListOption extends _MatListOptionMixinBase
272281
moduleId: module.id,
273282
selector: 'mat-selection-list',
274283
exportAs: 'matSelectionList',
275-
inputs: ['disabled', 'disableRipple', 'tabIndex'],
284+
inputs: ['disableRipple'],
276285
host: {
277286
'role': 'listbox',
278287
'[tabIndex]': 'tabIndex',

src/lib/stepper/stepper.scss

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,7 @@ $mat-stepper-line-gap: 8px !default;
9292
display: none;
9393
}
9494

95-
& .mat-step-icon,
96-
& .mat-step-icon-not-touched {
95+
& .mat-step-icon {
9796
// Cleans margin both for ltr and rtl direction
9897
margin-right: 0;
9998
margin-left: 0;

src/lib/tabs/tab-header.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,10 @@ export class MatTabHeader extends _MatTabHeaderMixinBase
133133
private _selectedIndex: number = 0;
134134

135135
/** Event emitted when the option is selected. */
136-
@Output() readonly selectFocusedIndex = new EventEmitter();
136+
@Output() readonly selectFocusedIndex: EventEmitter<number> = new EventEmitter<number>();
137137

138138
/** Event emitted when a label is focused. */
139-
@Output() readonly indexFocused = new EventEmitter();
139+
@Output() readonly indexFocused: EventEmitter<number> = new EventEmitter<number>();
140140

141141
constructor(private _elementRef: ElementRef,
142142
private _changeDetectorRef: ChangeDetectorRef,

0 commit comments

Comments
 (0)