Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(overlay): overlay rtl support #1593

Merged
merged 1 commit into from
Oct 25, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions src/lib/core/overlay/overlay-directives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
EventEmitter,
TemplateRef,
ViewContainerRef,
Optional,
Input,
OnDestroy,
Output,
Expand All @@ -18,6 +19,7 @@ import {ConnectionPositionPair} from './position/connected-position';
import {PortalModule} from '../portal/portal-directives';
import {ConnectedPositionStrategy} from './position/connected-position-strategy';
import {Subscription} from 'rxjs/Subscription';
import {Dir, LayoutDirection} from '../rtl/dir';

/** Default set of positions for the overlay. Follows the behavior of a dropdown. */
let defaultPositionList = [
Expand Down Expand Up @@ -103,14 +105,19 @@ export class ConnectedOverlayDirective implements OnDestroy {
constructor(
private _overlay: Overlay,
templateRef: TemplateRef<any>,
viewContainerRef: ViewContainerRef) {
viewContainerRef: ViewContainerRef,
@Optional() private _dir: Dir) {
this._templatePortal = new TemplatePortal(templateRef, viewContainerRef);
}

get overlayRef(): OverlayRef {
return this._overlayRef;
}

get dir(): LayoutDirection {
return this._dir ? this._dir.value : 'ltr';
}

/** TODO: internal */
ngOnDestroy() {
this._destroyOverlay();
Expand Down Expand Up @@ -145,6 +152,8 @@ export class ConnectedOverlayDirective implements OnDestroy {

overlayConfig.positionStrategy = this._getPosition();

overlayConfig.direction = this.dir;

return overlayConfig;
}

Expand All @@ -153,7 +162,8 @@ export class ConnectedOverlayDirective implements OnDestroy {
return this._overlay.position().connectedTo(
this.origin.elementRef,
{originX: this.positions[0].overlayX, originY: this.positions[0].originY},
{overlayX: this.positions[0].overlayX, overlayY: this.positions[0].overlayY});
{overlayX: this.positions[0].overlayX, overlayY: this.positions[0].overlayY})
.setDirection(this.dir);
}

/** Attaches the overlay and subscribes to backdrop clicks if backdrop exists */
Expand Down
6 changes: 6 additions & 0 deletions src/lib/core/overlay/overlay-ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export class OverlayRef implements PortalHost {

let attachResult = this._portalHost.attach(portal);
this.updateSize();
this.updateDirection();
this.updatePosition();

return attachResult;
Expand Down Expand Up @@ -59,6 +60,11 @@ export class OverlayRef implements PortalHost {
}
}

/** Updates the text direction of the overlay panel. **/
private updateDirection() {
this._pane.setAttribute('dir', this._state.direction);
}

/** Updates the size of the overlay based on the overlay config. */
updateSize() {
if (this._state.width || this._state.width === 0) {
Expand Down
4 changes: 4 additions & 0 deletions src/lib/core/overlay/overlay-state.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {PositionStrategy} from './position/position-strategy';
import {LayoutDirection} from '../rtl/dir';


/**
Expand All @@ -21,6 +22,9 @@ export class OverlayState {
/** The height of the overlay panel. If a number is provided, pixel units are assumed. **/
height: number | string;

/** The direction of the text in the overlay panel. */
direction: LayoutDirection = 'ltr';

// TODO(jelbourn): configuration still to add
// - focus trap
// - disable pointer events
Expand Down
10 changes: 10 additions & 0 deletions src/lib/core/overlay/overlay.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,16 @@ describe('Overlay', () => {
expect(overlayContainerElement.textContent).toBe('');
});

it('should set the direction', () => {
const state = new OverlayState();
state.direction = 'rtl';

overlay.create(state).attach(componentPortal);

const pane = overlayContainerElement.children[0] as HTMLElement;
expect(pane.getAttribute('dir')).toEqual('rtl');
});

describe('positioning', () => {
let state: OverlayState;

Expand Down
17 changes: 17 additions & 0 deletions src/lib/core/overlay/position/connected-position-strategy.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,23 @@ describe('ConnectedPositionStrategy', () => {
expect(overlayRect.top).toBe(originRect.bottom);
expect(overlayRect.right).toBe(originRect.left);
});

it('should position a panel properly when rtl', () => {
// must make the overlay longer than the origin to properly test attachment
overlayElement.style.width = `500px`;
originRect = originElement.getBoundingClientRect();
strategy = positionBuilder.connectedTo(
fakeElementRef,
{originX: 'start', originY: 'bottom'},
{overlayX: 'start', overlayY: 'top'})
.setDirection('rtl');

strategy.apply(overlayElement);

let overlayRect = overlayElement.getBoundingClientRect();
expect(overlayRect.top).toBe(originRect.bottom);
expect(overlayRect.right).toBe(originRect.right);
});
});


Expand Down
16 changes: 13 additions & 3 deletions src/lib/core/overlay/position/connected-position-strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@ import {
* of the overlay.
*/
export class ConnectedPositionStrategy implements PositionStrategy {
// TODO(jelbourn): set RTL to the actual value from the app.
private _dir = 'ltr';

/** Whether the we're dealing with an RTL context */
_isRtl: boolean = false;
get _isRtl() {
return this._dir === 'rtl';
}

/** Ordered list of preferred positions, from most to least desirable. */
_preferredPositions: ConnectionPositionPair[] = [];
Expand Down Expand Up @@ -85,6 +88,11 @@ export class ConnectedPositionStrategy implements PositionStrategy {
return this;
}

/** Sets the layout direction so the overlay's position can be adjusted to match. */
setDirection(dir: 'ltr' | 'rtl') {
this._dir = dir;
return this;
}

/**
* Gets the horizontal (x) "start" dimension based on whether the overlay is in an RTL context.
Expand Down Expand Up @@ -146,8 +154,10 @@ export class ConnectedPositionStrategy implements PositionStrategy {
let overlayStartX: number;
if (pos.overlayX == 'center') {
overlayStartX = -overlayRect.width / 2;
} else if (pos.overlayX === 'start') {
overlayStartX = this._isRtl ? -overlayRect.width : 0;
} else {
overlayStartX = pos.overlayX == 'start' ? 0 : -overlayRect.width;
overlayStartX = this._isRtl ? 0 : -overlayRect.width;
}

let overlayStartY: number;
Expand Down