{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "realtime-monaco-tanstack",
  "title": "Realtime Monaco",
  "description": "Real-time Monaco editor for collaborative applications.",
  "dependencies": [
    "@monaco-editor/react@latest",
    "y-monaco@latest",
    "yjs@latest",
    "@supabase/ssr@latest",
    "@supabase/supabase-js@latest"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/default/blocks/realtime-monaco/hooks/use-connect-on-mount.ts",
      "content": "'use client'\n\nimport { SupabasePersistenceOptions, SupabaseProvider } from '@supabase-labs/y-supabase'\nimport type { editor as MonacoEditor } from 'monaco-editor'\nimport { useCallback, useEffect, useRef } from 'react'\nimport { MonacoBinding } from 'y-monaco'\nimport { Awareness } from 'y-protocols/awareness'\nimport * as Y from 'yjs'\n\nimport { createClient } from '@/registry/default/clients/tanstack/lib/supabase/client'\n\ntype UseConnectOnMountOptions = {\n  channel: string\n  persistence?: boolean | SupabasePersistenceOptions\n  awareness?: boolean | Awareness\n}\n\nconst generateRandomColor = () => `hsl(${Math.floor(Math.random() * 360)}, 80%, 60%)`\n\nexport function useConnectOnMount({\n  channel,\n  persistence,\n  awareness = true,\n}: UseConnectOnMountOptions) {\n  const docRef = useRef<Y.Doc | null>(null)\n  const providerRef = useRef<SupabaseProvider | null>(null)\n  const bindingRef = useRef<MonacoBinding | null>(null)\n  const userRef = useRef<{ color: string } | null>(null)\n  const styleRef = useRef<HTMLStyleElement | null>(null)\n  const awarenessHandlerRef = useRef<(() => void) | null>(null)\n\n  const connectOnMount = useCallback(\n    (editor: MonacoEditor.IStandaloneCodeEditor) => {\n      if (bindingRef.current) return\n\n      const model = editor.getModel()\n      if (!model) return\n\n      const doc = new Y.Doc()\n      const yText = doc.getText('monaco')\n      const supabase = createClient()\n      const provider = new SupabaseProvider(channel, doc, supabase as any, {\n        awareness,\n        persistence,\n      })\n      const providerAwareness = provider.getAwareness()\n\n      if (providerAwareness) {\n        if (!userRef.current) {\n          userRef.current = {\n            color: generateRandomColor(),\n          }\n        }\n        providerAwareness.setLocalStateField('user', userRef.current)\n\n        const applyAwarenessStyles = () => {\n          if (!styleRef.current) {\n            styleRef.current = document.createElement('style')\n            styleRef.current.setAttribute('data-monaco-y-cursors', 'true')\n            document.head.appendChild(styleRef.current)\n          }\n\n          let css = `\n            .yRemoteSelection {\n              background-color: var(--y-remote-selection-color, rgba(0, 0, 0, 0.2));\n              opacity: 0.2;\n            }\n            .yRemoteSelectionHead {\n              border-left: 2px solid var(--y-remote-selection-color, rgba(0, 0, 0, 0.7));\n              margin-left: -1px;\n              box-sizing: border-box;\n            }\n          `\n\n          providerAwareness.getStates().forEach((state, clientId) => {\n            const color = state?.user?.color\n            const isValidHsl = /^hsl\\(\\d{1,3},\\s*\\d{1,3}%,\\s*\\d{1,3}%\\)$/.test(color)\n\n            if (!isValidHsl) return\n            if (!color) return\n\n            css += `\n              .yRemoteSelection-${clientId}, .yRemoteSelectionHead-${clientId} {\n                --y-remote-selection-color: ${color};\n              }\n            `\n          })\n\n          styleRef.current.textContent = css\n        }\n\n        awarenessHandlerRef.current = applyAwarenessStyles\n        applyAwarenessStyles()\n        providerAwareness.on('update', applyAwarenessStyles)\n      }\n\n      docRef.current = doc\n      providerRef.current = provider\n      bindingRef.current = new MonacoBinding(yText, model, new Set([editor]), providerAwareness)\n    },\n    [channel]\n  )\n\n  useEffect(() => {\n    return () => {\n      if (awarenessHandlerRef.current && providerRef.current) {\n        const awareness = providerRef.current.getAwareness()\n        awareness?.off('update', awarenessHandlerRef.current)\n      }\n      styleRef.current?.remove()\n      bindingRef.current?.destroy()\n      bindingRef.current = null\n      providerRef.current?.destroy()\n      providerRef.current = null\n      docRef.current?.destroy()\n      docRef.current = null\n    }\n  }, [])\n\n  return { connectOnMount }\n}\n",
      "type": "registry:hook"
    },
    {
      "path": "registry/default/blocks/realtime-monaco/components/realtime-monaco.tsx",
      "content": "'use client'\n\nimport { Editor } from '@monaco-editor/react'\nimport { SupabasePersistenceOptions } from '@supabase-labs/y-supabase'\nimport { Awareness } from 'y-protocols/awareness.js'\n\nimport { useConnectOnMount } from '../hooks/use-connect-on-mount'\n\ntype RealtimeMonacoProps = {\n  channel: string\n  language?: string\n  height?: string | number\n  className?: string\n  awareness?: boolean | Awareness\n  persistence?: boolean | SupabasePersistenceOptions\n  theme?: 'light' | 'dark'\n}\n\nconst DEFAULT_HEIGHT = 550\n\nconst RealtimeMonaco = ({\n  channel,\n  language = 'javascript',\n  height = DEFAULT_HEIGHT,\n  awareness = true,\n  persistence,\n  theme,\n  ...rest\n}: RealtimeMonacoProps) => {\n  const { connectOnMount } = useConnectOnMount({ channel, persistence, awareness })\n\n  return (\n    <Editor\n      height={height}\n      language={language}\n      theme={theme === 'dark' ? 'vs-dark' : 'light'}\n      onMount={connectOnMount}\n      {...rest}\n    />\n  )\n}\n\nexport { RealtimeMonaco }\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/clients/tanstack/lib/supabase/client.ts",
      "content": "/// <reference types=\"vite/types/importMeta.d.ts\" />\nimport { createBrowserClient } from '@supabase/ssr'\n\nexport function createClient() {\n  return createBrowserClient(\n    import.meta.env.VITE_SUPABASE_URL!,\n    import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY!\n  )\n}\n",
      "type": "registry:lib"
    },
    {
      "path": "registry/default/clients/tanstack/lib/supabase/server.ts",
      "content": "import { createServerClient } from '@supabase/ssr'\nimport { getCookies, setCookie } from '@tanstack/react-start/server'\n\nexport function createClient() {\n  return createServerClient(\n    process.env.VITE_SUPABASE_URL!,\n    process.env.VITE_SUPABASE_PUBLISHABLE_KEY!,\n    {\n      cookies: {\n        getAll() {\n          return Object.entries(getCookies()).map(\n            ([name, value]) =>\n              ({\n                name,\n                value,\n              }) as { name: string; value: string }\n          )\n        },\n        setAll(cookies) {\n          cookies.forEach((cookie) => {\n            setCookie(cookie.name, cookie.value)\n          })\n        },\n      },\n    }\n  )\n}\n",
      "type": "registry:lib"
    }
  ],
  "envVars": {
    "VITE_SUPABASE_URL": "",
    "VITE_SUPABASE_PUBLISHABLE_KEY": ""
  },
  "docs": "You'll need to set the following environment variables in your project: `VITE_SUPABASE_URL` and `VITE_SUPABASE_PUBLISHABLE_KEY`.",
  "type": "registry:component"
}