Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Commit

Permalink
feat(menu-surface): Add support for flipping menu corner horizontally.
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 307486345
  • Loading branch information
abhiomkar authored and copybara-github committed Apr 20, 2020
1 parent 9cff431 commit 7b44824
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 3 deletions.
25 changes: 22 additions & 3 deletions packages/mdc-menu-surface/foundation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export class MDCMenuSurfaceFoundation extends MDCFoundation<MDCMenuSurfaceAdapte
* | |
* +--------------+
*/
private readonly originCorner_: Corner = Corner.TOP_LEFT;
private originCorner_: Corner = Corner.TOP_START;
private anchorMargin_: MDCMenuDistance = {top: 0, right: 0, bottom: 0, left: 0};
private position_: MDCMenuPoint = {x: 0, y: 0};

Expand Down Expand Up @@ -151,6 +151,13 @@ export class MDCMenuSurfaceFoundation extends MDCFoundation<MDCMenuSurfaceAdapte
this.anchorCorner_ = corner;
}

/**
* Flip menu corner horizontally.
*/
flipCornerHorizontally() {
this.originCorner_ = this.originCorner_ ^ CornerBit.RIGHT;
}

/**
* @param margin Set of margin values from anchor.
*/
Expand Down Expand Up @@ -417,8 +424,16 @@ export class MDCMenuSurfaceFoundation extends MDCFoundation<MDCMenuSurfaceAdapte

const isAvailableLeft = availableLeft - surfaceSize.width > 0;
const isAvailableRight = availableRight - surfaceSize.width > 0;

if (isAvailableLeft && isAnchoredToRight && isRtl ||
const isOriginCornerAlignedToEnd =
this.hasBit_(corner, CornerBit.FLIP_RTL) &&
this.hasBit_(corner, CornerBit.RIGHT);

if (isAvailableRight && isOriginCornerAlignedToEnd && isRtl ||
!isAvailableLeft && isOriginCornerAlignedToEnd) {
// Attach left side of surface to the anchor.
corner = this.unsetBit_(corner, CornerBit.RIGHT);
} else if (
isAvailableLeft && isAnchoredToRight && isRtl ||
(isAvailableLeft && !isAnchoredToRight && hasRightBit) ||
(!isAvailableRight && availableLeft >= availableRight)) {
// Attach right side of surface to the anchor.
Expand Down Expand Up @@ -554,6 +569,10 @@ export class MDCMenuSurfaceFoundation extends MDCFoundation<MDCMenuSurfaceAdapte
return corner | bit; // tslint:disable-line:no-bitwise
}

private unsetBit_(corner: Corner, bit: CornerBit): Corner {
return corner ^ bit;
}

/**
* isFinite that doesn't force conversion to number type.
* Equivalent to Number.isFinite in ES2015, which is not supported in IE.
Expand Down
72 changes: 72 additions & 0 deletions packages/mdc-menu-surface/test/foundation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -829,6 +829,78 @@ describe('MDCMenuSurfaceFoundation', () => {
.toHaveBeenCalledWith({left: 0, bottom: -0});
});

testFoundation(
'#open Surface is positioned from right side in LTR when corner is flipped horizontally.',
({foundation, mockAdapter}) => {
initAnchorLayout(mockAdapter, smallCenter);
foundation.flipCornerHorizontally();
foundation.open();
jasmine.clock().tick(1); // Run to frame.
expect(mockAdapter.setTransformOrigin)
.toHaveBeenCalledWith('right top');
expect(mockAdapter.setPosition)
.toHaveBeenCalledWith({right: 0, top: 0});
});

testFoundation(
'#open Surface is positioned from left side in LTR when corner is flipped horizontally and space is not available on the left side.',
({foundation, mockAdapter}) => {
initAnchorLayout(mockAdapter, smallTopLeft);
foundation.flipCornerHorizontally();
foundation.open();
jasmine.clock().tick(1); // Run to frame.
expect(mockAdapter.setTransformOrigin).toHaveBeenCalledWith('left top');
expect(mockAdapter.setPosition).toHaveBeenCalledWith({left: 0, top: 0});
});

testFoundation(
'#open Surface is positioned from right side in LTR when corner is flipped horizontally and space is not available on the right side.',
({foundation, mockAdapter}) => {
initAnchorLayout(mockAdapter, smallTopRight);
foundation.flipCornerHorizontally();
foundation.open();
jasmine.clock().tick(1); // Run to frame.
expect(mockAdapter.setTransformOrigin)
.toHaveBeenCalledWith('right top');
expect(mockAdapter.setPosition)
.toHaveBeenCalledWith({right: 0, top: 0});
});

testFoundation(
'#open Surface is positioned from left side in RTL when corner is flipped horizontally.',
({foundation, mockAdapter}) => {
initAnchorLayout(mockAdapter, smallCenter, /* isRtl */ true);
foundation.flipCornerHorizontally();
foundation.open();
jasmine.clock().tick(1); // Run to frame.
expect(mockAdapter.setTransformOrigin).toHaveBeenCalledWith('left top');
expect(mockAdapter.setPosition).toHaveBeenCalledWith({left: 0, top: 0});
});

testFoundation(
'#open Surface is positioned from left side in RTL when corner is flipped horizontally and space is not available on the left side.',
({foundation, mockAdapter}) => {
initAnchorLayout(mockAdapter, smallTopLeft, /* isRtl */ true);
foundation.flipCornerHorizontally();
foundation.open();
jasmine.clock().tick(1); // Run to frame.
expect(mockAdapter.setTransformOrigin).toHaveBeenCalledWith('left top');
expect(mockAdapter.setPosition).toHaveBeenCalledWith({left: 0, top: 0});
});

testFoundation(
'#open Surface is positioned from right side in RTL when corner is flipped horizontally and space is not available on the right side.',
({foundation, mockAdapter}) => {
initAnchorLayout(mockAdapter, smallTopRight, /* isRtl */ true);
foundation.flipCornerHorizontally();
foundation.open();
jasmine.clock().tick(1); // Run to frame.
expect(mockAdapter.setTransformOrigin)
.toHaveBeenCalledWith('right top');
expect(mockAdapter.setPosition)
.toHaveBeenCalledWith({right: 0, top: 0});
});

testFoundation(
'#open adds the open-below class to the menu surface, from small anchor in top of viewport',
({foundation, mockAdapter}) => {
Expand Down

0 comments on commit 7b44824

Please sign in to comment.