-
Notifications
You must be signed in to change notification settings - Fork 55
Add Tooltip
component
#360
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
import PropTypes from 'prop-types'; | ||
import React from 'react'; | ||
import ReactDOM from 'react-dom'; | ||
import {classNames} from 'react-extras'; | ||
import CSSTransition from 'react-transition-group/CSSTransition'; | ||
import {Manager, Popper, Reference, placements} from 'react-popper'; | ||
import './Tooltip.scss'; | ||
|
||
class Tooltip extends React.PureComponent { | ||
static propTypes = { | ||
animationDuration: PropTypes.number, | ||
children: PropTypes.node, | ||
content: PropTypes.node, | ||
margin: PropTypes.oneOfType([ | ||
PropTypes.number, | ||
PropTypes.string, | ||
]), | ||
onClose: PropTypes.func, | ||
position: PropTypes.oneOf(placements), | ||
} | ||
|
||
static defaultProps = { | ||
animationDuration: 300, | ||
margin: 0, | ||
position: 'top', | ||
} | ||
|
||
state = { | ||
isOpen: false, | ||
} | ||
|
||
componentWillReceiveProps({content}) { | ||
if (typeof this.updatePopper === 'function' && this.props.content !== content) { | ||
this.updatePopper(); | ||
} | ||
} | ||
|
||
handleMouseEnter = () => { | ||
this.setState({isOpen: true}); | ||
} | ||
|
||
handleMouseLeave = () => { | ||
this.setState({isOpen: false}); | ||
} | ||
|
||
render() { | ||
const {animationDuration, children, content, margin, onClose, position} = this.props; | ||
const {isOpen} = this.state; | ||
const tooltip = ( | ||
<Popper placement={position} modifiers={{offset: {offset: `0, ${margin}`}}}> | ||
{({arrowProps, placement, ref, scheduleUpdate, style}) => { | ||
this.updatePopper = scheduleUpdate; | ||
|
||
return ( | ||
<div ref={ref} className="Tooltip__container" style={style}> | ||
<CSSTransition | ||
classNames="Tooltip" | ||
in={isOpen} | ||
mountOnEnter | ||
timeout={{ | ||
enter: 0, // Start animation immediately | ||
exit: animationDuration, | ||
}} | ||
onExited={onClose} | ||
> | ||
<div | ||
className={classNames( | ||
'Tooltip', | ||
`Tooltip--${placement}`, | ||
)} | ||
> | ||
<div className="Tooltip__content"> | ||
{content} | ||
</div> | ||
<div | ||
ref={arrowProps.ref} | ||
className="Tooltip__arrow" | ||
style={arrowProps.style} | ||
/> | ||
</div> | ||
</CSSTransition> | ||
<style jsx> | ||
{` | ||
.Tooltip { | ||
transition-duration: ${animationDuration}ms; | ||
} | ||
`} | ||
</style> | ||
</div> | ||
); | ||
}} | ||
</Popper> | ||
); | ||
|
||
return ( | ||
<Manager> | ||
<Reference> | ||
{({ref}) => ( | ||
<div | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Really bothers me that we have to wrap the children in a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, it's only available in Chrome 65, but Electron 2 is at 61. We'll be able to use this when Electron 3 is stable. #374 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added the flag to |
||
ref={ref} | ||
onMouseEnter={this.handleMouseEnter} | ||
onMouseLeave={this.handleMouseLeave} | ||
> | ||
{children} | ||
</div> | ||
)} | ||
</Reference> | ||
{ReactDOM.createPortal(tooltip, document.body)} | ||
</Manager> | ||
); | ||
} | ||
} | ||
|
||
export default Tooltip; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add prop-types too? I've been too lazy to do this on the other components, but in hindsight, I should have. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I didn't because no other components had it. Will add! |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
.Tooltip { | ||
--color: var(--border-color); | ||
--arrow-height: 7px; | ||
--arrow-width: 12px; | ||
opacity: 0; | ||
transition-property: opacity, transform; | ||
transition-timing-function: ease-out; | ||
|
||
&__target { | ||
overflow: hidden; | ||
} | ||
|
||
&__container { | ||
z-index: 1100; | ||
} | ||
|
||
&__content { | ||
background-color: var(--color); | ||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 0 1px rgba(0, 0, 0, 0.1); | ||
border-radius: 4px; | ||
font-size: 13px; | ||
padding: 8px 10px; | ||
text-align: center; | ||
} | ||
|
||
&__arrow { | ||
display: block; | ||
height: var(--arrow-height); | ||
position: absolute; | ||
width: var(--arrow-width); | ||
|
||
&::before { | ||
border-color: transparent; | ||
border-style: solid; | ||
content: ''; | ||
position: absolute; | ||
} | ||
} | ||
|
||
&--top { | ||
padding-bottom: var(--arrow-height); | ||
transform: translate3d(0, -10%, 0); | ||
|
||
.Tooltip__arrow { | ||
bottom: 0; | ||
left: 0; | ||
|
||
&::before { | ||
border-top-color: var(--color); | ||
border-width: var(--arrow-height) calc(var(--arrow-width) / 2) 0; | ||
filter: | ||
drop-shadow(0 calc(var(--arrow-height) / 2) 2px rgba(0, 0, 0, 0.1)) | ||
drop-shadow(0 calc(var(--arrow-height) / 2) 1px rgba(0, 0, 0, 0.1)); | ||
top: 0; | ||
} | ||
} | ||
} | ||
|
||
&--right { | ||
padding-left: var(--arrow-height); | ||
transform: translate3d(5%, 0, 0); | ||
|
||
.Tooltip__arrow { | ||
height: var(--arrow-width); | ||
left: 0; | ||
width: var(--arrow-height); | ||
|
||
&::before { | ||
border-right-color: var(--color); | ||
border-width: calc(var(--arrow-width) / 2) var(--arrow-height) calc(var(--arrow-width) / 2) 0; | ||
filter: | ||
drop-shadow(calc(var(--arrow-height) / 2 * -1) 0 2px rgba(0, 0, 0, 0.1)) | ||
drop-shadow(calc(var(--arrow-height) / 2 * -1) 0 1px rgba(0, 0, 0, 0.1)); | ||
right: 0; | ||
} | ||
} | ||
} | ||
|
||
&--bottom { | ||
padding-top: var(--arrow-height); | ||
transform: translate3d(0, 10%, 0); | ||
|
||
.Tooltip__arrow { | ||
left: 0; | ||
top: 0; | ||
|
||
&::before { | ||
border-bottom-color: var(--color); | ||
border-width: 0 calc(var(--arrow-width) / 2) var(--arrow-height); | ||
filter: | ||
drop-shadow(0 calc(var(--arrow-height) / 2 * -1) 2px rgba(0, 0, 0, 0.1)) | ||
drop-shadow(0 calc(var(--arrow-height) / 2 * -1) 1px rgba(0, 0, 0, 0.1)); | ||
bottom: 0; | ||
} | ||
} | ||
} | ||
|
||
&--left { | ||
padding-right: var(--arrow-height); | ||
transform: translate3d(-5%, 0, 0); | ||
|
||
.Tooltip__arrow { | ||
height: var(--arrow-width); | ||
right: 0; | ||
width: var(--arrow-height); | ||
|
||
&::before { | ||
border-left-color: var(--color); | ||
border-width: calc(var(--arrow-width) / 2) 0 calc(var(--arrow-width) / 2) var(--arrow-height); | ||
filter: | ||
drop-shadow(calc(var(--arrow-height) / 2) 0 2px rgba(0, 0, 0, 0.1)) | ||
drop-shadow(calc(var(--arrow-height) / 2) 0 1px rgba(0, 0, 0, 0.1)); | ||
left: 0; | ||
} | ||
} | ||
} | ||
|
||
&-enter-done { | ||
opacity: 1; | ||
transform: translate3d(0, 0, 0); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,12 +5,15 @@ import ReloadButton from 'components/ReloadButton'; | |
import CopyButton from 'components/CopyButton'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Had to rewrite this file to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Much better! No idea why I didn't use flexbox in the first place... |
||
import WrapWidth from 'components/WrapWidth'; | ||
import ExternalLink from 'components/ExternalLink'; | ||
import Tooltip from 'components/Tooltip'; | ||
import container from 'containers/CreatePortfolio'; | ||
import {withState} from 'containers/SuperContainer'; | ||
import './CreatePortfolio.scss'; | ||
|
||
const CreatePortfolioStep2 = () => { | ||
const CreatePortfolioStep2 = ({setState, ...props}) => { | ||
// TODO(sindresorhus): Fill in the link to security best practices | ||
|
||
const {isCopied} = props.state; | ||
const {state} = container; | ||
|
||
return ( | ||
|
@@ -19,11 +22,32 @@ const CreatePortfolioStep2 = () => { | |
<h1>Seed Phrase for Your Portfolio</h1> | ||
<div className="form-group" style={{width: '460px', marginTop: '20px'}}> | ||
<div className="generated-seed-phrase-container"> | ||
<ReloadButton onClick={container.generateSeedPhrase}/> | ||
<WrapWidth wordsPerLine={6} className="seed-phrase"> | ||
{state.generatedSeedPhrase} | ||
</WrapWidth> | ||
<CopyButton value={state.generatedSeedPhrase}/> | ||
<div className="button button--reload"> | ||
<ReloadButton onClick={() => { | ||
container.generateSeedPhrase(); | ||
setState({isCopied: false}); | ||
}}/> | ||
</div> | ||
<div className="seed-phrase"> | ||
<WrapWidth wordsPerLine={6}> | ||
{state.generatedSeedPhrase} | ||
</WrapWidth> | ||
</div> | ||
<div className="button button--copy"> | ||
<Tooltip | ||
content={isCopied ? 'Copied' : 'Copy'} | ||
onClose={() => { | ||
setState({isCopied: false}); | ||
}} | ||
> | ||
<CopyButton | ||
value={state.generatedSeedPhrase} | ||
onClick={() => { | ||
setState({isCopied: true}); | ||
}} | ||
/> | ||
</Tooltip> | ||
</div> | ||
</div> | ||
<div className="warning-box"> | ||
<img className="icon" src="/assets/warning-icon.svg" width="30" height="30"/> | ||
|
@@ -44,4 +68,4 @@ const CreatePortfolioStep2 = () => { | |
); | ||
}; | ||
|
||
export default CreatePortfolioStep2; | ||
export default withState(CreatePortfolioStep2, {isCopied: false}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would've wanted to put these into
styled-jsx
too, but that'd require converting them to a CSS string. Decided not to bother with it.