{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "macbook-keyboard",
  "title": "Macbook Keyboard",
  "description": "Interactive animated MacBook keyboard component.",
  "dependencies": [
    "react",
    "@tabler/icons-react",
    "motion"
  ],
  "files": [
    {
      "path": "registry/gammaui/macbook-keyboard.tsx",
      "content": "\"use client\"\n\nimport React, { memo, useEffect, useState } from \"react\"\nimport {\n  ArrowDownIcon,\n  ArrowLeftIcon,\n  ArrowRightIcon,\n  ArrowUpIcon,\n  ChevronUpIcon,\n  CommandIcon,\n  DotIcon,\n  GlobeIcon,\n  LayoutPanelLeft,\n  MicIcon,\n  MoonIcon,\n  OptionIcon,\n  PauseIcon,\n  SearchIcon,\n  SkipBackIcon,\n  SkipForwardIcon,\n  SunDimIcon,\n  SunIcon,\n  Volume1Icon,\n  Volume2Icon,\n  VolumeIcon,\n} from \"lucide-react\"\nimport { motion } from \"motion/react\"\n\nimport { cn } from \"../lib/utils\"\n\nconst iconSize = 12\n\ntype CustomKeyType = \"FingerPrintKey\" | \"ArrowKeys\"\n\ninterface IconKeyboardKeyProps {\n  icon: string | React.ReactNode\n  text?: string | React.ReactNode\n  className?: string\n  isSingleKey?: boolean\n  custom?: CustomKeyType\n  index?: number\n  rowIndex?: number\n  isLastRow?: boolean\n  keySize?: number\n  transparentKey?: boolean\n  glowColor?: string\n  pressedKey: string | null\n}\n\ninterface MacBookKeyboardSvgProps {\n  transparentKey?: boolean\n  keySize?: number\n  glowColor?: string\n}\n\ntype KeyRowDataProps = Omit<IconKeyboardKeyProps, \"pressedKey\">\n\nconst keyMap: Record<string, string> = {\n  Escape: \"esc\",\n  F1: \"F1\",\n  F2: \"F2\",\n  F3: \"F3\",\n  F4: \"F4\",\n  F5: \"F5\",\n  F6: \"F6\",\n  F7: \"F7\",\n  F8: \"F8\",\n  F9: \"F9\",\n  F10: \"F10\",\n  F11: \"F11\",\n  F12: \"F12\",\n  \"`\": \"`\",\n  \"1\": \"1\",\n  \"2\": \"2\",\n  \"3\": \"3\",\n  \"4\": \"4\",\n  \"5\": \"5\",\n  \"6\": \"6\",\n  \"7\": \"7\",\n  \"8\": \"8\",\n  \"9\": \"9\",\n  \"0\": \"0\",\n  \"-\": \"-\",\n  \"=\": \"=\",\n  Backspace: \"delete\",\n  Tab: \"tab\",\n  q: \"Q\",\n  w: \"W\",\n  e: \"E\",\n  r: \"R\",\n  t: \"T\",\n  y: \"Y\",\n  u: \"U\",\n  i: \"I\",\n  o: \"O\",\n  p: \"P\",\n  \"[\": \"[\",\n  \"]\": \"]\",\n  \"\\\\\": \"/\",\n  CapsLock: \"caps lock\",\n  a: \"A\",\n  s: \"S\",\n  d: \"D\",\n  f: \"F\",\n  g: \"G\",\n  h: \"H\",\n  j: \"J\",\n  k: \"K\",\n  l: \"L\",\n  \";\": \";\",\n  \"'\": \"'\",\n  Enter: \"return\",\n  Shift: \"shift\",\n  z: \"Z\",\n  x: \"X\",\n  c: \"C\",\n  v: \"V\",\n  b: \"B\",\n  n: \"N\",\n  m: \"M\",\n  \",\": \",\",\n  \".\": \".\",\n  \"/\": \"/\",\n  Control: \"control\",\n  Alt: \"option\",\n  Meta: \"command\",\n  \" \": \"\",\n  ArrowUp: \"ArrowUp\",\n  ArrowDown: \"ArrowDown\",\n  ArrowLeft: \"ArrowLeft\",\n  ArrowRight: \"ArrowRight\",\n}\n\nconst MacBookKeyboard = memo(\n  ({\n    transparentKey = true,\n    keySize = 40,\n    glowColor = \"#f43f5d\",\n  }: MacBookKeyboardSvgProps) => {\n    const [pressedKey, setPressedKey] = useState<string | null>(null)\n\n    useEffect(() => {\n      const handleKeyDown = (event: KeyboardEvent) => {\n        const mappedKey = keyMap[event.key]\n        if (mappedKey !== undefined) {\n          setPressedKey(mappedKey)\n        }\n      }\n\n      const handleKeyUp = () => {\n        setPressedKey(null)\n      }\n\n      window.addEventListener(\"keydown\", handleKeyDown)\n      window.addEventListener(\"keyup\", handleKeyUp)\n\n      return () => {\n        window.removeEventListener(\"keydown\", handleKeyDown)\n        window.removeEventListener(\"keyup\", handleKeyUp)\n      }\n    }, [])\n\n    return (\n      <div className=\"card-color flex w-full flex-col gap-1 rounded-[3px] p-2\">\n        {keysData.map((row, rowIndex) => {\n          return (\n            <div key={rowIndex} className=\"flex flex-row gap-1\">\n              {row.map((item, index) => {\n                if (item.custom === \"FingerPrintKey\") {\n                  return (\n                    <FingerPrintKey\n                      key={index}\n                      index={index}\n                      rowIndex={rowIndex}\n                      keySize={keySize}\n                      transparentKey={transparentKey}\n                    />\n                  )\n                }\n\n                if (item.custom === \"ArrowKeys\") {\n                  return (\n                    <ArrowKeys\n                      key={index}\n                      index={index}\n                      rowIndex={rowIndex}\n                      pressedKey={pressedKey}\n                      glowColor={glowColor}\n                    />\n                  )\n                }\n\n                return (\n                  <IconKeyboardKey\n                    key={index}\n                    index={index}\n                    rowIndex={rowIndex}\n                    text={item.text}\n                    icon={item.icon}\n                    className={item.className}\n                    isSingleKey={item.isSingleKey}\n                    isLastRow={rowIndex === keysData.length - 1}\n                    keySize={keySize}\n                    transparentKey={transparentKey}\n                    glowColor={glowColor}\n                    pressedKey={pressedKey}\n                  />\n                )\n              })}\n            </div>\n          )\n        })}\n      </div>\n    )\n  }\n)\n\nMacBookKeyboard.displayName = \"MacBookKeyboard\"\n\nconst IconKeyboardKey = memo(\n  ({\n    icon,\n    text,\n    className,\n    isSingleKey,\n    index = 0,\n    rowIndex = 0,\n    isLastRow,\n    keySize,\n    transparentKey,\n    glowColor,\n    pressedKey,\n  }: IconKeyboardKeyProps) => {\n    const isText = typeof text === \"string\"\n    const shouldGlow = isText && pressedKey === text\n\n    return (\n      <motion.div\n        variants={{\n          initial: { borderColor: \"#212121\" },\n          animate: {\n            borderColor: [\"#212121\", \"#383838\", \"#212121\"],\n          },\n        }}\n        initial=\"initial\"\n        animate=\"animate\"\n        transition={{\n          duration: 0.8,\n          ease: \"easeInOut\",\n          delay: index * 0.1 + rowIndex * 0.12,\n        }}\n        style={{\n          width: `${keySize}px`,\n          height: `${keySize}px`,\n          minWidth: `${keySize}px`,\n          flexBasis: `${keySize}px`,\n          color: shouldGlow ? `${glowColor}50` : \"#212121\",\n        }}\n        className={cn(\n          className,\n          shouldGlow && \"animate-[6000ms]\",\n          \"group border-border/80 relative flex flex-col items-center justify-center gap-1.5 rounded-[3px] border border-x border-t-[1.5px] border-b-[0.1px] px-2 shadow-[inset_0px_0px_15px_rgba(0,0,0,0.2)] duration-200 select-none first:items-start last:items-end active:scale-[0.98]!\",\n          transparentKey ? \"bg-transparent\" : \"bg-[#121214]\"\n        )}\n      >\n        {!isSingleKey && (\n          <div className=\"text-muted-foreground/70 group-hover:text-muted-foreground mt-0.5 h-[10px] w-[10px] text-center text-xs font-light duration-200\">\n            {icon}\n          </div>\n        )}\n        <div\n          style={{\n            color: shouldGlow ? glowColor : \"\",\n            textShadow: shouldGlow ? `0 0 10px ${glowColor}` : \"\",\n          }}\n          className={cn(\n            isLastRow && \"text-[8px]!\",\n            isSingleKey ? \"text-sm\" : \"text-xs\",\n            \"dark:text-muted-foreground/70 text-center text-white duration-200 group-hover:text-white/60\"\n          )}\n        >\n          {text}\n        </div>\n      </motion.div>\n    )\n  }\n)\n\nIconKeyboardKey.displayName = \"IconKeyboardKey\"\n\nconst FingerPrintKey = memo(\n  ({\n    index,\n    rowIndex,\n    keySize,\n    transparentKey,\n  }: {\n    index: number\n    rowIndex: number\n    keySize: number\n    transparentKey: boolean\n  }) => {\n    return (\n      <motion.div\n        variants={{\n          initial: { borderColor: \"#212121\" },\n          animate: {\n            borderColor: [\"#212121\", \"#383838\", \"#212121\"],\n          },\n        }}\n        initial=\"initial\"\n        animate=\"animate\"\n        transition={{\n          duration: 0.6,\n          ease: \"easeInOut\",\n          delay: index * 0.1 + rowIndex * 0.12,\n        }}\n        style={{\n          width: `${keySize}px`,\n          height: `${keySize}px`,\n          minWidth: `${keySize}px`,\n        }}\n        className={cn(\n          \"group border-border/80 relative flex flex-col items-center justify-center gap-1.5 rounded-[3px] border border-x border-t-[1.5px] border-b-[0.1px] shadow-[inset_0px_0px_15px_rgba(0,0,0,0.2)] duration-200\",\n          transparentKey ? \"bg-transparent\" : \"bg-[#121214]\"\n        )}\n      >\n        <div className=\"bg-muted/20 group-hover:bg-muted/35 h-8 w-8 rounded-full shadow-[inset_0px_0px_2px_rgba(0,0,0,0.6)] duration-200\" />\n      </motion.div>\n    )\n  }\n)\n\nFingerPrintKey.displayName = \"FingerPrintKey\"\n\nconst ArrowKeys = memo(\n  ({\n    index,\n    rowIndex,\n    pressedKey,\n    glowColor,\n  }: {\n    index: number\n    rowIndex: number\n    pressedKey: string | null\n    glowColor: string\n  }) => {\n    return (\n      <div className=\"flex flex-row gap-1\">\n        <ArrowKey\n          index={index}\n          rowIndex={rowIndex}\n          icon={<ArrowLeftIcon size={iconSize} />}\n          keyName=\"ArrowLeft\"\n          pressedKey={pressedKey}\n          glowColor={glowColor}\n          className=\"h-1/2! translate-y-5 items-center!\"\n        />\n        <div className=\"flex h-10 flex-col\">\n          <ArrowKey\n            index={index}\n            rowIndex={rowIndex}\n            icon={<ArrowUpIcon size={iconSize} />}\n            keyName=\"ArrowUp\"\n            pressedKey={pressedKey}\n            glowColor={glowColor}\n            className=\"h-1/2! items-center! rounded-b-none!\"\n          />\n          <ArrowKey\n            index={index}\n            rowIndex={rowIndex}\n            icon={<ArrowDownIcon size={iconSize} />}\n            keyName=\"ArrowDown\"\n            pressedKey={pressedKey}\n            glowColor={glowColor}\n            className=\"h-1/2! items-center! rounded-t-none!\"\n          />\n        </div>\n        <ArrowKey\n          index={index}\n          rowIndex={rowIndex}\n          icon={<ArrowRightIcon size={iconSize} />}\n          keyName=\"ArrowRight\"\n          pressedKey={pressedKey}\n          glowColor={glowColor}\n          className=\"h-1/2! translate-y-5 items-center!\"\n        />\n      </div>\n    )\n  }\n)\n\nArrowKeys.displayName = \"ArrowKeys\"\n\nconst ArrowKey = memo(\n  ({\n    index,\n    rowIndex,\n    icon,\n    keyName,\n    pressedKey,\n    glowColor,\n    className,\n  }: {\n    index: number\n    rowIndex: number\n    icon: React.ReactNode\n    keyName: string\n    pressedKey: string | null\n    glowColor: string\n    className?: string\n  }) => {\n    const shouldGlow = pressedKey === keyName\n\n    return (\n      <motion.div\n        variants={{\n          initial: { borderColor: \"#212121\" },\n          animate: {\n            borderColor: [\"#212121\", \"#383838\", \"#212121\"],\n          },\n        }}\n        initial=\"initial\"\n        animate=\"animate\"\n        transition={{\n          duration: 0.8,\n          ease: \"easeInOut\",\n          delay: index * 0.1 + rowIndex * 0.12,\n        }}\n        className={cn(\n          className,\n          \"group border-border/80 relative flex flex-col items-center justify-center gap-1.5 rounded-[3px] border border-x border-t-[1.5px] border-b-[0.1px] bg-transparent px-2 shadow-[inset_0px_0px_15px_rgba(0,0,0,0.2)] duration-200 select-none\"\n        )}\n      >\n        <div\n          style={{\n            color: shouldGlow ? glowColor : \"\",\n            filter: shouldGlow ? `drop-shadow(0 0 8px ${glowColor})` : \"\",\n          }}\n          className=\"text-muted-foreground/70 text-center duration-200\"\n        >\n          {icon}\n        </div>\n      </motion.div>\n    )\n  }\n)\n\nArrowKey.displayName = \"ArrowKey\"\n\nexport { MacBookKeyboard }\n\nconst firstRowData: KeyRowDataProps[] = [\n  {\n    icon: null,\n    text: \"esc\",\n    className: \"!basis-full\",\n  },\n  {\n    icon: <SunDimIcon size={iconSize} />,\n    text: \"F1\",\n  },\n  {\n    icon: <SunIcon size={iconSize} />,\n    text: \"F2\",\n  },\n  {\n    icon: <LayoutPanelLeft size={iconSize} />,\n    text: \"F3\",\n  },\n  {\n    icon: <SearchIcon size={iconSize} />,\n    text: \"F4\",\n  },\n  {\n    icon: <MicIcon size={iconSize} />,\n    text: \"F5\",\n  },\n  {\n    icon: <MoonIcon size={iconSize} />,\n    text: \"F6\",\n  },\n  {\n    icon: <SkipBackIcon size={iconSize} />,\n    text: \"F7\",\n  },\n  {\n    icon: <PauseIcon size={iconSize} />,\n    text: \"F8\",\n  },\n  {\n    icon: <SkipForwardIcon size={iconSize} />,\n    text: \"F9\",\n  },\n  {\n    icon: <VolumeIcon size={iconSize} />,\n    text: \"F10\",\n  },\n  {\n    icon: <Volume1Icon size={iconSize} />,\n    text: \"F11\",\n  },\n  {\n    icon: <Volume2Icon size={iconSize} />,\n    text: \"F12\",\n  },\n  {\n    custom: \"FingerPrintKey\",\n    icon: null,\n  },\n]\n\nconst secondRowData: KeyRowDataProps[] = [\n  {\n    icon: \"~\",\n    text: \"`\",\n    className: \"first:!items-center\",\n  },\n  {\n    icon: \"!\",\n    text: \"1\",\n  },\n  {\n    icon: \"@\",\n    text: \"2\",\n  },\n  {\n    icon: \"#\",\n    text: \"3\",\n  },\n  {\n    icon: \"$\",\n    text: \"4\",\n  },\n  {\n    icon: \"%\",\n    text: \"5\",\n  },\n  {\n    icon: \"^\",\n    text: \"6\",\n  },\n  {\n    icon: \"&\",\n    text: \"7\",\n  },\n  {\n    icon: \"*\",\n    text: \"8\",\n  },\n  {\n    icon: \"(\",\n    text: \"9\",\n  },\n  {\n    icon: \")\",\n    text: \"0\",\n  },\n  {\n    icon: \"_\",\n    text: \"-\",\n  },\n  {\n    icon: \"+\",\n    text: \"=\",\n  },\n  {\n    icon: null,\n    text: \"delete\",\n    className: \"!basis-full\",\n  },\n]\n\nconst thirdRowData: KeyRowDataProps[] = [\n  {\n    icon: null,\n    text: \"tab\",\n    className: \"!basis-full\",\n  },\n  {\n    icon: \"q\",\n    text: \"Q\",\n    isSingleKey: true,\n  },\n  {\n    icon: \"w\",\n    text: \"W\",\n    isSingleKey: true,\n  },\n  {\n    icon: \"e\",\n    text: \"E\",\n    isSingleKey: true,\n  },\n  {\n    icon: \"r\",\n    text: \"R\",\n    isSingleKey: true,\n  },\n  {\n    icon: \"t\",\n    text: \"T\",\n    isSingleKey: true,\n  },\n  {\n    icon: \"y\",\n    text: \"Y\",\n    isSingleKey: true,\n  },\n  {\n    icon: \"u\",\n    text: \"U\",\n    isSingleKey: true,\n  },\n  {\n    icon: \"i\",\n    text: \"I\",\n    isSingleKey: true,\n  },\n  {\n    icon: \"o\",\n    text: \"O\",\n    isSingleKey: true,\n  },\n  {\n    icon: \"p\",\n    text: \"P\",\n    isSingleKey: true,\n  },\n  {\n    icon: \"{\",\n    text: \"[\",\n  },\n  {\n    icon: \"}\",\n    text: \"]\",\n  },\n  {\n    icon: \"|\",\n    text: \"/\",\n    className: \"last:!items-center\",\n  },\n]\n\nconst fourthRowData: KeyRowDataProps[] = [\n  {\n    icon: <DotIcon size={iconSize + 3} className=\"-mt-0.5 -ml-1.5\" />,\n    text: \"caps lock\",\n    className: \"!basis-full\",\n  },\n  {\n    icon: \"a\",\n    text: \"A\",\n    isSingleKey: true,\n  },\n  {\n    icon: \"s\",\n    text: \"S\",\n    isSingleKey: true,\n  },\n  {\n    icon: \"d\",\n    text: \"D\",\n    isSingleKey: true,\n  },\n  {\n    icon: \"f\",\n    text: \"F\",\n    isSingleKey: true,\n  },\n  {\n    icon: \"g\",\n    text: \"G\",\n    isSingleKey: true,\n  },\n  {\n    icon: \"h\",\n    text: \"H\",\n    isSingleKey: true,\n  },\n  {\n    icon: \"j\",\n    text: \"J\",\n    isSingleKey: true,\n  },\n  {\n    icon: \"k\",\n    text: \"K\",\n    isSingleKey: true,\n  },\n  {\n    icon: \"l\",\n    text: \"L\",\n    isSingleKey: true,\n  },\n  {\n    icon: \":\",\n    text: \";\",\n  },\n  {\n    icon: '\"',\n    text: \"'\",\n  },\n  {\n    icon: null,\n    text: \"return\",\n    className: \"!basis-full\",\n  },\n]\n\nconst fifthRowData: KeyRowDataProps[] = [\n  {\n    icon: null,\n    text: \"shift\",\n    className: \"!basis-full\",\n  },\n  {\n    icon: \"z\",\n    text: \"Z\",\n    isSingleKey: true,\n  },\n  {\n    icon: \"x\",\n    text: \"X\",\n    isSingleKey: true,\n  },\n  {\n    icon: \"c\",\n    text: \"C\",\n    isSingleKey: true,\n  },\n  {\n    icon: \"v\",\n    text: \"V\",\n    isSingleKey: true,\n  },\n  {\n    icon: \"b\",\n    text: \"B\",\n    isSingleKey: true,\n  },\n  {\n    icon: \"n\",\n    text: \"N\",\n    isSingleKey: true,\n  },\n  {\n    icon: \"m\",\n    text: \"M\",\n    isSingleKey: true,\n  },\n  {\n    icon: \"<\",\n    text: \",\",\n  },\n  {\n    icon: \">\",\n    text: \".\",\n  },\n  {\n    icon: \"?\",\n    text: \"/\",\n  },\n  {\n    icon: null,\n    text: \"shift\",\n    className: \"!basis-full\",\n  },\n]\n\nconst sixthRowData: KeyRowDataProps[] = [\n  {\n    icon: \"fn\",\n    text: <GlobeIcon size={iconSize} />,\n  },\n  {\n    icon: <ChevronUpIcon size={iconSize} />,\n    text: \"control\",\n    className: \"!items-end\",\n  },\n  {\n    icon: <OptionIcon size={iconSize} />,\n    text: \"option\",\n    className: \"!items-end\",\n  },\n  {\n    icon: <CommandIcon size={iconSize} />,\n    text: \"command\",\n    className: \"!items-end !basis-20\",\n  },\n  {\n    icon: null,\n    text: \"\",\n    className: \"!basis-80\",\n  },\n  {\n    icon: <CommandIcon size={iconSize} />,\n    text: \"command\",\n    className: \"!items-start !basis-20\",\n  },\n  {\n    icon: <OptionIcon size={iconSize} />,\n    text: \"option\",\n    className: \"!items-start\",\n  },\n  {\n    icon: null,\n    custom: \"ArrowKeys\",\n  },\n]\n\nconst keysData = [\n  firstRowData,\n  secondRowData,\n  thirdRowData,\n  fourthRowData,\n  fifthRowData,\n  sixthRowData,\n]\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}