@adatechnology/conversations-ui 0.1.0-rc.4 → 0.1.0-rc.41
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/ConversationSimulatorPanel--5fIzXWY.d.ts +804 -0
- package/dist/chunk-BJNRLLDO.js +2708 -0
- package/dist/chunk-DKPXKQGC.js +110 -0
- package/dist/{chunk-OGRRHQQW.js → chunk-WCBDXZ3X.js} +68 -4
- package/dist/flows/index.d.ts +422 -5
- package/dist/flows/index.js +2389 -678
- package/dist/index.d.ts +1171 -42
- package/dist/index.js +3755 -843
- package/dist/preview/index.d.ts +157 -42
- package/dist/preview/index.js +772 -191
- package/dist/styles.css +893 -0
- package/package.json +9 -8
- package/src/AudioPlayer.tsx +8 -0
- package/src/AudioRecorderButton.test.tsx +30 -0
- package/src/AudioRecorderButton.tsx +248 -0
- package/src/AudioTranscription.test.tsx +115 -0
- package/src/AudioTranscription.tsx +252 -0
- package/src/Avatar.tsx +14 -3
- package/src/ConversationContextPanel.tsx +218 -44
- package/src/ConversationDocumentsPanel.tsx +347 -24
- package/src/ConversationHeader.test.tsx +66 -0
- package/src/ConversationHeader.tsx +163 -45
- package/src/ConversationListItem.tsx +19 -2
- package/src/ConversationLocalesProvider.tsx +28 -0
- package/src/ConversationRow.tsx +31 -7
- package/src/DarkModeToggle.test.tsx +76 -0
- package/src/DarkModeToggle.tsx +92 -0
- package/src/DocumentsLibrary.tsx +382 -0
- package/src/EmojiPicker.tsx +70 -55
- package/src/FileIcon.test.ts +83 -0
- package/src/FileIcon.tsx +88 -11
- package/src/InteractiveMessage.test.tsx +41 -0
- package/src/InteractiveMessage.tsx +146 -0
- package/src/Lightbox.tsx +18 -3
- package/src/MediaRenderer.tsx +92 -16
- package/src/MessageBubble.test.tsx +41 -0
- package/src/MessageBubble.tsx +75 -6
- package/src/MessageComposer.test.tsx +35 -0
- package/src/MessageComposer.tsx +155 -19
- package/src/RichMessageComposer.test.tsx +113 -0
- package/src/RichMessageComposer.tsx +551 -0
- package/src/SimpleEmojiPicker.tsx +5 -3
- package/src/StatusTicks.tsx +1 -1
- package/src/Toast.tsx +4 -0
- package/src/Tooltip.test.ts +42 -0
- package/src/Tooltip.tsx +167 -0
- package/src/Wallpaper.test.tsx +21 -0
- package/src/Wallpaper.tsx +67 -7
- package/src/WhatsAppMessageEditor.tsx +34 -7
- package/src/WindowExpiredNotice.tsx +12 -4
- package/src/audioRecorderFormat.test.ts +67 -0
- package/src/buildOutput.test.ts +79 -0
- package/src/composer.constant.ts +33 -0
- package/src/conversationTranscript.test.ts +57 -0
- package/src/conversationTranscript.ts +29 -4
- package/src/conversationWindow.ts +7 -5
- package/src/documentTypeLabel.test.ts +57 -0
- package/src/documents/DocumentsWorkspace.tsx +550 -0
- package/src/documents/index.ts +8 -0
- package/src/documents/labels.ts +92 -0
- package/src/emojiCatalog.test.ts +35 -0
- package/src/emojiCatalog.ts +189 -0
- package/src/flows/FlowConnectionEdge.tsx +104 -0
- package/src/flows/FlowGroupHeader.tsx +12 -2
- package/src/flows/FlowLegend.tsx +125 -0
- package/src/flows/FlowMapCanvas.tsx +15 -12
- package/src/flows/FlowMapNode.tsx +4 -1
- package/src/flows/FlowNodeCard.tsx +219 -34
- package/src/flows/FlowNodePanel.tsx +153 -39
- package/src/flows/FlowPalette.tsx +106 -69
- package/src/flows/FlowPortalNode.tsx +1 -1
- package/src/flows/FlowWhatsAppPreview.tsx +14 -3
- package/src/flows/FlowsWorkspace.tsx +1219 -0
- package/src/flows/flowCanvasModel.test.ts +456 -0
- package/src/flows/flowCanvasModel.ts +378 -0
- package/src/flows/flowEditorOps.test.ts +276 -0
- package/src/flows/flowEditorOps.ts +202 -0
- package/src/flows/flowGraph.ts +78 -53
- package/src/flows/index.ts +51 -2
- package/src/flows/labels.ts +180 -0
- package/src/flows/workspaceContract.test.ts +126 -0
- package/src/hooks/useContainerWidth.ts +35 -0
- package/src/hooks/useConversationActions.ts +56 -0
- package/src/hooks/useConversationDocuments.ts +11 -7
- package/src/hooks/useConversationList.ts +15 -9
- package/src/hooks/useConversationMessages.ts +2 -2
- package/src/hooks/useConversationRealtime.ts +10 -8
- package/src/hooks/useScrollToLatestMessage.ts +127 -0
- package/src/hooks/useUrlFilterState.ts +107 -0
- package/src/icon.constant.ts +12 -0
- package/src/index.ts +129 -13
- package/src/lib/cn.test.ts +29 -0
- package/src/lib/composer-formatting.test.ts +78 -0
- package/src/lib/composer-formatting.ts +145 -0
- package/src/lib/createMediaUrlResolver.ts +33 -0
- package/src/lib/paginated.test.ts +33 -0
- package/src/lib/paginated.ts +26 -0
- package/src/lib/whatsapp-formatting.test.tsx +37 -0
- package/src/lib/whatsapp-formatting.tsx +28 -3
- package/src/listing/index.tsx +202 -0
- package/src/pagination.constant.ts +10 -0
- package/src/preview/ConversationPreview.tsx +225 -17
- package/src/preview/ConversationSimulatorClient.ts +143 -0
- package/src/preview/ConversationSimulatorPanel.test.tsx +55 -0
- package/src/preview/ConversationSimulatorPanel.tsx +131 -0
- package/src/preview/MediaTypesPreview.tsx +87 -0
- package/src/preview/conversationPreviewFailures.test.ts +64 -0
- package/src/preview/createMockConversationsApi.ts +175 -15
- package/src/preview/createPreviewBridgeClient.test.ts +92 -0
- package/src/preview/createPreviewBridgeClient.ts +124 -0
- package/src/preview/createPreviewMediaUploader.ts +82 -0
- package/src/preview/createPreviewWebhookClient.test.ts +96 -0
- package/src/preview/createPreviewWebhookClient.ts +127 -4
- package/src/preview/index.ts +51 -3
- package/src/preview/mediaTypeOf.test.ts +15 -0
- package/src/preview/mockDocumentsSearch.test.ts +57 -0
- package/src/preview/preview.test.ts +5 -3
- package/src/preview/previewFileSamples.test.ts +151 -0
- package/src/preview/previewFileSamples.ts +74 -0
- package/src/preview/previewFixtures.ts +288 -1
- package/src/preview/previewMediaSource.test.ts +62 -0
- package/src/preview/previewMediaSource.ts +91 -0
- package/src/preview/previewMediaUploader.test.ts +61 -0
- package/src/providers/ConversationsProvider.tsx +8 -6
- package/src/providers/types.ts +185 -10
- package/src/quickReply.test.ts +58 -0
- package/src/settings/MessagesWorkspace.tsx +571 -0
- package/src/settings/TopicsForm.tsx +2 -0
- package/src/settings/TranscriptionSettingsForm.test.tsx +81 -0
- package/src/settings/TranscriptionSettingsForm.tsx +190 -0
- package/src/settings/WelcomeFarewellForm.tsx +1 -0
- package/src/settings/WhatsAppCreateTemplateForm.tsx +4 -1
- package/src/settings/WhatsAppTemplateSettingsForm.tsx +5 -2
- package/src/settings/WhatsAppTemplatesSettings.test.tsx +61 -0
- package/src/settings/WhatsAppTemplatesSettings.tsx +22 -2
- package/src/styles.css +858 -0
- package/src/types.ts +64 -1
- package/src/useWaitingNotifications.ts +74 -29
- package/src/workspace/BulkTemplateModal.tsx +132 -0
- package/src/workspace/ConversationPane.tsx +432 -0
- package/src/workspace/ConversationsInboxList.tsx +194 -0
- package/src/workspace/ConversationsWorkspace.tsx +423 -0
- package/src/workspace/index.ts +17 -0
- package/src/workspace/labels.test.ts +17 -0
- package/src/workspace/labels.ts +85 -0
- package/src/workspace/useConversationsInbox.ts +332 -0
- package/dist/chunk-4R6Y43DQ.js +0 -726
- package/dist/chunk-NV2RZ5KT.js +0 -56
- package/dist/types-C0PtaO7S.d.ts +0 -207
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// src/Tooltip.tsx
|
|
2
|
+
import { useEffect, useRef, useState } from "react";
|
|
3
|
+
import { createPortal } from "react-dom";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
var TOOLTIP_ATTRIBUTE = "data-cv-tooltip";
|
|
6
|
+
var TOOLTIP_DELAY_MS = 120;
|
|
7
|
+
var TOOLTIP_GAP_PX = 8;
|
|
8
|
+
var TOOLTIP_EDGE_PX = 72;
|
|
9
|
+
function tooltipPositionOf({ targetRect, viewportWidth }) {
|
|
10
|
+
const placement = targetRect.top < TOOLTIP_EDGE_PX ? "bottom" : "top";
|
|
11
|
+
const centerX = targetRect.left + targetRect.width / 2;
|
|
12
|
+
return {
|
|
13
|
+
left: Math.min(Math.max(centerX, TOOLTIP_EDGE_PX), viewportWidth - TOOLTIP_EDGE_PX),
|
|
14
|
+
top: placement === "top" ? targetRect.top - TOOLTIP_GAP_PX : targetRect.bottom + TOOLTIP_GAP_PX,
|
|
15
|
+
placement
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function tooltipStateFor(target, text) {
|
|
19
|
+
const position = tooltipPositionOf({
|
|
20
|
+
targetRect: target.getBoundingClientRect(),
|
|
21
|
+
viewportWidth: window.innerWidth
|
|
22
|
+
});
|
|
23
|
+
return { text, ...position };
|
|
24
|
+
}
|
|
25
|
+
var layerOwner;
|
|
26
|
+
function TooltipLayer() {
|
|
27
|
+
const identity = useRef({});
|
|
28
|
+
const [isOwner, setIsOwner] = useState(false);
|
|
29
|
+
const [tooltip, setTooltip] = useState(void 0);
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
const owned = identity.current;
|
|
32
|
+
if (layerOwner && layerOwner !== owned) return void 0;
|
|
33
|
+
layerOwner = owned;
|
|
34
|
+
setIsOwner(true);
|
|
35
|
+
return () => {
|
|
36
|
+
if (layerOwner === owned) layerOwner = void 0;
|
|
37
|
+
};
|
|
38
|
+
}, []);
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
if (!isOwner) return void 0;
|
|
41
|
+
let timer;
|
|
42
|
+
function cancelPending() {
|
|
43
|
+
if (timer) clearTimeout(timer);
|
|
44
|
+
timer = void 0;
|
|
45
|
+
}
|
|
46
|
+
function hide() {
|
|
47
|
+
cancelPending();
|
|
48
|
+
setTooltip(void 0);
|
|
49
|
+
}
|
|
50
|
+
function handleEnter(event) {
|
|
51
|
+
const origin = event.target;
|
|
52
|
+
if (!(origin instanceof Element)) return;
|
|
53
|
+
const target = origin.closest(`[${TOOLTIP_ATTRIBUTE}]`);
|
|
54
|
+
if (!target) {
|
|
55
|
+
hide();
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const text = target.getAttribute(TOOLTIP_ATTRIBUTE);
|
|
59
|
+
if (!text) {
|
|
60
|
+
hide();
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
cancelPending();
|
|
64
|
+
timer = setTimeout(() => setTooltip(tooltipStateFor(target, text)), TOOLTIP_DELAY_MS);
|
|
65
|
+
}
|
|
66
|
+
function handleLeaveWindow(event) {
|
|
67
|
+
if (!event.relatedTarget) hide();
|
|
68
|
+
}
|
|
69
|
+
function handleKeyDown(event) {
|
|
70
|
+
if (event.key === "Escape") hide();
|
|
71
|
+
}
|
|
72
|
+
document.addEventListener("pointerover", handleEnter);
|
|
73
|
+
document.addEventListener("pointerout", handleLeaveWindow);
|
|
74
|
+
document.addEventListener("focusin", handleEnter);
|
|
75
|
+
document.addEventListener("pointerdown", hide);
|
|
76
|
+
document.addEventListener("focusout", hide);
|
|
77
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
78
|
+
window.addEventListener("scroll", hide, true);
|
|
79
|
+
window.addEventListener("resize", hide);
|
|
80
|
+
return () => {
|
|
81
|
+
cancelPending();
|
|
82
|
+
document.removeEventListener("pointerover", handleEnter);
|
|
83
|
+
document.removeEventListener("pointerout", handleLeaveWindow);
|
|
84
|
+
document.removeEventListener("focusin", handleEnter);
|
|
85
|
+
document.removeEventListener("pointerdown", hide);
|
|
86
|
+
document.removeEventListener("focusout", hide);
|
|
87
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
88
|
+
window.removeEventListener("scroll", hide, true);
|
|
89
|
+
window.removeEventListener("resize", hide);
|
|
90
|
+
};
|
|
91
|
+
}, [isOwner]);
|
|
92
|
+
if (!tooltip) return null;
|
|
93
|
+
return createPortal(
|
|
94
|
+
/* @__PURE__ */ jsx(
|
|
95
|
+
"div",
|
|
96
|
+
{
|
|
97
|
+
role: "tooltip",
|
|
98
|
+
className: `cv-tooltip cv-tooltip--${tooltip.placement}`,
|
|
99
|
+
style: { left: tooltip.left, top: tooltip.top },
|
|
100
|
+
children: tooltip.text
|
|
101
|
+
}
|
|
102
|
+
),
|
|
103
|
+
document.body
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export {
|
|
108
|
+
TOOLTIP_ATTRIBUTE,
|
|
109
|
+
TooltipLayer
|
|
110
|
+
};
|
|
@@ -69,9 +69,12 @@ function parseInlineTokens(text) {
|
|
|
69
69
|
if (remaining) result.push({ type: "text", content: remaining });
|
|
70
70
|
break;
|
|
71
71
|
}
|
|
72
|
-
if (nextSpecial
|
|
73
|
-
result.push({ type: "text", content: remaining.slice(0,
|
|
72
|
+
if (nextSpecial === 0) {
|
|
73
|
+
result.push({ type: "text", content: remaining.slice(0, 1) });
|
|
74
|
+
remaining = remaining.slice(1);
|
|
75
|
+
continue;
|
|
74
76
|
}
|
|
77
|
+
result.push({ type: "text", content: remaining.slice(0, nextSpecial) });
|
|
75
78
|
remaining = remaining.slice(nextSpecial);
|
|
76
79
|
}
|
|
77
80
|
return result;
|
|
@@ -103,6 +106,9 @@ function unescapeHtml(text) {
|
|
|
103
106
|
}
|
|
104
107
|
var CODE_TOKEN_MARK = String.fromCharCode(57344);
|
|
105
108
|
var CODE_TOKEN_REGEX = new RegExp(`${CODE_TOKEN_MARK}(\\d+)${CODE_TOKEN_MARK}`, "g");
|
|
109
|
+
var ZERO_WIDTH_SPACE = String.fromCharCode(8203);
|
|
110
|
+
var EMPTY_CODE_REGEX = new RegExp(`<code[^>]*>[${ZERO_WIDTH_SPACE}\\s]*</code>`, "gi");
|
|
111
|
+
var ZERO_WIDTH_SPACE_REGEX = new RegExp(ZERO_WIDTH_SPACE, "g");
|
|
106
112
|
function waToHTML(text) {
|
|
107
113
|
if (!text) return "";
|
|
108
114
|
const codeTokens = [];
|
|
@@ -117,7 +123,7 @@ function waToHTML(text) {
|
|
|
117
123
|
let html = escapeHtml(working);
|
|
118
124
|
html = html.replace(/\*([^*\n]+)\*/g, "<strong>$1</strong>");
|
|
119
125
|
html = html.replace(/_([^_\n]+)_/g, "<em>$1</em>");
|
|
120
|
-
html = html.replace(/~([^~\n]+)~/g, "<
|
|
126
|
+
html = html.replace(/~([^~\n]+)~/g, "<s>$1</s>");
|
|
121
127
|
html = html.replace(/\n/g, "<br>");
|
|
122
128
|
html = html.replace(CODE_TOKEN_REGEX, (_match, indexStr) => {
|
|
123
129
|
const token = codeTokens[Number(indexStr)];
|
|
@@ -132,6 +138,7 @@ function waToHTML(text) {
|
|
|
132
138
|
function htmlToWA(html) {
|
|
133
139
|
if (!html) return "";
|
|
134
140
|
let text = html;
|
|
141
|
+
text = text.replace(EMPTY_CODE_REGEX, "");
|
|
135
142
|
text = text.replace(/<code data-wa="block"[^>]*>([\s\S]*?)<\/code>/gi, (_match, inner) => `\`\`\`${unescapeHtml(inner.replace(/<br\s*\/?>/gi, "\n"))}\`\`\``);
|
|
136
143
|
text = text.replace(/<code data-wa="inline"[^>]*>([\s\S]*?)<\/code>/gi, (_match, inner) => `\`${unescapeHtml(inner)}\``);
|
|
137
144
|
text = text.replace(/<br\s*\/?>/gi, "\n").replace(/<div>/gi, "\n").replace(/<\/div>/gi, "").replace(/<\/p>/gi, "\n").replace(/<p[^>]*>/gi, "");
|
|
@@ -141,9 +148,11 @@ function htmlToWA(html) {
|
|
|
141
148
|
text = text.replace(/<i>(.*?)<\/i>/gi, "_$1_");
|
|
142
149
|
text = text.replace(/<del>(.*?)<\/del>/gi, "~$1~");
|
|
143
150
|
text = text.replace(/<s>(.*?)<\/s>/gi, "~$1~");
|
|
151
|
+
text = text.replace(/<strike>(.*?)<\/strike>/gi, "~$1~");
|
|
144
152
|
text = text.replace(/<code[^>]*>(.*?)<\/code>/gi, "`$1`");
|
|
145
153
|
text = text.replace(/<[^>]+>/g, "");
|
|
146
154
|
text = unescapeHtml(text);
|
|
155
|
+
text = text.replace(ZERO_WIDTH_SPACE_REGEX, "");
|
|
147
156
|
return text.trim();
|
|
148
157
|
}
|
|
149
158
|
function waToHTMLInline(text) {
|
|
@@ -151,9 +160,64 @@ function waToHTMLInline(text) {
|
|
|
151
160
|
return escapeHtml(text).replace(/\*([^*\n]+)\*/g, "<strong>$1</strong>").replace(/_([^_\n]+)_/g, "<em>$1</em>").replace(/~([^~\n]+)~/g, "<del>$1</del>").replace(/`([^`\n]+)`/g, "<code>$1</code>");
|
|
152
161
|
}
|
|
153
162
|
|
|
163
|
+
// src/useDarkMode.ts
|
|
164
|
+
import { useState, useEffect, useCallback } from "react";
|
|
165
|
+
var STORAGE_KEY = "conversations-ui-dark-mode";
|
|
166
|
+
function getInitialDark() {
|
|
167
|
+
if (typeof window === "undefined") return false;
|
|
168
|
+
const stored = localStorage.getItem(STORAGE_KEY);
|
|
169
|
+
if (stored !== null) {
|
|
170
|
+
return stored === "true";
|
|
171
|
+
}
|
|
172
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
173
|
+
}
|
|
174
|
+
function useIsDarkTheme() {
|
|
175
|
+
const [isDark, setIsDark] = useState(
|
|
176
|
+
() => typeof document !== "undefined" && document.documentElement.classList.contains("dark")
|
|
177
|
+
);
|
|
178
|
+
useEffect(() => {
|
|
179
|
+
const root = document.documentElement;
|
|
180
|
+
const observer = new MutationObserver(() => setIsDark(root.classList.contains("dark")));
|
|
181
|
+
observer.observe(root, { attributes: true, attributeFilter: ["class"] });
|
|
182
|
+
setIsDark(root.classList.contains("dark"));
|
|
183
|
+
return () => observer.disconnect();
|
|
184
|
+
}, []);
|
|
185
|
+
return isDark;
|
|
186
|
+
}
|
|
187
|
+
function useDarkMode() {
|
|
188
|
+
const [isDark, setIsDark] = useState(getInitialDark);
|
|
189
|
+
useEffect(() => {
|
|
190
|
+
const root = document.documentElement;
|
|
191
|
+
if (isDark) {
|
|
192
|
+
root.classList.add("dark");
|
|
193
|
+
} else {
|
|
194
|
+
root.classList.remove("dark");
|
|
195
|
+
}
|
|
196
|
+
localStorage.setItem(STORAGE_KEY, String(isDark));
|
|
197
|
+
}, [isDark]);
|
|
198
|
+
useEffect(() => {
|
|
199
|
+
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
|
200
|
+
const handleChange = (event) => {
|
|
201
|
+
const stored = localStorage.getItem(STORAGE_KEY);
|
|
202
|
+
if (stored === null) {
|
|
203
|
+
setIsDark(event.matches);
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
mediaQuery.addEventListener("change", handleChange);
|
|
207
|
+
return () => mediaQuery.removeEventListener("change", handleChange);
|
|
208
|
+
}, []);
|
|
209
|
+
const toggle = useCallback(() => {
|
|
210
|
+
setIsDark((prev) => !prev);
|
|
211
|
+
}, []);
|
|
212
|
+
return { isDark, toggle };
|
|
213
|
+
}
|
|
214
|
+
|
|
154
215
|
export {
|
|
155
216
|
parseWhatsAppFormatting,
|
|
217
|
+
ZERO_WIDTH_SPACE,
|
|
156
218
|
waToHTML,
|
|
157
219
|
htmlToWA,
|
|
158
|
-
waToHTMLInline
|
|
220
|
+
waToHTMLInline,
|
|
221
|
+
useIsDarkTheme,
|
|
222
|
+
useDarkMode
|
|
159
223
|
};
|