Files
supabase/apps/ui-library/public/r/current-user-avatar-react-router.json
Tiago Antunes b79a64e301 feat: add Realtime Flow component (#44273)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Feature, docs update

## What is the new behavior?

This PR introduces a new `RealtimeFlow` component and hook to the UI
library for building collaborative React Flow with Supabase Realtime:
- keeps nodes and edges in sync across multiple connected clients in
real time
- uses Yjs with `@supabase-labs/y-supabase` to propagate flow updates
- supports optional persistence, so a flow can be restored from
previously saved shared state

## Additional context


https://github.com/user-attachments/assets/90d3a381-6f9c-427f-a493-5d91c2141462



<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Collaborative "Realtime Flow" diagram editor with syncing overlays and
a dual-view demo component
* Interactive demo page and registry example for live editing
(add/remove/rename nodes)
* Framework-ready registry packages for Next.js, React, React Router,
and TanStack

* **Documentation**
* Comprehensive docs added for Next.js, React, React Router, and
TanStack (usage, persistence, hook API)

* **Chores**
  * Added runtime dependency for the flow component package

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/44273)
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-26 13:28:52 +03:00

46 lines
4.2 KiB
JSON

{
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
"name": "current-user-avatar-react-router",
"type": "registry:component",
"title": "Current User Avatar",
"description": "Component which renders the current user's avatar.",
"dependencies": [
"@supabase/ssr@latest",
"@supabase/supabase-js@latest"
],
"registryDependencies": [
"avatar"
],
"files": [
{
"path": "registry/default/blocks/current-user-avatar/components/current-user-avatar.tsx",
"content": "'use client'\n\nimport { useCurrentUserImage } from '@/registry/default/blocks/current-user-avatar/hooks/use-current-user-image'\nimport { useCurrentUserName } from '@/registry/default/blocks/current-user-avatar/hooks/use-current-user-name'\nimport { Avatar, AvatarFallback, AvatarImage } from '@/registry/default/components/ui/avatar'\n\nexport const CurrentUserAvatar = () => {\n const profileImage = useCurrentUserImage()\n const name = useCurrentUserName()\n const initials = name\n ?.split(' ')\n ?.map((word) => word[0])\n ?.join('')\n ?.toUpperCase()\n\n return (\n <Avatar>\n {profileImage && <AvatarImage src={profileImage} alt={initials} />}\n <AvatarFallback>{initials}</AvatarFallback>\n </Avatar>\n )\n}\n",
"type": "registry:component"
},
{
"path": "registry/default/blocks/current-user-avatar/hooks/use-current-user-name.ts",
"content": "import { useEffect, useState } from 'react'\n\nimport { createClient } from '@/registry/default/clients/react-router/lib/supabase/client'\n\nexport const useCurrentUserName = () => {\n const [name, setName] = useState<string | null>(null)\n\n useEffect(() => {\n const fetchProfileName = async () => {\n const { data, error } = await createClient().auth.getSession()\n if (error) {\n console.error(error)\n }\n\n setName(data.session?.user.user_metadata.full_name ?? '?')\n }\n\n fetchProfileName()\n }, [])\n\n return name || '?'\n}\n",
"type": "registry:hook"
},
{
"path": "registry/default/blocks/current-user-avatar/hooks/use-current-user-image.ts",
"content": "import { useEffect, useState } from 'react'\n\nimport { createClient } from '@/registry/default/clients/react-router/lib/supabase/client'\n\nexport const useCurrentUserImage = () => {\n const [image, setImage] = useState<string | null>(null)\n\n useEffect(() => {\n const fetchUserImage = async () => {\n const { data, error } = await createClient().auth.getSession()\n if (error) {\n console.error(error)\n }\n\n setImage(data.session?.user.user_metadata.avatar_url ?? null)\n }\n fetchUserImage()\n }, [])\n\n return image\n}\n",
"type": "registry:hook"
},
{
"path": "registry/default/clients/react-router/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/react-router/lib/supabase/server.ts",
"content": "import { createServerClient, parseCookieHeader, serializeCookieHeader } from '@supabase/ssr'\n\nexport function createClient(request: Request) {\n const headers = new Headers()\n\n const supabase = createServerClient(\n process.env.VITE_SUPABASE_URL!,\n process.env.VITE_SUPABASE_PUBLISHABLE_KEY!,\n {\n cookies: {\n getAll() {\n return parseCookieHeader(request.headers.get('Cookie') ?? '') as {\n name: string\n value: string\n }[]\n },\n setAll(cookiesToSet) {\n cookiesToSet.forEach(({ name, value, options }) =>\n headers.append('Set-Cookie', serializeCookieHeader(name, value, options))\n )\n },\n },\n }\n )\n\n return { supabase, headers }\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`."
}