import { StyleSheet, View, type ImageSourcePropType } from 'react-native'; import React, { useMemo, useState } from 'react'; import { ConfettiItemFall, ConfettiItemTumble, } from './components/ConfettiItem'; import Circle from './components/Particles/Circle'; import Polygon from './components/Particles/Polygon'; import Polyline from './components/Particles/Polyline'; import Square from './components/Particles/Square'; import Star from './components/Particles/Star'; import Triangle from './components/Particles/Triangle'; const Confetti = ({ count = 50, start, stop, speed = 3500, itemSize = 12, svgs = [ , , , , , , ], images, type, fromCenter, testID, }: { count?: number; // start and stop are the y-axis values for the confetti to start and stop // start is default to the height of the container // stop is default to 0, which is the top of the container start?: number; stop?: number; speed?: number; itemSize?: number; svgs?: any[]; images?: ImageSourcePropType[]; type?: 'tumble' | 'fall'; fromCenter?: boolean; testID?: string; }) => { const [layout, setLayout] = useState<{ width: number; height: number; } | null>(null); const maxCount = useMemo(() => (count > 100 ? 100 : count), [count]); const arrayOfConfettis = useMemo( () => Array.from({ length: maxCount }, (_, i) => i), [maxCount] ); const ConfettiElement = type === 'fall' ? ConfettiItemFall : ConfettiItemTumble; // If start is 0 and stop is not defined, set stop to layout height // This is to prevent confetti from staying stuck at the top of the screen if (start === 0 && !stop) { stop = layout?.height; } // if stop is is at the bottom of the screen and start is not defined, set start to 0 // This is to prevent confetti from staying stuck at the bottom of the screen if (stop && layout?.height) { if (stop >= layout.height && !start) { start = 0; } } if (images && images?.length >= 1) { return ( { const { width, height } = event.nativeEvent.layout; setLayout({ width, height, }); }} style={styles.confettiView} testID={testID} > {layout ? arrayOfConfettis.map((i) => { const imgIdx = images[i % images.length]; return ( ); }) : null} ); } if (svgs && svgs?.length >= 1) { return ( { const { width, height } = event.nativeEvent.layout; setLayout({ width, height, }); }} style={styles.confettiView} testID={testID} > {layout ? arrayOfConfettis.map((i) => { const svgIdx = svgs[i % svgs.length]; return ( ); }) : null} ); } return null; }; export default React.memo(Confetti); const styles = StyleSheet.create({ confettiView: { height: '100%', width: '100%', flexDirection: 'row', }, });