Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

react-hint

Package Overview
Dependencies
Maintainers
1
Versions
19
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-hint - npm Package Compare versions

Comparing version 1.3.1 to 2.0.0

42

package.json
{
"name": "react-hint",
"version": "1.3.1",
"version": "2.0.0",
"license": "MIT",
"description": "Tooltip component for React, Preact, Inferno",
"author": "Vladimir Simonov <slmgc@ya.ru>",
"homepage": "https://github.com/slmgc/react-hint",
"homepage": "https://react-hint.js.org",
"repository": "slmgc/react-hint",
"license": "MIT",
"main": "lib",
"jsnext:main": "src",
"style": "css/index.css",
"main": "lib/index.js",
"module": "src/index.js",
"jsnext:main": "src/index.js",
"scripts": {
"build": "npm run build:css && npm run build:js",
"build:css": "postcss --use autoprefixer src/css/*.css -d css",
"build:js": "nwb build-react-component",
"start": "nwb serve-react-demo --port 8080"
"build": "nwb build",
"clean": "nwb clean",
"start": "nwb serve --no-clear --port 8080 --reload"
},
"devDependencies": {
"autoprefixer": "6.x",
"nwb": "0.12.x",
"postcss-cli": "2.x",
"primer-buttons": "*",
"react": ">=0.14",
"react-dom": ">=0.14"
"nwb": "0.18.x",
"react": "15.x",
"react-dom": "15.x"
},

@@ -33,9 +29,11 @@ "files": [

"keywords": [
"tooltip",
"react",
"react-tooltip",
"react-component",
"preact",
"inferno"
"hint",
"inferno",
"preact",
"react",
"react-component",
"react-hint",
"react-tooltip",
"tooltip"
]
}
React-hint
==========
**React-hint** is a small tooltip component for [React](https://github.com/facebook/react) which is developed with simplicity and performance in mind. It also plays nicely with [Preact](https://github.com/developit/preact) and [Inferno](https://github.com/trueadm/inferno). There is a [demo page](https://slmgc.github.io/react-hint/).
[![npm package][npm-badge]][npm]
**React-hint** is a small tooltip component for [React](https://github.com/facebook/react) which is developed with simplicity and performance in mind. It also plays nicely with [Preact](https://github.com/developit/preact) and [Inferno](https://github.com/trueadm/inferno).
![react-hint tooltip](https://raw.githubusercontent.com/slmgc/react-hint/master/demo/react-hint.gif)

@@ -17,57 +20,69 @@

----------
Property/Attribute|Type|Default Value|Description
ReactHint Property|Type|Default Value|Description
:---|:---|:---|:---
className|String|react-hint|`<ReactHint />` is a singleton component. You can completely override the default tooltip style by passing `className` property with a new base class name.
attribute|String|"data-rh"|Allows to set a custom tooltip attribute instead of a default `data-rh`.
className|String|"react-hint"|You can completely override a tooltip style by passing a `className` property.
delay|Number|0|The default delay before showing a tooltip.
events|Boolean|false|Enables/disables `mouseOver` events. Disabling events is useful in case you want to trigger a tooltip programmatically.
hover|Boolean|false|Enables to hover a mouse cursor over a tooltip.
position|"top", "left", "right", "bottom"|"top"|Allows to customize a default placement of tooltips.
ref|function||You can get a reference to an instance by passing a function which will set it for you, e.g. `<ReactHint ref={(ref) => this.instance = ref} />`. This might be needed to programmatically trigger a tooltip by calling `this.instance.setState({target})` or update it's content by calling `this.instance.forceUpdate()`.
DOM Element Attribute|Type|Default Value|Description
:---|:---|:---|:---
data-rh|String or #element-id||To show a tooltip on any DOM element and its children add `data-rh` attribute with a tooltip text to the element. Pass `#element-id` instead of a text to show the element's HTML content.
data-rh-at|top, left, right, bottom|top|The default placement of a tooltip is at the top, but you can add `data-rh-at` attribute to change the placement.
data-rh-cls|String||To customize a single tooltip add `data-rh-cls` with a class name which will be added to the tooltip.
data-rh-at|"top", "left", "right", "bottom"|"top"|Allows overriding the default tooltip placement.
```jsx
import React from 'react'
import {render} from 'react-dom'
import ReactHint from 'react-hint'
import {ReactHintFactory} from 'react-hint'
import 'react-hint/css/index.css'
class Demo extends React.Component {
state = {count: 0}
// You can pass any object which contains
// `createElement` & `Component` properties.
// This allows you to pass Inferno/Preact in
// compatibility mode.
const ReactHint = ReactHintFactory(React)
componentDidMount() {
setInterval(() => {
this.setState({count: this.state.count + 1})
ReactHint.instance.forceUpdate()
}, 1000)
class App extends Component {
toggleCustomHint = ({target}) => {
if (this.instance.state.target) target = null
this.instance.setState({target})
}
render() {
const {count} = this.state
return (
<div>
<button data-rh="Default">Default</button>
<button data-rh="Left" data-rh-at="left">Left</button>
<button data-rh="Top" data-rh-at="top">Top</button>
<button data-rh="Bottom" data-rh-at="bottom">Bottom</button>
<button data-rh="Right" data-rh-at="right">Right</button>
<button data-rh={`Count: ${count}`}>Count: {count}</button>
<button data-rh="#custom" data-rh-cls="react-hint--custom">Custom</button>
<ReactHint />
return <div>
<ReactHint events delay={100} />
<ReactHint attribute="data-custom" className="custom-hint"
ref={(ref) => this.instance = ref} />
<div style={{display: 'none'}} id="custom">
Here goes a custom tooltip.<br />
You can show <b>HTML</b> content in tooltips.
<img src="//placekitten.com/260/100" />
</div>
<button data-rh="Default">Default</button>
<button data-rh="Top" data-rh-at="top">Top</button>
<button data-rh="Right" data-rh-at="right">Right</button>
<button data-rh="Bottom" data-rh-at="bottom">Bottom</button>
<button data-rh="Left" data-rh-at="left">Left</button>
<button data-custom="#content" data-custom-at="bottom"
onClick={this.toggleCustomHint}>Click Me</button>
<div id="content" style={{display: 'none'}}>
Here goes a custom tooltip.<br />
You can show <b>HTML</b> content in tooltips.<br />
<img data-rh="Cat" data-rh-at="bottom"
src="https://images.pexels.com/photos/20787/pexels-photo.jpg?w=240" />
</div>
)
</div>
}
}
render(<Demo />, document.getElementById('demo'))
render(<App />, demo)
```
How to rerender
---------------
**React-hint** uses [shouldComponentUpdate](https://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate) under the hood to decide if it needs to be updated. You can use `ReactHint.instance.forceUpdate()` in case you want to force an update.
License
-------
MIT
MIT
[npm-badge]: https://img.shields.io/npm/v/react-hint.png
[npm]: https://www.npmjs.org/package/react-hint

@@ -1,162 +0,150 @@

import React from 'react'
export const ReactHintFactory = ({Component, createElement}) => {
class ReactHint extends Component {
constructor(...args) {
super(...args)
this.state = {target: null}
export default class ReactHint extends React.Component {
static _instance = null
this.shouldComponentUpdate = this.shouldComponentUpdate.bind(this)
this.shallowEqual = this.shallowEqual.bind(this)
this.findHint = this.findHint.bind(this)
this.getHintData = this.getHintData.bind(this)
this.mouseOver = this.mouseOver.bind(this)
this.renderContent = this.renderContent.bind(this)
}
static get instance() {
return ReactHint._instance
}
componentDidMount() {
document.addEventListener('mouseover', this.mouseOver)
}
static set instance(instance) {
if (instance) {
document.addEventListener('mouseover', instance.onHover)
} else {
document.removeEventListener('mouseover', ReactHint.instance.onHover)
componentWillUnmount() {
document.removeEventListener('mouseover', this.mouseOver)
clearTimeout(this._timeout)
}
ReactHint._instance = instance
}
shouldComponentUpdate(props, state) {
return !this.shallowEqual(state, this.state) ||
!this.shallowEqual(props, this.props)
}
static defaultProps = {
className: 'react-hint'
}
shallowEqual(a, b) {
const keys = Object.keys(a)
return keys.length === Object.keys(b).length &&
keys.reduce((result, key) => result &&
(typeof a[key] === 'function' || a[key] === b[key]), true)
}
state = {
target: null,
content: null,
cls: null,
at: 'top',
top: 0,
left: 0
}
componentDidUpdate() {
if (this.state.target) this.setState(this.getHintData)
}
shouldComponentUpdate({className}, {target, content, cls, at, top, left}) {
const {props, state} = this
return target !== state.target
|| content !== state.content
|| cls !== state.cls
|| at !== state.at
|| top !== state.top
|| left !== state.left
|| className !== props.className
}
findHint(el) {
const {attribute, hover} = this.props
const {target} = this.state
componentDidMount() {
if (ReactHint.instance) ReactHint.instance = null
ReactHint.instance = this
}
while (el) {
if (el === document) break
if (hover && el === this._hint) return target
if (el.hasAttribute(attribute)) return el
el = el.parentNode
} return null
}
componentDidUpdate() {
const {target} = this.state
if (!target) return
getHintData({target}, {attribute, position}) {
const content = target.getAttribute(attribute) || ''
const at = target.getAttribute(`${attribute}-at`) || position
const {top, left, width, height} = target.getBoundingClientRect()
if (!(top || left || width || height)) return
const {
top: containerTop,
left: containerLeft
} = this._container.getBoundingClientRect()
this.setState(this.getHintData(target))
}
const {
width: hintWidth,
height: hintHeight
} = this._hint.getBoundingClientRect()
componentWillUnmount() {
ReactHint.instance = null
}
const {
top: targetTop,
left: targetLeft,
width: targetWidth,
height: targetHeight
} = target.getBoundingClientRect()
findHint = (el) => {
while (el) {
if (el === document) break
if (el.hasAttribute('data-rh')) return el
if (el === this._hint) return this.state.target
el = el.parentNode
} return null
}
let top, left
switch (at) {
case 'left':
top = targetHeight - hintHeight >> 1
left = -hintWidth
break
getHintData = (target) => {
const {_container, _hint} = this
const content = target.getAttribute('data-rh')
const cls = target.getAttribute('data-rh-cls')
const at = target.getAttribute('data-rh-at') || 'top'
case 'right':
top = targetHeight - hintHeight >> 1
left = targetWidth
break
const {
top: container_top,
left: container_left,
} = _container.getBoundingClientRect()
case 'bottom':
top = targetHeight
left = targetWidth - hintWidth >> 1
break
const {
width: hint_width,
height: hint_height,
} = _hint.getBoundingClientRect()
case 'top':
default:
top = -hintHeight
left = targetWidth - hintWidth >> 1
}
const {
top: target_top,
left: target_left,
width: target_width,
height: target_height,
} = target.getBoundingClientRect()
return {
content, at,
top: top + targetTop - containerTop,
left: left + targetLeft - containerLeft
}
}
let top, left
switch (at) {
case 'left':
top = target_height - hint_height >> 1
left = -hint_width
break
mouseOver({target}) {
const {delay, events} = this.props
if (!events) return
case 'right':
top = target_height - hint_height >> 1
left = target_width
break
clearTimeout(this._timeout)
this._timeout = setTimeout(() => this.setState(() => ({
target: this.findHint(target)
})), delay)
}
case 'bottom':
top = target_height
left = target_width - hint_width >> 1
break
case 'top':
default:
top = -hint_height
left = target_width - hint_width >> 1
renderContent(content) {
if (String(content)[0] === '#') {
const el = document.getElementById(content.slice(1))
if (el) return createElement('div', {
dangerouslySetInnerHTML: {__html: el.innerHTML}
})
} return content
}
return {
content, cls, at,
top: top + target_top - container_top,
left: left + target_left - container_left
render() {
const {className} = this.props
const {target, content, at, top, left} = this.state
return createElement('div', {
ref: (ref) => this._container = ref,
style: {position: 'relative'},
}, target && createElement('div', {
className: `${className} ${className}--${at}`,
ref: (ref) => this._hint = ref,
style: {top, left}
}, createElement('div', {
className: `${className}__content`
}, this.renderContent(content)))
)
}
}
onHover = ({target}) => {
clearTimeout(this.timeout)
this.timeout = setTimeout(() => {
target = this.findHint(target)
this.setState({target})
}, 100)
ReactHint.defaultProps = {
attribute: 'data-rh',
className: 'react-hint',
delay: 0,
events: false,
hover: false,
position: 'top'
}
setRef = (name, ref) =>
this[name] = ref
renderContent = (content) => {
if (content && content[0] === '#') {
const el = document.getElementById(content.slice(1))
if (el) return <span dangerouslySetInnerHTML={{__html: el.innerHTML}} />
} return content
}
render() {
const {className} = this.props
const {target, content, cls, at, top, left} = this.state
return (
<div style={{position: 'relative'}}
ref={this.setRef.bind(this, '_container')}>
{target &&
<div className={`${className} ${className}--${at} ${cls}`}
ref={this.setRef.bind(this, '_hint')}
style={{top, left}}>
<div className={`${className}__content`}>
{this.renderContent(content)}
</div>
</div>
}
</div>
)
}
}
return ReactHint
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc