Files
jrshikoku/components/Menu/Carousel/SortGridCard.tsx

98 lines
2.6 KiB
TypeScript

import React, { useEffect } from "react";
import { useItemContext } from "react-native-sortables";
import Animated, {
interpolate,
useAnimatedStyle,
useSharedValue,
withDelay,
withSpring,
} 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;
isExiting: boolean;
exitDelay: number;
onPress?: () => void;
};
/** カルーセル中央 → グリッドセルへ飛ぶアニメーション付きカード */
export const SortGridCard = React.memo(function SortGridCard({
item,
cellW,
cellH,
startX,
startY,
exitX,
exitY,
startScale,
isExiting,
exitDelay,
onPress,
}: Props) {
const { activationAnimationProgress } = useItemContext();
const tx = useSharedValue(startX);
const ty = useSharedValue(startY);
const sc = useSharedValue(startScale);
// 入場: カルーセル位置からグリッドセル位置へ
useEffect(() => {
tx.value = withSpring(0, { damping: 16, stiffness: 110 });
ty.value = withSpring(0, { damping: 16, stiffness: 110 });
sc.value = withSpring(1, { damping: 16, stiffness: 110 });
}, []);
// 退場: グリッドセル位置からカルーセル位置へ戻る
useEffect(() => {
if (!isExiting) return;
tx.value = withDelay(exitDelay, withSpring(exitX, { damping: 16, stiffness: 110 }));
ty.value = withDelay(exitDelay, withSpring(exitY, { damping: 16, stiffness: 110 }));
sc.value = withDelay(exitDelay, withSpring(startScale, { damping: 16, stiffness: 110 }));
}, [isExiting]);
const animStyle = useAnimatedStyle(() => {
const p = activationAnimationProgress.value;
return {
opacity: 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 (
<Animated.View
style={[
{
width: cellW,
height: cellH,
shadowColor: "#000",
shadowOffset: { width: 0, height: 4 },
},
animStyle,
]}
>
<GridMiniSign
item={item}
width={cellW}
height={cellH}
onPress={onPress}
/>
</Animated.View>
);
});