@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.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";
|
|
@@ -4839,9 +4840,8 @@ var init_ParticipantView = __esm({
|
|
|
4839
4840
|
isHandRaised = false,
|
|
4840
4841
|
className
|
|
4841
4842
|
}) => {
|
|
4842
|
-
const { webcamStream,
|
|
4843
|
+
const { webcamStream, webcamOn, micOn, displayName, isActiveSpeaker } = sdk.useParticipant(participantId);
|
|
4843
4844
|
const videoRef = React11.useRef(null);
|
|
4844
|
-
const audioRef = React11.useRef(null);
|
|
4845
4845
|
const [hasFrame, setHasFrame] = React11.useState(false);
|
|
4846
4846
|
React11.useEffect(() => {
|
|
4847
4847
|
const el = videoRef.current;
|
|
@@ -4854,17 +4854,6 @@ var init_ParticipantView = __esm({
|
|
|
4854
4854
|
setHasFrame(false);
|
|
4855
4855
|
}
|
|
4856
4856
|
}, [webcamOn, webcamStream]);
|
|
4857
|
-
React11.useEffect(() => {
|
|
4858
|
-
if (isLocal) return;
|
|
4859
|
-
const el = audioRef.current;
|
|
4860
|
-
if (!el) return;
|
|
4861
|
-
if (micOn && micStream?.track) {
|
|
4862
|
-
el.srcObject = new MediaStream([micStream.track]);
|
|
4863
|
-
el.play().catch(() => void 0);
|
|
4864
|
-
} else {
|
|
4865
|
-
el.srcObject = null;
|
|
4866
|
-
}
|
|
4867
|
-
}, [micOn, micStream, isLocal]);
|
|
4868
4857
|
const name = displayName || fallbackName || "Participant";
|
|
4869
4858
|
const showVideo = webcamOn && hasFrame;
|
|
4870
4859
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -4897,7 +4886,6 @@ var init_ParticipantView = __esm({
|
|
|
4897
4886
|
)
|
|
4898
4887
|
}
|
|
4899
4888
|
),
|
|
4900
|
-
!isLocal && /* @__PURE__ */ jsxRuntime.jsx("audio", { ref: audioRef, autoPlay: true, playsInline: true }),
|
|
4901
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 }) }),
|
|
4902
4890
|
!showVideo && /* @__PURE__ */ jsxRuntime.jsxs(Avatar, { size: "lg", className: "size-20", children: [
|
|
4903
4891
|
/* @__PURE__ */ jsxRuntime.jsx(AvatarImage, { src: fallbackImage, alt: name }),
|
|
@@ -5064,7 +5052,8 @@ var init_CallControls = __esm({
|
|
|
5064
5052
|
isHandRaised,
|
|
5065
5053
|
onToggleRaiseHand,
|
|
5066
5054
|
isChatOpen,
|
|
5067
|
-
onToggleChat
|
|
5055
|
+
onToggleChat,
|
|
5056
|
+
isVideoActive
|
|
5068
5057
|
}) => {
|
|
5069
5058
|
const {
|
|
5070
5059
|
toggleMic,
|
|
@@ -5073,9 +5062,28 @@ var init_CallControls = __esm({
|
|
|
5073
5062
|
localWebcamOn,
|
|
5074
5063
|
localScreenShareOn,
|
|
5075
5064
|
toggleScreenShare,
|
|
5065
|
+
recordingState,
|
|
5066
|
+
startRecording,
|
|
5067
|
+
stopRecording,
|
|
5076
5068
|
leave
|
|
5077
5069
|
} = sdk.useMeeting();
|
|
5078
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
|
+
};
|
|
5079
5087
|
const handleLeave = () => {
|
|
5080
5088
|
leave();
|
|
5081
5089
|
endCall();
|
|
@@ -5091,7 +5099,7 @@ var init_CallControls = __esm({
|
|
|
5091
5099
|
onClick: () => toggleMic()
|
|
5092
5100
|
}
|
|
5093
5101
|
),
|
|
5094
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5102
|
+
isVideoActive ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
5095
5103
|
ControlButton,
|
|
5096
5104
|
{
|
|
5097
5105
|
icon: localWebcamOn ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Video, { size: 20 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.VideoOff, { size: 20 }),
|
|
@@ -5099,6 +5107,13 @@ var init_CallControls = __esm({
|
|
|
5099
5107
|
active: !localWebcamOn,
|
|
5100
5108
|
onClick: () => toggleWebcam()
|
|
5101
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()
|
|
5116
|
+
}
|
|
5102
5117
|
),
|
|
5103
5118
|
/* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "mx-0.5 h-7 w-px shrink-0 bg-white/15" }),
|
|
5104
5119
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -5111,6 +5126,16 @@ var init_CallControls = __esm({
|
|
|
5111
5126
|
onClick: () => toggleScreenShare()
|
|
5112
5127
|
}
|
|
5113
5128
|
),
|
|
5129
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5130
|
+
ControlButton,
|
|
5131
|
+
{
|
|
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
|
|
5137
|
+
}
|
|
5138
|
+
),
|
|
5114
5139
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5115
5140
|
ControlButton,
|
|
5116
5141
|
{
|
|
@@ -5290,7 +5315,7 @@ var init_useCallReactions = __esm({
|
|
|
5290
5315
|
};
|
|
5291
5316
|
}
|
|
5292
5317
|
});
|
|
5293
|
-
var
|
|
5318
|
+
var RemoteParticipantWatcher, MeetingView, MeetingView_default;
|
|
5294
5319
|
var init_MeetingView = __esm({
|
|
5295
5320
|
"src/call/MeetingView.tsx"() {
|
|
5296
5321
|
init_ParticipantView();
|
|
@@ -5301,17 +5326,28 @@ var init_MeetingView = __esm({
|
|
|
5301
5326
|
init_useCallReactions();
|
|
5302
5327
|
init_call_store();
|
|
5303
5328
|
init_utils2();
|
|
5304
|
-
|
|
5329
|
+
RemoteParticipantWatcher = ({
|
|
5305
5330
|
sdk,
|
|
5306
5331
|
participantId,
|
|
5307
|
-
|
|
5332
|
+
onWebcamChange
|
|
5308
5333
|
}) => {
|
|
5309
|
-
const { webcamOn } = sdk.useParticipant(participantId);
|
|
5334
|
+
const { webcamOn, micStream, micOn } = sdk.useParticipant(participantId);
|
|
5335
|
+
const audioRef = React11.useRef(null);
|
|
5310
5336
|
React11.useEffect(() => {
|
|
5311
|
-
|
|
5312
|
-
return () =>
|
|
5337
|
+
onWebcamChange(participantId, webcamOn);
|
|
5338
|
+
return () => onWebcamChange(participantId, false);
|
|
5313
5339
|
}, [participantId, webcamOn]);
|
|
5314
|
-
|
|
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 });
|
|
5315
5351
|
};
|
|
5316
5352
|
MeetingView = ({
|
|
5317
5353
|
sdk,
|
|
@@ -5364,7 +5400,17 @@ var init_MeetingView = __esm({
|
|
|
5364
5400
|
(id) => id !== localParticipant?.id
|
|
5365
5401
|
);
|
|
5366
5402
|
const isGroup = remoteIds.length > 1;
|
|
5367
|
-
const
|
|
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;
|
|
5368
5414
|
const controls = /* @__PURE__ */ jsxRuntime.jsx(
|
|
5369
5415
|
CallControls_default,
|
|
5370
5416
|
{
|
|
@@ -5373,7 +5419,8 @@ var init_MeetingView = __esm({
|
|
|
5373
5419
|
isHandRaised,
|
|
5374
5420
|
onToggleRaiseHand: toggleRaiseHand,
|
|
5375
5421
|
isChatOpen,
|
|
5376
|
-
onToggleChat
|
|
5422
|
+
onToggleChat,
|
|
5423
|
+
isVideoActive: showVideoGrid
|
|
5377
5424
|
}
|
|
5378
5425
|
);
|
|
5379
5426
|
const connectionStatusText = meetingState === "CONNECTING" ? "Connecting\u2026" : meetingState === "DISCONNECTED" ? "Reconnecting\u2026" : meetingState === "FAILED" ? "Connection lost" : null;
|
|
@@ -5383,7 +5430,7 @@ var init_MeetingView = __esm({
|
|
|
5383
5430
|
] });
|
|
5384
5431
|
if (presenterId) {
|
|
5385
5432
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5386
|
-
|
|
5433
|
+
remoteParticipantWatchers,
|
|
5387
5434
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex flex-1 flex-col", children: [
|
|
5388
5435
|
statusBanner,
|
|
5389
5436
|
/* @__PURE__ */ jsxRuntime.jsx(FloatingReactions_default, { reactions: floatingReactions }),
|
|
@@ -5424,11 +5471,9 @@ var init_MeetingView = __esm({
|
|
|
5424
5471
|
] })
|
|
5425
5472
|
] });
|
|
5426
5473
|
}
|
|
5427
|
-
const anyRemoteWebcamOn = Object.values(remoteWebcamOn).some(Boolean);
|
|
5428
|
-
const showVideoGrid = mode === "video" || localWebcamOn || anyRemoteWebcamOn;
|
|
5429
5474
|
if (!showVideoGrid) {
|
|
5430
5475
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5431
|
-
|
|
5476
|
+
remoteParticipantWatchers,
|
|
5432
5477
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex flex-1 flex-col", children: [
|
|
5433
5478
|
statusBanner,
|
|
5434
5479
|
/* @__PURE__ */ jsxRuntime.jsx(FloatingReactions_default, { reactions: floatingReactions }),
|
|
@@ -5451,7 +5496,7 @@ var init_MeetingView = __esm({
|
|
|
5451
5496
|
(id) => !!id && id !== focusedId
|
|
5452
5497
|
) : [];
|
|
5453
5498
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5454
|
-
|
|
5499
|
+
remoteParticipantWatchers,
|
|
5455
5500
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex flex-1 flex-col", children: [
|
|
5456
5501
|
statusBanner,
|
|
5457
5502
|
/* @__PURE__ */ jsxRuntime.jsx(FloatingReactions_default, { reactions: floatingReactions }),
|
|
@@ -6561,7 +6606,186 @@ init_useStore();
|
|
|
6561
6606
|
init_store_helpers();
|
|
6562
6607
|
init_utils2();
|
|
6563
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
|
+
}
|
|
6564
6787
|
var CallChatPanel = ({ conversationId, isGroupCall, onClose, className }) => {
|
|
6788
|
+
const { scopeClassName, themeStyles } = useChatTheme();
|
|
6565
6789
|
const rawMessages = exports.useChatStore((s) => s.messagesByConversation[conversationId]);
|
|
6566
6790
|
const loggedUserDetails = exports.useChatStore((s) => s.loggedUserDetails);
|
|
6567
6791
|
const conversations = exports.useChatStore((s) => s.conversations);
|
|
@@ -6632,68 +6856,89 @@ var CallChatPanel = ({ conversationId, isGroupCall, onClose, className }) => {
|
|
|
6632
6856
|
emitDmSend(payload);
|
|
6633
6857
|
}
|
|
6634
6858
|
};
|
|
6635
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6636
|
-
|
|
6637
|
-
|
|
6638
|
-
|
|
6639
|
-
|
|
6640
|
-
|
|
6641
|
-
|
|
6642
|
-
"aria-label": "Close chat panel",
|
|
6643
|
-
onClick: onClose,
|
|
6644
|
-
className: "flex size-7 items-center justify-center rounded-lg text-white/60 transition-colors hover:bg-white/10 hover:text-white",
|
|
6645
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: 16 })
|
|
6646
|
-
}
|
|
6647
|
-
)
|
|
6648
|
-
] }),
|
|
6649
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 space-y-3 overflow-y-auto px-4 py-3", children: [
|
|
6650
|
-
messages.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pt-6 text-center text-xs text-white/40", children: "No messages yet \u2014 say hi without leaving the call." }),
|
|
6651
|
-
messages.map((message) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col", message.isOwn && "items-end"), children: [
|
|
6652
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-0.5 text-[11px] font-medium text-white/40", children: message.isOwn ? "You" : message.senderName }),
|
|
6653
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6654
|
-
"div",
|
|
6655
|
-
{
|
|
6656
|
-
className: cn(
|
|
6657
|
-
"max-w-[85%] rounded-2xl px-3 py-1.5 text-sm break-words",
|
|
6658
|
-
message.isOwn ? "rounded-br-sm bg-(--chat-theme,#4f46e5) text-white" : "rounded-bl-sm bg-white/10 text-white/90",
|
|
6659
|
-
message.pending && "opacity-60"
|
|
6660
|
-
),
|
|
6661
|
-
children: message.content
|
|
6662
|
-
}
|
|
6663
|
-
)
|
|
6664
|
-
] }, message.id)),
|
|
6665
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: listEndRef })
|
|
6666
|
-
] }),
|
|
6667
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 border-t border-white/10 p-3", children: [
|
|
6668
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6669
|
-
"input",
|
|
6670
|
-
{
|
|
6671
|
-
value: text,
|
|
6672
|
-
onChange: (e) => setText(e.target.value),
|
|
6673
|
-
onKeyDown: (e) => {
|
|
6674
|
-
if (e.key === "Enter" && !e.shiftKey) {
|
|
6675
|
-
e.preventDefault();
|
|
6676
|
-
handleSend();
|
|
6677
|
-
}
|
|
6678
|
-
},
|
|
6679
|
-
placeholder: "Message\u2026",
|
|
6680
|
-
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"
|
|
6681
|
-
}
|
|
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
|
|
6682
6866
|
),
|
|
6683
|
-
|
|
6684
|
-
|
|
6685
|
-
{
|
|
6686
|
-
|
|
6687
|
-
|
|
6688
|
-
|
|
6689
|
-
|
|
6690
|
-
|
|
6691
|
-
|
|
6692
|
-
|
|
6693
|
-
|
|
6694
|
-
|
|
6695
|
-
|
|
6696
|
-
|
|
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
|
+
);
|
|
6697
6942
|
};
|
|
6698
6943
|
var CallChatPanel_default = CallChatPanel;
|
|
6699
6944
|
var CallSession2 = React11__namespace.default.lazy(() => Promise.resolve().then(() => (init_CallSession(), CallSession_exports)));
|
|
@@ -7153,162 +7398,6 @@ function AlertDialogCancel({
|
|
|
7153
7398
|
|
|
7154
7399
|
// src/chat/ChatOverlay.tsx
|
|
7155
7400
|
init_utils2();
|
|
7156
|
-
|
|
7157
|
-
// src/chat/lib/chat-theme.ts
|
|
7158
|
-
init_utils2();
|
|
7159
|
-
var getChatScopeClass = (isDark) => cn("chat-theme-scope", isDark && "dark");
|
|
7160
|
-
var chatSheetContentClass = "flex w-full flex-col gap-0 p-0 bg-(--chat-surface) text-(--chat-text)";
|
|
7161
|
-
var chatSheetHeaderClass = "border-b border-(--chat-border) px-4 py-3 pr-11 text-left";
|
|
7162
|
-
var chatSheetBodyClass = "chat-message-scroll flex-1 overflow-y-auto bg-(--chat-surface) p-3";
|
|
7163
|
-
var chatSheetTitleClass = "text-[13px] font-semibold tracking-tight text-(--chat-text)";
|
|
7164
|
-
var chatSheetSubtitleClass = "text-[11px] text-(--chat-muted)";
|
|
7165
|
-
var chatDetailRowClass = "flex items-start justify-between gap-3 border-b border-(--chat-border) py-2.5 last:border-b-0";
|
|
7166
|
-
var chatDetailLabelClass = "text-[11px] text-(--chat-muted)";
|
|
7167
|
-
var chatDetailValueClass = "text-[13px] font-medium text-(--chat-text) text-right";
|
|
7168
|
-
var chatDialogContentClass = "overflow-hidden rounded-2xl border border-(--chat-border) bg-(--chat-surface) p-0 text-(--chat-text) shadow-[var(--chat-shadow)]";
|
|
7169
|
-
var chatDropdownContentClass = "rounded-xl border border-(--chat-border) bg-(--chat-surface) text-(--chat-text) shadow-lg";
|
|
7170
|
-
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)]";
|
|
7171
|
-
var chatOptionsMenuLabelClass = "px-2.5 pb-0.5 pt-1 text-[10px] font-semibold uppercase tracking-[0.12em] text-(--chat-muted)";
|
|
7172
|
-
var chatOptionsMenuSeparatorClass = "my-1.5 h-px bg-(--chat-border)";
|
|
7173
|
-
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)";
|
|
7174
|
-
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)";
|
|
7175
|
-
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)";
|
|
7176
|
-
var chatPopoverContentClass = "w-auto border border-(--chat-border) bg-(--chat-surface) p-0 text-(--chat-text) shadow-2xl";
|
|
7177
|
-
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)";
|
|
7178
|
-
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)]";
|
|
7179
|
-
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";
|
|
7180
|
-
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)";
|
|
7181
|
-
var chatListItemClass = "transition-colors hover:bg-(--chat-hover)";
|
|
7182
|
-
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";
|
|
7183
|
-
var chatDrawerSectionHeadingClass = "mb-1 px-0.5 text-[10px] font-semibold tracking-wide text-(--chat-muted)";
|
|
7184
|
-
var chatHeaderToolbarIconProps = { size: 14, strokeWidth: 1.75 };
|
|
7185
|
-
var chatSavedMessageModalIconClass = "shrink-0 text-(--chat-theme)";
|
|
7186
|
-
var chatHeaderToolbarIconLgProps = { size: 22, strokeWidth: 1.75 };
|
|
7187
|
-
var chatHeaderToolbarIconSmProps = { size: 11, strokeWidth: 1.75 };
|
|
7188
|
-
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";
|
|
7189
|
-
var chatDrawerFileIconWrapClass = "flex size-8 shrink-0 items-center justify-center rounded-md bg-(--chat-hover)";
|
|
7190
|
-
var chatDrawerMediaFrameClass = "overflow-hidden rounded-md border border-(--chat-border)/70 bg-(--chat-elevated)";
|
|
7191
|
-
var buildChatThemeStyles = (themeColor) => ({
|
|
7192
|
-
"--chat-theme": themeColor,
|
|
7193
|
-
"--chat-theme-5": `${themeColor}0D`,
|
|
7194
|
-
"--chat-theme-10": `${themeColor}1A`,
|
|
7195
|
-
"--chat-theme-20": `${themeColor}33`,
|
|
7196
|
-
"--chat-theme-40": `${themeColor}66`,
|
|
7197
|
-
"--chat-theme-60": `${themeColor}99`,
|
|
7198
|
-
"--read-tick-color": themeColor.toLowerCase() === "#0000ff" || themeColor.toLowerCase().includes("007aff") ? "#00e5ff" : "#40C4FF"
|
|
7199
|
-
});
|
|
7200
|
-
|
|
7201
|
-
// src/chat/lib/chat-theme-storage.ts
|
|
7202
|
-
var STORAGE_KEY = "chat-color-mode";
|
|
7203
|
-
var loadChatColorMode = () => {
|
|
7204
|
-
if (typeof window === "undefined") return null;
|
|
7205
|
-
try {
|
|
7206
|
-
const stored = localStorage.getItem(STORAGE_KEY);
|
|
7207
|
-
return stored === "dark" || stored === "light" ? stored : null;
|
|
7208
|
-
} catch {
|
|
7209
|
-
return null;
|
|
7210
|
-
}
|
|
7211
|
-
};
|
|
7212
|
-
var saveChatColorMode = (mode) => {
|
|
7213
|
-
if (typeof window === "undefined") return;
|
|
7214
|
-
try {
|
|
7215
|
-
localStorage.setItem(STORAGE_KEY, mode);
|
|
7216
|
-
} catch {
|
|
7217
|
-
}
|
|
7218
|
-
};
|
|
7219
|
-
var CHAT_THEME_SHELL_CLASS = "chat-theme-shell";
|
|
7220
|
-
function withThemeTransition(apply) {
|
|
7221
|
-
if (typeof document === "undefined") {
|
|
7222
|
-
apply();
|
|
7223
|
-
return;
|
|
7224
|
-
}
|
|
7225
|
-
reactDom.flushSync(apply);
|
|
7226
|
-
}
|
|
7227
|
-
|
|
7228
|
-
// src/context/ChatThemeContext.tsx
|
|
7229
|
-
init_utils2();
|
|
7230
|
-
var ChatThemeContext = React11.createContext(null);
|
|
7231
|
-
var ChatThemeProvider = ({
|
|
7232
|
-
children,
|
|
7233
|
-
themeColor,
|
|
7234
|
-
colorMode,
|
|
7235
|
-
defaultColorMode = "light",
|
|
7236
|
-
onColorModeChange,
|
|
7237
|
-
showColorModeToggle = true
|
|
7238
|
-
}) => {
|
|
7239
|
-
const isControlled = colorMode !== void 0;
|
|
7240
|
-
const [internalMode, setInternalMode] = React11.useState(defaultColorMode);
|
|
7241
|
-
const [isThemeTransitionReady, setIsThemeTransitionReady] = React11.useState(false);
|
|
7242
|
-
const skipThemeTransitionRef = React11.useRef(true);
|
|
7243
|
-
React11.useLayoutEffect(() => {
|
|
7244
|
-
if (!isControlled) {
|
|
7245
|
-
const stored = loadChatColorMode();
|
|
7246
|
-
if (stored) {
|
|
7247
|
-
setInternalMode(stored);
|
|
7248
|
-
}
|
|
7249
|
-
}
|
|
7250
|
-
const frame = requestAnimationFrame(() => {
|
|
7251
|
-
skipThemeTransitionRef.current = false;
|
|
7252
|
-
setIsThemeTransitionReady(true);
|
|
7253
|
-
});
|
|
7254
|
-
return () => cancelAnimationFrame(frame);
|
|
7255
|
-
}, [isControlled]);
|
|
7256
|
-
const resolvedMode = isControlled ? colorMode : internalMode;
|
|
7257
|
-
const isDark = resolvedMode === "dark";
|
|
7258
|
-
const setColorMode = React11.useCallback(
|
|
7259
|
-
(mode) => {
|
|
7260
|
-
const apply = () => {
|
|
7261
|
-
if (!isControlled) {
|
|
7262
|
-
setInternalMode(mode);
|
|
7263
|
-
saveChatColorMode(mode);
|
|
7264
|
-
}
|
|
7265
|
-
onColorModeChange?.(mode);
|
|
7266
|
-
};
|
|
7267
|
-
if (skipThemeTransitionRef.current) {
|
|
7268
|
-
apply();
|
|
7269
|
-
return;
|
|
7270
|
-
}
|
|
7271
|
-
withThemeTransition(apply);
|
|
7272
|
-
},
|
|
7273
|
-
[isControlled, onColorModeChange]
|
|
7274
|
-
);
|
|
7275
|
-
const toggleColorMode = React11.useCallback(() => {
|
|
7276
|
-
setColorMode(resolvedMode === "dark" ? "light" : "dark");
|
|
7277
|
-
}, [resolvedMode, setColorMode]);
|
|
7278
|
-
const value = React11.useMemo(
|
|
7279
|
-
() => ({
|
|
7280
|
-
colorMode: resolvedMode,
|
|
7281
|
-
isDark,
|
|
7282
|
-
isThemeTransitionReady,
|
|
7283
|
-
themeColor,
|
|
7284
|
-
themeStyles: buildChatThemeStyles(themeColor),
|
|
7285
|
-
scopeClassName: cn(
|
|
7286
|
-
getChatScopeClass(isDark),
|
|
7287
|
-
!isThemeTransitionReady && "chat-theme-no-transition"
|
|
7288
|
-
),
|
|
7289
|
-
setColorMode,
|
|
7290
|
-
toggleColorMode,
|
|
7291
|
-
showColorModeToggle
|
|
7292
|
-
}),
|
|
7293
|
-
[
|
|
7294
|
-
resolvedMode,
|
|
7295
|
-
isDark,
|
|
7296
|
-
isThemeTransitionReady,
|
|
7297
|
-
themeColor,
|
|
7298
|
-
setColorMode,
|
|
7299
|
-
toggleColorMode,
|
|
7300
|
-
showColorModeToggle
|
|
7301
|
-
]
|
|
7302
|
-
);
|
|
7303
|
-
return /* @__PURE__ */ jsxRuntime.jsx(ChatThemeContext.Provider, { value, children });
|
|
7304
|
-
};
|
|
7305
|
-
var useChatTheme = () => {
|
|
7306
|
-
const context = React11.useContext(ChatThemeContext);
|
|
7307
|
-
if (!context) {
|
|
7308
|
-
throw new Error("useChatTheme must be used within ChatThemeProvider");
|
|
7309
|
-
}
|
|
7310
|
-
return context;
|
|
7311
|
-
};
|
|
7312
7401
|
var ChatSheetContent = ({
|
|
7313
7402
|
className,
|
|
7314
7403
|
style,
|
|
@@ -7364,6 +7453,66 @@ init_avatar();
|
|
|
7364
7453
|
init_button();
|
|
7365
7454
|
init_utils2();
|
|
7366
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
|
+
};
|
|
7367
7516
|
var IncomingCallDialog = ({ ringtoneUrl }) => {
|
|
7368
7517
|
const uiStatus = exports.useCallStore((s) => s.uiStatus);
|
|
7369
7518
|
const callId = exports.useCallStore((s) => s.callId);
|
|
@@ -7386,6 +7535,12 @@ var IncomingCallDialog = ({ ringtoneUrl }) => {
|
|
|
7386
7535
|
el.pause();
|
|
7387
7536
|
}
|
|
7388
7537
|
}, [isOpen, ringtoneUrl]);
|
|
7538
|
+
React11.useEffect(() => {
|
|
7539
|
+
if (ringtoneUrl) return;
|
|
7540
|
+
if (isOpen) playDefaultRingtone();
|
|
7541
|
+
else stopDefaultRingtone();
|
|
7542
|
+
return () => stopDefaultRingtone();
|
|
7543
|
+
}, [isOpen, ringtoneUrl]);
|
|
7389
7544
|
if (!isOpen) return null;
|
|
7390
7545
|
const callerName = caller?.name || "Unknown caller";
|
|
7391
7546
|
const name = isGroupCall ? peer?.name || callerName : callerName;
|
|
@@ -11962,28 +12117,6 @@ function MessageForwardedLabel({ isSender, className, overlay }) {
|
|
|
11962
12117
|
}
|
|
11963
12118
|
);
|
|
11964
12119
|
}
|
|
11965
|
-
|
|
11966
|
-
// src/chat/lib/chat-message-bubble.ts
|
|
11967
|
-
init_utils2();
|
|
11968
|
-
function getBubbleCornerClasses(isSender) {
|
|
11969
|
-
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";
|
|
11970
|
-
}
|
|
11971
|
-
function getChatBubbleClasses({
|
|
11972
|
-
isSender = false,
|
|
11973
|
-
surface,
|
|
11974
|
-
className
|
|
11975
|
-
}) {
|
|
11976
|
-
const resolvedSurface = surface ?? (isSender ? "sent" : "received");
|
|
11977
|
-
const isNeutral = resolvedSurface === "neutral";
|
|
11978
|
-
return cn(
|
|
11979
|
-
"relative",
|
|
11980
|
-
getBubbleCornerClasses(isSender),
|
|
11981
|
-
resolvedSurface === "sent" && "chat-bubble-sent bg-(--chat-theme) text-white",
|
|
11982
|
-
resolvedSurface === "received" && "chat-bubble-received border border-(--chat-border)/60 bg-(--chat-incoming-bubble) text-(--chat-incoming-text)",
|
|
11983
|
-
isNeutral && "chat-bubble-received border border-(--chat-border)/60 bg-(--chat-incoming-bubble) text-(--chat-incoming-text)",
|
|
11984
|
-
className
|
|
11985
|
-
);
|
|
11986
|
-
}
|
|
11987
12120
|
init_utils2();
|
|
11988
12121
|
init_client();
|
|
11989
12122
|
function getPreviewKind(name) {
|
|
@@ -21011,6 +21144,7 @@ init_normalize_helpers();
|
|
|
21011
21144
|
init_useStore();
|
|
21012
21145
|
init_open_conversation();
|
|
21013
21146
|
var RETRY_DELAYS_MS = [1e3, 3e3, 8e3, 2e4];
|
|
21147
|
+
var CHAT_HEARTBEAT_INTERVAL_MS = 15e3;
|
|
21014
21148
|
var recentToastIds = /* @__PURE__ */ new Set();
|
|
21015
21149
|
var rememberToastId = (id) => {
|
|
21016
21150
|
if (!id) return true;
|
|
@@ -21233,6 +21367,36 @@ var ForegroundPushBridge = ({ onPush }) => {
|
|
|
21233
21367
|
window.removeEventListener(PUSH_CHANGED_EVENT, onPushChanged);
|
|
21234
21368
|
};
|
|
21235
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
|
+
}, []);
|
|
21236
21400
|
React11.useEffect(() => {
|
|
21237
21401
|
const onOpen = (event) => {
|
|
21238
21402
|
const id = String(
|