Skip to content
This repository was archived by the owner on May 20, 2023. It is now read-only.

Commit 6efe993

Browse files
authored
Components update (#96)
* Material Progress: Cleanup animations on destroy to prevent memory leaks. * Material Select: * Support deselect item in Material dropdown select with single selection model. * Unified template files (deleted material_select_dropdown_item.html). * Add support for `Selectable` `SelectionOptions`. * Create a `ControlValueAccessor`. * Add backspace and delete keys to `KeyboardHandlerMixin`. * Add `selectedValue` getter to `RadioGroupSingleSelectionModel`. * Add null check to `ObservableComposite`'s `register` method. * Add `totalEntitiesCountChange` getter to table selection models. * Add `isStandardMouseEvent` utility to test for clicks without modifier keys. * Add string selection sanitizing options. * Remove `NoopStream` in favor of `Stream.empty()` as provided by the SDK. * Migrate use of LazyEventController to StreamController. * Fix bug in lazy group creation that would cause multiple groups to be created. * Strong mode fixes.
1 parent 4518e63 commit 6efe993

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+372
-385
lines changed

CHANGELOG.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,24 @@
1+
## 0.5.2
2+
3+
* Material Progress: Cleanup animations on destroy to prevent memory leaks.
4+
* Material Select:
5+
* Support deselect item in Material dropdown select with single selection
6+
model.
7+
* Unified template files (deleted material_select_dropdown_item.html).
8+
* Add support for `Selectable` `SelectionOptions`.
9+
* Create a `ControlValueAccessor`.
10+
* Add backspace and delete keys to `KeyboardHandlerMixin`.
11+
* Add `selectedValue` getter to `RadioGroupSingleSelectionModel`.
12+
* Add null check to `ObservableComposite`'s `register` method.
13+
* Add `totalEntitiesCountChange` getter to table selection models.
14+
* Add `isStandardMouseEvent` utility to test for clicks without modifier keys.
15+
* Add string selection sanitizing options.
16+
* Remove `NoopStream` in favor of `Stream.empty()` as provided by the SDK.
17+
* Migrate use of LazyEventController to StreamController.
18+
* Fix bug in lazy group creation that would cause multiple groups to be
19+
created.
20+
* Strong mode fixes.
21+
122
## 0.5.1
223

324
* Glyph: Add baseline attribute.

lib/src/all_components.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export 'components/material_chips/material_chip.dart';
2626
export 'components/material_chips/material_chips.dart';
2727
export 'components/material_dialog/material_dialog.dart';
2828
export 'components/material_expansionpanel/material_expansionpanel.dart';
29+
export 'components/material_expansionpanel/material_expansionpanel_auto_dismiss.dart';
2930
export 'components/material_expansionpanel/material_expansionpanel_set.dart';
3031
export 'components/material_input/base_material_input.dart';
3132
export 'components/material_input/deferred_validator.dart';

lib/src/components/material_button/material_button.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
import 'package:angular2/angular2.dart';
6-
76
import '../button_decorator/button_decorator.dart';
87
import '../material_ripple/material_ripple.dart';
98
import '../theme/dark_theme.dart';
9+
1010
import 'material_button_base.dart';
1111

1212
/// Material button is a button.

lib/src/components/material_button/material_fab.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
import 'package:angular2/angular2.dart';
6-
76
import '../material_ripple/material_ripple.dart';
7+
88
import 'material_button_base.dart';
99

1010
/// Material FAB is a Floating Action Button. It is round, and behaves mostly

lib/src/components/material_chips/material_chip.scss.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/src/components/material_expansionpanel/material_expansionpanel.dart

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import 'package:intl/intl.dart';
1010
import '../../model/action/async_action.dart';
1111
import '../../utils/angular/managed_zone/angular_2.dart';
1212
import '../../utils/angular/properties/properties.dart';
13-
import '../../utils/async/async.dart';
1413
import '../../utils/browser/dom_service/dom_service.dart';
1514
import '../../utils/disposer/disposer.dart';
1615
import '../button_decorator/button_decorator.dart';
@@ -159,13 +158,17 @@ class MaterialExpansionPanel
159158
}
160159

161160
@Output('expandedChange')
162-
final isExpandedChange = new LazyEventEmitter<bool>.broadcast();
161+
Stream<bool> get isExpandedChange => _isExpandedChange.stream;
162+
final _isExpandedChange = new StreamController<bool>.broadcast(sync: true);
163163

164164
@Output('expandedChangeByUser')
165-
final isExpandedChangeByUserAction = new LazyEventEmitter<bool>.broadcast();
165+
Stream<bool> get isExpandedChangeByUserAction =>
166+
_isExpandedChangeByUserAction.stream;
167+
final _isExpandedChangeByUserAction =
168+
new StreamController<bool>.broadcast(sync: true);
166169

167170
@override
168-
LazyEventEmitter<bool> get contentVisible => isExpandedChange;
171+
Stream<bool> get contentVisible => isExpandedChange;
169172

170173
/// Whether a different panel in the set is currently expanded.
171174
///
@@ -379,8 +382,8 @@ class MaterialExpansionPanel
379382
actionCtrl.execute(() {
380383
if (closeOnSave) {
381384
_isExpanded = false;
382-
isExpandedChange.add(false);
383-
isExpandedChangeByUserAction.add(false);
385+
_isExpandedChange.add(false);
386+
_isExpandedChangeByUserAction.add(false);
384387
_changeDetector.markForCheck();
385388
}
386389
return true;
@@ -399,8 +402,8 @@ class MaterialExpansionPanel
399402
_changeDetector.markForCheck();
400403
actionCtrl.execute(() {
401404
_isExpanded = false;
402-
isExpandedChange.add(false);
403-
isExpandedChangeByUserAction.add(false);
405+
_isExpandedChange.add(false);
406+
_isExpandedChangeByUserAction.add(false);
404407
_changeDetector.markForCheck();
405408
return true;
406409
}, valueOnCancel: false);
@@ -424,8 +427,8 @@ class MaterialExpansionPanel
424427
stream.add(actionCtrl.action);
425428
actionCtrl.execute(() {
426429
_isExpanded = expand;
427-
isExpandedChange.add(expand);
428-
if (byUserAction) isExpandedChangeByUserAction.add(expand);
430+
_isExpandedChange.add(expand);
431+
if (byUserAction) _isExpandedChangeByUserAction.add(expand);
429432
_changeDetector.markForCheck();
430433
if (expand && autoFocusChild != null) {
431434
_domService.scheduleWrite(() {

lib/src/components/material_expansionpanel/src/material_expansionpanel_auto_dismiss.dart renamed to lib/src/components/material_expansionpanel/material_expansionpanel_auto_dismiss.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import 'dart:html';
77

88
import 'package:angular2/angular2.dart';
99

10-
import '../../../laminate/overlay/module.dart' show overlayContainerToken;
11-
import '../material_expansionpanel.dart';
10+
import '../../laminate/overlay/module.dart' show overlayContainerToken;
11+
import './material_expansionpanel.dart';
1212

1313
/// A directive that automatically collapses [MaterialExpansionPanel].
1414
///

lib/src/components/material_progress/material_progress.dart

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ const Map<String, double> _indeterminateTiming = const {
3131
templateUrl: 'material_progress.html',
3232
styleUrls: const ['material_progress.scss.css'],
3333
changeDetection: ChangeDetectionStrategy.OnPush)
34-
class MaterialProgressComponent implements AfterViewInit {
34+
class MaterialProgressComponent implements AfterViewInit, OnDestroy {
3535
final HtmlElement _element;
3636

3737
/// The current progress value.
@@ -106,6 +106,16 @@ class MaterialProgressComponent implements AfterViewInit {
106106
if (indeterminate) _tryFancyAnimation();
107107
}
108108

109+
@override
110+
void ngOnDestroy() {
111+
_primaryAnimation?.cancel();
112+
_secondaryAnimation?.cancel();
113+
_primaryAnimation = null;
114+
_secondaryAnimation = null;
115+
_primaryIndicator = null;
116+
_secondaryIndicator = null;
117+
}
118+
109119
/// Sets up the "indeterminate" animation using the animation API.
110120
void _tryFancyAnimation() {
111121
// Only set this up if we support the animation API and if the component's

lib/src/components/material_select/material_dropdown_select.dart

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import '../../model/selection/selection_model.dart';
1717
import '../../model/selection/selection_options.dart';
1818
import '../../model/ui/has_renderer.dart';
1919
import '../../model/ui/template_support.dart';
20-
import '../../utils/async/async.dart';
2120
import '../../utils/id_generator/id_generator.dart';
2221
import '../annotations/rtl_annotation.dart';
2322
import '../content/deferred_content.dart';
@@ -90,6 +89,8 @@ import './shift_click_selection.dart';
9089
/// as wide as the select width.
9190
/// - `slide: String` -- Direction of popup scaling. Valid values are `x`, `y`,
9291
/// or `null`.
92+
/// - `deselectLabel: String` -- Text label for select item that deselects
93+
/// the current selection.
9394
@Component(
9495
selector: 'material-dropdown-select',
9596
inputs: const [
@@ -168,6 +169,10 @@ class MaterialDropdownSelectComponent extends MaterialSelectBase
168169
/// instead of the implementation of this class.
169170
final PopupSizeProvider _popupSizeDelegate;
170171

172+
/// Text label for select item that deselects the current selection.
173+
@Input()
174+
String deselectLabel;
175+
171176
MaterialDropdownSelectComponent(
172177
@Optional() IdGenerator idGenerator,
173178
@Optional() @SkipSelf() this._popupSizeDelegate,
@@ -188,28 +193,32 @@ class MaterialDropdownSelectComponent extends MaterialSelectBase
188193
set options(SelectionOptions newOptions) {
189194
super.options = newOptions;
190195

191-
activeModel.items = options?.optionsList ?? [];
196+
_updateActiveModel();
192197
_setInitialActiveItem();
193198

194199
_optionsListener?.cancel();
195200
_optionsListener = options?.stream?.listen((_) {
196-
activeModel.items = options.optionsList;
201+
_updateActiveModel();
197202
_setInitialActiveItem();
198203
});
199204
}
200205

201206
@Output()
202-
LazyEventEmitter<FocusEvent> focus = new LazyEventEmitter<FocusEvent>();
207+
Stream<FocusEvent> get focus => _focus.stream;
208+
StreamController<FocusEvent> _focus =
209+
new StreamController<FocusEvent>.broadcast(sync: true);
203210

204211
@Output()
205-
LazyEventEmitter<FocusEvent> blur = new LazyEventEmitter<FocusEvent>();
212+
Stream<FocusEvent> get blur => _blur.stream;
213+
StreamController<FocusEvent> _blur =
214+
new StreamController<FocusEvent>.broadcast(sync: true);
206215

207216
void onFocus(FocusEvent event) {
208-
focus.add(event);
217+
_focus.add(event);
209218
}
210219

211220
void onBlur(FocusEvent event) {
212-
blur.add(event);
221+
_blur.add(event);
213222
}
214223

215224
@override
@@ -228,6 +237,14 @@ class MaterialDropdownSelectComponent extends MaterialSelectBase
228237
});
229238
}
230239

240+
void _updateActiveModel() {
241+
var items = options?.optionsList?.toList() ?? [];
242+
if (showDeselectItem) {
243+
items.insert(0, deselectLabel);
244+
}
245+
activeModel.items = items;
246+
}
247+
231248
void _setInitialActiveItem() {
232249
if (selection == null || selection.selectedValues.isEmpty) {
233250
activeModel.activate(null);
@@ -289,7 +306,9 @@ class MaterialDropdownSelectComponent extends MaterialSelectBase
289306
} else {
290307
var item = activeModel.activeItem;
291308
if (item != null && selection != null) {
292-
if (selection.isSelected(item)) {
309+
if (item == deselectLabel) {
310+
deselectCurrentSelection();
311+
} else if (selection.isSelected(item)) {
293312
selection.deselect(item);
294313
} else {
295314
selection.select(item);
@@ -372,6 +391,18 @@ class MaterialDropdownSelectComponent extends MaterialSelectBase
372391
}
373392
return false;
374393
}
394+
395+
/// Whether to show select item that deselects the current selection.
396+
bool get showDeselectItem =>
397+
!isMultiSelect && deselectLabel?.isNotEmpty == true;
398+
399+
bool get isDeselectItemSelected => selection.isEmpty;
400+
401+
void deselectCurrentSelection() {
402+
if (selection.isNotEmpty) {
403+
selection.deselect(selection.selectedValues.single);
404+
}
405+
}
375406
}
376407

377408
// TODO(google): Move it to a common home to increase reusability.

lib/src/components/material_select/material_dropdown_select.html

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,17 @@
1818
(trigger)="handleClick($event)"
1919
popupSource
2020
#source="popupSource">
21-
<ng-content select="[buttonContent]"></ng-content>
21+
<ng-content select="[buttonContent]"></ng-content>
2222
</dropdown-button>
2323
<material-popup enforceSpaceConstraints
24-
[preferredPositions]="preferredPositions"
25-
[matchMinSourceWidth]="popupMatchInputWidth"
26-
[slide]="slide"
27-
[source]="source"
28-
[autoDismiss]="autoDismiss"
29-
[trackLayoutChanges]="trackLayoutChanges"
30-
[visible]="visible"
31-
(visibleChange)="onVisible($event)">
24+
[preferredPositions]="preferredPositions"
25+
[matchMinSourceWidth]="popupMatchInputWidth"
26+
[slide]="slide"
27+
[source]="source"
28+
[autoDismiss]="autoDismiss"
29+
[trackLayoutChanges]="trackLayoutChanges"
30+
[visible]="visible"
31+
(visibleChange)="onVisible($event)">
3232
<div header
3333
(keydown)="onKeyDown($event)"
3434
(keypress)="onKeyPress($event)"
@@ -46,21 +46,33 @@
4646
(mouseout)="activeModel.activate(null)">
4747
<ng-content></ng-content>
4848
<div class="options-wrapper" *ngIf="options != null">
49-
<div *ngFor="let group of options.optionGroups trackBy trackByIndexFn" group
50-
[class.empty]="group.isEmpty && !group.hasEmptyLabel">
49+
<material-select-dropdown-item
50+
*ngIf="showDeselectItem"
51+
[class.empty]="options.optionGroups.length == 1"
52+
keyboardOnlyFocusIndicator
53+
[selected]="isDeselectItemSelected"
54+
[value]="deselectLabel"
55+
(trigger)="deselectCurrentSelection()"
56+
[active]="activeModel.isActive(deselectLabel)"
57+
[attr.id]="activeModel.id(deselectLabel)"
58+
(mouseenter)="activeModel.activate(deselectLabel)">
59+
</material-select-dropdown-item>
60+
<div *ngFor="let group of options.optionGroups trackBy trackByIndexFn"
61+
group
62+
[class.empty]="group.isEmpty && !group.hasEmptyLabel">
5163
<template [ngIf]="group.isNotEmpty || group.hasEmptyLabel">
5264
<span *ngIf="group.hasLabel" label>{{group.uiDisplayName}}</span>
5365
<template [ngIf]="group.isNotEmpty">
5466
<material-select-dropdown-item *ngFor="let item of group"
55-
keyboardOnlyFocusIndicator
56-
[itemRenderer]="itemRenderer"
57-
[componentRenderer]="componentRenderer"
58-
[selection]="selection"
59-
[disabled]="isOptionDisabled(item)"
60-
[value]="item"
61-
[active]="activeModel.isActive(item)"
62-
[attr.id]="activeModel.id(item)"
63-
(mouseenter)="activeModel.activate(item)">
67+
keyboardOnlyFocusIndicator
68+
[itemRenderer]="itemRenderer"
69+
[componentRenderer]="componentRenderer"
70+
[selection]="selection"
71+
[disabled]="isOptionDisabled(item)"
72+
[value]="item"
73+
[active]="activeModel.isActive(item)"
74+
[attr.id]="activeModel.id(item)"
75+
(mouseenter)="activeModel.activate(item)">
6476
</material-select-dropdown-item>
6577
</template>
6678
<material-select-dropdown-item

0 commit comments

Comments
 (0)