@adatechnology/conversations-ui 0.1.0-rc.4 → 0.1.0-rc.6

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 (42) hide show
  1. package/dist/chunk-LITPZCWW.js +1465 -0
  2. package/dist/index.d.ts +223 -29
  3. package/dist/index.js +316 -366
  4. package/dist/preview/index.d.ts +92 -3
  5. package/dist/preview/index.js +627 -103
  6. package/dist/types-CeixG2Z9.d.ts +324 -0
  7. package/package.json +2 -2
  8. package/src/Avatar.tsx +13 -2
  9. package/src/ConversationDocumentsPanel.tsx +342 -24
  10. package/src/ConversationListItem.tsx +18 -2
  11. package/src/DocumentsLibrary.tsx +322 -0
  12. package/src/FileIcon.test.ts +83 -0
  13. package/src/FileIcon.tsx +88 -11
  14. package/src/Lightbox.tsx +18 -3
  15. package/src/MediaRenderer.tsx +5 -2
  16. package/src/MessageBubble.tsx +18 -2
  17. package/src/MessageComposer.tsx +20 -3
  18. package/src/WhatsAppMessageEditor.tsx +28 -4
  19. package/src/hooks/useConversationActions.ts +56 -0
  20. package/src/hooks/useConversationDocuments.ts +11 -7
  21. package/src/hooks/useConversationList.ts +15 -9
  22. package/src/hooks/useConversationMessages.ts +2 -2
  23. package/src/index.ts +32 -11
  24. package/src/lib/cn.test.ts +29 -0
  25. package/src/lib/createMediaUrlResolver.ts +33 -0
  26. package/src/lib/paginated.test.ts +33 -0
  27. package/src/lib/paginated.ts +26 -0
  28. package/src/preview/MediaTypesPreview.tsx +87 -0
  29. package/src/preview/createMockConversationsApi.ts +175 -15
  30. package/src/preview/index.ts +6 -1
  31. package/src/preview/mockDocumentsSearch.test.ts +57 -0
  32. package/src/preview/preview.test.ts +5 -3
  33. package/src/preview/previewFileSamples.test.ts +151 -0
  34. package/src/preview/previewFileSamples.ts +74 -0
  35. package/src/preview/previewFixtures.ts +288 -1
  36. package/src/preview/previewMediaSource.test.ts +62 -0
  37. package/src/preview/previewMediaSource.ts +91 -0
  38. package/src/providers/types.ts +127 -9
  39. package/src/settings/WhatsAppCreateTemplateForm.tsx +3 -1
  40. package/src/useWaitingNotifications.ts +74 -29
  41. package/dist/chunk-4R6Y43DQ.js +0 -726
  42. package/dist/types-C0PtaO7S.d.ts +0 -207
package/dist/index.d.ts CHANGED
@@ -1,15 +1,7 @@
1
1
  import * as react from 'react';
2
2
  import react__default, { ReactNode, FormEvent } from 'react';
3
- import { M as MessagePayload, k as ConversationsFeatures, i as ConversationSummary, f as ConversationChannel, j as ConversationsApi, S as SSEProvider, g as ConversationDocument } from './types-C0PtaO7S.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, h as ConversationEventSource, l as ConversationsTheme, m as ConversationsUIConfig, D as DEFAULT_CONVERSATION_CHANNEL, F as FormatContactHandleParams, H as HANDLE_KIND, n as HandleKind, R as REOPEN_MECHANISM, o as ReopenMechanism, p as capabilitiesOf, q as channelFiltersFor, r as contactFlag, s as formatContactHandle } from './types-C0PtaO7S.js';
5
-
6
- type ResolveMediaUrl = (message: MessagePayload) => Promise<string | null>;
7
- interface MediaRendererProps {
8
- message: MessagePayload;
9
- onLightbox: (src: string) => void;
10
- onResolveUrl?: ResolveMediaUrl;
11
- }
12
- declare function MediaRenderer({ message, onLightbox, onResolveUrl }: MediaRendererProps): react.JSX.Element | null;
3
+ import { v as MessagePayload, x as ResolveMediaUrl, p as ConversationsFeatures, m as ConversationSummary, h as ConversationChannel, L as ListConversationsParams, o as ConversationsApi, S as SSEProvider, t as ListDocumentsParams, i as ConversationDocument, n as ConversationTemplate } from './types-CeixG2Z9.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, M as MediaRenderer, u as MediaRendererProps, R as REOPEN_MECHANISM, w as ReopenMechanism, y as capabilitiesOf, z as channelFiltersFor, A as contactFlag, B as formatContactHandle } from './types-CeixG2Z9.js';
13
5
 
14
6
  interface MessageBubbleProps {
15
7
  message: MessagePayload;
@@ -19,6 +11,10 @@ interface MessageBubbleProps {
19
11
  isSelecting?: boolean;
20
12
  isSelected?: boolean;
21
13
  onToggleSelect?: () => void;
14
+ /**
15
+ * Como buscar a mídia da mensagem. Ausente, o balão usa o `ConversationsApi` do
16
+ * `ConversationsProvider` — passe apenas para sobrescrever (cache próprio, CDN, proxy do host).
17
+ */
22
18
  onResolveMediaUrl?: ResolveMediaUrl;
23
19
  className?: string;
24
20
  }
@@ -82,7 +78,14 @@ interface EmojiPickerProps {
82
78
  }
83
79
  declare const EmojiPicker: ({ onSelect, className }: EmojiPickerProps) => react.JSX.Element;
84
80
 
81
+ interface MessageComposerLabels {
82
+ emoji: string;
83
+ attach: string;
84
+ send: string;
85
+ }
86
+ declare const DEFAULT_MESSAGE_COMPOSER_LABELS: MessageComposerLabels;
85
87
  interface MessageComposerProps {
88
+ labels?: Partial<MessageComposerLabels>;
86
89
  onSend: (text: string) => void;
87
90
  onAttach?: (file: File) => void;
88
91
  value?: string;
@@ -99,9 +102,21 @@ interface MessageComposerClassNames {
99
102
  root: string;
100
103
  field: string;
101
104
  }
102
- declare const MessageComposer: ({ onSend, onAttach, value: externalValue, onChange: externalOnChange, features, placeholder, maxLength, disabled, acceptedFileTypes, className, classNames, }: MessageComposerProps) => react.JSX.Element;
105
+ declare const MessageComposer: ({ onSend, onAttach, value: externalValue, onChange: externalOnChange, features, placeholder, maxLength, disabled, acceptedFileTypes, className, classNames, labels, }: MessageComposerProps) => react.JSX.Element;
103
106
 
107
+ interface WhatsAppMessageEditorLabels {
108
+ bold: string;
109
+ /** Tooltip da negrito — traz a sintaxe do WhatsApp junto, por isso é separado do `aria-label`. */
110
+ boldHint: string;
111
+ italic: string;
112
+ italicHint: string;
113
+ strikethrough: string;
114
+ strikethroughHint: string;
115
+ insertPlaceholder: (token: string) => string;
116
+ }
117
+ declare const DEFAULT_WHATSAPP_MESSAGE_EDITOR_LABELS: WhatsAppMessageEditorLabels;
104
118
  interface WhatsAppMessageEditorProps {
119
+ labels?: Partial<WhatsAppMessageEditorLabels>;
105
120
  value: string;
106
121
  onChange: (value: string) => void;
107
122
  placeholder?: string;
@@ -110,7 +125,7 @@ interface WhatsAppMessageEditorProps {
110
125
  previewLabel?: string;
111
126
  emptyPreviewText?: string;
112
127
  }
113
- declare function WhatsAppMessageEditor({ value, onChange, placeholder, placeholders, rows, previewLabel, emptyPreviewText, }: WhatsAppMessageEditorProps): react.JSX.Element;
128
+ declare function WhatsAppMessageEditor({ value, onChange, placeholder, placeholders, rows, previewLabel, emptyPreviewText, labels, }: WhatsAppMessageEditorProps): react.JSX.Element;
114
129
 
115
130
  interface SimpleEmojiPickerProps {
116
131
  onSelect: (emoji: string) => void;
@@ -131,16 +146,30 @@ interface DateDividerProps {
131
146
  }
132
147
  declare function DateDivider({ iso, className, classNames }: DateDividerProps): react.JSX.Element;
133
148
 
149
+ interface AvatarLabels {
150
+ /** Lido por leitor de tela quando não há nome nem imagem — a silhueta genérica. */
151
+ unnamedContact: string;
152
+ }
134
153
  interface AvatarProps {
135
154
  name?: string | null;
136
155
  avatarUrl?: string;
137
156
  size?: 'sm' | 'md' | 'lg';
138
157
  className?: string;
158
+ labels?: Partial<AvatarLabels>;
139
159
  }
140
- declare function Avatar({ name, avatarUrl, size, className }: AvatarProps): react.JSX.Element;
160
+ declare const DEFAULT_AVATAR_LABELS: AvatarLabels;
161
+ declare function Avatar({ name, avatarUrl, size, className, labels }: AvatarProps): react.JSX.Element;
141
162
 
163
+ interface ConversationListItemLabels {
164
+ /** Tooltip do ponto vermelho: a janela de atendimento de 24h já fechou. */
165
+ expiredWindow: string;
166
+ /** Tooltip do ponto laranja: a janela de atendimento está perto de fechar. */
167
+ warningWindow: string;
168
+ }
169
+ declare const DEFAULT_CONVERSATION_LIST_ITEM_LABELS: ConversationListItemLabels;
142
170
  interface ConversationListItemProps {
143
171
  conversation: ConversationSummary;
172
+ labels?: Partial<ConversationListItemLabels>;
144
173
  active?: boolean;
145
174
  selected?: boolean;
146
175
  onClick?: () => void;
@@ -157,7 +186,7 @@ interface ConversationListItemProps {
157
186
  */
158
187
  highlightActive?: boolean;
159
188
  }
160
- declare const ConversationListItem: ({ conversation, active, selected, onClick, onSelect, showDivider, highlightActive, }: ConversationListItemProps) => react.JSX.Element;
189
+ declare const ConversationListItem: ({ conversation, active, selected, onClick, onSelect, showDivider, highlightActive, labels, }: ConversationListItemProps) => react.JSX.Element;
161
190
 
162
191
  type ToastType = 'success' | 'error' | 'info';
163
192
  interface ToastContextValue {
@@ -177,12 +206,19 @@ interface StatusTicksProps {
177
206
  }
178
207
  declare function StatusTicks({ status, title }: StatusTicksProps): react.JSX.Element;
179
208
 
209
+ interface LightboxLabels {
210
+ /** Texto alternativo quando a imagem não tem legenda — sem ele o leitor de tela anuncia a URL. */
211
+ imageAlt: string;
212
+ close: string;
213
+ }
180
214
  interface LightboxProps {
181
215
  imageUrl: string;
182
216
  caption?: string;
183
217
  onClose: () => void;
218
+ labels?: Partial<LightboxLabels>;
184
219
  }
185
- declare function Lightbox({ imageUrl, caption, onClose }: LightboxProps): react.JSX.Element;
220
+ declare const DEFAULT_LIGHTBOX_LABELS: LightboxLabels;
221
+ declare function Lightbox({ imageUrl, caption, onClose, labels }: LightboxProps): react.JSX.Element;
186
222
 
187
223
  interface FileIconProps {
188
224
  filename?: string;
@@ -380,6 +416,61 @@ declare function WindowExpiredNotice({ onSendTemplate, disabled, labels: labelsO
380
416
  */
381
417
  declare function isWindowBlocking(window: ConversationWindow): boolean;
382
418
 
419
+ /**
420
+ * Biblioteca de arquivos de TODAS as conversas — a tela de Documentos do painel, fora do
421
+ * atendimento.
422
+ *
423
+ * Distinta do `ConversationDocumentsPanel`: aquele parte de uma conversa aberta e vive dentro dela;
424
+ * esta varre a empresa e por isso mostra de qual conversa cada arquivo veio, com o número
425
+ * clicável. Sem essa referência, uma lista global de anexos não responde nenhuma pergunta.
426
+ */
427
+ interface DocumentsLibraryLabels {
428
+ title: string;
429
+ searchPlaceholder: string;
430
+ empty: string;
431
+ noResults: string;
432
+ loading: string;
433
+ failure: string;
434
+ view: string;
435
+ download: string;
436
+ openConversation: string;
437
+ sourceFilterAll: string;
438
+ sourceFilterCustomer: string;
439
+ sourceFilterTeam: string;
440
+ sortMostRecent: string;
441
+ sortOldest: string;
442
+ clearFilters: string;
443
+ total: (count: number) => string;
444
+ page: (current: number, last: number) => string;
445
+ }
446
+ declare const DEFAULT_DOCUMENTS_LIBRARY_LABELS: DocumentsLibraryLabels;
447
+ interface DocumentsLibraryClassNames {
448
+ root: string;
449
+ title: string;
450
+ filters: string;
451
+ search: string;
452
+ sourceSelect: string;
453
+ sortButton: string;
454
+ clearButton: string;
455
+ status: string;
456
+ list: string;
457
+ item: string;
458
+ conversationLink: string;
459
+ filename: string;
460
+ meta: string;
461
+ pagination: string;
462
+ }
463
+ interface DocumentsLibraryProps {
464
+ /** Itens por página. O total vem do servidor. */
465
+ perPage?: number;
466
+ /** Abrir a conversa de origem. Ausente, o número aparece como texto e não como link. */
467
+ onOpenConversation?: (conversationId: string) => void;
468
+ labels?: Partial<DocumentsLibraryLabels>;
469
+ className?: string;
470
+ classNames?: Partial<DocumentsLibraryClassNames>;
471
+ }
472
+ declare function DocumentsLibrary({ perPage, onOpenConversation, labels: labelsOverride, className, classNames, }: DocumentsLibraryProps): react.JSX.Element | null;
473
+
383
474
  /**
384
475
  * Arquivos trocados na conversa. Sai do transcript e vira lista própria porque anexo é o que o
385
476
  * atendente mais precisa reencontrar depois — rolar meses de mensagens para achar um comprovante é
@@ -388,29 +479,76 @@ declare function isWindowBlocking(window: ConversationWindow): boolean;
388
479
  * Usa `useConversationDocuments`, então funciona com qualquer `ConversationsApi`. Host sem
389
480
  * biblioteca de documentos cai no estado vazio, sem quebrar.
390
481
  */
482
+ /** Origens que o filtro oferece. `all` não é origem — é a ausência de filtro. */
483
+ declare const DOCUMENT_SOURCE_FILTER: {
484
+ readonly ALL: "all";
485
+ readonly CUSTOMER: "customer";
486
+ readonly TEAM: "team";
487
+ };
488
+ type DocumentSourceFilter = (typeof DOCUMENT_SOURCE_FILTER)[keyof typeof DOCUMENT_SOURCE_FILTER];
391
489
  interface ConversationDocumentsPanelLabels {
392
490
  toggle: string;
393
491
  title: string;
394
492
  searchPlaceholder: string;
395
493
  empty: string;
494
+ /** Distinto de `empty`: sem resultado POR CAUSA do filtro, e não conversa sem anexo nenhum. */
495
+ noResults: string;
396
496
  loading: string;
397
497
  failure: string;
398
498
  download: string;
499
+ view: string;
500
+ sourceFilterAll: string;
501
+ sourceFilterCustomer: string;
502
+ sourceFilterTeam: string;
503
+ sortMostRecent: string;
504
+ sortOldest: string;
505
+ clearFilters: string;
506
+ selectAll: string;
507
+ downloadSelected: (count: number) => string;
508
+ archiveFailed: string;
509
+ total: (count: number) => string;
510
+ page: (current: number, last: number) => string;
399
511
  }
400
512
  declare const DEFAULT_CONVERSATION_DOCUMENTS_LABELS: ConversationDocumentsPanelLabels;
513
+ /**
514
+ * Partes estilizáveis do painel, no mesmo contrato do `ConversationHeader`: `cn` funde por cima da
515
+ * base e conflito de utilitário (padding, tamanho de fonte, borda) fica com o valor do produto.
516
+ *
517
+ * `status` cobre carregando/erro/vazio de uma vez — são a mesma linha de texto auxiliar, e slots
518
+ * separados só multiplicariam chave para quem quer mudar a cor de aviso.
519
+ */
401
520
  interface ConversationDocumentsPanelClassNames {
402
521
  root: string;
403
522
  body: string;
523
+ title: string;
524
+ filters: string;
525
+ search: string;
526
+ sourceSelect: string;
527
+ sortButton: string;
528
+ clearButton: string;
529
+ status: string;
530
+ list: string;
531
+ item: string;
532
+ sourceBadge: string;
533
+ filename: string;
534
+ meta: string;
535
+ viewButton: string;
536
+ downloadButton: string;
537
+ pagination: string;
538
+ selectionBar: string;
539
+ checkbox: string;
404
540
  }
405
541
  interface ConversationDocumentsPanelProps {
406
542
  conversationId: string;
407
543
  /** Controlado de fora porque o gatilho vive no cabeçalho, junto das outras ações da conversa. */
408
544
  open: boolean;
545
+ /** Itens por página. O total vem do servidor; sem paginação no host, a barra não aparece. */
546
+ perPage?: number;
409
547
  labels?: Partial<ConversationDocumentsPanelLabels>;
410
548
  className?: string;
411
549
  classNames?: Partial<ConversationDocumentsPanelClassNames>;
412
550
  }
413
- declare function ConversationDocumentsPanel({ conversationId, open, labels: labelsOverride, className, classNames, }: ConversationDocumentsPanelProps): react.JSX.Element | null;
551
+ declare function ConversationDocumentsPanel({ conversationId, open, perPage, labels: labelsOverride, className, classNames, }: ConversationDocumentsPanelProps): react.JSX.Element | null;
414
552
 
415
553
  /**
416
554
  * Serialização do transcript para download. Fica no pacote porque o formato de um histórico de
@@ -461,11 +599,35 @@ declare function useDarkMode(): {
461
599
  declare const NARROW_MAX_WIDTH_PX = 1023;
462
600
  declare function useIsNarrow(): boolean;
463
601
 
602
+ interface UseWaitingNotificationsLabels {
603
+ /** Título da notificação do sistema. Recebe a conversa para o host escolher nome × número. */
604
+ title: (conversation: ConversationSummary) => string;
605
+ body: (conversation: ConversationSummary) => string;
606
+ }
607
+ interface UseWaitingNotificationsParams {
608
+ /**
609
+ * Repassado cru ao `fetchConversations`. É o que permite filtrar não lidas **no servidor** em
610
+ * vez de baixar a lista inteira e contar no cliente: um painel com milhares de conversas não
611
+ * pode paginar 50 por vez atrás de quem tem `unread > 0`.
612
+ */
613
+ readonly params?: ListConversationsParams;
614
+ readonly intervalMs?: number;
615
+ /** Desliga o polling sem desmontar quem chama — útil com a aba em segundo plano. */
616
+ readonly enabled?: boolean;
617
+ readonly icon?: string;
618
+ readonly labels?: Partial<UseWaitingNotificationsLabels>;
619
+ }
464
620
  interface UseWaitingNotificationsResult {
465
621
  unreadCount: number;
466
622
  conversations: ConversationSummary[];
623
+ /**
624
+ * Releitura sob demanda. Existe porque o polling é o piso, não o mecanismo: quem já recebe SSE
625
+ * ou acabou de marcar tudo como lido sabe da mudança antes do próximo tick, e esperar 10s para
626
+ * o contador acompanhar faz a interface parecer travada.
627
+ */
628
+ refresh: () => Promise<void>;
467
629
  }
468
- declare function useWaitingNotifications(): UseWaitingNotificationsResult;
630
+ declare function useWaitingNotifications(params?: UseWaitingNotificationsParams): UseWaitingNotificationsResult;
469
631
 
470
632
  interface ConversationsContextValue {
471
633
  api: ConversationsApi;
@@ -547,6 +709,7 @@ interface WhatsAppCreateTemplateFormLabels {
547
709
  sectionDescription: string;
548
710
  nameLabel: string;
549
711
  nameHint: string;
712
+ namePlaceholder: string;
550
713
  categoryLabel: string;
551
714
  languageLabel: string;
552
715
  headerLabel: string;
@@ -684,7 +847,7 @@ interface UseConversationMessagesResult {
684
847
  caption?: string;
685
848
  }) => Promise<MessagePayload>;
686
849
  sendTemplate: (data: {
687
- templateName: string;
850
+ templateName?: string;
688
851
  languageCode?: string;
689
852
  bodyParams?: string[];
690
853
  }) => Promise<void>;
@@ -695,14 +858,11 @@ declare function useConversationMessages(conversationId: string, params?: {
695
858
  before?: string;
696
859
  }): UseConversationMessagesResult;
697
860
 
698
- interface UseConversationListParams {
699
- page?: number;
700
- limit?: number;
701
- waitingHuman?: boolean;
702
- search?: string;
703
- }
861
+ type UseConversationListParams = ListConversationsParams;
704
862
  interface UseConversationListResult {
705
863
  conversations: ConversationSummary[];
864
+ /** Total no servidor. Cai para o tamanho da página quando a API devolve só o array. */
865
+ total: number;
706
866
  loading: boolean;
707
867
  error: Error | undefined;
708
868
  refetch: () => Promise<void>;
@@ -717,12 +877,11 @@ interface UseConversationContextResult {
717
877
  }
718
878
  declare function useConversationContext(conversationId: string): UseConversationContextResult;
719
879
 
720
- interface UseConversationDocumentsParams {
721
- search?: string;
722
- page?: number;
723
- }
880
+ type UseConversationDocumentsParams = ListDocumentsParams;
724
881
  interface UseConversationDocumentsResult {
725
882
  documents: ConversationDocument[];
883
+ /** Total no servidor. Cai para o tamanho da página quando a API devolve só o array. */
884
+ total: number;
726
885
  loading: boolean;
727
886
  error: Error | undefined;
728
887
  refetch: () => Promise<void>;
@@ -733,6 +892,27 @@ type ConversationRealtimeHandler = (event: MessageEvent) => void;
733
892
  declare function useConversationRealtime(conversationId: string | undefined, onEvent: ConversationRealtimeHandler): void;
734
893
  declare function useGlobalRealtime(onEvent: ConversationRealtimeHandler): void;
735
894
 
895
+ interface UseConversationActionsResult {
896
+ /** `undefined` quando a API do host não implementa a operação — a UI esconde a afordância. */
897
+ takeover: (() => Promise<void>) | undefined;
898
+ release: (() => Promise<void>) | undefined;
899
+ finalize: (() => Promise<void>) | undefined;
900
+ }
901
+ /**
902
+ * Ações de atendimento de UMA conversa, já ligadas ao id.
903
+ *
904
+ * Separado de `useConversationMessages` porque assumir e devolver conversa também acontece a
905
+ * partir da lista, onde nenhuma thread está aberta — embutir nas mensagens obrigaria a carregar
906
+ * a thread inteira só para desenhar um botão na linha.
907
+ */
908
+ declare function useConversationActions(conversationId: string): UseConversationActionsResult;
909
+ interface UseInboxActionsResult {
910
+ markAllRead: (() => Promise<void>) | undefined;
911
+ listTemplates: (() => Promise<ConversationTemplate[]>) | undefined;
912
+ }
913
+ /** Ações que valem para a caixa inteira, sem conversa selecionada. */
914
+ declare function useInboxActions(): UseInboxActionsResult;
915
+
736
916
  declare function parseWhatsAppFormatting(text: string): ReactNode[];
737
917
  declare function waToHTML(text: string): string;
738
918
  declare function htmlToWA(html: string): string;
@@ -742,6 +922,8 @@ declare function formatPhone(number: string): string;
742
922
  declare function phoneInitials(number: string): string;
743
923
 
744
924
  declare function formatTimestamp(timestamp: string): string;
925
+ declare function formatDateTime(iso: string): string;
926
+ declare function isSameDay(a: Date, b: Date): boolean;
745
927
  declare function formatFileSize(bytes: number): string;
746
928
 
747
929
  interface AsyncResourceState<T> {
@@ -751,4 +933,16 @@ interface AsyncResourceState<T> {
751
933
  refetch: () => Promise<void>;
752
934
  }
753
935
 
754
- export { type AsyncResourceState, AudioPlayer, type AudioPlayerProps, Avatar, type AvatarProps, type BuildTranscriptTextParams, CHANNEL_BRAND_COLOR, CONVERSATION_WINDOW, ChannelIcon, type ChannelIconProps, ConversationChannel, type ConversationContextEntry, ConversationContextPanel, type ConversationContextPanelClassNames, type ConversationContextPanelLabels, type ConversationContextPanelProps, ConversationDocument, ConversationDocumentsPanel, type ConversationDocumentsPanelClassNames, type ConversationDocumentsPanelLabels, type ConversationDocumentsPanelProps, ConversationHeader, type ConversationHeaderClassNames, type ConversationHeaderLabels, type ConversationHeaderProps, ConversationListItem, type ConversationListItemProps, type ConversationLocales, ConversationLocalesProvider, type ConversationLocalesProviderProps, type ConversationRealtimeHandler, ConversationRow, type ConversationRowClassNames, type ConversationRowProps, ConversationSummary, ConversationWallpaper, type ConversationWallpaperProps, type ConversationWindow, ConversationsApi, ConversationsFeatures, ConversationsProvider, DEFAULT_CONVERSATION_CONTEXT_LABELS, DEFAULT_CONVERSATION_DOCUMENTS_LABELS, DEFAULT_CONVERSATION_HEADER_LABELS, DEFAULT_TEMPLATES_SETTINGS_LABELS, DEFAULT_WINDOW_EXPIRED_LABELS, DateDivider, type DateDividerClassNames, type DateDividerProps, EmojiPicker, type EmojiPickerProps, FileIcon, type FileIconProps, Lightbox, type LightboxProps, MediaRenderer, type MediaRendererProps, MessageBubble, type MessageBubbleProps, MessageComposer, type MessageComposerClassNames, type MessageComposerProps, MessagePayload, MessageTail, MessageText, type MessageTextProps, MessageTimestamp, NARROW_MAX_WIDTH_PX, type ResolveMediaUrl, SSEProvider, SimpleEmojiPicker, type SimpleEmojiPickerProps, StatusTicks, type StatusTicksProps, TEMPLATE_SETTINGS_TAB, type TemplateSettingsTab, ToastProvider, type TopicItem, TopicsForm, type TopicsFormLabels, type TopicsFormProps, type UseConversationContextResult, type UseConversationDocumentsParams, type UseConversationDocumentsResult, type UseConversationListParams, type UseConversationListResult, type UseConversationMessagesResult, WINDOW_FILTERS, WelcomeFarewellForm, type WelcomeFarewellFormLabels, type WelcomeFarewellFormProps, WhatsAppCreateTemplateForm, type WhatsAppCreateTemplateFormLabels, type WhatsAppCreateTemplateFormProps, type WhatsAppCreateTemplateResult, type WhatsAppCreateTemplateState, WhatsAppMessageEditor, type WhatsAppMessageEditorProps, type WhatsAppTemplateHeaderType, WhatsAppTemplateSettingsForm, type WhatsAppTemplateSettingsFormLabels, type WhatsAppTemplateSettingsFormProps, type WhatsAppTemplateSummary, type WhatsAppTemplateVariableSuggestion, WhatsAppTemplatesSettings, type WhatsAppTemplatesSettingsLabels, type WhatsAppTemplatesSettingsProps, WindowExpiredNotice, type WindowExpiredNoticeLabels, type WindowExpiredNoticeProps, type WindowOfParams, buildTranscriptFilename, buildTranscriptText, downloadTextFile, formatFileSize, formatPhone, formatStalledFor, formatTimestamp, htmlToWA, isWindowBlocking, parseWhatsAppFormatting, phoneInitials, toast, useConversationContext, useConversationDocuments, useConversationList, useConversationLocales, useConversationMessages, useConversationRealtime, useConversations, useDarkMode, useGlobalRealtime, useIsDarkTheme, useIsNarrow, useToast, useWaitingNotifications, waToHTML, waToHTMLInline, windowOf };
936
+ /**
937
+ * Resolve a mídia de uma mensagem numa URL exibível, usando só o `ConversationsApi`.
938
+ *
939
+ * Mora no pacote, e não em cada host, porque a regra não tem nada de específico de produto: é a
940
+ * tradução de `uploadId`/`mediaId` pelos dois métodos que o próprio contrato já declara. Deixá-la no
941
+ * host significava que todo projeto que adotasse o SDK reescreveria as mesmas oito linhas — e, na
942
+ * prática, ninguém escrevia: o `MediaRenderer` só busca mídia pela porta `onResolveMediaUrl`, então
943
+ * onde nada era injetado foto, vídeo e áudio ficavam no placeholder para sempre.
944
+ */
945
+
946
+ declare function createMediaUrlResolver(api: Pick<ConversationsApi, 'getDocumentUrl' | 'getMediaProxyUrl'>): ResolveMediaUrl;
947
+
948
+ export { type AsyncResourceState, AudioPlayer, type AudioPlayerProps, Avatar, type AvatarLabels, type AvatarProps, type BuildTranscriptTextParams, CHANNEL_BRAND_COLOR, CONVERSATION_WINDOW, ChannelIcon, type ChannelIconProps, ConversationChannel, type ConversationContextEntry, ConversationContextPanel, type ConversationContextPanelClassNames, type ConversationContextPanelLabels, type ConversationContextPanelProps, ConversationDocument, ConversationDocumentsPanel, type ConversationDocumentsPanelClassNames, type ConversationDocumentsPanelLabels, type ConversationDocumentsPanelProps, ConversationHeader, type ConversationHeaderClassNames, type ConversationHeaderLabels, type ConversationHeaderProps, ConversationListItem, type ConversationListItemLabels, type ConversationListItemProps, type ConversationLocales, ConversationLocalesProvider, type ConversationLocalesProviderProps, type ConversationRealtimeHandler, ConversationRow, type ConversationRowClassNames, type ConversationRowProps, ConversationSummary, ConversationTemplate, ConversationWallpaper, type ConversationWallpaperProps, type ConversationWindow, ConversationsApi, ConversationsFeatures, ConversationsProvider, DEFAULT_AVATAR_LABELS, DEFAULT_CONVERSATION_CONTEXT_LABELS, DEFAULT_CONVERSATION_DOCUMENTS_LABELS, DEFAULT_CONVERSATION_HEADER_LABELS, DEFAULT_CONVERSATION_LIST_ITEM_LABELS, DEFAULT_DOCUMENTS_LIBRARY_LABELS, DEFAULT_LIGHTBOX_LABELS, DEFAULT_MESSAGE_COMPOSER_LABELS, DEFAULT_TEMPLATES_SETTINGS_LABELS, DEFAULT_WHATSAPP_MESSAGE_EDITOR_LABELS, DEFAULT_WINDOW_EXPIRED_LABELS, DOCUMENT_SOURCE_FILTER, DateDivider, type DateDividerClassNames, type DateDividerProps, type DocumentSourceFilter, DocumentsLibrary, type DocumentsLibraryClassNames, type DocumentsLibraryLabels, type DocumentsLibraryProps, EmojiPicker, type EmojiPickerProps, FileIcon, type FileIconProps, Lightbox, type LightboxLabels, type LightboxProps, ListConversationsParams, ListDocumentsParams, MessageBubble, type MessageBubbleProps, MessageComposer, type MessageComposerClassNames, type MessageComposerLabels, type MessageComposerProps, MessagePayload, MessageTail, MessageText, type MessageTextProps, MessageTimestamp, NARROW_MAX_WIDTH_PX, ResolveMediaUrl, SSEProvider, SimpleEmojiPicker, type SimpleEmojiPickerProps, StatusTicks, type StatusTicksProps, TEMPLATE_SETTINGS_TAB, type TemplateSettingsTab, ToastProvider, type TopicItem, TopicsForm, type TopicsFormLabels, type TopicsFormProps, type UseConversationActionsResult, type UseConversationContextResult, type UseConversationDocumentsParams, type UseConversationDocumentsResult, type UseConversationListParams, type UseConversationListResult, type UseConversationMessagesResult, type UseInboxActionsResult, type UseWaitingNotificationsLabels, type UseWaitingNotificationsParams, type UseWaitingNotificationsResult, WINDOW_FILTERS, WelcomeFarewellForm, type WelcomeFarewellFormLabels, type WelcomeFarewellFormProps, WhatsAppCreateTemplateForm, type WhatsAppCreateTemplateFormLabels, type WhatsAppCreateTemplateFormProps, type WhatsAppCreateTemplateResult, type WhatsAppCreateTemplateState, WhatsAppMessageEditor, type WhatsAppMessageEditorLabels, type WhatsAppMessageEditorProps, type WhatsAppTemplateHeaderType, WhatsAppTemplateSettingsForm, type WhatsAppTemplateSettingsFormLabels, type WhatsAppTemplateSettingsFormProps, type WhatsAppTemplateSummary, type WhatsAppTemplateVariableSuggestion, WhatsAppTemplatesSettings, type WhatsAppTemplatesSettingsLabels, type WhatsAppTemplatesSettingsProps, WindowExpiredNotice, type WindowExpiredNoticeLabels, type WindowExpiredNoticeProps, type WindowOfParams, buildTranscriptFilename, buildTranscriptText, createMediaUrlResolver, downloadTextFile, formatDateTime, formatFileSize, formatPhone, formatStalledFor, formatTimestamp, htmlToWA, isSameDay, isWindowBlocking, parseWhatsAppFormatting, phoneInitials, toast, useConversationActions, useConversationContext, useConversationDocuments, useConversationList, useConversationLocales, useConversationMessages, useConversationRealtime, useConversations, useDarkMode, useGlobalRealtime, useInboxActions, useIsDarkTheme, useIsNarrow, useToast, useWaitingNotifications, waToHTML, waToHTMLInline, windowOf };