@grupo-elo-editorial/shared-ui-react
v1.1.0
Published
Grupo ELO Editorial — React component library. Multibrand-aware primitives (atoms/molecules/organisms/layout) and domain components, built on Radix UI + shadcn/ui, consuming @grupo-elo-editorial/design-tokens@^3.1.0. Tailwind CSS v4 bundled.
Maintainers
Readme
@grupo-elo-editorial/shared-ui-react
React component library for the Grupo ELO Editorial multibrand design system. Brand-aware primitives, composed components, layout patterns, and domain components — all rendering against the same CSS-variable contract as @grupo-elo-editorial/design-tokens v3+.
Stack: React 18+ · TypeScript · Tailwind CSS v4 · Radix UI (via shadcn/ui primitives) · Lucide icons · Sonner toasts · class-variance-authority for variants.
This is the React sibling of @grupo-elo-editorial/shared-ui-vue (Vue 3). Both packages share the same semantic component surface and consume the same design tokens.
Architecture position
shared-ui-react ───────► design-system (tokens, themes)
apps/<consumer> ──► shared-ui-react + design-systemshared-ui-react never imports from app code or from shared-ui-vue.
Install
pnpm add @grupo-elo-editorial/shared-ui-react @grupo-elo-editorial/design-tokensThe package's dependencies field declares every Radix UI primitive and helper (lucide-react, class-variance-authority, clsx, tailwind-merge, sonner, next-themes, cmdk, embla-carousel-react, input-otp, react-day-picker, react-hook-form, react-resizable-panels, recharts, vaul) so a fresh consumer install resolves everything in one step.
Use
// main.tsx — once per app
import '@grupo-elo-editorial/shared-ui-react/style.css';
// The stylesheet ships Lato + Tailwind CSS v4 + multibrand theme tokens.
// Brand + theme switch via attributes on <html> (or a scoped container):
//
// <html data-brand="elo-editora" data-theme="light"> ... </html>
// <html data-brand="perabook" data-theme="dark"> ... </html>import { Button, ProductCard, Hero, Modal, TopAccessibilityBar } from '@grupo-elo-editorial/shared-ui-react';
export function Example() {
return (
<>
<TopAccessibilityBar />
<Hero
title="Histórias que acompanham gerações"
subtitle="Mais de 30 anos publicando literatura infantojuvenil"
ctaLabel="Conheça o catálogo"
/>
<Button variant="primary" size="lg">Comprar agora</Button>
</>
);
}Component inventory (42)
Atoms (7 custom + 6 re-exported)
| Custom | Re-exported (shadcn/ui) |
|---|---|
| Button (primary/secondary/ghost/danger/link/success × sm/md/lg) | Input |
| Textarea | Select, SelectContent, SelectItem, SelectTrigger, SelectValue |
| Badge (default/secondary/success/warning/danger/info/outline) | Checkbox |
| Avatar (sm/md/lg/xl + status) | RadioGroup, RadioGroupItem |
| Spinner (sm/md/lg/xl) | Toggle (= Switch) |
| Divider (horizontal/vertical, solid/dashed/dotted) | |
| Rating (interactive + readonly + half-stars) | |
Molecules (5 custom + 4 re-exported)
| Custom | Re-exported |
|---|---|
| ProductCard (default/skeleton/out-of-stock variants) | Breadcrumb* |
| SearchBar (icon, clear, loading) | Accordion* |
| PriceDisplay (original price + discount + installments) | Tooltip* |
| QuantitySelector (min/max constraints) | ProgressBar (@radix-ui/react-progress) |
| FormGroup (label/required/error/helper) | toast (sonner) |
Organisms (4 custom + 2 re-exported)
| Custom | Re-exported |
|---|---|
| Hero (default/centered/split variants) | Modal (= Dialog from shadcn) |
| EmptyState (default/search/cart/error) | Drawer (= Sheet from shadcn) |
| ErrorState (404/500/network/generic) | |
| ProductGrid (responsive 2–5 columns) | |
PRD-specific (2)
TopAccessibilityBar— dark-mode toggle, A+/A- font controls, VLibras lazy-load.HeroCarousel— responsive<picture>with srcset, autoplay + pause on hover, respectsprefers-reduced-motion.
Utility
cn(...)— class-name merger (clsx+tailwind-merge).
Brand + theme contract
The bundled stylesheet defines tokens at four selectors:
| Selector | Effect |
|---|---|
| :root or [data-brand="elo-editora"] or [data-brand="elo-editora"][data-theme="light"] | Elo Editora — light (default) |
| [data-brand="elo-editora"][data-theme="dark"] | Elo Editora — dark |
| [data-brand="perabook"] or [data-brand="perabook"][data-theme="light"] | PeraBook — light |
| [data-brand="perabook"][data-theme="dark"] | PeraBook — dark |
This matches the data-brand / data-theme contract from @grupo-elo-editorial/design-tokens v3.
// Apply globally
document.documentElement.setAttribute('data-brand', 'elo-editora');
document.documentElement.setAttribute('data-theme', 'dark');
// Or scope to a container
<div data-brand="perabook" data-theme="light">
<ProductCard ... />
</div>Source layout
packages/shared-ui-react/
├── src/
│ ├── index.ts ← public API barrel (imports CSS)
│ ├── components/
│ │ ├── atoms/{Button,Avatar,Badge,…}.tsx
│ │ ├── molecules/{ProductCard,SearchBar,FormGroup,…}.tsx
│ │ ├── organisms/{Hero,EmptyState,ErrorState,ProductGrid}.tsx
│ │ ├── prd/{HeroCarousel,TopAccessibilityBar}.tsx
│ │ ├── ui/ ← shadcn/ui primitives (Radix wrappers)
│ │ └── figma/ImageWithFallback.tsx
│ └── styles/{fonts,theme,index}.css ← bundled into dist/style.css
├── playground/ ← Vite dev preview (pnpm run play)
├── docs/
│ ├── COMPONENT_LIBRARY.md ← original Figma export documentation
│ ├── CORRECTIONS.md ← Figma export correction notes
│ └── GUIDELINES.md ← original Figma project guidelines
├── vite.config.ts ← Tailwind v4 + library build, externals
├── tsconfig.{json,build.json}
├── package.json ← @grupo-elo-editorial/[email protected]
└── README.mdDevelopment
# From the monorepo root
pnpm install # workspace install
# From this package
pnpm --filter @grupo-elo-editorial/shared-ui-react type-check # ts check, no emit
pnpm --filter @grupo-elo-editorial/shared-ui-react build # builds dist/
pnpm --filter @grupo-elo-editorial/shared-ui-react play # Vite playground previewConventions
- React 18+ with function components and hooks. No class components.
- Naming: component names
PascalCase(e.g.Button, notRButton— the scope already namespaces). File namesPascalCase.tsx. - Variants: defined via
class-variance-authority(cva). Re-exported alongside the component (e.g.buttonVariants). - Styling: Tailwind v4 utilities consuming
var(--brand-*)/ shadcn semantic tokens. Never hardcoded hex. - Brand awareness: components don't reach for brand state — they consume CSS variables. Brand switching is the consumer's concern (
data-brand/data-themeon root or scoped container). - Accessibility: WCAG 2.2 AA — focus-visible, keyboard nav, ARIA labels on icon-only buttons, focus traps in modals (provided by Radix), respects
prefers-reduced-motion. - Strict TypeScript: every component exports its prop interface (e.g.
ButtonProps).
Origin
Initial component set seeded from the Figma Make multibrand export. See docs/COMPONENT_LIBRARY.md for the full inventory the Figma project shipped and docs/CORRECTIONS.md for adjustments applied during the export. The historical Figma React preview app is preserved at design-system/_explorations/figma-multibrand/ for visual reference.
Sibling — Vue 3
@grupo-elo-editorial/shared-ui-vue is the Vue 3 sibling. Same component semantics, same tokens, same brand contract — a Button in React and a DSButton in Vue render identically.
Publish
Releases go through the NPM Release GitHub Actions workflow. See design-system/RELEASE.md for the full release procedure.
License
UNLICENSED — proprietary to Grupo ELO Editorial.