react-native-bread 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,18 +1,19 @@
1
1
  # React Native Bread 🍞
2
2
 
3
- An opinionated toast component for React Native. Inspired by @emilkowalski's Sonner, built for mobile with smooth 60fps animations and intuitive swipe gestures. Extremely lightweight.
3
+ An extremely lightweight, opinionated toast component for React Native. Inspired by Sonner, built for mobile with smooth premium-feeling 60fps animations and complex swipe gestures.
4
4
 
5
5
  https://github.com/user-attachments/assets/8a862dba-422c-4573-9f12-0a36cf6efe49
6
6
 
7
7
  ## Features
8
8
 
9
- - **Extremely lightweight** package, only 13.8KB packed size
9
+ - **Extremely lightweight** package, only 13.8KB packed size
10
10
  - Clean, imperative API inspired by [Sonner](https://sonner.emilkowal.ski/)
11
11
  - Zero setup - add one component, start toasting. No hooks, no providers
12
- - Built for mobile with smooth 60fps animations via Reanimated 3
12
+ - Built for mobile with smooth 60fps animations powered by Reanimated
13
13
  - Natural swipe gestures that feel native to the platform
14
14
  - Multiple toast types: `success`, `error`, `info`, and `promise`
15
15
  - Promise handling with automatic loading → success/error states
16
+ - Complex animations and gestures but with high performance
16
17
  - Toast stacking with configurable limits
17
18
  - Position toasts at top or bottom of screen
18
19
  - Completely customizable - colors, icons, styles, animations
@@ -160,7 +161,7 @@ Available options include:
160
161
 
161
162
  ## Known Issues
162
163
 
163
- **Modal Overlays**: Toasts may render behind React Native's `<Modal>` component since modals are mounted at the native layer.
164
+ **Modal Pages**: Toasts may render behind React Native's `screenOptions={{ presentation: "modal" }}` since they are mounted at the native layer above the whole app.
164
165
 
165
- **Solution**: Use absolute positioning within your component tree instead of `<Modal>` for better toast visibility.
166
+ **Solution**: Use `screenOptions={{ presentation: "containedModal" }}`, or add another `<BreadLoaf>` inside the modal page.
166
167
 
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.ToastContainer=void 0;var e=require("react"),t=require("react-native"),i=require("react-native-gesture-handler"),o=function(e,t){if("function"==typeof WeakMap)var i=new WeakMap,o=new WeakMap;return function(e,t){if(!t&&e&&e.__esModule)return e;var n,s,r={__proto__:null,default:e};if(null===e||"object"!=typeof e&&"function"!=typeof e)return r;if(n=t?o:i){if(n.has(e))return n.get(e);n.set(e,r)}for(const t in e)"default"!==t&&{}.hasOwnProperty.call(e,t)&&((s=(n=Object.defineProperty)&&Object.getOwnPropertyDescriptor(e,t))&&(s.get||s.set)?n(r,t,s):r[t]=e[t]);return r}(e,t)}(require("react-native-reanimated")),n=require("react-native-safe-area-context"),s=require("react-native-worklets"),r=require("./icons/index.js"),a=require("./toast-store.js"),l=require("react/jsx-runtime");const c=28,u=(0,e.memo)(({fill:e})=>(0,l.jsx)(r.GreenCheck,{width:36,height:36,fill:e})),d=(0,e.memo)(({fill:e})=>(0,l.jsx)(r.RedX,{width:c,height:c,fill:e})),p=(0,e.memo)(({fill:e})=>(0,l.jsx)(r.InfoIcon,{width:c,height:c,fill:e})),h=(0,e.memo)(()=>(0,l.jsx)(r.CloseIcon,{width:20,height:20})),f=(0,e.memo)(({type:e,accentColor:i})=>{switch(e){case"success":default:return(0,l.jsx)(u,{fill:i});case"error":return(0,l.jsx)(d,{fill:i});case"loading":return(0,l.jsx)(t.ActivityIndicator,{size:c,color:i});case"info":return(0,l.jsx)(p,{fill:i})}}),g=(e,t,i,o)=>i?"function"==typeof i?i({color:t,size:c}):i:o?o({color:t,size:c}):(0,l.jsx)(f,{type:e,accentColor:t}),m=(0,e.memo)(({type:t,accentColor:i,customIcon:n,configIcon:s})=>{const r=(0,o.useSharedValue)(0);(0,e.useEffect)(()=>{r.value=(0,o.withTiming)(1,{duration:350,easing:o.Easing.out(o.Easing.back(1.5))})},[r]);const a=(0,o.useAnimatedStyle)(()=>({opacity:r.value,transform:[{scale:.7+.3*r.value}]}));return(0,l.jsx)(o.default.View,{style:a,children:g(t,i,n,s)})}),y=(0,e.memo)(({type:e,title:i,description:o,accentColor:n,customIcon:s,configIcon:r,showCloseButton:a,onDismiss:c,titleStyle:u,descriptionStyle:d,optionsTitleStyle:p,optionsDescriptionStyle:f})=>(0,l.jsxs)(t.View,{style:j.content,children:[(0,l.jsx)(t.View,{style:j.icon,children:(0,l.jsx)(m,{type:e,accentColor:n,customIcon:s,configIcon:r},e)}),(0,l.jsxs)(t.View,{style:j.textContainer,children:[(0,l.jsx)(t.Text,{maxFontSizeMultiplier:1.35,allowFontScaling:!1,style:[j.title,{color:n},u,p],children:i}),o&&(0,l.jsx)(t.Text,{allowFontScaling:!1,maxFontSizeMultiplier:1.35,style:[j.description,d,f],children:o})]}),a&&(0,l.jsx)(t.Pressable,{style:j.closeButton,onPress:c,hitSlop:12,children:(0,l.jsx)(h,{})})]}));exports.ToastContainer=()=>{const[i,o]=(0,e.useState)([]),[s,r]=(0,e.useState)(()=>a.toastStore.getTheme()),{top:c,bottom:u}=(0,n.useSafeAreaInsets)();(0,e.useEffect)(()=>{const e=a.toastStore.getState();return o(e.visibleToasts),r(a.toastStore.getTheme()),a.toastStore.subscribe(e=>{o(e.visibleToasts),r(a.toastStore.getTheme())})},[]);const d=(0,e.useCallback)(e=>{let t=0;for(const o of i){if(o.id===e)break;o.isExiting||t++}return t},[i]),p=(0,e.useMemo)(()=>[...i].reverse(),[i]);if(0===i.length)return null;const h="bottom"===s.position,f=h?u:c,g=h?{bottom:f+s.offset+2}:{top:f+s.offset+2};return(0,l.jsx)(t.View,{style:[j.container,g],pointerEvents:"box-none",children:p.map(e=>{const t=e.isExiting?-1:d(e.id);return(0,l.jsx)(w,{toast:e,index:t,theme:s,position:s.position},e.id)})})};const x=o.Easing.bezier(.25,.1,.25,1),v=350,S=({toast:t,index:n,theme:r,position:c})=>{const u=(0,o.useSharedValue)(0),d=(0,o.useSharedValue)(0),p=(0,o.useSharedValue)(!1),h=(0,o.useSharedValue)(!1),f="bottom"===c,g=f?80:-80,m=f?100:-100,S=(0,o.useSharedValue)(n),w=(0,e.useRef)(t.type),b=(0,e.useRef)(n),C=(0,e.useRef)(!1);(0,e.useEffect)(()=>{C.current||t.isExiting||(u.value=(0,o.withTiming)(1,{duration:400,easing:x}),C.current=!0),t.isExiting&&(u.value=(0,o.withTiming)(0,{duration:v,easing:x}),d.value=(0,o.withTiming)(m,{duration:v,easing:x})),t.type!==w.current&&(w.current=t.type),n>=0&&b.current!==n&&(S.value=(0,o.withTiming)(n,{duration:300,easing:x}),b.current=n)},[t.isExiting,t.type,n,u,d,S,m]);const T=(0,e.useCallback)(()=>{a.toastStore.hide(t.id)},[t.id]),I=(0,e.useMemo)(()=>i.Gesture.Pan().onStart(()=>{"worklet";p.value=!0,h.value=!1}).onUpdate(e=>{"worklet";const t=e.translationY,i=f?t:-t,o=f?-t:t;if(i>0){const o=f?Math.min(t,180):Math.max(t,-180);d.value=o,(i>40||(f?e.velocityY>300:e.velocityY<-300))&&(h.value=!0)}else{const e=60*(1-Math.exp(-o/250));d.value=f?-Math.min(e,60):Math.min(e,60),h.value=!1}}).onEnd(()=>{"worklet";if(p.value=!1,h.value){u.value=(0,o.withTiming)(0,{duration:v,easing:x});const e=f?200:-200;d.value=(0,o.withTiming)(d.value+e,{duration:v,easing:x}),(0,s.scheduleOnRN)(T)}else d.value=(0,o.withTiming)(0,{duration:650,easing:x})}),[f,T,u,d,h,p]),M=(0,e.useMemo)(()=>i.Gesture.Pan().enabled(!1),[]),E=(0,o.useDerivedValue)(()=>1e3-Math.round(S.value)),k=(0,o.useAnimatedStyle)(()=>{const e=(0,o.interpolate)(u.value,[0,1],[g,0]),t=f?10*S.value:-10*S.value,i=1-.05*S.value,n=e+d.value+t,s=(0,o.interpolate)(u.value,[0,1],[0,1]),r=f?d.value:-d.value,a=s*(r>0?(0,o.interpolate)(r,[0,130],[1,0],"clamp"):1);return{transform:[{translateY:n},{scale:i*(0,o.interpolate)(Math.abs(d.value),[0,50],[1,.98],"clamp")}],opacity:a,zIndex:E.value}}),V=r.colors[t.type].accent,z=r.colors[t.type].background,q=f?{bottom:0}:{top:0},{options:D}=t,O=D?.icon,P=r.icons[t.type],_=D?.dismissible??r.dismissible,B="loading"!==t.type&&(D?.showCloseButton??r.showCloseButton),R=_?I:M,W=[j.toast,q,{backgroundColor:z},r.toastStyle,D?.style,k];return(0,l.jsx)(i.GestureDetector,{gesture:R,children:(0,l.jsx)(o.default.View,{style:W,children:(0,l.jsx)(y,{type:t.type,title:t.title,description:t.description,accentColor:V,customIcon:O,configIcon:P,showCloseButton:B,onDismiss:T,titleStyle:r.titleStyle,descriptionStyle:r.descriptionStyle,optionsTitleStyle:D?.titleStyle,optionsDescriptionStyle:D?.descriptionStyle})})})},w=(0,e.memo)(S,(e,t)=>e.toast.id===t.toast.id&&e.toast.type===t.toast.type&&e.toast.title===t.toast.title&&e.toast.description===t.toast.description&&e.toast.isExiting===t.toast.isExiting&&e.index===t.index&&e.position===t.position&&e.theme===t.theme),j=t.StyleSheet.create({container:{position:"absolute",left:16,right:16,zIndex:1e3},closeButton:{padding:4,alignItems:"center",justifyContent:"center"},icon:{width:48,height:48,alignItems:"center",justifyContent:"center",marginLeft:8},content:{alignItems:"center",flexDirection:"row",gap:12,minHeight:36},description:{color:"#6B7280",fontSize:12,fontWeight:"500",lineHeight:16},textContainer:{flex:1,gap:1,justifyContent:"center"},title:{fontSize:14,fontWeight:"700",lineHeight:20},toast:{borderRadius:20,borderCurve:"continuous",position:"absolute",left:0,right:0,paddingHorizontal:12,paddingVertical:10,shadowColor:"#000",shadowOffset:{width:0,height:8},shadowOpacity:.05,shadowRadius:24,elevation:8}});
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.ToastContainer=void 0;var e=require("react"),t=require("react-native"),i=require("react-native-gesture-handler"),n=function(e,t){if("function"==typeof WeakMap)var i=new WeakMap,n=new WeakMap;return function(e,t){if(!t&&e&&e.__esModule)return e;var o,s,a={__proto__:null,default:e};if(null===e||"object"!=typeof e&&"function"!=typeof e)return a;if(o=t?n:i){if(o.has(e))return o.get(e);o.set(e,a)}for(const t in e)"default"!==t&&{}.hasOwnProperty.call(e,t)&&((s=(o=Object.defineProperty)&&Object.getOwnPropertyDescriptor(e,t))&&(s.get||s.set)?o(a,t,s):a[t]=e[t]);return a}(e,t)}(require("react-native-reanimated")),o=require("react-native-safe-area-context"),s=require("react-native-worklets"),a=require("./icons/index.js"),r=require("./toast-store.js"),l=require("react/jsx-runtime");const u=28,c=350,d=n.Easing.bezier(.25,.1,.25,1),p=Array.from({length:5},()=>({progress:(0,n.makeMutable)(0),translationY:(0,n.makeMutable)(0),stackIndex:(0,n.makeMutable)(0)})),f=Array.from({length:5},()=>({wasExiting:!1,prevIndex:0,initialized:!1})),g=new Map,h=new Set,m=(e,i,n,o)=>{if(n)return"function"==typeof n?n({color:i,size:u}):n;if(o)return o({color:i,size:u});switch(e){case"success":default:return(0,l.jsx)(a.GreenCheck,{width:36,height:36,fill:i});case"error":return(0,l.jsx)(a.RedX,{width:u,height:u,fill:i});case"loading":return(0,l.jsx)(t.ActivityIndicator,{size:u,color:i});case"info":return(0,l.jsx)(a.InfoIcon,{width:u,height:u,fill:i})}},x=(0,e.memo)(({type:t,color:i,custom:o,config:s})=>{const a=(0,n.useSharedValue)(0);(0,e.useEffect)(()=>{a.value=(0,n.withTiming)(1,{duration:350,easing:n.Easing.out(n.Easing.back(1.5))})},[a]);const r=(0,n.useAnimatedStyle)(()=>({opacity:a.value,transform:[{scale:.7+.3*a.value}]}));return(0,l.jsx)(n.default.View,{style:r,children:m(t,i,o,s)})});exports.ToastContainer=()=>{const[a,u]=(0,e.useState)([]),[p,f]=(0,e.useState)(()=>r.toastStore.getTheme()),{top:g,bottom:h}=(0,o.useSafeAreaInsets)(),m=(0,e.useRef)((0,n.makeMutable)(null)),x=(0,e.useRef)((0,n.makeMutable)("bottom"===p.position)),v=(0,e.useRef)((0,n.makeMutable)(!0)),b=(0,n.useSharedValue)(!1);(0,e.useEffect)(()=>{u(r.toastStore.getState().visibleToasts);let e=null,t=null;return r.toastStore.subscribe(i=>{e=i.visibleToasts,null===t&&(t=requestAnimationFrame(()=>{e&&(u(e),e=null),t=null;const i=r.toastStore.getTheme();f(e=>e===i?e:i)}))})},[]);const T=(0,e.useMemo)(()=>{const e=new Map;let t=0;for(const i of a)e.set(i.id,i.isExiting?-1:t),i.isExiting||t++;return[...a].reverse().map(t=>({toast:t,index:e.get(t.id)??0}))},[a]),S="bottom"===p.position,j=a.find(e=>!e.isExiting),k=j?.options?.dismissible??p.dismissible;(0,e.useEffect)(()=>{x.current.value=S,v.current.value=k},[S,k]);const E=(0,e.useMemo)(()=>i.Gesture.Pan().onStart(()=>{"worklet";b.value=!1}).onUpdate(e=>{"worklet";if(!v.current.value)return;const t=m.current.value;if(!t)return;const{slot:i}=t,n=x.current.value,o=e.translationY,s=n?o:-o,a=n?-o:o;if(s>0){const t=n?Math.min(o,180):Math.max(o,-180);i.translationY.value=t;const a=s>40||(n?e.velocityY>300:e.velocityY<-300);b.value=a}else{const e=60*(1-Math.exp(-a/250));i.translationY.value=n?-Math.min(e,60):Math.min(e,60),b.value=!1}}).onEnd(()=>{"worklet";if(!v.current.value)return;const e=m.current.value;if(!e)return;const{slot:t}=e,i=x.current.value;if(b.value){t.progress.value=(0,n.withTiming)(0,{duration:c,easing:d});const o=i?200:-200;t.translationY.value=(0,n.withTiming)(t.translationY.value+o,{duration:c,easing:d}),(0,s.scheduleOnRN)(e.dismiss)}else t.translationY.value=(0,n.withTiming)(0,{duration:650,easing:d})}),[b]),M=(0,e.useCallback)(e=>{m.current.value=e},[]);if(0===a.length)return null;const I=S?h:g,C=S?{bottom:I+p.offset+2}:{top:I+p.offset+2};return(0,l.jsx)(i.GestureDetector,{gesture:E,children:(0,l.jsx)(t.View,{style:[w.container,C],pointerEvents:"box-none",children:T.map(({toast:e,index:t})=>(0,l.jsx)(y,{toast:e,index:t,theme:p,position:p.position,isTopToast:0===t,registerTopToast:M},e.id))})})};const v=({toast:i,index:o,theme:s,position:u,isTopToast:v,registerTopToast:y})=>{const b=(0,e.useRef)(null);null===b.current&&(b.current=(e=>{if(g.has(e))return g.get(e)??0;for(let t=0;t<5;t++)if(!h.has(t))return g.set(e,t),h.add(t),f[t].initialized=!1,f[t].wasExiting=!1,f[t].prevIndex=0,t;return 0})(i.id));const T=b.current,S=p[T],j=f[T],k="bottom"===u,E=k?80:-80,M=k?100:-100,I=(0,e.useRef)(i.type),[C,z]=(0,e.useState)(!1);(0,e.useEffect)(()=>()=>{(e=>{const t=g.get(e);void 0!==t&&(h.delete(t),g.delete(e),f[t].initialized=!1,f[t].wasExiting=!1,f[t].prevIndex=0)})(i.id)},[i.id]),(0,e.useEffect)(()=>{S.progress.value=0,S.translationY.value=0,S.stackIndex.value=o,S.progress.value=(0,n.withTiming)(1,{duration:400,easing:d})},[]),(0,e.useEffect)(()=>{i.isExiting&&!j.wasExiting&&(j.wasExiting=!0,S.progress.value=(0,n.withTiming)(0,{duration:c,easing:d}),S.translationY.value=(0,n.withTiming)(M,{duration:c,easing:d}))},[i.isExiting,S,j,M]),(0,e.useEffect)(()=>{j.initialized&&o!==j.prevIndex&&(S.stackIndex.value=(0,n.withTiming)(o,{duration:300,easing:d})),j.prevIndex=o,j.initialized=!0},[o,S,j]),(0,e.useEffect)(()=>{const e=setTimeout(()=>z(!0),50);return()=>clearTimeout(e)},[]);const Y="loading"===I.current&&"loading"!==i.type;I.current=i.type;const q=(0,e.useCallback)(()=>{r.toastStore.hide(i.id)},[i.id]);(0,e.useEffect)(()=>{if(v)return y({slot:S,dismiss:q}),()=>y(null)},[v,y,S,q]);const R=(0,n.useAnimatedStyle)(()=>{const e=(0,n.interpolate)(S.progress.value,[0,1],[E,0]),t=k?10*S.stackIndex.value:-10*S.stackIndex.value,i=1-.05*S.stackIndex.value,o=e+S.translationY.value+t,s=(0,n.interpolate)(S.progress.value,[0,1],[0,1]),a=k?S.translationY.value:-S.translationY.value,r=s*(a>0?(0,n.interpolate)(a,[0,130],[1,0],"clamp"):1);return{transform:[{translateY:o},{scale:i*(0,n.interpolate)(Math.abs(S.translationY.value),[0,50],[1,.98],"clamp")}],opacity:r,zIndex:1e3-Math.round(S.stackIndex.value)}}),{options:O}=i,V=s.colors[i.type],_="loading"!==i.type&&(O?.showCloseButton??s.showCloseButton);return(0,l.jsxs)(n.default.View,{style:[w.toast,k?w.toastBottom:w.toastTop,{backgroundColor:V.background},s.toastStyle,O?.style,R],children:[(0,l.jsx)(t.View,{style:w.iconContainer,children:C&&(Y?(0,l.jsx)(x,{type:i.type,color:V.accent,custom:O?.icon,config:s.icons[i.type]},i.type):m(i.type,V.accent,O?.icon,s.icons[i.type]))}),(0,l.jsxs)(t.View,{style:w.textContainer,children:[(0,l.jsx)(t.Text,{maxFontSizeMultiplier:1.35,allowFontScaling:!1,style:[w.title,{color:V.accent},s.titleStyle,O?.titleStyle],children:i.title}),i.description&&(0,l.jsx)(t.Text,{allowFontScaling:!1,maxFontSizeMultiplier:1.35,style:[w.description,s.descriptionStyle,O?.descriptionStyle],children:i.description})]}),_&&(0,l.jsx)(t.Pressable,{style:w.closeButton,onPress:q,hitSlop:12,children:(0,l.jsx)(a.CloseIcon,{width:20,height:20})})]})},y=(0,e.memo)(v,(e,t)=>e.toast.id===t.toast.id&&e.toast.type===t.toast.type&&e.toast.title===t.toast.title&&e.toast.description===t.toast.description&&e.toast.isExiting===t.toast.isExiting&&e.index===t.index&&e.position===t.position&&e.theme===t.theme&&e.isTopToast===t.isTopToast),w=t.StyleSheet.create({container:{position:"absolute",left:16,right:16,zIndex:1e3},toast:{flexDirection:"row",alignItems:"center",gap:12,minHeight:36,borderRadius:20,borderCurve:"continuous",position:"absolute",left:0,right:0,paddingHorizontal:12,paddingVertical:10,shadowColor:"#000",shadowOffset:{width:0,height:8},shadowOpacity:.05,shadowRadius:24,elevation:8},toastTop:{top:0},toastBottom:{bottom:0},iconContainer:{width:48,height:48,alignItems:"center",justifyContent:"center",marginLeft:8},textContainer:{flex:1,gap:1,justifyContent:"center"},title:{fontSize:14,fontWeight:"700",lineHeight:20},description:{color:"#6B7280",fontSize:12,fontWeight:"500",lineHeight:16},closeButton:{padding:4,alignItems:"center",justifyContent:"center"}});
@@ -1 +1 @@
1
- "use strict";import{memo as t,useCallback as e,useEffect as o,useMemo as i,useRef as n,useState as s}from"react";import{ActivityIndicator as l,Pressable as r,StyleSheet as a,Text as c,View as u}from"react-native";import{Gesture as d,GestureDetector as p}from"react-native-gesture-handler";import h,{Easing as m,interpolate as g,useAnimatedStyle as f,useDerivedValue as y,useSharedValue as v,withTiming as x}from"react-native-reanimated";import{useSafeAreaInsets as w}from"react-native-safe-area-context";import{scheduleOnRN as b}from"react-native-worklets";import{CloseIcon as S,GreenCheck as C,InfoIcon as I,RedX as z}from"./icons/index.js";import{toastStore as E}from"./toast-store.js";import{jsx as M,jsxs as j}from"react/jsx-runtime";const k=28,T=t(({fill:t})=>M(C,{width:36,height:36,fill:t})),B=t(({fill:t})=>M(z,{width:k,height:k,fill:t})),D=t(({fill:t})=>M(I,{width:k,height:k,fill:t})),F=t(()=>M(S,{width:20,height:20})),H=t(({type:t,accentColor:e})=>{switch(t){case"success":default:return M(T,{fill:e});case"error":return M(B,{fill:e});case"loading":return M(l,{size:k,color:e});case"info":return M(D,{fill:e})}}),Y=(t,e,o,i)=>o?"function"==typeof o?o({color:e,size:k}):o:i?i({color:e,size:k}):M(H,{type:t,accentColor:e}),P=t(({type:t,accentColor:e,customIcon:i,configIcon:n})=>{const s=v(0);o(()=>{s.value=x(1,{duration:350,easing:m.out(m.back(1.5))})},[s]);const l=f(()=>({opacity:s.value,transform:[{scale:.7+.3*s.value}]}));return M(h.View,{style:l,children:Y(t,e,i,n)})}),V=t(({type:t,title:e,description:o,accentColor:i,customIcon:n,configIcon:s,showCloseButton:l,onDismiss:a,titleStyle:d,descriptionStyle:p,optionsTitleStyle:h,optionsDescriptionStyle:m})=>j(u,{style:L.content,children:[M(u,{style:L.icon,children:M(P,{type:t,accentColor:i,customIcon:n,configIcon:s},t)}),j(u,{style:L.textContainer,children:[M(c,{maxFontSizeMultiplier:1.35,allowFontScaling:!1,style:[L.title,{color:i},d,h],children:e}),o&&M(c,{allowFontScaling:!1,maxFontSizeMultiplier:1.35,style:[L.description,p,m],children:o})]}),l&&M(r,{style:L.closeButton,onPress:a,hitSlop:12,children:M(F,{})})]}));export const ToastContainer=()=>{const[t,n]=s([]),[l,r]=s(()=>E.getTheme()),{top:a,bottom:c}=w();o(()=>{const t=E.getState();return n(t.visibleToasts),r(E.getTheme()),E.subscribe(t=>{n(t.visibleToasts),r(E.getTheme())})},[]);const d=e(e=>{let o=0;for(const i of t){if(i.id===e)break;i.isExiting||o++}return o},[t]),p=i(()=>[...t].reverse(),[t]);if(0===t.length)return null;const h="bottom"===l.position,m=h?c:a,g=h?{bottom:m+l.offset+2}:{top:m+l.offset+2};return M(u,{style:[L.container,g],pointerEvents:"box-none",children:p.map(t=>{const e=t.isExiting?-1:d(t.id);return M(W,{toast:t,index:e,theme:l,position:l.position},t.id)})})};const O=m.bezier(.25,.1,.25,1),R=350,W=t(({toast:t,index:s,theme:l,position:r})=>{const a=v(0),c=v(0),u=v(!1),m=v(!1),w="bottom"===r,S=w?80:-80,C=w?100:-100,I=v(s),z=n(t.type),j=n(s),k=n(!1);o(()=>{k.current||t.isExiting||(a.value=x(1,{duration:400,easing:O}),k.current=!0),t.isExiting&&(a.value=x(0,{duration:R,easing:O}),c.value=x(C,{duration:R,easing:O})),t.type!==z.current&&(z.current=t.type),s>=0&&j.current!==s&&(I.value=x(s,{duration:300,easing:O}),j.current=s)},[t.isExiting,t.type,s,a,c,I,C]);const T=e(()=>{E.hide(t.id)},[t.id]),B=i(()=>d.Pan().onStart(()=>{"worklet";u.value=!0,m.value=!1}).onUpdate(t=>{"worklet";const e=t.translationY,o=w?e:-e,i=w?-e:e;if(o>0){const i=w?Math.min(e,180):Math.max(e,-180);c.value=i,(o>40||(w?t.velocityY>300:t.velocityY<-300))&&(m.value=!0)}else{const t=60*(1-Math.exp(-i/250));c.value=w?-Math.min(t,60):Math.min(t,60),m.value=!1}}).onEnd(()=>{"worklet";if(u.value=!1,m.value){a.value=x(0,{duration:R,easing:O});const t=w?200:-200;c.value=x(c.value+t,{duration:R,easing:O}),b(T)}else c.value=x(0,{duration:650,easing:O})}),[w,T,a,c,m,u]),D=i(()=>d.Pan().enabled(!1),[]),F=y(()=>1e3-Math.round(I.value)),H=f(()=>{const t=g(a.value,[0,1],[S,0]),e=w?10*I.value:-10*I.value,o=1-.05*I.value,i=t+c.value+e,n=g(a.value,[0,1],[0,1]),s=w?c.value:-c.value,l=n*(s>0?g(s,[0,130],[1,0],"clamp"):1);return{transform:[{translateY:i},{scale:o*g(Math.abs(c.value),[0,50],[1,.98],"clamp")}],opacity:l,zIndex:F.value}}),Y=l.colors[t.type].accent,P=l.colors[t.type].background,W=w?{bottom:0}:{top:0},{options:U}=t,q=U?.icon,A=l.icons[t.type],G=U?.dismissible??l.dismissible,J="loading"!==t.type&&(U?.showCloseButton??l.showCloseButton),K=G?B:D,N=[L.toast,W,{backgroundColor:P},l.toastStyle,U?.style,H];return M(p,{gesture:K,children:M(h.View,{style:N,children:M(V,{type:t.type,title:t.title,description:t.description,accentColor:Y,customIcon:q,configIcon:A,showCloseButton:J,onDismiss:T,titleStyle:l.titleStyle,descriptionStyle:l.descriptionStyle,optionsTitleStyle:U?.titleStyle,optionsDescriptionStyle:U?.descriptionStyle})})})},(t,e)=>t.toast.id===e.toast.id&&t.toast.type===e.toast.type&&t.toast.title===e.toast.title&&t.toast.description===e.toast.description&&t.toast.isExiting===e.toast.isExiting&&t.index===e.index&&t.position===e.position&&t.theme===e.theme),L=a.create({container:{position:"absolute",left:16,right:16,zIndex:1e3},closeButton:{padding:4,alignItems:"center",justifyContent:"center"},icon:{width:48,height:48,alignItems:"center",justifyContent:"center",marginLeft:8},content:{alignItems:"center",flexDirection:"row",gap:12,minHeight:36},description:{color:"#6B7280",fontSize:12,fontWeight:"500",lineHeight:16},textContainer:{flex:1,gap:1,justifyContent:"center"},title:{fontSize:14,fontWeight:"700",lineHeight:20},toast:{borderRadius:20,borderCurve:"continuous",position:"absolute",left:0,right:0,paddingHorizontal:12,paddingVertical:10,shadowColor:"#000",shadowOffset:{width:0,height:8},shadowOpacity:.05,shadowRadius:24,elevation:8}});
1
+ "use strict";import{memo as t,useCallback as e,useEffect as i,useMemo as n,useRef as o,useState as s}from"react";import{ActivityIndicator as r,Pressable as a,StyleSheet as l,Text as c,View as u}from"react-native";import{Gesture as d,GestureDetector as p}from"react-native-gesture-handler";import g,{Easing as m,interpolate as h,makeMutable as v,useAnimatedStyle as f,useSharedValue as x,withTiming as y}from"react-native-reanimated";import{useSafeAreaInsets as w}from"react-native-safe-area-context";import{scheduleOnRN as b}from"react-native-worklets";import{CloseIcon as T,GreenCheck as I,InfoIcon as z,RedX as Y}from"./icons/index.js";import{toastStore as S}from"./toast-store.js";import{jsx as k,jsxs as E}from"react/jsx-runtime";const C=28,M=350,j=m.bezier(.25,.1,.25,1),B=Array.from({length:5},()=>({progress:v(0),translationY:v(0),stackIndex:v(0)})),F=Array.from({length:5},()=>({wasExiting:!1,prevIndex:0,initialized:!1})),H=new Map,A=new Set,V=(t,e,i,n)=>{if(i)return"function"==typeof i?i({color:e,size:C}):i;if(n)return n({color:e,size:C});switch(t){case"success":default:return k(I,{width:36,height:36,fill:e});case"error":return k(Y,{width:C,height:C,fill:e});case"loading":return k(r,{size:C,color:e});case"info":return k(z,{width:C,height:C,fill:e})}},O=t(({type:t,color:e,custom:n,config:o})=>{const s=x(0);i(()=>{s.value=y(1,{duration:350,easing:m.out(m.back(1.5))})},[s]);const r=f(()=>({opacity:s.value,transform:[{scale:.7+.3*s.value}]}));return k(g.View,{style:r,children:V(t,e,n,o)})});export const ToastContainer=()=>{const[t,r]=s([]),[a,l]=s(()=>S.getTheme()),{top:c,bottom:g}=w(),m=o(v(null)),h=o(v("bottom"===a.position)),f=o(v(!0)),T=x(!1);i(()=>{r(S.getState().visibleToasts);let t=null,e=null;return S.subscribe(i=>{t=i.visibleToasts,null===e&&(e=requestAnimationFrame(()=>{t&&(r(t),t=null),e=null;const i=S.getTheme();l(t=>t===i?t:i)}))})},[]);const I=n(()=>{const e=new Map;let i=0;for(const n of t)e.set(n.id,n.isExiting?-1:i),n.isExiting||i++;return[...t].reverse().map(t=>({toast:t,index:e.get(t.id)??0}))},[t]),z="bottom"===a.position,Y=t.find(t=>!t.isExiting),E=Y?.options?.dismissible??a.dismissible;i(()=>{h.current.value=z,f.current.value=E},[z,E]);const C=n(()=>d.Pan().onStart(()=>{"worklet";T.value=!1}).onUpdate(t=>{"worklet";if(!f.current.value)return;const e=m.current.value;if(!e)return;const{slot:i}=e,n=h.current.value,o=t.translationY,s=n?o:-o,r=n?-o:o;if(s>0){const e=n?Math.min(o,180):Math.max(o,-180);i.translationY.value=e;const r=s>40||(n?t.velocityY>300:t.velocityY<-300);T.value=r}else{const t=60*(1-Math.exp(-r/250));i.translationY.value=n?-Math.min(t,60):Math.min(t,60),T.value=!1}}).onEnd(()=>{"worklet";if(!f.current.value)return;const t=m.current.value;if(!t)return;const{slot:e}=t,i=h.current.value;if(T.value){e.progress.value=y(0,{duration:M,easing:j});const n=i?200:-200;e.translationY.value=y(e.translationY.value+n,{duration:M,easing:j}),b(t.dismiss)}else e.translationY.value=y(0,{duration:650,easing:j})}),[T]),B=e(t=>{m.current.value=t},[]);if(0===t.length)return null;const F=z?g:c,H=z?{bottom:F+a.offset+2}:{top:F+a.offset+2};return k(p,{gesture:C,children:k(u,{style:[R.container,H],pointerEvents:"box-none",children:I.map(({toast:t,index:e})=>k(P,{toast:t,index:e,theme:a,position:a.position,isTopToast:0===e,registerTopToast:B},t.id))})})};const P=t(({toast:t,index:n,theme:r,position:l,isTopToast:d,registerTopToast:p})=>{const m=o(null);null===m.current&&(m.current=(t=>{if(H.has(t))return H.get(t)??0;for(let e=0;e<5;e++)if(!A.has(e))return H.set(t,e),A.add(e),F[e].initialized=!1,F[e].wasExiting=!1,F[e].prevIndex=0,e;return 0})(t.id));const v=m.current,x=B[v],w=F[v],b="bottom"===l,I=b?80:-80,z=b?100:-100,Y=o(t.type),[C,P]=s(!1);i(()=>()=>{(t=>{const e=H.get(t);void 0!==e&&(A.delete(e),H.delete(t),F[e].initialized=!1,F[e].wasExiting=!1,F[e].prevIndex=0)})(t.id)},[t.id]),i(()=>{x.progress.value=0,x.translationY.value=0,x.stackIndex.value=n,x.progress.value=y(1,{duration:400,easing:j})},[]),i(()=>{t.isExiting&&!w.wasExiting&&(w.wasExiting=!0,x.progress.value=y(0,{duration:M,easing:j}),x.translationY.value=y(z,{duration:M,easing:j}))},[t.isExiting,x,w,z]),i(()=>{w.initialized&&n!==w.prevIndex&&(x.stackIndex.value=y(n,{duration:300,easing:j})),w.prevIndex=n,w.initialized=!0},[n,x,w]),i(()=>{const t=setTimeout(()=>P(!0),50);return()=>clearTimeout(t)},[]);const W="loading"===Y.current&&"loading"!==t.type;Y.current=t.type;const q=e(()=>{S.hide(t.id)},[t.id]);i(()=>{if(d)return p({slot:x,dismiss:q}),()=>p(null)},[d,p,x,q]);const D=f(()=>{const t=h(x.progress.value,[0,1],[I,0]),e=b?10*x.stackIndex.value:-10*x.stackIndex.value,i=1-.05*x.stackIndex.value,n=t+x.translationY.value+e,o=h(x.progress.value,[0,1],[0,1]),s=b?x.translationY.value:-x.translationY.value,r=o*(s>0?h(s,[0,130],[1,0],"clamp"):1);return{transform:[{translateY:n},{scale:i*h(Math.abs(x.translationY.value),[0,50],[1,.98],"clamp")}],opacity:r,zIndex:1e3-Math.round(x.stackIndex.value)}}),{options:L}=t,U=r.colors[t.type],G="loading"!==t.type&&(L?.showCloseButton??r.showCloseButton);return E(g.View,{style:[R.toast,b?R.toastBottom:R.toastTop,{backgroundColor:U.background},r.toastStyle,L?.style,D],children:[k(u,{style:R.iconContainer,children:C&&(W?k(O,{type:t.type,color:U.accent,custom:L?.icon,config:r.icons[t.type]},t.type):V(t.type,U.accent,L?.icon,r.icons[t.type]))}),E(u,{style:R.textContainer,children:[k(c,{maxFontSizeMultiplier:1.35,allowFontScaling:!1,style:[R.title,{color:U.accent},r.titleStyle,L?.titleStyle],children:t.title}),t.description&&k(c,{allowFontScaling:!1,maxFontSizeMultiplier:1.35,style:[R.description,r.descriptionStyle,L?.descriptionStyle],children:t.description})]}),G&&k(a,{style:R.closeButton,onPress:q,hitSlop:12,children:k(T,{width:20,height:20})})]})},(t,e)=>t.toast.id===e.toast.id&&t.toast.type===e.toast.type&&t.toast.title===e.toast.title&&t.toast.description===e.toast.description&&t.toast.isExiting===e.toast.isExiting&&t.index===e.index&&t.position===e.position&&t.theme===e.theme&&t.isTopToast===e.isTopToast),R=l.create({container:{position:"absolute",left:16,right:16,zIndex:1e3},toast:{flexDirection:"row",alignItems:"center",gap:12,minHeight:36,borderRadius:20,borderCurve:"continuous",position:"absolute",left:0,right:0,paddingHorizontal:12,paddingVertical:10,shadowColor:"#000",shadowOffset:{width:0,height:8},shadowOpacity:.05,shadowRadius:24,elevation:8},toastTop:{top:0},toastBottom:{bottom:0},iconContainer:{width:48,height:48,alignItems:"center",justifyContent:"center",marginLeft:8},textContainer:{flex:1,gap:1,justifyContent:"center"},title:{fontSize:14,fontWeight:"700",lineHeight:20},description:{color:"#6B7280",fontSize:12,fontWeight:"500",lineHeight:16},closeButton:{padding:4,alignItems:"center",justifyContent:"center"}});
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "react-native-bread",
3
- "version": "0.1.2",
4
- "description": "A delicious toast library for React Native with beautiful animations and gesture support",
3
+ "version": "0.2.0",
4
+ "description": "A lightweight sonner-inspired toast library for React Native with premium-feeling animations and complex gesture support",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
7
7
  "types": "lib/typescript/index.d.ts",
@@ -18,7 +18,18 @@
18
18
  "url": "https://github.com/AlshehriAli0/react-native-bread/issues"
19
19
  },
20
20
  "homepage": "https://github.com/AlshehriAli0/react-native-bread#readme",
21
- "keywords": ["react-native", "toast", "notification", "snackbar", "bread", "animation", "gesture", "reanimated"],
21
+ "keywords": [
22
+ "react-native",
23
+ "toast",
24
+ "react-native-toast",
25
+ "react-hot-toast",
26
+ "notification",
27
+ "snackbar",
28
+ "bread",
29
+ "animation",
30
+ "gesture",
31
+ "reanimated"
32
+ ],
22
33
  "scripts": {
23
34
  "build": "bob build",
24
35
  "minify": "find lib -name '*.js' -not -path '*/node_modules/*' -exec terser {} -o {} -c directives=false -m --module \\;",