UNPKG

react-native-swipe-cards-stack

Version:

A highly customizable, performant swipeable cards stack component for React Native.

141 lines (140 loc) 4.55 kB
/** * Default configuration values for the SwipeableCardsStack component */ export const DEFAULT_SWIPE_ICONS = { // New simplified icon system leftSwipeIcon: null, rightSwipeIcon: null, upSwipeIcon: null, downSwipeIcon: null, leftSwipeIconStyle: {}, rightSwipeIconStyle: {}, upSwipeIconStyle: {}, downSwipeIconStyle: {}, // Legacy support (deprecated but maintained for backward compatibility) tickIcon: null, crossIcon: null, upIcon: null, downIcon: null, leftIcon: null, rightIcon: null, // Legacy show/hide controls (deprecated) showTickIcon: false, // Changed to false by default showCrossIcon: false, // Changed to false by default showUpIcon: false, showDownIcon: false, showLeftIcon: false, showRightIcon: false, // Legacy style overrides (deprecated) tickIconStyle: {}, crossIconStyle: {}, upIconStyle: {}, downIconStyle: {}, leftIconStyle: {}, rightIconStyle: {}, // Legacy position controls (deprecated) iconPosition: 'center', customIconPosition: {}, }; export const DEFAULT_THRESHOLDS = { horizontal: 120, vertical: 120, iconDelay: 30, rotationThreshold: 15, velocity: 0.3, }; export const DEFAULT_ANIMATIONS = { duration: 300, easing: undefined, useNativeDriver: false, rotationEnabled: true, scaleEnabled: false, opacityEnabled: false, }; export const DEFAULT_GESTURES = { swipeDirections: ['left', 'right', 'up', 'down'], // All directions enabled by default enableRotation: true, enableScale: true, gestureThreshold: 10, simultaneousGestures: false, allowPartialSwipe: true, partialSwipeReturnDuration: 300, partialSwipeReturnEasing: null, }; export const DEFAULT_STACK_BEHAVIOR = { stackSize: 2, }; export const DEFAULT_CARD_STYLE = { borderRadius: 15, }; /** * Merge user props with default values */ export const mergeWithDefaults = (props) => { return { ...props, cardStyle: { ...DEFAULT_CARD_STYLE, ...props.cardStyle }, swipeIcons: { ...DEFAULT_SWIPE_ICONS, ...props.swipeIcons }, thresholds: { ...DEFAULT_THRESHOLDS, ...props.thresholds }, animations: { ...DEFAULT_ANIMATIONS, ...props.animations }, gestures: { ...DEFAULT_GESTURES, ...props.gestures }, stackBehavior: { ...DEFAULT_STACK_BEHAVIOR, ...props.stackBehavior }, }; }; /** * Utility functions for the component */ export const getCardId = (item, index, keyExtractor) => { if (keyExtractor) { return keyExtractor(item, index); } // Use index as default identifier since items can be any type (string, number, object, etc.) return index.toString(); }; export const calculateCardStyle = (relativeIndex, isActive, stackBehavior, cardStyle, activeCardStyle, inactiveCardStyle) => { const baseStyle = [cardStyle]; // cardStyle is always applied to all cards if (isActive && activeCardStyle) { baseStyle.push(activeCardStyle); } else if (!isActive && inactiveCardStyle) { baseStyle.push(inactiveCardStyle); } // Apply simple stack transformations (only basic Y offset for now) if (!isActive && relativeIndex > 0) { baseStyle.push({ transform: [{ translateY: relativeIndex * 10 }], opacity: 1 - (relativeIndex * 0.1) // Simple opacity reduction }); } return baseStyle; }; export const getDirectionFromGesture = (dx, dy, thresholds) => { const horizontalThreshold = thresholds.horizontal || 120; const verticalThreshold = thresholds.vertical || 120; // Determine primary direction based on larger displacement if (Math.abs(dx) > Math.abs(dy)) { // Horizontal movement is primary if (Math.abs(dx) > horizontalThreshold) { return dx > 0 ? 'right' : 'left'; } } else { // Vertical movement is primary if (Math.abs(dy) > verticalThreshold) { return dy > 0 ? 'down' : 'up'; } } return null; }; export const shouldShowIcon = (direction, displacement, iconDelay) => { if (!direction) return false; return Math.abs(displacement) > iconDelay; }; export const calculateIconOpacity = (displacement, iconDelay, threshold) => { const adjustedDisplacement = Math.abs(displacement) - iconDelay; if (adjustedDisplacement <= 0) return 0; const maxOpacityRange = threshold - iconDelay; return Math.min(adjustedDisplacement / maxOpacityRange, 1); };