@@ -7,6 +7,56 @@ A react hook to use the
77declaratively in your React app for the purposes of finding out if an element is in a given
88viewport.
99
10+ ## Motivation
11+
12+ I wrote [ isInViewport] ( https://github.com/zeusdeux/isInViewport ) for the jQuery world back in the
13+ day and while how we build interfaces has changed massively since, the problem
14+ [ isInViewport] ( https://github.com/zeusdeux/isInViewport ) solved still remains. What did change was
15+ that the web platform gave us better primitives to solve this problem in the shape of the
16+ [ Intersection Observer API] ( https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API ) .
17+
18+ I was looking for a simple way to use the
19+ [ Intersection Observer API] ( https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API )
20+ in my React app for the purposes of checking if a component is in some viewport. I started off by
21+ writing [ a wrapper] ( https://github.com/zeusdeux/observe-element-in-viewport ) around the Intersection
22+ Observer API but that still didn't _ feel_ right. Its dev ergonomics felt off due to the callback
23+ based core interface it shares with the Intersection Observer API.
24+
25+ Then, [ React Hooks happened] ( https://reactjs.org/blog/2019/02/06/react-v16.8.0.html ) ! I started
26+ playing around attempting to write a generic ` useIntersectionObserver ` hook. I gave up on that idea
27+ in favour of a more directed hook. One which solves a problem that I and many other devs have.
28+
29+ The following guiding principles in combination with the
30+ [ community] ( https://twitter.com/muditameta/status/1117854963911340042?s=12 ) helped shape the api for
31+ this hook.
32+
33+ ### Guiding principles
34+
35+ 1 . Solve a real problem
36+ - Test an element in a viewport for visibility
37+ 2 . Make it straightforward to consume the package
38+ - Simple, to the point name
39+ - Easy installation
40+ - Correct peer dependencies to prevent foot-guns
41+ - Tons of docs and examples (in progress)
42+ 3 . Make it easy to solve the most likely use cases
43+ - e.g., "Tell me when an element is visible in the current window viewport", "Tell me when 75% of
44+ an element is visible in current window viewport"
45+ 4 . Make it possible to solve other problems without unnecessary noise
46+ - e.g., "Tell me when an element is visible in my custom viewport", "Let me customize the
47+ viewport I want to pass down", "Let me use this with a component that uses React.forwardRef",
48+ etc
49+ 5 . Provide as much developer feedback as possible
50+ - made possible by types that ship with the project
51+ 6 . Only solve the actual problem
52+ - e.g., providing a polyfill for Intersection Observer is not this package's job
53+ 7 . Be trustworthy
54+ - All use cases have corresponding integration tests using Cypress (in progress)
55+
56+ > With all
57+ > [ all major browsers having added support for Intersection Observer API] ( https://caniuse.com/#search=intersection%20observer ) ,
58+ > this package is even more easier to drop into your application!
59+
1060## Installation
1161
1262` npm install use-is-in-viewport `
@@ -17,6 +67,61 @@ Please note that this hook declares `react` and as _peer dependency_. Therefore,
1767Please [ open as issue] ( https://github.com/zeusdeux/use-is-in-viewport/issues/new ) if this default
1868causes an issue in your application.
1969
70+ ## API
71+
72+ ### useIsInViewport([ options] ) => [ boolean | null, TargetCbRef, ViewportCbRef]
73+
74+ > The nomenclature (target, viewport, threshold, etc) are borrowed from that of the
75+ > [ Intersection Observer API] ( https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#Intersection_observer_concepts_and_usage )
76+
77+ The hook accepts an optional ` options ` object. When not provided, sane defaults are used. They are
78+ described in the ` options ` section below.
79+
80+ It returns an array that contains the following in order:
81+
82+ 1 . a flag that is one of ` null ` , ` true ` , ` false ` based on the visibility of target element in
83+ provided viewport
84+ - ` null ` -> first call to the hook when nothing is initialized
85+ - ` true ` -> target element is visible in the given viewport
86+ - ` false ` -> target element is visible in the given viewport
87+ 2 . A [ callback ref] ( https://reactjs.org/docs/refs-and-the-dom.html#callback-refs ) to pass to the
88+ element you want to know the visibility of.
89+ 3 . A [ callback ref] ( https://reactjs.org/docs/refs-and-the-dom.html#callback-refs ) to pass to the
90+ element you want to use as the viewport.
91+
92+ #### Options
93+
94+ All options are optional. Please (ab)use your editor's Typescript capabilities to capitalize on
95+ types for this hook.
96+
97+ ##### options.threshold
98+
99+ The threshold describes what ** percent** of the target element should intersect with the given
100+ viewport for it to be considered as visible in the viewport.
101+
102+ It can be a number or an array of numbers. The number is interpreted as a percent of the target
103+ element's dimensions.
104+
105+ Passing an array of numbers is likely to be useless for most use cases. It only exists as an
106+ artefact of the library this hook is built on and hence will most likely will be deprecated and
107+ removed based on feedback from the community.
108+
109+ example: ` useIsInViewport({ threshold: 50 }) ` would report an element as visible in its parent
110+ document viewport when at least 50% of the target intersects with the viewport.
111+
112+ ##### options.target
113+
114+ The target accepts a [ ref] ( https://reactjs.org/docs/refs-and-the-dom.html ) for the element you want
115+ track the visibility in viewport of. This ref is wrapped and a new ref is returned at index 1 in the
116+ returned array.
117+
118+ example: ` useIsInViewport({ target: node => console.log(node) }) ` or
119+ ` useIsInViewport({ target: useRef(null) }) `
120+
121+ ##### options.viewport
122+
123+ ##### options.{modTop, modRight, modBottom, modLeft}
124+
20125## Usage
21126
22127### Example 1: Element with its parent document as viewport
@@ -29,7 +134,7 @@ import React from 'react'
29134import ReactDOM from ' react-dom'
30135import useIsInViewport from ' use-is-in-viewport
31136
32- export default function OnlyChildWithNullViewport () {
137+ export default function SimpleElement () {
33138 const [isInViewport, childElToWatch] = useIsInViewport()
34139
35140 return (
0 commit comments