{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "ai-environment-variables",
  "title": "AI: Environment Variables",
  "description": "Environment variable rows with controlled visibility and copy actions.",
  "dependencies": [
    "@untitledui/icons@^0.0.23"
  ],
  "registryDependencies": [
    "@nx-ui/utils",
    "@nx-ui/badge",
    "@nx-ui/button",
    "@nx-ui/switch"
  ],
  "files": [
    {
      "path": "components/ai/environment-variables.tsx",
      "content": "// Ported from vercel/ai-elements@6a9d5b1822ffb10bba4bd97175f01edd7d8651cd.\n\"use client\";\n\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Switch } from \"@/components/ui/switch\";\nimport { cn } from \"@/lib/utils\";\nimport { Check as CheckIcon, Copy01 as CopyIcon, Eye as EyeIcon, EyeOff as EyeOffIcon } from \"@untitledui/icons\";\nimport type { ComponentProps, HTMLAttributes } from \"react\";\nimport {\n  createContext,\n  useCallback,\n  useContext,\n  useEffect,\n  useMemo,\n  useRef,\n  useState,\n} from \"react\";\n\ninterface EnvironmentVariablesContextType {\n  showValues: boolean;\n  setShowValues: (show: boolean) => void;\n}\n\n// Default noop for context default value\n// oxlint-disable-next-line eslint(no-empty-function)\nconst noop = () => {};\n\nconst EnvironmentVariablesContext =\n  createContext<EnvironmentVariablesContextType>({\n    setShowValues: noop,\n    showValues: false,\n  });\n\nexport type EnvironmentVariablesProps = HTMLAttributes<HTMLDivElement> & {\n  showValues?: boolean;\n  defaultShowValues?: boolean;\n  onShowValuesChange?: (show: boolean) => void;\n};\n\nexport const EnvironmentVariables = ({\n  showValues: controlledShowValues,\n  defaultShowValues = false,\n  onShowValuesChange,\n  className,\n  children,\n  ...props\n}: EnvironmentVariablesProps) => {\n  const [internalShowValues, setInternalShowValues] =\n    useState(defaultShowValues);\n  const showValues = controlledShowValues ?? internalShowValues;\n\n  const setShowValues = useCallback(\n    (show: boolean) => {\n      setInternalShowValues(show);\n      onShowValuesChange?.(show);\n    },\n    [onShowValuesChange]\n  );\n\n  const contextValue = useMemo(\n    () => ({ setShowValues, showValues }),\n    [setShowValues, showValues]\n  );\n\n  return (\n    <EnvironmentVariablesContext.Provider value={contextValue}>\n      <div\n        className={cn(\"rounded-lg border bg-background\", className)}\n        {...props}\n      >\n        {children}\n      </div>\n    </EnvironmentVariablesContext.Provider>\n  );\n};\n\nexport type EnvironmentVariablesHeaderProps = HTMLAttributes<HTMLDivElement>;\n\nexport const EnvironmentVariablesHeader = ({\n  className,\n  children,\n  ...props\n}: EnvironmentVariablesHeaderProps) => (\n  <div\n    className={cn(\n      \"flex items-center justify-between border-b px-4 py-3\",\n      className\n    )}\n    {...props}\n  >\n    {children}\n  </div>\n);\n\nexport type EnvironmentVariablesTitleProps = HTMLAttributes<HTMLHeadingElement>;\n\nexport const EnvironmentVariablesTitle = ({\n  className,\n  children,\n  ...props\n}: EnvironmentVariablesTitleProps) => (\n  <h3 className={cn(\"font-medium text-sm\", className)} {...props}>\n    {children ?? \"Environment Variables\"}\n  </h3>\n);\n\nexport type EnvironmentVariablesToggleProps = ComponentProps<typeof Switch>;\n\nexport const EnvironmentVariablesToggle = ({\n  className,\n  ...props\n}: EnvironmentVariablesToggleProps) => {\n  const { showValues, setShowValues } = useContext(EnvironmentVariablesContext);\n\n  return (\n    <div className={cn(\"flex items-center gap-2\", className)}>\n      <span className=\"text-muted-foreground text-xs\">\n        {showValues ? <EyeIcon size={14} /> : <EyeOffIcon size={14} />}\n      </span>\n      <Switch\n        aria-label=\"Toggle value visibility\"\n        checked={showValues}\n        onCheckedChange={setShowValues}\n        {...props}\n      />\n    </div>\n  );\n};\n\nexport type EnvironmentVariablesContentProps = HTMLAttributes<HTMLDivElement>;\n\nexport const EnvironmentVariablesContent = ({\n  className,\n  children,\n  ...props\n}: EnvironmentVariablesContentProps) => (\n  <div className={cn(\"divide-y\", className)} {...props}>\n    {children}\n  </div>\n);\n\ninterface EnvironmentVariableContextType {\n  name: string;\n  value: string;\n}\n\nconst EnvironmentVariableContext =\n  createContext<EnvironmentVariableContextType>({\n    name: \"\",\n    value: \"\",\n  });\n\nexport type EnvironmentVariableGroupProps = HTMLAttributes<HTMLDivElement>;\n\nexport const EnvironmentVariableGroup = ({\n  className,\n  children,\n  ...props\n}: EnvironmentVariableGroupProps) => (\n  <div className={cn(\"flex items-center gap-2\", className)} {...props}>\n    {children}\n  </div>\n);\n\nexport type EnvironmentVariableNameProps = HTMLAttributes<HTMLSpanElement>;\n\nexport const EnvironmentVariableName = ({\n  className,\n  children,\n  ...props\n}: EnvironmentVariableNameProps) => {\n  const { name } = useContext(EnvironmentVariableContext);\n\n  return (\n    <span className={cn(\"font-mono text-sm\", className)} {...props}>\n      {children ?? name}\n    </span>\n  );\n};\n\nexport type EnvironmentVariableValueProps = HTMLAttributes<HTMLSpanElement>;\n\nexport const EnvironmentVariableValue = ({\n  className,\n  children,\n  ...props\n}: EnvironmentVariableValueProps) => {\n  const { value } = useContext(EnvironmentVariableContext);\n  const { showValues } = useContext(EnvironmentVariablesContext);\n\n  const displayValue = showValues\n    ? value\n    : \"•\".repeat(Math.min(value.length, 20));\n\n  return (\n    <span\n      className={cn(\n        \"font-mono text-muted-foreground text-sm\",\n        !showValues && \"select-none\",\n        className\n      )}\n      {...props}\n    >\n      {children ?? displayValue}\n    </span>\n  );\n};\n\nexport type EnvironmentVariableProps = HTMLAttributes<HTMLDivElement> & {\n  name: string;\n  value: string;\n};\n\nexport const EnvironmentVariable = ({\n  name,\n  value,\n  className,\n  children,\n  ...props\n}: EnvironmentVariableProps) => {\n  const envVarContextValue = useMemo(() => ({ name, value }), [name, value]);\n\n  return (\n    <EnvironmentVariableContext.Provider value={envVarContextValue}>\n      <div\n        className={cn(\n          \"flex items-center justify-between gap-4 px-4 py-3\",\n          className\n        )}\n        {...props}\n      >\n        {children ?? (\n          <>\n            <div className=\"flex items-center gap-2\">\n              <EnvironmentVariableName />\n            </div>\n            <EnvironmentVariableValue />\n          </>\n        )}\n      </div>\n    </EnvironmentVariableContext.Provider>\n  );\n};\n\nexport type EnvironmentVariableCopyButtonProps = ComponentProps<\n  typeof Button\n> & {\n  onCopy?: () => void;\n  onError?: (error: Error) => void;\n  timeout?: number;\n  copyFormat?: \"name\" | \"value\" | \"export\";\n};\n\nexport const EnvironmentVariableCopyButton = ({\n  onCopy,\n  onError,\n  timeout = 2000,\n  copyFormat = \"value\",\n  children,\n  className,\n  \"aria-label\": ariaLabel,\n  ...props\n}: EnvironmentVariableCopyButtonProps) => {\n  const [isCopied, setIsCopied] = useState(false);\n  const timeoutRef = useRef<number>(0);\n  const { name, value } = useContext(EnvironmentVariableContext);\n\n  const getTextToCopy = useCallback((): string => {\n    const formatMap = {\n      export: () => {\n        if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) {\n          throw new Error(\"Invalid environment variable name.\");\n        }\n        // POSIX single quoting preserves dollars, backticks, newlines and\n        // command substitutions; embedded quotes need a brief quoted escape.\n        return `export ${name}='${value.replaceAll(\"'\", \"'\\\\''\")}'`;\n      },\n      name: () => name,\n      value: () => value,\n    };\n    return formatMap[copyFormat]();\n  }, [name, value, copyFormat]);\n\n  const copyToClipboard = useCallback(async () => {\n    if (typeof window === \"undefined\" || !navigator?.clipboard?.writeText) {\n      onError?.(new Error(\"Clipboard API not available\"));\n      return;\n    }\n\n    try {\n      await navigator.clipboard.writeText(getTextToCopy());\n      setIsCopied(true);\n      onCopy?.();\n      timeoutRef.current = window.setTimeout(() => setIsCopied(false), timeout);\n    } catch (error) {\n      onError?.(error as Error);\n    }\n  }, [getTextToCopy, onCopy, onError, timeout]);\n\n  useEffect(\n    () => () => {\n      window.clearTimeout(timeoutRef.current);\n    },\n    []\n  );\n\n  const Icon = isCopied ? CheckIcon : CopyIcon;\n\n  return (\n    <Button\n      className={cn(\"size-6 shrink-0\", className)}\n      onClick={copyToClipboard}\n      size=\"icon\"\n      variant=\"ghost\"\n      {...props}\n      aria-label={ariaLabel ?? `Copy ${name}`}\n    >\n      {children ?? <Icon size={12} />}\n    </Button>\n  );\n};\n\nexport type EnvironmentVariableRequiredProps = ComponentProps<typeof Badge>;\n\nexport const EnvironmentVariableRequired = ({\n  className,\n  children,\n  ...props\n}: EnvironmentVariableRequiredProps) => (\n  <Badge className={cn(\"text-xs\", className)} variant=\"secondary\" {...props}>\n    {children ?? \"Required\"}\n  </Badge>\n);\n",
      "type": "registry:ui",
      "target": "components/ai/environment-variables.tsx"
    }
  ],
  "type": "registry:ui"
}