Skip to content

Commit a52534f

Browse files
Daniel Schmidtthebuilder
authored andcommitted
Add rootID and refactor intersection.js
1 parent f3b58d5 commit a52534f

File tree

3 files changed

+38
-32
lines changed

3 files changed

+38
-32
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ You can import the [polyfill](https://yarnpkg.com/en/package/intersection-observ
4242
yarn add intersection-observer
4343
```
4444

45-
Then import it in your app
45+
Then import it in your app:
4646

4747
```js
4848
import 'intersection-observer'
@@ -53,10 +53,10 @@ The **`<Observer />`** accepts the following props:
5353

5454
| Name | Type | Default | Required | Description |
5555
| ---------------- | --------- | ----------------- | -------- | ----------------------------------------------------- |
56+
| children | func/node | | true | Children should be either a function or a node |
5657
| tag | String | | false | Element tag to use for the wrapping component |
57-
| children | func/node | | false | Children should be either a function or a node |
58-
| triggerOnce | Bool | false | true | Only trigger this method once |
5958
| threshold | Number | 0 | false | Number between 0 and 1 indicating the the percentage that should be visible before triggering |
59+
| triggerOnce | Bool | false | false | Only trigger this method once |
6060
| onChange | Func | | false | Call this function whenever the in view state changes |
6161
| render | Func | | false | Use render method to only render content when inView |
6262

src/index.js

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,17 @@ class Observer extends Component {
2222
/** Only trigger the inView callback once */
2323
triggerOnce: PropTypes.bool,
2424
/** Number between 0 and 1 indicating the the percentage that should be visible before triggering */
25-
threshold: PropTypes.oneOfType([PropTypes.array, PropTypes.number]),
26-
/** The element that is used as the viewport for checking visibility of the target. Defaults to the browser viewport if not specified or if null.*/
27-
root: PropTypes.shape({
28-
id: PropTypes.string,
29-
getAttribute: PropTypes.func,
30-
}),
25+
threshold: PropTypes.oneOfType([
26+
PropTypes.arrayOf(PropTypes.number),
27+
PropTypes.number,
28+
]),
29+
/** 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.*/
30+
root: PropTypes.object,
3131
/** Margin around the root. Can have values similar to the CSS margin property, e.g. "10px 20px 30px 40px" (top, right, bottom, left). */
3232
rootMargin: PropTypes.string,
33+
/** Unique identifier for the root element - This is used to identify the IntersectionObserver instance, so it can be reused.
34+
* If you defined a root element, without adding an id, it will create a new instance for all components. */
35+
rootId: PropTypes.string,
3336
/** Call this function whenever the in view state changes */
3437
onChange: PropTypes.func,
3538
/** Use render method to only render content when inView */
@@ -82,12 +85,16 @@ class Observer extends Component {
8285

8386
observeNode() {
8487
if (!this.node) return
88+
const { threshold, root, rootMargin, rootId } = this.props
8589
observe(
8690
this.node,
8791
this.handleChange,
88-
this.props.threshold,
89-
this.props.root,
90-
this.props.rootMargin,
92+
{
93+
threshold,
94+
root,
95+
rootMargin,
96+
},
97+
rootId,
9198
)
9299
}
93100

src/intersection.js

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,39 +5,38 @@ const OBSERVER_MAP = new Map()
55
* Monitor element, and trigger callback when element becomes visible
66
* @param element {HTMLElement}
77
* @param callback {Function} Called with inView
8-
* @param threshold {Number} Number between 0 and 1, indicating how much of the element should be visible before triggering
9-
* @param root {HTMLElement} It should have a unique id or data-intersection-id in order for the Observer to reused.
10-
* @param rootMargin {String} The CSS margin to apply to the root element.
8+
* @param options {Object} InterSection observer options
9+
* @param options.threshold {Number} Number between 0 and 1, indicating how much of the element should be visible before triggering
10+
* @param options.root {HTMLElement} It should have a unique id or data-intersection-id in order for the Observer to reused.
11+
* @param options.rootMargin {String} The CSS margin to apply to the root element.
12+
* @param rootId {String} Unique identifier for the root element, to enable reusing the IntersectionObserver
1113
*/
1214
export function observe(
1315
element,
1416
callback,
15-
threshold = 0,
16-
root = null,
17-
rootMargin = '0px',
17+
options = {
18+
threshold: 0,
19+
},
20+
rootId = null,
1821
) {
22+
const { threshold, root, rootMargin } = options
1923
if (!element || !callback) return
20-
let observerId = `${threshold}_${rootMargin}`
24+
let observerId = rootMargin ? `${threshold}_${rootMargin}` : `${threshold}`
2125

2226
if (root) {
23-
const rootId = root.id || root.getAttribute('data-intersection-id')
2427
observerId = rootId ? `${rootId}_${observerId}` : null
2528
}
2629

2730
let observerInstance = observerId ? OBSERVER_MAP.get(observerId) : null
2831
if (!observerInstance) {
29-
observerInstance = new IntersectionObserver(onChange, {
30-
threshold,
31-
root,
32-
rootMargin,
33-
})
32+
observerInstance = new IntersectionObserver(onChange, options)
3433
if (observerId) OBSERVER_MAP.set(observerId, observerInstance)
3534
}
3635

3736
INSTANCE_MAP.set(element, {
3837
callback,
3938
visible: false,
40-
threshold,
39+
options,
4140
observerId,
4241
})
4342

@@ -62,8 +61,8 @@ export function unobserve(element) {
6261

6362
// Check if we are stilling observing any elements with the same threshold.
6463
let itemsLeft = false
65-
INSTANCE_MAP.forEach(item => {
66-
if (item.observerId === observerId) {
64+
INSTANCE_MAP.forEach((item, key) => {
65+
if (item.observerId === observerId && key !== element) {
6766
itemsLeft = true
6867
}
6968
})
@@ -95,14 +94,14 @@ function onChange(changes) {
9594
changes.forEach(intersection => {
9695
if (INSTANCE_MAP.has(intersection.target)) {
9796
const { isIntersecting, intersectionRatio, target } = intersection
98-
const { callback, visible, threshold, observerId } = INSTANCE_MAP.get(
97+
const { callback, visible, options, observerId } = INSTANCE_MAP.get(
9998
target,
10099
)
101100

102101
// Trigger on 0 ratio only when not visible. This is fallback for browsers without isIntersecting support
103102
let inView = visible
104-
? intersectionRatio > threshold
105-
: intersectionRatio >= threshold
103+
? intersectionRatio > options.threshold
104+
: intersectionRatio >= options.threshold
106105

107106
if (isIntersecting !== undefined) {
108107
// If isIntersecting is defined, ensure that the element is actually intersecting.
@@ -113,7 +112,7 @@ function onChange(changes) {
113112
INSTANCE_MAP.set(target, {
114113
callback,
115114
visible: inView,
116-
threshold,
115+
options,
117116
observerId,
118117
})
119118

0 commit comments

Comments
 (0)