diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..0e3e3f8 --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["es2015", "stage-1", "react"] +} diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..2235935 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,9 @@ +{ + "extends": "airbnb", + "parser": "babel-eslint", + "rules": { + "react/forbid-prop-types": "off", + "react/require-default-props": "off", + "react/no-did-mount-set-state": "off" + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..17e6e32 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +lib/ +node_modules/ +playground/ +npm-debug.log +.DS_Store diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..5a61604 --- /dev/null +++ b/.npmignore @@ -0,0 +1,5 @@ +src/ +node_modules/ +playground/ +npm-debug.log +**/.* diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6fe9931 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017-present Nick Uraltsev + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..f11bc74 --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +# react-overflow + +A React component that detects when it's overflowed by its content. + +## Installation + +Install `react-overflow` using [npm](https://www.npmjs.org/): + +``` +npm install --save react-overflow +``` + +## Usage + +```jsx +import { OverflowDetector } from 'react-overflow'; + +function handleOverflowChange(isOverflowed) { + console.log(isOverflowed); +} + + +
Overflowing
+
+``` + +## License + +[MIT](https://github.com/nickuraltsev/react-overflow/blob/master/LICENSE) diff --git a/package.json b/package.json new file mode 100644 index 0000000..ac9de7c --- /dev/null +++ b/package.json @@ -0,0 +1,45 @@ +{ + "name": "react-overflow", + "version": "0.1.0", + "description": "A React component that detects when it's overflowed by its content", + "keywords": [ + "react", + "overflow" + ], + "author": { + "name": "Nick Uraltsev", + "email": "nick.uraltsev@gmail.com" + }, + "repository": { + "type": "git", + "url": "https://github.com/nickuraltsev/react-overflow.git" + }, + "bugs": { + "url": "https://github.com/nickuraltsev/react-overflow/issues" + }, + "license": "MIT", + "main": "lib/index.js", + "devDependencies": { + "babel-cli": "^6.24.0", + "babel-core": "^6.24.0", + "babel-preset-es2015": "^6.24.0", + "babel-preset-stage-1": "^6.22.0", + "babel-preset-react": "^6.24.1", + "eslint": "^3.18.0", + "eslint-config-airbnb": "^14.1.0", + "eslint-plugin-import": "^2.2.0", + "eslint-plugin-react": "^6.10.3", + "eslint-plugin-jsx-a11y": "^4.0.0", + "babel-eslint": "^7.2.1", + "rimraf": "^2.6.1" + }, + "peerDependencies": { + "react": "^15.0.0", + "react-dom": "^15.0.0" + }, + "scripts": { + "clean": "rimraf lib", + "build": "npm run clean && babel src --out-dir lib", + "lint": "eslint src --ext .js,.jsx" + } +} diff --git a/src/OverflowDetector.jsx b/src/OverflowDetector.jsx new file mode 100644 index 0000000..e6cc662 --- /dev/null +++ b/src/OverflowDetector.jsx @@ -0,0 +1,62 @@ +import React, { Component, PropTypes } from 'react'; +import ResizeDetector from './ResizeDetector'; + +export default class OverflowDetector extends Component { + static propTypes = { + onOverflowChange: PropTypes.func, + children: PropTypes.node, + style: PropTypes.object, + className: PropTypes.string, + }; + + static defaultProps = { + style: {}, + }; + + constructor(props) { + super(props); + this.isOverflowed = false; + this.domElement = null; + this.setDOMElement = this.setDOMElement.bind(this); + this.checkOverflow = this.checkOverflow.bind(this); + } + + componentDidMount() { + this.checkOverflow(); + } + + componentDidUpdate() { + this.checkOverflow(); + } + + setDOMElement(domElement) { + this.domElement = domElement; + } + + checkOverflow() { + const isOverflowed = + this.domElement.scrollWidth > this.domElement.clientWidth || + this.domElement.scrollHeight > this.domElement.scrollHeight; + + if (isOverflowed !== this.isOverflowed) { + this.isOverflowed = isOverflowed; + if (this.props.onOverflowChange) { + this.props.onOverflowChange(isOverflowed); + } + } + } + + render() { + const { style, className, children } = this.props; + return ( +
+ {children} + +
+ ); + } +} diff --git a/src/ResizeDetector.jsx b/src/ResizeDetector.jsx new file mode 100644 index 0000000..7c14ffb --- /dev/null +++ b/src/ResizeDetector.jsx @@ -0,0 +1,58 @@ +import React, { Component, PropTypes } from 'react'; + +const OBJECT_STYLE = { + display: 'block', + position: 'absolute', + top: 0, + left: 0, + height: '100%', + width: '100%', + overflow: 'hidden', + pointerEvents: 'none', + zIndex: -1, +}; + +export default class ResizeDetector extends Component { + static propTypes = { + onResize: PropTypes.func.isRequired, + }; + + constructor(props) { + super(props); + this.state = { + isMounted: false, + }; + this.setDOMElement = this.setDOMElement.bind(this); + this.handleLoad = this.handleLoad.bind(this); + } + + componentDidMount() { + this.setState({ + isMounted: true, + }); + } + + componentWillUnmount() { + this.domElement.contentDocument.defaultView.removeEventListener('resize', this.props.onResize); + } + + setDOMElement(domElement) { + this.domElement = domElement; + } + + handleLoad() { + this.domElement.contentDocument.defaultView.addEventListener('resize', this.props.onResize); + } + + render() { + return ( + + ); + } +} diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..804b63e --- /dev/null +++ b/src/index.js @@ -0,0 +1 @@ +export OverflowDetector from './OverflowDetector';