@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 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,5 @@
1
+ import React from 'react';
2
+ import { IntersectionObserverProps } from './type';
3
+ declare const WebIntersectionObserver: React.FC<IntersectionObserverProps>;
4
+ export default WebIntersectionObserver;
5
+ //# sourceMappingURL=IntersectionObserver.d.ts.map
@@ -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,5 @@
1
+ import React from 'react';
2
+ import { IntersectionObserverProps } from './type';
3
+ declare const InterSectionObserver: React.FC<IntersectionObserverProps>;
4
+ export default InterSectionObserver;
5
+ //# sourceMappingURL=IntersectionObserver.native.d.ts.map
@@ -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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"}
@@ -0,0 +1,3 @@
1
+ export { default as IntersectionObserver } from './IntersectionObserver';
2
+ export * from './type';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -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
@@ -0,0 +1,2 @@
1
+ export { default as IntersectionObserver } from './IntersectionObserver';
2
+ export * from './type';
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
+ }
@@ -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;