{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "elements-mcp-config-state",
  "type": "registry:component",
  "title": "Elements MCP Config State",
  "description": "Shared focus and announcement state for MCP config dialogs.",
  "dependencies": [
    "@assistant-ui/react-mcp@^0.1.23",
    "@assistant-ui/store@^0.3.21"
  ],
  "files": [
    {
      "type": "registry:component",
      "path": "components/assistant-ui/utils/mcp-config-state.ts",
      "sourcePath": "packages/ui/src/components/react/assistant-ui/utils/mcp-config-state.ts",
      "content": "\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { useAuiState } from \"@assistant-ui/store\";\nimport type { MCPConnectionState } from \"@assistant-ui/react-mcp\";\n\nconst FOCUSABLE_SELECTOR = \"button:not([disabled]), a[href]\";\n\nconst firstFocusable = (element: Element | null | undefined) =>\n  element?.matches(FOCUSABLE_SELECTOR)\n    ? (element as HTMLElement)\n    : element?.querySelector<HTMLElement>(FOCUSABLE_SELECTOR);\n\nconst indexOfServer = (list: Element, element: Element) =>\n  [...list.children].findIndex((card) => card.contains(element));\n\nconst isFocusLost = () => {\n  const active = document.activeElement;\n  return (\n    !active ||\n    active === document.body ||\n    active.getAttribute(\"role\") === \"dialog\"\n  );\n};\n\nexport function useCustomServersSection() {\n  const serverIds = useAuiState((s) =>\n    s.mcp.customServers.map((server) => server.id).join(\"\\x1f\"),\n  );\n  const [showForm, setShowForm] = useState(false);\n  const listRef = useRef<HTMLDivElement>(null);\n  const focusedServerRef = useRef<{ element: Element; index: number } | null>(\n    null,\n  );\n  const addTriggerRef = useRef<HTMLButtonElement>(null);\n  const restoreFocusRef = useRef(false);\n\n  useEffect(() => {\n    if (showForm || !restoreFocusRef.current) return;\n    restoreFocusRef.current = false;\n    addTriggerRef.current?.focus();\n  }, [showForm]);\n\n  useEffect(() => {\n    const list = listRef.current;\n    const focused = focusedServerRef.current;\n    if (!list || !focused) return;\n    if (focused.element.isConnected) {\n      focused.index = indexOfServer(list, focused.element);\n      return;\n    }\n    focusedServerRef.current = null;\n    if (!isFocusLost()) return;\n    (\n      firstFocusable(list.children[focused.index]) ??\n      firstFocusable(list.nextElementSibling)\n    )?.focus();\n  }, [serverIds]);\n\n  const onListFocus = (list: Element, element: Element) => {\n    focusedServerRef.current = {\n      element,\n      index: indexOfServer(list, element),\n    };\n  };\n\n  const openForm = () => setShowForm(true);\n  const closeForm = () => {\n    restoreFocusRef.current = true;\n    setShowForm(false);\n  };\n\n  return { showForm, listRef, addTriggerRef, onListFocus, openForm, closeForm };\n}\n\nexport const STATUS_LABEL: Record<MCPConnectionState, string> = {\n  connected: \"Connected\",\n  connecting: \"Connecting…\",\n  authRequired: \"Auth required\",\n  authPending: \"Authorizing…\",\n  error: \"Error\",\n  disconnected: \"Disconnected\",\n};\n\nexport function useServerAnnouncement() {\n  const status = useAuiState((s) => s.mcpServer.connectionState);\n  const message = useAuiState((s) => s.mcpServer.lastError?.message ?? null);\n  const [seen, setSeen] = useState({ status, message });\n  const [announcement, setAnnouncement] = useState(\"\");\n\n  if (seen.status !== status || seen.message !== message) {\n    setSeen({ status, message });\n    if (message && message !== seen.message) {\n      setAnnouncement(`${STATUS_LABEL.error}: ${message}`);\n    } else if (status !== seen.status) {\n      setAnnouncement(STATUS_LABEL[status]);\n    }\n  }\n\n  useEffect(() => {\n    if (!announcement) return;\n    const timeout = setTimeout(() => setAnnouncement(\"\"), 1000);\n    return () => clearTimeout(timeout);\n  }, [announcement]);\n\n  return announcement;\n}\n\nexport function useServerActionFocus() {\n  const state = useAuiState((s) => s.mcpServer.connectionState);\n  const actionRef = useRef<HTMLButtonElement>(null);\n  const focusedRef = useRef<Element | null>(null);\n\n  useEffect(() => {\n    const focused = focusedRef.current;\n    if (!focused || focused.isConnected) return;\n    focusedRef.current = null;\n    if (isFocusLost()) actionRef.current?.focus();\n  }, [state]);\n\n  const onActionFocus = (element: Element) => {\n    focusedRef.current = element;\n  };\n\n  return { actionRef, onActionFocus };\n}\n"
    }
  ]
}