From 05d58ca66940d835f010141f10fda2fbda1c9910 Mon Sep 17 00:00:00 2001 From: Chris Nicholas Date: Fri, 19 Jun 2026 14:28:27 +0100 Subject: [PATCH 1/3] =?UTF-8?q?CHANGELOG=20=E2=80=94=20WEEK=2024=20&=2025?= =?UTF-8?q?=20(#3510)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Vincent Driessen Co-authored-by: Marc Bouchenoire --- CHANGELOG_PUBLIC.md | 50 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/CHANGELOG_PUBLIC.md b/CHANGELOG_PUBLIC.md index 128db7b97f..cb80938fa8 100644 --- a/CHANGELOG_PUBLIC.md +++ b/CHANGELOG_PUBLIC.md @@ -18,6 +18,52 @@ list and feel free to give them credit at the end of a line, e.g.: --> +# Week 25 (2026-06-19) + +## v3.20.0 + +### All packages + +- Add support for new resource-specific permissions. You can now start from a + `*:read` or `*:write` base, then grant or deny access per resource (storage, + comments, feeds) using new permission strings like `storage:none` or + `comments:read`. + +### `@liveblocks/node` + +- Deprecate `session.FULL_ACCESS` and `session.READ_ACCESS` in favor of + `["*:write"]` and `["*:read"]` respectively. + +### `@liveblocks/client` + +- Deprecate `room.getStorageSnapshot()` in favor of `room.getStorageOrNull()`. + +## Examples + +- New example: [AI Spreadsheet](https://liveblocks.io/examples/ai-spreadsheet/nextjs-ai-spreadsheet). +- New example: [Realtime AI Elements Chats](https://liveblocks.io/examples/ai-elements-realtime/nextjs-ai-elements-realtime). +- Added “?” button to various examples, featuring a pop-up that explains how to use them. + +## Contributors + +ofoucherot, nvie, marcbouchenoire, ctnicholas + +# Week 24 (2026-06-12) + +## v3.19.5 + +### `@liveblocks/client` + +- Fix a `LiveList` divergence after reconnects: a pending `push` could under specific timing conditions during a reconnect still cause a divergence between clients, despite the fix from 3.19.4. + +## Liveblocks dev server (v1.6.1) + +- Fix a `LiveList` divergence after reconnects: when a client re-sends a pending `push` op whose node the server had already stored (the original ack got lost in the disconnect) + +## Contributors + +nvie + # Week 23 (2026-06-05) ## v3.19.4 @@ -49,9 +95,7 @@ list and feel free to give them credit at the end of a line, e.g.: ## Liveblocks dev server (v1.6.0) -- Update internal storage format of dev server. Note that your local dev rooms - are not automatically migrated and will appear as empty rooms after the - upgrade. +- Update internal storage format of dev server. Note that your local dev rooms are not automatically migrated and will appear as empty rooms after the upgrade. ## Contributors From 8915617f5fd0c2e237aa8d5e1bc7ded5d70f2d44 Mon Sep 17 00:00:00 2001 From: Marc Bouchenoire Date: Fri, 19 Jun 2026 17:29:19 +0200 Subject: [PATCH 2/3] Remove unused components/dependencies in examples (#3538) --- .../components/ai-elements/artifact.tsx | 147 ------- .../components/ai-elements/canvas.tsx | 22 -- .../components/ai-elements/checkpoint.tsx | 68 ---- .../components/ai-elements/confirmation.tsx | 176 --------- .../components/ai-elements/connection.tsx | 28 -- .../components/ai-elements/controls.tsx | 18 - .../components/ai-elements/edge.tsx | 140 ------- .../components/ai-elements/image.tsx | 24 -- .../ai-elements/inline-citation.tsx | 287 -------------- .../components/ai-elements/model-selector.tsx | 205 ---------- .../components/ai-elements/node.tsx | 71 ---- .../components/ai-elements/open-in-chat.tsx | 365 ------------------ .../components/ai-elements/panel.tsx | 15 - .../components/ai-elements/plan.tsx | 142 ------- .../components/ai-elements/queue.tsx | 274 ------------- .../components/ai-elements/task.tsx | 87 ----- .../components/ai-elements/toolbar.tsx | 16 - .../components/ai-elements/web-preview.tsx | 263 ------------- .../components/ui/alert.tsx | 66 ---- .../components/ui/card.tsx | 92 ----- .../components/ui/carousel.tsx | 241 ------------ .../package-lock.json | 270 ++++--------- .../nextjs-ai-elements-realtime/package.json | 6 +- .../components/ai-elements/artifact.tsx | 147 ------- .../components/ai-elements/canvas.tsx | 22 -- .../components/ai-elements/checkpoint.tsx | 68 ---- .../components/ai-elements/code-block.tsx | 178 --------- .../components/ai-elements/confirmation.tsx | 176 --------- .../components/ai-elements/connection.tsx | 28 -- .../components/ai-elements/controls.tsx | 18 - .../components/ai-elements/edge.tsx | 140 ------- .../components/ai-elements/image.tsx | 24 -- .../ai-elements/inline-citation.tsx | 287 -------------- .../components/ai-elements/model-selector.tsx | 205 ---------- .../components/ai-elements/node.tsx | 71 ---- .../components/ai-elements/open-in-chat.tsx | 365 ------------------ .../components/ai-elements/panel.tsx | 15 - .../components/ai-elements/plan.tsx | 142 ------- .../components/ai-elements/queue.tsx | 274 ------------- .../components/ai-elements/sources.tsx | 77 ---- .../components/ai-elements/task.tsx | 87 ----- .../components/ai-elements/tool.tsx | 163 -------- .../components/ai-elements/toolbar.tsx | 16 - .../components/ai-elements/web-preview.tsx | 263 ------------- .../components/ui/alert.tsx | 66 ---- .../components/ui/card.tsx | 92 ----- .../components/ui/carousel.tsx | 241 ------------ .../nextjs-ai-spreadsheet/package-lock.json | 295 ++++---------- examples/nextjs-ai-spreadsheet/package.json | 3 - 49 files changed, 135 insertions(+), 6351 deletions(-) delete mode 100644 examples/nextjs-ai-elements-realtime/components/ai-elements/artifact.tsx delete mode 100644 examples/nextjs-ai-elements-realtime/components/ai-elements/canvas.tsx delete mode 100644 examples/nextjs-ai-elements-realtime/components/ai-elements/checkpoint.tsx delete mode 100644 examples/nextjs-ai-elements-realtime/components/ai-elements/confirmation.tsx delete mode 100644 examples/nextjs-ai-elements-realtime/components/ai-elements/connection.tsx delete mode 100644 examples/nextjs-ai-elements-realtime/components/ai-elements/controls.tsx delete mode 100644 examples/nextjs-ai-elements-realtime/components/ai-elements/edge.tsx delete mode 100644 examples/nextjs-ai-elements-realtime/components/ai-elements/image.tsx delete mode 100644 examples/nextjs-ai-elements-realtime/components/ai-elements/inline-citation.tsx delete mode 100644 examples/nextjs-ai-elements-realtime/components/ai-elements/model-selector.tsx delete mode 100644 examples/nextjs-ai-elements-realtime/components/ai-elements/node.tsx delete mode 100644 examples/nextjs-ai-elements-realtime/components/ai-elements/open-in-chat.tsx delete mode 100644 examples/nextjs-ai-elements-realtime/components/ai-elements/panel.tsx delete mode 100644 examples/nextjs-ai-elements-realtime/components/ai-elements/plan.tsx delete mode 100644 examples/nextjs-ai-elements-realtime/components/ai-elements/queue.tsx delete mode 100644 examples/nextjs-ai-elements-realtime/components/ai-elements/task.tsx delete mode 100644 examples/nextjs-ai-elements-realtime/components/ai-elements/toolbar.tsx delete mode 100644 examples/nextjs-ai-elements-realtime/components/ai-elements/web-preview.tsx delete mode 100644 examples/nextjs-ai-elements-realtime/components/ui/alert.tsx delete mode 100644 examples/nextjs-ai-elements-realtime/components/ui/card.tsx delete mode 100644 examples/nextjs-ai-elements-realtime/components/ui/carousel.tsx delete mode 100644 examples/nextjs-ai-spreadsheet/components/ai-elements/artifact.tsx delete mode 100644 examples/nextjs-ai-spreadsheet/components/ai-elements/canvas.tsx delete mode 100644 examples/nextjs-ai-spreadsheet/components/ai-elements/checkpoint.tsx delete mode 100644 examples/nextjs-ai-spreadsheet/components/ai-elements/code-block.tsx delete mode 100644 examples/nextjs-ai-spreadsheet/components/ai-elements/confirmation.tsx delete mode 100644 examples/nextjs-ai-spreadsheet/components/ai-elements/connection.tsx delete mode 100644 examples/nextjs-ai-spreadsheet/components/ai-elements/controls.tsx delete mode 100644 examples/nextjs-ai-spreadsheet/components/ai-elements/edge.tsx delete mode 100644 examples/nextjs-ai-spreadsheet/components/ai-elements/image.tsx delete mode 100644 examples/nextjs-ai-spreadsheet/components/ai-elements/inline-citation.tsx delete mode 100644 examples/nextjs-ai-spreadsheet/components/ai-elements/model-selector.tsx delete mode 100644 examples/nextjs-ai-spreadsheet/components/ai-elements/node.tsx delete mode 100644 examples/nextjs-ai-spreadsheet/components/ai-elements/open-in-chat.tsx delete mode 100644 examples/nextjs-ai-spreadsheet/components/ai-elements/panel.tsx delete mode 100644 examples/nextjs-ai-spreadsheet/components/ai-elements/plan.tsx delete mode 100644 examples/nextjs-ai-spreadsheet/components/ai-elements/queue.tsx delete mode 100644 examples/nextjs-ai-spreadsheet/components/ai-elements/sources.tsx delete mode 100644 examples/nextjs-ai-spreadsheet/components/ai-elements/task.tsx delete mode 100644 examples/nextjs-ai-spreadsheet/components/ai-elements/tool.tsx delete mode 100644 examples/nextjs-ai-spreadsheet/components/ai-elements/toolbar.tsx delete mode 100644 examples/nextjs-ai-spreadsheet/components/ai-elements/web-preview.tsx delete mode 100644 examples/nextjs-ai-spreadsheet/components/ui/alert.tsx delete mode 100644 examples/nextjs-ai-spreadsheet/components/ui/card.tsx delete mode 100644 examples/nextjs-ai-spreadsheet/components/ui/carousel.tsx diff --git a/examples/nextjs-ai-elements-realtime/components/ai-elements/artifact.tsx b/examples/nextjs-ai-elements-realtime/components/ai-elements/artifact.tsx deleted file mode 100644 index c90cb5fe3d..0000000000 --- a/examples/nextjs-ai-elements-realtime/components/ai-elements/artifact.tsx +++ /dev/null @@ -1,147 +0,0 @@ -"use client"; - -import { Button } from "@/components/ui/button"; -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from "@/components/ui/tooltip"; -import { cn } from "@/lib/utils"; -import { type LucideIcon, XIcon } from "lucide-react"; -import type { ComponentProps, HTMLAttributes } from "react"; - -export type ArtifactProps = HTMLAttributes; - -export const Artifact = ({ className, ...props }: ArtifactProps) => ( -
-); - -export type ArtifactHeaderProps = HTMLAttributes; - -export const ArtifactHeader = ({ - className, - ...props -}: ArtifactHeaderProps) => ( -
-); - -export type ArtifactCloseProps = ComponentProps; - -export const ArtifactClose = ({ - className, - children, - size = "sm", - variant = "ghost", - ...props -}: ArtifactCloseProps) => ( - -); - -export type ArtifactTitleProps = HTMLAttributes; - -export const ArtifactTitle = ({ className, ...props }: ArtifactTitleProps) => ( -

-); - -export type ArtifactDescriptionProps = HTMLAttributes; - -export const ArtifactDescription = ({ - className, - ...props -}: ArtifactDescriptionProps) => ( -

-); - -export type ArtifactActionsProps = HTMLAttributes; - -export const ArtifactActions = ({ - className, - ...props -}: ArtifactActionsProps) => ( -

-); - -export type ArtifactActionProps = ComponentProps & { - tooltip?: string; - label?: string; - icon?: LucideIcon; -}; - -export const ArtifactAction = ({ - tooltip, - label, - icon: Icon, - children, - className, - size = "sm", - variant = "ghost", - ...props -}: ArtifactActionProps) => { - const button = ( - - ); - - if (tooltip) { - return ( - - - {button} - -

{tooltip}

-
-
-
- ); - } - - return button; -}; - -export type ArtifactContentProps = HTMLAttributes; - -export const ArtifactContent = ({ - className, - ...props -}: ArtifactContentProps) => ( -
-); diff --git a/examples/nextjs-ai-elements-realtime/components/ai-elements/canvas.tsx b/examples/nextjs-ai-elements-realtime/components/ai-elements/canvas.tsx deleted file mode 100644 index 5aa83cb5e7..0000000000 --- a/examples/nextjs-ai-elements-realtime/components/ai-elements/canvas.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { Background, ReactFlow, type ReactFlowProps } from "@xyflow/react"; -import type { ReactNode } from "react"; -import "@xyflow/react/dist/style.css"; - -type CanvasProps = ReactFlowProps & { - children?: ReactNode; -}; - -export const Canvas = ({ children, ...props }: CanvasProps) => ( - - - {children} - -); diff --git a/examples/nextjs-ai-elements-realtime/components/ai-elements/checkpoint.tsx b/examples/nextjs-ai-elements-realtime/components/ai-elements/checkpoint.tsx deleted file mode 100644 index d9a5d326c8..0000000000 --- a/examples/nextjs-ai-elements-realtime/components/ai-elements/checkpoint.tsx +++ /dev/null @@ -1,68 +0,0 @@ -"use client"; - -import { Button } from "@/components/ui/button"; -import { Separator } from "@/components/ui/separator"; -import { - Tooltip, - TooltipContent, - TooltipTrigger, -} from "@/components/ui/tooltip"; -import { cn } from "@/lib/utils"; -import { BookmarkIcon, type LucideProps } from "lucide-react"; -import type { ComponentProps, HTMLAttributes } from "react"; - -export type CheckpointProps = HTMLAttributes; - -export const Checkpoint = ({ - className, - children, - ...props -}: CheckpointProps) => ( -
- {children} - -
-); - -export type CheckpointIconProps = LucideProps; - -export const CheckpointIcon = ({ - className, - children, - ...props -}: CheckpointIconProps) => - children ?? ( - - ); - -export type CheckpointTriggerProps = ComponentProps & { - tooltip?: string; -}; - -export const CheckpointTrigger = ({ - children, - className, - variant = "ghost", - size = "sm", - tooltip, - ...props -}: CheckpointTriggerProps) => - tooltip ? ( - - - - - - {tooltip} - - - ) : ( - - ); diff --git a/examples/nextjs-ai-elements-realtime/components/ai-elements/confirmation.tsx b/examples/nextjs-ai-elements-realtime/components/ai-elements/confirmation.tsx deleted file mode 100644 index 2ec0aab578..0000000000 --- a/examples/nextjs-ai-elements-realtime/components/ai-elements/confirmation.tsx +++ /dev/null @@ -1,176 +0,0 @@ -"use client"; - -import { Alert, AlertDescription } from "@/components/ui/alert"; -import { Button } from "@/components/ui/button"; -import { cn } from "@/lib/utils"; -import type { ToolUIPart } from "ai"; -import { - type ComponentProps, - createContext, - type ReactNode, - useContext, -} from "react"; - -type ToolUIPartApproval = - | { - id: string; - approved?: never; - reason?: never; - } - | { - id: string; - approved: boolean; - reason?: string; - } - | { - id: string; - approved: true; - reason?: string; - } - | { - id: string; - approved: true; - reason?: string; - } - | { - id: string; - approved: false; - reason?: string; - } - | undefined; - -type ConfirmationContextValue = { - approval: ToolUIPartApproval; - state: ToolUIPart["state"]; -}; - -const ConfirmationContext = createContext( - null -); - -const useConfirmation = () => { - const context = useContext(ConfirmationContext); - - if (!context) { - throw new Error("Confirmation components must be used within Confirmation"); - } - - return context; -}; - -export type ConfirmationProps = ComponentProps & { - approval?: ToolUIPartApproval; - state: ToolUIPart["state"]; -}; - -export const Confirmation = ({ - className, - approval, - state, - ...props -}: ConfirmationProps) => { - if (!approval || state === "input-streaming" || state === "input-available") { - return null; - } - - return ( - - - - ); -}; - -export type ConfirmationTitleProps = ComponentProps; - -export const ConfirmationTitle = ({ - className, - ...props -}: ConfirmationTitleProps) => ( - -); - -export type ConfirmationRequestProps = { - children?: ReactNode; -}; - -export const ConfirmationRequest = ({ children }: ConfirmationRequestProps) => { - const { state } = useConfirmation(); - - // Only show when approval is requested - if (state !== "approval-requested") { - return null; - } - - return children; -}; - -export type ConfirmationAcceptedProps = { - children?: ReactNode; -}; - -export const ConfirmationAccepted = ({ - children, -}: ConfirmationAcceptedProps) => { - const { approval, state } = useConfirmation(); - - // Only show when approved and in response states - if ( - !approval?.approved || - (state !== "approval-responded" && - state !== "output-denied" && - state !== "output-available") - ) { - return null; - } - - return children; -}; - -export type ConfirmationRejectedProps = { - children?: ReactNode; -}; - -export const ConfirmationRejected = ({ - children, -}: ConfirmationRejectedProps) => { - const { approval, state } = useConfirmation(); - - // Only show when rejected and in response states - if ( - approval?.approved !== false || - (state !== "approval-responded" && - state !== "output-denied" && - state !== "output-available") - ) { - return null; - } - - return children; -}; - -export type ConfirmationActionsProps = ComponentProps<"div">; - -export const ConfirmationActions = ({ - className, - ...props -}: ConfirmationActionsProps) => { - const { state } = useConfirmation(); - - // Only show when approval is requested - if (state !== "approval-requested") { - return null; - } - - return ( -
- ); -}; - -export type ConfirmationActionProps = ComponentProps; - -export const ConfirmationAction = (props: ConfirmationActionProps) => ( - - ); -}; - -export type InlineCitationCarouselNextProps = ComponentProps<"button">; - -export const InlineCitationCarouselNext = ({ - className, - ...props -}: InlineCitationCarouselNextProps) => { - const api = useCarouselApi(); - - const handleClick = useCallback(() => { - if (api) { - api.scrollNext(); - } - }, [api]); - - return ( - - ); -}; - -export type InlineCitationSourceProps = ComponentProps<"div"> & { - title?: string; - url?: string; - description?: string; -}; - -export const InlineCitationSource = ({ - title, - url, - description, - className, - children, - ...props -}: InlineCitationSourceProps) => ( -
- {title && ( -

{title}

- )} - {url && ( -

{url}

- )} - {description && ( -

- {description} -

- )} - {children} -
-); - -export type InlineCitationQuoteProps = ComponentProps<"blockquote">; - -export const InlineCitationQuote = ({ - children, - className, - ...props -}: InlineCitationQuoteProps) => ( -
- {children} -
-); diff --git a/examples/nextjs-ai-elements-realtime/components/ai-elements/model-selector.tsx b/examples/nextjs-ai-elements-realtime/components/ai-elements/model-selector.tsx deleted file mode 100644 index ef6ebd7e8b..0000000000 --- a/examples/nextjs-ai-elements-realtime/components/ai-elements/model-selector.tsx +++ /dev/null @@ -1,205 +0,0 @@ -import { - Command, - CommandDialog, - CommandEmpty, - CommandGroup, - CommandInput, - CommandItem, - CommandList, - CommandSeparator, - CommandShortcut, -} from "@/components/ui/command"; -import { - Dialog, - DialogContent, - DialogTitle, - DialogTrigger, -} from "@/components/ui/dialog"; -import { cn } from "@/lib/utils"; -import type { ComponentProps, ReactNode } from "react"; - -export type ModelSelectorProps = ComponentProps; - -export const ModelSelector = (props: ModelSelectorProps) => ( - -); - -export type ModelSelectorTriggerProps = ComponentProps; - -export const ModelSelectorTrigger = (props: ModelSelectorTriggerProps) => ( - -); - -export type ModelSelectorContentProps = ComponentProps & { - title?: ReactNode; -}; - -export const ModelSelectorContent = ({ - className, - children, - title = "Model Selector", - ...props -}: ModelSelectorContentProps) => ( - - {title} - - {children} - - -); - -export type ModelSelectorDialogProps = ComponentProps; - -export const ModelSelectorDialog = (props: ModelSelectorDialogProps) => ( - -); - -export type ModelSelectorInputProps = ComponentProps; - -export const ModelSelectorInput = ({ - className, - ...props -}: ModelSelectorInputProps) => ( - -); - -export type ModelSelectorListProps = ComponentProps; - -export const ModelSelectorList = (props: ModelSelectorListProps) => ( - -); - -export type ModelSelectorEmptyProps = ComponentProps; - -export const ModelSelectorEmpty = (props: ModelSelectorEmptyProps) => ( - -); - -export type ModelSelectorGroupProps = ComponentProps; - -export const ModelSelectorGroup = (props: ModelSelectorGroupProps) => ( - -); - -export type ModelSelectorItemProps = ComponentProps; - -export const ModelSelectorItem = (props: ModelSelectorItemProps) => ( - -); - -export type ModelSelectorShortcutProps = ComponentProps; - -export const ModelSelectorShortcut = (props: ModelSelectorShortcutProps) => ( - -); - -export type ModelSelectorSeparatorProps = ComponentProps< - typeof CommandSeparator ->; - -export const ModelSelectorSeparator = (props: ModelSelectorSeparatorProps) => ( - -); - -export type ModelSelectorLogoProps = Omit< - ComponentProps<"img">, - "src" | "alt" -> & { - provider: - | "moonshotai-cn" - | "lucidquery" - | "moonshotai" - | "zai-coding-plan" - | "alibaba" - | "xai" - | "vultr" - | "nvidia" - | "upstage" - | "groq" - | "github-copilot" - | "mistral" - | "vercel" - | "nebius" - | "deepseek" - | "alibaba-cn" - | "google-vertex-anthropic" - | "venice" - | "chutes" - | "cortecs" - | "github-models" - | "togetherai" - | "azure" - | "baseten" - | "huggingface" - | "opencode" - | "fastrouter" - | "google" - | "google-vertex" - | "cloudflare-workers-ai" - | "inception" - | "wandb" - | "openai" - | "zhipuai-coding-plan" - | "perplexity" - | "openrouter" - | "zenmux" - | "v0" - | "iflowcn" - | "synthetic" - | "deepinfra" - | "zhipuai" - | "submodel" - | "zai" - | "inference" - | "requesty" - | "morph" - | "lmstudio" - | "anthropic" - | "aihubmix" - | "fireworks-ai" - | "modelscope" - | "llama" - | "scaleway" - | "amazon-bedrock" - | "cerebras" - | (string & {}); -}; - -export const ModelSelectorLogo = ({ - provider, - className, - ...props -}: ModelSelectorLogoProps) => ( - {`${provider} -); - -export type ModelSelectorLogoGroupProps = ComponentProps<"div">; - -export const ModelSelectorLogoGroup = ({ - className, - ...props -}: ModelSelectorLogoGroupProps) => ( -
img]:rounded-full [&>img]:bg-background [&>img]:p-px [&>img]:ring-1 dark:[&>img]:bg-foreground", - className - )} - {...props} - /> -); - -export type ModelSelectorNameProps = ComponentProps<"span">; - -export const ModelSelectorName = ({ - className, - ...props -}: ModelSelectorNameProps) => ( - -); diff --git a/examples/nextjs-ai-elements-realtime/components/ai-elements/node.tsx b/examples/nextjs-ai-elements-realtime/components/ai-elements/node.tsx deleted file mode 100644 index 75ac59a153..0000000000 --- a/examples/nextjs-ai-elements-realtime/components/ai-elements/node.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import { - Card, - CardAction, - CardContent, - CardDescription, - CardFooter, - CardHeader, - CardTitle, -} from "@/components/ui/card"; -import { cn } from "@/lib/utils"; -import { Handle, Position } from "@xyflow/react"; -import type { ComponentProps } from "react"; - -export type NodeProps = ComponentProps & { - handles: { - target: boolean; - source: boolean; - }; -}; - -export const Node = ({ handles, className, ...props }: NodeProps) => ( - - {handles.target && } - {handles.source && } - {props.children} - -); - -export type NodeHeaderProps = ComponentProps; - -export const NodeHeader = ({ className, ...props }: NodeHeaderProps) => ( - -); - -export type NodeTitleProps = ComponentProps; - -export const NodeTitle = (props: NodeTitleProps) => ; - -export type NodeDescriptionProps = ComponentProps; - -export const NodeDescription = (props: NodeDescriptionProps) => ( - -); - -export type NodeActionProps = ComponentProps; - -export const NodeAction = (props: NodeActionProps) => ; - -export type NodeContentProps = ComponentProps; - -export const NodeContent = ({ className, ...props }: NodeContentProps) => ( - -); - -export type NodeFooterProps = ComponentProps; - -export const NodeFooter = ({ className, ...props }: NodeFooterProps) => ( - -); diff --git a/examples/nextjs-ai-elements-realtime/components/ai-elements/open-in-chat.tsx b/examples/nextjs-ai-elements-realtime/components/ai-elements/open-in-chat.tsx deleted file mode 100644 index 0c62a6ac4a..0000000000 --- a/examples/nextjs-ai-elements-realtime/components/ai-elements/open-in-chat.tsx +++ /dev/null @@ -1,365 +0,0 @@ -"use client"; - -import { Button } from "@/components/ui/button"; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuSeparator, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; -import { cn } from "@/lib/utils"; -import { - ChevronDownIcon, - ExternalLinkIcon, - MessageCircleIcon, -} from "lucide-react"; -import { type ComponentProps, createContext, useContext } from "react"; - -const providers = { - github: { - title: "Open in GitHub", - createUrl: (url: string) => url, - icon: ( - - GitHub - - - ), - }, - scira: { - title: "Open in Scira", - createUrl: (q: string) => - `https://scira.ai/?${new URLSearchParams({ - q, - })}`, - icon: ( - - Scira AI - - - - - - - - - ), - }, - chatgpt: { - title: "Open in ChatGPT", - createUrl: (prompt: string) => - `https://chatgpt.com/?${new URLSearchParams({ - hints: "search", - prompt, - })}`, - icon: ( - - OpenAI - - - ), - }, - claude: { - title: "Open in Claude", - createUrl: (q: string) => - `https://claude.ai/new?${new URLSearchParams({ - q, - })}`, - icon: ( - - Claude - - - ), - }, - t3: { - title: "Open in T3 Chat", - createUrl: (q: string) => - `https://t3.chat/new?${new URLSearchParams({ - q, - })}`, - icon: , - }, - v0: { - title: "Open in v0", - createUrl: (q: string) => - `https://v0.app?${new URLSearchParams({ - q, - })}`, - icon: ( - - v0 - - - - ), - }, - cursor: { - title: "Open in Cursor", - createUrl: (text: string) => { - const url = new URL("https://cursor.com/link/prompt"); - url.searchParams.set("text", text); - return url.toString(); - }, - icon: ( - - Cursor - - - ), - }, -}; - -const OpenInContext = createContext<{ query: string } | undefined>(undefined); - -const useOpenInContext = () => { - const context = useContext(OpenInContext); - if (!context) { - throw new Error("OpenIn components must be used within an OpenIn provider"); - } - return context; -}; - -export type OpenInProps = ComponentProps & { - query: string; -}; - -export const OpenIn = ({ query, ...props }: OpenInProps) => ( - - - -); - -export type OpenInContentProps = ComponentProps; - -export const OpenInContent = ({ className, ...props }: OpenInContentProps) => ( - -); - -export type OpenInItemProps = ComponentProps; - -export const OpenInItem = (props: OpenInItemProps) => ( - -); - -export type OpenInLabelProps = ComponentProps; - -export const OpenInLabel = (props: OpenInLabelProps) => ( - -); - -export type OpenInSeparatorProps = ComponentProps; - -export const OpenInSeparator = (props: OpenInSeparatorProps) => ( - -); - -export type OpenInTriggerProps = ComponentProps; - -export const OpenInTrigger = ({ children, ...props }: OpenInTriggerProps) => ( - - {children ?? ( - - )} - -); - -export type OpenInChatGPTProps = ComponentProps; - -export const OpenInChatGPT = (props: OpenInChatGPTProps) => { - const { query } = useOpenInContext(); - return ( - - - {providers.chatgpt.icon} - {providers.chatgpt.title} - - - - ); -}; - -export type OpenInClaudeProps = ComponentProps; - -export const OpenInClaude = (props: OpenInClaudeProps) => { - const { query } = useOpenInContext(); - return ( - - - {providers.claude.icon} - {providers.claude.title} - - - - ); -}; - -export type OpenInT3Props = ComponentProps; - -export const OpenInT3 = (props: OpenInT3Props) => { - const { query } = useOpenInContext(); - return ( - - - {providers.t3.icon} - {providers.t3.title} - - - - ); -}; - -export type OpenInSciraProps = ComponentProps; - -export const OpenInScira = (props: OpenInSciraProps) => { - const { query } = useOpenInContext(); - return ( - - - {providers.scira.icon} - {providers.scira.title} - - - - ); -}; - -export type OpenInv0Props = ComponentProps; - -export const OpenInv0 = (props: OpenInv0Props) => { - const { query } = useOpenInContext(); - return ( - - - {providers.v0.icon} - {providers.v0.title} - - - - ); -}; - -export type OpenInCursorProps = ComponentProps; - -export const OpenInCursor = (props: OpenInCursorProps) => { - const { query } = useOpenInContext(); - return ( - - - {providers.cursor.icon} - {providers.cursor.title} - - - - ); -}; diff --git a/examples/nextjs-ai-elements-realtime/components/ai-elements/panel.tsx b/examples/nextjs-ai-elements-realtime/components/ai-elements/panel.tsx deleted file mode 100644 index 059cb7ac21..0000000000 --- a/examples/nextjs-ai-elements-realtime/components/ai-elements/panel.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { cn } from "@/lib/utils"; -import { Panel as PanelPrimitive } from "@xyflow/react"; -import type { ComponentProps } from "react"; - -type PanelProps = ComponentProps; - -export const Panel = ({ className, ...props }: PanelProps) => ( - -); diff --git a/examples/nextjs-ai-elements-realtime/components/ai-elements/plan.tsx b/examples/nextjs-ai-elements-realtime/components/ai-elements/plan.tsx deleted file mode 100644 index be04d883be..0000000000 --- a/examples/nextjs-ai-elements-realtime/components/ai-elements/plan.tsx +++ /dev/null @@ -1,142 +0,0 @@ -"use client"; - -import { Button } from "@/components/ui/button"; -import { - Card, - CardAction, - CardContent, - CardDescription, - CardFooter, - CardHeader, - CardTitle, -} from "@/components/ui/card"; -import { - Collapsible, - CollapsibleContent, - CollapsibleTrigger, -} from "@/components/ui/collapsible"; -import { cn } from "@/lib/utils"; -import { ChevronsUpDownIcon } from "lucide-react"; -import type { ComponentProps } from "react"; -import { createContext, useContext } from "react"; -import { Shimmer } from "./shimmer"; - -type PlanContextValue = { - isStreaming: boolean; -}; - -const PlanContext = createContext(null); - -const usePlan = () => { - const context = useContext(PlanContext); - if (!context) { - throw new Error("Plan components must be used within Plan"); - } - return context; -}; - -export type PlanProps = ComponentProps & { - isStreaming?: boolean; -}; - -export const Plan = ({ - className, - isStreaming = false, - children, - ...props -}: PlanProps) => ( - - - {children} - - -); - -export type PlanHeaderProps = ComponentProps; - -export const PlanHeader = ({ className, ...props }: PlanHeaderProps) => ( - -); - -export type PlanTitleProps = Omit< - ComponentProps, - "children" -> & { - children: string; -}; - -export const PlanTitle = ({ children, ...props }: PlanTitleProps) => { - const { isStreaming } = usePlan(); - - return ( - - {isStreaming ? {children} : children} - - ); -}; - -export type PlanDescriptionProps = Omit< - ComponentProps, - "children" -> & { - children: string; -}; - -export const PlanDescription = ({ - className, - children, - ...props -}: PlanDescriptionProps) => { - const { isStreaming } = usePlan(); - - return ( - - {isStreaming ? {children} : children} - - ); -}; - -export type PlanActionProps = ComponentProps; - -export const PlanAction = (props: PlanActionProps) => ( - -); - -export type PlanContentProps = ComponentProps; - -export const PlanContent = (props: PlanContentProps) => ( - - - -); - -export type PlanFooterProps = ComponentProps<"div">; - -export const PlanFooter = (props: PlanFooterProps) => ( - -); - -export type PlanTriggerProps = ComponentProps; - -export const PlanTrigger = ({ className, ...props }: PlanTriggerProps) => ( - - - -); diff --git a/examples/nextjs-ai-elements-realtime/components/ai-elements/queue.tsx b/examples/nextjs-ai-elements-realtime/components/ai-elements/queue.tsx deleted file mode 100644 index 0c91d1300b..0000000000 --- a/examples/nextjs-ai-elements-realtime/components/ai-elements/queue.tsx +++ /dev/null @@ -1,274 +0,0 @@ -"use client"; - -import { Button } from "@/components/ui/button"; -import { - Collapsible, - CollapsibleContent, - CollapsibleTrigger, -} from "@/components/ui/collapsible"; -import { ScrollArea } from "@/components/ui/scroll-area"; -import { cn } from "@/lib/utils"; -import { ChevronDownIcon, PaperclipIcon } from "lucide-react"; -import type { ComponentProps } from "react"; - -export type QueueMessagePart = { - type: string; - text?: string; - url?: string; - filename?: string; - mediaType?: string; -}; - -export type QueueMessage = { - id: string; - parts: QueueMessagePart[]; -}; - -export type QueueTodo = { - id: string; - title: string; - description?: string; - status?: "pending" | "completed"; -}; - -export type QueueItemProps = ComponentProps<"li">; - -export const QueueItem = ({ className, ...props }: QueueItemProps) => ( -
  • -); - -export type QueueItemIndicatorProps = ComponentProps<"span"> & { - completed?: boolean; -}; - -export const QueueItemIndicator = ({ - completed = false, - className, - ...props -}: QueueItemIndicatorProps) => ( - -); - -export type QueueItemContentProps = ComponentProps<"span"> & { - completed?: boolean; -}; - -export const QueueItemContent = ({ - completed = false, - className, - ...props -}: QueueItemContentProps) => ( - -); - -export type QueueItemDescriptionProps = ComponentProps<"div"> & { - completed?: boolean; -}; - -export const QueueItemDescription = ({ - completed = false, - className, - ...props -}: QueueItemDescriptionProps) => ( -
    -); - -export type QueueItemActionsProps = ComponentProps<"div">; - -export const QueueItemActions = ({ - className, - ...props -}: QueueItemActionsProps) => ( -
    -); - -export type QueueItemActionProps = Omit< - ComponentProps, - "variant" | "size" ->; - -export const QueueItemAction = ({ - className, - ...props -}: QueueItemActionProps) => ( - - -); - -// QueueSectionLabel - label content with icon and count -export type QueueSectionLabelProps = ComponentProps<"span"> & { - count?: number; - label: string; - icon?: React.ReactNode; -}; - -export const QueueSectionLabel = ({ - count, - label, - icon, - className, - ...props -}: QueueSectionLabelProps) => ( - - - {icon} - - {count} {label} - - -); - -// QueueSectionContent - collapsible content area -export type QueueSectionContentProps = ComponentProps< - typeof CollapsibleContent ->; - -export const QueueSectionContent = ({ - className, - ...props -}: QueueSectionContentProps) => ( - -); - -export type QueueProps = ComponentProps<"div">; - -export const Queue = ({ className, ...props }: QueueProps) => ( -
    -); diff --git a/examples/nextjs-ai-elements-realtime/components/ai-elements/task.tsx b/examples/nextjs-ai-elements-realtime/components/ai-elements/task.tsx deleted file mode 100644 index eeb802c61d..0000000000 --- a/examples/nextjs-ai-elements-realtime/components/ai-elements/task.tsx +++ /dev/null @@ -1,87 +0,0 @@ -"use client"; - -import { - Collapsible, - CollapsibleContent, - CollapsibleTrigger, -} from "@/components/ui/collapsible"; -import { cn } from "@/lib/utils"; -import { ChevronDownIcon, SearchIcon } from "lucide-react"; -import type { ComponentProps } from "react"; - -export type TaskItemFileProps = ComponentProps<"div">; - -export const TaskItemFile = ({ - children, - className, - ...props -}: TaskItemFileProps) => ( -
    - {children} -
    -); - -export type TaskItemProps = ComponentProps<"div">; - -export const TaskItem = ({ children, className, ...props }: TaskItemProps) => ( -
    - {children} -
    -); - -export type TaskProps = ComponentProps; - -export const Task = ({ - defaultOpen = true, - className, - ...props -}: TaskProps) => ( - -); - -export type TaskTriggerProps = ComponentProps & { - title: string; -}; - -export const TaskTrigger = ({ - children, - className, - title, - ...props -}: TaskTriggerProps) => ( - - {children ?? ( -
    - -

    {title}

    - -
    - )} -
    -); - -export type TaskContentProps = ComponentProps; - -export const TaskContent = ({ - children, - className, - ...props -}: TaskContentProps) => ( - -
    - {children} -
    -
    -); diff --git a/examples/nextjs-ai-elements-realtime/components/ai-elements/toolbar.tsx b/examples/nextjs-ai-elements-realtime/components/ai-elements/toolbar.tsx deleted file mode 100644 index b55aa8895d..0000000000 --- a/examples/nextjs-ai-elements-realtime/components/ai-elements/toolbar.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { cn } from "@/lib/utils"; -import { NodeToolbar, Position } from "@xyflow/react"; -import type { ComponentProps } from "react"; - -type ToolbarProps = ComponentProps; - -export const Toolbar = ({ className, ...props }: ToolbarProps) => ( - -); diff --git a/examples/nextjs-ai-elements-realtime/components/ai-elements/web-preview.tsx b/examples/nextjs-ai-elements-realtime/components/ai-elements/web-preview.tsx deleted file mode 100644 index 8f0ab5a530..0000000000 --- a/examples/nextjs-ai-elements-realtime/components/ai-elements/web-preview.tsx +++ /dev/null @@ -1,263 +0,0 @@ -"use client"; - -import { Button } from "@/components/ui/button"; -import { - Collapsible, - CollapsibleContent, - CollapsibleTrigger, -} from "@/components/ui/collapsible"; -import { Input } from "@/components/ui/input"; -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from "@/components/ui/tooltip"; -import { cn } from "@/lib/utils"; -import { ChevronDownIcon } from "lucide-react"; -import type { ComponentProps, ReactNode } from "react"; -import { createContext, useContext, useEffect, useState } from "react"; - -export type WebPreviewContextValue = { - url: string; - setUrl: (url: string) => void; - consoleOpen: boolean; - setConsoleOpen: (open: boolean) => void; -}; - -const WebPreviewContext = createContext(null); - -const useWebPreview = () => { - const context = useContext(WebPreviewContext); - if (!context) { - throw new Error("WebPreview components must be used within a WebPreview"); - } - return context; -}; - -export type WebPreviewProps = ComponentProps<"div"> & { - defaultUrl?: string; - onUrlChange?: (url: string) => void; -}; - -export const WebPreview = ({ - className, - children, - defaultUrl = "", - onUrlChange, - ...props -}: WebPreviewProps) => { - const [url, setUrl] = useState(defaultUrl); - const [consoleOpen, setConsoleOpen] = useState(false); - - const handleUrlChange = (newUrl: string) => { - setUrl(newUrl); - onUrlChange?.(newUrl); - }; - - const contextValue: WebPreviewContextValue = { - url, - setUrl: handleUrlChange, - consoleOpen, - setConsoleOpen, - }; - - return ( - -
    - {children} -
    -
    - ); -}; - -export type WebPreviewNavigationProps = ComponentProps<"div">; - -export const WebPreviewNavigation = ({ - className, - children, - ...props -}: WebPreviewNavigationProps) => ( -
    - {children} -
    -); - -export type WebPreviewNavigationButtonProps = ComponentProps & { - tooltip?: string; -}; - -export const WebPreviewNavigationButton = ({ - onClick, - disabled, - tooltip, - children, - ...props -}: WebPreviewNavigationButtonProps) => ( - - - - - - -

    {tooltip}

    -
    -
    -
    -); - -export type WebPreviewUrlProps = ComponentProps; - -export const WebPreviewUrl = ({ - value, - onChange, - onKeyDown, - ...props -}: WebPreviewUrlProps) => { - const { url, setUrl } = useWebPreview(); - const [inputValue, setInputValue] = useState(url); - - // Sync input value with context URL when it changes externally - useEffect(() => { - setInputValue(url); - }, [url]); - - const handleChange = (event: React.ChangeEvent) => { - setInputValue(event.target.value); - onChange?.(event); - }; - - const handleKeyDown = (event: React.KeyboardEvent) => { - if (event.key === "Enter") { - const target = event.target as HTMLInputElement; - setUrl(target.value); - } - onKeyDown?.(event); - }; - - return ( - - ); -}; - -export type WebPreviewBodyProps = ComponentProps<"iframe"> & { - loading?: ReactNode; -}; - -export const WebPreviewBody = ({ - className, - loading, - src, - ...props -}: WebPreviewBodyProps) => { - const { url } = useWebPreview(); - - return ( -
    -