Skip to content

Commit be577b1

Browse files
crisbetommalerba
authored andcommitted
feat(overlay): allow for Directionality instance to be passed in (#11411)
Allows for a `Directionality` instance to be passed in to the `OverlayRef`, in addition to a static `Direction`. Using a `Directionality` has the advantage of not having to keep the overlay's direction in sync manually with whatever component triggered it. It also gets rid of some annoying null checks.
1 parent 1d96d5a commit be577b1

File tree

10 files changed

+41
-30
lines changed

10 files changed

+41
-30
lines changed

src/cdk/overlay/overlay-config.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*/
88

99
import {PositionStrategy} from './position/position-strategy';
10-
import {Direction} from '@angular/cdk/bidi';
10+
import {Direction, Directionality} from '@angular/cdk/bidi';
1111
import {ScrollStrategy} from './scroll/scroll-strategy';
1212
import {NoopScrollStrategy} from './scroll/noop-scroll-strategy';
1313

@@ -47,8 +47,11 @@ export class OverlayConfig {
4747
/** The max-height of the overlay panel. If a number is provided, pixel units are assumed. */
4848
maxHeight?: number | string;
4949

50-
/** The direction of the text in the overlay panel. */
51-
direction?: Direction;
50+
/**
51+
* Direction of the text in the overlay panel. If a `Directionality` instance
52+
* is passed in, the overlay will handle changes to its value automatically.
53+
*/
54+
direction?: Direction | Directionality;
5255

5356
constructor(config?: OverlayConfig) {
5457
if (config) {

src/cdk/overlay/overlay-directives.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges {
267267
private _buildConfig(): OverlayConfig {
268268
const positionStrategy = this._position = this._createPositionStrategy();
269269
const overlayConfig = new OverlayConfig({
270+
direction: this._dir,
270271
positionStrategy,
271272
scrollStrategy: this.scrollStrategy,
272273
hasBackdrop: this.hasBackdrop
@@ -348,8 +349,6 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges {
348349
});
349350
}
350351

351-
this._overlayRef.setDirection(this.dir);
352-
353352
if (!this._overlayRef.hasAttached()) {
354353
this._overlayRef.attach(this._templatePortal);
355354
this.attach.emit();

src/cdk/overlay/overlay-ref.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {Direction} from '@angular/cdk/bidi';
9+
import {Direction, Directionality} from '@angular/cdk/bidi';
1010
import {ComponentPortal, Portal, PortalOutlet, TemplatePortal} from '@angular/cdk/portal';
1111
import {ComponentRef, EmbeddedViewRef, NgZone} from '@angular/core';
1212
import {Observable, Subject} from 'rxjs';
@@ -21,9 +21,6 @@ export type ImmutableObject<T> = {
2121
readonly [P in keyof T]: T[P];
2222
};
2323

24-
// TODO(crisbeto): add support for passing in a `Directionality`
25-
// to make syncing the direction easier.
26-
2724
/**
2825
* Reference to an overlay that has been created with the Overlay service.
2926
* Used to manipulate or dispose of said overlay.
@@ -242,14 +239,27 @@ export class OverlayRef implements PortalOutlet {
242239
}
243240

244241
/** Sets the LTR/RTL direction for the overlay. */
245-
setDirection(dir: Direction) {
242+
setDirection(dir: Direction | Directionality) {
246243
this._config = {...this._config, direction: dir};
247244
this._updateElementDirection();
248245
}
249246

247+
/**
248+
* Returns the layout direction of the overlay panel.
249+
*/
250+
getDirection(): Direction {
251+
const direction = this._config.direction;
252+
253+
if (!direction) {
254+
return 'ltr';
255+
}
256+
257+
return typeof direction === 'string' ? direction : direction.value;
258+
}
259+
250260
/** Updates the text direction of the overlay panel. */
251261
private _updateElementDirection() {
252-
this._host.setAttribute('dir', this._config.direction!);
262+
this._host.setAttribute('dir', this.getDirection());
253263
}
254264

255265
/** Updates the size of the overlay element based on the overlay config. */

src/cdk/overlay/overlay.spec.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
ViewContainerRef,
77
ErrorHandler,
88
Injectable,
9+
EventEmitter,
910
} from '@angular/core';
1011
import {Direction, Directionality} from '@angular/cdk/bidi';
1112
import {
@@ -318,6 +319,15 @@ describe('Overlay', () => {
318319
expect(() => TestBed.compileComponents()).not.toThrow();
319320
});
320321

322+
it('should keep the direction in sync with the passed in Directionality', () => {
323+
const customDirectionality = {value: 'rtl', change: new EventEmitter()};
324+
const overlayRef = overlay.create({direction: customDirectionality as Directionality});
325+
326+
expect(overlayRef.getDirection()).toBe('rtl');
327+
customDirectionality.value = 'ltr';
328+
expect(overlayRef.getDirection()).toBe('ltr');
329+
});
330+
321331
describe('positioning', () => {
322332
let config: OverlayConfig;
323333

src/cdk/overlay/position/connected-position-strategy.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export class ConnectedPositionStrategy implements PositionStrategy {
4545

4646
/** Whether the we're dealing with an RTL context */
4747
get _isRtl() {
48-
return this._overlayRef.getConfig().direction === 'rtl';
48+
return this._overlayRef.getDirection() === 'rtl';
4949
}
5050

5151
/** Ordered list of preferred positions, from most to least desirable. */

src/cdk/overlay/position/flexible-connected-position-strategy.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -942,7 +942,7 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
942942

943943
/** Whether the we're dealing with an RTL context */
944944
private _isRtl() {
945-
return this._overlayRef.getConfig().direction === 'rtl';
945+
return this._overlayRef.getDirection() === 'rtl';
946946
}
947947

948948
/** Determines whether the overlay uses exact or flexible positioning. */

src/lib/autocomplete/autocomplete-trigger.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,6 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
528528
} else {
529529
// Update the panel width and direction, in case anything has changed.
530530
this._overlayRef.updateSize({width: this._getHostWidth()});
531-
this._overlayRef.setDirection(this._getDirection());
532531
}
533532

534533
if (this._overlayRef && !this._overlayRef.hasAttached()) {
@@ -553,7 +552,7 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
553552
positionStrategy: this._getOverlayPosition(),
554553
scrollStrategy: this._scrollStrategy(),
555554
width: this._getHostWidth(),
556-
direction: this._getDirection()
555+
direction: this._dir
557556
});
558557
}
559558

@@ -570,10 +569,6 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
570569
return this._positionStrategy;
571570
}
572571

573-
private _getDirection() {
574-
return this._dir ? this._dir.value : 'ltr';
575-
}
576-
577572
private _getConnectedElement(): ElementRef {
578573
if (this.connectedTo) {
579574
return this.connectedTo.elementRef;

src/lib/datepicker/datepicker.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ export class MatDatepicker<D> implements OnDestroy, CanColor {
381381
/** Open the calendar as a dialog. */
382382
private _openAsDialog(): void {
383383
this._dialogRef = this._dialog.open<MatDatepickerContent<D>>(MatDatepickerContent, {
384-
direction: this._getDirection(),
384+
direction: this._dir ? this._dir.value : 'ltr',
385385
viewContainerRef: this._viewContainerRef,
386386
panelClass: 'mat-datepicker-dialog',
387387
});
@@ -403,7 +403,6 @@ export class MatDatepicker<D> implements OnDestroy, CanColor {
403403
}
404404

405405
if (!this._popupRef.hasAttached()) {
406-
this._popupRef.setDirection(this._getDirection());
407406
this._popupComponentRef = this._popupRef.attach(this._calendarPortal);
408407
this._popupComponentRef.instance.datepicker = this;
409408
this._setColor();
@@ -421,7 +420,7 @@ export class MatDatepicker<D> implements OnDestroy, CanColor {
421420
positionStrategy: this._createPopupPositionStrategy(),
422421
hasBackdrop: true,
423422
backdropClass: 'mat-overlay-transparent-backdrop',
424-
direction: this._getDirection(),
423+
direction: this._dir,
425424
scrollStrategy: this._scrollStrategy(),
426425
panelClass: 'mat-datepicker-popup',
427426
});
@@ -493,9 +492,4 @@ export class MatDatepicker<D> implements OnDestroy, CanColor {
493492
this._dialogRef.componentInstance.color = color;
494493
}
495494
}
496-
497-
/** Returns the layout direction of the datepicker. */
498-
private _getDirection() {
499-
return this._dir ? this._dir.value : 'ltr';
500-
}
501495
}

src/lib/menu/menu-trigger.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,6 @@ export class MatMenuTrigger implements AfterContentInit, OnDestroy {
195195
}
196196

197197
const overlayRef = this._createOverlay();
198-
overlayRef.setDirection(this.dir);
199198
overlayRef.attach(this._portal);
200199

201200
if (this.menu.lazyContent) {
@@ -353,7 +352,8 @@ export class MatMenuTrigger implements AfterContentInit, OnDestroy {
353352
positionStrategy: this._getPosition(),
354353
hasBackdrop: this.menu.hasBackdrop == null ? !this.triggersSubmenu() : this.menu.hasBackdrop,
355354
backdropClass: this.menu.backdropClass || 'cdk-overlay-transparent-backdrop',
356-
scrollStrategy: this._scrollStrategy()
355+
scrollStrategy: this._scrollStrategy(),
356+
direction: this._dir
357357
});
358358
}
359359

src/lib/tooltip/tooltip.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,6 @@ export class MatTooltip implements OnDestroy {
264264
const overlayRef = this._createOverlay();
265265

266266
this._detach();
267-
overlayRef.setDirection(this._dir ? this._dir.value : 'ltr');
268267
this._portal = this._portal || new ComponentPortal(TooltipComponent, this._viewContainerRef);
269268
this._tooltipInstance = overlayRef.attach(this._portal).instance;
270269
this._tooltipInstance.afterHidden()
@@ -334,6 +333,7 @@ export class MatTooltip implements OnDestroy {
334333
});
335334

336335
this._overlayRef = this._overlay.create({
336+
direction: this._dir,
337337
positionStrategy: strategy,
338338
panelClass: TOOLTIP_PANEL_CLASS,
339339
scrollStrategy: this._scrollStrategy()

0 commit comments

Comments
 (0)