-
-
-
+
+
)
}
diff --git a/apps/www/components/component-preview.tsx b/apps/www/components/component-preview.tsx
index 44ad7863..7857b256 100644
--- a/apps/www/components/component-preview.tsx
+++ b/apps/www/components/component-preview.tsx
@@ -2,6 +2,7 @@ import Image from "next/image"
import { ComponentPreviewTabs } from "@/components/component-preview-tabs"
import { ComponentSource } from "@/components/component-source"
+import { RegistryPreviewProvider } from "@/components/registry-preview-provider"
import { Index } from "@/registry/__index__"
export function ComponentPreview({
@@ -63,7 +64,11 @@ export function ComponentPreview({
className={className}
align={align}
hideCode={hideCode}
- component={
}
+ component={
+
+
+
+ }
source={
}
marginOff={marginOff}
{...props}
diff --git a/apps/www/components/registry-preview-provider.tsx b/apps/www/components/registry-preview-provider.tsx
new file mode 100644
index 00000000..cb36f1d3
--- /dev/null
+++ b/apps/www/components/registry-preview-provider.tsx
@@ -0,0 +1,8 @@
+"use client"
+
+import type { ReactNode } from "react"
+import { ConversationProvider } from "@elevenlabs/react"
+
+export function RegistryPreviewProvider({ children }: { children: ReactNode }) {
+ return
{children}
+}
diff --git a/apps/www/package.json b/apps/www/package.json
index 390e1893..13d717e9 100644
--- a/apps/www/package.json
+++ b/apps/www/package.json
@@ -22,9 +22,9 @@
"@dnd-kit/modifiers": "^9.0.0",
"@dnd-kit/sortable": "^10.0.0",
"@dnd-kit/utilities": "^3.2.2",
- "@elevenlabs/client": "^0.12.0",
+ "@elevenlabs/client": "^1.7.0",
"@elevenlabs/elevenlabs-js": "^2.20.1",
- "@elevenlabs/react": "^0.12.0",
+ "@elevenlabs/react": "^1.6.0",
"@faker-js/faker": "^8.2.0",
"@hookform/resolvers": "^3.10.0",
"@radix-ui/react-accessible-icon": "^1.1.1",
diff --git a/apps/www/registry/elevenlabs-ui/blocks/voice-chat-01/page.tsx b/apps/www/registry/elevenlabs-ui/blocks/voice-chat-01/page.tsx
index 87d52958..17ea9a58 100644
--- a/apps/www/registry/elevenlabs-ui/blocks/voice-chat-01/page.tsx
+++ b/apps/www/registry/elevenlabs-ui/blocks/voice-chat-01/page.tsx
@@ -2,7 +2,11 @@
import { useCallback, useEffect, useRef, useState } from "react"
import type { ComponentProps } from "react"
-import { useConversation } from "@elevenlabs/react"
+import {
+ useConversation,
+ useConversationControls,
+ useConversationStatus,
+} from "@elevenlabs/react"
import {
AudioLinesIcon,
CheckIcon,
@@ -107,25 +111,29 @@ const ChatAction = ({
}
export default function Page() {
+ const { status } = useConversationStatus()
+ const {
+ startSession,
+ endSession,
+ sendUserMessage,
+ getInputVolume,
+ getOutputVolume,
+ } = useConversationControls()
const [messages, setMessages] = useState
([])
- const [agentState, setAgentState] = useState<
- "disconnected" | "connecting" | "connected" | "disconnecting" | null
- >("disconnected")
const [textInput, setTextInput] = useState("")
const [copiedIndex, setCopiedIndex] = useState(null)
const [errorMessage, setErrorMessage] = useState(null)
const mediaStreamRef = useRef(null)
const isTextOnlyModeRef = useRef(true)
- const conversation = useConversation({
+ // Keep useConversation for callbacks that need access to local state
+ useConversation({
onConnect: () => {
- // Only clear messages for voice mode
if (!isTextOnlyModeRef.current) {
setMessages([])
}
},
onDisconnect: () => {
- // Only clear messages for voice mode
if (!isTextOnlyModeRef.current) {
setMessages([])
}
@@ -141,10 +149,6 @@ export default function Page() {
},
onError: (error) => {
console.error("Error:", error)
- setAgentState("disconnected")
- },
- onDebug: (debug) => {
- console.log("Debug:", debug)
},
})
@@ -180,7 +184,7 @@ export default function Page() {
await getMicStream()
}
- await conversation.startSession({
+ startSession({
agentId: DEFAULT_AGENT.agentId,
connectionType: textOnly ? "websocket" : "webrtc",
overrides: {
@@ -191,35 +195,31 @@ export default function Page() {
firstMessage: textOnly ? "" : undefined,
},
},
- onStatusChange: (status) => setAgentState(status.status),
})
} catch (error) {
console.error(error)
- setAgentState("disconnected")
setMessages([])
}
},
- [conversation, getMicStream]
+ [startSession, getMicStream]
)
const handleCall = useCallback(async () => {
- if (agentState === "disconnected" || agentState === null) {
- setAgentState("connecting")
+ if (status === "disconnected" || status === "error") {
try {
await startConversation(false)
} catch {
- setAgentState("disconnected")
+ // getMicStream error already handled
}
- } else if (agentState === "connected") {
- conversation.endSession()
- setAgentState("disconnected")
+ } else if (status === "connected") {
+ endSession()
if (mediaStreamRef.current) {
mediaStreamRef.current.getTracks().forEach((t) => t.stop())
mediaStreamRef.current = null
}
}
- }, [agentState, conversation, startConversation])
+ }, [status, endSession, startConversation])
const handleTextInputChange = useCallback(
(e: React.ChangeEvent) => {
@@ -233,24 +233,21 @@ export default function Page() {
const messageToSend = textInput
- if (agentState === "disconnected" || agentState === null) {
+ if (status === "disconnected" || status === "error") {
const userMessage: ChatMessage = {
role: "user",
content: messageToSend,
}
setTextInput("")
- setAgentState("connecting")
try {
await startConversation(true, true)
- // Add message once converstation started
setMessages([userMessage])
- // Send message after connection is established
- conversation.sendUserMessage(messageToSend)
+ sendUserMessage(messageToSend)
} catch (error) {
console.error("Failed to start conversation:", error)
}
- } else if (agentState === "connected") {
+ } else if (status === "connected") {
const newMessage: ChatMessage = {
role: "user",
content: messageToSend,
@@ -258,9 +255,9 @@ export default function Page() {
setMessages((prev) => [...prev, newMessage])
setTextInput("")
- conversation.sendUserMessage(messageToSend)
+ sendUserMessage(messageToSend)
}
- }, [textInput, agentState, conversation, startConversation])
+ }, [textInput, status, startConversation, sendUserMessage])
const handleKeyDown = useCallback(
(e: React.KeyboardEvent) => {
@@ -280,19 +277,26 @@ export default function Page() {
}
}, [])
- const isCallActive = agentState === "connected"
- const isTransitioning =
- agentState === "connecting" || agentState === "disconnecting"
+ const isCallActive = status === "connected"
+ const isTransitioning = status === "connecting"
- const getInputVolume = useCallback(() => {
- const rawValue = conversation.getInputVolume?.() ?? 0
- return Math.min(1.0, Math.pow(rawValue, 0.5) * 2.5)
- }, [conversation])
+ const scaledInputVolume = useCallback(() => {
+ try {
+ const rawValue = getInputVolume() ?? 0
+ return Math.min(1.0, Math.pow(rawValue, 0.5) * 2.5)
+ } catch {
+ return 0
+ }
+ }, [getInputVolume])
- const getOutputVolume = useCallback(() => {
- const rawValue = conversation.getOutputVolume?.() ?? 0
- return Math.min(1.0, Math.pow(rawValue, 0.5) * 2.5)
- }, [conversation])
+ const scaledOutputVolume = useCallback(() => {
+ try {
+ const rawValue = getOutputVolume() ?? 0
+ return Math.min(1.0, Math.pow(rawValue, 0.5) * 2.5)
+ } catch {
+ return 0
+ }
+ }, [getOutputVolume])
return (
@@ -317,17 +321,14 @@ export default function Page() {
{errorMessage ? (
{errorMessage}
- ) : agentState === "disconnected" || agentState === null ? (
+ ) : status === "disconnected" || status === "error" ? (
Tap to start voice chat
- ) : agentState === "connected" ? (
+ ) : status === "connected" ? (
Connected
) : isTransitioning ? (
-
+
) : null}
@@ -335,7 +336,7 @@ export default function Page() {
}
title={
- agentState === "connecting" ? (
+ status === "connecting" ? (
- ) : agentState === "connected" ? (
+ ) : status === "connected" ? (
) : (
"Start a conversation"
)
}
description={
- agentState === "connecting"
+ status === "connecting"
? "Connecting..."
- : agentState === "connected"
+ : status === "connected"
? "Ready to chat"
: "Type a message or tap the voice button"
}
diff --git a/apps/www/registry/elevenlabs-ui/blocks/voice-chat-02/page.tsx b/apps/www/registry/elevenlabs-ui/blocks/voice-chat-02/page.tsx
index 45febc21..63a72f88 100644
--- a/apps/www/registry/elevenlabs-ui/blocks/voice-chat-02/page.tsx
+++ b/apps/www/registry/elevenlabs-ui/blocks/voice-chat-02/page.tsx
@@ -1,7 +1,10 @@
"use client"
import { useCallback, useState } from "react"
-import { useConversation } from "@elevenlabs/react"
+import {
+ useConversationControls,
+ useConversationStatus,
+} from "@elevenlabs/react"
import { AnimatePresence, motion } from "framer-motion"
import { Loader2Icon, PhoneIcon, PhoneOffIcon } from "lucide-react"
@@ -17,68 +20,56 @@ const DEFAULT_AGENT = {
description: "Tap to start voice chat",
}
-type AgentState =
- | "disconnected"
- | "connecting"
- | "connected"
- | "disconnecting"
- | null
-
export default function Page() {
- const [agentState, setAgentState] = useState
("disconnected")
+ const { status } = useConversationStatus()
+ const { startSession, endSession, getInputVolume, getOutputVolume } =
+ useConversationControls()
const [errorMessage, setErrorMessage] = useState(null)
- const conversation = useConversation({
- onConnect: () => console.log("Connected"),
- onDisconnect: () => console.log("Disconnected"),
- onMessage: (message) => console.log("Message:", message),
- onError: (error) => {
- console.error("Error:", error)
- setAgentState("disconnected")
- },
- })
-
const startConversation = useCallback(async () => {
try {
setErrorMessage(null)
await navigator.mediaDevices.getUserMedia({ audio: true })
- await conversation.startSession({
+ startSession({
agentId: DEFAULT_AGENT.agentId,
connectionType: "webrtc",
- onStatusChange: (status) => setAgentState(status.status),
})
} catch (error) {
console.error("Error starting conversation:", error)
- setAgentState("disconnected")
if (error instanceof DOMException && error.name === "NotAllowedError") {
setErrorMessage("Please enable microphone permissions in your browser.")
}
}
- }, [conversation])
+ }, [startSession])
const handleCall = useCallback(() => {
- if (agentState === "disconnected" || agentState === null) {
- setAgentState("connecting")
+ if (status === "disconnected" || status === "error") {
startConversation()
- } else if (agentState === "connected") {
- conversation.endSession()
- setAgentState("disconnected")
+ } else if (status === "connected") {
+ endSession()
}
- }, [agentState, conversation, startConversation])
+ }, [status, endSession, startConversation])
- const isCallActive = agentState === "connected"
- const isTransitioning =
- agentState === "connecting" || agentState === "disconnecting"
+ const isCallActive = status === "connected"
+ const isTransitioning = status === "connecting"
- const getInputVolume = useCallback(() => {
- const rawValue = conversation.getInputVolume?.() ?? 0
- return Math.min(1.0, Math.pow(rawValue, 0.5) * 2.5)
- }, [conversation])
+ const scaledInputVolume = useCallback(() => {
+ try {
+ const rawValue = getInputVolume() ?? 0
+ return Math.min(1.0, Math.pow(rawValue, 0.5) * 2.5)
+ } catch {
+ return 0
+ }
+ }, [getInputVolume])
- const getOutputVolume = useCallback(() => {
- const rawValue = conversation.getOutputVolume?.() ?? 0
- return Math.min(1.0, Math.pow(rawValue, 0.5) * 2.5)
- }, [conversation])
+ const scaledOutputVolume = useCallback(() => {
+ try {
+ const rawValue = getOutputVolume() ?? 0
+ return Math.min(1.0, Math.pow(rawValue, 0.5) * 2.5)
+ } catch {
+ return 0
+ }
+ }, [getOutputVolume])
return (
@@ -89,8 +80,8 @@ export default function Page() {