@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.
Files changed (149) hide show
  1. package/dist/ConversationSimulatorPanel--5fIzXWY.d.ts +804 -0
  2. package/dist/chunk-BJNRLLDO.js +2708 -0
  3. package/dist/chunk-DKPXKQGC.js +110 -0
  4. package/dist/{chunk-OGRRHQQW.js → chunk-WCBDXZ3X.js} +68 -4
  5. package/dist/flows/index.d.ts +422 -5
  6. package/dist/flows/index.js +2389 -678
  7. package/dist/index.d.ts +1171 -42
  8. package/dist/index.js +3755 -843
  9. package/dist/preview/index.d.ts +157 -42
  10. package/dist/preview/index.js +772 -191
  11. package/dist/styles.css +893 -0
  12. package/package.json +9 -8
  13. package/src/AudioPlayer.tsx +8 -0
  14. package/src/AudioRecorderButton.test.tsx +30 -0
  15. package/src/AudioRecorderButton.tsx +248 -0
  16. package/src/AudioTranscription.test.tsx +115 -0
  17. package/src/AudioTranscription.tsx +252 -0
  18. package/src/Avatar.tsx +14 -3
  19. package/src/ConversationContextPanel.tsx +218 -44
  20. package/src/ConversationDocumentsPanel.tsx +347 -24
  21. package/src/ConversationHeader.test.tsx +66 -0
  22. package/src/ConversationHeader.tsx +163 -45
  23. package/src/ConversationListItem.tsx +19 -2
  24. package/src/ConversationLocalesProvider.tsx +28 -0
  25. package/src/ConversationRow.tsx +31 -7
  26. package/src/DarkModeToggle.test.tsx +76 -0
  27. package/src/DarkModeToggle.tsx +92 -0
  28. package/src/DocumentsLibrary.tsx +382 -0
  29. package/src/EmojiPicker.tsx +70 -55
  30. package/src/FileIcon.test.ts +83 -0
  31. package/src/FileIcon.tsx +88 -11
  32. package/src/InteractiveMessage.test.tsx +41 -0
  33. package/src/InteractiveMessage.tsx +146 -0
  34. package/src/Lightbox.tsx +18 -3
  35. package/src/MediaRenderer.tsx +92 -16
  36. package/src/MessageBubble.test.tsx +41 -0
  37. package/src/MessageBubble.tsx +75 -6
  38. package/src/MessageComposer.test.tsx +35 -0
  39. package/src/MessageComposer.tsx +155 -19
  40. package/src/RichMessageComposer.test.tsx +113 -0
  41. package/src/RichMessageComposer.tsx +551 -0
  42. package/src/SimpleEmojiPicker.tsx +5 -3
  43. package/src/StatusTicks.tsx +1 -1
  44. package/src/Toast.tsx +4 -0
  45. package/src/Tooltip.test.ts +42 -0
  46. package/src/Tooltip.tsx +167 -0
  47. package/src/Wallpaper.test.tsx +21 -0
  48. package/src/Wallpaper.tsx +67 -7
  49. package/src/WhatsAppMessageEditor.tsx +34 -7
  50. package/src/WindowExpiredNotice.tsx +12 -4
  51. package/src/audioRecorderFormat.test.ts +67 -0
  52. package/src/buildOutput.test.ts +79 -0
  53. package/src/composer.constant.ts +33 -0
  54. package/src/conversationTranscript.test.ts +57 -0
  55. package/src/conversationTranscript.ts +29 -4
  56. package/src/conversationWindow.ts +7 -5
  57. package/src/documentTypeLabel.test.ts +57 -0
  58. package/src/documents/DocumentsWorkspace.tsx +550 -0
  59. package/src/documents/index.ts +8 -0
  60. package/src/documents/labels.ts +92 -0
  61. package/src/emojiCatalog.test.ts +35 -0
  62. package/src/emojiCatalog.ts +189 -0
  63. package/src/flows/FlowConnectionEdge.tsx +104 -0
  64. package/src/flows/FlowGroupHeader.tsx +12 -2
  65. package/src/flows/FlowLegend.tsx +125 -0
  66. package/src/flows/FlowMapCanvas.tsx +15 -12
  67. package/src/flows/FlowMapNode.tsx +4 -1
  68. package/src/flows/FlowNodeCard.tsx +219 -34
  69. package/src/flows/FlowNodePanel.tsx +153 -39
  70. package/src/flows/FlowPalette.tsx +106 -69
  71. package/src/flows/FlowPortalNode.tsx +1 -1
  72. package/src/flows/FlowWhatsAppPreview.tsx +14 -3
  73. package/src/flows/FlowsWorkspace.tsx +1219 -0
  74. package/src/flows/flowCanvasModel.test.ts +456 -0
  75. package/src/flows/flowCanvasModel.ts +378 -0
  76. package/src/flows/flowEditorOps.test.ts +276 -0
  77. package/src/flows/flowEditorOps.ts +202 -0
  78. package/src/flows/flowGraph.ts +78 -53
  79. package/src/flows/index.ts +51 -2
  80. package/src/flows/labels.ts +180 -0
  81. package/src/flows/workspaceContract.test.ts +126 -0
  82. package/src/hooks/useContainerWidth.ts +35 -0
  83. package/src/hooks/useConversationActions.ts +56 -0
  84. package/src/hooks/useConversationDocuments.ts +11 -7
  85. package/src/hooks/useConversationList.ts +15 -9
  86. package/src/hooks/useConversationMessages.ts +2 -2
  87. package/src/hooks/useConversationRealtime.ts +10 -8
  88. package/src/hooks/useScrollToLatestMessage.ts +127 -0
  89. package/src/hooks/useUrlFilterState.ts +107 -0
  90. package/src/icon.constant.ts +12 -0
  91. package/src/index.ts +129 -13
  92. package/src/lib/cn.test.ts +29 -0
  93. package/src/lib/composer-formatting.test.ts +78 -0
  94. package/src/lib/composer-formatting.ts +145 -0
  95. package/src/lib/createMediaUrlResolver.ts +33 -0
  96. package/src/lib/paginated.test.ts +33 -0
  97. package/src/lib/paginated.ts +26 -0
  98. package/src/lib/whatsapp-formatting.test.tsx +37 -0
  99. package/src/lib/whatsapp-formatting.tsx +28 -3
  100. package/src/listing/index.tsx +202 -0
  101. package/src/pagination.constant.ts +10 -0
  102. package/src/preview/ConversationPreview.tsx +225 -17
  103. package/src/preview/ConversationSimulatorClient.ts +143 -0
  104. package/src/preview/ConversationSimulatorPanel.test.tsx +55 -0
  105. package/src/preview/ConversationSimulatorPanel.tsx +131 -0
  106. package/src/preview/MediaTypesPreview.tsx +87 -0
  107. package/src/preview/conversationPreviewFailures.test.ts +64 -0
  108. package/src/preview/createMockConversationsApi.ts +175 -15
  109. package/src/preview/createPreviewBridgeClient.test.ts +92 -0
  110. package/src/preview/createPreviewBridgeClient.ts +124 -0
  111. package/src/preview/createPreviewMediaUploader.ts +82 -0
  112. package/src/preview/createPreviewWebhookClient.test.ts +96 -0
  113. package/src/preview/createPreviewWebhookClient.ts +127 -4
  114. package/src/preview/index.ts +51 -3
  115. package/src/preview/mediaTypeOf.test.ts +15 -0
  116. package/src/preview/mockDocumentsSearch.test.ts +57 -0
  117. package/src/preview/preview.test.ts +5 -3
  118. package/src/preview/previewFileSamples.test.ts +151 -0
  119. package/src/preview/previewFileSamples.ts +74 -0
  120. package/src/preview/previewFixtures.ts +288 -1
  121. package/src/preview/previewMediaSource.test.ts +62 -0
  122. package/src/preview/previewMediaSource.ts +91 -0
  123. package/src/preview/previewMediaUploader.test.ts +61 -0
  124. package/src/providers/ConversationsProvider.tsx +8 -6
  125. package/src/providers/types.ts +185 -10
  126. package/src/quickReply.test.ts +58 -0
  127. package/src/settings/MessagesWorkspace.tsx +571 -0
  128. package/src/settings/TopicsForm.tsx +2 -0
  129. package/src/settings/TranscriptionSettingsForm.test.tsx +81 -0
  130. package/src/settings/TranscriptionSettingsForm.tsx +190 -0
  131. package/src/settings/WelcomeFarewellForm.tsx +1 -0
  132. package/src/settings/WhatsAppCreateTemplateForm.tsx +4 -1
  133. package/src/settings/WhatsAppTemplateSettingsForm.tsx +5 -2
  134. package/src/settings/WhatsAppTemplatesSettings.test.tsx +61 -0
  135. package/src/settings/WhatsAppTemplatesSettings.tsx +22 -2
  136. package/src/styles.css +858 -0
  137. package/src/types.ts +64 -1
  138. package/src/useWaitingNotifications.ts +74 -29
  139. package/src/workspace/BulkTemplateModal.tsx +132 -0
  140. package/src/workspace/ConversationPane.tsx +432 -0
  141. package/src/workspace/ConversationsInboxList.tsx +194 -0
  142. package/src/workspace/ConversationsWorkspace.tsx +423 -0
  143. package/src/workspace/index.ts +17 -0
  144. package/src/workspace/labels.test.ts +17 -0
  145. package/src/workspace/labels.ts +85 -0
  146. package/src/workspace/useConversationsInbox.ts +332 -0
  147. package/dist/chunk-4R6Y43DQ.js +0 -726
  148. package/dist/chunk-NV2RZ5KT.js +0 -56
  149. 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 > 0) {
73
- result.push({ type: "text", content: remaining.slice(0, nextSpecial) });
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, "<del>$1</del>");
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
  };