@verta/ui (0.3.0)

Published 2026-06-01 09:58:15 +00:00 by forgeadmin

Installation

@verta:registry=
npm install @verta/ui@0.3.0
"@verta/ui": "0.3.0"

About this package

@verta/ui

The shared Verta component library — shadcn-style components built on Radix primitives + CVA variants + cn (clsx + tailwind-merge), themed entirely from @verta/tokens. One library instead of every repo keeping its own src/components/ui.

Components

Button (primary/secondary/ghost/danger/accent · md/sm/icon), Card, Table, Input / Textarea / Label / Hint / Field, Select, Dialog, Tabs, Badge / Pill, StatusDot, Toast, AppShell (frosted sticky header + nav), ThemeToggle. Icons via lucide-react.

Component contracts

Conventions that bit consumers during the identity-admin rollout — pinned here so recall / iskra don't repeat them.

Card padding

The root <Card> is padding-free by design; padding lives in the slots CardHeader / CardContent / CardFooter (each p-5). Two layouts, never mixed:

  • Slotted (default): <Card><CardHeader/><CardContent/><CardFooter/></Card> — the slots own the padding.
  • Padded block: <Card padded>{content}</Card> — the root gets p-6 for a single self-contained block with no slots.

A bare <Card>{content}</Card> (no slot, no padded) renders flush to the border — add padded. Don't combine them (a padded root wrapping CardContent double-pads). padded is opt-in (default false), so existing slotted cards are unchanged.

Button semantics: primary vs accent

Button defaults to primary = bg-fg — a neutral fill (near-black in dark, near-white in light). The colored call-to-action is variant="accent" (bg-accent, #3291ff). This is the opposite of some pre-canon local kits where primary was the blue accent — porting those 1:1 makes every primary CTA render neutral/black (identity saw ~37 CTAs "go black": Save / Generate / Create…).

  • Migration: a CTA that should read as the colored primary action must be <Button variant="accent">, not the default. Audit each ported <Button> / variant="primary" and switch the genuine accent CTAs to accent.
  • Decision: no accent-default in the kit — primary stays neutral (canon: neutral primary, one accent CTA per view). Consumers opt into accent per CTA. (kit-fix: none — consumer-side migration + this doc.)

Sizing & spacing parity (kit vs pre-canon local)

Reconciliation of kit metrics against the pre-canon local kits, decision per row:

Element Kit (canon) Pre-canon local Decision
Input / SelectTrigger height h-[38px] 36px Keep 38px (canon control height). Consumer-side: align hand-rolled <select>/<input> to 38px, or wrap in the kit components.
Button height (md) h-9 (36px) 36px Keep 36px. Action buttons and text controls intentionally differ by 2px — documented, not a bug.
Badge / Pill x-padding px-2.5 px-2 Keep px-2.5 (canon); cosmetic, consumer-side.
Sheet width / padding w-72/96/[32rem], p-6 varied Keep canon. Use the size prop; custom widths via className.
AppShellSidebar padding p-3, item px-2.5 py-2 varied Keep canon; consumer-side.

Tailwind v4 defaults to verify in consumers:

  • border-color — v4's bare border utility resolves to currentColor (v3 was gray-200). The kit always sets an explicit colour (border-border), so kit components are safe; consumers using a bare border should add a base reset (*, ::after, ::before { border-color: var(--color-border); }) or always pair border with border-border.
  • ring — the kit uses explicit ring-2 ring-accent/55 (+ the ring-focus-ring token), so it does not rely on v4's 1px currentColor ring default.
  • space-scale — the kit uses Tailwind's standard numeric scale; the token spacing scale is consumed via arbitrary values (p-[var(--space-4)]) so it never shadows it.

Install (package model)

pnpm add @verta/ui   # pulls @verta/tokens; requires the @verta registry in .npmrc

Consumer entry CSS (Tailwind v4):

@import "@verta/ui/styles.css";   /* = @verta/tokens fonts + tokens + theme */
@import "tailwindcss";
@source "../node_modules/@verta/ui/dist";   /* scan component classes */
import { Button, Card, ThemeToggle } from "@verta/ui";

Registry model (own the source)

Components are also emitted as a shadcn-style registry under dist/registry/ (@verta/ui/registry), so you can copy a component's source into your repo and own it instead of importing the package.

Develop

pnpm --filter @verta/ui build       # tsup (ESM + d.ts) + styles + registry
pnpm --filter @verta/ui test        # Vitest + Testing Library (jsdom)
pnpm --filter @verta/ui typecheck

The live component catalogue runs on Ladle — a Vite-native Storybook alternative. Stories are co-located next to each component (src/components/<name>.stories.tsx); the whole gallery is wired in .ladle/.

pnpm --filter @verta/ui ladle        # dev server → http://localhost:61000
pnpm --filter @verta/ui ladle:build  # static build → ladle-dist/ (deployable to nginx/preview)

The gallery reads @verta/tokens straight from workspace source (aliased in .ladle/vite.config.ts), so it runs on a clean checkout with no prior build. The toolbar theme toggle (bottom-left) drives the .light class via @verta/tokens — every component is shown in both dark and light. Key props (variant, size, disabled, tone, status) are exposed as interactive controls on each component's Playground story.

Add a story for a new component

Drop a *.stories.tsx next to the component — no other wiring needed:

// src/components/widget.stories.tsx
import type { Story, StoryDefault } from "@ladle/react";
import { Widget, type WidgetProps } from "./widget";

export default { title: "Components / Widget" } satisfies StoryDefault;

export const Playground: Story<{ variant: WidgetProps["variant"] }> = ({ variant }) => (
  <Widget variant={variant} />
);
Playground.args = { variant: "primary" };
Playground.argTypes = {
  variant: { options: ["primary", "secondary"], control: { type: "select" } },
};

Ladle does not infer controls from TS types — declare them via args / argTypes. For components that portal into document.body (Dialog, Select, Toast), add meta = { iframed: true } so the overlay doesn't cover the Ladle navigation. *.stories.tsx files are excluded from the published bundle and the shadcn registry.

Dependencies

Dependencies

ID Version
@radix-ui/react-avatar ^1.1.11
@radix-ui/react-checkbox ^1.3.3
@radix-ui/react-dialog ^1.1.15
@radix-ui/react-dropdown-menu ^2.1.16
@radix-ui/react-label ^2.1.8
@radix-ui/react-popover ^1.1.15
@radix-ui/react-select ^2.2.6
@radix-ui/react-slot ^1.2.4
@radix-ui/react-switch ^1.2.6
@radix-ui/react-tabs ^1.1.13
@radix-ui/react-toast ^1.2.15
@radix-ui/react-tooltip ^1.2.8
@verta/tokens 0.3.0
class-variance-authority ^0.7.1
clsx ^2.1.1
echarts ^6.1.0
lucide-react ^1.17.0
tailwind-merge ^3.6.0

Development dependencies

ID Version
@ladle/react ^5.1.1
@tailwindcss/vite ^4.1.13
@testing-library/jest-dom ^6.9.1
@testing-library/react ^16.3.2
@testing-library/user-event ^14.6.1
@types/react ^19.2.15
@types/react-dom ^19.2.3
jsdom ^29.1.1
react ^19.2.6
react-dom ^19.2.6
tailwindcss ^4.1.13
tsup ^8.5.1
typescript ^5.6.2
vite ^6.3.6
vitest ^2.1.3

Peer dependencies

ID Version
react ^18 || ^19
react-dom ^18 || ^19
Details
npm
2026-06-01 09:58:15 +00:00
10
UNLICENSED
latest
38 KiB
Assets (1)
ui-0.3.0.tgz 38 KiB
Versions (3) View all
0.3.0 2026-06-01
0.2.0 2026-05-31
0.1.0 2026-05-28