@aiquants/swipe-overlay 0.0.1 → 0.1.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/dist/index.d.mts CHANGED
@@ -41,5 +41,29 @@ declare const useSwipeToDismissOverlay: ({ isOpen, onClose, isCloseBlocked, skip
41
41
  isCloseBlocked: () => boolean;
42
42
  skipWhenTextSelected?: boolean;
43
43
  }) => SwipeDismissHookResult;
44
+ /**
45
+ * Manages the blocking state for swipe-to-dismiss interactions.
46
+ * スワイプクローズ操作のブロック状態を管理するフック。
47
+ */
48
+ declare const useSwipeGuardState: () => {
49
+ isBlocked: boolean;
50
+ requestBlock: () => () => void;
51
+ reset: () => void;
52
+ };
53
+ /**
54
+ * Keeps the last non-null value while the overlay is closing to allow exit animations.
55
+ * オーバーレイが閉じるアニメーション中も、直前の非 null 値を保持します。
56
+ */
57
+ declare function useTransitionDisplay<T>(isOpen: boolean, current: T | null): T | null;
58
+ /**
59
+ * Hook to distinguish between tap and scroll gestures.
60
+ * タップとスクロール操作を区別するフック。
61
+ */
62
+ declare const useTapClick: (onTap: () => void, threshold?: number) => {
63
+ onPointerDown: (e: React.PointerEvent) => void;
64
+ onPointerUp: (e: React.PointerEvent) => void;
65
+ onPointerCancel: () => void;
66
+ onClick: (e: React.MouseEvent) => void;
67
+ };
44
68
 
45
- export { SwipeCloseGuardContext, type SwipeCloseGuardContextValue, type SwipeDismissHookResult, useOverlayEscapeStack, useSwipeCloseGuard, useSwipeToDismissOverlay };
69
+ export { SwipeCloseGuardContext, type SwipeCloseGuardContextValue, type SwipeDismissHookResult, useOverlayEscapeStack, useSwipeCloseGuard, useSwipeGuardState, useSwipeToDismissOverlay, useTapClick, useTransitionDisplay };
package/dist/index.d.ts CHANGED
@@ -41,5 +41,29 @@ declare const useSwipeToDismissOverlay: ({ isOpen, onClose, isCloseBlocked, skip
41
41
  isCloseBlocked: () => boolean;
42
42
  skipWhenTextSelected?: boolean;
43
43
  }) => SwipeDismissHookResult;
44
+ /**
45
+ * Manages the blocking state for swipe-to-dismiss interactions.
46
+ * スワイプクローズ操作のブロック状態を管理するフック。
47
+ */
48
+ declare const useSwipeGuardState: () => {
49
+ isBlocked: boolean;
50
+ requestBlock: () => () => void;
51
+ reset: () => void;
52
+ };
53
+ /**
54
+ * Keeps the last non-null value while the overlay is closing to allow exit animations.
55
+ * オーバーレイが閉じるアニメーション中も、直前の非 null 値を保持します。
56
+ */
57
+ declare function useTransitionDisplay<T>(isOpen: boolean, current: T | null): T | null;
58
+ /**
59
+ * Hook to distinguish between tap and scroll gestures.
60
+ * タップとスクロール操作を区別するフック。
61
+ */
62
+ declare const useTapClick: (onTap: () => void, threshold?: number) => {
63
+ onPointerDown: (e: React.PointerEvent) => void;
64
+ onPointerUp: (e: React.PointerEvent) => void;
65
+ onPointerCancel: () => void;
66
+ onClick: (e: React.MouseEvent) => void;
67
+ };
44
68
 
45
- export { SwipeCloseGuardContext, type SwipeCloseGuardContextValue, type SwipeDismissHookResult, useOverlayEscapeStack, useSwipeCloseGuard, useSwipeToDismissOverlay };
69
+ export { SwipeCloseGuardContext, type SwipeCloseGuardContextValue, type SwipeDismissHookResult, useOverlayEscapeStack, useSwipeCloseGuard, useSwipeGuardState, useSwipeToDismissOverlay, useTapClick, useTransitionDisplay };
package/dist/index.js CHANGED
@@ -1,2 +1 @@
1
- "use strict";var v=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var P=Object.getOwnPropertyNames;var M=Object.prototype.hasOwnProperty;var k=(t,o)=>{for(var i in o)v(t,i,{get:o[i],enumerable:!0})},X=(t,o,i,l)=>{if(o&&typeof o=="object"||typeof o=="function")for(let e of P(o))!M.call(t,e)&&e!==i&&v(t,e,{get:()=>o[e],enumerable:!(l=D(o,e))||l.enumerable});return t};var H=t=>X(v({},"__esModule",{value:!0}),t);var T={};k(T,{SwipeCloseGuardContext:()=>I,useOverlayEscapeStack:()=>w,useSwipeCloseGuard:()=>R,useSwipeToDismissOverlay:()=>A});module.exports=H(T);var s=require("react"),O=120,I=(0,s.createContext)(null),R=()=>(0,s.useContext)(I)??{isBlocked:!1,requestBlock:()=>()=>{}},a=[],g=t=>{if(t.key!=="Escape")return;a[a.length-1]?.onEscape(t)&&(t.preventDefault(),t.stopPropagation())},w=()=>(0,s.useCallback)(t=>{let o=a.findIndex(i=>i.id===t.id);return o>=0&&a.splice(o,1),a.push(t),a.length===1&&typeof document<"u"&&document.addEventListener("keydown",g,!0),()=>{let i=a.findIndex(l=>l.id===t.id);i>=0&&a.splice(i,1),a.length===0&&typeof document<"u"&&document.removeEventListener("keydown",g,!0)}},[]),A=({isOpen:t,onClose:o,isCloseBlocked:i,skipWhenTextSelected:l=!1})=>{let[e,h]=(0,s.useState)(null),[x,d]=(0,s.useState)(!1),C=w(),E=(0,s.useRef)(`overlay-${Math.random().toString(36).slice(2)}`).current,u=(0,s.useRef)({pointerId:null,startX:0,startY:0,isActive:!1,isClosing:!1,lastDelta:0,hasCapture:!1}),p=(0,s.useCallback)(()=>i()?!1:(o(),!0),[i,o]);(0,s.useEffect)(()=>{if(t)return C({id:E,onEscape:p})},[t,p,C,E]),(0,s.useEffect)(()=>{if(!(e&&t))return;let c=()=>{let n=u.current;n.hasCapture&&n.pointerId!==null&&e.releasePointerCapture?.(n.pointerId),Object.assign(n,{pointerId:null,isActive:!1,isClosing:!1,hasCapture:!1}),e.style.transform="",e.style.transition="",d(!1)};u.current={pointerId:null,startX:0,startY:0,isActive:!1,isClosing:!1,lastDelta:0,hasCapture:!1},d(!1);let m=n=>{n.pointerType==="mouse"&&n.button!==0||n.target?.closest('[data-overlay-interactive="true"]')||l&&window.getSelection()?.toString().trim()||(e.style.transition="none",d(!0),u.current={pointerId:n.pointerId,startX:n.clientX,startY:n.clientY,isActive:!0,isClosing:!1,lastDelta:0,hasCapture:!1})},y=n=>{let r=u.current;if(!r.isActive||r.pointerId!==n.pointerId)return;if(l&&window.getSelection()?.toString().trim()){c();return}let f=n.clientX-r.startX,L=n.clientY-r.startY;if(!r.isClosing){if(Math.abs(f)<4)return;if(Math.abs(f)<Math.abs(L)*1.3||f<=0){c();return}r.isClosing=!0,r.hasCapture||(e.setPointerCapture?.(n.pointerId),r.hasCapture=!0)}r.isClosing&&(n.preventDefault(),r.lastDelta=Math.max(0,f),e.style.transform=`translateX(${Math.min(r.lastDelta,520)}px)`)},S=n=>{let r=u.current;r.pointerId===n.pointerId&&(r.isClosing&&r.lastDelta>O?(e.style.transition="",e.style.transform="translateX(100%)",r.hasCapture&&r.pointerId!==null&&e.releasePointerCapture?.(r.pointerId),Object.assign(r,{pointerId:null,isActive:!1,isClosing:!1,hasCapture:!1}),d(!1),p()):c())};return e.addEventListener("pointerdown",m),e.addEventListener("pointermove",y),e.addEventListener("pointerup",S),e.addEventListener("pointercancel",c),()=>{e.removeEventListener("pointerdown",m),e.removeEventListener("pointermove",y),e.removeEventListener("pointerup",S),e.removeEventListener("pointercancel",c)}},[t,e,p,l]);let b=(0,s.useMemo)(()=>({transform:t?"translateX(0px)":"translateX(100%)"}),[t]);return{overlayRef:h,overlayStyle:b,attemptClose:p,isSwiping:x,element:e}};0&&(module.exports={SwipeCloseGuardContext,useOverlayEscapeStack,useSwipeCloseGuard,useSwipeToDismissOverlay});
2
- //# sourceMappingURL=index.js.map
1
+ "use strict";var y=Object.defineProperty;var P=Object.getOwnPropertyDescriptor;var k=Object.getOwnPropertyNames;var L=Object.prototype.hasOwnProperty;var M=(e,r)=>{for(var n in r)y(e,n,{get:r[n],enumerable:!0})},R=(e,r,n,o)=>{if(r&&typeof r=="object"||typeof r=="function")for(let t of k(r))!L.call(e,t)&&t!==n&&y(e,t,{get:()=>r[t],enumerable:!(o=P(r,t))||o.enumerable});return e};var T=e=>R(y({},"__esModule",{value:!0}),e);var O={};M(O,{SwipeCloseGuardContext:()=>b,useOverlayEscapeStack:()=>w,useSwipeCloseGuard:()=>B,useSwipeGuardState:()=>Y,useSwipeToDismissOverlay:()=>H,useTapClick:()=>G,useTransitionDisplay:()=>A});module.exports=T(O);var s=require("react"),X=120,b=(0,s.createContext)(null),B=()=>(0,s.useContext)(b)??{isBlocked:!1,requestBlock:()=>()=>{}},a=[],x=e=>{if(e.key!=="Escape")return;a[a.length-1]?.onEscape(e)&&(e.preventDefault(),e.stopPropagation())},w=()=>(0,s.useCallback)(e=>{let r=a.findIndex(n=>n.id===e.id);return r>=0&&a.splice(r,1),a.push(e),a.length===1&&typeof document<"u"&&document.addEventListener("keydown",x,!0),()=>{let n=a.findIndex(o=>o.id===e.id);n>=0&&a.splice(n,1),a.length===0&&typeof document<"u"&&document.removeEventListener("keydown",x,!0)}},[]),H=({isOpen:e,onClose:r,isCloseBlocked:n,skipWhenTextSelected:o=!1})=>{let[t,d]=(0,s.useState)(null),[I,f]=(0,s.useState)(!1),C=w(),E=(0,s.useRef)(`overlay-${Math.random().toString(36).slice(2)}`).current,u=(0,s.useRef)({pointerId:null,startX:0,startY:0,isActive:!1,isClosing:!1,lastDelta:0,hasCapture:!1}),c=(0,s.useCallback)(()=>n()?!1:(r(),!0),[n,r]);(0,s.useEffect)(()=>{if(e)return C({id:E,onEscape:c})},[e,c,C,E]),(0,s.useEffect)(()=>{if(!(t&&e))return;let p=()=>{let i=u.current;i.hasCapture&&i.pointerId!==null&&t.releasePointerCapture?.(i.pointerId),Object.assign(i,{pointerId:null,isActive:!1,isClosing:!1,hasCapture:!1}),t.style.transform="",t.style.transition="",f(!1)};u.current={pointerId:null,startX:0,startY:0,isActive:!1,isClosing:!1,lastDelta:0,hasCapture:!1},f(!1);let m=i=>{i.pointerType==="mouse"&&i.button!==0||i.target?.closest('[data-overlay-interactive="true"]')||o&&window.getSelection()?.toString().trim()||(t.style.transition="none",f(!0),u.current={pointerId:i.pointerId,startX:i.clientX,startY:i.clientY,isActive:!0,isClosing:!1,lastDelta:0,hasCapture:!1})},S=i=>{let l=u.current;if(!l.isActive||l.pointerId!==i.pointerId)return;if(o&&window.getSelection()?.toString().trim()){p();return}let v=i.clientX-l.startX,D=i.clientY-l.startY;if(!l.isClosing){if(Math.abs(v)<4)return;if(Math.abs(v)<Math.abs(D)*1.3||v<=0){p();return}l.isClosing=!0,l.hasCapture||(t.setPointerCapture?.(i.pointerId),l.hasCapture=!0)}l.isClosing&&(i.preventDefault(),l.lastDelta=Math.max(0,v),t.style.transform=`translateX(${Math.min(l.lastDelta,520)}px)`)},g=i=>{let l=u.current;l.pointerId===i.pointerId&&(l.isClosing&&l.lastDelta>X?(t.style.transition="",t.style.transform="translateX(100%)",l.hasCapture&&l.pointerId!==null&&t.releasePointerCapture?.(l.pointerId),Object.assign(l,{pointerId:null,isActive:!1,isClosing:!1,hasCapture:!1}),f(!1),c()):p())};return t.addEventListener("pointerdown",m),t.addEventListener("pointermove",S),t.addEventListener("pointerup",g),t.addEventListener("pointercancel",p),()=>{t.removeEventListener("pointerdown",m),t.removeEventListener("pointermove",S),t.removeEventListener("pointerup",g),t.removeEventListener("pointercancel",p)}},[e,t,c,o]);let h=(0,s.useMemo)(()=>({transform:e?"translateX(0px)":"translateX(100%)"}),[e]);return{overlayRef:d,overlayStyle:h,attemptClose:c,isSwiping:I,element:t}},Y=()=>{let e=(0,s.useRef)(new Set),[r,n]=(0,s.useState)(!1),o=(0,s.useCallback)(()=>{let d=Symbol("guard");return e.current.add(d),n(!0),()=>{e.current.delete(d),n(e.current.size>0)}},[]),t=(0,s.useCallback)(()=>{e.current.clear(),n(!1)},[]);return{isBlocked:r,requestBlock:o,reset:t}};function A(e,r){let n=(0,s.useRef)(r);return e&&r!==null&&(n.current=r),e?r:n.current}var G=(e,r=10)=>{let n=(0,s.useRef)(null);return{onPointerDown:o=>{n.current={x:o.clientX,y:o.clientY}},onPointerUp:o=>{if(n.current){let t=Math.hypot(o.clientX-n.current.x,o.clientY-n.current.y);n.current=null,t<r&&(o.preventDefault(),e())}},onPointerCancel:()=>{n.current=null},onClick:o=>o.preventDefault()}};0&&(module.exports={SwipeCloseGuardContext,useOverlayEscapeStack,useSwipeCloseGuard,useSwipeGuardState,useSwipeToDismissOverlay,useTapClick,useTransitionDisplay});
package/dist/index.mjs CHANGED
@@ -1,2 +1 @@
1
- import{createContext as D,useCallback as w,useContext as P,useEffect as y,useMemo as M,useRef as S,useState as g}from"react";var k=120,X=D(null),R=()=>P(X)??{isBlocked:!1,requestBlock:()=>()=>{}},s=[],I=r=>{if(r.key!=="Escape")return;s[s.length-1]?.onEscape(r)&&(r.preventDefault(),r.stopPropagation())},H=()=>w(r=>{let i=s.findIndex(o=>o.id===r.id);return i>=0&&s.splice(i,1),s.push(r),s.length===1&&typeof document<"u"&&document.addEventListener("keydown",I,!0),()=>{let o=s.findIndex(a=>a.id===r.id);o>=0&&s.splice(o,1),s.length===0&&typeof document<"u"&&document.removeEventListener("keydown",I,!0)}},[]),A=({isOpen:r,onClose:i,isCloseBlocked:o,skipWhenTextSelected:a=!1})=>{let[e,h]=g(null),[x,c]=g(!1),f=H(),v=S(`overlay-${Math.random().toString(36).slice(2)}`).current,l=S({pointerId:null,startX:0,startY:0,isActive:!1,isClosing:!1,lastDelta:0,hasCapture:!1}),u=w(()=>o()?!1:(i(),!0),[o,i]);y(()=>{if(r)return f({id:v,onEscape:u})},[r,u,f,v]),y(()=>{if(!(e&&r))return;let p=()=>{let t=l.current;t.hasCapture&&t.pointerId!==null&&e.releasePointerCapture?.(t.pointerId),Object.assign(t,{pointerId:null,isActive:!1,isClosing:!1,hasCapture:!1}),e.style.transform="",e.style.transition="",c(!1)};l.current={pointerId:null,startX:0,startY:0,isActive:!1,isClosing:!1,lastDelta:0,hasCapture:!1},c(!1);let C=t=>{t.pointerType==="mouse"&&t.button!==0||t.target?.closest('[data-overlay-interactive="true"]')||a&&window.getSelection()?.toString().trim()||(e.style.transition="none",c(!0),l.current={pointerId:t.pointerId,startX:t.clientX,startY:t.clientY,isActive:!0,isClosing:!1,lastDelta:0,hasCapture:!1})},E=t=>{let n=l.current;if(!n.isActive||n.pointerId!==t.pointerId)return;if(a&&window.getSelection()?.toString().trim()){p();return}let d=t.clientX-n.startX,L=t.clientY-n.startY;if(!n.isClosing){if(Math.abs(d)<4)return;if(Math.abs(d)<Math.abs(L)*1.3||d<=0){p();return}n.isClosing=!0,n.hasCapture||(e.setPointerCapture?.(t.pointerId),n.hasCapture=!0)}n.isClosing&&(t.preventDefault(),n.lastDelta=Math.max(0,d),e.style.transform=`translateX(${Math.min(n.lastDelta,520)}px)`)},m=t=>{let n=l.current;n.pointerId===t.pointerId&&(n.isClosing&&n.lastDelta>k?(e.style.transition="",e.style.transform="translateX(100%)",n.hasCapture&&n.pointerId!==null&&e.releasePointerCapture?.(n.pointerId),Object.assign(n,{pointerId:null,isActive:!1,isClosing:!1,hasCapture:!1}),c(!1),u()):p())};return e.addEventListener("pointerdown",C),e.addEventListener("pointermove",E),e.addEventListener("pointerup",m),e.addEventListener("pointercancel",p),()=>{e.removeEventListener("pointerdown",C),e.removeEventListener("pointermove",E),e.removeEventListener("pointerup",m),e.removeEventListener("pointercancel",p)}},[r,e,u,a]);let b=M(()=>({transform:r?"translateX(0px)":"translateX(100%)"}),[r]);return{overlayRef:h,overlayStyle:b,attemptClose:u,isSwiping:x,element:e}};export{X as SwipeCloseGuardContext,H as useOverlayEscapeStack,R as useSwipeCloseGuard,A as useSwipeToDismissOverlay};
2
- //# sourceMappingURL=index.mjs.map
1
+ import{createContext as P,useCallback as y,useContext as k,useEffect as b,useMemo as L,useRef as p,useState as C}from"react";var M=120,R=P(null),B=()=>k(R)??{isBlocked:!1,requestBlock:()=>()=>{}},l=[],w=e=>{if(e.key!=="Escape")return;l[l.length-1]?.onEscape(e)&&(e.preventDefault(),e.stopPropagation())},T=()=>y(e=>{let i=l.findIndex(n=>n.id===e.id);return i>=0&&l.splice(i,1),l.push(e),l.length===1&&typeof document<"u"&&document.addEventListener("keydown",w,!0),()=>{let n=l.findIndex(o=>o.id===e.id);n>=0&&l.splice(n,1),l.length===0&&typeof document<"u"&&document.removeEventListener("keydown",w,!0)}},[]),H=({isOpen:e,onClose:i,isCloseBlocked:n,skipWhenTextSelected:o=!1})=>{let[t,d]=C(null),[I,f]=C(!1),E=T(),m=p(`overlay-${Math.random().toString(36).slice(2)}`).current,a=p({pointerId:null,startX:0,startY:0,isActive:!1,isClosing:!1,lastDelta:0,hasCapture:!1}),u=y(()=>n()?!1:(i(),!0),[n,i]);b(()=>{if(e)return E({id:m,onEscape:u})},[e,u,E,m]),b(()=>{if(!(t&&e))return;let c=()=>{let r=a.current;r.hasCapture&&r.pointerId!==null&&t.releasePointerCapture?.(r.pointerId),Object.assign(r,{pointerId:null,isActive:!1,isClosing:!1,hasCapture:!1}),t.style.transform="",t.style.transition="",f(!1)};a.current={pointerId:null,startX:0,startY:0,isActive:!1,isClosing:!1,lastDelta:0,hasCapture:!1},f(!1);let S=r=>{r.pointerType==="mouse"&&r.button!==0||r.target?.closest('[data-overlay-interactive="true"]')||o&&window.getSelection()?.toString().trim()||(t.style.transition="none",f(!0),a.current={pointerId:r.pointerId,startX:r.clientX,startY:r.clientY,isActive:!0,isClosing:!1,lastDelta:0,hasCapture:!1})},g=r=>{let s=a.current;if(!s.isActive||s.pointerId!==r.pointerId)return;if(o&&window.getSelection()?.toString().trim()){c();return}let v=r.clientX-s.startX,D=r.clientY-s.startY;if(!s.isClosing){if(Math.abs(v)<4)return;if(Math.abs(v)<Math.abs(D)*1.3||v<=0){c();return}s.isClosing=!0,s.hasCapture||(t.setPointerCapture?.(r.pointerId),s.hasCapture=!0)}s.isClosing&&(r.preventDefault(),s.lastDelta=Math.max(0,v),t.style.transform=`translateX(${Math.min(s.lastDelta,520)}px)`)},x=r=>{let s=a.current;s.pointerId===r.pointerId&&(s.isClosing&&s.lastDelta>M?(t.style.transition="",t.style.transform="translateX(100%)",s.hasCapture&&s.pointerId!==null&&t.releasePointerCapture?.(s.pointerId),Object.assign(s,{pointerId:null,isActive:!1,isClosing:!1,hasCapture:!1}),f(!1),u()):c())};return t.addEventListener("pointerdown",S),t.addEventListener("pointermove",g),t.addEventListener("pointerup",x),t.addEventListener("pointercancel",c),()=>{t.removeEventListener("pointerdown",S),t.removeEventListener("pointermove",g),t.removeEventListener("pointerup",x),t.removeEventListener("pointercancel",c)}},[e,t,u,o]);let h=L(()=>({transform:e?"translateX(0px)":"translateX(100%)"}),[e]);return{overlayRef:d,overlayStyle:h,attemptClose:u,isSwiping:I,element:t}},Y=()=>{let e=p(new Set),[i,n]=C(!1),o=y(()=>{let d=Symbol("guard");return e.current.add(d),n(!0),()=>{e.current.delete(d),n(e.current.size>0)}},[]),t=y(()=>{e.current.clear(),n(!1)},[]);return{isBlocked:i,requestBlock:o,reset:t}};function A(e,i){let n=p(i);return e&&i!==null&&(n.current=i),e?i:n.current}var G=(e,i=10)=>{let n=p(null);return{onPointerDown:o=>{n.current={x:o.clientX,y:o.clientY}},onPointerUp:o=>{if(n.current){let t=Math.hypot(o.clientX-n.current.x,o.clientY-n.current.y);n.current=null,t<i&&(o.preventDefault(),e())}},onPointerCancel:()=>{n.current=null},onClick:o=>o.preventDefault()}};export{R as SwipeCloseGuardContext,T as useOverlayEscapeStack,B as useSwipeCloseGuard,Y as useSwipeGuardState,H as useSwipeToDismissOverlay,G as useTapClick,A as useTransitionDisplay};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiquants/swipe-overlay",
3
- "version": "0.0.1",
3
+ "version": "0.1.0",
4
4
  "description": "React hooks and context for swipe-to-dismiss overlay interactions",
5
5
  "keywords": [
6
6
  "react",
@@ -31,32 +31,16 @@
31
31
  "README.md",
32
32
  "LICENSE"
33
33
  ],
34
- "peerDependencies": {
35
- "react": ">=16.8.0",
36
- "react-dom": ">=16.8.0"
37
- },
38
- "devDependencies": {
39
- "@biomejs/biome": "^2.3.7",
40
- "@types/react": "^18.3.27",
41
- "@types/react-dom": "^18.3.7",
42
- "react": "^18.3.1",
43
- "react-dom": "^18.3.1",
44
- "rimraf": "^6.1.2",
45
- "tsup": "^8.5.1",
46
- "typescript": "^5.9.3",
47
- "vitest": "^3.2.4"
48
- },
49
- "publishConfig": {
50
- "access": "public"
51
- },
52
34
  "scripts": {
53
35
  "build": "tsup",
36
+ "prepare": "pnpm run build",
54
37
  "build:watch": "tsup --watch",
55
38
  "dev": "tsup --watch",
56
39
  "watch": "tsup --watch",
57
40
  "type-check": "tsc --noEmit",
58
41
  "typecheck": "npm run type-check",
59
42
  "clean": "rimraf dist",
43
+ "prepublishOnly": "npm run clean && npm run typecheck && npm run test --if-present && npm run build",
60
44
  "publish:patch": "npm version patch && npm publish",
61
45
  "publish:minor": "npm version minor && npm publish",
62
46
  "publish:major": "npm version major && npm publish",
@@ -70,5 +54,23 @@
70
54
  "license-check:json": "pnpm dlx license-checker --production --onlyAllow \"MIT;Apache-2.0;BSD-2-Clause;BSD-3-Clause;ISC;Unlicense\" --json",
71
55
  "test": "vitest run --passWithNoTests",
72
56
  "test:coverage": "vitest run --coverage --passWithNoTests"
57
+ },
58
+ "peerDependencies": {
59
+ "react": ">=16.8.0",
60
+ "react-dom": ">=16.8.0"
61
+ },
62
+ "devDependencies": {
63
+ "@biomejs/biome": "^2.3.7",
64
+ "@types/react": "^18.3.27",
65
+ "@types/react-dom": "^18.3.7",
66
+ "react": "^18.3.1",
67
+ "react-dom": "^18.3.1",
68
+ "rimraf": "^6.1.2",
69
+ "tsup": "^8.5.1",
70
+ "typescript": "^5.9.3",
71
+ "vitest": "^3.2.4"
72
+ },
73
+ "publishConfig": {
74
+ "access": "public"
73
75
  }
74
- }
76
+ }
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { type CSSProperties, createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from \"react\"\n\nconst MOBILE_SWIPE_CLOSE_THRESHOLD = 120\n\n/* --- Contexts & Hooks for Overlay Management --- */\n\nexport type SwipeCloseGuardContextValue = { isBlocked: boolean; requestBlock: () => () => void }\n/**\n * Provides swipe-dismiss guard controls for mobile overlays.\n * モバイルオーバーレイのスワイプクローズ操作を制御するガード機構を提供。\n */\nexport const SwipeCloseGuardContext = createContext<SwipeCloseGuardContextValue | null>(null)\n\n/**\n * Returns the swipe-dismiss guard handlers for overlay content.\n * オーバーレイコンテンツ用のスワイプクローズガード制御を取得するフック。\n */\nexport const useSwipeCloseGuard = (): SwipeCloseGuardContextValue => {\n return useContext(SwipeCloseGuardContext) ?? { isBlocked: false, requestBlock: () => () => {} }\n}\n\ntype OverlayEscapeEntry = { id: string; onEscape: (e: KeyboardEvent) => boolean }\nconst overlayEscapeStack: OverlayEscapeEntry[] = []\n\nconst handleOverlayEscape = (e: KeyboardEvent) => {\n if (e.key !== \"Escape\") return\n const top = overlayEscapeStack[overlayEscapeStack.length - 1]\n if (top?.onEscape(e)) {\n e.preventDefault()\n e.stopPropagation()\n }\n}\n\n/**\n * Manages a LIFO stack for Escape key handling in overlays.\n * オーバーレイでの Escape キー処理を LIFO (後入れ先出し) で管理するフック。\n */\nexport const useOverlayEscapeStack = () => {\n return useCallback((entry: OverlayEscapeEntry) => {\n // 登録: 既存があれば削除して末尾に追加 (最優先)\n const idx = overlayEscapeStack.findIndex((x) => x.id === entry.id)\n if (idx >= 0) overlayEscapeStack.splice(idx, 1)\n overlayEscapeStack.push(entry)\n\n if (overlayEscapeStack.length === 1 && typeof document !== \"undefined\") {\n document.addEventListener(\"keydown\", handleOverlayEscape, true)\n }\n\n // 解除関数\n return () => {\n const index = overlayEscapeStack.findIndex((x) => x.id === entry.id)\n if (index >= 0) overlayEscapeStack.splice(index, 1)\n if (overlayEscapeStack.length === 0 && typeof document !== \"undefined\") {\n document.removeEventListener(\"keydown\", handleOverlayEscape, true)\n }\n }\n }, [])\n}\n\nexport type SwipeDismissHookResult = {\n overlayRef: (node: HTMLDivElement | null) => void\n overlayStyle: CSSProperties\n attemptClose: () => boolean\n isSwiping: boolean\n element: HTMLDivElement | null\n}\n\n/**\n * Manages swipe-to-dismiss interactions on the mobile overlay panel.\n * モバイルオーバーレイパネルのスワイプクローズ操作を管理。\n */\nexport const useSwipeToDismissOverlay = ({\n isOpen,\n onClose,\n isCloseBlocked,\n skipWhenTextSelected = false,\n}: {\n isOpen: boolean\n onClose: () => void\n isCloseBlocked: () => boolean\n skipWhenTextSelected?: boolean\n}): SwipeDismissHookResult => {\n const [element, setElement] = useState<HTMLDivElement | null>(null)\n const [isSwiping, setIsSwiping] = useState(false)\n const registerEscape = useOverlayEscapeStack()\n const overlayId = useRef(`overlay-${Math.random().toString(36).slice(2)}`).current\n\n // State ref to avoid re-renders during high-frequency pointer events\n const stateRef = useRef({\n pointerId: null as number | null,\n startX: 0,\n startY: 0,\n isActive: false,\n isClosing: false,\n lastDelta: 0,\n hasCapture: false,\n })\n\n const attemptClose = useCallback(() => {\n if (isCloseBlocked()) return false\n onClose()\n return true\n }, [isCloseBlocked, onClose])\n\n /**\n * Registers Escape key handler when open.\n * 開いている時に Escape キーハンドラを登録。\n */\n useEffect(() => {\n if (!isOpen) return\n return registerEscape({ id: overlayId, onEscape: attemptClose })\n }, [isOpen, attemptClose, registerEscape, overlayId])\n\n /**\n * Handles pointer events for swipe interaction.\n * スワイプ操作のためのポインターイベントを処理。\n */\n useEffect(() => {\n if (!(element && isOpen)) return\n\n const resetState = () => {\n const s = stateRef.current\n if (s.hasCapture && s.pointerId !== null) element.releasePointerCapture?.(s.pointerId)\n Object.assign(s, { pointerId: null, isActive: false, isClosing: false, hasCapture: false })\n element.style.transform = \"\"\n element.style.transition = \"\"\n setIsSwiping(false)\n }\n\n // Reset on open\n stateRef.current = { pointerId: null, startX: 0, startY: 0, isActive: false, isClosing: false, lastDelta: 0, hasCapture: false }\n setIsSwiping(false)\n\n const onPointerDown = (e: PointerEvent) => {\n if ((e.pointerType === \"mouse\" && e.button !== 0) || (e.target as HTMLElement)?.closest('[data-overlay-interactive=\"true\"]')) return\n if (skipWhenTextSelected && window.getSelection()?.toString().trim()) return\n\n element.style.transition = \"none\"\n setIsSwiping(true)\n stateRef.current = { pointerId: e.pointerId, startX: e.clientX, startY: e.clientY, isActive: true, isClosing: false, lastDelta: 0, hasCapture: false }\n }\n\n const onPointerMove = (e: PointerEvent) => {\n const s = stateRef.current\n if (!s.isActive || s.pointerId !== e.pointerId) return\n if (skipWhenTextSelected && window.getSelection()?.toString().trim()) { resetState(); return }\n\n const dx = e.clientX - s.startX\n const dy = e.clientY - s.startY\n\n if (!s.isClosing) {\n if (Math.abs(dx) < 4) return\n // Cancel if vertical scroll is dominant or moving left\n if (Math.abs(dx) < Math.abs(dy) * 1.3 || dx <= 0) { resetState(); return }\n s.isClosing = true\n if (!s.hasCapture) { element.setPointerCapture?.(e.pointerId); s.hasCapture = true }\n }\n\n if (s.isClosing) {\n e.preventDefault()\n s.lastDelta = Math.max(0, dx)\n element.style.transform = `translateX(${Math.min(s.lastDelta, 520)}px)`\n }\n }\n\n const onPointerUp = (e: PointerEvent) => {\n const s = stateRef.current\n if (s.pointerId !== e.pointerId) return\n\n if (s.isClosing && s.lastDelta > MOBILE_SWIPE_CLOSE_THRESHOLD) {\n element.style.transition = \"\"\n element.style.transform = \"translateX(100%)\"\n if (s.hasCapture && s.pointerId !== null) element.releasePointerCapture?.(s.pointerId)\n Object.assign(s, { pointerId: null, isActive: false, isClosing: false, hasCapture: false })\n setIsSwiping(false)\n attemptClose()\n } else {\n resetState()\n }\n }\n\n element.addEventListener(\"pointerdown\", onPointerDown)\n element.addEventListener(\"pointermove\", onPointerMove)\n element.addEventListener(\"pointerup\", onPointerUp)\n element.addEventListener(\"pointercancel\", resetState)\n\n return () => {\n element.removeEventListener(\"pointerdown\", onPointerDown)\n element.removeEventListener(\"pointermove\", onPointerMove)\n element.removeEventListener(\"pointerup\", onPointerUp)\n element.removeEventListener(\"pointercancel\", resetState)\n }\n }, [isOpen, element, attemptClose, skipWhenTextSelected])\n\n const overlayStyle = useMemo<CSSProperties>(() => ({\n transform: isOpen ? \"translateX(0px)\" : \"translateX(100%)\",\n }), [isOpen])\n\n return { overlayRef: setElement, overlayStyle, attemptClose, isSwiping, element }\n}\n"],"mappings":"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","names":["index_exports","__export","SwipeCloseGuardContext","useOverlayEscapeStack","useSwipeCloseGuard","useSwipeToDismissOverlay","__toCommonJS","import_react","MOBILE_SWIPE_CLOSE_THRESHOLD","overlayEscapeStack","handleOverlayEscape","e","entry","idx","x","index","isOpen","onClose","isCloseBlocked","skipWhenTextSelected","element","setElement","isSwiping","setIsSwiping","registerEscape","overlayId","stateRef","attemptClose","resetState","s","onPointerDown","onPointerMove","dx","dy","onPointerUp","overlayStyle"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { type CSSProperties, createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from \"react\"\n\nconst MOBILE_SWIPE_CLOSE_THRESHOLD = 120\n\n/* --- Contexts & Hooks for Overlay Management --- */\n\nexport type SwipeCloseGuardContextValue = { isBlocked: boolean; requestBlock: () => () => void }\n/**\n * Provides swipe-dismiss guard controls for mobile overlays.\n * モバイルオーバーレイのスワイプクローズ操作を制御するガード機構を提供。\n */\nexport const SwipeCloseGuardContext = createContext<SwipeCloseGuardContextValue | null>(null)\n\n/**\n * Returns the swipe-dismiss guard handlers for overlay content.\n * オーバーレイコンテンツ用のスワイプクローズガード制御を取得するフック。\n */\nexport const useSwipeCloseGuard = (): SwipeCloseGuardContextValue => {\n return useContext(SwipeCloseGuardContext) ?? { isBlocked: false, requestBlock: () => () => {} }\n}\n\ntype OverlayEscapeEntry = { id: string; onEscape: (e: KeyboardEvent) => boolean }\nconst overlayEscapeStack: OverlayEscapeEntry[] = []\n\nconst handleOverlayEscape = (e: KeyboardEvent) => {\n if (e.key !== \"Escape\") return\n const top = overlayEscapeStack[overlayEscapeStack.length - 1]\n if (top?.onEscape(e)) {\n e.preventDefault()\n e.stopPropagation()\n }\n}\n\n/**\n * Manages a LIFO stack for Escape key handling in overlays.\n * オーバーレイでの Escape キー処理を LIFO (後入れ先出し) で管理するフック。\n */\nexport const useOverlayEscapeStack = () => {\n return useCallback((entry: OverlayEscapeEntry) => {\n // 登録: 既存があれば削除して末尾に追加 (最優先)\n const idx = overlayEscapeStack.findIndex((x) => x.id === entry.id)\n if (idx >= 0) overlayEscapeStack.splice(idx, 1)\n overlayEscapeStack.push(entry)\n\n if (overlayEscapeStack.length === 1 && typeof document !== \"undefined\") {\n document.addEventListener(\"keydown\", handleOverlayEscape, true)\n }\n\n // 解除関数\n return () => {\n const index = overlayEscapeStack.findIndex((x) => x.id === entry.id)\n if (index >= 0) overlayEscapeStack.splice(index, 1)\n if (overlayEscapeStack.length === 0 && typeof document !== \"undefined\") {\n document.removeEventListener(\"keydown\", handleOverlayEscape, true)\n }\n }\n }, [])\n}\n\nexport type SwipeDismissHookResult = {\n overlayRef: (node: HTMLDivElement | null) => void\n overlayStyle: CSSProperties\n attemptClose: () => boolean\n isSwiping: boolean\n element: HTMLDivElement | null\n}\n\n/**\n * Manages swipe-to-dismiss interactions on the mobile overlay panel.\n * モバイルオーバーレイパネルのスワイプクローズ操作を管理。\n */\nexport const useSwipeToDismissOverlay = ({\n isOpen,\n onClose,\n isCloseBlocked,\n skipWhenTextSelected = false,\n}: {\n isOpen: boolean\n onClose: () => void\n isCloseBlocked: () => boolean\n skipWhenTextSelected?: boolean\n}): SwipeDismissHookResult => {\n const [element, setElement] = useState<HTMLDivElement | null>(null)\n const [isSwiping, setIsSwiping] = useState(false)\n const registerEscape = useOverlayEscapeStack()\n const overlayId = useRef(`overlay-${Math.random().toString(36).slice(2)}`).current\n\n // State ref to avoid re-renders during high-frequency pointer events\n const stateRef = useRef({\n pointerId: null as number | null,\n startX: 0,\n startY: 0,\n isActive: false,\n isClosing: false,\n lastDelta: 0,\n hasCapture: false,\n })\n\n const attemptClose = useCallback(() => {\n if (isCloseBlocked()) return false\n onClose()\n return true\n }, [isCloseBlocked, onClose])\n\n /**\n * Registers Escape key handler when open.\n * 開いている時に Escape キーハンドラを登録。\n */\n useEffect(() => {\n if (!isOpen) return\n return registerEscape({ id: overlayId, onEscape: attemptClose })\n }, [isOpen, attemptClose, registerEscape, overlayId])\n\n /**\n * Handles pointer events for swipe interaction.\n * スワイプ操作のためのポインターイベントを処理。\n */\n useEffect(() => {\n if (!(element && isOpen)) return\n\n const resetState = () => {\n const s = stateRef.current\n if (s.hasCapture && s.pointerId !== null) element.releasePointerCapture?.(s.pointerId)\n Object.assign(s, { pointerId: null, isActive: false, isClosing: false, hasCapture: false })\n element.style.transform = \"\"\n element.style.transition = \"\"\n setIsSwiping(false)\n }\n\n // Reset on open\n stateRef.current = { pointerId: null, startX: 0, startY: 0, isActive: false, isClosing: false, lastDelta: 0, hasCapture: false }\n setIsSwiping(false)\n\n const onPointerDown = (e: PointerEvent) => {\n if ((e.pointerType === \"mouse\" && e.button !== 0) || (e.target as HTMLElement)?.closest('[data-overlay-interactive=\"true\"]')) return\n if (skipWhenTextSelected && window.getSelection()?.toString().trim()) return\n\n element.style.transition = \"none\"\n setIsSwiping(true)\n stateRef.current = { pointerId: e.pointerId, startX: e.clientX, startY: e.clientY, isActive: true, isClosing: false, lastDelta: 0, hasCapture: false }\n }\n\n const onPointerMove = (e: PointerEvent) => {\n const s = stateRef.current\n if (!s.isActive || s.pointerId !== e.pointerId) return\n if (skipWhenTextSelected && window.getSelection()?.toString().trim()) { resetState(); return }\n\n const dx = e.clientX - s.startX\n const dy = e.clientY - s.startY\n\n if (!s.isClosing) {\n if (Math.abs(dx) < 4) return\n // Cancel if vertical scroll is dominant or moving left\n if (Math.abs(dx) < Math.abs(dy) * 1.3 || dx <= 0) { resetState(); return }\n s.isClosing = true\n if (!s.hasCapture) { element.setPointerCapture?.(e.pointerId); s.hasCapture = true }\n }\n\n if (s.isClosing) {\n e.preventDefault()\n s.lastDelta = Math.max(0, dx)\n element.style.transform = `translateX(${Math.min(s.lastDelta, 520)}px)`\n }\n }\n\n const onPointerUp = (e: PointerEvent) => {\n const s = stateRef.current\n if (s.pointerId !== e.pointerId) return\n\n if (s.isClosing && s.lastDelta > MOBILE_SWIPE_CLOSE_THRESHOLD) {\n element.style.transition = \"\"\n element.style.transform = \"translateX(100%)\"\n if (s.hasCapture && s.pointerId !== null) element.releasePointerCapture?.(s.pointerId)\n Object.assign(s, { pointerId: null, isActive: false, isClosing: false, hasCapture: false })\n setIsSwiping(false)\n attemptClose()\n } else {\n resetState()\n }\n }\n\n element.addEventListener(\"pointerdown\", onPointerDown)\n element.addEventListener(\"pointermove\", onPointerMove)\n element.addEventListener(\"pointerup\", onPointerUp)\n element.addEventListener(\"pointercancel\", resetState)\n\n return () => {\n element.removeEventListener(\"pointerdown\", onPointerDown)\n element.removeEventListener(\"pointermove\", onPointerMove)\n element.removeEventListener(\"pointerup\", onPointerUp)\n element.removeEventListener(\"pointercancel\", resetState)\n }\n }, [isOpen, element, attemptClose, skipWhenTextSelected])\n\n const overlayStyle = useMemo<CSSProperties>(() => ({\n transform: isOpen ? \"translateX(0px)\" : \"translateX(100%)\",\n }), [isOpen])\n\n return { overlayRef: setElement, overlayStyle, attemptClose, isSwiping, element }\n}\n"],"mappings":"AAAA,OAA6B,iBAAAA,EAAe,eAAAC,EAAa,cAAAC,EAAY,aAAAC,EAAW,WAAAC,EAAS,UAAAC,EAAQ,YAAAC,MAAgB,QAEjH,IAAMC,EAA+B,IASxBC,EAAyBR,EAAkD,IAAI,EAM/ES,EAAqB,IACvBP,EAAWM,CAAsB,GAAK,CAAE,UAAW,GAAO,aAAc,IAAM,IAAM,CAAC,CAAE,EAI5FE,EAA2C,CAAC,EAE5CC,EAAuBC,GAAqB,CAC9C,GAAIA,EAAE,MAAQ,SAAU,OACZF,EAAmBA,EAAmB,OAAS,CAAC,GACnD,SAASE,CAAC,IACfA,EAAE,eAAe,EACjBA,EAAE,gBAAgB,EAE1B,EAMaC,EAAwB,IAC1BZ,EAAaa,GAA8B,CAE9C,IAAMC,EAAML,EAAmB,UAAWM,GAAMA,EAAE,KAAOF,EAAM,EAAE,EACjE,OAAIC,GAAO,GAAGL,EAAmB,OAAOK,EAAK,CAAC,EAC9CL,EAAmB,KAAKI,CAAK,EAEzBJ,EAAmB,SAAW,GAAK,OAAO,SAAa,KACvD,SAAS,iBAAiB,UAAWC,EAAqB,EAAI,EAI3D,IAAM,CACT,IAAMM,EAAQP,EAAmB,UAAWM,GAAMA,EAAE,KAAOF,EAAM,EAAE,EAC/DG,GAAS,GAAGP,EAAmB,OAAOO,EAAO,CAAC,EAC9CP,EAAmB,SAAW,GAAK,OAAO,SAAa,KACvD,SAAS,oBAAoB,UAAWC,EAAqB,EAAI,CAEzE,CACJ,EAAG,CAAC,CAAC,EAeIO,EAA2B,CAAC,CACrC,OAAAC,EACA,QAAAC,EACA,eAAAC,EACA,qBAAAC,EAAuB,EAC3B,IAK8B,CAC1B,GAAM,CAACC,EAASC,CAAU,EAAIlB,EAAgC,IAAI,EAC5D,CAACmB,EAAWC,CAAY,EAAIpB,EAAS,EAAK,EAC1CqB,EAAiBd,EAAsB,EACvCe,EAAYvB,EAAO,WAAW,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC,EAAE,EAAE,QAGrEwB,EAAWxB,EAAO,CACpB,UAAW,KACX,OAAQ,EACR,OAAQ,EACR,SAAU,GACV,UAAW,GACX,UAAW,EACX,WAAY,EAChB,CAAC,EAEKyB,EAAe7B,EAAY,IACzBoB,EAAe,EAAU,IAC7BD,EAAQ,EACD,IACR,CAACC,EAAgBD,CAAO,CAAC,EAM5BjB,EAAU,IAAM,CACZ,GAAKgB,EACL,OAAOQ,EAAe,CAAE,GAAIC,EAAW,SAAUE,CAAa,CAAC,CACnE,EAAG,CAACX,EAAQW,EAAcH,EAAgBC,CAAS,CAAC,EAMpDzB,EAAU,IAAM,CACZ,GAAI,EAAEoB,GAAWJ,GAAS,OAE1B,IAAMY,EAAa,IAAM,CACrB,IAAMC,EAAIH,EAAS,QACfG,EAAE,YAAcA,EAAE,YAAc,MAAMT,EAAQ,wBAAwBS,EAAE,SAAS,EACrF,OAAO,OAAOA,EAAG,CAAE,UAAW,KAAM,SAAU,GAAO,UAAW,GAAO,WAAY,EAAM,CAAC,EAC1FT,EAAQ,MAAM,UAAY,GAC1BA,EAAQ,MAAM,WAAa,GAC3BG,EAAa,EAAK,CACtB,EAGAG,EAAS,QAAU,CAAE,UAAW,KAAM,OAAQ,EAAG,OAAQ,EAAG,SAAU,GAAO,UAAW,GAAO,UAAW,EAAG,WAAY,EAAM,EAC/HH,EAAa,EAAK,EAElB,IAAMO,EAAiBrB,GAAoB,CAClCA,EAAE,cAAgB,SAAWA,EAAE,SAAW,GAAOA,EAAE,QAAwB,QAAQ,mCAAmC,GACvHU,GAAwB,OAAO,aAAa,GAAG,SAAS,EAAE,KAAK,IAEnEC,EAAQ,MAAM,WAAa,OAC3BG,EAAa,EAAI,EACjBG,EAAS,QAAU,CAAE,UAAWjB,EAAE,UAAW,OAAQA,EAAE,QAAS,OAAQA,EAAE,QAAS,SAAU,GAAM,UAAW,GAAO,UAAW,EAAG,WAAY,EAAM,EACzJ,EAEMsB,EAAiBtB,GAAoB,CACvC,IAAMoB,EAAIH,EAAS,QACnB,GAAI,CAACG,EAAE,UAAYA,EAAE,YAAcpB,EAAE,UAAW,OAChD,GAAIU,GAAwB,OAAO,aAAa,GAAG,SAAS,EAAE,KAAK,EAAG,CAAES,EAAW,EAAG,MAAO,CAE7F,IAAMI,EAAKvB,EAAE,QAAUoB,EAAE,OACnBI,EAAKxB,EAAE,QAAUoB,EAAE,OAEzB,GAAI,CAACA,EAAE,UAAW,CACd,GAAI,KAAK,IAAIG,CAAE,EAAI,EAAG,OAEtB,GAAI,KAAK,IAAIA,CAAE,EAAI,KAAK,IAAIC,CAAE,EAAI,KAAOD,GAAM,EAAG,CAAEJ,EAAW,EAAG,MAAO,CACzEC,EAAE,UAAY,GACTA,EAAE,aAAcT,EAAQ,oBAAoBX,EAAE,SAAS,EAAGoB,EAAE,WAAa,GAClF,CAEIA,EAAE,YACFpB,EAAE,eAAe,EACjBoB,EAAE,UAAY,KAAK,IAAI,EAAGG,CAAE,EAC5BZ,EAAQ,MAAM,UAAY,cAAc,KAAK,IAAIS,EAAE,UAAW,GAAG,CAAC,MAE1E,EAEMK,EAAezB,GAAoB,CACrC,IAAMoB,EAAIH,EAAS,QACfG,EAAE,YAAcpB,EAAE,YAElBoB,EAAE,WAAaA,EAAE,UAAYzB,GAC7BgB,EAAQ,MAAM,WAAa,GAC3BA,EAAQ,MAAM,UAAY,mBACtBS,EAAE,YAAcA,EAAE,YAAc,MAAMT,EAAQ,wBAAwBS,EAAE,SAAS,EACrF,OAAO,OAAOA,EAAG,CAAE,UAAW,KAAM,SAAU,GAAO,UAAW,GAAO,WAAY,EAAM,CAAC,EAC1FN,EAAa,EAAK,EAClBI,EAAa,GAEbC,EAAW,EAEnB,EAEA,OAAAR,EAAQ,iBAAiB,cAAeU,CAAa,EACrDV,EAAQ,iBAAiB,cAAeW,CAAa,EACrDX,EAAQ,iBAAiB,YAAac,CAAW,EACjDd,EAAQ,iBAAiB,gBAAiBQ,CAAU,EAE7C,IAAM,CACTR,EAAQ,oBAAoB,cAAeU,CAAa,EACxDV,EAAQ,oBAAoB,cAAeW,CAAa,EACxDX,EAAQ,oBAAoB,YAAac,CAAW,EACpDd,EAAQ,oBAAoB,gBAAiBQ,CAAU,CAC3D,CACJ,EAAG,CAACZ,EAAQI,EAASO,EAAcR,CAAoB,CAAC,EAExD,IAAMgB,EAAelC,EAAuB,KAAO,CAC/C,UAAWe,EAAS,kBAAoB,kBAC5C,GAAI,CAACA,CAAM,CAAC,EAEZ,MAAO,CAAE,WAAYK,EAAY,aAAAc,EAAc,aAAAR,EAAc,UAAAL,EAAW,QAAAF,CAAQ,CACpF","names":["createContext","useCallback","useContext","useEffect","useMemo","useRef","useState","MOBILE_SWIPE_CLOSE_THRESHOLD","SwipeCloseGuardContext","useSwipeCloseGuard","overlayEscapeStack","handleOverlayEscape","e","useOverlayEscapeStack","entry","idx","x","index","useSwipeToDismissOverlay","isOpen","onClose","isCloseBlocked","skipWhenTextSelected","element","setElement","isSwiping","setIsSwiping","registerEscape","overlayId","stateRef","attemptClose","resetState","s","onPointerDown","onPointerMove","dx","dy","onPointerUp","overlayStyle"]}