From 2caf9a63d6ac56c6a9fa197baee5f5a245ac0290 Mon Sep 17 00:00:00 2001 From: Arkadiusz Zalewski Date: Sun, 8 Oct 2017 20:20:03 +0200 Subject: [PATCH 1/2] Added handleScroll method. --- src/ResizeDetector.jsx | 155 ++++++++++++++++++++++++++--------------- 1 file changed, 98 insertions(+), 57 deletions(-) diff --git a/src/ResizeDetector.jsx b/src/ResizeDetector.jsx index 7c14ffb..20df93d 100644 --- a/src/ResizeDetector.jsx +++ b/src/ResizeDetector.jsx @@ -1,58 +1,99 @@ -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 ( - - ); - } +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.scrollState = { + atTop: true, + atBottom: true, + atLeft: true, + atRight: true, + } + this.setDOMElement = this.setDOMElement.bind(this) + this.checkOverflow = this.checkOverflow.bind(this) + this.handleScroll = this.handleScroll.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.clientHeight + + if (isOverflowed !== this.isOverflowed) { + this.isOverflowed = isOverflowed + if (this.props.onOverflowChange) { + this.props.onOverflowChange(isOverflowed) + } + if (!isOverflowed) { + this.handleScroll() + } + } + } + + handleScroll() { + const { + clientHeight, + clientWidth, + scrollTop, + scrollLeft, + scrollHeight, + scrollWidth, + } = this.domElement + const atTop = scrollTop === 0 + const atBottom = scrollTop + clientHeight === scrollHeight + const atLeft = scrollLeft === 0 + const atRight = scrollLeft + clientWidth === scrollWidth + const s = this.scrollState + if ( + s.atTop !== atTop || + s.atBottom !== atBottom || + s.atLeft !== atLeft || + s.atRight !== atRight + ) { + const scrollState = {atTop, atBottom, atLeft, atRight} + this.scrollState = scrollState + this.props.onScrolled(scrollState) + } + } + + render() { + const {style, className, children, onScrolled} = this.props + return ( +
+ {children} + +
+ ) + } } From d22444f33184a404945cdcaffa8234099e3088fa Mon Sep 17 00:00:00 2001 From: Wout Mertens Date: Fri, 13 Oct 2017 10:09:27 +0200 Subject: [PATCH 2/2] onScrolled: move to correct component, document --- README.md | 28 ++++++- src/OverflowDetector.jsx | 41 ++++++++++- src/ResizeDetector.jsx | 155 ++++++++++++++------------------------- 3 files changed, 124 insertions(+), 100 deletions(-) diff --git a/README.md b/README.md index f11bc74..d373090 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # react-overflow -A React component that detects when it's overflowed by its content. +A React component that detects when it's overflowed by its content. It can also tell you if you are at the edge of the scroll area. ## Installation @@ -12,6 +12,8 @@ npm install --save react-overflow ## Usage +Using the `onOverFlowChange` callback: + ```jsx import { OverflowDetector } from 'react-overflow'; @@ -27,6 +29,30 @@ function handleOverflowChange(isOverflowed) { ``` +Using the `onScrolled` callback: + +```jsx +import { OverflowDetector } from 'react-overflow'; + +class TextWithArrows extends React.Component { + state = { atTop: true, atBottom: true, atLeft: true, atRight: true }; + handleScrolled = pos => this.setState(pos); + render() { + const { text } = this.props; + const { atTop, atBottom, atLeft, atRight } = this.state; + return ( + + + {!atTop && } + {text} + {!atBottom && } + + + ); + } +} +``` + ## License [MIT](https://github.com/nickuraltsev/react-overflow/blob/master/LICENSE) diff --git a/src/OverflowDetector.jsx b/src/OverflowDetector.jsx index c18ed33..82148f5 100644 --- a/src/OverflowDetector.jsx +++ b/src/OverflowDetector.jsx @@ -17,8 +17,15 @@ export default class OverflowDetector extends Component { super(props); this.isOverflowed = false; this.domElement = null; + this.scrollState = { + atTop: true, + atBottom: true, + atLeft: true, + atRight: true, + }; this.setDOMElement = this.setDOMElement.bind(this); this.checkOverflow = this.checkOverflow.bind(this); + this.handleScroll = this.handleScroll.bind(this); } componentDidMount() { @@ -43,16 +50,48 @@ export default class OverflowDetector extends Component { if (this.props.onOverflowChange) { this.props.onOverflowChange(isOverflowed); } + if (!isOverflowed) { + this.handleScroll(); + } + } + } + + handleScroll() { + const { + clientHeight, + clientWidth, + scrollTop, + scrollLeft, + scrollHeight, + scrollWidth, + } = this.domElement; + const atTop = scrollTop === 0; + const atBottom = scrollTop + clientHeight === scrollHeight; + const atLeft = scrollLeft === 0; + const atRight = scrollLeft + clientWidth === scrollWidth; + const s = this.scrollState; + if ( + s.atTop !== atTop || + s.atBottom !== atBottom || + s.atLeft !== atLeft || + s.atRight !== atRight + ) { + const scrollState = { atTop, atBottom, atLeft, atRight }; + this.scrollState = scrollState; + this.props.onScrolled(scrollState); } } render() { - const { style, className, children } = this.props; + const { style, className, children, onScrolled } = this.props; + const onScroll = + this.isOverflowed && onScrolled ? this.handleScroll : undefined; return (
{children} diff --git a/src/ResizeDetector.jsx b/src/ResizeDetector.jsx index 20df93d..7c14ffb 100644 --- a/src/ResizeDetector.jsx +++ b/src/ResizeDetector.jsx @@ -1,99 +1,58 @@ -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.scrollState = { - atTop: true, - atBottom: true, - atLeft: true, - atRight: true, - } - this.setDOMElement = this.setDOMElement.bind(this) - this.checkOverflow = this.checkOverflow.bind(this) - this.handleScroll = this.handleScroll.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.clientHeight - - if (isOverflowed !== this.isOverflowed) { - this.isOverflowed = isOverflowed - if (this.props.onOverflowChange) { - this.props.onOverflowChange(isOverflowed) - } - if (!isOverflowed) { - this.handleScroll() - } - } - } - - handleScroll() { - const { - clientHeight, - clientWidth, - scrollTop, - scrollLeft, - scrollHeight, - scrollWidth, - } = this.domElement - const atTop = scrollTop === 0 - const atBottom = scrollTop + clientHeight === scrollHeight - const atLeft = scrollLeft === 0 - const atRight = scrollLeft + clientWidth === scrollWidth - const s = this.scrollState - if ( - s.atTop !== atTop || - s.atBottom !== atBottom || - s.atLeft !== atLeft || - s.atRight !== atRight - ) { - const scrollState = {atTop, atBottom, atLeft, atRight} - this.scrollState = scrollState - this.props.onScrolled(scrollState) - } - } - - render() { - const {style, className, children, onScrolled} = this.props - return ( -
- {children} - -
- ) - } +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 ( + + ); + } }