diff --git a/src/cdk/clipboard/BUILD.bazel b/src/cdk/clipboard/BUILD.bazel index dc8f762aca61..cbfdf2b45778 100644 --- a/src/cdk/clipboard/BUILD.bazel +++ b/src/cdk/clipboard/BUILD.bazel @@ -10,6 +10,7 @@ ng_module( ), assets = glob(["**/*.html"]), deps = [ + "//src/cdk/coercion", "@npm//@angular/core", "@npm//rxjs", ], diff --git a/src/cdk/clipboard/copy-to-clipboard.ts b/src/cdk/clipboard/copy-to-clipboard.ts index a672b7d18f84..6f728f4dc4db 100644 --- a/src/cdk/clipboard/copy-to-clipboard.ts +++ b/src/cdk/clipboard/copy-to-clipboard.ts @@ -17,6 +17,7 @@ import { Optional, OnDestroy, } from '@angular/core'; +import {coerceNumberProperty, NumberInput} from '@angular/cdk/coercion'; import {Clipboard} from './clipboard'; import {PendingCopy} from './pending-copy'; @@ -48,7 +49,10 @@ export class CdkCopyToClipboard implements OnDestroy { * How many times to attempt to copy the text. This may be necessary for longer text, because * the browser needs time to fill an intermediate textarea element and copy the content. */ - @Input('cdkCopyToClipboardAttempts') attempts: number = 1; + @Input('cdkCopyToClipboardAttempts') + get attempts(): number { return this._attempts; } + set attempts(value: number) { this._attempts = coerceNumberProperty(value); } + private _attempts = 1; /** * Emits when some text is copied to the clipboard. The @@ -109,4 +113,6 @@ export class CdkCopyToClipboard implements OnDestroy { this._pending.clear(); this._destroyed = true; } + + static ngAcceptInputType_attempts: NumberInput; } diff --git a/src/cdk/drag-drop/directives/drop-list.ts b/src/cdk/drag-drop/directives/drop-list.ts index 691b313e7584..db2105f65445 100644 --- a/src/cdk/drag-drop/directives/drop-list.ts +++ b/src/cdk/drag-drop/directives/drop-list.ts @@ -8,10 +8,10 @@ import { BooleanInput, + NumberInput, coerceArray, - coerceNumberProperty, coerceBooleanProperty, - NumberInput, + coerceNumberProperty, } from '@angular/cdk/coercion'; import { ElementRef, diff --git a/src/cdk/overlay/overlay-directives.ts b/src/cdk/overlay/overlay-directives.ts index bcebf3c5a82d..a94b38f0b742 100644 --- a/src/cdk/overlay/overlay-directives.ts +++ b/src/cdk/overlay/overlay-directives.ts @@ -7,7 +7,12 @@ */ import {Direction, Directionality} from '@angular/cdk/bidi'; -import {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion'; +import { + BooleanInput, + NumberInput, + coerceBooleanProperty, + coerceNumberProperty, +} from '@angular/cdk/coercion'; import {ESCAPE, hasModifierKey} from '@angular/cdk/keycodes'; import {TemplatePortal} from '@angular/cdk/portal'; import { @@ -100,6 +105,9 @@ export class CdkOverlayOrigin { export class CdkConnectedOverlay implements OnDestroy, OnChanges { private _overlayRef: OverlayRef; private _templatePortal: TemplatePortal; + private _viewportMargin = 0; + private _open = false; + private _disableClose = false; private _hasBackdrop = false; private _lockPosition = false; private _growAfterOpen = false; @@ -131,7 +139,7 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges { @Input('cdkConnectedOverlayOffsetX') get offsetX(): number { return this._offsetX; } set offsetX(offsetX: number) { - this._offsetX = offsetX; + this._offsetX = coerceNumberProperty(offsetX); if (this._position) { this._updatePositionStrategy(this._position); @@ -142,7 +150,7 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges { @Input('cdkConnectedOverlayOffsetY') get offsetY() { return this._offsetY; } set offsetY(offsetY: number) { - this._offsetY = offsetY; + this._offsetY = coerceNumberProperty(offsetY); if (this._position) { this._updatePositionStrategy(this._position); @@ -168,16 +176,22 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges { @Input('cdkConnectedOverlayPanelClass') panelClass: string | string[]; /** Margin between the overlay and the viewport edges. */ - @Input('cdkConnectedOverlayViewportMargin') viewportMargin: number = 0; + @Input('cdkConnectedOverlayViewportMargin') + get viewportMargin(): number { return this._viewportMargin; } + set viewportMargin(value: number) { this._viewportMargin = coerceNumberProperty(value); } /** Strategy to be used when handling scroll events while the overlay is open. */ @Input('cdkConnectedOverlayScrollStrategy') scrollStrategy: ScrollStrategy; /** Whether the overlay is open. */ - @Input('cdkConnectedOverlayOpen') open: boolean = false; + @Input('cdkConnectedOverlayOpen') + get open() { return this._open; } + set open(value: any) { this._open = coerceBooleanProperty(value); } /** Whether the overlay can be closed by user interaction. */ - @Input('cdkConnectedOverlayDisableClose') disableClose: boolean = false; + @Input('cdkConnectedOverlayDisableClose') + get disableClose() { return this._disableClose; } + set disableClose(value: any) { this._disableClose = coerceBooleanProperty(value); } /** CSS selector which to set the transform origin. */ @Input('cdkConnectedOverlayTransformOriginOn') transformOriginSelector: string; @@ -428,6 +442,11 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges { this._positionSubscription.unsubscribe(); } + static ngAcceptInputType_offsetX: NumberInput; + static ngAcceptInputType_offsetY: NumberInput; + static ngAcceptInputType_viewportMargin: NumberInput; + static ngAcceptInputType_open: BooleanInput; + static ngAcceptInputType_disableClose: BooleanInput; static ngAcceptInputType_hasBackdrop: BooleanInput; static ngAcceptInputType_lockPosition: BooleanInput; static ngAcceptInputType_flexibleDimensions: BooleanInput; diff --git a/src/google-maps/BUILD.bazel b/src/google-maps/BUILD.bazel index 474cc720258d..721870d7e397 100644 --- a/src/google-maps/BUILD.bazel +++ b/src/google-maps/BUILD.bazel @@ -12,6 +12,7 @@ ng_module( ), deps = [ "//src:dev_mode_types", + "//src/cdk/coercion", "@npm//@angular/common", "@npm//@angular/core", "@npm//@types/googlemaps", diff --git a/src/google-maps/google-map/google-map.ts b/src/google-maps/google-map/google-map.ts index e88cfbd68ae2..fc8e3db4ff74 100644 --- a/src/google-maps/google-map/google-map.ts +++ b/src/google-maps/google-map/google-map.ts @@ -26,6 +26,7 @@ import { EventEmitter, } from '@angular/core'; import {isPlatformBrowser} from '@angular/common'; +import {NumberInput, coerceNumberProperty} from '@angular/cdk/coercion'; import {Observable} from 'rxjs'; import {MapEventManager} from '../map-event-manager'; @@ -93,10 +94,10 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy { private _center: google.maps.LatLngLiteral|google.maps.LatLng; @Input() - set zoom(zoom: number) { - this._zoom = zoom; + set zoom(zoom: number | undefined) { + this._zoom = zoom === undefined ? zoom : coerceNumberProperty(zoom); } - private _zoom: number; + private _zoom: number | undefined; @Input() set options(options: google.maps.MapOptions) { @@ -505,6 +506,8 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy { 'Please wait for the API to load before trying to interact with it.'); } } + + static ngAcceptInputType_zoom: NumberInput; } const cssUnitsPattern = /([A-Za-z%]+)$/; diff --git a/src/google-maps/map-circle/map-circle.ts b/src/google-maps/map-circle/map-circle.ts index 78a3de30f423..9e897636b68c 100644 --- a/src/google-maps/map-circle/map-circle.ts +++ b/src/google-maps/map-circle/map-circle.ts @@ -10,6 +10,7 @@ /// import {Directive, Input, NgZone, OnDestroy, OnInit, Output} from '@angular/core'; +import {NumberInput, coerceNumberProperty} from '@angular/cdk/coercion'; import {BehaviorSubject, combineLatest, Observable, Subject} from 'rxjs'; import {map, take, takeUntil} from 'rxjs/operators'; @@ -51,8 +52,8 @@ export class MapCircle implements OnInit, OnDestroy { } @Input() - set radius(radius: number) { - this._radius.next(radius); + set radius(radius: number | undefined) { + this._radius.next(radius === undefined ? radius : coerceNumberProperty(radius)); } /** @@ -282,4 +283,6 @@ export class MapCircle implements OnInit, OnDestroy { } } } + + static ngAcceptInputType_radius: NumberInput; } diff --git a/src/google-maps/map-ground-overlay/map-ground-overlay.ts b/src/google-maps/map-ground-overlay/map-ground-overlay.ts index 5c8afcb79843..105ef8eb32f9 100644 --- a/src/google-maps/map-ground-overlay/map-ground-overlay.ts +++ b/src/google-maps/map-ground-overlay/map-ground-overlay.ts @@ -10,6 +10,12 @@ /// import {Directive, Input, NgZone, OnDestroy, OnInit, Output} from '@angular/core'; +import { + BooleanInput, + NumberInput, + coerceBooleanProperty, + coerceNumberProperty +} from '@angular/cdk/coercion'; import {BehaviorSubject, Observable, Subject} from 'rxjs'; import {takeUntil} from 'rxjs/operators'; @@ -27,6 +33,7 @@ import {MapEventManager} from '../map-event-manager'; }) export class MapGroundOverlay implements OnInit, OnDestroy { private _eventManager = new MapEventManager(this._ngZone); + private _clickable = false; private readonly _opacity = new BehaviorSubject(1); private readonly _url = new BehaviorSubject(''); @@ -58,12 +65,14 @@ export class MapGroundOverlay implements OnInit, OnDestroy { } /** Whether the overlay is clickable */ - @Input() clickable: boolean = false; + @Input() + get clickable() { return this._clickable; } + set clickable(value: any) { this._clickable = coerceBooleanProperty(value); } /** Opacity of the overlay. */ @Input() set opacity(opacity: number) { - this._opacity.next(opacity); + this._opacity.next(coerceNumberProperty(opacity)); } /** @@ -189,4 +198,7 @@ export class MapGroundOverlay implements OnInit, OnDestroy { } } } + + static ngAcceptInputType_clickable: BooleanInput; + static ngAcceptInputType_opacity: NumberInput; } diff --git a/src/google-maps/map-marker-clusterer/map-marker-clusterer.spec.ts b/src/google-maps/map-marker-clusterer/map-marker-clusterer.spec.ts index 551e092aa416..46144ed0749c 100644 --- a/src/google-maps/map-marker-clusterer/map-marker-clusterer.spec.ts +++ b/src/google-maps/map-marker-clusterer/map-marker-clusterer.spec.ts @@ -80,11 +80,11 @@ describe('MapMarkerClusterer', () => { imagePath: undefined, imageSizes: undefined, maxZoom: undefined, - minimumClusterSize: undefined, + minimumClusterSize: 0, styles: undefined, title: undefined, zIndex: undefined, - zoomOnClick: undefined, + zoomOnClick: false, }); }); diff --git a/src/google-maps/map-marker-clusterer/map-marker-clusterer.ts b/src/google-maps/map-marker-clusterer/map-marker-clusterer.ts index 0ae2e1ecb6ef..6cd1e141cdb4 100644 --- a/src/google-maps/map-marker-clusterer/map-marker-clusterer.ts +++ b/src/google-maps/map-marker-clusterer/map-marker-clusterer.ts @@ -25,6 +25,13 @@ import { SimpleChanges, ViewEncapsulation } from '@angular/core'; +import { + BooleanInput, + NumberInput, + coerceArray, + coerceBooleanProperty, + coerceNumberProperty +} from '@angular/cdk/coercion'; import {Observable, Subject} from 'rxjs'; import {takeUntil} from 'rxjs/operators'; @@ -59,18 +66,25 @@ export class MapMarkerClusterer implements OnInit, AfterContentInit, OnChanges, ariaLabelFn: AriaLabelFn = () => '' @Input() - set averageCenter(averageCenter: boolean) { - this._averageCenter = averageCenter; + set averageCenter(averageCenter: boolean | undefined) { + this._averageCenter = averageCenter === undefined + ? averageCenter + : coerceBooleanProperty(averageCenter); } - private _averageCenter: boolean; + private _averageCenter: boolean | undefined; - @Input() batchSize?: number; + @Input() + get batchSize(): number | undefined { return this._batchSize; } + set batchSize(batchSize: any) { + this._batchSize = batchSize === undefined ? batchSize : coerceNumberProperty(batchSize); + } + private _batchSize?: number; @Input() - set batchSizeIE(batchSizeIE: number) { - this._batchSizeIE = batchSizeIE; + set batchSizeIE(batchSizeIE: number | undefined) { + this._batchSizeIE = batchSizeIE === undefined ? batchSizeIE : coerceNumberProperty(batchSizeIE); } - private _batchSizeIE: number; + private _batchSizeIE?: number; @Input() set calculator(calculator: Calculator) { @@ -85,22 +99,26 @@ export class MapMarkerClusterer implements OnInit, AfterContentInit, OnChanges, private _clusterClass: string; @Input() - set enableRetinaIcons(enableRetinaIcons: boolean) { - this._enableRetinaIcons = enableRetinaIcons; + set enableRetinaIcons(enableRetinaIcons: boolean | undefined) { + this._enableRetinaIcons = enableRetinaIcons === undefined + ? enableRetinaIcons + : coerceBooleanProperty(enableRetinaIcons); } - private _enableRetinaIcons: boolean; + private _enableRetinaIcons: boolean | undefined; @Input() - set gridSize(gridSize: number) { - this._gridSize = gridSize; + set gridSize(gridSize: number | undefined) { + this._gridSize = gridSize === undefined ? gridSize : coerceNumberProperty(gridSize); } - private _gridSize: number; + private _gridSize: number | undefined; @Input() - set ignoreHidden(ignoreHidden: boolean) { - this._ignoreHidden = ignoreHidden; + set ignoreHidden(ignoreHidden: boolean | undefined) { + this._ignoreHidden = ignoreHidden === undefined + ? ignoreHidden + : coerceBooleanProperty(ignoreHidden); } - private _ignoreHidden: boolean; + private _ignoreHidden: boolean | undefined; @Input() set imageExtension(imageExtension: string) { @@ -115,20 +133,20 @@ export class MapMarkerClusterer implements OnInit, AfterContentInit, OnChanges, private _imagePath: string; @Input() - set imageSizes(imageSizes: number[]) { - this._imageSizes = imageSizes; + set imageSizes(imageSizes: number | number[] | undefined) { + this._imageSizes = imageSizes === undefined ? imageSizes : coerceArray(imageSizes); } - private _imageSizes: number[]; + private _imageSizes: number[] | undefined; @Input() - set maxZoom(maxZoom: number) { - this._maxZoom = maxZoom; + set maxZoom(maxZoom: number | undefined) { + this._maxZoom = maxZoom === undefined ? maxZoom : coerceNumberProperty(maxZoom); } - private _maxZoom: number; + private _maxZoom: number | undefined; @Input() set minimumClusterSize(minimumClusterSize: number) { - this._minimumClusterSize = minimumClusterSize; + this._minimumClusterSize = coerceNumberProperty(minimumClusterSize); } private _minimumClusterSize: number; @@ -145,14 +163,14 @@ export class MapMarkerClusterer implements OnInit, AfterContentInit, OnChanges, private _title: string; @Input() - set zIndex(zIndex: number) { - this._zIndex = zIndex; + set zIndex(zIndex: number | undefined) { + this._zIndex = zIndex === undefined ? zIndex : coerceNumberProperty(zIndex); } - private _zIndex: number; + private _zIndex: number | undefined; @Input() set zoomOnClick(zoomOnClick: boolean) { - this._zoomOnClick = zoomOnClick; + this._zoomOnClick = coerceBooleanProperty(zoomOnClick); } private _zoomOnClick: boolean; @@ -480,4 +498,15 @@ export class MapMarkerClusterer implements OnInit, AfterContentInit, OnChanges, } } } + + static ngAcceptInputType_averageCenter: BooleanInput; + static ngAcceptInputType_batchSize: NumberInput; + static ngAcceptInputType_batchSizeIE: NumberInput; + static ngAcceptInputType_enableRetinaIcons: BooleanInput; + static ngAcceptInputType_gridSize: NumberInput; + static ngAcceptInputType_ignoreHidden: BooleanInput; + static ngAcceptInputType_maxZoom: NumberInput; + static ngAcceptInputType_minimumClusterSize: NumberInput; + static ngAcceptInputType_zIndex: NumberInput; + static ngAcceptInputType_zoomOnClick: BooleanInput; } diff --git a/src/google-maps/map-marker/map-marker.spec.ts b/src/google-maps/map-marker/map-marker.spec.ts index 178663864027..c8f73b48e358 100644 --- a/src/google-maps/map-marker/map-marker.spec.ts +++ b/src/google-maps/map-marker/map-marker.spec.ts @@ -44,9 +44,9 @@ describe('MapMarker', () => { ...DEFAULT_MARKER_OPTIONS, title: undefined, label: undefined, - clickable: undefined, + clickable: false, icon: undefined, - visible: undefined, + visible: false, map: mapSpy, }); }); @@ -83,7 +83,7 @@ describe('MapMarker', () => { label: 'marker label', clickable: false, icon: 'icon name', - visible: undefined + visible: false }; const markerSpy = createMarkerSpy(options); const markerConstructorSpy = createMarkerConstructorSpy(markerSpy).and.callThrough(); @@ -110,7 +110,7 @@ describe('MapMarker', () => { clickable: true, icon: 'icon name', map: mapSpy, - visible: undefined + visible: false }; const markerSpy = createMarkerSpy(options); const markerConstructorSpy = createMarkerConstructorSpy(markerSpy).and.callThrough(); diff --git a/src/google-maps/map-marker/map-marker.ts b/src/google-maps/map-marker/map-marker.ts index d02e0cd30679..2077da51ab91 100644 --- a/src/google-maps/map-marker/map-marker.ts +++ b/src/google-maps/map-marker/map-marker.ts @@ -19,6 +19,7 @@ import { OnChanges, SimpleChanges, } from '@angular/core'; +import {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion'; import {Observable} from 'rxjs'; import {GoogleMap} from '../google-map/google-map'; @@ -81,7 +82,7 @@ export class MapMarker implements OnInit, OnChanges, OnDestroy, MapAnchorPoint { */ @Input() set clickable(clickable: boolean) { - this._clickable = clickable; + this._clickable = coerceBooleanProperty(clickable); } private _clickable: boolean; @@ -111,7 +112,7 @@ export class MapMarker implements OnInit, OnChanges, OnDestroy, MapAnchorPoint { */ @Input() set visible(value: boolean) { - this._visible = value; + this._visible = coerceBooleanProperty(value); } private _visible: boolean; @@ -471,4 +472,7 @@ export class MapMarker implements OnInit, OnChanges, OnDestroy, MapAnchorPoint { } } } + + static ngAcceptInputType_clickable: BooleanInput; + static ngAcceptInputType_visible: BooleanInput; } diff --git a/src/google-maps/map-traffic-layer/map-traffic-layer.ts b/src/google-maps/map-traffic-layer/map-traffic-layer.ts index 47c6988aa98e..50ec9c9836ce 100644 --- a/src/google-maps/map-traffic-layer/map-traffic-layer.ts +++ b/src/google-maps/map-traffic-layer/map-traffic-layer.ts @@ -10,6 +10,7 @@ /// import {Directive, Input, NgZone, OnDestroy, OnInit} from '@angular/core'; +import {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion'; import {BehaviorSubject, Observable, Subject} from 'rxjs'; import {map, take, takeUntil} from 'rxjs/operators'; @@ -40,7 +41,7 @@ export class MapTrafficLayer implements OnInit, OnDestroy { */ @Input() set autoRefresh(autoRefresh: boolean) { - this._autoRefresh.next(autoRefresh); + this._autoRefresh.next(coerceBooleanProperty(autoRefresh)); } constructor(private readonly _map: GoogleMap, private readonly _ngZone: NgZone) {} @@ -94,4 +95,6 @@ export class MapTrafficLayer implements OnInit, OnDestroy { 'Please wait for the Traffic Layer to load before trying to interact with it.'); } } + + static ngAcceptInputType_autoRefresh: BooleanInput; } diff --git a/src/google-maps/package.json b/src/google-maps/package.json index 242f18504ae1..c66cc55c56a7 100644 --- a/src/google-maps/package.json +++ b/src/google-maps/package.json @@ -21,6 +21,7 @@ "tslib": "0.0.0-TSLIB" }, "peerDependencies": { + "@angular/cdk": "0.0.0-PLACEHOLDER", "@angular/core": "0.0.0-NG", "@angular/common": "0.0.0-NG", "rxjs": "0.0.0-RXJS" diff --git a/src/google-maps/tsconfig-tests.json b/src/google-maps/tsconfig-tests.json index 0b483e5010b7..f234a9721924 100644 --- a/src/google-maps/tsconfig-tests.json +++ b/src/google-maps/tsconfig-tests.json @@ -1,5 +1,10 @@ { "extends": "../bazel-tsconfig-build.json", + "references": [ + { + "path": "../cdk/tsconfig-tests.json" + } + ], "compilerOptions": { "baseUrl": ".", "outDir": "../../dist/packages/google-maps", @@ -13,7 +18,10 @@ "target": "es5", "types": ["jasmine"], "experimentalDecorators": true, - "emitDecoratorMetadata": true + "emitDecoratorMetadata": true, + "paths": { + "@angular/cdk/*": ["../../dist/packages/cdk/*"] + } }, "include": [ "**/*.spec.ts", diff --git a/src/google-maps/tsconfig.json b/src/google-maps/tsconfig.json index d57281895299..deabd52aa26e 100644 --- a/src/google-maps/tsconfig.json +++ b/src/google-maps/tsconfig.json @@ -4,7 +4,9 @@ "compilerOptions": { "rootDir": "..", "baseUrl": ".", - "paths": {}, + "paths": { + "@angular/cdk/*": ["../cdk/*"] + }, "types": [ "jasmine" ] diff --git a/src/material-experimental/mdc-checkbox/checkbox.ts b/src/material-experimental/mdc-checkbox/checkbox.ts index 5056ce39d26d..e443fd33315b 100644 --- a/src/material-experimental/mdc-checkbox/checkbox.ts +++ b/src/material-experimental/mdc-checkbox/checkbox.ts @@ -6,7 +6,12 @@ * found in the LICENSE file at https://angular.io/license */ -import {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion'; +import { + BooleanInput, + NumberInput, + coerceBooleanProperty, + coerceNumberProperty, +} from '@angular/cdk/coercion'; import { AfterViewInit, Attribute, @@ -102,7 +107,10 @@ export class MatCheckbox extends _MatCheckboxBase implements AfterViewInit, OnDe @Input() name: string|null = null; /** The `tabindex` attribute to use for the input element. */ - @Input() tabIndex: number; + @Input() + get tabIndex(): number { return this._tabIndex; } + set tabIndex(value: number) { this._tabIndex = coerceNumberProperty(value); } + private _tabIndex: number; /** The `value` attribute to use for the input element */ @Input() value: string; @@ -385,6 +393,7 @@ export class MatCheckbox extends _MatCheckboxBase implements AfterViewInit, OnDe } } + static ngAcceptInputType_tabIndex: NumberInput; static ngAcceptInputType_checked: BooleanInput; static ngAcceptInputType_indeterminate: BooleanInput; static ngAcceptInputType_disabled: BooleanInput; diff --git a/src/material-experimental/mdc-chips/chip-row.ts b/src/material-experimental/mdc-chips/chip-row.ts index a879ee84b09a..d31524f5a2f4 100644 --- a/src/material-experimental/mdc-chips/chip-row.ts +++ b/src/material-experimental/mdc-chips/chip-row.ts @@ -7,7 +7,7 @@ */ import {Directionality} from '@angular/cdk/bidi'; -import {BooleanInput} from '@angular/cdk/coercion'; +import {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion'; import {BACKSPACE, DELETE} from '@angular/cdk/keycodes'; import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations'; import { @@ -78,7 +78,10 @@ export class MatChipRow extends MatChip implements AfterContentInit, AfterViewIn GridKeyManagerRow { protected override basicChipAttrName = 'mat-basic-chip-row'; - @Input() editable: boolean = false; + @Input() + get editable(): boolean { return this._editable; } + set editable(value: boolean) { this._editable = coerceBooleanProperty(value); } + private _editable = false; /** Emitted when the chip is edited. */ @Output() readonly edited: EventEmitter = diff --git a/src/material-experimental/mdc-form-field/directives/floating-label.ts b/src/material-experimental/mdc-form-field/directives/floating-label.ts index e0932abb3d3b..bfc30775d4b3 100644 --- a/src/material-experimental/mdc-form-field/directives/floating-label.ts +++ b/src/material-experimental/mdc-form-field/directives/floating-label.ts @@ -7,6 +7,7 @@ */ import {Directive, ElementRef, Input} from '@angular/core'; +import {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion'; import {ponyfill} from '@material/dom'; /** @@ -31,10 +32,21 @@ import {ponyfill} from '@material/dom'; }, }) export class MatFormFieldFloatingLabel { + private _floating = false; + private _required = false; + /** Whether the label is floating. */ - @Input() floating: boolean = false; + @Input() + get floating(): boolean { return this._floating; } + set floating(value: boolean) { this._floating = coerceBooleanProperty(value); } + /** Whether the label is required. */ - @Input() required: boolean = false; + @Input() + get required(): boolean { return this._required; } + set required(value: boolean) { this._required = coerceBooleanProperty(value); } + + /** Gets the HTML element for the floating label. */ + get element(): HTMLElement { return this._elementRef.nativeElement; } constructor(private _elementRef: ElementRef) {} @@ -43,8 +55,6 @@ export class MatFormFieldFloatingLabel { return ponyfill.estimateScrollWidth(this._elementRef.nativeElement); } - /** Gets the HTML element for the floating label. */ - get element(): HTMLElement { - return this._elementRef.nativeElement; - } + static ngAcceptInputType_floating: BooleanInput; + static ngAcceptInputType_required: BooleanInput; } diff --git a/src/material-experimental/mdc-form-field/directives/notched-outline.ts b/src/material-experimental/mdc-form-field/directives/notched-outline.ts index 63eac20ee532..81de2499d5fe 100644 --- a/src/material-experimental/mdc-form-field/directives/notched-outline.ts +++ b/src/material-experimental/mdc-form-field/directives/notched-outline.ts @@ -6,6 +6,12 @@ * found in the LICENSE file at https://angular.io/license */ +import { + BooleanInput, + NumberInput, + coerceBooleanProperty, + coerceNumberProperty, +} from '@angular/cdk/coercion'; import {Platform} from '@angular/cdk/platform'; import { AfterViewInit, @@ -42,10 +48,16 @@ import {MDCNotchedOutline} from '@material/notched-outline'; }) export class MatFormFieldNotchedOutline implements AfterViewInit, OnChanges, OnDestroy { /** Width of the notch. */ - @Input('matFormFieldNotchedOutlineWidth') width: number = 0; + @Input('matFormFieldNotchedOutlineWidth') + get width(): number { return this._width; } + set width(value: number) { this._width = coerceNumberProperty(value); } + private _width = 0; /** Whether the notch should be opened. */ - @Input('matFormFieldNotchedOutlineOpen') open: boolean = false; + @Input('matFormFieldNotchedOutlineOpen') + get open(): boolean { return this._open; } + set open(value: boolean) { this._open = coerceBooleanProperty(value); } + private _open = false; /** Instance of the MDC notched outline. */ private _mdcNotchedOutline: MDCNotchedOutline|null = null; @@ -89,4 +101,7 @@ export class MatFormFieldNotchedOutline implements AfterViewInit, OnChanges, OnD this._mdcNotchedOutline.closeNotch(); } } + + static ngAcceptInputType_width: NumberInput; + static ngAcceptInputType_open: BooleanInput; } diff --git a/src/material-experimental/mdc-progress-bar/progress-bar.ts b/src/material-experimental/mdc-progress-bar/progress-bar.ts index fdda55384a87..98a6e2d6d1ef 100644 --- a/src/material-experimental/mdc-progress-bar/progress-bar.ts +++ b/src/material-experimental/mdc-progress-bar/progress-bar.ts @@ -20,6 +20,7 @@ import { AfterViewInit, OnDestroy, } from '@angular/core'; +import {NumberInput, coerceNumberProperty} from '@angular/cdk/coercion'; import {CanColor, mixinColor} from '@angular/material-experimental/mdc-core'; import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations'; import { @@ -148,7 +149,7 @@ export class MatProgressBar extends _MatProgressBarBase implements AfterViewInit @Input() get value(): number { return this._value; } set value(v: number) { - this._value = clamp(v || 0); + this._value = clamp(coerceNumberProperty(v, 0)); this._syncFoundation(); } private _value = 0; @@ -157,7 +158,7 @@ export class MatProgressBar extends _MatProgressBarBase implements AfterViewInit @Input() get bufferValue(): number { return this._bufferValue || 0; } set bufferValue(v: number) { - this._bufferValue = clamp(v || 0); + this._bufferValue = clamp(coerceNumberProperty(v, 0)); this._syncFoundation(); } private _bufferValue = 0; @@ -243,6 +244,9 @@ export class MatProgressBar extends _MatProgressBarBase implements AfterViewInit } } } + + static ngAcceptInputType_value: NumberInput; + static ngAcceptInputType_bufferValue: NumberInput; } /** Clamps a value to be between two numbers, by default 0 and 100. */ diff --git a/src/material-experimental/mdc-slider/slider.ts b/src/material-experimental/mdc-slider/slider.ts index 287641d4ad9b..1e6c2b7dbe65 100644 --- a/src/material-experimental/mdc-slider/slider.ts +++ b/src/material-experimental/mdc-slider/slider.ts @@ -90,7 +90,10 @@ export interface MatSliderDragEvent { }) export class MatSliderVisualThumb implements AfterViewInit, OnDestroy { /** Whether the slider displays a numeric value label upon pressing the thumb. */ - @Input() discrete: boolean; + @Input() + get discrete(): boolean { return this._discrete; } + set discrete(value: boolean) { this._discrete = coerceBooleanProperty(value); } + private _discrete: boolean; /** Indicates which slider thumb this input corresponds to. */ @Input() thumbPosition: Thumb; @@ -99,7 +102,10 @@ export class MatSliderVisualThumb implements AfterViewInit, OnDestroy { @Input() valueIndicatorText: string; /** Whether ripples on the slider thumb should be disabled. */ - @Input() disableRipple: boolean = false; + @Input() + get disableRipple(): boolean { return this._disableRipple; } + set disableRipple(value: boolean) { this._disableRipple = coerceBooleanProperty(value); } + private _disableRipple = false; /** The MatRipple for this slider thumb. */ @ViewChild(MatRipple) private readonly _ripple: MatRipple; @@ -260,6 +266,9 @@ export class MatSliderVisualThumb implements AfterViewInit, OnDestroy { _getKnob(): HTMLElement { return this._knob.nativeElement; } + + static ngAcceptInputType_discrete: BooleanInput; + static ngAcceptInputType_disableRipple: BooleanInput; } /** diff --git a/src/material/button-toggle/button-toggle.ts b/src/material/button-toggle/button-toggle.ts index 8211689b7edb..225b04ee45d7 100644 --- a/src/material/button-toggle/button-toggle.ts +++ b/src/material/button-toggle/button-toggle.ts @@ -7,7 +7,12 @@ */ import {FocusMonitor} from '@angular/cdk/a11y'; -import {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion'; +import { + BooleanInput, + NumberInput, + coerceBooleanProperty, + coerceNumberProperty +} from '@angular/cdk/coercion'; import {SelectionModel} from '@angular/cdk/collections'; import { AfterContentInit, @@ -445,7 +450,10 @@ export class MatButtonToggle extends _MatButtonToggleBase implements OnInit, Aft @Input() value: any; /** Tabindex for the toggle. */ - @Input() tabIndex: number | null; + @Input() + get tabIndex(): number | null { return this._tabIndex; } + set tabIndex(value: number | null) { this._tabIndex = coerceNumberProperty(value); } + private _tabIndex: number | null; /** The appearance style of the button. */ @Input() @@ -573,6 +581,7 @@ export class MatButtonToggle extends _MatButtonToggleBase implements OnInit, Aft this._changeDetectorRef.markForCheck(); } + static ngAcceptInputType_tabIndex: NumberInput; static ngAcceptInputType_checked: BooleanInput; static ngAcceptInputType_disabled: BooleanInput; static ngAcceptInputType_vertical: BooleanInput; diff --git a/src/material/button/button.ts b/src/material/button/button.ts index 74abd5d24b9d..a63b744c8cd4 100644 --- a/src/material/button/button.ts +++ b/src/material/button/button.ts @@ -7,7 +7,7 @@ */ import {FocusMonitor, FocusableOption, FocusOrigin} from '@angular/cdk/a11y'; -import {BooleanInput} from '@angular/cdk/coercion'; +import {BooleanInput, NumberInput, coerceNumberProperty} from '@angular/cdk/coercion'; import { ChangeDetectionStrategy, Component, @@ -172,7 +172,10 @@ export class MatButton extends _MatButtonBase }) export class MatAnchor extends MatButton { /** Tabindex of the button. */ - @Input() tabIndex: number; + @Input() + get tabIndex(): number { return this._tabIndex; } + set tabIndex(value: number) { this._tabIndex = coerceNumberProperty(value); } + private _tabIndex: number; constructor( focusMonitor: FocusMonitor, @@ -188,4 +191,6 @@ export class MatAnchor extends MatButton { event.stopImmediatePropagation(); } } + + static ngAcceptInputType_tabIndex: NumberInput; } diff --git a/src/material/checkbox/checkbox.ts b/src/material/checkbox/checkbox.ts index 27e109cc59f1..c5a24be3b7ca 100644 --- a/src/material/checkbox/checkbox.ts +++ b/src/material/checkbox/checkbox.ts @@ -7,7 +7,12 @@ */ import {FocusableOption, FocusMonitor, FocusOrigin} from '@angular/cdk/a11y'; -import {BooleanInput, coerceBooleanProperty, NumberInput} from '@angular/cdk/coercion'; +import { + BooleanInput, + NumberInput, + coerceBooleanProperty, + coerceNumberProperty +} from '@angular/cdk/coercion'; import { AfterViewChecked, Attribute, @@ -199,7 +204,7 @@ export class MatCheckbox extends _MatCheckboxBase implements ControlValueAccesso super(elementRef); this._options = this._options || defaults; this.color = this.defaultColor = this._options.color || defaults.color; - this.tabIndex = parseInt(tabIndex) || 0; + this.tabIndex = coerceNumberProperty(tabIndex, 0); } ngAfterViewInit() { @@ -233,8 +238,10 @@ export class MatCheckbox extends _MatCheckboxBase implements ControlValueAccesso @Input() get checked(): boolean { return this._checked; } set checked(value: boolean) { - if (value != this.checked) { - this._checked = value; + const newValue = coerceBooleanProperty(value); + + if (newValue != this.checked) { + this._checked = newValue; this._changeDetectorRef.markForCheck(); } } @@ -265,8 +272,9 @@ export class MatCheckbox extends _MatCheckboxBase implements ControlValueAccesso @Input() get indeterminate(): boolean { return this._indeterminate; } set indeterminate(value: boolean) { - const changed = value != this._indeterminate; - this._indeterminate = coerceBooleanProperty(value); + const newValue = coerceBooleanProperty(value); + const changed = newValue != this._indeterminate; + this._indeterminate = coerceBooleanProperty(newValue); if (changed) { if (this._indeterminate) { @@ -489,9 +497,10 @@ export class MatCheckbox extends _MatCheckboxBase implements ControlValueAccesso } } - static ngAcceptInputType_disabled: BooleanInput; static ngAcceptInputType_required: BooleanInput; static ngAcceptInputType_disableRipple: BooleanInput; - static ngAcceptInputType_indeterminate: BooleanInput; static ngAcceptInputType_tabIndex: NumberInput; + static ngAcceptInputType_checked: BooleanInput; + static ngAcceptInputType_disabled: BooleanInput; + static ngAcceptInputType_indeterminate: BooleanInput; } diff --git a/src/material/chips/chip-list.ts b/src/material/chips/chip-list.ts index de95edc14aee..141dbbfcc628 100644 --- a/src/material/chips/chip-list.ts +++ b/src/material/chips/chip-list.ts @@ -8,7 +8,12 @@ import {FocusKeyManager} from '@angular/cdk/a11y'; import {Directionality} from '@angular/cdk/bidi'; -import {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion'; +import { + BooleanInput, + NumberInput, + coerceBooleanProperty, + coerceNumberProperty, +} from '@angular/cdk/coercion'; import {SelectionModel} from '@angular/cdk/collections'; import { AfterContentInit, @@ -294,8 +299,9 @@ export class MatChipList extends _MatChipListBase implements MatFormFieldControl @Input() set tabIndex(value: number) { - this._userTabIndex = value; - this._tabIndex = value; + const newValue = coerceNumberProperty(value); + this._userTabIndex = newValue; + this._tabIndex = newValue; } /** Combined stream of all of the child chips' selection change events. */ @@ -800,4 +806,5 @@ export class MatChipList extends _MatChipListBase implements MatFormFieldControl static ngAcceptInputType_required: BooleanInput; static ngAcceptInputType_disabled: BooleanInput; static ngAcceptInputType_selectable: BooleanInput; + static ngAcceptInputType_tabIndex: NumberInput; } diff --git a/src/material/chips/chip.ts b/src/material/chips/chip.ts index 235e8b632cbb..ab659a741471 100644 --- a/src/material/chips/chip.ts +++ b/src/material/chips/chip.ts @@ -7,7 +7,12 @@ */ import {FocusableOption} from '@angular/cdk/a11y'; -import {BooleanInput, coerceBooleanProperty, NumberInput} from '@angular/cdk/coercion'; +import { + BooleanInput, + NumberInput, + coerceBooleanProperty, + coerceNumberProperty, +} from '@angular/cdk/coercion'; import {BACKSPACE, DELETE, SPACE} from '@angular/cdk/keycodes'; import {Platform} from '@angular/cdk/platform'; import {DOCUMENT} from '@angular/common'; @@ -297,7 +302,7 @@ export class MatChip extends _MatChipMixinBase implements FocusableOption, OnDes this.rippleConfig = globalRippleOptions || {}; this._animationsDisabled = animationMode === 'NoopAnimations'; - this.tabIndex = tabIndex != null ? (parseInt(tabIndex) || -1) : -1; + this.tabIndex = coerceNumberProperty(tabIndex, -1); } _addHostClassName() { diff --git a/src/material/core/ripple/ripple.ts b/src/material/core/ripple/ripple.ts index e2357b86b280..eb9081ab59b7 100644 --- a/src/material/core/ripple/ripple.ts +++ b/src/material/core/ripple/ripple.ts @@ -18,6 +18,12 @@ import { OnInit, Optional, } from '@angular/core'; +import { + BooleanInput, + coerceBooleanProperty, + NumberInput, + coerceNumberProperty +} from '@angular/cdk/coercion'; import {RippleAnimationConfig, RippleConfig, RippleRef} from './ripple-ref'; import {RippleRenderer, RippleTarget} from './ripple-renderer'; import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations'; @@ -62,20 +68,29 @@ export class MatRipple implements OnInit, OnDestroy, RippleTarget { @Input('matRippleColor') color: string; /** Whether the ripples should be visible outside the component's bounds. */ - @Input('matRippleUnbounded') unbounded: boolean; + @Input('matRippleUnbounded') + get unbounded(): boolean { return this._unbounded; } + set unbounded(value: boolean) { this._unbounded = coerceBooleanProperty(value); } + private _unbounded = false; /** * Whether the ripple always originates from the center of the host element's bounds, rather * than originating from the location of the click event. */ - @Input('matRippleCentered') centered: boolean; + @Input('matRippleCentered') + get centered(): boolean { return this._centered; } + set centered(value: boolean) { this._centered = coerceBooleanProperty(value); } + private _centered = false; /** * If set, the radius in pixels of foreground ripples when fully expanded. If unset, the radius * will be the distance from the center of the ripple to the furthest corner of the host element's * bounding rectangle. */ - @Input('matRippleRadius') radius: number = 0; + @Input('matRippleRadius') + get radius(): number { return this._radius; } + set radius(value: number) { this._radius = coerceNumberProperty(value, 0); } + private _radius = 0; /** * Configuration for the ripple animation. Allows modifying the enter and exit animation @@ -91,13 +106,14 @@ export class MatRipple implements OnInit, OnDestroy, RippleTarget { @Input('matRippleDisabled') get disabled() { return this._disabled; } set disabled(value: boolean) { - if (value) { + const newValue = coerceBooleanProperty(value); + if (newValue) { this.fadeOutAllNonPersistent(); } - this._disabled = value; + this._disabled = newValue; this._setupTriggerEventsIfEnabled(); } - private _disabled: boolean = false; + private _disabled = false; /** * The element that triggers the ripple when click events are received. @@ -118,14 +134,13 @@ export class MatRipple implements OnInit, OnDestroy, RippleTarget { private _globalOptions: RippleGlobalOptions; /** Whether ripple directive is initialized and the input bindings are set. */ - private _isInitialized: boolean = false; + private _isInitialized = false; constructor(private _elementRef: ElementRef, ngZone: NgZone, platform: Platform, @Optional() @Inject(MAT_RIPPLE_GLOBAL_OPTIONS) globalOptions?: RippleGlobalOptions, @Optional() @Inject(ANIMATION_MODULE_TYPE) private _animationMode?: string) { - this._globalOptions = globalOptions || {}; this._rippleRenderer = new RippleRenderer(this, ngZone, _elementRef, platform); } @@ -206,5 +221,9 @@ export class MatRipple implements OnInit, OnDestroy, RippleTarget { return this._rippleRenderer.fadeInRipple(0, 0, {...this.rippleConfig, ...configOrX}); } } -} + static ngAcceptInputType_unbounded: BooleanInput; + static ngAcceptInputType_centered: BooleanInput; + static ngAcceptInputType_radius: NumberInput; + static ngAcceptInputType_disabled: BooleanInput; +} diff --git a/src/material/core/selection/pseudo-checkbox/pseudo-checkbox.ts b/src/material/core/selection/pseudo-checkbox/pseudo-checkbox.ts index 55f20d014366..ccc1f98b0970 100644 --- a/src/material/core/selection/pseudo-checkbox/pseudo-checkbox.ts +++ b/src/material/core/selection/pseudo-checkbox/pseudo-checkbox.ts @@ -15,6 +15,7 @@ import { Optional, } from '@angular/core'; import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations'; +import {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion'; /** * Possible states for a pseudo checkbox. @@ -52,9 +53,14 @@ export type MatPseudoCheckboxState = 'unchecked' | 'checked' | 'indeterminate'; export class MatPseudoCheckbox { /** Display state of the checkbox. */ @Input() state: MatPseudoCheckboxState = 'unchecked'; + private _disabled = false; /** Whether the checkbox is disabled. */ - @Input() disabled: boolean = false; + @Input() + get disabled(): boolean { return this._disabled; } + set disabled(value: boolean) { this._disabled = coerceBooleanProperty(value); } constructor(@Optional() @Inject(ANIMATION_MODULE_TYPE) public _animationMode?: string) { } + + static ngAcceptInputType_disabled: BooleanInput; } diff --git a/src/material/datepicker/calendar-body.ts b/src/material/datepicker/calendar-body.ts index e3601a8e884a..54770385f539 100644 --- a/src/material/datepicker/calendar-body.ts +++ b/src/material/datepicker/calendar-body.ts @@ -358,7 +358,6 @@ export class MatCalendarBody implements OnChanges, OnDestroy { return null; } - } /** Checks whether a node is a table cell element. */ diff --git a/src/material/datepicker/datepicker-toggle.ts b/src/material/datepicker/datepicker-toggle.ts index 34c8e9fbc16b..95a3a64d1112 100644 --- a/src/material/datepicker/datepicker-toggle.ts +++ b/src/material/datepicker/datepicker-toggle.ts @@ -6,7 +6,6 @@ * found in the LICENSE file at https://angular.io/license */ -import {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion'; import { AfterContentInit, Attribute, @@ -22,6 +21,12 @@ import { ViewEncapsulation, ViewChild, } from '@angular/core'; +import { + BooleanInput, + NumberInput, + coerceBooleanProperty, + coerceNumberProperty, +} from '@angular/cdk/coercion'; import {MatButton} from '@angular/material/button'; import {merge, Observable, of as observableOf, Subscription} from 'rxjs'; import {MatDatepickerIntl} from './datepicker-intl'; @@ -63,7 +68,10 @@ export class MatDatepickerToggle implements AfterContentInit, OnChanges, OnDe @Input('for') datepicker: MatDatepickerPanel, D>; /** Tabindex for the toggle. */ - @Input() tabIndex: number | null; + @Input() + get tabIndex(): number | null { return this._tabIndex; } + set tabIndex(value: number | null) { this._tabIndex = coerceNumberProperty(value); } + private _tabIndex: number | null; /** Screenreader label for the button. */ @Input('aria-label') ariaLabel: string; @@ -83,7 +91,10 @@ export class MatDatepickerToggle implements AfterContentInit, OnChanges, OnDe private _disabled: boolean; /** Whether ripples on the toggle should be disabled. */ - @Input() disableRipple: boolean; + @Input() + get disableRipple(): boolean { return this._disableRipple; } + set disableRipple(value: boolean) { this._disableRipple = coerceBooleanProperty(value); } + private _disableRipple: boolean; /** Custom icon set by the consumer. */ @ContentChild(MatDatepickerToggleIcon) _customIcon: MatDatepickerToggleIcon; @@ -138,5 +149,7 @@ export class MatDatepickerToggle implements AfterContentInit, OnChanges, OnDe ).subscribe(() => this._changeDetectorRef.markForCheck()); } + static ngAcceptInputType_tabIndex: NumberInput; static ngAcceptInputType_disabled: BooleanInput; + static ngAcceptInputType_disableRipple: BooleanInput; } diff --git a/src/material/list/selection-list.ts b/src/material/list/selection-list.ts index c3310355c713..74a190492200 100644 --- a/src/material/list/selection-list.ts +++ b/src/material/list/selection-list.ts @@ -7,7 +7,12 @@ */ import {FocusableOption, FocusKeyManager, FocusMonitor} from '@angular/cdk/a11y'; -import {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion'; +import { + BooleanInput, + NumberInput, + coerceBooleanProperty, + coerceNumberProperty, +} from '@angular/cdk/coercion'; import {SelectionModel} from '@angular/cdk/collections'; import { A, @@ -341,7 +346,7 @@ export class MatListOption extends _MatListOptionBase implements AfterContentIni '(keydown)': '_keydown($event)', '[attr.aria-multiselectable]': 'multiple', '[attr.aria-disabled]': 'disabled.toString()', - '[attr.tabindex]': '_tabIndex', + '[attr.tabindex]': 'tabIndex', }, template: '', styleUrls: ['list.css'], @@ -368,7 +373,10 @@ export class MatSelectionList extends _MatSelectionListBase implements CanDisabl * Tabindex of the selection list. * @breaking-change 11.0.0 Remove `tabIndex` input. */ - @Input() tabIndex: number = 0; + @Input() + get tabIndex(): number { return this._tabIndex; } + set tabIndex(value: number) { this._tabIndex = coerceNumberProperty(value); } + private _tabIndex = -1; /** Theme color of the selection list. This sets the checkbox color for all list options. */ @Input() color: ThemePalette = 'accent'; @@ -414,9 +422,6 @@ export class MatSelectionList extends _MatSelectionListBase implements CanDisabl /** The currently selected options. */ selectedOptions = new SelectionModel(this._multiple); - /** The tabindex of the selection list. */ - _tabIndex = -1; - /** View to model callback that should be called whenever the selected options change. */ private _onChange: (value: any) => void = (_: any) => {}; @@ -739,6 +744,7 @@ export class MatSelectionList extends _MatSelectionListBase implements CanDisabl this._tabIndex = (this.options.length === 0) ? -1 : 0; } + static ngAcceptInputType_tabIndex: NumberInput; static ngAcceptInputType_disabled: BooleanInput; static ngAcceptInputType_disableRipple: BooleanInput; static ngAcceptInputType_multiple: BooleanInput; diff --git a/src/material/menu/menu-trigger.ts b/src/material/menu/menu-trigger.ts index 747d62579cba..de7716b73bff 100644 --- a/src/material/menu/menu-trigger.ts +++ b/src/material/menu/menu-trigger.ts @@ -13,6 +13,7 @@ import { isFakeTouchstartFromScreenReader, } from '@angular/cdk/a11y'; import {Direction, Directionality} from '@angular/cdk/bidi'; +import {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion'; import {ENTER, LEFT_ARROW, RIGHT_ARROW, SPACE} from '@angular/cdk/keycodes'; import { FlexibleConnectedPositionStrategy, @@ -165,7 +166,10 @@ export abstract class _MatMenuTriggerBase implements AfterContentInit, OnDestroy * Note that disabling this option can have accessibility implications * and it's up to you to manage focus, if you decide to turn it off. */ - @Input('matMenuTriggerRestoreFocus') restoreFocus: boolean = true; + @Input('matMenuTriggerRestoreFocus') + get restoreFocus(): boolean { return this._restoreFocus; } + set restoreFocus(value: boolean) { this._restoreFocus = coerceBooleanProperty(value); } + private _restoreFocus = true; /** Event emitted when the associated menu is opened. */ @Output() readonly menuOpened: EventEmitter = new EventEmitter(); @@ -604,6 +608,7 @@ export abstract class _MatMenuTriggerBase implements AfterContentInit, OnDestroy return this._portal; } + static ngAcceptInputType_restoreFocus: BooleanInput; } /** Directive applied to an element that should trigger a `mat-menu`. */ diff --git a/src/material/progress-bar/progress-bar.ts b/src/material/progress-bar/progress-bar.ts index d4ddc06016ca..4cfa56af6a5d 100644 --- a/src/material/progress-bar/progress-bar.ts +++ b/src/material/progress-bar/progress-bar.ts @@ -164,7 +164,7 @@ export class MatProgressBar extends _MatProgressBarBase implements CanColor, /** Buffer value of the progress bar. Defaults to zero. */ @Input() get bufferValue(): number { return this._bufferValue; } - set bufferValue(v: number) { this._bufferValue = clamp(v || 0); } + set bufferValue(v: number) { this._bufferValue = clamp(coerceNumberProperty(v) || 0); } private _bufferValue: number = 0; @ViewChild('primaryValueBar') _primaryValueBar: ElementRef; @@ -236,6 +236,7 @@ export class MatProgressBar extends _MatProgressBarBase implements CanColor, } static ngAcceptInputType_value: NumberInput; + static ngAcceptInputType_bufferValue: NumberInput; } /** Clamps a value to be between two numbers, by default 0 and 100. */ diff --git a/src/material/stepper/stepper.ts b/src/material/stepper/stepper.ts index d04de8b70fc4..39702a572daf 100644 --- a/src/material/stepper/stepper.ts +++ b/src/material/stepper/stepper.ts @@ -7,6 +7,7 @@ */ import {Directionality} from '@angular/cdk/bidi'; +import {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion'; import { CdkStep, CdkStepper, @@ -190,7 +191,10 @@ export class MatStepper extends CdkStepper implements AfterContentInit { @Output() readonly animationDone: EventEmitter = new EventEmitter(); /** Whether ripples should be disabled for the step headers. */ - @Input() disableRipple: boolean; + @Input() + get disableRipple(): boolean { return this._disableRipple; } + set disableRipple(value: boolean) { this._disableRipple = coerceBooleanProperty(value); } + private _disableRipple: boolean; /** Theme color for all of the steps in stepper. */ @Input() color: ThemePalette; @@ -243,4 +247,6 @@ export class MatStepper extends CdkStepper implements AfterContentInit { _stepIsNavigable(index: number, step: MatStep): boolean { return step.completed || this.selectedIndex === index || !this.linear; } + + static ngAcceptInputType_disableRipple: BooleanInput; } diff --git a/src/material/tabs/paginated-tab-header.ts b/src/material/tabs/paginated-tab-header.ts index 946dc06fa239..8b107aaa612e 100644 --- a/src/material/tabs/paginated-tab-header.ts +++ b/src/material/tabs/paginated-tab-header.ts @@ -22,7 +22,12 @@ import { Input, } from '@angular/core'; import {Direction, Directionality} from '@angular/cdk/bidi'; -import {coerceNumberProperty, NumberInput} from '@angular/cdk/coercion'; +import { + BooleanInput, + NumberInput, + coerceBooleanProperty, + coerceNumberProperty, +} from '@angular/cdk/coercion'; import {ViewportRuler} from '@angular/cdk/scrolling'; import {FocusKeyManager, FocusableOption} from '@angular/cdk/a11y'; import {ENTER, SPACE, hasModifierKey} from '@angular/cdk/keycodes'; @@ -119,7 +124,9 @@ export abstract class MatPaginatedTabHeader implements AfterContentChecked, Afte * layout recalculations if it's known that pagination won't be required. */ @Input() - disablePagination: boolean = false; + get disablePagination(): boolean { return this._disablePagination; } + set disablePagination(value: boolean) { this._disablePagination = coerceBooleanProperty(value); } + private _disablePagination = false; /** The index of the active tab. */ get selectedIndex(): number { return this._selectedIndex; } @@ -586,5 +593,6 @@ export abstract class MatPaginatedTabHeader implements AfterContentChecked, Afte return {maxScrollDistance, distance: this._scrollDistance}; } + static ngAcceptInputType_disablePagination: BooleanInput; static ngAcceptInputType_selectedIndex: NumberInput; } diff --git a/src/material/tabs/tab-body.ts b/src/material/tabs/tab-body.ts index 648fbf4360bb..a9aed444e91e 100644 --- a/src/material/tabs/tab-body.ts +++ b/src/material/tabs/tab-body.ts @@ -28,6 +28,7 @@ import { import {AnimationEvent} from '@angular/animations'; import {TemplatePortal, CdkPortalOutlet} from '@angular/cdk/portal'; import {Directionality, Direction} from '@angular/cdk/bidi'; +import {NumberInput, coerceNumberProperty} from '@angular/cdk/coercion'; import {DOCUMENT} from '@angular/common'; import {Subscription, Subject} from 'rxjs'; import {matTabsAnimations} from './tabs-animations'; @@ -137,7 +138,12 @@ export abstract class _MatTabBodyBase implements OnInit, OnDestroy { @Input('content') _content: TemplatePortal; /** Position that will be used when the tab is immediately becoming visible after creation. */ - @Input() origin: number | null; + @Input() + get origin(): number | null { return this._origin; } + set origin(value: number | null) { + this._origin = value == null ? null : coerceNumberProperty(value); + } + private _origin: number | null; // Note that the default value will always be overwritten by `MatTabBody`, but we need one // anyway to prevent the animations module from throwing an error if the body is used on its own. @@ -147,7 +153,7 @@ export abstract class _MatTabBodyBase implements OnInit, OnDestroy { /** The shifted index position of the tab body, where zero represents the active center tab. */ @Input() set position(position: number) { - this._positionIndex = position; + this._positionIndex = coerceNumberProperty(position); this._computePositionAnimationState(); } @@ -237,6 +243,9 @@ export abstract class _MatTabBodyBase implements OnInit, OnDestroy { return 'right-origin-center'; } + + static ngAcceptInputType_origin: NumberInput; + static ngAcceptInputType_position: NumberInput; } /** diff --git a/src/material/tabs/tab-group.ts b/src/material/tabs/tab-group.ts index e719fca94dd7..2c48193cdc1a 100644 --- a/src/material/tabs/tab-group.ts +++ b/src/material/tabs/tab-group.ts @@ -8,9 +8,9 @@ import { BooleanInput, + NumberInput, coerceBooleanProperty, coerceNumberProperty, - NumberInput } from '@angular/cdk/coercion'; import { AfterContentChecked, @@ -145,7 +145,9 @@ export abstract class _MatTabGroupBase extends _MatTabGroupMixinBase implements * layout recalculations if it's known that pagination won't be required. */ @Input() - disablePagination: boolean; + get disablePagination(): boolean { return this._disablePagination; } + set disablePagination(value: boolean) { this._disablePagination = coerceBooleanProperty(value); } + private _disablePagination: boolean; /** Background color of the tab group. */ @Input() @@ -421,6 +423,7 @@ export abstract class _MatTabGroupBase extends _MatTabGroupMixinBase implements static ngAcceptInputType_selectedIndex: NumberInput; static ngAcceptInputType_disableRipple: BooleanInput; static ngAcceptInputType_contentTabIndex: NumberInput; + static ngAcceptInputType_disablePagination: BooleanInput; } /** diff --git a/src/material/tabs/tab-nav-bar/tab-nav-bar.ts b/src/material/tabs/tab-nav-bar/tab-nav-bar.ts index 832239903323..c584e8888f8a 100644 --- a/src/material/tabs/tab-nav-bar/tab-nav-bar.ts +++ b/src/material/tabs/tab-nav-bar/tab-nav-bar.ts @@ -7,7 +7,12 @@ */ import {FocusableOption, FocusMonitor} from '@angular/cdk/a11y'; import {Directionality} from '@angular/cdk/bidi'; -import {BooleanInput, coerceBooleanProperty, NumberInput} from '@angular/cdk/coercion'; +import { + BooleanInput, + NumberInput, + coerceBooleanProperty, + coerceNumberProperty, +} from '@angular/cdk/coercion'; import {Platform} from '@angular/cdk/platform'; import {ViewportRuler} from '@angular/cdk/scrolling'; import { @@ -223,7 +228,7 @@ export class _MatTabLinkBase extends _MatTabLinkMixinBase implements AfterViewIn super(); this.rippleConfig = globalRippleOptions || {}; - this.tabIndex = parseInt(tabIndex) || 0; + this.tabIndex = coerceNumberProperty(tabIndex, 0); if (animationMode === 'NoopAnimations') { this.rippleConfig.animation = {enterDuration: 0, exitDuration: 0}; diff --git a/src/material/tooltip/tooltip.ts b/src/material/tooltip/tooltip.ts index 3685dd0b0285..8c9c8f20b166 100644 --- a/src/material/tooltip/tooltip.ts +++ b/src/material/tooltip/tooltip.ts @@ -8,7 +8,12 @@ import {AnimationEvent} from '@angular/animations'; import {AriaDescriber, FocusMonitor} from '@angular/cdk/a11y'; import {Directionality} from '@angular/cdk/bidi'; -import {BooleanInput, coerceBooleanProperty, NumberInput} from '@angular/cdk/coercion'; +import { + BooleanInput, + NumberInput, + coerceBooleanProperty, + coerceNumberProperty, +} from '@angular/cdk/coercion'; import {ESCAPE, hasModifierKey} from '@angular/cdk/keycodes'; import {BreakpointObserver, Breakpoints, BreakpointState} from '@angular/cdk/layout'; import { @@ -180,10 +185,16 @@ export abstract class _MatTooltipBase implement } /** The default delay in ms before showing the tooltip after show is called */ - @Input('matTooltipShowDelay') showDelay: number = this._defaultOptions.showDelay; + @Input('matTooltipShowDelay') + get showDelay(): number { return this._showDelay; } + set showDelay(value: number) { this._showDelay = coerceNumberProperty(value); } + private _showDelay = this._defaultOptions.showDelay; /** The default delay in ms before hiding the tooltip after hide is called */ - @Input('matTooltipHideDelay') hideDelay: number = this._defaultOptions.hideDelay; + @Input('matTooltipHideDelay') + get hideDelay(): number { return this._hideDelay; } + set hideDelay(value: number) { this._hideDelay = coerceNumberProperty(value); } + private _hideDelay = this._defaultOptions.hideDelay; /** * How touch gestures should be handled by the tooltip. On touch devices the tooltip directive @@ -718,8 +729,8 @@ export abstract class _MatTooltipBase implement } static ngAcceptInputType_disabled: BooleanInput; - static ngAcceptInputType_hideDelay: NumberInput; static ngAcceptInputType_showDelay: NumberInput; + static ngAcceptInputType_hideDelay: NumberInput; } /** diff --git a/src/material/tree/node.ts b/src/material/tree/node.ts index 04e78b32304e..40c989d2e091 100644 --- a/src/material/tree/node.ts +++ b/src/material/tree/node.ts @@ -6,6 +6,12 @@ * found in the LICENSE file at https://angular.io/license */ +import { + BooleanInput, + NumberInput, + coerceBooleanProperty, + coerceNumberProperty, +} from '@angular/cdk/coercion'; import { CDK_TREE_NODE_OUTLET_NODE, CdkNestedTreeNode, @@ -29,7 +35,6 @@ import { mixinDisabled, mixinTabIndex, } from '@angular/material/core'; -import {BooleanInput, coerceBooleanProperty, NumberInput} from '@angular/cdk/coercion'; const _MatTreeNodeBase = mixinTabIndex(mixinDisabled(CdkTreeNode)); @@ -120,7 +125,7 @@ export class MatNestedTreeNode extends CdkNestedTreeNode get tabIndex(): number { return this.disabled ? -1 : this._tabIndex; } set tabIndex(value: number) { // If the specified tabIndex value is null or undefined, fall back to the default value. - this._tabIndex = value != null ? value : 0; + this._tabIndex = coerceNumberProperty(value, 0); } private _tabIndex: number; @@ -157,4 +162,5 @@ export class MatNestedTreeNode extends CdkNestedTreeNode } static ngAcceptInputType_disabled: BooleanInput; + static ngAcceptInputType_tabIndex: NumberInput; } diff --git a/src/youtube-player/BUILD.bazel b/src/youtube-player/BUILD.bazel index eaa79c409abb..1ad9e6d6b063 100644 --- a/src/youtube-player/BUILD.bazel +++ b/src/youtube-player/BUILD.bazel @@ -19,6 +19,7 @@ ng_module( ), deps = [ "//src:dev_mode_types", + "//src/cdk/coercion", "@npm//@angular/common", "@npm//@angular/core", "@npm//@types/youtube", diff --git a/src/youtube-player/package.json b/src/youtube-player/package.json index a33dad7eaaec..ff0ed05f00ef 100644 --- a/src/youtube-player/package.json +++ b/src/youtube-player/package.json @@ -21,6 +21,7 @@ "tslib": "0.0.0-TSLIB" }, "peerDependencies": { + "@angular/cdk": "0.0.0-PLACEHOLDER", "@angular/core": "0.0.0-NG", "@angular/common": "0.0.0-NG", "rxjs": "0.0.0-RXJS" diff --git a/src/youtube-player/tsconfig-tests.json b/src/youtube-player/tsconfig-tests.json index 42801e3fe93a..6015039071eb 100644 --- a/src/youtube-player/tsconfig-tests.json +++ b/src/youtube-player/tsconfig-tests.json @@ -1,5 +1,10 @@ { "extends": "../bazel-tsconfig-build.json", + "references": [ + { + "path": "../cdk/tsconfig-tests.json" + } + ], "compilerOptions": { "baseUrl": ".", "outDir": "../../dist/packages/youtube-player", @@ -13,7 +18,10 @@ "target": "es5", "types": ["jasmine"], "experimentalDecorators": true, - "emitDecoratorMetadata": true + "emitDecoratorMetadata": true, + "paths": { + "@angular/cdk/*": ["../../dist/packages/cdk/*"] + } }, "include": [ "**/*.ts", diff --git a/src/youtube-player/tsconfig.json b/src/youtube-player/tsconfig.json index 19ef7205e54f..8f792cb549cf 100644 --- a/src/youtube-player/tsconfig.json +++ b/src/youtube-player/tsconfig.json @@ -4,7 +4,9 @@ "compilerOptions": { "rootDir": "..", "baseUrl": ".", - "paths": {}, + "paths": { + "@angular/cdk/*": ["../cdk/*"] + }, "types": ["jasmine"] }, "include": ["*.ts", "../dev-mode-types.d.ts"] diff --git a/src/youtube-player/youtube-player.ts b/src/youtube-player/youtube-player.ts index b5624d8248b9..46ad91207024 100644 --- a/src/youtube-player/youtube-player.ts +++ b/src/youtube-player/youtube-player.ts @@ -25,7 +25,12 @@ import { PLATFORM_ID, } from '@angular/core'; import {isPlatformBrowser} from '@angular/common'; - +import { + BooleanInput, + NumberInput, + coerceBooleanProperty, + coerceNumberProperty +} from '@angular/cdk/coercion'; import { combineLatest, ConnectableObservable, @@ -40,7 +45,6 @@ import { BehaviorSubject, fromEventPattern, } from 'rxjs'; - import { combineLatest as combineLatestOp, distinctUntilChanged, @@ -125,7 +129,7 @@ export class YouTubePlayer implements AfterViewInit, OnDestroy, OnInit { @Input() get height(): number | undefined { return this._height.value; } set height(height: number | undefined) { - this._height.next(height || DEFAULT_PLAYER_HEIGHT); + this._height.next(coerceNumberProperty(height, DEFAULT_PLAYER_HEIGHT)); } private readonly _height = new BehaviorSubject(DEFAULT_PLAYER_HEIGHT); @@ -133,21 +137,21 @@ export class YouTubePlayer implements AfterViewInit, OnDestroy, OnInit { @Input() get width(): number | undefined { return this._width.value; } set width(width: number | undefined) { - this._width.next(width || DEFAULT_PLAYER_WIDTH); + this._width.next(coerceNumberProperty(width, DEFAULT_PLAYER_WIDTH)); } private readonly _width = new BehaviorSubject(DEFAULT_PLAYER_WIDTH); /** The moment when the player is supposed to start playing */ @Input() set startSeconds(startSeconds: number | undefined) { - this._startSeconds.next(startSeconds); + this._startSeconds.next(coerceNumberProperty(startSeconds)); } private readonly _startSeconds = new BehaviorSubject(undefined); /** The moment when the player is supposed to stop playing */ @Input() set endSeconds(endSeconds: number | undefined) { - this._endSeconds.next(endSeconds); + this._endSeconds.next(coerceNumberProperty(endSeconds)); } private readonly _endSeconds = new BehaviorSubject(undefined); @@ -175,7 +179,12 @@ export class YouTubePlayer implements AfterViewInit, OnDestroy, OnInit { * page. Set this to true if you don't want the `onYouTubeIframeAPIReady` field to be * set on the global window. */ - @Input() showBeforeIframeApiLoads: boolean | undefined; + @Input() + get showBeforeIframeApiLoads(): boolean | undefined { return this._showBeforeIframeApiLoads; } + set showBeforeIframeApiLoads(value: boolean | undefined) { + this._showBeforeIframeApiLoads = coerceBooleanProperty(value); + } + private _showBeforeIframeApiLoads: boolean | undefined; /** Outputs are direct proxies from the player itself. */ @Output() readonly ready: Observable = @@ -546,6 +555,12 @@ export class YouTubePlayer implements AfterViewInit, OnDestroy, OnInit { takeUntil(this._destroyed) ); } + + static ngAcceptInputType_height: NumberInput; + static ngAcceptInputType_width: NumberInput; + static ngAcceptInputType_startSeconds: NumberInput; + static ngAcceptInputType_endSeconds: NumberInput; + static ngAcceptInputType_showBeforeIframeApiLoads: BooleanInput; } /** Listens to changes to the given width and height and sets it on the player. */