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

@neetru/page-tour

v0.1.0

Published

Tour guiado (onboarding) reutilizavel para produtos SaaS Neetru — destaca elementos da pagina por id, com mascara SVG e navegacao passo a passo. Extraido do pdv-agiliza; headless por padrao (voce estiliza), com um card default pronto pra uso.

Readme

@neetru/page-tour

Tour guiado (onboarding) reutilizável para produtos SaaS Neetru. Destaca um elemento por vez na página atual, recorta um "spotlight" ao redor dele com máscara SVG, e mostra um card com o passo atual + navegação Voltar/Próximo.

Extraído do produto pdv-agiliza, que tinha essa lógica implementada do zero (portal + máscara + posicionamento por getBoundingClientRect). Generalizado aqui pra qualquer produto reusar em vez de reimplementar.

Por que existe

Onboarding guiado é uma necessidade transversal — todo produto SaaS Neetru com uma UI de várias páginas eventualmente precisa explicar "isso aqui é X, aquilo é Y" pro usuário novo. A parte difícil (rastrear a posição do elemento- alvo em tempo real, reagir a scroll/resize, recortar a máscara) é sempre a mesma; só a aparência do card muda de produto pra produto.

Instalação

npm install @neetru/page-tour framer-motion

react, react-dom e framer-motion são peer dependencies — o produto que consome já deve ter os dois primeiros; framer-motion é a única dependência nova que este pacote introduz.

Uso básico

  1. Marque os elementos que vão virar passos do tour com um id:
<input id="tour-search" ... />
<div id="tour-cart" ...>...</div>
  1. Declare os passos e monte o <PageTour>:
import { useState } from 'react';
import { PageTour, type TourStep } from '@neetru/page-tour';

const steps: TourStep[] = [
  { targetId: 'tour-search', title: 'Busca', content: 'Encontre qualquer item pelo nome ou código de barras.', position: 'bottom' },
  { targetId: 'tour-cart', title: 'Carrinho', content: 'Ajuste quantidades e finalize a venda por aqui.', position: 'top' },
];

function MinhaPagina() {
  const [tourOpen, setTourOpen] = useState(false);

  return (
    <>
      <button onClick={() => setTourOpen(true)}>Ver guia</button>
      <PageTour steps={steps} isOpen={tourOpen} onClose={() => setTourOpen(false)} />
    </>
  );
}

Isso já funciona sem nenhum CSS — o card default vem sem estilos (sem Tailwind, sem design system embutido), então na primeira vez que testar vai aparecer como HTML puro. Estilize com classNames (abaixo) ou substitua o card inteiro com renderCard.

Estilizando o card default

<PageTour
  steps={steps}
  isOpen={tourOpen}
  onClose={() => setTourOpen(false)}
  classNames={{
    card: 'meu-card-do-tour',
    title: 'meu-titulo',
    content: 'meu-texto',
    nextButton: 'meu-botao-primario',
    backButton: 'meu-botao-secundario',
    finishButton: 'meu-botao-sucesso',
    closeButton: 'meu-botao-fechar',
    stepBadge: 'meu-indicador-de-etapa',
  }}
/>

Cada chave vira a prop className do elemento correspondente — estilize com Tailwind, CSS Modules, styled-components, o que o produto já usar.

Substituindo o card inteiro (renderCard)

Pra controle total sobre a aparência (ex: reusar componentes de design system do produto), passe renderCard. O PageTour continua responsável pelo overlay, pela máscara de destaque e pelo posicionamento — só o conteúdo do card muda:

<PageTour
  steps={steps}
  isOpen={tourOpen}
  onClose={() => setTourOpen(false)}
  renderCard={({ step, stepIndex, totalSteps, isFirstStep, isLastStep, goBack, goNext, close }) => (
    <MeuCardDeDesignSystem>
      <h3>{step.title}</h3>
      <p>{step.content}</p>
      <Progresso atual={stepIndex + 1} total={totalSteps} />
      {!isFirstStep && <Botao onClick={goBack}>Voltar</Botao>}
      <Botao onClick={isLastStep ? close : goNext}>{isLastStep ? 'Concluir' : 'Próximo'}</Botao>
    </MeuCardDeDesignSystem>
  )}
/>

i18n

Os textos padrão do card default (Voltar, Próximo, Concluir, "Etapa N / M") já vêm em PT-BR. Pra trocar:

<PageTour
  steps={steps}
  isOpen={tourOpen}
  onClose={close}
  labels={{ back: 'Back', next: 'Next', finish: 'Done', stepOf: (c, t) => `${c} of ${t}` }}
/>

Catálogo de tours por rota

Padrão recomendado (usado no pdv-agiliza): um mapa rota -> TourStep[] num componente de layout central (ex: o cabeçalho da aplicação), que só mostra o botão de ajuda quando a rota atual tem tour cadastrado:

const pageTours: Record<string, TourStep[]> = {
  '/': [...],
  '/pos': [...],
  '/finance': [...],
};

const steps = pageTours[pathname];
{steps && <BotaoAjuda onClick={() => setTourOpen(true)} />}

API

<PageTour />

| Prop | Tipo | Descrição | |---|---|---| | steps | TourStep[] | Passos do tour, em ordem. | | isOpen | boolean | Controla visibilidade. | | onClose | () => void | Chamado ao fechar (X, "Concluir", ou via renderCard). | | onStepChange? | (index: number) => void | Chamado a cada mudança de passo (inclui abertura, passo 0). | | renderCard? | (props: TourCardRenderProps) => ReactNode | Substitui o card default. | | classNames? | Partial<PageTourClassNames> | Classes CSS pro card default. Ignorado se renderCard for usado. | | labels? | Partial<PageTourLabels> | Textos dos botões/indicador (i18n). | | zIndex? | number | zIndex base do overlay (card usa zIndex + 10). Default 999999 — de propósito bem alto, pra vencer qualquer coisa que a página já tenha com z-index próprio (ex.: Leaflet usa 1000 nos controles de zoom por padrão). |

TourStep

interface TourStep {
  targetId: string;              // id do elemento-alvo no DOM
  title: string;
  content: string;
  position?: 'top' | 'bottom' | 'left' | 'right'; // default 'bottom'
}

useTourPosition(targetId, active, stepKey)

Hook headless usado internamente — exportado pra quem quiser construir uma UI de tour totalmente própria sem usar <PageTour>. Retorna { coords, isMobile }, recalculado em resize/scroll, com scroll-into-view automático quando o stepKey muda e o alvo está fora da área confortável da viewport.

Limitações conhecidas (v0.0.0 — versão mínima deliberada)

  • Sem persistência: não lembra se o usuário já viu o tour. Fica a cargo do produto (ex: salvar em localStorage ou no perfil do usuário).
  • Um elemento-alvo por passo — não há suporte a destacar múltiplos elementos simultaneamente.
  • framer-motion é peer dependency obrigatória, não opcional.