├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .prettierrc ├── LICENSE ├── README.md ├── babel.config.js ├── package.json ├── rollup.config.js ├── src └── index.js ├── styles.css ├── website ├── .gitignore ├── .prettierrc ├── README.md ├── gatsby-browser.js ├── gatsby-config.js ├── gatsby-node.js ├── gatsby-ssr.js ├── package.json ├── src │ ├── components │ │ └── Layout.js │ ├── pages │ │ ├── 404.js │ │ └── index.js │ └── styles │ │ └── index.css └── yarn.lock └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | website 3 | node_modules 4 | yarn.lock 5 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["react-app", "plugin:prettier/recommended", "prettier"], 3 | "plugins": ["prettier"], 4 | "rules": { 5 | "react/prop-types": 2 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore annoying DS files 2 | .DS_Store 3 | *.DS_Store 4 | **.DS_Store 5 | 6 | # npm 7 | node_modules 8 | npm-debug.log 9 | npm-debug.log.* 10 | package-lock.json 11 | 12 | # yarn 13 | yarn-error.log 14 | yarn-debug.log* 15 | 16 | # builds 17 | dist 18 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "semi": false, 4 | "trailingComma": "es5", 5 | "printWidth": 80 6 | } 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Neo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-texty 2 | 3 | A straight forward text component with tooltip support when it's truncated 4 | 5 | ## Install 6 | 7 | ```bash 8 | # Yarn 9 | yarn add react-texty 10 | 11 | # NPM 12 | npm install --save react-texty 13 | ``` 14 | 15 | ## Props 16 | 17 | - **tagName** `string` Tag name for the component, defaults to `div` 18 | - **children** `node`, Should be string or inline element 19 | - **tooltip** `node` Tooltip for the truncated text if set, or the children will be used 20 | - **tooltipClassName** `string` Classname for the tooltip 21 | - **tooltipStyle** `object` Custom style of the tooltip 22 | - **tooltipMaxWidth** `number` Max width of the tooltip 23 | - **showDelay** `number` Delay milliseconds to show when mouse enter, defaults to `150` 24 | - **hideDelay** `number` Delay milliseconds to hide when mouse leave, defaults to `150` 25 | - **arrowClassName** `string` Classname for the arrow 26 | - **hideArrow** `bool` Whether to show the tooltip arrow, defaults to `false` 27 | - **placement** `top|top-start|top-end|bottom|bottom-start|bottom-end` The placement of the tooltip, defaults to `top` 28 | 29 | Learn more at https://nihgwu.github.io/react-texty/ 30 | 31 | ## Usage 32 | 33 | ```jsx 34 | import Text from 'react-texty' 35 | // import the styles 36 | import 'react-texty/styles.css' 37 | 38 | // just use it as a normal text node 39 | Hello world 40 | Hello world 41 | Hello world 42 | ``` 43 | 44 | ## License 45 | 46 | MIT © [Neo Nie](https://github.com/nihgwu) 47 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | [ 4 | '@babel/preset-env', 5 | { 6 | modules: false, 7 | loose: true, 8 | }, 9 | ], 10 | '@babel/preset-react', 11 | ], 12 | plugins: ['@babel/plugin-proposal-class-properties'], 13 | } 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-texty", 3 | "version": "0.6.0", 4 | "description": "A straight forward text component with tooltip support when it's truncated", 5 | "homepage": "https://nihgwu.github.io/react-texty/", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/nihgwu/react-texty.git" 9 | }, 10 | "author": "Neo Nie ", 11 | "license": "MIT", 12 | "keywords": [ 13 | "react", 14 | "component", 15 | "text", 16 | "ellipsis", 17 | "tooltip" 18 | ], 19 | "main": "dist/index.cjs.js", 20 | "module": "dist/index.esm.js", 21 | "files": [ 22 | "dist", 23 | "styles.css" 24 | ], 25 | "scripts": { 26 | "start": "cd website && npm start", 27 | "deploy": "cd website && npm run deploy", 28 | "lint": "eslint ./src/**/*.js", 29 | "prettier": "prettier --write '**/src/**/*.{js,css}'", 30 | "clean": "rimraf dist", 31 | "build": "rollup -c", 32 | "prebuild": "npm run clean", 33 | "precommit": "lint-staged", 34 | "prepublish": "npm run build" 35 | }, 36 | "dependencies": { 37 | "react-popper": "^1.3.3" 38 | }, 39 | "peerDependencies": { 40 | "prop-types": "^15.5.7", 41 | "react": "^16.0.0", 42 | "react-dom": "^16.0.0" 43 | }, 44 | "husky": { 45 | "hooks": { 46 | "pre-commit": "lint-staged" 47 | } 48 | }, 49 | "lint-staged": { 50 | "**/*.js": [ 51 | "prettier --write", 52 | "eslint", 53 | "git add" 54 | ] 55 | }, 56 | "devDependencies": { 57 | "@babel/core": "^7.4.5", 58 | "@babel/plugin-proposal-class-properties": "^7.4.4", 59 | "@babel/preset-env": "^7.4.5", 60 | "@babel/preset-react": "^7.0.0", 61 | "babel-core": "^7.0.0-bridge.0", 62 | "babel-eslint": "^10.0.1", 63 | "babel-jest": "^24.8.0", 64 | "cross-env": "^5.2.0", 65 | "eslint": "^5.16.0", 66 | "eslint-config-prettier": "^4.3.0", 67 | "eslint-config-react-app": "^4.0.1", 68 | "eslint-plugin-flowtype": "^3.9.1", 69 | "eslint-plugin-import": "^2.17.3", 70 | "eslint-plugin-jsx-a11y": "^6.1.1", 71 | "eslint-plugin-prettier": "^3.1.0", 72 | "eslint-plugin-react": "^7.13.0", 73 | "eslint-plugin-react-hooks": "^1.6.0", 74 | "husky": "^2.4.0", 75 | "jest": "^24.8.0", 76 | "lerna": "^3.14.1", 77 | "lint-staged": "^8.1.7", 78 | "npm-run-all": "^4.1.5", 79 | "prettier": "^1.17.1", 80 | "prop-types": "^15.7.2", 81 | "react": "^16.8.6", 82 | "react-dom": "^16.8.6", 83 | "rimraf": "^2.6.2", 84 | "rollup": "^1.14.1", 85 | "rollup-plugin-babel": "^4.0.3", 86 | "rollup-plugin-commonjs": "^10.0.0", 87 | "rollup-plugin-copy": "^3.0.0", 88 | "rollup-plugin-node-resolve": "^5.0.1", 89 | "rollup-plugin-peer-deps-external": "^2.2.0" 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel' 2 | import commonjs from 'rollup-plugin-commonjs' 3 | import external from 'rollup-plugin-peer-deps-external' 4 | import resolve from 'rollup-plugin-node-resolve' 5 | import copy from 'rollup-plugin-copy' 6 | 7 | import pkg from './package.json' 8 | 9 | export default { 10 | input: 'src/index.js', 11 | output: [ 12 | { 13 | file: pkg.main, 14 | format: 'cjs', 15 | }, 16 | { 17 | file: pkg.module, 18 | format: 'esm', 19 | }, 20 | ], 21 | plugins: [ 22 | external({ 23 | includeDependencies: true, 24 | }), 25 | babel({ 26 | exclude: 'node_modules/**', 27 | }), 28 | resolve(), 29 | commonjs(), 30 | copy({ 31 | targets: [{ src: '../../README.md', dest: './' }], 32 | }), 33 | ], 34 | } 35 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDom from 'react-dom' 3 | import PropTypes from 'prop-types' 4 | import { Popper } from 'react-popper' 5 | 6 | const modifiers = { 7 | preventOverflow: { 8 | boundariesElement: 'viewport', 9 | padding: 10, 10 | }, 11 | } 12 | 13 | /** 14 | * Text component with tooltip support powered by Popper 15 | */ 16 | class Texty extends React.Component { 17 | state = { 18 | isHovered: false, 19 | } 20 | 21 | componentDidUpdate() { 22 | if (this.state.isHovered) { 23 | window.addEventListener('scroll', this.handleScroll, true) 24 | // react-virtualized-auto-sizer would trigger scroll events after tooltip shown in some case, we have to skip those scroll events 25 | this.listenTimer = setTimeout(() => { 26 | window.addEventListener('scroll', this.handleScroll, true) 27 | delete this.listenTimer 28 | }, 50) 29 | } else { 30 | this._clearListenTimer() 31 | window.removeEventListener('scroll', this.handleScroll, true) 32 | } 33 | } 34 | 35 | componentWillUnmount() { 36 | this._clearListenTimer() 37 | window.removeEventListener('scroll', this.handleScroll, true) 38 | this._clearShowTimer() 39 | this._clearHideTimer() 40 | } 41 | 42 | render() { 43 | /* eslint-disable no-unused-vars */ 44 | const { 45 | tagName: Tag, 46 | children, 47 | placement, 48 | // omit the following from rest 49 | innerRef, 50 | showDelay, 51 | hideDelay, 52 | tooltip, 53 | tooltipClassName, 54 | tooltipStyle, 55 | tooltipMaxWidth, 56 | hideArrow, 57 | container, 58 | ...rest 59 | } = this.props 60 | /* eslint-enable no-unused-vars */ 61 | 62 | if (!children) { 63 | return 64 | } 65 | 66 | const target = this.targetNode 67 | const isTruncated = !!target && target.scrollWidth > target.offsetWidth 68 | const showTooltip = this.state.isHovered && isTruncated 69 | return ( 70 | 77 | {children} 78 | {showTooltip && ( 79 | 84 | {this.renderTooltip} 85 | 86 | )} 87 | 88 | ) 89 | } 90 | 91 | renderTooltip = ({ ref, style, placement, arrowProps }) => { 92 | const { 93 | children, 94 | container, 95 | tooltip, 96 | tooltipClassName, 97 | tooltipStyle, 98 | tooltipMaxWidth, 99 | arrowClassName, 100 | hideArrow, 101 | } = this.props 102 | 103 | const content = tooltip || children 104 | const extraStyle = tooltipMaxWidth 105 | ? { ...tooltipStyle, maxWidth: tooltipMaxWidth } 106 | : tooltipStyle 107 | return ReactDom.createPortal( 108 |
119 | {content} 120 | {!hideArrow && ( 121 |
127 | )} 128 |
, 129 | container || this.targetNode.ownerDocument.body 130 | ) 131 | } 132 | 133 | setTargetRef = ref => { 134 | this.props.innerRef && this.props.innerRef(ref) 135 | this.targetNode = ref 136 | } 137 | 138 | handleMouseEvent = e => { 139 | e.stopPropagation() 140 | } 141 | 142 | handleScroll = e => { 143 | this.setState({ isHovered: false }) 144 | } 145 | 146 | _clearListenTimer() { 147 | if (this.listenTimer) { 148 | clearTimeout(this.listenTimer) 149 | delete this.listenTimer 150 | } 151 | } 152 | 153 | _clearShowTimer() { 154 | if (this.showTimer) { 155 | clearTimeout(this.showTimer) 156 | delete this.showTimer 157 | } 158 | } 159 | 160 | _clearHideTimer() { 161 | if (this.hideTimer) { 162 | clearTimeout(this.hideTimer) 163 | delete this.hideTimer 164 | } 165 | } 166 | 167 | handleMouseEnter = e => { 168 | // eslint-disable-next-line react/prop-types 169 | const { showDelay, onMouseEnter } = this.props 170 | onMouseEnter && onMouseEnter(e) 171 | 172 | this._clearHideTimer() 173 | 174 | if (!showDelay) { 175 | this.setState({ isHovered: true }) 176 | return 177 | } 178 | 179 | this.showTimer = setTimeout(() => { 180 | this.setState({ isHovered: true }) 181 | delete this.showTimer 182 | }, showDelay) 183 | } 184 | 185 | handleMouseLeave = e => { 186 | // eslint-disable-next-line react/prop-types 187 | const { hideDelay, onMouseLeave } = this.props 188 | onMouseLeave && onMouseLeave(e) 189 | 190 | this._clearShowTimer() 191 | 192 | const { isHovered } = this.state 193 | if (!isHovered) return 194 | 195 | if (!hideDelay) { 196 | this.setState({ isHovered: false }) 197 | return 198 | } 199 | 200 | this.hideTimer = setTimeout(() => { 201 | this.setState({ isHovered: false }) 202 | delete this.hideTimer 203 | }, hideDelay) 204 | } 205 | } 206 | 207 | Texty.defaultProps = { 208 | tagName: 'div', 209 | showDelay: 150, 210 | hideDelay: 150, 211 | hideArrow: false, 212 | placement: 'top', 213 | } 214 | 215 | Texty.propTypes = { 216 | /** 217 | * Get inner ref of the component 218 | */ 219 | innerRef: PropTypes.func, 220 | /** 221 | * Tag name for the component 222 | */ 223 | tagName: PropTypes.string, 224 | /** 225 | * Should be string or inline element 226 | */ 227 | children: PropTypes.node, 228 | /** 229 | * Tooltip for the truncated text if set, or the children will be used 230 | */ 231 | tooltip: PropTypes.node, 232 | /** 233 | * Classname for the tooltip 234 | */ 235 | tooltipClassName: PropTypes.string, 236 | /** 237 | * Custom style of the tooltip 238 | */ 239 | tooltipStyle: PropTypes.object, 240 | /** 241 | * Max width of the tooltip 242 | */ 243 | tooltipMaxWidth: PropTypes.number, 244 | /** 245 | * Delay milliseconds to show when mouse enter 246 | */ 247 | showDelay: PropTypes.number, 248 | /** 249 | * Delay milliseconds to hide when mouse leave 250 | */ 251 | hideDelay: PropTypes.number, 252 | /** 253 | * Classname for the arrow 254 | */ 255 | arrowClassName: PropTypes.string, 256 | /** 257 | * Whether to show the tooltip arrow 258 | */ 259 | hideArrow: PropTypes.bool, 260 | /** 261 | * The placement of the tooltip 262 | */ 263 | placement: PropTypes.oneOf([ 264 | 'top', 265 | 'top-start', 266 | 'top-end', 267 | 'bottom', 268 | 'bottom-start', 269 | 'bottom-end', 270 | ]), 271 | /** 272 | * The HTML Element to append the tooltip **In most cases you don't need to set it manually** 273 | */ 274 | container: PropTypes.instanceOf( 275 | typeof Element !== 'undefined' ? Element : Object 276 | ), 277 | } 278 | 279 | export default Texty 280 | -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | [data-texty] { 2 | display: block; 3 | overflow: hidden; 4 | text-overflow: ellipsis; 5 | white-space: nowrap; 6 | } 7 | 8 | [data-texty-tooltip] { 9 | margin: 6px 0; 10 | padding: 4px 10px; 11 | border-radius: 4px; 12 | background-color: #222; 13 | color: #fff; 14 | z-index: 99999; 15 | } 16 | 17 | [data-texty-arrow] { 18 | position: absolute; 19 | bottom: -6px; 20 | width: 0; 21 | height: 0; 22 | border-style: solid; 23 | border-width: 6px 6px 0; 24 | border-color: #222 transparent transparent; 25 | } 26 | 27 | [data-texty-arrow*='bottom'] { 28 | top: -6px; 29 | bottom: inherit; 30 | transform: rotate(180deg); 31 | } 32 | 33 | /* disable the builtin tooltip for truncated text on Safari */ 34 | @media screen and (-webkit-min-device-pixel-ratio: 0) { 35 | @supports (not (-ms-ime-align: auto)) { 36 | .EllipsisText::before { 37 | content: ''; 38 | display: block; 39 | width: 0; 40 | height: 0; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /website/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # dotenv environment variables file 55 | .env 56 | 57 | # gatsby files 58 | .cache/ 59 | public 60 | 61 | # Mac files 62 | .DS_Store 63 | 64 | # Yarn 65 | yarn-error.log 66 | .pnp/ 67 | .pnp.js 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | -------------------------------------------------------------------------------- /website/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "semi": false, 4 | "trailingComma": "es5", 5 | "printWidth": 80 6 | } 7 | -------------------------------------------------------------------------------- /website/README.md: -------------------------------------------------------------------------------- 1 | [Website](https://nihgwu.github.io/react-texty/) for [react-texty](https://github.com/nihgwu/react-texty) 2 | -------------------------------------------------------------------------------- /website/gatsby-browser.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Implement Gatsby's Browser APIs in this file. 3 | * 4 | * See: https://www.gatsbyjs.org/docs/browser-apis/ 5 | */ 6 | 7 | // You can delete this file if you're not using it 8 | -------------------------------------------------------------------------------- /website/gatsby-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | pathPrefix: '/react-texty', 3 | siteMetadata: { 4 | title: 'Website for react-texty', 5 | }, 6 | plugins: [ 7 | { 8 | resolve: `gatsby-plugin-google-analytics`, 9 | options: { 10 | trackingId: 'UA-39825336-3', 11 | }, 12 | }, 13 | 'gatsby-plugin-react-helmet', 14 | 'gatsby-plugin-offline', 15 | ], 16 | } 17 | -------------------------------------------------------------------------------- /website/gatsby-node.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | exports.onCreateWebpackConfig = ({ actions }) => { 4 | actions.setWebpackConfig({ 5 | resolve: { 6 | alias: { 7 | 'react-texty/styles.css': path.resolve(__dirname, '../styles.css'), 8 | 'react-texty': path.resolve(__dirname, '../src'), 9 | react: path.resolve(__dirname, './node_modules/react'), 10 | 'react-dom': path.resolve(__dirname, './node_modules/react-dom'), 11 | }, 12 | }, 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /website/gatsby-ssr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Implement Gatsby's SSR (Server Side Rendering) APIs in this file. 3 | * 4 | * See: https://www.gatsbyjs.org/docs/ssr-apis/ 5 | */ 6 | 7 | // You can delete this file if you're not using it 8 | -------------------------------------------------------------------------------- /website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "website", 3 | "version": "0.0.0", 4 | "private": true, 5 | "author": "Neo Nie ", 6 | "homepage": "https://nihgwu.github.io/react-texty/", 7 | "scripts": { 8 | "start": "gatsby develop", 9 | "develop": "gatsby develop", 10 | "build": "gatsby build", 11 | "serve": "gatsby serve", 12 | "deploy": "rimraf .cache public && gatsby build --prefix-paths && gh-pages -d public", 13 | "prettier": "prettier --write 'src/**/*.{js,css}'", 14 | "test": "echo \"Error: no test specified\" && exit 1" 15 | }, 16 | "dependencies": { 17 | "gatsby": "^2.13.21", 18 | "gatsby-plugin-google-analytics": "^2.1.4", 19 | "gatsby-plugin-offline": "^2.2.4", 20 | "gatsby-plugin-react-helmet": "^3.1.2", 21 | "prop-types": "^15.7.2", 22 | "react": "^16.8.6", 23 | "react-dom": "^16.8.6", 24 | "react-github-corner": "^2.3.0", 25 | "react-helmet": "^5.2.1" 26 | }, 27 | "devDependencies": { 28 | "gh-pages": "^2.0.1", 29 | "prettier": "^1.18.2", 30 | "rimraf": "^2.6.3" 31 | }, 32 | "repository": { 33 | "type": "git", 34 | "url": "https://github.com/gatsbyjs/gatsby-starter-default" 35 | }, 36 | "bugs": { 37 | "url": "https://github.com/gatsbyjs/gatsby/issues" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /website/src/components/Layout.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Helmet from 'react-helmet' 3 | import GithubCorner from 'react-github-corner' 4 | 5 | import '../styles/index.css' 6 | 7 | const Layout = ({ children }) => ( 8 | <> 9 | ', 24 | }, 25 | ]} 26 | /> 27 | 32 |
{children}
33 | 34 | ) 35 | 36 | export default Layout 37 | -------------------------------------------------------------------------------- /website/src/pages/404.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import Layout from '../components/Layout' 4 | 5 | const NotFoundPage = () => ( 6 | 7 |

NOT FOUND

8 |

You just hit a route that doesn't exist... the sadness.

9 |
10 | ) 11 | 12 | export default NotFoundPage 13 | -------------------------------------------------------------------------------- /website/src/pages/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Text from 'react-texty' 3 | 4 | import Layout from '../components/Layout' 5 | 6 | const Page = () => ( 7 | 8 |

react-texty

9 | I'm not truncated so there is no tooltip. 10 | I'm too long to show, so there is tooltip for the full content. 11 | 12 | tagName="a": I'm too long to show, so there is tooltip for the full 13 | content. 14 | 15 | 16 | tooltip="react-texty": I'm too long to show, so there is tooltip for the 17 | full content. 18 | 19 | 20 | tooltipClassName: I'm too long to show, so there is tooltip for the 21 | full content. 22 | 23 | 24 | tooltipStyle={`{ color: 'red' }`}: I'm too long to show, so there is 25 | tooltip for the full content. 26 | 27 | 28 | tooltipMaxWidth=300: I'm too long to show, so there is 29 | tooltip for the full content. 30 | 31 | 32 | showDelay=1000: I'm too long to show, so there is tooltip for the 33 | full content. 34 | 35 | 36 | hideDelay=1000: I'm too long to show, so there is tooltip for the 37 | full content. 38 | 39 | 40 | hideArrow: I'm too long to show, so there is tooltip for the full 41 | content. 42 | 43 | 44 | placement="bottom": I'm too long to show, so there is tooltip for 45 | the full content. 46 | 47 | 48 | placement="bottom-start": I'm too long to show, so there is tooltip 49 | for the full content. 50 | 51 | 52 | placement="bottom-end": I'm too long to show, so there is tooltip 53 | for the full content. 54 | 55 |
56 | ) 57 | 58 | export default Page 59 | -------------------------------------------------------------------------------- /website/src/styles/index.css: -------------------------------------------------------------------------------- 1 | @import '~react-texty/styles.css'; 2 | 3 | * { 4 | box-sizing: border-box; 5 | } 6 | 7 | html { 8 | font-size: 62.5%; 9 | font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, 10 | Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, 11 | Noto Color Emoji; 12 | margin: 0; 13 | padding: 0; 14 | } 15 | 16 | body { 17 | -webkit-font-smoothing: antialiased; 18 | /* Currently ems cause chrome bug misinterpreting rems on body element */ 19 | font-size: 1.6em; 20 | line-height: 1.6; 21 | color: #222; 22 | font-weight: 400; 23 | padding: 10px; 24 | } 25 | 26 | .content { 27 | max-width: 400px; 28 | margin: 50px auto; 29 | } 30 | 31 | [data-texty] { 32 | margin: 10px 0; 33 | } 34 | 35 | .steelblue { 36 | background-color: steelblue; 37 | color: #fff; 38 | } 39 | 40 | .steelblue [data-texty-arrow] { 41 | border-color: steelblue transparent transparent; 42 | } 43 | --------------------------------------------------------------------------------