npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

sm-click-webchat-library-ui

v0.0.28

Published

Componentes do webchat SM Click

Readme

npm Develop Production Hotfix

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 cliente
  • sm-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-ui
import { 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 Prettier

Git 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 quebrou

Usando 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.