Skip to content

Commit 20c8925

Browse files
authored
feat: implement useHooks and update rollup config (#136)
* feat: implement useHooks and update rollup config This commit implements the new Hook API, and also improves the Rollup build output * docs: work on the readme * chore: upgrade dependencies - upgrade npm-run-all No more flatmap-stream * refactor: update the typescript definition
1 parent ace15bc commit 20c8925

File tree

14 files changed

+860
-609
lines changed

14 files changed

+860
-609
lines changed

.babelrc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
{
2-
"presets": ["@babel/preset-env", "@babel/preset-react", "@babel/preset-flow"],
2+
"presets": [
3+
["@babel/preset-env", { "loose": true }],
4+
"@babel/preset-react",
5+
"@babel/preset-flow"
6+
],
37
"plugins": ["@babel/plugin-proposal-class-properties"]
48
}

.size-snapshot.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"dist/react-intersection-observer.cjs.js": {
3+
"bundled": 10178,
4+
"minified": 4474,
5+
"gzipped": 1693
6+
},
7+
"dist/react-intersection-observer.umd.min.js": {
8+
"bundled": 4648,
9+
"minified": 4648,
10+
"gzipped": 2043
11+
},
12+
"dist/react-intersection-observer.esm.js": {
13+
"bundled": 9882,
14+
"minified": 4257,
15+
"gzipped": 1629,
16+
"treeshaked": {
17+
"rollup": {
18+
"code": 2882,
19+
"import_statements": 376
20+
},
21+
"webpack": {
22+
"code": 4129
23+
}
24+
}
25+
}
26+
}

README.md

Lines changed: 93 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -31,81 +31,128 @@ or NPM:
3131
npm install react-intersection-observer --save
3232
```
3333

34-
> ⚠️ You also want to add the [intersection-observer](https://www.npmjs.com/package/react-intersection-observer) polyfill for full browser support. Check out adding the [polyfill](#polyfill) for details about how you can include it.
34+
> ⚠️ You also want to add the
35+
> [intersection-observer](https://www.npmjs.com/package/react-intersection-observer)
36+
> polyfill for full browser support. Check out adding the [polyfill](#polyfill)
37+
> for details about how you can include it.
3538
3639
## Usage
3740

41+
### Hooks 🎣
42+
43+
> 🚨 Hooks are a new feature proposal that lets you use state and other React
44+
> features without writing a class. They’re currently in React v16.7.0-alpha and
45+
> being discussed in an [open RFC](https://github.com/reactjs/rfcs/pull/68). If
46+
> you decide to use it in production, keep in mind that it may very well break.
47+
48+
The new Hooks feature, makes it even easier than before to monitor the `inView`
49+
state of your components. You can import the `useInView` hook, and pass it a ref
50+
to the DOM node you want to observe.
51+
52+
It also accepts an [options](#options) object, to control the Intersection
53+
Observer.
54+
55+
```jsx
56+
import { useRef } from 'react'
57+
import { useInView } from 'react-intersection-observer'
58+
59+
const Component = () => {
60+
const ref = useRef()
61+
const inView = useInView(ref, {
62+
/* Optional options */
63+
threshold: 0,
64+
})
65+
66+
return (
67+
<div ref={ref}>
68+
<h2>{`Header inside viewport ${inView}.`}</h2>
69+
</div>
70+
)
71+
}
72+
```
73+
3874
### Child as function
3975

40-
To use the `Observer`, you pass it a function. It will be called whenever the state changes, with the new value of `inView`.
41-
In addition to the `inView` prop, children also receives a `ref` that should be set on the containing DOM element.
76+
To use the `Observer`, you pass it a function. It will be called whenever the
77+
state changes, with the new value of `inView`. In addition to the `inView` prop,
78+
children also receives a `ref` that should be set on the containing DOM element.
4279
This is the element that the IntersectionObserver will monitor.
4380

4481
```jsx
45-
import Observer from 'react-intersection-observer'
82+
import { InView } from 'react-intersection-observer'
4683

4784
const Component = () => (
48-
<Observer>
85+
<InView>
4986
{({ inView, ref }) => (
5087
<div ref={ref}>
5188
<h2>{`Header inside viewport ${inView}.`}</h2>
5289
</div>
5390
)}
54-
</Observer>
91+
</InView>
5592
)
5693

5794
export default Component
5895
```
5996

6097
### Plain children
6198

62-
You can pass any element to the `<Observer />`, and it will handle creating the wrapping DOM element.
63-
Add a handler to the `onChange` method, and control the state in your own component.
64-
It will pass any extra props to the HTML element, allowing you set the `className`, `style`, etc.
99+
You can pass any element to the `<Observer />`, and it will handle creating the
100+
wrapping DOM element. Add a handler to the `onChange` method, and control the
101+
state in your own component. It will pass any extra props to the HTML element,
102+
allowing you set the `className`, `style`, etc.
65103

66104
```jsx
67-
import Observer from 'react-intersection-observer'
105+
import { InView } from 'react-intersection-observer'
68106

69107
const Component = () => (
70-
<Observer tag="div" onChange={inView => console.log('Inview:', inView)}>
108+
<InView tag="div" onChange={inView => console.log('Inview:', inView)}>
71109
<h2>Plain children are always rendered. Use onChange to monitor state.</h2>
72-
</Observer>
110+
</InView>
73111
)
74112

75113
export default Component
76114
```
77115

78116
> ⚠️ When rendering a plain child, make sure you keep your HTML output semantic.
79-
> Change the `tag` to match the context, and add a `className` to style the `<Observer />`.
117+
> Change the `tag` to match the context, and add a `className` to style the
118+
> `<Observer />`.
119+
120+
## API
121+
122+
### Options
123+
124+
| Name | Type | Default | Required | Description |
125+
| --------------- | ----------- | ------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
126+
| **root** | HTMLElement | | false | The HTMLElement that is used as the viewport for checking visibility of the target. Defaults to the browser viewport if not specified or if null. |
127+
| **rootId** | String | | false | Unique identifier for the root element - This is used to identify the IntersectionObserver instance, so it can be reused. If you defined a root element, without adding an id, it will create a new instance for all components. |
128+
| **rootMargin** | String | '0px' | false | Margin around the root. Can have values similar to the CSS margin property, e.g. "10px 20px 30px 40px" (top, right, bottom, left). |
129+
| **threshold** | Number | 0 | false | Number between 0 and 1 indicating the the percentage that should be visible before triggering. Can also be an array of numbers, to create multiple trigger points. |
130+
| **triggerOnce** | Bool | false | false | Only trigger this method once |
80131

81-
## Props
132+
### InView Props
82133

83-
The **`<Observer />`** accepts the following props:
134+
The **`<InView />`** component also accepts the following props:
84135

85-
| Name | Type | Default | Required | Description |
86-
| --------------- | ------------------------------------------ | ------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
87-
| **children** | ({inView, ref}) => React.Node / React.Node | | true | Children expects a function that receives an object contain an `inView` boolean and `ref` that should be assigned to the element root. Alternately pass a plain child, to have the `<Observer />` deal with the wrapping element. |
88-
| **onChange** | (inView) => void | | false | Call this function whenever the in view state changes |
89-
| **root** | HTMLElement | | false | The HTMLElement that is used as the viewport for checking visibility of the target. Defaults to the browser viewport if not specified or if null. |
90-
| **rootId** | String | | false | Unique identifier for the root element - This is used to identify the IntersectionObserver instance, so it can be reused. If you defined a root element, without adding an id, it will create a new instance for all components. |
91-
| **rootMargin** | String | '0px' | false | Margin around the root. Can have values similar to the CSS margin property, e.g. "10px 20px 30px 40px" (top, right, bottom, left). |
92-
| **threshold** | Number | 0 | false | Number between 0 and 1 indicating the the percentage that should be visible before triggering. Can also be an array of numbers, to create multiple trigger points. |
93-
| **triggerOnce** | Bool | false | false | Only trigger this method once |
136+
| Name | Type | Default | Required | Description |
137+
| ------------ | ------------------------------------------ | ------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
138+
| **children** | ({inView, ref}) => React.Node / React.Node | | true | Children expects a function that receives an object contain an `inView` boolean and `ref` that should be assigned to the element root. Alternately pass a plain child, to have the `<Observer />` deal with the wrapping element. |
139+
| **onChange** | (inView) => void | | false | Call this function whenever the in view state changes |
94140

95141
## Usage in other projects
96142

97143
### react-scroll-percentage
98144

99145
This module is used in
100146
[react-scroll-percentage](https://github.com/thebuilder/react-scroll-percentage)
101-
to monitor the scroll position of elements in view, useful for animating items as
102-
they become visible. This module is also a great example of using `react-intersection-observer`
103-
as the basis for more complex needs.
147+
to monitor the scroll position of elements in view, useful for animating items
148+
as they become visible. This module is also a great example of using
149+
`react-intersection-observer` as the basis for more complex needs.
104150

105151
## Intersection Observer
106152

107153
[Intersection Observer](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API)
108-
is the API is used to determine if an element is inside the viewport or not. Browser support is pretty good, but Safari is still missing support.
154+
is the API is used to determine if an element is inside the viewport or not.
155+
Browser support is pretty good, but Safari is still missing support.
109156

110157
> [Can i use intersectionobserver?](https://caniuse.com/#feat=intersectionobserver)
111158
@@ -126,9 +173,10 @@ Then import it in your app:
126173
import 'intersection-observer'
127174
```
128175

129-
If you are using Webpack (or similar) you could use [dynamic
130-
imports](https://webpack.js.org/api/module-methods/#import-), to load the
131-
Polyfill only if needed. A basic implementation could look something like this:
176+
If you are using Webpack (or similar) you could use
177+
[dynamic imports](https://webpack.js.org/api/module-methods/#import-), to load
178+
the Polyfill only if needed. A basic implementation could look something like
179+
this:
132180

133181
```js
134182
loadPolyfills()
@@ -159,20 +207,27 @@ function supportsIntersectionObserver() {
159207
[package-url]: https://npmjs.org/package/react-intersection-observer
160208
[npm-version-svg]: https://img.shields.io/npm/v/react-intersection-observer.svg
161209
[npm-minzip-svg]: https://img.shields.io/bundlephobia/minzip/react.svg
162-
[bundlephobia-url]: https://bundlephobia.com/result?p=react-intersection-observer
210+
[bundlephobia-url]:
211+
https://bundlephobia.com/result?p=react-intersection-observer
163212
[travis-svg]: https://travis-ci.org/thebuilder/react-intersection-observer.svg
164213
[travis-url]: https://travis-ci.org/thebuilder/react-intersection-observer
165-
[coveralls-svg]: https://coveralls.io/repos/github/thebuilder/react-intersection-observer/badge.svg?branch=master
166-
[coveralls-url]: https://coveralls.io/github/thebuilder/react-intersection-observer?branch=master
214+
[coveralls-svg]:
215+
https://coveralls.io/repos/github/thebuilder/react-intersection-observer/badge.svg?branch=master
216+
[coveralls-url]:
217+
https://coveralls.io/github/thebuilder/react-intersection-observer?branch=master
167218
[deps-svg]: https://david-dm.org/thebuilder/react-intersection-observer.svg
168219
[deps-url]: https://david-dm.org/thebuilder/react-intersection-observer
169-
[dev-deps-svg]: https://david-dm.org/thebuilder/react-intersection-observer/dev-status.svg
170-
[dev-deps-url]: https://david-dm.org/thebuilder/react-intersection-observer#info=devDependencies
220+
[dev-deps-svg]:
221+
https://david-dm.org/thebuilder/react-intersection-observer/dev-status.svg
222+
[dev-deps-url]:
223+
https://david-dm.org/thebuilder/react-intersection-observer#info=devDependencies
171224
[license-image]: http://img.shields.io/npm/l/react-intersection-observer.svg
172225
[license-url]: LICENSE
173226
[downloads-image]: http://img.shields.io/npm/dm/react-intersection-observer.svg
174-
[downloads-url]: http://npm-stat.com/charts.html?package=react-intersection-observer
175-
[greenkeeper-svg]: https://badges.greenkeeper.io/thebuilder/react-intersection-observer.svg
227+
[downloads-url]:
228+
http://npm-stat.com/charts.html?package=react-intersection-observer
229+
[greenkeeper-svg]:
230+
https://badges.greenkeeper.io/thebuilder/react-intersection-observer.svg
176231
[greenkeeper-url]: https://greenkeeper.io/
177232
[prettier-svg]: https://img.shields.io/badge/styled_with-prettier-ff69b4.svg
178233
[prettier-url]: https://github.com/prettier/prettier

index.d.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@ export interface RenderProps {
55
ref: React.RefObject<any>
66
}
77

8-
export interface IntersectionObserverProps {
9-
/** Children expects a function that receives an object contain an `inView` boolean and `ref` that should be assigned to the element root. */
10-
children?: React.ReactNode | ((fields: RenderProps) => React.ReactNode)
11-
8+
export interface IntersectionOptions {
129
/**
1310
* The `HTMLElement` that is used as the viewport for checking visibility of
1411
* the target.
@@ -31,12 +28,6 @@ export interface IntersectionObserverProps {
3128
*/
3229
rootMargin?: string
3330

34-
/**
35-
* Element tag to use for the wrapping component
36-
* @default `'div'`
37-
*/
38-
tag?: string
39-
4031
/** Number between 0 and 1 indicating the the percentage that should be
4132
* visible before triggering. Can also be an array of numbers, to create
4233
* multiple trigger points.
@@ -49,11 +40,28 @@ export interface IntersectionObserverProps {
4940
* @default `false`
5041
*/
5142
triggerOnce?: boolean
43+
}
44+
45+
export interface IntersectionObserverProps extends IntersectionOptions {
46+
/**
47+
* Children expects a function that receives an object
48+
* contain an `inView` boolean and `ref` that should be
49+
* assigned to the element root.
50+
*/
51+
children?: React.ReactNode | ((fields: RenderProps) => React.ReactNode)
52+
53+
/**
54+
* Element tag to use for the wrapping component
55+
* @default `'div'`
56+
*/
57+
tag?: string
5258

5359
/** Call this function whenever the in view state changes */
5460
onChange?: (inView: boolean) => void
5561
}
5662

63+
export class InView extends React.Component<IntersectionObserverProps, {}> {}
64+
5765
export default class ReactIntersectionObserver extends React.Component<
5866
IntersectionObserverProps,
5967
{}

package.json

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
"prettier": {
2828
"singleQuote": true,
2929
"semi": false,
30-
"trailingComma": "all"
30+
"trailingComma": "all",
31+
"proseWrap": "always"
3132
},
3233
"eslintIgnore": [
3334
"*.snap",
@@ -38,15 +39,11 @@
3839
"scripts": {
3940
"coveralls": "cat ./coverage/lcov.info | coveralls",
4041
"build": "rm -rf dist && yarn run build:lib && yarn run build:flow",
41-
"build:lib": "run-p rollup:*",
42+
"build:lib": "rollup -c && git add .size-snapshot.json",
4243
"build:storybook": "build-storybook --output-dir example",
4344
"build:flow": "node scripts/create-flow",
4445
"dev": "concurrently -k -r 'jest --watch' 'yarn run storybook'",
4546
"lint": "eslint {src,stories,tests}/**/*.js ",
46-
"rollup:es": "rollup -c --environment FORMAT:es",
47-
"rollup:cjs": "rollup -c --environment FORMAT:cjs",
48-
"rollup:umd": "rollup -c --environment FORMAT:umd",
49-
"rollup:umd.min": "rollup -c --environment MINIFY,FORMAT:umd",
5047
"prepare": "yarn build",
5148
"pretty": "prettier '**/*.{js,md,json,yml,html}' --write",
5249
"storybook": "start-storybook -p 9000",
@@ -88,6 +85,7 @@
8885
]
8986
},
9087
"dependencies": {
88+
"@babel/runtime": "^7.1.0",
9189
"invariant": "^2.2.4"
9290
},
9391
"peerDependencies": {
@@ -100,35 +98,37 @@
10098
"@babel/preset-env": "^7.1.5",
10199
"@babel/preset-flow": "^7.0.0",
102100
"@babel/preset-react": "^7.0.0",
103-
"@babel/runtime": "^7.1.5",
104-
"@storybook/addon-actions": "^4.0.4",
101+
"@storybook/addon-actions": "^4.0.9",
105102
"@storybook/addon-options": "^4.0.4",
106-
"@storybook/react": "^4.0.4",
103+
"@storybook/react": "^4.0.9",
104+
"babel-core": "^7.0.0-bridge.0",
107105
"babel-jest": "^23.4.2",
108106
"babel-loader": "^8.0.4",
109-
"concurrently": "4.0.1",
107+
"concurrently": "4.1.0",
110108
"coveralls": "^3.0.2",
111109
"enzyme": "^3.7.0",
112110
"enzyme-adapter-react-16": "^1.7.0",
113111
"enzyme-to-json": "^3.3.4",
114112
"eslint": "^5.9.0",
115113
"eslint-config-insilico": "^5.2.0",
116-
"flow-bin": "^0.86.0",
114+
"flow-bin": "^0.87.0",
117115
"flow-copy-source": "^2.0.2",
118116
"husky": "^1.1.3",
119117
"intersection-observer": "^0.5.1",
120118
"jest": "^23.5.0",
119+
"jest-dom": "^2.1.1",
121120
"lint-staged": "^8.0.4",
122-
"npm-run-all": "^4.1.3",
121+
"npm-run-all": "^4.1.5",
123122
"prettier": "^1.15.2",
124-
"react": "^16.6.1",
125-
"react-dom": "^16.6.1",
126-
"react-test-renderer": "^16.6.1",
123+
"react": "^16.7.0-alpha",
124+
"react-dom": "^16.7.0-alpha",
125+
"react-test-renderer": "^16.7.0-alpha",
127126
"rollup": "^0.67.1",
128127
"rollup-plugin-babel": "^4.0.1",
129128
"rollup-plugin-commonjs": "^9.2.0",
130129
"rollup-plugin-node-resolve": "^3.3.0",
131130
"rollup-plugin-replace": "^2.1.0",
131+
"rollup-plugin-size-snapshot": "^0.7.0",
132132
"rollup-plugin-uglify": "^6.0.0"
133133
}
134134
}

0 commit comments

Comments
 (0)