Skip to content

Commit

Permalink
port k7 popover component over (#13322)
Browse files Browse the repository at this point in the history
* port k7 popover component over

* Fix line height

* Clean up css
  • Loading branch information
stacey-gammon authored Aug 9, 2017
1 parent fb203ea commit 7199476
Show file tree
Hide file tree
Showing 14 changed files with 702 additions and 0 deletions.
4 changes: 4 additions & 0 deletions ui_framework/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ export {
KuiPagerButtonGroup,
} from './pager';

export {
KuiPopover,
} from './popover';

export {
KuiTabs,
KuiTab
Expand Down
1 change: 1 addition & 0 deletions ui_framework/components/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
@import "notice/index";
@import "pager/index";
@import "panel/index";
@import "popover/index";
@import "empty_table_prompt/index";
@import "status_text/index";
@import "table/index";
Expand Down
82 changes: 82 additions & 0 deletions ui_framework/components/popover/__snapshots__/popover.test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`KuiPopover anchorPosition defaults to center 1`] = `
<div
class="kuiPopover"
>
<button />
<div
class="kuiPopover__body"
/>
</div>
`;

exports[`KuiPopover anchorPosition left is rendered 1`] = `
<div
class="kuiPopover kuiPopover--anchorLeft"
>
<button />
<div
class="kuiPopover__body"
/>
</div>
`;

exports[`KuiPopover anchorPosition right is rendered 1`] = `
<div
class="kuiPopover kuiPopover--anchorRight"
>
<button />
<div
class="kuiPopover__body"
/>
</div>
`;

exports[`KuiPopover children is rendered 1`] = `
<div
class="kuiPopover"
>
<button />
<div
class="kuiPopover__body"
>
Children
</div>
</div>
`;

exports[`KuiPopover is rendered 1`] = `
<div
aria-label="aria-label"
class="kuiPopover testClass1 testClass2"
data-test-subj="test subject string"
>
<button />
<div
class="kuiPopover__body"
/>
</div>
`;

exports[`KuiPopover isOpen defaults to false 1`] = `
<div
class="kuiPopover"
>
<button />
<div
class="kuiPopover__body"
/>
</div>
`;

exports[`KuiPopover isOpen renders true 1`] = `
<div
class="kuiPopover kuiPopover-isOpen"
>
<button />
<div
class="kuiPopover__body"
/>
</div>
`;
3 changes: 3 additions & 0 deletions ui_framework/components/popover/_index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
$popOverBackgroundColor: #FFF;

@import 'popover';
95 changes: 95 additions & 0 deletions ui_framework/components/popover/_popover.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Pop menu is an animated popover relatively positioned to a button / action.
// By default it positions in the middle, but can be anchored left and right.

.kuiPopover {
display: inline-block;
position: relative;

// Open state happens on the wrapper and applies to the body.
&.kuiPopover-isOpen {
.kuiPopover__body {
opacity: 1;
visibility: visible;
z-index: 1;
margin-top: 10px;
box-shadow: 0 16px 16px -8px rgba(0, 0, 0, 0.1);
}
}
}

// Animation happens on the body.
.kuiPopover__body {
line-height: $globalLineHeight;
font-size: $globalFontSize;
position: absolute;
min-width: 256px; // Can expand further, but this size is good for our menus.
top: 100%;
left: 50%;
background: $popOverBackgroundColor;
border: 1px solid $globalBorderColor;
border-radius: $globalBorderRadius 0 $globalBorderRadius $globalBorderRadius;
padding: 16px;
transform: translateX(-50%) translateY(8px) translateZ(0);
backface-visibility: hidden;
transform-origin: center top;
opacity: 0;
visibility: hidden;
margin-top: 32px;

// This fakes a border on the arrow.
&:before {
position: absolute;
content: "";
top: -16px;
height: 0;
width: 0;
left: 50%;
margin-left: -16px;
border-left: 16px solid transparent;
border-right: 16px solid transparent;
border-bottom: 16px solid $globalBorderColor;
}

// This part of the arrow matches the body.
&:after {
position: absolute;
content: "";
top: -16px + 1;
right: 0;
height: 0;
left: 50%;
margin-left: -16px;
width: 0;
border-left: 16px solid transparent;
border-right: 16px solid transparent;
border-bottom: 16px solid $popOverBackgroundColor;
}
}


// Positions the menu and arrow to the left of the parent.
.kuiPopover--anchorLeft {
.kuiPopover__body {
left: 0;
transform: translateX(0%) translateY(8px) translateZ(0);

&:before, &:after {
right: auto;
left: 8px;
margin: 0;
}
}
}

// Positions the menu and arrow to the right of the parent.
.kuiPopover--anchorRight {
.kuiPopover__body {
left: 100%;
transform: translateX(-100%) translateY(8px) translateZ(0);

&:before, &:after {
right: 8px;
left: auto;
}
}
}
3 changes: 3 additions & 0 deletions ui_framework/components/popover/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export {
KuiPopover,
} from './popover';
100 changes: 100 additions & 0 deletions ui_framework/components/popover/popover.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

const anchorPositionToClassNameMap = {
'center': '',
'left': 'kuiPopover--anchorLeft',
'right': 'kuiPopover--anchorRight',
};

export const ANCHOR_POSITIONS = Object.keys(anchorPositionToClassNameMap);

export class KuiPopover extends Component {
constructor(props) {
super(props);

// Use this variable to differentiate between clicks on the element that should not cause the pop up
// to close, and external clicks that should cause the pop up to close.
this.didClickMyself = false;
}

closePopover = () => {
if (this.didClickMyself) {
this.didClickMyself = false;
return;
}

this.props.closePopover();
};

onClickRootElement = () => {
// This prevents clicking on the element from closing it, due to the event handler on the
// document object.
this.didClickMyself = true;
};

componentDidMount() {
// When the user clicks somewhere outside of the color picker, we will dismiss it.
document.addEventListener('click', this.closePopover);
}

componentWillUnmount() {
document.removeEventListener('click', this.closePopover);
}

render() {
const {
anchorPosition,
bodyClassName,
button,
isOpen,
children,
className,
closePopover, // eslint-disable-line no-unused-vars
...rest,
} = this.props;

const classes = classNames(
'kuiPopover',
anchorPositionToClassNameMap[anchorPosition],
className,
{
'kuiPopover-isOpen': isOpen,
},
);

const bodyClasses = classNames('kuiPopover__body', bodyClassName);

const body = (
<div className={ bodyClasses }>
{ children }
</div>
);

return (
<div
onClick={ this.onClickRootElement }
className={ classes }
{ ...rest }
>
{ button }
{ body }
</div>
);
}
}

KuiPopover.propTypes = {
isOpen: PropTypes.bool,
closePopover: PropTypes.func.isRequired,
button: PropTypes.node.isRequired,
children: PropTypes.node,
anchorPosition: PropTypes.oneOf(ANCHOR_POSITIONS),
bodyClassName: PropTypes.string,
};

KuiPopover.defaultProps = {
isOpen: false,
anchorPosition: 'center',
};
Loading

0 comments on commit 7199476

Please sign in to comment.