mirror of
https://github.com/supabase/supabase.git
synced 2026-10-08 10:55:06 +03:00
## 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 [](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/44273) <!-- end of auto-generated comment: release notes by coderabbit.ai -->
64 lines
3.9 KiB
TypeScript
64 lines
3.9 KiB
TypeScript
import { type RegistryItem } from 'shadcn/schema'
|
|
|
|
import { clients } from './clients'
|
|
import currentUserAvatar from './default/blocks/current-user-avatar/registry-item.json' with { type: 'json' }
|
|
import dropzone from './default/blocks/dropzone/registry-item.json' with { type: 'json' }
|
|
import infiniteQueryHook from './default/blocks/infinite-query-hook/registry-item.json' with { type: 'json' }
|
|
import passwordBasedAuthNextjs from './default/blocks/password-based-auth-nextjs/registry-item.json' with { type: 'json' }
|
|
import passwordBasedAuthReactRouter from './default/blocks/password-based-auth-react-router/registry-item.json' with { type: 'json' }
|
|
import passwordBasedAuthReact from './default/blocks/password-based-auth-react/registry-item.json' with { type: 'json' }
|
|
import passwordBasedAuthTanstack from './default/blocks/password-based-auth-tanstack/registry-item.json' with { type: 'json' }
|
|
import realtimeAvatarStack from './default/blocks/realtime-avatar-stack/registry-item.json' with { type: 'json' }
|
|
import realtimeChat from './default/blocks/realtime-chat/registry-item.json' with { type: 'json' }
|
|
import realtimeCursor from './default/blocks/realtime-cursor/registry-item.json' with { type: 'json' }
|
|
import realtimeFlow from './default/blocks/realtime-flow/registry-item.json' with { type: 'json' }
|
|
import realtimeMonaco from './default/blocks/realtime-monaco/registry-item.json' with { type: 'json' }
|
|
import socialAuthNextjs from './default/blocks/social-auth-nextjs/registry-item.json' with { type: 'json' }
|
|
import socialAuthReactRouter from './default/blocks/social-auth-react-router/registry-item.json' with { type: 'json' }
|
|
import socialAuthReact from './default/blocks/social-auth-react/registry-item.json' with { type: 'json' }
|
|
import socialAuthTanstack from './default/blocks/social-auth-tanstack/registry-item.json' with { type: 'json' }
|
|
import tanstackDbNextjs from './default/blocks/tanstack-db/registry-item.json' with { type: 'json' }
|
|
import { registryItemAppend } from './utils'
|
|
|
|
const combine = (component: RegistryItem) => {
|
|
return clients.flatMap((client) => {
|
|
return registryItemAppend(
|
|
{
|
|
...component,
|
|
name: `${component.name}-${client.name.replace('supabase-client-', '')}`,
|
|
},
|
|
[client]
|
|
)
|
|
})
|
|
}
|
|
|
|
const nextjsClient = clients.find((client) => client.name === 'supabase-client-nextjs')
|
|
const reactClient = clients.find((client) => client.name === 'supabase-client-react')
|
|
const tanstackClient = clients.find((client) => client.name === 'supabase-client-tanstack')
|
|
const reactRouterClient = clients.find((client) => client.name === 'supabase-client-react-router')
|
|
|
|
export const blocks = [
|
|
registryItemAppend(passwordBasedAuthNextjs as RegistryItem, [nextjsClient!]),
|
|
registryItemAppend(passwordBasedAuthReact as RegistryItem, [reactClient!]),
|
|
registryItemAppend(passwordBasedAuthReactRouter as RegistryItem, [reactRouterClient!]),
|
|
registryItemAppend(passwordBasedAuthTanstack as RegistryItem, [tanstackClient!]),
|
|
|
|
registryItemAppend(socialAuthNextjs as RegistryItem, [nextjsClient!]),
|
|
registryItemAppend(socialAuthReact as RegistryItem, [reactClient!]),
|
|
registryItemAppend(socialAuthReactRouter as RegistryItem, [reactRouterClient!]),
|
|
registryItemAppend(socialAuthTanstack as RegistryItem, [tanstackClient!]),
|
|
|
|
...combine(dropzone as RegistryItem),
|
|
...combine(realtimeCursor as RegistryItem),
|
|
...combine(currentUserAvatar as RegistryItem),
|
|
...combine(realtimeAvatarStack as RegistryItem),
|
|
...combine(realtimeChat as RegistryItem),
|
|
...combine(realtimeFlow as RegistryItem),
|
|
...combine(realtimeMonaco as RegistryItem),
|
|
// infinite query hook is intentionally not combined with the clients since it depends on clients having database types.
|
|
infiniteQueryHook as RegistryItem,
|
|
|
|
// tanstack-db is served dynamically via API route, but we register it here for the static build
|
|
registryItemAppend(tanstackDbNextjs as RegistryItem, [nextjsClient!]),
|
|
] as RegistryItem[]
|