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

@rase-ui/react

v0.4.0

Published

RaseUI — componentes React sobre Base UI com o modelo de tema do Radix (variante ⊥ cor). Temável por CSS vars, sem domínio.

Downloads

217

Readme

@rase-ui/react

RaseUI — componentes React sobre Base UI (comportamento/a11y) com o modelo de tema do Radix (variante ⊥ cor). Sem domínio, temável pelo host por CSS vars.

O modelo vigente está em docs/DESIGN-SYSTEM.md — leia esse primeiro. O DESIGN.md/STYLES.md descrevem o sistema relief/skin antigo, ainda vivo nos componentes não migrados.

A doc de uso de cada componente vive co-localizada com o código, no README.md da pasta dele (linkado na tabela abaixo) — pra não dessincronizar doc e código.

pnpm --filter @rase-ui/react build       # tsup (esm) + tsc (.d.ts) + tailwind (css)
pnpm --filter @rase-ui/react typecheck
import { Modal } from "@rase-ui/react"; // barrel completo
import { Modal } from "@rase-ui/react/modal"; // ...ou granular (tree-shake)
import "@rase-ui/react/styles.css"; // uma vez, na raiz do app

Instalação

pnpm add @rase-ui/react
import "@rase-ui/react/styles.css"; // uma vez, na raiz do app

Isso basta. Sem classe nenhuma o app sai no modo dark (o default do kit); o claro é <Theme appearance="light">, ou a classe light num ancestral — é o que o provider emite. O tema embarcado é o default (src/foundation/themes/default.json, variantes light e dark), compilado pelo @csstokens/core no build; a camada de cor põe as escalas do mesmo modo no :root.

Peers

react e react-dom (18 ou 19). recharts e react-grid-layout são opcionais — só quem importa /chart ou /dashboard precisa deles.

ESM puro

O pacote não publica CJS: um require() não resolve. Use import. Em moduleResolution: "bundler" (Vite, Next, tsup) está tudo verde; em node16/nodenext também.

Tema — o provider <Theme>

O que transforma "componentes soltos" em produto único. Ele não é um segundo mecanismo: só emite num escopo os data-* que as camadas de CSS já traduzem — então trocar a marca de um app inteiro é uma prop, e o mesmo resultado se obtém escrevendo os atributos na mão se você preferir.

import { Theme } from "@rase-ui/react";

<Theme accentColor="tomato" grayColor="auto" radius="large" scaling="105%">
  <App />
</Theme>;

| prop | → | efeito | | ------------- | --------------------- | ------------------------------------------------ | | accentColor | data-accent | reponta --accent-* pra uma das 31 escalas | | grayColor | data-gray-color | o neutro; auto escolhe o que casa com o accent | | radius | data-radius | none · small · medium · large · full | | scaling | data-scaling | zoom global: 90%110% | | appearance | classe light/dark | pinta o fundo do escopo |

É aninhável (herda por Context o que você não redefinir), e os atributos valem em qualquer elemento — <div data-radius="small"> escopa o raio sem provider nenhum. Detalhes em src/base/theme/README.md.

Eixos

Variante = estrutura (solid/soft/surface/…) e cor = ortogonal (color="tomato") — o oposto do shadcn, onde a cor está presa na variante. Tamanho é size="1..4" no componente; data-scaling é o zoom global; data-radius escopa o raio em qualquer elemento.

Não existe eixo de densidade. O [data-density] foi removido: era um zoom não-uniforme travestido de eixo de tema. Um painel denso declara as próprias métricas --ui-* localmente.

Fontes — o kit não carrega nenhuma

Ele só declara os stacks (--font-sans/--font-serif/--font-mono). Uma biblioteca de componentes não deve forçar 300KB de download em ninguém — e o Radix Themes também não embarca fonte.

Quem quer as nossas — Geist (sans) · Newsreader (serif) · Geist Mono (mono), as três variáveis — instala e importa:

pnpm add @fontsource-variable/geist @fontsource-variable/geist-mono @fontsource-variable/newsreader

Sem elas o kit cai no stack de sistema e continua funcionando. Por que essas três, e por que trocar a sans re-calibra as outras duas: DESIGN-SYSTEM.md §8.4.

[!WARNING] O kit aplica a família no :root e os componentes herdam — nenhum .ui-* declara font-family. Um body { font-family: system-ui, sans-serif } no app (o boilerplate de qualquer template) troca a fonte de todos os componentes, e a falha é muda: nada quebra, o layout monta, e o texto passa a sentar ~1px mais baixo em botões, campos e badges — porque a métrica vertical da fonte de sistema é outra. Pra trocar a fonte do kit, redefina --font-sans; pra não trocar, não declare font-family no body (ou declare var(--font-sans)).

O que o kit resolve sozinho — e o que ainda não

O kit traz o próprio reset escopado (não exige Tailwind), o tema default com os dois modos e a geometria default: import "@rase-ui/react/styles.css" e acabou. Um app que quer o próprio tema ou a própria geometria compila os dois JSON publicados com o @csstokens/core e importa o components.css no lugar do styles.css (seção abaixo); a prova rodando é o apps/consumer do monorepo — o app que consome o dist como um terceiro, sem alias e sem preflight.

O que ainda não fecha sozinho: o components.css sem os defaults ainda precisa dos --theme-* do sistema relief (skin.css e tooltip.css leem cru). Nada do base/ depende disso; é o que sobra fora dele, e sai com o relief (TODO.md §2).

[!WARNING] O playground não serve de prova de que o pacote funciona instalado: ele consome o src (condição rase-source) e carrega o preflight do Tailwind. Foi assim que o .d.ts sem tipos e o "use client" descartado passaram meses invisíveis. Mediu no playground, meça também no apps/consumer.

Compilar os próprios tokens (o caminho do csstokens)

O styles.css é o feijão com arroz: instalou, importou, funciona. Mas o kit também publica a FONTE, pra um app fazer o que se faz com Tailwind — puxar o preset, estender, e compilar no próprio build:

| artefato | o quê | | --- | --- | | @rase-ui/react/struct/struct.json | o preset de arquitetura — radius, tipografia, containers, z-index, movimento | | @rase-ui/react/struct | o compilador (renderStruct) + extendTokens | | @rase-ui/react/themes/*.json | os temas: default.json (o que o kit embarca) e o catálogo (ocean) | | @rase-ui/react/components.css | o kit sem os defaults de token — 19,2KB a menos que o styles.css | | @rase-ui/react/manifest · /manifest/manifest.json | as peças como dado — o descriptor de cada type (props com enum e default, slots, eventos), pra um montador que não é código. Sem React | | @rase-ui/react/registry | o manifest com os componentes: as tuplas [type, Component, descriptor] que um host registra num motor |

import { extendTokens, renderStruct } from "@rase-ui/react/struct";
import preset from "@rase-ui/react/struct/struct.json" with { type: "json" };
import * as engine from "@csstokens/core";

const { css } = renderStruct(extendTokens(preset, meuPatch), engine);

Dá pra estender qualquer nó, inclusive as bases das escalas — que é onde importa, porque aí você muda o número sem copiar a fórmula (radius.base.3, font.serif-adjust).

Use o renderStruct, não o renderStylesheet cru. Emitir geometria tem um segundo bloco obrigatório — a recomputação em :where(.rase-theme, [data-radius], [data-scaling]). Sem ele, var() resolve no :root e um <Theme scaling> não faz nada; pior, a geometria do kit volta dentro de qualquer <Theme>. A regra é do sistema, não de cada app.

@csstokens/core é peer opcional: só quem compila precisa. E arquitetura ⊥ tema — são dois TokenSets, duas compilações, dois arquivos. O apps/consumer do monorepo é o exemplo rodando.

Build & packaging

  • ESM (dist/*.js) → tsup, um bundle por subpath. É ESM puro: não publicamos CJS, então um require() não resolve — use import.
  • Tipos (dist/types/**) → tsc -p tsconfig.build.json, não o dts do tsup: com 51 entries o rollup-plugin-dts estoura a memória e o processo morre sem falhar alto — o ESM saía, o .d.ts não, e o pacote era publicado sem tipos. Não voltar pro dts: true.
  • Import relativo no src leva extensão (from "./x.js", from "./x/index.js"), mesmo o alvo sendo .ts. O tsc copia o specifier pro .d.ts como está — sem a extensão, o consumidor em node16/nodenext recebe TS2307 apontando pro nosso tipo. Cobrado pelo pnpm check:imports, que roda antes do build.
  • "use client" é reinserido depois do tsup (pnpm build:directives) — o esbuild descarta a diretiva, e sem ela o pacote quebra em consumidor RSC.
  • Tokenspnpm build:theme (cor, themes/default.json) e pnpm build:struct (geometria, struct/struct.json), os dois via @csstokens/core; pnpm build:relief compila o que resta do relief (fork jsoncss). O build:struct também copia o preset e o catálogo de temas pro dist/ — é o que faz o caminho "compilo no meu app" existir.
  • CSS (dist/*.css) → Tailwind, um entry por camada (styles, components, structure; e os do relief em legacy/: skin, controls, inspector). Mais a camada de cor fatiada em dist/accent/, que é CSS puro (só custom properties) e por isso vai pro artefato sem passar pelo Tailwind — ver "Enxugar a camada de cor" abaixo.
  • O exports tem uma condição rase-source que aponta pro src/: é o playground pedindo o source (HMR). Um consumidor normal nunca a pede e cai no dist. É custom de propósito — com development, qualquer app Vite em dev tentaria carregar nosso src/*.tsx, que não é publicado (files: ["dist"]).

Enxugar a camada de cor

import "@rase-ui/react/styles.css" traz tudo e continua sendo o caminho certo pra começar. Só que dentro dele a camada de cor sozinha é 17 KB gzip — mais de um terço do CSS do kit — porque ela carrega as 31 escalas nomeadas do eixo color. E ela não sai por tree-shaking: CSS não é tree-shaken, e um [data-accent="tomato"] só é "usado" em runtime.

Quem monta o próprio bundle pode trocar isso pelo piso mais as hues que usa:

@import "@rase-ui/react/accent/base.css"; /* 2,2 KB — accent + gray + indigo */
@import "@rase-ui/react/accent/hues/tomato.css"; /* +0,6 KB, só se usar color="tomato" */

O piso já cobre o caso comum: o --accent-* do tema (com fallback indigo), o --gray-* global, os alphas neutros e os eixos color="gray" / color="indigo" / <Theme grayColor>. Cada hue extra custa ~890 B gzip. Detalhes em DESIGN-SYSTEM.md §6.1.

Organização do source

O src/ é agrupado por papel (os subpaths públicos não seguem as pastas — são planos e estáveis: @rase-ui/react/button continua igual):

| Pasta | O quê | | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | foundation/ | máquina de tokens/skin/tema + helpers — internal, prop-def, accent, tokens, skin, presets, theme, schema | | base/ | CONTROLES atômicos e primitivos de apresentação — button, icon-button, badge, checkbox, card, container, textfield, input, select, combobox, dropdown-menu, table, typography, avatar, image, inset, data-list, list-row, segmented-control, skeleton, line-loader, drawer, structure, chat, chat-core, theme | | effects/ | EFFECTS — decoração pura: backdrop, animated-border. Sem valor, sem estado, sem papel de a11y (§ abaixo) | | overlays/ | camadas flutuantes ainda não migradasmodal, dynamic-modal, popover, tooltip, context-menu, command | | layout/ | estrutura & containers — resizable, collapsible, nav | | forms/ | editores de valor — controls | | data/ | exibição de dados & widgets — primitives, chart, json-view, json-editor, node, widget, combine, dashboard, signal | | complex/ | compostos (compõem os primitivos) — data-table, inspector, kanban, presence-rail, app-header, notifications | | manifest/ | as peças como dado — o descriptor de cada type (derivado dos props.ts + o catálogo declarado) e o registry com os componentes. Ver src/manifest/README.md | | styles/ | CSS centralizado — tokens, os 3 skins compartilhados (control.css, popup.css, material.css) e um por componente |

Packages próprios (compõem sobre este kit): o grafo node-edge @rase-ui/flow (flow + connector), o @rase-ui/chat (chat humano) e o @rase-ui/assistant (chat de IA). A fundação compartilhada dos chats fica aqui em base/chat-core (@rase-ui/react/chat-core).

A regra: base (primitivos) ≠ complex (compostos), e foundation isola a máquina que todos importam. Mover um módulo de pasta não muda seu subpath — só o entry do tsup.config.ts.

effects/ — a terceira categoria

base e complex não davam conta de tudo: um backdrop não é controle (não interage, não tem valor nem estado nem role) e não é complex (não compõe nada — é folha). O teste: se você remover, a página continua funcionando igual, só fica mais feia; se remover quebra uma interação, não é effect.

A regra de composição completa (e por que o nome vem do vocabulário que o projeto já tinha) está em DESIGN-SYSTEM.md §10.

Os compostos vêm em duas camadas

Um componente de complex/ que carrega dados (/kanban, /data-table) vem em duas peças que se encaixam, nunca numa só:

| | /kanban | /data-table | | --------------------------- | ----------------------------- | ------------------- | | o pronto, config-driven | <KanbanBoard columns cards> | <DataTable table> | | o compound por baixo | KanbanRoot+Column+Card | base/table | | o estado, puro | moveCard / useKanbanBoard | useDataTable |

Comece pelo pronto; desça pro compound quando ele não der conta. O escape hatch está sempre aberto, e a camada de cima não ganha prop que a de baixo já resolve — é o que impede o componente de 40 props.

Componentes

Um subpath por peça, todos planos (@rase-ui/react/<nome>) — a pasta em que o source mora não aparece aqui, e mover um módulo de pasta não muda o subpath dele.

Base — controles e primitivos de apresentação

| Subpath | Doc | O quê | | -------------------- | ------------------------------------------- | ------------------------------------------------------------------------------------------ | | /button | | botão — variante = estrutura (solid/soft/surface/outline/ghost) · cor ⊥ | | /icon-button | | o botão quadrado — mesmos eixos do Button, caixa = altura. aria-label é obrigatório | | /badge | | chip de status — solid/soft/surface/outline · cor ⊥ · sizes 1·2·3 | | /checkbox | | checkbox — surface/soft/outline · checked/indeterminate | | /switch | | o irmão do Checkbox — a trilha que muda de cor deslizando; --radius-thumb | | /textfield | | campo de texto — surface/classic/soft · Slots · Field (label/erro) | | /select | | Select sobre Base UI — o valor é um item, sem digitar | | /combobox | | Combobox — o select BUSCÁVEL (digita pra filtrar; chips no multi) | | /dropdown-menu | | menu de AÇÕES sobre Base UI Menu — composição + data-driven (DropdownItem[]) | | /segmented-control | | escolher um de N modos — "Grade | Lista | Tabela" | | /tabs | | as abas — N vistas do mesmo objeto; underline/soft/outline, o indicador desliza; abas como navegação | | /breadcrumb | | a trilha; um segmento com items vira switcher (time › projeto) | | /dialog | | o modal centrado sobre Base UI — size 1..4, modal, dismissible; o pronto e o compound | | /drawer | | a superfície que entra pela borda — side, size (a espessura), modal={false} | | /tooltip | | a anotação flutuante sobre Base UI — invertida, seta fundida; o filho é o gatilho | | /toast | | o aviso temporário — <Toaster> + toast() chamável de fora do React | | /calendar | | o Calendar do shadcn (react-day-picker), instalado como veio — a receita é pendente | | /card | | container — surface/classic/ghost/acrylic/mica · slots · interativo via render | | /box · /flex · /grid · /spacer | | os primitivos de arranjo — gap/p na escala de espaço; Grid com span responsivo por container e columns="auto" | | /container | | capa a largura de um bloco de conteúdo e centraliza (a escala --container-1..5) | | /inset | | o conteúdo sangra até a borda do container (lê o --inset-* que o Card publica) | | /image | | aspect-ratio + object-fit, sem wrapper | | /avatar | | a foto do usuário — vira ícone ou iniciais quando não há foto | | /typography | | Text/Heading/Code/… na escala de 9 passos · eixo font · trim | | /table | | o <table> do Radix — apresentação pura (<th scope>), ghost/surface, sticky | | /data-list | | pares label/valor num <dl> semântico | | /list-row | | a linha de lista com ação principal + ações que aparecem no hover (a vaga, §9.6) | | /dot | | o indicador — size 1·2·3, solid/soft, cor ⊥ (o não-lido, a presença, o grau) | | /separator | | a divisória do Base UI — orientation, size, color | | /toolbar | | a barra de ferramentas — o RITMO: gap de família na barra, de irmãos no grupo, ToolbarSpacer | | /skeleton | | o placeholder de carregamento — funde no elemento, herda o raio dele | | /line-loader | | barra de progresso indeterminada, dep-free e tokenizada | | /structure | | layouts headless por REGIÃO: AppStructure, PageStructure, View, Section | | /nav | | o NavMenu data-driven — size com caixa fixa de ícone (16·24·32), badges, grupos, rail | | /chat | | primitivas de chat headless (data-driven; não sabem de transporte) | | /chat-core | | a fundação compartilhada dos chats (avatar, typing, markdown, auto-scroll) | | /theme | | o provider <Theme> (accent · gray · radius · scaling · appearance) |

Effects

| Subpath | Doc | O quê | | ------------------ | -------------------------------------------- | -------------------------------------------------------------------------------------- | | /backdrop | | fundos decorativos (aurora, camadas) — aria-hidden, sem interação | | /animated-border | | borda animada correndo (rect SVG, pathLength=100) — comet ou marching ants; active/from | | /page-transition | | a entrada de rota, mount-only, em --motion-duration-page + --motion-ease-standard |

Data & widgets

| Subpath | Doc | O quê | | -------------- | ------------------------------------- | ----------------------------------------------------------------------------- | | /primitives | | primitivos de display white-label pra widget (recebem valor pronto) | | /chart | | primitivos de gráfico white-label sobre Recharts, nos tokens do kit | | /node | | descritores de nó JSON + <NodeRenderer> — o que torna o widget serializável | | /widget | | o <Widget> config-driven ({ type, data, template }) | | /dashboard | | grid de widgets combináveis, data-driven | | /combine | | superfície drag-drop + seleção headless, agnóstica do combiner | | /signal | | introspecção de elementos + anotação visual, headless | | /json-view | | visualizador de JSON read-only (árvore colapsável) | | /json-editor | | editor de JSON sobre o Monaco + modal de edição imperativo |

Complex — compostos sobre os primitivos

| Subpath | Doc | O quê | | -------------------- | --------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | | /data-table | | o MOTOR (TanStack) — ordena/filtra/pagina/seleciona. Compõe o /table | | /kanban | | board de funil — <KanbanBoard columns cards> pronto e o compound por baixo; arraste por ponteiro e teclado | | /presence-rail | | a faixa de presença da equipe — quem está online, não-lidas, a conversa aberta | | /app-header | | a barra global em cinco zonas (nav · brand · scope ··· search · primary · tools · account), cada uma dado ou nó; os eventos na raiz | | /notifications | | a caixa de entrada sem domínio — NotificationList (itens prontos) e o NotificationsDrawer não-modal | | /complex/inspector | | painel de propriedades (Photoshop/Blender) + variante resizable — fora do barrel: compõe o legacy/controls |

legacy/* — o que ainda veste o sistema relief

Estes subpaths não são API do RaseUI: vestem o relief, não saem pelo barrel e não têm garantia de semver. Cada um sai da lista quando o equivalente no modelo nascer (Popover, Modal, Tooltip → Base UI) ou quando o relief morrer. O legacy/input (o TextField ocupou o papel) e o legacy/theme-manifest (o applier de manifest JSON, anterior ao tema compilado) são delete pendente de consumidor.

Overlays — camadas flutuantes (ainda em Radix/cmdk)

| Subpath | Doc | O quê | | ---------------- | ------------------------------------------- | -------------------------------------------------------------- | | /legacy/modal | | overlay controlado (portal, backdrop, focus-trap, scroll-lock) | | /legacy/dynamic-modal | | modal imperativo que devolve uma Promise | | /legacy/popover | | Radix Popover (camada flutuante interativa) | | /legacy/tooltip | | Radix Tooltip (self-contained) | | /legacy/context-menu | | menu de contexto estilo programa (mata o do navegador) | | /legacy/command | | paleta ⌘K data-driven sobre cmdk |

Layout e formulário

| Subpath | Doc | O quê | | ------------------ | -------------------------------------------- | -------------------------------------------------------------------------------------- | | /legacy/resizable | | re-export do react-resizable-panels + handle nos tokens | | /legacy/collapsible | | Radix Collapsible (base do accordion) | | /legacy/nav | | menu de navegação data-driven (sidebar/rail) — não conhece router | | /legacy/controls | | editores de valor: Number, Range, Select, Toggle, Text, Segmented, Vector, Color, Tags |

Fundação do relief

| Subpath | Doc | O quê | | ---------- | --------------------------------------- | ------------------------------------------------------------------------------------- | | /legacy/skin | | SkinLayer: camada de fundo (folha) no padrão 2 camadas — sistema relief, legado | | /legacy/presets | | o catálogo curado de superfícies sobre o skin — sistema relief, legado | | /legacy/tokens | | o fork jsoncss que alimenta o relief (pnpm build:relief) — legado, morre com ele |

Tokens e a referência de estilo: docs/STYLES.md.

Schema engine (WIP)

A camada declarativa (JSON → render: inspector / form / página nocode pela mesma engine) tem os contratos definidos em src/foundation/schema/model.ts (dados puros, sem React) e render.ts (o registry). O runtime e a integração com o state/cook estão pendentes, e por isso o módulo ainda não tem subpath público: onde a engine vai morar (subpath daqui vs. pacote de contratos próprio) é decisão em aberto.

Stack

Tailwind v4 (@theme, sem preflight) · Base UI (select, combobox, menu — o comportamento das peças migradas) · Radix UI (collapsible, dialog, popover, tooltip, slider, switch, toggle-group — o que ainda não migrou) · TanStack Table (motor do /data-table) · react-resizable-panels v3 · cmdk (paleta ⌘K) · Monaco (/json-editor) · Recharts (/chart) · react-colorful + @uiw/react-color (color). Tudo external no bundle: nada disso é duplicado dentro do artefato publicado.