@avatarfirst/react 0.1.0
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/README.md +75 -0
- package/dist/index.cjs +1731 -0
- package/dist/index.d.cts +430 -0
- package/dist/index.d.ts +430 -0
- package/dist/index.js +1674 -0
- package/package.json +42 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,1731 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
AvatarAgent: () => AvatarAgent,
|
|
24
|
+
AvatarContext: () => AvatarContext,
|
|
25
|
+
AvatarFallback: () => AvatarFallback,
|
|
26
|
+
AvatarFirst: () => AvatarFirst,
|
|
27
|
+
AvatarProvider: () => AvatarProvider,
|
|
28
|
+
AvatarView: () => AvatarView,
|
|
29
|
+
CalendarOverlay: () => CalendarOverlay,
|
|
30
|
+
CardOverlay: () => CardOverlay,
|
|
31
|
+
ChartOverlay: () => ChartOverlay,
|
|
32
|
+
ChatOverlay: () => ChatOverlay,
|
|
33
|
+
ComparisonOverlay: () => ComparisonOverlay,
|
|
34
|
+
ConfirmOverlay: () => ConfirmOverlay,
|
|
35
|
+
DetailCardOverlay: () => DetailCardOverlay,
|
|
36
|
+
FileUploadOverlay: () => FileUploadOverlay,
|
|
37
|
+
FormOverlay: () => FormOverlay,
|
|
38
|
+
InsightOverlay: () => InsightOverlay,
|
|
39
|
+
MapOverlay: () => MapOverlay,
|
|
40
|
+
MediaOverlay: () => MediaOverlay,
|
|
41
|
+
OverlayContainer: () => OverlayContainer,
|
|
42
|
+
ProgressOverlay: () => ProgressOverlay,
|
|
43
|
+
RichTextOverlay: () => RichTextOverlay,
|
|
44
|
+
TableOverlay: () => TableOverlay,
|
|
45
|
+
avatarPulse: () => avatarPulse,
|
|
46
|
+
cardHover: () => cardHover,
|
|
47
|
+
cn: () => cn,
|
|
48
|
+
fadeIn: () => fadeIn,
|
|
49
|
+
fadeInUp: () => fadeInUp,
|
|
50
|
+
getOverlayVariants: () => getOverlayVariants,
|
|
51
|
+
pageTransition: () => pageTransition,
|
|
52
|
+
scaleIn: () => scaleIn,
|
|
53
|
+
slideIn: () => slideIn,
|
|
54
|
+
staggerContainer: () => staggerContainer,
|
|
55
|
+
useAction: () => useAction,
|
|
56
|
+
useAvatar: () => useAvatar,
|
|
57
|
+
useAvatarEvent: () => useAvatarEvent,
|
|
58
|
+
useAvatarFirst: () => useAvatarFirst,
|
|
59
|
+
useOverlay: () => useOverlay
|
|
60
|
+
});
|
|
61
|
+
module.exports = __toCommonJS(index_exports);
|
|
62
|
+
|
|
63
|
+
// src/context/AvatarProvider.tsx
|
|
64
|
+
var import_react2 = require("react");
|
|
65
|
+
|
|
66
|
+
// src/context/AvatarContext.ts
|
|
67
|
+
var import_react = require("react");
|
|
68
|
+
var AvatarContext = (0, import_react.createContext)(null);
|
|
69
|
+
|
|
70
|
+
// src/context/AvatarProvider.tsx
|
|
71
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
72
|
+
function AvatarProvider({ agent, autoStart = false, children }) {
|
|
73
|
+
const [state, setState] = (0, import_react2.useState)(agent.getState());
|
|
74
|
+
const [overlays, setOverlays] = (0, import_react2.useState)(agent.getVisibleOverlays());
|
|
75
|
+
(0, import_react2.useEffect)(() => {
|
|
76
|
+
const unsubState = agent.on("state:changed", ({ to }) => {
|
|
77
|
+
setState(to);
|
|
78
|
+
});
|
|
79
|
+
const unsubOverlay = agent.overlays.events.on("overlay:change", (visible) => {
|
|
80
|
+
setOverlays([...visible]);
|
|
81
|
+
});
|
|
82
|
+
if (autoStart) {
|
|
83
|
+
agent.start();
|
|
84
|
+
}
|
|
85
|
+
return () => {
|
|
86
|
+
unsubState();
|
|
87
|
+
unsubOverlay();
|
|
88
|
+
};
|
|
89
|
+
}, [agent, autoStart]);
|
|
90
|
+
const isConnected = state === "connected" || state === "speaking" || state === "listening" || state === "thinking";
|
|
91
|
+
const value = (0, import_react2.useMemo)(
|
|
92
|
+
() => ({ agent, state, isConnected, overlays }),
|
|
93
|
+
[agent, state, isConnected, overlays]
|
|
94
|
+
);
|
|
95
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AvatarContext.Provider, { value, children });
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// src/hooks/useAvatar.ts
|
|
99
|
+
var import_react3 = require("react");
|
|
100
|
+
function useAvatar() {
|
|
101
|
+
const ctx = (0, import_react3.useContext)(AvatarContext);
|
|
102
|
+
if (!ctx) {
|
|
103
|
+
throw new Error("useAvatar must be used within an AvatarProvider");
|
|
104
|
+
}
|
|
105
|
+
const { agent, state, isConnected } = ctx;
|
|
106
|
+
const start = (0, import_react3.useCallback)(async () => {
|
|
107
|
+
await agent?.start();
|
|
108
|
+
}, [agent]);
|
|
109
|
+
const stop = (0, import_react3.useCallback)(async () => {
|
|
110
|
+
await agent?.stop();
|
|
111
|
+
}, [agent]);
|
|
112
|
+
const speak = (0, import_react3.useCallback)(
|
|
113
|
+
async (text) => {
|
|
114
|
+
await agent?.speak(text);
|
|
115
|
+
},
|
|
116
|
+
[agent]
|
|
117
|
+
);
|
|
118
|
+
const message = (0, import_react3.useCallback)(
|
|
119
|
+
async (text) => {
|
|
120
|
+
await agent?.message(text);
|
|
121
|
+
},
|
|
122
|
+
[agent]
|
|
123
|
+
);
|
|
124
|
+
const interrupt = (0, import_react3.useCallback)(async () => {
|
|
125
|
+
await agent?.interrupt();
|
|
126
|
+
}, [agent]);
|
|
127
|
+
const startListening = (0, import_react3.useCallback)(() => {
|
|
128
|
+
agent?.startListening();
|
|
129
|
+
}, [agent]);
|
|
130
|
+
const stopListening = (0, import_react3.useCallback)(() => {
|
|
131
|
+
agent?.stopListening();
|
|
132
|
+
}, [agent]);
|
|
133
|
+
const attachVideoElement = (0, import_react3.useCallback)(
|
|
134
|
+
(el) => {
|
|
135
|
+
agent?.attachVideoElement(el);
|
|
136
|
+
},
|
|
137
|
+
[agent]
|
|
138
|
+
);
|
|
139
|
+
return {
|
|
140
|
+
agent,
|
|
141
|
+
state,
|
|
142
|
+
isConnected,
|
|
143
|
+
start,
|
|
144
|
+
stop,
|
|
145
|
+
speak,
|
|
146
|
+
message,
|
|
147
|
+
interrupt,
|
|
148
|
+
startListening,
|
|
149
|
+
stopListening,
|
|
150
|
+
attachVideoElement
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// src/hooks/useOverlay.ts
|
|
155
|
+
var import_react4 = require("react");
|
|
156
|
+
function useOverlay(overlayId) {
|
|
157
|
+
const ctx = (0, import_react4.useContext)(AvatarContext);
|
|
158
|
+
if (!ctx) {
|
|
159
|
+
throw new Error("useOverlay must be used within an AvatarProvider");
|
|
160
|
+
}
|
|
161
|
+
const { agent, overlays } = ctx;
|
|
162
|
+
const isVisible = (0, import_react4.useMemo)(() => {
|
|
163
|
+
if (!overlayId) return false;
|
|
164
|
+
return overlays.some((o) => o.id === overlayId);
|
|
165
|
+
}, [overlayId, overlays]);
|
|
166
|
+
const overlayData = (0, import_react4.useMemo)(() => {
|
|
167
|
+
if (!overlayId) return void 0;
|
|
168
|
+
return overlays.find((o) => o.id === overlayId);
|
|
169
|
+
}, [overlayId, overlays]);
|
|
170
|
+
const show = (0, import_react4.useCallback)(
|
|
171
|
+
(config) => {
|
|
172
|
+
agent?.showOverlay(config);
|
|
173
|
+
},
|
|
174
|
+
[agent]
|
|
175
|
+
);
|
|
176
|
+
const hide = (0, import_react4.useCallback)(
|
|
177
|
+
(id) => {
|
|
178
|
+
agent?.hideOverlay(id ?? overlayId ?? "");
|
|
179
|
+
},
|
|
180
|
+
[agent, overlayId]
|
|
181
|
+
);
|
|
182
|
+
return {
|
|
183
|
+
overlays,
|
|
184
|
+
isVisible,
|
|
185
|
+
overlayData,
|
|
186
|
+
show,
|
|
187
|
+
hide
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// src/hooks/useAvatarEvent.ts
|
|
192
|
+
var import_react5 = require("react");
|
|
193
|
+
function useAvatarEvent(event, handler) {
|
|
194
|
+
const ctx = (0, import_react5.useContext)(AvatarContext);
|
|
195
|
+
if (!ctx) {
|
|
196
|
+
throw new Error("useAvatarEvent must be used within an AvatarProvider");
|
|
197
|
+
}
|
|
198
|
+
(0, import_react5.useEffect)(() => {
|
|
199
|
+
if (!ctx.agent) return;
|
|
200
|
+
const unsub = ctx.agent.on(event, handler);
|
|
201
|
+
return unsub;
|
|
202
|
+
}, [ctx.agent, event, handler]);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// src/hooks/useAction.ts
|
|
206
|
+
var import_react6 = require("react");
|
|
207
|
+
function useAction() {
|
|
208
|
+
const ctx = (0, import_react6.useContext)(AvatarContext);
|
|
209
|
+
if (!ctx) {
|
|
210
|
+
throw new Error("useAction must be used within an AvatarProvider");
|
|
211
|
+
}
|
|
212
|
+
const trigger = (0, import_react6.useCallback)(
|
|
213
|
+
(actionId) => {
|
|
214
|
+
ctx.agent?.triggerAction(actionId);
|
|
215
|
+
},
|
|
216
|
+
[ctx.agent]
|
|
217
|
+
);
|
|
218
|
+
return { trigger };
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// src/hooks/useAvatarFirst.ts
|
|
222
|
+
var import_react7 = require("react");
|
|
223
|
+
var import_core = require("@avatarfirst/core");
|
|
224
|
+
function useAvatarFirst(options) {
|
|
225
|
+
const [state, setState] = (0, import_react7.useState)("idle");
|
|
226
|
+
const [sessionId, setSessionId] = (0, import_react7.useState)(null);
|
|
227
|
+
const [greeting, setGreeting] = (0, import_react7.useState)(null);
|
|
228
|
+
const [avatarToken, setAvatarToken] = (0, import_react7.useState)(null);
|
|
229
|
+
const [overlays, setOverlays] = (0, import_react7.useState)([]);
|
|
230
|
+
const [isProcessing, setIsProcessing] = (0, import_react7.useState)(false);
|
|
231
|
+
const [error, setError] = (0, import_react7.useState)(null);
|
|
232
|
+
const clientRef = (0, import_react7.useRef)(null);
|
|
233
|
+
const optionsRef = (0, import_react7.useRef)(options);
|
|
234
|
+
optionsRef.current = options;
|
|
235
|
+
(0, import_react7.useEffect)(() => {
|
|
236
|
+
clientRef.current = new import_core.AvatarFirstClient({
|
|
237
|
+
apiKey: options.apiKey,
|
|
238
|
+
baseUrl: options.baseUrl
|
|
239
|
+
});
|
|
240
|
+
}, [options.apiKey, options.baseUrl]);
|
|
241
|
+
const connect = (0, import_react7.useCallback)(async () => {
|
|
242
|
+
if (!clientRef.current) return null;
|
|
243
|
+
setState("connecting");
|
|
244
|
+
setError(null);
|
|
245
|
+
optionsRef.current.onStateChange?.("connecting");
|
|
246
|
+
try {
|
|
247
|
+
const session = await clientRef.current.createSession();
|
|
248
|
+
setSessionId(session.sessionId);
|
|
249
|
+
setGreeting(session.greeting);
|
|
250
|
+
setAvatarToken(session.avatar ?? null);
|
|
251
|
+
setState("connected");
|
|
252
|
+
optionsRef.current.onStateChange?.("connected");
|
|
253
|
+
return session;
|
|
254
|
+
} catch (err) {
|
|
255
|
+
const msg = err.message;
|
|
256
|
+
setError(msg);
|
|
257
|
+
setState("error");
|
|
258
|
+
optionsRef.current.onStateChange?.("error");
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
}, []);
|
|
262
|
+
const sendMessage = (0, import_react7.useCallback)(async (text) => {
|
|
263
|
+
if (!clientRef.current || !sessionId || isProcessing) return null;
|
|
264
|
+
setIsProcessing(true);
|
|
265
|
+
try {
|
|
266
|
+
const response = await clientRef.current.sendMessage(sessionId, text);
|
|
267
|
+
if (response.overlay) {
|
|
268
|
+
setOverlays((prev) => [...prev, response.overlay]);
|
|
269
|
+
optionsRef.current.onOverlay?.(response.overlay);
|
|
270
|
+
}
|
|
271
|
+
if (response.actions) {
|
|
272
|
+
for (const action of response.actions) {
|
|
273
|
+
optionsRef.current.onAction?.(action);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
setIsProcessing(false);
|
|
277
|
+
return response;
|
|
278
|
+
} catch (err) {
|
|
279
|
+
setError(err.message);
|
|
280
|
+
setIsProcessing(false);
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
}, [sessionId, isProcessing]);
|
|
284
|
+
const disconnect = (0, import_react7.useCallback)(() => {
|
|
285
|
+
if (clientRef.current && sessionId) {
|
|
286
|
+
clientRef.current.endSession(sessionId);
|
|
287
|
+
}
|
|
288
|
+
setSessionId(null);
|
|
289
|
+
setGreeting(null);
|
|
290
|
+
setAvatarToken(null);
|
|
291
|
+
setOverlays([]);
|
|
292
|
+
setState("idle");
|
|
293
|
+
optionsRef.current.onStateChange?.("idle");
|
|
294
|
+
}, [sessionId]);
|
|
295
|
+
return {
|
|
296
|
+
state,
|
|
297
|
+
sessionId,
|
|
298
|
+
greeting,
|
|
299
|
+
avatarToken,
|
|
300
|
+
overlays,
|
|
301
|
+
isProcessing,
|
|
302
|
+
error,
|
|
303
|
+
connect,
|
|
304
|
+
sendMessage,
|
|
305
|
+
disconnect
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// src/components/overlays/OverlayContainer.tsx
|
|
310
|
+
var import_framer_motion = require("framer-motion");
|
|
311
|
+
|
|
312
|
+
// src/animations/overlayAnimations.ts
|
|
313
|
+
function getOverlayVariants(animation = "fade") {
|
|
314
|
+
if (typeof animation === "object") {
|
|
315
|
+
return {
|
|
316
|
+
initial: animation.enter,
|
|
317
|
+
animate: animation.enter,
|
|
318
|
+
exit: animation.exit
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
switch (animation) {
|
|
322
|
+
case "fade":
|
|
323
|
+
return {
|
|
324
|
+
initial: { opacity: 0 },
|
|
325
|
+
animate: { opacity: 1, transition: { duration: 0.3 } },
|
|
326
|
+
exit: { opacity: 0, transition: { duration: 0.2 } }
|
|
327
|
+
};
|
|
328
|
+
case "slide-up":
|
|
329
|
+
return {
|
|
330
|
+
initial: { opacity: 0, y: 40 },
|
|
331
|
+
animate: { opacity: 1, y: 0, transition: { type: "spring", stiffness: 300, damping: 25 } },
|
|
332
|
+
exit: { opacity: 0, y: 40, transition: { duration: 0.2 } }
|
|
333
|
+
};
|
|
334
|
+
case "slide-down":
|
|
335
|
+
return {
|
|
336
|
+
initial: { opacity: 0, y: -40 },
|
|
337
|
+
animate: { opacity: 1, y: 0, transition: { type: "spring", stiffness: 300, damping: 25 } },
|
|
338
|
+
exit: { opacity: 0, y: -40, transition: { duration: 0.2 } }
|
|
339
|
+
};
|
|
340
|
+
case "slide-left":
|
|
341
|
+
return {
|
|
342
|
+
initial: { opacity: 0, x: 40 },
|
|
343
|
+
animate: { opacity: 1, x: 0, transition: { type: "spring", stiffness: 300, damping: 25 } },
|
|
344
|
+
exit: { opacity: 0, x: 40, transition: { duration: 0.2 } }
|
|
345
|
+
};
|
|
346
|
+
case "slide-right":
|
|
347
|
+
return {
|
|
348
|
+
initial: { opacity: 0, x: -40 },
|
|
349
|
+
animate: { opacity: 1, x: 0, transition: { type: "spring", stiffness: 300, damping: 25 } },
|
|
350
|
+
exit: { opacity: 0, x: -40, transition: { duration: 0.2 } }
|
|
351
|
+
};
|
|
352
|
+
case "scale":
|
|
353
|
+
return {
|
|
354
|
+
initial: { opacity: 0, scale: 0.85 },
|
|
355
|
+
animate: { opacity: 1, scale: 1, transition: { type: "spring", stiffness: 300, damping: 25 } },
|
|
356
|
+
exit: { opacity: 0, scale: 0.85, transition: { duration: 0.2 } }
|
|
357
|
+
};
|
|
358
|
+
case "none":
|
|
359
|
+
return {
|
|
360
|
+
initial: {},
|
|
361
|
+
animate: {},
|
|
362
|
+
exit: {}
|
|
363
|
+
};
|
|
364
|
+
default:
|
|
365
|
+
return {
|
|
366
|
+
initial: { opacity: 0 },
|
|
367
|
+
animate: { opacity: 1 },
|
|
368
|
+
exit: { opacity: 0 }
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// src/components/overlays/OverlayContainer.tsx
|
|
374
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
375
|
+
function getPositionStyles(position = "bottom-center") {
|
|
376
|
+
if (typeof position === "object") {
|
|
377
|
+
return { position: "absolute", left: position.x, top: position.y };
|
|
378
|
+
}
|
|
379
|
+
const base = { position: "absolute" };
|
|
380
|
+
switch (position) {
|
|
381
|
+
case "center":
|
|
382
|
+
return { ...base, top: "50%", left: "50%", transform: "translate(-50%, -50%)" };
|
|
383
|
+
case "bottom-center":
|
|
384
|
+
return { ...base, bottom: "2rem", left: "50%", transform: "translateX(-50%)" };
|
|
385
|
+
case "bottom-right":
|
|
386
|
+
return { ...base, bottom: "2rem", right: "2rem" };
|
|
387
|
+
case "bottom-left":
|
|
388
|
+
return { ...base, bottom: "2rem", left: "2rem" };
|
|
389
|
+
case "top-center":
|
|
390
|
+
return { ...base, top: "2rem", left: "50%", transform: "translateX(-50%)" };
|
|
391
|
+
case "right-center":
|
|
392
|
+
return { ...base, top: "50%", right: "2rem", transform: "translateY(-50%)" };
|
|
393
|
+
case "fullscreen":
|
|
394
|
+
return { ...base, inset: 0 };
|
|
395
|
+
default:
|
|
396
|
+
return { ...base, bottom: "2rem", left: "50%", transform: "translateX(-50%)" };
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
function OverlayContainer({ components }) {
|
|
400
|
+
const { overlays, hide } = useOverlay();
|
|
401
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "fixed inset-0 pointer-events-none z-40", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_framer_motion.AnimatePresence, { children: overlays.map((overlay) => {
|
|
402
|
+
const Component = components[overlay.component];
|
|
403
|
+
if (!Component) return null;
|
|
404
|
+
const variants = getOverlayVariants(overlay.animation);
|
|
405
|
+
const positionStyle = getPositionStyles(overlay.position);
|
|
406
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
407
|
+
import_framer_motion.motion.div,
|
|
408
|
+
{
|
|
409
|
+
variants,
|
|
410
|
+
initial: "initial",
|
|
411
|
+
animate: "animate",
|
|
412
|
+
exit: "exit",
|
|
413
|
+
style: positionStyle,
|
|
414
|
+
className: "pointer-events-auto",
|
|
415
|
+
onClick: overlay.dismissOnClickOutside ? (e) => {
|
|
416
|
+
if (e.target === e.currentTarget) hide(overlay.id);
|
|
417
|
+
} : void 0,
|
|
418
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
419
|
+
Component,
|
|
420
|
+
{
|
|
421
|
+
data: overlay.data,
|
|
422
|
+
overlayId: overlay.id,
|
|
423
|
+
onDismiss: () => hide(overlay.id)
|
|
424
|
+
}
|
|
425
|
+
)
|
|
426
|
+
},
|
|
427
|
+
overlay.id
|
|
428
|
+
);
|
|
429
|
+
}) }) });
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// src/components/AvatarAgent.tsx
|
|
433
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
434
|
+
function AvatarAgent({
|
|
435
|
+
config,
|
|
436
|
+
overlayComponents = {},
|
|
437
|
+
autoStart = false,
|
|
438
|
+
children
|
|
439
|
+
}) {
|
|
440
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(AvatarProvider, { agent: config, autoStart, children: [
|
|
441
|
+
children,
|
|
442
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(OverlayContainer, { components: overlayComponents })
|
|
443
|
+
] });
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// src/components/AvatarFirst.tsx
|
|
447
|
+
var import_react14 = require("react");
|
|
448
|
+
var import_core2 = require("@avatarfirst/core");
|
|
449
|
+
|
|
450
|
+
// src/components/AvatarView.tsx
|
|
451
|
+
var import_react8 = require("react");
|
|
452
|
+
var import_framer_motion3 = require("framer-motion");
|
|
453
|
+
|
|
454
|
+
// src/components/AvatarFallback.tsx
|
|
455
|
+
var import_framer_motion2 = require("framer-motion");
|
|
456
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
457
|
+
function AvatarFallback({ size, state }) {
|
|
458
|
+
const isSmall = size === "small";
|
|
459
|
+
const isMedium = size === "medium";
|
|
460
|
+
const faceSize = isSmall ? "w-12 h-12" : isMedium ? "w-24 h-24" : "w-full h-full";
|
|
461
|
+
const eyeSize = isSmall ? 4 : isMedium ? 6 : 12;
|
|
462
|
+
const mouthWidth = isSmall ? 15 : isMedium ? 25 : 50;
|
|
463
|
+
if (state === "connecting") {
|
|
464
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "relative w-full h-full flex items-center justify-center", children: [
|
|
465
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
466
|
+
import_framer_motion2.motion.div,
|
|
467
|
+
{
|
|
468
|
+
className: "absolute inset-4 rounded-full border-4 border-blue-500/30",
|
|
469
|
+
animate: { scale: [1, 1.2, 1], opacity: [0.5, 0, 0.5] },
|
|
470
|
+
transition: { duration: 2, repeat: Infinity }
|
|
471
|
+
}
|
|
472
|
+
),
|
|
473
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
474
|
+
import_framer_motion2.motion.div,
|
|
475
|
+
{
|
|
476
|
+
className: "absolute inset-8 rounded-full border-4 border-purple-500/30",
|
|
477
|
+
animate: { scale: [1, 1.3, 1], opacity: [0.5, 0, 0.5] },
|
|
478
|
+
transition: { duration: 2, repeat: Infinity, delay: 0.3 }
|
|
479
|
+
}
|
|
480
|
+
),
|
|
481
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
482
|
+
import_framer_motion2.motion.div,
|
|
483
|
+
{
|
|
484
|
+
className: "w-10 h-10 border-4 border-white/30 border-t-white rounded-full",
|
|
485
|
+
animate: { rotate: 360 },
|
|
486
|
+
transition: { duration: 1, repeat: Infinity, ease: "linear" }
|
|
487
|
+
}
|
|
488
|
+
)
|
|
489
|
+
] });
|
|
490
|
+
}
|
|
491
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: `relative ${faceSize}`, children: [
|
|
492
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
493
|
+
import_framer_motion2.motion.div,
|
|
494
|
+
{
|
|
495
|
+
className: "absolute inset-0 rounded-full bg-gradient-to-br from-blue-400 via-purple-500 to-pink-500",
|
|
496
|
+
animate: {
|
|
497
|
+
background: [
|
|
498
|
+
"linear-gradient(135deg, #60a5fa, #a855f7, #ec4899)",
|
|
499
|
+
"linear-gradient(135deg, #a855f7, #ec4899, #60a5fa)",
|
|
500
|
+
"linear-gradient(135deg, #ec4899, #60a5fa, #a855f7)",
|
|
501
|
+
"linear-gradient(135deg, #60a5fa, #a855f7, #ec4899)"
|
|
502
|
+
]
|
|
503
|
+
},
|
|
504
|
+
transition: { duration: 8, repeat: Infinity, ease: "linear" }
|
|
505
|
+
}
|
|
506
|
+
),
|
|
507
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "absolute inset-2 rounded-full bg-gradient-to-br from-white/30 to-transparent" }),
|
|
508
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { viewBox: "0 0 100 100", className: "absolute inset-0 w-full h-full", children: [
|
|
509
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
510
|
+
import_framer_motion2.motion.ellipse,
|
|
511
|
+
{
|
|
512
|
+
cx: "35",
|
|
513
|
+
cy: "42",
|
|
514
|
+
rx: eyeSize,
|
|
515
|
+
ry: eyeSize,
|
|
516
|
+
fill: "white",
|
|
517
|
+
animate: { ry: [eyeSize, eyeSize * 0.1, eyeSize] },
|
|
518
|
+
transition: { duration: 0.15, repeat: Infinity, repeatDelay: 4, times: [0, 0.5, 1] }
|
|
519
|
+
}
|
|
520
|
+
),
|
|
521
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
522
|
+
import_framer_motion2.motion.circle,
|
|
523
|
+
{
|
|
524
|
+
cx: "35",
|
|
525
|
+
cy: "42",
|
|
526
|
+
r: eyeSize * 0.5,
|
|
527
|
+
fill: "#1e293b",
|
|
528
|
+
animate: { cx: [35, 37, 35, 33, 35] },
|
|
529
|
+
transition: { duration: 3, repeat: Infinity, ease: "easeInOut" }
|
|
530
|
+
}
|
|
531
|
+
),
|
|
532
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "37", cy: "40", r: eyeSize * 0.2, fill: "white", opacity: "0.8" }),
|
|
533
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
534
|
+
import_framer_motion2.motion.ellipse,
|
|
535
|
+
{
|
|
536
|
+
cx: "65",
|
|
537
|
+
cy: "42",
|
|
538
|
+
rx: eyeSize,
|
|
539
|
+
ry: eyeSize,
|
|
540
|
+
fill: "white",
|
|
541
|
+
animate: { ry: [eyeSize, eyeSize * 0.1, eyeSize] },
|
|
542
|
+
transition: { duration: 0.15, repeat: Infinity, repeatDelay: 4, times: [0, 0.5, 1] }
|
|
543
|
+
}
|
|
544
|
+
),
|
|
545
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
546
|
+
import_framer_motion2.motion.circle,
|
|
547
|
+
{
|
|
548
|
+
cx: "65",
|
|
549
|
+
cy: "42",
|
|
550
|
+
r: eyeSize * 0.5,
|
|
551
|
+
fill: "#1e293b",
|
|
552
|
+
animate: { cx: [65, 67, 65, 63, 65] },
|
|
553
|
+
transition: { duration: 3, repeat: Infinity, ease: "easeInOut" }
|
|
554
|
+
}
|
|
555
|
+
),
|
|
556
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "67", cy: "40", r: eyeSize * 0.2, fill: "white", opacity: "0.8" }),
|
|
557
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
558
|
+
import_framer_motion2.motion.path,
|
|
559
|
+
{
|
|
560
|
+
d: state === "speaking" ? `M ${50 - mouthWidth / 2} 62 Q 50 75 ${50 + mouthWidth / 2} 62` : `M ${50 - mouthWidth / 2} 65 Q 50 72 ${50 + mouthWidth / 2} 65`,
|
|
561
|
+
stroke: "white",
|
|
562
|
+
strokeWidth: isSmall ? 2 : isMedium ? 3 : 4,
|
|
563
|
+
fill: state === "speaking" ? "rgba(255,255,255,0.3)" : "none",
|
|
564
|
+
strokeLinecap: "round",
|
|
565
|
+
animate: state === "speaking" ? {
|
|
566
|
+
d: [
|
|
567
|
+
`M ${50 - mouthWidth / 2} 62 Q 50 75 ${50 + mouthWidth / 2} 62`,
|
|
568
|
+
`M ${50 - mouthWidth / 2} 62 Q 50 68 ${50 + mouthWidth / 2} 62`,
|
|
569
|
+
`M ${50 - mouthWidth / 2} 62 Q 50 78 ${50 + mouthWidth / 2} 62`,
|
|
570
|
+
`M ${50 - mouthWidth / 2} 62 Q 50 70 ${50 + mouthWidth / 2} 62`
|
|
571
|
+
]
|
|
572
|
+
} : {},
|
|
573
|
+
transition: { duration: 0.3, repeat: Infinity, ease: "easeInOut" }
|
|
574
|
+
}
|
|
575
|
+
)
|
|
576
|
+
] })
|
|
577
|
+
] });
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// src/components/AvatarView.tsx
|
|
581
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
582
|
+
var sizeClasses = {
|
|
583
|
+
small: "w-16 h-16",
|
|
584
|
+
medium: "w-32 h-32",
|
|
585
|
+
large: "w-64 h-64",
|
|
586
|
+
fullscreen: "w-full h-full",
|
|
587
|
+
hero: "w-[500px] h-[500px]"
|
|
588
|
+
};
|
|
589
|
+
function AvatarView({ size = "medium", showStatus = true, className = "" }) {
|
|
590
|
+
const { state, attachVideoElement } = useAvatar();
|
|
591
|
+
const videoRef = (0, import_react8.useRef)(null);
|
|
592
|
+
(0, import_react8.useEffect)(() => {
|
|
593
|
+
if (videoRef.current) {
|
|
594
|
+
attachVideoElement(videoRef.current);
|
|
595
|
+
}
|
|
596
|
+
}, [attachVideoElement]);
|
|
597
|
+
const isConnected = state === "connected" || state === "speaking" || state === "listening" || state === "thinking";
|
|
598
|
+
const isFullscreen = size === "fullscreen";
|
|
599
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: `relative ${className}`, children: [
|
|
600
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
601
|
+
import_framer_motion3.motion.div,
|
|
602
|
+
{
|
|
603
|
+
className: `relative overflow-hidden ${isFullscreen ? "rounded-2xl" : "rounded-full"} ${sizeClasses[size]}`,
|
|
604
|
+
animate: {
|
|
605
|
+
scale: state === "speaking" ? [1, 1.02, 1] : 1
|
|
606
|
+
},
|
|
607
|
+
transition: {
|
|
608
|
+
duration: state === "speaking" ? 0.5 : 0.3,
|
|
609
|
+
repeat: state === "speaking" ? Infinity : 0
|
|
610
|
+
},
|
|
611
|
+
children: [
|
|
612
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
613
|
+
"video",
|
|
614
|
+
{
|
|
615
|
+
ref: videoRef,
|
|
616
|
+
autoPlay: true,
|
|
617
|
+
playsInline: true,
|
|
618
|
+
className: `absolute inset-0 w-full h-full object-cover ${!isConnected ? "hidden" : ""}`
|
|
619
|
+
}
|
|
620
|
+
),
|
|
621
|
+
!isConnected && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "absolute inset-0 flex items-center justify-center bg-gradient-to-br from-slate-800 to-slate-900", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(AvatarFallback, { state, size }) }),
|
|
622
|
+
state === "connecting" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
623
|
+
import_framer_motion3.motion.div,
|
|
624
|
+
{
|
|
625
|
+
className: "absolute inset-0 rounded-full border-4 border-yellow-500",
|
|
626
|
+
animate: { rotate: 360 },
|
|
627
|
+
transition: { duration: 2, repeat: Infinity, ease: "linear" },
|
|
628
|
+
style: { borderTopColor: "transparent", borderLeftColor: "transparent" }
|
|
629
|
+
}
|
|
630
|
+
),
|
|
631
|
+
state === "connected" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
632
|
+
import_framer_motion3.motion.div,
|
|
633
|
+
{
|
|
634
|
+
className: "absolute inset-0 rounded-full border-4 border-green-500/50",
|
|
635
|
+
animate: { opacity: [0.3, 0.6, 0.3] },
|
|
636
|
+
transition: { duration: 2, repeat: Infinity }
|
|
637
|
+
}
|
|
638
|
+
),
|
|
639
|
+
state === "speaking" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
640
|
+
import_framer_motion3.motion.div,
|
|
641
|
+
{
|
|
642
|
+
className: "absolute inset-0 rounded-full border-4 border-blue-400",
|
|
643
|
+
animate: { scale: [1, 1.03, 1], opacity: [0.7, 1, 0.7] },
|
|
644
|
+
transition: { duration: 0.5, repeat: Infinity }
|
|
645
|
+
}
|
|
646
|
+
)
|
|
647
|
+
]
|
|
648
|
+
}
|
|
649
|
+
),
|
|
650
|
+
showStatus && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
651
|
+
import_framer_motion3.motion.div,
|
|
652
|
+
{
|
|
653
|
+
className: `absolute flex items-center gap-1 px-2 py-1 rounded-full text-xs font-medium shadow-lg ${state === "disconnected" ? "bg-slate-600 text-white" : state === "connecting" ? "bg-yellow-500 text-white" : state === "connected" ? "bg-green-500 text-white" : state === "speaking" ? "bg-blue-500 text-white" : state === "listening" ? "bg-purple-500 text-white" : "bg-slate-600 text-white"} ${size === "small" ? "-bottom-1 -right-1 text-[10px] px-1.5 py-0.5" : size === "medium" ? "bottom-0 right-0" : size === "large" ? "bottom-2 right-2" : "bottom-4 right-4 text-sm px-3 py-1.5"}`,
|
|
654
|
+
initial: { scale: 0 },
|
|
655
|
+
animate: { scale: 1 },
|
|
656
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "capitalize", children: state === "disconnected" ? "Offline" : state })
|
|
657
|
+
},
|
|
658
|
+
state
|
|
659
|
+
)
|
|
660
|
+
] });
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
// src/components/overlays/CardOverlay.tsx
|
|
664
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
665
|
+
function CardOverlay({ data, onDismiss }) {
|
|
666
|
+
const { title, description, items, actions } = data ?? {};
|
|
667
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "bg-white rounded-2xl shadow-2xl p-6 min-w-[300px] max-w-md", children: [
|
|
668
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h3", { className: "text-lg font-semibold mb-1", children: title }),
|
|
669
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-sm text-gray-500 mb-4", children: description }),
|
|
670
|
+
items && items.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "space-y-2 mb-4", children: items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center justify-between py-2 border-b border-gray-100 last:border-0", children: [
|
|
671
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-sm font-medium text-gray-700", children: item.label }),
|
|
672
|
+
item.value && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-sm text-gray-500", children: item.value })
|
|
673
|
+
] }, i)) }),
|
|
674
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex gap-2 justify-end", children: [
|
|
675
|
+
actions?.map((action, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
676
|
+
"button",
|
|
677
|
+
{
|
|
678
|
+
onClick: action.onClick,
|
|
679
|
+
className: "px-4 py-2 text-sm font-medium rounded-lg bg-blue-500 text-white hover:bg-blue-600 transition-colors",
|
|
680
|
+
children: action.label
|
|
681
|
+
},
|
|
682
|
+
i
|
|
683
|
+
)),
|
|
684
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
685
|
+
"button",
|
|
686
|
+
{
|
|
687
|
+
onClick: onDismiss,
|
|
688
|
+
className: "px-4 py-2 text-sm font-medium rounded-lg bg-gray-100 text-gray-700 hover:bg-gray-200 transition-colors",
|
|
689
|
+
children: "Close"
|
|
690
|
+
}
|
|
691
|
+
)
|
|
692
|
+
] })
|
|
693
|
+
] });
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
// src/components/overlays/FormOverlay.tsx
|
|
697
|
+
var import_react9 = require("react");
|
|
698
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
699
|
+
function FormOverlay({ data, onDismiss }) {
|
|
700
|
+
const { title, fields = [], submitLabel = "Submit", onSubmit } = data ?? {};
|
|
701
|
+
const [values, setValues] = (0, import_react9.useState)({});
|
|
702
|
+
const handleSubmit = (e) => {
|
|
703
|
+
e.preventDefault();
|
|
704
|
+
onSubmit?.(values);
|
|
705
|
+
onDismiss();
|
|
706
|
+
};
|
|
707
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "bg-white rounded-2xl shadow-2xl p-6 min-w-[320px] max-w-md", children: [
|
|
708
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h3", { className: "text-lg font-semibold mb-4", children: title }),
|
|
709
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("form", { onSubmit: handleSubmit, className: "space-y-3", children: [
|
|
710
|
+
fields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { children: [
|
|
711
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: field.label }),
|
|
712
|
+
field.type === "textarea" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
713
|
+
"textarea",
|
|
714
|
+
{
|
|
715
|
+
className: "w-full border border-gray-200 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500",
|
|
716
|
+
placeholder: field.placeholder,
|
|
717
|
+
required: field.required,
|
|
718
|
+
value: values[field.name] ?? "",
|
|
719
|
+
onChange: (e) => setValues((v) => ({ ...v, [field.name]: e.target.value }))
|
|
720
|
+
}
|
|
721
|
+
) : field.type === "select" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
722
|
+
"select",
|
|
723
|
+
{
|
|
724
|
+
className: "w-full border border-gray-200 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500",
|
|
725
|
+
required: field.required,
|
|
726
|
+
value: values[field.name] ?? "",
|
|
727
|
+
onChange: (e) => setValues((v) => ({ ...v, [field.name]: e.target.value })),
|
|
728
|
+
children: [
|
|
729
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "", children: field.placeholder ?? "Select..." }),
|
|
730
|
+
field.options?.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: opt, children: opt }, opt))
|
|
731
|
+
]
|
|
732
|
+
}
|
|
733
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
734
|
+
"input",
|
|
735
|
+
{
|
|
736
|
+
type: field.type ?? "text",
|
|
737
|
+
className: "w-full border border-gray-200 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500",
|
|
738
|
+
placeholder: field.placeholder,
|
|
739
|
+
required: field.required,
|
|
740
|
+
value: values[field.name] ?? "",
|
|
741
|
+
onChange: (e) => setValues((v) => ({ ...v, [field.name]: e.target.value }))
|
|
742
|
+
}
|
|
743
|
+
)
|
|
744
|
+
] }, field.name)),
|
|
745
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex gap-2 justify-end pt-2", children: [
|
|
746
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
747
|
+
"button",
|
|
748
|
+
{
|
|
749
|
+
type: "submit",
|
|
750
|
+
className: "px-4 py-2 text-sm font-medium rounded-lg bg-blue-500 text-white hover:bg-blue-600 transition-colors",
|
|
751
|
+
children: submitLabel
|
|
752
|
+
}
|
|
753
|
+
),
|
|
754
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
755
|
+
"button",
|
|
756
|
+
{
|
|
757
|
+
type: "button",
|
|
758
|
+
onClick: onDismiss,
|
|
759
|
+
className: "px-4 py-2 text-sm font-medium rounded-lg bg-gray-100 text-gray-700 hover:bg-gray-200 transition-colors",
|
|
760
|
+
children: "Cancel"
|
|
761
|
+
}
|
|
762
|
+
)
|
|
763
|
+
] })
|
|
764
|
+
] })
|
|
765
|
+
] });
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
// src/components/overlays/TableOverlay.tsx
|
|
769
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
770
|
+
function TableOverlay({ data, onDismiss }) {
|
|
771
|
+
const { title, columns = [], rows = [] } = data ?? {};
|
|
772
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "bg-white rounded-2xl shadow-2xl p-6 min-w-[400px] max-w-2xl overflow-x-auto", children: [
|
|
773
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center justify-between mb-4", children: [
|
|
774
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { className: "text-lg font-semibold", children: title }),
|
|
775
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { onClick: onDismiss, className: "text-gray-400 hover:text-gray-600 text-sm", children: "Close" })
|
|
776
|
+
] }),
|
|
777
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("table", { className: "w-full", children: [
|
|
778
|
+
columns.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("tr", { className: "border-b", children: columns.map((col, i) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("th", { className: "text-left py-2 px-3 text-sm font-medium text-gray-500", children: col }, i)) }) }),
|
|
779
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("tbody", { children: rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("tr", { className: "border-b last:border-0 hover:bg-gray-50", children: row.map((cell, j) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { className: "py-2 px-3 text-sm text-gray-700", children: cell }, j)) }, i)) })
|
|
780
|
+
] })
|
|
781
|
+
] });
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
// src/components/overlays/ProgressOverlay.tsx
|
|
785
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
786
|
+
function ProgressOverlay({ data, onDismiss }) {
|
|
787
|
+
const { title, steps = [] } = data ?? {};
|
|
788
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "bg-white rounded-2xl shadow-2xl p-6 min-w-[280px] max-w-sm", children: [
|
|
789
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h3", { className: "text-lg font-semibold mb-4", children: title }),
|
|
790
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "space-y-3", children: steps.map((step, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-3", children: [
|
|
791
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
792
|
+
"div",
|
|
793
|
+
{
|
|
794
|
+
className: `w-8 h-8 rounded-full flex items-center justify-center text-sm font-medium ${step.completed ? "bg-green-500 text-white" : step.active ? "bg-blue-500 text-white" : "bg-gray-100 text-gray-400"}`,
|
|
795
|
+
children: step.completed ? "\u2713" : i + 1
|
|
796
|
+
}
|
|
797
|
+
),
|
|
798
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: `text-sm ${step.completed ? "text-gray-500 line-through" : step.active ? "text-gray-900 font-medium" : "text-gray-400"}`, children: step.label })
|
|
799
|
+
] }, i)) }),
|
|
800
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
801
|
+
"button",
|
|
802
|
+
{
|
|
803
|
+
onClick: onDismiss,
|
|
804
|
+
className: "mt-4 w-full py-2 text-sm font-medium rounded-lg bg-gray-100 text-gray-700 hover:bg-gray-200 transition-colors",
|
|
805
|
+
children: "Close"
|
|
806
|
+
}
|
|
807
|
+
)
|
|
808
|
+
] });
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
// src/components/overlays/ConfirmOverlay.tsx
|
|
812
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
813
|
+
function ConfirmOverlay({ data, onDismiss }) {
|
|
814
|
+
const { title, message, confirmLabel = "Confirm", cancelLabel = "Cancel", onConfirm, onCancel } = data ?? {};
|
|
815
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "bg-white rounded-2xl shadow-2xl p-6 min-w-[300px] max-w-sm", children: [
|
|
816
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h3", { className: "text-lg font-semibold mb-2", children: title }),
|
|
817
|
+
message && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-sm text-gray-500 mb-6", children: message }),
|
|
818
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex gap-3", children: [
|
|
819
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
820
|
+
"button",
|
|
821
|
+
{
|
|
822
|
+
onClick: () => {
|
|
823
|
+
onConfirm?.();
|
|
824
|
+
onDismiss();
|
|
825
|
+
},
|
|
826
|
+
className: "flex-1 py-2 text-sm font-medium rounded-lg bg-blue-500 text-white hover:bg-blue-600 transition-colors",
|
|
827
|
+
children: confirmLabel
|
|
828
|
+
}
|
|
829
|
+
),
|
|
830
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
831
|
+
"button",
|
|
832
|
+
{
|
|
833
|
+
onClick: () => {
|
|
834
|
+
onCancel?.();
|
|
835
|
+
onDismiss();
|
|
836
|
+
},
|
|
837
|
+
className: "flex-1 py-2 text-sm font-medium rounded-lg bg-gray-100 text-gray-700 hover:bg-gray-200 transition-colors",
|
|
838
|
+
children: cancelLabel
|
|
839
|
+
}
|
|
840
|
+
)
|
|
841
|
+
] })
|
|
842
|
+
] });
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
// src/components/overlays/ChatOverlay.tsx
|
|
846
|
+
var import_react10 = require("react");
|
|
847
|
+
var import_framer_motion4 = require("framer-motion");
|
|
848
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
849
|
+
function ChatOverlay({ data, onDismiss }) {
|
|
850
|
+
const { title = "Chat", messages: initialMessages = [], suggestions = [] } = data ?? {};
|
|
851
|
+
const [messages, setMessages] = (0, import_react10.useState)(initialMessages);
|
|
852
|
+
const [input, setInput] = (0, import_react10.useState)("");
|
|
853
|
+
const { speak } = useAvatar();
|
|
854
|
+
const handleSend = async () => {
|
|
855
|
+
if (!input.trim()) return;
|
|
856
|
+
const userMsg = {
|
|
857
|
+
id: Date.now().toString(),
|
|
858
|
+
role: "user",
|
|
859
|
+
content: input,
|
|
860
|
+
timestamp: (/* @__PURE__ */ new Date()).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })
|
|
861
|
+
};
|
|
862
|
+
setMessages((prev) => [...prev, userMsg]);
|
|
863
|
+
setInput("");
|
|
864
|
+
await speak(`I understand you want to ${input.toLowerCase()}. Let me help you with that.`);
|
|
865
|
+
const aiMsg = {
|
|
866
|
+
id: (Date.now() + 1).toString(),
|
|
867
|
+
role: "assistant",
|
|
868
|
+
content: `I'll help you ${input.toLowerCase()}. This action has been queued.`,
|
|
869
|
+
timestamp: (/* @__PURE__ */ new Date()).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })
|
|
870
|
+
};
|
|
871
|
+
setMessages((prev) => [...prev, aiMsg]);
|
|
872
|
+
};
|
|
873
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "bg-white rounded-2xl shadow-2xl overflow-hidden w-96 flex flex-col", style: { maxHeight: "500px" }, children: [
|
|
874
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "bg-gradient-to-r from-blue-500 to-blue-600 p-4 flex items-center justify-between", children: [
|
|
875
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h3", { className: "text-white font-semibold", children: title }),
|
|
876
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { onClick: onDismiss, className: "text-white/70 hover:text-white text-sm", children: "Close" })
|
|
877
|
+
] }),
|
|
878
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "flex-1 overflow-y-auto p-4 space-y-3", children: messages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "text-center text-gray-400 py-8", children: [
|
|
879
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "font-medium mb-4", children: "How can I help?" }),
|
|
880
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "space-y-2", children: suggestions.map((s) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
881
|
+
"button",
|
|
882
|
+
{
|
|
883
|
+
className: "block w-full text-left text-sm p-2 rounded-lg bg-gray-100 hover:bg-gray-200 transition-colors",
|
|
884
|
+
onClick: () => setInput(s),
|
|
885
|
+
children: s
|
|
886
|
+
},
|
|
887
|
+
s
|
|
888
|
+
)) })
|
|
889
|
+
] }) : messages.map((msg) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
890
|
+
import_framer_motion4.motion.div,
|
|
891
|
+
{
|
|
892
|
+
className: `flex ${msg.role === "user" ? "justify-end" : "justify-start"}`,
|
|
893
|
+
initial: { opacity: 0, y: 10 },
|
|
894
|
+
animate: { opacity: 1, y: 0 },
|
|
895
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: `max-w-[80%] p-3 rounded-2xl ${msg.role === "user" ? "bg-blue-500 text-white rounded-br-none" : "bg-gray-100 text-gray-800 rounded-bl-none"}`, children: [
|
|
896
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "text-sm", children: msg.content }),
|
|
897
|
+
msg.timestamp && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: `text-xs mt-1 ${msg.role === "user" ? "text-blue-100" : "text-gray-400"}`, children: msg.timestamp })
|
|
898
|
+
] })
|
|
899
|
+
},
|
|
900
|
+
msg.id
|
|
901
|
+
)) }),
|
|
902
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "p-3 border-t", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex gap-2", children: [
|
|
903
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
904
|
+
"input",
|
|
905
|
+
{
|
|
906
|
+
value: input,
|
|
907
|
+
onChange: (e) => setInput(e.target.value),
|
|
908
|
+
onKeyDown: (e) => e.key === "Enter" && handleSend(),
|
|
909
|
+
placeholder: "Type a message...",
|
|
910
|
+
className: "flex-1 border border-gray-200 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
911
|
+
}
|
|
912
|
+
),
|
|
913
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
914
|
+
"button",
|
|
915
|
+
{
|
|
916
|
+
onClick: handleSend,
|
|
917
|
+
disabled: !input.trim(),
|
|
918
|
+
className: "px-4 py-2 text-sm font-medium rounded-lg bg-blue-500 text-white hover:bg-blue-600 disabled:opacity-50 transition-colors",
|
|
919
|
+
children: "Send"
|
|
920
|
+
}
|
|
921
|
+
)
|
|
922
|
+
] }) })
|
|
923
|
+
] });
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
// src/components/overlays/InsightOverlay.tsx
|
|
927
|
+
var import_framer_motion5 = require("framer-motion");
|
|
928
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
929
|
+
var insightStyles = {
|
|
930
|
+
recommendation: { bg: "bg-green-50", border: "border-green-200", icon: "\u2191", iconColor: "text-green-500" },
|
|
931
|
+
comparison: { bg: "bg-blue-50", border: "border-blue-200", icon: "\u2261", iconColor: "text-blue-500" },
|
|
932
|
+
warning: { bg: "bg-yellow-50", border: "border-yellow-200", icon: "\u26A0", iconColor: "text-yellow-500" }
|
|
933
|
+
};
|
|
934
|
+
function InsightOverlay({ data, onDismiss }) {
|
|
935
|
+
const { title, subtitle, insights = [], actions = [], onAction } = data ?? {};
|
|
936
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "bg-white rounded-2xl shadow-2xl p-6 min-w-[320px] max-w-md", children: [
|
|
937
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center justify-between mb-4", children: [
|
|
938
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
939
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h3", { className: "text-lg font-semibold", children: title }),
|
|
940
|
+
subtitle && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-sm text-gray-500", children: subtitle })
|
|
941
|
+
] }),
|
|
942
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { onClick: onDismiss, className: "text-gray-400 hover:text-gray-600 text-sm", children: "Close" })
|
|
943
|
+
] }),
|
|
944
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "space-y-3", children: insights.map((insight, i) => {
|
|
945
|
+
const style = insightStyles[insight.type];
|
|
946
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
947
|
+
import_framer_motion5.motion.div,
|
|
948
|
+
{
|
|
949
|
+
className: `p-3 rounded-lg border ${style.bg} ${style.border}`,
|
|
950
|
+
initial: { opacity: 0, x: -10 },
|
|
951
|
+
animate: { opacity: 1, x: 0 },
|
|
952
|
+
transition: { delay: i * 0.1 },
|
|
953
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-start gap-2", children: [
|
|
954
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: style.iconColor, children: style.icon }),
|
|
955
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex-1", children: [
|
|
956
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-sm", children: insight.text }),
|
|
957
|
+
insight.confidence != null && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("p", { className: "text-xs text-gray-400 mt-1", children: [
|
|
958
|
+
"Confidence: ",
|
|
959
|
+
Math.round(insight.confidence * 100),
|
|
960
|
+
"%"
|
|
961
|
+
] })
|
|
962
|
+
] })
|
|
963
|
+
] })
|
|
964
|
+
},
|
|
965
|
+
i
|
|
966
|
+
);
|
|
967
|
+
}) }),
|
|
968
|
+
actions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "mt-4 pt-3 border-t flex flex-wrap gap-2", children: actions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
969
|
+
"button",
|
|
970
|
+
{
|
|
971
|
+
onClick: () => onAction?.(action),
|
|
972
|
+
className: "text-xs px-3 py-1.5 rounded-full bg-purple-100 text-purple-700 hover:bg-purple-200 transition-colors",
|
|
973
|
+
children: action
|
|
974
|
+
},
|
|
975
|
+
action
|
|
976
|
+
)) })
|
|
977
|
+
] });
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
// src/components/overlays/DetailCardOverlay.tsx
|
|
981
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
982
|
+
function DetailCardOverlay({ data, onDismiss }) {
|
|
983
|
+
const { title, body, image, metadata, actions } = data ?? {};
|
|
984
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "bg-white rounded-2xl shadow-2xl p-6 min-w-[320px] max-w-lg", children: [
|
|
985
|
+
image && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
986
|
+
"img",
|
|
987
|
+
{
|
|
988
|
+
src: image,
|
|
989
|
+
alt: title ?? "Detail",
|
|
990
|
+
className: "w-full h-48 object-cover rounded-xl mb-4"
|
|
991
|
+
}
|
|
992
|
+
),
|
|
993
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h3", { className: "text-lg font-semibold mb-1", children: title }),
|
|
994
|
+
body && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-sm text-gray-600 mb-4 leading-relaxed", children: body }),
|
|
995
|
+
metadata && Object.keys(metadata).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "space-y-1.5 mb-4", children: Object.entries(metadata).map(([key, value]) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center justify-between py-1.5 border-b border-gray-100 last:border-0", children: [
|
|
996
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-xs font-medium text-gray-400 uppercase tracking-wider", children: key }),
|
|
997
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-sm text-gray-700", children: value })
|
|
998
|
+
] }, key)) }),
|
|
999
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex gap-2 justify-end", children: [
|
|
1000
|
+
actions?.map((action, i) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1001
|
+
"button",
|
|
1002
|
+
{
|
|
1003
|
+
onClick: action.onClick,
|
|
1004
|
+
className: "px-4 py-2 text-sm font-medium rounded-lg bg-blue-500 text-white hover:bg-blue-600 transition-colors",
|
|
1005
|
+
children: action.label
|
|
1006
|
+
},
|
|
1007
|
+
i
|
|
1008
|
+
)),
|
|
1009
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1010
|
+
"button",
|
|
1011
|
+
{
|
|
1012
|
+
onClick: onDismiss,
|
|
1013
|
+
className: "px-4 py-2 text-sm font-medium rounded-lg bg-gray-100 text-gray-700 hover:bg-gray-200 transition-colors",
|
|
1014
|
+
children: "Close"
|
|
1015
|
+
}
|
|
1016
|
+
)
|
|
1017
|
+
] })
|
|
1018
|
+
] });
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
// src/components/overlays/ComparisonOverlay.tsx
|
|
1022
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1023
|
+
function ComparisonOverlay({ data, onDismiss }) {
|
|
1024
|
+
const { title, items } = data ?? {};
|
|
1025
|
+
const attributeKeys = items?.length ? [...new Set(items.flatMap((item) => Object.keys(item.attributes)))] : [];
|
|
1026
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "bg-white rounded-2xl shadow-2xl p-6 min-w-[400px] max-w-2xl", children: [
|
|
1027
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h3", { className: "text-lg font-semibold mb-4", children: title }),
|
|
1028
|
+
items && items.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "overflow-x-auto mb-4", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("table", { className: "w-full text-sm", children: [
|
|
1029
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("tr", { className: "border-b border-gray-200", children: [
|
|
1030
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("th", { className: "text-left py-2 pr-4 text-gray-400 font-medium text-xs uppercase tracking-wider", children: "Feature" }),
|
|
1031
|
+
items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("th", { className: "text-center py-2 px-3 font-semibold text-gray-800", children: item.name }, item.name))
|
|
1032
|
+
] }) }),
|
|
1033
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("tbody", { children: attributeKeys.map((key, i) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("tr", { className: i % 2 === 0 ? "bg-gray-50" : "", children: [
|
|
1034
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("td", { className: "py-2 pr-4 text-gray-600 font-medium", children: key }),
|
|
1035
|
+
items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("td", { className: "text-center py-2 px-3 text-gray-700", children: String(item.attributes[key] ?? "\u2014") }, item.name))
|
|
1036
|
+
] }, key)) })
|
|
1037
|
+
] }) }),
|
|
1038
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "flex justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1039
|
+
"button",
|
|
1040
|
+
{
|
|
1041
|
+
onClick: onDismiss,
|
|
1042
|
+
className: "px-4 py-2 text-sm font-medium rounded-lg bg-gray-100 text-gray-700 hover:bg-gray-200 transition-colors",
|
|
1043
|
+
children: "Close"
|
|
1044
|
+
}
|
|
1045
|
+
) })
|
|
1046
|
+
] });
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
// src/components/overlays/CalendarOverlay.tsx
|
|
1050
|
+
var import_react11 = require("react");
|
|
1051
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
1052
|
+
function CalendarOverlay({ data, onDismiss }) {
|
|
1053
|
+
const { title, available_slots, onSelect } = data ?? {};
|
|
1054
|
+
const [selectedDate, setSelectedDate] = (0, import_react11.useState)(null);
|
|
1055
|
+
const [selectedSlot, setSelectedSlot] = (0, import_react11.useState)(null);
|
|
1056
|
+
const groupedSlots = (0, import_react11.useMemo)(() => {
|
|
1057
|
+
if (!available_slots) return /* @__PURE__ */ new Map();
|
|
1058
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1059
|
+
for (const slot of available_slots) {
|
|
1060
|
+
const existing = groups.get(slot.date) ?? [];
|
|
1061
|
+
existing.push(slot);
|
|
1062
|
+
groups.set(slot.date, existing);
|
|
1063
|
+
}
|
|
1064
|
+
return groups;
|
|
1065
|
+
}, [available_slots]);
|
|
1066
|
+
const dates = [...groupedSlots.keys()];
|
|
1067
|
+
const activeDate = selectedDate ?? dates[0] ?? null;
|
|
1068
|
+
const slotsForDate = activeDate ? groupedSlots.get(activeDate) ?? [] : [];
|
|
1069
|
+
const handleConfirm = () => {
|
|
1070
|
+
if (selectedSlot) {
|
|
1071
|
+
onSelect?.(selectedSlot);
|
|
1072
|
+
onDismiss();
|
|
1073
|
+
}
|
|
1074
|
+
};
|
|
1075
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "bg-white rounded-2xl shadow-2xl p-6 min-w-[280px] max-w-sm", children: [
|
|
1076
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h3", { className: "text-lg font-semibold mb-4", children: title }),
|
|
1077
|
+
dates.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
|
|
1078
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex gap-2 overflow-x-auto pb-2 mb-3", children: dates.map((date) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1079
|
+
"button",
|
|
1080
|
+
{
|
|
1081
|
+
onClick: () => {
|
|
1082
|
+
setSelectedDate(date);
|
|
1083
|
+
setSelectedSlot(null);
|
|
1084
|
+
},
|
|
1085
|
+
className: `px-3 py-1.5 text-xs font-medium rounded-full whitespace-nowrap transition-colors ${activeDate === date ? "bg-blue-500 text-white" : "bg-gray-100 text-gray-600 hover:bg-gray-200"}`,
|
|
1086
|
+
children: date
|
|
1087
|
+
},
|
|
1088
|
+
date
|
|
1089
|
+
)) }),
|
|
1090
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex flex-wrap gap-2 mb-4", children: slotsForDate.map((slot, i) => {
|
|
1091
|
+
const isAvailable = slot.available !== false;
|
|
1092
|
+
const isSelected = selectedSlot === slot;
|
|
1093
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1094
|
+
"button",
|
|
1095
|
+
{
|
|
1096
|
+
disabled: !isAvailable,
|
|
1097
|
+
onClick: () => setSelectedSlot(slot),
|
|
1098
|
+
className: `px-3 py-1.5 text-sm rounded-lg transition-colors ${!isAvailable ? "bg-gray-50 text-gray-300 cursor-not-allowed" : isSelected ? "bg-blue-500 text-white ring-2 ring-blue-300" : "bg-gray-100 text-gray-700 hover:bg-gray-200"}`,
|
|
1099
|
+
children: slot.time
|
|
1100
|
+
},
|
|
1101
|
+
i
|
|
1102
|
+
);
|
|
1103
|
+
}) })
|
|
1104
|
+
] }),
|
|
1105
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex gap-2 justify-end", children: [
|
|
1106
|
+
selectedSlot && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1107
|
+
"button",
|
|
1108
|
+
{
|
|
1109
|
+
onClick: handleConfirm,
|
|
1110
|
+
className: "px-4 py-2 text-sm font-medium rounded-lg bg-blue-500 text-white hover:bg-blue-600 transition-colors",
|
|
1111
|
+
children: "Confirm"
|
|
1112
|
+
}
|
|
1113
|
+
),
|
|
1114
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1115
|
+
"button",
|
|
1116
|
+
{
|
|
1117
|
+
onClick: onDismiss,
|
|
1118
|
+
className: "px-4 py-2 text-sm font-medium rounded-lg bg-gray-100 text-gray-700 hover:bg-gray-200 transition-colors",
|
|
1119
|
+
children: "Close"
|
|
1120
|
+
}
|
|
1121
|
+
)
|
|
1122
|
+
] })
|
|
1123
|
+
] });
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
// src/components/overlays/MediaOverlay.tsx
|
|
1127
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
1128
|
+
function MediaOverlay({ data, onDismiss }) {
|
|
1129
|
+
const { title, url, type = "image", alt, autoplay } = data ?? {};
|
|
1130
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "bg-white rounded-2xl shadow-2xl p-6 min-w-[320px] max-w-xl", children: [
|
|
1131
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h3", { className: "text-lg font-semibold mb-4", children: title }),
|
|
1132
|
+
url && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "mb-4 rounded-xl overflow-hidden bg-gray-100", children: [
|
|
1133
|
+
type === "video" && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
1134
|
+
"video",
|
|
1135
|
+
{
|
|
1136
|
+
src: url,
|
|
1137
|
+
controls: true,
|
|
1138
|
+
autoPlay: autoplay,
|
|
1139
|
+
className: "w-full max-h-80 object-contain"
|
|
1140
|
+
}
|
|
1141
|
+
),
|
|
1142
|
+
type === "audio" && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "p-6 flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("audio", { src: url, controls: true, autoPlay: autoplay, className: "w-full" }) }),
|
|
1143
|
+
type === "image" && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
1144
|
+
"img",
|
|
1145
|
+
{
|
|
1146
|
+
src: url,
|
|
1147
|
+
alt: alt ?? title ?? "Media",
|
|
1148
|
+
className: "w-full max-h-80 object-contain"
|
|
1149
|
+
}
|
|
1150
|
+
)
|
|
1151
|
+
] }),
|
|
1152
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "flex justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
1153
|
+
"button",
|
|
1154
|
+
{
|
|
1155
|
+
onClick: onDismiss,
|
|
1156
|
+
className: "px-4 py-2 text-sm font-medium rounded-lg bg-gray-100 text-gray-700 hover:bg-gray-200 transition-colors",
|
|
1157
|
+
children: "Close"
|
|
1158
|
+
}
|
|
1159
|
+
) })
|
|
1160
|
+
] });
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
// src/components/overlays/MapOverlay.tsx
|
|
1164
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
1165
|
+
function MapOverlay({ data, onDismiss }) {
|
|
1166
|
+
const { title, locations } = data ?? {};
|
|
1167
|
+
const getMapsUrl = (loc) => `https://www.google.com/maps/search/?api=1&query=${loc.lat},${loc.lng}`;
|
|
1168
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "bg-white rounded-2xl shadow-2xl p-6 min-w-[280px] max-w-md", children: [
|
|
1169
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("h3", { className: "text-lg font-semibold mb-4", children: title }),
|
|
1170
|
+
locations && locations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "space-y-3 mb-4", children: locations.map((loc, i) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-start gap-3 p-3 rounded-xl bg-gray-50", children: [
|
|
1171
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "w-8 h-8 rounded-full bg-red-100 flex items-center justify-center flex-shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("svg", { className: "w-4 h-4 text-red-500", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { fillRule: "evenodd", d: "M5.05 4.05a7 7 0 119.9 9.9L10 18.9l-4.95-4.95a7 7 0 010-9.9zM10 11a2 2 0 100-4 2 2 0 000 4z", clipRule: "evenodd" }) }) }),
|
|
1172
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex-1 min-w-0", children: [
|
|
1173
|
+
loc.label && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "text-sm font-medium text-gray-800", children: loc.label }),
|
|
1174
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("p", { className: "text-xs text-gray-400", children: [
|
|
1175
|
+
loc.lat.toFixed(4),
|
|
1176
|
+
", ",
|
|
1177
|
+
loc.lng.toFixed(4)
|
|
1178
|
+
] }),
|
|
1179
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1180
|
+
"a",
|
|
1181
|
+
{
|
|
1182
|
+
href: getMapsUrl(loc),
|
|
1183
|
+
target: "_blank",
|
|
1184
|
+
rel: "noopener noreferrer",
|
|
1185
|
+
className: "text-xs text-blue-500 hover:text-blue-600 font-medium",
|
|
1186
|
+
children: "Open in Maps \u2192"
|
|
1187
|
+
}
|
|
1188
|
+
)
|
|
1189
|
+
] })
|
|
1190
|
+
] }, i)) }),
|
|
1191
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "flex justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1192
|
+
"button",
|
|
1193
|
+
{
|
|
1194
|
+
onClick: onDismiss,
|
|
1195
|
+
className: "px-4 py-2 text-sm font-medium rounded-lg bg-gray-100 text-gray-700 hover:bg-gray-200 transition-colors",
|
|
1196
|
+
children: "Close"
|
|
1197
|
+
}
|
|
1198
|
+
) })
|
|
1199
|
+
] });
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
// src/components/overlays/RichTextOverlay.tsx
|
|
1203
|
+
var import_react12 = require("react");
|
|
1204
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
1205
|
+
function parseMarkdown(md) {
|
|
1206
|
+
let html = md.replace(/```(\w*)\n([\s\S]*?)```/g, '<pre class="bg-gray-900 text-gray-100 rounded-lg p-3 text-xs overflow-x-auto my-2"><code>$2</code></pre>').replace(/`([^`]+)`/g, '<code class="bg-gray-100 text-gray-800 px-1 py-0.5 rounded text-xs">$1</code>').replace(/^### (.+)$/gm, '<h4 class="text-base font-semibold mt-3 mb-1">$1</h4>').replace(/^## (.+)$/gm, '<h3 class="text-lg font-semibold mt-4 mb-1">$1</h3>').replace(/^# (.+)$/gm, '<h2 class="text-xl font-bold mt-4 mb-2">$1</h2>').replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>").replace(/\*(.+?)\*/g, "<em>$1</em>").replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" target="_blank" rel="noopener noreferrer" class="text-blue-500 hover:text-blue-600 underline">$1</a>').replace(/^- (.+)$/gm, '<li class="ml-4 list-disc text-sm">$1</li>').replace(/^(?!<[hlupao])(.*\S.*)$/gm, '<p class="text-sm text-gray-600 my-1">$1</p>');
|
|
1207
|
+
return html;
|
|
1208
|
+
}
|
|
1209
|
+
function RichTextOverlay({ data, onDismiss }) {
|
|
1210
|
+
const { title, content } = data ?? {};
|
|
1211
|
+
const html = (0, import_react12.useMemo)(() => content ? parseMarkdown(content) : "", [content]);
|
|
1212
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "bg-white rounded-2xl shadow-2xl p-6 min-w-[320px] max-w-lg", children: [
|
|
1213
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h3", { className: "text-lg font-semibold mb-4", children: title }),
|
|
1214
|
+
html && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
1215
|
+
"div",
|
|
1216
|
+
{
|
|
1217
|
+
className: "max-h-96 overflow-y-auto mb-4",
|
|
1218
|
+
dangerouslySetInnerHTML: { __html: html }
|
|
1219
|
+
}
|
|
1220
|
+
),
|
|
1221
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "flex justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
1222
|
+
"button",
|
|
1223
|
+
{
|
|
1224
|
+
onClick: onDismiss,
|
|
1225
|
+
className: "px-4 py-2 text-sm font-medium rounded-lg bg-gray-100 text-gray-700 hover:bg-gray-200 transition-colors",
|
|
1226
|
+
children: "Close"
|
|
1227
|
+
}
|
|
1228
|
+
) })
|
|
1229
|
+
] });
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
// src/components/overlays/ChartOverlay.tsx
|
|
1233
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
1234
|
+
var DEFAULT_COLORS = ["#3b82f6", "#8b5cf6", "#ec4899", "#f59e0b", "#10b981", "#06b6d4", "#ef4444", "#84cc16"];
|
|
1235
|
+
function BarChart({ series }) {
|
|
1236
|
+
const max = Math.max(...series.map((s) => s.value), 1);
|
|
1237
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "space-y-2", children: series.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-3", children: [
|
|
1238
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-xs text-gray-500 w-20 truncate text-right", children: item.label }),
|
|
1239
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "flex-1 h-6 bg-gray-100 rounded-full overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1240
|
+
"div",
|
|
1241
|
+
{
|
|
1242
|
+
className: "h-full rounded-full transition-all duration-500",
|
|
1243
|
+
style: {
|
|
1244
|
+
width: `${item.value / max * 100}%`,
|
|
1245
|
+
backgroundColor: item.color ?? DEFAULT_COLORS[i % DEFAULT_COLORS.length]
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
) }),
|
|
1249
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-xs font-medium text-gray-700 w-12", children: item.value })
|
|
1250
|
+
] }, i)) });
|
|
1251
|
+
}
|
|
1252
|
+
function PieChart({ series }) {
|
|
1253
|
+
const total = series.reduce((sum, s) => sum + s.value, 0) || 1;
|
|
1254
|
+
const radius = 60;
|
|
1255
|
+
const circumference = 2 * Math.PI * radius;
|
|
1256
|
+
let offset = 0;
|
|
1257
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-6", children: [
|
|
1258
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { width: "160", height: "160", viewBox: "0 0 160 160", className: "flex-shrink-0", children: series.map((item, i) => {
|
|
1259
|
+
const dash = item.value / total * circumference;
|
|
1260
|
+
const currentOffset = offset;
|
|
1261
|
+
offset += dash;
|
|
1262
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1263
|
+
"circle",
|
|
1264
|
+
{
|
|
1265
|
+
cx: "80",
|
|
1266
|
+
cy: "80",
|
|
1267
|
+
r: radius,
|
|
1268
|
+
fill: "none",
|
|
1269
|
+
stroke: item.color ?? DEFAULT_COLORS[i % DEFAULT_COLORS.length],
|
|
1270
|
+
strokeWidth: "24",
|
|
1271
|
+
strokeDasharray: `${dash} ${circumference - dash}`,
|
|
1272
|
+
strokeDashoffset: -currentOffset,
|
|
1273
|
+
transform: "rotate(-90 80 80)"
|
|
1274
|
+
},
|
|
1275
|
+
i
|
|
1276
|
+
);
|
|
1277
|
+
}) }),
|
|
1278
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "space-y-1.5", children: series.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
1279
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1280
|
+
"div",
|
|
1281
|
+
{
|
|
1282
|
+
className: "w-3 h-3 rounded-sm flex-shrink-0",
|
|
1283
|
+
style: { backgroundColor: item.color ?? DEFAULT_COLORS[i % DEFAULT_COLORS.length] }
|
|
1284
|
+
}
|
|
1285
|
+
),
|
|
1286
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-xs text-gray-600", children: item.label }),
|
|
1287
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "text-xs font-medium text-gray-800", children: [
|
|
1288
|
+
Math.round(item.value / total * 100),
|
|
1289
|
+
"%"
|
|
1290
|
+
] })
|
|
1291
|
+
] }, i)) })
|
|
1292
|
+
] });
|
|
1293
|
+
}
|
|
1294
|
+
function LineChart({ series }) {
|
|
1295
|
+
const max = Math.max(...series.map((s) => s.value), 1);
|
|
1296
|
+
const width = 300;
|
|
1297
|
+
const height = 120;
|
|
1298
|
+
const padding = 8;
|
|
1299
|
+
const points = series.map((item, i) => ({
|
|
1300
|
+
x: padding + i / Math.max(series.length - 1, 1) * (width - padding * 2),
|
|
1301
|
+
y: height - padding - item.value / max * (height - padding * 2)
|
|
1302
|
+
}));
|
|
1303
|
+
const pathD = points.map((p, i) => `${i === 0 ? "M" : "L"} ${p.x} ${p.y}`).join(" ");
|
|
1304
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
|
|
1305
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("svg", { width, height, viewBox: `0 0 ${width} ${height}`, className: "w-full", children: [
|
|
1306
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("path", { d: pathD, fill: "none", stroke: "#3b82f6", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
|
|
1307
|
+
points.map((p, i) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("circle", { cx: p.x, cy: p.y, r: "3", fill: "#3b82f6" }, i))
|
|
1308
|
+
] }),
|
|
1309
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "flex justify-between mt-1", children: series.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-[10px] text-gray-400", children: item.label }, i)) })
|
|
1310
|
+
] });
|
|
1311
|
+
}
|
|
1312
|
+
function ChartOverlay({ data, onDismiss }) {
|
|
1313
|
+
const { title, type = "bar", series } = data ?? {};
|
|
1314
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "bg-white rounded-2xl shadow-2xl p-6 min-w-[280px] max-w-md", children: [
|
|
1315
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h3", { className: "text-lg font-semibold mb-4", children: title }),
|
|
1316
|
+
series && series.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "mb-4", children: [
|
|
1317
|
+
type === "bar" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(BarChart, { series }),
|
|
1318
|
+
type === "pie" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PieChart, { series }),
|
|
1319
|
+
type === "line" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(LineChart, { series })
|
|
1320
|
+
] }),
|
|
1321
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "flex justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1322
|
+
"button",
|
|
1323
|
+
{
|
|
1324
|
+
onClick: onDismiss,
|
|
1325
|
+
className: "px-4 py-2 text-sm font-medium rounded-lg bg-gray-100 text-gray-700 hover:bg-gray-200 transition-colors",
|
|
1326
|
+
children: "Close"
|
|
1327
|
+
}
|
|
1328
|
+
) })
|
|
1329
|
+
] });
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
// src/components/overlays/FileUploadOverlay.tsx
|
|
1333
|
+
var import_react13 = require("react");
|
|
1334
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
1335
|
+
var MIME_MAP = {
|
|
1336
|
+
pdf: "application/pdf",
|
|
1337
|
+
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
1338
|
+
doc: "application/msword",
|
|
1339
|
+
txt: "text/plain",
|
|
1340
|
+
csv: "text/csv",
|
|
1341
|
+
png: "image/png",
|
|
1342
|
+
jpg: "image/jpeg",
|
|
1343
|
+
jpeg: "image/jpeg",
|
|
1344
|
+
gif: "image/gif",
|
|
1345
|
+
svg: "image/svg+xml"
|
|
1346
|
+
};
|
|
1347
|
+
function formatSize(bytes) {
|
|
1348
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
1349
|
+
if (bytes < 1048576) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
1350
|
+
return `${(bytes / 1048576).toFixed(1)} MB`;
|
|
1351
|
+
}
|
|
1352
|
+
function FileUploadOverlay({ data, onDismiss }) {
|
|
1353
|
+
const { title, accept, max_size, multiple, onUpload } = data ?? {};
|
|
1354
|
+
const inputRef = (0, import_react13.useRef)(null);
|
|
1355
|
+
const [files, setFiles] = (0, import_react13.useState)([]);
|
|
1356
|
+
const [dragging, setDragging] = (0, import_react13.useState)(false);
|
|
1357
|
+
const acceptMime = accept?.map((ext) => MIME_MAP[ext.toLowerCase()] ?? `.${ext}`).join(",");
|
|
1358
|
+
const addFiles = (0, import_react13.useCallback)((newFiles) => {
|
|
1359
|
+
if (!newFiles) return;
|
|
1360
|
+
const arr = Array.from(newFiles).filter((f) => {
|
|
1361
|
+
if (max_size && f.size > max_size) return false;
|
|
1362
|
+
return true;
|
|
1363
|
+
});
|
|
1364
|
+
setFiles((prev) => multiple ? [...prev, ...arr] : arr.slice(0, 1));
|
|
1365
|
+
}, [max_size, multiple]);
|
|
1366
|
+
const removeFile = (index) => {
|
|
1367
|
+
setFiles((prev) => prev.filter((_, i) => i !== index));
|
|
1368
|
+
};
|
|
1369
|
+
const handleSubmit = () => {
|
|
1370
|
+
if (files.length > 0) {
|
|
1371
|
+
onUpload?.(files);
|
|
1372
|
+
onDismiss();
|
|
1373
|
+
}
|
|
1374
|
+
};
|
|
1375
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "bg-white rounded-2xl shadow-2xl p-6 min-w-[280px] max-w-sm", children: [
|
|
1376
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h3", { className: "text-lg font-semibold mb-4", children: title }),
|
|
1377
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
1378
|
+
"div",
|
|
1379
|
+
{
|
|
1380
|
+
className: `border-2 border-dashed rounded-xl p-6 text-center cursor-pointer transition-colors mb-3 ${dragging ? "border-blue-400 bg-blue-50" : "border-gray-200 hover:border-gray-300"}`,
|
|
1381
|
+
onClick: () => inputRef.current?.click(),
|
|
1382
|
+
onDragOver: (e) => {
|
|
1383
|
+
e.preventDefault();
|
|
1384
|
+
setDragging(true);
|
|
1385
|
+
},
|
|
1386
|
+
onDragLeave: () => setDragging(false),
|
|
1387
|
+
onDrop: (e) => {
|
|
1388
|
+
e.preventDefault();
|
|
1389
|
+
setDragging(false);
|
|
1390
|
+
addFiles(e.dataTransfer.files);
|
|
1391
|
+
},
|
|
1392
|
+
children: [
|
|
1393
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("svg", { className: "w-8 h-8 text-gray-300 mx-auto mb-2", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" }) }),
|
|
1394
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "text-sm text-gray-500", children: "Drop files here or click to browse" }),
|
|
1395
|
+
accept && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "text-xs text-gray-400 mt-1", children: accept.map((e) => `.${e}`).join(", ") }),
|
|
1396
|
+
max_size && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("p", { className: "text-xs text-gray-400", children: [
|
|
1397
|
+
"Max ",
|
|
1398
|
+
formatSize(max_size)
|
|
1399
|
+
] }),
|
|
1400
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1401
|
+
"input",
|
|
1402
|
+
{
|
|
1403
|
+
ref: inputRef,
|
|
1404
|
+
type: "file",
|
|
1405
|
+
className: "hidden",
|
|
1406
|
+
accept: acceptMime,
|
|
1407
|
+
multiple,
|
|
1408
|
+
onChange: (e) => addFiles(e.target.files)
|
|
1409
|
+
}
|
|
1410
|
+
)
|
|
1411
|
+
]
|
|
1412
|
+
}
|
|
1413
|
+
),
|
|
1414
|
+
files.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "space-y-2 mb-4", children: files.map((file, i) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center justify-between py-1.5 px-3 bg-gray-50 rounded-lg", children: [
|
|
1415
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "min-w-0", children: [
|
|
1416
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "text-sm text-gray-700 truncate", children: file.name }),
|
|
1417
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "text-xs text-gray-400", children: formatSize(file.size) })
|
|
1418
|
+
] }),
|
|
1419
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: () => removeFile(i), className: "text-gray-400 hover:text-red-500 text-sm ml-2", children: "\xD7" })
|
|
1420
|
+
] }, i)) }),
|
|
1421
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex gap-2 justify-end", children: [
|
|
1422
|
+
files.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1423
|
+
"button",
|
|
1424
|
+
{
|
|
1425
|
+
onClick: handleSubmit,
|
|
1426
|
+
className: "px-4 py-2 text-sm font-medium rounded-lg bg-blue-500 text-white hover:bg-blue-600 transition-colors",
|
|
1427
|
+
children: "Upload"
|
|
1428
|
+
}
|
|
1429
|
+
),
|
|
1430
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1431
|
+
"button",
|
|
1432
|
+
{
|
|
1433
|
+
onClick: onDismiss,
|
|
1434
|
+
className: "px-4 py-2 text-sm font-medium rounded-lg bg-gray-100 text-gray-700 hover:bg-gray-200 transition-colors",
|
|
1435
|
+
children: "Close"
|
|
1436
|
+
}
|
|
1437
|
+
)
|
|
1438
|
+
] })
|
|
1439
|
+
] });
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
// src/components/AvatarFirst.tsx
|
|
1443
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
1444
|
+
var defaultOverlays = {
|
|
1445
|
+
card: CardOverlay,
|
|
1446
|
+
form: FormOverlay,
|
|
1447
|
+
table: TableOverlay,
|
|
1448
|
+
progress: ProgressOverlay,
|
|
1449
|
+
confirm: ConfirmOverlay,
|
|
1450
|
+
chat: ChatOverlay,
|
|
1451
|
+
insight: InsightOverlay
|
|
1452
|
+
};
|
|
1453
|
+
function AvatarFirstInner({
|
|
1454
|
+
client,
|
|
1455
|
+
onOverlay,
|
|
1456
|
+
onAction
|
|
1457
|
+
}) {
|
|
1458
|
+
const { state: avatarState, speak } = useAvatar();
|
|
1459
|
+
const { show } = useOverlay();
|
|
1460
|
+
const [sessionId, setSessionId] = (0, import_react14.useState)(null);
|
|
1461
|
+
const [greeting, setGreeting] = (0, import_react14.useState)(null);
|
|
1462
|
+
const [hasGreeted, setHasGreeted] = (0, import_react14.useState)(false);
|
|
1463
|
+
const [isProcessing, setIsProcessing] = (0, import_react14.useState)(false);
|
|
1464
|
+
(0, import_react14.useEffect)(() => {
|
|
1465
|
+
if (avatarState === "connected" && !sessionId) {
|
|
1466
|
+
client.createSession().then((session) => {
|
|
1467
|
+
setSessionId(session.sessionId);
|
|
1468
|
+
setGreeting(session.greeting);
|
|
1469
|
+
}).catch((err) => {
|
|
1470
|
+
console.error("[AvatarFirst] Session init failed:", err);
|
|
1471
|
+
});
|
|
1472
|
+
}
|
|
1473
|
+
}, [avatarState, sessionId, client]);
|
|
1474
|
+
(0, import_react14.useEffect)(() => {
|
|
1475
|
+
if (sessionId && avatarState === "connected" && greeting && !hasGreeted) {
|
|
1476
|
+
setHasGreeted(true);
|
|
1477
|
+
speak(greeting);
|
|
1478
|
+
}
|
|
1479
|
+
}, [sessionId, avatarState, greeting, hasGreeted, speak]);
|
|
1480
|
+
const handleResponse = (0, import_react14.useCallback)((data) => {
|
|
1481
|
+
if (data.speech) {
|
|
1482
|
+
speak(data.speech);
|
|
1483
|
+
}
|
|
1484
|
+
if (data.overlay) {
|
|
1485
|
+
const overlayId = `overlay-${Date.now()}`;
|
|
1486
|
+
show({
|
|
1487
|
+
id: overlayId,
|
|
1488
|
+
component: data.overlay.type,
|
|
1489
|
+
data: data.overlay.data,
|
|
1490
|
+
position: "right-center",
|
|
1491
|
+
animation: "slide-left",
|
|
1492
|
+
dismissOnClickOutside: true
|
|
1493
|
+
});
|
|
1494
|
+
onOverlay?.(data.overlay);
|
|
1495
|
+
}
|
|
1496
|
+
if (data.actions) {
|
|
1497
|
+
for (const action of data.actions) {
|
|
1498
|
+
onAction?.(action);
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
}, [speak, show, onOverlay, onAction]);
|
|
1502
|
+
const handleSend = (0, import_react14.useCallback)(async (text) => {
|
|
1503
|
+
if (!sessionId || isProcessing) return;
|
|
1504
|
+
setIsProcessing(true);
|
|
1505
|
+
try {
|
|
1506
|
+
const response = await client.sendMessage(sessionId, text);
|
|
1507
|
+
handleResponse(response);
|
|
1508
|
+
} catch (err) {
|
|
1509
|
+
console.error("[AvatarFirst] Message failed:", err);
|
|
1510
|
+
} finally {
|
|
1511
|
+
setIsProcessing(false);
|
|
1512
|
+
}
|
|
1513
|
+
}, [client, sessionId, isProcessing, handleResponse]);
|
|
1514
|
+
const isConnected = avatarState === "connected" || avatarState === "speaking" || avatarState === "listening" || avatarState === "thinking";
|
|
1515
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "relative w-full h-full", children: [
|
|
1516
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(AvatarView, { size: "fullscreen", showStatus: false, className: "w-full h-full" }),
|
|
1517
|
+
isConnected && sessionId && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "absolute bottom-4 left-1/2 -translate-x-1/2 z-20 w-full max-w-md px-4", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
1518
|
+
"form",
|
|
1519
|
+
{
|
|
1520
|
+
onSubmit: (e) => {
|
|
1521
|
+
e.preventDefault();
|
|
1522
|
+
const input = e.currentTarget.elements.namedItem("message");
|
|
1523
|
+
if (input.value.trim()) {
|
|
1524
|
+
handleSend(input.value.trim());
|
|
1525
|
+
input.value = "";
|
|
1526
|
+
}
|
|
1527
|
+
},
|
|
1528
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
1529
|
+
"input",
|
|
1530
|
+
{
|
|
1531
|
+
name: "message",
|
|
1532
|
+
type: "text",
|
|
1533
|
+
placeholder: "Type a message...",
|
|
1534
|
+
disabled: isProcessing,
|
|
1535
|
+
className: "w-full px-4 py-3 bg-white/10 backdrop-blur-md border border-white/20 rounded-full text-white placeholder-white/50 outline-none focus:border-white/40"
|
|
1536
|
+
}
|
|
1537
|
+
)
|
|
1538
|
+
}
|
|
1539
|
+
) }),
|
|
1540
|
+
!isConnected && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "absolute inset-0 flex items-center justify-center bg-slate-950/80 z-30", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "text-center", children: [
|
|
1541
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "w-12 h-12 border-2 border-purple-500 border-t-transparent rounded-full animate-spin mx-auto mb-4" }),
|
|
1542
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "text-white/60 text-sm", children: "Connecting..." })
|
|
1543
|
+
] }) })
|
|
1544
|
+
] });
|
|
1545
|
+
}
|
|
1546
|
+
function AvatarFirst({
|
|
1547
|
+
apiKey,
|
|
1548
|
+
baseUrl,
|
|
1549
|
+
onOverlay,
|
|
1550
|
+
onAction,
|
|
1551
|
+
onStateChange,
|
|
1552
|
+
className,
|
|
1553
|
+
overlayComponents
|
|
1554
|
+
}) {
|
|
1555
|
+
const [agent, setAgent] = (0, import_react14.useState)(null);
|
|
1556
|
+
const [error, setError] = (0, import_react14.useState)(false);
|
|
1557
|
+
const client = (0, import_react14.useMemo)(
|
|
1558
|
+
() => new import_core2.AvatarFirstClient({ apiKey, baseUrl }),
|
|
1559
|
+
[apiKey, baseUrl]
|
|
1560
|
+
);
|
|
1561
|
+
const mergedOverlays = (0, import_react14.useMemo)(
|
|
1562
|
+
() => ({ ...defaultOverlays, ...overlayComponents }),
|
|
1563
|
+
[overlayComponents]
|
|
1564
|
+
);
|
|
1565
|
+
const onStateChangeRef = (0, import_react14.useRef)(onStateChange);
|
|
1566
|
+
onStateChangeRef.current = onStateChange;
|
|
1567
|
+
(0, import_react14.useEffect)(() => {
|
|
1568
|
+
let cancelled = false;
|
|
1569
|
+
async function init() {
|
|
1570
|
+
try {
|
|
1571
|
+
onStateChangeRef.current?.("connecting");
|
|
1572
|
+
const session = await client.createSession();
|
|
1573
|
+
if (cancelled) return;
|
|
1574
|
+
const engine = new import_core2.HeyGenAdapter();
|
|
1575
|
+
const avatarAgent = (0, import_core2.createAvatarAgent)({
|
|
1576
|
+
engine,
|
|
1577
|
+
engineConfig: {
|
|
1578
|
+
serverUrl: baseUrl || "https://avatarfirst.dev",
|
|
1579
|
+
sessionToken: session.avatar?.token,
|
|
1580
|
+
language: "en",
|
|
1581
|
+
voiceChat: false
|
|
1582
|
+
},
|
|
1583
|
+
actions: []
|
|
1584
|
+
});
|
|
1585
|
+
setAgent(avatarAgent);
|
|
1586
|
+
onStateChangeRef.current?.("connected");
|
|
1587
|
+
} catch (err) {
|
|
1588
|
+
if (!cancelled) {
|
|
1589
|
+
console.error("[AvatarFirst] Init failed:", err);
|
|
1590
|
+
setError(true);
|
|
1591
|
+
onStateChangeRef.current?.("error");
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
init();
|
|
1596
|
+
return () => {
|
|
1597
|
+
cancelled = true;
|
|
1598
|
+
};
|
|
1599
|
+
}, [client, baseUrl]);
|
|
1600
|
+
(0, import_react14.useEffect)(() => {
|
|
1601
|
+
return () => {
|
|
1602
|
+
agent?.destroy();
|
|
1603
|
+
};
|
|
1604
|
+
}, [agent]);
|
|
1605
|
+
if (error || !agent) {
|
|
1606
|
+
if (error) {
|
|
1607
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: `flex items-center justify-center bg-slate-950 ${className || ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "text-center", children: [
|
|
1608
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "text-red-400 mb-2 text-sm", children: "Failed to connect" }),
|
|
1609
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
1610
|
+
"button",
|
|
1611
|
+
{
|
|
1612
|
+
onClick: () => window.location.reload(),
|
|
1613
|
+
className: "text-white/60 text-xs underline hover:text-white/80",
|
|
1614
|
+
children: "Retry"
|
|
1615
|
+
}
|
|
1616
|
+
)
|
|
1617
|
+
] }) });
|
|
1618
|
+
}
|
|
1619
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: `flex items-center justify-center bg-slate-950 ${className || ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "w-12 h-12 border-2 border-purple-500 border-t-transparent rounded-full animate-spin" }) });
|
|
1620
|
+
}
|
|
1621
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(AvatarProvider, { agent, autoStart: true, children: [
|
|
1622
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(OverlayContainer, { components: mergedOverlays }),
|
|
1623
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(AvatarFirstInner, { client, onOverlay, onAction })
|
|
1624
|
+
] }) });
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1627
|
+
// src/animations/variants.ts
|
|
1628
|
+
var pageTransition = {
|
|
1629
|
+
initial: { opacity: 0, x: -20 },
|
|
1630
|
+
animate: { opacity: 1, x: 0, transition: { duration: 0.3 } },
|
|
1631
|
+
exit: { opacity: 0, x: 20, transition: { duration: 0.2 } }
|
|
1632
|
+
};
|
|
1633
|
+
var fadeIn = {
|
|
1634
|
+
initial: { opacity: 0 },
|
|
1635
|
+
animate: { opacity: 1, transition: { duration: 0.5 } },
|
|
1636
|
+
exit: { opacity: 0 }
|
|
1637
|
+
};
|
|
1638
|
+
var fadeInUp = {
|
|
1639
|
+
initial: { opacity: 0, y: 20 },
|
|
1640
|
+
animate: { opacity: 1, y: 0, transition: { duration: 0.4 } }
|
|
1641
|
+
};
|
|
1642
|
+
var cardHover = {
|
|
1643
|
+
initial: { scale: 1, y: 0 },
|
|
1644
|
+
hover: {
|
|
1645
|
+
scale: 1.03,
|
|
1646
|
+
y: -8,
|
|
1647
|
+
transition: { type: "spring", stiffness: 300, damping: 20 }
|
|
1648
|
+
},
|
|
1649
|
+
tap: { scale: 0.98 }
|
|
1650
|
+
};
|
|
1651
|
+
var avatarPulse = {
|
|
1652
|
+
idle: {
|
|
1653
|
+
scale: [1, 1.02, 1],
|
|
1654
|
+
transition: { repeat: Infinity, duration: 3, ease: "easeInOut" }
|
|
1655
|
+
},
|
|
1656
|
+
speaking: {
|
|
1657
|
+
scale: [1, 1.03, 1],
|
|
1658
|
+
transition: { repeat: Infinity, duration: 0.5, ease: "easeInOut" }
|
|
1659
|
+
},
|
|
1660
|
+
listening: {
|
|
1661
|
+
scale: 1,
|
|
1662
|
+
transition: { duration: 0.2 }
|
|
1663
|
+
},
|
|
1664
|
+
thinking: {
|
|
1665
|
+
scale: [1, 1.01, 1],
|
|
1666
|
+
transition: { repeat: Infinity, duration: 1, ease: "easeInOut" }
|
|
1667
|
+
}
|
|
1668
|
+
};
|
|
1669
|
+
var staggerContainer = {
|
|
1670
|
+
initial: {},
|
|
1671
|
+
animate: {
|
|
1672
|
+
transition: { staggerChildren: 0.1 }
|
|
1673
|
+
}
|
|
1674
|
+
};
|
|
1675
|
+
var slideIn = {
|
|
1676
|
+
initial: { x: "100%", opacity: 0 },
|
|
1677
|
+
animate: { x: 0, opacity: 1, transition: { type: "spring", stiffness: 300, damping: 30 } },
|
|
1678
|
+
exit: { x: "100%", opacity: 0 }
|
|
1679
|
+
};
|
|
1680
|
+
var scaleIn = {
|
|
1681
|
+
initial: { scale: 0.8, opacity: 0 },
|
|
1682
|
+
animate: { scale: 1, opacity: 1, transition: { type: "spring", stiffness: 300, damping: 25 } },
|
|
1683
|
+
exit: { scale: 0.8, opacity: 0 }
|
|
1684
|
+
};
|
|
1685
|
+
|
|
1686
|
+
// src/utils/cn.ts
|
|
1687
|
+
var import_clsx = require("clsx");
|
|
1688
|
+
var import_tailwind_merge = require("tailwind-merge");
|
|
1689
|
+
function cn(...inputs) {
|
|
1690
|
+
return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
|
|
1691
|
+
}
|
|
1692
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1693
|
+
0 && (module.exports = {
|
|
1694
|
+
AvatarAgent,
|
|
1695
|
+
AvatarContext,
|
|
1696
|
+
AvatarFallback,
|
|
1697
|
+
AvatarFirst,
|
|
1698
|
+
AvatarProvider,
|
|
1699
|
+
AvatarView,
|
|
1700
|
+
CalendarOverlay,
|
|
1701
|
+
CardOverlay,
|
|
1702
|
+
ChartOverlay,
|
|
1703
|
+
ChatOverlay,
|
|
1704
|
+
ComparisonOverlay,
|
|
1705
|
+
ConfirmOverlay,
|
|
1706
|
+
DetailCardOverlay,
|
|
1707
|
+
FileUploadOverlay,
|
|
1708
|
+
FormOverlay,
|
|
1709
|
+
InsightOverlay,
|
|
1710
|
+
MapOverlay,
|
|
1711
|
+
MediaOverlay,
|
|
1712
|
+
OverlayContainer,
|
|
1713
|
+
ProgressOverlay,
|
|
1714
|
+
RichTextOverlay,
|
|
1715
|
+
TableOverlay,
|
|
1716
|
+
avatarPulse,
|
|
1717
|
+
cardHover,
|
|
1718
|
+
cn,
|
|
1719
|
+
fadeIn,
|
|
1720
|
+
fadeInUp,
|
|
1721
|
+
getOverlayVariants,
|
|
1722
|
+
pageTransition,
|
|
1723
|
+
scaleIn,
|
|
1724
|
+
slideIn,
|
|
1725
|
+
staggerContainer,
|
|
1726
|
+
useAction,
|
|
1727
|
+
useAvatar,
|
|
1728
|
+
useAvatarEvent,
|
|
1729
|
+
useAvatarFirst,
|
|
1730
|
+
useOverlay
|
|
1731
|
+
});
|