Skip to content

Commit

Permalink
Add yAxis=middle support to Popover (#7038)
Browse files Browse the repository at this point in the history
* Add yAxis=middle support to Popover

Add yAxis=middle support to the Popover component so that we can use it
to implement NUX tips.

* Update popover README
  • Loading branch information
noisysocks authored Jun 7, 2018
1 parent 5984cdf commit be00077
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 9 deletions.
10 changes: 9 additions & 1 deletion components/popover/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ By default, the popover will receive focus when it mounts. To suppress this beha

### position

The direction in which the popover should open relative to its parent node. Specify y- and x-axis as a space-separated string. Supports `"top"`, `"bottom"` y axis, and `"left"`, `"center"`, `"right"` x axis.
The direction in which the popover should open relative to its parent node. Specify y- and x-axis as a space-separated string. Supports `"top"`, `"middle"`, `"bottom"` y axis, and `"left"`, `"center"`, `"right"` x axis.

- Type: `String`
- Required: No
Expand Down Expand Up @@ -109,3 +109,11 @@ Opt-in prop to show popovers fullscreen on mobile, pass `false` in this prop to

- Type: `String`
- Required: No

## noArrow

Set this to hide the arrow which visually indicates what the popover is anchored to. Note that the arrow will not display if `position` is set to `"middle center"`.

- Type: `Boolean`
- Required: No
- Default: `false`
3 changes: 2 additions & 1 deletion components/popover/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class Popover extends Component {

this.focus = this.focus.bind( this );
this.getAnchorRect = this.getAnchorRect.bind( this );
this.updatePopoverSize = this.updatePopoverSize.bind( this );
this.computePopoverPosition = this.computePopoverPosition.bind( this );
this.throttledComputePopoverPosition = this.throttledComputePopoverPosition.bind( this );
this.maybeClose = this.maybeClose.bind( this );
Expand Down Expand Up @@ -220,7 +221,7 @@ class Popover extends Component {
'is-' + xAxis,
{
'is-mobile': isMobile,
'no-arrow': noArrow,
'no-arrow': noArrow || ( xAxis === 'center' && yAxis === 'middle' ),
}
);

Expand Down
64 changes: 59 additions & 5 deletions components/popover/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,8 @@ $arrow-size: 8px;
&:after {
content: "";
position: absolute;
margin-left: -10px;
height: 0;
width: 0;
border-left-color: transparent;
border-right-color: transparent;
line-height: 0;
}

Expand All @@ -48,13 +45,16 @@ $arrow-size: 8px;

&:before,
&:after {
border-top-style: solid;
border-bottom: none;
border-left-color: transparent;
border-right-color: transparent;
border-top-style: solid;
margin-left: -10px;
}
}

&.is-bottom {
margin-top: 8px;
margin-top: $arrow-size;

&:before {
top: -$arrow-size;
Expand All @@ -67,7 +67,50 @@ $arrow-size: 8px;
&:before,
&:after {
border-bottom-style: solid;
border-left-color: transparent;
border-right-color: transparent;
border-top: none;
margin-left: -10px;
}
}

&.is-middle.is-left {
margin-left: -$arrow-size;

&:before {
right: -$arrow-size;
}

&:after {
right: -6px;
}

&:before,
&:after {
border-bottom-color: transparent;
border-left-style: solid;
border-right: none;
border-top-color: transparent;
}
}

&.is-middle.is-right {
margin-left: $arrow-size;

&:before {
left: -$arrow-size;
}

&:after {
left: -6px;
}

&:before,
&:after {
border-bottom-color: transparent;
border-left: none;
border-right-style: solid;
border-top-color: transparent;
}
}
}
Expand All @@ -81,6 +124,11 @@ $arrow-size: 8px;
top: 100%;
z-index: z-index( ".components-popover.is-bottom" );
}

&.is-middle {
align-items: center;
display: flex;
}
}
}

Expand Down Expand Up @@ -114,12 +162,18 @@ $arrow-size: 8px;
.components-popover:not(.is-mobile).is-right & {
position: absolute;
left: 100%;
}

.components-popover:not(.is-mobile):not(.is-middle).is-right & {
margin-left: -24px;
}

.components-popover:not(.is-mobile).is-left & {
position: absolute;
right: 100%;
}

.components-popover:not(.is-mobile):not(.is-middle).is-left & {
margin-right: -24px;
}
}
Expand Down
22 changes: 22 additions & 0 deletions components/popover/test/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,28 @@ describe( 'computePopoverYAxisPosition', () => {
yAxis: 'top',
} );
} );

it( 'should position a popover in the middle', () => {
const anchorRect = {
top: 400,
left: 10,
bottom: 30,
right: 30,
width: 20,
height: 20,
};

const contentSize = {
width: 200,
height: 300,
};

expect( computePopoverYAxisPosition( anchorRect, contentSize, 'middle' ) ).toEqual( {
contentHeight: null,
popoverTop: 410,
yAxis: 'middle',
} );
} );
} );

describe( 'computePopoverXAxisPosition', () => {
Expand Down
21 changes: 19 additions & 2 deletions components/popover/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@ export function computePopoverYAxisPosition( anchorRect, contentSize, yAxis ) {
const { height } = contentSize;

// y axis aligment choices
const anchorMidPoint = anchorRect.top + ( anchorRect.height / 2 );
const middleAlignment = {
popoverTop: anchorMidPoint,
contentHeight: (
( anchorMidPoint - ( height / 2 ) > 0 ? ( height / 2 ) : anchorMidPoint ) +
( anchorMidPoint + ( height / 2 ) > window.innerHeight ? window.innerHeight - anchorMidPoint : ( height / 2 ) )
),
};
const topAlignment = {
popoverTop: anchorRect.top,
contentHeight: anchorRect.top - HEIGHT_OFFSET - height > 0 ? height : anchorRect.top - HEIGHT_OFFSET,
Expand All @@ -81,7 +89,9 @@ export function computePopoverYAxisPosition( anchorRect, contentSize, yAxis ) {
// Choosing the y axis
let chosenYAxis;
let contentHeight = null;
if ( yAxis === 'top' && topAlignment.contentHeight === height ) {
if ( yAxis === 'middle' && middleAlignment.contentHeight === height ) {
chosenYAxis = 'middle';
} else if ( yAxis === 'top' && topAlignment.contentHeight === height ) {
chosenYAxis = 'top';
} else if ( yAxis === 'bottom' && bottomAlignment.contentHeight === height ) {
chosenYAxis = 'bottom';
Expand All @@ -91,7 +101,14 @@ export function computePopoverYAxisPosition( anchorRect, contentSize, yAxis ) {
contentHeight = chosenHeight !== height ? chosenHeight : null;
}

const popoverTop = chosenYAxis === 'top' ? topAlignment.popoverTop : bottomAlignment.popoverTop;
let popoverTop;
if ( chosenYAxis === 'middle' ) {
popoverTop = middleAlignment.popoverTop;
} else if ( chosenYAxis === 'top' ) {
popoverTop = topAlignment.popoverTop;
} else {
popoverTop = bottomAlignment.popoverTop;
}

return {
yAxis: chosenYAxis,
Expand Down

0 comments on commit be00077

Please sign in to comment.