Skip to content

Commit 4b6e59b

Browse files
authored
Convert to TypeScript (#159)
This is a rewritte to TypeScript that also improves the documentation by using Docz
1 parent aafe028 commit 4b6e59b

37 files changed

+5053
-2248
lines changed

.babelrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"presets": [
33
["@babel/preset-env", { "loose": true }],
44
"@babel/preset-react",
5-
"@babel/preset-flow"
5+
"@babel/preset-typescript"
66
],
77
"plugins": ["@babel/plugin-proposal-class-properties"]
88
}

.flowconfig

Lines changed: 0 additions & 17 deletions
This file was deleted.

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
.vscode
22
.cache
3+
.docz
34
node_modules
45
reports
56
example

.npmignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,12 @@ npm-debug.log
2222
.editorconfig
2323
.storybook
2424
yarn.lock
25+
26+
# Project files
2527
coverage
2628
stories
2729
tests
2830
example
29-
jest-setup.js
31+
jest-setup.js
32+
__tests__
33+
global-types.d.ts

.prettierignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
dist/
22
lib/
33
example/
4-
package.json
4+
package.json
5+
coverage

.storybook/.babelrc

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

.storybook/config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ withOptions({
1313
/**
1414
* Use require.context to load dynamically: https://webpack.github.io/docs/context.html
1515
*/
16-
const req = require.context('../stories', true, /story\.js$/)
16+
const req = require.context('../stories', true, /story\.tsx$/)
1717

1818
function loadStories() {
1919
req.keys().forEach(req)

.storybook/webpack.config.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// webpack.config.js
2+
const ErrorOverlayPlugin = require('error-overlay-webpack-plugin')
3+
4+
module.exports = (baseConfig, env, defaultConfig) => {
5+
defaultConfig.entry = defaultConfig.entry.map(path => {
6+
if (path.includes('webpack-hot-middleware')) {
7+
return path + '&overlay=false'
8+
}
9+
return path
10+
})
11+
12+
defaultConfig.module.rules.push({
13+
test: /\.(ts|tsx)$/,
14+
loader: require.resolve('babel-loader'),
15+
options: {
16+
presets: [['react-app', { flow: false, typescript: true }]],
17+
},
18+
})
19+
defaultConfig.resolve.extensions.push('.ts', '.tsx')
20+
21+
defaultConfig.plugins.push(new ErrorOverlayPlugin())
22+
23+
return defaultConfig
24+
}

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ cache: yarn
55
script:
66
- yarn lint
77
- yarn test --coverage
8-
- yarn flow check
8+
- yarn tsc
99
- yarn build:storybook
1010
after_success:
1111
- yarn coveralls

README.md

Lines changed: 33 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@
1111
[![Greenkeeper badge][greenkeeper-svg]][greenkeeper-url]
1212
[![styled with prettier][prettier-svg]][prettier-url]
1313

14-
React component that triggers a function when the component enters or leaves the
15-
viewport. No complex configuration needed, just wrap your views and it handles
16-
the events.
14+
React component that uses the IntersectionObserver API to tell you when an
15+
element enters or leaves the viewport. No complex configuration needed, just
16+
wrap your views and it handles the events.
1717

18-
> **Storybook demo:** https://thebuilder.github.io/react-intersection-observer/
18+
> **DOCS** https://react-intersection-observer.now.sh
1919
2020
## Installation
2121

@@ -47,7 +47,8 @@ npm install react-intersection-observer --save
4747
4848
The new Hooks feature, makes it even easier than before to monitor the `inView`
4949
state of your components. You can import the `useInView` hook, and pass it a ref
50-
to the DOM node you want to observe.
50+
to the DOM node you want to observe. It will then return `true` once the element
51+
enter the viewport.
5152

5253
It also accepts an [options](#options) object, to control the Intersection
5354
Observer.
@@ -71,12 +72,17 @@ const Component = () => {
7172
}
7273
```
7374

74-
### Child as function
75+
If you need to know more details about the intersection, you can call the
76+
`useIntersectionObserver` hook instead. It takes the same input, but will return
77+
an object containing `inView` and `intersection`.
7578

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.
79-
This is the element that the IntersectionObserver will monitor.
79+
### Render props
80+
81+
To use the `<InView>` component , you pass it a function. It will be called
82+
whenever the state changes, with the new value of `inView`. In addition to the
83+
`inView` prop, children also receives a `ref` that should be set on the
84+
containing DOM element. This is the element that the IntersectionObserver will
85+
monitor.
8086

8187
```jsx
8288
import { InView } from 'react-intersection-observer'
@@ -96,7 +102,7 @@ export default Component
96102

97103
### Plain children
98104

99-
You can pass any element to the `<Observer />`, and it will handle creating the
105+
You can pass any element to the `<InView />`, and it will handle creating the
100106
wrapping DOM element. Add a handler to the `onChange` method, and control the
101107
state in your own component. It will pass any extra props to the HTML element,
102108
allowing you set the `className`, `style`, etc.
@@ -115,28 +121,27 @@ export default Component
115121

116122
> ⚠️ When rendering a plain child, make sure you keep your HTML output semantic.
117123
> Change the `tag` to match the context, and add a `className` to style the
118-
> `<Observer />`.
124+
> `<InView />`.
119125
120126
## API
121127

122128
### Options
123129

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 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 |
130+
| Name | Type | Default | Required | Description |
131+
| --------------- | ------------------ | ------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
132+
| **root** | Element | | false | The Element that is used as the viewport for checking visibility of the target. Defaults to the browser viewport (`window`) if not specified or if null. |
133+
| **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). |
134+
| **threshold** | Number \| number[] | 0 | false | Number between 0 and 1 indicating the percentage that should be visible before triggering. Can also be an array of numbers, to create multiple trigger points. |
135+
| **triggerOnce** | Bool | false | false | Only trigger this method once |
131136

132137
### InView Props
133138

134139
The **`<InView />`** component also accepts the following props:
135140

136-
| Name | Type | Default | Required | Description |
137-
| ------------ | ------------------------------------------------------------- | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
138-
| **children** | ({inView, intersectionRatio, 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. You also receive the last `intersectionRatio` |
139-
| **onChange** | (inView, intersectionRatio) => void | | false | Call this function whenever the in view state changes |
141+
| Name | Type | Default | Required | Description |
142+
| ------------ | ------------------------------------------------------------- | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
143+
| **children** | `({inView, intersection, ref}) => React.Node` or `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. You will also get the `IntersectionObserverEntry` as `intersection, giving you more details. |
144+
| **onChange** | `(inView, intersection) => void` | | false | Call this function whenever the in view state changes |
140145

141146
## Usage in other projects
142147

@@ -179,28 +184,13 @@ the Polyfill only if needed. A basic implementation could look something like
179184
this:
180185

181186
```js
182-
loadPolyfills()
183-
.then(() => /* Render React application now that your Polyfills are ready */)
184-
185187
/**
186-
* Do feature detection, to figure out which polyfills needs to be imported.
187-
**/
188-
function loadPolyfills() {
189-
const polyfills = []
190-
191-
if (!supportsIntersectionObserver()) {
192-
polyfills.push(import('intersection-observer'))
188+
* Do feature detection, to figure out which polyfills needs to be imported.
189+
**/
190+
async function loadPolyfills() {
191+
if (typeof window.IntersectionObserver === 'undefined') {
192+
await import('intersection-observer')
193193
}
194-
195-
return Promise.all(polyfills)
196-
}
197-
198-
function supportsIntersectionObserver() {
199-
return (
200-
'IntersectionObserver' in global &&
201-
'IntersectionObserverEntry' in global &&
202-
'intersectionRatio' in IntersectionObserverEntry.prototype
203-
)
204194
}
205195
```
206196

0 commit comments

Comments
 (0)