@cuekit-ai/react 1.5.0 → 1.6.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/dist/index.mjs CHANGED
@@ -37,7 +37,7 @@ import {
37
37
  setWebRTCCallbacks,
38
38
  setWebRTCConfig,
39
39
  validateDynamicElements
40
- } from "./chunk-MHLYAXXW.mjs";
40
+ } from "./chunk-24V3WQXJ.mjs";
41
41
 
42
42
  // node_modules/inline-style-parser/index.js
43
43
  var require_inline_style_parser = __commonJS({
@@ -74,17 +74,17 @@ var require_inline_style_parser = __commonJS({
74
74
  function position3() {
75
75
  var start2 = { line: lineno, column };
76
76
  return function(node2) {
77
- node2.position = new Position(start2);
77
+ node2.position = new Position2(start2);
78
78
  whitespace2();
79
79
  return node2;
80
80
  };
81
81
  }
82
- function Position(start2) {
82
+ function Position2(start2) {
83
83
  this.start = start2;
84
84
  this.end = { line: lineno, column };
85
85
  this.source = options.source;
86
86
  }
87
- Position.prototype.content = style;
87
+ Position2.prototype.content = style;
88
88
  var errorsList = [];
89
89
  function error(msg) {
90
90
  var err = new Error(
@@ -1165,7 +1165,7 @@ var require_md5 = __commonJS({
1165
1165
  }
1166
1166
  });
1167
1167
 
1168
- // src/providers/cuekit-provider.tsx
1168
+ // src/providers/ansyr-provider.tsx
1169
1169
  import React, { createContext, useContext, useEffect, useState } from "react";
1170
1170
 
1171
1171
  // src/core/init.ts
@@ -1222,9 +1222,9 @@ var initWebRTC = (apiKey) => {
1222
1222
  return initWebRTCWithDeployedBackend(apiKey);
1223
1223
  };
1224
1224
 
1225
- // src/providers/cuekit-provider.tsx
1226
- if (typeof window !== "undefined" && !globalThis.CuekitStore) {
1227
- globalThis.CuekitStore = {
1225
+ // src/providers/ansyr-provider.tsx
1226
+ if (typeof window !== "undefined" && !globalThis.AnsyrStore) {
1227
+ globalThis.AnsyrStore = {
1228
1228
  intent: null,
1229
1229
  lastText: "",
1230
1230
  lastClickedLabel: "",
@@ -1232,38 +1232,46 @@ if (typeof window !== "undefined" && !globalThis.CuekitStore) {
1232
1232
  appId: void 0,
1233
1233
  deviceId: void 0,
1234
1234
  update(data) {
1235
- Object.assign(globalThis.CuekitStore, data);
1235
+ Object.assign(globalThis.AnsyrStore, data);
1236
1236
  }
1237
1237
  };
1238
1238
  }
1239
- var QubeContext = createContext({
1239
+ var AnsyrContext = createContext({
1240
1240
  apiKey: "",
1241
- appId: ""
1241
+ appId: "",
1242
+ title: "ansyr.ai",
1243
+ showLogo: true,
1244
+ showAIIcon: true,
1245
+ showUserIcon: true
1242
1246
  });
1243
- var useQubeContext = () => useContext(QubeContext);
1247
+ var useAnsyrContext = () => useContext(AnsyrContext);
1244
1248
  var getUniqueId = () => {
1245
1249
  if (typeof window === "undefined") {
1246
1250
  return "server-" + Date.now().toString(36);
1247
1251
  }
1248
1252
  try {
1249
- let id = localStorage.getItem("cuekit_device_id");
1253
+ let id = localStorage.getItem("ansyr_device_id");
1250
1254
  if (!id) {
1251
1255
  id = Date.now().toString(36) + Math.random().toString(36).substring(2);
1252
- localStorage.setItem("cuekit_device_id", id);
1256
+ localStorage.setItem("ansyr_device_id", id);
1253
1257
  }
1254
1258
  return id;
1255
1259
  } catch {
1256
1260
  return "anon-" + Date.now().toString(36);
1257
1261
  }
1258
1262
  };
1259
- var CuekitProvider = ({
1263
+ var AnsyrProvider = ({
1260
1264
  apiKey,
1261
1265
  deviceId = "",
1262
1266
  appId,
1263
1267
  children,
1264
1268
  navigationHandler,
1265
1269
  onConnectionStateChange,
1266
- onParticipantUpdate
1270
+ onParticipantUpdate,
1271
+ title = "ansyr.ai",
1272
+ showLogo = true,
1273
+ showAIIcon = true,
1274
+ showUserIcon = true
1267
1275
  }) => {
1268
1276
  const [internalDeviceId, setInternalDeviceId] = useState(deviceId);
1269
1277
  useEffect(() => {
@@ -1285,7 +1293,7 @@ var CuekitProvider = ({
1285
1293
  };
1286
1294
  }, [navigationHandler]);
1287
1295
  useEffect(() => {
1288
- import("./webrtc-service-AUWJ6AHB.mjs").then(({ setWebRTCCallbacks: setWebRTCCallbacks2 }) => {
1296
+ import("./webrtc-service-N76TYFI4.mjs").then(({ setWebRTCCallbacks: setWebRTCCallbacks2 }) => {
1289
1297
  setWebRTCCallbacks2({
1290
1298
  onNavigationCommand: (command) => {
1291
1299
  if (command.data.actionType === "navigate" && command.data.routeName) {
@@ -1311,8 +1319,8 @@ var CuekitProvider = ({
1311
1319
  }, [onConnectionStateChange, onParticipantUpdate, navigationHandler]);
1312
1320
  useEffect(() => {
1313
1321
  const updateGlobalStore = (id) => {
1314
- if (typeof window !== "undefined" && globalThis.CuekitStore) {
1315
- globalThis.CuekitStore.update({
1322
+ if (typeof window !== "undefined" && globalThis.AnsyrStore) {
1323
+ globalThis.AnsyrStore.update({
1316
1324
  apiKey,
1317
1325
  appId,
1318
1326
  deviceId: id
@@ -1362,11 +1370,15 @@ var CuekitProvider = ({
1362
1370
  };
1363
1371
  }, [apiKey, appId, internalDeviceId]);
1364
1372
  return /* @__PURE__ */ React.createElement(
1365
- QubeContext.Provider,
1373
+ AnsyrContext.Provider,
1366
1374
  {
1367
1375
  value: {
1368
1376
  apiKey,
1369
- appId
1377
+ appId,
1378
+ title,
1379
+ showLogo,
1380
+ showAIIcon,
1381
+ showUserIcon
1370
1382
  }
1371
1383
  },
1372
1384
  children
@@ -1374,7 +1386,7 @@ var CuekitProvider = ({
1374
1386
  };
1375
1387
 
1376
1388
  // src/components/mic-button.tsx
1377
- import React11, { useState as useState10, useEffect as useEffect9, useCallback as useCallback5, useRef as useRef7 } from "react";
1389
+ import React15, { useState as useState12, useEffect as useEffect12, useCallback as useCallback6, useRef as useRef10 } from "react";
1378
1390
 
1379
1391
  // src/hooks/use-cuekit.ts
1380
1392
  import { useState as useState3, useCallback as useCallback2, useRef as useRef2 } from "react";
@@ -1420,22 +1432,25 @@ var useWebRTC = (options) => {
1420
1432
  options?.onAISpeechStart,
1421
1433
  options?.onAISpeechEnd
1422
1434
  ]);
1423
- const connect = useCallback(async (identity, apiKey, appId) => {
1424
- try {
1425
- setError(null);
1426
- setIsConnecting(true);
1427
- const authData = await authenticate(identity, apiKey || _apiKey, appId || _appId);
1428
- await connectToRoom(authData.livekit_url, authData.livekit_token);
1429
- setRoom(getRoom());
1430
- setIsConnected(true);
1431
- return authData;
1432
- } catch (err) {
1433
- setError(err.message || "Failed to connect");
1434
- setIsConnected(false);
1435
- } finally {
1436
- setIsConnecting(false);
1437
- }
1438
- }, []);
1435
+ const connect = useCallback(
1436
+ async (identity, apiKey, appId, language) => {
1437
+ try {
1438
+ setError(null);
1439
+ setIsConnecting(true);
1440
+ const authData = await authenticate(identity, apiKey || _apiKey, appId || _appId, language);
1441
+ await connectToRoom(authData.livekit_url, authData.livekit_token);
1442
+ setRoom(getRoom());
1443
+ setIsConnected(true);
1444
+ return authData;
1445
+ } catch (err) {
1446
+ setError(err.message || "Failed to connect");
1447
+ setIsConnected(false);
1448
+ } finally {
1449
+ setIsConnecting(false);
1450
+ }
1451
+ },
1452
+ []
1453
+ );
1439
1454
  const disconnect = useCallback(async () => {
1440
1455
  await disconnectFromRoom();
1441
1456
  setIsConnected(false);
@@ -1653,8 +1668,8 @@ var useCuekit = (options) => {
1653
1668
  onNavigationCommand: handleNavigationCommand
1654
1669
  });
1655
1670
  const connect = useCallback2(
1656
- async (identity, apiKey, appId) => {
1657
- await webrtc.connect(identity, apiKey, appId);
1671
+ async (identity, apiKey, appId, language) => {
1672
+ await webrtc.connect(identity, apiKey, appId, language);
1658
1673
  },
1659
1674
  [webrtc]
1660
1675
  );
@@ -1761,7 +1776,7 @@ var useCuekit = (options) => {
1761
1776
  };
1762
1777
 
1763
1778
  // src/components/chat-popup.tsx
1764
- import React8, { useState as useState5, useEffect as useEffect4, useRef as useRef3 } from "react";
1779
+ import React10, { useState as useState6, useEffect as useEffect6, useRef as useRef5 } from "react";
1765
1780
 
1766
1781
  // node_modules/devlop/lib/default.js
1767
1782
  function ok() {
@@ -14558,6 +14573,606 @@ var MicIcon = ({ width = 24, height = 24, className, ...props }) => {
14558
14573
  };
14559
14574
  var mic_default = MicIcon;
14560
14575
 
14576
+ // src/components/draggable-resizable-container.tsx
14577
+ import React9, { useRef as useRef4, useEffect as useEffect5 } from "react";
14578
+
14579
+ // src/utils/draggable-resizable.ts
14580
+ import { useCallback as useCallback3, useRef as useRef3, useState as useState5, useEffect as useEffect4 } from "react";
14581
+ var absoluteToRelative = (position3, size, viewportWidth, viewportHeight) => {
14582
+ return {
14583
+ position: {
14584
+ xPercent: position3.x / viewportWidth * 100,
14585
+ yPercent: position3.y / viewportHeight * 100
14586
+ },
14587
+ size: {
14588
+ widthPercent: size.width / viewportWidth * 100,
14589
+ heightPercent: size.height / viewportHeight * 100
14590
+ }
14591
+ };
14592
+ };
14593
+ var relativeToAbsolute = (relativePosition, relativeSize, viewportWidth, viewportHeight) => {
14594
+ return {
14595
+ position: {
14596
+ x: relativePosition.xPercent / 100 * viewportWidth,
14597
+ y: relativePosition.yPercent / 100 * viewportHeight
14598
+ },
14599
+ size: {
14600
+ width: relativeSize.widthPercent / 100 * viewportWidth,
14601
+ height: relativeSize.heightPercent / 100 * viewportHeight
14602
+ }
14603
+ };
14604
+ };
14605
+ var DEFAULT_BOUNDS = {
14606
+ minWidth: 300,
14607
+ minHeight: 200,
14608
+ maxWidth: typeof window !== "undefined" ? Math.min(window.innerWidth * 0.92, 800) : 800,
14609
+ maxHeight: typeof window !== "undefined" ? Math.min(window.innerHeight * 0.9, 600) : 600
14610
+ };
14611
+ var DEFAULT_POSITION = { x: 0, y: 0 };
14612
+ var DEFAULT_SIZE = {
14613
+ width: 420,
14614
+ height: typeof window !== "undefined" ? Math.min(window.innerHeight * 0.55, 500) : 400
14615
+ };
14616
+ function useDraggableResizable(options = {}) {
14617
+ const {
14618
+ bounds = DEFAULT_BOUNDS,
14619
+ initialPosition = DEFAULT_POSITION,
14620
+ initialSize = DEFAULT_SIZE,
14621
+ onPositionChange,
14622
+ onSizeChange,
14623
+ disabled = false,
14624
+ dragHandle
14625
+ } = options;
14626
+ const [position3, setPositionState] = useState5(initialPosition);
14627
+ const [size, setSizeState] = useState5(initialSize);
14628
+ const [dragState, setDragState] = useState5({
14629
+ isDragging: false,
14630
+ startPosition: { x: 0, y: 0 },
14631
+ startMousePosition: { x: 0, y: 0 }
14632
+ });
14633
+ const [resizeState, setResizeState] = useState5({
14634
+ isResizing: false,
14635
+ direction: "se",
14636
+ startSize: { width: 0, height: 0 },
14637
+ startPosition: { x: 0, y: 0 },
14638
+ startMousePosition: { x: 0, y: 0 }
14639
+ });
14640
+ const containerRef = useRef3(null);
14641
+ const constrainPosition = useCallback3((pos, size2) => {
14642
+ const maxX = window.innerWidth - size2.width;
14643
+ const maxY = window.innerHeight - size2.height;
14644
+ return {
14645
+ x: Math.max(0, Math.min(pos.x, maxX)),
14646
+ y: Math.max(0, Math.min(pos.y, maxY))
14647
+ };
14648
+ }, []);
14649
+ const constrainSize = useCallback3(
14650
+ (newSize) => {
14651
+ return {
14652
+ width: Math.max(bounds.minWidth, Math.min(newSize.width, bounds.maxWidth || Infinity)),
14653
+ height: Math.max(bounds.minHeight, Math.min(newSize.height, bounds.maxHeight || Infinity))
14654
+ };
14655
+ },
14656
+ [bounds]
14657
+ );
14658
+ const setPosition = useCallback3(
14659
+ (newPosition) => {
14660
+ const constrainedPosition = constrainPosition(newPosition, size);
14661
+ setPositionState(constrainedPosition);
14662
+ onPositionChange?.(constrainedPosition);
14663
+ },
14664
+ [size, constrainPosition, onPositionChange]
14665
+ );
14666
+ const setSize = useCallback3(
14667
+ (newSize) => {
14668
+ const constrainedSize = constrainSize(newSize);
14669
+ setSizeState(constrainedSize);
14670
+ onSizeChange?.(constrainedSize);
14671
+ const constrainedPosition = constrainPosition(position3, constrainedSize);
14672
+ if (constrainedPosition.x !== position3.x || constrainedPosition.y !== position3.y) {
14673
+ setPositionState(constrainedPosition);
14674
+ onPositionChange?.(constrainedPosition);
14675
+ }
14676
+ },
14677
+ [position3, constrainSize, constrainPosition, onSizeChange, onPositionChange]
14678
+ );
14679
+ const resetToInitial = useCallback3(() => {
14680
+ setPositionState(initialPosition);
14681
+ setSizeState(initialSize);
14682
+ onPositionChange?.(initialPosition);
14683
+ onSizeChange?.(initialSize);
14684
+ }, [initialPosition, initialSize, onPositionChange, onSizeChange]);
14685
+ const handleDragStart = useCallback3(
14686
+ (e2) => {
14687
+ if (disabled) return;
14688
+ if (dragHandle) {
14689
+ const target = e2.target;
14690
+ if (!target.closest(dragHandle)) return;
14691
+ }
14692
+ e2.preventDefault();
14693
+ e2.stopPropagation();
14694
+ setDragState({
14695
+ isDragging: true,
14696
+ startPosition: { ...position3 },
14697
+ startMousePosition: { x: e2.clientX, y: e2.clientY }
14698
+ });
14699
+ },
14700
+ [disabled, dragHandle, position3]
14701
+ );
14702
+ const handleResizeStart = useCallback3(
14703
+ (direction) => (e2) => {
14704
+ if (disabled) return;
14705
+ e2.preventDefault();
14706
+ e2.stopPropagation();
14707
+ setResizeState({
14708
+ isResizing: true,
14709
+ direction,
14710
+ startSize: { ...size },
14711
+ startPosition: { ...position3 },
14712
+ startMousePosition: { x: e2.clientX, y: e2.clientY }
14713
+ });
14714
+ },
14715
+ [disabled, size, position3]
14716
+ );
14717
+ useEffect4(() => {
14718
+ const handleMouseMove = (e2) => {
14719
+ if (dragState.isDragging) {
14720
+ const deltaX = e2.clientX - dragState.startMousePosition.x;
14721
+ const deltaY = e2.clientY - dragState.startMousePosition.y;
14722
+ const newPosition = {
14723
+ x: dragState.startPosition.x + deltaX,
14724
+ y: dragState.startPosition.y + deltaY
14725
+ };
14726
+ setPosition(newPosition);
14727
+ } else if (resizeState.isResizing) {
14728
+ const deltaX = e2.clientX - resizeState.startMousePosition.x;
14729
+ const deltaY = e2.clientY - resizeState.startMousePosition.y;
14730
+ let newSize = { ...resizeState.startSize };
14731
+ let newPosition = { ...resizeState.startPosition };
14732
+ const { direction } = resizeState;
14733
+ if (direction.includes("e")) {
14734
+ newSize.width = resizeState.startSize.width + deltaX;
14735
+ }
14736
+ if (direction.includes("w")) {
14737
+ newSize.width = resizeState.startSize.width - deltaX;
14738
+ newPosition.x = resizeState.startPosition.x + deltaX;
14739
+ }
14740
+ if (direction.includes("s")) {
14741
+ newSize.height = resizeState.startSize.height + deltaY;
14742
+ }
14743
+ if (direction.includes("n")) {
14744
+ newSize.height = resizeState.startSize.height - deltaY;
14745
+ newPosition.y = resizeState.startPosition.y + deltaY;
14746
+ }
14747
+ setSize(newSize);
14748
+ if (newPosition.x !== resizeState.startPosition.x || newPosition.y !== resizeState.startPosition.y) {
14749
+ setPosition(newPosition);
14750
+ }
14751
+ }
14752
+ };
14753
+ const handleMouseUp = () => {
14754
+ setDragState((prev) => ({ ...prev, isDragging: false }));
14755
+ setResizeState((prev) => ({ ...prev, isResizing: false }));
14756
+ };
14757
+ if (dragState.isDragging || resizeState.isResizing) {
14758
+ document.addEventListener("mousemove", handleMouseMove);
14759
+ document.addEventListener("mouseup", handleMouseUp);
14760
+ }
14761
+ return () => {
14762
+ document.removeEventListener("mousemove", handleMouseMove);
14763
+ document.removeEventListener("mouseup", handleMouseUp);
14764
+ };
14765
+ }, [dragState, resizeState, setPosition, setSize]);
14766
+ const resizeHandlers = {
14767
+ n: { onMouseDown: handleResizeStart("n") },
14768
+ s: { onMouseDown: handleResizeStart("s") },
14769
+ e: { onMouseDown: handleResizeStart("e") },
14770
+ w: { onMouseDown: handleResizeStart("w") },
14771
+ ne: { onMouseDown: handleResizeStart("ne") },
14772
+ nw: { onMouseDown: handleResizeStart("nw") },
14773
+ se: { onMouseDown: handleResizeStart("se") },
14774
+ sw: { onMouseDown: handleResizeStart("sw") }
14775
+ };
14776
+ return {
14777
+ position: position3,
14778
+ size,
14779
+ isDragging: dragState.isDragging,
14780
+ isResizing: resizeState.isResizing,
14781
+ dragHandlers: {
14782
+ onMouseDown: handleDragStart
14783
+ },
14784
+ resizeHandlers,
14785
+ setPosition,
14786
+ setSize,
14787
+ resetToInitial
14788
+ };
14789
+ }
14790
+ function getResizeCursor(direction) {
14791
+ const cursorMap = {
14792
+ n: "n-resize",
14793
+ s: "s-resize",
14794
+ e: "e-resize",
14795
+ w: "w-resize",
14796
+ ne: "ne-resize",
14797
+ nw: "nw-resize",
14798
+ se: "se-resize",
14799
+ sw: "sw-resize"
14800
+ };
14801
+ return cursorMap[direction];
14802
+ }
14803
+
14804
+ // src/components/resize-handle.tsx
14805
+ import React8 from "react";
14806
+ var ResizeHandle = ({
14807
+ direction,
14808
+ onMouseDown,
14809
+ disabled = false,
14810
+ className = "",
14811
+ style = {},
14812
+ size = 8
14813
+ }) => {
14814
+ const getHandleStyle = () => {
14815
+ const baseStyle = {
14816
+ position: "absolute",
14817
+ backgroundColor: "transparent",
14818
+ cursor: disabled ? "default" : getResizeCursor(direction),
14819
+ zIndex: 1e3,
14820
+ userSelect: "none",
14821
+ ...style
14822
+ };
14823
+ switch (direction) {
14824
+ case "n":
14825
+ return {
14826
+ ...baseStyle,
14827
+ top: -size / 2,
14828
+ left: 0,
14829
+ right: 0,
14830
+ height: size
14831
+ };
14832
+ case "s":
14833
+ return {
14834
+ ...baseStyle,
14835
+ bottom: -size / 2,
14836
+ left: 0,
14837
+ right: 0,
14838
+ height: size
14839
+ };
14840
+ case "e":
14841
+ return {
14842
+ ...baseStyle,
14843
+ top: 0,
14844
+ bottom: 0,
14845
+ right: -size / 2,
14846
+ width: size
14847
+ };
14848
+ case "w":
14849
+ return {
14850
+ ...baseStyle,
14851
+ top: 0,
14852
+ bottom: 0,
14853
+ left: -size / 2,
14854
+ width: size
14855
+ };
14856
+ case "ne":
14857
+ return {
14858
+ ...baseStyle,
14859
+ top: -size / 2,
14860
+ right: -size / 2,
14861
+ width: size,
14862
+ height: size
14863
+ };
14864
+ case "nw":
14865
+ return {
14866
+ ...baseStyle,
14867
+ top: -size / 2,
14868
+ left: -size / 2,
14869
+ width: size,
14870
+ height: size
14871
+ };
14872
+ case "se":
14873
+ return {
14874
+ ...baseStyle,
14875
+ bottom: -size / 2,
14876
+ right: -size / 2,
14877
+ width: size,
14878
+ height: size
14879
+ };
14880
+ case "sw":
14881
+ return {
14882
+ ...baseStyle,
14883
+ bottom: -size / 2,
14884
+ left: -size / 2,
14885
+ width: size,
14886
+ height: size
14887
+ };
14888
+ default:
14889
+ return baseStyle;
14890
+ }
14891
+ };
14892
+ const handleMouseDown = (e2) => {
14893
+ if (!disabled) {
14894
+ onMouseDown(e2);
14895
+ }
14896
+ };
14897
+ return /* @__PURE__ */ React8.createElement(
14898
+ "div",
14899
+ {
14900
+ className: `resize-handle resize-handle-${direction} ${className}`,
14901
+ style: getHandleStyle(),
14902
+ onMouseDown: handleMouseDown,
14903
+ "data-direction": direction,
14904
+ "aria-label": `Resize ${direction}`
14905
+ }
14906
+ );
14907
+ };
14908
+ var ResizeHandles = ({
14909
+ onResizeStart,
14910
+ disabled = false,
14911
+ className = "",
14912
+ style = {},
14913
+ size = 8,
14914
+ showHandles = ["n", "s", "e", "w", "ne", "nw", "se", "sw"]
14915
+ }) => {
14916
+ return /* @__PURE__ */ React8.createElement(React8.Fragment, null, showHandles.map((direction) => /* @__PURE__ */ React8.createElement(
14917
+ ResizeHandle,
14918
+ {
14919
+ key: direction,
14920
+ direction,
14921
+ onMouseDown: onResizeStart(direction),
14922
+ disabled,
14923
+ className,
14924
+ style,
14925
+ size
14926
+ }
14927
+ )));
14928
+ };
14929
+
14930
+ // src/components/draggable-resizable-container.tsx
14931
+ var DraggableResizableContainer = ({
14932
+ children,
14933
+ className = "",
14934
+ style = {},
14935
+ dragHandle,
14936
+ showResizeHandles = true,
14937
+ resizeHandleSize = 8,
14938
+ onPositionChange,
14939
+ onSizeChange,
14940
+ onDragStart,
14941
+ onDragEnd,
14942
+ onResizeStart,
14943
+ onResizeEnd,
14944
+ storageKey,
14945
+ persistPosition = false,
14946
+ persistSize = false,
14947
+ ...options
14948
+ }) => {
14949
+ const containerRef = useRef4(null);
14950
+ const loadPersistedData = () => {
14951
+ if (!storageKey || typeof window === "undefined") return {};
14952
+ try {
14953
+ const data = localStorage.getItem(`cuekit-${storageKey}`);
14954
+ if (data) {
14955
+ const parsed = JSON.parse(data);
14956
+ if (parsed.relativePosition && parsed.relativeSize) {
14957
+ const viewportWidth = window.innerWidth;
14958
+ const viewportHeight = window.innerHeight;
14959
+ const { position: position4, size: size2 } = relativeToAbsolute(
14960
+ parsed.relativePosition,
14961
+ parsed.relativeSize,
14962
+ viewportWidth,
14963
+ viewportHeight
14964
+ );
14965
+ return { position: position4, size: size2 };
14966
+ }
14967
+ return {
14968
+ position: parsed.position,
14969
+ size: parsed.size
14970
+ };
14971
+ }
14972
+ } catch (error) {
14973
+ console.warn("Failed to load persisted position/size:", error);
14974
+ }
14975
+ return {};
14976
+ };
14977
+ const savePersistedData = (position4, size2) => {
14978
+ if (!storageKey || typeof window === "undefined") return;
14979
+ try {
14980
+ const viewportWidth = window.innerWidth;
14981
+ const viewportHeight = window.innerHeight;
14982
+ const { position: relativePosition, size: relativeSize } = absoluteToRelative(
14983
+ position4,
14984
+ size2,
14985
+ viewportWidth,
14986
+ viewportHeight
14987
+ );
14988
+ const data = {};
14989
+ if (persistPosition) {
14990
+ data.position = position4;
14991
+ data.relativePosition = relativePosition;
14992
+ }
14993
+ if (persistSize) {
14994
+ data.size = size2;
14995
+ data.relativeSize = relativeSize;
14996
+ }
14997
+ localStorage.setItem(`cuekit-${storageKey}`, JSON.stringify(data));
14998
+ } catch (error) {
14999
+ console.warn("Failed to save persisted position/size:", error);
15000
+ }
15001
+ };
15002
+ const persistedData = loadPersistedData();
15003
+ const initialPosition = persistedData.position || options.initialPosition;
15004
+ const initialSize = persistedData.size || options.initialSize;
15005
+ useEffect5(() => {
15006
+ const handleResize = () => {
15007
+ if (!storageKey || typeof window === "undefined") return;
15008
+ try {
15009
+ const data = localStorage.getItem(`cuekit-${storageKey}`);
15010
+ if (data) {
15011
+ const parsed = JSON.parse(data);
15012
+ if (parsed.relativePosition && parsed.relativeSize) {
15013
+ const viewportWidth = window.innerWidth;
15014
+ const viewportHeight = window.innerHeight;
15015
+ const { position: position4, size: size2 } = relativeToAbsolute(
15016
+ parsed.relativePosition,
15017
+ parsed.relativeSize,
15018
+ viewportWidth,
15019
+ viewportHeight
15020
+ );
15021
+ if (containerRef.current) {
15022
+ containerRef.current.style.left = `${position4.x}px`;
15023
+ containerRef.current.style.top = `${position4.y}px`;
15024
+ containerRef.current.style.width = `${size2.width}px`;
15025
+ containerRef.current.style.height = `${size2.height}px`;
15026
+ }
15027
+ }
15028
+ }
15029
+ } catch (error) {
15030
+ console.warn("Failed to update position on resize:", error);
15031
+ }
15032
+ };
15033
+ window.addEventListener("resize", handleResize);
15034
+ return () => window.removeEventListener("resize", handleResize);
15035
+ }, [storageKey]);
15036
+ const {
15037
+ position: position3,
15038
+ size,
15039
+ isDragging,
15040
+ isResizing,
15041
+ dragHandlers,
15042
+ resizeHandlers,
15043
+ setPosition,
15044
+ setSize
15045
+ } = useDraggableResizable({
15046
+ ...options,
15047
+ initialPosition,
15048
+ initialSize,
15049
+ onPositionChange: (pos) => {
15050
+ onPositionChange?.(pos);
15051
+ if (persistPosition || persistSize) {
15052
+ savePersistedData(pos, size);
15053
+ }
15054
+ },
15055
+ onSizeChange: (newSize) => {
15056
+ onSizeChange?.(newSize);
15057
+ if (persistPosition || persistSize) {
15058
+ savePersistedData(position3, newSize);
15059
+ }
15060
+ }
15061
+ });
15062
+ const handleDragStart = (e2) => {
15063
+ dragHandlers.onMouseDown(e2);
15064
+ onDragStart?.();
15065
+ };
15066
+ const handleResizeStart = (direction) => (e2) => {
15067
+ resizeHandlers[direction].onMouseDown(e2);
15068
+ onResizeStart?.();
15069
+ };
15070
+ useEffect5(() => {
15071
+ if (!isDragging) {
15072
+ onDragEnd?.();
15073
+ }
15074
+ }, [isDragging, onDragEnd]);
15075
+ useEffect5(() => {
15076
+ if (!isResizing) {
15077
+ onResizeEnd?.();
15078
+ }
15079
+ }, [isResizing, onResizeEnd]);
15080
+ const containerStyle = {
15081
+ position: "fixed",
15082
+ left: position3.x,
15083
+ top: position3.y,
15084
+ width: size.width,
15085
+ height: size.height,
15086
+ transform: "none",
15087
+ // We use left/top instead of transform for better performance
15088
+ zIndex: 1e3,
15089
+ ...style
15090
+ };
15091
+ const containerClassName = [
15092
+ "draggable-resizable-container",
15093
+ isDragging ? "is-dragging" : "",
15094
+ isResizing ? "is-resizing" : "",
15095
+ className
15096
+ ].filter(Boolean).join(" ");
15097
+ return /* @__PURE__ */ React9.createElement(
15098
+ "div",
15099
+ {
15100
+ ref: containerRef,
15101
+ className: containerClassName,
15102
+ style: containerStyle,
15103
+ "data-cuekit-ignore": true
15104
+ },
15105
+ /* @__PURE__ */ React9.createElement(
15106
+ "div",
15107
+ {
15108
+ className: "drag-handle",
15109
+ style: {
15110
+ position: "absolute",
15111
+ top: 0,
15112
+ left: 0,
15113
+ right: 0,
15114
+ height: "20px",
15115
+ // Height of the header area
15116
+ cursor: "move",
15117
+ zIndex: 10
15118
+ },
15119
+ onMouseDown: handleDragStart,
15120
+ "data-drag-handle": "true"
15121
+ }
15122
+ ),
15123
+ /* @__PURE__ */ React9.createElement(
15124
+ "div",
15125
+ {
15126
+ className: "draggable-content",
15127
+ style: {
15128
+ width: "100%",
15129
+ height: "100%",
15130
+ overflow: "hidden",
15131
+ display: "flex",
15132
+ flexDirection: "column"
15133
+ }
15134
+ },
15135
+ children
15136
+ ),
15137
+ showResizeHandles && /* @__PURE__ */ React9.createElement(
15138
+ ResizeHandles,
15139
+ {
15140
+ onResizeStart: handleResizeStart,
15141
+ disabled: options.disabled,
15142
+ size: resizeHandleSize
15143
+ }
15144
+ )
15145
+ );
15146
+ };
15147
+ var useDraggableResizableContainer = (storageKey) => {
15148
+ const loadData = () => {
15149
+ if (!storageKey || typeof window === "undefined") return null;
15150
+ try {
15151
+ const data = localStorage.getItem(`cuekit-${storageKey}`);
15152
+ return data ? JSON.parse(data) : null;
15153
+ } catch {
15154
+ return null;
15155
+ }
15156
+ };
15157
+ const saveData = (data) => {
15158
+ if (!storageKey || typeof window === "undefined") return;
15159
+ try {
15160
+ localStorage.setItem(`cuekit-${storageKey}`, JSON.stringify(data));
15161
+ } catch (error) {
15162
+ console.warn("Failed to save data:", error);
15163
+ }
15164
+ };
15165
+ const clearData = () => {
15166
+ if (!storageKey || typeof window === "undefined") return;
15167
+ try {
15168
+ localStorage.removeItem(`cuekit-${storageKey}`);
15169
+ } catch (error) {
15170
+ console.warn("Failed to clear data:", error);
15171
+ }
15172
+ };
15173
+ return { loadData, saveData, clearData };
15174
+ };
15175
+
14561
15176
  // src/components/chat-popup.tsx
14562
15177
  var ChatPopup = ({
14563
15178
  isOpen,
@@ -14576,15 +15191,26 @@ var ChatPopup = ({
14576
15191
  status,
14577
15192
  anchor,
14578
15193
  muteState,
14579
- onToggleMute
15194
+ onToggleMute,
15195
+ // Draggable/Resizable props
15196
+ draggable = true,
15197
+ resizable = true,
15198
+ initialPosition,
15199
+ initialSize,
15200
+ onPositionChange,
15201
+ onSizeChange,
15202
+ persistPosition = true,
15203
+ persistSize = true,
15204
+ storageKey = "chat-popup"
14580
15205
  }) => {
14581
- const [inputText, setInputText] = useState5("");
14582
- const [isSending, setIsSending] = useState5(false);
14583
- const messagesEndRef = useRef3(null);
15206
+ const { title, showLogo, showAIIcon, showUserIcon } = useAnsyrContext();
15207
+ const [inputText, setInputText] = useState6("");
15208
+ const [isSending, setIsSending] = useState6(false);
15209
+ const messagesEndRef = useRef5(null);
14584
15210
  const scrollToBottom = () => {
14585
15211
  messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
14586
15212
  };
14587
- useEffect4(() => {
15213
+ useEffect6(() => {
14588
15214
  console.log("\u{1F4EC} ChatPopup received messages:", JSON.stringify(messages, null, 2));
14589
15215
  scrollToBottom();
14590
15216
  }, [messages]);
@@ -14606,7 +15232,6 @@ var ChatPopup = ({
14606
15232
  handleSend();
14607
15233
  }
14608
15234
  };
14609
- if (!isOpen || isMinimized) return null;
14610
15235
  const getStatusText = () => {
14611
15236
  if (status) return status;
14612
15237
  if (micState === "listening") return "Listening...";
@@ -14614,48 +15239,57 @@ var ChatPopup = ({
14614
15239
  if (micState === "replying") return "Responding...";
14615
15240
  return "Listening...";
14616
15241
  };
14617
- const getPositionStyle = () => {
15242
+ const getInitialPosition = () => {
15243
+ if (initialPosition) return initialPosition;
14618
15244
  if (!anchor) {
14619
15245
  return {
14620
- bottom: "100px",
14621
- right: "20px"
15246
+ x: window.innerWidth - 420 - 20,
15247
+ y: window.innerHeight - window.innerHeight * 0.55 - 20
14622
15248
  };
14623
15249
  }
14624
15250
  const bottomOffset = anchor.bottom + anchor.size + 16;
14625
- const baseStyle = {
14626
- bottom: `${bottomOffset}px`
14627
- };
15251
+ const popupHeight = window.innerHeight * 0.55;
15252
+ const y = window.innerHeight - bottomOffset - popupHeight;
14628
15253
  switch (anchor.position) {
14629
15254
  case "bottom-center":
14630
- return {
14631
- ...baseStyle,
14632
- left: "50%",
14633
- transform: "translateX(-50%)"
14634
- };
15255
+ return { x: (window.innerWidth - 420) / 2, y };
14635
15256
  case "bottom-left":
14636
- return {
14637
- ...baseStyle,
14638
- left: "20px"
14639
- };
15257
+ return { x: 20, y };
14640
15258
  case "bottom-right":
14641
15259
  default:
14642
- return {
14643
- ...baseStyle,
14644
- right: "20px"
14645
- };
15260
+ return { x: window.innerWidth - 420 - 20, y };
14646
15261
  }
14647
15262
  };
14648
- const positionStyle = getPositionStyle();
14649
- return /* @__PURE__ */ React8.createElement(
14650
- "div",
15263
+ const getInitialSize = () => {
15264
+ if (initialSize) return initialSize;
15265
+ return {
15266
+ width: 420,
15267
+ height: window.innerHeight * 0.55
15268
+ };
15269
+ };
15270
+ if (!isOpen || isMinimized) return null;
15271
+ return /* @__PURE__ */ React10.createElement(
15272
+ DraggableResizableContainer,
14651
15273
  {
14652
- "data-cuekit-ignore": true,
15274
+ initialPosition: getInitialPosition(),
15275
+ initialSize: getInitialSize(),
15276
+ onPositionChange,
15277
+ onSizeChange,
15278
+ persistPosition,
15279
+ persistSize,
15280
+ storageKey,
15281
+ disabled: !draggable && !resizable,
15282
+ showResizeHandles: resizable,
15283
+ bounds: {
15284
+ minWidth: 300,
15285
+ minHeight: 200,
15286
+ maxWidth: Math.min(window.innerWidth * 0.92, 800),
15287
+ // Cap at 800px max width
15288
+ maxHeight: Math.min(window.innerHeight * 0.9, 600)
15289
+ // Cap at 600px max height
15290
+ },
14653
15291
  className: `cuekit-voice-popup ${currentTheme === "dark" ? "cuekit-dark" : ""}`,
14654
15292
  style: {
14655
- position: "fixed",
14656
- width: "420px",
14657
- maxWidth: "92vw",
14658
- height: "55vh",
14659
15293
  borderRadius: "10px",
14660
15294
  background: "hsl(var(--voice-bg))",
14661
15295
  boxShadow: "var(--shadow-card)",
@@ -14663,13 +15297,11 @@ var ChatPopup = ({
14663
15297
  display: "flex",
14664
15298
  animation: "scaleIn 0.3s ease-out",
14665
15299
  flexDirection: "column",
14666
- zIndex: 1e3,
14667
15300
  fontFamily: "Inter, system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif",
14668
- overflow: "hidden",
14669
- ...positionStyle
15301
+ overflow: "hidden"
14670
15302
  }
14671
15303
  },
14672
- /* @__PURE__ */ React8.createElement(
15304
+ /* @__PURE__ */ React10.createElement(
14673
15305
  "div",
14674
15306
  {
14675
15307
  style: {
@@ -14680,14 +15312,14 @@ var ChatPopup = ({
14680
15312
  justifyContent: "space-between"
14681
15313
  }
14682
15314
  },
14683
- /* @__PURE__ */ React8.createElement("div", { style: { display: "flex", alignItems: "center", gap: 0 } }, /* @__PURE__ */ React8.createElement(
15315
+ /* @__PURE__ */ React10.createElement("div", { style: { display: "flex", alignItems: "center", gap: 0 } }, showLogo && /* @__PURE__ */ React10.createElement(
14684
15316
  "img",
14685
15317
  {
14686
15318
  src: "https://dashboard.cuekit.ai/_next/image?url=%2Fimages%2Fcuekit-logo-2.png&w=256&q=100",
14687
15319
  alt: "Cuekit AI",
14688
15320
  style: { width: 58, objectFit: "cover" }
14689
15321
  }
14690
- ), /* @__PURE__ */ React8.createElement(
15322
+ ), /* @__PURE__ */ React10.createElement(
14691
15323
  "div",
14692
15324
  {
14693
15325
  style: {
@@ -14698,10 +15330,11 @@ var ChatPopup = ({
14698
15330
  justifyContent: "center"
14699
15331
  }
14700
15332
  },
14701
- /* @__PURE__ */ React8.createElement(
15333
+ /* @__PURE__ */ React10.createElement(
14702
15334
  "span",
14703
15335
  {
14704
15336
  style: {
15337
+ paddingLeft: showLogo ? 0 : 12,
14705
15338
  fontSize: 18,
14706
15339
  fontWeight: 700,
14707
15340
  lineHeight: "1.2",
@@ -14713,9 +15346,9 @@ var ChatPopup = ({
14713
15346
  WebkitTextFillColor: "transparent"
14714
15347
  }
14715
15348
  },
14716
- "ansyr.ai"
15349
+ title
14717
15350
  ),
14718
- /* @__PURE__ */ React8.createElement("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 4 } }, /* @__PURE__ */ React8.createElement(
15351
+ /* @__PURE__ */ React10.createElement("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 4 } }, /* @__PURE__ */ React10.createElement(
14719
15352
  "div",
14720
15353
  {
14721
15354
  style: {
@@ -14731,7 +15364,7 @@ var ChatPopup = ({
14731
15364
  fontWeight: "500"
14732
15365
  }
14733
15366
  },
14734
- /* @__PURE__ */ React8.createElement(
15367
+ /* @__PURE__ */ React10.createElement(
14735
15368
  "span",
14736
15369
  {
14737
15370
  style: {
@@ -14742,8 +15375,8 @@ var ChatPopup = ({
14742
15375
  )
14743
15376
  ))
14744
15377
  )),
14745
- /* @__PURE__ */ React8.createElement("div", { style: { minWidth: 100, textAlign: "center" } }),
14746
- /* @__PURE__ */ React8.createElement(
15378
+ /* @__PURE__ */ React10.createElement("div", { style: { minWidth: 100, textAlign: "center" } }),
15379
+ /* @__PURE__ */ React10.createElement(
14747
15380
  "div",
14748
15381
  {
14749
15382
  style: {
@@ -14755,7 +15388,7 @@ var ChatPopup = ({
14755
15388
  top: 16
14756
15389
  }
14757
15390
  },
14758
- onThemeToggle && /* @__PURE__ */ React8.createElement(
15391
+ onThemeToggle && /* @__PURE__ */ React10.createElement(
14759
15392
  "button",
14760
15393
  {
14761
15394
  onClick: () => {
@@ -14785,7 +15418,7 @@ var ChatPopup = ({
14785
15418
  "aria-label": "Toggle theme",
14786
15419
  title: `Switch to ${currentTheme === "dark" ? "light" : "dark"} mode`
14787
15420
  },
14788
- currentTheme === "dark" ? /* @__PURE__ */ React8.createElement(
15421
+ currentTheme === "dark" ? /* @__PURE__ */ React10.createElement(
14789
15422
  sun_default,
14790
15423
  {
14791
15424
  style: {
@@ -14795,7 +15428,7 @@ var ChatPopup = ({
14795
15428
  animation: "themeToggleEnter 0.3s ease-in-out"
14796
15429
  }
14797
15430
  }
14798
- ) : /* @__PURE__ */ React8.createElement(
15431
+ ) : /* @__PURE__ */ React10.createElement(
14799
15432
  moon_default,
14800
15433
  {
14801
15434
  style: {
@@ -14807,7 +15440,7 @@ var ChatPopup = ({
14807
15440
  }
14808
15441
  )
14809
15442
  ),
14810
- /* @__PURE__ */ React8.createElement(
15443
+ /* @__PURE__ */ React10.createElement(
14811
15444
  "button",
14812
15445
  {
14813
15446
  onClick: onMinimize,
@@ -14834,11 +15467,11 @@ var ChatPopup = ({
14834
15467
  "aria-label": "Minimize",
14835
15468
  title: "Minimize chat"
14836
15469
  },
14837
- /* @__PURE__ */ React8.createElement(close_default, { style: { width: 16, height: 16, color: "hsl(var(--voice-text-muted))" } })
15470
+ /* @__PURE__ */ React10.createElement(close_default, { style: { width: 16, height: 16, color: "hsl(var(--voice-text-muted))" } })
14838
15471
  )
14839
15472
  )
14840
15473
  ),
14841
- /* @__PURE__ */ React8.createElement(
15474
+ /* @__PURE__ */ React10.createElement(
14842
15475
  "div",
14843
15476
  {
14844
15477
  style: {
@@ -14851,7 +15484,7 @@ var ChatPopup = ({
14851
15484
  color: "hsl(var(--voice-text))"
14852
15485
  }
14853
15486
  },
14854
- messages.length === 0 ? /* @__PURE__ */ React8.createElement(
15487
+ messages.length === 0 ? /* @__PURE__ */ React10.createElement(
14855
15488
  "div",
14856
15489
  {
14857
15490
  style: {
@@ -14861,7 +15494,7 @@ var ChatPopup = ({
14861
15494
  }
14862
15495
  },
14863
15496
  "Start a conversation with CueKit AI"
14864
- ) : messages.map((message, index2) => /* @__PURE__ */ React8.createElement(
15497
+ ) : messages.map((message, index2) => /* @__PURE__ */ React10.createElement(
14865
15498
  "div",
14866
15499
  {
14867
15500
  key: index2,
@@ -14875,7 +15508,7 @@ var ChatPopup = ({
14875
15508
  justifyContent: message.sender === "user" ? "flex-end" : "flex-start"
14876
15509
  }
14877
15510
  },
14878
- message.sender === "assistant" && /* @__PURE__ */ React8.createElement(
15511
+ message.sender === "assistant" && showAIIcon && /* @__PURE__ */ React10.createElement(
14879
15512
  "div",
14880
15513
  {
14881
15514
  style: {
@@ -14890,7 +15523,7 @@ var ChatPopup = ({
14890
15523
  overflow: "hidden"
14891
15524
  }
14892
15525
  },
14893
- /* @__PURE__ */ React8.createElement(
15526
+ /* @__PURE__ */ React10.createElement(
14894
15527
  "img",
14895
15528
  {
14896
15529
  src: "https://dashboard.cuekit.ai/_next/image?url=%2Fimages%2Fcuekit-logo-2.png&w=256&q=100",
@@ -14904,7 +15537,7 @@ var ChatPopup = ({
14904
15537
  }
14905
15538
  )
14906
15539
  ),
14907
- /* @__PURE__ */ React8.createElement(
15540
+ /* @__PURE__ */ React10.createElement(
14908
15541
  "div",
14909
15542
  {
14910
15543
  style: {
@@ -14915,7 +15548,7 @@ var ChatPopup = ({
14915
15548
  flex: 1
14916
15549
  }
14917
15550
  },
14918
- /* @__PURE__ */ React8.createElement(
15551
+ /* @__PURE__ */ React10.createElement(
14919
15552
  "div",
14920
15553
  {
14921
15554
  style: {
@@ -14933,12 +15566,12 @@ var ChatPopup = ({
14933
15566
  marginLeft: message.sender === "user" ? "auto" : 0
14934
15567
  }
14935
15568
  },
14936
- /* @__PURE__ */ React8.createElement("div", null, /* @__PURE__ */ React8.createElement(
15569
+ /* @__PURE__ */ React10.createElement("div", null, /* @__PURE__ */ React10.createElement(
14937
15570
  Markdown,
14938
15571
  {
14939
15572
  remarkPlugins: [remarkGfm],
14940
15573
  components: {
14941
- p: ({ children }) => /* @__PURE__ */ React8.createElement(
15574
+ p: ({ children }) => /* @__PURE__ */ React10.createElement(
14942
15575
  "p",
14943
15576
  {
14944
15577
  style: {
@@ -14949,7 +15582,7 @@ var ChatPopup = ({
14949
15582
  },
14950
15583
  children
14951
15584
  ),
14952
- h1: ({ children }) => /* @__PURE__ */ React8.createElement(
15585
+ h1: ({ children }) => /* @__PURE__ */ React10.createElement(
14953
15586
  "h1",
14954
15587
  {
14955
15588
  style: {
@@ -14961,7 +15594,7 @@ var ChatPopup = ({
14961
15594
  },
14962
15595
  children
14963
15596
  ),
14964
- h2: ({ children }) => /* @__PURE__ */ React8.createElement(
15597
+ h2: ({ children }) => /* @__PURE__ */ React10.createElement(
14965
15598
  "h2",
14966
15599
  {
14967
15600
  style: {
@@ -14973,7 +15606,7 @@ var ChatPopup = ({
14973
15606
  },
14974
15607
  children
14975
15608
  ),
14976
- h3: ({ children }) => /* @__PURE__ */ React8.createElement(
15609
+ h3: ({ children }) => /* @__PURE__ */ React10.createElement(
14977
15610
  "h3",
14978
15611
  {
14979
15612
  style: {
@@ -14985,7 +15618,7 @@ var ChatPopup = ({
14985
15618
  },
14986
15619
  children
14987
15620
  ),
14988
- ul: ({ children }) => /* @__PURE__ */ React8.createElement(
15621
+ ul: ({ children }) => /* @__PURE__ */ React10.createElement(
14989
15622
  "ul",
14990
15623
  {
14991
15624
  style: {
@@ -14997,7 +15630,7 @@ var ChatPopup = ({
14997
15630
  },
14998
15631
  children
14999
15632
  ),
15000
- ol: ({ children }) => /* @__PURE__ */ React8.createElement(
15633
+ ol: ({ children }) => /* @__PURE__ */ React10.createElement(
15001
15634
  "ol",
15002
15635
  {
15003
15636
  style: {
@@ -15009,7 +15642,7 @@ var ChatPopup = ({
15009
15642
  },
15010
15643
  children
15011
15644
  ),
15012
- li: ({ children }) => /* @__PURE__ */ React8.createElement(
15645
+ li: ({ children }) => /* @__PURE__ */ React10.createElement(
15013
15646
  "li",
15014
15647
  {
15015
15648
  style: {
@@ -15020,7 +15653,7 @@ var ChatPopup = ({
15020
15653
  },
15021
15654
  children
15022
15655
  ),
15023
- strong: ({ children }) => /* @__PURE__ */ React8.createElement(
15656
+ strong: ({ children }) => /* @__PURE__ */ React10.createElement(
15024
15657
  "strong",
15025
15658
  {
15026
15659
  style: {
@@ -15031,7 +15664,7 @@ var ChatPopup = ({
15031
15664
  },
15032
15665
  children
15033
15666
  ),
15034
- em: ({ children }) => /* @__PURE__ */ React8.createElement(
15667
+ em: ({ children }) => /* @__PURE__ */ React10.createElement(
15035
15668
  "em",
15036
15669
  {
15037
15670
  style: {
@@ -15042,7 +15675,7 @@ var ChatPopup = ({
15042
15675
  },
15043
15676
  children
15044
15677
  ),
15045
- code: ({ children }) => /* @__PURE__ */ React8.createElement(
15678
+ code: ({ children }) => /* @__PURE__ */ React10.createElement(
15046
15679
  "code",
15047
15680
  {
15048
15681
  style: {
@@ -15055,7 +15688,7 @@ var ChatPopup = ({
15055
15688
  },
15056
15689
  children
15057
15690
  ),
15058
- pre: ({ children }) => /* @__PURE__ */ React8.createElement(
15691
+ pre: ({ children }) => /* @__PURE__ */ React10.createElement(
15059
15692
  "pre",
15060
15693
  {
15061
15694
  style: {
@@ -15070,7 +15703,7 @@ var ChatPopup = ({
15070
15703
  },
15071
15704
  children
15072
15705
  ),
15073
- blockquote: ({ children }) => /* @__PURE__ */ React8.createElement(
15706
+ blockquote: ({ children }) => /* @__PURE__ */ React10.createElement(
15074
15707
  "blockquote",
15075
15708
  {
15076
15709
  style: {
@@ -15089,7 +15722,7 @@ var ChatPopup = ({
15089
15722
  message.text
15090
15723
  ))
15091
15724
  ),
15092
- message.sender === "user" && /* @__PURE__ */ React8.createElement(
15725
+ message.sender === "user" && showUserIcon && /* @__PURE__ */ React10.createElement(
15093
15726
  "div",
15094
15727
  {
15095
15728
  style: {
@@ -15110,9 +15743,9 @@ var ChatPopup = ({
15110
15743
  )
15111
15744
  )
15112
15745
  )),
15113
- /* @__PURE__ */ React8.createElement("div", { ref: messagesEndRef })
15746
+ /* @__PURE__ */ React10.createElement("div", { ref: messagesEndRef })
15114
15747
  ),
15115
- /* @__PURE__ */ React8.createElement(
15748
+ /* @__PURE__ */ React10.createElement(
15116
15749
  "div",
15117
15750
  {
15118
15751
  style: {
@@ -15121,7 +15754,7 @@ var ChatPopup = ({
15121
15754
  background: "hsl(var(--voice-bg))"
15122
15755
  }
15123
15756
  },
15124
- /* @__PURE__ */ React8.createElement(
15757
+ /* @__PURE__ */ React10.createElement(
15125
15758
  "form",
15126
15759
  {
15127
15760
  onSubmit: (e2) => {
@@ -15130,7 +15763,7 @@ var ChatPopup = ({
15130
15763
  },
15131
15764
  style: { display: "flex", alignItems: "center", gap: 8, margin: 0 }
15132
15765
  },
15133
- /* @__PURE__ */ React8.createElement(
15766
+ /* @__PURE__ */ React10.createElement(
15134
15767
  "input",
15135
15768
  {
15136
15769
  type: "text",
@@ -15157,7 +15790,7 @@ var ChatPopup = ({
15157
15790
  }
15158
15791
  }
15159
15792
  ),
15160
- muteState?.canMute && onToggleMute && /* @__PURE__ */ React8.createElement(
15793
+ muteState?.canMute && onToggleMute && /* @__PURE__ */ React10.createElement(
15161
15794
  "button",
15162
15795
  {
15163
15796
  onClick: onToggleMute,
@@ -15177,8 +15810,8 @@ var ChatPopup = ({
15177
15810
  "aria-label": muteState.isMuted ? "Unmute microphone" : "Mute microphone",
15178
15811
  title: muteState.isMuted ? "Unmute microphone" : "Mute microphone"
15179
15812
  },
15180
- muteState.isMuted ? /* @__PURE__ */ React8.createElement(
15181
- mic_default,
15813
+ muteState.isMuted ? /* @__PURE__ */ React10.createElement(
15814
+ mic_off_default,
15182
15815
  {
15183
15816
  style: {
15184
15817
  width: 16,
@@ -15186,8 +15819,8 @@ var ChatPopup = ({
15186
15819
  color: "hsl(var(--voice-user-text))"
15187
15820
  }
15188
15821
  }
15189
- ) : /* @__PURE__ */ React8.createElement(
15190
- mic_off_default,
15822
+ ) : /* @__PURE__ */ React10.createElement(
15823
+ mic_default,
15191
15824
  {
15192
15825
  style: {
15193
15826
  width: 16,
@@ -15197,7 +15830,7 @@ var ChatPopup = ({
15197
15830
  }
15198
15831
  )
15199
15832
  ),
15200
- isConnected && onEndCall && /* @__PURE__ */ React8.createElement(
15833
+ isConnected && onEndCall && /* @__PURE__ */ React10.createElement(
15201
15834
  "button",
15202
15835
  {
15203
15836
  type: "submit",
@@ -15216,7 +15849,7 @@ var ChatPopup = ({
15216
15849
  cursor: "pointer"
15217
15850
  }
15218
15851
  },
15219
- /* @__PURE__ */ React8.createElement(phone_off_default, { style: { width: 16, height: 16 } })
15852
+ /* @__PURE__ */ React10.createElement(phone_off_default, { style: { width: 16, height: 16 } })
15220
15853
  )
15221
15854
  )
15222
15855
  )
@@ -15224,7 +15857,7 @@ var ChatPopup = ({
15224
15857
  };
15225
15858
 
15226
15859
  // src/components/border-glow.tsx
15227
- import React9 from "react";
15860
+ import React11 from "react";
15228
15861
  var BorderGlow = ({ isActive }) => {
15229
15862
  if (!isActive) return null;
15230
15863
  const styles = {
@@ -15351,7 +15984,7 @@ var BorderGlow = ({ isActive }) => {
15351
15984
  opacity: 0.6
15352
15985
  }
15353
15986
  };
15354
- return /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement("style", null, `
15987
+ return /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement("style", null, `
15355
15988
  @keyframes borderPulse {
15356
15989
  0%, 100% {
15357
15990
  opacity: 1;
@@ -15360,12 +15993,12 @@ var BorderGlow = ({ isActive }) => {
15360
15993
  opacity: 0.5;
15361
15994
  }
15362
15995
  }
15363
- `), /* @__PURE__ */ React9.createElement("div", { style: styles.container }, /* @__PURE__ */ React9.createElement("div", { style: styles.rightBorder1 }), /* @__PURE__ */ React9.createElement("div", { style: styles.rightBorder2 }), /* @__PURE__ */ React9.createElement("div", { style: styles.rightBorder3 }), /* @__PURE__ */ React9.createElement("div", { style: styles.leftBorder1 }), /* @__PURE__ */ React9.createElement("div", { style: styles.leftBorder2 }), /* @__PURE__ */ React9.createElement("div", { style: styles.leftBorder3 }), /* @__PURE__ */ React9.createElement("div", { style: styles.cornerTopLeft }), /* @__PURE__ */ React9.createElement("div", { style: styles.cornerTopRight }), /* @__PURE__ */ React9.createElement("div", { style: styles.cornerBottomRight }), /* @__PURE__ */ React9.createElement("div", { style: styles.cornerBottomLeft })));
15996
+ `), /* @__PURE__ */ React11.createElement("div", { style: styles.container }, /* @__PURE__ */ React11.createElement("div", { style: styles.rightBorder1 }), /* @__PURE__ */ React11.createElement("div", { style: styles.rightBorder2 }), /* @__PURE__ */ React11.createElement("div", { style: styles.rightBorder3 }), /* @__PURE__ */ React11.createElement("div", { style: styles.leftBorder1 }), /* @__PURE__ */ React11.createElement("div", { style: styles.leftBorder2 }), /* @__PURE__ */ React11.createElement("div", { style: styles.leftBorder3 }), /* @__PURE__ */ React11.createElement("div", { style: styles.cornerTopLeft }), /* @__PURE__ */ React11.createElement("div", { style: styles.cornerTopRight }), /* @__PURE__ */ React11.createElement("div", { style: styles.cornerBottomRight }), /* @__PURE__ */ React11.createElement("div", { style: styles.cornerBottomLeft })));
15364
15997
  };
15365
15998
  var border_glow_default = BorderGlow;
15366
15999
 
15367
16000
  // src/components/voice-intensity-visualizer.tsx
15368
- import React10, { useEffect as useEffect8, useState as useState9 } from "react";
16001
+ import React12, { useEffect as useEffect10, useState as useState10 } from "react";
15369
16002
 
15370
16003
  // node_modules/@livekit/components-react/dist/hooks-C2Bp5v2q.mjs
15371
16004
  import * as r from "react";
@@ -17181,8 +17814,8 @@ var Xt = /* @__PURE__ */ e.forwardRef(
17181
17814
 
17182
17815
  // src/components/voice-intensity-visualizer.tsx
17183
17816
  var VoiceIntensityWithRoom = (props) => {
17184
- const [room, setRoom] = useState9(null);
17185
- useEffect8(() => {
17817
+ const [room, setRoom] = useState10(null);
17818
+ useEffect10(() => {
17186
17819
  if (props.isActive) {
17187
17820
  const currentRoom = getRoom();
17188
17821
  if (currentRoom) {
@@ -17195,7 +17828,7 @@ var VoiceIntensityWithRoom = (props) => {
17195
17828
  if (!room) {
17196
17829
  return null;
17197
17830
  }
17198
- return /* @__PURE__ */ React10.createElement(Wn.Provider, { value: room }, /* @__PURE__ */ React10.createElement(VoiceIntensityBars, { ...props }));
17831
+ return /* @__PURE__ */ React12.createElement(Wn.Provider, { value: room }, /* @__PURE__ */ React12.createElement(VoiceIntensityBars, { ...props }));
17199
17832
  };
17200
17833
  var VoiceIntensityBars = ({
17201
17834
  isActive,
@@ -17238,7 +17871,7 @@ var VoiceIntensityBars = ({
17238
17871
  if (!trackRef) {
17239
17872
  return null;
17240
17873
  }
17241
- return /* @__PURE__ */ React10.createElement(
17874
+ return /* @__PURE__ */ React12.createElement(
17242
17875
  "div",
17243
17876
  {
17244
17877
  className: `voice-intensity-visualizer ${className}`,
@@ -17255,7 +17888,7 @@ var VoiceIntensityBars = ({
17255
17888
  pointerEvents: "none"
17256
17889
  }
17257
17890
  },
17258
- /* @__PURE__ */ React10.createElement(
17891
+ /* @__PURE__ */ React12.createElement(
17259
17892
  Xt,
17260
17893
  {
17261
17894
  barCount,
@@ -17269,19 +17902,151 @@ var VoiceIntensityBars = ({
17269
17902
  gap: "0.25rem"
17270
17903
  }
17271
17904
  },
17272
- /* @__PURE__ */ React10.createElement("span", { className: "cuekit-voice-intensity-bar" })
17905
+ /* @__PURE__ */ React12.createElement("span", { className: "cuekit-voice-intensity-bar" })
17273
17906
  )
17274
17907
  );
17275
17908
  };
17276
17909
  var VoiceIntensityVisualizer = VoiceIntensityWithRoom;
17277
17910
 
17911
+ // src/components/language-selector.tsx
17912
+ import React14, { useState as useState11, useRef as useRef9, useEffect as useEffect11 } from "react";
17913
+
17914
+ // src/components/svgs/chevron-down.tsx
17915
+ import React13 from "react";
17916
+ function ChevronDownIcon({
17917
+ width = 24,
17918
+ height = 24,
17919
+ className,
17920
+ ...props
17921
+ }) {
17922
+ return /* @__PURE__ */ React13.createElement(
17923
+ "svg",
17924
+ {
17925
+ xmlns: "http://www.w3.org/2000/svg",
17926
+ width,
17927
+ height,
17928
+ viewBox: "0 0 24 24",
17929
+ fill: "none",
17930
+ stroke: "currentColor",
17931
+ "stroke-width": "2",
17932
+ "stroke-linecap": "round",
17933
+ "stroke-linejoin": "round",
17934
+ className,
17935
+ ...props
17936
+ },
17937
+ /* @__PURE__ */ React13.createElement("path", { d: "m6 9 6 6 6-6" })
17938
+ );
17939
+ }
17940
+
17941
+ // src/components/language-selector.tsx
17942
+ var FLAG_EMOJIS = {
17943
+ "en-US": "\u{1F1FA}\u{1F1F8}",
17944
+ "ar-SA": "\u{1F1F8}\u{1F1E6}",
17945
+ "es-ES": "\u{1F1EA}\u{1F1F8}",
17946
+ "fr-FR": "\u{1F1EB}\u{1F1F7}",
17947
+ "de-DE": "\u{1F1E9}\u{1F1EA}",
17948
+ "it-IT": "\u{1F1EE}\u{1F1F9}",
17949
+ "pt-BR": "\u{1F1E7}\u{1F1F7}",
17950
+ "ja-JP": "\u{1F1EF}\u{1F1F5}",
17951
+ "ko-KR": "\u{1F1F0}\u{1F1F7}",
17952
+ "zh-CN": "\u{1F1E8}\u{1F1F3}",
17953
+ "hi-IN": "\u{1F1EE}\u{1F1F3}"
17954
+ };
17955
+ var LanguageSelector = ({
17956
+ selectedLanguage,
17957
+ onLanguageChange,
17958
+ availableLanguages,
17959
+ disabled = false,
17960
+ className = "",
17961
+ tooltip,
17962
+ screenPosition = "bottom-center"
17963
+ }) => {
17964
+ const [isOpen, setIsOpen] = useState11(false);
17965
+ const [showTooltip, setShowTooltip] = useState11(false);
17966
+ const [dropdownUp, setDropdownUp] = useState11(false);
17967
+ const dropdownRef = useRef9(null);
17968
+ useEffect11(() => {
17969
+ const handleClickOutside = (event) => {
17970
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
17971
+ setIsOpen(false);
17972
+ }
17973
+ };
17974
+ document.addEventListener("mousedown", handleClickOutside);
17975
+ return () => {
17976
+ document.removeEventListener("mousedown", handleClickOutside);
17977
+ };
17978
+ }, []);
17979
+ const handleLanguageSelect = (language) => {
17980
+ if (disabled) return;
17981
+ onLanguageChange(language);
17982
+ setIsOpen(false);
17983
+ };
17984
+ const handleButtonClick = () => {
17985
+ if (disabled) return;
17986
+ const isBottomPosition = screenPosition.startsWith("bottom");
17987
+ setDropdownUp(isBottomPosition);
17988
+ setIsOpen(!isOpen);
17989
+ };
17990
+ const getFlagEmoji = (code4) => {
17991
+ return FLAG_EMOJIS[code4] || "\u{1F310}";
17992
+ };
17993
+ return /* @__PURE__ */ React14.createElement(
17994
+ "div",
17995
+ {
17996
+ className: `language-selector-container ${className}`,
17997
+ ref: dropdownRef,
17998
+ onMouseEnter: () => {
17999
+ if (disabled) {
18000
+ setShowTooltip(true);
18001
+ }
18002
+ },
18003
+ onMouseLeave: () => {
18004
+ setShowTooltip(false);
18005
+ }
18006
+ },
18007
+ /* @__PURE__ */ React14.createElement(
18008
+ "button",
18009
+ {
18010
+ className: `language-selector-button ${isOpen ? "open" : ""} ${disabled ? "disabled" : ""}`,
18011
+ onClick: handleButtonClick,
18012
+ disabled,
18013
+ "aria-label": disabled ? tooltip || "Language cannot be changed during conversation" : "Select language",
18014
+ "aria-expanded": isOpen,
18015
+ "aria-haspopup": "listbox"
18016
+ },
18017
+ /* @__PURE__ */ React14.createElement("div", { className: "language-selector-content" }, /* @__PURE__ */ React14.createElement("span", { className: "language-flag" }, getFlagEmoji(selectedLanguage.code)), /* @__PURE__ */ React14.createElement("span", { className: "language-code" }, selectedLanguage.code), /* @__PURE__ */ React14.createElement(
18018
+ ChevronDownIcon,
18019
+ {
18020
+ className: `language-chevron ${isOpen ? dropdownUp ? "rotated-up" : "rotated" : ""}`,
18021
+ width: 14,
18022
+ height: 14
18023
+ }
18024
+ ))
18025
+ ),
18026
+ disabled && /* @__PURE__ */ React14.createElement("div", { className: `language-tooltip ${showTooltip ? "show" : ""}` }, /* @__PURE__ */ React14.createElement("div", { className: "language-tooltip-content" }, tooltip || "Close the conversation to change the language"), /* @__PURE__ */ React14.createElement("div", { className: "language-tooltip-arrow" })),
18027
+ isOpen && /* @__PURE__ */ React14.createElement("div", { className: `language-dropdown ${dropdownUp ? "dropdown-up" : ""}` }, /* @__PURE__ */ React14.createElement("div", { className: "language-dropdown-content" }, availableLanguages.map((language) => /* @__PURE__ */ React14.createElement(
18028
+ "button",
18029
+ {
18030
+ key: language.code,
18031
+ className: `language-option ${selectedLanguage.code === language.code ? "selected" : ""}`,
18032
+ onClick: () => handleLanguageSelect(language),
18033
+ role: "option",
18034
+ "aria-selected": selectedLanguage.code === language.code
18035
+ },
18036
+ /* @__PURE__ */ React14.createElement("span", { className: "language-flag" }, getFlagEmoji(language.code)),
18037
+ /* @__PURE__ */ React14.createElement("div", { className: "language-info" }, /* @__PURE__ */ React14.createElement("span", { className: "language-name" }, language.name)),
18038
+ selectedLanguage.code === language.code && /* @__PURE__ */ React14.createElement("div", { className: "language-check" }, "\u2713")
18039
+ ))))
18040
+ );
18041
+ };
18042
+
17278
18043
  // src/components/mic-button.tsx
17279
18044
  var chatState = {
17280
18045
  isOpen: false,
17281
18046
  isMinimized: false
17282
18047
  };
17283
18048
  var VoiceIntensityWrapper = ({ active, buttonSize }) => {
17284
- return /* @__PURE__ */ React11.createElement(
18049
+ return /* @__PURE__ */ React15.createElement(
17285
18050
  VoiceIntensityVisualizer,
17286
18051
  {
17287
18052
  isActive: active,
@@ -17291,6 +18056,10 @@ var VoiceIntensityWrapper = ({ active, buttonSize }) => {
17291
18056
  }
17292
18057
  );
17293
18058
  };
18059
+ var DEFAULT_LANGUAGES = [
18060
+ { code: "en-US", name: "English (US)", flag: "\u{1F1FA}\u{1F1F8}" },
18061
+ { code: "ar-SA", name: "\u0627\u0644\u0639\u0631\u0628\u064A\u0629", flag: "\u{1F1F8}\u{1F1E6}" }
18062
+ ];
17294
18063
  var MicButton = ({
17295
18064
  buttonSize = 52,
17296
18065
  screenPosition = "bottom-center",
@@ -17302,22 +18071,29 @@ var MicButton = ({
17302
18071
  buttonStyle,
17303
18072
  bottomSpace = 20,
17304
18073
  defaultTheme = "system",
17305
- showBorderGlow = false
18074
+ showBorderGlow = false,
18075
+ language,
18076
+ defaultLanguage,
18077
+ onLanguageChange
17306
18078
  }) => {
17307
- const { apiKey, appId } = useQubeContext();
17308
- const [showBodyGlow, setShowBodyGlow] = useState10(false);
17309
- const [currentTheme, setCurrentTheme] = useState10("dark");
17310
- const [isChatOpen, setIsChatOpen] = useState10(chatState.isOpen);
17311
- const [isChatMinimized, setIsChatMinimized] = useState10(chatState.isMinimized);
17312
- useEffect9(() => {
18079
+ const { apiKey, appId } = useAnsyrContext();
18080
+ const [showBodyGlow, setShowBodyGlow] = useState12(false);
18081
+ const [currentTheme, setCurrentTheme] = useState12("dark");
18082
+ const [showLanguageSelector, setShowLanguageSelector] = useState12(false);
18083
+ const [selectedLanguage, setSelectedLanguage] = useState12(
18084
+ language || defaultLanguage || DEFAULT_LANGUAGES[0]
18085
+ );
18086
+ const [isChatOpen, setIsChatOpen] = useState12(chatState.isOpen);
18087
+ const [isChatMinimized, setIsChatMinimized] = useState12(chatState.isMinimized);
18088
+ useEffect12(() => {
17313
18089
  chatState.isOpen = isChatOpen;
17314
18090
  chatState.isMinimized = isChatMinimized;
17315
18091
  }, [isChatOpen, isChatMinimized]);
17316
- const audioContainerRef = useRef7(null);
17317
- const silenceTimerRef = useRef7(null);
17318
- const aiSpeakingRef = useRef7(false);
17319
- const aiSpeechTimeoutRef = useRef7(null);
17320
- const activeAITracksRef = useRef7(/* @__PURE__ */ new Set());
18092
+ const audioContainerRef = useRef10(null);
18093
+ const silenceTimerRef = useRef10(null);
18094
+ const aiSpeakingRef = useRef10(false);
18095
+ const aiSpeechTimeoutRef = useRef10(null);
18096
+ const activeAITracksRef = useRef10(/* @__PURE__ */ new Set());
17321
18097
  const {
17322
18098
  isConnected,
17323
18099
  isConnecting,
@@ -17347,7 +18123,7 @@ var MicButton = ({
17347
18123
  onAISpeechEnd: (trackId) => handleAISpeech(false, trackId),
17348
18124
  appId
17349
18125
  });
17350
- useEffect9(() => {
18126
+ useEffect12(() => {
17351
18127
  const checkTheme = () => {
17352
18128
  if (typeof document !== "undefined") {
17353
18129
  let newTheme;
@@ -17370,31 +18146,31 @@ var MicButton = ({
17370
18146
  return () => observer.disconnect();
17371
18147
  }
17372
18148
  }, [defaultTheme]);
17373
- const openChat = useCallback5(() => {
18149
+ const openChat = useCallback6(() => {
17374
18150
  setIsChatOpen(true);
17375
18151
  setIsChatMinimized(false);
17376
18152
  }, []);
17377
- const minimizeChat = useCallback5(() => {
18153
+ const minimizeChat = useCallback6(() => {
17378
18154
  setIsChatMinimized(true);
17379
18155
  if (showBorderGlow) {
17380
18156
  setShowBodyGlow(false);
17381
18157
  }
17382
18158
  }, [showBorderGlow]);
17383
- const restoreChat = useCallback5(() => {
18159
+ const restoreChat = useCallback6(() => {
17384
18160
  setIsChatMinimized(false);
17385
18161
  setIsChatOpen(true);
17386
18162
  if (showBorderGlow && (micState === "listening" || micState === "thinking" || micState === "replying")) {
17387
18163
  setShowBodyGlow(true);
17388
18164
  }
17389
18165
  }, [showBorderGlow, micState]);
17390
- const closeChat = useCallback5(() => {
18166
+ const closeChat = useCallback6(() => {
17391
18167
  setIsChatOpen(false);
17392
18168
  setIsChatMinimized(false);
17393
18169
  if (showBorderGlow) {
17394
18170
  setShowBodyGlow(false);
17395
18171
  }
17396
18172
  }, [showBorderGlow]);
17397
- const handleAISpeech = useCallback5(
18173
+ const handleAISpeech = useCallback6(
17398
18174
  (isSpeaking, trackId) => {
17399
18175
  if (isSpeaking && trackId) {
17400
18176
  activeAITracksRef.current.add(trackId);
@@ -17415,7 +18191,7 @@ var MicButton = ({
17415
18191
  },
17416
18192
  [status, micState, isConnected]
17417
18193
  );
17418
- useEffect9(() => {
18194
+ useEffect12(() => {
17419
18195
  if (audioContainerRef.current) {
17420
18196
  setAudioContainer(audioContainerRef);
17421
18197
  }
@@ -17442,29 +18218,51 @@ var MicButton = ({
17442
18218
  }
17443
18219
  return isConnected2 ? "Ready" : "Connecting...";
17444
18220
  };
17445
- useEffect9(() => {
18221
+ useEffect12(() => {
17446
18222
  if (isConnected) {
17447
18223
  } else {
17448
18224
  }
17449
18225
  }, [isConnected]);
17450
- useEffect9(() => {
18226
+ useEffect12(() => {
17451
18227
  if (isConnected && !isChatOpen) {
17452
18228
  openChat();
17453
18229
  }
17454
18230
  }, [isConnected, isChatOpen, openChat]);
17455
- useEffect9(() => {
18231
+ useEffect12(() => {
17456
18232
  if (messageManagerMessages.length > 0 && !isChatOpen) {
17457
18233
  openChat();
17458
18234
  }
17459
18235
  }, [messageManagerMessages.length, isChatOpen, openChat]);
17460
- const handleMicClick = useCallback5(() => {
18236
+ const handleLanguageChange = useCallback6(
18237
+ (newLanguage) => {
18238
+ setSelectedLanguage(newLanguage);
18239
+ onLanguageChange?.(newLanguage);
18240
+ },
18241
+ [onLanguageChange]
18242
+ );
18243
+ const handleLanguageConfirm = useCallback6(() => {
18244
+ setShowLanguageSelector(false);
18245
+ voiceConnect(`user_${Date.now()}`, apiKey, appId, selectedLanguage).then(() => {
18246
+ if (showBorderGlow) setShowBodyGlow(true);
18247
+ openChat();
18248
+ setTimeout(() => {
18249
+ openChat();
18250
+ }, 500);
18251
+ }).catch((error) => {
18252
+ });
18253
+ }, [voiceConnect, apiKey, appId, selectedLanguage, showBorderGlow, openChat]);
18254
+ const handleMicClick = useCallback6(() => {
17461
18255
  const shouldStop = micState === "listening" && isConnected;
17462
18256
  if (shouldStop) {
17463
18257
  voiceDisconnect().then(() => {
17464
18258
  }).catch((error) => {
17465
18259
  });
17466
18260
  } else {
17467
- voiceConnect(`user_${Date.now()}`, apiKey, appId).then(() => {
18261
+ if (!language && !defaultLanguage && !selectedLanguage) {
18262
+ setShowLanguageSelector(true);
18263
+ return;
18264
+ }
18265
+ voiceConnect(`user_${Date.now()}`, apiKey, appId, selectedLanguage).then(() => {
17468
18266
  if (showBorderGlow) setShowBodyGlow(true);
17469
18267
  openChat();
17470
18268
  setTimeout(() => {
@@ -17480,6 +18278,8 @@ var MicButton = ({
17480
18278
  voiceConnect,
17481
18279
  apiKey,
17482
18280
  appId,
18281
+ language,
18282
+ selectedLanguage,
17483
18283
  openChat,
17484
18284
  showBorderGlow,
17485
18285
  sendChatMessage,
@@ -17528,9 +18328,9 @@ var MicButton = ({
17528
18328
  ...imageStyle
17529
18329
  };
17530
18330
  if (micState === "idle") {
17531
- return /* @__PURE__ */ React11.createElement("img", { src: imageSource, alt: "Voice Assistant", style: baseImageStyle });
18331
+ return /* @__PURE__ */ React15.createElement("img", { src: imageSource, alt: "Voice Assistant", style: baseImageStyle });
17532
18332
  } else {
17533
- return /* @__PURE__ */ React11.createElement(VoiceIntensityWrapper, { active: true, buttonSize });
18333
+ return /* @__PURE__ */ React15.createElement(VoiceIntensityWrapper, { active: true, buttonSize });
17534
18334
  }
17535
18335
  }
17536
18336
  const iconStyle = {
@@ -17540,9 +18340,9 @@ var MicButton = ({
17540
18340
  filter: "drop-shadow(0 10px 8px rgba(0, 0, 0, 0.04)) drop-shadow(0 4px 3px rgba(0, 0, 0, 0.1))"
17541
18341
  };
17542
18342
  if (micState === "idle") {
17543
- return /* @__PURE__ */ React11.createElement(mic_default, { style: iconStyle });
18343
+ return /* @__PURE__ */ React15.createElement(mic_default, { style: iconStyle });
17544
18344
  } else {
17545
- return /* @__PURE__ */ React11.createElement(VoiceIntensityWrapper, { active: true, buttonSize });
18345
+ return /* @__PURE__ */ React15.createElement(VoiceIntensityWrapper, { active: true, buttonSize });
17546
18346
  }
17547
18347
  };
17548
18348
  const getPositionStyle = () => {
@@ -17604,15 +18404,15 @@ var MicButton = ({
17604
18404
  const baseStyle = { ...buttonStyles.button };
17605
18405
  switch (micState) {
17606
18406
  case "listening":
17607
- baseStyle.transform = "scale(1.1)";
18407
+ baseStyle.transform = "scale(1.05)";
17608
18408
  baseStyle.boxShadow = "0 25px 50px -12px rgba(59, 130, 246, 0.6)";
17609
18409
  break;
17610
18410
  case "thinking":
17611
- baseStyle.transform = "scale(1.05)";
18411
+ baseStyle.transform = "scale(1.02)";
17612
18412
  baseStyle.boxShadow = "0 20px 25px -5px rgba(196, 132, 252, 0.4)";
17613
18413
  break;
17614
18414
  case "replying":
17615
- baseStyle.transform = "scale(1.05)";
18415
+ baseStyle.transform = "scale(1.02)";
17616
18416
  baseStyle.boxShadow = "0 20px 25px -5px rgba(34, 211, 238, 0.4)";
17617
18417
  break;
17618
18418
  default:
@@ -17621,7 +18421,34 @@ var MicButton = ({
17621
18421
  }
17622
18422
  return baseStyle;
17623
18423
  };
17624
- return /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement("div", { "data-cuekit-ignore": true, style: { ...buttonStyles.container, ...getPositionStyle() } }, /* @__PURE__ */ React11.createElement("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: "8px" } }, /* @__PURE__ */ React11.createElement(
18424
+ return /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement("div", { "data-cuekit-ignore": true, style: { ...buttonStyles.container, ...getPositionStyle() } }, showLanguageSelector ? /* @__PURE__ */ React15.createElement("div", { className: "voice-chat-language-selection" }, /* @__PURE__ */ React15.createElement("div", { className: "voice-chat-language-header" }, /* @__PURE__ */ React15.createElement("div", { className: "voice-chat-language-icon" }, /* @__PURE__ */ React15.createElement(mic_default, { width: 20, height: 20 })), /* @__PURE__ */ React15.createElement("span", { className: "voice-chat-language-title" }, "Select Language")), /* @__PURE__ */ React15.createElement(
18425
+ LanguageSelector,
18426
+ {
18427
+ selectedLanguage,
18428
+ onLanguageChange: handleLanguageChange,
18429
+ availableLanguages: DEFAULT_LANGUAGES,
18430
+ className: "voice-chat-language-selector",
18431
+ screenPosition
18432
+ }
18433
+ ), /* @__PURE__ */ React15.createElement("div", { className: "voice-chat-language-actions" }, /* @__PURE__ */ React15.createElement(
18434
+ "button",
18435
+ {
18436
+ className: "voice-chat-cancel-button",
18437
+ onClick: () => setShowLanguageSelector(false)
18438
+ },
18439
+ "Cancel"
18440
+ ), /* @__PURE__ */ React15.createElement("button", { className: "voice-chat-confirm-button", onClick: handleLanguageConfirm }, "Start Voice Chat"))) : /* @__PURE__ */ React15.createElement("div", { className: "voice-chat-main-button" }, /* @__PURE__ */ React15.createElement(
18441
+ LanguageSelector,
18442
+ {
18443
+ selectedLanguage,
18444
+ onLanguageChange: handleLanguageChange,
18445
+ availableLanguages: DEFAULT_LANGUAGES,
18446
+ className: "voice-chat-language-preview",
18447
+ disabled: isConnected || micState !== "idle",
18448
+ tooltip: "Close the conversation to change the language",
18449
+ screenPosition
18450
+ }
18451
+ ), /* @__PURE__ */ React15.createElement(
17625
18452
  "button",
17626
18453
  {
17627
18454
  "data-testid": "ignore",
@@ -17642,8 +18469,8 @@ var MicButton = ({
17642
18469
  },
17643
18470
  "aria-label": micState === "thinking" ? "Processing..." : micState === "replying" ? "AI is responding..." : isListening ? "Stop listening" : "Start listening"
17644
18471
  },
17645
- /* @__PURE__ */ React11.createElement("div", { style: buttonStyles.iconContainer }, getIcon())
17646
- ), hasText && text7 && /* @__PURE__ */ React11.createElement(
18472
+ /* @__PURE__ */ React15.createElement("div", { style: buttonStyles.iconContainer }, getIcon())
18473
+ )), !showLanguageSelector && hasText && text7 && /* @__PURE__ */ React15.createElement(
17647
18474
  "div",
17648
18475
  {
17649
18476
  style: {
@@ -17661,11 +18488,12 @@ var MicButton = ({
17661
18488
  alignItems: "center",
17662
18489
  justifyContent: "center",
17663
18490
  gap: "4px",
18491
+ marginTop: "8px",
17664
18492
  ...textStyle
17665
18493
  }
17666
18494
  },
17667
- /* @__PURE__ */ React11.createElement("span", null, text7)
17668
- ))), /* @__PURE__ */ React11.createElement(
18495
+ /* @__PURE__ */ React15.createElement("span", null, text7)
18496
+ )), /* @__PURE__ */ React15.createElement(
17669
18497
  ChatPopup,
17670
18498
  {
17671
18499
  isOpen: isChatOpen,
@@ -17688,9 +18516,14 @@ var MicButton = ({
17688
18516
  status: getUserFriendlyStatus(micState, isConnected ?? false),
17689
18517
  anchor: { position: screenPosition, bottom: bottomSpace, size: buttonSize },
17690
18518
  muteState,
17691
- onToggleMute: toggleMute
17692
- }
17693
- ), isChatOpen && isChatMinimized && /* @__PURE__ */ React11.createElement(
18519
+ onToggleMute: toggleMute,
18520
+ draggable: true,
18521
+ resizable: true,
18522
+ persistPosition: true,
18523
+ persistSize: true,
18524
+ storageKey: "cuekit-chat-popup"
18525
+ }
18526
+ ), isChatOpen && isChatMinimized && /* @__PURE__ */ React15.createElement(
17694
18527
  "button",
17695
18528
  {
17696
18529
  onClick: restoreChat,
@@ -17711,8 +18544,8 @@ var MicButton = ({
17711
18544
  className: `cuekit-voice-popup ${currentTheme === "dark" ? "cuekit-dark" : ""}`,
17712
18545
  "aria-label": "Open chat"
17713
18546
  },
17714
- /* @__PURE__ */ React11.createElement("span", { style: { fontSize: 12, fontWeight: 600, color: "hsl(var(--voice-text))" } }, "Open chat")
17715
- ), /* @__PURE__ */ React11.createElement("div", { ref: audioContainerRef, style: { display: "none" } }), showBorderGlow && showBodyGlow && /* @__PURE__ */ React11.createElement(border_glow_default, { isActive: true }));
18547
+ /* @__PURE__ */ React15.createElement("span", { style: { fontSize: 12, fontWeight: 600, color: "hsl(var(--voice-text))" } }, "Open chat")
18548
+ ), /* @__PURE__ */ React15.createElement("div", { ref: audioContainerRef, style: { display: "none" } }), showBorderGlow && showBodyGlow && /* @__PURE__ */ React15.createElement(border_glow_default, { isActive: true }));
17716
18549
  };
17717
18550
 
17718
18551
  // src/utils/instrumentation.ts
@@ -17723,11 +18556,15 @@ function generateDynamicId(routePath, elementIdentifier) {
17723
18556
  return hash.substring(0, 8);
17724
18557
  }
17725
18558
  export {
18559
+ AnsyrProvider,
17726
18560
  border_glow_default as BorderGlow,
17727
18561
  ChatPopup,
17728
- CuekitProvider,
18562
+ DraggableResizableContainer,
17729
18563
  InitCuekit,
18564
+ LanguageSelector,
17730
18565
  MicButton,
18566
+ ResizeHandle,
18567
+ ResizeHandles,
17731
18568
  VoiceIntensityVisualizer,
17732
18569
  captureAllInteractiveElements,
17733
18570
  clearElementCache,
@@ -17739,8 +18576,9 @@ export {
17739
18576
  initWebRTC,
17740
18577
  initWebRTCWithDeployedBackend,
17741
18578
  resolveRoutePath,
18579
+ useAnsyrContext,
17742
18580
  useCuekit,
17743
- useQubeContext,
18581
+ useDraggableResizableContainer,
17744
18582
  useWebRTC,
17745
18583
  validateDynamicElements
17746
18584
  };