@adatechnology/conversations-ui 0.5.0 → 0.6.1

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 (52) hide show
  1. package/README.md +82 -20
  2. package/dist/{chunk-JXJCPN34.js → chunk-FAQLC3TX.js} +1 -1
  3. package/dist/{chunk-RJMSM3YA.js → chunk-O6457XHK.js} +17 -11
  4. package/dist/chunk-OVFCLRQQ.js +84 -0
  5. package/dist/index.d.ts +14 -4
  6. package/dist/index.js +7 -7
  7. package/dist/participant/index.d.ts +25 -1
  8. package/dist/participant/index.js +454 -194
  9. package/dist/preview/index.js +2 -2
  10. package/dist/styles.css +106 -0
  11. package/package.json +3 -3
  12. package/src/MessageBubble.test.tsx +2 -2
  13. package/src/MessageText.test.tsx +27 -10
  14. package/src/MessageText.tsx +25 -17
  15. package/src/MessageTextCopiedBadge.tsx +10 -2
  16. package/src/StatusTicks.test.tsx +27 -6
  17. package/src/StatusTicks.tsx +30 -15
  18. package/src/cssBlocks.test-helper.ts +31 -0
  19. package/src/legacyChannels.golden.test.ts +89 -0
  20. package/src/legacyDefaults.golden.test.tsx +127 -0
  21. package/src/legacyStyles.fixture.css +1121 -0
  22. package/src/legacyStyles.golden.test.ts +92 -0
  23. package/src/messageTextCopyInteraction.test.ts +75 -0
  24. package/src/messageTextCopyInteraction.ts +37 -0
  25. package/src/participant/ParticipantChannelBadges.test.tsx +59 -0
  26. package/src/participant/ParticipantChannelBadges.tsx +75 -0
  27. package/src/participant/ParticipantConversations.tsx +13 -6
  28. package/src/participant/ParticipantConversationsScreen.tsx +18 -7
  29. package/src/participant/ParticipantInbox.test.tsx +99 -2
  30. package/src/participant/ParticipantInbox.tsx +27 -46
  31. package/src/participant/ParticipantInboxRow.tsx +75 -0
  32. package/src/participant/ParticipantInboxSearchField.tsx +34 -0
  33. package/src/participant/ParticipantMessageBubble.test.tsx +2 -0
  34. package/src/participant/ParticipantMessageBubble.tsx +3 -3
  35. package/src/participant/ParticipantProtocolBadge.tsx +74 -0
  36. package/src/participant/ParticipantProtocolView.test.tsx +208 -0
  37. package/src/participant/ParticipantThread.test.tsx +19 -2
  38. package/src/participant/ParticipantThread.tsx +25 -15
  39. package/src/participant/index.ts +1 -0
  40. package/src/participant/participant.types.ts +9 -0
  41. package/src/participant/participantChannels.test.ts +42 -0
  42. package/src/participant/participantChannels.ts +33 -0
  43. package/src/participant/participantGrouping.test.ts +101 -3
  44. package/src/participant/participantGrouping.ts +20 -7
  45. package/src/participant/participantLabels.ts +29 -0
  46. package/src/participant/participantProtocol.test.ts +104 -0
  47. package/src/participant/participantProtocol.ts +52 -0
  48. package/src/participant/participantProtocolCopy.test.ts +45 -0
  49. package/src/participant/participantProtocolCopy.ts +32 -0
  50. package/src/participantLayoutShrink.test.ts +82 -0
  51. package/src/styles.css +22 -1
  52. package/dist/chunk-WSFGNR5R.js +0 -55
package/README.md CHANGED
@@ -9,11 +9,18 @@ Tela de conversa do lado de **quem conversa com a empresa** (app do motorista, p
9
9
  `ConversationsProvider`, não puxa `@xyflow/react` nem o `ConversationsWorkspace`, e não depende de Tailwind:
10
10
  todas as classes são `.cv-p-*` e vêm de `@adatechnology/conversations-ui/styles.css`.
11
11
 
12
- `@adatechnology/conversations-ui/styles.css` é **requisito**: sem ele a tela fica sem layout e o `MessageText` e o
13
- `StatusTicks` perdem a formatação (negrito, itálico, tachado, tiques coloridos). Importe-o uma vez na raiz do app.
12
+ `@adatechnology/conversations-ui/styles.css` é **requisito da visão do participante**: sem ele a tela fica sem layout.
13
+ A visão do participante renderiza `MessageText` e `StatusTicks` com `appearance="stylesheet"` (classes `.cv-*`, sem
14
+ Tailwind). Fora dela, os dois componentes mantêm o padrão da 0.4.2 (classes Tailwind do host).
14
15
 
15
- `MessageText` **copia ao tocar** por padrão (como na 0.3.1); `copyOnClick={false}` desliga. O aviso de cópia usa
16
- `copiedLabel` (padrão `Copied`; passe `copiedLabel="Copiado!"` para manter o português).
16
+ Props opt-in (o padrão é sempre o comportamento da 0.4.2):
17
+
18
+ - `MessageText`: `appearance?: 'tailwind' | 'stylesheet'` (padrão `'tailwind'`); `accessibleCopy?: boolean` (padrão
19
+ `false`; liga `role="button"`, `tabIndex=0` e Enter/Espaço para copiar); `copyOnClick` (padrão `true`; `false`
20
+ desliga a cópia); `copiedLabel` (padrão `Copiado!`).
21
+ - `StatusTicks`: `appearance?: 'tailwind' | 'stylesheet'` (padrão `'tailwind'`). Só em `'stylesheet'` valem o estado
22
+ `queued` (relógio), `bounced` tratado como `failed` e o `aria-label`; `queuedLabel?: string` (padrão `Queued`) define
23
+ o rótulo do relógio. No padrão, qualquer status diferente de `sent` e `failed` desenha dois tiques, como na 0.4.2; em `'stylesheet'`, um status desconhecido cai em `sent` (um tique).
17
24
 
18
25
  ### Uso mínimo
19
26
 
@@ -86,11 +93,13 @@ export const participantApi: ParticipantConversationsApi = {
86
93
  await request(`/conversations${cursor ? `?cursor=${encodeURIComponent(cursor)}` : ''}`),
87
94
  ),
88
95
  fetchMessages: async (subject, { before, limit } = {}) =>
89
- z.array(participantMessageSchema).parse(
90
- await request(
91
- `${conversationPath(subject)}/messages?limit=${limit ?? 30}${before ? `&before=${encodeURIComponent(before)}` : ''}`,
96
+ z
97
+ .array(participantMessageSchema)
98
+ .parse(
99
+ await request(
100
+ `${conversationPath(subject)}/messages?limit=${limit ?? 30}${before ? `&before=${encodeURIComponent(before)}` : ''}`,
101
+ ),
92
102
  ),
93
- ),
94
103
  sendMessage: async ({ subject, clientMessageId, text }) => {
95
104
  const message = participantMessageSchema.parse(
96
105
  await request(`${conversationPath(subject)}/messages`, {
@@ -140,24 +149,77 @@ render refaz a carga da lista e reinscreve os eventos de `subscribe` a cada rend
140
149
  empresa, ou seja, foi escrita pelo participante (é a bolha "minha"); `outbound` saiu da empresa. O adapter do
141
150
  app **não inverte nada**.
142
151
 
152
+ ### Protocolo legível da conversa
153
+
154
+ `ParticipantConversationSummary.protocol?` (1 a 32 caracteres, `[A-Za-z0-9-]`, ex.: `261009-K7M2`) é um código
155
+ curto para citar a conversa por telefone ou mensagem. **Quem gera é o produto, no servidor, uma vez e imutável**: o
156
+ pacote nunca gera nem conhece o formato, só **exibe, copia e busca**. Campo ausente = nada é desenhado.
157
+
158
+ - **Lista:** a linha mostra o protocolo abaixo do título (fonte mono); o prefixo `labels.protocolPrefix` é um `<span>` só para
159
+ leitor de tela (sem `aria-label` em elemento genérico, que o ARIA 1.2 proíbe).
160
+ - **Cabeçalho da conversa:** protocolo abaixo do título e botão de copiar (alvo de 44px) que usa
161
+ `navigator.clipboard.writeText`; falha de cópia é silenciosa. Durante 3 s o texto visível do botão vira
162
+ `labels.protocolCopied` (o nome acessível segue "`copyProtocol` + código") e o aviso também vai numa região
163
+ `aria-live="polite"` sempre na árvore; copiar de novo dentro dos 3 s reinicia o prazo e reanuncia.
164
+ - **Busca:** um campo `type="search"` acima da lista filtra por título (sem acento nem caixa) **ou** protocolo
165
+ (parcial, sem traço, sem caixa: `k7m2` acha `261009-K7M2`). Aparece só quando alguma conversa tem `protocol` ou
166
+ há mais de 8 conversas na lista; sem nada disso, nada é desenhado. Sem resultado: `labels.noResults`.
167
+ - Os chips de assunto e suas contagens são sempre calculados sobre **todas** as conversas carregadas; a busca só
168
+ restringe as linhas. Se o chip ativo não contém o que a busca acha (mas outro assunto contém), os chips continuam
169
+ visíveis e o estado vazio mostra `labels.noResultsInFilter` ("tente Todas") em vez de esconder a barra.
170
+ - O campo permanece enquanto houver consulta, mesmo que um refresh reduza a lista abaixo do limiar.
171
+ - **Limitação:** a busca cobre só as conversas já carregadas. Com `hasMore` e sem resultado, o estado vazio mostra
172
+ `labels.noResultsLoadedOnly` e o botão "carregar mais" fica à mão. Busca no servidor fica como evolução.
173
+ - **Labels novas** (defaults em inglês): `searchLabel`, `searchPlaceholder`, `noResults`, `noResultsInFilter`,
174
+ `noResultsLoadedOnly`, `protocolPrefix`, `copyProtocol` (padrão "Copy protocol"), `protocolCopied`.
175
+ - **Classes novas:** `.cv-p-protocol`, `.cv-p-protocol__copy`, `.cv-p-search` (mesmos tokens `--cv-p-*`).
176
+
177
+ ### Canais e ícone do assunto na lista
178
+
179
+ `ParticipantConversationSummary.channels?` (até 5 canais do vocabulário `email | whatsapp | app | portal | webchat`, sem
180
+ repetição, pode ser vazio) e `iconName?` (1 a 32 caracteres, `[a-z0-9-]`, nome **opaco**: o pacote não conhece o
181
+ catálogo) chegam **calculados pelo servidor**: `channels` são os canais distintos das mensagens da conversa e
182
+ `iconName` o nome escolhido pelo produto para o assunto. **O pacote não deduz nada**; campo ausente = nada é desenhado.
183
+
184
+ - **Lista:** a linha mostra à esquerda o ícone do assunto e, ao lado do protocolo, os selos de canal. O ícone vem de
185
+ `renderSubjectIcon?: (conversation) => ReactNode` (em `ParticipantConversations`); se a prop faltar, ou devolver
186
+ `null`/`undefined`, cai no ícone do grupo (`subjectGroups[].icon`). O host usa `conversation.iconName` para escolher.
187
+ - **Selos de canal:** um por canal, na ordem fixa app, whatsapp, email, portal, webchat (duplicata e canal desconhecido são
188
+ ignorados). O sinal visual é o ícone (cor é só reforço); o nome do canal está sempre em `<span class="cv-p-sr-only">`.
189
+ Sem `channels` ou vazio, nada é desenhado. Duas marcações (`ParticipantChannelBadges variant`): no **cabeçalho** da
190
+ conversa, `<ul class="cv-p-channels" aria-label>` com `<li class="cv-p-channel cv-p-channel--{canal}">`; na **linha** da
191
+ lista (dentro de um `<button>`, onde lista não é HTML válido), `<span class="cv-p-channels">` com `<span class="cv-p-channel
192
+ cv-p-channel--{canal}">`, um prefixo sr-only `Channels in this conversation: ` e o nome seguido de vírgula e espaço, para
193
+ o leitor dizer "Channels in this conversation: App, WhatsApp".
194
+ - **`renderSubjectIcon`** deve ser **puro e não lançar** (o pacote não tem error boundary); `null`, `undefined`, `false` e
195
+ `''` valem como ausente.
196
+ - **Cabeçalho da conversa:** os mesmos selos ao lado do protocolo.
197
+ - **Labels novas** (defaults em inglês): `channelsGroup` ("Channels in this conversation"), `channelApp`,
198
+ `channelWhatsapp`, `channelEmail`, `channelPortal`, `channelWebchat`.
199
+ - **Classes novas:** `.cv-p-channels`, `.cv-p-channel`, `.cv-p-row__tags`, `.cv-p-inbox__icon`; cores opcionais
200
+ `--cv-p-channel-app` (padrão: o destaque) e `--cv-p-channel-whatsapp` (padrão `#20914f`, ≥ 3:1 sobre as superfícies claras e
201
+ escuras; ao trocar, mantenha 3:1).
202
+
143
203
  ### Variáveis `--cv-p-*`
144
204
 
145
205
  Defina no `.cv-p`, no wrapper (`className`) ou em qualquer ancestral. Há também a prop `theme`
146
206
  (`primaryColor` → `--cv-p-accent`, `backgroundColor` → `--cv-p-surface`, `textPrimary` → `--cv-p-text`,
147
207
  `textSecondary` → `--cv-p-text-muted`).
148
208
 
149
- | Variável | Para que serve | Padrão (claro) |
150
- | --- | --- | --- |
151
- | `--cv-p-surface` | fundo da tela | `#ffffff` |
152
- | `--cv-p-surface-raised` | fundo de bolhas recebidas e campos | `#f3f4f6` |
153
- | `--cv-p-text` | texto principal | `#111827` |
154
- | `--cv-p-text-muted` | texto secundário | `#5b6573` |
155
- | `--cv-p-border` | bordas | `#d5d9df` |
156
- | `--cv-p-accent` | destaque, botão primário, bolha própria | `#a85a1c` |
157
- | `--cv-p-accent-contrast` | texto sobre o destaque | `#ffffff` |
158
- | `--cv-p-highlight` | fundo de "espera sua resposta" | `#fbefe2` |
159
- | `--cv-p-danger` | erro e falha de envio | `#c62828` |
160
- | `--cv-p-radius` | raio dos cantos | `0` |
209
+ | Variável | Para que serve | Padrão (claro) |
210
+ | ------------------------- | --------------------------------------- | -------------- |
211
+ | `--cv-p-surface` | fundo da tela | `#ffffff` |
212
+ | `--cv-p-surface-raised` | fundo de bolhas recebidas e campos | `#f3f4f6` |
213
+ | `--cv-p-text` | texto principal | `#111827` |
214
+ | `--cv-p-text-muted` | texto secundário | `#5b6573` |
215
+ | `--cv-p-border` | bordas | `#d5d9df` |
216
+ | `--cv-p-accent` | destaque, botão primário, bolha própria | `#a85a1c` |
217
+ | `--cv-p-accent-contrast` | texto sobre o destaque | `#ffffff` |
218
+ | `--cv-p-highlight` | fundo de "espera sua resposta" | `#fbefe2` |
219
+ | `--cv-p-danger` | erro e falha de envio | `#c62828` |
220
+ | `--cv-p-radius` | raio dos cantos | `0` |
221
+ | `--cv-p-channel-app` | cor do selo do canal app | o destaque |
222
+ | `--cv-p-channel-whatsapp` | cor do selo do canal WhatsApp | `#20914f` |
161
223
 
162
224
  O tema escuro segue a classe `.dark` (mesma do restante do pacote). Os nomes `.cv-p-*` e `--cv-p-*` são API
163
225
  pública e não mudam sem nova versão maior.
@@ -12,7 +12,7 @@ import {
12
12
  formatPhone,
13
13
  formatTimestamp,
14
14
  isSameDay
15
- } from "./chunk-RJMSM3YA.js";
15
+ } from "./chunk-O6457XHK.js";
16
16
  import {
17
17
  parseWhatsAppFormatting
18
18
  } from "./chunk-CBYEHPX6.js";
@@ -156,7 +156,13 @@ function channelCapabilityFor(channel) {
156
156
  // src/StatusTicks.tsx
157
157
  import { AlertTriangle, Clock } from "lucide-react";
158
158
  import { jsx, jsxs } from "react/jsx-runtime";
159
- var STATUS_MODIFIER = {
159
+ var TAILWIND_COLOR_CLASS = {
160
+ sent: "text-black/40 dark:text-white/40",
161
+ delivered: "text-black/40 dark:text-white/40",
162
+ read: "text-sky-500",
163
+ failed: "text-red-500"
164
+ };
165
+ var STYLESHEET_MODIFIER = {
160
166
  queued: "queued",
161
167
  sent: "sent",
162
168
  delivered: "delivered",
@@ -164,7 +170,6 @@ var STATUS_MODIFIER = {
164
170
  failed: "failed",
165
171
  bounced: "failed"
166
172
  };
167
- var QUEUED_LABEL = "Queued";
168
173
  function Ticks({ double }) {
169
174
  return /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 20 12", width: "15", height: "9", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
170
175
  double && /* @__PURE__ */ jsx("path", { d: "M1 6.5L4.5 10L11 2", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round", strokeLinejoin: "round" }),
@@ -180,24 +185,25 @@ function Ticks({ double }) {
180
185
  )
181
186
  ] });
182
187
  }
183
- function StatusIcon({ modifier }) {
184
- if (modifier === "failed") return /* @__PURE__ */ jsx(AlertTriangle, { size: 11 });
185
- if (modifier === "queued") return /* @__PURE__ */ jsx(Clock, { size: 11 });
186
- return /* @__PURE__ */ jsx(Ticks, { double: modifier !== "sent" });
187
- }
188
- function StatusTicks({ status, title }) {
189
- const modifier = STATUS_MODIFIER[status] ?? "sent";
190
- const ariaLabel = modifier === "queued" ? QUEUED_LABEL : void 0;
188
+ function StylesheetStatusTicks({ status, title, queuedLabel }) {
189
+ const modifier = STYLESHEET_MODIFIER[status] ?? "sent";
190
+ const ariaLabel = modifier === "queued" ? queuedLabel : void 0;
191
+ const icon = modifier === "failed" ? /* @__PURE__ */ jsx(AlertTriangle, { size: 11 }) : modifier === "queued" ? /* @__PURE__ */ jsx(Clock, { size: 11 }) : /* @__PURE__ */ jsx(Ticks, { double: modifier !== "sent" });
191
192
  return /* @__PURE__ */ jsx(
192
193
  "span",
193
194
  {
194
195
  className: `cv-status-ticks cv-status-ticks--${modifier}`,
195
196
  "data-cv-tooltip": title ?? ariaLabel,
196
197
  "aria-label": ariaLabel,
197
- children: /* @__PURE__ */ jsx(StatusIcon, { modifier })
198
+ children: icon
198
199
  }
199
200
  );
200
201
  }
202
+ function StatusTicks({ status, title, appearance = "tailwind", queuedLabel = "Queued" }) {
203
+ if (appearance === "stylesheet") return /* @__PURE__ */ jsx(StylesheetStatusTicks, { status, title, queuedLabel });
204
+ const colorClass = TAILWIND_COLOR_CLASS[status] ?? TAILWIND_COLOR_CLASS.sent;
205
+ return /* @__PURE__ */ jsx("span", { className: `cursor-help leading-none flex items-center ${colorClass}`, "data-cv-tooltip": title, children: status === "failed" ? /* @__PURE__ */ jsx(AlertTriangle, { size: 11 }) : /* @__PURE__ */ jsx(Ticks, { double: status !== "sent" }) });
206
+ }
201
207
 
202
208
  // src/lib/format.ts
203
209
  function formatTimestamp(timestamp) {
@@ -0,0 +1,84 @@
1
+ import {
2
+ parseWhatsAppFormatting
3
+ } from "./chunk-CBYEHPX6.js";
4
+
5
+ // src/MessageText.tsx
6
+ import { useCallback, useState } from "react";
7
+
8
+ // src/theme.ts
9
+ var CHAT_TEXT_PRIMARY_CLASS = "text-[#111b21] dark:text-[#e9edef]";
10
+ var CHAT_TEXT_SECONDARY_CLASS = "text-[#667781] dark:text-[#8696a0]";
11
+
12
+ // src/messageTextCopyInteraction.ts
13
+ function resolveCopyInteraction({
14
+ copyOnClick,
15
+ accessibleCopy,
16
+ onCopy
17
+ }) {
18
+ if (!copyOnClick) return {};
19
+ if (!accessibleCopy) return { onClick: onCopy };
20
+ return {
21
+ onClick: onCopy,
22
+ role: "button",
23
+ tabIndex: 0,
24
+ onKeyDown: (event) => {
25
+ if (event.key !== "Enter" && event.key !== " ") return;
26
+ event.preventDefault();
27
+ onCopy();
28
+ }
29
+ };
30
+ }
31
+
32
+ // src/MessageTextCopiedBadge.tsx
33
+ import { jsx } from "react/jsx-runtime";
34
+ var TAILWIND_CLASS = "absolute top-0 right-0 -translate-y-full bg-[#3b4a54] text-white text-[11px] px-1.5 py-0.5 rounded shadow-lg";
35
+ function MessageTextCopiedBadge({ label = "Copiado!", appearance = "tailwind" }) {
36
+ const className = appearance === "stylesheet" ? "cv-message-text__copied" : TAILWIND_CLASS;
37
+ return /* @__PURE__ */ jsx("span", { className, children: label });
38
+ }
39
+
40
+ // src/MessageText.tsx
41
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
42
+ var TAILWIND_CLASS2 = "text-[14.2px] leading-[19px] whitespace-pre-wrap break-words select-all [&_strong]:font-bold [&_em]:italic [&_del]:line-through";
43
+ function resolveClassName(appearance, copyOnClick) {
44
+ if (appearance === "tailwind") return TAILWIND_CLASS2;
45
+ return copyOnClick ? "cv-message-text cv-message-text--copyable" : "cv-message-text";
46
+ }
47
+ function MessageText({
48
+ message,
49
+ copyOnClick = true,
50
+ accessibleCopy = false,
51
+ copiedLabel,
52
+ appearance = "tailwind"
53
+ }) {
54
+ const [copied, setCopied] = useState(false);
55
+ const handleCopy = useCallback(async () => {
56
+ if (!copyOnClick || !message.content) return;
57
+ try {
58
+ await navigator.clipboard.writeText(message.content);
59
+ setCopied(true);
60
+ setTimeout(() => setCopied(false), 2e3);
61
+ } catch {
62
+ }
63
+ }, [copyOnClick, message.content]);
64
+ if (message.type === "template")
65
+ return /* @__PURE__ */ jsx2("p", { className: `text-sm italic ${CHAT_TEXT_SECONDARY_CLASS}`, children: message.content ?? "Template message" });
66
+ const interactionProps = resolveCopyInteraction({ copyOnClick, accessibleCopy, onCopy: handleCopy });
67
+ return /* @__PURE__ */ jsxs(
68
+ "div",
69
+ {
70
+ className: resolveClassName(appearance, copyOnClick),
71
+ ...interactionProps,
72
+ children: [
73
+ /* @__PURE__ */ jsx2("div", { children: parseWhatsAppFormatting(message.content ?? "") }),
74
+ copied && /* @__PURE__ */ jsx2(MessageTextCopiedBadge, { label: copiedLabel, appearance })
75
+ ]
76
+ }
77
+ );
78
+ }
79
+
80
+ export {
81
+ CHAT_TEXT_PRIMARY_CLASS,
82
+ CHAT_TEXT_SECONDARY_CLASS,
83
+ MessageText
84
+ };
package/dist/index.d.ts CHANGED
@@ -602,8 +602,12 @@ declare function TooltipLayer(): react.ReactPortal | null;
602
602
  interface StatusTicksProps {
603
603
  status: string;
604
604
  title?: string;
605
+ /** 'tailwind' (default) keeps the 0.4.2 markup; 'stylesheet' uses .cv-status-ticks--* and adds queued/bounced handling. */
606
+ appearance?: 'tailwind' | 'stylesheet';
607
+ /** Accessible label of the queued state (stylesheet appearance only). Defaults to 'Queued'. */
608
+ queuedLabel?: string;
605
609
  }
606
- declare function StatusTicks({ status, title }: StatusTicksProps): react.JSX.Element;
610
+ declare function StatusTicks({ status, title, appearance, queuedLabel }: StatusTicksProps): react.JSX.Element;
607
611
 
608
612
  interface LightboxLabels {
609
613
  /** Texto alternativo quando a imagem não tem legenda — sem ele o leitor de tela anuncia a URL. */
@@ -627,14 +631,20 @@ interface FileIconProps {
627
631
  }
628
632
  declare function FileIcon({ filename, mimeType, size, className }: FileIconProps): react.JSX.Element;
629
633
 
634
+ type MessageTextAppearance = 'tailwind' | 'stylesheet';
635
+
630
636
  interface MessageTextProps {
631
637
  message: MessagePayload;
632
- /** Defaults to true (tap copies the text, as in 0.3.1); false disables copying and its button semantics. */
638
+ /** Defaults to true (tap copies the text, as in 0.4.2); false disables copying. */
633
639
  copyOnClick?: boolean;
634
- /** Text of the badge shown after copying; absent means the package default ("Copied"). */
640
+ /** Opt-in: exposes the copy target as a keyboard-operable button (role, tabIndex, Enter/Space). Defaults to false. */
641
+ accessibleCopy?: boolean;
642
+ /** Text of the badge shown after copying. Defaults to 'Copiado!', as in 0.4.2. */
635
643
  copiedLabel?: string;
644
+ /** 'tailwind' (default) keeps the 0.4.2 utility classes; 'stylesheet' uses the .cv-* rules from styles.css. */
645
+ appearance?: MessageTextAppearance;
636
646
  }
637
- declare function MessageText({ message, copyOnClick, copiedLabel }: MessageTextProps): react.JSX.Element;
647
+ declare function MessageText({ message, copyOnClick, accessibleCopy, copiedLabel, appearance, }: MessageTextProps): react.JSX.Element;
638
648
 
639
649
  interface MessageTimestampProps {
640
650
  timestamp: string;
package/dist/index.js CHANGED
@@ -3,11 +3,6 @@ import {
3
3
  TooltipLayer,
4
4
  WhatsAppMessagePreview
5
5
  } from "./chunk-HOKNKXIT.js";
6
- import {
7
- CHAT_TEXT_PRIMARY_CLASS,
8
- CHAT_TEXT_SECONDARY_CLASS,
9
- MessageText
10
- } from "./chunk-WSFGNR5R.js";
11
6
  import {
12
7
  AudioPlayer,
13
8
  AudioRecorderButton,
@@ -64,12 +59,17 @@ import {
64
59
  useConversationLocales,
65
60
  useConversations,
66
61
  useQuickRepliesPicker
67
- } from "./chunk-JXJCPN34.js";
62
+ } from "./chunk-FAQLC3TX.js";
68
63
  import {
69
64
  cn,
70
65
  useDarkMode,
71
66
  useIsDarkTheme
72
67
  } from "./chunk-MRVFFJEH.js";
68
+ import {
69
+ CHAT_TEXT_PRIMARY_CLASS,
70
+ CHAT_TEXT_SECONDARY_CLASS,
71
+ MessageText
72
+ } from "./chunk-OVFCLRQQ.js";
73
73
  import {
74
74
  CHANNEL_CAPABILITIES,
75
75
  CHANNEL_FILTER_ALL,
@@ -89,7 +89,7 @@ import {
89
89
  formatTimestamp,
90
90
  isSameDay,
91
91
  phoneInitials
92
- } from "./chunk-RJMSM3YA.js";
92
+ } from "./chunk-O6457XHK.js";
93
93
  import {
94
94
  ZERO_WIDTH_SPACE,
95
95
  htmlToWA,
@@ -9,6 +9,8 @@ type ParticipantSubjectGroup = {
9
9
  readonly label: string;
10
10
  readonly icon?: ReactNode;
11
11
  };
12
+ /** Host-drawn icon for a list row; null/undefined falls back to the subject group icon. */
13
+ type ParticipantSubjectIconRenderer = (conversation: ParticipantConversationSummary) => ReactNode;
12
14
  type ParticipantInboxSection = {
13
15
  /** 'awaiting' | 'closed' | 'other' or the subjectType of a group. */
14
16
  readonly key: string;
@@ -26,12 +28,18 @@ type ParticipantInboxView = {
26
28
  readonly sections: readonly ParticipantInboxSection[];
27
29
  readonly filters: readonly ParticipantInboxFilter[];
28
30
  readonly showFilters: boolean;
31
+ /** The filter actually applied: 'all' when the requested one has no conversations left. */
32
+ readonly activeFilter: string;
33
+ /** The search finds conversations, but none under the active subject filter. */
34
+ readonly hasMatchesOutsideFilter: boolean;
29
35
  };
30
36
  type GroupParticipantConversationsParams = {
31
37
  readonly conversations: readonly ParticipantConversationSummary[];
32
38
  readonly subjectGroups: readonly ParticipantSubjectGroup[];
33
39
  /** subjectType, or 'all'/undefined for everything. */
34
40
  readonly filter?: string;
41
+ /** Narrows the rows only: chips and their counts always describe the whole list. */
42
+ readonly searchQuery?: string;
35
43
  };
36
44
  type ParticipantConversationsClassNames = {
37
45
  readonly root: string;
@@ -133,6 +141,21 @@ type ParticipantConversationsLabels = {
133
141
  readonly loading: string;
134
142
  readonly loadError: string;
135
143
  readonly loadMore: string;
144
+ readonly searchLabel: string;
145
+ readonly searchPlaceholder: string;
146
+ readonly noResults: string;
147
+ readonly noResultsInFilter: string;
148
+ readonly noResultsLoadedOnly: string;
149
+ /** Spoken before the protocol code, e.g. "Protocol 261009-K7M2". */
150
+ readonly protocolPrefix: string;
151
+ readonly copyProtocol: string;
152
+ readonly protocolCopied: string;
153
+ readonly channelsGroup: string;
154
+ readonly channelApp: string;
155
+ readonly channelWhatsapp: string;
156
+ readonly channelEmail: string;
157
+ readonly channelPortal: string;
158
+ readonly channelWebchat: string;
136
159
  };
137
160
  declare const DEFAULT_PARTICIPANT_CONVERSATIONS_LABELS: ParticipantConversationsLabels;
138
161
 
@@ -152,6 +175,7 @@ type ParticipantConversationsProps = {
152
175
  pendingMessages?: readonly ParticipantPendingMessage[];
153
176
  onRetryPending?: (clientMessageId: string) => void;
154
177
  quickReplies?: readonly QuickReply[];
178
+ renderSubjectIcon?: ParticipantSubjectIconRenderer;
155
179
  renderSubjectCard?: (conversation: ParticipantConversationSummary) => ReactNode;
156
180
  onOpenSubject?: (subject: ParticipantSubjectRef) => void;
157
181
  };
@@ -159,4 +183,4 @@ declare function ParticipantConversations(props: ParticipantConversationsProps):
159
183
 
160
184
  declare function groupParticipantConversations(params: GroupParticipantConversationsParams): ParticipantInboxView;
161
185
 
162
- export { DEFAULT_PARTICIPANT_CONVERSATIONS_LABELS, type GroupParticipantConversationsParams, type ParticipantConversationEvent, ParticipantConversations, type ParticipantConversationsApi, type ParticipantConversationsClassNames, type ParticipantConversationsLabels, type ParticipantConversationsProps, type ParticipantInboxSection, type ParticipantInboxView, type ParticipantLocalPendingMessage, type ParticipantPendingMessage, type ParticipantSendInput, type ParticipantSendResult, type ParticipantSubjectGroup, groupParticipantConversations };
186
+ export { DEFAULT_PARTICIPANT_CONVERSATIONS_LABELS, type GroupParticipantConversationsParams, type ParticipantConversationEvent, ParticipantConversations, type ParticipantConversationsApi, type ParticipantConversationsClassNames, type ParticipantConversationsLabels, type ParticipantConversationsProps, type ParticipantInboxSection, type ParticipantInboxView, type ParticipantLocalPendingMessage, type ParticipantPendingMessage, type ParticipantSendInput, type ParticipantSendResult, type ParticipantSubjectGroup, type ParticipantSubjectIconRenderer, groupParticipantConversations };