sm-click-webchat-library-ui
v0.0.28
Published
Componentes do webchat SM Click
Readme
Sobre
Este pacote contém os componentes visuais do webchat SM Click publicados como biblioteca npm. Ele é consumido por dois projetos:
sm-click-webchat-widget— o widget embedável que roda no iframe dentro do site do clientesm-zap-front— a prévia ao vivo na tela de customização da instância webchat
Mantendo os componentes neste pacote separado, a aparência da prévia e do widget real são garantidamente idênticas.
Regras de contribuição (contrato prop-driven, tokens de cor, comentários, checklist antes de dar a tarefa por pronta) estão em
.claude/skills/webchat-library-ui/SKILL.md— leia antes de mexer neste repo.
Estrutura
src/
├── index.js # Entrypoint da lib — exporta WebchatShell e LauncherButton
├── main.js # Entrypoint do servidor de dev (App.vue)
├── App.vue # Wrapper apenas para desenvolvimento local
├── tailwind.css # Base Tailwind + resets pontuais injetados no bundle da lib
├── WebchatShell.vue # Componente raiz exportado — orquestra todos os estados
├── WebchatShell.stories.js # Stories do Storybook pro WebchatShell
│
├── components/
│ ├── ChatHeader.vue # Cabeçalho com título, avatar, protocolo e botão fechar
│ ├── ChatComposer.vue # Campo de texto, fila de anexos, gravação de áudio, emoji
│ ├── ChatLoadingState.vue # Tela de carregamento com spinner e mensagens cíclicas
│ ├── ChatBlockedState.vue # Tela de widget indisponível/bloqueado
│ ├── VisitorProfile.vue # Tela "Meus dados": iniciais, nome/telefone pedidos no pré-chat, protocolo
│ ├── WebchatBottomNav.vue # Barra de baixo estilo app (Conversa / Meus dados)
│ ├── LinkAccessTopics.vue # Lista de regras do acesso por link (Meus dados e tela de expirado)
│ ├── PreChatForm.vue # Formulário de nome/WhatsApp antes de liberar a conversa
│ ├── MessageBubble.vue # Balão de mensagem (delega para os sub-tipos em messages/)
│ ├── MessageActionToolbar.vue # Barra de reagir/citar/editar/apagar/baixar
│ ├── DeleteConfirmModal.vue # Confirmação de exclusão de mensagem
│ ├── MediaViewer.vue # Visualizador embutido de imagem/vídeo/PDF
│ ├── ScrollToBottomButton.vue # Botão flutuante "voltar ao início" da conversa
│ ├── SystemMessage.vue # Balão de evento de sistema (iniciado/transferido/finalizado)
│ ├── ErrorToast.vue # Aviso temporário (ex.: permissão de microfone negada)
│ ├── FileExtensionBadge.vue # Badge de extensão sobreposta num ícone de arquivo
│ ├── LauncherButton.vue # Botão flutuante — só usado na prévia, ver SKILL.md regra 1
│ ├── LauncherButton.stories.js # Stories do Storybook pro LauncherButton
│ │
│ ├── emoji/
│ │ └── EmojiPicker.vue # Seletor de emoji completo (busca, categorias, tom de pele)
│ │
│ ├── inputs/
│ │ ├── PhoneField.vue # Campo de telefone com seletor de país
│ │ └── TextField.vue # Campo de texto genérico do pré-chat
│ │
│ ├── messages/
│ │ ├── MessageText.vue # Texto (markdown + preview de link do YouTube)
│ │ ├── MessageImage.vue # Imagem
│ │ ├── MessageVideo.vue # Vídeo
│ │ ├── MessageAudio.vue # Áudio (onda real via Web Audio API)
│ │ ├── MessageFile.vue # Documento/arquivo genérico
│ │ ├── MessageGroupMedia.vue # Álbum de imagens/vídeos agrupados
│ │ ├── MessageButtons.vue # Mensagem com botões (botão de link abre o site)
│ │ ├── MessageStatusTicks.vue # Check estilo WhatsApp (pending/sent/failed)
│ │ ├── MessageYouTubePreview.vue # Card de preview de link do YouTube
│ │ └── QuotedPreview.vue # Prévia de mensagem citada dentro do balão
│ │
│ └── __tests__/ # Testes unitários dos componentes (Vitest + @vue/test-utils)
│
├── composables/
│ ├── useTheme.js # Converte props de cor/estilo em CSS custom properties
│ ├── useEmojiPicker.js # Emoji recentes + tom de pele (persistidos em localStorage)
│ └── __tests__/
│
└── utils/
├── chatMarkdown.js # *negrito*/_itálico_/```código```/link, sempre escapando HTML
├── phone.js # Máscara/validação de telefone, formato E.164
├── fileExtension.js # Extensão de arquivo pra badge
├── graphemes.js # Split seguro de emoji composto (ZWJ/tom de pele/bandeira)
├── youtube.js # Extração de vídeo do YouTube de um texto
├── downloadMedia.js # Download via blob (contorna limite de link cross-origin)
├── emojiData.js # Catálogo de emoji + tons de pele
└── __tests__/Stack
| | |
| --------------- | ------------------------------------ |
| Framework | Vue 3 (Composition API) |
| Estilo | Tailwind CSS + CSS custom properties |
| Build | Vite (library mode) |
| Testes | Vitest + @vue/test-utils + happy-dom |
| Catálogo visual | Storybook (@storybook/vue3-vite) |
| Publicação | npm público |
Usando em outro projeto
npm install sm-click-webchat-library-uiimport { WebchatShell } from "sm-click-webchat-library-ui";
import "sm-click-webchat-library-ui/style.css";<WebchatShell
:messages="messages"
:connected="true"
header-title="Suporte"
primary-color="#49d3c4"
@send="handleSend"
@close="handleClose"
/>Props
| Prop | Tipo | Default | Descrição |
| ------------------ | ---------------- | --------- | ------------------------------------------------------------------ |
| primaryColor | String | #49d3c4 | Cor principal (header, balão enviado, botão) |
| secondaryColor | String | #f1f2f4 | Cor dos balões recebidos |
| headerTitle | String | "" | Título exibido no cabeçalho |
| avatarUrl | String | "" | URL do avatar genérico (fallback quando não há attendantPhoto) |
| borderRadius | String | medium | none | small | medium | large | rounded |
| messages | Array | [] | Lista de mensagens { id, fromMe, content, time, type?, ... } |
| connected | Boolean | false | Se a conexão com o atendimento está ativa |
| loading | Boolean | false | Exibe spinner de carregamento |
| blocked | Boolean | false | Exibe tela de widget bloqueado |
| blockReason | String | "" | Motivo de bloqueio exibido na tela bloqueada |
| chatId | String | "" | ID do chat (exibido no rodapé para debug) |
| protocol | Number\|String | null | Número de protocolo exibido no cabeçalho |
| attendantName | String | "" | Nome do atendente atual |
| attendantPhoto | String | "" | Foto do atendente atual (sobrepõe avatarUrl no cabeçalho) |
| interactive | Boolean | true | false = modo prévia, composer sempre habilitado |
| sending | Boolean | false | Exibe spinner de envio no botão |
| visualStyle | String | classic | classic | modern | minimal |
| askName | Boolean | false | Ativa o campo de nome na tela de pré-chat |
| askWhatsapp | Boolean | false | Ativa o campo de WhatsApp na tela de pré-chat |
| preChatCompleted | Boolean | false | Pula a tela de pré-chat quando true |
| expiredReason | String | "" | Com texto, mostra a tela de link expirado no lugar da conversa |
| visitorName | String | "" | Nome do visitante na tela "Meus dados" (só aparece com askName) |
| visitorTelephone | String | "" | Telefone (DDI + número) em "Meus dados" (só com askWhatsapp) |
| linkAccessNotice | String | "" | Aviso pronto do acesso por link em "Meus dados" (ex.: validade) |
| linkAccessTopics | Array | [] | Regras do acesso por link { title, text }, abrem em "Meus dados" |
| expiredTopics | Array | [] | Orientações { title, text } abaixo do motivo na tela de expirado |
Eventos
| Evento | Payload | Descrição |
| ----------------- | ---------------------------------------- | ------------------------------------------------ |
| send | (text, quotedId) | Texto digitado ao enviar mensagem |
| attach | object | Anexo enviado (arquivo em lote ou áudio gravado) |
| close | — | Clique no botão fechar |
| submit-pre-chat | { name?, whatsapp?, whatsappDisplay? } | Formulário de pré-chat enviado |
| react | { id, reaction } | Reação escolhida numa mensagem |
| edit | { id, text } | Edição de mensagem própria salva |
| delete | id | Exclusão de mensagem própria confirmada |
| clear-data | — | "Limpar meus dados" confirmado em "Meus dados" |
Desenvolvimento local
npm install
npm run dev # servidor de desenvolvimento com hot-reload (App.vue)
npm run build # gera dist/Testes e formatação
npm test # Vitest
npm run format:check # verifica se o código está formatado
npm run format # corrige automaticamente com PrettierGit hooks
npm install já configura um pre-commit (roda Prettier nos arquivos staged e re-adiciona ao commit) e um pre-push (git pull origin main na branch atual, pra ela nunca ficar publicando/gerando release em cima de uma versão de main desatualizada). Ver .claude/skills/webchat-library-ui/references/publishing.md.
Storybook
Catálogo visual isolado dos componentes — útil pra ver todos os estados/variantes sem precisar rodar o widget ou o sm-zap-front. Ver .claude/skills/webchat-library-ui/references/storybook.md.
npm run storybook # dev server em :6006
npm run build-storybook # build estático, útil pra validar que nada quebrouUsando a versão local no widget sem publicar
O sm-click-webchat-widget resolve sm-click-webchat-library-ui pro src/ local deste repo via alias do Vite, ativado por env var — não precisa editar vite.config manualmente:
# .env / .env.local do sm-click-webchat-widget
VITE_USE_LOCAL_WEBCHAT_UI=true
VITE_LOCAL_WEBCHAT_UI_PATH=<caminho absoluto deste repo> # opcional — default é o repo irmão "../sm-click-webchat-library-ui"Com isso, editar aqui vale no widget na hora, sem build/publish/npm link. sm-zap-front tem um toggle equivalente.
