@livelayer/react 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +332 -1
- package/dist/index.js +1 -1
- package/dist/index.mjs +1757 -27
- package/dist/styles.css +1199 -0
- package/package.json +10 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,192 @@
|
|
|
1
|
+
import { AgentConfig } from '@livelayer/sdk';
|
|
2
|
+
import { AgentState } from '@livelayer/sdk';
|
|
3
|
+
import { Component } from 'react';
|
|
4
|
+
import { ConnectionState } from '@livelayer/sdk';
|
|
5
|
+
import { CSSProperties } from 'react';
|
|
6
|
+
import { ErrorInfo } from 'react';
|
|
1
7
|
import { FC } from 'react';
|
|
8
|
+
import { JSX } from 'react/jsx-runtime';
|
|
9
|
+
import { LiveKitSession } from '@livelayer/sdk';
|
|
10
|
+
import { ReactNode } from 'react';
|
|
11
|
+
import { Room } from 'livekit-client';
|
|
12
|
+
import { SessionOptions } from '@livelayer/sdk';
|
|
13
|
+
import { TranscriptEntry } from '@livelayer/sdk';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Agent commands streamed over the LiveKit data channel. The base package
|
|
17
|
+
* recognizes universal types (agent_state, avatar_active, etc.) and forwards
|
|
18
|
+
* everything else to the consumer's `onAgentCommand` callback.
|
|
19
|
+
*
|
|
20
|
+
* This is an open union — unknown future command types still include `type`.
|
|
21
|
+
*/
|
|
22
|
+
export declare interface AgentCommand {
|
|
23
|
+
type: string;
|
|
24
|
+
[key: string]: unknown;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { AgentConfig }
|
|
2
28
|
|
|
3
29
|
export declare interface AgentEventDetail {
|
|
4
30
|
eventName: string;
|
|
5
31
|
data: Record<string, unknown>;
|
|
6
32
|
}
|
|
7
33
|
|
|
34
|
+
export declare interface AgentInfo {
|
|
35
|
+
id: string;
|
|
36
|
+
name: string;
|
|
37
|
+
avatarImageUrl: string;
|
|
38
|
+
idleLoopUrl: string | null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export declare interface AgentInfoHandle {
|
|
42
|
+
info: AgentInfo | null;
|
|
43
|
+
error: string | null;
|
|
44
|
+
loading: boolean;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export { AgentState }
|
|
48
|
+
|
|
49
|
+
export declare interface AudioLevelHandle {
|
|
50
|
+
/** Attach a media element as the analyser source. Safe to call repeatedly — swaps sources. */
|
|
51
|
+
attach: (element: HTMLMediaElement) => void;
|
|
52
|
+
/** Stop the rAF loop and disconnect the current source. Keeps the context alive. */
|
|
53
|
+
detach: () => void;
|
|
54
|
+
/** Subscribe to level ticks (0..1). Returns an unsubscribe fn. */
|
|
55
|
+
subscribe: (cb: LevelSubscriber) => () => void;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* LiveLayer agent widget. Renders a voice/video avatar agent embed with
|
|
60
|
+
* three display modes (expanded, minimized, hidden), responsive
|
|
61
|
+
* layouts, team-member switching, and full branding.
|
|
62
|
+
*
|
|
63
|
+
* Import the stylesheet once in your app:
|
|
64
|
+
* import "@livelayer/react/styles.css";
|
|
65
|
+
*/
|
|
66
|
+
export declare function AvatarWidget(props: AvatarWidgetProps): JSX.Element;
|
|
67
|
+
|
|
68
|
+
export declare interface AvatarWidgetProps {
|
|
69
|
+
agentId: string;
|
|
70
|
+
apiKey?: string;
|
|
71
|
+
baseUrl?: string;
|
|
72
|
+
sessionEndpoint?: string;
|
|
73
|
+
sessionBody?: Record<string, unknown>;
|
|
74
|
+
experienceMode?: "WIDGET" | "EMBEDDED";
|
|
75
|
+
autoConnect?: boolean;
|
|
76
|
+
displayMode?: DisplayMode;
|
|
77
|
+
defaultDisplayMode?: DisplayMode;
|
|
78
|
+
onDisplayModeChange?: (m: DisplayMode) => void;
|
|
79
|
+
position?: WidgetPosition;
|
|
80
|
+
mobileBreakpoint?: number | false;
|
|
81
|
+
persistKey?: string;
|
|
82
|
+
disablePersistence?: boolean;
|
|
83
|
+
teamMembers?: TeamMember[];
|
|
84
|
+
currentTeamMemberId?: string;
|
|
85
|
+
onTeamMemberChange?: (m: TeamMember) => void;
|
|
86
|
+
avatarImageUrl?: string;
|
|
87
|
+
idleLoopUrl?: string;
|
|
88
|
+
greeting?: string;
|
|
89
|
+
agentName?: string;
|
|
90
|
+
branding?: BrandingConfig;
|
|
91
|
+
allowCamera?: boolean;
|
|
92
|
+
allowScreenShare?: boolean;
|
|
93
|
+
allowTyping?: boolean;
|
|
94
|
+
allowMic?: boolean;
|
|
95
|
+
onConnect?: () => void;
|
|
96
|
+
onDisconnect?: () => void;
|
|
97
|
+
onTranscript?: (entries: TranscriptEntry[]) => void;
|
|
98
|
+
onAgentState?: (state: AgentState) => void;
|
|
99
|
+
onConnectionStateChange?: (state: ConnectionState) => void;
|
|
100
|
+
onAgentEvent?: (e: AgentEventDetail) => void;
|
|
101
|
+
onAgentCommand?: (cmd: AgentCommand) => void;
|
|
102
|
+
/**
|
|
103
|
+
* When provided, the widget does not create its own LiveKit session.
|
|
104
|
+
* The consumer owns connection lifecycle. Use for cross-page
|
|
105
|
+
* persistence, shared rooms, or integration with existing Room logic.
|
|
106
|
+
*/
|
|
107
|
+
controlledSession?: ControlledSession;
|
|
108
|
+
className?: string;
|
|
109
|
+
style?: CSSProperties;
|
|
110
|
+
zIndex?: number;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export declare interface BrandingConfig {
|
|
114
|
+
logoUrl?: string;
|
|
115
|
+
productName?: string;
|
|
116
|
+
primaryColor?: string;
|
|
117
|
+
accentColor?: string;
|
|
118
|
+
backgroundColor?: string;
|
|
119
|
+
textColor?: string;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export declare interface CameraStateHandle {
|
|
123
|
+
isEnabled: boolean;
|
|
124
|
+
/** Human-readable error if getUserMedia was denied, else null. */
|
|
125
|
+
error: string | null;
|
|
126
|
+
/** The <video> element displaying the local camera preview (or null). */
|
|
127
|
+
previewEl: HTMLVideoElement | null;
|
|
128
|
+
/** The active device id, or "" if using default. */
|
|
129
|
+
activeDeviceId: string;
|
|
130
|
+
toggle: () => Promise<void>;
|
|
131
|
+
/** Switch to a different camera device (keeps camera enabled). */
|
|
132
|
+
switchDevice: (deviceId: string) => Promise<void>;
|
|
133
|
+
/** Attach the Room once it's connected. */
|
|
134
|
+
attachRoom: (room: Room) => void;
|
|
135
|
+
/** Unpublish, stop the track, and clear state. */
|
|
136
|
+
teardown: () => void;
|
|
137
|
+
clearError: () => void;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export { ConnectionState }
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Fully-controlled session state. When a consumer supplies this, the widget
|
|
144
|
+
* does NOT create its own LiveKitSession — it presents the state you give it
|
|
145
|
+
* and calls your onConnect/onDisconnect/onRawMessage when the user clicks
|
|
146
|
+
* buttons. Use this when you need cross-page persistence, a shared room
|
|
147
|
+
* across multiple widget instances, or any custom session lifecycle.
|
|
148
|
+
*
|
|
149
|
+
* When omitted, the widget manages its own session via useLiveKitSession.
|
|
150
|
+
*/
|
|
151
|
+
export declare interface ControlledSession {
|
|
152
|
+
connectionState: ConnectionState;
|
|
153
|
+
agentState: AgentState;
|
|
154
|
+
transcript: TranscriptEntry[];
|
|
155
|
+
videoElement: HTMLVideoElement | null;
|
|
156
|
+
audioElement: HTMLAudioElement | null;
|
|
157
|
+
canResume: boolean;
|
|
158
|
+
error: string | null;
|
|
159
|
+
/** Called when the user clicks the Connect/Start button. */
|
|
160
|
+
onConnect: () => void | Promise<void>;
|
|
161
|
+
/** Called when the user clicks End/Disconnect. */
|
|
162
|
+
onDisconnect: () => void;
|
|
163
|
+
/**
|
|
164
|
+
* Subscribe to data-channel messages from the agent. The widget uses this
|
|
165
|
+
* to route universal commands (state/agent_state) internally and forward
|
|
166
|
+
* everything else via onAgentCommand. Return an unsubscribe function.
|
|
167
|
+
*/
|
|
168
|
+
subscribeToDataMessages?: (cb: (msg: Record<string, unknown>) => void) => () => void;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export declare type DisplayMode = "hidden" | "minimized" | "expanded";
|
|
172
|
+
|
|
173
|
+
declare type DisplayMode_2 = "hidden" | "minimized" | "expanded";
|
|
174
|
+
|
|
175
|
+
export declare class ErrorBoundary extends Component<Props, State> {
|
|
176
|
+
state: State;
|
|
177
|
+
static getDerivedStateFromError(error: Error): State;
|
|
178
|
+
componentDidCatch(error: Error, info: ErrorInfo): void;
|
|
179
|
+
reset: () => void;
|
|
180
|
+
render(): ReactNode;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export declare interface LegacyAgentEventDetail {
|
|
184
|
+
eventName: string;
|
|
185
|
+
data: Record<string, unknown>;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
declare type LevelSubscriber = (level: number) => void;
|
|
189
|
+
|
|
8
190
|
/**
|
|
9
191
|
* React component that renders a `<livelayer-widget>` custom element.
|
|
10
192
|
*
|
|
@@ -31,11 +213,160 @@ export declare interface LiveLayerWidgetProps {
|
|
|
31
213
|
*/
|
|
32
214
|
mode?: "WIDGET" | "EMBEDDED";
|
|
33
215
|
/** Callback fired when the agent emits an event via the data channel */
|
|
34
|
-
onAgentEvent?: (event:
|
|
216
|
+
onAgentEvent?: (event: LegacyAgentEventDetail) => void;
|
|
35
217
|
/** Additional CSS class name on the wrapper div */
|
|
36
218
|
className?: string;
|
|
37
219
|
/** Inline styles on the wrapper div */
|
|
38
220
|
style?: React.CSSProperties;
|
|
39
221
|
}
|
|
40
222
|
|
|
223
|
+
export declare interface MediaDevicesHandle {
|
|
224
|
+
mics: MediaDeviceInfo[];
|
|
225
|
+
cameras: MediaDeviceInfo[];
|
|
226
|
+
refresh: () => Promise<void>;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export declare interface MicrophoneStateHandle {
|
|
230
|
+
isMuted: boolean;
|
|
231
|
+
/** Human-readable error when mic publish failed, else null. */
|
|
232
|
+
micError: string | null;
|
|
233
|
+
/** Toggle mute on the currently-published track. No-op if no track. */
|
|
234
|
+
toggleMute: () => void;
|
|
235
|
+
/**
|
|
236
|
+
* Create + publish a local mic track into the given room. Safe to call
|
|
237
|
+
* multiple times — replaces any existing track.
|
|
238
|
+
*/
|
|
239
|
+
setupMic: (room: Room) => Promise<void>;
|
|
240
|
+
/** Unpublish and dispose the current track. Safe to call when no track. */
|
|
241
|
+
teardownMic: () => void;
|
|
242
|
+
/** Clear the error state (e.g. after user clicks Retry). */
|
|
243
|
+
clearError: () => void;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
declare interface Options {
|
|
247
|
+
value?: DisplayMode_2;
|
|
248
|
+
defaultValue?: DisplayMode_2;
|
|
249
|
+
onChange?: (next: DisplayMode_2) => void;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
declare interface Options_2 {
|
|
253
|
+
value?: DisplayMode_2;
|
|
254
|
+
defaultValue?: DisplayMode_2;
|
|
255
|
+
onChange?: (next: DisplayMode_2) => void;
|
|
256
|
+
persistKey?: string;
|
|
257
|
+
disablePersistence?: boolean;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
declare interface Props {
|
|
261
|
+
children: ReactNode;
|
|
262
|
+
/** Callback fired when an error is caught. Useful for telemetry. */
|
|
263
|
+
onError?: (error: Error, info: ErrorInfo) => void;
|
|
264
|
+
/** Optional custom fallback. Defaults to a small inline error card. */
|
|
265
|
+
fallback?: ReactNode;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export declare interface ScreenShareStateHandle {
|
|
269
|
+
isEnabled: boolean;
|
|
270
|
+
error: string | null;
|
|
271
|
+
previewEl: HTMLVideoElement | null;
|
|
272
|
+
toggle: () => Promise<void>;
|
|
273
|
+
attachRoom: (room: Room) => void;
|
|
274
|
+
teardown: () => void;
|
|
275
|
+
clearError: () => void;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
declare interface State {
|
|
279
|
+
hasError: boolean;
|
|
280
|
+
error: Error | null;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export declare interface TeamMember {
|
|
284
|
+
id: string;
|
|
285
|
+
name: string;
|
|
286
|
+
role?: string;
|
|
287
|
+
avatarImageUrl?: string;
|
|
288
|
+
previewVideoUrl?: string;
|
|
289
|
+
/**
|
|
290
|
+
* Per-member agent override. When the user switches to this member the
|
|
291
|
+
* widget reconnects with this agentId. If omitted, uses the top-level
|
|
292
|
+
* agentId prop (single-agent team).
|
|
293
|
+
*/
|
|
294
|
+
agentId?: string;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
export { TranscriptEntry }
|
|
298
|
+
|
|
299
|
+
declare interface TranscriptEntry_2 {
|
|
300
|
+
id: string;
|
|
301
|
+
role: "agent" | "user";
|
|
302
|
+
text: string;
|
|
303
|
+
final: boolean;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export declare interface TranscriptHandle {
|
|
307
|
+
entries: TranscriptEntry_2[];
|
|
308
|
+
/** Add or update a segment by id. */
|
|
309
|
+
pushSegment: (segment: TranscriptEntry_2) => void;
|
|
310
|
+
/** Reset the buffer (e.g. on team-member switch). */
|
|
311
|
+
clear: () => void;
|
|
312
|
+
/** Latest entry, or null if empty. */
|
|
313
|
+
latest: TranscriptEntry_2 | null;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
export declare function useAgentInfo(agentId: string, baseUrl: string | undefined,
|
|
317
|
+
/** Skip the fetch (e.g. when consumer has passed avatarImageUrl as a prop). */
|
|
318
|
+
skip?: boolean): AgentInfoHandle;
|
|
319
|
+
|
|
320
|
+
export declare function useAudioLevel(): AudioLevelHandle;
|
|
321
|
+
|
|
322
|
+
export declare function useCameraState(): CameraStateHandle;
|
|
323
|
+
|
|
324
|
+
export declare function useDisplayMode({ value, defaultValue, onChange, }?: Options): [DisplayMode_2, (next: DisplayMode_2) => void];
|
|
325
|
+
|
|
326
|
+
export declare function useDisplayModePersistence({ value, defaultValue, onChange, persistKey, disablePersistence, }?: Options_2): [DisplayMode_2, (next: DisplayMode_2) => void];
|
|
327
|
+
|
|
328
|
+
export declare function useIsMobile(breakpoint?: number | false): boolean;
|
|
329
|
+
|
|
330
|
+
export declare function useLiveKitSession(options: UseLiveKitSessionOptions): UseLiveKitSessionResult;
|
|
331
|
+
|
|
332
|
+
declare interface UseLiveKitSessionOptions extends SessionOptions {
|
|
333
|
+
/**
|
|
334
|
+
* Fires for every data channel message from the agent. The hook also
|
|
335
|
+
* interprets recognized state-bearing messages (agent_state) and updates
|
|
336
|
+
* its own state; consumers use this callback to handle everything else.
|
|
337
|
+
*/
|
|
338
|
+
onDataMessage?: (msg: Record<string, unknown>) => void;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export declare interface UseLiveKitSessionResult {
|
|
342
|
+
connectionState: ConnectionState;
|
|
343
|
+
agentState: AgentState;
|
|
344
|
+
transcript: TranscriptEntry[];
|
|
345
|
+
agentConfig: AgentConfig | null;
|
|
346
|
+
/** Live video <video> element attached by the agent, or null. */
|
|
347
|
+
videoElement: HTMLVideoElement | null;
|
|
348
|
+
/** Remote <audio> element (agent voice), or null. */
|
|
349
|
+
audioElement: HTMLAudioElement | null;
|
|
350
|
+
/** True when the session's resume window is still open. */
|
|
351
|
+
canResume: boolean;
|
|
352
|
+
/** Surface a friendly error string when connect fails. */
|
|
353
|
+
error: string | null;
|
|
354
|
+
connect: () => Promise<void>;
|
|
355
|
+
disconnect: () => void;
|
|
356
|
+
/** Access the underlying Room (e.g. to publish mic track). */
|
|
357
|
+
getRoom: () => ReturnType<LiveKitSession["getRoom"]>;
|
|
358
|
+
/** The session instance, if consumers need it. */
|
|
359
|
+
session: LiveKitSession | null;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
export declare function useMediaDevices(): MediaDevicesHandle;
|
|
363
|
+
|
|
364
|
+
export declare function useMicrophoneState(): MicrophoneStateHandle;
|
|
365
|
+
|
|
366
|
+
export declare function useScreenShareState(): ScreenShareStateHandle;
|
|
367
|
+
|
|
368
|
+
export declare function useTranscript(): TranscriptHandle;
|
|
369
|
+
|
|
370
|
+
export declare type WidgetPosition = "top-left" | "top-right" | "bottom-left" | "bottom-right" | "custom";
|
|
371
|
+
|
|
41
372
|
export { }
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const b=require("react/jsx-runtime"),t=require("react");require("@livelayer/sdk");const m=({agentId:s,baseUrl:c,apiKey:l,mode:r,onAgentEvent:o,className:v,style:g})=>{const a=t.useRef(null),n=t.useRef(null),u=t.useRef(o);u.current=o;const d=t.useCallback(i=>{var f;const e=i.detail;(f=u.current)==null||f.call(u,e)},[]);return t.useEffect(()=>{const i=a.current;if(!i)return;const e=document.createElement("livelayer-widget");return e.setAttribute("agent-id",s),c&&e.setAttribute("base-url",c),l&&e.setAttribute("api-key",l),r&&e.setAttribute("mode",r),e.addEventListener("agent-event",d),i.appendChild(e),n.current=e,()=>{e.removeEventListener("agent-event",d),i.removeChild(e),n.current=null}},[s]),t.useEffect(()=>{n.current&&(r?n.current.setAttribute("mode",r):n.current.removeAttribute("mode"))},[r]),b.jsx("div",{ref:a,className:v,style:g})};exports.LiveLayerWidget=m;
|
|
1
|
+
"use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),t=require("react"),st=require("@livelayer/sdk"),xe=require("livekit-client");class Be extends t.Component{constructor(){super(...arguments),this.state={hasError:!1,error:null},this.reset=()=>{this.setState({hasError:!1,error:null})}}static getDerivedStateFromError(r){return{hasError:!0,error:r}}componentDidCatch(r,l){var a,s;(s=(a=this.props).onError)==null||s.call(a,r,l)}render(){var r;return this.state.hasError?this.props.fallback?this.props.fallback:e.jsxs("div",{className:"ll-error-boundary",role:"alert",children:[e.jsx("p",{className:"ll-error-boundary__title",children:"Widget crashed"}),e.jsx("p",{className:"ll-error-boundary__message",children:((r=this.state.error)==null?void 0:r.message)||"Something went wrong."}),e.jsx("button",{type:"button",className:"ll-error-boundary__retry",onClick:this.reset,children:"Reload widget"})]}):this.props.children}}function $e(n){const[r,l]=t.useState("idle"),[a,s]=t.useState("idle"),[o,d]=t.useState([]),[m,u]=t.useState(null),[x,f]=t.useState(null),[c,i]=t.useState(null),[y,b]=t.useState(!1),[j,N]=t.useState(null),C=t.useRef(null),M=t.useRef(n.onDataMessage);M.current=n.onDataMessage,t.useEffect(()=>{const _={onConnectionStateChange:v=>{l(v),v==="connected"&&N(null)},onAgentStateChange:s,onTranscript:v=>d([...v]),onAgentConfig:u,onAudioTrack:v=>i(v),onVideoTrack:v=>f(v),onVideoTrackRemoved:()=>f(null),onError:v=>N(v),onDataMessage:v=>{var E;(E=M.current)==null||E.call(M,v)},onResumabilityChange:b},k=new st.LiveKitSession({agentId:n.agentId,baseUrl:n.baseUrl,apiKey:n.apiKey,sessionEndpoint:n.sessionEndpoint,sessionBody:n.sessionBody},_);return C.current=k,l("idle"),s("idle"),d([]),u(null),f(null),i(null),b(!1),N(null),()=>{var v;(v=k.destroy)==null||v.call(k),C.current=null}},[n.agentId,n.baseUrl,n.apiKey,n.sessionEndpoint,JSON.stringify(n.sessionBody??{})]);const R=t.useCallback(async()=>{const _=C.current;if(_)try{await _.connect()}catch(k){throw N(k instanceof Error?k.message:String(k)),k}},[]),L=t.useCallback(()=>{const _=C.current;_&&_.disconnect()},[]),S=t.useCallback(()=>{var _;return((_=C.current)==null?void 0:_.getRoom())??null},[]);return{connectionState:r,agentState:a,transcript:o,agentConfig:m,videoElement:x,audioElement:c,canResume:y,error:j,connect:R,disconnect:L,getRoom:S,session:C.current}}function Ue(){const n=t.useRef(null),r=t.useRef(null),l=t.useRef(null),a=t.useRef(null),s=t.useRef(new Set),o=t.useRef(null),d=t.useCallback(()=>{const c=r.current;if(!c){a.current=null;return}(!o.current||o.current.length!==c.frequencyBinCount)&&(o.current=new Uint8Array(new ArrayBuffer(c.frequencyBinCount)));const i=o.current;c.getByteFrequencyData(i);let y=0;for(let j=0;j<i.length;j++)y+=i[j];const b=y/i.length/255;for(const j of s.current)try{j(b)}catch(N){console.error("[useAudioLevel] subscriber threw:",N)}a.current=requestAnimationFrame(d)},[]),m=t.useCallback(()=>{if(n.current||typeof window>"u"||typeof AudioContext>"u")return;const c=new AudioContext,i=c.createAnalyser();i.fftSize=64,i.connect(c.destination),n.current=c,r.current=i},[]),u=t.useCallback(c=>{if(m(),!(!n.current||!r.current)){if(l.current){try{l.current.disconnect()}catch{}l.current=null}try{const i=n.current.createMediaElementSource(c);i.connect(r.current),l.current=i}catch(i){console.warn("[useAudioLevel] createMediaElementSource failed:",i);return}a.current===null&&(a.current=requestAnimationFrame(d))}},[m,d]),x=t.useCallback(()=>{if(a.current!==null&&(cancelAnimationFrame(a.current),a.current=null),l.current){try{l.current.disconnect()}catch{}l.current=null}},[]),f=t.useCallback(c=>(s.current.add(c),()=>{s.current.delete(c)}),[]);return t.useEffect(()=>()=>{if(x(),r.current){try{r.current.disconnect()}catch{}r.current=null}if(n.current){try{n.current.close()}catch{}n.current=null}s.current.clear(),o.current=null},[x]),{attach:u,detach:x,subscribe:f}}function Oe(){const[n,r]=t.useState(!1),[l,a]=t.useState(null),s=t.useRef(null),o=t.useRef(null),d=t.useCallback(async f=>{if(s.current&&o.current){try{await o.current.localParticipant.unpublishTrack(s.current)}catch{}s.current.stop(),s.current=null}o.current=f,a(null);try{const c=await xe.createLocalAudioTrack({echoCancellation:!0,noiseSuppression:!0});await f.localParticipant.publishTrack(c),s.current=c,r(c.isMuted)}catch(c){const i=c instanceof Error&&c.name==="NotAllowedError"?"Enable your microphone to talk with the agent.":"Microphone unavailable. Check browser permissions and try again.";throw a(i),c}},[]),m=t.useCallback(()=>{const f=s.current;f&&(f.isMuted?(f.unmute(),r(!1)):(f.mute(),r(!0)))},[]),u=t.useCallback(()=>{const f=s.current,c=o.current;if(f&&c){try{c.localParticipant.unpublishTrack(f)}catch{}f.stop()}s.current=null,o.current=null,r(!1)},[]),x=t.useCallback(()=>a(null),[]);return{isMuted:n,micError:l,toggleMute:m,setupMic:d,teardownMic:u,clearError:x}}const lt={resolution:{width:640,height:480,frameRate:24}};function Ve(){const[n,r]=t.useState(!1),[l,a]=t.useState(null),[s,o]=t.useState(null),[d,m]=t.useState(""),u=t.useRef(null),x=t.useRef(null),f=t.useCallback(C=>{u.current=C},[]),c=t.useCallback(()=>{const C=u.current,M=x.current;if(M&&C){const R=C.localParticipant.getTrackPublication(xe.Track.Source.Camera);if(R!=null&&R.track){try{C.localParticipant.unpublishTrack(R.track)}catch{}R.track.stop()}else M.stop()}x.current=null,o(null),r(!1)},[]),i=t.useCallback(async C=>{const M=u.current;if(M){a(null);try{const R={...lt};C&&(R.deviceId=C);const L=await xe.createLocalVideoTrack(R);await M.localParticipant.publishTrack(L),x.current=L;const S=L.attach();o(S),r(!0),C&&m(C);try{M.localParticipant.publishData(new TextEncoder().encode(JSON.stringify({type:"user_camera_on"})),{reliable:!0})}catch{}}catch(R){const L=R instanceof Error&&R.name==="NotAllowedError"?"Enable your camera in the browser to share video.":"Camera unavailable. Check permissions and try again.";a(L)}}},[]),y=t.useCallback(async()=>{n?c():await i(d||void 0)},[n,d,c,i]),b=t.useCallback(async C=>{c(),await i(C)},[c,i]),j=t.useCallback(()=>{c(),u.current=null,a(null),m("")},[c]),N=t.useCallback(()=>a(null),[]);return t.useEffect(()=>()=>{x.current&&x.current.stop()},[]),{isEnabled:n,error:l,previewEl:s,activeDeviceId:d,toggle:y,switchDevice:b,attachRoom:f,teardown:j,clearError:N}}function We(){const[n,r]=t.useState(!1),[l,a]=t.useState(null),[s,o]=t.useState(null),d=t.useRef(null),m=t.useCallback(i=>{d.current=i},[]),u=t.useCallback(()=>o(null),[]),x=t.useCallback(async()=>{const i=d.current;if(i){if(n){try{await i.localParticipant.setScreenShareEnabled(!1)}catch{}u(),r(!1);return}a(null);try{await i.localParticipant.setScreenShareEnabled(!0);let y=0;const b=()=>{const j=i.localParticipant.getTrackPublication(xe.Track.Source.ScreenShare);if(j!=null&&j.track){const N=j.track.attach();o(N),r(!0);try{i.localParticipant.publishData(new TextEncoder().encode(JSON.stringify({type:"user_screen_share_on"})),{reliable:!0})}catch{}return}y++<10?setTimeout(b,100):r(!0)};b()}catch(y){const b=y instanceof Error?y.name:"";b!=="NotAllowedError"&&b!=="AbortError"&&a("Screen share unavailable. Try again."),r(!1)}}},[n,u]),f=t.useCallback(()=>{const i=d.current;if(i&&n)try{i.localParticipant.setScreenShareEnabled(!1)}catch{}u(),r(!1),a(null),d.current=null},[n,u]),c=t.useCallback(()=>a(null),[]);return{isEnabled:n,error:l,previewEl:s,toggle:x,attachRoom:m,teardown:f,clearError:c}}function Fe(){const[n,r]=t.useState([]),[l,a]=t.useState([]),s=t.useCallback(async()=>{if(!(typeof navigator>"u"||!navigator.mediaDevices))try{const o=await navigator.mediaDevices.enumerateDevices();r(o.filter(d=>d.kind==="audioinput")),a(o.filter(d=>d.kind==="videoinput"))}catch{}},[]);return t.useEffect(()=>{if(s(),typeof navigator>"u"||!navigator.mediaDevices)return;const o=()=>void s();return navigator.mediaDevices.addEventListener("devicechange",o),()=>navigator.mediaDevices.removeEventListener("devicechange",o)},[s]),{mics:n,cameras:l,refresh:s}}function Ke(n,r,l=!1){const[a,s]=t.useState(null),[o,d]=t.useState(null),[m,u]=t.useState(!l&&!!n),x=t.useRef("");return t.useEffect(()=>{if(l||!n){u(!1);return}const f=`${r||""}::${n}`;if(x.current===f)return;x.current=f;const c=new AbortController,i=r||"https://app.livelayer.studio";return u(!0),d(null),fetch(`${i}/api/widget/agent/${encodeURIComponent(n)}`,{signal:c.signal}).then(async y=>{if(!y.ok){const b=await y.json().catch(()=>({}));throw new Error(b.error||`HTTP ${y.status}`)}return y.json()}).then(y=>{s(y),u(!1)}).catch(y=>{c.signal.aborted||(d(y instanceof Error?y.message:"Agent lookup failed"),u(!1))}),()=>c.abort()},[n,r,l]),{info:a,error:o,loading:m}}function at(n){if(typeof window>"u")return null;try{return window.localStorage.getItem(n)}catch{return null}}function it(n,r){if(!(typeof window>"u"))try{window.localStorage.setItem(n,r)}catch{}}function qe({value:n,defaultValue:r="expanded",onChange:l}={}){const a=n!==void 0,[s,o]=t.useState(r),d=a?n:s,m=t.useCallback(u=>{u!==d&&(a||o(u),l==null||l(u))},[d,a,l]);return[d,m]}const ot=["hidden","minimized","expanded"];function ct(n){return n&&ot.includes(n)?n:null}function Ge({value:n,defaultValue:r="expanded",onChange:l,persistKey:a="ll-widget",disablePersistence:s=!1}={}){const o=`${a}:display-mode`,d=t.useRef(!1),[m,u]=qe({value:n,defaultValue:r,onChange:x=>{n===void 0&&!s&&it(o,x),l==null||l(x)}});return t.useEffect(()=>{if(d.current||(d.current=!0,s||n!==void 0))return;const x=ct(at(o));x&&x!==m&&u(x)},[]),[m,u]}const dt=640;function Ye(n=dt){const[r,l]=t.useState(!1);return t.useEffect(()=>{if(n===!1){l(!1);return}if(typeof window>"u"||typeof window.matchMedia>"u")return;const a=`(max-width: ${n-1}px)`,s=window.matchMedia(a),o=()=>l(s.matches);return o(),typeof s.addEventListener=="function"?(s.addEventListener("change",o),()=>s.removeEventListener("change",o)):(s.addListener(o),()=>{s.removeListener(o)})},[n]),r}const Ie=({muted:n=!1,className:r})=>n?e.jsxs("svg",{className:r,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,"aria-hidden":"true",children:[e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M5.586 15H4a1 1 0 01-1-1v-4a1 1 0 011-1h1.586l4.707-4.707C10.923 3.663 12 4.109 12 5v14c0 .891-1.077 1.337-1.707.707L5.586 15z"}),e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M17 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2"})]}):e.jsx("svg",{className:r,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,"aria-hidden":"true",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4M12 1a3 3 0 00-3 3v4a3 3 0 006 0V4a3 3 0 00-3-3z"})}),Ae=({className:n})=>e.jsx("svg",{className:n,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,"aria-hidden":"true",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4"})}),ut=({className:n})=>e.jsx("svg",{className:n,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,"aria-hidden":"true",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M6 18L18 6M6 6l12 12"})}),ft={left:180,right:0,up:-90,down:90},ht=({direction:n="right",className:r})=>e.jsx("svg",{className:r,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,style:{transform:`rotate(${ft[n]}deg)`},"aria-hidden":"true",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M9 6l6 6-6 6"})});function pt(n){return n==="top-left"||n==="bottom-left"?"left":"right"}const He="ll-hidden-tab-center-y",mt=5,De=16;function xt(){if(typeof window>"u")return null;try{const n=window.localStorage.getItem(He);if(!n)return null;const r=Number.parseFloat(n);return Number.isFinite(r)?r:null}catch{return null}}function Te(n){if(!(typeof window>"u"))try{window.localStorage.setItem(He,String(n))}catch{}}const gt=({position:n,isMobile:r,isSpeaking:l,onExpand:a,label:s="Open widget"})=>{const o=pt(n),d=o==="right"?"left":"right",m=r?80:72,[u,x]=t.useState(null),[f,c]=t.useState(!1),i=t.useRef(null),y=t.useRef(!1),b=t.useCallback(_=>{if(typeof window>"u")return _;const k=m/2,v=De+k,E=window.innerHeight-De-k;return E<v?Math.max(v,_):Math.max(v,Math.min(E,_))},[m]);t.useEffect(()=>{const _=xt();x(b(_??window.innerHeight/2));const k=()=>{x(v=>v===null?null:b(v))};return window.addEventListener("resize",k),()=>window.removeEventListener("resize",k)},[b]);const j=t.useCallback(_=>{if(!(_.pointerType==="mouse"&&_.button!==0)&&u!==null){try{_.currentTarget.setPointerCapture(_.pointerId)}catch{}i.current={startClientY:_.clientY,startCenterY:u,moved:!1}}},[u]),N=t.useCallback(_=>{const k=i.current;if(!k)return;const v=_.clientY-k.startClientY;!k.moved&&Math.abs(v)>mt&&(k.moved=!0,c(!0)),k.moved&&x(b(k.startCenterY+v))},[b]),C=t.useCallback(_=>{const k=i.current;if(k){try{_.currentTarget.releasePointerCapture(_.pointerId)}catch{}i.current=null,k.moved&&(c(!1),y.current=!0,x(v=>(v!==null&&Te(v),v)))}},[]),M=t.useCallback(()=>{if(y.current){y.current=!1;return}a()},[a]),R=t.useCallback(_=>{if(_.key==="ArrowUp"||_.key==="ArrowDown"){_.preventDefault();const k=_.key==="ArrowUp"?-8:8;x(v=>{if(v===null)return v;const E=b(v+k);return Te(E),E})}},[b]),L=["ll-hidden",`ll-hidden--${o}`,r?"ll-hidden--mobile":"ll-hidden--desktop",l?"ll-hidden--speaking":null,f?"is-dragging":null].filter(Boolean).join(" "),S=u===null?void 0:{top:`${u-m/2}px`,transform:"none"};return e.jsx("button",{type:"button",className:L,onPointerDown:j,onPointerMove:N,onPointerUp:C,onPointerCancel:C,onClick:M,onKeyDown:R,"aria-label":s,"data-position":n,style:S,children:e.jsx(ht,{direction:d,className:"ll-hidden__chevron"})})},vt=({audioLevel:n,bars:r=20,maxHeight:l=20,minHeight:a=4,className:s,barClassName:o})=>{const d=t.useRef(null),m=t.useRef([]),u=t.useMemo(()=>{const f=(Math.sqrt(5)-1)/2;return Array.from({length:r},(c,i)=>.5+i*f%1*.5)},[r]);t.useEffect(()=>n.subscribe(c=>{for(let i=0;i<r;i++){const y=m.current[i];if(!y)continue;const b=Math.max(a,c*l*u[i]);y.style.height=`${b}px`}}),[n,r,l,a,u]);const x=["ll-waveform",s].filter(Boolean).join(" ");return e.jsx("div",{ref:d,className:x,"aria-hidden":"true",children:Array.from({length:r},(f,c)=>e.jsx("div",{ref:i=>{m.current[c]=i},className:["ll-waveform__bar",o].filter(Boolean).join(" "),style:{height:`${a}px`}},c))})},bt=({position:n,isMobile:r,agentName:l,avatarImageUrl:a,agentState:s,isMuted:o,audioLevel:d,onExpand:m,onToggleMute:u,onClose:x})=>r?e.jsx("div",{className:"ll-minimized ll-minimized--mobile",role:"region","aria-label":`${l} widget`,children:e.jsxs("button",{type:"button",className:"ll-minimized__surface",onClick:m,"aria-label":`Expand ${l} widget`,children:[a?e.jsx("img",{src:a,alt:l,className:"ll-minimized__avatar"}):e.jsx("div",{className:"ll-minimized__avatar ll-minimized__avatar--placeholder"}),e.jsx(vt,{audioLevel:d,bars:16,maxHeight:18,className:"ll-minimized__waveform"}),e.jsx("span",{className:"ll-minimized__name",children:l}),e.jsxs("div",{className:"ll-minimized__controls",children:[e.jsx("span",{className:"ll-minimized__btn",role:"button",tabIndex:0,onClick:f=>{f.stopPropagation(),u()},onKeyDown:f=>{(f.key==="Enter"||f.key===" ")&&(f.stopPropagation(),f.preventDefault(),u())},"aria-label":o?"Unmute microphone":"Mute microphone",children:e.jsx(Ie,{muted:o,className:"ll-minimized__icon"})}),e.jsx(Ae,{className:"ll-minimized__icon ll-minimized__icon--expand"})]})]})}):e.jsx("div",{className:"ll-minimized ll-minimized--desktop","data-position":n,role:"region","aria-label":`${l} widget`,children:e.jsxs("div",{className:"ll-minimized__surface",children:[a?e.jsx("img",{src:a,alt:l,className:"ll-minimized__avatar"}):e.jsx("div",{className:"ll-minimized__avatar ll-minimized__avatar--placeholder"}),e.jsxs("div",{className:"ll-minimized__meta",children:[e.jsx("span",{className:"ll-minimized__name",children:l}),e.jsx("span",{className:"ll-minimized__state",children:s==="speaking"?"Speaking":s==="thinking"?"Thinking":"Listening"})]}),e.jsxs("div",{className:"ll-minimized__controls",children:[e.jsx("button",{type:"button",className:"ll-minimized__btn",onClick:u,"aria-label":o?"Unmute microphone":"Mute microphone",children:e.jsx(Ie,{muted:o,className:"ll-minimized__icon"})}),e.jsx("button",{type:"button",className:"ll-minimized__btn",onClick:m,"aria-label":`Expand ${l} widget`,children:e.jsx(Ae,{className:"ll-minimized__icon"})}),e.jsx("button",{type:"button",className:"ll-minimized__btn ll-minimized__btn--close",onClick:x,"aria-label":"Close widget",children:e.jsx(ut,{className:"ll-minimized__icon"})})]})]})}),yt=({src:n,alt:r,preCannedPlaying:l=!1,className:a,style:s})=>{const[o,d]=t.useState(!1),m=t.useRef(n);if(t.useEffect(()=>{m.current!==n&&(m.current=n,d(!1))},[n]),!n)return null;const u={position:"absolute",inset:0,width:"100%",height:"100%",objectFit:"cover",objectPosition:"top",transition:"opacity 500ms ease, transform 500ms ease",transform:l?"scale(1.02)":"scale(1)",opacity:o?1:0,...s};return e.jsx("img",{src:n,alt:r,className:a,style:u,loading:"eager",fetchpriority:"high",onLoad:()=>d(!0)})},_t=({position:n,isMobile:r,agentName:l,avatarImageUrl:a,idleLoopUrl:s,greeting:o,branding:d,teamMembers:m,currentTeamMemberId:u,isSwitchingTeamMember:x,teamSwitcherOpen:f,onToggleTeamSwitcher:c,onSelectTeamMember:i,languageMenuOpen:y,onToggleLanguageMenu:b,connectionState:j,agentState:N,transcript:C,canResume:M,needsUserGesture:R,error:L,isMuted:S,micError:_,micDevices:k,isCameraEnabled:v,cameraPreviewEl:E,cameraDevices:G,activeCameraId:Q,isScreenShareEnabled:T,screenPreviewEl:z,isSpeakerMuted:U,allowCamera:Z,allowScreenShare:I,allowTyping:ge,avatarVideoContainerRef:ve,onConnect:fe,onDisconnect:ae,onRetry:be,onResumeAudio:ye,onToggleMute:Y,onToggleCamera:D,onSwitchCameraDevice:he,onToggleScreenShare:H,onToggleSpeaker:O,onSendMessage:J,onMinimize:ie,onClose:P,onClearMicError:V})=>{var pe;const B=C.length>0?C[C.length-1]:null,W=((m==null?void 0:m.length)??0)>1,ee=j==="connecting"||j==="connected",F=j==="connected",oe=j==="idle"||j==="disconnected"||j==="error",ce=t.useRef(null),te=t.useRef(null);t.useEffect(()=>{const h=ce.current;h&&(h.innerHTML="",E&&(E.style.width="100%",E.style.height="100%",E.style.objectFit="cover",E.style.transform="scaleX(-1)",h.appendChild(E)))},[E]),t.useEffect(()=>{const h=te.current;h&&(h.innerHTML="",z&&(z.style.width="100%",z.style.height="100%",z.style.objectFit="contain",h.appendChild(z)))},[z]);const[K,ne]=t.useState(!1),[re,q]=t.useState(!1);t.useEffect(()=>{if(!K&&!re&&!y&&!f)return;const h=()=>{ne(!1),q(!1),y&&b(),f&&c()};return document.addEventListener("click",h),()=>document.removeEventListener("click",h)},[K,re,y,f,b,c]);const[se,le]=t.useState(""),A=t.useCallback(h=>{h.preventDefault();const $=se.trim();$&&(J($),le(""))},[se,J]),p=d.productName||"Live Layer",de=F&&(B!=null&&B.text)?B.text:o||"",_e=["ll-expanded",r?"ll-expanded--mobile":"ll-expanded--desktop"].join(" ");return e.jsxs("div",{className:_e,"data-position":n,"data-state":F?"connected":ee?"connecting":"idle",role:"dialog","aria-label":`${l} widget`,children:[e.jsxs("div",{className:"ll-expanded__bg",children:[a?e.jsx(yt,{src:a,alt:l,className:"ll-expanded__bg-img"}):e.jsx("div",{className:"ll-expanded__bg-fallback",children:e.jsx("span",{className:"ll-expanded__bg-initial",children:((pe=l==null?void 0:l.charAt(0))==null?void 0:pe.toUpperCase())||"A"})}),s&&!F&&e.jsx("video",{className:"ll-expanded__bg-idle",src:s,autoPlay:!0,loop:!0,muted:!0,playsInline:!0})]}),e.jsx("div",{ref:ve,className:"ll-expanded__video"}),j==="connecting"&&e.jsxs("div",{className:"ll-expanded__overlay ll-expanded__overlay--connecting",children:[e.jsx("div",{className:"ll-expanded__spinner"}),e.jsx("p",{className:"ll-expanded__overlay-text",children:x?"Switching...":"Connecting..."})]}),R&&F&&e.jsxs("button",{type:"button",className:"ll-expanded__overlay ll-expanded__overlay--gesture",onClick:ye,children:[e.jsx("svg",{width:"32",height:"32",viewBox:"0 0 24 24",fill:"currentColor","aria-hidden":!0,children:e.jsx("path",{d:"M3 9v6h4l5 5V4L7 9H3zm13.54.12a5 5 0 0 1 0 5.76l-1.41-1.41a3 3 0 0 0 0-2.94L16.54 9.12z"})}),e.jsx("p",{className:"ll-expanded__overlay-text",children:"Tap to enable audio"})]}),ee?e.jsxs("div",{className:"ll-expanded__topbar",children:[e.jsxs("div",{className:"ll-expanded__topbar-left",children:[e.jsxs("div",{className:"ll-expanded__pill-wrap",children:[e.jsxs("button",{type:"button",className:"ll-hpill",onClick:h=>{W&&(h.stopPropagation(),c())},"aria-haspopup":W?"listbox":void 0,"aria-expanded":W?f:void 0,children:[e.jsx("span",{className:"ll-hpill__label",children:l}),W&&e.jsx(me,{})]}),W&&f&&e.jsx("div",{className:"ll-hmenu",onClick:h=>h.stopPropagation(),role:"listbox",children:m==null?void 0:m.map(h=>e.jsxs("button",{type:"button",className:`ll-hmenu__item ${h.id===u?"is-active":""}`,onClick:()=>i(h.id),role:"option","aria-selected":h.id===u,children:[h.avatarImageUrl&&e.jsx("img",{src:h.avatarImageUrl,alt:"",className:"ll-hmenu__avatar"}),e.jsx("span",{className:"ll-hmenu__name",children:h.name}),h.role&&e.jsx("span",{className:"ll-hmenu__role",children:h.role})]},h.id))})]}),e.jsxs("div",{className:"ll-expanded__pill-wrap",children:[e.jsxs("button",{type:"button",className:"ll-hpill",onClick:h=>{h.stopPropagation(),b()},"aria-haspopup":"listbox","aria-expanded":y,children:[e.jsx("span",{className:"ll-hpill__label",children:"English"}),e.jsx(me,{})]}),y&&e.jsx("div",{className:"ll-hmenu",onClick:h=>h.stopPropagation(),role:"listbox",children:e.jsx("button",{type:"button",className:"ll-hmenu__item is-active",role:"option","aria-selected":!0,children:e.jsx("span",{className:"ll-hmenu__name",children:"English"})})})]}),e.jsx("span",{className:`ll-expanded__state ll-expanded__state--${N}`,children:N})]}),e.jsx("button",{type:"button",className:"ll-hbtn",onClick:P,"aria-label":"Close widget",title:"Close",children:e.jsx(ze,{})})]}):e.jsxs("div",{className:"ll-expanded__header ll-expanded__header--idle",children:[e.jsx("span",{className:"ll-expanded__brand",children:p}),e.jsxs("div",{className:"ll-expanded__header-actions",children:[e.jsx("button",{type:"button",className:"ll-hbtn ll-hbtn--ghost",onClick:ie,"aria-label":"Minimize widget",children:e.jsx(kt,{})}),e.jsx("button",{type:"button",className:"ll-hbtn ll-hbtn--ghost",onClick:P,"aria-label":"Close widget",children:e.jsx(ze,{})})]})]}),oe&&e.jsxs("button",{type:"button",className:"ll-expanded__play",onClick:fe,"aria-label":M?"Resume session":"Start video call",children:[e.jsx("div",{className:"ll-expanded__play-circle",children:e.jsx("svg",{width:"22",height:"22",viewBox:"0 0 24 24",fill:"currentColor","aria-hidden":!0,children:e.jsx("polygon",{points:"6 3 20 12 6 21 6 3"})})}),e.jsx("span",{className:"ll-expanded__play-label",children:M?"Restart session":"Start video call"}),M&&e.jsx("span",{className:"ll-expanded__play-sublabel",children:"Pick up where you left off"})]}),e.jsxs("div",{className:`ll-expanded__pip ${ee&&(v||T)?"is-visible":""}`,children:[e.jsx("div",{ref:te,className:T?"ll-expanded__pip-host":"ll-expanded__pip-host is-hidden"}),e.jsx("div",{ref:ce,className:!T&&v?"ll-expanded__pip-host":"ll-expanded__pip-host is-hidden"})]}),ee?e.jsxs("div",{className:"ll-expanded__bottom",children:[de&&e.jsx("div",{className:"ll-expanded__transcript",children:e.jsx("p",{className:"ll-expanded__transcript-text",children:de})}),e.jsxs("div",{className:"ll-toolbar",onClick:h=>h.stopPropagation(),children:[I&&e.jsx("button",{type:"button",className:`ll-tool ${T?"is-on":""}`,onClick:H,"aria-label":T?"Stop sharing screen":"Share screen",title:T?"Stop sharing":"Share screen",children:e.jsx(jt,{})}),Z&&e.jsxs("div",{className:"ll-tool-split",children:[e.jsx("button",{type:"button",className:`ll-tool ll-tool--left ${v?"is-on":""}`,onClick:D,"aria-label":v?"Turn off camera":"Turn on camera",title:v?"Stop camera":"Start camera",children:e.jsx(Ct,{})}),e.jsx("button",{type:"button",className:`ll-tool ll-tool--right ${v?"is-on":""}`,onClick:h=>{h.stopPropagation(),q($=>!$),ne(!1)},"aria-label":"Camera devices","aria-haspopup":"listbox","aria-expanded":re,children:e.jsx(me,{})}),re&&G.length>0&&e.jsx(Pe,{label:"Camera",devices:G,activeId:Q,onPick:h=>{q(!1),he(h)}})]}),e.jsxs("div",{className:"ll-tool-split",children:[e.jsx("button",{type:"button",className:`ll-tool ll-tool--left ${S?"is-muted":""}`,onClick:Y,"aria-label":S?"Unmute microphone":"Mute microphone",title:S?"Unmute":"Mute",children:e.jsx(wt,{muted:S})}),e.jsx("button",{type:"button",className:`ll-tool ll-tool--right ${S?"is-muted":""}`,onClick:h=>{h.stopPropagation(),ne($=>!$),q(!1)},"aria-label":"Microphone devices","aria-haspopup":"listbox","aria-expanded":K,children:e.jsx(me,{})}),K&&k.length>0&&e.jsx(Pe,{label:"Microphone",devices:k,activeId:"",onPick:()=>ne(!1)})]}),e.jsx("button",{type:"button",className:`ll-tool ${U?"is-muted":""}`,onClick:O,"aria-label":U?"Unmute speaker":"Mute speaker",title:U?"Unmute speaker":"Mute speaker",children:e.jsx(St,{muted:U})})]}),ge&&e.jsxs("form",{className:"ll-message-input",onSubmit:A,children:[e.jsx("input",{type:"text",className:"ll-message-input__field",placeholder:"Message...",value:se,onChange:h=>le(h.target.value),"aria-label":"Message the agent"}),se.trim()&&e.jsx("button",{type:"submit",className:"ll-message-input__send","aria-label":"Send message",children:e.jsx(Et,{})})]}),e.jsx("button",{type:"button",className:"ll-expanded__end",onClick:ae,children:"End conversation"})]}):o&&e.jsx("div",{className:"ll-expanded__bottom ll-expanded__bottom--idle",children:e.jsx("div",{className:"ll-expanded__transcript",children:e.jsx("p",{className:"ll-expanded__transcript-text",children:o})})}),(()=>{if(_&&j!=="error")return e.jsxs("div",{className:"ll-expanded__banner",role:"alert",children:[e.jsx("span",{children:_}),e.jsx("button",{type:"button",className:"ll-expanded__banner-x",onClick:V,"aria-label":"Dismiss",children:"×"})]});if(!L||j!=="error")return null;let h="Failed to connect",$="Try again";return L==="MIC_PERMISSION_DENIED"?h="Microphone blocked. Allow access to talk.":L==="MIC_NOT_FOUND"?h="No microphone found. Plug one in + retry.":L==="MIC_UNAVAILABLE"?h="Mic unavailable. Check other apps using it.":L==="AGENT_TIMEOUT"?h="Agent didn't pick up. Try again.":L==="CONNECT_FAILED"?h="Connection failed. Check your network.":L.length<80&&(h=L),e.jsxs("div",{className:"ll-expanded__banner ll-expanded__banner--error",role:"alert",children:[e.jsx("span",{children:h}),e.jsx("button",{type:"button",className:"ll-expanded__banner-retry",onClick:be,children:$})]})})()]})};function me(){return e.jsx("svg",{width:"12",height:"12",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round","aria-hidden":!0,children:e.jsx("polyline",{points:"6 9 12 15 18 9"})})}function ze(){return e.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round","aria-hidden":!0,children:[e.jsx("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),e.jsx("line",{x1:"6",y1:"6",x2:"18",y2:"18"})]})}function kt(){return e.jsx("svg",{width:"12",height:"12",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round","aria-hidden":!0,children:e.jsx("line",{x1:"5",y1:"12",x2:"19",y2:"12"})})}function jt(){return e.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":!0,children:[e.jsx("rect",{x:"2",y:"3",width:"20",height:"14",rx:"2"}),e.jsx("line",{x1:"8",y1:"21",x2:"16",y2:"21"}),e.jsx("line",{x1:"12",y1:"17",x2:"12",y2:"21"})]})}function Ct(){return e.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":!0,children:[e.jsx("path",{d:"M23 7l-7 5 7 5V7z"}),e.jsx("rect",{x:"1",y:"5",width:"15",height:"14",rx:"2"})]})}function wt({muted:n}){return e.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":!0,children:[e.jsx("path",{d:"M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"}),e.jsx("path",{d:"M19 10v2a7 7 0 0 1-14 0v-2"}),e.jsx("line",{x1:"12",y1:"19",x2:"12",y2:"23"}),n&&e.jsx("line",{x1:"1",y1:"1",x2:"23",y2:"23"})]})}function St({muted:n}){return e.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":!0,children:[e.jsx("polygon",{points:"11 5 6 9 2 9 2 15 6 15 11 19 11 5"}),n?e.jsx("line",{x1:"23",y1:"9",x2:"17",y2:"15"}):e.jsxs(e.Fragment,{children:[e.jsx("path",{d:"M19.07 4.93a10 10 0 0 1 0 14.14"}),e.jsx("path",{d:"M15.54 8.46a5 5 0 0 1 0 7.07"})]})]})}function Et(){return e.jsxs("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":!0,children:[e.jsx("line",{x1:"5",y1:"12",x2:"19",y2:"12"}),e.jsx("polyline",{points:"12 5 19 12 12 19"})]})}const Pe=({label:n,devices:r,activeId:l,onPick:a})=>e.jsxs("div",{className:"ll-device-menu",onClick:s=>s.stopPropagation(),role:"listbox",children:[e.jsx("p",{className:"ll-device-menu__label",children:n}),r.map((s,o)=>{const d=l===s.deviceId;return e.jsxs("button",{type:"button",className:`ll-device-menu__item ${d?"is-active":""}`,onClick:()=>a(s.deviceId),role:"option","aria-selected":d,children:[d&&e.jsx("span",{className:"ll-device-menu__dot",children:"●"}),e.jsx("span",{className:"ll-device-menu__name",children:s.label||`${n} ${o+1}`})]},s.deviceId||o)})]}),Nt=new Set(["agent_state","avatar_stream_ready","avatar_active","avatar_idle","bot_ready","agent_error","idle_warning","idle_timeout"]);function Mt(n){var Se,Ee,Ne,Me,Re,Le;const{agentId:r,apiKey:l,baseUrl:a="https://app.livelayer.studio",sessionEndpoint:s,sessionBody:o,autoConnect:d=!1,displayMode:m,defaultDisplayMode:u="expanded",onDisplayModeChange:x,position:f="bottom-right",mobileBreakpoint:c=640,persistKey:i="ll-widget",disablePersistence:y=!1,teamMembers:b,currentTeamMemberId:j,onTeamMemberChange:N,idleLoopUrl:C,greeting:M,avatarImageUrl:R,agentName:L,branding:S={},allowCamera:_=!0,allowScreenShare:k=!0,allowTyping:v=!0,onConnect:E,onDisconnect:G,onTranscript:Q,onAgentState:T,onConnectionStateChange:z,onAgentEvent:U,onAgentCommand:Z,controlledSession:I,className:ge,style:ve,zIndex:fe=2147483647}=n,ae=j!==void 0,[be,ye]=t.useState(()=>{var g;return j??((g=b==null?void 0:b[0])==null?void 0:g.id)}),Y=ae?j:be,D=t.useMemo(()=>(b==null?void 0:b.find(g=>g.id===Y))??null,[b,Y]),he=(D==null?void 0:D.agentId)??r,[H,O]=Ge({value:m,defaultValue:u,onChange:x,persistKey:i,disablePersistence:y}),J=Ye(c),ie=Ue(),P=Oe(),V=Ve(),B=We(),W=Fe(),[ee,F]=t.useState(!1),[oe,ce]=t.useState(!1),[te,K]=t.useState(!1),[ne,re]=t.useState(!1),[q,se]=t.useState(!1),le=t.useCallback(g=>{const w=g;!w.type||typeof w.type!="string"||(U==null||U({eventName:w.type,data:g}),Nt.has(w.type)||Z==null||Z(w))},[Z,U]),A=$e({agentId:I?"__controlled__":he,baseUrl:a,apiKey:l,sessionEndpoint:s,sessionBody:o,onDataMessage:I?void 0:le});t.useEffect(()=>{if(I!=null&&I.subscribeToDataMessages)return I.subscribeToDataMessages(le)},[I,le]);const p=t.useMemo(()=>I?{connectionState:I.connectionState,agentState:I.agentState,transcript:I.transcript,videoElement:I.videoElement,audioElement:I.audioElement,canResume:I.canResume,error:I.error,agentConfig:null,connect:async()=>{await I.onConnect()},disconnect:()=>I.onDisconnect(),getRoom:A.getRoom,isControlled:!0}:{connectionState:A.connectionState,agentState:A.agentState,transcript:A.transcript,videoElement:A.videoElement,audioElement:A.audioElement,canResume:A.canResume,error:A.error,agentConfig:A.agentConfig,connect:A.connect,disconnect:A.disconnect,getRoom:A.getRoom,isControlled:!1},[I,A]),de=t.useRef(null);t.useEffect(()=>{const g=p.videoElement,w=de.current;if(!(!g||!w))return w.appendChild(g),()=>{g.parentNode===w&&w.removeChild(g)}},[p.videoElement]),t.useEffect(()=>{const g=p.audioElement;if(!g)return;ie.attach(g);const w=g.play();return w&&typeof w.catch=="function"&&w.catch(X=>{(X==null?void 0:X.name)==="NotAllowedError"&&F(!0)}),()=>{ie.detach()}},[p.audioElement]),t.useEffect(()=>{if(p.isControlled||p.connectionState!=="connected")return;const g=p.getRoom();if(g)return P.setupMic(g).catch(()=>{}),V.attachRoom(g),B.attachRoom(g),W.refresh(),()=>{P.teardownMic(),V.teardown(),B.teardown()}},[p.isControlled,p.connectionState]),t.useEffect(()=>{const g=p.audioElement;g&&(g.muted=q)},[p.audioElement,q]);const _e=t.useCallback(g=>{const w=p.getRoom();if(w)try{const X=new TextEncoder().encode(JSON.stringify({type:"user_message",text:g}));w.localParticipant.publishData(X,{reliable:!0})}catch{}},[p]),pe=t.useCallback(()=>{se(g=>!g)},[]);t.useEffect(()=>{z==null||z(p.connectionState),p.connectionState==="connected"?E==null||E():p.connectionState==="disconnected"&&(G==null||G())},[p.connectionState,E,G,z]),t.useEffect(()=>{Q==null||Q(p.transcript)},[p.transcript,Q]),t.useEffect(()=>{T==null||T(p.agentState)},[p.agentState,T]);const h=t.useRef(!1);t.useEffect(()=>{p.isControlled||!d||h.current||p.connectionState==="idle"&&(h.current=!0,p.connect())},[d,p.connectionState,p]);const $=t.useCallback(g=>{const w=b==null?void 0:b.find(X=>X.id===g);w&&(K(!1),g!==Y&&(ce(!0),p.disconnect(),ae||ye(g),N==null||N(w)))},[b,Y,p,ae,N]);t.useEffect(()=>{oe&&p.connectionState==="connected"&&ce(!1)},[p.connectionState,oe]),t.useEffect(()=>{if(!te)return;const g=w=>{w.key==="Escape"&&K(!1)};return window.addEventListener("keydown",g),()=>window.removeEventListener("keydown",g)},[te]);const Je=!!R||!!(D!=null&&D.avatarImageUrl)||p.isControlled,ke=Ke(he,a,Je),je=(D==null?void 0:D.name)??L??((Se=p.agentConfig)==null?void 0:Se.name)??((Ee=ke.info)==null?void 0:Ee.name)??"Live Layer",Ce=(D==null?void 0:D.avatarImageUrl)??R??((Ne=p.agentConfig)==null?void 0:Ne.avatarImageUrl)??((Me=ke.info)==null?void 0:Me.avatarImageUrl)??null,Xe=C??((Re=p.agentConfig)==null?void 0:Re.idleLoopUrl)??((Le=ke.info)==null?void 0:Le.idleLoopUrl)??null,Qe=M??null,Ze=t.useCallback(()=>O("expanded"),[O]),et=t.useCallback(()=>O("minimized"),[O]),we=t.useCallback(()=>O("hidden"),[O]),tt=t.useCallback(()=>{const g=p.audioElement;g&&g.play().then(()=>F(!1)).catch(()=>{})},[p.audioElement]),nt=t.useCallback(()=>{F(!1),p.connect()},[p]),ue={...ve,zIndex:fe};S.primaryColor&&(ue["--ll-color-primary"]=S.primaryColor),S.accentColor&&(ue["--ll-color-accent"]=S.accentColor),S.backgroundColor&&(ue["--ll-color-bg"]=S.backgroundColor),S.textColor&&(ue["--ll-color-fg"]=S.textColor);const rt=["ll-widget",`ll-widget--${H}`,`ll-widget--${J?"mobile":"desktop"}`,ge].filter(Boolean).join(" ");return e.jsxs("div",{className:rt,style:ue,"data-display-mode":H,"data-position":f,children:[H==="hidden"&&e.jsx(gt,{position:f,isMobile:J,isSpeaking:p.agentState==="speaking",onExpand:()=>O("expanded"),label:`Open ${je} widget`}),H==="minimized"&&e.jsx(bt,{position:f,isMobile:J,agentName:je,avatarImageUrl:Ce,agentState:p.agentState,isMuted:P.isMuted,audioLevel:ie,onExpand:Ze,onToggleMute:P.toggleMute,onClose:we}),H==="expanded"&&e.jsx(_t,{position:f,isMobile:J,agentName:je,avatarImageUrl:Ce,idleLoopUrl:Xe,greeting:Qe,branding:S,teamMembers:b,currentTeamMemberId:Y,isSwitchingTeamMember:oe,teamSwitcherOpen:te,onToggleTeamSwitcher:()=>K(g=>!g),onSelectTeamMember:$,connectionState:p.connectionState,agentState:p.agentState,transcript:p.transcript,isMuted:P.isMuted,micDevices:W.mics,isCameraEnabled:V.isEnabled,cameraPreviewEl:V.previewEl,cameraDevices:W.cameras,activeCameraId:V.activeDeviceId,isScreenShareEnabled:B.isEnabled,screenPreviewEl:B.previewEl,isSpeakerMuted:q,allowCamera:_,allowScreenShare:k,allowTyping:v,languageMenuOpen:ne,onToggleLanguageMenu:()=>re(g=>!g),needsUserGesture:ee,canResume:p.canResume,micError:P.micError,error:p.error,avatarVideoContainerRef:de,onConnect:()=>void p.connect(),onDisconnect:()=>p.disconnect(),onRetry:nt,onResumeAudio:tt,onToggleMute:P.toggleMute,onToggleCamera:()=>void V.toggle(),onSwitchCameraDevice:g=>void V.switchDevice(g),onToggleScreenShare:()=>void B.toggle(),onToggleSpeaker:pe,onSendMessage:_e,onMinimize:et,onClose:we,onClearMicError:P.clearError})]})}function Rt(n){return e.jsx(Be,{children:e.jsx(Mt,{...n})})}const Lt=({agentId:n,baseUrl:r,apiKey:l,mode:a,onAgentEvent:s,className:o,style:d})=>{const m=t.useRef(null),u=t.useRef(null),x=t.useRef(s);x.current=s;const f=t.useCallback(c=>{var y;const i=c.detail;(y=x.current)==null||y.call(x,i)},[]);return t.useEffect(()=>{const c=m.current;if(!c)return;const i=document.createElement("livelayer-widget");return i.setAttribute("agent-id",n),r&&i.setAttribute("base-url",r),l&&i.setAttribute("api-key",l),a&&i.setAttribute("mode",a),i.addEventListener("agent-event",f),c.appendChild(i),u.current=i,()=>{i.removeEventListener("agent-event",f),c.removeChild(i),u.current=null}},[n]),t.useEffect(()=>{u.current&&(a?u.current.setAttribute("mode",a):u.current.removeAttribute("mode"))},[a]),e.jsx("div",{ref:m,className:o,style:d})};function It(){const[n,r]=t.useState([]),l=t.useCallback(s=>{r(o=>{const d=o.findIndex(m=>m.id===s.id);if(d>=0){const m=o.slice();return m[d]=s,m}return[...o,s]})},[]),a=t.useCallback(()=>r([]),[]);return{entries:n,pushSegment:l,clear:a,latest:n.length>0?n[n.length-1]:null}}exports.AvatarWidget=Rt;exports.ErrorBoundary=Be;exports.LiveLayerWidget=Lt;exports.useAgentInfo=Ke;exports.useAudioLevel=Ue;exports.useCameraState=Ve;exports.useDisplayMode=qe;exports.useDisplayModePersistence=Ge;exports.useIsMobile=Ye;exports.useLiveKitSession=$e;exports.useMediaDevices=Fe;exports.useMicrophoneState=Oe;exports.useScreenShareState=We;exports.useTranscript=It;
|