{"$schema":"https://ui.shadcn.com/schema/registry-item.json","author":"Eduardo Calvo <educlopez93@gmail.com>","css":{},"dependencies":["motion"],"description":"A SocialSelector component for SmoothUI.","devDependencies":[],"files":[{"content":"\"use client\";\n\nimport { motion, useReducedMotion } from \"motion/react\";\nimport { useState } from \"react\";\n\ntype XIconProps = React.SVGProps<SVGSVGElement> & {\n  className?: string;\n};\n\nexport const XIcon: React.FC<XIconProps> = ({ className, ...props }) => (\n  <svg\n    className={className}\n    viewBox=\"0 0 512 512\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n    {...props}\n  >\n    <title>X icon</title>\n    <path d=\"M389.2 48h70.6L305.6 224.2 487 464H345L233.7 318.6 106.5 464H35.8L200.7 275.5 26.8 48H172.4L272.9 180.9 389.2 48zM364.4 421.8h39.1L151.1 88h-42L364.4 421.8z\" />\n  </svg>\n);\n\ntype ThreadsIconProps = React.SVGProps<SVGSVGElement> & {\n  className?: string;\n};\n\nexport const ThreadsIcon: React.FC<ThreadsIconProps> = ({\n  className,\n  ...props\n}) => (\n  <svg\n    className={className}\n    viewBox=\"0 0 448 512\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n    {...props}\n  >\n    <title>Threads icon</title>\n    <path d=\"M331.5 235.7c2.2 .9 4.2 1.9 6.3 2.8c29.2 14.1 50.6 35.2 61.8 61.4c15.7 36.5 17.2 95.8-30.3 143.2c-36.2 36.2-80.3 52.5-142.6 53h-.3c-70.2-.5-124.1-24.1-160.4-70.2c-32.3-41-48.9-98.1-49.5-169.6V256v-.2C17 184.3 33.6 127.2 65.9 86.2C102.2 40.1 156.2 16.5 226.4 16h.3c70.3 .5 124.9 24 162.3 69.9c18.4 22.7 32 50 40.6 81.7l-40.4 10.8c-7.1-25.8-17.8-47.8-32.2-65.4c-29.2-35.8-73-54.2-130.5-54.6c-57 .5-100.1 18.8-128.2 54.4C72.1 146.1 58.5 194.3 58 256c.5 61.7 14.1 109.9 40.3 143.3c28 35.6 71.2 53.9 128.2 54.4c51.4-.4 85.4-12.6 113.7-40.9c32.3-32.2 31.7-71.8 21.4-95.9c-6.1-14.2-17.1-26-31.9-34.9c-3.7 26.9-11.8 48.3-24.7 64.8c-17.1 21.8-41.4 33.6-72.7 35.3c-23.6 1.3-46.3-4.4-63.9-16c-20.8-13.8-33-34.8-34.3-59.3c-2.5-48.3 35.7-83 95.2-86.4c21.1-1.2 40.9-.3 59.2 2.8c-2.4-14.8-7.3-26.6-14.6-35.2c-10-11.7-25.6-17.7-46.2-17.8H227c-16.6 0-39 4.6-53.3 26.3l-34.4-23.6c19.2-29.1 50.3-45.1 87.8-45.1h.8c62.6 .4 99.9 39.5 103.7 107.7l-.2 .2zm-156 68.8c1.3 25.1 28.4 36.8 54.6 35.3c25.6-1.4 54.6-11.4 59.5-73.2c-13.2-2.9-27.8-4.4-43.4-4.4c-4.8 0-9.6 .1-14.4 .4c-42.9 2.4-57.2 23.2-56.2 41.8l-.1 .1z\" />\n  </svg>\n);\n\ntype BskyIconProps = React.SVGProps<SVGSVGElement> & {\n  className?: string;\n};\n\nexport const BskyIcon: React.FC<BskyIconProps> = ({ className, ...props }) => (\n  <svg\n    className={className}\n    viewBox=\"0 0 512 512\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n    {...props}\n  >\n    <title>Bluesky icon</title>\n    <path d=\"M111.8 62.2C170.2 105.9 233 194.7 256 242.4c23-47.6 85.8-136.4 144.2-180.2c42.1-31.6 110.3-56 110.3 21.8c0 15.5-8.9 130.5-14.1 149.2C478.2 298 412 314.6 353.1 304.5c102.9 17.5 129.1 75.5 72.5 133.5c-107.4 110.2-154.3-27.6-166.3-62.9l0 0c-1.7-4.9-2.6-7.8-3.3-7.8s-1.6 3-3.3 7.8l0 0c-12 35.3-59 173.1-166.3 62.9c-56.5-58-30.4-116 72.5-133.5C100 314.6 33.8 298 15.7 233.1C10.4 214.4 1.5 99.4 1.5 83.9c0-77.8 68.2-53.4 110.3-21.8z\" />\n  </svg>\n);\n\nexport interface Platform {\n  domain: string;\n  icon: React.ReactNode;\n  name: string;\n  url: string;\n}\n\nconst ICON_SIZE = 36;\nconst ICON_GAP = 16;\n\nconst defaultPlatforms: Platform[] = [\n  {\n    domain: \"x.com\",\n    icon: <XIcon className=\"h-5 w-5\" />,\n    name: \"X\",\n    url: \"https://x.com/educalvolpz\",\n  },\n  {\n    domain: \"bsky.app\",\n    icon: <BskyIcon className=\"h-5 w-5\" />,\n    name: \"Bluesky\",\n    url: \"https://bsky.app/profile/educalvolpz.bsky.social\",\n  },\n  {\n    domain: \"threads.net\",\n    icon: <ThreadsIcon className=\"h-5 w-5\" />,\n    name: \"Threads\",\n    url: \"https://threads.net/@educalvolpz\",\n  },\n];\n\nexport interface SocialSelectorProps {\n  className?: string;\n  handle?: string;\n  onChange?: (platform: Platform) => void;\n  platforms?: Platform[];\n  selectedPlatform?: Platform;\n}\n\nexport default function SocialSelector({\n  platforms = defaultPlatforms,\n  handle = \"educalvolpz\",\n  selectedPlatform: controlledSelected,\n  onChange,\n  className = \"\",\n}: SocialSelectorProps) {\n  const [internalSelected, setInternalSelected] = useState<Platform>(\n    platforms[0]\n  );\n  const shouldReduceMotion = useReducedMotion();\n  const selectedPlatform = controlledSelected ?? internalSelected;\n\n  return (\n    <div className={`mx-auto my-4 w-full max-w-2xl text-center ${className}`}>\n      <div className=\"space-y-6\">\n        <div className=\"flex items-center justify-center\">\n          <div className=\"relative flex w-fit items-center justify-center gap-4\">\n            {platforms.map((platform) => (\n              <button\n                aria-label={`Select ${platform.name} platform`}\n                className={`relative z-10 cursor-pointer rounded-full p-2 transition-colors ${\n                  selectedPlatform.name === platform.name\n                    ? \"fill-foreground\"\n                    : \"fill-primary-foreground hover:bg-primary\"\n                }`}\n                key={platform.name}\n                onClick={() => {\n                  if (onChange) {\n                    onChange(platform);\n                  } else {\n                    setInternalSelected(platform);\n                  }\n                }}\n                type=\"button\"\n              >\n                {platform.icon}\n                <span className=\"sr-only\">{platform.name}</span>\n              </button>\n            ))}\n            <motion.div\n              animate={\n                shouldReduceMotion\n                  ? {}\n                  : {\n                      x:\n                        platforms.findIndex(\n                          (p) => p.name === selectedPlatform.name\n                        ) *\n                        (ICON_SIZE + ICON_GAP),\n                    }\n              }\n              className=\"absolute inset-0 z-0 h-9 w-9 rounded-full border bg-background\"\n              initial={false}\n              layoutId={shouldReduceMotion ? undefined : \"background\"}\n              transition={\n                shouldReduceMotion\n                  ? { duration: 0 }\n                  : {\n                      damping: 30,\n                      duration: 0.25,\n                      stiffness: 500,\n                      type: \"spring\" as const,\n                    }\n              }\n            />\n          </div>\n        </div>\n        <p className=\"text-md text-primary-foreground\">\n          Updates on{\" \"}\n          <span className=\"font-medium text-foreground\">\n            <motion.a\n              animate={\n                shouldReduceMotion\n                  ? { opacity: 1 }\n                  : { filter: \"blur(0px)\", opacity: 1, y: 0 }\n              }\n              exit={\n                shouldReduceMotion\n                  ? { opacity: 0, transition: { duration: 0 } }\n                  : { filter: \"blur(5px)\", opacity: 0, y: -10 }\n              }\n              href={selectedPlatform.url}\n              initial={\n                shouldReduceMotion\n                  ? { opacity: 1 }\n                  : { filter: \"blur(5px)\", opacity: 0, y: 10 }\n              }\n              key={selectedPlatform.domain}\n              rel=\"noopener noreferrer\"\n              target=\"_blank\"\n              transition={\n                shouldReduceMotion ? { duration: 0 } : { duration: 0.25 }\n              }\n            >\n              {selectedPlatform.domain}\n            </motion.a>\n          </span>\n          <br />\n          <a\n            className=\"font-medium text-foreground\"\n            href={selectedPlatform.url}\n            rel=\"noopener noreferrer\"\n            target=\"_blank\"\n          >\n            @{handle}\n          </a>\n        </p>\n      </div>\n    </div>\n  );\n}\n","path":"index.tsx","target":"components/smoothui/social-selector/index.tsx","type":"registry:ui"}],"name":"social-selector","registryDependencies":[],"title":"Social Selector","type":"registry:ui"}