Last active
October 8, 2015 14:49
-
-
Save kaw2k/c7a204d8ddad5182829a to your computer and use it in GitHub Desktop.
A hypothetical tooltip API
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
import mouseTracker from 'decorators/mouseTracker'; | |
// options: { | |
// followMouse: false, | |
// positionOrder: ['top', 'bottom', 'left', 'right'], | |
// | |
// } | |
@mouseTracker | |
class PopoverComponent extends React.Component { | |
followMouse() { | |
// TODO: Change to new FINDDomNode | |
const domPopover = this.refs.popover.getDOMNode(); | |
const domToWrap = this.refs.toWrap.getDOMNode(); | |
const width = window.screen.width; | |
const height = window.screen.height; | |
const { clientX, clientY } = this.props.mouse; | |
const { left, right, top, bottom } = domToWrap.getBoundingClientRect(); | |
const { offsetHeight: popoverHeight, offsetWidth: popoverWidth} = domPopover; | |
domPopover.style.left = `${clientX - left}px`; | |
domPopover.style.top = `${clientY - top + 20}px`; | |
} | |
componentDidUpdate() { | |
// If we are not hovering (no mouse prop), | |
// no need to position the popover | |
if (!this.props.mouse) { return; } | |
if (this.props.followMouse) { | |
this.followMouse(); | |
} | |
} | |
render() { | |
const popover = <div ref="popover" | |
className="popover-wrapper" | |
style={{ position: 'absolute' }}> | |
{this.props.popover} | |
</div>; | |
return <div style={{ position: 'relative' }} ref="toWrap"> | |
{this.props.toWrap} | |
{this.props.mouse ? popover : null} | |
</div>; | |
} | |
} | |
export default function Popover(options, popover, toWrap) { | |
return <PopoverComponent {...options} popover={popover} toWrap={toWrap} /> | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* V1. BAD | |
* | |
* This API is confusing in multiple was: | |
* 1. title is a terrible name, it overloads the DOM's title tag | |
* 2. Nesting a <Tooltip /> component feels clunky and requires | |
* thought. Do you nest just one? What happens with two... | |
*/ | |
// We have the ability to make simple one off tooltips by just passing | |
// a title attribute | |
function() { | |
return <TooltipWrapper title="Cool"> | |
Anything within this tag gets a tooltip | |
</TooltipWrapper>; | |
} | |
// If we want more complex functionallity, we can nest components. We | |
// Omit the title (or keep it) and nest a <TooltipBody /> component | |
function() { | |
return <TooltipWrapper> | |
<Tooltip> | |
You can put any arbitrary html in this tag | |
</Tooltip> | |
Anything within this tag gets a tooltip | |
</TooltipWrapper>; | |
} | |
/* | |
* V2. Meh? | |
* | |
* The thrust here is fix the bad from V1 by ONLY limiting it | |
* to using props to render. The tooltip prop would always | |
* take a function whose result gets rendered in a tooltip | |
* | |
* GOOD: | |
* - Consistent API | |
* - Easy to configure how tooltips work (via props) | |
* | |
* BAD: | |
* - Still confusing in the sense that you are wrapping non | |
* tooltip text in a tag and rendering the actual tooltip | |
* via props | |
*/ | |
function() { | |
return <TooltipWrapper tooltip={ () => <span> Hello world!</span> }> | |
Anything within this tag gets a tooltip | |
</TooltipWrapper>; | |
} | |
/* | |
* V3. Meh? | |
* | |
* What we actually are building is a popover component. This | |
* logic could be shared between popover menus, tooltips, etc. | |
* To eliminate the bad from V2 we could change Tooltip, popover | |
* or whatever, to be a function. | |
* | |
* Popover.wrap({options}, <ThingToWrap />, <ThingToPopover />) | |
* | |
* GOOD: | |
* - More explicit with who is doing what | |
* | |
* BAD: | |
* - Still need to know order of operations for method signature | |
* - Hard (or clunky) with how we would configure popovers | |
*/ | |
function() { | |
return <div> | |
{Popver.wrap( | |
{ stayOpen: true, followMouse: true}, | |
<span>Anything within this tag gets a tooltip</span>, | |
<span>Hello world!</span> | |
)} | |
</div>; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment