From 66a54318241d4a0e52aaf95166054163ac41941e Mon Sep 17 00:00:00 2001 From: srawlins Date: Thu, 13 Dec 2018 21:39:15 -0800 Subject: [PATCH 001/503] Automated g4 rollback of changelist 225276100. *** Reason for rollback *** Breaks code that does not exercise MaterialDropdownSelectComponent's itemRenderer. *** Original change description *** Fix the type of MaterialDropdownSelectComponent's itemRenderer. *** PiperOrigin-RevId: 225486540 --- .../material_time_picker.dart | 7 ++----- .../material_dropdown_select.dart | 17 ++++++++++++++--- .../lib/builder/template/main.dart.mustache | 2 +- .../gallery_component/gallery_component.dart | 11 ----------- 4 files changed, 17 insertions(+), 20 deletions(-) diff --git a/angular_components/lib/material_datepicker/material_time_picker.dart b/angular_components/lib/material_datepicker/material_time_picker.dart index 88bad41f6..9e5aab90f 100644 --- a/angular_components/lib/material_datepicker/material_time_picker.dart +++ b/angular_components/lib/material_datepicker/material_time_picker.dart @@ -27,9 +27,6 @@ import 'package:angular_components/utils/disposer/disposer.dart'; materialInputDirectives, NgStyle, ], - directiveTypes: [ - Typed>(), - ], providers: [ Provider(HasDisabled, useExisting: MaterialTimePickerComponent), ], @@ -356,7 +353,7 @@ class MaterialTimePickerComponent extends KeyboardHandlerMixin /// /// Only options between [minTime] and [maxTime] are selectable. class TimeSelectionOptions extends StringSelectionOptions - implements Selectable { + implements Selectable { DateTime _minTime; DateTime _maxTime; @@ -366,7 +363,7 @@ class TimeSelectionOptions extends StringSelectionOptions set maxTime(DateTime time) => _maxTime = time; @override - SelectableOption getSelectable(DateTime item) { + SelectableOption getSelectable(item) { return item is DateTime && ((_minTime != null && item.isBefore(_minTime)) || (_maxTime != null && item.isAfter(_maxTime))) diff --git a/angular_components/lib/material_select/material_dropdown_select.dart b/angular_components/lib/material_select/material_dropdown_select.dart index 3bdc3ef4c..0d1871a92 100644 --- a/angular_components/lib/material_select/material_dropdown_select.dart +++ b/angular_components/lib/material_select/material_dropdown_select.dart @@ -232,10 +232,22 @@ class MaterialDropdownSelectComponent extends MaterialSelectBase } /// Function to convert an option object to string. + /// + // TODO(google): Fix this now that generics are supported. + // Ideally, [value] would be a [ItemRenderer], where T is also the type + // parameter of the SelectionOptions and the SelectionModel, as parent + // components typically use a function that accepts a specific type (T). + // + // However, we don't have a T. Angular doesn't support injecting a + // type-annotated component yet, and setters, like [itemRenderer], cannot + // be type-annotated. This forces us to accept a plain old [Function] as + // [value], in order to avoid uses_dynamic_as_bottom errors. (Basically, a + // function like [MaterialTimePicker]'s `String renderTime(DateTime time)` + // cannot work as a [ItemRenderer], since it expects DateTime, not dynamic.) @Input() @override - set itemRenderer(ItemRenderer value) { - super.itemRenderer = value; + set itemRenderer(Function value) { + super.itemRenderer = (item) => value(item); } /// Width of the dropdown/list, default none, valid values are 0-5. @@ -256,7 +268,6 @@ class MaterialDropdownSelectComponent extends MaterialSelectBase // Note we don't allow deactivation because some teams incorrectly use // activeItemLabel instead of selectedItemLabel, and this breaks them. // TODO(google): remove allowDeactivate when client tests are fixed. - // https://test.corp.google.com/ui#id=OCL:219567674:BASE:219582901:1541045481973:dd9a971c _setInitialActiveItem(allowDeactivate: false); } } diff --git a/angular_gallery/lib/builder/template/main.dart.mustache b/angular_gallery/lib/builder/template/main.dart.mustache index 1a07315da..77075127d 100644 --- a/angular_gallery/lib/builder/template/main.dart.mustache +++ b/angular_gallery/lib/builder/template/main.dart.mustache @@ -10,7 +10,7 @@ import '{{{ galleryImportUri }}}' as app; import 'main.template.dart' as ng; -Logger _logger = Logger("ads.acx2.demo"); +Logger _logger = Logger("angular_dart_gallery"); void main() { Logger.root.onRecord.listen((x) => print("${x.level}: ${x.message}")); diff --git a/angular_gallery_section/lib/components/gallery_component/gallery_component.dart b/angular_gallery_section/lib/components/gallery_component/gallery_component.dart index 3d6eab334..855d892d0 100644 --- a/angular_gallery_section/lib/components/gallery_component/gallery_component.dart +++ b/angular_gallery_section/lib/components/gallery_component/gallery_component.dart @@ -58,17 +58,6 @@ class GalleryComponent { String getTeamsLink(String ldap) => 'http://who/$ldap'; - String getBuganizerLink(Doc doc) { - var params = []; - if (doc.path.startsWith('ads/acx2') || - doc.path.startsWith('third_party/dart_src/acx')) { - params.add('component=105665'); - params.add('template=38109'); - } - params.add('title=${doc.name} bug:'); - return 'http://b/issues/new?' + params.join('&'); - } - /// Reformats a library path name to a link path that can be used by /// CodeSearch. String getCodeSearchLink(String componentPath) { From 92179294396687e33226b2082be8f75eca051437 Mon Sep 17 00:00:00 2001 From: cissyshi Date: Thu, 13 Dec 2018 23:12:18 -0800 Subject: [PATCH 002/503] Do not create new SafeHtml in each change detection cycle in gallery component. PiperOrigin-RevId: 225493032 --- .../gallery_component/gallery_component.dart | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/angular_gallery_section/lib/components/gallery_component/gallery_component.dart b/angular_gallery_section/lib/components/gallery_component/gallery_component.dart index 855d892d0..ab2a86d91 100644 --- a/angular_gallery_section/lib/components/gallery_component/gallery_component.dart +++ b/angular_gallery_section/lib/components/gallery_component/gallery_component.dart @@ -37,6 +37,8 @@ class GalleryComponent { DomSanitizationService _santizationService; + final _sanitizedHtml = {}; + /// Used to disable latency charts in testing environments where they can't /// load successfully. final latencyChartsEnabled = @@ -47,8 +49,14 @@ class GalleryComponent { bool get showToc => (model.docs.length + model.demos.length + model.benchmarks.length) > 1; - SafeHtml getSafeHtml(String value) => - _santizationService.bypassSecurityTrustHtml(value); + SafeHtml getSafeHtml(String value) { + var html = _sanitizedHtml[value]; + if (html == null) { + html = _santizationService.bypassSecurityTrustHtml(value); + _sanitizedHtml[value] = html; + } + return html; + } String getDocId(Doc doc) => '${doc.name}Doc'; From b4438474bcbfa5487a98d77afdbbc4716330e537 Mon Sep 17 00:00:00 2001 From: tsander Date: Fri, 14 Dec 2018 10:00:19 -0800 Subject: [PATCH 003/503] Add home/end key modifiers to focus_list to focus the first or last value. PiperOrigin-RevId: 225558808 --- angular_components/lib/focus/focus.dart | 41 +++++++++++++++++--- angular_components/lib/focus/focus_list.dart | 12 ++++-- 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/angular_components/lib/focus/focus.dart b/angular_components/lib/focus/focus.dart index beb1b4de8..b43b02e18 100644 --- a/angular_components/lib/focus/focus.dart +++ b/angular_components/lib/focus/focus.dart @@ -6,6 +6,7 @@ import 'dart:async'; import 'dart:html' show KeyCode, KeyboardEvent, Element, HtmlElement; import 'package:angular/angular.dart'; +import 'package:meta/meta.dart'; import 'package:angular_components/laminate/components/modal/modal.dart'; import 'package:angular_components/laminate/popup/popup.dart'; import 'package:angular_components/utils/browser/dom_service/dom_service.dart'; @@ -85,6 +86,12 @@ class FocusMoveEvent { /// The position, relative the item, of where to set focus. final int offset; + /// Home key was pressed. + final bool home; + + /// End key was pressed. + final bool end; + /// Prevent Default action for occuring. When the `FocusMoveEvent` is created /// from a KeyboardEvent, this method delegates to the `preventDefault` method /// of the `KeyboardEvent`, allowing consumers of this event to control the @@ -95,18 +102,40 @@ class FocusMoveEvent { final Function _preventDefaultDelegate; - FocusMoveEvent(this.focusItem, this.offset, [this._preventDefaultDelegate]); + @visibleForTesting + FocusMoveEvent(this.focusItem, this.offset, [this._preventDefaultDelegate]) + : home = false, + end = false; + + @visibleForTesting + FocusMoveEvent.homeKey(this.focusItem, [this._preventDefaultDelegate]) + : offset = 0, + home = true, + end = false; + + @visibleForTesting + FocusMoveEvent.endKey(this.focusItem, [this._preventDefaultDelegate]) + : offset = 0, + home = false, + end = true; /// Builds a `FocusMoveEvent` instance from a keyboard event, iff the keycode - /// is a next or previous key (i.e. up/down/left/right). + /// is a next, previous, home or end key (i.e. up/down/left/right/home/end). factory FocusMoveEvent.fromKeyboardEvent( FocusableItem item, KeyboardEvent kbEvent) { int keyCode = kbEvent.keyCode; + final preventDefaultFn = () { + kbEvent.preventDefault(); + }; + if (_isHomeKey(keyCode)) { + return FocusMoveEvent.homeKey(item, preventDefaultFn); + } + if (_isEndKey(keyCode)) { + return FocusMoveEvent.endKey(item, preventDefaultFn); + } if (!_isNextKey(keyCode) && !_isPrevKey(keyCode)) return null; int offset = _isNextKey(keyCode) ? 1 : -1; - return FocusMoveEvent(item, offset, () { - kbEvent.preventDefault(); - }); + return FocusMoveEvent(item, offset, preventDefaultFn); } // TODO(google): account for RTL. @@ -114,6 +143,8 @@ class FocusMoveEvent { keyCode == KeyCode.RIGHT || keyCode == KeyCode.DOWN; static bool _isPrevKey(int keyCode) => keyCode == KeyCode.LEFT || keyCode == KeyCode.UP; + static bool _isHomeKey(int keyCode) => keyCode == KeyCode.HOME; + static bool _isEndKey(int keyCode) => keyCode == KeyCode.END; } /// The element will be focused as soon as directive is initialized. diff --git a/angular_components/lib/focus/focus_list.dart b/angular_components/lib/focus/focus_list.dart index 563a3c9e3..5d55a0e64 100644 --- a/angular_components/lib/focus/focus_list.dart +++ b/angular_components/lib/focus/focus_list.dart @@ -62,9 +62,15 @@ class FocusListDirective implements OnDestroy { } void _moveFocus(FocusMoveEvent event) { - var i = _children.indexOf(event.focusItem); - if (i != -1) { - focus(i + event.offset); + if (event.home) { + focus(0); + } else if (event.end) { + focus(_length - 1); + } else { + var i = _children.indexOf(event.focusItem); + if (i != -1) { + focus(i + event.offset); + } } event.preventDefault(); } From 0743abaf3c10f412f6fca1bb54b3bbca612990a0 Mon Sep 17 00:00:00 2001 From: tsander Date: Fri, 14 Dec 2018 15:13:54 -0800 Subject: [PATCH 004/503] Passthrough initPopupAriaAttributes to all the tooltip variations so teams can choose to drop those attributes for certain instances if they would like. PiperOrigin-RevId: 225612074 --- .../lib/src/material_tooltip/tooltip.dart | 6 +++-- .../src/material_tooltip/tooltip_source.dart | 6 +++-- .../src/material_tooltip/tooltip_target.dart | 24 +++++++++++-------- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/angular_components/lib/src/material_tooltip/tooltip.dart b/angular_components/lib/src/material_tooltip/tooltip.dart index fbd38acb5..f19791cad 100644 --- a/angular_components/lib/src/material_tooltip/tooltip.dart +++ b/angular_components/lib/src/material_tooltip/tooltip.dart @@ -50,9 +50,11 @@ class MaterialTooltipDirective extends TooltipTarget HtmlElement element, this._viewLoader, this._changeDetector, - this._window) + this._window, + @Attribute('initPopupAriaAttributes') String initAriaAttributes) : this.element = element, - super(domPopupSourceFactory, viewContainerRef, element) { + super(domPopupSourceFactory, viewContainerRef, element, + initAriaAttributes) { inLongPress = false; _delayedActivate = DelayedAction(tooltipShowDelay, _activate); } diff --git a/angular_components/lib/src/material_tooltip/tooltip_source.dart b/angular_components/lib/src/material_tooltip/tooltip_source.dart index 8c19cca57..4ea86623d 100644 --- a/angular_components/lib/src/material_tooltip/tooltip_source.dart +++ b/angular_components/lib/src/material_tooltip/tooltip_source.dart @@ -49,14 +49,16 @@ class MaterialTooltipSourceDirective extends PopupSourceDirective bool _isMouseInside = false; MaterialTooltipSourceDirective( - DomPopupSourceFactory domPopupSourceFactory, HtmlElement element) + DomPopupSourceFactory domPopupSourceFactory, + HtmlElement element, + @Attribute('initPopupAriaAttributes') String initAriaAttributes) : this.element = element, super( domPopupSourceFactory, element, /* referenceDirective */ null, /* focusable */ null, - /* initAriaAttributes */ null) { + initAriaAttributes) { _show = DelayedAction(tooltipShowDelay, activate); } diff --git a/angular_components/lib/src/material_tooltip/tooltip_target.dart b/angular_components/lib/src/material_tooltip/tooltip_target.dart index cdf422cd9..4b91f825c 100644 --- a/angular_components/lib/src/material_tooltip/tooltip_target.dart +++ b/angular_components/lib/src/material_tooltip/tooltip_target.dart @@ -34,9 +34,10 @@ class MaterialTooltipTargetDirective extends TooltipBehavior DomPopupSourceFactory domPopupSourceFactory, ViewContainerRef viewContainerRef, HtmlElement element, - ChangeDetectorRef changeDetector) - : super( - domPopupSourceFactory, viewContainerRef, element, changeDetector) { + ChangeDetectorRef changeDetector, + @Attribute('initPopupAriaAttributes') String initAriaAttributes) + : super(domPopupSourceFactory, viewContainerRef, element, changeDetector, + initAriaAttributes) { this.element = element; } @@ -71,8 +72,10 @@ abstract class TooltipBehavior extends TooltipTarget { DomPopupSourceFactory domPopupSourceFactory, ViewContainerRef viewContainerRef, HtmlElement element, - this._changeDetector) - : super(domPopupSourceFactory, viewContainerRef, element) { + this._changeDetector, + String initAriaAttributes) + : super(domPopupSourceFactory, viewContainerRef, element, + initAriaAttributes) { _show = DelayedAction(tooltipShowDelay, showTooltip); } @@ -147,9 +150,10 @@ class ClickableTooltipTargetDirective extends TooltipBehavior DomPopupSourceFactory domPopupSourceFactory, ViewContainerRef viewContainerRef, HtmlElement element, - ChangeDetectorRef changeDetector) - : super( - domPopupSourceFactory, viewContainerRef, element, changeDetector) { + ChangeDetectorRef changeDetector, + @Attribute('initPopupAriaAttributes') String initAriaAttributes) + : super(domPopupSourceFactory, viewContainerRef, element, changeDetector, + initAriaAttributes) { this.element = element; _tooltipSubscription = tooltipActivate.listen((visible) { _tooltipVisible = visible; @@ -209,13 +213,13 @@ abstract class TooltipTarget extends PopupSourceDirective { final HtmlElement _element; TooltipTarget(DomPopupSourceFactory domPopupSourceFactory, - this.viewContainerRef, this._element) + this.viewContainerRef, this._element, String initAriaAttributes) : super( domPopupSourceFactory, _element, /* referenceDirective */ null, /* focusable */ null, - /* initAriaAttributes */ null); + initAriaAttributes); /// Sets the tooltip associated with this target. void setTooltip(Tooltip component) { From 7e6d68b97c25159d7b50d2f280584edda18175d2 Mon Sep 17 00:00:00 2001 From: Googler Date: Mon, 17 Dec 2018 06:45:55 -0800 Subject: [PATCH 005/503] Make material-icon using SVG correctly stretch icon. PiperOrigin-RevId: 225818293 --- angular_components/lib/material_icon/_mixins.scss | 1 + examples/material_icon_example/lib/material_icon_demo.html | 1 + 2 files changed, 2 insertions(+) diff --git a/angular_components/lib/material_icon/_mixins.scss b/angular_components/lib/material_icon/_mixins.scss index c1da4dac3..fd078c470 100644 --- a/angular_components/lib/material_icon/_mixins.scss +++ b/angular_components/lib/material_icon/_mixins.scss @@ -49,5 +49,6 @@ @mixin svg-icon($svg-icon) { ::ng-deep .material-icon-i { background-image: $svg-icon; + background-size: cover; } } diff --git a/examples/material_icon_example/lib/material_icon_demo.html b/examples/material_icon_example/lib/material_icon_demo.html index e973fb662..fadb7001f 100644 --- a/examples/material_icon_example/lib/material_icon_demo.html +++ b/examples/material_icon_example/lib/material_icon_demo.html @@ -89,6 +89,7 @@

SVG Icon

Note: This requires setting the "icon" to the material-icon as blank so that it is not shown.

+
From c5ba91c0a76a87cd0e73852db841f63fced6c0cf Mon Sep 17 00:00:00 2001 From: cissyshi Date: Mon, 17 Dec 2018 13:36:49 -0800 Subject: [PATCH 006/503] Fix gallery title not updating. PiperOrigin-RevId: 225880739 --- angular_gallery/lib/builder/template/gallery.dart.mustache | 4 +++- angular_gallery/lib/builder/template/gallery.scss.mustache | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/angular_gallery/lib/builder/template/gallery.dart.mustache b/angular_gallery/lib/builder/template/gallery.dart.mustache index d73aca18b..4e5763d46 100644 --- a/angular_gallery/lib/builder/template/gallery.dart.mustache +++ b/angular_gallery/lib/builder/template/gallery.dart.mustache @@ -67,7 +67,9 @@ class GalleryComponent implements HighlightProvider { GalleryComponent(this.focusIndicatorController, Router router) { router.stream.listen((newRoute) { - _breadcrumb = breadcrumbs[newRoute.path]; + var example = newRoute.path; + if (example.startsWith('/')) example = example.substring(1); + _breadcrumb = breadcrumbs[example]; querySelector('material-content').scrollTop = 0; }); exampleOptions = StringSelectionOptions<_Example>(allExamples, diff --git a/angular_gallery/lib/builder/template/gallery.scss.mustache b/angular_gallery/lib/builder/template/gallery.scss.mustache index 3a8ed4f9a..8d162b24a 100644 --- a/angular_gallery/lib/builder/template/gallery.scss.mustache +++ b/angular_gallery/lib/builder/template/gallery.scss.mustache @@ -70,4 +70,8 @@ material-content { @include material-checkbox-color($mat-orange-500); } + + .material-header-row { + flex-grow: 1; + } } From c741ef6bf0356fef919dd37d622964e4436c18df Mon Sep 17 00:00:00 2001 From: hcameron Date: Tue, 18 Dec 2018 12:42:20 -0800 Subject: [PATCH 007/503] `mat-gray` was provided as an alias for `mat-grey` but is being removed PiperOrigin-RevId: 226041951 --- angular_components/lib/material_chips/_mixins.scss | 6 +++--- .../lib/material_chips/material_chip.scss | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/angular_components/lib/material_chips/_mixins.scss b/angular_components/lib/material_chips/_mixins.scss index 5c91d64d9..ed3b5ecf7 100644 --- a/angular_components/lib/material_chips/_mixins.scss +++ b/angular_components/lib/material_chips/_mixins.scss @@ -100,8 +100,8 @@ $left-icon-width: $mat-grid * 4; } } -$main-hover-bg-color: $mat-gray-400; -$main-selected-bg-color: $mat-gray-600; +$main-hover-bg-color: $mat-grey-400; +$main-selected-bg-color: $mat-grey-600; $emphasis-hover-bg-color: $mat-blue-700; $emphasis-selected-bg-color: $mat-blue-900; @@ -182,7 +182,7 @@ $emphasis-selected-bg-color: $mat-blue-900; } ::ng-deep .delete-icon:focus { - fill: $mat-gray-300; + fill: $mat-grey-300; } } } diff --git a/angular_components/lib/material_chips/material_chip.scss b/angular_components/lib/material_chips/material_chip.scss index 0c690965c..9bd8ed54f 100644 --- a/angular_components/lib/material_chips/material_chip.scss +++ b/angular_components/lib/material_chips/material_chip.scss @@ -9,7 +9,7 @@ $mat-option-inline-icons: true; $chip-height: $mat-grid * 4; $chip-border-radius: $chip-height / 2; -$main-bg-color: $mat-gray-300; +$main-bg-color: $mat-grey-300; $emphasis-bg-color: $mat-blue-500; @@ -40,8 +40,8 @@ $delete-icon-padding: ($clickable-size - $delete-icon-size) / 2; .left-icon { // make it easy to use either or - color: $mat-gray-500; - fill: $mat-gray-500; + color: $mat-grey-500; + fill: $mat-grey-500; display: flex; align-items: center; @@ -65,7 +65,7 @@ $delete-icon-padding: ($clickable-size - $delete-icon-size) / 2; padding: $delete-icon-padding; width: $delete-icon-size; - fill: $mat-gray-500; + fill: $mat-grey-500; &:focus { fill: $mat-white; @@ -87,7 +87,7 @@ $delete-icon-padding: ($clickable-size - $delete-icon-size) / 2; fill: $mat-white; &:focus { - fill: $mat-gray-300; + fill: $mat-grey-300; } } } From b7d9746161000c4883615730e5f04b544778184b Mon Sep 17 00:00:00 2001 From: Googler Date: Tue, 18 Dec 2018 13:27:17 -0800 Subject: [PATCH 008/503] Modularize the bindings for dom service. PiperOrigin-RevId: 226049139 --- .../lib/utils/browser/dom_service/angular_2.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/angular_components/lib/utils/browser/dom_service/angular_2.dart b/angular_components/lib/utils/browser/dom_service/angular_2.dart index 0648a0bb6..6b975a43d 100644 --- a/angular_components/lib/utils/browser/dom_service/angular_2.dart +++ b/angular_components/lib/utils/browser/dom_service/angular_2.dart @@ -32,6 +32,9 @@ const domServiceBinding = FactoryProvider( ], ); +/// DI module for dom service. +const domServiceModule = Module(provide: [domServiceBinding]); + // Shared DomService resource. Currently there is only one per application. DomService _singletonService; From f342d149b8a411bfc7a994164592f4b2bef3e20d Mon Sep 17 00:00:00 2001 From: tsander Date: Tue, 18 Dec 2018 14:17:12 -0800 Subject: [PATCH 009/503] Remove aria label from the icon: a) It wasn't being used as the icon was aria-hidden b) It should be on the focusable element which is not the glyph for us. We use button-decorator or similar to enable. To support this in inputs we will have to enable this differently. PiperOrigin-RevId: 226057929 --- angular_components/lib/material_icon/material_icon.dart | 4 ---- angular_components/lib/material_icon/material_icon.html | 3 +-- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/angular_components/lib/material_icon/material_icon.dart b/angular_components/lib/material_icon/material_icon.dart index 9bac7a2cf..408c01e33 100644 --- a/angular_components/lib/material_icon/material_icon.dart +++ b/angular_components/lib/material_icon/material_icon.dart @@ -71,10 +71,6 @@ class MaterialIconComponent { } } - /// Aria label to add to the icon. - @Input() - String ariaLabel; - dynamic _icon; /// The icon identifier. diff --git a/angular_components/lib/material_icon/material_icon.html b/angular_components/lib/material_icon/material_icon.html index 32bd3aa5e..f6677462a 100644 --- a/angular_components/lib/material_icon/material_icon.html +++ b/angular_components/lib/material_icon/material_icon.html @@ -4,7 +4,6 @@ BSD-style license that can be found in the LICENSE file. --> From 888f812243bcb5cf8802ac52512da132892933bb Mon Sep 17 00:00:00 2001 From: cpelling Date: Tue, 18 Dec 2018 15:11:10 -0800 Subject: [PATCH 010/503] Mark globalDateRangeBindings deprecated. PiperOrigin-RevId: 226068156 --- angular_components/lib/material_datepicker/module.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/angular_components/lib/material_datepicker/module.dart b/angular_components/lib/material_datepicker/module.dart index a503f1dd1..a4b67c32a 100644 --- a/angular_components/lib/material_datepicker/module.dart +++ b/angular_components/lib/material_datepicker/module.dart @@ -69,6 +69,8 @@ const defaultDateComparison = OpaqueToken('defaultDateComparison'); /// ]; /// /// (where `last7Days` comes from this package's `range.dart` library). +@Deprecated('These bindings are not generally useful for most use cases and ' + 'thus do not belong in this general-purpose library. Will be removed soon.') const globalDateRangeBindings = [ Provider(DatepickerModel, useFactory: modelFactory), Provider(DatepickerSelection, useFactory: selectionFactory), From 105b5a8c877eb34ea13dce226ccf9e6238ab0b24 Mon Sep 17 00:00:00 2001 From: Googler Date: Tue, 18 Dec 2018 23:30:59 -0800 Subject: [PATCH 011/503] Clean up SimpleStream implementation. Found this file by accident, saw no reason to extend StreamView. The list-removal code seemed inefficient, as did creating a tear-off of Zone.run when you can just store the zone. PiperOrigin-RevId: 226122158 --- .../lib/src/utils/async/simple_stream.dart | 96 +++++++++---------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/angular_components/lib/src/utils/async/simple_stream.dart b/angular_components/lib/src/utils/async/simple_stream.dart index f2685fa82..680027cd1 100644 --- a/angular_components/lib/src/utils/async/simple_stream.dart +++ b/angular_components/lib/src/utils/async/simple_stream.dart @@ -8,34 +8,37 @@ typedef void StreamCallContextFunc(dynamic func()); typedef void StreamCallbackFunc(T value); typedef void SubscriptionChangeListener(StreamSubscription subscription); -/// A ListenOnly Implementation of a Stream. It only supports the listen +/// A ListenOnly Implementation of a [Stream]. It only supports the listen /// method with the onData parameter. Additionally, the streamsubscription can /// only be cancelled. -/// This also acts as a StreamController via the add method. +/// This also acts like a [StreamController] via the add method. /// -/// Usage: Stream stream = SimpleStream(); +/// Usage: +/// ``` +/// Stream stream = SimpleStream(); /// StreamSubscription sub = stream.listen((item) {print('$item')); /// stream.add('hi'); /// sub.cancel(); /// stream.add(hi); +/// ``` /// -/// This does not behave like an actual stream. A callback throwing an +/// This does not behave like an actual stream. A callback throwing an /// exception will cause other callbacks to not execute and the if the stream /// is synchronous, the error will propagate back to code adding the object /// to the stream. /// /// When a subscription is cancelled, it gets cleaned up and will not get /// called but will remain in the stream's list of subscriptions until the -/// the cleanup microtask executes. As such, calling hasListener on the +/// the cleanup microtask executes. As such, calling [hasListener] on the /// stream give the wrong result until the cleanup executes. Cleanups for all -/// SimpleStreams will occur in the same microtask. +/// [SimpleStreams] will occur in the same microtask. /// -class SimpleStream extends StreamView implements EventSink { +class SimpleStream extends Stream implements EventSink { /// Determines if the stream is synchronous or asynchronous. final bool _isSync; - /// Determines if the stream runs callbacks in the zone that the listeners - /// were registered in. If this is false, callbacks from SimpleStream might + /// The zone that the listeners were registered in. + /// If this is null, callbacks from SimpleStream might /// run outside of ng change detection. final bool _runInZone; @@ -53,7 +56,7 @@ class SimpleStream extends StreamView implements EventSink { /// smarter. If it is null, it means that the stream is closed. List> _subscriptions = const []; - /// List of items to send to avoid scheduling multiple micro tasks for each + /// List of items to send to avoid scheduling multiple microtasks for each /// item to be sent. List _itemsToSend; @@ -66,8 +69,7 @@ class SimpleStream extends StreamView implements EventSink { SimpleStream({bool isSync = false, bool runInZone = false}) : _isSync = isSync, - _runInZone = runInZone, - super(const Stream.empty()); + _runInZone = runInZone; SimpleStream.broadcast( {bool isSync = false, @@ -77,8 +79,7 @@ class SimpleStream extends StreamView implements EventSink { : _isSync = isSync, _runInZone = runInZone, _onListen = onListen, - _onCancel = onCancel, - super(const Stream.empty()); + _onCancel = onCancel; bool get isSync => _isSync; @@ -104,15 +105,11 @@ class SimpleStream extends StreamView implements EventSink { _sendItem(_subscriptions, item); } else { /// Only schedule a single micro-task for async streams. - bool schedule = false; if (_itemsToSend == null) { _itemsToSend = []; - schedule = true; - } - _itemsToSend.add(item); - if (schedule) { scheduleMicrotask(_sendAsync); } + _itemsToSend.add(item); } } @@ -131,19 +128,26 @@ class SimpleStream extends StreamView implements EventSink { // Loop over them all is faster than keeping track of a list and // looking up each one separately. List> listeners = _subscriptions; - SimpleStreamSubscription lastSubscription; - int i = listeners.length - 1; - while (i >= 0) { - var stream = listeners[i]._stream; - if (stream == null) { - lastSubscription = listeners.removeAt(i); + assert(listeners.isNotEmpty); + + for (var liveCount = 0; liveCount < listeners.length; liveCount++) { + var firstRemovedListener = listeners[liveCount]; + if (firstRemovedListener._stream != null) continue; + // At least one removed listener. Collect live listeners at beginning + // and truncate the list to only the live listeners. + for (var i = liveCount + 1; i < listeners.length; i++) { + var listener = listeners[i]; + if (listener._stream != null) { + listeners[liveCount++] = listener; + } } - i--; - } - // If there are no listeners left and onCancel is set, then call onCancel - // to indicate that the last subscription has been removed. - if (listeners.isEmpty && lastSubscription != null && _onCancel != null) { - _onCancel(lastSubscription); + listeners.length = liveCount; + // If there are no listeners left and onCancel is set, then call + // onCancel to indicate that the last subscription has been removed. + if (liveCount == 0 && _onCancel != null) { + _onCancel(firstRemovedListener); + } + break; } } _subscriptionRemoved = false; @@ -223,7 +227,7 @@ class SimpleStream extends StreamView implements EventSink { /// Remove a subscription. /// It marks a subscription for removal during a microtask to ensure that /// a subscription wasn't cancelled as a result of processing a callback. - void _scheduleCleanup(SimpleStreamSubscription subscription) { + void _scheduleCleanup() { if (!_subscriptionRemoved) { _subscriptionRemoved = true; _cleanupStreams.add(this); @@ -245,12 +249,12 @@ class SimpleStream extends StreamView implements EventSink { // non checked mode since subscriptions will be null once the stream is // closed. assert(_subscriptions != null); - StreamCallContextFunc contextFunc; + Zone contextZone; if (_runInZone) { - contextFunc = Zone.current.run; + contextZone = Zone.current; } var sub = SimpleStreamSubscription( - this, onData, onDone, onError, cancelOnError, contextFunc); + this, onData, onDone, onError, cancelOnError, contextZone); if (_subscriptions.isEmpty) { _subscriptions = [sub]; } else { @@ -319,19 +323,18 @@ class EmptySimpleStream extends SimpleStream { } } -/// A SimpleStream implementation of [StreamSubscription]. +/// A [SimpleStream] implementation of [StreamSubscription]. /// /// Major differences: -/// Future returned by cancel is shared by all subscriptions. -/// Using [pause] is not supported. -/// _onError is not implemented by SimpleStream. +/// * [cancel] returns null. +/// * Using [pause] is not supported. /// class SimpleStreamSubscription implements StreamSubscription { @override final bool isPaused = false; SimpleStream _stream; StreamCallbackFunc _callback; - StreamCallContextFunc _contextFunc; + Zone _contextZone; Function _doneCallback; Function _onError; bool _cancelOnError = false; @@ -340,7 +343,7 @@ class SimpleStreamSubscription implements StreamSubscription { SimpleStreamSubscription(null, null, null, null, false, null); SimpleStreamSubscription(this._stream, this._callback, this._doneCallback, - this._onError, this._cancelOnError, this._contextFunc); + this._onError, this._cancelOnError, this._contextZone); @override Future cancel() { @@ -350,7 +353,7 @@ class SimpleStreamSubscription implements StreamSubscription { var stream = _stream; _doneCallback = null; _closeSubscription(); - stream._scheduleCleanup(this); + stream._scheduleCleanup(); } return null; } @@ -367,8 +370,8 @@ class SimpleStreamSubscription implements StreamSubscription { void _add(T data) { if (_callback != null) { - if (_contextFunc != null) { - _contextFunc(() => _callback(data)); + if (_contextZone != null) { + _contextZone.runUnary(_callback, data); } else { _callback(data); } @@ -410,7 +413,7 @@ class SimpleStreamSubscription implements StreamSubscription { } } -/// Provides an interface for both StreamController & and Stream for use with +/// Provides an interface for both [StreamController] and [Stream] for use with /// output events in Angular components. /// /// Reduces the amount of boilerplate needed by removing the need for a getter @@ -427,9 +430,6 @@ class SimpleEmitter extends SimpleStream { onListen: onListen, onCancel: onCancel); - /// Returns `this`. - Stream get stream => this; - /// Returns `this`. EventSink get sink => this; } From c0db405d96252cd3f6d35e252c3d0e9791604e70 Mon Sep 17 00:00:00 2001 From: Googler Date: Wed, 19 Dec 2018 09:21:42 -0800 Subject: [PATCH 012/503] Adding optional ARIA Label inputs to the MaterialYesNoButtonsComponent. By default, screen readers will read the button text as the label. This works OK, but there are many cases where a different label would improve accessibility. Changes: - Adding a `yesAriaLabel` input. This sets the `aria-label` attribute on the yes button. - Adding a `noAriaLabel` input. This sets the `aria-label` attribute on the no button. PiperOrigin-RevId: 226184300 --- .../material_yes_no_buttons.dart | 14 ++++++++++++++ .../material_yes_no_buttons.html | 2 ++ 2 files changed, 16 insertions(+) diff --git a/angular_components/lib/material_yes_no_buttons/material_yes_no_buttons.dart b/angular_components/lib/material_yes_no_buttons/material_yes_no_buttons.dart index b52908400..9f6ac9066 100644 --- a/angular_components/lib/material_yes_no_buttons/material_yes_no_buttons.dart +++ b/angular_components/lib/material_yes_no_buttons/material_yes_no_buttons.dart @@ -121,6 +121,20 @@ class MaterialYesNoButtonsComponent implements HasDisabled { @Input() bool pending = false; + /// The text to be used as an ARIA label on the save button. + /// + /// For example, `Ok`, `Apply`, etc. Defaults to `null` so screen readers will + /// read the button text as the label. + @Input() + String yesAriaLabel; + + /// The text to be used as an ARIA label on the cancel button. + /// + /// For example, `Dismiss`, `Not now`, etc. Defaults to `null` so screen + /// readers will read the button text as the label. + @Input() + String noAriaLabel; + @ViewChild('yesButton') MaterialButtonComponent yesButton; diff --git a/angular_components/lib/material_yes_no_buttons/material_yes_no_buttons.html b/angular_components/lib/material_yes_no_buttons/material_yes_no_buttons.html index 68999ec98..b04cf5312 100644 --- a/angular_components/lib/material_yes_no_buttons/material_yes_no_buttons.html +++ b/angular_components/lib/material_yes_no_buttons/material_yes_no_buttons.html @@ -13,6 +13,7 @@ [raised]="yesRaised || raised" [class.highlighted]="yesHighlighted" [disabled]="yesDisabled || disabled" + [attr.aria-label]="yesAriaLabel" (trigger)="onYes($event)"> {{yesText}} @@ -21,6 +22,7 @@ class="btn btn-no" [raised]="raised" [disabled]="noDisabled || disabled" + [attr.aria-label]="noAriaLabel" (trigger)="onNo($event)"> {{noText}} From 4a53e85befe710a429b5e50f34576d261bd19667 Mon Sep 17 00:00:00 2001 From: srawlins Date: Wed, 19 Dec 2018 15:57:14 -0800 Subject: [PATCH 013/503] Re-land Fix the type of MaterialDropdownSelectComponent's itemRenderer. This originally landed in cl/225276100, but was rolled back in cl/225486540. The original change was rolled back as I neglected to announce the breaking change, and it surprised folks in their development apps with breakages, and no fixes were announced. PiperOrigin-RevId: 226248258 --- .../material_time_picker.dart | 7 +++++-- .../material_dropdown_select.dart | 16 ++-------------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/angular_components/lib/material_datepicker/material_time_picker.dart b/angular_components/lib/material_datepicker/material_time_picker.dart index 9e5aab90f..88bad41f6 100644 --- a/angular_components/lib/material_datepicker/material_time_picker.dart +++ b/angular_components/lib/material_datepicker/material_time_picker.dart @@ -27,6 +27,9 @@ import 'package:angular_components/utils/disposer/disposer.dart'; materialInputDirectives, NgStyle, ], + directiveTypes: [ + Typed>(), + ], providers: [ Provider(HasDisabled, useExisting: MaterialTimePickerComponent), ], @@ -353,7 +356,7 @@ class MaterialTimePickerComponent extends KeyboardHandlerMixin /// /// Only options between [minTime] and [maxTime] are selectable. class TimeSelectionOptions extends StringSelectionOptions - implements Selectable { + implements Selectable { DateTime _minTime; DateTime _maxTime; @@ -363,7 +366,7 @@ class TimeSelectionOptions extends StringSelectionOptions set maxTime(DateTime time) => _maxTime = time; @override - SelectableOption getSelectable(item) { + SelectableOption getSelectable(DateTime item) { return item is DateTime && ((_minTime != null && item.isBefore(_minTime)) || (_maxTime != null && item.isAfter(_maxTime))) diff --git a/angular_components/lib/material_select/material_dropdown_select.dart b/angular_components/lib/material_select/material_dropdown_select.dart index 0d1871a92..1024cc2c6 100644 --- a/angular_components/lib/material_select/material_dropdown_select.dart +++ b/angular_components/lib/material_select/material_dropdown_select.dart @@ -232,22 +232,10 @@ class MaterialDropdownSelectComponent extends MaterialSelectBase } /// Function to convert an option object to string. - /// - // TODO(google): Fix this now that generics are supported. - // Ideally, [value] would be a [ItemRenderer], where T is also the type - // parameter of the SelectionOptions and the SelectionModel, as parent - // components typically use a function that accepts a specific type (T). - // - // However, we don't have a T. Angular doesn't support injecting a - // type-annotated component yet, and setters, like [itemRenderer], cannot - // be type-annotated. This forces us to accept a plain old [Function] as - // [value], in order to avoid uses_dynamic_as_bottom errors. (Basically, a - // function like [MaterialTimePicker]'s `String renderTime(DateTime time)` - // cannot work as a [ItemRenderer], since it expects DateTime, not dynamic.) @Input() @override - set itemRenderer(Function value) { - super.itemRenderer = (item) => value(item); + set itemRenderer(ItemRenderer value) { + super.itemRenderer = value; } /// Width of the dropdown/list, default none, valid values are 0-5. From bde3283592e5701d64814da8525f832a1105e0bf Mon Sep 17 00:00:00 2001 From: Googler Date: Thu, 20 Dec 2018 07:03:40 -0800 Subject: [PATCH 014/503] Material Auto Suggest clear icon should be disabled when the input is disabled PiperOrigin-RevId: 226330283 --- .../lib/material_input/material_auto_suggest_input.html | 1 + 1 file changed, 1 insertion(+) diff --git a/angular_components/lib/material_input/material_auto_suggest_input.html b/angular_components/lib/material_input/material_auto_suggest_input.html index 27351ed68..b72b26bbf 100644 --- a/angular_components/lib/material_input/material_auto_suggest_input.html +++ b/angular_components/lib/material_input/material_auto_suggest_input.html @@ -47,6 +47,7 @@ keyboardOnlyFocusIndicator stopPropagation class="clear-icon" + [disabled]="disabled" [materialTooltip]="clearIconTooltip" [showTooltipIf]="hasClearIconTooltip" [attr.aria-label]="clearIconTooltip" From 6a594d6024cc13aa30e940debc34c310f5f9b9a9 Mon Sep 17 00:00:00 2001 From: cissyshi Date: Thu, 20 Dec 2018 14:21:45 -0800 Subject: [PATCH 015/503] Move the overlay focus placeholder elements inside of material popup. 1. To simply the logic around focusing 2. Prevent tabbing to the elements when popup is closed (noticed when I turned on the focus indicator) PiperOrigin-RevId: 226392988 --- .../lib/laminate/overlay/constants.dart | 2 -- angular_components/lib/laminate/overlay/module.dart | 13 ------------- .../lib/material_popup/material_popup.dart | 12 ++++-------- .../lib/material_popup/material_popup.html | 10 ++++++++++ 4 files changed, 14 insertions(+), 23 deletions(-) diff --git a/angular_components/lib/laminate/overlay/constants.dart b/angular_components/lib/laminate/overlay/constants.dart index 7ac953d24..17432635e 100644 --- a/angular_components/lib/laminate/overlay/constants.dart +++ b/angular_components/lib/laminate/overlay/constants.dart @@ -5,5 +5,3 @@ const overlayDefaultContainerId = 'default-acx-overlay-container'; const overlayContainerClassName = 'acx-overlay-container'; const overlayContainerNameAttribute = 'container-name'; -const overlayFocusablePlaceholderClassName = - 'acx-overlay-focusable-placeholder'; diff --git a/angular_components/lib/laminate/overlay/module.dart b/angular_components/lib/laminate/overlay/module.dart index bfb0f0cd3..6daf8cb78 100644 --- a/angular_components/lib/laminate/overlay/module.dart +++ b/angular_components/lib/laminate/overlay/module.dart @@ -33,24 +33,11 @@ HtmlElement createAcxOverlayContainer(HtmlElement parent, {@required String id, @required String name, String className}) { var container = parent.querySelector('#$id'); if (container == null) { - // Add a hidden focusable element before overlay container to prevent screen - // reader from picking up content from a random element when users shift tab - // out of the first visible overlay. - parent.append(DivElement() - ..tabIndex = 0 - ..classes.add(overlayFocusablePlaceholderClassName)); - container = DivElement() ..id = id ..classes.add(overlayContainerClassName); if (className != null) container.classes.add(className); parent.append(container); - - // Add a hidden focusable element after overlay container to ensure there's - // a focusable element when users tab out of the last visible overlay. - parent.append(DivElement() - ..tabIndex = 0 - ..classes.add(overlayFocusablePlaceholderClassName)); } container.attributes[overlayContainerNameAttribute] = name; return container; diff --git a/angular_components/lib/material_popup/material_popup.dart b/angular_components/lib/material_popup/material_popup.dart index b121b4be3..be35117dd 100644 --- a/angular_components/lib/material_popup/material_popup.dart +++ b/angular_components/lib/material_popup/material_popup.dart @@ -13,7 +13,6 @@ import 'package:angular_components/focus/focus_interface.dart'; import 'package:angular_components/laminate/enums/alignment.dart'; import 'package:angular_components/laminate/enums/visibility.dart' as visibility; -import 'package:angular_components/laminate/overlay/constants.dart'; import 'package:angular_components/laminate/overlay/module.dart'; import 'package:angular_components/laminate/overlay/overlay.dart'; import 'package:angular_components/laminate/overlay/zindexer.dart'; @@ -565,17 +564,14 @@ class MaterialPopupComponent extends Object _stopRepositionLoop(); } - // If user tabs out of the popup or if the focus is inside of popup when the - // popup closes, restore focus on the popup source element instead of some - // seemingly random DOM location. + // If the focus is inside of popup when the popup closes, restore focus on + // the popup source element instead of some seemingly random DOM location. // TODO(google): removed the islastTriggerWithKeyboard to better support // mouse/keyboard mixed interactions. if (state.source is Focusable && hierarchy.islastTriggerWithKeyboard) { _domService.scheduleWrite(() { - if (window.document.activeElement.classes - .contains(overlayFocusablePlaceholderClassName) || - _overlayRef.overlayElement - .contains(window.document.activeElement)) { + if (_overlayRef.overlayElement + .contains(window.document.activeElement)) { (state.source as Focusable).focus(); } }); diff --git a/angular_components/lib/material_popup/material_popup.html b/angular_components/lib/material_popup/material_popup.html index 947daae6a..d17c72626 100644 --- a/angular_components/lib/material_popup/material_popup.html +++ b/angular_components/lib/material_popup/material_popup.html @@ -20,6 +20,11 @@ [style.min-width.px]="minWidth" [style.max-height.px]="maxHeight" [style.max-width.px]="maxWidth"> + +
@@ -31,6 +36,11 @@
+ +
From e3f1d14e2a7d71b9c18c36cb9daa9965a3f603f3 Mon Sep 17 00:00:00 2001 From: Googler Date: Thu, 20 Dec 2018 14:38:37 -0800 Subject: [PATCH 016/503] Move menu_root.dart to a shared directory to avoid build dependency cycles. PiperOrigin-RevId: 226395550 --- .../lib/material_menu/common/menu_root.dart | 35 +++++++++++++++++++ .../lib/material_menu/menu_root.dart | 32 +---------------- 2 files changed, 36 insertions(+), 31 deletions(-) create mode 100644 angular_components/lib/material_menu/common/menu_root.dart diff --git a/angular_components/lib/material_menu/common/menu_root.dart b/angular_components/lib/material_menu/common/menu_root.dart new file mode 100644 index 000000000..98c8690d0 --- /dev/null +++ b/angular_components/lib/material_menu/common/menu_root.dart @@ -0,0 +1,35 @@ +// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:angular/angular.dart'; +import 'package:angular_components/mixins/material_dropdown_base.dart'; + +/// A directive providing a [MenuRoot] through the injected [DropdownHandle]. +@Directive( + selector: '[menu-root]', + providers: [Provider(MenuRoot, useExisting: MenuRootDirective)], +) +class MenuRootDirective extends MenuRoot { + final DropdownHandle _dropdown; + + MenuRootDirective(@Optional() this._dropdown) { + visible = true; + } + + closeHierarchy() { + visible = false; + _dropdown.close(); + } +} + +/// The root of a hierarchy of [MenuItemGroups]. +/// +/// This must be provided as it permits to close the menu hierarchy on menu +/// actions. +abstract class MenuRoot { + void closeHierarchy(); + + /// Is this menu closed or closing. + bool visible; +} diff --git a/angular_components/lib/material_menu/menu_root.dart b/angular_components/lib/material_menu/menu_root.dart index 98c8690d0..5d7880627 100644 --- a/angular_components/lib/material_menu/menu_root.dart +++ b/angular_components/lib/material_menu/menu_root.dart @@ -2,34 +2,4 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -import 'package:angular/angular.dart'; -import 'package:angular_components/mixins/material_dropdown_base.dart'; - -/// A directive providing a [MenuRoot] through the injected [DropdownHandle]. -@Directive( - selector: '[menu-root]', - providers: [Provider(MenuRoot, useExisting: MenuRootDirective)], -) -class MenuRootDirective extends MenuRoot { - final DropdownHandle _dropdown; - - MenuRootDirective(@Optional() this._dropdown) { - visible = true; - } - - closeHierarchy() { - visible = false; - _dropdown.close(); - } -} - -/// The root of a hierarchy of [MenuItemGroups]. -/// -/// This must be provided as it permits to close the menu hierarchy on menu -/// actions. -abstract class MenuRoot { - void closeHierarchy(); - - /// Is this menu closed or closing. - bool visible; -} +export 'package:angular_components/material_menu/common/menu_root.dart'; From cd36b465d134a852fdc46d6c166453e85e3b0f01 Mon Sep 17 00:00:00 2001 From: Googler Date: Thu, 20 Dec 2018 16:45:13 -0800 Subject: [PATCH 017/503] Create an IconAffix.simple constructor for creating non-action icons. PiperOrigin-RevId: 226414801 --- angular_components/lib/model/menu/menu_item_affix.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/angular_components/lib/model/menu/menu_item_affix.dart b/angular_components/lib/model/menu/menu_item_affix.dart index 87bea5397..76fe16126 100644 --- a/angular_components/lib/model/menu/menu_item_affix.dart +++ b/angular_components/lib/model/menu/menu_item_affix.dart @@ -52,6 +52,12 @@ class IconAffix extends MenuItemAffix { this.visibility = IconVisibility.visible, this.cssClass}); + /// Creates a simple icon without any trigger action. + const IconAffix.simple( + {@required this.icon, + this.visibility = IconVisibility.visible, + this.cssClass}); + @override bool get shouldCloseMenuOnTrigger => icon is IconWithAction && From 02b2e8d9d60df588676a80968b4684299f3a1265 Mon Sep 17 00:00:00 2001 From: Googler Date: Wed, 2 Jan 2019 12:05:59 -0800 Subject: [PATCH 018/503] Dispose gallery section on hot restart. PiperOrigin-RevId: 227559068 --- .../lib/builder/template/main.dart.mustache | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/angular_gallery/lib/builder/template/main.dart.mustache b/angular_gallery/lib/builder/template/main.dart.mustache index 77075127d..cb16f827a 100644 --- a/angular_gallery/lib/builder/template/main.dart.mustache +++ b/angular_gallery/lib/builder/template/main.dart.mustache @@ -12,11 +12,21 @@ import 'main.template.dart' as ng; Logger _logger = Logger("angular_dart_gallery"); +ComponentRef gallery; + void main() { Logger.root.onRecord.listen((x) => print("${x.level}: ${x.message}")); // Start angular. - runApp(app.GalleryComponentNgFactory, createInjector: galleryInjector); + gallery = runApp(app.GalleryComponentNgFactory, createInjector: galleryInjector); +} + +/// The [onReloadStart] method is invoked immediately after the call to +/// dart_library.reload(), and the app will be in the same state as it was +/// before the reload. After this call, all invalidated modules will be +/// reloaded. go/dart-dc#warm-reload-with-ddc-dogfood +void onReloadStart() { + gallery.destroy(); } @Injectable() From f7cc834df529622da297889d1ad341e03e5ac96b Mon Sep 17 00:00:00 2001 From: Googler Date: Wed, 2 Jan 2019 15:23:18 -0800 Subject: [PATCH 019/503] Once expansion panel content is destroyed upon closing the panel, we can no longer assume _mainContent will be set by the time the domService.read executes. So we may need to hold on to the completer until the view child is set, and then perform the read and complete the futures. PiperOrigin-RevId: 227591183 --- .../material_expansionpanel.dart | 49 +++++++++++++------ 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/angular_components/lib/material_expansionpanel/material_expansionpanel.dart b/angular_components/lib/material_expansionpanel/material_expansionpanel.dart index 7db735226..84984f0ef 100644 --- a/angular_components/lib/material_expansionpanel/material_expansionpanel.dart +++ b/angular_components/lib/material_expansionpanel/material_expansionpanel.dart @@ -68,6 +68,7 @@ class MaterialExpansionPanel final _disposer = Disposer.oneShot(); final _defaultExpandIcon = 'expand_less'; final bool shouldExpandOnLeft; + final _pendingExpandedPanelHeightReads = >[]; bool initialized = false; @@ -106,7 +107,17 @@ class MaterialExpansionPanel HtmlElement _mainContent; @ViewChild('mainContent') - set mainContent(HtmlElement mainContent) => _mainContent = mainContent; + set mainContent(HtmlElement mainContent) { + _mainContent = mainContent; + if (_mainContent == null) return; + if (_pendingExpandedPanelHeightReads.isNotEmpty) { + var height = _readMainContentHeight(); + for (var completer in _pendingExpandedPanelHeightReads) { + completer.complete(height); + } + _pendingExpandedPanelHeightReads.clear(); + } + } HtmlElement _headerContent; @ViewChild('headerContent') @@ -489,26 +500,34 @@ class MaterialExpansionPanel final completeExpandedHeight = Completer(); _domService.scheduleRead(() { - final contentHeight = _mainContent.scrollHeight; - var expandedPanelHeight = ''; - - final mainPanelStyle = _mainPanel.getComputedStyle(); - // Do our best to make sure that onTransitionEnd will fire later. - final hasHeightTransition = - contentHeight > 0 && mainPanelStyle.transition.contains('height'); - - if (hasHeightTransition) { - // If the content-wrapper has a top margin, it is not reflected in the - // scroll height. - final topMargin = _contentWrapper.getComputedStyle().marginTop; - expandedPanelHeight = 'calc(${contentHeight}px + ${topMargin})'; + if (_mainContent != null) { + completeExpandedHeight.complete(_readMainContentHeight()); + } else { + _pendingExpandedPanelHeightReads.add(completeExpandedHeight); } - completeExpandedHeight.complete(expandedPanelHeight); }); return completeExpandedHeight.future; } + String _readMainContentHeight() { + final contentHeight = _mainContent.scrollHeight; + var expandedPanelHeight = ''; + + final mainPanelStyle = _mainPanel.getComputedStyle(); + // Do our best to make sure that onTransitionEnd will fire later. + final hasHeightTransition = + contentHeight > 0 && mainPanelStyle.transition.contains('height'); + + if (hasHeightTransition) { + // If the content-wrapper has a top margin, it is not reflected in the + // scroll height. + final topMargin = _contentWrapper.getComputedStyle().marginTop; + expandedPanelHeight = 'calc(${contentHeight}px + ${topMargin})'; + } + return expandedPanelHeight; + } + /// Reads the DOM state to calculate the height of the header in its /// current condition. /// From 17fa34e0101baafe25c00c43483d3b648679046d Mon Sep 17 00:00:00 2001 From: Googler Date: Thu, 3 Jan 2019 15:16:16 -0800 Subject: [PATCH 020/503] Allow custom app bindings in Gallery scaffolding. Added gallery_bindings and deps to component_gallery_app definition. PiperOrigin-RevId: 227758815 --- angular_gallery/lib/builder/gallery_app_builder.dart | 12 ++++++++++-- .../lib/builder/template/main.dart.mustache | 6 ++++++ angular_gallery/lib/builders.dart | 7 +++++-- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/angular_gallery/lib/builder/gallery_app_builder.dart b/angular_gallery/lib/builder/gallery_app_builder.dart index 5ca3aa398..2690776ad 100644 --- a/angular_gallery/lib/builder/gallery_app_builder.dart +++ b/angular_gallery/lib/builder/gallery_app_builder.dart @@ -13,8 +13,11 @@ import '../src/template_util.dart'; class GalleryWebBuilder extends Builder { final String _galleryTitle; final String _direction; + final String _galleryBindingName; + final String _galleryBindingImport; - GalleryWebBuilder(this._direction, this._galleryTitle); + GalleryWebBuilder(this._direction, this._galleryTitle, + this._galleryBindingName, this._galleryBindingImport); @override Future build(BuildStep buildStep) async { @@ -36,8 +39,13 @@ class GalleryWebBuilder extends Builder { Future _generateMainDart(BuildStep buildStep) async { final mustacheContext = { 'galleryImportUri': - 'package:${buildStep.inputId.package}/gallery/gallery.template.dart' + 'package:${buildStep.inputId.package}/gallery/gallery.template.dart', + 'hasBinding': + _galleryBindingName.isNotEmpty && _galleryBindingImport.isNotEmpty, + 'bindingName': _galleryBindingName, + 'bindingImport': _galleryBindingImport, }; + final newAssetId = AssetId(buildStep.inputId.package, 'web/main.dart'); await writeAsset(buildStep, 'lib/builder/template/main.dart.mustache', mustacheContext, newAssetId); diff --git a/angular_gallery/lib/builder/template/main.dart.mustache b/angular_gallery/lib/builder/template/main.dart.mustache index cb16f827a..df910b1cd 100644 --- a/angular_gallery/lib/builder/template/main.dart.mustache +++ b/angular_gallery/lib/builder/template/main.dart.mustache @@ -7,6 +7,9 @@ import 'package:angular_components/laminate/popup/module.dart'; import 'package:angular_components/laminate/overlay/module.dart'; import 'package:angular_components/material_datepicker/module.dart'; import '{{{ galleryImportUri }}}' as app; +{{# hasBinding }} +import '{{{ bindingImport }}}' as binding; +{{/ hasBinding }} import 'main.template.dart' as ng; @@ -39,6 +42,9 @@ HtmlElement materialContentElement(Document document) { popupBindings, datepickerBindings, Provider(overlayContainerParent, useFactory: materialContentElement), + {{# hasBinding }} + binding.{{ bindingName }}, + {{/ hasBinding }} ]) final InjectorFactory galleryInjector = ng.galleryInjector$Injector; diff --git a/angular_gallery/lib/builders.dart b/angular_gallery/lib/builders.dart index 47468b3d1..6b8ab0f74 100644 --- a/angular_gallery/lib/builders.dart +++ b/angular_gallery/lib/builders.dart @@ -9,8 +9,11 @@ import 'package:angular_gallery/builder/syntax_highlight_builder.dart'; /// Builders used to generate files in the gallery app target. Builder galleryAppBuilder(BuilderOptions options) => MultiplexingBuilder([ - GalleryWebBuilder(options.config['direction'] ?? 'ltr', - options.config['galleryTitle'] ?? 'Example Gallery'), + GalleryWebBuilder( + options.config['direction'] ?? 'ltr', + options.config['galleryTitle'] ?? 'Example Gallery', + options.config['galleryBindingName'], + options.config['galleryBindingImport']), HomeDartBuilder(), ]); From 0bc8954fc08c78fbd3befce0bf2452a036ebdfa4 Mon Sep 17 00:00:00 2001 From: jamesbutkovic Date: Thu, 3 Jan 2019 17:21:30 -0800 Subject: [PATCH 021/503] Material Autosuggest: hide empty suggestion group PiperOrigin-RevId: 227777624 --- .../material_auto_suggest_input.html | 79 ++++++++++--------- 1 file changed, 41 insertions(+), 38 deletions(-) diff --git a/angular_components/lib/material_input/material_auto_suggest_input.html b/angular_components/lib/material_input/material_auto_suggest_input.html index b72b26bbf..cf1de80d7 100644 --- a/angular_components/lib/material_input/material_auto_suggest_input.html +++ b/angular_components/lib/material_input/material_auto_suggest_input.html @@ -96,47 +96,50 @@ [id]="popupId" [width]="width" (mouseleave)="activeModel.activate(null)"> -
+ +
+ label + class="list-group-label" + (mouseenter)="activeModel.activate(null)"> {{suggestionGroup.uiDisplayName}} - - - - - - -
+ + + + + + +
+
Date: Fri, 4 Jan 2019 11:22:23 -0800 Subject: [PATCH 022/503] Automated g4 rollback of changelist 227777624. *** Reason for rollback *** Breaking Tests *** Original change description *** Material Autosuggest: hide empty suggestion group *** PiperOrigin-RevId: 227885299 --- .../material_auto_suggest_input.html | 79 +++++++++---------- 1 file changed, 38 insertions(+), 41 deletions(-) diff --git a/angular_components/lib/material_input/material_auto_suggest_input.html b/angular_components/lib/material_input/material_auto_suggest_input.html index cf1de80d7..b72b26bbf 100644 --- a/angular_components/lib/material_input/material_auto_suggest_input.html +++ b/angular_components/lib/material_input/material_auto_suggest_input.html @@ -96,50 +96,47 @@ [id]="popupId" [width]="width" (mouseleave)="activeModel.activate(null)"> - -
+
+ label + class="list-group-label" + (mouseenter)="activeModel.activate(null)"> {{suggestionGroup.uiDisplayName}} - - - - - - -
- + + + + + + +
Date: Fri, 4 Jan 2019 11:26:41 -0800 Subject: [PATCH 023/503] When an expansion panel is expanded, and the header is hidden, we shouldn't be able to tab into the hidden header buttons for expanding and collapsing the panel using a screen reader. PiperOrigin-RevId: 227886072 --- .../material_expansionpanel/material_expansionpanel.dart | 2 ++ .../material_expansionpanel/material_expansionpanel.html | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/angular_components/lib/material_expansionpanel/material_expansionpanel.dart b/angular_components/lib/material_expansionpanel/material_expansionpanel.dart index 84984f0ef..accb9768a 100644 --- a/angular_components/lib/material_expansionpanel/material_expansionpanel.dart +++ b/angular_components/lib/material_expansionpanel/material_expansionpanel.dart @@ -459,6 +459,8 @@ class MaterialExpansionPanel return actionCtrl.action.onDone; } + bool get headerHidden => isExpanded && hideExpandedHeader; + /// Sets necessary explicit heights to allow CSS transitions when expanding /// or collapsing. void _transitionHeightChange(bool expand) { diff --git a/angular_components/lib/material_expansionpanel/material_expansionpanel.html b/angular_components/lib/material_expansionpanel/material_expansionpanel.html index 2c04de731..3a3388f54 100644 --- a/angular_components/lib/material_expansionpanel/material_expansionpanel.html +++ b/angular_components/lib/material_expansionpanel/material_expansionpanel.html @@ -12,12 +12,12 @@ keyupBoundary> -
+
@@ -44,6 +45,7 @@ *ngIf="shouldShowExpandIcon && !shouldExpandOnLeft" class="expand-button" [icon]="expandIcon" + [disabled]="headerHidden" [class.expand-more]="shouldFlipExpandIcon" (trigger)="handleExpandIconClick" [attr.aria-label]="expandAriaMsg"> From 3d1b29d9c1f0da99779ca28efb49033a8c0c69cf Mon Sep 17 00:00:00 2001 From: Googler Date: Fri, 4 Jan 2019 11:41:27 -0800 Subject: [PATCH 024/503] Support specifying a custom aria label for the delete button. PiperOrigin-RevId: 227888808 --- angular_components/lib/material_chips/material_chip.dart | 4 ++++ angular_components/lib/material_chips/material_chip.html | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/angular_components/lib/material_chips/material_chip.dart b/angular_components/lib/material_chips/material_chip.dart index f2aec9baf..11d59f372 100644 --- a/angular_components/lib/material_chips/material_chip.dart +++ b/angular_components/lib/material_chips/material_chip.dart @@ -41,6 +41,10 @@ class MaterialChipComponent extends RootFocusable implements HasRenderer { desc: 'Label for a button which removes the item when clicked.', meaning: 'Label for a button which removes the item when clicked.'); + /// Aria label for delete button. + @Input() + String deleteButtonAriaMessage = chipDeleteButtonMessage; + /// A selection model to render as chips. /// /// This model should not be used for rendering, changes will not be diff --git a/angular_components/lib/material_chips/material_chip.html b/angular_components/lib/material_chips/material_chip.html index 1ab1436a5..ff52f0347 100644 --- a/angular_components/lib/material_chips/material_chip.html +++ b/angular_components/lib/material_chips/material_chip.html @@ -15,7 +15,7 @@ class="delete-icon" buttonDecorator (trigger)="removeChip" - [attr.aria-label]="chipDeleteButtonMessage" + [attr.aria-label]="deleteButtonAriaMessage" [attr.aria-describedby]="uuid"> -
+ +
+ label + class="list-group-label" + (mouseenter)="activeModel.activate(null)"> {{suggestionGroup.uiDisplayName}} - - - - - - -
+ + + + + + +
+
Date: Wed, 9 Jan 2019 10:57:59 -0800 Subject: [PATCH 031/503] Remove ripple elements from MaterialRippleComponent when component is destroyed. Leaving the ripple elements attached to the component's element results in a memory leak. PiperOrigin-RevId: 228548424 --- angular_components/lib/material_ripple/material_ripple.dart | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/angular_components/lib/material_ripple/material_ripple.dart b/angular_components/lib/material_ripple/material_ripple.dart index 32f680dde..b44390889 100644 --- a/angular_components/lib/material_ripple/material_ripple.dart +++ b/angular_components/lib/material_ripple/material_ripple.dart @@ -217,5 +217,10 @@ class MaterialRippleComponent implements OnDestroy { void ngOnDestroy() { _element.removeEventListener('mousedown', _onMouseDown); _element.removeEventListener('keydown', _onKeyDown); + _ripplePool.forEach((ripple) { + if (ripple?.parent == _element) { + ripple.remove(); + } + }); } } From 35c7ac8ff50c9784b00520f5bbb7f91a5aefb1cb Mon Sep 17 00:00:00 2001 From: nshahan Date: Wed, 9 Jan 2019 16:40:25 -0800 Subject: [PATCH 032/503] Create separate documentation components for dart and markdown documentation. Enables documentation to be displayed with different templates. This is prep to add a third type of documentation for Sass mixin libraries. - Merge the models for documentation used during code gen and in the gallery component at run time. PiperOrigin-RevId: 228612593 --- .../lib/builder/component_api_builder.dart | 9 +- .../lib/builder/gallery_info_builder.dart | 19 +- .../template/component.api.dart.mustache | 14 +- .../gallery_component/dart_doc_component.html | 61 +++++++ .../documentation_component.dart | 73 ++++++++ .../documentation_component.scss | 30 ++++ .../gallery_component/documentation_info.dart | 166 ++++++++++++++++++ .../gallery_component/gallery_component.dart | 22 +-- .../gallery_component/gallery_component.html | 81 ++------- .../gallery_component/gallery_component.scss | 25 +-- .../gallery_component/gallery_info.dart | 39 +--- .../lib/gallery_docs_extraction.dart | 40 ++--- .../lib/resolved_config.dart | 84 +-------- 13 files changed, 403 insertions(+), 260 deletions(-) create mode 100644 angular_gallery_section/lib/components/gallery_component/dart_doc_component.html create mode 100644 angular_gallery_section/lib/components/gallery_component/documentation_component.dart create mode 100644 angular_gallery_section/lib/components/gallery_component/documentation_component.scss create mode 100644 angular_gallery_section/lib/components/gallery_component/documentation_info.dart diff --git a/angular_gallery_section/lib/builder/component_api_builder.dart b/angular_gallery_section/lib/builder/component_api_builder.dart index 25532d9c4..f562ce517 100644 --- a/angular_gallery_section/lib/builder/component_api_builder.dart +++ b/angular_gallery_section/lib/builder/component_api_builder.dart @@ -9,6 +9,7 @@ import 'package:build/build.dart'; import 'package:mustache/mustache.dart' show Template; import 'package:path/path.dart' as p; import 'package:angular_gallery_section/resolved_config.dart'; +import 'package:angular_gallery_section/components/gallery_component/documentation_info.dart'; /// A builder for generating an API page for an Angular component. /// @@ -69,7 +70,13 @@ class ComponentApiBuilder extends Builder { 'dartImport': config.mainDemo?.import, 'examplePath': config.mainDemo?.path, }, - 'docs': config.docs?.map((doc) => doc.toJson())?.toList() ?? [], + 'docs': config.docs?.map((doc) { + var jsonMap = doc.toJson(); + jsonMap['dartDoc'] = doc.docType == DocType.dartDocInfo; + jsonMap['markdownDoc'] = doc.docType == DocType.markdownDocInfo; + return jsonMap; + })?.toList() ?? + [], 'benchmarks': config.benchmarks ?? [], 'owners': config.owners, 'uxOwners': config.uxOwners, diff --git a/angular_gallery_section/lib/builder/gallery_info_builder.dart b/angular_gallery_section/lib/builder/gallery_info_builder.dart index 73d9aebd9..34813fd04 100644 --- a/angular_gallery_section/lib/builder/gallery_info_builder.dart +++ b/angular_gallery_section/lib/builder/gallery_info_builder.dart @@ -14,6 +14,7 @@ import 'package:angular_gallery_section/g3doc_markdown.dart'; import 'package:angular_gallery_section/gallery_docs_extraction.dart'; import 'package:angular_gallery_section/gallery_section_config_extraction.dart'; import 'package:angular_gallery_section/resolved_config.dart'; +import 'package:angular_gallery_section/components/gallery_component/documentation_info.dart'; import 'package:angular_gallery_section/visitors/path_utils.dart' as path_utils; /// A builder for generating a json summary of each occurance of a @@ -78,7 +79,7 @@ class GalleryInfoBuilder extends Builder { return resolved; })); - /// Resolve all [docs] into a [_DocInfo] that contains the HTML to be rendered + /// Resolve all [docs] into a [DocInfo] that contains the HTML to be rendered /// in the gallery. /// /// Searches imports for documentation starting at [rootLibrary], reading @@ -107,7 +108,7 @@ class GalleryInfoBuilder extends Builder { } /// Read the [markdownAsset] with [assetReader] and render as HTML. - Future _readMarkdownAsset( + Future _readMarkdownAsset( String markdownAsset, AssetReader assetReader) async { final assetId = AssetId.resolve(markdownAsset); if (extension(assetId.path) != '.md') { @@ -125,12 +126,10 @@ class GalleryInfoBuilder extends Builder { // Convert markdown to html and insert static server for images. final htmlContent = _replaceImgTags(g3docMarkdownToHtml(content)); - return DocInfo() + return MarkdownDocInfo() ..name = basenameWithoutExtension(assetId.path) - // Markdown docs have no annotations to signal they are deprecated. - ..deprecated = false ..path = path_utils.assetToPath(assetId.toString()) - ..comment = htmlContent; + ..contents = htmlContent; } /// Find the file that defines [identifier], and extract the documentation @@ -138,11 +137,11 @@ class GalleryInfoBuilder extends Builder { /// /// Searches imports starting at [library], reading source files with /// [assetReader]. - Future _resolveDocFromClass(String identifier, + Future _resolveDocFromClass(String identifier, LibraryElement library, AssetReader assetReader) async { final libraryId = AssetId.resolve(library.source.uri.toString()); final docClass = library.getType(identifier); - DocInfo docs; + DartDocInfo docs; // If this a functional directive, just extract the docs and we are done. if (docClass == null) { @@ -155,8 +154,8 @@ class GalleryInfoBuilder extends Builder { // Otherwise there is additional documenation for a class. Collect all // inherited @Input and @Output documentation. - final mergedInputs = {}; - final mergedOutputs = {}; + final mergedInputs = {}; + final mergedOutputs = {}; for (final classElement in _classHierarcy(docClass)) { // Must extract doumentation from AST becauses the diff --git a/angular_gallery_section/lib/builder/template/component.api.dart.mustache b/angular_gallery_section/lib/builder/template/component.api.dart.mustache index 64e996920..f2b1e4271 100644 --- a/angular_gallery_section/lib/builder/template/component.api.dart.mustache +++ b/angular_gallery_section/lib/builder/template/component.api.dart.mustache @@ -17,7 +17,8 @@ class {{component}}Api { GalleryInfo model = GalleryInfo( docs: [ {{#docs}} - Doc( + {{#dartDoc}} + DartDocInfo( '{{name}}', {{deprecated}}, '{{deprecatedMessage}}', @@ -27,7 +28,7 @@ class {{component}}Api { applyHighlighting(r"""{{comment}}"""), [ {{#inputs}} - Property( + DartPropertyInfo( '{{annotation}}', '{{name}}', '{{bindingAlias}}', @@ -41,7 +42,7 @@ class {{component}}Api { ], [ {{#outputs}} - Property( + DartPropertyInfo( '{{annotation}}', '{{name}}', '{{bindingAlias}}', @@ -53,6 +54,13 @@ class {{component}}Api { ), {{/outputs}} ]), + {{/dartDoc}} + {{#markdownDoc}} + MarkdownDocInfo( + '{{name}}', + '{{path}}', + applyHighlighting(r"""{{contents}}""")), + {{/markdownDoc}} {{/docs}} ], demos: [ diff --git a/angular_gallery_section/lib/components/gallery_component/dart_doc_component.html b/angular_gallery_section/lib/components/gallery_component/dart_doc_component.html new file mode 100644 index 000000000..90f53ed87 --- /dev/null +++ b/angular_gallery_section/lib/components/gallery_component/dart_doc_component.html @@ -0,0 +1,61 @@ + +

+ {{doc.deprecatedMessage}} +

+ +

+ Selector: + <{{doc.selector}}> +

+ +

+ Exported as: + {{doc.exportAs}} +

+ +
+ + +
+ Inputs: +
    +
  • + + {{input.bindingAlias.isNotEmpty ? input.bindingAlias : input.name}} + + {{input.type}} + +

    + {{input.deprecatedMessage}} +

    +

    + Missing a Dart Doc comment. +

    +
    +
  • +
+
+ +
+ Outputs: +
    +
  • + + {{output.bindingAlias.isNotEmpty ? output.bindingAlias : output.name}} + + {{output.type}} +

    + {{output.deprecatedMessage}} +

    +

    + Missing a Dart Doc comment. +

    +
    +
  • +
+
+
diff --git a/angular_gallery_section/lib/components/gallery_component/documentation_component.dart b/angular_gallery_section/lib/components/gallery_component/documentation_component.dart new file mode 100644 index 000000000..37acb03d2 --- /dev/null +++ b/angular_gallery_section/lib/components/gallery_component/documentation_component.dart @@ -0,0 +1,73 @@ +// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:angular/angular.dart'; +import 'package:angular/security.dart'; +import 'package:angular_gallery_section/components/gallery_component/gallery_info.dart'; + +/// A list of all documentation directives. +const documentationComponentDirectives = const [ + DartDocComponent, + MarkdownDocComponent, +]; + +class DocumentationComponent { + @Input() + bool showGeneratedDocs; + + final _sanitizedHtml = {}; + + DomSanitizationService _santizationService; + + DocumentationComponent(this._santizationService); + + SafeHtml getSafeHtml(String value) { + var html = _sanitizedHtml[value]; + if (html == null) { + html = _santizationService.bypassSecurityTrustHtml(value); + _sanitizedHtml[value] = html; + } + return html; + } +} + +/// Displays documentation for dart files in the gallery application. +/// +/// Docs are expected to be generated for Angular @Components and @Directives. +@Component( + selector: 'documentation-component[dart]', + directives: [ + NgFor, + NgIf, + SafeInnerHtmlDirective, + ], + templateUrl: 'dart_doc_component.html', + styleUrls: ['documentation_component.scss.css'], +) +class DartDocComponent extends DocumentationComponent { + DartDocComponent(DomSanitizationService santizationService) + : super(santizationService); + + /// The documentation to display. + @Input() + DartDocInfo doc; +} + +/// Displays a single piece of documentation. +/// +/// Typically used for the generated HTML from a markdown README. +@Component( + selector: 'documentation-component[markdown]', + directives: [SafeInnerHtmlDirective], + template: '
', + styleUrls: ['documentation_component.scss.css'], +) +class MarkdownDocComponent extends DocumentationComponent { + MarkdownDocComponent(DomSanitizationService santizationService) + : super(santizationService); + + /// The documentation to display. + @Input() + MarkdownDocInfo doc; +} diff --git a/angular_gallery_section/lib/components/gallery_component/documentation_component.scss b/angular_gallery_section/lib/components/gallery_component/documentation_component.scss new file mode 100644 index 000000000..059793bc7 --- /dev/null +++ b/angular_gallery_section/lib/components/gallery_component/documentation_component.scss @@ -0,0 +1,30 @@ +// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@import 'package:angular_components/css/all_material'; + +:host { + ::ng-deep strong { + @include mat-font-body-2; + color: $mat-blue; + } + + .property-type { + background: none; + border: 0; + color: $mat-blue; + font-size: smaller; + } + + .property-deprecated::before, + .declaration-deprecated::before { + color: $mat-red-600; + content: 'Deprecated! '; + } + + .declaration-deprecated { + font-weight: $mat-font-weight-bold; + font-size: $mat-font-size-subhead; + } +} diff --git a/angular_gallery_section/lib/components/gallery_component/documentation_info.dart b/angular_gallery_section/lib/components/gallery_component/documentation_info.dart new file mode 100644 index 000000000..5ba27a5c7 --- /dev/null +++ b/angular_gallery_section/lib/components/gallery_component/documentation_info.dart @@ -0,0 +1,166 @@ +// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// Encoding for different types of documenation for the gallery builders. +/// +/// Simplifies translating to and from JSON files between build steps. +enum DocType { dartDocInfo, markdownDocInfo } + +/// Base class for all documentation models in the gallery app. +abstract class DocInfo { + String get name; + String get path; + DocType get docType; + + /// Constructs a new [DocInfo] from a decoded json map. + factory DocInfo.fromJson(Map jsonMap) { + final docType = jsonMap['docType']; + + // Identify the specific documentation model to construct. + if (docType == DocType.dartDocInfo.toString()) { + return DartDocInfo.fromJson(jsonMap); + } + + if (docType == DocType.markdownDocInfo.toString()) { + return MarkdownDocInfo.fromJson(jsonMap); + } + + throw FormatException( + 'Unexpected docType found when constructing a DocInfo from JSON: ' + '$docType.'); + } + + Map toJson(); +} + +/// Documentation information for a Dart doc listed in an @GallerySectionConfig +/// annotation. +/// +/// Contains information for the Angular API of a @Component or @Directive. +class DartDocInfo implements DocInfo { + String name; + bool deprecated; + String deprecatedMessage; + String selector; + String exportAs; + String path; + String comment; + Iterable inputs; + Iterable outputs; + + DocType get docType => DocType.dartDocInfo; + + DartDocInfo( + [this.name, + this.deprecated, + this.deprecatedMessage, + this.selector, + this.exportAs, + this.path, + this.comment, + this.inputs, + this.outputs]); + + /// Constructs a new [DartDocInfo] from a decoded json map. + DartDocInfo.fromJson(Map jsonMap) { + name = jsonMap['name'] as String; + deprecated = jsonMap['deprecated'] as bool; + deprecatedMessage = jsonMap['deprecatedMessage'] as String; + selector = jsonMap['selector'] as String; + exportAs = jsonMap['exportAs'] as String; + path = jsonMap['path'] as String; + comment = jsonMap['comment'] as String; + inputs = (jsonMap['inputs'] as Iterable) + ?.map((element) => DartPropertyInfo.fromJson(element)); + outputs = (jsonMap['outputs'] as Iterable) + ?.map((element) => DartPropertyInfo.fromJson(element)); + } + + /// Returns a json encodeable representation of this [DartDocInfo]. + Map toJson() => { + 'docType': docType.toString(), + 'name': name, + 'deprecated': deprecated, + 'deprecatedMessage': deprecatedMessage, + 'selector': selector, + 'exportAs': exportAs, + 'path': path, + 'comment': comment, + 'inputs': inputs?.map((p) => p.toJson())?.toList(), + 'outputs': outputs?.map((p) => p.toJson())?.toList(), + }; +} + +/// Documentation information for an @Input or @Output property of an Angular +/// @Component or @Directive. +class DartPropertyInfo { + String annotation; + String name; + String bindingAlias; + String type; + String comment; + String classPath; + bool deprecated; + String deprecatedMessage; + + DartPropertyInfo( + [this.annotation, + this.name, + this.bindingAlias, + this.type, + this.comment, + this.classPath, + this.deprecated, + this.deprecatedMessage]); + + /// Constructs a new [DartPropertyInfo] from a decoded json map. + DartPropertyInfo.fromJson(Map jsonMap) { + annotation = jsonMap['annotation'] as String; + name = jsonMap['name'] as String; + bindingAlias = jsonMap['bindingAlias'] as String; + type = jsonMap['type'] as String; + comment = jsonMap['comment'] as String; + classPath = jsonMap['classPath'] as String; + deprecated = jsonMap['deprecated'] as bool; + deprecatedMessage = jsonMap['deprecatedMessage'] as String; + } + + /// Returns a json encodeable representation of this [DartPropertyInfo]. + Map toJson() => { + 'annotation': annotation, + 'name': name, + 'bindingAlias': bindingAlias, + 'type': type, + 'comment': comment, + 'classPath': classPath, + 'deprecated': deprecated, + 'deprecatedMessage': deprecatedMessage, + }; +} + +/// Documentation information for a single document, typically a markdown file. +class MarkdownDocInfo implements DocInfo { + String name; + String path; + String contents; + + DocType get docType => DocType.markdownDocInfo; + + MarkdownDocInfo([this.name, this.path, this.contents]); + + /// Constructs a new [MarkdownDocInfo] from a decoded json map. + MarkdownDocInfo.fromJson(Map jsonMap) { + name = jsonMap['name'] as String; + path = jsonMap['path'] as String; + contents = jsonMap['contents'] as String; + } + + /// Returns a json encodeable representation of this [MarkdownDocInfo]. + Map toJson() => { + 'docType': docType.toString(), + 'name': name, + 'path': path, + 'contents': contents, + }; +} diff --git a/angular_gallery_section/lib/components/gallery_component/gallery_component.dart b/angular_gallery_section/lib/components/gallery_component/gallery_component.dart index ab2a86d91..605b34b42 100644 --- a/angular_gallery_section/lib/components/gallery_component/gallery_component.dart +++ b/angular_gallery_section/lib/components/gallery_component/gallery_component.dart @@ -7,11 +7,11 @@ library angular_components.scaffolding.gallery_section.components.gallery_compon import 'dart:html'; import 'package:angular/angular.dart'; -import 'package:angular/security.dart'; import 'package:js/js.dart'; import 'package:angular_components/button_decorator/button_decorator.dart'; import 'package:angular_components/dynamic_component/dynamic_component.dart'; import 'package:angular_components/laminate/popup/module.dart'; +import 'package:angular_gallery_section/components/gallery_component/documentation_component.dart'; import 'package:angular_gallery_section/components/gallery_component/gallery_info.dart'; /// The gallery component details page that encompass the component's dart docs, @@ -23,11 +23,12 @@ import 'package:angular_gallery_section/components/gallery_component/gallery_inf DynamicComponent, NgFor, NgIf, - SafeInnerHtmlDirective, + documentationComponentDirectives, ], providers: [popupBindings], templateUrl: 'gallery_component.html', styleUrls: ['gallery_component.scss.css'], + exports: const [DocType], ) class GalleryComponent { /// The base model for the gallery that gathers all of the details needed by @@ -35,30 +36,15 @@ class GalleryComponent { @Input() GalleryInfo model; - DomSanitizationService _santizationService; - - final _sanitizedHtml = {}; - /// Used to disable latency charts in testing environments where they can't /// load successfully. final latencyChartsEnabled = !window.location.href.contains('enableLatencyCharts=false'); - GalleryComponent(this._santizationService); - bool get showToc => (model.docs.length + model.demos.length + model.benchmarks.length) > 1; - SafeHtml getSafeHtml(String value) { - var html = _sanitizedHtml[value]; - if (html == null) { - html = _santizationService.bypassSecurityTrustHtml(value); - _sanitizedHtml[value] = html; - } - return html; - } - - String getDocId(Doc doc) => '${doc.name}Doc'; + String getDocId(DocInfo doc) => '${doc.name}Doc'; String getDemoId(Demo demo) => '${demo.name}Demo'; diff --git a/angular_gallery_section/lib/components/gallery_component/gallery_component.html b/angular_gallery_section/lib/components/gallery_component/gallery_component.html index 71d1898bf..21f89540a 100644 --- a/angular_gallery_section/lib/components/gallery_component/gallery_component.html +++ b/angular_gallery_section/lib/components/gallery_component/gallery_component.html @@ -42,18 +42,14 @@
- + {{doc.name}} - + {{demo.name}} @@ -69,69 +65,16 @@

{{doc.name}} Source Code

- -

- {{doc.deprecatedMessage}} -

- -

- Selector: - <{{doc.selector}}> -

- -

- Exported as: - {{doc.exportAs}} -

- -
- - -
- Inputs: -
    -
  • - - {{input.bindingAlias.isNotEmpty ? input.bindingAlias : input.name}} - - {{input.type}} - -

    - {{input.deprecatedMessage}} -

    -

    - Missing a Dart Doc comment. Please update: - - {{input.classPath}} - -

    -
    -
  • -
-
- -
- Outputs: -
    -
  • - - {{output.bindingAlias.isNotEmpty ? output.bindingAlias : output.name}} - - {{output.type}} -

    - {{output.deprecatedMessage}} -

    -

    - Missing a Dart Doc comment. Please update: - - {{output.classPath}} - -

    -
    -
  • -
-
-
+ + + +
diff --git a/angular_gallery_section/lib/components/gallery_component/gallery_component.scss b/angular_gallery_section/lib/components/gallery_component/gallery_component.scss index 475067697..98b9b8a8b 100644 --- a/angular_gallery_section/lib/components/gallery_component/gallery_component.scss +++ b/angular_gallery_section/lib/components/gallery_component/gallery_component.scss @@ -2,7 +2,7 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -@import 'package:angular_components/css/material/material'; +@import 'package:angular_components/css/all_material'; // ::ng-deep rules may apply to target tags that don't appear in the template, // but are inserted dynamically. @@ -103,11 +103,6 @@ h2 { } } -.doc ::ng-deep strong { - @include mat-font-body-2; - color: $mat-blue; -} - ::ng-deep p { // Makes it so the docs for inputs and outputs could be closer to the // input/output declaration. @@ -137,24 +132,6 @@ h2 { margin-bottom: $mat-grid * 2; } -.property-type { - background: none; - border: 0; - color: $mat-blue; - font-size: smaller; -} - -.property-deprecated::before, -.declaration-deprecated::before { - color: $mat-red-600; - content: 'Deprecated! '; -} - -.declaration-deprecated { - font-weight: $mat-font-weight-bold; - font-size: $mat-font-size-subhead; -} - ::ng-deep table { border-collapse: collapse; margin: $mat-grid * 3 0; diff --git a/angular_gallery_section/lib/components/gallery_component/gallery_info.dart b/angular_gallery_section/lib/components/gallery_component/gallery_info.dart index 3204cdf2f..66c8a9d4d 100644 --- a/angular_gallery_section/lib/components/gallery_component/gallery_info.dart +++ b/angular_gallery_section/lib/components/gallery_component/gallery_info.dart @@ -3,13 +3,16 @@ // BSD-style license that can be found in the LICENSE file. import 'package:angular/angular.dart'; +import 'package:angular_gallery_section/components/gallery_component/documentation_info.dart'; + +// This needs to be a seperate build target for the builders but all runtime +// uses can access it via this export. +export 'package:angular_gallery_section/components/gallery_component/documentation_info.dart'; /// The model that keeps the details for all of the gallery information class GalleryInfo { - /// A list of Doc attributes pull Dart doc comments from. - /// - /// Specify docs in the order that they should be displayed. - final List docs; + /// The docs to show in the gallery page in the order that they should appear. + final List docs; /// A list of example component examples to include in the section. /// @@ -48,37 +51,9 @@ class GalleryInfo { this.showGeneratedDocs = true}); } -class Doc { - final String name; - final bool deprecated; - final String deprecatedMessage; - final String selector; - final String exportAs; - final String path; - final String comment; - final List inputs; - final List outputs; - const Doc(this.name, this.deprecated, this.deprecatedMessage, this.selector, - this.exportAs, this.path, this.comment, this.inputs, this.outputs); -} - class Demo { final ComponentFactory demoFactory; final String name; final String path; const Demo(this.demoFactory, this.name, this.path); } - -class Property { - final String annotation; - final String name; - final String bindingAlias; - final String type; - final String comment; - final String classPath; - final bool deprecated; - final String deprecatedMessage; - - const Property(this.annotation, this.name, this.bindingAlias, this.type, - this.comment, this.classPath, this.deprecated, this.deprecatedMessage); -} diff --git a/angular_gallery_section/lib/gallery_docs_extraction.dart b/angular_gallery_section/lib/gallery_docs_extraction.dart index a04019a1e..427f85fae 100644 --- a/angular_gallery_section/lib/gallery_docs_extraction.dart +++ b/angular_gallery_section/lib/gallery_docs_extraction.dart @@ -7,31 +7,31 @@ import 'dart:async'; import 'package:analyzer/analyzer.dart'; import 'package:build/build.dart'; import 'package:angular_gallery_section/g3doc_markdown.dart'; -import 'package:angular_gallery_section/resolved_config.dart'; +import 'package:angular_gallery_section/components/gallery_component/documentation_info.dart'; import 'package:angular_gallery_section/visitors/path_utils.dart' as path_utils; import 'src/common_extractors.dart'; -/// Extracts a [DocInfo] from [assetId] for the identifier [name]. +/// Extracts a [DartDocInfo] from [assetId] for the identifier [name]. /// /// Will read [assetId] with [assetReader]. -Future extractDocumentation( +Future extractDocumentation( String name, AssetId assetId, AssetReader assetReader) async => parseCompilationUnit(await assetReader.readAsString(assetId), parseFunctionBodies: false) .accept(GalleryDocumentaionExtraction( name, path_utils.assetToPath(assetId.toString()))); -/// A visitor that extracts a [DocInfo] for an identifier [_name] and +/// A visitor that extracts a [DartDocInfo] for an identifier [_name] and /// additional information from the Angular annotations @Component and /// @Directive (if present) for documentation purposes. [_filePath] is -/// passed through to the extractor for [ProperyInfo]s. -class GalleryDocumentaionExtraction extends SimpleAstVisitor { +/// passed through to the extractor for [DartProperyInfo]s. +class GalleryDocumentaionExtraction extends SimpleAstVisitor { static final inputAnnotation = 'Input'; static final outputAnnotation = 'Output'; final String _name; final String _filePath; - DocInfo _info; + DartDocInfo _info; GalleryDocumentaionExtraction(this._name, this._filePath); @@ -45,10 +45,10 @@ class GalleryDocumentaionExtraction extends SimpleAstVisitor { } @override - DocInfo visitClassDeclaration(ClassDeclaration node) { + DartDocInfo visitClassDeclaration(ClassDeclaration node) { if (_extractDocumentation(node) == null) return null; - var allProperties = []; + var allProperties = []; var propertyVisitor = _AllMemberDocsExtraction(_filePath); for (Declaration member in node.members) { // Must collect the annotations early becausae class fields don't have @@ -105,11 +105,11 @@ class GalleryDocumentaionExtraction extends SimpleAstVisitor { } /// Collect information needed for documentaiton from [node]. - DocInfo _extractDocumentation(NamedCompilationUnitMember node) { + DartDocInfo _extractDocumentation(NamedCompilationUnitMember node) { if (node.name.name != _name) return null; final deprecatedAnnotationNode = _deprecatedAnnotation(node); - _info = DocInfo() + _info = DartDocInfo() ..name = node.name.name ..deprecated = deprecatedAnnotationNode != null ..deprecatedMessage = deprecatedAnnotationNode?.arguments?.arguments @@ -152,13 +152,13 @@ class GalleryDocumentaionExtraction extends SimpleAstVisitor { orElse: () => null); } -/// A visitor that extracts a [PropertyInfo] for every @Input and @Output +/// A visitor that extracts a [DartPropertyInfo] for every @Input and @Output /// property. /// /// Only passes [_filePath] through the the indivudual extractor each -/// [PropertyInfo]. +/// [DartPropertyInfo]. class _AllMemberDocsExtraction - extends SimpleAstVisitor> { + extends SimpleAstVisitor> { final _MemberDocExtraction _propertyVisitor; _AllMemberDocsExtraction(_filePath) @@ -178,11 +178,11 @@ class _AllMemberDocsExtraction } /// A visitor that extracts comments and the name of a class field or method as -/// a [PropertyInfo]. +/// a [DartPropertyInfo]. /// -/// Only uses [_filePath] to store in the returned [PropertyInfo] to document -/// the file it was extracted from. -class _MemberDocExtraction extends SimpleAstVisitor { +/// Only uses [_filePath] to store in the returned [DartPropertyInfo] to +/// document the file it was extracted from. +class _MemberDocExtraction extends SimpleAstVisitor { final String _filePath; _MemberDocExtraction(this._filePath); @@ -195,8 +195,8 @@ class _MemberDocExtraction extends SimpleAstVisitor { /// Extracts information for documenentation from a [MethodDeclaration] or /// [VariableDeclaration]. - PropertyInfo extractProperty(Declaration node) { - return PropertyInfo() + DartPropertyInfo extractProperty(Declaration node) { + return DartPropertyInfo() ..name = (node as dynamic /* MethodDeclaration | VariableDeclaration */) .name .name diff --git a/angular_gallery_section/lib/resolved_config.dart b/angular_gallery_section/lib/resolved_config.dart index c241bb6ee..6ad134257 100644 --- a/angular_gallery_section/lib/resolved_config.dart +++ b/angular_gallery_section/lib/resolved_config.dart @@ -2,6 +2,7 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +import 'package:angular_gallery_section/components/gallery_component/documentation_info.dart'; import 'package:angular_gallery_section/visitors/path_utils.dart' as path_utils; import 'package:angular_components/utils/strings/string_utils.dart' as string; @@ -74,89 +75,6 @@ class ResolvedConfig { }; } -/// Represents the docs listed in an @GallerySectionConfig annotation resolved -/// to the values used by the gallery generators. -class DocInfo { - String name; - bool deprecated; - String deprecatedMessage; - String selector; - String exportAs; - String path; - String comment; - Iterable inputs; - Iterable outputs; - - DocInfo(); - - /// Constructs a new [DocInfo] from a decoded json map. - DocInfo.fromJson(Map jsonMap) { - name = jsonMap['name'] as String; - deprecated = jsonMap['deprecated'] as bool; - deprecatedMessage = jsonMap['deprecatedMessage'] as String; - selector = jsonMap['selector'] as String; - exportAs = jsonMap['exportAs'] as String; - path = jsonMap['path'] as String; - comment = jsonMap['comment'] as String; - inputs = (jsonMap['inputs'] as Iterable) - ?.map((element) => PropertyInfo.fromJson(element)); - outputs = (jsonMap['outputs'] as Iterable) - ?.map((element) => PropertyInfo.fromJson(element)); - } - - /// Returns a json encodeable representation of this [DocInfo]. - Map toJson() => { - 'name': name, - 'deprecated': deprecated, - 'deprecatedMessage': deprecatedMessage, - 'selector': selector, - 'exportAs': exportAs, - 'path': path, - 'comment': comment, - 'inputs': inputs?.map((p) => p.toJson())?.toList(), - 'outputs': outputs?.map((p) => p.toJson())?.toList(), - }; -} - -/// Represents an @Input or @Output property for an Angular @Component or -/// @Directive resolved to the values used by the gallery generators. -class PropertyInfo { - String annotation; - String name; - String bindingAlias; - String type; - String comment; - String classPath; - bool deprecated; - String deprecatedMessage; - - PropertyInfo(); - - /// Constructs a new [PropertyInfo] from a decoded json map. - PropertyInfo.fromJson(Map jsonMap) { - annotation = jsonMap['annotation'] as String; - name = jsonMap['name'] as String; - bindingAlias = jsonMap['bindingAlias'] as String; - type = jsonMap['type'] as String; - comment = jsonMap['comment'] as String; - classPath = jsonMap['classPath'] as String; - deprecated = jsonMap['deprecated'] as bool; - deprecatedMessage = jsonMap['deprecatedMessage'] as String; - } - - /// Returns a json encodeable representation of this [PropertyInfo]. - Map toJson() => { - 'annotation': annotation, - 'name': name, - 'bindingAlias': bindingAlias, - 'type': type, - 'comment': comment, - 'classPath': classPath, - 'deprecated': deprecated, - 'deprecatedMessage': deprecatedMessage, - }; -} - /// Represents the demos listed in an @GallerySectionConfig annotation resolved /// to the values used by the gallery generators. class DemoInfo { From d54f742bc1fe4a4493fd2e49881ffada8e6fe1d3 Mon Sep 17 00:00:00 2001 From: Googler Date: Thu, 10 Jan 2019 12:22:11 -0800 Subject: [PATCH 033/503] Ability to attach an aria label to the date picker PiperOrigin-RevId: 228755081 --- .../lib/material_datepicker/material_datepicker.dart | 4 ++++ .../lib/material_datepicker/material_datepicker.html | 1 + 2 files changed, 5 insertions(+) diff --git a/angular_components/lib/material_datepicker/material_datepicker.dart b/angular_components/lib/material_datepicker/material_datepicker.dart index fd8253377..903cc6244 100644 --- a/angular_components/lib/material_datepicker/material_datepicker.dart +++ b/angular_components/lib/material_datepicker/material_datepicker.dart @@ -76,6 +76,10 @@ class MaterialDatepickerComponent /// Only visible for the template. final String popupClassName; + /// aria-label attached to the dropdown button that opens the date picker. + @Input() + String ariaLabelForDropdownButton; + /// The format used to format dates. /// /// Defaults to `yMMMd`, e.g. 'Jan 23, 2015'. diff --git a/angular_components/lib/material_datepicker/material_datepicker.html b/angular_components/lib/material_datepicker/material_datepicker.html index 553faeb8e..34299a7ab 100644 --- a/angular_components/lib/material_datepicker/material_datepicker.html +++ b/angular_components/lib/material_datepicker/material_datepicker.html @@ -10,6 +10,7 @@ {{labelMsg}}
Date: Thu, 10 Jan 2019 12:39:38 -0800 Subject: [PATCH 034/503] Add a reorderProgress event to reorder list. This allows user of this widget to provide extra hints during an reordering. PiperOrigin-RevId: 228757878 --- angular_components/lib/reorder_list/reorder_list.dart | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/angular_components/lib/reorder_list/reorder_list.dart b/angular_components/lib/reorder_list/reorder_list.dart index b1c800917..1593d83d9 100644 --- a/angular_components/lib/reorder_list/reorder_list.dart +++ b/angular_components/lib/reorder_list/reorder_list.dart @@ -76,6 +76,12 @@ class ReorderListComponent implements OnDestroy { final _itemSelectionChanged = StreamController.broadcast(sync: true); + /// Emits [ReorderEvent] with the source index and the currently hovered index + /// during a reorder. + @Output() + Stream get reorderProgress => _reorderProgress.stream; + final _reorderProgress = StreamController.broadcast(sync: true); + final NgZone _ngZone; /// If true (default), items are aligned vertically. @@ -548,6 +554,9 @@ class ReorderListComponent implements OnDestroy { _moveItem(_currentMoveIndex, moveTargetIndex); _currentMoveIndex = moveTargetIndex; + _reorderProgress + .add(_createReorderEvent(_moveSourceIndex, _currentMoveIndex)); + // Need to temporary remove drag listener for element // we're switching with to not trigger another event during transition // otherwise we can trigger onDrag during transition and cause flickering From d306ef0a40ffac6661be9af81997a8b9ab71d471 Mon Sep 17 00:00:00 2001 From: hcameron Date: Thu, 10 Jan 2019 12:40:19 -0800 Subject: [PATCH 035/503] Update filename _core.scss to _core_material.scss Now consistent with other files in the library. PiperOrigin-RevId: 228757985 --- angular_components/lib/css/_all_material.scss | 2 +- angular_components/lib/css/{_core.scss => _core_material.scss} | 0 angular_components/lib/css/material/const/_functions.scss | 2 +- angular_components/lib/css/material/const/_mixins.scss | 2 +- angular_components/lib/css/material/const/_settings.scss | 2 +- 5 files changed, 4 insertions(+), 4 deletions(-) rename angular_components/lib/css/{_core.scss => _core_material.scss} (100%) diff --git a/angular_components/lib/css/_all_material.scss b/angular_components/lib/css/_all_material.scss index 99eed2f29..7e2e780e4 100644 --- a/angular_components/lib/css/_all_material.scss +++ b/angular_components/lib/css/_all_material.scss @@ -26,7 +26,7 @@ @import 'color_palette_material'; @import 'color_material'; -@import 'core'; +@import 'core_material'; @import 'elevation_material'; @import 'scrollbar_material'; @import 'transition_material'; diff --git a/angular_components/lib/css/_core.scss b/angular_components/lib/css/_core_material.scss similarity index 100% rename from angular_components/lib/css/_core.scss rename to angular_components/lib/css/_core_material.scss diff --git a/angular_components/lib/css/material/const/_functions.scss b/angular_components/lib/css/material/const/_functions.scss index cb6629c73..000207342 100644 --- a/angular_components/lib/css/material/const/_functions.scss +++ b/angular_components/lib/css/material/const/_functions.scss @@ -2,4 +2,4 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -@import 'package:angular_components/css/core'; +@import 'package:angular_components/css/core_material'; diff --git a/angular_components/lib/css/material/const/_mixins.scss b/angular_components/lib/css/material/const/_mixins.scss index fdb00170c..b32bc40c4 100644 --- a/angular_components/lib/css/material/const/_mixins.scss +++ b/angular_components/lib/css/material/const/_mixins.scss @@ -2,5 +2,5 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -@import 'package:angular_components/css/core'; +@import 'package:angular_components/css/core_material'; @import 'package:angular_components/css/scrollbar_material'; diff --git a/angular_components/lib/css/material/const/_settings.scss b/angular_components/lib/css/material/const/_settings.scss index 3f8a74487..ff0c33e2e 100644 --- a/angular_components/lib/css/material/const/_settings.scss +++ b/angular_components/lib/css/material/const/_settings.scss @@ -2,6 +2,6 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -@import 'package:angular_components/css/core'; +@import 'package:angular_components/css/core_material'; @import 'package:angular_components/css/transition_material'; @import 'package:angular_components/css/color_material'; From ff92b28dfbf17e3f3c52cb9ce3fadf07470371bd Mon Sep 17 00:00:00 2001 From: cpelling Date: Thu, 10 Jan 2019 14:00:05 -0800 Subject: [PATCH 036/503] Re-render highlights when month picker view is reset. Fixes https://github.com/dart-lang/angular_components/issues/358 PiperOrigin-RevId: 228772097 --- .../lib/material_datepicker/material_month_picker.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/angular_components/lib/material_datepicker/material_month_picker.dart b/angular_components/lib/material_datepicker/material_month_picker.dart index e35dff3a3..92ba64706 100644 --- a/angular_components/lib/material_datepicker/material_month_picker.dart +++ b/angular_components/lib/material_datepicker/material_month_picker.dart @@ -333,6 +333,8 @@ class MaterialMonthPickerComponent state.selections.isEmpty ? _today : state.selections.first.start; _renderAllYears(); scrollToYear(initialDate.year); + _renderHighlights(); + _renderHover(); } // Dart returns a separate instance every time a tearoff is accessed, so we From a7b87f616fd080e68e40f58b8b3d8f962d0f22e7 Mon Sep 17 00:00:00 2001 From: hcameron Date: Fri, 11 Jan 2019 10:51:13 -0800 Subject: [PATCH 037/503] Update import PiperOrigin-RevId: 228907693 --- angular_components/lib/css/_scrollbar_material.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/angular_components/lib/css/_scrollbar_material.scss b/angular_components/lib/css/_scrollbar_material.scss index ef1d3a5e1..51e915741 100644 --- a/angular_components/lib/css/_scrollbar_material.scss +++ b/angular_components/lib/css/_scrollbar_material.scss @@ -2,7 +2,7 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -@import 'core'; +@import 'core_material'; @import 'color_material'; /// Common colors for scrollbars. From ad0f834a8388cb582fc3e3d433d707d32254a3bd Mon Sep 17 00:00:00 2001 From: Googler Date: Mon, 14 Jan 2019 12:17:01 -0800 Subject: [PATCH 038/503] 'percent' is an invalid 'type' attribute value for the 'input' element. Use value 'text' instead. PiperOrigin-RevId: 229230264 --- .../lib/material_input/material_percent_directive.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/angular_components/lib/material_input/material_percent_directive.dart b/angular_components/lib/material_input/material_percent_directive.dart index bc69c69f8..65be7467e 100644 --- a/angular_components/lib/material_input/material_percent_directive.dart +++ b/angular_components/lib/material_input/material_percent_directive.dart @@ -21,6 +21,9 @@ export 'package:angular_components/material_input/material_number_accessor.dart' class MaterialPercentInputDirective { MaterialPercentInputDirective( MaterialInputComponent input, HtmlElement element) { + // 'percent' is an invalid 'type' attribute value for the 'input' element. + // Use value 'text' instead. + input.type = 'text'; input.rightAlign = true; element.dir = 'ltr'; final percentPattern = NumberFormat.percentPattern(); From e86d9862822844f226fae37a9fc6239fcaa5c9eb Mon Sep 17 00:00:00 2001 From: nshahan Date: Mon, 14 Jan 2019 12:55:12 -0800 Subject: [PATCH 039/503] Change a missing or unrecognized doc asset from a warning to an exception. PiperOrigin-RevId: 229236672 --- .../lib/builder/gallery_info_builder.dart | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/angular_gallery_section/lib/builder/gallery_info_builder.dart b/angular_gallery_section/lib/builder/gallery_info_builder.dart index 34813fd04..254ec16df 100644 --- a/angular_gallery_section/lib/builder/gallery_info_builder.dart +++ b/angular_gallery_section/lib/builder/gallery_info_builder.dart @@ -90,8 +90,8 @@ class GalleryInfoBuilder extends Builder { return docs.map((doc) async { if (doc.startsWith('package:')) { - // This is a Markdown asset, grab it directly. - return _readMarkdownAsset(doc, assetReader); + // This is an external asset to collect docs from. + return _readExternalAsset(doc, assetReader); } else { // Assume it is a class or function that needs to be found. final docLibrary = _searchFor(doc, rootLibrary); @@ -108,28 +108,25 @@ class GalleryInfoBuilder extends Builder { } /// Read the [markdownAsset] with [assetReader] and render as HTML. - Future _readMarkdownAsset( + Future _readExternalAsset( String markdownAsset, AssetReader assetReader) async { final assetId = AssetId.resolve(markdownAsset); - if (extension(assetId.path) != '.md') { - log.warning('Generator only supports .md files as supplementary docs. ' - 'Can not insert $assetId into gallery.'); - return null; - } if (!await assetReader.canRead(assetId)) { - log.warning('Counld not find the asset: $markdownAsset.'); - return null; + throw ('Counld not find the asset: $markdownAsset.'); } - final content = await assetReader.readAsString(assetId); - // Convert markdown to html and insert static server for images. - final htmlContent = _replaceImgTags(g3docMarkdownToHtml(content)); + if (extension(assetId.path) == '.md') { + final content = await assetReader.readAsString(assetId); + return MarkdownDocInfo() + ..name = basenameWithoutExtension(assetId.path) + ..path = path_utils.assetToPath(assetId.toString()) + // Convert markdown to html and insert static server for images. + ..contents = _replaceImgTags(g3docMarkdownToHtml(content)); + } - return MarkdownDocInfo() - ..name = basenameWithoutExtension(assetId.path) - ..path = path_utils.assetToPath(assetId.toString()) - ..contents = htmlContent; + throw ('Documentation generator only supports external files of type .md. ' + 'Can not load documentation from $assetId.'); } /// Find the file that defines [identifier], and extract the documentation From d447177a514101c8e4162702958a4a0589150b9c Mon Sep 17 00:00:00 2001 From: Googler Date: Tue, 15 Jan 2019 13:48:34 -0800 Subject: [PATCH 040/503] Add parameter to StringSelectionOptions to return empty filtered values when query is empty PiperOrigin-RevId: 229433371 --- .../selection/string_selection_options.dart | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/angular_components/lib/model/selection/string_selection_options.dart b/angular_components/lib/model/selection/string_selection_options.dart index 24ffaae8b..e02d235c1 100644 --- a/angular_components/lib/model/selection/string_selection_options.dart +++ b/angular_components/lib/model/selection/string_selection_options.dart @@ -59,6 +59,10 @@ class StringSelectionOptions extends SelectionOptions final bool _shouldSort; + /// True if [filter] should return the first limit of values when the query is + /// empty. + final bool _shouldFilterEmpty; + /// The list of options and optionally a function to convert the option into a /// string that can be used for filtering the list. /// @@ -68,25 +72,32 @@ class StringSelectionOptions extends SelectionOptions /// /// If the data needs to be sorted, it should be passed in sorted. The option /// [shouldSort] is a simple way to apply the default sorting rules. + /// + /// Set [shouldFilterEmpty] to false if [filter] should return empty when the + /// query is empty. StringSelectionOptions(List options, {ItemRenderer toFilterableString, StringSuggestionFilter suggestionFilter, ItemRenderer sanitizeString = _stringFormatSuggestion, - bool shouldSort = false}) + bool shouldSort = false, + bool shouldFilterEmpty = true}) : this.withOptionGroups([OptionGroup(options)], toFilterableString: toFilterableString, suggestionFilter: suggestionFilter, sanitizeString: sanitizeString, - shouldSort: shouldSort); + shouldSort: shouldSort, + shouldFilterEmpty: shouldFilterEmpty); StringSelectionOptions.withOptionGroups(List> optionGroups, {ItemRenderer toFilterableString, StringSuggestionFilter suggestionFilter, ItemRenderer sanitizeString = _stringFormatSuggestion, - bool shouldSort = false}) + bool shouldSort = false, + bool shouldFilterEmpty = true}) : _toFilterableString = toFilterableString ?? _defaultRenderer(sanitizeString), _shouldSort = shouldSort, + _shouldFilterEmpty = shouldFilterEmpty, _sanitizeString = sanitizeString, super(optionGroups) { _suggestionFilter = @@ -138,8 +149,10 @@ class StringSelectionOptions extends SelectionOptions list = group .where((suggestion) => _suggestionFilter(suggestion, filterQuery)) .take(limit); - } else { + } else if (_shouldFilterEmpty) { list = group.take(limit); + } else { + list = Iterable.empty(); } var filteredGroup = OptionGroup.withLabelFunction( list.toList(growable: false), From 8977ad0be8bc1ddeead9aaf4617fef416ea53289 Mon Sep 17 00:00:00 2001 From: Googler Date: Thu, 17 Jan 2019 12:31:53 -0800 Subject: [PATCH 041/503] Create standalone menu item affix components. PiperOrigin-RevId: 229797709 --- .../lib/material_menu/affix/base_affix.dart | 25 +++++ .../material_menu/affix/caption_affix.dart | 42 ++++++++ .../material_menu/affix/caption_affix.scss | 10 ++ .../affix/caption_affix_model.dart | 37 ++++++- .../lib/material_menu/affix/icon_affix.dart | 97 +++++++++++++++++++ .../lib/material_menu/affix/icon_affix.scss | 23 +++++ .../material_menu/affix/icon_affix_model.dart | 81 +++++++++++++++- .../material_menu/menu_item_affix_list.dart | 1 + .../lib/model/menu/menu_item_affix.dart | 74 +++----------- .../lib/material_menu_demo.dart | 1 + 10 files changed, 325 insertions(+), 66 deletions(-) create mode 100644 angular_components/lib/material_menu/affix/base_affix.dart create mode 100644 angular_components/lib/material_menu/affix/caption_affix.dart create mode 100644 angular_components/lib/material_menu/affix/caption_affix.scss create mode 100644 angular_components/lib/material_menu/affix/icon_affix.dart create mode 100644 angular_components/lib/material_menu/affix/icon_affix.scss diff --git a/angular_components/lib/material_menu/affix/base_affix.dart b/angular_components/lib/material_menu/affix/base_affix.dart new file mode 100644 index 000000000..68ceedb2e --- /dev/null +++ b/angular_components/lib/material_menu/affix/base_affix.dart @@ -0,0 +1,25 @@ +// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:angular/angular.dart'; +import 'package:angular_components/interfaces/has_disabled.dart'; +import 'package:angular_components/model/menu/menu_item_affix.dart'; +import 'package:angular_components/model/ui/has_renderer.dart'; + +/// Base interface for any components that renders a [MenuItemAffix]. +abstract class BaseAffixComponent + implements RendersValue, HasDisabled { + ModelType get value; +} + +/// Properly typed interface of [MenuItemAffix]. +/// +/// Please extend this class instead of [MenuItemAffix] directly. +abstract class BaseMenuItemAffixModel + extends MenuItemAffix> { + const BaseMenuItemAffixModel(); + + @override + ComponentFactory get componentFactory; +} diff --git a/angular_components/lib/material_menu/affix/caption_affix.dart b/angular_components/lib/material_menu/affix/caption_affix.dart new file mode 100644 index 000000000..9bf1792a5 --- /dev/null +++ b/angular_components/lib/material_menu/affix/caption_affix.dart @@ -0,0 +1,42 @@ +// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:angular/angular.dart'; +import 'package:angular/meta.dart'; +import 'package:angular_components/material_menu/affix/base_affix.dart'; +import 'package:angular_components/material_menu/affix/caption_affix_model.dart'; + +/// Simple text menu item affix. +@Component( + selector: 'caption-affix', + directives: [], + changeDetection: ChangeDetectionStrategy.OnPush, + styleUrls: ['caption_affix.scss.css'], + template: '{{text}}') +class CaptionAffixComponent implements BaseAffixComponent { + @HostBinding('class') + static const hostClass = 'caption-text'; + + final ChangeDetectorRef _cdRef; + + CaptionAffix _viewModel; + + /// No-op, not used by this component. + @override + bool disabled; + + CaptionAffixComponent(this._cdRef); + + @visibleForTemplate + String get text => _viewModel.text; + + @override + CaptionAffix get value => _viewModel; + + @override + set value(CaptionAffix newValue) { + _viewModel = newValue; + _cdRef.markForCheck(); + } +} diff --git a/angular_components/lib/material_menu/affix/caption_affix.scss b/angular_components/lib/material_menu/affix/caption_affix.scss new file mode 100644 index 000000000..699d754d0 --- /dev/null +++ b/angular_components/lib/material_menu/affix/caption_affix.scss @@ -0,0 +1,10 @@ +// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@import 'package:angular_components/css/material/material'; + +:host { + color: $mat-light-transparent-black; + display: block; +} diff --git a/angular_components/lib/material_menu/affix/caption_affix_model.dart b/angular_components/lib/material_menu/affix/caption_affix_model.dart index c588fddad..022fb24f6 100644 --- a/angular_components/lib/material_menu/affix/caption_affix_model.dart +++ b/angular_components/lib/material_menu/affix/caption_affix_model.dart @@ -2,5 +2,38 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -export 'package:angular_components/model/menu/menu_item_affix.dart' - show CaptionAffix; +import 'package:angular/angular.dart'; +import 'package:angular_components/material_menu/affix/base_affix.dart'; +import 'package:angular_components/material_menu/affix/caption_affix.template.dart'; +import 'package:angular_components/model/menu/menu_item_affix.dart'; + +/// Affix containing text. +class CaptionAffix extends BaseMenuItemAffixModel { + @override + final IconVisibility visibility; + + final String text; + + @override + final String cssClass; + + @override + ComponentFactory get componentFactory => + CaptionAffixComponentNgFactory; + + const CaptionAffix( + {this.text, this.visibility = IconVisibility.visible, this.cssClass}); + + const CaptionAffix.forShortcut( + {String text, IconVisibility visibility = IconVisibility.visible}) + : this(text: text, visibility: visibility, cssClass: 'shortcut'); + + @override + bool get shouldCloseMenuOnTrigger => false; + + @override + bool hasShortcutKeyCode(int keyCode) => false; + + @override + void triggerShortcutAction() {} +} diff --git a/angular_components/lib/material_menu/affix/icon_affix.dart b/angular_components/lib/material_menu/affix/icon_affix.dart new file mode 100644 index 000000000..7537a6b5f --- /dev/null +++ b/angular_components/lib/material_menu/affix/icon_affix.dart @@ -0,0 +1,97 @@ +// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:html'; + +import 'package:angular/angular.dart'; +import 'package:angular/meta.dart'; +import 'package:angular_components/button_decorator/button_decorator.dart'; +import 'package:angular_components/material_icon/material_icon.dart'; +import 'package:angular_components/material_menu/affix/base_affix.dart'; +import 'package:angular_components/material_menu/affix/icon_affix_model.dart'; +import 'package:angular_components/material_menu/common/menu_root.dart'; +import 'package:angular_components/model/ui/icon.dart'; + +/// Icon affix component - if the icon has an action attached to it, then +/// clicking/triggering the icon will also run the action. +@Component( + selector: 'icon-affix', + directives: [ + ButtonDirective, + MaterialIconComponent, + NgClass, + ], + changeDetection: ChangeDetectionStrategy.OnPush, + styleUrls: ['icon_affix.scss.css'], + template: r''' + + + ''') +class IconAffixComponent implements BaseAffixComponent { + /// The top most menu node. + /// + /// Used in order to close the whole hierarchy. + final MenuRoot _menuRoot; + + final ChangeDetectorRef _cdRef; + + IconAffix _viewModel; + + var _disabled = false; + + IconAffixComponent(this._cdRef, @Optional() this._menuRoot); + + @visibleForTemplate + Icon get icon => _viewModel.icon; + + @visibleForTemplate + bool get isActionIconAffix => affix.hasAction; + + @visibleForTemplate + String get actionIconAriaLabel => _viewModel.ariaLabel; + + @visibleForTemplate + IconAffix get affix => _viewModel; + + @override + IconAffix get value => _viewModel; + + @override + set value(IconAffix newValue) { + _viewModel = newValue; + _cdRef.markForCheck(); + } + + @override + bool get disabled => _disabled; + + @override + set disabled(value) { + _disabled = value; + _cdRef.markForCheck(); + } + + @visibleForTemplate + void handleActionIconTrigger(Event event) { + if (disabled) return; + + if (_viewModel.hasAction) { + _viewModel.triggerShortcutAction(); + event.stopPropagation(); + + if (_viewModel.shouldCloseMenuOnTrigger) _menuRoot?.closeHierarchy(); + } + } +} diff --git a/angular_components/lib/material_menu/affix/icon_affix.scss b/angular_components/lib/material_menu/affix/icon_affix.scss new file mode 100644 index 000000000..583815195 --- /dev/null +++ b/angular_components/lib/material_menu/affix/icon_affix.scss @@ -0,0 +1,23 @@ +// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@import 'package:angular_components/css/material/material'; + +:host { + display: block; +} + +.secondary-icon { + color: $mat-light-transparent-black; + transition: color $mat-transition $mat-transition-standard; + width: $mat-grid * 3; + + &:not(.disabled):hover { + color: $mat-transparent-black; + } +} + +.secondary-icon.hover-icon { + opacity: 0; +} diff --git a/angular_components/lib/material_menu/affix/icon_affix_model.dart b/angular_components/lib/material_menu/affix/icon_affix_model.dart index b4e4889da..fb00efb13 100644 --- a/angular_components/lib/material_menu/affix/icon_affix_model.dart +++ b/angular_components/lib/material_menu/affix/icon_affix_model.dart @@ -2,5 +2,82 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -export 'package:angular_components/model/menu/menu_item_affix.dart' - show IconAffix; +import 'package:angular/angular.dart'; +import 'package:meta/meta.dart'; +import 'package:angular_components/material_menu/affix/base_affix.dart'; +import 'package:angular_components/material_menu/affix/icon_affix.template.dart'; +import 'package:angular_components/model/menu/menu_item_affix.dart'; +import 'package:angular_components/model/ui/icon.dart'; + +/// Affix containing an icon. +class IconAffix extends BaseMenuItemAffixModel { + @override + final IconVisibility visibility; + + final Icon icon; + + @override + final String cssClass; + + final String ariaLabel; + final IconAction _action; + final int _keyCode; + + @override + final bool shouldCloseMenuOnTrigger; + + @Deprecated('Use IconAffix.simple and IconAffix.withAction instead') + factory IconAffix( + {@required Icon icon, + IconVisibility visibility = IconVisibility.visible, + String cssClass}) { + if (icon is IconWithAction) { + return IconAffix.withAction( + icon: icon, + action: icon.action, + ariaLabel: icon.ariaLabel, + shouldCloseMenuOnTrigger: icon.shouldCloseMenuOnTrigger, + visibility: visibility, + cssClass: cssClass); + } + + return IconAffix.simple( + icon: icon, visibility: visibility, cssClass: cssClass); + } + + /// Creates a simple icon without any trigger action. + const IconAffix.simple( + {@required this.icon, + this.visibility = IconVisibility.visible, + this.cssClass}) + : _action = null, + ariaLabel = null, + _keyCode = null, + shouldCloseMenuOnTrigger = false; + + /// Creates an icon that has a trigger action with a shortcut key. + const IconAffix.withAction( + {@required this.icon, + @required IconAction action, + @required this.ariaLabel, + int keyCode, + this.shouldCloseMenuOnTrigger = false, + this.visibility = IconVisibility.visible, + this.cssClass}) + : _action = action, + _keyCode = keyCode; + + @override + ComponentFactory get componentFactory => + IconAffixComponentNgFactory; + + bool get hasAction => _action != null; + + @override + bool hasShortcutKeyCode(int keyCode) => _keyCode == keyCode; + + @override + void triggerShortcutAction() { + _action?.call(); + } +} diff --git a/angular_components/lib/material_menu/menu_item_affix_list.dart b/angular_components/lib/material_menu/menu_item_affix_list.dart index 6176c3369..5bf067eed 100644 --- a/angular_components/lib/material_menu/menu_item_affix_list.dart +++ b/angular_components/lib/material_menu/menu_item_affix_list.dart @@ -11,6 +11,7 @@ import 'package:angular_components/button_decorator/button_decorator.dart'; import 'package:angular_components/interfaces/has_disabled.dart'; import 'package:angular_components/material_icon/material_icon.dart'; import 'package:angular_components/material_menu/menu_root.dart'; +import 'package:angular_components/material_menu/affix/caption_affix_model.dart'; import 'package:angular_components/material_menu/affix/icon_affix_model.dart'; import 'package:angular_components/model/menu/menu_item_affix.dart'; import 'package:angular_components/model/ui/icon.dart'; diff --git a/angular_components/lib/model/menu/menu_item_affix.dart b/angular_components/lib/model/menu/menu_item_affix.dart index 76fe16126..7ef41b3de 100644 --- a/angular_components/lib/model/menu/menu_item_affix.dart +++ b/angular_components/lib/model/menu/menu_item_affix.dart @@ -2,11 +2,13 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -import 'package:meta/meta.dart'; import 'package:angular_components/model/ui/icon.dart'; /// Represents a menu item content affix. -abstract class MenuItemAffix { +/// +/// For new affix component models, please extend BaseMenuItemAffixModel for +/// proper type safety. Do not extend this class directly. +abstract class MenuItemAffix { const MenuItemAffix(); IconVisibility get visibility; @@ -14,7 +16,14 @@ abstract class MenuItemAffix { bool get isVisibleOnHover => visibility == IconVisibility.hover; bool get isVisible => visibility != IconVisibility.hidden; + // Due to VM tests not supporting Angular, we cannot directly specify + // ComponentFactory here. + FactoryType get componentFactory; + + /// If true, close the menu upon triggering the [action]. bool get shouldCloseMenuOnTrigger; + + /// Returns true if the [keyCode] should trigger the shortcut action. bool hasShortcutKeyCode(int keyCode); void triggerShortcutAction(); @@ -24,6 +33,7 @@ abstract class MenuItemAffix { typedef void IconAction(); /// An icon that performs an action when the icon is triggered. +@Deprecated('Use the IconAffix.withAction directly') class IconWithAction extends Icon { final IconAction action; final String ariaLabel; @@ -37,66 +47,6 @@ class IconWithAction extends Icon { : super(name); } -/// Affix containing an icon. -class IconAffix extends MenuItemAffix { - @override - final IconVisibility visibility; - - final Icon icon; - - @override - final String cssClass; - - const IconAffix( - {@required this.icon, - this.visibility = IconVisibility.visible, - this.cssClass}); - - /// Creates a simple icon without any trigger action. - const IconAffix.simple( - {@required this.icon, - this.visibility = IconVisibility.visible, - this.cssClass}); - - @override - bool get shouldCloseMenuOnTrigger => - icon is IconWithAction && - (icon as IconWithAction).shouldCloseMenuOnTrigger; - - @override - bool hasShortcutKeyCode(int keyCode) => - icon is IconWithAction && (icon as IconWithAction).keyCode == keyCode; - - @override - void triggerShortcutAction() { - if (icon is! IconWithAction) return; - (icon as IconWithAction).action?.call(); - } -} - -/// Affix containing text. -class CaptionAffix extends MenuItemAffix { - @override - final IconVisibility visibility; - - final String text; - - @override - final String cssClass; - - const CaptionAffix( - {this.text, this.visibility = IconVisibility.visible, this.cssClass}); - - @override - bool get shouldCloseMenuOnTrigger => false; - - @override - bool hasShortcutKeyCode(int keyCode) => false; - - @override - void triggerShortcutAction() {} -} - /// Specifies the visibility state of an icon. enum IconVisibility { hidden, // always hidden diff --git a/examples/material_menu_example/lib/material_menu_demo.dart b/examples/material_menu_example/lib/material_menu_demo.dart index 8df1500fe..663f30794 100644 --- a/examples/material_menu_example/lib/material_menu_demo.dart +++ b/examples/material_menu_example/lib/material_menu_demo.dart @@ -11,6 +11,7 @@ import 'package:angular_components/laminate/popup/module.dart'; import 'package:angular_components/material_icon/material_icon.dart'; import 'package:angular_components/material_menu/dropdown_menu.dart'; import 'package:angular_components/material_menu/material_menu.dart'; +import 'package:angular_components/material_menu/affix/caption_affix_model.dart'; import 'package:angular_components/material_menu/affix/icon_affix_model.dart'; import 'package:angular_components/model/menu/menu.dart'; import 'package:angular_components/model/menu/selectable_menu.dart'; From 1663cfc2fe5215fdc5f51869a849141725c2db7a Mon Sep 17 00:00:00 2001 From: Googler Date: Thu, 17 Jan 2019 12:34:20 -0800 Subject: [PATCH 042/503] Make the role of a button mutable, after initialization. PiperOrigin-RevId: 229798118 --- .../lib/button_decorator/button_decorator.dart | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/angular_components/lib/button_decorator/button_decorator.dart b/angular_components/lib/button_decorator/button_decorator.dart index 30220a021..4c126db6c 100644 --- a/angular_components/lib/button_decorator/button_decorator.dart +++ b/angular_components/lib/button_decorator/button_decorator.dart @@ -26,7 +26,7 @@ import 'package:angular_components/utils/browser/events/events.dart'; ) class ButtonDirective extends RootFocusable with HasTabIndex - implements OnInit, HasDisabled { + implements HasDisabled { /// Fired when the button is activated via click, tap, or key press. @Output() Stream get trigger => _trigger.stream; @@ -34,27 +34,17 @@ class ButtonDirective extends RootFocusable final _trigger = StreamController.broadcast(sync: true); String _hostTabIndex; - String _role; - String _ariaRole; ButtonDirective(Element element, @Attribute('role') String role) - : _role = role, + : this.role = (role ?? 'button'), super(element); /// Role of this component used for a11y. @Input() - set role(String value) { - assert(ariaRole == null, 'Role can only be set before initialization.'); - _role = value; - } + String role; @HostBinding('attr.role') - String get ariaRole => _ariaRole; - - @override - void ngOnInit() { - _ariaRole = _role ?? 'button'; - } + String get ariaRole => role; /// String value to be passed to aria-disabled. @HostBinding('attr.aria-disabled') From 190e5ed20ca01641d79cc049577a38802114d5f7 Mon Sep 17 00:00:00 2001 From: Googler Date: Thu, 17 Jan 2019 12:41:48 -0800 Subject: [PATCH 043/503] Map test gallery logging statements to approximate levels in browser console. - Removes timestamp from the log since console adds that by default. - Adds caller site to the log. PiperOrigin-RevId: 229799139 --- .../lib/builder/template/main.dart.mustache | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/angular_gallery_section/lib/builder/template/main.dart.mustache b/angular_gallery_section/lib/builder/template/main.dart.mustache index ad00f6386..7777592f8 100644 --- a/angular_gallery_section/lib/builder/template/main.dart.mustache +++ b/angular_gallery_section/lib/builder/template/main.dart.mustache @@ -1,3 +1,5 @@ +import 'dart:html'; + import 'package:angular/angular.dart'; import 'package:logging/logging.dart'; import 'package:angular_components/material_datepicker/module.dart'; @@ -7,10 +9,19 @@ import 'main.template.dart' as ng; void main() { Logger.root.onRecord.listen((record) { - var msg = '${record.time}: ${record.message}'; - if (record.error != null) msg += '\n\nCaused by:\n\n${record.error}'; - if (record.stackTrace != null) msg+= '\n${record.stackTrace}'; - print(msg); + var message = '${record.loggerName}: ${record.message}'; + if (record.error != null) message += '\n\nCaused by:\n\n${record.error}'; + if (record.stackTrace != null) message += '\n${record.stackTrace}'; + + if (record.level == Level.SEVERE || record.level == Level.SHOUT) { + window.console.error(message); + } else if (record.level == Level.WARNING) { + window.console.warn(message); + } else if (record.level == Level.INFO || record.level == Level.CONFIG) { + window.console.info(message); + } else { // FINE, FINER, FINEST, ALL + window.console.debug(message); + } }); runApp(app.GallerySectionNgFactory, createInjector: appInjectorFactory); From dfdfc9b8c474ce8a4ea3785244560554db563413 Mon Sep 17 00:00:00 2001 From: Googler Date: Thu, 17 Jan 2019 18:39:05 -0800 Subject: [PATCH 044/503] Load standalone menu item affix components via dynamic component instead of using NgIfs. PiperOrigin-RevId: 229856756 --- .../material_menu/menu_item_affix_list.dart | 148 +++++++++++------- .../material_menu/menu_item_affix_list.html | 31 ---- .../material_menu/menu_item_affix_list.scss | 22 +-- 3 files changed, 98 insertions(+), 103 deletions(-) delete mode 100644 angular_components/lib/material_menu/menu_item_affix_list.html diff --git a/angular_components/lib/material_menu/menu_item_affix_list.dart b/angular_components/lib/material_menu/menu_item_affix_list.dart index 5bf067eed..9bdcd4985 100644 --- a/angular_components/lib/material_menu/menu_item_affix_list.dart +++ b/angular_components/lib/material_menu/menu_item_affix_list.dart @@ -3,60 +3,56 @@ // BSD-style license that can be found in the LICENSE file. import 'dart:async'; -import 'dart:html'; import 'package:angular/angular.dart'; +import 'package:angular/meta.dart'; import 'package:observable/observable.dart'; -import 'package:angular_components/button_decorator/button_decorator.dart'; +import 'package:quiver/core.dart' as qc; +import 'package:angular_components/dynamic_component/dynamic_component.dart'; import 'package:angular_components/interfaces/has_disabled.dart'; -import 'package:angular_components/material_icon/material_icon.dart'; -import 'package:angular_components/material_menu/menu_root.dart'; -import 'package:angular_components/material_menu/affix/caption_affix_model.dart'; -import 'package:angular_components/material_menu/affix/icon_affix_model.dart'; +import 'package:angular_components/material_menu/affix/base_affix.dart'; import 'package:angular_components/model/menu/menu_item_affix.dart'; -import 'package:angular_components/model/ui/icon.dart'; /// Renders the list of menu item affixes. /// /// An affix can be a text or an icon component. This component also listens /// on any affix list changes. +// TODO(google): move component management to common utils if useful to others @Component( - selector: 'menu-item-affix-list', - changeDetection: ChangeDetectionStrategy.OnPush, - directives: [ - ButtonDirective, - MaterialIconComponent, - NgFor, - NgIf, - NgClass, - ], - providers: [ - Provider(HasDisabled, useExisting: MenuItemAffixListComponent), - ], - templateUrl: 'menu_item_affix_list.html', - styleUrls: ['menu_item_affix_list.scss.css'], - // TODO(google): Change preserveWhitespace to false to improve codesize. - preserveWhitespace: true, -) + selector: 'menu-item-affix-list', + changeDetection: ChangeDetectionStrategy.OnPush, + directives: [ + DynamicComponent, + NgFor, + NgIf, + ], + providers: [ + ExistingProvider(HasDisabled, MenuItemAffixListComponent), + ], + template: '', + styleUrls: ['menu_item_affix_list.scss.css']) class MenuItemAffixListComponent implements HasDisabled, OnDestroy { final ChangeDetectorRef _cdRef; StreamSubscription _itemChangeStreamSub; + final _affixComponentRefs = <_AffixRef>[]; + ObservableList _items; - /// The top most menu node. - /// - /// Used in order to close the whole hierarchy. - final MenuRoot _menuRoot; + @ViewChild('loadPoint', read: ViewContainerRef) + @visibleForTemplate + ViewContainerRef viewRef; bool _disabled = false; - MenuItemAffixListComponent(this._cdRef, @Optional() this._menuRoot); + MenuItemAffixListComponent(this._cdRef); @Input() set disabled(bool disabled) { _disabled = disabled; + + _updateItemProperties(); } bool get disabled => _disabled; @@ -64,51 +60,93 @@ class MenuItemAffixListComponent implements HasDisabled, OnDestroy { /// Observable list of affix items. @Input() set items(ObservableList items) { - this._items = items; - _itemChangeStreamSub?.cancel(); - _itemChangeStreamSub = items?.listChanges?.listen((_) { + _itemChangeStreamSub = items?.listChanges?.listen((change) { + _updateVisibleItems(change); _cdRef.markForCheck(); }); + + _initializeItems(items.whereType()); } bool get hasAffixes => _items?.isNotEmpty ?? false; - Iterable get affixes => _items; - @override void ngOnDestroy() { + _clearChildren(); _itemChangeStreamSub?.cancel(); } - bool isIconAffix(MenuItemAffix item) => item is IconAffix; - bool isActionIconAffix(MenuItemAffix item) => - item is IconAffix && item.icon is IconWithAction; - - bool isCaptionAffix(MenuItemAffix item) => item is CaptionAffix; - - String getActionIconAriaLabel(Icon icon) => - icon is IconWithAction ? icon.ariaLabel : null; + void _clearChildren() { + viewRef.clear(); + for (final ref in _affixComponentRefs.expand((ref) => ref.componentRef)) { + ref.destroy(); + } + _affixComponentRefs.clear(); + } - void handleActionIconTrigger(Icon icon, Event event) { - if (_disabled) return; + void _updateVisibleItems(Iterable> changes) { + // For each change, apply the removed entries, then apply the added entries. + for (final change in changes) { + final start = change.index; + + if (change.removed.isNotEmpty) { + final end = start + change.removed.length; + final removed = _affixComponentRefs.sublist(start, end); + + for (final toRemove in removed) { + if (toRemove.componentRef.isPresent) { + toRemove.componentRef.value.destroy(); + } + } + + _affixComponentRefs.removeRange(start, end); + } + + if (change.addedCount > 0) { + final allAdded = + change.added.whereType().toList().reversed; + for (final toAdd in allAdded) { + _affixComponentRefs.insert( + start, _createComponentRef(toAdd, index: start)); + } + } + } + } - if (icon is IconWithAction) { - icon.action?.call(); - event.stopPropagation(); + void _initializeItems(Iterable items) { + _clearChildren(); + _affixComponentRefs + ..addAll(items.map((affix) => _createComponentRef(affix))); + } - if (icon.shouldCloseMenuOnTrigger) _menuRoot?.closeHierarchy(); + void _updateItemProperties() { + for (final ref in _affixComponentRefs) { + if (ref.componentRef.isPresent) { + ref.componentRef.value.instance.disabled = disabled; + } } } - Icon getIcon(MenuItemAffix affix) { - IconAffix iconAffix = affix; - return iconAffix.icon; - } + _AffixRef _createComponentRef(BaseMenuItemAffixModel affix, + {int index = -1}) { + if (!affix.isVisible) return _AffixRef.hidden(affix); - String getText(MenuItemAffix affix) { - CaptionAffix captionAffix = affix; - return captionAffix.text; + return _AffixRef( + affix, + viewRef.createComponent(affix.componentFactory, index) + ..location.classes.add('affix') + ..instance.value = affix + ..instance.disabled = disabled); } } + +class _AffixRef { + final BaseMenuItemAffixModel affix; + final qc.Optional> componentRef; + + _AffixRef(this.affix, ComponentRef componentRef) + : componentRef = qc.Optional.of(componentRef); + _AffixRef.hidden(this.affix) : componentRef = qc.Optional.absent(); +} diff --git a/angular_components/lib/material_menu/menu_item_affix_list.html b/angular_components/lib/material_menu/menu_item_affix_list.html deleted file mode 100644 index 6df78987a..000000000 --- a/angular_components/lib/material_menu/menu_item_affix_list.html +++ /dev/null @@ -1,31 +0,0 @@ - - diff --git a/angular_components/lib/material_menu/menu_item_affix_list.scss b/angular_components/lib/material_menu/menu_item_affix_list.scss index 8bdc7c1a0..ea0e2fd0b 100644 --- a/angular_components/lib/material_menu/menu_item_affix_list.scss +++ b/angular_components/lib/material_menu/menu_item_affix_list.scss @@ -6,27 +6,15 @@ @import 'package:angular_components/material_menu/mixins'; :host { - display: block; + display: flex; + align-items: baseline; &:hover { @include menu-item-affix-hover; } -} - -.material-list-item-primary.caption-text { - margin: 0 $mat-grid; -} -.material-list-item-primary.secondary-icon { - transition: color $mat-transition $mat-transition-standard; - width: $mat-grid * 3; - - &:not(.disabled):hover { - color: $mat-transparent-black; + // Dynamically loaded components are not shimmed, hence the need for ::ng-deep. + ::ng-deep .affix:not(:first-child) { + margin-left: $mat-grid-type; } } - -.secondary-icon.hover-icon { - opacity: 0; - transition: opacity $mat-transition $mat-transition-standard; -} From 09841c6cacbab1ba26b15333ba3fd6ab28d820f8 Mon Sep 17 00:00:00 2001 From: tsander Date: Fri, 18 Jan 2019 11:05:55 -0800 Subject: [PATCH 045/503] Change the default for material-list-item to be a listitem rather than a button. Also change material-list to default to a list role. PiperOrigin-RevId: 229959061 --- angular_components/lib/material_list/material_list.dart | 7 +++++++ .../lib/material_list/material_list_item.dart | 2 +- angular_components/lib/material_menu/menu_item_groups.html | 1 + angular_components/lib/material_menu/menu_popup.html | 1 + .../lib/material_select/material_select.html | 2 +- 5 files changed, 11 insertions(+), 2 deletions(-) diff --git a/angular_components/lib/material_list/material_list.dart b/angular_components/lib/material_list/material_list.dart index d69b01550..c5febe196 100644 --- a/angular_components/lib/material_list/material_list.dart +++ b/angular_components/lib/material_list/material_list.dart @@ -52,4 +52,11 @@ class MaterialListComponent implements AcceptsWidth { size = MaterialListSize.values[val]; } } + + /// Role to apply to the material-list. + /// + /// Defaults to 'list' + @HostBinding('attr.role') + @Input() + String role = 'list'; } diff --git a/angular_components/lib/material_list/material_list_item.dart b/angular_components/lib/material_list/material_list_item.dart index 0a32b8872..5ecca0611 100644 --- a/angular_components/lib/material_list/material_list_item.dart +++ b/angular_components/lib/material_list/material_list_item.dart @@ -45,7 +45,7 @@ class MaterialListItemComponent extends ButtonDirective implements OnDestroy { MaterialListItemComponent(this.element, @Optional() this._dropdown, @Attribute('tabindex') this._hostTabIndex, @Attribute('role') String role) - : super(element, role) { + : super(element, role ?? 'listitem') { if (_dropdown != null) { _disposer.addDisposable(trigger.listen(handleActivate)); } diff --git a/angular_components/lib/material_menu/menu_item_groups.html b/angular_components/lib/material_menu/menu_item_groups.html index 97dd5da52..2f85a0e6c 100644 --- a/angular_components/lib/material_menu/menu_item_groups.html +++ b/angular_components/lib/material_menu/menu_item_groups.html @@ -110,6 +110,7 @@ #submenu> - +
Date: Fri, 18 Jan 2019 15:33:25 -0800 Subject: [PATCH 046/503] [a11y] Make base ToolTipTarget smart enough to restore any previously defined aria-describedby value, after popup closes. This allows us to set a describeby for when the tooltip is closed. That way, when hovering over the tooltip, it will read out, for example. "Mouseover or hover over this icon for more information, button, haspopup, Maximum CPC Bid (optional)" When the popup is open, the describeby will point at the actual blob of text in the tooltip. Then when the popup closes, it will restore the previous describedby. PiperOrigin-RevId: 230005625 --- .../lib/src/material_tooltip/tooltip_target.dart | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/angular_components/lib/src/material_tooltip/tooltip_target.dart b/angular_components/lib/src/material_tooltip/tooltip_target.dart index 4b91f825c..ea569f939 100644 --- a/angular_components/lib/src/material_tooltip/tooltip_target.dart +++ b/angular_components/lib/src/material_tooltip/tooltip_target.dart @@ -211,6 +211,7 @@ abstract class TooltipTarget extends PopupSourceDirective { Tooltip _tooltip; final ViewContainerRef viewContainerRef; final HtmlElement _element; + String _previousDescribedbyId; TooltipTarget(DomPopupSourceFactory domPopupSourceFactory, this.viewContainerRef, this._element, String initAriaAttributes) @@ -237,12 +238,17 @@ abstract class TooltipTarget extends PopupSourceDirective { @override void onOpen() { if (_id == null) return; + _previousDescribedbyId = _element.getAttribute('aria-describedby'); _element.setAttribute('aria-describedby', _id); } @override void onClose() { if (_id == null) return; - _element.attributes.remove('aria-describedby'); + if (_previousDescribedbyId != null) { + _element.setAttribute('aria-describedby', _previousDescribedbyId); + } else { + _element.attributes.remove('aria-describedby'); + } } } From 1ab33ca9f6b187fe57bc21bfabfbb7d16b880d5f Mon Sep 17 00:00:00 2001 From: cpelling Date: Fri, 18 Jan 2019 15:39:59 -0800 Subject: [PATCH 047/503] Delete deprecated globalDateRangeBindings. PiperOrigin-RevId: 230006740 --- .../lib/material_datepicker/module.dart | 42 +++---------------- 1 file changed, 6 insertions(+), 36 deletions(-) diff --git a/angular_components/lib/material_datepicker/module.dart b/angular_components/lib/material_datepicker/module.dart index a4b67c32a..da8934d8e 100644 --- a/angular_components/lib/material_datepicker/module.dart +++ b/angular_components/lib/material_datepicker/module.dart @@ -5,7 +5,6 @@ import 'package:angular/angular.dart'; import 'package:quiver/time.dart'; import 'package:angular_components/laminate/popup/module.dart'; -import 'package:angular_components/model/date/date.dart'; import 'package:angular_components/model/date/time_zone_aware_clock.dart'; import 'model.dart'; @@ -48,40 +47,11 @@ const timeZoneAwareDatepickerProviders = [ // TODO(google): Remove this and fix clients. const _legacyClockBinding = Provider(Clock, useValue: clockValue); +/// DI token for specifying a default date range, intended to be consumed by +/// some client-specified bindings for a [DatepickerModel]. const defaultDateRange = OpaqueToken('defaultDateRange'); -const defaultDateComparison = OpaqueToken('defaultDateComparison'); - -/// Bindings to create a per-app global date range. This basically creates a -/// mutable [DatepickerComparison] reference to feed into the -/// material-date-range-picker component, and then exposes that same reference -/// as the immutable [DatepickerSelection] interface that other components or -/// services can then inject. -/// -/// If there's a binding to either the `defaultDateRange` or -/// `defaultDateComparison` tokens, these bindings will respect those. -/// For instance, a sensible set of bindings might look like: -/// -/// bindings = const [ -/// globalDateRangeBindings, -/// const Provider(defaultDateRangeToken, -/// useFactory: last7Days, deps: const [Clock]), -/// const Provider(Clock, useValue: const Clock()), -/// ]; -/// -/// (where `last7Days` comes from this package's `range.dart` library). -@Deprecated('These bindings are not generally useful for most use cases and ' - 'thus do not belong in this general-purpose library. Will be removed soon.') -const globalDateRangeBindings = [ - Provider(DatepickerModel, useFactory: modelFactory), - Provider(DatepickerSelection, useFactory: selectionFactory), -]; -@Injectable() -DatepickerModel modelFactory( - @Optional() @Inject(defaultDateComparison) DatepickerComparison cmp, - @Optional() @Inject(defaultDateRange) DatepickerDateRange range) => - DatepickerModel(cmp ?? DatepickerComparison.noComparison(range)); - -@Injectable() -DatepickerSelection selectionFactory(DatepickerModel model) => - DatepickerSelection.wrap(model); +/// DI token for specifying a default date range with a comparison range, +/// intended to be consumed by some client-specified bindings for a +/// [DatepickerModel]. +const defaultDateComparison = OpaqueToken('defaultDateComparison'); From d1860fa8b9bcdd6554b38263284e3449d2a02896 Mon Sep 17 00:00:00 2001 From: boydcharles Date: Fri, 18 Jan 2019 15:58:48 -0800 Subject: [PATCH 048/503] Add doc comment to mat. dropdown select selection input about deselectOnActivate Provide a warning to other users about some unexpected behavior when using SingleSelectionModel so they don't spend time debugging as I did. Long term I think we should change the default for deselectOnActivate to false for SingleSelectionModel. PiperOrigin-RevId: 230009641 --- .../lib/material_select/material_dropdown_select.dart | 2 +- .../lib/material_select/material_dropdown_select.md | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/angular_components/lib/material_select/material_dropdown_select.dart b/angular_components/lib/material_select/material_dropdown_select.dart index 1024cc2c6..7e1a16250 100644 --- a/angular_components/lib/material_select/material_dropdown_select.dart +++ b/angular_components/lib/material_select/material_dropdown_select.dart @@ -140,7 +140,7 @@ class MaterialDropdownSelectComponent extends MaterialSelectBase bool _deselectOnActivate = true; - /// Whether to deselect a selected option on click or enter/space key. + /// Whether to deselect a selected option on click or enter/space key. /// /// Single selection model only. Defaults to true. @Input() diff --git a/angular_components/lib/material_select/material_dropdown_select.md b/angular_components/lib/material_select/material_dropdown_select.md index 044c4ebb7..013f200a9 100644 --- a/angular_components/lib/material_select/material_dropdown_select.md +++ b/angular_components/lib/material_select/material_dropdown_select.md @@ -65,3 +65,9 @@ multi select, it will a list of selected values or an empty list. For simpler single select use cases, you can use the `[(selection)]` syntax to setup two-way binding for your selected value. + +**Important** If using SingleSelectionModel, this component will both deselect +and then reselect on selection changes (two events) and +SingleSelectionModel.selectedValue may become null unless +[`deselectOnActivate`](https://github.com/dart-lang/angular_components/blob/master/angular_components/lib/material_select/material_dropdown_select.dart?q=deselectOnActivate) +is set to false. From 3bdc13a55fbae89b694dada423f25705e9552b2c Mon Sep 17 00:00:00 2001 From: Googler Date: Fri, 18 Jan 2019 16:50:49 -0800 Subject: [PATCH 049/503] [a11y] Make material dropdown select support custom aria handling for each list item. PiperOrigin-RevId: 230017142 --- .../lib/material_select/handles_aria.dart | 18 ++++++++++++++++++ .../material_dropdown_select.dart | 7 +++++++ .../material_select_dropdown_item.dart | 11 ++++++++++- .../material_select/material_select_item.dart | 4 ++++ .../material_select/material_select_item.html | 1 + 5 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 angular_components/lib/material_select/handles_aria.dart diff --git a/angular_components/lib/material_select/handles_aria.dart b/angular_components/lib/material_select/handles_aria.dart new file mode 100644 index 000000000..e428b2df0 --- /dev/null +++ b/angular_components/lib/material_select/handles_aria.dart @@ -0,0 +1,18 @@ +// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// Custom dropdown item component implements this to indicate that it will +/// handle aria related tasks by itself. +/// +/// If a custom widget implements this interface, then the parent +/// will no longer generate a custom id attribute +/// or set the aria role = "option". Instead, the custom component is expected +/// to handle the following tasks by itself: +/// - set role = "option" +/// - generate a unique id for itself, using the parent's ActiveItemModel +/// - set aria-selected=true, whenever it becomes selected. +/// +/// Primary use cases for implementing interface is to enable the ability to +/// do custom aria-describedby, or other such a11y related behaviors. +class HandlesAria {} diff --git a/angular_components/lib/material_select/material_dropdown_select.dart b/angular_components/lib/material_select/material_dropdown_select.dart index 7e1a16250..e74772d43 100644 --- a/angular_components/lib/material_select/material_dropdown_select.dart +++ b/angular_components/lib/material_select/material_dropdown_select.dart @@ -78,6 +78,10 @@ import 'package:angular_components/utils/id_generator/id_generator.dart'; Typed>(on: 'emptyGroupLabel'), Typed.of([#T]), ], + viewProviders: [ + FactoryProvider(ActiveItemModel, fromDropdown, + deps: [MaterialDropdownSelectComponent]) + ], templateUrl: 'material_dropdown_select.html', styleUrls: ['material_dropdown_select.scss.css'], visibility: Visibility.all, // injected by directives @@ -596,3 +600,6 @@ class ActivateItemOnKeyPressMixin { return key; } } + +ActiveItemModel fromDropdown(MaterialDropdownSelectComponent dropdown) => + dropdown.activeModel; diff --git a/angular_components/lib/material_select/material_select_dropdown_item.dart b/angular_components/lib/material_select/material_select_dropdown_item.dart index 87222e801..00a4374c8 100644 --- a/angular_components/lib/material_select/material_select_dropdown_item.dart +++ b/angular_components/lib/material_select/material_select_dropdown_item.dart @@ -9,6 +9,7 @@ import 'package:angular_components/dynamic_component/dynamic_component.dart'; import 'package:angular_components/glyph/glyph.dart'; import 'package:angular_components/material_checkbox/material_checkbox.dart'; import 'package:angular_components/material_select/activation_handler.dart'; +import 'package:angular_components/material_select/handles_aria.dart'; import 'package:angular_components/material_select/material_select_item.dart'; import 'package:angular_components/mixins/material_dropdown_base.dart'; import 'package:angular_components/model/selection/selection_container.dart'; @@ -48,13 +49,15 @@ class MaterialSelectDropdownItemComponent /// The id of the element. @HostBinding('attr.id') - String get id => _id ?? _generatedId; + String get id => _customAriaHandling ? null : (_id ?? _generatedId); @Input() set id(String id) { _id = id; } + bool _customAriaHandling = false; + MaterialSelectDropdownItemComponent( HtmlElement element, @Attribute('role') String role, @@ -76,4 +79,10 @@ class MaterialSelectDropdownItemComponent void preventTextSelectionIfShiftKey(MouseEvent e) { if (e.shiftKey) e.preventDefault(); } + + @override + void onLoadCustomComponent(ComponentRef ref) { + _customAriaHandling = ref?.instance is HandlesAria; + if (_customAriaHandling) role = null; + } } diff --git a/angular_components/lib/material_select/material_select_item.dart b/angular_components/lib/material_select/material_select_item.dart index dc905ff39..9aeb578ca 100644 --- a/angular_components/lib/material_select/material_select_item.dart +++ b/angular_components/lib/material_select/material_select_item.dart @@ -6,6 +6,7 @@ import 'dart:async'; import 'dart:html'; import 'package:angular/angular.dart'; +import 'package:angular/meta.dart'; import 'package:angular_components/button_decorator/button_decorator.dart'; import 'package:angular_components/dynamic_component/dynamic_component.dart'; import 'package:angular_components/glyph/glyph.dart'; @@ -270,6 +271,9 @@ class MaterialSelectItemComponent extends ButtonDirective } } + @visibleForTemplate + void onLoadCustomComponent(ComponentRef ref) {} + @override void ngOnDestroy() { _disposer.dispose(); diff --git a/angular_components/lib/material_select/material_select_item.html b/angular_components/lib/material_select/material_select_item.html index 7dc70a31a..98be41df3 100644 --- a/angular_components/lib/material_select/material_select_item.html +++ b/angular_components/lib/material_select/material_select_item.html @@ -27,6 +27,7 @@ &ngsp; From 54e54646031cbe4bf41298ac69979b363a6fb994 Mon Sep 17 00:00:00 2001 From: hcameron Date: Mon, 21 Jan 2019 07:27:10 -0800 Subject: [PATCH 050/503] Internal cleanup PiperOrigin-RevId: 230224635 --- angular_components/lib/css/_core_material.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/angular_components/lib/css/_core_material.scss b/angular_components/lib/css/_core_material.scss index b29362ab8..21bcdff06 100644 --- a/angular_components/lib/css/_core_material.scss +++ b/angular_components/lib/css/_core_material.scss @@ -2,6 +2,7 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. + // Grid $mat-grid: 8px; $mat-grid-type: 4px; From 40ca5b77550e6015363ecf57c2919aa6a287ad46 Mon Sep 17 00:00:00 2001 From: Googler Date: Tue, 22 Jan 2019 07:39:01 -0800 Subject: [PATCH 051/503] Enable onPush for material popup component. PiperOrigin-RevId: 230337746 --- angular_components/lib/material_popup/material_popup.dart | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/angular_components/lib/material_popup/material_popup.dart b/angular_components/lib/material_popup/material_popup.dart index be35117dd..dc194fd3c 100644 --- a/angular_components/lib/material_popup/material_popup.dart +++ b/angular_components/lib/material_popup/material_popup.dart @@ -36,13 +36,6 @@ export 'package:angular_components/laminate/popup/popup.dart' /// [PopupInterface]. /// /// This is useful if content size is such that adds scroll to the page. -/// - Even though this component supports [ChangeDetectionStrategy.OnPush] -/// for the cases tested in examples, it does not set ChangeDetectionStrategy. -/// This means that usage of this component within another component in OnPush -/// mode is possible but at the implementors discretion since any such -/// implementation would require all it's content children to support OnPush -/// as well. -/// /// - If the contents change and need to readjust position use /// [trackLayoutChanges] which is also defined in [PopupInterface]. /// @@ -75,6 +68,7 @@ export 'package:angular_components/laminate/popup/popup.dart' // TODO(google): Change preserveWhitespace to false to improve codesize. preserveWhitespace: true, visibility: Visibility.all, // injected by hierarchy + changeDetection: ChangeDetectionStrategy.OnPush, ) class MaterialPopupComponent extends Object with PopupBase, PopupEvents, PopupHierarchyElement From 8cbd232c70ed4feeb14f677960c42773bf6fe3d1 Mon Sep 17 00:00:00 2001 From: Googler Date: Tue, 22 Jan 2019 07:42:04 -0800 Subject: [PATCH 052/503] Update MaterialDropdownSelectComponent so it can work with onPush. Currently if I embed the component within an onPush enabled component, the dropdown does not work. And I cannot simply enable onPush on MaterialDropdownSelectComponent directly, because one of its dependent component uses dynamic component, and would require ALL its users to be onPush. PiperOrigin-RevId: 230338110 --- .../lib/material_select/material_dropdown_select.dart | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/angular_components/lib/material_select/material_dropdown_select.dart b/angular_components/lib/material_select/material_dropdown_select.dart index e74772d43..d9351f81b 100644 --- a/angular_components/lib/material_select/material_dropdown_select.dart +++ b/angular_components/lib/material_select/material_dropdown_select.dart @@ -174,12 +174,15 @@ class MaterialDropdownSelectComponent extends MaterialSelectBase String _ariaActiveDescendant; + final ChangeDetectorRef _changeDetector; + MaterialDropdownSelectComponent( @Optional() IdGenerator idGenerator, @Optional() @SkipSelf() this._popupSizeDelegate, @Optional() @Inject(rtlToken) bool rtl, @Attribute('popupClass') String popupClass, @Attribute('buttonAriaRole') this.buttonAriaRole, + this._changeDetector, HtmlElement element) : activeModel = ActiveItemModel(idGenerator), popupClassName = constructEncapsulatedCss(popupClass, element.classes), @@ -252,6 +255,7 @@ class MaterialDropdownSelectComponent extends MaterialSelectBase /// Whether the dropdown is visible. @override set visible(bool value) { + _changeDetector.markForCheck(); super.visible = value; resetEnteredKeys(); if (value) { @@ -277,6 +281,7 @@ class MaterialDropdownSelectComponent extends MaterialSelectBase @override set options(SelectionOptions newOptions) { + _changeDetector.markForCheck(); super.options = newOptions; _updateActiveModel(); @@ -284,6 +289,7 @@ class MaterialDropdownSelectComponent extends MaterialSelectBase _optionsListener?.cancel(); _optionsListener = options?.stream?.listen((_) { + _changeDetector.markForCheck(); _updateActiveModel(); _setInitialActiveItem(); }); @@ -315,11 +321,13 @@ class MaterialDropdownSelectComponent extends MaterialSelectBase @override set selection(SelectionModel newSelection) { + _changeDetector.markForCheck(); super.selection = newSelection; _setInitialActiveItem(); _selectionListener?.cancel(); _selectionListener = selection?.selectionChanges?.listen((changes) { + _changeDetector.markForCheck(); // Update active item if new items are selected. var added = changes.last.added.isNotEmpty ? changes.last.added.first : null; From eed6431c99d26f7ff49a0fe87b563a3446012413 Mon Sep 17 00:00:00 2001 From: srawlins Date: Tue, 22 Jan 2019 09:35:58 -0800 Subject: [PATCH 053/503] Fix pre-existing issues with shadowing type parameters. In each change, there is a type paramter, T, on a method in a class which is also parameterized with a type parameter T. Shadowing should be avoided [1]. In a few cases, I believe the method actually needs no parameter, so I removed it. In most cases, I just renamed the type parameter on the method to S, and flipped all uses of T as a type argument inside the method (including return type) to also use S. It would probably be good to double-check my choices. [1] https://www.dartlang.org/guides/language/effective-dart/design#do-follow-existing-mnemonic-conventions-when-naming-type-parameters PiperOrigin-RevId: 230355420 --- .../lib/src/model/selection/delegating_selection_model.dart | 2 +- .../lib/src/model/selection/noop_selection_model_impl.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/angular_components/lib/src/model/selection/delegating_selection_model.dart b/angular_components/lib/src/model/selection/delegating_selection_model.dart index 6fca36203..169917384 100644 --- a/angular_components/lib/src/model/selection/delegating_selection_model.dart +++ b/angular_components/lib/src/model/selection/delegating_selection_model.dart @@ -54,7 +54,7 @@ class DelegatingSelectionModel extends Object } @override - T notifyPropertyChange(Symbol field, T oldValue, T newValue) { + S notifyPropertyChange(Symbol field, S oldValue, S newValue) { _delegateModel.notifyPropertyChange(field, oldValue, newValue); return newValue; } diff --git a/angular_components/lib/src/model/selection/noop_selection_model_impl.dart b/angular_components/lib/src/model/selection/noop_selection_model_impl.dart index 4f5e19718..0dd08a230 100644 --- a/angular_components/lib/src/model/selection/noop_selection_model_impl.dart +++ b/angular_components/lib/src/model/selection/noop_selection_model_impl.dart @@ -34,7 +34,7 @@ class _NoopSelectionModelImpl implements SingleSelectionModel { void notifyChange([_]) {} @override - T notifyPropertyChange(Symbol field, T oldValue, T newValue) => null; + S notifyPropertyChange(Symbol field, S oldValue, S newValue) => null; @override void observed() {} From d4d4ff6b211eb18cd6ebd93304682095494fc86e Mon Sep 17 00:00:00 2001 From: hcameron Date: Tue, 22 Jan 2019 09:38:09 -0800 Subject: [PATCH 054/503] add missing import to typography_material. PiperOrigin-RevId: 230355872 --- angular_components/lib/css/_typography_material.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/angular_components/lib/css/_typography_material.scss b/angular_components/lib/css/_typography_material.scss index 48aedffc1..7c14d19e1 100644 --- a/angular_components/lib/css/_typography_material.scss +++ b/angular_components/lib/css/_typography_material.scss @@ -5,6 +5,8 @@ // Typography constants // https://material.io/design/typography +@import 'color_material'; + // Roboto font stack. $mat-font-family: Roboto, Noto, sans-serif; From 7532590e0476bffa6323ae5031ea2ea48614ff6a Mon Sep 17 00:00:00 2001 From: tsander Date: Tue, 22 Jan 2019 20:42:20 -0800 Subject: [PATCH 055/503] If the multi-line input is not currently in the DOM listen to DOM updates until the line height can be read. PiperOrigin-RevId: 230463619 --- .../lib/material_input/material_input_multiline.dart | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/angular_components/lib/material_input/material_input_multiline.dart b/angular_components/lib/material_input/material_input_multiline.dart index b6ef9d5dc..44347a1b9 100644 --- a/angular_components/lib/material_input/material_input_multiline.dart +++ b/angular_components/lib/material_input/material_input_multiline.dart @@ -2,6 +2,7 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +import 'dart:async'; import 'dart:html'; import 'package:angular/angular.dart'; @@ -55,6 +56,8 @@ class MaterialMultilineInputComponent extends BaseMaterialInput final ChangeDetectorRef _changeDetector; final DomService _domService; + StreamSubscription _subscription; + @ViewChild('textareaEl') ElementRef textareaEl; @@ -121,10 +124,17 @@ class MaterialMultilineInputComponent extends BaseMaterialInput var height = (value.nativeElement as Element).clientHeight; if (height != 0) { _inputLineHeight = height; + _subscription?.cancel(); + _subscription = null; _changeDetector ..markForCheck() // TODO(google): remove after the bug is fixed. ..detectChanges(); + } else if (_subscription == null) { + // Listen to dom changes until we can read the line height. + _subscription = _domService.onLayoutChanged.listen((_) { + lineHeightMeasure = value; + }); } }); } @@ -161,6 +171,8 @@ class MaterialMultilineInputComponent extends BaseMaterialInput @override void ngOnDestroy() { super.ngOnDestroy(); + _subscription?.cancel(); + _subscription = null; textareaEl = null; popupSourceEl = null; } From a34b7a7eae07a25a146858d9baf51103186e1cb8 Mon Sep 17 00:00:00 2001 From: tsander Date: Tue, 22 Jan 2019 21:55:03 -0800 Subject: [PATCH 056/503] Rollback of changelist 222351562. *** Reason for rollback *** Breaks keyboard only navigation. *** Original change description *** Reduce some weirdness when mixing mouse and keyboard interactions in material dropdown select. *** PiperOrigin-RevId: 230469523 --- .../lib/material_select/material_dropdown_select.dart | 5 ----- 1 file changed, 5 deletions(-) diff --git a/angular_components/lib/material_select/material_dropdown_select.dart b/angular_components/lib/material_select/material_dropdown_select.dart index d9351f81b..6ae13a336 100644 --- a/angular_components/lib/material_select/material_dropdown_select.dart +++ b/angular_components/lib/material_select/material_dropdown_select.dart @@ -307,15 +307,11 @@ class MaterialDropdownSelectComponent extends MaterialSelectBase StreamController _blur = StreamController.broadcast(sync: true); - bool _isFocused = false; - void onFocus(FocusEvent event) { - _isFocused = true; _focus.add(event); } void onBlur(FocusEvent event) { - _isFocused = false; _blur.add(event); } @@ -364,7 +360,6 @@ class MaterialDropdownSelectComponent extends MaterialSelectBase void _handleNavigationKey(KeyboardEvent event, Function activateFunction) { if (disabled) return; event.preventDefault(); - if (!_isFocused) dropdownButton.focus(); activateFunction(); // Only select if the popup is not visible. if (!visible && selection != null && isSingleSelect) { From 53a970ca3bae8b3ba413ede1854b1bf7855ddc21 Mon Sep 17 00:00:00 2001 From: Googler Date: Wed, 23 Jan 2019 02:44:51 -0800 Subject: [PATCH 057/503] Create mixin to make tab-content display: block PiperOrigin-RevId: 230496960 --- angular_components/lib/material_tab/_mixins.scss | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/angular_components/lib/material_tab/_mixins.scss b/angular_components/lib/material_tab/_mixins.scss index aab7b581e..c17b2d5bf 100644 --- a/angular_components/lib/material_tab/_mixins.scss +++ b/angular_components/lib/material_tab/_mixins.scss @@ -34,7 +34,7 @@ $_focusTabBtnSel: $_tabBtnSel + '.focus'; } // Tab Panel -// Sets the dafault color, selected tab color and selected tab indicator color +// Sets the default color, selected tab color and selected tab indicator color // @Deprecated: use tab-strip-color directly instead. @mixin tab-panel-color($selector, $color, $accent-color) { @include tab-panel-tab-color($selector, $color); @@ -66,7 +66,7 @@ $_focusTabBtnSel: $_tabBtnSel + '.focus'; } // Tab Strip -// Sets the dafault color, selected tab color and selected tab indicator color +// Sets the default color, selected tab color and selected tab indicator color @mixin tab-strip-color($selector, $color, $accent-color) { @include tab-strip-tab-color($selector, $color); @include tab-strip-accent-color($selector, $accent-color); @@ -145,3 +145,10 @@ $_focusTabBtnSel: $_tabBtnSel + '.focus'; white-space: initial; } } + +// Make the tab-content a block display rather than the default, flex. +@mixin tab-content-block { + ::ng-deep material-tab .tab-content.tab-content { + display: block; + } +} From dc6a842936583de3a1e4c98cf4163bae7bbe3744 Mon Sep 17 00:00:00 2001 From: nshahan Date: Wed, 23 Jan 2019 12:43:24 -0800 Subject: [PATCH 058/503] Add ability to display basic documentation from .scss files to the ACX gallery - Triple slash comments are extracted for variables, functions and mixins. - Comments are treated as markdown and rendered as HTML in the gallery. - Collect additional info: - Variables: name and the value expression. - Functions and Mixins: name, argument names and default values, rest argument. - Skips collecting information for variables, functions, mixins, and args when their names start with an underscore. - Add docs for app layout mixins. PiperOrigin-RevId: 230582813 --- .../lib/app_layout/_mixins.scss | 4 +- .../lib/builder/component_api_builder.dart | 2 + .../lib/builder/gallery_info_builder.dart | 20 ++- .../template/component.api.dart.mustache | 41 ++++++ .../documentation_component.dart | 24 ++++ .../gallery_component/documentation_info.dart | 125 +++++++++++++++++- .../gallery_component/gallery_component.dart | 2 +- .../gallery_component/gallery_component.html | 5 + .../gallery_component/sass_doc_component.html | 38 ++++++ .../lib/sass_docs_extraction.dart | 64 +++++++++ examples/app_layout_example/lib/examples.dart | 3 +- 11 files changed, 317 insertions(+), 11 deletions(-) create mode 100644 angular_gallery_section/lib/components/gallery_component/sass_doc_component.html create mode 100644 angular_gallery_section/lib/sass_docs_extraction.dart diff --git a/angular_components/lib/app_layout/_mixins.scss b/angular_components/lib/app_layout/_mixins.scss index 7b108b676..a024df115 100644 --- a/angular_components/lib/app_layout/_mixins.scss +++ b/angular_components/lib/app_layout/_mixins.scss @@ -8,7 +8,7 @@ /// /// Must be applied to the component itself, e.g.: /// -/// ``` +/// ```scss /// material-drawer { /// @include mat-drawer-width(512px); /// } @@ -78,7 +78,7 @@ /// /// Should be applied to the component itself, e.g.: /// -/// ``` +/// ```scss /// material-drawer[temporary] { /// @include mat-temporary-drawer-width(512px); /// } diff --git a/angular_gallery_section/lib/builder/component_api_builder.dart b/angular_gallery_section/lib/builder/component_api_builder.dart index f562ce517..1b50ff1c5 100644 --- a/angular_gallery_section/lib/builder/component_api_builder.dart +++ b/angular_gallery_section/lib/builder/component_api_builder.dart @@ -72,8 +72,10 @@ class ComponentApiBuilder extends Builder { }, 'docs': config.docs?.map((doc) { var jsonMap = doc.toJson(); + // Add flags to identify the DocInfo constuctor to use later. jsonMap['dartDoc'] = doc.docType == DocType.dartDocInfo; jsonMap['markdownDoc'] = doc.docType == DocType.markdownDocInfo; + jsonMap['sassDoc'] = doc.docType == DocType.sassDocInfo; return jsonMap; })?.toList() ?? [], diff --git a/angular_gallery_section/lib/builder/gallery_info_builder.dart b/angular_gallery_section/lib/builder/gallery_info_builder.dart index 254ec16df..a9ad8f5be 100644 --- a/angular_gallery_section/lib/builder/gallery_info_builder.dart +++ b/angular_gallery_section/lib/builder/gallery_info_builder.dart @@ -14,6 +14,7 @@ import 'package:angular_gallery_section/g3doc_markdown.dart'; import 'package:angular_gallery_section/gallery_docs_extraction.dart'; import 'package:angular_gallery_section/gallery_section_config_extraction.dart'; import 'package:angular_gallery_section/resolved_config.dart'; +import 'package:angular_gallery_section/sass_docs_extraction.dart'; import 'package:angular_gallery_section/components/gallery_component/documentation_info.dart'; import 'package:angular_gallery_section/visitors/path_utils.dart' as path_utils; @@ -107,13 +108,20 @@ class GalleryInfoBuilder extends Builder { }); } - /// Read the [markdownAsset] with [assetReader] and render as HTML. + /// Read the [externalAsset] with [assetReader] and collect documentation + /// information. + /// + /// Supports reading .md or .scss assets. Future _readExternalAsset( - String markdownAsset, AssetReader assetReader) async { - final assetId = AssetId.resolve(markdownAsset); + String externalAsset, AssetReader assetReader) async { + final assetId = AssetId.resolve(externalAsset); if (!await assetReader.canRead(assetId)) { - throw ('Counld not find the asset: $markdownAsset.'); + throw ('Counld not find the asset: $externalAsset.'); + } + + if (extension(assetId.path) == '.scss') { + return extractSassDocs('Sass Mixins', assetId, assetReader); } if (extension(assetId.path) == '.md') { @@ -125,8 +133,8 @@ class GalleryInfoBuilder extends Builder { ..contents = _replaceImgTags(g3docMarkdownToHtml(content)); } - throw ('Documentation generator only supports external files of type .md. ' - 'Can not load documentation from $assetId.'); + throw ('Documentation generator only supports external files of type .md ' + 'or .scss. Can not load documentation from $assetId.'); } /// Find the file that defines [identifier], and extract the documentation diff --git a/angular_gallery_section/lib/builder/template/component.api.dart.mustache b/angular_gallery_section/lib/builder/template/component.api.dart.mustache index f2b1e4271..8a3a5707a 100644 --- a/angular_gallery_section/lib/builder/template/component.api.dart.mustache +++ b/angular_gallery_section/lib/builder/template/component.api.dart.mustache @@ -61,6 +61,47 @@ class {{component}}Api { '{{path}}', applyHighlighting(r"""{{contents}}""")), {{/markdownDoc}} + {{#sassDoc}} + SassDocInfo( + '{{name}}', + '{{path}}', + [ + {{#variables}} + SassVariableInfo( + '{{name}}', + r"""{{expression}}""", + applyHighlighting(r"""{{comment}}""")), + {{/variables}} + ],[ + {{#functions}} + SassCallableInfo( + '{{name}}', + [ + {{#arguments}} + SassArgumentInfo( + '{{name}}', + r"""{{defaultValue}}"""), + {{/arguments}} + ], + '{{restArgument}}', + applyHighlighting(r"""{{comment}}""")), + {{/functions}} + ],[ + {{#mixins}} + SassCallableInfo( + '{{name}}', + [ + {{#arguments}} + SassArgumentInfo( + '{{name}}', + r"""{{defaultValue}}"""), + {{/arguments}} + ], + '{{restArgument}}', + applyHighlighting(r"""{{comment}}""")), + {{/mixins}} + ]), + {{/sassDoc}} {{/docs}} ], demos: [ diff --git a/angular_gallery_section/lib/components/gallery_component/documentation_component.dart b/angular_gallery_section/lib/components/gallery_component/documentation_component.dart index 37acb03d2..22ba9b6db 100644 --- a/angular_gallery_section/lib/components/gallery_component/documentation_component.dart +++ b/angular_gallery_section/lib/components/gallery_component/documentation_component.dart @@ -10,6 +10,7 @@ import 'package:angular_gallery_section/components/gallery_component/gallery_inf const documentationComponentDirectives = const [ DartDocComponent, MarkdownDocComponent, + SassDocComponent, ]; class DocumentationComponent { @@ -71,3 +72,26 @@ class MarkdownDocComponent extends DocumentationComponent { @Input() MarkdownDocInfo doc; } + +/// Displays documentation for Sass files in the gallery application. +/// +/// Includes documentation for all variables, functions and mixins avaliable +/// by importing the Sass file. +@Component( + selector: 'documentation-component[sass]', + directives: [ + NgFor, + NgIf, + SafeInnerHtmlDirective, + ], + templateUrl: 'sass_doc_component.html', + styleUrls: ['documentation_component.scss.css'], +) +class SassDocComponent extends DocumentationComponent { + SassDocComponent(DomSanitizationService santizationService) + : super(santizationService); + + /// The documentation to display. + @Input() + SassDocInfo doc; +} diff --git a/angular_gallery_section/lib/components/gallery_component/documentation_info.dart b/angular_gallery_section/lib/components/gallery_component/documentation_info.dart index 5ba27a5c7..cde9e0fd8 100644 --- a/angular_gallery_section/lib/components/gallery_component/documentation_info.dart +++ b/angular_gallery_section/lib/components/gallery_component/documentation_info.dart @@ -5,7 +5,7 @@ /// Encoding for different types of documenation for the gallery builders. /// /// Simplifies translating to and from JSON files between build steps. -enum DocType { dartDocInfo, markdownDocInfo } +enum DocType { dartDocInfo, markdownDocInfo, sassDocInfo } /// Base class for all documentation models in the gallery app. abstract class DocInfo { @@ -26,6 +26,10 @@ abstract class DocInfo { return MarkdownDocInfo.fromJson(jsonMap); } + if (docType == DocType.sassDocInfo.toString()) { + return SassDocInfo.fromJson(jsonMap); + } + throw FormatException( 'Unexpected docType found when constructing a DocInfo from JSON: ' '$docType.'); @@ -164,3 +168,122 @@ class MarkdownDocInfo implements DocInfo { 'contents': contents, }; } + +/// Documentation information for a Sass file listed in an @GallerySectionConfig +/// annotation. +class SassDocInfo implements DocInfo { + final String name; + final String path; + final Iterable variables; + final Iterable functions; + final Iterable mixins; + + DocType get docType => DocType.sassDocInfo; + + SassDocInfo( + this.name, this.path, this.variables, this.functions, this.mixins); + + /// Constructs a new [SassDocInfo] from a decoded json map. + SassDocInfo.fromJson(Map jsonMap) + : name = jsonMap['name'] as String, + path = jsonMap['path'] as String, + variables = (jsonMap['variables'] as Iterable) + ?.map((element) => SassVariableInfo.fromJson(element)), + functions = (jsonMap['functions'] as Iterable) + ?.map((element) => SassCallableInfo.fromJson(element)), + mixins = (jsonMap['mixins'] as Iterable) + ?.map((element) => SassCallableInfo.fromJson(element)); + + /// Returns a json encodeable representation of this [SassDocInfo]. + Map toJson() => { + 'docType': docType.toString(), + 'name': name, + 'path': path, + 'variables': variables?.map((v) => v.toJson())?.toList(), + 'functions': functions?.map((f) => f.toJson())?.toList(), + 'mixins': mixins?.map((m) => m.toJson())?.toList(), + }; +} + +/// Documentation information for a Sass variable. +class SassVariableInfo { + final String name; + final String expression; + final String comment; + + SassVariableInfo(this.name, this.expression, this.comment); + + /// Constructs a new [SassVariableInfo] from a decoded json map. + SassVariableInfo.fromJson(Map jsonMap) + : name = jsonMap['name'] as String, + expression = jsonMap['expression'] as String, + comment = jsonMap['comment'] as String; + + /// Returns a json encodeable representation of this [SassVariableInfo]. + Map toJson() => { + 'name': name, + 'expression': expression, + 'comment': comment, + }; +} + +/// Documentation information for a Sass callable (function or mixin). +class SassCallableInfo { + final String name; + final Iterable arguments; + final String restArgument; + final String comment; + + SassCallableInfo(this.name, this.arguments, this.restArgument, this.comment); + + /// Constructs a new [SassCallableInfo] from a decoded json map. + SassCallableInfo.fromJson(Map jsonMap) + : name = jsonMap['name'] as String, + arguments = (jsonMap['arguments'] as Iterable) + ?.map((element) => SassArgumentInfo.fromJson(element)), + restArgument = jsonMap['restArgument'], + comment = jsonMap['comment'] as String; + + /// Returns a json encodeable representation of this [SassCallableInfo]. + Map toJson() => { + 'name': name, + 'arguments': arguments?.map((arg) => arg.toJson())?.toList(), + 'restArgument': restArgument, + 'comment': comment, + }; + + /// A simple signature represtation of this callable. + /// + /// Includes the name and arguments including a rest arg. + String get signature { + if (arguments == null || arguments.isEmpty) return name; + var args = arguments + .map((a) => a.defaultValue == null || a.defaultValue.isEmpty + ? '\$${a.name}' + : '\$${a.name}: ${a.defaultValue}') + .join(', '); + if (restArgument != null && restArgument.isNotEmpty) { + args = '$args, \$$restArgument...'; + } + return '$name( $args )'; + } +} + +/// Documentation information for a Sass callable's argument. +class SassArgumentInfo { + final String name; + final String defaultValue; + + SassArgumentInfo(this.name, this.defaultValue); + + /// Constructs a new [SassArgumentInfo] from a decoded json map. + SassArgumentInfo.fromJson(Map jsonMap) + : name = jsonMap['name'] as String, + defaultValue = jsonMap['defaultValue'] as String; + + /// Returns a json encodeable representation of this [SassArgumentInfo]. + Map toJson() => { + 'name': name, + 'defaultValue': defaultValue, + }; +} diff --git a/angular_gallery_section/lib/components/gallery_component/gallery_component.dart b/angular_gallery_section/lib/components/gallery_component/gallery_component.dart index 605b34b42..11228c2cf 100644 --- a/angular_gallery_section/lib/components/gallery_component/gallery_component.dart +++ b/angular_gallery_section/lib/components/gallery_component/gallery_component.dart @@ -44,7 +44,7 @@ class GalleryComponent { bool get showToc => (model.docs.length + model.demos.length + model.benchmarks.length) > 1; - String getDocId(DocInfo doc) => '${doc.name}Doc'; + String getDocId(DocInfo doc) => '${doc.name.replaceAll(' ', '_')}Doc'; String getDemoId(Demo demo) => '${demo.name}Demo'; diff --git a/angular_gallery_section/lib/components/gallery_component/gallery_component.html b/angular_gallery_section/lib/components/gallery_component/gallery_component.html index 21f89540a..01d24be75 100644 --- a/angular_gallery_section/lib/components/gallery_component/gallery_component.html +++ b/angular_gallery_section/lib/components/gallery_component/gallery_component.html @@ -75,6 +75,11 @@

[doc]="doc" [showGeneratedDocs]="model.showGeneratedDocs"> + +

diff --git a/angular_gallery_section/lib/components/gallery_component/sass_doc_component.html b/angular_gallery_section/lib/components/gallery_component/sass_doc_component.html new file mode 100644 index 000000000..72ff83c6a --- /dev/null +++ b/angular_gallery_section/lib/components/gallery_component/sass_doc_component.html @@ -0,0 +1,38 @@ + + + Variables: +
    +
  • + + ${{variable.name}}: {{variable.expression}}; + +
    +
    +
  • +
+
+ + + Functions: +
    +
  • + {{function.signature}} +
    +
    +
  • +
+
+ + + Mixins: +
    +
  • + {{mix.signature}} +
    +
  • +
+
diff --git a/angular_gallery_section/lib/sass_docs_extraction.dart b/angular_gallery_section/lib/sass_docs_extraction.dart new file mode 100644 index 000000000..bf633699d --- /dev/null +++ b/angular_gallery_section/lib/sass_docs_extraction.dart @@ -0,0 +1,64 @@ +// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:build/build.dart'; +import 'package:sass/src/ast/sass.dart'; +import 'package:angular_gallery_section/g3doc_markdown.dart'; +import 'package:angular_gallery_section/components/gallery_component/documentation_info.dart'; +import 'package:angular_gallery_section/visitors/path_utils.dart' as path_utils; + +/// Collects documentation information from a Sass file identified by [assetId]. +/// +/// Assigns [name] as a readable identifier for the docs. Will read [assetId] +/// with [assetReader]. Does not collect documentation for variables, functions +/// and mixins when their name starts with an underscore. +Future extractSassDocs( + String name, AssetId assetId, AssetReader assetReader) async { + final contents = await assetReader.readAsString(assetId); + final stylesheet = Stylesheet.parseScss(contents); + final variableDeclarations = []; + final functionRules = []; + final mixinRules = []; + + for (var node in stylesheet.children) { + // Collect the variables, functions and mixins that do not have names + // starting with an underscore. + if (node is VariableDeclaration && !node.name.startsWith('_')) { + variableDeclarations.add(SassVariableInfo( + node.name, node.expression.toString(), _formatComment(node.comment))); + } else if (node is FunctionRule && !node.name.startsWith('_')) { + functionRules.add(_extractCallable(node)); + } else if (node is MixinRule && !node.name.startsWith('_')) { + mixinRules.add(_extractCallable(node)); + } + } + + return SassDocInfo(name, path_utils.assetToPath(assetId.toString()), + variableDeclarations, functionRules, mixinRules); +} + +/// Gathers the information needed to document a [callable] (function or +/// mixin). +/// +/// Skips arguments when their names starts with an underscore. +SassCallableInfo _extractCallable(CallableDeclaration callable) { + final args = callable.arguments.arguments + .map((arg) => SassArgumentInfo(arg.name, arg.defaultValue?.toString())); + var restArg = callable.arguments.restArgument; + restArg = restArg != null && !restArg.startsWith('_') ? restArg : null; + return SassCallableInfo( + callable.name, + args.where((arg) => !arg.name.startsWith('_')), + restArg, + _formatComment(callable.comment)); +} + +/// Extracts any documentation (triple slash) comments from [silentComment]. +/// +/// The comment text is assumed to be markdown and converted to HTML. +String _formatComment(SilentComment silentComment) { + if (silentComment?.docComment == null) return ''; + + return g3docMarkdownToHtml(silentComment.docComment); +} diff --git a/examples/app_layout_example/lib/examples.dart b/examples/app_layout_example/lib/examples.dart index 687c27a3f..434b48239 100644 --- a/examples/app_layout_example/lib/examples.dart +++ b/examples/app_layout_example/lib/examples.dart @@ -3,8 +3,8 @@ // BSD-style license that can be found in the LICENSE file. import 'package:angular_components/app_layout/material_persistent_drawer.dart'; -import 'package:angular_components/app_layout/material_temporary_drawer.dart'; import 'package:angular_components/app_layout/material_stackable_drawer.dart'; +import 'package:angular_components/app_layout/material_temporary_drawer.dart'; import 'stacking_drawer_example.dart'; import 'package:angular_gallery_section/annotation/gallery_section_config.dart'; @@ -15,6 +15,7 @@ import 'mobile_app_layout_example.dart'; displayName: 'App Layout', docs: [ 'package:angular_components/app_layout/README.md', + 'package:angular_components/app_layout/_mixins.scss', MaterialPersistentDrawerDirective, MaterialTemporaryDrawerComponent, MaterialStackableDrawerComponent, From e52d8957adff045576c9bde77f1ce7153cf7f229 Mon Sep 17 00:00:00 2001 From: Googler Date: Wed, 23 Jan 2019 14:50:01 -0800 Subject: [PATCH 059/503] Sync TextField from MDC v0.42.0 PiperOrigin-RevId: 230607823 --- .../lib/css/mdc_web/shape/_mixins.scss | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/angular_components/lib/css/mdc_web/shape/_mixins.scss b/angular_components/lib/css/mdc_web/shape/_mixins.scss index b439f74b8..89a1ac3e9 100644 --- a/angular_components/lib/css/mdc_web/shape/_mixins.scss +++ b/angular_components/lib/css/mdc_web/shape/_mixins.scss @@ -24,11 +24,19 @@ @import "./functions"; @mixin mdc-shape-radius($radius, $rtl-reflexive: false) { + // Even if $rtl-reflexive is true, only emit RTL styles if we can't easily tell that the given radius is symmetrical + $needs-flip: $rtl-reflexive and length($radius) > 1; + + @if ($needs-flip) { + /* @noflip */ + } + border-radius: mdc-shape-prop-value($radius); - @if ($rtl-reflexive) { + @if ($needs-flip) { @include mdc-rtl { - border-radius: mdc-shape-flip-radius($radius); + /* @noflip */ + border-radius: mdc-shape-flip-radius(mdc-shape-prop-value($radius)); } } } From 1342b4dc57c802a7b9cb3a7cfaaed38d77741653 Mon Sep 17 00:00:00 2001 From: tsander Date: Wed, 23 Jan 2019 18:34:20 -0800 Subject: [PATCH 060/503] Ensure only whitespace is considered an invalid number input. PiperOrigin-RevId: 230642594 --- .../lib/material_input/material_number_accessor.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/angular_components/lib/material_input/material_number_accessor.dart b/angular_components/lib/material_input/material_number_accessor.dart index 796fef302..ebe4c1f08 100644 --- a/angular_components/lib/material_input/material_number_accessor.dart +++ b/angular_components/lib/material_input/material_number_accessor.dart @@ -165,7 +165,7 @@ class MaterialNumberValidator implements Validator { // If the control doesn't have a value, but had a value from the input then // it is considered an error. Producing error here as accessors can't easily // add errors themselves, but validators can. - if (control.value == null && !isBlank((control as Control).rawValue)) { + if (control.value == null && !isEmpty((control as Control).rawValue)) { return {inputNotNumberErrorKey: inputIsNotNumberMsg()}; } return null; From 9316acfaad43dc8661d85a5f85d4f1d6c31e9411 Mon Sep 17 00:00:00 2001 From: Googler Date: Thu, 24 Jan 2019 10:21:03 -0800 Subject: [PATCH 061/503] Add a word break mixin for the ink tooltip PiperOrigin-RevId: 230744685 --- .../lib/material_tooltip/_mixins.scss | 29 +++++++++++++++---- .../lib/src/material_tooltip/ink_tooltip.dart | 15 ++++++++-- .../lib/src/material_tooltip/tooltip.dart | 8 ++++- 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/angular_components/lib/material_tooltip/_mixins.scss b/angular_components/lib/material_tooltip/_mixins.scss index a33413d7f..16b45a852 100644 --- a/angular_components/lib/material_tooltip/_mixins.scss +++ b/angular_components/lib/material_tooltip/_mixins.scss @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +@import 'package:angular_components/material_popup/mixins'; + /// Exposes the material-icon color of . @mixin material-icon-tooltip-theme($primary-color, $active-color: $primary-color) { @@ -34,21 +36,36 @@ /// Overrides the default maximum width of . @mixin material-tooltip-card-max-width($max-width: 50 * $mat-grid) { - ::ng-deep .popup .material-popup-content .paper-container { - max-width: $max-width; + @include material-popup-style { + .paper-container { + max-width: $max-width; + } } } /// Overrides the default maximum height of . @mixin material-tooltip-card-max-height($max-height: 50 * $mat-grid) { - ::ng-deep .popup .material-popup-content .paper-container { - max-height: $max-height; + @include material-popup-style { + .paper-container { + max-height: $max-height; + } } } /// Overrides the default padding of . @mixin material-tooltip-card-padding($padding: $mat-grid * 3) { - ::ng-deep .popup .material-popup-content .paper-container { - padding: $padding; + @include material-popup-style { + .paper-container { + padding: $padding; + } + } +} + +/// Adds a word break property to or [materialTooltip]. +@mixin ink-tooltip-word-break($word-break: break-word) { + @include material-popup-style { + .ink-container { + word-break: $word-break; + } } } diff --git a/angular_components/lib/src/material_tooltip/ink_tooltip.dart b/angular_components/lib/src/material_tooltip/ink_tooltip.dart index 3b518eda3..10ddf56a5 100644 --- a/angular_components/lib/src/material_tooltip/ink_tooltip.dart +++ b/angular_components/lib/src/material_tooltip/ink_tooltip.dart @@ -2,12 +2,15 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +import 'dart:html'; + import 'package:angular/angular.dart'; import 'package:angular_components/content/deferred_content.dart'; import 'package:angular_components/laminate/enums/alignment.dart'; import 'package:angular_components/laminate/popup/popup.dart' show PopupSource; import 'package:angular_components/material_popup/material_popup.dart'; import 'package:angular_components/material_tooltip/module.dart'; +import 'package:angular_components/utils/angular/css/css.dart'; import 'tooltip_controller.dart'; import 'tooltip_target.dart'; @@ -37,7 +40,7 @@ import 'tooltip_target.dart'; [autoDismiss]="false" enforceSpaceConstraints [matchMinSourceWidth]="false" - class="aacmtit-ink-tooltip-shadow" + class="aacmtit-ink-tooltip-shadow {{popupClassName}}" trackLayoutChanges [preferredPositions]="positions" [source]="popupSource" @@ -75,7 +78,15 @@ class MaterialInkTooltipComponent implements Tooltip { @Input() String text; - MaterialInkTooltipComponent(this._tooltipController, this._changeDetector); + /// Classname applied to material-popup for use with mixins. + /// + /// Left modifiable so that it can be set by the [MaterialTooltipDirective]. + String popupClassName; + + MaterialInkTooltipComponent(this._tooltipController, this._changeDetector, + HtmlElement hostElement, @Attribute('tooltipClass') String tooltipClass) + : popupClassName = + constructEncapsulatedCss(tooltipClass, hostElement.classes); @override void activate() { diff --git a/angular_components/lib/src/material_tooltip/tooltip.dart b/angular_components/lib/src/material_tooltip/tooltip.dart index f19791cad..f659bded9 100644 --- a/angular_components/lib/src/material_tooltip/tooltip.dart +++ b/angular_components/lib/src/material_tooltip/tooltip.dart @@ -10,6 +10,7 @@ import 'package:angular_components/laminate/popup/popup.dart' show DomPopupSourceFactory; import 'package:angular_components/material_tooltip/module.dart'; import 'package:angular_components/model/action/delayed_action.dart'; +import 'package:angular_components/utils/angular/css/css.dart'; import 'package:angular_components/utils/browser/feature_detector/feature_detector.dart'; import 'package:angular_components/utils/disposer/disposer.dart'; @@ -29,6 +30,7 @@ class MaterialTooltipDirective extends TooltipTarget final _disposer = Disposer.multi(); final ComponentLoader _viewLoader; final ChangeDetectorRef _changeDetector; + final String _popupClassName; final Window _window; String _lastText; @@ -51,8 +53,11 @@ class MaterialTooltipDirective extends TooltipTarget this._viewLoader, this._changeDetector, this._window, - @Attribute('initPopupAriaAttributes') String initAriaAttributes) + @Attribute('initPopupAriaAttributes') String initAriaAttributes, + @Attribute('tooltipClass') String tooltipClass) : this.element = element, + _popupClassName = + constructEncapsulatedCss(tooltipClass, element.classes), super(domPopupSourceFactory, viewContainerRef, element, initAriaAttributes) { inLongPress = false; @@ -132,6 +137,7 @@ class MaterialTooltipDirective extends TooltipTarget _disposer.addDisposable(_componentRef.destroy); _inkTooltip + ..popupClassName = _popupClassName ..text = _lastText ..tooltipRef = this; if (positions != null) { From 05ee86dd57c0d18e06019555e7b953ecbeb5b62b Mon Sep 17 00:00:00 2001 From: Googler Date: Thu, 24 Jan 2019 10:30:34 -0800 Subject: [PATCH 062/503] Adds HtmlDocument in addition to Document as a provided windowBinding. PiperOrigin-RevId: 230746430 --- angular_components/lib/utils/browser/window/module.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/angular_components/lib/utils/browser/window/module.dart b/angular_components/lib/utils/browser/window/module.dart index 19af59e7b..6e095c6e4 100644 --- a/angular_components/lib/utils/browser/window/module.dart +++ b/angular_components/lib/utils/browser/window/module.dart @@ -12,7 +12,7 @@ import 'package:angular/angular.dart'; /// /// Visible for transformer only. @Injectable() -Document getDocument() => document; +HtmlDocument getDocument() => document; /// Returns the current browser's [Window]. /// @@ -20,7 +20,7 @@ Document getDocument() => document; @Injectable() Window getWindow() => window; -/// Provides [Document] and [Window] bound for use within Angular. +/// Provides [Document], [HtmlDocument], and [Window] bound for use within Angular. /// /// Ideally, an application would limit direct use of these to maintain /// compatibility with web workers, but there is no Angular sanitized version @@ -29,11 +29,13 @@ const windowBindings = [ // This strange syntax is required because we need windowBindings to be a // const list to be usable within component annotations. Provider(Document, useFactory: getDocument), + Provider(HtmlDocument, useFactory: getDocument), Provider(Window, useFactory: getWindow) ]; const windowModule = Module(provide: [ FactoryProvider(Document, getDocument), + FactoryProvider(HtmlDocument, getDocument), FactoryProvider(Window, getWindow), ]); From 4c4c2ff37be020a495d6c646aa5e2174af9f83c1 Mon Sep 17 00:00:00 2001 From: Googler Date: Thu, 24 Jan 2019 11:41:56 -0800 Subject: [PATCH 063/503] Add ariaLabel to the MaterialExpansionPanel interface to allow custom headers. PiperOrigin-RevId: 230761136 --- .../material_expansionpanel.dart | 22 ++++++++++++++----- .../material_expansionpanel.html | 2 +- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/angular_components/lib/material_expansionpanel/material_expansionpanel.dart b/angular_components/lib/material_expansionpanel/material_expansionpanel.dart index accb9768a..05a2bd2a7 100644 --- a/angular_components/lib/material_expansionpanel/material_expansionpanel.dart +++ b/angular_components/lib/material_expansionpanel/material_expansionpanel.dart @@ -215,6 +215,16 @@ class MaterialExpansionPanel @Input() String secondaryText; + String _groupAriaLabel; + + /// Aria label used to describe the header. + @Input() + set groupAriaLabel(String groupAriaLabel) { + _groupAriaLabel = groupAriaLabel; + } + + String get groupAriaLabel => _groupAriaLabel == null ? name : _groupAriaLabel; + /// An optional icon name to replace the expand arrows with a custom icon. @Input() set expandIcon(String expandIcon) => _expandIcon = expandIcon; @@ -277,15 +287,17 @@ class MaterialExpansionPanel @Input() String cancelText = _msgCancel; - String get closePanelMsg => - name == null ? _closePanelMsg : _closeNamedPanelMsg(name); + String get closePanelMsg => groupAriaLabel == null && name == null + ? _closePanelMsg + : _closeNamedPanelMsg(groupAriaLabel); - String get openPanelMsg => - name == null ? _openPanelMsg : _openNamedPanelMsg(name); + String get openPanelMsg => groupAriaLabel == null && name == null + ? _openPanelMsg + : _openNamedPanelMsg(groupAriaLabel); String get headerMsg { if (disabled) { - return name; + return groupAriaLabel; } else { return _isExpanded ? closePanelMsg : openPanelMsg; } diff --git a/angular_components/lib/material_expansionpanel/material_expansionpanel.html b/angular_components/lib/material_expansionpanel/material_expansionpanel.html index 3a3388f54..f15818599 100644 --- a/angular_components/lib/material_expansionpanel/material_expansionpanel.html +++ b/angular_components/lib/material_expansionpanel/material_expansionpanel.html @@ -5,7 +5,7 @@ -->
Date: Thu, 24 Jan 2019 15:20:15 -0800 Subject: [PATCH 064/503] Make the entire content of an expansion panel deferred rather than just the buttons. PiperOrigin-RevId: 230800047 --- .../lib/content/deferred_content.dart | 24 +++++++++++++++---- .../material_expansionpanel.dart | 16 ++++++++++--- .../material_expansionpanel.html | 4 +--- 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/angular_components/lib/content/deferred_content.dart b/angular_components/lib/content/deferred_content.dart index 539a20b07..a434f7951 100644 --- a/angular_components/lib/content/deferred_content.dart +++ b/angular_components/lib/content/deferred_content.dart @@ -36,11 +36,24 @@ class DeferredContentDirective implements OnDestroy { @Input('deferredContent') bool preserveDimensions = false; + /// Even when the content is not-visible force it to be on the page. + /// + /// Only use this for common components which needs to give options to it's + // content. + @Input() + set deferredContentForceContent(bool value) { + _forceContent = value; + _setVisible(); + } + // Keep around the current state. + bool _shown = false; bool _visible = false; + bool _forceContent = false; - void _setVisible(bool value) { - if (value == _visible) return; + void _setVisible() { + bool value = _visible || _forceContent; + if (value == _shown) return; if (value) { if (preserveDimensions) { // Remove the placeholder and add the deferred content. @@ -73,12 +86,15 @@ class DeferredContentDirective implements OnDestroy { } } } - _visible = value; + _shown = value; } DeferredContentDirective( this._viewContainer, this._template, DeferredContentAware parent) { - _disposer.addStreamSubscription(parent.contentVisible.listen(_setVisible)); + _disposer.addStreamSubscription(parent.contentVisible.listen((value) { + _visible = value; + _setVisible(); + })); } @override diff --git a/angular_components/lib/material_expansionpanel/material_expansionpanel.dart b/angular_components/lib/material_expansionpanel/material_expansionpanel.dart index 05a2bd2a7..1c033995c 100644 --- a/angular_components/lib/material_expansionpanel/material_expansionpanel.dart +++ b/angular_components/lib/material_expansionpanel/material_expansionpanel.dart @@ -38,6 +38,10 @@ import 'package:angular_components/utils/disposer/disposer.dart'; /// slightly wider then its width when collapsed. /// - `flat` -- Indicates that the panel should not "float" or separate from /// other panels when expanded. +/// - `forceContentWhenClosed` -- Keeps expansion panel content in the DOM when +/// the expansion panel is closed. This should only be used in rare +/// circumstances as the content will be tabbable and so will be worse for +/// accessibility. /// @Component( selector: 'material-expansionpanel', @@ -68,13 +72,19 @@ class MaterialExpansionPanel final _disposer = Disposer.oneShot(); final _defaultExpandIcon = 'expand_less'; final bool shouldExpandOnLeft; + final bool forceContentWhenClosed; final _pendingExpandedPanelHeightReads = >[]; bool initialized = false; - MaterialExpansionPanel(this._ngZone, this._changeDetector, this._domService, - @Attribute('shouldExpandOnLeft') String expandOnLeft) - : shouldExpandOnLeft = expandOnLeft != null; + MaterialExpansionPanel( + this._ngZone, + this._changeDetector, + this._domService, + @Attribute('shouldExpandOnLeft') String expandOnLeft, + @Attribute('forceContentWhenClosed') String forceContent) + : shouldExpandOnLeft = expandOnLeft != null, + forceContentWhenClosed = forceContent != null; /// Set the auto focus child so that we can focus on it when the panel opens. /// diff --git a/angular_components/lib/material_expansionpanel/material_expansionpanel.html b/angular_components/lib/material_expansionpanel/material_expansionpanel.html index f15818599..c36c56c71 100644 --- a/angular_components/lib/material_expansionpanel/material_expansionpanel.html +++ b/angular_components/lib/material_expansionpanel/material_expansionpanel.html @@ -58,7 +58,7 @@
-
+
-
@@ -101,7 +100,6 @@ (yes)="doSave" (no)="doCancel"> -
From 600210a94da20783cf7bc112c52e18421df49a22 Mon Sep 17 00:00:00 2001 From: Googler Date: Thu, 24 Jan 2019 20:05:37 -0800 Subject: [PATCH 065/503] Allow specifying an aria described by id on the input. PiperOrigin-RevId: 230838412 --- angular_components/lib/material_input/material_input.dart | 5 +++++ angular_components/lib/material_input/material_input.html | 1 + 2 files changed, 6 insertions(+) diff --git a/angular_components/lib/material_input/material_input.dart b/angular_components/lib/material_input/material_input.dart index 5f6032e39..8e9f10f24 100644 --- a/angular_components/lib/material_input/material_input.dart +++ b/angular_components/lib/material_input/material_input.dart @@ -203,6 +203,11 @@ class MaterialInputComponent extends BaseMaterialInput @Input() String inputAriaOwns; + /// The ID of an element which should be assigned to the inner input element's + /// aria-describedby attribute. + @Input() + String inputAriaDescribedBy; + /// The ID of an element which should be assigned to the inner input element's /// aria-activedescendant attribute. @Input() diff --git a/angular_components/lib/material_input/material_input.html b/angular_components/lib/material_input/material_input.html index cc2eb6c8e..4036c4bd8 100644 --- a/angular_components/lib/material_input/material_input.html +++ b/angular_components/lib/material_input/material_input.html @@ -49,6 +49,7 @@ [attr.aria-invalid]="invalid" [attr.aria-label]="inputAriaLabel" [attr.aria-labelledby]="labelId" + [attr.aria-describedby]="inputAriaDescribedBy" [attr.aria-owns]="inputAriaOwns" [attr.role]="inputRole" [ngModel]="inputText" From 4ecf17c07c65a3fccc5adceda89482d8a1b952c4 Mon Sep 17 00:00:00 2001 From: davidmorgan Date: Fri, 25 Jan 2019 03:44:08 -0800 Subject: [PATCH 066/503] Fix violations of slash_for_doc_comments lint Created using "dartfmt --fix-doc-comments -w". PiperOrigin-RevId: 230878513 --- angular_components/lib/mixins/track_layout_changes.dart | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/angular_components/lib/mixins/track_layout_changes.dart b/angular_components/lib/mixins/track_layout_changes.dart index 4388c55ef..774a64a49 100644 --- a/angular_components/lib/mixins/track_layout_changes.dart +++ b/angular_components/lib/mixins/track_layout_changes.dart @@ -4,10 +4,8 @@ import 'package:angular/angular.dart'; -/** - * Mixin for trackLayoutChanges property pass through to material popup to - * avoid duplicate code in multiple components. - */ +/// Mixin for trackLayoutChanges property pass through to material popup to +/// avoid duplicate code in multiple components. class TrackLayoutChangesMixin { /// Sets whether the suggestion list scrolls with the input box. /// From 18d52b5e640602088188ea8045bf2da2818ca3fb Mon Sep 17 00:00:00 2001 From: Googler Date: Fri, 25 Jan 2019 05:16:58 -0800 Subject: [PATCH 067/503] Allow 'class' attribute for all elements in simple-html. This will allow us to style them in a different color, for example. PiperOrigin-RevId: 230886459 --- angular_components/lib/simple_html/README.md | 6 ++++-- .../lib/simple_html/simple_html.dart | 16 ++++++++-------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/angular_components/lib/simple_html/README.md b/angular_components/lib/simple_html/README.md index 4d6763bed..b0ee1c39a 100644 --- a/angular_components/lib/simple_html/README.md +++ b/angular_components/lib/simple_html/README.md @@ -174,12 +174,12 @@ for the exact specification of what is supported. A general overview is: * `` supports the following safe inline elements: * Basic text formatting: ``, ``, ``, ``. * Line breaks: `
`. - * Text grouping: ``, including the `class` attribute. + * Text grouping: ``. * Links: `` provided the destination matches the current [origin](https://en.wikipedia.org/wiki/Same-origin_policy) or points to certain permitted URIs such as the Help Center; see [URI whitelisting](#uri-whitelisting)). - * The `class` and `rel` attributes are permitted. + * The `rel` attributes are permitted. * The `target` attribute is permitted provided `rel="noopener"` is set. * `` supports all of the above and the following safe block @@ -187,6 +187,8 @@ for the exact specification of what is supported. A general overview is: * Unordered lists: `
    ` and `
  • `. * Paragraphs: `

    `. +The `class` attribute is permitted by all elements. + ### URI whitelisting {#uri-whitelisting} By default, only links with the diff --git a/angular_components/lib/simple_html/simple_html.dart b/angular_components/lib/simple_html/simple_html.dart index fdf82475f..0a78d47fb 100644 --- a/angular_components/lib/simple_html/simple_html.dart +++ b/angular_components/lib/simple_html/simple_html.dart @@ -296,17 +296,17 @@ NodeValidatorBuilder _inlineElementValidatorBuilder( ..allowElement('a', attributes: ['class', 'href', 'rel', 'target'], uriPolicy: _SafeUriPolicy(domainWhitelist)) - ..allowElement('b') - ..allowElement('br') - ..allowElement('em') - ..allowElement('i') + ..allowElement('b', attributes: ['class']) + ..allowElement('br', attributes: ['class']) + ..allowElement('em', attributes: ['class']) + ..allowElement('i', attributes: ['class']) ..allowElement('span', attributes: ['class']) - ..allowElement('strong'); + ..allowElement('strong', attributes: ['class']); /// Returns a new [NodeValidator] which allows all SimpleHtml-permissible /// elements (both inline and block level). NodeValidator _elementValidator(List domainWhitelist) => _inlineElementValidatorBuilder(domainWhitelist) - ..allowElement('p') - ..allowElement('ul') - ..allowElement('li'); + ..allowElement('p', attributes: ['class']) + ..allowElement('ul', attributes: ['class']) + ..allowElement('li', attributes: ['class']); From 25f553d030e2599946dc41a52a83d482fce65f14 Mon Sep 17 00:00:00 2001 From: tsander Date: Fri, 25 Jan 2019 09:54:40 -0800 Subject: [PATCH 068/503] Make the expansion button not be tabbable since the heading is tabbable. Also have better a11y for the example dialog by moving focus. PiperOrigin-RevId: 230919521 --- .../lib/material_expansionpanel/material_expansionpanel.html | 2 ++ .../lib/material_expansionpanel_example.html | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/angular_components/lib/material_expansionpanel/material_expansionpanel.html b/angular_components/lib/material_expansionpanel/material_expansionpanel.html index c36c56c71..5f4f8f71f 100644 --- a/angular_components/lib/material_expansionpanel/material_expansionpanel.html +++ b/angular_components/lib/material_expansionpanel/material_expansionpanel.html @@ -28,6 +28,7 @@ class="expand-button expand-on-left" [disabled]="headerHidden" [icon]="expandIcon" + [tabbable]="false" [class.expand-more]="shouldFlipExpandIcon" (trigger)="handleExpandIconClick"> @@ -45,6 +46,7 @@ *ngIf="shouldShowExpandIcon && !shouldExpandOnLeft" class="expand-button" [icon]="expandIcon" + [tabbable]="false" [disabled]="headerHidden" [class.expand-more]="shouldFlipExpandIcon" (trigger)="handleExpandIconClick" diff --git a/examples/material_expansionpanel_example/lib/material_expansionpanel_example.html b/examples/material_expansionpanel_example/lib/material_expansionpanel_example.html index abbc39fe1..54ee44e97 100644 --- a/examples/material_expansionpanel_example/lib/material_expansionpanel_example.html +++ b/examples/material_expansionpanel_example/lib/material_expansionpanel_example.html @@ -233,7 +233,7 @@

- +

Do you really want to cancel?

Date: Fri, 25 Jan 2019 13:26:33 -0800 Subject: [PATCH 069/503] [a11y] Allow describedby to be specified for a drop down button. PiperOrigin-RevId: 230958094 --- angular_components/lib/material_menu/dropdown_menu.dart | 4 ++++ angular_components/lib/material_menu/dropdown_menu.html | 1 + angular_components/lib/material_select/dropdown_button.dart | 3 +++ angular_components/lib/material_select/dropdown_button.html | 1 + 4 files changed, 9 insertions(+) diff --git a/angular_components/lib/material_menu/dropdown_menu.dart b/angular_components/lib/material_menu/dropdown_menu.dart index 11c659339..667e8d72d 100644 --- a/angular_components/lib/material_menu/dropdown_menu.dart +++ b/angular_components/lib/material_menu/dropdown_menu.dart @@ -67,6 +67,10 @@ class DropdownMenuComponent extends Object focusable = _focusTarget; } + /// Id of element which describes the button for the drop down. + @Input() + String buttonAriaDescribedBy; + /// Whether the menu is tabbable or not. @Input() bool tabbable = true; diff --git a/angular_components/lib/material_menu/dropdown_menu.html b/angular_components/lib/material_menu/dropdown_menu.html index 039199b4d..94971a4b3 100644 --- a/angular_components/lib/material_menu/dropdown_menu.html +++ b/angular_components/lib/material_menu/dropdown_menu.html @@ -4,6 +4,7 @@ BSD-style license that can be found in the LICENSE file. --> _ariaLabelledBy == null ? null : '$_ariaLabelledBy $uuid'; + @Input() + String ariaDescribedBy; + bool get invalid => error != null; /// Whether to show the bottom border of the dropdown button. diff --git a/angular_components/lib/material_select/dropdown_button.html b/angular_components/lib/material_select/dropdown_button.html index 9f756b41e..839da9dbc 100644 --- a/angular_components/lib/material_select/dropdown_button.html +++ b/angular_components/lib/material_select/dropdown_button.html @@ -12,6 +12,7 @@ (blur)="handleBlur($event)" [attr.aria-label]="buttonAriaLabel" [attr.aria-labelledby]="ariaLabelledBy" + [attr.aria-describedby]="ariaDescribedBy" [class.border]="showButtonBorder" [class.invalid]="invalid" [disabled]="disabled" From 6584bdbc11015338515f3a617442d5db2d1362c4 Mon Sep 17 00:00:00 2001 From: Googler Date: Fri, 25 Jan 2019 14:04:40 -0800 Subject: [PATCH 070/503] Create MenuItemMixin Reduces boilerplate code when implementing a MenuItem interface on another class. Part of a larger feature to create MaterialMenu style items from ESS: cl/229654005 PiperOrigin-RevId: 230965086 --- angular_components/lib/model/menu/menu.dart | 42 ++++++++++++++------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/angular_components/lib/model/menu/menu.dart b/angular_components/lib/model/menu/menu.dart index 578d9108e..6dc7611e3 100644 --- a/angular_components/lib/model/menu/menu.dart +++ b/angular_components/lib/model/menu/menu.dart @@ -133,7 +133,7 @@ class MenuModel implements HasIcon, AcceptsWidth { /// Example code for creating a menu item with tooltip /// new MenuItem(label, tooltip: tooltip, /// action:action, icon:icon, subMenu:subMenu); -class MenuItem implements HasUIDisplayName, HasIcon { +class MenuItem with MenuItemMixin implements HasUIDisplayName, HasIcon { final String label; final String secondaryLabel; final String tooltip; @@ -149,8 +149,6 @@ class MenuItem implements HasUIDisplayName, HasIcon { Function action; final Icon icon; - @override - Icon get uiIcon => icon; /// List of rendered suffixes for this menu item. final ObservableList itemSuffixes; @@ -158,18 +156,8 @@ class MenuItem implements HasUIDisplayName, HasIcon { /// Additional CSS classes to be attached to the root menu item element. final BuiltList cssClasses; - void _noop() {} - Function get nullAwareActionHandler => action != null ? action : _noop; - @virtual bool enabled; - bool get hasIcon => icon != null; - - bool get hasSubMenu => subMenu != null; - bool get showTooltip => isNotEmpty(tooltip); - @override - String get uiDisplayName => label; - bool get hasSecondaryLabel => secondaryLabel != null; /// The constructor for a [MenuItem] which displays [label]. /// @@ -218,6 +206,34 @@ class MenuItem implements HasUIDisplayName, HasIcon { }.toString(); } +/// Required members to use [MenuItemMixin]. +abstract class _MenuItemBase { + Function get action; + Icon get icon; + String get label; + String get secondaryLabel; + String get tooltip; + MenuModel get subMenu; +} + +/// Mixin to implement trivial getters on [MenuItem]. +abstract class MenuItemMixin implements _MenuItemBase { + void _noop() {} + Function get nullAwareActionHandler => action != null ? action : _noop; + + bool get hasIcon => icon != null; + + String get uiDisplayName => label; + + Icon get uiIcon => icon; + + bool get hasSubMenu => subMenu != null; + + bool get hasSecondaryLabel => secondaryLabel != null; + + bool get showTooltip => isNotEmpty(tooltip); +} + /// Type that can be specified to mark that there can be no subMenus for /// a given [MenuItem]. abstract class NullMenuItem extends MenuItem { From e264fddc104e3f3a734815146254f25520bc067c Mon Sep 17 00:00:00 2001 From: nshahan Date: Fri, 25 Jan 2019 14:17:35 -0800 Subject: [PATCH 071/503] Fix doc comment typo PiperOrigin-RevId: 230967488 --- angular_components/lib/content/deferred_content.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/angular_components/lib/content/deferred_content.dart b/angular_components/lib/content/deferred_content.dart index a434f7951..5695bb3e1 100644 --- a/angular_components/lib/content/deferred_content.dart +++ b/angular_components/lib/content/deferred_content.dart @@ -39,7 +39,7 @@ class DeferredContentDirective implements OnDestroy { /// Even when the content is not-visible force it to be on the page. /// /// Only use this for common components which needs to give options to it's - // content. + /// content. @Input() set deferredContentForceContent(bool value) { _forceContent = value; From 257315edf0216145e60718fe6fb49c87f8697af1 Mon Sep 17 00:00:00 2001 From: Googler Date: Fri, 25 Jan 2019 16:11:32 -0800 Subject: [PATCH 072/503] Add mixin for material yes/no buttons to remove the left margin and left-align them to content. PiperOrigin-RevId: 230987932 --- .../lib/material_yes_no_buttons/_mixins.scss | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/angular_components/lib/material_yes_no_buttons/_mixins.scss b/angular_components/lib/material_yes_no_buttons/_mixins.scss index 8e1cb64f0..f10b97cd9 100644 --- a/angular_components/lib/material_yes_no_buttons/_mixins.scss +++ b/angular_components/lib/material_yes_no_buttons/_mixins.scss @@ -42,3 +42,16 @@ color: $value; } } + +// Remove the left-margin from the yes/no button on the left side to align with content. +// +// Apply directly to the element. +@mixin material-yes-no-button-remove-left-margin() { + &[reverse] ::ng-deep .btn.btn-no { + margin-left: 0; + } + + &:not([reverse]) ::ng-deep .btn.btn-yes { + margin-left: 0; + } +} From 4f2416add2659323ed7d514832577908acf5c9a8 Mon Sep 17 00:00:00 2001 From: nshahan Date: Fri, 25 Jan 2019 16:52:11 -0800 Subject: [PATCH 073/503] Add import prefixes to generated files to avoid unknown identifier errors from the analyzer PiperOrigin-RevId: 230994150 --- .../lib/material_menu/affix/caption_affix_model.dart | 5 +++-- .../lib/material_menu/affix/icon_affix_model.dart | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/angular_components/lib/material_menu/affix/caption_affix_model.dart b/angular_components/lib/material_menu/affix/caption_affix_model.dart index 022fb24f6..7c440012c 100644 --- a/angular_components/lib/material_menu/affix/caption_affix_model.dart +++ b/angular_components/lib/material_menu/affix/caption_affix_model.dart @@ -4,7 +4,8 @@ import 'package:angular/angular.dart'; import 'package:angular_components/material_menu/affix/base_affix.dart'; -import 'package:angular_components/material_menu/affix/caption_affix.template.dart'; +import 'package:angular_components/material_menu/affix/caption_affix.template.dart' + as ng; import 'package:angular_components/model/menu/menu_item_affix.dart'; /// Affix containing text. @@ -19,7 +20,7 @@ class CaptionAffix extends BaseMenuItemAffixModel { @override ComponentFactory get componentFactory => - CaptionAffixComponentNgFactory; + ng.CaptionAffixComponentNgFactory; const CaptionAffix( {this.text, this.visibility = IconVisibility.visible, this.cssClass}); diff --git a/angular_components/lib/material_menu/affix/icon_affix_model.dart b/angular_components/lib/material_menu/affix/icon_affix_model.dart index fb00efb13..ec91921c5 100644 --- a/angular_components/lib/material_menu/affix/icon_affix_model.dart +++ b/angular_components/lib/material_menu/affix/icon_affix_model.dart @@ -5,7 +5,8 @@ import 'package:angular/angular.dart'; import 'package:meta/meta.dart'; import 'package:angular_components/material_menu/affix/base_affix.dart'; -import 'package:angular_components/material_menu/affix/icon_affix.template.dart'; +import 'package:angular_components/material_menu/affix/icon_affix.template.dart' + as ng; import 'package:angular_components/model/menu/menu_item_affix.dart'; import 'package:angular_components/model/ui/icon.dart'; @@ -69,7 +70,7 @@ class IconAffix extends BaseMenuItemAffixModel { @override ComponentFactory get componentFactory => - IconAffixComponentNgFactory; + ng.IconAffixComponentNgFactory; bool get hasAction => _action != null; From 89fd5a702fea47fbe0317ab6fd20bdad27749138 Mon Sep 17 00:00:00 2001 From: Googler Date: Mon, 28 Jan 2019 02:17:52 -0800 Subject: [PATCH 074/503] Update simple-html dart doc to reflect the fact that 'class' is supported for all permitted tags (missed in cl/230886459). PiperOrigin-RevId: 231182480 --- angular_components/lib/simple_html/simple_html.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/angular_components/lib/simple_html/simple_html.dart b/angular_components/lib/simple_html/simple_html.dart index 0a78d47fb..d5771ba8b 100644 --- a/angular_components/lib/simple_html/simple_html.dart +++ b/angular_components/lib/simple_html/simple_html.dart @@ -45,8 +45,8 @@ const _triggerSelector = 'a.trigger'; /// `target` attributes. If `target` is set, `rel` must also be set and /// must contain `noopener` (see /// https://mathiasbynens.github.io/rel-noopener/ for background). -/// * `` with (optionally) a class attribute. -/// * ``, `
`, ``, and `` with no attributes. +/// * `` ``, `
`, ``, and `` with (optionally) a `class` +/// attribute. /// /// Note that any styles applied with the class attribute will need to be /// annotated with `::ng-deep` (or equivalent mechanism) in order to actually From eef5adfc1423cece235598338a77784caec22b8f Mon Sep 17 00:00:00 2001 From: Googler Date: Mon, 28 Jan 2019 16:35:45 -0800 Subject: [PATCH 075/503] Add a material button mixin for changing the color of a disabled button. PiperOrigin-RevId: 231311419 --- angular_components/lib/material_button/_mixins.scss | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/angular_components/lib/material_button/_mixins.scss b/angular_components/lib/material_button/_mixins.scss index 6a314fe16..858db124b 100644 --- a/angular_components/lib/material_button/_mixins.scss +++ b/angular_components/lib/material_button/_mixins.scss @@ -252,6 +252,12 @@ $button-disabled-background-dark: rgba(255, 255, 255, $mat-divider-opacity); } } +@mixin button-disabled-color($selector, $disabled-color) { + ::ng-deep #{$selector}[disabled] { + color: $disabled-color; + } +} + @mixin button-background-color($selector, $background-color) { ::ng-deep #{$selector}:not([disabled]) { background-color: $background-color; From 8b69d9ea80661b6eec6444f66a61534bdf319dd3 Mon Sep 17 00:00:00 2001 From: Googler Date: Tue, 29 Jan 2019 08:54:46 -0800 Subject: [PATCH 076/503] Fix for issue where hidden buttons could be focused in the header of the material expansion panel. PiperOrigin-RevId: 231411767 --- .../lib/material_expansionpanel/material_expansionpanel.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/angular_components/lib/material_expansionpanel/material_expansionpanel.html b/angular_components/lib/material_expansionpanel/material_expansionpanel.html index 5f4f8f71f..2e83346e6 100644 --- a/angular_components/lib/material_expansionpanel/material_expansionpanel.html +++ b/angular_components/lib/material_expansionpanel/material_expansionpanel.html @@ -53,7 +53,7 @@ [attr.aria-label]="expandAriaMsg"> -
+
From 36c1bd58dfbebbcfd466c1b52bfbf395c441acea Mon Sep 17 00:00:00 2001 From: Googler Date: Tue, 29 Jan 2019 12:07:35 -0800 Subject: [PATCH 077/503] [a11y] Multiline material input should also support described by. PiperOrigin-RevId: 231448060 --- .../lib/material_input/material_input_multiline.dart | 5 +++++ .../lib/material_input/material_input_multiline.html | 1 + 2 files changed, 6 insertions(+) diff --git a/angular_components/lib/material_input/material_input_multiline.dart b/angular_components/lib/material_input/material_input_multiline.dart index 44347a1b9..91d84215b 100644 --- a/angular_components/lib/material_input/material_input_multiline.dart +++ b/angular_components/lib/material_input/material_input_multiline.dart @@ -168,6 +168,11 @@ class MaterialMultilineInputComponent extends BaseMaterialInput _changeDetector.markForCheck(); } + /// The ID of an element which should be assigned to the inner input element's + /// aria-describedby attribute. + @Input() + String inputAriaDescribedBy; + @override void ngOnDestroy() { super.ngOnDestroy(); diff --git a/angular_components/lib/material_input/material_input_multiline.html b/angular_components/lib/material_input/material_input_multiline.html index 3c06f9de6..6908382a3 100644 --- a/angular_components/lib/material_input/material_input_multiline.html +++ b/angular_components/lib/material_input/material_input_multiline.html @@ -47,6 +47,7 @@ [class.disabledInput]="disabled" [class.staticHeight]="rows == maxRows" [style.height.px]="textAreaHeight" + [attr.aria-describedby]="inputAriaDescribedBy" attr.aria-invalid="{{invalid}}" [attr.aria-label]="ariaLabel" [readonly]="disabled" From 0e4dfa669bd7b267df8d9ead5f83232a05ae6b5d Mon Sep 17 00:00:00 2001 From: Googler Date: Wed, 30 Jan 2019 13:55:46 -0800 Subject: [PATCH 078/503] Support setting Aria label for material select. PiperOrigin-RevId: 231662310 --- .../lib/material_select/material_select.dart | 8 ++++++++ .../lib/material_select/material_select.html | 6 +++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/angular_components/lib/material_select/material_select.dart b/angular_components/lib/material_select/material_select.dart index ac1470ddc..a52bc25f9 100644 --- a/angular_components/lib/material_select/material_select.dart +++ b/angular_components/lib/material_select/material_select.dart @@ -70,6 +70,14 @@ class MaterialSelectComponent extends MaterialSelectBase super.width = value; } + /// The label which will be set to select group's aria-labelledby. + @Input() + String ariaLabelledBy; + + /// The description which will be set to select groups' aria-describedby. + @Input() + String ariaDescribedBy; + @Deprecated('Use factoryRenderer instead it is more tree-shakable') @Input() @override diff --git a/angular_components/lib/material_select/material_select.html b/angular_components/lib/material_select/material_select.html index 62e80ddb9..1eda7ec47 100644 --- a/angular_components/lib/material_select/material_select.html +++ b/angular_components/lib/material_select/material_select.html @@ -5,7 +5,11 @@ --> -
+
diff --git a/examples/material_tree_example/lib/src/material_tree_nested_single_demo.dart b/examples/material_tree_example/lib/src/material_tree_nested_single_demo.dart index fa6b441b0..8f9c23c82 100644 --- a/examples/material_tree_example/lib/src/material_tree_nested_single_demo.dart +++ b/examples/material_tree_example/lib/src/material_tree_nested_single_demo.dart @@ -37,6 +37,7 @@ import 'package:angular_components/model/selection/selection_options.dart';
@@ -60,4 +61,6 @@ class MaterialTreeNestedSingleDemoComponent { _expandAll = value; _changeDetector.markForCheck(); } + + bool allowDeselectInHierarchy; } From bad41bc04648f4d89b48e5148a505a20cdc5a738 Mon Sep 17 00:00:00 2001 From: Googler Date: Sat, 4 May 2019 01:33:15 -0700 Subject: [PATCH 291/503] Add Material-Dialog footer justify-content mixin PiperOrigin-RevId: 246634330 --- angular_components/lib/material_dialog/_mixins.scss | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/angular_components/lib/material_dialog/_mixins.scss b/angular_components/lib/material_dialog/_mixins.scss index 9c9527cce..6accb16c8 100644 --- a/angular_components/lib/material_dialog/_mixins.scss +++ b/angular_components/lib/material_dialog/_mixins.scss @@ -50,6 +50,12 @@ } } +@mixin material-dialog-footer-justify-content($justify-content) { + ::ng-deep .wrapper > footer [footer] { + justify-content: $justify-content; + } +} + @mixin material-dialog-header() { @include box-sizing(border-box); padding: $mat-grid * 3 $mat-grid * 3 0; From cc05d53f2f47704b43f7d4311aa68de331a8112f Mon Sep 17 00:00:00 2001 From: Googler Date: Mon, 6 May 2019 14:22:42 -0700 Subject: [PATCH 292/503] [CM Editing] (No-op) Added "Module" style provider for several time zone aware clock related bindings, in preparation to import base root module to CM editing's subapp root module. PiperOrigin-RevId: 246896539 --- angular_components/lib/material_datepicker/module.dart | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/angular_components/lib/material_datepicker/module.dart b/angular_components/lib/material_datepicker/module.dart index 860fdbacd..0dc74b6dd 100644 --- a/angular_components/lib/material_datepicker/module.dart +++ b/angular_components/lib/material_datepicker/module.dart @@ -36,9 +36,17 @@ const datepickerBindings = [ /// /// To use these bindings, you must initialize [SettableTimeZone] before /// constructing the datepicker, or console errors will occur. +@Deprecated("use timeZoneAwareDatepickerModule") const timeZoneAwareDatepickerProviders = [ - _legacyClockBinding, + _sharedClockBindings, timeZoneAwareClockProviders, +]; + +const timeZoneAwareDatepickerModule = + Module(include: [timeZoneAwareClockModule], provide: _sharedClockBindings); + +const _sharedClockBindings = [ + _legacyClockBinding, ExistingProvider.forToken(datepickerClock, timeZoneAwareClock), ]; From 380d8737219b877cc9c516e099a2cc5cbff8585b Mon Sep 17 00:00:00 2001 From: Googler Date: Mon, 6 May 2019 15:56:00 -0700 Subject: [PATCH 293/503] Fix an issue on material stepper where when activeStepIndex is set to a value but the step state is not updated accordingly. PiperOrigin-RevId: 246913842 --- .../lib/material_stepper/material_stepper.dart | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/angular_components/lib/material_stepper/material_stepper.dart b/angular_components/lib/material_stepper/material_stepper.dart index ce815eb92..f20a11eb6 100644 --- a/angular_components/lib/material_stepper/material_stepper.dart +++ b/angular_components/lib/material_stepper/material_stepper.dart @@ -54,7 +54,13 @@ class MaterialStepperComponent { static const defaultSize = sizeDefault; List steps = []; - int activeStepIndex; + int _activeStepIndex; + int get activeStepIndex => _activeStepIndex; + set activeStepIndex(int value) { + _activeStepIndex = value; + _recalculatePropertiesOfSteps(); + } + bool stepperDone = false; var _orientation = defaultOrientation; @@ -224,7 +230,6 @@ class MaterialStepperComponent { steps[index].requestStepJump(actionController.action); actionController.execute(() { activeStepIndex = index; - _recalculatePropertiesOfSteps(); _activeStepController.add(activeStep); return true; }, valueOnCancel: false); From a869a640d4bcd4b1e01882173a1489b34f4a521b Mon Sep 17 00:00:00 2001 From: Googler Date: Wed, 8 May 2019 07:31:54 -0700 Subject: [PATCH 294/503] Fix two typos PiperOrigin-RevId: 247209443 --- angular_components/lib/app_layout/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/angular_components/lib/app_layout/README.md b/angular_components/lib/app_layout/README.md index c0280a30c..ed33ef820 100644 --- a/angular_components/lib/app_layout/README.md +++ b/angular_components/lib/app_layout/README.md @@ -106,7 +106,7 @@ done using the [reference variable](https://webdev.dartlang.org/angular/guide/template-syntax#!#ref-vars) syntax. The persistent drawer directive exports itself as `drawer` this allows it to be used easily by other actions. `toggle()` can be used to open/close the -drawer. The drawer supports the `deferredConent` directive allowing a developer +drawer. The drawer supports the `deferredContent` directive allowing a developer to add/remove content from the page when the drawer is not visible (closed.) Here is a complete example: @@ -135,7 +135,7 @@ Here is a complete example: ### Temporary drawers -Temporary drawers are drawers that live on top of the conent. They are provided +Temporary drawers are drawers that live on top of the content. They are provided by `MaterialTemporaryDrawerComponent` which has a similar look and feel to the other drawers. To use a temporary drawer add the `temporary` attribute to the `material-drawer` element, and add `MaterialTemporaryDrawerComponent` to the From 5dee017e308c4c89f03dc534060132149ecd7f3b Mon Sep 17 00:00:00 2001 From: srawlins Date: Wed, 8 May 2019 10:55:07 -0700 Subject: [PATCH 295/503] Bumping markdown Dart package to 2.0.3. PiperOrigin-RevId: 247246376 --- angular_gallery_section/lib/builder/gallery_info_builder.dart | 4 ++-- angular_gallery_section/pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/angular_gallery_section/lib/builder/gallery_info_builder.dart b/angular_gallery_section/lib/builder/gallery_info_builder.dart index af7c738c4..fc42a43e2 100644 --- a/angular_gallery_section/lib/builder/gallery_info_builder.dart +++ b/angular_gallery_section/lib/builder/gallery_info_builder.dart @@ -246,8 +246,8 @@ class GalleryInfoBuilder extends Builder { /// Replace web server in `` tags with the [_staticImageServer]. String _replaceImgTags(String content) => content.replaceAllMapped( - RegExp(r'(.*)'), - (Match m) => '${m[1]}'); + RegExp(r'(.*)'), + (Match m) => '${m[2]}'); /// Resolve all [demoClassNames] into [_DemoInfo]s. /// diff --git a/angular_gallery_section/pubspec.yaml b/angular_gallery_section/pubspec.yaml index 3892af574..ba6d7a0de 100644 --- a/angular_gallery_section/pubspec.yaml +++ b/angular_gallery_section/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: build: '>=0.11.1 <2.0.0' build_config: '>=0.2.6 <0.4.0' glob: ^1.1.5 - markdown: ^2.0.0 + markdown: ^2.0.3 mustache: ^1.0.0 path: ^1.6.1 sass: '>=1.15.3 <2.0.0' From 946a96187307ec5f1c362e2c0bc2de2d64fe04e3 Mon Sep 17 00:00:00 2001 From: Googler Date: Thu, 9 May 2019 16:08:25 -0700 Subject: [PATCH 296/503] A11Y for the Material Paper Tooltip 1. Added a tabindex to the container with an aria label to make autoFocus actually force Screen readers to recognize the focus there 2. Setting focus back to the popup source when the popup closes PiperOrigin-RevId: 247514626 --- .../src/material_tooltip/paper_tooltip.dart | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/angular_components/lib/src/material_tooltip/paper_tooltip.dart b/angular_components/lib/src/material_tooltip/paper_tooltip.dart index cd4e47a33..7a777096b 100644 --- a/angular_components/lib/src/material_tooltip/paper_tooltip.dart +++ b/angular_components/lib/src/material_tooltip/paper_tooltip.dart @@ -10,7 +10,8 @@ import 'package:angular_components/content/deferred_content.dart'; import 'package:angular_components/content/deferred_content_aware.dart'; import 'package:angular_components/focus/focus.dart'; import 'package:angular_components/laminate/enums/alignment.dart'; -import 'package:angular_components/laminate/popup/popup.dart' show PopupSource; +import 'package:angular_components/laminate/popup/popup.dart' + show PopupSource, ElementPopupSource; import 'package:angular_components/material_popup/material_popup.dart'; import 'package:angular_components/material_tooltip/module.dart'; import 'package:angular_components/utils/angular/css/css.dart'; @@ -69,8 +70,11 @@ Tooltip getTooltipHandle(MaterialPaperTooltipComponent tooltip) => [autoDismiss]="focusContents" [class]="popupClassName" [source]="popupSource" + (autoDismissed)="onClose()" role="tooltip">
@@ -112,6 +116,13 @@ class MaterialPaperTooltipComponent implements DeferredContentAware, Tooltip { @Input('offsetY') int offsetY = 0; + /// The aria label given to the tooltip container. + /// + /// Should be used with [focusContents] so the label will be read out to + /// screen reader when the popup opens. + @Input() + String title; + bool get showPopup => _showPopup; final StreamController _visibleCtrl = @@ -155,6 +166,14 @@ class MaterialPaperTooltipComponent implements DeferredContentAware, Tooltip { _tooltipController.deactivate(this); } + /// Set focus back to the popupSource if focus was moved to the tooltip with + /// [focusContents]. + void onClose() { + if (focusContents && popupSource is ElementPopupSource) { + Future(() => (popupSource as ElementPopupSource)?.sourceElement?.focus()); + } + } + // Proxy control of this tooltip via the tooltip controller. Tooltip _controllerProxy; Tooltip get tooltipHandle => From f97c98c57b49d464c05577b2b8d12537d62e8d0b Mon Sep 17 00:00:00 2001 From: tijoforyou Date: Fri, 10 May 2019 05:59:47 -0700 Subject: [PATCH 297/503] Explicitly type, parameter annotated with @Attribute, as String. With angular components, attributes must be of type String. PiperOrigin-RevId: 247597505 --- angular_components/lib/material_list/material_list_item.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/angular_components/lib/material_list/material_list_item.dart b/angular_components/lib/material_list/material_list_item.dart index 64a282a83..a9d9693aa 100644 --- a/angular_components/lib/material_list/material_list_item.dart +++ b/angular_components/lib/material_list/material_list_item.dart @@ -40,7 +40,7 @@ class MaterialListItemComponent extends ButtonDirective implements OnDestroy { dom.HtmlElement element; MaterialListItemComponent(this.element, @Optional() this._dropdown, - @Attribute('tabindex') tabIndex, @Attribute('role') String role) + @Attribute('tabindex') String tabIndex, @Attribute('role') String role) : hostTabIndex = tabIndex ?? '0', super(element, role ?? 'listitem') { if (_dropdown != null) { From f92f1d557b4934b1dad4b7908c49125e236868b4 Mon Sep 17 00:00:00 2001 From: tijoforyou Date: Fri, 10 May 2019 06:01:14 -0700 Subject: [PATCH 298/503] Use the named providers instead of the soft deprecated provide(...) and Provider(...) https://github.com/dart-lang/angular/blob/master/doc/effective/dependency-injection.md#do-use-named-providers PiperOrigin-RevId: 247597624 --- .../lib/material_input/material_number_accessor.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/angular_components/lib/material_input/material_number_accessor.dart b/angular_components/lib/material_input/material_number_accessor.dart index 7ce32206b..edd361e4c 100644 --- a/angular_components/lib/material_input/material_number_accessor.dart +++ b/angular_components/lib/material_input/material_number_accessor.dart @@ -291,6 +291,6 @@ NumberFormat decimalNumberFormat() => NumberFormat.decimalPattern(); /// as the default. It should only be used with material-input[type=int64]. @Directive( selector: '[decimalNumberFormat]', - providers: [Provider(NumberFormat, useFactory: decimalNumberFormat)], + providers: [FactoryProvider(NumberFormat, decimalNumberFormat)], ) class DecimalNumberFormatDirective {} From 1d3607016d64fee084f7b1207b9ff0b0b656908f Mon Sep 17 00:00:00 2001 From: tijoforyou Date: Fri, 10 May 2019 06:07:01 -0700 Subject: [PATCH 299/503] Remove usages of deprecated getBool from menu_select.dart PiperOrigin-RevId: 247598494 --- .../lib/material_select/material_select.dart | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/angular_components/lib/material_select/material_select.dart b/angular_components/lib/material_select/material_select.dart index 8f6c554e0..5519acd8c 100644 --- a/angular_components/lib/material_select/material_select.dart +++ b/angular_components/lib/material_select/material_select.dart @@ -16,7 +16,6 @@ import 'package:angular_components/model/selection/selection_options.dart'; import 'package:angular_components/model/ui/has_factory.dart'; import 'package:angular_components/model/ui/has_renderer.dart'; import 'package:angular_components/model/ui/template_support.dart'; -import 'package:angular_components/utils/angular/properties/properties.dart'; import 'material_select_base.dart'; import 'material_select_item.dart'; @@ -59,7 +58,6 @@ class MaterialSelectComponent extends MaterialSelectBase /// DOM for the optionGroup. final Function trackByIndexFn = indexIdentityFn; - bool _disabled = false; bool _listAutoFocus = false; int _autoFocusIndex; @@ -130,14 +128,10 @@ class MaterialSelectComponent extends MaterialSelectBase /// /// Defaults to false. @Input() - set disabled(value) { - _disabled = getBool(value); - } - - bool get disabled => _disabled; + bool disabled = false; @HostBinding('attr.aria-disabled') - String get disabledStr => '$_disabled'; + String get disabledStr => '$disabled'; @override ItemRenderer get itemRenderer => _itemRenderer; From a65c18e7d85e2d9fc05bf88def084387570ecdb6 Mon Sep 17 00:00:00 2001 From: tijoforyou Date: Fri, 10 May 2019 06:15:13 -0700 Subject: [PATCH 300/503] Remove usages of deprecated getBool from menu_item_groups.dart, menu_popup_wrapper.dart, multi_suggest_input.dart, and scroll_host/lib/angular_2.dart PiperOrigin-RevId: 247599280 --- angular_components/lib/material_menu/menu_item_groups.dart | 5 ++--- angular_components/lib/material_menu/menu_popup_wrapper.dart | 4 ++-- .../lib/utils/angular/scroll_host/angular_2.dart | 5 ++--- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/angular_components/lib/material_menu/menu_item_groups.dart b/angular_components/lib/material_menu/menu_item_groups.dart index 8b879b2b5..f2a0b8b7c 100644 --- a/angular_components/lib/material_menu/menu_item_groups.dart +++ b/angular_components/lib/material_menu/menu_item_groups.dart @@ -32,7 +32,6 @@ import 'package:angular_components/model/menu/selectable_menu.dart'; import 'package:angular_components/model/selection/select.dart'; import 'package:angular_components/model/selection/selection_model.dart'; import 'package:angular_components/model/ui/highlighted_text_model.dart'; -import 'package:angular_components/utils/angular/properties/properties.dart'; import 'package:angular_components/utils/disposer/disposer.dart'; import 'package:angular_components/utils/id_generator/id_generator.dart'; @@ -104,8 +103,8 @@ class MenuItemGroupsComponent /// /// Defaults to `false`. @Input() - set preventCloseOnPressLeft(value) { - _closeOnPressLeft = !getBool(value); + set preventCloseOnPressLeft(bool value) { + _closeOnPressLeft = !value; } bool _closeOnPressLeft = true; diff --git a/angular_components/lib/material_menu/menu_popup_wrapper.dart b/angular_components/lib/material_menu/menu_popup_wrapper.dart index 3d5f994ae..d946e332d 100644 --- a/angular_components/lib/material_menu/menu_popup_wrapper.dart +++ b/angular_components/lib/material_menu/menu_popup_wrapper.dart @@ -42,10 +42,10 @@ class MenuPopupWrapper implements AcceptsWidth { /// visibility. Default state means no menu items are focused when the menu /// popup is opened. @Input() - set isExpanded(value) { + set isExpanded(bool value) { if (isExpanded == value) return; - if (getBool(value)) { + if (value) { expandAction ??= const ExpandAction.withNoFocus(); } else { expandAction = null; diff --git a/angular_components/lib/utils/angular/scroll_host/angular_2.dart b/angular_components/lib/utils/angular/scroll_host/angular_2.dart index ed56a2562..70fab48b8 100644 --- a/angular_components/lib/utils/angular/scroll_host/angular_2.dart +++ b/angular_components/lib/utils/angular/scroll_host/angular_2.dart @@ -7,7 +7,6 @@ import 'dart:html'; import 'package:angular/angular.dart'; import 'package:quiver/time.dart'; -import 'package:angular_components/utils/angular/properties/properties.dart'; import 'package:angular_components/utils/angular/scroll_host/interface.dart'; import 'package:angular_components/src/utils/angular/scroll_host/gestures.dart'; import 'package:angular_components/src/utils/angular/scroll_host/scroll_host_base.dart'; @@ -337,8 +336,8 @@ class StickyElementDirective implements AfterViewInit, OnDestroy { /// This allows the directive to be used for components in which the /// the sticky property is optional and dependent on input. @Input('sticky') - set sticky(sticky) { - _sticky = getBool(sticky); + set sticky(bool sticky) { + _sticky = sticky; if (_sticky) { _stick(); } else { From 0fe225db47f67ed2e41fd759cecacf6d6ef31647 Mon Sep 17 00:00:00 2001 From: tijoforyou Date: Fri, 10 May 2019 06:16:19 -0700 Subject: [PATCH 301/503] Remove usages of deprecated getBool from menu_suggest_input.dart Combined private field + public setter/getter pair into public field, where applicable, in the same file. PiperOrigin-RevId: 247599386 --- .../date_range_editor.html | 10 +-- .../material_datepicker.html | 2 +- .../lib/material_menu/menu_item_groups.html | 4 +- .../material_select/material_select_item.dart | 63 ++++--------------- .../comparison_range_editor.html | 2 +- .../lib/material_select_demo.html | 2 +- 6 files changed, 22 insertions(+), 61 deletions(-) diff --git a/angular_components/lib/material_datepicker/date_range_editor.html b/angular_components/lib/material_datepicker/date_range_editor.html index dd42c924d..d11c52d02 100644 --- a/angular_components/lib/material_datepicker/date_range_editor.html +++ b/angular_components/lib/material_datepicker/date_range_editor.html @@ -15,7 +15,7 @@
+ [closeOnActivate]="false">
{{customRangeMsg}} @@ -34,7 +34,7 @@ [showTooltipIf]="!isValid(preset)" [materialTooltip]="rangeDisabledTooltip" [selected]="isSelected(preset.range)" - closeOnActivate="false"> + [closeOnActivate]="false"> {{preset.title}}