diff --git a/skyvern-frontend/src/components/Flippable.tsx b/skyvern-frontend/src/components/Flippable.tsx new file mode 100644 index 00000000..d6bb2c14 --- /dev/null +++ b/skyvern-frontend/src/components/Flippable.tsx @@ -0,0 +1,89 @@ +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(null); + const backRef = useRef(null); + const capturedHeightRef = useRef(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 ( +
+
+
+ {front} +
+
+ {back} +
+
+
+ ); +}