├── .gitignore ├── .npmignore ├── .npmrc ├── README.md ├── dist ├── react-tippy.js └── react-tippy.js.map ├── doc └── doc.gif ├── package.json ├── public ├── favicon.ico └── index.html ├── src ├── App.css ├── App.js ├── App.test.js ├── Tooltip │ ├── component.js │ ├── hoc.js │ └── index.js ├── index.css ├── index.js ├── logo.svg ├── state.js └── state │ ├── createStore.js │ └── rootReducer.js ├── webpacklib.config.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | /dist 13 | 14 | # misc 15 | .DS_Store 16 | .env 17 | npm-debug.log* 18 | yarn-debug.log* 19 | yarn-error.log* 20 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | /doc 12 | /src 13 | /public 14 | 15 | 16 | # misc 17 | .DS_Store 18 | .env 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://registry.npmjs.org/ 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fork of [React Tippy](https://github.com/tvkhoa/react-tippy) 2 | 3 | Major changes: 4 | - [tippy.js](https://atomiks.github.io/tippyjs/) is now a true dependency (rather than a full copy of the source code) 5 | - Requires `tippy.js@2.x`, `react@16.x` 6 | - `html` property has been renamed to `render` (can be a function or React element), React Portal is used behind the scene to render the tooltip's content 7 | - See [tippy.js docs](https://atomiks.github.io/tippyjs/#all-options) for the list of all props/options 8 | -------------------------------------------------------------------------------- /dist/react-tippy.js: -------------------------------------------------------------------------------- 1 | (function webpackUniversalModuleDefinition(root, factory) { 2 | if(typeof exports === 'object' && typeof module === 'object') 3 | module.exports = factory(require("react"), require("react-dom"), require("tippy.js/dist/tippy.standalone.js")); 4 | else if(typeof define === 'function' && define.amd) 5 | define("reactTippy", ["react", "react-dom", "tippy.js/dist/tippy.standalone.js"], factory); 6 | else if(typeof exports === 'object') 7 | exports["reactTippy"] = factory(require("react"), require("react-dom"), require("tippy.js/dist/tippy.standalone.js")); 8 | else 9 | root["reactTippy"] = factory(root["React"], root["ReactDOM"], root["tippy"]); 10 | })(this, function(__WEBPACK_EXTERNAL_MODULE_1__, __WEBPACK_EXTERNAL_MODULE_4__, __WEBPACK_EXTERNAL_MODULE_5__) { 11 | return /******/ (function(modules) { // webpackBootstrap 12 | /******/ // The module cache 13 | /******/ var installedModules = {}; 14 | /******/ 15 | /******/ // The require function 16 | /******/ function __webpack_require__(moduleId) { 17 | /******/ 18 | /******/ // Check if module is in cache 19 | /******/ if(installedModules[moduleId]) 20 | /******/ return installedModules[moduleId].exports; 21 | /******/ 22 | /******/ // Create a new module (and put it into the cache) 23 | /******/ var module = installedModules[moduleId] = { 24 | /******/ i: moduleId, 25 | /******/ l: false, 26 | /******/ exports: {} 27 | /******/ }; 28 | /******/ 29 | /******/ // Execute the module function 30 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 31 | /******/ 32 | /******/ // Flag the module as loaded 33 | /******/ module.l = true; 34 | /******/ 35 | /******/ // Return the exports of the module 36 | /******/ return module.exports; 37 | /******/ } 38 | /******/ 39 | /******/ 40 | /******/ // expose the modules object (__webpack_modules__) 41 | /******/ __webpack_require__.m = modules; 42 | /******/ 43 | /******/ // expose the module cache 44 | /******/ __webpack_require__.c = installedModules; 45 | /******/ 46 | /******/ // identity function for calling harmony imports with the correct context 47 | /******/ __webpack_require__.i = function(value) { return value; }; 48 | /******/ 49 | /******/ // define getter function for harmony exports 50 | /******/ __webpack_require__.d = function(exports, name, getter) { 51 | /******/ if(!__webpack_require__.o(exports, name)) { 52 | /******/ Object.defineProperty(exports, name, { 53 | /******/ configurable: false, 54 | /******/ enumerable: true, 55 | /******/ get: getter 56 | /******/ }); 57 | /******/ } 58 | /******/ }; 59 | /******/ 60 | /******/ // getDefaultExport function for compatibility with non-harmony modules 61 | /******/ __webpack_require__.n = function(module) { 62 | /******/ var getter = module && module.__esModule ? 63 | /******/ function getDefault() { return module['default']; } : 64 | /******/ function getModuleExports() { return module; }; 65 | /******/ __webpack_require__.d(getter, 'a', getter); 66 | /******/ return getter; 67 | /******/ }; 68 | /******/ 69 | /******/ // Object.prototype.hasOwnProperty.call 70 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 71 | /******/ 72 | /******/ // __webpack_public_path__ 73 | /******/ __webpack_require__.p = ""; 74 | /******/ 75 | /******/ // Load entry module and return exports 76 | /******/ return __webpack_require__(__webpack_require__.s = 3); 77 | /******/ }) 78 | /************************************************************************/ 79 | /******/ ([ 80 | /* 0 */ 81 | /***/ (function(module, exports, __webpack_require__) { 82 | 83 | "use strict"; 84 | 85 | 86 | Object.defineProperty(exports, "__esModule", { 87 | value: true 88 | }); 89 | 90 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; 91 | 92 | var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; 93 | 94 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 95 | 96 | var _react = __webpack_require__(1); 97 | 98 | var _react2 = _interopRequireDefault(_react); 99 | 100 | var _reactDom = __webpack_require__(4); 101 | 102 | var _reactDom2 = _interopRequireDefault(_reactDom); 103 | 104 | var _tippyStandalone = __webpack_require__(5); 105 | 106 | var _tippyStandalone2 = _interopRequireDefault(_tippyStandalone); 107 | 108 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 109 | 110 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 111 | 112 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 113 | 114 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 115 | 116 | var defaultProps = { 117 | title: null, 118 | open: false, 119 | disabled: false 120 | }; 121 | 122 | function applyIfFunction(fn) { 123 | return typeof fn === 'function' ? fn() : fn; 124 | } 125 | 126 | var Tooltip = function (_Component) { 127 | _inherits(Tooltip, _Component); 128 | 129 | function Tooltip() { 130 | var _ref; 131 | 132 | var _temp, _this, _ret; 133 | 134 | _classCallCheck(this, Tooltip); 135 | 136 | for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { 137 | args[_key] = arguments[_key]; 138 | } 139 | 140 | return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = Tooltip.__proto__ || Object.getPrototypeOf(Tooltip)).call.apply(_ref, [this].concat(args))), _this), _this.showTooltip = function () { 141 | _this.tippy.show(); 142 | }, _this.hideTooltip = function () { 143 | _this.tippy.hide(); 144 | }, _this.contentRoot = function () { 145 | if (!_this._contentRoot && (typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object') _this._contentRoot = window.document.createElement('div'); 146 | return _this._contentRoot; 147 | }, _this.initTippy = function () { 148 | _this.tooltipDOM.setAttribute('title', _this.props.title); 149 | (0, _tippyStandalone2.default)(_this.tooltipDOM, _extends({}, _this.props, { 150 | html: _this.props.render ? _this.contentRoot() : _this.props.rawTemplate, 151 | dynamicTitle: true, 152 | performance: true 153 | })); 154 | _this.tippy = _this.tooltipDOM._tippy; 155 | if (_this.props.open) { 156 | _this.showTooltip(); 157 | } 158 | }, _this.destroyTippy = function () { 159 | _this.tippy.destroy(); 160 | _this.tippy = null; 161 | }, _temp), _possibleConstructorReturn(_this, _ret); 162 | } 163 | 164 | _createClass(Tooltip, [{ 165 | key: 'componentDidMount', 166 | value: function componentDidMount() { 167 | this.initTippy(); 168 | } 169 | }, { 170 | key: 'componentWillUnmount', 171 | value: function componentWillUnmount() { 172 | this.destroyTippy(); 173 | } 174 | }, { 175 | key: 'componentDidUpdate', 176 | value: function componentDidUpdate(prevProps) { 177 | var _this2 = this; 178 | 179 | if (!this.tippy) return; 180 | 181 | // enable and disabled 182 | if (this.props.disabled === false && prevProps.disabled === true) { 183 | this.tippy.enable(); 184 | return; 185 | } 186 | 187 | if (this.props.disabled === true && prevProps.disabled === false) { 188 | this.tippy.disable(); 189 | return; 190 | } 191 | 192 | // open 193 | if (this.props.open === true && !prevProps.open) { 194 | setTimeout(function () { 195 | _this2.showTooltip(); 196 | }, 0); 197 | } 198 | 199 | if (this.props.open === false && prevProps.open === true) { 200 | this.hideTooltip(); 201 | } 202 | } 203 | }, { 204 | key: 'render', 205 | value: function render() { 206 | var _this3 = this; 207 | 208 | return _react2.default.createElement( 209 | 'div', 210 | { 211 | ref: function ref(tooltip) { 212 | _this3.tooltipDOM = tooltip; 213 | }, 214 | title: this.props.title, 215 | className: this.props.className, 216 | tabIndex: this.props.tabIndex, 217 | style: _extends({ 218 | display: 'inline' 219 | }, this.props.style) 220 | }, 221 | this.props.children, 222 | this.props.render && this.contentRoot() ? _reactDom2.default.createPortal(applyIfFunction(this.props.render), this.contentRoot()) : null 223 | ); 224 | } 225 | }]); 226 | 227 | return Tooltip; 228 | }(_react.Component); 229 | 230 | Tooltip.defaultProps = defaultProps; 231 | 232 | exports.default = Tooltip; 233 | 234 | /***/ }), 235 | /* 1 */ 236 | /***/ (function(module, exports) { 237 | 238 | module.exports = __WEBPACK_EXTERNAL_MODULE_1__; 239 | 240 | /***/ }), 241 | /* 2 */ 242 | /***/ (function(module, exports, __webpack_require__) { 243 | 244 | "use strict"; 245 | 246 | 247 | Object.defineProperty(exports, "__esModule", { 248 | value: true 249 | }); 250 | 251 | var _react = __webpack_require__(1); 252 | 253 | var _react2 = _interopRequireDefault(_react); 254 | 255 | var _component = __webpack_require__(0); 256 | 257 | var _component2 = _interopRequireDefault(_component); 258 | 259 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 260 | 261 | function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } 262 | 263 | var withTooltip = function withTooltip(Component) { 264 | var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 265 | return function (_ref) { 266 | var props = _objectWithoutProperties(_ref, []); 267 | 268 | return _react2.default.createElement( 269 | _component2.default, 270 | options, 271 | _react2.default.createElement(Component, props) 272 | ); 273 | }; 274 | }; 275 | 276 | exports.default = withTooltip; 277 | 278 | /***/ }), 279 | /* 3 */ 280 | /***/ (function(module, exports, __webpack_require__) { 281 | 282 | "use strict"; 283 | 284 | 285 | Object.defineProperty(exports, "__esModule", { 286 | value: true 287 | }); 288 | exports.withTooltip = exports.Tooltip = undefined; 289 | 290 | var _component = __webpack_require__(0); 291 | 292 | var _component2 = _interopRequireDefault(_component); 293 | 294 | var _hoc = __webpack_require__(2); 295 | 296 | var _hoc2 = _interopRequireDefault(_hoc); 297 | 298 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 299 | 300 | exports.Tooltip = _component2.default; 301 | exports.withTooltip = _hoc2.default; 302 | 303 | /***/ }), 304 | /* 4 */ 305 | /***/ (function(module, exports) { 306 | 307 | module.exports = __WEBPACK_EXTERNAL_MODULE_4__; 308 | 309 | /***/ }), 310 | /* 5 */ 311 | /***/ (function(module, exports) { 312 | 313 | module.exports = __WEBPACK_EXTERNAL_MODULE_5__; 314 | 315 | /***/ }) 316 | /******/ ]); 317 | }); 318 | //# sourceMappingURL=react-tippy.js.map -------------------------------------------------------------------------------- /dist/react-tippy.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack:///webpack/universalModuleDefinition","webpack:///webpack/bootstrap 6acb0fb9028144671a84","webpack:///./src/Tooltip/component.js","webpack:///external {\"root\":\"React\",\"commonjs2\":\"react\",\"commonjs\":\"react\",\"amd\":\"react\",\"umd\":\"react\"}","webpack:///./src/Tooltip/hoc.js","webpack:///./src/Tooltip/index.js","webpack:///external {\"root\":\"ReactDOM\",\"commonjs2\":\"react-dom\",\"commonjs\":\"react-dom\",\"amd\":\"react-dom\",\"umd\":\"react-dom\"}","webpack:///external {\"root\":\"tippy\",\"commonjs2\":\"tippy.js/dist/tippy.standalone.js\",\"commonjs\":\"tippy.js/dist/tippy.standalone.js\",\"amd\":\"tippy.js/dist/tippy.standalone.js\",\"umd\":\"tippy.js/dist/tippy.standalone.js\"}"],"names":["defaultProps","title","open","disabled","applyIfFunction","fn","Tooltip","showTooltip","tippy","show","hideTooltip","hide","contentRoot","_contentRoot","window","document","createElement","initTippy","tooltipDOM","setAttribute","props","html","render","rawTemplate","dynamicTitle","performance","_tippy","destroyTippy","destroy","prevProps","enable","disable","setTimeout","tooltip","className","tabIndex","display","style","children","createPortal","withTooltip","Component","options"],"mappings":"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","file":"react-tippy.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"react\"), require(\"react-dom\"), require(\"tippy.js/dist/tippy.standalone.js\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"reactTippy\", [\"react\", \"react-dom\", \"tippy.js/dist/tippy.standalone.js\"], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"reactTippy\"] = factory(require(\"react\"), require(\"react-dom\"), require(\"tippy.js/dist/tippy.standalone.js\"));\n\telse\n\t\troot[\"reactTippy\"] = factory(root[\"React\"], root[\"ReactDOM\"], root[\"tippy\"]);\n})(this, function(__WEBPACK_EXTERNAL_MODULE_1__, __WEBPACK_EXTERNAL_MODULE_4__, __WEBPACK_EXTERNAL_MODULE_5__) {\nreturn \n\n\n// WEBPACK FOOTER //\n// webpack/universalModuleDefinition"," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// identity function for calling harmony imports with the correct context\n \t__webpack_require__.i = function(value) { return value; };\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 3);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 6acb0fb9028144671a84","import React, { Component } from 'react';\nimport ReactDOM from 'react-dom';\nimport tippy from 'tippy.js/dist/tippy.standalone.js';\n\nconst defaultProps = {\n title: null,\n open: false,\n disabled: false\n};\n\n\nfunction applyIfFunction( fn ) {\n return (typeof fn === 'function') ? fn() : fn;\n}\n\n\nclass Tooltip extends Component {\n\n componentDidMount() {\n this.initTippy();\n }\n\n componentWillUnmount() {\n this.destroyTippy();\n }\n\n componentDidUpdate(prevProps) {\n if ( !this.tippy )\n return;\n\n // enable and disabled\n if (this.props.disabled === false && prevProps.disabled === true) {\n this.tippy.enable();\n return;\n }\n\n if (this.props.disabled === true && prevProps.disabled === false) {\n this.tippy.disable();\n return;\n }\n\n // open\n if (this.props.open === true && !prevProps.open) {\n setTimeout(() => {\n this.showTooltip();\n }, 0)\n }\n\n if (this.props.open === false && prevProps.open === true) {\n this.hideTooltip();\n }\n }\n\n showTooltip = () => {\n this.tippy.show();\n }\n\n hideTooltip = () => {\n this.tippy.hide();\n }\n\n contentRoot = () => {\n if ( !this._contentRoot && typeof window === 'object' )\n this._contentRoot = window.document.createElement( 'div' );\n return this._contentRoot;\n }\n\n initTippy = () => {\n this.tooltipDOM.setAttribute('title', this.props.title);\n tippy(this.tooltipDOM, {\n ...this.props,\n html: this.props.render ? this.contentRoot() : this.props.rawTemplate,\n dynamicTitle: true,\n performance: true\n });\n this.tippy = this.tooltipDOM._tippy;\n if (this.props.open) {\n this.showTooltip();\n }\n }\n\n destroyTippy = () => {\n this.tippy.destroy();\n this.tippy = null;\n }\n\n\n render() {\n return (\n { this.tooltipDOM = tooltip; }}\n title={this.props.title}\n className={this.props.className}\n tabIndex={this.props.tabIndex}\n style={{\n display: 'inline',\n ...this.props.style\n }}\n >\n {this.props.children}\n {this.props.render && this.contentRoot()\n ? ReactDOM.createPortal(\n applyIfFunction( this.props.render ),\n this.contentRoot() )\n : null}\n \n );\n }\n}\n\n\nTooltip.defaultProps = defaultProps;\n\nexport default Tooltip;\n\n\n\n// WEBPACK FOOTER //\n// ./src/Tooltip/component.js","module.exports = __WEBPACK_EXTERNAL_MODULE_1__;\n\n\n//////////////////\n// WEBPACK FOOTER\n// external {\"root\":\"React\",\"commonjs2\":\"react\",\"commonjs\":\"react\",\"amd\":\"react\",\"umd\":\"react\"}\n// module id = 1\n// module chunks = 0","import React from 'react';\nimport Tooltip from './component';\n\nconst withTooltip = (Component, options = {}) => ({\n ...props,\n}) => (\n \n \n \n);\n\nexport default withTooltip;\n\n\n\n// WEBPACK FOOTER //\n// ./src/Tooltip/hoc.js","import Tooltip from './component';\nimport withTooltip from './hoc';\n\nexport {\n Tooltip,\n withTooltip,\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/Tooltip/index.js","module.exports = __WEBPACK_EXTERNAL_MODULE_4__;\n\n\n//////////////////\n// WEBPACK FOOTER\n// external {\"root\":\"ReactDOM\",\"commonjs2\":\"react-dom\",\"commonjs\":\"react-dom\",\"amd\":\"react-dom\",\"umd\":\"react-dom\"}\n// module id = 4\n// module chunks = 0","module.exports = __WEBPACK_EXTERNAL_MODULE_5__;\n\n\n//////////////////\n// WEBPACK FOOTER\n// external {\"root\":\"tippy\",\"commonjs2\":\"tippy.js/dist/tippy.standalone.js\",\"commonjs\":\"tippy.js/dist/tippy.standalone.js\",\"amd\":\"tippy.js/dist/tippy.standalone.js\",\"umd\":\"tippy.js/dist/tippy.standalone.js\"}\n// module id = 5\n// module chunks = 0"],"sourceRoot":""} -------------------------------------------------------------------------------- /doc/doc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/textpress/react-tippy/62574cb6351cf6390fd1764772c7df035cca6b9a/doc/doc.gif -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-tippy", 3 | "version": "1.2.2", 4 | "description": "React tippy", 5 | "main": "dist/react-tippy.js", 6 | "author": "Khoa Thai", 7 | "license": "MIT", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/tvkhoa/react-tippy.git" 11 | }, 12 | "bugs": { 13 | "url": "https://github.com/tvkhoa/react-tippy/issues" 14 | }, 15 | "homepage": "https://github.com/tvkhoa/react-tippy", 16 | "devDependencies": { 17 | "babel": "^6.23.0", 18 | "babel-core": "^6.24.0", 19 | "babel-eslint": "^7.2.0", 20 | "babel-loader": "^6.4.1", 21 | "babel-plugin-add-module-exports": "^0.2.1", 22 | "babel-plugin-lodash": "^3.2.11", 23 | "babel-plugin-transform-class-properties": "^6.24.1", 24 | "babel-plugin-transform-flow-strip-types": "^6.22.0", 25 | "babel-plugin-transform-object-rest-spread": "^6.26.0", 26 | "babel-preset-es2015": "^6.24.1", 27 | "babel-preset-react": "^6.24.1", 28 | "chai": "^3.5.0", 29 | "eslint": "^3.18.0", 30 | "eslint-loader": "^1.6.3", 31 | "eslint-plugin-import": "^2.2.0", 32 | "flow-bin": "^0.42.0", 33 | "lodash-webpack-plugin": "^0.11.2", 34 | "mocha": "^3.2.0", 35 | "react": "^16.2.0", 36 | "react-dom": "^16.2.0", 37 | "react-redux": "^5.0.5", 38 | "react-scripts": "1.1.1", 39 | "recompose": "^0.26.0", 40 | "redux": "^3.7.1", 41 | "redux-state-action": "^1.0.8", 42 | "redux-thunk": "^2.2.0", 43 | "webpack": "^2.3.0", 44 | "yargs": "^7.0.2" 45 | }, 46 | "scripts": { 47 | "build": "webpack --config webpacklib.config.js --env build", 48 | "start": "react-scripts start" 49 | }, 50 | "dependencies": { 51 | "popper.js": "^1.11.1", 52 | "tippy.js": "^2.1.1" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/textpress/react-tippy/62574cb6351cf6390fd1764772c7df035cca6b9a/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 16 | React App 17 | 18 | 19 |
20 | Raw here 21 |
22 |
23 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 80px; 8 | } 9 | 10 | .App-header { 11 | background-color: #222; 12 | height: 150px; 13 | padding: 20px; 14 | color: white; 15 | } 16 | 17 | .App-intro { 18 | font-size: large; 19 | } 20 | 21 | @keyframes App-logo-spin { 22 | from { transform: rotate(0deg); } 23 | to { transform: rotate(360deg); } 24 | } 25 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { 3 | compose, 4 | withState, 5 | } from 'recompose'; 6 | import { 7 | connect, 8 | } from 'react-redux'; 9 | import logo from './logo.svg'; 10 | import './App.css'; 11 | import { 12 | Tooltip, 13 | withTooltip, 14 | } from './Tooltip'; 15 | import { 16 | contentSelector 17 | } from './state'; 18 | 19 | const ManualPopover = ({ children, open, onRequestClose, content }) => { 20 | return ( 21 | 30 | {children} 31 | 32 | ); 33 | }; 34 | 35 | class Menu extends React.Component { 36 | state = { visible: false }; 37 | render() { 38 | const { selected, children } = this.props; 39 | 40 | const PopoverContent = ( 41 |
this.setState({ visible: false })}> 42 | {children} 43 |
44 | ); 45 | 46 | return ( 47 |
48 | { 52 | console.log('triggered'); 53 | this.setState({ visible: false }); 54 | }} 55 | > 56 | 59 | 60 | {children} 61 |
62 | ); 63 | } 64 | } 65 | 66 | class Example extends React.Component { 67 | state = { value: 1 }; 68 | 69 | render() { 70 | const { value } = this.state; 71 | const options = [1, 2]; 72 | 73 | return ( 74 | 75 | {options.map(option => { 76 | const isActive = option === value; 77 | console.log(`Rendering ${option}, isActive: ${isActive}`); 78 | return ( 79 |
this.setState({ value: option })}> 80 | {option} – {isActive ? "Active" : "Not Active"} 81 |
82 | ); 83 | })} 84 |
85 | ); 86 | } 87 | } 88 | 89 | 90 | const NormalHeader = () => ( 91 |

Normal component

92 | ); 93 | 94 | const Header = () => ( 95 |

Component with tooltip

96 | ); 97 | 98 | const HeaderWithTootip = withTooltip(Header, { 99 | title: 'Welcome to React with tooltip', 100 | }); 101 | 102 | const mapStateToProps = (state) => ({ 103 | content: contentSelector(state), 104 | }); 105 | 106 | class TooltipContentComponent extends Component { 107 | componentWillMount() { 108 | console.log('mount now'); 109 | } 110 | componentWillUnmount() { 111 | console.log('unmount now'); 112 | } 113 | 114 | render() { 115 | return ( 116 |
117 | TooltipContent here {this.props.content} 118 |
119 | ); 120 | } 121 | }; 122 | 123 | const TooltipContent = connect(mapStateToProps)(TooltipContentComponent); 124 | 125 | class App extends Component { 126 | render() { 127 | const { 128 | tooltipContent, 129 | setTooltipContent, 130 | disabled, 131 | setDisabled, 132 | open, 133 | setIsOpen, 134 | } = this.props; 135 | return ( 136 |
137 |
{setDisabled(!disabled)}}> 138 | logo 139 |
140 | 141 |
142 | 143 |
144 | 151 |

152 | Hover here to show popup 153 |

154 |
155 |
156 | 161 | Raw html 162 | 163 |
164 | 171 |

176 | Sticky 177 |

178 |
179 | 182 |
183 | {console.log('call'); setIsOpen(false)}} 188 | > 189 | { console.log('call open'); setIsOpen(true) }}> 190 | Big Tooltip with dynamic content: {tooltipContent} {open.toString()} {disabled.toString()} 191 | 192 | 193 |
194 | 195 | {!disabled && ( 196 | 202 | )} 203 | > 204 | Click here 205 | 206 | )} 207 | 208 |
209 | ( 216 |
217 |

{tooltipContent}

218 | {setTooltipContent(e.target.value)}} 222 | /> 223 |
224 | )} 225 | > 226 | 227 | Interactive tooltip 228 | 229 |
230 | 231 | 232 |
233 | ); 234 | } 235 | } 236 | 237 | const enhance = compose( 238 | withState('tooltipContent', 'setTooltipContent', 'tooltipContent'), 239 | withState('open', 'setIsOpen', false), 240 | withState('disabled', 'setDisabled', false), 241 | ); 242 | 243 | export default enhance(App); 244 | -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | }); 9 | -------------------------------------------------------------------------------- /src/Tooltip/component.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import tippy from 'tippy.js/dist/tippy.standalone.js'; 4 | 5 | const defaultProps = { 6 | title: null, 7 | open: false, 8 | disabled: false 9 | }; 10 | 11 | 12 | function applyIfFunction( fn ) { 13 | return (typeof fn === 'function') ? fn() : fn; 14 | } 15 | 16 | 17 | class Tooltip extends Component { 18 | 19 | componentDidMount() { 20 | this.initTippy(); 21 | } 22 | 23 | componentWillUnmount() { 24 | this.destroyTippy(); 25 | } 26 | 27 | componentDidUpdate(prevProps) { 28 | if ( !this.tippy ) 29 | return; 30 | 31 | // enable and disabled 32 | if (this.props.disabled === false && prevProps.disabled === true) { 33 | this.tippy.enable(); 34 | return; 35 | } 36 | 37 | if (this.props.disabled === true && prevProps.disabled === false) { 38 | this.tippy.disable(); 39 | return; 40 | } 41 | 42 | // open 43 | if (this.props.open === true && !prevProps.open) { 44 | setTimeout(() => { 45 | this.showTooltip(); 46 | }, 0) 47 | } 48 | 49 | if (this.props.open === false && prevProps.open === true) { 50 | this.hideTooltip(); 51 | } 52 | } 53 | 54 | showTooltip = () => { 55 | this.tippy.show(); 56 | } 57 | 58 | hideTooltip = () => { 59 | this.tippy.hide(); 60 | } 61 | 62 | contentRoot = () => { 63 | if ( !this._contentRoot && typeof window === 'object' ) 64 | this._contentRoot = window.document.createElement( 'div' ); 65 | return this._contentRoot; 66 | } 67 | 68 | initTippy = () => { 69 | this.tooltipDOM.setAttribute('title', this.props.title); 70 | tippy(this.tooltipDOM, { 71 | ...this.props, 72 | html: this.props.render ? this.contentRoot() : this.props.rawTemplate, 73 | dynamicTitle: true, 74 | performance: true 75 | }); 76 | this.tippy = this.tooltipDOM._tippy; 77 | if (this.props.open) { 78 | this.showTooltip(); 79 | } 80 | } 81 | 82 | destroyTippy = () => { 83 | this.tippy.destroy(); 84 | this.tippy = null; 85 | } 86 | 87 | 88 | render() { 89 | return ( 90 |
{ this.tooltipDOM = tooltip; }} 92 | title={this.props.title} 93 | className={this.props.className} 94 | tabIndex={this.props.tabIndex} 95 | style={{ 96 | display: 'inline', 97 | ...this.props.style 98 | }} 99 | > 100 | {this.props.children} 101 | {this.props.render && this.contentRoot() 102 | ? ReactDOM.createPortal( 103 | applyIfFunction( this.props.render ), 104 | this.contentRoot() ) 105 | : null} 106 |
107 | ); 108 | } 109 | } 110 | 111 | 112 | Tooltip.defaultProps = defaultProps; 113 | 114 | export default Tooltip; 115 | -------------------------------------------------------------------------------- /src/Tooltip/hoc.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Tooltip from './component'; 3 | 4 | const withTooltip = (Component, options = {}) => ({ 5 | ...props, 6 | }) => ( 7 | 8 | 9 | 10 | ); 11 | 12 | export default withTooltip; 13 | -------------------------------------------------------------------------------- /src/Tooltip/index.js: -------------------------------------------------------------------------------- 1 | import Tooltip from './component'; 2 | import withTooltip from './hoc'; 3 | 4 | export { 5 | Tooltip, 6 | withTooltip, 7 | } 8 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | import './index.css'; 5 | import 'tippy.js/dist/tippy.css'; 6 | 7 | import { Provider } from 'react-redux'; 8 | import store from './state/createStore'; 9 | 10 | ReactDOM.render( 11 | 12 | 13 | , 14 | document.getElementById('root') 15 | ); 16 | -------------------------------------------------------------------------------- /src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/state.js: -------------------------------------------------------------------------------- 1 | import makeStateAction from 'redux-state-action'; 2 | 3 | const reducerPath = 'eh/app'; 4 | 5 | const names = { 6 | content: { 7 | type: 'string', 8 | defaultValue: 'Content', 9 | }, 10 | }; 11 | 12 | export const { 13 | branch, 14 | actionCreatorFactory, 15 | selectorFactory, 16 | } = makeStateAction({ 17 | reducerPath, 18 | names, 19 | }); 20 | 21 | export const contentSelector = selectorFactory('content'); 22 | -------------------------------------------------------------------------------- /src/state/createStore.js: -------------------------------------------------------------------------------- 1 | import { createStore as createReduxStore, applyMiddleware, compose } from 'redux'; 2 | import thunk from 'redux-thunk'; 3 | import { rootReducer } from './rootReducer'; 4 | 5 | const enhancers = [ 6 | applyMiddleware( 7 | thunk, 8 | ), 9 | // Redux Dev Tools store enhancer. 10 | // @see https://github.com/zalmoxisus/redux-devtools-extension 11 | // We only want this enhancer enabled for development and when in a browser 12 | // with the extension installed. 13 | typeof window !== 'undefined' 14 | && typeof window.devToolsExtension !== 'undefined' 15 | // Call the brower extension function to create the enhancer. 16 | ? window.devToolsExtension() 17 | // Else we return a no-op function. 18 | : f => f, 19 | ]; 20 | 21 | export const configureStore = (initialState) => { 22 | const store = initialState 23 | ? createReduxStore(rootReducer, initialState, compose(...enhancers)) 24 | : createReduxStore(rootReducer, compose(...enhancers)); 25 | 26 | // Enable Webpack hot module replacement for reducers. This is so that we 27 | // don't lose all of our current application state during hot reloading. 28 | 29 | if (process.env.NODE_ENV === 'development' && module.hot) { 30 | module.hot.accept('./rootReducer', () => { 31 | // eslint-disable-next-line global-require, import/newline-after-import 32 | const nextReducer = require('./rootReducer').rootReducer; 33 | store.replaceReducer(nextReducer); 34 | }); 35 | } 36 | 37 | return store; 38 | }; 39 | 40 | const store = configureStore(); 41 | 42 | export default store; 43 | -------------------------------------------------------------------------------- /src/state/rootReducer.js: -------------------------------------------------------------------------------- 1 | import { branch as appBranch } from '../state'; 2 | import { 3 | combineReducers, 4 | } from 'redux'; 5 | 6 | export const rootReducer = combineReducers({ 7 | ...appBranch, 8 | }); 9 | 10 | export default rootReducer; 11 | -------------------------------------------------------------------------------- /webpacklib.config.js: -------------------------------------------------------------------------------- 1 | /* global __dirname, require, module */ 2 | 3 | const webpack = require('webpack'); 4 | const path = require('path'); 5 | const env = require('yargs').argv.env; // use --env with webpack 2 6 | 7 | const libraryName = 'reactTippy'; 8 | const outputFile = 'react-tippy.js'; 9 | const plugins = []; 10 | 11 | if (env === 'build') { 12 | // plugins.push(new UglifyJsPlugin({ minimize: true })); 13 | // plugins.push(new LodashModuleReplacementPlugin({ 14 | // collections: true, 15 | // paths: true, 16 | // })); 17 | } 18 | 19 | const config = { 20 | entry: __dirname + '/src/Tooltip/index.js', 21 | devtool: 'source-map', 22 | output: { 23 | path: __dirname + '/dist', 24 | filename: outputFile, 25 | library: libraryName, 26 | libraryTarget: 'umd', 27 | umdNamedDefine: true, 28 | }, 29 | module: { 30 | rules: [ 31 | { 32 | test: /(\.jsx|\.js)$/, 33 | loader: 'babel-loader', 34 | options: { 35 | presets: ['es2015', 'react'], 36 | plugins: ['transform-object-rest-spread', 'transform-class-properties'] 37 | }, 38 | exclude: /(node_modules|bower_components)/, 39 | }, 40 | ], 41 | }, 42 | resolve: { 43 | modules: [ 44 | path.resolve('./node_modules'), 45 | ], 46 | extensions: ['.json', '.js'], 47 | }, 48 | externals: { 49 | react: { 50 | root: 'React', 51 | commonjs2: 'react', 52 | commonjs: 'react', 53 | amd: 'react', 54 | umd: 'react', 55 | }, 56 | 'react-dom': { 57 | root: 'ReactDOM', 58 | commonjs2: 'react-dom', 59 | commonjs: 'react-dom', 60 | amd: 'react-dom', 61 | umd: 'react-dom', 62 | }, 63 | 'popper.js': { 64 | root: 'Popper', 65 | commonjs2: 'popper.js', 66 | commonjs: 'popper.js', 67 | amd: 'popper.js', 68 | umd: 'popper.js', 69 | }, 70 | 'tippy.js/dist/tippy.standalone.js': { 71 | root: 'tippy', 72 | commonjs2: 'tippy.js/dist/tippy.standalone.js', 73 | commonjs: 'tippy.js/dist/tippy.standalone.js', 74 | amd: 'tippy.js/dist/tippy.standalone.js', 75 | umd: 'tippy.js/dist/tippy.standalone.js', 76 | } 77 | }, 78 | plugins: plugins, 79 | }; 80 | 81 | module.exports = config; 82 | --------------------------------------------------------------------------------