@adatechnology/conversations-ui 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-HMCOTZAX.js → chunk-NSOAUYNE.js} +33 -28
- package/dist/chunk-ZSOD5AQT.js +19 -0
- package/dist/flows/index.js +4 -2
- package/dist/index.js +5 -3
- package/dist/participant/index.d.ts +3 -0
- package/dist/participant/index.js +536 -276
- package/dist/styles.css +99 -23
- package/package.json +2 -1
- package/src/Tooltip.tsx +5 -12
- package/src/TooltipDom.test.tsx +78 -0
- package/src/domHarness.test-helper.ts +53 -0
- package/src/participant/ParticipantBackButton.tsx +1 -1
- package/src/participant/ParticipantBubbleBody.tsx +54 -0
- package/src/participant/ParticipantBubbleStatus.tsx +22 -28
- package/src/participant/ParticipantChannelBadges.tsx +10 -2
- package/src/participant/ParticipantComposer.tsx +1 -1
- package/src/participant/ParticipantComposerControls.tsx +2 -0
- package/src/participant/ParticipantCopyableToken.tsx +1 -0
- package/src/participant/ParticipantFailedMenu.tsx +40 -0
- package/src/participant/ParticipantFailedMenuList.tsx +41 -0
- package/src/participant/ParticipantMessageBubble.test.tsx +6 -6
- package/src/participant/ParticipantMessageBubble.tsx +20 -52
- package/src/participant/ParticipantMessageText.test.tsx +1 -1
- package/src/participant/ParticipantMessageText.tsx +4 -2
- package/src/participant/ParticipantProtocolBadge.tsx +1 -0
- package/src/participant/ParticipantScrollToLatest.tsx +1 -1
- package/src/participant/ParticipantThread.tsx +23 -12
- package/src/participant/ParticipantThreadHeader.test.tsx +1 -1
- package/src/participant/failedMenuKeyboard.ts +29 -0
- package/src/participant/participantFailedMenuDom.test.tsx +154 -0
- package/src/participant/participantFailedMenuState.test.ts +61 -0
- package/src/participant/participantFailedMenuState.ts +57 -0
- package/src/participant/participantFailedMessage.test.tsx +83 -0
- package/src/participant/participantLabels.ts +6 -0
- package/src/participant/participantThemeContrast.test.ts +8 -0
- package/src/participant/participantTooltips.test.tsx +74 -0
- package/src/participant/test-fixtures/thread-avatars-initials.golden.html +1 -1
- package/src/participant/test-fixtures/thread-closed.golden.html +1 -1
- package/src/participant/test-fixtures/thread-default.golden.html +1 -1
- package/src/participant/test-fixtures/thread-error.golden.html +1 -1
- package/src/participant/test-fixtures/thread-loading.golden.html +1 -1
- package/src/participant/test-fixtures/thread-plain.golden.html +1 -1
- package/src/participant/test-fixtures/thread-tail-off.golden.html +1 -1
- package/src/participant/useFailedMenuEffects.ts +59 -0
- package/src/participant/useParticipantFailedMenu.ts +60 -0
- package/src/participant/useSuppressTouchTooltips.ts +38 -0
- package/src/styles.css +19 -5
- package/src/tooltipLayerRegistry.test.ts +56 -0
- package/src/tooltipLayerRegistry.ts +34 -0
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
TooltipLayer
|
|
3
|
+
} from "../chunk-NSOAUYNE.js";
|
|
1
4
|
import {
|
|
2
5
|
StatusTicks,
|
|
3
6
|
channelCapabilityFor,
|
|
@@ -7,7 +10,7 @@ import {
|
|
|
7
10
|
} from "../chunk-O6457XHK.js";
|
|
8
11
|
|
|
9
12
|
// src/participant/ParticipantConversationsScreen.tsx
|
|
10
|
-
import { useMemo as useMemo5, useReducer as
|
|
13
|
+
import { useMemo as useMemo5, useReducer as useReducer6, useRef as useRef12, useState as useState9 } from "react";
|
|
11
14
|
|
|
12
15
|
// src/participant/participantLoadView.ts
|
|
13
16
|
function resolveLoadView({ status, hasItems }) {
|
|
@@ -19,6 +22,7 @@ function resolveLoadView({ status, hasItems }) {
|
|
|
19
22
|
}
|
|
20
23
|
|
|
21
24
|
// src/participant/participantLabels.ts
|
|
25
|
+
var DEFAULT_MESSAGE_OPTIONS_LABEL = "Message options";
|
|
22
26
|
var DEFAULT_PARTICIPANT_CONVERSATIONS_LABELS = {
|
|
23
27
|
inboxTitle: "Conversations",
|
|
24
28
|
sectionAwaiting: "Waiting for your reply",
|
|
@@ -55,6 +59,7 @@ var DEFAULT_PARTICIPANT_CONVERSATIONS_LABELS = {
|
|
|
55
59
|
retry: "Retry",
|
|
56
60
|
discard: "Discard",
|
|
57
61
|
edit: "Edit",
|
|
62
|
+
messageOptions: DEFAULT_MESSAGE_OPTIONS_LABEL,
|
|
58
63
|
notFound: "Conversation not found",
|
|
59
64
|
loading: "Loading\u2026",
|
|
60
65
|
loadError: "Could not load. Check your connection and try again.",
|
|
@@ -128,18 +133,34 @@ function ParticipantChannelBadges({
|
|
|
128
133
|
if (variant === "inline") {
|
|
129
134
|
return /* @__PURE__ */ jsxs("span", { className: "cv-p-channels", children: [
|
|
130
135
|
/* @__PURE__ */ jsx("span", { className: "cv-p-sr-only", children: `${labels.channelsGroup}: ` }),
|
|
131
|
-
descriptors.map((descriptor, index) => /* @__PURE__ */ jsx(
|
|
132
|
-
|
|
136
|
+
descriptors.map((descriptor, index) => /* @__PURE__ */ jsx(
|
|
137
|
+
"span",
|
|
133
138
|
{
|
|
134
|
-
descriptor
|
|
135
|
-
labels,
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
139
|
+
className: `cv-p-channel cv-p-channel--${descriptor.channel}`,
|
|
140
|
+
"data-cv-tooltip": resolveParticipantChannelLabel(descriptor, labels),
|
|
141
|
+
children: /* @__PURE__ */ jsx(
|
|
142
|
+
BadgeContent,
|
|
143
|
+
{
|
|
144
|
+
descriptor,
|
|
145
|
+
labels,
|
|
146
|
+
separator: index < descriptors.length - 1 ? ", " : "",
|
|
147
|
+
iconSize
|
|
148
|
+
}
|
|
149
|
+
)
|
|
150
|
+
},
|
|
151
|
+
descriptor.channel
|
|
152
|
+
))
|
|
140
153
|
] });
|
|
141
154
|
}
|
|
142
|
-
return /* @__PURE__ */ jsx("ul", { className: "cv-p-channels", "aria-label": labels.channelsGroup, children: descriptors.map((descriptor) => /* @__PURE__ */ jsx(
|
|
155
|
+
return /* @__PURE__ */ jsx("ul", { className: "cv-p-channels", "aria-label": labels.channelsGroup, children: descriptors.map((descriptor) => /* @__PURE__ */ jsx(
|
|
156
|
+
"li",
|
|
157
|
+
{
|
|
158
|
+
className: `cv-p-channel cv-p-channel--${descriptor.channel}`,
|
|
159
|
+
"data-cv-tooltip": resolveParticipantChannelLabel(descriptor, labels),
|
|
160
|
+
children: /* @__PURE__ */ jsx(BadgeContent, { descriptor, labels, separator: "", iconSize })
|
|
161
|
+
},
|
|
162
|
+
descriptor.channel
|
|
163
|
+
)) });
|
|
143
164
|
}
|
|
144
165
|
|
|
145
166
|
// src/participant/participantSubjectIcon.ts
|
|
@@ -361,15 +382,18 @@ function ParticipantInbox(props) {
|
|
|
361
382
|
}
|
|
362
383
|
|
|
363
384
|
// src/participant/ParticipantThreadScreen.tsx
|
|
364
|
-
import { useEffect as
|
|
385
|
+
import { useEffect as useEffect13, useState as useState8 } from "react";
|
|
365
386
|
|
|
366
387
|
// src/participant/ParticipantBackButton.tsx
|
|
367
388
|
import { ArrowLeft } from "lucide-react";
|
|
368
389
|
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
369
390
|
function ParticipantBackButton({ label, onBack }) {
|
|
370
|
-
return /* @__PURE__ */ jsx6("button", { type: "button", className: "cv-p-thread__back", "aria-label": label, onClick: onBack, children: /* @__PURE__ */ jsx6(ArrowLeft, { size: 24, "aria-hidden": "true", focusable: "false" }) });
|
|
391
|
+
return /* @__PURE__ */ jsx6("button", { type: "button", className: "cv-p-thread__back", "aria-label": label, "data-cv-tooltip": label, onClick: onBack, children: /* @__PURE__ */ jsx6(ArrowLeft, { size: 24, "aria-hidden": "true", focusable: "false" }) });
|
|
371
392
|
}
|
|
372
393
|
|
|
394
|
+
// src/participant/ParticipantThread.tsx
|
|
395
|
+
import { useRef as useRef5 } from "react";
|
|
396
|
+
|
|
373
397
|
// src/participant/ParticipantComposer.tsx
|
|
374
398
|
import { useState } from "react";
|
|
375
399
|
|
|
@@ -406,6 +430,7 @@ function AttachControl({ labels, disabled, acceptedTypes, onChosen }) {
|
|
|
406
430
|
type: "button",
|
|
407
431
|
className: "cv-p-composer__attach",
|
|
408
432
|
"aria-label": labels.attach,
|
|
433
|
+
"data-cv-tooltip": labels.attach,
|
|
409
434
|
disabled,
|
|
410
435
|
onClick: () => fileInputRef.current?.click(),
|
|
411
436
|
children: /* @__PURE__ */ jsx7(Paperclip, { size: 24, "aria-hidden": "true", focusable: "false" })
|
|
@@ -420,6 +445,7 @@ function SendButton({ label, disabled }) {
|
|
|
420
445
|
type: "submit",
|
|
421
446
|
className: "cv-p-button cv-p-button--primary cv-p-composer__send",
|
|
422
447
|
"aria-label": label,
|
|
448
|
+
"data-cv-tooltip": label,
|
|
423
449
|
disabled,
|
|
424
450
|
children: /* @__PURE__ */ jsx7(Send, { size: 20, "aria-hidden": "true", focusable: "false" })
|
|
425
451
|
}
|
|
@@ -488,7 +514,7 @@ function FileList({ files, labels, onRemove }) {
|
|
|
488
514
|
return /* @__PURE__ */ jsx8("ul", { className: "cv-p-files", "aria-label": labels.attachmentsList, children: files.map((file, index) => /* @__PURE__ */ jsxs7("li", { className: "cv-p-files__item", children: [
|
|
489
515
|
/* @__PURE__ */ jsx8("span", { className: "cv-p-files__name", children: file.name }),
|
|
490
516
|
/* @__PURE__ */ jsx8("span", { className: "cv-p-files__size", children: formatFileSize(file.size) }),
|
|
491
|
-
/* @__PURE__ */ jsxs7("button", { type: "button", className: "cv-p-files__remove", "aria-label": `${labels.removeAttachment}: ${file.name}`, onClick: () => onRemove(file), children: [
|
|
517
|
+
/* @__PURE__ */ jsxs7("button", { type: "button", className: "cv-p-files__remove", "aria-label": `${labels.removeAttachment}: ${file.name}`, "data-cv-tooltip": labels.removeAttachment, onClick: () => onRemove(file), children: [
|
|
492
518
|
/* @__PURE__ */ jsx8("span", { "aria-hidden": "true", children: "\xD7" }),
|
|
493
519
|
/* @__PURE__ */ jsx8("span", { className: "cv-p-sr-only", children: labels.removeAttachment })
|
|
494
520
|
] })
|
|
@@ -544,8 +570,40 @@ function ParticipantComposer(props) {
|
|
|
544
570
|
] });
|
|
545
571
|
}
|
|
546
572
|
|
|
573
|
+
// src/participant/useSuppressTouchTooltips.ts
|
|
574
|
+
import { useEffect as useEffect2 } from "react";
|
|
575
|
+
function useSuppressTouchTooltips(rootRef) {
|
|
576
|
+
useEffect2(() => {
|
|
577
|
+
const root = rootRef.current;
|
|
578
|
+
if (!root) return void 0;
|
|
579
|
+
let isTouching = false;
|
|
580
|
+
function handlePointerDown(event) {
|
|
581
|
+
isTouching = event.pointerType === "touch";
|
|
582
|
+
}
|
|
583
|
+
function handlePointerOver(event) {
|
|
584
|
+
if (event.pointerType === "touch") event.stopPropagation();
|
|
585
|
+
}
|
|
586
|
+
function handleFocusIn(event) {
|
|
587
|
+
if (isTouching) event.stopPropagation();
|
|
588
|
+
}
|
|
589
|
+
function handleKeyDown() {
|
|
590
|
+
isTouching = false;
|
|
591
|
+
}
|
|
592
|
+
root.addEventListener("pointerdown", handlePointerDown, true);
|
|
593
|
+
root.addEventListener("pointerover", handlePointerOver);
|
|
594
|
+
root.addEventListener("focusin", handleFocusIn);
|
|
595
|
+
root.addEventListener("keydown", handleKeyDown, true);
|
|
596
|
+
return () => {
|
|
597
|
+
root.removeEventListener("pointerdown", handlePointerDown, true);
|
|
598
|
+
root.removeEventListener("pointerover", handlePointerOver);
|
|
599
|
+
root.removeEventListener("focusin", handleFocusIn);
|
|
600
|
+
root.removeEventListener("keydown", handleKeyDown, true);
|
|
601
|
+
};
|
|
602
|
+
}, [rootRef]);
|
|
603
|
+
}
|
|
604
|
+
|
|
547
605
|
// src/participant/ParticipantCopyAnnouncer.tsx
|
|
548
|
-
import { createContext, useCallback, useContext, useEffect as
|
|
606
|
+
import { createContext, useCallback, useContext, useEffect as useEffect3, useReducer, useRef as useRef3 } from "react";
|
|
549
607
|
|
|
550
608
|
// src/participant/participantCopyAnnouncement.ts
|
|
551
609
|
var INITIAL_COPY_ANNOUNCEMENT = { text: "", tick: 0 };
|
|
@@ -575,7 +633,7 @@ function useAnnounceCopy() {
|
|
|
575
633
|
function ParticipantCopyAnnouncer({ children }) {
|
|
576
634
|
const [announcement, dispatch] = useReducer(copyAnnouncementReducer, INITIAL_COPY_ANNOUNCEMENT);
|
|
577
635
|
const announce = useCallback((text) => dispatch({ type: "announce", text }), []);
|
|
578
|
-
|
|
636
|
+
useEffect3(() => {
|
|
579
637
|
if (announcement.text === "") return void 0;
|
|
580
638
|
const timer = setTimeout(() => dispatch({ type: "expired" }), ANNOUNCEMENT_MS);
|
|
581
639
|
return () => clearTimeout(timer);
|
|
@@ -616,6 +674,7 @@ function ParticipantScrollToLatest({
|
|
|
616
674
|
type: "button",
|
|
617
675
|
className: "cv-p-thread__latest-button",
|
|
618
676
|
"aria-label": label,
|
|
677
|
+
"data-cv-tooltip": label,
|
|
619
678
|
onClick: (event) => {
|
|
620
679
|
focusScrollerOf(event.currentTarget);
|
|
621
680
|
onClick();
|
|
@@ -692,8 +751,74 @@ function ParticipantDayDivider({ day, locale }) {
|
|
|
692
751
|
return /* @__PURE__ */ jsx12("div", { className: "cv-p-day", role: "separator", "aria-label": label, children: /* @__PURE__ */ jsx12("time", { className: "cv-p-day__label", dateTime: toDateTimeAttribute(day), children: label }) });
|
|
693
752
|
}
|
|
694
753
|
|
|
695
|
-
// src/participant/
|
|
754
|
+
// src/participant/ParticipantMessageBubble.tsx
|
|
755
|
+
import { useId as useId3 } from "react";
|
|
756
|
+
|
|
757
|
+
// src/participant/ParticipantAttachmentItem.tsx
|
|
758
|
+
import { useEffect as useEffect4, useState as useState2 } from "react";
|
|
759
|
+
|
|
760
|
+
// src/participant/participantAttachmentUrl.ts
|
|
761
|
+
var SAFE_ATTACHMENT_PROTOCOLS = /* @__PURE__ */ new Set(["https:", "http:", "blob:"]);
|
|
762
|
+
function isSafeAttachmentUrl(url) {
|
|
763
|
+
try {
|
|
764
|
+
return SAFE_ATTACHMENT_PROTOCOLS.has(new URL(url.trim()).protocol);
|
|
765
|
+
} catch {
|
|
766
|
+
return false;
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
// src/participant/ParticipantAttachmentItem.tsx
|
|
696
771
|
import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
772
|
+
function useAttachmentUrl(attachment, resolveAttachmentUrl) {
|
|
773
|
+
const [url, setUrl] = useState2(void 0);
|
|
774
|
+
const disposition = attachment.kind === "document" ? "attachment" : "inline";
|
|
775
|
+
useEffect4(() => {
|
|
776
|
+
let isCurrent = true;
|
|
777
|
+
resolveAttachmentUrl(attachment, disposition).then(
|
|
778
|
+
(resolved) => {
|
|
779
|
+
if (isCurrent) setUrl(isSafeAttachmentUrl(resolved) ? resolved.trim() : void 0);
|
|
780
|
+
},
|
|
781
|
+
() => {
|
|
782
|
+
if (isCurrent) setUrl(void 0);
|
|
783
|
+
}
|
|
784
|
+
);
|
|
785
|
+
return () => {
|
|
786
|
+
isCurrent = false;
|
|
787
|
+
};
|
|
788
|
+
}, [attachment, disposition, resolveAttachmentUrl]);
|
|
789
|
+
return url;
|
|
790
|
+
}
|
|
791
|
+
function ParticipantAttachmentItem({ attachment, resolveAttachmentUrl, labels }) {
|
|
792
|
+
const url = useAttachmentUrl(attachment, resolveAttachmentUrl);
|
|
793
|
+
if (attachment.kind === "image") {
|
|
794
|
+
return /* @__PURE__ */ jsxs9("figure", { className: "cv-p-attachment cv-p-attachment--image", children: [
|
|
795
|
+
url ? /* @__PURE__ */ jsx13("img", { className: "cv-p-attachment__image", src: url, alt: attachment.filename }) : null,
|
|
796
|
+
/* @__PURE__ */ jsx13("figcaption", { className: "cv-p-attachment__name", children: attachment.filename })
|
|
797
|
+
] });
|
|
798
|
+
}
|
|
799
|
+
if (attachment.kind === "audio") {
|
|
800
|
+
return /* @__PURE__ */ jsxs9("div", { className: "cv-p-attachment cv-p-attachment--audio", children: [
|
|
801
|
+
/* @__PURE__ */ jsx13("span", { className: "cv-p-attachment__name", children: attachment.filename }),
|
|
802
|
+
/* @__PURE__ */ jsx13("audio", { className: "cv-p-attachment__audio", controls: true, preload: "none", src: url })
|
|
803
|
+
] });
|
|
804
|
+
}
|
|
805
|
+
return /* @__PURE__ */ jsxs9(
|
|
806
|
+
"a",
|
|
807
|
+
{
|
|
808
|
+
className: "cv-p-attachment cv-p-attachment--document",
|
|
809
|
+
href: url,
|
|
810
|
+
download: attachment.filename,
|
|
811
|
+
"aria-label": `${labels.downloadAttachment}: ${attachment.filename}`,
|
|
812
|
+
children: [
|
|
813
|
+
/* @__PURE__ */ jsx13("span", { className: "cv-p-attachment__name", children: attachment.filename }),
|
|
814
|
+
/* @__PURE__ */ jsx13("span", { className: "cv-p-attachment__size", children: formatFileSize(attachment.sizeBytes) })
|
|
815
|
+
]
|
|
816
|
+
}
|
|
817
|
+
);
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
// src/participant/ParticipantBubbleStatus.tsx
|
|
821
|
+
import { jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
697
822
|
function statusText(status, labels) {
|
|
698
823
|
const byStatus = {
|
|
699
824
|
sending: labels.statusSending,
|
|
@@ -708,23 +833,204 @@ function statusText(status, labels) {
|
|
|
708
833
|
function OwnStatus({ status, labels, onRetry }) {
|
|
709
834
|
const ticksStatus = status === "sending" ? "queued" : status;
|
|
710
835
|
const isVisibleText = status === "sending" || status === "queued" || status === "failed";
|
|
711
|
-
if (status === "failed" && onRetry) {
|
|
712
|
-
return /* @__PURE__ */ jsxs9("button", { type: "button", className: "cv-p-bubble__retry", onClick: onRetry, children: [
|
|
713
|
-
/* @__PURE__ */ jsx13(StatusTicks, { status: "failed", appearance: "stylesheet" }),
|
|
714
|
-
/* @__PURE__ */ jsx13("span", { children: labels.statusFailed })
|
|
715
|
-
] });
|
|
716
|
-
}
|
|
717
836
|
const text = status === "failed" ? labels.statusFailedShort : statusText(status, labels);
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
/* @__PURE__ */
|
|
837
|
+
const isTextVisible = isVisibleText && !(status === "failed" && onRetry);
|
|
838
|
+
return /* @__PURE__ */ jsxs10("span", { className: "cv-p-bubble__status", children: [
|
|
839
|
+
/* @__PURE__ */ jsx14(StatusTicks, { status: ticksStatus, appearance: "stylesheet", title: isTextVisible ? void 0 : text }),
|
|
840
|
+
/* @__PURE__ */ jsx14("span", { className: isTextVisible ? "cv-p-bubble__status-text" : "cv-p-sr-only", children: text })
|
|
721
841
|
] });
|
|
722
842
|
}
|
|
723
|
-
function
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
843
|
+
function RetryButton({ labels, onRetry, describedBy }) {
|
|
844
|
+
return /* @__PURE__ */ jsx14(
|
|
845
|
+
"button",
|
|
846
|
+
{
|
|
847
|
+
type: "button",
|
|
848
|
+
className: "cv-p-failed-retry",
|
|
849
|
+
"aria-label": labels.statusFailed,
|
|
850
|
+
"aria-describedby": describedBy,
|
|
851
|
+
"data-cv-tooltip": labels.statusFailed,
|
|
852
|
+
onClick: onRetry,
|
|
853
|
+
children: /* @__PURE__ */ jsx14("span", { className: "cv-p-failed-retry__icon", children: /* @__PURE__ */ jsx14("svg", { viewBox: "0 0 16 16", width: "14", height: "14", "aria-hidden": "true", focusable: "false", children: /* @__PURE__ */ jsx14("path", { d: "M13 8a5 5 0 1 1-1.6-3.7M13 2.5v3h-3", fill: "none", stroke: "currentColor", strokeWidth: "1.5" }) }) })
|
|
854
|
+
}
|
|
855
|
+
);
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
// src/participant/ParticipantFailedMenu.tsx
|
|
859
|
+
import { useId as useId2 } from "react";
|
|
860
|
+
|
|
861
|
+
// src/participant/ParticipantFailedMenuList.tsx
|
|
862
|
+
import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
863
|
+
function ParticipantFailedMenuList({ menu, labelledBy, labels, onEdit, onDiscard }) {
|
|
864
|
+
function runAndClose(action) {
|
|
865
|
+
return () => {
|
|
866
|
+
menu.close();
|
|
867
|
+
action();
|
|
868
|
+
};
|
|
869
|
+
}
|
|
870
|
+
const className = `cv-p-failed-menu__list${menu.placement === "below" ? " cv-p-failed-menu__list--below" : ""}`;
|
|
871
|
+
return /* @__PURE__ */ jsxs11("div", { role: "menu", "aria-labelledby": labelledBy, ref: menu.menuRef, className, onKeyDown: menu.handleMenuKeyDown, children: [
|
|
872
|
+
onEdit ? /* @__PURE__ */ jsx15("button", { type: "button", role: "menuitem", tabIndex: -1, className: "cv-p-failed-menu__item", onClick: runAndClose(onEdit), children: labels.edit }) : null,
|
|
873
|
+
onDiscard ? /* @__PURE__ */ jsx15(
|
|
874
|
+
"button",
|
|
875
|
+
{
|
|
876
|
+
type: "button",
|
|
877
|
+
role: "menuitem",
|
|
878
|
+
tabIndex: -1,
|
|
879
|
+
className: "cv-p-failed-menu__item cv-p-failed-menu__item--danger",
|
|
880
|
+
onClick: runAndClose(onDiscard),
|
|
881
|
+
children: labels.discard
|
|
882
|
+
}
|
|
883
|
+
) : null
|
|
884
|
+
] });
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
// src/participant/useParticipantFailedMenu.ts
|
|
888
|
+
import { useReducer as useReducer2, useRef as useRef4 } from "react";
|
|
889
|
+
|
|
890
|
+
// src/participant/participantFailedMenuState.ts
|
|
891
|
+
var CLOSED_FAILED_MENU = { isOpen: false, initialFocus: "first" };
|
|
892
|
+
function failedMenuReducer(state, action) {
|
|
893
|
+
if (action.type === "open") return { isOpen: true, initialFocus: action.initialFocus };
|
|
894
|
+
if (action.type === "close") return state.isOpen ? CLOSED_FAILED_MENU : state;
|
|
895
|
+
return state.isOpen ? CLOSED_FAILED_MENU : { isOpen: true, initialFocus: "first" };
|
|
896
|
+
}
|
|
897
|
+
function resolveFailedMenuKey({ key, index, count }) {
|
|
898
|
+
if (key === "Escape") return { type: "close", shouldRestoreFocus: true };
|
|
899
|
+
if (key === "Tab") return { type: "close", shouldRestoreFocus: false };
|
|
900
|
+
if (key === "ArrowDown") return { type: "focus", index: (index + 1) % count };
|
|
901
|
+
if (key === "ArrowUp") return { type: "focus", index: (index - 1 + count) % count };
|
|
902
|
+
if (key === "Home") return { type: "focus", index: 0 };
|
|
903
|
+
if (key === "End") return { type: "focus", index: count - 1 };
|
|
904
|
+
return void 0;
|
|
905
|
+
}
|
|
906
|
+
function resolveFailedMenuTriggerKey(key) {
|
|
907
|
+
if (key === "ArrowDown") return "first";
|
|
908
|
+
if (key === "ArrowUp") return "last";
|
|
909
|
+
return void 0;
|
|
910
|
+
}
|
|
911
|
+
var MENU_GAP_PX = 8;
|
|
912
|
+
function resolveFailedMenuPlacement({ anchorTop, scrollerTop, menuHeight }) {
|
|
913
|
+
return anchorTop - scrollerTop >= menuHeight + MENU_GAP_PX ? "above" : "below";
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
// src/participant/failedMenuKeyboard.ts
|
|
917
|
+
function handleFailedMenuKeyDown({ event, menuRef, triggerRef, dispatch }) {
|
|
918
|
+
const items = Array.from(menuRef.current?.querySelectorAll('[role="menuitem"]') ?? []);
|
|
919
|
+
const index = items.findIndex((item) => item === document.activeElement);
|
|
920
|
+
const result = resolveFailedMenuKey({ key: event.key, index, count: items.length });
|
|
921
|
+
if (!result) return;
|
|
922
|
+
if (result.type === "focus") {
|
|
923
|
+
event.preventDefault();
|
|
924
|
+
items[result.index]?.focus();
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
if (result.shouldRestoreFocus) {
|
|
928
|
+
event.preventDefault();
|
|
929
|
+
event.stopPropagation();
|
|
930
|
+
triggerRef.current?.focus();
|
|
931
|
+
}
|
|
932
|
+
dispatch({ type: "close" });
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
// src/participant/useFailedMenuEffects.ts
|
|
936
|
+
import { useEffect as useEffect5, useLayoutEffect as useLayoutEffect2, useState as useState3 } from "react";
|
|
937
|
+
var SCROLLER_SELECTOR2 = ".cv-p-thread__scroll";
|
|
938
|
+
function useFailedMenuInitialFocus(state, menuRef) {
|
|
939
|
+
useEffect5(() => {
|
|
940
|
+
if (!state.isOpen) return;
|
|
941
|
+
const items = Array.from(menuRef.current?.querySelectorAll('[role="menuitem"]') ?? []);
|
|
942
|
+
const target = state.initialFocus === "last" ? items[items.length - 1] : items[0];
|
|
943
|
+
target?.focus();
|
|
944
|
+
}, [state, menuRef]);
|
|
945
|
+
}
|
|
946
|
+
function useFailedMenuOutsideClose(isOpen, containerRef, dispatch) {
|
|
947
|
+
useEffect5(() => {
|
|
948
|
+
if (!isOpen) return;
|
|
949
|
+
function handlePointerDown(event) {
|
|
950
|
+
if (event.target instanceof Node && containerRef.current?.contains(event.target)) return;
|
|
951
|
+
dispatch({ type: "close" });
|
|
952
|
+
}
|
|
953
|
+
document.addEventListener("pointerdown", handlePointerDown);
|
|
954
|
+
return () => document.removeEventListener("pointerdown", handlePointerDown);
|
|
955
|
+
}, [isOpen, containerRef, dispatch]);
|
|
956
|
+
}
|
|
957
|
+
function useFailedMenuPlacement(isOpen, { triggerRef, menuRef }) {
|
|
958
|
+
const [placement, setPlacement] = useState3("above");
|
|
959
|
+
useLayoutEffect2(() => {
|
|
960
|
+
const trigger = triggerRef.current;
|
|
961
|
+
const menu = menuRef.current;
|
|
962
|
+
if (!isOpen || !trigger || !menu) return;
|
|
963
|
+
const anchor = trigger.closest(".cv-p-bubble") ?? trigger;
|
|
964
|
+
const scroller = trigger.closest(SCROLLER_SELECTOR2);
|
|
965
|
+
setPlacement(
|
|
966
|
+
resolveFailedMenuPlacement({
|
|
967
|
+
anchorTop: anchor.getBoundingClientRect().top,
|
|
968
|
+
scrollerTop: scroller?.getBoundingClientRect().top ?? 0,
|
|
969
|
+
menuHeight: menu.getBoundingClientRect().height
|
|
970
|
+
})
|
|
971
|
+
);
|
|
972
|
+
}, [isOpen, triggerRef, menuRef]);
|
|
973
|
+
return placement;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
// src/participant/useParticipantFailedMenu.ts
|
|
977
|
+
function useParticipantFailedMenu() {
|
|
978
|
+
const [state, dispatch] = useReducer2(failedMenuReducer, CLOSED_FAILED_MENU);
|
|
979
|
+
const containerRef = useRef4(null);
|
|
980
|
+
const triggerRef = useRef4(null);
|
|
981
|
+
const menuRef = useRef4(null);
|
|
982
|
+
useFailedMenuInitialFocus(state, menuRef);
|
|
983
|
+
useFailedMenuOutsideClose(state.isOpen, containerRef, dispatch);
|
|
984
|
+
const placement = useFailedMenuPlacement(state.isOpen, { triggerRef, menuRef });
|
|
985
|
+
function handleTriggerKeyDown(event) {
|
|
986
|
+
const initialFocus = resolveFailedMenuTriggerKey(event.key);
|
|
987
|
+
if (!initialFocus) return;
|
|
988
|
+
event.preventDefault();
|
|
989
|
+
dispatch({ type: "open", initialFocus });
|
|
990
|
+
}
|
|
991
|
+
function handleBlur(event) {
|
|
992
|
+
const next = event.relatedTarget;
|
|
993
|
+
if (next instanceof Node && !containerRef.current?.contains(next)) dispatch({ type: "close" });
|
|
994
|
+
}
|
|
995
|
+
return {
|
|
996
|
+
state,
|
|
997
|
+
placement,
|
|
998
|
+
containerRef,
|
|
999
|
+
triggerRef,
|
|
1000
|
+
menuRef,
|
|
1001
|
+
handleTriggerClick: () => dispatch({ type: "toggle" }),
|
|
1002
|
+
handleTriggerKeyDown,
|
|
1003
|
+
handleMenuKeyDown: (event) => handleFailedMenuKeyDown({ event, menuRef, triggerRef, dispatch }),
|
|
1004
|
+
handleBlur,
|
|
1005
|
+
close: () => dispatch({ type: "close" })
|
|
1006
|
+
};
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
// src/participant/ParticipantFailedMenu.tsx
|
|
1010
|
+
import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1011
|
+
function ParticipantFailedMenu({ labels, onEdit, onDiscard }) {
|
|
1012
|
+
const menu = useParticipantFailedMenu();
|
|
1013
|
+
const triggerId = useId2();
|
|
1014
|
+
if (!onEdit && !onDiscard) return null;
|
|
1015
|
+
const label = labels.messageOptions ?? DEFAULT_MESSAGE_OPTIONS_LABEL;
|
|
1016
|
+
return /* @__PURE__ */ jsxs12("span", { className: "cv-p-failed-menu", ref: menu.containerRef, onBlur: menu.handleBlur, children: [
|
|
1017
|
+
/* @__PURE__ */ jsx16(
|
|
1018
|
+
"button",
|
|
1019
|
+
{
|
|
1020
|
+
type: "button",
|
|
1021
|
+
id: triggerId,
|
|
1022
|
+
ref: menu.triggerRef,
|
|
1023
|
+
className: "cv-p-failed-menu__trigger",
|
|
1024
|
+
"aria-haspopup": "menu",
|
|
1025
|
+
"aria-expanded": menu.state.isOpen,
|
|
1026
|
+
"aria-label": label,
|
|
1027
|
+
"data-cv-tooltip": menu.state.isOpen ? void 0 : label,
|
|
1028
|
+
onClick: menu.handleTriggerClick,
|
|
1029
|
+
onKeyDown: menu.handleTriggerKeyDown,
|
|
1030
|
+
children: /* @__PURE__ */ jsx16("span", { "aria-hidden": "true", children: "\u22EF" })
|
|
1031
|
+
}
|
|
1032
|
+
),
|
|
1033
|
+
menu.state.isOpen ? /* @__PURE__ */ jsx16(ParticipantFailedMenuList, { menu, labelledBy: triggerId, labels, onEdit, onDiscard }) : null
|
|
728
1034
|
] });
|
|
729
1035
|
}
|
|
730
1036
|
|
|
@@ -735,7 +1041,7 @@ import { useMemo } from "react";
|
|
|
735
1041
|
import { Check, Copy } from "lucide-react";
|
|
736
1042
|
|
|
737
1043
|
// src/participant/useParticipantCopyFeedback.ts
|
|
738
|
-
import { useEffect as
|
|
1044
|
+
import { useEffect as useEffect6, useReducer as useReducer3 } from "react";
|
|
739
1045
|
|
|
740
1046
|
// src/participant/participantProtocolCopy.ts
|
|
741
1047
|
async function copyProtocolToClipboard(protocol, clipboard) {
|
|
@@ -756,10 +1062,10 @@ function protocolCopyReducer(state, action) {
|
|
|
756
1062
|
// src/participant/useParticipantCopyFeedback.ts
|
|
757
1063
|
var COPIED_FEEDBACK_MS = 2e3;
|
|
758
1064
|
function useParticipantCopyFeedback() {
|
|
759
|
-
const [state, dispatch] =
|
|
1065
|
+
const [state, dispatch] = useReducer3(protocolCopyReducer, INITIAL_PROTOCOL_COPY_STATE);
|
|
760
1066
|
const announce = useAnnounceCopy();
|
|
761
1067
|
const { isCopied, copyCount } = state;
|
|
762
|
-
|
|
1068
|
+
useEffect6(() => {
|
|
763
1069
|
if (!isCopied) return void 0;
|
|
764
1070
|
const timer = setTimeout(() => dispatch({ type: "expired" }), COPIED_FEEDBACK_MS);
|
|
765
1071
|
return () => clearTimeout(timer);
|
|
@@ -774,10 +1080,10 @@ function useParticipantCopyFeedback() {
|
|
|
774
1080
|
}
|
|
775
1081
|
|
|
776
1082
|
// src/participant/ParticipantCopyableToken.tsx
|
|
777
|
-
import { jsx as
|
|
1083
|
+
import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
778
1084
|
function ParticipantCopyableToken({ copyKind, value, labels }) {
|
|
779
1085
|
const { isCopied, copy } = useParticipantCopyFeedback();
|
|
780
|
-
return /* @__PURE__ */
|
|
1086
|
+
return /* @__PURE__ */ jsxs13(
|
|
781
1087
|
"button",
|
|
782
1088
|
{
|
|
783
1089
|
type: "button",
|
|
@@ -786,8 +1092,8 @@ function ParticipantCopyableToken({ copyKind, value, labels }) {
|
|
|
786
1092
|
onClick: () => copy(value, labels.valueCopied),
|
|
787
1093
|
children: [
|
|
788
1094
|
value,
|
|
789
|
-
isCopied ? /* @__PURE__ */
|
|
790
|
-
/* @__PURE__ */
|
|
1095
|
+
isCopied ? /* @__PURE__ */ jsxs13("span", { className: "cv-p-copyable__done", "aria-hidden": "true", children: [
|
|
1096
|
+
/* @__PURE__ */ jsx17(Check, { size: 12, "aria-hidden": true }),
|
|
791
1097
|
" ",
|
|
792
1098
|
labels.valueCopied
|
|
793
1099
|
] }) : null
|
|
@@ -797,33 +1103,34 @@ function ParticipantCopyableToken({ copyKind, value, labels }) {
|
|
|
797
1103
|
}
|
|
798
1104
|
function ParticipantLinkCopyButton({ value, labels }) {
|
|
799
1105
|
const { isCopied, copy } = useParticipantCopyFeedback();
|
|
800
|
-
return /* @__PURE__ */
|
|
1106
|
+
return /* @__PURE__ */ jsx17(
|
|
801
1107
|
"button",
|
|
802
1108
|
{
|
|
803
1109
|
type: "button",
|
|
804
1110
|
className: "cv-p-text__link-copy",
|
|
805
1111
|
"aria-label": `${labels.copyValue} ${value}`,
|
|
1112
|
+
"data-cv-tooltip": labels.copyValue,
|
|
806
1113
|
onClick: () => copy(value, labels.valueCopied),
|
|
807
|
-
children: isCopied ? /* @__PURE__ */
|
|
1114
|
+
children: isCopied ? /* @__PURE__ */ jsx17(Check, { size: 14, "aria-hidden": true }) : /* @__PURE__ */ jsx17(Copy, { size: 14, "aria-hidden": true })
|
|
808
1115
|
}
|
|
809
1116
|
);
|
|
810
1117
|
}
|
|
811
1118
|
|
|
812
1119
|
// src/participant/ParticipantMessageNodes.tsx
|
|
813
|
-
import { jsx as
|
|
1120
|
+
import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
814
1121
|
var LINK_REL = "noopener noreferrer nofollow ugc";
|
|
815
1122
|
function renderLink(node, labels, key) {
|
|
816
1123
|
const isExternal = /^https?:/i.test(node.href);
|
|
817
|
-
return /* @__PURE__ */
|
|
818
|
-
/* @__PURE__ */
|
|
1124
|
+
return /* @__PURE__ */ jsxs14("span", { className: "cv-p-text__link-group", children: [
|
|
1125
|
+
/* @__PURE__ */ jsxs14("a", { className: "cv-p-text__link", href: node.href, rel: LINK_REL, target: isExternal ? "_blank" : void 0, children: [
|
|
819
1126
|
node.label,
|
|
820
|
-
isExternal ? /* @__PURE__ */
|
|
1127
|
+
isExternal ? /* @__PURE__ */ jsxs14("span", { className: "cv-p-sr-only", children: [
|
|
821
1128
|
" (",
|
|
822
1129
|
labels.externalLinkHint,
|
|
823
1130
|
")"
|
|
824
1131
|
] }) : null
|
|
825
1132
|
] }),
|
|
826
|
-
/* @__PURE__ */
|
|
1133
|
+
/* @__PURE__ */ jsx18(ParticipantLinkCopyButton, { value: node.href, labels })
|
|
827
1134
|
] }, key);
|
|
828
1135
|
}
|
|
829
1136
|
function renderInlineNodes(nodes, labels) {
|
|
@@ -832,17 +1139,17 @@ function renderInlineNodes(nodes, labels) {
|
|
|
832
1139
|
case "text":
|
|
833
1140
|
return node.value;
|
|
834
1141
|
case "strong":
|
|
835
|
-
return /* @__PURE__ */
|
|
1142
|
+
return /* @__PURE__ */ jsx18("strong", { children: renderInlineNodes(node.children, labels) }, key);
|
|
836
1143
|
case "em":
|
|
837
|
-
return /* @__PURE__ */
|
|
1144
|
+
return /* @__PURE__ */ jsx18("em", { children: renderInlineNodes(node.children, labels) }, key);
|
|
838
1145
|
case "del":
|
|
839
|
-
return /* @__PURE__ */
|
|
1146
|
+
return /* @__PURE__ */ jsx18("del", { children: renderInlineNodes(node.children, labels) }, key);
|
|
840
1147
|
case "code":
|
|
841
|
-
return /* @__PURE__ */
|
|
1148
|
+
return /* @__PURE__ */ jsx18("code", { className: "cv-p-text__code", children: node.value }, key);
|
|
842
1149
|
case "link":
|
|
843
1150
|
return renderLink(node, labels, key);
|
|
844
1151
|
case "copyable":
|
|
845
|
-
return /* @__PURE__ */
|
|
1152
|
+
return /* @__PURE__ */ jsx18(ParticipantCopyableToken, { copyKind: node.copyKind, value: node.value, labels }, key);
|
|
846
1153
|
}
|
|
847
1154
|
});
|
|
848
1155
|
}
|
|
@@ -1228,90 +1535,56 @@ function startsFenceLine(line) {
|
|
|
1228
1535
|
}
|
|
1229
1536
|
|
|
1230
1537
|
// src/participant/ParticipantMessageText.tsx
|
|
1231
|
-
import { jsx as
|
|
1538
|
+
import { jsx as jsx19 } from "react/jsx-runtime";
|
|
1232
1539
|
function renderBlock(block, labels, key) {
|
|
1233
|
-
if (block.kind === "paragraph") return /* @__PURE__ */
|
|
1540
|
+
if (block.kind === "paragraph") return /* @__PURE__ */ jsx19("span", { children: renderInlineNodes(block.children, labels) }, key);
|
|
1234
1541
|
if (block.kind === "pre") {
|
|
1235
|
-
return /* @__PURE__ */
|
|
1542
|
+
return /* @__PURE__ */ jsx19("pre", { className: "cv-p-text__pre", children: /* @__PURE__ */ jsx19("code", { children: block.value }) }, key);
|
|
1236
1543
|
}
|
|
1237
1544
|
if (block.kind === "quote") {
|
|
1238
|
-
return /* @__PURE__ */
|
|
1545
|
+
return /* @__PURE__ */ jsx19("blockquote", { className: "cv-p-text__quote", children: renderInlineNodes(block.children, labels) }, key);
|
|
1239
1546
|
}
|
|
1240
|
-
const items = block.items.map((item, index) => /* @__PURE__ */
|
|
1547
|
+
const items = block.items.map((item, index) => /* @__PURE__ */ jsx19("li", { children: renderInlineNodes(item, labels) }, index));
|
|
1241
1548
|
if (block.ordered) {
|
|
1242
|
-
return /* @__PURE__ */
|
|
1549
|
+
return /* @__PURE__ */ jsx19("ol", { className: "cv-p-text__list", start: block.start === 1 ? void 0 : block.start, children: items }, key);
|
|
1243
1550
|
}
|
|
1244
|
-
return /* @__PURE__ */
|
|
1551
|
+
return /* @__PURE__ */ jsx19("ul", { className: "cv-p-text__list", children: items }, key);
|
|
1245
1552
|
}
|
|
1246
|
-
function ParticipantMessageText({ text, labels }) {
|
|
1553
|
+
function ParticipantMessageText({ text, labels, id }) {
|
|
1247
1554
|
const blocks = useMemo(() => parseParticipantMessage(text), [text]);
|
|
1248
1555
|
if (blocks.length === 0) return null;
|
|
1249
1556
|
const [only] = blocks;
|
|
1250
1557
|
const children = blocks.length === 1 && only?.kind === "paragraph" ? renderInlineNodes(only.children, labels) : blocks.map((block, key) => renderBlock(block, labels, key));
|
|
1251
|
-
return /* @__PURE__ */
|
|
1558
|
+
return /* @__PURE__ */ jsx19("div", { className: "cv-p-text", id, children });
|
|
1252
1559
|
}
|
|
1253
1560
|
|
|
1254
|
-
// src/participant/
|
|
1255
|
-
import {
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
try {
|
|
1261
|
-
return SAFE_ATTACHMENT_PROTOCOLS.has(new URL(url.trim()).protocol);
|
|
1262
|
-
} catch {
|
|
1263
|
-
return false;
|
|
1264
|
-
}
|
|
1561
|
+
// src/participant/ParticipantBubbleBody.tsx
|
|
1562
|
+
import { Fragment as Fragment4, jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1563
|
+
function BubbleHeading({ content, labels }) {
|
|
1564
|
+
if (content.isMine) return /* @__PURE__ */ jsx20("span", { className: "cv-p-sr-only", children: labels.me });
|
|
1565
|
+
if (!content.authorName) return null;
|
|
1566
|
+
return /* @__PURE__ */ jsx20("span", { className: "cv-p-bubble__author", children: content.authorName });
|
|
1265
1567
|
}
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
if (isCurrent) setUrl(isSafeAttachmentUrl(resolved) ? resolved.trim() : void 0);
|
|
1568
|
+
function BubbleBody({ content, labels, ownStatus, textId, resolveAttachmentUrl, onRetry, onDiscard, onEdit }) {
|
|
1569
|
+
return /* @__PURE__ */ jsxs15(Fragment4, { children: [
|
|
1570
|
+
/* @__PURE__ */ jsx20(BubbleHeading, { content, labels }),
|
|
1571
|
+
content.text ? /* @__PURE__ */ jsx20(ParticipantMessageText, { text: content.text, labels, id: textId }) : null,
|
|
1572
|
+
content.attachments.map((attachment) => /* @__PURE__ */ jsx20(
|
|
1573
|
+
ParticipantAttachmentItem,
|
|
1574
|
+
{
|
|
1575
|
+
attachment,
|
|
1576
|
+
resolveAttachmentUrl,
|
|
1577
|
+
labels
|
|
1277
1578
|
},
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
}
|
|
1288
|
-
function ParticipantAttachmentItem({ attachment, resolveAttachmentUrl, labels }) {
|
|
1289
|
-
const url = useAttachmentUrl(attachment, resolveAttachmentUrl);
|
|
1290
|
-
if (attachment.kind === "image") {
|
|
1291
|
-
return /* @__PURE__ */ jsxs12("figure", { className: "cv-p-attachment cv-p-attachment--image", children: [
|
|
1292
|
-
url ? /* @__PURE__ */ jsx17("img", { className: "cv-p-attachment__image", src: url, alt: attachment.filename }) : null,
|
|
1293
|
-
/* @__PURE__ */ jsx17("figcaption", { className: "cv-p-attachment__name", children: attachment.filename })
|
|
1294
|
-
] });
|
|
1295
|
-
}
|
|
1296
|
-
if (attachment.kind === "audio") {
|
|
1297
|
-
return /* @__PURE__ */ jsxs12("div", { className: "cv-p-attachment cv-p-attachment--audio", children: [
|
|
1298
|
-
/* @__PURE__ */ jsx17("span", { className: "cv-p-attachment__name", children: attachment.filename }),
|
|
1299
|
-
/* @__PURE__ */ jsx17("audio", { className: "cv-p-attachment__audio", controls: true, preload: "none", src: url })
|
|
1300
|
-
] });
|
|
1301
|
-
}
|
|
1302
|
-
return /* @__PURE__ */ jsxs12(
|
|
1303
|
-
"a",
|
|
1304
|
-
{
|
|
1305
|
-
className: "cv-p-attachment cv-p-attachment--document",
|
|
1306
|
-
href: url,
|
|
1307
|
-
download: attachment.filename,
|
|
1308
|
-
"aria-label": `${labels.downloadAttachment}: ${attachment.filename}`,
|
|
1309
|
-
children: [
|
|
1310
|
-
/* @__PURE__ */ jsx17("span", { className: "cv-p-attachment__name", children: attachment.filename }),
|
|
1311
|
-
/* @__PURE__ */ jsx17("span", { className: "cv-p-attachment__size", children: formatFileSize(attachment.sizeBytes) })
|
|
1312
|
-
]
|
|
1313
|
-
}
|
|
1314
|
-
);
|
|
1579
|
+
attachment.id
|
|
1580
|
+
)),
|
|
1581
|
+
content.pendingFilenames.map((filename, index) => /* @__PURE__ */ jsx20("span", { className: "cv-p-attachment cv-p-attachment--pending", children: filename }, `${filename}-${index}`)),
|
|
1582
|
+
/* @__PURE__ */ jsxs15("span", { className: "cv-p-bubble__meta", children: [
|
|
1583
|
+
/* @__PURE__ */ jsx20("time", { className: "cv-p-bubble__time", dateTime: content.createdAt, children: formatTimestamp(content.createdAt) }),
|
|
1584
|
+
ownStatus ? /* @__PURE__ */ jsx20(OwnStatus, { status: ownStatus, labels, onRetry }) : null,
|
|
1585
|
+
ownStatus === "failed" ? /* @__PURE__ */ jsx20(ParticipantFailedMenu, { labels, onEdit, onDiscard }) : null
|
|
1586
|
+
] })
|
|
1587
|
+
] });
|
|
1315
1588
|
}
|
|
1316
1589
|
|
|
1317
1590
|
// src/participant/participantPerspective.ts
|
|
@@ -1376,7 +1649,7 @@ function resolveOwnMessageStatus(params) {
|
|
|
1376
1649
|
}
|
|
1377
1650
|
|
|
1378
1651
|
// src/participant/ParticipantMessageBubble.tsx
|
|
1379
|
-
import { jsx as
|
|
1652
|
+
import { jsx as jsx21, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1380
1653
|
function describeItem(item, perspective) {
|
|
1381
1654
|
if (item.kind === "server") {
|
|
1382
1655
|
const { message } = item;
|
|
@@ -1399,49 +1672,27 @@ function describeItem(item, perspective) {
|
|
|
1399
1672
|
displayState: item.displayState
|
|
1400
1673
|
};
|
|
1401
1674
|
}
|
|
1402
|
-
function bubbleClassName(isMine, hasTail) {
|
|
1675
|
+
function bubbleClassName(isMine, hasTail, hasFailed) {
|
|
1403
1676
|
const classes = ["cv-p-bubble"];
|
|
1404
1677
|
if (isMine) classes.push("cv-p-bubble--mine");
|
|
1678
|
+
if (hasFailed) classes.push("cv-p-bubble--failed");
|
|
1405
1679
|
if (!hasTail) classes.push("cv-p-bubble--no-tail");
|
|
1406
1680
|
return classes.join(" ");
|
|
1407
1681
|
}
|
|
1408
|
-
function ParticipantMessageBubble({
|
|
1409
|
-
item,
|
|
1410
|
-
|
|
1411
|
-
confirmsRead,
|
|
1412
|
-
resolveAttachmentUrl,
|
|
1413
|
-
onRetry,
|
|
1414
|
-
onDiscard,
|
|
1415
|
-
onEdit,
|
|
1416
|
-
avatar,
|
|
1417
|
-
tail = true,
|
|
1418
|
-
perspective
|
|
1419
|
-
}) {
|
|
1682
|
+
function ParticipantMessageBubble(props) {
|
|
1683
|
+
const { item, labels, confirmsRead, onRetry, avatar, tail = true, perspective } = props;
|
|
1684
|
+
const textId = useId3();
|
|
1420
1685
|
const content = describeItem(item, perspective);
|
|
1421
|
-
const
|
|
1422
|
-
const
|
|
1423
|
-
const
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
ParticipantAttachmentItem,
|
|
1428
|
-
{
|
|
1429
|
-
attachment,
|
|
1430
|
-
resolveAttachmentUrl,
|
|
1431
|
-
labels
|
|
1432
|
-
},
|
|
1433
|
-
attachment.id
|
|
1434
|
-
)),
|
|
1435
|
-
content.pendingFilenames.map((filename, index) => /* @__PURE__ */ jsx18("span", { className: "cv-p-attachment cv-p-attachment--pending", children: filename }, `${filename}-${index}`)),
|
|
1436
|
-
/* @__PURE__ */ jsxs13("span", { className: "cv-p-bubble__meta", children: [
|
|
1437
|
-
/* @__PURE__ */ jsx18("time", { className: "cv-p-bubble__time", dateTime: content.createdAt, children: formatTimestamp(content.createdAt) }),
|
|
1438
|
-
ownStatus ? /* @__PURE__ */ jsx18(OwnStatus, { status: ownStatus, labels, onRetry }) : null
|
|
1439
|
-
] }),
|
|
1440
|
-
ownStatus === "failed" ? /* @__PURE__ */ jsx18(FailedActions, { labels, onDiscard, onEdit }) : null
|
|
1686
|
+
const ownStatus = content.isMine ? resolveOwnMessageStatus({ displayState: content.displayState, serverStatus: content.serverStatus, confirmsRead }) : void 0;
|
|
1687
|
+
const isFailed = ownStatus === "failed";
|
|
1688
|
+
const canRetry = isFailed && onRetry !== void 0;
|
|
1689
|
+
const bubble = /* @__PURE__ */ jsxs16("div", { className: bubbleClassName(content.isMine, tail, isFailed), children: [
|
|
1690
|
+
canRetry ? /* @__PURE__ */ jsx21(RetryButton, { labels, onRetry, describedBy: textId }) : null,
|
|
1691
|
+
/* @__PURE__ */ jsx21(BubbleBody, { ...props, content, ownStatus, textId: canRetry ? textId : void 0 })
|
|
1441
1692
|
] });
|
|
1442
|
-
if (avatar === void 0 || isMine) return bubble;
|
|
1443
|
-
return /* @__PURE__ */
|
|
1444
|
-
/* @__PURE__ */
|
|
1693
|
+
if (avatar === void 0 || content.isMine) return bubble;
|
|
1694
|
+
return /* @__PURE__ */ jsxs16("div", { className: "cv-p-bubble-row", children: [
|
|
1695
|
+
/* @__PURE__ */ jsx21("span", { className: "cv-p-bubble-row__avatar", children: avatar }),
|
|
1445
1696
|
bubble
|
|
1446
1697
|
] });
|
|
1447
1698
|
}
|
|
@@ -1463,7 +1714,7 @@ function resolveParticipantBubbleActions(item, handlers) {
|
|
|
1463
1714
|
}
|
|
1464
1715
|
|
|
1465
1716
|
// src/participant/ParticipantTimeline.tsx
|
|
1466
|
-
import { jsx as
|
|
1717
|
+
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
1467
1718
|
function createdAtOf2(item) {
|
|
1468
1719
|
return item.kind === "server" ? item.message.createdAt : item.pending.createdAt;
|
|
1469
1720
|
}
|
|
@@ -1480,7 +1731,7 @@ function resolveActions(item, pendingActions) {
|
|
|
1480
1731
|
}
|
|
1481
1732
|
function resolveAvatarSlot({ isEnabled, isMine, showAvatar, author, render }) {
|
|
1482
1733
|
if (!isEnabled || isMine) return void 0;
|
|
1483
|
-
return showAvatar ? /* @__PURE__ */
|
|
1734
|
+
return showAvatar ? /* @__PURE__ */ jsx22(ParticipantAuthorAvatar, { name: author, render }) : null;
|
|
1484
1735
|
}
|
|
1485
1736
|
function ParticipantTimeline(props) {
|
|
1486
1737
|
const { items, labels, locale, resolveAttachmentUrl, pendingActions } = props;
|
|
@@ -1492,7 +1743,7 @@ function ParticipantTimeline(props) {
|
|
|
1492
1743
|
for (const item of items) {
|
|
1493
1744
|
const day = new Date(createdAtOf2(item));
|
|
1494
1745
|
if (previousDay === void 0 || !isSameDay(previousDay, day)) {
|
|
1495
|
-
nodes.push(/* @__PURE__ */
|
|
1746
|
+
nodes.push(/* @__PURE__ */ jsx22(ParticipantDayDivider, { day, locale }, `day:${keyOf(item)}`));
|
|
1496
1747
|
previousAuthor = void 0;
|
|
1497
1748
|
}
|
|
1498
1749
|
previousDay = day;
|
|
@@ -1507,7 +1758,7 @@ function ParticipantTimeline(props) {
|
|
|
1507
1758
|
render: props.renderAuthorAvatar
|
|
1508
1759
|
});
|
|
1509
1760
|
nodes.push(
|
|
1510
|
-
/* @__PURE__ */
|
|
1761
|
+
/* @__PURE__ */ jsx22(
|
|
1511
1762
|
ParticipantMessageBubble,
|
|
1512
1763
|
{
|
|
1513
1764
|
item,
|
|
@@ -1523,19 +1774,19 @@ function ParticipantTimeline(props) {
|
|
|
1523
1774
|
)
|
|
1524
1775
|
);
|
|
1525
1776
|
}
|
|
1526
|
-
return /* @__PURE__ */
|
|
1777
|
+
return /* @__PURE__ */ jsx22("div", { className: "cv-p-thread__messages", children: nodes });
|
|
1527
1778
|
}
|
|
1528
1779
|
|
|
1529
1780
|
// src/participant/ParticipantConversationAvatar.tsx
|
|
1530
|
-
import { jsx as
|
|
1781
|
+
import { jsx as jsx23 } from "react/jsx-runtime";
|
|
1531
1782
|
function ParticipantConversationAvatar({ icon }) {
|
|
1532
|
-
return /* @__PURE__ */
|
|
1783
|
+
return /* @__PURE__ */ jsx23("span", { className: "cv-p-thread__avatar", "aria-hidden": "true", children: icon });
|
|
1533
1784
|
}
|
|
1534
1785
|
|
|
1535
1786
|
// src/participant/ParticipantProtocolBadge.tsx
|
|
1536
1787
|
import { Check as Check2, Copy as Copy2 } from "lucide-react";
|
|
1537
|
-
import { useEffect as
|
|
1538
|
-
import { Fragment as
|
|
1788
|
+
import { useEffect as useEffect7, useReducer as useReducer4 } from "react";
|
|
1789
|
+
import { Fragment as Fragment5, jsx as jsx24, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1539
1790
|
var COPIED_ANNOUNCEMENT_MS = 3e3;
|
|
1540
1791
|
function ParticipantProtocolBadgeView({
|
|
1541
1792
|
protocol,
|
|
@@ -1544,36 +1795,37 @@ function ParticipantProtocolBadgeView({
|
|
|
1544
1795
|
onCopy
|
|
1545
1796
|
}) {
|
|
1546
1797
|
const { isCopied, copyCount } = copyState;
|
|
1547
|
-
return /* @__PURE__ */
|
|
1548
|
-
/* @__PURE__ */
|
|
1549
|
-
/* @__PURE__ */
|
|
1550
|
-
/* @__PURE__ */
|
|
1798
|
+
return /* @__PURE__ */ jsxs17(Fragment5, { children: [
|
|
1799
|
+
/* @__PURE__ */ jsxs17("span", { className: "cv-p-protocol cv-p-protocol--header", children: [
|
|
1800
|
+
/* @__PURE__ */ jsxs17("span", { className: "cv-p-protocol__code", children: [
|
|
1801
|
+
/* @__PURE__ */ jsxs17("span", { className: "cv-p-sr-only", children: [
|
|
1551
1802
|
labels.protocolPrefix,
|
|
1552
1803
|
" "
|
|
1553
1804
|
] }),
|
|
1554
1805
|
protocol
|
|
1555
1806
|
] }),
|
|
1556
|
-
/* @__PURE__ */
|
|
1807
|
+
/* @__PURE__ */ jsxs17(
|
|
1557
1808
|
"button",
|
|
1558
1809
|
{
|
|
1559
1810
|
type: "button",
|
|
1560
1811
|
className: "cv-p-protocol__copy",
|
|
1561
1812
|
"aria-label": `${labels.copyProtocol} ${protocol}`,
|
|
1813
|
+
"data-cv-tooltip": labels.copyProtocol,
|
|
1562
1814
|
onClick: onCopy,
|
|
1563
1815
|
children: [
|
|
1564
|
-
isCopied ? /* @__PURE__ */
|
|
1565
|
-
isCopied ? /* @__PURE__ */
|
|
1816
|
+
isCopied ? /* @__PURE__ */ jsx24(Check2, { size: 18, "aria-hidden": true }) : /* @__PURE__ */ jsx24(Copy2, { size: 18, "aria-hidden": true }),
|
|
1817
|
+
isCopied ? /* @__PURE__ */ jsx24("span", { className: "cv-p-protocol__copied", "aria-hidden": "true", children: labels.protocolCopied }) : null
|
|
1566
1818
|
]
|
|
1567
1819
|
}
|
|
1568
1820
|
)
|
|
1569
1821
|
] }),
|
|
1570
|
-
/* @__PURE__ */
|
|
1822
|
+
/* @__PURE__ */ jsx24("div", { className: "cv-p-sr-only", role: "status", "aria-live": "polite", children: isCopied ? /* @__PURE__ */ jsx24("span", { children: labels.protocolCopied }, copyCount) : null })
|
|
1571
1823
|
] });
|
|
1572
1824
|
}
|
|
1573
1825
|
function ParticipantProtocolBadge({ protocol, labels }) {
|
|
1574
|
-
const [copyState, dispatch] =
|
|
1826
|
+
const [copyState, dispatch] = useReducer4(protocolCopyReducer, INITIAL_PROTOCOL_COPY_STATE);
|
|
1575
1827
|
const { isCopied, copyCount } = copyState;
|
|
1576
|
-
|
|
1828
|
+
useEffect7(() => {
|
|
1577
1829
|
if (!isCopied) return void 0;
|
|
1578
1830
|
const timer = setTimeout(() => dispatch({ type: "expired" }), COPIED_ANNOUNCEMENT_MS);
|
|
1579
1831
|
return () => clearTimeout(timer);
|
|
@@ -1582,7 +1834,7 @@ function ParticipantProtocolBadge({ protocol, labels }) {
|
|
|
1582
1834
|
const clipboard = typeof navigator === "undefined" ? void 0 : navigator.clipboard;
|
|
1583
1835
|
if (await copyProtocolToClipboard(protocol, clipboard)) dispatch({ type: "copied" });
|
|
1584
1836
|
}
|
|
1585
|
-
return /* @__PURE__ */
|
|
1837
|
+
return /* @__PURE__ */ jsx24(
|
|
1586
1838
|
ParticipantProtocolBadgeView,
|
|
1587
1839
|
{
|
|
1588
1840
|
protocol,
|
|
@@ -1594,19 +1846,19 @@ function ParticipantProtocolBadge({ protocol, labels }) {
|
|
|
1594
1846
|
}
|
|
1595
1847
|
|
|
1596
1848
|
// src/participant/ParticipantThreadHeader.tsx
|
|
1597
|
-
import { jsx as
|
|
1849
|
+
import { jsx as jsx25, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1598
1850
|
function Title({ conversation, labels, onOpenSubject }) {
|
|
1599
1851
|
const { subjectType, subjectId, subjectLabel } = conversation;
|
|
1600
|
-
return /* @__PURE__ */
|
|
1852
|
+
return /* @__PURE__ */ jsx25("h2", { className: "cv-p-thread__title", children: onOpenSubject ? /* @__PURE__ */ jsx25(
|
|
1601
1853
|
"button",
|
|
1602
1854
|
{
|
|
1603
1855
|
type: "button",
|
|
1604
1856
|
className: "cv-p-thread__title-button",
|
|
1605
1857
|
"aria-label": `${labels.openSubject}: ${subjectLabel}`,
|
|
1606
1858
|
onClick: () => onOpenSubject({ subjectType, subjectId }),
|
|
1607
|
-
children: /* @__PURE__ */
|
|
1859
|
+
children: /* @__PURE__ */ jsx25("span", { className: "cv-p-thread__title-text", children: subjectLabel })
|
|
1608
1860
|
}
|
|
1609
|
-
) : /* @__PURE__ */
|
|
1861
|
+
) : /* @__PURE__ */ jsx25("span", { className: "cv-p-thread__title-text", children: subjectLabel }) });
|
|
1610
1862
|
}
|
|
1611
1863
|
function ParticipantThreadHeader({
|
|
1612
1864
|
conversation,
|
|
@@ -1621,30 +1873,30 @@ function ParticipantThreadHeader({
|
|
|
1621
1873
|
const group = subjectGroups?.find((candidate) => candidate.subjectType === conversation.subjectType);
|
|
1622
1874
|
const icon = resolveConversationIcon({ conversation, group, renderSubjectIcon });
|
|
1623
1875
|
const hasChannels = resolveParticipantChannels(conversation.channels).length > 0;
|
|
1624
|
-
return /* @__PURE__ */
|
|
1625
|
-
onBack ? /* @__PURE__ */
|
|
1626
|
-
icon !== void 0 ? /* @__PURE__ */
|
|
1627
|
-
/* @__PURE__ */
|
|
1628
|
-
icon === void 0 && group ? /* @__PURE__ */
|
|
1629
|
-
/* @__PURE__ */
|
|
1630
|
-
counterpartLabel ? /* @__PURE__ */
|
|
1631
|
-
conversation.protocol || hasChannels ? /* @__PURE__ */
|
|
1632
|
-
conversation.protocol ? /* @__PURE__ */
|
|
1633
|
-
/* @__PURE__ */
|
|
1876
|
+
return /* @__PURE__ */ jsxs18("header", { className: "cv-p-thread__header", children: [
|
|
1877
|
+
onBack ? /* @__PURE__ */ jsx25(ParticipantBackButton, { label: labels.back, onBack }) : null,
|
|
1878
|
+
icon !== void 0 ? /* @__PURE__ */ jsx25(ParticipantConversationAvatar, { icon }) : null,
|
|
1879
|
+
/* @__PURE__ */ jsxs18("div", { className: "cv-p-thread__heading", children: [
|
|
1880
|
+
icon === void 0 && group ? /* @__PURE__ */ jsx25("p", { className: "cv-p-thread__eyebrow", children: group.label }) : null,
|
|
1881
|
+
/* @__PURE__ */ jsx25(Title, { conversation, labels, onOpenSubject }),
|
|
1882
|
+
counterpartLabel ? /* @__PURE__ */ jsx25("p", { className: "cv-p-thread__counterpart", children: counterpartLabel }) : null,
|
|
1883
|
+
conversation.protocol || hasChannels ? /* @__PURE__ */ jsxs18("div", { className: "cv-p-thread__meta", children: [
|
|
1884
|
+
conversation.protocol ? /* @__PURE__ */ jsx25(ParticipantProtocolBadge, { protocol: conversation.protocol, labels }) : null,
|
|
1885
|
+
/* @__PURE__ */ jsx25(ParticipantChannelBadges, { channels: conversation.channels, labels, variant: "inline", iconSize: 16 })
|
|
1634
1886
|
] }) : null
|
|
1635
1887
|
] }),
|
|
1636
|
-
actions ? /* @__PURE__ */
|
|
1888
|
+
actions ? /* @__PURE__ */ jsx25("div", { className: "cv-p-thread__actions", children: actions }) : null
|
|
1637
1889
|
] });
|
|
1638
1890
|
}
|
|
1639
1891
|
|
|
1640
1892
|
// src/participant/ParticipantThread.tsx
|
|
1641
|
-
import { jsx as
|
|
1893
|
+
import { jsx as jsx26, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1642
1894
|
function Footer({ props }) {
|
|
1643
1895
|
const { conversation, labels, draft } = props;
|
|
1644
1896
|
if (conversation.status === "closed") {
|
|
1645
|
-
return /* @__PURE__ */
|
|
1897
|
+
return /* @__PURE__ */ jsx26("p", { className: "cv-p-thread__closed", children: labels.closedNotice });
|
|
1646
1898
|
}
|
|
1647
|
-
return /* @__PURE__ */
|
|
1899
|
+
return /* @__PURE__ */ jsx26(
|
|
1648
1900
|
ParticipantComposer,
|
|
1649
1901
|
{
|
|
1650
1902
|
value: draft.value,
|
|
@@ -1661,31 +1913,36 @@ function Footer({ props }) {
|
|
|
1661
1913
|
}
|
|
1662
1914
|
);
|
|
1663
1915
|
}
|
|
1916
|
+
function Header({ props }) {
|
|
1917
|
+
return /* @__PURE__ */ jsx26(
|
|
1918
|
+
ParticipantThreadHeader,
|
|
1919
|
+
{
|
|
1920
|
+
conversation: props.conversation,
|
|
1921
|
+
labels: props.labels,
|
|
1922
|
+
subjectGroups: props.subjectGroups,
|
|
1923
|
+
renderSubjectIcon: props.renderSubjectIcon,
|
|
1924
|
+
onBack: props.onBack,
|
|
1925
|
+
onOpenSubject: props.onOpenSubject,
|
|
1926
|
+
counterpartLabel: props.counterpartLabel,
|
|
1927
|
+
actions: props.headerActions
|
|
1928
|
+
}
|
|
1929
|
+
);
|
|
1930
|
+
}
|
|
1664
1931
|
function ThreadBody(props) {
|
|
1665
1932
|
const { conversation, labels, hasMore, onLoadOlder, renderSubjectCard } = props;
|
|
1666
1933
|
const subjectCard = renderSubjectCard?.(conversation);
|
|
1667
1934
|
const loadView = resolveLoadView({ status: props.status, hasItems: props.items.length > 0 });
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
actions: props.headerActions
|
|
1680
|
-
}
|
|
1681
|
-
),
|
|
1682
|
-
subjectCard ? /* @__PURE__ */ jsx23("div", { className: "cv-p-thread__subject-card", children: subjectCard }) : null,
|
|
1683
|
-
/* @__PURE__ */ jsxs16("div", { className: "cv-p-thread__scroll", ref: props.scroll.ref, onScroll: props.scroll.onScroll, tabIndex: -1, children: [
|
|
1684
|
-
loadView.isLoading ? /* @__PURE__ */ jsx23(ParticipantLoading, { labels }) : null,
|
|
1685
|
-
loadView.hasError ? /* @__PURE__ */ jsx23(ParticipantLoadError, { labels, onRetry: props.refresh }) : null,
|
|
1686
|
-
hasMore && onLoadOlder ? /* @__PURE__ */ jsx23("button", { type: "button", className: "cv-p-thread__older", onClick: onLoadOlder, children: labels.loadOlder }) : null,
|
|
1687
|
-
/* @__PURE__ */ jsx23(ParticipantTimeline, { ...props }),
|
|
1688
|
-
/* @__PURE__ */ jsx23(
|
|
1935
|
+
const rootRef = useRef5(null);
|
|
1936
|
+
useSuppressTouchTooltips(rootRef);
|
|
1937
|
+
return /* @__PURE__ */ jsxs19("div", { className: "cv-p cv-p-thread", "aria-busy": loadView.isLoading, ref: rootRef, children: [
|
|
1938
|
+
/* @__PURE__ */ jsx26(Header, { props }),
|
|
1939
|
+
subjectCard ? /* @__PURE__ */ jsx26("div", { className: "cv-p-thread__subject-card", children: subjectCard }) : null,
|
|
1940
|
+
/* @__PURE__ */ jsxs19("div", { className: "cv-p-thread__scroll", ref: props.scroll.ref, onScroll: props.scroll.onScroll, tabIndex: -1, children: [
|
|
1941
|
+
loadView.isLoading ? /* @__PURE__ */ jsx26(ParticipantLoading, { labels }) : null,
|
|
1942
|
+
loadView.hasError ? /* @__PURE__ */ jsx26(ParticipantLoadError, { labels, onRetry: props.refresh }) : null,
|
|
1943
|
+
hasMore && onLoadOlder ? /* @__PURE__ */ jsx26("button", { type: "button", className: "cv-p-thread__older", onClick: onLoadOlder, children: labels.loadOlder }) : null,
|
|
1944
|
+
/* @__PURE__ */ jsx26(ParticipantTimeline, { ...props }),
|
|
1945
|
+
/* @__PURE__ */ jsx26(
|
|
1689
1946
|
ParticipantScrollToLatest,
|
|
1690
1947
|
{
|
|
1691
1948
|
label: labels.scrollToLatest,
|
|
@@ -1696,12 +1953,15 @@ function ThreadBody(props) {
|
|
|
1696
1953
|
}
|
|
1697
1954
|
)
|
|
1698
1955
|
] }),
|
|
1699
|
-
/* @__PURE__ */
|
|
1700
|
-
/* @__PURE__ */
|
|
1956
|
+
/* @__PURE__ */ jsx26(ParticipantThreadLive, { notice: props.newMessagesCount > 0 ? labels.newMessages : "" }),
|
|
1957
|
+
/* @__PURE__ */ jsx26(Footer, { props })
|
|
1701
1958
|
] });
|
|
1702
1959
|
}
|
|
1703
1960
|
function ParticipantThread(props) {
|
|
1704
|
-
return /* @__PURE__ */
|
|
1961
|
+
return /* @__PURE__ */ jsxs19(ParticipantCopyAnnouncer, { children: [
|
|
1962
|
+
/* @__PURE__ */ jsx26(ThreadBody, { ...props }),
|
|
1963
|
+
/* @__PURE__ */ jsx26(TooltipLayer, {})
|
|
1964
|
+
] });
|
|
1705
1965
|
}
|
|
1706
1966
|
|
|
1707
1967
|
// src/participant/useParticipantThreadController.ts
|
|
@@ -1833,7 +2093,7 @@ function participantSendStatesReducer(states, { subject, action }) {
|
|
|
1833
2093
|
}
|
|
1834
2094
|
|
|
1835
2095
|
// src/participant/useParticipantThread.ts
|
|
1836
|
-
import { useCallback as useCallback4, useEffect as
|
|
2096
|
+
import { useCallback as useCallback4, useEffect as useEffect11, useMemo as useMemo2, useReducer as useReducer5, useRef as useRef9 } from "react";
|
|
1837
2097
|
|
|
1838
2098
|
// src/participant/participantThreadState.ts
|
|
1839
2099
|
var INITIAL_PARTICIPANT_THREAD_STATE = {
|
|
@@ -1869,7 +2129,7 @@ function participantThreadReducer(state, action) {
|
|
|
1869
2129
|
}
|
|
1870
2130
|
|
|
1871
2131
|
// src/participant/useParticipantMarkRead.ts
|
|
1872
|
-
import { useEffect as
|
|
2132
|
+
import { useEffect as useEffect9 } from "react";
|
|
1873
2133
|
|
|
1874
2134
|
// src/participant/shouldMarkRead.ts
|
|
1875
2135
|
function shouldMarkParticipantRead(params) {
|
|
@@ -1881,12 +2141,12 @@ function shouldMarkParticipantRead(params) {
|
|
|
1881
2141
|
}
|
|
1882
2142
|
|
|
1883
2143
|
// src/participant/useDocumentVisibility.ts
|
|
1884
|
-
import { useEffect as
|
|
2144
|
+
import { useEffect as useEffect8, useState as useState4 } from "react";
|
|
1885
2145
|
function useDocumentVisibility() {
|
|
1886
|
-
const [visibilityState, setVisibilityState] =
|
|
2146
|
+
const [visibilityState, setVisibilityState] = useState4(
|
|
1887
2147
|
() => typeof document === "undefined" ? "visible" : document.visibilityState
|
|
1888
2148
|
);
|
|
1889
|
-
|
|
2149
|
+
useEffect8(() => {
|
|
1890
2150
|
function handleVisibilityChange() {
|
|
1891
2151
|
setVisibilityState(document.visibilityState);
|
|
1892
2152
|
}
|
|
@@ -1901,18 +2161,18 @@ function useDocumentVisibility() {
|
|
|
1901
2161
|
function useParticipantMarkRead(params) {
|
|
1902
2162
|
const { apiRef, subject, unreadCount, messageCount, onMarkedRead } = params;
|
|
1903
2163
|
const visibilityState = useDocumentVisibility();
|
|
1904
|
-
|
|
2164
|
+
useEffect9(() => {
|
|
1905
2165
|
if (!shouldMarkParticipantRead({ selected: subject, subject, visibilityState, unreadCount })) return;
|
|
1906
2166
|
void apiRef.current.markRead(subject).then(() => onMarkedRead?.(subject), () => void 0);
|
|
1907
2167
|
}, [apiRef, subject, visibilityState, unreadCount, messageCount, onMarkedRead]);
|
|
1908
2168
|
}
|
|
1909
2169
|
|
|
1910
2170
|
// src/participant/useParticipantRevalidation.ts
|
|
1911
|
-
import { useEffect as
|
|
2171
|
+
import { useEffect as useEffect10, useRef as useRef6 } from "react";
|
|
1912
2172
|
function useParticipantRevalidation(api, onRevalidate) {
|
|
1913
|
-
const handlerRef =
|
|
2173
|
+
const handlerRef = useRef6(onRevalidate);
|
|
1914
2174
|
handlerRef.current = onRevalidate;
|
|
1915
|
-
|
|
2175
|
+
useEffect10(() => {
|
|
1916
2176
|
function handleFocus() {
|
|
1917
2177
|
handlerRef.current();
|
|
1918
2178
|
}
|
|
@@ -1939,10 +2199,10 @@ function useParticipantRevalidation(api, onRevalidate) {
|
|
|
1939
2199
|
}
|
|
1940
2200
|
|
|
1941
2201
|
// src/participant/useParticipantSend.ts
|
|
1942
|
-
import { useCallback as useCallback2, useRef as
|
|
2202
|
+
import { useCallback as useCallback2, useRef as useRef7 } from "react";
|
|
1943
2203
|
function useParticipantSend(params) {
|
|
1944
2204
|
const { apiRef, subject, dispatchSend, onSentMessage } = params;
|
|
1945
|
-
const entriesRef =
|
|
2205
|
+
const entriesRef = useRef7(params.entries);
|
|
1946
2206
|
entriesRef.current = params.entries;
|
|
1947
2207
|
const deliver = useCallback2(
|
|
1948
2208
|
async (entry) => {
|
|
@@ -1994,11 +2254,11 @@ function useParticipantSend(params) {
|
|
|
1994
2254
|
}
|
|
1995
2255
|
|
|
1996
2256
|
// src/participant/useParticipantUnread.ts
|
|
1997
|
-
import { useCallback as useCallback3, useRef as
|
|
2257
|
+
import { useCallback as useCallback3, useRef as useRef8, useState as useState5 } from "react";
|
|
1998
2258
|
function useParticipantUnread(params) {
|
|
1999
2259
|
const { messages, perspective, reportedUnreadCount, onMarkedRead } = params;
|
|
2000
|
-
const [acknowledgedCount, setAcknowledgedCount] =
|
|
2001
|
-
const messagesRef =
|
|
2260
|
+
const [acknowledgedCount, setAcknowledgedCount] = useState5(0);
|
|
2261
|
+
const messagesRef = useRef8(messages);
|
|
2002
2262
|
messagesRef.current = messages;
|
|
2003
2263
|
const handleMarkedRead = useCallback3(
|
|
2004
2264
|
(subject) => {
|
|
@@ -2024,10 +2284,10 @@ function useParticipantThread(params) {
|
|
|
2024
2284
|
const { api, subject, channel, unreadCount = 0, onMarkedRead, sendEntries, dispatchSend, hostPending = [], perspective } = params;
|
|
2025
2285
|
const { subjectType, subjectId } = subject;
|
|
2026
2286
|
const stableSubject = useMemo2(() => ({ subjectType, subjectId }), [subjectType, subjectId]);
|
|
2027
|
-
const [state, dispatch] =
|
|
2028
|
-
const apiRef =
|
|
2287
|
+
const [state, dispatch] = useReducer5(participantThreadReducer, INITIAL_PARTICIPANT_THREAD_STATE);
|
|
2288
|
+
const apiRef = useRef9(api);
|
|
2029
2289
|
apiRef.current = api;
|
|
2030
|
-
const activeSubjectKey =
|
|
2290
|
+
const activeSubjectKey = useRef9("");
|
|
2031
2291
|
const confirmsRead = channelCapabilityFor(channel).confirmsRead;
|
|
2032
2292
|
const refresh = useCallback4(async () => {
|
|
2033
2293
|
const requestKey = `${subjectType}:${subjectId}`;
|
|
@@ -2056,7 +2316,7 @@ function useParticipantThread(params) {
|
|
|
2056
2316
|
}, [stableSubject, subjectType, subjectId, oldestMessageId]);
|
|
2057
2317
|
const handleSentMessage = useCallback4((message) => dispatch({ type: "sendConfirmed", message }), []);
|
|
2058
2318
|
const sending = useParticipantSend({ apiRef, subject: stableSubject, entries: sendEntries, dispatchSend, onSentMessage: handleSentMessage });
|
|
2059
|
-
|
|
2319
|
+
useEffect11(() => {
|
|
2060
2320
|
activeSubjectKey.current = `${subjectType}:${subjectId}`;
|
|
2061
2321
|
dispatch({ type: "reset" });
|
|
2062
2322
|
void refresh();
|
|
@@ -2064,7 +2324,7 @@ function useParticipantThread(params) {
|
|
|
2064
2324
|
useParticipantRevalidation(api, (event) => {
|
|
2065
2325
|
if (isForSubject(event, stableSubject)) void refresh();
|
|
2066
2326
|
});
|
|
2067
|
-
|
|
2327
|
+
useEffect11(() => {
|
|
2068
2328
|
if (sendEntries.length === 0) return;
|
|
2069
2329
|
dispatchSend({ type: "reflected", knownClientMessageIds: collectKnownClientMessageIds({ messages: state.messages, hostPending }) });
|
|
2070
2330
|
}, [sendEntries, state.messages, hostPending, dispatchSend]);
|
|
@@ -2113,9 +2373,9 @@ function useParticipantConversationView(params) {
|
|
|
2113
2373
|
}
|
|
2114
2374
|
|
|
2115
2375
|
// src/participant/useParticipantDraft.ts
|
|
2116
|
-
import { useState as
|
|
2376
|
+
import { useState as useState6 } from "react";
|
|
2117
2377
|
function useParticipantDraft(draftsRef, subject) {
|
|
2118
|
-
const [draft, setDraftState] =
|
|
2378
|
+
const [draft, setDraftState] = useState6(() => getDraft(draftsRef.current, subject));
|
|
2119
2379
|
function replaceDrafts(next) {
|
|
2120
2380
|
draftsRef.current = next;
|
|
2121
2381
|
setDraftState(getDraft(next, subject));
|
|
@@ -2135,7 +2395,7 @@ function useParticipantDraft(draftsRef, subject) {
|
|
|
2135
2395
|
}
|
|
2136
2396
|
|
|
2137
2397
|
// src/participant/useParticipantThreadScroll.ts
|
|
2138
|
-
import { useEffect as
|
|
2398
|
+
import { useEffect as useEffect12, useRef as useRef11 } from "react";
|
|
2139
2399
|
|
|
2140
2400
|
// src/participant/participantNewMessages.ts
|
|
2141
2401
|
function collectServerMessageIds(items) {
|
|
@@ -2173,7 +2433,7 @@ function useScrollAwayState(ref, isNearBottom) {
|
|
|
2173
2433
|
}
|
|
2174
2434
|
|
|
2175
2435
|
// src/participant/useStickToBottom.ts
|
|
2176
|
-
import { useCallback as useCallback7, useLayoutEffect as
|
|
2436
|
+
import { useCallback as useCallback7, useLayoutEffect as useLayoutEffect3, useRef as useRef10, useState as useState7 } from "react";
|
|
2177
2437
|
|
|
2178
2438
|
// src/participant/participantScroll.ts
|
|
2179
2439
|
var NEAR_BOTTOM_THRESHOLD_PX = 80;
|
|
@@ -2195,16 +2455,16 @@ function resolveScrollAction(params) {
|
|
|
2195
2455
|
|
|
2196
2456
|
// src/participant/useStickToBottom.ts
|
|
2197
2457
|
function useStickToBottom({ firstKey, lastKey }) {
|
|
2198
|
-
const ref =
|
|
2199
|
-
const snapshot =
|
|
2458
|
+
const ref = useRef10(null);
|
|
2459
|
+
const snapshot = useRef10({
|
|
2200
2460
|
hasPositioned: false,
|
|
2201
2461
|
firstKey: void 0,
|
|
2202
2462
|
lastKey: void 0,
|
|
2203
2463
|
scrollTop: 0,
|
|
2204
2464
|
scrollHeight: 0
|
|
2205
2465
|
});
|
|
2206
|
-
const [isNearBottom, setIsNearBottom] =
|
|
2207
|
-
const isNearBottomRef =
|
|
2466
|
+
const [isNearBottom, setIsNearBottom] = useState7(true);
|
|
2467
|
+
const isNearBottomRef = useRef10(true);
|
|
2208
2468
|
const onScroll = useCallback7((event) => {
|
|
2209
2469
|
const { scrollTop, clientHeight, scrollHeight } = event.currentTarget;
|
|
2210
2470
|
const isNear = shouldStickToBottom({ scrollTop, clientHeight, scrollHeight, threshold: NEAR_BOTTOM_THRESHOLD_PX });
|
|
@@ -2213,7 +2473,7 @@ function useStickToBottom({ firstKey, lastKey }) {
|
|
|
2213
2473
|
isNearBottomRef.current = isNear;
|
|
2214
2474
|
setIsNearBottom(isNear);
|
|
2215
2475
|
}, []);
|
|
2216
|
-
|
|
2476
|
+
useLayoutEffect3(() => {
|
|
2217
2477
|
const element = ref.current;
|
|
2218
2478
|
const previous = snapshot.current;
|
|
2219
2479
|
if (!element) return;
|
|
@@ -2260,8 +2520,8 @@ function useParticipantThreadScroll(items, perspective) {
|
|
|
2260
2520
|
});
|
|
2261
2521
|
const { isAwayFromBottom, scrollToLatest } = useScrollAwayState(base.ref, isNearBottom);
|
|
2262
2522
|
const scroll = { ...base, isAwayFromBottom, scrollToLatest };
|
|
2263
|
-
const seenIds =
|
|
2264
|
-
|
|
2523
|
+
const seenIds = useRef11(/* @__PURE__ */ new Set());
|
|
2524
|
+
useEffect12(() => {
|
|
2265
2525
|
if (isNearBottom) seenIds.current = collectServerMessageIds(items);
|
|
2266
2526
|
}, [isNearBottom, items]);
|
|
2267
2527
|
return { scroll, newMessagesCount: isNearBottom ? 0 : countNewIncomingMessages(seenIds.current, items, perspective) };
|
|
@@ -2314,12 +2574,12 @@ function useParticipantThreadController(params) {
|
|
|
2314
2574
|
}
|
|
2315
2575
|
|
|
2316
2576
|
// src/participant/ParticipantThreadScreen.tsx
|
|
2317
|
-
import { jsx as
|
|
2577
|
+
import { jsx as jsx27, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
2318
2578
|
function useOpenedConversation(api, subject, isNeeded) {
|
|
2319
|
-
const [opened, setOpened] =
|
|
2579
|
+
const [opened, setOpened] = useState8({ status: "idle" });
|
|
2320
2580
|
const { subjectType, subjectId } = subject;
|
|
2321
2581
|
const canOpen = api.openConversation !== void 0;
|
|
2322
|
-
|
|
2582
|
+
useEffect13(() => {
|
|
2323
2583
|
if (!isNeeded || !canOpen) return;
|
|
2324
2584
|
let isCurrent = true;
|
|
2325
2585
|
setOpened({ status: "loading" });
|
|
@@ -2337,9 +2597,9 @@ function NotFound({
|
|
|
2337
2597
|
labels,
|
|
2338
2598
|
onBack
|
|
2339
2599
|
}) {
|
|
2340
|
-
return /* @__PURE__ */
|
|
2341
|
-
/* @__PURE__ */
|
|
2342
|
-
/* @__PURE__ */
|
|
2600
|
+
return /* @__PURE__ */ jsxs20("div", { className: "cv-p cv-p-thread", children: [
|
|
2601
|
+
/* @__PURE__ */ jsx27("header", { className: "cv-p-thread__header", children: onBack ? /* @__PURE__ */ jsx27(ParticipantBackButton, { label: labels.back, onBack }) : null }),
|
|
2602
|
+
/* @__PURE__ */ jsx27("p", { className: "cv-p-empty", children: labels.notFound })
|
|
2343
2603
|
] });
|
|
2344
2604
|
}
|
|
2345
2605
|
function ParticipantThreadScreen(props) {
|
|
@@ -2349,12 +2609,12 @@ function ParticipantThreadScreen(props) {
|
|
|
2349
2609
|
);
|
|
2350
2610
|
const opened = useOpenedConversation(api, selected, listed === void 0);
|
|
2351
2611
|
const conversation = listed ?? (opened.status === "found" ? opened.conversation : void 0);
|
|
2352
|
-
if (conversation) return /* @__PURE__ */
|
|
2612
|
+
if (conversation) return /* @__PURE__ */ jsx27(LoadedThread, { ...props, conversation });
|
|
2353
2613
|
const isResolving = opened.status === "loading" || api.openConversation !== void 0 && opened.status === "idle";
|
|
2354
2614
|
const isListLoading = inbox.status === "idle" || inbox.status === "loading";
|
|
2355
2615
|
if (isResolving || api.openConversation === void 0 && isListLoading)
|
|
2356
|
-
return /* @__PURE__ */
|
|
2357
|
-
return /* @__PURE__ */
|
|
2616
|
+
return /* @__PURE__ */ jsx27("div", { className: "cv-p cv-p-thread", "aria-busy": "true" });
|
|
2617
|
+
return /* @__PURE__ */ jsx27(NotFound, { labels, onBack: props.onBack });
|
|
2358
2618
|
}
|
|
2359
2619
|
function LoadedThread(props) {
|
|
2360
2620
|
const core = useParticipantThreadController({
|
|
@@ -2362,7 +2622,7 @@ function LoadedThread(props) {
|
|
|
2362
2622
|
subject: props.selected,
|
|
2363
2623
|
onMarkedRead: props.inbox.markSubjectRead
|
|
2364
2624
|
});
|
|
2365
|
-
return /* @__PURE__ */
|
|
2625
|
+
return /* @__PURE__ */ jsx27(
|
|
2366
2626
|
ParticipantThread,
|
|
2367
2627
|
{
|
|
2368
2628
|
...core,
|
|
@@ -2500,14 +2760,14 @@ function buildParticipantThemeStyle(theme) {
|
|
|
2500
2760
|
}
|
|
2501
2761
|
|
|
2502
2762
|
// src/participant/ParticipantConversationsScreen.tsx
|
|
2503
|
-
import { jsx as
|
|
2763
|
+
import { jsx as jsx28 } from "react/jsx-runtime";
|
|
2504
2764
|
var ALL_FILTER3 = "all";
|
|
2505
2765
|
function ParticipantConversationsScreen(props) {
|
|
2506
2766
|
const { selected, inbox, subjectGroups, classNames } = props;
|
|
2507
|
-
const [filter, setFilter] =
|
|
2508
|
-
const [searchQuery, setSearchQuery] =
|
|
2509
|
-
const draftsRef =
|
|
2510
|
-
const [sendStates, dispatchSendStates] =
|
|
2767
|
+
const [filter, setFilter] = useState9(ALL_FILTER3);
|
|
2768
|
+
const [searchQuery, setSearchQuery] = useState9("");
|
|
2769
|
+
const draftsRef = useRef12(/* @__PURE__ */ new Map());
|
|
2770
|
+
const [sendStates, dispatchSendStates] = useReducer6(participantSendStatesReducer, /* @__PURE__ */ new Map());
|
|
2511
2771
|
const labels = useMemo5(() => ({ ...DEFAULT_PARTICIPANT_CONVERSATIONS_LABELS, ...props.labels }), [props.labels]);
|
|
2512
2772
|
const view = useMemo5(
|
|
2513
2773
|
() => groupParticipantConversations({
|
|
@@ -2520,7 +2780,7 @@ function ParticipantConversationsScreen(props) {
|
|
|
2520
2780
|
);
|
|
2521
2781
|
const isSearchVisible = isInboxSearchVisible({ conversations: inbox.conversations, searchQuery });
|
|
2522
2782
|
const rootClassName = ["cv-p-root", props.className, classNames?.root].filter(Boolean).join(" ");
|
|
2523
|
-
return /* @__PURE__ */
|
|
2783
|
+
return /* @__PURE__ */ jsx28("div", { className: rootClassName, style: buildParticipantThemeStyle(props.theme), children: selected === void 0 ? /* @__PURE__ */ jsx28("div", { className: ["cv-p-root__screen", classNames?.inbox].filter(Boolean).join(" "), children: /* @__PURE__ */ jsx28(
|
|
2524
2784
|
ParticipantInbox,
|
|
2525
2785
|
{
|
|
2526
2786
|
view,
|
|
@@ -2537,7 +2797,7 @@ function ParticipantConversationsScreen(props) {
|
|
|
2537
2797
|
renderSubjectIcon: props.renderSubjectIcon,
|
|
2538
2798
|
search: { value: searchQuery, onChange: setSearchQuery, isVisible: isSearchVisible }
|
|
2539
2799
|
}
|
|
2540
|
-
) }) : /* @__PURE__ */
|
|
2800
|
+
) }) : /* @__PURE__ */ jsx28("div", { className: ["cv-p-root__screen", classNames?.thread].filter(Boolean).join(" "), children: /* @__PURE__ */ jsx28(
|
|
2541
2801
|
ParticipantThreadScreen,
|
|
2542
2802
|
{
|
|
2543
2803
|
...props,
|
|
@@ -2552,7 +2812,7 @@ function ParticipantConversationsScreen(props) {
|
|
|
2552
2812
|
}
|
|
2553
2813
|
|
|
2554
2814
|
// src/participant/useParticipantInbox.ts
|
|
2555
|
-
import { useCallback as useCallback8, useEffect as
|
|
2815
|
+
import { useCallback as useCallback8, useEffect as useEffect14, useReducer as useReducer7 } from "react";
|
|
2556
2816
|
|
|
2557
2817
|
// src/participant/participantInboxState.ts
|
|
2558
2818
|
var INITIAL_PARTICIPANT_INBOX_STATE = { status: "idle", conversations: [] };
|
|
@@ -2602,7 +2862,7 @@ function describeError2(error) {
|
|
|
2602
2862
|
return error instanceof Error ? error.message : "unknown error";
|
|
2603
2863
|
}
|
|
2604
2864
|
function useParticipantInbox(api) {
|
|
2605
|
-
const [state, dispatch] =
|
|
2865
|
+
const [state, dispatch] = useReducer7(participantInboxReducer, INITIAL_PARTICIPANT_INBOX_STATE);
|
|
2606
2866
|
const refresh = useCallback8(async () => {
|
|
2607
2867
|
dispatch({ type: "started" });
|
|
2608
2868
|
try {
|
|
@@ -2625,7 +2885,7 @@ function useParticipantInbox(api) {
|
|
|
2625
2885
|
const markSubjectRead = useCallback8((subject) => {
|
|
2626
2886
|
dispatch({ type: "markedRead", subject });
|
|
2627
2887
|
}, []);
|
|
2628
|
-
|
|
2888
|
+
useEffect14(() => {
|
|
2629
2889
|
void refresh();
|
|
2630
2890
|
}, [refresh]);
|
|
2631
2891
|
useParticipantRevalidation(api, () => {
|
|
@@ -2635,11 +2895,11 @@ function useParticipantInbox(api) {
|
|
|
2635
2895
|
}
|
|
2636
2896
|
|
|
2637
2897
|
// src/participant/ParticipantConversations.tsx
|
|
2638
|
-
import { jsx as
|
|
2898
|
+
import { jsx as jsx29 } from "react/jsx-runtime";
|
|
2639
2899
|
function ParticipantConversations(props) {
|
|
2640
2900
|
const inbox = useParticipantInbox(props.api);
|
|
2641
2901
|
const { status, conversations, hasMore, refresh, loadMore, markSubjectRead } = inbox;
|
|
2642
|
-
return /* @__PURE__ */
|
|
2902
|
+
return /* @__PURE__ */ jsx29(
|
|
2643
2903
|
ParticipantConversationsScreen,
|
|
2644
2904
|
{
|
|
2645
2905
|
...props,
|
|
@@ -2649,7 +2909,7 @@ function ParticipantConversations(props) {
|
|
|
2649
2909
|
}
|
|
2650
2910
|
|
|
2651
2911
|
// src/participant/ConversationThread.tsx
|
|
2652
|
-
import { useCallback as useCallback9, useMemo as useMemo6, useReducer as
|
|
2912
|
+
import { useCallback as useCallback9, useMemo as useMemo6, useReducer as useReducer8, useRef as useRef13 } from "react";
|
|
2653
2913
|
|
|
2654
2914
|
// src/participant/conversationThreadApi.ts
|
|
2655
2915
|
function toParticipantApi(api) {
|
|
@@ -2689,17 +2949,17 @@ function buildThreadSummary({
|
|
|
2689
2949
|
}
|
|
2690
2950
|
|
|
2691
2951
|
// src/participant/ConversationThread.tsx
|
|
2692
|
-
import { jsx as
|
|
2952
|
+
import { jsx as jsx30 } from "react/jsx-runtime";
|
|
2693
2953
|
function useConversationThreadCore(props) {
|
|
2694
2954
|
const { perspective = "participant" } = props;
|
|
2695
2955
|
const { subjectType, subjectId } = props.subject;
|
|
2696
2956
|
const subject = useMemo6(() => ({ subjectType, subjectId }), [subjectType, subjectId]);
|
|
2697
|
-
const onMarkedReadRef =
|
|
2957
|
+
const onMarkedReadRef = useRef13(props.onMarkedRead);
|
|
2698
2958
|
onMarkedReadRef.current = props.onMarkedRead;
|
|
2699
2959
|
const handleMarkedRead = useCallback9((marked) => onMarkedReadRef.current?.(marked), []);
|
|
2700
2960
|
const api = useMemo6(() => toParticipantApi(props.api), [props.api]);
|
|
2701
|
-
const draftsRef =
|
|
2702
|
-
const [sendStates, dispatchSendStates] =
|
|
2961
|
+
const draftsRef = useRef13(/* @__PURE__ */ new Map());
|
|
2962
|
+
const [sendStates, dispatchSendStates] = useReducer8(participantSendStatesReducer, /* @__PURE__ */ new Map());
|
|
2703
2963
|
const labels = useMemo6(() => ({ ...DEFAULT_PARTICIPANT_CONVERSATIONS_LABELS, ...props.labels }), [props.labels]);
|
|
2704
2964
|
const { title, protocol, channels, status } = props;
|
|
2705
2965
|
const conversation = useMemo6(
|
|
@@ -2724,12 +2984,12 @@ function useConversationThreadCore(props) {
|
|
|
2724
2984
|
}
|
|
2725
2985
|
function ConversationThreadBody(props) {
|
|
2726
2986
|
const core = useConversationThreadCore(props);
|
|
2727
|
-
return /* @__PURE__ */
|
|
2987
|
+
return /* @__PURE__ */ jsx30(
|
|
2728
2988
|
"div",
|
|
2729
2989
|
{
|
|
2730
2990
|
className: ["cv-p-root", props.className].filter(Boolean).join(" "),
|
|
2731
2991
|
style: buildParticipantThemeStyle(props.theme),
|
|
2732
|
-
children: /* @__PURE__ */
|
|
2992
|
+
children: /* @__PURE__ */ jsx30("div", { className: "cv-p-root__screen", children: /* @__PURE__ */ jsx30(
|
|
2733
2993
|
ParticipantThread,
|
|
2734
2994
|
{
|
|
2735
2995
|
...core,
|
|
@@ -2748,7 +3008,7 @@ function ConversationThreadBody(props) {
|
|
|
2748
3008
|
);
|
|
2749
3009
|
}
|
|
2750
3010
|
function ConversationThread(props) {
|
|
2751
|
-
return /* @__PURE__ */
|
|
3011
|
+
return /* @__PURE__ */ jsx30(ConversationThreadBody, { ...props }, draftKey(props.subject));
|
|
2752
3012
|
}
|
|
2753
3013
|
export {
|
|
2754
3014
|
ConversationThread,
|