@realtimexsco/live-chat 1.5.5 → 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 +434 -270
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +435 -271
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/PERMISSIONS.md +0 -445
package/dist/index.mjs
CHANGED
|
@@ -9,7 +9,7 @@ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
|
9
9
|
import { cva } from 'class-variance-authority';
|
|
10
10
|
import * as React11 from 'react';
|
|
11
11
|
import React11__default, { createContext, useState, useEffect, useMemo, useContext, useCallback, useRef, useLayoutEffect, Fragment as Fragment$1, useSyncExternalStore } from 'react';
|
|
12
|
-
import { Loader2, X, Users, Video, Phone, PhoneOff, Sun, Moon, Settings, Search, UserPlus, ChevronDown, ArrowLeft, WifiOff, Wifi, Sparkles, MessageSquareText, ChevronRight, Pin, Star, MoreVertical, Info, UserKey, ShieldUser, Paperclip, Clock, MessageSquareX, Trash2, LogOut, Ban, CheckCheck, Check, Camera, Save, Pencil, Mail, CornerUpLeft, CheckSquare, Smile, ChevronLeftIcon, ChevronRightIcon, ChevronDownIcon, MessageCircleMore, History, Shield, Send, AlertCircle, ShieldCheck, UserMinus, LayoutGrid, Rows3, MessageCircle, ExternalLink, Download, ChevronLeft, ZoomOut, ZoomIn, RotateCcw, Music, Hand, MicOff, MonitorUp, XIcon, ArrowRight, MoreHorizontal, PinOff, StarOff, ImageIcon, Film, Play, Pause, FileText, FileSpreadsheet, FileIcon, MessageSquare, Eye, Captions, Mic, VideoOff } from 'lucide-react';
|
|
12
|
+
import { Loader2, X, Users, Video, Phone, PhoneOff, Sun, Moon, Settings, Search, UserPlus, ChevronDown, ArrowLeft, WifiOff, Wifi, Sparkles, MessageSquareText, ChevronRight, Pin, Star, MoreVertical, Info, UserKey, ShieldUser, Paperclip, Clock, MessageSquareX, Trash2, LogOut, Ban, CheckCheck, Check, Camera, Save, Pencil, Mail, CornerUpLeft, CheckSquare, Smile, ChevronLeftIcon, ChevronRightIcon, ChevronDownIcon, MessageCircleMore, History, Shield, Send, AlertCircle, ShieldCheck, UserMinus, LayoutGrid, Rows3, MessageCircle, ExternalLink, Download, ChevronLeft, ZoomOut, ZoomIn, RotateCcw, Music, Hand, MicOff, MonitorUp, XIcon, ArrowRight, MoreHorizontal, PinOff, StarOff, ImageIcon, Film, Play, Pause, FileText, FileSpreadsheet, FileIcon, MessageSquare, Eye, Captions, Mic, VideoOff, Circle } from 'lucide-react';
|
|
13
13
|
import { flushSync } from 'react-dom';
|
|
14
14
|
import EmojiPicker, { Theme } from 'emoji-picker-react';
|
|
15
15
|
import { getDefaultClassNames, DayPicker } from 'react-day-picker';
|
|
@@ -884,12 +884,13 @@ var init_store_helpers = __esm({
|
|
|
884
884
|
});
|
|
885
885
|
|
|
886
886
|
// src/notifications/open-conversation.ts
|
|
887
|
-
var OPEN_CONVERSATION_EVENT, NOTIFICATION_CLICK_SW_TYPE, PUSH_BROADCAST_CHANNEL, PUSH_DATA_CACHE_NAME, PENDING_STORAGE_KEY, PENDING_OPEN_CACHE_PATH, resolveConversationIdFromPushData, normalizePushMeta, parsePendingRaw, peekPendingOpenConversation, peekPendingOpenRequest, consumePendingOpenConversation, consumePendingOpenRequest, requestOpenConversation, buildChannelFromPushRequest, mapConversationToChannel, stripConversationIdFromUrl, cacheRequestForPath, consumePendingOpenFromPushCache, readConversationIdFromLocation, consumedUrlConversationIds, lastHandledOpenId, lastHandledOpenAt, shouldHandleOpen, handleNotificationOpen, installNotificationClickBridge;
|
|
887
|
+
var OPEN_CONVERSATION_EVENT, NOTIFICATION_CLICK_SW_TYPE, CHAT_HEARTBEAT_SW_TYPE, PUSH_BROADCAST_CHANNEL, PUSH_DATA_CACHE_NAME, PENDING_STORAGE_KEY, PENDING_OPEN_CACHE_PATH, resolveConversationIdFromPushData, normalizePushMeta, parsePendingRaw, peekPendingOpenConversation, peekPendingOpenRequest, consumePendingOpenConversation, consumePendingOpenRequest, requestOpenConversation, buildChannelFromPushRequest, mapConversationToChannel, stripConversationIdFromUrl, cacheRequestForPath, consumePendingOpenFromPushCache, readConversationIdFromLocation, consumedUrlConversationIds, lastHandledOpenId, lastHandledOpenAt, shouldHandleOpen, handleNotificationOpen, installNotificationClickBridge;
|
|
888
888
|
var init_open_conversation = __esm({
|
|
889
889
|
"src/notifications/open-conversation.ts"() {
|
|
890
890
|
init_store_helpers();
|
|
891
891
|
OPEN_CONVERSATION_EVENT = "realtimex:open-conversation";
|
|
892
892
|
NOTIFICATION_CLICK_SW_TYPE = "realtimex:notification-click";
|
|
893
|
+
CHAT_HEARTBEAT_SW_TYPE = "realtimex:chat-heartbeat";
|
|
893
894
|
PUSH_BROADCAST_CHANNEL = "realtimex-push";
|
|
894
895
|
PUSH_DATA_CACHE_NAME = "realtimex-push-data-v1";
|
|
895
896
|
PENDING_STORAGE_KEY = "realtimex:pending-open-conversation";
|
|
@@ -4811,9 +4812,8 @@ var init_ParticipantView = __esm({
|
|
|
4811
4812
|
isHandRaised = false,
|
|
4812
4813
|
className
|
|
4813
4814
|
}) => {
|
|
4814
|
-
const { webcamStream,
|
|
4815
|
+
const { webcamStream, webcamOn, micOn, displayName, isActiveSpeaker } = sdk.useParticipant(participantId);
|
|
4815
4816
|
const videoRef = useRef(null);
|
|
4816
|
-
const audioRef = useRef(null);
|
|
4817
4817
|
const [hasFrame, setHasFrame] = useState(false);
|
|
4818
4818
|
useEffect(() => {
|
|
4819
4819
|
const el = videoRef.current;
|
|
@@ -4826,17 +4826,6 @@ var init_ParticipantView = __esm({
|
|
|
4826
4826
|
setHasFrame(false);
|
|
4827
4827
|
}
|
|
4828
4828
|
}, [webcamOn, webcamStream]);
|
|
4829
|
-
useEffect(() => {
|
|
4830
|
-
if (isLocal) return;
|
|
4831
|
-
const el = audioRef.current;
|
|
4832
|
-
if (!el) return;
|
|
4833
|
-
if (micOn && micStream?.track) {
|
|
4834
|
-
el.srcObject = new MediaStream([micStream.track]);
|
|
4835
|
-
el.play().catch(() => void 0);
|
|
4836
|
-
} else {
|
|
4837
|
-
el.srcObject = null;
|
|
4838
|
-
}
|
|
4839
|
-
}, [micOn, micStream, isLocal]);
|
|
4840
4829
|
const name = displayName || fallbackName || "Participant";
|
|
4841
4830
|
const showVideo = webcamOn && hasFrame;
|
|
4842
4831
|
return /* @__PURE__ */ jsxs(
|
|
@@ -4869,7 +4858,6 @@ var init_ParticipantView = __esm({
|
|
|
4869
4858
|
)
|
|
4870
4859
|
}
|
|
4871
4860
|
),
|
|
4872
|
-
!isLocal && /* @__PURE__ */ jsx("audio", { ref: audioRef, autoPlay: true, playsInline: true }),
|
|
4873
4861
|
isHandRaised && /* @__PURE__ */ 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__ */ jsx(Hand, { size: 14 }) }),
|
|
4874
4862
|
!showVideo && /* @__PURE__ */ jsxs(Avatar, { size: "lg", className: "size-20", children: [
|
|
4875
4863
|
/* @__PURE__ */ jsx(AvatarImage, { src: fallbackImage, alt: name }),
|
|
@@ -5036,7 +5024,8 @@ var init_CallControls = __esm({
|
|
|
5036
5024
|
isHandRaised,
|
|
5037
5025
|
onToggleRaiseHand,
|
|
5038
5026
|
isChatOpen,
|
|
5039
|
-
onToggleChat
|
|
5027
|
+
onToggleChat,
|
|
5028
|
+
isVideoActive
|
|
5040
5029
|
}) => {
|
|
5041
5030
|
const {
|
|
5042
5031
|
toggleMic,
|
|
@@ -5045,9 +5034,28 @@ var init_CallControls = __esm({
|
|
|
5045
5034
|
localWebcamOn,
|
|
5046
5035
|
localScreenShareOn,
|
|
5047
5036
|
toggleScreenShare,
|
|
5037
|
+
recordingState,
|
|
5038
|
+
startRecording,
|
|
5039
|
+
stopRecording,
|
|
5048
5040
|
leave
|
|
5049
5041
|
} = sdk.useMeeting();
|
|
5050
5042
|
const endCall = useCallStore((s) => s.endCall);
|
|
5043
|
+
const isRecording = recordingState === "RECORDING_STARTED" || recordingState === "RECORDING_STARTING";
|
|
5044
|
+
const isRecordingBusy = recordingState === "RECORDING_STARTING" || recordingState === "RECORDING_STOPPING";
|
|
5045
|
+
const handleToggleRecording = () => {
|
|
5046
|
+
if (isRecordingBusy) return;
|
|
5047
|
+
if (isRecording) {
|
|
5048
|
+
stopRecording();
|
|
5049
|
+
return;
|
|
5050
|
+
}
|
|
5051
|
+
startRecording("", "", {
|
|
5052
|
+
layout: { type: "GRID", priority: "SPEAKER", gridSize: 4 },
|
|
5053
|
+
orientation: "landscape",
|
|
5054
|
+
theme: "DEFAULT",
|
|
5055
|
+
mode: "video-and-audio",
|
|
5056
|
+
quality: "high"
|
|
5057
|
+
});
|
|
5058
|
+
};
|
|
5051
5059
|
const handleLeave = () => {
|
|
5052
5060
|
leave();
|
|
5053
5061
|
endCall();
|
|
@@ -5063,7 +5071,7 @@ var init_CallControls = __esm({
|
|
|
5063
5071
|
onClick: () => toggleMic()
|
|
5064
5072
|
}
|
|
5065
5073
|
),
|
|
5066
|
-
/* @__PURE__ */ jsx(
|
|
5074
|
+
isVideoActive ? /* @__PURE__ */ jsx(
|
|
5067
5075
|
ControlButton,
|
|
5068
5076
|
{
|
|
5069
5077
|
icon: localWebcamOn ? /* @__PURE__ */ jsx(Video, { size: 20 }) : /* @__PURE__ */ jsx(VideoOff, { size: 20 }),
|
|
@@ -5071,6 +5079,13 @@ var init_CallControls = __esm({
|
|
|
5071
5079
|
active: !localWebcamOn,
|
|
5072
5080
|
onClick: () => toggleWebcam()
|
|
5073
5081
|
}
|
|
5082
|
+
) : /* @__PURE__ */ jsx(
|
|
5083
|
+
ControlButton,
|
|
5084
|
+
{
|
|
5085
|
+
icon: /* @__PURE__ */ jsx(Video, { size: 20 }),
|
|
5086
|
+
label: "Switch to video call",
|
|
5087
|
+
onClick: () => toggleWebcam()
|
|
5088
|
+
}
|
|
5074
5089
|
),
|
|
5075
5090
|
/* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "mx-0.5 h-7 w-px shrink-0 bg-white/15" }),
|
|
5076
5091
|
/* @__PURE__ */ jsx(
|
|
@@ -5083,6 +5098,16 @@ var init_CallControls = __esm({
|
|
|
5083
5098
|
onClick: () => toggleScreenShare()
|
|
5084
5099
|
}
|
|
5085
5100
|
),
|
|
5101
|
+
/* @__PURE__ */ jsx(
|
|
5102
|
+
ControlButton,
|
|
5103
|
+
{
|
|
5104
|
+
icon: /* @__PURE__ */ jsx(Circle, { size: 14, className: cn("fill-current", isRecording && "animate-pulse") }),
|
|
5105
|
+
label: isRecording ? "Stop recording" : "Start recording",
|
|
5106
|
+
active: isRecording,
|
|
5107
|
+
activeClassName: "bg-red-600 hover:bg-red-500",
|
|
5108
|
+
onClick: handleToggleRecording
|
|
5109
|
+
}
|
|
5110
|
+
),
|
|
5086
5111
|
/* @__PURE__ */ jsx(
|
|
5087
5112
|
ControlButton,
|
|
5088
5113
|
{
|
|
@@ -5262,7 +5287,7 @@ var init_useCallReactions = __esm({
|
|
|
5262
5287
|
};
|
|
5263
5288
|
}
|
|
5264
5289
|
});
|
|
5265
|
-
var
|
|
5290
|
+
var RemoteParticipantWatcher, MeetingView, MeetingView_default;
|
|
5266
5291
|
var init_MeetingView = __esm({
|
|
5267
5292
|
"src/call/MeetingView.tsx"() {
|
|
5268
5293
|
init_ParticipantView();
|
|
@@ -5273,17 +5298,28 @@ var init_MeetingView = __esm({
|
|
|
5273
5298
|
init_useCallReactions();
|
|
5274
5299
|
init_call_store();
|
|
5275
5300
|
init_utils2();
|
|
5276
|
-
|
|
5301
|
+
RemoteParticipantWatcher = ({
|
|
5277
5302
|
sdk,
|
|
5278
5303
|
participantId,
|
|
5279
|
-
|
|
5304
|
+
onWebcamChange
|
|
5280
5305
|
}) => {
|
|
5281
|
-
const { webcamOn } = sdk.useParticipant(participantId);
|
|
5306
|
+
const { webcamOn, micStream, micOn } = sdk.useParticipant(participantId);
|
|
5307
|
+
const audioRef = useRef(null);
|
|
5282
5308
|
useEffect(() => {
|
|
5283
|
-
|
|
5284
|
-
return () =>
|
|
5309
|
+
onWebcamChange(participantId, webcamOn);
|
|
5310
|
+
return () => onWebcamChange(participantId, false);
|
|
5285
5311
|
}, [participantId, webcamOn]);
|
|
5286
|
-
|
|
5312
|
+
useEffect(() => {
|
|
5313
|
+
const el = audioRef.current;
|
|
5314
|
+
if (!el) return;
|
|
5315
|
+
if (micOn && micStream?.track) {
|
|
5316
|
+
el.srcObject = new MediaStream([micStream.track]);
|
|
5317
|
+
el.play().catch(() => void 0);
|
|
5318
|
+
} else {
|
|
5319
|
+
el.srcObject = null;
|
|
5320
|
+
}
|
|
5321
|
+
}, [micOn, micStream]);
|
|
5322
|
+
return /* @__PURE__ */ jsx("audio", { ref: audioRef, autoPlay: true, playsInline: true });
|
|
5287
5323
|
};
|
|
5288
5324
|
MeetingView = ({
|
|
5289
5325
|
sdk,
|
|
@@ -5336,7 +5372,17 @@ var init_MeetingView = __esm({
|
|
|
5336
5372
|
(id) => id !== localParticipant?.id
|
|
5337
5373
|
);
|
|
5338
5374
|
const isGroup = remoteIds.length > 1;
|
|
5339
|
-
const
|
|
5375
|
+
const remoteParticipantWatchers = remoteIds.map((id) => /* @__PURE__ */ jsx(
|
|
5376
|
+
RemoteParticipantWatcher,
|
|
5377
|
+
{
|
|
5378
|
+
sdk,
|
|
5379
|
+
participantId: id,
|
|
5380
|
+
onWebcamChange: handleRemoteWebcamChange
|
|
5381
|
+
},
|
|
5382
|
+
id
|
|
5383
|
+
));
|
|
5384
|
+
const anyRemoteWebcamOn = Object.values(remoteWebcamOn).some(Boolean);
|
|
5385
|
+
const showVideoGrid = mode === "video" || localWebcamOn || anyRemoteWebcamOn;
|
|
5340
5386
|
const controls = /* @__PURE__ */ jsx(
|
|
5341
5387
|
CallControls_default,
|
|
5342
5388
|
{
|
|
@@ -5345,7 +5391,8 @@ var init_MeetingView = __esm({
|
|
|
5345
5391
|
isHandRaised,
|
|
5346
5392
|
onToggleRaiseHand: toggleRaiseHand,
|
|
5347
5393
|
isChatOpen,
|
|
5348
|
-
onToggleChat
|
|
5394
|
+
onToggleChat,
|
|
5395
|
+
isVideoActive: showVideoGrid
|
|
5349
5396
|
}
|
|
5350
5397
|
);
|
|
5351
5398
|
const connectionStatusText = meetingState === "CONNECTING" ? "Connecting\u2026" : meetingState === "DISCONNECTED" ? "Reconnecting\u2026" : meetingState === "FAILED" ? "Connection lost" : null;
|
|
@@ -5355,7 +5402,7 @@ var init_MeetingView = __esm({
|
|
|
5355
5402
|
] });
|
|
5356
5403
|
if (presenterId) {
|
|
5357
5404
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5358
|
-
|
|
5405
|
+
remoteParticipantWatchers,
|
|
5359
5406
|
/* @__PURE__ */ jsxs("div", { className: "relative flex flex-1 flex-col", children: [
|
|
5360
5407
|
statusBanner,
|
|
5361
5408
|
/* @__PURE__ */ jsx(FloatingReactions_default, { reactions: floatingReactions }),
|
|
@@ -5396,11 +5443,9 @@ var init_MeetingView = __esm({
|
|
|
5396
5443
|
] })
|
|
5397
5444
|
] });
|
|
5398
5445
|
}
|
|
5399
|
-
const anyRemoteWebcamOn = Object.values(remoteWebcamOn).some(Boolean);
|
|
5400
|
-
const showVideoGrid = mode === "video" || localWebcamOn || anyRemoteWebcamOn;
|
|
5401
5446
|
if (!showVideoGrid) {
|
|
5402
5447
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5403
|
-
|
|
5448
|
+
remoteParticipantWatchers,
|
|
5404
5449
|
/* @__PURE__ */ jsxs("div", { className: "relative flex flex-1 flex-col", children: [
|
|
5405
5450
|
statusBanner,
|
|
5406
5451
|
/* @__PURE__ */ jsx(FloatingReactions_default, { reactions: floatingReactions }),
|
|
@@ -5423,7 +5468,7 @@ var init_MeetingView = __esm({
|
|
|
5423
5468
|
(id) => !!id && id !== focusedId
|
|
5424
5469
|
) : [];
|
|
5425
5470
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5426
|
-
|
|
5471
|
+
remoteParticipantWatchers,
|
|
5427
5472
|
/* @__PURE__ */ jsxs("div", { className: "relative flex flex-1 flex-col", children: [
|
|
5428
5473
|
statusBanner,
|
|
5429
5474
|
/* @__PURE__ */ jsx(FloatingReactions_default, { reactions: floatingReactions }),
|
|
@@ -6533,7 +6578,186 @@ init_useStore();
|
|
|
6533
6578
|
init_store_helpers();
|
|
6534
6579
|
init_utils2();
|
|
6535
6580
|
init_button();
|
|
6581
|
+
|
|
6582
|
+
// src/chat/lib/chat-theme.ts
|
|
6583
|
+
init_utils2();
|
|
6584
|
+
var getChatScopeClass = (isDark) => cn("chat-theme-scope", isDark && "dark");
|
|
6585
|
+
var chatSheetContentClass = "flex w-full flex-col gap-0 p-0 bg-(--chat-surface) text-(--chat-text)";
|
|
6586
|
+
var chatSheetHeaderClass = "border-b border-(--chat-border) px-4 py-3 pr-11 text-left";
|
|
6587
|
+
var chatSheetBodyClass = "chat-message-scroll flex-1 overflow-y-auto bg-(--chat-surface) p-3";
|
|
6588
|
+
var chatSheetTitleClass = "text-[13px] font-semibold tracking-tight text-(--chat-text)";
|
|
6589
|
+
var chatSheetSubtitleClass = "text-[11px] text-(--chat-muted)";
|
|
6590
|
+
var chatDetailRowClass = "flex items-start justify-between gap-3 border-b border-(--chat-border) py-2.5 last:border-b-0";
|
|
6591
|
+
var chatDetailLabelClass = "text-[11px] text-(--chat-muted)";
|
|
6592
|
+
var chatDetailValueClass = "text-[13px] font-medium text-(--chat-text) text-right";
|
|
6593
|
+
var chatDialogContentClass = "overflow-hidden rounded-2xl border border-(--chat-border) bg-(--chat-surface) p-0 text-(--chat-text) shadow-[var(--chat-shadow)]";
|
|
6594
|
+
var chatDropdownContentClass = "rounded-xl border border-(--chat-border) bg-(--chat-surface) text-(--chat-text) shadow-lg";
|
|
6595
|
+
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)]";
|
|
6596
|
+
var chatOptionsMenuLabelClass = "px-2.5 pb-0.5 pt-1 text-[10px] font-semibold uppercase tracking-[0.12em] text-(--chat-muted)";
|
|
6597
|
+
var chatOptionsMenuSeparatorClass = "my-1.5 h-px bg-(--chat-border)";
|
|
6598
|
+
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)";
|
|
6599
|
+
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)";
|
|
6600
|
+
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)";
|
|
6601
|
+
var chatPopoverContentClass = "w-auto border border-(--chat-border) bg-(--chat-surface) p-0 text-(--chat-text) shadow-2xl";
|
|
6602
|
+
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)";
|
|
6603
|
+
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)]";
|
|
6604
|
+
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";
|
|
6605
|
+
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)";
|
|
6606
|
+
var chatListItemClass = "transition-colors hover:bg-(--chat-hover)";
|
|
6607
|
+
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";
|
|
6608
|
+
var chatDrawerSectionHeadingClass = "mb-1 px-0.5 text-[10px] font-semibold tracking-wide text-(--chat-muted)";
|
|
6609
|
+
var chatHeaderToolbarIconProps = { size: 14, strokeWidth: 1.75 };
|
|
6610
|
+
var chatSavedMessageModalIconClass = "shrink-0 text-(--chat-theme)";
|
|
6611
|
+
var chatHeaderToolbarIconLgProps = { size: 22, strokeWidth: 1.75 };
|
|
6612
|
+
var chatHeaderToolbarIconSmProps = { size: 11, strokeWidth: 1.75 };
|
|
6613
|
+
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";
|
|
6614
|
+
var chatDrawerFileIconWrapClass = "flex size-8 shrink-0 items-center justify-center rounded-md bg-(--chat-hover)";
|
|
6615
|
+
var chatDrawerMediaFrameClass = "overflow-hidden rounded-md border border-(--chat-border)/70 bg-(--chat-elevated)";
|
|
6616
|
+
var buildChatThemeStyles = (themeColor) => ({
|
|
6617
|
+
"--chat-theme": themeColor,
|
|
6618
|
+
"--chat-theme-5": `${themeColor}0D`,
|
|
6619
|
+
"--chat-theme-10": `${themeColor}1A`,
|
|
6620
|
+
"--chat-theme-20": `${themeColor}33`,
|
|
6621
|
+
"--chat-theme-40": `${themeColor}66`,
|
|
6622
|
+
"--chat-theme-60": `${themeColor}99`,
|
|
6623
|
+
"--read-tick-color": themeColor.toLowerCase() === "#0000ff" || themeColor.toLowerCase().includes("007aff") ? "#00e5ff" : "#40C4FF"
|
|
6624
|
+
});
|
|
6625
|
+
|
|
6626
|
+
// src/chat/lib/chat-theme-storage.ts
|
|
6627
|
+
var STORAGE_KEY = "chat-color-mode";
|
|
6628
|
+
var loadChatColorMode = () => {
|
|
6629
|
+
if (typeof window === "undefined") return null;
|
|
6630
|
+
try {
|
|
6631
|
+
const stored = localStorage.getItem(STORAGE_KEY);
|
|
6632
|
+
return stored === "dark" || stored === "light" ? stored : null;
|
|
6633
|
+
} catch {
|
|
6634
|
+
return null;
|
|
6635
|
+
}
|
|
6636
|
+
};
|
|
6637
|
+
var saveChatColorMode = (mode) => {
|
|
6638
|
+
if (typeof window === "undefined") return;
|
|
6639
|
+
try {
|
|
6640
|
+
localStorage.setItem(STORAGE_KEY, mode);
|
|
6641
|
+
} catch {
|
|
6642
|
+
}
|
|
6643
|
+
};
|
|
6644
|
+
var CHAT_THEME_SHELL_CLASS = "chat-theme-shell";
|
|
6645
|
+
function withThemeTransition(apply) {
|
|
6646
|
+
if (typeof document === "undefined") {
|
|
6647
|
+
apply();
|
|
6648
|
+
return;
|
|
6649
|
+
}
|
|
6650
|
+
flushSync(apply);
|
|
6651
|
+
}
|
|
6652
|
+
|
|
6653
|
+
// src/context/ChatThemeContext.tsx
|
|
6654
|
+
init_utils2();
|
|
6655
|
+
var ChatThemeContext = createContext(null);
|
|
6656
|
+
var ChatThemeProvider = ({
|
|
6657
|
+
children,
|
|
6658
|
+
themeColor,
|
|
6659
|
+
colorMode,
|
|
6660
|
+
defaultColorMode = "light",
|
|
6661
|
+
onColorModeChange,
|
|
6662
|
+
showColorModeToggle = true
|
|
6663
|
+
}) => {
|
|
6664
|
+
const isControlled = colorMode !== void 0;
|
|
6665
|
+
const [internalMode, setInternalMode] = useState(defaultColorMode);
|
|
6666
|
+
const [isThemeTransitionReady, setIsThemeTransitionReady] = useState(false);
|
|
6667
|
+
const skipThemeTransitionRef = useRef(true);
|
|
6668
|
+
useLayoutEffect(() => {
|
|
6669
|
+
if (!isControlled) {
|
|
6670
|
+
const stored = loadChatColorMode();
|
|
6671
|
+
if (stored) {
|
|
6672
|
+
setInternalMode(stored);
|
|
6673
|
+
}
|
|
6674
|
+
}
|
|
6675
|
+
const frame = requestAnimationFrame(() => {
|
|
6676
|
+
skipThemeTransitionRef.current = false;
|
|
6677
|
+
setIsThemeTransitionReady(true);
|
|
6678
|
+
});
|
|
6679
|
+
return () => cancelAnimationFrame(frame);
|
|
6680
|
+
}, [isControlled]);
|
|
6681
|
+
const resolvedMode = isControlled ? colorMode : internalMode;
|
|
6682
|
+
const isDark = resolvedMode === "dark";
|
|
6683
|
+
const setColorMode = useCallback(
|
|
6684
|
+
(mode) => {
|
|
6685
|
+
const apply = () => {
|
|
6686
|
+
if (!isControlled) {
|
|
6687
|
+
setInternalMode(mode);
|
|
6688
|
+
saveChatColorMode(mode);
|
|
6689
|
+
}
|
|
6690
|
+
onColorModeChange?.(mode);
|
|
6691
|
+
};
|
|
6692
|
+
if (skipThemeTransitionRef.current) {
|
|
6693
|
+
apply();
|
|
6694
|
+
return;
|
|
6695
|
+
}
|
|
6696
|
+
withThemeTransition(apply);
|
|
6697
|
+
},
|
|
6698
|
+
[isControlled, onColorModeChange]
|
|
6699
|
+
);
|
|
6700
|
+
const toggleColorMode = useCallback(() => {
|
|
6701
|
+
setColorMode(resolvedMode === "dark" ? "light" : "dark");
|
|
6702
|
+
}, [resolvedMode, setColorMode]);
|
|
6703
|
+
const value = useMemo(
|
|
6704
|
+
() => ({
|
|
6705
|
+
colorMode: resolvedMode,
|
|
6706
|
+
isDark,
|
|
6707
|
+
isThemeTransitionReady,
|
|
6708
|
+
themeColor,
|
|
6709
|
+
themeStyles: buildChatThemeStyles(themeColor),
|
|
6710
|
+
scopeClassName: cn(
|
|
6711
|
+
getChatScopeClass(isDark),
|
|
6712
|
+
!isThemeTransitionReady && "chat-theme-no-transition"
|
|
6713
|
+
),
|
|
6714
|
+
setColorMode,
|
|
6715
|
+
toggleColorMode,
|
|
6716
|
+
showColorModeToggle
|
|
6717
|
+
}),
|
|
6718
|
+
[
|
|
6719
|
+
resolvedMode,
|
|
6720
|
+
isDark,
|
|
6721
|
+
isThemeTransitionReady,
|
|
6722
|
+
themeColor,
|
|
6723
|
+
setColorMode,
|
|
6724
|
+
toggleColorMode,
|
|
6725
|
+
showColorModeToggle
|
|
6726
|
+
]
|
|
6727
|
+
);
|
|
6728
|
+
return /* @__PURE__ */ jsx(ChatThemeContext.Provider, { value, children });
|
|
6729
|
+
};
|
|
6730
|
+
var useChatTheme = () => {
|
|
6731
|
+
const context = useContext(ChatThemeContext);
|
|
6732
|
+
if (!context) {
|
|
6733
|
+
throw new Error("useChatTheme must be used within ChatThemeProvider");
|
|
6734
|
+
}
|
|
6735
|
+
return context;
|
|
6736
|
+
};
|
|
6737
|
+
|
|
6738
|
+
// src/chat/lib/chat-message-bubble.ts
|
|
6739
|
+
init_utils2();
|
|
6740
|
+
function getBubbleCornerClasses(isSender) {
|
|
6741
|
+
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";
|
|
6742
|
+
}
|
|
6743
|
+
function getChatBubbleClasses({
|
|
6744
|
+
isSender = false,
|
|
6745
|
+
surface,
|
|
6746
|
+
className
|
|
6747
|
+
}) {
|
|
6748
|
+
const resolvedSurface = surface ?? (isSender ? "sent" : "received");
|
|
6749
|
+
const isNeutral = resolvedSurface === "neutral";
|
|
6750
|
+
return cn(
|
|
6751
|
+
"relative",
|
|
6752
|
+
getBubbleCornerClasses(isSender),
|
|
6753
|
+
resolvedSurface === "sent" && "chat-bubble-sent bg-(--chat-theme) text-white",
|
|
6754
|
+
resolvedSurface === "received" && "chat-bubble-received border border-(--chat-border)/60 bg-(--chat-incoming-bubble) text-(--chat-incoming-text)",
|
|
6755
|
+
isNeutral && "chat-bubble-received border border-(--chat-border)/60 bg-(--chat-incoming-bubble) text-(--chat-incoming-text)",
|
|
6756
|
+
className
|
|
6757
|
+
);
|
|
6758
|
+
}
|
|
6536
6759
|
var CallChatPanel = ({ conversationId, isGroupCall, onClose, className }) => {
|
|
6760
|
+
const { scopeClassName, themeStyles } = useChatTheme();
|
|
6537
6761
|
const rawMessages = useStore((s) => s.messagesByConversation[conversationId]);
|
|
6538
6762
|
const loggedUserDetails = useStore((s) => s.loggedUserDetails);
|
|
6539
6763
|
const conversations = useStore((s) => s.conversations);
|
|
@@ -6604,68 +6828,89 @@ var CallChatPanel = ({ conversationId, isGroupCall, onClose, className }) => {
|
|
|
6604
6828
|
emitDmSend(payload);
|
|
6605
6829
|
}
|
|
6606
6830
|
};
|
|
6607
|
-
return /* @__PURE__ */ jsxs(
|
|
6608
|
-
|
|
6609
|
-
|
|
6610
|
-
|
|
6611
|
-
|
|
6612
|
-
|
|
6613
|
-
|
|
6614
|
-
"aria-label": "Close chat panel",
|
|
6615
|
-
onClick: onClose,
|
|
6616
|
-
className: "flex size-7 items-center justify-center rounded-lg text-white/60 transition-colors hover:bg-white/10 hover:text-white",
|
|
6617
|
-
children: /* @__PURE__ */ jsx(X, { size: 16 })
|
|
6618
|
-
}
|
|
6619
|
-
)
|
|
6620
|
-
] }),
|
|
6621
|
-
/* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-3 overflow-y-auto px-4 py-3", children: [
|
|
6622
|
-
messages.length === 0 && /* @__PURE__ */ jsx("p", { className: "pt-6 text-center text-xs text-white/40", children: "No messages yet \u2014 say hi without leaving the call." }),
|
|
6623
|
-
messages.map((message) => /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col", message.isOwn && "items-end"), children: [
|
|
6624
|
-
/* @__PURE__ */ jsx("span", { className: "mb-0.5 text-[11px] font-medium text-white/40", children: message.isOwn ? "You" : message.senderName }),
|
|
6625
|
-
/* @__PURE__ */ jsx(
|
|
6626
|
-
"div",
|
|
6627
|
-
{
|
|
6628
|
-
className: cn(
|
|
6629
|
-
"max-w-[85%] rounded-2xl px-3 py-1.5 text-sm break-words",
|
|
6630
|
-
message.isOwn ? "rounded-br-sm bg-(--chat-theme,#4f46e5) text-white" : "rounded-bl-sm bg-white/10 text-white/90",
|
|
6631
|
-
message.pending && "opacity-60"
|
|
6632
|
-
),
|
|
6633
|
-
children: message.content
|
|
6634
|
-
}
|
|
6635
|
-
)
|
|
6636
|
-
] }, message.id)),
|
|
6637
|
-
/* @__PURE__ */ jsx("div", { ref: listEndRef })
|
|
6638
|
-
] }),
|
|
6639
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-t border-white/10 p-3", children: [
|
|
6640
|
-
/* @__PURE__ */ jsx(
|
|
6641
|
-
"input",
|
|
6642
|
-
{
|
|
6643
|
-
value: text,
|
|
6644
|
-
onChange: (e) => setText(e.target.value),
|
|
6645
|
-
onKeyDown: (e) => {
|
|
6646
|
-
if (e.key === "Enter" && !e.shiftKey) {
|
|
6647
|
-
e.preventDefault();
|
|
6648
|
-
handleSend();
|
|
6649
|
-
}
|
|
6650
|
-
},
|
|
6651
|
-
placeholder: "Message\u2026",
|
|
6652
|
-
className: "min-w-0 flex-1 rounded-full border border-white/10 bg-white/5 px-3.5 py-2 text-sm text-white placeholder:text-white/40 focus:outline-none focus:ring-1 focus:ring-white/30"
|
|
6653
|
-
}
|
|
6831
|
+
return /* @__PURE__ */ jsxs(
|
|
6832
|
+
"div",
|
|
6833
|
+
{
|
|
6834
|
+
className: cn(
|
|
6835
|
+
scopeClassName,
|
|
6836
|
+
"flex flex-col border-l border-(--chat-border) bg-(--chat-surface) text-(--chat-text)",
|
|
6837
|
+
className
|
|
6654
6838
|
),
|
|
6655
|
-
|
|
6656
|
-
|
|
6657
|
-
{
|
|
6658
|
-
|
|
6659
|
-
|
|
6660
|
-
|
|
6661
|
-
|
|
6662
|
-
|
|
6663
|
-
|
|
6664
|
-
|
|
6665
|
-
|
|
6666
|
-
|
|
6667
|
-
|
|
6668
|
-
|
|
6839
|
+
style: themeStyles,
|
|
6840
|
+
children: [
|
|
6841
|
+
/* @__PURE__ */ jsxs("div", { className: cn(chatSheetHeaderClass, "flex items-center justify-between"), children: [
|
|
6842
|
+
/* @__PURE__ */ jsx("p", { className: chatSheetTitleClass, children: "In-call chat" }),
|
|
6843
|
+
/* @__PURE__ */ jsx(
|
|
6844
|
+
"button",
|
|
6845
|
+
{
|
|
6846
|
+
type: "button",
|
|
6847
|
+
"aria-label": "Close chat panel",
|
|
6848
|
+
onClick: onClose,
|
|
6849
|
+
className: "flex size-7 items-center justify-center rounded-lg text-(--chat-muted) transition-colors hover:bg-(--chat-hover) hover:text-(--chat-text)",
|
|
6850
|
+
children: /* @__PURE__ */ jsx(X, { size: 16 })
|
|
6851
|
+
}
|
|
6852
|
+
)
|
|
6853
|
+
] }),
|
|
6854
|
+
/* @__PURE__ */ jsxs("div", { className: cn(chatSheetBodyClass, "space-y-3"), children: [
|
|
6855
|
+
messages.length === 0 && /* @__PURE__ */ jsx("p", { className: "pt-6 text-center text-xs text-(--chat-muted)", children: "No messages yet \u2014 say hi without leaving the call." }),
|
|
6856
|
+
messages.map((message) => /* @__PURE__ */ jsxs(
|
|
6857
|
+
"div",
|
|
6858
|
+
{
|
|
6859
|
+
className: cn("flex flex-col", message.isOwn ? "items-end" : "items-start"),
|
|
6860
|
+
children: [
|
|
6861
|
+
/* @__PURE__ */ jsx("span", { className: "mb-0.5 text-[11px] font-medium text-(--chat-muted)", children: message.isOwn ? "You" : message.senderName }),
|
|
6862
|
+
/* @__PURE__ */ jsx(
|
|
6863
|
+
"div",
|
|
6864
|
+
{
|
|
6865
|
+
className: cn(
|
|
6866
|
+
getChatBubbleClasses({ isSender: message.isOwn }),
|
|
6867
|
+
"max-w-[85%] px-3 py-1.5 text-sm break-words",
|
|
6868
|
+
message.pending && "opacity-60"
|
|
6869
|
+
),
|
|
6870
|
+
children: message.content
|
|
6871
|
+
}
|
|
6872
|
+
)
|
|
6873
|
+
]
|
|
6874
|
+
},
|
|
6875
|
+
message.id
|
|
6876
|
+
)),
|
|
6877
|
+
/* @__PURE__ */ jsx("div", { ref: listEndRef })
|
|
6878
|
+
] }),
|
|
6879
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-t border-(--chat-border) p-3", children: [
|
|
6880
|
+
/* @__PURE__ */ jsx(
|
|
6881
|
+
"input",
|
|
6882
|
+
{
|
|
6883
|
+
value: text,
|
|
6884
|
+
onChange: (e) => setText(e.target.value),
|
|
6885
|
+
onKeyDown: (e) => {
|
|
6886
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
6887
|
+
e.preventDefault();
|
|
6888
|
+
handleSend();
|
|
6889
|
+
}
|
|
6890
|
+
},
|
|
6891
|
+
placeholder: "Message\u2026",
|
|
6892
|
+
className: cn(chatInputClass, "min-w-0 flex-1 rounded-full px-3.5 py-2 text-sm")
|
|
6893
|
+
}
|
|
6894
|
+
),
|
|
6895
|
+
/* @__PURE__ */ jsx(
|
|
6896
|
+
Button,
|
|
6897
|
+
{
|
|
6898
|
+
variant: "ghost",
|
|
6899
|
+
size: "icon",
|
|
6900
|
+
"aria-label": "Send message",
|
|
6901
|
+
disabled: !text.trim(),
|
|
6902
|
+
onClick: handleSend,
|
|
6903
|
+
className: cn(
|
|
6904
|
+
"size-9 shrink-0 rounded-full transition-colors",
|
|
6905
|
+
text.trim() ? "bg-(--chat-theme) text-white hover:opacity-90" : "bg-(--chat-hover) text-(--chat-muted)"
|
|
6906
|
+
),
|
|
6907
|
+
children: /* @__PURE__ */ jsx(Send, { size: 16 })
|
|
6908
|
+
}
|
|
6909
|
+
)
|
|
6910
|
+
] })
|
|
6911
|
+
]
|
|
6912
|
+
}
|
|
6913
|
+
);
|
|
6669
6914
|
};
|
|
6670
6915
|
var CallChatPanel_default = CallChatPanel;
|
|
6671
6916
|
var CallSession2 = React11__default.lazy(() => Promise.resolve().then(() => (init_CallSession(), CallSession_exports)));
|
|
@@ -7125,162 +7370,6 @@ function AlertDialogCancel({
|
|
|
7125
7370
|
|
|
7126
7371
|
// src/chat/ChatOverlay.tsx
|
|
7127
7372
|
init_utils2();
|
|
7128
|
-
|
|
7129
|
-
// src/chat/lib/chat-theme.ts
|
|
7130
|
-
init_utils2();
|
|
7131
|
-
var getChatScopeClass = (isDark) => cn("chat-theme-scope", isDark && "dark");
|
|
7132
|
-
var chatSheetContentClass = "flex w-full flex-col gap-0 p-0 bg-(--chat-surface) text-(--chat-text)";
|
|
7133
|
-
var chatSheetHeaderClass = "border-b border-(--chat-border) px-4 py-3 pr-11 text-left";
|
|
7134
|
-
var chatSheetBodyClass = "chat-message-scroll flex-1 overflow-y-auto bg-(--chat-surface) p-3";
|
|
7135
|
-
var chatSheetTitleClass = "text-[13px] font-semibold tracking-tight text-(--chat-text)";
|
|
7136
|
-
var chatSheetSubtitleClass = "text-[11px] text-(--chat-muted)";
|
|
7137
|
-
var chatDetailRowClass = "flex items-start justify-between gap-3 border-b border-(--chat-border) py-2.5 last:border-b-0";
|
|
7138
|
-
var chatDetailLabelClass = "text-[11px] text-(--chat-muted)";
|
|
7139
|
-
var chatDetailValueClass = "text-[13px] font-medium text-(--chat-text) text-right";
|
|
7140
|
-
var chatDialogContentClass = "overflow-hidden rounded-2xl border border-(--chat-border) bg-(--chat-surface) p-0 text-(--chat-text) shadow-[var(--chat-shadow)]";
|
|
7141
|
-
var chatDropdownContentClass = "rounded-xl border border-(--chat-border) bg-(--chat-surface) text-(--chat-text) shadow-lg";
|
|
7142
|
-
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)]";
|
|
7143
|
-
var chatOptionsMenuLabelClass = "px-2.5 pb-0.5 pt-1 text-[10px] font-semibold uppercase tracking-[0.12em] text-(--chat-muted)";
|
|
7144
|
-
var chatOptionsMenuSeparatorClass = "my-1.5 h-px bg-(--chat-border)";
|
|
7145
|
-
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)";
|
|
7146
|
-
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)";
|
|
7147
|
-
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)";
|
|
7148
|
-
var chatPopoverContentClass = "w-auto border border-(--chat-border) bg-(--chat-surface) p-0 text-(--chat-text) shadow-2xl";
|
|
7149
|
-
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)";
|
|
7150
|
-
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)]";
|
|
7151
|
-
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";
|
|
7152
|
-
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)";
|
|
7153
|
-
var chatListItemClass = "transition-colors hover:bg-(--chat-hover)";
|
|
7154
|
-
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";
|
|
7155
|
-
var chatDrawerSectionHeadingClass = "mb-1 px-0.5 text-[10px] font-semibold tracking-wide text-(--chat-muted)";
|
|
7156
|
-
var chatHeaderToolbarIconProps = { size: 14, strokeWidth: 1.75 };
|
|
7157
|
-
var chatSavedMessageModalIconClass = "shrink-0 text-(--chat-theme)";
|
|
7158
|
-
var chatHeaderToolbarIconLgProps = { size: 22, strokeWidth: 1.75 };
|
|
7159
|
-
var chatHeaderToolbarIconSmProps = { size: 11, strokeWidth: 1.75 };
|
|
7160
|
-
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";
|
|
7161
|
-
var chatDrawerFileIconWrapClass = "flex size-8 shrink-0 items-center justify-center rounded-md bg-(--chat-hover)";
|
|
7162
|
-
var chatDrawerMediaFrameClass = "overflow-hidden rounded-md border border-(--chat-border)/70 bg-(--chat-elevated)";
|
|
7163
|
-
var buildChatThemeStyles = (themeColor) => ({
|
|
7164
|
-
"--chat-theme": themeColor,
|
|
7165
|
-
"--chat-theme-5": `${themeColor}0D`,
|
|
7166
|
-
"--chat-theme-10": `${themeColor}1A`,
|
|
7167
|
-
"--chat-theme-20": `${themeColor}33`,
|
|
7168
|
-
"--chat-theme-40": `${themeColor}66`,
|
|
7169
|
-
"--chat-theme-60": `${themeColor}99`,
|
|
7170
|
-
"--read-tick-color": themeColor.toLowerCase() === "#0000ff" || themeColor.toLowerCase().includes("007aff") ? "#00e5ff" : "#40C4FF"
|
|
7171
|
-
});
|
|
7172
|
-
|
|
7173
|
-
// src/chat/lib/chat-theme-storage.ts
|
|
7174
|
-
var STORAGE_KEY = "chat-color-mode";
|
|
7175
|
-
var loadChatColorMode = () => {
|
|
7176
|
-
if (typeof window === "undefined") return null;
|
|
7177
|
-
try {
|
|
7178
|
-
const stored = localStorage.getItem(STORAGE_KEY);
|
|
7179
|
-
return stored === "dark" || stored === "light" ? stored : null;
|
|
7180
|
-
} catch {
|
|
7181
|
-
return null;
|
|
7182
|
-
}
|
|
7183
|
-
};
|
|
7184
|
-
var saveChatColorMode = (mode) => {
|
|
7185
|
-
if (typeof window === "undefined") return;
|
|
7186
|
-
try {
|
|
7187
|
-
localStorage.setItem(STORAGE_KEY, mode);
|
|
7188
|
-
} catch {
|
|
7189
|
-
}
|
|
7190
|
-
};
|
|
7191
|
-
var CHAT_THEME_SHELL_CLASS = "chat-theme-shell";
|
|
7192
|
-
function withThemeTransition(apply) {
|
|
7193
|
-
if (typeof document === "undefined") {
|
|
7194
|
-
apply();
|
|
7195
|
-
return;
|
|
7196
|
-
}
|
|
7197
|
-
flushSync(apply);
|
|
7198
|
-
}
|
|
7199
|
-
|
|
7200
|
-
// src/context/ChatThemeContext.tsx
|
|
7201
|
-
init_utils2();
|
|
7202
|
-
var ChatThemeContext = createContext(null);
|
|
7203
|
-
var ChatThemeProvider = ({
|
|
7204
|
-
children,
|
|
7205
|
-
themeColor,
|
|
7206
|
-
colorMode,
|
|
7207
|
-
defaultColorMode = "light",
|
|
7208
|
-
onColorModeChange,
|
|
7209
|
-
showColorModeToggle = true
|
|
7210
|
-
}) => {
|
|
7211
|
-
const isControlled = colorMode !== void 0;
|
|
7212
|
-
const [internalMode, setInternalMode] = useState(defaultColorMode);
|
|
7213
|
-
const [isThemeTransitionReady, setIsThemeTransitionReady] = useState(false);
|
|
7214
|
-
const skipThemeTransitionRef = useRef(true);
|
|
7215
|
-
useLayoutEffect(() => {
|
|
7216
|
-
if (!isControlled) {
|
|
7217
|
-
const stored = loadChatColorMode();
|
|
7218
|
-
if (stored) {
|
|
7219
|
-
setInternalMode(stored);
|
|
7220
|
-
}
|
|
7221
|
-
}
|
|
7222
|
-
const frame = requestAnimationFrame(() => {
|
|
7223
|
-
skipThemeTransitionRef.current = false;
|
|
7224
|
-
setIsThemeTransitionReady(true);
|
|
7225
|
-
});
|
|
7226
|
-
return () => cancelAnimationFrame(frame);
|
|
7227
|
-
}, [isControlled]);
|
|
7228
|
-
const resolvedMode = isControlled ? colorMode : internalMode;
|
|
7229
|
-
const isDark = resolvedMode === "dark";
|
|
7230
|
-
const setColorMode = useCallback(
|
|
7231
|
-
(mode) => {
|
|
7232
|
-
const apply = () => {
|
|
7233
|
-
if (!isControlled) {
|
|
7234
|
-
setInternalMode(mode);
|
|
7235
|
-
saveChatColorMode(mode);
|
|
7236
|
-
}
|
|
7237
|
-
onColorModeChange?.(mode);
|
|
7238
|
-
};
|
|
7239
|
-
if (skipThemeTransitionRef.current) {
|
|
7240
|
-
apply();
|
|
7241
|
-
return;
|
|
7242
|
-
}
|
|
7243
|
-
withThemeTransition(apply);
|
|
7244
|
-
},
|
|
7245
|
-
[isControlled, onColorModeChange]
|
|
7246
|
-
);
|
|
7247
|
-
const toggleColorMode = useCallback(() => {
|
|
7248
|
-
setColorMode(resolvedMode === "dark" ? "light" : "dark");
|
|
7249
|
-
}, [resolvedMode, setColorMode]);
|
|
7250
|
-
const value = useMemo(
|
|
7251
|
-
() => ({
|
|
7252
|
-
colorMode: resolvedMode,
|
|
7253
|
-
isDark,
|
|
7254
|
-
isThemeTransitionReady,
|
|
7255
|
-
themeColor,
|
|
7256
|
-
themeStyles: buildChatThemeStyles(themeColor),
|
|
7257
|
-
scopeClassName: cn(
|
|
7258
|
-
getChatScopeClass(isDark),
|
|
7259
|
-
!isThemeTransitionReady && "chat-theme-no-transition"
|
|
7260
|
-
),
|
|
7261
|
-
setColorMode,
|
|
7262
|
-
toggleColorMode,
|
|
7263
|
-
showColorModeToggle
|
|
7264
|
-
}),
|
|
7265
|
-
[
|
|
7266
|
-
resolvedMode,
|
|
7267
|
-
isDark,
|
|
7268
|
-
isThemeTransitionReady,
|
|
7269
|
-
themeColor,
|
|
7270
|
-
setColorMode,
|
|
7271
|
-
toggleColorMode,
|
|
7272
|
-
showColorModeToggle
|
|
7273
|
-
]
|
|
7274
|
-
);
|
|
7275
|
-
return /* @__PURE__ */ jsx(ChatThemeContext.Provider, { value, children });
|
|
7276
|
-
};
|
|
7277
|
-
var useChatTheme = () => {
|
|
7278
|
-
const context = useContext(ChatThemeContext);
|
|
7279
|
-
if (!context) {
|
|
7280
|
-
throw new Error("useChatTheme must be used within ChatThemeProvider");
|
|
7281
|
-
}
|
|
7282
|
-
return context;
|
|
7283
|
-
};
|
|
7284
7373
|
var ChatSheetContent = ({
|
|
7285
7374
|
className,
|
|
7286
7375
|
style,
|
|
@@ -7336,6 +7425,66 @@ init_avatar();
|
|
|
7336
7425
|
init_button();
|
|
7337
7426
|
init_utils2();
|
|
7338
7427
|
init_call_store();
|
|
7428
|
+
|
|
7429
|
+
// src/call/ringtone.ts
|
|
7430
|
+
var audioCtx = null;
|
|
7431
|
+
var scheduledTimer = null;
|
|
7432
|
+
var activeOscillators = [];
|
|
7433
|
+
var RING_ON_MS = 1200;
|
|
7434
|
+
var RING_OFF_MS = 2400;
|
|
7435
|
+
var RING_FREQUENCIES = [440, 480];
|
|
7436
|
+
var getContext = () => {
|
|
7437
|
+
if (typeof window === "undefined") return null;
|
|
7438
|
+
const Ctor = window.AudioContext || window.webkitAudioContext;
|
|
7439
|
+
if (!Ctor) return null;
|
|
7440
|
+
if (!audioCtx || audioCtx.state === "closed") audioCtx = new Ctor();
|
|
7441
|
+
return audioCtx;
|
|
7442
|
+
};
|
|
7443
|
+
var stopOscillators = () => {
|
|
7444
|
+
activeOscillators.forEach((osc) => {
|
|
7445
|
+
try {
|
|
7446
|
+
osc.stop();
|
|
7447
|
+
} catch {
|
|
7448
|
+
}
|
|
7449
|
+
});
|
|
7450
|
+
activeOscillators = [];
|
|
7451
|
+
};
|
|
7452
|
+
var ringBurst = (ctx) => {
|
|
7453
|
+
const onSeconds = RING_ON_MS / 1e3;
|
|
7454
|
+
const gain = ctx.createGain();
|
|
7455
|
+
gain.gain.setValueAtTime(0, ctx.currentTime);
|
|
7456
|
+
gain.gain.linearRampToValueAtTime(0.15, ctx.currentTime + 0.05);
|
|
7457
|
+
gain.gain.setValueAtTime(0.15, ctx.currentTime + onSeconds - 0.05);
|
|
7458
|
+
gain.gain.linearRampToValueAtTime(0, ctx.currentTime + onSeconds);
|
|
7459
|
+
gain.connect(ctx.destination);
|
|
7460
|
+
RING_FREQUENCIES.forEach((freq) => {
|
|
7461
|
+
const osc = ctx.createOscillator();
|
|
7462
|
+
osc.type = "sine";
|
|
7463
|
+
osc.frequency.value = freq;
|
|
7464
|
+
osc.connect(gain);
|
|
7465
|
+
osc.start();
|
|
7466
|
+
osc.stop(ctx.currentTime + onSeconds);
|
|
7467
|
+
activeOscillators.push(osc);
|
|
7468
|
+
});
|
|
7469
|
+
};
|
|
7470
|
+
var playDefaultRingtone = () => {
|
|
7471
|
+
if (scheduledTimer) return;
|
|
7472
|
+
const ctx = getContext();
|
|
7473
|
+
if (!ctx) return;
|
|
7474
|
+
ctx.resume().catch(() => void 0);
|
|
7475
|
+
const cycle = () => {
|
|
7476
|
+
ringBurst(ctx);
|
|
7477
|
+
scheduledTimer = setTimeout(cycle, RING_ON_MS + RING_OFF_MS);
|
|
7478
|
+
};
|
|
7479
|
+
cycle();
|
|
7480
|
+
};
|
|
7481
|
+
var stopDefaultRingtone = () => {
|
|
7482
|
+
if (scheduledTimer) {
|
|
7483
|
+
clearTimeout(scheduledTimer);
|
|
7484
|
+
scheduledTimer = null;
|
|
7485
|
+
}
|
|
7486
|
+
stopOscillators();
|
|
7487
|
+
};
|
|
7339
7488
|
var IncomingCallDialog = ({ ringtoneUrl }) => {
|
|
7340
7489
|
const uiStatus = useCallStore((s) => s.uiStatus);
|
|
7341
7490
|
const callId = useCallStore((s) => s.callId);
|
|
@@ -7358,6 +7507,12 @@ var IncomingCallDialog = ({ ringtoneUrl }) => {
|
|
|
7358
7507
|
el.pause();
|
|
7359
7508
|
}
|
|
7360
7509
|
}, [isOpen, ringtoneUrl]);
|
|
7510
|
+
useEffect(() => {
|
|
7511
|
+
if (ringtoneUrl) return;
|
|
7512
|
+
if (isOpen) playDefaultRingtone();
|
|
7513
|
+
else stopDefaultRingtone();
|
|
7514
|
+
return () => stopDefaultRingtone();
|
|
7515
|
+
}, [isOpen, ringtoneUrl]);
|
|
7361
7516
|
if (!isOpen) return null;
|
|
7362
7517
|
const callerName = caller?.name || "Unknown caller";
|
|
7363
7518
|
const name = isGroupCall ? peer?.name || callerName : callerName;
|
|
@@ -11934,28 +12089,6 @@ function MessageForwardedLabel({ isSender, className, overlay }) {
|
|
|
11934
12089
|
}
|
|
11935
12090
|
);
|
|
11936
12091
|
}
|
|
11937
|
-
|
|
11938
|
-
// src/chat/lib/chat-message-bubble.ts
|
|
11939
|
-
init_utils2();
|
|
11940
|
-
function getBubbleCornerClasses(isSender) {
|
|
11941
|
-
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";
|
|
11942
|
-
}
|
|
11943
|
-
function getChatBubbleClasses({
|
|
11944
|
-
isSender = false,
|
|
11945
|
-
surface,
|
|
11946
|
-
className
|
|
11947
|
-
}) {
|
|
11948
|
-
const resolvedSurface = surface ?? (isSender ? "sent" : "received");
|
|
11949
|
-
const isNeutral = resolvedSurface === "neutral";
|
|
11950
|
-
return cn(
|
|
11951
|
-
"relative",
|
|
11952
|
-
getBubbleCornerClasses(isSender),
|
|
11953
|
-
resolvedSurface === "sent" && "chat-bubble-sent bg-(--chat-theme) text-white",
|
|
11954
|
-
resolvedSurface === "received" && "chat-bubble-received border border-(--chat-border)/60 bg-(--chat-incoming-bubble) text-(--chat-incoming-text)",
|
|
11955
|
-
isNeutral && "chat-bubble-received border border-(--chat-border)/60 bg-(--chat-incoming-bubble) text-(--chat-incoming-text)",
|
|
11956
|
-
className
|
|
11957
|
-
);
|
|
11958
|
-
}
|
|
11959
12092
|
init_utils2();
|
|
11960
12093
|
init_client();
|
|
11961
12094
|
function getPreviewKind(name) {
|
|
@@ -20983,6 +21116,7 @@ init_normalize_helpers();
|
|
|
20983
21116
|
init_useStore();
|
|
20984
21117
|
init_open_conversation();
|
|
20985
21118
|
var RETRY_DELAYS_MS = [1e3, 3e3, 8e3, 2e4];
|
|
21119
|
+
var CHAT_HEARTBEAT_INTERVAL_MS = 15e3;
|
|
20986
21120
|
var recentToastIds = /* @__PURE__ */ new Set();
|
|
20987
21121
|
var rememberToastId = (id) => {
|
|
20988
21122
|
if (!id) return true;
|
|
@@ -21205,6 +21339,36 @@ var ForegroundPushBridge = ({ onPush }) => {
|
|
|
21205
21339
|
window.removeEventListener(PUSH_CHANGED_EVENT, onPushChanged);
|
|
21206
21340
|
};
|
|
21207
21341
|
}, []);
|
|
21342
|
+
useEffect(() => {
|
|
21343
|
+
if (typeof navigator === "undefined" || !("serviceWorker" in navigator)) {
|
|
21344
|
+
return;
|
|
21345
|
+
}
|
|
21346
|
+
let interval = null;
|
|
21347
|
+
const sendHeartbeat = () => {
|
|
21348
|
+
navigator.serviceWorker.getRegistration().then(
|
|
21349
|
+
(registration) => registration?.active?.postMessage({ type: CHAT_HEARTBEAT_SW_TYPE })
|
|
21350
|
+
).catch(() => void 0);
|
|
21351
|
+
};
|
|
21352
|
+
const startHeartbeat = () => {
|
|
21353
|
+
if (interval || !getStoredPushToken()) return;
|
|
21354
|
+
sendHeartbeat();
|
|
21355
|
+
interval = setInterval(sendHeartbeat, CHAT_HEARTBEAT_INTERVAL_MS);
|
|
21356
|
+
};
|
|
21357
|
+
const stopHeartbeat = () => {
|
|
21358
|
+
if (interval) clearInterval(interval);
|
|
21359
|
+
interval = null;
|
|
21360
|
+
};
|
|
21361
|
+
startHeartbeat();
|
|
21362
|
+
const onPushChanged = (event) => {
|
|
21363
|
+
if (event.detail?.enabled) startHeartbeat();
|
|
21364
|
+
else stopHeartbeat();
|
|
21365
|
+
};
|
|
21366
|
+
window.addEventListener(PUSH_CHANGED_EVENT, onPushChanged);
|
|
21367
|
+
return () => {
|
|
21368
|
+
stopHeartbeat();
|
|
21369
|
+
window.removeEventListener(PUSH_CHANGED_EVENT, onPushChanged);
|
|
21370
|
+
};
|
|
21371
|
+
}, []);
|
|
21208
21372
|
useEffect(() => {
|
|
21209
21373
|
const onOpen = (event) => {
|
|
21210
21374
|
const id = String(
|