react-scrollwatcher
installation
npm install @grid23/react-scrollwatcher
usage
example 1
import React, {useRef} from "react"
import ScrollWatcher from "@grid23/react-scrollwatcher"
function SomeComponent({children}){
const watchedRef = useRef()
const onOffsetChange = (matrix) =>
console.dir(matrix)
return (
<ScrollWatcher watch={watchedRef} onOffsetChange={onOffsetChange}>
<div ref={watchedRef}>
{children}
</div>
</ScrollWatcher>
)
}
example 2
import React, {forwardRef, useContext, useRef} from "react"
import ScrollWatcher, {useScrollWatch} from "@grid23/react-scrollwatcher"
const WatchedComponent = forwardRef(({children}, ref) => {
const matrix = useScrollWatch()
console.log(matrix)
return (
<div ref={ref}>
{children}
</div>
)
})
function SomeComponent({children}){
const watchedRef = useRef()
return (
<ScrollWatcher watch={watchedRef}>
<WatchedComponent ref={watchedRef}>
{children}
</WatchedComponent>
</ScrollWatcher>
)
}
example 3
import React, {Component, createRef} from "react"
import ScrollWatcher from "@grid23/react-scrollwatcher"
class SomeComponent extends Component {
constructor(...args){
super(...args)
this.watchedRef = createRef()
}
onOffsetChange(matrix){
console.dir(matrix)
}
render(){
return (
<ScrollWatcher watch={this.watchedRef} onOffsetChange={this.onOffsetChange}>
<div ref={this.watchedRef}>
{this.props.children}
</div>
</ScrollWatcher>
)
}
}
example 4
import React, {Component, createRef} from "react"
import ScrollWatcher, {ScrollWatcherCTX} from "@grid23/react-scrollwatcher"
class SomeComponent extends Component {
constructor(...args){
super(...args)
this.watchedRef = createRef()
}
render(){
return (
<ScrollWatcher watch={this.watchedRef}>
<div ref={this.watchedRef}>
<SomeOtherComponent>
{this.props.children}
</SomeOtherComponent>
</div>
</ScrollWatcher>
)
}
}
class SomeOtherComponent extends Component{
static contextType = ScrollWatcherCTX
constructor(...args){
super(...args)
}
render(){
console.dir(this.context)
return (
<span>
{this.props.children}
</span>
)
}
}
watching a node inside another scrollable node
Only supports one level of nesting.
example 5
import React, {useRef} from "react"
import ScrollWatcher from "@grid23/react-scrollwatcher"
function SomeComponent({children}){
const scrollableRef = useRef()
const watchedRef = useRef()
const onOffsetChange = (matrix) =>
console.dir(matrix)
return (
<ScrollWatcher watch={watchedRef} inside={scrollableRef} onOffsetChange={onOffsetChange}>
<div ref={scrollableRef}>
<div ref={watchedRef}>
{children}
</div>
</div>
</ScrollWatcher>
)
}
scrollwatcher matrix
When the watched node is not visible, matrix is undefined, otherwise it is an object with the following properties:
coverage:Number [0-1] % of the node visible inside the viewport
coverageX:Number [0-1] % of the node visible in the viewport on the horizontal plane
coverageY:Number [0-1] % of the node visible in the viewport on the vertical plane
deltaX:Number the distance in pixels the node moved since the last matrix update on the horizontal plane
deltaY:Number the distance in pixels the node moved since the last matrix update on the vertical plane
dir:String dir setting
direction:bitmask direction(s) the node is moving relative to the scroll, in bitmask format ( see directions )
offsetX:Number distance in pixels from the left side of the viewport to the left side of node (negative: the left side of the node is outside the viewport)
offsetY:Number *distance in pixels from the top side of the viewport to the top of the node (negative: the top side of the node is outside the viewport) *
overflowX:Number distance in pixels from the right side of the viewport to the right side of the node (negative: the right side of the node is inside the viewport)
overflowY:Number distance in pixels from the bottom side of the viewport to the bottom side of the node (negative: the bottom side of the node is inside the viewport)
progressX:Number [0,1] by default, or with dir=ltr, % representing the distance travelled by the node towards the point when the right side of the node has reached the left side of the viewport; with dir=rtl, % representing the distance travelled by the node towards the point when the left side of the node has reached the right side of the viewport (see dir)
progressY:Number [0,1] % representing the distance travelled by the node towards the point when the bottom side of the node has reached the top side of the viewport
visibility:Boolean always true when reading the matrix object
height:Number node.clientHeight
contentHeight:Number node.scrollHeight
visibleHeight:Number absolute value in pixels of how much of the node is visible on the vertical plane
width:Number node.clientWidth
contentWidth:Number node.scrollWidth
visibleWidth:Number absolute value in pixels of how much of the node is visible on the horizontal plane
dir
You can invert the progressX logic by passing dir=rtl
<ScrollWatcher dir="rtl" watch={someRef}>
{children}
</ScrollWatcher>
directions
The directions towards which the node is moving relative to the scroll of the window are given in a bitmask format.
import ScrollWatcher, {directions} from "@grid23/react-scrollwatcher"
function onOffsetChange(matrix){
matrix.direction & directions.UP
matrix.direction & directions.DOWN
matrix.direction & directions.LEFT
matrix.direction & directions.RIGHT
matrix.direction & (directions.UP^direction.LEFT)
matrix.direction & (directions.UP^direction.RIGHT)
matrix.direction & (directions.DOWN^direction.LEFT)
matrix.direction & (directions.DOWN^direction.RIGHT)
}
notes
The position of the watched node is computed at:
- DOM events:
- focus
- orientationchange
- resize
- scroll
- DOM Mutations
- watcher creation.
Listeners are only active when at least one node is being actively watched.