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 🙏

© 2025 – Pkg Stats / Ryan Hefner

tabistry

v0.0.0-experimental-70f6226

Published

Biblioteca React para gerenciamento de abas baseadas em rotas.

Downloads

102

Readme

Tabistry

Biblioteca React para gerenciamento de abas baseadas em rotas.

Instalação

npm install tabistry

ou

yarn add tabistry

Uso Básico

1. Definindo uma Tab

Primeiro, crie uma classe que estenda RouteTab:

import { RouteTab } from "tabistry";

interface UserParams {
  id: string;
}

class UserTab extends RouteTab<UserParams> {
  type = "user";

  renderTab({ onRemove, isSelected }) {
    return (
      <div className={isSelected ? "selected" : ""}>
        Usuário {this.params.id}
        <button onClick={onRemove}>x</button>
      </div>
    );
  }

  renderScreen() {
    return <UserDetails id={this.params.id} />;
  }
}

2. Configurando as Rotas

import { RouteDescriptor } from "tabistry";

const routes: RouteDescriptor<UserTab>[] = [
  {
    path: "/users/:id",
    tab: UserTab,
  },
];

3. Implementando o Provider

import { RouteTabs } from "tabistry";

function App() {
  const [tabs, setTabs] = useState<UserTab[]>([]);

  const handleAddTab = (tab: UserTab) => {
    setTabs((prev) => [...prev, tab]);
  };

  const handleRemoveTab = (tab: UserTab) => {
    setTabs((prev) => prev.filter((t) => t !== tab));
  };

  return (
    <RouteTabs
      tabs={tabs}
      routes={routes}
      onAddTab={handleAddTab}
      onRemoveTab={handleRemoveTab}
    />
  );
}

Exemplos Detalhados

Configuração de Rotas

import { RouteDescriptor } from "tabistry";

// 1. Defina suas tabs
class UserTab extends RouteTab<{ id: string }> {
  type = "user";
  // ...implementação da tab...
}

class ProductTab extends RouteTab<{ productId: string }> {
  type = "product";
  // ...implementação da tab...
}

// 2. Configure as rotas com suas respectivas tabs
const routes: RouteDescriptor[] = [
  {
    path: "/users/:id",
    tab: UserTab,
    element: <UserLayout />, // Layout opcional
    children: [
      {
        path: "profile",
        element: <UserProfile />,
      },
      {
        path: "settings",
        element: <UserSettings />,
      },
    ],
  },
  {
    path: "/products/:productId",
    tab: ProductTab,
    element: <ProductDetails />,
  },
];

Usando o Hook useRouteTabState

O hook useRouteTabState permite acessar e manipular o estado das tabs de qualquer lugar da aplicação:

import { useRouteTabState } from "tabistry";

function TabList() {
  const { tabs, tab, change, remove, isTabActive } = useRouteTabState();

  return (
    <div className="tab-list">
      {tabs.map((t) => (
        <div
          key={t.type}
          className={isTabActive(t) ? "active" : ""}
          onClick={() => change(t)}
        >
          {t.renderTab({
            onRemove: () => remove(t),
            isSelected: isTabActive(t),
          })}
        </div>
      ))}
    </div>
  );
}

Exemplo de Aplicação Completa

import { RouteTabs, useRouteTabState } from "tabistry";

// Componente de Layout
function Layout({ children }) {
  const { tabs, tab, change, remove, isTabActive } = useRouteTabState();

  return (
    <div>
      <header>
        <nav>
          {tabs.map((t) => (
            <TabButton
              key={t.type}
              tab={t}
              isActive={isTabActive(t)}
              onChange={change}
              onRemove={remove}
            />
          ))}
        </nav>
      </header>
      <main>{children}</main>
    </div>
  );
}

// Aplicação Principal
function App() {
  const [tabs, setTabs] = useState<(UserTab | ProductTab)[]>([]);

  const handleAddTab = (tab) => {
    setTabs((prev) => [...prev, tab]);
  };

  const handleRemoveTab = (tab) => {
    setTabs((prev) => prev.filter((t) => !t.equals(tab)));
  };

  return (
    <BrowserRouter>
      <RouteTabs
        tabs={tabs}
        routes={routes}
        onAddTab={handleAddTab}
        onRemoveTab={handleRemoveTab}
      >
        <Layout />
      </RouteTabs>
    </BrowserRouter>
  );
}

Funcionalidades do Hook useRouteTabState

O hook retorna um objeto com as seguintes propriedades:

  • tab - Tab atualmente ativa
  • tabs - Array com todas as tabs abertas
  • change(tab) - Função para mudar para uma tab específica
  • remove(tab) - Função para remover uma tab
  • isTabActive(tab) - Função que verifica se uma tab está ativa

API

RouteTab

Classe abstrata base para definição de tabs:

  • type: string - Identificador único do tipo da tab
  • params - Parâmetros da rota
  • query - Parâmetros da query string
  • renderTab(props: RenderTab) - Renderiza o conteúdo da aba
  • renderScreen() - Renderiza o conteúdo principal da aba
  • onFocus?() - Callback quando a aba recebe foco
  • onBlur?() - Callback quando a aba perde foco
  • onAdd?() - Callback quando a aba é adicionada
  • onRemove?() - Callback quando a aba é removida

RouteTabs Props

  • tabs - Array de tabs ativas
  • routes - Configuração das rotas
  • onAddTab - Callback quando uma nova tab é adicionada
  • onFocusTab - Callback quando uma tab recebe foco
  • onBlurTab - Callback quando uma tab perde foco
  • onRemoveTab - Callback quando uma tab é removida

Funcionalidades

  • Gerenciamento automático de estado das tabs
  • Sincronização com rotas do React Router
  • Suporte a parâmetros de rota e query string
  • Callbacks para eventos do ciclo de vida das tabs
  • Verificação de tabs ativas

Dicas e Boas Práticas

  1. Use o type da tab como identificador único
  2. Implemente o método equals na sua tab para comparação personalizada
  3. Mantenha a lógica de renderização dentro dos métodos renderTab e renderScreen
  4. Use os callbacks de ciclo de vida (onFocus, onBlur, etc) para efeitos colaterais