{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "image-expand-to-fullscreen",
  "title": "Image Expand To Fullscreen",
  "description": "An image lifts out of a feed post and morphs into a fullscreen editor with toolbars sliding in.",
  "dependencies": [
    "remotion"
  ],
  "files": [
    {
      "path": "registry/bases/editframe/components/image-expand-to-fullscreen/index.tsx",
      "content": "\"use client\";\n\nimport { Timegroup } from \"@editframe/react\";\nimport type { CSSProperties } from \"react\";\n\nconst FONT_FAMILY =\n  \"var(--font-geist-sans), -apple-system, BlinkMacSystemFont, sans-serif\";\n\nexport interface ImageExpandRect {\n  top: number;\n  left: number;\n  width: number;\n  height: number;\n}\n\nexport interface ImageExpandToFullscreenProps {\n  from?: ImageExpandRect;\n  to?: ImageExpandRect;\n  borderRadiusFrom?: number;\n  borderRadiusTo?: number;\n  morphAt?: number;\n  imageColorA?: string;\n  imageColorB?: string;\n  imageColorC?: string;\n  feedBackground?: string;\n  editorBackground?: string;\n  accent?: string;\n  postAuthor?: string;\n  postBody?: string;\n  speed?: number;\n  fps?: number;\n  durationInFrames?: number;\n  width?: number;\n  height?: number;\n  className?: string;\n}\n\nconst DEFAULT_FROM: ImageExpandRect = {\n  height: 200,\n  left: 460,\n  top: 280,\n  width: 360,\n};\n\nconst DEFAULT_TO: ImageExpandRect = {\n  height: 480,\n  left: 200,\n  top: 120,\n  width: 880,\n};\n\nexport const ImageExpandToFullscreen = ({\n  from = DEFAULT_FROM,\n  to = DEFAULT_TO,\n  borderRadiusFrom = 12,\n  borderRadiusTo = 16,\n  morphAt = 30,\n  imageColorA = \"#ff6b6b\",\n  imageColorB = \"#845ec2\",\n  imageColorC = \"#4d8dff\",\n  feedBackground = \"#f4f4f5\",\n  editorBackground = \"#0a0a0a\",\n  accent = \"#fafafa\",\n  postAuthor = \"Maya Larsson\",\n  postBody = \"Sunset over the old harbor — color graded straight out of camera.\",\n  speed = 1,\n  fps = 30,\n  durationInFrames = 150,\n  width = 1280,\n  height = 720,\n  className,\n}: ImageExpandToFullscreenProps) => {\n  const safeSpeed = Math.max(0.01, speed);\n  const durationMs = (durationInFrames / fps) * 1000;\n  const frameMs = 1000 / fps;\n  const morphMs = ((durationInFrames / fps) * 1000) / safeSpeed;\n\n  const containerStyle: CSSProperties = {\n    fontFamily: FONT_FAMILY,\n    height,\n    overflow: \"hidden\",\n    position: \"relative\",\n    width,\n  };\n\n  const imageGradient = `linear-gradient(135deg, ${imageColorA}, ${imageColorB}, ${imageColorC})`;\n\n  return (\n    <Timegroup\n      className={className}\n      duration={`${durationMs}ms`}\n      mode=\"fixed\"\n      style={containerStyle}\n    >\n      <>\n        <style>{`\n          @keyframes framecn-img-expand-feed {\n            from { opacity: 1; }\n            to { opacity: 0; }\n          }\n          @keyframes framecn-img-expand-editor {\n            from { opacity: 0; }\n            to { opacity: 1; }\n          }\n          @keyframes framecn-img-expand-img {\n            0% { left: ${from.left}px; top: ${from.top}px; width: ${from.width}px; height: ${from.height}px; border-radius: ${borderRadiusFrom}px; }\n            100% { left: ${to.left}px; top: ${to.top}px; width: ${to.width}px; height: ${to.height}px; border-radius: ${borderRadiusTo}px; }\n          }\n          @keyframes framecn-img-expand-toolbar {\n            from { opacity: 0; transform: translateY(-100%); }\n            to { opacity: 1; transform: translateY(0); }\n          }\n        `}</style>\n\n        {/* Feed background */}\n        <div\n          style={{\n            animation: `framecn-img-expand-feed ${morphMs * 0.5}ms ease-out ${morphAt * frameMs}ms forwards`,\n            background: feedBackground,\n            inset: 0,\n            position: \"absolute\",\n          }}\n        />\n\n        {/* Editor background */}\n        <div\n          style={{\n            animation: `framecn-img-expand-editor ${morphMs * 0.5}ms ease-in ${morphAt * frameMs}ms backwards`,\n            background: editorBackground,\n            inset: 0,\n            position: \"absolute\",\n          }}\n        />\n\n        {/* Fake post card */}\n        <div\n          style={{\n            animation: `framecn-img-expand-feed ${morphMs * 0.5}ms ease-out ${morphAt * frameMs}ms forwards`,\n            background: \"#ffffff\",\n            borderRadius: 20,\n            boxShadow: \"0 30px 80px rgba(15, 15, 25, 0.08)\",\n            display: \"flex\",\n            flexDirection: \"column\",\n            gap: 16,\n            left: 380,\n            opacity: 1,\n            padding: 24,\n            position: \"absolute\",\n            top: 140,\n            width: 520,\n          }}\n        >\n          <div style={{ alignItems: \"center\", display: \"flex\", gap: 12 }}>\n            <div\n              style={{\n                background: imageGradient,\n                borderRadius: 999,\n                height: 44,\n                width: 44,\n              }}\n            />\n            <div style={{ display: \"flex\", flexDirection: \"column\", gap: 2 }}>\n              <div\n                style={{\n                  color: \"#0a0a0a\",\n                  fontSize: 15,\n                  fontWeight: 600,\n                  letterSpacing: \"-0.005em\",\n                }}\n              >\n                {postAuthor}\n              </div>\n              <div style={{ color: \"#71717a\", fontSize: 12 }}>2h ago</div>\n            </div>\n          </div>\n          <div\n            style={{\n              color: \"#27272a\",\n              fontSize: 14,\n              lineHeight: 1.5,\n            }}\n          >\n            {postBody}\n          </div>\n          <div\n            style={{\n              background: \"transparent\",\n              borderRadius: 12,\n              height: 200,\n              width: \"100%\",\n            }}\n          />\n          <div style={{ display: \"flex\", gap: 16 }}>\n            {[0, 1, 2].map((i) => (\n              <div\n                key={i}\n                style={{\n                  background: \"#f4f4f5\",\n                  borderRadius: 8,\n                  height: 28,\n                  width: 28,\n                }}\n              />\n            ))}\n          </div>\n        </div>\n\n        {/* Morphing image */}\n        <div\n          style={{\n            animation: `framecn-img-expand-img ${morphMs}ms cubic-bezier(0.16, 1, 0.3, 1) ${morphAt * frameMs}ms backwards`,\n            background: imageGradient,\n            boxShadow:\n              \"0 40px 100px rgba(0,0,0,0.55), 0 0 0 1px rgba(255,255,255,0.06)\",\n            overflow: \"hidden\",\n            position: \"absolute\",\n          }}\n        />\n\n        {/* Top toolbar */}\n        <div\n          style={{\n            WebkitBackdropFilter: \"blur(20px)\",\n            alignItems: \"center\",\n            animation: `framecn-img-expand-toolbar ${morphMs * 0.5}ms cubic-bezier(0.16, 1, 0.3, 1) ${morphAt * frameMs + morphMs * 0.5}ms backwards`,\n            backdropFilter: \"blur(20px)\",\n            background: \"rgba(15, 15, 18, 0.6)\",\n            borderBottom: \"1px solid rgba(255,255,255,0.06)\",\n            display: \"flex\",\n            height: 64,\n            justifyContent: \"space-between\",\n            left: 0,\n            padding: \"0 24px\",\n            position: \"absolute\",\n            right: 0,\n            top: 0,\n          }}\n        >\n          <div style={{ alignItems: \"center\", display: \"flex\", gap: 12 }}>\n            <div\n              style={{\n                background: \"rgba(255,255,255,0.08)\",\n                borderRadius: 8,\n                height: 32,\n                width: 32,\n              }}\n            />\n            <div\n              style={{\n                color: accent,\n                fontSize: 14,\n                fontWeight: 500,\n                letterSpacing: \"-0.005em\",\n              }}\n            >\n              Editor\n            </div>\n          </div>\n          <div style={{ display: \"flex\", gap: 10 }}>\n            {[0, 1, 2, 3].map((i) => (\n              <div\n                key={i}\n                style={{\n                  background: \"rgba(255,255,255,0.06)\",\n                  borderRadius: 8,\n                  height: 32,\n                  width: 32,\n                }}\n              />\n            ))}\n          </div>\n        </div>\n\n        {/* Bottom toolbar */}\n        <div\n          style={{\n            WebkitBackdropFilter: \"blur(20px)\",\n            alignItems: \"center\",\n            animation: `framecn-img-expand-toolbar ${morphMs * 0.5}ms cubic-bezier(0.16, 1, 0.3, 1) ${morphAt * frameMs + morphMs * 0.5}ms backwards`,\n            backdropFilter: \"blur(20px)\",\n            background: \"rgba(15, 15, 18, 0.6)\",\n            borderTop: \"1px solid rgba(255,255,255,0.06)\",\n            bottom: 0,\n            display: \"flex\",\n            gap: 14,\n            height: 80,\n            justifyContent: \"center\",\n            left: 0,\n            padding: \"0 24px\",\n            position: \"absolute\",\n            right: 0,\n          }}\n        >\n          {[0, 1, 2, 3, 4, 5].map((i) => (\n            <div\n              key={i}\n              style={{\n                background: i === 2 ? accent : \"rgba(255,255,255,0.06)\",\n                border: \"1px solid rgba(255,255,255,0.08)\",\n                borderRadius: 12,\n                height: 44,\n                width: 44,\n              }}\n            />\n          ))}\n        </div>\n      </>\n    </Timegroup>\n  );\n};\n",
      "type": "registry:component",
      "target": "components/framecn/image-expand-to-fullscreen.tsx"
    }
  ],
  "type": "registry:component"
}