import React, { useEffect } from "react"; import { useItemContext } from "react-native-sortables"; import Animated, { Easing, interpolate, useAnimatedStyle, useSharedValue, withDelay, withTiming, } from "react-native-reanimated"; import { GridMiniSign } from "./GridMiniSign"; type Props = { item: any; cellW: number; cellH: number; startX: number; startY: number; exitX: number; exitY: number; startScale: number; isCurrentCard: boolean; isExiting: boolean; exitDelay: number; onPress?: () => void; }; const EASE_OUT = Easing.out(Easing.cubic); const DURATION = 320; /** グリッドセルへのスライド+スケールアニメーション付きカード */ export const SortGridCard = React.memo(function SortGridCard({ item, cellW, cellH, startX, startY, exitX, exitY, startScale, isCurrentCard, isExiting, exitDelay, onPress, }: Props) { const { activationAnimationProgress } = useItemContext(); // 現在選択中のカードはカルーセル位置から、それ以外は近距離からスライド const initX = isCurrentCard ? startX : startX * 0.35; const initY = isCurrentCard ? startY : startY * 0.35; const initScale = isCurrentCard ? Math.min(startScale, 1.5) : Math.min(startScale, 1.15); const tx = useSharedValue(initX); const ty = useSharedValue(initY); const sc = useSharedValue(initScale); const opacity = useSharedValue(0); // 入場 useEffect(() => { const cfg = { duration: DURATION, easing: EASE_OUT }; tx.value = withTiming(0, cfg); ty.value = withTiming(0, cfg); sc.value = withTiming(1, cfg); opacity.value = withTiming(1, { duration: 180, easing: EASE_OUT }); }, []); // 退場 useEffect(() => { if (!isExiting) return; const cfg = { duration: DURATION, easing: EASE_OUT }; const toX = isCurrentCard ? exitX : exitX * 0.35; const toY = isCurrentCard ? exitY : exitY * 0.35; tx.value = withDelay(exitDelay, withTiming(toX, cfg)); ty.value = withDelay(exitDelay, withTiming(toY, cfg)); sc.value = withDelay(exitDelay, withTiming(initScale, cfg)); opacity.value = withDelay(exitDelay, withTiming(0, { duration: 150, easing: EASE_OUT })); }, [isExiting]); const animStyle = useAnimatedStyle(() => { const p = activationAnimationProgress.value; return { opacity: opacity.value * interpolate(p, [0, 1], [1, 0.85]), shadowOpacity: interpolate(p, [0, 1], [0, 0.4]), shadowRadius: interpolate(p, [0, 1], [0, 10]), elevation: interpolate(p, [0, 1], [1, 12]), transform: [ { translateX: tx.value }, { translateY: ty.value }, { scale: sc.value * interpolate(p, [0, 1], [1, 1.06]) }, ] as any, }; }); return ( ); });