@webority/mobile-ui 0.94.0 → 0.95.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.
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.useBottomSheet=exports.default=exports.BottomSheet=void 0;var cache,_react=require("react"),_reactNative=require("react-native"),_reactNativeGestureHandler=require("react-native-gesture-handler"),_reactNativeKeyboardController=require("react-native-keyboard-controller"),_reactNativeReanimated=_interopRequireWildcard(require("react-native-reanimated")),_reactNativeSafeAreaContext=require("react-native-safe-area-context"),_usePresenceMotion=require("../../hooks/usePresenceMotion.js"),_index=require("../../theme/index.js"),_index2=require("../../utils/index.js"),_corners=require("../../utils/corners.js"),_ModalSafeArea=require("../ModalSafeArea/ModalSafeArea.js"),_ToastProvider=require("../Toast/ToastProvider.js"),_jsxRuntime=require("react/jsx-runtime");function _interopRequireWildcard(e,t){if(!t&&e&&e.__esModule)return e;var a,r,n=Object.defineProperty,o={__proto__:null,default:e};if(Object(e)!==e)return o;if(cache||"function"!=typeof WeakMap||(cache=new WeakMap),cache){if(cache.has(e))return cache.get(e);cache.set(e,o)}for(r in e)"default"!==r&&{}.hasOwnProperty.call(e,r)&&((a=n&&Object.getOwnPropertyDescriptor(e,r))&&(a.get||a.set)?n(o,r,a):o[r]=e[r]);return o}const TABLET_MIN_SHORT_SIDE=600,DIALOG_MAX_WIDTH=560,BottomSheetContext=(0,_react.createContext)(null),useBottomSheet=()=>{const e=(0,_react.useContext)(BottomSheetContext);if(!e)throw new Error("useBottomSheet must be used inside a <BottomSheet>.");return e};exports.useBottomSheet=useBottomSheet;const SPRING_CONFIG={damping:20,stiffness:240,mass:1},CLOSE_VELOCITY_THRESHOLD=1e3,DRAG_ACTIVATION_OFFSET=10,BottomSheet=exports.BottomSheet=(0,_react.forwardRef)((e,t)=>{const{snapPoints:a,index:r,onChange:n,onAnimate:o,onAfterClose:s,enablePanDownToClose:i=!0,enableBackdropPress:c=!0,confirmDismiss:l,scrollable:u=!1,scrollRef:d,onScroll:_,onContentSizeChange:h,onScrollLayout:m,scrollEventThrottle:v,keyboardBehavior:f="shift",mode:b="modal",presentation:p="sheet",handleIndicatorStyle:S,containerStyle:R,header:x,footer:y,headerStyle:N,footerStyle:g,children:w,accessibilityLabel:C,accessibilityViewIsModal:j,testID:M}=e,k=(0,_index.useTheme)(),O=(0,_usePresenceMotion.usePresenceMotion)(),I=(0,_reactNativeSafeAreaContext.useSafeAreaInsets)(),[T,P]=(0,_react.useState)(()=>_reactNative.Dimensions.get("window").height),[E,A]=(0,_react.useState)(()=>_reactNative.Dimensions.get("window").width),H=(0,_react.useCallback)(e=>{const{height:t,width:a}=e.nativeEvent.layout;t>0&&P(e=>e===t?e:t),a>0&&A(e=>e===a?e:a)},[]),B=(0,_reactNative.useWindowDimensions)(),D="dialog"===p||"auto"===p&&Math.min(B.width,B.height)>=600,G=Math.min(560,E-2*k.space.xl),[V,q]=(0,_ModalSafeArea.useModalInsets)(),L="modal"===b?V.top:I.top,F="modal"===b?V.bottom:I.bottom,J=a.includes("content"),[W,z]=useMeasuredHeight(),[Y,$]=useMeasuredHeight(),[K,U,X]=useMeasuredHeight(),[Q,Z]=useMeasuredHeight(),ee=D?k.space.md:W,te=J?Math.min(ee+(null!=x?Y:0)+K+(null!=y?Q:0)+F,T-L):0,ae=(0,_react.useCallback)((e,t)=>{J&&X(t),h?.(e,t)},[J,h,X]),re=(0,_react.useMemo)(()=>resolveSnapPoints(a,T,te),[a,T,te]),ne=T,oe=re[re.length-1]??0,se=(0,_reactNativeReanimated.useSharedValue)(ne),ie=(0,_reactNativeReanimated.useSharedValue)(ne),ce=(0,_reactNativeReanimated.useSharedValue)(1),le=(0,_reactNativeReanimated.useSharedValue)(-1),[ue,de]=(0,_react.useState)(-1),he=(0,_react.useRef)(!1),[me,ve]=(0,_react.useState)(!1),[fe,be]=(0,_react.useState)(!1),pe=(0,_react.useRef)(!1),Se=(0,_react.useRef)(s);Se.current=s;const[Re,xe]=(0,_react.useState)(!1),ye=(0,_react.useRef)(-1),Ne=(0,_react.useRef)(!1);Ne.current="modal"===b?fe:Re;const ge=(0,_react.useRef)(l);ge.current=l;const we=(0,_react.useRef)(!1),Ce=(0,_react.useRef)(!0),je=(0,_react.useRef)([]),Me=(0,_react.useCallback)(e=>{const t=je.current;je.current=[];for(const a of t)a(e)},[]);(0,_react.useEffect)(()=>(Ce.current=!0,()=>{Ce.current=!1,Me(!1)}),[Me]);const ke=(0,_react.useCallback)(e=>{if(e<0||e>=re.length)return ne;const t=re[e];return D?(T-t)/2:T-t},[re,T,ne,D]),Oe=(0,_react.useCallback)(e=>{ye.current=e;ue!==e&&(de(e),le.value=e,n?.(e))},[ue,le,n]),Ie=(0,_react.useCallback)(()=>{he.current=!1,le.value<0&&(pe.current=!0,"modal"===b?(ve(!1),"ios"!==_reactNative.Platform.OS&&be(!1)):xe(!1))},[b,le]),Te=(0,_react.useCallback)(()=>{pe.current&&be(!1)},[]);(0,_react.useEffect)(()=>{("modal"===b?!fe:!Re)&&pe.current&&(pe.current=!1,Se.current?.(),Me(!0))},[b,fe,Re,Me]);const Pe=(0,_react.useCallback)((e,t,a)=>{he.current=!0,o?.(t,a),se.value=(0,_reactNativeReanimated.withSpring)(e,SPRING_CONFIG,e=>{"worklet";e&&(0,_reactNativeReanimated.runOnJS)(Ie)()})},[o,se,Ie]),Ee=(0,_react.useCallback)(e=>{const t="number"==typeof e?clamp(e,0,re.length-1):ue>=0?ue:0,a=le.value,r=ke(t);if(pe.current=!1,Me(!1),"modal"===b?(be(!0),ve(!0)):xe(!0),a<0&&O.reduced)return se.value=r,ce.value=0,ce.value=(0,_reactNativeReanimated.withTiming)(1,{duration:O.duration("fast"),easing:_reactNativeReanimated.Easing.bezier(...k.motion.ease.decelerate),reduceMotion:_usePresenceMotion.PRESENCE_REDUCE_MOTION}),Oe(t),void o?.(a,t);a<0&&(se.value=ne,ce.value=1),Oe(t),Pe(r,a,t)},[Pe,ne,ue,le,b,o,O,ce,re.length,Oe,Me,k.motion.ease.decelerate,se,ke]),Ae=(0,_react.useCallback)(()=>{if(0===re.length)return;const e=le.value,t=ke(0);Oe(0),Pe(t,e,0)},[Pe,le,re.length,Oe,ke]),He=(0,_react.useCallback)(()=>new Promise(e=>{if(ye.current<0)return void(Ne.current?je.current.push(e):e(!0));je.current.push(e);const t=le.value;Oe(-1),he.current=!0,o?.(t,-1);const a=O.reduced?ce:se,r=O.reduced?0:ne;a.value=(0,_reactNativeReanimated.withTiming)(r,{duration:O.duration("fast"),easing:_reactNativeReanimated.Easing.bezier(...k.motion.ease.accelerate),reduceMotion:_usePresenceMotion.PRESENCE_REDUCE_MOTION},e=>{"worklet";e&&(0,_reactNativeReanimated.runOnJS)(Ie)()})}),[ne,le,Ie,o,O,ce,Oe,se,k.motion.ease.accelerate]),Be=(0,_react.useCallback)(async()=>{await He()},[He]),De=(0,_react.useCallback)((e,t,a)=>{const r=ge.current;if(!r)return void e();if(we.current)return void t?.();const n=r();"boolean"!=typeof n?(we.current=!0,a?.(),n.then(a=>{we.current=!1,a&&Ce.current&&ye.current>=0?e():t?.()},e=>{throw we.current=!1,e})):(n?e:t)?.()},[]),Ge=(0,_react.useCallback)(()=>new Promise(e=>{ye.current<0?He().then(e):De(()=>{He().then(e)},()=>e(!1))}),[He,De]),Ve=(0,_react.useCallback)(()=>{c&&Ge()},[c,Ge]);(0,_react.useImperativeHandle)(t,()=>({expand:Ee,collapse:Ae,close:Be,requestClose:Ge}),[Ee,Ae,Be,Ge]),(0,_react.useEffect)(()=>{"number"==typeof r&&r!==ue&&(-1===r?Be():Ee(r))},[r]);const qe=(0,_react.useRef)({hostHeight:T,contentSnap:te});(0,_react.useEffect)(()=>{const e=qe.current;e.hostHeight===T&&e.contentSnap===te||(qe.current={hostHeight:T,contentSnap:te},e.hostHeight===T&&le.value<0||(se.value=(0,_reactNativeReanimated.withSpring)(ke(le.value),SPRING_CONFIG)))},[T,te]);const Le=T-oe,Fe=(0,_react.useMemo)(()=>re.map(e=>T-e),[re,T]),Je=(0,_react.useCallback)(()=>{const e=ye.current;e<0||Pe(ke(e),e,e)},[Pe,ke]),We=(0,_react.useCallback)((e,t)=>{const a=le.value;-1!==e?(Oe(e),Pe(t,a,e)):De(()=>{(0,_index2.triggerHaptic)("selection"),Be()},Je,Je)},[Pe,Be,le,De,Oe,Je]),ze=(0,_react.useMemo)(()=>_reactNativeGestureHandler.Gesture.Native().withTestId(M?`${M}-content-gesture`:"bottom-sheet-content-gesture"),[M]),Ye=(0,_react.useMemo)(()=>{const e=Fe,t=ne,a=Le,r=i;return _reactNativeGestureHandler.Gesture.Pan().withTestId(M?`${M}-pan-gesture`:"bottom-sheet-pan-gesture").activeOffsetY([-10,10]).failOffsetX([-15,15]).onStart(()=>{"worklet";ie.value=se.value}).onUpdate(e=>{"worklet";const t=ie.value+e.translationY;se.value=t<a?a+.25*(t-a):t}).onEnd(a=>{"worklet";const n=se.value;if(a.velocityY>1e3)return r?void(0,_reactNativeReanimated.runOnJS)(We)(-1,t):void(0,_reactNativeReanimated.runOnJS)(We)(0,e[0]);let o=0,s=Math.abs(n-e[0]);for(let t=1;t<e.length;t++){const a=Math.abs(n-e[t]);a<s&&(s=a,o=t)}const i=e[0];r&&n-i>80?(0,_reactNativeReanimated.runOnJS)(We)(-1,t):(0,_reactNativeReanimated.runOnJS)(We)(o,e[o])})},[ne,ie,i,We,Le,Fe,M,se]),{height:$e}=(0,_reactNativeKeyboardController.useReanimatedKeyboardAnimation)(),Ke="shift"===f,Ue=(0,_reactNativeReanimated.useDerivedValue)(()=>Ke?$e.value:0),Xe=re[ue>=0?ue:0]??oe,Qe=k.space.md,Ze=(0,_reactNativeReanimated.useAnimatedStyle)(()=>{if(D){const e=Ue.value,t=T+e-Xe-Qe,a=e<0&&se.value>t?t:se.value;return{top:a<L?L:a,opacity:ce.value}}const e=se.value+Ue.value,t=Ue.value<0?L:Le;return{top:e<t?t:e,opacity:ce.value}}),et=(0,_reactNativeReanimated.useAnimatedStyle)(()=>{const e=Ue.value;if(D){const t=T+e-Xe-Qe,a=e<0&&se.value>t?t:se.value,r=T+e-Qe-(a<L?L:a);return{height:r<0?0:r>Xe?Xe:r}}const t=e<0?L:Le,a=se.value+e,r=T+e-(a<t?t:a);return{height:r<0?0:r>oe?oe:r}}),tt=ue>=0,at=(0,_react.useMemo)(()=>buildStyles(k),[k]),rt=(0,_react.useCallback)(()=>{c&&De(()=>{(0,_index2.triggerHaptic)("selection"),Be()})},[c,Be,De]),nt=(0,_react.useMemo)(()=>_reactNativeGestureHandler.Gesture.Tap().withTestId(M?`${M}-backdrop-gesture`:"bottom-sheet-backdrop-gesture").maxDuration(250).onEnd((_e,e)=>{"worklet";e&&(0,_reactNativeReanimated.runOnJS)(rt)()}),[rt,M]),ot=(0,_react.useMemo)(()=>({snapIndex:ue,snapPoints:re,expand:Ee,collapse:Ae,close:Be,requestClose:Ge}),[ue,re,Ee,Ae,Be,Ge]);if("inline"===b&&!Re)return null;if("modal"===b&&!fe)return null;const st=(0,_jsxRuntime.jsxs)(_reactNative.View,{collapsable:!1,style:["modal"===b?at.backdropModal:at.backdropInline,{backgroundColor:k.colors.scrim}],onLayout:H,testID:M,accessibilityViewIsModal:j??tt,children:[(0,_jsxRuntime.jsx)(_reactNativeGestureHandler.GestureDetector,{gesture:nt,children:(0,_jsxRuntime.jsx)(_reactNativeReanimated.default.View,{style:_reactNative.StyleSheet.absoluteFill,accessibilityRole:"button",accessibilityLabel:"Close bottom sheet"})}),(0,_jsxRuntime.jsx)(_reactNativeReanimated.default.View,{accessibilityRole:"alert",accessibilityLabel:C,accessibilityViewIsModal:j??tt,accessibilityActions:[{name:"escape",label:"Close bottom sheet"}],onAccessibilityAction:e=>{"escape"===e.nativeEvent.actionName&&Ve()},onAccessibilityEscape:Ve,style:[at.sheet,{height:oe,backgroundColor:k.colors.surface,borderTopLeftRadius:k.radius.xl,borderTopRightRadius:k.radius.xl,..._corners.smoothCorners,...k.shadow.modal},D?{height:Xe,left:(E-G)/2,right:void 0,width:G,borderBottomLeftRadius:k.radius.xl,borderBottomRightRadius:k.radius.xl}:null,R,Ze],children:(0,_jsxRuntime.jsxs)(SheetBody,{style:[at.body,et],keyboardOffset:Ue,children:[D?(0,_jsxRuntime.jsx)(_reactNative.View,{style:{height:k.space.md}}):(0,_jsxRuntime.jsx)(_reactNativeGestureHandler.GestureDetector,{gesture:Ye,children:(0,_jsxRuntime.jsx)(_reactNative.View,{style:at.handleRow,onLayout:J?z:void 0,accessible:!0,accessibilityLabel:"Drag handle",accessibilityHint:"Drag up or down to resize the sheet, or swipe down to close it",testID:M?`${M}-handle`:"bottom-sheet-handle",children:(0,_jsxRuntime.jsx)(_reactNative.View,{style:[at.handle,{backgroundColor:k.colors.border},S]})})}),null!=x&&(0,_jsxRuntime.jsx)(_reactNative.View,{style:[at.header,N],onLayout:J?$:void 0,children:x}),u?(0,_jsxRuntime.jsx)(_reactNativeGestureHandler.GestureDetector,{gesture:ze,children:(0,_jsxRuntime.jsx)(_reactNative.ScrollView,{ref:d,style:at.scrollContent,onScroll:_,onContentSizeChange:ae,onLayout:m,scrollEventThrottle:v,keyboardShouldPersistTaps:"always",keyboardDismissMode:"none",children:w})}):(0,_jsxRuntime.jsx)(_reactNative.View,{style:J?[at.content,{overflow:"visible"}]:at.content,children:J?(0,_jsxRuntime.jsx)(_reactNative.View,{onLayout:U,children:w}):w}),null!=y&&(0,_jsxRuntime.jsx)(_reactNative.View,{style:[at.footer,g],onLayout:J?Z:void 0,children:y})]})})]}),it=(0,_jsxRuntime.jsx)(BottomSheetContext.Provider,{value:ot,children:st});return"modal"===b?(0,_jsxRuntime.jsx)(_reactNative.Modal,{transparent:!0,visible:me,onRequestClose:Ve,onDismiss:"ios"===_reactNative.Platform.OS?Te:void 0,statusBarTranslucent:!0,navigationBarTranslucent:!0,animationType:"none",supportedOrientations:["portrait","landscape"],children:(0,_jsxRuntime.jsxs)(_ModalSafeArea.ModalSafeArea,{onInsets:q,children:["android"===_reactNative.Platform.OS?(0,_jsxRuntime.jsx)(_reactNativeGestureHandler.GestureHandlerRootView,{style:at.modalRoot,children:it}):it,(0,_jsxRuntime.jsx)(_ToastProvider.ToastHost,{})]})}):it}),SheetBody=({style:e,keyboardOffset:t,children:a})=>{const r=(0,_reactNativeSafeAreaContext.useSafeAreaInsets)().bottom,n=(0,_reactNativeReanimated.useAnimatedStyle)(()=>{const e=r+t.value;return{paddingBottom:e>0?e:0}});return(0,_jsxRuntime.jsx)(_reactNativeReanimated.default.View,{style:[e,n],children:a})};BottomSheet.displayName="BottomSheet";const useMeasuredHeight=()=>{const[e,t]=(0,_react.useState)(0),a=(0,_react.useCallback)(e=>{t(t=>t===e?t:e)},[]);return[e,(0,_react.useCallback)(e=>a(e.nativeEvent.layout.height),[a]),a]},resolveSnapPoints=(e,t,a)=>[...e.map(e=>{if("number"==typeof e)return e;if("content"===e)return a;const r=parseFloat(e);return Number.isNaN(r)?0:r/100*t})].sort((e,t)=>e-t),clamp=(e,t,a)=>Math.min(Math.max(e,t),a),buildStyles=e=>_reactNative.StyleSheet.create({backdropModal:{flex:1},backdropInline:{..._reactNative.StyleSheet.absoluteFill},sheet:{position:"absolute",left:0,right:0,overflow:"hidden"},body:{overflow:"hidden"},handleRow:{alignItems:"center",justifyContent:"center",alignSelf:"stretch",paddingTop:e.space.md,paddingBottom:e.space.xl},header:{},footer:{},handle:{width:36,height:4,borderRadius:e.radius.pill,..._corners.smoothCorners},content:{flex:1,overflow:"hidden"},scrollContent:{flex:1},modalRoot:{flex:1}});var _default=exports.default=BottomSheet;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.useBottomSheet=exports.default=exports.BottomSheet=void 0;var cache,_react=require("react"),_reactNative=require("react-native"),_reactNativeGestureHandler=require("react-native-gesture-handler"),_reactNativeKeyboardController=require("react-native-keyboard-controller"),_reactNativeReanimated=_interopRequireWildcard(require("react-native-reanimated")),_reactNativeSafeAreaContext=require("react-native-safe-area-context"),_usePresenceMotion=require("../../hooks/usePresenceMotion.js"),_index=require("../../theme/index.js"),_index2=require("../../utils/index.js"),_corners=require("../../utils/corners.js"),_ModalSafeArea=require("../ModalSafeArea/ModalSafeArea.js"),_ToastProvider=require("../Toast/ToastProvider.js"),_jsxRuntime=require("react/jsx-runtime");function _interopRequireWildcard(e,t){if(!t&&e&&e.__esModule)return e;var a,r,n=Object.defineProperty,o={__proto__:null,default:e};if(Object(e)!==e)return o;if(cache||"function"!=typeof WeakMap||(cache=new WeakMap),cache){if(cache.has(e))return cache.get(e);cache.set(e,o)}for(r in e)"default"!==r&&{}.hasOwnProperty.call(e,r)&&((a=n&&Object.getOwnPropertyDescriptor(e,r))&&(a.get||a.set)?n(o,r,a):o[r]=e[r]);return o}const TABLET_MIN_SHORT_SIDE=600,DIALOG_MAX_WIDTH=560,BottomSheetContext=(0,_react.createContext)(null),useBottomSheet=()=>{const e=(0,_react.useContext)(BottomSheetContext);if(!e)throw new Error("useBottomSheet must be used inside a <BottomSheet>.");return e};exports.useBottomSheet=useBottomSheet;const SPRING_CONFIG={damping:20,stiffness:240,mass:1},CLOSE_VELOCITY_THRESHOLD=1e3,DRAG_ACTIVATION_OFFSET=10,BottomSheet=exports.BottomSheet=(0,_react.forwardRef)((e,t)=>{const{snapPoints:a,index:r,onChange:n,onAnimate:o,onAfterClose:s,enablePanDownToClose:i=!0,enableBackdropPress:c=!0,confirmDismiss:l,scrollable:u=!1,scrollRef:d,onScroll:_,onContentSizeChange:h,onScrollLayout:m,scrollEventThrottle:v,keyboardBehavior:f="shift",mode:b="modal",presentation:p="sheet",animateMount:S=!0,handleIndicatorStyle:R,containerStyle:x,header:y,footer:N,headerStyle:g,footerStyle:w,children:C,accessibilityLabel:j,accessibilityViewIsModal:M,testID:k}=e,O=(0,_index.useTheme)(),I=(0,_usePresenceMotion.usePresenceMotion)(),T=(0,_reactNativeSafeAreaContext.useSafeAreaInsets)(),[P,E]=(0,_react.useState)(()=>_reactNative.Dimensions.get("window").height),[A,H]=(0,_react.useState)(()=>_reactNative.Dimensions.get("window").width),B=(0,_react.useCallback)(e=>{const{height:t,width:a}=e.nativeEvent.layout;t>0&&E(e=>e===t?e:t),a>0&&H(e=>e===a?e:a)},[]),D=(0,_reactNative.useWindowDimensions)(),G="dialog"===p||"auto"===p&&Math.min(D.width,D.height)>=600,V=Math.min(560,A-2*O.space.xl),[q,L]=(0,_ModalSafeArea.useModalInsets)(),F="modal"===b?q.top:T.top,J="modal"===b?q.bottom:T.bottom,W=a.includes("content"),[z,Y]=useMeasuredHeight(),[$,K]=useMeasuredHeight(),[U,X,Q]=useMeasuredHeight(),[Z,ee]=useMeasuredHeight(),te=G?O.space.md:z,ae=W?Math.min(te+(null!=y?$:0)+U+(null!=N?Z:0)+J,P-F):0,re=(0,_react.useCallback)((e,t)=>{W&&Q(t),h?.(e,t)},[W,h,Q]),ne=(0,_react.useMemo)(()=>resolveSnapPoints(a,P,ae),[a,P,ae]),oe=P,se=ne[ne.length-1]??0,ie=(0,_reactNativeReanimated.useSharedValue)(oe),ce=(0,_reactNativeReanimated.useSharedValue)(oe),le=(0,_reactNativeReanimated.useSharedValue)(1),ue=(0,_reactNativeReanimated.useSharedValue)(-1),[de,he]=(0,_react.useState)(-1),me=(0,_react.useRef)(!1),[ve,fe]=(0,_react.useState)(!1),[be,pe]=(0,_react.useState)(!1),Se=(0,_react.useRef)(!1),Re=(0,_react.useRef)(s);Re.current=s;const[xe,ye]=(0,_react.useState)(!1),Ne=(0,_react.useRef)(!S&&"number"==typeof r&&r>=0),ge=(0,_react.useRef)(-1),we=(0,_react.useRef)(!1);we.current="modal"===b?be:xe;const Ce=(0,_react.useRef)(l);Ce.current=l;const je=(0,_react.useRef)(!1),Me=(0,_react.useRef)(!0),ke=(0,_react.useRef)([]),Oe=(0,_react.useCallback)(e=>{const t=ke.current;ke.current=[];for(const a of t)a(e)},[]);(0,_react.useEffect)(()=>(Me.current=!0,()=>{Me.current=!1,Oe(!1)}),[Oe]);const Ie=(0,_react.useCallback)(e=>{if(e<0||e>=ne.length)return oe;const t=ne[e];return G?(P-t)/2:P-t},[ne,P,oe,G]),Te=(0,_react.useCallback)(e=>{ge.current=e;de!==e&&(he(e),ue.value=e,n?.(e))},[de,ue,n]),Pe=(0,_react.useCallback)(()=>{me.current=!1,ue.value<0&&(Se.current=!0,"modal"===b?(fe(!1),"ios"!==_reactNative.Platform.OS&&pe(!1)):ye(!1))},[b,ue]),Ee=(0,_react.useCallback)(()=>{Se.current&&pe(!1)},[]);(0,_react.useEffect)(()=>{("modal"===b?!be:!xe)&&Se.current&&(Se.current=!1,Re.current?.(),Oe(!0))},[b,be,xe,Oe]);const Ae=(0,_react.useCallback)((e,t,a)=>{me.current=!0,o?.(t,a),ie.value=(0,_reactNativeReanimated.withSpring)(e,SPRING_CONFIG,e=>{"worklet";e&&(0,_reactNativeReanimated.runOnJS)(Pe)()})},[o,ie,Pe]),He=(0,_react.useCallback)(e=>{const t="number"==typeof e?clamp(e,0,ne.length-1):de>=0?de:0,a=ue.value,r=Ie(t);return Se.current=!1,Oe(!1),"modal"===b?(pe(!0),fe(!0)):ye(!0),a<0&&Ne.current?(ie.value=r,le.value=1,Te(t),void o?.(a,t)):a<0&&I.reduced?(ie.value=r,le.value=0,le.value=(0,_reactNativeReanimated.withTiming)(1,{duration:I.duration("fast"),easing:_reactNativeReanimated.Easing.bezier(...O.motion.ease.decelerate),reduceMotion:_usePresenceMotion.PRESENCE_REDUCE_MOTION}),Te(t),void o?.(a,t)):(a<0&&(ie.value=oe,le.value=1),Te(t),void Ae(r,a,t))},[Ae,oe,de,ue,b,o,I,le,ne.length,Te,Oe,O.motion.ease.decelerate,ie,Ie]),Be=(0,_react.useCallback)(()=>{if(0===ne.length)return;const e=ue.value,t=Ie(0);Te(0),Ae(t,e,0)},[Ae,ue,ne.length,Te,Ie]),De=(0,_react.useCallback)(()=>new Promise(e=>{if(ge.current<0)return void(we.current?ke.current.push(e):e(!0));ke.current.push(e),Ne.current=!1;const t=ue.value;Te(-1),me.current=!0,o?.(t,-1);const a=I.reduced?le:ie,r=I.reduced?0:oe;a.value=(0,_reactNativeReanimated.withTiming)(r,{duration:I.duration("fast"),easing:_reactNativeReanimated.Easing.bezier(...O.motion.ease.accelerate),reduceMotion:_usePresenceMotion.PRESENCE_REDUCE_MOTION},e=>{"worklet";e&&(0,_reactNativeReanimated.runOnJS)(Pe)()})}),[oe,ue,Pe,o,I,le,Te,ie,O.motion.ease.accelerate]),Ge=(0,_react.useCallback)(async()=>{await De()},[De]),Ve=(0,_react.useCallback)((e,t,a)=>{const r=Ce.current;if(!r)return void e();if(je.current)return void t?.();const n=r();"boolean"!=typeof n?(je.current=!0,a?.(),n.then(a=>{je.current=!1,a&&Me.current&&ge.current>=0?e():t?.()},e=>{throw je.current=!1,e})):(n?e:t)?.()},[]),qe=(0,_react.useCallback)(()=>new Promise(e=>{ge.current<0?De().then(e):Ve(()=>{De().then(e)},()=>e(!1))}),[De,Ve]),Le=(0,_react.useCallback)(()=>{c&&qe()},[c,qe]);(0,_react.useImperativeHandle)(t,()=>({expand:He,collapse:Be,close:Ge,requestClose:qe}),[He,Be,Ge,qe]),(0,_react.useEffect)(()=>{"number"==typeof r&&r!==de&&(-1===r?Ge():He(r))},[r]);const Fe=(0,_react.useRef)({hostHeight:P,contentSnap:ae});(0,_react.useEffect)(()=>{const e=Fe.current;if(e.hostHeight===P&&e.contentSnap===ae)return;if(Fe.current={hostHeight:P,contentSnap:ae},e.hostHeight===P&&ue.value<0)return;const t=Ie(ue.value);ie.value=Ne.current?t:(0,_reactNativeReanimated.withSpring)(t,SPRING_CONFIG)},[P,ae]);const Je=P-se,We=(0,_react.useMemo)(()=>ne.map(e=>P-e),[ne,P]),ze=(0,_react.useCallback)(()=>{const e=ge.current;e<0||Ae(Ie(e),e,e)},[Ae,Ie]),Ye=(0,_react.useCallback)((e,t)=>{const a=ue.value;-1!==e?(Te(e),Ae(t,a,e)):Ve(()=>{(0,_index2.triggerHaptic)("selection"),Ge()},ze,ze)},[Ae,Ge,ue,Ve,Te,ze]),$e=(0,_react.useMemo)(()=>_reactNativeGestureHandler.Gesture.Native().withTestId(k?`${k}-content-gesture`:"bottom-sheet-content-gesture"),[k]),Ke=(0,_react.useMemo)(()=>{const e=We,t=oe,a=Je,r=i;return _reactNativeGestureHandler.Gesture.Pan().withTestId(k?`${k}-pan-gesture`:"bottom-sheet-pan-gesture").activeOffsetY([-10,10]).failOffsetX([-15,15]).onStart(()=>{"worklet";ce.value=ie.value}).onUpdate(e=>{"worklet";const t=ce.value+e.translationY;ie.value=t<a?a+.25*(t-a):t}).onEnd(a=>{"worklet";const n=ie.value;if(a.velocityY>1e3)return r?void(0,_reactNativeReanimated.runOnJS)(Ye)(-1,t):void(0,_reactNativeReanimated.runOnJS)(Ye)(0,e[0]);let o=0,s=Math.abs(n-e[0]);for(let t=1;t<e.length;t++){const a=Math.abs(n-e[t]);a<s&&(s=a,o=t)}const i=e[0];r&&n-i>80?(0,_reactNativeReanimated.runOnJS)(Ye)(-1,t):(0,_reactNativeReanimated.runOnJS)(Ye)(o,e[o])})},[oe,ce,i,Ye,Je,We,k,ie]),{height:Ue}=(0,_reactNativeKeyboardController.useReanimatedKeyboardAnimation)(),Xe="shift"===f,Qe=(0,_reactNativeReanimated.useDerivedValue)(()=>Xe?Ue.value:0),Ze=ne[de>=0?de:0]??se,et=O.space.md,tt=(0,_reactNativeReanimated.useAnimatedStyle)(()=>{if(G){const e=Qe.value,t=P+e-Ze-et,a=e<0&&ie.value>t?t:ie.value;return{top:a<F?F:a,opacity:le.value}}const e=ie.value+Qe.value,t=Qe.value<0?F:Je;return{top:e<t?t:e,opacity:le.value}}),at=(0,_reactNativeReanimated.useAnimatedStyle)(()=>{const e=Qe.value;if(G){const t=P+e-Ze-et,a=e<0&&ie.value>t?t:ie.value,r=P+e-et-(a<F?F:a);return{height:r<0?0:r>Ze?Ze:r}}const t=e<0?F:Je,a=ie.value+e,r=P+e-(a<t?t:a);return{height:r<0?0:r>se?se:r}}),rt=de>=0,nt=(0,_react.useMemo)(()=>buildStyles(O),[O]),ot=(0,_react.useCallback)(()=>{c&&Ve(()=>{(0,_index2.triggerHaptic)("selection"),Ge()})},[c,Ge,Ve]),st=(0,_react.useMemo)(()=>_reactNativeGestureHandler.Gesture.Tap().withTestId(k?`${k}-backdrop-gesture`:"bottom-sheet-backdrop-gesture").maxDuration(250).onEnd((_e,e)=>{"worklet";e&&(0,_reactNativeReanimated.runOnJS)(ot)()}),[ot,k]),it=(0,_react.useMemo)(()=>({snapIndex:de,snapPoints:ne,expand:He,collapse:Be,close:Ge,requestClose:qe}),[de,ne,He,Be,Ge,qe]);if("inline"===b&&!xe)return null;if("modal"===b&&!be)return null;const ct=(0,_jsxRuntime.jsxs)(_reactNative.View,{collapsable:!1,style:["modal"===b?nt.backdropModal:nt.backdropInline,{backgroundColor:O.colors.scrim}],onLayout:B,testID:k,accessibilityViewIsModal:M??rt,children:[(0,_jsxRuntime.jsx)(_reactNativeGestureHandler.GestureDetector,{gesture:st,children:(0,_jsxRuntime.jsx)(_reactNativeReanimated.default.View,{style:_reactNative.StyleSheet.absoluteFill,accessibilityRole:"button",accessibilityLabel:"Close bottom sheet"})}),(0,_jsxRuntime.jsx)(_reactNativeReanimated.default.View,{accessibilityRole:"alert",accessibilityLabel:j,accessibilityViewIsModal:M??rt,accessibilityActions:[{name:"escape",label:"Close bottom sheet"}],onAccessibilityAction:e=>{"escape"===e.nativeEvent.actionName&&Le()},onAccessibilityEscape:Le,style:[nt.sheet,{height:se,backgroundColor:O.colors.surface,borderTopLeftRadius:O.radius.xl,borderTopRightRadius:O.radius.xl,..._corners.smoothCorners,...O.shadow.modal},G?{height:Ze,left:(A-V)/2,right:void 0,width:V,borderBottomLeftRadius:O.radius.xl,borderBottomRightRadius:O.radius.xl}:null,x,tt],children:(0,_jsxRuntime.jsxs)(SheetBody,{style:[nt.body,at],keyboardOffset:Qe,children:[G?(0,_jsxRuntime.jsx)(_reactNative.View,{style:{height:O.space.md}}):(0,_jsxRuntime.jsx)(_reactNativeGestureHandler.GestureDetector,{gesture:Ke,children:(0,_jsxRuntime.jsx)(_reactNative.View,{style:nt.handleRow,onLayout:W?Y:void 0,accessible:!0,accessibilityLabel:"Drag handle",accessibilityHint:"Drag up or down to resize the sheet, or swipe down to close it",testID:k?`${k}-handle`:"bottom-sheet-handle",children:(0,_jsxRuntime.jsx)(_reactNative.View,{style:[nt.handle,{backgroundColor:O.colors.border},R]})})}),null!=y&&(0,_jsxRuntime.jsx)(_reactNative.View,{style:[nt.header,g],onLayout:W?K:void 0,children:y}),u?(0,_jsxRuntime.jsx)(_reactNativeGestureHandler.GestureDetector,{gesture:$e,children:(0,_jsxRuntime.jsx)(_reactNative.ScrollView,{ref:d,style:nt.scrollContent,onScroll:_,onContentSizeChange:re,onLayout:m,scrollEventThrottle:v,keyboardShouldPersistTaps:"always",keyboardDismissMode:"none",children:C})}):(0,_jsxRuntime.jsx)(_reactNative.View,{style:W?[nt.content,{overflow:"visible"}]:nt.content,children:W?(0,_jsxRuntime.jsx)(_reactNative.View,{onLayout:X,children:C}):C}),null!=N&&(0,_jsxRuntime.jsx)(_reactNative.View,{style:[nt.footer,w],onLayout:W?ee:void 0,children:N})]})})]}),lt=(0,_jsxRuntime.jsx)(BottomSheetContext.Provider,{value:it,children:ct});return"modal"===b?(0,_jsxRuntime.jsx)(_reactNative.Modal,{transparent:!0,visible:ve,onRequestClose:Le,onDismiss:"ios"===_reactNative.Platform.OS?Ee:void 0,statusBarTranslucent:!0,navigationBarTranslucent:!0,animationType:"none",supportedOrientations:["portrait","landscape"],children:(0,_jsxRuntime.jsxs)(_ModalSafeArea.ModalSafeArea,{onInsets:L,children:["android"===_reactNative.Platform.OS?(0,_jsxRuntime.jsx)(_reactNativeGestureHandler.GestureHandlerRootView,{style:nt.modalRoot,children:lt}):lt,(0,_jsxRuntime.jsx)(_ToastProvider.ToastHost,{})]})}):lt}),SheetBody=({style:e,keyboardOffset:t,children:a})=>{const r=(0,_reactNativeSafeAreaContext.useSafeAreaInsets)().bottom,n=(0,_reactNativeReanimated.useAnimatedStyle)(()=>{const e=r+t.value;return{paddingBottom:e>0?e:0}});return(0,_jsxRuntime.jsx)(_reactNativeReanimated.default.View,{style:[e,n],children:a})};BottomSheet.displayName="BottomSheet";const useMeasuredHeight=()=>{const[e,t]=(0,_react.useState)(0),a=(0,_react.useCallback)(e=>{t(t=>t===e?t:e)},[]);return[e,(0,_react.useCallback)(e=>a(e.nativeEvent.layout.height),[a]),a]},resolveSnapPoints=(e,t,a)=>[...e.map(e=>{if("number"==typeof e)return e;if("content"===e)return a;const r=parseFloat(e);return Number.isNaN(r)?0:r/100*t})].sort((e,t)=>e-t),clamp=(e,t,a)=>Math.min(Math.max(e,t),a),buildStyles=e=>_reactNative.StyleSheet.create({backdropModal:{flex:1},backdropInline:{..._reactNative.StyleSheet.absoluteFill},sheet:{position:"absolute",left:0,right:0,overflow:"hidden"},body:{overflow:"hidden"},handleRow:{alignItems:"center",justifyContent:"center",alignSelf:"stretch",paddingTop:e.space.md,paddingBottom:e.space.xl},header:{},footer:{},handle:{width:36,height:4,borderRadius:e.radius.pill,..._corners.smoothCorners},content:{flex:1,overflow:"hidden"},scrollContent:{flex:1},modalRoot:{flex:1}});var _default=exports.default=BottomSheet;
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.meta=void 0;var _meta=require("../../canvasKit/meta.js");const meta=exports.meta=(0,_meta.definePhoneMeta)()({name:"BottomSheet",marker:null,platforms:["phone"],acceptsChildren:!0,props:{snapPoints:{type:"array",required:!0,description:"The heights the sheet rests at: a number of points, a percentage such as 50%, or content to hug the content."},index:{type:"number",description:"The snap point the sheet shows, counted from 0. Minus one closes it."},enablePanDownToClose:{type:"boolean",default:!0,description:"Lets a drag on the handle past the threshold close the sheet."},enableBackdropPress:{type:"boolean",default:!0,description:"Lets a tap on the scrim close the sheet. Back and Escape follow it."},scrollable:{type:"boolean",default:!1,description:"Wraps the content in a vertical scroll view between the header and the footer."},scrollEventThrottle:{type:"number",description:"How often the inner scroll view reports scrolling, in milliseconds. Used only with scrollable."},backdropOpacity:{type:"number",description:"The opacity of the scrim."},keyboardBehavior:{type:"enum",values:["none","shift"],default:"shift",description:"How the sheet reacts to the keyboard. Shift rides up with it; none stays put."},mode:{type:"enum",values:["modal","inline"],default:"modal",description:"Modal covers the whole screen in a native modal; inline overlays the parent view."},presentation:{type:"enum",values:["sheet","dialog","auto"],default:"sheet",description:"Sheet is full width at the bottom; dialog is centred; auto picks a dialog on a tablet."},header:{type:"node",description:"A fixed region between the handle and the content. It does not scroll."},footer:{type:"node",description:"A fixed region at the bottom of the sheet, such as a row of buttons."},accessibilityLabel:{type:"string",description:"Names the sheet for a screen reader."},accessibilityViewIsModal:{type:"boolean",description:"Tells a screen reader to ignore what is behind the sheet."}},omit:["scrollRef"],examples:[{id:"BottomSheet.content",title:"Hugs its content",props:{snapPoints:["content"],mode:"inline",index:0},children:"Sheet content."},{id:"BottomSheet.headerFooter",title:"Header and footer",props:{snapPoints:["50%"],mode:"inline",index:0,header:"Filters",footer:"Apply"},children:"Choose how to filter the list."},{id:"BottomSheet.dialog",title:"Dialog presentation",props:{snapPoints:["50%"],presentation:"dialog",mode:"inline",index:0},children:"Centred on a tablet."}],usage:{when:["A short task or a list of choices belongs on top of the current screen.","The person should be able to drag the sheet between a small and a tall height.","The content needs a fixed header or a fixed row of buttons."],whenNot:[{text:"The person must answer one question before going on.",instead:"Dialog"},{text:"The content is a full screen of its own.",instead:"a new screen"}],do:[{note:"Use the content snap point so the sheet is as tall as what it holds.",example:[{component:"BottomSheet",props:{snapPoints:["content"],mode:"inline",index:0}}]}],dont:[{note:"Do not set a snap point taller than the content needs. It leaves a large empty area.",example:[{component:"BottomSheet",props:{snapPoints:["90%"],mode:"inline",index:0}}]}],a11y:["Turning off backdrop press also turns off Back and Escape, so a sheet that must be answered stays open.","Set accessibilityLabel so a screen reader names the sheet when it opens."]}});
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.meta=void 0;var _meta=require("../../canvasKit/meta.js");const meta=exports.meta=(0,_meta.definePhoneMeta)()({name:"BottomSheet",marker:null,platforms:["phone"],acceptsChildren:!0,props:{snapPoints:{type:"array",required:!0,description:"The heights the sheet rests at: a number of points, a percentage such as 50%, or content to hug the content."},index:{type:"number",description:"The snap point the sheet shows, counted from 0. Minus one closes it."},enablePanDownToClose:{type:"boolean",default:!0,description:"Lets a drag on the handle past the threshold close the sheet."},enableBackdropPress:{type:"boolean",default:!0,description:"Lets a tap on the scrim close the sheet. Back and Escape follow it."},scrollable:{type:"boolean",default:!1,description:"Wraps the content in a vertical scroll view between the header and the footer."},scrollEventThrottle:{type:"number",description:"How often the inner scroll view reports scrolling, in milliseconds. Used only with scrollable."},backdropOpacity:{type:"number",description:"The opacity of the scrim."},keyboardBehavior:{type:"enum",values:["none","shift"],default:"shift",description:"How the sheet reacts to the keyboard. Shift rides up with it; none stays put."},mode:{type:"enum",values:["modal","inline"],default:"modal",description:"Modal covers the whole screen in a native modal; inline overlays the parent view."},presentation:{type:"enum",values:["sheet","dialog","auto"],default:"sheet",description:"Sheet is full width at the bottom; dialog is centred; auto picks a dialog on a tablet."},animateMount:{type:"boolean",default:!0,description:"Slides the sheet up when it opens as it mounts. Off, it is drawn at its snap point at once."},header:{type:"node",description:"A fixed region between the handle and the content. It does not scroll."},footer:{type:"node",description:"A fixed region at the bottom of the sheet, such as a row of buttons."},accessibilityLabel:{type:"string",description:"Names the sheet for a screen reader."},accessibilityViewIsModal:{type:"boolean",description:"Tells a screen reader to ignore what is behind the sheet."}},omit:["scrollRef"],examples:[{id:"BottomSheet.content",title:"Hugs its content",props:{snapPoints:["content"],mode:"inline",index:0},children:"Sheet content."},{id:"BottomSheet.headerFooter",title:"Header and footer",props:{snapPoints:["50%"],mode:"inline",index:0,header:"Filters",footer:"Apply"},children:"Choose how to filter the list."},{id:"BottomSheet.dialog",title:"Dialog presentation",props:{snapPoints:["50%"],presentation:"dialog",mode:"inline",index:0},children:"Centred on a tablet."}],usage:{when:["A short task or a list of choices belongs on top of the current screen.","The person should be able to drag the sheet between a small and a tall height.","The content needs a fixed header or a fixed row of buttons."],whenNot:[{text:"The person must answer one question before going on.",instead:"Dialog"},{text:"The content is a full screen of its own.",instead:"a new screen"}],do:[{note:"Use the content snap point so the sheet is as tall as what it holds.",example:[{component:"BottomSheet",props:{snapPoints:["content"],mode:"inline",index:0}}]}],dont:[{note:"Do not set a snap point taller than the content needs. It leaves a large empty area.",example:[{component:"BottomSheet",props:{snapPoints:["90%"],mode:"inline",index:0}}]}],a11y:["Turning off backdrop press also turns off Back and Escape, so a sheet that must be answered stays open.","Set accessibilityLabel so a screen reader names the sheet when it opens."]}});
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=exports.Modal=exports.MODAL_DISMISS_GRACE_MS=void 0;var _react=require("react"),_reactNative=require("react-native"),_usePresenceMotion=require("../../hooks/usePresenceMotion.js"),_index=require("../../theme/index.js"),_color=require("../../utils/color.js"),_corners=require("../../utils/corners.js"),_hapticUtils=require("../../utils/hapticUtils.js"),_squircle=require("../../utils/squircle.js"),_ModalSafeArea=require("../ModalSafeArea/ModalSafeArea.js"),_SquircleFill=require("../SquircleFill/SquircleFill.js"),_ToastProvider=require("../Toast/ToastProvider.js"),_jsxRuntime=require("react/jsx-runtime");const MODAL_DISMISS_GRACE_MS=exports.MODAL_DISMISS_GRACE_MS=300,SCALE_START_VALUE=.9,Modal=exports.Modal=(0,_react.forwardRef)((e,t)=>{const{visible:r,onRequestClose:a,presentation:i="centered",backdropOpacity:s,backdropPressClose:o=!0,animationDuration:n,accessibilityLabel:l,hardwareBackPress:c=!0,children:u,contentStyle:d,backdropStyle:m,restoreFocusRef:_,onDismissed:f,haptic:p,testID:v}=e,g=(0,_index.useTheme)(),b=(0,_usePresenceMotion.usePresenceMotion)(),[S,h]=(0,_ModalSafeArea.useModalInsets)(),x=n??b.duration("default"),A=_reactNative.Dimensions.get("window").height,M=(0,_react.useRef)((0,_index.createAnimatedValue)(.9)).current,N=(0,_react.useRef)((0,_index.createAnimatedValue)(0)).current,y=(0,_react.useRef)((0,_index.createAnimatedValue)(A)).current,R=(0,_react.useRef)((0,_index.createAnimatedValue)(0)).current,j=(0,_react.useRef)(null),q=(0,_react.useRef)(!1),[C,V]=(0,_react.useState)(r),D=(0,_react.useMemo)(()=>buildStyles(g),[g]),T=(0,_react.useMemo)(()=>{const e=g.colors.scrim;return"number"!=typeof s?e:(0,_color.withAlpha)(e,s)??e},[g.colors.scrim,s]),w=(0,_react.useMemo)(()=>R.interpolate({inputRange:[0,1],outputRange:[(0,_color.transparentOf)(T),T]}),[R,T]);(0,_react.useEffect)(()=>{r&&V(!0)},[r]),(0,_react.useEffect)(()=>{const e=[];if(r&&C){const t=_reactNative.Animated.timing(R,{toValue:1,duration:b.duration("default"),useNativeDriver:!1});if(t.start(),e.push(t),b.reduced){N.setValue(0),y.setValue(0),M.setValue(1);const t=_reactNative.Animated.timing(N,{toValue:1,duration:x,useNativeDriver:!0});t.start(),e.push(t)}else if("bottom"===i){N.setValue(1);const t=_reactNative.Animated.spring(y,{toValue:0,damping:g.motion.spring.gentle.damping,stiffness:g.motion.spring.gentle.stiffness,mass:g.motion.spring.gentle.mass,useNativeDriver:!0});t.start(),e.push(t)}else{const t=_reactNative.Animated.parallel([_reactNative.Animated.spring(M,{toValue:1,damping:g.motion.spring.gentle.damping,stiffness:g.motion.spring.gentle.stiffness,mass:g.motion.spring.gentle.mass,useNativeDriver:!0}),_reactNative.Animated.timing(N,{toValue:1,duration:x,useNativeDriver:!0})]);t.start(),e.push(t)}}else if(C){const t=b.duration("fast"),r=_reactNative.Easing.bezier(...g.motion.ease.accelerate),a=_reactNative.Animated.timing(N,{toValue:0,duration:t,easing:r,useNativeDriver:!0}),s=b.reduced?a:"bottom"===i?_reactNative.Animated.timing(y,{toValue:A,duration:t,easing:r,useNativeDriver:!0}):_reactNative.Animated.parallel([_reactNative.Animated.timing(M,{toValue:.9,duration:t,easing:r,useNativeDriver:!0}),a]),o=_reactNative.Animated.parallel([s,_reactNative.Animated.timing(R,{toValue:0,duration:b.duration("default"),useNativeDriver:!1})]);o.start(({finished:e})=>{e&&(y.setValue(A),V(!1))}),e.push(o)}return()=>e.forEach(e=>e.stop())},[r,C,i,x,M,N,R,y,A,g.motion.spring.gentle.damping,g.motion.spring.gentle.stiffness,g.motion.spring.gentle.mass,b,g.motion.ease.accelerate]),(0,_react.useEffect)(()=>{if("web"===_reactNative.Platform.OS)return;let e,t;return r?(e=setTimeout(()=>{j.current&&_reactNative.AccessibilityInfo.sendAccessibilityEvent(j.current,"focus")},150),q.current=!0):q.current&&(q.current=!1,_&&_.current&&(t=setTimeout(()=>{const e=_.current;e&&_reactNative.AccessibilityInfo.sendAccessibilityEvent(e,"focus")},x))),()=>{e&&clearTimeout(e),t&&clearTimeout(t)}},[r,x,_]);const I=(0,_react.useRef)(!1);(0,_react.useEffect)(()=>{if(r)return void(I.current=!0);if(!I.current)return;if(I.current=!1,!f)return;const e=setTimeout(f,MODAL_DISMISS_GRACE_MS);return()=>clearTimeout(e)},[r,f]);const E=(0,_react.useCallback)(()=>{if(!o)return;const e=(0,_hapticUtils.resolveHaptic)(p,"selection");e&&(0,_hapticUtils.triggerHaptic)(e),a()},[o,a,p]),P=(0,_react.useCallback)(()=>{c&&a()},[c,a]),L=(0,_SquircleFill.useSquircle)("bottom"!==i&&"fullScreen"!==i,g.radius.xl),k=(0,_react.useMemo)(()=>"fullScreen"===i?[D.fullScreenContent,{backgroundColor:g.colors.surface}]:"bottom"===i?[D.bottomContent,{backgroundColor:g.colors.surface,borderTopLeftRadius:g.radius.xl,borderTopRightRadius:g.radius.xl,..._corners.smoothCorners,paddingTop:g.space.lg,paddingHorizontal:g.space.lg,paddingBottom:g.space.lg+S.bottom},g.shadow.modal]:[D.centeredContent,{backgroundColor:g.colors.surface,borderRadius:L.active&&L.size?(0,_squircle.squircleHostRadius)(L.size.width,L.size.height,g.radius.xl):g.radius.xl,..._corners.smoothCorners,padding:g.space.xl},g.shadow.modal],[i,g,D,S.bottom,L.active,L.size]),z=(0,_react.useMemo)(()=>"bottom"===i?D.bottomWrapper:"fullScreen"===i?D.fullScreenWrapper:D.centeredWrapper,[i,D]),F=(0,_react.useMemo)(()=>"bottom"===i?{opacity:N,transform:[{translateY:y}]}:"fullScreen"===i?{opacity:N}:{opacity:N,transform:[{scale:M}]},[i,M,N,y]);return(0,_jsxRuntime.jsx)(_reactNative.Modal,{visible:C,transparent:!0,statusBarTranslucent:!0,navigationBarTranslucent:!0,animationType:"none",onRequestClose:P,testID:v,children:(0,_jsxRuntime.jsx)(_reactNative.View,{ref:e=>{j.current=e,"function"==typeof t?t(e):t&&(t.current=e)},style:D.root,accessible:!1,accessibilityViewIsModal:!0,accessibilityRole:"alert",accessibilityLabel:l,children:(0,_jsxRuntime.jsxs)(_ModalSafeArea.ModalSafeArea,{onInsets:h,children:[(0,_jsxRuntime.jsxs)(_reactNative.Animated.View,{collapsable:!1,style:[_reactNative.StyleSheet.absoluteFill,z,{backgroundColor:w},m],children:[(0,_jsxRuntime.jsx)(_reactNative.Pressable,{style:_reactNative.StyleSheet.absoluteFill,onPress:E,accessibilityRole:"button",accessibilityLabel:"Close modal",disabled:!o}),(0,_jsxRuntime.jsxs)(_reactNative.Animated.View,{style:[k,F,d],onLayout:L.onLayout,pointerEvents:"auto",children:[L.active&&L.size?(0,_jsxRuntime.jsx)(_SquircleFill.SquircleFill,{width:L.size.width,height:L.size.height,radius:g.radius.xl,fill:g.colors.surface}):null,u]})]}),(0,_jsxRuntime.jsx)(_ToastProvider.ToastHost,{})]})})})});Modal.displayName="Modal";const buildStyles=e=>_reactNative.StyleSheet.create({root:{flex:1},centeredWrapper:{flex:1,alignItems:"center",justifyContent:"center",paddingHorizontal:e.space.lg},centeredContent:{maxWidth:"90%",width:"90%"},bottomWrapper:{flex:1,justifyContent:"flex-end"},bottomContent:{width:"100%"},fullScreenWrapper:{flex:1},fullScreenContent:{flex:1}});var _default=exports.default=Modal;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=exports.Modal=exports.MODAL_DISMISS_GRACE_MS=void 0;var _react=require("react"),_reactNative=require("react-native"),_usePresenceMotion=require("../../hooks/usePresenceMotion.js"),_index=require("../../theme/index.js"),_color=require("../../utils/color.js"),_corners=require("../../utils/corners.js"),_hapticUtils=require("../../utils/hapticUtils.js"),_squircle=require("../../utils/squircle.js"),_ModalSafeArea=require("../ModalSafeArea/ModalSafeArea.js"),_SquircleFill=require("../SquircleFill/SquircleFill.js"),_ToastProvider=require("../Toast/ToastProvider.js"),_jsxRuntime=require("react/jsx-runtime");const MODAL_DISMISS_GRACE_MS=exports.MODAL_DISMISS_GRACE_MS=300,SCALE_START_VALUE=.9,Modal=exports.Modal=(0,_react.forwardRef)((e,t)=>{const{visible:r,onRequestClose:a,presentation:i="centered",backdropOpacity:s,backdropPressClose:n=!0,animationDuration:o,animateMount:l=!0,accessibilityLabel:c,hardwareBackPress:u=!0,children:d,contentStyle:m,backdropStyle:_,restoreFocusRef:f,onDismissed:p,haptic:v,testID:g}=e,b=(0,_index.useTheme)(),S=(0,_usePresenceMotion.usePresenceMotion)(),[h,x]=(0,_ModalSafeArea.useModalInsets)(),A=o??S.duration("default"),M=_reactNative.Dimensions.get("window").height,N=(0,_react.useRef)(!l&&r),R=N.current,y=(0,_react.useRef)((0,_index.createAnimatedValue)(R?1:.9)).current,j=(0,_react.useRef)((0,_index.createAnimatedValue)(R?1:0)).current,q=(0,_react.useRef)((0,_index.createAnimatedValue)(R?0:M)).current,C=(0,_react.useRef)((0,_index.createAnimatedValue)(R?1:0)).current,V=(0,_react.useRef)(null),D=(0,_react.useRef)(!1),[T,w]=(0,_react.useState)(r),I=(0,_react.useMemo)(()=>buildStyles(b),[b]),E=(0,_react.useMemo)(()=>{const e=b.colors.scrim;return"number"!=typeof s?e:(0,_color.withAlpha)(e,s)??e},[b.colors.scrim,s]),P=(0,_react.useMemo)(()=>C.interpolate({inputRange:[0,1],outputRange:[(0,_color.transparentOf)(E),E]}),[C,E]);(0,_react.useEffect)(()=>{r&&w(!0)},[r]),(0,_react.useEffect)(()=>{const e=[];if(r&&T&&N.current)N.current=!1;else if(r&&T){const t=_reactNative.Animated.timing(C,{toValue:1,duration:S.duration("default"),useNativeDriver:!1});if(t.start(),e.push(t),S.reduced){j.setValue(0),q.setValue(0),y.setValue(1);const t=_reactNative.Animated.timing(j,{toValue:1,duration:A,useNativeDriver:!0});t.start(),e.push(t)}else if("bottom"===i){j.setValue(1);const t=_reactNative.Animated.spring(q,{toValue:0,damping:b.motion.spring.gentle.damping,stiffness:b.motion.spring.gentle.stiffness,mass:b.motion.spring.gentle.mass,useNativeDriver:!0});t.start(),e.push(t)}else{const t=_reactNative.Animated.parallel([_reactNative.Animated.spring(y,{toValue:1,damping:b.motion.spring.gentle.damping,stiffness:b.motion.spring.gentle.stiffness,mass:b.motion.spring.gentle.mass,useNativeDriver:!0}),_reactNative.Animated.timing(j,{toValue:1,duration:A,useNativeDriver:!0})]);t.start(),e.push(t)}}else if(T){const t=S.duration("fast"),r=_reactNative.Easing.bezier(...b.motion.ease.accelerate),a=_reactNative.Animated.timing(j,{toValue:0,duration:t,easing:r,useNativeDriver:!0}),s=S.reduced?a:"bottom"===i?_reactNative.Animated.timing(q,{toValue:M,duration:t,easing:r,useNativeDriver:!0}):_reactNative.Animated.parallel([_reactNative.Animated.timing(y,{toValue:.9,duration:t,easing:r,useNativeDriver:!0}),a]),n=_reactNative.Animated.parallel([s,_reactNative.Animated.timing(C,{toValue:0,duration:S.duration("default"),useNativeDriver:!1})]);n.start(({finished:e})=>{e&&(q.setValue(M),w(!1))}),e.push(n)}return()=>e.forEach(e=>e.stop())},[r,T,i,A,y,j,C,q,M,b.motion.spring.gentle.damping,b.motion.spring.gentle.stiffness,b.motion.spring.gentle.mass,S,b.motion.ease.accelerate]),(0,_react.useEffect)(()=>{if("web"===_reactNative.Platform.OS)return;let e,t;return r?(e=setTimeout(()=>{V.current&&_reactNative.AccessibilityInfo.sendAccessibilityEvent(V.current,"focus")},150),D.current=!0):D.current&&(D.current=!1,f&&f.current&&(t=setTimeout(()=>{const e=f.current;e&&_reactNative.AccessibilityInfo.sendAccessibilityEvent(e,"focus")},A))),()=>{e&&clearTimeout(e),t&&clearTimeout(t)}},[r,A,f]);const L=(0,_react.useRef)(!1);(0,_react.useEffect)(()=>{if(r)return void(L.current=!0);if(!L.current)return;if(L.current=!1,!p)return;const e=setTimeout(p,MODAL_DISMISS_GRACE_MS);return()=>clearTimeout(e)},[r,p]);const k=(0,_react.useCallback)(()=>{if(!n)return;const e=(0,_hapticUtils.resolveHaptic)(v,"selection");e&&(0,_hapticUtils.triggerHaptic)(e),a()},[n,a,v]),z=(0,_react.useCallback)(()=>{u&&a()},[u,a]),F=(0,_SquircleFill.useSquircle)("bottom"!==i&&"fullScreen"!==i,b.radius.xl),O=(0,_react.useMemo)(()=>"fullScreen"===i?[I.fullScreenContent,{backgroundColor:b.colors.surface}]:"bottom"===i?[I.bottomContent,{backgroundColor:b.colors.surface,borderTopLeftRadius:b.radius.xl,borderTopRightRadius:b.radius.xl,..._corners.smoothCorners,paddingTop:b.space.lg,paddingHorizontal:b.space.lg,paddingBottom:b.space.lg+h.bottom},b.shadow.modal]:[I.centeredContent,{backgroundColor:b.colors.surface,borderRadius:F.active&&F.size?(0,_squircle.squircleHostRadius)(F.size.width,F.size.height,b.radius.xl):b.radius.xl,..._corners.smoothCorners,padding:b.space.xl},b.shadow.modal],[i,b,I,h.bottom,F.active,F.size]),W=(0,_react.useMemo)(()=>"bottom"===i?I.bottomWrapper:"fullScreen"===i?I.fullScreenWrapper:I.centeredWrapper,[i,I]),H=(0,_react.useMemo)(()=>"bottom"===i?{opacity:j,transform:[{translateY:q}]}:"fullScreen"===i?{opacity:j}:{opacity:j,transform:[{scale:y}]},[i,y,j,q]);return(0,_jsxRuntime.jsx)(_reactNative.Modal,{visible:T,transparent:!0,statusBarTranslucent:!0,navigationBarTranslucent:!0,animationType:"none",onRequestClose:z,testID:g,children:(0,_jsxRuntime.jsx)(_reactNative.View,{ref:e=>{V.current=e,"function"==typeof t?t(e):t&&(t.current=e)},style:I.root,accessible:!1,accessibilityViewIsModal:!0,accessibilityRole:"alert",accessibilityLabel:c,children:(0,_jsxRuntime.jsxs)(_ModalSafeArea.ModalSafeArea,{onInsets:x,children:[(0,_jsxRuntime.jsxs)(_reactNative.Animated.View,{collapsable:!1,style:[_reactNative.StyleSheet.absoluteFill,W,{backgroundColor:P},_],children:[(0,_jsxRuntime.jsx)(_reactNative.Pressable,{style:_reactNative.StyleSheet.absoluteFill,onPress:k,accessibilityRole:"button",accessibilityLabel:"Close modal",disabled:!n}),(0,_jsxRuntime.jsxs)(_reactNative.Animated.View,{style:[O,H,m],onLayout:F.onLayout,pointerEvents:"auto",children:[F.active&&F.size?(0,_jsxRuntime.jsx)(_SquircleFill.SquircleFill,{width:F.size.width,height:F.size.height,radius:b.radius.xl,fill:b.colors.surface}):null,d]})]}),(0,_jsxRuntime.jsx)(_ToastProvider.ToastHost,{})]})})})});Modal.displayName="Modal";const buildStyles=e=>_reactNative.StyleSheet.create({root:{flex:1},centeredWrapper:{flex:1,alignItems:"center",justifyContent:"center",paddingHorizontal:e.space.lg},centeredContent:{maxWidth:"90%",width:"90%"},bottomWrapper:{flex:1,justifyContent:"flex-end"},bottomContent:{width:"100%"},fullScreenWrapper:{flex:1},fullScreenContent:{flex:1}});var _default=exports.default=Modal;
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.meta=void 0;var _meta=require("../../canvasKit/meta.js");const meta=exports.meta=(0,_meta.definePhoneMeta)()({name:"Modal",marker:null,platforms:["phone"],acceptsChildren:!0,props:{visible:{type:"boolean",required:!0,description:"Whether the modal is shown. The parent owns it."},presentation:{type:"enum",values:["centered","bottom","fullScreen"],default:"centered",description:"How the dialog is laid out: a centred card, a sheet anchored to the bottom, or a full screen takeover."},backdropOpacity:{type:"number",description:"Overrides the opacity of the dimmed backdrop for this modal."},backdropPressClose:{type:"boolean",default:!0,description:"Whether tapping the dimmed backdrop closes the modal."},animationDuration:{type:"number",description:"The enter animation length in milliseconds. Without it the theme's normal duration is used."},accessibilityLabel:{type:"string",description:"The name a screen reader gives the dialog."},hardwareBackPress:{type:"boolean",default:!0,description:"Whether the Android back button closes the modal."}},omit:["restoreFocusRef","haptic"],examples:[{id:"Modal.default",title:"Centred dialog",props:{visible:!0,presentation:"centered",accessibilityLabel:"Demo modal"},children:"centered modal"},{id:"Modal.bottom",title:"Bottom sheet",props:{visible:!0,presentation:"bottom",accessibilityLabel:"Demo modal"},children:"bottom modal"},{id:"Modal.fullScreen",title:"Full screen",props:{visible:!0,presentation:"fullScreen",accessibilityLabel:"Demo modal"},children:"fullScreen modal"},{id:"Modal.backdropLocked",title:"Backdrop tap does not close",props:{visible:!0,presentation:"centered",backdropPressClose:!1,accessibilityLabel:"Demo modal"},children:"centered modal"}],usage:{when:["A dialog, confirmation or sheet must sit above the current screen.","A full screen takeover such as onboarding or a media viewer is needed."],whenNot:[{text:"The choice is a list of options.",instead:"OptionSheet"},{text:"A brief message needs no action.",instead:"Toast"}],do:[{note:"Name the dialog with an accessibilityLabel so a screen reader announces what opened.",example:[{component:"Modal",props:{visible:!0,accessibilityLabel:"Delete project"},children:"Delete this project?"}]},{note:"Use the bottom presentation for an action menu.",example:[{component:"Modal",props:{visible:!0,presentation:"bottom"},children:"Choose an action"}]}],dont:[{note:"A dialog with no label opens in silence for a screen reader.",example:[{component:"Modal",props:{visible:!0},children:"Delete this project?"}]},{note:"A full screen takeover for a one-line confirmation hides the page for no reason.",example:[{component:"Modal",props:{visible:!0,presentation:"fullScreen"},children:"Delete this project?"}]}],a11y:["The dialog is marked as a modal view with an alert role and takes its name from accessibilityLabel.","The Android back button closes it unless hardwareBackPress is off, and a screen reader can reach a Close modal button."]}});
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.meta=void 0;var _meta=require("../../canvasKit/meta.js");const meta=exports.meta=(0,_meta.definePhoneMeta)()({name:"Modal",marker:null,platforms:["phone"],acceptsChildren:!0,props:{visible:{type:"boolean",required:!0,description:"Whether the modal is shown. The parent owns it."},presentation:{type:"enum",values:["centered","bottom","fullScreen"],default:"centered",description:"How the dialog is laid out: a centred card, a sheet anchored to the bottom, or a full screen takeover."},backdropOpacity:{type:"number",description:"Overrides the opacity of the dimmed backdrop for this modal."},backdropPressClose:{type:"boolean",default:!0,description:"Whether tapping the dimmed backdrop closes the modal."},animationDuration:{type:"number",description:"The enter animation length in milliseconds. Without it the theme's normal duration is used."},animateMount:{type:"boolean",default:!0,description:"Plays the enter animation when the modal is visible as it mounts. Off, it is drawn at rest at once."},accessibilityLabel:{type:"string",description:"The name a screen reader gives the dialog."},hardwareBackPress:{type:"boolean",default:!0,description:"Whether the Android back button closes the modal."}},omit:["restoreFocusRef","haptic"],examples:[{id:"Modal.default",title:"Centred dialog",props:{visible:!0,presentation:"centered",accessibilityLabel:"Demo modal"},children:"centered modal"},{id:"Modal.bottom",title:"Bottom sheet",props:{visible:!0,presentation:"bottom",accessibilityLabel:"Demo modal"},children:"bottom modal"},{id:"Modal.fullScreen",title:"Full screen",props:{visible:!0,presentation:"fullScreen",accessibilityLabel:"Demo modal"},children:"fullScreen modal"},{id:"Modal.backdropLocked",title:"Backdrop tap does not close",props:{visible:!0,presentation:"centered",backdropPressClose:!1,accessibilityLabel:"Demo modal"},children:"centered modal"}],usage:{when:["A dialog, confirmation or sheet must sit above the current screen.","A full screen takeover such as onboarding or a media viewer is needed."],whenNot:[{text:"The choice is a list of options.",instead:"OptionSheet"},{text:"A brief message needs no action.",instead:"Toast"}],do:[{note:"Name the dialog with an accessibilityLabel so a screen reader announces what opened.",example:[{component:"Modal",props:{visible:!0,accessibilityLabel:"Delete project"},children:"Delete this project?"}]},{note:"Use the bottom presentation for an action menu.",example:[{component:"Modal",props:{visible:!0,presentation:"bottom"},children:"Choose an action"}]}],dont:[{note:"A dialog with no label opens in silence for a screen reader.",example:[{component:"Modal",props:{visible:!0},children:"Delete this project?"}]},{note:"A full screen takeover for a one-line confirmation hides the page for no reason.",example:[{component:"Modal",props:{visible:!0,presentation:"fullScreen"},children:"Delete this project?"}]}],a11y:["The dialog is marked as a modal view with an alert role and takes its name from accessibilityLabel.","The Android back button closes it unless hardwareBackPress is off, and a screen reader can reach a Close modal button."]}});
@@ -1 +1 @@
1
- "use strict";import{createContext,forwardRef,useCallback,useContext,useEffect,useImperativeHandle,useMemo,useRef,useState}from"react";import{Dimensions,Modal,Platform,ScrollView,StyleSheet,useWindowDimensions,View}from"react-native";import{Gesture,GestureDetector,GestureHandlerRootView}from"react-native-gesture-handler";import{useReanimatedKeyboardAnimation}from"react-native-keyboard-controller";import Animated,{Easing,runOnJS,useAnimatedStyle,useDerivedValue,useSharedValue,withSpring,withTiming}from"react-native-reanimated";import{useSafeAreaInsets}from"react-native-safe-area-context";import{PRESENCE_REDUCE_MOTION,usePresenceMotion}from"../../hooks/usePresenceMotion.js";import{useTheme}from"../../theme/index.js";import{triggerHaptic}from"../../utils/index.js";import{smoothCorners}from"../../utils/corners.js";import{ModalSafeArea,useModalInsets}from"../ModalSafeArea/ModalSafeArea.js";import{ToastHost}from"../Toast/ToastProvider.js";import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";const TABLET_MIN_SHORT_SIDE=600,DIALOG_MAX_WIDTH=560,BottomSheetContext=createContext(null);export const useBottomSheet=()=>{const e=useContext(BottomSheetContext);if(!e)throw new Error("useBottomSheet must be used inside a <BottomSheet>.");return e};const SPRING_CONFIG={damping:20,stiffness:240,mass:1},CLOSE_VELOCITY_THRESHOLD=1e3,DRAG_ACTIVATION_OFFSET=10,BottomSheet=forwardRef((e,t)=>{const{snapPoints:o,index:s,onChange:n,onAnimate:r,onAfterClose:a,enablePanDownToClose:l=!0,enableBackdropPress:i=!0,confirmDismiss:u,scrollable:c=!1,scrollRef:d,onScroll:h,onContentSizeChange:m,onScrollLayout:f,scrollEventThrottle:b,keyboardBehavior:p="shift",mode:S="modal",presentation:v="sheet",handleIndicatorStyle:g,containerStyle:y,header:w,footer:C,headerStyle:x,footerStyle:k,children:M,accessibilityLabel:R,accessibilityViewIsModal:_,testID:E}=e,I=useTheme(),T=usePresenceMotion(),j=useSafeAreaInsets(),[O,A]=useState(()=>Dimensions.get("window").height),[D,V]=useState(()=>Dimensions.get("window").width),P=useCallback(e=>{const{height:t,width:o}=e.nativeEvent.layout;t>0&&A(e=>e===t?e:t),o>0&&V(e=>e===o?e:o)},[]),H=useWindowDimensions(),B="dialog"===v||"auto"===v&&Math.min(H.width,H.height)>=600,N=Math.min(560,D-2*I.space.xl),[G,L]=useModalInsets(),F="modal"===S?G.top:j.top,J="modal"===S?G.bottom:j.bottom,z=o.includes("content"),[U,Y]=useMeasuredHeight(),[$,q]=useMeasuredHeight(),[W,K,X]=useMeasuredHeight(),[Q,Z]=useMeasuredHeight(),ee=B?I.space.md:U,te=z?Math.min(ee+(null!=w?$:0)+W+(null!=C?Q:0)+J,O-F):0,oe=useCallback((e,t)=>{z&&X(t),m?.(e,t)},[z,m,X]),se=useMemo(()=>resolveSnapPoints(o,O,te),[o,O,te]),ne=O,re=se[se.length-1]??0,ae=useSharedValue(ne),le=useSharedValue(ne),ie=useSharedValue(1),ue=useSharedValue(-1),[ce,de]=useState(-1),he=useRef(!1),[me,fe]=useState(!1),[be,pe]=useState(!1),Se=useRef(!1),ve=useRef(a);ve.current=a;const[ge,ye]=useState(!1),we=useRef(-1),Ce=useRef(!1);Ce.current="modal"===S?be:ge;const xe=useRef(u);xe.current=u;const ke=useRef(!1),Me=useRef(!0),Re=useRef([]),Ee=useCallback(e=>{const t=Re.current;Re.current=[];for(const o of t)o(e)},[]);useEffect(()=>(Me.current=!0,()=>{Me.current=!1,Ee(!1)}),[Ee]);const Ie=useCallback(e=>{if(e<0||e>=se.length)return ne;const t=se[e];return B?(O-t)/2:O-t},[se,O,ne,B]),Te=useCallback(e=>{we.current=e;ce!==e&&(de(e),ue.value=e,n?.(e))},[ce,ue,n]),je=useCallback(()=>{he.current=!1,ue.value<0&&(Se.current=!0,"modal"===S?(fe(!1),"ios"!==Platform.OS&&pe(!1)):ye(!1))},[S,ue]),Oe=useCallback(()=>{Se.current&&pe(!1)},[]);useEffect(()=>{("modal"===S?!be:!ge)&&Se.current&&(Se.current=!1,ve.current?.(),Ee(!0))},[S,be,ge,Ee]);const Ae=useCallback((e,t,o)=>{he.current=!0,r?.(t,o),ae.value=withSpring(e,SPRING_CONFIG,e=>{"worklet";e&&runOnJS(je)()})},[r,ae,je]),De=useCallback(e=>{const t="number"==typeof e?clamp(e,0,se.length-1):ce>=0?ce:0,o=ue.value,s=Ie(t);if(Se.current=!1,Ee(!1),"modal"===S?(pe(!0),fe(!0)):ye(!0),o<0&&T.reduced)return ae.value=s,ie.value=0,ie.value=withTiming(1,{duration:T.duration("fast"),easing:Easing.bezier(...I.motion.ease.decelerate),reduceMotion:PRESENCE_REDUCE_MOTION}),Te(t),void r?.(o,t);o<0&&(ae.value=ne,ie.value=1),Te(t),Ae(s,o,t)},[Ae,ne,ce,ue,S,r,T,ie,se.length,Te,Ee,I.motion.ease.decelerate,ae,Ie]),Ve=useCallback(()=>{if(0===se.length)return;const e=ue.value,t=Ie(0);Te(0),Ae(t,e,0)},[Ae,ue,se.length,Te,Ie]),Pe=useCallback(()=>new Promise(e=>{if(we.current<0)return void(Ce.current?Re.current.push(e):e(!0));Re.current.push(e);const t=ue.value;Te(-1),he.current=!0,r?.(t,-1);const o=T.reduced?ie:ae,s=T.reduced?0:ne;o.value=withTiming(s,{duration:T.duration("fast"),easing:Easing.bezier(...I.motion.ease.accelerate),reduceMotion:PRESENCE_REDUCE_MOTION},e=>{"worklet";e&&runOnJS(je)()})}),[ne,ue,je,r,T,ie,Te,ae,I.motion.ease.accelerate]),He=useCallback(async()=>{await Pe()},[Pe]),Be=useCallback((e,t,o)=>{const s=xe.current;if(!s)return void e();if(ke.current)return void t?.();const n=s();"boolean"!=typeof n?(ke.current=!0,o?.(),n.then(o=>{ke.current=!1,o&&Me.current&&we.current>=0?e():t?.()},e=>{throw ke.current=!1,e})):(n?e:t)?.()},[]),Ne=useCallback(()=>new Promise(e=>{we.current<0?Pe().then(e):Be(()=>{Pe().then(e)},()=>e(!1))}),[Pe,Be]),Ge=useCallback(()=>{i&&Ne()},[i,Ne]);useImperativeHandle(t,()=>({expand:De,collapse:Ve,close:He,requestClose:Ne}),[De,Ve,He,Ne]),useEffect(()=>{"number"==typeof s&&s!==ce&&(-1===s?He():De(s))},[s]);const Le=useRef({hostHeight:O,contentSnap:te});useEffect(()=>{const e=Le.current;e.hostHeight===O&&e.contentSnap===te||(Le.current={hostHeight:O,contentSnap:te},e.hostHeight===O&&ue.value<0||(ae.value=withSpring(Ie(ue.value),SPRING_CONFIG)))},[O,te]);const Fe=O-re,Je=useMemo(()=>se.map(e=>O-e),[se,O]),ze=useCallback(()=>{const e=we.current;e<0||Ae(Ie(e),e,e)},[Ae,Ie]),Ue=useCallback((e,t)=>{const o=ue.value;-1!==e?(Te(e),Ae(t,o,e)):Be(()=>{triggerHaptic("selection"),He()},ze,ze)},[Ae,He,ue,Be,Te,ze]),Ye=useMemo(()=>Gesture.Native().withTestId(E?`${E}-content-gesture`:"bottom-sheet-content-gesture"),[E]),$e=useMemo(()=>{const e=Je,t=ne,o=Fe,s=l;return Gesture.Pan().withTestId(E?`${E}-pan-gesture`:"bottom-sheet-pan-gesture").activeOffsetY([-10,10]).failOffsetX([-15,15]).onStart(()=>{"worklet";le.value=ae.value}).onUpdate(e=>{"worklet";const t=le.value+e.translationY;ae.value=t<o?o+.25*(t-o):t}).onEnd(o=>{"worklet";const n=ae.value;if(o.velocityY>1e3)return s?void runOnJS(Ue)(-1,t):void runOnJS(Ue)(0,e[0]);let r=0,a=Math.abs(n-e[0]);for(let t=1;t<e.length;t++){const o=Math.abs(n-e[t]);o<a&&(a=o,r=t)}const l=e[0];s&&n-l>80?runOnJS(Ue)(-1,t):runOnJS(Ue)(r,e[r])})},[ne,le,l,Ue,Fe,Je,E,ae]),{height:qe}=useReanimatedKeyboardAnimation(),We="shift"===p,Ke=useDerivedValue(()=>We?qe.value:0),Xe=se[ce>=0?ce:0]??re,Qe=I.space.md,Ze=useAnimatedStyle(()=>{if(B){const e=Ke.value,t=O+e-Xe-Qe,o=e<0&&ae.value>t?t:ae.value;return{top:o<F?F:o,opacity:ie.value}}const e=ae.value+Ke.value,t=Ke.value<0?F:Fe;return{top:e<t?t:e,opacity:ie.value}}),et=useAnimatedStyle(()=>{const e=Ke.value;if(B){const t=O+e-Xe-Qe,o=e<0&&ae.value>t?t:ae.value,s=O+e-Qe-(o<F?F:o);return{height:s<0?0:s>Xe?Xe:s}}const t=e<0?F:Fe,o=ae.value+e,s=O+e-(o<t?t:o);return{height:s<0?0:s>re?re:s}}),tt=ce>=0,ot=useMemo(()=>buildStyles(I),[I]),st=useCallback(()=>{i&&Be(()=>{triggerHaptic("selection"),He()})},[i,He,Be]),nt=useMemo(()=>Gesture.Tap().withTestId(E?`${E}-backdrop-gesture`:"bottom-sheet-backdrop-gesture").maxDuration(250).onEnd((_e,e)=>{"worklet";e&&runOnJS(st)()}),[st,E]),rt=useMemo(()=>({snapIndex:ce,snapPoints:se,expand:De,collapse:Ve,close:He,requestClose:Ne}),[ce,se,De,Ve,He,Ne]);if("inline"===S&&!ge)return null;if("modal"===S&&!be)return null;const at=_jsxs(View,{collapsable:!1,style:["modal"===S?ot.backdropModal:ot.backdropInline,{backgroundColor:I.colors.scrim}],onLayout:P,testID:E,accessibilityViewIsModal:_??tt,children:[_jsx(GestureDetector,{gesture:nt,children:_jsx(Animated.View,{style:StyleSheet.absoluteFill,accessibilityRole:"button",accessibilityLabel:"Close bottom sheet"})}),_jsx(Animated.View,{accessibilityRole:"alert",accessibilityLabel:R,accessibilityViewIsModal:_??tt,accessibilityActions:[{name:"escape",label:"Close bottom sheet"}],onAccessibilityAction:e=>{"escape"===e.nativeEvent.actionName&&Ge()},onAccessibilityEscape:Ge,style:[ot.sheet,{height:re,backgroundColor:I.colors.surface,borderTopLeftRadius:I.radius.xl,borderTopRightRadius:I.radius.xl,...smoothCorners,...I.shadow.modal},B?{height:Xe,left:(D-N)/2,right:void 0,width:N,borderBottomLeftRadius:I.radius.xl,borderBottomRightRadius:I.radius.xl}:null,y,Ze],children:_jsxs(SheetBody,{style:[ot.body,et],keyboardOffset:Ke,children:[B?_jsx(View,{style:{height:I.space.md}}):_jsx(GestureDetector,{gesture:$e,children:_jsx(View,{style:ot.handleRow,onLayout:z?Y:void 0,accessible:!0,accessibilityLabel:"Drag handle",accessibilityHint:"Drag up or down to resize the sheet, or swipe down to close it",testID:E?`${E}-handle`:"bottom-sheet-handle",children:_jsx(View,{style:[ot.handle,{backgroundColor:I.colors.border},g]})})}),null!=w&&_jsx(View,{style:[ot.header,x],onLayout:z?q:void 0,children:w}),c?_jsx(GestureDetector,{gesture:Ye,children:_jsx(ScrollView,{ref:d,style:ot.scrollContent,onScroll:h,onContentSizeChange:oe,onLayout:f,scrollEventThrottle:b,keyboardShouldPersistTaps:"always",keyboardDismissMode:"none",children:M})}):_jsx(View,{style:z?[ot.content,{overflow:"visible"}]:ot.content,children:z?_jsx(View,{onLayout:K,children:M}):M}),null!=C&&_jsx(View,{style:[ot.footer,k],onLayout:z?Z:void 0,children:C})]})})]}),lt=_jsx(BottomSheetContext.Provider,{value:rt,children:at});return"modal"===S?_jsx(Modal,{transparent:!0,visible:me,onRequestClose:Ge,onDismiss:"ios"===Platform.OS?Oe:void 0,statusBarTranslucent:!0,navigationBarTranslucent:!0,animationType:"none",supportedOrientations:["portrait","landscape"],children:_jsxs(ModalSafeArea,{onInsets:L,children:["android"===Platform.OS?_jsx(GestureHandlerRootView,{style:ot.modalRoot,children:lt}):lt,_jsx(ToastHost,{})]})}):lt}),SheetBody=({style:e,keyboardOffset:t,children:o})=>{const s=useSafeAreaInsets().bottom,n=useAnimatedStyle(()=>{const e=s+t.value;return{paddingBottom:e>0?e:0}});return _jsx(Animated.View,{style:[e,n],children:o})};BottomSheet.displayName="BottomSheet";const useMeasuredHeight=()=>{const[e,t]=useState(0),o=useCallback(e=>{t(t=>t===e?t:e)},[]);return[e,useCallback(e=>o(e.nativeEvent.layout.height),[o]),o]},resolveSnapPoints=(e,t,o)=>[...e.map(e=>{if("number"==typeof e)return e;if("content"===e)return o;const s=parseFloat(e);return Number.isNaN(s)?0:s/100*t})].sort((e,t)=>e-t),clamp=(e,t,o)=>Math.min(Math.max(e,t),o),buildStyles=e=>StyleSheet.create({backdropModal:{flex:1},backdropInline:{...StyleSheet.absoluteFill},sheet:{position:"absolute",left:0,right:0,overflow:"hidden"},body:{overflow:"hidden"},handleRow:{alignItems:"center",justifyContent:"center",alignSelf:"stretch",paddingTop:e.space.md,paddingBottom:e.space.xl},header:{},footer:{},handle:{width:36,height:4,borderRadius:e.radius.pill,...smoothCorners},content:{flex:1,overflow:"hidden"},scrollContent:{flex:1},modalRoot:{flex:1}});export{BottomSheet};export default BottomSheet;
1
+ "use strict";import{createContext,forwardRef,useCallback,useContext,useEffect,useImperativeHandle,useMemo,useRef,useState}from"react";import{Dimensions,Modal,Platform,ScrollView,StyleSheet,useWindowDimensions,View}from"react-native";import{Gesture,GestureDetector,GestureHandlerRootView}from"react-native-gesture-handler";import{useReanimatedKeyboardAnimation}from"react-native-keyboard-controller";import Animated,{Easing,runOnJS,useAnimatedStyle,useDerivedValue,useSharedValue,withSpring,withTiming}from"react-native-reanimated";import{useSafeAreaInsets}from"react-native-safe-area-context";import{PRESENCE_REDUCE_MOTION,usePresenceMotion}from"../../hooks/usePresenceMotion.js";import{useTheme}from"../../theme/index.js";import{triggerHaptic}from"../../utils/index.js";import{smoothCorners}from"../../utils/corners.js";import{ModalSafeArea,useModalInsets}from"../ModalSafeArea/ModalSafeArea.js";import{ToastHost}from"../Toast/ToastProvider.js";import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";const TABLET_MIN_SHORT_SIDE=600,DIALOG_MAX_WIDTH=560,BottomSheetContext=createContext(null);export const useBottomSheet=()=>{const e=useContext(BottomSheetContext);if(!e)throw new Error("useBottomSheet must be used inside a <BottomSheet>.");return e};const SPRING_CONFIG={damping:20,stiffness:240,mass:1},CLOSE_VELOCITY_THRESHOLD=1e3,DRAG_ACTIVATION_OFFSET=10,BottomSheet=forwardRef((e,t)=>{const{snapPoints:o,index:s,onChange:n,onAnimate:r,onAfterClose:a,enablePanDownToClose:l=!0,enableBackdropPress:i=!0,confirmDismiss:u,scrollable:c=!1,scrollRef:d,onScroll:h,onContentSizeChange:m,onScrollLayout:f,scrollEventThrottle:b,keyboardBehavior:p="shift",mode:S="modal",presentation:v="sheet",animateMount:g=!0,handleIndicatorStyle:y,containerStyle:w,header:C,footer:x,headerStyle:M,footerStyle:R,children:k,accessibilityLabel:_,accessibilityViewIsModal:E,testID:I}=e,T=useTheme(),j=usePresenceMotion(),O=useSafeAreaInsets(),[A,D]=useState(()=>Dimensions.get("window").height),[V,P]=useState(()=>Dimensions.get("window").width),H=useCallback(e=>{const{height:t,width:o}=e.nativeEvent.layout;t>0&&D(e=>e===t?e:t),o>0&&P(e=>e===o?e:o)},[]),B=useWindowDimensions(),N="dialog"===v||"auto"===v&&Math.min(B.width,B.height)>=600,G=Math.min(560,V-2*T.space.xl),[L,F]=useModalInsets(),J="modal"===S?L.top:O.top,z="modal"===S?L.bottom:O.bottom,U=o.includes("content"),[Y,$]=useMeasuredHeight(),[q,W]=useMeasuredHeight(),[K,X,Q]=useMeasuredHeight(),[Z,ee]=useMeasuredHeight(),te=N?T.space.md:Y,oe=U?Math.min(te+(null!=C?q:0)+K+(null!=x?Z:0)+z,A-J):0,se=useCallback((e,t)=>{U&&Q(t),m?.(e,t)},[U,m,Q]),ne=useMemo(()=>resolveSnapPoints(o,A,oe),[o,A,oe]),re=A,ae=ne[ne.length-1]??0,le=useSharedValue(re),ie=useSharedValue(re),ue=useSharedValue(1),ce=useSharedValue(-1),[de,he]=useState(-1),me=useRef(!1),[fe,be]=useState(!1),[pe,Se]=useState(!1),ve=useRef(!1),ge=useRef(a);ge.current=a;const[ye,we]=useState(!1),Ce=useRef(!g&&"number"==typeof s&&s>=0),xe=useRef(-1),Me=useRef(!1);Me.current="modal"===S?pe:ye;const Re=useRef(u);Re.current=u;const ke=useRef(!1),Ee=useRef(!0),Ie=useRef([]),Te=useCallback(e=>{const t=Ie.current;Ie.current=[];for(const o of t)o(e)},[]);useEffect(()=>(Ee.current=!0,()=>{Ee.current=!1,Te(!1)}),[Te]);const je=useCallback(e=>{if(e<0||e>=ne.length)return re;const t=ne[e];return N?(A-t)/2:A-t},[ne,A,re,N]),Oe=useCallback(e=>{xe.current=e;de!==e&&(he(e),ce.value=e,n?.(e))},[de,ce,n]),Ae=useCallback(()=>{me.current=!1,ce.value<0&&(ve.current=!0,"modal"===S?(be(!1),"ios"!==Platform.OS&&Se(!1)):we(!1))},[S,ce]),De=useCallback(()=>{ve.current&&Se(!1)},[]);useEffect(()=>{("modal"===S?!pe:!ye)&&ve.current&&(ve.current=!1,ge.current?.(),Te(!0))},[S,pe,ye,Te]);const Ve=useCallback((e,t,o)=>{me.current=!0,r?.(t,o),le.value=withSpring(e,SPRING_CONFIG,e=>{"worklet";e&&runOnJS(Ae)()})},[r,le,Ae]),Pe=useCallback(e=>{const t="number"==typeof e?clamp(e,0,ne.length-1):de>=0?de:0,o=ce.value,s=je(t);return ve.current=!1,Te(!1),"modal"===S?(Se(!0),be(!0)):we(!0),o<0&&Ce.current?(le.value=s,ue.value=1,Oe(t),void r?.(o,t)):o<0&&j.reduced?(le.value=s,ue.value=0,ue.value=withTiming(1,{duration:j.duration("fast"),easing:Easing.bezier(...T.motion.ease.decelerate),reduceMotion:PRESENCE_REDUCE_MOTION}),Oe(t),void r?.(o,t)):(o<0&&(le.value=re,ue.value=1),Oe(t),void Ve(s,o,t))},[Ve,re,de,ce,S,r,j,ue,ne.length,Oe,Te,T.motion.ease.decelerate,le,je]),He=useCallback(()=>{if(0===ne.length)return;const e=ce.value,t=je(0);Oe(0),Ve(t,e,0)},[Ve,ce,ne.length,Oe,je]),Be=useCallback(()=>new Promise(e=>{if(xe.current<0)return void(Me.current?Ie.current.push(e):e(!0));Ie.current.push(e),Ce.current=!1;const t=ce.value;Oe(-1),me.current=!0,r?.(t,-1);const o=j.reduced?ue:le,s=j.reduced?0:re;o.value=withTiming(s,{duration:j.duration("fast"),easing:Easing.bezier(...T.motion.ease.accelerate),reduceMotion:PRESENCE_REDUCE_MOTION},e=>{"worklet";e&&runOnJS(Ae)()})}),[re,ce,Ae,r,j,ue,Oe,le,T.motion.ease.accelerate]),Ne=useCallback(async()=>{await Be()},[Be]),Ge=useCallback((e,t,o)=>{const s=Re.current;if(!s)return void e();if(ke.current)return void t?.();const n=s();"boolean"!=typeof n?(ke.current=!0,o?.(),n.then(o=>{ke.current=!1,o&&Ee.current&&xe.current>=0?e():t?.()},e=>{throw ke.current=!1,e})):(n?e:t)?.()},[]),Le=useCallback(()=>new Promise(e=>{xe.current<0?Be().then(e):Ge(()=>{Be().then(e)},()=>e(!1))}),[Be,Ge]),Fe=useCallback(()=>{i&&Le()},[i,Le]);useImperativeHandle(t,()=>({expand:Pe,collapse:He,close:Ne,requestClose:Le}),[Pe,He,Ne,Le]),useEffect(()=>{"number"==typeof s&&s!==de&&(-1===s?Ne():Pe(s))},[s]);const Je=useRef({hostHeight:A,contentSnap:oe});useEffect(()=>{const e=Je.current;if(e.hostHeight===A&&e.contentSnap===oe)return;if(Je.current={hostHeight:A,contentSnap:oe},e.hostHeight===A&&ce.value<0)return;const t=je(ce.value);le.value=Ce.current?t:withSpring(t,SPRING_CONFIG)},[A,oe]);const ze=A-ae,Ue=useMemo(()=>ne.map(e=>A-e),[ne,A]),Ye=useCallback(()=>{const e=xe.current;e<0||Ve(je(e),e,e)},[Ve,je]),$e=useCallback((e,t)=>{const o=ce.value;-1!==e?(Oe(e),Ve(t,o,e)):Ge(()=>{triggerHaptic("selection"),Ne()},Ye,Ye)},[Ve,Ne,ce,Ge,Oe,Ye]),qe=useMemo(()=>Gesture.Native().withTestId(I?`${I}-content-gesture`:"bottom-sheet-content-gesture"),[I]),We=useMemo(()=>{const e=Ue,t=re,o=ze,s=l;return Gesture.Pan().withTestId(I?`${I}-pan-gesture`:"bottom-sheet-pan-gesture").activeOffsetY([-10,10]).failOffsetX([-15,15]).onStart(()=>{"worklet";ie.value=le.value}).onUpdate(e=>{"worklet";const t=ie.value+e.translationY;le.value=t<o?o+.25*(t-o):t}).onEnd(o=>{"worklet";const n=le.value;if(o.velocityY>1e3)return s?void runOnJS($e)(-1,t):void runOnJS($e)(0,e[0]);let r=0,a=Math.abs(n-e[0]);for(let t=1;t<e.length;t++){const o=Math.abs(n-e[t]);o<a&&(a=o,r=t)}const l=e[0];s&&n-l>80?runOnJS($e)(-1,t):runOnJS($e)(r,e[r])})},[re,ie,l,$e,ze,Ue,I,le]),{height:Ke}=useReanimatedKeyboardAnimation(),Xe="shift"===p,Qe=useDerivedValue(()=>Xe?Ke.value:0),Ze=ne[de>=0?de:0]??ae,et=T.space.md,tt=useAnimatedStyle(()=>{if(N){const e=Qe.value,t=A+e-Ze-et,o=e<0&&le.value>t?t:le.value;return{top:o<J?J:o,opacity:ue.value}}const e=le.value+Qe.value,t=Qe.value<0?J:ze;return{top:e<t?t:e,opacity:ue.value}}),ot=useAnimatedStyle(()=>{const e=Qe.value;if(N){const t=A+e-Ze-et,o=e<0&&le.value>t?t:le.value,s=A+e-et-(o<J?J:o);return{height:s<0?0:s>Ze?Ze:s}}const t=e<0?J:ze,o=le.value+e,s=A+e-(o<t?t:o);return{height:s<0?0:s>ae?ae:s}}),st=de>=0,nt=useMemo(()=>buildStyles(T),[T]),rt=useCallback(()=>{i&&Ge(()=>{triggerHaptic("selection"),Ne()})},[i,Ne,Ge]),at=useMemo(()=>Gesture.Tap().withTestId(I?`${I}-backdrop-gesture`:"bottom-sheet-backdrop-gesture").maxDuration(250).onEnd((_e,e)=>{"worklet";e&&runOnJS(rt)()}),[rt,I]),lt=useMemo(()=>({snapIndex:de,snapPoints:ne,expand:Pe,collapse:He,close:Ne,requestClose:Le}),[de,ne,Pe,He,Ne,Le]);if("inline"===S&&!ye)return null;if("modal"===S&&!pe)return null;const it=_jsxs(View,{collapsable:!1,style:["modal"===S?nt.backdropModal:nt.backdropInline,{backgroundColor:T.colors.scrim}],onLayout:H,testID:I,accessibilityViewIsModal:E??st,children:[_jsx(GestureDetector,{gesture:at,children:_jsx(Animated.View,{style:StyleSheet.absoluteFill,accessibilityRole:"button",accessibilityLabel:"Close bottom sheet"})}),_jsx(Animated.View,{accessibilityRole:"alert",accessibilityLabel:_,accessibilityViewIsModal:E??st,accessibilityActions:[{name:"escape",label:"Close bottom sheet"}],onAccessibilityAction:e=>{"escape"===e.nativeEvent.actionName&&Fe()},onAccessibilityEscape:Fe,style:[nt.sheet,{height:ae,backgroundColor:T.colors.surface,borderTopLeftRadius:T.radius.xl,borderTopRightRadius:T.radius.xl,...smoothCorners,...T.shadow.modal},N?{height:Ze,left:(V-G)/2,right:void 0,width:G,borderBottomLeftRadius:T.radius.xl,borderBottomRightRadius:T.radius.xl}:null,w,tt],children:_jsxs(SheetBody,{style:[nt.body,ot],keyboardOffset:Qe,children:[N?_jsx(View,{style:{height:T.space.md}}):_jsx(GestureDetector,{gesture:We,children:_jsx(View,{style:nt.handleRow,onLayout:U?$:void 0,accessible:!0,accessibilityLabel:"Drag handle",accessibilityHint:"Drag up or down to resize the sheet, or swipe down to close it",testID:I?`${I}-handle`:"bottom-sheet-handle",children:_jsx(View,{style:[nt.handle,{backgroundColor:T.colors.border},y]})})}),null!=C&&_jsx(View,{style:[nt.header,M],onLayout:U?W:void 0,children:C}),c?_jsx(GestureDetector,{gesture:qe,children:_jsx(ScrollView,{ref:d,style:nt.scrollContent,onScroll:h,onContentSizeChange:se,onLayout:f,scrollEventThrottle:b,keyboardShouldPersistTaps:"always",keyboardDismissMode:"none",children:k})}):_jsx(View,{style:U?[nt.content,{overflow:"visible"}]:nt.content,children:U?_jsx(View,{onLayout:X,children:k}):k}),null!=x&&_jsx(View,{style:[nt.footer,R],onLayout:U?ee:void 0,children:x})]})})]}),ut=_jsx(BottomSheetContext.Provider,{value:lt,children:it});return"modal"===S?_jsx(Modal,{transparent:!0,visible:fe,onRequestClose:Fe,onDismiss:"ios"===Platform.OS?De:void 0,statusBarTranslucent:!0,navigationBarTranslucent:!0,animationType:"none",supportedOrientations:["portrait","landscape"],children:_jsxs(ModalSafeArea,{onInsets:F,children:["android"===Platform.OS?_jsx(GestureHandlerRootView,{style:nt.modalRoot,children:ut}):ut,_jsx(ToastHost,{})]})}):ut}),SheetBody=({style:e,keyboardOffset:t,children:o})=>{const s=useSafeAreaInsets().bottom,n=useAnimatedStyle(()=>{const e=s+t.value;return{paddingBottom:e>0?e:0}});return _jsx(Animated.View,{style:[e,n],children:o})};BottomSheet.displayName="BottomSheet";const useMeasuredHeight=()=>{const[e,t]=useState(0),o=useCallback(e=>{t(t=>t===e?t:e)},[]);return[e,useCallback(e=>o(e.nativeEvent.layout.height),[o]),o]},resolveSnapPoints=(e,t,o)=>[...e.map(e=>{if("number"==typeof e)return e;if("content"===e)return o;const s=parseFloat(e);return Number.isNaN(s)?0:s/100*t})].sort((e,t)=>e-t),clamp=(e,t,o)=>Math.min(Math.max(e,t),o),buildStyles=e=>StyleSheet.create({backdropModal:{flex:1},backdropInline:{...StyleSheet.absoluteFill},sheet:{position:"absolute",left:0,right:0,overflow:"hidden"},body:{overflow:"hidden"},handleRow:{alignItems:"center",justifyContent:"center",alignSelf:"stretch",paddingTop:e.space.md,paddingBottom:e.space.xl},header:{},footer:{},handle:{width:36,height:4,borderRadius:e.radius.pill,...smoothCorners},content:{flex:1,overflow:"hidden"},scrollContent:{flex:1},modalRoot:{flex:1}});export{BottomSheet};export default BottomSheet;
@@ -1 +1 @@
1
- "use strict";import{definePhoneMeta}from"../../canvasKit/meta.js";export const meta=definePhoneMeta()({name:"BottomSheet",marker:null,platforms:["phone"],acceptsChildren:!0,props:{snapPoints:{type:"array",required:!0,description:"The heights the sheet rests at: a number of points, a percentage such as 50%, or content to hug the content."},index:{type:"number",description:"The snap point the sheet shows, counted from 0. Minus one closes it."},enablePanDownToClose:{type:"boolean",default:!0,description:"Lets a drag on the handle past the threshold close the sheet."},enableBackdropPress:{type:"boolean",default:!0,description:"Lets a tap on the scrim close the sheet. Back and Escape follow it."},scrollable:{type:"boolean",default:!1,description:"Wraps the content in a vertical scroll view between the header and the footer."},scrollEventThrottle:{type:"number",description:"How often the inner scroll view reports scrolling, in milliseconds. Used only with scrollable."},backdropOpacity:{type:"number",description:"The opacity of the scrim."},keyboardBehavior:{type:"enum",values:["none","shift"],default:"shift",description:"How the sheet reacts to the keyboard. Shift rides up with it; none stays put."},mode:{type:"enum",values:["modal","inline"],default:"modal",description:"Modal covers the whole screen in a native modal; inline overlays the parent view."},presentation:{type:"enum",values:["sheet","dialog","auto"],default:"sheet",description:"Sheet is full width at the bottom; dialog is centred; auto picks a dialog on a tablet."},header:{type:"node",description:"A fixed region between the handle and the content. It does not scroll."},footer:{type:"node",description:"A fixed region at the bottom of the sheet, such as a row of buttons."},accessibilityLabel:{type:"string",description:"Names the sheet for a screen reader."},accessibilityViewIsModal:{type:"boolean",description:"Tells a screen reader to ignore what is behind the sheet."}},omit:["scrollRef"],examples:[{id:"BottomSheet.content",title:"Hugs its content",props:{snapPoints:["content"],mode:"inline",index:0},children:"Sheet content."},{id:"BottomSheet.headerFooter",title:"Header and footer",props:{snapPoints:["50%"],mode:"inline",index:0,header:"Filters",footer:"Apply"},children:"Choose how to filter the list."},{id:"BottomSheet.dialog",title:"Dialog presentation",props:{snapPoints:["50%"],presentation:"dialog",mode:"inline",index:0},children:"Centred on a tablet."}],usage:{when:["A short task or a list of choices belongs on top of the current screen.","The person should be able to drag the sheet between a small and a tall height.","The content needs a fixed header or a fixed row of buttons."],whenNot:[{text:"The person must answer one question before going on.",instead:"Dialog"},{text:"The content is a full screen of its own.",instead:"a new screen"}],do:[{note:"Use the content snap point so the sheet is as tall as what it holds.",example:[{component:"BottomSheet",props:{snapPoints:["content"],mode:"inline",index:0}}]}],dont:[{note:"Do not set a snap point taller than the content needs. It leaves a large empty area.",example:[{component:"BottomSheet",props:{snapPoints:["90%"],mode:"inline",index:0}}]}],a11y:["Turning off backdrop press also turns off Back and Escape, so a sheet that must be answered stays open.","Set accessibilityLabel so a screen reader names the sheet when it opens."]}});
1
+ "use strict";import{definePhoneMeta}from"../../canvasKit/meta.js";export const meta=definePhoneMeta()({name:"BottomSheet",marker:null,platforms:["phone"],acceptsChildren:!0,props:{snapPoints:{type:"array",required:!0,description:"The heights the sheet rests at: a number of points, a percentage such as 50%, or content to hug the content."},index:{type:"number",description:"The snap point the sheet shows, counted from 0. Minus one closes it."},enablePanDownToClose:{type:"boolean",default:!0,description:"Lets a drag on the handle past the threshold close the sheet."},enableBackdropPress:{type:"boolean",default:!0,description:"Lets a tap on the scrim close the sheet. Back and Escape follow it."},scrollable:{type:"boolean",default:!1,description:"Wraps the content in a vertical scroll view between the header and the footer."},scrollEventThrottle:{type:"number",description:"How often the inner scroll view reports scrolling, in milliseconds. Used only with scrollable."},backdropOpacity:{type:"number",description:"The opacity of the scrim."},keyboardBehavior:{type:"enum",values:["none","shift"],default:"shift",description:"How the sheet reacts to the keyboard. Shift rides up with it; none stays put."},mode:{type:"enum",values:["modal","inline"],default:"modal",description:"Modal covers the whole screen in a native modal; inline overlays the parent view."},presentation:{type:"enum",values:["sheet","dialog","auto"],default:"sheet",description:"Sheet is full width at the bottom; dialog is centred; auto picks a dialog on a tablet."},animateMount:{type:"boolean",default:!0,description:"Slides the sheet up when it opens as it mounts. Off, it is drawn at its snap point at once."},header:{type:"node",description:"A fixed region between the handle and the content. It does not scroll."},footer:{type:"node",description:"A fixed region at the bottom of the sheet, such as a row of buttons."},accessibilityLabel:{type:"string",description:"Names the sheet for a screen reader."},accessibilityViewIsModal:{type:"boolean",description:"Tells a screen reader to ignore what is behind the sheet."}},omit:["scrollRef"],examples:[{id:"BottomSheet.content",title:"Hugs its content",props:{snapPoints:["content"],mode:"inline",index:0},children:"Sheet content."},{id:"BottomSheet.headerFooter",title:"Header and footer",props:{snapPoints:["50%"],mode:"inline",index:0,header:"Filters",footer:"Apply"},children:"Choose how to filter the list."},{id:"BottomSheet.dialog",title:"Dialog presentation",props:{snapPoints:["50%"],presentation:"dialog",mode:"inline",index:0},children:"Centred on a tablet."}],usage:{when:["A short task or a list of choices belongs on top of the current screen.","The person should be able to drag the sheet between a small and a tall height.","The content needs a fixed header or a fixed row of buttons."],whenNot:[{text:"The person must answer one question before going on.",instead:"Dialog"},{text:"The content is a full screen of its own.",instead:"a new screen"}],do:[{note:"Use the content snap point so the sheet is as tall as what it holds.",example:[{component:"BottomSheet",props:{snapPoints:["content"],mode:"inline",index:0}}]}],dont:[{note:"Do not set a snap point taller than the content needs. It leaves a large empty area.",example:[{component:"BottomSheet",props:{snapPoints:["90%"],mode:"inline",index:0}}]}],a11y:["Turning off backdrop press also turns off Back and Escape, so a sheet that must be answered stays open.","Set accessibilityLabel so a screen reader names the sheet when it opens."]}});
@@ -1 +1 @@
1
- "use strict";import{forwardRef,useCallback,useEffect,useMemo,useRef,useState}from"react";import{AccessibilityInfo,Animated,Dimensions,Easing,Platform,Pressable,Modal as RNModal,StyleSheet,View}from"react-native";import{usePresenceMotion}from"../../hooks/usePresenceMotion.js";import{createAnimatedValue,useTheme}from"../../theme/index.js";import{transparentOf,withAlpha}from"../../utils/color.js";import{smoothCorners}from"../../utils/corners.js";import{resolveHaptic,triggerHaptic}from"../../utils/hapticUtils.js";import{squircleHostRadius}from"../../utils/squircle.js";import{ModalSafeArea,useModalInsets}from"../ModalSafeArea/ModalSafeArea.js";import{SquircleFill,useSquircle}from"../SquircleFill/SquircleFill.js";import{ToastHost}from"../Toast/ToastProvider.js";import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";export const MODAL_DISMISS_GRACE_MS=300;const SCALE_START_VALUE=.9,Modal=forwardRef((e,t)=>{const{visible:s,onRequestClose:i,presentation:r="centered",backdropOpacity:o,backdropPressClose:a=!0,animationDuration:n,accessibilityLabel:l,hardwareBackPress:u=!0,children:c,contentStyle:d,backdropStyle:m,restoreFocusRef:f,onDismissed:p,haptic:g,testID:b}=e,h=useTheme(),S=usePresenceMotion(),[A,y]=useModalInsets(),v=n??S.duration("default"),x=Dimensions.get("window").height,M=useRef(createAnimatedValue(.9)).current,R=useRef(createAnimatedValue(0)).current,V=useRef(createAnimatedValue(x)).current,j=useRef(createAnimatedValue(0)).current,C=useRef(null),w=useRef(!1),[T,D]=useState(s),_=useMemo(()=>buildStyles(h),[h]),E=useMemo(()=>{const e=h.colors.scrim;return"number"!=typeof o?e:withAlpha(e,o)??e},[h.colors.scrim,o]),k=useMemo(()=>j.interpolate({inputRange:[0,1],outputRange:[transparentOf(E),E]}),[j,E]);useEffect(()=>{s&&D(!0)},[s]),useEffect(()=>{const e=[];if(s&&T){const t=Animated.timing(j,{toValue:1,duration:S.duration("default"),useNativeDriver:!1});if(t.start(),e.push(t),S.reduced){R.setValue(0),V.setValue(0),M.setValue(1);const t=Animated.timing(R,{toValue:1,duration:v,useNativeDriver:!0});t.start(),e.push(t)}else if("bottom"===r){R.setValue(1);const t=Animated.spring(V,{toValue:0,damping:h.motion.spring.gentle.damping,stiffness:h.motion.spring.gentle.stiffness,mass:h.motion.spring.gentle.mass,useNativeDriver:!0});t.start(),e.push(t)}else{const t=Animated.parallel([Animated.spring(M,{toValue:1,damping:h.motion.spring.gentle.damping,stiffness:h.motion.spring.gentle.stiffness,mass:h.motion.spring.gentle.mass,useNativeDriver:!0}),Animated.timing(R,{toValue:1,duration:v,useNativeDriver:!0})]);t.start(),e.push(t)}}else if(T){const t=S.duration("fast"),s=Easing.bezier(...h.motion.ease.accelerate),i=Animated.timing(R,{toValue:0,duration:t,easing:s,useNativeDriver:!0}),o=S.reduced?i:"bottom"===r?Animated.timing(V,{toValue:x,duration:t,easing:s,useNativeDriver:!0}):Animated.parallel([Animated.timing(M,{toValue:.9,duration:t,easing:s,useNativeDriver:!0}),i]),a=Animated.parallel([o,Animated.timing(j,{toValue:0,duration:S.duration("default"),useNativeDriver:!1})]);a.start(({finished:e})=>{e&&(V.setValue(x),D(!1))}),e.push(a)}return()=>e.forEach(e=>e.stop())},[s,T,r,v,M,R,j,V,x,h.motion.spring.gentle.damping,h.motion.spring.gentle.stiffness,h.motion.spring.gentle.mass,S,h.motion.ease.accelerate]),useEffect(()=>{if("web"===Platform.OS)return;let e,t;return s?(e=setTimeout(()=>{C.current&&AccessibilityInfo.sendAccessibilityEvent(C.current,"focus")},150),w.current=!0):w.current&&(w.current=!1,f&&f.current&&(t=setTimeout(()=>{const e=f.current;e&&AccessibilityInfo.sendAccessibilityEvent(e,"focus")},v))),()=>{e&&clearTimeout(e),t&&clearTimeout(t)}},[s,v,f]);const I=useRef(!1);useEffect(()=>{if(s)return void(I.current=!0);if(!I.current)return;if(I.current=!1,!p)return;const e=setTimeout(p,300);return()=>clearTimeout(e)},[s,p]);const N=useCallback(()=>{if(!a)return;const e=resolveHaptic(g,"selection");e&&triggerHaptic(e),i()},[a,i,g]),q=useCallback(()=>{u&&i()},[u,i]),P=useSquircle("bottom"!==r&&"fullScreen"!==r,h.radius.xl),z=useMemo(()=>"fullScreen"===r?[_.fullScreenContent,{backgroundColor:h.colors.surface}]:"bottom"===r?[_.bottomContent,{backgroundColor:h.colors.surface,borderTopLeftRadius:h.radius.xl,borderTopRightRadius:h.radius.xl,...smoothCorners,paddingTop:h.space.lg,paddingHorizontal:h.space.lg,paddingBottom:h.space.lg+A.bottom},h.shadow.modal]:[_.centeredContent,{backgroundColor:h.colors.surface,borderRadius:P.active&&P.size?squircleHostRadius(P.size.width,P.size.height,h.radius.xl):h.radius.xl,...smoothCorners,padding:h.space.xl},h.shadow.modal],[r,h,_,A.bottom,P.active,P.size]),H=useMemo(()=>"bottom"===r?_.bottomWrapper:"fullScreen"===r?_.fullScreenWrapper:_.centeredWrapper,[r,_]),L=useMemo(()=>"bottom"===r?{opacity:R,transform:[{translateY:V}]}:"fullScreen"===r?{opacity:R}:{opacity:R,transform:[{scale:M}]},[r,M,R,V]);return _jsx(RNModal,{visible:T,transparent:!0,statusBarTranslucent:!0,navigationBarTranslucent:!0,animationType:"none",onRequestClose:q,testID:b,children:_jsx(View,{ref:e=>{C.current=e,"function"==typeof t?t(e):t&&(t.current=e)},style:_.root,accessible:!1,accessibilityViewIsModal:!0,accessibilityRole:"alert",accessibilityLabel:l,children:_jsxs(ModalSafeArea,{onInsets:y,children:[_jsxs(Animated.View,{collapsable:!1,style:[StyleSheet.absoluteFill,H,{backgroundColor:k},m],children:[_jsx(Pressable,{style:StyleSheet.absoluteFill,onPress:N,accessibilityRole:"button",accessibilityLabel:"Close modal",disabled:!a}),_jsxs(Animated.View,{style:[z,L,d],onLayout:P.onLayout,pointerEvents:"auto",children:[P.active&&P.size?_jsx(SquircleFill,{width:P.size.width,height:P.size.height,radius:h.radius.xl,fill:h.colors.surface}):null,c]})]}),_jsx(ToastHost,{})]})})})});Modal.displayName="Modal";const buildStyles=e=>StyleSheet.create({root:{flex:1},centeredWrapper:{flex:1,alignItems:"center",justifyContent:"center",paddingHorizontal:e.space.lg},centeredContent:{maxWidth:"90%",width:"90%"},bottomWrapper:{flex:1,justifyContent:"flex-end"},bottomContent:{width:"100%"},fullScreenWrapper:{flex:1},fullScreenContent:{flex:1}});export{Modal};export default Modal;
1
+ "use strict";import{forwardRef,useCallback,useEffect,useMemo,useRef,useState}from"react";import{AccessibilityInfo,Animated,Dimensions,Easing,Platform,Pressable,Modal as RNModal,StyleSheet,View}from"react-native";import{usePresenceMotion}from"../../hooks/usePresenceMotion.js";import{createAnimatedValue,useTheme}from"../../theme/index.js";import{transparentOf,withAlpha}from"../../utils/color.js";import{smoothCorners}from"../../utils/corners.js";import{resolveHaptic,triggerHaptic}from"../../utils/hapticUtils.js";import{squircleHostRadius}from"../../utils/squircle.js";import{ModalSafeArea,useModalInsets}from"../ModalSafeArea/ModalSafeArea.js";import{SquircleFill,useSquircle}from"../SquircleFill/SquircleFill.js";import{ToastHost}from"../Toast/ToastProvider.js";import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";export const MODAL_DISMISS_GRACE_MS=300;const SCALE_START_VALUE=.9,Modal=forwardRef((e,t)=>{const{visible:s,onRequestClose:r,presentation:i="centered",backdropOpacity:o,backdropPressClose:a=!0,animationDuration:n,animateMount:l=!0,accessibilityLabel:u,hardwareBackPress:c=!0,children:d,contentStyle:m,backdropStyle:f,restoreFocusRef:p,onDismissed:g,haptic:b,testID:h}=e,S=useTheme(),A=usePresenceMotion(),[y,v]=useModalInsets(),x=n??A.duration("default"),M=Dimensions.get("window").height,R=useRef(!l&&s),V=R.current,j=useRef(createAnimatedValue(V?1:.9)).current,C=useRef(createAnimatedValue(V?1:0)).current,w=useRef(createAnimatedValue(V?0:M)).current,T=useRef(createAnimatedValue(V?1:0)).current,D=useRef(null),_=useRef(!1),[E,k]=useState(s),I=useMemo(()=>buildStyles(S),[S]),N=useMemo(()=>{const e=S.colors.scrim;return"number"!=typeof o?e:withAlpha(e,o)??e},[S.colors.scrim,o]),q=useMemo(()=>T.interpolate({inputRange:[0,1],outputRange:[transparentOf(N),N]}),[T,N]);useEffect(()=>{s&&k(!0)},[s]),useEffect(()=>{const e=[];if(s&&E&&R.current)R.current=!1;else if(s&&E){const t=Animated.timing(T,{toValue:1,duration:A.duration("default"),useNativeDriver:!1});if(t.start(),e.push(t),A.reduced){C.setValue(0),w.setValue(0),j.setValue(1);const t=Animated.timing(C,{toValue:1,duration:x,useNativeDriver:!0});t.start(),e.push(t)}else if("bottom"===i){C.setValue(1);const t=Animated.spring(w,{toValue:0,damping:S.motion.spring.gentle.damping,stiffness:S.motion.spring.gentle.stiffness,mass:S.motion.spring.gentle.mass,useNativeDriver:!0});t.start(),e.push(t)}else{const t=Animated.parallel([Animated.spring(j,{toValue:1,damping:S.motion.spring.gentle.damping,stiffness:S.motion.spring.gentle.stiffness,mass:S.motion.spring.gentle.mass,useNativeDriver:!0}),Animated.timing(C,{toValue:1,duration:x,useNativeDriver:!0})]);t.start(),e.push(t)}}else if(E){const t=A.duration("fast"),s=Easing.bezier(...S.motion.ease.accelerate),r=Animated.timing(C,{toValue:0,duration:t,easing:s,useNativeDriver:!0}),o=A.reduced?r:"bottom"===i?Animated.timing(w,{toValue:M,duration:t,easing:s,useNativeDriver:!0}):Animated.parallel([Animated.timing(j,{toValue:.9,duration:t,easing:s,useNativeDriver:!0}),r]),a=Animated.parallel([o,Animated.timing(T,{toValue:0,duration:A.duration("default"),useNativeDriver:!1})]);a.start(({finished:e})=>{e&&(w.setValue(M),k(!1))}),e.push(a)}return()=>e.forEach(e=>e.stop())},[s,E,i,x,j,C,T,w,M,S.motion.spring.gentle.damping,S.motion.spring.gentle.stiffness,S.motion.spring.gentle.mass,A,S.motion.ease.accelerate]),useEffect(()=>{if("web"===Platform.OS)return;let e,t;return s?(e=setTimeout(()=>{D.current&&AccessibilityInfo.sendAccessibilityEvent(D.current,"focus")},150),_.current=!0):_.current&&(_.current=!1,p&&p.current&&(t=setTimeout(()=>{const e=p.current;e&&AccessibilityInfo.sendAccessibilityEvent(e,"focus")},x))),()=>{e&&clearTimeout(e),t&&clearTimeout(t)}},[s,x,p]);const P=useRef(!1);useEffect(()=>{if(s)return void(P.current=!0);if(!P.current)return;if(P.current=!1,!g)return;const e=setTimeout(g,300);return()=>clearTimeout(e)},[s,g]);const z=useCallback(()=>{if(!a)return;const e=resolveHaptic(b,"selection");e&&triggerHaptic(e),r()},[a,r,b]),H=useCallback(()=>{c&&r()},[c,r]),L=useSquircle("bottom"!==i&&"fullScreen"!==i,S.radius.xl),F=useMemo(()=>"fullScreen"===i?[I.fullScreenContent,{backgroundColor:S.colors.surface}]:"bottom"===i?[I.bottomContent,{backgroundColor:S.colors.surface,borderTopLeftRadius:S.radius.xl,borderTopRightRadius:S.radius.xl,...smoothCorners,paddingTop:S.space.lg,paddingHorizontal:S.space.lg,paddingBottom:S.space.lg+y.bottom},S.shadow.modal]:[I.centeredContent,{backgroundColor:S.colors.surface,borderRadius:L.active&&L.size?squircleHostRadius(L.size.width,L.size.height,S.radius.xl):S.radius.xl,...smoothCorners,padding:S.space.xl},S.shadow.modal],[i,S,I,y.bottom,L.active,L.size]),W=useMemo(()=>"bottom"===i?I.bottomWrapper:"fullScreen"===i?I.fullScreenWrapper:I.centeredWrapper,[i,I]),O=useMemo(()=>"bottom"===i?{opacity:C,transform:[{translateY:w}]}:"fullScreen"===i?{opacity:C}:{opacity:C,transform:[{scale:j}]},[i,j,C,w]);return _jsx(RNModal,{visible:E,transparent:!0,statusBarTranslucent:!0,navigationBarTranslucent:!0,animationType:"none",onRequestClose:H,testID:h,children:_jsx(View,{ref:e=>{D.current=e,"function"==typeof t?t(e):t&&(t.current=e)},style:I.root,accessible:!1,accessibilityViewIsModal:!0,accessibilityRole:"alert",accessibilityLabel:u,children:_jsxs(ModalSafeArea,{onInsets:v,children:[_jsxs(Animated.View,{collapsable:!1,style:[StyleSheet.absoluteFill,W,{backgroundColor:q},f],children:[_jsx(Pressable,{style:StyleSheet.absoluteFill,onPress:z,accessibilityRole:"button",accessibilityLabel:"Close modal",disabled:!a}),_jsxs(Animated.View,{style:[F,O,m],onLayout:L.onLayout,pointerEvents:"auto",children:[L.active&&L.size?_jsx(SquircleFill,{width:L.size.width,height:L.size.height,radius:S.radius.xl,fill:S.colors.surface}):null,d]})]}),_jsx(ToastHost,{})]})})})});Modal.displayName="Modal";const buildStyles=e=>StyleSheet.create({root:{flex:1},centeredWrapper:{flex:1,alignItems:"center",justifyContent:"center",paddingHorizontal:e.space.lg},centeredContent:{maxWidth:"90%",width:"90%"},bottomWrapper:{flex:1,justifyContent:"flex-end"},bottomContent:{width:"100%"},fullScreenWrapper:{flex:1},fullScreenContent:{flex:1}});export{Modal};export default Modal;
@@ -1 +1 @@
1
- "use strict";import{definePhoneMeta}from"../../canvasKit/meta.js";export const meta=definePhoneMeta()({name:"Modal",marker:null,platforms:["phone"],acceptsChildren:!0,props:{visible:{type:"boolean",required:!0,description:"Whether the modal is shown. The parent owns it."},presentation:{type:"enum",values:["centered","bottom","fullScreen"],default:"centered",description:"How the dialog is laid out: a centred card, a sheet anchored to the bottom, or a full screen takeover."},backdropOpacity:{type:"number",description:"Overrides the opacity of the dimmed backdrop for this modal."},backdropPressClose:{type:"boolean",default:!0,description:"Whether tapping the dimmed backdrop closes the modal."},animationDuration:{type:"number",description:"The enter animation length in milliseconds. Without it the theme's normal duration is used."},accessibilityLabel:{type:"string",description:"The name a screen reader gives the dialog."},hardwareBackPress:{type:"boolean",default:!0,description:"Whether the Android back button closes the modal."}},omit:["restoreFocusRef","haptic"],examples:[{id:"Modal.default",title:"Centred dialog",props:{visible:!0,presentation:"centered",accessibilityLabel:"Demo modal"},children:"centered modal"},{id:"Modal.bottom",title:"Bottom sheet",props:{visible:!0,presentation:"bottom",accessibilityLabel:"Demo modal"},children:"bottom modal"},{id:"Modal.fullScreen",title:"Full screen",props:{visible:!0,presentation:"fullScreen",accessibilityLabel:"Demo modal"},children:"fullScreen modal"},{id:"Modal.backdropLocked",title:"Backdrop tap does not close",props:{visible:!0,presentation:"centered",backdropPressClose:!1,accessibilityLabel:"Demo modal"},children:"centered modal"}],usage:{when:["A dialog, confirmation or sheet must sit above the current screen.","A full screen takeover such as onboarding or a media viewer is needed."],whenNot:[{text:"The choice is a list of options.",instead:"OptionSheet"},{text:"A brief message needs no action.",instead:"Toast"}],do:[{note:"Name the dialog with an accessibilityLabel so a screen reader announces what opened.",example:[{component:"Modal",props:{visible:!0,accessibilityLabel:"Delete project"},children:"Delete this project?"}]},{note:"Use the bottom presentation for an action menu.",example:[{component:"Modal",props:{visible:!0,presentation:"bottom"},children:"Choose an action"}]}],dont:[{note:"A dialog with no label opens in silence for a screen reader.",example:[{component:"Modal",props:{visible:!0},children:"Delete this project?"}]},{note:"A full screen takeover for a one-line confirmation hides the page for no reason.",example:[{component:"Modal",props:{visible:!0,presentation:"fullScreen"},children:"Delete this project?"}]}],a11y:["The dialog is marked as a modal view with an alert role and takes its name from accessibilityLabel.","The Android back button closes it unless hardwareBackPress is off, and a screen reader can reach a Close modal button."]}});
1
+ "use strict";import{definePhoneMeta}from"../../canvasKit/meta.js";export const meta=definePhoneMeta()({name:"Modal",marker:null,platforms:["phone"],acceptsChildren:!0,props:{visible:{type:"boolean",required:!0,description:"Whether the modal is shown. The parent owns it."},presentation:{type:"enum",values:["centered","bottom","fullScreen"],default:"centered",description:"How the dialog is laid out: a centred card, a sheet anchored to the bottom, or a full screen takeover."},backdropOpacity:{type:"number",description:"Overrides the opacity of the dimmed backdrop for this modal."},backdropPressClose:{type:"boolean",default:!0,description:"Whether tapping the dimmed backdrop closes the modal."},animationDuration:{type:"number",description:"The enter animation length in milliseconds. Without it the theme's normal duration is used."},animateMount:{type:"boolean",default:!0,description:"Plays the enter animation when the modal is visible as it mounts. Off, it is drawn at rest at once."},accessibilityLabel:{type:"string",description:"The name a screen reader gives the dialog."},hardwareBackPress:{type:"boolean",default:!0,description:"Whether the Android back button closes the modal."}},omit:["restoreFocusRef","haptic"],examples:[{id:"Modal.default",title:"Centred dialog",props:{visible:!0,presentation:"centered",accessibilityLabel:"Demo modal"},children:"centered modal"},{id:"Modal.bottom",title:"Bottom sheet",props:{visible:!0,presentation:"bottom",accessibilityLabel:"Demo modal"},children:"bottom modal"},{id:"Modal.fullScreen",title:"Full screen",props:{visible:!0,presentation:"fullScreen",accessibilityLabel:"Demo modal"},children:"fullScreen modal"},{id:"Modal.backdropLocked",title:"Backdrop tap does not close",props:{visible:!0,presentation:"centered",backdropPressClose:!1,accessibilityLabel:"Demo modal"},children:"centered modal"}],usage:{when:["A dialog, confirmation or sheet must sit above the current screen.","A full screen takeover such as onboarding or a media viewer is needed."],whenNot:[{text:"The choice is a list of options.",instead:"OptionSheet"},{text:"A brief message needs no action.",instead:"Toast"}],do:[{note:"Name the dialog with an accessibilityLabel so a screen reader announces what opened.",example:[{component:"Modal",props:{visible:!0,accessibilityLabel:"Delete project"},children:"Delete this project?"}]},{note:"Use the bottom presentation for an action menu.",example:[{component:"Modal",props:{visible:!0,presentation:"bottom"},children:"Choose an action"}]}],dont:[{note:"A dialog with no label opens in silence for a screen reader.",example:[{component:"Modal",props:{visible:!0},children:"Delete this project?"}]},{note:"A full screen takeover for a one-line confirmation hides the page for no reason.",example:[{component:"Modal",props:{visible:!0,presentation:"fullScreen"},children:"Delete this project?"}]}],a11y:["The dialog is marked as a modal view with an alert role and takes its name from accessibilityLabel.","The Android back button closes it unless hardwareBackPress is off, and a screen reader can reach a Close modal button."]}});
@@ -127,6 +127,13 @@ export interface BottomSheetProps {
127
127
  * more), `'sheet'` on a phone.
128
128
  */
129
129
  presentation?: BottomSheetPresentation;
130
+ /**
131
+ * Whether a sheet that opens as it mounts (an `index` of 0 or more on the
132
+ * first render) slides up into place. When false it is drawn at its snap
133
+ * point at once, and a re-measured host moves it without a spring, until
134
+ * its first close; later opens slide as usual. Default true.
135
+ */
136
+ animateMount?: boolean;
130
137
  handleIndicatorStyle?: StyleProp<ViewStyle>;
131
138
  containerStyle?: StyleProp<ViewStyle>;
132
139
  /**
@@ -15,6 +15,12 @@ export interface ModalProps {
15
15
  backdropOpacity?: number;
16
16
  backdropPressClose?: boolean;
17
17
  animationDuration?: number;
18
+ /**
19
+ * Whether a modal that is visible as it mounts plays its enter animation.
20
+ * When false it is drawn at rest at once, scrim included; later opens and
21
+ * every close animate as usual. Default true.
22
+ */
23
+ animateMount?: boolean;
18
24
  accessibilityLabel?: string;
19
25
  hardwareBackPress?: boolean;
20
26
  children: React.ReactNode;
@@ -127,6 +127,13 @@ export interface BottomSheetProps {
127
127
  * more), `'sheet'` on a phone.
128
128
  */
129
129
  presentation?: BottomSheetPresentation;
130
+ /**
131
+ * Whether a sheet that opens as it mounts (an `index` of 0 or more on the
132
+ * first render) slides up into place. When false it is drawn at its snap
133
+ * point at once, and a re-measured host moves it without a spring, until
134
+ * its first close; later opens slide as usual. Default true.
135
+ */
136
+ animateMount?: boolean;
130
137
  handleIndicatorStyle?: StyleProp<ViewStyle>;
131
138
  containerStyle?: StyleProp<ViewStyle>;
132
139
  /**
@@ -15,6 +15,12 @@ export interface ModalProps {
15
15
  backdropOpacity?: number;
16
16
  backdropPressClose?: boolean;
17
17
  animationDuration?: number;
18
+ /**
19
+ * Whether a modal that is visible as it mounts plays its enter animation.
20
+ * When false it is drawn at rest at once, scrim included; later opens and
21
+ * every close animate as usual. Default true.
22
+ */
23
+ animateMount?: boolean;
18
24
  accessibilityLabel?: string;
19
25
  hardwareBackPress?: boolean;
20
26
  children: React.ReactNode;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webority/mobile-ui",
3
- "version": "0.94.0",
3
+ "version": "0.95.0",
4
4
  "description": "Beautiful, animated, accessible React Native components, theme and form engine for Webority projects.",
5
5
  "keywords": [
6
6
  "react-native",
@@ -84,8 +84,8 @@
84
84
  "react-native-safe-area-context": ">=5.4.0",
85
85
  "react-native-svg": ">=15.0.0",
86
86
  "react-native-worklets": ">=0.10.0",
87
- "@webority/canvas-kit": "0.94.0",
88
- "@webority/mobile-core": "0.94.0"
87
+ "@webority/canvas-kit": "0.95.0",
88
+ "@webority/mobile-core": "0.95.0"
89
89
  },
90
90
  "peerDependenciesMeta": {
91
91
  "@webority/canvas-kit": {
@@ -146,10 +146,10 @@
146
146
  "react-test-renderer": "19.2.8",
147
147
  "rimraf": "6.1.3",
148
148
  "typescript": "5.9.3",
149
- "@webority/canvas-kit": "0.94.0",
149
+ "@webority/canvas-kit": "0.95.0",
150
+ "@webority/mobile-core": "0.95.0",
150
151
  "@webority/mobile-dev": "0.0.0",
151
- "@webority/mobile-core": "0.94.0",
152
- "@webority/tokens": "0.94.0"
152
+ "@webority/tokens": "0.95.0"
153
153
  },
154
154
  "scripts": {
155
155
  "build": "bob build && node ../mobile-dev/scripts/minify-lib.mjs",