react-native-bread 0.2.2 → 0.3.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
|
@@ -6,16 +6,17 @@ An extremely lightweight, opinionated toast component for React Native.
|
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
|
-
- **Extremely lightweight** package, only
|
|
9
|
+
- **Extremely lightweight** package, only 14KB 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 powered by Reanimated
|
|
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
16
|
- Complex animations and gestures but with high performance
|
|
17
17
|
- Toast stacking with configurable limits
|
|
18
18
|
- Position toasts at top or bottom of screen
|
|
19
|
+
- **RTL built-in support** - perfect for Arabic and other RTL languages
|
|
19
20
|
- Completely customizable - colors, icons, styles, animations
|
|
20
21
|
- Full Expo compatibility
|
|
21
22
|
- Imperative API works anywhere - components, utilities, event handlers
|
|
@@ -125,6 +126,7 @@ Customize all toasts globally via the `config` prop on `<BreadLoaf />`:
|
|
|
125
126
|
<BreadLoaf
|
|
126
127
|
config={{
|
|
127
128
|
position: 'bottom',
|
|
129
|
+
rtl: false, // Enable for RTL languages
|
|
128
130
|
stacking: true,
|
|
129
131
|
maxStack: 3,
|
|
130
132
|
defaultDuration: 4000,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.toastStore=void 0;const t={position:"top",offset:0,stacking:!0,maxStack:3,dismissible:!0,showCloseButton:!0,colors:{success:{accent:"#28B770",background:"#FFFFFF"},error:{accent:"#F05964",background:"#FFFFFF"},info:{accent:"#EDBE43",background:"#FFFFFF"},loading:{accent:"#232323",background:"#FFFFFF"}},icons:{},toastStyle:{},titleStyle:{},descriptionStyle:{},defaultDuration:4e3};exports.toastStore=new class{state={visibleToasts:[]};theme=t;listeners=new Set;toastIdCounter=0;timeouts=new Map;subscribe=t=>(this.listeners.add(t),()=>{this.listeners.delete(t)});emit(){for(const t of this.listeners)t(this.state)}setState(t){this.state={...this.state,...t},this.emit()}getState=()=>this.state;getTheme=()=>this.theme;setConfig=s=>{this.theme=function(s){if(!s)return t;const e={...t.colors};if(s.colors)for(const i of Object.keys(s.colors)){const o=s.colors[i];o&&(e[i]={...t.colors[i],...o})}return{position:s.position??t.position,offset:s.offset??t.offset,stacking:s.stacking??t.stacking,maxStack:s.maxStack??t.maxStack,dismissible:s.dismissible??t.dismissible,showCloseButton:s.showCloseButton??t.showCloseButton,colors:e,icons:{...t.icons,...s.icons},toastStyle:{...t.toastStyle,...s.toastStyle},titleStyle:{...t.titleStyle,...s.titleStyle},descriptionStyle:{...t.descriptionStyle,...s.descriptionStyle},defaultDuration:s.defaultDuration??t.defaultDuration}}(s)};show=(t,s,e="success",i,o)=>{const a=i??o?.duration??this.theme.defaultDuration,
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.toastStore=void 0;const t={position:"top",offset:0,rtl:!1,stacking:!0,maxStack:3,dismissible:!0,showCloseButton:!0,colors:{success:{accent:"#28B770",background:"#FFFFFF"},error:{accent:"#F05964",background:"#FFFFFF"},info:{accent:"#EDBE43",background:"#FFFFFF"},loading:{accent:"#232323",background:"#FFFFFF"}},icons:{},toastStyle:{},titleStyle:{},descriptionStyle:{},defaultDuration:4e3};exports.toastStore=new class{state={visibleToasts:[]};theme=t;listeners=new Set;toastIdCounter=0;timeouts=new Map;subscribe=t=>(this.listeners.add(t),()=>{this.listeners.delete(t)});emit(){for(const t of this.listeners)t(this.state)}setState(t){this.state={...this.state,...t},this.emit()}getState=()=>this.state;getTheme=()=>this.theme;setConfig=s=>{this.theme=function(s){if(!s)return t;const e={...t.colors};if(s.colors)for(const i of Object.keys(s.colors)){const o=s.colors[i];o&&(e[i]={...t.colors[i],...o})}return{position:s.position??t.position,offset:s.offset??t.offset,rtl:s.rtl??t.rtl,stacking:s.stacking??t.stacking,maxStack:s.maxStack??t.maxStack,dismissible:s.dismissible??t.dismissible,showCloseButton:s.showCloseButton??t.showCloseButton,colors:e,icons:{...t.icons,...s.icons},toastStyle:{...t.toastStyle,...s.toastStyle},titleStyle:{...t.titleStyle,...s.titleStyle},descriptionStyle:{...t.descriptionStyle,...s.descriptionStyle},defaultDuration:s.defaultDuration??t.defaultDuration}}(s)};show=(t,s,e="success",i,o)=>{const a=i??o?.duration??this.theme.defaultDuration,l=this.theme.stacking?this.theme.maxStack:1,n="toast-"+ ++this.toastIdCounter,c={id:n,title:t,description:s??o?.description,type:e,duration:a,createdAt:Date.now(),isExiting:!1,options:o},{visibleToasts:r}=this.state,h=r.filter(t=>!t.isExiting);if(h.length>=l){const t=h.slice(l-1);for(const s of t){const t=this.timeouts.get(s.id);t&&(clearTimeout(t),this.timeouts.delete(s.id))}const s=new Set(t.map(t=>t.id));if(!this.theme.stacking)return this.setState({visibleToasts:r.map(t=>s.has(t.id)?{...t,isExiting:!0}:t)}),setTimeout(()=>{for(const s of t)this.removeToast(s.id);this.addToast(c,a)},130),n;this.setState({visibleToasts:r.filter(t=>!s.has(t.id))})}return this.addToast(c,a),n};addToast(t,s){this.setState({visibleToasts:[t,...this.state.visibleToasts.filter(t=>!t.isExiting)]}),this.scheduleTimeout(t.id,s,0),this.rescheduleAllTimeouts()}scheduleTimeout(t,s,e){const i=this.timeouts.get(t);i&&clearTimeout(i);const o=setTimeout(()=>{this.hide(t)},s*(e+1));this.timeouts.set(t,o)}rescheduleAllTimeouts(){const{visibleToasts:t}=this.state;t.forEach((t,s)=>{t.isExiting||0===s||this.scheduleTimeout(t.id,t.duration,s)})}hide=t=>{const{visibleToasts:s}=this.state,e=s.find(s=>s.id===t);if(!e||e.isExiting)return;const i=this.timeouts.get(t);i&&(clearTimeout(i),this.timeouts.delete(t)),this.setState({visibleToasts:s.map(s=>s.id===t?{...s,isExiting:!0}:s)}),setTimeout(()=>{this.removeToast(t)},350)};removeToast(t){const s=this.timeouts.get(t);s&&(clearTimeout(s),this.timeouts.delete(t)),this.setState({visibleToasts:this.state.visibleToasts.filter(s=>s.id!==t)}),this.rescheduleAllTimeouts()}updateToast=(t,s)=>{const{visibleToasts:e}=this.state,i=e.findIndex(s=>s.id===t);-1!==i&&(this.setState({visibleToasts:e.map(e=>e.id===t?{...e,...s}:e)}),void 0!==s.duration&&this.scheduleTimeout(t,s.duration,i))};hideAll=()=>{for(const t of this.timeouts.values())clearTimeout(t);this.timeouts.clear(),this.setState({visibleToasts:[]})}};
|
package/lib/commonjs/toast.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.ToastContainer=void 0;var
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.ToastContainer=void 0;var t=require("react"),e=require("react-native"),i=require("react-native-gesture-handler"),n=function(t,e){if("function"==typeof WeakMap)var i=new WeakMap,n=new WeakMap;return function(t,e){if(!e&&t&&t.__esModule)return t;var o,s,r={__proto__:null,default:t};if(null===t||"object"!=typeof t&&"function"!=typeof t)return r;if(o=e?n:i){if(o.has(t))return o.get(t);o.set(t,r)}for(const e in t)"default"!==e&&{}.hasOwnProperty.call(t,e)&&((s=(o=Object.defineProperty)&&Object.getOwnPropertyDescriptor(t,e))&&(s.get||s.set)?o(r,e,s):r[e]=t[e]);return r}(t,e)}(require("react-native-reanimated")),o=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 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,x=(t,i,n,o)=>{if(n)return"function"==typeof n?n({color:i,size:u}):n;if(o)return o({color:i,size:u});switch(t){case"success":default:return(0,l.jsx)(r.GreenCheck,{width:36,height:36,fill:i});case"error":return(0,l.jsx)(r.RedX,{width:u,height:u,fill:i});case"loading":return(0,l.jsx)(e.ActivityIndicator,{size:u,color:i});case"info":return(0,l.jsx)(r.InfoIcon,{width:u,height:u,fill:i})}},m=(0,t.memo)(({type:e,color:i,custom:o,config:s})=>{const r=(0,n.useSharedValue)(0);(0,t.useEffect)(()=>{r.value=(0,n.withTiming)(1,{duration:350,easing:n.Easing.out(n.Easing.back(1.5))})},[r]);const a=(0,n.useAnimatedStyle)(()=>({opacity:r.value,transform:[{scale:.7+.3*r.value}]}));return(0,l.jsx)(n.default.View,{style:a,children:x(e,i,o,s)})});exports.ToastContainer=()=>{const[r,u]=(0,t.useState)([]),[p,f]=(0,t.useState)(()=>a.toastStore.getTheme()),{top:g,bottom:h}=(0,o.useSafeAreaInsets)(),x=(0,t.useRef)((0,n.makeMutable)(null)),m=(0,t.useRef)((0,n.makeMutable)("bottom"===p.position)),v=(0,t.useRef)((0,n.makeMutable)(!0)),b=(0,n.useSharedValue)(!1);(0,t.useEffect)(()=>{u(a.toastStore.getState().visibleToasts);let t=null,e=null;return a.toastStore.subscribe(i=>{t=i.visibleToasts,null===e&&(e=requestAnimationFrame(()=>{t&&(u(t),t=null),e=null;const i=a.toastStore.getTheme();f(t=>t===i?t:i)}))})},[]);const T=(0,t.useMemo)(()=>{const t=new Map;let e=0;for(const i of r)t.set(i.id,i.isExiting?-1:e),i.isExiting||e++;return[...r].reverse().map(e=>({toast:e,index:t.get(e.id)??0}))},[r]),S="bottom"===p.position,j=r.find(t=>!t.isExiting),k=j?.options?.dismissible??p.dismissible;(0,t.useEffect)(()=>{m.current.value=S,v.current.value=k},[S,k]);const E=(0,t.useMemo)(()=>i.Gesture.Pan().onStart(()=>{"worklet";b.value=!1}).onUpdate(t=>{"worklet";if(!v.current.value)return;const e=x.current.value;if(!e)return;const{slot:i}=e,n=m.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);b.value=r}else{const t=60*(1-Math.exp(-r/250));i.translationY.value=n?-Math.min(t,60):Math.min(t,60),b.value=!1}}).onEnd(()=>{"worklet";if(!v.current.value)return;const t=x.current.value;if(!t)return;const{slot:e}=t,i=m.current.value;if(b.value){e.progress.value=(0,n.withTiming)(0,{duration:c,easing:d});const o=i?200:-200;e.translationY.value=(0,n.withTiming)(e.translationY.value+o,{duration:c,easing:d}),(0,s.scheduleOnRN)(t.dismiss)}else e.translationY.value=(0,n.withTiming)(0,{duration:650,easing:d})}),[b]),M=(0,t.useCallback)(t=>{x.current.value=t},[]);if(0===r.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)(e.View,{style:[w.container,C],pointerEvents:"box-none",children:T.map(({toast:t,index:e})=>(0,l.jsx)(y,{toast:t,index:e,theme:p,position:p.position,isTopToast:0===e,registerTopToast:M},t.id))})})};const v=({toast:i,index:o,theme:s,position:u,isTopToast:v,registerTopToast:y})=>{const b=(0,t.useRef)(null);null===b.current&&(b.current=(t=>{if(g.has(t))return g.get(t)??0;for(let e=0;e<5;e++)if(!h.has(e))return g.set(t,e),h.add(e),f[e].initialized=!1,f[e].wasExiting=!1,f[e].prevIndex=0,e;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,t.useRef)(i.type),[C,z]=(0,t.useState)(!1);(0,t.useEffect)(()=>()=>{(t=>{const e=g.get(t);void 0!==e&&(h.delete(e),g.delete(t),f[e].initialized=!1,f[e].wasExiting=!1,f[e].prevIndex=0)})(i.id)},[i.id]),(0,t.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,t.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,t.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,t.useEffect)(()=>{const t=setTimeout(()=>z(!0),50);return()=>clearTimeout(t)},[]);const Y="loading"===I.current&&"loading"!==i.type;I.current=i.type;const q=(0,t.useCallback)(()=>{a.toastStore.hide(i.id)},[i.id]);(0,t.useEffect)(()=>{if(v)return y({slot:S,dismiss:q}),()=>y(null)},[v,y,S,q]);const A=(0,n.useAnimatedStyle)(()=>{const t=(0,n.interpolate)(S.progress.value,[0,1],[E,0]),e=k?10*S.stackIndex.value:-10*S.stackIndex.value,i=1-.05*S.stackIndex.value,o=t+S.translationY.value+e,s=(0,n.interpolate)(S.progress.value,[0,1],[0,1]),r=k?S.translationY.value:-S.translationY.value,a=s*(r>0?(0,n.interpolate)(r,[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:a,zIndex:1e3-Math.round(S.stackIndex.value)}}),{options:R}=i,O=s.colors[i.type],V="loading"!==i.type&&(R?.showCloseButton??s.showCloseButton);return(0,l.jsxs)(n.default.View,{style:[w.toast,k?w.toastBottom:w.toastTop,{backgroundColor:O.background},s.rtl&&w.rtl,s.toastStyle,R?.style,A],children:[(0,l.jsx)(e.View,{style:w.iconContainer,children:C&&(Y?(0,l.jsx)(m,{type:i.type,color:O.accent,custom:R?.icon,config:s.icons[i.type]},i.type):x(i.type,O.accent,R?.icon,s.icons[i.type]))}),(0,l.jsxs)(e.View,{style:w.textContainer,children:[(0,l.jsx)(e.Text,{maxFontSizeMultiplier:1.35,allowFontScaling:!1,style:[w.title,{color:O.accent},s.rtl&&{textAlign:"right"},s.titleStyle,R?.titleStyle],children:i.title}),i.description&&(0,l.jsx)(e.Text,{allowFontScaling:!1,maxFontSizeMultiplier:1.35,style:[w.description,s.rtl&&{textAlign:"right"},s.descriptionStyle,R?.descriptionStyle],children:i.description})]}),V&&(0,l.jsx)(e.Pressable,{style:w.closeButton,onPress:q,hitSlop:12,children:(0,l.jsx)(r.CloseIcon,{width:20,height:20})})]})},y=(0,t.memo)(v,(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),w=e.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},rtl:{flexDirection:"row-reverse"},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";const t={position:"top",offset:0,stacking:!0,maxStack:3,dismissible:!0,showCloseButton:!0,colors:{success:{accent:"#28B770",background:"#FFFFFF"},error:{accent:"#F05964",background:"#FFFFFF"},info:{accent:"#EDBE43",background:"#FFFFFF"},loading:{accent:"#232323",background:"#FFFFFF"}},icons:{},toastStyle:{},titleStyle:{},descriptionStyle:{},defaultDuration:4e3};export const toastStore=new class{state={visibleToasts:[]};theme=t;listeners=new Set;toastIdCounter=0;timeouts=new Map;subscribe=t=>(this.listeners.add(t),()=>{this.listeners.delete(t)});emit(){for(const t of this.listeners)t(this.state)}setState(t){this.state={...this.state,...t},this.emit()}getState=()=>this.state;getTheme=()=>this.theme;setConfig=s=>{this.theme=function(s){if(!s)return t;const e={...t.colors};if(s.colors)for(const i of Object.keys(s.colors)){const o=s.colors[i];o&&(e[i]={...t.colors[i],...o})}return{position:s.position??t.position,offset:s.offset??t.offset,stacking:s.stacking??t.stacking,maxStack:s.maxStack??t.maxStack,dismissible:s.dismissible??t.dismissible,showCloseButton:s.showCloseButton??t.showCloseButton,colors:e,icons:{...t.icons,...s.icons},toastStyle:{...t.toastStyle,...s.toastStyle},titleStyle:{...t.titleStyle,...s.titleStyle},descriptionStyle:{...t.descriptionStyle,...s.descriptionStyle},defaultDuration:s.defaultDuration??t.defaultDuration}}(s)};show=(t,s,e="success",i,o)=>{const a=i??o?.duration??this.theme.defaultDuration,n=this.theme.stacking?this.theme.maxStack:1,l="toast-"+ ++this.toastIdCounter,c={id:l,title:t,description:s??o?.description,type:e,duration:a,createdAt:Date.now(),isExiting:!1,options:o},{visibleToasts:
|
|
1
|
+
"use strict";const t={position:"top",offset:0,rtl:!1,stacking:!0,maxStack:3,dismissible:!0,showCloseButton:!0,colors:{success:{accent:"#28B770",background:"#FFFFFF"},error:{accent:"#F05964",background:"#FFFFFF"},info:{accent:"#EDBE43",background:"#FFFFFF"},loading:{accent:"#232323",background:"#FFFFFF"}},icons:{},toastStyle:{},titleStyle:{},descriptionStyle:{},defaultDuration:4e3};export const toastStore=new class{state={visibleToasts:[]};theme=t;listeners=new Set;toastIdCounter=0;timeouts=new Map;subscribe=t=>(this.listeners.add(t),()=>{this.listeners.delete(t)});emit(){for(const t of this.listeners)t(this.state)}setState(t){this.state={...this.state,...t},this.emit()}getState=()=>this.state;getTheme=()=>this.theme;setConfig=s=>{this.theme=function(s){if(!s)return t;const e={...t.colors};if(s.colors)for(const i of Object.keys(s.colors)){const o=s.colors[i];o&&(e[i]={...t.colors[i],...o})}return{position:s.position??t.position,offset:s.offset??t.offset,rtl:s.rtl??t.rtl,stacking:s.stacking??t.stacking,maxStack:s.maxStack??t.maxStack,dismissible:s.dismissible??t.dismissible,showCloseButton:s.showCloseButton??t.showCloseButton,colors:e,icons:{...t.icons,...s.icons},toastStyle:{...t.toastStyle,...s.toastStyle},titleStyle:{...t.titleStyle,...s.titleStyle},descriptionStyle:{...t.descriptionStyle,...s.descriptionStyle},defaultDuration:s.defaultDuration??t.defaultDuration}}(s)};show=(t,s,e="success",i,o)=>{const a=i??o?.duration??this.theme.defaultDuration,n=this.theme.stacking?this.theme.maxStack:1,l="toast-"+ ++this.toastIdCounter,c={id:l,title:t,description:s??o?.description,type:e,duration:a,createdAt:Date.now(),isExiting:!1,options:o},{visibleToasts:r}=this.state,h=r.filter(t=>!t.isExiting);if(h.length>=n){const t=h.slice(n-1);for(const s of t){const t=this.timeouts.get(s.id);t&&(clearTimeout(t),this.timeouts.delete(s.id))}const s=new Set(t.map(t=>t.id));if(!this.theme.stacking)return this.setState({visibleToasts:r.map(t=>s.has(t.id)?{...t,isExiting:!0}:t)}),setTimeout(()=>{for(const s of t)this.removeToast(s.id);this.addToast(c,a)},130),l;this.setState({visibleToasts:r.filter(t=>!s.has(t.id))})}return this.addToast(c,a),l};addToast(t,s){this.setState({visibleToasts:[t,...this.state.visibleToasts.filter(t=>!t.isExiting)]}),this.scheduleTimeout(t.id,s,0),this.rescheduleAllTimeouts()}scheduleTimeout(t,s,e){const i=this.timeouts.get(t);i&&clearTimeout(i);const o=setTimeout(()=>{this.hide(t)},s*(e+1));this.timeouts.set(t,o)}rescheduleAllTimeouts(){const{visibleToasts:t}=this.state;t.forEach((t,s)=>{t.isExiting||0===s||this.scheduleTimeout(t.id,t.duration,s)})}hide=t=>{const{visibleToasts:s}=this.state,e=s.find(s=>s.id===t);if(!e||e.isExiting)return;const i=this.timeouts.get(t);i&&(clearTimeout(i),this.timeouts.delete(t)),this.setState({visibleToasts:s.map(s=>s.id===t?{...s,isExiting:!0}:s)}),setTimeout(()=>{this.removeToast(t)},350)};removeToast(t){const s=this.timeouts.get(t);s&&(clearTimeout(s),this.timeouts.delete(t)),this.setState({visibleToasts:this.state.visibleToasts.filter(s=>s.id!==t)}),this.rescheduleAllTimeouts()}updateToast=(t,s)=>{const{visibleToasts:e}=this.state,i=e.findIndex(s=>s.id===t);-1!==i&&(this.setState({visibleToasts:e.map(e=>e.id===t?{...e,...s}:e)}),void 0!==s.duration&&this.scheduleTimeout(t,s.duration,i))};hideAll=()=>{for(const t of this.timeouts.values())clearTimeout(t);this.timeouts.clear(),this.setState({visibleToasts:[]})}};
|
package/lib/module/toast.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{memo as t,useCallback as e,useEffect as i,useMemo as n,useRef as o,useState as
|
|
1
|
+
"use strict";import{memo as t,useCallback as e,useEffect as i,useMemo as n,useRef as o,useState as r}from"react";import{ActivityIndicator as s,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 h,interpolate as m,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=h.bezier(.25,.1,.25,1),B=Array.from({length:5},()=>({progress:v(0),translationY:v(0),stackIndex:v(0)})),A=Array.from({length:5},()=>({wasExiting:!1,prevIndex:0,initialized:!1})),F=new Map,H=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(s,{size:C,color:e});case"info":return k(z,{width:C,height:C,fill:e})}},D=t(({type:t,color:e,custom:n,config:o})=>{const r=x(0);i(()=>{r.value=y(1,{duration:350,easing:h.out(h.back(1.5))})},[r]);const s=f(()=>({opacity:r.value,transform:[{scale:.7+.3*r.value}]}));return k(g.View,{style:s,children:V(t,e,n,o)})});export const ToastContainer=()=>{const[t,s]=r([]),[a,l]=r(()=>S.getTheme()),{top:c,bottom:g}=w(),h=o(v(null)),m=o(v("bottom"===a.position)),f=o(v(!0)),T=x(!1);i(()=>{s(S.getState().visibleToasts);let t=null,e=null;return S.subscribe(i=>{t=i.visibleToasts,null===e&&(e=requestAnimationFrame(()=>{t&&(s(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(()=>{m.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=h.current.value;if(!e)return;const{slot:i}=e,n=m.current.value,o=t.translationY,r=n?o:-o,s=n?-o:o;if(r>0){const e=n?Math.min(o,180):Math.max(o,-180);i.translationY.value=e;const s=r>40||(n?t.velocityY>300:t.velocityY<-300);T.value=s}else{const t=60*(1-Math.exp(-s/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=h.current.value;if(!t)return;const{slot:e}=t,i=m.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=>{h.current.value=t},[]);if(0===t.length)return null;const A=z?g:c,F=z?{bottom:A+a.offset+2}:{top:A+a.offset+2};return k(p,{gesture:C,children:k(u,{style:[P.container,F],pointerEvents:"box-none",children:I.map(({toast:t,index:e})=>k(O,{toast:t,index:e,theme:a,position:a.position,isTopToast:0===e,registerTopToast:B},t.id))})})};const O=t(({toast:t,index:n,theme:s,position:l,isTopToast:d,registerTopToast:p})=>{const h=o(null);null===h.current&&(h.current=(t=>{if(F.has(t))return F.get(t)??0;for(let e=0;e<5;e++)if(!H.has(e))return F.set(t,e),H.add(e),A[e].initialized=!1,A[e].wasExiting=!1,A[e].prevIndex=0,e;return 0})(t.id));const v=h.current,x=B[v],w=A[v],b="bottom"===l,I=b?80:-80,z=b?100:-100,Y=o(t.type),[C,O]=r(!1);i(()=>()=>{(t=>{const e=F.get(t);void 0!==e&&(H.delete(e),F.delete(t),A[e].initialized=!1,A[e].wasExiting=!1,A[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(()=>O(!0),50);return()=>clearTimeout(t)},[]);const R="loading"===Y.current&&"loading"!==t.type;Y.current=t.type;const W=e(()=>{S.hide(t.id)},[t.id]);i(()=>{if(d)return p({slot:x,dismiss:W}),()=>p(null)},[d,p,x,W]);const q=f(()=>{const t=m(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=m(x.progress.value,[0,1],[0,1]),r=b?x.translationY.value:-x.translationY.value,s=o*(r>0?m(r,[0,130],[1,0],"clamp"):1);return{transform:[{translateY:n},{scale:i*m(Math.abs(x.translationY.value),[0,50],[1,.98],"clamp")}],opacity:s,zIndex:1e3-Math.round(x.stackIndex.value)}}),{options:L}=t,U=s.colors[t.type],G="loading"!==t.type&&(L?.showCloseButton??s.showCloseButton);return E(g.View,{style:[P.toast,b?P.toastBottom:P.toastTop,{backgroundColor:U.background},s.rtl&&P.rtl,s.toastStyle,L?.style,q],children:[k(u,{style:P.iconContainer,children:C&&(R?k(D,{type:t.type,color:U.accent,custom:L?.icon,config:s.icons[t.type]},t.type):V(t.type,U.accent,L?.icon,s.icons[t.type]))}),E(u,{style:P.textContainer,children:[k(c,{maxFontSizeMultiplier:1.35,allowFontScaling:!1,style:[P.title,{color:U.accent},s.rtl&&{textAlign:"right"},s.titleStyle,L?.titleStyle],children:t.title}),t.description&&k(c,{allowFontScaling:!1,maxFontSizeMultiplier:1.35,style:[P.description,s.rtl&&{textAlign:"right"},s.descriptionStyle,L?.descriptionStyle],children:t.description})]}),G&&k(a,{style:P.closeButton,onPress:W,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),P=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},rtl:{flexDirection:"row-reverse"},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"}});
|
|
@@ -22,6 +22,8 @@ export interface ToastTheme {
|
|
|
22
22
|
position: ToastPosition;
|
|
23
23
|
/** Extra offset from safe area edge (in addition to safe area insets) */
|
|
24
24
|
offset: number;
|
|
25
|
+
/** Enable right-to-left layout (reverses icon/text order) */
|
|
26
|
+
rtl: boolean;
|
|
25
27
|
/** Whether to show multiple toasts stacked (default: true). When false, only one toast shows at a time. */
|
|
26
28
|
stacking: boolean;
|
|
27
29
|
/** Maximum number of toasts visible at once when stacking is enabled (default: 3) */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-bread",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
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",
|