@realtimexsco/live-chat 1.5.4 → 1.5.6
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/firebase-messaging-sw.js +37 -32
- package/dist/index.cjs +991 -570
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +993 -572
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/PERMISSIONS.md +0 -445
package/dist/index.cjs
CHANGED
|
@@ -912,12 +912,13 @@ var init_store_helpers = __esm({
|
|
|
912
912
|
});
|
|
913
913
|
|
|
914
914
|
// src/notifications/open-conversation.ts
|
|
915
|
-
exports.OPEN_CONVERSATION_EVENT = void 0; exports.NOTIFICATION_CLICK_SW_TYPE = void 0; exports.PUSH_BROADCAST_CHANNEL = void 0; exports.PUSH_DATA_CACHE_NAME = void 0; var PENDING_STORAGE_KEY, PENDING_OPEN_CACHE_PATH; exports.resolveConversationIdFromPushData = void 0; var normalizePushMeta, parsePendingRaw; exports.peekPendingOpenConversation = void 0; exports.peekPendingOpenRequest = void 0; exports.consumePendingOpenConversation = void 0; exports.consumePendingOpenRequest = void 0; exports.requestOpenConversation = void 0; exports.buildChannelFromPushRequest = void 0; var mapConversationToChannel, stripConversationIdFromUrl, cacheRequestForPath; exports.consumePendingOpenFromPushCache = void 0; var readConversationIdFromLocation, consumedUrlConversationIds, lastHandledOpenId, lastHandledOpenAt, shouldHandleOpen, handleNotificationOpen; exports.installNotificationClickBridge = void 0;
|
|
915
|
+
exports.OPEN_CONVERSATION_EVENT = void 0; exports.NOTIFICATION_CLICK_SW_TYPE = void 0; var CHAT_HEARTBEAT_SW_TYPE; exports.PUSH_BROADCAST_CHANNEL = void 0; exports.PUSH_DATA_CACHE_NAME = void 0; var PENDING_STORAGE_KEY, PENDING_OPEN_CACHE_PATH; exports.resolveConversationIdFromPushData = void 0; var normalizePushMeta, parsePendingRaw; exports.peekPendingOpenConversation = void 0; exports.peekPendingOpenRequest = void 0; exports.consumePendingOpenConversation = void 0; exports.consumePendingOpenRequest = void 0; exports.requestOpenConversation = void 0; exports.buildChannelFromPushRequest = void 0; var mapConversationToChannel, stripConversationIdFromUrl, cacheRequestForPath; exports.consumePendingOpenFromPushCache = void 0; var readConversationIdFromLocation, consumedUrlConversationIds, lastHandledOpenId, lastHandledOpenAt, shouldHandleOpen, handleNotificationOpen; exports.installNotificationClickBridge = void 0;
|
|
916
916
|
var init_open_conversation = __esm({
|
|
917
917
|
"src/notifications/open-conversation.ts"() {
|
|
918
918
|
init_store_helpers();
|
|
919
919
|
exports.OPEN_CONVERSATION_EVENT = "realtimex:open-conversation";
|
|
920
920
|
exports.NOTIFICATION_CLICK_SW_TYPE = "realtimex:notification-click";
|
|
921
|
+
CHAT_HEARTBEAT_SW_TYPE = "realtimex:chat-heartbeat";
|
|
921
922
|
exports.PUSH_BROADCAST_CHANNEL = "realtimex-push";
|
|
922
923
|
exports.PUSH_DATA_CACHE_NAME = "realtimex-push-data-v1";
|
|
923
924
|
PENDING_STORAGE_KEY = "realtimex:pending-open-conversation";
|
|
@@ -4639,6 +4640,67 @@ var init_utils2 = __esm({
|
|
|
4639
4640
|
"src/lib/utils.ts"() {
|
|
4640
4641
|
}
|
|
4641
4642
|
});
|
|
4643
|
+
function TooltipProvider({
|
|
4644
|
+
delayDuration = 0,
|
|
4645
|
+
...props
|
|
4646
|
+
}) {
|
|
4647
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4648
|
+
radixUi.Tooltip.Provider,
|
|
4649
|
+
{
|
|
4650
|
+
"data-slot": "tooltip-provider",
|
|
4651
|
+
delayDuration,
|
|
4652
|
+
...props
|
|
4653
|
+
}
|
|
4654
|
+
);
|
|
4655
|
+
}
|
|
4656
|
+
function Tooltip({
|
|
4657
|
+
...props
|
|
4658
|
+
}) {
|
|
4659
|
+
return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Tooltip.Root, { "data-slot": "tooltip", ...props });
|
|
4660
|
+
}
|
|
4661
|
+
function TooltipTrigger({
|
|
4662
|
+
...props
|
|
4663
|
+
}) {
|
|
4664
|
+
return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Tooltip.Trigger, { "data-slot": "tooltip-trigger", ...props });
|
|
4665
|
+
}
|
|
4666
|
+
function TooltipContent({
|
|
4667
|
+
className,
|
|
4668
|
+
sideOffset = 0,
|
|
4669
|
+
children,
|
|
4670
|
+
showArrow = true,
|
|
4671
|
+
arrowClassName,
|
|
4672
|
+
...props
|
|
4673
|
+
}) {
|
|
4674
|
+
return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Tooltip.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4675
|
+
radixUi.Tooltip.Content,
|
|
4676
|
+
{
|
|
4677
|
+
"data-slot": "tooltip-content",
|
|
4678
|
+
sideOffset,
|
|
4679
|
+
className: cn(
|
|
4680
|
+
"bg-foreground text-background animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
|
|
4681
|
+
className
|
|
4682
|
+
),
|
|
4683
|
+
...props,
|
|
4684
|
+
children: [
|
|
4685
|
+
children,
|
|
4686
|
+
showArrow ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4687
|
+
radixUi.Tooltip.Arrow,
|
|
4688
|
+
{
|
|
4689
|
+
className: cn(
|
|
4690
|
+
"bg-foreground fill-foreground z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]",
|
|
4691
|
+
arrowClassName
|
|
4692
|
+
)
|
|
4693
|
+
}
|
|
4694
|
+
) : null
|
|
4695
|
+
]
|
|
4696
|
+
}
|
|
4697
|
+
) });
|
|
4698
|
+
}
|
|
4699
|
+
var init_tooltip = __esm({
|
|
4700
|
+
"src/ui/tooltip.tsx"() {
|
|
4701
|
+
init_utils2();
|
|
4702
|
+
}
|
|
4703
|
+
});
|
|
4642
4704
|
function Avatar({
|
|
4643
4705
|
className,
|
|
4644
4706
|
size = "default",
|
|
@@ -4778,9 +4840,8 @@ var init_ParticipantView = __esm({
|
|
|
4778
4840
|
isHandRaised = false,
|
|
4779
4841
|
className
|
|
4780
4842
|
}) => {
|
|
4781
|
-
const { webcamStream,
|
|
4843
|
+
const { webcamStream, webcamOn, micOn, displayName, isActiveSpeaker } = sdk.useParticipant(participantId);
|
|
4782
4844
|
const videoRef = React11.useRef(null);
|
|
4783
|
-
const audioRef = React11.useRef(null);
|
|
4784
4845
|
const [hasFrame, setHasFrame] = React11.useState(false);
|
|
4785
4846
|
React11.useEffect(() => {
|
|
4786
4847
|
const el = videoRef.current;
|
|
@@ -4793,17 +4854,6 @@ var init_ParticipantView = __esm({
|
|
|
4793
4854
|
setHasFrame(false);
|
|
4794
4855
|
}
|
|
4795
4856
|
}, [webcamOn, webcamStream]);
|
|
4796
|
-
React11.useEffect(() => {
|
|
4797
|
-
if (isLocal) return;
|
|
4798
|
-
const el = audioRef.current;
|
|
4799
|
-
if (!el) return;
|
|
4800
|
-
if (micOn && micStream?.track) {
|
|
4801
|
-
el.srcObject = new MediaStream([micStream.track]);
|
|
4802
|
-
el.play().catch(() => void 0);
|
|
4803
|
-
} else {
|
|
4804
|
-
el.srcObject = null;
|
|
4805
|
-
}
|
|
4806
|
-
}, [micOn, micStream, isLocal]);
|
|
4807
4857
|
const name = displayName || fallbackName || "Participant";
|
|
4808
4858
|
const showVideo = webcamOn && hasFrame;
|
|
4809
4859
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -4836,8 +4886,7 @@ var init_ParticipantView = __esm({
|
|
|
4836
4886
|
)
|
|
4837
4887
|
}
|
|
4838
4888
|
),
|
|
4839
|
-
|
|
4840
|
-
isHandRaised && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute top-2 left-2 flex size-7 items-center justify-center rounded-full bg-amber-400 text-neutral-900 shadow", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Hand, { size: 14 }) }),
|
|
4889
|
+
isHandRaised && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute top-2 left-2 flex size-7 items-center justify-center rounded-full bg-amber-400 text-neutral-900 shadow-lg shadow-amber-400/30 animate-[bounce_1s_ease-in-out_2]", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Hand, { size: 14 }) }),
|
|
4841
4890
|
!showVideo && /* @__PURE__ */ jsxRuntime.jsxs(Avatar, { size: "lg", className: "size-20", children: [
|
|
4842
4891
|
/* @__PURE__ */ jsxRuntime.jsx(AvatarImage, { src: fallbackImage, alt: name }),
|
|
4843
4892
|
/* @__PURE__ */ jsxRuntime.jsx(AvatarFallback, { className: "bg-neutral-700 text-xl font-medium text-white", children: name.charAt(0).toUpperCase() })
|
|
@@ -4894,7 +4943,7 @@ var init_AudioCallView = __esm({
|
|
|
4894
4943
|
}
|
|
4895
4944
|
),
|
|
4896
4945
|
isMuted && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -right-1 -bottom-1 flex size-9 items-center justify-center rounded-full bg-neutral-700 ring-4 ring-neutral-900", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MicOff, { size: 16, className: "text-white/80" }) }),
|
|
4897
|
-
isRemoteHandRaised && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -left-1 -top-1 flex size-9 items-center justify-center rounded-full bg-amber-400 text-neutral-900 ring-4 ring-neutral-900", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Hand, { size: 16 }) })
|
|
4946
|
+
isRemoteHandRaised && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -left-1 -top-1 flex size-9 items-center justify-center rounded-full bg-amber-400 text-neutral-900 shadow-lg shadow-amber-400/30 ring-4 ring-neutral-900 animate-[bounce_1s_ease-in-out_2]", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Hand, { size: 16 }) })
|
|
4898
4947
|
] }),
|
|
4899
4948
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xl font-semibold tracking-tight", children: name })
|
|
4900
4949
|
] });
|
|
@@ -4918,13 +4967,13 @@ var init_ScreenShareView = __esm({
|
|
|
4918
4967
|
el.srcObject = null;
|
|
4919
4968
|
}
|
|
4920
4969
|
}, [screenShareOn, screenShareStream]);
|
|
4921
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, children: [
|
|
4922
|
-
/* @__PURE__ */ jsxRuntime.
|
|
4923
|
-
|
|
4970
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex flex-1 items-center justify-center overflow-hidden rounded-2xl bg-black ring-1 ring-white/10 shadow-2xl", children: [
|
|
4971
|
+
/* @__PURE__ */ jsxRuntime.jsx("video", { ref: videoRef, playsInline: true, muted: isLocal, className: "max-h-full max-w-full object-contain" }),
|
|
4972
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute top-3 left-3 flex items-center gap-1.5 rounded-full bg-black/70 px-3 py-1.5 text-xs font-medium text-white shadow backdrop-blur-sm", children: [
|
|
4973
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.MonitorUp, { size: 13, className: "text-indigo-300" }),
|
|
4924
4974
|
isLocal ? "You are presenting" : `${displayName || "Someone"} is presenting`
|
|
4925
|
-
] })
|
|
4926
|
-
|
|
4927
|
-
] });
|
|
4975
|
+
] })
|
|
4976
|
+
] }) });
|
|
4928
4977
|
};
|
|
4929
4978
|
ScreenShareView_default = ScreenShareView;
|
|
4930
4979
|
}
|
|
@@ -4964,22 +5013,47 @@ var init_popover = __esm({
|
|
|
4964
5013
|
init_utils2();
|
|
4965
5014
|
}
|
|
4966
5015
|
});
|
|
4967
|
-
var circleBtn, idleBtnClass, activeBtnClass, QUICK_REACTIONS, CallControls, CallControls_default;
|
|
5016
|
+
var circleBtn, idleBtnClass, activeBtnClass, ControlButton, QUICK_REACTIONS, CallControls, CallControls_default;
|
|
4968
5017
|
var init_CallControls = __esm({
|
|
4969
5018
|
"src/call/CallControls.tsx"() {
|
|
4970
5019
|
init_button();
|
|
4971
5020
|
init_popover();
|
|
5021
|
+
init_tooltip();
|
|
4972
5022
|
init_utils2();
|
|
4973
5023
|
init_call_store();
|
|
4974
5024
|
circleBtn = "size-13 rounded-full text-white transition-all duration-150 disabled:opacity-40 hover:scale-105 active:scale-95";
|
|
4975
5025
|
idleBtnClass = "bg-white/10 hover:bg-white/20";
|
|
4976
5026
|
activeBtnClass = "bg-white text-neutral-900 hover:bg-white/90";
|
|
5027
|
+
ControlButton = ({
|
|
5028
|
+
icon,
|
|
5029
|
+
label,
|
|
5030
|
+
active,
|
|
5031
|
+
activeClassName = activeBtnClass,
|
|
5032
|
+
className,
|
|
5033
|
+
onClick
|
|
5034
|
+
}) => /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
|
|
5035
|
+
/* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5036
|
+
Button,
|
|
5037
|
+
{
|
|
5038
|
+
variant: "ghost",
|
|
5039
|
+
size: "icon",
|
|
5040
|
+
"aria-label": label,
|
|
5041
|
+
onClick,
|
|
5042
|
+
className: cn(circleBtn, active ? activeClassName : idleBtnClass, className),
|
|
5043
|
+
children: icon
|
|
5044
|
+
}
|
|
5045
|
+
) }),
|
|
5046
|
+
/* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", className: "z-[1000000]", children: label })
|
|
5047
|
+
] });
|
|
4977
5048
|
QUICK_REACTIONS = ["\u{1F44D}", "\u2764\uFE0F", "\u{1F602}", "\u{1F62E}", "\u{1F44F}", "\u{1F389}"];
|
|
4978
5049
|
CallControls = ({
|
|
4979
5050
|
sdk,
|
|
4980
5051
|
onReaction,
|
|
4981
5052
|
isHandRaised,
|
|
4982
|
-
onToggleRaiseHand
|
|
5053
|
+
onToggleRaiseHand,
|
|
5054
|
+
isChatOpen,
|
|
5055
|
+
onToggleChat,
|
|
5056
|
+
isVideoActive
|
|
4983
5057
|
}) => {
|
|
4984
5058
|
const {
|
|
4985
5059
|
toggleMic,
|
|
@@ -4988,81 +5062,124 @@ var init_CallControls = __esm({
|
|
|
4988
5062
|
localWebcamOn,
|
|
4989
5063
|
localScreenShareOn,
|
|
4990
5064
|
toggleScreenShare,
|
|
5065
|
+
recordingState,
|
|
5066
|
+
startRecording,
|
|
5067
|
+
stopRecording,
|
|
4991
5068
|
leave
|
|
4992
5069
|
} = sdk.useMeeting();
|
|
4993
5070
|
const endCall = exports.useCallStore((s) => s.endCall);
|
|
5071
|
+
const isRecording = recordingState === "RECORDING_STARTED" || recordingState === "RECORDING_STARTING";
|
|
5072
|
+
const isRecordingBusy = recordingState === "RECORDING_STARTING" || recordingState === "RECORDING_STOPPING";
|
|
5073
|
+
const handleToggleRecording = () => {
|
|
5074
|
+
if (isRecordingBusy) return;
|
|
5075
|
+
if (isRecording) {
|
|
5076
|
+
stopRecording();
|
|
5077
|
+
return;
|
|
5078
|
+
}
|
|
5079
|
+
startRecording("", "", {
|
|
5080
|
+
layout: { type: "GRID", priority: "SPEAKER", gridSize: 4 },
|
|
5081
|
+
orientation: "landscape",
|
|
5082
|
+
theme: "DEFAULT",
|
|
5083
|
+
mode: "video-and-audio",
|
|
5084
|
+
quality: "high"
|
|
5085
|
+
});
|
|
5086
|
+
};
|
|
4994
5087
|
const handleLeave = () => {
|
|
4995
5088
|
leave();
|
|
4996
5089
|
endCall();
|
|
4997
5090
|
};
|
|
4998
5091
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-5 py-6", children: [
|
|
4999
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-
|
|
5092
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 rounded-full bg-white/10 p-2 shadow-lg shadow-black/20 backdrop-blur-sm", children: [
|
|
5000
5093
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5001
|
-
|
|
5094
|
+
ControlButton,
|
|
5002
5095
|
{
|
|
5003
|
-
|
|
5004
|
-
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
|
|
5096
|
+
icon: localMicOn ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mic, { size: 20 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MicOff, { size: 20 }),
|
|
5097
|
+
label: localMicOn ? "Mute microphone" : "Unmute microphone",
|
|
5098
|
+
active: !localMicOn,
|
|
5099
|
+
onClick: () => toggleMic()
|
|
5100
|
+
}
|
|
5101
|
+
),
|
|
5102
|
+
isVideoActive ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
5103
|
+
ControlButton,
|
|
5104
|
+
{
|
|
5105
|
+
icon: localWebcamOn ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Video, { size: 20 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.VideoOff, { size: 20 }),
|
|
5106
|
+
label: localWebcamOn ? "Turn off camera" : "Turn on camera",
|
|
5107
|
+
active: !localWebcamOn,
|
|
5108
|
+
onClick: () => toggleWebcam()
|
|
5109
|
+
}
|
|
5110
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
5111
|
+
ControlButton,
|
|
5112
|
+
{
|
|
5113
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Video, { size: 20 }),
|
|
5114
|
+
label: "Switch to video call",
|
|
5115
|
+
onClick: () => toggleWebcam()
|
|
5009
5116
|
}
|
|
5010
5117
|
),
|
|
5118
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "mx-0.5 h-7 w-px shrink-0 bg-white/15" }),
|
|
5011
5119
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5012
|
-
|
|
5120
|
+
ControlButton,
|
|
5013
5121
|
{
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
onClick: () =>
|
|
5019
|
-
children: localWebcamOn ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Video, { size: 20 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.VideoOff, { size: 20 })
|
|
5122
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MonitorUp, { size: 20 }),
|
|
5123
|
+
label: localScreenShareOn ? "Stop sharing your screen" : "Share your screen",
|
|
5124
|
+
active: localScreenShareOn,
|
|
5125
|
+
activeClassName: "bg-indigo-500 hover:bg-indigo-400",
|
|
5126
|
+
onClick: () => toggleScreenShare()
|
|
5020
5127
|
}
|
|
5021
5128
|
),
|
|
5022
5129
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5023
|
-
|
|
5130
|
+
ControlButton,
|
|
5024
5131
|
{
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
onClick:
|
|
5030
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MonitorUp, { size: 20 })
|
|
5132
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Circle, { size: 14, className: cn("fill-current", isRecording && "animate-pulse") }),
|
|
5133
|
+
label: isRecording ? "Stop recording" : "Start recording",
|
|
5134
|
+
active: isRecording,
|
|
5135
|
+
activeClassName: "bg-red-600 hover:bg-red-500",
|
|
5136
|
+
onClick: handleToggleRecording
|
|
5031
5137
|
}
|
|
5032
5138
|
),
|
|
5033
5139
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5034
|
-
|
|
5140
|
+
ControlButton,
|
|
5035
5141
|
{
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
onClick: onToggleRaiseHand
|
|
5041
|
-
|
|
5142
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Hand, { size: 20, className: isHandRaised ? "animate-[bounce_1s_ease-in-out_2]" : void 0 }),
|
|
5143
|
+
label: isHandRaised ? "Lower hand" : "Raise hand",
|
|
5144
|
+
active: isHandRaised,
|
|
5145
|
+
activeClassName: "bg-amber-400 text-neutral-900 hover:bg-amber-300",
|
|
5146
|
+
onClick: onToggleRaiseHand
|
|
5147
|
+
}
|
|
5148
|
+
),
|
|
5149
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5150
|
+
ControlButton,
|
|
5151
|
+
{
|
|
5152
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageSquare, { size: 20 }),
|
|
5153
|
+
label: isChatOpen ? "Close in-call chat" : "Open in-call chat",
|
|
5154
|
+
active: isChatOpen,
|
|
5155
|
+
onClick: onToggleChat
|
|
5042
5156
|
}
|
|
5043
5157
|
),
|
|
5044
5158
|
/* @__PURE__ */ jsxRuntime.jsxs(Popover, { children: [
|
|
5045
|
-
/* @__PURE__ */ jsxRuntime.
|
|
5046
|
-
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5159
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
|
|
5160
|
+
/* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5161
|
+
Button,
|
|
5162
|
+
{
|
|
5163
|
+
variant: "ghost",
|
|
5164
|
+
size: "icon",
|
|
5165
|
+
className: cn(circleBtn, idleBtnClass),
|
|
5166
|
+
"aria-label": "Send a reaction",
|
|
5167
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Smile, { size: 20 })
|
|
5168
|
+
}
|
|
5169
|
+
) }) }),
|
|
5170
|
+
/* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", className: "z-[1000000]", children: "React" })
|
|
5171
|
+
] }),
|
|
5055
5172
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5056
5173
|
PopoverContent,
|
|
5057
5174
|
{
|
|
5058
5175
|
side: "top",
|
|
5059
5176
|
align: "center",
|
|
5060
|
-
className: "w-auto rounded-full border-white/10 bg-neutral-900 p-1.5 shadow-xl",
|
|
5177
|
+
className: "z-[1000000] w-auto rounded-full border-white/10 bg-neutral-900 p-1.5 shadow-xl",
|
|
5061
5178
|
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-0.5", children: QUICK_REACTIONS.map((emoji) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
5062
5179
|
"button",
|
|
5063
5180
|
{
|
|
5064
5181
|
type: "button",
|
|
5065
|
-
className: "flex size-10 items-center justify-center rounded-full text-xl transition-transform hover:scale-125 hover:bg-white/10",
|
|
5182
|
+
className: "flex size-10 items-center justify-center rounded-full text-xl transition-transform hover:scale-125 hover:bg-white/10 active:scale-95",
|
|
5066
5183
|
"aria-label": `React with ${emoji}`,
|
|
5067
5184
|
onClick: () => onReaction(emoji),
|
|
5068
5185
|
children: emoji
|
|
@@ -5073,17 +5190,20 @@ var init_CallControls = __esm({
|
|
|
5073
5190
|
)
|
|
5074
5191
|
] })
|
|
5075
5192
|
] }),
|
|
5076
|
-
/* @__PURE__ */ jsxRuntime.
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
5193
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
|
|
5194
|
+
/* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5195
|
+
Button,
|
|
5196
|
+
{
|
|
5197
|
+
variant: "ghost",
|
|
5198
|
+
size: "icon",
|
|
5199
|
+
className: cn(circleBtn, "bg-red-600 shadow-lg shadow-red-600/30 hover:bg-red-500"),
|
|
5200
|
+
"aria-label": "End call",
|
|
5201
|
+
onClick: handleLeave,
|
|
5202
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PhoneOff, { size: 22 })
|
|
5203
|
+
}
|
|
5204
|
+
) }),
|
|
5205
|
+
/* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", className: "z-[1000000]", children: "Leave call" })
|
|
5206
|
+
] })
|
|
5087
5207
|
] });
|
|
5088
5208
|
};
|
|
5089
5209
|
CallControls_default = CallControls;
|
|
@@ -5140,15 +5260,18 @@ var init_useCallReactions = __esm({
|
|
|
5140
5260
|
}, []);
|
|
5141
5261
|
const { send, localParticipant } = sdk.useMeeting({
|
|
5142
5262
|
onData: (data) => {
|
|
5263
|
+
console.log("[realtimex-call] data channel received:", data);
|
|
5143
5264
|
try {
|
|
5144
5265
|
const raw = typeof data.payload === "string" ? data.payload : new TextDecoder().decode(data.payload);
|
|
5145
5266
|
const message = JSON.parse(raw);
|
|
5267
|
+
console.log("[realtimex-call] data channel parsed:", message, "from", data.from);
|
|
5146
5268
|
if (message.type === "reaction") {
|
|
5147
5269
|
addFloatingReaction(message.emoji, data.from);
|
|
5148
5270
|
} else if (message.type === "raise-hand") {
|
|
5149
5271
|
setRaisedHands((prev) => ({ ...prev, [data.from]: message.raised }));
|
|
5150
5272
|
}
|
|
5151
|
-
} catch {
|
|
5273
|
+
} catch (err) {
|
|
5274
|
+
console.warn("[realtimex-call] data channel payload not decodable:", err, data);
|
|
5152
5275
|
}
|
|
5153
5276
|
}
|
|
5154
5277
|
});
|
|
@@ -5161,12 +5284,22 @@ var init_useCallReactions = __esm({
|
|
|
5161
5284
|
return next;
|
|
5162
5285
|
});
|
|
5163
5286
|
}, [localParticipant?.id]);
|
|
5287
|
+
const sendDataMessage = React11.useCallback(
|
|
5288
|
+
(message) => {
|
|
5289
|
+
send(JSON.stringify(message)).then((ok) => {
|
|
5290
|
+
console.log("[realtimex-call] data channel send result:", ok, message);
|
|
5291
|
+
}).catch((err) => {
|
|
5292
|
+
console.warn("[realtimex-call] data channel send failed:", err, message);
|
|
5293
|
+
});
|
|
5294
|
+
},
|
|
5295
|
+
[send]
|
|
5296
|
+
);
|
|
5164
5297
|
const sendReaction = React11.useCallback(
|
|
5165
5298
|
(emoji) => {
|
|
5166
5299
|
if (localParticipant?.id) addFloatingReaction(emoji, localParticipant.id);
|
|
5167
|
-
|
|
5300
|
+
sendDataMessage({ type: "reaction", emoji });
|
|
5168
5301
|
},
|
|
5169
|
-
[
|
|
5302
|
+
[localParticipant?.id, addFloatingReaction, sendDataMessage]
|
|
5170
5303
|
);
|
|
5171
5304
|
const toggleRaiseHand = React11.useCallback(() => {
|
|
5172
5305
|
setIsHandRaised((prev) => {
|
|
@@ -5174,15 +5307,15 @@ var init_useCallReactions = __esm({
|
|
|
5174
5307
|
if (localParticipant?.id) {
|
|
5175
5308
|
setRaisedHands((hands) => ({ ...hands, [localParticipant.id]: next }));
|
|
5176
5309
|
}
|
|
5177
|
-
|
|
5310
|
+
sendDataMessage({ type: "raise-hand", raised: next });
|
|
5178
5311
|
return next;
|
|
5179
5312
|
});
|
|
5180
|
-
}, [
|
|
5313
|
+
}, [localParticipant?.id, sendDataMessage]);
|
|
5181
5314
|
return { floatingReactions, raisedHands, isHandRaised, sendReaction, toggleRaiseHand };
|
|
5182
5315
|
};
|
|
5183
5316
|
}
|
|
5184
5317
|
});
|
|
5185
|
-
var MeetingView, MeetingView_default;
|
|
5318
|
+
var RemoteParticipantWatcher, MeetingView, MeetingView_default;
|
|
5186
5319
|
var init_MeetingView = __esm({
|
|
5187
5320
|
"src/call/MeetingView.tsx"() {
|
|
5188
5321
|
init_ParticipantView();
|
|
@@ -5193,11 +5326,48 @@ var init_MeetingView = __esm({
|
|
|
5193
5326
|
init_useCallReactions();
|
|
5194
5327
|
init_call_store();
|
|
5195
5328
|
init_utils2();
|
|
5196
|
-
|
|
5329
|
+
RemoteParticipantWatcher = ({
|
|
5330
|
+
sdk,
|
|
5331
|
+
participantId,
|
|
5332
|
+
onWebcamChange
|
|
5333
|
+
}) => {
|
|
5334
|
+
const { webcamOn, micStream, micOn } = sdk.useParticipant(participantId);
|
|
5335
|
+
const audioRef = React11.useRef(null);
|
|
5336
|
+
React11.useEffect(() => {
|
|
5337
|
+
onWebcamChange(participantId, webcamOn);
|
|
5338
|
+
return () => onWebcamChange(participantId, false);
|
|
5339
|
+
}, [participantId, webcamOn]);
|
|
5340
|
+
React11.useEffect(() => {
|
|
5341
|
+
const el = audioRef.current;
|
|
5342
|
+
if (!el) return;
|
|
5343
|
+
if (micOn && micStream?.track) {
|
|
5344
|
+
el.srcObject = new MediaStream([micStream.track]);
|
|
5345
|
+
el.play().catch(() => void 0);
|
|
5346
|
+
} else {
|
|
5347
|
+
el.srcObject = null;
|
|
5348
|
+
}
|
|
5349
|
+
}, [micOn, micStream]);
|
|
5350
|
+
return /* @__PURE__ */ jsxRuntime.jsx("audio", { ref: audioRef, autoPlay: true, playsInline: true });
|
|
5351
|
+
};
|
|
5352
|
+
MeetingView = ({
|
|
5353
|
+
sdk,
|
|
5354
|
+
mode,
|
|
5355
|
+
peerName,
|
|
5356
|
+
peerAvatar,
|
|
5357
|
+
isChatOpen,
|
|
5358
|
+
onToggleChat
|
|
5359
|
+
}) => {
|
|
5197
5360
|
const endCall = exports.useCallStore((s) => s.endCall);
|
|
5198
5361
|
const [hasJoined, setHasJoined] = React11.useState(false);
|
|
5199
5362
|
const hasJoinedRef = React11.useRef(false);
|
|
5200
5363
|
const [groupView, setGroupView] = React11.useState("grid");
|
|
5364
|
+
const [meetingState, setMeetingState] = React11.useState("CONNECTING");
|
|
5365
|
+
const [remoteWebcamOn, setRemoteWebcamOn] = React11.useState({});
|
|
5366
|
+
const handleRemoteWebcamChange = React11.useCallback((participantId, on) => {
|
|
5367
|
+
setRemoteWebcamOn(
|
|
5368
|
+
(prev) => prev[participantId] === on ? prev : { ...prev, [participantId]: on }
|
|
5369
|
+
);
|
|
5370
|
+
}, []);
|
|
5201
5371
|
const {
|
|
5202
5372
|
join,
|
|
5203
5373
|
participants,
|
|
@@ -5213,7 +5383,8 @@ var init_MeetingView = __esm({
|
|
|
5213
5383
|
onMeetingLeft: () => {
|
|
5214
5384
|
if (!hasJoinedRef.current) return;
|
|
5215
5385
|
endCall();
|
|
5216
|
-
}
|
|
5386
|
+
},
|
|
5387
|
+
onMeetingStateChanged: ({ state }) => setMeetingState(state)
|
|
5217
5388
|
});
|
|
5218
5389
|
const { floatingReactions, raisedHands, isHandRaised, sendReaction, toggleRaiseHand } = useCallReactions(sdk);
|
|
5219
5390
|
React11.useEffect(() => {
|
|
@@ -5229,149 +5400,58 @@ var init_MeetingView = __esm({
|
|
|
5229
5400
|
(id) => id !== localParticipant?.id
|
|
5230
5401
|
);
|
|
5231
5402
|
const isGroup = remoteIds.length > 1;
|
|
5403
|
+
const remoteParticipantWatchers = remoteIds.map((id) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
5404
|
+
RemoteParticipantWatcher,
|
|
5405
|
+
{
|
|
5406
|
+
sdk,
|
|
5407
|
+
participantId: id,
|
|
5408
|
+
onWebcamChange: handleRemoteWebcamChange
|
|
5409
|
+
},
|
|
5410
|
+
id
|
|
5411
|
+
));
|
|
5412
|
+
const anyRemoteWebcamOn = Object.values(remoteWebcamOn).some(Boolean);
|
|
5413
|
+
const showVideoGrid = mode === "video" || localWebcamOn || anyRemoteWebcamOn;
|
|
5232
5414
|
const controls = /* @__PURE__ */ jsxRuntime.jsx(
|
|
5233
5415
|
CallControls_default,
|
|
5234
5416
|
{
|
|
5235
5417
|
sdk,
|
|
5236
5418
|
onReaction: sendReaction,
|
|
5237
5419
|
isHandRaised,
|
|
5238
|
-
onToggleRaiseHand: toggleRaiseHand
|
|
5420
|
+
onToggleRaiseHand: toggleRaiseHand,
|
|
5421
|
+
isChatOpen,
|
|
5422
|
+
onToggleChat,
|
|
5423
|
+
isVideoActive: showVideoGrid
|
|
5239
5424
|
}
|
|
5240
5425
|
);
|
|
5426
|
+
const connectionStatusText = meetingState === "CONNECTING" ? "Connecting\u2026" : meetingState === "DISCONNECTED" ? "Reconnecting\u2026" : meetingState === "FAILED" ? "Connection lost" : null;
|
|
5427
|
+
const statusBanner = connectionStatusText && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center justify-center gap-1.5 bg-amber-500/15 px-4 py-1.5 text-xs font-medium text-amber-300", children: [
|
|
5428
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "size-1.5 animate-pulse rounded-full bg-amber-400" }),
|
|
5429
|
+
connectionStatusText
|
|
5430
|
+
] });
|
|
5241
5431
|
if (presenterId) {
|
|
5242
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5243
|
-
|
|
5244
|
-
/* @__PURE__ */ jsxRuntime.
|
|
5245
|
-
|
|
5246
|
-
{
|
|
5247
|
-
|
|
5248
|
-
|
|
5249
|
-
isLocal: presenterId === localParticipant?.id,
|
|
5250
|
-
className: "flex flex-1 flex-col overflow-hidden p-4 pb-2"
|
|
5251
|
-
}
|
|
5252
|
-
),
|
|
5253
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2 overflow-x-auto px-4 pb-2", children: [
|
|
5254
|
-
localParticipant?.id && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5255
|
-
ParticipantView_default,
|
|
5432
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5433
|
+
remoteParticipantWatchers,
|
|
5434
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex flex-1 flex-col", children: [
|
|
5435
|
+
statusBanner,
|
|
5436
|
+
/* @__PURE__ */ jsxRuntime.jsx(FloatingReactions_default, { reactions: floatingReactions }),
|
|
5437
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5438
|
+
ScreenShareView_default,
|
|
5256
5439
|
{
|
|
5257
5440
|
sdk,
|
|
5258
|
-
|
|
5259
|
-
isLocal:
|
|
5260
|
-
|
|
5261
|
-
className: "aspect-video h-20 min-h-0 w-32 shrink-0"
|
|
5441
|
+
presenterId,
|
|
5442
|
+
isLocal: presenterId === localParticipant?.id,
|
|
5443
|
+
className: "flex flex-1 flex-col overflow-hidden p-4 pb-2"
|
|
5262
5444
|
}
|
|
5263
5445
|
),
|
|
5264
|
-
|
|
5265
|
-
ParticipantView_default,
|
|
5266
|
-
{
|
|
5267
|
-
sdk,
|
|
5268
|
-
participantId: id,
|
|
5269
|
-
fallbackName: peerName,
|
|
5270
|
-
fallbackImage: peerAvatar,
|
|
5271
|
-
isHandRaised: !!raisedHands[id],
|
|
5272
|
-
className: "aspect-video h-20 min-h-0 w-32 shrink-0"
|
|
5273
|
-
},
|
|
5274
|
-
id
|
|
5275
|
-
))
|
|
5276
|
-
] }),
|
|
5277
|
-
controls
|
|
5278
|
-
] });
|
|
5279
|
-
}
|
|
5280
|
-
const showVideoGrid = mode === "video" || localWebcamOn;
|
|
5281
|
-
if (!showVideoGrid) {
|
|
5282
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex flex-1 flex-col", children: [
|
|
5283
|
-
/* @__PURE__ */ jsxRuntime.jsx(FloatingReactions_default, { reactions: floatingReactions }),
|
|
5284
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5285
|
-
AudioCallView_default,
|
|
5286
|
-
{
|
|
5287
|
-
sdk,
|
|
5288
|
-
remoteParticipantId: remoteIds[0],
|
|
5289
|
-
peerName,
|
|
5290
|
-
peerAvatar,
|
|
5291
|
-
isRemoteHandRaised: !!(remoteIds[0] && raisedHands[remoteIds[0]])
|
|
5292
|
-
}
|
|
5293
|
-
),
|
|
5294
|
-
controls
|
|
5295
|
-
] });
|
|
5296
|
-
}
|
|
5297
|
-
const focusedId = groupView === "speaker" ? activeSpeakerId && activeSpeakerId !== localParticipant?.id ? activeSpeakerId : remoteIds[0] || localParticipant?.id : null;
|
|
5298
|
-
const stripIds = focusedId ? [localParticipant?.id, ...remoteIds].filter(
|
|
5299
|
-
(id) => !!id && id !== focusedId
|
|
5300
|
-
) : [];
|
|
5301
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex flex-1 flex-col", children: [
|
|
5302
|
-
/* @__PURE__ */ jsxRuntime.jsx(FloatingReactions_default, { reactions: floatingReactions }),
|
|
5303
|
-
isGroup && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-1 px-4 pt-2", children: [
|
|
5304
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5305
|
-
"button",
|
|
5306
|
-
{
|
|
5307
|
-
type: "button",
|
|
5308
|
-
"aria-label": "Grid view",
|
|
5309
|
-
onClick: () => setGroupView("grid"),
|
|
5310
|
-
className: cn(
|
|
5311
|
-
"flex size-8 items-center justify-center rounded-lg transition-colors",
|
|
5312
|
-
groupView === "grid" ? "bg-white/15 text-white" : "text-white/50 hover:text-white/80"
|
|
5313
|
-
),
|
|
5314
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.LayoutGrid, { size: 16 })
|
|
5315
|
-
}
|
|
5316
|
-
),
|
|
5317
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5318
|
-
"button",
|
|
5319
|
-
{
|
|
5320
|
-
type: "button",
|
|
5321
|
-
"aria-label": "Speaker view",
|
|
5322
|
-
onClick: () => setGroupView("speaker"),
|
|
5323
|
-
className: cn(
|
|
5324
|
-
"flex size-8 items-center justify-center rounded-lg transition-colors",
|
|
5325
|
-
groupView === "speaker" ? "bg-white/15 text-white" : "text-white/50 hover:text-white/80"
|
|
5326
|
-
),
|
|
5327
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Rows3, { size: 16 })
|
|
5328
|
-
}
|
|
5329
|
-
)
|
|
5330
|
-
] }),
|
|
5331
|
-
focusedId ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col gap-3 overflow-y-auto p-4", children: [
|
|
5332
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5333
|
-
ParticipantView_default,
|
|
5334
|
-
{
|
|
5335
|
-
sdk,
|
|
5336
|
-
participantId: focusedId,
|
|
5337
|
-
isLocal: focusedId === localParticipant?.id,
|
|
5338
|
-
fallbackName: peerName,
|
|
5339
|
-
fallbackImage: peerAvatar,
|
|
5340
|
-
isHandRaised: !!raisedHands[focusedId],
|
|
5341
|
-
className: "min-h-[240px] flex-1"
|
|
5342
|
-
}
|
|
5343
|
-
),
|
|
5344
|
-
stripIds.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-2 overflow-x-auto", children: stripIds.map((id) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
5345
|
-
ParticipantView_default,
|
|
5346
|
-
{
|
|
5347
|
-
sdk,
|
|
5348
|
-
participantId: id,
|
|
5349
|
-
isLocal: id === localParticipant?.id,
|
|
5350
|
-
fallbackName: peerName,
|
|
5351
|
-
fallbackImage: peerAvatar,
|
|
5352
|
-
isHandRaised: !!raisedHands[id],
|
|
5353
|
-
className: "aspect-video h-20 min-h-0 w-32 shrink-0"
|
|
5354
|
-
},
|
|
5355
|
-
id
|
|
5356
|
-
)) })
|
|
5357
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5358
|
-
"div",
|
|
5359
|
-
{
|
|
5360
|
-
className: "grid flex-1 auto-rows-fr gap-3 overflow-y-auto p-4",
|
|
5361
|
-
style: {
|
|
5362
|
-
gridTemplateColumns: `repeat(${Math.min(
|
|
5363
|
-
Math.max(remoteIds.length + 1, 1),
|
|
5364
|
-
3
|
|
5365
|
-
)}, minmax(0, 1fr))`
|
|
5366
|
-
},
|
|
5367
|
-
children: [
|
|
5446
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2 overflow-x-auto px-4 pb-2", children: [
|
|
5368
5447
|
localParticipant?.id && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5369
5448
|
ParticipantView_default,
|
|
5370
5449
|
{
|
|
5371
5450
|
sdk,
|
|
5372
5451
|
participantId: localParticipant.id,
|
|
5373
5452
|
isLocal: true,
|
|
5374
|
-
isHandRaised: !!raisedHands[localParticipant.id]
|
|
5453
|
+
isHandRaised: !!raisedHands[localParticipant.id],
|
|
5454
|
+
className: "aspect-video h-20 min-h-0 w-32 shrink-0"
|
|
5375
5455
|
}
|
|
5376
5456
|
),
|
|
5377
5457
|
remoteIds.map((id) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -5381,37 +5461,160 @@ var init_MeetingView = __esm({
|
|
|
5381
5461
|
participantId: id,
|
|
5382
5462
|
fallbackName: peerName,
|
|
5383
5463
|
fallbackImage: peerAvatar,
|
|
5384
|
-
isHandRaised: !!raisedHands[id]
|
|
5464
|
+
isHandRaised: !!raisedHands[id],
|
|
5465
|
+
className: "aspect-video h-20 min-h-0 w-32 shrink-0"
|
|
5385
5466
|
},
|
|
5386
5467
|
id
|
|
5387
5468
|
))
|
|
5388
|
-
]
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5469
|
+
] }),
|
|
5470
|
+
controls
|
|
5471
|
+
] })
|
|
5472
|
+
] });
|
|
5473
|
+
}
|
|
5474
|
+
if (!showVideoGrid) {
|
|
5475
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5476
|
+
remoteParticipantWatchers,
|
|
5477
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex flex-1 flex-col", children: [
|
|
5478
|
+
statusBanner,
|
|
5479
|
+
/* @__PURE__ */ jsxRuntime.jsx(FloatingReactions_default, { reactions: floatingReactions }),
|
|
5480
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5481
|
+
AudioCallView_default,
|
|
5482
|
+
{
|
|
5483
|
+
sdk,
|
|
5484
|
+
remoteParticipantId: remoteIds[0],
|
|
5485
|
+
peerName,
|
|
5486
|
+
peerAvatar,
|
|
5487
|
+
isRemoteHandRaised: !!(remoteIds[0] && raisedHands[remoteIds[0]])
|
|
5488
|
+
}
|
|
5489
|
+
),
|
|
5490
|
+
controls
|
|
5491
|
+
] })
|
|
5492
|
+
] });
|
|
5493
|
+
}
|
|
5494
|
+
const focusedId = groupView === "speaker" ? activeSpeakerId && activeSpeakerId !== localParticipant?.id ? activeSpeakerId : remoteIds[0] || localParticipant?.id : null;
|
|
5495
|
+
const stripIds = focusedId ? [localParticipant?.id, ...remoteIds].filter(
|
|
5496
|
+
(id) => !!id && id !== focusedId
|
|
5497
|
+
) : [];
|
|
5498
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5499
|
+
remoteParticipantWatchers,
|
|
5500
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex flex-1 flex-col", children: [
|
|
5501
|
+
statusBanner,
|
|
5502
|
+
/* @__PURE__ */ jsxRuntime.jsx(FloatingReactions_default, { reactions: floatingReactions }),
|
|
5503
|
+
isGroup && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-1 px-4 pt-2", children: [
|
|
5504
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5505
|
+
"button",
|
|
5506
|
+
{
|
|
5507
|
+
type: "button",
|
|
5508
|
+
"aria-label": "Grid view",
|
|
5509
|
+
onClick: () => setGroupView("grid"),
|
|
5510
|
+
className: cn(
|
|
5511
|
+
"flex size-8 items-center justify-center rounded-lg transition-colors",
|
|
5512
|
+
groupView === "grid" ? "bg-white/15 text-white" : "text-white/50 hover:text-white/80"
|
|
5513
|
+
),
|
|
5514
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.LayoutGrid, { size: 16 })
|
|
5515
|
+
}
|
|
5516
|
+
),
|
|
5517
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5518
|
+
"button",
|
|
5519
|
+
{
|
|
5520
|
+
type: "button",
|
|
5521
|
+
"aria-label": "Speaker view",
|
|
5522
|
+
onClick: () => setGroupView("speaker"),
|
|
5523
|
+
className: cn(
|
|
5524
|
+
"flex size-8 items-center justify-center rounded-lg transition-colors",
|
|
5525
|
+
groupView === "speaker" ? "bg-white/15 text-white" : "text-white/50 hover:text-white/80"
|
|
5526
|
+
),
|
|
5527
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Rows3, { size: 16 })
|
|
5528
|
+
}
|
|
5529
|
+
)
|
|
5530
|
+
] }),
|
|
5531
|
+
focusedId ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col gap-3 overflow-y-auto p-4", children: [
|
|
5532
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5533
|
+
ParticipantView_default,
|
|
5534
|
+
{
|
|
5535
|
+
sdk,
|
|
5536
|
+
participantId: focusedId,
|
|
5537
|
+
isLocal: focusedId === localParticipant?.id,
|
|
5538
|
+
fallbackName: peerName,
|
|
5539
|
+
fallbackImage: peerAvatar,
|
|
5540
|
+
isHandRaised: !!raisedHands[focusedId],
|
|
5541
|
+
className: "min-h-[240px] flex-1"
|
|
5542
|
+
}
|
|
5543
|
+
),
|
|
5544
|
+
stripIds.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-2 overflow-x-auto", children: stripIds.map((id) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
5545
|
+
ParticipantView_default,
|
|
5546
|
+
{
|
|
5547
|
+
sdk,
|
|
5548
|
+
participantId: id,
|
|
5549
|
+
isLocal: id === localParticipant?.id,
|
|
5550
|
+
fallbackName: peerName,
|
|
5551
|
+
fallbackImage: peerAvatar,
|
|
5552
|
+
isHandRaised: !!raisedHands[id],
|
|
5553
|
+
className: "aspect-video h-20 min-h-0 w-32 shrink-0"
|
|
5554
|
+
},
|
|
5555
|
+
id
|
|
5556
|
+
)) })
|
|
5557
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5558
|
+
"div",
|
|
5559
|
+
{
|
|
5560
|
+
className: "grid flex-1 auto-rows-fr gap-3 overflow-y-auto p-4",
|
|
5561
|
+
style: {
|
|
5562
|
+
gridTemplateColumns: `repeat(${Math.min(
|
|
5563
|
+
Math.max(remoteIds.length + 1, 1),
|
|
5564
|
+
3
|
|
5565
|
+
)}, minmax(0, 1fr))`
|
|
5566
|
+
},
|
|
5567
|
+
children: [
|
|
5568
|
+
localParticipant?.id && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5569
|
+
ParticipantView_default,
|
|
5570
|
+
{
|
|
5571
|
+
sdk,
|
|
5572
|
+
participantId: localParticipant.id,
|
|
5573
|
+
isLocal: true,
|
|
5574
|
+
isHandRaised: !!raisedHands[localParticipant.id]
|
|
5575
|
+
}
|
|
5576
|
+
),
|
|
5577
|
+
remoteIds.map((id) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
5578
|
+
ParticipantView_default,
|
|
5579
|
+
{
|
|
5580
|
+
sdk,
|
|
5581
|
+
participantId: id,
|
|
5582
|
+
fallbackName: peerName,
|
|
5583
|
+
fallbackImage: peerAvatar,
|
|
5584
|
+
isHandRaised: !!raisedHands[id]
|
|
5585
|
+
},
|
|
5586
|
+
id
|
|
5587
|
+
))
|
|
5588
|
+
]
|
|
5589
|
+
}
|
|
5590
|
+
),
|
|
5591
|
+
controls
|
|
5592
|
+
] })
|
|
5593
|
+
] });
|
|
5594
|
+
};
|
|
5595
|
+
MeetingView_default = MeetingView;
|
|
5596
|
+
}
|
|
5597
|
+
});
|
|
5598
|
+
|
|
5599
|
+
// src/call/CallSession.tsx
|
|
5600
|
+
var CallSession_exports = {};
|
|
5601
|
+
__export(CallSession_exports, {
|
|
5602
|
+
default: () => CallSession_default
|
|
5603
|
+
});
|
|
5604
|
+
var CallSession, CallSession_default;
|
|
5605
|
+
var init_CallSession = __esm({
|
|
5606
|
+
"src/call/CallSession.tsx"() {
|
|
5607
|
+
init_useStore();
|
|
5608
|
+
init_videosdk_loader();
|
|
5609
|
+
init_MeetingView();
|
|
5610
|
+
CallSession = ({
|
|
5611
|
+
meetingId,
|
|
5612
|
+
token,
|
|
5613
|
+
mode,
|
|
5614
|
+
peerName,
|
|
5414
5615
|
peerAvatar,
|
|
5616
|
+
isChatOpen,
|
|
5617
|
+
onToggleChat,
|
|
5415
5618
|
onError
|
|
5416
5619
|
}) => {
|
|
5417
5620
|
const [sdk, setSdk] = React11.useState(null);
|
|
@@ -5454,7 +5657,17 @@ var init_CallSession = __esm({
|
|
|
5454
5657
|
token,
|
|
5455
5658
|
reinitialiseMeetingOnConfigChange: false,
|
|
5456
5659
|
joinWithoutUserInteraction: true,
|
|
5457
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5660
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5661
|
+
MeetingView_default,
|
|
5662
|
+
{
|
|
5663
|
+
sdk,
|
|
5664
|
+
mode,
|
|
5665
|
+
peerName,
|
|
5666
|
+
peerAvatar,
|
|
5667
|
+
isChatOpen,
|
|
5668
|
+
onToggleChat
|
|
5669
|
+
}
|
|
5670
|
+
)
|
|
5458
5671
|
}
|
|
5459
5672
|
);
|
|
5460
5673
|
};
|
|
@@ -5466,67 +5679,7 @@ var init_CallSession = __esm({
|
|
|
5466
5679
|
init_useStore();
|
|
5467
5680
|
init_api_service();
|
|
5468
5681
|
init_socket_service2();
|
|
5469
|
-
|
|
5470
|
-
// src/ui/tooltip.tsx
|
|
5471
|
-
init_utils2();
|
|
5472
|
-
function TooltipProvider({
|
|
5473
|
-
delayDuration = 0,
|
|
5474
|
-
...props
|
|
5475
|
-
}) {
|
|
5476
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5477
|
-
radixUi.Tooltip.Provider,
|
|
5478
|
-
{
|
|
5479
|
-
"data-slot": "tooltip-provider",
|
|
5480
|
-
delayDuration,
|
|
5481
|
-
...props
|
|
5482
|
-
}
|
|
5483
|
-
);
|
|
5484
|
-
}
|
|
5485
|
-
function Tooltip({
|
|
5486
|
-
...props
|
|
5487
|
-
}) {
|
|
5488
|
-
return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Tooltip.Root, { "data-slot": "tooltip", ...props });
|
|
5489
|
-
}
|
|
5490
|
-
function TooltipTrigger({
|
|
5491
|
-
...props
|
|
5492
|
-
}) {
|
|
5493
|
-
return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Tooltip.Trigger, { "data-slot": "tooltip-trigger", ...props });
|
|
5494
|
-
}
|
|
5495
|
-
function TooltipContent({
|
|
5496
|
-
className,
|
|
5497
|
-
sideOffset = 0,
|
|
5498
|
-
children,
|
|
5499
|
-
showArrow = true,
|
|
5500
|
-
arrowClassName,
|
|
5501
|
-
...props
|
|
5502
|
-
}) {
|
|
5503
|
-
return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Tooltip.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5504
|
-
radixUi.Tooltip.Content,
|
|
5505
|
-
{
|
|
5506
|
-
"data-slot": "tooltip-content",
|
|
5507
|
-
sideOffset,
|
|
5508
|
-
className: cn(
|
|
5509
|
-
"bg-foreground text-background animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
|
|
5510
|
-
className
|
|
5511
|
-
),
|
|
5512
|
-
...props,
|
|
5513
|
-
children: [
|
|
5514
|
-
children,
|
|
5515
|
-
showArrow ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
5516
|
-
radixUi.Tooltip.Arrow,
|
|
5517
|
-
{
|
|
5518
|
-
className: cn(
|
|
5519
|
-
"bg-foreground fill-foreground z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]",
|
|
5520
|
-
arrowClassName
|
|
5521
|
-
)
|
|
5522
|
-
}
|
|
5523
|
-
) : null
|
|
5524
|
-
]
|
|
5525
|
-
}
|
|
5526
|
-
) });
|
|
5527
|
-
}
|
|
5528
|
-
|
|
5529
|
-
// src/chat/ChatContext.tsx
|
|
5682
|
+
init_tooltip();
|
|
5530
5683
|
init_utils2();
|
|
5531
5684
|
|
|
5532
5685
|
// src/config/chat-endpoints.ts
|
|
@@ -6447,11 +6600,353 @@ var useCallDuration = (startedAt) => {
|
|
|
6447
6600
|
const pad = (n) => String(n).padStart(2, "0");
|
|
6448
6601
|
return hours > 0 ? `${hours}:${pad(minutes)}:${pad(seconds)}` : `${pad(minutes)}:${pad(seconds)}`;
|
|
6449
6602
|
};
|
|
6603
|
+
|
|
6604
|
+
// src/call/CallChatPanel.tsx
|
|
6605
|
+
init_useStore();
|
|
6606
|
+
init_store_helpers();
|
|
6607
|
+
init_utils2();
|
|
6608
|
+
init_button();
|
|
6609
|
+
|
|
6610
|
+
// src/chat/lib/chat-theme.ts
|
|
6611
|
+
init_utils2();
|
|
6612
|
+
var getChatScopeClass = (isDark) => cn("chat-theme-scope", isDark && "dark");
|
|
6613
|
+
var chatSheetContentClass = "flex w-full flex-col gap-0 p-0 bg-(--chat-surface) text-(--chat-text)";
|
|
6614
|
+
var chatSheetHeaderClass = "border-b border-(--chat-border) px-4 py-3 pr-11 text-left";
|
|
6615
|
+
var chatSheetBodyClass = "chat-message-scroll flex-1 overflow-y-auto bg-(--chat-surface) p-3";
|
|
6616
|
+
var chatSheetTitleClass = "text-[13px] font-semibold tracking-tight text-(--chat-text)";
|
|
6617
|
+
var chatSheetSubtitleClass = "text-[11px] text-(--chat-muted)";
|
|
6618
|
+
var chatDetailRowClass = "flex items-start justify-between gap-3 border-b border-(--chat-border) py-2.5 last:border-b-0";
|
|
6619
|
+
var chatDetailLabelClass = "text-[11px] text-(--chat-muted)";
|
|
6620
|
+
var chatDetailValueClass = "text-[13px] font-medium text-(--chat-text) text-right";
|
|
6621
|
+
var chatDialogContentClass = "overflow-hidden rounded-2xl border border-(--chat-border) bg-(--chat-surface) p-0 text-(--chat-text) shadow-[var(--chat-shadow)]";
|
|
6622
|
+
var chatDropdownContentClass = "rounded-xl border border-(--chat-border) bg-(--chat-surface) text-(--chat-text) shadow-lg";
|
|
6623
|
+
var chatOptionsMenuClass = "min-w-[220px] rounded-xl border border-(--chat-border) bg-(--chat-surface) p-1.5 text-(--chat-text) shadow-[0_10px_40px_rgba(0,0,0,0.12)]";
|
|
6624
|
+
var chatOptionsMenuLabelClass = "px-2.5 pb-0.5 pt-1 text-[10px] font-semibold uppercase tracking-[0.12em] text-(--chat-muted)";
|
|
6625
|
+
var chatOptionsMenuSeparatorClass = "my-1.5 h-px bg-(--chat-border)";
|
|
6626
|
+
var chatOptionsMenuItemClass = "cursor-pointer gap-2.5 rounded-lg px-2.5 py-2 text-[13px] font-medium text-(--chat-text) focus:bg-(--chat-hover) focus:text-(--chat-text) data-[highlighted]:bg-(--chat-hover) [&_svg]:size-[15px] [&_svg]:shrink-0 [&_svg]:text-(--chat-muted)";
|
|
6627
|
+
var chatOptionsMenuItemDestructiveClass = "cursor-pointer gap-2.5 rounded-lg px-2.5 py-2 text-[13px] font-medium text-(--chat-danger-text) focus:bg-red-500/10 focus:text-(--chat-danger-text) data-[highlighted]:bg-red-500/10 data-[highlighted]:text-(--chat-danger-text) [&_svg]:size-[15px] [&_svg]:shrink-0 [&_svg]:!text-(--chat-danger-text)";
|
|
6628
|
+
var chatOptionsMenuSubTriggerClass = "cursor-pointer gap-2.5 rounded-lg px-2.5 py-2 pr-7 text-[13px] font-medium text-(--chat-text) focus:bg-(--chat-hover) focus:text-(--chat-text) data-[highlighted]:bg-(--chat-hover) data-[state=open]:bg-(--chat-hover) [&_svg]:size-[15px] [&_svg]:shrink-0 [&_svg]:text-(--chat-muted)";
|
|
6629
|
+
var chatPopoverContentClass = "w-auto border border-(--chat-border) bg-(--chat-surface) p-0 text-(--chat-text) shadow-2xl";
|
|
6630
|
+
var chatInputClass = "border border-(--chat-border) bg-(--chat-input-bg) text-(--chat-text) shadow-none placeholder:text-(--chat-muted) focus-visible:border-(--chat-theme-20) focus-visible:ring-2 focus-visible:ring-(--chat-theme-10)";
|
|
6631
|
+
var chatSidebarSearchShellClass = "relative flex min-w-0 flex-1 items-center rounded-lg border border-(--chat-border) bg-(--chat-search-bg) px-2.5 transition-colors focus-within:border-(--chat-theme) focus-within:shadow-[0_0_0_2px_var(--chat-theme-10)]";
|
|
6632
|
+
var chatSidebarSearchInputClass = "h-8 w-full min-w-0 border-0 bg-transparent px-1.5 text-xs text-(--chat-text) shadow-none outline-none placeholder:text-(--chat-muted)/60 focus-visible:border-0 focus-visible:shadow-none focus-visible:ring-0";
|
|
6633
|
+
var chatSelectClass = "h-10 w-full cursor-pointer appearance-none rounded-xl border border-(--chat-border) bg-(--chat-input-bg) pl-3 pr-9 text-sm text-(--chat-text) shadow-none focus-visible:border-(--chat-theme-20) focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--chat-theme-10)";
|
|
6634
|
+
var chatListItemClass = "transition-colors hover:bg-(--chat-hover)";
|
|
6635
|
+
var chatLoadMoreButtonClass = "h-7 gap-1 rounded-full border border-(--chat-border) bg-(--chat-elevated) px-4 text-[10px] font-medium text-(--chat-text) transition-colors hover:border-(--chat-theme-20) hover:bg-(--chat-theme-5) hover:text-(--chat-theme) disabled:opacity-50 [&_svg]:size-3 [&_svg]:text-current";
|
|
6636
|
+
var chatDrawerSectionHeadingClass = "mb-1 px-0.5 text-[10px] font-semibold tracking-wide text-(--chat-muted)";
|
|
6637
|
+
var chatHeaderToolbarIconProps = { size: 14, strokeWidth: 1.75 };
|
|
6638
|
+
var chatSavedMessageModalIconClass = "shrink-0 text-(--chat-theme)";
|
|
6639
|
+
var chatHeaderToolbarIconLgProps = { size: 22, strokeWidth: 1.75 };
|
|
6640
|
+
var chatHeaderToolbarIconSmProps = { size: 11, strokeWidth: 1.75 };
|
|
6641
|
+
var chatDrawerFileRowClass = "flex items-center gap-2 rounded-md border border-(--chat-border)/70 bg-(--chat-elevated) px-2 py-1.5 transition-colors hover:bg-(--chat-hover)/50";
|
|
6642
|
+
var chatDrawerFileIconWrapClass = "flex size-8 shrink-0 items-center justify-center rounded-md bg-(--chat-hover)";
|
|
6643
|
+
var chatDrawerMediaFrameClass = "overflow-hidden rounded-md border border-(--chat-border)/70 bg-(--chat-elevated)";
|
|
6644
|
+
var buildChatThemeStyles = (themeColor) => ({
|
|
6645
|
+
"--chat-theme": themeColor,
|
|
6646
|
+
"--chat-theme-5": `${themeColor}0D`,
|
|
6647
|
+
"--chat-theme-10": `${themeColor}1A`,
|
|
6648
|
+
"--chat-theme-20": `${themeColor}33`,
|
|
6649
|
+
"--chat-theme-40": `${themeColor}66`,
|
|
6650
|
+
"--chat-theme-60": `${themeColor}99`,
|
|
6651
|
+
"--read-tick-color": themeColor.toLowerCase() === "#0000ff" || themeColor.toLowerCase().includes("007aff") ? "#00e5ff" : "#40C4FF"
|
|
6652
|
+
});
|
|
6653
|
+
|
|
6654
|
+
// src/chat/lib/chat-theme-storage.ts
|
|
6655
|
+
var STORAGE_KEY = "chat-color-mode";
|
|
6656
|
+
var loadChatColorMode = () => {
|
|
6657
|
+
if (typeof window === "undefined") return null;
|
|
6658
|
+
try {
|
|
6659
|
+
const stored = localStorage.getItem(STORAGE_KEY);
|
|
6660
|
+
return stored === "dark" || stored === "light" ? stored : null;
|
|
6661
|
+
} catch {
|
|
6662
|
+
return null;
|
|
6663
|
+
}
|
|
6664
|
+
};
|
|
6665
|
+
var saveChatColorMode = (mode) => {
|
|
6666
|
+
if (typeof window === "undefined") return;
|
|
6667
|
+
try {
|
|
6668
|
+
localStorage.setItem(STORAGE_KEY, mode);
|
|
6669
|
+
} catch {
|
|
6670
|
+
}
|
|
6671
|
+
};
|
|
6672
|
+
var CHAT_THEME_SHELL_CLASS = "chat-theme-shell";
|
|
6673
|
+
function withThemeTransition(apply) {
|
|
6674
|
+
if (typeof document === "undefined") {
|
|
6675
|
+
apply();
|
|
6676
|
+
return;
|
|
6677
|
+
}
|
|
6678
|
+
reactDom.flushSync(apply);
|
|
6679
|
+
}
|
|
6680
|
+
|
|
6681
|
+
// src/context/ChatThemeContext.tsx
|
|
6682
|
+
init_utils2();
|
|
6683
|
+
var ChatThemeContext = React11.createContext(null);
|
|
6684
|
+
var ChatThemeProvider = ({
|
|
6685
|
+
children,
|
|
6686
|
+
themeColor,
|
|
6687
|
+
colorMode,
|
|
6688
|
+
defaultColorMode = "light",
|
|
6689
|
+
onColorModeChange,
|
|
6690
|
+
showColorModeToggle = true
|
|
6691
|
+
}) => {
|
|
6692
|
+
const isControlled = colorMode !== void 0;
|
|
6693
|
+
const [internalMode, setInternalMode] = React11.useState(defaultColorMode);
|
|
6694
|
+
const [isThemeTransitionReady, setIsThemeTransitionReady] = React11.useState(false);
|
|
6695
|
+
const skipThemeTransitionRef = React11.useRef(true);
|
|
6696
|
+
React11.useLayoutEffect(() => {
|
|
6697
|
+
if (!isControlled) {
|
|
6698
|
+
const stored = loadChatColorMode();
|
|
6699
|
+
if (stored) {
|
|
6700
|
+
setInternalMode(stored);
|
|
6701
|
+
}
|
|
6702
|
+
}
|
|
6703
|
+
const frame = requestAnimationFrame(() => {
|
|
6704
|
+
skipThemeTransitionRef.current = false;
|
|
6705
|
+
setIsThemeTransitionReady(true);
|
|
6706
|
+
});
|
|
6707
|
+
return () => cancelAnimationFrame(frame);
|
|
6708
|
+
}, [isControlled]);
|
|
6709
|
+
const resolvedMode = isControlled ? colorMode : internalMode;
|
|
6710
|
+
const isDark = resolvedMode === "dark";
|
|
6711
|
+
const setColorMode = React11.useCallback(
|
|
6712
|
+
(mode) => {
|
|
6713
|
+
const apply = () => {
|
|
6714
|
+
if (!isControlled) {
|
|
6715
|
+
setInternalMode(mode);
|
|
6716
|
+
saveChatColorMode(mode);
|
|
6717
|
+
}
|
|
6718
|
+
onColorModeChange?.(mode);
|
|
6719
|
+
};
|
|
6720
|
+
if (skipThemeTransitionRef.current) {
|
|
6721
|
+
apply();
|
|
6722
|
+
return;
|
|
6723
|
+
}
|
|
6724
|
+
withThemeTransition(apply);
|
|
6725
|
+
},
|
|
6726
|
+
[isControlled, onColorModeChange]
|
|
6727
|
+
);
|
|
6728
|
+
const toggleColorMode = React11.useCallback(() => {
|
|
6729
|
+
setColorMode(resolvedMode === "dark" ? "light" : "dark");
|
|
6730
|
+
}, [resolvedMode, setColorMode]);
|
|
6731
|
+
const value = React11.useMemo(
|
|
6732
|
+
() => ({
|
|
6733
|
+
colorMode: resolvedMode,
|
|
6734
|
+
isDark,
|
|
6735
|
+
isThemeTransitionReady,
|
|
6736
|
+
themeColor,
|
|
6737
|
+
themeStyles: buildChatThemeStyles(themeColor),
|
|
6738
|
+
scopeClassName: cn(
|
|
6739
|
+
getChatScopeClass(isDark),
|
|
6740
|
+
!isThemeTransitionReady && "chat-theme-no-transition"
|
|
6741
|
+
),
|
|
6742
|
+
setColorMode,
|
|
6743
|
+
toggleColorMode,
|
|
6744
|
+
showColorModeToggle
|
|
6745
|
+
}),
|
|
6746
|
+
[
|
|
6747
|
+
resolvedMode,
|
|
6748
|
+
isDark,
|
|
6749
|
+
isThemeTransitionReady,
|
|
6750
|
+
themeColor,
|
|
6751
|
+
setColorMode,
|
|
6752
|
+
toggleColorMode,
|
|
6753
|
+
showColorModeToggle
|
|
6754
|
+
]
|
|
6755
|
+
);
|
|
6756
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ChatThemeContext.Provider, { value, children });
|
|
6757
|
+
};
|
|
6758
|
+
var useChatTheme = () => {
|
|
6759
|
+
const context = React11.useContext(ChatThemeContext);
|
|
6760
|
+
if (!context) {
|
|
6761
|
+
throw new Error("useChatTheme must be used within ChatThemeProvider");
|
|
6762
|
+
}
|
|
6763
|
+
return context;
|
|
6764
|
+
};
|
|
6765
|
+
|
|
6766
|
+
// src/chat/lib/chat-message-bubble.ts
|
|
6767
|
+
init_utils2();
|
|
6768
|
+
function getBubbleCornerClasses(isSender) {
|
|
6769
|
+
return isSender ? "rounded-tl-[18px] rounded-tr-[18px] rounded-bl-[18px] rounded-br-none" : "rounded-tl-[18px] rounded-tr-[18px] rounded-br-[18px] rounded-bl-none";
|
|
6770
|
+
}
|
|
6771
|
+
function getChatBubbleClasses({
|
|
6772
|
+
isSender = false,
|
|
6773
|
+
surface,
|
|
6774
|
+
className
|
|
6775
|
+
}) {
|
|
6776
|
+
const resolvedSurface = surface ?? (isSender ? "sent" : "received");
|
|
6777
|
+
const isNeutral = resolvedSurface === "neutral";
|
|
6778
|
+
return cn(
|
|
6779
|
+
"relative",
|
|
6780
|
+
getBubbleCornerClasses(isSender),
|
|
6781
|
+
resolvedSurface === "sent" && "chat-bubble-sent bg-(--chat-theme) text-white",
|
|
6782
|
+
resolvedSurface === "received" && "chat-bubble-received border border-(--chat-border)/60 bg-(--chat-incoming-bubble) text-(--chat-incoming-text)",
|
|
6783
|
+
isNeutral && "chat-bubble-received border border-(--chat-border)/60 bg-(--chat-incoming-bubble) text-(--chat-incoming-text)",
|
|
6784
|
+
className
|
|
6785
|
+
);
|
|
6786
|
+
}
|
|
6787
|
+
var CallChatPanel = ({ conversationId, isGroupCall, onClose, className }) => {
|
|
6788
|
+
const { scopeClassName, themeStyles } = useChatTheme();
|
|
6789
|
+
const rawMessages = exports.useChatStore((s) => s.messagesByConversation[conversationId]);
|
|
6790
|
+
const loggedUserDetails = exports.useChatStore((s) => s.loggedUserDetails);
|
|
6791
|
+
const conversations = exports.useChatStore((s) => s.conversations);
|
|
6792
|
+
const emitDmSend = exports.useChatStore((s) => s.emitDmSend);
|
|
6793
|
+
const emitGroupMessageSend2 = exports.useChatStore((s) => s.emitGroupMessageSend);
|
|
6794
|
+
const [text, setText] = React11.useState("");
|
|
6795
|
+
const [optimistic, setOptimistic] = React11.useState([]);
|
|
6796
|
+
const listEndRef = React11.useRef(null);
|
|
6797
|
+
const loggedUserId = String(loggedUserDetails?._id || "");
|
|
6798
|
+
const serverMessages = React11.useMemo(() => {
|
|
6799
|
+
return (rawMessages || []).filter((m) => !m?.isSystemMessage && !m?.isDeletedForEveryone).map((m) => {
|
|
6800
|
+
const senderId = String(m.sender?._id || m.sender || "");
|
|
6801
|
+
return {
|
|
6802
|
+
id: String(m._id || m.id || ""),
|
|
6803
|
+
content: String(m.content || ""),
|
|
6804
|
+
senderName: senderId === loggedUserId ? "You" : m.sender?.name || "Unknown",
|
|
6805
|
+
isOwn: senderId === loggedUserId,
|
|
6806
|
+
timestamp: m.createdAt || m.timestamp || (/* @__PURE__ */ new Date()).toISOString()
|
|
6807
|
+
};
|
|
6808
|
+
});
|
|
6809
|
+
}, [rawMessages, loggedUserId]);
|
|
6810
|
+
React11.useEffect(() => {
|
|
6811
|
+
if (!optimistic.length) return;
|
|
6812
|
+
setOptimistic(
|
|
6813
|
+
(prev) => prev.filter(
|
|
6814
|
+
(pending) => !serverMessages.some(
|
|
6815
|
+
(real) => real.isOwn && real.content === pending.content
|
|
6816
|
+
)
|
|
6817
|
+
)
|
|
6818
|
+
);
|
|
6819
|
+
}, [serverMessages]);
|
|
6820
|
+
const messages = React11.useMemo(
|
|
6821
|
+
() => [...serverMessages, ...optimistic].sort(
|
|
6822
|
+
(a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()
|
|
6823
|
+
),
|
|
6824
|
+
[serverMessages, optimistic]
|
|
6825
|
+
);
|
|
6826
|
+
React11.useEffect(() => {
|
|
6827
|
+
listEndRef.current?.scrollIntoView({ block: "end" });
|
|
6828
|
+
}, [messages.length]);
|
|
6829
|
+
const handleSend = () => {
|
|
6830
|
+
const content = text.trim();
|
|
6831
|
+
if (!content) return;
|
|
6832
|
+
setText("");
|
|
6833
|
+
setOptimistic((prev) => [
|
|
6834
|
+
...prev,
|
|
6835
|
+
{
|
|
6836
|
+
id: `pending-${Date.now()}`,
|
|
6837
|
+
content,
|
|
6838
|
+
senderName: "You",
|
|
6839
|
+
isOwn: true,
|
|
6840
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6841
|
+
pending: true
|
|
6842
|
+
}
|
|
6843
|
+
]);
|
|
6844
|
+
const payload = {
|
|
6845
|
+
tempId: `temp-${Date.now()}`,
|
|
6846
|
+
sender: loggedUserId,
|
|
6847
|
+
content,
|
|
6848
|
+
type: "text",
|
|
6849
|
+
conversationId
|
|
6850
|
+
};
|
|
6851
|
+
if (isGroupCall) {
|
|
6852
|
+
emitGroupMessageSend2(payload);
|
|
6853
|
+
} else {
|
|
6854
|
+
const conversation = findConversationById(conversations, conversationId);
|
|
6855
|
+
payload.receiver = getOtherParticipantId(conversation, loggedUserId);
|
|
6856
|
+
emitDmSend(payload);
|
|
6857
|
+
}
|
|
6858
|
+
};
|
|
6859
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6860
|
+
"div",
|
|
6861
|
+
{
|
|
6862
|
+
className: cn(
|
|
6863
|
+
scopeClassName,
|
|
6864
|
+
"flex flex-col border-l border-(--chat-border) bg-(--chat-surface) text-(--chat-text)",
|
|
6865
|
+
className
|
|
6866
|
+
),
|
|
6867
|
+
style: themeStyles,
|
|
6868
|
+
children: [
|
|
6869
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(chatSheetHeaderClass, "flex items-center justify-between"), children: [
|
|
6870
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: chatSheetTitleClass, children: "In-call chat" }),
|
|
6871
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6872
|
+
"button",
|
|
6873
|
+
{
|
|
6874
|
+
type: "button",
|
|
6875
|
+
"aria-label": "Close chat panel",
|
|
6876
|
+
onClick: onClose,
|
|
6877
|
+
className: "flex size-7 items-center justify-center rounded-lg text-(--chat-muted) transition-colors hover:bg-(--chat-hover) hover:text-(--chat-text)",
|
|
6878
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: 16 })
|
|
6879
|
+
}
|
|
6880
|
+
)
|
|
6881
|
+
] }),
|
|
6882
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(chatSheetBodyClass, "space-y-3"), children: [
|
|
6883
|
+
messages.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pt-6 text-center text-xs text-(--chat-muted)", children: "No messages yet \u2014 say hi without leaving the call." }),
|
|
6884
|
+
messages.map((message) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6885
|
+
"div",
|
|
6886
|
+
{
|
|
6887
|
+
className: cn("flex flex-col", message.isOwn ? "items-end" : "items-start"),
|
|
6888
|
+
children: [
|
|
6889
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-0.5 text-[11px] font-medium text-(--chat-muted)", children: message.isOwn ? "You" : message.senderName }),
|
|
6890
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6891
|
+
"div",
|
|
6892
|
+
{
|
|
6893
|
+
className: cn(
|
|
6894
|
+
getChatBubbleClasses({ isSender: message.isOwn }),
|
|
6895
|
+
"max-w-[85%] px-3 py-1.5 text-sm break-words",
|
|
6896
|
+
message.pending && "opacity-60"
|
|
6897
|
+
),
|
|
6898
|
+
children: message.content
|
|
6899
|
+
}
|
|
6900
|
+
)
|
|
6901
|
+
]
|
|
6902
|
+
},
|
|
6903
|
+
message.id
|
|
6904
|
+
)),
|
|
6905
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: listEndRef })
|
|
6906
|
+
] }),
|
|
6907
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 border-t border-(--chat-border) p-3", children: [
|
|
6908
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6909
|
+
"input",
|
|
6910
|
+
{
|
|
6911
|
+
value: text,
|
|
6912
|
+
onChange: (e) => setText(e.target.value),
|
|
6913
|
+
onKeyDown: (e) => {
|
|
6914
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
6915
|
+
e.preventDefault();
|
|
6916
|
+
handleSend();
|
|
6917
|
+
}
|
|
6918
|
+
},
|
|
6919
|
+
placeholder: "Message\u2026",
|
|
6920
|
+
className: cn(chatInputClass, "min-w-0 flex-1 rounded-full px-3.5 py-2 text-sm")
|
|
6921
|
+
}
|
|
6922
|
+
),
|
|
6923
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6924
|
+
Button,
|
|
6925
|
+
{
|
|
6926
|
+
variant: "ghost",
|
|
6927
|
+
size: "icon",
|
|
6928
|
+
"aria-label": "Send message",
|
|
6929
|
+
disabled: !text.trim(),
|
|
6930
|
+
onClick: handleSend,
|
|
6931
|
+
className: cn(
|
|
6932
|
+
"size-9 shrink-0 rounded-full transition-colors",
|
|
6933
|
+
text.trim() ? "bg-(--chat-theme) text-white hover:opacity-90" : "bg-(--chat-hover) text-(--chat-muted)"
|
|
6934
|
+
),
|
|
6935
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, { size: 16 })
|
|
6936
|
+
}
|
|
6937
|
+
)
|
|
6938
|
+
] })
|
|
6939
|
+
]
|
|
6940
|
+
}
|
|
6941
|
+
);
|
|
6942
|
+
};
|
|
6943
|
+
var CallChatPanel_default = CallChatPanel;
|
|
6450
6944
|
var CallSession2 = React11__namespace.default.lazy(() => Promise.resolve().then(() => (init_CallSession(), CallSession_exports)));
|
|
6451
6945
|
var CallOverlay = () => {
|
|
6452
6946
|
const uiStatus = exports.useCallStore((s) => s.uiStatus);
|
|
6453
6947
|
const mode = exports.useCallStore((s) => s.mode);
|
|
6454
6948
|
const callId = exports.useCallStore((s) => s.callId);
|
|
6949
|
+
const conversationId = exports.useCallStore((s) => s.conversationId);
|
|
6455
6950
|
const meetingId = exports.useCallStore((s) => s.meetingId);
|
|
6456
6951
|
const token = exports.useCallStore((s) => s.token);
|
|
6457
6952
|
const error = exports.useCallStore((s) => s.error);
|
|
@@ -6463,112 +6958,111 @@ var CallOverlay = () => {
|
|
|
6463
6958
|
const reset = exports.useCallStore((s) => s.reset);
|
|
6464
6959
|
const notifyServerCallFailed = exports.useCallStore((s) => s.notifyServerCallFailed);
|
|
6465
6960
|
const [sessionError, setSessionError] = React11.useState(null);
|
|
6961
|
+
const [isChatOpen, setIsChatOpen] = React11.useState(false);
|
|
6466
6962
|
const secondsLeft = useRingCountdown(uiStatus === "ringing-out", callId);
|
|
6467
6963
|
const duration = useCallDuration(callStartedAt);
|
|
6468
6964
|
React11.useEffect(() => {
|
|
6469
6965
|
setSessionError(null);
|
|
6966
|
+
setIsChatOpen(false);
|
|
6470
6967
|
}, [callId]);
|
|
6471
6968
|
React11.useEffect(() => {
|
|
6472
6969
|
if (sessionError) notifyServerCallFailed();
|
|
6473
6970
|
}, [sessionError, notifyServerCallFailed]);
|
|
6474
6971
|
const isOpen = uiStatus !== "idle" && uiStatus !== "incoming";
|
|
6475
|
-
if (!isOpen
|
|
6972
|
+
if (!isOpen) return null;
|
|
6476
6973
|
const displayError = error || sessionError;
|
|
6477
6974
|
const peerName = peer?.name || caller?.name || "";
|
|
6478
6975
|
const peerAvatar = peer?.avatar || caller?.profileImage || void 0;
|
|
6479
|
-
const isVideo = mode === "video";
|
|
6480
|
-
return
|
|
6481
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6482
|
-
|
|
6483
|
-
{
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
|
|
6493
|
-
|
|
6494
|
-
|
|
6495
|
-
|
|
6496
|
-
|
|
6497
|
-
|
|
6498
|
-
|
|
6499
|
-
|
|
6500
|
-
isGroupCall && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Users, { size: 14, className: "text-white/50" }),
|
|
6501
|
-
peerName && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-white/90", children: peerName }),
|
|
6502
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "text-white/30", children: "\xB7" }),
|
|
6503
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: duration })
|
|
6504
|
-
] }),
|
|
6505
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6506
|
-
React11__namespace.default.Suspense,
|
|
6507
|
-
{
|
|
6508
|
-
fallback: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col items-center justify-center gap-3 text-white/80", children: [
|
|
6509
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-8 animate-spin" }),
|
|
6510
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm", children: "Loading call\u2026" })
|
|
6511
|
-
] }),
|
|
6512
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
6513
|
-
CallSession2,
|
|
6514
|
-
{
|
|
6515
|
-
meetingId,
|
|
6516
|
-
token,
|
|
6517
|
-
mode,
|
|
6518
|
-
peerName,
|
|
6519
|
-
peerAvatar,
|
|
6520
|
-
onError: setSessionError
|
|
6521
|
-
}
|
|
6522
|
-
)
|
|
6523
|
-
}
|
|
6524
|
-
)
|
|
6525
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col items-center justify-center gap-6 p-6 text-center", children: [
|
|
6526
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex items-center justify-center", children: [
|
|
6527
|
-
uiStatus === "ringing-out" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
6528
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inline-flex size-32 animate-ping rounded-full bg-white/10" }),
|
|
6529
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6530
|
-
"span",
|
|
6531
|
-
{
|
|
6532
|
-
className: "absolute inline-flex size-32 animate-ping rounded-full bg-white/5",
|
|
6533
|
-
style: { animationDelay: "0.6s" }
|
|
6534
|
-
}
|
|
6535
|
-
)
|
|
6536
|
-
] }),
|
|
6537
|
-
peerName ? /* @__PURE__ */ jsxRuntime.jsxs(Avatar, { className: "relative size-28 ring-4 ring-white/10", children: [
|
|
6538
|
-
/* @__PURE__ */ jsxRuntime.jsx(AvatarImage, { src: peerAvatar, alt: peerName }),
|
|
6539
|
-
/* @__PURE__ */ jsxRuntime.jsx(AvatarFallback, { className: "bg-neutral-700 text-3xl font-medium text-white", children: peerName.charAt(0).toUpperCase() })
|
|
6540
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative flex size-28 items-center justify-center rounded-full bg-white/10", children: isVideo ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Video, { size: 36 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Phone, { size: 36 }) })
|
|
6541
|
-
] }),
|
|
6542
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
6543
|
-
peerName && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center justify-center gap-1.5 text-xl font-semibold tracking-tight", children: [
|
|
6544
|
-
isGroupCall && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Users, { size: 16, className: "text-white/50" }),
|
|
6545
|
-
peerName
|
|
6546
|
-
] }),
|
|
6547
|
-
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-1 text-sm text-white/60", children: [
|
|
6548
|
-
uiStatus === "creating" && "Starting call\u2026",
|
|
6549
|
-
uiStatus === "ringing-out" && `${isVideo ? "Video calling" : "Calling"}\u2026 \xB7 ${secondsLeft}s`,
|
|
6550
|
-
uiStatus === "joining" && "Connecting\u2026"
|
|
6551
|
-
] })
|
|
6976
|
+
const isVideo = mode === "video";
|
|
6977
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 z-40 flex flex-col overflow-hidden bg-gradient-to-b from-neutral-900 via-neutral-950 to-black text-white", children: displayError ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col items-center justify-center gap-4 p-6 text-center", children: [
|
|
6978
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "max-w-sm text-sm text-white/80", children: displayError }),
|
|
6979
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "secondary", onClick: reset, children: [
|
|
6980
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: 16, className: "mr-1" }),
|
|
6981
|
+
" Close"
|
|
6982
|
+
] })
|
|
6983
|
+
] }) : uiStatus === "in-call" && meetingId && token && mode && conversationId ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col min-h-0", children: [
|
|
6984
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center justify-center gap-2 px-4 py-3 text-sm text-white/70", children: [
|
|
6985
|
+
isGroupCall && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Users, { size: 14, className: "text-white/50" }),
|
|
6986
|
+
peerName && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-white/90", children: peerName }),
|
|
6987
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "text-white/30", children: "\xB7" }),
|
|
6988
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: duration })
|
|
6989
|
+
] }),
|
|
6990
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 min-h-0", children: [
|
|
6991
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6992
|
+
React11__namespace.default.Suspense,
|
|
6993
|
+
{
|
|
6994
|
+
fallback: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col items-center justify-center gap-3 text-white/80", children: [
|
|
6995
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-8 animate-spin" }),
|
|
6996
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm", children: "Loading call\u2026" })
|
|
6552
6997
|
] }),
|
|
6553
|
-
|
|
6554
|
-
|
|
6555
|
-
|
|
6556
|
-
|
|
6557
|
-
|
|
6558
|
-
|
|
6559
|
-
|
|
6560
|
-
|
|
6561
|
-
|
|
6562
|
-
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
|
|
6568
|
-
|
|
6569
|
-
|
|
6570
|
-
|
|
6571
|
-
|
|
6998
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
6999
|
+
CallSession2,
|
|
7000
|
+
{
|
|
7001
|
+
meetingId,
|
|
7002
|
+
token,
|
|
7003
|
+
mode,
|
|
7004
|
+
peerName,
|
|
7005
|
+
peerAvatar,
|
|
7006
|
+
isChatOpen,
|
|
7007
|
+
onToggleChat: () => setIsChatOpen((v) => !v),
|
|
7008
|
+
onError: setSessionError
|
|
7009
|
+
}
|
|
7010
|
+
)
|
|
7011
|
+
}
|
|
7012
|
+
),
|
|
7013
|
+
isChatOpen && /* @__PURE__ */ jsxRuntime.jsx(
|
|
7014
|
+
CallChatPanel_default,
|
|
7015
|
+
{
|
|
7016
|
+
conversationId,
|
|
7017
|
+
isGroupCall,
|
|
7018
|
+
onClose: () => setIsChatOpen(false),
|
|
7019
|
+
className: "hidden w-80 shrink-0 sm:flex"
|
|
7020
|
+
}
|
|
7021
|
+
)
|
|
7022
|
+
] })
|
|
7023
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col items-center justify-center gap-6 p-6 text-center", children: [
|
|
7024
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex items-center justify-center", children: [
|
|
7025
|
+
uiStatus === "ringing-out" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
7026
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inline-flex size-32 animate-ping rounded-full bg-white/10" }),
|
|
7027
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7028
|
+
"span",
|
|
7029
|
+
{
|
|
7030
|
+
className: "absolute inline-flex size-32 animate-ping rounded-full bg-white/5",
|
|
7031
|
+
style: { animationDelay: "0.6s" }
|
|
7032
|
+
}
|
|
7033
|
+
)
|
|
7034
|
+
] }),
|
|
7035
|
+
peerName ? /* @__PURE__ */ jsxRuntime.jsxs(Avatar, { className: "relative size-28 ring-4 ring-white/10", children: [
|
|
7036
|
+
/* @__PURE__ */ jsxRuntime.jsx(AvatarImage, { src: peerAvatar, alt: peerName }),
|
|
7037
|
+
/* @__PURE__ */ jsxRuntime.jsx(AvatarFallback, { className: "bg-neutral-700 text-3xl font-medium text-white", children: peerName.charAt(0).toUpperCase() })
|
|
7038
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative flex size-28 items-center justify-center rounded-full bg-white/10", children: isVideo ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Video, { size: 36 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Phone, { size: 36 }) })
|
|
7039
|
+
] }),
|
|
7040
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
7041
|
+
peerName && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center justify-center gap-1.5 text-xl font-semibold tracking-tight", children: [
|
|
7042
|
+
isGroupCall && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Users, { size: 16, className: "text-white/50" }),
|
|
7043
|
+
peerName
|
|
7044
|
+
] }),
|
|
7045
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-1 text-sm text-white/60", children: [
|
|
7046
|
+
uiStatus === "creating" && "Starting call\u2026",
|
|
7047
|
+
uiStatus === "ringing-out" && `${isVideo ? "Video calling" : "Calling"}\u2026 \xB7 ${secondsLeft}s`,
|
|
7048
|
+
uiStatus === "joining" && "Connecting\u2026"
|
|
7049
|
+
] })
|
|
7050
|
+
] }),
|
|
7051
|
+
uiStatus === "ringing-out" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1 flex flex-col items-center gap-2", children: [
|
|
7052
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7053
|
+
Button,
|
|
7054
|
+
{
|
|
7055
|
+
variant: "ghost",
|
|
7056
|
+
size: "icon",
|
|
7057
|
+
className: "size-16 rounded-full bg-red-600 text-white shadow-lg shadow-red-600/30 transition-transform hover:scale-105 hover:bg-red-500 active:scale-95",
|
|
7058
|
+
"aria-label": "Cancel call",
|
|
7059
|
+
onClick: cancelCall,
|
|
7060
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PhoneOff, { size: 24 })
|
|
7061
|
+
}
|
|
7062
|
+
),
|
|
7063
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-white/60", children: "Cancel" })
|
|
7064
|
+
] })
|
|
7065
|
+
] }) });
|
|
6572
7066
|
};
|
|
6573
7067
|
var CallOverlay_default = CallOverlay;
|
|
6574
7068
|
|
|
@@ -6904,162 +7398,6 @@ function AlertDialogCancel({
|
|
|
6904
7398
|
|
|
6905
7399
|
// src/chat/ChatOverlay.tsx
|
|
6906
7400
|
init_utils2();
|
|
6907
|
-
|
|
6908
|
-
// src/chat/lib/chat-theme.ts
|
|
6909
|
-
init_utils2();
|
|
6910
|
-
var getChatScopeClass = (isDark) => cn("chat-theme-scope", isDark && "dark");
|
|
6911
|
-
var chatSheetContentClass = "flex w-full flex-col gap-0 p-0 bg-(--chat-surface) text-(--chat-text)";
|
|
6912
|
-
var chatSheetHeaderClass = "border-b border-(--chat-border) px-4 py-3 pr-11 text-left";
|
|
6913
|
-
var chatSheetBodyClass = "chat-message-scroll flex-1 overflow-y-auto bg-(--chat-surface) p-3";
|
|
6914
|
-
var chatSheetTitleClass = "text-[13px] font-semibold tracking-tight text-(--chat-text)";
|
|
6915
|
-
var chatSheetSubtitleClass = "text-[11px] text-(--chat-muted)";
|
|
6916
|
-
var chatDetailRowClass = "flex items-start justify-between gap-3 border-b border-(--chat-border) py-2.5 last:border-b-0";
|
|
6917
|
-
var chatDetailLabelClass = "text-[11px] text-(--chat-muted)";
|
|
6918
|
-
var chatDetailValueClass = "text-[13px] font-medium text-(--chat-text) text-right";
|
|
6919
|
-
var chatDialogContentClass = "overflow-hidden rounded-2xl border border-(--chat-border) bg-(--chat-surface) p-0 text-(--chat-text) shadow-[var(--chat-shadow)]";
|
|
6920
|
-
var chatDropdownContentClass = "rounded-xl border border-(--chat-border) bg-(--chat-surface) text-(--chat-text) shadow-lg";
|
|
6921
|
-
var chatOptionsMenuClass = "min-w-[220px] rounded-xl border border-(--chat-border) bg-(--chat-surface) p-1.5 text-(--chat-text) shadow-[0_10px_40px_rgba(0,0,0,0.12)]";
|
|
6922
|
-
var chatOptionsMenuLabelClass = "px-2.5 pb-0.5 pt-1 text-[10px] font-semibold uppercase tracking-[0.12em] text-(--chat-muted)";
|
|
6923
|
-
var chatOptionsMenuSeparatorClass = "my-1.5 h-px bg-(--chat-border)";
|
|
6924
|
-
var chatOptionsMenuItemClass = "cursor-pointer gap-2.5 rounded-lg px-2.5 py-2 text-[13px] font-medium text-(--chat-text) focus:bg-(--chat-hover) focus:text-(--chat-text) data-[highlighted]:bg-(--chat-hover) [&_svg]:size-[15px] [&_svg]:shrink-0 [&_svg]:text-(--chat-muted)";
|
|
6925
|
-
var chatOptionsMenuItemDestructiveClass = "cursor-pointer gap-2.5 rounded-lg px-2.5 py-2 text-[13px] font-medium text-(--chat-danger-text) focus:bg-red-500/10 focus:text-(--chat-danger-text) data-[highlighted]:bg-red-500/10 data-[highlighted]:text-(--chat-danger-text) [&_svg]:size-[15px] [&_svg]:shrink-0 [&_svg]:!text-(--chat-danger-text)";
|
|
6926
|
-
var chatOptionsMenuSubTriggerClass = "cursor-pointer gap-2.5 rounded-lg px-2.5 py-2 pr-7 text-[13px] font-medium text-(--chat-text) focus:bg-(--chat-hover) focus:text-(--chat-text) data-[highlighted]:bg-(--chat-hover) data-[state=open]:bg-(--chat-hover) [&_svg]:size-[15px] [&_svg]:shrink-0 [&_svg]:text-(--chat-muted)";
|
|
6927
|
-
var chatPopoverContentClass = "w-auto border border-(--chat-border) bg-(--chat-surface) p-0 text-(--chat-text) shadow-2xl";
|
|
6928
|
-
var chatInputClass = "border border-(--chat-border) bg-(--chat-input-bg) text-(--chat-text) shadow-none placeholder:text-(--chat-muted) focus-visible:border-(--chat-theme-20) focus-visible:ring-2 focus-visible:ring-(--chat-theme-10)";
|
|
6929
|
-
var chatSidebarSearchShellClass = "relative flex min-w-0 flex-1 items-center rounded-lg border border-(--chat-border) bg-(--chat-search-bg) px-2.5 transition-colors focus-within:border-(--chat-theme) focus-within:shadow-[0_0_0_2px_var(--chat-theme-10)]";
|
|
6930
|
-
var chatSidebarSearchInputClass = "h-8 w-full min-w-0 border-0 bg-transparent px-1.5 text-xs text-(--chat-text) shadow-none outline-none placeholder:text-(--chat-muted)/60 focus-visible:border-0 focus-visible:shadow-none focus-visible:ring-0";
|
|
6931
|
-
var chatSelectClass = "h-10 w-full cursor-pointer appearance-none rounded-xl border border-(--chat-border) bg-(--chat-input-bg) pl-3 pr-9 text-sm text-(--chat-text) shadow-none focus-visible:border-(--chat-theme-20) focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--chat-theme-10)";
|
|
6932
|
-
var chatListItemClass = "transition-colors hover:bg-(--chat-hover)";
|
|
6933
|
-
var chatLoadMoreButtonClass = "h-7 gap-1 rounded-full border border-(--chat-border) bg-(--chat-elevated) px-4 text-[10px] font-medium text-(--chat-text) transition-colors hover:border-(--chat-theme-20) hover:bg-(--chat-theme-5) hover:text-(--chat-theme) disabled:opacity-50 [&_svg]:size-3 [&_svg]:text-current";
|
|
6934
|
-
var chatDrawerSectionHeadingClass = "mb-1 px-0.5 text-[10px] font-semibold tracking-wide text-(--chat-muted)";
|
|
6935
|
-
var chatHeaderToolbarIconProps = { size: 14, strokeWidth: 1.75 };
|
|
6936
|
-
var chatSavedMessageModalIconClass = "shrink-0 text-(--chat-theme)";
|
|
6937
|
-
var chatHeaderToolbarIconLgProps = { size: 22, strokeWidth: 1.75 };
|
|
6938
|
-
var chatHeaderToolbarIconSmProps = { size: 11, strokeWidth: 1.75 };
|
|
6939
|
-
var chatDrawerFileRowClass = "flex items-center gap-2 rounded-md border border-(--chat-border)/70 bg-(--chat-elevated) px-2 py-1.5 transition-colors hover:bg-(--chat-hover)/50";
|
|
6940
|
-
var chatDrawerFileIconWrapClass = "flex size-8 shrink-0 items-center justify-center rounded-md bg-(--chat-hover)";
|
|
6941
|
-
var chatDrawerMediaFrameClass = "overflow-hidden rounded-md border border-(--chat-border)/70 bg-(--chat-elevated)";
|
|
6942
|
-
var buildChatThemeStyles = (themeColor) => ({
|
|
6943
|
-
"--chat-theme": themeColor,
|
|
6944
|
-
"--chat-theme-5": `${themeColor}0D`,
|
|
6945
|
-
"--chat-theme-10": `${themeColor}1A`,
|
|
6946
|
-
"--chat-theme-20": `${themeColor}33`,
|
|
6947
|
-
"--chat-theme-40": `${themeColor}66`,
|
|
6948
|
-
"--chat-theme-60": `${themeColor}99`,
|
|
6949
|
-
"--read-tick-color": themeColor.toLowerCase() === "#0000ff" || themeColor.toLowerCase().includes("007aff") ? "#00e5ff" : "#40C4FF"
|
|
6950
|
-
});
|
|
6951
|
-
|
|
6952
|
-
// src/chat/lib/chat-theme-storage.ts
|
|
6953
|
-
var STORAGE_KEY = "chat-color-mode";
|
|
6954
|
-
var loadChatColorMode = () => {
|
|
6955
|
-
if (typeof window === "undefined") return null;
|
|
6956
|
-
try {
|
|
6957
|
-
const stored = localStorage.getItem(STORAGE_KEY);
|
|
6958
|
-
return stored === "dark" || stored === "light" ? stored : null;
|
|
6959
|
-
} catch {
|
|
6960
|
-
return null;
|
|
6961
|
-
}
|
|
6962
|
-
};
|
|
6963
|
-
var saveChatColorMode = (mode) => {
|
|
6964
|
-
if (typeof window === "undefined") return;
|
|
6965
|
-
try {
|
|
6966
|
-
localStorage.setItem(STORAGE_KEY, mode);
|
|
6967
|
-
} catch {
|
|
6968
|
-
}
|
|
6969
|
-
};
|
|
6970
|
-
var CHAT_THEME_SHELL_CLASS = "chat-theme-shell";
|
|
6971
|
-
function withThemeTransition(apply) {
|
|
6972
|
-
if (typeof document === "undefined") {
|
|
6973
|
-
apply();
|
|
6974
|
-
return;
|
|
6975
|
-
}
|
|
6976
|
-
reactDom.flushSync(apply);
|
|
6977
|
-
}
|
|
6978
|
-
|
|
6979
|
-
// src/context/ChatThemeContext.tsx
|
|
6980
|
-
init_utils2();
|
|
6981
|
-
var ChatThemeContext = React11.createContext(null);
|
|
6982
|
-
var ChatThemeProvider = ({
|
|
6983
|
-
children,
|
|
6984
|
-
themeColor,
|
|
6985
|
-
colorMode,
|
|
6986
|
-
defaultColorMode = "light",
|
|
6987
|
-
onColorModeChange,
|
|
6988
|
-
showColorModeToggle = true
|
|
6989
|
-
}) => {
|
|
6990
|
-
const isControlled = colorMode !== void 0;
|
|
6991
|
-
const [internalMode, setInternalMode] = React11.useState(defaultColorMode);
|
|
6992
|
-
const [isThemeTransitionReady, setIsThemeTransitionReady] = React11.useState(false);
|
|
6993
|
-
const skipThemeTransitionRef = React11.useRef(true);
|
|
6994
|
-
React11.useLayoutEffect(() => {
|
|
6995
|
-
if (!isControlled) {
|
|
6996
|
-
const stored = loadChatColorMode();
|
|
6997
|
-
if (stored) {
|
|
6998
|
-
setInternalMode(stored);
|
|
6999
|
-
}
|
|
7000
|
-
}
|
|
7001
|
-
const frame = requestAnimationFrame(() => {
|
|
7002
|
-
skipThemeTransitionRef.current = false;
|
|
7003
|
-
setIsThemeTransitionReady(true);
|
|
7004
|
-
});
|
|
7005
|
-
return () => cancelAnimationFrame(frame);
|
|
7006
|
-
}, [isControlled]);
|
|
7007
|
-
const resolvedMode = isControlled ? colorMode : internalMode;
|
|
7008
|
-
const isDark = resolvedMode === "dark";
|
|
7009
|
-
const setColorMode = React11.useCallback(
|
|
7010
|
-
(mode) => {
|
|
7011
|
-
const apply = () => {
|
|
7012
|
-
if (!isControlled) {
|
|
7013
|
-
setInternalMode(mode);
|
|
7014
|
-
saveChatColorMode(mode);
|
|
7015
|
-
}
|
|
7016
|
-
onColorModeChange?.(mode);
|
|
7017
|
-
};
|
|
7018
|
-
if (skipThemeTransitionRef.current) {
|
|
7019
|
-
apply();
|
|
7020
|
-
return;
|
|
7021
|
-
}
|
|
7022
|
-
withThemeTransition(apply);
|
|
7023
|
-
},
|
|
7024
|
-
[isControlled, onColorModeChange]
|
|
7025
|
-
);
|
|
7026
|
-
const toggleColorMode = React11.useCallback(() => {
|
|
7027
|
-
setColorMode(resolvedMode === "dark" ? "light" : "dark");
|
|
7028
|
-
}, [resolvedMode, setColorMode]);
|
|
7029
|
-
const value = React11.useMemo(
|
|
7030
|
-
() => ({
|
|
7031
|
-
colorMode: resolvedMode,
|
|
7032
|
-
isDark,
|
|
7033
|
-
isThemeTransitionReady,
|
|
7034
|
-
themeColor,
|
|
7035
|
-
themeStyles: buildChatThemeStyles(themeColor),
|
|
7036
|
-
scopeClassName: cn(
|
|
7037
|
-
getChatScopeClass(isDark),
|
|
7038
|
-
!isThemeTransitionReady && "chat-theme-no-transition"
|
|
7039
|
-
),
|
|
7040
|
-
setColorMode,
|
|
7041
|
-
toggleColorMode,
|
|
7042
|
-
showColorModeToggle
|
|
7043
|
-
}),
|
|
7044
|
-
[
|
|
7045
|
-
resolvedMode,
|
|
7046
|
-
isDark,
|
|
7047
|
-
isThemeTransitionReady,
|
|
7048
|
-
themeColor,
|
|
7049
|
-
setColorMode,
|
|
7050
|
-
toggleColorMode,
|
|
7051
|
-
showColorModeToggle
|
|
7052
|
-
]
|
|
7053
|
-
);
|
|
7054
|
-
return /* @__PURE__ */ jsxRuntime.jsx(ChatThemeContext.Provider, { value, children });
|
|
7055
|
-
};
|
|
7056
|
-
var useChatTheme = () => {
|
|
7057
|
-
const context = React11.useContext(ChatThemeContext);
|
|
7058
|
-
if (!context) {
|
|
7059
|
-
throw new Error("useChatTheme must be used within ChatThemeProvider");
|
|
7060
|
-
}
|
|
7061
|
-
return context;
|
|
7062
|
-
};
|
|
7063
7401
|
var ChatSheetContent = ({
|
|
7064
7402
|
className,
|
|
7065
7403
|
style,
|
|
@@ -7115,6 +7453,66 @@ init_avatar();
|
|
|
7115
7453
|
init_button();
|
|
7116
7454
|
init_utils2();
|
|
7117
7455
|
init_call_store();
|
|
7456
|
+
|
|
7457
|
+
// src/call/ringtone.ts
|
|
7458
|
+
var audioCtx = null;
|
|
7459
|
+
var scheduledTimer = null;
|
|
7460
|
+
var activeOscillators = [];
|
|
7461
|
+
var RING_ON_MS = 1200;
|
|
7462
|
+
var RING_OFF_MS = 2400;
|
|
7463
|
+
var RING_FREQUENCIES = [440, 480];
|
|
7464
|
+
var getContext = () => {
|
|
7465
|
+
if (typeof window === "undefined") return null;
|
|
7466
|
+
const Ctor = window.AudioContext || window.webkitAudioContext;
|
|
7467
|
+
if (!Ctor) return null;
|
|
7468
|
+
if (!audioCtx || audioCtx.state === "closed") audioCtx = new Ctor();
|
|
7469
|
+
return audioCtx;
|
|
7470
|
+
};
|
|
7471
|
+
var stopOscillators = () => {
|
|
7472
|
+
activeOscillators.forEach((osc) => {
|
|
7473
|
+
try {
|
|
7474
|
+
osc.stop();
|
|
7475
|
+
} catch {
|
|
7476
|
+
}
|
|
7477
|
+
});
|
|
7478
|
+
activeOscillators = [];
|
|
7479
|
+
};
|
|
7480
|
+
var ringBurst = (ctx) => {
|
|
7481
|
+
const onSeconds = RING_ON_MS / 1e3;
|
|
7482
|
+
const gain = ctx.createGain();
|
|
7483
|
+
gain.gain.setValueAtTime(0, ctx.currentTime);
|
|
7484
|
+
gain.gain.linearRampToValueAtTime(0.15, ctx.currentTime + 0.05);
|
|
7485
|
+
gain.gain.setValueAtTime(0.15, ctx.currentTime + onSeconds - 0.05);
|
|
7486
|
+
gain.gain.linearRampToValueAtTime(0, ctx.currentTime + onSeconds);
|
|
7487
|
+
gain.connect(ctx.destination);
|
|
7488
|
+
RING_FREQUENCIES.forEach((freq) => {
|
|
7489
|
+
const osc = ctx.createOscillator();
|
|
7490
|
+
osc.type = "sine";
|
|
7491
|
+
osc.frequency.value = freq;
|
|
7492
|
+
osc.connect(gain);
|
|
7493
|
+
osc.start();
|
|
7494
|
+
osc.stop(ctx.currentTime + onSeconds);
|
|
7495
|
+
activeOscillators.push(osc);
|
|
7496
|
+
});
|
|
7497
|
+
};
|
|
7498
|
+
var playDefaultRingtone = () => {
|
|
7499
|
+
if (scheduledTimer) return;
|
|
7500
|
+
const ctx = getContext();
|
|
7501
|
+
if (!ctx) return;
|
|
7502
|
+
ctx.resume().catch(() => void 0);
|
|
7503
|
+
const cycle = () => {
|
|
7504
|
+
ringBurst(ctx);
|
|
7505
|
+
scheduledTimer = setTimeout(cycle, RING_ON_MS + RING_OFF_MS);
|
|
7506
|
+
};
|
|
7507
|
+
cycle();
|
|
7508
|
+
};
|
|
7509
|
+
var stopDefaultRingtone = () => {
|
|
7510
|
+
if (scheduledTimer) {
|
|
7511
|
+
clearTimeout(scheduledTimer);
|
|
7512
|
+
scheduledTimer = null;
|
|
7513
|
+
}
|
|
7514
|
+
stopOscillators();
|
|
7515
|
+
};
|
|
7118
7516
|
var IncomingCallDialog = ({ ringtoneUrl }) => {
|
|
7119
7517
|
const uiStatus = exports.useCallStore((s) => s.uiStatus);
|
|
7120
7518
|
const callId = exports.useCallStore((s) => s.callId);
|
|
@@ -7137,6 +7535,12 @@ var IncomingCallDialog = ({ ringtoneUrl }) => {
|
|
|
7137
7535
|
el.pause();
|
|
7138
7536
|
}
|
|
7139
7537
|
}, [isOpen, ringtoneUrl]);
|
|
7538
|
+
React11.useEffect(() => {
|
|
7539
|
+
if (ringtoneUrl) return;
|
|
7540
|
+
if (isOpen) playDefaultRingtone();
|
|
7541
|
+
else stopDefaultRingtone();
|
|
7542
|
+
return () => stopDefaultRingtone();
|
|
7543
|
+
}, [isOpen, ringtoneUrl]);
|
|
7140
7544
|
if (!isOpen) return null;
|
|
7141
7545
|
const callerName = caller?.name || "Unknown caller";
|
|
7142
7546
|
const name = isGroupCall ? peer?.name || callerName : callerName;
|
|
@@ -7404,7 +7808,7 @@ var Chat = ({
|
|
|
7404
7808
|
}),
|
|
7405
7809
|
[uiConfig.components, uiConfig.classNames, uiConfig.features]
|
|
7406
7810
|
);
|
|
7407
|
-
return /* @__PURE__ */ jsxRuntime.jsx(ChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsx(ChatCustomizationProvider, { customization, children: /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "chat-container-root flex h-full min-h-0 w-full flex-1 flex-col overflow-hidden", children: isSessionReady ? /* @__PURE__ */ jsxRuntime.jsxs(ChatEffectiveSettingsProvider, { enabled: true, children: [
|
|
7811
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsx(ChatCustomizationProvider, { customization, children: /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "chat-container-root relative flex h-full min-h-0 w-full flex-1 flex-col overflow-hidden", children: isSessionReady ? /* @__PURE__ */ jsxRuntime.jsxs(ChatEffectiveSettingsProvider, { enabled: true, children: [
|
|
7408
7812
|
children,
|
|
7409
7813
|
/* @__PURE__ */ jsxRuntime.jsx(CallLayer_default, {})
|
|
7410
7814
|
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center text-gray-400 font-bold", children: "Initializing session..." }) }) }) }) });
|
|
@@ -7861,6 +8265,7 @@ init_avatar();
|
|
|
7861
8265
|
|
|
7862
8266
|
// src/chat/ChatThemeToggle.tsx
|
|
7863
8267
|
init_button();
|
|
8268
|
+
init_tooltip();
|
|
7864
8269
|
init_utils2();
|
|
7865
8270
|
var ChatThemeToggle = ({ className }) => {
|
|
7866
8271
|
const { isDark, toggleColorMode } = useChatTheme();
|
|
@@ -7918,6 +8323,7 @@ var buildLoggedUserProfile = (loggedUserDetails) => ({
|
|
|
7918
8323
|
|
|
7919
8324
|
// src/chat/sidebar/create-chat-dialog/CreateChatDialog.tsx
|
|
7920
8325
|
init_button();
|
|
8326
|
+
init_tooltip();
|
|
7921
8327
|
init_utils2();
|
|
7922
8328
|
|
|
7923
8329
|
// src/chat/sidebar/create-chat-dialog/useCreateChatDialog.ts
|
|
@@ -8368,6 +8774,9 @@ function GroupCreateTab({
|
|
|
8368
8774
|
) })
|
|
8369
8775
|
] });
|
|
8370
8776
|
}
|
|
8777
|
+
|
|
8778
|
+
// src/chat/components/AdminPermissionTooltip.tsx
|
|
8779
|
+
init_tooltip();
|
|
8371
8780
|
init_utils2();
|
|
8372
8781
|
function AdminPermissionTooltip({
|
|
8373
8782
|
disabled,
|
|
@@ -8994,6 +9403,7 @@ var LoggedUserSettingsContent_default = LoggedUserSettingsContent;
|
|
|
8994
9403
|
|
|
8995
9404
|
// src/chat/sidebar/LoggedUserSettingsTrigger.tsx
|
|
8996
9405
|
init_button();
|
|
9406
|
+
init_tooltip();
|
|
8997
9407
|
init_utils2();
|
|
8998
9408
|
var LoggedUserSettingsTrigger = ({
|
|
8999
9409
|
onClick,
|
|
@@ -10660,6 +11070,7 @@ init_call_store();
|
|
|
10660
11070
|
init_utils2();
|
|
10661
11071
|
|
|
10662
11072
|
// src/chat/header/header-right/OptionsMenuItem.tsx
|
|
11073
|
+
init_tooltip();
|
|
10663
11074
|
init_utils2();
|
|
10664
11075
|
function OptionsMenuItem({
|
|
10665
11076
|
icon: Icon,
|
|
@@ -11706,28 +12117,6 @@ function MessageForwardedLabel({ isSender, className, overlay }) {
|
|
|
11706
12117
|
}
|
|
11707
12118
|
);
|
|
11708
12119
|
}
|
|
11709
|
-
|
|
11710
|
-
// src/chat/lib/chat-message-bubble.ts
|
|
11711
|
-
init_utils2();
|
|
11712
|
-
function getBubbleCornerClasses(isSender) {
|
|
11713
|
-
return isSender ? "rounded-tl-[18px] rounded-tr-[18px] rounded-bl-[18px] rounded-br-none" : "rounded-tl-[18px] rounded-tr-[18px] rounded-br-[18px] rounded-bl-none";
|
|
11714
|
-
}
|
|
11715
|
-
function getChatBubbleClasses({
|
|
11716
|
-
isSender = false,
|
|
11717
|
-
surface,
|
|
11718
|
-
className
|
|
11719
|
-
}) {
|
|
11720
|
-
const resolvedSurface = surface ?? (isSender ? "sent" : "received");
|
|
11721
|
-
const isNeutral = resolvedSurface === "neutral";
|
|
11722
|
-
return cn(
|
|
11723
|
-
"relative",
|
|
11724
|
-
getBubbleCornerClasses(isSender),
|
|
11725
|
-
resolvedSurface === "sent" && "chat-bubble-sent bg-(--chat-theme) text-white",
|
|
11726
|
-
resolvedSurface === "received" && "chat-bubble-received border border-(--chat-border)/60 bg-(--chat-incoming-bubble) text-(--chat-incoming-text)",
|
|
11727
|
-
isNeutral && "chat-bubble-received border border-(--chat-border)/60 bg-(--chat-incoming-bubble) text-(--chat-incoming-text)",
|
|
11728
|
-
className
|
|
11729
|
-
);
|
|
11730
|
-
}
|
|
11731
12120
|
init_utils2();
|
|
11732
12121
|
init_client();
|
|
11733
12122
|
function getPreviewKind(name) {
|
|
@@ -16342,6 +16731,7 @@ init_avatar();
|
|
|
16342
16731
|
|
|
16343
16732
|
// src/chat/message/MessageReactions.tsx
|
|
16344
16733
|
init_utils2();
|
|
16734
|
+
init_tooltip();
|
|
16345
16735
|
var MessageReactions = ({
|
|
16346
16736
|
groupedReactions,
|
|
16347
16737
|
reactions,
|
|
@@ -20754,6 +21144,7 @@ init_normalize_helpers();
|
|
|
20754
21144
|
init_useStore();
|
|
20755
21145
|
init_open_conversation();
|
|
20756
21146
|
var RETRY_DELAYS_MS = [1e3, 3e3, 8e3, 2e4];
|
|
21147
|
+
var CHAT_HEARTBEAT_INTERVAL_MS = 15e3;
|
|
20757
21148
|
var recentToastIds = /* @__PURE__ */ new Set();
|
|
20758
21149
|
var rememberToastId = (id) => {
|
|
20759
21150
|
if (!id) return true;
|
|
@@ -20976,6 +21367,36 @@ var ForegroundPushBridge = ({ onPush }) => {
|
|
|
20976
21367
|
window.removeEventListener(PUSH_CHANGED_EVENT, onPushChanged);
|
|
20977
21368
|
};
|
|
20978
21369
|
}, []);
|
|
21370
|
+
React11.useEffect(() => {
|
|
21371
|
+
if (typeof navigator === "undefined" || !("serviceWorker" in navigator)) {
|
|
21372
|
+
return;
|
|
21373
|
+
}
|
|
21374
|
+
let interval = null;
|
|
21375
|
+
const sendHeartbeat = () => {
|
|
21376
|
+
navigator.serviceWorker.getRegistration().then(
|
|
21377
|
+
(registration) => registration?.active?.postMessage({ type: CHAT_HEARTBEAT_SW_TYPE })
|
|
21378
|
+
).catch(() => void 0);
|
|
21379
|
+
};
|
|
21380
|
+
const startHeartbeat = () => {
|
|
21381
|
+
if (interval || !getStoredPushToken()) return;
|
|
21382
|
+
sendHeartbeat();
|
|
21383
|
+
interval = setInterval(sendHeartbeat, CHAT_HEARTBEAT_INTERVAL_MS);
|
|
21384
|
+
};
|
|
21385
|
+
const stopHeartbeat = () => {
|
|
21386
|
+
if (interval) clearInterval(interval);
|
|
21387
|
+
interval = null;
|
|
21388
|
+
};
|
|
21389
|
+
startHeartbeat();
|
|
21390
|
+
const onPushChanged = (event) => {
|
|
21391
|
+
if (event.detail?.enabled) startHeartbeat();
|
|
21392
|
+
else stopHeartbeat();
|
|
21393
|
+
};
|
|
21394
|
+
window.addEventListener(PUSH_CHANGED_EVENT, onPushChanged);
|
|
21395
|
+
return () => {
|
|
21396
|
+
stopHeartbeat();
|
|
21397
|
+
window.removeEventListener(PUSH_CHANGED_EVENT, onPushChanged);
|
|
21398
|
+
};
|
|
21399
|
+
}, []);
|
|
20979
21400
|
React11.useEffect(() => {
|
|
20980
21401
|
const onOpen = (event) => {
|
|
20981
21402
|
const id = String(
|