feat(overlay): add the ability to set the default offsets on FlexibleConnectedPositionStrategy (#10555)

This commit is contained in:
Kristiyan Kostadinov
2018-03-30 04:25:55 +02:00
committed by Joey Perrott
parent b47bfafad2
commit bcff93e8e4
3 changed files with 120 additions and 21 deletions
@@ -174,12 +174,7 @@ export class ConnectedPositionStrategy implements PositionStrategy {
* @param offset New offset in the X axis.
*/
withOffsetX(offset: number): this {
this._preferredPositions.forEach(position => {
if (position.offsetX == null) {
position.offsetX = offset;
}
});
this._positionStrategy.withDefaultOffsetX(offset);
return this;
}
@@ -188,12 +183,7 @@ export class ConnectedPositionStrategy implements PositionStrategy {
* @param offset New offset in the Y axis.
*/
withOffsetY(offset: number): this {
this._preferredPositions.forEach(position => {
if (position.offsetY == null) {
position.offsetY = offset;
}
});
this._positionStrategy.withDefaultOffsetY(offset);
return this;
}
@@ -385,6 +385,41 @@ describe('FlexibleConnectedPositionStrategy', () => {
expect(Math.floor(overlayRect.left)).toBe(Math.floor(originRect.left + 10));
});
it('should be able to set the default x offset', () => {
const originRect = originElement.getBoundingClientRect();
positionStrategy.withDefaultOffsetX(20).withPositions([{
originX: 'start',
originY: 'top',
overlayX: 'start',
overlayY: 'top',
}]);
attachOverlay({positionStrategy});
const overlayRect = overlayRef.overlayElement.getBoundingClientRect();
expect(Math.floor(overlayRect.top)).toBe(Math.floor(originRect.top));
expect(Math.floor(overlayRect.left)).toBe(Math.floor(originRect.left + 20));
});
it('should have the position offset x take precedence over the default offset x', () => {
const originRect = originElement.getBoundingClientRect();
positionStrategy.withDefaultOffsetX(20).withPositions([{
originX: 'start',
originY: 'top',
overlayX: 'start',
overlayY: 'top',
offsetX: 10
}]);
attachOverlay({positionStrategy});
const overlayRect = overlayRef.overlayElement.getBoundingClientRect();
expect(Math.floor(overlayRect.top)).toBe(Math.floor(originRect.top));
expect(Math.floor(overlayRect.left)).toBe(Math.floor(originRect.left + 10));
});
it('should position a panel with the y offset provided', () => {
const originRect = originElement.getBoundingClientRect();
@@ -403,6 +438,41 @@ describe('FlexibleConnectedPositionStrategy', () => {
expect(Math.floor(overlayRect.left)).toBe(Math.floor(originRect.left));
});
it('should be able to set the default y offset', () => {
const originRect = originElement.getBoundingClientRect();
positionStrategy.withDefaultOffsetY(60).withPositions([{
originX: 'start',
originY: 'top',
overlayX: 'start',
overlayY: 'top',
}]);
attachOverlay({positionStrategy});
const overlayRect = overlayRef.overlayElement.getBoundingClientRect();
expect(Math.floor(overlayRect.top)).toBe(Math.floor(originRect.top + 60));
expect(Math.floor(overlayRect.left)).toBe(Math.floor(originRect.left));
});
it('should have the position offset y take precedence over the default offset y', () => {
const originRect = originElement.getBoundingClientRect();
positionStrategy.withDefaultOffsetY(60).withPositions([{
originX: 'start',
originY: 'top',
overlayX: 'start',
overlayY: 'top',
offsetY: 50
}]);
attachOverlay({positionStrategy});
const overlayRect = overlayRef.overlayElement.getBoundingClientRect();
expect(Math.floor(overlayRect.top)).toBe(Math.floor(originRect.top + 50));
expect(Math.floor(overlayRect.left)).toBe(Math.floor(originRect.left));
});
it('should allow for the fallback positions to specify their own offsets', () => {
originElement.style.bottom = '0';
originElement.style.left = '50%';
@@ -69,7 +69,7 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
private _viewportRect: ClientRect;
/** Amount of space that must be maintained between the overlay and the edge of the viewport. */
private _viewportMargin: number = 0;
private _viewportMargin = 0;
/** The Scrollable containers used to check scrollable view properties on position change. */
private scrollables: CdkScrollable[] = [];
@@ -101,6 +101,12 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
/** Subscription to viewport size changes. */
private _resizeSubscription = Subscription.EMPTY;
/** Default offset for the overlay along the x axis. */
private _offsetX = 0;
/** Default offset for the overlay along the y axis. */
private _offsetY = 0;
/** Observable sequence of position changes. */
positionChanges: Observable<ConnectedOverlayPositionChange> =
this._positionChanges.asObservable();
@@ -366,6 +372,24 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
return this;
}
/**
* Sets the default offset for the overlay's connection point on the x-axis.
* @param offset New offset in the X axis.
*/
withDefaultOffsetX(offset: number): this {
this._offsetX = offset;
return this;
}
/**
* Sets the default offset for the overlay's connection point on the y-axis.
* @param offset New offset in the Y axis.
*/
withDefaultOffsetY(offset: number): this {
this._offsetY = offset;
return this;
}
/**
* Gets the (x, y) coordinate of a connection point on the origin based on a relative position.
*/
@@ -431,14 +455,16 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
position: ConnectedPosition): OverlayFit {
let {x, y} = point;
let offsetX = this._getOffset(position, 'x');
let offsetY = this._getOffset(position, 'y');
// Account for the offsets since they could push the overlay out of the viewport.
if (position.offsetX) {
x += position.offsetX;
if (offsetX) {
x += offsetX;
}
if (position.offsetY) {
y += position.offsetY;
if (offsetY) {
y += offsetY;
}
// How much the overlay would overflow at this position, on each side.
@@ -721,13 +747,15 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
// cases where the element doesn't have anything to "push off of". Finally, this works
// better both with flexible and non-flexible positioning.
let transformString = ' ';
let offsetX = this._getOffset(position, 'x');
let offsetY = this._getOffset(position, 'y');
if (position.offsetX) {
transformString += `translateX(${position.offsetX}px)`;
if (offsetX) {
transformString += `translateX(${offsetX}px)`;
}
if (position.offsetY) {
transformString += `translateY(${position.offsetY}px)`;
if (offsetY) {
transformString += `translateY(${offsetY}px)`;
}
styles.transform = transformString.trim();
@@ -869,6 +897,17 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
private _isRtl() {
return this._overlayRef.getConfig().direction === 'rtl';
}
/** Retrieves the offset of a position along the x or y axis. */
private _getOffset(position: ConnectedPosition, axis: 'x' | 'y') {
if (axis === 'x') {
// We don't do something like `position['offset' + axis]` in
// order to avoid breking minifiers that rename properties.
return position.offsetX == null ? this._offsetX : position.offsetX;
}
return position.offsetY == null ? this._offsetY : position.offsetY;
}
}
/** A simple (x, y) coordinate. */