@kushagradhawan/kookie-ui 0.1.38 → 0.1.39
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/dist/cjs/hooks/use-body-pointer-events-cleanup.d.ts.map +1 -1
- package/dist/cjs/hooks/use-body-pointer-events-cleanup.js +1 -1
- package/dist/cjs/hooks/use-body-pointer-events-cleanup.js.map +3 -3
- package/dist/esm/hooks/use-body-pointer-events-cleanup.d.ts.map +1 -1
- package/dist/esm/hooks/use-body-pointer-events-cleanup.js +1 -1
- package/dist/esm/hooks/use-body-pointer-events-cleanup.js.map +3 -3
- package/package.json +1 -1
- package/src/hooks/use-body-pointer-events-cleanup.ts +58 -21
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-body-pointer-events-cleanup.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-body-pointer-events-cleanup.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"use-body-pointer-events-cleanup.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-body-pointer-events-cleanup.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AACH,wBAAgB,2BAA2B,SAqE1C"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var b=Object.create;var i=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var v=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,E=Object.prototype.hasOwnProperty;var p=(e,t)=>{for(var o in t)i(e,o,{get:t[o],enumerable:!0})},s=(e,t,o,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of v(t))!E.call(e,r)&&r!==o&&i(e,r,{get:()=>t[r],enumerable:!(n=y(t,r))||n.enumerable});return e};var w=(e,t,o)=>(o=e!=null?b(f(e)):{},s(t||!e||!e.__esModule?i(o,"default",{value:e,enumerable:!0}):o,e)),L=e=>s(i({},"__esModule",{value:!0}),e);var h={};p(h,{useBodyPointerEventsCleanup:()=>k});module.exports=L(h);var O=w(require("react"));let a=!1;function k(){O.useEffect(()=>{if(typeof document>"u")return;let e;const t=()=>!!document.querySelector('[role="dialog"][aria-modal="true"], [role="alertdialog"][aria-modal="true"]'),o=()=>{document.body.style.pointerEvents==="none"&&!t()&&(document.body.style.pointerEvents="")},n=(d=50)=>{e&&window.clearTimeout(e),e=window.setTimeout(o,d)};if(n(100),a)return()=>{e&&window.clearTimeout(e)};a=!0;const r=()=>n(50),u=d=>{(d.key==="Escape"||d.key==="Enter"||d.key===" ")&&n(50)},c=()=>{document.hidden||n(50)},l=()=>n(0),m=()=>n(0);return document.addEventListener("pointerup",r,!0),document.addEventListener("click",r,!0),document.addEventListener("keydown",u,!0),document.addEventListener("keyup",u,!0),document.addEventListener("visibilitychange",c),document.addEventListener("transitionend",l,!0),document.addEventListener("animationend",m,!0),new MutationObserver(()=>n(0)).observe(document.body,{attributes:!0,attributeFilter:["style"]}),new MutationObserver(()=>n(0)).observe(document,{childList:!0,subtree:!0}),()=>{e&&window.clearTimeout(e)}},[])}
|
|
2
2
|
//# sourceMappingURL=use-body-pointer-events-cleanup.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/hooks/use-body-pointer-events-cleanup.ts"],
|
|
4
|
-
"sourcesContent": ["import * as React from 'react';\n\n/**\n * Hook to cleanup stuck pointer-events: none on document.body\n *\n * This addresses an issue where react-remove-scroll (used by Radix UI Dialog)\n * sometimes fails to restore body pointer-events after dialog closes,\n * leaving the page unclickable.\n */\nexport function useBodyPointerEventsCleanup() {\n React.useEffect(() => {\n
|
|
5
|
-
"mappings": "0jBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,iCAAAE,IAAA,eAAAC,EAAAH,GAAA,IAAAI,EAAuB,
|
|
6
|
-
"names": ["use_body_pointer_events_cleanup_exports", "__export", "useBodyPointerEventsCleanup", "__toCommonJS", "React", "
|
|
4
|
+
"sourcesContent": ["import * as React from 'react';\n\nlet bodyCleanupInstalled = false;\n\n/**\n * Hook to cleanup stuck pointer-events: none on document.body\n *\n * This addresses an issue where react-remove-scroll (used by Radix UI Dialog)\n * sometimes fails to restore body pointer-events after dialog closes,\n * leaving the page unclickable.\n */\nexport function useBodyPointerEventsCleanup() {\n React.useEffect(() => {\n if (typeof document === 'undefined') return;\n\n let timeoutId: number | undefined;\n\n const hasOpenModal = (): boolean => {\n // Detect any open modal dialogs/alertdialogs\n return Boolean(\n document.querySelector(\n '[role=\"dialog\"][aria-modal=\"true\"], [role=\"alertdialog\"][aria-modal=\"true\"]',\n ),\n );\n };\n\n const cleanup = () => {\n if (document.body.style.pointerEvents === 'none' && !hasOpenModal()) {\n document.body.style.pointerEvents = '';\n }\n };\n\n const scheduleCleanup = (delay = 50) => {\n if (timeoutId) window.clearTimeout(timeoutId);\n timeoutId = window.setTimeout(cleanup, delay);\n };\n\n // Initial run to catch already-stuck state\n scheduleCleanup(100);\n\n // If already installed globally, don't re-register listeners/observers\n if (bodyCleanupInstalled) {\n return () => {\n if (timeoutId) window.clearTimeout(timeoutId);\n };\n }\n\n bodyCleanupInstalled = true;\n\n const onPointer = () => scheduleCleanup(50);\n const onKey = (event: KeyboardEvent) => {\n if (event.key === 'Escape' || event.key === 'Enter' || event.key === ' ') scheduleCleanup(50);\n };\n const onVisibility = () => {\n if (!document.hidden) scheduleCleanup(50);\n };\n const onTransitionEnd = () => scheduleCleanup(0);\n const onAnimationEnd = () => scheduleCleanup(0);\n\n // Listen for common interactions that close overlays/menus\n document.addEventListener('pointerup', onPointer, true);\n document.addEventListener('click', onPointer, true);\n document.addEventListener('keydown', onKey, true);\n document.addEventListener('keyup', onKey, true);\n document.addEventListener('visibilitychange', onVisibility);\n document.addEventListener('transitionend', onTransitionEnd, true);\n document.addEventListener('animationend', onAnimationEnd, true);\n\n // Observe body style changes (where pointer-events is applied) and DOM mutations\n const bodyObserver = new MutationObserver(() => scheduleCleanup(0));\n bodyObserver.observe(document.body, { attributes: true, attributeFilter: ['style'] });\n\n const domObserver = new MutationObserver(() => scheduleCleanup(0));\n domObserver.observe(document, { childList: true, subtree: true });\n\n // Keep listeners/observers for the app lifetime to ensure cleanup even after overlays unmount\n return () => {\n if (timeoutId) window.clearTimeout(timeoutId);\n };\n }, []);\n}\n"],
|
|
5
|
+
"mappings": "0jBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,iCAAAE,IAAA,eAAAC,EAAAH,GAAA,IAAAI,EAAuB,oBAEvB,IAAIC,EAAuB,GASpB,SAASH,GAA8B,CAC5CE,EAAM,UAAU,IAAM,CACpB,GAAI,OAAO,SAAa,IAAa,OAErC,IAAIE,EAEJ,MAAMC,EAAe,IAEZ,EACL,SAAS,cACP,6EACF,EAIEC,EAAU,IAAM,CAChB,SAAS,KAAK,MAAM,gBAAkB,QAAU,CAACD,EAAa,IAChE,SAAS,KAAK,MAAM,cAAgB,GAExC,EAEME,EAAkB,CAACC,EAAQ,KAAO,CAClCJ,GAAW,OAAO,aAAaA,CAAS,EAC5CA,EAAY,OAAO,WAAWE,EAASE,CAAK,CAC9C,EAMA,GAHAD,EAAgB,GAAG,EAGfJ,EACF,MAAO,IAAM,CACPC,GAAW,OAAO,aAAaA,CAAS,CAC9C,EAGFD,EAAuB,GAEvB,MAAMM,EAAY,IAAMF,EAAgB,EAAE,EACpCG,EAASC,GAAyB,EAClCA,EAAM,MAAQ,UAAYA,EAAM,MAAQ,SAAWA,EAAM,MAAQ,MAAKJ,EAAgB,EAAE,CAC9F,EACMK,EAAe,IAAM,CACpB,SAAS,QAAQL,EAAgB,EAAE,CAC1C,EACMM,EAAkB,IAAMN,EAAgB,CAAC,EACzCO,EAAiB,IAAMP,EAAgB,CAAC,EAG9C,gBAAS,iBAAiB,YAAaE,EAAW,EAAI,EACtD,SAAS,iBAAiB,QAASA,EAAW,EAAI,EAClD,SAAS,iBAAiB,UAAWC,EAAO,EAAI,EAChD,SAAS,iBAAiB,QAASA,EAAO,EAAI,EAC9C,SAAS,iBAAiB,mBAAoBE,CAAY,EAC1D,SAAS,iBAAiB,gBAAiBC,EAAiB,EAAI,EAChE,SAAS,iBAAiB,eAAgBC,EAAgB,EAAI,EAGzC,IAAI,iBAAiB,IAAMP,EAAgB,CAAC,CAAC,EACrD,QAAQ,SAAS,KAAM,CAAE,WAAY,GAAM,gBAAiB,CAAC,OAAO,CAAE,CAAC,EAEhE,IAAI,iBAAiB,IAAMA,EAAgB,CAAC,CAAC,EACrD,QAAQ,SAAU,CAAE,UAAW,GAAM,QAAS,EAAK,CAAC,EAGzD,IAAM,CACPH,GAAW,OAAO,aAAaA,CAAS,CAC9C,CACF,EAAG,CAAC,CAAC,CACP",
|
|
6
|
+
"names": ["use_body_pointer_events_cleanup_exports", "__export", "useBodyPointerEventsCleanup", "__toCommonJS", "React", "bodyCleanupInstalled", "timeoutId", "hasOpenModal", "cleanup", "scheduleCleanup", "delay", "onPointer", "onKey", "event", "onVisibility", "onTransitionEnd", "onAnimationEnd"]
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-body-pointer-events-cleanup.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-body-pointer-events-cleanup.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"use-body-pointer-events-cleanup.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-body-pointer-events-cleanup.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AACH,wBAAgB,2BAA2B,SAqE1C"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import*as
|
|
1
|
+
import*as l from"react";let d=!1;function y(){l.useEffect(()=>{if(typeof document>"u")return;let t;const i=()=>!!document.querySelector('[role="dialog"][aria-modal="true"], [role="alertdialog"][aria-modal="true"]'),u=()=>{document.body.style.pointerEvents==="none"&&!i()&&(document.body.style.pointerEvents="")},e=(n=50)=>{t&&window.clearTimeout(t),t=window.setTimeout(u,n)};if(e(100),d)return()=>{t&&window.clearTimeout(t)};d=!0;const o=()=>e(50),r=n=>{(n.key==="Escape"||n.key==="Enter"||n.key===" ")&&e(50)},s=()=>{document.hidden||e(50)},a=()=>e(0),c=()=>e(0);return document.addEventListener("pointerup",o,!0),document.addEventListener("click",o,!0),document.addEventListener("keydown",r,!0),document.addEventListener("keyup",r,!0),document.addEventListener("visibilitychange",s),document.addEventListener("transitionend",a,!0),document.addEventListener("animationend",c,!0),new MutationObserver(()=>e(0)).observe(document.body,{attributes:!0,attributeFilter:["style"]}),new MutationObserver(()=>e(0)).observe(document,{childList:!0,subtree:!0}),()=>{t&&window.clearTimeout(t)}},[])}export{y as useBodyPointerEventsCleanup};
|
|
2
2
|
//# sourceMappingURL=use-body-pointer-events-cleanup.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/hooks/use-body-pointer-events-cleanup.ts"],
|
|
4
|
-
"sourcesContent": ["import * as React from 'react';\n\n/**\n * Hook to cleanup stuck pointer-events: none on document.body\n *\n * This addresses an issue where react-remove-scroll (used by Radix UI Dialog)\n * sometimes fails to restore body pointer-events after dialog closes,\n * leaving the page unclickable.\n */\nexport function useBodyPointerEventsCleanup() {\n React.useEffect(() => {\n
|
|
5
|
-
"mappings": "AAAA,UAAYA,MAAW,
|
|
6
|
-
"names": ["React", "useBodyPointerEventsCleanup", "cleanup", "
|
|
4
|
+
"sourcesContent": ["import * as React from 'react';\n\nlet bodyCleanupInstalled = false;\n\n/**\n * Hook to cleanup stuck pointer-events: none on document.body\n *\n * This addresses an issue where react-remove-scroll (used by Radix UI Dialog)\n * sometimes fails to restore body pointer-events after dialog closes,\n * leaving the page unclickable.\n */\nexport function useBodyPointerEventsCleanup() {\n React.useEffect(() => {\n if (typeof document === 'undefined') return;\n\n let timeoutId: number | undefined;\n\n const hasOpenModal = (): boolean => {\n // Detect any open modal dialogs/alertdialogs\n return Boolean(\n document.querySelector(\n '[role=\"dialog\"][aria-modal=\"true\"], [role=\"alertdialog\"][aria-modal=\"true\"]',\n ),\n );\n };\n\n const cleanup = () => {\n if (document.body.style.pointerEvents === 'none' && !hasOpenModal()) {\n document.body.style.pointerEvents = '';\n }\n };\n\n const scheduleCleanup = (delay = 50) => {\n if (timeoutId) window.clearTimeout(timeoutId);\n timeoutId = window.setTimeout(cleanup, delay);\n };\n\n // Initial run to catch already-stuck state\n scheduleCleanup(100);\n\n // If already installed globally, don't re-register listeners/observers\n if (bodyCleanupInstalled) {\n return () => {\n if (timeoutId) window.clearTimeout(timeoutId);\n };\n }\n\n bodyCleanupInstalled = true;\n\n const onPointer = () => scheduleCleanup(50);\n const onKey = (event: KeyboardEvent) => {\n if (event.key === 'Escape' || event.key === 'Enter' || event.key === ' ') scheduleCleanup(50);\n };\n const onVisibility = () => {\n if (!document.hidden) scheduleCleanup(50);\n };\n const onTransitionEnd = () => scheduleCleanup(0);\n const onAnimationEnd = () => scheduleCleanup(0);\n\n // Listen for common interactions that close overlays/menus\n document.addEventListener('pointerup', onPointer, true);\n document.addEventListener('click', onPointer, true);\n document.addEventListener('keydown', onKey, true);\n document.addEventListener('keyup', onKey, true);\n document.addEventListener('visibilitychange', onVisibility);\n document.addEventListener('transitionend', onTransitionEnd, true);\n document.addEventListener('animationend', onAnimationEnd, true);\n\n // Observe body style changes (where pointer-events is applied) and DOM mutations\n const bodyObserver = new MutationObserver(() => scheduleCleanup(0));\n bodyObserver.observe(document.body, { attributes: true, attributeFilter: ['style'] });\n\n const domObserver = new MutationObserver(() => scheduleCleanup(0));\n domObserver.observe(document, { childList: true, subtree: true });\n\n // Keep listeners/observers for the app lifetime to ensure cleanup even after overlays unmount\n return () => {\n if (timeoutId) window.clearTimeout(timeoutId);\n };\n }, []);\n}\n"],
|
|
5
|
+
"mappings": "AAAA,UAAYA,MAAW,QAEvB,IAAIC,EAAuB,GASpB,SAASC,GAA8B,CAC5CF,EAAM,UAAU,IAAM,CACpB,GAAI,OAAO,SAAa,IAAa,OAErC,IAAIG,EAEJ,MAAMC,EAAe,IAEZ,EACL,SAAS,cACP,6EACF,EAIEC,EAAU,IAAM,CAChB,SAAS,KAAK,MAAM,gBAAkB,QAAU,CAACD,EAAa,IAChE,SAAS,KAAK,MAAM,cAAgB,GAExC,EAEME,EAAkB,CAACC,EAAQ,KAAO,CAClCJ,GAAW,OAAO,aAAaA,CAAS,EAC5CA,EAAY,OAAO,WAAWE,EAASE,CAAK,CAC9C,EAMA,GAHAD,EAAgB,GAAG,EAGfL,EACF,MAAO,IAAM,CACPE,GAAW,OAAO,aAAaA,CAAS,CAC9C,EAGFF,EAAuB,GAEvB,MAAMO,EAAY,IAAMF,EAAgB,EAAE,EACpCG,EAASC,GAAyB,EAClCA,EAAM,MAAQ,UAAYA,EAAM,MAAQ,SAAWA,EAAM,MAAQ,MAAKJ,EAAgB,EAAE,CAC9F,EACMK,EAAe,IAAM,CACpB,SAAS,QAAQL,EAAgB,EAAE,CAC1C,EACMM,EAAkB,IAAMN,EAAgB,CAAC,EACzCO,EAAiB,IAAMP,EAAgB,CAAC,EAG9C,gBAAS,iBAAiB,YAAaE,EAAW,EAAI,EACtD,SAAS,iBAAiB,QAASA,EAAW,EAAI,EAClD,SAAS,iBAAiB,UAAWC,EAAO,EAAI,EAChD,SAAS,iBAAiB,QAASA,EAAO,EAAI,EAC9C,SAAS,iBAAiB,mBAAoBE,CAAY,EAC1D,SAAS,iBAAiB,gBAAiBC,EAAiB,EAAI,EAChE,SAAS,iBAAiB,eAAgBC,EAAgB,EAAI,EAGzC,IAAI,iBAAiB,IAAMP,EAAgB,CAAC,CAAC,EACrD,QAAQ,SAAS,KAAM,CAAE,WAAY,GAAM,gBAAiB,CAAC,OAAO,CAAE,CAAC,EAEhE,IAAI,iBAAiB,IAAMA,EAAgB,CAAC,CAAC,EACrD,QAAQ,SAAU,CAAE,UAAW,GAAM,QAAS,EAAK,CAAC,EAGzD,IAAM,CACPH,GAAW,OAAO,aAAaA,CAAS,CAC9C,CACF,EAAG,CAAC,CAAC,CACP",
|
|
6
|
+
"names": ["React", "bodyCleanupInstalled", "useBodyPointerEventsCleanup", "timeoutId", "hasOpenModal", "cleanup", "scheduleCleanup", "delay", "onPointer", "onKey", "event", "onVisibility", "onTransitionEnd", "onAnimationEnd"]
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
|
+
let bodyCleanupInstalled = false;
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* Hook to cleanup stuck pointer-events: none on document.body
|
|
5
7
|
*
|
|
@@ -9,36 +11,71 @@ import * as React from 'react';
|
|
|
9
11
|
*/
|
|
10
12
|
export function useBodyPointerEventsCleanup() {
|
|
11
13
|
React.useEffect(() => {
|
|
14
|
+
if (typeof document === 'undefined') return;
|
|
15
|
+
|
|
16
|
+
let timeoutId: number | undefined;
|
|
17
|
+
|
|
18
|
+
const hasOpenModal = (): boolean => {
|
|
19
|
+
// Detect any open modal dialogs/alertdialogs
|
|
20
|
+
return Boolean(
|
|
21
|
+
document.querySelector(
|
|
22
|
+
'[role="dialog"][aria-modal="true"], [role="alertdialog"][aria-modal="true"]',
|
|
23
|
+
),
|
|
24
|
+
);
|
|
25
|
+
};
|
|
26
|
+
|
|
12
27
|
const cleanup = () => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
// Check if there are any actually open dialogs/overlays
|
|
16
|
-
const hasOpenDialogs = document.querySelector(
|
|
17
|
-
'[data-state="open"][role="dialog"], [data-state="open"][role="alertdialog"]',
|
|
18
|
-
);
|
|
19
|
-
|
|
20
|
-
if (!hasOpenDialogs) {
|
|
21
|
-
// Safe to restore pointer events
|
|
22
|
-
document.body.style.pointerEvents = '';
|
|
23
|
-
}
|
|
28
|
+
if (document.body.style.pointerEvents === 'none' && !hasOpenModal()) {
|
|
29
|
+
document.body.style.pointerEvents = '';
|
|
24
30
|
}
|
|
25
31
|
};
|
|
26
32
|
|
|
27
|
-
|
|
28
|
-
|
|
33
|
+
const scheduleCleanup = (delay = 50) => {
|
|
34
|
+
if (timeoutId) window.clearTimeout(timeoutId);
|
|
35
|
+
timeoutId = window.setTimeout(cleanup, delay);
|
|
36
|
+
};
|
|
29
37
|
|
|
30
|
-
//
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
38
|
+
// Initial run to catch already-stuck state
|
|
39
|
+
scheduleCleanup(100);
|
|
40
|
+
|
|
41
|
+
// If already installed globally, don't re-register listeners/observers
|
|
42
|
+
if (bodyCleanupInstalled) {
|
|
43
|
+
return () => {
|
|
44
|
+
if (timeoutId) window.clearTimeout(timeoutId);
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
bodyCleanupInstalled = true;
|
|
49
|
+
|
|
50
|
+
const onPointer = () => scheduleCleanup(50);
|
|
51
|
+
const onKey = (event: KeyboardEvent) => {
|
|
52
|
+
if (event.key === 'Escape' || event.key === 'Enter' || event.key === ' ') scheduleCleanup(50);
|
|
35
53
|
};
|
|
54
|
+
const onVisibility = () => {
|
|
55
|
+
if (!document.hidden) scheduleCleanup(50);
|
|
56
|
+
};
|
|
57
|
+
const onTransitionEnd = () => scheduleCleanup(0);
|
|
58
|
+
const onAnimationEnd = () => scheduleCleanup(0);
|
|
59
|
+
|
|
60
|
+
// Listen for common interactions that close overlays/menus
|
|
61
|
+
document.addEventListener('pointerup', onPointer, true);
|
|
62
|
+
document.addEventListener('click', onPointer, true);
|
|
63
|
+
document.addEventListener('keydown', onKey, true);
|
|
64
|
+
document.addEventListener('keyup', onKey, true);
|
|
65
|
+
document.addEventListener('visibilitychange', onVisibility);
|
|
66
|
+
document.addEventListener('transitionend', onTransitionEnd, true);
|
|
67
|
+
document.addEventListener('animationend', onAnimationEnd, true);
|
|
68
|
+
|
|
69
|
+
// Observe body style changes (where pointer-events is applied) and DOM mutations
|
|
70
|
+
const bodyObserver = new MutationObserver(() => scheduleCleanup(0));
|
|
71
|
+
bodyObserver.observe(document.body, { attributes: true, attributeFilter: ['style'] });
|
|
36
72
|
|
|
37
|
-
|
|
73
|
+
const domObserver = new MutationObserver(() => scheduleCleanup(0));
|
|
74
|
+
domObserver.observe(document, { childList: true, subtree: true });
|
|
38
75
|
|
|
76
|
+
// Keep listeners/observers for the app lifetime to ensure cleanup even after overlays unmount
|
|
39
77
|
return () => {
|
|
40
|
-
clearTimeout(timeoutId);
|
|
41
|
-
document.removeEventListener('visibilitychange', handleVisibilityChange);
|
|
78
|
+
if (timeoutId) window.clearTimeout(timeoutId);
|
|
42
79
|
};
|
|
43
80
|
}, []);
|
|
44
81
|
}
|