@cleartrip/ct-design-intersection-observer 4.0.0-SNAPSHOT-test.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -0
- package/dist/IntersectionObserver.d.ts +5 -0
- package/dist/IntersectionObserver.d.ts.map +1 -0
- package/dist/IntersectionObserver.native.d.ts +5 -0
- package/dist/IntersectionObserver.native.d.ts.map +1 -0
- package/dist/ct-design-intersection-observer.browser.cjs.js +2 -0
- package/dist/ct-design-intersection-observer.browser.cjs.js.map +1 -0
- package/dist/ct-design-intersection-observer.browser.esm.js +2 -0
- package/dist/ct-design-intersection-observer.browser.esm.js.map +1 -0
- package/dist/ct-design-intersection-observer.cjs.js +64 -0
- package/dist/ct-design-intersection-observer.cjs.js.map +1 -0
- package/dist/ct-design-intersection-observer.esm.js +62 -0
- package/dist/ct-design-intersection-observer.esm.js.map +1 -0
- package/dist/ct-design-intersection-observer.umd.js +67 -0
- package/dist/ct-design-intersection-observer.umd.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/type.d.ts +16 -0
- package/dist/type.d.ts.map +1 -0
- package/dist/useInViewType.d.ts +48 -0
- package/dist/useInViewType.d.ts.map +1 -0
- package/dist/useinView.d.ts +4 -0
- package/dist/useinView.d.ts.map +1 -0
- package/package.json +59 -0
- package/src/IntersectionObserver.native.tsx +50 -0
- package/src/IntersectionObserver.tsx +87 -0
- package/src/index.ts +2 -0
- package/src/type.ts +43 -0
- package/src/useInViewType.ts +106 -0
- package/src/useinView.ts +283 -0
package/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# InterSectionObserver
|
|
2
|
+
|
|
3
|
+
A component that observes element visibility using Intersection Observer API.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @cleartrip/ct-design-intersection-observer
|
|
11
|
+
# or
|
|
12
|
+
pnpm add @cleartrip/ct-design-intersection-observer
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Peer dependencies
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# Required for all targets
|
|
19
|
+
npm install react
|
|
20
|
+
|
|
21
|
+
# Web only
|
|
22
|
+
npm install react-dom
|
|
23
|
+
|
|
24
|
+
# React Native only
|
|
25
|
+
npm install react-native
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Usage
|
|
31
|
+
|
|
32
|
+
### Basic
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
import { InterSectionObserver } from '@cleartrip/ct-design-intersection-observer';
|
|
36
|
+
|
|
37
|
+
function Example() {
|
|
38
|
+
return (
|
|
39
|
+
<InterSectionObserver>
|
|
40
|
+
{/* Basic usage */}
|
|
41
|
+
</InterSectionObserver>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Accessibility
|
|
49
|
+
|
|
50
|
+
- The component follows accessibility best practices
|
|
51
|
+
- Ensure proper ARIA attributes are provided where needed
|
|
52
|
+
- Test with screen readers to ensure usability
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Migration
|
|
57
|
+
|
|
58
|
+
If migrating from a previous version:
|
|
59
|
+
|
|
60
|
+
```diff
|
|
61
|
+
- import { InterSectionObserver } from 'yagami/core/components';
|
|
62
|
+
+ import { InterSectionObserver } from '@cleartrip/ct-design-intersection-observer';
|
|
63
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IntersectionObserver.d.ts","sourceRoot":"","sources":["../packages/components/InterSectionObserver/src/IntersectionObserver.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAyC,MAAM,OAAO,CAAC;AAE9D,OAAO,EAAE,yBAAyB,EAAE,MAAM,QAAQ,CAAC;AAEnD,QAAA,MAAM,uBAAuB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,CAgFhE,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IntersectionObserver.native.d.ts","sourceRoot":"","sources":["../packages/components/InterSectionObserver/src/IntersectionObserver.native.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B,OAAO,EAAE,yBAAyB,EAAE,MAAM,QAAQ,CAAC;AAEnD,QAAA,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,CAwC7D,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var e=require("react/jsx-runtime"),r=require("react");exports.IntersectionObserver=({children:t,onIntersection:n,onTimedObservationComplete:u,threshold:c=[.01,.5],wrapped:s})=>{const i=r.useRef(!1),o=r.useRef(!1),l=r.useRef(null),a=r.useRef(null),d=r.useCallback(e=>{l.current&&e.unobserve(l.current)},[l]),f=r.useCallback((e,r)=>{const t=e[0];if(null==t?void 0:t.isIntersecting){o.current||(n(),o.current=!0);const{intersectionRatio:e}=t;e>=.5?(a.current&&clearTimeout(a.current),a.current=setTimeout(()=>{i.current||(d(r),i.current=!0,null==u||u())},1e3)):a.current&&clearTimeout(a.current)}else a.current&&clearTimeout(a.current)},[n,u,d]);return r.useEffect(()=>{const e=new IntersectionObserver(f,{threshold:c});return l.current&&e.observe(l.current),()=>{d(e)}},[f,c,d]),s?e.jsx("div",{ref:l,children:t}):e.jsxs(e.Fragment,{children:[e.jsx("div",{ref:l}),t]})};
|
|
2
|
+
//# sourceMappingURL=ct-design-intersection-observer.browser.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ct-design-intersection-observer.browser.cjs.js","sources":["../packages/components/InterSectionObserver/src/IntersectionObserver.tsx"],"sourcesContent":[null],"names":["children","onIntersection","onTimedObservationComplete","threshold","wrapped","viewed","useRef","intersected","intersectionRef","timeoutInstance","unobserve","useCallback","observer","current","handleIO","entries","entry","isIntersecting","intersectionRatio","clearTimeout","setTimeout","useEffect","IntersectionObserver","observe","_jsx","ref","_jsxs","jsxs","_Fragment","Fragment"],"mappings":"gGAIqE,EACnEA,WACAC,iBACAC,6BACAC,YAAY,CAAC,IAAM,IACnBC,cAEA,MAAMC,EAASC,UAAgB,GACzBC,EAAcD,UAAgB,GAC9BE,EAAkBF,SAA8B,MAChDG,EAAkBH,SAA8B,MAEhDI,EAAYC,cACfC,IACKJ,EAAgBK,SAClBD,EAASF,UAAUF,EAAgBK,UAGvC,CAACL,IAGGM,EAAWH,EAAAA,YACf,CAACI,EAAsCH,KACrC,MAAMI,EAAQD,EAAQ,GAEtB,GAAIC,aAAK,EAALA,EAAOC,eAAgB,CACpBV,EAAYM,UACfZ,IACAM,EAAYM,SAAU,GAGxB,MAAMK,kBAAEA,GAAsBF,EAE1BE,GAAqB,IACnBT,EAAgBI,SAClBM,aAAaV,EAAgBI,SAE/BJ,EAAgBI,QAAUO,WAAW,KAC9Bf,EAAOQ,UACVH,EAAUE,GACVP,EAAOQ,SAAU,EACjBX,SAAAA,MAED,MACMO,EAAgBI,SACzBM,aAAaV,EAAgBI,QAEhC,MACKJ,EAAgBI,SAClBM,aAAaV,EAAgBI,UAInC,CAACZ,EAAgBC,EAA4BQ,IAiB/C,OAdAW,EAAAA,UAAU,KACR,MAAMT,EAAW,IAAIU,qBAAqBR,EAAU,CAClDX,cAOF,OAJIK,EAAgBK,SAClBD,EAASW,QAAQf,EAAgBK,SAG5B,KACLH,EAAUE,KAEX,CAACE,EAAUX,EAAWO,IAErBN,EACKoB,EAAAA,WAAKC,IAAKjB,EAAkBR,SAAAA,IAInC0B,EACEC,KAAAC,EAAAC,SAAA,CAAA7B,SAAA,CAAAwB,EAAAA,IAAA,MAAA,CAAKC,IAAKjB,IACTR"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{jsx as r,jsxs as e,Fragment as t}from"react/jsx-runtime";import{useRef as n,useCallback as c,useEffect as o}from"react";const u=({children:u,onIntersection:i,onTimedObservationComplete:s,threshold:l=[.01,.5],wrapped:m})=>{const d=n(!1),a=n(!1),v=n(null),h=n(null),p=c(r=>{v.current&&r.unobserve(v.current)},[v]),b=c((r,e)=>{const t=r[0];if(null==t?void 0:t.isIntersecting){a.current||(i(),a.current=!0);const{intersectionRatio:r}=t;r>=.5?(h.current&&clearTimeout(h.current),h.current=setTimeout(()=>{d.current||(p(e),d.current=!0,null==s||s())},1e3)):h.current&&clearTimeout(h.current)}else h.current&&clearTimeout(h.current)},[i,s,p]);return o(()=>{const r=new IntersectionObserver(b,{threshold:l});return v.current&&r.observe(v.current),()=>{p(r)}},[b,l,p]),m?r("div",{ref:v,children:u}):e(t,{children:[r("div",{ref:v}),u]})};export{u as IntersectionObserver};
|
|
2
|
+
//# sourceMappingURL=ct-design-intersection-observer.browser.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ct-design-intersection-observer.browser.esm.js","sources":["../packages/components/InterSectionObserver/src/IntersectionObserver.tsx"],"sourcesContent":[null],"names":["WebIntersectionObserver","children","onIntersection","onTimedObservationComplete","threshold","wrapped","viewed","useRef","intersected","intersectionRef","timeoutInstance","unobserve","useCallback","observer","current","handleIO","entries","entry","isIntersecting","intersectionRatio","clearTimeout","setTimeout","useEffect","IntersectionObserver","observe","_jsx","ref","_jsxs","_Fragment"],"mappings":"+HAIM,MAAAA,EAA+D,EACnEC,WACAC,iBACAC,6BACAC,YAAY,CAAC,IAAM,IACnBC,cAEA,MAAMC,EAASC,GAAgB,GACzBC,EAAcD,GAAgB,GAC9BE,EAAkBF,EAA8B,MAChDG,EAAkBH,EAA8B,MAEhDI,EAAYC,EACfC,IACKJ,EAAgBK,SAClBD,EAASF,UAAUF,EAAgBK,UAGvC,CAACL,IAGGM,EAAWH,EACf,CAACI,EAAsCH,KACrC,MAAMI,EAAQD,EAAQ,GAEtB,GAAIC,aAAK,EAALA,EAAOC,eAAgB,CACpBV,EAAYM,UACfZ,IACAM,EAAYM,SAAU,GAGxB,MAAMK,kBAAEA,GAAsBF,EAE1BE,GAAqB,IACnBT,EAAgBI,SAClBM,aAAaV,EAAgBI,SAE/BJ,EAAgBI,QAAUO,WAAW,KAC9Bf,EAAOQ,UACVH,EAAUE,GACVP,EAAOQ,SAAU,EACjBX,SAAAA,MAED,MACMO,EAAgBI,SACzBM,aAAaV,EAAgBI,QAEhC,MACKJ,EAAgBI,SAClBM,aAAaV,EAAgBI,UAInC,CAACZ,EAAgBC,EAA4BQ,IAiB/C,OAdAW,EAAU,KACR,MAAMT,EAAW,IAAIU,qBAAqBR,EAAU,CAClDX,cAOF,OAJIK,EAAgBK,SAClBD,EAASW,QAAQf,EAAgBK,SAG5B,KACLH,EAAUE,KAEX,CAACE,EAAUX,EAAWO,IAErBN,EACKoB,SAAKC,IAAKjB,EAAkBR,SAAAA,IAInC0B,EACEC,EAAA,CAAA3B,SAAA,CAAAwB,EAAA,MAAA,CAAKC,IAAKjB,IACTR"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
var react = require('react');
|
|
5
|
+
|
|
6
|
+
const WebIntersectionObserver = ({ children, onIntersection, onTimedObservationComplete, threshold = [0.01, 0.5], wrapped, }) => {
|
|
7
|
+
const viewed = react.useRef(false);
|
|
8
|
+
const intersected = react.useRef(false);
|
|
9
|
+
const intersectionRef = react.useRef(null);
|
|
10
|
+
const timeoutInstance = react.useRef(null);
|
|
11
|
+
const unobserve = react.useCallback((observer) => {
|
|
12
|
+
if (intersectionRef.current) {
|
|
13
|
+
observer.unobserve(intersectionRef.current);
|
|
14
|
+
}
|
|
15
|
+
}, [intersectionRef]);
|
|
16
|
+
const handleIO = react.useCallback((entries, observer) => {
|
|
17
|
+
const entry = entries[0];
|
|
18
|
+
if (entry === null || entry === void 0 ? void 0 : entry.isIntersecting) {
|
|
19
|
+
if (!intersected.current) {
|
|
20
|
+
onIntersection();
|
|
21
|
+
intersected.current = true;
|
|
22
|
+
}
|
|
23
|
+
const { intersectionRatio } = entry;
|
|
24
|
+
if (intersectionRatio >= 0.5) {
|
|
25
|
+
if (timeoutInstance.current) {
|
|
26
|
+
clearTimeout(timeoutInstance.current);
|
|
27
|
+
}
|
|
28
|
+
timeoutInstance.current = setTimeout(() => {
|
|
29
|
+
if (!viewed.current) {
|
|
30
|
+
unobserve(observer);
|
|
31
|
+
viewed.current = true;
|
|
32
|
+
onTimedObservationComplete === null || onTimedObservationComplete === void 0 ? void 0 : onTimedObservationComplete();
|
|
33
|
+
}
|
|
34
|
+
}, 1000);
|
|
35
|
+
}
|
|
36
|
+
else if (timeoutInstance.current) {
|
|
37
|
+
clearTimeout(timeoutInstance.current);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
if (timeoutInstance.current) {
|
|
42
|
+
clearTimeout(timeoutInstance.current);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}, [onIntersection, onTimedObservationComplete, unobserve]);
|
|
46
|
+
react.useEffect(() => {
|
|
47
|
+
const observer = new IntersectionObserver(handleIO, {
|
|
48
|
+
threshold,
|
|
49
|
+
});
|
|
50
|
+
if (intersectionRef.current) {
|
|
51
|
+
observer.observe(intersectionRef.current);
|
|
52
|
+
}
|
|
53
|
+
return () => {
|
|
54
|
+
unobserve(observer);
|
|
55
|
+
};
|
|
56
|
+
}, [handleIO, threshold, unobserve]);
|
|
57
|
+
if (wrapped) {
|
|
58
|
+
return jsxRuntime.jsx("div", { ref: intersectionRef, children: children });
|
|
59
|
+
}
|
|
60
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { ref: intersectionRef }), children] }));
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
exports.IntersectionObserver = WebIntersectionObserver;
|
|
64
|
+
//# sourceMappingURL=ct-design-intersection-observer.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ct-design-intersection-observer.cjs.js","sources":["../packages/components/InterSectionObserver/src/IntersectionObserver.tsx"],"sourcesContent":[null],"names":["useRef","useCallback","useEffect","_jsx","_jsxs","_Fragment"],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
|
+
import { useRef, useCallback, useEffect } from 'react';
|
|
3
|
+
|
|
4
|
+
const WebIntersectionObserver = ({ children, onIntersection, onTimedObservationComplete, threshold = [0.01, 0.5], wrapped, }) => {
|
|
5
|
+
const viewed = useRef(false);
|
|
6
|
+
const intersected = useRef(false);
|
|
7
|
+
const intersectionRef = useRef(null);
|
|
8
|
+
const timeoutInstance = useRef(null);
|
|
9
|
+
const unobserve = useCallback((observer) => {
|
|
10
|
+
if (intersectionRef.current) {
|
|
11
|
+
observer.unobserve(intersectionRef.current);
|
|
12
|
+
}
|
|
13
|
+
}, [intersectionRef]);
|
|
14
|
+
const handleIO = useCallback((entries, observer) => {
|
|
15
|
+
const entry = entries[0];
|
|
16
|
+
if (entry === null || entry === void 0 ? void 0 : entry.isIntersecting) {
|
|
17
|
+
if (!intersected.current) {
|
|
18
|
+
onIntersection();
|
|
19
|
+
intersected.current = true;
|
|
20
|
+
}
|
|
21
|
+
const { intersectionRatio } = entry;
|
|
22
|
+
if (intersectionRatio >= 0.5) {
|
|
23
|
+
if (timeoutInstance.current) {
|
|
24
|
+
clearTimeout(timeoutInstance.current);
|
|
25
|
+
}
|
|
26
|
+
timeoutInstance.current = setTimeout(() => {
|
|
27
|
+
if (!viewed.current) {
|
|
28
|
+
unobserve(observer);
|
|
29
|
+
viewed.current = true;
|
|
30
|
+
onTimedObservationComplete === null || onTimedObservationComplete === void 0 ? void 0 : onTimedObservationComplete();
|
|
31
|
+
}
|
|
32
|
+
}, 1000);
|
|
33
|
+
}
|
|
34
|
+
else if (timeoutInstance.current) {
|
|
35
|
+
clearTimeout(timeoutInstance.current);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
if (timeoutInstance.current) {
|
|
40
|
+
clearTimeout(timeoutInstance.current);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}, [onIntersection, onTimedObservationComplete, unobserve]);
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
const observer = new IntersectionObserver(handleIO, {
|
|
46
|
+
threshold,
|
|
47
|
+
});
|
|
48
|
+
if (intersectionRef.current) {
|
|
49
|
+
observer.observe(intersectionRef.current);
|
|
50
|
+
}
|
|
51
|
+
return () => {
|
|
52
|
+
unobserve(observer);
|
|
53
|
+
};
|
|
54
|
+
}, [handleIO, threshold, unobserve]);
|
|
55
|
+
if (wrapped) {
|
|
56
|
+
return jsx("div", { ref: intersectionRef, children: children });
|
|
57
|
+
}
|
|
58
|
+
return (jsxs(Fragment, { children: [jsx("div", { ref: intersectionRef }), children] }));
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export { WebIntersectionObserver as IntersectionObserver };
|
|
62
|
+
//# sourceMappingURL=ct-design-intersection-observer.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ct-design-intersection-observer.esm.js","sources":["../packages/components/InterSectionObserver/src/IntersectionObserver.tsx"],"sourcesContent":[null],"names":["_jsx","_jsxs","_Fragment"],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
(function (global, factory) {
|
|
2
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react/jsx-runtime'), require('react')) :
|
|
3
|
+
typeof define === 'function' && define.amd ? define(['exports', 'react/jsx-runtime', 'react'], factory) :
|
|
4
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.CTDesignSystemIntersectionObserver = {}, global.jsxRuntime, global.React));
|
|
5
|
+
})(this, (function (exports, jsxRuntime, react) { 'use strict';
|
|
6
|
+
|
|
7
|
+
const WebIntersectionObserver = ({ children, onIntersection, onTimedObservationComplete, threshold = [0.01, 0.5], wrapped, }) => {
|
|
8
|
+
const viewed = react.useRef(false);
|
|
9
|
+
const intersected = react.useRef(false);
|
|
10
|
+
const intersectionRef = react.useRef(null);
|
|
11
|
+
const timeoutInstance = react.useRef(null);
|
|
12
|
+
const unobserve = react.useCallback((observer) => {
|
|
13
|
+
if (intersectionRef.current) {
|
|
14
|
+
observer.unobserve(intersectionRef.current);
|
|
15
|
+
}
|
|
16
|
+
}, [intersectionRef]);
|
|
17
|
+
const handleIO = react.useCallback((entries, observer) => {
|
|
18
|
+
const entry = entries[0];
|
|
19
|
+
if (entry === null || entry === void 0 ? void 0 : entry.isIntersecting) {
|
|
20
|
+
if (!intersected.current) {
|
|
21
|
+
onIntersection();
|
|
22
|
+
intersected.current = true;
|
|
23
|
+
}
|
|
24
|
+
const { intersectionRatio } = entry;
|
|
25
|
+
if (intersectionRatio >= 0.5) {
|
|
26
|
+
if (timeoutInstance.current) {
|
|
27
|
+
clearTimeout(timeoutInstance.current);
|
|
28
|
+
}
|
|
29
|
+
timeoutInstance.current = setTimeout(() => {
|
|
30
|
+
if (!viewed.current) {
|
|
31
|
+
unobserve(observer);
|
|
32
|
+
viewed.current = true;
|
|
33
|
+
onTimedObservationComplete === null || onTimedObservationComplete === void 0 ? void 0 : onTimedObservationComplete();
|
|
34
|
+
}
|
|
35
|
+
}, 1000);
|
|
36
|
+
}
|
|
37
|
+
else if (timeoutInstance.current) {
|
|
38
|
+
clearTimeout(timeoutInstance.current);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
if (timeoutInstance.current) {
|
|
43
|
+
clearTimeout(timeoutInstance.current);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}, [onIntersection, onTimedObservationComplete, unobserve]);
|
|
47
|
+
react.useEffect(() => {
|
|
48
|
+
const observer = new IntersectionObserver(handleIO, {
|
|
49
|
+
threshold,
|
|
50
|
+
});
|
|
51
|
+
if (intersectionRef.current) {
|
|
52
|
+
observer.observe(intersectionRef.current);
|
|
53
|
+
}
|
|
54
|
+
return () => {
|
|
55
|
+
unobserve(observer);
|
|
56
|
+
};
|
|
57
|
+
}, [handleIO, threshold, unobserve]);
|
|
58
|
+
if (wrapped) {
|
|
59
|
+
return jsxRuntime.jsx("div", { ref: intersectionRef, children: children });
|
|
60
|
+
}
|
|
61
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { ref: intersectionRef }), children] }));
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
exports.IntersectionObserver = WebIntersectionObserver;
|
|
65
|
+
|
|
66
|
+
}));
|
|
67
|
+
//# sourceMappingURL=ct-design-intersection-observer.umd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ct-design-intersection-observer.umd.js","sources":["../packages/components/InterSectionObserver/src/IntersectionObserver.tsx"],"sourcesContent":[null],"names":["useRef","useCallback","useEffect","_jsx","_jsxs","_Fragment"],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../packages/components/InterSectionObserver/src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACzE,cAAc,QAAQ,CAAC"}
|
package/dist/type.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
export interface IntersectionObserverProps {
|
|
3
|
+
children: ReactNode;
|
|
4
|
+
onIntersection: () => void;
|
|
5
|
+
onIntersectionComplete?: () => void;
|
|
6
|
+
onTimedObservationComplete?: () => void;
|
|
7
|
+
threshold?: number[];
|
|
8
|
+
timedThreshold?: number;
|
|
9
|
+
wrapped?: boolean;
|
|
10
|
+
observerBox?: [number, number, number | undefined, number | undefined];
|
|
11
|
+
gestureHorizontallyScrollable?: boolean;
|
|
12
|
+
triggerOnce?: boolean;
|
|
13
|
+
onUnmount?: () => void;
|
|
14
|
+
observeOnScroll?: boolean;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=type.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type.d.ts","sourceRoot":"","sources":["../packages/components/InterSectionObserver/src/type.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElC,MAAM,WAAW,yBAAyB;IAExC,QAAQ,EAAE,SAAS,CAAC;IAGpB,cAAc,EAAE,MAAM,IAAI,CAAC;IAG3B,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAC;IAGpC,0BAA0B,CAAC,EAAE,MAAM,IAAI,CAAC;IAGxC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IAGrB,cAAc,CAAC,EAAE,MAAM,CAAC;IAGxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAGlB,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAGvE,6BAA6B,CAAC,EAAE,OAAO,CAAC;IAGxC,WAAW,CAAC,EAAE,OAAO,CAAC;IAKtB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IAKvB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { RefObject } from 'react';
|
|
2
|
+
import { LayoutChangeEvent, View } from 'react-native';
|
|
3
|
+
export type InViewHookResponse<T> = RefObject<T>;
|
|
4
|
+
export interface IntersectionOptions extends IntersectionObserverInit {
|
|
5
|
+
root?: Element | null;
|
|
6
|
+
rootMargin?: string;
|
|
7
|
+
threshold?: number[];
|
|
8
|
+
triggerOnce?: boolean;
|
|
9
|
+
skip?: boolean;
|
|
10
|
+
delay?: number;
|
|
11
|
+
onChange?: (inView: boolean) => void;
|
|
12
|
+
onIntersectionComplete?: () => void;
|
|
13
|
+
customIntersectionRatio?: {
|
|
14
|
+
horizontal: number;
|
|
15
|
+
vertical: number;
|
|
16
|
+
};
|
|
17
|
+
fireEventOnlyOnEnterInViewPort?: boolean;
|
|
18
|
+
pageName?: string;
|
|
19
|
+
timedThreshold?: number;
|
|
20
|
+
onTimedObservationComplete?: () => void;
|
|
21
|
+
minimumObservationTime?: number;
|
|
22
|
+
observerBox?: [number, number, number | undefined, number | undefined];
|
|
23
|
+
gestureHorizontallyScrollable?: boolean;
|
|
24
|
+
observeOnScroll?: boolean;
|
|
25
|
+
onUnmount?: () => void;
|
|
26
|
+
checkFullVisibility?: boolean;
|
|
27
|
+
}
|
|
28
|
+
export declare enum SCROLLING_TYPE {
|
|
29
|
+
NONE = "none",
|
|
30
|
+
HORIZONTAL = "horizontal",
|
|
31
|
+
VERTICAL = "vertical"
|
|
32
|
+
}
|
|
33
|
+
interface Thresholds {
|
|
34
|
+
[key: number]: () => void;
|
|
35
|
+
}
|
|
36
|
+
export interface UseInViewProps {
|
|
37
|
+
thresholds: Thresholds;
|
|
38
|
+
onExit?: () => void;
|
|
39
|
+
id?: string;
|
|
40
|
+
}
|
|
41
|
+
export interface UseInViewReturn {
|
|
42
|
+
viewRef: React.RefObject<View>;
|
|
43
|
+
visiblePercent: number;
|
|
44
|
+
isInView: boolean;
|
|
45
|
+
onLayout: (event: LayoutChangeEvent) => void;
|
|
46
|
+
}
|
|
47
|
+
export {};
|
|
48
|
+
//# sourceMappingURL=useInViewType.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useInViewType.d.ts","sourceRoot":"","sources":["../packages/components/InterSectionObserver/src/useInViewType.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,EAAE,iBAAiB,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAKvD,MAAM,MAAM,kBAAkB,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC;AAEjD,MAAM,WAAW,mBAAoB,SAAQ,wBAAwB;IAEnE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAEtB,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IAErB,WAAW,CAAC,EAAE,OAAO,CAAC;IAGtB,IAAI,CAAC,EAAE,OAAO,CAAC;IAGf,KAAK,CAAC,EAAE,MAAM,CAAC;IAKf,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAGrC,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAC;IAMpC,uBAAuB,CAAC,EAAE;QACxB,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IAKF,8BAA8B,CAAC,EAAE,OAAO,CAAC;IAKzC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAGlB,cAAc,CAAC,EAAE,MAAM,CAAC;IAGxB,0BAA0B,CAAC,EAAE,MAAM,IAAI,CAAC;IAGxC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAGhC,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAEvE,6BAA6B,CAAC,EAAE,OAAO,CAAC;IAMxC,eAAe,CAAC,EAAE,OAAO,CAAC;IAK1B,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IAMvB,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,oBAAY,cAAc;IACxB,IAAI,SAAS;IACb,UAAU,eAAe;IACzB,QAAQ,aAAa;CACtB;AAED,UAAU,UAAU;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAC9C"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { IntersectionOptions, InViewHookResponse } from './useInViewType';
|
|
2
|
+
declare const useInView: <T>({ threshold, timedThreshold, onChange, onIntersectionComplete, onTimedObservationComplete, minimumObservationTime, observerBox, gestureHorizontallyScrollable, triggerOnce, observeOnScroll, onUnmount, checkFullVisibility, }: IntersectionOptions) => InViewHookResponse<T>;
|
|
3
|
+
export default useInView;
|
|
4
|
+
//# sourceMappingURL=useinView.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useinView.d.ts","sourceRoot":"","sources":["../packages/components/InterSectionObserver/src/useinView.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAgI1E,QAAA,MAAM,SAAS,GAAI,CAAC,EAAE,gOAanB,mBAAmB,KAAG,kBAAkB,CAAC,CAAC,CAoI5C,CAAC;AAEF,eAAe,SAAS,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cleartrip/ct-design-intersection-observer",
|
|
3
|
+
"version": "4.0.0-SNAPSHOT-test.0",
|
|
4
|
+
"description": "Intersection Observer Component",
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
|
+
"main": "./dist/ct-design-intersection-observer.cjs.js",
|
|
7
|
+
"react-native": "src/index.ts",
|
|
8
|
+
"jsnext:main": "dist/ct-design-intersection-observer.esm.js",
|
|
9
|
+
"module": "dist/ct-design-intersection-observer.esm.js",
|
|
10
|
+
"sideEffects": false,
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/ct-design-intersection-observer.d.ts",
|
|
14
|
+
"import": "./dist/ct-design-intersection-observer.esm.js",
|
|
15
|
+
"default": "./dist/ct-design-intersection-observer.cjs.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"browser": {
|
|
19
|
+
"./dist/ct-design-intersection-observer.esm.js": "./dist/ct-design-intersection-observer.browser.esm.js",
|
|
20
|
+
"./dist/ct-design-intersection-observer.cjs.js": "./dist/ct-design-intersection-observer.browser.cjs.js"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"src"
|
|
25
|
+
],
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@cleartrip/ct-design-scroll-container": "4.0.0-SNAPSHOT-test.0",
|
|
28
|
+
"@cleartrip/ct-design-container": "4.0.0-SNAPSHOT-test.0",
|
|
29
|
+
"@cleartrip/ct-design-style-manager": "4.0.0-SNAPSHOT-test.0",
|
|
30
|
+
"@cleartrip/ct-design-theme": "4.0.0-SNAPSHOT-test.0",
|
|
31
|
+
"@cleartrip/ct-design-list": "4.0.0-SNAPSHOT-test.0",
|
|
32
|
+
"@cleartrip/ct-design-common-utils": "4.0.0-SNAPSHOT-test.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@cleartrip/ct-design-types": "4.0.0-SNAPSHOT-test.0"
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"react": ">=16.8.0",
|
|
39
|
+
"react-dom": ">=16.8.0",
|
|
40
|
+
"react-native": ">=0.78.0"
|
|
41
|
+
},
|
|
42
|
+
"peerDependenciesMeta": {
|
|
43
|
+
"react-native": {
|
|
44
|
+
"optional": true
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"access": "public"
|
|
49
|
+
},
|
|
50
|
+
"author": "Cleartrip",
|
|
51
|
+
"license": "ISC",
|
|
52
|
+
"scripts": {
|
|
53
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
54
|
+
"watch-package": "rollup -c -w",
|
|
55
|
+
"build-package": "rollup -c",
|
|
56
|
+
"build-package:clean": "rm -rf dist && rollup -c",
|
|
57
|
+
"publish-package:local": "yalc publish"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { View } from 'react-native';
|
|
4
|
+
import useInView from './useinView';
|
|
5
|
+
|
|
6
|
+
import { IntersectionObserverProps } from './type';
|
|
7
|
+
|
|
8
|
+
const InterSectionObserver: React.FC<IntersectionObserverProps> = ({
|
|
9
|
+
children,
|
|
10
|
+
onIntersection,
|
|
11
|
+
onTimedObservationComplete,
|
|
12
|
+
threshold = [0.01, 0.05],
|
|
13
|
+
timedThreshold = 1000,
|
|
14
|
+
wrapped = false,
|
|
15
|
+
observerBox,
|
|
16
|
+
gestureHorizontallyScrollable,
|
|
17
|
+
triggerOnce,
|
|
18
|
+
onIntersectionComplete,
|
|
19
|
+
onUnmount,
|
|
20
|
+
observeOnScroll,
|
|
21
|
+
}) => {
|
|
22
|
+
const ref = useInView<View>({
|
|
23
|
+
onChange: onIntersection,
|
|
24
|
+
onTimedObservationComplete,
|
|
25
|
+
onIntersectionComplete,
|
|
26
|
+
threshold,
|
|
27
|
+
timedThreshold: timedThreshold,
|
|
28
|
+
minimumObservationTime: timedThreshold,
|
|
29
|
+
observerBox,
|
|
30
|
+
gestureHorizontallyScrollable,
|
|
31
|
+
triggerOnce,
|
|
32
|
+
onUnmount,
|
|
33
|
+
observeOnScroll,
|
|
34
|
+
});
|
|
35
|
+
if (wrapped) {
|
|
36
|
+
return (
|
|
37
|
+
<View ref={ref} collapsable={false}>
|
|
38
|
+
{children}
|
|
39
|
+
</View>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
return (
|
|
43
|
+
<>
|
|
44
|
+
<View ref={ref} collapsable={false} />
|
|
45
|
+
{children}
|
|
46
|
+
</>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export default InterSectionObserver;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import React, { useCallback, useEffect, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
import { IntersectionObserverProps } from './type';
|
|
4
|
+
|
|
5
|
+
const WebIntersectionObserver: React.FC<IntersectionObserverProps> = ({
|
|
6
|
+
children,
|
|
7
|
+
onIntersection,
|
|
8
|
+
onTimedObservationComplete,
|
|
9
|
+
threshold = [0.01, 0.5],
|
|
10
|
+
wrapped,
|
|
11
|
+
}) => {
|
|
12
|
+
const viewed = useRef<boolean>(false);
|
|
13
|
+
const intersected = useRef<boolean>(false);
|
|
14
|
+
const intersectionRef = useRef<HTMLDivElement | null>(null);
|
|
15
|
+
const timeoutInstance = useRef<NodeJS.Timeout | null>(null);
|
|
16
|
+
|
|
17
|
+
const unobserve = useCallback(
|
|
18
|
+
(observer: IntersectionObserver) => {
|
|
19
|
+
if (intersectionRef.current) {
|
|
20
|
+
observer.unobserve(intersectionRef.current);
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
[intersectionRef],
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
const handleIO = useCallback(
|
|
27
|
+
(entries: IntersectionObserverEntry[], observer: IntersectionObserver) => {
|
|
28
|
+
const entry = entries[0];
|
|
29
|
+
|
|
30
|
+
if (entry?.isIntersecting) {
|
|
31
|
+
if (!intersected.current) {
|
|
32
|
+
onIntersection();
|
|
33
|
+
intersected.current = true;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const { intersectionRatio } = entry;
|
|
37
|
+
|
|
38
|
+
if (intersectionRatio >= 0.5) {
|
|
39
|
+
if (timeoutInstance.current) {
|
|
40
|
+
clearTimeout(timeoutInstance.current);
|
|
41
|
+
}
|
|
42
|
+
timeoutInstance.current = setTimeout(() => {
|
|
43
|
+
if (!viewed.current) {
|
|
44
|
+
unobserve(observer);
|
|
45
|
+
viewed.current = true;
|
|
46
|
+
onTimedObservationComplete?.();
|
|
47
|
+
}
|
|
48
|
+
}, 1000);
|
|
49
|
+
} else if (timeoutInstance.current) {
|
|
50
|
+
clearTimeout(timeoutInstance.current);
|
|
51
|
+
}
|
|
52
|
+
} else {
|
|
53
|
+
if (timeoutInstance.current) {
|
|
54
|
+
clearTimeout(timeoutInstance.current);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
[onIntersection, onTimedObservationComplete, unobserve],
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
const observer = new IntersectionObserver(handleIO, {
|
|
63
|
+
threshold,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
if (intersectionRef.current) {
|
|
67
|
+
observer.observe(intersectionRef.current);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return () => {
|
|
71
|
+
unobserve(observer);
|
|
72
|
+
};
|
|
73
|
+
}, [handleIO, threshold, unobserve]);
|
|
74
|
+
|
|
75
|
+
if (wrapped) {
|
|
76
|
+
return <div ref={intersectionRef}>{children}</div>;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<>
|
|
81
|
+
<div ref={intersectionRef} />
|
|
82
|
+
{children}
|
|
83
|
+
</>
|
|
84
|
+
);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export default WebIntersectionObserver;
|
package/src/index.ts
ADDED
package/src/type.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface IntersectionObserverProps {
|
|
4
|
+
/** The content to be observed for intersection */
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
|
|
7
|
+
/** Callback function triggered when intersection occurs */
|
|
8
|
+
onIntersection: () => void;
|
|
9
|
+
|
|
10
|
+
/** Callback function triggered when intersection completes and element goes out of view */
|
|
11
|
+
onIntersectionComplete?: () => void;
|
|
12
|
+
|
|
13
|
+
/** Optional callback function triggered when timed observation is complete */
|
|
14
|
+
onTimedObservationComplete?: () => void;
|
|
15
|
+
|
|
16
|
+
/** Array of threshold values between 0 and 1, indicating at what percentage of the target's visibility the observer's callback should be executed */
|
|
17
|
+
threshold?: number[];
|
|
18
|
+
|
|
19
|
+
/** Time in milliseconds to wait before triggering onTimedObservationComplete */
|
|
20
|
+
timedThreshold?: number;
|
|
21
|
+
|
|
22
|
+
/** Whether the observed element should be wrapped in a containing element */
|
|
23
|
+
wrapped?: boolean;
|
|
24
|
+
|
|
25
|
+
/** observer box: instead of root margin */
|
|
26
|
+
observerBox?: [number, number, number | undefined, number | undefined];
|
|
27
|
+
|
|
28
|
+
/** Whether the observed element should be horizontally scrollable */
|
|
29
|
+
gestureHorizontallyScrollable?: boolean;
|
|
30
|
+
|
|
31
|
+
/** Whether the observed element should be triggered once */
|
|
32
|
+
triggerOnce?: boolean;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* handlle umount
|
|
36
|
+
*/
|
|
37
|
+
onUnmount?: () => void;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* observe on scroll
|
|
41
|
+
*/
|
|
42
|
+
observeOnScroll?: boolean;
|
|
43
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { RefObject } from 'react';
|
|
2
|
+
|
|
3
|
+
import { LayoutChangeEvent, View } from 'react-native';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The Hook response supports both array and object destructing
|
|
7
|
+
*/
|
|
8
|
+
export type InViewHookResponse<T> = RefObject<T>;
|
|
9
|
+
|
|
10
|
+
export interface IntersectionOptions extends IntersectionObserverInit {
|
|
11
|
+
/** The IntersectionObserver interface's read-only `root` property identifies the Element or Document whose bounds are treated as the bounding box of the viewport for the element which is the observer's target. If the `root` is null, then the bounds of the actual document viewport are used.*/
|
|
12
|
+
root?: Element | null;
|
|
13
|
+
/** Margin around the root. Can have values similar to the CSS margin property, e.g. `10px 20px 30px 40px` (top, right, bottom, left). */
|
|
14
|
+
rootMargin?: string;
|
|
15
|
+
/** 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. */
|
|
16
|
+
threshold?: number[];
|
|
17
|
+
/** Only trigger the inView callback once */
|
|
18
|
+
triggerOnce?: boolean;
|
|
19
|
+
|
|
20
|
+
/** Skip assigning the observer to the `ref` */
|
|
21
|
+
skip?: boolean;
|
|
22
|
+
|
|
23
|
+
/** Set a minimum delay in milliseconds between notifications */
|
|
24
|
+
delay?: number;
|
|
25
|
+
|
|
26
|
+
/** Callback function triggered whenever the in-view state changes
|
|
27
|
+
* @param inView - Boolean indicating if element is in viewport
|
|
28
|
+
*/
|
|
29
|
+
onChange?: (inView: boolean) => void;
|
|
30
|
+
|
|
31
|
+
/** Callback function triggered when intersection completes and element goes out of view */
|
|
32
|
+
onIntersectionComplete?: () => void;
|
|
33
|
+
|
|
34
|
+
/** Custom intersection ratio thresholds for horizontal and vertical directions
|
|
35
|
+
* @property {number} horizontal - Percentage (0-100) for horizontal threshold
|
|
36
|
+
* @property {number} vertical - Percentage (0-100) for vertical threshold
|
|
37
|
+
*/
|
|
38
|
+
customIntersectionRatio?: {
|
|
39
|
+
horizontal: number;
|
|
40
|
+
vertical: number;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/** Controls if the event should only fire on entering viewport
|
|
44
|
+
* @default true
|
|
45
|
+
*/
|
|
46
|
+
fireEventOnlyOnEnterInViewPort?: boolean;
|
|
47
|
+
|
|
48
|
+
/** Unique identifier for the page where hook is used
|
|
49
|
+
* Used to calculate rootMargin
|
|
50
|
+
*/
|
|
51
|
+
pageName?: string;
|
|
52
|
+
|
|
53
|
+
/** Time threshold in milliseconds for observation */
|
|
54
|
+
timedThreshold?: number;
|
|
55
|
+
|
|
56
|
+
/** Callback fired when timed observation is complete */
|
|
57
|
+
onTimedObservationComplete?: () => void;
|
|
58
|
+
|
|
59
|
+
/** Minimum time in milliseconds required for observation */
|
|
60
|
+
minimumObservationTime?: number;
|
|
61
|
+
|
|
62
|
+
/** observer box: instead of root margin */
|
|
63
|
+
observerBox?: [number, number, number | undefined, number | undefined];
|
|
64
|
+
|
|
65
|
+
gestureHorizontallyScrollable?: boolean;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Observe the element on scroll
|
|
69
|
+
* @default false
|
|
70
|
+
*/
|
|
71
|
+
observeOnScroll?: boolean;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Callback function triggered when the hook is unmounted
|
|
75
|
+
*/
|
|
76
|
+
onUnmount?: () => void;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* check full visibility of the element
|
|
80
|
+
* @default false
|
|
81
|
+
*/
|
|
82
|
+
checkFullVisibility?: boolean;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export enum SCROLLING_TYPE {
|
|
86
|
+
NONE = 'none',
|
|
87
|
+
HORIZONTAL = 'horizontal',
|
|
88
|
+
VERTICAL = 'vertical',
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
interface Thresholds {
|
|
92
|
+
[key: number]: () => void;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface UseInViewProps {
|
|
96
|
+
thresholds: Thresholds;
|
|
97
|
+
onExit?: () => void;
|
|
98
|
+
id?: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface UseInViewReturn {
|
|
102
|
+
viewRef: React.RefObject<View>;
|
|
103
|
+
visiblePercent: number;
|
|
104
|
+
isInView: boolean;
|
|
105
|
+
onLayout: (event: LayoutChangeEvent) => void;
|
|
106
|
+
}
|
package/src/useinView.ts
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
import { Dimensions, View } from 'react-native';
|
|
4
|
+
import { useAddObservableChild, useGetScrolling } from '@cleartrip/ct-design-scroll-container';
|
|
5
|
+
import { useListItem } from '@cleartrip/ct-design-list';
|
|
6
|
+
import { promiseHandler } from '@cleartrip/ct-design-common-utils';
|
|
7
|
+
|
|
8
|
+
import { IntersectionOptions, InViewHookResponse } from './useInViewType';
|
|
9
|
+
|
|
10
|
+
const { width, height } = Dimensions.get('window');
|
|
11
|
+
/**
|
|
12
|
+
* todo
|
|
13
|
+
* horizontal scroll and root margin
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
interface VisibilityState {
|
|
17
|
+
visibleRef: React.MutableRefObject<number>;
|
|
18
|
+
timeoutVisibleRef: React.MutableRefObject<boolean>;
|
|
19
|
+
timeoutVisibleStartRef: React.MutableRefObject<{ start: number; end: number }>;
|
|
20
|
+
triggerOnceValue: React.MutableRefObject<boolean>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const calculateVisibility = (
|
|
24
|
+
rectTop: number,
|
|
25
|
+
rectBottom: number,
|
|
26
|
+
rectHeight: number,
|
|
27
|
+
rectLeft: number,
|
|
28
|
+
rectRight: number,
|
|
29
|
+
rectWidth: number,
|
|
30
|
+
observerBox: [number, number, number | undefined, number | undefined],
|
|
31
|
+
): { verticalVisibility: number; horizontalVisibility: number } => {
|
|
32
|
+
const [top, left, _height = height, _width = width] = observerBox;
|
|
33
|
+
|
|
34
|
+
// Calculate vertical visibility
|
|
35
|
+
let verticalVisibility = 0;
|
|
36
|
+
if (rectHeight) {
|
|
37
|
+
if (rectTop >= top && rectBottom <= _height) {
|
|
38
|
+
verticalVisibility = 100;
|
|
39
|
+
} else if (rectTop < top) {
|
|
40
|
+
verticalVisibility = ((rectBottom - top) / rectHeight) * 100;
|
|
41
|
+
} else {
|
|
42
|
+
verticalVisibility = ((_height - rectTop) / rectHeight) * 100;
|
|
43
|
+
}
|
|
44
|
+
} else {
|
|
45
|
+
const visibleHeight = rectTop > top && rectTop < _height ? rectTop - top : 0;
|
|
46
|
+
verticalVisibility = (visibleHeight / _height) * 100;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Calculate horizontal visibility
|
|
50
|
+
let horizontalVisibility = 0;
|
|
51
|
+
if (rectWidth) {
|
|
52
|
+
if (rectLeft >= left && rectRight <= _width) {
|
|
53
|
+
horizontalVisibility = 100;
|
|
54
|
+
} else if (rectLeft < left) {
|
|
55
|
+
horizontalVisibility = ((rectRight - left) / rectWidth) * 100;
|
|
56
|
+
} else {
|
|
57
|
+
horizontalVisibility = ((_width - rectLeft) / rectWidth) * 100;
|
|
58
|
+
}
|
|
59
|
+
} else {
|
|
60
|
+
const visibleWidth = rectLeft > left && rectLeft < _width ? rectLeft - left : 0;
|
|
61
|
+
horizontalVisibility = (visibleWidth / _width) * 100;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return { verticalVisibility, horizontalVisibility };
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const handleVisibilityChange = (
|
|
68
|
+
visibility: number,
|
|
69
|
+
threshold: number[],
|
|
70
|
+
state: VisibilityState,
|
|
71
|
+
callbacks: {
|
|
72
|
+
onChange?: (visible: boolean) => void;
|
|
73
|
+
onIntersectionComplete?: () => void;
|
|
74
|
+
onTimedObservationComplete?: () => void;
|
|
75
|
+
triggerOnce?: boolean;
|
|
76
|
+
minimumObservationTime: number;
|
|
77
|
+
observerMethod?: (visibleItems?: Set<number>, isScrolling?: boolean) => void;
|
|
78
|
+
},
|
|
79
|
+
) => {
|
|
80
|
+
const { visibleRef, timeoutVisibleRef, timeoutVisibleStartRef, triggerOnceValue } = state;
|
|
81
|
+
const {
|
|
82
|
+
onChange,
|
|
83
|
+
onIntersectionComplete,
|
|
84
|
+
onTimedObservationComplete,
|
|
85
|
+
triggerOnce,
|
|
86
|
+
minimumObservationTime,
|
|
87
|
+
observerMethod,
|
|
88
|
+
} = callbacks;
|
|
89
|
+
|
|
90
|
+
if (visibility === 0) {
|
|
91
|
+
if (visibleRef.current > 0) {
|
|
92
|
+
onIntersectionComplete?.();
|
|
93
|
+
}
|
|
94
|
+
visibleRef.current = 0;
|
|
95
|
+
timeoutVisibleRef.current = false;
|
|
96
|
+
timeoutVisibleStartRef.current.end = 0;
|
|
97
|
+
timeoutVisibleStartRef.current.start = 0;
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const thresholdVisibility = threshold[visibleRef.current] * 100;
|
|
102
|
+
|
|
103
|
+
if (visibility >= thresholdVisibility) {
|
|
104
|
+
if (!triggerOnceValue.current) {
|
|
105
|
+
timeoutVisibleRef.current = true;
|
|
106
|
+
visibleRef.current = visibleRef.current + 1;
|
|
107
|
+
|
|
108
|
+
if (timeoutVisibleStartRef.current.start === 0) {
|
|
109
|
+
timeoutVisibleStartRef.current.start = Date.now();
|
|
110
|
+
} else {
|
|
111
|
+
timeoutVisibleStartRef.current.end = Date.now();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (triggerOnce) {
|
|
115
|
+
triggerOnceValue.current = true;
|
|
116
|
+
}
|
|
117
|
+
onChange?.(true);
|
|
118
|
+
setTimeout(() => {
|
|
119
|
+
observerMethod?.();
|
|
120
|
+
}, minimumObservationTime);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (
|
|
125
|
+
timeoutVisibleRef.current &&
|
|
126
|
+
timeoutVisibleStartRef.current.start > 0 &&
|
|
127
|
+
Date.now() - timeoutVisibleStartRef.current.start >= minimumObservationTime
|
|
128
|
+
) {
|
|
129
|
+
timeoutVisibleRef.current = false;
|
|
130
|
+
onTimedObservationComplete?.();
|
|
131
|
+
timeoutVisibleStartRef.current.end = -1;
|
|
132
|
+
timeoutVisibleStartRef.current.start = -1;
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const useInView = <T>({
|
|
137
|
+
threshold = [0.01, 0.5],
|
|
138
|
+
timedThreshold = 1000,
|
|
139
|
+
onChange,
|
|
140
|
+
onIntersectionComplete,
|
|
141
|
+
onTimedObservationComplete,
|
|
142
|
+
minimumObservationTime = timedThreshold,
|
|
143
|
+
observerBox = [0, 0, height, width],
|
|
144
|
+
gestureHorizontallyScrollable = false,
|
|
145
|
+
triggerOnce = false,
|
|
146
|
+
observeOnScroll = false,
|
|
147
|
+
onUnmount,
|
|
148
|
+
checkFullVisibility = false,
|
|
149
|
+
}: IntersectionOptions): InViewHookResponse<T> => {
|
|
150
|
+
const ref = useRef<View>(null);
|
|
151
|
+
const visibleRef = useRef(0);
|
|
152
|
+
const timeoutVisibleRef = useRef(false);
|
|
153
|
+
const timeoutVisibleStartRef = useRef({ start: 0, end: 0 });
|
|
154
|
+
const triggerOnceValue = useRef(false);
|
|
155
|
+
|
|
156
|
+
const { horizontal } = useGetScrolling();
|
|
157
|
+
const { listId } = useListItem();
|
|
158
|
+
|
|
159
|
+
const observerMethod = useCallback(
|
|
160
|
+
(visibleItems?: Set<number>, isScrolling?: boolean) => {
|
|
161
|
+
if (!observeOnScroll && isScrolling) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (visibleItems) {
|
|
165
|
+
const visibleItem = visibleItems?.has(listId);
|
|
166
|
+
|
|
167
|
+
if (visibleItem) {
|
|
168
|
+
onTimedObservationComplete?.();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (visibleItem && visibleRef.current === 0) {
|
|
172
|
+
visibleRef.current = 1;
|
|
173
|
+
onChange?.(true);
|
|
174
|
+
return;
|
|
175
|
+
} else if (!visibleItem && visibleRef.current === 1) {
|
|
176
|
+
visibleRef.current = 0;
|
|
177
|
+
onIntersectionComplete?.();
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
promiseHandler.add(() => {
|
|
184
|
+
return new Promise<void>((resolve) => {
|
|
185
|
+
if (!ref.current) {
|
|
186
|
+
resolve();
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
ref.current?.measure((_x, _y, width, height, pageX, pageY) => {
|
|
190
|
+
const { verticalVisibility, horizontalVisibility } = calculateVisibility(
|
|
191
|
+
pageY,
|
|
192
|
+
pageY + height,
|
|
193
|
+
height,
|
|
194
|
+
pageX,
|
|
195
|
+
pageX + width,
|
|
196
|
+
width,
|
|
197
|
+
observerBox,
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
const visiblePercentage = threshold[0] * 100;
|
|
201
|
+
const isVisible =
|
|
202
|
+
horizontal || gestureHorizontallyScrollable
|
|
203
|
+
? horizontalVisibility >= visiblePercentage
|
|
204
|
+
: verticalVisibility >= visiblePercentage;
|
|
205
|
+
const visibility = horizontal ? horizontalVisibility : verticalVisibility;
|
|
206
|
+
|
|
207
|
+
const totalVisibility = (horizontalVisibility * verticalVisibility) / 100;
|
|
208
|
+
const isTotalVisible = totalVisibility >= visiblePercentage;
|
|
209
|
+
|
|
210
|
+
const state = {
|
|
211
|
+
visibleRef,
|
|
212
|
+
timeoutVisibleRef,
|
|
213
|
+
timeoutVisibleStartRef,
|
|
214
|
+
triggerOnceValue,
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
const callbacks = {
|
|
218
|
+
onChange,
|
|
219
|
+
onIntersectionComplete,
|
|
220
|
+
onTimedObservationComplete,
|
|
221
|
+
triggerOnce,
|
|
222
|
+
minimumObservationTime,
|
|
223
|
+
observerMethod,
|
|
224
|
+
};
|
|
225
|
+
if (isTotalVisible) {
|
|
226
|
+
handleVisibilityChange(totalVisibility, threshold, state, callbacks);
|
|
227
|
+
} else if (!checkFullVisibility && isVisible) {
|
|
228
|
+
handleVisibilityChange(visibility, threshold, state, callbacks);
|
|
229
|
+
} else {
|
|
230
|
+
handleVisibilityChange(0, threshold, state, callbacks);
|
|
231
|
+
}
|
|
232
|
+
resolve();
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
}, ref.current);
|
|
236
|
+
},
|
|
237
|
+
[
|
|
238
|
+
checkFullVisibility,
|
|
239
|
+
gestureHorizontallyScrollable,
|
|
240
|
+
horizontal,
|
|
241
|
+
listId,
|
|
242
|
+
minimumObservationTime,
|
|
243
|
+
observeOnScroll,
|
|
244
|
+
observerBox,
|
|
245
|
+
onChange,
|
|
246
|
+
onIntersectionComplete,
|
|
247
|
+
onTimedObservationComplete,
|
|
248
|
+
threshold,
|
|
249
|
+
triggerOnce,
|
|
250
|
+
],
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
const addObservable = useCallback(() => {
|
|
254
|
+
return { observe: observerMethod, layout: { X: 0, Y: 0 } };
|
|
255
|
+
}, [observerMethod]);
|
|
256
|
+
|
|
257
|
+
useAddObservableChild(addObservable);
|
|
258
|
+
|
|
259
|
+
const handleUnmount = useCallback(() => {
|
|
260
|
+
onUnmount?.();
|
|
261
|
+
promiseHandler.clear();
|
|
262
|
+
visibleRef.current = 0;
|
|
263
|
+
timeoutVisibleRef.current = false;
|
|
264
|
+
timeoutVisibleStartRef.current.end = 0;
|
|
265
|
+
timeoutVisibleStartRef.current.start = 0;
|
|
266
|
+
triggerOnceValue.current = false;
|
|
267
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
268
|
+
}, []);
|
|
269
|
+
|
|
270
|
+
useEffect(() => {
|
|
271
|
+
setTimeout(() => {
|
|
272
|
+
observerMethod();
|
|
273
|
+
}, 400);
|
|
274
|
+
return () => {
|
|
275
|
+
handleUnmount();
|
|
276
|
+
};
|
|
277
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
278
|
+
}, [handleUnmount]);
|
|
279
|
+
|
|
280
|
+
return ref as InViewHookResponse<T>;
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
export default useInView;
|