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

pgx-theme-resolver

v1.0.0

Published

Dynamic theme resolver library for PGX projects. Converts API theme tokens into CSS custom properties with a 3-layer architecture (primitives, semantic, Tailwind).

Readme

pgx-theme-resolver

Biblioteca dinâmica de resolução de temas para projetos PGX. Converte tokens de tema vindos de API ou JSON em CSS custom properties com arquitetura de 3 camadas (primitivos, semânticos, Tailwind).

Arquitetura

┌─────────────────────────────────────────────────────────────┐
│                        API / JSON                           │
│  { "Colors": { "CTA Colors": { "50": { hex: "#f5f4fe" } }} │
└──────────────────────────┬──────────────────────────────────┘
                           │
                    normalizePrimitiveTokens()
                           │
                           ▼
┌─────────────────────────────────────────────────────────────┐
│              Camada 1: CSS Vars Primitivos                  │
│  --cta-50: #f5f4fe   --brand-950: #0b0b0b                  │
│  --cta-op-50: rgba(245,244,254,0.5)                        │
└──────────────────────────┬──────────────────────────────────┘
                           │
                    referenciados via var()
                           │
                           ▼
┌─────────────────────────────────────────────────────────────┐
│              Camada 2: CSS Vars Semânticos                  │
│  --bg-page: var(--brand-950)                                │
│  --text-primary: var(--brand-50)                            │
│  --action-primary: var(--cta-600)                           │
└──────────────────────────┬──────────────────────────────────┘
                           │
                    @theme inline / config
                           │
                           ▼
┌─────────────────────────────────────────────────────────────┐
│              Camada 3: Tailwind Utilities                   │
│  bg-bg-page  text-text-primary  border-action-primary       │
└─────────────────────────────────────────────────────────────┘

Quando os primitivos mudam (via API), os semânticos atualizam automaticamente pela cascata CSS.

Instalação

# Via npm/pnpm/yarn
pnpm add pgx-theme-resolver

# Ou link local (desenvolvimento)
cd pgx-theme-resolver && pnpm install && pnpm build
cd ../seu-projeto && pnpm add ../pgx-theme-resolver

CLI — Geração de arquivos estáticos

Para projetos que preferem ter os arquivos de tema gerados estaticamente (sem resolução dinâmica), a lib oferece dois comandos CLI via npx:

npx pgx-theme generate-styles

Gera um arquivo CSS completo com :root vars (primitivos + semânticos + estáticos + fades + shadows). Se Tailwind CSS 4 for detectado no projeto (ou --tw4 for passado), inclui automaticamente o bloco @theme inline com os mapeamentos de cores.

# Gera src/styles/pgx-theme.css (detecta Tailwind automaticamente)
npx pgx-theme generate-styles

# Força Tailwind 4 (@theme inline incluído)
npx pgx-theme generate-styles --tw4

# Gera apenas :root vars, sem Tailwind
npx pgx-theme generate-styles --no-tailwind

# Output customizado
npx pgx-theme generate-styles --out=src/theme/variables.css

Arquivo gerado (com --tw4):

/* pgx-theme-resolver — Generated CSS */

:root {
  /* ── Primitivos ── */
  --cta-50: #f5f4fe;
  --cta-600: #754dda;
  --brand-950: #0b0b0b;
  /* ... 60+ primitivos ... */

  /* ── Semânticos ── */
  --bg-page: var(--brand-950);
  --text-primary: var(--brand-50);
  --action-primary: var(--cta-600);
  /* ... 50+ semânticos ... */

  /* ── Fades / Shadows ── */
  --fade-primary-default: linear-gradient(180deg, var(--cta-600) 0%, var(--cta-500) 100%);
  --shadow-primary: 0px 10px 15px var(--cta-op-700);
  /* ... */
}

/* ── Tailwind CSS 4 ── */
@theme inline {
  --color-bg-page: var(--bg-page);
  --color-text-primary: var(--text-primary);
  --color-cta-600: var(--cta-600);
  /* ... 120+ cores utilitárias ... */
}

Depois basta importar no seu globals.css:

@import "tailwindcss";
@import "./pgx-theme.css";

npx pgx-theme generate-tw-config

Gera um arquivo TypeScript (ou JavaScript) com o objeto de cores para Tailwind CSS 3. Detecta automaticamente se o projeto usa TS ou JS.

# Gera config/tailwind-theme-colors-config.ts (ou .js)
npx pgx-theme generate-tw-config

# Força JavaScript
npx pgx-theme generate-tw-config --js

# Output customizado
npx pgx-theme generate-tw-config --out=src/config/theme-colors.ts

Arquivo gerado (TypeScript):

/* pgx-theme-resolver — Tailwind CSS 3 Color Config */

export const themeColors = {
  /* ── bg ── */
  "bg-page": "var(--bg-page)",
  "bg-surface-primary": "var(--bg-surface-primary)",

  /* ── text ── */
  "text-primary": "var(--text-primary)",

  /* ── action ── */
  "action-primary": "var(--action-primary)",

  /* ── cta (primitivos) ── */
  "cta-50": "var(--cta-50)",
  "cta-600": "var(--cta-600)",
  /* ... 122 cores no total ... */
} as const;

export type ThemeColorKey = keyof typeof themeColors;

Uso no tailwind.config.ts:

import { themeColors } from "./config/tailwind-theme-colors-config";

export default {
  theme: {
    extend: {
      colors: themeColors,
    },
  },
};

Flags da CLI

| Comando | Flag | Descrição | |---------|------|-----------| | generate-styles | --out=<path> | Caminho do output (default: src/styles/pgx-theme.css) | | | --tw4 | Força inclusão do @theme inline | | | --tw3 | Não inclui @theme inline | | | --no-tailwind | Gera apenas :root vars | | generate-tw-config | --out=<path> | Caminho do output (default: config/tailwind-theme-colors-config.ts) | | | --ts | Força TypeScript | | | --js | Força JavaScript |


Quick Start

1. Básico — Aplicar tema da API no DOM

import {
  resolveThemeFromApi,
  applyTheme,
} from "pgx-theme-resolver";

// Dados vindos da API (ou mock)
const apiData = {
  Colors: {
    "CTA Colors": {
      "50": { hex: "#f5f4fe" },
      "100": { hex: "#edebfc" },
      "600": { hex: "#754dda" },
      "900": { hex: "#472a88" },
    },
    "Brand Colors": {
      "50": { hex: "#fafafa" },
      "900": { hex: "#141414" },
      "950": { hex: "#0b0b0b" },
    },
  },
  "Opacity Colors": {
    "CTA Colors": {
      "600": { hex: "#754dda", alpha: 0.5 },
    },
  },
};

// Resolve → aplica
const vars = resolveThemeFromApi(apiData);
applyTheme(vars);

2. SSR (Next.js App Router)

// app/layout.tsx
import {
  fetchAndResolveTheme,
  getDefaultTheme,
} from "pgx-theme-resolver";
import { ThemeStyle } from "pgx-theme-resolver/react";

export default async function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  const vars =
    (await fetchAndResolveTheme({
      url: `${process.env.API_URL}/themes`,
    })) ?? getDefaultTheme();

  return (
    <html>
      <head>
        <ThemeStyle vars={vars} id="pgx-theme" />
      </head>
      <body>{children}</body>
    </html>
  );
}

3. React Hook (Client-side)

import { useTheme } from "pgx-theme-resolver/react";

function ThemeLoader() {
  const { setTheme } = useTheme();

  useEffect(() => {
    fetch("/api/themes")
      .then((r) => r.json())
      .then((data) => setTheme(data.value));
  }, [setTheme]);

  return null;
}

4. Gerar <style> tag como string (SSR genérico)

import {
  resolveThemeFromApi,
  buildStyleTag,
} from "pgx-theme-resolver";

const vars = resolveThemeFromApi(apiData);
const css = buildStyleTag(vars);
// → ":root{--cta-50:#f5f4fe;--brand-950:#0b0b0b;...}"

// Injetar no HTML:
const html = `<html><head><style>${css}</style></head>...</html>`;

5. Formato legado/simplificado (JSON plano)

import { resolveThemeFromJson, applyTheme } from "pgx-theme-resolver";

const json = {
  bg: { page: "#080816", surfacePrimary: "#1F1F40" },
  text: { primary: "#E6E6F8" },
  action: { primary: "#0062FF" },
};

const vars = resolveThemeFromJson(json);
applyTheme(vars);

6. Resposta completa da API

import {
  resolveThemeFromResponse,
  applyTheme,
} from "pgx-theme-resolver";

const response = await fetch("/api/themes").then((r) => r.json());
// response = { id, name, active, value: {...}, ... }

const vars = resolveThemeFromResponse(response);
applyTheme(vars);

Integração com Tailwind CSS

Tailwind CSS 4 (@theme inline)

import { generateTailwindThemeBlock } from "pgx-theme-resolver";

const block = generateTailwindThemeBlock();
console.log(block);

Cole o output no seu globals.css:

@import "tailwindcss";

/* ... seus :root vars ... */

@theme inline {
  /* output do generateTailwindThemeBlock() */
  --color-bg-page: var(--bg-page);
  --color-text-primary: var(--text-primary);
  --color-action-primary: var(--action-primary);
  --color-cta-600: var(--cta-600);
  /* ... */
}

Agora você pode usar: bg-bg-page, text-text-primary, bg-cta-600, etc.

Tailwind CSS 3 (tailwind.config.js)

const { generateTailwindV3Colors } = require("pgx-theme-resolver");

module.exports = {
  theme: {
    extend: {
      colors: generateTailwindV3Colors(),
    },
  },
};

API Reference

Resolvers

| Função | Input | Descrição | |--------|-------|-----------| | resolveThemeFromApi(value, options?) | ThemeApiValue | Resolve tokens do formato da API PGX | | resolveThemeFromResponse(response, options?) | ThemeApiResponse | Resolve a partir da resposta completa do endpoint | | resolveThemeFromJson(json, options?) | ThemeJson | Resolve a partir do formato legado/simplificado | | getDefaultTheme(overrides?) | — | Retorna tema padrão (fallback) |

DOM

| Função | Descrição | |--------|-----------| | applyTheme(vars, options?) | Aplica CSS vars via style.setProperty() | | clearTheme(target?) | Remove todas as CSS vars inline | | buildStyleTag(vars, selector?) | Gera string CSS (:root{...}) | | buildStyleElement(vars, id?, selector?) | Cria <style> element |

Fetch

| Função | Descrição | |--------|-----------| | fetchAndResolveTheme(options) | Busca + resolve em uma chamada | | fetchThemeValue(options) | Busca apenas o ThemeApiValue bruto |

Normalize (low-level)

| Função | Descrição | |--------|-----------| | normalizePrimitiveTokens(json, groupMap?) | Converte formato API → CSS vars | | normalizeThemeJson(json) | Converte formato legado → CSS vars |

Tailwind

| Função | Descrição | |--------|-----------| | generateTailwindThemeBlock(extra?) | Gera @theme inline { ... } para TW4 | | generateTailwindV3Colors() | Gera objeto de cores para TW3 config |

React (pgx-theme-resolver/react)

| Export | Tipo | Descrição | |--------|------|-----------| | useTheme(options?) | Hook | Resolve + aplica temas dinamicamente | | ThemeStyle | Component | <style> tag para SSR |

CLI

| Comando | Descrição | |---------|-----------| | npx pgx-theme generate-styles | Gera CSS com :root + @theme inline (TW4) | | npx pgx-theme generate-tw-config | Gera arquivo de cores para tailwind.config (TW3) |

Constantes exportadas

| Constante | Descrição | |-----------|-----------| | DEFAULT_GROUP_MAP | Mapeamento de grupos API → prefixos CSS | | DEFAULT_SEMANTIC_TOKENS | Tokens semânticos padrão (camada 2) | | DEFAULT_PRIMITIVES | Cores primitivas padrão (fallback) | | STATIC_TOKENS | Tokens estáticos (gamification) | | TAILWIND_COLOR_MAP | Mapeamento semântico → Tailwind |

Customização

Mapeamento de grupos customizado

Se a sua API usa nomes de grupo diferentes:

const vars = resolveThemeFromApi(apiData, {
  groupMap: {
    "Primary Colors": "cta",    // mapeia "Primary Colors" → --cta-*
    "Neutral Colors": "brand",  // mapeia "Neutral Colors" → --brand-*
  },
});

Tokens semânticos customizados

Sobrescreva ou adicione tokens semânticos:

const vars = resolveThemeFromApi(apiData, {
  semanticTokens: {
    "--bg-page": "var(--cta-1100)",        // sobrescreve
    "--bg-custom": "var(--brand-800)",     // adiciona novo
  },
});

Aplicar em elemento específico

applyTheme(vars, {
  target: document.getElementById("my-app")!,
  cleanPrevious: true,
});

Formato dos dados da API

Formato principal (ThemeApiValue)

{
  "Colors": {
    "CTA Colors": {
      "50": { "hex": "#f5f4fe" },
      "100": { "hex": "#edebfc" },
      "600": { "hex": "#754dda" },
      "900": { "hex": "#472a88" }
    },
    "Brand Colors": {
      "50": { "hex": "#fafafa" },
      "950": { "hex": "#0b0b0b" }
    },
    "Green": {
      "400": { "hex": "#10b981" }
    }
  },
  "Opacity Colors": {
    "CTA Colors": {
      "600": { "hex": "#754dda", "alpha": 0.5 }
    }
  }
}

Formato legado (ThemeJson)

{
  "bg": {
    "page": "#080816",
    "surfacePrimary": "#1F1F40"
  },
  "text": {
    "primary": "#E6E6F8"
  },
  "action": {
    "primary": "#0062FF"
  }
}

Resposta completa (ThemeApiResponse)

{
  "id": "uuid",
  "name": "dark-purple",
  "active": true,
  "allowedUsers": null,
  "value": { /* ThemeApiValue */ },
  "createdAt": "2024-01-01T00:00:00Z",
  "updatedAt": "2024-01-01T00:00:00Z"
}

Tokens disponíveis

Primitivos (Camada 1)

| Grupo | Shades | Exemplo | |-------|--------|---------| | CTA | 50-1100 (14 shades) | --cta-600: #754dda | | Brand | 50-950 (11 shades) | --brand-950: #0b0b0b | | Green | 50, 200, 400, 800 | --green-400: #10b981 | | Yellow | 100, 300, 500, 800 | --yellow-500: #ffc801 | | Special | 100, 300, 500, 800 | --special-300: #fcbb4d | | Red | 100, 300, 500, 800 | --red-500: #ef4444 |

Cada grupo tem variantes de opacidade: --cta-op-600, --brand-op-800, etc.

Semânticos (Camada 2)

| Categoria | Tokens | |-----------|--------| | Background | --bg-page, --bg-surface-primary, --bg-surface-secondary, --bg-on-surface-primary, --bg-border-primary, --bg-border-secondary, --bg-page-border | | Text | --text-primary, --text-secondary, --text-tertiary, --text-inverse, --text-disabled, --text-special | | Icon | --icon-primary, --icon-secondary, --icon-disabled, --icon-special | | Success | --semantic-success, -container, -on-container, -border-container | | Warning | --semantic-warning, -container, -on-container, -border-container | | Error | --semantic-error, -container, -on-container, -border-container | | Info | --semantic-info, -container, -on-container, -border-container | | Action Primary | --action-primary, -on-primary, -hover, -pressed, -disabled, -border | | Action Secondary | --action-secondary, -active, -on-secondary, -hover, -pressed, -disabled, -border | | Action Special | --action-special, -on-special, -hover, -pressed, -border | | Input | --input-rest-primary, -rest-secondary, -hover, -active, -border-*, -on-container-* |

Estáticos

| Categoria | Tokens | |-----------|--------| | Gamification Bronze | --gamification-bronze, -container, -border-container, -on-container | | Gamification Prata | --gamification-prata, -container, -border-container, -on-container | | Gamification Ouro | --gamification-ouro, -container, -border-container, -on-container |

Uso com Mock (desenvolvimento)

import {
  getDefaultTheme,
  applyTheme,
  DEFAULT_PRIMITIVES,
} from "pgx-theme-resolver";

// Usa o tema padrão completo
applyTheme(getDefaultTheme());

// Ou sobrescreve apenas alguns primitivos
applyTheme({
  ...getDefaultTheme(),
  "--cta-600": "#ff0000",
  "--brand-950": "#000033",
});

TypeScript

Todos os tipos são exportados:

import type {
  ThemeApiValue,
  ThemeApiResponse,
  ThemeJson,
  CssVarMap,
  SemanticTokenMap,
  GroupMap,
  ThemeResolverOptions,
  FetchThemeOptions,
} from "pgx-theme-resolver";

Playground

O projeto inclui um playground interativo com Vite para testar os 4 temas mock em tempo real, com 3 variantes de switcher (select, tabs, radio) e preview visual de todos os tokens.

pnpm install
pnpm playground
# → http://localhost:5173

O playground mostra:

  • Select — dropdown para trocar de tema
  • Switcher (Tabs) — botões side-by-side com highlight no ativo
  • Radio Buttons — com nome e descrição de cada tema
  • Theme Preview — textos, backgrounds, paletas CTA/Brand, botões de ação, estados semânticos, gradients, shadows, inputs, icons e gamification

Todas as cores atualizam em tempo real ao trocar de tema.

Build

pnpm install
pnpm build       # Gera dist/ (CJS + ESM + types + CLI)
pnpm typecheck   # Verifica tipos
pnpm test        # Executa testes
pnpm playground  # Abre playground interativo (Vite)

License

MIT