@hex-core/registry

Zod schemas + TypeScript types for components, themes, and recipes.

Install

Version 0.3.1Runtime dependency
pnpm
pnpm add @hex-core/registry

What it does

`@hex-core/registry` is the schema package — Zod schemas plus the TypeScript types they generate. It defines the shape every other hex-core package speaks: `Theme`, `TokenValue`, `RegistryItem`, `Recipe`, the strict variants of each.

Most consumers never `import` from this package directly; they use it transitively through `@hex-core/components`, `@hex-core/tokens`, `@hex-core/themes`, or `@hex-core/payload`. You install it directly when you need to type a function parameter as `Theme`, validate user input against `strictThemeSchema`, or build a tool that produces registry items.

The 0.2.0 release tightened `Theme.tokens.{light,dark}` from `Record<string, unknown>` to the strict `Record<string, TokenValue>` shape. Type-version skew between sibling packages is now caught at `tsc` time instead of at runtime.

Public API

Theme

ts
export interface Theme {
	name: string;
	displayName: string;
	colorScheme: "light" | "dark";
	tokens: {
		light: Record<string, TokenValue>;
		dark: Record<string, TokenValue>;
	};
}

The canonical Theme shape. Every theme object the design system consumes — `defaultTheme`, `midnightTheme`, anything you author — must satisfy this type.

tsx
import type { Theme } from "@hex-core/registry";

const myTheme: Theme = {
	name: "brand",
	displayName: "Brand",
	colorScheme: "light",
	tokens: { light: {/* ... */}, dark: {/* ... */} },
};

TokenValue / TokenSet

ts
export interface TokenValue {
	value: string;
	type: "color" | "spacing" | "typography" | "radius" | "shadow" | "duration" | "easing";
}

export type TokenSet = Record<string, TokenValue>;

A token is a `value` (HSL triplet, CSS length, easing function, etc.) plus a `type` discriminant. Discriminating by `type` lets transformers emit the right wrapper — `hsl()` for colors, raw value for everything else.

tsx
import type { TokenValue } from "@hex-core/registry";

const primary: TokenValue = { value: "240 5.9% 10%", type: "color" };
const radius: TokenValue = { value: "0.5rem", type: "radius" };

RegistryItem

ts
export interface RegistryItem {
	name: string;
	displayName: string;
	description: string;
	category: "primitive" | "component" | "block" | "hook";
	props: PropDef[];
	variants: VariantDef[];
	examples: Example[];
	ai: AIHints;
	dependencies: { npm: string[]; internal: string[]; peer: string[] };
	tags: string[];
}

Schema for one entry in `registry/items/<slug>.json`. Components, the CLI's `hex add`, and the MCP server's `get_component` tool all serialize to this shape. The `ai` block is what makes hex-ui LLM-native — `whenToUse`, `commonMistakes`, `accessibilityNotes`.

tsx
import { registryItemSchema } from "@hex-core/registry";

const parsed = registryItemSchema.parse(rawJson);
// → typed RegistryItem with full validation

strictThemeSchema / strictTokenSetSchema

ts
import { strictThemeSchema, strictTokenSetSchema } from "@hex-core/registry";
import type { z } from "zod";

declare const strictThemeSchema: z.ZodType<Theme>;
declare const strictTokenSetSchema: z.ZodType<TokenSet>;

Zod schemas for runtime validation. Use these at trust boundaries — parsing user-submitted theme overrides, validating an MCP tool input, ingesting a third-party token set.

tsx
import { strictThemeSchema } from "@hex-core/registry";

const result = strictThemeSchema.safeParse(input);
if (!result.success) {
	throw new Error("Invalid theme: " + result.error.message);
}
const theme = result.data;

Workflows

Validate a user-uploaded theme JSON file

Users sometimes ship custom themes as JSON. Parse with `strictThemeSchema` before handing the result to any transformer.

tsx
import { strictThemeSchema } from "@hex-core/registry";
import { themeToCss } from "@hex-core/tokens";

export async function compileUploadedTheme(json: unknown) {
	const result = strictThemeSchema.safeParse(json);
	if (!result.success) {
		return { ok: false, errors: result.error.issues };
	}
	return { ok: true, css: themeToCss(result.data, { mode: "light" }) };
}

Build a typed registry-item generator

Authoring a custom component? Type your scaffold against `RegistryItem` so missing fields surface at `tsc` time.

tsx
import type { RegistryItem } from "@hex-core/registry";

export function makeRegistryItem(name: string): RegistryItem {
	return {
		name,
		displayName: name,
		description: "TODO",
		category: "component",
		props: [],
		variants: [],
		examples: [],
		ai: {
			whenToUse: "",
			whenNotToUse: "",
			commonMistakes: [],
			relatedComponents: [],
			accessibilityNotes: "",
			tokenBudget: 0,
		},
		dependencies: { npm: [], internal: [], peer: [] },
		tags: [],
	};
}

Compatibility

  • Depends only on `zod@^4.3.6`. No React, no DOM, no Node-specific APIs.
  • Compiled to ESM with `.d.ts` types. Tree-shakable — importing only `Theme` doesn't pull the Zod runtime.
  • Strict-mode schema versioning: 0.2.x line is back-compatible at the type level; ingesting older theme JSON usually still parses cleanly.

See also