Skip to content

Commit f111452

Browse files
authored
Merge pull request #115 from wwayne/improve-structure
Improve structure
2 parents e0ee73d + a5477b2 commit f111452

20 files changed

+739
-548
lines changed

.babelrc

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
{
2-
"presets": ["es2015", "react"]
2+
"presets": ["es2015", "react", "stage-0"],
3+
"plugins": ["transform-decorators-legacy"],
34
}

Makefile

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
NODE_BIN = node_modules/.bin
2+
EXAMPLE_DIST = example/dist
3+
EXAMPLE_SRC = example/src
4+
STANDALONE = standalone
5+
SRC = src
6+
DIST = dist
7+
TEST = test/*.test.js
8+
MOCHA_OPTS = --compilers js:babel-core/register --require test/setup.js -b --timeout 20000 --reporter spec
9+
10+
lint:
11+
@echo Linting...
12+
@$(NODE_BIN)/standard --verbose | $(NODE_BIN)/snazzy src/index.js
13+
14+
test: lint
15+
@echo Start testing...
16+
@$(NODE_BIN)/mocha $(MOCHA_OPTS) $(TEST)
17+
18+
convertCSS:
19+
@echo Converting css...
20+
@node bin/transferSass.js
21+
22+
genStand:
23+
@echo Generating standard...
24+
@rm -rf $(STANDALONE) && mkdir $(STANDALONE)
25+
@$(NODE_BIN)/browserify -t babelify -t browserify-shim $(SRC)/index.js --standalone ReactTooltip -o $(STANDALONE)/react-tooltip.js
26+
@$(NODE_BIN)/browserify -t babelify -t browserify-shim $(SRC)/index.js --standalone ReactTooltip | $(NODE_BIN)/uglifyjs > $(STANDALONE)/react-tooltip.min.js
27+
@cp $(DIST)/style.js $(STANDALONE)/style.js
28+
29+
devJS:
30+
@$(NODE_BIN)/watchify -t babelify $(EXAMPLE_SRC)/index.js -o $(EXAMPLE_DIST)/index.js -dv
31+
32+
devCSS:
33+
@$(NODE_BIN)/node-sass $(EXAMPLE_SRC)/index.scss $(EXAMPLE_DIST)/index.css
34+
@$(NODE_BIN)/node-sass -w $(EXAMPLE_SRC)/index.scss $(EXAMPLE_DIST)/index.css
35+
36+
devServer:
37+
@echo Listening 8888...
38+
@$(NODE_BIN)/http-server example -p 8888 -s
39+
40+
dev:
41+
@echo starting dev server...
42+
@rm -rf $(EXAMPLE_DIST)
43+
@mkdir -p $(EXAMPLE_DIST)
44+
@make convertCSS
45+
@$(NODE_BIN)/concurrently --kill-others "make devJS" "make devCSS" "make devServer"
46+
47+
deployJS:
48+
@echo Generating deploy JS files...
49+
@$(NODE_BIN)/babel $(SRC)/index.js -o $(DIST)/react-tooltip.js
50+
@$(NODE_BIN)/babel $(SRC)/style.js -o $(DIST)/style.js
51+
@$(NODE_BIN)/babel $(SRC)/index.js | $(NODE_BIN)/uglifyjs > $(DIST)/react-tooltip.min.js
52+
53+
deployCSS:
54+
@echo Generating deploy CSS files...
55+
@cp $(SRC)/index.scss $(DIST)/react-tooltip.scss
56+
@$(NODE_BIN)/node-sass --output-style compressed $(SRC)/index.scss $(DIST)/react-tooltip.min.css
57+
58+
deploy: lint
59+
@echo Deploy...
60+
@rm -rf dist && mkdir dist
61+
@make convertCSS
62+
@make deployCSS
63+
@make deployJS
64+
@make genStand
65+
@echo success!
66+
67+
.PHONY: lint convertCSS genStand devJS devCSS devServer dev deployJS deployCSS deploy

bin/transferSass.js

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ function transferSass () {
1616
console.error(err)
1717
}
1818
console.log('css file has been transformed successful')
19+
process.exit()
1920
})
2021
})
2122
}

circle.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
machine:
22
node:
3-
version: 0.12.0
3+
version: 4.2.1
44

55
dependencies:
66
override:

example/src/index.js

+61-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import React from 'react'
44
import {render} from 'react-dom'
5-
import ReactTooltip from '../../src/index'
5+
import ReactTooltip from '../../src'
66

77
const Test = React.createClass({
88

@@ -152,18 +152,75 @@ const Test = React.createClass({
152152

153153
<div className="example-jsx">
154154
<div className="side">
155-
<a data-for='customer-event' data-tip='customer event' data-event='click' data-type='info'>( •̀д•́)</a>
156-
<ReactTooltip id='customer-event' />
155+
<a data-for='customer-event' data-tip='customer show' data-event='click focus'>( •̀д•́)</a>
156+
<ReactTooltip id='customer-event' globalEventOff='click'/>
157+
</div>
158+
159+
<div className="side">
160+
<a data-for='customer-off-event' data-tip='custom show and hide' data-event='click' data-event-off='dblclick'>( •̀д•́)</a>
161+
<ReactTooltip id='customer-off-event'/>
157162
</div>
158163
</div>
159164
<br />
160165
<pre className='example-pre'>
161166
<div>
162-
<p>{"<a data-tip='customer event' data-event='click' data-type='info'>( •̀д•́)</a>\n" +
167+
<p>{"<a data-tip='customer show' data-event='click focus'>( •̀д•́)</a>\n" +
168+
"<ReactTooltip globalEventOff='click' />"}</p>
169+
</div>
170+
<div>
171+
<p>{"<a data-tip='custom show and hide' data-event='click' data-event-off='dblclick'>( •̀д•́)</a>\n" +
163172
"<ReactTooltip/>"}</p>
164173
</div>
165174
</pre>
166175
</div>
176+
177+
<div className="section">
178+
<h4 className='title'>Theme and delay</h4>
179+
<p className="sub-title"></p>
180+
181+
<div className="example-jsx">
182+
<div className="side">
183+
<a data-for='customer-class' data-tip='hover on me will keep the tootlip'>(・ω´・ )</a>
184+
<ReactTooltip id='customer-class' class='extraClass' delayHide={1000} effect='solid'/>
185+
</div>
186+
187+
<div className="side">
188+
<a data-for='customer-theme' data-tip='custom theme'>(・ω´・ )</a>
189+
<ReactTooltip id='customer-theme' class='customeTheme'/>
190+
</div>
191+
</div>
192+
<br />
193+
<pre className='example-pre'>
194+
<div>
195+
<p>{"<a data-tip='hover on me will keep the tootlip'>(・ω´・ )́)</a>\n" +
196+
"<ReactTooltip class='extraClass' delayHide={1000} effect='solid'/>\n" +
197+
".extraClass {\n" +
198+
" font-size: 20px !important;\n" +
199+
" pointer-events: auto !important;\n" +
200+
" &:hover {\n" +
201+
"visibility: visible !important;\n" +
202+
"opacity: 1 !important;\n" +
203+
" }\n" +
204+
"}"}</p>
205+
</div>
206+
207+
<div>
208+
<p>{"<a data-tip='custom theme'>(・ω´・ )́)</a>\n" +
209+
"<ReactTooltip class='customeTheme'/>\n" +
210+
" .customeTheme {\n" +
211+
" color: #ff6e00 !important;\n" +
212+
" background-color: orange !important;\n" +
213+
" &.place-top {\n" +
214+
" &:after {\n" +
215+
" border-top-color: orange !important;\n" +
216+
" border-top-style: solid !important;\n" +
217+
" border-top-width: 6px !important;\n" +
218+
" }\n" +
219+
" }\n" +
220+
"}"}</p>
221+
</div>
222+
</pre>
223+
</div>
167224
</section>
168225
</div>
169226
)

example/src/index.scss

+22
Original file line numberDiff line numberDiff line change
@@ -206,3 +206,25 @@ html, body{
206206
line-height: 30px;
207207
}
208208
}
209+
210+
// Extra class for demonstration
211+
.extraClass {
212+
font-size: 20px !important;
213+
pointer-events: auto !important;
214+
&:hover {
215+
visibility: visible !important;
216+
opacity: 1 !important;
217+
}
218+
}
219+
220+
.customeTheme {
221+
color: #ff6e00 !important;
222+
background-color: orange !important;
223+
&.place-top {
224+
&:after {
225+
border-top-color: orange !important;
226+
border-top-style: solid !important;
227+
border-top-width: 6px !important;
228+
}
229+
}
230+
}

package.json

+17-18
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,12 @@
11
{
22
"name": "react-tooltip",
3-
"version": "2.0.3",
3+
"version": "3.0.0",
44
"description": "react tooltip component",
55
"main": "index.js",
66
"scripts": {
7-
"check": "standard --verbose | snazzy src/index.js",
8-
"test": "npm run check",
9-
"devjs": "node bin/transferSass.js & watchify -t babelify ./example/src/index.js -o ./example/dist/index.js -dv",
10-
"devcss": "node-sass example/src/index.scss example/dist/index.css & node-sass -w example/src/index.scss example/dist/index.css",
11-
"predev": "rm -rf example/dist",
12-
"dev": "mkdir -p ./example/dist & npm run devjs & npm run devcss & http-server example -p 8888 -s -o",
13-
"deployjs": "babel src/index.js -o dist/react-tooltip.js && babel src/style.js -o dist/style.js && npm run deployminjs",
14-
"deployminjs": "babel src/index.js | uglifyjs > dist/react-tooltip.min.js",
15-
"predeploycss": "cp src/index.scss dist/react-tooltip.scss",
16-
"deploycss": "node-sass --output-style compressed src/index.scss dist/react-tooltip.min.css",
17-
"predeploy": "rm -rf dist",
18-
"deploy": "mkdir dist & npm run deployjs & npm run deploycss & npm run standjs",
19-
"prestandjs": "rm -rf standalone",
20-
"standjs": "mkdir standalone && browserify -t babelify -t browserify-shim src/index.js --standalone ReactTooltip -o standalone/react-tooltip.js & npm run standminjs",
21-
"standminjs": "browserify -t babelify -t browserify-shim src/index.js --standalone ReactTooltip | uglifyjs > standalone/react-tooltip.min.js",
22-
"poststandjs": "cp ./dist/style.js ./standalone/style.js"
7+
"test": "make test",
8+
"dev": "make start",
9+
"deploy": "make deploy"
2310
},
2411
"standard": {
2512
"parser": "babel-eslint",
@@ -59,15 +46,27 @@
5946
},
6047
"devDependencies": {
6148
"babel-cli": "^6.5.1",
49+
"babel-core": "^6.9.1",
6250
"babel-eslint": "^4.1.1",
51+
"babel-plugin-transform-decorators-legacy": "^1.3.4",
6352
"babel-plugin-transform-runtime": "^6.5.0",
6453
"babel-preset-es2015": "^6.5.0",
6554
"babel-preset-react": "^6.5.0",
55+
"babel-preset-stage-0": "^6.5.0",
6656
"babelify": "^7.2.0",
6757
"browserify": "^13.0.0",
6858
"browserify-shim": "^3.8.12",
59+
"chai": "^3.5.0",
60+
"chai-enzyme": "^0.5.0",
61+
"cheerio": "^0.20.0",
62+
"concurrently": "^2.1.0",
63+
"enzyme": "^2.3.0",
6964
"http-server": "^0.8.0",
70-
"node-sass": "^3.3.2",
65+
"jsdom": "^9.2.1",
66+
"mocha": "^2.5.3",
67+
"node-sass": "^3.7.0",
68+
"react-addons-test-utils": "^15.1.0",
69+
"sinon": "^1.17.4",
7170
"snazzy": "^2.0.1",
7271
"standard": "^5.2.2",
7372
"tape": "^4.2.0",

src/constant.js

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export default {
2+
3+
GLOBAL: {
4+
HIDE: '__react_tooltip_hide_event',
5+
REBUILD: '__react_tooltip_rebuild_event',
6+
SHOW: '__react_tooltip_show_event'
7+
}
8+
}

src/decorators/customEvent.js

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/**
2+
* Custom events to control showing and hiding of tooltip
3+
*
4+
* @attributes
5+
* - `event` {String}
6+
* - `eventOff` {String}
7+
*/
8+
9+
const checkStatus = function (dataEventOff, e) {
10+
const {show} = this.state
11+
const dataIsCapture = e.currentTarget.getAttribute('data-iscapture')
12+
const isCapture = dataIsCapture && dataIsCapture === 'true' || this.props.isCapture
13+
const currentItem = e.currentTarget.getAttribute('currentItem')
14+
15+
if (!isCapture) e.stopPropagation()
16+
if (show && currentItem === 'true') {
17+
if (!dataEventOff) this.hideTooltip(e)
18+
} else {
19+
e.currentTarget.setAttribute('currentItem', 'true')
20+
setUntargetItems(e.currentTarget, this.getTargetArray())
21+
this.showTooltip(e)
22+
}
23+
}
24+
25+
const setUntargetItems = function (currentTarget, targetArray) {
26+
for (let i = 0; i < targetArray.length; i++) {
27+
if (currentTarget !== targetArray[i]) {
28+
targetArray[i].setAttribute('currentItem', 'false')
29+
} else {
30+
targetArray[i].setAttribute('currentItem', 'true')
31+
}
32+
}
33+
}
34+
35+
export default function (target) {
36+
target.prototype.isCustomEvent = function (ele) {
37+
const {event} = this.state
38+
return event || ele.getAttribute('data-event')
39+
}
40+
41+
/* Bind listener for custom event */
42+
target.prototype.customBindListener = function (ele) {
43+
const {event, eventOff} = this.state
44+
const dataEvent = ele.getAttribute('data-event') || event
45+
const dataEventOff = ele.getAttribute('data-event-off') || eventOff
46+
47+
dataEvent.split(' ').forEach(event => {
48+
ele.removeEventListener(event, checkStatus)
49+
ele.addEventListener(event, checkStatus.bind(this, dataEventOff), false)
50+
})
51+
if (dataEventOff) {
52+
dataEventOff.split(' ').forEach(event => {
53+
ele.removeEventListener(event, this.hideTooltip)
54+
ele.addEventListener(event, ::this.hideTooltip, false)
55+
})
56+
}
57+
}
58+
59+
/* Unbind listener for custom event */
60+
target.prototype.customUnbindListener = function (ele) {
61+
const {event, eventOff} = this.state
62+
const dataEvent = event || ele.getAttribute('data-event')
63+
const dataEventOff = eventOff || ele.getAttribute('data-event-off')
64+
65+
ele.removeEventListener(dataEvent, checkStatus)
66+
if (dataEventOff) ele.removeEventListener(dataEventOff, this.hideTooltip)
67+
}
68+
}

src/decorators/isCapture.js

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* Util method to judge if it should follow capture model
3+
*/
4+
5+
export default function (target) {
6+
target.prototype.isCapture = function (currentTarget) {
7+
const dataIsCapture = currentTarget.getAttribute('data-iscapture')
8+
return dataIsCapture && dataIsCapture === 'true' || this.props.isCapture || false
9+
}
10+
}

src/decorators/staticMethods.js

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
* Static methods for react-tooltip
3+
*/
4+
import CONSTANT from '../constant'
5+
6+
const dispatchGlobalEvent = (eventName) => {
7+
// Compatibale with IE
8+
// @see http://stackoverflow.com/questions/26596123/internet-explorer-9-10-11-event-constructor-doesnt-work
9+
let event
10+
11+
if (typeof window.Event === 'function') {
12+
event = new window.Event(eventName)
13+
} else {
14+
event = document.createEvent('Event')
15+
event.initEvent(eventName, false, true)
16+
}
17+
18+
window.dispatchEvent(event)
19+
}
20+
21+
export default function (target) {
22+
/**
23+
* Hide all tooltip
24+
* @trigger ReactTooltip.hide()
25+
*/
26+
target.hide = () => {
27+
dispatchGlobalEvent(CONSTANT.GLOBAL.HIDE)
28+
}
29+
30+
/**
31+
* Rebuild all tooltip
32+
* @trigger ReactTooltip.rebuild()
33+
*/
34+
target.rebuild = () => {
35+
dispatchGlobalEvent(CONSTANT.GLOBAL.REBUILD)
36+
}
37+
38+
target.prototype.globalRebuild = function () {
39+
if (this.mount) {
40+
this.unbindListener()
41+
this.bindListener()
42+
}
43+
}
44+
}

0 commit comments

Comments
 (0)