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

@joserqc/feedback-widget

v0.10.0

Published

Widget de feedback in-app da plataforma ZexIA — botão flutuante com captura de tela e contexto técnico

Readme

@joserqc/feedback-widget

Widget de feedback in-app da plataforma ZexIA: botão flutuante → modal de bug/sugestão com captura de tela opcional, logs de console e contexto técnico → painel central de triagem.

Instalação

pnpm add @joserqc/feedback-widget

React ^18.2.0 || ^19.0.0 (peer). As libs de captura (@zumer/snapdom, modern-screenshot) carregam por import lazy — fora do bundle inicial.

Uso

import { FeedbackWidget } from '@joserqc/feedback-widget';

<FeedbackWidget
  projectKey="fbk_..."
  user={{ id: usuario.id, email: usuario.email, name: usuario.nome, role: usuario.papel }}
  metadata={{ tenantId }}
  appVersion="1.4.2"
  position="bottom-right"
  offset={{ bottom: 96, side: 24 }}
  accentColor="#0f766e"
/>

Monte uma única vez, dentro da área autenticada. Client-only: no Next.js (App Router), envolva em um componente com 'use client'.

Props

| Prop | Tipo | Descrição | | --- | --- | --- | | projectKey | string (obrigatória) | Chave pública do projeto (fbk_...) | | apiUrl | string | Base da API (default https://feedback.zexia.tech) | | user | { id?, email?, name?, role? } | Usuário logado (recomendado) | | metadata | object | Contexto extra do app (≤16KB) | | appVersion | string | Versão do app host | | position | 'bottom-right' \| 'bottom-left' | Posição do botão | | offset | number \| { bottom?, side? } | Distância das bordas em px (default 20); objeto separa vertical/lateral para não colidir com outros FABs | | accentColor | string | Cor de destaque do modal/botão | | zIndex | number | Default 2147482000 | | enabled | boolean | Desliga o widget sem desmontar (default true) | | captureScope | 'page' \| 'viewport' | O que entra na captura (default page): a página inteira rolável ou só a área visível da janela. O aviso mostrado ao usuário acompanha a escolha | | keepHostOverlaysOpen | boolean | Impede que a interação com o widget feche o modal/popover aberto do app (default true) — é o que permite reportar um problema dentro de um modal com ele visível na captura. Desligue só se o host precisar enxergar cliques globais |

Requisitos no app host

  • Origem permitida: o ingest valida o header Origin contra as origens do projeto — cadastre o domínio do app (e http://localhost:<porta> em dev) no painel, senão o envio retorna 403.
  • CSP (se o app tiver): connect-src https://feedback.zexia.tech e style-src 'unsafe-inline' (o CSS do widget é auto-injetado). Sem isso o widget falha silenciosamente.
  • Escopo da captura: captureScope="viewport" recorta a imagem para o que está visível na janela — menos dado exposto e arquivo menor. Não deixa a captura mais rápida: as duas libs serializam o DOM inteiro de qualquer forma, e é o recorte que muda, não o trabalho. Para reduzir o tempo em página pesada, marque a parte cara com data-fbw-mask. Se o recorte falhar, o widget devolve captura nenhuma em vez da página inteira — o aviso exibido ao usuário promete só a área visível e mandar mais do que isso quebraria o consentimento.
  • LGPD: adicione data-fbw-mask a elementos com dados sensíveis — eles saem da captura de tela. O usuário sempre vê um preview da captura antes de enviar. Não logue PII em console.log (os últimos logs vão junto do feedback, com redação best-effort de tokens/senhas).

Anotação na captura (>=0.3)

Sobre o preview, o usuário pode marcar onde está o problema com círculo, seta ou caneta (com desfazer/limpar). As marcas são compostas na própria imagem antes do envio — nada muda no contrato da API. Falha na composição nunca bloqueia o envio (a captura segue sem marcas).

A partir da 0.4, com captura presente o modal expande para o centro da tela (até 960px; prévia com até 62vh) — no desktop o formulário fica à esquerda e a imagem grande à direita, facilitando localizar o elemento a destacar. Sem captura (ou após o envio), o modal volta ao formato compacto junto ao botão.

Em telas estreitas ou baixas, a prévia tem altura limitada, o conteúdo central rola e as ações permanecem em um rodapé aderente. O modo inicial da prévia é “Rolar”; círculo, seta e caneta só passam a capturar gestos depois que o usuário escolhe explicitamente uma ferramenta.

Imagens extras (>=0.9)

Além da captura automática, o usuário pode selecionar, arrastar ou colar até três prints extras. O modal mostra a prévia de cada arquivo e permite removê-lo antes do envio. São aceitos PNG, JPEG e WebP, com até 5MB por imagem e 8MB no total somando a captura automática.

O painel técnico, o portal do cliente e get_feedback no MCP recebem a mesma galeria por URLs assinadas do bucket privado. Falha de uma imagem não descarta o relato textual; o retry usa identificadores estáveis para completar uploads sem criar outro feedback.

Carregamento da captura (>=0.6)

O modal abre já no formato final, com spinner e área reservada enquanto a captura é gerada — sem salto de layout, e interagir durante o carregamento (trocar o tipo, digitar) nunca fecha o modal. Fechar pelo fundo escurecido exige pressionar e soltar fora do modal. Captura que falha oferece "Tentar novamente"; páginas acima do limite de canvas do navegador (~32k px de altura) caem nesse estado em vez de enviar imagem vazia.

Atalhos de teclado (>=0.4)

Esc fecha o modal. Ctrl+Enter (Cmd+Enter no Mac) envia o feedback de qualquer campo do modal — inclusive para tentar novamente após erro. Enter sozinho continua inserindo nova linha na mensagem.

Comportamento de rede

Timeout de 15s + 1 retry automático com backoff; reenvio não duplica (idempotência por client_event_id). Se falhar de vez, o texto digitado é preservado com botão "Tentar novamente". Imagens cross-origin sem CORS saem em branco na captura — o envio nunca é bloqueado por falha de screenshot.

Desde a 0.9.2, o widget também cria um reporterToken criptográfico antes da primeira tentativa e o preserva junto do clientEventId. Se o servidor gravar o feedback mas o 201 se perder na rede, a API devolve o token no 200 deduplicado somente quando seu hash confere com o já persistido. Assim, o caso continua disponível em “Meus envios” sem guardar token em claro no servidor. APIs anteriores ignoram o novo campo e continuam compatíveis, mas não recuperam o token nesse cenário específico até serem atualizadas.

Atualização de “Meus envios” (>=0.9.1)

O widget consulta os casos pendentes 2,5 segundos após montar e volta a sincronizá-los ao abrir o modal, ao recuperar foco e quando a página volta a ficar visível. Chamadas disparadas por foco têm intervalo mínimo de 15 segundos. Uma triagem automática concluída já aparece como “Em análise”, sem alterar o status humano armazenado no painel.

Versionamento

0.x durante a fase de integrações (o contrato do ingest evolui apenas de forma aditiva); 1.0.0 será congelada com os apps de produção rodando.