Skip to content

Commit bbffac3

Browse files
committed
Add more documentation
1 parent f3dbde6 commit bbffac3

File tree

1 file changed

+142
-25
lines changed

1 file changed

+142
-25
lines changed

Readme.md

Lines changed: 142 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,26 @@ A react hook to use the
77
declaratively in your React app for the purposes of finding out if an element is in a given
88
viewport.
99

10+
- [Motivation](#motivation)
11+
- [Guiding principles](#guiding-principles)
12+
- [Installation](#installation)
13+
- [API docs](#api)
14+
- [Return value](#return-value)
15+
- [Input options](#options)
16+
- [options.threshold](#options.threshold)
17+
- [options.target](#options.target)
18+
- [options.viewport](#options.viewport)
19+
- [options.{modTop, modRight, modBottom, modLeft}](#optionsmodtop-modright-modbottom-modleft)
20+
- [Example usage](#example-usage)
21+
- [Tasks](#tasks)
22+
1023
## Motivation
1124

1225
I wrote [isInViewport](https://github.com/zeusdeux/isInViewport) for the jQuery world back in the
1326
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
27+
[isInViewport](https://github.com/zeusdeux/isInViewport) solves still remains. Since then, the web
28+
platform has grown massively and now gives us better primitives to solve this problem in the shape
29+
of the
1630
[Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API).
1731

1832
I was looking for a simple way to use the
@@ -39,10 +53,10 @@ this hook.
3953
- Easy installation
4054
- Correct peer dependencies to prevent foot-guns
4155
- Tons of docs and examples (in progress)
42-
3. Make it easy to solve the most likely use cases
56+
3. Make it easy to address the most likely use-cases
4357
- e.g., "Tell me when an element is visible in the current window viewport", "Tell me when 75% of
4458
an element is visible in current window viewport"
45-
4. Make it possible to solve other problems without unnecessary noise
59+
4. Make it possible to address other use-cases without unnecessary noise
4660
- e.g., "Tell me when an element is visible in my custom viewport", "Let me customize the
4761
viewport I want to pass down", "Let me use this with a component that uses React.forwardRef",
4862
etc
@@ -64,8 +78,8 @@ this hook.
6478
Please note that this hook declares `react` and as _peer dependency_. Therefore, you must have
6579
`react` installed to use this package.
6680

67-
Please [open as issue](https://github.com/zeusdeux/use-is-in-viewport/issues/new) if this default
68-
causes an issue in your application.
81+
Please [open an issue](https://github.com/zeusdeux/use-is-in-viewport/issues/new) if this default
82+
causes a problem in your application.
6983

7084
## API
7185

@@ -74,10 +88,12 @@ causes an issue in your application.
7488
> The nomenclature (target, viewport, threshold, etc) are borrowed from that of the
7589
> [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#Intersection_observer_concepts_and_usage)
7690
77-
The hook accepts an optional `options` object. When not provided, sane defaults are used. They are
78-
described in the `options` section below.
91+
- [Return value](#return-value)
92+
- [Input options](#options)
93+
94+
#### Return value
7995

80-
It returns an array that contains the following in order:
96+
It returns an `array` that contains the following in order:
8197

8298
1. a flag that is one of `null`, `true`, `false` based on the visibility of target element in
8399
provided viewport
@@ -91,10 +107,10 @@ It returns an array that contains the following in order:
91107

92108
#### Options
93109

94-
All options are optional. Please (ab)use your editor's Typescript capabilities to capitalize on
95-
types for this hook.
110+
The hook accepts an optional `options` object. When not provided, "sane" defaults are used. They are
111+
described in the `options` section below.
96112

97-
##### options.threshold
113+
#### _options.threshold_
98114

99115
The threshold describes what **percent** of the target element should intersect with the given
100116
viewport for it to be considered as visible in the viewport.
@@ -106,23 +122,124 @@ Passing an array of numbers is likely to be useless for most use cases. It only
106122
artefact of the library this hook is built on and hence will most likely will be deprecated and
107123
removed based on feedback from the community.
108124

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.
125+
**Default**: `0%` -> as soon as even `1px` of your target element is visible in viewport it'll be
126+
reported as visible in viewport.
127+
128+
**Example**:
111129

112-
##### options.target
130+
```jsx
131+
// this would report an element as visible in its parent document viewport when
132+
// at least 50% of the target intersects with the viewport
133+
const [isInViewport, targetRef] = useIsInViewport({ threshold: 50 })
134+
...
135+
<div ref={wrappedTargetRef}>{ isInViewport ? 'Visible' : 'Nope' }</div>
136+
```
137+
138+
#### _options.target_
113139

114140
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.
141+
track the visibility of in a viewport. This is useful when you have a `ref` that is created outside
142+
of this hook (for e.g., passed in via `ref` prop from another component, a forwarded ref, etc).
143+
144+
This ref is wrapped and a new ref is returned at index 1 in the returned array. The returned ref is
145+
what you must pass to the `ref` property of the element you want to track the visibility of.
146+
147+
**Default**: `undefined`
148+
149+
**Example**:
150+
151+
```jsx
152+
const targetRef = useCallback(node => console.log(node)) // can come from anywhere
153+
// or
154+
const targetRef = useRef(null) // can come from anywhere
155+
156+
const [isInViewport, wrappedTargetRef] = useIsInViewport({ target: targetRef })
157+
...
158+
<div ref={wrappedTargetRef}>{ isInViewport ? 'Visible' : 'Nope' }</div>
159+
```
160+
161+
#### _options.viewport_
162+
163+
The viewport accepts a [ref](https://reactjs.org/docs/refs-and-the-dom.html) for the element you
164+
want to use as the viewport. This _must_ be a parent of the element you want to track the visibility
165+
of. This options is useful when you have a `ref` that is created outside of this hook (for e.g.,
166+
passed in via `ref` prop from another component, a forwarded ref, etc).
167+
168+
This ref is wrapped and a new ref is returned at index 2 in the returned array. The returned ref is
169+
what you must pass to the `ref` property of the element you want to use as the viewport.
170+
171+
Also, if you want plan to use the same viewport for multiple child elements, then the viewport ref
172+
must be **_chained_** as shown in the example below. This might feel a bit weird at first but this
173+
chaining is necessary so that we can -
174+
175+
1. Preserve whatever behaviour the incoming viewport ref has (it could be a fn or a object ref)
176+
2. Have only one viewport ref that can then be passed to the element you want to use as viewport
117177

118-
example: `useIsInViewport({ target: node => console.log(node) })` or
119-
`useIsInViewport({ target: useRef(null) })`
178+
**Default**: `undefined`
120179

121-
##### options.viewport
180+
**Example**:
181+
182+
```jsx
183+
const MyElement = React.forwardRef(function MyElement(props, parentRef) {
184+
const [isFirstDivInViewport, firstDiv, wrappedViewportRef] = useIsInViewport({
185+
viewport: parentRef
186+
})
187+
const [isSecondDivInViewport, secondDiv, finalViewportRef] = useIsInViewport({
188+
viewport: wrappedViewportRef, // viewport ref is chained
189+
threshold: 20
190+
})
191+
192+
return (
193+
<section ref={finalViewportRef}>
194+
<div ref={firstDiv}>{isFirstDivInViewport ? 'Visible' : 'Nope'}</div>
195+
<div ref={secondDiv}>{isSecondDivInViewport ? 'Visible' : 'Nope'}</div>
196+
</section>
197+
)
198+
})
199+
200+
201+
function App() {
202+
const ref = // however you want to create a ref (useRef, raw fn, useCallback, useMemo, React.createRef, etc)
203+
204+
return <MyElement ref={ref} />
205+
}
206+
207+
```
208+
209+
#### _options.{modTop, modRight, modBottom, modLeft}_
210+
211+
These values map directly to
212+
[`rootMargin`](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#The_intersection_root_and_root_margin)
213+
in Intersection Observer API. The can have values similar to the CSS
214+
[`margin`](https://developer.mozilla.org/en-US/docs/Web/CSS/margin) property.
215+
216+
> The values in rootMargin define offsets added to each side of the intersection root's bounding box
217+
> to create the final intersection root bounds.
218+
219+
**Defaults**:
220+
221+
- `modTop`: `'0px'`
222+
- `modRight`: `'0px'`
223+
- `modBottom`: `'0px'`
224+
- `modLeft`: `'0px'`
225+
226+
**Example**:
227+
228+
```jsx
229+
...
230+
const [isInViewport, targetRef] = useIsInViewport({
231+
modTop: '10px',
232+
modRight: '1em',
233+
modBottom: '2.5rem',
234+
modLeft: '10%'
235+
})
236+
...
237+
```
122238

123-
##### options.{modTop, modRight, modBottom, modLeft}
239+
## Example usage
124240

125-
## Usage
241+
A CRA based example app (which is also used in the test suite) can be found under
242+
[examples/cra](examples/cra). Inline examples showcasing use-cases are below.
126243

127244
### Example 1: Element with its parent document as viewport
128245

@@ -146,12 +263,12 @@ export default function SimpleElement() {
146263
147264
```
148265
149-
More example coming soon...
266+
More examples coming soon...
150267
151268
## Tasks
152269
153270
- [x] Setup the hook to work with CRA, codesandbox and standalone react app
154271
- [x] Write the hook in a way that can be tested with Cypress
155-
- [x] Write tests
156272
- [x] Setup CI
157-
- [ ] Write awesome docs!
273+
- [ ] Increase test coverage⏳
274+
- [ ] Write awesome docs!⏳

0 commit comments

Comments
 (0)