@adatechnology/conversations-ui 0.1.0-rc.12 → 0.1.0-rc.13

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.
@@ -1081,11 +1081,99 @@ var MessageComposer = ({
1081
1081
  );
1082
1082
  };
1083
1083
 
1084
+ // src/AudioRecorderButton.tsx
1085
+ import { useCallback as useCallback3, useRef as useRef3, useState as useState7 } from "react";
1086
+ import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
1087
+ var DEFAULT_AUDIO_RECORDER_BUTTON_LABELS = {
1088
+ start: "Gravar \xE1udio",
1089
+ stop: "Parar grava\xE7\xE3o",
1090
+ unsupported: "Este navegador n\xE3o grava \xE1udio.",
1091
+ denied: "Sem permiss\xE3o para usar o microfone."
1092
+ };
1093
+ var DEFAULT_MAX_RECORDING_MILLISECONDS = 5 * 60 * 1e3;
1094
+ var RECORDING_FORMATS = [
1095
+ { mimeType: "audio/ogg;codecs=opus", uploadMimeType: "audio/ogg", extension: "ogg" },
1096
+ { mimeType: "audio/mp4", uploadMimeType: "audio/mp4", extension: "m4a" },
1097
+ { mimeType: "audio/webm", uploadMimeType: "audio/webm", extension: "webm" }
1098
+ ];
1099
+ function resolveRecordingFormat() {
1100
+ if (typeof MediaRecorder === "undefined") return void 0;
1101
+ if (typeof MediaRecorder.isTypeSupported !== "function") return RECORDING_FORMATS[0];
1102
+ return RECORDING_FORMATS.find((format) => MediaRecorder.isTypeSupported(format.mimeType));
1103
+ }
1104
+ function AudioRecorderButton({
1105
+ onRecorded,
1106
+ onFailure,
1107
+ onRecordingChange,
1108
+ maxDurationMilliseconds = DEFAULT_MAX_RECORDING_MILLISECONDS,
1109
+ labels,
1110
+ disabled
1111
+ }) {
1112
+ const startLabel = labels?.start ?? DEFAULT_AUDIO_RECORDER_BUTTON_LABELS.start;
1113
+ const stopLabel = labels?.stop ?? DEFAULT_AUDIO_RECORDER_BUTTON_LABELS.stop;
1114
+ const [isRecording, setIsRecording] = useState7(false);
1115
+ const recorderRef = useRef3(null);
1116
+ const autoStopRef = useRef3(void 0);
1117
+ const stop = useCallback3(() => {
1118
+ recorderRef.current?.stop();
1119
+ }, []);
1120
+ const start = useCallback3(async () => {
1121
+ const format = resolveRecordingFormat();
1122
+ if (!format || !navigator.mediaDevices?.getUserMedia) {
1123
+ onFailure?.(labels?.unsupported ?? DEFAULT_AUDIO_RECORDER_BUTTON_LABELS.unsupported);
1124
+ return;
1125
+ }
1126
+ try {
1127
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
1128
+ const recorder = new MediaRecorder(stream, { mimeType: format.mimeType });
1129
+ const chunks = [];
1130
+ recorder.addEventListener("dataavailable", (event) => {
1131
+ if (event.data.size > 0) chunks.push(event.data);
1132
+ });
1133
+ recorder.addEventListener("stop", () => {
1134
+ stream.getTracks().forEach((track) => track.stop());
1135
+ clearTimeout(autoStopRef.current);
1136
+ setIsRecording(false);
1137
+ onRecordingChange?.(false);
1138
+ recorderRef.current = null;
1139
+ const blob = new Blob(chunks, { type: format.uploadMimeType });
1140
+ void onRecorded(
1141
+ new File([blob], `audio-${Date.now()}.${format.extension}`, { type: format.uploadMimeType })
1142
+ );
1143
+ });
1144
+ recorderRef.current = recorder;
1145
+ recorder.start();
1146
+ autoStopRef.current = setTimeout(() => recorder.stop(), maxDurationMilliseconds);
1147
+ setIsRecording(true);
1148
+ onRecordingChange?.(true);
1149
+ } catch {
1150
+ onFailure?.(labels?.denied ?? DEFAULT_AUDIO_RECORDER_BUTTON_LABELS.denied);
1151
+ }
1152
+ }, [labels?.denied, labels?.unsupported, maxDurationMilliseconds, onFailure, onRecorded, onRecordingChange]);
1153
+ return /* @__PURE__ */ jsx13(
1154
+ "button",
1155
+ {
1156
+ type: "button",
1157
+ disabled,
1158
+ onClick: () => isRecording ? stop() : void start(),
1159
+ title: isRecording ? stopLabel : startLabel,
1160
+ "aria-label": isRecording ? stopLabel : startLabel,
1161
+ "aria-pressed": isRecording,
1162
+ className: `flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-full transition-colors ${isRecording ? "animate-pulse bg-red-500 text-white ring-4 ring-red-500/30 hover:bg-red-600" : "text-gray-500 hover:bg-gray-200 dark:hover:bg-gray-700"}`,
1163
+ children: isRecording ? /* @__PURE__ */ jsx13("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx13("rect", { x: "6", y: "6", width: "12", height: "12", rx: "2" }) }) : /* @__PURE__ */ jsxs9("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", children: [
1164
+ /* @__PURE__ */ jsx13("path", { d: "M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3z" }),
1165
+ /* @__PURE__ */ jsx13("path", { d: "M19 11a7 7 0 0 1-14 0" }),
1166
+ /* @__PURE__ */ jsx13("line", { x1: "12", y1: "18", x2: "12", y2: "22" })
1167
+ ] })
1168
+ }
1169
+ );
1170
+ }
1171
+
1084
1172
  // src/DateDivider.tsx
1085
- import { jsx as jsx13 } from "react/jsx-runtime";
1173
+ import { jsx as jsx14 } from "react/jsx-runtime";
1086
1174
  function DateDivider({ iso, className, classNames }) {
1087
1175
  const { dateDivider } = useConversationLocales();
1088
- return /* @__PURE__ */ jsx13("div", { className: cn("flex justify-center sticky top-0 z-10 my-2 pointer-events-none", classNames?.root, className), children: /* @__PURE__ */ jsx13(
1176
+ return /* @__PURE__ */ jsx14("div", { className: cn("flex justify-center sticky top-0 z-10 my-2 pointer-events-none", classNames?.root, className), children: /* @__PURE__ */ jsx14(
1089
1177
  "span",
1090
1178
  {
1091
1179
  className: cn(
@@ -1152,13 +1240,13 @@ function phoneInitials(number) {
1152
1240
  }
1153
1241
 
1154
1242
  // src/hooks/useAsyncResource.ts
1155
- import { useCallback as useCallback3, useEffect as useEffect2, useRef as useRef3, useState as useState7 } from "react";
1243
+ import { useCallback as useCallback4, useEffect as useEffect2, useRef as useRef4, useState as useState8 } from "react";
1156
1244
  function useAsyncResource(fetcher, deps) {
1157
- const [data, setData] = useState7(void 0);
1158
- const [loading, setLoading] = useState7(false);
1159
- const [error, setError] = useState7(void 0);
1160
- const requestIdRef = useRef3(0);
1161
- const load = useCallback3(async () => {
1245
+ const [data, setData] = useState8(void 0);
1246
+ const [loading, setLoading] = useState8(false);
1247
+ const [error, setError] = useState8(void 0);
1248
+ const requestIdRef = useRef4(0);
1249
+ const load = useCallback4(async () => {
1162
1250
  const requestId = ++requestIdRef.current;
1163
1251
  setLoading(true);
1164
1252
  setError(void 0);
@@ -1206,9 +1294,9 @@ function useConversationDocuments(conversationId, params) {
1206
1294
  }
1207
1295
 
1208
1296
  // src/ConversationDocumentsPanel.tsx
1209
- import { useState as useState8 } from "react";
1297
+ import { useState as useState9 } from "react";
1210
1298
  import { ArrowUpDown, Bot, Download, Eye, Users } from "lucide-react";
1211
- import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
1299
+ import { jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
1212
1300
  var DOCUMENT_SOURCE_FILTER = {
1213
1301
  ALL: "all",
1214
1302
  CUSTOMER: "customer",
@@ -1248,12 +1336,12 @@ function ConversationDocumentsPanel({
1248
1336
  }) {
1249
1337
  const labels = { ...DEFAULT_CONVERSATION_DOCUMENTS_LABELS, ...labelsOverride };
1250
1338
  const context = useConversations();
1251
- const [search, setSearch] = useState8("");
1252
- const [sourceFilter, setSourceFilter] = useState8(DOCUMENT_SOURCE_FILTER.ALL);
1253
- const [sortDirection, setSortDirection] = useState8("desc");
1254
- const [page, setPage] = useState8(1);
1255
- const [selectedIds, setSelectedIds] = useState8([]);
1256
- const [archiveError, setArchiveError] = useState8(false);
1339
+ const [search, setSearch] = useState9("");
1340
+ const [sourceFilter, setSourceFilter] = useState9(DOCUMENT_SOURCE_FILTER.ALL);
1341
+ const [sortDirection, setSortDirection] = useState9("desc");
1342
+ const [page, setPage] = useState9(1);
1343
+ const [selectedIds, setSelectedIds] = useState9([]);
1344
+ const [archiveError, setArchiveError] = useState9(false);
1257
1345
  const hasFilters = search !== "" || sourceFilter !== DOCUMENT_SOURCE_FILTER.ALL || sortDirection !== "desc";
1258
1346
  const { documents, total, loading, error } = useConversationDocuments(open ? conversationId : void 0, {
1259
1347
  search,
@@ -1304,10 +1392,10 @@ function ConversationDocumentsPanel({
1304
1392
  }
1305
1393
  }
1306
1394
  if (!open) return null;
1307
- return /* @__PURE__ */ jsx14("div", { className: cn("border-b", classNames?.root, className), children: /* @__PURE__ */ jsxs9("section", { className: cn("px-4 py-3", classNames?.body), children: [
1308
- /* @__PURE__ */ jsx14("p", { className: cn("mb-2 text-sm font-medium", classNames?.title), children: labels.title }),
1309
- /* @__PURE__ */ jsxs9("div", { className: cn("mb-2 flex flex-wrap items-center gap-2 border-b pb-2", classNames?.filters), children: [
1310
- /* @__PURE__ */ jsx14(
1395
+ return /* @__PURE__ */ jsx15("div", { className: cn("border-b", classNames?.root, className), children: /* @__PURE__ */ jsxs10("section", { className: cn("px-4 py-3", classNames?.body), children: [
1396
+ /* @__PURE__ */ jsx15("p", { className: cn("mb-2 text-sm font-medium", classNames?.title), children: labels.title }),
1397
+ /* @__PURE__ */ jsxs10("div", { className: cn("mb-2 flex flex-wrap items-center gap-2 border-b pb-2", classNames?.filters), children: [
1398
+ /* @__PURE__ */ jsx15(
1311
1399
  "input",
1312
1400
  {
1313
1401
  type: "search",
@@ -1318,7 +1406,7 @@ function ConversationDocumentsPanel({
1318
1406
  className: cn("w-full rounded-md border px-3 py-2 text-sm sm:w-52", classNames?.search)
1319
1407
  }
1320
1408
  ),
1321
- /* @__PURE__ */ jsxs9(
1409
+ /* @__PURE__ */ jsxs10(
1322
1410
  "select",
1323
1411
  {
1324
1412
  value: sourceFilter,
@@ -1326,25 +1414,25 @@ function ConversationDocumentsPanel({
1326
1414
  "aria-label": labels.sourceFilterAll,
1327
1415
  className: cn("w-full rounded-md border px-2 py-2 text-sm sm:w-36", classNames?.sourceSelect),
1328
1416
  children: [
1329
- /* @__PURE__ */ jsx14("option", { value: DOCUMENT_SOURCE_FILTER.ALL, children: labels.sourceFilterAll }),
1330
- /* @__PURE__ */ jsx14("option", { value: DOCUMENT_SOURCE_FILTER.CUSTOMER, children: labels.sourceFilterCustomer }),
1331
- /* @__PURE__ */ jsx14("option", { value: DOCUMENT_SOURCE_FILTER.TEAM, children: labels.sourceFilterTeam })
1417
+ /* @__PURE__ */ jsx15("option", { value: DOCUMENT_SOURCE_FILTER.ALL, children: labels.sourceFilterAll }),
1418
+ /* @__PURE__ */ jsx15("option", { value: DOCUMENT_SOURCE_FILTER.CUSTOMER, children: labels.sourceFilterCustomer }),
1419
+ /* @__PURE__ */ jsx15("option", { value: DOCUMENT_SOURCE_FILTER.TEAM, children: labels.sourceFilterTeam })
1332
1420
  ]
1333
1421
  }
1334
1422
  ),
1335
- /* @__PURE__ */ jsxs9(
1423
+ /* @__PURE__ */ jsxs10(
1336
1424
  "button",
1337
1425
  {
1338
1426
  type: "button",
1339
1427
  onClick: () => applyFilter(() => setSortDirection(sortDirection === "desc" ? "asc" : "desc")),
1340
1428
  className: cn("cv-header-action inline-flex items-center gap-1", classNames?.sortButton),
1341
1429
  children: [
1342
- /* @__PURE__ */ jsx14(ArrowUpDown, { size: 14 }),
1430
+ /* @__PURE__ */ jsx15(ArrowUpDown, { size: 14 }),
1343
1431
  sortDirection === "desc" ? labels.sortMostRecent : labels.sortOldest
1344
1432
  ]
1345
1433
  }
1346
1434
  ),
1347
- hasFilters ? /* @__PURE__ */ jsx14(
1435
+ hasFilters ? /* @__PURE__ */ jsx15(
1348
1436
  "button",
1349
1437
  {
1350
1438
  type: "button",
@@ -1358,12 +1446,12 @@ function ConversationDocumentsPanel({
1358
1446
  }
1359
1447
  ) : null
1360
1448
  ] }),
1361
- loading ? /* @__PURE__ */ jsx14("p", { className: cn("text-xs text-gray-500", classNames?.status), children: labels.loading }) : null,
1362
- error ? /* @__PURE__ */ jsx14("p", { role: "alert", className: cn("text-xs text-red-600 dark:text-red-400", classNames?.status), children: labels.failure }) : null,
1363
- !loading && !error && documents.length === 0 ? /* @__PURE__ */ jsx14("p", { className: cn("text-xs text-gray-500", classNames?.status), children: hasFilters ? labels.noResults : labels.empty }) : null,
1364
- canArchive && documents.length > 0 ? /* @__PURE__ */ jsxs9("div", { className: cn("mb-2 flex flex-wrap items-center gap-3 text-xs", classNames?.selectionBar), children: [
1365
- /* @__PURE__ */ jsxs9("label", { className: "inline-flex items-center gap-1.5", children: [
1366
- /* @__PURE__ */ jsx14(
1449
+ loading ? /* @__PURE__ */ jsx15("p", { className: cn("text-xs text-gray-500", classNames?.status), children: labels.loading }) : null,
1450
+ error ? /* @__PURE__ */ jsx15("p", { role: "alert", className: cn("text-xs text-red-600 dark:text-red-400", classNames?.status), children: labels.failure }) : null,
1451
+ !loading && !error && documents.length === 0 ? /* @__PURE__ */ jsx15("p", { className: cn("text-xs text-gray-500", classNames?.status), children: hasFilters ? labels.noResults : labels.empty }) : null,
1452
+ canArchive && documents.length > 0 ? /* @__PURE__ */ jsxs10("div", { className: cn("mb-2 flex flex-wrap items-center gap-3 text-xs", classNames?.selectionBar), children: [
1453
+ /* @__PURE__ */ jsxs10("label", { className: "inline-flex items-center gap-1.5", children: [
1454
+ /* @__PURE__ */ jsx15(
1367
1455
  "input",
1368
1456
  {
1369
1457
  type: "checkbox",
@@ -1374,13 +1462,13 @@ function ConversationDocumentsPanel({
1374
1462
  ),
1375
1463
  labels.selectAll
1376
1464
  ] }),
1377
- selectedIds.length > 0 ? /* @__PURE__ */ jsx14("button", { type: "button", onClick: () => void handleDownloadSelected(), className: "cv-header-action", children: labels.downloadSelected(selectedIds.length) }) : null,
1378
- archiveError ? /* @__PURE__ */ jsx14("span", { role: "alert", className: "text-red-600 dark:text-red-400", children: labels.archiveFailed }) : null
1465
+ selectedIds.length > 0 ? /* @__PURE__ */ jsx15("button", { type: "button", onClick: () => void handleDownloadSelected(), className: "cv-header-action", children: labels.downloadSelected(selectedIds.length) }) : null,
1466
+ archiveError ? /* @__PURE__ */ jsx15("span", { role: "alert", className: "text-red-600 dark:text-red-400", children: labels.archiveFailed }) : null
1379
1467
  ] }) : null,
1380
- /* @__PURE__ */ jsx14("ul", { className: cn("space-y-2", classNames?.list), children: documents.map((document2) => {
1468
+ /* @__PURE__ */ jsx15("ul", { className: cn("space-y-2", classNames?.list), children: documents.map((document2) => {
1381
1469
  const isFromCustomer = !TEAM_SOURCES.has(document2.source);
1382
1470
  const SourceIcon = isFromCustomer ? Users : Bot;
1383
- return /* @__PURE__ */ jsxs9(
1471
+ return /* @__PURE__ */ jsxs10(
1384
1472
  "li",
1385
1473
  {
1386
1474
  className: cn(
@@ -1388,8 +1476,8 @@ function ConversationDocumentsPanel({
1388
1476
  classNames?.item
1389
1477
  ),
1390
1478
  children: [
1391
- /* @__PURE__ */ jsxs9("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
1392
- canArchive ? /* @__PURE__ */ jsx14(
1479
+ /* @__PURE__ */ jsxs10("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
1480
+ canArchive ? /* @__PURE__ */ jsx15(
1393
1481
  "input",
1394
1482
  {
1395
1483
  type: "checkbox",
@@ -1399,9 +1487,9 @@ function ConversationDocumentsPanel({
1399
1487
  className: cn("shrink-0", classNames?.checkbox)
1400
1488
  }
1401
1489
  ) : null,
1402
- /* @__PURE__ */ jsx14(FileIcon, { filename: document2.filename, mimeType: document2.mimeType }),
1403
- /* @__PURE__ */ jsxs9("div", { className: "min-w-0 flex-1", children: [
1404
- /* @__PURE__ */ jsxs9(
1490
+ /* @__PURE__ */ jsx15(FileIcon, { filename: document2.filename, mimeType: document2.mimeType }),
1491
+ /* @__PURE__ */ jsxs10("div", { className: "min-w-0 flex-1", children: [
1492
+ /* @__PURE__ */ jsxs10(
1405
1493
  "div",
1406
1494
  {
1407
1495
  className: cn(
@@ -1410,12 +1498,12 @@ function ConversationDocumentsPanel({
1410
1498
  classNames?.sourceBadge
1411
1499
  ),
1412
1500
  children: [
1413
- /* @__PURE__ */ jsx14(SourceIcon, { size: 11 }),
1501
+ /* @__PURE__ */ jsx15(SourceIcon, { size: 11 }),
1414
1502
  isFromCustomer ? labels.sourceFilterCustomer : labels.sourceFilterTeam
1415
1503
  ]
1416
1504
  }
1417
1505
  ),
1418
- /* @__PURE__ */ jsx14(
1506
+ /* @__PURE__ */ jsx15(
1419
1507
  "div",
1420
1508
  {
1421
1509
  className: cn("truncate text-sm font-medium", classNames?.filename),
@@ -1423,15 +1511,15 @@ function ConversationDocumentsPanel({
1423
1511
  children: document2.filename
1424
1512
  }
1425
1513
  ),
1426
- /* @__PURE__ */ jsxs9("div", { className: cn("text-xs text-gray-500 dark:text-gray-400", classNames?.meta), children: [
1514
+ /* @__PURE__ */ jsxs10("div", { className: cn("text-xs text-gray-500 dark:text-gray-400", classNames?.meta), children: [
1427
1515
  formatDateTime(document2.linkedAt),
1428
1516
  " \xB7 ",
1429
1517
  formatFileSize(document2.sizeBytes)
1430
1518
  ] })
1431
1519
  ] })
1432
1520
  ] }),
1433
- /* @__PURE__ */ jsxs9("div", { className: "flex shrink-0 gap-1", children: [
1434
- /* @__PURE__ */ jsx14(
1521
+ /* @__PURE__ */ jsxs10("div", { className: "flex shrink-0 gap-1", children: [
1522
+ /* @__PURE__ */ jsx15(
1435
1523
  "button",
1436
1524
  {
1437
1525
  type: "button",
@@ -1439,10 +1527,10 @@ function ConversationDocumentsPanel({
1439
1527
  title: labels.view,
1440
1528
  "aria-label": `${labels.view}: ${document2.filename}`,
1441
1529
  className: cn("cv-header-icon", classNames?.viewButton),
1442
- children: /* @__PURE__ */ jsx14(Eye, { size: 14 })
1530
+ children: /* @__PURE__ */ jsx15(Eye, { size: 14 })
1443
1531
  }
1444
1532
  ),
1445
- /* @__PURE__ */ jsx14(
1533
+ /* @__PURE__ */ jsx15(
1446
1534
  "button",
1447
1535
  {
1448
1536
  type: "button",
@@ -1450,7 +1538,7 @@ function ConversationDocumentsPanel({
1450
1538
  title: labels.download,
1451
1539
  "aria-label": `${labels.download}: ${document2.filename}`,
1452
1540
  className: cn("cv-header-icon", classNames?.downloadButton),
1453
- children: /* @__PURE__ */ jsx14(Download, { size: 14 })
1541
+ children: /* @__PURE__ */ jsx15(Download, { size: 14 })
1454
1542
  }
1455
1543
  )
1456
1544
  ] })
@@ -1459,7 +1547,7 @@ function ConversationDocumentsPanel({
1459
1547
  document2.id
1460
1548
  );
1461
1549
  }) }),
1462
- total > perPage ? /* @__PURE__ */ jsxs9(
1550
+ total > perPage ? /* @__PURE__ */ jsxs10(
1463
1551
  "div",
1464
1552
  {
1465
1553
  className: cn(
@@ -1467,9 +1555,9 @@ function ConversationDocumentsPanel({
1467
1555
  classNames?.pagination
1468
1556
  ),
1469
1557
  children: [
1470
- /* @__PURE__ */ jsx14("span", { className: "text-gray-400", children: labels.total(total) }),
1471
- /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2", children: [
1472
- /* @__PURE__ */ jsx14(
1558
+ /* @__PURE__ */ jsx15("span", { className: "text-gray-400", children: labels.total(total) }),
1559
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2", children: [
1560
+ /* @__PURE__ */ jsx15(
1473
1561
  "button",
1474
1562
  {
1475
1563
  type: "button",
@@ -1480,8 +1568,8 @@ function ConversationDocumentsPanel({
1480
1568
  children: "\u2039"
1481
1569
  }
1482
1570
  ),
1483
- /* @__PURE__ */ jsx14("span", { className: "text-gray-500", children: labels.page(page, lastPage) }),
1484
- /* @__PURE__ */ jsx14(
1571
+ /* @__PURE__ */ jsx15("span", { className: "text-gray-500", children: labels.page(page, lastPage) }),
1572
+ /* @__PURE__ */ jsx15(
1485
1573
  "button",
1486
1574
  {
1487
1575
  type: "button",
@@ -1500,9 +1588,9 @@ function ConversationDocumentsPanel({
1500
1588
  }
1501
1589
 
1502
1590
  // src/DocumentsLibrary.tsx
1503
- import { useEffect as useEffect3, useState as useState9 } from "react";
1591
+ import { useEffect as useEffect3, useState as useState10 } from "react";
1504
1592
  import { ArrowUpDown as ArrowUpDown2, Bot as Bot2, Download as Download2, Eye as Eye2, MessageSquare, Users as Users2 } from "lucide-react";
1505
- import { jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
1593
+ import { jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
1506
1594
  var DEFAULT_DOCUMENTS_LIBRARY_LABELS = {
1507
1595
  title: "Documentos",
1508
1596
  searchPlaceholder: "Buscar por nome do arquivo ou telefone",
@@ -1533,14 +1621,14 @@ function DocumentsLibrary({
1533
1621
  }) {
1534
1622
  const labels = { ...DEFAULT_DOCUMENTS_LIBRARY_LABELS, ...labelsOverride };
1535
1623
  const context = useConversations();
1536
- const [search, setSearch] = useState9("");
1537
- const [sourceFilter, setSourceFilter] = useState9(DOCUMENT_SOURCE_FILTER.ALL);
1538
- const [sortDirection, setSortDirection] = useState9("desc");
1539
- const [page, setPage] = useState9(1);
1540
- const [documents, setDocuments] = useState9([]);
1541
- const [total, setTotal] = useState9(0);
1542
- const [loading, setLoading] = useState9(false);
1543
- const [failed, setFailed] = useState9(false);
1624
+ const [search, setSearch] = useState10("");
1625
+ const [sourceFilter, setSourceFilter] = useState10(DOCUMENT_SOURCE_FILTER.ALL);
1626
+ const [sortDirection, setSortDirection] = useState10("desc");
1627
+ const [page, setPage] = useState10(1);
1628
+ const [documents, setDocuments] = useState10([]);
1629
+ const [total, setTotal] = useState10(0);
1630
+ const [loading, setLoading] = useState10(false);
1631
+ const [failed, setFailed] = useState10(false);
1544
1632
  const hasFilters = search !== "" || sourceFilter !== DOCUMENT_SOURCE_FILTER.ALL || sortDirection !== "desc";
1545
1633
  const lastPage = Math.max(1, Math.ceil(total / perPage));
1546
1634
  const fetchAll = context?.api.getAllDocuments;
@@ -1577,10 +1665,10 @@ function DocumentsLibrary({
1577
1665
  if (url) window.open(url, "_blank", "noopener,noreferrer");
1578
1666
  }
1579
1667
  if (!fetchAll) return null;
1580
- return /* @__PURE__ */ jsxs10("div", { className: cn("space-y-3", classNames?.root, className), children: [
1581
- /* @__PURE__ */ jsx15("h2", { className: cn("text-lg font-semibold", classNames?.title), children: labels.title }),
1582
- /* @__PURE__ */ jsxs10("div", { className: cn("flex flex-wrap items-center gap-2", classNames?.filters), children: [
1583
- /* @__PURE__ */ jsx15(
1668
+ return /* @__PURE__ */ jsxs11("div", { className: cn("space-y-3", classNames?.root, className), children: [
1669
+ /* @__PURE__ */ jsx16("h2", { className: cn("text-lg font-semibold", classNames?.title), children: labels.title }),
1670
+ /* @__PURE__ */ jsxs11("div", { className: cn("flex flex-wrap items-center gap-2", classNames?.filters), children: [
1671
+ /* @__PURE__ */ jsx16(
1584
1672
  "input",
1585
1673
  {
1586
1674
  type: "search",
@@ -1591,7 +1679,7 @@ function DocumentsLibrary({
1591
1679
  className: cn("w-full rounded-md border px-3 py-2 text-sm sm:w-64", classNames?.search)
1592
1680
  }
1593
1681
  ),
1594
- /* @__PURE__ */ jsxs10(
1682
+ /* @__PURE__ */ jsxs11(
1595
1683
  "select",
1596
1684
  {
1597
1685
  value: sourceFilter,
@@ -1599,25 +1687,25 @@ function DocumentsLibrary({
1599
1687
  "aria-label": labels.sourceFilterAll,
1600
1688
  className: cn("w-full rounded-md border px-2 py-2 text-sm sm:w-40", classNames?.sourceSelect),
1601
1689
  children: [
1602
- /* @__PURE__ */ jsx15("option", { value: DOCUMENT_SOURCE_FILTER.ALL, children: labels.sourceFilterAll }),
1603
- /* @__PURE__ */ jsx15("option", { value: DOCUMENT_SOURCE_FILTER.CUSTOMER, children: labels.sourceFilterCustomer }),
1604
- /* @__PURE__ */ jsx15("option", { value: DOCUMENT_SOURCE_FILTER.TEAM, children: labels.sourceFilterTeam })
1690
+ /* @__PURE__ */ jsx16("option", { value: DOCUMENT_SOURCE_FILTER.ALL, children: labels.sourceFilterAll }),
1691
+ /* @__PURE__ */ jsx16("option", { value: DOCUMENT_SOURCE_FILTER.CUSTOMER, children: labels.sourceFilterCustomer }),
1692
+ /* @__PURE__ */ jsx16("option", { value: DOCUMENT_SOURCE_FILTER.TEAM, children: labels.sourceFilterTeam })
1605
1693
  ]
1606
1694
  }
1607
1695
  ),
1608
- /* @__PURE__ */ jsxs10(
1696
+ /* @__PURE__ */ jsxs11(
1609
1697
  "button",
1610
1698
  {
1611
1699
  type: "button",
1612
1700
  onClick: () => applyFilter(() => setSortDirection(sortDirection === "desc" ? "asc" : "desc")),
1613
1701
  className: cn("cv-header-action inline-flex items-center gap-1", classNames?.sortButton),
1614
1702
  children: [
1615
- /* @__PURE__ */ jsx15(ArrowUpDown2, { size: 14 }),
1703
+ /* @__PURE__ */ jsx16(ArrowUpDown2, { size: 14 }),
1616
1704
  sortDirection === "desc" ? labels.sortMostRecent : labels.sortOldest
1617
1705
  ]
1618
1706
  }
1619
1707
  ),
1620
- hasFilters ? /* @__PURE__ */ jsx15(
1708
+ hasFilters ? /* @__PURE__ */ jsx16(
1621
1709
  "button",
1622
1710
  {
1623
1711
  type: "button",
@@ -1631,13 +1719,13 @@ function DocumentsLibrary({
1631
1719
  }
1632
1720
  ) : null
1633
1721
  ] }),
1634
- loading ? /* @__PURE__ */ jsx15("p", { className: cn("text-sm text-gray-500", classNames?.status), children: labels.loading }) : null,
1635
- failed ? /* @__PURE__ */ jsx15("p", { role: "alert", className: cn("text-sm text-red-600 dark:text-red-400", classNames?.status), children: labels.failure }) : null,
1636
- !loading && !failed && documents.length === 0 ? /* @__PURE__ */ jsx15("p", { className: cn("text-sm text-gray-500", classNames?.status), children: hasFilters ? labels.noResults : labels.empty }) : null,
1637
- /* @__PURE__ */ jsx15("ul", { className: cn("space-y-2", classNames?.list), children: documents.map((document2) => {
1722
+ loading ? /* @__PURE__ */ jsx16("p", { className: cn("text-sm text-gray-500", classNames?.status), children: labels.loading }) : null,
1723
+ failed ? /* @__PURE__ */ jsx16("p", { role: "alert", className: cn("text-sm text-red-600 dark:text-red-400", classNames?.status), children: labels.failure }) : null,
1724
+ !loading && !failed && documents.length === 0 ? /* @__PURE__ */ jsx16("p", { className: cn("text-sm text-gray-500", classNames?.status), children: hasFilters ? labels.noResults : labels.empty }) : null,
1725
+ /* @__PURE__ */ jsx16("ul", { className: cn("space-y-2", classNames?.list), children: documents.map((document2) => {
1638
1726
  const isFromCustomer = !TEAM_SOURCES2.has(document2.source);
1639
1727
  const SourceIcon = isFromCustomer ? Users2 : Bot2;
1640
- return /* @__PURE__ */ jsxs10(
1728
+ return /* @__PURE__ */ jsxs11(
1641
1729
  "li",
1642
1730
  {
1643
1731
  className: cn(
@@ -1645,23 +1733,23 @@ function DocumentsLibrary({
1645
1733
  classNames?.item
1646
1734
  ),
1647
1735
  children: [
1648
- /* @__PURE__ */ jsxs10("div", { className: "flex min-w-0 flex-1 items-center gap-3", children: [
1649
- /* @__PURE__ */ jsx15(FileIcon, { filename: document2.filename, mimeType: document2.mimeType }),
1650
- /* @__PURE__ */ jsxs10("div", { className: "min-w-0 flex-1", children: [
1651
- /* @__PURE__ */ jsx15("div", { className: cn("truncate text-sm font-medium", classNames?.filename), title: document2.filename, children: document2.filename }),
1652
- /* @__PURE__ */ jsxs10("div", { className: cn("flex flex-wrap items-center gap-x-2 text-xs text-gray-500", classNames?.meta), children: [
1653
- /* @__PURE__ */ jsxs10("span", { className: "inline-flex items-center gap-1", children: [
1654
- /* @__PURE__ */ jsx15(SourceIcon, { size: 11 }),
1736
+ /* @__PURE__ */ jsxs11("div", { className: "flex min-w-0 flex-1 items-center gap-3", children: [
1737
+ /* @__PURE__ */ jsx16(FileIcon, { filename: document2.filename, mimeType: document2.mimeType }),
1738
+ /* @__PURE__ */ jsxs11("div", { className: "min-w-0 flex-1", children: [
1739
+ /* @__PURE__ */ jsx16("div", { className: cn("truncate text-sm font-medium", classNames?.filename), title: document2.filename, children: document2.filename }),
1740
+ /* @__PURE__ */ jsxs11("div", { className: cn("flex flex-wrap items-center gap-x-2 text-xs text-gray-500", classNames?.meta), children: [
1741
+ /* @__PURE__ */ jsxs11("span", { className: "inline-flex items-center gap-1", children: [
1742
+ /* @__PURE__ */ jsx16(SourceIcon, { size: 11 }),
1655
1743
  isFromCustomer ? labels.sourceFilterCustomer : labels.sourceFilterTeam
1656
1744
  ] }),
1657
- /* @__PURE__ */ jsx15("span", { children: "\xB7" }),
1658
- /* @__PURE__ */ jsx15("span", { children: formatDateTime(document2.linkedAt) }),
1659
- /* @__PURE__ */ jsx15("span", { children: "\xB7" }),
1660
- /* @__PURE__ */ jsx15("span", { children: formatFileSize(document2.sizeBytes) })
1745
+ /* @__PURE__ */ jsx16("span", { children: "\xB7" }),
1746
+ /* @__PURE__ */ jsx16("span", { children: formatDateTime(document2.linkedAt) }),
1747
+ /* @__PURE__ */ jsx16("span", { children: "\xB7" }),
1748
+ /* @__PURE__ */ jsx16("span", { children: formatFileSize(document2.sizeBytes) })
1661
1749
  ] })
1662
1750
  ] })
1663
1751
  ] }),
1664
- onOpenConversation ? /* @__PURE__ */ jsxs10(
1752
+ onOpenConversation ? /* @__PURE__ */ jsxs11(
1665
1753
  "button",
1666
1754
  {
1667
1755
  type: "button",
@@ -1669,13 +1757,13 @@ function DocumentsLibrary({
1669
1757
  title: labels.openConversation,
1670
1758
  className: cn("cv-header-action inline-flex shrink-0 items-center gap-1", classNames?.conversationLink),
1671
1759
  children: [
1672
- /* @__PURE__ */ jsx15(MessageSquare, { size: 12 }),
1760
+ /* @__PURE__ */ jsx16(MessageSquare, { size: 12 }),
1673
1761
  formatPhone(document2.conversationId)
1674
1762
  ]
1675
1763
  }
1676
- ) : /* @__PURE__ */ jsx15("span", { className: cn("shrink-0 text-xs text-gray-500", classNames?.conversationLink), children: formatPhone(document2.conversationId) }),
1677
- /* @__PURE__ */ jsxs10("div", { className: "flex shrink-0 gap-1", children: [
1678
- /* @__PURE__ */ jsx15(
1764
+ ) : /* @__PURE__ */ jsx16("span", { className: cn("shrink-0 text-xs text-gray-500", classNames?.conversationLink), children: formatPhone(document2.conversationId) }),
1765
+ /* @__PURE__ */ jsxs11("div", { className: "flex shrink-0 gap-1", children: [
1766
+ /* @__PURE__ */ jsx16(
1679
1767
  "button",
1680
1768
  {
1681
1769
  type: "button",
@@ -1683,10 +1771,10 @@ function DocumentsLibrary({
1683
1771
  title: labels.view,
1684
1772
  "aria-label": `${labels.view}: ${document2.filename}`,
1685
1773
  className: "cv-header-icon",
1686
- children: /* @__PURE__ */ jsx15(Eye2, { size: 14 })
1774
+ children: /* @__PURE__ */ jsx16(Eye2, { size: 14 })
1687
1775
  }
1688
1776
  ),
1689
- /* @__PURE__ */ jsx15(
1777
+ /* @__PURE__ */ jsx16(
1690
1778
  "button",
1691
1779
  {
1692
1780
  type: "button",
@@ -1694,7 +1782,7 @@ function DocumentsLibrary({
1694
1782
  title: labels.download,
1695
1783
  "aria-label": `${labels.download}: ${document2.filename}`,
1696
1784
  className: "cv-header-icon",
1697
- children: /* @__PURE__ */ jsx15(Download2, { size: 14 })
1785
+ children: /* @__PURE__ */ jsx16(Download2, { size: 14 })
1698
1786
  }
1699
1787
  )
1700
1788
  ] })
@@ -1703,10 +1791,10 @@ function DocumentsLibrary({
1703
1791
  `${document2.conversationId}:${document2.id}`
1704
1792
  );
1705
1793
  }) }),
1706
- total > perPage ? /* @__PURE__ */ jsxs10("div", { className: cn("flex items-center justify-between border-t pt-2 text-xs dark:border-gray-700", classNames?.pagination), children: [
1707
- /* @__PURE__ */ jsx15("span", { className: "text-gray-400", children: labels.total(total) }),
1708
- /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2", children: [
1709
- /* @__PURE__ */ jsx15(
1794
+ total > perPage ? /* @__PURE__ */ jsxs11("div", { className: cn("flex items-center justify-between border-t pt-2 text-xs dark:border-gray-700", classNames?.pagination), children: [
1795
+ /* @__PURE__ */ jsx16("span", { className: "text-gray-400", children: labels.total(total) }),
1796
+ /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2", children: [
1797
+ /* @__PURE__ */ jsx16(
1710
1798
  "button",
1711
1799
  {
1712
1800
  type: "button",
@@ -1716,8 +1804,8 @@ function DocumentsLibrary({
1716
1804
  children: "\u2039"
1717
1805
  }
1718
1806
  ),
1719
- /* @__PURE__ */ jsx15("span", { className: "text-gray-500", children: labels.page(page, lastPage) }),
1720
- /* @__PURE__ */ jsx15(
1807
+ /* @__PURE__ */ jsx16("span", { className: "text-gray-500", children: labels.page(page, lastPage) }),
1808
+ /* @__PURE__ */ jsx16(
1721
1809
  "button",
1722
1810
  {
1723
1811
  type: "button",
@@ -1762,6 +1850,9 @@ export {
1762
1850
  DEFAULT_MESSAGE_COMPOSER_LABELS,
1763
1851
  DEFAULT_ACCEPTED_FILE_TYPES,
1764
1852
  MessageComposer,
1853
+ DEFAULT_AUDIO_RECORDER_BUTTON_LABELS,
1854
+ DEFAULT_MAX_RECORDING_MILLISECONDS,
1855
+ AudioRecorderButton,
1765
1856
  DateDivider,
1766
1857
  formatPhone,
1767
1858
  phoneCountryFlag,
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as react from 'react';
2
2
  import react__default, { ReactNode, CSSProperties, FormEvent } from 'react';
3
- import { y as MessagePayload, A as ResolveMediaUrl, v as InteractiveSelection, t as InteractivePayload, p as ConversationsFeatures, m as ConversationSummary, h as ConversationChannel, L as ListConversationsParams, o as ConversationsApi, S as SSEProvider, w as ListDocumentsParams, i as ConversationDocument, n as ConversationTemplate } from './types-B5C1DLu1.js';
4
- export { C as CHANNEL_CAPABILITIES, a as CHANNEL_FILTER_ALL, b as CONVERSATION_CHANNEL, c as ChannelCapabilities, d as ChannelFilter, e as ChannelFilterOption, f as CompanyDocument, g as CompanyDocumentPage, j as ConversationDocumentPage, k as ConversationEventSource, l as ConversationPage, q as ConversationsTheme, r as ConversationsUIConfig, D as DEFAULT_CONVERSATION_CHANNEL, F as FormatContactHandleParams, H as HANDLE_KIND, s as HandleKind, I as InteractiveOption, u as InteractiveSection, M as MediaRenderer, x as MediaRendererProps, R as REOPEN_MECHANISM, z as ReopenMechanism, B as capabilitiesOf, E as channelFiltersFor, G as contactFlag, J as formatContactHandle } from './types-B5C1DLu1.js';
3
+ import { G as MessagePayload, K as ResolveMediaUrl, z as InteractiveSelection, x as InteractivePayload, r as ConversationsFeatures, o as ConversationSummary, j as ConversationChannel, L as ListConversationsParams, q as ConversationsApi, S as SSEProvider, B as ListDocumentsParams, k as ConversationDocument, p as ConversationTemplate } from './types-C_dqJ83O.js';
4
+ export { A as AudioRecorderButton, a as AudioRecorderButtonLabels, b as AudioRecorderButtonProps, C as CHANNEL_CAPABILITIES, c as CHANNEL_FILTER_ALL, d as CONVERSATION_CHANNEL, e as ChannelCapabilities, f as ChannelFilter, g as ChannelFilterOption, h as CompanyDocument, i as CompanyDocumentPage, l as ConversationDocumentPage, m as ConversationEventSource, n as ConversationPage, s as ConversationsTheme, t as ConversationsUIConfig, D as DEFAULT_AUDIO_RECORDER_BUTTON_LABELS, u as DEFAULT_CONVERSATION_CHANNEL, v as DEFAULT_MAX_RECORDING_MILLISECONDS, F as FormatContactHandleParams, H as HANDLE_KIND, w as HandleKind, I as InteractiveOption, y as InteractiveSection, M as MediaRenderer, E as MediaRendererProps, R as REOPEN_MECHANISM, J as ReopenMechanism, N as capabilitiesOf, O as channelFiltersFor, P as contactFlag, Q as formatContactHandle } from './types-C_dqJ83O.js';
5
5
 
6
6
  interface MessageBubbleProps {
7
7
  message: MessagePayload;
package/dist/index.js CHANGED
@@ -1,15 +1,18 @@
1
1
  import {
2
2
  AudioPlayer,
3
+ AudioRecorderButton,
3
4
  ConversationDocumentsPanel,
4
5
  ConversationLocalesProvider,
5
6
  ConversationWallpaper,
6
7
  ConversationsProvider,
7
8
  DEFAULT_ACCEPTED_FILE_TYPES,
9
+ DEFAULT_AUDIO_RECORDER_BUTTON_LABELS,
8
10
  DEFAULT_CONVERSATION_DOCUMENTS_LABELS,
9
11
  DEFAULT_DOCUMENTS_LIBRARY_LABELS,
10
12
  DEFAULT_EMOJI_PICKER_LABELS,
11
13
  DEFAULT_INTERACTIVE_MESSAGE_LABELS,
12
14
  DEFAULT_LIGHTBOX_LABELS,
15
+ DEFAULT_MAX_RECORDING_MILLISECONDS,
13
16
  DEFAULT_MESSAGE_COMPOSER_LABELS,
14
17
  DOCUMENT_SOURCE_FILTER,
15
18
  DateDivider,
@@ -41,7 +44,7 @@ import {
41
44
  useConversationDocuments,
42
45
  useConversationLocales,
43
46
  useConversations
44
- } from "./chunk-3RKFU46R.js";
47
+ } from "./chunk-QFEESERN.js";
45
48
  import {
46
49
  htmlToWA,
47
50
  parseWhatsAppFormatting,
@@ -2271,6 +2274,7 @@ function useInboxActions() {
2271
2274
  }
2272
2275
  export {
2273
2276
  AudioPlayer,
2277
+ AudioRecorderButton,
2274
2278
  Avatar,
2275
2279
  CHANNEL_BRAND_COLOR,
2276
2280
  CHANNEL_CAPABILITIES,
@@ -2287,6 +2291,7 @@ export {
2287
2291
  ConversationWallpaper,
2288
2292
  ConversationsProvider,
2289
2293
  DEFAULT_ACCEPTED_FILE_TYPES,
2294
+ DEFAULT_AUDIO_RECORDER_BUTTON_LABELS,
2290
2295
  DEFAULT_AVATAR_LABELS,
2291
2296
  DEFAULT_CONVERSATION_CHANNEL,
2292
2297
  DEFAULT_CONVERSATION_CONTEXT_LABELS,
@@ -2297,6 +2302,7 @@ export {
2297
2302
  DEFAULT_EMOJI_PICKER_LABELS,
2298
2303
  DEFAULT_INTERACTIVE_MESSAGE_LABELS,
2299
2304
  DEFAULT_LIGHTBOX_LABELS,
2305
+ DEFAULT_MAX_RECORDING_MILLISECONDS,
2300
2306
  DEFAULT_MESSAGE_COMPOSER_LABELS,
2301
2307
  DEFAULT_RICH_COMPOSER_TOOLTIPS,
2302
2308
  DEFAULT_TEMPLATES_SETTINGS_LABELS,
@@ -1,4 +1,5 @@
1
- import { y as MessagePayload, m as ConversationSummary, k as ConversationEventSource, o as ConversationsApi, L as ListConversationsParams, l as ConversationPage, S as SSEProvider, i as ConversationDocument, A as ResolveMediaUrl } from '../types-B5C1DLu1.js';
1
+ import { G as MessagePayload, o as ConversationSummary, m as ConversationEventSource, q as ConversationsApi, L as ListConversationsParams, n as ConversationPage, S as SSEProvider, k as ConversationDocument, K as ResolveMediaUrl } from '../types-C_dqJ83O.js';
2
+ export { A as AudioRecorderButton, a as AudioRecorderButtonLabels, b as AudioRecorderButtonProps, D as DEFAULT_AUDIO_RECORDER_BUTTON_LABELS } from '../types-C_dqJ83O.js';
2
3
  import * as react from 'react';
3
4
  import { InteractiveReplyOption, InboundMediaType } from '@adatechnology/meta-whatsapp-contracts/testing';
4
5
 
@@ -205,41 +206,6 @@ type PreviewUploadedMedia = {
205
206
  declare function mediaTypeOf(mimeType: string): SendPreviewMediaParams['mediaType'];
206
207
  declare function ConversationPreview({ client, sse, conversationId, loadMessages, placeholder, pollIntervalMs, uploadMedia, }: ConversationPreviewProps): react.JSX.Element;
207
208
 
208
- /**
209
- * Gravação de áudio no simulador, pelo microfone do próprio navegador.
210
- *
211
- * Existe porque áudio é o formato que mais chega de cliente real e o que mais quebra fluxo: sem
212
- * poder gravar aqui, testar o caminho de transcrição exigia mandar mensagem do celular de alguém.
213
- *
214
- * O arquivo gravado sai daqui como `File` e segue exatamente o mesmo caminho de um anexo — quem
215
- * hospeda e devolve o `mediaId` é o host, via `uploadMedia`.
216
- */
217
- interface AudioRecorderButtonLabels {
218
- start: string;
219
- stop: string;
220
- unsupported: string;
221
- denied: string;
222
- }
223
- declare const DEFAULT_AUDIO_RECORDER_BUTTON_LABELS: AudioRecorderButtonLabels;
224
- interface AudioRecorderButtonProps {
225
- onRecorded: (file: File) => void | Promise<void>;
226
- onFailure?: (message: string) => void;
227
- /**
228
- * Avisa quando a gravação começa e termina. O botão é um interruptor — o segundo toque é que
229
- * envia — e sem um aviso fora dele o operador grava, não vê nada acontecer e desiste achando
230
- * que o microfone está quebrado.
231
- */
232
- onRecordingChange?: (isRecording: boolean) => void;
233
- /**
234
- * Teto de duração da gravação, em milissegundos. Passado o tempo, o gravador para e envia o que
235
- * tem. Produto com limite próprio sobrescreve.
236
- */
237
- maxDurationMilliseconds?: number;
238
- labels?: Partial<AudioRecorderButtonLabels>;
239
- disabled?: boolean;
240
- }
241
- declare function AudioRecorderButton({ onRecorded, onFailure, onRecordingChange, maxDurationMilliseconds, labels, disabled, }: AudioRecorderButtonProps): react.JSX.Element;
242
-
243
209
  /**
244
210
  * Roteiro que mantém o preview vivo: sem tráfego chegando, a inbox é uma tela estática e as
245
211
  * transições que o atendente precisa testar (fila de espera enchendo, handoff, devolução ao bot)
@@ -338,4 +304,4 @@ type MediaTypesPreviewProps = {
338
304
  };
339
305
  declare function MediaTypesPreview({ conversationId, className, }: MediaTypesPreviewProps): react.JSX.Element;
340
306
 
341
- export { type AppendMessageParams, AudioRecorderButton, type AudioRecorderButtonLabels, type AudioRecorderButtonProps, ConversationPreview, type ConversationPreviewProps, type CreateMockConversationsApiParams, type CreateMockSSEProviderParams, type CreatePreviewStoreParams, type CreatePreviewWebhookClientParams, DEFAULT_AUDIO_RECORDER_BUTTON_LABELS, DEFAULT_PREVIEW_SCRIPT, GLOBAL_CHANNEL, type ListConversationsFilters, MEDIA_TYPES_CONVERSATION_ID, MediaTypesPreview, type MediaTypesPreviewProps, type MockEventSource, PREVIEW_CONVERSATIONS, PREVIEW_DOCUMENTS, PREVIEW_FILE_SAMPLES, PREVIEW_MESSAGES, type PreviewEmission, PreviewInProductionError, type PreviewScriptStep, type PreviewStore, type PreviewStoreListener, type PreviewUploadedMedia, type PreviewWebhookClient, PreviewWebhookRejectedError, type SendPreviewMediaParams, type SetModeParams, type StartPreviewScriptParams, assertPreviewEnvironment, conversationChannel, createMockConversationsApi, createMockEventSource, createMockSSEProvider, createPreviewMediaResolver, createPreviewStore, createPreviewWebhookClient, mediaTypeOf, previewFileBase64, previewFileUrl, resolvePreviewFileSample, signPreviewPayload, startPreviewScript };
307
+ export { type AppendMessageParams, ConversationPreview, type ConversationPreviewProps, type CreateMockConversationsApiParams, type CreateMockSSEProviderParams, type CreatePreviewStoreParams, type CreatePreviewWebhookClientParams, DEFAULT_PREVIEW_SCRIPT, GLOBAL_CHANNEL, type ListConversationsFilters, MEDIA_TYPES_CONVERSATION_ID, MediaTypesPreview, type MediaTypesPreviewProps, type MockEventSource, PREVIEW_CONVERSATIONS, PREVIEW_DOCUMENTS, PREVIEW_FILE_SAMPLES, PREVIEW_MESSAGES, type PreviewEmission, PreviewInProductionError, type PreviewScriptStep, type PreviewStore, type PreviewStoreListener, type PreviewUploadedMedia, type PreviewWebhookClient, PreviewWebhookRejectedError, type SendPreviewMediaParams, type SetModeParams, type StartPreviewScriptParams, assertPreviewEnvironment, conversationChannel, createMockConversationsApi, createMockEventSource, createMockSSEProvider, createPreviewMediaResolver, createPreviewStore, createPreviewWebhookClient, mediaTypeOf, previewFileBase64, previewFileUrl, resolvePreviewFileSample, signPreviewPayload, startPreviewScript };
@@ -1,12 +1,14 @@
1
1
  import {
2
+ AudioRecorderButton,
2
3
  ConversationDocumentsPanel,
3
4
  ConversationWallpaper,
4
5
  ConversationsProvider,
6
+ DEFAULT_AUDIO_RECORDER_BUTTON_LABELS,
5
7
  DateDivider,
6
8
  DocumentsLibrary,
7
9
  MessageBubble,
8
10
  MessageComposer
9
- } from "../chunk-3RKFU46R.js";
11
+ } from "../chunk-QFEESERN.js";
10
12
  import "../chunk-2AYDBWNE.js";
11
13
 
12
14
  // src/preview/previewStore.ts
@@ -845,98 +847,8 @@ function createMockSSEProvider(params) {
845
847
  }
846
848
 
847
849
  // src/preview/ConversationPreview.tsx
848
- import { useCallback as useCallback2, useEffect, useMemo, useRef as useRef2, useState as useState2 } from "react";
849
-
850
- // src/preview/AudioRecorderButton.tsx
851
- import { useCallback, useRef, useState } from "react";
850
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
852
851
  import { jsx, jsxs } from "react/jsx-runtime";
853
- var DEFAULT_AUDIO_RECORDER_BUTTON_LABELS = {
854
- start: "Gravar \xE1udio",
855
- stop: "Parar grava\xE7\xE3o",
856
- unsupported: "Este navegador n\xE3o grava \xE1udio.",
857
- denied: "Sem permiss\xE3o para usar o microfone."
858
- };
859
- var DEFAULT_MAX_RECORDING_MILLISECONDS = 5 * 60 * 1e3;
860
- var RECORDING_FORMATS = [
861
- { mimeType: "audio/ogg;codecs=opus", uploadMimeType: "audio/ogg", extension: "ogg" },
862
- { mimeType: "audio/mp4", uploadMimeType: "audio/mp4", extension: "m4a" },
863
- { mimeType: "audio/webm", uploadMimeType: "audio/webm", extension: "webm" }
864
- ];
865
- function resolveRecordingFormat() {
866
- if (typeof MediaRecorder === "undefined") return void 0;
867
- if (typeof MediaRecorder.isTypeSupported !== "function") return RECORDING_FORMATS[0];
868
- return RECORDING_FORMATS.find((format) => MediaRecorder.isTypeSupported(format.mimeType));
869
- }
870
- function AudioRecorderButton({
871
- onRecorded,
872
- onFailure,
873
- onRecordingChange,
874
- maxDurationMilliseconds = DEFAULT_MAX_RECORDING_MILLISECONDS,
875
- labels,
876
- disabled
877
- }) {
878
- const startLabel = labels?.start ?? DEFAULT_AUDIO_RECORDER_BUTTON_LABELS.start;
879
- const stopLabel = labels?.stop ?? DEFAULT_AUDIO_RECORDER_BUTTON_LABELS.stop;
880
- const [isRecording, setIsRecording] = useState(false);
881
- const recorderRef = useRef(null);
882
- const autoStopRef = useRef(void 0);
883
- const stop = useCallback(() => {
884
- recorderRef.current?.stop();
885
- }, []);
886
- const start = useCallback(async () => {
887
- const format = resolveRecordingFormat();
888
- if (!format || !navigator.mediaDevices?.getUserMedia) {
889
- onFailure?.(labels?.unsupported ?? DEFAULT_AUDIO_RECORDER_BUTTON_LABELS.unsupported);
890
- return;
891
- }
892
- try {
893
- const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
894
- const recorder = new MediaRecorder(stream, { mimeType: format.mimeType });
895
- const chunks = [];
896
- recorder.addEventListener("dataavailable", (event) => {
897
- if (event.data.size > 0) chunks.push(event.data);
898
- });
899
- recorder.addEventListener("stop", () => {
900
- stream.getTracks().forEach((track) => track.stop());
901
- clearTimeout(autoStopRef.current);
902
- setIsRecording(false);
903
- onRecordingChange?.(false);
904
- recorderRef.current = null;
905
- const blob = new Blob(chunks, { type: format.uploadMimeType });
906
- void onRecorded(
907
- new File([blob], `audio-${Date.now()}.${format.extension}`, { type: format.uploadMimeType })
908
- );
909
- });
910
- recorderRef.current = recorder;
911
- recorder.start();
912
- autoStopRef.current = setTimeout(() => recorder.stop(), maxDurationMilliseconds);
913
- setIsRecording(true);
914
- onRecordingChange?.(true);
915
- } catch {
916
- onFailure?.(labels?.denied ?? DEFAULT_AUDIO_RECORDER_BUTTON_LABELS.denied);
917
- }
918
- }, [labels?.denied, labels?.unsupported, maxDurationMilliseconds, onFailure, onRecorded, onRecordingChange]);
919
- return /* @__PURE__ */ jsx(
920
- "button",
921
- {
922
- type: "button",
923
- disabled,
924
- onClick: () => isRecording ? stop() : void start(),
925
- title: isRecording ? stopLabel : startLabel,
926
- "aria-label": isRecording ? stopLabel : startLabel,
927
- "aria-pressed": isRecording,
928
- className: `flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-full transition-colors ${isRecording ? "animate-pulse bg-red-500 text-white ring-4 ring-red-500/30 hover:bg-red-600" : "text-gray-500 hover:bg-gray-200 dark:hover:bg-gray-700"}`,
929
- children: isRecording ? /* @__PURE__ */ jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx("rect", { x: "6", y: "6", width: "12", height: "12", rx: "2" }) }) : /* @__PURE__ */ jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", children: [
930
- /* @__PURE__ */ jsx("path", { d: "M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3z" }),
931
- /* @__PURE__ */ jsx("path", { d: "M19 11a7 7 0 0 1-14 0" }),
932
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "18", x2: "12", y2: "22" })
933
- ] })
934
- }
935
- );
936
- }
937
-
938
- // src/preview/ConversationPreview.tsx
939
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
940
852
  function mediaTypeOf(mimeType) {
941
853
  if (mimeType.startsWith("image/")) return "image";
942
854
  if (mimeType.startsWith("video/")) return "video";
@@ -983,15 +895,15 @@ function ConversationPreview({
983
895
  pollIntervalMs,
984
896
  uploadMedia
985
897
  }) {
986
- const [messages, setMessages] = useState2([]);
987
- const [failure, setFailure] = useState2(void 0);
988
- const [loadFailure, setLoadFailure] = useState2(void 0);
989
- const [isRecording, setIsRecording] = useState2(false);
990
- const [pendingLocal, setPendingLocal] = useState2([]);
991
- const loadMessagesRef = useRef2(loadMessages);
992
- const bottomRef = useRef2(null);
898
+ const [messages, setMessages] = useState([]);
899
+ const [failure, setFailure] = useState(void 0);
900
+ const [loadFailure, setLoadFailure] = useState(void 0);
901
+ const [isRecording, setIsRecording] = useState(false);
902
+ const [pendingLocal, setPendingLocal] = useState([]);
903
+ const loadMessagesRef = useRef(loadMessages);
904
+ const bottomRef = useRef(null);
993
905
  loadMessagesRef.current = loadMessages;
994
- const refresh = useCallback2(async () => {
906
+ const refresh = useCallback(async () => {
995
907
  try {
996
908
  const loaded = await loadMessagesRef.current(conversationId);
997
909
  setMessages(loaded);
@@ -1084,11 +996,11 @@ function ConversationPreview({
1084
996
  setFailure(error instanceof Error ? error.message : "Falha ao enviar o arquivo.");
1085
997
  }
1086
998
  }
1087
- return /* @__PURE__ */ jsxs2("div", { className: "flex h-full min-h-0 flex-col", children: [
1088
- /* @__PURE__ */ jsxs2(ConversationWallpaper, { className: "flex-1 min-h-0 overflow-y-auto px-4 py-3", children: [
1089
- rendered.map(({ message, isFirstInGroup, showDateDivider }) => /* @__PURE__ */ jsxs2("div", { children: [
1090
- showDateDivider ? /* @__PURE__ */ jsx2(DateDivider, { iso: message.timestamp }) : null,
1091
- /* @__PURE__ */ jsx2(
999
+ return /* @__PURE__ */ jsxs("div", { className: "flex h-full min-h-0 flex-col", children: [
1000
+ /* @__PURE__ */ jsxs(ConversationWallpaper, { className: "flex-1 min-h-0 overflow-y-auto px-4 py-3", children: [
1001
+ rendered.map(({ message, isFirstInGroup, showDateDivider }) => /* @__PURE__ */ jsxs("div", { children: [
1002
+ showDateDivider ? /* @__PURE__ */ jsx(DateDivider, { iso: message.timestamp }) : null,
1003
+ /* @__PURE__ */ jsx(
1092
1004
  MessageBubble,
1093
1005
  {
1094
1006
  message,
@@ -1098,17 +1010,17 @@ function ConversationPreview({
1098
1010
  }
1099
1011
  )
1100
1012
  ] }, message.id)),
1101
- /* @__PURE__ */ jsx2("div", { ref: bottomRef })
1013
+ /* @__PURE__ */ jsx("div", { ref: bottomRef })
1102
1014
  ] }),
1103
- failure ? /* @__PURE__ */ jsx2("p", { role: "alert", className: "px-4 py-2 text-sm text-red-600 dark:text-red-400", children: failure }) : null,
1104
- loadFailure ? /* @__PURE__ */ jsx2("p", { role: "status", className: "px-4 py-2 text-sm text-amber-700 dark:text-amber-400", children: loadFailure }) : null,
1105
- /* @__PURE__ */ jsx2(
1015
+ failure ? /* @__PURE__ */ jsx("p", { role: "alert", className: "px-4 py-2 text-sm text-red-600 dark:text-red-400", children: failure }) : null,
1016
+ loadFailure ? /* @__PURE__ */ jsx("p", { role: "status", className: "px-4 py-2 text-sm text-amber-700 dark:text-amber-400", children: loadFailure }) : null,
1017
+ /* @__PURE__ */ jsx(
1106
1018
  MessageComposer,
1107
1019
  {
1108
1020
  onSend: (text) => void handleSend(text),
1109
1021
  onAttach: uploadMedia ? (file) => void handleAttach(file) : void 0,
1110
1022
  placeholder: isRecording ? "Gravando\u2026 toque no quadrado para enviar" : placeholder ?? "Escreva como o cliente\u2026",
1111
- idleAction: uploadMedia ? /* @__PURE__ */ jsx2(
1023
+ idleAction: uploadMedia ? /* @__PURE__ */ jsx(
1112
1024
  AudioRecorderButton,
1113
1025
  {
1114
1026
  onRecorded: (file) => void handleAttach(file),
@@ -1218,7 +1130,7 @@ function startPreviewScript(params) {
1218
1130
 
1219
1131
  // src/preview/MediaTypesPreview.tsx
1220
1132
  import { useMemo as useMemo2 } from "react";
1221
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1133
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
1222
1134
  var MEDIA_TYPES_CONVERSATION_ID = "5511944443333";
1223
1135
  function MediaTypesPreview({
1224
1136
  conversationId = MEDIA_TYPES_CONVERSATION_ID,
@@ -1233,26 +1145,26 @@ function MediaTypesPreview({
1233
1145
  const messages = PREVIEW_MESSAGES[conversationId] ?? [];
1234
1146
  const documents = PREVIEW_DOCUMENTS[conversationId] ?? [];
1235
1147
  const mimeTypes = [...new Set(documents.map((document) => document.mimeType))];
1236
- return /* @__PURE__ */ jsx3(ConversationsProvider, { api, sse, children: /* @__PURE__ */ jsxs3("div", { className, children: [
1237
- /* @__PURE__ */ jsxs3("header", { className: "border-b px-4 py-3 dark:border-gray-700", children: [
1238
- /* @__PURE__ */ jsx3("h1", { className: "text-lg font-semibold", children: "Teste manual de m\xEDdia" }),
1239
- /* @__PURE__ */ jsxs3("p", { className: "text-sm text-gray-500", children: [
1148
+ return /* @__PURE__ */ jsx2(ConversationsProvider, { api, sse, children: /* @__PURE__ */ jsxs2("div", { className, children: [
1149
+ /* @__PURE__ */ jsxs2("header", { className: "border-b px-4 py-3 dark:border-gray-700", children: [
1150
+ /* @__PURE__ */ jsx2("h1", { className: "text-lg font-semibold", children: "Teste manual de m\xEDdia" }),
1151
+ /* @__PURE__ */ jsxs2("p", { className: "text-sm text-gray-500", children: [
1240
1152
  documents.length,
1241
1153
  " arquivos, ",
1242
1154
  mimeTypes.length,
1243
1155
  " tipos. Clique no olho para abrir em aba nova e no bot\xE3o da bolha para carregar a m\xEDdia na thread \u2014 \xE9 o que teste automatizado n\xE3o v\xEA."
1244
1156
  ] })
1245
1157
  ] }),
1246
- /* @__PURE__ */ jsxs3("div", { className: "grid gap-4 p-4 lg:grid-cols-2", children: [
1247
- /* @__PURE__ */ jsxs3("section", { className: "space-y-3", children: [
1248
- /* @__PURE__ */ jsx3("h2", { className: "text-sm font-semibold uppercase tracking-wide text-gray-500", children: "Biblioteca da empresa" }),
1249
- /* @__PURE__ */ jsx3(DocumentsLibrary, { perPage: documents.length || 20 })
1158
+ /* @__PURE__ */ jsxs2("div", { className: "grid gap-4 p-4 lg:grid-cols-2", children: [
1159
+ /* @__PURE__ */ jsxs2("section", { className: "space-y-3", children: [
1160
+ /* @__PURE__ */ jsx2("h2", { className: "text-sm font-semibold uppercase tracking-wide text-gray-500", children: "Biblioteca da empresa" }),
1161
+ /* @__PURE__ */ jsx2(DocumentsLibrary, { perPage: documents.length || 20 })
1250
1162
  ] }),
1251
- /* @__PURE__ */ jsxs3("section", { className: "space-y-3", children: [
1252
- /* @__PURE__ */ jsx3("h2", { className: "text-sm font-semibold uppercase tracking-wide text-gray-500", children: "Painel da conversa" }),
1253
- /* @__PURE__ */ jsx3(ConversationDocumentsPanel, { conversationId, open: true, perPage: documents.length || 20 }),
1254
- /* @__PURE__ */ jsx3("h2", { className: "text-sm font-semibold uppercase tracking-wide text-gray-500", children: "Bolhas na thread" }),
1255
- /* @__PURE__ */ jsx3(ConversationWallpaper, { className: "max-h-[70vh] overflow-y-auto rounded-lg px-3 py-2", children: messages.map((message, index) => /* @__PURE__ */ jsx3(
1163
+ /* @__PURE__ */ jsxs2("section", { className: "space-y-3", children: [
1164
+ /* @__PURE__ */ jsx2("h2", { className: "text-sm font-semibold uppercase tracking-wide text-gray-500", children: "Painel da conversa" }),
1165
+ /* @__PURE__ */ jsx2(ConversationDocumentsPanel, { conversationId, open: true, perPage: documents.length || 20 }),
1166
+ /* @__PURE__ */ jsx2("h2", { className: "text-sm font-semibold uppercase tracking-wide text-gray-500", children: "Bolhas na thread" }),
1167
+ /* @__PURE__ */ jsx2(ConversationWallpaper, { className: "max-h-[70vh] overflow-y-auto rounded-lg px-3 py-2", children: messages.map((message, index) => /* @__PURE__ */ jsx2(
1256
1168
  MessageBubble,
1257
1169
  {
1258
1170
  message,
@@ -104,6 +104,47 @@ interface MediaRendererProps {
104
104
  }
105
105
  declare function MediaRenderer({ message, onLightbox, onResolveUrl, className }: MediaRendererProps): react.JSX.Element | null;
106
106
 
107
+ /**
108
+ * Gravação de áudio no simulador, pelo microfone do próprio navegador.
109
+ *
110
+ * Existe porque áudio é o formato que mais chega de cliente real e o que mais quebra fluxo: sem
111
+ * poder gravar aqui, testar o caminho de transcrição exigia mandar mensagem do celular de alguém.
112
+ *
113
+ * O arquivo gravado sai daqui como `File` e segue exatamente o mesmo caminho de um anexo — quem
114
+ * hospeda e devolve o `mediaId` é o host, via `uploadMedia`.
115
+ */
116
+ interface AudioRecorderButtonLabels {
117
+ start: string;
118
+ stop: string;
119
+ unsupported: string;
120
+ denied: string;
121
+ }
122
+ declare const DEFAULT_AUDIO_RECORDER_BUTTON_LABELS: AudioRecorderButtonLabels;
123
+ interface AudioRecorderButtonProps {
124
+ onRecorded: (file: File) => void | Promise<void>;
125
+ onFailure?: (message: string) => void;
126
+ /**
127
+ * Avisa quando a gravação começa e termina. O botão é um interruptor — o segundo toque é que
128
+ * envia — e sem um aviso fora dele o operador grava, não vê nada acontecer e desiste achando
129
+ * que o microfone está quebrado.
130
+ */
131
+ onRecordingChange?: (isRecording: boolean) => void;
132
+ /**
133
+ * Teto de duração da gravação, em milissegundos. Passado o tempo, o gravador para e envia o que
134
+ * tem. Produto com limite próprio sobrescreve.
135
+ */
136
+ maxDurationMilliseconds?: number;
137
+ labels?: Partial<AudioRecorderButtonLabels>;
138
+ disabled?: boolean;
139
+ }
140
+ /**
141
+ * Cinco minutos: com o codec de voz do WhatsApp isso dá menos de 3MB, folgado dentro do teto de
142
+ * 16MB que a Meta impõe a áudio, e é mais do que qualquer recado de cliente. O corte automático
143
+ * existe porque gravação esquecida aberta só se descobre no envio, com o arquivo inteiro perdido.
144
+ */
145
+ declare const DEFAULT_MAX_RECORDING_MILLISECONDS: number;
146
+ declare function AudioRecorderButton({ onRecorded, onFailure, onRecordingChange, maxDurationMilliseconds, labels, disabled, }: AudioRecorderButtonProps): react.JSX.Element;
147
+
107
148
  /**
108
149
  * Canal de origem da conversa e o que cada um permite.
109
150
  *
@@ -362,4 +403,4 @@ interface ConversationDocument {
362
403
  linkedAt: string;
363
404
  }
364
405
 
365
- export { type ResolveMediaUrl as A, capabilitiesOf as B, CHANNEL_CAPABILITIES as C, DEFAULT_CONVERSATION_CHANNEL as D, channelFiltersFor as E, type FormatContactHandleParams as F, contactFlag as G, HANDLE_KIND as H, type InteractiveOption as I, formatContactHandle as J, type ListConversationsParams as L, MediaRenderer as M, REOPEN_MECHANISM as R, type SSEProvider as S, CHANNEL_FILTER_ALL as a, CONVERSATION_CHANNEL as b, type ChannelCapabilities as c, type ChannelFilter as d, type ChannelFilterOption as e, type CompanyDocument as f, type CompanyDocumentPage as g, type ConversationChannel as h, type ConversationDocument as i, type ConversationDocumentPage as j, type ConversationEventSource as k, type ConversationPage as l, type ConversationSummary as m, type ConversationTemplate as n, type ConversationsApi as o, type ConversationsFeatures as p, type ConversationsTheme as q, type ConversationsUIConfig as r, type HandleKind as s, type InteractivePayload as t, type InteractiveSection as u, type InteractiveSelection as v, type ListDocumentsParams as w, type MediaRendererProps as x, type MessagePayload as y, type ReopenMechanism as z };
406
+ export { AudioRecorderButton as A, type ListDocumentsParams as B, CHANNEL_CAPABILITIES as C, DEFAULT_AUDIO_RECORDER_BUTTON_LABELS as D, type MediaRendererProps as E, type FormatContactHandleParams as F, type MessagePayload as G, HANDLE_KIND as H, type InteractiveOption as I, type ReopenMechanism as J, type ResolveMediaUrl as K, type ListConversationsParams as L, MediaRenderer as M, capabilitiesOf as N, channelFiltersFor as O, contactFlag as P, formatContactHandle as Q, REOPEN_MECHANISM as R, type SSEProvider as S, type AudioRecorderButtonLabels as a, type AudioRecorderButtonProps as b, CHANNEL_FILTER_ALL as c, CONVERSATION_CHANNEL as d, type ChannelCapabilities as e, type ChannelFilter as f, type ChannelFilterOption as g, type CompanyDocument as h, type CompanyDocumentPage as i, type ConversationChannel as j, type ConversationDocument as k, type ConversationDocumentPage as l, type ConversationEventSource as m, type ConversationPage as n, type ConversationSummary as o, type ConversationTemplate as p, type ConversationsApi as q, type ConversationsFeatures as r, type ConversationsTheme as s, type ConversationsUIConfig as t, DEFAULT_CONVERSATION_CHANNEL as u, DEFAULT_MAX_RECORDING_MILLISECONDS as v, type HandleKind as w, type InteractivePayload as x, type InteractiveSection as y, type InteractiveSelection as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adatechnology/conversations-ui",
3
- "version": "0.1.0-rc.12",
3
+ "version": "0.1.0-rc.13",
4
4
  "description": "WhatsApp conversation UI components — parametrizável por endpoint, tema e feature flags",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -1,7 +1,7 @@
1
1
  import { afterEach, describe, expect, it } from 'bun:test'
2
2
 
3
3
  import { resolveRecordingFormat } from './AudioRecorderButton'
4
- import { DEFAULT_ACCEPTED_FILE_TYPES } from '../MessageComposer'
4
+ import { DEFAULT_ACCEPTED_FILE_TYPES } from './MessageComposer'
5
5
 
6
6
  const originalMediaRecorder = (globalThis as Record<string, unknown>).MediaRecorder
7
7
 
package/src/index.ts CHANGED
@@ -15,6 +15,12 @@ export type {
15
15
  RichComposerVariable,
16
16
  RichMessageComposerHandle,
17
17
  } from './RichMessageComposer'
18
+ export {
19
+ AudioRecorderButton,
20
+ DEFAULT_AUDIO_RECORDER_BUTTON_LABELS,
21
+ DEFAULT_MAX_RECORDING_MILLISECONDS,
22
+ } from './AudioRecorderButton'
23
+ export type { AudioRecorderButtonProps, AudioRecorderButtonLabels } from './AudioRecorderButton'
18
24
  export { WhatsAppMessageEditor, DEFAULT_WHATSAPP_MESSAGE_EDITOR_LABELS } from './WhatsAppMessageEditor'
19
25
  export { SimpleEmojiPicker } from './SimpleEmojiPicker'
20
26
  export { DateDivider } from './DateDivider'
@@ -20,7 +20,7 @@ import { MessageComposer } from '../MessageComposer'
20
20
  import { DateDivider } from '../DateDivider'
21
21
  import { ConversationWallpaper } from '../Wallpaper'
22
22
  import type { PreviewWebhookClient, SendPreviewMediaParams } from './createPreviewWebhookClient'
23
- import { AudioRecorderButton } from './AudioRecorderButton'
23
+ import { AudioRecorderButton } from '../AudioRecorderButton'
24
24
 
25
25
  export type ConversationPreviewProps = {
26
26
  client: PreviewWebhookClient
@@ -29,8 +29,8 @@ export { ConversationPreview } from './ConversationPreview'
29
29
  export { mediaTypeOf } from './ConversationPreview'
30
30
  export type { ConversationPreviewProps, PreviewUploadedMedia } from './ConversationPreview'
31
31
 
32
- export { AudioRecorderButton, DEFAULT_AUDIO_RECORDER_BUTTON_LABELS } from './AudioRecorderButton'
33
- export type { AudioRecorderButtonProps, AudioRecorderButtonLabels } from './AudioRecorderButton'
32
+ export { AudioRecorderButton, DEFAULT_AUDIO_RECORDER_BUTTON_LABELS } from '../AudioRecorderButton'
33
+ export type { AudioRecorderButtonProps, AudioRecorderButtonLabels } from '../AudioRecorderButton'
34
34
 
35
35
  export {
36
36
  createPreviewWebhookClient,