Files
Dorod-Sky/skyvern-frontend/src/components/Flippable.tsx
2025-08-07 17:29:11 -04:00

90 lines
2.5 KiB
TypeScript

import { ReactNode, Children, useRef, useEffect } from "react";
import { cn } from "@/util/utils";
interface FlippableProps {
facing?: "front" | "back";
children: ReactNode;
className?: string;
/**
* If `true`, then the height of the content of the front, whatever it happens
* to be, is marked right before the flip-from-front-to-back takes place.
* This height is then applied to the content in the back. This synchronizes
* the front content height onto the back content height.
*
* Default is `false`.
*/
preserveFrontsideHeight?: boolean;
}
export function Flippable({
facing = "front",
children,
className,
preserveFrontsideHeight = false,
}: FlippableProps) {
const childrenArray = Children.toArray(children);
const front = childrenArray[0];
const back = childrenArray[1];
const frontRef = useRef<HTMLDivElement>(null);
const backRef = useRef<HTMLDivElement>(null);
const capturedHeightRef = useRef<number | null>(null);
useEffect(() => {
if (
preserveFrontsideHeight &&
facing === "back" &&
frontRef.current &&
backRef.current
) {
if (capturedHeightRef.current === null) {
capturedHeightRef.current = frontRef.current.offsetHeight;
}
backRef.current.style.height = `${capturedHeightRef.current}px`;
} else if (facing === "front" && backRef.current) {
backRef.current.style.height = "auto";
capturedHeightRef.current = null;
}
}, [facing, preserveFrontsideHeight]);
return (
<div className={className} style={{ perspective: "1000px" }}>
<div
className={cn(
"transition-transform duration-700",
"transform-style-preserve-3d",
{
"rotate-y-180": facing === "back",
},
)}
style={{
transformStyle: "preserve-3d",
transform: facing === "back" ? "rotateY(180deg)" : "rotateY(0deg)",
transition: "transform 0.7s cubic-bezier(0.68, -0.55, 0.265, 1.55)",
}}
>
<div
ref={frontRef}
style={{
backfaceVisibility: "hidden",
WebkitBackfaceVisibility: "hidden",
}}
>
{front}
</div>
<div
ref={backRef}
className="absolute inset-0 flex items-start justify-start"
style={{
backfaceVisibility: "hidden",
WebkitBackfaceVisibility: "hidden",
transform: "rotateY(180deg)",
}}
>
{back}
</div>
</div>
</div>
);
}